Add excessFileFrames at the beginning of the file dataRecenter the 4-sample splines from -1 to 2 (relative to the interpolated sample) rather than 0 to 3

This commit is contained in:
Paul Ferrand 2020-05-28 23:34:48 +02:00 committed by Jean Pierre Cimalando
parent c48e14ee2b
commit 590af85823
6 changed files with 44 additions and 19 deletions

View file

@ -27,6 +27,7 @@
#include "FileInstrument.h"
#include "Buffer.h"
#include "AudioBuffer.h"
#include "AudioSpan.h"
#include "Config.h"
#include "Debug.h"
#include "Oversampler.h"
@ -42,7 +43,7 @@ template <class T>
void readBaseFile(SndfileHandle& sndFile, sfz::AudioBuffer<T>& output, uint32_t numFrames, bool reverse)
{
output.reset();
output.resize(numFrames + sfz::config::excessFileFrames);
output.resize(numFrames + 2 * sfz::config::excessFileFrames);
if (reverse)
sndFile.seek(-static_cast<sf_count_t>(numFrames), SEEK_END);
@ -52,20 +53,23 @@ void readBaseFile(SndfileHandle& sndFile, sfz::AudioBuffer<T>& output, uint32_t
if (channels == 1) {
output.addChannel();
output.clear();
sndFile.readf(output.channelWriter(0), numFrames);
sndFile.readf(output.channelWriter(0) + sfz::config::excessFileFrames, numFrames);
} else if (channels == 2) {
output.addChannel();
output.addChannel();
output.clear();
sfz::Buffer<T> tempReadBuffer { 2 * numFrames };
sndFile.readf(tempReadBuffer.data(), numFrames);
sfz::readInterleaved<T>(tempReadBuffer, output.getSpan(0).first(numFrames), output.getSpan(1).first(numFrames));
sfz::readInterleaved<T>(tempReadBuffer,
output.getSpan(0).subspan(sfz::config::excessFileFrames, numFrames),
output.getSpan(1).subspan(sfz::config::excessFileFrames, numFrames)
);
}
if (reverse) {
for (unsigned c = 0; c < channels; ++c) {
// TODO: consider optimizing with SIMD
absl::Span<float> channel = output.getSpan(c).first(numFrames);
absl::Span<float> channel = output.getSpan(c).subspan(sfz::config::excessFileFrames, numFrames);
std::reverse(channel.begin(), channel.end());
}
}
@ -80,10 +84,12 @@ std::unique_ptr<sfz::AudioBuffer<T>> readFromFile(SndfileHandle& sndFile, uint32
if (factor == sfz::Oversampling::x1)
return baseBuffer;
auto outputBuffer = absl::make_unique<sfz::AudioBuffer<T>>(sndFile.channels(), numFrames * static_cast<int>(factor) + sfz::config::excessFileFrames);
auto outputBuffer = absl::make_unique<sfz::AudioBuffer<T>>(sndFile.channels(), numFrames * static_cast<int>(factor) + 2 * sfz::config::excessFileFrames);
outputBuffer->clear();
auto baseSpan = sfz::AudioSpan<T>(*baseBuffer).subspan(sfz::config::excessFileFrames, numFrames);
auto outputSpan = sfz::AudioSpan<T>(*outputBuffer).subspan(sfz::config::excessFileFrames, numFrames * static_cast<int>(factor));
sfz::Oversampler oversampler { factor };
oversampler.stream(*baseBuffer, *outputBuffer);
oversampler.stream(baseSpan, outputSpan);
return outputBuffer;
}
@ -100,10 +106,12 @@ void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversamplin
auto baseBuffer = readFromFile<T>(sndFile, numFrames, sfz::Oversampling::x1, reverse);
output.reset();
output.addChannels(baseBuffer->getNumChannels());
output.resize(numFrames * static_cast<int>(factor) + sfz::config::excessFileFrames);
output.resize(numFrames * static_cast<int>(factor) + 2 * sfz::config::excessFileFrames);
output.clear();
sfz::Oversampler oversampler { factor };
oversampler.stream(*baseBuffer, output, filledFrames);
auto baseSpan = sfz::AudioSpan<T>(*baseBuffer).subspan(sfz::config::excessFileFrames, numFrames);
auto outputSpan = sfz::AudioSpan<T>(output).subspan(sfz::config::excessFileFrames, numFrames * static_cast<int>(factor));
oversampler.stream(baseSpan, outputSpan, filledFrames);
}
sfz::FilePool::FilePool(sfz::Logger& logger)

View file

@ -66,11 +66,14 @@ struct FilePromise
{
if (dataStatus == DataStatus::Ready)
return AudioSpan<const float>(fileData)
.first(fileData.getNumFrames() - sfz::config::excessFileFrames);
.subspan(sfz::config::excessFileFrames,
fileData.getNumFrames() - 2 * sfz::config::excessFileFrames);
else if (availableFrames > preloadedData->getNumFrames())
return AudioSpan<const float>(fileData).first(availableFrames);
return AudioSpan<const float>(fileData).subspan(sfz::config::excessFileFrames, availableFrames);
else
return AudioSpan<const float>(*preloadedData);
return AudioSpan<const float>(*preloadedData)
.subspan(sfz::config::excessFileFrames,
preloadedData->getNumFrames() - sfz::config::excessFileFrames);
}
void reset()

View file

@ -17,6 +17,19 @@ enum InterpolatorModel : int {
kInterpolatorBspline3,
};
/**
* @brief Interpolate from a vector of values
*
* @tparam M the interpolator model
* @tparam R the sample type
* @param values Pointer to a value in a larger vector of values.
* Depending on the interpolator the algorithm may
* read samples before and after. Usually you need
* to ensure that you have order - 1 samples available
* before and after the pointer, padding if necessary.
* @param coeff the interpolation coefficient
* @return R
*/
template <InterpolatorModel M, class R>
R interpolate(const R* values, R coeff);

View file

@ -44,7 +44,7 @@ public:
{
__m128 x = _mm_sub_ps(_mm_setr_ps(-1, 0, 1, 2), _mm_set1_ps(coeff));
__m128 h = hermite3x4(x);
__m128 y = _mm_mul_ps(h, _mm_loadu_ps(values));
__m128 y = _mm_mul_ps(h, _mm_loadu_ps(values - 1));
// sum 4 to 1
__m128 xmm0 = y;
__m128 xmm1 = _mm_shuffle_ps(xmm0, xmm0, 0xe5);
@ -68,8 +68,8 @@ public:
static inline R process(const R* values, R coeff)
{
R y = 0;
for (int i = 0; i < 4; ++i) {
R h = hermite3<R>(i - 1 - coeff);
for (int i = -1; i < 3; ++i) {
R h = hermite3<R>(i - coeff);
y += h * values[i];
}
return y;
@ -88,7 +88,7 @@ public:
{
__m128 x = _mm_sub_ps(_mm_setr_ps(-1, 0, 1, 2), _mm_set1_ps(coeff));
__m128 h = bspline3x4(x);
__m128 y = _mm_mul_ps(h, _mm_loadu_ps(values));
__m128 y = _mm_mul_ps(h, _mm_loadu_ps(values - 1));
// sum 4 to 1
__m128 xmm0 = y;
__m128 xmm1 = _mm_shuffle_ps(xmm0, xmm0, 0xe5);
@ -112,8 +112,8 @@ public:
static inline R process(const R* values, R coeff)
{
R y = 0;
for (int i = 0; i < 4; ++i) {
R h = bspline3<R>(i - 1 - coeff);
for (int i = -1; i < 3; ++i) {
R h = bspline3<R>(i - coeff);
y += h * values[i];
}
return y;

View file

@ -61,7 +61,7 @@ sfz::Oversampler::Oversampler(sfz::Oversampling factor, size_t chunkSize)
}
void sfz::Oversampler::stream(const sfz::AudioBuffer<float>& input, sfz::AudioBuffer<float>& output, std::atomic<size_t>* framesReady)
void sfz::Oversampler::stream(AudioSpan<float> input, AudioSpan<float> output, std::atomic<size_t>* framesReady)
{
ASSERT(output.getNumFrames() >= input.getNumFrames() * static_cast<int>(factor));
ASSERT(output.getNumChannels() == input.getNumChannels());

View file

@ -11,6 +11,7 @@
#include "Debug.h"
#include "Buffer.h"
#include "AudioBuffer.h"
#include "AudioSpan.h"
#include "Config.h"
namespace sfz {
@ -39,7 +40,7 @@ public:
* @param output
* @param framesReady an atomic counter for the ready frames. If null no signaling is done.
*/
void stream(const AudioBuffer<float>& input, AudioBuffer<float>& output, std::atomic<size_t>* framesReady = nullptr);
void stream(AudioSpan<float> input, AudioSpan<float> output, std::atomic<size_t>* framesReady = nullptr);
Oversampler() = delete;
Oversampler(const Oversampler&) = delete;