diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index fbeca154..fd9978fc 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -342,9 +342,9 @@ sfz::FileDataHolder sfz::FilePool::loadFile(const FileId& fileId) noexcept } } -sfz::FileDataHolder sfz::FilePool::getFilePromise(const FileId& fileId) noexcept +sfz::FileDataHolder sfz::FilePool::getFilePromise(const std::shared_ptr& fileId) noexcept { - const auto preloaded = preloadedFiles.find(fileId); + const auto preloaded = preloadedFiles.find(*fileId); if (preloaded == preloadedFiles.end()) { DBG("[sfizz] File not found in the preloaded files: " << fileId); return {}; @@ -381,14 +381,20 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept { raiseCurrentThreadPriority(); + std::shared_ptr id = data.id.lock(); + if (!id) { + // file ID was nulled, it means the region was deleted, ignore + return; + } + const auto loadStartTime = std::chrono::high_resolution_clock::now(); const auto waitDuration = loadStartTime - data.queuedTime; - const fs::path file { rootDirectory / data.id.filename() }; + const fs::path file { rootDirectory / id->filename() }; std::error_code readError; - AudioReaderPtr reader = createAudioReader(file, data.id.isReverse(), &readError); + AudioReaderPtr reader = createAudioReader(file, id->isReverse(), &readError); if (readError) { - DBG("[sfizz] libsndfile errored for " << data.id << " with message " << readError.message()); + DBG("[sfizz] libsndfile errored for " << *id << " with message " << readError.message()); return; } @@ -398,7 +404,7 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept while (currentStatus == FileData::Status::Invalid) { // Spin until the state changes if (spinCounter > 1024) { - DBG("[sfizz] " << data.id << " is stuck on Invalid? Leaving the load"); + DBG("[sfizz] " << *id << " is stuck on Invalid? Leaving the load"); return; } @@ -418,13 +424,13 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept const auto frames = static_cast(reader->frames()); streamFromFile(*reader, frames, oversamplingFactor, data.data->fileData, &data.data->availableFrames); const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime; - logger.logFileTime(waitDuration, loadDuration, frames, data.id.filename()); + logger.logFileTime(waitDuration, loadDuration, frames, id->filename()); data.data->status = FileData::Status::Done; std::lock_guard guard { lastUsedMutex }; - if (absl::c_find(lastUsedFiles, data.id) == lastUsedFiles.end()) - lastUsedFiles.push_back(data.id); + if (absl::c_find(lastUsedFiles, *id) == lastUsedFiles.end()) + lastUsedFiles.push_back(*id); } void sfz::FilePool::clear() @@ -487,20 +493,15 @@ void sfz::FilePool::dispatchingJob() noexcept { QueuedFileData queuedData; while (dispatchBarrier.wait(), dispatchFlag) { - if (emptyQueueFlag) { - while (filesToLoad.try_pop(queuedData)) { - // pass - } - semEmptyQueueFinished.post(); - emptyQueueFlag = false; - continue; - } - std::lock_guard guard { loadingJobsMutex }; if (filesToLoad.try_pop(queuedData)) { - loadingJobs.push_back( - threadPool->enqueue([this](const QueuedFileData& data) { loadingJob(data); }, queuedData)); + if (!queuedData.id.lock()) { + // file ID was nulled, it means the region was deleted, ignore + } + else + loadingJobs.push_back( + threadPool->enqueue([this](const QueuedFileData& data) { loadingJob(data); }, queuedData)); } // Clear finished jobs @@ -521,17 +522,6 @@ void sfz::FilePool::garbageJob() noexcept } } -void sfz::FilePool::emptyFileLoadingQueues() noexcept -{ - ASSERT(dispatchFlag); - emptyQueueFlag = true; - std::error_code ec; - dispatchBarrier.post(ec); - - if (!ec) - semEmptyQueueFinished.wait(); -} - void sfz::FilePool::waitForBackgroundLoading() noexcept { std::lock_guard guard { loadingJobsMutex }; diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index a9f0ecff..8c14f1ce 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -263,7 +263,7 @@ public: * @param fileId the file to preload * @return FileDataHolder a file data handle */ - FileDataHolder getFilePromise(const FileId& fileId) noexcept; + FileDataHolder getFilePromise(const std::shared_ptr& fileId) noexcept; /** * @brief Change the preloading size. This will trigger a full * reload of all samples, so don't call it on the audio thread. @@ -296,7 +296,11 @@ public: * method on the audio thread as it will spinlock. * */ - void emptyFileLoadingQueues() noexcept; + void emptyFileLoadingQueues() noexcept + { + // nothing to do in this implementation, + // deleting the region and its sample ID take care of it + } /** * @brief Wait for the background loading to finish for all promises * in the queue. @@ -331,9 +335,7 @@ private: // Signals volatile bool dispatchFlag { true }; volatile bool garbageFlag { true }; - volatile bool emptyQueueFlag { false }; RTSemaphore dispatchBarrier; - RTSemaphore semEmptyQueueFinished; RTSemaphore semGarbageBarrier; // Structures for the background loaders @@ -341,13 +343,13 @@ private: { using TimePoint = std::chrono::time_point; QueuedFileData() = default; - QueuedFileData(FileId id, FileData* data, TimePoint queuedTime) + QueuedFileData(std::weak_ptr id, FileData* data, TimePoint queuedTime) : id(id), data(data), queuedTime(queuedTime) {} QueuedFileData(const QueuedFileData&) = default; QueuedFileData& operator=(const QueuedFileData&) = default; QueuedFileData(QueuedFileData&&) = default; QueuedFileData& operator=(QueuedFileData&&) = default; - FileId id {}; + std::weak_ptr id; FileData* data { nullptr }; TimePoint queuedTime {}; }; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index bdf25f7d..3b2ee301 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -94,7 +94,7 @@ void sfz::Voice::startVoice(Region* region, int delay, const TriggerEvent& event } setupOscillatorUnison(); } else { - currentPromise = resources.filePool.getFilePromise(*region->sampleId); + currentPromise = resources.filePool.getFilePromise(region->sampleId); if (!currentPromise) { switchState(State::cleanMeUp); return;