diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 8f3806a1..e8bfe92c 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -27,10 +27,10 @@ #include "Config.h" #include "Debug.h" #include "Oversampler.h" +#include "AtomicGuard.h" #include "absl/types/span.h" #include #include -#include #include #include using namespace std::chrono_literals; @@ -149,12 +149,28 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept this->preloadSize = preloadSize; } +void sfz::FilePool::tryToClearPromises() +{ + AtomicDisabler disabler { canAddPromisesToClear }; + + while (addingPromisesToClear) + std::this_thread::sleep_for(1ms); + + promisesToClear.clear(); +} + +void sfz::FilePool::clearingThread() +{ + while (!quitThread) { + tryToClearPromises(); + std::this_thread::sleep_for(50ms); + } +} + void sfz::FilePool::loadingThread() noexcept { FilePromisePtr promise; while (!quitThread) { - promisesToClean.clear(); - if (emptyQueue) { while(promiseQueue.try_dequeue(promise)) { // We're just dequeuing @@ -197,11 +213,16 @@ void sfz::FilePool::clear() emptyFileLoadingQueues(); preloadedFiles.clear(); temporaryFilePromises.clear(); - promisesToClean.clear(); + promisesToClear.clear(); } void sfz::FilePool::cleanupPromises() noexcept { + AtomicGuard guard { addingPromisesToClear }; + + if (!canAddPromisesToClear) + return; + FilePromisePtr promise; // Remove stuff from the filled queue and put them in a linear storage while (filledPromiseQueue.try_dequeue(promise)) @@ -211,7 +232,7 @@ void sfz::FilePool::cleanupPromises() noexcept auto sentinel = temporaryFilePromises.end() - 1; while (promiseIterator != temporaryFilePromises.end()) { if (promiseIterator->use_count() == 1) { - promisesToClean.push_back(*promiseIterator); + promisesToClear.push_back(*promiseIterator); std::iter_swap(promiseIterator, sentinel); sentinel--; temporaryFilePromises.pop_back(); diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 679526e1..725b7814 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -26,6 +26,7 @@ #include "Defaults.h" #include "LeakDetector.h" #include "AudioBuffer.h" +#include "AudioSpan.h" #include "SIMDHelpers.h" #include "ghc/fs_std.hpp" #include @@ -61,7 +62,7 @@ struct FilePromise AudioBufferPtr preloadedData {}; std::unique_ptr> fileData {}; float sampleRate { config::defaultSampleRate }; - std::atomic availableFrames { 0 }; + std::atomic_size_t availableFrames { 0 }; std::atomic dataReady { false }; Oversampling oversamplingFactor { config::defaultOversamplingFactor }; }; @@ -92,6 +93,7 @@ public: { for (int i = 0; i < config::numBackgroundThreads; ++i) fileLoadingThreadPool.emplace_back( &FilePool::loadingThread, this ); + fileLoadingThreadPool.emplace_back( &FilePool::clearingThread, this ); } ~FilePool() @@ -200,6 +202,8 @@ public: private: fs::path rootDirectory; void loadingThread() noexcept; + void clearingThread(); + void tryToClearPromises(); moodycamel::BlockingConcurrentQueue promiseQueue { config::maxVoices }; moodycamel::BlockingConcurrentQueue filledPromiseQueue { config::maxVoices }; @@ -211,7 +215,10 @@ private: std::atomic threadsLoading { 0 }; std::vector temporaryFilePromises; - std::vector promisesToClean; + std::vector promisesToClear; + std::atomic addingPromisesToClear; + std::atomic canAddPromisesToClear; + absl::flat_hash_map preloadedFiles; std::vector fileLoadingThreadPool { }; LEAK_DETECTOR(FilePool);