1 /**
2  * The MIT License (MIT)
3  *
4  * Copyright (c) 2013-2018 Igor Zinken - https://www.igorski.nl
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy of
7  * this software and associated documentation files (the "Software"), to deal in
8  * the Software without restriction, including without limitation the rights to
9  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10  * the Software, and to permit persons to whom the Software is furnished to do so,
11  * subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include "filter.h"
24 #include "global.h"
25 #include <algorithm>
26 
27 namespace Igorski {
28 
Filter(float sampleRate)29 Filter::Filter( float sampleRate ) {
30     _sampleRate = sampleRate;
31 
32     _cutoff     = VST::FILTER_MIN_FREQ;
33     _resonance  = VST::FILTER_MIN_RESONANCE;
34     _depth      = 1.f;
35     _lfoMin     = VST::FILTER_MIN_FREQ;
36     _lfoMax     = VST::FILTER_MAX_FREQ;
37     _lfoRange   = _cutoff * _depth;
38     _tempCutoff = _cutoff; // used when applying LFO
39 
40     _a1 = 0.f;
41     _a2 = 0.f;
42     _a3 = 0.f;
43     _b1 = 0.f;
44     _b2 = 0.f;
45     _c  = 0.f;
46 
47     lfo = new Igorski::LFO( sampleRate );
48 
49     _hasLFO = false;
50 
51     // stereo (2) probably enough...
52     int numChannels = 8;
53 
54     _in1  = new float[ numChannels ];
55     _in2  = new float[ numChannels ];
56     _out1 = new float[ numChannels ];
57     _out2 = new float[ numChannels ];
58 
59     for ( int i = 0; i < numChannels; ++i )
60     {
61         _in1 [ i ] = 0.f;
62         _in2 [ i ] = 0.f;
63         _out1[ i ] = 0.f;
64         _out2[ i ] = 0.f;
65     }
66     setCutoff( VST::FILTER_MAX_FREQ / 2 );
67 }
68 
~Filter()69 Filter::~Filter() {
70     delete lfo;
71     delete[] _in1;
72     delete[] _in2;
73     delete[] _out1;
74     delete[] _out2;
75 }
76 
77 /* public methods */
78 
updateProperties(float cutoffPercentage,float resonancePercentage,float LFORatePercentage,float LFODepth)79 void Filter::updateProperties( float cutoffPercentage, float resonancePercentage, float LFORatePercentage, float LFODepth )
80 {
81     float co  = VST::FILTER_MIN_FREQ + ( cutoffPercentage * ( VST::FILTER_MAX_FREQ - VST::FILTER_MIN_FREQ ));
82     float res = VST::FILTER_MIN_RESONANCE + ( resonancePercentage * ( VST::FILTER_MAX_RESONANCE - VST::FILTER_MIN_RESONANCE ));
83 
84     if ( _cutoff != co || _resonance != res ) {
85         setCutoff( co );
86         setResonance( res );
87     }
88     _depth = LFODepth;
89 
90     bool doLFO = LFORatePercentage != 0.f;
91 
92     if ( !doLFO && _hasLFO ) {
93         setLFO( false );
94     }
95     else if ( doLFO ) {
96         setLFO( true );
97         cacheLFOProperties();
98         lfo->setRate(
99             VST::MIN_LFO_RATE() + (
100                 LFORatePercentage * ( VST::MAX_LFO_RATE() - VST::MIN_LFO_RATE() )
101             )
102         );
103     }
104 }
105 
process(float * sampleBuffer,int bufferSize,int c)106 void Filter::process( float* sampleBuffer, int bufferSize, int c )
107 {
108     for ( int32 i = 0; i < bufferSize; ++i )
109     {
110         float input  = sampleBuffer[ i ];
111         float output = _a1 * input + _a2 * _in1[ c ] + _a3 * _in2[ c ] - _b1 * _out1[ c ] - _b2 * _out2[ c ];
112 
113         _in2 [ c ] = _in1[ c ];
114         _in1 [ c ] = input;
115         _out2[ c ] = _out1[ c ];
116         _out1[ c ] = output;
117 
118         // oscillator attached to Filter ? travel the cutoff values
119         // between the minimum and maximum frequencies
120 
121         if ( _hasLFO )
122         {
123             // multiply by .5 and add .5 to make bipolar waveform unipolar
124             float lfoValue = lfo->peek() * .5f  + .5f;
125             _tempCutoff = std::min( _lfoMax, _lfoMin + _lfoRange * lfoValue );
126 
127             calculateParameters();
128         }
129 
130         // commit the effect
131         sampleBuffer[ i ] = output;
132     }
133 }
134 
setCutoff(float frequency)135 void Filter::setCutoff( float frequency )
136 {
137     // in case LFO is moving, set the current temp cutoff (last LFO value)
138     // to the relative value for the new cutoff frequency)
139 
140     float tempRatio = _tempCutoff / _cutoff;
141 
142     _cutoff     = std::max( VST::FILTER_MIN_FREQ, std::min( frequency, VST::FILTER_MAX_FREQ ));
143     _tempCutoff = _cutoff * tempRatio;
144 
145     calculateParameters();
146 }
147 
getCutoff()148 float Filter::getCutoff()
149 {
150     return _cutoff;
151 }
152 
setResonance(float resonance)153 void Filter::setResonance( float resonance )
154 {
155     _resonance = std::max( VST::FILTER_MIN_RESONANCE, std::min( resonance, VST::FILTER_MAX_RESONANCE ));
156     calculateParameters();
157 }
158 
getResonance()159 float Filter::getResonance()
160 {
161     return _resonance;
162 }
163 
setLFO(bool enabled)164 void Filter::setLFO( bool enabled )
165 {
166     _hasLFO = enabled;
167 
168     // no LFO ? make sure the filter returns to its default parameters
169 
170     if ( !enabled )
171     {
172         _tempCutoff = _cutoff;
173         cacheLFOProperties();
174         calculateParameters();
175     }
176 }
177 
store()178 void Filter::store()
179 {
180     _accumulatorStored = lfo->getAccumulator();
181     _tempCutoffStored  = _tempCutoff;
182 }
183 
restore()184 void Filter::restore()
185 {
186     lfo->setAccumulator( _accumulatorStored );
187     _tempCutoff = _tempCutoffStored;
188     calculateParameters();
189 }
190 
calculateParameters()191 void Filter::calculateParameters()
192 {
193     _c  = 1.f / tan( VST::PI * _tempCutoff / _sampleRate );
194     _a1 = 1.f / ( 1.f + _resonance * _c + _c * _c );
195     _a2 = 2.f * _a1;
196     _a3 = _a1;
197     _b1 = 2.f * ( 1.f - _c * _c ) * _a1;
198     _b2 = ( 1.f - _resonance * _c + _c * _c ) * _a1;
199 }
200 
cacheLFOProperties()201 void Filter::cacheLFOProperties()
202 {
203     _lfoRange = _cutoff * _depth;
204     _lfoMax   = std::min( VST::FILTER_MAX_FREQ, _cutoff + _lfoRange / 2.f );
205     _lfoMin   = std::max( VST::FILTER_MIN_FREQ, _cutoff - _lfoRange / 2.f );
206 }
207 
208 }
209