From d6136b6bf9b0c5a6ea2133696da80b0488313fcf Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 22 Dec 2019 23:37:57 +0100 Subject: [PATCH] Refactor the filepool loading for streaming --- src/sfizz/FilePool.cpp | 71 ++++++++++++++++++++++++++++-------------- src/sfizz/FilePool.h | 6 ++-- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index e8bfe92c..a48e1515 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -35,31 +35,54 @@ #include using namespace std::chrono_literals; +template +void readBaseFile(SndfileHandle& sndFile, sfz::AudioBuffer& 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 tempReadBuffer { 2 * numFrames }; + sndFile.readf(tempReadBuffer.data(), numFrames); + sfz::readInterleaved(tempReadBuffer, output.getSpan(0), output.getSpan(1)); + } +} + template std::unique_ptr> readFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor) { - auto baseBuffer = std::make_unique>(sndFile.channels(), numFrames); - if (sndFile.channels() == 1) { - sndFile.readf(baseBuffer->channelWriter(0), numFrames); - } else if (sndFile.channels() == 2) { - auto tempReadBuffer = std::make_unique>(2 * numFrames); - sndFile.readf(tempReadBuffer->data(), numFrames); - auto fileBuffer = std::make_unique>(2, numFrames); - sfz::readInterleaved(*tempReadBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); + auto baseBuffer = std::make_unique>(); + readBaseFile(sndFile, *baseBuffer, numFrames); + + if (factor == sfz::Oversampling::x1) + return baseBuffer; + + auto outputBuffer = std::make_unique>(sndFile.channels(), numFrames * static_cast(factor)); + sfz::Oversampler oversampler { factor }; + oversampler.stream(*baseBuffer, *outputBuffer); + return outputBuffer; +} + +template +void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, sfz::AudioBuffer& output, std::atomic* filledFrames=nullptr) +{ + if (factor == sfz::Oversampling::x1) { + readBaseFile(sndFile, output, numFrames); + if (filledFrames != nullptr) + filledFrames->store(numFrames); + return; } - switch (factor) { - case sfz::Oversampling::x1: - return baseBuffer; - case sfz::Oversampling::x2: - return sfz::upsample2x(*baseBuffer); - case sfz::Oversampling::x4: - return sfz::upsample4x(*baseBuffer); - case sfz::Oversampling::x8: - return sfz::upsample8x(*baseBuffer); - default: - return {}; - } + auto baseBuffer = readFromFile(sndFile, numFrames, sfz::Oversampling::x1); + output.reset(); + output.addChannels(baseBuffer->getNumChannels()); + output.resize(numFrames * static_cast(factor)); + sfz::Oversampler oversampler { factor }; + oversampler.stream(*baseBuffer, output, filledFrames); } absl::optional sfz::FilePool::getFileInformation(const std::string& filename) noexcept @@ -115,7 +138,7 @@ bool sfz::FilePool::preloadFile(const std::string& filename, uint32_t maxOffset) } else { preloadedFiles.insert_or_assign(filename, { readFromFile(sndFile, framesToLoad, oversamplingFactor), - static_cast(sndFile.samplerate() * oversamplingFactor) + static_cast(oversamplingFactor) * sndFile.samplerate() }); } @@ -140,7 +163,7 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept { // Update all the preloaded sizes for (auto& preloadedFile : preloadedFiles) { - const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / oversamplingFactor; + const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / static_cast(oversamplingFactor); const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0; fs::path file { rootDirectory / std::string(preloadedFile.first) }; SndfileHandle sndFile(file.c_str()); @@ -194,7 +217,7 @@ void sfz::FilePool::loadingThread() noexcept DBG("Loading file for " << promise->filename << " in the background"); const uint32_t frames = sndFile.frames(); - promise->fileData = readFromFile(sndFile, frames, oversamplingFactor); + streamFromFile(sndFile, frames, oversamplingFactor, promise->fileData, &promise->availableFrames); promise->dataReady = true; threadsLoading--; @@ -246,7 +269,7 @@ void sfz::FilePool::setOversamplingFactor(sfz::Oversampling factor) noexcept { float samplerateChange { static_cast(factor) / static_cast(this->oversamplingFactor) }; for (auto& preloadedFile : preloadedFiles) { - const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / this->oversamplingFactor; + const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / static_cast(this->oversamplingFactor); const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0; fs::path file { rootDirectory / std::string(preloadedFile.first) }; SndfileHandle sndFile(file.c_str()); diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 725b7814..b97ee776 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -51,16 +51,16 @@ struct FilePromise auto getData() { if (dataReady) - return AudioSpan(*fileData); + return AudioSpan(fileData); else if (availableFrames > preloadedData->getNumFrames()) - return AudioSpan(*fileData).first(availableFrames); + return AudioSpan(fileData).first(availableFrames); else return AudioSpan(*preloadedData); } absl::string_view filename {}; AudioBufferPtr preloadedData {}; - std::unique_ptr> fileData {}; + AudioBuffer fileData {}; float sampleRate { config::defaultSampleRate }; std::atomic_size_t availableFrames { 0 }; std::atomic dataReady { false };