Eliminate excessFileFrames from FilePool, use fixed padding buffer

This commit is contained in:
Jean Pierre Cimalando 2020-06-11 03:12:31 +02:00
parent dd5d11f4a3
commit c94eea2a3f
2 changed files with 29 additions and 41 deletions

View file

@ -39,11 +39,10 @@
#include <sndfile.hh> #include <sndfile.hh>
#include <thread> #include <thread>
template <class T> void readBaseFile(SndfileHandle& sndFile, sfz::FileAudioBuffer& output, uint32_t numFrames, bool reverse)
void readBaseFile(SndfileHandle& sndFile, sfz::AudioBuffer<T>& output, uint32_t numFrames, bool reverse)
{ {
output.reset(); output.reset();
output.resize(numFrames + 2 * sfz::config::excessFileFrames); output.resize(numFrames);
if (reverse) if (reverse)
sndFile.seek(-static_cast<sf_count_t>(numFrames), SEEK_END); sndFile.seek(-static_cast<sf_count_t>(numFrames), SEEK_END);
@ -53,48 +52,42 @@ void readBaseFile(SndfileHandle& sndFile, sfz::AudioBuffer<T>& output, uint32_t
if (channels == 1) { if (channels == 1) {
output.addChannel(); output.addChannel();
output.clear(); output.clear();
sndFile.readf(output.channelWriter(0) + sfz::config::excessFileFrames, numFrames); sndFile.readf(output.channelWriter(0), numFrames);
} else if (channels == 2) { } else if (channels == 2) {
output.addChannel(); output.addChannel();
output.addChannel(); output.addChannel();
output.clear(); output.clear();
sfz::Buffer<T> tempReadBuffer { 2 * numFrames }; sfz::Buffer<float> tempReadBuffer { 2 * numFrames };
sndFile.readf(tempReadBuffer.data(), numFrames); sndFile.readf(tempReadBuffer.data(), numFrames);
sfz::readInterleaved<T>(tempReadBuffer, sfz::readInterleaved<float>(tempReadBuffer, output.getSpan(0), output.getSpan(1));
output.getSpan(0).subspan(sfz::config::excessFileFrames, numFrames),
output.getSpan(1).subspan(sfz::config::excessFileFrames, numFrames)
);
} }
if (reverse) { if (reverse) {
for (unsigned c = 0; c < channels; ++c) { for (unsigned c = 0; c < channels; ++c) {
// TODO: consider optimizing with SIMD // TODO: consider optimizing with SIMD
absl::Span<float> channel = output.getSpan(c).subspan(sfz::config::excessFileFrames, numFrames); absl::Span<float> channel = output.getSpan(c);
std::reverse(channel.begin(), channel.end()); std::reverse(channel.begin(), channel.end());
} }
} }
} }
template <class T> std::unique_ptr<sfz::FileAudioBuffer> readFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse)
std::unique_ptr<sfz::AudioBuffer<T>> readFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse)
{ {
auto baseBuffer = absl::make_unique<sfz::AudioBuffer<T>>(); auto baseBuffer = absl::make_unique<sfz::FileAudioBuffer>();
readBaseFile(sndFile, *baseBuffer, numFrames, reverse); readBaseFile(sndFile, *baseBuffer, numFrames, reverse);
if (factor == sfz::Oversampling::x1) if (factor == sfz::Oversampling::x1)
return baseBuffer; return baseBuffer;
auto outputBuffer = absl::make_unique<sfz::AudioBuffer<T>>(sndFile.channels(), numFrames * static_cast<int>(factor) + 2 * sfz::config::excessFileFrames); auto outputBuffer = absl::make_unique<sfz::FileAudioBuffer>(sndFile.channels(), numFrames * static_cast<int>(factor));
outputBuffer->clear(); 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 }; sfz::Oversampler oversampler { factor };
oversampler.stream(baseSpan, outputSpan); oversampler.stream(*baseBuffer, *outputBuffer);
return outputBuffer; return outputBuffer;
} }
template <class T> template <class T>
void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse, sfz::AudioBuffer<float>& output, std::atomic<size_t>* filledFrames = nullptr) void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse, sfz::FileAudioBuffer& output, std::atomic<size_t>* filledFrames = nullptr)
{ {
if (factor == sfz::Oversampling::x1) { if (factor == sfz::Oversampling::x1) {
readBaseFile(sndFile, output, numFrames, reverse); readBaseFile(sndFile, output, numFrames, reverse);
@ -103,15 +96,13 @@ void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversamplin
return; return;
} }
auto baseBuffer = readFromFile<T>(sndFile, numFrames, sfz::Oversampling::x1, reverse); auto baseBuffer = readFromFile(sndFile, numFrames, sfz::Oversampling::x1, reverse);
output.reset(); output.reset();
output.addChannels(baseBuffer->getNumChannels()); output.addChannels(baseBuffer->getNumChannels());
output.resize(numFrames * static_cast<int>(factor) + 2 * sfz::config::excessFileFrames); output.resize(numFrames * static_cast<int>(factor));
output.clear(); output.clear();
sfz::Oversampler oversampler { factor }; sfz::Oversampler oversampler { factor };
auto baseSpan = sfz::AudioSpan<T>(*baseBuffer).subspan(sfz::config::excessFileFrames, numFrames); oversampler.stream(*baseBuffer, output, filledFrames);
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) sfz::FilePool::FilePool(sfz::Logger& logger)
@ -272,12 +263,12 @@ bool sfz::FilePool::preloadFile(const FileId& fileId, uint32_t maxOffset) noexce
const auto existingFile = preloadedFiles.find(fileId); const auto existingFile = preloadedFiles.find(fileId);
if (existingFile != preloadedFiles.end()) { if (existingFile != preloadedFiles.end()) {
if (framesToLoad > existingFile->second.preloadedData->getNumFrames()) { if (framesToLoad > existingFile->second.preloadedData->getNumFrames()) {
preloadedFiles[fileId].preloadedData = readFromFile<float>(sndFile, framesToLoad, oversamplingFactor, fileId.isReverse()); preloadedFiles[fileId].preloadedData = readFromFile(sndFile, framesToLoad, oversamplingFactor, fileId.isReverse());
} }
} else { } else {
fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate()); fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate());
FileDataHandle handle { FileDataHandle handle {
readFromFile<float>(sndFile, framesToLoad, oversamplingFactor, fileId.isReverse()), readFromFile(sndFile, framesToLoad, oversamplingFactor, fileId.isReverse()),
*fileInformation *fileInformation
}; };
preloadedFiles.insert_or_assign(fileId, handle); preloadedFiles.insert_or_assign(fileId, handle);
@ -302,7 +293,7 @@ absl::optional<sfz::FileDataHandle> sfz::FilePool::loadFile(const FileId& fileId
} else { } else {
fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate()); fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate());
FileDataHandle handle { FileDataHandle handle {
readFromFile<float>(sndFile, frames, oversamplingFactor, fileId.isReverse()), readFromFile(sndFile, frames, oversamplingFactor, fileId.isReverse()),
*fileInformation *fileInformation
}; };
loadedFiles.insert_or_assign(fileId, handle); loadedFiles.insert_or_assign(fileId, handle);
@ -352,7 +343,7 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept
const auto maxOffset = numFrames > this->preloadSize ? static_cast<uint32_t>(numFrames) - this->preloadSize : 0; const auto maxOffset = numFrames > this->preloadSize ? static_cast<uint32_t>(numFrames) - this->preloadSize : 0;
fs::path file { rootDirectory / preloadedFile.first.filename() }; fs::path file { rootDirectory / preloadedFile.first.filename() };
SndfileHandle sndFile(file.string().c_str()); SndfileHandle sndFile(file.string().c_str());
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, oversamplingFactor, preloadedFile.first.isReverse()); preloadedFile.second.preloadedData = readFromFile(sndFile, preloadSize + maxOffset, oversamplingFactor, preloadedFile.first.isReverse());
} }
this->preloadSize = preloadSize; this->preloadSize = preloadSize;
} }
@ -481,7 +472,7 @@ void sfz::FilePool::setOversamplingFactor(sfz::Oversampling factor) noexcept
const uint32_t maxOffset = numFrames > this->preloadSize ? static_cast<uint32_t>(numFrames) - this->preloadSize : 0; const uint32_t maxOffset = numFrames > this->preloadSize ? static_cast<uint32_t>(numFrames) - this->preloadSize : 0;
fs::path file { rootDirectory / preloadedFile.first.filename() }; fs::path file { rootDirectory / preloadedFile.first.filename() };
SndfileHandle sndFile(file.string().c_str()); SndfileHandle sndFile(file.string().c_str());
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, factor, preloadedFile.first.isReverse()); preloadedFile.second.preloadedData = readFromFile(sndFile, preloadSize + maxOffset, factor, preloadedFile.first.isReverse());
preloadedFile.second.information.sampleRate *= samplerateChange; preloadedFile.second.information.sampleRate *= samplerateChange;
} }

