Merge pull request #514 from jpcima/race-conditions-2

Fix race conditions (2)
This commit is contained in:
JP Cimalando 2020-10-21 04:21:00 +02:00 committed by GitHub
commit 7962e9c3a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 115 additions and 123 deletions

View file

@ -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()) {
DBG("[sfizz] File not found in the preloaded files: " << fileId);
return {};
@ -381,14 +381,20 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept
{
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 waitDuration = loadStartTime - data.queuedTime;
const fs::path file { rootDirectory / data.id.filename() };
const fs::path file { rootDirectory / id->filename() };
std::error_code readError;
AudioReaderPtr reader = createAudioReader(file, data.id.isReverse(), &readError);
AudioReaderPtr reader = createAudioReader(file, id->isReverse(), &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;
}
@ -398,7 +404,7 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept
while (currentStatus == FileData::Status::Invalid) {
// Spin until the state changes
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;
}
@ -418,13 +424,13 @@ void sfz::FilePool::loadingJob(QueuedFileData data) noexcept
const auto frames = static_cast<uint32_t>(reader->frames());
streamFromFile(*reader, frames, oversamplingFactor, data.data->fileData, &data.data->availableFrames);
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;
std::lock_guard<SpinMutex> guard { lastUsedMutex };
if (absl::c_find(lastUsedFiles, data.id) == lastUsedFiles.end())
lastUsedFiles.push_back(data.id);
if (absl::c_find(lastUsedFiles, *id) == lastUsedFiles.end())
lastUsedFiles.push_back(*id);
}
void sfz::FilePool::clear()
@ -487,20 +493,15 @@ void sfz::FilePool::dispatchingJob() noexcept
{
QueuedFileData queuedData;
while (dispatchBarrier.wait(), dispatchFlag) {
if (emptyQueueFlag) {
while (filesToLoad.try_pop(queuedData)) {
// pass
}
semEmptyQueueFinished.post();
emptyQueueFlag = false;
continue;
}
std::lock_guard<std::mutex> guard { loadingJobsMutex };
if (filesToLoad.try_pop(queuedData)) {
loadingJobs.push_back(
threadPool->enqueue([this](const QueuedFileData& data) { loadingJob(data); }, queuedData));
if (queuedData.id.expired()) {
// file ID was nulled, it means the region was deleted, ignore
}
else
loadingJobs.push_back(
threadPool->enqueue([this](const QueuedFileData& data) { loadingJob(data); }, queuedData));
}
// Clear finished jobs
@ -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
{
std::lock_guard<std::mutex> guard { loadingJobsMutex };

View file

@ -263,7 +263,7 @@ public:
* @param fileId the file to preload
* @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
* 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.
*
*/
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
* in the queue.
@ -331,9 +335,7 @@ private:
// Signals
volatile bool dispatchFlag { true };
volatile bool garbageFlag { true };
volatile bool emptyQueueFlag { false };
RTSemaphore dispatchBarrier;
RTSemaphore semEmptyQueueFinished;
RTSemaphore semGarbageBarrier;
// Structures for the background loaders
@ -341,13 +343,13 @@ private:
{
using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
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) {}
QueuedFileData(const QueuedFileData&) = default;
QueuedFileData& operator=(const QueuedFileData&) = default;
QueuedFileData(QueuedFileData&&) = default;
QueuedFileData& operator=(QueuedFileData&&) = default;
FileId id {};
std::weak_ptr<FileId> id;
FileData* data { nullptr };
TimePoint queuedTime {};
};

View file

@ -75,7 +75,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
else
filename = absl::StrCat(defaultPath, absl::StrReplaceAll(trimmedSample, { { "\\", "/" } }));
sampleId = FileId(std::move(filename), sampleId.isReverse());
*sampleId = FileId(std::move(filename), sampleId->isReverse());
}
break;
case hash("sample_quality"):
@ -88,7 +88,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
}
break;
case hash("direction"):
sampleId = sampleId.reversed(opcode.value == "reverse");
*sampleId = sampleId->reversed(opcode.value == "reverse");
break;
case hash("delay"):
setValueFromOpcode(opcode, delay, Default::delayRange);

View file

@ -78,7 +78,7 @@ struct Region {
* @return true
* @return false
*/
bool isGenerator() const noexcept { return sampleId.filename().size() > 0 ? sampleId.filename()[0] == '*' : false; }
bool isGenerator() const noexcept { return sampleId->filename().size() > 0 ? sampleId->filename()[0] == '*' : false; }
/**
* @brief Is an oscillator (generator or wavetable)?
*
@ -308,7 +308,7 @@ struct Region {
const NumericId<Region> id;
// Sound source: sample playback
FileId sampleId {}; // Sample
std::shared_ptr<FileId> sampleId { new FileId }; // Sample
absl::optional<int> sampleQuality {};
float delay { Default::delay }; // delay
float delayRandom { Default::delayRandom }; // delay_random

View file

@ -514,7 +514,7 @@ void sfz::Synth::finalizeSfzLoad()
size_t currentRegionCount = regions.size();
auto removeCurrentRegion = [this, &currentRegionIndex, &currentRegionCount]() {
DBG("Removing the region with sample " << regions[currentRegionIndex]->sampleId);
DBG("Removing the region with sample " << *regions[currentRegionIndex]->sampleId);
regions.erase(regions.begin() + currentRegionIndex);
--currentRegionCount;
};
@ -534,12 +534,12 @@ void sfz::Synth::finalizeSfzLoad()
absl::optional<FileInformation> fileInformation;
if (!region->isGenerator()) {
if (!resources.filePool.checkSampleId(region->sampleId)) {
if (!resources.filePool.checkSampleId(*region->sampleId)) {
removeCurrentRegion();
continue;
}
fileInformation = resources.filePool.getFileInformation(region->sampleId);
fileInformation = resources.filePool.getFileInformation(*region->sampleId);
if (!fileInformation) {
removeCurrentRegion();
continue;
@ -583,11 +583,11 @@ void sfz::Synth::finalizeSfzLoad()
return Default::offsetCCRange.clamp(sumOffsetCC);
}();
if (!resources.filePool.preloadFile(region->sampleId, maxOffset))
if (!resources.filePool.preloadFile(*region->sampleId, maxOffset))
removeCurrentRegion();
}
else if (!region->isGenerator()) {
if (!resources.wavePool.createFileWave(resources.filePool, std::string(region->sampleId.filename()))) {
if (!resources.wavePool.createFileWave(resources.filePool, std::string(region->sampleId->filename()))) {
removeCurrentRegion();
continue;
}

View file

@ -64,9 +64,9 @@ void sfz::Voice::startVoice(Region* region, int delay, const TriggerEvent& event
if (region->isOscillator()) {
const WavetableMulti* wave = nullptr;
if (!region->isGenerator())
wave = resources.wavePool.getFileWave(region->sampleId.filename());
wave = resources.wavePool.getFileWave(region->sampleId->filename());
else {
switch (hash(region->sampleId.filename())) {
switch (hash(region->sampleId->filename())) {
default:
case hash("*silence"):
break;
@ -658,7 +658,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
DBG("[sfizz] Underflow: source available samples "
<< source.getNumFrames() << "/"
<< currentPromise->information.end
<< " for sample " << region->sampleId);
<< " for sample " << *region->sampleId);
}
#endif
if (!region->flexAmpEG) {
@ -891,13 +891,13 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
const auto leftSpan = buffer.getSpan(0);
const auto rightSpan = buffer.getSpan(1);
if (region->sampleId.filename() == "*noise") {
if (region->sampleId->filename() == "*noise") {
auto gen = [&]() {
return uniformNoiseDist(Random::randomGenerator);
};
absl::c_generate(leftSpan, gen);
absl::c_generate(rightSpan, gen);
} else if (region->sampleId.filename() == "*gnoise") {
} else if (region->sampleId->filename() == "*gnoise") {
// You need to wrap in a lambda, otherwise generate will
// make a copy of the gaussian distribution *along with its state*
// leading to periodic behavior....

View file

@ -23,7 +23,7 @@ TEST_CASE("[Files] Single region (regions_one.sfz)")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_one.sfz");
REQUIRE(synth.getNumRegions() == 1);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav");
}
@ -32,9 +32,9 @@ TEST_CASE("[Files] Multiple regions (regions_many.sfz)")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_many.sfz");
REQUIRE(synth.getNumRegions() == 3);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId.filename() == "dummy.2.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId->filename() == "dummy.2.wav");
}
TEST_CASE("[Files] Basic opcodes (regions_opcodes.sfz)")
@ -58,8 +58,8 @@ TEST_CASE("[Files] (regions_bad.sfz)")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_bad.sfz");
REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy.wav");
}
TEST_CASE("[Files] Local include")
@ -67,7 +67,7 @@ TEST_CASE("[Files] Local include")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_local.sfz");
REQUIRE(synth.getNumRegions() == 1);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav");
}
TEST_CASE("[Files] Multiple includes")
@ -75,8 +75,8 @@ TEST_CASE("[Files] Multiple includes")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes.sfz");
REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy2.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy2.wav");
}
TEST_CASE("[Files] Multiple includes with comments")
@ -84,8 +84,8 @@ TEST_CASE("[Files] Multiple includes with comments")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes_with_comments.sfz");
REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy2.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy2.wav");
}
TEST_CASE("[Files] Subdir include")
@ -93,7 +93,7 @@ TEST_CASE("[Files] Subdir include")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir.sfz");
REQUIRE(synth.getNumRegions() == 1);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy_subdir.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy_subdir.wav");
}
TEST_CASE("[Files] Subdir include Win")
@ -101,7 +101,7 @@ TEST_CASE("[Files] Subdir include Win")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir_win.sfz");
REQUIRE(synth.getNumRegions() == 1);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy_subdir.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy_subdir.wav");
}
TEST_CASE("[Files] Recursive include (with include guard)")
@ -111,8 +111,8 @@ TEST_CASE("[Files] Recursive include (with include guard)")
parser.setRecursiveIncludeGuardEnabled(true);
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_recursive.sfz");
REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy_recursive2.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy_recursive1.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy_recursive2.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy_recursive1.wav");
}
TEST_CASE("[Files] Include loops (with include guard)")
@ -122,8 +122,8 @@ TEST_CASE("[Files] Include loops (with include guard)")
parser.setRecursiveIncludeGuardEnabled(true);
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_loop.sfz");
REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy_loop2.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy_loop1.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy_loop2.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy_loop1.wav");
}
TEST_CASE("[Files] Define test")
@ -209,28 +209,28 @@ TEST_CASE("[Files] Full hierarchy with antislashes")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz");
REQUIRE(synth.getNumRegions() == 8);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(3)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(4)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(5)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(6)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(7)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(3)->sampleId->filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(4)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(5)->sampleId->filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(6)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(7)->sampleId->filename() == "Regions/dummy.1.wav");
}
{
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy_antislash.sfz");
REQUIRE(synth.getNumRegions() == 8);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(3)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(4)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(5)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(6)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(7)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(3)->sampleId->filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(4)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(5)->sampleId->filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(6)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(7)->sampleId->filename() == "Regions/dummy.1.wav");
}
}
@ -249,10 +249,10 @@ TEST_CASE("[Files] Pizz basic")
REQUIRE(synth.getRegionView(1)->randRange == Range<float>(0.25, 0.5));
REQUIRE(synth.getRegionView(2)->randRange == Range<float>(0.5, 0.75));
REQUIRE(synth.getRegionView(3)->randRange == Range<float>(0.75, 1.0));
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(../Samples/pizz/a0_vl4_rr1.wav)");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == R"(../Samples/pizz/a0_vl4_rr2.wav)");
REQUIRE(synth.getRegionView(2)->sampleId.filename() == R"(../Samples/pizz/a0_vl4_rr3.wav)");
REQUIRE(synth.getRegionView(3)->sampleId.filename() == R"(../Samples/pizz/a0_vl4_rr4.wav)");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(../Samples/pizz/a0_vl4_rr1.wav)");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == R"(../Samples/pizz/a0_vl4_rr2.wav)");
REQUIRE(synth.getRegionView(2)->sampleId->filename() == R"(../Samples/pizz/a0_vl4_rr3.wav)");
REQUIRE(synth.getRegionView(3)->sampleId->filename() == R"(../Samples/pizz/a0_vl4_rr4.wav)");
}
TEST_CASE("[Files] Channels (channels.sfz)")
@ -260,9 +260,9 @@ TEST_CASE("[Files] Channels (channels.sfz)")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/channels.sfz");
REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "mono_sample.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "mono_sample.wav");
REQUIRE(!synth.getRegionView(0)->isStereo());
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "stereo_sample.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "stereo_sample.wav");
REQUIRE(synth.getRegionView(1)->isStereo());
}
@ -277,7 +277,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// generator only
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "*sine");
REQUIRE(region->sampleId->filename() == "*sine");
REQUIRE(!region->isStereo());
REQUIRE(region->isGenerator());
REQUIRE(region->isOscillator());
@ -285,7 +285,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// generator with multi
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "*sine");
REQUIRE(region->sampleId->filename() == "*sine");
REQUIRE(region->isStereo());
REQUIRE(region->isGenerator());
REQUIRE(region->isOscillator());
@ -293,7 +293,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// explicit wavetable
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "ramp_wave.wav");
REQUIRE(region->sampleId->filename() == "ramp_wave.wav");
REQUIRE(!region->isStereo());
REQUIRE(!region->isGenerator());
REQUIRE(region->isOscillator());
@ -301,7 +301,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// explicit wavetable with multi
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "ramp_wave.wav");
REQUIRE(region->sampleId->filename() == "ramp_wave.wav");
REQUIRE(region->isStereo());
REQUIRE(!region->isGenerator());
REQUIRE(region->isOscillator());
@ -309,7 +309,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// explicit disabled wavetable
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "ramp_wave.wav");
REQUIRE(region->sampleId->filename() == "ramp_wave.wav");
REQUIRE(!region->isStereo());
REQUIRE(!region->isGenerator());
REQUIRE(!region->isOscillator());
@ -317,7 +317,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// explicit disabled wavetable with multi
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "ramp_wave.wav");
REQUIRE(region->sampleId->filename() == "ramp_wave.wav");
REQUIRE(!region->isStereo());
REQUIRE(!region->isGenerator());
REQUIRE(!region->isOscillator());
@ -325,7 +325,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// implicit wavetable (sound file < 3000 frames)
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "ramp_wave.wav");
REQUIRE(region->sampleId->filename() == "ramp_wave.wav");
REQUIRE(!region->isStereo());
REQUIRE(!region->isGenerator());
REQUIRE(region->isOscillator());
@ -333,7 +333,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// implicit non-wavetable (sound file >= 3000 frames)
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "snare.wav");
REQUIRE(region->sampleId->filename() == "snare.wav");
REQUIRE(!region->isStereo());
REQUIRE(!region->isGenerator());
REQUIRE(!region->isOscillator());
@ -341,7 +341,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// generator with multi=1 (single)
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "*sine");
REQUIRE(region->sampleId->filename() == "*sine");
REQUIRE(!region->isStereo());
REQUIRE(region->isGenerator());
REQUIRE(region->isOscillator());
@ -349,7 +349,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
// generator with multi=2 (ring modulation)
region = synth.getRegionView(regionNumber++);
REQUIRE(region->sampleId.filename() == "*sine");
REQUIRE(region->sampleId->filename() == "*sine");
REQUIRE(!region->isStereo());
REQUIRE(region->isGenerator());
REQUIRE(region->isOscillator());
@ -424,7 +424,7 @@ TEST_CASE("[Files] Specific bug: relative path with backslashes")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/win_backslashes.sfz");
REQUIRE(synth.getNumRegions() == 1);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(Xylo/Subfolder/closedhat.wav)");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(Xylo/Subfolder/closedhat.wav)");
}
TEST_CASE("[Files] Default path")
@ -432,10 +432,10 @@ TEST_CASE("[Files] Default path")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path.sfz");
REQUIRE(synth.getNumRegions() == 4);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(DefaultPath/SubPath1/sample1.wav)");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == R"(DefaultPath/SubPath2/sample2.wav)");
REQUIRE(synth.getRegionView(2)->sampleId.filename() == R"(DefaultPath/SubPath1/sample1.wav)");
REQUIRE(synth.getRegionView(3)->sampleId.filename() == R"(DefaultPath/SubPath2/sample2.wav)");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(DefaultPath/SubPath1/sample1.wav)");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == R"(DefaultPath/SubPath2/sample2.wav)");
REQUIRE(synth.getRegionView(2)->sampleId->filename() == R"(DefaultPath/SubPath1/sample1.wav)");
REQUIRE(synth.getRegionView(3)->sampleId->filename() == R"(DefaultPath/SubPath2/sample2.wav)");
}
TEST_CASE("[Files] Default path reset when calling loadSfzFile again")
@ -445,7 +445,7 @@ TEST_CASE("[Files] Default path reset when calling loadSfzFile again")
REQUIRE(synth.getNumRegions() == 4);
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_reset.sfz");
REQUIRE(synth.getNumRegions() == 1);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(DefaultPath/SubPath2/sample2.wav)");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(DefaultPath/SubPath2/sample2.wav)");
}
TEST_CASE("[Files] Default path is ignored for generators")
@ -453,7 +453,7 @@ TEST_CASE("[Files] Default path is ignored for generators")
Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_generator.sfz");
REQUIRE(synth.getNumRegions() == 1);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(*sine)");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(*sine)");
}
TEST_CASE("[Files] Set CC applies properly")
@ -616,10 +616,10 @@ TEST_CASE("[Files] Case sentitiveness")
Synth synth;
synth.loadSfzFile(sfzFilePath);
REQUIRE(synth.getNumRegions() == 4);
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy1.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(2)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(3)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy1.wav");
REQUIRE(synth.getRegionView(1)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(2)->sampleId->filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(3)->sampleId->filename() == "Regions/dummy.wav");
}
}

View file

@ -23,18 +23,18 @@ TEST_CASE("[Region] Parsing opcodes")
SECTION("sample")
{
REQUIRE(region.sampleId.filename() == "");
REQUIRE(region.sampleId->filename() == "");
region.parseOpcode({ "sample", "dummy.wav" });
REQUIRE(region.sampleId.filename() == "dummy.wav");
REQUIRE(region.sampleId->filename() == "dummy.wav");
}
SECTION("direction")
{
REQUIRE(!region.sampleId.isReverse());
REQUIRE(!region.sampleId->isReverse());
region.parseOpcode({ "direction", "reverse" });
REQUIRE(region.sampleId.isReverse());
REQUIRE(region.sampleId->isReverse());
region.parseOpcode({ "direction", "forward" });
REQUIRE(!region.sampleId.isReverse());
REQUIRE(!region.sampleId->isReverse());
}
SECTION("delay")

View file

@ -698,13 +698,13 @@ TEST_CASE("[Synth] Release (basic behavior with sample)")
)");
synth.noteOn(0, 62, 85);
REQUIRE( numPlayingVoices(synth) == 1 );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId.filename() == "*sine" );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "*sine" );
synth.noteOff(0, 62, 85);
REQUIRE( numPlayingVoices(synth) == 1 );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId.filename() == "closedhat.wav" );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "closedhat.wav" );
synth.renderBlock(buffer);
REQUIRE( numPlayingVoices(synth) == 1 );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId.filename() == "closedhat.wav" );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "closedhat.wav" );
}
TEST_CASE("[Synth] Release key (basic behavior with sample)")
@ -720,7 +720,7 @@ TEST_CASE("[Synth] Release key (basic behavior with sample)")
REQUIRE( numPlayingVoices(synth) == 1 );
synth.renderBlock(buffer);
REQUIRE( numPlayingVoices(synth) == 1 );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId.filename() == "closedhat.wav" );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "closedhat.wav" );
}
TEST_CASE("[Synth] Release key (pedal)")
@ -1338,15 +1338,15 @@ TEST_CASE("[Synth] Off by with CC switches")
)");
synth.noteOn(0, 60, 85);
REQUIRE( numPlayingVoices(synth) == 1 );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId.filename() == "*saw" );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "*saw" );
synth.cc(0, 4, 127);
synth.noteOn(0, 60, 85);
REQUIRE( numPlayingVoices(synth) == 1 );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId.filename() == "*triangle" );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "*triangle" );
synth.cc(0, 4, 0);
synth.noteOn(0, 60, 85);
REQUIRE( numPlayingVoices(synth) == 1 );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId.filename() == "*saw" );
REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "*saw" );
}
TEST_CASE("[Synth] Initial values of CC")