Added Tal Reverb 3

pull/764/head
jnonis 7 months ago
parent 116881b3a5
commit e034e66f87
  1. 2
      src/Makefile
  2. 1
      src/effect_base.cpp
  3. 1
      src/effect_base.h
  4. 112
      src/effect_talreverb3.cpp
  5. 48
      src/effect_talreverb3.h
  6. 4
      src/effects.h
  7. 127
      src/tal-reverb-3/AllPassFilter.h
  8. 155
      src/tal-reverb-3/AudioUtils.h
  9. 123
      src/tal-reverb-3/CombFilter.h
  10. 88
      src/tal-reverb-3/Filter.h
  11. 126
      src/tal-reverb-3/HighShelf.h
  12. 127
      src/tal-reverb-3/LowShelf.h
  13. 110
      src/tal-reverb-3/NoiseGenerator.h
  14. 52
      src/tal-reverb-3/ParamChangeUtil.h
  15. 72
      src/tal-reverb-3/Params.h
  16. 104
      src/tal-reverb-3/PeakEq.h
  17. 303
      src/tal-reverb-3/Reverb - Bestest.h
  18. 303
      src/tal-reverb-3/Reverb - Great Sound.h
  19. 303
      src/tal-reverb-3/Reverb - improvement.h
  20. 316
      src/tal-reverb-3/Reverb.h
  21. 232
      src/tal-reverb-3/ReverbEngine.h
  22. 93
      src/tal-reverb-3/TalEq.h
  23. 44
      src/uimenu.cpp
  24. 2
      src/uimenu.h

@ -10,7 +10,7 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \
mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \
sysexfileloader.o performanceconfig.o perftimer.o \
effect_base.o effect_chorus.o effect_delay.o \
effect_ds1.o effect_bigmuff.o \
effect_talreverb3.o effect_ds1.o effect_bigmuff.o \
moddistortion/Distortion_DS1.o moddistortion/Distortion_BigMuff.o \
moddistortion/HyperbolicTables.o moddistortion/OverSample.o \
effect_compressor.o effect_platervbstereo.o uibuttons.o midipin.o

@ -51,6 +51,7 @@ void AudioEffect::process(const float32_t* inblock, float32_t* outblock, uint16_
// Mono process
// Dummy buffer for right channel
float32_t dummyBuffer[len];
memset(dummyBuffer, 0, len * sizeof(float32_t));
process(inblock, dummyBuffer, outblock, dummyBuffer, len);
}

@ -11,6 +11,7 @@
#define EFFECT_LPF 3
#define EFFECT_DS1 4
#define EFFECT_BIGMUFF 5
#define EFFECT_TALREVERB3 6
class AudioEffect
{

@ -0,0 +1,112 @@
#include <circle/logger.h>
#include "effect_talreverb3.h"
LOGMODULE ("fx talreverb3");
AudioEffectTalReverb3::AudioEffectTalReverb3(float32_t samplerate) : AudioEffect(samplerate)
{
this->engine = new ReverbEngine(samplerate);
this->params = this->engine->param;
this->setParameter(AudioEffectTalReverb3::Param::DRY, 50);
this->setParameter(AudioEffectTalReverb3::Param::WET, 23);
this->setParameter(AudioEffectTalReverb3::Param::DECAYTIME, 42);
this->setParameter(AudioEffectTalReverb3::Param::PREDELAY, 0);
this->setParameter(AudioEffectTalReverb3::Param::LOWSHELFGAIN, 89);
this->setParameter(AudioEffectTalReverb3::Param::HIGHSHELFGAIN, 33);
this->setParameter(AudioEffectTalReverb3::Param::STEREO, 100);
this->setParameter(AudioEffectTalReverb3::Param::REALSTEREOMODE, 100);
this->setParameter(AudioEffectTalReverb3::Param::POWER, 100);
}
AudioEffectTalReverb3::~AudioEffectTalReverb3()
{
delete this->engine;
}
void AudioEffectTalReverb3::setParameter(unsigned param, unsigned value)
{
this->params[param] = value;
switch (param)
{
case AudioEffectTalReverb3::Param::BYPASS:
this->setBypass(value == 1);
break;
case AudioEffectTalReverb3::Param::WET:
this->engine->setWet((float) value / 100.0f);
break;
case AudioEffectTalReverb3::Param::DRY:
this->engine->setDry((float) value / 100.0f);
break;
case AudioEffectTalReverb3::Param::DECAYTIME:
this->engine->setDecayTime((float) value / 100.0f);
break;
case AudioEffectTalReverb3::Param::PREDELAY:
this->engine->setPreDelay((float) value / 100.0f);
break;
case AudioEffectTalReverb3::Param::LOWSHELFGAIN:
this->engine->setLowShelfGain((float) value / 100.0f);
break;
case AudioEffectTalReverb3::Param::HIGHSHELFGAIN:
this->engine->setHighShelfGain((float) value / 100.0f);
break;
case AudioEffectTalReverb3::Param::STEREO:
this->engine->setStereoWidth((float) value / 100.0f);
break;
case AudioEffectTalReverb3::Param::REALSTEREOMODE:
this->engine->setStereoMode((float) value / 100.0f);
break;
case AudioEffectTalReverb3::Param::POWER:
this->engine->setPower((float) value / 100.0f);
break;
default:
break;
}
}
unsigned AudioEffectTalReverb3::getParameter(unsigned param)
{
switch (param)
{
case AudioEffectTalReverb3::Param::BYPASS:
return this->getBypass() ? 1 : 0;
case AudioEffectTalReverb3::Param::WET:
case AudioEffectTalReverb3::Param::DRY:
case AudioEffectTalReverb3::Param::DECAYTIME:
case AudioEffectTalReverb3::Param::PREDELAY:
case AudioEffectTalReverb3::Param::LOWSHELFGAIN:
case AudioEffectTalReverb3::Param::HIGHSHELFGAIN:
case AudioEffectTalReverb3::Param::STEREO:
case AudioEffectTalReverb3::Param::REALSTEREOMODE:
case AudioEffectTalReverb3::Param::POWER:
return params[param];
default:
return 0;
}
}
void AudioEffectTalReverb3::doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len)
{
int numberOfChannels = 2;
if (inblockL == inblockR) {
numberOfChannels = 1;
}
for (size_t i = 0; i < len; i++)
{
if (numberOfChannels == 2)
{
outblockL[i] = inblockL[i];
outblockR[i] = inblockR[i];
}
else
{
outblockL[i] = inblockL[i];
outblockR[i] = inblockL[i];
}
engine->process(&outblockL[i], &outblockR[i]);
}
}

