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