Chris@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2
|
Chris@13
|
3 #define _USE_MATH_DEFINES
|
Chris@13
|
4 #include <cmath>
|
Chris@13
|
5
|
Chris@9
|
6 #include "devuvuzelator-vst.h"
|
Chris@9
|
7
|
Chris@0
|
8 #include <iostream>
|
Chris@2
|
9 #include <cstdio>
|
Chris@0
|
10
|
Chris@9
|
11 #include "params.h"
|
Chris@2
|
12
|
Chris@2
|
13 #define snprintf _snprintf
|
Chris@2
|
14 #define alloca _alloca
|
Chris@0
|
15
|
Chris@1
|
16 // VST params 0->1
|
Chris@1
|
17
|
Chris@0
|
18 void
|
Chris@0
|
19 Devuvuzelator::setParameter(VstInt32 index, float value)
|
Chris@0
|
20 {
|
Chris@1
|
21 switch (index) {
|
Chris@4
|
22 case 0: m_fundamental = 50 + 720 * value; break;
|
Chris@4
|
23 case 1: m_bandwidth = 20 + 80 * value; break;
|
Chris@4
|
24 case 2: m_harmonics = int(value * 6 + 0.5); break;
|
Chris@4
|
25 case 3: m_reduction = 100 * value; break;
|
Chris@1
|
26 }
|
Chris@0
|
27 }
|
Chris@0
|
28
|
Chris@0
|
29 float
|
Chris@0
|
30 Devuvuzelator::getParameter(VstInt32 index)
|
Chris@0
|
31 {
|
Chris@1
|
32 switch (index) {
|
Chris@4
|
33 case 0: return (m_fundamental - 50) / 720;
|
Chris@4
|
34 case 1: return (m_bandwidth - 20) / 80;
|
Chris@4
|
35 case 2: return (m_harmonics / 6.f);
|
Chris@4
|
36 case 3: return m_reduction / 100;
|
Chris@1
|
37 }
|
Chris@4
|
38 return 0;
|
Chris@0
|
39 }
|
Chris@0
|
40
|
Chris@0
|
41 // NB! The max name length for VST parameter names, labels
|
Chris@0
|
42 // (i.e. units) and display values (i.e. string renderings of current
|
Chris@0
|
43 // value) is a rather amazing 8 bytes
|
Chris@0
|
44
|
Chris@0
|
45 void
|
Chris@0
|
46 Devuvuzelator::getParameterLabel(VstInt32 index, char *label)
|
Chris@0
|
47 {
|
Chris@0
|
48 const char *units[NumParams] = {
|
Chris@0
|
49 "Hz",
|
Chris@0
|
50 "Hz",
|
Chris@0
|
51 "",
|
Chris@4
|
52 "%",
|
Chris@0
|
53 };
|
Chris@0
|
54
|
Chris@0
|
55 vst_strncpy(label, units[index], kVstMaxParamStrLen);
|
Chris@0
|
56 }
|
Chris@0
|
57
|
Chris@0
|
58 void
|
Chris@0
|
59 Devuvuzelator::getParameterDisplay(VstInt32 index, char *label)
|
Chris@0
|
60 {
|
Chris@4
|
61 switch (index) {
|
Chris@4
|
62 case 0: snprintf(label, kVstMaxParamStrLen, "%f", m_fundamental); break;
|
Chris@4
|
63 case 1: snprintf(label, kVstMaxParamStrLen, "%f", m_bandwidth); break;
|
Chris@4
|
64 case 2: snprintf(label, kVstMaxParamStrLen, "%d", m_harmonics); break;
|
Chris@4
|
65 case 3: snprintf(label, kVstMaxParamStrLen, "%f", m_reduction); break;
|
Chris@4
|
66 }
|
Chris@0
|
67 }
|
Chris@0
|
68
|
Chris@0
|
69 void
|
Chris@0
|
70 Devuvuzelator::getParameterName(VstInt32 index, char *label)
|
Chris@0
|
71 {
|
Chris@0
|
72 const char *names[NumParams] = {
|
Chris@0
|
73 "Pitch",
|
Chris@0
|
74 "B/W",
|
Chris@0
|
75 "Partials",
|
Chris@0
|
76 "Reductn",
|
Chris@0
|
77 };
|
Chris@0
|
78
|
Chris@0
|
79 vst_strncpy(label, names[index], kVstMaxParamStrLen);
|
Chris@0
|
80 }
|
Chris@0
|
81
|
Chris@0
|
82 Devuvuzelator::Devuvuzelator(audioMasterCallback cb) :
|
Chris@0
|
83 AudioEffect(cb, 0, NumParams),
|
Chris@0
|
84 m_sampleRate(0),
|
Chris@0
|
85 m_input(0),
|
Chris@0
|
86 m_output(0),
|
Chris@0
|
87 m_fftsize(FFTSIZE),
|
Chris@7
|
88 m_winsize(WINSIZE),
|
Chris@5
|
89 m_increment(m_winsize/2),
|
Chris@9
|
90 m_filtersecs(FILTERSECS),
|
Chris@0
|
91 m_fill(0),
|
Chris@0
|
92 m_read(0)
|
Chris@0
|
93 {
|
Chris@4
|
94 m_buffer = new float[m_winsize];
|
Chris@4
|
95 m_outacc = new float[m_winsize * 2];
|
Chris@4
|
96 m_window = new double[m_winsize];
|
Chris@9
|
97 m_frame = new double[m_fftsize];
|
Chris@9
|
98 m_spare = new double[m_fftsize];
|
Chris@0
|
99 m_real = new double[m_fftsize];
|
Chris@0
|
100 m_imag = new double[m_fftsize];
|
Chris@4
|
101 m_medians = new MedianFilter<double> *[m_fftsize/2+1];
|
Chris@0
|
102
|
Chris@4
|
103 for (int i = 0; i < m_winsize; ++i) {
|
Chris@4
|
104 m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_winsize);
|
Chris@4
|
105 }
|
Chris@4
|
106 for (int i = 0; i < m_fftsize/2+1; ++i) {
|
Chris@4
|
107 m_medians[i] = 0;
|
Chris@0
|
108 }
|
Chris@0
|
109
|
Chris@4
|
110 m_fundamental = 230;
|
Chris@0
|
111 m_bandwidth = 60;
|
Chris@0
|
112 m_harmonics = 3;
|
Chris@4
|
113 m_reduction = 30;
|
Chris@0
|
114
|
Chris@2
|
115 setUniqueID('qmvz');
|
Chris@0
|
116 setNumInputs(1);
|
Chris@0
|
117 setNumOutputs(1);
|
Chris@0
|
118 canProcessReplacing(true);
|
Chris@0
|
119 canDoubleReplacing(false);
|
Chris@0
|
120
|
Chris@0
|
121 reset();
|
Chris@0
|
122 }
|
Chris@0
|
123
|
Chris@0
|
124 Devuvuzelator::~Devuvuzelator()
|
Chris@0
|
125 {
|
Chris@0
|
126 delete[] m_buffer;
|
Chris@0
|
127 delete[] m_outacc;
|
Chris@9
|
128 delete[] m_frame;
|
Chris@9
|
129 delete[] m_spare;
|
Chris@0
|
130 delete[] m_real;
|
Chris@0
|
131 delete[] m_imag;
|
Chris@0
|
132 delete[] m_window;
|
Chris@4
|
133 for (int i = 0; i < m_fftsize/2+1; ++i) {
|
Chris@4
|
134 delete m_medians[i];
|
Chris@4
|
135 }
|
Chris@4
|
136 delete[] m_medians;
|
Chris@0
|
137 }
|
Chris@0
|
138
|
Chris@0
|
139 void
|
Chris@0
|
140 Devuvuzelator::reset()
|
Chris@0
|
141 {
|
Chris@4
|
142 for (int i = 0; i < m_winsize; ++i) {
|
Chris@0
|
143 m_buffer[i] = 0.f;
|
Chris@0
|
144 }
|
Chris@4
|
145 for (int i = 0; i < m_winsize*2; ++i) {
|
Chris@0
|
146 m_outacc[i] = 0.f;
|
Chris@0
|
147 }
|
Chris@0
|
148 m_fill = 0;
|
Chris@0
|
149 m_read = 0;
|
Chris@4
|
150 for (int i = 0; i < m_fftsize/2+1; ++i) {
|
Chris@4
|
151 if (m_medians[i]) m_medians[i]->reset();
|
Chris@4
|
152 }
|
Chris@0
|
153 }
|
Chris@0
|
154
|
Chris@0
|
155 void
|
Chris@0
|
156 Devuvuzelator::runImpl(unsigned long sampleCount)
|
Chris@0
|
157 {
|
Chris@0
|
158 if (!m_input || !m_output) return;
|
Chris@0
|
159
|
Chris@4
|
160 const int sc = sampleCount;
|
Chris@0
|
161
|
Chris@9
|
162 float *output = m_output;
|
Chris@9
|
163 if (m_input == m_output) {
|
Chris@9
|
164 output = (float *)alloca(sampleCount * sizeof(float));
|
Chris@9
|
165 }
|
Chris@0
|
166
|
Chris@9
|
167 int oi = 0;
|
Chris@9
|
168 for (int ii = 0; ii < sc; ++ii) {
|
Chris@0
|
169
|
Chris@9
|
170 output[oi++] = m_outacc[m_read++];
|
Chris@4
|
171 if (m_fill == m_winsize) {
|
Chris@0
|
172
|
Chris@0
|
173 processFrame();
|
Chris@0
|
174
|
Chris@4
|
175 for (int j = m_increment; j < m_winsize; ++j) {
|
Chris@0
|
176 m_buffer[j - m_increment] = m_buffer[j];
|
Chris@0
|
177 }
|
Chris@0
|
178
|
Chris@4
|
179 for (int j = m_increment; j < m_winsize*2; ++j) {
|
Chris@0
|
180 m_outacc[j - m_increment] = m_outacc[j];
|
Chris@0
|
181 }
|
Chris@0
|
182
|
Chris@4
|
183 for (int j = m_winsize*2 - m_increment; j < m_winsize*2; ++j) {
|
Chris@0
|
184 m_outacc[j] = 0.f;
|
Chris@0
|
185 }
|
Chris@0
|
186
|
Chris@8
|
187 m_fill = m_fill - m_increment;
|
Chris@8
|
188 m_read = m_read - m_increment;
|
Chris@0
|
189 }
|
Chris@9
|
190 m_buffer[m_fill] = m_input[ii];
|
Chris@9
|
191 ++m_fill;
|
Chris@8
|
192 }
|
Chris@0
|
193
|
Chris@9
|
194 if (m_input == m_output) {
|
Chris@9
|
195 for (int i = 0; i < sc; ++i) m_output[i] = output[i];
|
Chris@9
|
196 }
|
Chris@0
|
197 }
|
Chris@0
|
198
|
Chris@0
|
199 void
|
Chris@0
|
200 Devuvuzelator::processFrame()
|
Chris@0
|
201 {
|
Chris@0
|
202 for (int i = 0; i < m_fftsize; ++i) {
|
Chris@8
|
203 m_frame[i] = 0.0;
|
Chris@4
|
204 }
|
Chris@4
|
205
|
Chris@4
|
206 int ix = m_fftsize - m_winsize/2;
|
Chris@4
|
207 while (ix < 0) ix += m_fftsize;
|
Chris@4
|
208 for (int i = 0; i < m_winsize; ++i) {
|
Chris@8
|
209 m_frame[ix++] += m_buffer[i] * m_window[i];
|
Chris@0
|
210 if (ix == m_fftsize) ix = 0;
|
Chris@0
|
211 }
|
Chris@0
|
212
|
Chris@8
|
213 fft(m_fftsize, false, m_frame, 0, m_real, m_imag);
|
Chris@0
|
214
|
Chris@9
|
215 processSpectralFrame();
|
Chris@0
|
216
|
Chris@0
|
217 for (int i = 0; i < m_fftsize/2-1; ++i) {
|
Chris@3
|
218 m_real[m_fftsize-i-1] = m_real[i+1];
|
Chris@3
|
219 m_imag[m_fftsize-i-1] = -m_imag[i+1];
|
Chris@0
|
220 }
|
Chris@0
|
221
|
Chris@8
|
222 fft(m_fftsize, true, m_real, m_imag, m_frame, m_spare);
|
Chris@0
|
223
|
Chris@4
|
224 ix = m_fftsize - m_winsize/2;
|
Chris@4
|
225 while (ix < 0) ix += m_fftsize;
|
Chris@4
|
226 for (int i = 0; i < m_winsize; ++i) {
|
Chris@8
|
227 m_outacc[m_winsize + i] += m_frame[ix++];
|
Chris@0
|
228 if (ix == m_fftsize) ix = 0;
|
Chris@0
|
229 }
|
Chris@0
|
230 }
|
Chris@0
|
231
|
Chris@0
|
232 AudioEffect *createEffectInstance(audioMasterCallback audioMaster)
|
Chris@0
|
233 {
|
Chris@0
|
234 return new Devuvuzelator(audioMaster);
|
Chris@0
|
235 }
|
Chris@0
|
236
|
Chris@1
|
237
|