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