Switch back to a queue for file promises
This commit is contained in:
parent
0d285cf494
commit
91e4678c4b
3 changed files with 45 additions and 32 deletions
|
|
@ -60,18 +60,19 @@ std::unique_ptr<sfz::AudioBuffer<T>> upsample4x(const sfz::AudioBuffer<T>& buffe
|
||||||
template <class T>
|
template <class T>
|
||||||
std::unique_ptr<sfz::AudioBuffer<T>> upsample8x(const sfz::AudioBuffer<T>& buffer)
|
std::unique_ptr<sfz::AudioBuffer<T>> upsample8x(const sfz::AudioBuffer<T>& buffer)
|
||||||
{
|
{
|
||||||
auto tempBuffer = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 4);
|
auto tempBuffer2x = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 2);
|
||||||
|
auto tempBuffer4x = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 4);
|
||||||
auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(buffer.getNumChannels(), buffer.getNumFrames() * 8);
|
auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(buffer.getNumChannels(), buffer.getNumFrames() * 8);
|
||||||
for (int channelIdx = 0; channelIdx < buffer.getNumChannels(); channelIdx++) {
|
for (int channelIdx = 0; channelIdx < buffer.getNumChannels(); channelIdx++) {
|
||||||
sfz::upsample2xStage(buffer.getConstSpan(channelIdx), absl::MakeSpan(*tempBuffer).first(buffer.getNumFrames() * 2));
|
sfz::upsample2xStage(buffer.getConstSpan(channelIdx), absl::MakeSpan(*tempBuffer2x));
|
||||||
sfz::upsample4xStage(absl::MakeConstSpan(*tempBuffer).first(buffer.getNumFrames() * 2), absl::MakeSpan(*tempBuffer));
|
sfz::upsample4xStage(absl::MakeConstSpan(*tempBuffer2x), absl::MakeSpan(*tempBuffer4x));
|
||||||
sfz::upsample8xStage(absl::MakeConstSpan(*tempBuffer), outputBuffer->getSpan(channelIdx));
|
sfz::upsample8xStage(absl::MakeConstSpan(*tempBuffer4x), outputBuffer->getSpan(channelIdx));
|
||||||
}
|
}
|
||||||
return outputBuffer;
|
return outputBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
std::unique_ptr<sfz::AudioBuffer<T>> readFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor = sfz::Oversampling::x1)
|
std::unique_ptr<sfz::AudioBuffer<T>> readFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor)
|
||||||
{
|
{
|
||||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<T>>(sndFile.channels(), numFrames);
|
auto baseBuffer = std::make_unique<sfz::AudioBuffer<T>>(sndFile.channels(), numFrames);
|
||||||
if (sndFile.channels() == 1) {
|
if (sndFile.channels() == 1) {
|
||||||
|
|
@ -83,13 +84,17 @@ std::unique_ptr<sfz::AudioBuffer<T>> readFromFile(SndfileHandle& sndFile, uint32
|
||||||
sfz::readInterleaved<T>(tempReadBuffer->getSpan(0), baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
sfz::readInterleaved<T>(tempReadBuffer->getSpan(0), baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (factor)
|
switch (factor) {
|
||||||
{
|
case sfz::Oversampling::x1:
|
||||||
case sfz::Oversampling::x1: return baseBuffer;
|
return baseBuffer;
|
||||||
case sfz::Oversampling::x2: return upsample2x(*baseBuffer);
|
case sfz::Oversampling::x2:
|
||||||
case sfz::Oversampling::x4: return upsample4x(*baseBuffer);
|
return upsample2x(*baseBuffer);
|
||||||
case sfz::Oversampling::x8: return upsample8x(*baseBuffer);
|
case sfz::Oversampling::x4:
|
||||||
default: return {};
|
return upsample4x(*baseBuffer);
|
||||||
|
case sfz::Oversampling::x8:
|
||||||
|
return upsample8x(*baseBuffer);
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,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;
|
||||||
temporaryFilePromises.push_back(promise);
|
promiseQueue.enqueue(promise);
|
||||||
}
|
}
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
@ -172,30 +177,32 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept
|
||||||
const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0;
|
const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0;
|
||||||
fs::path file { rootDirectory / std::string(preloadedFile.first) };
|
fs::path file { rootDirectory / std::string(preloadedFile.first) };
|
||||||
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
||||||
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset);
|
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, oversamplingFactor);
|
||||||
}
|
}
|
||||||
this->preloadSize = preloadSize;
|
this->preloadSize = preloadSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::FilePool::loadingThread() noexcept
|
void sfz::FilePool::loadingThread() noexcept
|
||||||
{
|
{
|
||||||
|
FilePromisePtr promise;
|
||||||
while (!quitThread) {
|
while (!quitThread) {
|
||||||
std::this_thread::sleep_for(1ms);
|
promisesToClean.clear();
|
||||||
for (auto& promise : temporaryFilePromises) {
|
if (!promiseQueue.try_dequeue(promise)) {
|
||||||
if (!promise->dataReady) {
|
std::this_thread::sleep_for(0.1ms);
|
||||||
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");
|
|
||||||
const uint32_t frames = sndFile.frames();
|
|
||||||
promise->fileData = readFromFile<float>(sndFile, frames);
|
|
||||||
promise->dataReady = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
promisesToClean.clear();
|
fs::path file { rootDirectory / std::string(promise->filename) };
|
||||||
|
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
||||||
|
if (sndFile.error() != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DBG("Loading file for " << promise->filename << " in the background");
|
||||||
|
const uint32_t frames = sndFile.frames();
|
||||||
|
promise->fileData = readFromFile<float>(sndFile, frames, oversamplingFactor);
|
||||||
|
promise->dataReady = true;
|
||||||
|
temporaryFilePromises.push_back(promise);
|
||||||
|
promise.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +240,7 @@ void sfz::FilePool::setOversamplingFactor(sfz::Oversampling factor) noexcept
|
||||||
const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0;
|
const uint32_t maxOffset = numFrames > this->preloadSize ? numFrames - this->preloadSize : 0;
|
||||||
fs::path file { rootDirectory / std::string(preloadedFile.first) };
|
fs::path file { rootDirectory / std::string(preloadedFile.first) };
|
||||||
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
SndfileHandle sndFile(reinterpret_cast<const char*>(file.c_str()));
|
||||||
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset);
|
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, factor);
|
||||||
preloadedFile.second.sampleRate *= samplerateChange;
|
preloadedFile.second.sampleRate *= samplerateChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +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/readerwriterqueue.h"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <sndfile.hh>
|
#include <sndfile.hh>
|
||||||
|
|
||||||
|
|
@ -139,9 +140,9 @@ private:
|
||||||
fs::path rootDirectory;
|
fs::path rootDirectory;
|
||||||
void loadingThread() noexcept;
|
void loadingThread() noexcept;
|
||||||
|
|
||||||
|
moodycamel::ReaderWriterQueue<FilePromisePtr> promiseQueue;
|
||||||
uint32_t preloadSize { config::preloadSize };
|
uint32_t preloadSize { config::preloadSize };
|
||||||
Oversampling oversamplingFactor { config::defaultOversamplingFactor };
|
Oversampling oversamplingFactor { config::defaultOversamplingFactor };
|
||||||
|
|
||||||
// Signals
|
// Signals
|
||||||
bool quitThread { false };
|
bool quitThread { false };
|
||||||
bool emptyQueue { false };
|
bool emptyQueue { false };
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,11 @@ void sfz::Voice::startVoice(Region* region, int delay, int channel, int number,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate);
|
speedRatio = static_cast<float>(currentPromise->sampleRate / this->sampleRate);
|
||||||
|
DBG("[Voice] Sample rate for " << region->sample << " is " << currentPromise->sampleRate);
|
||||||
|
DBG("[Voice] Speed ratio set to " << speedRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
pitchRatio = region->getBasePitchVariation(number, value);
|
pitchRatio = region->getBasePitchVariation(number, value);
|
||||||
|
DBG("[Voice] Pitch ratio set to " << pitchRatio);
|
||||||
|
|
||||||
baseVolumedB = region->getBaseVolumedB(number);
|
baseVolumedB = region->getBaseVolumedB(number);
|
||||||
|
|
||||||
|
|
@ -373,7 +375,10 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
||||||
add<int>(sourcePosition, indices);
|
add<int>(sourcePosition, indices);
|
||||||
|
|
||||||
//FIXME : all this casting is driving me crazy
|
//FIXME : all this casting is driving me crazy
|
||||||
const auto sampleEnd = min(static_cast<size_t>(region->trueSampleEnd(currentPromise->oversamplingFactor)), source.getNumFrames()) - 1;
|
const auto sampleEnd = min(
|
||||||
|
static_cast<int>(region->trueSampleEnd(currentPromise->oversamplingFactor)),
|
||||||
|
static_cast<int>(source.getNumFrames())
|
||||||
|
) - 1;
|
||||||
if (region->shouldLoop() && region->loopEnd(currentPromise->oversamplingFactor) <= source.getNumFrames()) {
|
if (region->shouldLoop() && region->loopEnd(currentPromise->oversamplingFactor) <= source.getNumFrames()) {
|
||||||
const auto offset = sampleEnd - static_cast<int>(region->loopStart(currentPromise->oversamplingFactor));
|
const auto offset = sampleEnd - static_cast<int>(region->loopStart(currentPromise->oversamplingFactor));
|
||||||
for (auto* index = indices.begin(); index < indices.end(); ++index) {
|
for (auto* index = indices.begin(); index < indices.end(); ++index) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue