1 /** 2 * Copyright 2017 Cut Through Recordings 3 * License: MIT License 4 * Author(s): Ethan Reker 5 */ 6 module ddsp.filter.shelf; 7 8 import ddsp.filter.biquad; 9 import ddsp.effect.effect; 10 11 import std.math; 12 13 /// The equations for calculating the BiQuad Coefficients are based off of those from vinniefalco/DSPFilters 14 class LowShelf : AudioEffect 15 { 16 public: 17 18 void setGain(float gain) nothrow @nogc 19 { 20 if(_gain != gain) 21 { 22 _gain = gain; 23 calcCoefficients(); 24 } 25 } 26 27 override float getNextSample(const float input) nothrow @nogc 28 { 29 _w = input - _a1 * _w1 - _a2 * _w2; 30 _yn = _b0 * _w + _b1 *_w1 + _b2 * _w2; 31 32 _w2 = _w1; 33 _w1 = _w; 34 35 return _yn; 36 } 37 38 override void reset() nothrow @nogc 39 { 40 _w = 0; 41 _w1 = 0; 42 _w2 = 0; 43 44 _yn = 0; 45 } 46 47 void setFrequency(float frequency) nothrow @nogc 48 { 49 if(_frequency != frequency) 50 { 51 _frequency = frequency; 52 calcCoefficients(); 53 } 54 } 55 56 override string toString() 57 { 58 import std.conv; 59 return "a0: " ~ to!string(_a0) ~ 60 "a1: " ~ to!string(_a1) ~ 61 "a2: " ~ to!string(_a2) ~ 62 "b0: " ~ to!string(_b0) ~ 63 "b1: " ~ to!string(_b1) ~ 64 "b2: " ~ to!string(_b2); 65 } 66 67 private: 68 float _a0 = 0; 69 float _a1 = 0; 70 float _a2 = 0; 71 float _b0 = 0; 72 float _b1 = 0; 73 float _b2 = 0; 74 75 float _w = 0; 76 float _w1 = 0; 77 float _w2 = 0; 78 79 float _yn; 80 81 float _frequency; 82 float _gain; 83 84 void calcCoefficients() nothrow @nogc 85 { 86 float shelfSlope = 2.0f; 87 float A = pow (10, _gain/40); 88 float w0 = 2 * pi * _frequency / _sampleRate; 89 float cs = cos (w0); 90 float sn = sin (w0); 91 float AL = sn / 2 * sqrt ((A + 1/A) * (1 / shelfSlope - 1) + 2); 92 float sq = 2 * sqrt(A) * AL; 93 _b0 = A*( (A+1) - (A-1)*cs + sq ); 94 _b1 = 2*A*( (A-1) - (A+1)*cs ); 95 _b2 = A*( (A+1) - (A-1)*cs - sq ); 96 _a0 = (A+1) + (A-1)*cs + sq; 97 _a1 = -2*( (A-1) + (A+1)*cs ); 98 _a2 = (A+1) + (A-1)*cs - sq; 99 100 _b0 /= _a0; 101 _b1 /= _a0; 102 _b2 /= _a0; 103 _a1 /= _a0; 104 _a2 /= _a0; 105 } 106 } 107 108 unittest 109 { 110 import dplug.core.nogc; 111 import dplug.core.alignedbuffer; 112 import ddsp.effect.effect; 113 114 Vec!LowShelf filters = makeVec!LowShelf; 115 foreach(channel; 0..2) 116 { 117 filters.pushBack(mallocNew!LowShelf); 118 filters[channel].setSampleRate(44100.0f); 119 filters[channel].setFrequency(150.0f); 120 filters[channel].setGain(3.0f); 121 } 122 123 //testEffect(AudioEffect effect, string name, size_t bufferSize = 20000, bool outputResults = false) 124 foreach(filter; filters) 125 testEffect(filter, "LowShelf" , 20000, false); 126 }