Implement sfizz oversampler using new code

This commit is contained in:
Jean Pierre Cimalando 2021-02-15 15:25:50 +01:00
parent 090619cfa4
commit 4b6497272d

View file

@ -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 <class T, std::size_t A = sfz::config::defaultAlignment>
using aligned_vector = std::vector<T, jsl::aligned_allocator<T, A>>;
constexpr std::array<double, 12> 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<double, 4> coeffsStage4x {
0.042448989488488006,
0.17072114107630679,
0.39329183835224008,
0.74569514831986694
};
constexpr std::array<double, 3> coeffsStage8x {
0.055748680811302048,
0.24305119574153092,
0.6466991311926823
};
#if SFIZZ_HAVE_SSE
#include "hiir/Upsampler2xSse.h"
using Upsampler2x = hiir::Upsampler2xSse<coeffsStage2x.size()>;
using Upsampler4x = hiir::Upsampler2xSse<coeffsStage4x.size()>;
using Upsampler8x = hiir::Upsampler2xSse<coeffsStage8x.size()>;
#elif SFIZZ_HAVE_NEON
#include "hiir/Upsampler2xNeon.h"
using Upsampler2x = hiir::Upsampler2xNeon<coeffsStage2x.size()>;
using Upsampler4x = hiir::Upsampler2xNeon<coeffsStage4x.size()>;
using Upsampler8x = hiir::Upsampler2xNeon<coeffsStage8x.size()>;
#else
#include "hiir/Upsampler2xFpu.h"
using Upsampler2x = hiir::Upsampler2xFpu<coeffsStage2x.size()>;
using Upsampler4x = hiir::Upsampler2xFpu<coeffsStage4x.size()>;
using Upsampler8x = hiir::Upsampler2xFpu<coeffsStage8x.size()>;
#endif
sfz::Oversampler::Oversampler(sfz::Oversampling factor, size_t chunkSize)
: factor(factor), chunkSize(chunkSize)
{
@ -74,36 +29,10 @@ void sfz::Oversampler::stream(AudioSpan<float> input, AudioSpan<float> output, s
const auto numFrames = input.getNumFrames();
const auto numChannels = input.getNumChannels();
aligned_vector<Upsampler2x> upsampler2x;
aligned_vector<Upsampler4x> upsampler4x;
aligned_vector<Upsampler8x> upsampler8x;
aligned_vector<Upsampler> 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<float> buffer1 { chunkSize * 2 };
sfz::Buffer<float> buffer2 { chunkSize * 4 };
auto span1 = absl::MakeSpan(buffer1);
auto span2 = absl::MakeSpan(buffer2);
// Intermediate buffer
sfz::Buffer<float> temp { std::max<size_t>(128, Upsampler::recommendedBuffer(16, chunkSize)) };
size_t inputFrameCounter { 0 };
size_t outputFrameCounter { 0 };
@ -115,23 +44,10 @@ void sfz::Oversampler::stream(AudioSpan<float> input, AudioSpan<float> 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<float>(inputChunk, outputChunk);
break;
case Oversampling::x2:
upsampler2x[chanIdx].process_block(outputChunk.data(), inputChunk.data(), static_cast<long>(thisChunkSize));
break;
case Oversampling::x4:
upsampler2x[chanIdx].process_block(span1.data(), inputChunk.data(), static_cast<long>(thisChunkSize));
upsampler4x[chanIdx].process_block(outputChunk.data(), span1.data(), static_cast<long>(thisChunkSize * 2));
break;
case Oversampling::x8:
upsampler2x[chanIdx].process_block(span1.data(), inputChunk.data(), static_cast<long>(thisChunkSize));
upsampler4x[chanIdx].process_block(span2.data(), span1.data(), static_cast<long>(thisChunkSize * 2));
upsampler8x[chanIdx].process_block(outputChunk.data(), span2.data(), static_cast<long>(thisChunkSize * 4));
break;
}
upsampler[chanIdx].process(
static_cast<int>(factor),
inputChunk.data(), outputChunk.data(), static_cast<int>(inputChunk.size()),
temp.data(), static_cast<int>(temp.size()));
}
inputFrameCounter += thisChunkSize;
outputFrameCounter += outputChunkSize;
@ -149,47 +65,18 @@ void sfz::Oversampler::stream(AudioReader& input, AudioSpan<float> output, std::
const auto numFrames = static_cast<size_t>(input.frames());
const auto numChannels = input.channels();
aligned_vector<Upsampler2x> upsampler2x;
aligned_vector<Upsampler4x> upsampler4x;
aligned_vector<Upsampler8x> 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> upsampler(numChannels);
// Intermediate buffers
sfz::Buffer<float> fileBlock { chunkSize * numChannels };
sfz::Buffer<float> buffer1 { chunkSize * 2 };
sfz::Buffer<float> buffer2 { chunkSize * 4 };
auto span1 = absl::MakeSpan(buffer1);
auto span2 = absl::MakeSpan(buffer2);
sfz::Buffer<float> channelBlock { chunkSize };
sfz::Buffer<float> temp { std::max<size_t>(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<float> 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<long>(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<long>(thisChunkSize * 2));
upsampler8x[chanIdx].process_block(outputChunk.data(), span2.data(), static_cast<long>(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<int>(factor),
channelBlock.data(), outputChunk.data(), static_cast<int>(thisChunkSize),
temp.data(), static_cast<int>(temp.size()));
}
}
inputFrameCounter += thisChunkSize;