Mercurial > hg > devuvuzelator
comparison devuvuzelator-vst.cpp @ 4:d90abfa9585a
* Adaptive method
author | Chris Cannam |
---|---|
date | Fri, 11 Jun 2010 15:38:44 +0100 |
parents | 8b79175c9f02 |
children | 45bcfa3d5da7 |
comparison
equal
deleted
inserted
replaced
3:8b79175c9f02 | 4:d90abfa9585a |
---|---|
10 #include "public.sdk/source/vst2.x/audioeffect.h" | 10 #include "public.sdk/source/vst2.x/audioeffect.h" |
11 | 11 |
12 #define snprintf _snprintf | 12 #define snprintf _snprintf |
13 #define alloca _alloca | 13 #define alloca _alloca |
14 | 14 |
15 #define FFTSIZE 1024 | 15 #define FFTSIZE 4096 |
16 #define WINSIZE 1024 | |
17 | |
18 #include "median.h" | |
16 | 19 |
17 class Devuvuzelator : public AudioEffect | 20 class Devuvuzelator : public AudioEffect |
18 { | 21 { |
19 enum { | 22 enum { |
20 LowParam = 0, | 23 FundamentalParam = 1, |
21 HighParam = 1, | 24 BandwidthParam = 2, |
22 FundamentalParam = 2, | 25 HarmonicsParam = 3, |
23 BandwidthParam = 3, | 26 ReductionParam = 4, |
24 HarmonicsParam = 4, | 27 NumParams = 5 |
25 ReductionParam = 5, | |
26 NumParams = 6 | |
27 }; | 28 }; |
28 | 29 |
29 public: | 30 public: |
30 Devuvuzelator(audioMasterCallback cb); | 31 Devuvuzelator(audioMasterCallback cb); |
31 ~Devuvuzelator(); | 32 ~Devuvuzelator(); |
76 float m_bandwidth; | 77 float m_bandwidth; |
77 int m_harmonics; | 78 int m_harmonics; |
78 float m_reduction; | 79 float m_reduction; |
79 | 80 |
80 const int m_fftsize; | 81 const int m_fftsize; |
82 const int m_winsize; | |
81 const int m_increment; | 83 const int m_increment; |
82 int m_fill; | 84 int m_fill; |
83 int m_read; | 85 int m_read; |
84 float *m_buffer; | 86 float *m_buffer; |
85 float *m_outacc; | 87 float *m_outacc; |
86 double *m_real; | 88 double *m_real; |
87 double *m_imag; | 89 double *m_imag; |
88 double *m_window; | 90 double *m_window; |
91 MedianFilter<double> **m_medians; | |
89 }; | 92 }; |
90 | 93 |
91 // VST params 0->1 | 94 // VST params 0->1 |
92 | 95 |
93 void | 96 void |
94 Devuvuzelator::setParameter(VstInt32 index, float value) | 97 Devuvuzelator::setParameter(VstInt32 index, float value) |
95 { | 98 { |
96 switch (index) { | 99 switch (index) { |
97 case 0: m_low = -80 + 80 * value; break; | 100 case 0: m_fundamental = 50 + 720 * value; break; |
98 case 1: m_high = -80 + 80 * value; break; | 101 case 1: m_bandwidth = 20 + 80 * value; break; |
99 case 2: m_fundamental = 110 + 440 * value; break; | 102 case 2: m_harmonics = int(value * 6 + 0.5); break; |
100 case 3: m_bandwidth = 20 + 80 * value; break; | 103 case 3: m_reduction = 100 * value; break; |
101 case 4: m_harmonics = int(value * 6 + 0.5); break; | |
102 case 5: m_reduction = 20 * value; break; | |
103 } | 104 } |
104 } | 105 } |
105 | 106 |
106 float | 107 float |
107 Devuvuzelator::getParameter(VstInt32 index) | 108 Devuvuzelator::getParameter(VstInt32 index) |
108 { | 109 { |
109 switch (index) { | 110 switch (index) { |
110 case 0: return (m_low + 80) / 80; | 111 case 0: return (m_fundamental - 50) / 720; |
111 case 1: return (m_high + 80) / 80; | 112 case 1: return (m_bandwidth - 20) / 80; |
112 case 2: return (m_fundamental - 110) / 440; | 113 case 2: return (m_harmonics / 6.f); |
113 case 3: return (m_bandwidth - 20) / 80; | 114 case 3: return m_reduction / 100; |
114 case 4: return (m_harmonics / 6.f); | 115 } |
115 case 5: return m_reduction / 20; | 116 return 0; |
116 } | |
117 return 0; | |
118 } | 117 } |
119 | 118 |
120 // NB! The max name length for VST parameter names, labels | 119 // NB! The max name length for VST parameter names, labels |
121 // (i.e. units) and display values (i.e. string renderings of current | 120 // (i.e. units) and display values (i.e. string renderings of current |
122 // value) is a rather amazing 8 bytes | 121 // value) is a rather amazing 8 bytes |
123 | 122 |
124 void | 123 void |
125 Devuvuzelator::getParameterLabel(VstInt32 index, char *label) | 124 Devuvuzelator::getParameterLabel(VstInt32 index, char *label) |
126 { | 125 { |
127 const char *units[NumParams] = { | 126 const char *units[NumParams] = { |
128 "dB", | |
129 "dB", | |
130 "Hz", | 127 "Hz", |
131 "Hz", | 128 "Hz", |
132 "", | 129 "", |
133 "dB", | 130 "%", |
134 }; | 131 }; |
135 | 132 |
136 vst_strncpy(label, units[index], kVstMaxParamStrLen); | 133 vst_strncpy(label, units[index], kVstMaxParamStrLen); |
137 } | 134 } |
138 | 135 |
139 void | 136 void |
140 Devuvuzelator::getParameterDisplay(VstInt32 index, char *label) | 137 Devuvuzelator::getParameterDisplay(VstInt32 index, char *label) |
141 { | 138 { |
142 switch (index) { | 139 switch (index) { |
143 case 0: snprintf(label, kVstMaxParamStrLen, "%f", m_low); break; | 140 case 0: snprintf(label, kVstMaxParamStrLen, "%f", m_fundamental); break; |
144 case 1: snprintf(label, kVstMaxParamStrLen, "%f", m_high); break; | 141 case 1: snprintf(label, kVstMaxParamStrLen, "%f", m_bandwidth); break; |
145 case 2: snprintf(label, kVstMaxParamStrLen, "%f", m_fundamental); break; | 142 case 2: snprintf(label, kVstMaxParamStrLen, "%d", m_harmonics); break; |
146 case 3: snprintf(label, kVstMaxParamStrLen, "%f", m_bandwidth); break; | 143 case 3: snprintf(label, kVstMaxParamStrLen, "%f", m_reduction); break; |
147 case 4: snprintf(label, kVstMaxParamStrLen, "%d", m_harmonics); break; | 144 } |
148 case 5: snprintf(label, kVstMaxParamStrLen, "%f", m_reduction); break; | |
149 } | |
150 } | 145 } |
151 | 146 |
152 void | 147 void |
153 Devuvuzelator::getParameterName(VstInt32 index, char *label) | 148 Devuvuzelator::getParameterName(VstInt32 index, char *label) |
154 { | 149 { |
155 const char *names[NumParams] = { | 150 const char *names[NumParams] = { |
156 "Floor", | |
157 "Ceiling", | |
158 "Pitch", | 151 "Pitch", |
159 "B/W", | 152 "B/W", |
160 "Partials", | 153 "Partials", |
161 "Reductn", | 154 "Reductn", |
162 }; | 155 }; |
167 Devuvuzelator::Devuvuzelator(audioMasterCallback cb) : | 160 Devuvuzelator::Devuvuzelator(audioMasterCallback cb) : |
168 AudioEffect(cb, 0, NumParams), | 161 AudioEffect(cb, 0, NumParams), |
169 m_sampleRate(0), | 162 m_sampleRate(0), |
170 m_input(0), | 163 m_input(0), |
171 m_output(0), | 164 m_output(0), |
172 m_low(0), | |
173 m_high(0), | |
174 m_fftsize(FFTSIZE), | 165 m_fftsize(FFTSIZE), |
175 m_increment(m_fftsize/4), | 166 m_increment(m_fftsize/4), |
176 m_fill(0), | 167 m_fill(0), |
177 m_read(0) | 168 m_read(0) |
178 { | 169 { |
179 m_buffer = new float[m_fftsize]; | 170 m_buffer = new float[m_winsize]; |
180 m_outacc = new float[m_fftsize * 2]; | 171 m_outacc = new float[m_winsize * 2]; |
172 m_window = new double[m_winsize]; | |
181 m_real = new double[m_fftsize]; | 173 m_real = new double[m_fftsize]; |
182 m_imag = new double[m_fftsize]; | 174 m_imag = new double[m_fftsize]; |
183 m_window = new double[m_fftsize]; | 175 m_medians = new MedianFilter<double> *[m_fftsize/2+1]; |
184 | 176 |
185 for (int i = 0; i < m_fftsize; ++i) { | 177 for (int i = 0; i < m_winsize; ++i) { |
186 m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_fftsize); | 178 m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_winsize); |
187 } | 179 } |
188 | 180 for (int i = 0; i < m_fftsize/2+1; ++i) { |
189 m_low = -40; | 181 m_medians[i] = 0; |
190 m_high = -20; | 182 } |
191 m_fundamental = 220; | 183 |
184 m_fundamental = 230; | |
192 m_bandwidth = 60; | 185 m_bandwidth = 60; |
193 m_harmonics = 3; | 186 m_harmonics = 3; |
194 m_reduction = 10; | 187 m_reduction = 30; |
195 | 188 |
196 setUniqueID('qmvz'); | 189 setUniqueID('qmvz'); |
197 setNumInputs(1); | 190 setNumInputs(1); |
198 setNumOutputs(1); | 191 setNumOutputs(1); |
199 canProcessReplacing(true); | 192 canProcessReplacing(true); |
207 delete[] m_buffer; | 200 delete[] m_buffer; |
208 delete[] m_outacc; | 201 delete[] m_outacc; |
209 delete[] m_real; | 202 delete[] m_real; |
210 delete[] m_imag; | 203 delete[] m_imag; |
211 delete[] m_window; | 204 delete[] m_window; |
205 for (int i = 0; i < m_fftsize/2+1; ++i) { | |
206 delete m_medians[i]; | |
207 } | |
208 delete[] m_medians; | |
212 } | 209 } |
213 | 210 |
214 void | 211 void |
215 Devuvuzelator::reset() | 212 Devuvuzelator::reset() |
216 { | 213 { |
217 for (int i = 0; i < m_fftsize; ++i) { | 214 for (int i = 0; i < m_winsize; ++i) { |
218 m_buffer[i] = 0.f; | 215 m_buffer[i] = 0.f; |
219 } | 216 } |
220 for (int i = 0; i < m_fftsize*2; ++i) { | 217 for (int i = 0; i < m_winsize*2; ++i) { |
221 m_outacc[i] = 0.f; | 218 m_outacc[i] = 0.f; |
222 } | 219 } |
223 m_fill = 0; | 220 m_fill = 0; |
224 m_read = 0; | 221 m_read = 0; |
222 for (int i = 0; i < m_fftsize/2+1; ++i) { | |
223 if (m_medians[i]) m_medians[i]->reset(); | |
224 } | |
225 } | 225 } |
226 | 226 |
227 void | 227 void |
228 Devuvuzelator::runImpl(unsigned long sampleCount) | 228 Devuvuzelator::runImpl(unsigned long sampleCount) |
229 { | 229 { |
230 if (!m_input || !m_output) return; | 230 if (!m_input || !m_output) return; |
231 | 231 |
232 int ii = 0; | 232 int ii = 0; |
233 int oi = 0; | 233 int oi = 0; |
234 const int sc = sampleCount; | 234 const int sc = sampleCount; |
235 | 235 |
236 while (ii < sc) { | 236 while (ii < sc) { |
237 | 237 |
238 m_output[oi++] = m_outacc[m_read++] / 1.5f; | 238 m_output[oi++] = m_outacc[m_read++]; |
239 | 239 |
240 if (m_fill == m_fftsize) { | 240 if (m_fill == m_winsize) { |
241 | 241 |
242 processFrame(); | 242 processFrame(); |
243 | 243 |
244 for (int j = m_increment; j < m_fftsize; ++j) { | 244 for (int j = m_increment; j < m_winsize; ++j) { |
245 m_buffer[j - m_increment] = m_buffer[j]; | 245 m_buffer[j - m_increment] = m_buffer[j]; |
246 } | 246 } |
247 | 247 |
248 for (int j = m_increment; j < m_fftsize*2; ++j) { | 248 for (int j = m_increment; j < m_winsize*2; ++j) { |
249 m_outacc[j - m_increment] = m_outacc[j]; | 249 m_outacc[j - m_increment] = m_outacc[j]; |
250 } | 250 } |
251 | 251 |
252 for (int j = m_fftsize*2 - m_increment; j < m_fftsize*2; ++j) { | 252 for (int j = m_winsize*2 - m_increment; j < m_winsize*2; ++j) { |
253 m_outacc[j] = 0.f; | 253 m_outacc[j] = 0.f; |
254 } | 254 } |
255 | 255 |
256 m_fill -= m_increment; | 256 m_fill -= m_increment; |
257 m_read -= m_increment; | 257 m_read -= m_increment; |
263 | 263 |
264 void | 264 void |
265 Devuvuzelator::processFrame() | 265 Devuvuzelator::processFrame() |
266 { | 266 { |
267 double *frame = (double *)alloca(m_fftsize * sizeof(double)); | 267 double *frame = (double *)alloca(m_fftsize * sizeof(double)); |
268 int ix = m_fftsize/2; | |
269 for (int i = 0; i < m_fftsize; ++i) { | 268 for (int i = 0; i < m_fftsize; ++i) { |
270 frame[ix++] = m_buffer[i] * m_window[i]; | 269 frame[i] = 0.0; |
270 } | |
271 | |
272 int ix = m_fftsize - m_winsize/2; | |
273 while (ix < 0) ix += m_fftsize; | |
274 for (int i = 0; i < m_winsize; ++i) { | |
275 frame[ix++] += m_buffer[i] * m_window[i]; | |
271 if (ix == m_fftsize) ix = 0; | 276 if (ix == m_fftsize) ix = 0; |
272 } | 277 } |
273 | 278 |
274 fft(m_fftsize, false, frame, 0, m_real, m_imag); | 279 fft(m_fftsize, false, frame, 0, m_real, m_imag); |
275 | 280 |
281 } | 286 } |
282 | 287 |
283 double *spare = (double *)alloca(m_fftsize * sizeof(double)); | 288 double *spare = (double *)alloca(m_fftsize * sizeof(double)); |
284 fft(m_fftsize, true, m_real, m_imag, frame, spare); | 289 fft(m_fftsize, true, m_real, m_imag, frame, spare); |
285 | 290 |
286 ix = m_fftsize/2; | 291 ix = m_fftsize - m_winsize/2; |
287 for (int i = 0; i < m_fftsize; ++i) { | 292 while (ix < 0) ix += m_fftsize; |
288 m_outacc[m_fftsize + i] += frame[ix++] * m_window[i]; | 293 for (int i = 0; i < m_winsize; ++i) { |
294 m_outacc[m_winsize + i] += frame[ix++]; | |
289 if (ix == m_fftsize) ix = 0; | 295 if (ix == m_fftsize) ix = 0; |
290 } | 296 } |
291 } | 297 } |
292 | 298 |
293 // FFT implementation by Don Cross, public domain. | 299 // FFT implementation by Don Cross, public domain. |