Merge from branch logger
This commit is contained in:
@@ -42,10 +42,11 @@ library_sources = [
|
|||||||
'src/faster/R2Stretcher.cpp',
|
'src/faster/R2Stretcher.cpp',
|
||||||
'src/faster/StretcherChannelData.cpp',
|
'src/faster/StretcherChannelData.cpp',
|
||||||
'src/faster/StretcherProcess.cpp',
|
'src/faster/StretcherProcess.cpp',
|
||||||
|
'src/common/Allocators.cpp',
|
||||||
|
'src/common/FFT.cpp',
|
||||||
|
'src/common/Log.cpp',
|
||||||
'src/common/Profiler.cpp',
|
'src/common/Profiler.cpp',
|
||||||
'src/common/Resampler.cpp',
|
'src/common/Resampler.cpp',
|
||||||
'src/common/FFT.cpp',
|
|
||||||
'src/common/Allocators.cpp',
|
|
||||||
'src/common/StretchCalculator.cpp',
|
'src/common/StretchCalculator.cpp',
|
||||||
'src/common/sysutils.cpp',
|
'src/common/sysutils.cpp',
|
||||||
'src/common/Thread.cpp',
|
'src/common/Thread.cpp',
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -277,7 +279,6 @@ public:
|
|||||||
* provided for backward compatibility only. They are ignored by
|
* provided for backward compatibility only. They are ignored by
|
||||||
* the stretcher.
|
* the stretcher.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum Option {
|
enum Option {
|
||||||
|
|
||||||
OptionProcessOffline = 0x00000000,
|
OptionProcessOffline = 0x00000000,
|
||||||
@@ -331,6 +332,13 @@ public:
|
|||||||
PercussiveOptions = 0x00102000
|
PercussiveOptions = 0x00102000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Logger {
|
||||||
|
virtual void log(const char *) = 0;
|
||||||
|
virtual void log(const char *, double) = 0;
|
||||||
|
virtual void log(const char *, double, double) = 0;
|
||||||
|
virtual ~Logger() { }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a time and pitch stretcher object to run at the given
|
* Construct a time and pitch stretcher object to run at the given
|
||||||
* sample rate, with the given number of channels.
|
* sample rate, with the given number of channels.
|
||||||
@@ -361,6 +369,30 @@ public:
|
|||||||
Options options = DefaultOptions,
|
Options options = DefaultOptions,
|
||||||
double initialTimeRatio = 1.0,
|
double initialTimeRatio = 1.0,
|
||||||
double initialPitchScale = 1.0);
|
double initialPitchScale = 1.0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a time and pitch stretcher object with a custom debug
|
||||||
|
* logger. This may be useful for debugging if the default logger
|
||||||
|
* output (which simply goes to cout) is not visible in the
|
||||||
|
* runtime environment, or if the application has a standard or
|
||||||
|
* more realtime-appropriate logging mechanism.
|
||||||
|
*
|
||||||
|
* See the documentation for the other constructor above for
|
||||||
|
* details of the arguments other than the logger.
|
||||||
|
*
|
||||||
|
* Note that although the supplied logger gets to decide what to
|
||||||
|
* do with log messages, the separately-set debug level (see
|
||||||
|
* setDebugLevel() and setDefaultDebugLevel()) still determines
|
||||||
|
* whether any given debug message is sent to the logger in the
|
||||||
|
* first place.
|
||||||
|
*/
|
||||||
|
RubberBandStretcher(size_t sampleRate,
|
||||||
|
size_t channels,
|
||||||
|
std::shared_ptr<Logger> logger,
|
||||||
|
Options options = DefaultOptions,
|
||||||
|
double initialTimeRatio = 1.0,
|
||||||
|
double initialPitchScale = 1.0);
|
||||||
|
|
||||||
~RubberBandStretcher();
|
~RubberBandStretcher();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,24 +24,68 @@
|
|||||||
#include "faster/R2Stretcher.h"
|
#include "faster/R2Stretcher.h"
|
||||||
#include "finer/R3Stretcher.h"
|
#include "finer/R3Stretcher.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace RubberBand {
|
namespace RubberBand {
|
||||||
|
|
||||||
class RubberBandStretcher::Impl
|
class RubberBandStretcher::Impl
|
||||||
{
|
{
|
||||||
R2Stretcher *m_r2;
|
R2Stretcher *m_r2;
|
||||||
R3Stretcher *m_r3;
|
R3Stretcher *m_r3;
|
||||||
|
|
||||||
|
class CerrLogger : public RubberBandStretcher::Logger {
|
||||||
|
public:
|
||||||
|
void log(const char *message) override {
|
||||||
|
std::cerr << "RubberBand: " << message << "\n";
|
||||||
|
}
|
||||||
|
void log(const char *message, double arg0) override {
|
||||||
|
auto prec = std::cerr.precision();
|
||||||
|
std::cerr.precision(10);
|
||||||
|
std::cerr << "RubberBand: " << message << ": " << arg0 << "\n";
|
||||||
|
std::cerr.precision(prec);
|
||||||
|
}
|
||||||
|
void log(const char *message, double arg0, double arg1) override {
|
||||||
|
auto prec = std::cerr.precision();
|
||||||
|
std::cerr.precision(10);
|
||||||
|
std::cerr << "RubberBand: " << message
|
||||||
|
<< ": (" << arg0 << ", " << arg1 << ")" << "\n";
|
||||||
|
std::cerr.precision(prec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Log makeRBLog(std::shared_ptr<RubberBandStretcher::Logger> logger) {
|
||||||
|
if (logger) {
|
||||||
|
return Log(
|
||||||
|
[=](const char *message) {
|
||||||
|
logger->log(message);
|
||||||
|
},
|
||||||
|
[=](const char *message, double arg0) {
|
||||||
|
logger->log(message, arg0);
|
||||||
|
},
|
||||||
|
[=](const char *message, double arg0, double arg1) {
|
||||||
|
logger->log(message, arg0, arg1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return makeRBLog(std::shared_ptr<RubberBandStretcher::Logger>
|
||||||
|
(new CerrLogger()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Impl(size_t sampleRate, size_t channels, Options options,
|
Impl(size_t sampleRate, size_t channels, Options options,
|
||||||
|
std::shared_ptr<RubberBandStretcher::Logger> logger,
|
||||||
double initialTimeRatio, double initialPitchScale) :
|
double initialTimeRatio, double initialPitchScale) :
|
||||||
m_r2 (!(options & OptionEngineFiner) ?
|
m_r2 (!(options & OptionEngineFiner) ?
|
||||||
new R2Stretcher(sampleRate, channels, options,
|
new R2Stretcher(sampleRate, channels, options,
|
||||||
initialTimeRatio, initialPitchScale)
|
initialTimeRatio, initialPitchScale,
|
||||||
|
makeRBLog(logger))
|
||||||
: nullptr),
|
: nullptr),
|
||||||
m_r3 ((options & OptionEngineFiner) ?
|
m_r3 ((options & OptionEngineFiner) ?
|
||||||
new R3Stretcher(R3Stretcher::Parameters
|
new R3Stretcher(R3Stretcher::Parameters
|
||||||
(double(sampleRate), channels, options),
|
(double(sampleRate), channels, options),
|
||||||
initialTimeRatio, initialPitchScale)
|
initialTimeRatio, initialPitchScale,
|
||||||
|
makeRBLog(logger))
|
||||||
: nullptr)
|
: nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -272,13 +316,13 @@ public:
|
|||||||
setDebugLevel(int level)
|
setDebugLevel(int level)
|
||||||
{
|
{
|
||||||
if (m_r2) m_r2->setDebugLevel(level);
|
if (m_r2) m_r2->setDebugLevel(level);
|
||||||
|
else m_r3->setDebugLevel(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
setDefaultDebugLevel(int level)
|
setDefaultDebugLevel(int level)
|
||||||
{
|
{
|
||||||
R2Stretcher::setDefaultDebugLevel(level);
|
Log::setDefaultDebugLevel(level);
|
||||||
//!!! R3Stretcher::setDefaultDebugLevel(level);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -287,7 +331,18 @@ RubberBandStretcher::RubberBandStretcher(size_t sampleRate,
|
|||||||
Options options,
|
Options options,
|
||||||
double initialTimeRatio,
|
double initialTimeRatio,
|
||||||
double initialPitchScale) :
|
double initialPitchScale) :
|
||||||
m_d(new Impl(sampleRate, channels, options,
|
m_d(new Impl(sampleRate, channels, options, nullptr,
|
||||||
|
initialTimeRatio, initialPitchScale))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RubberBandStretcher::RubberBandStretcher(size_t sampleRate,
|
||||||
|
size_t channels,
|
||||||
|
std::shared_ptr<Logger> logger,
|
||||||
|
Options options,
|
||||||
|
double initialTimeRatio,
|
||||||
|
double initialPitchScale) :
|
||||||
|
m_d(new Impl(sampleRate, channels, options, logger,
|
||||||
initialTimeRatio, initialPitchScale))
|
initialTimeRatio, initialPitchScale))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/common/Log.cpp
Normal file
31
src/common/Log.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rubber Band Library
|
||||||
|
An audio time-stretching and pitch-shifting library.
|
||||||
|
Copyright 2007-2022 Particular Programs Ltd.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Alternatively, if you have a valid commercial licence for the
|
||||||
|
Rubber Band Library obtained by agreement with the copyright
|
||||||
|
holders, you may redistribute and/or modify it under the terms
|
||||||
|
described in that licence.
|
||||||
|
|
||||||
|
If you wish to distribute code using the Rubber Band Library
|
||||||
|
under terms other than those of the GNU General Public License,
|
||||||
|
you must obtain a valid commercial licence before doing so.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
namespace RubberBand
|
||||||
|
{
|
||||||
|
|
||||||
|
int Log::m_defaultDebugLevel = 0;
|
||||||
|
|
||||||
|
}
|
||||||
72
src/common/Log.h
Normal file
72
src/common/Log.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rubber Band Library
|
||||||
|
An audio time-stretching and pitch-shifting library.
|
||||||
|
Copyright 2007-2022 Particular Programs Ltd.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Alternatively, if you have a valid commercial licence for the
|
||||||
|
Rubber Band Library obtained by agreement with the copyright
|
||||||
|
holders, you may redistribute and/or modify it under the terms
|
||||||
|
described in that licence.
|
||||||
|
|
||||||
|
If you wish to distribute code using the Rubber Band Library
|
||||||
|
under terms other than those of the GNU General Public License,
|
||||||
|
you must obtain a valid commercial licence before doing so.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RUBBERBAND_LOG_H
|
||||||
|
#define RUBBERBAND_LOG_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace RubberBand {
|
||||||
|
|
||||||
|
class Log {
|
||||||
|
public:
|
||||||
|
Log(std::function<void(const char *)> _log0,
|
||||||
|
std::function<void(const char *, double)> _log1,
|
||||||
|
std::function<void(const char *, double, double)> _log2) :
|
||||||
|
m_log0(_log0),
|
||||||
|
m_log1(_log1),
|
||||||
|
m_log2(_log2),
|
||||||
|
m_debugLevel(m_defaultDebugLevel) { }
|
||||||
|
|
||||||
|
Log(const Log &other) =default;
|
||||||
|
Log(Log &&other) =default;
|
||||||
|
Log &operator=(const Log &other) =default;
|
||||||
|
Log &operator=(Log &&other) =default;
|
||||||
|
|
||||||
|
void setDebugLevel(int level) { m_debugLevel = level; }
|
||||||
|
int getDebugLevel() const { return m_debugLevel; }
|
||||||
|
|
||||||
|
static void setDefaultDebugLevel(int level) { m_defaultDebugLevel = level; }
|
||||||
|
|
||||||
|
void log(int level, const char *message) const {
|
||||||
|
if (level <= m_debugLevel) m_log0(message);
|
||||||
|
}
|
||||||
|
void log(int level, const char *message, double arg0) const {
|
||||||
|
if (level <= m_debugLevel) m_log1(message, arg0);
|
||||||
|
}
|
||||||
|
void log(int level, const char *message, double arg0, double arg1) const {
|
||||||
|
if (level <= m_debugLevel) m_log2(message, arg0, arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void(const char *)> m_log0;
|
||||||
|
std::function<void(const char *, double)> m_log1;
|
||||||
|
std::function<void(const char *, double, double)> m_log2;
|
||||||
|
int m_debugLevel;
|
||||||
|
static int m_defaultDebugLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "sysutils.h"
|
#include "sysutils.h"
|
||||||
|
|
||||||
@@ -37,7 +38,8 @@ namespace RubberBand
|
|||||||
|
|
||||||
StretchCalculator::StretchCalculator(size_t sampleRate,
|
StretchCalculator::StretchCalculator(size_t sampleRate,
|
||||||
size_t inputIncrement,
|
size_t inputIncrement,
|
||||||
bool useHardPeaks) :
|
bool useHardPeaks,
|
||||||
|
Log log) :
|
||||||
m_sampleRate(sampleRate),
|
m_sampleRate(sampleRate),
|
||||||
m_increment(inputIncrement),
|
m_increment(inputIncrement),
|
||||||
m_prevDf(0),
|
m_prevDf(0),
|
||||||
@@ -49,9 +51,10 @@ StretchCalculator::StretchCalculator(size_t sampleRate,
|
|||||||
m_useHardPeaks(useHardPeaks),
|
m_useHardPeaks(useHardPeaks),
|
||||||
m_inFrameCounter(0),
|
m_inFrameCounter(0),
|
||||||
m_frameCheckpoint(0, 0),
|
m_frameCheckpoint(0, 0),
|
||||||
m_outFrameCounter(0)
|
m_outFrameCounter(0),
|
||||||
|
m_log(log)
|
||||||
{
|
{
|
||||||
// std::cerr << "StretchCalculator::StretchCalculator: useHardPeaks = " << useHardPeaks << std::endl;
|
m_log.log(2, "StretchCalculator: useHardPeaks", useHardPeaks);
|
||||||
}
|
}
|
||||||
|
|
||||||
StretchCalculator::~StretchCalculator()
|
StretchCalculator::~StretchCalculator()
|
||||||
@@ -83,25 +86,18 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
|||||||
|
|
||||||
size_t outputDuration = lrint(inputDuration * ratio);
|
size_t outputDuration = lrint(inputDuration * ratio);
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "StretchCalculator::calculate: inputDuration and ratio", inputDuration, ratio);
|
||||||
std::cerr << "StretchCalculator::calculate(): inputDuration " << inputDuration << ", ratio " << ratio << ", outputDuration " << outputDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputDuration = lrint((phaseResetDf.size() * m_increment) * ratio);
|
outputDuration = lrint((phaseResetDf.size() * m_increment) * ratio);
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "StretchCalculator::calculate: outputDuration rounds up from and to", inputDuration * ratio, outputDuration);
|
||||||
std::cerr << " (rounded up to " << outputDuration << ")";
|
m_log.log(1, "StretchCalculator::calculate: df size and increment", phaseResetDf.size(), m_increment);
|
||||||
std::cerr << ", df size " << phaseResetDf.size() << ", increment "
|
|
||||||
<< m_increment << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Peak> peaks; // peak position (in chunks) and hardness
|
std::vector<Peak> peaks; // peak position (in chunks) and hardness
|
||||||
std::vector<size_t> targets; // targets for mapping peaks (in samples)
|
std::vector<size_t> targets; // targets for mapping peaks (in samples)
|
||||||
mapPeaks(peaks, targets, outputDuration, totalCount);
|
mapPeaks(peaks, targets, outputDuration, totalCount);
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "have fixed positions", peaks.size());
|
||||||
std::cerr << "have " << peaks.size() << " fixed positions" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t totalInput = 0, totalOutput = 0;
|
size_t totalInput = 0, totalOutput = 0;
|
||||||
|
|
||||||
@@ -122,7 +118,6 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i == peaks.size()) {
|
if (i == peaks.size()) {
|
||||||
// std::cerr << "note: i (=" << i << ") == peaks.size(); regionEndChunk " << regionEndChunk << " -> " << totalCount << ", regionEnd " << regionEnd << " -> " << outputDuration << std::endl;
|
|
||||||
regionEndChunk = totalCount;
|
regionEndChunk = totalCount;
|
||||||
regionEnd = outputDuration;
|
regionEnd = outputDuration;
|
||||||
} else {
|
} else {
|
||||||
@@ -141,15 +136,12 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
|||||||
size_t regionDuration = regionEnd - regionStart;
|
size_t regionDuration = regionEnd - regionStart;
|
||||||
|
|
||||||
size_t nchunks = regionEndChunk - regionStartChunk;
|
size_t nchunks = regionEndChunk - regionStartChunk;
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "region from and to (chunks)", regionStartChunk, regionEndChunk);
|
||||||
std::cerr << "region from " << regionStartChunk << " to " << regionEndChunk << " (samples " << regionStart << " to " << regionEnd << ")" << std::endl;
|
m_log.log(2, "region from and to (samples)", regionStart, regionEnd);
|
||||||
}
|
|
||||||
|
|
||||||
if (nchunks == 0) {
|
if (nchunks == 0) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "note: nchunks == 0");
|
||||||
std::cerr << "note: nchunks == 0" << std::endl;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,10 +187,10 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
|||||||
totalOutput += totalForRegion;
|
totalOutput += totalForRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "total input (frames, chunks)", totalInput, totalInput / m_increment);
|
||||||
std::cerr << "total input increment = " << totalInput << " (= " << totalInput / m_increment << " chunks), output = " << totalOutput << ", ratio = " << double(totalOutput)/double(totalInput) << ", ideal output " << size_t(ceil(totalInput * ratio)) << std::endl;
|
m_log.log(1, "total output and achieved ratio", totalOutput, double(totalOutput)/double(totalInput));
|
||||||
}
|
m_log.log(1, "ideal output", totalInput * ratio);
|
||||||
|
|
||||||
return increments;
|
return increments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,8 +229,6 @@ StretchCalculator::mapPeaks(std::vector<Peak> &peaks,
|
|||||||
|
|
||||||
while (mi != m_keyFrameMap.end()) {
|
while (mi != m_keyFrameMap.end()) {
|
||||||
|
|
||||||
// std::cerr << "mi->first is " << mi->first << ", second is " << mi->second <<std::endl;
|
|
||||||
|
|
||||||
// The map we've been given is from sample to sample, but
|
// The map we've been given is from sample to sample, but
|
||||||
// we can only map from chunk to sample. We should perhaps
|
// we can only map from chunk to sample. We should perhaps
|
||||||
// adjust the target sample to compensate for the discrepancy
|
// adjust the target sample to compensate for the discrepancy
|
||||||
@@ -261,7 +251,8 @@ StretchCalculator::mapPeaks(std::vector<Peak> &peaks,
|
|||||||
sourceStartChunk >= sourceEndChunk ||
|
sourceStartChunk >= sourceEndChunk ||
|
||||||
targetStartSample >= outputDuration ||
|
targetStartSample >= outputDuration ||
|
||||||
targetStartSample >= targetEndSample) {
|
targetStartSample >= targetEndSample) {
|
||||||
std::cerr << "NOTE: ignoring mapping from chunk " << sourceStartChunk << " to sample " << targetStartSample << "\n(source or target chunk exceeds total count, or end is not later than start)" << std::endl;
|
m_log.log(0, "NOTE: ignoring key-frame mapping from chunk to sample", sourceStartChunk, targetStartSample);
|
||||||
|
m_log.log(0, "(source or target chunk exceeds total count, or end is not later than start)");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,9 +265,7 @@ StretchCalculator::mapPeaks(std::vector<Peak> &peaks,
|
|||||||
peaks.push_back(p);
|
peaks.push_back(p);
|
||||||
targets.push_back(targetStartSample);
|
targets.push_back(targetStartSample);
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "mapped key-frame chunk to frame", sourceStartChunk, targetStartSample);
|
||||||
std::cerr << "mapped chunk " << sourceStartChunk << " (frame " << sourceStartChunk * m_increment << ") -> " << targetStartSample << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (peakidx < m_peaks.size()) {
|
while (peakidx < m_peaks.size()) {
|
||||||
|
|
||||||
@@ -316,9 +305,7 @@ StretchCalculator::mapPeaks(std::vector<Peak> &peaks,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "mapped peak chunk to frame", pchunk, target);
|
||||||
std::cerr << " peak chunk " << pchunk << " (frame " << pchunk * m_increment << ") -> " << target << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
peaks.push_back(p);
|
peaks.push_back(p);
|
||||||
targets.push_back(target);
|
targets.push_back(target);
|
||||||
@@ -389,9 +376,7 @@ StretchCalculator::calculateSingle(double timeRatio,
|
|||||||
// this function, which normally precedes resampling - hence
|
// this function, which normally precedes resampling - hence
|
||||||
// the use of timeRatio rather than ratio here
|
// the use of timeRatio rather than ratio here
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "StretchCalculator: ratio changed from and to", m_prevRatio, ratio);
|
||||||
std::cerr << "StretchCalculator: ratio changed from " << m_prevRatio << " to " << ratio << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t toCheckpoint = expectedOutFrame
|
int64_t toCheckpoint = expectedOutFrame
|
||||||
(m_inFrameCounter, m_prevTimeRatio);
|
(m_inFrameCounter, m_prevTimeRatio);
|
||||||
@@ -402,23 +387,25 @@ StretchCalculator::calculateSingle(double timeRatio,
|
|||||||
m_prevRatio = ratio;
|
m_prevRatio = ratio;
|
||||||
m_prevTimeRatio = timeRatio;
|
m_prevTimeRatio = timeRatio;
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
if (m_log.getDebugLevel() > 2) {
|
||||||
std::cerr << "StretchCalculator::calculateSingle: timeRatio = "
|
std::ostringstream os;
|
||||||
<< timeRatio << ", effectivePitchRatio = "
|
os << "StretchCalculator::calculateSingle: timeRatio = "
|
||||||
<< effectivePitchRatio << " (that's 1.0 / "
|
<< timeRatio << ", effectivePitchRatio = "
|
||||||
<< (1.0 / effectivePitchRatio)
|
<< effectivePitchRatio << " (that's 1.0 / "
|
||||||
<< "), ratio = " << ratio << ", df = " << df
|
<< (1.0 / effectivePitchRatio)
|
||||||
<< ", inIncrement = " << inIncrement
|
<< "), ratio = " << ratio << ", df = " << df
|
||||||
<< ", default outIncrement = " << outIncrement
|
<< ", inIncrement = " << inIncrement
|
||||||
<< ", analysisWindowSize = " << analysisWindowSize
|
<< ", default outIncrement = " << outIncrement
|
||||||
<< ", synthesisWindowSize = " << synthesisWindowSize
|
<< ", analysisWindowSize = " << analysisWindowSize
|
||||||
<< std::endl;
|
<< ", synthesisWindowSize = " << synthesisWindowSize
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
std::cerr << "inFrameCounter = " << m_inFrameCounter
|
os << "inFrameCounter = " << m_inFrameCounter
|
||||||
<< ", outFrameCounter = " << m_outFrameCounter
|
<< ", outFrameCounter = " << m_outFrameCounter
|
||||||
<< std::endl;
|
<< "\n";
|
||||||
|
|
||||||
std::cerr << "The next sample out is input sample " << m_inFrameCounter << std::endl;
|
os << "The next sample out is input sample " << m_inFrameCounter << "\n";
|
||||||
|
m_log.log(3, os.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t intended, projected;
|
int64_t intended, projected;
|
||||||
@@ -436,9 +423,8 @@ StretchCalculator::calculateSingle(double timeRatio,
|
|||||||
|
|
||||||
int64_t divergence = projected - intended;
|
int64_t divergence = projected - intended;
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "for current frame + quarter frame: intended vs projected", intended, projected);
|
||||||
std::cerr << "for current frame + quarter frame: intended " << intended << ", projected " << projected << ", divergence " << divergence << std::endl;
|
m_log.log(3, "divergence", divergence);
|
||||||
}
|
|
||||||
|
|
||||||
// In principle, the threshold depends on chunk size: larger chunk
|
// In principle, the threshold depends on chunk size: larger chunk
|
||||||
// sizes need higher thresholds. Since chunk size depends on
|
// sizes need higher thresholds. Since chunk size depends on
|
||||||
@@ -451,35 +437,26 @@ StretchCalculator::calculateSingle(double timeRatio,
|
|||||||
|
|
||||||
if (m_useHardPeaks && df > m_prevDf * 1.1f && df > transientThreshold) {
|
if (m_useHardPeaks && df > m_prevDf * 1.1f && df > transientThreshold) {
|
||||||
if (divergence > 1000 || divergence < -1000) {
|
if (divergence > 1000 || divergence < -1000) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "StretchCalculator::calculateSingle: transient, but we're not permitting it because the divergence is too great", divergence);
|
||||||
std::cerr << "StretchCalculator::calculateSingle: transient, but we're not permitting it because the divergence (" << divergence << ") is too great" << std::endl;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
isTransient = true;
|
isTransient = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "df and prevDf", df, m_prevDf);
|
||||||
std::cerr << "df = " << df << ", prevDf = " << m_prevDf
|
|
||||||
<< ", thresh = " << transientThreshold << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_prevDf = df;
|
m_prevDf = df;
|
||||||
|
|
||||||
if (m_transientAmnesty > 0) {
|
if (m_transientAmnesty > 0) {
|
||||||
if (isTransient) {
|
if (isTransient) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "StretchCalculator::calculateSingle: transient, but we have an amnesty: df and threshold", df, transientThreshold);
|
||||||
std::cerr << "StretchCalculator::calculateSingle: transient, but we have an amnesty (df " << df << ", threshold " << transientThreshold << ")" << std::endl;
|
|
||||||
}
|
|
||||||
isTransient = false;
|
isTransient = false;
|
||||||
}
|
}
|
||||||
--m_transientAmnesty;
|
--m_transientAmnesty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTransient) {
|
if (isTransient) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "StretchCalculator::calculateSingle: transient: df and threshold", df, transientThreshold);
|
||||||
std::cerr << "StretchCalculator::calculateSingle: transient at (df " << df << ", threshold " << transientThreshold << ")" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// as in offline mode, 0.05 sec approx min between transients
|
// as in offline mode, 0.05 sec approx min between transients
|
||||||
m_transientAmnesty =
|
m_transientAmnesty =
|
||||||
@@ -499,9 +476,10 @@ StretchCalculator::calculateSingle(double timeRatio,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int incr = lrint(outIncrement - recovery);
|
int incr = lrint(outIncrement - recovery);
|
||||||
if (m_debugLevel > 2 || (m_debugLevel > 1 && divergence != 0)) {
|
|
||||||
std::cerr << "divergence = " << divergence << ", recovery = " << recovery << ", incr = " << incr << ", ";
|
int level = (divergence != 0 ? 2 : 3);
|
||||||
}
|
m_log.log(level, "divergence and recovery", divergence, recovery);
|
||||||
|
m_log.log(level, "outIncrement and adjusted incr", outIncrement, incr);
|
||||||
|
|
||||||
int minIncr = lrint(increment * ratio * 0.3);
|
int minIncr = lrint(increment * ratio * 0.3);
|
||||||
int maxIncr = lrint(increment * ratio * 2);
|
int maxIncr = lrint(increment * ratio * 2);
|
||||||
@@ -512,25 +490,18 @@ StretchCalculator::calculateSingle(double timeRatio,
|
|||||||
incr = maxIncr;
|
incr = maxIncr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 2 || (m_debugLevel > 1 && divergence != 0)) {
|
m_log.log(level, "clamped into", minIncr, maxIncr);
|
||||||
std::cerr << "clamped into [" << minIncr << ", " << maxIncr
|
m_log.log(level, "giving incr", incr);
|
||||||
<< "] becomes " << incr << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (incr < 0) {
|
if (incr < 0) {
|
||||||
std::cerr << "WARNING: internal error: incr < 0 in calculateSingle"
|
m_log.log(0, "WARNING: internal error: incr < 0 in calculateSingle");
|
||||||
<< std::endl;
|
|
||||||
outIncrement = 0;
|
outIncrement = 0;
|
||||||
} else {
|
} else {
|
||||||
outIncrement = incr;
|
outIncrement = incr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "StretchCalculator::calculateSingle: returning isTransient and outIncrement", isTransient, outIncrement);
|
||||||
std::cerr << "StretchCalculator::calculateSingle: returning isTransient = "
|
|
||||||
<< isTransient << ", outIncrement = " << outIncrement
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_inFrameCounter += inIncrement;
|
m_inFrameCounter += inIncrement;
|
||||||
m_outFrameCounter += outIncrement * effectivePitchRatio;
|
m_outFrameCounter += outIncrement * effectivePitchRatio;
|
||||||
@@ -584,9 +555,7 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
(20 * double(m_increment))));
|
(20 * double(m_increment))));
|
||||||
size_t prevHardPeak = 0;
|
size_t prevHardPeak = 0;
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "hardPeakAmnesty", hardPeakAmnesty);
|
||||||
std::cerr << "hardPeakAmnesty = " << hardPeakAmnesty << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 1; i + 1 < df.size(); ++i) {
|
for (size_t i = 1; i + 1 < df.size(); ++i) {
|
||||||
|
|
||||||
@@ -600,20 +569,16 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool hard = (df[i] > 0.4);
|
bool hard = (df[i] > 0.4);
|
||||||
|
|
||||||
if (hard && (m_debugLevel > 1)) {
|
if (hard) {
|
||||||
std::cerr << "hard peak at " << i << ": " << df[i]
|
m_log.log(2, "hard peak, df > absolute 0.4: chunk and df", i, df[i]);
|
||||||
<< " > absolute " << 0.4
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hard) {
|
if (!hard) {
|
||||||
hard = (df[i] > df[i-1] * 1.4);
|
hard = (df[i] > df[i-1] * 1.4);
|
||||||
|
|
||||||
if (hard && (m_debugLevel > 1)) {
|
if (hard) {
|
||||||
std::cerr << "hard peak at " << i << ": " << df[i]
|
m_log.log(2, "hard peak, single rise of 40%: chunk and df", i, df[i]);
|
||||||
<< " > prev " << df[i-1] << " * 1.4"
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,11 +586,8 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
hard = (df[i] > df[i-1] * 1.2 &&
|
hard = (df[i] > df[i-1] * 1.2 &&
|
||||||
df[i-1] > df[i-2] * 1.2);
|
df[i-1] > df[i-2] * 1.2);
|
||||||
|
|
||||||
if (hard && (m_debugLevel > 1)) {
|
if (hard) {
|
||||||
std::cerr << "hard peak at " << i << ": " << df[i]
|
m_log.log(2, "hard peak, two rises of 20%: chunk and df", i, df[i]);
|
||||||
<< " > prev " << df[i-1] << " * 1.2 and "
|
|
||||||
<< df[i-1] << " > prev " << df[i-2] << " * 1.2"
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,20 +597,13 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
df[i-1] > df[i-2] * 1.1 &&
|
df[i-1] > df[i-2] * 1.1 &&
|
||||||
df[i-2] > df[i-3] * 1.1);
|
df[i-2] > df[i-3] * 1.1);
|
||||||
|
|
||||||
if (hard && (m_debugLevel > 1)) {
|
if (hard) {
|
||||||
std::cerr << "hard peak at " << i << ": " << df[i]
|
m_log.log(2, "hard peak, three rises of 10%: chunk and df", i, df[i]);
|
||||||
<< " > prev " << df[i-1] << " * 1.1 and "
|
|
||||||
<< df[i-1] << " > prev " << df[i-2] << " * 1.1 and "
|
|
||||||
<< df[i-2] << " > prev " << df[i-3] << " * 1.1"
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hard) continue;
|
if (!hard) continue;
|
||||||
|
|
||||||
// (df[i+1] > df[i] && df[i+1] > df[i-1] * 1.8) ||
|
|
||||||
// df[i] > 0.4) {
|
|
||||||
|
|
||||||
size_t peakLocation = i;
|
size_t peakLocation = i;
|
||||||
|
|
||||||
if (i + 1 < rawDf.size() &&
|
if (i + 1 < rawDf.size() &&
|
||||||
@@ -656,9 +611,7 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
|
|
||||||
++peakLocation;
|
++peakLocation;
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "big rise next, pushing hard peak forward to", peakLocation);
|
||||||
std::cerr << "pushing hard peak forward to " << peakLocation << ": " << df[peakLocation] << " > " << df[peakLocation-1] << " * " << 1.4 << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hardPeakCandidates.insert(peakLocation);
|
hardPeakCandidates.insert(peakLocation);
|
||||||
@@ -669,14 +622,10 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
size_t medianmaxsize = lrint(ceil(double(m_sampleRate) /
|
size_t medianmaxsize = lrint(ceil(double(m_sampleRate) /
|
||||||
double(m_increment))); // 1 sec ish
|
double(m_increment))); // 1 sec ish
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "mediansize", medianmaxsize);
|
||||||
std::cerr << "mediansize = " << medianmaxsize << std::endl;
|
|
||||||
}
|
|
||||||
if (medianmaxsize < 7) {
|
if (medianmaxsize < 7) {
|
||||||
medianmaxsize = 7;
|
medianmaxsize = 7;
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "adjusted mediansize", medianmaxsize);
|
||||||
std::cerr << "adjusted mediansize = " << medianmaxsize << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int minspacing = lrint(ceil(double(m_sampleRate) /
|
int minspacing = lrint(ceil(double(m_sampleRate) /
|
||||||
@@ -720,10 +669,6 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
|
||||||
// std::cerr << "have " << mediansize << " in median buffer" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
sorted.clear();
|
sorted.clear();
|
||||||
for (size_t j = 0; j < mediansize; ++j) {
|
for (size_t j = 0; j < mediansize; ++j) {
|
||||||
sorted.push_back(medianwin[j]);
|
sorted.push_back(medianwin[j]);
|
||||||
@@ -736,17 +681,6 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
if (index == sorted.size()-1 && index > 0) --index;
|
if (index == sorted.size()-1 && index > 0) --index;
|
||||||
float thresh = sorted[index];
|
float thresh = sorted[index];
|
||||||
|
|
||||||
// if (m_debugLevel > 2) {
|
|
||||||
// std::cerr << "medianwin[" << middle << "] = " << medianwin[middle] << ", thresh = " << thresh << std::endl;
|
|
||||||
// if (medianwin[middle] == 0.f) {
|
|
||||||
// std::cerr << "contents: ";
|
|
||||||
// for (size_t j = 0; j < medianwin.size(); ++j) {
|
|
||||||
// std::cerr << medianwin[j] << " ";
|
|
||||||
// }
|
|
||||||
// std::cerr << std::endl;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (medianwin[middle] > thresh &&
|
if (medianwin[middle] > thresh &&
|
||||||
medianwin[middle] > medianwin[middle-1] &&
|
medianwin[middle] > medianwin[middle-1] &&
|
||||||
medianwin[middle] > medianwin[middle+1] &&
|
medianwin[middle] > medianwin[middle+1] &&
|
||||||
@@ -766,26 +700,10 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
|
|
||||||
size_t peak = i + maxindex - middle;
|
size_t peak = i + maxindex - middle;
|
||||||
|
|
||||||
// std::cerr << "i = " << i << ", maxindex = " << maxindex << ", middle = " << middle << ", so peak at " << peak << std::endl;
|
|
||||||
|
|
||||||
if (softPeakCandidates.empty() || lastSoftPeak != peak) {
|
if (softPeakCandidates.empty() || lastSoftPeak != peak) {
|
||||||
|
m_log.log(2, "soft peak: chunk and median df", peak, medianwin[middle]);
|
||||||
if (m_debugLevel > 1) {
|
|
||||||
std::cerr << "soft peak at " << peak << " ("
|
|
||||||
<< peak * m_increment << "): "
|
|
||||||
<< medianwin[middle] << " > "
|
|
||||||
<< thresh << " and "
|
|
||||||
<< medianwin[middle]
|
|
||||||
<< " > " << medianwin[middle-1] << " and "
|
|
||||||
<< medianwin[middle]
|
|
||||||
<< " > " << medianwin[middle+1]
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peak >= df.size()) {
|
if (peak >= df.size()) {
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(2, "peak is beyond end");
|
||||||
std::cerr << "peak is beyond end" << std::endl;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
softPeakCandidates.insert(peak);
|
softPeakCandidates.insert(peak);
|
||||||
lastSoftPeak = peak;
|
lastSoftPeak = peak;
|
||||||
@@ -793,9 +711,7 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
softPeakAmnesty = minspacing + maxindex - middle;
|
softPeakAmnesty = minspacing + maxindex - middle;
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "amnesty", softPeakAmnesty);
|
||||||
std::cerr << "amnesty = " << softPeakAmnesty << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (softPeakAmnesty > 0) --softPeakAmnesty;
|
} else if (softPeakAmnesty > 0) --softPeakAmnesty;
|
||||||
|
|
||||||
@@ -827,26 +743,16 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
|||||||
|
|
||||||
if (haveHardPeak &&
|
if (haveHardPeak &&
|
||||||
(!haveSoftPeak || hardPeak <= softPeak)) {
|
(!haveSoftPeak || hardPeak <= softPeak)) {
|
||||||
|
m_log.log(3, "hard peak", hardPeak);
|
||||||
if (m_debugLevel > 2) {
|
|
||||||
std::cerr << "Hard peak: " << hardPeak << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
peak.hard = true;
|
peak.hard = true;
|
||||||
peak.chunk = hardPeak;
|
peak.chunk = hardPeak;
|
||||||
hardPeakCandidates.erase(hardPeakCandidates.begin());
|
hardPeakCandidates.erase(hardPeakCandidates.begin());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "soft peak", softPeak);
|
||||||
std::cerr << "Soft peak: " << softPeak << std::endl;
|
|
||||||
}
|
|
||||||
if (!peaks.empty() &&
|
if (!peaks.empty() &&
|
||||||
peaks[peaks.size()-1].hard &&
|
peaks[peaks.size()-1].hard &&
|
||||||
peaks[peaks.size()-1].chunk + 3 >= softPeak) {
|
peaks[peaks.size()-1].chunk + 3 >= softPeak) {
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "ignoring, as we just had a hard peak");
|
||||||
std::cerr << "(ignoring, as we just had a hard peak)"
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
ignore = true;
|
ignore = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,13 +30,18 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
namespace RubberBand
|
namespace RubberBand
|
||||||
{
|
{
|
||||||
|
|
||||||
class StretchCalculator
|
class StretchCalculator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StretchCalculator(size_t sampleRate, size_t inputIncrement, bool useHardPeaks);
|
StretchCalculator(size_t sampleRate,
|
||||||
|
size_t inputIncrement,
|
||||||
|
bool useHardPeaks,
|
||||||
|
Log log);
|
||||||
virtual ~StretchCalculator();
|
virtual ~StretchCalculator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,6 +112,7 @@ protected:
|
|||||||
std::pair<int64_t, int64_t> m_frameCheckpoint;
|
std::pair<int64_t, int64_t> m_frameCheckpoint;
|
||||||
int64_t expectedOutFrame(int64_t inFrame, double timeRatio);
|
int64_t expectedOutFrame(int64_t inFrame, double timeRatio);
|
||||||
double m_outFrameCounter;
|
double m_outFrameCounter;
|
||||||
|
Log m_log;
|
||||||
|
|
||||||
std::map<size_t, size_t> m_keyFrameMap;
|
std::map<size_t, size_t> m_keyFrameMap;
|
||||||
std::vector<Peak> m_peaks;
|
std::vector<Peak> m_peaks;
|
||||||
|
|||||||
@@ -40,8 +40,6 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using std::cerr;
|
|
||||||
using std::endl;
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::map;
|
using std::map;
|
||||||
using std::set;
|
using std::set;
|
||||||
@@ -56,16 +54,14 @@ R2Stretcher::m_defaultIncrement = 256;
|
|||||||
const size_t
|
const size_t
|
||||||
R2Stretcher::m_defaultFftSize = 2048;
|
R2Stretcher::m_defaultFftSize = 2048;
|
||||||
|
|
||||||
int
|
|
||||||
R2Stretcher::m_defaultDebugLevel = 0;
|
|
||||||
|
|
||||||
static bool _initialised = false;
|
static bool _initialised = false;
|
||||||
|
|
||||||
R2Stretcher::R2Stretcher(size_t sampleRate,
|
R2Stretcher::R2Stretcher(size_t sampleRate,
|
||||||
size_t channels,
|
size_t channels,
|
||||||
RubberBandStretcher::Options options,
|
RubberBandStretcher::Options options,
|
||||||
double initialTimeRatio,
|
double initialTimeRatio,
|
||||||
double initialPitchScale) :
|
double initialPitchScale,
|
||||||
|
Log log) :
|
||||||
m_sampleRate(sampleRate),
|
m_sampleRate(sampleRate),
|
||||||
m_channels(channels),
|
m_channels(channels),
|
||||||
m_timeRatio(initialTimeRatio),
|
m_timeRatio(initialTimeRatio),
|
||||||
@@ -82,7 +78,7 @@ R2Stretcher::R2Stretcher(size_t sampleRate,
|
|||||||
#endif
|
#endif
|
||||||
m_realtime(false),
|
m_realtime(false),
|
||||||
m_options(options),
|
m_options(options),
|
||||||
m_debugLevel(m_defaultDebugLevel),
|
m_log(log),
|
||||||
m_mode(JustCreated),
|
m_mode(JustCreated),
|
||||||
m_awindow(0),
|
m_awindow(0),
|
||||||
m_afilter(0),
|
m_afilter(0),
|
||||||
@@ -110,9 +106,10 @@ R2Stretcher::R2Stretcher(size_t sampleRate,
|
|||||||
_initialised = true;
|
_initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "R2Stretcher::R2Stretcher: rate, options",
|
||||||
cerr << "R2Stretcher::R2Stretcher: rate = " << m_sampleRate << ", options = " << options << endl;
|
m_sampleRate, options);
|
||||||
}
|
m_log.log(1, "R2Stretcher::R2Stretcher: initial time ratio and pitch scale",
|
||||||
|
m_timeRatio, m_pitchScale);
|
||||||
|
|
||||||
// Window size will vary according to the audio sample rate, but
|
// Window size will vary according to the audio sample rate, but
|
||||||
// we don't let it drop below the 48k default
|
// we don't let it drop below the 48k default
|
||||||
@@ -124,17 +121,13 @@ R2Stretcher::R2Stretcher(size_t sampleRate,
|
|||||||
(options & RubberBandStretcher::OptionWindowLong)) {
|
(options & RubberBandStretcher::OptionWindowLong)) {
|
||||||
if ((options & RubberBandStretcher::OptionWindowShort) &&
|
if ((options & RubberBandStretcher::OptionWindowShort) &&
|
||||||
(options & RubberBandStretcher::OptionWindowLong)) {
|
(options & RubberBandStretcher::OptionWindowLong)) {
|
||||||
cerr << "R2Stretcher::R2Stretcher: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl;
|
m_log.log(0, "R2Stretcher::R2Stretcher: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard");
|
||||||
} else if (options & RubberBandStretcher::OptionWindowShort) {
|
} else if (options & RubberBandStretcher::OptionWindowShort) {
|
||||||
m_baseFftSize = m_baseFftSize / 2;
|
m_baseFftSize = m_baseFftSize / 2;
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "setting baseFftSize", m_baseFftSize);
|
||||||
cerr << "setting baseFftSize to " << m_baseFftSize << endl;
|
|
||||||
}
|
|
||||||
} else if (options & RubberBandStretcher::OptionWindowLong) {
|
} else if (options & RubberBandStretcher::OptionWindowLong) {
|
||||||
m_baseFftSize = m_baseFftSize * 2;
|
m_baseFftSize = m_baseFftSize * 2;
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "setting baseFftSize", m_baseFftSize);
|
||||||
cerr << "setting baseFftSize to " << m_baseFftSize << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_fftSize = m_baseFftSize;
|
m_fftSize = m_baseFftSize;
|
||||||
m_aWindowSize = m_baseFftSize;
|
m_aWindowSize = m_baseFftSize;
|
||||||
@@ -161,8 +154,8 @@ R2Stretcher::R2Stretcher(size_t sampleRate,
|
|||||||
m_threaded = false;
|
m_threaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_threaded && m_debugLevel > 0) {
|
if (m_threaded) {
|
||||||
cerr << "Going multithreaded..." << endl;
|
m_log.log(1, "Going multithreaded...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -177,9 +170,7 @@ R2Stretcher::~R2Stretcher()
|
|||||||
MutexLocker locker(&m_threadSetMutex);
|
MutexLocker locker(&m_threadSetMutex);
|
||||||
for (set<ProcessThread *>::iterator i = m_threadSet.begin();
|
for (set<ProcessThread *>::iterator i = m_threadSet.begin();
|
||||||
i != m_threadSet.end(); ++i) {
|
i != m_threadSet.end(); ++i) {
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "RubberBandStretcher::~RubberBandStretcher: joining for channel", (*i)->channel());
|
||||||
cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
|
|
||||||
}
|
|
||||||
(*i)->abandon();
|
(*i)->abandon();
|
||||||
(*i)->wait();
|
(*i)->wait();
|
||||||
delete *i;
|
delete *i;
|
||||||
@@ -214,9 +205,7 @@ R2Stretcher::reset()
|
|||||||
m_threadSetMutex.lock();
|
m_threadSetMutex.lock();
|
||||||
for (set<ProcessThread *>::iterator i = m_threadSet.begin();
|
for (set<ProcessThread *>::iterator i = m_threadSet.begin();
|
||||||
i != m_threadSet.end(); ++i) {
|
i != m_threadSet.end(); ++i) {
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "RubberBandStretcher::~RubberBandStretcher: joining for channel", (*i)->channel());
|
||||||
cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
|
|
||||||
}
|
|
||||||
(*i)->abandon();
|
(*i)->abandon();
|
||||||
(*i)->wait();
|
(*i)->wait();
|
||||||
delete *i;
|
delete *i;
|
||||||
@@ -253,7 +242,7 @@ R2Stretcher::setTimeRatio(double ratio)
|
|||||||
{
|
{
|
||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
if (m_mode == Studying || m_mode == Processing) {
|
if (m_mode == Studying || m_mode == Processing) {
|
||||||
cerr << "R2Stretcher::setTimeRatio: Cannot set ratio while studying or processing in non-RT mode" << endl;
|
m_log.log(0, "R2Stretcher::setTimeRatio: Cannot set ratio while studying or processing in non-RT mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,7 +258,7 @@ R2Stretcher::setPitchScale(double fs)
|
|||||||
{
|
{
|
||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
if (m_mode == Studying || m_mode == Processing) {
|
if (m_mode == Studying || m_mode == Processing) {
|
||||||
cerr << "R2Stretcher::setPitchScale: Cannot set ratio while studying or processing in non-RT mode" << endl;
|
m_log.log(0, "R2Stretcher::setPitchScale: Cannot set ratio while studying or processing in non-RT mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -331,11 +320,11 @@ R2Stretcher::setKeyFrameMap(const std::map<size_t, size_t> &
|
|||||||
mapping)
|
mapping)
|
||||||
{
|
{
|
||||||
if (m_realtime) {
|
if (m_realtime) {
|
||||||
cerr << "R2Stretcher::setKeyFrameMap: Cannot specify key frame map in RT mode" << endl;
|
m_log.log(0, "R2Stretcher::setKeyFrameMap: Cannot specify key frame map in RT mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_mode == Processing) {
|
if (m_mode == Processing) {
|
||||||
cerr << "R2Stretcher::setKeyFrameMap: Cannot specify key frame map after process() has begun" << endl;
|
m_log.log(0, "R2Stretcher::setKeyFrameMap: Cannot specify key frame map after process() has begun");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,12 +392,12 @@ R2Stretcher::calculateSizes()
|
|||||||
// This special case is likelier than one might hope, because
|
// This special case is likelier than one might hope, because
|
||||||
// of naive initialisations in programs that set it from a
|
// of naive initialisations in programs that set it from a
|
||||||
// variable
|
// variable
|
||||||
std::cerr << "RubberBandStretcher: WARNING: Pitch scale must be greater than zero!\nResetting it from " << m_pitchScale << " to the default of 1.0: no pitch change will occur" << std::endl;
|
m_log.log(0, "WARNING: Pitch scale must be greater than zero! Resetting it to default, no pitch shift will happen", m_pitchScale);
|
||||||
m_pitchScale = 1.0;
|
m_pitchScale = 1.0;
|
||||||
}
|
}
|
||||||
if (m_timeRatio <= 0.0) {
|
if (m_timeRatio <= 0.0) {
|
||||||
// Likewise
|
// Likewise
|
||||||
std::cerr << "RubberBandStretcher: WARNING: Time ratio must be greater than zero!\nResetting it from " << m_timeRatio << " to the default of 1.0: no time stretch will occur" << std::endl;
|
m_log.log(0, "WARNING: Time ratio must be greater than zero! Resetting it to default, no time stretch will happen", m_timeRatio);
|
||||||
m_timeRatio = 1.0;
|
m_timeRatio = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +450,7 @@ R2Stretcher::calculateSizes()
|
|||||||
if (windowSize < minwin) windowSize = minwin;
|
if (windowSize < minwin) windowSize = minwin;
|
||||||
|
|
||||||
if (rsb) {
|
if (rsb) {
|
||||||
// cerr << "adjusting window size from " << windowSize;
|
size_t oldWindowSize = windowSize;
|
||||||
size_t newWindowSize = roundUp(lrint(windowSize / m_pitchScale));
|
size_t newWindowSize = roundUp(lrint(windowSize / m_pitchScale));
|
||||||
if (newWindowSize < 512) newWindowSize = 512;
|
if (newWindowSize < 512) newWindowSize = 512;
|
||||||
size_t div = windowSize / newWindowSize;
|
size_t div = windowSize / newWindowSize;
|
||||||
@@ -470,7 +459,8 @@ R2Stretcher::calculateSizes()
|
|||||||
outputIncrement /= div;
|
outputIncrement /= div;
|
||||||
windowSize /= div;
|
windowSize /= div;
|
||||||
}
|
}
|
||||||
// cerr << " to " << windowSize << " (inputIncrement = " << inputIncrement << ", outputIncrement = " << outputIncrement << ")" << endl;
|
m_log.log(2, "adjusting window size from/to", oldWindowSize, windowSize);
|
||||||
|
m_log.log(2, "input and output increments", inputIncrement, outputIncrement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,10 +520,11 @@ R2Stretcher::calculateSizes()
|
|||||||
// twice the basic output increment (i.e. input increment times
|
// twice the basic output increment (i.e. input increment times
|
||||||
// ratio) for any chunk.
|
// ratio) for any chunk.
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "calculateSizes: time ratio and pitch scale", m_timeRatio, m_pitchScale);
|
||||||
cerr << "calculateSizes: time ratio = " << m_timeRatio << ", pitch scale = " << m_pitchScale << ", effective ratio = " << getEffectiveRatio() << endl;
|
m_log.log(1, "effective ratio", getEffectiveRatio());
|
||||||
cerr << "calculateSizes: analysis window size = " << m_aWindowSize << ", synthesis window size = " << m_sWindowSize << ", fft size = " << m_fftSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl;
|
m_log.log(1, "analysis and synthesis window sizes", m_aWindowSize, m_sWindowSize);
|
||||||
}
|
m_log.log(1, "fft size", m_fftSize);
|
||||||
|
m_log.log(1, "input increment and mean output increment", m_increment, m_increment * getEffectiveRatio());
|
||||||
|
|
||||||
if (std::max(m_aWindowSize, m_sWindowSize) > m_maxProcessSize) {
|
if (std::max(m_aWindowSize, m_sWindowSize) > m_maxProcessSize) {
|
||||||
m_maxProcessSize = std::max(m_aWindowSize, m_sWindowSize);
|
m_maxProcessSize = std::max(m_aWindowSize, m_sWindowSize);
|
||||||
@@ -561,18 +552,19 @@ R2Stretcher::calculateSizes()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "calculateSizes: outbuf size", m_outbufSize);
|
||||||
cerr << "calculateSizes: outbuf size = " << m_outbufSize << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
R2Stretcher::configure()
|
R2Stretcher::configure()
|
||||||
{
|
{
|
||||||
if (m_debugLevel > 0) {
|
if (m_realtime) {
|
||||||
std::cerr << "configure[" << this << "]: realtime = " << m_realtime << ", pitch scale = "
|
m_log.log(1, "configure, realtime: pitch scale and channels",
|
||||||
<< m_pitchScale << ", channels = " << m_channels << std::endl;
|
m_pitchScale, m_channels);
|
||||||
}
|
} else {
|
||||||
|
m_log.log(1, "configure, offline: pitch scale and channels",
|
||||||
|
m_pitchScale, m_channels);
|
||||||
|
}
|
||||||
|
|
||||||
size_t prevFftSize = m_fftSize;
|
size_t prevFftSize = m_fftSize;
|
||||||
size_t prevAWindowSize = m_aWindowSize;
|
size_t prevAWindowSize = m_aWindowSize;
|
||||||
@@ -626,9 +618,8 @@ R2Stretcher::configure()
|
|||||||
m_afilter = m_sincs[m_aWindowSize];
|
m_afilter = m_sincs[m_aWindowSize];
|
||||||
m_swindow = m_windows[m_sWindowSize];
|
m_swindow = m_windows[m_sWindowSize];
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "analysis and synthesis window areas",
|
||||||
cerr << "Window area: " << m_awindow->getArea() << "; synthesis window area: " << m_swindow->getArea() << endl;
|
m_awindow->getArea(), m_swindow->getArea());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windowSizeChanged || outbufSizeChanged) {
|
if (windowSizeChanged || outbufSizeChanged) {
|
||||||
@@ -649,7 +640,7 @@ R2Stretcher::configure()
|
|||||||
|
|
||||||
if (!m_realtime && fftSizeChanged) {
|
if (!m_realtime && fftSizeChanged) {
|
||||||
delete m_studyFFT;
|
delete m_studyFFT;
|
||||||
m_studyFFT = new FFT(m_fftSize, m_debugLevel);
|
m_studyFFT = new FFT(m_fftSize, m_log.getDebugLevel());
|
||||||
m_studyFFT->initFloat();
|
m_studyFFT->initFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,7 +665,8 @@ R2Stretcher::configure()
|
|||||||
}
|
}
|
||||||
|
|
||||||
params.maxBufferSize = 4096 * 16;
|
params.maxBufferSize = 4096 * 16;
|
||||||
params.debugLevel = (m_debugLevel > 0 ? m_debugLevel-1 : 0);
|
int myLevel = m_log.getDebugLevel();
|
||||||
|
params.debugLevel = (myLevel > 0 ? myLevel-1 : 0);
|
||||||
|
|
||||||
m_channelData[c]->resampler = new Resampler(params, 1);
|
m_channelData[c]->resampler = new Resampler(params, 1);
|
||||||
|
|
||||||
@@ -700,9 +692,10 @@ R2Stretcher::configure()
|
|||||||
delete m_stretchCalculator;
|
delete m_stretchCalculator;
|
||||||
m_stretchCalculator = new StretchCalculator
|
m_stretchCalculator = new StretchCalculator
|
||||||
(m_sampleRate, m_increment,
|
(m_sampleRate, m_increment,
|
||||||
!(m_options & RubberBandStretcher::OptionTransientsSmooth));
|
!(m_options & RubberBandStretcher::OptionTransientsSmooth),
|
||||||
|
m_log);
|
||||||
|
|
||||||
m_stretchCalculator->setDebugLevel(m_debugLevel);
|
m_stretchCalculator->setDebugLevel(m_log.getDebugLevel());
|
||||||
m_inputDuration = 0;
|
m_inputDuration = 0;
|
||||||
|
|
||||||
// Prepare the inbufs with half a chunk of emptiness. The centre
|
// Prepare the inbufs with half a chunk of emptiness. The centre
|
||||||
@@ -717,17 +710,16 @@ R2Stretcher::configure()
|
|||||||
// want gaps when the ratio changes.
|
// want gaps when the ratio changes.
|
||||||
|
|
||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(1, "offline mode: prefilling with", m_aWindowSize/2);
|
||||||
cerr << "Not real time mode: prefilling with " << m_aWindowSize/2 << " samples" << endl;
|
|
||||||
}
|
|
||||||
for (size_t c = 0; c < m_channels; ++c) {
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
m_channelData[c]->reset();
|
m_channelData[c]->reset();
|
||||||
m_channelData[c]->inbuf->zero(m_aWindowSize/2);
|
m_channelData[c]->inbuf->zero(m_aWindowSize/2);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
m_log.log(1, "realtime mode: no prefill");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
R2Stretcher::reconfigure()
|
R2Stretcher::reconfigure()
|
||||||
{
|
{
|
||||||
@@ -763,7 +755,7 @@ R2Stretcher::reconfigure()
|
|||||||
m_sWindowSize != prevSWindowSize) {
|
m_sWindowSize != prevSWindowSize) {
|
||||||
|
|
||||||
if (m_windows.find(m_aWindowSize) == m_windows.end()) {
|
if (m_windows.find(m_aWindowSize) == m_windows.end()) {
|
||||||
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_aWindowSize << ") required in RT mode" << std::endl;
|
m_log.log(0, "WARNING: reconfigure(): window allocation required in realtime mode, size", m_aWindowSize);
|
||||||
m_windows[m_aWindowSize] = new Window<float>
|
m_windows[m_aWindowSize] = new Window<float>
|
||||||
(HannWindow, m_aWindowSize);
|
(HannWindow, m_aWindowSize);
|
||||||
m_sincs[m_aWindowSize] = new SincWindow<float>
|
m_sincs[m_aWindowSize] = new SincWindow<float>
|
||||||
@@ -771,7 +763,7 @@ R2Stretcher::reconfigure()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_windows.find(m_sWindowSize) == m_windows.end()) {
|
if (m_windows.find(m_sWindowSize) == m_windows.end()) {
|
||||||
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_sWindowSize << ") required in RT mode" << std::endl;
|
m_log.log(0, "WARNING: reconfigure(): window allocation required in realtime mode, size", m_sWindowSize);
|
||||||
m_windows[m_sWindowSize] = new Window<float>
|
m_windows[m_sWindowSize] = new Window<float>
|
||||||
(HannWindow, m_sWindowSize);
|
(HannWindow, m_sWindowSize);
|
||||||
m_sincs[m_sWindowSize] = new SincWindow<float>
|
m_sincs[m_sWindowSize] = new SincWindow<float>
|
||||||
@@ -802,14 +794,15 @@ R2Stretcher::reconfigure()
|
|||||||
|
|
||||||
if (m_channelData[c]->resampler) continue;
|
if (m_channelData[c]->resampler) continue;
|
||||||
|
|
||||||
std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl;
|
m_log.log(0, "WARNING: reconfigure(): resampler construction required in RT mode");
|
||||||
|
|
||||||
Resampler::Parameters params;
|
Resampler::Parameters params;
|
||||||
params.quality = Resampler::FastestTolerable;
|
params.quality = Resampler::FastestTolerable;
|
||||||
params.dynamism = Resampler::RatioOftenChanging;
|
params.dynamism = Resampler::RatioOftenChanging;
|
||||||
params.ratioChange = Resampler::SmoothRatioChange;
|
params.ratioChange = Resampler::SmoothRatioChange;
|
||||||
params.maxBufferSize = m_sWindowSize;
|
params.maxBufferSize = m_sWindowSize;
|
||||||
params.debugLevel = (m_debugLevel > 0 ? m_debugLevel-1 : 0);
|
int myLevel = m_log.getDebugLevel();
|
||||||
|
params.debugLevel = (myLevel > 0 ? myLevel-1 : 0);
|
||||||
|
|
||||||
m_channelData[c]->resampler = new Resampler(params, 1);
|
m_channelData[c]->resampler = new Resampler(params, 1);
|
||||||
|
|
||||||
@@ -828,12 +821,10 @@ R2Stretcher::reconfigure()
|
|||||||
somethingChanged = true;
|
somethingChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
if (somethingChanged) {
|
||||||
if (somethingChanged) {
|
m_log.log(1, "reconfigure: at least one parameter changed");
|
||||||
std::cerr << "reconfigure: at least one parameter changed" << std::endl;
|
} else {
|
||||||
} else {
|
m_log.log(1, "reconfigure: nothing changed");
|
||||||
std::cerr << "reconfigure: nothing changed" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,7 +839,7 @@ void
|
|||||||
R2Stretcher::setTransientsOption(RubberBandStretcher::Options options)
|
R2Stretcher::setTransientsOption(RubberBandStretcher::Options options)
|
||||||
{
|
{
|
||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
cerr << "R2Stretcher::setTransientsOption: Not permissible in non-realtime mode" << endl;
|
m_log.log(0, "R2Stretcher::setTransientsOption: Not permissible in non-realtime mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int mask = (RubberBandStretcher::OptionTransientsMixed |
|
int mask = (RubberBandStretcher::OptionTransientsMixed |
|
||||||
@@ -866,7 +857,7 @@ void
|
|||||||
R2Stretcher::setDetectorOption(RubberBandStretcher::Options options)
|
R2Stretcher::setDetectorOption(RubberBandStretcher::Options options)
|
||||||
{
|
{
|
||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
cerr << "R2Stretcher::setDetectorOption: Not permissible in non-realtime mode" << endl;
|
m_log.log(0, "R2Stretcher::setDetectorOption: Not permissible in non-realtime mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int mask = (RubberBandStretcher::OptionDetectorPercussive |
|
int mask = (RubberBandStretcher::OptionDetectorPercussive |
|
||||||
@@ -915,7 +906,7 @@ void
|
|||||||
R2Stretcher::setPitchOption(RubberBandStretcher::Options options)
|
R2Stretcher::setPitchOption(RubberBandStretcher::Options options)
|
||||||
{
|
{
|
||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
cerr << "R2Stretcher::setPitchOption: Pitch option is not used in non-RT mode" << endl;
|
m_log.log(0, "R2Stretcher::setPitchOption: Pitch option is not used in non-RT mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -937,14 +928,12 @@ R2Stretcher::study(const float *const *input, size_t samples, bool final)
|
|||||||
Profiler profiler("R2Stretcher::study");
|
Profiler profiler("R2Stretcher::study");
|
||||||
|
|
||||||
if (m_realtime) {
|
if (m_realtime) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(0, "R2Stretcher::study: Not meaningful in realtime mode");
|
||||||
cerr << "R2Stretcher::study: Not meaningful in realtime mode" << endl;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_mode == Processing || m_mode == Finished) {
|
if (m_mode == Processing || m_mode == Finished) {
|
||||||
cerr << "R2Stretcher::study: Cannot study after processing" << endl;
|
m_log.log(0, "R2Stretcher::study: Cannot study after processing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_mode = Studying;
|
m_mode = Studying;
|
||||||
@@ -987,7 +976,8 @@ R2Stretcher::study(const float *const *input, size_t samples, bool final)
|
|||||||
|
|
||||||
if (writable == 0) {
|
if (writable == 0) {
|
||||||
// warn
|
// warn
|
||||||
cerr << "WARNING: writable == 0 (consumed = " << consumed << ", samples = " << samples << ")" << endl;
|
m_log.log(0, "WARNING: writable == 0: consumed, samples",
|
||||||
|
consumed, samples);
|
||||||
} else {
|
} else {
|
||||||
inbuf.write(mixdown + consumed, writable);
|
inbuf.write(mixdown + consumed, writable);
|
||||||
consumed += writable;
|
consumed += writable;
|
||||||
@@ -1048,8 +1038,8 @@ R2Stretcher::study(const float *const *input, size_t samples, bool final)
|
|||||||
|
|
||||||
df = m_silentAudioCurve->processFloat(cd.fltbuf, m_increment);
|
df = m_silentAudioCurve->processFloat(cd.fltbuf, m_increment);
|
||||||
bool silent = (df > 0.f);
|
bool silent = (df > 0.f);
|
||||||
if (silent && m_debugLevel > 1) {
|
if (silent) {
|
||||||
cerr << "silence found at " << m_inputDuration << endl;
|
m_log.log(2, "silence at", m_inputDuration);
|
||||||
}
|
}
|
||||||
m_silence.push_back(silent);
|
m_silence.push_back(silent);
|
||||||
|
|
||||||
@@ -1063,7 +1053,6 @@ R2Stretcher::study(const float *const *input, size_t samples, bool final)
|
|||||||
// extra afterwards.
|
// extra afterwards.
|
||||||
|
|
||||||
m_inputDuration += m_increment;
|
m_inputDuration += m_increment;
|
||||||
// cerr << "incr input duration by increment: " << m_increment << " -> " << m_inputDuration << endl;
|
|
||||||
inbuf.skip(m_increment);
|
inbuf.skip(m_increment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1071,8 +1060,6 @@ R2Stretcher::study(const float *const *input, size_t samples, bool final)
|
|||||||
if (final) {
|
if (final) {
|
||||||
int rs = inbuf.getReadSpace();
|
int rs = inbuf.getReadSpace();
|
||||||
m_inputDuration += rs;
|
m_inputDuration += rs;
|
||||||
// cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl;
|
|
||||||
|
|
||||||
if (m_inputDuration > m_aWindowSize/2) { // deducting the extra
|
if (m_inputDuration > m_aWindowSize/2) { // deducting the extra
|
||||||
m_inputDuration -= m_aWindowSize/2;
|
m_inputDuration -= m_aWindowSize/2;
|
||||||
}
|
}
|
||||||
@@ -1132,7 +1119,7 @@ R2Stretcher::calculateStretch()
|
|||||||
|
|
||||||
if (!m_realtime && m_expectedInputDuration > 0) {
|
if (!m_realtime && m_expectedInputDuration > 0) {
|
||||||
if (m_expectedInputDuration != inputDuration) {
|
if (m_expectedInputDuration != inputDuration) {
|
||||||
std::cerr << "RubberBandStretcher: WARNING: Actual study() duration differs from duration set by setExpectedInputDuration (" << m_inputDuration << " vs " << m_expectedInputDuration << ", diff = " << (m_expectedInputDuration - m_inputDuration) << "), using the latter for calculation" << std::endl;
|
m_log.log(0, "WARNING: Actual study() duration differs from duration set by setExpectedInputDuration - using the latter for calculation", m_inputDuration, m_expectedInputDuration);
|
||||||
inputDuration = m_expectedInputDuration;
|
inputDuration = m_expectedInputDuration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1149,10 +1136,7 @@ R2Stretcher::calculateStretch()
|
|||||||
else history = 0;
|
else history = 0;
|
||||||
if (history >= int(m_aWindowSize / m_increment) && increments[i] >= 0) {
|
if (history >= int(m_aWindowSize / m_increment) && increments[i] >= 0) {
|
||||||
increments[i] = -increments[i];
|
increments[i] = -increments[i];
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "phase reset on silence: silent history", history);
|
||||||
std::cerr << "phase reset on silence (silent history == "
|
|
||||||
<< history << ")" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1169,8 +1153,10 @@ R2Stretcher::calculateStretch()
|
|||||||
void
|
void
|
||||||
R2Stretcher::setDebugLevel(int level)
|
R2Stretcher::setDebugLevel(int level)
|
||||||
{
|
{
|
||||||
m_debugLevel = level;
|
m_log.setDebugLevel(level);
|
||||||
if (m_stretchCalculator) m_stretchCalculator->setDebugLevel(level);
|
if (m_stretchCalculator) {
|
||||||
|
m_stretchCalculator->setDebugLevel(level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
@@ -1191,9 +1177,7 @@ R2Stretcher::getSamplesRequired() const
|
|||||||
size_t rs = inbuf.getReadSpace();
|
size_t rs = inbuf.getReadSpace();
|
||||||
size_t ws = outbuf.getReadSpace();
|
size_t ws = outbuf.getReadSpace();
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "getSamplesRequired: ws and rs ", ws, rs);
|
||||||
cerr << "getSamplesRequired: ws = " << ws << ", rs = " << rs << ", m_aWindowSize = " << m_aWindowSize << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should never return zero in non-threaded modes if
|
// We should never return zero in non-threaded modes if
|
||||||
// available() would also return zero, i.e. if ws == 0. If we
|
// available() would also return zero, i.e. if ws == 0. If we
|
||||||
@@ -1230,7 +1214,7 @@ R2Stretcher::process(const float *const *input, size_t samples, bool final)
|
|||||||
Profiler profiler("R2Stretcher::process");
|
Profiler profiler("R2Stretcher::process");
|
||||||
|
|
||||||
if (m_mode == Finished) {
|
if (m_mode == Finished) {
|
||||||
cerr << "R2Stretcher::process: Cannot process again after final chunk" << endl;
|
m_log.log(0, "R2Stretcher::process: Cannot process again after final chunk");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1243,9 +1227,7 @@ R2Stretcher::process(const float *const *input, size_t samples, bool final)
|
|||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
// See note in configure() above. Of course, we should
|
// See note in configure() above. Of course, we should
|
||||||
// never enter Studying unless we are non-RT anyway
|
// never enter Studying unless we are non-RT anyway
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(1, "offline mode: prefilling with", m_aWindowSize/2);
|
||||||
cerr << "Not real time mode: prefilling" << endl;
|
|
||||||
}
|
|
||||||
for (size_t c = 0; c < m_channels; ++c) {
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
m_channelData[c]->reset();
|
m_channelData[c]->reset();
|
||||||
m_channelData[c]->inbuf->zero(m_aWindowSize/2);
|
m_channelData[c]->inbuf->zero(m_aWindowSize/2);
|
||||||
@@ -1262,10 +1244,8 @@ R2Stretcher::process(const float *const *input, size_t samples, bool final)
|
|||||||
m_threadSet.insert(thread);
|
m_threadSet.insert(thread);
|
||||||
thread->start();
|
thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "created threads", m_channels);
|
||||||
cerr << m_channels << " threads created" << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1297,12 +1277,10 @@ R2Stretcher::process(const float *const *input, size_t samples, bool final)
|
|||||||
final);
|
final);
|
||||||
if (consumed[c] < samples) {
|
if (consumed[c] < samples) {
|
||||||
allConsumed = false;
|
allConsumed = false;
|
||||||
// cerr << "process: waiting on input consumption for channel " << c << endl;
|
|
||||||
} else {
|
} else {
|
||||||
if (final) {
|
if (final) {
|
||||||
m_channelData[c]->inputSize = m_channelData[c]->inCount;
|
m_channelData[c]->inputSize = m_channelData[c]->inCount;
|
||||||
}
|
}
|
||||||
// cerr << "process: happy with channel " << c << endl;
|
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
#ifndef NO_THREADING
|
#ifndef NO_THREADING
|
||||||
@@ -1335,14 +1313,10 @@ R2Stretcher::process(const float *const *input, size_t samples, bool final)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "process looping");
|
||||||
if (!allConsumed) cerr << "process looping" << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "process returning");
|
||||||
cerr << "process returning" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (final) m_mode = Finished;
|
if (final) m_mode = Finished;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "../common/RingBuffer.h"
|
#include "../common/RingBuffer.h"
|
||||||
#include "../common/Scavenger.h"
|
#include "../common/Scavenger.h"
|
||||||
#include "../common/Thread.h"
|
#include "../common/Thread.h"
|
||||||
|
#include "../common/Log.h"
|
||||||
#include "../common/sysutils.h"
|
#include "../common/sysutils.h"
|
||||||
|
|
||||||
#include "SincWindow.h"
|
#include "SincWindow.h"
|
||||||
@@ -50,7 +51,8 @@ class R2Stretcher
|
|||||||
public:
|
public:
|
||||||
R2Stretcher(size_t sampleRate, size_t channels,
|
R2Stretcher(size_t sampleRate, size_t channels,
|
||||||
RubberBandStretcher::Options options,
|
RubberBandStretcher::Options options,
|
||||||
double initialTimeRatio, double initialPitchScale);
|
double initialTimeRatio, double initialPitchScale,
|
||||||
|
Log log);
|
||||||
~R2Stretcher();
|
~R2Stretcher();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
@@ -98,7 +100,6 @@ public:
|
|||||||
void calculateStretch();
|
void calculateStretch();
|
||||||
|
|
||||||
void setDebugLevel(int level);
|
void setDebugLevel(int level);
|
||||||
static void setDefaultDebugLevel(int level) { m_defaultDebugLevel = level; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
size_t m_sampleRate;
|
size_t m_sampleRate;
|
||||||
@@ -174,7 +175,7 @@ protected:
|
|||||||
|
|
||||||
bool m_realtime;
|
bool m_realtime;
|
||||||
RubberBandStretcher::Options m_options;
|
RubberBandStretcher::Options m_options;
|
||||||
int m_debugLevel;
|
Log m_log;
|
||||||
|
|
||||||
enum ProcessMode {
|
enum ProcessMode {
|
||||||
JustCreated,
|
JustCreated,
|
||||||
@@ -202,6 +203,7 @@ protected:
|
|||||||
void run();
|
void run();
|
||||||
void signalDataAvailable();
|
void signalDataAvailable();
|
||||||
void abandon();
|
void abandon();
|
||||||
|
size_t channel() { return m_channel; }
|
||||||
private:
|
private:
|
||||||
R2Stretcher *m_s;
|
R2Stretcher *m_s;
|
||||||
size_t m_channel;
|
size_t m_channel;
|
||||||
@@ -251,7 +253,6 @@ protected:
|
|||||||
void writeOutput(RingBuffer<float> &to, float *from,
|
void writeOutput(RingBuffer<float> &to, float *from,
|
||||||
size_t qty, size_t &outCount, size_t theoreticalOut);
|
size_t qty, size_t &outCount, size_t theoreticalOut);
|
||||||
|
|
||||||
static int m_defaultDebugLevel;
|
|
||||||
static const size_t m_defaultIncrement;
|
static const size_t m_defaultIncrement;
|
||||||
static const size_t m_defaultFftSize;
|
static const size_t m_defaultFftSize;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ R2Stretcher::ChannelData::construct(const std::set<size_t> &sizes,
|
|||||||
size_t maxSize = initialWindowSize * 2;
|
size_t maxSize = initialWindowSize * 2;
|
||||||
if (initialFftSize > maxSize) maxSize = initialFftSize;
|
if (initialFftSize > maxSize) maxSize = initialFftSize;
|
||||||
|
|
||||||
// std::cerr << "ChannelData::construct: initialWindowSize = " << initialWindowSize << ", initialFftSize = " << initialFftSize << ", outbufSize = " << outbufSize << std::endl;
|
|
||||||
|
|
||||||
// std::set is ordered by value
|
// std::set is ordered by value
|
||||||
std::set<size_t>::const_iterator i = sizes.end();
|
std::set<size_t>::const_iterator i = sizes.end();
|
||||||
if (i != sizes.begin()) {
|
if (i != sizes.begin()) {
|
||||||
@@ -68,8 +66,6 @@ R2Stretcher::ChannelData::construct(const std::set<size_t> &sizes,
|
|||||||
// max possible size of the real "half" of freq data
|
// max possible size of the real "half" of freq data
|
||||||
size_t realSize = maxSize / 2 + 1;
|
size_t realSize = maxSize / 2 + 1;
|
||||||
|
|
||||||
// std::cerr << "ChannelData::construct([" << sizes.size() << "], " << maxSize << ", " << realSize << ", " << outbufSize << ")" << std::endl;
|
|
||||||
|
|
||||||
if (outbufSize < maxSize) outbufSize = maxSize;
|
if (outbufSize < maxSize) outbufSize = maxSize;
|
||||||
|
|
||||||
inbuf = new RingBuffer<float>(maxSize);
|
inbuf = new RingBuffer<float>(maxSize);
|
||||||
@@ -117,8 +113,6 @@ void
|
|||||||
R2Stretcher::ChannelData::setSizes(size_t windowSize,
|
R2Stretcher::ChannelData::setSizes(size_t windowSize,
|
||||||
size_t fftSize)
|
size_t fftSize)
|
||||||
{
|
{
|
||||||
// std::cerr << "ChannelData::setSizes: windowSize = " << windowSize << ", fftSize = " << fftSize << std::endl;
|
|
||||||
|
|
||||||
size_t maxSize = 2 * std::max(windowSize, fftSize);
|
size_t maxSize = 2 * std::max(windowSize, fftSize);
|
||||||
size_t realSize = maxSize / 2 + 1;
|
size_t realSize = maxSize / 2 + 1;
|
||||||
size_t oldMax = inbuf->getSize();
|
size_t oldMax = inbuf->getSize();
|
||||||
@@ -210,8 +204,6 @@ R2Stretcher::ChannelData::setOutbufSize(size_t outbufSize)
|
|||||||
{
|
{
|
||||||
size_t oldSize = outbuf->getSize();
|
size_t oldSize = outbuf->getSize();
|
||||||
|
|
||||||
// std::cerr << "ChannelData::setOutbufSize(" << outbufSize << ") [from " << oldSize << "]" << std::endl;
|
|
||||||
|
|
||||||
if (oldSize < outbufSize) {
|
if (oldSize < outbufSize) {
|
||||||
|
|
||||||
//!!! at this point we need a lock in case a different client
|
//!!! at this point we need a lock in case a different client
|
||||||
|
|||||||
@@ -40,9 +40,6 @@
|
|||||||
|
|
||||||
using namespace RubberBand;
|
using namespace RubberBand;
|
||||||
|
|
||||||
using std::cerr;
|
|
||||||
using std::endl;
|
|
||||||
|
|
||||||
namespace RubberBand {
|
namespace RubberBand {
|
||||||
|
|
||||||
#ifndef NO_THREADING
|
#ifndef NO_THREADING
|
||||||
@@ -57,20 +54,13 @@ R2Stretcher::ProcessThread::ProcessThread(R2Stretcher *s, size_t c) :
|
|||||||
void
|
void
|
||||||
R2Stretcher::ProcessThread::run()
|
R2Stretcher::ProcessThread::run()
|
||||||
{
|
{
|
||||||
if (m_s->m_debugLevel > 1) {
|
m_s->m_log.log(2, "thread getting going for channel", m_channel);
|
||||||
cerr << "thread " << m_channel << " getting going" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelData &cd = *m_s->m_channelData[m_channel];
|
ChannelData &cd = *m_s->m_channelData[m_channel];
|
||||||
|
|
||||||
while (cd.inputSize == -1 ||
|
while (cd.inputSize == -1 ||
|
||||||
cd.inbuf->getReadSpace() > 0) {
|
cd.inbuf->getReadSpace() > 0) {
|
||||||
|
|
||||||
// if (cd.inputSize != -1) {
|
|
||||||
// cerr << "inputSize == " << cd.inputSize
|
|
||||||
// << ", readSpace == " << cd.inbuf->getReadSpace() << endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
bool any = false, last = false;
|
bool any = false, last = false;
|
||||||
m_s->processChunks(m_channel, any, last);
|
m_s->processChunks(m_channel, any, last);
|
||||||
|
|
||||||
@@ -89,9 +79,7 @@ R2Stretcher::ProcessThread::run()
|
|||||||
m_dataAvailable.unlock();
|
m_dataAvailable.unlock();
|
||||||
|
|
||||||
if (m_abandoning) {
|
if (m_abandoning) {
|
||||||
if (m_s->m_debugLevel > 1) {
|
m_s->m_log.log(2, "thread abandoning for channel", m_channel);
|
||||||
cerr << "thread " << m_channel << " abandoning" << endl;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,9 +90,7 @@ R2Stretcher::ProcessThread::run()
|
|||||||
m_s->m_spaceAvailable.signal();
|
m_s->m_spaceAvailable.signal();
|
||||||
m_s->m_spaceAvailable.unlock();
|
m_s->m_spaceAvailable.unlock();
|
||||||
|
|
||||||
if (m_s->m_debugLevel > 1) {
|
m_s->m_log.log(2, "thread done for channel", m_channel);
|
||||||
cerr << "thread " << m_channel << " done" << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -205,8 +191,7 @@ R2Stretcher::consumeChannel(size_t c,
|
|||||||
|
|
||||||
size_t reqSize = int(ceil(samples / m_pitchScale));
|
size_t reqSize = int(ceil(samples / m_pitchScale));
|
||||||
if (reqSize > cd.resamplebufSize) {
|
if (reqSize > cd.resamplebufSize) {
|
||||||
cerr << "WARNING: R2Stretcher::consumeChannel: resizing resampler buffer from "
|
m_log.log(0, "WARNING: R2Stretcher::consumeChannel: resizing resampler buffer from and to", cd.resamplebufSize, reqSize);
|
||||||
<< cd.resamplebufSize << " to " << reqSize << endl;
|
|
||||||
cd.setResampleBufSize(reqSize);
|
cd.setResampleBufSize(reqSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,9 +271,7 @@ R2Stretcher::processChunks(size_t c, bool &any, bool &last)
|
|||||||
while (!last) {
|
while (!last) {
|
||||||
|
|
||||||
if (!testInbufReadSpace(c)) {
|
if (!testInbufReadSpace(c)) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "processChunks: out of input");
|
||||||
cerr << "processChunks: out of input" << endl;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,9 +294,7 @@ R2Stretcher::processChunks(size_t c, bool &any, bool &last)
|
|||||||
(c, phaseIncrement, shiftIncrement, phaseReset);
|
(c, phaseIncrement, shiftIncrement, phaseReset);
|
||||||
} else {
|
} else {
|
||||||
size_t bit = m_aWindowSize/4;
|
size_t bit = m_aWindowSize/4;
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "breaking down overlong increment into chunks from and to", shiftIncrement, bit);
|
||||||
cerr << "channel " << c << " breaking down overlong increment " << shiftIncrement << " into " << bit << "-size bits" << endl;
|
|
||||||
}
|
|
||||||
if (!tmp) tmp = allocate<float>(m_aWindowSize);
|
if (!tmp) tmp = allocate<float>(m_aWindowSize);
|
||||||
analyseChunk(c);
|
analyseChunk(c);
|
||||||
v_copy(tmp, cd.fltbuf, m_aWindowSize);
|
v_copy(tmp, cd.fltbuf, m_aWindowSize);
|
||||||
@@ -330,9 +311,8 @@ R2Stretcher::processChunks(size_t c, bool &any, bool &last)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cd.chunkCount++;
|
cd.chunkCount++;
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "channel/last", c, last);
|
||||||
cerr << "channel " << c << ": last = " << last << ", chunkCount = " << cd.chunkCount << endl;
|
m_log.log(3, "channel/chunkCount", c, cd.chunkCount);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp) deallocate(tmp);
|
if (tmp) deallocate(tmp);
|
||||||
@@ -351,9 +331,7 @@ R2Stretcher::processOneChunk()
|
|||||||
|
|
||||||
for (size_t c = 0; c < m_channels; ++c) {
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
if (!testInbufReadSpace(c)) {
|
if (!testInbufReadSpace(c)) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "processOneChunk: out of input");
|
||||||
cerr << "processOneChunk: out of input" << endl;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ChannelData &cd = *m_channelData[c];
|
ChannelData &cd = *m_channelData[c];
|
||||||
@@ -405,11 +383,7 @@ R2Stretcher::testInbufReadSpace(size_t c)
|
|||||||
#ifndef NO_THREADING
|
#ifndef NO_THREADING
|
||||||
if (!m_threaded) {
|
if (!m_threaded) {
|
||||||
#endif
|
#endif
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "Note: read space < chunk size when not all input written", inbuf.getReadSpace(), m_aWindowSize);
|
||||||
cerr << "Note: RubberBandStretcher: read space < chunk size ("
|
|
||||||
<< inbuf.getReadSpace() << " < " << m_aWindowSize
|
|
||||||
<< ") when not all input written, on processChunks for channel " << c << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NO_THREADING
|
#ifndef NO_THREADING
|
||||||
}
|
}
|
||||||
@@ -418,18 +392,10 @@ R2Stretcher::testInbufReadSpace(size_t c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rs == 0) {
|
if (rs == 0) {
|
||||||
|
m_log.log(2, "read space = 0, giving up");
|
||||||
if (m_debugLevel > 1) {
|
|
||||||
cerr << "read space = 0, giving up" << endl;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} else if (rs < m_aWindowSize/2) {
|
} else if (rs < m_aWindowSize/2) {
|
||||||
|
m_log.log(2, "setting draining true with read space", rs);
|
||||||
if (m_debugLevel > 1) {
|
|
||||||
cerr << "read space = " << rs << ", setting draining true" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cd.draining = true;
|
cd.draining = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -450,9 +416,9 @@ R2Stretcher::processChunkForChannel(size_t c,
|
|||||||
// using e.g. testInbufReadSpace first. Return true if this is
|
// using e.g. testInbufReadSpace first. Return true if this is
|
||||||
// the last chunk on the channel.
|
// the last chunk on the channel.
|
||||||
|
|
||||||
if (phaseReset && (m_debugLevel > 1)) {
|
if (phaseReset) {
|
||||||
cerr << "processChunkForChannel: phase reset found, incrs "
|
m_log.log(2, "processChunkForChannel: phase reset found, increments",
|
||||||
<< phaseIncrement << ":" << shiftIncrement << endl;
|
phaseIncrement, shiftIncrement);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelData &cd = *m_channelData[c];
|
ChannelData &cd = *m_channelData[c];
|
||||||
@@ -475,7 +441,7 @@ R2Stretcher::processChunkForChannel(size_t c,
|
|||||||
modifyChunk(c, phaseIncrement, phaseReset);
|
modifyChunk(c, phaseIncrement, phaseReset);
|
||||||
synthesiseChunk(c, shiftIncrement); // reads from cd.mag, cd.phase
|
synthesiseChunk(c, shiftIncrement); // reads from cd.mag, cd.phase
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
if (m_log.getDebugLevel() > 2) {
|
||||||
if (phaseReset) {
|
if (phaseReset) {
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
cd.accumulator[i] = 1.2f - (i % 3) * 1.2f;
|
cd.accumulator[i] = 1.2f - (i % 3) * 1.2f;
|
||||||
@@ -487,19 +453,13 @@ R2Stretcher::processChunkForChannel(size_t c,
|
|||||||
bool last = false;
|
bool last = false;
|
||||||
|
|
||||||
if (cd.draining) {
|
if (cd.draining) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "draining: accumulator fill and shift increment", cd.accumulatorFill, shiftIncrement);
|
||||||
cerr << "draining: accumulator fill = " << cd.accumulatorFill << " (shiftIncrement = " << shiftIncrement << ")" << endl;
|
|
||||||
}
|
|
||||||
if (shiftIncrement == 0) {
|
if (shiftIncrement == 0) {
|
||||||
cerr << "WARNING: draining: shiftIncrement == 0, can't handle that in this context: setting to " << m_increment << endl;
|
m_log.log(0, "WARNING: draining: shiftIncrement == 0, can't handle that in this context: setting to", m_increment);
|
||||||
shiftIncrement = m_increment;
|
shiftIncrement = m_increment;
|
||||||
}
|
}
|
||||||
if (cd.accumulatorFill <= shiftIncrement) {
|
if (cd.accumulatorFill <= shiftIncrement) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "draining: marking as last and reducing shift increment from and to", shiftIncrement, cd.accumulatorFill);
|
||||||
cerr << "reducing shift increment from " << shiftIncrement
|
|
||||||
<< " to " << cd.accumulatorFill
|
|
||||||
<< " and marking as last" << endl;
|
|
||||||
}
|
|
||||||
shiftIncrement = cd.accumulatorFill;
|
shiftIncrement = cd.accumulatorFill;
|
||||||
last = true;
|
last = true;
|
||||||
}
|
}
|
||||||
@@ -513,9 +473,7 @@ R2Stretcher::processChunkForChannel(size_t c,
|
|||||||
|
|
||||||
int ws = cd.outbuf->getWriteSpace();
|
int ws = cd.outbuf->getWriteSpace();
|
||||||
if (ws < required) {
|
if (ws < required) {
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(1, "Buffer overrun on output for channel", c);
|
||||||
cerr << "Buffer overrun on output for channel " << c << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The only correct thing we can do here is resize the buffer.
|
// The only correct thing we can do here is resize the buffer.
|
||||||
// We can't wait for the client thread to read some data out
|
// We can't wait for the client thread to read some data out
|
||||||
@@ -528,12 +486,10 @@ R2Stretcher::processChunkForChannel(size_t c,
|
|||||||
RingBuffer<float> *oldbuf = cd.outbuf;
|
RingBuffer<float> *oldbuf = cd.outbuf;
|
||||||
cd.outbuf = oldbuf->resized(oldbuf->getSize() * 2);
|
cd.outbuf = oldbuf->resized(oldbuf->getSize() * 2);
|
||||||
|
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "write space and space needed", ws, required);
|
||||||
cerr << "(Write space was " << ws << ", needed " << required
|
m_log.log(2, "resized output buffer from and to", oldbuf->getSize(),
|
||||||
<< ": resized output buffer from " << oldbuf->getSize()
|
cd.outbuf->getSize());
|
||||||
<< " to " << cd.outbuf->getSize() << ")" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_emergencyScavenger.claim(oldbuf);
|
m_emergencyScavenger.claim(oldbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,8 +504,6 @@ R2Stretcher::calculateIncrements(size_t &phaseIncrementRtn,
|
|||||||
{
|
{
|
||||||
Profiler profiler("R2Stretcher::calculateIncrements");
|
Profiler profiler("R2Stretcher::calculateIncrements");
|
||||||
|
|
||||||
// cerr << "calculateIncrements" << endl;
|
|
||||||
|
|
||||||
// Calculate the next upcoming phase and shift increment, on the
|
// Calculate the next upcoming phase and shift increment, on the
|
||||||
// basis that both channels are in sync. This is in contrast to
|
// basis that both channels are in sync. This is in contrast to
|
||||||
// getIncrements, which requires that all the increments have been
|
// getIncrements, which requires that all the increments have been
|
||||||
@@ -572,7 +526,7 @@ R2Stretcher::calculateIncrements(size_t &phaseIncrementRtn,
|
|||||||
size_t bc = cd.chunkCount;
|
size_t bc = cd.chunkCount;
|
||||||
for (size_t c = 1; c < m_channels; ++c) {
|
for (size_t c = 1; c < m_channels; ++c) {
|
||||||
if (m_channelData[c]->chunkCount != bc) {
|
if (m_channelData[c]->chunkCount != bc) {
|
||||||
cerr << "ERROR: R2Stretcher::calculateIncrements: Channels are not in sync" << endl;
|
m_log.log(0, "ERROR: R2Stretcher::calculateIncrements: Channels are not in sync");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -669,10 +623,7 @@ R2Stretcher::calculateIncrements(size_t &phaseIncrementRtn,
|
|||||||
|
|
||||||
if (m_silentHistory >= int(m_aWindowSize / m_increment) && !phaseReset) {
|
if (m_silentHistory >= int(m_aWindowSize / m_increment) && !phaseReset) {
|
||||||
phaseReset = true;
|
phaseReset = true;
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "calculateIncrements: phase reset on silence: silent history", m_silentHistory);
|
||||||
cerr << "calculateIncrements: phase reset on silence (silent history == "
|
|
||||||
<< m_silentHistory << ")" << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,9 +662,6 @@ R2Stretcher::getIncrements(size_t channel,
|
|||||||
bool gotData = true;
|
bool gotData = true;
|
||||||
|
|
||||||
if (cd.chunkCount >= m_outputIncrements.size()) {
|
if (cd.chunkCount >= m_outputIncrements.size()) {
|
||||||
// cerr << "WARNING: R2Stretcher::getIncrements:"
|
|
||||||
// << " chunk count " << cd.chunkCount << " >= "
|
|
||||||
// << m_outputIncrements.size() << endl;
|
|
||||||
if (m_outputIncrements.size() == 0) {
|
if (m_outputIncrements.size() == 0) {
|
||||||
phaseIncrementRtn = m_increment;
|
phaseIncrementRtn = m_increment;
|
||||||
shiftIncrementRtn = m_increment;
|
shiftIncrementRtn = m_increment;
|
||||||
@@ -740,12 +688,12 @@ R2Stretcher::getIncrements(size_t channel,
|
|||||||
if (shiftIncrement < 0) {
|
if (shiftIncrement < 0) {
|
||||||
shiftIncrement = -shiftIncrement;
|
shiftIncrement = -shiftIncrement;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if (shiftIncrement >= int(m_windowSize)) {
|
if (shiftIncrement >= int(m_aWindowSize)) {
|
||||||
cerr << "*** ERROR: R2Stretcher::processChunks: shiftIncrement " << shiftIncrement << " >= windowSize " << m_windowSize << " at " << cd.chunkCount << " (of " << m_outputIncrements.size() << ")" << endl;
|
m_log.log(1, "WARNING: shiftIncrement >= analysis window size", shiftIncrement, m_aWindowSize);
|
||||||
shiftIncrement = m_windowSize;
|
m_log.log(1, "at chunk of total", cd.chunkCount, m_outputIncrements.size());
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
phaseIncrementRtn = phaseIncrement;
|
phaseIncrementRtn = phaseIncrement;
|
||||||
shiftIncrementRtn = shiftIncrement;
|
shiftIncrementRtn = shiftIncrement;
|
||||||
if (cd.chunkCount == 0) phaseReset = true; // don't mess with the first chunk
|
if (cd.chunkCount == 0) phaseReset = true; // don't mess with the first chunk
|
||||||
@@ -782,8 +730,8 @@ R2Stretcher::modifyChunk(size_t channel,
|
|||||||
|
|
||||||
ChannelData &cd = *m_channelData[channel];
|
ChannelData &cd = *m_channelData[channel];
|
||||||
|
|
||||||
if (phaseReset && m_debugLevel > 1) {
|
if (phaseReset) {
|
||||||
cerr << "phase reset: leaving phases unmodified" << endl;
|
m_log.log(2, "phase reset: leaving phases unmodified");
|
||||||
}
|
}
|
||||||
|
|
||||||
const process_t rate = process_t(m_sampleRate);
|
const process_t rate = process_t(m_sampleRate);
|
||||||
@@ -904,15 +852,13 @@ R2Stretcher::modifyChunk(size_t channel,
|
|||||||
cd.unwrappedPhase[i] = outphase;
|
cd.unwrappedPhase[i] = outphase;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "mean inheritance distance", distacc / count);
|
||||||
cerr << "mean inheritance distance = " << distacc / count << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fullReset) unchanged = true;
|
if (fullReset) unchanged = true;
|
||||||
cd.unchanged = unchanged;
|
cd.unchanged = unchanged;
|
||||||
|
|
||||||
if (unchanged && m_debugLevel > 1) {
|
if (unchanged) {
|
||||||
cerr << "frame unchanged on channel " << channel << endl;
|
m_log.log(2, "frame unchanged on channel", channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -936,8 +882,6 @@ R2Stretcher::formantShiftChunk(size_t channel)
|
|||||||
|
|
||||||
const int cutoff = m_sampleRate / 700;
|
const int cutoff = m_sampleRate / 700;
|
||||||
|
|
||||||
// cerr <<"cutoff = "<< cutoff << ", m_sampleRate/cutoff = " << m_sampleRate/cutoff << endl;
|
|
||||||
|
|
||||||
dblbuf[0] /= 2;
|
dblbuf[0] /= 2;
|
||||||
dblbuf[cutoff-1] /= 2;
|
dblbuf[cutoff-1] /= 2;
|
||||||
|
|
||||||
@@ -1061,8 +1005,10 @@ R2Stretcher::writeChunk(size_t channel, size_t shiftIncrement, bool last)
|
|||||||
const int sz = cd.accumulatorFill;
|
const int sz = cd.accumulatorFill;
|
||||||
const int si = shiftIncrement;
|
const int si = shiftIncrement;
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "writeChunk: channel and shiftIncrement",
|
||||||
cerr << "writeChunk(" << channel << ", " << shiftIncrement << ", " << last << ")" << endl;
|
channel, shiftIncrement);
|
||||||
|
if (last) {
|
||||||
|
m_log.log(3, "writeChunk: last true");
|
||||||
}
|
}
|
||||||
|
|
||||||
v_divide(accumulator, windowAccumulator, si);
|
v_divide(accumulator, windowAccumulator, si);
|
||||||
@@ -1090,12 +1036,10 @@ R2Stretcher::writeChunk(size_t channel, size_t shiftIncrement, bool last)
|
|||||||
// first place. But we retain this check in case the
|
// first place. But we retain this check in case the
|
||||||
// pitch scale has changed since then, or the stretch
|
// pitch scale has changed since then, or the stretch
|
||||||
// calculator has gone mad, or something.
|
// calculator has gone mad, or something.
|
||||||
cerr << "WARNING: R2Stretcher::writeChunk: resizing resampler buffer from "
|
m_log.log(0, "WARNING: R2Stretcher::writeChunk: resizing resampler buffer from and to", cd.resamplebufSize, reqSize);
|
||||||
<< cd.resamplebufSize << " to " << reqSize << endl;
|
|
||||||
cd.setResampleBufSize(reqSize);
|
cd.setResampleBufSize(reqSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
|
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
|
||||||
if (m_threaded) {
|
if (m_threaded) {
|
||||||
m_resamplerMutex.lock();
|
m_resamplerMutex.lock();
|
||||||
@@ -1134,9 +1078,7 @@ R2Stretcher::writeChunk(size_t channel, size_t shiftIncrement, bool last)
|
|||||||
} else {
|
} else {
|
||||||
cd.accumulatorFill = 0;
|
cd.accumulatorFill = 0;
|
||||||
if (cd.draining) {
|
if (cd.draining) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "processChunks: setting outputComplete to true");
|
||||||
cerr << "R2Stretcher::processChunks: setting outputComplete to true" << endl;
|
|
||||||
}
|
|
||||||
cd.outputComplete = true;
|
cd.outputComplete = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1162,31 +1104,23 @@ R2Stretcher::writeOutput(RingBuffer<float> &to, float *from, size_t qty, size_t
|
|||||||
// this is the normal case
|
// this is the normal case
|
||||||
|
|
||||||
if (theoreticalOut > 0) {
|
if (theoreticalOut > 0) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "theoreticalOut and outCount",
|
||||||
cerr << "theoreticalOut = " << theoreticalOut
|
theoreticalOut, outCount);
|
||||||
<< ", outCount = " << outCount
|
m_log.log(2, "startSkip and qty",
|
||||||
<< ", startSkip = " << startSkip
|
startSkip, qty);
|
||||||
<< ", qty = " << qty << endl;
|
|
||||||
}
|
|
||||||
if (outCount - startSkip <= theoreticalOut &&
|
if (outCount - startSkip <= theoreticalOut &&
|
||||||
outCount - startSkip + qty > theoreticalOut) {
|
outCount - startSkip + qty > theoreticalOut) {
|
||||||
qty = theoreticalOut - (outCount - startSkip);
|
qty = theoreticalOut - (outCount - startSkip);
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "reducing qty to", qty);
|
||||||
cerr << "reduce qty to " << qty << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "writing", qty);
|
||||||
cerr << "writing " << qty << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t written = to.write(from, qty);
|
size_t written = to.write(from, qty);
|
||||||
|
|
||||||
if (written < qty) {
|
if (written < qty) {
|
||||||
cerr << "WARNING: R2Stretcher::writeOutput: "
|
m_log.log(0, "WARNING: writeOutput: buffer overrun: wanted to write and able to write", qty, written);
|
||||||
<< "Buffer overrun on output: wrote " << written
|
|
||||||
<< " of " << qty << " samples" << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outCount += written;
|
outCount += written;
|
||||||
@@ -1196,22 +1130,16 @@ R2Stretcher::writeOutput(RingBuffer<float> &to, float *from, size_t qty, size_t
|
|||||||
// the rest of this is only used during the first startSkip samples
|
// the rest of this is only used during the first startSkip samples
|
||||||
|
|
||||||
if (outCount + qty <= startSkip) {
|
if (outCount + qty <= startSkip) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "discarding with startSkip", startSkip);
|
||||||
cerr << "qty = " << qty << ", startSkip = "
|
m_log.log(2, "qty and outCount", qty, outCount);
|
||||||
<< startSkip << ", outCount = " << outCount
|
|
||||||
<< ", discarding" << endl;
|
|
||||||
}
|
|
||||||
outCount += qty;
|
outCount += qty;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t off = startSkip - outCount;
|
size_t off = startSkip - outCount;
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "shortening with startSkip", startSkip);
|
||||||
cerr << "qty = " << qty << ", startSkip = "
|
m_log.log(2, "qty and outCount", qty, outCount);
|
||||||
<< startSkip << ", outCount = " << outCount
|
m_log.log(2, "start offset and number written", off, qty - off);
|
||||||
<< ", writing " << qty - off
|
|
||||||
<< " from start offset " << off << endl;
|
|
||||||
}
|
|
||||||
to.write(from + off, qty - off);
|
to.write(from + off, qty - off);
|
||||||
outCount += qty;
|
outCount += qty;
|
||||||
}
|
}
|
||||||
@@ -1235,11 +1163,8 @@ R2Stretcher::available() const
|
|||||||
#endif
|
#endif
|
||||||
for (size_t c = 0; c < m_channels; ++c) {
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
if (m_channelData[c]->inputSize >= 0) {
|
if (m_channelData[c]->inputSize >= 0) {
|
||||||
// cerr << "available: m_done true" << endl;
|
|
||||||
if (m_channelData[c]->inbuf->getReadSpace() > 0) {
|
if (m_channelData[c]->inbuf->getReadSpace() > 0) {
|
||||||
if (m_debugLevel > 1) {
|
m_log.log(2, "calling processChunks from available, channel" , c);
|
||||||
cerr << "calling processChunks(" << c << ") from available" << endl;
|
|
||||||
}
|
|
||||||
//!!! do we ever actually do this? if so, this method should not be const
|
//!!! do we ever actually do this? if so, this method should not be const
|
||||||
// ^^^ yes, we do sometimes -- e.g. when fed a very short file
|
// ^^^ yes, we do sometimes -- e.g. when fed a very short file
|
||||||
bool any = false, last = false;
|
bool any = false, last = false;
|
||||||
@@ -1258,9 +1183,7 @@ R2Stretcher::available() const
|
|||||||
for (size_t i = 0; i < m_channels; ++i) {
|
for (size_t i = 0; i < m_channels; ++i) {
|
||||||
size_t availIn = m_channelData[i]->inbuf->getReadSpace();
|
size_t availIn = m_channelData[i]->inbuf->getReadSpace();
|
||||||
size_t availOut = m_channelData[i]->outbuf->getReadSpace();
|
size_t availOut = m_channelData[i]->outbuf->getReadSpace();
|
||||||
if (m_debugLevel > 2) {
|
m_log.log(3, "available in and out", availIn, availOut);
|
||||||
cerr << "available on channel " << i << ": " << availOut << " (waiting: " << availIn << ")" << endl;
|
|
||||||
}
|
|
||||||
if (i == 0 || availOut < min) min = availOut;
|
if (i == 0 || availOut < min) min = availOut;
|
||||||
if (!m_channelData[i]->outputComplete) consumed = false;
|
if (!m_channelData[i]->outputComplete) consumed = false;
|
||||||
if (m_channelData[i]->resampler) haveResamplers = true;
|
if (m_channelData[i]->resampler) haveResamplers = true;
|
||||||
@@ -1284,9 +1207,7 @@ R2Stretcher::retrieve(float *const *output, size_t samples) const
|
|||||||
size_t gotHere = m_channelData[c]->outbuf->read(output[c], got);
|
size_t gotHere = m_channelData[c]->outbuf->read(output[c], got);
|
||||||
if (gotHere < got) {
|
if (gotHere < got) {
|
||||||
if (c > 0) {
|
if (c > 0) {
|
||||||
if (m_debugLevel > 0) {
|
m_log.log(0, "R2Stretcher::retrieve: WARNING: channel imbalance detected");
|
||||||
cerr << "R2Stretcher::retrieve: WARNING: channel imbalance detected" << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
got = gotHere;
|
got = gotHere;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#ifndef RUBBERBAND_GUIDE_H
|
#ifndef RUBBERBAND_GUIDE_H
|
||||||
#define RUBBERBAND_GUIDE_H
|
#define RUBBERBAND_GUIDE_H
|
||||||
|
|
||||||
|
#include "../common/Log.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@@ -102,15 +104,12 @@ public:
|
|||||||
|
|
||||||
struct Parameters {
|
struct Parameters {
|
||||||
double sampleRate;
|
double sampleRate;
|
||||||
std::function<void(const std::string &)> logger;
|
Parameters(double _sampleRate) : sampleRate(_sampleRate) { }
|
||||||
Parameters(double _sampleRate,
|
|
||||||
std::function<void(const std::string &)> _log) :
|
|
||||||
sampleRate(_sampleRate),
|
|
||||||
logger(_log) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Guide(Parameters parameters) :
|
Guide(Parameters parameters, Log log) :
|
||||||
m_parameters(parameters),
|
m_parameters(parameters),
|
||||||
|
m_log(log),
|
||||||
m_configuration(roundUp(int(ceil(parameters.sampleRate / 16.0))),
|
m_configuration(roundUp(int(ceil(parameters.sampleRate / 16.0))),
|
||||||
roundUp(int(ceil(parameters.sampleRate / 64.0))),
|
roundUp(int(ceil(parameters.sampleRate / 64.0))),
|
||||||
roundUp(int(ceil(parameters.sampleRate / 32.0)))),
|
roundUp(int(ceil(parameters.sampleRate / 32.0)))),
|
||||||
@@ -120,10 +119,12 @@ public:
|
|||||||
{
|
{
|
||||||
double rate = m_parameters.sampleRate;
|
double rate = m_parameters.sampleRate;
|
||||||
|
|
||||||
|
m_log.log(1, "Guide: rate", rate);
|
||||||
|
|
||||||
int bandFftSize = roundUp(int(ceil(rate/16.0)));
|
int bandFftSize = roundUp(int(ceil(rate/16.0)));
|
||||||
m_configuration.fftBandLimits[0] =
|
m_configuration.fftBandLimits[0] =
|
||||||
BandLimits(bandFftSize, rate, 0.0, m_maxLower);
|
BandLimits(bandFftSize, rate, 0.0, m_maxLower);
|
||||||
|
|
||||||
// This is the classification and fallback FFT: we need it to
|
// This is the classification and fallback FFT: we need it to
|
||||||
// go up to Nyquist so we can seamlessly switch to it for
|
// go up to Nyquist so we can seamlessly switch to it for
|
||||||
// longer stretches
|
// longer stretches
|
||||||
@@ -134,6 +135,9 @@ public:
|
|||||||
bandFftSize = roundUp(int(ceil(rate/64.0)));
|
bandFftSize = roundUp(int(ceil(rate/64.0)));
|
||||||
m_configuration.fftBandLimits[2] =
|
m_configuration.fftBandLimits[2] =
|
||||||
BandLimits(bandFftSize, rate, m_minHigher, rate/2.0);
|
BandLimits(bandFftSize, rate, m_minHigher, rate/2.0);
|
||||||
|
|
||||||
|
m_log.log(1, "Guide: classification FFT size",
|
||||||
|
m_configuration.classificationFftSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Configuration &getConfiguration() const {
|
const Configuration &getConfiguration() const {
|
||||||
@@ -332,8 +336,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setDebugLevel(int level) {
|
||||||
|
m_log.setDebugLevel(level);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Parameters m_parameters;
|
Parameters m_parameters;
|
||||||
|
Log m_log;
|
||||||
Configuration m_configuration;
|
Configuration m_configuration;
|
||||||
|
|
||||||
double m_minLower;
|
double m_minLower;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "Guide.h"
|
#include "Guide.h"
|
||||||
|
|
||||||
|
#include "../common/Log.h"
|
||||||
#include "../common/mathmisc.h"
|
#include "../common/mathmisc.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -41,15 +42,13 @@ public:
|
|||||||
int fftSize;
|
int fftSize;
|
||||||
double sampleRate;
|
double sampleRate;
|
||||||
int channels;
|
int channels;
|
||||||
std::function<void(const std::string &)> logger;
|
Parameters(int _fftSize, double _sampleRate, int _channels) :
|
||||||
Parameters(int _fftSize, double _sampleRate, int _channels,
|
fftSize(_fftSize), sampleRate(_sampleRate), channels(_channels) { }
|
||||||
std::function<void(const std::string &)> _log) :
|
|
||||||
fftSize(_fftSize), sampleRate(_sampleRate),
|
|
||||||
channels(_channels), logger(_log) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GuidedPhaseAdvance(Parameters parameters) :
|
GuidedPhaseAdvance(Parameters parameters, Log log) :
|
||||||
m_parameters(parameters),
|
m_parameters(parameters),
|
||||||
|
m_log(log),
|
||||||
m_binCount(parameters.fftSize / 2 + 1),
|
m_binCount(parameters.fftSize / 2 + 1),
|
||||||
m_peakPicker(m_binCount),
|
m_peakPicker(m_binCount),
|
||||||
m_reported(false) {
|
m_reported(false) {
|
||||||
@@ -111,18 +110,18 @@ public:
|
|||||||
int lowest = configuration.fftBandLimits[myFftBand].b0min;
|
int lowest = configuration.fftBandLimits[myFftBand].b0min;
|
||||||
int highest = configuration.fftBandLimits[myFftBand].b1max;
|
int highest = configuration.fftBandLimits[myFftBand].b1max;
|
||||||
|
|
||||||
if (!m_reported) {
|
if (m_log.getDebugLevel() > 0 && !m_reported) {
|
||||||
std::ostringstream ostr;
|
m_log.log(1, "PhaseAdvance: for fftSize and bins",
|
||||||
ostr << "PhaseAdvance: fftSize = " << m_parameters.fftSize
|
m_parameters.fftSize, bs);
|
||||||
<< ": bins = " << bs << ", channels = " << channels
|
m_log.log(1, "PhaseAdvance: channels", channels);
|
||||||
<< ", inhop = "<< inhop << ", outhop = " << outhop
|
m_log.log(1, "PhaseAdvance: widest bin range for this size",
|
||||||
<< ", ratio = " << ratio << std::endl;
|
lowest, highest);
|
||||||
ostr << "PhaseAdvance: lowest possible bin = " << lowest
|
m_log.log(1, "PhaseAdvance: widest freq range for this size",
|
||||||
<< " (" << configuration.fftBandLimits[myFftBand].f0min
|
configuration.fftBandLimits[myFftBand].f0min,
|
||||||
<< "Hz), highest = " << highest
|
configuration.fftBandLimits[myFftBand].f1max);
|
||||||
<< " (" << configuration.fftBandLimits[myFftBand].f1max
|
m_log.log(1, "PhaseAdvance: initial inhop and outhop",
|
||||||
<< "Hz)" << std::endl;
|
inhop, outhop);
|
||||||
m_parameters.logger(ostr.str());
|
m_log.log(1, "PhaseAdvance: initial ratio", ratio);
|
||||||
m_reported = true;
|
m_reported = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,8 +230,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setDebugLevel(int debugLevel) {
|
||||||
|
m_log.setDebugLevel(debugLevel);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Parameters m_parameters;
|
Parameters m_parameters;
|
||||||
|
Log m_log;
|
||||||
int m_binCount;
|
int m_binCount;
|
||||||
Peak<double> m_peakPicker;
|
Peak<double> m_peakPicker;
|
||||||
int **m_currentPeaks;
|
int **m_currentPeaks;
|
||||||
|
|||||||
@@ -31,12 +31,14 @@ namespace RubberBand {
|
|||||||
|
|
||||||
R3Stretcher::R3Stretcher(Parameters parameters,
|
R3Stretcher::R3Stretcher(Parameters parameters,
|
||||||
double initialTimeRatio,
|
double initialTimeRatio,
|
||||||
double initialPitchScale) :
|
double initialPitchScale,
|
||||||
|
Log log) :
|
||||||
m_parameters(parameters),
|
m_parameters(parameters),
|
||||||
|
m_log(log),
|
||||||
m_timeRatio(initialTimeRatio),
|
m_timeRatio(initialTimeRatio),
|
||||||
m_pitchScale(initialPitchScale),
|
m_pitchScale(initialPitchScale),
|
||||||
m_formantScale(0.0),
|
m_formantScale(0.0),
|
||||||
m_guide(Guide::Parameters(m_parameters.sampleRate, parameters.logger)),
|
m_guide(Guide::Parameters(m_parameters.sampleRate), m_log),
|
||||||
m_guideConfiguration(m_guide.getConfiguration()),
|
m_guideConfiguration(m_guide.getConfiguration()),
|
||||||
m_channelAssembly(m_parameters.channels),
|
m_channelAssembly(m_parameters.channels),
|
||||||
m_inhop(1),
|
m_inhop(1),
|
||||||
@@ -51,6 +53,11 @@ R3Stretcher::R3Stretcher(Parameters parameters,
|
|||||||
m_totalOutputDuration(0),
|
m_totalOutputDuration(0),
|
||||||
m_mode(ProcessMode::JustCreated)
|
m_mode(ProcessMode::JustCreated)
|
||||||
{
|
{
|
||||||
|
m_log.log(1, "R3Stretcher::R3Stretcher: rate, options",
|
||||||
|
m_parameters.sampleRate, m_parameters.options);
|
||||||
|
m_log.log(1, "R3Stretcher::R3Stretcher: initial time ratio and pitch scale",
|
||||||
|
m_timeRatio, m_pitchScale);
|
||||||
|
|
||||||
double maxClassifierFrequency = 16000.0;
|
double maxClassifierFrequency = 16000.0;
|
||||||
if (maxClassifierFrequency > m_parameters.sampleRate/2) {
|
if (maxClassifierFrequency > m_parameters.sampleRate/2) {
|
||||||
maxClassifierFrequency = m_parameters.sampleRate/2;
|
maxClassifierFrequency = m_parameters.sampleRate/2;
|
||||||
@@ -83,18 +90,19 @@ R3Stretcher::R3Stretcher(Parameters parameters,
|
|||||||
(fftSize, m_guideConfiguration.longestFftSize);
|
(fftSize, m_guideConfiguration.longestFftSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto band: m_guideConfiguration.fftBandLimits) {
|
for (auto band: m_guideConfiguration.fftBandLimits) {
|
||||||
int fftSize = band.fftSize;
|
int fftSize = band.fftSize;
|
||||||
GuidedPhaseAdvance::Parameters guidedParameters
|
GuidedPhaseAdvance::Parameters guidedParameters
|
||||||
(fftSize, m_parameters.sampleRate, m_parameters.channels,
|
(fftSize, m_parameters.sampleRate, m_parameters.channels);
|
||||||
m_parameters.logger);
|
m_scaleData[fftSize] = std::make_shared<ScaleData>
|
||||||
m_scaleData[fftSize] = std::make_shared<ScaleData>(guidedParameters);
|
(guidedParameters, m_log);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_calculator = std::unique_ptr<StretchCalculator>
|
m_calculator = std::unique_ptr<StretchCalculator>
|
||||||
(new StretchCalculator(int(round(m_parameters.sampleRate)), //!!! which is a double...
|
(new StretchCalculator(int(round(m_parameters.sampleRate)), //!!! which is a double...
|
||||||
1, false)); // no fixed inputIncrement
|
1, false, // no fixed inputIncrement
|
||||||
|
m_log));
|
||||||
|
|
||||||
Resampler::Parameters resamplerParameters;
|
Resampler::Parameters resamplerParameters;
|
||||||
resamplerParameters.quality = Resampler::FastestTolerable;
|
resamplerParameters.quality = Resampler::FastestTolerable;
|
||||||
@@ -119,10 +127,10 @@ R3Stretcher::R3Stretcher(Parameters parameters,
|
|||||||
m_prevOuthop = int(round(m_inhop * getEffectiveRatio()));
|
m_prevOuthop = int(round(m_inhop * getEffectiveRatio()));
|
||||||
|
|
||||||
if (!m_inhop.is_lock_free()) {
|
if (!m_inhop.is_lock_free()) {
|
||||||
m_parameters.logger("WARNING: std::atomic<int> is not lock-free");
|
m_log.log(0, "WARNING: std::atomic<int> is not lock-free");
|
||||||
}
|
}
|
||||||
if (!m_timeRatio.is_lock_free()) {
|
if (!m_timeRatio.is_lock_free()) {
|
||||||
m_parameters.logger("WARNING: std::atomic<double> is not lock-free");
|
m_log.log(0, "WARNING: std::atomic<double> is not lock-free");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad to half of the longest frame. As with R2, in real-time mode
|
// Pad to half of the longest frame. As with R2, in real-time mode
|
||||||
@@ -131,15 +139,15 @@ R3Stretcher::R3Stretcher(Parameters parameters,
|
|||||||
// changes.
|
// changes.
|
||||||
|
|
||||||
if (!isRealTime()) {
|
if (!isRealTime()) {
|
||||||
m_parameters.logger("Offline mode: pre-padding");
|
|
||||||
int pad = m_guideConfiguration.longestFftSize / 2;
|
int pad = m_guideConfiguration.longestFftSize / 2;
|
||||||
|
m_log.log(1, "offline mode: prefilling with", pad);
|
||||||
for (int c = 0; c < m_parameters.channels; ++c) {
|
for (int c = 0; c < m_parameters.channels; ++c) {
|
||||||
m_channelData[c]->inbuf->zero(pad);
|
m_channelData[c]->inbuf->zero(pad);
|
||||||
}
|
}
|
||||||
// By the time we skip this later we will have resampled
|
// By the time we skip this later we will have resampled
|
||||||
m_startSkip = int(round(pad / m_pitchScale));
|
m_startSkip = int(round(pad / m_pitchScale));
|
||||||
} else {
|
} else {
|
||||||
m_parameters.logger("RT mode: no internal pre-pad");
|
m_log.log(1, "realtime mode: no prefill");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +184,7 @@ R3Stretcher::setTimeRatio(double ratio)
|
|||||||
if (!isRealTime()) {
|
if (!isRealTime()) {
|
||||||
if (m_mode == ProcessMode::Studying ||
|
if (m_mode == ProcessMode::Studying ||
|
||||||
m_mode == ProcessMode::Processing) {
|
m_mode == ProcessMode::Processing) {
|
||||||
m_parameters.logger("R3Stretcher::setTimeRatio: Cannot set time ratio while studying or processing in non-RT mode");
|
m_log.log(0, "R3Stretcher::setTimeRatio: Cannot set time ratio while studying or processing in non-RT mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +200,7 @@ R3Stretcher::setPitchScale(double scale)
|
|||||||
if (!isRealTime()) {
|
if (!isRealTime()) {
|
||||||
if (m_mode == ProcessMode::Studying ||
|
if (m_mode == ProcessMode::Studying ||
|
||||||
m_mode == ProcessMode::Processing) {
|
m_mode == ProcessMode::Processing) {
|
||||||
m_parameters.logger("R3Stretcher::setTimeRatio: Cannot set pitch scale while studying or processing in non-RT mode");
|
m_log.log(0, "R3Stretcher::setTimeRatio: Cannot set pitch scale while studying or processing in non-RT mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,7 +216,7 @@ R3Stretcher::setFormantScale(double scale)
|
|||||||
if (!isRealTime()) {
|
if (!isRealTime()) {
|
||||||
if (m_mode == ProcessMode::Studying ||
|
if (m_mode == ProcessMode::Studying ||
|
||||||
m_mode == ProcessMode::Processing) {
|
m_mode == ProcessMode::Processing) {
|
||||||
m_parameters.logger("R3Stretcher::setTimeRatio: Cannot set formant scale while studying or processing in non-RT mode");
|
m_log.log(0, "R3Stretcher::setTimeRatio: Cannot set formant scale while studying or processing in non-RT mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,11 +238,11 @@ void
|
|||||||
R3Stretcher::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
|
R3Stretcher::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
|
||||||
{
|
{
|
||||||
if (isRealTime()) {
|
if (isRealTime()) {
|
||||||
m_parameters.logger("R3Stretcher::setKeyFrameMap: Cannot specify key frame map in RT mode");
|
m_log.log(0, "R3Stretcher::setKeyFrameMap: Cannot specify key frame map in RT mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_mode == ProcessMode::Processing || m_mode == ProcessMode::Finished) {
|
if (m_mode == ProcessMode::Processing || m_mode == ProcessMode::Finished) {
|
||||||
m_parameters.logger("R3Stretcher::setKeyFrameMap: Cannot specify key frame map after process() has begun");
|
m_log.log(0, "R3Stretcher::setKeyFrameMap: Cannot specify key frame map after process() has begun");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,22 +274,21 @@ R3Stretcher::calculateHop()
|
|||||||
if (proposedOuthop > 512.0) proposedOuthop = 512.0;
|
if (proposedOuthop > 512.0) proposedOuthop = 512.0;
|
||||||
if (proposedOuthop < 128.0) proposedOuthop = 128.0;
|
if (proposedOuthop < 128.0) proposedOuthop = 128.0;
|
||||||
|
|
||||||
std::cout << "calculateHop: for ratio " << ratio << " proposedOuthop = "
|
m_log.log(1, "calculateHop: ratio and proposed outhop", ratio, proposedOuthop);
|
||||||
<< proposedOuthop << std::endl;
|
|
||||||
|
|
||||||
double inhop = proposedOuthop / ratio;
|
double inhop = proposedOuthop / ratio;
|
||||||
if (inhop < 1.0) {
|
if (inhop < 1.0) {
|
||||||
m_parameters.logger("WARNING: Extreme ratio yields ideal inhop < 1, results may be suspect");
|
m_log.log(0, "WARNING: Extreme ratio yields ideal inhop < 1, results may be suspect", ratio, inhop);
|
||||||
inhop = 1.0;
|
inhop = 1.0;
|
||||||
}
|
}
|
||||||
if (inhop > 768.0) {
|
if (inhop > 768.0) {
|
||||||
m_parameters.logger("WARNING: Extreme ratio yields ideal inhop > 768, results may be suspect");
|
m_log.log(0, "WARNING: Extreme ratio yields ideal inhop > 768, results may be suspect", ratio, inhop);
|
||||||
inhop = 768.0;
|
inhop = 768.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_inhop = int(floor(inhop));
|
m_inhop = int(floor(inhop));
|
||||||
|
|
||||||
std::cout << "R3Stretcher::calculateHop: inhop = " << m_inhop << ", proposed outhop = " << proposedOuthop << ", mean outhop = " << m_inhop * ratio << std::endl;
|
m_log.log(1, "calculateHop: inhop and mean outhop", m_inhop, m_inhop * ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -292,7 +299,12 @@ R3Stretcher::updateRatioFromMap()
|
|||||||
if (m_processInputDuration == 0) {
|
if (m_processInputDuration == 0) {
|
||||||
m_timeRatio = double(m_keyFrameMap.begin()->second) /
|
m_timeRatio = double(m_keyFrameMap.begin()->second) /
|
||||||
double(m_keyFrameMap.begin()->first);
|
double(m_keyFrameMap.begin()->first);
|
||||||
std::cout << "initial key-frame map entry " << m_keyFrameMap.begin()->first << " -> " << m_keyFrameMap.begin()->second << " gives initial ratio " << m_timeRatio << std::endl;
|
|
||||||
|
m_log.log(1, "initial key-frame map entry ",
|
||||||
|
double(m_keyFrameMap.begin()->first),
|
||||||
|
double(m_keyFrameMap.begin()->second));
|
||||||
|
m_log.log(1, "giving initial ratio ", m_timeRatio);
|
||||||
|
|
||||||
calculateHop();
|
calculateHop();
|
||||||
m_lastKeyFrameSurpassed = 0;
|
m_lastKeyFrameSurpassed = 0;
|
||||||
return;
|
return;
|
||||||
@@ -306,7 +318,8 @@ R3Stretcher::updateRatioFromMap()
|
|||||||
|
|
||||||
if (m_processInputDuration >= i0->first) {
|
if (m_processInputDuration >= i0->first) {
|
||||||
|
|
||||||
std::cout << "at " << m_processInputDuration << " (output = " << m_totalOutputDuration << ") we have passed " << i0->first << ", looking ahead to next key frame" << std::endl;
|
m_log.log(2, "input duration surpasses pending key frame",
|
||||||
|
double(m_processInputDuration), double(i0->first));
|
||||||
|
|
||||||
auto i1 = m_keyFrameMap.upper_bound(m_processInputDuration);
|
auto i1 = m_keyFrameMap.upper_bound(m_processInputDuration);
|
||||||
|
|
||||||
@@ -331,10 +344,13 @@ R3Stretcher::updateRatioFromMap()
|
|||||||
|
|
||||||
double ratio = double(toKeyFrameAtOutput) / double(toKeyFrameAtInput);
|
double ratio = double(toKeyFrameAtOutput) / double(toKeyFrameAtInput);
|
||||||
|
|
||||||
std::cout << "keyFrameAtInput = " << keyFrameAtInput << ", keyFrameAtOutput = " << keyFrameAtOutput << std::endl;
|
m_log.log(2, "next key frame input and output",
|
||||||
std::cout << "currently at input = " << m_processInputDuration << ", currently at output = " << m_totalOutputDuration << std::endl;
|
double(keyFrameAtInput), double(keyFrameAtOutput));
|
||||||
std::cout << "toKeyFrameAtInput = " << toKeyFrameAtInput << ", toKeyFrameAtOutput = " << toKeyFrameAtOutput << std::endl;
|
m_log.log(2, "current input and output",
|
||||||
std::cout << "ratio = " << ratio << std::endl;
|
double(m_processInputDuration), double(m_totalOutputDuration));
|
||||||
|
m_log.log(2, "to next key frame input and output",
|
||||||
|
double(toKeyFrameAtInput), double(toKeyFrameAtOutput));
|
||||||
|
m_log.log(2, "new ratio", ratio);
|
||||||
|
|
||||||
m_timeRatio = ratio;
|
m_timeRatio = ratio;
|
||||||
calculateHop();
|
calculateHop();
|
||||||
@@ -409,12 +425,12 @@ void
|
|||||||
R3Stretcher::study(const float *const *, size_t samples, bool)
|
R3Stretcher::study(const float *const *, size_t samples, bool)
|
||||||
{
|
{
|
||||||
if (isRealTime()) {
|
if (isRealTime()) {
|
||||||
m_parameters.logger("R3Stretcher::study: Not meaningful in realtime mode");
|
m_log.log(0, "R3Stretcher::study: Not meaningful in realtime mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_mode == ProcessMode::Processing || m_mode == ProcessMode::Finished) {
|
if (m_mode == ProcessMode::Processing || m_mode == ProcessMode::Finished) {
|
||||||
m_parameters.logger("R3Stretcher::study: Cannot study after processing");
|
m_log.log(0, "R3Stretcher::study: Cannot study after processing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,7 +459,7 @@ void
|
|||||||
R3Stretcher::process(const float *const *input, size_t samples, bool final)
|
R3Stretcher::process(const float *const *input, size_t samples, bool final)
|
||||||
{
|
{
|
||||||
if (m_mode == ProcessMode::Finished) {
|
if (m_mode == ProcessMode::Finished) {
|
||||||
m_parameters.logger("R3Stretcher::process: Cannot process again after final chunk");
|
m_log.log(0, "R3Stretcher::process: Cannot process again after final chunk");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,7 +484,7 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
|
|||||||
size_t ws = m_channelData[0]->inbuf->getWriteSpace();
|
size_t ws = m_channelData[0]->inbuf->getWriteSpace();
|
||||||
if (samples > ws) {
|
if (samples > ws) {
|
||||||
//!!! check this
|
//!!! check this
|
||||||
m_parameters.logger("R3Stretcher::process: WARNING: Forced to increase input buffer size. Either setMaxProcessSize was not properly called or process is being called repeatedly without retrieve.");
|
m_log.log(0, "R3Stretcher::process: WARNING: Forced to increase input buffer size. Either setMaxProcessSize was not properly called or process is being called repeatedly without retrieve.");
|
||||||
size_t newSize = m_channelData[0]->inbuf->getSize() - ws + samples;
|
size_t newSize = m_channelData[0]->inbuf->getSize() - ws + samples;
|
||||||
for (int c = 0; c < m_parameters.channels; ++c) {
|
for (int c = 0; c < m_parameters.channels; ++c) {
|
||||||
auto newBuf = m_channelData[c]->inbuf->resized(newSize);
|
auto newBuf = m_channelData[c]->inbuf->resized(newSize);
|
||||||
@@ -505,7 +521,7 @@ R3Stretcher::retrieve(float *const *output, size_t samples) const
|
|||||||
int gotHere = m_channelData[c]->outbuf->read(output[c], got);
|
int gotHere = m_channelData[c]->outbuf->read(output[c], got);
|
||||||
if (gotHere < got) {
|
if (gotHere < got) {
|
||||||
if (c > 0) {
|
if (c > 0) {
|
||||||
m_parameters.logger("R3Stretcher::retrieve: WARNING: channel imbalance detected");
|
m_log.log(0, "R3Stretcher::retrieve: WARNING: channel imbalance detected");
|
||||||
}
|
}
|
||||||
got = std::min(got, std::max(gotHere, 0));
|
got = std::min(got, std::max(gotHere, 0));
|
||||||
}
|
}
|
||||||
@@ -550,16 +566,14 @@ R3Stretcher::consume()
|
|||||||
// advanced the input and output since the previous frame, not the
|
// advanced the input and output since the previous frame, not the
|
||||||
// distances we are about to advance them, so they use the m_prev
|
// distances we are about to advance them, so they use the m_prev
|
||||||
// values.
|
// values.
|
||||||
/*
|
|
||||||
if (inhop != m_prevInhop) {
|
if (inhop != m_prevInhop) {
|
||||||
std::cout << "Note: inhop has changed from " << m_prevInhop
|
m_log.log(2, "change in inhop", double(m_prevInhop), double(inhop));
|
||||||
<< " to " << inhop << std::endl;
|
|
||||||
}
|
}
|
||||||
if (outhop != m_prevOuthop) {
|
if (outhop != m_prevOuthop) {
|
||||||
std::cout << "Note: outhop has changed from " << m_prevOuthop
|
m_log.log(2, "change in outhop", double(m_prevOuthop), double(outhop));
|
||||||
<< " to " << outhop << std::endl;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
while (m_channelData.at(0)->outbuf->getWriteSpace() >= outhop) {
|
while (m_channelData.at(0)->outbuf->getWriteSpace() >= outhop) {
|
||||||
|
|
||||||
// NB our ChannelData, ScaleData, and ChannelScaleData maps
|
// NB our ChannelData, ScaleData, and ChannelScaleData maps
|
||||||
|
|||||||
@@ -36,12 +36,12 @@
|
|||||||
#include "../common/Allocators.h"
|
#include "../common/Allocators.h"
|
||||||
#include "../common/Window.h"
|
#include "../common/Window.h"
|
||||||
#include "../common/VectorOpsComplex.h"
|
#include "../common/VectorOpsComplex.h"
|
||||||
|
#include "../common/Log.h"
|
||||||
|
|
||||||
#include "../../rubberband/RubberBandStretcher.h"
|
#include "../../rubberband/RubberBandStretcher.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace RubberBand
|
namespace RubberBand
|
||||||
{
|
{
|
||||||
@@ -53,17 +53,15 @@ public:
|
|||||||
double sampleRate;
|
double sampleRate;
|
||||||
int channels;
|
int channels;
|
||||||
RubberBandStretcher::Options options;
|
RubberBandStretcher::Options options;
|
||||||
std::function<void(const std::string &)> logger;
|
|
||||||
Parameters(double _sampleRate, int _channels,
|
Parameters(double _sampleRate, int _channels,
|
||||||
RubberBandStretcher::Options _options,
|
RubberBandStretcher::Options _options) :
|
||||||
std::function<void(const std::string &)> _log = &logCout) :
|
sampleRate(_sampleRate), channels(_channels), options(_options) { }
|
||||||
sampleRate(_sampleRate), channels(_channels), options(_options),
|
|
||||||
logger(_log) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
R3Stretcher(Parameters parameters,
|
R3Stretcher(Parameters parameters,
|
||||||
double initialTimeRatio,
|
double initialTimeRatio,
|
||||||
double initialPitchScale);
|
double initialPitchScale,
|
||||||
|
Log log);
|
||||||
~R3Stretcher() { }
|
~R3Stretcher() { }
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
@@ -89,6 +87,15 @@ public:
|
|||||||
size_t getLatency() const;
|
size_t getLatency() const;
|
||||||
size_t getChannelCount() const;
|
size_t getChannelCount() const;
|
||||||
|
|
||||||
|
void setDebugLevel(int level) {
|
||||||
|
m_log.setDebugLevel(level);
|
||||||
|
for (auto &sd : m_scaleData) {
|
||||||
|
sd.second->guided.setDebugLevel(level);
|
||||||
|
}
|
||||||
|
m_guide.setDebugLevel(level);
|
||||||
|
m_calculator->setDebugLevel(level);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct ClassificationReadaheadData {
|
struct ClassificationReadaheadData {
|
||||||
FixedVector<double> timeDomain;
|
FixedVector<double> timeDomain;
|
||||||
@@ -242,7 +249,8 @@ protected:
|
|||||||
Window<double> synthesisWindow;
|
Window<double> synthesisWindow;
|
||||||
double windowScaleFactor;
|
double windowScaleFactor;
|
||||||
GuidedPhaseAdvance guided;
|
GuidedPhaseAdvance guided;
|
||||||
ScaleData(GuidedPhaseAdvance::Parameters guidedParameters) :
|
ScaleData(GuidedPhaseAdvance::Parameters guidedParameters,
|
||||||
|
Log log) :
|
||||||
fftSize(guidedParameters.fftSize),
|
fftSize(guidedParameters.fftSize),
|
||||||
fft(fftSize),
|
fft(fftSize),
|
||||||
analysisWindow(analysisWindowShape(fftSize),
|
analysisWindow(analysisWindowShape(fftSize),
|
||||||
@@ -250,7 +258,7 @@ protected:
|
|||||||
synthesisWindow(synthesisWindowShape(fftSize),
|
synthesisWindow(synthesisWindowShape(fftSize),
|
||||||
synthesisWindowLength(fftSize)),
|
synthesisWindowLength(fftSize)),
|
||||||
windowScaleFactor(0.0),
|
windowScaleFactor(0.0),
|
||||||
guided(guidedParameters)
|
guided(guidedParameters, log)
|
||||||
{
|
{
|
||||||
int asz = analysisWindow.getSize(), ssz = synthesisWindow.getSize();
|
int asz = analysisWindow.getSize(), ssz = synthesisWindow.getSize();
|
||||||
int off = (asz - ssz) / 2;
|
int off = (asz - ssz) / 2;
|
||||||
@@ -267,6 +275,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Parameters m_parameters;
|
Parameters m_parameters;
|
||||||
|
Log m_log;
|
||||||
|
|
||||||
std::atomic<double> m_timeRatio;
|
std::atomic<double> m_timeRatio;
|
||||||
std::atomic<double> m_pitchScale;
|
std::atomic<double> m_pitchScale;
|
||||||
@@ -347,10 +356,6 @@ protected:
|
|||||||
return m_parameters.options &
|
return m_parameters.options &
|
||||||
RubberBandStretcher::OptionProcessRealTime;
|
RubberBandStretcher::OptionProcessRealTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void logCout(const std::string &message) {
|
|
||||||
std::cout << "RubberBandStretcher: " << message << std::endl;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -454,6 +454,28 @@ RubberBandVampPlugin::Impl::processOffline(const float *const *inputBuffers,
|
|||||||
return FeatureSet();
|
return FeatureSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RubberBand::Log makeCerrLog()
|
||||||
|
{
|
||||||
|
auto log0 = [](const char *message) {
|
||||||
|
std::cerr << "RubberBand: " << message << "\n";
|
||||||
|
};
|
||||||
|
auto log1 = [](const char *message, double arg0) {
|
||||||
|
auto prec = std::cerr.precision();
|
||||||
|
std::cerr.precision(10);
|
||||||
|
std::cerr << "RubberBand: " << message << ": " << arg0 << "\n";
|
||||||
|
std::cerr.precision(prec);
|
||||||
|
};
|
||||||
|
auto log2 = [](const char *message, double arg0, double arg1) {
|
||||||
|
auto prec = std::cerr.precision();
|
||||||
|
std::cerr.precision(10);
|
||||||
|
std::cerr << "RubberBand: " << message
|
||||||
|
<< ": (" << arg0 << ", " << arg1 << ")" << "\n";
|
||||||
|
std::cerr.precision(prec);
|
||||||
|
};
|
||||||
|
|
||||||
|
return RubberBand::Log(log0, log1, log2);
|
||||||
|
}
|
||||||
|
|
||||||
RubberBandVampPlugin::FeatureSet
|
RubberBandVampPlugin::FeatureSet
|
||||||
RubberBandVampPlugin::Impl::getRemainingFeaturesOffline()
|
RubberBandVampPlugin::Impl::getRemainingFeaturesOffline()
|
||||||
{
|
{
|
||||||
@@ -463,7 +485,8 @@ RubberBandVampPlugin::Impl::getRemainingFeaturesOffline()
|
|||||||
|
|
||||||
int rate = m_sampleRate;
|
int rate = m_sampleRate;
|
||||||
|
|
||||||
RubberBand::StretchCalculator sc(rate, m_stretcher->getInputIncrement(), true);
|
RubberBand::StretchCalculator sc
|
||||||
|
(rate, m_stretcher->getInputIncrement(), true, makeCerrLog());
|
||||||
|
|
||||||
size_t inputIncrement = m_stretcher->getInputIncrement();
|
size_t inputIncrement = m_stretcher->getInputIncrement();
|
||||||
std::vector<int> outputIncrements = m_stretcher->getOutputIncrements();
|
std::vector<int> outputIncrements = m_stretcher->getOutputIncrements();
|
||||||
|
|||||||
Reference in New Issue
Block a user