1 /**
2 * Copyright 2017 Cut Through Recordings
3 * License: MIT License
4 * Author(s): Ethan Reker
5 */
6 module ddsp.filter.peak;
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 BandShelf : 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     const double doubleLn2  =0.69314718055994530941723212145818;
85 
86     void calcCoefficients() nothrow @nogc
87     {
88         float bandWidth = 0.707f;
89         float A  = pow (10, _gain/40);
90         float w0 = 2 * pi * _frequency / _sampleRate;
91         float cs = cos(w0);
92         float sn = sin(w0);
93         float AL = sn * sinh( doubleLn2/2 * bandWidth * w0/sn );
94         _b0 =  1 + AL * A;
95         _b1 = -2 * cs;
96         _b2 =  1 - AL * A;
97         _a0 =  1 + AL / A;
98         _a1 = -2 * cs;
99         _a2 =  1 - AL / A;
100 
101         _b0 /= _a0;
102         _b1 /= _a0;
103         _b2 /= _a0;
104         _a1 /= _a0;
105         _a2 /= _a0;
106     }
107 }
108 
109 unittest
110 {
111     import dplug.core.nogc;
112     import dplug.core.alignedbuffer;
113     import ddsp.effect.effect;
114 
115     Vec!BandShelf filters = makeVec!BandShelf;
116     foreach(channel; 0..2)
117     {
118         filters.pushBack(mallocNew!BandShelf);
119         filters[channel].setSampleRate(44100.0f);
120         filters[channel].setFrequency(150.0f);
121         filters[channel].setGain(3.0f);
122     }
123 
124     //testEffect(AudioEffect effect, string name, size_t bufferSize = 20000, bool outputResults = false)
125     foreach(filter; filters)
126         testEffect(filter, "BandShelf" , 20000, false);
127 }