Files
librubberband/ladspa-lv2/RubberBandPitchShifter.cpp

665 lines
17 KiB
C++
Raw Normal View History

2007-11-06 21:41:16 +00:00
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
2012-09-09 16:57:42 +01:00
Rubber Band Library
2007-11-06 21:41:16 +00:00
An audio time-stretching and pitch-shifting library.
2022-01-04 17:50:15 +00:00
Copyright 2007-2022 Particular Programs Ltd.
2012-09-09 16:57:42 +01:00
2007-11-06 21:41:16 +00:00
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
2012-09-09 16:57:42 +01:00
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
2007-11-06 21:41:16 +00:00
*/
#include "RubberBandPitchShifter.h"
#include "RubberBandStretcher.h"
#include <iostream>
#include <cmath>
using namespace RubberBand;
2008-07-06 19:24:53 +00:00
using std::cout;
using std::cerr;
using std::endl;
using std::min;
2022-01-07 13:33:18 +00:00
#ifdef RB_PLUGIN_LADSPA
2007-11-06 21:41:16 +00:00
const char *const
RubberBandPitchShifter::portNamesMono[PortCountMono] =
{
2008-01-28 17:24:55 +00:00
"latency",
2007-11-06 21:41:16 +00:00
"Cents",
"Semitones",
"Octaves",
"Crispness",
2008-07-04 19:31:23 +00:00
"Formant Preserving",
"Wet-Dry Mix",
2007-11-06 21:41:16 +00:00
"Input",
"Output"
};
const char *const
RubberBandPitchShifter::portNamesStereo[PortCountStereo] =
{
2008-01-28 17:24:55 +00:00
"latency",
2007-11-06 21:41:16 +00:00
"Cents",
"Semitones",
"Octaves",
"Crispness",
2008-07-04 19:31:23 +00:00
"Formant Preserving",
"Wet-Dry Mix",
2007-11-06 21:41:16 +00:00
"Input L",
"Output L",
"Input R",
"Output R"
};
const LADSPA_PortDescriptor
RubberBandPitchShifter::portsMono[PortCountMono] =
{
LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
2008-07-04 19:31:23 +00:00
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
2007-11-06 21:41:16 +00:00
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
};
const LADSPA_PortDescriptor
RubberBandPitchShifter::portsStereo[PortCountStereo] =
{
LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
2008-07-04 19:31:23 +00:00
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
2007-11-06 21:41:16 +00:00
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
};
const LADSPA_PortRangeHint
RubberBandPitchShifter::hintsMono[PortCountMono] =
{
2008-07-04 14:19:32 +00:00
{ 0, 0, 0 }, // latency
{ LADSPA_HINT_DEFAULT_0 | // cents
2007-11-06 21:41:16 +00:00
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
-100.0, 100.0 },
2008-07-04 14:19:32 +00:00
{ LADSPA_HINT_DEFAULT_0 | // semitones
2007-11-06 21:41:16 +00:00
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-12.0, 12.0 },
2008-07-04 14:19:32 +00:00
{ LADSPA_HINT_DEFAULT_0 | // octaves
2007-11-06 21:41:16 +00:00
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-2.0, 2.0 },
2008-07-04 14:19:32 +00:00
{ LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
0.0, 3.0 },
2008-07-04 14:19:32 +00:00
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ LADSPA_HINT_DEFAULT_0 | // wet-dry mix
2008-07-04 19:31:23 +00:00
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
2008-07-04 19:31:23 +00:00
0.0, 1.0 },
2007-11-06 21:41:16 +00:00
{ 0, 0, 0 },
{ 0, 0, 0 }
};
const LADSPA_PortRangeHint
RubberBandPitchShifter::hintsStereo[PortCountStereo] =
{
2008-07-04 14:19:32 +00:00
{ 0, 0, 0 }, // latency
{ LADSPA_HINT_DEFAULT_0 | // cents
2007-11-06 21:41:16 +00:00
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
-100.0, 100.0 },
2008-07-04 14:19:32 +00:00
{ LADSPA_HINT_DEFAULT_0 | // semitones
2007-11-06 21:41:16 +00:00
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-12.0, 12.0 },
2008-07-04 14:19:32 +00:00
{ LADSPA_HINT_DEFAULT_0 | // octaves
2007-11-06 21:41:16 +00:00
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-2.0, 2.0 },
2008-07-04 14:19:32 +00:00
{ LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
0.0, 3.0 },
2008-07-04 14:19:32 +00:00
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ LADSPA_HINT_DEFAULT_0 | // wet-dry mix
2008-07-04 19:31:23 +00:00
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
2008-07-04 19:31:23 +00:00
0.0, 1.0 },
2007-11-06 21:41:16 +00:00
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 }
};
const LADSPA_Properties
RubberBandPitchShifter::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
const LADSPA_Descriptor
RubberBandPitchShifter::ladspaDescriptorMono =
{
2979, // "Unique" ID
"rubberband-pitchshifter-mono", // Label
properties,
"Rubber Band Mono Pitch Shifter", // Name
2008-06-04 20:43:22 +00:00
"Breakfast Quay",
"GPL",
2007-11-06 21:41:16 +00:00
PortCountMono,
portsMono,
portNamesMono,
hintsMono,
2022-01-07 13:33:18 +00:00
nullptr, // Implementation data
2007-11-06 21:41:16 +00:00
instantiate,
connectPort,
activate,
run,
2022-01-07 13:33:18 +00:00
nullptr, // Run adding
nullptr, // Set run adding gain
2007-11-06 21:41:16 +00:00
deactivate,
cleanup
};
const LADSPA_Descriptor
RubberBandPitchShifter::ladspaDescriptorStereo =
{
9792, // "Unique" ID
"rubberband-pitchshifter-stereo", // Label
properties,
"Rubber Band Stereo Pitch Shifter", // Name
2008-06-04 20:43:22 +00:00
"Breakfast Quay",
"GPL",
2007-11-06 21:41:16 +00:00
PortCountStereo,
portsStereo,
portNamesStereo,
hintsStereo,
2022-01-07 13:33:18 +00:00
nullptr, // Implementation data
2007-11-06 21:41:16 +00:00
instantiate,
connectPort,
activate,
run,
2022-01-07 13:33:18 +00:00
nullptr, // Run adding
nullptr, // Set run adding gain
2007-11-06 21:41:16 +00:00
deactivate,
cleanup
};
const LADSPA_Descriptor *
RubberBandPitchShifter::getDescriptor(unsigned long index)
{
if (index == 0) return &ladspaDescriptorMono;
if (index == 1) return &ladspaDescriptorStereo;
else return 0;
}
2022-01-07 13:33:18 +00:00
#else
const LV2_Descriptor
RubberBandPitchShifter::lv2DescriptorMono =
{
"http://breakfastquay.com/rdf/lv2-rubberband#mono",
instantiate,
connectPort,
activate,
run,
deactivate,
cleanup,
nullptr
};
const LV2_Descriptor
RubberBandPitchShifter::lv2DescriptorStereo =
{
"http://breakfastquay.com/rdf/lv2-rubberband#stereo",
instantiate,
connectPort,
activate,
run,
deactivate,
cleanup,
nullptr
};
const LV2_Descriptor *
RubberBandPitchShifter::getDescriptor(uint32_t index)
{
if (index == 0) return &lv2DescriptorMono;
if (index == 1) return &lv2DescriptorStereo;
else return 0;
}
#endif
2007-11-06 21:41:16 +00:00
RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) :
2022-01-07 13:33:18 +00:00
m_latency(nullptr),
m_cents(nullptr),
m_semitones(nullptr),
m_octaves(nullptr),
m_crispness(nullptr),
m_formant(nullptr),
m_wetDry(nullptr),
2007-11-06 21:41:16 +00:00
m_ratio(1.0),
m_prevRatio(1.0),
m_currentCrispness(-1),
2008-06-09 20:46:37 +00:00
m_currentFormant(false),
2008-07-04 14:19:32 +00:00
m_blockSize(1024),
m_reserve(8192),
m_bufsize(0),
2008-07-06 19:24:53 +00:00
m_minfill(0),
m_stretcher(new RubberBandStretcher
2007-11-06 21:41:16 +00:00
(sampleRate, channels,
2008-07-04 14:19:32 +00:00
RubberBandStretcher::OptionProcessRealTime |
RubberBandStretcher::OptionPitchHighConsistency)),
2007-11-06 21:41:16 +00:00
m_sampleRate(sampleRate),
m_channels(channels)
{
m_input = new float *[m_channels];
m_output = new float *[m_channels];
m_outputBuffer = new RingBuffer<float> *[m_channels];
m_delayMixBuffer = new RingBuffer<float> *[m_channels];
m_scratch = new float *[m_channels];
2022-01-07 13:33:18 +00:00
m_inptrs = new float *[m_channels];
m_bufsize = m_blockSize + m_reserve + 8192;
2007-11-06 21:41:16 +00:00
for (size_t c = 0; c < m_channels; ++c) {
2008-07-04 14:19:32 +00:00
2007-11-06 21:41:16 +00:00
m_input[c] = 0;
m_output[c] = 0;
2008-07-04 14:19:32 +00:00
m_outputBuffer[c] = new RingBuffer<float>(m_bufsize);
m_delayMixBuffer[c] = new RingBuffer<float>(m_bufsize);
2008-07-04 14:19:32 +00:00
m_scratch[c] = new float[m_bufsize];
2021-05-14 15:09:28 +01:00
for (size_t i = 0; i < m_bufsize; ++i) {
m_scratch[c][i] = 0.f;
}
2022-01-07 13:33:18 +00:00
m_inptrs[c] = 0;
2007-11-06 21:41:16 +00:00
}
2008-07-04 14:19:32 +00:00
activateImpl();
2007-11-06 21:41:16 +00:00
}
RubberBandPitchShifter::~RubberBandPitchShifter()
{
delete m_stretcher;
for (size_t c = 0; c < m_channels; ++c) {
delete m_outputBuffer[c];
delete m_delayMixBuffer[c];
2007-11-06 21:41:16 +00:00
delete[] m_scratch[c];
}
delete[] m_outputBuffer;
delete[] m_delayMixBuffer;
2022-01-07 13:33:18 +00:00
delete[] m_inptrs;
delete[] m_scratch;
delete[] m_output;
delete[] m_input;
2007-11-06 21:41:16 +00:00
}
2022-01-07 13:33:18 +00:00
#ifdef RB_PLUGIN_LADSPA
2007-11-06 21:41:16 +00:00
LADSPA_Handle
RubberBandPitchShifter::instantiate(const LADSPA_Descriptor *desc, unsigned long rate)
{
if (desc->PortCount == ladspaDescriptorMono.PortCount) {
return new RubberBandPitchShifter(rate, 1);
} else if (desc->PortCount == ladspaDescriptorStereo.PortCount) {
return new RubberBandPitchShifter(rate, 2);
}
2022-01-07 13:33:18 +00:00
return nullptr;
2007-11-06 21:41:16 +00:00
}
2022-01-07 13:33:18 +00:00
#else
LV2_Handle
RubberBandPitchShifter::instantiate(const LV2_Descriptor *desc, double rate,
const char *, const LV2_Feature *const *)
{
if (rate < 1.0) {
std::cerr << "RubberBandPitchShifter::instantiate: invalid sample rate "
<< rate << " provided" << std::endl;
return nullptr;
}
size_t srate = size_t(round(rate));
if (std::string(desc->URI) == lv2DescriptorMono.URI) {
return new RubberBandPitchShifter(srate, 1);
} else if (std::string(desc->URI) == lv2DescriptorStereo.URI) {
return new RubberBandPitchShifter(srate, 2);
} else {
std::cerr << "RubberBandPitchShifter::instantiate: unrecognised URI "
<< desc->URI << " requested" << std::endl;
return nullptr;
}
}
#endif
#ifdef RB_PLUGIN_LADSPA
2007-11-06 21:41:16 +00:00
void
RubberBandPitchShifter::connectPort(LADSPA_Handle handle,
unsigned long port, LADSPA_Data *location)
2022-01-07 13:33:18 +00:00
#else
void
RubberBandPitchShifter::connectPort(LV2_Handle handle,
uint32_t port, void *location)
#endif
2007-11-06 21:41:16 +00:00
{
RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
float **ports[PortCountStereo] = {
&shifter->m_latency,
&shifter->m_cents,
&shifter->m_semitones,
&shifter->m_octaves,
&shifter->m_crispness,
2008-06-09 20:46:37 +00:00
&shifter->m_formant,
&shifter->m_wetDry,
&shifter->m_input[0],
2007-11-06 21:41:16 +00:00
&shifter->m_output[0],
&shifter->m_input[1],
&shifter->m_output[1]
};
2008-07-04 19:31:23 +00:00
if (shifter->m_channels == 1) {
if (port >= PortCountMono) return;
} else {
if (port >= PortCountStereo) return;
}
2007-11-06 21:41:16 +00:00
*ports[port] = (float *)location;
2008-07-04 14:19:32 +00:00
if (shifter->m_latency) {
*(shifter->m_latency) = shifter->getLatency();
}
}
2022-01-07 13:33:18 +00:00
#ifdef RB_PLUGIN_LADSPA
void
RubberBandPitchShifter::activate(LADSPA_Handle handle)
#else
void
RubberBandPitchShifter::activate(LV2_Handle handle)
#endif
{
2022-01-07 13:33:18 +00:00
RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
shifter->activateImpl();
2007-11-06 21:41:16 +00:00
}
2022-01-07 13:33:18 +00:00
#ifdef RB_PLUGIN_LADSPA
2007-11-06 21:41:16 +00:00
void
2022-01-07 13:33:18 +00:00
RubberBandPitchShifter::run(LADSPA_Handle handle, unsigned long samples)
#else
void
RubberBandPitchShifter::run(LV2_Handle handle, uint32_t samples)
#endif
2007-11-06 21:41:16 +00:00
{
RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
2022-01-07 13:33:18 +00:00
shifter->runImpl(samples);
}
#ifdef RB_PLUGIN_LADSPA
void
RubberBandPitchShifter::deactivate(LADSPA_Handle handle)
#else
void
RubberBandPitchShifter::deactivate(LV2_Handle handle)
#endif
{
activate(handle); // both functions just reset the plugin
}
#ifdef RB_PLUGIN_LADSPA
void
RubberBandPitchShifter::cleanup(LADSPA_Handle handle)
#else
void
RubberBandPitchShifter::cleanup(LV2_Handle handle)
#endif
{
delete (RubberBandPitchShifter *)handle;
}
int
RubberBandPitchShifter::getLatency() const
{
return m_reserve;
2008-07-04 14:19:32 +00:00
}
void
RubberBandPitchShifter::activateImpl()
{
updateRatio();
m_prevRatio = m_ratio;
m_stretcher->reset();
m_stretcher->setPitchScale(m_ratio);
2008-07-04 19:31:23 +00:00
for (size_t c = 0; c < m_channels; ++c) {
2008-07-04 14:19:32 +00:00
m_outputBuffer[c]->reset();
}
for (size_t c = 0; c < m_channels; ++c) {
m_delayMixBuffer[c]->reset();
m_delayMixBuffer[c]->zero(getLatency());
}
for (size_t c = 0; c < m_channels; ++c) {
2021-05-14 15:09:28 +01:00
for (size_t i = 0; i < m_bufsize; ++i) {
m_scratch[c][i] = 0.f;
}
}
2008-07-06 19:24:53 +00:00
m_minfill = 0;
2021-05-14 15:09:28 +01:00
m_stretcher->process(m_scratch, m_reserve, false);
2007-11-06 21:41:16 +00:00
}
void
RubberBandPitchShifter::updateRatio()
{
2008-07-04 14:19:32 +00:00
double oct = (m_octaves ? *m_octaves : 0.0);
oct += (m_semitones ? *m_semitones : 0.0) / 12;
oct += (m_cents ? *m_cents : 0.0) / 1200;
2007-11-06 21:41:16 +00:00
m_ratio = pow(2.0, oct);
}
void
RubberBandPitchShifter::updateCrispness()
{
if (!m_crispness) return;
int c = lrintf(*m_crispness);
if (c == m_currentCrispness) return;
if (c < 0 || c > 3) return;
RubberBandStretcher *s = m_stretcher;
switch (c) {
case 0:
s->setPhaseOption(RubberBandStretcher::OptionPhaseIndependent);
s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
break;
case 1:
s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
break;
case 2:
s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsMixed);
break;
case 3:
s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp);
break;
}
m_currentCrispness = c;
}
2008-06-09 20:46:37 +00:00
void
RubberBandPitchShifter::updateFormant()
{
if (!m_formant) return;
bool f = (*m_formant > 0.5f);
if (f == m_currentFormant) return;
RubberBandStretcher *s = m_stretcher;
s->setFormantOption(f ?
RubberBandStretcher::OptionFormantPreserved :
RubberBandStretcher::OptionFormantShifted);
m_currentFormant = f;
}
2007-11-06 21:41:16 +00:00
void
2022-01-07 13:33:18 +00:00
RubberBandPitchShifter::runImpl(uint32_t insamples)
2008-07-04 14:19:32 +00:00
{
for (size_t c = 0; c < m_channels; ++c) {
m_delayMixBuffer[c]->write(m_input[c], insamples);
}
2022-01-07 13:33:18 +00:00
size_t offset = 0;
2008-07-04 14:19:32 +00:00
// We have to break up the input into chunks like this because
// insamples could be arbitrarily large and our output buffer is
// of limited size
while (offset < insamples) {
2022-01-07 13:33:18 +00:00
size_t block = m_blockSize;
if (offset + block > insamples) {
block = insamples - offset;
}
2008-07-04 14:19:32 +00:00
runImpl(block, offset);
offset += block;
}
2022-01-07 13:33:18 +00:00
float mix = 0.0;
if (m_wetDry) mix = *m_wetDry;
2022-01-07 13:33:18 +00:00
for (size_t c = 0; c < m_channels; ++c) {
if (mix > 0.0) {
for (size_t i = 0; i < insamples; ++i) {
float dry = m_delayMixBuffer[c]->readOne();
m_output[c][i] *= (1.0 - mix);
m_output[c][i] += dry * mix;
}
2022-01-07 13:33:18 +00:00
} else {
m_delayMixBuffer[c]->skip(insamples);
}
}
2008-07-04 14:19:32 +00:00
}
void
2022-01-07 13:33:18 +00:00
RubberBandPitchShifter::runImpl(uint32_t insamples, uint32_t offset)
2007-11-06 21:41:16 +00:00
{
updateRatio();
if (m_ratio != m_prevRatio) {
m_stretcher->setPitchScale(m_ratio);
m_prevRatio = m_ratio;
}
2007-11-06 21:41:16 +00:00
if (m_latency) {
*m_latency = getLatency();
2007-11-06 21:41:16 +00:00
}
updateCrispness();
2008-06-09 20:46:37 +00:00
updateFormant();
2008-07-04 14:19:32 +00:00
const int samples = insamples;
2007-11-06 21:41:16 +00:00
int processed = 0;
size_t outTotal = 0;
while (processed < samples) {
2008-07-04 14:19:32 +00:00
// never feed more than the minimum necessary number of
// samples at a time; ensures nothing will overflow internally
// and we don't need to call setMaxProcessSize
2007-11-06 21:41:16 +00:00
int toCauseProcessing = m_stretcher->getSamplesRequired();
2008-07-06 19:24:53 +00:00
int inchunk = min(samples - processed, toCauseProcessing);
2022-01-07 13:33:18 +00:00
2007-11-06 21:41:16 +00:00
for (size_t c = 0; c < m_channels; ++c) {
2022-01-07 13:33:18 +00:00
m_inptrs[c] = &(m_input[c][offset + processed]);
2007-11-06 21:41:16 +00:00
}
2022-01-07 13:33:18 +00:00
m_stretcher->process(m_inptrs, inchunk, false);
2007-11-06 21:41:16 +00:00
processed += inchunk;
int avail = m_stretcher->available();
int writable = m_outputBuffer[0]->getWriteSpace();
int outchunk = avail;
if (outchunk > writable) {
cerr << "RubberBandPitchShifter::runImpl: buffer is not large enough: size = " << m_outputBuffer[0]->getSize() << ", chunk = " << outchunk << ", space = " << writable << " (buffer contains " << m_outputBuffer[0]->getReadSpace() << " unread)" << endl;
outchunk = writable;
}
2007-11-06 21:41:16 +00:00
size_t actual = m_stretcher->retrieve(m_scratch, outchunk);
outTotal += actual;
for (size_t c = 0; c < m_channels; ++c) {
m_outputBuffer[c]->write(m_scratch[c], actual);
2007-11-06 21:41:16 +00:00
}
}
for (size_t c = 0; c < m_channels; ++c) {
2008-07-04 14:19:32 +00:00
int toRead = m_outputBuffer[c]->getReadSpace();
if (toRead < samples && c == 0) {
2008-07-06 19:24:53 +00:00
cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << endl;
2007-11-06 21:41:16 +00:00
}
2008-07-06 19:24:53 +00:00
int chunk = min(toRead, samples);
2008-07-04 14:19:32 +00:00
m_outputBuffer[c]->read(&(m_output[c][offset]), chunk);
}
2008-07-06 19:24:53 +00:00
2021-05-14 15:09:28 +01:00
size_t fill = m_outputBuffer[0]->getReadSpace();
if (fill < m_minfill || m_minfill == 0) {
m_minfill = fill;
2021-05-14 15:09:28 +01:00
// cerr << "minfill = " << m_minfill << endl;
2008-07-06 19:24:53 +00:00
}
2007-11-06 21:41:16 +00:00
}