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:
parent
13f9baed33
commit
7379ba37c0
3 changed files with 60 additions and 18 deletions
|
|
@ -40,6 +40,7 @@ namespace config {
|
||||||
constexpr int numBackgroundThreads { 4 };
|
constexpr int numBackgroundThreads { 4 };
|
||||||
constexpr int numVoices { 64 };
|
constexpr int numVoices { 64 };
|
||||||
constexpr int maxVoices { 256 };
|
constexpr int maxVoices { 256 };
|
||||||
|
constexpr int maxFilePromises { maxVoices * 2 };
|
||||||
constexpr int sustainCC { 64 };
|
constexpr int sustainCC { 64 };
|
||||||
constexpr int allSoundOffCC { 120 };
|
constexpr int allSoundOffCC { 120 };
|
||||||
constexpr int resetCC { 121 };
|
constexpr int resetCC { 121 };
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,11 @@ sfz::FilePool::FilePool()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < config::numBackgroundThreads; ++i)
|
for (int i = 0; i < config::numBackgroundThreads; ++i)
|
||||||
threadPool.emplace_back( &FilePool::loadingThread, this );
|
threadPool.emplace_back( &FilePool::loadingThread, this );
|
||||||
|
|
||||||
threadPool.emplace_back( &FilePool::clearingThread, 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()
|
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
|
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);
|
const auto preloaded = preloadedFiles.find(filename);
|
||||||
if (preloaded != preloadedFiles.end()) {
|
if (preloaded == preloadedFiles.end())
|
||||||
promise->filename = preloaded->first;
|
return {};
|
||||||
promise->preloadedData = preloaded->second.preloadedData;
|
|
||||||
promise->sampleRate = preloaded->second.sampleRate;
|
auto& promise = emptyPromises.back();
|
||||||
promise->oversamplingFactor = oversamplingFactor;
|
promise->filename = preloaded->first;
|
||||||
promiseQueue.try_enqueue(promise);
|
promise->preloadedData = preloaded->second.preloadedData;
|
||||||
}
|
promise->sampleRate = preloaded->second.sampleRate;
|
||||||
|
promise->oversamplingFactor = oversamplingFactor;
|
||||||
|
promiseQueue.try_enqueue(promise);
|
||||||
|
emptyPromises.pop_back();
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,7 +203,10 @@ void sfz::FilePool::tryToClearPromises()
|
||||||
while (addingPromisesToClear)
|
while (addingPromisesToClear)
|
||||||
std::this_thread::sleep_for(1ms);
|
std::this_thread::sleep_for(1ms);
|
||||||
|
|
||||||
promisesToClear.clear();
|
for (auto& promise: promisesToClear) {
|
||||||
|
if (promise->dataReady)
|
||||||
|
promise->reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::FilePool::clearingThread()
|
void sfz::FilePool::clearingThread()
|
||||||
|
|
@ -261,21 +274,37 @@ void sfz::FilePool::cleanupPromises() noexcept
|
||||||
if (!canAddPromisesToClear)
|
if (!canAddPromisesToClear)
|
||||||
return;
|
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;
|
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))
|
while (filledPromiseQueue.try_dequeue(promise))
|
||||||
temporaryFilePromises.push_back(promise);
|
temporaryFilePromises.push_back(promise);
|
||||||
|
|
||||||
auto promiseIterator = temporaryFilePromises.begin();
|
auto filledIterator = temporaryFilePromises.begin();
|
||||||
auto sentinel = temporaryFilePromises.end() - 1;
|
auto filledSentinel = temporaryFilePromises.end() - 1;
|
||||||
while (promiseIterator != temporaryFilePromises.end()) {
|
while (filledIterator != temporaryFilePromises.end()) {
|
||||||
if (promiseIterator->use_count() == 1) {
|
if (filledIterator->use_count() == 1) {
|
||||||
promisesToClear.push_back(*promiseIterator);
|
promisesToClear.push_back(*filledIterator);
|
||||||
std::iter_swap(promiseIterator, sentinel);
|
std::iter_swap(filledIterator, filledSentinel);
|
||||||
sentinel--;
|
filledSentinel--;
|
||||||
temporaryFilePromises.pop_back();
|
temporaryFilePromises.pop_back();
|
||||||
} else {
|
} else {
|
||||||
promiseIterator++;
|
filledIterator++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,17 @@ struct FilePromise
|
||||||
return AudioSpan<const float>(*preloadedData);
|
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 {};
|
absl::string_view filename {};
|
||||||
AudioBufferPtr preloadedData {};
|
AudioBufferPtr preloadedData {};
|
||||||
AudioBuffer<float> fileData {};
|
AudioBuffer<float> fileData {};
|
||||||
|
|
@ -214,6 +225,7 @@ private:
|
||||||
std::atomic<int> threadsLoading { 0 };
|
std::atomic<int> threadsLoading { 0 };
|
||||||
|
|
||||||
// File promises data structures along with their guards.
|
// File promises data structures along with their guards.
|
||||||
|
std::vector<FilePromisePtr> emptyPromises;
|
||||||
std::vector<FilePromisePtr> temporaryFilePromises;
|
std::vector<FilePromisePtr> temporaryFilePromises;
|
||||||
std::vector<FilePromisePtr> promisesToClear;
|
std::vector<FilePromisePtr> promisesToClear;
|
||||||
std::atomic<bool> addingPromisesToClear { false };
|
std::atomic<bool> addingPromisesToClear { false };
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue