Optional split computation, behind a configuration switch

This commit is contained in:
Geraint 2025-02-27 15:45:33 +00:00
parent 8c3852cae3
commit a654087551
2 changed files with 25 additions and 16 deletions

View File

@ -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();

View File

@ -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;