* 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:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
97
src/dsp/SpectralDifferenceAudioCurve.cpp
Normal file
97
src/dsp/SpectralDifferenceAudioCurve.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
global: ladspa_descriptor;
|
||||
local: *;
|
||||
};
|
||||
@@ -1,2 +0,0 @@
|
||||
ladspa:ladspa-rubberband:rubberband-pitchshifter-mono::Frequency > Pitch shifters
|
||||
ladspa:ladspa-rubberband:rubberband-pitchshifter-stereo::Frequency > Pitch shifters
|
||||
@@ -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>
|
||||
|
||||
529
src/main.cpp
529
src/main.cpp
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
111
src/system/sysutils.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
global: vampGetPluginDescriptor;
|
||||
local: *;
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
vamp:vamp-rubberband:rubberband::Time > Timestretch Analysis
|
||||
Reference in New Issue
Block a user