Chris@1
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@1
|
2
|
Chris@9
|
3 #include "devuvuzelator-ladspa.h"
|
Chris@9
|
4
|
Chris@1
|
5 #include <alloca.h>
|
Chris@1
|
6 #include <iostream>
|
Chris@1
|
7 #include <cmath>
|
Chris@1
|
8
|
Chris@9
|
9 #include "params.h"
|
Chris@1
|
10
|
Chris@1
|
11 const char *const
|
Chris@1
|
12 Devuvuzelator::portNames[PortCount] =
|
Chris@1
|
13 {
|
Chris@1
|
14 "Input",
|
Chris@1
|
15 "Output",
|
Chris@4
|
16 "latency",
|
Chris@1
|
17 "Fundamental frequency (Hz)",
|
Chris@1
|
18 "Bandwidth of fundamental (Hz)",
|
Chris@1
|
19 "Number of partials",
|
Chris@4
|
20 "Reduction (%)",
|
Chris@1
|
21 };
|
Chris@1
|
22
|
Chris@1
|
23 const LADSPA_PortDescriptor
|
Chris@1
|
24 Devuvuzelator::ports[PortCount] =
|
Chris@1
|
25 {
|
Chris@1
|
26 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
|
Chris@1
|
27 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
|
Chris@4
|
28 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
|
Chris@1
|
29 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@1
|
30 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@1
|
31 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@1
|
32 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@1
|
33 };
|
Chris@1
|
34
|
Chris@1
|
35 const LADSPA_PortRangeHint
|
Chris@1
|
36 Devuvuzelator::hints[PortCount] =
|
Chris@1
|
37 {
|
Chris@1
|
38 { 0, 0, 0 },
|
Chris@1
|
39 { 0, 0, 0 },
|
Chris@4
|
40 { 0, 0, 0 },
|
Chris@1
|
41 { LADSPA_HINT_DEFAULT_LOW |
|
Chris@4
|
42 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 50, 770 },
|
Chris@1
|
43 { LADSPA_HINT_DEFAULT_MIDDLE |
|
Chris@1
|
44 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 20, 100 },
|
Chris@1
|
45 { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER |
|
Chris@1
|
46 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 6 },
|
Chris@1
|
47 { LADSPA_HINT_DEFAULT_MIDDLE |
|
Chris@4
|
48 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 100 },
|
Chris@1
|
49 };
|
Chris@1
|
50
|
Chris@1
|
51 const LADSPA_Properties
|
Chris@1
|
52 Devuvuzelator::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
|
Chris@1
|
53
|
Chris@1
|
54 const LADSPA_Descriptor
|
Chris@1
|
55 Devuvuzelator::ladspaDescriptor =
|
Chris@1
|
56 {
|
Chris@16
|
57 0xf0b374, // "Unique" ID
|
Chris@1
|
58 "devuvuzelator", // Label
|
Chris@1
|
59 properties,
|
Chris@1
|
60 "Devuvuzelator", // Name
|
Chris@1
|
61 "Queen Mary, University of London", // Maker
|
Chris@11
|
62 "BSD", // Copyright
|
Chris@1
|
63 PortCount,
|
Chris@1
|
64 ports,
|
Chris@1
|
65 portNames,
|
Chris@1
|
66 hints,
|
Chris@1
|
67 0, // Implementation data
|
Chris@1
|
68 instantiate,
|
Chris@1
|
69 connectPort,
|
Chris@1
|
70 activate,
|
Chris@1
|
71 run,
|
Chris@1
|
72 0, // Run adding
|
Chris@1
|
73 0, // Set run adding gain
|
Chris@1
|
74 deactivate,
|
Chris@1
|
75 cleanup
|
Chris@1
|
76 };
|
Chris@1
|
77
|
Chris@1
|
78 const LADSPA_Descriptor *
|
Chris@1
|
79 Devuvuzelator::getDescriptor(unsigned long index)
|
Chris@1
|
80 {
|
Chris@1
|
81 if (index == 0) return &ladspaDescriptor;
|
Chris@1
|
82 return 0;
|
Chris@1
|
83 }
|
Chris@1
|
84
|
Chris@1
|
85 Devuvuzelator::Devuvuzelator(int sampleRate) :
|
Chris@1
|
86 m_sampleRate(sampleRate),
|
Chris@1
|
87 m_input(0),
|
Chris@1
|
88 m_output(0),
|
Chris@4
|
89 m_platency(0),
|
Chris@4
|
90 m_pfundamental(0),
|
Chris@4
|
91 m_pbandwidth(0),
|
Chris@4
|
92 m_pharmonics(0),
|
Chris@4
|
93 m_preduction(0),
|
Chris@1
|
94 m_fftsize(FFTSIZE),
|
Chris@4
|
95 m_winsize(WINSIZE),
|
Chris@4
|
96 m_increment(m_winsize/2),
|
Chris@9
|
97 m_filtersecs(FILTERSECS),
|
Chris@1
|
98 m_fill(0),
|
Chris@1
|
99 m_read(0)
|
Chris@1
|
100 {
|
Chris@4
|
101 m_buffer = new float[m_winsize];
|
Chris@4
|
102 m_outacc = new float[m_winsize * 2];
|
Chris@4
|
103 m_window = new double[m_winsize];
|
Chris@1
|
104 m_real = new double[m_fftsize];
|
Chris@1
|
105 m_imag = new double[m_fftsize];
|
Chris@4
|
106 m_medians = new MedianFilter<double> *[m_fftsize/2+1];
|
Chris@1
|
107
|
Chris@4
|
108 for (int i = 0; i < m_winsize; ++i) {
|
Chris@4
|
109 m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_winsize);
|
Chris@1
|
110 }
|
Chris@4
|
111 for (int i = 0; i < m_fftsize/2+1; ++i) {
|
Chris@4
|
112 m_medians[i] = 0;
|
Chris@4
|
113 }
|
Chris@4
|
114
|
Chris@4
|
115 m_fundamental = 230;
|
Chris@4
|
116 m_bandwidth = 60;
|
Chris@4
|
117 m_harmonics = 3;
|
Chris@4
|
118 m_reduction = 50;
|
Chris@4
|
119
|
Chris@4
|
120 std::cerr << "note: latency = " << (float(m_winsize) / m_sampleRate)*1000 << " msec" << std::endl;
|
Chris@1
|
121
|
Chris@1
|
122 reset();
|
Chris@1
|
123 }
|
Chris@1
|
124
|
Chris@1
|
125 Devuvuzelator::~Devuvuzelator()
|
Chris@1
|
126 {
|
Chris@1
|
127 delete[] m_buffer;
|
Chris@1
|
128 delete[] m_outacc;
|
Chris@1
|
129 delete[] m_real;
|
Chris@1
|
130 delete[] m_imag;
|
Chris@1
|
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@1
|
136 }
|
Chris@1
|
137
|
Chris@1
|
138 LADSPA_Handle
|
Chris@1
|
139 Devuvuzelator::instantiate(const LADSPA_Descriptor *, unsigned long rate)
|
Chris@1
|
140 {
|
Chris@1
|
141 Devuvuzelator *devuvu = new Devuvuzelator(rate);
|
Chris@1
|
142 return devuvu;
|
Chris@1
|
143 }
|
Chris@1
|
144
|
Chris@1
|
145 void
|
Chris@1
|
146 Devuvuzelator::connectPort(LADSPA_Handle handle,
|
Chris@1
|
147 unsigned long port, LADSPA_Data *location)
|
Chris@1
|
148 {
|
Chris@1
|
149 Devuvuzelator *devuvu = (Devuvuzelator *)handle;
|
Chris@1
|
150
|
Chris@1
|
151 float **ports[PortCount] = {
|
Chris@1
|
152 &devuvu->m_input,
|
Chris@1
|
153 &devuvu->m_output,
|
Chris@4
|
154 &devuvu->m_platency,
|
Chris@4
|
155 &devuvu->m_pfundamental,
|
Chris@4
|
156 &devuvu->m_pbandwidth,
|
Chris@4
|
157 &devuvu->m_pharmonics,
|
Chris@4
|
158 &devuvu->m_preduction,
|
Chris@1
|
159 };
|
Chris@1
|
160
|
Chris@1
|
161 *ports[port] = (float *)location;
|
Chris@1
|
162 }
|
Chris@1
|
163
|
Chris@1
|
164 void
|
Chris@1
|
165 Devuvuzelator::activate(LADSPA_Handle handle)
|
Chris@1
|
166 {
|
Chris@1
|
167 Devuvuzelator *devuvu = (Devuvuzelator *)handle;
|
Chris@1
|
168 devuvu->reset();
|
Chris@1
|
169 }
|
Chris@1
|
170
|
Chris@1
|
171 void
|
Chris@1
|
172 Devuvuzelator::run(LADSPA_Handle handle, unsigned long samples)
|
Chris@1
|
173 {
|
Chris@1
|
174 Devuvuzelator *devuvu = (Devuvuzelator *)handle;
|
Chris@1
|
175 devuvu->runImpl(samples);
|
Chris@1
|
176 }
|
Chris@1
|
177
|
Chris@1
|
178 void
|
Chris@1
|
179 Devuvuzelator::deactivate(LADSPA_Handle handle)
|
Chris@1
|
180 {
|
Chris@1
|
181 activate(handle); // both functions just reset the plugin
|
Chris@1
|
182 }
|
Chris@1
|
183
|
Chris@1
|
184 void
|
Chris@1
|
185 Devuvuzelator::cleanup(LADSPA_Handle handle)
|
Chris@1
|
186 {
|
Chris@1
|
187 delete (Devuvuzelator *)handle;
|
Chris@1
|
188 }
|
Chris@1
|
189
|
Chris@1
|
190 void
|
Chris@1
|
191 Devuvuzelator::reset()
|
Chris@1
|
192 {
|
Chris@4
|
193 for (int i = 0; i < m_winsize; ++i) {
|
Chris@1
|
194 m_buffer[i] = 0.f;
|
Chris@1
|
195 }
|
Chris@4
|
196 for (int i = 0; i < m_winsize*2; ++i) {
|
Chris@1
|
197 m_outacc[i] = 0.f;
|
Chris@1
|
198 }
|
Chris@1
|
199 m_fill = 0;
|
Chris@1
|
200 m_read = 0;
|
Chris@4
|
201 for (int i = 0; i < m_fftsize/2+1; ++i) {
|
Chris@4
|
202 if (m_medians[i]) m_medians[i]->reset();
|
Chris@4
|
203 }
|
Chris@4
|
204 }
|
Chris@4
|
205
|
Chris@4
|
206 void
|
Chris@4
|
207 Devuvuzelator::updateParameters()
|
Chris@4
|
208 {
|
Chris@4
|
209 if (m_platency) *m_platency = m_winsize;
|
Chris@4
|
210 if (m_pfundamental) m_fundamental = *m_pfundamental;
|
Chris@4
|
211 if (m_pbandwidth) m_bandwidth = *m_pbandwidth;
|
Chris@4
|
212 if (m_pharmonics) m_harmonics = *m_pharmonics;
|
Chris@4
|
213 if (m_preduction) m_reduction = *m_preduction;
|
Chris@1
|
214 }
|
Chris@1
|
215
|
Chris@1
|
216 void
|
Chris@1
|
217 Devuvuzelator::runImpl(unsigned long sampleCount)
|
Chris@1
|
218 {
|
Chris@1
|
219 if (!m_input || !m_output) return;
|
Chris@4
|
220 updateParameters();
|
Chris@1
|
221
|
Chris@1
|
222 int ii = 0;
|
Chris@1
|
223 int oi = 0;
|
Chris@1
|
224 const int sc = sampleCount;
|
Chris@1
|
225
|
Chris@14
|
226 float tmp_input;
|
Chris@14
|
227
|
Chris@1
|
228 while (ii < sc) {
|
Chris@1
|
229
|
Chris@14
|
230 tmp_input = m_input[ii++];
|
Chris@14
|
231
|
Chris@4
|
232 m_output[oi++] = m_outacc[m_read++];
|
Chris@1
|
233
|
Chris@4
|
234 if (m_fill == m_winsize) {
|
Chris@1
|
235
|
Chris@1
|
236 processFrame();
|
Chris@1
|
237
|
Chris@4
|
238 for (int j = m_increment; j < m_winsize; ++j) {
|
Chris@1
|
239 m_buffer[j - m_increment] = m_buffer[j];
|
Chris@1
|
240 }
|
Chris@1
|
241
|
Chris@4
|
242 for (int j = m_increment; j < m_winsize*2; ++j) {
|
Chris@1
|
243 m_outacc[j - m_increment] = m_outacc[j];
|
Chris@1
|
244 }
|
Chris@1
|
245
|
Chris@4
|
246 for (int j = m_winsize*2 - m_increment; j < m_winsize*2; ++j) {
|
Chris@1
|
247 m_outacc[j] = 0.f;
|
Chris@1
|
248 }
|
Chris@1
|
249
|
Chris@1
|
250 m_fill -= m_increment;
|
Chris@1
|
251 m_read -= m_increment;
|
Chris@1
|
252 }
|
Chris@1
|
253
|
Chris@14
|
254 m_buffer[m_fill++] = tmp_input;
|
Chris@1
|
255 }
|
Chris@1
|
256 }
|
Chris@1
|
257
|
Chris@1
|
258 void
|
Chris@1
|
259 Devuvuzelator::processFrame()
|
Chris@1
|
260 {
|
Chris@1
|
261 double *frame = (double *)alloca(m_fftsize * sizeof(double));
|
Chris@1
|
262 for (int i = 0; i < m_fftsize; ++i) {
|
Chris@4
|
263 frame[i] = 0.0;
|
Chris@4
|
264 }
|
Chris@4
|
265
|
Chris@4
|
266 int ix = m_fftsize - m_winsize/2;
|
Chris@4
|
267 while (ix < 0) ix += m_fftsize;
|
Chris@4
|
268 for (int i = 0; i < m_winsize; ++i) {
|
Chris@4
|
269 frame[ix++] += m_buffer[i] * m_window[i];
|
Chris@1
|
270 if (ix == m_fftsize) ix = 0;
|
Chris@1
|
271 }
|
Chris@1
|
272
|
Chris@1
|
273 fft(m_fftsize, false, frame, 0, m_real, m_imag);
|
Chris@1
|
274
|
Chris@1
|
275 processSpectralFrame();
|
Chris@1
|
276
|
Chris@1
|
277 for (int i = 0; i < m_fftsize/2-1; ++i) {
|
Chris@3
|
278 m_real[m_fftsize-i-1] = m_real[i+1];
|
Chris@3
|
279 m_imag[m_fftsize-i-1] = -m_imag[i+1];
|
Chris@1
|
280 }
|
Chris@1
|
281
|
Chris@1
|
282 double *spare = (double *)alloca(m_fftsize * sizeof(double));
|
Chris@1
|
283 fft(m_fftsize, true, m_real, m_imag, frame, spare);
|
Chris@1
|
284
|
Chris@4
|
285 ix = m_fftsize - m_winsize/2;
|
Chris@4
|
286 while (ix < 0) ix += m_fftsize;
|
Chris@4
|
287 for (int i = 0; i < m_winsize; ++i) {
|
Chris@4
|
288 m_outacc[m_winsize + i] += frame[ix++];
|
Chris@1
|
289 if (ix == m_fftsize) ix = 0;
|
Chris@1
|
290 }
|
Chris@1
|
291 }
|
Chris@1
|
292
|
Chris@1
|
293 const LADSPA_Descriptor *
|
Chris@1
|
294 ladspa_descriptor(unsigned long ix)
|
Chris@1
|
295 {
|
Chris@1
|
296 return Devuvuzelator::getDescriptor(ix);
|
Chris@1
|
297 }
|
Chris@1
|
298
|