diff --git a/src/Makefile b/src/Makefile index 2f81a6f..3522c14 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 diff --git a/src/effect_base.cpp b/src/effect_base.cpp index abbc9bd..1aff46b 100644 --- a/src/effect_base.cpp +++ b/src/effect_base.cpp @@ -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); } diff --git a/src/effect_base.h b/src/effect_base.h index 246e21f..2b151c2 100644 --- a/src/effect_base.h +++ b/src/effect_base.h @@ -11,6 +11,7 @@ #define EFFECT_LPF 3 #define EFFECT_DS1 4 #define EFFECT_BIGMUFF 5 +#define EFFECT_TALREVERB3 6 class AudioEffect { diff --git a/src/effect_talreverb3.cpp b/src/effect_talreverb3.cpp new file mode 100644 index 0000000..846f14d --- /dev/null +++ b/src/effect_talreverb3.cpp @@ -0,0 +1,112 @@ +#include +#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]); + } +} \ No newline at end of file diff --git a/src/effect_talreverb3.h b/src/effect_talreverb3.h new file mode 100644 index 0000000..8399d3c --- /dev/null +++ b/src/effect_talreverb3.h @@ -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 \ No newline at end of file diff --git a/src/effects.h b/src/effects.h index 07c73a4..c83f21f 100644 --- a/src/effects.h +++ b/src/effects.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"; } diff --git a/src/tal-reverb-3/AllPassFilter.h b/src/tal-reverb-3/AllPassFilter.h new file mode 100644 index 0000000..1d14e58 --- /dev/null +++ b/src/tal-reverb-3/AllPassFilter.h @@ -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 \ No newline at end of file diff --git a/src/tal-reverb-3/AudioUtils.h b/src/tal-reverb-3/AudioUtils.h new file mode 100644 index 0000000..d83c4bd --- /dev/null +++ b/src/tal-reverb-3/AudioUtils.h @@ -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 + diff --git a/src/tal-reverb-3/CombFilter.h b/src/tal-reverb-3/CombFilter.h new file mode 100644 index 0000000..cd3c245 --- /dev/null +++ b/src/tal-reverb-3/CombFilter.h @@ -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 diff --git a/src/tal-reverb-3/Filter.h b/src/tal-reverb-3/Filter.h new file mode 100644 index 0000000..4b8db7b --- /dev/null +++ b/src/tal-reverb-3/Filter.h @@ -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 diff --git a/src/tal-reverb-3/HighShelf.h b/src/tal-reverb-3/HighShelf.h new file mode 100644 index 0000000..187dac3 --- /dev/null +++ b/src/tal-reverb-3/HighShelf.h @@ -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 diff --git a/src/tal-reverb-3/LowShelf.h b/src/tal-reverb-3/LowShelf.h new file mode 100644 index 0000000..b47ddf4 --- /dev/null +++ b/src/tal-reverb-3/LowShelf.h @@ -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 diff --git a/src/tal-reverb-3/NoiseGenerator.h b/src/tal-reverb-3/NoiseGenerator.h new file mode 100644 index 0000000..69b270e --- /dev/null +++ b/src/tal-reverb-3/NoiseGenerator.h @@ -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 + +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 diff --git a/src/tal-reverb-3/ParamChangeUtil.h b/src/tal-reverb-3/ParamChangeUtil.h new file mode 100644 index 0000000..b96deb1 --- /dev/null +++ b/src/tal-reverb-3/ParamChangeUtil.h @@ -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 diff --git a/src/tal-reverb-3/Params.h b/src/tal-reverb-3/Params.h new file mode 100644 index 0000000..b300765 --- /dev/null +++ b/src/tal-reverb-3/Params.h @@ -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 +#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 diff --git a/src/tal-reverb-3/Reverb - Bestest.h b/src/tal-reverb-3/Reverb - Bestest.h new file mode 100644 index 0000000..0454c5f --- /dev/null +++ b/src/tal-reverb-3/Reverb - Bestest.h @@ -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 diff --git a/src/tal-reverb-3/Reverb - Great Sound.h b/src/tal-reverb-3/Reverb - Great Sound.h new file mode 100644 index 0000000..efe4bbb --- /dev/null +++ b/src/tal-reverb-3/Reverb - Great Sound.h @@ -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 diff --git a/src/tal-reverb-3/Reverb - improvement.h b/src/tal-reverb-3/Reverb - improvement.h new file mode 100644 index 0000000..b7cbbea --- /dev/null +++ b/src/tal-reverb-3/Reverb - improvement.h @@ -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 diff --git a/src/tal-reverb-3/Reverb.h b/src/tal-reverb-3/Reverb.h new file mode 100644 index 0000000..f6aecbc --- /dev/null +++ b/src/tal-reverb-3/Reverb.h @@ -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 diff --git a/src/tal-reverb-3/ReverbEngine.h b/src/tal-reverb-3/ReverbEngine.h new file mode 100644 index 0000000..d5db578 --- /dev/null +++ b/src/tal-reverb-3/ReverbEngine.h @@ -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 + diff --git a/src/tal-reverb-3/TalEq.h b/src/tal-reverb-3/TalEq.h new file mode 100644 index 0000000..64c1a4b --- /dev/null +++ b/src/tal-reverb-3/TalEq.h @@ -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 + diff --git a/src/uimenu.cpp b/src/uimenu.cpp index bd224c4..4d7a72c 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -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; } diff --git a/src/uimenu.h b/src/uimenu.h index 22923d8..682ac30 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -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[];