1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
5 An audio time-stretching and pitch-shifting library.
6 Copyright 2007-2008 Chris Cannam.
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.
15 #include "RubberBandPitchShifter.h"
17 #include "RubberBandStretcher.h"
22 using namespace RubberBand;
30 RubberBandPitchShifter::portNamesMono[PortCountMono] =
44 RubberBandPitchShifter::portNamesStereo[PortCountStereo] =
59 const LADSPA_PortDescriptor
60 RubberBandPitchShifter::portsMono[PortCountMono] =
62 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
63 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
64 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
65 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
66 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
67 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
68 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
69 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
70 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
73 const LADSPA_PortDescriptor
74 RubberBandPitchShifter::portsStereo[PortCountStereo] =
76 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
77 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
78 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
79 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
80 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
81 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
82 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
83 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
84 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
85 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
86 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
89 const LADSPA_PortRangeHint
90 RubberBandPitchShifter::hintsMono[PortCountMono] =
92 { 0, 0, 0 }, // latency
93 { LADSPA_HINT_DEFAULT_0 | // cents
94 LADSPA_HINT_BOUNDED_BELOW |
95 LADSPA_HINT_BOUNDED_ABOVE,
97 { LADSPA_HINT_DEFAULT_0 | // semitones
98 LADSPA_HINT_BOUNDED_BELOW |
99 LADSPA_HINT_BOUNDED_ABOVE |
102 { LADSPA_HINT_DEFAULT_0 | // octaves
103 LADSPA_HINT_BOUNDED_BELOW |
104 LADSPA_HINT_BOUNDED_ABOVE |
107 { LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
108 LADSPA_HINT_BOUNDED_BELOW |
109 LADSPA_HINT_BOUNDED_ABOVE |
112 { LADSPA_HINT_DEFAULT_0 | // formant preserving
113 LADSPA_HINT_BOUNDED_BELOW |
114 LADSPA_HINT_BOUNDED_ABOVE |
117 { LADSPA_HINT_DEFAULT_0 | // fast
118 LADSPA_HINT_BOUNDED_BELOW |
119 LADSPA_HINT_BOUNDED_ABOVE |
126 const LADSPA_PortRangeHint
127 RubberBandPitchShifter::hintsStereo[PortCountStereo] =
129 { 0, 0, 0 }, // latency
130 { LADSPA_HINT_DEFAULT_0 | // cents
131 LADSPA_HINT_BOUNDED_BELOW |
132 LADSPA_HINT_BOUNDED_ABOVE,
134 { LADSPA_HINT_DEFAULT_0 | // semitones
135 LADSPA_HINT_BOUNDED_BELOW |
136 LADSPA_HINT_BOUNDED_ABOVE |
139 { LADSPA_HINT_DEFAULT_0 | // octaves
140 LADSPA_HINT_BOUNDED_BELOW |
141 LADSPA_HINT_BOUNDED_ABOVE |
144 { LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
145 LADSPA_HINT_BOUNDED_BELOW |
146 LADSPA_HINT_BOUNDED_ABOVE |
149 { LADSPA_HINT_DEFAULT_0 | // formant preserving
150 LADSPA_HINT_BOUNDED_BELOW |
151 LADSPA_HINT_BOUNDED_ABOVE |
154 { LADSPA_HINT_DEFAULT_0 | // fast
155 LADSPA_HINT_BOUNDED_BELOW |
156 LADSPA_HINT_BOUNDED_ABOVE |
165 const LADSPA_Properties
166 RubberBandPitchShifter::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
168 const LADSPA_Descriptor
169 RubberBandPitchShifter::ladspaDescriptorMono =
172 "rubberband-pitchshifter-mono", // Label
174 "Rubber Band Mono Pitch Shifter", // Name
181 0, // Implementation data
187 0, // Set run adding gain
192 const LADSPA_Descriptor
193 RubberBandPitchShifter::ladspaDescriptorStereo =
196 "rubberband-pitchshifter-stereo", // Label
198 "Rubber Band Stereo Pitch Shifter", // Name
205 0, // Implementation data
211 0, // Set run adding gain
216 const LADSPA_Descriptor *
217 RubberBandPitchShifter::getDescriptor(unsigned long index)
219 if (index == 0) return &ladspaDescriptorMono;
220 if (index == 1) return &ladspaDescriptorStereo;
224 RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) :
234 m_currentCrispness(-1),
235 m_currentFormant(false),
236 m_currentFast(false),
240 m_stretcher(new RubberBandStretcher
241 (sampleRate, channels,
242 RubberBandStretcher::OptionProcessRealTime |
243 RubberBandStretcher::OptionPitchHighConsistency)),
244 m_sampleRate(sampleRate),
247 for (size_t c = 0; c < m_channels; ++c) {
252 int bufsize = m_blockSize + m_reserve + 8192;
254 m_outputBuffer[c] = new RingBuffer<float>(bufsize);
256 m_scratch[c] = new float[bufsize];
257 for (int i = 0; i < bufsize; ++i) m_scratch[c][i] = 0.f;
263 RubberBandPitchShifter::~RubberBandPitchShifter()
266 for (size_t c = 0; c < m_channels; ++c) {
267 delete m_outputBuffer[c];
268 delete[] m_scratch[c];
273 RubberBandPitchShifter::instantiate(const LADSPA_Descriptor *desc, unsigned long rate)
275 if (desc->PortCount == ladspaDescriptorMono.PortCount) {
276 return new RubberBandPitchShifter(rate, 1);
277 } else if (desc->PortCount == ladspaDescriptorStereo.PortCount) {
278 return new RubberBandPitchShifter(rate, 2);
284 RubberBandPitchShifter::connectPort(LADSPA_Handle handle,
285 unsigned long port, LADSPA_Data *location)
287 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
289 float **ports[PortCountStereo] = {
292 &shifter->m_semitones,
294 &shifter->m_crispness,
297 &shifter->m_input[0],
298 &shifter->m_output[0],
299 &shifter->m_input[1],
300 &shifter->m_output[1]
303 if (shifter->m_channels == 1) {
304 if (port >= PortCountMono) return;
306 if (port >= PortCountStereo) return;
309 *ports[port] = (float *)location;
311 if (shifter->m_latency) {
312 *(shifter->m_latency) =
313 float(shifter->m_stretcher->getLatency() + shifter->m_reserve);
318 RubberBandPitchShifter::activate(LADSPA_Handle handle)
320 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
321 shifter->activateImpl();
325 RubberBandPitchShifter::activateImpl()
328 m_prevRatio = m_ratio;
329 m_stretcher->reset();
330 m_stretcher->setPitchScale(m_ratio);
332 for (size_t c = 0; c < m_channels; ++c) {
333 m_outputBuffer[c]->reset();
334 m_outputBuffer[c]->zero(m_reserve);
340 // for (int i = 0; i < 8; ++i) {
341 // int reqd = m_stretcher->getSamplesRequired();
342 // m_stretcher->process(m_scratch, reqd, false);
343 // int avail = m_stretcher->available();
345 // m_stretcher->retrieve(m_scratch, avail);
351 RubberBandPitchShifter::run(LADSPA_Handle handle, unsigned long samples)
353 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
354 shifter->runImpl(samples);
358 RubberBandPitchShifter::updateRatio()
360 double oct = (m_octaves ? *m_octaves : 0.0);
361 oct += (m_semitones ? *m_semitones : 0.0) / 12;
362 oct += (m_cents ? *m_cents : 0.0) / 1200;
363 m_ratio = pow(2.0, oct);
367 RubberBandPitchShifter::updateCrispness()
369 if (!m_crispness) return;
371 int c = lrintf(*m_crispness);
372 if (c == m_currentCrispness) return;
373 if (c < 0 || c > 3) return;
374 RubberBandStretcher *s = m_stretcher;
378 s->setPhaseOption(RubberBandStretcher::OptionPhaseIndependent);
379 s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
382 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
383 s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
386 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
387 s->setTransientsOption(RubberBandStretcher::OptionTransientsMixed);
390 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
391 s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp);
395 m_currentCrispness = c;
399 RubberBandPitchShifter::updateFormant()
401 if (!m_formant) return;
403 bool f = (*m_formant > 0.5f);
404 if (f == m_currentFormant) return;
406 RubberBandStretcher *s = m_stretcher;
408 s->setFormantOption(f ?
409 RubberBandStretcher::OptionFormantPreserved :
410 RubberBandStretcher::OptionFormantShifted);
412 m_currentFormant = f;
416 RubberBandPitchShifter::updateFast()
420 bool f = (*m_fast > 0.5f);
421 if (f == m_currentFast) return;
423 RubberBandStretcher *s = m_stretcher;
425 s->setPitchOption(f ?
426 RubberBandStretcher::OptionPitchHighSpeed :
427 RubberBandStretcher::OptionPitchHighConsistency);
433 RubberBandPitchShifter::runImpl(unsigned long insamples)
435 unsigned long offset = 0;
437 // We have to break up the input into chunks like this because
438 // insamples could be arbitrarily large and our output buffer is
441 while (offset < insamples) {
443 unsigned long block = (unsigned long)m_blockSize;
444 if (block + offset > insamples) block = insamples - offset;
446 runImpl(block, offset);
453 RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset)
455 // cerr << "RubberBandPitchShifter::runImpl(" << insamples << ")" << endl;
457 // static int incount = 0, outcount = 0;
460 if (m_ratio != m_prevRatio) {
461 m_stretcher->setPitchScale(m_ratio);
462 m_prevRatio = m_ratio;
466 *m_latency = float(m_stretcher->getLatency() + m_reserve);
467 // cerr << "latency = " << *m_latency << endl;
474 const int samples = insamples;
480 int rs = m_outputBuffer[0]->getReadSpace();
481 if (rs < int(m_minfill)) {
482 // cerr << "temporary expansion (have " << rs << ", want " << m_reserve << ")" << endl;
483 m_stretcher->setTimeRatio(1.1); // fill up temporarily
484 } else if (rs > 8192) {
485 // cerr << "temporary reduction (have " << rs << ", want " << m_reserve << ")" << endl;
486 m_stretcher->setTimeRatio(0.9); // reduce temporarily
488 m_stretcher->setTimeRatio(1.0);
491 while (processed < samples) {
493 // never feed more than the minimum necessary number of
494 // samples at a time; ensures nothing will overflow internally
495 // and we don't need to call setMaxProcessSize
497 int toCauseProcessing = m_stretcher->getSamplesRequired();
498 int inchunk = min(samples - processed, toCauseProcessing);
499 for (size_t c = 0; c < m_channels; ++c) {
500 ptrs[c] = &(m_input[c][offset + processed]);
502 m_stretcher->process(ptrs, inchunk, false);
503 processed += inchunk;
505 int avail = m_stretcher->available();
506 int writable = m_outputBuffer[0]->getWriteSpace();
507 int outchunk = min(avail, writable);
508 size_t actual = m_stretcher->retrieve(m_scratch, outchunk);
511 // incount += inchunk;
512 // outcount += actual;
514 // cout << "avail: " << avail << ", outchunk = " << outchunk;
515 // if (actual != outchunk) cout << " (" << actual << ")";
520 for (size_t c = 0; c < m_channels; ++c) {
521 if (int(m_outputBuffer[c]->getWriteSpace()) < outchunk) {
522 cerr << "RubberBandPitchShifter::runImpl: buffer overrun: chunk = " << outchunk << ", space = " << m_outputBuffer[c]->getWriteSpace() << endl;
524 m_outputBuffer[c]->write(m_scratch[c], outchunk);
528 for (size_t c = 0; c < m_channels; ++c) {
529 int toRead = m_outputBuffer[c]->getReadSpace();
530 if (toRead < samples && c == 0) {
531 cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << endl;
533 int chunk = min(toRead, samples);
534 m_outputBuffer[c]->read(&(m_output[c][offset]), chunk);
537 if (m_minfill == 0) {
538 m_minfill = m_outputBuffer[0]->getReadSpace();
539 // cerr << "minfill = " << m_minfill << endl;
544 RubberBandPitchShifter::deactivate(LADSPA_Handle handle)
546 activate(handle); // both functions just reset the plugin
550 RubberBandPitchShifter::cleanup(LADSPA_Handle handle)
552 delete (RubberBandPitchShifter *)handle;