Added MVerb effect

pull/764/head
Javier Nonis 6 months ago
parent bf30d1a1c9
commit 6d673aa8be
  1. 2
      src/Makefile
  2. 1
      src/effect_base.h
  3. 116
      src/effect_mverb.cpp
  4. 54
      src/effect_mverb.h
  5. 1
      src/effect_talreverb3.cpp
  6. 1
      src/effect_talreverb3.h
  7. 4
      src/effects.h
  8. 842
      src/mverb/MVerb.h
  9. 40
      src/uimenu.cpp
  10. 2
      src/uimenu.h

@ -9,7 +9,7 @@ CMSIS_DIR = ../CMSIS_5/CMSIS
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_base.o effect_chorus.o effect_delay.o effect_mverb.o \
effect_talreverb3.o effect_ds1.o effect_bigmuff.o \
moddistortion/Distortion_DS1.o moddistortion/Distortion_BigMuff.o \
moddistortion/HyperbolicTables.o moddistortion/OverSample.o \

@ -16,6 +16,7 @@
#define EFFECT_BIGMUFF 5
#define EFFECT_TALREVERB3 6
#define EFFECT_REVERB 7
#define EFFECT_MVERB 8
class AudioEffect
{

@ -0,0 +1,116 @@
/*
* MVerb Reverb Port
* Ported from https://github.com/DISTRHO/MVerb
* Original https://github.com/martineastwood/mverb/
*
* Javier Nonis (https://github.com/jnonis) - 2024
*/
#include "effect_mverb.h"
AudioEffectMVerb::AudioEffectMVerb(float32_t samplerate) : AudioEffect(samplerate)
{
fVerb.setSampleRate(samplerate);
fVerb.setParameter(MVerb<float>::DAMPINGFREQ, 0.5f);
fVerb.setParameter(MVerb<float>::DENSITY, 0.5f);
fVerb.setParameter(MVerb<float>::BANDWIDTHFREQ, 0.5f);
fVerb.setParameter(MVerb<float>::DECAY, 0.5f);
fVerb.setParameter(MVerb<float>::PREDELAY, 0.5f);
fVerb.setParameter(MVerb<float>::SIZE, 0.75f);
fVerb.setParameter(MVerb<float>::GAIN, 1.0f);
fVerb.setParameter(MVerb<float>::MIX, 0.5f);
fVerb.setParameter(MVerb<float>::EARLYMIX, 0.5f);
fVerb.reset();
}
AudioEffectMVerb::~AudioEffectMVerb()
{
}
void AudioEffectMVerb::initializeSendFX()
{
this->setParameter(AudioEffectMVerb::Param::MIX, 100);
}
void AudioEffectMVerb::setParameter(unsigned param, unsigned value)
{
switch (param)
{
case AudioEffectMVerb::Param::BYPASS:
this->setBypass(value == 1);
break;
case AudioEffectMVerb::Param::DAMPINGFREQ:
fVerb.setParameter(MVerb<float>::DAMPINGFREQ, (float) value / 100.0f);
break;
case AudioEffectMVerb::Param::DENSITY:
fVerb.setParameter(MVerb<float>::DENSITY, (float) value / 100.0f);
break;
case AudioEffectMVerb::Param::BANDWIDTHFREQ:
fVerb.setParameter(MVerb<float>::BANDWIDTHFREQ, (float) value / 100.0f);
break;
case AudioEffectMVerb::Param::DECAY:
fVerb.setParameter(MVerb<float>::DECAY, (float) value / 100.0f);
break;
case AudioEffectMVerb::Param::PREDELAY:
fVerb.setParameter(MVerb<float>::PREDELAY, (float) value / 100.0f);
break;
case AudioEffectMVerb::Param::SIZE:
fVerb.setParameter(MVerb<float>::SIZE, (float) value / 100.0f);
break;
case AudioEffectMVerb::Param::GAIN:
fVerb.setParameter(MVerb<float>::GAIN, (float) value / 100.0f);
break;
case AudioEffectMVerb::Param::MIX:
fVerb.setParameter(MVerb<float>::MIX, (float) value / 100.0f);
break;
case AudioEffectMVerb::Param::EARLYMIX:
fVerb.setParameter(MVerb<float>::EARLYMIX, (float) value / 100.0f);
break;
default:
break;
}
}
unsigned AudioEffectMVerb::getParameter(unsigned param)
{
switch (param)
{
case AudioEffectMVerb::Param::BYPASS:
return this->getBypass() ? 1 : 0;
case AudioEffectMVerb::Param::DAMPINGFREQ:
return roundf(fVerb.getParameter(MVerb<float>::DAMPINGFREQ) * 100);
case AudioEffectMVerb::Param::DENSITY:
return roundf(fVerb.getParameter(MVerb<float>::DENSITY) * 100);
case AudioEffectMVerb::Param::BANDWIDTHFREQ:
return roundf(fVerb.getParameter(MVerb<float>::BANDWIDTHFREQ) * 100);
case AudioEffectMVerb::Param::DECAY:
return roundf(fVerb.getParameter(MVerb<float>::DECAY) * 100);
case AudioEffectMVerb::Param::PREDELAY:
return roundf(fVerb.getParameter(MVerb<float>::PREDELAY) * 100);
case AudioEffectMVerb::Param::SIZE:
return roundf(fVerb.getParameter(MVerb<float>::SIZE) * 100);
case AudioEffectMVerb::Param::GAIN:
return roundf(fVerb.getParameter(MVerb<float>::GAIN) * 100);
case AudioEffectMVerb::Param::MIX:
return roundf(fVerb.getParameter(MVerb<float>::MIX) * 100);
case AudioEffectMVerb::Param::EARLYMIX:
return roundf(fVerb.getParameter(MVerb<float>::EARLYMIX) * 100);
default:
return 0;
}
}
void AudioEffectMVerb::doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len)
{
const float32_t* inputs[2];
inputs[0] = inblockL;
inputs[1] = inblockR;
float32_t* outputs[2];
outputs[0] = outblockL;
outputs[1] = outblockR;
fVerb.process(inputs, outputs, static_cast<int>(len));
}

