Refactor the filepool loading for streaming

This commit is contained in:
Paul Ferrand 2019-12-22 23:37:57 +01:00
parent 9d53878873
commit d6136b6bf9
2 changed files with 50 additions and 27 deletions

View file

@ -35,31 +35,54 @@
#include <thread> #include <thread>
using namespace std::chrono_literals; using namespace std::chrono_literals;
template <class T>
void readBaseFile(SndfileHandle& sndFile, sfz::AudioBuffer<T>& output, uint32_t numFrames)
{
output.reset();
output.resize(numFrames);
if (sndFile.channels() == 1) {
output.addChannel();
sndFile.readf(output.channelWriter(0), numFrames);
} else if (sndFile.channels() == 2) {
output.addChannel();
output.addChannel();
sfz::Buffer<T> tempReadBuffer { 2 * numFrames };
sndFile.readf(tempReadBuffer.data(), numFrames);
sfz::readInterleaved<T>(tempReadBuffer, output.getSpan(0), output.getSpan(1));
}
}
template <class T> template <class T>
std::unique_ptr<sfz::AudioBuffer<T>> readFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor) std::unique_ptr<sfz::AudioBuffer<T>> readFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor)
{ {
auto baseBuffer = std::make_unique<sfz::AudioBuffer<T>>(sndFile.channels(), numFrames); auto baseBuffer = std::make_unique<sfz::AudioBuffer<T>>();
if (sndFile.channels() == 1) { readBaseFile(sndFile, *baseBuffer, numFrames);
sndFile.readf(baseBuffer->channelWriter(0), numFrames);
} else if (sndFile.channels() == 2) { if (factor == sfz::Oversampling::x1)
auto tempReadBuffer = std::make_unique<sfz::Buffer<T>>(2 * numFrames); return baseBuffer;
sndFile.readf(tempReadBuffer->data(), numFrames);
auto fileBuffer = std::make_unique<sfz::AudioBuffer<T>>(2, numFrames); auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(sndFile.channels(), numFrames * static_cast<int>(factor));
sfz::readInterleaved<T>(*tempReadBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); sfz::Oversampler oversampler { factor };
oversampler.stream(*baseBuffer, *outputBuffer);
return outputBuffer;
}
template <class T>
void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, sfz::AudioBuffer<float>& output, std::atomic<size_t>* filledFrames=nullptr)
{
if (factor == sfz::Oversampling::x1) {
readBaseFile(sndFile, output, numFrames);
if (filledFrames != nullptr)
filledFrames->store(numFrames);
return;
} }
switch (factor) { auto baseBuffer = readFromFile<T>(sndFile, numFrames, sfz::Oversampling::x1);
case sfz::Oversampling::x1: output.reset();
return baseBuffer; output.addChannels(baseBuffer->getNumChannels());
case sfz::Oversampling::x2: output.resize(numFrames * static_cast<int>(factor));
return sfz::upsample2x(*baseBuffer); sfz::Oversampler oversampler { factor };
case sfz::Oversampling::x4: oversampler.stream(*baseBuffer, output, filledFrames);
return sfz::upsample4x(*baseBuffer);
case sfz::Oversampling::x8:
return sfz::upsample8x(*baseBuffer);
default:
return {};
}
} }
absl::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(const std::string& filename) noexcept absl::optional<sfz::FilePool::FileInformation> sfz::FilePool::getFileInformation(const std::string& filename) noexcept
@ -115,7 +138,7 @@ bool sfz::FilePool::preloadFile(const std::string& filename, uint32_t maxOffset)
} else { } else {
preloadedFiles.insert_or_assign(filename, { preloadedFiles.insert_or_assign(filename, {
readFromFile<float>(sndFile, framesToLoad, oversamplingFactor), readFromFile<float>(sndFile, framesToLoad, oversamplingFactor),
static_cast<float>(sndFile.samplerate() * oversamplingFactor) static_cast<float>(oversamplingFactor) * sndFile.samplerate()
}); });
} }
@ -140,7 +163,7 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept
{ {
// Update all the preloaded sizes // Update all the preloaded sizes
for (auto& preloadedFile : preloadedFiles) { for (auto& preloadedFile : preloadedFiles) {
const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / oversamplingFactor; const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / static_cast<int>(oversamplingFactor);
const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0; const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0;
fs::path file { rootDirectory / std::string(preloadedFile.first) }; fs::path file { rootDirectory / std::string(preloadedFile.first) };
SndfileHandle sndFile(file.c_str()); SndfileHandle sndFile(file.c_str());
@ -194,7 +217,7 @@ void sfz::FilePool::loadingThread() noexcept
DBG("Loading file for " << promise->filename << " in the background"); DBG("Loading file for " << promise->filename << " in the background");
const uint32_t frames = sndFile.frames(); const uint32_t frames = sndFile.frames();
promise->fileData = readFromFile<float>(sndFile, frames, oversamplingFactor); streamFromFile<float>(sndFile, frames, oversamplingFactor, promise->fileData, &promise->availableFrames);
promise->dataReady = true; promise->dataReady = true;
threadsLoading--; threadsLoading--;
@ -246,7 +269,7 @@ void sfz::FilePool::setOversamplingFactor(sfz::Oversampling factor) noexcept
{ {
float samplerateChange { static_cast<float>(factor) / static_cast<float>(this->oversamplingFactor) }; float samplerateChange { static_cast<float>(factor) / static_cast<float>(this->oversamplingFactor) };
for (auto& preloadedFile : preloadedFiles) { for (auto& preloadedFile : preloadedFiles) {
const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / this->oversamplingFactor; const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / static_cast<int>(this->oversamplingFactor);
const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0; const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0;
fs::path file { rootDirectory / std::string(preloadedFile.first) }; fs::path file { rootDirectory / std::string(preloadedFile.first) };
SndfileHandle sndFile(file.c_str()); SndfileHandle sndFile(file.c_str());

View file

@ -51,16 +51,16 @@ struct FilePromise
auto getData() auto getData()
{ {
if (dataReady) if (dataReady)
return AudioSpan<const float>(*fileData); return AudioSpan<const float>(fileData);
else if (availableFrames > preloadedData->getNumFrames()) else if (availableFrames > preloadedData->getNumFrames())
return AudioSpan<const float>(*fileData).first(availableFrames); return AudioSpan<const float>(fileData).first(availableFrames);
else else
return AudioSpan<const float>(*preloadedData); return AudioSpan<const float>(*preloadedData);
} }
absl::string_view filename {}; absl::string_view filename {};
AudioBufferPtr preloadedData {}; AudioBufferPtr preloadedData {};
std::unique_ptr<AudioBuffer<float>> fileData {}; AudioBuffer<float> fileData {};
float sampleRate { config::defaultSampleRate }; float sampleRate { config::defaultSampleRate };
std::atomic_size_t availableFrames { 0 }; std::atomic_size_t availableFrames { 0 };
std::atomic<bool> dataReady { false }; std::atomic<bool> dataReady { false };