@ -0,0 +1,48 @@
#ifndef _EFFECT_TALREVERB3_H
#define _EFFECT_TALREVERB3_H
#include "effect_base.h"
#include "tal-reverb-3/ReverbEngine.h"
class AudioEffectTalReverb3 : public AudioEffect
{
public:
static const unsigned MAX_DELAY_TIME = 1;
enum Param
{
BYPASS,
DRY,
WET,
DECAYTIME,
PREDELAY,
LOWSHELFGAIN,
HIGHSHELFGAIN,
STEREO,
REALSTEREOMODE,
POWER,
UNKNOWN
};
AudioEffectTalReverb3(float32_t samplerate);
virtual ~AudioEffectTalReverb3();
virtual unsigned getId()
{
return EFFECT_TALREVERB3;
}
virtual void setParameter(unsigned param, unsigned value);
virtual unsigned getParameter(unsigned param);
protected:
virtual size_t getParametersSize()
{
return sizeof(AudioEffectTalReverb3::Param);
}
virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len);
private:
float *params;
ReverbEngine *engine;
};
#endif // _EFFECT_TALREVERB3_H

@ -8,6 +8,7 @@
#include "effect_lpf.h"
#include "effect_ds1.h"
#include "effect_bigmuff.h"
#include "effect_talreverb3.h"
inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate)
{
@ -23,6 +24,8 @@ inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate)
return new AudioEffectDS1(samplerate);
case EFFECT_BIGMUFF:
return new AudioEffectBigMuff(samplerate);
case EFFECT_TALREVERB3:
return new AudioEffectTalReverb3(samplerate);
case EFFECT_NONE:
default:
return new AudioEffectNone(samplerate);
@ -38,6 +41,7 @@ inline std::string getFXTypeName(int nValue)
case EFFECT_LPF: return "LP Filter";
case EFFECT_DS1: return "DS1";
case EFFECT_BIGMUFF: return "Big Muff";
case EFFECT_TALREVERB3: return "Tal Reverb 3";
case EFFECT_NONE:
default: return "None";
}

