Mercurial > hg > sv-dependency-builds
comparison src/rubberband-1.8.1/ladspa/RubberBandPitchShifter.cpp @ 95:89f5e221ed7b
Add FFTW3
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Wed, 20 Mar 2013 15:35:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
94:d278df1123f9 | 95:89f5e221ed7b |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Rubber Band Library | |
5 An audio time-stretching and pitch-shifting library. | |
6 Copyright 2007-2012 Particular Programs Ltd. | |
7 | |
8 This program is free software; you can redistribute it and/or | |
9 modify it under the terms of the GNU General Public License as | |
10 published by the Free Software Foundation; either version 2 of the | |
11 License, or (at your option) any later version. See the file | |
12 COPYING included with this distribution for more information. | |
13 | |
14 Alternatively, if you have a valid commercial licence for the | |
15 Rubber Band Library obtained by agreement with the copyright | |
16 holders, you may redistribute and/or modify it under the terms | |
17 described in that licence. | |
18 | |
19 If you wish to distribute code using the Rubber Band Library | |
20 under terms other than those of the GNU General Public License, | |
21 you must obtain a valid commercial licence before doing so. | |
22 */ | |
23 | |
24 #include "RubberBandPitchShifter.h" | |
25 | |
26 #include "RubberBandStretcher.h" | |
27 | |
28 #include <iostream> | |
29 #include <cmath> | |
30 | |
31 using namespace RubberBand; | |
32 | |
33 using std::cout; | |
34 using std::cerr; | |
35 using std::endl; | |
36 using std::min; | |
37 | |
38 const char *const | |
39 RubberBandPitchShifter::portNamesMono[PortCountMono] = | |
40 { | |
41 "latency", | |
42 "Cents", | |
43 "Semitones", | |
44 "Octaves", | |
45 "Crispness", | |
46 "Formant Preserving", | |
47 "Faster", | |
48 "Input", | |
49 "Output" | |
50 }; | |
51 | |
52 const char *const | |
53 RubberBandPitchShifter::portNamesStereo[PortCountStereo] = | |
54 { | |
55 "latency", | |
56 "Cents", | |
57 "Semitones", | |
58 "Octaves", | |
59 "Crispness", | |
60 "Formant Preserving", | |
61 "Faster", | |
62 "Input L", | |
63 "Output L", | |
64 "Input R", | |
65 "Output R" | |
66 }; | |
67 | |
68 const LADSPA_PortDescriptor | |
69 RubberBandPitchShifter::portsMono[PortCountMono] = | |
70 { | |
71 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, | |
72 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
73 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
74 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
75 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
76 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
77 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
78 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, | |
79 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO | |
80 }; | |
81 | |
82 const LADSPA_PortDescriptor | |
83 RubberBandPitchShifter::portsStereo[PortCountStereo] = | |
84 { | |
85 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, | |
86 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
87 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
88 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
89 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
90 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
91 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, | |
92 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, | |
93 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, | |
94 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, | |
95 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO | |
96 }; | |
97 | |
98 const LADSPA_PortRangeHint | |
99 RubberBandPitchShifter::hintsMono[PortCountMono] = | |
100 { | |
101 { 0, 0, 0 }, // latency | |
102 { LADSPA_HINT_DEFAULT_0 | // cents | |
103 LADSPA_HINT_BOUNDED_BELOW | | |
104 LADSPA_HINT_BOUNDED_ABOVE, | |
105 -100.0, 100.0 }, | |
106 { LADSPA_HINT_DEFAULT_0 | // semitones | |
107 LADSPA_HINT_BOUNDED_BELOW | | |
108 LADSPA_HINT_BOUNDED_ABOVE | | |
109 LADSPA_HINT_INTEGER, | |
110 -12.0, 12.0 }, | |
111 { LADSPA_HINT_DEFAULT_0 | // octaves | |
112 LADSPA_HINT_BOUNDED_BELOW | | |
113 LADSPA_HINT_BOUNDED_ABOVE | | |
114 LADSPA_HINT_INTEGER, | |
115 -3.0, 3.0 }, | |
116 { LADSPA_HINT_DEFAULT_MAXIMUM | // crispness | |
117 LADSPA_HINT_BOUNDED_BELOW | | |
118 LADSPA_HINT_BOUNDED_ABOVE | | |
119 LADSPA_HINT_INTEGER, | |
120 0.0, 3.0 }, | |
121 { LADSPA_HINT_DEFAULT_0 | // formant preserving | |
122 LADSPA_HINT_BOUNDED_BELOW | | |
123 LADSPA_HINT_BOUNDED_ABOVE | | |
124 LADSPA_HINT_TOGGLED, | |
125 0.0, 1.0 }, | |
126 { LADSPA_HINT_DEFAULT_0 | // fast | |
127 LADSPA_HINT_BOUNDED_BELOW | | |
128 LADSPA_HINT_BOUNDED_ABOVE | | |
129 LADSPA_HINT_TOGGLED, | |
130 0.0, 1.0 }, | |
131 { 0, 0, 0 }, | |
132 { 0, 0, 0 } | |
133 }; | |
134 | |
135 const LADSPA_PortRangeHint | |
136 RubberBandPitchShifter::hintsStereo[PortCountStereo] = | |
137 { | |
138 { 0, 0, 0 }, // latency | |
139 { LADSPA_HINT_DEFAULT_0 | // cents | |
140 LADSPA_HINT_BOUNDED_BELOW | | |
141 LADSPA_HINT_BOUNDED_ABOVE, | |
142 -100.0, 100.0 }, | |
143 { LADSPA_HINT_DEFAULT_0 | // semitones | |
144 LADSPA_HINT_BOUNDED_BELOW | | |
145 LADSPA_HINT_BOUNDED_ABOVE | | |
146 LADSPA_HINT_INTEGER, | |
147 -12.0, 12.0 }, | |
148 { LADSPA_HINT_DEFAULT_0 | // octaves | |
149 LADSPA_HINT_BOUNDED_BELOW | | |
150 LADSPA_HINT_BOUNDED_ABOVE | | |
151 LADSPA_HINT_INTEGER, | |
152 -3.0, 3.0 }, | |
153 { LADSPA_HINT_DEFAULT_MAXIMUM | // crispness | |
154 LADSPA_HINT_BOUNDED_BELOW | | |
155 LADSPA_HINT_BOUNDED_ABOVE | | |
156 LADSPA_HINT_INTEGER, | |
157 0.0, 3.0 }, | |
158 { LADSPA_HINT_DEFAULT_0 | // formant preserving | |
159 LADSPA_HINT_BOUNDED_BELOW | | |
160 LADSPA_HINT_BOUNDED_ABOVE | | |
161 LADSPA_HINT_TOGGLED, | |
162 0.0, 1.0 }, | |
163 { LADSPA_HINT_DEFAULT_0 | // fast | |
164 LADSPA_HINT_BOUNDED_BELOW | | |
165 LADSPA_HINT_BOUNDED_ABOVE | | |
166 LADSPA_HINT_TOGGLED, | |
167 0.0, 1.0 }, | |
168 { 0, 0, 0 }, | |
169 { 0, 0, 0 }, | |
170 { 0, 0, 0 }, | |
171 { 0, 0, 0 } | |
172 }; | |
173 | |
174 const LADSPA_Properties | |
175 RubberBandPitchShifter::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; | |
176 | |
177 const LADSPA_Descriptor | |
178 RubberBandPitchShifter::ladspaDescriptorMono = | |
179 { | |
180 2979, // "Unique" ID | |
181 "rubberband-pitchshifter-mono", // Label | |
182 properties, | |
183 "Rubber Band Mono Pitch Shifter", // Name | |
184 "Breakfast Quay", | |
185 "GPL", | |
186 PortCountMono, | |
187 portsMono, | |
188 portNamesMono, | |
189 hintsMono, | |
190 0, // Implementation data | |
191 instantiate, | |
192 connectPort, | |
193 activate, | |
194 run, | |
195 0, // Run adding | |
196 0, // Set run adding gain | |
197 deactivate, | |
198 cleanup | |
199 }; | |
200 | |
201 const LADSPA_Descriptor | |
202 RubberBandPitchShifter::ladspaDescriptorStereo = | |
203 { | |
204 9792, // "Unique" ID | |
205 "rubberband-pitchshifter-stereo", // Label | |
206 properties, | |
207 "Rubber Band Stereo Pitch Shifter", // Name | |
208 "Breakfast Quay", | |
209 "GPL", | |
210 PortCountStereo, | |
211 portsStereo, | |
212 portNamesStereo, | |
213 hintsStereo, | |
214 0, // Implementation data | |
215 instantiate, | |
216 connectPort, | |
217 activate, | |
218 run, | |
219 0, // Run adding | |
220 0, // Set run adding gain | |
221 deactivate, | |
222 cleanup | |
223 }; | |
224 | |
225 const LADSPA_Descriptor * | |
226 RubberBandPitchShifter::getDescriptor(unsigned long index) | |
227 { | |
228 if (index == 0) return &ladspaDescriptorMono; | |
229 if (index == 1) return &ladspaDescriptorStereo; | |
230 else return 0; | |
231 } | |
232 | |
233 RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) : | |
234 m_latency(0), | |
235 m_cents(0), | |
236 m_semitones(0), | |
237 m_octaves(0), | |
238 m_crispness(0), | |
239 m_formant(0), | |
240 m_fast(0), | |
241 m_ratio(1.0), | |
242 m_prevRatio(1.0), | |
243 m_currentCrispness(-1), | |
244 m_currentFormant(false), | |
245 m_currentFast(false), | |
246 m_blockSize(1024), | |
247 m_reserve(1024), | |
248 m_minfill(0), | |
249 m_stretcher(new RubberBandStretcher | |
250 (sampleRate, channels, | |
251 RubberBandStretcher::OptionProcessRealTime | | |
252 RubberBandStretcher::OptionPitchHighConsistency)), | |
253 m_sampleRate(sampleRate), | |
254 m_channels(channels) | |
255 { | |
256 for (size_t c = 0; c < m_channels; ++c) { | |
257 | |
258 m_input[c] = 0; | |
259 m_output[c] = 0; | |
260 | |
261 int bufsize = m_blockSize + m_reserve + 8192; | |
262 | |
263 m_outputBuffer[c] = new RingBuffer<float>(bufsize); | |
264 | |
265 m_scratch[c] = new float[bufsize]; | |
266 for (int i = 0; i < bufsize; ++i) m_scratch[c][i] = 0.f; | |
267 } | |
268 | |
269 activateImpl(); | |
270 } | |
271 | |
272 RubberBandPitchShifter::~RubberBandPitchShifter() | |
273 { | |
274 delete m_stretcher; | |
275 for (size_t c = 0; c < m_channels; ++c) { | |
276 delete m_outputBuffer[c]; | |
277 delete[] m_scratch[c]; | |
278 } | |
279 } | |
280 | |
281 LADSPA_Handle | |
282 RubberBandPitchShifter::instantiate(const LADSPA_Descriptor *desc, unsigned long rate) | |
283 { | |
284 if (desc->PortCount == ladspaDescriptorMono.PortCount) { | |
285 return new RubberBandPitchShifter(rate, 1); | |
286 } else if (desc->PortCount == ladspaDescriptorStereo.PortCount) { | |
287 return new RubberBandPitchShifter(rate, 2); | |
288 } | |
289 return 0; | |
290 } | |
291 | |
292 void | |
293 RubberBandPitchShifter::connectPort(LADSPA_Handle handle, | |
294 unsigned long port, LADSPA_Data *location) | |
295 { | |
296 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle; | |
297 | |
298 float **ports[PortCountStereo] = { | |
299 &shifter->m_latency, | |
300 &shifter->m_cents, | |
301 &shifter->m_semitones, | |
302 &shifter->m_octaves, | |
303 &shifter->m_crispness, | |
304 &shifter->m_formant, | |
305 &shifter->m_fast, | |
306 &shifter->m_input[0], | |
307 &shifter->m_output[0], | |
308 &shifter->m_input[1], | |
309 &shifter->m_output[1] | |
310 }; | |
311 | |
312 if (shifter->m_channels == 1) { | |
313 if (port >= PortCountMono) return; | |
314 } else { | |
315 if (port >= PortCountStereo) return; | |
316 } | |
317 | |
318 *ports[port] = (float *)location; | |
319 | |
320 if (shifter->m_latency) { | |
321 *(shifter->m_latency) = | |
322 float(shifter->m_stretcher->getLatency() + shifter->m_reserve); | |
323 } | |
324 } | |
325 | |
326 void | |
327 RubberBandPitchShifter::activate(LADSPA_Handle handle) | |
328 { | |
329 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle; | |
330 shifter->activateImpl(); | |
331 } | |
332 | |
333 void | |
334 RubberBandPitchShifter::activateImpl() | |
335 { | |
336 updateRatio(); | |
337 m_prevRatio = m_ratio; | |
338 m_stretcher->reset(); | |
339 m_stretcher->setPitchScale(m_ratio); | |
340 | |
341 for (size_t c = 0; c < m_channels; ++c) { | |
342 m_outputBuffer[c]->reset(); | |
343 m_outputBuffer[c]->zero(m_reserve); | |
344 } | |
345 | |
346 m_minfill = 0; | |
347 | |
348 // prime stretcher | |
349 // for (int i = 0; i < 8; ++i) { | |
350 // int reqd = m_stretcher->getSamplesRequired(); | |
351 // m_stretcher->process(m_scratch, reqd, false); | |
352 // int avail = m_stretcher->available(); | |
353 // if (avail > 0) { | |
354 // m_stretcher->retrieve(m_scratch, avail); | |
355 // } | |
356 // } | |
357 } | |
358 | |
359 void | |
360 RubberBandPitchShifter::run(LADSPA_Handle handle, unsigned long samples) | |
361 { | |
362 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle; | |
363 shifter->runImpl(samples); | |
364 } | |
365 | |
366 void | |
367 RubberBandPitchShifter::updateRatio() | |
368 { | |
369 double oct = (m_octaves ? *m_octaves : 0.0); | |
370 oct += (m_semitones ? *m_semitones : 0.0) / 12; | |
371 oct += (m_cents ? *m_cents : 0.0) / 1200; | |
372 m_ratio = pow(2.0, oct); | |
373 } | |
374 | |
375 void | |
376 RubberBandPitchShifter::updateCrispness() | |
377 { | |
378 if (!m_crispness) return; | |
379 | |
380 int c = lrintf(*m_crispness); | |
381 if (c == m_currentCrispness) return; | |
382 if (c < 0 || c > 3) return; | |
383 RubberBandStretcher *s = m_stretcher; | |
384 | |
385 switch (c) { | |
386 case 0: | |
387 s->setPhaseOption(RubberBandStretcher::OptionPhaseIndependent); | |
388 s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth); | |
389 break; | |
390 case 1: | |
391 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar); | |
392 s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth); | |
393 break; | |
394 case 2: | |
395 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar); | |
396 s->setTransientsOption(RubberBandStretcher::OptionTransientsMixed); | |
397 break; | |
398 case 3: | |
399 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar); | |
400 s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp); | |
401 break; | |
402 } | |
403 | |
404 m_currentCrispness = c; | |
405 } | |
406 | |
407 void | |
408 RubberBandPitchShifter::updateFormant() | |
409 { | |
410 if (!m_formant) return; | |
411 | |
412 bool f = (*m_formant > 0.5f); | |
413 if (f == m_currentFormant) return; | |
414 | |
415 RubberBandStretcher *s = m_stretcher; | |
416 | |
417 s->setFormantOption(f ? | |
418 RubberBandStretcher::OptionFormantPreserved : | |
419 RubberBandStretcher::OptionFormantShifted); | |
420 | |
421 m_currentFormant = f; | |
422 } | |
423 | |
424 void | |
425 RubberBandPitchShifter::updateFast() | |
426 { | |
427 if (!m_fast) return; | |
428 | |
429 bool f = (*m_fast > 0.5f); | |
430 if (f == m_currentFast) return; | |
431 | |
432 RubberBandStretcher *s = m_stretcher; | |
433 | |
434 s->setPitchOption(f ? | |
435 RubberBandStretcher::OptionPitchHighSpeed : | |
436 RubberBandStretcher::OptionPitchHighConsistency); | |
437 | |
438 m_currentFast = f; | |
439 } | |
440 | |
441 void | |
442 RubberBandPitchShifter::runImpl(unsigned long insamples) | |
443 { | |
444 unsigned long offset = 0; | |
445 | |
446 // We have to break up the input into chunks like this because | |
447 // insamples could be arbitrarily large and our output buffer is | |
448 // of limited size | |
449 | |
450 while (offset < insamples) { | |
451 | |
452 unsigned long block = (unsigned long)m_blockSize; | |
453 if (block + offset > insamples) block = insamples - offset; | |
454 | |
455 runImpl(block, offset); | |
456 | |
457 offset += block; | |
458 } | |
459 } | |
460 | |
461 void | |
462 RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset) | |
463 { | |
464 // cerr << "RubberBandPitchShifter::runImpl(" << insamples << ")" << endl; | |
465 | |
466 // static int incount = 0, outcount = 0; | |
467 | |
468 updateRatio(); | |
469 if (m_ratio != m_prevRatio) { | |
470 m_stretcher->setPitchScale(m_ratio); | |
471 m_prevRatio = m_ratio; | |
472 } | |
473 | |
474 if (m_latency) { | |
475 *m_latency = float(m_stretcher->getLatency() + m_reserve); | |
476 // cerr << "latency = " << *m_latency << endl; | |
477 } | |
478 | |
479 updateCrispness(); | |
480 updateFormant(); | |
481 updateFast(); | |
482 | |
483 const int samples = insamples; | |
484 int processed = 0; | |
485 size_t outTotal = 0; | |
486 | |
487 float *ptrs[2]; | |
488 | |
489 int rs = m_outputBuffer[0]->getReadSpace(); | |
490 if (rs < int(m_minfill)) { | |
491 // cerr << "temporary expansion (have " << rs << ", want " << m_reserve << ")" << endl; | |
492 m_stretcher->setTimeRatio(1.1); // fill up temporarily | |
493 } else if (rs > 8192) { | |
494 // cerr << "temporary reduction (have " << rs << ", want " << m_reserve << ")" << endl; | |
495 m_stretcher->setTimeRatio(0.9); // reduce temporarily | |
496 } else { | |
497 m_stretcher->setTimeRatio(1.0); | |
498 } | |
499 | |
500 while (processed < samples) { | |
501 | |
502 // never feed more than the minimum necessary number of | |
503 // samples at a time; ensures nothing will overflow internally | |
504 // and we don't need to call setMaxProcessSize | |
505 | |
506 int toCauseProcessing = m_stretcher->getSamplesRequired(); | |
507 int inchunk = min(samples - processed, toCauseProcessing); | |
508 for (size_t c = 0; c < m_channels; ++c) { | |
509 ptrs[c] = &(m_input[c][offset + processed]); | |
510 } | |
511 m_stretcher->process(ptrs, inchunk, false); | |
512 processed += inchunk; | |
513 | |
514 int avail = m_stretcher->available(); | |
515 int writable = m_outputBuffer[0]->getWriteSpace(); | |
516 int outchunk = min(avail, writable); | |
517 size_t actual = m_stretcher->retrieve(m_scratch, outchunk); | |
518 outTotal += actual; | |
519 | |
520 // incount += inchunk; | |
521 // outcount += actual; | |
522 | |
523 // cout << "avail: " << avail << ", outchunk = " << outchunk; | |
524 // if (actual != outchunk) cout << " (" << actual << ")"; | |
525 // cout << endl; | |
526 | |
527 outchunk = actual; | |
528 | |
529 for (size_t c = 0; c < m_channels; ++c) { | |
530 if (int(m_outputBuffer[c]->getWriteSpace()) < outchunk) { | |
531 cerr << "RubberBandPitchShifter::runImpl: buffer overrun: chunk = " << outchunk << ", space = " << m_outputBuffer[c]->getWriteSpace() << endl; | |
532 } | |
533 m_outputBuffer[c]->write(m_scratch[c], outchunk); | |
534 } | |
535 } | |
536 | |
537 for (size_t c = 0; c < m_channels; ++c) { | |
538 int toRead = m_outputBuffer[c]->getReadSpace(); | |
539 if (toRead < samples && c == 0) { | |
540 cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << endl; | |
541 } | |
542 int chunk = min(toRead, samples); | |
543 m_outputBuffer[c]->read(&(m_output[c][offset]), chunk); | |
544 } | |
545 | |
546 if (m_minfill == 0) { | |
547 m_minfill = m_outputBuffer[0]->getReadSpace(); | |
548 // cerr << "minfill = " << m_minfill << endl; | |
549 } | |
550 } | |
551 | |
552 void | |
553 RubberBandPitchShifter::deactivate(LADSPA_Handle handle) | |
554 { | |
555 activate(handle); // both functions just reset the plugin | |
556 } | |
557 | |
558 void | |
559 RubberBandPitchShifter::cleanup(LADSPA_Handle handle) | |
560 { | |
561 delete (RubberBandPitchShifter *)handle; | |
562 } | |
563 |