Merge pull request #190 from jpcima/fileid-rt

Prevent FileId allocating memory from Voice init
This commit is contained in:
JP Cimalando 2020-04-19 02:33:30 +02:00 committed by GitHub
commit f16821b06c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 157 additions and 96 deletions

View file

@ -10,15 +10,17 @@
size_t std::hash<sfz::FileId>::operator()(const sfz::FileId &id) const size_t std::hash<sfz::FileId>::operator()(const sfz::FileId &id) const
{ {
uint64_t h = ::hash(id.filename); uint64_t h = ::hash(id.filename());
h = ::hash(id.reverse ? "!" : "", h); h = ::hash(id.isReverse() ? "!" : "", h);
return h; return h;
} }
std::ostream &operator<<(std::ostream &os, const sfz::FileId &fileId) std::ostream &operator<<(std::ostream &os, const sfz::FileId &fileId)
{ {
os << fileId.filename; os << fileId.filename();
if (fileId.reverse) if (fileId.isReverse())
os << " (reverse)"; os << " (reverse)";
return os; return os;
} }
const std::string sfz::FileId::emptyFilename;

View file

@ -6,6 +6,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <memory>
#include <iosfwd> #include <iosfwd>
namespace sfz { namespace sfz {
@ -14,9 +15,6 @@ namespace sfz {
* @brief Sample file identifier within a file pool. * @brief Sample file identifier within a file pool.
*/ */
struct FileId { struct FileId {
std::string filename;
bool reverse = false;
/** /**
* @brief Construct a null identifier. * @brief Construct a null identifier.
*/ */
@ -30,11 +28,46 @@ struct FileId {
* @param filename * @param filename
* @param reverse * @param reverse
*/ */
FileId(std::string filename, bool reverse = false) explicit FileId(std::string filename, bool reverse = false)
: filename(std::move(filename)), reverse(reverse) : filenameBuffer(new std::string(std::move(filename))),
reverse(reverse)
{ {
} }
/**
* @brief Make an identifier which is a clone of the callee, except with the
* reverse flag passed as parameter.
*
* @param reverse
*/
FileId reversed(bool reverse = true)
{
FileId id;
id.filenameBuffer = filenameBuffer;
id.reverse = reverse;
return id;
}
/**
* @brief Get the file name of this identifier.
*
* @return file name
*/
const std::string &filename() const noexcept
{
return filenameBuffer ? *filenameBuffer : emptyFilename;
}
/**
* @brief Get whether the identified file is reversed.
*
* @return bool
*/
bool isReverse() const noexcept
{
return reverse;
}
/** /**
* @brief Check equality with another identifier. * @brief Check equality with another identifier.
* *
@ -42,7 +75,7 @@ struct FileId {
*/ */
bool operator==(const FileId &other) const bool operator==(const FileId &other) const
{ {
return reverse == other.reverse && filename == other.filename; return reverse == other.reverse && filename() == other.filename();
} }
/** /**
@ -54,6 +87,11 @@ struct FileId {
{ {
return !operator==(other); return !operator==(other);
} }
private:
std::shared_ptr<std::string> filenameBuffer;
bool reverse = false;
static const std::string emptyFilename;
}; };
} }

View file

@ -190,9 +190,18 @@ bool sfz::FilePool::checkSample(std::string& filename) const noexcept
#endif #endif
} }
bool sfz::FilePool::checkSampleId(FileId& fileId) const noexcept
{
std::string filename = fileId.filename();
bool result = checkSample(filename);
if (result)
fileId = FileId(std::move(filename), fileId.isReverse());
return result;
}
absl::optional<sfz::FileInformation> sfz::FilePool::getFileInformation(const FileId& fileId) noexcept absl::optional<sfz::FileInformation> sfz::FilePool::getFileInformation(const FileId& fileId) noexcept
{ {
const fs::path file { rootDirectory / fileId.filename }; const fs::path file { rootDirectory / fileId.filename() };
if (!fs::exists(file)) if (!fs::exists(file))
return {}; return {};
@ -208,7 +217,7 @@ absl::optional<sfz::FileInformation> sfz::FilePool::getFileInformation(const Fil
returnedValue.sampleRate = static_cast<double>(sndFile.samplerate()); returnedValue.sampleRate = static_cast<double>(sndFile.samplerate());
returnedValue.numChannels = sndFile.channels(); returnedValue.numChannels = sndFile.channels();
if (!fileId.reverse) { if (!fileId.isReverse()) {
SF_INSTRUMENT instrumentInfo; SF_INSTRUMENT instrumentInfo;
sndFile.command(SFC_GET_INSTRUMENT, &instrumentInfo, sizeof(instrumentInfo)); sndFile.command(SFC_GET_INSTRUMENT, &instrumentInfo, sizeof(instrumentInfo));
if (instrumentInfo.loop_count > 0) { if (instrumentInfo.loop_count > 0) {
@ -229,7 +238,7 @@ bool sfz::FilePool::preloadFile(const FileId& fileId, uint32_t maxOffset) noexce
if (!fileInformation) if (!fileInformation)
return false; return false;
const fs::path file { rootDirectory / fileId.filename }; const fs::path file { rootDirectory / fileId.filename() };
SndfileHandle sndFile(file.string().c_str()); SndfileHandle sndFile(file.string().c_str());
// FIXME: Large offsets will require large preloading; is this OK in practice? Apparently sforzando does the same // FIXME: Large offsets will require large preloading; is this OK in practice? Apparently sforzando does the same
@ -244,12 +253,12 @@ bool sfz::FilePool::preloadFile(const FileId& fileId, uint32_t maxOffset) noexce
const auto existingFile = preloadedFiles.find(fileId); const auto existingFile = preloadedFiles.find(fileId);
if (existingFile != preloadedFiles.end()) { if (existingFile != preloadedFiles.end()) {
if (framesToLoad > existingFile->second.preloadedData->getNumFrames()) { if (framesToLoad > existingFile->second.preloadedData->getNumFrames()) {
preloadedFiles[fileId].preloadedData = readFromFile<float>(sndFile, framesToLoad, oversamplingFactor, fileId.reverse); preloadedFiles[fileId].preloadedData = readFromFile<float>(sndFile, framesToLoad, oversamplingFactor, fileId.isReverse());
} }
} else { } else {
fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate()); fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate());
FileDataHandle handle { FileDataHandle handle {
readFromFile<float>(sndFile, framesToLoad, oversamplingFactor, fileId.reverse), readFromFile<float>(sndFile, framesToLoad, oversamplingFactor, fileId.isReverse()),
*fileInformation *fileInformation
}; };
preloadedFiles.insert_or_assign(fileId, handle); preloadedFiles.insert_or_assign(fileId, handle);
@ -263,7 +272,7 @@ absl::optional<sfz::FileDataHandle> sfz::FilePool::loadFile(const FileId& fileId
if (!fileInformation) if (!fileInformation)
return {}; return {};
const fs::path file { rootDirectory / fileId.filename }; const fs::path file { rootDirectory / fileId.filename() };
SndfileHandle sndFile(file.string().c_str()); SndfileHandle sndFile(file.string().c_str());
// FIXME: Large offsets will require large preloading; is this OK in practice? Apparently sforzando does the same // FIXME: Large offsets will require large preloading; is this OK in practice? Apparently sforzando does the same
@ -274,7 +283,7 @@ absl::optional<sfz::FileDataHandle> sfz::FilePool::loadFile(const FileId& fileId
} else { } else {
fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate()); fileInformation->sampleRate = static_cast<float>(oversamplingFactor) * static_cast<float>(sndFile.samplerate());
FileDataHandle handle { FileDataHandle handle {
readFromFile<float>(sndFile, frames, oversamplingFactor, fileId.reverse), readFromFile<float>(sndFile, frames, oversamplingFactor, fileId.isReverse()),
*fileInformation *fileInformation
}; };
loadedFiles.insert_or_assign(fileId, handle); loadedFiles.insert_or_assign(fileId, handle);
@ -322,9 +331,9 @@ void sfz::FilePool::setPreloadSize(uint32_t preloadSize) noexcept
for (auto& preloadedFile : preloadedFiles) { for (auto& preloadedFile : preloadedFiles) {
const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / static_cast<int>(oversamplingFactor); const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / static_cast<int>(oversamplingFactor);
const auto maxOffset = numFrames > this->preloadSize ? static_cast<uint32_t>(numFrames) - this->preloadSize : 0; const auto maxOffset = numFrames > this->preloadSize ? static_cast<uint32_t>(numFrames) - this->preloadSize : 0;
fs::path file { rootDirectory / preloadedFile.first.filename }; fs::path file { rootDirectory / preloadedFile.first.filename() };
SndfileHandle sndFile(file.string().c_str()); SndfileHandle sndFile(file.string().c_str());
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, oversamplingFactor, preloadedFile.first.reverse); preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, oversamplingFactor, preloadedFile.first.isReverse());
} }
this->preloadSize = preloadSize; this->preloadSize = preloadSize;
} }
@ -372,7 +381,7 @@ void sfz::FilePool::loadingThread() noexcept
const auto loadStartTime = std::chrono::high_resolution_clock::now(); const auto loadStartTime = std::chrono::high_resolution_clock::now();
const auto waitDuration = loadStartTime - promise->creationTime; const auto waitDuration = loadStartTime - promise->creationTime;
const fs::path file { rootDirectory / promise->fileId.filename }; const fs::path file { rootDirectory / promise->fileId.filename() };
SndfileHandle sndFile(file.string().c_str()); SndfileHandle sndFile(file.string().c_str());
if (sndFile.error() != 0) { if (sndFile.error() != 0) {
DBG("[sfizz] libsndfile errored for " << promise->fileId << " with message " << sndFile.strError()); DBG("[sfizz] libsndfile errored for " << promise->fileId << " with message " << sndFile.strError());
@ -380,10 +389,10 @@ void sfz::FilePool::loadingThread() noexcept
continue; continue;
} }
const auto frames = static_cast<uint32_t>(sndFile.frames()); const auto frames = static_cast<uint32_t>(sndFile.frames());
streamFromFile<float>(sndFile, frames, oversamplingFactor, promise->fileId.reverse, promise->fileData, &promise->availableFrames); streamFromFile<float>(sndFile, frames, oversamplingFactor, promise->fileId.isReverse(), promise->fileData, &promise->availableFrames);
promise->dataStatus = FilePromise::DataStatus::Ready; promise->dataStatus = FilePromise::DataStatus::Ready;
const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime; const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime;
logger.logFileTime(waitDuration, loadDuration, frames, promise->fileId.filename); logger.logFileTime(waitDuration, loadDuration, frames, promise->fileId.filename());
threadsLoading--; threadsLoading--;
@ -451,9 +460,9 @@ void sfz::FilePool::setOversamplingFactor(sfz::Oversampling factor) noexcept
for (auto& preloadedFile : preloadedFiles) { for (auto& preloadedFile : preloadedFiles) {
const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / static_cast<int>(this->oversamplingFactor); const auto numFrames = preloadedFile.second.preloadedData->getNumFrames() / static_cast<int>(this->oversamplingFactor);
const uint32_t maxOffset = numFrames > this->preloadSize ? static_cast<uint32_t>(numFrames) - this->preloadSize : 0; const uint32_t maxOffset = numFrames > this->preloadSize ? static_cast<uint32_t>(numFrames) - this->preloadSize : 0;
fs::path file { rootDirectory / preloadedFile.first.filename }; fs::path file { rootDirectory / preloadedFile.first.filename() };
SndfileHandle sndFile(file.string().c_str()); SndfileHandle sndFile(file.string().c_str());
preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, factor, preloadedFile.first.reverse); preloadedFile.second.preloadedData = readFromFile<float>(sndFile, preloadSize + maxOffset, factor, preloadedFile.first.isReverse());
preloadedFile.second.information.sampleRate *= samplerateChange; preloadedFile.second.information.sampleRate *= samplerateChange;
} }

View file

@ -189,6 +189,15 @@ public:
*/ */
bool checkSample(std::string& filename) const noexcept; bool checkSample(std::string& filename) const noexcept;
/**
* @brief Check that the sample exists. If not, try to find it in a case insensitive way.
*
* @param fileId the sample file identifier; may be updated by the method
* @return true if the sample exists or was updated properly
* @return false if no sample was found even with a case insensitive search
*/
bool checkSampleId(FileId& fileId) const noexcept;
/** /**
* @brief Clear all preloaded files. * @brief Clear all preloaded files.
* *

View file

@ -41,14 +41,17 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
if (trimmedSample.empty()) if (trimmedSample.empty())
break; break;
std::string filename;
if (trimmedSample[0] == '*') if (trimmedSample[0] == '*')
sampleId.filename = std::string(trimmedSample); filename = std::string(trimmedSample);
else else
sampleId.filename = absl::StrCat(defaultPath, absl::StrReplaceAll(trimmedSample, { { "\\", "/" } })); filename = absl::StrCat(defaultPath, absl::StrReplaceAll(trimmedSample, { { "\\", "/" } }));
sampleId = FileId(std::move(filename), sampleId.isReverse());
} }
break; break;
case hash("direction"): case hash("direction"):
sampleId.reverse = opcode.value == "reverse"; sampleId = sampleId.reversed(opcode.value == "reverse");
break; break;
case hash("delay"): case hash("delay"):
setValueFromOpcode(opcode, delay, Default::delayRange); setValueFromOpcode(opcode, delay, Default::delayRange);

View file

@ -58,7 +58,7 @@ struct Region {
* @return true * @return true
* @return false * @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 stereo (has stereo sample or is unison oscillator)? * @brief Is stereo (has stereo sample or is unison oscillator)?
* *

View file

@ -350,7 +350,7 @@ bool sfz::Synth::loadSfzFile(const fs::path& file)
auto region = currentRegion->get(); auto region = currentRegion->get();
if (!region->oscillator && !region->isGenerator()) { if (!region->oscillator && !region->isGenerator()) {
if (!resources.filePool.checkSample(region->sampleId.filename)) { if (!resources.filePool.checkSampleId(region->sampleId)) {
removeCurrentRegion(); removeCurrentRegion();
continue; continue;
} }
@ -391,12 +391,12 @@ bool sfz::Synth::loadSfzFile(const fs::path& file)
removeCurrentRegion(); removeCurrentRegion();
} }
else if (region->oscillator && !region->isGenerator()) { else if (region->oscillator && !region->isGenerator()) {
if (!resources.filePool.checkSample(region->sampleId.filename)) { if (!resources.filePool.checkSampleId(region->sampleId)) {
removeCurrentRegion(); removeCurrentRegion();
continue; continue;
} }
if (!resources.wavePool.createFileWave(resources.filePool, region->sampleId.filename)) { if (!resources.wavePool.createFileWave(resources.filePool, std::string(region->sampleId.filename()))) {
removeCurrentRegion(); removeCurrentRegion();
continue; continue;
} }

View file

@ -40,7 +40,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
if (region->isGenerator()) { if (region->isGenerator()) {
const WavetableMulti* wave = nullptr; const WavetableMulti* wave = nullptr;
switch (hash(region->sampleId.filename)) { switch (hash(region->sampleId.filename())) {
default: default:
case hash("*silence"): case hash("*silence"):
break; break;
@ -64,7 +64,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
} }
setupOscillatorUnison(); setupOscillatorUnison();
} else if (region->oscillator) { } else if (region->oscillator) {
const WavetableMulti* wave = resources.wavePool.getFileWave(region->sampleId.filename); const WavetableMulti* wave = resources.wavePool.getFileWave(region->sampleId.filename());
for (WavetableOscillator& osc : waveOscillators) { for (WavetableOscillator& osc : waveOscillators) {
osc.setWavetable(wave); osc.setWavetable(wave);
osc.setPhase(region->getPhase()); osc.setPhase(region->getPhase());
@ -529,7 +529,7 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
const auto leftSpan = buffer.getSpan(0); const auto leftSpan = buffer.getSpan(0);
const auto rightSpan = buffer.getSpan(1); const auto rightSpan = buffer.getSpan(1);
if (region->sampleId.filename == "*noise") { if (region->sampleId.filename() == "*noise") {
absl::c_generate(leftSpan, [&](){ return noiseDist(Random::randomGenerator); }); absl::c_generate(leftSpan, [&](){ return noiseDist(Random::randomGenerator); });
absl::c_generate(rightSpan, [&](){ return noiseDist(Random::randomGenerator); }); absl::c_generate(rightSpan, [&](){ return noiseDist(Random::randomGenerator); });
} else { } else {

View file

@ -365,7 +365,7 @@ bool WavetablePool::createFileWave(FilePool& filePool, const std::string& filena
if (_fileWaves.contains(filename)) if (_fileWaves.contains(filename))
return true; return true;
auto fileHandle = filePool.loadFile(filename); auto fileHandle = filePool.loadFile(FileId(filename));
if (!fileHandle) if (!fileHandle)
return false; return false;

View file

@ -19,7 +19,7 @@ TEST_CASE("[Files] Single region (regions_one.sfz)")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_one.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_one.sfz");
REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getNumRegions() == 1);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "dummy.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
} }
@ -28,9 +28,9 @@ TEST_CASE("[Files] Multiple regions (regions_many.sfz)")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_many.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_many.sfz");
REQUIRE(synth.getNumRegions() == 3); REQUIRE(synth.getNumRegions() == 3);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "dummy.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "dummy.1.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId.filename == "dummy.2.wav"); REQUIRE(synth.getRegionView(2)->sampleId.filename() == "dummy.2.wav");
} }
TEST_CASE("[Files] Basic opcodes (regions_opcodes.sfz)") TEST_CASE("[Files] Basic opcodes (regions_opcodes.sfz)")
@ -54,8 +54,8 @@ TEST_CASE("[Files] (regions_bad.sfz)")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_bad.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_bad.sfz");
REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "dummy.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "dummy.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy.wav");
} }
TEST_CASE("[Files] Local include") TEST_CASE("[Files] Local include")
@ -63,7 +63,7 @@ TEST_CASE("[Files] Local include")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_local.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_local.sfz");
REQUIRE(synth.getNumRegions() == 1); 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") TEST_CASE("[Files] Multiple includes")
@ -71,8 +71,8 @@ TEST_CASE("[Files] Multiple includes")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes.sfz");
REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "dummy.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "dummy2.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy2.wav");
} }
TEST_CASE("[Files] Multiple includes with comments") TEST_CASE("[Files] Multiple includes with comments")
@ -80,8 +80,8 @@ TEST_CASE("[Files] Multiple includes with comments")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes_with_comments.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes_with_comments.sfz");
REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "dummy.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "dummy2.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy2.wav");
} }
TEST_CASE("[Files] Subdir include") TEST_CASE("[Files] Subdir include")
@ -89,7 +89,7 @@ TEST_CASE("[Files] Subdir include")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir.sfz");
REQUIRE(synth.getNumRegions() == 1); 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") TEST_CASE("[Files] Subdir include Win")
@ -97,7 +97,7 @@ TEST_CASE("[Files] Subdir include Win")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir_win.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir_win.sfz");
REQUIRE(synth.getNumRegions() == 1); 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)") TEST_CASE("[Files] Recursive include (with include guard)")
@ -107,8 +107,8 @@ TEST_CASE("[Files] Recursive include (with include guard)")
parser.setRecursiveIncludeGuardEnabled(true); parser.setRecursiveIncludeGuardEnabled(true);
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_recursive.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_recursive.sfz");
REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "dummy_recursive2.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy_recursive2.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "dummy_recursive1.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy_recursive1.wav");
} }
TEST_CASE("[Files] Include loops (with include guard)") TEST_CASE("[Files] Include loops (with include guard)")
@ -118,8 +118,8 @@ TEST_CASE("[Files] Include loops (with include guard)")
parser.setRecursiveIncludeGuardEnabled(true); parser.setRecursiveIncludeGuardEnabled(true);
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_loop.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_loop.sfz");
REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getNumRegions() == 2);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "dummy_loop2.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy_loop2.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "dummy_loop1.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "dummy_loop1.wav");
} }
TEST_CASE("[Files] Define test") TEST_CASE("[Files] Define test")
@ -205,28 +205,28 @@ TEST_CASE("[Files] Full hierarchy with antislashes")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz");
REQUIRE(synth.getNumRegions() == 8); REQUIRE(synth.getNumRegions() == 8);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "Regions/dummy.1.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(2)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(3)->sampleId.filename == "Regions/dummy.1.wav"); REQUIRE(synth.getRegionView(3)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(4)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(4)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(5)->sampleId.filename == "Regions/dummy.1.wav"); REQUIRE(synth.getRegionView(5)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(6)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(6)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(7)->sampleId.filename == "Regions/dummy.1.wav"); REQUIRE(synth.getRegionView(7)->sampleId.filename() == "Regions/dummy.1.wav");
} }
{ {
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy_antislash.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy_antislash.sfz");
REQUIRE(synth.getNumRegions() == 8); REQUIRE(synth.getNumRegions() == 8);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "Regions/dummy.1.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(2)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(2)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(3)->sampleId.filename == "Regions/dummy.1.wav"); REQUIRE(synth.getRegionView(3)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(4)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(4)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(5)->sampleId.filename == "Regions/dummy.1.wav"); REQUIRE(synth.getRegionView(5)->sampleId.filename() == "Regions/dummy.1.wav");
REQUIRE(synth.getRegionView(6)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(6)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(7)->sampleId.filename == "Regions/dummy.1.wav"); REQUIRE(synth.getRegionView(7)->sampleId.filename() == "Regions/dummy.1.wav");
} }
} }
@ -245,10 +245,10 @@ TEST_CASE("[Files] Pizz basic")
REQUIRE(synth.getRegionView(1)->randRange == sfz::Range<float>(0.25, 0.5)); REQUIRE(synth.getRegionView(1)->randRange == sfz::Range<float>(0.25, 0.5));
REQUIRE(synth.getRegionView(2)->randRange == sfz::Range<float>(0.5, 0.75)); REQUIRE(synth.getRegionView(2)->randRange == sfz::Range<float>(0.5, 0.75));
REQUIRE(synth.getRegionView(3)->randRange == sfz::Range<float>(0.75, 1.0)); REQUIRE(synth.getRegionView(3)->randRange == sfz::Range<float>(0.75, 1.0));
REQUIRE(synth.getRegionView(0)->sampleId.filename == R"(../Samples/pizz/a0_vl4_rr1.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(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(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(3)->sampleId.filename() == R"(../Samples/pizz/a0_vl4_rr4.wav)");
} }
TEST_CASE("[Files] Channels (channels.sfz)") TEST_CASE("[Files] Channels (channels.sfz)")
@ -256,9 +256,9 @@ TEST_CASE("[Files] Channels (channels.sfz)")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/channels.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/channels.sfz");
REQUIRE(synth.getNumRegions() == 2); 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(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()); REQUIRE(synth.getRegionView(1)->isStereo());
} }
@ -268,32 +268,32 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/channels_multi.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/channels_multi.sfz");
REQUIRE(synth.getNumRegions() == 6); REQUIRE(synth.getNumRegions() == 6);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "*sine"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "*sine");
REQUIRE(!synth.getRegionView(0)->isStereo()); REQUIRE(!synth.getRegionView(0)->isStereo());
REQUIRE(synth.getRegionView(0)->isGenerator()); REQUIRE(synth.getRegionView(0)->isGenerator());
REQUIRE(!synth.getRegionView(0)->oscillator); REQUIRE(!synth.getRegionView(0)->oscillator);
REQUIRE(synth.getRegionView(1)->sampleId.filename == "*sine"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "*sine");
REQUIRE(synth.getRegionView(1)->isStereo()); REQUIRE(synth.getRegionView(1)->isStereo());
REQUIRE(synth.getRegionView(1)->isGenerator()); REQUIRE(synth.getRegionView(1)->isGenerator());
REQUIRE(!synth.getRegionView(1)->oscillator); REQUIRE(!synth.getRegionView(1)->oscillator);
REQUIRE(synth.getRegionView(2)->sampleId.filename == "ramp_wave.wav"); REQUIRE(synth.getRegionView(2)->sampleId.filename() == "ramp_wave.wav");
REQUIRE(!synth.getRegionView(2)->isStereo()); REQUIRE(!synth.getRegionView(2)->isStereo());
REQUIRE(!synth.getRegionView(2)->isGenerator()); REQUIRE(!synth.getRegionView(2)->isGenerator());
REQUIRE(synth.getRegionView(2)->oscillator); REQUIRE(synth.getRegionView(2)->oscillator);
REQUIRE(synth.getRegionView(3)->sampleId.filename == "ramp_wave.wav"); REQUIRE(synth.getRegionView(3)->sampleId.filename() == "ramp_wave.wav");
REQUIRE(synth.getRegionView(3)->isStereo()); REQUIRE(synth.getRegionView(3)->isStereo());
REQUIRE(!synth.getRegionView(3)->isGenerator()); REQUIRE(!synth.getRegionView(3)->isGenerator());
REQUIRE(synth.getRegionView(3)->oscillator); REQUIRE(synth.getRegionView(3)->oscillator);
REQUIRE(synth.getRegionView(4)->sampleId.filename == "*sine"); REQUIRE(synth.getRegionView(4)->sampleId.filename() == "*sine");
REQUIRE(!synth.getRegionView(4)->isStereo()); REQUIRE(!synth.getRegionView(4)->isStereo());
REQUIRE(synth.getRegionView(4)->isGenerator()); REQUIRE(synth.getRegionView(4)->isGenerator());
REQUIRE(!synth.getRegionView(4)->oscillator); REQUIRE(!synth.getRegionView(4)->oscillator);
REQUIRE(synth.getRegionView(5)->sampleId.filename == "*sine"); REQUIRE(synth.getRegionView(5)->sampleId.filename() == "*sine");
REQUIRE(!synth.getRegionView(5)->isStereo()); REQUIRE(!synth.getRegionView(5)->isStereo());
REQUIRE(synth.getRegionView(5)->isGenerator()); REQUIRE(synth.getRegionView(5)->isGenerator());
REQUIRE(!synth.getRegionView(5)->oscillator); REQUIRE(!synth.getRegionView(5)->oscillator);
@ -359,7 +359,7 @@ TEST_CASE("[Files] Specific bug: relative path with backslashes")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/win_backslashes.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/win_backslashes.sfz");
REQUIRE(synth.getNumRegions() == 1); 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") TEST_CASE("[Files] Default path")
@ -367,10 +367,10 @@ TEST_CASE("[Files] Default path")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path.sfz");
REQUIRE(synth.getNumRegions() == 4); REQUIRE(synth.getNumRegions() == 4);
REQUIRE(synth.getRegionView(0)->sampleId.filename == R"(DefaultPath/SubPath1/sample1.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(1)->sampleId.filename() == R"(DefaultPath/SubPath2/sample2.wav)");
REQUIRE(synth.getRegionView(2)->sampleId.filename == R"(DefaultPath/SubPath1/sample1.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(3)->sampleId.filename() == R"(DefaultPath/SubPath2/sample2.wav)");
} }
TEST_CASE("[Files] Default path reset when calling loadSfzFile again") TEST_CASE("[Files] Default path reset when calling loadSfzFile again")
@ -380,7 +380,7 @@ TEST_CASE("[Files] Default path reset when calling loadSfzFile again")
REQUIRE(synth.getNumRegions() == 4); REQUIRE(synth.getNumRegions() == 4);
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_reset.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_reset.sfz");
REQUIRE(synth.getNumRegions() == 1); 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") TEST_CASE("[Files] Default path is ignored for generators")
@ -388,7 +388,7 @@ TEST_CASE("[Files] Default path is ignored for generators")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_generator.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_generator.sfz");
REQUIRE(synth.getNumRegions() == 1); 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") TEST_CASE("[Files] Set CC applies properly")
@ -547,10 +547,10 @@ TEST_CASE("[Files] Case sentitiveness")
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(sfzFilePath); synth.loadSfzFile(sfzFilePath);
REQUIRE(synth.getNumRegions() == 4); REQUIRE(synth.getNumRegions() == 4);
REQUIRE(synth.getRegionView(0)->sampleId.filename == "dummy1.wav"); REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy1.wav");
REQUIRE(synth.getRegionView(1)->sampleId.filename == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(1)->sampleId.filename() == "Regions/dummy.wav");
REQUIRE(synth.getRegionView(2)->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(3)->sampleId.filename() == "Regions/dummy.wav");
} }
} }

View file

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