From 0b502b44f13e44dd22b2a3f6675d3aca2a4a59a5 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 3 Oct 2020 10:01:08 +0200 Subject: [PATCH] Don't assume a single for region sets --- src/sfizz/Opcode.h | 2 +- src/sfizz/RegionSet.h | 16 ++++++++++++++++ src/sfizz/Synth.cpp | 38 +++++++++++++++----------------------- src/sfizz/Synth.h | 3 +-- tests/PolyphonyT.cpp | 12 ++++++------ 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index a3132499..a6c3a1d6 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -43,7 +43,7 @@ enum OpcodeCategory { */ enum OpcodeScope { //! unknown scope or other - kOpcodeScopeGeneric, + kOpcodeScopeGeneric = 0, //! global scope kOpcodeScopeGlobal, //! control scope diff --git a/src/sfizz/RegionSet.h b/src/sfizz/RegionSet.h index bbfadce0..4424a030 100644 --- a/src/sfizz/RegionSet.h +++ b/src/sfizz/RegionSet.h @@ -8,6 +8,7 @@ #include "Region.h" #include "Voice.h" +#include "Opcode.h" #include "SwapAndPop.h" #include @@ -16,6 +17,13 @@ namespace sfz class RegionSet { public: + RegionSet() = delete; + RegionSet(RegionSet* parentSet, OpcodeScope level) + : parent(parentSet), level(level) + { + if (parentSet != nullptr) + parentSet->addSubset(this); + } /** * @brief Set the polyphony limit for the set * @@ -73,6 +81,13 @@ public: * @return RegionSet* */ RegionSet* getParent() const noexcept { return parent; } + + /** + * @brief Get the set level + * + * @return OpcodeScope + */ + OpcodeScope getLevel() const noexcept { return level; } /** * @brief Set the parent set * @@ -109,6 +124,7 @@ public: const std::vector& getSubsets() const noexcept { return subsets; } private: RegionSet* parent { nullptr }; + OpcodeScope level { kOpcodeScopeGeneric }; std::vector regions; std::vector subsets; std::vector voices; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b191d841..8a093612 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -77,20 +77,19 @@ void sfz::Synth::onVoiceStateChanged(NumericId id, Voice::State state) void sfz::Synth::onParseFullBlock(const std::string& header, const std::vector& members) { - const auto newRegionSet = [&](RegionSet* parentSet) { - ASSERT(parentSet != nullptr); - sets.emplace_back(new RegionSet); - auto newSet = sets.back().get(); - parentSet->addSubset(newSet); - newSet->setParent(parentSet); - currentSet = newSet; + const auto newRegionSet = [&](OpcodeScope level) { + auto parent = currentSet; + while (parent && parent->getLevel() >= level) + parent = parent->getParent(); + + sets.emplace_back(new RegionSet(parent, level)); + currentSet = sets.back().get(); }; switch (hash(header)) { case hash("global"): globalOpcodes = members; - currentSet = sets.front().get(); - lastHeader = OpcodeScope::kOpcodeScopeGlobal; + newRegionSet(OpcodeScope::kOpcodeScopeGlobal); groupOpcodes.clear(); masterOpcodes.clear(); handleGlobalOpcodes(members); @@ -101,19 +100,14 @@ void sfz::Synth::onParseFullBlock(const std::string& header, const std::vectorgetParent()); - else - newRegionSet(currentSet); - lastHeader = OpcodeScope::kOpcodeScopeGroup; + newRegionSet(OpcodeScope::kOpcodeScopeGroup); handleGroupOpcodes(members, masterOpcodes); numGroups++; break; @@ -145,8 +139,6 @@ void sfz::Synth::onParseWarning(const SourceRange& range, const std::string& mes void sfz::Synth::buildRegion(const std::vector& regionOpcodes) { - ASSERT(currentSet != nullptr); - int regionNumber = static_cast(regions.size()); auto lastRegion = absl::make_unique(regionNumber, resources.midiState, defaultPath); @@ -184,8 +176,10 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) setGroupPolyphony(lastRegion->group, lastRegion->polyphony); - lastRegion->parent = currentSet; - currentSet->addRegion(lastRegion.get()); + if (currentSet != nullptr) { + lastRegion->parent = currentSet; + currentSet->addRegion(lastRegion.get()); + } // Adapt the size of the delayed releases to avoid allocating later on lastRegion->delayedReleases.reserve(lastRegion->keyRange.length()); @@ -204,10 +198,8 @@ void sfz::Synth::clear() for (auto& list : ccActivationLists) list.clear(); - lastHeader = OpcodeScope::kOpcodeScopeGlobal; + currentSet = nullptr; sets.clear(); - sets.emplace_back(new RegionSet); - currentSet = sets.front().get(); regions.clear(); effectBuses.clear(); effectBuses.emplace_back(new EffectBus); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 880726cf..c0d32c2e 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -817,8 +817,7 @@ private: std::vector voices; // These are more general "groups" than sfz and encapsulates the full hierarchy - RegionSet* currentSet; - OpcodeScope lastHeader { OpcodeScope::kOpcodeScopeGlobal }; + RegionSet* currentSet { nullptr }; std::vector sets; // These are the `group=` groups where you can off voices diff --git a/tests/PolyphonyT.cpp b/tests/PolyphonyT.cpp index b7de5c7a..c1d891d4 100644 --- a/tests/PolyphonyT.cpp +++ b/tests/PolyphonyT.cpp @@ -33,13 +33,13 @@ TEST_CASE("[Polyphony] Polyphony in hierarchy") key=64 sample=*sine )"); REQUIRE( synth.getRegionView(0)->polyphony == 2 ); - REQUIRE( synth.getRegionSetView(1)->getPolyphonyLimit() == 2 ); + REQUIRE( synth.getRegionSetView(0)->getPolyphonyLimit() == 2 ); REQUIRE( synth.getRegionView(1)->polyphony == 2 ); - REQUIRE( synth.getRegionSetView(2)->getPolyphonyLimit() == 3 ); - REQUIRE( synth.getRegionSetView(2)->getRegions()[0]->polyphony == 3 ); - REQUIRE( synth.getRegionSetView(3)->getPolyphonyLimit() == 4 ); - REQUIRE( synth.getRegionSetView(3)->getRegions()[0]->polyphony == 5 ); - REQUIRE( synth.getRegionSetView(3)->getRegions()[1]->polyphony == 4 ); + REQUIRE( synth.getRegionSetView(1)->getPolyphonyLimit() == 3 ); + REQUIRE( synth.getRegionSetView(1)->getRegions()[0]->polyphony == 3 ); + REQUIRE( synth.getRegionSetView(2)->getPolyphonyLimit() == 4 ); + REQUIRE( synth.getRegionSetView(2)->getRegions()[0]->polyphony == 5 ); + REQUIRE( synth.getRegionSetView(2)->getRegions()[1]->polyphony == 4 ); } TEST_CASE("[Polyphony] Polyphony groups")