diff --git a/CMakeLists.txt b/CMakeLists.txt index 15666e19..3decff49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,10 @@ if (WIN32) target_include_directories(sndfile INTERFACE "${WIN_SNDFILE_PATH}/include") endif() +# Export MoodyCamel's queue as a library +add_library(readerwriterqueue INTERFACE) +target_include_directories(readerwriterqueue INTERFACE "external/readerwriterqueue") + # Export the compile_commands.json file set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -121,7 +125,7 @@ add_executable(sfizz sources/Main.cpp ${COMMON_SOURCES}) if(UNIX) target_link_libraries(sfizz stdc++fs) endif(UNIX) -target_link_libraries(sfizz absl::strings cxxopts sndfile absl::flat_hash_map) +target_link_libraries(sfizz absl::strings cxxopts sndfile absl::flat_hash_map readerwriterqueue) ############################### # Test application diff --git a/sources/FilePool.cpp b/sources/FilePool.cpp index eb335b1f..08bd6562 100644 --- a/sources/FilePool.cpp +++ b/sources/FilePool.cpp @@ -9,7 +9,7 @@ std::optional sfz::FilePool::getFileInformation( SndfileHandle sndFile ( reinterpret_cast(file.c_str()) ); FileInformation returnedValue; returnedValue.end = static_cast(sndFile.frames()); - + returnedValue.sampleRate = static_cast(sndFile.samplerate()); SF_INSTRUMENT instrumentInfo; sndFile.command(SFC_GET_INSTRUMENT, &instrumentInfo, sizeof(instrumentInfo)); @@ -27,4 +27,40 @@ std::optional sfz::FilePool::getFileInformation( // sndFile.command(SFC_GET_LOG_INFO, buffer, sizeof(buffer)) ; // DBG(buffer); return returnedValue; +} + +void sfz::FilePool::enqueueLoading(Voice* voice, std::string_view sample, int numFrames) +{ + if (!loadingQueue.try_enqueue({ voice, sample, numFrames })) + DBG("Problem enqueuing a file read for file " << sample); +} + +void sfz::FilePool::loadingThread() +{ + FileLoadingInformation fileToLoad; + while (true) + { + loadingQueue.wait_dequeue(fileToLoad); + if (fileToLoad.voice == nullptr) + { + DBG("Background thread error: voice is null."); + continue; + } + + DBG("Background loading of: " << fileToLoad.sample); + std::filesystem::path file { rootDirectory / fileToLoad.sample }; + if (!std::filesystem::exists(file)) + { + DBG("Background thread: no file " << fileToLoad.sample << " exists."); + continue; + } + + SndfileHandle sndFile ( reinterpret_cast(file.c_str()) ); + auto fileLoaded = std::make_unique>(fileToLoad.numFrames); + auto readBuffer = std::make_unique>(fileToLoad.numFrames * 2); + sndFile.readf(readBuffer->data(), fileToLoad.numFrames); + fileLoaded->readInterleaved(readBuffer->data(), fileToLoad.numFrames); + fileToLoad.voice->setFileData(std::move(fileLoaded)); + } + } \ No newline at end of file diff --git a/sources/FilePool.h b/sources/FilePool.h index 3ab962b7..04c2f373 100644 --- a/sources/FilePool.h +++ b/sources/FilePool.h @@ -1,19 +1,26 @@ #pragma once #include "StereoBuffer.h" #include "Defaults.h" +#include "Voice.h" #include #include #include #include #include #include +#include +#include namespace sfz { class FilePool { public: - FilePool() = default; + FilePool() + : fileLoadingThread(std::thread(&FilePool::loadingThread, this)) + { + + } void setRootDirectory(const std::filesystem::path& directory) { rootDirectory = directory; } size_t getNumPreloadedSamples() { return preloadedData.size(); } @@ -22,11 +29,22 @@ public: uint32_t end { Default::sampleEndRange.getEnd() }; uint32_t loopBegin { Default::loopRange.getStart() }; uint32_t loopEnd { Default::loopRange.getEnd() }; + double sampleRate { config::defaultSampleRate }; std::shared_ptr> preloadedData; }; std::optional getFileInformation(std::string_view filename); + void enqueueLoading(Voice* voice, std::string_view sample, int numFrames); private: std::filesystem::path rootDirectory; + struct FileLoadingInformation + { + Voice* voice; + std::string_view sample; + int numFrames; + }; + moodycamel::BlockingReaderWriterQueue loadingQueue; + void loadingThread(); + std::thread fileLoadingThread; Buffer tempReadBuffer { config::preloadSize * 2 }; // std::map>> preloadedData; absl::flat_hash_map>> preloadedData; diff --git a/sources/Synth.cpp b/sources/Synth.cpp index 188179df..f910e882 100644 --- a/sources/Synth.cpp +++ b/sources/Synth.cpp @@ -147,6 +147,7 @@ bool sfz::Synth::loadSfzFile(const std::filesystem::path& filename) region->sampleEnd = std::min(region->sampleEnd, fileInformation->end); region->loopRange.shrinkIfSmaller(fileInformation->loopBegin, fileInformation->loopEnd); region->preloadedData = fileInformation->preloadedData; + region->sampleRate = fileInformation->sampleRate; for (auto note = region->keyRange.getStart(); note <= region->keyRange.getEnd(); note++) noteActivationLists[note].push_back(*currentRegion); @@ -156,7 +157,7 @@ bool sfz::Synth::loadSfzFile(const std::filesystem::path& filename) currentRegion++; } - + DBG("Removed " << regions.size() - std::distance(regions.begin(), lastRegion) - 1 << " out of " << regions.size() << " regions."); regions.resize(std::distance(regions.begin(), lastRegion) + 1); return parserReturned; diff --git a/sources/Voice.h b/sources/Voice.h index 7fdb7ecc..0f7207a1 100644 --- a/sources/Voice.h +++ b/sources/Voice.h @@ -1,10 +1,20 @@ #pragma once +#include "StereoBuffer.h" +#include +#include namespace sfz { class Voice { public: + void setFileData(std::unique_ptr> file) + { + fileData = std::move(file); + dataReady.store(true); + } private: + std::atomic dataReady; + std::unique_ptr> fileData; }; } \ No newline at end of file