Use .outputSeek() for .exact()
This commit is contained in:
parent
c3fcda8563
commit
3e71aec5f7
@ -60,10 +60,10 @@ int main(int argc, char* argv[]) {
|
|||||||
// At this point, the next output samples we get will correspond to the beginning of the audio file.
|
// At this point, the next output samples we get will correspond to the beginning of the audio file.
|
||||||
|
|
||||||
// We're going to process until *just* before the end of the audio file (so we can get a tidier end using `.flush()`.
|
// We're going to process until *just* before the end of the audio file (so we can get a tidier end using `.flush()`.
|
||||||
int outputIndex = outputLength - stretch.outputLatency();
|
int outputIndex = outputLength - stretch.intervalSamples();
|
||||||
|
|
||||||
// Stretch's internal output position is slightly ahead of the output samples we get
|
// Stretch's internal output position is slightly ahead of the output samples we get
|
||||||
int outputPos = outputLength + stretch.outputLatency();
|
int outputPos = outputIndex + stretch.outputLatency();
|
||||||
// Time-map: where do we want the input position to be at that moment?
|
// Time-map: where do we want the input position to be at that moment?
|
||||||
int inputPos = std::round(outputPos/time);
|
int inputPos = std::round(outputPos/time);
|
||||||
// And therefore which input samples do we need to be supplying?
|
// And therefore which input samples do we need to be supplying?
|
||||||
|
|||||||
@ -180,24 +180,6 @@ struct SignalsmithStretch {
|
|||||||
int seekSamples = inputLength - surplusInput;
|
int seekSamples = inputLength - surplusInput;
|
||||||
seek(inputs, seekSamples, playbackRate);
|
seek(inputs, seekSamples, playbackRate);
|
||||||
|
|
||||||
// Awkward proxy classes to avoid copying/allocating anything
|
|
||||||
struct OffsetInput {
|
|
||||||
Inputs &inputs;
|
|
||||||
int offset;
|
|
||||||
|
|
||||||
struct Channel {
|
|
||||||
Inputs &inputs;
|
|
||||||
int channel;
|
|
||||||
int offset;
|
|
||||||
|
|
||||||
Sample operator[](int i) {
|
|
||||||
return Sample(inputs[channel][i + offset]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Channel operator[](int c) {
|
|
||||||
return {inputs, c, offset};
|
|
||||||
}
|
|
||||||
} offsetInput{inputs, seekSamples};
|
|
||||||
tmpBuffer.resize(outputLatency()*channels);
|
tmpBuffer.resize(outputLatency()*channels);
|
||||||
struct PreRollOutput {
|
struct PreRollOutput {
|
||||||
Sample *samples;
|
Sample *samples;
|
||||||
@ -209,6 +191,7 @@ struct SignalsmithStretch {
|
|||||||
} preRollOutput{tmpBuffer.data(), outputLatency()};
|
} preRollOutput{tmpBuffer.data(), outputLatency()};
|
||||||
|
|
||||||
// Use the surplus input to produce pre-roll output
|
// Use the surplus input to produce pre-roll output
|
||||||
|
OffsetIO<Inputs> offsetInput{inputs, seekSamples};
|
||||||
process(offsetInput, surplusInput, preRollOutput, outputLatency());
|
process(offsetInput, surplusInput, preRollOutput, outputLatency());
|
||||||
// TODO: put the thing down, flip it and reverse it
|
// TODO: put the thing down, flip it and reverse it
|
||||||
}
|
}
|
||||||
@ -462,9 +445,12 @@ struct SignalsmithStretch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process a complete audio buffer all in one go
|
||||||
template<class Inputs, class Outputs>
|
template<class Inputs, class Outputs>
|
||||||
bool exact(Inputs &&inputs, int inputSamples, Outputs &&outputs, int outputSamples) {
|
bool exact(Inputs &&inputs, int inputSamples, Outputs &&outputs, int outputSamples) {
|
||||||
if (outputSamples < outputLatency()*2) {
|
Sample playbackRate = inputSamples/Sample(outputSamples);
|
||||||
|
auto seekLength = outputSeekLength(playbackRate);
|
||||||
|
if (inputSamples < seekLength) {
|
||||||
// to short for this - zero the output just to be polite
|
// to short for this - zero the output just to be polite
|
||||||
for (int c = 0; c < channels; ++c) {
|
for (int c = 0; c < channels; ++c) {
|
||||||
auto &&channel = outputs[c];
|
auto &&channel = outputs[c];
|
||||||
@ -475,61 +461,29 @@ struct SignalsmithStretch {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ZeroPaddedInput {
|
outputSeek(inputs, seekLength);
|
||||||
Inputs &inputs;
|
|
||||||
int offset, length;
|
int outputIndex = outputSamples - seekLength/playbackRate;
|
||||||
|
OffsetIO<Inputs> offsetInput{inputs, seekLength};
|
||||||
|
process(offsetInput, inputSamples - seekLength, outputs, outputIndex);
|
||||||
|
|
||||||
|
struct Zeros {
|
||||||
struct Channel {
|
struct Channel {
|
||||||
ZeroPaddedInput &zpi;
|
Sample operator[](int) {
|
||||||
int channel;
|
|
||||||
|
|
||||||
Sample operator[](int i) {
|
|
||||||
if (zpi.offset + i < zpi.length) return zpi.inputs[channel][zpi.offset + i];
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Channel operator[](int) {
|
||||||
Channel operator[](int c){
|
return {};
|
||||||
return {*this, c};
|
|
||||||
}
|
}
|
||||||
} zpi{inputs, inputLatency(), inputSamples};
|
} zeros;
|
||||||
seek(inputs, inputLatency(), Sample(inputSamples)/outputSamples); // start positioned on the centre of the input
|
OffsetIO<Outputs> oo{outputs, outputIndex};
|
||||||
process(zpi, inputSamples, outputs, outputSamples);
|
int outputIndex2 = outputSamples - stft.defaultInterval();
|
||||||
|
int outputBlock = outputIndex2 - outputIndex;
|
||||||
// Fold the first bit of the input back onto itself
|
process(zeros, outputBlock/playbackRate, oo, outputBlock);
|
||||||
for (int c = 0; c < channels; ++c) {
|
|
||||||
auto &&channel = outputs[c];
|
|
||||||
for (int i = 0; i < std::min<int>(outputSamples - outputLatency(), outputLatency()); ++i) {
|
|
||||||
channel[i + outputLatency()] -= channel[outputLatency() - 1 - i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Shuffle everything along to compensate for output latency
|
|
||||||
for (int c = 0; c < channels; ++c) {
|
|
||||||
auto &&channel = outputs[c];
|
|
||||||
for (int i = 0; i < outputSamples - outputLatency(); ++i) {
|
|
||||||
channel[i] = channel[i + outputLatency()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OffsetOutput {
|
OffsetIO<Outputs> offsetOutput{outputs, outputIndex2};
|
||||||
Outputs &outputs;
|
flush(offsetOutput, outputSamples - outputIndex);
|
||||||
int offset;
|
|
||||||
|
|
||||||
struct Channel {
|
|
||||||
OffsetOutput &oo;
|
|
||||||
int channel;
|
|
||||||
|
|
||||||
decltype(outputs[0][0]) operator[](int i) {
|
|
||||||
return oo.outputs[channel][oo.offset + i];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Channel operator[](int c){
|
|
||||||
return {*this, c};
|
|
||||||
}
|
|
||||||
} oo{outputs, outputSamples - outputLatency()};
|
|
||||||
// Get the final chunk - extra output is already folded back as part of this
|
|
||||||
flush(oo, outputLatency());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1077,6 +1031,26 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Proxy class to avoid copying/allocating anything
|
||||||
|
template<class Io>
|
||||||
|
struct OffsetIO {
|
||||||
|
Io &io;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
struct Channel {
|
||||||
|
Io &io;
|
||||||
|
int channel;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
auto operator[](int i) -> decltype(io[0][0]) {
|
||||||
|
return io[channel][i + offset];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Channel operator[](int c) {
|
||||||
|
return {io, c, offset};
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace
|
}} // namespace
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user