* Fix under/overruns in ladspa plugin
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
|
||||
CXX := @CXX@
|
||||
#CXXFLAGS := -DHAVE_FFTW3 -DFFTW_DOUBLE_ONLY -DNO_THREAD_CHECKS @CXXFLAGS@ @SRC_CFLAGS@ @SNDFILE_CFLAGS@ @FFTW_CFLAGS@ @Vamp_CFLAGS@ -Irubberband -Isrc $(OPTFLAGS)
|
||||
OPTFLAGS := -O3 -ffast-math -ftree-vectorize -ftree-vect-loop-version -march=pentium4 -msse -msse2
|
||||
CXXFLAGS := -DHAVE_FFTW3 -DFFTW_DOUBLE_ONLY -DNO_THREAD_CHECKS @CXXFLAGS@ @SRC_CFLAGS@ @SNDFILE_CFLAGS@ @FFTW_CFLAGS@ @Vamp_CFLAGS@ -Irubberband -Isrc $(OPTFLAGS)
|
||||
CFLAGS := @CFLAGS@ $(OPTFLAGS)
|
||||
LDFLAGS := @LDFLAGS@ -lpthread $(LDFLAGS)
|
||||
|
||||
@@ -65,6 +65,7 @@ protected:
|
||||
SRC_STATE *m_src;
|
||||
float *m_iin;
|
||||
float *m_iout;
|
||||
float m_lastRatio;
|
||||
int m_channels;
|
||||
int m_iinsize;
|
||||
int m_ioutsize;
|
||||
@@ -76,6 +77,7 @@ D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
|
||||
m_src(0),
|
||||
m_iin(0),
|
||||
m_iout(0),
|
||||
m_lastRatio(1.f),
|
||||
m_channels(channels),
|
||||
m_iinsize(0),
|
||||
m_ioutsize(0),
|
||||
@@ -105,6 +107,8 @@ D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
|
||||
m_iin = (float *)malloc(m_iinsize * sizeof(float));
|
||||
m_iout = (float *)malloc(m_ioutsize * sizeof(float));
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
D_SRC::~D_SRC()
|
||||
@@ -171,6 +175,8 @@ D_SRC::resample(const float *const R__ *const R__ in,
|
||||
}
|
||||
}
|
||||
|
||||
m_lastRatio = ratio;
|
||||
|
||||
return data.output_frames_gen;
|
||||
}
|
||||
|
||||
|
||||
@@ -195,6 +195,9 @@ StretchCalculator::calculateSingle(double ratio,
|
||||
|
||||
m_prevDf = df;
|
||||
|
||||
bool ratioChanged = (ratio != m_prevRatio);
|
||||
m_prevRatio = ratio;
|
||||
|
||||
if (isTransient && m_transientAmnesty == 0) {
|
||||
if (m_debugLevel > 1) {
|
||||
std::cerr << "StretchCalculator::calculateSingle: transient"
|
||||
@@ -210,9 +213,8 @@ StretchCalculator::calculateSingle(double ratio,
|
||||
return -int(increment);
|
||||
}
|
||||
|
||||
if (m_prevRatio != ratio) {
|
||||
if (ratioChanged) {
|
||||
m_recovery = m_divergence / ((m_sampleRate / 10.0) / increment);
|
||||
m_prevRatio = ratio;
|
||||
}
|
||||
|
||||
if (m_transientAmnesty > 0) --m_transientAmnesty;
|
||||
|
||||
@@ -236,9 +236,27 @@ RubberBandStretcher::Impl::setPitchScale(double fs)
|
||||
}
|
||||
|
||||
if (fs == m_pitchScale) return;
|
||||
|
||||
bool was1 = (m_pitchScale == 1.f);
|
||||
bool rbs = resampleBeforeStretching();
|
||||
|
||||
m_pitchScale = fs;
|
||||
|
||||
reconfigure();
|
||||
|
||||
if (!(m_options & OptionPitchHighConsistency) &&
|
||||
(was1 || resampleBeforeStretching() != rbs) &&
|
||||
m_pitchScale != 1.f) {
|
||||
|
||||
cerr << "reset resampler" << endl;
|
||||
|
||||
// resampling mode has changed
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
if (m_channelData[c]->resampler) {
|
||||
m_channelData[c]->resampler->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
|
||||
@@ -1042,7 +1042,6 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
|
||||
1.0 / m_pitchScale,
|
||||
last);
|
||||
|
||||
|
||||
writeOutput(*cd.outbuf, cd.resamplebuf,
|
||||
outframes, cd.outCount, theoreticalOut);
|
||||
|
||||
|
||||
@@ -80,27 +80,27 @@ RubberBandPitchShifter::portsStereo[PortCountStereo] =
|
||||
const LADSPA_PortRangeHint
|
||||
RubberBandPitchShifter::hintsMono[PortCountMono] =
|
||||
{
|
||||
{ 0, 0, 0 },
|
||||
{ LADSPA_HINT_DEFAULT_0 |
|
||||
{ 0, 0, 0 }, // latency
|
||||
{ LADSPA_HINT_DEFAULT_0 | // cents
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE,
|
||||
-100.0, 100.0 },
|
||||
{ LADSPA_HINT_DEFAULT_0 |
|
||||
{ LADSPA_HINT_DEFAULT_0 | // semitones
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE |
|
||||
LADSPA_HINT_INTEGER,
|
||||
-12.0, 12.0 },
|
||||
{ LADSPA_HINT_DEFAULT_0 |
|
||||
{ LADSPA_HINT_DEFAULT_0 | // octaves
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE |
|
||||
LADSPA_HINT_INTEGER,
|
||||
-4.0, 4.0 },
|
||||
{ LADSPA_HINT_DEFAULT_MAXIMUM |
|
||||
-3.0, 3.0 },
|
||||
{ LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE |
|
||||
LADSPA_HINT_INTEGER,
|
||||
0.0, 3.0 },
|
||||
{ LADSPA_HINT_DEFAULT_0 |
|
||||
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE |
|
||||
LADSPA_HINT_TOGGLED,
|
||||
@@ -112,27 +112,27 @@ RubberBandPitchShifter::hintsMono[PortCountMono] =
|
||||
const LADSPA_PortRangeHint
|
||||
RubberBandPitchShifter::hintsStereo[PortCountStereo] =
|
||||
{
|
||||
{ 0, 0, 0 },
|
||||
{ LADSPA_HINT_DEFAULT_0 |
|
||||
{ 0, 0, 0 }, // latency
|
||||
{ LADSPA_HINT_DEFAULT_0 | // cents
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE,
|
||||
-100.0, 100.0 },
|
||||
{ LADSPA_HINT_DEFAULT_0 |
|
||||
{ LADSPA_HINT_DEFAULT_0 | // semitones
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE |
|
||||
LADSPA_HINT_INTEGER,
|
||||
-12.0, 12.0 },
|
||||
{ LADSPA_HINT_DEFAULT_0 |
|
||||
{ LADSPA_HINT_DEFAULT_0 | // octaves
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE |
|
||||
LADSPA_HINT_INTEGER,
|
||||
-4.0, 4.0 },
|
||||
{ LADSPA_HINT_DEFAULT_MAXIMUM |
|
||||
-3.0, 3.0 },
|
||||
{ LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE |
|
||||
LADSPA_HINT_INTEGER,
|
||||
0.0, 3.0 },
|
||||
{ LADSPA_HINT_DEFAULT_0 |
|
||||
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
|
||||
LADSPA_HINT_BOUNDED_BELOW |
|
||||
LADSPA_HINT_BOUNDED_ABOVE |
|
||||
LADSPA_HINT_TOGGLED,
|
||||
@@ -213,32 +213,29 @@ RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels)
|
||||
m_prevRatio(1.0),
|
||||
m_currentCrispness(-1),
|
||||
m_currentFormant(false),
|
||||
m_extraLatency(128),
|
||||
m_blockSize(1024),
|
||||
m_reserve(1024),
|
||||
m_stretcher(new RubberBandStretcher
|
||||
(sampleRate, channels,
|
||||
RubberBandStretcher::OptionProcessRealTime)),
|
||||
RubberBandStretcher::OptionProcessRealTime |
|
||||
RubberBandStretcher::OptionPitchHighConsistency)),
|
||||
m_sampleRate(sampleRate),
|
||||
m_channels(channels)
|
||||
{
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
|
||||
m_input[c] = 0;
|
||||
m_output[c] = 0;
|
||||
//!!! size must be at least max process size plus m_extraLatency:
|
||||
m_outputBuffer[c] = new RingBuffer<float>(8092); //!!!
|
||||
m_outputBuffer[c]->zero(m_extraLatency);
|
||||
//!!! size must be at least max process size:
|
||||
m_scratch[c] = new float[16384];//!!!
|
||||
for (int i = 0; i < 16384; ++i) {
|
||||
m_scratch[c][i] = 0.f;
|
||||
}
|
||||
}
|
||||
int reqd = m_stretcher->getSamplesRequired();
|
||||
m_stretcher->process(m_scratch, reqd, false);
|
||||
int avail = m_stretcher->available();
|
||||
std::cerr << "construction: reqd = " << reqd << ", available = " << avail << std::endl;
|
||||
if (avail > 0) {
|
||||
m_stretcher->retrieve(m_scratch, avail);
|
||||
|
||||
int bufsize = m_blockSize + m_reserve + 8192;
|
||||
|
||||
m_outputBuffer[c] = new RingBuffer<float>(bufsize);
|
||||
|
||||
m_scratch[c] = new float[bufsize];
|
||||
for (int i = 0; i < bufsize; ++i) m_scratch[c][i] = 0.f;
|
||||
}
|
||||
|
||||
activateImpl();
|
||||
}
|
||||
|
||||
RubberBandPitchShifter::~RubberBandPitchShifter()
|
||||
@@ -281,16 +278,40 @@ RubberBandPitchShifter::connectPort(LADSPA_Handle handle,
|
||||
};
|
||||
|
||||
*ports[port] = (float *)location;
|
||||
|
||||
if (shifter->m_latency) {
|
||||
*(shifter->m_latency) =
|
||||
float(shifter->m_stretcher->getLatency() + shifter->m_reserve);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandPitchShifter::activate(LADSPA_Handle handle)
|
||||
{
|
||||
RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
|
||||
shifter->updateRatio();
|
||||
shifter->m_prevRatio = shifter->m_ratio;
|
||||
shifter->m_stretcher->reset();
|
||||
shifter->m_stretcher->setPitchScale(shifter->m_ratio);
|
||||
shifter->activateImpl();
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandPitchShifter::activateImpl()
|
||||
{
|
||||
updateRatio();
|
||||
m_prevRatio = m_ratio;
|
||||
m_stretcher->reset();
|
||||
m_stretcher->setPitchScale(m_ratio);
|
||||
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
m_outputBuffer[c]->reset();
|
||||
m_outputBuffer[c]->zero(m_reserve);
|
||||
}
|
||||
|
||||
// prime stretcher
|
||||
int reqd = m_stretcher->getSamplesRequired();
|
||||
m_stretcher->process(m_scratch, reqd, false);
|
||||
int avail = m_stretcher->available();
|
||||
if (avail > 0) {
|
||||
m_stretcher->retrieve(m_scratch, avail);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -303,9 +324,9 @@ RubberBandPitchShifter::run(LADSPA_Handle handle, unsigned long samples)
|
||||
void
|
||||
RubberBandPitchShifter::updateRatio()
|
||||
{
|
||||
double oct = *m_octaves;
|
||||
oct += *m_semitones / 12;
|
||||
oct += *m_cents / 1200;
|
||||
double oct = (m_octaves ? *m_octaves : 0.0);
|
||||
oct += (m_semitones ? *m_semitones : 0.0) / 12;
|
||||
oct += (m_cents ? *m_cents : 0.0) / 1200;
|
||||
m_ratio = pow(2.0, oct);
|
||||
}
|
||||
|
||||
@@ -360,10 +381,30 @@ RubberBandPitchShifter::updateFormant()
|
||||
|
||||
void
|
||||
RubberBandPitchShifter::runImpl(unsigned long insamples)
|
||||
{
|
||||
unsigned long offset = 0;
|
||||
|
||||
// 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) {
|
||||
|
||||
unsigned long block = (unsigned long)m_blockSize;
|
||||
if (block > insamples) block = insamples;
|
||||
|
||||
runImpl(block, offset);
|
||||
|
||||
offset += block;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset)
|
||||
{
|
||||
// std::cerr << "RubberBandPitchShifter::runImpl(" << insamples << ")" << std::endl;
|
||||
|
||||
static int incount = 0, outcount = 0;
|
||||
// static int incount = 0, outcount = 0;
|
||||
|
||||
updateRatio();
|
||||
if (m_ratio != m_prevRatio) {
|
||||
@@ -372,43 +413,51 @@ RubberBandPitchShifter::runImpl(unsigned long insamples)
|
||||
}
|
||||
|
||||
if (m_latency) {
|
||||
*m_latency = float(m_stretcher->getLatency() + m_extraLatency);
|
||||
*m_latency = float(m_stretcher->getLatency() + m_reserve);
|
||||
// std::cerr << "latency = " << *m_latency << std::endl;
|
||||
}
|
||||
|
||||
updateCrispness();
|
||||
updateFormant();
|
||||
|
||||
int samples = insamples;
|
||||
const int samples = insamples;
|
||||
int processed = 0;
|
||||
size_t outTotal = 0;
|
||||
|
||||
float *ptrs[2];
|
||||
|
||||
// We have to break up the input into chunks like this because
|
||||
// insamples could be arbitrarily large
|
||||
if (m_outputBuffer[0]->getReadSpace() < m_reserve) {
|
||||
m_stretcher->setTimeRatio(1.1); // fill up temporarily
|
||||
} else if (m_outputBuffer[0]->getReadSpace() > 8192) {
|
||||
m_stretcher->setTimeRatio(0.9); // reduce temporarily
|
||||
} else {
|
||||
m_stretcher->setTimeRatio(1.0);
|
||||
}
|
||||
|
||||
while (processed < samples) {
|
||||
|
||||
//!!! size_t:
|
||||
// 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
|
||||
|
||||
int toCauseProcessing = m_stretcher->getSamplesRequired();
|
||||
// std::cout << "to-cause: " << toCauseProcessing << ", remain = " << samples - processed;
|
||||
int inchunk = std::min(samples - processed, toCauseProcessing);
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
ptrs[c] = &(m_input[c][processed]);
|
||||
ptrs[c] = &(m_input[c][offset + processed]);
|
||||
}
|
||||
m_stretcher->process(ptrs, inchunk, false);
|
||||
processed += inchunk;
|
||||
incount += inchunk; //!!!
|
||||
|
||||
int avail = m_stretcher->available();
|
||||
int writable = m_outputBuffer[0]->getWriteSpace();
|
||||
int outchunk = std::min(avail, writable);
|
||||
size_t actual = m_stretcher->retrieve(m_scratch, outchunk);
|
||||
outTotal += actual;
|
||||
outcount += actual;
|
||||
|
||||
// std::cout << ", avail: " << avail << ", outchunk = " << outchunk;
|
||||
// incount += inchunk;
|
||||
// outcount += actual;
|
||||
|
||||
// std::cout << "avail: " << avail << ", outchunk = " << outchunk;
|
||||
// if (actual != outchunk) std::cout << " (" << actual << ")";
|
||||
// std::cout << std::endl;
|
||||
|
||||
@@ -421,27 +470,14 @@ RubberBandPitchShifter::runImpl(unsigned long insamples)
|
||||
m_outputBuffer[c]->write(m_scratch[c], outchunk);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "in: " << incount << ", out: " << outcount << ", loss: " << incount - outcount << std::endl;
|
||||
|
||||
// std::cout << "processed = " << processed << " in, " << outTotal << " out" << ", fill = " << m_outputBuffer[0]->getReadSpace() << " of " << m_outputBuffer[0]->getSize() << std::endl;
|
||||
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
int avail = m_outputBuffer[c]->getReadSpace();
|
||||
// std::cout << "avail: " << avail << std::endl;
|
||||
if (avail < samples && c == 0) {
|
||||
std::cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << avail << std::endl;
|
||||
int toRead = m_outputBuffer[c]->getReadSpace();
|
||||
if (toRead < samples && c == 0) {
|
||||
std::cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << std::endl;
|
||||
}
|
||||
int chunk = std::min(avail, samples);
|
||||
// std::cout << "out chunk: " << chunk << std::endl;
|
||||
m_outputBuffer[c]->read(m_output[c], chunk);
|
||||
}
|
||||
|
||||
static int minr = -1;
|
||||
int avail = m_outputBuffer[0]->getReadSpace();
|
||||
if (minr == -1 || (avail >= 0 && avail < minr)) {
|
||||
std::cerr << "RubberBandPitchShifter::runImpl: new min remaining " << avail << " from " << minr << std::endl;
|
||||
minr = avail;
|
||||
int chunk = std::min(toRead, samples);
|
||||
m_outputBuffer[c]->read(&(m_output[c][offset]), chunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,9 @@ protected:
|
||||
static void deactivate(LADSPA_Handle);
|
||||
static void cleanup(LADSPA_Handle);
|
||||
|
||||
void activateImpl();
|
||||
void runImpl(unsigned long);
|
||||
void runImpl(unsigned long, unsigned long offset);
|
||||
void updateRatio();
|
||||
void updateCrispness();
|
||||
void updateFormant();
|
||||
@@ -85,7 +87,8 @@ protected:
|
||||
int m_currentCrispness;
|
||||
bool m_currentFormant;
|
||||
|
||||
size_t m_extraLatency;
|
||||
size_t m_blockSize;
|
||||
size_t m_reserve;
|
||||
|
||||
RubberBand::RubberBandStretcher *m_stretcher;
|
||||
RubberBand::RingBuffer<float> *m_outputBuffer[2];
|
||||
|
||||
4
src/ladspa/ladspa-plugin.map
Normal file
4
src/ladspa/ladspa-plugin.map
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
global: ladspa_descriptor;
|
||||
local: *;
|
||||
};
|
||||
4
src/vamp/vamp-plugin.map
Normal file
4
src/vamp/vamp-plugin.map
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
global: vampGetPluginDescriptor;
|
||||
local: *;
|
||||
};
|
||||
Reference in New Issue
Block a user