* Work around a patent (also producing better results, in many cases)

* Add aligned allocation functions in sysutils
This commit is contained in:
Chris Cannam
2008-07-08 15:00:22 +00:00
parent d6d4af1539
commit 057481ea41
12 changed files with 195 additions and 250 deletions

View File

@@ -110,21 +110,15 @@ public:
* during non-transient segments. These options may be changed at
* any time.
*
* \li \c OptionPhaseAdaptive - Lock the adjustments of phase
* for frequencies close to peak frequencies to those of the
* peak, but reduce the degree of locking as the stretch ratio
* gets longer. This, the default setting, should give a good
* balance between clarity and smoothness in most situations.
* \li \c OptionPhaseLaminar - Adjust phases when stretching in
* such a way as to try to retain the continuity of phase
* relationships between adjacent frequency bins whose phases
* are behaving in similar ways. This, the default setting,
* should give good results in most situations.
*
* \li \c OptionPhasePeakLocked - Lock the adjustments of phase
* for frequencies close to peak frequencies to those of the
* peak. This should give a clear result in situations with
* relatively low stretch ratios, but a relatively metallic
* sound at longer stretches.
*
* \li \c OptionPhaseIndependent - Do not lock phase adjustments
* to peak frequencies. This usually results in a softer,
* phasier sound.
* \li \c OptionPhaseIndependent - Adjust the phase in each
* frequency bin independently from its neighbours. This
* usually results in a slightly softer, phasier sound.
*
* 5. Flags prefixed \c OptionThreading control the threading
* model of the stretcher. These options may not be changed after
@@ -207,8 +201,7 @@ public:
OptionTransientsMixed = 0x00000100,
OptionTransientsSmooth = 0x00000200,
OptionPhaseAdaptive = 0x00000000,
OptionPhasePeakLocked = 0x00001000,
OptionPhaseLaminar = 0x00000000,
OptionPhaseIndependent = 0x00002000,
OptionThreadingAuto = 0x00000000,

View File

