The file promise logic actually allocated

Changed to add a pool of "empty" promises, but I
wonder if all of this could be made a bit simpler?
This commit is contained in:
Paul Ferrand 2019-12-23 13:59:43 +01:00
parent 13f9baed33
commit 7379ba37c0
3 changed files with 60 additions and 18 deletions

View file

@ -40,6 +40,7 @@ namespace config {
constexpr int numBackgroundThreads { 4 };
constexpr int numVoices { 64 };
constexpr int maxVoices { 256 };
constexpr int maxFilePromises { maxVoices * 2 };
constexpr int sustainCC { 64 };
constexpr int allSoundOffCC { 120 };
constexpr int resetCC { 121 };

View file

@ -89,7 +89,11 @@ sfz::FilePool::FilePool()
{
for (int i = 0; i < config::numBackgroundThreads; ++i)
threadPool.emplace_back( &FilePool::loadingThread, this );
threadPool.emplace_back( &FilePool::clearingThread, this );
for (int i = 0; i < config::maxFilePromises; ++i)
emptyPromises.push_back(std::make_shared<FilePromise>());
}
sfz::FilePool::~FilePool()
@ -161,15 +165,21 @@ bool sfz::FilePool::preloadFile(const std::string& filename, uint32_t maxOffset)
sfz::FilePromisePtr sfz::FilePool::getFilePromise(const std::string& filename) noexcept
{
auto promise = std::make_shared<FilePromise>();
if (emptyPromises.empty())
return {};
const auto preloaded = preloadedFiles.find(filename);
if (preloaded != preloadedFiles.end()) {
promise->filename = preloaded->first;
promise->preloadedData = preloaded->second.preloadedData;
promise->sampleRate = preloaded->second.sampleRate;
promise->oversamplingFactor = oversamplingFactor;
promiseQueue.try_enqueue(promise);
}
if (preloaded == preloadedFiles.end())
return {};
auto& promise = emptyPromises.back();
promise->filename = preloaded->first;
promise->preloadedData = preloaded->second.preloadedData;
promise->sampleRate = preloaded->second.sampleRate;
promise->oversamplingFactor = oversamplingFactor;
promiseQueue.try_enqueue(promise);
emptyPromises.pop_back();
return promise;
}
@ -193,7 +203,10 @@ void sfz::FilePool::tryToClearPromises()
while (addingPromisesToClear)
std::this_thread::sleep_for(1ms);
promisesToClear.clear();
for (auto& promise: promisesToClear) {
if (promise->dataReady)
promise->reset();
}
}
void sfz::FilePool::clearingThread()
@ -261,21 +274,37 @@ void sfz::FilePool::cleanupPromises() noexcept
if (!canAddPromisesToClear)
return;
// The garbage collection cleared the data from these so we can move them
// back to the empty queue
auto clearedIterator = promisesToClear.begin();
auto clearedSentinel = promisesToClear.end() - 1;
while (clearedIterator != promisesToClear.end()) {
if (clearedIterator->get()->dataReady == false) {
emptyPromises.push_back(*clearedIterator);
std::iter_swap(clearedIterator, clearedSentinel);
clearedSentinel--;
promisesToClear.pop_back();
} else {
clearedIterator++;
}
}
FilePromisePtr promise;
// Remove stuff from the filled queue and put them in a linear storage
// Remove the promises from the filled queue and put them in a linear
// storage
while (filledPromiseQueue.try_dequeue(promise))
temporaryFilePromises.push_back(promise);
auto promiseIterator = temporaryFilePromises.begin();
auto sentinel = temporaryFilePromises.end() - 1;
while (promiseIterator != temporaryFilePromises.end()) {
if (promiseIterator->use_count() == 1) {
promisesToClear.push_back(*promiseIterator);
std::iter_swap(promiseIterator, sentinel);
sentinel--;
auto filledIterator = temporaryFilePromises.begin();
auto filledSentinel = temporaryFilePromises.end() - 1;
while (filledIterator != temporaryFilePromises.end()) {
if (filledIterator->use_count() == 1) {
promisesToClear.push_back(*filledIterator);
std::iter_swap(filledIterator, filledSentinel);
filledSentinel--;
temporaryFilePromises.pop_back();
} else {
promiseIterator++;
filledIterator++;
}
}
}

View file

@ -58,6 +58,17 @@ struct FilePromise
return AudioSpan<const float>(*preloadedData);
}
void reset()
{
fileData.reset();
preloadedData.reset();
filename = "";
availableFrames = 0;
dataReady = false;
oversamplingFactor = config::defaultOversamplingFactor;
sampleRate = config::defaultSampleRate;
}
absl::string_view filename {};
AudioBufferPtr preloadedData {};
AudioBuffer<float> fileData {};
@ -214,6 +225,7 @@ private:
std::atomic<int> threadsLoading { 0 };
// File promises data structures along with their guards.
std::vector<FilePromisePtr> emptyPromises;
std::vector<FilePromisePtr> temporaryFilePromises;
std::vector<FilePromisePtr> promisesToClear;
std::atomic<bool> addingPromisesToClear { false };