@ -0,0 +1,54 @@
/*
* MVerb Reverb Port
* Ported from https://github.com/DISTRHO/MVerb
* Original https://github.com/martineastwood/mverb/
*
* Javier Nonis (https://github.com/jnonis) - 2024
*/
#ifndef _EFFECT_MVERB_H
#define _EFFECT_MVERB_H
#include "effect_base.h"
#include "mverb/MVerb.h"
class AudioEffectMVerb : public AudioEffect
{
public:
enum Param
{
BYPASS,
DAMPINGFREQ,
DENSITY,
BANDWIDTHFREQ,
DECAY,
PREDELAY,
SIZE,
GAIN,
MIX,
EARLYMIX,
UNKNOWN
};
AudioEffectMVerb(float32_t samplerate);
virtual ~AudioEffectMVerb();
virtual unsigned getId()
{
return EFFECT_MVERB;
}
virtual void initializeSendFX();
virtual void setParameter(unsigned param, unsigned value);
virtual unsigned getParameter(unsigned param);
protected:
virtual size_t getParametersSize()
{
return AudioEffectMVerb::Param::UNKNOWN;
}
virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len);
private:
MVerb<float> fVerb;
};
#endif // _EFFECT_MVERB_H

@ -1,6 +1,7 @@
/*
* Tal Reverb 3 Port
* Ported from https://github.com/DISTRHO/DISTRHO-Ports/tree/master/ports-juce5/tal-reverb-3
* Original https://tal-software.com/
*
* Javier Nonis (https://github.com/jnonis) - 2024
*/

@ -1,6 +1,7 @@
/*
* Tal Reverb 3 Port
* Ported from https://github.com/DISTRHO/DISTRHO-Ports/tree/master/ports-juce5/tal-reverb-3
* Original https://tal-software.com/
*
* Javier Nonis (https://github.com/jnonis) - 2024
*/

@ -14,6 +14,7 @@
#include "effect_bigmuff.h"
#include "effect_talreverb3.h"
#include "effect_platervbstereo.h"
#include "effect_mverb.h"
inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate)
{
@ -33,6 +34,8 @@ inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate)
return new AudioEffectTalReverb3(samplerate);
case EFFECT_REVERB:
return new AudioEffectPlateReverb(samplerate);
case EFFECT_MVERB:
return new AudioEffectMVerb(samplerate);
case EFFECT_NONE:
default:
return new AudioEffectNone(samplerate);
@ -50,6 +53,7 @@ inline std::string getFXTypeName(int nValue)
case EFFECT_BIGMUFF: return "Big Muff";
case EFFECT_TALREVERB3: return "TalRvrb3";
case EFFECT_REVERB: return "Reverb";
case EFFECT_MVERB: return "MVerb";
case EFFECT_NONE:
default: return "None";
}

