Move the spsc queues to mpmc queues
This commit is contained in:
parent
e33ce85a6a
commit
19b475ed94
4 changed files with 47 additions and 29 deletions
|
|
@ -36,7 +36,9 @@ namespace config {
|
||||||
constexpr int defaultSamplesPerBlock { 1024 };
|
constexpr int defaultSamplesPerBlock { 1024 };
|
||||||
constexpr int preloadSize { 8192 };
|
constexpr int preloadSize { 8192 };
|
||||||
constexpr int numChannels { 2 };
|
constexpr int numChannels { 2 };
|
||||||
|
constexpr int numBackgroundThreads { 4 };
|
||||||
constexpr int numVoices { 64 };
|
constexpr int numVoices { 64 };
|
||||||
|
constexpr int maxVoices { 256 };
|
||||||
constexpr int sustainCC { 64 };
|
constexpr int sustainCC { 64 };
|
||||||
constexpr int halfCCThreshold { 64 };
|
constexpr int halfCCThreshold { 64 };
|
||||||
constexpr int centPerSemitone { 100 };
|
constexpr int centPerSemitone { 100 };
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) n
|
||||||
promise->preloadedData = preloaded->second.preloadedData;
|
promise->preloadedData = preloaded->second.preloadedData;
|
||||||
promise->sampleRate = preloaded->second.sampleRate;
|
promise->sampleRate = preloaded->second.sampleRate;
|
||||||
promise->oversamplingFactor = oversamplingFactor;
|
promise->oversamplingFactor = oversamplingFactor;
|
||||||
promiseQueue.enqueue(promise);
|
promiseQueue.try_enqueue(promise);
|
||||||
}
|
}
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
@ -196,28 +196,34 @@ void sfz::FilePool::loadingThread() noexcept
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!promiseQueue.try_dequeue(promise)) {
|
if (!promiseQueue.wait_dequeue_timed(promise, 50ms)) {
|
||||||
std::this_thread::sleep_for(0.1ms);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path file { rootDirectory / std::string(promise->filename) };
|
// The voice abandoned the promise already we just don't care
|
||||||
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
if (promise.use_count() != 1) {
|
||||||
if (sndFile.error() != 0)
|
fs::path file { rootDirectory / std::string(promise->filename) };
|
||||||
continue;
|
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
||||||
|
if (sndFile.error() != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
DBG("Loading file for " << promise->filename << " in the background");
|
DBG("Loading file for " << promise->filename << " in the background");
|
||||||
const uint32_t frames = sndFile.frames();
|
const uint32_t frames = sndFile.frames();
|
||||||
promise->fileData = readFromFile<float>(sndFile, frames, oversamplingFactor);
|
promise->fileData = readFromFile<float>(sndFile, frames, oversamplingFactor);
|
||||||
promise->dataReady = true;
|
promise->dataReady = true;
|
||||||
temporaryFilePromises.push_back(promise);
|
}
|
||||||
|
|
||||||
|
while (!filledPromiseQueue.try_enqueue(promise)) {
|
||||||
|
DBG("Error enqueuing the file for " << promise->filename << " in the filledPromiseQueue");
|
||||||
|
std::this_thread::sleep_for(1ms);
|
||||||
|
}
|
||||||
promise.reset();
|
promise.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::FilePool::clear()
|
void sfz::FilePool::clear()
|
||||||
{
|
{
|
||||||
emptyFileLoadingQueue();
|
emptyFileLoadingQueues();
|
||||||
preloadedFiles.clear();
|
preloadedFiles.clear();
|
||||||
temporaryFilePromises.clear();
|
temporaryFilePromises.clear();
|
||||||
promisesToClean.clear();
|
promisesToClean.clear();
|
||||||
|
|
@ -225,19 +231,23 @@ void sfz::FilePool::clear()
|
||||||
|
|
||||||
void sfz::FilePool::cleanupPromises() noexcept
|
void sfz::FilePool::cleanupPromises() noexcept
|
||||||
{
|
{
|
||||||
if (temporaryFilePromises.empty())
|
FilePromisePtr promise;
|
||||||
return;
|
// Remove stuff from the filled queue and put them in a linear storage
|
||||||
|
while (filledPromiseQueue.try_dequeue(promise)) {
|
||||||
|
temporaryFilePromises.push_back(promise);
|
||||||
|
promise.reset();
|
||||||
|
}
|
||||||
|
|
||||||
auto promise = temporaryFilePromises.begin();
|
auto promiseIterator = temporaryFilePromises.begin();
|
||||||
auto sentinel = temporaryFilePromises.end() - 1;
|
auto sentinel = temporaryFilePromises.end() - 1;
|
||||||
while (promise != temporaryFilePromises.end()) {
|
while (promiseIterator != temporaryFilePromises.end()) {
|
||||||
if (promise->use_count() == 1) {
|
if (promiseIterator->use_count() == 1) {
|
||||||
promisesToClean.push_back(*promise);
|
promisesToClean.push_back(*promiseIterator);
|
||||||
std::iter_swap(promise, sentinel);
|
std::iter_swap(promiseIterator, sentinel);
|
||||||
sentinel--;
|
sentinel--;
|
||||||
temporaryFilePromises.pop_back();
|
temporaryFilePromises.pop_back();
|
||||||
} else {
|
} else {
|
||||||
promise++;
|
promiseIterator++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -267,7 +277,7 @@ uint32_t sfz::FilePool::getPreloadSize() const noexcept
|
||||||
return preloadSize;
|
return preloadSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::FilePool::emptyFileLoadingQueue() noexcept
|
void sfz::FilePool::emptyFileLoadingQueues() noexcept
|
||||||
{
|
{
|
||||||
emptyQueue = true;
|
emptyQueue = true;
|
||||||
while (emptyQueue)
|
while (emptyQueue)
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
#include <absl/container/flat_hash_map.h>
|
#include <absl/container/flat_hash_map.h>
|
||||||
#include <absl/types/optional.h>
|
#include <absl/types/optional.h>
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "moodycamel/concurrentqueue.h"
|
#include "moodycamel/blockingconcurrentqueue.h"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <sndfile.hh>
|
#include <sndfile.hh>
|
||||||
|
|
||||||
|
|
@ -77,12 +77,17 @@ using FilePromisePtr = std::shared_ptr<FilePromise>;
|
||||||
|
|
||||||
class FilePool {
|
class FilePool {
|
||||||
public:
|
public:
|
||||||
FilePool() { }
|
FilePool()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < config::numBackgroundThreads; ++i)
|
||||||
|
fileLoadingThreadPool.emplace_back( &FilePool::loadingThread, this );
|
||||||
|
}
|
||||||
|
|
||||||
~FilePool()
|
~FilePool()
|
||||||
{
|
{
|
||||||
quitThread = true;
|
quitThread = true;
|
||||||
fileLoadingThread.join();
|
for (auto& thread: fileLoadingThreadPool)
|
||||||
|
thread.join();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Set the root directory from which to search for files to load
|
* @brief Set the root directory from which to search for files to load
|
||||||
|
|
@ -136,12 +141,13 @@ public:
|
||||||
uint32_t getPreloadSize() const noexcept;
|
uint32_t getPreloadSize() const noexcept;
|
||||||
void setOversamplingFactor(Oversampling factor) noexcept;
|
void setOversamplingFactor(Oversampling factor) noexcept;
|
||||||
Oversampling getOversamplingFactor() const noexcept;
|
Oversampling getOversamplingFactor() const noexcept;
|
||||||
void emptyFileLoadingQueue() noexcept;
|
void emptyFileLoadingQueues() noexcept;
|
||||||
private:
|
private:
|
||||||
fs::path rootDirectory;
|
fs::path rootDirectory;
|
||||||
void loadingThread() noexcept;
|
void loadingThread() noexcept;
|
||||||
|
|
||||||
moodycamel::ConcurrentQueue<FilePromisePtr> promiseQueue;
|
moodycamel::BlockingConcurrentQueue<FilePromisePtr> promiseQueue { config::maxVoices };
|
||||||
|
moodycamel::BlockingConcurrentQueue<FilePromisePtr> filledPromiseQueue { config::maxVoices };
|
||||||
uint32_t preloadSize { config::preloadSize };
|
uint32_t preloadSize { config::preloadSize };
|
||||||
Oversampling oversamplingFactor { config::defaultOversamplingFactor };
|
Oversampling oversamplingFactor { config::defaultOversamplingFactor };
|
||||||
// Signals
|
// Signals
|
||||||
|
|
@ -151,7 +157,7 @@ private:
|
||||||
std::vector<FilePromisePtr> temporaryFilePromises;
|
std::vector<FilePromisePtr> temporaryFilePromises;
|
||||||
std::vector<FilePromisePtr> promisesToClean;
|
std::vector<FilePromisePtr> promisesToClean;
|
||||||
absl::flat_hash_map<absl::string_view, PreloadedFileHandle> preloadedFiles;
|
absl::flat_hash_map<absl::string_view, PreloadedFileHandle> preloadedFiles;
|
||||||
std::thread fileLoadingThread { &FilePool::loadingThread, this };
|
std::vector<std::thread> fileLoadingThreadPool { };
|
||||||
LEAK_DETECTOR(FilePool);
|
LEAK_DETECTOR(FilePool);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -551,7 +551,7 @@ void sfz::Synth::setOversamplingFactor(sfz::Oversampling factor) noexcept
|
||||||
for (auto& voice: voices)
|
for (auto& voice: voices)
|
||||||
voice->reset();
|
voice->reset();
|
||||||
|
|
||||||
resources.filePool.emptyFileLoadingQueue();
|
resources.filePool.emptyFileLoadingQueues();
|
||||||
resources.filePool.setOversamplingFactor(factor);
|
resources.filePool.setOversamplingFactor(factor);
|
||||||
oversamplingFactor = factor;
|
oversamplingFactor = factor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue