Auto-cleaning file pool
This commit is contained in:
parent
e6ecbc6fcd
commit
0e24daf26d
3 changed files with 30 additions and 38 deletions
|
|
@ -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>& fileId) noexcept
|
||||||
{
|
{
|
||||||
const auto preloaded = preloadedFiles.find(fileId);
|
const auto preloaded = preloadedFiles.find(*fileId);
|
||||||
if (preloaded == preloadedFiles.end()) {
|
if (preloaded == preloadedFiles.end()) {
|
||||||
DBG("[sfizz] File not found in the preloaded files: " << fileId);
|
DBG("[sfizz] File not found in the preloaded files: " << fileId);
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -381,14 +381,20 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept
|
||||||
{
|
{
|
||||||
raiseCurrentThreadPriority();
|
raiseCurrentThreadPriority();
|
||||||
|
|
||||||
|
std::shared_ptr<FileId> 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 loadStartTime = std::chrono::high_resolution_clock::now();
|
||||||
const auto waitDuration = loadStartTime - data.queuedTime;
|
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;
|
std::error_code readError;
|
||||||
AudioReaderPtr reader = createAudioReader(file, data.id.isReverse(), &readError);
|
AudioReaderPtr reader = createAudioReader(file, id->isReverse(), &readError);
|
||||||
|
|
||||||
if (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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -398,7 +404,7 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept
|
||||||
while (currentStatus == FileData::Status::Invalid) {
|
while (currentStatus == FileData::Status::Invalid) {
|
||||||
// Spin until the state changes
|
// Spin until the state changes
|
||||||
if (spinCounter > 1024) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -418,13 +424,13 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept
|
||||||
const auto frames = static_cast<uint32_t>(reader->frames());
|
const auto frames = static_cast<uint32_t>(reader->frames());
|
||||||
streamFromFile(*reader, frames, oversamplingFactor, data.data->fileData, &data.data->availableFrames);
|
streamFromFile(*reader, frames, oversamplingFactor, data.data->fileData, &data.data->availableFrames);
|
||||||
const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime;
|
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;
|
data.data->status = FileData::Status::Done;
|
||||||
|
|
||||||
std::lock_guard<SpinMutex> guard { lastUsedMutex };
|
std::lock_guard<SpinMutex> guard { lastUsedMutex };
|
||||||
if (absl::c_find(lastUsedFiles, data.id) == lastUsedFiles.end())
|
if (absl::c_find(lastUsedFiles, *id) == lastUsedFiles.end())
|
||||||
lastUsedFiles.push_back(data.id);
|
lastUsedFiles.push_back(*id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::FilePool::clear()
|
void sfz::FilePool::clear()
|
||||||
|
|
@ -487,18 +493,13 @@ void sfz::FilePool::dispatchingJob() noexcept
|
||||||
{
|
{
|
||||||
QueuedFileData queuedData;
|
QueuedFileData queuedData;
|
||||||
while (dispatchBarrier.wait(), dispatchFlag) {
|
while (dispatchBarrier.wait(), dispatchFlag) {
|
||||||
if (emptyQueueFlag) {
|
|
||||||
while (filesToLoad.try_pop(queuedData)) {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
semEmptyQueueFinished.post();
|
|
||||||
emptyQueueFlag = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard { loadingJobsMutex };
|
std::lock_guard<std::mutex> guard { loadingJobsMutex };
|
||||||
|
|
||||||
if (filesToLoad.try_pop(queuedData)) {
|
if (filesToLoad.try_pop(queuedData)) {
|
||||||
|
if (!queuedData.id.lock()) {
|
||||||
|
// file ID was nulled, it means the region was deleted, ignore
|
||||||
|
}
|
||||||
|
else
|
||||||
loadingJobs.push_back(
|
loadingJobs.push_back(
|
||||||
threadPool->enqueue([this](const QueuedFileData& data) { loadingJob(data); }, queuedData));
|
threadPool->enqueue([this](const QueuedFileData& data) { loadingJob(data); }, queuedData));
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
void sfz::FilePool::waitForBackgroundLoading() noexcept
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard { loadingJobsMutex };
|
std::lock_guard<std::mutex> guard { loadingJobsMutex };
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ public:
|
||||||
* @param fileId the file to preload
|
* @param fileId the file to preload
|
||||||
* @return FileDataHolder a file data handle
|
* @return FileDataHolder a file data handle
|
||||||
*/
|
*/
|
||||||
FileDataHolder getFilePromise(const FileId& fileId) noexcept;
|
FileDataHolder getFilePromise(const std::shared_ptr<FileId>& fileId) noexcept;
|
||||||
/**
|
/**
|
||||||
* @brief Change the preloading size. This will trigger a full
|
* @brief Change the preloading size. This will trigger a full
|
||||||
* reload of all samples, so don't call it on the audio thread.
|
* 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.
|
* 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
|
* @brief Wait for the background loading to finish for all promises
|
||||||
* in the queue.
|
* in the queue.
|
||||||
|
|
@ -331,9 +335,7 @@ private:
|
||||||
// Signals
|
// Signals
|
||||||
volatile bool dispatchFlag { true };
|
volatile bool dispatchFlag { true };
|
||||||
volatile bool garbageFlag { true };
|
volatile bool garbageFlag { true };
|
||||||
volatile bool emptyQueueFlag { false };
|
|
||||||
RTSemaphore dispatchBarrier;
|
RTSemaphore dispatchBarrier;
|
||||||
RTSemaphore semEmptyQueueFinished;
|
|
||||||
RTSemaphore semGarbageBarrier;
|
RTSemaphore semGarbageBarrier;
|
||||||
|
|
||||||
// Structures for the background loaders
|
// Structures for the background loaders
|
||||||
|
|
@ -341,13 +343,13 @@ private:
|
||||||
{
|
{
|
||||||
using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
||||||
QueuedFileData() = default;
|
QueuedFileData() = default;
|
||||||
QueuedFileData(FileId id, FileData* data, TimePoint queuedTime)
|
QueuedFileData(std::weak_ptr<FileId> id, FileData* data, TimePoint queuedTime)
|
||||||
: id(id), data(data), queuedTime(queuedTime) {}
|
: id(id), data(data), queuedTime(queuedTime) {}
|
||||||
QueuedFileData(const QueuedFileData&) = default;
|
QueuedFileData(const QueuedFileData&) = default;
|
||||||
QueuedFileData& operator=(const QueuedFileData&) = default;
|
QueuedFileData& operator=(const QueuedFileData&) = default;
|
||||||
QueuedFileData(QueuedFileData&&) = default;
|
QueuedFileData(QueuedFileData&&) = default;
|
||||||
QueuedFileData& operator=(QueuedFileData&&) = default;
|
QueuedFileData& operator=(QueuedFileData&&) = default;
|
||||||
FileId id {};
|
std::weak_ptr<FileId> id;
|
||||||
FileData* data { nullptr };
|
FileData* data { nullptr };
|
||||||
TimePoint queuedTime {};
|
TimePoint queuedTime {};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ void sfz::Voice::startVoice(Region* region, int delay, const TriggerEvent& event
|
||||||
}
|
}
|
||||||
setupOscillatorUnison();
|
setupOscillatorUnison();
|
||||||
} else {
|
} else {
|
||||||
currentPromise = resources.filePool.getFilePromise(*region->sampleId);
|
currentPromise = resources.filePool.getFilePromise(region->sampleId);
|
||||||
if (!currentPromise) {
|
if (!currentPromise) {
|
||||||
switchState(State::cleanMeUp);
|
switchState(State::cleanMeUp);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue