From 4b6497272d54c02f24e03b97b5100e8c5ad29685 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 15 Feb 2021 15:25:50 +0100 Subject: [PATCH] Implement sfizz oversampler using new code --- src/sfizz/Oversampler.cpp | 169 ++++++-------------------------------- 1 file changed, 24 insertions(+), 145 deletions(-) diff --git a/src/sfizz/Oversampler.cpp b/src/sfizz/Oversampler.cpp index 954a6119..b0d1ed5f 100644 --- a/src/sfizz/Oversampler.cpp +++ b/src/sfizz/Oversampler.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Oversampler.h" +#include "OversamplerHelpers.h" #include "Buffer.h" #include "AudioSpan.h" #include "AudioReader.h" @@ -14,52 +15,6 @@ template using aligned_vector = std::vector>; -constexpr std::array coeffsStage2x { - 0.036681502163648017, - 0.13654762463195771, - 0.27463175937945411, - 0.42313861743656667, - 0.56109869787919475, - 0.67754004997416162, - 0.76974183386322659, - 0.83988962484963803, - 0.89226081800387891, - 0.9315419599631839, - 0.96209454837808395, - 0.98781637073289708 -}; - -constexpr std::array coeffsStage4x { - 0.042448989488488006, - 0.17072114107630679, - 0.39329183835224008, - 0.74569514831986694 -}; - -constexpr std::array coeffsStage8x { - 0.055748680811302048, - 0.24305119574153092, - 0.6466991311926823 -}; - - -#if SFIZZ_HAVE_SSE -#include "hiir/Upsampler2xSse.h" -using Upsampler2x = hiir::Upsampler2xSse; -using Upsampler4x = hiir::Upsampler2xSse; -using Upsampler8x = hiir::Upsampler2xSse; -#elif SFIZZ_HAVE_NEON -#include "hiir/Upsampler2xNeon.h" -using Upsampler2x = hiir::Upsampler2xNeon; -using Upsampler4x = hiir::Upsampler2xNeon; -using Upsampler8x = hiir::Upsampler2xNeon; -#else -#include "hiir/Upsampler2xFpu.h" -using Upsampler2x = hiir::Upsampler2xFpu; -using Upsampler4x = hiir::Upsampler2xFpu; -using Upsampler8x = hiir::Upsampler2xFpu; -#endif - sfz::Oversampler::Oversampler(sfz::Oversampling factor, size_t chunkSize) : factor(factor), chunkSize(chunkSize) { @@ -74,36 +29,10 @@ void sfz::Oversampler::stream(AudioSpan input, AudioSpan output, s const auto numFrames = input.getNumFrames(); const auto numChannels = input.getNumChannels(); - aligned_vector upsampler2x; - aligned_vector upsampler4x; - aligned_vector upsampler8x; + aligned_vector upsampler(numChannels); - switch(factor) - { - case Oversampling::x8: - upsampler8x.resize(numChannels); - for (auto& upsampler: upsampler8x) - upsampler.set_coefs(coeffsStage8x.data()); - // fallthrough - case Oversampling::x4: - upsampler4x.resize(numChannels); - for (auto& upsampler: upsampler4x) - upsampler.set_coefs(coeffsStage4x.data()); - // fallthrough - case Oversampling::x2: - upsampler2x.resize(numChannels); - for (auto& upsampler: upsampler2x) - upsampler.set_coefs(coeffsStage2x.data()); - break; - case Oversampling::x1: - break; - } - - // Intermediate buffers - sfz::Buffer buffer1 { chunkSize * 2 }; - sfz::Buffer buffer2 { chunkSize * 4 }; - auto span1 = absl::MakeSpan(buffer1); - auto span2 = absl::MakeSpan(buffer2); + // Intermediate buffer + sfz::Buffer temp { std::max(128, Upsampler::recommendedBuffer(16, chunkSize)) }; size_t inputFrameCounter { 0 }; size_t outputFrameCounter { 0 }; @@ -115,23 +44,10 @@ void sfz::Oversampler::stream(AudioSpan input, AudioSpan output, s for (size_t chanIdx = 0; chanIdx < numChannels; chanIdx++) { const auto inputChunk = input.getSpan(chanIdx).subspan(inputFrameCounter, thisChunkSize); const auto outputChunk = output.getSpan(chanIdx).subspan(outputFrameCounter, outputChunkSize); - switch (factor) { - case Oversampling::x1: - copy(inputChunk, outputChunk); - break; - case Oversampling::x2: - upsampler2x[chanIdx].process_block(outputChunk.data(), inputChunk.data(), static_cast(thisChunkSize)); - break; - case Oversampling::x4: - upsampler2x[chanIdx].process_block(span1.data(), inputChunk.data(), static_cast(thisChunkSize)); - upsampler4x[chanIdx].process_block(outputChunk.data(), span1.data(), static_cast(thisChunkSize * 2)); - break; - case Oversampling::x8: - upsampler2x[chanIdx].process_block(span1.data(), inputChunk.data(), static_cast(thisChunkSize)); - upsampler4x[chanIdx].process_block(span2.data(), span1.data(), static_cast(thisChunkSize * 2)); - upsampler8x[chanIdx].process_block(outputChunk.data(), span2.data(), static_cast(thisChunkSize * 4)); - break; - } + upsampler[chanIdx].process( + static_cast(factor), + inputChunk.data(), outputChunk.data(), static_cast(inputChunk.size()), + temp.data(), static_cast(temp.size())); } inputFrameCounter += thisChunkSize; outputFrameCounter += outputChunkSize; @@ -149,47 +65,18 @@ void sfz::Oversampler::stream(AudioReader& input, AudioSpan output, std:: const auto numFrames = static_cast(input.frames()); const auto numChannels = input.channels(); - aligned_vector upsampler2x; - aligned_vector upsampler4x; - aligned_vector upsampler8x; - - switch(factor) - { - case Oversampling::x8: - upsampler8x.resize(numChannels); - for (auto& upsampler: upsampler8x) - upsampler.set_coefs(coeffsStage8x.data()); - // fallthrough - case Oversampling::x4: - upsampler4x.resize(numChannels); - for (auto& upsampler: upsampler4x) - upsampler.set_coefs(coeffsStage4x.data()); - // fallthrough - case Oversampling::x2: - upsampler2x.resize(numChannels); - for (auto& upsampler: upsampler2x) - upsampler.set_coefs(coeffsStage2x.data()); - break; - case Oversampling::x1: - break; - } + aligned_vector upsampler(numChannels); // Intermediate buffers sfz::Buffer fileBlock { chunkSize * numChannels }; - sfz::Buffer buffer1 { chunkSize * 2 }; - sfz::Buffer buffer2 { chunkSize * 4 }; - auto span1 = absl::MakeSpan(buffer1); - auto span2 = absl::MakeSpan(buffer2); + sfz::Buffer channelBlock { chunkSize }; + sfz::Buffer temp { std::max(128, Upsampler::recommendedBuffer(16, chunkSize)) }; - auto upsample2xFromInterleaved = [numChannels]( - Upsampler2x& upsampler, float* output, const float* input, - size_t numInputFrames, unsigned chanIdx) + auto deinterleave = [numChannels]( + float* output, const float* input, size_t numFrames, unsigned chanIdx) { - for (size_t i = 0; i < numInputFrames; ++i) { - float* outp = &output[2 * i]; - const float* inp = &input[i * numChannels + chanIdx]; - upsampler.process_sample(outp[0], outp[1], inp[0]); - } + for (size_t i = 0; i < numFrames; ++i) + output[i] = input[i * numChannels + chanIdx]; }; size_t inputFrameCounter { 0 }; @@ -211,23 +98,15 @@ void sfz::Oversampler::stream(AudioReader& input, AudioSpan output, std:: for (size_t chanIdx = 0; chanIdx < numChannels; chanIdx++) { const auto outputChunk = output.getSpan(chanIdx).subspan(outputFrameCounter, outputChunkSize); - switch (factor) { - case Oversampling::x1: - for (size_t i = 0; i < thisChunkSize; ++i) - outputChunk[i] = fileBlock[i * numChannels + chanIdx]; - break; - case Oversampling::x2: - upsample2xFromInterleaved(upsampler2x[chanIdx], outputChunk.data(), fileBlock.data(), thisChunkSize, chanIdx); - break; - case Oversampling::x4: - upsample2xFromInterleaved(upsampler2x[chanIdx], span1.data(), fileBlock.data(), thisChunkSize, chanIdx); - upsampler4x[chanIdx].process_block(outputChunk.data(), span1.data(), static_cast(thisChunkSize * 2)); - break; - case Oversampling::x8: - upsample2xFromInterleaved(upsampler2x[chanIdx], span1.data(), fileBlock.data(), thisChunkSize, chanIdx); - upsampler4x[chanIdx].process_block(span2.data(), span1.data(), static_cast(thisChunkSize * 2)); - upsampler8x[chanIdx].process_block(outputChunk.data(), span2.data(), static_cast(thisChunkSize * 4)); - break; + + if (factor == Oversampling::x1) + deinterleave(outputChunk.data(), fileBlock.data(), thisChunkSize, chanIdx); + else { + deinterleave(channelBlock.data(), fileBlock.data(), thisChunkSize, chanIdx); + upsampler[chanIdx].process( + static_cast(factor), + channelBlock.data(), outputChunk.data(), static_cast(thisChunkSize), + temp.data(), static_cast(temp.size())); } } inputFrameCounter += thisChunkSize;