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