@ -0,0 +1,127 @@
/*
==============================================================================
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(__AllPassFilter_h)
#define __AllPassFilter_h
#include "math.h"
#include "AudioUtils.h"
class AllPassFilter
{
private:
float delay, gain;
float* buffer;
int bufferLength, writePtr, readPtr1, readPtr2;
float z1;
AudioUtils audioUtils;
public:
// delay times in milliseconds
AllPassFilter(float delayTime, float feedbackGain, long samplingRate)
{
//OutputDebugString("start init allPass");
gain = feedbackGain;
delay = delayTime;
bufferLength = (int)(delay * samplingRate / 1000.0f);
bufferLength = audioUtils.getNextNearPrime(bufferLength);
buffer = new float[bufferLength];
//zero out the buffer (create silence)
for (int i = 0; i < bufferLength; i++)
buffer[i] = 0.0f;
writePtr = readPtr1 = readPtr2 = 0;
z1 = 0.0f;
//OutputDebugString("end init allPass");
}
~AllPassFilter()
{
delete buffer;
}
// all values [0..1]
inline float processInterpolated(float input, float delayLength, float diffuse, bool negative)
{
// dynamic delay length
float offset = (bufferLength - 2.0f) * delayLength + 1.0f;
readPtr1 = writePtr - (int)floorf(offset);
if (readPtr1 < 0)
readPtr1 += bufferLength;
readPtr2 = readPtr1 - 1;
if (readPtr2 < 0)
readPtr2 += bufferLength;
// interpolate, see paper: http://www.stanford.edu/~dattorro/EffectDesignPart2.pdf
float frac = offset - (int)floorf(offset);
float temp = buffer[readPtr2] + buffer[readPtr1] * (1-frac) - (1-frac) * z1;
z1 = temp;
float output;
if (!negative)
{
buffer[writePtr] = diffuse * gain * temp + input;
output = temp - diffuse * gain * buffer[writePtr];
}
else
{
buffer[writePtr] = diffuse * gain * temp - input;
output = temp + diffuse * gain * buffer[writePtr];
}
if (++writePtr >= bufferLength)
writePtr = 0;
return output;
}
inline float process(float input, float diffuse)
{
float temp = buffer[readPtr1];
buffer[readPtr1] = diffuse * gain * temp + input;
float output = temp - diffuse * gain * buffer[readPtr1];
if (++readPtr1 >= bufferLength)
readPtr1 = 0;
return output;
}
inline float process(float input)
{
float temp = buffer[readPtr1];
buffer[readPtr1] = gain * temp + input;
float output = temp - gain * buffer[readPtr1];
if (++readPtr1 >= bufferLength)
readPtr1 = 0;
return output;
}
};
#endif

@ -0,0 +1,155 @@
/*
==============================================================================
This file is part of Tal-Dub-III 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(__AudioUtils_h)
#define __AudioUtils_h
#include "math.h"
class AudioUtils
{
private:
public:
AudioUtils()
{
}
~AudioUtils()
{
}
float getLogScaledValueInDecibel(float inputValue, float maxValue)
{
float logScaled = getLogScaledVolume(inputValue, maxValue);
return getValueInDecibel(logScaled);
}
float getLogScaledValueInDecibelFilter(float inputValue, float maxValue)
{
float logScaled = getLogScaledVolume(inputValue, maxValue);
return getValueInDecibelFilter(logScaled);
}
// max value unscalled
float getLogScaledVolume(float inputValue, float maxValue)
{
return (expf(inputValue * maxValue * logf(20.0f)) - 1.0f) / 19.0f;
}
// max value unscalled
float getLogScaledValue(float inputValue)
{
// have to return a value between 0..1
return (expf(inputValue * logf(20.0f)) - 1.0f) / 19.0f;
}
float getLogScaledValue(float inputValue, float expValue)
{
// have to return a value between 0..1
return (expf(inputValue * logf(expValue)) - 1.0f) / (expValue - 1.0f);
}
float getLogScaledFrequency(float inputValue)
{
return 100.0f + getLogScaledValue(inputValue) * 9900.0f;
}
float getLogScaledValueInverted(float inputValue)
{
// have to return a value between 0..1
inputValue = 1.0f - inputValue;
inputValue = (expf(inputValue * logf(20.0f)) - 1.0f) / 19.0f;
return 1.0f - inputValue;
}
float getLogScaledValueInverted(float inputValue, int exponent)
{
// have to return a value between 0..1
inputValue = 1.0f - inputValue;
inputValue = (expf(inputValue * logf((float)exponent)) - 1.0f) / (exponent - 1.0f);
return 1.0f - inputValue;
}
// input value >= 0
float getValueInDecibel(float inputValue)
{
if (inputValue <= 0)
{
return -96.0f;
}
else
{
// 1.0 --> 0dB
return 20.0f * log10f(inputValue / 1.0f);
}
}
float getValueInDecibelFilter(float inputValue)
{
if (inputValue <= 0)
{
return -18.0f;
}
else
{
// 1.0 --> 0dB
return 5.0f * log10f(inputValue / 1.0f);
}
}
inline float tanhApp(float x)
{
// Original
//return tanh(x);
// Approx
x*= 2.0f;
float a= fabs(x);
float b= 6.0f + a*(3.0f + a); // 6, 3
return (x * b)/(a * b + 12.0f);
}
inline int getNextNearPrime(int value)
{
while (!isPrime(value)) value++;
return value;
}
inline bool isPrime(int value)
{
bool answer = true;
if (value == 0) value = 1;
for (int i = 2; i <= sqrtf((float)value) ; i++)
{
if (value % i == 0)
{
answer = false;
break;
}
}
return answer;
}
};
#endif

@ -0,0 +1,123 @@
/*
==============================================================================
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(__CombFilter_h)
#define __CombFilter_h
#include "math.h"
#include "AudioUtils.h"
class CombFilter
{
private:
float sampleRateFactor;
float gain, minDamp;
float* buffer;
int readPtr1, readPtr2, writePtr;
float z1;
int bufferLengthDelay;
float filterStore;
AudioUtils audioUtils;
public:
// delay times in milliseconds
CombFilter(float delayTime, float minDamp, long sampleRate)
{
bufferLengthDelay = (int)(delayTime * sampleRate / 1000);
bufferLengthDelay = audioUtils.getNextNearPrime(bufferLengthDelay);
buffer = new float[bufferLengthDelay];
//zero out the buffer (silence)
for (int i = 0; i < bufferLengthDelay; i++)
buffer[i] = 0.0f;
writePtr = 0;
//set read pointer to start of buffer
readPtr1 = 0;
z1 = filterStore = 0.0f;
this->minDamp = minDamp;
this->sampleRateFactor = 44100.0f / sampleRate;
if (this->sampleRateFactor > 1.0f)
{
this->sampleRateFactor = 1.0f;
}
}
~CombFilter()
{
delete buffer;
}
// delayIntensity [0..1]
inline float processInterpolated(float input, float damp, float feedback, float delay)
{
damp *= this->sampleRateFactor;
float offset = (bufferLengthDelay - 2) * delay + 1.0f;
readPtr1 = writePtr - (int)floorf(offset);
if (readPtr1 < 0)
readPtr1 += bufferLengthDelay;
readPtr2 = readPtr1 - 1;
if (readPtr2 < 0)
readPtr2 += bufferLengthDelay;
// interpolate, see paper: http://www.stanford.edu/~dattorro/EffectDesignPart2.pdf
float frac = offset - (int)floorf(offset);
float output = buffer[readPtr2] + buffer[readPtr1] * (1-frac) - (1-frac) * z1;
z1 = output;
damp = minDamp * damp;
filterStore = output * (1.0f - damp) + filterStore * damp;
buffer[writePtr] = input + (filterStore * feedback);
if (++writePtr >= bufferLengthDelay)
writePtr = 0;
return output;
}
inline float process(float input, float damp, float feedback, float delay)
{
damp *= this->sampleRateFactor;
float offset = (bufferLengthDelay - 2) * delay + 1.0f;
readPtr1 = writePtr - (int)floorf(offset);
if (readPtr1 < 0)
readPtr1 += bufferLengthDelay;
float output = buffer[readPtr1];
filterStore = output * (1.0f - damp) + filterStore * damp;
buffer[writePtr] = input + (filterStore * feedback);
if (++writePtr >= bufferLengthDelay)
writePtr = 0;
return output;
}
};
#endif

@ -0,0 +1,88 @@
/*
==============================================================================
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(__Filter_h)
#define __Filter_h
#include "math.h"
class Filter
{
private:
float f, k, p, scale, r, x;
float y1, y2, y3, y4, oldx, oldy1, oldy2, oldy3;
float fCutoff, fActualCutoff;
float Pi;
float sampleRateFactor;
public:
Filter(float sampleRate)
{
Pi = 3.141592653f;
y1 = y2 = y3 = y4 = oldx = oldy1 = oldy2 = oldy3 = 0.0f;
if (sampleRate <= 0.0f) sampleRate = 44100.0f;
sampleRateFactor= 44100.0f / sampleRate;
if (sampleRateFactor > 1.0f)
sampleRateFactor = 1.0f;
fActualCutoff = -1.0f;
}
inline float process(float input, float fCutoff, float fRes, bool highPass)
{
if (fCutoff != fActualCutoff)
{
fActualCutoff = fCutoff;
fCutoff *= sampleRateFactor;
updateValues(fCutoff * fCutoff);
}
x = input;
// Four cascaded onepole filters (bilinear transform)
y1 = (x + oldx) * p - k * y1;
y2 = (y1 + oldy1) * p - k * y2;
// Save values
oldx = x;
oldy1 = y1;
if (highPass) input = input - y2;
else input = y2;
return input;
}
void updateValues(float fCutoff)
{
// Filter section MOOG VCF
// CSound source code, Stilson/Smith CCRMA paper.
f = fCutoff; // [0 - 1]
k = 3.6f * f - 1.6f * f * f - 1.0f; // (Empirical tunning) /// !!! original (convex)
p = (k + 1.0f) * 0.5f; // scale [0, 1]
scale = expf((1.0f - p) * 1.386249f); // original
}
};
#endif

@ -0,0 +1,126 @@
/*
==============================================================================
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(__HighShelf_h)
#define __HighShelf_h
#include "math.h"
class HighShelf
{
public:
int filterDecibel;
float sampleRate;
float a0, a1, a2;
float b0, b1, b2;
float x0, x1, x2;
float y1, y2;
float outSample;
float a, w0, q, s, alpha;
float cosValue, sqrtValue;
float dBgain, freq;
HighShelf(float sampleRate, int filterDecibel)
{
this->sampleRate = sampleRate;
this->filterDecibel = filterDecibel;
a0 = a1 = a2 = 0.0f;
b0 = b1 = b2 = 0.0f;
x0 = x1 = x2 = 0.0f;
y1 = y2 = 0.0f;
q = dBgain = freq = 0.0f;
s = 2.0f;
}
// gain [0..1], q[0..1], freq[0..44100]
inline void tick(float *inSample, float freq, float q, float gain)
{
gain = filterDecibel - (1.0f - gain) * filterDecibel * 2.0f;
calcCoefficients(freq, q, gain);
outSample = b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2;
outSample = b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2;
updateHistory(*inSample, outSample);
*inSample = outSample;
}
inline void calcCoefficients(float freq, float q, float dBgain)
{
if (this->q != q || this->dBgain != dBgain || this->freq != freq)
{
this->dBgain = dBgain;
this->q = q;
this->freq = freq;
w0 = 2.0f * 3.141592653589793f * freq / sampleRate;
a = sqrtf(pow(10, dBgain/20.0f));
alpha = sinf(w0)/(2.0f*q);
q = 1.0f / sqrt((a + 1.0f/a)*(1.0f/s - 1.0f) + 2.0f);
cosValue = cosf(w0);
sqrtValue = sqrtf(a);
}
b0 = a * ((a + 1.0f) + (a - 1.0f) * cosValue + 2.0f * sqrtValue * alpha );
b1 = -2.0f * a * ((a - 1.0f) + (a + 1.0f) * cosValue );
b2 = a * ((a + 1.0f) + (a - 1.0f) * cosValue - 2.0f * sqrtValue * alpha );
a0 = (a + 1.0f) - (a - 1.0f) * cosValue + 2.0f * sqrtValue * alpha;
a1 = 2.0f * ((a - 1.0f) - (a + 1.0f) * cosValue );
a2 = (a + 1.0f) - (a - 1.0f) * cosValue - 2.0f * sqrtValue * alpha;
a0 = 1.0f/a0;
b0 *= a0;
b1 *= a0;
b2 *= a0;
a1 *= a0;
a2 *= a0;
}
inline void updateHistory(float inSample, float outSample)
{
x0 = saturate(x1, -0.05f);
x1 = saturate(x2, 0.04f);
x2 = inSample;
y2 = y1;
y1 = outSample;
}
inline float saturate(float x, float variation)
{
return x - 0.002f * (x + variation) * x * x;
}
};
#endif

@ -0,0 +1,127 @@
/*
==============================================================================
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(__LowShelf_h)
#define __LowShelf_h
#include "math.h"
class LowShelf
{
public:
int filterDecibel;
float sampleRate;
float a0, a1, a2;
float b0, b1, b2;
float x0, x1, x2;
float y1, y2;
float outSample;
float a, w0, q, s, alpha;
float cosValue, sqrtValue;
float dBgain, freq;
float random;
LowShelf(float sampleRate, int filterDecibel)
{
this->sampleRate = sampleRate;
this->filterDecibel = filterDecibel;
a0 = a1 = a2 = 0.0f;
b0 = b1 = b2 = 0.0f;
x0 = x1 = x2 = 0.0f;
y1 = y2 = 0.0f;
q = dBgain = freq = 0.0f;
s = 1.0f;
}
// gain [0..1], q[0..1], freq[0..44100]
inline void tick(float *inSample, float freq, float q, float gain)
{
gain = filterDecibel - (1.0f - gain) * filterDecibel * 2.0f;
calcCoefficients(freq, q, gain);
outSample = b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2;
outSample = b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2;
updateHistory(*inSample, outSample);
*inSample = outSample;
}
inline void calcCoefficients(float freq, float q, float dBgain)
{
if (this->q != q || this->dBgain != dBgain || this->freq != freq)
{
this->dBgain = dBgain;
this->q = q;
this->freq = freq;
w0 = 2.0f * 3.141592653589793f * freq / sampleRate;
a = sqrtf(pow(10, dBgain/20.0f));
alpha = sinf(w0)/(2.0f*q);
q = 1.0f / sqrt((a + 1.0f/a)*(1.0f/s - 1.0f) + 2.0f);
cosValue = cosf(w0);
sqrtValue = sqrtf(a);
}
b0 = a * ((a + 1.0f) - (a - 1.0f) * cosValue + 2.0f * sqrtValue * alpha );
b1 = 2.0f * a * ((a - 1.0f) - (a + 1.0f) * cosValue );
b2 = a * ((a + 1.0f) - (a - 1.0f) * cosValue - 2.0f * sqrtValue * alpha );
a0 = (a + 1.0f) + (a - 1.0f) * cosValue + 2.0f * sqrtValue * alpha;
a1 = - 2.0f * ((a - 1.0f) + (a + 1.0f) * cosValue );
a2 = (a + 1.0f) + (a - 1.0f) * cosValue - 2.0f * sqrtValue * alpha;
a0 = 1.0f/a0;
b0 *= a0;
b1 *= a0;
b2 *= a0;
a1 *= a0;
a2 *= a0;
}
inline void updateHistory(float inSample, float outSample)
{
x0 = saturate(x1, -0.08f);
x1 = saturate(x2, 0.05f);
x2 = saturate(inSample, 0.01f);
y2 = y1;
y1 = outSample;
}
inline float saturate(float x, float variation)
{
return x - 0.002f * (x + variation) * x * x;
}
};
#endif

@ -0,0 +1,110 @@
/*
==============================================================================
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(__NoiseGenerator_h)
#define __NoiseGenerator_h
#include <cstdlib>
class NoiseGenerator
{
public:
float sampleRate;
int randomSeed;
float actualValue;
float deltaValue;
float actualValueFiltered;
float filterFactor;
float filterFactorInversePlusOne;
float periodRange;
float periodOffset;
float noiseFastModFilterValue;
NoiseGenerator(float sampleRate, float randomSeed)
{
this->sampleRate = sampleRate;
this->randomSeed = (int)randomSeed;
this->filterFactor = 44100.0f * 2800.0f / sampleRate;
this->filterFactorInversePlusOne = 1.0f / (filterFactor + 1.0f);
this->periodRange = 44100.0f * 25000.0f / sampleRate;
this->periodOffset = 44100.0f * 1000.0f / sampleRate;
this->noiseFastModFilterValue = 44100.0f * 10.0f / sampleRate;
//this->noiseFastModFilterValue = 10.0f;
this->deltaValue = 0.0f;
this->actualValue = 0.0f;
this->actualValueFiltered = 0.0f;
this->getNextRandomPeriod(1.0f);
}
// returns a random value [0..1]
inline float tickNoise()
{
// return ((float)(((randSeed = randSeed * 214013L + 2531011L) >> 16) & 0x7fff)/RAND_MAX);
this->randomSeed *= 16807;
return (float)(randomSeed & 0x7FFFFFFF) * 4.6566129e-010f;
//return (float)randSeed * 4.6566129e-010f;
}
// returns a lp filtered random value [0..1]
inline float tickFilteredNoise()
{
if (actualValue >= 1.0f)
{
getNextRandomPeriod(-1.0f);
}
if (actualValue <= 0.0f)
{
getNextRandomPeriod(1.0f);
}
actualValue += deltaValue;
// Exponential averager
actualValueFiltered = (actualValueFiltered * filterFactor + actualValue) * filterFactorInversePlusOne;
return actualValueFiltered;
}
inline void getNextRandomPeriod(float sign)
{
int randomPeriod = (int)(tickNoise() * this->periodRange + this->periodOffset);
deltaValue = 1.0f / (float)randomPeriod;
deltaValue *= sign;
}
inline float tickFilteredNoiseFast()
{
actualValueFiltered = (actualValueFiltered * this->noiseFastModFilterValue + tickNoise()) / (this->noiseFastModFilterValue + 1.0f);
return actualValueFiltered;
}
};
#endif

@ -0,0 +1,52 @@
/*
==============================================================================
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(__ParamChangeUtil_h)
#define __ParamChangeUtil_h
#include "math.h"
// Low pass filter for gentle parameter changes
class ParamChangeUtil
{
private:
float currentValue;
float paramWeight;
float paramWeigthInverse;
public:
// param weight should be bigger than 1
ParamChangeUtil(float sampleRate, float paramWeight)
{
currentValue = 0;
this->paramWeight = paramWeight * sampleRate / 44100.0f;
paramWeigthInverse = 1.0f / (this->paramWeight + 1.0f);
}
inline float tick(float input)
{
currentValue = (paramWeight * currentValue + input) * paramWeigthInverse;
return currentValue;
}
};
#endif

@ -0,0 +1,72 @@
/*
==============================================================================
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.
==============================================================================
*/
#ifndef Params_H
#define Params_H
/*-----------------------------------------------------------------------------
Kunz Patrick
Parameter table
-----------------------------------------------------------------------------*/
enum SYNTHPARAMETERS
{
// Controllable values [0.0..1.0
UNUSED= 0,
DRY,
WET,
DECAYTIME,
PREDELAY,
LOWSHELFGAIN,
HIGHSHELFGAIN,
STEREO,
REALSTEREOMODE,
POWER,
// Number of controllable synth paramenters
NUMPARAM,
NUMPROGRAMS = 10,
};
class Params
{
public:
float *parameters;
Params() {
parameters= new float[NUMPARAM];
// Zero program values
for(int j=0; j<NUMPARAM; j++) {
parameters[j]= 0.0f;
}
}
};
#endif

