Add reflected pre-roll to .outputSeek()
This commit is contained in:
parent
2724daacaf
commit
90d6c686eb
@ -7,7 +7,7 @@ include(FetchContent)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
signalsmith-linear
|
signalsmith-linear
|
||||||
GIT_REPOSITORY https://github.com/Signalsmith-Audio/linear.git
|
GIT_REPOSITORY https://github.com/Signalsmith-Audio/linear.git
|
||||||
GIT_TAG 0.2.2
|
GIT_TAG 0.2.3
|
||||||
GIT_SHALLOW ON
|
GIT_SHALLOW ON
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(signalsmith-linear)
|
FetchContent_MakeAvailable(signalsmith-linear)
|
||||||
|
|||||||
@ -89,7 +89,8 @@ struct SignalsmithStretch {
|
|||||||
blockProcess = {};
|
blockProcess = {};
|
||||||
formantMetric.resize(bands + 2);
|
formantMetric.resize(bands + 2);
|
||||||
|
|
||||||
tmpBuffer.resize(std::max(outputLatency()*channels, blockSamples + intervalSamples));
|
tmpProcessBuffer.resize(blockSamples + intervalSamples);
|
||||||
|
tmpPreRollBuffer.resize(outputLatency()*channels);
|
||||||
}
|
}
|
||||||
// For querying the existing config
|
// For querying the existing config
|
||||||
int blockSamples() const {
|
int blockSamples() const {
|
||||||
@ -137,11 +138,11 @@ struct SignalsmithStretch {
|
|||||||
// You should ideally feed it `seekLength()` frames of input, unless it's directly after a `.reset()` (in which case `.outputSeek()` might be a better choice)
|
// You should ideally feed it `seekLength()` frames of input, unless it's directly after a `.reset()` (in which case `.outputSeek()` might be a better choice)
|
||||||
template<class Inputs>
|
template<class Inputs>
|
||||||
void seek(Inputs &&inputs, int inputSamples, double playbackRate) {
|
void seek(Inputs &&inputs, int inputSamples, double playbackRate) {
|
||||||
tmpBuffer.resize(0);
|
tmpProcessBuffer.resize(0);
|
||||||
tmpBuffer.resize(stft.blockSamples() + stft.defaultInterval());
|
tmpProcessBuffer.resize(stft.blockSamples() + stft.defaultInterval());
|
||||||
|
|
||||||
int startIndex = std::max<int>(0, inputSamples - int(tmpBuffer.size())); // start position in input
|
int startIndex = std::max<int>(0, inputSamples - int(tmpProcessBuffer.size())); // start position in input
|
||||||
int padStart = int(tmpBuffer.size() + startIndex) - inputSamples; // start position in tmpBuffer
|
int padStart = int(tmpProcessBuffer.size() + startIndex) - inputSamples; // start position in tmpProcessBuffer
|
||||||
|
|
||||||
Sample totalEnergy = 0;
|
Sample totalEnergy = 0;
|
||||||
for (int c = 0; c < channels; ++c) {
|
for (int c = 0; c < channels; ++c) {
|
||||||
@ -149,12 +150,12 @@ struct SignalsmithStretch {
|
|||||||
for (int i = startIndex; i < inputSamples; ++i) {
|
for (int i = startIndex; i < inputSamples; ++i) {
|
||||||
Sample s = inputChannel[i];
|
Sample s = inputChannel[i];
|
||||||
totalEnergy += s*s;
|
totalEnergy += s*s;
|
||||||
tmpBuffer[i - startIndex + padStart] = s;
|
tmpProcessBuffer[i - startIndex + padStart] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
stft.writeInput(c, tmpBuffer.size(), tmpBuffer.data());
|
stft.writeInput(c, tmpProcessBuffer.size(), tmpProcessBuffer.data());
|
||||||
}
|
}
|
||||||
stft.moveInput(tmpBuffer.size());
|
stft.moveInput(tmpProcessBuffer.size());
|
||||||
if (totalEnergy >= noiseFloor) {
|
if (totalEnergy >= noiseFloor) {
|
||||||
silenceCounter = 0;
|
silenceCounter = 0;
|
||||||
silenceFirst = true;
|
silenceFirst = true;
|
||||||
@ -180,20 +181,26 @@ struct SignalsmithStretch {
|
|||||||
int seekSamples = inputLength - surplusInput;
|
int seekSamples = inputLength - surplusInput;
|
||||||
seek(inputs, seekSamples, playbackRate);
|
seek(inputs, seekSamples, playbackRate);
|
||||||
|
|
||||||
tmpBuffer.resize(outputLatency()*channels);
|
tmpPreRollBuffer.resize(outputLatency()*channels);
|
||||||
struct PreRollOutput {
|
struct BufferOutput {
|
||||||
Sample *samples;
|
Sample *samples;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
Sample * operator[](int c) {
|
Sample * operator[](int c) {
|
||||||
return samples + c*length;
|
return samples + c*length;
|
||||||
}
|
}
|
||||||
} preRollOutput{tmpBuffer.data(), outputLatency()};
|
} preRollOutput{tmpPreRollBuffer.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};
|
OffsetIO<Inputs> offsetInput{inputs, seekSamples};
|
||||||
process(offsetInput, surplusInput, preRollOutput, outputLatency());
|
process(offsetInput, surplusInput, preRollOutput, preRollOutput.length);
|
||||||
// TODO: put the thing down, flip it and reverse it
|
|
||||||
|
// put the thing down, flip it and reverse it
|
||||||
|
for (auto &v : tmpPreRollBuffer) v = -v;
|
||||||
|
for (int c = 0; c < channels; ++c) {
|
||||||
|
std::reverse(preRollOutput[c], preRollOutput[c] + preRollOutput.length);
|
||||||
|
stft.addOutput(c, preRollOutput.length, preRollOutput[c]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int outputSeekLength(Sample playbackRate) const {
|
int outputSeekLength(Sample playbackRate) const {
|
||||||
return inputLatency() + playbackRate*outputLatency();
|
return inputLatency() + playbackRate*outputLatency();
|
||||||
@ -208,14 +215,14 @@ struct SignalsmithStretch {
|
|||||||
auto copyInput = [&](int toIndex){
|
auto copyInput = [&](int toIndex){
|
||||||
|
|
||||||
int length = std::min<int>(int(stft.blockSamples() + stft.defaultInterval()), toIndex - prevCopiedInput);
|
int length = std::min<int>(int(stft.blockSamples() + stft.defaultInterval()), toIndex - prevCopiedInput);
|
||||||
tmpBuffer.resize(length);
|
tmpProcessBuffer.resize(length);
|
||||||
int offset = toIndex - length;
|
int offset = toIndex - length;
|
||||||
for (int c = 0; c < channels; ++c) {
|
for (int c = 0; c < channels; ++c) {
|
||||||
auto &&inputBuffer = inputs[c];
|
auto &&inputBuffer = inputs[c];
|
||||||
for (int i = 0; i < length; ++i) {
|
for (int i = 0; i < length; ++i) {
|
||||||
tmpBuffer[i] = inputBuffer[i + offset];
|
tmpProcessBuffer[i] = inputBuffer[i + offset];
|
||||||
}
|
}
|
||||||
stft.writeInput(c, length, tmpBuffer.data());
|
stft.writeInput(c, length, tmpProcessBuffer.data());
|
||||||
}
|
}
|
||||||
stft.moveInput(length);
|
stft.moveInput(length);
|
||||||
prevCopiedInput = toIndex;
|
prevCopiedInput = toIndex;
|
||||||
@ -433,19 +440,17 @@ struct SignalsmithStretch {
|
|||||||
if (outputBlock > 0) process(zeros, outputBlock*playbackRate, outputs, outputBlock);
|
if (outputBlock > 0) process(zeros, outputBlock*playbackRate, outputs, outputBlock);
|
||||||
|
|
||||||
int tailSamples = outputSamples - outputBlock; // at most one interval
|
int tailSamples = outputSamples - outputBlock; // at most one interval
|
||||||
int reflectSamples = std::min<int>(tailSamples, outputSamples - tailSamples);
|
tmpProcessBuffer.resize(tailSamples);
|
||||||
stft.finishOutput(1);
|
stft.finishOutput(1);
|
||||||
for (int c = 0; c < channels; ++c) {
|
for (int c = 0; c < channels; ++c) {
|
||||||
tmpBuffer.resize(tailSamples);
|
stft.readOutput(c, tailSamples, tmpProcessBuffer.data());
|
||||||
stft.readOutput(c, tailSamples, tmpBuffer.data());
|
|
||||||
auto &&outputChannel = outputs[c];
|
auto &&outputChannel = outputs[c];
|
||||||
for (int i = 0; i < tailSamples; ++i) {
|
for (int i = 0; i < tailSamples; ++i) {
|
||||||
outputChannel[outputBlock + i] = tmpBuffer[i];
|
outputChannel[outputBlock + i] = tmpProcessBuffer[i];
|
||||||
}
|
}
|
||||||
tmpBuffer.resize(reflectSamples);
|
stft.readOutput(c, tailSamples, tailSamples, tmpProcessBuffer.data());
|
||||||
stft.readOutput(c, reflectSamples, tailSamples, tmpBuffer.data());
|
for (int i = 0; i < tailSamples; ++i) {
|
||||||
for (int i = 0; i < reflectSamples; ++i) {
|
outputChannel[outputBlock + tailSamples - 1 - i] -= tmpProcessBuffer[i];
|
||||||
outputChannel[outputBlock + tailSamples - 1 - i] -= tmpBuffer[i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stft.reset(0.1f);
|
stft.reset(0.1f);
|
||||||
@ -516,7 +521,7 @@ private:
|
|||||||
typename STFT::Input stashedInput;
|
typename STFT::Input stashedInput;
|
||||||
typename STFT::Output stashedOutput;
|
typename STFT::Output stashedOutput;
|
||||||
|
|
||||||
std::vector<Sample> tmpBuffer;
|
std::vector<Sample> tmpProcessBuffer, tmpPreRollBuffer;
|
||||||
|
|
||||||
int channels = 0, bands = 0;
|
int channels = 0, bands = 0;
|
||||||
int prevInputOffset = -1;
|
int prevInputOffset = -1;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user