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