@ -0,0 +1,104 @@
#if !defined(__PeakEq_h)
#define __PeakEq_h
#include <stdio.h>
#include "math.h"
class PeakEq
{
public:
int filterDecibel;
float sampleRate;
float a0, a1, a2;
float b0, b1, b2;
float x0, x1, x2;
float y1, y2;
float outSample;
float a, w0, q, s, alpha;
float cosValue, sqrtValue;
float dBgain, freq;
PeakEq(float sampleRate, int filterDecibel)
{
this->sampleRate = sampleRate;
this->filterDecibel = filterDecibel;
a0 = a1 = a2 = 0.0f;
b0 = b1 = b2 = 0.0f;
x0 = x1 = x2 = 0.0f;
y1 = y2 = 0.0f;
q = dBgain = freq = 0.0f;
s = 2.0f;
}
// gain [0..1], q[0..1], freq[0..44100]
inline void tick(float *inSample, float freq, float q, float gain)
{
gain = filterDecibel - (1.0f - gain) * filterDecibel * 2.0f;
calcCoefficients(freq, q, gain);
outSample = b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2;
outSample = b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2;
updateHistory(*inSample, outSample);
*inSample = outSample;
}
inline void calcCoefficients(float freq, float q, float dBgain)
{
if (this->q != q || this->dBgain != dBgain || this->freq != freq)
{
this->dBgain = dBgain;
this->q = q;
this->freq = freq;
w0 = 2.0f * 3.141592653589793f * freq / sampleRate;
a = sqrtf(pow(10, dBgain/20.0f));
alpha = sinf(w0)*sinhf( logf(2.0f)/2.0f * q * w0/sinf(w0));
// q = 1.0f / sqrt((a + 1.0f/a)*(1.0f/s - 1.0f) + 2.0f);
cosValue = cosf(w0);
sqrtValue = sqrtf(a);
}
b0 = 1.0f + alpha * a;
b1 = -2.0f * cosValue;
b2 = 1.0f - alpha * a;
a0 = 1.0f + alpha / a;
a1 = -2.0f * cosValue;
a2 = 1.0f - alpha / a;
a0 = 1.0f/a0;
b0 *= a0;
b1 *= a0;
b2 *= a0;
a1 *= a0;
a2 *= a0;
}
inline void updateHistory(float inSample, float outSample)
{
x0 = saturate(x1, -0.05f);
x1 = saturate(x2, 0.04f);
x2 = inSample;
y2 = y1;
y1 = outSample;
}
inline float saturate(float x, float variation)
{
return x - 0.002f * (x + variation) * x * x;
}
};
#endif

