in pedalboard/plugin_templates/Resample.h [335:510]
int process(const juce::dsp::ProcessContextReplacing<SampleType> &context)
override final {
auto ioBlock = context.getOutputBlock();
float expectedResampledSamples = ioBlock.getNumSamples() / resamplerRatio;
if (spaceAvailableInResampledBuffer() < expectedResampledSamples) {
throw std::runtime_error(
"More samples were provided than can be buffered! This is an "
"internal Pedalboard error and should be reported. Buffer had " +
std::to_string(processedSamplesInResampledBuffer +
cleanSamplesInResampledBuffer) +
"/" + std::to_string(resampledBuffer.getNumSamples()) +
" samples at target sample rate, but was provided " +
std::to_string(expectedResampledSamples) + ".");
}
unsigned long samplesUsed = 0;
if (samplesInInputReservoir) {
// Copy the input samples into the input reservoir and use that as the
// resampler's input:
expectedResampledSamples +=
(float)samplesInInputReservoir / resamplerRatio;
for (size_t c = 0; c < ioBlock.getNumChannels(); c++) {
inputReservoir.copyFrom(c, samplesInInputReservoir,
ioBlock.getChannelPointer(c),
ioBlock.getNumSamples());
SampleType *resampledBufferPointer =
resampledBuffer.getWritePointer(c) +
processedSamplesInResampledBuffer + cleanSamplesInResampledBuffer;
samplesUsed = nativeToTargetResamplers[c].process(
resamplerRatio, inputReservoir.getReadPointer(c),
resampledBufferPointer, expectedResampledSamples);
}
if (samplesUsed < ioBlock.getNumSamples() + samplesInInputReservoir) {
// Take the missing samples and put them at the start of the input
// reservoir for next time:
int unusedInputSampleCount =
(ioBlock.getNumSamples() + samplesInInputReservoir) - samplesUsed;
juce::dsp::AudioBlock<SampleType> inputReservoirBlock(inputReservoir);
inputReservoirBlock.move(samplesUsed, 0, unusedInputSampleCount);
samplesInInputReservoir = unusedInputSampleCount;
} else {
samplesInInputReservoir = 0;
}
} else {
for (size_t c = 0; c < ioBlock.getNumChannels(); c++) {
SampleType *resampledBufferPointer =
resampledBuffer.getWritePointer(c) +
processedSamplesInResampledBuffer + cleanSamplesInResampledBuffer;
samplesUsed = nativeToTargetResamplers[c].process(
resamplerRatio, ioBlock.getChannelPointer(c),
resampledBufferPointer, (int)expectedResampledSamples);
}
if (samplesUsed < ioBlock.getNumSamples()) {
// Take the missing samples and put them at the start of the input
// reservoir for next time:
int unusedInputSampleCount = ioBlock.getNumSamples() - samplesUsed;
for (size_t c = 0; c < ioBlock.getNumChannels(); c++) {
inputReservoir.copyFrom(c, 0,
ioBlock.getChannelPointer(c) + samplesUsed,
unusedInputSampleCount);
}
samplesInInputReservoir = unusedInputSampleCount;
}
}
cleanSamplesInResampledBuffer += (int)expectedResampledSamples;
// Pass resampledBuffer to the plugin, in chunks:
juce::dsp::AudioBlock<SampleType> resampledBlock(resampledBuffer);
// Only pass in the maximumBlockSize (in target sample rate) that the
// sub-plugin expects:
while (cleanSamplesInResampledBuffer > 0) {
int cleanSamplesToProcess =
std::min((int)maximumBlockSizeInTargetSampleRate,
cleanSamplesInResampledBuffer);
juce::dsp::AudioBlock<SampleType> subBlock = resampledBlock.getSubBlock(
processedSamplesInResampledBuffer, cleanSamplesToProcess);
juce::dsp::ProcessContextReplacing<SampleType> subContext(subBlock);
int resampledSamplesOutput = plugin.process(subContext);
if (resampledSamplesOutput < cleanSamplesToProcess) {
// Move all remaining samples to the left of the buffer:
int offset = cleanSamplesToProcess - resampledSamplesOutput;
for (size_t c = 0; c < ioBlock.getNumChannels(); c++) {
// Move the contents of the resampled block to the left:
std::memmove(
(char *)resampledBuffer.getWritePointer(c) +
processedSamplesInResampledBuffer,
(char *)(resampledBuffer.getWritePointer(c) +
processedSamplesInResampledBuffer + offset),
(resampledSamplesOutput + cleanSamplesInResampledBuffer) *
sizeof(SampleType));
}
}
processedSamplesInResampledBuffer += resampledSamplesOutput;
cleanSamplesInResampledBuffer -= cleanSamplesToProcess;
}
// Resample back to the intended sample rate:
int expectedOutputSamples =
processedSamplesInResampledBuffer * resamplerRatio;
int samplesConsumed = 0;
if (spaceAvailableInOutputBuffer() < expectedOutputSamples) {
throw std::runtime_error(
"More samples were provided than can be buffered! This is an "
"internal Pedalboard error and should be reported. Buffer had " +
std::to_string(samplesInOutputBuffer) + "/" +
std::to_string(outputBuffer.getNumSamples()) +
" samples at native sample rate, but was provided " +
std::to_string(expectedOutputSamples) + ".");
}
for (size_t c = 0; c < ioBlock.getNumChannels(); c++) {
float *outputBufferPointer =
outputBuffer.getWritePointer(c) + samplesInOutputBuffer;
samplesConsumed = targetToNativeResamplers[c].process(
inverseResamplerRatio, resampledBuffer.getReadPointer(c),
outputBufferPointer, expectedOutputSamples);
}
samplesInOutputBuffer += expectedOutputSamples;
int samplesRemainingInResampledBuffer = processedSamplesInResampledBuffer +
cleanSamplesInResampledBuffer -
samplesConsumed;
if (samplesRemainingInResampledBuffer > 0) {
for (size_t c = 0; c < ioBlock.getNumChannels(); c++) {
// Move the contents of the resampled block to the left:
std::memmove(
(char *)resampledBuffer.getWritePointer(c),
(char *)(resampledBuffer.getWritePointer(c) + samplesConsumed),
(samplesRemainingInResampledBuffer) * sizeof(SampleType));
}
}
processedSamplesInResampledBuffer -= samplesConsumed;
// Copy from output buffer to output block:
int samplesToOutput =
std::min((int)ioBlock.getNumSamples(), (int)samplesInOutputBuffer);
ioBlock.copyFrom(outputBuffer, 0, ioBlock.getNumSamples() - samplesToOutput,
samplesToOutput);
int samplesRemainingInOutputBuffer =
samplesInOutputBuffer - samplesToOutput;
if (samplesRemainingInOutputBuffer > 0) {
for (size_t c = 0; c < ioBlock.getNumChannels(); c++) {
// Move the contents of the resampled block to the left:
std::memmove(
(char *)outputBuffer.getWritePointer(c),
(char *)(outputBuffer.getWritePointer(c) + samplesToOutput),
(samplesRemainingInOutputBuffer) * sizeof(SampleType));
}
}
samplesInOutputBuffer -= samplesToOutput;
samplesProduced += samplesToOutput;
int samplesToReturn = std::min((long)(samplesProduced - inStreamLatency),
(long)samplesToOutput);
if (samplesToReturn < 0)
samplesToReturn = 0;
return samplesToReturn;
}