mirror of https://github.com/probonopd/MiniDexed
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
9.8 KiB
303 lines
9.8 KiB
/*
|
|
==============================================================================
|
|
This file is part of Tal-Reverb by Patrick Kunz.
|
|
|
|
Copyright(c) 2005-2009 Patrick Kunz, TAL
|
|
Togu Audio Line, Inc.
|
|
http://kunz.corrupt.ch
|
|
|
|
This file may be licensed under the terms of of the
|
|
GNU General Public License Version 2 (the ``GPL'').
|
|
|
|
Software distributed under the License is distributed
|
|
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
|
|
express or implied. See the GPL for the specific language
|
|
governing rights and limitations.
|
|
|
|
You should have received a copy of the GPL along with this
|
|
program. If not, go to http://www.gnu.org/licenses/gpl.html
|
|
or write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
==============================================================================
|
|
*/
|
|
|
|
|
|
#if !defined(__Reverb_h)
|
|
#define __Reverb_h
|
|
|
|
#include "AllPassFilter.h"
|
|
#include "CombFilter.h"
|
|
#include "NoiseGenerator.h"
|
|
#include "Filter.h"
|
|
#include "math.h"
|
|
#include "AudioUtils.h"
|
|
#include "TalEq.h"
|
|
|
|
class Reverb
|
|
{
|
|
private:
|
|
static const int DELAY_LINES_COMB = 4;
|
|
static const int DELAY_LINES_ALLPASS = 5;
|
|
|
|
static const int MAX_PRE_DELAY_MS = 1000;
|
|
float* reflectionGains;
|
|
float* reflectionDelays;
|
|
|
|
CombFilter *combFiltersPreDelayL;
|
|
CombFilter *combFiltersPreDelayR;
|
|
|
|
CombFilter **combFiltersL;
|
|
CombFilter **combFiltersR;
|
|
NoiseGenerator **noiseGeneratorAllPassL;
|
|
NoiseGenerator **noiseGeneratorAllPassR;
|
|
NoiseGenerator **noiseGeneratorDelayL;
|
|
NoiseGenerator **noiseGeneratorDelayR;
|
|
NoiseGenerator **diffusionL;
|
|
NoiseGenerator **diffusionR;
|
|
|
|
AllPassFilter **allPassFiltersL;
|
|
AllPassFilter **allPassFiltersR;
|
|
|
|
AllPassFilter *preAllPassFilterL;
|
|
AllPassFilter *preAllPassFilterR;
|
|
|
|
AllPassFilter *postAllPassFilterL;
|
|
AllPassFilter *postAllPassFilterR;
|
|
|
|
TalEq* talEqL;
|
|
TalEq* talEqR;
|
|
|
|
float feedbackValueL;
|
|
float feedbackValueR;
|
|
|
|
float decayTime;
|
|
float preDelayTime;
|
|
bool stereoMode;
|
|
float modulationIntensity;
|
|
|
|
float outL;
|
|
float outR;
|
|
|
|
AudioUtils audioUtils;
|
|
|
|
public:
|
|
Reverb(int sampleRate)
|
|
{
|
|
createDelaysAndCoefficients(DELAY_LINES_COMB + DELAY_LINES_ALLPASS, 82.0f);
|
|
|
|
combFiltersPreDelayL = new CombFilter((float)MAX_PRE_DELAY_MS, 0.0f, sampleRate);
|
|
combFiltersPreDelayR = new CombFilter((float)MAX_PRE_DELAY_MS, 0.0f, sampleRate);
|
|
|
|
combFiltersL = new CombFilter *[DELAY_LINES_COMB];
|
|
combFiltersR = new CombFilter *[DELAY_LINES_COMB];
|
|
noiseGeneratorAllPassL = new NoiseGenerator *[DELAY_LINES_COMB];
|
|
noiseGeneratorAllPassR = new NoiseGenerator *[DELAY_LINES_COMB];
|
|
noiseGeneratorDelayL = new NoiseGenerator *[DELAY_LINES_COMB];
|
|
noiseGeneratorDelayR = new NoiseGenerator *[DELAY_LINES_COMB];
|
|
diffusionL = new NoiseGenerator *[DELAY_LINES_COMB];
|
|
diffusionR = new NoiseGenerator *[DELAY_LINES_COMB];
|
|
|
|
float stereoSpreadValue = 0.008f;
|
|
float stereoSpreadSign = 1.0f;
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++)
|
|
{
|
|
float stereoSpreadFactor = 1.0f + stereoSpreadValue;
|
|
if (stereoSpreadSign > 0.0f)
|
|
{
|
|
combFiltersL[i] = new CombFilter(reflectionDelays[i] * stereoSpreadFactor, reflectionGains[i], sampleRate);
|
|
combFiltersR[i] = new CombFilter(reflectionDelays[i], reflectionGains[i], sampleRate);
|
|
}
|
|
else
|
|
{
|
|
combFiltersL[i] = new CombFilter(reflectionDelays[i], reflectionGains[i], sampleRate);
|
|
combFiltersR[i] = new CombFilter(reflectionDelays[i] * stereoSpreadFactor, reflectionGains[i], sampleRate);
|
|
}
|
|
stereoSpreadSign *= -1.0f;
|
|
noiseGeneratorAllPassL[i] = new NoiseGenerator(sampleRate);
|
|
noiseGeneratorAllPassR[i] = new NoiseGenerator(sampleRate);
|
|
noiseGeneratorDelayL[i] = new NoiseGenerator(sampleRate);
|
|
noiseGeneratorDelayR[i] = new NoiseGenerator(sampleRate);
|
|
diffusionL[i] = new NoiseGenerator(sampleRate);
|
|
diffusionR[i] = new NoiseGenerator(sampleRate);
|
|
}
|
|
|
|
preAllPassFilterL = new AllPassFilter(220.0f, 0.68f, sampleRate);
|
|
preAllPassFilterR = new AllPassFilter(220.0f, 0.68f, sampleRate);
|
|
|
|
postAllPassFilterL = new AllPassFilter(180.0f, 0.68f, sampleRate);
|
|
postAllPassFilterR = new AllPassFilter(180.0f, 0.68f, sampleRate);
|
|
|
|
allPassFiltersL = new AllPassFilter *[DELAY_LINES_ALLPASS];
|
|
allPassFiltersR = new AllPassFilter *[DELAY_LINES_ALLPASS];
|
|
for (int i = 0; i < DELAY_LINES_ALLPASS; i++)
|
|
{
|
|
allPassFiltersL[i] = new AllPassFilter(reflectionDelays[i + DELAY_LINES_COMB - 1] * 0.2f, 0.68f, sampleRate);
|
|
allPassFiltersR[i] = new AllPassFilter(reflectionDelays[i + DELAY_LINES_COMB - 1] * 0.2f, 0.68f, sampleRate);
|
|
}
|
|
|
|
talEqL = new TalEq(sampleRate);
|
|
talEqR = new TalEq(sampleRate);
|
|
|
|
decayTime = 0.5f;
|
|
preDelayTime = 0.0f;
|
|
modulationIntensity = 0.12f;
|
|
stereoMode = false;
|
|
|
|
outL = 0.0f;
|
|
outR = 0.0f;
|
|
|
|
feedbackValueL = 0.0f;
|
|
feedbackValueR = 0.0f;
|
|
}
|
|
|
|
~Reverb()
|
|
{
|
|
delete[] reflectionGains;
|
|
delete[] reflectionDelays;
|
|
|
|
delete combFiltersPreDelayL;
|
|
delete combFiltersPreDelayR;
|
|
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++) delete combFiltersL[i];
|
|
delete[] combFiltersL;
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++) delete combFiltersR[i];
|
|
delete[] combFiltersR;
|
|
|
|
for (int i = 0; i < DELAY_LINES_ALLPASS; i++) delete allPassFiltersL[i];
|
|
delete[] allPassFiltersL;
|
|
for (int i = 0; i < DELAY_LINES_ALLPASS; i++) delete allPassFiltersR[i];
|
|
delete[] allPassFiltersR;
|
|
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++) delete noiseGeneratorAllPassL[i];
|
|
delete[] noiseGeneratorAllPassL;
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++) delete noiseGeneratorAllPassR[i];
|
|
delete[] noiseGeneratorAllPassR;
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++) delete noiseGeneratorDelayL[i];
|
|
delete[] noiseGeneratorDelayL;
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++) delete noiseGeneratorDelayR[i];
|
|
delete[] noiseGeneratorDelayR;
|
|
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++) delete diffusionL[i];
|
|
delete[] diffusionL;
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++) delete diffusionR[i];
|
|
delete[] diffusionR;
|
|
|
|
delete preAllPassFilterL;
|
|
delete preAllPassFilterR;
|
|
|
|
delete postAllPassFilterL;
|
|
delete postAllPassFilterR;
|
|
|
|
delete talEqL;
|
|
delete talEqR;
|
|
}
|
|
|
|
|
|
void setDecayTime(float decayTime)
|
|
{
|
|
this->decayTime = audioUtils.getLogScaledValueInverted(decayTime) * 0.99f;
|
|
}
|
|
|
|
void setPreDelay(float preDelayTime)
|
|
{
|
|
this->preDelayTime = audioUtils.getLogScaledValue(preDelayTime);
|
|
}
|
|
|
|
void setStereoMode(bool stereoMode)
|
|
{
|
|
this->stereoMode = stereoMode;
|
|
}
|
|
|
|
void setLowShelfGain(float lowShelfGain)
|
|
{
|
|
talEqL->setLowShelfGain(lowShelfGain);
|
|
talEqR->setLowShelfGain(lowShelfGain);
|
|
}
|
|
|
|
void setHighShelfGain(float highShelfGain)
|
|
{
|
|
talEqL->setHighShelfGain(highShelfGain);
|
|
talEqR->setHighShelfGain(highShelfGain);
|
|
}
|
|
|
|
void setLowShelfFrequency(float lowShelfFrequency)
|
|
{
|
|
talEqL->setLowShelfFrequency(lowShelfFrequency);
|
|
talEqR->setLowShelfFrequency(lowShelfFrequency);
|
|
}
|
|
|
|
void setHighShelfFrequency(float highShelfFrequency)
|
|
{
|
|
talEqL->setHighShelfFrequency(highShelfFrequency);
|
|
talEqR->setHighShelfFrequency(highShelfFrequency);
|
|
}
|
|
|
|
// All input values [0..1]
|
|
inline void process(float* sampleL, float* sampleR)
|
|
{
|
|
float revL = 0.0f;
|
|
float revR = 0.0f;
|
|
|
|
if (!stereoMode)
|
|
{
|
|
revL += (*sampleL + *sampleR) * 0.125f;
|
|
revL += combFiltersPreDelayL->process(revL, 0.0f, 0.0f, preDelayTime);
|
|
talEqL->process(&revL);
|
|
revR = revL;
|
|
}
|
|
else
|
|
{
|
|
revL += combFiltersPreDelayL->process(*sampleL * 0.5f, 0.0f, 0.0f, preDelayTime);
|
|
revR += combFiltersPreDelayR->process(*sampleR * 0.5f, 0.0f, 0.0f, preDelayTime);
|
|
talEqL->process(&revL);
|
|
talEqR->process(&revR);
|
|
}
|
|
|
|
// ----------------- Comb Filter --------------------
|
|
outL = feedbackValueL * 0.05f;
|
|
outR = feedbackValueR * 0.05f;
|
|
|
|
float scaledRoomSize = decayTime * 0.97f;
|
|
for (int i = 0; i < DELAY_LINES_COMB; i++)
|
|
{
|
|
outL += combFiltersL[i]->processInterpolated(revL, diffusionL[i]->tickFilteredNoiseFast() * 0.01f, scaledRoomSize, scaledRoomSize + 0.035f * noiseGeneratorDelayL[i]->tickFilteredNoise());
|
|
outR += combFiltersR[i]->processInterpolated(revR, diffusionR[i]->tickFilteredNoiseFast() * 0.01f, scaledRoomSize, scaledRoomSize + 0.035f * noiseGeneratorDelayR[i]->tickFilteredNoise());
|
|
}
|
|
|
|
// ----------------- Pre AllPass --------------------
|
|
float modL = preAllPassFilterL->processInterpolated(outL, decayTime * decayTime * 0.999f + 0.001f * noiseGeneratorAllPassL[0]->tickFilteredNoise(), 0.68f, true);
|
|
float modR = preAllPassFilterR->processInterpolated(outR, decayTime * decayTime * 0.999f + 0.001f * noiseGeneratorAllPassR[0]->tickFilteredNoise(), 0.68f, true);
|
|
|
|
// ----------------- Post AllPass --------------------
|
|
outL += 0.3f * postAllPassFilterL->processInterpolated(modL, decayTime * decayTime * 1.0f, 0.68f, false);
|
|
outR += 0.3f * postAllPassFilterR->processInterpolated(modR, decayTime * decayTime * 1.0f, 0.68f, false);
|
|
|
|
// ----------------- AllPass Filter ------------------
|
|
for (int i = 0; i < DELAY_LINES_ALLPASS; i++)
|
|
{
|
|
outL = allPassFiltersL[i]->process(outL);
|
|
outR = allPassFiltersR[i]->process(outR);
|
|
}
|
|
|
|
// ----------------- Write to output / Stereo --------
|
|
*sampleL = outL;
|
|
*sampleR = outR;
|
|
|
|
feedbackValueL = outL;
|
|
feedbackValueR = outR;
|
|
}
|
|
|
|
void createDelaysAndCoefficients(int numlines, float delayLength)
|
|
{
|
|
reflectionDelays = new float[numlines];
|
|
reflectionGains = new float[numlines];
|
|
|
|
float volumeScale = (float)(-3.0 * delayLength / log10f(0.5f));
|
|
for (int n = numlines - 1; n >= 0; n--)
|
|
{
|
|
reflectionDelays[numlines -1 - n] = delayLength / powf(2.0f, (float)n / numlines);
|
|
reflectionGains[numlines -1 - n] = powf(10.0f, - (3.0f * reflectionDelays[numlines -1 - n]) / volumeScale);
|
|
}
|
|
}
|
|
};
|
|
#endif
|
|
|