Optional split computation, behind a configuration switch
This commit is contained in:
parent
8c3852cae3
commit
a654087551
@ -77,6 +77,7 @@ int main(int argc, char* argv[]) {
|
|||||||
double tonality = args.flag<double>("tonality", "tonality limit (Hz)", 8000);
|
double tonality = args.flag<double>("tonality", "tonality limit (Hz)", 8000);
|
||||||
double time = args.flag<double>("time", "time-stretch factor", 1);
|
double time = args.flag<double>("time", "time-stretch factor", 1);
|
||||||
bool exactLength = args.hasFlag("exact", "trims the start/end so the output has the correct length");
|
bool exactLength = args.hasFlag("exact", "trims the start/end so the output has the correct length");
|
||||||
|
bool splitComputation = args.hasFlag("split-computation", "distributes the computation more evenly (but higher latency)");
|
||||||
args.errorExit();
|
args.errorExit();
|
||||||
|
|
||||||
std::cout << Console::Bright << inputWav << Console::Reset;
|
std::cout << Console::Bright << inputWav << Console::Reset;
|
||||||
@ -105,7 +106,7 @@ int main(int argc, char* argv[]) {
|
|||||||
signalsmith::Stopwatch stopwatch;
|
signalsmith::Stopwatch stopwatch;
|
||||||
|
|
||||||
stopwatch.start();
|
stopwatch.start();
|
||||||
stretch.presetDefault(int(inWav.channels), inWav.sampleRate);
|
stretch.presetDefault(int(inWav.channels), inWav.sampleRate, splitComputation);
|
||||||
stretch.setTransposeSemitones(semitones, tonality/inWav.sampleRate);
|
stretch.setTransposeSemitones(semitones, tonality/inWav.sampleRate);
|
||||||
double initSeconds = stopwatch.lap();
|
double initSeconds = stopwatch.lap();
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,7 @@ struct SignalsmithStretch {
|
|||||||
return int(stft.analysisLatency());
|
return int(stft.analysisLatency());
|
||||||
}
|
}
|
||||||
int outputLatency() const {
|
int outputLatency() const {
|
||||||
return int(stft.synthesisLatency() + stft.defaultInterval());
|
return int(stft.synthesisLatency() + _splitComputation*stft.defaultInterval());
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
@ -67,15 +67,16 @@ struct SignalsmithStretch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configures using a default preset
|
// Configures using a default preset
|
||||||
void presetDefault(int nChannels, Sample sampleRate) {
|
void presetDefault(int nChannels, Sample sampleRate, bool splitComputation=false) {
|
||||||
configure(nChannels, sampleRate*0.12, sampleRate*0.03);
|
configure(nChannels, sampleRate*0.12, sampleRate*0.03, splitComputation);
|
||||||
}
|
}
|
||||||
void presetCheaper(int nChannels, Sample sampleRate) {
|
void presetCheaper(int nChannels, Sample sampleRate, bool splitComputation=true) {
|
||||||
configure(nChannels, sampleRate*0.1, sampleRate*0.04);
|
configure(nChannels, sampleRate*0.1, sampleRate*0.04, splitComputation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manual setup
|
// Manual setup
|
||||||
void configure(int nChannels, int blockSamples, int intervalSamples) {
|
void configure(int nChannels, int blockSamples, int intervalSamples, bool splitComputation=false) {
|
||||||
|
_splitComputation = splitComputation;
|
||||||
channels = nChannels;
|
channels = nChannels;
|
||||||
stft.configure(channels, channels, blockSamples, intervalSamples + 1);
|
stft.configure(channels, channels, blockSamples, intervalSamples + 1);
|
||||||
stft.setInterval(intervalSamples, stft.kaiser);
|
stft.setInterval(intervalSamples, stft.kaiser);
|
||||||
@ -216,11 +217,10 @@ struct SignalsmithStretch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int outputIndex = 0; outputIndex < outputSamples; ++outputIndex) {
|
for (int outputIndex = 0; outputIndex < outputSamples; ++outputIndex) {
|
||||||
Sample processRatio = Sample(blockProcess.samplesSinceLast)/stft.defaultInterval();
|
bool newBlock = blockProcess.samplesSinceLast >= stft.defaultInterval();
|
||||||
if (processRatio >= 1) { // we're ready to start a new block
|
if (newBlock) {
|
||||||
processRatio = 0;
|
|
||||||
blockProcess.step = 0;
|
blockProcess.step = 0;
|
||||||
blockProcess.steps = 0; // how many steps
|
blockProcess.steps = 0; // how many processing steps this block will have
|
||||||
blockProcess.samplesSinceLast = 0;
|
blockProcess.samplesSinceLast = 0;
|
||||||
|
|
||||||
// Time to process a spectrum! Where should it come from in the input?
|
// Time to process a spectrum! Where should it come from in the input?
|
||||||
@ -230,8 +230,10 @@ struct SignalsmithStretch {
|
|||||||
|
|
||||||
copyInput(inputOffset);
|
copyInput(inputOffset);
|
||||||
stashedInput = stft.input; // save the input state, since that's what we'll analyse later
|
stashedInput = stft.input; // save the input state, since that's what we'll analyse later
|
||||||
stashedOutput = stft.output; // save the current output, and read from it
|
if (_splitComputation) {
|
||||||
stft.moveOutput(stft.defaultInterval()); // the actual input jumps forward in time by one interval, ready for the synthesis
|
stashedOutput = stft.output; // save the current output, and read from it
|
||||||
|
stft.moveOutput(stft.defaultInterval()); // the actual input jumps forward in time by one interval, ready for the synthesis
|
||||||
|
}
|
||||||
|
|
||||||
blockProcess.newSpectrum = didSeek || (inputInterval > 0);
|
blockProcess.newSpectrum = didSeek || (inputInterval > 0);
|
||||||
blockProcess.mappedFrequencies = customFreqMap || freqMultiplier != 1;
|
blockProcess.mappedFrequencies = customFreqMap || freqMultiplier != 1;
|
||||||
@ -252,7 +254,12 @@ struct SignalsmithStretch {
|
|||||||
|
|
||||||
blockProcess.steps += stft.synthesiseSteps() + 1;
|
blockProcess.steps += stft.synthesiseSteps() + 1;
|
||||||
}
|
}
|
||||||
size_t processToStep = std::min<size_t>(blockProcess.steps, (blockProcess.steps + 1)*processRatio);
|
|
||||||
|
size_t processToStep = newBlock ? blockProcess.steps : 0;
|
||||||
|
if (_splitComputation) {
|
||||||
|
Sample processRatio = Sample(blockProcess.samplesSinceLast + 1)/stft.defaultInterval();
|
||||||
|
processToStep = std::min<size_t>(blockProcess.steps, (blockProcess.steps + 0.999f)*processRatio);
|
||||||
|
}
|
||||||
|
|
||||||
while (blockProcess.step < processToStep) {
|
while (blockProcess.step < processToStep) {
|
||||||
size_t step = blockProcess.step++;
|
size_t step = blockProcess.step++;
|
||||||
@ -334,7 +341,7 @@ struct SignalsmithStretch {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
++blockProcess.samplesSinceLast;
|
++blockProcess.samplesSinceLast;
|
||||||
stashedOutput.swap(stft.output);
|
if (_splitComputation) stashedOutput.swap(stft.output);
|
||||||
for (int c = 0; c < channels; ++c) {
|
for (int c = 0; c < channels; ++c) {
|
||||||
auto &&outputChannel = outputs[c];
|
auto &&outputChannel = outputs[c];
|
||||||
Sample v = 0;
|
Sample v = 0;
|
||||||
@ -342,7 +349,7 @@ struct SignalsmithStretch {
|
|||||||
outputChannel[outputIndex] = v;
|
outputChannel[outputIndex] = v;
|
||||||
}
|
}
|
||||||
stft.moveOutput(1);
|
stft.moveOutput(1);
|
||||||
stashedOutput.swap(stft.output);
|
if (_splitComputation) stashedOutput.swap(stft.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyInput(inputSamples);
|
copyInput(inputSamples);
|
||||||
@ -383,6 +390,7 @@ struct SignalsmithStretch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
bool _splitComputation = false;
|
||||||
struct {
|
struct {
|
||||||
size_t samplesSinceLast = -1;
|
size_t samplesSinceLast = -1;
|
||||||
size_t steps = 0;
|
size_t steps = 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user