@ -0,0 +1,842 @@
// Copyright (c) 2010 Martin Eastwood
// This code is distributed under the terms of the GNU General Public License
// MVerb is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// at your option) any later version.
//
// MVerb is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this MVerb. If not, see <http://www.gnu.org/licenses/>.
#ifndef _EMVERB_H
#define _EMVERB_H
#include <cmath>
#include <cstring>
//forward declaration
template<typename T, int maxLength> class Allpass;
template<typename T, int maxLength> class StaticAllpassFourTap;
template<typename T, int maxLength> class StaticDelayLine;
template<typename T, int maxLength> class StaticDelayLineFourTap;
template<typename T, int maxLength> class StaticDelayLineEightTap;
template<typename T, int OverSampleCount> class StateVariable;
template<typename T>
class MVerb
{
private:
Allpass<T, 96000> allpass[4];
StaticAllpassFourTap<T, 96000> allpassFourTap[4];
StateVariable<T,4> bandwidthFilter[2];
StateVariable<T,4> damping[2];
StaticDelayLine<T, 96000> predelay;
StaticDelayLineFourTap<T, 96000> staticDelayLine[4];
StaticDelayLineEightTap<T, 96000> earlyReflectionsDelayLine[2];
T SampleRate, DampingFreq, Density1, Density2, BandwidthFreq, PreDelayTime, Decay, Gain, Mix, EarlyMix, Size;
T MixSmooth, EarlyLateSmooth, BandwidthSmooth, DampingSmooth, PredelaySmooth, SizeSmooth, DensitySmooth, DecaySmooth;
T PreviousLeftTank, PreviousRightTank;
int ControlRate, ControlRateCounter;
public:
enum
{
DAMPINGFREQ=0,
DENSITY,
BANDWIDTHFREQ,
DECAY,
PREDELAY,
SIZE,
GAIN,
MIX,
EARLYMIX,
NUM_PARAMS
};
MVerb(){
DampingFreq = 0.9;
BandwidthFreq = 0.9;
SampleRate = 44100.;
Decay = 0.5;
Gain = 1.;
Mix = 1.;
Size = 1.;
EarlyMix = 1.;
PreviousLeftTank = 0.;
PreviousRightTank = 0.;
PreDelayTime = 100 * (SampleRate / 1000);
MixSmooth = EarlyLateSmooth = BandwidthSmooth = DampingSmooth = PredelaySmooth = SizeSmooth = DecaySmooth = DensitySmooth = 0.;
ControlRate = SampleRate / 1000;
ControlRateCounter = 0;
reset();
}
~MVerb(){
//nowt to do here
}
void process(const T **inputs, T **outputs, int sampleFrames){
T OneOverSampleFrames = 1. / sampleFrames;
T MixDelta = (Mix - MixSmooth) * OneOverSampleFrames;
T EarlyLateDelta = (EarlyMix - EarlyLateSmooth) * OneOverSampleFrames;
T BandwidthDelta = (((BandwidthFreq * 18400.) + 100.) - BandwidthSmooth) * OneOverSampleFrames;
T DampingDelta = (((DampingFreq * 18400.) + 100.) - DampingSmooth) * OneOverSampleFrames;
T PredelayDelta = ((PreDelayTime * 200 * (SampleRate / 1000)) - PredelaySmooth) * OneOverSampleFrames;
T SizeDelta = (Size - SizeSmooth) * OneOverSampleFrames;
T DecayDelta = (((0.7995f * Decay) + 0.005) - DecaySmooth) * OneOverSampleFrames;
T DensityDelta = (((0.7995f * Density1) + 0.005) - DensitySmooth) * OneOverSampleFrames;
for(int i=0;i<sampleFrames;++i){
T left = inputs[0][i];
T right = inputs[1][i];
MixSmooth += MixDelta;
EarlyLateSmooth += EarlyLateDelta;
BandwidthSmooth += BandwidthDelta;
DampingSmooth += DampingDelta;
PredelaySmooth += PredelayDelta;
SizeSmooth += SizeDelta;
DecaySmooth += DecayDelta;
DensitySmooth += DensityDelta;
if (ControlRateCounter >= ControlRate){
ControlRateCounter = 0;
bandwidthFilter[0].Frequency(BandwidthSmooth);
bandwidthFilter[1].Frequency(BandwidthSmooth);
damping[0].Frequency(DampingSmooth);
damping[1].Frequency(DampingSmooth);
}
++ControlRateCounter;
predelay.SetLength(PredelaySmooth);
Density2 = DecaySmooth + 0.15;
if (Density2 > 0.5)
Density2 = 0.5;
if (Density2 < 0.25)
Density2 = 0.25;
allpassFourTap[1].SetFeedback(Density2);
allpassFourTap[3].SetFeedback(Density2);
allpassFourTap[0].SetFeedback(Density1);
allpassFourTap[2].SetFeedback(Density1);
T bandwidthLeft = bandwidthFilter[0](left) ;
T bandwidthRight = bandwidthFilter[1](right) ;
T earlyReflectionsL = earlyReflectionsDelayLine[0] ( bandwidthLeft * 0.5 + bandwidthRight * 0.3 )
+ earlyReflectionsDelayLine[0].GetIndex(2) * 0.6
+ earlyReflectionsDelayLine[0].GetIndex(3) * 0.4
+ earlyReflectionsDelayLine[0].GetIndex(4) * 0.3
+ earlyReflectionsDelayLine[0].GetIndex(5) * 0.3
+ earlyReflectionsDelayLine[0].GetIndex(6) * 0.1
+ earlyReflectionsDelayLine[0].GetIndex(7) * 0.1
+ ( bandwidthLeft * 0.4 + bandwidthRight * 0.2 ) * 0.5 ;
T earlyReflectionsR = earlyReflectionsDelayLine[1] ( bandwidthLeft * 0.3 + bandwidthRight * 0.5 )
+ earlyReflectionsDelayLine[1].GetIndex(2) * 0.6
+ earlyReflectionsDelayLine[1].GetIndex(3) * 0.4
+ earlyReflectionsDelayLine[1].GetIndex(4) * 0.3
+ earlyReflectionsDelayLine[1].GetIndex(5) * 0.3
+ earlyReflectionsDelayLine[1].GetIndex(6) * 0.1
+ earlyReflectionsDelayLine[1].GetIndex(7) * 0.1
+ ( bandwidthLeft * 0.2 + bandwidthRight * 0.4 ) * 0.5 ;
T predelayMonoInput = predelay(( bandwidthRight + bandwidthLeft ) * 0.5f);
T smearedInput = predelayMonoInput;
for(int j=0;j<4;j++)
smearedInput = allpass[j] ( smearedInput );
T leftTank = allpassFourTap[0] ( smearedInput + PreviousRightTank ) ;
leftTank = staticDelayLine[0] (leftTank);
leftTank = damping[0](leftTank);
leftTank = allpassFourTap[1](leftTank);
leftTank = staticDelayLine[1](leftTank);
T rightTank = allpassFourTap[2] (smearedInput + PreviousLeftTank) ;
rightTank = staticDelayLine[2](rightTank);
rightTank = damping[1] (rightTank);
rightTank = allpassFourTap[3](rightTank);
rightTank = staticDelayLine[3](rightTank);
PreviousLeftTank = leftTank * DecaySmooth;
PreviousRightTank = rightTank * DecaySmooth;
T accumulatorL = (0.6*staticDelayLine[2].GetIndex(1))
+(0.6*staticDelayLine[2].GetIndex(2))
-(0.6*allpassFourTap[3].GetIndex(1))
+(0.6*staticDelayLine[3].GetIndex(1))
-(0.6*staticDelayLine[0].GetIndex(1))
-(0.6*allpassFourTap[1].GetIndex(1))
-(0.6*staticDelayLine[1].GetIndex(1));
T accumulatorR = (0.6*staticDelayLine[0].GetIndex(2))
+(0.6*staticDelayLine[0].GetIndex(3))
-(0.6*allpassFourTap[1].GetIndex(2))
+(0.6*staticDelayLine[1].GetIndex(2))
-(0.6*staticDelayLine[2].GetIndex(3))
-(0.6*allpassFourTap[3].GetIndex(2))
-(0.6*staticDelayLine[3].GetIndex(2));
accumulatorL = ((accumulatorL * EarlyMix) + ((1 - EarlyMix) * earlyReflectionsL));
accumulatorR = ((accumulatorR * EarlyMix) + ((1 - EarlyMix) * earlyReflectionsR));
left = ( left + MixSmooth * ( accumulatorL - left ) ) * Gain;
right = ( right + MixSmooth * ( accumulatorR - right ) ) * Gain;
outputs[0][i] = left;
outputs[1][i] = right;
}
}
void reset(){
ControlRateCounter = 0;
bandwidthFilter[0].SetSampleRate (SampleRate );
bandwidthFilter[1].SetSampleRate (SampleRate );
bandwidthFilter[0].Reset();
bandwidthFilter[1].Reset();
damping[0].SetSampleRate (SampleRate );
damping[1].SetSampleRate (SampleRate );
damping[0].Reset();
damping[1].Reset();
predelay.Clear();
predelay.SetLength(PreDelayTime);
allpass[0].Clear();
allpass[1].Clear();
allpass[2].Clear();
allpass[3].Clear();
allpass[0].SetLength (0.0048 * SampleRate);
allpass[1].SetLength (0.0036 * SampleRate);
allpass[2].SetLength (0.0127 * SampleRate);
allpass[3].SetLength (0.0093 * SampleRate);
allpass[0].SetFeedback (0.75);
allpass[1].SetFeedback (0.75);
allpass[2].SetFeedback (0.625);
allpass[3].SetFeedback (0.625);
allpassFourTap[0].Clear();
allpassFourTap[1].Clear();
allpassFourTap[2].Clear();
allpassFourTap[3].Clear();
allpassFourTap[0].SetLength(0.020 * SampleRate * Size);
allpassFourTap[1].SetLength(0.060 * SampleRate * Size);
allpassFourTap[2].SetLength(0.030 * SampleRate * Size);
allpassFourTap[3].SetLength(0.089 * SampleRate * Size);
allpassFourTap[0].SetFeedback(Density1);
allpassFourTap[1].SetFeedback(Density2);
allpassFourTap[2].SetFeedback(Density1);
allpassFourTap[3].SetFeedback(Density2);
allpassFourTap[0].SetIndex(0,0,0,0);
allpassFourTap[1].SetIndex(0,0.006 * SampleRate * Size, 0.041 * SampleRate * Size, 0);
allpassFourTap[2].SetIndex(0,0,0,0);
allpassFourTap[3].SetIndex(0,0.031 * SampleRate * Size, 0.011 * SampleRate * Size, 0);
staticDelayLine[0].Clear();
staticDelayLine[1].Clear();
staticDelayLine[2].Clear();
staticDelayLine[3].Clear();
staticDelayLine[0].SetLength(0.15 * SampleRate * Size);
staticDelayLine[1].SetLength(0.12 * SampleRate * Size);
staticDelayLine[2].SetLength(0.14 * SampleRate * Size);
staticDelayLine[3].SetLength(0.11 * SampleRate * Size);
staticDelayLine[0].SetIndex(0, 0.067 * SampleRate * Size, 0.011 * SampleRate * Size , 0.121 * SampleRate * Size);
staticDelayLine[1].SetIndex(0, 0.036 * SampleRate * Size, 0.089 * SampleRate * Size , 0);
staticDelayLine[2].SetIndex(0, 0.0089 * SampleRate * Size, 0.099 * SampleRate * Size , 0);
staticDelayLine[3].SetIndex(0, 0.067 * SampleRate * Size, 0.0041 * SampleRate * Size , 0);
earlyReflectionsDelayLine[0].Clear();
earlyReflectionsDelayLine[1].Clear();
earlyReflectionsDelayLine[0].SetLength(0.089 * SampleRate);
earlyReflectionsDelayLine[0].SetIndex (0, 0.0199*SampleRate, 0.0219*SampleRate, 0.0354*SampleRate,0.0389*SampleRate, 0.0414*SampleRate, 0.0692*SampleRate, 0);
earlyReflectionsDelayLine[1].SetLength(0.069 * SampleRate);
earlyReflectionsDelayLine[1].SetIndex (0, 0.0099*SampleRate, 0.011*SampleRate, 0.0182*SampleRate,0.0189*SampleRate, 0.0213*SampleRate, 0.0431*SampleRate, 0);
}
void setParameter(int index, T value){
switch(index){
case DAMPINGFREQ:
DampingFreq = /* 1. - */ value; // FIXME?
break;
case DENSITY:
Density1 = value;
break;
case BANDWIDTHFREQ:
BandwidthFreq = value;
break;
case PREDELAY:
PreDelayTime = value;
break;
case SIZE:
Size = value;
allpassFourTap[0].Clear();
allpassFourTap[1].Clear();
allpassFourTap[2].Clear();
allpassFourTap[3].Clear();
allpassFourTap[0].SetLength(0.020 * SampleRate * Size);
allpassFourTap[1].SetLength(0.060 * SampleRate * Size);
allpassFourTap[2].SetLength(0.030 * SampleRate * Size);
allpassFourTap[3].SetLength(0.089 * SampleRate * Size);
allpassFourTap[1].SetIndex(0,0.006 * SampleRate * Size, 0.041 * SampleRate * Size, 0);
allpassFourTap[3].SetIndex(0,0.031 * SampleRate * Size, 0.011 * SampleRate * Size, 0);
staticDelayLine[0].Clear();
staticDelayLine[1].Clear();
staticDelayLine[2].Clear();
staticDelayLine[3].Clear();
staticDelayLine[0].SetLength(0.15 * SampleRate * Size);
staticDelayLine[1].SetLength(0.12 * SampleRate * Size);
staticDelayLine[2].SetLength(0.14 * SampleRate * Size);
staticDelayLine[3].SetLength(0.11 * SampleRate * Size);
staticDelayLine[0].SetIndex(0, 0.067 * SampleRate * Size, 0.011 * SampleRate * Size , 0.121 * SampleRate * Size);
staticDelayLine[1].SetIndex(0, 0.036 * SampleRate * Size, 0.089 * SampleRate * Size , 0);
staticDelayLine[2].SetIndex(0, 0.0089 * SampleRate * Size, 0.099 * SampleRate * Size , 0);
staticDelayLine[3].SetIndex(0, 0.067 * SampleRate * Size, 0.0041 * SampleRate * Size , 0);
break;
case DECAY:
Decay = value;
break;
case GAIN:
Gain = value;
break;
case MIX:
Mix = value;
break;
case EARLYMIX:
EarlyMix = value;
break;
}
}
float getParameter(int index) const{
switch(index){
case DAMPINGFREQ:
return DampingFreq;
break;
case DENSITY:
return Density1;
break;
case BANDWIDTHFREQ:
return BandwidthFreq;
break;
case PREDELAY:
return PreDelayTime;
break;
case SIZE:
return Size;
break;
case DECAY:
return Decay;
break;
case GAIN:
return Gain;
break;
case MIX:
return Mix;
break;
case EARLYMIX:
return EarlyMix;
break;
default: return 0.f;
break;
}
}
void setSampleRate(T sr){
SampleRate = sr;
ControlRate = SampleRate / 1000;
reset();
}
};
template<typename T, int maxLength>
class Allpass
{
private:
T buffer[maxLength];
int index;
int Length;
T Feedback;
public:
Allpass()
{
SetLength ( maxLength - 1 );
Clear();
Feedback = 0.5;
}
T operator()(T input)
{
T output;
T bufout;
bufout = buffer[index];
T temp = input * -Feedback;
output = bufout + temp;
buffer[index] = input + ((bufout+temp)*Feedback);
if(++index>=Length) index = 0;
return output;
}
void SetLength (int Length)
{
if( Length >= maxLength )
Length = maxLength;
if( Length < 0 )
Length = 0;
this->Length = Length;
}
void SetFeedback(T feedback)
{
Feedback = feedback;
}
void Clear()
{
std::memset(buffer, 0, sizeof(buffer));
index = 0;
}
int GetLength() const
{
return Length;
}
};
template<typename T, int maxLength>
class StaticAllpassFourTap
{
private:
T buffer[maxLength];
int index1, index2, index3, index4;
int Length;
T Feedback;
public:
StaticAllpassFourTap()
{
SetLength ( maxLength - 1 );
Clear();
Feedback = 0.5;
}
T operator()(T input)
{
T output;
T bufout;
bufout = buffer[index1];
T temp = input * -Feedback;
output = bufout + temp;
buffer[index1] = input + ((bufout+temp)*Feedback);
if(++index1>=Length)
index1 = 0;
if(++index2 >= Length)
index2 = 0;
if(++index3 >= Length)
index3 = 0;
if(++index4 >= Length)
index4 = 0;
return output;
}
void SetIndex (int Index1, int Index2, int Index3, int Index4)
{
index1 = Index1;
index2 = Index2;
index3 = Index3;
index4 = Index4;
}
T GetIndex (int Index)
{
switch (Index)
{
case 0:
return buffer[index1];
break;
case 1:
return buffer[index2];
break;
case 2:
return buffer[index3];
break;
case 3:
return buffer[index4];
break;
default:
return buffer[index1];
break;
}
}
void SetLength (int Length)
{
if( Length >= maxLength )
Length = maxLength;
if( Length < 0 )
Length = 0;
this->Length = Length;
}
void Clear()
{
std::memset(buffer, 0, sizeof(buffer));
index1 = index2 = index3 = index4 = 0;
}
void SetFeedback(T feedback)
{
Feedback = feedback;
}
int GetLength() const
{
return Length;
}
};
template<typename T, int maxLength>
class StaticDelayLine
{
private:
T buffer[maxLength];
int index;
int Length;
T Feedback;
public:
StaticDelayLine()
{
SetLength ( maxLength - 1 );
Clear();
}
T operator()(T input)
{
T output = buffer[index];
buffer[index++] = input;
if(index >= Length)
index = 0;
return output;
}
void SetLength (int Length)
{
if( Length >= maxLength )
Length = maxLength;
if( Length < 0 )
Length = 0;
this->Length = Length;
}
void Clear()
{
std::memset(buffer, 0, sizeof(buffer));
index = 0;
}
int GetLength() const
{
return Length;
}
};
template<typename T, int maxLength>
class StaticDelayLineFourTap
{
private:
T buffer[maxLength];
int index1, index2, index3, index4;
int Length;
T Feedback;
public:
StaticDelayLineFourTap()
{
SetLength ( maxLength - 1 );
Clear();
}
//get ouput and iterate
T operator()(T input)
{
T output = buffer[index1];
buffer[index1++] = input;
if(index1 >= Length)
index1 = 0;
if(++index2 >= Length)
index2 = 0;
if(++index3 >= Length)
index3 = 0;
if(++index4 >= Length)
index4 = 0;
return output;
}
void SetIndex (int Index1, int Index2, int Index3, int Index4)
{
index1 = Index1;
index2 = Index2;
index3 = Index3;
index4 = Index4;
}
T GetIndex (int Index)
{
switch (Index)
{
case 0:
return buffer[index1];
break;
case 1:
return buffer[index2];
break;
case 2:
return buffer[index3];
break;
case 3:
return buffer[index4];
break;
default:
return buffer[index1];
break;
}
}
void SetLength (int Length)
{
if( Length >= maxLength )
Length = maxLength;
if( Length < 0 )
Length = 0;
this->Length = Length;
}
void Clear()
{
std::memset(buffer, 0, sizeof(buffer));
index1 = index2 = index3 = index4 = 0;
}
int GetLength() const
{
return Length;
}
};
template<typename T, int maxLength>
class StaticDelayLineEightTap
{
private:
T buffer[maxLength];
int index1, index2, index3, index4, index5, index6, index7, index8;
int Length;
T Feedback;
public:
StaticDelayLineEightTap()
{
SetLength ( maxLength - 1 );
Clear();
}
//get ouput and iterate
T operator()(T input)
{
T output = buffer[index1];
buffer[index1++] = input;
if(index1 >= Length)
index1 = 0;
if(++index2 >= Length)
index2 = 0;
if(++index3 >= Length)
index3 = 0;
if(++index4 >= Length)
index4 = 0;
if(++index5 >= Length)
index5 = 0;
if(++index6 >= Length)
index6 = 0;
if(++index7 >= Length)
index7 = 0;
if(++index8 >= Length)
index8 = 0;
return output;
}
void SetIndex (int Index1, int Index2, int Index3, int Index4, int Index5, int Index6, int Index7, int Index8)
{
index1 = Index1;
index2 = Index2;
index3 = Index3;
index4 = Index4;
index5 = Index5;
index6 = Index6;
index7 = Index7;
index8 = Index8;
}
T GetIndex (int Index)
{
switch (Index)
{
case 0:
return buffer[index1];
break;
case 1:
return buffer[index2];
break;
case 2:
return buffer[index3];
break;
case 3:
return buffer[index4];
break;
case 4:
return buffer[index5];
break;
case 5:
return buffer[index6];
break;
case 6:
return buffer[index7];
break;
case 7:
return buffer[index8];
break;
default:
return buffer[index1];
break;
}
}
void SetLength (int Length)
{
if( Length >= maxLength )
Length = maxLength;
if( Length < 0 )
Length = 0;
this->Length = Length;
}
void Clear()
{
std::memset(buffer, 0, sizeof(buffer));
index1 = index2 = index3 = index4 = index5 = index6 = index7 = index8 = 0;
}
int GetLength() const
{
return Length;
}
};
template<typename T, int OverSampleCount>
class StateVariable
{
public:
enum FilterType
{
LOWPASS,
HIGHPASS,
BANDPASS,
NOTCH,
FilterTypeCount
};
private:
T sampleRate;
T frequency;
T q;
T f;
T low;
T high;
T band;
T notch;
T *out;
public:
StateVariable()
{
SetSampleRate(44100.);
Frequency(1000.);
Resonance(0);
Type(LOWPASS);
Reset();
}
T operator()(T input)
{
for(unsigned int i = 0; i < OverSampleCount; i++)
{
low += f * band + 1e-25;
high = input - low - q * band;
band += f * high;
notch = low + high;
}
return *out;
}
void Reset()
{
low = high = band = notch = 0;
}
void SetSampleRate(T sampleRate)
{
this->sampleRate = sampleRate * OverSampleCount;
UpdateCoefficient();
}
void Frequency(T frequency)
{
this->frequency = frequency;
UpdateCoefficient();
}
void Resonance(T resonance)
{
this->q = 2 - 2 * resonance;
}
void Type(int type)
{
switch(type)
{
case LOWPASS:
out = &low;
break;
case HIGHPASS:
out = &high;
break;
case BANDPASS:
out = &band;
break;
case NOTCH:
out = &notch;
break;
default:
out = &low;
break;
}
}
private:
void UpdateCoefficient()
{
f = 2. * std::sin(PI * frequency / sampleRate);
}
};
#endif