@@ -48,8 +48,7 @@ enum RubberBandOption {
RubberBandOptionTransientsMixed = 0x00000100,
RubberBandOptionTransientsSmooth = 0x00000200,
RubberBandOptionPhaseAdaptive = 0x00000000,
RubberBandOptionPhasePeakLocked = 0x00001000,
RubberBandOptionPhaseLaminar = 0x00000000,
RubberBandOptionPhaseIndependent = 0x00002000,
RubberBandOptionThreadingAuto = 0x00000000,

View File

@@ -101,11 +101,10 @@ D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
}
if (maxBufferSize > 0 && m_channels > 1) {
//!!! alignment?
m_iinsize = maxBufferSize * m_channels;
m_ioutsize = maxBufferSize * m_channels * 2;
m_iin = (float *)malloc(m_iinsize * sizeof(float));
m_iout = (float *)malloc(m_ioutsize * sizeof(float));
m_iin = allocFloat(m_iinsize);
m_iout = allocFloat(m_ioutsize);
}
reset();
@@ -138,12 +137,10 @@ D_SRC::resample(const float *const R__ *const R__ in,
data.data_out = *out;
} else {
if (incount * m_channels > m_iinsize) {
m_iinsize = incount * m_channels;
m_iin = (float *)realloc(m_iin, m_iinsize * sizeof(float));
m_iin = allocFloat(m_iin, m_iinsize);
}
if (outcount * m_channels > m_ioutsize) {
m_ioutsize = outcount * m_channels;
m_iout = (float *)realloc(m_iout, m_ioutsize * sizeof(float));
m_iout = allocFloat(m_iout, m_ioutsize);
}
for (int i = 0; i < incount; ++i) {
for (int c = 0; c < m_channels; ++c) {

View File

@@ -19,7 +19,7 @@
namespace RubberBand
{
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
int overSample,
size_t outbufSize) :
@@ -64,18 +64,19 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
inbuf = new RingBuffer<float>(maxSize);
outbuf = new RingBuffer<float>(outbufSize);
mag = new double[realSize];
phase = new double[realSize];
prevPhase = new double[realSize];
unwrappedPhase = new double[realSize];
mag = allocDouble(realSize);
phase = allocDouble(realSize);
prevPhase = allocDouble(realSize);
prevError = allocDouble(realSize);
unwrappedPhase = allocDouble(realSize);
envelope = allocDouble(realSize);
freqPeak = new size_t[realSize];
envelope = new double[realSize];
fltbuf = new float[maxSize];
accumulator = new float[maxSize];
windowAccumulator = new float[maxSize];
fltbuf = allocFloat(maxSize);
accumulator = allocFloat(maxSize);
windowAccumulator = allocFloat(maxSize);
for (std::set<size_t>::const_iterator i = windowSizes.begin();
i != windowSizes.end(); ++i) {
@@ -97,23 +98,12 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
reset();
for (size_t i = 0; i < realSize; ++i) {
mag[i] = 0.0;
phase[i] = 0.0;
prevPhase[i] = 0.0;
unwrappedPhase[i] = 0.0;
freqPeak[i] = 0;
envelope[i] = 0.0;
}
for (size_t i = 0; i < initialWindowSize * oversample; ++i) {
dblbuf[i] = 0.0;
}
for (size_t i = 0; i < maxSize; ++i) {
accumulator[i] = 0.f;
windowAccumulator[i] = 0.f;
fltbuf[i] = 0.f;
}
}
void
@@ -151,6 +141,7 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
mag[i] = 0.0;
phase[i] = 0.0;
prevPhase[i] = 0.0;
prevError[i] = 0.0;
unwrappedPhase[i] = 0.0;
freqPeak[i] = 0;
}
@@ -171,56 +162,44 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
// We don't want to preserve data in these arrays
delete[] mag;
delete[] phase;
delete[] prevPhase;
delete[] unwrappedPhase;
mag = allocDouble(mag, realSize);
phase = allocDouble(phase, realSize);
prevPhase = allocDouble(prevPhase, realSize);
prevError = allocDouble(prevError, realSize);
unwrappedPhase = allocDouble(unwrappedPhase, realSize);
envelope = allocDouble(envelope, realSize);
delete[] freqPeak;
delete[] envelope;
mag = new double[realSize];
phase = new double[realSize];
prevPhase = new double[realSize];
unwrappedPhase = new double[realSize];
freqPeak = new size_t[realSize];
envelope = new double[realSize];
delete[] fltbuf;
fltbuf = new float[windowSize];
fltbuf = allocFloat(fltbuf, windowSize);
// But we do want to preserve data in these
float *newAcc = new float[windowSize];
float *newAcc = allocFloat(windowSize);
for (size_t i = 0; i < oldSize; ++i) newAcc[i] = accumulator[i];
delete[] accumulator;
freeFloat(accumulator);
accumulator = newAcc;
newAcc = new float[windowSize];
newAcc = allocFloat(windowSize);
for (size_t i = 0; i < oldSize; ++i) newAcc[i] = windowAccumulator[i];
delete[] windowAccumulator;
freeFloat(windowAccumulator);
windowAccumulator = newAcc;
//!!! and resampler?
for (size_t i = 0; i < realSize; ++i) {
mag[i] = 0.0;
phase[i] = 0.0;
prevPhase[i] = 0.0;
unwrappedPhase[i] = 0.0;
freqPeak[i] = 0;
envelope[i] = 0.0;
}
for (size_t i = 0; i < windowSize; ++i) {
fltbuf[i] = 0.f;
}
for (size_t i = oldSize; i < windowSize; ++i) {
accumulator[i] = 0.f;
windowAccumulator[i] = 0.f;
}
if (ffts.find(windowSize) == ffts.end()) {
ffts[windowSize] = new FFT(windowSize * oversample);
ffts[windowSize]->initDouble();
@@ -256,15 +235,7 @@ RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize)
void
RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz)
{
if (!resamplebuf) {
resamplebuf = new float[sz];
resamplebufSize = sz;
return;
}
delete[] resamplebuf;
resamplebuf = new float[sz];
for (size_t i = 0; i < sz; ++i) resamplebuf[i] = 0.f;
resamplebuf = allocFloat(resamplebuf, sz);
resamplebufSize = sz;
}
@@ -272,22 +243,21 @@ RubberBandStretcher::Impl::ChannelData::~ChannelData()
{
delete resampler;
if (resamplebuf) {
delete[] resamplebuf;
}
freeFloat(resamplebuf);
delete inbuf;
delete outbuf;
delete[] mag;
delete[] phase;
delete[] prevPhase;
delete[] unwrappedPhase;
freeDouble(mag);
freeDouble(phase);
freeDouble(prevPhase);
freeDouble(prevError);
freeDouble(unwrappedPhase);
freeDouble(envelope);
delete[] freqPeak;
delete[] accumulator;
delete[] windowAccumulator;
delete[] fltbuf;
delete[] envelope;
freeFloat(accumulator);
freeFloat(windowAccumulator);
freeFloat(fltbuf);
for (std::map<size_t, FFT *>::iterator i = ffts.begin();
i != ffts.end(); ++i) {

View File

@@ -91,6 +91,7 @@ public:
double *phase;
double *prevPhase;
double *prevError;
double *unwrappedPhase;

View File

@@ -713,7 +713,7 @@ RubberBandStretcher::Impl::setTransientsOption(Options options)
void
RubberBandStretcher::Impl::setPhaseOption(Options options)
{
int mask = (OptionPhaseAdaptive | OptionPhasePeakLocked | OptionPhaseIndependent);
int mask = (OptionPhaseLaminar | OptionPhaseIndependent);
m_options &= ~mask;
options &= mask;
m_options |= options;

View File

@@ -333,7 +333,7 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
// We need to peek m_windowSize samples for processing, and
// then skip m_increment to advance the read pointer.
modifyChunk(c, phaseIncrement, phaseReset);
synthesiseChunk(c); // reads from cd.mag, cd.phase
@@ -643,7 +643,8 @@ 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,
RubberBandStretcher::Impl::modifyChunk(size_t channel,
size_t outputIncrement,
bool phaseReset)
{
Profiler profiler("RubberBandStretcher::Impl::modifyChunk");
@@ -654,184 +655,120 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
cerr << "phase reset: leaving phases unmodified" << endl;
}
int pfp = 0;
double rate = m_sampleRate;
int sz = m_windowSize;
int count = (sz * cd.oversample) / 2;
const double rate = m_sampleRate;
const int sz = m_windowSize;
const int count = (sz * cd.oversample) / 2;
bool unchanged = cd.unchanged && (outputIncrement == m_increment);
bool fullReset = phaseReset;
bool laminar = !(m_options & OptionPhaseIndependent);
bool bandlimited = (m_options & OptionTransientsMixed);
int bandlow = lrint((150 * sz * cd.oversample) / rate);
int bandhigh = lrint((1000 * sz * cd.oversample) / rate);
if (!(m_options & OptionPhaseIndependent)) {
float freq0 = m_freq0;
float freq1 = m_freq1;
float freq2 = m_freq2;
cd.freqPeak[0] = 0;
float freq0 = m_freq0;
float freq1 = m_freq1;
float freq2 = m_freq2;
// As the stretch ratio increases, so the frequency thresholds
// for phase lamination should increase. Beyond a ratio of
// about 1.5, the threshold should be about 1200Hz; beyond a
// ratio of 2, we probably want no lamination to happen at all
// by default. This calculation aims for more or less that.
// We only do this if the phase option is OptionPhaseAdaptive
// (the default), i.e. not Independent or PeakLocked.
if (!(m_options & OptionPhasePeakLocked)) {
float r = getEffectiveRatio();
if (r > 1) {
float rf0 = 600 + (600 * ((r-1)*(r-1)*(r-1)*2));
float f1ratio = freq1 / freq0;
float f2ratio = freq2 / freq0;
freq0 = std::max(freq0, rf0);
freq1 = freq0 * f1ratio;
freq2 = freq0 * f2ratio;
}
if (laminar) {
float r = getEffectiveRatio();
if (r > 1) {
float rf0 = 600 + (600 * ((r-1)*(r-1)*(r-1)*2));
float f1ratio = freq1 / freq0;
float f2ratio = freq2 / freq0;
freq0 = std::max(freq0, rf0);
freq1 = freq0 * f1ratio;
freq2 = freq0 * f2ratio;
}
int limit0 = lrint((freq0 * sz * cd.oversample) / rate);
int limit1 = lrint((freq1 * sz * cd.oversample) / rate);
int limit2 = lrint((freq2 * sz * cd.oversample) / rate);
int range = 0;
if (limit1 < limit0) limit1 = limit0;
if (limit2 < limit1) limit2 = limit1;
// cerr << "limit0 = " << limit0 << " limit1 = " << limit1 << " limit2 = " << limit2 << endl;
int peakCount = 0;
for (int i = 0; i <= count; ++i) {
double mag = cd.mag[i];
bool isPeak = true;
for (int j = 1; j <= range; ++j) {
if (mag < cd.mag[i-j]) {
isPeak = false;
break;
}
if (mag < cd.mag[i+j]) {
isPeak = false;
break;
}
}
if (isPeak) {
// i is a peak bin.
// The previous peak bin was at pfp; make freqPeak entries
// from pfp to half-way between pfp and i point at pfp, and
// those from the half-way mark to i point at i.
int halfway = (pfp + i) / 2;
if (halfway == pfp) halfway = pfp + 1;
for (int j = pfp + 1; j < halfway; ++j) {
cd.freqPeak[j] = pfp;
}
for (int j = halfway; j <= i; ++j) {
cd.freqPeak[j] = i;
}
pfp = i;
++peakCount;
}
if (i == limit0) range = 1;
if (i == limit1) range = 2;
if (i >= limit2) {
range = 3;
if (i + range + 1 > count) range = count - i - 1;
}
}
// cerr << "peakCount = " << peakCount << endl;
cd.freqPeak[count-1] = count-1;
cd.freqPeak[count] = count;
}
Profiler profiler2("RubberBandStretcher::Impl::modifyChunk part 2");
int limit0 = lrint((freq0 * sz * cd.oversample) / rate);
int limit1 = lrint((freq1 * sz * cd.oversample) / rate);
int limit2 = lrint((freq2 * sz * cd.oversample) / rate);
double peakInPhase = 0.0;
double peakOutPhase = 0.0;
int p = -1, pp = -1;
if (limit1 < limit0) limit1 = limit0;
if (limit2 < limit1) limit2 = limit1;
double prevInstability = 0.0;
double prevDirection = 0.0;
double distance = 0.0;
const double maxdist = 8.0;
for (int i = 0; i <= count; ++i) {
if (m_options & OptionPhaseIndependent) {
p = i;
pp = i-1;
} else {
p = cd.freqPeak[i];
if (i > 0) pp = cd.freqPeak[i-1];
}
const int lookback = -1;
for (int i = 0; i <= count; i -= lookback) {
bool resetThis = phaseReset;
if (m_options & OptionTransientsMixed) {
int low = lrint((150 * sz * cd.oversample) / rate);
int high = lrint((1000 * sz * cd.oversample) / rate);
if (bandlimited) {
if (resetThis) {
if (i > low && i < high) {
if (i > bandlow && i < bandhigh) {
resetThis = false;
fullReset = false;
}
}
}
double p = cd.phase[i];
double perr = 0.0;
double outphase = p;
double mi = maxdist;
if (i <= limit0) mi = 0.0;
else if (i <= limit1) mi = 1.0;
else if (i <= limit2) mi = 3.0;
if (!resetThis) {
if (i == 0 || p != pp) {
double omega = (2 * M_PI * m_increment * i) / (sz * cd.oversample);
double omega = (2 * M_PI * m_increment * p) /
(sz * cd.oversample);
double expectedPhase = cd.prevPhase[p] + omega;
double phaseError = princarg(cd.phase[p] - expectedPhase);
double phaseIncrement = (omega + phaseError) / m_increment;
double unwrappedPhase = cd.unwrappedPhase[p] +
outputIncrement * phaseIncrement;
double pp = cd.prevPhase[i];
double ep = pp + omega;
perr = princarg(p - ep);
cd.prevPhase[p] = cd.phase[p];
cd.phase[p] = unwrappedPhase;
cd.unwrappedPhase[p] = unwrappedPhase;
double instability = fabs(perr - cd.prevError[i]);
bool direction = (perr > cd.prevError[i]);
peakInPhase = cd.prevPhase[p];
peakOutPhase = unwrappedPhase;
bool inherit = false;
if (laminar) {
if (distance >= mi) {
inherit = false;
} else if (bandlimited && (i == bandhigh || i == bandlow)) {
inherit = false;
} else if (instability > prevInstability &&
direction == prevDirection) {
inherit = true;
}
}
if (i != p) {
double advance = outputIncrement * ((omega + perr) / m_increment);
// cd.phase[i] = atan2(cd.imag[i], cd.real[i]);//!!!
double diffToPeak = peakInPhase - cd.phase[i];
double unwrappedPhase = peakOutPhase - diffToPeak;
cd.prevPhase[i] = cd.phase[i];
cd.phase[i] = unwrappedPhase;
cd.unwrappedPhase[i] = unwrappedPhase;
if (inherit) {
double inherited =
cd.unwrappedPhase[i + lookback] - cd.prevPhase[i + lookback];
advance = ((advance * distance) + (inherited * (mi - distance)))
/ mi;
outphase = p + advance;
distance += 1.0;
} else {
outphase = cd.unwrappedPhase[i] + advance;
distance = 0.0;
}
prevInstability = instability;
prevDirection = direction;
} else {
// resetThis == true
cd.prevPhase[i] = cd.phase[i];
cd.unwrappedPhase[i] = cd.phase[i];
distance = 0.0;
}
}
cd.prevError[i] = perr;
cd.prevPhase[i] = p;
cd.phase[i] = outphase;
cd.unwrappedPhase[i] = outphase;
}
if (fullReset) unchanged = true;
cd.unchanged = unchanged;
@@ -839,7 +776,7 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
if (unchanged && m_debugLevel > 1) {
cerr << "frame unchanged on channel " << channel << endl;
}
}
}
void

View File

@@ -379,15 +379,15 @@ RubberBandPitchShifter::updateCrispness()
s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
break;
case 1:
s->setPhaseOption(RubberBandStretcher::OptionPhaseAdaptive);
s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
break;
case 2:
s->setPhaseOption(RubberBandStretcher::OptionPhaseAdaptive);
s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsMixed);
break;
case 3:
s->setPhaseOption(RubberBandStretcher::OptionPhaseAdaptive);
s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp);
break;
}

View File

@@ -76,7 +76,6 @@ int main(int argc, char **argv)
bool longwin = false;
bool shortwin = false;
bool hqpitch = false;
bool softening = true;
bool formant = false;
bool crispchanged = false;
int crispness = -1;
@@ -115,7 +114,6 @@ int main(int argc, char **argv)
{ "window-long", 0, 0, '3' },
{ "window-short", 0, 0, '4' },
{ "bl-transients", 0, 0, '8' },
{ "no-softening", 0, 0, '9' },
{ "pitch-hq", 0, 0, '%' },
{ "threads", 0, 0, '@' },
{ "quiet", 0, 0, 'q' },
@@ -144,7 +142,6 @@ int main(int argc, char **argv)
case '3': longwin = true; crispchanged = true; break;
case '4': shortwin = true; crispchanged = true; break;
case '8': transients = BandLimitedTransients; crispchanged = true; break;
case '9': softening = false; break;
case '%': hqpitch = true; break;
case 'c': crispness = atoi(optarg); break;
case 'q': quiet = true; break;
@@ -193,7 +190,6 @@ int main(int argc, char **argv)
cerr << " --no-transients Disable phase resynchronisation at transients" << endl;
cerr << " --bl-transients Band-limit phase resync to extreme frequencies" << endl;
cerr << " --no-peaklock Disable phase locking to peak frequencies" << endl;
cerr << " --no-softening Disable large-ratio softening of phase locking" << 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;
@@ -290,7 +286,6 @@ int main(int argc, char **argv)
if (realtime) options |= RubberBandStretcher::OptionProcessRealTime;
if (precise) options |= RubberBandStretcher::OptionStretchPrecise;
if (!peaklock) options |= RubberBandStretcher::OptionPhaseIndependent;
if (!softening) options |= RubberBandStretcher::OptionPhasePeakLocked;
if (longwin) options |= RubberBandStretcher::OptionWindowLong;
if (shortwin) options |= RubberBandStretcher::OptionWindowShort;
if (formant) options |= RubberBandStretcher::OptionFormantPreserved;

View File

@@ -27,6 +27,7 @@
#include <iostream>
namespace RubberBand {
bool
@@ -101,6 +102,50 @@ void usleep(unsigned long usec)
#endif
float *allocFloat(float *ptr, int count)
{
if (ptr) free((void *)ptr);
void *allocated;
if (!posix_memalign(&allocated, 16, count * sizeof(float))) {
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;
if (!posix_memalign(&allocated, 16, count * sizeof(double))) {
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);
}
}

View File

@@ -49,6 +49,14 @@ void usleep(unsigned long);
#endif
extern float *allocFloat(int);
extern float *allocFloat(float *, int);
extern void freeFloat(float *);
extern double *allocDouble(int);
extern double *allocDouble(double *, int);
extern void freeDouble(double *);
}
#endif

View File

@@ -379,7 +379,7 @@ RubberBandVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockS
if (m_d->m_phaseIndependent)
options |= RubberBand::RubberBandStretcher::OptionPhaseIndependent;
else options |= RubberBand::RubberBandStretcher::OptionPhasePeakLocked;
else options |= RubberBand::RubberBandStretcher::OptionPhaseLaminar;
if (m_d->m_windowLength == 0)
options |= RubberBand::RubberBandStretcher::OptionWindowStandard;