View file

@ -43,7 +43,9 @@
#include <mutex> #include <mutex>
namespace sfz { namespace sfz {
using AudioBufferPtr = std::shared_ptr<AudioBuffer<float>>; using FileAudioBuffer = AudioBuffer<float, 2, SIMDConfig::defaultAlignment,
sfz::config::excessFileFrames, sfz::config::excessFileFrames>;
using FileAudioBufferPtr = std::shared_ptr<FileAudioBuffer>;
struct FileInformation { struct FileInformation {
uint32_t end { Default::sampleEndRange.getEnd() }; uint32_t end { Default::sampleEndRange.getEnd() };
@ -56,7 +58,7 @@ struct FileInformation {
// Strict C++11 disallows member initialization if aggregate initialization is to be used... // Strict C++11 disallows member initialization if aggregate initialization is to be used...
struct FileDataHandle struct FileDataHandle
{ {
std::shared_ptr<AudioBuffer<float>> preloadedData; FileAudioBufferPtr preloadedData;
FileInformation information; FileInformation information;
}; };
@ -65,16 +67,11 @@ struct FilePromise
AudioSpan<const float> getData() AudioSpan<const float> getData()
{ {
if (dataStatus == DataStatus::Ready) if (dataStatus == DataStatus::Ready)
return AudioSpan<const float>(fileData) return AudioSpan<const float>(fileData);
.subspan(sfz::config::excessFileFrames, else if (availableFrames > preloadedData->getNumFrames())
fileData.getNumFrames() - 2 * sfz::config::excessFileFrames); return AudioSpan<const float>(fileData).first(availableFrames);
else if (availableFrames > preloadedData->getNumFrames() + sfz::config::excessFileFrames)
return AudioSpan<const float>(fileData)
.subspan(sfz::config::excessFileFrames, availableFrames - sfz::config::excessFileFrames);
else else
return AudioSpan<const float>(*preloadedData) return AudioSpan<const float>(*preloadedData);
.subspan(sfz::config::excessFileFrames,
preloadedData->getNumFrames() - 2 * sfz::config::excessFileFrames);
} }
void reset() void reset()
@ -101,8 +98,8 @@ struct FilePromise
}; };
FileId fileId {}; FileId fileId {};
AudioBufferPtr preloadedData {}; FileAudioBufferPtr preloadedData {};
AudioBuffer<float> fileData {}; FileAudioBuffer fileData {};
float sampleRate { config::defaultSampleRate }; float sampleRate { config::defaultSampleRate };
Oversampling oversamplingFactor { config::defaultOversamplingFactor }; Oversampling oversamplingFactor { config::defaultOversamplingFactor };
std::atomic<size_t> availableFrames { 0 }; std::atomic<size_t> availableFrames { 0 };