@ -0,0 +1,303 @@
/*
==============================================================================
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(180.0f, 0.68f, sampleRate);
preAllPassFilterR = new AllPassFilter(180.0f, 0.68f, sampleRate);
postAllPassFilterL = new AllPassFilter(220.0f, 0.68f, sampleRate);
postAllPassFilterR = new AllPassFilter(220.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.1f, 0.68f, sampleRate);
allPassFiltersR[i] = new AllPassFilter(reflectionDelays[i + DELAY_LINES_COMB - 1] * 0.1f, 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.1f;
outR = feedbackValueR * 0.1f;
float scaledRoomSize = decayTime * 0.979f;
for (int i = 0; i < DELAY_LINES_COMB; i++)
{
outL += combFiltersL[i]->processInterpolated(revL, diffusionL[i]->tickFilteredNoiseFast() * 0.01f, scaledRoomSize, scaledRoomSize + 0.02f * noiseGeneratorDelayL[i]->tickFilteredNoise());
outR += combFiltersR[i]->processInterpolated(revR, diffusionR[i]->tickFilteredNoiseFast() * 0.01f, scaledRoomSize, scaledRoomSize + 0.02f * noiseGeneratorDelayR[i]->tickFilteredNoise());
}
// ----------------- Pre AllPass --------------------
outL += 0.5f * preAllPassFilterL->processInterpolated(revL, scaledRoomSize * 0.99f + 0.01f * noiseGeneratorAllPassL[0]->tickFilteredNoise(), 0.0f, true);
outR += 0.5f * preAllPassFilterR->processInterpolated(revR, scaledRoomSize * 0.99f + 0.01f * noiseGeneratorAllPassR[0]->tickFilteredNoise(), 0.0f, true);
// ----------------- Post AllPass --------------------
outL += 0.1f * postAllPassFilterL->processInterpolated(outL, scaledRoomSize * 0.99f + 0.01f, 0.0f, false);
outR += 0.1f * postAllPassFilterR->processInterpolated(outR, scaledRoomSize * 0.99f + 0.01f, 0.0f, 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

@ -0,0 +1,303 @@
/*
==============================================================================
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(100.0f, 0.68f, sampleRate);
preAllPassFilterR = new AllPassFilter(100.0f, 0.68f, sampleRate);
postAllPassFilterL = new AllPassFilter(80.0f, 0.68f, sampleRate);
postAllPassFilterR = new AllPassFilter(80.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.105f, 0.68f, sampleRate);
allPassFiltersR[i] = new AllPassFilter(reflectionDelays[i + DELAY_LINES_COMB - 1] * 0.1f, 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.99f;
for (int i = 0; i < DELAY_LINES_COMB; i++)
{
outL += combFiltersL[i]->processInterpolated(revL, diffusionL[i]->tickFilteredNoiseFast() * 0.01f, scaledRoomSize, scaledRoomSize + 0.01f * noiseGeneratorDelayL[i]->tickFilteredNoise());
outR += combFiltersR[i]->processInterpolated(revR, diffusionR[i]->tickFilteredNoiseFast() * 0.01f, scaledRoomSize, scaledRoomSize + 0.01f * noiseGeneratorDelayR[i]->tickFilteredNoise());
}
// ----------------- Pre AllPass --------------------
float invAllPassL = 0.1f * preAllPassFilterL->processInterpolated(revL, 0.99f + 0.01f * noiseGeneratorAllPassL[0]->tickFilteredNoiseFast(), 0.68f, true);
float invAllPassR = 0.1f * preAllPassFilterR->processInterpolated(revR, 0.99f + 0.01f * noiseGeneratorAllPassR[0]->tickFilteredNoiseFast(), 0.68f, true);
//// ----------------- Post AllPass --------------------
outL += 0.15f * postAllPassFilterL->processInterpolated(invAllPassL, 0.99f + 0.01f, 0.68f, false);
outR += 0.15f * postAllPassFilterR->processInterpolated(invAllPassR, 0.99f + 0.01f, 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

@ -0,0 +1,303 @@
/*
==============================================================================
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

@ -0,0 +1,316 @@
/*
==============================================================================
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(__TalReverb_h)
#define __TalReverb_h
#include "AllPassFilter.h"
#include "CombFilter.h"
#include "NoiseGenerator.h"
#include "Filter.h"
#include "math.h"
#include "AudioUtils.h"
#include "TalEq.h"
class TalReverb
{
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;
float feedbackSampleRateFactor;
AudioUtils audioUtils;
public:
TalReverb(long sampleRate)
{
// Ignore sample rates smaller then 44100 Hz
this->feedbackSampleRateFactor = sampleRate / 44100.0f;
if (this->feedbackSampleRateFactor < 1.0f) this->feedbackSampleRateFactor = 1.0f;
this->createDelaysAndCoefficients(DELAY_LINES_ALLPASS, 100.0f);
this->combFiltersPreDelayL = new CombFilter((float)MAX_PRE_DELAY_MS, 0.0f, sampleRate);
this->combFiltersPreDelayR = new CombFilter((float)MAX_PRE_DELAY_MS, 0.0f, sampleRate);
this->combFiltersL = new CombFilter *[DELAY_LINES_COMB];
this->combFiltersR = new CombFilter *[DELAY_LINES_COMB];
this->noiseGeneratorAllPassL = new NoiseGenerator *[DELAY_LINES_COMB];
this->noiseGeneratorAllPassR = new NoiseGenerator *[DELAY_LINES_COMB];
this->noiseGeneratorDelayL = new NoiseGenerator *[DELAY_LINES_COMB];
this->noiseGeneratorDelayR = new NoiseGenerator *[DELAY_LINES_COMB];
this->diffusionL = new NoiseGenerator *[DELAY_LINES_COMB];
this->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, 1.0f, sampleRate);
combFiltersR[i] = new CombFilter(reflectionDelays[i], 1.0f, sampleRate);
}
else
{
combFiltersL[i] = new CombFilter(reflectionDelays[i], 1.0f, sampleRate);
combFiltersR[i] = new CombFilter(reflectionDelays[i] * stereoSpreadFactor, 1.0f, sampleRate);
}
stereoSpreadSign *= -1.0f;
this->noiseGeneratorAllPassL[i] = new NoiseGenerator((float)sampleRate, (float)i);
this->noiseGeneratorAllPassR[i] = new NoiseGenerator((float)sampleRate, i + 163.0f);
this->noiseGeneratorDelayL[i] = new NoiseGenerator((float)sampleRate, i + 257.0f);
this->noiseGeneratorDelayR[i] = new NoiseGenerator((float)sampleRate, i + 353.0f);
this->diffusionL[i] = new NoiseGenerator((float)sampleRate, i + 455.0f);
this->diffusionR[i] = new NoiseGenerator((float)sampleRate, i + 633.0f);
}
this->preAllPassFilterL = new AllPassFilter(90.0f, 0.68f, sampleRate);
this->preAllPassFilterR = new AllPassFilter(90.0f, 0.68f, sampleRate);
this->postAllPassFilterL = new AllPassFilter(91.0f, 0.68f, sampleRate);
this->postAllPassFilterR = new AllPassFilter(91.0f, 0.68f, sampleRate);
this->allPassFiltersL = new AllPassFilter *[DELAY_LINES_ALLPASS];
this->allPassFiltersR = new AllPassFilter *[DELAY_LINES_ALLPASS];
for (int i = 0; i < DELAY_LINES_ALLPASS; i++)
{
this->allPassFiltersL[i] = new AllPassFilter(reflectionDelays[i] * 0.2f, 0.68f, sampleRate);
this->allPassFiltersR[i] = new AllPassFilter(reflectionDelays[i] * 0.2f, 0.68f, sampleRate);
}
this->talEqL = new TalEq((float)sampleRate);
this->talEqR = new TalEq((float)sampleRate);
this->decayTime = 0.5f;
this->preDelayTime = 0.0f;
this->modulationIntensity = 0.12f;
this->stereoMode = false;
this->outL = 0.0f;
this->outR = 0.0f;
this->feedbackValueL = 0.0f;
this->feedbackValueR = 0.0f;
}
~TalReverb()
{
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.9f + 0.1f;
}
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 --------------------
float feedbackFactor = 0.15f;
outL = feedbackValueL * feedbackFactor;
outR = feedbackValueR * feedbackFactor;
float scaledRoomSizeDelay = this->decayTime * 0.972f;
float scaledRoomSizeDamp = this->decayTime * 0.99f;
float invDecayTime = 0.9f * (1.0f - this->decayTime);
for (int i = 0; i < DELAY_LINES_COMB; i++)
{
outL += combFiltersL[i]->processInterpolated(revL, diffusionL[i]->tickFilteredNoiseFast() * invDecayTime, scaledRoomSizeDamp, scaledRoomSizeDelay + 0.028f * noiseGeneratorDelayL[i]->tickFilteredNoise());
outR += combFiltersR[i]->processInterpolated(revR, diffusionR[i]->tickFilteredNoiseFast() * invDecayTime, scaledRoomSizeDamp, scaledRoomSizeDelay + 0.028f * noiseGeneratorDelayR[i]->tickFilteredNoise());
}
// ----------------- Pre AllPass --------------------
float modL = preAllPassFilterL->processInterpolated(revL, 0.995f + 0.005f * noiseGeneratorAllPassL[0]->tickFilteredNoise(), 0.68f, true);
float modR = preAllPassFilterR->processInterpolated(revR, 0.995f + 0.005f * noiseGeneratorAllPassR[0]->tickFilteredNoise(), 0.68f, true);
// ----------------- Post AllPass --------------------
outL += 0.4f * postAllPassFilterL->processInterpolated(modL, decayTime, 0.68f, false);
outR += 0.4f * postAllPassFilterR->processInterpolated(modR, decayTime, 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 --------
//if (outL > 2.0f) outL = 2.0f;
//if (outR > 2.0f) outR = 2.0f;
//if (outL < -2.0f) outL = -2.0f;
//if (outR < -2.0f) outR = -2.0f;
*sampleL = outL;
*sampleR = outR;
feedbackValueL = outL;
feedbackValueR = outR;
}
void createDelaysAndCoefficients(int numlines, float delayLength)
{
this->reflectionDelays = new float[numlines];
this->reflectionGains = new float[numlines];
float volumeScale = (float)(-3.0 * delayLength / log10f(0.55f));
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

@ -0,0 +1,232 @@
/*
==============================================================================
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(__ReverbEngine_h)
#define __ReverbEngine_h
#include "Reverb.h"
#include "AudioUtils.h"
#include "Params.h"
#include "ParamChangeUtil.h"
#include "NoiseGenerator.h"
class ReverbEngine
{
public:
float *param;
TalReverb* reverb;
ParamChangeUtil* dryParamChange;
ParamChangeUtil* wetParamChange;
NoiseGenerator *noiseGenerator;
float dry;
float wet;
float stereoWidth;
float power;
float* stereoVolumeWet;
float* stereoVolumeWetReturnValue;
AudioUtils audioUtils;
ReverbEngine(float sampleRate)
{
Params *params= new Params();
this->param= params->parameters;
initialize(sampleRate);
}
~ReverbEngine()
{
delete reverb;
delete stereoVolumeWet;
delete noiseGenerator;
}
void setDry(float dry)
{
this->dry = audioUtils.getLogScaledVolume(dry, 2.0f);
}
void setWet(float wet)
{
this->wet = audioUtils.getLogScaledVolume(wet, 2.0f);
}
void setDecayTime(float decayTime)
{
float scaledDecayTime = audioUtils.getLogScaledValueInverted(decayTime);
reverb->setDecayTime(scaledDecayTime);
}
void setPreDelay(float preDelay)
{
reverb->setPreDelay(preDelay);
}
void setLowShelfGain(float lowShelfGain)
{
reverb->setLowShelfGain(lowShelfGain);
}
void setHighShelfGain(float highShelfGain)
{
reverb->setHighShelfGain(highShelfGain);
}
void setLowShelfFrequency(float lowShelfFrequency)
{
reverb->setLowShelfFrequency(lowShelfFrequency);
}
void setHighShelfFrequency(float highShelfFrequency)
{
reverb->setHighShelfFrequency(highShelfFrequency);
}
void setStereoWidth(float stereoWidth)
{
this->stereoWidth = stereoWidth;
}
void setStereoMode(float stereoMode)
{
reverb->setStereoMode(stereoMode > 0.0f ? true : false);
}
void setSampleRate(float sampleRate)
{
initialize(sampleRate);
}
void setPower(float value)
{
this->power = value;
}
float* getCurrentVolume()
{
stereoVolumeWetReturnValue[0] = stereoVolumeWet[0];
stereoVolumeWetReturnValue[1] = stereoVolumeWet[1];
stereoVolumeWet[0] -= 0.01f;
stereoVolumeWet[1] -= 0.01f;
if (stereoVolumeWet[0] < 0.0f) stereoVolumeWet[0] = 0.0f;
if (stereoVolumeWet[1] < 0.0f) stereoVolumeWet[1] = 0.0f;
if (stereoVolumeWet[0] > 1.0f) stereoVolumeWet[0] = 1.0f;
if (stereoVolumeWet[1] > 1.0f) stereoVolumeWet[1] = 1.0f;
return stereoVolumeWetReturnValue;
}
void initialize(float sampleRate)
{
if (sampleRate <= 0)
{
sampleRate = 44100.0f;
}
reverb = new TalReverb((int)sampleRate);
dryParamChange = new ParamChangeUtil(sampleRate, 300.0f);
wetParamChange = new ParamChangeUtil(sampleRate, 300.0f);
noiseGenerator = new NoiseGenerator(sampleRate, 1);
stereoVolumeWet = new float[2];
stereoVolumeWet[0] = 0.0f;
stereoVolumeWet[1] = 0.0f;
stereoVolumeWetReturnValue = new float[2];
stereoVolumeWetReturnValue[0] = 0.0f;
stereoVolumeWetReturnValue[1] = 0.0f;
dry = 1.0f;
wet = 0.5f;
stereoWidth = 1.0f;
power = 1.0f;
}
void process(float *sampleL, float *sampleR)
{
if (power > 0)
{
// avoid cpu spikes
float noise = noiseGenerator->tickNoise() * 0.000000001f;
*sampleL += noise;
*sampleR += noise;
float drysampleL = *sampleL;
float drysampleR = *sampleR;
reverb->process(sampleL, sampleR);
// Process Stereo
float actualDryValue = dryParamChange->tick(dry);
float wet1 = wet * (stereoWidth * 0.5f + 0.5f);
float wet2 = wet * ((1.0f - stereoWidth) * 0.5f);
float wetSignalL = *sampleL * wet1 + *sampleR * wet2;
float wetSignalR = *sampleR * wet1 + *sampleL * wet2;
this->setMeterValue(wetSignalL, wetSignalR);
float resultL = wetSignalL + drysampleL * actualDryValue;
float resultR = wetSignalR + drysampleR * actualDryValue;
*sampleL = resultL;
*sampleR = resultR;
}
else
{
this->setMeterValue(0.0f, 0.0f);
}
}
void setMeterValue(float valueL, float valueR)
{
float absValueL = fabsf(valueL);
float absValueR = fabsf(valueR);
if (absValueL >= stereoVolumeWet[0])
{
stereoVolumeWet[0] = absValueL;
}
if (absValueR >= stereoVolumeWet[1])
{
stereoVolumeWet[1] = absValueR;
}
}
void resetMeterValue()
{
this->setMeterValue(0.0f, 0.0f);
}
};
#endif

@ -0,0 +1,93 @@
/*
==============================================================================
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(__TalEq_h)
#define __TalEq_h
#include "HighShelf.h"
#include "LowShelf.h"
class TalEq
{
private:
HighShelf *highShelf;
LowShelf *lowShelf;
float lowShelfGain;
float highShelfGain;
float lowShelfFrequency;
float highShelfFrequency;
AudioUtils audioUtils;
public:
TalEq(float sampleRate)
{
initialize(sampleRate);
}
~TalEq()
{
}
void setLowShelfGain(float lowShelfGain)
{
this->lowShelfGain = lowShelfGain * 0.5f;
}
void setHighShelfGain(float highShelfGain)
{
this->highShelfGain = highShelfGain * 0.5f;
}
void setLowShelfFrequency(float lowShelfFrequency)
{
this->lowShelfFrequency = audioUtils.getLogScaledFrequency(lowShelfFrequency);
}
void setHighShelfFrequency(float highShelfFrequency)
{
this->highShelfFrequency = audioUtils.getLogScaledFrequency(highShelfFrequency);
}
void initialize(float sampleRate)
{
highShelf = new HighShelf(sampleRate, 18);
lowShelf = new LowShelf(sampleRate, 18);
lowShelfGain = 0.5f;
highShelfGain = 0.5f;
lowShelfFrequency = 1000.0f;
highShelfFrequency = 200.0f;
}
void process(float *sample)
{
highShelf->tick(sample, highShelfFrequency, 1.05f, highShelfGain); // 0..0.5
lowShelf->tick(sample, lowShelfFrequency, 1.05f, lowShelfGain); // 0..0.5
}
};
#endif

@ -196,6 +196,21 @@ const CUIMenu::TMenuItem CUIMenu::s_FXBigMuff[] =
{0}
};
const CUIMenu::TMenuItem CUIMenu::s_FXTalReverb3[] =
{
{"Bypass", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::BYPASS},
{"Dry", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::DRY},
{"Wet", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::WET},
{"Decay Time", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::DECAYTIME},
{"Predelay", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::PREDELAY},
{"Low Shelf", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::LOWSHELFGAIN},
{"High Shelf", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::HIGHSHELFGAIN},
{"Stereo Width", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::STEREO},
{"Stereo Mode", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::REALSTEREOMODE},
{"Power", EditTGFXParameter, 0, AudioEffectTalReverb3::Param::POWER},
{0}
};
// inserting menu items before "OP1" affect OPShortcutHandler()
const CUIMenu::TMenuItem CUIMenu::s_EditVoiceMenu[] =
{
@ -287,7 +302,7 @@ const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown]
{0, CSysExFileLoader::VoicesPerBank-1, 1}, // TGParameterProgram
{0, 127, 8, ToVolume}, // TGParameterVolume
{0, 127, 8, ToPan}, // TGParameterPan
{0, 5, 1, ToFXType}, // TGParameterInsertFXType
{0, 6, 1, ToFXType}, // TGParameterInsertFXType
{-99, 99, 1}, // TGParameterMasterTune
{0, 99, 1}, // TGParameterCutoff
{0, 99, 1}, // TGParameterResonance
@ -363,6 +378,21 @@ const CUIMenu::TParameter CUIMenu::s_TGFXBigMuffParam[AudioEffectBigMuff::Param:
{0, 100, 1} // LEVEL
};
// must match AudioEffectTalReverb3::Param
const CUIMenu::TParameter CUIMenu::s_TGFXTalReverb3Param[AudioEffectTalReverb3::Param::UNKNOWN] =
{
{0, 1, 1, ToOnOff}, // BYPASS
{0, 100, 1}, // DRY
{0, 100, 1}, // WET
{0, 100, 1}, // DECAYTIME
{0, 100, 1}, // PREDELAY
{0, 100, 1}, // LOWSHELFGAIN
{0, 100, 1}, // HIGHSHELFGAIN
{0, 100, 1}, // STEREO
{0, 100, 1}, // REALSTEREOMODE
{0, 100, 1} // POWER
};
// must match DexedVoiceParameters in Synth_Dexed
const CUIMenu::TParameter CUIMenu::s_VoiceParameter[] =
{
@ -869,24 +899,21 @@ void CUIMenu::EditInsertFX (CUIMenu *pUIMenu, TMenuEvent Event)
case EFFECT_CHORUS:
pUIMenu->m_pCurrentMenu = s_FXChorus;
break;
case EFFECT_DELAY:
pUIMenu->m_pCurrentMenu = s_FXDelay;
break;
case EFFECT_LPF:
pUIMenu->m_pCurrentMenu = s_FXLPFilter;
break;
case EFFECT_DS1:
pUIMenu->m_pCurrentMenu = s_FXDS1;
break;
case EFFECT_BIGMUFF:
pUIMenu->m_pCurrentMenu = s_FXBigMuff;
break;
case EFFECT_TALREVERB3:
pUIMenu->m_pCurrentMenu = s_FXTalReverb3;
break;
default:
pUIMenu->m_pCurrentMenu = s_FXNone;
break;
@ -980,6 +1007,9 @@ void CUIMenu::EditTGFXParameter (CUIMenu *pUIMenu, TMenuEvent Event)
case EFFECT_BIGMUFF:
pParam = s_TGFXBigMuffParam[nParam];
break;
case EFFECT_TALREVERB3:
pParam = s_TGFXTalReverb3Param[nParam];
break;
default:
return;
}

@ -158,6 +158,7 @@ private:
static const TMenuItem s_FXLPFilter[];
static const TMenuItem s_FXDS1[];
static const TMenuItem s_FXBigMuff[];
static const TMenuItem s_FXTalReverb3[];
static const TMenuItem s_EditVoiceMenu[];
static const TMenuItem s_OperatorMenu[];
static const TMenuItem s_SaveMenu[];
@ -175,6 +176,7 @@ private:
static const TParameter s_TGFXLPFParam[];
static const TParameter s_TGFXDS1Param[];
static const TParameter s_TGFXBigMuffParam[];
static const TParameter s_TGFXTalReverb3Param[];
static const TParameter s_VoiceParameter[];
static const TParameter s_OPParameter[];

Loading…
Cancel
Save