* Some code rearrangement

* Threading fixes (corrections to condition usage)
* Avoid a potential hang when faced with some peculiar stretch factors
* More modular calls out to vectorizable functions
* Solaris build fixes
* Bump version number
This commit is contained in:
Chris Cannam
2009-09-17 13:01:21 +00:00
parent aa5f708467
commit abf577ee9d
60 changed files with 1083 additions and 984 deletions

View File

@@ -1,44 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include "AudioCurve.h"
#include <iostream>
using namespace std;
namespace RubberBand
{
AudioCurve::AudioCurve(size_t sampleRate, size_t windowSize) :
m_sampleRate(sampleRate),
m_windowSize(windowSize)
{
}
AudioCurve::~AudioCurve()
{
}
float
AudioCurve::processDouble(const double *R__ mag, size_t increment)
{
cerr << "AudioCurve::processDouble: WARNING: Using inefficient and lossy conversion for AudioCurve::process(float)" << endl;
float *tmp = new float[m_windowSize];
for (int i = 0; i < int(m_windowSize); ++i) tmp[i] = float(mag[i]);
float df = process(tmp, increment);
delete[] tmp;
return df;
}
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as

View File

@@ -1,83 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include "SpectralDifferenceAudioCurve.h"
namespace RubberBand
{
SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize)
{
m_prevMag = new float[m_windowSize/2 + 1];
for (size_t i = 0; i <= m_windowSize/2; ++i) {
m_prevMag[i] = 0.f;
}
}
SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve()
{
delete[] m_prevMag;
}
void
SpectralDifferenceAudioCurve::reset()
{
for (size_t i = 0; i <= m_windowSize/2; ++i) {
m_prevMag[i] = 0;
}
}
void
SpectralDifferenceAudioCurve::setWindowSize(size_t newSize)
{
delete[] m_prevMag;
m_windowSize = newSize;
m_prevMag = new float[m_windowSize/2 + 1];
reset();
}
float
SpectralDifferenceAudioCurve::process(const float *R__ mag, size_t increment)
{
float result = 0.0;
for (size_t n = 0; n <= m_windowSize / 2; ++n) {
result += sqrtf(fabsf((mag[n] * mag[n]) -
(m_prevMag[n] * m_prevMag[n])));
m_prevMag[n] = mag[n];
}
return result;
}
float
SpectralDifferenceAudioCurve::processDouble(const double *R__ mag, size_t increment)
{
float result = 0.0;
for (size_t n = 0; n <= m_windowSize / 2; ++n) {
result += sqrtf(fabsf((mag[n] * mag[n]) -
(m_prevMag[n] * m_prevMag[n])));
m_prevMag[n] = (float)mag[n];
}
return result;
}
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -21,7 +21,7 @@
#include <cassert>
#include <algorithm>
#include "sysutils.h"
#include "system/sysutils.h"
namespace RubberBand
{
@@ -659,7 +659,12 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
maxDf = 0;
float adj = 0;
while (!acceptableSquashRange) {
const int acceptableIterations = 10;
int iteration = 0;
while (!acceptableSquashRange && iteration < acceptableIterations) {
++iteration;
acceptableSquashRange = true;
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
@@ -682,21 +687,22 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
int extremeIncrement = m_increment + lrint((toAllot * maxDisplacement) / totalDisplacement);
if (ratio < 1.0) {
if (extremeIncrement > lrint(ceil(m_increment * ratio))) {
std::cerr << "ERROR: extreme increment " << extremeIncrement << " > " << m_increment * ratio << " (this should not happen)" << std::endl;
std::cerr << "WARNING: extreme increment " << extremeIncrement << " > " << m_increment * ratio << std::endl;
} else if (extremeIncrement < (m_increment * ratio) / 2) {
if (m_debugLevel > 0) {
std::cerr << "WARNING: extreme increment " << extremeIncrement << " < " << (m_increment * ratio) / 2 << std::endl;
std::cerr << "NOTE: extreme increment " << extremeIncrement << " < " << (m_increment * ratio) / 2 << ", adjusting" << std::endl;
}
acceptableSquashRange = false;
}
} else {
if (extremeIncrement > m_increment * ratio * 2) {
if (m_debugLevel > 0) {
std::cerr << "WARNING: extreme increment " << extremeIncrement << " > " << m_increment * ratio * 2 << std::endl;
std::cerr << "NOTE: extreme increment " << extremeIncrement << " > " << m_increment * ratio * 2 << ", adjusting" << std::endl;
}
acceptableSquashRange = false;
} else if (extremeIncrement < lrint(floor(m_increment * ratio))) {
std::cerr << "ERROR: extreme increment " << extremeIncrement << " < " << m_increment * ratio << " (I thought this couldn't happen?)" << std::endl;
std::cerr << "WARNING: extreme increment " << extremeIncrement << " < " << m_increment * ratio << std::endl;
}
}
@@ -708,6 +714,13 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
}
}
if (!acceptableSquashRange) {
std::cerr << "WARNING: No acceptable displacement adjustment found, using defaults:\nthis region will probably sound bad" << std::endl;
adj = 0;
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
adj);
}
for (size_t i = 0; i < df.size(); ++i) {
double displacement = maxDf - df[i];

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -14,8 +14,9 @@
#include "StretcherChannelData.h"
#include "Resampler.h"
#include "dsp/Resampler.h"
#include "system/Allocators.h"
namespace RubberBand
{
@@ -64,19 +65,19 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
inbuf = new RingBuffer<float>(maxSize);
outbuf = new RingBuffer<float>(outbufSize);
mag = allocDouble(realSize);
phase = allocDouble(realSize);
prevPhase = allocDouble(realSize);
prevError = allocDouble(realSize);
unwrappedPhase = allocDouble(realSize);
envelope = allocDouble(realSize);
mag = allocate<double>(realSize);
phase = allocate<double>(realSize);
prevPhase = allocate<double>(realSize);
prevError = allocate<double>(realSize);
unwrappedPhase = allocate<double>(realSize);
envelope = allocate<double>(realSize);
freqPeak = new size_t[realSize];
fltbuf = allocFloat(maxSize);
fltbuf = allocate<float>(maxSize);
accumulator = allocFloat(maxSize);
windowAccumulator = allocFloat(maxSize);
accumulator = allocate<float>(maxSize);
windowAccumulator = allocate<float>(maxSize);
for (std::set<size_t>::const_iterator i = windowSizes.begin();
i != windowSizes.end(); ++i) {
@@ -122,7 +123,7 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
// std::cerr << "ChannelData::setWindowSize(" << windowSize << ") [from " << oldSize << "]" << std::endl;
if (oldSize >= windowSize) {
if (oldSize >= windowSize) { //!!! shurely >= realSize?
// no need to reallocate buffers, just reselect fft
@@ -170,32 +171,33 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
// We don't want to preserve data in these arrays
mag = allocDouble(mag, realSize);
phase = allocDouble(phase, realSize);
prevPhase = allocDouble(prevPhase, realSize);
prevError = allocDouble(prevError, realSize);
unwrappedPhase = allocDouble(unwrappedPhase, realSize);
envelope = allocDouble(envelope, realSize);
mag = reallocate<double>(mag, oldSize, realSize);
phase = reallocate<double>(phase, oldSize, realSize);
prevPhase = reallocate<double>(prevPhase, oldSize, realSize);
prevError = reallocate<double>(prevError, oldSize, realSize);
unwrappedPhase = reallocate<double>(unwrappedPhase, oldSize, realSize);
envelope = reallocate<double>(envelope, oldSize, realSize);
delete[] freqPeak;
freqPeak = new size_t[realSize];
fltbuf = allocFloat(fltbuf, windowSize);
deallocate(fltbuf);
fltbuf = allocate<float>(windowSize);
// But we do want to preserve data in these
float *newAcc = allocFloat(windowSize);
float *newAcc = allocate<float>(windowSize);
for (size_t i = 0; i < oldSize; ++i) newAcc[i] = accumulator[i];
v_copy(newAcc, accumulator, oldSize);
freeFloat(accumulator);
deallocate(accumulator);
accumulator = newAcc;
newAcc = allocFloat(windowSize);
newAcc = allocate<float>(windowSize);
for (size_t i = 0; i < oldSize; ++i) newAcc[i] = windowAccumulator[i];
v_copy(newAcc, windowAccumulator, oldSize);
freeFloat(windowAccumulator);
deallocate(windowAccumulator);
windowAccumulator = newAcc;
//!!! and resampler?
@@ -243,7 +245,7 @@ RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize)
void
RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz)
{
resamplebuf = allocFloat(resamplebuf, sz);
resamplebuf = reallocate<float>(resamplebuf, resamplebufSize, sz);
resamplebufSize = sz;
}
@@ -251,21 +253,21 @@ RubberBandStretcher::Impl::ChannelData::~ChannelData()
{
delete resampler;
freeFloat(resamplebuf);
deallocate(resamplebuf);
delete inbuf;
delete outbuf;
freeDouble(mag);
freeDouble(phase);
freeDouble(prevPhase);
freeDouble(prevError);
freeDouble(unwrappedPhase);
freeDouble(envelope);
deallocate(mag);
deallocate(phase);
deallocate(prevPhase);
deallocate(prevError);
deallocate(unwrappedPhase);
deallocate(envelope);
delete[] freqPeak;
freeFloat(accumulator);
freeFloat(windowAccumulator);
freeFloat(fltbuf);
deallocate(accumulator);
deallocate(windowAccumulator);
deallocate(fltbuf);
for (std::map<size_t, FFT *>::iterator i = ffts.begin();
i != ffts.end(); ++i) {

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -21,11 +21,11 @@
//#define EXPERIMENT 1
namespace RubberBand { class Resampler; }
namespace RubberBand
{
class Resampler;
class RubberBandStretcher::Impl::ChannelData
{
public:

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -13,21 +13,30 @@
*/
#include "StretcherImpl.h"
#include "PercussiveAudioCurve.h"
#include "HighFrequencyAudioCurve.h"
#include "SpectralDifferenceAudioCurve.h"
#include "SilentAudioCurve.h"
#include "ConstantAudioCurve.h"
#include "dsp/PercussiveAudioCurve.h"
#include "dsp/HighFrequencyAudioCurve.h"
#include "dsp/SpectralDifferenceAudioCurve.h"
#include "dsp/SilentAudioCurve.h"
#include "dsp/ConstantAudioCurve.h"
#include "dsp/Resampler.h"
#include "StretchCalculator.h"
#include "StretcherChannelData.h"
#include "Resampler.h"
#include "Profiler.h"
#include "base/Profiler.h"
#ifndef _WIN32
#include <alloca.h>
#endif
#include <cassert>
#include <cmath>
#include <set>
#include <map>
using namespace RubberBand;
using std::cerr;
using std::endl;
using std::vector;
@@ -36,7 +45,6 @@ using std::set;
using std::max;
using std::min;
namespace RubberBand {
const size_t
@@ -48,7 +56,7 @@ RubberBandStretcher::Impl::m_defaultWindowSize = 2048;
int
RubberBandStretcher::Impl::m_defaultDebugLevel = 0;
static bool _initialised = false;
RubberBandStretcher::Impl::Impl(size_t sampleRate,
size_t channels,
@@ -85,6 +93,10 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_freq2(12000),
m_baseWindowSize(m_defaultWindowSize)
{
if (!_initialised) {
system_specific_initialise();
_initialised = true;
}
if (m_debugLevel > 0) {
cerr << "RubberBandStretcher::Impl::Impl: rate = " << m_sampleRate << ", options = " << options << endl;
@@ -844,15 +856,15 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
m_studyFFT->forwardMagnitude(cd.accumulator, cd.fltbuf);
float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment);
float df = m_phaseResetAudioCurve->processFloat(cd.fltbuf, m_increment);
m_phaseResetDf.push_back(df);
// cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: ";
df = m_stretchAudioCurve->process(cd.fltbuf, m_increment);
df = m_stretchAudioCurve->processFloat(cd.fltbuf, m_increment);
m_stretchDf.push_back(df);
df = m_silentAudioCurve->process(cd.fltbuf, m_increment);
df = m_silentAudioCurve->processFloat(cd.fltbuf, m_increment);
bool silent = (df > 0.f);
if (silent && m_debugLevel > 1) {
cerr << "silence found at " << m_inputDuration << endl;
@@ -1111,9 +1123,11 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
i != m_threadSet.end(); ++i) {
(*i)->signalDataAvailable();
}
m_spaceAvailable.lock();
if (!allConsumed) {
m_spaceAvailable.wait(500);
}
m_spaceAvailable.unlock();
/*
} else {
if (!allConsumed) {

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,20 +15,24 @@
#ifndef _RUBBERBAND_STRETCHERIMPL_H_
#define _RUBBERBAND_STRETCHERIMPL_H_
#include "RubberBandStretcher.h"
#include "rubberband/RubberBandStretcher.h"
#include "Window.h"
#include "Thread.h"
#include "RingBuffer.h"
#include "FFT.h"
#include "sysutils.h"
#include "dsp/Window.h"
#include "dsp/FFT.h"
#include "base/RingBuffer.h"
#include "system/Thread.h"
#include "system/sysutils.h"
#include <set>
using namespace RubberBand;
namespace RubberBand { class AudioCurveCalculator; }
namespace RubberBand
{
class AudioCurve;
class StretchCalculator;
class RubberBandStretcher::Impl
@@ -177,9 +181,9 @@ protected:
mutable RingBuffer<int> m_lastProcessOutputIncrements;
mutable RingBuffer<float> m_lastProcessPhaseResetDf;
AudioCurve *m_phaseResetAudioCurve;
AudioCurve *m_stretchAudioCurve;
AudioCurve *m_silentAudioCurve;
AudioCurveCalculator *m_phaseResetAudioCurve;
AudioCurveCalculator *m_stretchAudioCurve;
AudioCurveCalculator *m_silentAudioCurve;
StretchCalculator *m_stretchCalculator;
float m_freq0;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -13,13 +13,21 @@
*/
#include "StretcherImpl.h"
#include "PercussiveAudioCurve.h"
#include "HighFrequencyAudioCurve.h"
#include "ConstantAudioCurve.h"
#include "dsp/PercussiveAudioCurve.h"
#include "dsp/HighFrequencyAudioCurve.h"
#include "dsp/ConstantAudioCurve.h"
#include "StretchCalculator.h"
#include "StretcherChannelData.h"
#include "Resampler.h"
#include "Profiler.h"
#include "dsp/Resampler.h"
#include "base/Profiler.h"
#include "system/VectorOps.h"
#ifndef _WIN32
#include <alloca.h>
#endif
#include <cassert>
#include <cmath>
@@ -27,6 +35,7 @@
#include <map>
#include <deque>
using namespace RubberBand;
using std::cerr;
using std::endl;
@@ -62,14 +71,17 @@ RubberBandStretcher::Impl::ProcessThread::run()
if (last) break;
if (any) m_s->m_spaceAvailable.signal();
if (any) {
m_s->m_spaceAvailable.lock();
m_s->m_spaceAvailable.signal();
m_s->m_spaceAvailable.unlock();
}
m_dataAvailable.lock();
if (!m_s->testInbufReadSpace(m_channel) && !m_abandoning) {
m_dataAvailable.wait(50000); // bounded in case of abandonment
} else {
m_dataAvailable.unlock();
}
m_dataAvailable.unlock();
if (m_abandoning) {
if (m_s->m_debugLevel > 1) {
@@ -81,7 +93,9 @@ RubberBandStretcher::Impl::ProcessThread::run()
bool any = false, last = false;
m_s->processChunks(m_channel, any, last);
m_s->m_spaceAvailable.lock();
m_s->m_spaceAvailable.signal();
m_s->m_spaceAvailable.unlock();
if (m_s->m_debugLevel > 1) {
cerr << "thread " << m_channel << " done" << endl;
@@ -91,7 +105,9 @@ RubberBandStretcher::Impl::ProcessThread::run()
void
RubberBandStretcher::Impl::ProcessThread::signalDataAvailable()
{
m_dataAvailable.lock();
m_dataAvailable.signal();
m_dataAvailable.unlock();
}
void
@@ -454,13 +470,9 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
double *tmp = (double *)alloca(hs * sizeof(double));
for (int i = 0; i < hs; ++i) {
tmp[i] = 0.0;
}
v_zero(tmp, hs);
for (size_t c = 0; c < m_channels; ++c) {
for (int i = 0; i < hs; ++i) {
tmp[i] += m_channelData[c]->mag[i];
}
v_add(tmp, m_channelData[c]->mag, hs);
}
df = m_phaseResetAudioCurve->processDouble(tmp, m_increment);
@@ -630,18 +642,13 @@ RubberBandStretcher::Impl::analyseChunk(size_t channel)
dblbuf[i + bufsiz/2] = tmp;
}
} else {
for (i = 0; i < hs; ++i) {
dblbuf[i] = fltbuf[i + hs];
dblbuf[i + hs] = fltbuf[i];
}
v_convert(dblbuf, fltbuf + hs, hs);
v_convert(dblbuf + hs, fltbuf, hs);
}
cd.fft->forwardPolar(dblbuf, cd.mag, cd.phase);
}
static inline double mod(double x, double y) { return x - (y * floor(x / y)); }
static inline double princarg(double a) { return mod(a + M_PI, -2.0 * M_PI) + M_PI; }
void
RubberBandStretcher::Impl::modifyChunk(size_t channel,
size_t outputIncrement,
@@ -800,14 +807,11 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
const int sz = m_windowSize;
const int hs = m_windowSize/2;
const double denom = sz;
const double factor = 1.0 / sz;
cd.fft->inverseCepstral(mag, dblbuf);
for (int i = 0; i < sz; ++i) {
dblbuf[i] /= denom;
}
v_scale(dblbuf, factor, sz);
const int cutoff = m_sampleRate / 700;
@@ -822,13 +826,8 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
cd.fft->forward(dblbuf, envelope, 0);
for (int i = 0; i <= hs; ++i) {
envelope[i] = exp(envelope[i]);
}
for (int i = 0; i <= hs; ++i) {
mag[i] /= envelope[i];
}
v_exp(envelope, hs + 1);
v_divide(mag, envelope, hs + 1);
if (m_pitchScale > 1.0) {
// scaling up, we want a new envelope that is lower by the pitch factor
@@ -849,9 +848,7 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
}
}
for (int i = 0; i <= hs; ++i) {
mag[i] *= envelope[i];
}
v_multiply(mag, envelope, hs+1);
cd.unchanged = false;
}
@@ -898,36 +895,23 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel)
fltbuf[i] = float(dblbuf[i + offset]);
}
} else {
for (i = 0; i < hs; ++i) {
fltbuf[i] = float(dblbuf[i + hs]);
}
for (i = 0; i < hs; ++i) {
fltbuf[i + hs] = float(dblbuf[i]);
}
v_convert(fltbuf, dblbuf + hs, hs);
v_convert(fltbuf + hs, dblbuf, hs);
}
float denom = float(sz * cd.oversample);
// our ffts produced unscaled results
for (i = 0; i < sz; ++i) {
fltbuf[i] = fltbuf[i] / denom;
}
float factor = 1.f / float(sz * cd.oversample);
v_scale(fltbuf, factor, sz);
}
m_window->cut(fltbuf);
for (i = 0; i < sz; ++i) {
accumulator[i] += fltbuf[i];
}
v_add(accumulator, fltbuf, sz);
cd.accumulatorFill = m_windowSize;
float fixed = m_window->getArea() * 1.5f;
for (i = 0; i < sz; ++i) {
float val = m_window->getValue(i);
windowAccumulator[i] += val * fixed;
}
m_window->add(windowAccumulator, fixed);
}
void
@@ -949,11 +933,7 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
cerr << "writeChunk(" << channel << ", " << shiftIncrement << ", " << last << ")" << endl;
}
for (i = 0; i < si; ++i) {
if (windowAccumulator[i] > 0.f) {
accumulator[i] /= windowAccumulator[i];
}
}
v_divide(accumulator, windowAccumulator, si);
// for exact sample scaling (probably not meaningful if we
// were running in RT mode)
@@ -995,22 +975,12 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
writeOutput(*cd.outbuf, accumulator,
si, cd.outCount, theoreticalOut);
}
v_move(accumulator, accumulator + si, sz - si);
v_zero(accumulator + sz - si, si);
for (i = 0; i < sz - si; ++i) {
accumulator[i] = accumulator[i + si];
}
for (i = sz - si; i < sz; ++i) {
accumulator[i] = 0.0f;
}
for (i = 0; i < sz - si; ++i) {
windowAccumulator[i] = windowAccumulator[i + si];
}
for (i = sz - si; i < sz; ++i) {
windowAccumulator[i] = 0.0f;
}
v_move(windowAccumulator, windowAccumulator + si, sz - si);
v_zero(windowAccumulator + sz - si, si);
if (int(cd.accumulatorFill) > si) {
cd.accumulatorFill -= si;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -171,6 +171,17 @@ Profiler::end()
m_ended = true;
}
#else /* NO_TIMING */
#ifndef NO_TIMING_COMPLETE_NOOP
Profiler::Profiler(const char *) { }
Profiler::~Profiler() { }
void Profiler::end() { }
void Profiler::dump() { }
#endif
#endif
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,7 +15,7 @@
#ifndef _PROFILER_H_
#define _PROFILER_H_
#define NO_TIMING 1
//#define NO_TIMING 1
//#define WANT_TIMING 1
//#define PROFILE_CLOCKS 1
@@ -30,7 +30,7 @@
#ifdef PROFILE_CLOCKS
#include <time.h>
#else
#include "sysutils.h"
#include "system/sysutils.h"
#ifndef _WIN32
#include <sys/time.h>
#endif
@@ -73,17 +73,35 @@ protected:
#else
#ifdef NO_TIMING_COMPLETE_NOOP
// Fastest for release builds, but annoying because it can't be linked
// with code built in debug mode (expecting non-inline functions), so
// not preferred during development
class Profiler
{
public:
Profiler(const char *) { }
~Profiler() { }
void update() const { }
void end() { }
static void dump() { }
};
#else
class Profiler
{
public:
Profiler(const char *);
~Profiler();
void end();
static void dump();
};
#endif
#endif
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,25 +17,12 @@
#include <sys/types.h>
#include <cstring>
#ifndef _WIN32
#include <sys/mman.h>
#endif
#include "Scavenger.h"
#include "Profiler.h"
//#define DEBUG_RINGBUFFER 1
#ifdef _WIN32
#define MLOCK(a,b) 1
#define MUNLOCK(a,b) 1
#else
#define MLOCK(a,b) ::mlock(a,b)
#define MUNLOCK(a,b) ::munlock(a,b)
#endif
#include "system/sysutils.h"
#include "system/Allocators.h"
#ifdef DEBUG_RINGBUFFER
#include <iostream>
@@ -61,7 +48,7 @@ public:
* power of two, this means n should ideally be some power of two
* minus one.
*/
RingBuffer(int n);
RingBuffer(int n = 0);
virtual ~RingBuffer();
@@ -117,7 +104,7 @@ public:
* are available, the remainder will be zeroed out. Returns the
* number of samples actually read.
*/
int read(T *R__ destination, int n, int R = 0);
int read(T *const R__ destination, int n, int R = 0);
/**
* Read n samples from the buffer, for reader R, adding them to
@@ -125,7 +112,7 @@ public:
* will be left alone. Returns the number of samples actually
* read.
*/
int readAdding(T *R__ destination, int n, int R = 0);
int readAdding(T *const R__ destination, int n, int R = 0);
/**
* Read one sample from the buffer, for reader R. If no sample is
@@ -143,7 +130,7 @@ public:
* n are available, the remainder will be zeroed out. Returns the
* number of samples actually read.
*/
int peek(T *R__ destination, int n, int R = 0) const;
int peek(T *const R__ destination, int n, int R = 0) const;
/**
* Read one sample from the buffer, if available, without
@@ -166,7 +153,7 @@ public:
* available, not all samples may actually be written. Returns
* the number of samples actually written.
*/
int write(const T *source, int n);
int write(const T *const R__ source, int n);
/**
* Write n zero-value samples to the buffer. If insufficient
@@ -176,7 +163,7 @@ public:
int zero(int n);
protected:
T *R__ m_buffer;
T *R__ m_buffer;
volatile int m_writer;
volatile int m_readers[N];
int m_size;
@@ -194,11 +181,12 @@ Scavenger<ScavengerArrayWrapper<T> > RingBuffer<T, N>::m_scavenger;
template <typename T, int N>
RingBuffer<T, N>::RingBuffer(int n) :
m_buffer(new T[n + 1]),
m_writer(0),
m_size(n + 1),
m_mlocked(false)
{
m_buffer = allocate<T>(n + 1);
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
#endif
@@ -218,7 +206,8 @@ RingBuffer<T, N>::~RingBuffer()
if (m_mlocked) {
MUNLOCK((void *)m_buffer, m_size * sizeof(T));
}
delete[] m_buffer;
deallocate<T>(m_buffer);
m_scavenger.scavenge();
}
@@ -251,7 +240,7 @@ RingBuffer<T, N>::resize(int newSize)
m_scavenger.claim(new ScavengerArrayWrapper<T>(m_buffer));
reset();
m_buffer = new T[newSize + 1];
m_buffer = allocate<T>(newSize + 1);
m_size = newSize + 1;
if (m_mlocked) {
@@ -353,10 +342,8 @@ RingBuffer<T, N>::getWriteSpace() const
template <typename T, int N>
int
RingBuffer<T, N>::read(T *R__ destination, int n, int R)
RingBuffer<T, N>::read(T *const R__ destination, int n, int R)
{
Profiler profiler("RingBuffer::read");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
#endif
@@ -379,18 +366,10 @@ RingBuffer<T, N>::read(T *R__ destination, int n, int R)
T *const R__ bufbase = m_buffer + reader;
if (here >= n) {
for (int i = 0; i < n; ++i) {
destination[i] = bufbase[i];
}
v_copy(destination, bufbase, n);
} else {
for (int i = 0; i < here; ++i) {
destination[i] = bufbase[i];
}
T *const R__ destbase = destination + here;
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] = m_buffer[i];
}
v_copy(destination, bufbase, here);
v_copy(destination + here, m_buffer, n - here);
}
reader += n;
@@ -406,10 +385,8 @@ RingBuffer<T, N>::read(T *R__ destination, int n, int R)
template <typename T, int N>
int
RingBuffer<T, N>::readAdding(T *R__ destination, int n, int R)
RingBuffer<T, N>::readAdding(T *const R__ destination, int n, int R)
{
Profiler profiler("RingBuffer::readAdding");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
#endif
@@ -429,18 +406,10 @@ RingBuffer<T, N>::readAdding(T *R__ destination, int n, int R)
const T *const R__ bufbase = m_buffer + reader;
if (here >= n) {
for (int i = 0; i < n; ++i) {
destination[i] += bufbase[i];
}
v_add(destination, bufbase, n);
} else {
for (int i = 0; i < here; ++i) {
destination[i] += bufbase[i];
}
T *const R__ destbase = destination + here;
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] += m_buffer[i];
}
v_add(destination, bufbase, here);
v_add(destination + here, m_buffer, n - here);
}
reader += n;
@@ -473,10 +442,8 @@ RingBuffer<T, N>::readOne(int R)
template <typename T, int N>
int
RingBuffer<T, N>::peek(T *R__ destination, int n, int R) const
RingBuffer<T, N>::peek(T *const R__ destination, int n, int R) const
{
Profiler profiler("RingBuffer::peek");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
#endif
@@ -497,18 +464,10 @@ RingBuffer<T, N>::peek(T *R__ destination, int n, int R) const
const T *const R__ bufbase = m_buffer + reader;
if (here >= n) {
for (int i = 0; i < n; ++i) {
destination[i] = bufbase[i];
}
v_copy(destination, bufbase, n);
} else {
for (int i = 0; i < here; ++i) {
destination[i] = bufbase[i];
}
T *const R__ destbase = destination + here;
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] = m_buffer[i];
}
v_copy(destination, bufbase, here);
v_copy(destination + here, m_buffer, n - here);
}
#ifdef DEBUG_RINGBUFFER
@@ -564,10 +523,8 @@ RingBuffer<T, N>::skip(int n, int R)
template <typename T, int N>
int
RingBuffer<T, N>::write(const T *source, int n)
RingBuffer<T, N>::write(const T *const R__ source, int n)
{
Profiler profiler("RingBuffer::write");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
#endif
@@ -587,19 +544,10 @@ RingBuffer<T, N>::write(const T *source, int n)
T *const R__ bufbase = m_buffer + writer;
if (here >= n) {
for (int i = 0; i < n; ++i) {
bufbase[i] = source[i];
}
v_copy(bufbase, source, n);
} else {
for (int i = 0; i < here; ++i) {
bufbase[i] = source[i];
}
const int nh = n - here;
const T *const R__ srcbase = source + here;
T *const R__ buf = m_buffer;
for (int i = 0; i < nh; ++i) {
buf[i] = srcbase[i];
}
v_copy(bufbase, source, here);
v_copy(m_buffer, source + here, n - here);
}
writer += n;
@@ -617,8 +565,6 @@ template <typename T, int N>
int
RingBuffer<T, N>::zero(int n)
{
Profiler profiler("RingBuffer::zero");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
#endif
@@ -638,17 +584,10 @@ RingBuffer<T, N>::zero(int n)
T *const R__ bufbase = m_buffer + writer;
if (here >= n) {
for (int i = 0; i < n; ++i) {
bufbase[i] = 0;
}
v_zero(bufbase, n);
} else {
for (int i = 0; i < here; ++i) {
bufbase[i] = 0;
}
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
m_buffer[i] = 0;
}
v_zero(bufbase, here);
v_zero(m_buffer, n - here);
}
writer += n;
@@ -664,6 +603,4 @@ RingBuffer<T, N>::zero(int n)
}
//#include "RingBuffer.cpp"
#endif // _RINGBUFFER_H_

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,8 +23,11 @@
#include <sys/time.h>
#endif
#include "Thread.h"
#include "sysutils.h"
#include "system/Thread.h"
#include "system/sysutils.h"
#include "system/Allocators.h"
//#define DEBUG_SCAVENGER 1
namespace RubberBand {
@@ -73,10 +76,12 @@ protected:
unsigned int m_claimed;
unsigned int m_scavenged;
unsigned int m_asExcess;
};
/**
* A wrapper to permit arrays to be scavenged.
* A wrapper to permit arrays allocated with new[] to be scavenged.
*/
template <typename T>
@@ -91,12 +96,30 @@ private:
};
/**
* A wrapper to permit arrays allocated with the Allocators functions
* to be scavenged.
*/
template <typename T>
class ScavengerAllocArrayWrapper
{
public:
ScavengerAllocArrayWrapper(T *array) : m_array(array) { }
~ScavengerAllocArrayWrapper() { deallocate<T>(m_array); }
private:
T *m_array;
};
template <typename T>
Scavenger<T>::Scavenger(int sec, int defaultObjectListSize) :
m_objects(ObjectTimeList(defaultObjectListSize)),
m_sec(sec),
m_claimed(0),
m_scavenged(0)
m_scavenged(0),
m_asExcess(0)
{
}
@@ -138,8 +161,10 @@ Scavenger<T>::claim(T *t)
}
}
std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, "
<< "using non-RT-safe method" << std::endl;
#ifdef DEBUG_SCAVENGER
std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots (at "
<< m_objects.size() << "), using non-RT-safe method" << std::endl;
#endif
pushExcess(t);
}
@@ -147,26 +172,30 @@ template <typename T>
void
Scavenger<T>::scavenge(bool clearNow)
{
// std::cerr << "Scavenger::scavenge: scavenged " << m_scavenged << ", claimed " << m_claimed << std::endl;
#ifdef DEBUG_SCAVENGER
std::cerr << "Scavenger::scavenge: claimed " << m_claimed << ", scavenged " << m_scavenged << ", cleared as excess " << m_asExcess << std::endl;
#endif
if (m_scavenged >= m_claimed) return;
struct timeval tv;
(void)gettimeofday(&tv, 0);
int sec = tv.tv_sec;
bool anything = false;
for (size_t i = 0; i < m_objects.size(); ++i) {
ObjectTimePair &pair = m_objects[i];
if (clearNow ||
(pair.first != 0 && pair.second + m_sec < sec)) {
if (!pair.first) continue;
if (clearNow || pair.second + m_sec < sec) {
T *ot = pair.first;
pair.first = 0;
delete ot;
++m_scavenged;
anything = true;
}
}
if (sec > m_lastExcess + m_sec) {
if (clearNow || anything || (sec > m_lastExcess + m_sec)) {
clearExcess(sec);
}
}
@@ -187,10 +216,15 @@ template <typename T>
void
Scavenger<T>::clearExcess(int sec)
{
#ifdef DEBUG_SCAVENGER
std::cerr << "Scavenger::clearExcess: Excess now " << m_excess.size() << std::endl;
#endif
m_excessMutex.lock();
for (typename ObjectList::iterator i = m_excess.begin();
i != m_excess.end(); ++i) {
delete *i;
++m_asExcess;
}
m_excess.clear();
m_lastExcess = sec;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -12,15 +12,20 @@
COPYING included with this distribution for more information.
*/
#include "RubberBandPitchShifter.h"
#include "AudioCurveCalculator.h"
#include <stdio.h>
extern "C" {
const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
namespace RubberBand
{
AudioCurveCalculator::AudioCurveCalculator(size_t sampleRate, size_t windowSize) :
m_sampleRate(sampleRate),
m_windowSize(windowSize)
{
return RubberBandPitchShifter::getDescriptor(index);
}
AudioCurveCalculator::~AudioCurveCalculator()
{
}
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -12,26 +12,35 @@
COPYING included with this distribution for more information.
*/
#ifndef _AUDIO_CURVE_H_
#define _AUDIO_CURVE_H_
#ifndef _AUDIO_CURVE_CALCULATOR_H_
#define _AUDIO_CURVE_CALCULATOR_H_
#include <sys/types.h>
#include "sysutils.h"
#include "system/sysutils.h"
namespace RubberBand
{
class AudioCurve
class AudioCurveCalculator
{
public:
AudioCurve(size_t sampleRate, size_t windowSize);
virtual ~AudioCurve();
AudioCurveCalculator(size_t sampleRate, size_t windowSize);
virtual ~AudioCurveCalculator();
size_t getSampleRate() const { return m_sampleRate; }
size_t getWindowSize() const { return m_windowSize; }
virtual void setWindowSize(size_t newSize) = 0;
virtual float process(const float *R__ mag, size_t increment) = 0;
virtual float processDouble(const double *R__ mag, size_t increment);
// You may not mix calls to the various process functions on a
// given instance
virtual float processFloat(const float *R__ mag, size_t increment) = 0;
virtual double processDouble(const double *R__ mag, size_t increment) = 0;
virtual void reset() = 0;
protected:

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -18,7 +18,7 @@ namespace RubberBand
{
ConstantAudioCurve::ConstantAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize)
AudioCurveCalculator(sampleRate, windowSize)
{
}
@@ -38,15 +38,15 @@ ConstantAudioCurve::setWindowSize(size_t newSize)
}
float
ConstantAudioCurve::process(const float *R__, size_t)
ConstantAudioCurve::processFloat(const float *R__, size_t)
{
return 1.f;
}
float
double
ConstantAudioCurve::processDouble(const double *R__, size_t)
{
return 1.f;
return 1.0;
}
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,12 +15,12 @@
#ifndef _CONSTANT_AUDIO_CURVE_H_
#define _CONSTANT_AUDIO_CURVE_H_
#include "AudioCurve.h"
#include "AudioCurveCalculator.h"
namespace RubberBand
{
class ConstantAudioCurve : public AudioCurve
class ConstantAudioCurve : public AudioCurveCalculator
{
public:
ConstantAudioCurve(size_t sampleRate, size_t windowSize);
@@ -28,8 +28,8 @@ public:
virtual void setWindowSize(size_t newSize);
virtual float process(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual void reset();
};

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -13,8 +13,10 @@
*/
#include "FFT.h"
#include "Thread.h"
#include "Profiler.h"
#include "system/Thread.h"
#include "base/Profiler.h"
#include "system/Allocators.h"
#include "system/VectorOps.h"
//#define FFT_MEASUREMENT 1
@@ -23,8 +25,9 @@
#include <fftw3.h>
#endif
#ifdef USE_KISSFFT
#include "bsd-3rdparty/kissfft/kiss_fftr.h"
#include "kissfft/kiss_fftr.h"
#endif
#ifndef HAVE_FFTW3
@@ -42,6 +45,7 @@
#include <cstdlib>
#include <vector>
namespace RubberBand {
class FFTImpl
@@ -75,6 +79,7 @@ public:
namespace FFTs {
#ifdef HAVE_FFTW3
// Define FFTW_DOUBLE_ONLY to make all uses of FFTW functions be
@@ -242,7 +247,7 @@ public:
if (!home) return;
char fn[256];
snprintf(fn, 256, "%s/%s.%c", home, ".rubberband.wisdom", type);
snprintf(fn, 256, "%s/%s.%c", home, ".turbot.wisdom", type);
FILE *f = fopen(fn, save ? "wb" : "rb");
if (!f) return;
@@ -657,7 +662,15 @@ public:
const int hs = m_size/2;
for (int i = 0; i <= hs; ++i) {
m_fpacked[i].r = re[i];
m_fpacked[i].i = im[i];
}
if (im) {
for (int i = 0; i <= hs; ++i) {
m_fpacked[i].i = im[i];
}
} else {
for (int i = 0; i <= hs; ++i) {
m_fpacked[i].i = 0.f;
}
}
}
@@ -665,7 +678,11 @@ public:
const int hs = m_size/2;
for (int i = 0; i <= hs; ++i) {
re[i] = m_fpacked[i].r;
im[i] = m_fpacked[i].i;
}
if (im) {
for (int i = 0; i <= hs; ++i) {
im[i] = m_fpacked[i].i;
}
}
}
@@ -673,7 +690,15 @@ public:
const int hs = m_size/2;
for (int i = 0; i <= hs; ++i) {
m_fpacked[i].r = float(re[i]);
m_fpacked[i].i = float(im[i]);
}
if (im) {
for (int i = 0; i <= hs; ++i) {
m_fpacked[i].i = float(im[i]);
}
} else {
for (int i = 0; i <= hs; ++i) {
m_fpacked[i].i = 0.f;
}
}
}
@@ -681,7 +706,11 @@ public:
const int hs = m_size/2;
for (int i = 0; i <= hs; ++i) {
re[i] = double(m_fpacked[i].r);
im[i] = double(m_fpacked[i].i);
}
if (im) {
for (int i = 0; i <= hs; ++i) {
im[i] = double(m_fpacked[i].i);
}
}
}
@@ -1238,6 +1267,16 @@ FFT::FFT(int size, int debugLevel)
std::cerr << "FFT::FFT(" << size << "): ERROR: Fallback implementation not available!" << std::endl;
abort();
#endif
#endif
break;
case 4:
std::cerr << "FFT::FFT(" << size << "): WARNING: Selected implemention not available" << std::endl;
#ifdef USE_BUILTIN_FFT
d = new FFTs::D_Cross(size);
#else
std::cerr << "FFT::FFT(" << size << "): ERROR: Fallback implementation not available!" << std::endl;
abort();
#endif
break;
@@ -1358,6 +1397,7 @@ FFT::getDoubleTimeBuffer()
void
FFT::tune()
{
std::cerr << "FFT::tune: Measurement not enabled" << std::endl;
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,7 +15,7 @@
#ifndef _RUBBERBAND_FFT_H_
#define _RUBBERBAND_FFT_H_
#include "sysutils.h"
#include "system/sysutils.h"
namespace RubberBand {
@@ -30,9 +30,11 @@ class FFTImpl;
* complex conjugates half is omitted), so the "complex" arrays need
* room for size/2+1 elements.
*
* Not thread safe: use a separate instance per thread.
* Not thread safe: use a separate instance per thread, or use a mutex.
*/
//!!! it would be nice if we could redefine forwardMagnitude as forwardPower (i.e. square of magnitude)
class FFT
{
public:

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -18,7 +18,7 @@ namespace RubberBand
{
HighFrequencyAudioCurve::HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize)
AudioCurveCalculator(sampleRate, windowSize)
{
}
@@ -38,7 +38,7 @@ HighFrequencyAudioCurve::setWindowSize(size_t newSize)
}
float
HighFrequencyAudioCurve::process(const float *R__ mag, size_t increment)
HighFrequencyAudioCurve::processFloat(const float *R__ mag, size_t increment)
{
float result = 0.0;
@@ -51,7 +51,7 @@ HighFrequencyAudioCurve::process(const float *R__ mag, size_t increment)
return result;
}
float
double
HighFrequencyAudioCurve::processDouble(const double *R__ mag, size_t increment)
{
float result = 0.0;
@@ -59,7 +59,7 @@ HighFrequencyAudioCurve::processDouble(const double *R__ mag, size_t increment)
const int sz = m_windowSize / 2;
for (int n = 0; n <= sz; ++n) {
result = result + (float)mag[n] * n;
result = result + mag[n] * n;
}
return result;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,13 +15,12 @@
#ifndef _HIGHFREQUENCY_AUDIO_CURVE_H_
#define _HIGHFREQUENCY_AUDIO_CURVE_H_
#include "AudioCurve.h"
#include "Window.h"
#include "AudioCurveCalculator.h"
namespace RubberBand
{
class HighFrequencyAudioCurve : public AudioCurve
class HighFrequencyAudioCurve : public AudioCurveCalculator
{
public:
HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize);
@@ -30,8 +29,8 @@ public:
virtual void setWindowSize(size_t newSize);
virtual float process(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual void reset();
};

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -14,50 +14,41 @@
#include "PercussiveAudioCurve.h"
#include "Profiler.h"
#include "system/Allocators.h"
#include "system/VectorOps.h"
#include <cmath>
namespace RubberBand
{
PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize)
AudioCurveCalculator(sampleRate, windowSize)
{
m_prevMag = new float[m_windowSize/2 + 1];
for (size_t i = 0; i <= m_windowSize/2; ++i) {
m_prevMag[i] = 0.f;
}
m_prevMag = allocate_and_zero<double>(m_windowSize/2 + 1);
}
PercussiveAudioCurve::~PercussiveAudioCurve()
{
delete[] m_prevMag;
deallocate(m_prevMag);
}
void
PercussiveAudioCurve::reset()
{
for (size_t i = 0; i <= m_windowSize/2; ++i) {
m_prevMag[i] = 0;
}
v_zero(m_prevMag, m_windowSize/2 + 1);
}
void
PercussiveAudioCurve::setWindowSize(size_t newSize)
{
m_prevMag = reallocate(m_prevMag, m_windowSize, newSize);
m_windowSize = newSize;
delete[] m_prevMag;
m_prevMag = new float[m_windowSize/2 + 1];
reset();
}
float
PercussiveAudioCurve::process(const float *R__ mag, size_t increment)
PercussiveAudioCurve::processFloat(const float *R__ mag, size_t increment)
{
static float threshold = powf(10.f, 0.15f); // 3dB rise in square of magnitude
static float zeroThresh = powf(10.f, -8);
@@ -73,21 +64,17 @@ PercussiveAudioCurve::process(const float *R__ mag, size_t increment)
if (mag[n] > zeroThresh) ++nonZeroCount;
}
for (int n = 1; n <= sz; ++n) {
m_prevMag[n] = mag[n];
}
v_convert(m_prevMag, mag, sz + 1);
if (nonZeroCount == 0) return 0;
else return float(count) / float(nonZeroCount);
}
float
double
PercussiveAudioCurve::processDouble(const double *R__ mag, size_t increment)
{
Profiler profiler("PercussiveAudioCurve::process");
static double threshold = pow(10.0, 0.15); // 3dB rise in square of magnitude
static double zeroThresh = pow(10.0, -8);
static double threshold = powf(10., 0.15); // 3dB rise in square of magnitude
static double zeroThresh = powf(10., -8);
size_t count = 0;
size_t nonZeroCount = 0;
@@ -100,13 +87,12 @@ PercussiveAudioCurve::processDouble(const double *R__ mag, size_t increment)
if (mag[n] > zeroThresh) ++nonZeroCount;
}
for (int n = 1; n <= sz; ++n) {
m_prevMag[n] = mag[n];
}
v_copy(m_prevMag, mag, sz + 1);
if (nonZeroCount == 0) return 0;
else return float(count) / float(nonZeroCount);
else return double(count) / double(nonZeroCount);
}
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,12 +15,12 @@
#ifndef _PERCUSSIVE_AUDIO_CURVE_H_
#define _PERCUSSIVE_AUDIO_CURVE_H_
#include "AudioCurve.h"
#include "AudioCurveCalculator.h"
namespace RubberBand
{
class PercussiveAudioCurve : public AudioCurve
class PercussiveAudioCurve : public AudioCurveCalculator
{
public:
PercussiveAudioCurve(size_t sampleRate, size_t windowSize);
@@ -29,12 +29,14 @@ public:
virtual void setWindowSize(size_t newSize);
virtual float process(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual void reset();
protected:
float *R__ m_prevMag;
double *R__ m_prevMag;
};
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -13,14 +13,15 @@
*/
#include "Resampler.h"
#include "Profiler.h"
#include "base/Profiler.h"
#include <cstdlib>
#include <cmath>
#include <iostream>
#include "system/Allocators.h"
#include <samplerate.h>
@@ -39,6 +40,8 @@ public:
float ratio,
bool final) = 0;
virtual int getChannelCount() const = 0;
virtual void reset() = 0;
};
@@ -59,6 +62,8 @@ public:
float ratio,
bool final);
int getChannelCount() const { return m_channels; }
void reset();
protected:
@@ -103,8 +108,8 @@ D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
if (maxBufferSize > 0 && m_channels > 1) {
m_iinsize = maxBufferSize * m_channels;
m_ioutsize = maxBufferSize * m_channels * 2;
m_iin = allocFloat(m_iinsize);
m_iout = allocFloat(m_ioutsize);
m_iin = allocate<float>(m_iinsize);
m_iout = allocate<float>(m_ioutsize);
}
reset();
@@ -113,12 +118,8 @@ D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
D_SRC::~D_SRC()
{
src_delete(m_src);
if (m_iinsize > 0) {
free(m_iin);
}
if (m_ioutsize > 0) {
free(m_iout);
}
deallocate<float>(m_iin);
deallocate<float>(m_iout);
}
int
@@ -137,12 +138,12 @@ D_SRC::resample(const float *const R__ *const R__ in,
data.data_out = *out;
} else {
if (incount * m_channels > m_iinsize) {
m_iin = reallocate<float>(m_iin, m_iinsize, incount * m_channels);
m_iinsize = incount * m_channels;
m_iin = allocFloat(m_iin, m_iinsize);
}
if (outcount * m_channels > m_ioutsize) {
m_iout = reallocate<float>(m_iout, m_ioutsize, outcount * m_channels);
m_ioutsize = outcount * m_channels;
m_iout = allocFloat(m_iout, m_ioutsize);
}
for (int i = 0; i < incount; ++i) {
for (int c = 0; c < m_channels; ++c) {
@@ -251,6 +252,12 @@ Resampler::resample(const float *const R__ *const R__ in,
return d->resample(in, out, incount, ratio, final);
}
int
Resampler::getChannelCount() const
{
return d->getChannelCount();
}
void
Resampler::reset()
{

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,9 +15,7 @@
#ifndef _RUBBERBAND_RESAMPLER_H_
#define _RUBBERBAND_RESAMPLER_H_
#include <sys/types.h>
#include "sysutils.h"
#include "system/sysutils.h"
namespace RubberBand {
@@ -45,6 +43,8 @@ public:
float ratio,
bool final = false);
int getChannelCount() const;
void reset();
protected:

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -20,7 +20,7 @@ namespace RubberBand
{
SilentAudioCurve::SilentAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize)
AudioCurveCalculator(sampleRate, windowSize)
{
}
@@ -40,7 +40,7 @@ SilentAudioCurve::setWindowSize(size_t newSize)
}
float
SilentAudioCurve::process(const float *R__ mag, size_t)
SilentAudioCurve::processFloat(const float *R__ mag, size_t)
{
const int hs = m_windowSize / 2;
static float threshold = powf(10.f, -6);
@@ -52,7 +52,7 @@ SilentAudioCurve::process(const float *R__ mag, size_t)
return 1.f;
}
float
double
SilentAudioCurve::processDouble(const double *R__ mag, size_t)
{
const int hs = m_windowSize / 2;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,12 +15,12 @@
#ifndef _SILENT_AUDIO_CURVE_H_
#define _SILENT_AUDIO_CURVE_H_
#include "AudioCurve.h"
#include "AudioCurveCalculator.h"
namespace RubberBand
{
class SilentAudioCurve : public AudioCurve
class SilentAudioCurve : public AudioCurveCalculator
{
public:
SilentAudioCurve(size_t sampleRate, size_t windowSize);
@@ -28,8 +28,8 @@ public:
virtual void setWindowSize(size_t newSize);
virtual float process(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual void reset();
};

View File

@@ -0,0 +1,97 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2009 Chris Cannam.
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.
*/
#include "SpectralDifferenceAudioCurve.h"
#include "system/Allocators.h"
#include "system/VectorOps.h"
namespace RubberBand
{
SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurveCalculator(sampleRate, windowSize)
{
m_mag = allocate<double>(m_windowSize/2 + 1);
m_tmpbuf = allocate<double>(m_windowSize/2 + 1);
v_zero(m_mag, m_windowSize/2 + 1);
}
SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve()
{
deallocate(m_mag);
deallocate(m_tmpbuf);
}
void
SpectralDifferenceAudioCurve::reset()
{
v_zero(m_mag, m_windowSize/2 + 1);
}
void
SpectralDifferenceAudioCurve::setWindowSize(size_t newSize)
{
deallocate(m_tmpbuf);
deallocate(m_mag);
m_windowSize = newSize;
m_mag = allocate<double>(m_windowSize/2 + 1);
m_tmpbuf = allocate<double>(m_windowSize/2 + 1);
reset();
}
float
SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, size_t increment)
{
double result = 0.0;
const int hs1 = m_windowSize/2 + 1;
v_convert(m_tmpbuf, mag, hs1);
v_square(m_tmpbuf, hs1);
v_subtract(m_mag, m_tmpbuf, hs1);
v_abs(m_mag, hs1);
v_sqrt(m_mag, hs1);
for (int i = 0; i < hs1; ++i) {
result += m_mag[i];
}
v_copy(m_mag, m_tmpbuf, hs1);
return result;
}
double
SpectralDifferenceAudioCurve::processDouble(const double *R__ mag, size_t increment)
{
double result = 0.0;
const int hs1 = m_windowSize/2 + 1;
v_convert(m_tmpbuf, mag, hs1);
v_square(m_tmpbuf, hs1);
v_subtract(m_mag, m_tmpbuf, hs1);
v_abs(m_mag, hs1);
v_sqrt(m_mag, hs1);
for (int i = 0; i < hs1; ++i) {
result += m_mag[i];
}
v_copy(m_mag, m_tmpbuf, hs1);
return result;
}
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,13 +15,13 @@
#ifndef _SPECTRALDIFFERENCE_AUDIO_CURVE_H_
#define _SPECTRALDIFFERENCE_AUDIO_CURVE_H_
#include "AudioCurve.h"
#include "AudioCurveCalculator.h"
#include "Window.h"
namespace RubberBand
{
class SpectralDifferenceAudioCurve : public AudioCurve
class SpectralDifferenceAudioCurve : public AudioCurveCalculator
{
public:
SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize);
@@ -30,12 +30,13 @@ public:
virtual void setWindowSize(size_t newSize);
virtual float process(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual void reset();
protected:
float *R__ m_prevMag;
double *R__ m_mag;
double *R__ m_tmpbuf;
};
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -20,7 +20,8 @@
#include <cstdlib>
#include <map>
#include "sysutils.h"
#include "system/sysutils.h"
#include "system/VectorOps.h"
namespace RubberBand {
@@ -54,29 +55,23 @@ public:
}
virtual ~Window() { delete[] m_cache; }
void cut(T *R__ src) const
{
const int sz = m_size;
for (int i = 0; i < sz; ++i) {
src[i] *= m_cache[i];
}
inline void cut(T *const R__ block) const {
v_multiply(block, m_cache, m_size);
}
void cut(T *R__ src, T *dst) const {
const int sz = m_size;
for (int i = 0; i < sz; ++i) {
dst[i] = src[i];
}
for (int i = 0; i < sz; ++i) {
dst[i] *= m_cache[i];
}
inline void cut(const T *const R__ src, T *const R__ dst) const {
v_multiply(dst, src, m_cache, m_size);
}
T getArea() { return m_area; }
T getValue(int i) { return m_cache[i]; }
inline void add(T *const R__ dst, T scale) const {
v_add_with_gain(dst, m_cache, m_size, scale);
}
WindowType getType() const { return m_type; }
int getSize() const { return m_size; }
inline T getArea() const { return m_area; }
inline T getValue(int i) const { return m_cache[i]; }
inline WindowType getType() const { return m_type; }
inline int getSize() const { return m_size; }
protected:
WindowType m_type;

View File

@@ -1,554 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include "RubberBandPitchShifter.h"
#include "RubberBandStretcher.h"
#include <iostream>
#include <cmath>
using namespace RubberBand;
using std::cout;
using std::cerr;
using std::endl;
using std::min;
const char *const
RubberBandPitchShifter::portNamesMono[PortCountMono] =
{
"latency",
"Cents",
"Semitones",
"Octaves",
"Crispness",
"Formant Preserving",
"Faster",
"Input",
"Output"
};
const char *const
RubberBandPitchShifter::portNamesStereo[PortCountStereo] =
{
"latency",
"Cents",
"Semitones",
"Octaves",
"Crispness",
"Formant Preserving",
"Faster",
"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,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
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,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
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] =
{
{ 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 | // semitones
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-12.0, 12.0 },
{ LADSPA_HINT_DEFAULT_0 | // octaves
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-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 | // formant preserving
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ LADSPA_HINT_DEFAULT_0 | // fast
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ 0, 0, 0 },
{ 0, 0, 0 }
};
const LADSPA_PortRangeHint
RubberBandPitchShifter::hintsStereo[PortCountStereo] =
{
{ 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 | // semitones
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-12.0, 12.0 },
{ LADSPA_HINT_DEFAULT_0 | // octaves
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-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 | // formant preserving
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ LADSPA_HINT_DEFAULT_0 | // fast
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ 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
"Breakfast Quay",
"GPL",
PortCountMono,
portsMono,
portNamesMono,
hintsMono,
0, // Implementation data
instantiate,
connectPort,
activate,
run,
0, // Run adding
0, // Set run adding gain
deactivate,
cleanup
};
const LADSPA_Descriptor
RubberBandPitchShifter::ladspaDescriptorStereo =
{
9792, // "Unique" ID
"rubberband-pitchshifter-stereo", // Label
properties,
"Rubber Band Stereo Pitch Shifter", // Name
"Breakfast Quay",
"GPL",
PortCountStereo,
portsStereo,
portNamesStereo,
hintsStereo,
0, // Implementation data
instantiate,
connectPort,
activate,
run,
0, // Run adding
0, // Set run adding gain
deactivate,
cleanup
};
const LADSPA_Descriptor *
RubberBandPitchShifter::getDescriptor(unsigned long index)
{
if (index == 0) return &ladspaDescriptorMono;
if (index == 1) return &ladspaDescriptorStereo;
else return 0;
}
RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) :
m_latency(0),
m_cents(0),
m_semitones(0),
m_octaves(0),
m_crispness(0),
m_formant(0),
m_fast(0),
m_ratio(1.0),
m_prevRatio(1.0),
m_currentCrispness(-1),
m_currentFormant(false),
m_currentFast(false),
m_blockSize(1024),
m_reserve(1024),
m_minfill(0),
m_stretcher(new RubberBandStretcher
(sampleRate, channels,
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;
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()
{
delete m_stretcher;
for (size_t c = 0; c < m_channels; ++c) {
delete m_outputBuffer[c];
delete[] m_scratch[c];
}
}
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);
}
return 0;
}
void
RubberBandPitchShifter::connectPort(LADSPA_Handle handle,
unsigned long port, LADSPA_Data *location)
{
RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
float **ports[PortCountStereo] = {
&shifter->m_latency,
&shifter->m_cents,
&shifter->m_semitones,
&shifter->m_octaves,
&shifter->m_crispness,
&shifter->m_formant,
&shifter->m_fast,
&shifter->m_input[0],
&shifter->m_output[0],
&shifter->m_input[1],
&shifter->m_output[1]
};
if (shifter->m_channels == 1) {
if (port >= PortCountMono) return;
} else {
if (port >= PortCountStereo) return;
}
*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->activateImpl();
}
void
RubberBandPitchShifter::activateImpl()
{
updateRatio();
m_prevRatio = m_ratio;
m_stretcher->reset();
m_stretcher->setPitchScale(m_ratio);
for (size_t c = 0; c < m_channels; ++c) {
m_outputBuffer[c]->reset();
m_outputBuffer[c]->zero(m_reserve);
}
m_minfill = 0;
// prime stretcher
// for (int i = 0; i < 8; ++i) {
// 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
RubberBandPitchShifter::run(LADSPA_Handle handle, unsigned long samples)
{
RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
shifter->runImpl(samples);
}
void
RubberBandPitchShifter::updateRatio()
{
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);
}
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;
}
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;
}
void
RubberBandPitchShifter::updateFast()
{
if (!m_fast) return;
bool f = (*m_fast > 0.5f);
if (f == m_currentFast) return;
RubberBandStretcher *s = m_stretcher;
s->setPitchOption(f ?
RubberBandStretcher::OptionPitchHighSpeed :
RubberBandStretcher::OptionPitchHighConsistency);
m_currentFast = f;
}
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 + offset > insamples) block = insamples - offset;
runImpl(block, offset);
offset += block;
}
}
void
RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset)
{
// cerr << "RubberBandPitchShifter::runImpl(" << insamples << ")" << endl;
// static int incount = 0, outcount = 0;
updateRatio();
if (m_ratio != m_prevRatio) {
m_stretcher->setPitchScale(m_ratio);
m_prevRatio = m_ratio;
}
if (m_latency) {
*m_latency = float(m_stretcher->getLatency() + m_reserve);
// cerr << "latency = " << *m_latency << endl;
}
updateCrispness();
updateFormant();
updateFast();
const int samples = insamples;
int processed = 0;
size_t outTotal = 0;
float *ptrs[2];
int rs = m_outputBuffer[0]->getReadSpace();
if (rs < int(m_minfill)) {
// cerr << "temporary expansion (have " << rs << ", want " << m_reserve << ")" << endl;
m_stretcher->setTimeRatio(1.1); // fill up temporarily
} else if (rs > 8192) {
// cerr << "temporary reduction (have " << rs << ", want " << m_reserve << ")" << endl;
m_stretcher->setTimeRatio(0.9); // reduce temporarily
} else {
m_stretcher->setTimeRatio(1.0);
}
while (processed < samples) {
// 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();
int inchunk = min(samples - processed, toCauseProcessing);
for (size_t c = 0; c < m_channels; ++c) {
ptrs[c] = &(m_input[c][offset + processed]);
}
m_stretcher->process(ptrs, inchunk, false);
processed += inchunk;
int avail = m_stretcher->available();
int writable = m_outputBuffer[0]->getWriteSpace();
int outchunk = min(avail, writable);
size_t actual = m_stretcher->retrieve(m_scratch, outchunk);
outTotal += actual;
// incount += inchunk;
// outcount += actual;
// cout << "avail: " << avail << ", outchunk = " << outchunk;
// if (actual != outchunk) cout << " (" << actual << ")";
// cout << endl;
outchunk = actual;
for (size_t c = 0; c < m_channels; ++c) {
if (int(m_outputBuffer[c]->getWriteSpace()) < outchunk) {
cerr << "RubberBandPitchShifter::runImpl: buffer overrun: chunk = " << outchunk << ", space = " << m_outputBuffer[c]->getWriteSpace() << endl;
}
m_outputBuffer[c]->write(m_scratch[c], outchunk);
}
}
for (size_t c = 0; c < m_channels; ++c) {
int toRead = m_outputBuffer[c]->getReadSpace();
if (toRead < samples && c == 0) {
cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << endl;
}
int chunk = min(toRead, samples);
m_outputBuffer[c]->read(&(m_output[c][offset]), chunk);
}
if (m_minfill == 0) {
m_minfill = m_outputBuffer[0]->getReadSpace();
// cerr << "minfill = " << m_minfill << endl;
}
}
void
RubberBandPitchShifter::deactivate(LADSPA_Handle handle)
{
activate(handle); // both functions just reset the plugin
}
void
RubberBandPitchShifter::cleanup(LADSPA_Handle handle)
{
delete (RubberBandPitchShifter *)handle;
}

View File

@@ -1,107 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#ifndef _RUBBERBAND_PITCH_SHIFTER_H_
#define _RUBBERBAND_PITCH_SHIFTER_H_
#include <ladspa.h>
#include "RingBuffer.h"
namespace RubberBand {
class RubberBandStretcher;
}
class RubberBandPitchShifter
{
public:
static const LADSPA_Descriptor *getDescriptor(unsigned long index);
protected:
RubberBandPitchShifter(int sampleRate, size_t channels);
~RubberBandPitchShifter();
enum {
LatencyPort = 0,
OctavesPort = 1,
SemitonesPort = 2,
CentsPort = 3,
CrispnessPort = 4,
FormantPort = 5,
FastPort = 6,
InputPort1 = 7,
OutputPort1 = 8,
PortCountMono = OutputPort1 + 1,
InputPort2 = 9,
OutputPort2 = 10,
PortCountStereo = OutputPort2 + 1
};
static const char *const portNamesMono[PortCountMono];
static const LADSPA_PortDescriptor portsMono[PortCountMono];
static const LADSPA_PortRangeHint hintsMono[PortCountMono];
static const char *const portNamesStereo[PortCountStereo];
static const LADSPA_PortDescriptor portsStereo[PortCountStereo];
static const LADSPA_PortRangeHint hintsStereo[PortCountStereo];
static const LADSPA_Properties properties;
static const LADSPA_Descriptor ladspaDescriptorMono;
static const LADSPA_Descriptor ladspaDescriptorStereo;
static LADSPA_Handle instantiate(const LADSPA_Descriptor *, unsigned long);
static void connectPort(LADSPA_Handle, unsigned long, LADSPA_Data *);
static void activate(LADSPA_Handle);
static void run(LADSPA_Handle, unsigned long);
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();
void updateFast();
float *m_input[2];
float *m_output[2];
float *m_latency;
float *m_cents;
float *m_semitones;
float *m_octaves;
float *m_crispness;
float *m_formant;
float *m_fast;
double m_ratio;
double m_prevRatio;
int m_currentCrispness;
bool m_currentFormant;
bool m_currentFast;
size_t m_blockSize;
size_t m_reserve;
size_t m_minfill;
RubberBand::RubberBandStretcher *m_stretcher;
RubberBand::RingBuffer<float> *m_outputBuffer[2];
float *m_scratch[2];
int m_sampleRate;
size_t m_channels;
};
#endif

View File

@@ -1,4 +0,0 @@
{
global: ladspa_descriptor;
local: *;
};

View File

@@ -1,2 +0,0 @@
ladspa:ladspa-rubberband:rubberband-pitchshifter-mono::Frequency > Pitch shifters
ladspa:ladspa-rubberband:rubberband-pitchshifter-stereo::Frequency > Pitch shifters

View File

@@ -1,14 +0,0 @@
<?xml version='1.0' encoding='ISO-8859-1'?>
<!DOCTYPE rdf:RDF [
<!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<!ENTITY ladspa 'http://ladspa.org/ontology#'>
]>
<rdf:RDF xmlns:rdf="&rdf;" xmlns:ladspa="&ladspa;">
<ladspa:PitchPlugin rdf:about="&ladspa;2979"/>
<ladspa:PitchPlugin rdf:about="&ladspa;9792"/>
</rdf:RDF>

View File

@@ -1,529 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include "RubberBandStretcher.h"
#include <iostream>
#include <sndfile.h>
#include <cmath>
#include <time.h>
#include <cstdlib>
#include <cstring>
#include "sysutils.h"
#ifdef __MSVC__
#include "bsd-3rdparty/getopt/getopt.h"
#else
#include <getopt.h>
#include <sys/time.h>
#endif
#include "Profiler.h"
using namespace std;
using namespace RubberBand;
#ifdef _WIN32
using RubberBand::gettimeofday;
using RubberBand::usleep;
#endif
double tempo_convert(const char *str)
{
char *d = strchr((char *)str, ':');
if (!d || !*d) {
double m = atof(str);
if (m != 0.0) return 1.0 / m;
else return 1.0;
}
char *a = strdup(str);
char *b = strdup(d+1);
a[d-str] = '\0';
double m = atof(a);
double n = atof(b);
free(a);
free(b);
if (n != 0.0 && m != 0.0) return m / n;
else return 1.0;
}
int main(int argc, char **argv)
{
int c;
double ratio = 1.0;
double duration = 0.0;
double pitchshift = 0.0;
double frequencyshift = 1.0;
int debug = 0;
bool realtime = false;
bool precise = false;
int threading = 0;
bool lamination = true;
bool longwin = false;
bool shortwin = false;
bool hqpitch = false;
bool formant = false;
bool crispchanged = false;
int crispness = -1;
bool help = false;
bool version = false;
bool quiet = false;
bool haveRatio = false;
enum {
NoTransients,
BandLimitedTransients,
Transients
} transients = Transients;
while (1) {
int optionIndex = 0;
static struct option longOpts[] = {
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'V' },
{ "time", 1, 0, 't' },
{ "tempo", 1, 0, 'T' },
{ "duration", 1, 0, 'D' },
{ "pitch", 1, 0, 'p' },
{ "frequency", 1, 0, 'f' },
{ "crisp", 1, 0, 'c' },
{ "crispness", 1, 0, 'c' },
{ "debug", 1, 0, 'd' },
{ "realtime", 0, 0, 'R' },
{ "precise", 0, 0, 'P' },
{ "formant", 0, 0, 'F' },
{ "no-threads", 0, 0, '0' },
{ "no-transients", 0, 0, '1' },
{ "no-lamination", 0, 0, '2' },
{ "window-long", 0, 0, '3' },
{ "window-short", 0, 0, '4' },
{ "bl-transients", 0, 0, '8' },
{ "pitch-hq", 0, 0, '%' },
{ "threads", 0, 0, '@' },
{ "quiet", 0, 0, 'q' },
{ 0, 0, 0 }
};
c = getopt_long(argc, argv, "t:p:d:RPFc:f:T:D:qhV", longOpts, &optionIndex);
if (c == -1) break;
switch (c) {
case 'h': help = true; break;
case 'V': version = true; break;
case 't': ratio *= atof(optarg); haveRatio = true; break;
case 'T': ratio *= tempo_convert(optarg); haveRatio = true; break;
case 'D': duration = atof(optarg); haveRatio = true; break;
case 'p': pitchshift = atof(optarg); haveRatio = true; break;
case 'f': frequencyshift = atof(optarg); haveRatio = true; break;
case 'd': debug = atoi(optarg); break;
case 'R': realtime = true; break;
case 'P': precise = true; break;
case 'F': formant = true; break;
case '0': threading = 1; break;
case '@': threading = 2; break;
case '1': transients = NoTransients; crispchanged = true; break;
case '2': lamination = false; crispchanged = true; break;
case '3': longwin = true; crispchanged = true; break;
case '4': shortwin = true; crispchanged = true; break;
case '8': transients = BandLimitedTransients; crispchanged = true; break;
case '%': hqpitch = true; break;
case 'c': crispness = atoi(optarg); break;
case 'q': quiet = true; break;
default: help = true; break;
}
}
if (version) {
cerr << RUBBERBAND_VERSION << endl;
return 0;
}
if (help || !haveRatio || optind + 2 != argc) {
cerr << endl;
cerr << "Rubber Band" << endl;
cerr << "An audio time-stretching and pitch-shifting library and utility program." << endl;
cerr << "Copyright 2008 Chris Cannam. Distributed under the GNU General Public License." << endl;
cerr << endl;
cerr << " Usage: " << argv[0] << " [options] <infile.wav> <outfile.wav>" << endl;
cerr << endl;
cerr << "You must specify at least one of the following time and pitch ratio options." << endl;
cerr << endl;
cerr << " -t<X>, --time <X> Stretch to X times original duration, or" << endl;
cerr << " -T<X>, --tempo <X> Change tempo by multiple X (same as --time 1/X), or" << endl;
cerr << " -T<X>, --tempo <X>:<Y> Change tempo from X to Y (same as --time X/Y), or" << endl;
cerr << " -D<X>, --duration <X> Stretch or squash to make output file X seconds long" << endl;
cerr << endl;
cerr << " -p<X>, --pitch <X> Raise pitch by X semitones, or" << endl;
cerr << " -f<X>, --frequency <X> Change frequency by multiple X" << endl;
cerr << endl;
cerr << "The following options provide a simple way to adjust the sound. See below" << endl;
cerr << "for more details." << endl;
cerr << endl;
cerr << " -c<N>, --crisp <N> Crispness (N = 0,1,2,3,4,5); default 4 (see below)" << endl;
cerr << " -F, --formant Enable formant preservation when pitch shifting" << endl;
cerr << endl;
cerr << "The remaining options fine-tune the processing mode and stretch algorithm." << endl;
cerr << "These are mostly included for test purposes; the default settings and standard" << endl;
cerr << "crispness parameter are intended to provide the best sounding set of options" << endl;
cerr << "for most situations. The default is to use none of these options." << endl;
cerr << endl;
cerr << " -P, --precise Aim for minimal time distortion (implied by -R)" << endl;
cerr << " -R, --realtime Select realtime mode (implies -P --no-threads)" << endl;
cerr << " --no-threads No extra threads regardless of CPU and channel count" << endl;
cerr << " --threads Assume multi-CPU even if only one CPU is identified" << endl;
cerr << " --no-transients Disable phase resynchronisation at transients" << endl;
cerr << " --bl-transients Band-limit phase resync to extreme frequencies" << endl;
cerr << " --no-lamination Disable phase lamination" << endl;
cerr << " --window-long Use longer processing window (actual size may vary)" << endl;
cerr << " --window-short Use shorter processing window" << endl;
cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl;
cerr << endl;
cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl;
cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl;
cerr << " -q, --quiet Suppress progress output" << endl;
cerr << endl;
cerr << " -V, --version Show version number and exit" << endl;
cerr << " -h, --help Show this help" << endl;
cerr << endl;
cerr << "\"Crispness\" levels:" << endl;
cerr << " -c 0 equivalent to --no-transients --no-lamination --window-long" << endl;
cerr << " -c 1 equivalent to --no-transients --no-lamination" << endl;
cerr << " -c 2 equivalent to --no-transients" << endl;
cerr << " -c 3 equivalent to --bl-transients" << endl;
cerr << " -c 4 default processing options" << endl;
cerr << " -c 5 equivalent to --no-lamination --window-short (may be good for drums)" << endl;
cerr << endl;
return 2;
}
if (crispness >= 0 && crispchanged) {
cerr << "WARNING: Both crispness option and transients, lamination or window options" << endl;
cerr << " provided -- crispness will override these other options" << endl;
}
switch (crispness) {
case -1: crispness = 4; break;
case 0: transients = NoTransients; lamination = false; longwin = true; shortwin = false; break;
case 1: transients = NoTransients; lamination = false; longwin = false; shortwin = false; break;
case 2: transients = NoTransients; lamination = true; longwin = false; shortwin = false; break;
case 3: transients = BandLimitedTransients; lamination = true; longwin = false; shortwin = false; break;
case 4: transients = Transients; lamination = true; longwin = false; shortwin = false; break;
case 5: transients = Transients; lamination = false; longwin = false; shortwin = true; break;
};
if (!quiet) {
cerr << "Using crispness level: " << crispness << " (";
switch (crispness) {
case 0: cerr << "Mushy"; break;
case 1: cerr << "Smooth"; break;
case 2: cerr << "Balanced multitimbral mixture"; break;
case 3: cerr << "Unpitched percussion with stable notes"; break;
case 4: cerr << "Crisp monophonic instrumental"; break;
case 5: cerr << "Unpitched solo percussion"; break;
}
cerr << ")" << endl;
}
char *fileName = strdup(argv[optind++]);
char *fileNameOut = strdup(argv[optind++]);
SNDFILE *sndfile;
SNDFILE *sndfileOut;
SF_INFO sfinfo;
SF_INFO sfinfoOut;
memset(&sfinfo, 0, sizeof(SF_INFO));
sndfile = sf_open(fileName, SFM_READ, &sfinfo);
if (!sndfile) {
cerr << "ERROR: Failed to open input file \"" << fileName << "\": "
<< sf_strerror(sndfile) << endl;
return 1;
}
if (duration != 0.0) {
if (sfinfo.frames == 0 || sfinfo.samplerate == 0) {
cerr << "ERROR: File lacks frame count or sample rate in header, cannot use --duration" << endl;
return 1;
}
double induration = double(sfinfo.frames) / double(sfinfo.samplerate);
if (induration != 0.0) ratio = duration / induration;
}
sfinfoOut.channels = sfinfo.channels;
sfinfoOut.format = sfinfo.format;
sfinfoOut.frames = int(sfinfo.frames * ratio + 0.1);
sfinfoOut.samplerate = sfinfo.samplerate;
sfinfoOut.sections = sfinfo.sections;
sfinfoOut.seekable = sfinfo.seekable;
sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut) ;
if (!sndfileOut) {
cerr << "ERROR: Failed to open output file \"" << fileNameOut << "\" for writing: "
<< sf_strerror(sndfileOut) << endl;
return 1;
}
int ibs = 1024;
size_t channels = sfinfo.channels;
RubberBandStretcher::Options options = 0;
if (realtime) options |= RubberBandStretcher::OptionProcessRealTime;
if (precise) options |= RubberBandStretcher::OptionStretchPrecise;
if (!lamination) options |= RubberBandStretcher::OptionPhaseIndependent;
if (longwin) options |= RubberBandStretcher::OptionWindowLong;
if (shortwin) options |= RubberBandStretcher::OptionWindowShort;
if (formant) options |= RubberBandStretcher::OptionFormantPreserved;
if (hqpitch) options |= RubberBandStretcher::OptionPitchHighQuality;
switch (threading) {
case 0:
options |= RubberBandStretcher::OptionThreadingAuto;
break;
case 1:
options |= RubberBandStretcher::OptionThreadingNever;
break;
case 2:
options |= RubberBandStretcher::OptionThreadingAlways;
break;
}
switch (transients) {
case NoTransients:
options |= RubberBandStretcher::OptionTransientsSmooth;
break;
case BandLimitedTransients:
options |= RubberBandStretcher::OptionTransientsMixed;
break;
case Transients:
options |= RubberBandStretcher::OptionTransientsCrisp;
break;
}
if (pitchshift != 0.0) {
frequencyshift *= pow(2.0, pitchshift / 12);
}
cerr << "Using time ratio " << ratio;
cerr << " and frequency ratio " << frequencyshift << endl;
#ifdef _WIN32
RubberBand::
#endif
timeval tv;
(void)gettimeofday(&tv, 0);
RubberBandStretcher::setDefaultDebugLevel(debug);
RubberBandStretcher ts(sfinfo.samplerate, channels, options,
ratio, frequencyshift);
ts.setExpectedInputDuration(sfinfo.frames);
float *fbuf = new float[channels * ibs];
float **ibuf = new float *[channels];
for (size_t i = 0; i < channels; ++i) ibuf[i] = new float[ibs];
int frame = 0;
int percent = 0;
sf_seek(sndfile, 0, SEEK_SET);
if (!realtime) {
if (!quiet) {
cerr << "Pass 1: Studying..." << endl;
}
while (frame < sfinfo.frames) {
int count = -1;
if ((count = sf_readf_float(sndfile, fbuf, ibs)) <= 0) break;
for (size_t c = 0; c < channels; ++c) {
for (int i = 0; i < count; ++i) {
float value = fbuf[i * channels + c];
ibuf[c][i] = value;
}
}
bool final = (frame + ibs >= sfinfo.frames);
ts.study(ibuf, count, final);
int p = int((double(frame) * 100.0) / sfinfo.frames);
if (p > percent || frame == 0) {
percent = p;
if (!quiet) {
cerr << "\r" << percent << "% ";
}
}
frame += ibs;
}
if (!quiet) {
cerr << "\rCalculating profile..." << endl;
}
sf_seek(sndfile, 0, SEEK_SET);
}
frame = 0;
percent = 0;
size_t countIn = 0, countOut = 0;
while (frame < sfinfo.frames) {
int count = -1;
if ((count = sf_readf_float(sndfile, fbuf, ibs)) < 0) break;
countIn += count;
for (size_t c = 0; c < channels; ++c) {
for (int i = 0; i < count; ++i) {
float value = fbuf[i * channels + c];
ibuf[c][i] = value;
}
}
bool final = (frame + ibs >= sfinfo.frames);
ts.process(ibuf, count, final);
int avail = ts.available();
if (debug > 1) cerr << "available = " << avail << endl;
if (avail > 0) {
float **obf = new float *[channels];
for (size_t i = 0; i < channels; ++i) {
obf[i] = new float[avail];
}
ts.retrieve(obf, avail);
countOut += avail;
float *fobf = new float[channels * avail];
for (size_t c = 0; c < channels; ++c) {
for (int i = 0; i < avail; ++i) {
float value = obf[c][i];
if (value > 1.f) value = 1.f;
if (value < -1.f) value = -1.f;
fobf[i * channels + c] = value;
}
}
// cout << "fobf mean: ";
// double d = 0;
// for (int i = 0; i < avail; ++i) {
// d += fobf[i];
// }
// d /= avail;
// cout << d << endl;
sf_writef_float(sndfileOut, fobf, avail);
delete[] fobf;
for (size_t i = 0; i < channels; ++i) {
delete[] obf[i];
}
delete[] obf;
}
if (frame == 0 && !realtime && !quiet) {
cerr << "Pass 2: Processing..." << endl;
}
int p = int((double(frame) * 100.0) / sfinfo.frames);
if (p > percent || frame == 0) {
percent = p;
if (!quiet) {
cerr << "\r" << percent << "% ";
}
}
frame += ibs;
}
if (!quiet) {
cerr << "\r " << endl;
}
int avail;
while ((avail = ts.available()) >= 0) {
if (debug > 1) {
cerr << "(completing) available = " << avail << endl;
}
if (avail > 0) {
float **obf = new float *[channels];
for (size_t i = 0; i < channels; ++i) {
obf[i] = new float[avail];
}
ts.retrieve(obf, avail);
countOut += avail;
float *fobf = new float[channels * avail];
for (size_t c = 0; c < channels; ++c) {
for (int i = 0; i < avail; ++i) {
float value = obf[c][i];
if (value > 1.f) value = 1.f;
if (value < -1.f) value = -1.f;
fobf[i * channels + c] = value;
}
}
sf_writef_float(sndfileOut, fobf, avail);
delete[] fobf;
for (size_t i = 0; i < channels; ++i) {
delete[] obf[i];
}
delete[] obf;
} else {
usleep(10000);
}
}
sf_close(sndfile);
sf_close(sndfileOut);
if (!quiet) {
cerr << "in: " << countIn << ", out: " << countOut << ", ratio: " << float(countOut)/float(countIn) << ", ideal output: " << lrint(countIn * ratio) << ", error: " << abs(lrint(countIn * ratio) - int(countOut)) << endl;
#ifdef _WIN32
RubberBand::
#endif
timeval etv;
(void)gettimeofday(&etv, 0);
etv.tv_sec -= tv.tv_sec;
if (etv.tv_usec < tv.tv_usec) {
etv.tv_usec += 1000000;
etv.tv_sec -= 1;
}
etv.tv_usec -= tv.tv_usec;
double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0);
cerr << "elapsed time: " << sec << " sec, in frames/sec: " << countIn/sec << ", out frames/sec: " << countOut/sec << endl;
}
Profiler::dump();
return 0;
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -12,8 +12,8 @@
COPYING included with this distribution for more information.
*/
#include "rubberband-c.h"
#include "RubberBandStretcher.h"
#include "rubberband/rubberband-c.h"
#include "rubberband/RubberBandStretcher.h"
struct RubberBandState_
{

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -213,12 +213,6 @@ Condition::~Condition()
void
Condition::lock()
{
if (m_locked) {
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Already locked " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
return;
}
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
@@ -248,8 +242,6 @@ Condition::unlock()
void
Condition::wait(int us)
{
if (!m_locked) lock();
if (us == 0) {
#ifdef DEBUG_CONDITION
@@ -270,12 +262,10 @@ Condition::wait(int us)
WaitForSingleObject(m_mutex, INFINITE);
}
ReleaseMutex(m_mutex);
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
m_locked = false;
m_locked = true;
}
void
@@ -478,12 +468,6 @@ Condition::~Condition()
void
Condition::lock()
{
if (m_locked) {
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Already locked " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
return;
}
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
@@ -513,8 +497,6 @@ Condition::unlock()
void
Condition::wait(int us)
{
if (!m_locked) lock();
if (us == 0) {
#ifdef DEBUG_CONDITION
@@ -543,12 +525,10 @@ Condition::wait(int us)
pthread_cond_timedwait(&m_condition, &m_mutex, &timeout);
}
pthread_mutex_unlock(&m_mutex);
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
m_locked = false;
m_locked = true;
}
void

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -105,16 +105,20 @@ public:
Condition(std::string name);
~Condition();
// To wait on a condition, either simply call wait(), or call
// lock() and then wait() (perhaps testing some state in between).
// To signal a condition, call signal().
// The Condition class bundles a condition variable and mutex.
// To wait on a condition, call lock(), test the termination
// condition if desired, then wait(). The condition will be
// unlocked during the wait and re-locked when wait() returns
// (which will happen when the condition is signalled or the timer
// times out).
// To signal a condition, call signal(). If the condition is
// signalled between lock() and wait(), the signal may be missed
// by the waiting thread. To avoid this, the signalling thread
// should also lock the condition before calling signal() and
// unlock it afterwards.
// Although any thread may signal on a given condition, only one
// thread should ever wait on any given condition object --
// otherwise there will be a race conditions in the logic that
// avoids the thread code having to track whether the condition's
// mutex is locked or not. If that is your requirement, this
// Condition wrapper is not for you.
void lock();
void unlock();
void wait(int us = 0);

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
Copyright 2007-2009 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -16,7 +16,11 @@
#ifdef _WIN32
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#else /* !_WIN32 */
#include <signal.h>
#include <unistd.h>
#ifdef __APPLE__
#include <sys/sysctl.h>
#else /* !__APPLE__, !_WIN32 */
@@ -25,12 +29,44 @@
#endif /* !__APPLE__, !_WIN32 */
#endif /* !_WIN32 */
#ifdef __sun
#include <sys/processor.h>
#endif
#include <cstdlib>
#include <iostream>
#ifdef _WIN32
#include <fstream>
#endif
namespace RubberBand {
const char *
system_get_platform_tag()
{
#ifdef _WIN32
return "win32";
#else /* !_WIN32 */
#ifdef __APPLE__
return "osx";
#else /* !__APPLE__ */
#ifdef __LINUX__
if (sizeof(long) == 8) {
return "linux64";
} else {
return "linux";
}
#else /* !__LINUX__ */
return "posix";
#endif /* !__LINUX__ */
#endif /* !__APPLE__ */
#endif /* !_WIN32 */
}
bool
system_is_multiprocessor()
{
@@ -50,13 +86,27 @@ system_is_multiprocessor()
size_t sz = sizeof(count);
if (sysctlbyname("hw.ncpu", &count, &sz, NULL, 0)) {
count = 0;
mp = false;
} else {
mp = (count > 1);
}
#else /* !__APPLE__, !_WIN32 */
#ifdef __sun
processorid_t i, n;
n = sysconf(_SC_CPUID_MAX);
for (i = 0; i <= n; ++i) {
int status = p_online(i, P_STATUS);
if (status == P_ONLINE) {
++count;
}
if (count > 1) break;
}
#else /* !__sun, !__APPLE__, !_WIN32 */
//...
FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
@@ -64,7 +114,7 @@ system_is_multiprocessor()
char buf[256];
while (!feof(cpuinfo)) {
fgets(buf, 256, cpuinfo);
if (!fgets(buf, 256, cpuinfo)) break;
if (!strncmp(buf, "processor", 9)) {
++count;
}
@@ -73,6 +123,7 @@ system_is_multiprocessor()
fclose(cpuinfo);
#endif /* !__sun, !__APPLE__, !_WIN32 */
#endif /* !__APPLE__, !_WIN32 */
#endif /* !_WIN32 */
@@ -83,7 +134,7 @@ system_is_multiprocessor()
#ifdef _WIN32
int gettimeofday(struct timeval *tv, void *tz)
void gettimeofday(struct timeval *tv, void *tz)
{
union {
long long ns100;
@@ -93,7 +144,6 @@ int gettimeofday(struct timeval *tv, void *tz)
::GetSystemTimeAsFileTime(&now.ft);
tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL);
tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL);
return 0;
}
void usleep(unsigned long usec)
@@ -103,55 +153,39 @@ void usleep(unsigned long usec)
#endif
float *allocFloat(float *ptr, int count)
void system_specific_initialise()
{
if (ptr) free((void *)ptr);
void *allocated;
#ifndef _WIN32
#ifndef __APPLE__
if (posix_memalign(&allocated, 16, count * sizeof(float)))
}
void system_specific_application_initialise()
{
}
ProcessStatus
GetProcessStatus(int pid)
{
#ifdef _WIN32
HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!handle) {
return ProcessNotRunning;
} else {
CloseHandle(handle);
return ProcessRunning;
}
#else
if (kill(getpid(), 0) == 0) {
if (kill(pid, 0) == 0) {
return ProcessRunning;
} else {
return ProcessNotRunning;
}
} else {
return UnknownProcessStatus;
}
#endif
#endif
allocated = malloc(count * sizeof(float));
for (int i = 0; i < count; ++i) ((float *)allocated)[i] = 0.f;
return (float *)allocated;
}
float *allocFloat(int count)
{
return allocFloat(0, count);
}
void freeFloat(float *ptr)
{
if (ptr) free(ptr);
}
double *allocDouble(double *ptr, int count)
{
if (ptr) free((void *)ptr);
void *allocated;
#ifndef _WIN32
#ifndef __APPLE__
if (posix_memalign(&allocated, 16, count * sizeof(double)))
#endif
#endif
allocated = malloc(count * sizeof(double));
for (int i = 0; i < count; ++i) ((double *)allocated)[i] = 0.f;
return (double *)allocated;
}
double *allocDouble(int count)
{
return allocDouble(0, count);
}
void freeDouble(double *ptr)
{
if (ptr) free(ptr);
}
}

111
src/system/sysutils.h Normal file
View File

@@ -0,0 +1,111 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2009 Chris Cannam.
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.
*/
#ifndef _RUBBERBAND_SYSUTILS_H_
#define _RUBBERBAND_SYSUTILS_H_
#ifdef __MSVC__
#include <float_cast/float_cast.h>
#define R__ __restrict
#endif
#ifdef __GNUC__
#define R__ __restrict__
#endif
#ifndef R__
#define R__
#endif
#ifdef __MINGW32__
#include <malloc.h>
#endif
#ifdef __MSVC__
#define alloca _alloca
#define getpid _getpid
#endif
#ifdef __MSVC__
#define uint8_t unsigned __int8
#define uint16_t unsigned __int16
#define uint32_t unsigned __int32
#define ssize_t long
#else
#include <stdint.h>
#endif
#include <math.h>
namespace RubberBand {
extern const char *system_get_platform_tag();
extern bool system_is_multiprocessor();
extern void system_specific_initialise();
extern void system_specific_application_initialise();
#ifdef _WIN32
struct timeval { long tv_sec; long tv_usec; };
void gettimeofday(struct timeval *p, void *tz);
void usleep(unsigned long);
#endif
enum ProcessStatus { ProcessRunning, ProcessNotRunning, UnknownProcessStatus };
extern ProcessStatus GetProcessStatus(int pid);
inline double mod(double x, double y) { return x - (y * floor(x / y)); }
inline float modf(float x, float y) { return x - (y * float(floor(x / y))); }
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
inline double princarg(double a) { return mod(a + M_PI, -2.0 * M_PI) + M_PI; }
inline float princargf(float a) { return modf(a + (float)M_PI, -2.f * (float)M_PI) + (float)M_PI; }
} // end namespace
// The following should be functions in the RubberBand namespace, really
#ifdef _WIN32
#define MLOCK(a,b) 1
#define MUNLOCK(a,b) 1
#define MUNLOCK_SAMPLEBLOCK(a) 1
#define DLOPEN(a,b) LoadLibrary((a).toStdWString().c_str())
#define DLSYM(a,b) GetProcAddress((HINSTANCE)(a),(b))
#define DLCLOSE(a) FreeLibrary((HINSTANCE)(a))
#define DLERROR() ""
#else
#include <sys/mman.h>
#include <dlfcn.h>
#define MLOCK(a,b) ::mlock((char *)(a),(b))
#define MUNLOCK(a,b) (::munlock((char *)(a),(b)) ? (::perror("munlock failed"), 0) : 0)
#define MUNLOCK_SAMPLEBLOCK(a) do { if (!(a).empty()) { const float &b = *(a).begin(); MUNLOCK(&b, (a).capacity() * sizeof(float)); } } while(0);
#define DLOPEN(a,b) dlopen((a).toStdString().c_str(),(b))
#define DLSYM(a,b) dlsym((a),(b))
#define DLCLOSE(a) dlclose((a))
#define DLERROR() dlerror()
#endif
#endif

View File

@@ -1,62 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#ifndef _RUBBERBAND_SYSINFO_H_
#define _RUBBERBAND_SYSINFO_H_
#ifdef __MSVC__
#include "bsd-3rdparty/float_cast/float_cast.h"
#define R__ __restrict
#endif
#ifdef __GNUC__
#define R__ __restrict__
#endif
#ifndef R__
#define R__
#endif
#ifdef __MINGW32__
#include <malloc.h>
#endif
#ifdef __MSVC__
#define alloca _alloca
#endif
namespace RubberBand {
extern bool system_is_multiprocessor();
#ifdef _WIN32
struct timeval { long tv_sec; long tv_usec; };
int gettimeofday(struct timeval *p, void *tz);
void usleep(unsigned long);
#endif
extern float *allocFloat(int);
extern float *allocFloat(float *, int);
extern void freeFloat(float *);
extern double *allocDouble(int);
extern double *allocDouble(double *, int);
extern void freeDouble(double *);
}
#endif

View File

@@ -1,648 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include "RubberBandVampPlugin.h"
#include "StretchCalculator.h"
#include "sysutils.h"
#include <cmath>
using std::string;
using std::vector;
using std::cerr;
using std::endl;
class RubberBandVampPlugin::Impl
{
public:
size_t m_stepSize;
size_t m_blockSize;
size_t m_sampleRate;
float m_timeRatio;
float m_pitchRatio;
bool m_realtime;
bool m_elasticTiming;
int m_transientMode;
bool m_phaseIndependent;
int m_windowLength;
RubberBand::RubberBandStretcher *m_stretcher;
int m_incrementsOutput;
int m_aggregateIncrementsOutput;
int m_divergenceOutput;
int m_phaseResetDfOutput;
int m_smoothedPhaseResetDfOutput;
int m_phaseResetPointsOutput;
int m_timeSyncPointsOutput;
size_t m_counter;
size_t m_accumulatedIncrement;
float **m_outputDump;
FeatureSet processOffline(const float *const *inputBuffers,
Vamp::RealTime timestamp);
FeatureSet getRemainingFeaturesOffline();
FeatureSet processRealTime(const float *const *inputBuffers,
Vamp::RealTime timestamp);
FeatureSet getRemainingFeaturesRealTime();
FeatureSet createFeatures(size_t inputIncrement,
std::vector<int> &outputIncrements,
std::vector<float> &phaseResetDf,
std::vector<int> &exactPoints,
std::vector<float> &smoothedDf,
size_t baseCount,
bool includeFinal);
};
RubberBandVampPlugin::RubberBandVampPlugin(float inputSampleRate) :
Plugin(inputSampleRate)
{
m_d = new Impl();
m_d->m_stepSize = 0;
m_d->m_timeRatio = 1.f;
m_d->m_pitchRatio = 1.f;
m_d->m_realtime = false;
m_d->m_elasticTiming = true;
m_d->m_transientMode = 0;
m_d->m_phaseIndependent = false;
m_d->m_windowLength = 0;
m_d->m_stretcher = 0;
m_d->m_sampleRate = lrintf(m_inputSampleRate);
}
RubberBandVampPlugin::~RubberBandVampPlugin()
{
if (m_d->m_outputDump) {
for (size_t i = 0; i < m_d->m_stretcher->getChannelCount(); ++i) {
delete[] m_d->m_outputDump[i];
}
delete[] m_d->m_outputDump;
}
delete m_d->m_stretcher;
delete m_d;
}
string
RubberBandVampPlugin::getIdentifier() const
{
return "rubberband";
}
string
RubberBandVampPlugin::getName() const
{
return "Rubber Band Timestretch Analysis";
}
string
RubberBandVampPlugin::getDescription() const
{
return "Carry out analysis phases of time stretcher process";
}
string
RubberBandVampPlugin::getMaker() const
{
return "Breakfast Quay";
}
int
RubberBandVampPlugin::getPluginVersion() const
{
return 1;
}
string
RubberBandVampPlugin::getCopyright() const
{
return "";//!!!
}
RubberBandVampPlugin::OutputList
RubberBandVampPlugin::getOutputDescriptors() const
{
OutputList list;
size_t rate = 0;
if (m_d->m_stretcher) {
rate = lrintf(m_inputSampleRate / m_d->m_stretcher->getInputIncrement());
}
OutputDescriptor d;
d.identifier = "increments";
d.name = "Output Increments";
d.description = "Output time increment for each input step";
d.unit = "samples";
d.hasFixedBinCount = true;
d.binCount = 1;
d.hasKnownExtents = false;
d.isQuantized = true;
d.quantizeStep = 1.0;
d.sampleType = OutputDescriptor::VariableSampleRate;
d.sampleRate = float(rate);
m_d->m_incrementsOutput = list.size();
list.push_back(d);
d.identifier = "aggregate_increments";
d.name = "Accumulated Output Increments";
d.description = "Accumulated output time increments";
d.sampleRate = 0;
m_d->m_aggregateIncrementsOutput = list.size();
list.push_back(d);
d.identifier = "divergence";
d.name = "Divergence from Linear";
d.description = "Difference between actual output time and the output time for a theoretical linear stretch";
d.isQuantized = false;
d.sampleRate = 0;
m_d->m_divergenceOutput = list.size();
list.push_back(d);
d.identifier = "phaseresetdf";
d.name = "Phase Reset Detection Function";
d.description = "Curve whose peaks are used to identify transients for phase reset points";
d.unit = "";
d.sampleRate = float(rate);
m_d->m_phaseResetDfOutput = list.size();
list.push_back(d);
d.identifier = "smoothedphaseresetdf";
d.name = "Smoothed Phase Reset Detection Function";
d.description = "Phase reset curve smoothed for peak picking";
d.unit = "";
m_d->m_smoothedPhaseResetDfOutput = list.size();
list.push_back(d);
d.identifier = "phaseresetpoints";
d.name = "Phase Reset Points";
d.description = "Points estimated as transients at which phase reset occurs";
d.unit = "";
d.hasFixedBinCount = true;
d.binCount = 0;
d.hasKnownExtents = false;
d.isQuantized = false;
d.sampleRate = 0;
m_d->m_phaseResetPointsOutput = list.size();
list.push_back(d);
d.identifier = "timesyncpoints";
d.name = "Time Sync Points";
d.description = "Salient points which stretcher aims to place with strictly correct timing";
d.unit = "";
d.hasFixedBinCount = true;
d.binCount = 0;
d.hasKnownExtents = false;
d.isQuantized = false;
d.sampleRate = 0;
m_d->m_timeSyncPointsOutput = list.size();
list.push_back(d);
return list;
}
RubberBandVampPlugin::ParameterList
RubberBandVampPlugin::getParameterDescriptors() const
{
ParameterList list;
ParameterDescriptor d;
d.identifier = "timeratio";
d.name = "Time Ratio";
d.description = "Ratio to modify overall duration by";
d.unit = "%";
d.minValue = 1;
d.maxValue = 500;
d.defaultValue = 100;
d.isQuantized = false;
list.push_back(d);
d.identifier = "pitchratio";
d.name = "Pitch Scale Ratio";
d.description = "Frequency ratio to modify pitch by";
d.unit = "%";
d.minValue = 1;
d.maxValue = 500;
d.defaultValue = 100;
d.isQuantized = false;
list.push_back(d);
d.identifier = "mode";
d.name = "Processing Mode";
d.description = ""; //!!!
d.unit = "";
d.minValue = 0;
d.maxValue = 1;
d.defaultValue = 0;
d.isQuantized = true;
d.quantizeStep = 1;
d.valueNames.clear();
d.valueNames.push_back("Offline");
d.valueNames.push_back("Real Time");
list.push_back(d);
d.identifier = "stretchtype";
d.name = "Stretch Flexibility";
d.description = ""; //!!!
d.unit = "";
d.minValue = 0;
d.maxValue = 1;
d.defaultValue = 0;
d.isQuantized = true;
d.quantizeStep = 1;
d.valueNames.clear();
d.valueNames.push_back("Elastic");
d.valueNames.push_back("Precise");
list.push_back(d);
d.identifier = "transientmode";
d.name = "Transient Handling";
d.description = ""; //!!!
d.unit = "";
d.minValue = 0;
d.maxValue = 2;
d.defaultValue = 0;
d.isQuantized = true;
d.quantizeStep = 1;
d.valueNames.clear();
d.valueNames.push_back("Mixed");
d.valueNames.push_back("Smooth");
d.valueNames.push_back("Crisp");
list.push_back(d);
d.identifier = "phasemode";
d.name = "Phase Handling";
d.description = ""; //!!!
d.unit = "";
d.minValue = 0;
d.maxValue = 1;
d.defaultValue = 0;
d.isQuantized = true;
d.quantizeStep = 1;
d.valueNames.clear();
d.valueNames.push_back("Peak Locked");
d.valueNames.push_back("Independent");
list.push_back(d);
d.identifier = "windowmode";
d.name = "Window Length";
d.description = ""; //!!!
d.unit = "";
d.minValue = 0;
d.maxValue = 2;
d.defaultValue = 0;
d.isQuantized = true;
d.quantizeStep = 1;
d.valueNames.clear();
d.valueNames.push_back("Standard");
d.valueNames.push_back("Short");
d.valueNames.push_back("Long");
list.push_back(d);
return list;
}
float
RubberBandVampPlugin::getParameter(std::string id) const
{
if (id == "timeratio") return m_d->m_timeRatio * 100.f;
if (id == "pitchratio") return m_d->m_pitchRatio * 100.f;
if (id == "mode") return m_d->m_realtime ? 1.f : 0.f;
if (id == "stretchtype") return m_d->m_elasticTiming ? 0.f : 1.f;
if (id == "transientmode") return float(m_d->m_transientMode);
if (id == "phasemode") return m_d->m_phaseIndependent ? 1.f : 0.f;
if (id == "windowmode") return float(m_d->m_windowLength);
return 0.f;
}
void
RubberBandVampPlugin::setParameter(std::string id, float value)
{
if (id == "timeratio") {
m_d->m_timeRatio = value / 100;
} else if (id == "pitchratio") {
m_d->m_pitchRatio = value / 100;
} else {
bool set = (value > 0.5);
if (id == "mode") m_d->m_realtime = set;
else if (id == "stretchtype") m_d->m_elasticTiming = !set;
else if (id == "transientmode") m_d->m_transientMode = int(value + 0.5);
else if (id == "phasemode") m_d->m_phaseIndependent = set;
else if (id == "windowmode") m_d->m_windowLength = int(value + 0.5);
}
}
bool
RubberBandVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
if (channels < getMinChannelCount() ||
channels > getMaxChannelCount()) return false;
m_d->m_stepSize = std::min(stepSize, blockSize);
m_d->m_blockSize = stepSize;
RubberBand::RubberBandStretcher::Options options = 0;
if (m_d->m_realtime)
options |= RubberBand::RubberBandStretcher::OptionProcessRealTime;
else options |= RubberBand::RubberBandStretcher::OptionProcessOffline;
if (m_d->m_elasticTiming)
options |= RubberBand::RubberBandStretcher::OptionStretchElastic;
else options |= RubberBand::RubberBandStretcher::OptionStretchPrecise;
if (m_d->m_transientMode == 0)
options |= RubberBand::RubberBandStretcher::OptionTransientsMixed;
else if (m_d->m_transientMode == 1)
options |= RubberBand::RubberBandStretcher::OptionTransientsSmooth;
else options |= RubberBand::RubberBandStretcher::OptionTransientsCrisp;
if (m_d->m_phaseIndependent)
options |= RubberBand::RubberBandStretcher::OptionPhaseIndependent;
else options |= RubberBand::RubberBandStretcher::OptionPhaseLaminar;
if (m_d->m_windowLength == 0)
options |= RubberBand::RubberBandStretcher::OptionWindowStandard;
else if (m_d->m_windowLength == 1)
options |= RubberBand::RubberBandStretcher::OptionWindowShort;
else options |= RubberBand::RubberBandStretcher::OptionWindowLong;
delete m_d->m_stretcher;
m_d->m_stretcher = new RubberBand::RubberBandStretcher
(m_d->m_sampleRate, channels, options);
m_d->m_stretcher->setDebugLevel(1);
m_d->m_stretcher->setTimeRatio(m_d->m_timeRatio);
m_d->m_stretcher->setPitchScale(m_d->m_pitchRatio);
m_d->m_counter = 0;
m_d->m_accumulatedIncrement = 0;
m_d->m_outputDump = 0;
return true;
}
void
RubberBandVampPlugin::reset()
{
// delete m_stretcher; //!!! or just if (m_stretcher) m_stretcher->reset();
// m_stretcher = new RubberBand::RubberBandStretcher(lrintf(m_inputSampleRate), channels);
if (m_d->m_stretcher) m_d->m_stretcher->reset();
}
RubberBandVampPlugin::FeatureSet
RubberBandVampPlugin::process(const float *const *inputBuffers,
Vamp::RealTime timestamp)
{
if (m_d->m_realtime) {
return m_d->processRealTime(inputBuffers, timestamp);
} else {
return m_d->processOffline(inputBuffers, timestamp);
}
}
RubberBandVampPlugin::FeatureSet
RubberBandVampPlugin::getRemainingFeatures()
{
if (m_d->m_realtime) {
return m_d->getRemainingFeaturesRealTime();
} else {
return m_d->getRemainingFeaturesOffline();
}
}
RubberBandVampPlugin::FeatureSet
RubberBandVampPlugin::Impl::processOffline(const float *const *inputBuffers,
Vamp::RealTime timestamp)
{
if (!m_stretcher) {
cerr << "ERROR: RubberBandVampPlugin::processOffline: "
<< "RubberBandVampPlugin has not been initialised"
<< endl;
return FeatureSet();
}
m_stretcher->study(inputBuffers, m_blockSize, false);
return FeatureSet();
}
RubberBandVampPlugin::FeatureSet
RubberBandVampPlugin::Impl::getRemainingFeaturesOffline()
{
m_stretcher->study(0, 0, true);
m_stretcher->calculateStretch();
int rate = m_sampleRate;
RubberBand::StretchCalculator sc(rate,
m_stretcher->getInputIncrement(),
true);
size_t inputIncrement = m_stretcher->getInputIncrement();
std::vector<int> outputIncrements = m_stretcher->getOutputIncrements();
std::vector<float> phaseResetDf = m_stretcher->getPhaseResetCurve();
std::vector<int> peaks = m_stretcher->getExactTimePoints();
std::vector<float> smoothedDf = sc.smoothDF(phaseResetDf);
FeatureSet features = createFeatures
(inputIncrement, outputIncrements, phaseResetDf, peaks, smoothedDf,
0, true);
return features;
}
RubberBandVampPlugin::FeatureSet
RubberBandVampPlugin::Impl::processRealTime(const float *const *inputBuffers,
Vamp::RealTime timestamp)
{
// This function is not in any way a real-time function (i.e. it
// has no requirement to be RT safe); it simply operates the
// stretcher in RT mode.
if (!m_stretcher) {
cerr << "ERROR: RubberBandVampPlugin::processRealTime: "
<< "RubberBandVampPlugin has not been initialised"
<< endl;
return FeatureSet();
}
m_stretcher->process(inputBuffers, m_blockSize, false);
size_t inputIncrement = m_stretcher->getInputIncrement();
std::vector<int> outputIncrements = m_stretcher->getOutputIncrements();
std::vector<float> phaseResetDf = m_stretcher->getPhaseResetCurve();
std::vector<float> smoothedDf; // not meaningful in RT mode
std::vector<int> dummyPoints;
FeatureSet features = createFeatures
(inputIncrement, outputIncrements, phaseResetDf, dummyPoints, smoothedDf,
m_counter, false);
m_counter += outputIncrements.size();
int available = 0;
while ((available = m_stretcher->available()) > 0) {
if (!m_outputDump) {
m_outputDump = new float *[m_stretcher->getChannelCount()];
for (size_t i = 0; i < m_stretcher->getChannelCount(); ++i) {
m_outputDump[i] = new float[m_blockSize];
}
}
m_stretcher->retrieve(m_outputDump,
std::min(int(m_blockSize), available));
}
return features;
}
RubberBandVampPlugin::FeatureSet
RubberBandVampPlugin::Impl::getRemainingFeaturesRealTime()
{
return FeatureSet();
}
RubberBandVampPlugin::FeatureSet
RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement,
std::vector<int> &outputIncrements,
std::vector<float> &phaseResetDf,
std::vector<int> &exactPoints,
std::vector<float> &smoothedDf,
size_t baseCount,
bool includeFinal)
{
size_t actual = m_accumulatedIncrement;
double overallRatio = m_timeRatio * m_pitchRatio;
char label[200];
FeatureSet features;
int rate = m_sampleRate;
size_t epi = 0;
for (size_t i = 0; i < outputIncrements.size(); ++i) {
size_t frame = (baseCount + i) * inputIncrement;
int oi = outputIncrements[i];
bool hard = false;
bool soft = false;
if (oi < 0) {
oi = -oi;
hard = true;
}
if (epi < exactPoints.size() && int(i) == exactPoints[epi]) {
soft = true;
++epi;
}
double linear = (frame * overallRatio);
Vamp::RealTime t = Vamp::RealTime::frame2RealTime(frame, rate);
Feature feature;
feature.hasTimestamp = true;
feature.timestamp = t;
feature.values.push_back(float(oi));
feature.label = Vamp::RealTime::frame2RealTime(oi, rate).toText();
features[m_incrementsOutput].push_back(feature);
feature.values.clear();
feature.values.push_back(float(actual));
feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText();
features[m_aggregateIncrementsOutput].push_back(feature);
feature.values.clear();
feature.values.push_back(actual - linear);
sprintf(label, "expected %ld, actual %ld, difference %ld (%s ms)",
long(linear), long(actual), long(actual - linear),
// frame2RealTime expects an integer frame number,
// hence our multiplication factor
(Vamp::RealTime::frame2RealTime
(lrintf((actual - linear) * 1000), rate) / 1000)
.toText().c_str());
feature.label = label;
features[m_divergenceOutput].push_back(feature);
actual += oi;
char buf[30];
if (i < phaseResetDf.size()) {
feature.values.clear();
feature.values.push_back(phaseResetDf[i]);
sprintf(buf, "%d", int(baseCount + i));
feature.label = buf;
features[m_phaseResetDfOutput].push_back(feature);
}
if (i < smoothedDf.size()) {
feature.values.clear();
feature.values.push_back(smoothedDf[i]);
features[m_smoothedPhaseResetDfOutput].push_back(feature);
}
if (hard) {
feature.values.clear();
feature.label = "Phase Reset";
features[m_phaseResetPointsOutput].push_back(feature);
}
if (hard || soft) {
feature.values.clear();
feature.label = "Time Sync";
features[m_timeSyncPointsOutput].push_back(feature);
}
}
if (includeFinal) {
Vamp::RealTime t = Vamp::RealTime::frame2RealTime
(inputIncrement * (baseCount + outputIncrements.size()), rate);
Feature feature;
feature.hasTimestamp = true;
feature.timestamp = t;
feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText();
feature.values.clear();
feature.values.push_back(float(actual));
features[m_aggregateIncrementsOutput].push_back(feature);
float linear = ((baseCount + outputIncrements.size())
* inputIncrement * overallRatio);
feature.values.clear();
feature.values.push_back(actual - linear);
feature.label = // see earlier comment
(Vamp::RealTime::frame2RealTime //!!! update this as earlier label
(lrintf((actual - linear) * 1000), rate) / 1000)
.toText();
features[m_divergenceOutput].push_back(feature);
}
m_accumulatedIncrement = actual;
return features;
}

View File

@@ -1,56 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#ifndef _RUBBERBAND_VAMP_PLUGIN_H_
#define _RUBBERBAND_VAMP_PLUGIN_H_
#include <vamp-sdk/Plugin.h>
#include "RubberBandStretcher.h"
class RubberBandVampPlugin : public Vamp::Plugin
{
public:
RubberBandVampPlugin(float inputSampleRate);
virtual ~RubberBandVampPlugin();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const { return TimeDomain; }
std::string getIdentifier() const;
std::string getName() const;
std::string getDescription() const;
std::string getMaker() const;
int getPluginVersion() const;
std::string getCopyright() const;
ParameterList getParameterDescriptors() const;
float getParameter(std::string id) const;
void setParameter(std::string id, float value);
OutputList getOutputDescriptors() const;
FeatureSet process(const float *const *inputBuffers,
Vamp::RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
class Impl;
Impl *m_d;
};
#endif

View File

@@ -1,32 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include <vamp/vamp.h>
#include <vamp-sdk/PluginAdapter.h>
#include "RubberBandVampPlugin.h"
static Vamp::PluginAdapter<RubberBandVampPlugin> rubberBandAdapter;
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
unsigned int index)
{
if (version < 1) return 0;
switch (index) {
case 0: return rubberBandAdapter.getDescriptor();
default: return 0;
}
}

View File

@@ -1,4 +0,0 @@
{
global: vampGetPluginDescriptor;
local: *;
};

View File

@@ -1 +0,0 @@
vamp:vamp-rubberband:rubberband::Time > Timestretch Analysis