@ -237,6 +237,21 @@ CUIMenu::TMenuItem CUIMenu::s_FXReverb[] =
{0}
};
CUIMenu::TMenuItem CUIMenu::s_FXMVerb[] =
{
{"Bypass", EditTGFXParameter, 0, AudioEffectMVerb::Param::BYPASS},
{"Damp Fq", EditTGFXParameter, 0, AudioEffectMVerb::Param::DAMPINGFREQ},
{"Density", EditTGFXParameter, 0, AudioEffectMVerb::Param::DENSITY},
{"Band Fq", EditTGFXParameter, 0, AudioEffectMVerb::Param::BANDWIDTHFREQ},
{"Decay", EditTGFXParameter, 0, AudioEffectMVerb::Param::DECAY},
{"Predelay", EditTGFXParameter, 0, AudioEffectMVerb::Param::PREDELAY},
{"Size", EditTGFXParameter, 0, AudioEffectMVerb::Param::SIZE},
{"Gain", EditTGFXParameter, 0, AudioEffectMVerb::Param::GAIN},
{"Mix", EditTGFXParameter, 0, AudioEffectMVerb::Param::MIX},
{"Early Mix", EditTGFXParameter, 0, AudioEffectMVerb::Param::EARLYMIX},
{0}
};
const CUIMenu::TMenuItem CUIMenu::s_MidiFX[] =
{
{"Type:", EditTGParameter2, 0, CMiniDexed::TGParameterMidiFXType},
@ -336,7 +351,7 @@ const CUIMenu::TMenuItem CUIMenu::s_SaveMenu[] =
const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] =
{
{0, 1, 1, ToOnOff}, // ParameterCompressorEnable
{0, 7, 1, ToFXType}, // ParameterSendFXType
{0, 8, 1, ToFXType}, // ParameterSendFXType
{0, 100, 1}, // ParameterSendFXLevel
{0, 1, 1, ToOnOff}, // ParameterReverbEnable
{0, 99, 1}, // ParameterReverbSize
@ -359,7 +374,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, 7, 1, ToFXType}, // TGParameterInsertFXType
{0, 8, 1, ToFXType}, // TGParameterInsertFXType
{0, 1, 1, ToMidiFXType}, // TGParameterMidiFXType
{-99, 99, 1}, // TGParameterMasterTune
{0, 99, 1}, // TGParameterCutoff
@ -466,6 +481,21 @@ const CUIMenu::TParameter CUIMenu::s_TGFXReverbParam[AudioEffectPlateReverb::Par
{0, 99, 1}, // LEVEL
};
// must match AudioEffectPlateReverb::Param
const CUIMenu::TParameter CUIMenu::s_TGFXMVerbParam[AudioEffectMVerb::Param::UNKNOWN] =
{
{0, 1, 1, ToOnOff}, // BYPASS
{0, 100, 1}, // DAMPINGFREQ
{0, 100, 1}, // DENSITY
{0, 100, 1}, // BANDWIDTHFREQ
{0, 100, 1}, // DECAY
{0, 100, 1}, // PREDELAY
{0, 100, 1}, // SIZE
{0, 100, 1}, // GAIN
{0, 100, 1, ToMix}, // MIX
{0, 100, 1}, // EARLYMIX
};
// must match MidiArp::Param
const CUIMenu::TParameter CUIMenu::s_TGMidiFXArpParam[MidiArp::Param::UNKNOWN] =
{
@ -2905,6 +2935,9 @@ CUIMenu::TMenuItem* CUIMenu::getFXMenuItem(unsigned type)
case EFFECT_REVERB:
menu = s_FXReverb;
break;
case EFFECT_MVERB:
menu = s_FXMVerb;
break;
case EFFECT_NONE:
default:
menu = s_FXNone;
@ -2963,6 +2996,9 @@ CUIMenu::TParameter CUIMenu::getFXParameter(unsigned type, unsigned nParam)
case EFFECT_REVERB:
pParam = s_TGFXReverbParam[nParam];
break;
case EFFECT_MVERB:
pParam = s_TGFXMVerbParam[nParam];
break;
default:
break;
}

@ -182,6 +182,7 @@ private:
static TMenuItem s_FXBigMuff[];
static TMenuItem s_FXTalReverb3[];
static TMenuItem s_FXReverb[];
static TMenuItem s_FXMVerb[];
static TMenuItem s_MidiFXNone[];
static TMenuItem s_MidiFXArp[];
@ -205,6 +206,7 @@ private:
static const TParameter s_TGFXBigMuffParam[];
static const TParameter s_TGFXTalReverb3Param[];
static const TParameter s_TGFXReverbParam[];
static const TParameter s_TGFXMVerbParam[];
static const TParameter s_TGMidiFXArpParam[];
static const TParameter s_VoiceParameter[];
static const TParameter s_OPParameter[];

Loading…
Cancel
Save