From b3eb8e47ca87fdc2f5b01a8a14946f8c4d66db84 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 25 Oct 2020 12:13:27 +0100 Subject: [PATCH 001/668] Version bump in Cmake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3356da61..32455b1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ else() endif() endif() -project (sfizz VERSION 0.5.1 LANGUAGES CXX C) +project (sfizz VERSION 0.5.2 LANGUAGES CXX C) set (PROJECT_DESCRIPTION "A library to load SFZ description files and use them to render music.") # External configuration CMake scripts From c27cb69a838a832eccd1a1fd16477f8a36f1f6fb Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 26 Oct 2020 22:07:40 +0100 Subject: [PATCH 002/668] Build a set of "effective" keyswitches anduse it instead of sw_lokey/sw_hikey --- src/sfizz/Region.cpp | 67 +++---- src/sfizz/Region.h | 5 +- src/sfizz/Resources.h | 3 + src/sfizz/SfzHelpers.h | 19 ++ src/sfizz/Synth.cpp | 35 +++- tests/FilesT.cpp | 42 ----- tests/RegionActivationT.cpp | 277 +++++++++++++++++++++-------- tests/RegionT.cpp | 17 -- tests/RegionValueComputationsT.cpp | 1 - tests/TestFiles/sw_default.sfz | 5 - 10 files changed, 271 insertions(+), 200 deletions(-) delete mode 100644 tests/TestFiles/sw_default.sfz diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 71eb7ca6..601f2a48 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -292,11 +292,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (auto value = readOpcode(opcode.value, Default::normalizedRange)) ccConditions[opcode.parameters.back()].setEnd(*value); break; - case hash("sw_lokey"): - setRangeStartFromOpcode(opcode, keyswitchRange, Default::keyRange); - break; + case hash("sw_lokey"): // fallthrough case hash("sw_hikey"): - setRangeEndFromOpcode(opcode, keyswitchRange, Default::keyRange); break; case hash("sw_last"): setValueFromOpcode(opcode, keyswitch, Default::keyRange); @@ -1591,16 +1588,11 @@ bool sfz::Region::registerNoteOn(int noteNumber, float velocity, float randValue { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - if (keyswitchRange.containsWithEnd(noteNumber)) { - if (keyswitch) - keySwitched = (*keyswitch == noteNumber); + if (keyswitchDown && *keyswitchDown == noteNumber) + keySwitched = true; - if (keyswitchDown && *keyswitchDown == noteNumber) - keySwitched = true; - - if (keyswitchUp && *keyswitchUp == noteNumber) - keySwitched = false; - } + if (keyswitchUp && *keyswitchUp == noteNumber) + keySwitched = false; const bool keyOk = keyRange.containsWithEnd(noteNumber); if (keyOk) { @@ -1634,13 +1626,11 @@ bool sfz::Region::registerNoteOff(int noteNumber, float velocity, float randValu { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - if (keyswitchRange.containsWithEnd(noteNumber)) { - if (keyswitchDown && *keyswitchDown == noteNumber) - keySwitched = false; + if (keyswitchDown && *keyswitchDown == noteNumber) + keySwitched = false; - if (keyswitchUp && *keyswitchUp == noteNumber) - keySwitched = true; - } + if (keyswitchUp && *keyswitchUp == noteNumber) + keySwitched = true; if (!isSwitchedOn()) return false; @@ -1860,57 +1850,40 @@ float sfz::Region::velocityCurve(float velocity) const noexcept return gain; } -uint8_t offsetAndClamp(uint8_t key, int offset, sfz::Range range) -{ - const int offsetKey { key + offset }; - if (offsetKey > std::numeric_limits::max()) - return range.getEnd(); - if (offsetKey < std::numeric_limits::min()) - return range.getStart(); - - return range.clamp(static_cast(offsetKey)); -} - void sfz::Region::offsetAllKeys(int offset) noexcept { // Offset key range if (keyRange != Default::keyRange) { const auto start = keyRange.getStart(); const auto end = keyRange.getEnd(); - keyRange.setStart(offsetAndClamp(start, offset, Default::keyRange)); - keyRange.setEnd(offsetAndClamp(end, offset, Default::keyRange)); + keyRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); + keyRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); } - pitchKeycenter = offsetAndClamp(pitchKeycenter, offset, Default::keyRange); + pitchKeycenter = offsetAndClampKey(pitchKeycenter, offset, Default::keyRange); // Offset key switches - if (keyswitchRange != Default::keyRange) { - const auto start = keyswitchRange.getStart(); - const auto end = keyswitchRange.getEnd(); - keyswitchRange.setStart(offsetAndClamp(start, offset, Default::keyRange)); - keyswitchRange.setEnd(offsetAndClamp(end, offset, Default::keyRange)); - } if (keyswitchUp) - keyswitchUp = offsetAndClamp(*keyswitchUp, offset, Default::keyRange); + keyswitchUp = offsetAndClampKey(*keyswitchUp, offset, Default::keyRange); if (keyswitch) - keyswitch = offsetAndClamp(*keyswitch, offset, Default::keyRange); + keyswitch = offsetAndClampKey(*keyswitch, offset, Default::keyRange); if (keyswitchDown) - keyswitchDown = offsetAndClamp(*keyswitchDown, offset, Default::keyRange); + keyswitchDown = offsetAndClampKey(*keyswitchDown, offset, Default::keyRange); if (previousNote) - previousNote = offsetAndClamp(*previousNote, offset, Default::keyRange); + previousNote = offsetAndClampKey(*previousNote, offset, Default::keyRange); // Offset crossfade ranges if (crossfadeKeyInRange != Default::crossfadeKeyInRange) { const auto start = crossfadeKeyInRange.getStart(); const auto end = crossfadeKeyInRange.getEnd(); - crossfadeKeyInRange.setStart(offsetAndClamp(start, offset, Default::keyRange)); - crossfadeKeyInRange.setEnd(offsetAndClamp(end, offset, Default::keyRange)); + crossfadeKeyInRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); + crossfadeKeyInRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); } if (crossfadeKeyOutRange != Default::crossfadeKeyOutRange) { const auto start = crossfadeKeyOutRange.getStart(); const auto end = crossfadeKeyOutRange.getEnd(); - crossfadeKeyOutRange.setStart(offsetAndClamp(start, offset, Default::keyRange)); - crossfadeKeyOutRange.setEnd(offsetAndClamp(end, offset, Default::keyRange)); + crossfadeKeyOutRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); + crossfadeKeyOutRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); } } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 2f0f7f0b..a88ab965 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -292,8 +292,6 @@ struct Region { uint32_t loopStart(Oversampling factor = Oversampling::x1) const noexcept; uint32_t loopEnd(Oversampling factor = Oversampling::x1) const noexcept; - bool hasKeyswitches() const noexcept { return keyswitchDown || keyswitchUp || keyswitch || previousNote; } - /** * @brief Get the gain this region contributes into the input of the Nth * effect bus @@ -349,7 +347,6 @@ struct Region { // Region logic: MIDI conditions Range bendRange { Default::bendValueRange }; // hibend and lobend CCMap> ccConditions { Default::ccValueRange }; - Range keyswitchRange { Default::keyRange }; // sw_hikey and sw_lokey absl::optional keyswitch {}; // sw_last absl::optional keyswitchLabel {}; absl::optional keyswitchUp {}; // sw_up @@ -455,7 +452,7 @@ struct Region { // Started notes std::vector> delayedReleases; -private: + const MidiState& midiState; bool keySwitched { true }; bool previousKeySwitched { true }; diff --git a/src/sfizz/Resources.h b/src/sfizz/Resources.h index 577ff756..cf5d27b5 100644 --- a/src/sfizz/Resources.h +++ b/src/sfizz/Resources.h @@ -33,6 +33,8 @@ struct Resources absl::optional stretch; ModMatrix modMatrix; + std::vector keyswitches; + void setSampleRate(float samplerate) { midiState.setSampleRate(samplerate); @@ -54,6 +56,7 @@ struct Resources logger.clear(); midiState.reset(); modMatrix.clear(); + keyswitches.clear(); } }; } diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 416b2304..a2d2439e 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -177,6 +177,25 @@ constexpr float normalizeBend(float bendValue) return clamp(bendValue, -8191.0f, 8191.0f) / 8191.0f; } +/** + * @brief Offset a key and clamp it to a reasonable range + * + * @param key + * @param offset + * @param range + * @return uint8_t + */ +inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset, sfz::Range range) +{ + const int offsetKey { key + offset }; + if (offsetKey > std::numeric_limits::max()) + return range.getEnd(); + if (offsetKey < std::numeric_limits::min()) + return range.getStart(); + + return range.clamp(static_cast(offsetKey)); +} + namespace literals { inline float operator""_norm(unsigned long long int value) { diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index f947331f..b52d538d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -175,6 +175,12 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) if (octaveOffset != 0 || noteOffset != 0) lastRegion->offsetAllKeys(octaveOffset * 12 + noteOffset); + if (lastRegion->keyswitch) { + auto it = absl::c_find(resources.keyswitches, *lastRegion->keyswitch); + if (it == resources.keyswitches.end()) + resources.keyswitches.push_back(*lastRegion->keyswitch); + } + // There was a combination of group= and polyphony= on a region, so set the group polyphony if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) setGroupPolyphony(lastRegion->group, lastRegion->polyphony); @@ -529,6 +535,7 @@ void sfz::Synth::finalizeSfzLoad() bool haveFilterEG { false }; FlexEGs::clearUnusedCurves(); + absl::c_sort(resources.keyswitches); while (currentRegionIndex < currentRegionCount) { auto region = regions[currentRegionIndex].get(); @@ -595,8 +602,13 @@ void sfz::Synth::finalizeSfzLoad() } } - if (region->keyswitchLabel && region->keyswitch) - insertPairUniquely(keyswitchLabels, *region->keyswitch, *region->keyswitchLabel); + if (region->keyswitch) { + if (defaultSwitch) + region->keySwitched = (*defaultSwitch == *region->keyswitch); + + if (region->keyswitchLabel) + insertPairUniquely(keyswitchLabels, *region->keyswitch, *region->keyswitchLabel); + } // Some regions had group number but no "group-level" opcodes handled the polyphony while (polyphonyGroups.size() <= region->group) { @@ -605,7 +617,15 @@ void sfz::Synth::finalizeSfzLoad() } for (auto note = 0; note < 128; note++) { - if (region->keyRange.containsWithEnd(note) || (region->hasKeyswitches() && region->keyswitchRange.containsWithEnd(note))) + bool noteIsKeyswitch = (absl::c_binary_search(resources.keyswitches, note)); + + if ( + region->keyRange.containsWithEnd(note) + || (region->keyswitch && noteIsKeyswitch) + || (region->keyswitchDown && *region->keyswitchDown == note) + || (region->keyswitchUp && *region->keyswitchUp == note) + || (region->previousNote && *region->previousNote == note) + ) noteActivationLists[note].push_back(region); } @@ -621,10 +641,6 @@ void sfz::Synth::finalizeSfzLoad() region->registerCC(cc, resources.midiState.getCCValue(cc)); } - if (defaultSwitch) { - region->registerNoteOn(*defaultSwitch, 1.0f, 1.0f); - region->registerNoteOff(*defaultSwitch, 0.0f, 1.0f); - } // Set the default frequencies on equalizers if needed if (region->equalizers.size() > 0 @@ -1126,7 +1142,12 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc SisterVoiceRingBuilder ring; const TriggerEvent triggerEvent { TriggerEventType::NoteOn, noteNumber, velocity }; + bool noteIsKeyswitch = absl::c_binary_search(resources.keyswitches, noteNumber); + for (auto& region : noteActivationLists[noteNumber]) { + if (noteIsKeyswitch && region->keyswitch) + region->keySwitched = (*region->keyswitch == noteNumber); + if (region->registerNoteOn(noteNumber, velocity, randValue)) { for (auto& voice : voices) { if (voice->checkOffGroup(region, delay, noteNumber)) { diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 5f524b64..8917e591 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -356,46 +356,6 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); } -TEST_CASE("[Files] sw_default") -{ - Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/sw_default.sfz"); - REQUIRE( synth.getNumRegions() == 4 ); - REQUIRE( !synth.getRegionView(0)->isSwitchedOn() ); - REQUIRE( synth.getRegionView(1)->isSwitchedOn() ); - REQUIRE( !synth.getRegionView(2)->isSwitchedOn() ); - REQUIRE( synth.getRegionView(3)->isSwitchedOn() ); -} - -TEST_CASE("[Files] sw_default and playing with switches") -{ - Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/sw_default.sfz"); - REQUIRE( synth.getNumRegions() == 4 ); - REQUIRE( !synth.getRegionView(0)->isSwitchedOn() ); - REQUIRE( synth.getRegionView(1)->isSwitchedOn() ); - REQUIRE( !synth.getRegionView(2)->isSwitchedOn() ); - REQUIRE( synth.getRegionView(3)->isSwitchedOn() ); - synth.noteOn(0, 41, 64); - synth.noteOff(0, 41, 0); - REQUIRE( synth.getRegionView(0)->isSwitchedOn() ); - REQUIRE( !synth.getRegionView(1)->isSwitchedOn() ); - REQUIRE( synth.getRegionView(2)->isSwitchedOn() ); - REQUIRE( !synth.getRegionView(3)->isSwitchedOn() ); - synth.noteOn(0, 42, 64); - synth.noteOff(0, 42, 0); - REQUIRE( !synth.getRegionView(0)->isSwitchedOn() ); - REQUIRE( !synth.getRegionView(1)->isSwitchedOn() ); - REQUIRE( !synth.getRegionView(2)->isSwitchedOn() ); - REQUIRE( !synth.getRegionView(3)->isSwitchedOn() ); - synth.noteOn(0, 40, 64); - synth.noteOff(0, 40, 64); - REQUIRE( !synth.getRegionView(0)->isSwitchedOn() ); - REQUIRE( synth.getRegionView(1)->isSwitchedOn() ); - REQUIRE( !synth.getRegionView(2)->isSwitchedOn() ); - REQUIRE( synth.getRegionView(3)->isSwitchedOn() ); -} - TEST_CASE("[Files] wrong (overlapping) replacement for defines") { Synth synth; @@ -491,7 +451,6 @@ TEST_CASE("[Files] Note and octave offsets") REQUIRE(synth.getRegionView(0)->keyRange == Range(64, 64)); REQUIRE( synth.getRegionView(0)->pitchKeycenter == 64 ); - REQUIRE(synth.getRegionView(0)->keyswitchRange == Default::keyRange); REQUIRE(synth.getRegionView(0)->crossfadeKeyInRange == Default::crossfadeKeyInRange); REQUIRE(synth.getRegionView(0)->crossfadeKeyOutRange == Default::crossfadeKeyOutRange); @@ -504,7 +463,6 @@ TEST_CASE("[Files] Note and octave offsets") REQUIRE(synth.getRegionView(2)->crossfadeKeyOutRange == Range(45, 49)); REQUIRE(synth.getRegionView(3)->keyRange == Range(62, 62)); - REQUIRE(synth.getRegionView(3)->keyswitchRange == Range(23, 27)); REQUIRE( synth.getRegionView(3)->keyswitch ); REQUIRE( *synth.getRegionView(3)->keyswitch == 24 ); REQUIRE( synth.getRegionView(3)->keyswitchUp ); diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index e7957ffb..af5ee739 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "sfizz/Region.h" +#include "sfizz/Synth.h" #include "sfizz/SfzHelpers.h" #include "catch2/catch.hpp" using namespace Catch::literals; @@ -113,83 +114,6 @@ TEST_CASE("Region activation", "Region tests") REQUIRE(!region.isSwitchedOn()); } - // TODO: add keyswitches - SECTION("Keyswitches: sw_last") - { - region.parseOpcode({ "sw_last", "40" }); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOn(40, 64_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOff(40, 64_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOn(41, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(41, 0_norm, 0.5f); - } - - SECTION("Keyswitches: sw_last with non-default keyswitch range") - { - region.parseOpcode({ "sw_lokey", "30" }); - region.parseOpcode({ "sw_hikey", "50" }); - region.parseOpcode({ "sw_last", "40" }); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOn(60, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(60, 0_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOn(40, 64_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOff(40, 0_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOn(60, 64_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOff(60, 0_norm, 0.5f); - region.registerNoteOn(41, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(41, 0_norm, 0.5f); - } - - SECTION("Keyswitches: sw_down with non-default keyswitch range") - { - region.parseOpcode({ "sw_lokey", "30" }); - region.parseOpcode({ "sw_hikey", "50" }); - region.parseOpcode({ "sw_down", "40" }); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOn(60, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(60, 0_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOn(40, 64_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOff(40, 0_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOn(60, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(60, 0_norm, 0.5f); - region.registerNoteOn(41, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(41, 0_norm, 0.5f); - } - - SECTION("Keyswitches: sw_up with non-default keyswitch range") - { - region.parseOpcode({ "sw_lokey", "30" }); - region.parseOpcode({ "sw_hikey", "50" }); - region.parseOpcode({ "sw_up", "40" }); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOn(40, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(40, 0_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOn(41, 64_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOn(40, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(40, 0_norm, 0.5f); - region.registerNoteOff(41, 0_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - } - SECTION("Keyswitches: sw_previous") { region.parseOpcode({ "sw_previous", "40" }); @@ -273,3 +197,202 @@ TEST_CASE("Region activation", "Region tests") REQUIRE(!region.isSwitchedOn()); } } + +TEST_CASE("[Keyswitches] Normal keyswitch range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + sw_lokey=40 sw_hikey=42 sw_default=40 + sw_last=40 key=60 sample=*sine + sw_last=41 key=62 sample=*saw + )"); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 41, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 2); +} + +TEST_CASE("[Keyswitches] No keyswitch range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + sw_last=40 key=60 sample=*sine + sw_last=41 key=62 sample=*saw + )"); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 0); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 0); + synth.noteOn(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 41, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 2); +} + +TEST_CASE("[Keyswitches] Out of keyswitch range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + sw_lokey=40 sw_hikey=42 sw_default=40 + sw_last=40 key=60 sample=*sine + sw_last=43 key=62 sample=*saw + )"); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 43, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 2); +} + +TEST_CASE("[Keyswitches] Overlapping key and keyswitch range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + sw_lokey=1 sw_hikey=127 sw_default=40 + sw_last=40 key=60 sample=*sine + sw_last=41 key=62 sample=*saw + )"); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 41, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 2); + synth.noteOn(0, 43, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 2); + synth.noteOn(0, 62, 64); + REQUIRE(synth.getNumActiveVoices(true) == 3); +} + +TEST_CASE("[Keyswitches] sw_down, in range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + sw_lokey=1 sw_hikey=127 sw_default=40 + sw_down=40 key=60 sample=*sine + )"); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 0); + synth.noteOn(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOff(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); +} + +TEST_CASE("[Keyswitches] sw_down, out of range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + sw_lokey=1 sw_hikey=10 sw_default=40 + sw_down=40 key=60 sample=*sine + )"); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 0); + synth.noteOn(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOff(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); +} + +TEST_CASE("[Keyswitches] sw_up, in range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + sw_lokey=1 sw_hikey=127 sw_default=40 + sw_up=40 key=60 sample=*sine + )"); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOff(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 2); +} + +TEST_CASE("[Keyswitches] sw_up, out of range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + sw_lokey=1 sw_hikey=127 sw_default=40 + sw_up=40 key=60 sample=*sine + )"); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOff(0, 40, 64); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 2); +} + +TEST_CASE("[Keyswitches] sw_default") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_default.sfz", R"( + sw_lokey=30 sw_hikey=50 sw_default=40 + sw_last=41 key=51 sample=*sine + sw_last=40 key=52 sample=*sine + sw_last=41 key=53 sample=*sine + sw_last=40 key=54 sample=*sine + )"); + REQUIRE( synth.getNumRegions() == 4 ); + REQUIRE( !synth.getRegionView(0)->isSwitchedOn() ); + REQUIRE( synth.getRegionView(1)->isSwitchedOn() ); + REQUIRE( !synth.getRegionView(2)->isSwitchedOn() ); + REQUIRE( synth.getRegionView(3)->isSwitchedOn() ); +} + +TEST_CASE("[Keyswitches] sw_default and playing with switches") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_default.sfz", R"( + sw_lokey=30 sw_hikey=50 sw_default=40 + sw_last=41 key=51 sample=*sine + sw_last=40 key=52 sample=*sine + sw_last=41 key=53 sample=*sine + sw_last=40 key=54 sample=*sine + )"); + REQUIRE( synth.getNumRegions() == 4 ); + REQUIRE( !synth.getRegionView(0)->isSwitchedOn() ); + REQUIRE( synth.getRegionView(1)->isSwitchedOn() ); + REQUIRE( !synth.getRegionView(2)->isSwitchedOn() ); + REQUIRE( synth.getRegionView(3)->isSwitchedOn() ); + synth.noteOn(0, 41, 64); + synth.noteOff(0, 41, 0); + REQUIRE( synth.getRegionView(0)->isSwitchedOn() ); + REQUIRE( !synth.getRegionView(1)->isSwitchedOn() ); + REQUIRE( synth.getRegionView(2)->isSwitchedOn() ); + REQUIRE( !synth.getRegionView(3)->isSwitchedOn() ); + synth.noteOn(0, 40, 64); + synth.noteOff(0, 40, 64); + REQUIRE( !synth.getRegionView(0)->isSwitchedOn() ); + REQUIRE( synth.getRegionView(1)->isSwitchedOn() ); + REQUIRE( !synth.getRegionView(2)->isSwitchedOn() ); + REQUIRE( synth.getRegionView(3)->isSwitchedOn() ); +} diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index f15bd286..2b1cc780 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -339,23 +339,6 @@ TEST_CASE("[Region] Parsing opcodes") REQUIRE(region.ccConditions[125] == sfz::Range(0.0f, 1.0f)); } - SECTION("sw_lokey, sw_hikey") - { - REQUIRE(region.keyswitchRange == Range(0, 127)); - region.parseOpcode({ "sw_lokey", "4" }); - REQUIRE(region.keyswitchRange == Range(4, 127)); - region.parseOpcode({ "sw_lokey", "128" }); - REQUIRE(region.keyswitchRange == Range(127, 127)); - region.parseOpcode({ "sw_lokey", "0" }); - REQUIRE(region.keyswitchRange == Range(0, 127)); - region.parseOpcode({ "sw_hikey", "39" }); - REQUIRE(region.keyswitchRange == Range(0, 39)); - region.parseOpcode({ "sw_hikey", "135" }); - REQUIRE(region.keyswitchRange == Range(0, 127)); - region.parseOpcode({ "sw_hikey", "-1" }); - REQUIRE(region.keyswitchRange == Range(0, 0)); - } - SECTION("sw_label") { REQUIRE(!region.keyswitchLabel); diff --git a/tests/RegionValueComputationsT.cpp b/tests/RegionValueComputationsT.cpp index 50deb231..3b2d3e32 100644 --- a/tests/RegionValueComputationsT.cpp +++ b/tests/RegionValueComputationsT.cpp @@ -7,7 +7,6 @@ #include "sfizz/Defaults.h" #include "sfizz/Region.h" #include "sfizz/SfzHelpers.h" -#include "sfizz/MidiState.h" #include "catch2/catch.hpp" #include #include diff --git a/tests/TestFiles/sw_default.sfz b/tests/TestFiles/sw_default.sfz deleted file mode 100644 index 44d896c5..00000000 --- a/tests/TestFiles/sw_default.sfz +++ /dev/null @@ -1,5 +0,0 @@ - sw_lokey=30 sw_hikey=50 sw_default=40 - sw_last=41 key=51 sample=*silence - sw_last=40 key=52 sample=*silence - sw_last=41 key=53 sample=*silence - sw_last=40 key=54 sample=*silence \ No newline at end of file From 6bfc9074d723e87f083ef74b036c60ae8729df93 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Tue, 27 Oct 2020 11:04:25 +0100 Subject: [PATCH 003/668] Move the keyswitch logic in the synth rather than the regions --- src/sfizz/Region.cpp | 18 --------- src/sfizz/Resources.h | 3 -- src/sfizz/Synth.cpp | 74 +++++++++++++++++++++++++------------ src/sfizz/Synth.h | 8 +++- tests/RegionActivationT.cpp | 71 ++++++++++++++++++++++++----------- 5 files changed, 106 insertions(+), 68 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 601f2a48..f4be5582 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1588,20 +1588,11 @@ bool sfz::Region::registerNoteOn(int noteNumber, float velocity, float randValue { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - if (keyswitchDown && *keyswitchDown == noteNumber) - keySwitched = true; - - if (keyswitchUp && *keyswitchUp == noteNumber) - keySwitched = false; - const bool keyOk = keyRange.containsWithEnd(noteNumber); if (keyOk) { // Sequence activation sequenceSwitched = ((sequenceCounter++ % sequenceLength) == sequencePosition - 1); - - if (previousNote) - previousKeySwitched = (*previousNote == noteNumber); } if (!isSwitchedOn()) @@ -1610,9 +1601,6 @@ bool sfz::Region::registerNoteOn(int noteNumber, float velocity, float randValue if (!triggerOnNote) return false; - if (previousNote && !(previousKeySwitched && noteNumber != *previousNote)) - return false; - const bool velOk = velocityRange.containsWithEnd(velocity); const bool randOk = randRange.contains(randValue) || (randValue == 1.0f && randRange.getEnd() == 1.0f); const bool firstLegatoNote = (trigger == SfzTrigger::first && midiState.getActiveNotes() == 1); @@ -1626,12 +1614,6 @@ bool sfz::Region::registerNoteOff(int noteNumber, float velocity, float randValu { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - if (keyswitchDown && *keyswitchDown == noteNumber) - keySwitched = false; - - if (keyswitchUp && *keyswitchUp == noteNumber) - keySwitched = true; - if (!isSwitchedOn()) return false; diff --git a/src/sfizz/Resources.h b/src/sfizz/Resources.h index cf5d27b5..577ff756 100644 --- a/src/sfizz/Resources.h +++ b/src/sfizz/Resources.h @@ -33,8 +33,6 @@ struct Resources absl::optional stretch; ModMatrix modMatrix; - std::vector keyswitches; - void setSampleRate(float samplerate) { midiState.setSampleRate(samplerate); @@ -56,7 +54,6 @@ struct Resources logger.clear(); midiState.reset(); modMatrix.clear(); - keyswitches.clear(); } }; } diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b52d538d..143e22ba 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -175,11 +175,17 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) if (octaveOffset != 0 || noteOffset != 0) lastRegion->offsetAllKeys(octaveOffset * 12 + noteOffset); - if (lastRegion->keyswitch) { - auto it = absl::c_find(resources.keyswitches, *lastRegion->keyswitch); - if (it == resources.keyswitches.end()) - resources.keyswitches.push_back(*lastRegion->keyswitch); - } + if (lastRegion->keyswitch) + lastKeyswitchLists[*lastRegion->keyswitch].push_back(lastRegion.get()); + + if (lastRegion->keyswitchUp) + upKeyswitchLists[*lastRegion->keyswitchUp].push_back(lastRegion.get()); + + if (lastRegion->keyswitchDown) + downKeyswitchLists[*lastRegion->keyswitchDown].push_back(lastRegion.get()); + + if (lastRegion->previousNote) + previousKeyswitchLists.push_back(lastRegion.get()); // There was a combination of group= and polyphony= on a region, so set the group polyphony if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) @@ -203,10 +209,17 @@ void sfz::Synth::clear() for (auto& voice : voices) voice->reset(); + for (auto& list : lastKeyswitchLists) + list.clear(); + for (auto& list : downKeyswitchLists) + list.clear(); + for (auto& list : upKeyswitchLists) + list.clear(); for (auto& list : noteActivationLists) list.clear(); for (auto& list : ccActivationLists) list.clear(); + previousKeyswitchLists.clear(); currentSet = nullptr; sets.clear(); @@ -220,7 +233,7 @@ void sfz::Synth::clear() resources.clear(); numGroups = 0; numMasters = 0; - defaultSwitch = absl::nullopt; + currentSwitch = absl::nullopt; defaultPath = ""; resources.midiState.reset(); resources.filePool.clear(); @@ -262,7 +275,7 @@ void sfz::Synth::handleMasterOpcodes(const std::vector& members) currentSet->setPolyphonyLimit(*value); break; case hash("sw_default"): - setValueFromOpcode(member, defaultSwitch, Default::keyRange); + setValueFromOpcode(member, currentSwitch, Default::keyRange); break; } } @@ -280,7 +293,7 @@ void sfz::Synth::handleGlobalOpcodes(const std::vector& members) currentSet->setPolyphonyLimit(*value); break; case hash("sw_default"): - setValueFromOpcode(member, defaultSwitch, Default::keyRange); + setValueFromOpcode(member, currentSwitch, Default::keyRange); break; case hash("volume"): // FIXME : Probably best not to mess with this and let the host control the volume @@ -306,7 +319,7 @@ void sfz::Synth::handleGroupOpcodes(const std::vector& members, const st setValueFromOpcode(member, maxPolyphony, Default::polyphonyRange); break; case hash("sw_default"): - setValueFromOpcode(member, defaultSwitch, Default::keyRange); + setValueFromOpcode(member, currentSwitch, Default::keyRange); break; } }; @@ -535,7 +548,6 @@ void sfz::Synth::finalizeSfzLoad() bool haveFilterEG { false }; FlexEGs::clearUnusedCurves(); - absl::c_sort(resources.keyswitches); while (currentRegionIndex < currentRegionCount) { auto region = regions[currentRegionIndex].get(); @@ -603,8 +615,8 @@ void sfz::Synth::finalizeSfzLoad() } if (region->keyswitch) { - if (defaultSwitch) - region->keySwitched = (*defaultSwitch == *region->keyswitch); + if (currentSwitch) + region->keySwitched = (*currentSwitch == *region->keyswitch); if (region->keyswitchLabel) insertPairUniquely(keyswitchLabels, *region->keyswitch, *region->keyswitchLabel); @@ -617,15 +629,7 @@ void sfz::Synth::finalizeSfzLoad() } for (auto note = 0; note < 128; note++) { - bool noteIsKeyswitch = (absl::c_binary_search(resources.keyswitches, note)); - - if ( - region->keyRange.containsWithEnd(note) - || (region->keyswitch && noteIsKeyswitch) - || (region->keyswitchDown && *region->keyswitchDown == note) - || (region->keyswitchUp && *region->keyswitchUp == note) - || (region->previousNote && *region->previousNote == note) - ) + if (region->keyRange.containsWithEnd(note)) noteActivationLists[note].push_back(region); } @@ -1032,6 +1036,12 @@ void sfz::Synth::noteOffDispatch(int delay, int noteNumber, float velocity) noex SisterVoiceRingBuilder ring; const TriggerEvent triggerEvent { TriggerEventType::NoteOff, noteNumber, velocity }; + for (auto& region : upKeyswitchLists[noteNumber]) + region->keySwitched = true; + + for (auto& region : downKeyswitchLists[noteNumber]) + region->keySwitched = false; + for (auto& region : noteActivationLists[noteNumber]) { if (region->registerNoteOff(noteNumber, velocity, randValue)) { if (region->trigger == SfzTrigger::release && !region->rtDead && !playingAttackVoice(region)) @@ -1142,11 +1152,24 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc SisterVoiceRingBuilder ring; const TriggerEvent triggerEvent { TriggerEventType::NoteOn, noteNumber, velocity }; - bool noteIsKeyswitch = absl::c_binary_search(resources.keyswitches, noteNumber); + if (!lastKeyswitchLists[noteNumber].empty()) { + if (currentSwitch && *currentSwitch != noteNumber) { + for (auto& region : lastKeyswitchLists[*currentSwitch]) + region->keySwitched = false; + } + currentSwitch = noteNumber; + } + + for (auto& region : lastKeyswitchLists[noteNumber]) + region->keySwitched = true; + + for (auto& region : upKeyswitchLists[noteNumber]) + region->keySwitched = false; + + for (auto& region : downKeyswitchLists[noteNumber]) + region->keySwitched = true; for (auto& region : noteActivationLists[noteNumber]) { - if (noteIsKeyswitch && region->keyswitch) - region->keySwitched = (*region->keyswitch == noteNumber); if (region->registerNoteOn(noteNumber, velocity, randValue)) { for (auto& voice : voices) { @@ -1159,6 +1182,9 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc startVoice(region, delay, triggerEvent, ring); } } + + for (auto& region : previousKeyswitchLists) + region->previousKeySwitched = (*region->previousNote == noteNumber); } void sfz::Synth::startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index d1db8a93..40b5012e 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -803,8 +803,8 @@ private: std::vector keyLabels; std::vector keyswitchLabels; - // Default active switch if multiple keyswitchable regions are present - absl::optional defaultSwitch; + // Set as sw_default if present in the file + absl::optional currentSwitch; std::vector unknownOpcodes; using RegionViewVector = std::vector; using VoiceViewVector = std::vector; @@ -899,6 +899,10 @@ private: */ bool playingAttackVoice(const Region* releaseRegion) noexcept; + std::array lastKeyswitchLists; + std::array downKeyswitchLists; + std::array upKeyswitchLists; + RegionViewVector previousKeyswitchLists; std::array noteActivationLists; std::array ccActivationLists; diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index af5ee739..7a08ce76 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -114,27 +114,6 @@ TEST_CASE("Region activation", "Region tests") REQUIRE(!region.isSwitchedOn()); } - SECTION("Keyswitches: sw_previous") - { - region.parseOpcode({ "sw_previous", "40" }); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOn(40, 64_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOff(40, 0_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOn(41, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOn(40, 64_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOff(40, 0_norm, 0.5f); - region.registerNoteOff(41, 0_norm, 0.5f); - REQUIRE(region.isSwitchedOn()); - region.registerNoteOn(41, 64_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - region.registerNoteOff(41, 0_norm, 0.5f); - REQUIRE(!region.isSwitchedOn()); - } - SECTION("Sequences: length 2, default position") { region.parseOpcode({ "seq_length", "2" }); @@ -396,3 +375,53 @@ TEST_CASE("[Keyswitches] sw_default and playing with switches") REQUIRE( !synth.getRegionView(2)->isSwitchedOn() ); REQUIRE( synth.getRegionView(3)->isSwitchedOn() ); } + +TEST_CASE("[Keyswitches] sw_previous in range") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + sample=*saw sw_previous=60 lokey=50 hikey=70 + )"); + // Note: sforzando seems to activate by default if sw_previous is indeed 60, + // but not any other value. As it does not seem really useful at this point + // the test assumes that sw_previous regions are disabled by default + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + synth.noteOn(0, 51, 64); + REQUIRE(synth.getNumActiveVoices(true) == 0); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + synth.noteOn(0, 51, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); +} + + +TEST_CASE("[Keyswitches] sw_previous out of range") +{ + // The behavior is the same in this case, regardless of the keyrange + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + sample=*saw sw_previous=60 lokey=50 hikey=55 + )"); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + synth.noteOn(0, 51, 64); + REQUIRE(synth.getNumActiveVoices(true) == 0); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + synth.noteOn(0, 51, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + synth.noteOn(0, 60, 64); + REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + synth.noteOn(0, 61, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); +} From 9c3de9daddf37fcfa430dae5936f2fb548cc9d0c Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Tue, 27 Oct 2020 11:19:12 +0100 Subject: [PATCH 004/668] Rename for consistency --- src/sfizz/Region.cpp | 24 ++++++++-------- src/sfizz/Region.h | 8 +++--- src/sfizz/Synth.cpp | 22 +++++++-------- tests/FilesT.cpp | 16 +++++------ tests/RegionActivationT.cpp | 8 +++--- tests/RegionT.cpp | 56 ++++++++++++++++++------------------- 6 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index f4be5582..d7826720 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -296,21 +296,21 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("sw_hikey"): break; case hash("sw_last"): - setValueFromOpcode(opcode, keyswitch, Default::keyRange); + setValueFromOpcode(opcode, lastKeyswitch, Default::keyRange); keySwitched = false; break; case hash("sw_label"): keyswitchLabel = opcode.value; break; case hash("sw_down"): - setValueFromOpcode(opcode, keyswitchDown, Default::keyRange); + setValueFromOpcode(opcode, downKeyswitch, Default::keyRange); keySwitched = false; break; case hash("sw_up"): - setValueFromOpcode(opcode, keyswitchUp, Default::keyRange); + setValueFromOpcode(opcode, upKeyswitch, Default::keyRange); break; case hash("sw_previous"): - setValueFromOpcode(opcode, previousNote, Default::keyRange); + setValueFromOpcode(opcode, previousKeyswitch, Default::keyRange); previousKeySwitched = false; break; case hash("sw_vel"): @@ -1844,14 +1844,14 @@ void sfz::Region::offsetAllKeys(int offset) noexcept pitchKeycenter = offsetAndClampKey(pitchKeycenter, offset, Default::keyRange); // Offset key switches - if (keyswitchUp) - keyswitchUp = offsetAndClampKey(*keyswitchUp, offset, Default::keyRange); - if (keyswitch) - keyswitch = offsetAndClampKey(*keyswitch, offset, Default::keyRange); - if (keyswitchDown) - keyswitchDown = offsetAndClampKey(*keyswitchDown, offset, Default::keyRange); - if (previousNote) - previousNote = offsetAndClampKey(*previousNote, offset, Default::keyRange); + if (upKeyswitch) + upKeyswitch = offsetAndClampKey(*upKeyswitch, offset, Default::keyRange); + if (lastKeyswitch) + lastKeyswitch = offsetAndClampKey(*lastKeyswitch, offset, Default::keyRange); + if (downKeyswitch) + downKeyswitch = offsetAndClampKey(*downKeyswitch, offset, Default::keyRange); + if (previousKeyswitch) + previousKeyswitch = offsetAndClampKey(*previousKeyswitch, offset, Default::keyRange); // Offset crossfade ranges if (crossfadeKeyInRange != Default::crossfadeKeyInRange) { diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index a88ab965..996eec4e 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -347,11 +347,11 @@ struct Region { // Region logic: MIDI conditions Range bendRange { Default::bendValueRange }; // hibend and lobend CCMap> ccConditions { Default::ccValueRange }; - absl::optional keyswitch {}; // sw_last + absl::optional lastKeyswitch {}; // sw_last absl::optional keyswitchLabel {}; - absl::optional keyswitchUp {}; // sw_up - absl::optional keyswitchDown {}; // sw_down - absl::optional previousNote {}; // sw_previous + absl::optional upKeyswitch {}; // sw_up + absl::optional downKeyswitch {}; // sw_down + absl::optional previousKeyswitch {}; // sw_previous SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel bool checkSustain { Default::checkSustain }; // sustain_sw bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 143e22ba..631a5b43 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -175,16 +175,16 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) if (octaveOffset != 0 || noteOffset != 0) lastRegion->offsetAllKeys(octaveOffset * 12 + noteOffset); - if (lastRegion->keyswitch) - lastKeyswitchLists[*lastRegion->keyswitch].push_back(lastRegion.get()); + if (lastRegion->lastKeyswitch) + lastKeyswitchLists[*lastRegion->lastKeyswitch].push_back(lastRegion.get()); - if (lastRegion->keyswitchUp) - upKeyswitchLists[*lastRegion->keyswitchUp].push_back(lastRegion.get()); + if (lastRegion->upKeyswitch) + upKeyswitchLists[*lastRegion->upKeyswitch].push_back(lastRegion.get()); - if (lastRegion->keyswitchDown) - downKeyswitchLists[*lastRegion->keyswitchDown].push_back(lastRegion.get()); + if (lastRegion->downKeyswitch) + downKeyswitchLists[*lastRegion->downKeyswitch].push_back(lastRegion.get()); - if (lastRegion->previousNote) + if (lastRegion->previousKeyswitch) previousKeyswitchLists.push_back(lastRegion.get()); // There was a combination of group= and polyphony= on a region, so set the group polyphony @@ -614,12 +614,12 @@ void sfz::Synth::finalizeSfzLoad() } } - if (region->keyswitch) { + if (region->lastKeyswitch) { if (currentSwitch) - region->keySwitched = (*currentSwitch == *region->keyswitch); + region->keySwitched = (*currentSwitch == *region->lastKeyswitch); if (region->keyswitchLabel) - insertPairUniquely(keyswitchLabels, *region->keyswitch, *region->keyswitchLabel); + insertPairUniquely(keyswitchLabels, *region->lastKeyswitch, *region->keyswitchLabel); } // Some regions had group number but no "group-level" opcodes handled the polyphony @@ -1184,7 +1184,7 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc } for (auto& region : previousKeyswitchLists) - region->previousKeySwitched = (*region->previousNote == noteNumber); + region->previousKeySwitched = (*region->previousKeyswitch == noteNumber); } void sfz::Synth::startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 8917e591..b0a19757 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -463,14 +463,14 @@ TEST_CASE("[Files] Note and octave offsets") REQUIRE(synth.getRegionView(2)->crossfadeKeyOutRange == Range(45, 49)); REQUIRE(synth.getRegionView(3)->keyRange == Range(62, 62)); - REQUIRE( synth.getRegionView(3)->keyswitch ); - REQUIRE( *synth.getRegionView(3)->keyswitch == 24 ); - REQUIRE( synth.getRegionView(3)->keyswitchUp ); - REQUIRE( *synth.getRegionView(3)->keyswitchUp == 24 ); - REQUIRE( synth.getRegionView(3)->keyswitchDown ); - REQUIRE( *synth.getRegionView(3)->keyswitchDown == 24 ); - REQUIRE( synth.getRegionView(3)->previousNote ); - REQUIRE( *synth.getRegionView(3)->previousNote == 61 ); + REQUIRE( synth.getRegionView(3)->lastKeyswitch ); + REQUIRE( *synth.getRegionView(3)->lastKeyswitch == 24 ); + REQUIRE( synth.getRegionView(3)->upKeyswitch ); + REQUIRE( *synth.getRegionView(3)->upKeyswitch == 24 ); + REQUIRE( synth.getRegionView(3)->downKeyswitch ); + REQUIRE( *synth.getRegionView(3)->downKeyswitch == 24 ); + REQUIRE( synth.getRegionView(3)->previousKeyswitch ); + REQUIRE( *synth.getRegionView(3)->previousKeyswitch == 61 ); REQUIRE(synth.getRegionView(4)->keyRange == Range(76, 76)); REQUIRE( synth.getRegionView(4)->pitchKeycenter == 76 ); diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index 7a08ce76..0763b56f 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -177,7 +177,7 @@ TEST_CASE("Region activation", "Region tests") } } -TEST_CASE("[Keyswitches] Normal keyswitch range") +TEST_CASE("[Keyswitches] Normal lastKeyswitch range") { sfz::Synth synth; synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( @@ -196,7 +196,7 @@ TEST_CASE("[Keyswitches] Normal keyswitch range") REQUIRE(synth.getNumActiveVoices(true) == 2); } -TEST_CASE("[Keyswitches] No keyswitch range") +TEST_CASE("[Keyswitches] No lastKeyswitch range") { sfz::Synth synth; synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( @@ -219,7 +219,7 @@ TEST_CASE("[Keyswitches] No keyswitch range") REQUIRE(synth.getNumActiveVoices(true) == 2); } -TEST_CASE("[Keyswitches] Out of keyswitch range") +TEST_CASE("[Keyswitches] Out of lastKeyswitch range") { sfz::Synth synth; synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( @@ -238,7 +238,7 @@ TEST_CASE("[Keyswitches] Out of keyswitch range") REQUIRE(synth.getNumActiveVoices(true) == 2); } -TEST_CASE("[Keyswitches] Overlapping key and keyswitch range") +TEST_CASE("[Keyswitches] Overlapping key and lastKeyswitch range") { sfz::Synth synth; synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index 2b1cc780..7e20583c 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -350,58 +350,58 @@ TEST_CASE("[Region] Parsing opcodes") SECTION("sw_last") { - REQUIRE(!region.keyswitch); + REQUIRE(!region.lastKeyswitch); region.parseOpcode({ "sw_last", "4" }); - REQUIRE(region.keyswitch); - REQUIRE(*region.keyswitch == 4); + REQUIRE(region.lastKeyswitch); + REQUIRE(*region.lastKeyswitch == 4); region.parseOpcode({ "sw_last", "128" }); - REQUIRE(region.keyswitch); - REQUIRE(*region.keyswitch == 127); + REQUIRE(region.lastKeyswitch); + REQUIRE(*region.lastKeyswitch == 127); region.parseOpcode({ "sw_last", "-1" }); - REQUIRE(region.keyswitch); - REQUIRE(*region.keyswitch == 0); + REQUIRE(region.lastKeyswitch); + REQUIRE(*region.lastKeyswitch == 0); } SECTION("sw_up") { - REQUIRE(!region.keyswitchUp); + REQUIRE(!region.upKeyswitch); region.parseOpcode({ "sw_up", "4" }); - REQUIRE(region.keyswitchUp); - REQUIRE(*region.keyswitchUp == 4); + REQUIRE(region.upKeyswitch); + REQUIRE(*region.upKeyswitch == 4); region.parseOpcode({ "sw_up", "128" }); - REQUIRE(region.keyswitchUp); - REQUIRE(*region.keyswitchUp == 127); + REQUIRE(region.upKeyswitch); + REQUIRE(*region.upKeyswitch == 127); region.parseOpcode({ "sw_up", "-1" }); - REQUIRE(region.keyswitchUp); - REQUIRE(*region.keyswitchUp == 0); + REQUIRE(region.upKeyswitch); + REQUIRE(*region.upKeyswitch == 0); } SECTION("sw_down") { - REQUIRE(!region.keyswitchDown); + REQUIRE(!region.downKeyswitch); region.parseOpcode({ "sw_down", "4" }); - REQUIRE(region.keyswitchDown); - REQUIRE(*region.keyswitchDown == 4); + REQUIRE(region.downKeyswitch); + REQUIRE(*region.downKeyswitch == 4); region.parseOpcode({ "sw_down", "128" }); - REQUIRE(region.keyswitchDown); - REQUIRE(*region.keyswitchDown == 127); + REQUIRE(region.downKeyswitch); + REQUIRE(*region.downKeyswitch == 127); region.parseOpcode({ "sw_down", "-1" }); - REQUIRE(region.keyswitchDown); - REQUIRE(*region.keyswitchDown == 0); + REQUIRE(region.downKeyswitch); + REQUIRE(*region.downKeyswitch == 0); } SECTION("sw_previous") { - REQUIRE(!region.previousNote); + REQUIRE(!region.previousKeyswitch); region.parseOpcode({ "sw_previous", "4" }); - REQUIRE(region.previousNote); - REQUIRE(*region.previousNote == 4); + REQUIRE(region.previousKeyswitch); + REQUIRE(*region.previousKeyswitch == 4); region.parseOpcode({ "sw_previous", "128" }); - REQUIRE(region.previousNote); - REQUIRE(*region.previousNote == 127); + REQUIRE(region.previousKeyswitch); + REQUIRE(*region.previousKeyswitch == 127); region.parseOpcode({ "sw_previous", "-1" }); - REQUIRE(region.previousNote); - REQUIRE(*region.previousNote == 0); + REQUIRE(region.previousKeyswitch); + REQUIRE(*region.previousKeyswitch == 0); } SECTION("sw_vel") From 5ea4b876dfd207f2e2e9c57a0b4706610e46bfde Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Tue, 27 Oct 2020 14:50:31 +0100 Subject: [PATCH 005/668] Add sw_lolast/sw_hilast --- src/sfizz/Region.cpp | 28 ++++++++++++++-- src/sfizz/Region.h | 1 + src/sfizz/Synth.cpp | 6 ++++ tests/RegionActivationT.cpp | 64 ++++++++++++++++++++++++++++++++++++- tests/RegionT.cpp | 42 ++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 3 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index d7826720..42be5f79 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -296,8 +296,32 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("sw_hikey"): break; case hash("sw_last"): - setValueFromOpcode(opcode, lastKeyswitch, Default::keyRange); - keySwitched = false; + if (!lastKeyswitchRange) { + setValueFromOpcode(opcode, lastKeyswitch, Default::keyRange); + keySwitched = false; + } + break; + case hash("sw_lolast"): + if (auto value = readOpcode(opcode.value, Default::keyRange)) { + if (!lastKeyswitchRange) + lastKeyswitchRange.emplace(*value, *value); + else + lastKeyswitchRange->setStart(*value); + + keySwitched = false; + lastKeyswitch = absl::nullopt; + } + break; + case hash("sw_hilast"): + if (auto value = readOpcode(opcode.value, Default::keyRange)) { + if (!lastKeyswitchRange) + lastKeyswitchRange.emplace(*value, *value); + else + lastKeyswitchRange->setEnd(*value); + + keySwitched = false; + lastKeyswitch = absl::nullopt; + } break; case hash("sw_label"): keyswitchLabel = opcode.value; diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 996eec4e..7fb0b695 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -348,6 +348,7 @@ struct Region { Range bendRange { Default::bendValueRange }; // hibend and lobend CCMap> ccConditions { Default::ccValueRange }; absl::optional lastKeyswitch {}; // sw_last + absl::optional> lastKeyswitchRange {}; // sw_last absl::optional keyswitchLabel {}; absl::optional upKeyswitch {}; // sw_up absl::optional downKeyswitch {}; // sw_down diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 631a5b43..ba5c109d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -178,6 +178,12 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) if (lastRegion->lastKeyswitch) lastKeyswitchLists[*lastRegion->lastKeyswitch].push_back(lastRegion.get()); + if (lastRegion->lastKeyswitchRange) { + auto& range = *lastRegion->lastKeyswitchRange; + for (uint8_t note = range.getStart(), end = range.getEnd(); note <= end; note++) + lastKeyswitchLists[note].push_back(lastRegion.get()); + } + if (lastRegion->upKeyswitch) upKeyswitchLists[*lastRegion->upKeyswitch].push_back(lastRegion.get()); diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index 0763b56f..6c5a3ed9 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -402,7 +402,6 @@ TEST_CASE("[Keyswitches] sw_previous in range") REQUIRE(synth.getRegionView(0)->isSwitchedOn()); } - TEST_CASE("[Keyswitches] sw_previous out of range") { // The behavior is the same in this case, regardless of the keyrange @@ -425,3 +424,66 @@ TEST_CASE("[Keyswitches] sw_previous out of range") synth.noteOn(0, 61, 64); REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); } + +TEST_CASE("[Keyswitches] sw_lolast and sw_hilast") +{ + // The behavior is the same in this case, regardless of the keyrange + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + sw_lolast=57 sw_hilast=59 key=70 sample=*saw + sw_lolast=60 sw_hilast=62 key=72 sample=*sine + )"); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 51, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 57, 64); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 60, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 58, 64); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 61, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 59, 64); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 62, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(synth.getRegionView(1)->isSwitchedOn()); +} + +TEST_CASE("[Keyswitches] sw_lolast and sw_hilast with sw_last") +{ + // The behavior is the same in this case, regardless of the keyrange + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + sw_last=40 sw_lolast=57 sw_hilast=59 key=70 sample=*saw + sw_lolast=60 sw_hilast=62 sw_last=41 key=72 sample=*sine + )"); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 40, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 41, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 57, 64); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 41, 64); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 60, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(synth.getRegionView(1)->isSwitchedOn()); + synth.noteOn(0, 40, 64); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(synth.getRegionView(1)->isSwitchedOn()); +} diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index 7e20583c..312d17a0 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -362,6 +362,48 @@ TEST_CASE("[Region] Parsing opcodes") REQUIRE(*region.lastKeyswitch == 0); } + SECTION("sw_lolast/hilast") + { + REQUIRE(!region.lastKeyswitchRange); + region.parseOpcode({ "sw_lolast", "4" }); + REQUIRE(region.lastKeyswitchRange); + REQUIRE(*region.lastKeyswitchRange == Range(4, 4)); + region.parseOpcode({ "sw_hilast", "128" }); + REQUIRE(*region.lastKeyswitchRange == Range(4, 127)); + region.parseOpcode({ "sw_hilast", "63" }); + REQUIRE(*region.lastKeyswitchRange == Range(4, 63)); + region.parseOpcode({ "sw_lolast", "64" }); + REQUIRE(*region.lastKeyswitchRange == Range(64, 64)); + region.parseOpcode({ "sw_lolast", "-1" }); + REQUIRE(*region.lastKeyswitchRange == Range(0, 64)); + } + + SECTION("sw_hilast disables sw_last") + { + REQUIRE(!region.lastKeyswitchRange); + REQUIRE(!region.lastKeyswitch); + region.parseOpcode({ "sw_last", "4" }); + REQUIRE(region.lastKeyswitch); + region.parseOpcode({ "sw_hilast", "63" }); + REQUIRE(region.lastKeyswitchRange); + REQUIRE(!region.lastKeyswitch); + region.parseOpcode({ "sw_last", "4" }); + REQUIRE(!region.lastKeyswitch); + } + + SECTION("sw_lolast disables sw_last") + { + REQUIRE(!region.lastKeyswitchRange); + REQUIRE(!region.lastKeyswitch); + region.parseOpcode({ "sw_last", "4" }); + REQUIRE(region.lastKeyswitch); + region.parseOpcode({ "sw_lolast", "63" }); + REQUIRE(region.lastKeyswitchRange); + REQUIRE(!region.lastKeyswitch); + region.parseOpcode({ "sw_last", "4" }); + REQUIRE(!region.lastKeyswitch); + } + SECTION("sw_up") { REQUIRE(!region.upKeyswitch); From 74a676b4930bc60baae7e55c08f3865037a572ab Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Tue, 27 Oct 2020 15:11:51 +0100 Subject: [PATCH 006/668] sw_default with sw_lolast and sw_hilast --- src/sfizz/Synth.cpp | 12 +++++++++++- tests/RegionActivationT.cpp | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index ba5c109d..b15e8adb 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -628,6 +628,17 @@ void sfz::Synth::finalizeSfzLoad() insertPairUniquely(keyswitchLabels, *region->lastKeyswitch, *region->keyswitchLabel); } + if (region->lastKeyswitchRange) { + auto& range = *region->lastKeyswitchRange; + if (currentSwitch) + region->keySwitched = range.containsWithEnd(*currentSwitch); + + if (region->keyswitchLabel) { + for (uint8_t note = range.getStart(), end = range.getEnd(); note <= end; note++) + insertPairUniquely(keyswitchLabels, note, *region->keyswitchLabel); + } + } + // Some regions had group number but no "group-level" opcodes handled the polyphony while (polyphonyGroups.size() <= region->group) { polyphonyGroups.emplace_back(); @@ -1176,7 +1187,6 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc region->keySwitched = true; for (auto& region : noteActivationLists[noteNumber]) { - if (region->registerNoteOn(noteNumber, velocity, randValue)) { for (auto& voice : voices) { if (voice->checkOffGroup(region, delay, noteNumber)) { diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index 6c5a3ed9..be5c808c 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -427,7 +427,6 @@ TEST_CASE("[Keyswitches] sw_previous out of range") TEST_CASE("[Keyswitches] sw_lolast and sw_hilast") { - // The behavior is the same in this case, regardless of the keyrange sfz::Synth synth; synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( sw_lolast=57 sw_hilast=59 key=70 sample=*saw @@ -460,7 +459,6 @@ TEST_CASE("[Keyswitches] sw_lolast and sw_hilast") TEST_CASE("[Keyswitches] sw_lolast and sw_hilast with sw_last") { - // The behavior is the same in this case, regardless of the keyrange sfz::Synth synth; synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( sw_last=40 sw_lolast=57 sw_hilast=59 key=70 sample=*saw @@ -487,3 +485,15 @@ TEST_CASE("[Keyswitches] sw_lolast and sw_hilast with sw_last") REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); REQUIRE(synth.getRegionView(1)->isSwitchedOn()); } + +TEST_CASE("[Keyswitches] sw_lolast and sw_hilast with sw_default") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + sw_default=58 + sw_lolast=57 sw_hilast=59 key=70 sample=*saw + sw_lolast=60 sw_hilast=62 key=72 sample=*sine + )"); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); +} From 84019a00e4701099d1f0c97ce892125fdac2d85b Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 28 Oct 2020 09:17:10 +0100 Subject: [PATCH 007/668] Let the flex eg free-run when set as the ampeg --- src/sfizz/FlexEnvelope.cpp | 25 +++++--- src/sfizz/FlexEnvelope.h | 7 +++ .../modulations/sources/FlexEnvelope.cpp | 6 ++ tests/FlexEGT.cpp | 59 +++++++++++++++++++ 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/sfizz/FlexEnvelope.cpp b/src/sfizz/FlexEnvelope.cpp index 3a7402dd..4158978f 100644 --- a/src/sfizz/FlexEnvelope.cpp +++ b/src/sfizz/FlexEnvelope.cpp @@ -45,6 +45,7 @@ struct FlexEnvelope::Impl { float currentTime_ { 0.0 }; absl::optional currentFramesUntilRelease_ { absl::nullopt }; bool isReleased_ { false }; + bool freeRunning_ { false }; // void process(absl::Span out); @@ -70,6 +71,15 @@ void FlexEnvelope::configure(const FlexEGDescription* desc) { Impl& impl = *impl_; impl.desc_ = desc; + + // + impl.freeRunning_ = false; + impl.isReleased_ = false; + + // + impl.currentStageNumber_ = 0; + impl.currentLevel_ = 0.0; + impl.currentTime_ = 0.0; } void FlexEnvelope::start(unsigned triggerDelay) @@ -90,12 +100,12 @@ void FlexEnvelope::start(unsigned triggerDelay) impl.stageSustained_ = desc.sustain == 0; impl.stageCurve_ = &point.curve(); impl.currentFramesUntilRelease_ = absl::nullopt; - impl.isReleased_ = false; +} - // - impl.currentStageNumber_ = 0; - impl.currentLevel_ = 0.0; - impl.currentTime_ = 0.0; +void FlexEnvelope::setFreeRunning(bool freeRunning) +{ + Impl& impl = *impl_; + impl.freeRunning_ = freeRunning; } void FlexEnvelope::release(unsigned releaseDelay) @@ -134,7 +144,6 @@ void FlexEnvelope::Impl::process(absl::Span out) const FlexEGDescription& desc = *desc_; size_t numFrames = out.size(); const float samplePeriod = samplePeriod_; - // Skip the initial delay, for frame-accurate trigger size_t skipFrames = std::min(numFrames, delayFramesLeft_); if (skipFrames > 0) { @@ -171,9 +180,9 @@ void FlexEnvelope::Impl::process(absl::Span out) } } } - while (!stageSustained_ && currentTime_ >= stageTime_) { + while ((!stageSustained_ || freeRunning_) && currentTime_ >= stageTime_) { // advance through completed timed stages - ASSERT(isReleased_ || !stageSustained_); + ASSERT(isReleased_ || !stageSustained_ || freeRunning_); if (stageTime_ == 0) { // if stage is of zero duration, immediate transition to level currentLevel_ = stageTargetLevel_; diff --git a/src/sfizz/FlexEnvelope.h b/src/sfizz/FlexEnvelope.h index d1d01a4a..d8cc2bf0 100644 --- a/src/sfizz/FlexEnvelope.h +++ b/src/sfizz/FlexEnvelope.h @@ -30,6 +30,13 @@ public: */ void configure(const FlexEGDescription* desc); + /** + * @brief Set the EG to be freeRunning or not + * + * @param freeRunning + */ + void setFreeRunning(bool freeRunning); + /** Start processing an EG as a region is triggered. */ diff --git a/src/sfizz/modulations/sources/FlexEnvelope.cpp b/src/sfizz/modulations/sources/FlexEnvelope.cpp index 557dd4db..13965373 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.cpp +++ b/src/sfizz/modulations/sources/FlexEnvelope.cpp @@ -38,6 +38,12 @@ void FlexEnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, FlexEnvelope* eg = voice->getFlexEG(egIndex); eg->configure(®ion->flexEGs[egIndex]); + bool freeRunning = ( + (region->loopMode == SfzLoopMode::one_shot && region->isOscillator()) + ); + if (freeRunning && region->flexAmpEG && egIndex == *region->flexAmpEG) + eg->setFreeRunning(true); + eg->start(delay); } diff --git a/tests/FlexEGT.cpp b/tests/FlexEGT.cpp index 5a8412eb..439ead5c 100644 --- a/tests/FlexEGT.cpp +++ b/tests/FlexEGT.cpp @@ -6,6 +6,7 @@ #include "sfizz/Synth.h" +#include "sfizz/AudioBuffer.h" #include "sfizz/FlexEnvelope.h" #include "catch2/catch.hpp" #include "TestHelpers.h" @@ -357,3 +358,61 @@ TEST_CASE("[FlexEG] Early release") } } } + +TEST_CASE("[FlexEG] Free-running flex AmpEG (no sustain)") +{ + sfz::Synth synth; + + synth.loadSfzString(fs::current_path(), R"( + sample=*noise + key=60 + loop_mode=one_shot + eg1_ampeg=1 + eg1_time1=0 eg1_level1=1 + eg1_time2=0.03 eg1_level2=0.6 + eg1_time3=0.06 eg1_level3=0.3 + eg1_time4=0.12 eg1_level4=0.1 + eg1_time5=0.3 eg1_level5=0 + sample=*noise + key=62 + loop_mode=one_shot + eg1_ampeg=1 + eg1_time1=0 eg1_level1=1 + eg1_time2=0.03 eg1_level2=0.6 + eg1_time3=0.06 eg1_level3=0.3 + eg1_time4=0.12 eg1_level4=0.1 + eg1_time5=0.3 eg1_level5=0 eg1_sustain=5 + sample=*noise + key=64 + eg1_ampeg=1 + eg1_time1=0 eg1_level1=1 + eg1_time2=0.03 eg1_level2=0.6 + eg1_time3=0.06 eg1_level3=0.3 + eg1_time4=0.12 eg1_level4=0.1 + eg1_time5=0.3 eg1_level5=0 eg1_sustain=5 + )"); + synth.noteOn(0, 60, 0); + sfz::AudioBuffer buffer { 2, 256 }; + synth.renderBlock(buffer); + REQUIRE( synth.getNumActiveVoices(true) == 1 ); + for (unsigned i = 0; i < 100; ++i) + synth.renderBlock(buffer); + REQUIRE( synth.getNumActiveVoices(true) == 0 ); + + synth.noteOn(0, 62, 0); + synth.renderBlock(buffer); + REQUIRE( synth.getNumActiveVoices(true) == 1 ); + for (unsigned i = 0; i < 100; ++i) + synth.renderBlock(buffer); + REQUIRE( synth.getNumActiveVoices(true) == 0 ); + + synth.noteOn(0, 64, 0); + synth.renderBlock(buffer); + REQUIRE( synth.getNumActiveVoices(true) == 1 ); + for (unsigned i = 0; i < 100; ++i) + synth.renderBlock(buffer); + REQUIRE( synth.getNumActiveVoices(true) == 1 ); + synth.noteOff(0, 64, 0); // the release stage is 0 duration + synth.renderBlock(buffer); + REQUIRE( synth.getNumActiveVoices(true) == 0 ); +} From 8dd169c9d2c5e510d0ba761c4c526c87e097c8ee Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 28 Oct 2020 16:12:42 +0100 Subject: [PATCH 008/668] Handle sw_default in --- src/sfizz/Region.cpp | 4 +++- src/sfizz/Region.h | 1 + src/sfizz/Synth.cpp | 3 +++ tests/RegionActivationT.cpp | 30 ++++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 42be5f79..f131febf 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1390,11 +1390,13 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) gainToEffect[effectNumber] = *value / 100; break; } + case hash("sw_default"): + setValueFromOpcode(opcode, defaultSwitch, Default::keyRange); + break; // Ignored opcodes case hash("hichan"): case hash("lochan"): - case hash("sw_default"): case hash("ampeg_depth"): case hash("ampeg_vel&depth"): break; diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 7fb0b695..932aecf4 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -353,6 +353,7 @@ struct Region { absl::optional upKeyswitch {}; // sw_up absl::optional downKeyswitch {}; // sw_down absl::optional previousKeyswitch {}; // sw_previous + absl::optional defaultSwitch {}; SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel bool checkSustain { Default::checkSustain }; // sustain_sw bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b15e8adb..271e1e3e 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -193,6 +193,9 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) if (lastRegion->previousKeyswitch) previousKeyswitchLists.push_back(lastRegion.get()); + if (lastRegion->defaultSwitch) + currentSwitch = *lastRegion->defaultSwitch; + // There was a combination of group= and polyphony= on a region, so set the group polyphony if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) setGroupPolyphony(lastRegion->group, lastRegion->polyphony); diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index be5c808c..b67690ee 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -497,3 +497,33 @@ TEST_CASE("[Keyswitches] sw_lolast and sw_hilast with sw_default") REQUIRE(synth.getRegionView(0)->isSwitchedOn()); REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); } + +TEST_CASE("[Keyswitches] Multiple sw_default") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + sw_default=60 + sw_last=60 key=70 sample=*saw + sw_default=58 + sw_last=59 key=72 sample=*saw + sw_default=59 + sw_last=62 key=73 sample=*saw + )"); + REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); + // Only the last one is taken into account + REQUIRE(synth.getRegionView(1)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(2)->isSwitchedOn()); +} + +TEST_CASE("[Keyswitches] Multiple sw_default, in region") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + sw_default=60 + sw_last=58 key=70 sample=*saw + sw_default=58 sw_last=59 key=72 sample=*saw + )"); + REQUIRE(synth.getRegionView(0)->isSwitchedOn()); + REQUIRE(!synth.getRegionView(1)->isSwitchedOn()); +} + From ff1d749ee78f7a4081408e02fdced7abc98ad21f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 7 Oct 2020 16:41:31 +0200 Subject: [PATCH 009/668] Add library: st_audiofile --- .gitmodules | 4 + external/st_audiofile/CMakeLists.txt | 37 ++++ external/st_audiofile/LICENSE.md | 25 +++ external/st_audiofile/src/st_audiofile.c | 206 ++++++++++++++++++ external/st_audiofile/src/st_audiofile.h | 52 +++++ external/st_audiofile/src/st_audiofile.hpp | 168 ++++++++++++++ .../st_audiofile/src/st_audiofile_common.c | 35 +++ external/st_audiofile/src/st_audiofile_libs.c | 9 + external/st_audiofile/src/st_audiofile_libs.h | 9 + .../st_audiofile/src/st_audiofile_sndfile.c | 120 ++++++++++ external/st_audiofile/src/st_info.c | 33 +++ external/st_audiofile/thirdparty/dr_libs | 1 + 12 files changed, 699 insertions(+) create mode 100644 external/st_audiofile/CMakeLists.txt create mode 100644 external/st_audiofile/LICENSE.md create mode 100644 external/st_audiofile/src/st_audiofile.c create mode 100644 external/st_audiofile/src/st_audiofile.h create mode 100644 external/st_audiofile/src/st_audiofile.hpp create mode 100644 external/st_audiofile/src/st_audiofile_common.c create mode 100644 external/st_audiofile/src/st_audiofile_libs.c create mode 100644 external/st_audiofile/src/st_audiofile_libs.h create mode 100644 external/st_audiofile/src/st_audiofile_sndfile.c create mode 100644 external/st_audiofile/src/st_info.c create mode 160000 external/st_audiofile/thirdparty/dr_libs diff --git a/.gitmodules b/.gitmodules index 1247ca5f..f4453c71 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,7 @@ path = editor/external/vstgui4 url = https://github.com/sfztools/vstgui.git shallow = true +[submodule "external/st_audiofile/thirdparty/dr_libs"] + path = external/st_audiofile/thirdparty/dr_libs + url = https://github.com/mackron/dr_libs.git + shallow = true diff --git a/external/st_audiofile/CMakeLists.txt b/external/st_audiofile/CMakeLists.txt new file mode 100644 index 00000000..137f3201 --- /dev/null +++ b/external/st_audiofile/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.5) +project(st_audiofile) + +option(ST_AUDIO_FILE_USE_SNDFILE "Use sndfile" OFF) +set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "" CACHE STRING "Name of external sndfile target") + +add_library(st_audiofile STATIC + "src/st_audiofile.c" + "src/st_audiofile_common.c" + "src/st_audiofile_libs.c" + "src/st_audiofile_sndfile.c") +target_include_directories(st_audiofile + PUBLIC "src" + PUBLIC "thirdparty/dr_libs") + +add_executable(st_info + "src/st_info.c") +target_link_libraries(st_info + PRIVATE st_audiofile) + +if(ST_AUDIO_FILE_USE_SNDFILE) + target_compile_definitions(st_audiofile + PUBLIC "ST_AUDIO_FILE_USE_SNDFILE=1") + if(ST_AUDIO_FILE_EXTERNAL_SNDFILE) + target_link_libraries(st_audiofile + PRIVATE "${ST_AUDIO_FILE_EXTERNAL_SNDFILE}") + else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(Sndfile "sndfile" REQUIRED) + target_include_directories(st_audiofile + PUBLIC ${Sndfile_INCLUDE_DIRS}) + target_link_libraries(st_audiofile + PUBLIC ${Sndfile_LIBRARIES}) + link_directories( + ${Sndfile_LIBRARY_DIRS}) + endif() +endif() diff --git a/external/st_audiofile/LICENSE.md b/external/st_audiofile/LICENSE.md new file mode 100644 index 00000000..bb52be90 --- /dev/null +++ b/external/st_audiofile/LICENSE.md @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2020, Jean-Pierre Cimalando +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c new file mode 100644 index 00000000..efaccb85 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "st_audiofile.h" +#if !defined(ST_AUDIO_FILE_USE_SNDFILE) +#include "st_audiofile_libs.h" +#include + +struct st_audio_file { + int type; + union { + drwav *wav; + drflac *flac; + }; +}; + +enum { + st_audio_file_null = -1, +}; + +st_audio_file* st_open_file(const char* filename) +{ + st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file)); + if (!af) + return NULL; + + af->type = st_audio_file_null; + + if (af->type == st_audio_file_null) { + af->wav = (drwav*)malloc(sizeof(drwav)); + if (!af->wav) { + free(af); + return NULL; + } + if (!drwav_init_file(af->wav, filename, NULL)) + free(af->wav); + else + af->type = st_audio_file_wav; + } + + if (af->type == st_audio_file_null) { + af->flac = drflac_open_file(filename, NULL); + if (af->flac) + af->type = st_audio_file_flac; + } + + if (af->type == st_audio_file_null) { + free(af); + af = NULL; + } + + return af; +} + +#if defined(_WIN32) +st_audio_file* st_open_file_w(const wchar_t* filename) +{ + st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file)); + if (!af) + return NULL; + + af->type = st_audio_file_null; + + if (af->type == st_audio_file_null) { + af->wav = (drwav*)malloc(sizeof(drwav)); + if (!af->wav) { + free(af); + return NULL; + } + if (!drwav_init_file_w(af->wav, filename, NULL)) + free(af->wav); + else + af->type = st_audio_file_wav; + } + + if (af->type == st_audio_file_null) { + af->flac = drflac_open_file_w(filename, NULL); + if (af->flac) + af->type = st_audio_file_flac; + } + + if (af->type == st_audio_file_null) { + free(af); + af = NULL; + } + + return af; +} +#endif + +void st_close(st_audio_file* af) +{ + switch (af->type) { + case st_audio_file_wav: + drwav_uninit(af->wav); + free(af->wav); + break; + case st_audio_file_flac: + drflac_close(af->flac); + break; + } + + af->type = st_audio_file_null; +} + +int st_get_type(st_audio_file* af) +{ + return af->type; +} + +uint32_t st_get_channels(st_audio_file* af) +{ + uint32_t channels = 0; + + switch (af->type) { + case st_audio_file_wav: + channels = af->wav->channels; + break; + case st_audio_file_flac: + channels = af->flac->channels; + break; + } + + return channels; +} + +float st_get_sample_rate(st_audio_file* af) +{ + float sample_rate = 0; + + switch (af->type) { + case st_audio_file_wav: + sample_rate = af->wav->sampleRate; + break; + case st_audio_file_flac: + sample_rate = af->flac->sampleRate; + break; + } + + return sample_rate; +} + +uint64_t st_get_frame_count(st_audio_file* af) +{ + uint64_t frames = 0; + + switch (af->type) { + case st_audio_file_wav: + frames = af->wav->totalPCMFrameCount; + break; + case st_audio_file_flac: + frames = af->flac->totalPCMFrameCount; + break; + } + + return frames; +} + +bool st_seek(st_audio_file* af, uint64_t frame) +{ + bool success = false; + + switch (af->type) { + case st_audio_file_wav: + success = drwav_seek_to_pcm_frame(af->wav, frame); + break; + case st_audio_file_flac: + success = drflac_seek_to_pcm_frame(af->flac, frame); + break; + } + + return success; +} + +uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count) +{ + switch (af->type) { + case st_audio_file_wav: + count = drwav_read_pcm_frames_s16(af->wav, count, buffer); + break; + case st_audio_file_flac: + count = drflac_read_pcm_frames_s16(af->flac, count, buffer); + break; + } + + return count; +} + +uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count) +{ + switch (af->type) { + case st_audio_file_wav: + count = drwav_read_pcm_frames_f32(af->wav, count, buffer); + break; + case st_audio_file_flac: + count = drflac_read_pcm_frames_f32(af->flac, count, buffer); + break; + } + + return count; +} + +#endif // !defined(ST_AUDIO_FILE_USE_SNDFILE) diff --git a/external/st_audiofile/src/st_audiofile.h b/external/st_audiofile/src/st_audiofile.h new file mode 100644 index 00000000..704addb8 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile.h @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#include +#endif +#include +#include +#if defined(_WIN32) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_audio_file st_audio_file; + +typedef enum st_audio_file_type { + st_audio_file_wav, + st_audio_file_flac, + st_audio_file_ogg, + st_audio_file_other, +} st_audio_file_type; + +st_audio_file* st_open_file(const char* filename); +#if defined(_WIN32) +st_audio_file* st_open_file_w(const wchar_t* filename); +#endif +void st_close(st_audio_file* af); +int st_get_type(st_audio_file* af); +const char* st_get_type_string(st_audio_file* af); +const char* st_type_string(int type); +uint32_t st_get_channels(st_audio_file* af); +float st_get_sample_rate(st_audio_file* af); +uint64_t st_get_frame_count(st_audio_file* af); +bool st_seek(st_audio_file* af, uint64_t frame); +uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count); +uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count); + +#if defined(ST_AUDIO_FILE_USE_SNDFILE) +SNDFILE* st_get_sndfile_handle(st_audio_file* af); +int st_get_sndfile_format(st_audio_file* af); +#endif + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/external/st_audiofile/src/st_audiofile.hpp b/external/st_audiofile/src/st_audiofile.hpp new file mode 100644 index 00000000..c30da975 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile.hpp @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "st_audiofile.h" + +class ST_AudioFile { +public: + constexpr ST_AudioFile() noexcept; + ~ST_AudioFile() noexcept; + + ST_AudioFile(ST_AudioFile&&) noexcept; + ST_AudioFile& operator=(ST_AudioFile&&) noexcept; + + ST_AudioFile(const ST_AudioFile&) = delete; + ST_AudioFile& operator=(const ST_AudioFile&) = delete; + + explicit operator bool() const noexcept; + void reset(st_audio_file* new_af = nullptr) noexcept; + + bool open_file(const char* filename); +#if defined(_WIN32) + bool open_file_w(const wchar_t* filename); +#endif + + int get_type() const noexcept; + const char* get_type_string() const noexcept; + static const char* type_string(int type) noexcept; + uint32_t get_channels() const noexcept; + float get_sample_rate() const noexcept; + uint64_t get_frame_count() const noexcept; + + bool seek(uint64_t frame) noexcept; + uint64_t read_s16(int16_t* buffer, uint64_t count) noexcept; + uint64_t read_f32(float* buffer, uint64_t count) noexcept; + + st_audio_file* get_handle() const noexcept; + +#if defined(ST_AUDIO_FILE_USE_SNDFILE) + void* get_sndfile_handle() const noexcept; + int get_sndfile_format() const noexcept; +#endif + +private: + st_audio_file* af_ = nullptr; +}; + +//------------------------------------------------------------------------------ + +inline constexpr ST_AudioFile::ST_AudioFile() noexcept +{ +} + +inline ST_AudioFile::~ST_AudioFile() noexcept +{ + reset(); +} + +ST_AudioFile::ST_AudioFile(ST_AudioFile&& other) noexcept + : af_(other.af_) +{ + other.af_ = nullptr; +} + +ST_AudioFile& ST_AudioFile::operator=(ST_AudioFile&& other) noexcept +{ + if (this != &other) { + if (af_) + st_close(af_); + af_ = other.af_; + other.af_ = nullptr; + } + return *this; +} + +inline ST_AudioFile::operator bool() const noexcept +{ + return af_ != nullptr; +} + +inline void ST_AudioFile::reset(st_audio_file* new_af) noexcept +{ + if (af_ != new_af) { + if (af_) + st_close(af_); + af_ = new_af; + } +} + +bool ST_AudioFile::open_file(const char* filename) +{ + st_audio_file* new_af = st_open_file(filename); + reset(new_af); + return new_af != nullptr; +} +#if defined(_WIN32) +inline bool ST_AudioFile::open_file_w(const wchar_t* filename) +{ + st_audio_file* new_af = st_open_file_w(filename); + reset(new_af); + return new_af != nullptr; +} +#endif + +inline int ST_AudioFile::get_type() const noexcept +{ + return st_get_type(af_); +} + +inline const char* ST_AudioFile::get_type_string() const noexcept +{ + return st_get_type_string(af_); +} + +inline const char* ST_AudioFile::type_string(int type) noexcept +{ + return st_type_string(type); +} + +inline uint32_t ST_AudioFile::get_channels() const noexcept +{ + return st_get_channels(af_); +} + +inline float ST_AudioFile::get_sample_rate() const noexcept +{ + return st_get_sample_rate(af_); +} + +inline uint64_t ST_AudioFile::get_frame_count() const noexcept +{ + return st_get_frame_count(af_); +} + +inline bool ST_AudioFile::seek(uint64_t frame) noexcept +{ + return st_seek(af_, frame); +} + +inline uint64_t ST_AudioFile::read_s16(int16_t* buffer, uint64_t count) noexcept +{ + return st_read_s16(af_, buffer, count); +} + +inline uint64_t ST_AudioFile::read_f32(float* buffer, uint64_t count) noexcept +{ + return st_read_f32(af_, buffer, count); +} + +inline st_audio_file* ST_AudioFile::get_handle() const noexcept +{ + return af_; +} + +#if defined(ST_AUDIO_FILE_USE_SNDFILE) +inline void* ST_AudioFile::get_sndfile_handle() const noexcept +{ + return st_get_sndfile_handle(af_); +} + +int ST_AudioFile::get_sndfile_format() const noexcept +{ + return st_get_sndfile_format(af_); +} +#endif diff --git a/external/st_audiofile/src/st_audiofile_common.c b/external/st_audiofile/src/st_audiofile_common.c new file mode 100644 index 00000000..2b6e5d34 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile_common.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "st_audiofile.h" +#include + +const char* st_get_type_string(st_audio_file* af) +{ + return st_type_string(st_get_type(af)); +} + +const char* st_type_string(int type) +{ + const char *type_string = NULL; + + switch (type) { + case st_audio_file_wav: + type_string = "WAV"; + break; + case st_audio_file_flac: + type_string = "FLAC"; + break; + case st_audio_file_ogg: + type_string = "OGG"; + break; + case st_audio_file_other: + type_string = "other"; + break; + } + + return type_string; +} diff --git a/external/st_audiofile/src/st_audiofile_libs.c b/external/st_audiofile/src/st_audiofile_libs.c new file mode 100644 index 00000000..77ae28c2 --- /dev/null +++ b/external/st_audiofile/src/st_audiofile_libs.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#define DR_WAV_IMPLEMENTATION +#define DR_FLAC_IMPLEMENTATION +#include "st_audiofile_libs.h" diff --git a/external/st_audiofile/src/st_audiofile_libs.h b/external/st_audiofile/src/st_audiofile_libs.h new file mode 100644 index 00000000..8620cdce --- /dev/null +++ b/external/st_audiofile/src/st_audiofile_libs.h @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "dr_wav.h" +#include "dr_flac.h" diff --git a/external/st_audiofile/src/st_audiofile_sndfile.c b/external/st_audiofile/src/st_audiofile_sndfile.c new file mode 100644 index 00000000..5b3e9b9e --- /dev/null +++ b/external/st_audiofile/src/st_audiofile_sndfile.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "st_audiofile.h" +#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#if defined(_WIN32) +#include +#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 +#endif +#include +#include + +struct st_audio_file { + SNDFILE* snd; + SF_INFO info; +}; + +st_audio_file* st_open_file(const char* filename) +{ + st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file)); + if (!af) + return NULL; + + af->snd = sf_open(filename, SFM_READ, &af->info); + if (!af->snd) { + free(af); + return NULL; + } + + return af; +} + +#if defined(_WIN32) +st_audio_file* st_open_file_w(const wchar_t* filename) +{ + st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file)); + if (!af) + return NULL; + + af->snd = sf_wchar_open(filename, SFM_READ, &af->info); + if (!af->snd) { + free(af); + return NULL; + } + + return af; +} +#endif + +void st_close(st_audio_file* af) +{ + if (af->snd) { + sf_close(af->snd); + af->snd = NULL; + } +} + +int st_get_type(st_audio_file* af) +{ + int type = st_audio_file_other; + + switch (af->info.format & SF_FORMAT_TYPEMASK) { + case SF_FORMAT_WAV: + type = st_audio_file_wav; + break; + case SF_FORMAT_FLAC: + type = st_audio_file_flac; + break; + case SF_FORMAT_OGG: + type = st_audio_file_ogg; + break; + } + + return type; +} + +uint32_t st_get_channels(st_audio_file* af) +{ + return af->info.channels; +} + +float st_get_sample_rate(st_audio_file* af) +{ + return af->info.samplerate; +} + +uint64_t st_get_frame_count(st_audio_file* af) +{ + return af->info.frames; +} + +bool st_seek(st_audio_file* af, uint64_t frame) +{ + return sf_seek(af->snd, frame, SEEK_SET) != -1; +} + +uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count) +{ + return sf_readf_short(af->snd, buffer, count); +} + +uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count) +{ + return sf_readf_float(af->snd, buffer, count); +} + +SNDFILE* st_get_sndfile_handle(st_audio_file* af) +{ + return af->snd; +} + +int st_get_sndfile_format(st_audio_file* af) +{ + return af->info.format; +} + +#endif // defined(ST_AUDIO_FILE_USE_SNDFILE) diff --git a/external/st_audiofile/src/st_info.c b/external/st_audiofile/src/st_info.c new file mode 100644 index 00000000..dc5680f4 --- /dev/null +++ b/external/st_audiofile/src/st_info.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "st_audiofile.h" +#include +#include + +int main(int argc, char* argv[]) +{ + if (argc != 2) { + fprintf(stderr, "Please indicate a sound file.\n"); + return 1; + } + + const char* filename = argv[1]; + + st_audio_file* af = st_open_file(filename); + if (!af) { + fprintf(stderr, "Could not open the sound file.\n"); + return 1; + } + + printf("File name : %s\n", filename); + printf("File type : %s\n", st_get_type_string(af)); + printf("Channels : %u\n", st_get_channels(af)); + printf("Sample rate : %f\n", st_get_sample_rate(af)); + printf("Frames : %" PRIu64 "\n", st_get_frame_count(af)); + + return 0; +} diff --git a/external/st_audiofile/thirdparty/dr_libs b/external/st_audiofile/thirdparty/dr_libs new file mode 160000 index 00000000..cac1785c --- /dev/null +++ b/external/st_audiofile/thirdparty/dr_libs @@ -0,0 +1 @@ +Subproject commit cac1785cee4abb455817b43d5dee33b49d61be2f From d5aad5836623b9da44bbf357bccd9ba3da7c97f3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 7 Oct 2020 16:42:25 +0200 Subject: [PATCH 010/668] Eliminate the strict requirement of libsndfile --- CMakeLists.txt | 1 + benchmarks/CMakeLists.txt | 2 +- cmake/SfizzConfig.cmake | 43 ++++++---- src/CMakeLists.txt | 4 +- src/sfizz/AudioReader.cpp | 157 +++++++++++++++++++++++-------------- src/sfizz/AudioReader.h | 9 +-- src/sfizz/FileMetadata.cpp | 10 +-- src/sfizz/FileMetadata.h | 48 ++++++++++-- src/sfizz/FilePool.cpp | 3 +- tests/CMakeLists.txt | 8 +- tests/FileInstrument.cpp | 21 ++--- 11 files changed, 196 insertions(+), 110 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32455b1b..d3896ef5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF) option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF) option (SFIZZ_DEVTOOLS "Enable developer tools build [default: OFF]" OFF) option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON) +option (SFIZZ_USE_SNDFILE "Enable use of the sndfile library [default: ON]" ON) option (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg [default: OFF]" OFF) option (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically [default: OFF]" OFF) option (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds [default: OFF]" OFF) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index d53ff15f..2f33e648 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -86,7 +86,7 @@ sfizz_add_benchmark(bm_flacfile BM_flacfile.cpp) target_link_libraries(bm_flacfile PRIVATE sfizz-sndfile) sfizz_add_benchmark(bm_audioReaders BM_audioReaders.cpp ../src/sfizz/AudioReader.cpp) -target_link_libraries(bm_audioReaders PRIVATE sfizz-sndfile) +target_link_libraries(bm_audioReaders PRIVATE st_audiofile sfizz-sndfile) sfizz_add_benchmark(bm_readChunk BM_readChunk.cpp) target_link_libraries(bm_readChunk PRIVATE sfizz-sndfile) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index b488b4db..f9387a09 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -79,30 +79,40 @@ function(sfizz_enable_fast_math NAME) endif() endfunction() -# The sndfile library -add_library(sfizz-sndfile INTERFACE) - # The jsl utility library for C++ add_library(sfizz-jsl INTERFACE) target_include_directories(sfizz-jsl INTERFACE "external/jsl/include") -if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - find_package(SndFile CONFIG REQUIRED) - find_path(SNDFILE_INCLUDE_DIR sndfile.hh) - target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}") - target_link_libraries(sfizz-sndfile INTERFACE SndFile::sndfile) -else() - find_package(PkgConfig REQUIRED) - pkg_check_modules(SNDFILE "sndfile" REQUIRED) - target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS}) - if (SFIZZ_STATIC_DEPENDENCIES) - target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES}) +# The sndfile library +if (SFIZZ_USE_SNDFILE OR SFIZZ_TESTS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) + add_library(sfizz-sndfile INTERFACE) + if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + find_package(SndFile CONFIG REQUIRED) + find_path(SNDFILE_INCLUDE_DIR "sndfile.hh") + target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}") + target_link_libraries(sfizz-sndfile INTERFACE SndFile::sndfile) else() - target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES}) + find_package(PkgConfig REQUIRED) + pkg_check_modules(SNDFILE "sndfile" REQUIRED) + target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS}) + if (SFIZZ_STATIC_DEPENDENCIES) + target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES}) + else() + target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES}) + endif() + link_directories(${SNDFILE_LIBRARY_DIRS}) endif() - link_directories(${SNDFILE_LIBRARY_DIRS}) endif() +# The st_audiofile library +if (SFIZZ_USE_SNDFILE) + set(ST_AUDIO_FILE_USE_SNDFILE ON CACHE BOOL "" FORCE) + set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "sfizz-sndfile" CACHE STRING "" FORCE) +else() + set(ST_AUDIO_FILE_USE_SNDFILE OFF CACHE BOOL "" FORCE) + set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "" CACHE STRING "" FORCE) +endif() +add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL) # If we build with Clang, optionally use libc++. Enabled by default on Apple OS. cmake_dependent_option(USE_LIBCPP "Use libc++ with clang" "${APPLE}" @@ -154,6 +164,7 @@ Build VST plug-in: ${SFIZZ_VST} Build AU plug-in: ${SFIZZ_AU} Build benchmarks: ${SFIZZ_BENCHMARKS} Build tests: ${SFIZZ_TESTS} +Use sndfile: ${SFIZZ_USE_SNDFILE} Use vcpkg: ${SFIZZ_USE_VCPKG} Statically link dependencies: ${SFIZZ_STATIC_DEPENDENCIES} Link libatomic: ${SFIZZ_LINK_LIBATOMIC} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b4a55653..d005c794 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -218,7 +218,7 @@ target_sources(sfizz_static PRIVATE target_include_directories (sfizz_static PUBLIC .) target_include_directories (sfizz_static PUBLIC external) target_link_libraries (sfizz_static PUBLIC absl::strings absl::span) -target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) +target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp") if (WIN32) target_compile_definitions (sfizz_static PRIVATE _USE_MATH_DEFINES) @@ -245,7 +245,7 @@ if (SFIZZ_SHARED) ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) target_include_directories (sfizz_shared PRIVATE .) target_include_directories (sfizz_shared PRIVATE external) - target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) + target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) if (WIN32) target_compile_definitions (sfizz_shared PRIVATE _USE_MATH_DEFINES) endif() diff --git a/src/sfizz/AudioReader.cpp b/src/sfizz/AudioReader.cpp index e906e3ae..6f9fe1b9 100644 --- a/src/sfizz/AudioReader.cpp +++ b/src/sfizz/AudioReader.cpp @@ -5,51 +5,60 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "AudioReader.h" -#include +#include "FileMetadata.h" +#include +#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#include +#endif #include namespace sfz { class BasicSndfileReader : public AudioReader { public: - explicit BasicSndfileReader(SndfileHandle handle) : handle_(handle) {} + explicit BasicSndfileReader(ST_AudioFile handle) : handle_(std::move(handle)) {} virtual ~BasicSndfileReader() {} int format() const override; int64_t frames() const override; unsigned channels() const override; unsigned sampleRate() const override; - bool getInstrument(SF_INSTRUMENT* instrument) override; + bool getInstrument(InstrumentInfo* instrument) override; protected: - SndfileHandle handle_; + ST_AudioFile handle_; }; int BasicSndfileReader::format() const { - return handle_.format(); + return handle_.get_type(); } int64_t BasicSndfileReader::frames() const { - return handle_.frames(); + return handle_.get_frame_count(); } unsigned BasicSndfileReader::channels() const { - return handle_.channels(); + return handle_.get_channels(); } unsigned BasicSndfileReader::sampleRate() const { - return handle_.samplerate(); + return handle_.get_sample_rate(); } -bool BasicSndfileReader::getInstrument(SF_INSTRUMENT* instrument) +bool BasicSndfileReader::getInstrument(InstrumentInfo* instrument) { - if (handle_.command(SFC_GET_INSTRUMENT, instrument, sizeof(SF_INSTRUMENT)) == SF_FALSE) - return false; - return true; +#if defined(ST_AUDIO_FILE_USE_SNDFILE) + SNDFILE* sndfile = reinterpret_cast(handle_.get_sndfile_handle()); + if (sf_command(sndfile, SFC_GET_INSTRUMENT, &instrument, sizeof(instrument)) == SF_TRUE) + return true; +#else + (void)instrument; +#endif + return false; } //------------------------------------------------------------------------------ @@ -59,13 +68,13 @@ bool BasicSndfileReader::getInstrument(SF_INSTRUMENT* instrument) */ class ForwardReader : public BasicSndfileReader { public: - explicit ForwardReader(SndfileHandle handle); + explicit ForwardReader(ST_AudioFile handle); AudioReaderType type() const override; size_t readNextBlock(float* buffer, size_t frames) override; }; -ForwardReader::ForwardReader(SndfileHandle handle) - : BasicSndfileReader(handle) +ForwardReader::ForwardReader(ST_AudioFile handle) + : BasicSndfileReader(std::move(handle)) { } @@ -76,7 +85,7 @@ AudioReaderType ForwardReader::type() const size_t ForwardReader::readNextBlock(float* buffer, size_t frames) { - sf_count_t readFrames = handle_.readf(buffer, frames); + uint64_t readFrames = handle_.read_f32(buffer, frames); if (frames <= 0) return 0; @@ -93,7 +102,7 @@ struct AudioFrame { /** * @brief Reorder a sequence of frames in reverse */ -static void reverse_frames(float* data, sf_count_t frames, unsigned channels) +static void reverse_frames(float* data, size_t frames, unsigned channels) { switch (channels) { @@ -108,8 +117,8 @@ static void reverse_frames(float* data, sf_count_t frames, unsigned channels) SPECIALIZE_FOR(2); default: - for (sf_count_t i = 0; i < frames / 2; ++i) { - sf_count_t j = frames - 1 - i; + for (size_t i = 0; i < frames / 2; ++i) { + size_t j = frames - 1 - i; float* frame1 = &data[i * channels]; float* frame2 = &data[j * channels]; for (unsigned c = 0; c < channels; ++c) @@ -128,18 +137,18 @@ static void reverse_frames(float* data, sf_count_t frames, unsigned channels) */ class ReverseReader : public BasicSndfileReader { public: - explicit ReverseReader(SndfileHandle handle); + explicit ReverseReader(ST_AudioFile handle); AudioReaderType type() const override; size_t readNextBlock(float* buffer, size_t frames) override; private: - sf_count_t position_ {}; + uint64_t position_ {}; }; -ReverseReader::ReverseReader(SndfileHandle handle) - : BasicSndfileReader(handle) +ReverseReader::ReverseReader(ST_AudioFile handle) + : BasicSndfileReader(std::move(handle)) { - position_ = handle.seek(0, SEEK_END); + position_ = handle_.get_frame_count(); } AudioReaderType ReverseReader::type() const @@ -149,16 +158,16 @@ AudioReaderType ReverseReader::type() const size_t ReverseReader::readNextBlock(float* buffer, size_t frames) { - sf_count_t position = position_; - const unsigned channels = handle_.channels(); + uint64_t position = position_; + const unsigned channels = handle_.get_channels(); - const sf_count_t readFrames = std::min(frames, position); + const uint64_t readFrames = std::min(frames, position); if (readFrames <= 0) return false; position -= readFrames; - if (handle_.seek(position, SEEK_SET) != position || - handle_.readf(buffer, readFrames) != readFrames) + if (!handle_.seek(position) || + handle_.read_f32(buffer, readFrames) != readFrames) return false; position_ = position; @@ -173,7 +182,7 @@ size_t ReverseReader::readNextBlock(float* buffer, size_t frames) */ class NoSeekReverseReader : public BasicSndfileReader { public: - explicit NoSeekReverseReader(SndfileHandle handle); + explicit NoSeekReverseReader(ST_AudioFile handle); AudioReaderType type() const override; size_t readNextBlock(float* buffer, size_t frames) override; @@ -182,11 +191,11 @@ private: private: std::unique_ptr fileBuffer_; - sf_count_t fileFramesLeft_ { 0 }; + uint64_t fileFramesLeft_ { 0 }; }; -NoSeekReverseReader::NoSeekReverseReader(SndfileHandle handle) - : BasicSndfileReader(handle) +NoSeekReverseReader::NoSeekReverseReader(ST_AudioFile handle) + : BasicSndfileReader(std::move(handle)) { } @@ -203,9 +212,9 @@ size_t NoSeekReverseReader::readNextBlock(float* buffer, size_t frames) fileBuffer = fileBuffer_.get(); } - const unsigned channels = handle_.channels(); - const sf_count_t fileFramesLeft = fileFramesLeft_; - sf_count_t readFrames = std::min(frames, fileFramesLeft); + const unsigned channels = handle_.get_channels(); + const uint64_t fileFramesLeft = fileFramesLeft_; + uint64_t readFrames = std::min(frames, fileFramesLeft); if (readFrames <= 0) return 0; @@ -220,15 +229,16 @@ size_t NoSeekReverseReader::readNextBlock(float* buffer, size_t frames) void NoSeekReverseReader::readWholeFile() { - const sf_count_t frames = handle_.frames(); - const unsigned channels = handle_.channels(); + const uint64_t frames = handle_.get_frame_count(); + const unsigned channels = handle_.get_channels(); float* fileBuffer = new float[channels * frames]; fileBuffer_.reset(fileBuffer); - fileFramesLeft_ = handle_.readf(fileBuffer, frames); + fileFramesLeft_ = handle_.read_f32(fileBuffer, frames); } //------------------------------------------------------------------------------ +#if defined(ST_AUDIO_FILE_USE_SNDFILE) const std::error_category& sndfile_category() { class sndfile_category : public std::error_category { @@ -248,6 +258,26 @@ const std::error_category& sndfile_category() static const sndfile_category cat; return cat; } +#endif + +const std::error_category& undetailed_category() +{ + class undetailed_category : public std::error_category { + public: + const char* name() const noexcept override + { + return "undetailed"; + } + + std::string message(int condition) const override + { + return (condition == 0) ? "success" : "failure"; + } + }; + + static const undetailed_category cat; + return cat; +} //------------------------------------------------------------------------------ @@ -260,7 +290,7 @@ public: unsigned channels() const override { return 1; } unsigned sampleRate() const override { return 44100; } size_t readNextBlock(float*, size_t) override { return 0; } - bool getInstrument(SF_INSTRUMENT* ) override { return false; } + bool getInstrument(InstrumentInfo* ) override { return false; } private: AudioReaderType type_ {}; @@ -268,6 +298,7 @@ private: //------------------------------------------------------------------------------ +#if defined(ST_AUDIO_FILE_USE_SNDFILE) static bool formatHasFastSeeking(int format) { bool fast; @@ -300,8 +331,9 @@ static bool formatHasFastSeeking(int format) return fast; } +#endif -static AudioReaderPtr createAudioReaderWithHandle(SndfileHandle handle, bool reverse, std::error_code* ec) +static AudioReaderPtr createAudioReaderWithHandle(ST_AudioFile handle, bool reverse, std::error_code* ec) { AudioReaderPtr reader; @@ -310,30 +342,38 @@ static AudioReaderPtr createAudioReaderWithHandle(SndfileHandle handle, bool rev if (!handle) { if (ec) - *ec = std::error_code(handle.error(), sndfile_category()); + *ec = std::error_code(1, undetailed_category()); reader.reset(new DummyAudioReader(reverse ? AudioReaderType::Reverse : AudioReaderType::Forward)); } else if (!reverse) - reader.reset(new ForwardReader(handle)); - else if (formatHasFastSeeking(handle.format())) - reader.reset(new ReverseReader(handle)); - else - reader.reset(new NoSeekReverseReader(handle)); + reader.reset(new ForwardReader(std::move(handle))); + else { +#if defined(ST_AUDIO_FILE_USE_SNDFILE) + bool hasFastSeeking = formatHasFastSeeking(handle.get_sndfile_format()); +#else + bool hasFastSeeking = true; +#endif + if (hasFastSeeking) + reader.reset(new ReverseReader(std::move(handle))); + else + reader.reset(new NoSeekReverseReader(std::move(handle))); + } return reader; } AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_code* ec) { + ST_AudioFile handle; #if defined(_WIN32) - SndfileHandle handle(path.wstring().c_str()); + handle.open_file_w(path.wstring().c_str()); #else - SndfileHandle handle(path.c_str()); + handle.open_file(path.c_str()); #endif - return createAudioReaderWithHandle(handle, reverse, ec); + return createAudioReaderWithHandle(std::move(handle), reverse, ec); } -static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle, AudioReaderType type, std::error_code* ec) +static AudioReaderPtr createExplicitAudioReaderWithHandle(ST_AudioFile handle, AudioReaderType type, std::error_code* ec) { AudioReaderPtr reader; @@ -342,19 +382,19 @@ static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle, if (!handle) { if (ec) - *ec = std::error_code(handle.error(), sndfile_category()); + *ec = std::error_code(1, undetailed_category()); reader.reset(new DummyAudioReader(type)); } else { switch (type) { case AudioReaderType::Forward: - reader.reset(new ForwardReader(handle)); + reader.reset(new ForwardReader(std::move(handle))); break; case AudioReaderType::Reverse: - reader.reset(new ReverseReader(handle)); + reader.reset(new ReverseReader(std::move(handle))); break; case AudioReaderType::NoSeekReverse: - reader.reset(new NoSeekReverseReader(handle)); + reader.reset(new NoSeekReverseReader(std::move(handle))); break; } } @@ -364,12 +404,13 @@ static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle, AudioReaderPtr createExplicitAudioReader(const fs::path& path, AudioReaderType type, std::error_code* ec) { + ST_AudioFile handle; #if defined(_WIN32) - SndfileHandle handle(path.wstring().c_str()); + handle.open_file_w(path.wstring().c_str()); #else - SndfileHandle handle(path.c_str()); + handle.open_file(path.c_str()); #endif - return createExplicitAudioReaderWithHandle(handle, type, ec); + return createExplicitAudioReaderWithHandle(std::move(handle), type, ec); } } // namespace sfz diff --git a/src/sfizz/AudioReader.h b/src/sfizz/AudioReader.h index 64c661f1..8e138c2e 100644 --- a/src/sfizz/AudioReader.h +++ b/src/sfizz/AudioReader.h @@ -7,16 +7,13 @@ #pragma once #include "absl/types/span.h" #include "ghc/fs_std.hpp" +#include #include #include #include -#if defined(_WIN32) -#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 -#include -#endif -#include namespace sfz { +struct InstrumentInfo; /** * @brief Designation of a particular kind of audio reader @@ -42,7 +39,7 @@ public: virtual unsigned channels() const = 0; virtual unsigned sampleRate() const = 0; virtual size_t readNextBlock(float* buffer, size_t frames) = 0; - virtual bool getInstrument(SF_INSTRUMENT* instrument) = 0; + virtual bool getInstrument(InstrumentInfo* instrument) = 0; }; typedef std::unique_ptr AudioReaderPtr; diff --git a/src/sfizz/FileMetadata.cpp b/src/sfizz/FileMetadata.cpp index 60f6d64e..bb1d3d0c 100644 --- a/src/sfizz/FileMetadata.cpp +++ b/src/sfizz/FileMetadata.cpp @@ -242,7 +242,7 @@ size_t FileMetadataReader::Impl::readRiffData(size_t index, void* buffer, size_t return fread(buffer, 1, count, stream); } -bool FileMetadataReader::extractRiffInstrument(SF_INSTRUMENT& ins) +bool FileMetadataReader::extractRiffInstrument(InstrumentInfo& ins) { const RiffChunkInfo* riff = riffChunkById(RiffChunkId{'s', 'm', 'p', 'l'}); if (!riff) @@ -278,16 +278,16 @@ bool FileMetadataReader::extractRiffInstrument(SF_INSTRUMENT& ins) switch (extractU32(loopOffset + 0x04)) { default: - ins.loops[i].mode = SF_LOOP_NONE; + ins.loops[i].mode = LoopNone; break; case 0: - ins.loops[i].mode = SF_LOOP_FORWARD; + ins.loops[i].mode = LoopForward; break; case 1: - ins.loops[i].mode = SF_LOOP_ALTERNATING; + ins.loops[i].mode = LoopAlternating; break; case 2: - ins.loops[i].mode = SF_LOOP_BACKWARD; + ins.loops[i].mode = LoopBackward; break; } diff --git a/src/sfizz/FileMetadata.h b/src/sfizz/FileMetadata.h index 9e93be2e..74c6d9ad 100644 --- a/src/sfizz/FileMetadata.h +++ b/src/sfizz/FileMetadata.h @@ -5,15 +5,13 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#include +#endif #include "ghc/fs_std.hpp" #include #include #include -#if defined(_WIN32) -#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 -#include -#endif -#include namespace sfz { @@ -26,6 +24,44 @@ struct RiffChunkInfo { uint32_t length; }; +#if !defined(ST_AUDIO_FILE_USE_SNDFILE) +/** + @brief Loop mode, like SF_LOOP_* + */ +enum LoopMode { + LoopNone, + LoopForward, + LoopBackward, + LoopAlternating, +}; + +/** + @brief Instrument information, like SF_INSTRUMENT + */ +struct InstrumentInfo { + int gain; + int8_t basenote, detune; + int8_t velocity_lo, velocity_hi; + int8_t key_lo, key_hi; + int loop_count; + struct { + int mode; + uint32_t start; + uint32_t end; + uint32_t count; + } loops[16]; +}; +#else +enum LoopMode { + LoopNone = SF_LOOP_NONE, + LoopForward = SF_LOOP_FORWARD, + LoopBackward = SF_LOOP_BACKWARD, + LoopAlternating = SF_LOOP_ALTERNATING, +}; + +struct InstrumentInfo : SF_INSTRUMENT {}; +#endif + struct WavetableInfo { /** @brief Size of each successive table in the file @@ -79,7 +115,7 @@ public: /** * @brief Extract the RIFF 'smpl' data and convert it to sndfile instrument */ - bool extractRiffInstrument(SF_INSTRUMENT& ins); + bool extractRiffInstrument(InstrumentInfo& ins); /** * @brief Extract the wavetable information from various relevant RIFF chunks diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index bb66bb31..5bea534c 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -39,7 +39,6 @@ #include #include #include -#include #if defined(_WIN32) #include #else @@ -235,7 +234,7 @@ absl::optional sfz::FilePool::getFileInformation(const Fil returnedValue.sampleRate = static_cast(reader->sampleRate()); returnedValue.numChannels = reader->channels(); - SF_INSTRUMENT instrumentInfo {}; + InstrumentInfo instrumentInfo {}; bool haveInstrumentInfo = reader->getInstrument(&instrumentInfo); FileMetadataReader mdReader; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index eba64aea..522042dd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -88,10 +88,10 @@ if(JACK_FOUND AND TARGET Qt5::Widgets) endif() add_executable(eq_apply EQ.cpp) -target_link_libraries(eq_apply PRIVATE sfizz::sfizz) +target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz-sndfile) add_executable(filter_apply Filter.cpp) -target_link_libraries(filter_apply PRIVATE sfizz::sfizz) +target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz-sndfile) add_executable(sfizz_plot_curve PlotCurve.cpp) target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz) @@ -100,10 +100,10 @@ add_executable(sfizz_plot_wavetables PlotWavetables.cpp) target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::sfizz) add_executable(sfizz_plot_lfo PlotLFO.cpp) -target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz) +target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz sfizz-sndfile) add_executable(sfizz_file_instrument FileInstrument.cpp) -target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz) +target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz sfizz-sndfile) add_executable(sfizz_file_wavetable FileWavetable.cpp) target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::sfizz) diff --git a/tests/FileInstrument.cpp b/tests/FileInstrument.cpp index 98643be2..e759f481 100644 --- a/tests/FileInstrument.cpp +++ b/tests/FileInstrument.cpp @@ -12,20 +12,21 @@ static const char* modeString(int mode, const char* valueFallback = nullptr) { switch (mode) { - case SF_LOOP_NONE: + case sfz::LoopNone: return "none"; - case SF_LOOP_FORWARD: + case sfz::LoopForward: return "forward"; - case SF_LOOP_BACKWARD: + case sfz::LoopBackward: return "backward"; - case SF_LOOP_ALTERNATING: + case sfz::LoopAlternating: return "alternating"; default: return valueFallback; } } -static void printInstrument(const SF_INSTRUMENT& ins) +template +static void printInstrument(const Instrument& ins) { printf("Gain: %d\n", ins.gain); printf("Base note: %d\n", ins.basenote); @@ -34,7 +35,7 @@ static void printInstrument(const SF_INSTRUMENT& ins) printf("Key: %d:%d\n", ins.key_lo, ins.key_hi); printf("Loop count: %d\n", ins.loop_count); - for (int i = 0; i < ins.loop_count; ++i) { + for (unsigned i = 0, n = ins.loop_count; i < n; ++i) { printf("\nLoop %d:\n", i + 1); printf("\tMode: %s\n", modeString(ins.loops[i].mode, "(unknown)")); printf("\tStart: %u\n", ins.loops[i].start); @@ -83,18 +84,18 @@ int main(int argc, char *argv[]) return 1; } - SF_INSTRUMENT ins {}; - if (method == kMethodRiff) { sfz::FileMetadataReader reader; if (!reader.open(path)) { fprintf(stderr, "Cannot open file\n"); return 1; } + sfz::InstrumentInfo ins {}; if (!reader.extractRiffInstrument(ins)) { fprintf(stderr, "Cannot get instrument\n"); return 1; } + printInstrument(ins); } else { SndfileHandle sndFile(path); @@ -102,13 +103,13 @@ int main(int argc, char *argv[]) fprintf(stderr, "Cannot open file\n"); return 1; } + SF_INSTRUMENT ins {}; if (sndFile.command(SFC_GET_INSTRUMENT, &ins, sizeof(ins)) != 1) { fprintf(stderr, "Cannot get instrument\n"); return 1; } + printInstrument(ins); } - printInstrument(ins); - return 0; } From c6090d44fcf8085f2ea9b57de9e8768ac3246162 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 7 Oct 2020 17:11:59 +0200 Subject: [PATCH 011/668] Update makefiles --- common.mk | 10 ++++++++-- rack.mk | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/common.mk b/common.mk index 99a83ee1..7edce04d 100644 --- a/common.mk +++ b/common.mk @@ -4,6 +4,10 @@ ifndef SFIZZ_DIR $(error sfizz: The source directory must be set before including) endif +### Options + +SFIZZ_USE_SNDFILE ?= 1 + ### SFIZZ_MACHINE := $(shell $(CC) -dumpmachine) @@ -125,13 +129,15 @@ SFIZZ_PKG_CONFIG ?= pkg-config # Sndfile dependency +ifeq ($(SFIZZ_USE_SNDFILE),1) SFIZZ_SNDFILE_C_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --cflags sndfile) SFIZZ_SNDFILE_CXX_FLAGS ?= $(SFIZZ_SNDFILE_C_FLAGS) SFIZZ_SNDFILE_LINK_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --libs sndfile) -SFIZZ_C_FLAGS += $(SFIZZ_SNDFILE_C_FLAGS) -SFIZZ_CXX_FLAGS += $(SFIZZ_SNDFILE_CXX_FLAGS) +SFIZZ_C_FLAGS += $(SFIZZ_SNDFILE_C_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1 +SFIZZ_CXX_FLAGS += $(SFIZZ_SNDFILE_CXX_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1 SFIZZ_LINK_FLAGS += $(SFIZZ_SNDFILE_LINK_FLAGS) +endif ### Abseil dependency diff --git a/rack.mk b/rack.mk index 4f8d2512..7c483ca6 100644 --- a/rack.mk +++ b/rack.mk @@ -29,6 +29,7 @@ # # SFIZZ_RACK_PLUGIN_DIR = # SFIZZ_PKG_CONFIG = +# SFIZZ_USE_SNDFILE = <0 disabled, 1 enabled (default)> # SFIZZ_SNDFILE_C_FLAGS = # SFIZZ_SNDFILE_CXX_FLAGS = # SFIZZ_SNDFILE_LINK_FLAGS = From ae48eda57eba9dd274337b5be91a6f95f11eb1b9 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 7 Oct 2020 17:23:59 +0200 Subject: [PATCH 012/668] Update the audio reader benchmark --- benchmarks/BM_audioReaders.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/benchmarks/BM_audioReaders.cpp b/benchmarks/BM_audioReaders.cpp index 569a8810..88e1f9b5 100644 --- a/benchmarks/BM_audioReaders.cpp +++ b/benchmarks/BM_audioReaders.cpp @@ -146,16 +146,12 @@ static void doReaderBenchmark(const fs::path& path, std::vector &buffer, static void doEntireRead(const fs::path& path) { -#if !defined(_WIN32) - SndfileHandle handle(path.c_str()); -#else - SndfileHandle handle(path.wstring().c_str()); -#endif - if (handle.error()) - throw std::runtime_error("cannot open sound file for reading"); + sfz::AudioReaderPtr reader = sfz::createAudioReader(path, false); + if (!reader) + return; - std::vector buffer(static_cast(2 * handle.frames())); - handle.read(buffer.data(), buffer.size()); + std::vector buffer(static_cast(2 * reader->frames())); + reader->readNextBlock(buffer.data(), buffer.size()); } BENCHMARK_DEFINE_F(AudioReaderFixture, EntireWav)(benchmark::State& state) From 4238f0de7cd7d3d84bb92d0542dc52d49b02b749 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 7 Oct 2020 17:37:50 +0200 Subject: [PATCH 013/668] Update makefiles (2) --- common.mk | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/common.mk b/common.mk index 7edce04d..e7ada2c1 100644 --- a/common.mk +++ b/common.mk @@ -133,7 +133,24 @@ ifeq ($(SFIZZ_USE_SNDFILE),1) SFIZZ_SNDFILE_C_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --cflags sndfile) SFIZZ_SNDFILE_CXX_FLAGS ?= $(SFIZZ_SNDFILE_C_FLAGS) SFIZZ_SNDFILE_LINK_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --libs sndfile) +endif +# st_audiofile dependency + +SFIZZ_SOURCES += \ + $(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile.c \ + $(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_common.c \ + $(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_libs.c \ + $(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_sndfile.c + +SFIZZ_C_FLAGS += \ + -I$(SFIZZ_DIR)/external/st_audiofile/src \ + -I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/dr_libs +SFIZZ_CXX_FLAGS += \ + -I$(SFIZZ_DIR)/external/st_audiofile/src \ + -I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/dr_libs + +ifeq ($(SFIZZ_USE_SNDFILE),1) SFIZZ_C_FLAGS += $(SFIZZ_SNDFILE_C_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1 SFIZZ_CXX_FLAGS += $(SFIZZ_SNDFILE_CXX_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1 SFIZZ_LINK_FLAGS += $(SFIZZ_SNDFILE_LINK_FLAGS) From f552f48b514b7711005a6cf184ec03ad965b132e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 7 Oct 2020 17:43:01 +0200 Subject: [PATCH 014/668] Clang-tidy update --- scripts/run_clang_tidy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index 08ceb36c..18d0b08f 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -31,6 +31,7 @@ clang-tidy \ vst/SfizzVstEditor.cpp \ vst/SfizzVstState.cpp \ -- -Iexternal/abseil-cpp -Iexternal/jsl/include -Isrc/external -Isrc/external/pugixml/src \ + -Iexternal/st_audiofile/src -Iexternal/st_audiofile/thirdparty/dr_libs \ -Isrc/sfizz -Isrc -Isrc/external/spline -Isrc/external/cpuid/src \ -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer \ -Ieditor/src \ From 3b51b42e56d641e3ea063514866b9366a33752cc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 9 Oct 2020 13:48:03 +0200 Subject: [PATCH 015/668] Make st_audiofile link sndfile publicly --- external/st_audiofile/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/st_audiofile/CMakeLists.txt b/external/st_audiofile/CMakeLists.txt index 137f3201..d876b8f0 100644 --- a/external/st_audiofile/CMakeLists.txt +++ b/external/st_audiofile/CMakeLists.txt @@ -23,7 +23,7 @@ if(ST_AUDIO_FILE_USE_SNDFILE) PUBLIC "ST_AUDIO_FILE_USE_SNDFILE=1") if(ST_AUDIO_FILE_EXTERNAL_SNDFILE) target_link_libraries(st_audiofile - PRIVATE "${ST_AUDIO_FILE_EXTERNAL_SNDFILE}") + PUBLIC "${ST_AUDIO_FILE_EXTERNAL_SNDFILE}") else() find_package(PkgConfig REQUIRED) pkg_check_modules(Sndfile "sndfile" REQUIRED) From 32835b29d9a5e911d5162184677ff21e960f639d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 9 Oct 2020 15:41:08 +0200 Subject: [PATCH 016/668] Add MP3 --- external/st_audiofile/src/st_audiofile.c | 53 +++++++++++++++++++ external/st_audiofile/src/st_audiofile.h | 1 + .../st_audiofile/src/st_audiofile_common.c | 3 ++ external/st_audiofile/src/st_audiofile_libs.c | 1 + external/st_audiofile/src/st_audiofile_libs.h | 1 + 5 files changed, 59 insertions(+) diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c index efaccb85..671e8618 100644 --- a/external/st_audiofile/src/st_audiofile.c +++ b/external/st_audiofile/src/st_audiofile.c @@ -14,7 +14,12 @@ struct st_audio_file { union { drwav *wav; drflac *flac; + drmp3 *mp3; }; + + union { + struct { uint64_t frames; } mp3; + } cache; }; enum { @@ -47,6 +52,19 @@ st_audio_file* st_open_file(const char* filename) af->type = st_audio_file_flac; } + if (af->type == st_audio_file_null) { + af->mp3 = (drmp3*)malloc(sizeof(drmp3)); + if (!af->mp3) { + free(af); + return NULL; + } + if (!drmp3_init_file(af->mp3, filename, NULL) || + (af->cache.mp3.frames = drmp3_get_pcm_frame_count(af->mp3)) == 0) + free(af->mp3); + else + af->type = st_audio_file_mp3; + } + if (af->type == st_audio_file_null) { free(af); af = NULL; @@ -82,6 +100,19 @@ st_audio_file* st_open_file_w(const wchar_t* filename) af->type = st_audio_file_flac; } + if (af->type == st_audio_file_null) { + af->mp3 = (drmp3*)malloc(sizeof(drmp3)); + if (!af->mp3) { + free(af); + return NULL; + } + if (!drmp3_init_file_w(af->mp3, filename, NULL) || + (af->cache.mp3.frames = drmp3_get_pcm_frame_count(af->mp3)) == 0) + free(af->mp3); + else + af->type = st_audio_file_mp3; + } + if (af->type == st_audio_file_null) { free(af); af = NULL; @@ -101,6 +132,10 @@ void st_close(st_audio_file* af) case st_audio_file_flac: drflac_close(af->flac); break; + case st_audio_file_mp3: + drmp3_uninit(af->mp3); + free(af->mp3); + break; } af->type = st_audio_file_null; @@ -122,6 +157,9 @@ uint32_t st_get_channels(st_audio_file* af) case st_audio_file_flac: channels = af->flac->channels; break; + case st_audio_file_mp3: + channels = af->mp3->channels; + break; } return channels; @@ -138,6 +176,9 @@ float st_get_sample_rate(st_audio_file* af) case st_audio_file_flac: sample_rate = af->flac->sampleRate; break; + case st_audio_file_mp3: + sample_rate = af->mp3->sampleRate; + break; } return sample_rate; @@ -154,6 +195,9 @@ uint64_t st_get_frame_count(st_audio_file* af) case st_audio_file_flac: frames = af->flac->totalPCMFrameCount; break; + case st_audio_file_mp3: + frames = af->cache.mp3.frames; + break; } return frames; @@ -170,6 +214,9 @@ bool st_seek(st_audio_file* af, uint64_t frame) case st_audio_file_flac: success = drflac_seek_to_pcm_frame(af->flac, frame); break; + case st_audio_file_mp3: + success = drmp3_seek_to_pcm_frame(af->mp3, frame); + break; } return success; @@ -184,6 +231,9 @@ uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count) case st_audio_file_flac: count = drflac_read_pcm_frames_s16(af->flac, count, buffer); break; + case st_audio_file_mp3: + count = drmp3_read_pcm_frames_s16(af->mp3, count, buffer); + break; } return count; @@ -198,6 +248,9 @@ uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count) case st_audio_file_flac: count = drflac_read_pcm_frames_f32(af->flac, count, buffer); break; + case st_audio_file_mp3: + count = drmp3_read_pcm_frames_f32(af->mp3, count, buffer); + break; } return count; diff --git a/external/st_audiofile/src/st_audiofile.h b/external/st_audiofile/src/st_audiofile.h index 704addb8..fd62c77f 100644 --- a/external/st_audiofile/src/st_audiofile.h +++ b/external/st_audiofile/src/st_audiofile.h @@ -24,6 +24,7 @@ typedef enum st_audio_file_type { st_audio_file_wav, st_audio_file_flac, st_audio_file_ogg, + st_audio_file_mp3, st_audio_file_other, } st_audio_file_type; diff --git a/external/st_audiofile/src/st_audiofile_common.c b/external/st_audiofile/src/st_audiofile_common.c index 2b6e5d34..d8e2ac6e 100644 --- a/external/st_audiofile/src/st_audiofile_common.c +++ b/external/st_audiofile/src/st_audiofile_common.c @@ -26,6 +26,9 @@ const char* st_type_string(int type) case st_audio_file_ogg: type_string = "OGG"; break; + case st_audio_file_mp3: + type_string = "MP3"; + break; case st_audio_file_other: type_string = "other"; break; diff --git a/external/st_audiofile/src/st_audiofile_libs.c b/external/st_audiofile/src/st_audiofile_libs.c index 77ae28c2..4c39e703 100644 --- a/external/st_audiofile/src/st_audiofile_libs.c +++ b/external/st_audiofile/src/st_audiofile_libs.c @@ -6,4 +6,5 @@ #define DR_WAV_IMPLEMENTATION #define DR_FLAC_IMPLEMENTATION +#define DR_MP3_IMPLEMENTATION #include "st_audiofile_libs.h" diff --git a/external/st_audiofile/src/st_audiofile_libs.h b/external/st_audiofile/src/st_audiofile_libs.h index 8620cdce..16f329b0 100644 --- a/external/st_audiofile/src/st_audiofile_libs.h +++ b/external/st_audiofile/src/st_audiofile_libs.h @@ -7,3 +7,4 @@ #pragma once #include "dr_wav.h" #include "dr_flac.h" +#include "dr_mp3.h" From f57fc490d335f25e917d7d674b870fac1234abf8 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 9 Oct 2020 17:29:53 +0200 Subject: [PATCH 017/668] Add OGG --- .gitmodules | 4 ++ external/st_audiofile/CMakeLists.txt | 3 +- external/st_audiofile/src/st_audiofile.c | 55 +++++++++++++++++++ external/st_audiofile/src/st_audiofile_libs.c | 19 +++++++ external/st_audiofile/src/st_audiofile_libs.h | 11 ++++ external/st_audiofile/thirdparty/stb_vorbis | 1 + 6 files changed, 92 insertions(+), 1 deletion(-) create mode 160000 external/st_audiofile/thirdparty/stb_vorbis diff --git a/.gitmodules b/.gitmodules index f4453c71..c47fa23b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,3 +23,7 @@ path = external/st_audiofile/thirdparty/dr_libs url = https://github.com/mackron/dr_libs.git shallow = true +[submodule "external/st_audiofile/thirdparty/stb_vorbis"] + path = external/st_audiofile/thirdparty/stb_vorbis + url = https://github.com/sfztools/stb_vorbis.git + shallow = true diff --git a/external/st_audiofile/CMakeLists.txt b/external/st_audiofile/CMakeLists.txt index d876b8f0..e0fb1e4e 100644 --- a/external/st_audiofile/CMakeLists.txt +++ b/external/st_audiofile/CMakeLists.txt @@ -11,7 +11,8 @@ add_library(st_audiofile STATIC "src/st_audiofile_sndfile.c") target_include_directories(st_audiofile PUBLIC "src" - PUBLIC "thirdparty/dr_libs") + PUBLIC "thirdparty/dr_libs" + PUBLIC "thirdparty/stb_vorbis") add_executable(st_info "src/st_info.c") diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c index 671e8618..8325617a 100644 --- a/external/st_audiofile/src/st_audiofile.c +++ b/external/st_audiofile/src/st_audiofile.c @@ -15,10 +15,12 @@ struct st_audio_file { drwav *wav; drflac *flac; drmp3 *mp3; + stb_vorbis* ogg; }; union { struct { uint64_t frames; } mp3; + struct { uint32_t channels; float sample_rate; uint64_t frames; } ogg; } cache; }; @@ -52,6 +54,20 @@ st_audio_file* st_open_file(const char* filename) af->type = st_audio_file_flac; } + if (af->type == st_audio_file_null) { + af->ogg = stb_vorbis_open_filename(filename, NULL, NULL); + if (af->ogg) { + if ((af->cache.ogg.frames = stb_vorbis_stream_length_in_samples(af->ogg)) == 0) + stb_vorbis_close(af->ogg); + else { + stb_vorbis_info info = stb_vorbis_get_info(af->ogg); + af->cache.ogg.channels = info.channels; + af->cache.ogg.sample_rate = info.sample_rate; + af->type = st_audio_file_ogg; + } + } + } + if (af->type == st_audio_file_null) { af->mp3 = (drmp3*)malloc(sizeof(drmp3)); if (!af->mp3) { @@ -100,6 +116,20 @@ st_audio_file* st_open_file_w(const wchar_t* filename) af->type = st_audio_file_flac; } + if (af->type == st_audio_file_null) { + af->ogg = stb_vorbis_open_filename_w(filename, NULL, NULL); + if (af->ogg) { + if ((af->cache.ogg.frames = stb_vorbis_stream_length_in_samples(af->ogg)) == 0) + stb_vorbis_close(af->ogg); + else { + stb_vorbis_info info = stb_vorbis_get_info(af->ogg); + af->cache.ogg.channels = info.channels; + af->cache.ogg.sample_rate = info.sample_rate; + af->type = st_audio_file_ogg; + } + } + } + if (af->type == st_audio_file_null) { af->mp3 = (drmp3*)malloc(sizeof(drmp3)); if (!af->mp3) { @@ -132,6 +162,9 @@ void st_close(st_audio_file* af) case st_audio_file_flac: drflac_close(af->flac); break; + case st_audio_file_ogg: + stb_vorbis_close(af->ogg); + break; case st_audio_file_mp3: drmp3_uninit(af->mp3); free(af->mp3); @@ -157,6 +190,9 @@ uint32_t st_get_channels(st_audio_file* af) case st_audio_file_flac: channels = af->flac->channels; break; + case st_audio_file_ogg: + channels = af->cache.ogg.channels; + break; case st_audio_file_mp3: channels = af->mp3->channels; break; @@ -176,6 +212,9 @@ float st_get_sample_rate(st_audio_file* af) case st_audio_file_flac: sample_rate = af->flac->sampleRate; break; + case st_audio_file_ogg: + sample_rate = af->cache.ogg.sample_rate; + break; case st_audio_file_mp3: sample_rate = af->mp3->sampleRate; break; @@ -195,6 +234,9 @@ uint64_t st_get_frame_count(st_audio_file* af) case st_audio_file_flac: frames = af->flac->totalPCMFrameCount; break; + case st_audio_file_ogg: + frames = af->cache.ogg.frames; + break; case st_audio_file_mp3: frames = af->cache.mp3.frames; break; @@ -214,6 +256,9 @@ bool st_seek(st_audio_file* af, uint64_t frame) case st_audio_file_flac: success = drflac_seek_to_pcm_frame(af->flac, frame); break; + case st_audio_file_ogg: + success = stb_vorbis_seek(af->ogg, (unsigned)frame) != 0; + break; case st_audio_file_mp3: success = drmp3_seek_to_pcm_frame(af->mp3, frame); break; @@ -231,6 +276,11 @@ uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count) case st_audio_file_flac: count = drflac_read_pcm_frames_s16(af->flac, count, buffer); break; + case st_audio_file_ogg: + count = stb_vorbis_get_samples_short_interleaved( + af->ogg, af->cache.ogg.channels, buffer, + count * af->cache.ogg.channels); + break; case st_audio_file_mp3: count = drmp3_read_pcm_frames_s16(af->mp3, count, buffer); break; @@ -248,6 +298,11 @@ uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count) case st_audio_file_flac: count = drflac_read_pcm_frames_f32(af->flac, count, buffer); break; + case st_audio_file_ogg: + count = stb_vorbis_get_samples_float_interleaved( + af->ogg, af->cache.ogg.channels, buffer, + count * af->cache.ogg.channels); + break; case st_audio_file_mp3: count = drmp3_read_pcm_frames_f32(af->mp3, count, buffer); break; diff --git a/external/st_audiofile/src/st_audiofile_libs.c b/external/st_audiofile/src/st_audiofile_libs.c index 4c39e703..0bbcccca 100644 --- a/external/st_audiofile/src/st_audiofile_libs.c +++ b/external/st_audiofile/src/st_audiofile_libs.c @@ -7,4 +7,23 @@ #define DR_WAV_IMPLEMENTATION #define DR_FLAC_IMPLEMENTATION #define DR_MP3_IMPLEMENTATION +#define STB_VORBIS_HEADER_ONLY 0 #include "st_audiofile_libs.h" + +#if defined(_WIN32) +stb_vorbis* stb_vorbis_open_filename_w(const wchar_t* filename, int* error, const stb_vorbis_alloc* alloc) +{ + FILE* f; +#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) + if (0 != _wfopen_s(&f, filename, L"rb")) + f = NULL; +#else + f = _wfopen(filename, L"rb"); +#endif + if (f) + return stb_vorbis_open_file(f, TRUE, error, alloc); + if (error) + *error = VORBIS_file_open_failure; + return NULL; +} +#endif diff --git a/external/st_audiofile/src/st_audiofile_libs.h b/external/st_audiofile/src/st_audiofile_libs.h index 16f329b0..21727c6b 100644 --- a/external/st_audiofile/src/st_audiofile_libs.h +++ b/external/st_audiofile/src/st_audiofile_libs.h @@ -8,3 +8,14 @@ #include "dr_wav.h" #include "dr_flac.h" #include "dr_mp3.h" +#if !defined(STB_VORBIS_HEADER_ONLY) +# define STB_VORBIS_HEADER_ONLY 1 +#elif STB_VORBIS_HEADER_ONLY == 0 +# undef STB_VORBIS_HEADER_ONLY +#endif +#include "stb_vorbis.c" + +#if defined(_WIN32) +#include +stb_vorbis* stb_vorbis_open_filename_w(const wchar_t* filename, int* error, const stb_vorbis_alloc* alloc); +#endif diff --git a/external/st_audiofile/thirdparty/stb_vorbis b/external/st_audiofile/thirdparty/stb_vorbis new file mode 160000 index 00000000..fc0bd698 --- /dev/null +++ b/external/st_audiofile/thirdparty/stb_vorbis @@ -0,0 +1 @@ +Subproject commit fc0bd698b26888da0a632da33f4c49b90763e69b From 20718c43d84a71d401624ed4b7695a86c348126d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 9 Oct 2020 17:37:11 +0200 Subject: [PATCH 018/668] Enable the Reverse OGG benchmark on stb_vorbis --- benchmarks/BM_audioReaders.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/benchmarks/BM_audioReaders.cpp b/benchmarks/BM_audioReaders.cpp index 88e1f9b5..98483a8d 100644 --- a/benchmarks/BM_audioReaders.cpp +++ b/benchmarks/BM_audioReaders.cpp @@ -210,12 +210,14 @@ BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardOgg)(benchmark::State& state) } } -//BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseOgg)(benchmark::State& state) -//{ -// for (auto _ : state) { -// doReaderBenchmark(fileOgg.path(), workBuffer, sfz::AudioReaderType::Reverse); -// } -//} +#if !defined(ST_AUDIO_FILE_USE_SNDFILE) +BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseOgg)(benchmark::State& state) +{ + for (auto _ : state) { + doReaderBenchmark(fileOgg.path(), workBuffer, sfz::AudioReaderType::Reverse); + } +} +#endif BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardWav)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseWav)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); @@ -224,6 +226,8 @@ BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardFlac)->RangeMultiplier(2)->Range BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseFlac)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); BENCHMARK_REGISTER_F(AudioReaderFixture, EntireFlac)->Range(1, 1); BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); -//BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); +#if !defined(ST_AUDIO_FILE_USE_SNDFILE) +BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); +#endif BENCHMARK_REGISTER_F(AudioReaderFixture, EntireOgg)->Range(1, 1); BENCHMARK_MAIN(); From a118f5386ac60bac1523292e5be19b741a41f291 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 9 Oct 2020 18:30:26 +0200 Subject: [PATCH 019/668] Get rid of a code duplication --- external/st_audiofile/src/st_audiofile.c | 164 ++++++++++------------- 1 file changed, 74 insertions(+), 90 deletions(-) diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c index 8325617a..81eb5d47 100644 --- a/external/st_audiofile/src/st_audiofile.c +++ b/external/st_audiofile/src/st_audiofile.c @@ -28,127 +28,111 @@ enum { st_audio_file_null = -1, }; -st_audio_file* st_open_file(const char* filename) +static st_audio_file* st_generic_open_file(const void* filename, int widepath) { +#if !defined(_WIN32) + if (widepath) + return NULL; +#endif + st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file)); if (!af) return NULL; - af->type = st_audio_file_null; - - if (af->type == st_audio_file_null) { + // Try WAV + { af->wav = (drwav*)malloc(sizeof(drwav)); if (!af->wav) { free(af); return NULL; } - if (!drwav_init_file(af->wav, filename, NULL)) + drwav_bool32 ok = +#if defined(_WIN32) + widepath ? drwav_init_file_w(af->wav, (const wchar_t*)filename, NULL) : +#endif + drwav_init_file(af->wav, (const char*)filename, NULL); + if (!ok) free(af->wav); - else + else { af->type = st_audio_file_wav; - } - - if (af->type == st_audio_file_null) { - af->flac = drflac_open_file(filename, NULL); - if (af->flac) - af->type = st_audio_file_flac; - } - - if (af->type == st_audio_file_null) { - af->ogg = stb_vorbis_open_filename(filename, NULL, NULL); - if (af->ogg) { - if ((af->cache.ogg.frames = stb_vorbis_stream_length_in_samples(af->ogg)) == 0) - stb_vorbis_close(af->ogg); - else { - stb_vorbis_info info = stb_vorbis_get_info(af->ogg); - af->cache.ogg.channels = info.channels; - af->cache.ogg.sample_rate = info.sample_rate; - af->type = st_audio_file_ogg; - } + return af; } } + // Try FLAC + { + af->flac = +#if defined(_WIN32) + widepath ? drflac_open_file_w((const wchar_t*)filename, NULL) : +#endif + drflac_open_file((const char*)filename, NULL); + if (af->flac) { + af->type = st_audio_file_flac; + return af; + } + } + + // Try OGG + { + af->ogg = +#if defined(_WIN32) + widepath ? stb_vorbis_open_filename_w((const wchar_t*)filename, NULL, NULL) : +#endif + stb_vorbis_open_filename((const char*)filename, NULL, NULL); + if (af->ogg) { + af->cache.ogg.frames = stb_vorbis_stream_length_in_samples(af->ogg); + if (af->cache.ogg.frames == 0) { + stb_vorbis_close(af->ogg); + free(af); + return NULL; + } + stb_vorbis_info info = stb_vorbis_get_info(af->ogg); + af->cache.ogg.channels = info.channels; + af->cache.ogg.sample_rate = info.sample_rate; + af->type = st_audio_file_ogg; + return af; + } + } + + // Try MP3 if (af->type == st_audio_file_null) { af->mp3 = (drmp3*)malloc(sizeof(drmp3)); if (!af->mp3) { free(af); return NULL; } - if (!drmp3_init_file(af->mp3, filename, NULL) || - (af->cache.mp3.frames = drmp3_get_pcm_frame_count(af->mp3)) == 0) + drmp3_bool32 ok = +#if defined(_WIN32) + widepath ? drmp3_init_file_w(af->mp3, (const wchar_t*)filename, NULL) : +#endif + drmp3_init_file(af->mp3, (const char*)filename, NULL); + if (!ok) free(af->mp3); - else + else { + af->cache.mp3.frames = drmp3_get_pcm_frame_count(af->mp3); + if (af->cache.mp3.frames == 0) { + free(af->mp3); + free(af); + return NULL; + } af->type = st_audio_file_mp3; + return af; + } } - if (af->type == st_audio_file_null) { - free(af); - af = NULL; - } + free(af); + return NULL; +} - return af; +st_audio_file* st_open_file(const char* filename) +{ + return st_generic_open_file(filename, 0); } #if defined(_WIN32) st_audio_file* st_open_file_w(const wchar_t* filename) { - st_audio_file* af = (st_audio_file*)malloc(sizeof(st_audio_file)); - if (!af) - return NULL; - - af->type = st_audio_file_null; - - if (af->type == st_audio_file_null) { - af->wav = (drwav*)malloc(sizeof(drwav)); - if (!af->wav) { - free(af); - return NULL; - } - if (!drwav_init_file_w(af->wav, filename, NULL)) - free(af->wav); - else - af->type = st_audio_file_wav; - } - - if (af->type == st_audio_file_null) { - af->flac = drflac_open_file_w(filename, NULL); - if (af->flac) - af->type = st_audio_file_flac; - } - - if (af->type == st_audio_file_null) { - af->ogg = stb_vorbis_open_filename_w(filename, NULL, NULL); - if (af->ogg) { - if ((af->cache.ogg.frames = stb_vorbis_stream_length_in_samples(af->ogg)) == 0) - stb_vorbis_close(af->ogg); - else { - stb_vorbis_info info = stb_vorbis_get_info(af->ogg); - af->cache.ogg.channels = info.channels; - af->cache.ogg.sample_rate = info.sample_rate; - af->type = st_audio_file_ogg; - } - } - } - - if (af->type == st_audio_file_null) { - af->mp3 = (drmp3*)malloc(sizeof(drmp3)); - if (!af->mp3) { - free(af); - return NULL; - } - if (!drmp3_init_file_w(af->mp3, filename, NULL) || - (af->cache.mp3.frames = drmp3_get_pcm_frame_count(af->mp3)) == 0) - free(af->mp3); - else - af->type = st_audio_file_mp3; - } - - if (af->type == st_audio_file_null) { - free(af); - af = NULL; - } - - return af; + return st_generic_open_file(filename, 1); } #endif From 6a2382f37a04c011d5f00dfde2da9f7ba1a46d29 Mon Sep 17 00:00:00 2001 From: redtide Date: Tue, 27 Oct 2020 04:12:54 +0100 Subject: [PATCH 020/668] CI reorganization --- .appveyor.yml | 83 +++++++++++++++++++++++++++++++ .gitignore | 13 +---- .travis.yml | 21 +------- .travis/prepare_tarball.sh | 2 +- appveyor.yml | 53 -------------------- cmake/SfizzConfig.cmake | 5 ++ scripts/appveyor/after_build.cmd | 4 ++ scripts/appveyor/after_build.sh | 12 +++++ scripts/appveyor/before_build.cmd | 16 ++++++ scripts/appveyor/before_build.sh | 14 ++++++ scripts/appveyor/install.cmd | 7 +++ scripts/innosetup.iss.in | 2 +- vst/CMakeLists.txt | 2 +- 13 files changed, 147 insertions(+), 87 deletions(-) create mode 100644 .appveyor.yml delete mode 100644 appveyor.yml create mode 100644 scripts/appveyor/after_build.cmd create mode 100755 scripts/appveyor/after_build.sh create mode 100644 scripts/appveyor/before_build.cmd create mode 100644 scripts/appveyor/before_build.sh create mode 100644 scripts/appveyor/install.cmd diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 00000000..655a5b67 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,83 @@ +version: build-{build} +configuration: Release + +environment: + matrix: + - job_name: macOS Mojave + appveyor_build_worker_image: macos-mojave + INSTALL_DIR: sfizz-$(APPVEYOR_REPO_TAG_NAME)-macos + + - job_name: Windows x86 + appveyor_build_worker_image: Visual Studio 2019 + platform: x86 + VCPKG_TRIPLET: x86-windows-static + PATH: C:\Program Files (x86)\Inno Setup 6;%PATH% + + - job_name: Windows x64 + appveyor_build_worker_image: Visual Studio 2019 + platform: x64 + VCPKG_TRIPLET: x64-windows-static + PATH: C:\Program Files (x86)\Inno Setup 6;%PATH% + +matrix: + allow_failures: + - platform: x86 + - platform: x64 + +for: +- matrix: + only: + - job_name: macOS Mojave + init: + - system_profiler SPSoftwareDataType + - cmake --version + - gcc -v + install: + - brew install jack + - brew install dylibbundler + before_build: + - chmod +x ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/before_build.sh + - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/before_build.sh + build_script: cd build && make -j2 + after_build: + - chmod +x ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/after_build.sh + - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/after_build.sh + test: off + artifacts: + - name: macOS Tarball + path: "sfizz-*.tar.gz" + +- matrix: + only: + - job_name: Windows x86 + cache: c:\tools\vcpkg\installed\ -> appveyor.yml + install: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\install.cmd + before_build: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\before_build.cmd + build_script: cmake --build . --config Release -j2 + after_build: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\after_build.cmd + artifacts: + - name: x86 Setup + path: "sfizz-*.exe" + +- matrix: + only: + - job_name: Windows x64 + cache: c:\tools\vcpkg\installed\ -> appveyor.yml + install: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\install.cmd + before_build: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\before_build.cmd + build_script: cmake --build . --config Release -j2 + after_build: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\after_build.cmd + artifacts: + - name: x64 Setup + path: "sfizz-*.exe" + +deploy: +- provider: GitHub + auth_token: + secure: xOugGAynvnZdc0DXaL3rlgMf4CICFLkdO8JxoRfLQMKJhkj/kZ4d8h7NCFneDzXG + artifact: macOS Tarball,x86 Setup,x64 Setup + draft: false + prerelease: false + force_update: true + on: + APPVEYOR_REPO_TAG: true diff --git a/.gitignore b/.gitignore index d9ddf04e..b1f6f768 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -build* +build*/* docs .vscode perf.data @@ -23,17 +23,6 @@ clients/sfzprint /editor/external/fluentui-system-icons/ -# gh-pages unstaged files: -_api/ -_site/ -.bundle/ -api/ -assets/ -node_modules/ -.jekyll-cache -.jekyll-metadata -.sass-cache -*.lock *.sublime-* *.code-* .kak.tags.namecache diff --git a/.travis.yml b/.travis.yml index 47ae06a8..1e2a0c6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ cache: jobs: include: - name: "clang-tidy checks" - stage: "Tests" addons: apt: packages: @@ -42,27 +41,12 @@ jobs: install: .travis/download_cmake.sh script: .travis/script_test.sh - - name: "macOS" - stage: "Build" - os: osx - osx_image: xcode11.3 - addons: - homebrew: - packages: - - cmake - - libsndfile - - jack - - dylibbundler - env: - - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}" - script: .travis/script_osx.sh - after_success: .travis/prepare_tarball.sh - - name: "MOD devices arm" env: - CONTAINER=jpcima/mod-plugin-builder - CROSS_COMPILE=moddevices-arm - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-moddevices" + - DEPLOY_BUILD=true before_install: .travis/before_install_moddevices.sh install: .travis/install_moddevices.sh script: .travis/script_moddevices.sh @@ -160,8 +144,7 @@ jobs: script: .travis/script_plugins.sh after_success: .travis/prepare_tarball.sh - - stage: "Deploy" - name: "Source packaging" + - name: "Source packaging" if: (tag =~ /^v?[0-9]/) AND (type = push) env: - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-src" diff --git a/.travis/prepare_tarball.sh b/.travis/prepare_tarball.sh index 6e111406..1447feea 100755 --- a/.travis/prepare_tarball.sh +++ b/.travis/prepare_tarball.sh @@ -13,7 +13,7 @@ buildenv make DESTDIR=${PWD}/${INSTALL_DIR} install tar -zcvf "${INSTALL_DIR}.tar.gz" ${INSTALL_DIR} # Only release a tarball if there is a tag -if [[ ${TRAVIS_TAG} != "" ]]; then +if [[ ${TRAVIS_TAG} != "" ]] && [[ ${DEPLOY_BUILD} ]]; then mv "${INSTALL_DIR}.tar.gz" ${TRAVIS_BUILD_DIR} fi diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 47a33c26..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,53 +0,0 @@ -version: build-{build} -image: Visual Studio 2019 -configuration: Release -platform: -- Win32 -- x64 -cache: - - c:\tools\vcpkg\installed\ -> appveyor.yml - -install: -- cmd: choco install -y innosetup -- cmd: set PATH=C:\Program Files (x86)\Inno Setup 6;%PATH% -- cmd: if %platform%==Win32 set VCPKG_TRIPLET=x86-windows-static -- cmd: if %platform%==x64 set VCPKG_TRIPLET=x64-windows-static -# - cmd: cd c:\tools\vcpkg\ -# - cmd: git pull -# - cmd: .\bootstrap-vcpkg.bat -# - cmd: cd %APPVEYOR_BUILD_FOLDER% -- cmd: vcpkg install libsndfile:%VCPKG_TRIPLET% - -before_build: -- cmd: git submodule update --init --recursive -- cmd: mkdir CMakeBuild -- cmd: cd CMakeBuild -- cmd: cmake .. -G"Visual Studio 16 2019" -A"%platform%" -DSFIZZ_JACK=OFF -DSFIZZ_BENCHMARKS=OFF -DSFIZZ_TESTS=OFF -DSFIZZ_LV2=ON -DSFIZZ_VST=ON -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake - -build_script: -- cmd: cmake --build . --config Release -j - -after_build: -- cmd: if %platform%==Win32 set RELEASE_ARCH=x86 -- cmd: if %platform%==x64 set RELEASE_ARCH=x64 -- cmd: 7z a sfizz-lv2-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip sfizz.lv2 -- cmd: 7z a sfizz-vst3-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip sfizz.vst3 -- cmd: 7z a sfizz-lib-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip src/Release/sfizz* -- cmd: iscc.exe /dARCH=%RELEASE_ARCH% innosetup.iss - -artifacts: -- name: Packages - path: 'CMakeBuild/sfizz-*-msvc*' - -# Deploy to GitHub Releases -# See https://www.appveyor.com/docs/deployment/github/ -deploy: -- provider: GitHub - auth_token: - secure: xOugGAynvnZdc0DXaL3rlgMf4CICFLkdO8JxoRfLQMKJhkj/kZ4d8h7NCFneDzXG - artifact: Packages - draft: false - prerelease: false - force_update: true - on: - appveyor_repo_tag: true diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index f9387a09..b10a7a6f 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -40,6 +40,11 @@ if(APPLE) find_library(APPLE_AUDIOUNIT_LIBRARY "AudioUnit") find_library(APPLE_COREAUDIO_LIBRARY "CoreAudio") find_library(APPLE_COREMIDI_LIBRARY "CoreMIDI") + # See https://stackoverflow.com/a/54103956 + # and https://stackoverflow.com/a/21692023 + # Apparently this is not needed in Travis CI using addons + # but it is in Appveyor instead + list (APPEND CMAKE_PREFIX_PATH /usr/local) endif() # The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio... diff --git a/scripts/appveyor/after_build.cmd b/scripts/appveyor/after_build.cmd new file mode 100644 index 00000000..069a079d --- /dev/null +++ b/scripts/appveyor/after_build.cmd @@ -0,0 +1,4 @@ +@echo off + +iscc.exe /dARCH=%platform% innosetup.iss +move *.exe ../ diff --git a/scripts/appveyor/after_build.sh b/scripts/appveyor/after_build.sh new file mode 100755 index 00000000..2eb8e9af --- /dev/null +++ b/scripts/appveyor/after_build.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -ex + +make DESTDIR=${PWD}/${INSTALL_DIR} install +tar -zcvf "${INSTALL_DIR}.tar.gz" ${INSTALL_DIR} + +# Only release a tarball if there is a tag +if [[ ${APPVEYOR_REPO_TAG} ]]; then + mv "${INSTALL_DIR}.tar.gz" ${APPVEYOR_BUILD_FOLDER} +fi + +cd ${APPVEYOR_BUILD_FOLDER} diff --git a/scripts/appveyor/before_build.cmd b/scripts/appveyor/before_build.cmd new file mode 100644 index 00000000..6b7fa13e --- /dev/null +++ b/scripts/appveyor/before_build.cmd @@ -0,0 +1,16 @@ +git submodule update --init --recursive + +mkdir build && cd build + +if %platform%==x86 set RELEASE_ARCH=Win32 +if %platform%==x64 set RELEASE_ARCH=x64 + +cmake .. -G"Visual Studio 16 2019" -A"%RELEASE_ARCH%"^ + -DSFIZZ_JACK=OFF^ + -DSFIZZ_BENCHMARKS=OFF^ + -DSFIZZ_TESTS=OFF^ + -DSFIZZ_LV2=ON^ + -DSFIZZ_VST=ON^ + -DCMAKE_BUILD_TYPE=Release^ + -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET%^ + -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake diff --git a/scripts/appveyor/before_build.sh b/scripts/appveyor/before_build.sh new file mode 100644 index 00000000..bd242fbb --- /dev/null +++ b/scripts/appveyor/before_build.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -ex + +git submodule update --init --recursive +mkdir -p build/${INSTALL_DIR} && cd build +cmake -DCMAKE_BUILD_TYPE=Release \ + -DSFIZZ_VST=ON \ + -DSFIZZ_AU=ON \ + -DSFIZZ_TESTS=OFF \ + -DCMAKE_CXX_STANDARD=14 \ + -DLV2PLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/LV2 \ + -DVSTPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/VST3 \ + -DAUPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/Components \ + .. diff --git a/scripts/appveyor/install.cmd b/scripts/appveyor/install.cmd new file mode 100644 index 00000000..4b7b8c28 --- /dev/null +++ b/scripts/appveyor/install.cmd @@ -0,0 +1,7 @@ +choco install -y innosetup +REM Uncomment the next 4 lines to force vcpkg update +REM cd c:\tools\vcpkg\ +REM git pull +REM .\bootstrap-vcpkg.bat +REM cd %APPVEYOR_BUILD_FOLDER% +vcpkg install libsndfile:%VCPKG_TRIPLET% diff --git a/scripts/innosetup.iss.in b/scripts/innosetup.iss.in index 4ac737bd..3586f7d3 100644 --- a/scripts/innosetup.iss.in +++ b/scripts/innosetup.iss.in @@ -33,7 +33,7 @@ DefaultDirName={commonpf}\{#MyAppName} DefaultGroupName={#MyAppPublisher} ;DisableDirPage=yes LicenseFile="sfizz.lv2\LICENSE.md" -OutputBaseFileName={#MyAppName}-{#MyAppVersion}-{#Arch}-msvc-setup +OutputBaseFileName={#MyAppName}-{#MyAppVersion}-msvc-{#Arch}-setup OutputDir=. UninstallFilesDir={app} WizardImageFile="C:\Program Files (x86)\Inno Setup 6\WizModernImage-IS.bmp" diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index b5db2495..c6f573fb 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -255,7 +255,7 @@ elseif(SFIZZ_AU) DESTINATION "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}") # Add the resource fork - if (TRUE) + if (FALSE) execute_process(COMMAND "xcrun" "--find" "Rez" OUTPUT_VARIABLE OSX_REZ_COMMAND OUTPUT_STRIP_TRAILING_WHITESPACE) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include") From c5be7bc848329f48c37818b6cbccdc729791cdd1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 28 Oct 2020 10:21:37 +0100 Subject: [PATCH 021/668] Ignore appveyor scripts in the export --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 1a848588..fac64928 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ .* export-ignore .*/** export-ignore appveyor.yml export-ignore +/scripts/appveyor/** export-ignore From f1912cebc79ef7e87318163f8a53ba1600b3d8f5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 29 Oct 2020 05:43:30 +0100 Subject: [PATCH 022/668] Forbid failures --- .appveyor.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 655a5b67..9e612363 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,11 +19,6 @@ environment: VCPKG_TRIPLET: x64-windows-static PATH: C:\Program Files (x86)\Inno Setup 6;%PATH% -matrix: - allow_failures: - - platform: x86 - - platform: x64 - for: - matrix: only: From 6ff8e076f39fa34e795cf958442ee228e6e6e29d Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 29 Oct 2020 09:18:18 +0100 Subject: [PATCH 023/668] Do tests on appveyor and merge builds on travis --- .appveyor.yml | 4 +- .travis.yml | 54 ++++++++----------- ...cript_test.sh => script_test_and_build.sh} | 11 +++- scripts/appveyor/build.cmd | 5 ++ 4 files changed, 38 insertions(+), 36 deletions(-) rename .travis/{script_test.sh => script_test_and_build.sh} (55%) create mode 100644 scripts/appveyor/build.cmd diff --git a/.appveyor.yml b/.appveyor.yml index 9e612363..91693aa9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -48,7 +48,7 @@ for: cache: c:\tools\vcpkg\installed\ -> appveyor.yml install: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\install.cmd before_build: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\before_build.cmd - build_script: cmake --build . --config Release -j2 + build_script: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\build.cmd after_build: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\after_build.cmd artifacts: - name: x86 Setup @@ -60,7 +60,7 @@ for: cache: c:\tools\vcpkg\installed\ -> appveyor.yml install: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\install.cmd before_build: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\before_build.cmd - build_script: cmake --build . --config Release -j2 + build_script: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\build.cmd after_build: call %APPVEYOR_BUILD_FOLDER%\scripts\appveyor\after_build.cmd artifacts: - name: x64 Setup diff --git a/.travis.yml b/.travis.yml index 1e2a0c6e..627b6118 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,17 +19,26 @@ jobs: install: .travis/download_vst_sdk.sh script: scripts/run_clang_tidy.sh - - name: "Linux amd64 tests" + - name: "Linux amd64 test and build" arch: amd64 addons: apt: packages: - libjack-jackd2-dev - libsndfile1-dev + - libcairo2-dev + - libfontconfig1-dev + - libx11-xcb-dev + - libxcb-util-dev + - libxcb-cursor-dev + - libxcb-xkb-dev + - libxkbcommon-dev + - libxkbcommon-x11-dev + - libxcb-keysyms1-dev install: .travis/download_cmake.sh - script: .travis/script_test.sh + script: .travis/script_test_and_build.sh - - name: "Linux arm64 tests" + - name: "Linux arm64 test and build" arch: arm64-graviton2 group: edge virt: lxd @@ -38,8 +47,17 @@ jobs: packages: - libjack-jackd2-dev - libsndfile1-dev + - libcairo2-dev + - libfontconfig1-dev + - libx11-xcb-dev + - libxcb-util-dev + - libxcb-cursor-dev + - libxcb-xkb-dev + - libxkbcommon-dev + - libxkbcommon-x11-dev + - libxcb-keysyms1-dev install: .travis/download_cmake.sh - script: .travis/script_test.sh + script: .travis/script_test_and_build.sh - name: "MOD devices arm" env: @@ -72,34 +90,6 @@ jobs: script: .travis/script_mingw.sh after_success: .travis/prepare_tarball.sh - - name: "Linux amd64 library" - arch: amd64 - env: - - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}" - addons: - apt: - packages: - - libjack-jackd2-dev - - libsndfile1-dev - install: .travis/download_cmake.sh - script: .travis/script_library.sh - after_success: .travis/prepare_tarball.sh - - - name: "Linux arm64 library" - arch: arm64-graviton2 - group: edge - virt: lxd - env: - - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}" - addons: - apt: - packages: - - libjack-jackd2-dev - - libsndfile1-dev - install: .travis/download_cmake.sh - script: .travis/script_library.sh - after_success: .travis/prepare_tarball.sh - - name: "Linux arm64 static plugins" arch: arm64-graviton2 group: edge diff --git a/.travis/script_test.sh b/.travis/script_test_and_build.sh similarity index 55% rename from .travis/script_test.sh rename to .travis/script_test_and_build.sh index 8481cbfb..d7b3d6c7 100755 --- a/.travis/script_test.sh +++ b/.travis/script_test_and_build.sh @@ -3,12 +3,19 @@ set -ex mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release \ - -DSFIZZ_JACK=OFF \ + -DSFIZZ_JACK=ON \ + -DSFIZZ_VST=ON \ + -DSFIZZ_LV2_UI=ON \ -DSFIZZ_TESTS=ON \ -DSFIZZ_SHARED=OFF \ -DSFIZZ_STATIC_DEPENDENCIES=OFF \ - -DSFIZZ_LV2=OFF \ + -DSFIZZ_LV2=ON \ -DCMAKE_CXX_STANDARD=17 \ .. make -j2 sfizz_tests tests/sfizz_tests +make -j2 sfizz_jack +make -j2 sfizz_render +make -j2 sfizz_lv2 +make -j2 sfizz_lv2_ui +make -j2 sfizz_vst3 diff --git a/scripts/appveyor/build.cmd b/scripts/appveyor/build.cmd new file mode 100644 index 00000000..94838421 --- /dev/null +++ b/scripts/appveyor/build.cmd @@ -0,0 +1,5 @@ +cmake --build . --target sfizz_tests --config Release -j2 +.\tests\Release\sfizz_tests.exe +cmake --build . --target sfizz_lv2 --config Release -j2 +cmake --build . --target sfizz_lv2_ui --config Release -j2 +cmake --build . --target sfizz_vst3 --config Release -j2 From 8881c369f339dcbf728b0abbba503d2772b8c831 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 29 Oct 2020 10:10:57 +0100 Subject: [PATCH 024/668] Reinstate the Deploy stage --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 627b6118..8ed0c817 100644 --- a/.travis.yml +++ b/.travis.yml @@ -134,7 +134,8 @@ jobs: script: .travis/script_plugins.sh after_success: .travis/prepare_tarball.sh - - name: "Source packaging" + - stage: "Deploy" + name: "Source packaging" if: (tag =~ /^v?[0-9]/) AND (type = push) env: - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-src" From a34ac38aec220719a155daa554f6a1ac78829e07 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 29 Oct 2020 08:35:43 +0100 Subject: [PATCH 025/668] Add helpers to identify the documents directory --- vst/CMakeLists.txt | 20 ++++++++++++++++++-- vst/NativeHelpers.cpp | 39 +++++++++++++++++++++++++++++++++++++++ vst/NativeHelpers.h | 10 ++++++++++ vst/NativeHelpers.mm | 26 ++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 vst/NativeHelpers.cpp create mode 100644 vst/NativeHelpers.h create mode 100644 vst/NativeHelpers.mm diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index c6f573fb..145fa099 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -18,14 +18,20 @@ set(VSTPLUGIN_SOURCES SfizzVstEditor.cpp SfizzVstState.cpp VstPluginFactory.cpp - X11RunLoop.cpp) + X11RunLoop.cpp + NativeHelpers.cpp) set(VSTPLUGIN_HEADERS SfizzVstProcessor.h SfizzVstController.h SfizzVstEditor.h SfizzVstState.h - X11RunLoop.h) + X11RunLoop.h + NativeHelpers.h) + +if(APPLE) + list(APPEND VSTPLUGIN_SOURCES NativeHelpers.mm) +endif() add_library(${VSTPLUGIN_PRJ_NAME} MODULE ${VSTPLUGIN_HEADERS} @@ -65,6 +71,16 @@ if (MINGW) set_target_properties (${VSTPLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static") endif() +# Link system dependencies +if(WIN32) +elseif(APPLE) + target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${APPLE_FOUNDATION_LIBRARY}) +else() + pkg_check_modules(GLIB REQUIRED glib-2.0) + target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE ${GLIB_INCLUDE_DIRS}) + target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${GLIB_LIBRARIES}) +endif() + # Create the bundle (see "VST 3 Locations / Format") execute_process ( COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") diff --git a/vst/NativeHelpers.cpp b/vst/NativeHelpers.cpp new file mode 100644 index 00000000..3e373a63 --- /dev/null +++ b/vst/NativeHelpers.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "NativeHelpers.h" +#include + +#if defined(_WIN32) +#include +#include + +const fs::path& getUserDocumentsDirectory() +{ + static const fs::path directory = []() -> fs::path { + std::unique_ptr path(new WCHAR[32768]); + if (SHGetFolderPathW(nullptr, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, path.get()) != S_OK) + throw std::runtime_error("Cannot get the document directory."); + return fs::path(path.get()); + }(); + return directory; +} +#elif defined(__APPLE__) + // implemented in NativeHelpers.mm +#else +#include + +const fs::path& getUserDocumentsDirectory() +{ + static const fs::path directory = []() -> fs::path { + const gchar *path = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS); + if (!path) + throw std::runtime_error("Cannot get the document directory."); + return fs::path(path); + }(); + return directory; +} +#endif diff --git a/vst/NativeHelpers.h b/vst/NativeHelpers.h new file mode 100644 index 00000000..766d01d7 --- /dev/null +++ b/vst/NativeHelpers.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include + +const fs::path& getUserDocumentsDirectory(); diff --git a/vst/NativeHelpers.mm b/vst/NativeHelpers.mm new file mode 100644 index 00000000..85f924f1 --- /dev/null +++ b/vst/NativeHelpers.mm @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "NativeHelpers.h" +#import +#include + +#if defined(__APPLE__) +const fs::path& getUserDocumentsDirectory() +{ + static const fs::path directory = []() -> fs::path { + NSFileManager *fm = [NSFileManager defaultManager]; + NSArray *urls = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; + for (NSUInteger i = 0, n = [urls count]; i < n; ++i) { + NSURL *url = [urls objectAtIndex:i]; + if ([url isFileURL]) + return fs::path([url path].UTF8String); + } + throw std::runtime_error("Cannot get the document directory."); + }(); + return directory; +} +#endif From 45285a4a660ba6ceb20146f2bd7f43409ebb6443 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 29 Oct 2020 10:24:00 +0100 Subject: [PATCH 026/668] VST file search --- vst/CMakeLists.txt | 11 ++- vst/NativeHelpers.mm | 3 + vst/SfizzFileScan.cpp | 198 ++++++++++++++++++++++++++++++++++++++ vst/SfizzFileScan.h | 38 ++++++++ vst/SfizzForeignPaths.cpp | 51 ++++++++++ vst/SfizzForeignPaths.h | 12 +++ vst/SfizzForeignPaths.mm | 27 ++++++ vst/SfizzVstProcessor.cpp | 27 ++++++ 8 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 vst/SfizzFileScan.cpp create mode 100644 vst/SfizzFileScan.h create mode 100644 vst/SfizzForeignPaths.cpp create mode 100644 vst/SfizzForeignPaths.h create mode 100644 vst/SfizzForeignPaths.mm diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 145fa099..72e27562 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -17,6 +17,8 @@ set(VSTPLUGIN_SOURCES SfizzVstController.cpp SfizzVstEditor.cpp SfizzVstState.cpp + SfizzFileScan.cpp + SfizzForeignPaths.cpp VstPluginFactory.cpp X11RunLoop.cpp NativeHelpers.cpp) @@ -26,11 +28,18 @@ set(VSTPLUGIN_HEADERS SfizzVstController.h SfizzVstEditor.h SfizzVstState.h + SfizzFileScan.h + SfizzForeignPaths.h X11RunLoop.h NativeHelpers.h) if(APPLE) - list(APPEND VSTPLUGIN_SOURCES NativeHelpers.mm) + set(VSTPLUGIN_MAC_SOURCES + SfizzForeignPaths.mm + NativeHelpers.mm) + list(APPEND VSTPLUGIN_SOURCES ${VSTPLUGIN_MAC_SOURCES}) + set_property(SOURCE ${VSTPLUGIN_MAC_SOURCES} APPEND_STRING + PROPERTY COMPILE_FLAGS " -fobjc-arc") endif() add_library(${VSTPLUGIN_PRJ_NAME} MODULE diff --git a/vst/NativeHelpers.mm b/vst/NativeHelpers.mm index 85f924f1..016ff4d1 100644 --- a/vst/NativeHelpers.mm +++ b/vst/NativeHelpers.mm @@ -7,6 +7,9 @@ #include "NativeHelpers.h" #import #include +#if !__has_feature(objc_arc) +#error This source file requires ARC +#endif #if defined(__APPLE__) const fs::path& getUserDocumentsDirectory() diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp new file mode 100644 index 00000000..f8e2faf4 --- /dev/null +++ b/vst/SfizzFileScan.cpp @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzFileScan.h" +#include "SfizzForeignPaths.h" +#include "NativeHelpers.h" +#include +#include +#include + +// wait at least this much before refreshing the file rescan +// it permits to not repeat the operation many times if many searches are +// requested at once, eg. on session loading with multiple plugin instances +static const std::chrono::seconds expiration_time { 10 }; + +SfzFileScan& SfzFileScan::getInstance() +{ + static SfzFileScan instance; + return instance; +} + +bool SfzFileScan::locateRealFile(const fs::path& pathOrig, fs::path& pathFound) +{ + if (pathOrig.empty()) + return false; + + std::unique_lock lock { mutex }; + refreshScan(); + + auto it = file_index_.find(keyOf(pathOrig)); + if (it == file_index_.end()) + return false; + + std::list candidateStrings = it->second; + lock.unlock(); + + std::vector candidates; + candidates.reserve(candidateStrings.size()); + for (const std::string& str : candidateStrings) + candidates.push_back(fs::u8path(str)); + + pathFound = electBestMatch(pathOrig, candidates); + return true; +} + +bool SfzFileScan::isExpired() const +{ + return !completion_time_ || + (clock::now() - *completion_time_) > expiration_time; +} + +void SfzFileScan::refreshScan(bool force) +{ + if (!force && !isExpired()) + return; + + for (const fs::path& dirPath : SfizzPaths::sfzDefaultPaths()) { + std::error_code ec; + + for (fs::recursive_directory_iterator it(dirPath, ec); + !ec && it != fs::recursive_directory_iterator(); + it.increment(ec)) + { + const fs::directory_entry& ent = *it; + const fs::path& filePath = ent.path(); + std::error_code ec; + if (ent.is_regular_file(ec) /*&& pathIsSfz(filePath)*/) + file_index_[keyOf(filePath.filename())].push_back(filePath.u8string()); + } + } + + completion_time_ = clock::now(); +} + +std::string SfzFileScan::keyOf(const fs::path& path) +{ + std::string key = path.u8string(); + absl::AsciiStrToLower(&key); + return key; +} + +namespace SfzFileScanImpl { +template +bool asciiCaseEqual(const std::basic_string& a, const std::basic_string& b) +{ + const size_t n = a.size(); + if (n != b.size()) + return false; + + auto lower = [](T c) -> T { + return (c >= T('A') && c <= T('Z')) ? (c - T('A') + T('a')) : c; + }; + + for (size_t i = 0; i < n; ++i) + if (lower(a[i]) != lower(b[i])) + return false; + + return true; +} +} // namespace SfzFileScanImpl + +bool SfzFileScan::pathIsSfz(const fs::path& path) +{ + const fs::path::string_type& str = path.native(); + using char_type = fs::path::value_type; + const size_t n = str.size(); + return n > 4 && + str[n - 4] == char_type('.') && + (str[n - 3] == char_type('s') || str[n - 3] == char_type('S')) && + (str[n - 2] == char_type('f') || str[n - 2] == char_type('F')) && + (str[n - 1] == char_type('z') || str[n - 1] == char_type('Z')); +} + +const fs::path& SfzFileScan::electBestMatch(const fs::path& path, absl::Span candidates) +{ + if (candidates.empty()) + return path; + + if (candidates.size() == 1) + return candidates.front(); + + struct Score { + size_t index = 0; + size_t components = 0; + size_t exact = 0; + explicit Score(size_t index) noexcept : index(index) {} + bool operator<(const Score& other) const noexcept + { + return (components != other.components) ? + (components < other.components) : (exact < other.exact); + } + }; + + std::vector scores; + scores.reserve(candidates.size()); + + for (size_t i = 0, n = candidates.size(); i < n; ++i) { + scores.emplace_back(i); + Score& score = scores.back(); + + const fs::path& p1 = path; + const fs::path& p2 = candidates[i]; + auto it1 = p1.end(); + auto it2 = p2.end(); + + while (it1-- != p1.begin() && it2-- != p2.begin()) { + const fs::path& c1 = *it1; + const fs::path& c2 = *it2; + if (c1 == c2) { + score.components += 1; + score.exact += 1; + } + else if (SfzFileScanImpl::asciiCaseEqual(c1.native(), c2.native())) + score.components += 1; + } + } + + std::stable_sort(scores.begin(), scores.end()); + + return candidates[scores[0].index]; +} + +//------------------------------------------------------------------------------ + +namespace SfizzPaths { + +absl::Span sfzDefaultPaths() +{ + static const auto paths = []() -> std::vector { + std::vector paths; + paths.reserve(8); + + paths.push_back(getUserDocumentsDirectory() / "SFZ instruments"); + + for (const fs::path& foreign : { + getAriaPathSetting("user_files_dir"), + getAriaPathSetting("Converted_path") }) + if (!foreign.empty() && foreign.is_absolute()) + paths.push_back(foreign); + + paths.shrink_to_fit(); + return paths; + }(); + return paths; +} + +void createSfzDefaultPaths() +{ + for (const fs::path& path : sfzDefaultPaths()) { + std::error_code ec; + fs::create_directory(path, ec); + } +} + +} // namespace SfizzPaths diff --git a/vst/SfizzFileScan.h b/vst/SfizzFileScan.h new file mode 100644 index 00000000..68b80a90 --- /dev/null +++ b/vst/SfizzFileScan.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +class SfzFileScan { +public: + static SfzFileScan& getInstance(); + bool locateRealFile(const fs::path& pathOrig, fs::path& pathFound); + +private: + typedef std::chrono::steady_clock clock; + std::mutex mutex; + absl::optional completion_time_; + std::unordered_map> file_index_; + + bool isExpired() const; + void refreshScan(bool force = false); + static std::string keyOf(const fs::path& path); + static bool pathIsSfz(const fs::path& path); + static const fs::path& electBestMatch(const fs::path& path, absl::Span candidates); +}; + +namespace SfizzPaths { +absl::Span sfzDefaultPaths(); +void createSfzDefaultPaths(); +} // namespace SfizzPaths diff --git a/vst/SfizzForeignPaths.cpp b/vst/SfizzForeignPaths.cpp new file mode 100644 index 00000000..17319997 --- /dev/null +++ b/vst/SfizzForeignPaths.cpp @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzForeignPaths.h" + +namespace SfizzPaths { + +#if defined(_WIN32) +#include + +fs::path getAriaPathSetting(const char* name) +{ + fs::path path; + + HKEY key = 0; + + std::unique_ptr nameW; + unsigned nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0); + if (nameSize == 0) + return {}; + nameW.reset(new WCHAR[nameSize]); + if (MultiByteToWideChar(CP_UTF8, 0, name, -1, nameW.get(), nameSize) == 0) + return {}; + + const WCHAR ariaKeyPath[] = L"Software\\Plogue Art et Technologie, Inc\\Aria"; + + if (RegOpenKeyExW(HKEY_CURRENT_USER, ariaKeyPath, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { + WCHAR valueBuffer[32768 + 1]; + DWORD valueSize = sizeof(valueBuffer) - sizeof(WCHAR); + if (RegQueryValueExW(key, nameW.get(), nullptr, nullptr, reinterpret_cast(valueBuffer), &valueSize) == ERROR_SUCCESS) { + valueBuffer[32768] = L'\0'; + path = fs::path(valueBuffer); + } + RegCloseKey(key); + } + + return path; +} +#elif defined(__APPLE__) + // implementation in SfizzForeignPaths.mm +#else +fs::path getAriaPathSetting(const char* name) +{ + return {}; +} +#endif + +} // namespace SfizzPaths diff --git a/vst/SfizzForeignPaths.h b/vst/SfizzForeignPaths.h new file mode 100644 index 00000000..02f79b42 --- /dev/null +++ b/vst/SfizzForeignPaths.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include + +namespace SfizzPaths { +fs::path getAriaPathSetting(const char* name); +} // namespace SfizzPaths diff --git a/vst/SfizzForeignPaths.mm b/vst/SfizzForeignPaths.mm new file mode 100644 index 00000000..074a3ece --- /dev/null +++ b/vst/SfizzForeignPaths.mm @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzForeignPaths.h" + +#if defined(__APPLE__) +#import +#if !__has_feature(objc_arc) +#error This source file requires ARC +#endif + +namespace SfizzPaths { + +fs::path getAriaPathSetting(const char* name) +{ + NSUserDefaults* ud = [[NSUserDefaults alloc] initWithSuiteName:@"com.plogue.aria"]; + NSString* value = [ud stringForKey:[NSString stringWithUTF8String:name]]; + if (!value) + return {}; + return fs::path(value.UTF8String); +} + +} // namespace SfizzPaths +#endif diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 6f729a27..3825db65 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -7,9 +7,11 @@ #include "SfizzVstProcessor.h" #include "SfizzVstController.h" #include "SfizzVstState.h" +#include "SfizzFileScan.h" #include "base/source/fstreamer.h" #include "pluginterfaces/vst/ivstevents.h" #include "pluginterfaces/vst/ivstparameterchanges.h" +#include #include template @@ -28,6 +30,8 @@ SfizzVstProcessor::SfizzVstProcessor() : _fifoToWorker(64 * 1024), _fifoMidiFromUi(64 * 1024) { setControllerClass(SfizzVstController::cid); + + SfizzPaths::createSfzDefaultPaths(); } SfizzVstProcessor::~SfizzVstProcessor() @@ -83,6 +87,29 @@ tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream) if (r != kResultTrue) return r; + // check the files to really exist, otherwise search them + for (std::string* statePath : { &s.sfzFile, &s.scalaFile }) { + if (statePath->empty()) + continue; + + fs::path pathOrig = fs::u8path(*statePath); + std::error_code ec; + if (fs::is_regular_file(pathOrig, ec)) + continue; + + fprintf(stderr, "[Sfizz] searching for missing file: %s\n", pathOrig.filename().u8string().c_str()); + + SfzFileScan& fileScan = SfzFileScan::getInstance(); + fs::path pathFound; + if (!fileScan.locateRealFile(pathOrig, pathFound)) + fprintf(stderr, "[Sfizz] file not found: %s\n", pathOrig.filename().u8string().c_str()); + else { + fprintf(stderr, "[Sfizz] file found: %s\n", pathFound.filename().u8string().c_str()); + *statePath = pathFound.u8string(); + } + } + + // std::lock_guard lock(_processMutex); _state = s; From 3db710f10160dbed3f3dfa34f3f4072b0c3dfe16 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 30 Oct 2020 06:00:30 +0100 Subject: [PATCH 027/668] Do some minor code cleanups --- vst/NativeHelpers.cpp | 2 +- vst/NativeHelpers.mm | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/vst/NativeHelpers.cpp b/vst/NativeHelpers.cpp index 3e373a63..2015a194 100644 --- a/vst/NativeHelpers.cpp +++ b/vst/NativeHelpers.cpp @@ -29,7 +29,7 @@ const fs::path& getUserDocumentsDirectory() const fs::path& getUserDocumentsDirectory() { static const fs::path directory = []() -> fs::path { - const gchar *path = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS); + const gchar* path = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS); if (!path) throw std::runtime_error("Cannot get the document directory."); return fs::path(path); diff --git a/vst/NativeHelpers.mm b/vst/NativeHelpers.mm index 016ff4d1..8f2bfd3d 100644 --- a/vst/NativeHelpers.mm +++ b/vst/NativeHelpers.mm @@ -11,12 +11,11 @@ #error This source file requires ARC #endif -#if defined(__APPLE__) const fs::path& getUserDocumentsDirectory() { static const fs::path directory = []() -> fs::path { - NSFileManager *fm = [NSFileManager defaultManager]; - NSArray *urls = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; + NSFileManager* fm = [NSFileManager defaultManager]; + NSArray* urls = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; for (NSUInteger i = 0, n = [urls count]; i < n; ++i) { NSURL *url = [urls objectAtIndex:i]; if ([url isFileURL]) @@ -26,4 +25,3 @@ const fs::path& getUserDocumentsDirectory() }(); return directory; } -#endif From 6f8078af45c56c9072583fba5a99b46bb047bfcb Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 30 Oct 2020 06:05:13 +0100 Subject: [PATCH 028/668] Allow the file scan to proceed on permission denied --- vst/SfizzFileScan.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index f8e2faf4..dd6a1990 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -59,8 +59,10 @@ void SfzFileScan::refreshScan(bool force) for (const fs::path& dirPath : SfizzPaths::sfzDefaultPaths()) { std::error_code ec; + const fs::directory_options dirOpts = + fs::directory_options::skip_permission_denied; - for (fs::recursive_directory_iterator it(dirPath, ec); + for (fs::recursive_directory_iterator it(dirPath, dirOpts, ec); !ec && it != fs::recursive_directory_iterator(); it.increment(ec)) { From 336847ee7cfee54e0fc556e282d9d9b3ff1a52f8 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 30 Oct 2020 06:24:42 +0100 Subject: [PATCH 029/668] Clear the file index on refresh --- vst/SfizzFileScan.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index dd6a1990..951778df 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -57,6 +57,8 @@ void SfzFileScan::refreshScan(bool force) if (!force && !isExpired()) return; + file_index_.clear(); + for (const fs::path& dirPath : SfizzPaths::sfzDefaultPaths()) { std::error_code ec; const fs::directory_options dirOpts = From 99b7780ff3f9b7280e22435c6459adfdafc6a7f1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 30 Oct 2020 07:05:19 +0100 Subject: [PATCH 030/668] Implement the file trie --- vst/CMakeLists.txt | 6 ++- vst/FileTrie.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++ vst/FileTrie.h | 49 ++++++++++++++++++++++ vst/SfizzFileScan.cpp | 22 ++++++---- vst/SfizzFileScan.h | 4 +- 5 files changed, 168 insertions(+), 11 deletions(-) create mode 100644 vst/FileTrie.cpp create mode 100644 vst/FileTrie.h diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 72e27562..0ee8cddc 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -21,7 +21,8 @@ set(VSTPLUGIN_SOURCES SfizzForeignPaths.cpp VstPluginFactory.cpp X11RunLoop.cpp - NativeHelpers.cpp) + NativeHelpers.cpp + FileTrie.cpp) set(VSTPLUGIN_HEADERS SfizzVstProcessor.h @@ -31,7 +32,8 @@ set(VSTPLUGIN_HEADERS SfizzFileScan.h SfizzForeignPaths.h X11RunLoop.h - NativeHelpers.h) + NativeHelpers.h + FileTrie.h) if(APPLE) set(VSTPLUGIN_MAC_SOURCES diff --git a/vst/FileTrie.cpp b/vst/FileTrie.cpp new file mode 100644 index 00000000..2819c863 --- /dev/null +++ b/vst/FileTrie.cpp @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "FileTrie.h" +#include +#include + +constexpr size_t FileTrie::npos; + +fs::path FileTrie::at(size_t index) const +{ + if (index >= entries_.size()) + throw std::out_of_range("FileTrie::at"); + return pathFromEntry(index); +} + +fs::path FileTrie::operator[](size_t index) const +{ + assert(index < entries_.size()); + return pathFromEntry(index); +} + +fs::path FileTrie::pathFromEntry(size_t index) const +{ + const Entry* currentEntry = &entries_[index]; + fs::path path { currentEntry->name }; + + size_t currentIndex; + while ((currentIndex = currentEntry->parent) != npos) { + currentEntry = &entries_[currentIndex]; + path = fs::path { currentEntry->name } / path; + } + + return path; +} + +//------------------------------------------------------------------------------ +FileTrieBuilder::FileTrieBuilder(size_t initialCapacity) +{ + FileTrie& trie = trie_; + trie.entries_.reserve(initialCapacity); +} + +FileTrie&& FileTrieBuilder::build() +{ + FileTrie& trie = trie_; + trie.entries_.shrink_to_fit(); + return std::move(trie); +} + +size_t FileTrieBuilder::addFile(const fs::path& path) +{ + if (path.empty()) + return FileTrie::npos; + + size_t dirIndex = ensureDirectory(path.parent_path()); + + FileTrie& trie = trie_; + FileTrie::Entry ent; + ent.parent = dirIndex; + ent.name = (--path.end())->u8string(); + + size_t fileIndex = trie.entries_.size(); + trie.entries_.push_back(std::move(ent)); + + return fileIndex; +} + +size_t FileTrieBuilder::ensureDirectory(const fs::path& dirPath) +{ + if (dirPath.empty()) + return FileTrie::npos; + + const fs::path::string_type& dirNat = dirPath.native(); + auto it = directories_.find(dirNat); + if (it != directories_.end()) + return it->second; + + FileTrie& trie = trie_; + FileTrie::Entry ent; + ent.parent = FileTrie::npos; + ent.name = (--dirPath.end())->u8string(); + if (dirPath.has_parent_path()) { + fs::path parentPath = dirPath.parent_path(); + if (parentPath != dirPath) + ent.parent = ensureDirectory(parentPath); + } + + size_t dirIndex = trie.entries_.size(); + trie.entries_.push_back(std::move(ent)); + + directories_[dirNat] = dirIndex; + + return dirIndex; +} diff --git a/vst/FileTrie.h b/vst/FileTrie.h new file mode 100644 index 00000000..8ea73559 --- /dev/null +++ b/vst/FileTrie.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include +#include +#include +#include + +class FileTrie { +public: + static constexpr size_t npos = ~size_t(0); + + size_t size() const noexcept { return entries_.size(); } + fs::path at(size_t index) const; + fs::path operator[](size_t index) const; + void clear() noexcept { entries_.clear(); } + +private: + fs::path pathFromEntry(size_t index) const; + +private: + struct Entry { + size_t parent = npos; + std::string name; + }; + std::vector entries_; + + friend class FileTrieBuilder; +}; + +//------------------------------------------------------------------------------ +class FileTrieBuilder { +public: + explicit FileTrieBuilder(size_t initialCapacity = 8192); + FileTrie&& build(); + size_t addFile(const fs::path& path); + +private: + size_t ensureDirectory(const fs::path& dirPath); + +private: + FileTrie trie_; + std::unordered_map directories_; +}; diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index 951778df..ae2c4b60 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -34,13 +34,13 @@ bool SfzFileScan::locateRealFile(const fs::path& pathOrig, fs::path& pathFound) if (it == file_index_.end()) return false; - std::list candidateStrings = it->second; - lock.unlock(); - + const std::list& candidateIndices = it->second; std::vector candidates; - candidates.reserve(candidateStrings.size()); - for (const std::string& str : candidateStrings) - candidates.push_back(fs::u8path(str)); + candidates.reserve(candidateIndices.size()); + for (const size_t index : candidateIndices) + candidates.push_back(file_trie_[index]); + + lock.unlock(); pathFound = electBestMatch(pathOrig, candidates); return true; @@ -57,8 +57,11 @@ void SfzFileScan::refreshScan(bool force) if (!force && !isExpired()) return; + file_trie_.clear(); file_index_.clear(); + FileTrieBuilder builder; + for (const fs::path& dirPath : SfizzPaths::sfzDefaultPaths()) { std::error_code ec; const fs::directory_options dirOpts = @@ -71,11 +74,14 @@ void SfzFileScan::refreshScan(bool force) const fs::directory_entry& ent = *it; const fs::path& filePath = ent.path(); std::error_code ec; - if (ent.is_regular_file(ec) /*&& pathIsSfz(filePath)*/) - file_index_[keyOf(filePath.filename())].push_back(filePath.u8string()); + if (ent.is_regular_file(ec) /*&& pathIsSfz(filePath)*/) { + size_t fileIndex = builder.addFile(filePath); + file_index_[keyOf(filePath.filename())].push_back(fileIndex); + } } } + file_trie_ = builder.build(); completion_time_ = clock::now(); } diff --git a/vst/SfizzFileScan.h b/vst/SfizzFileScan.h index 68b80a90..2626ef15 100644 --- a/vst/SfizzFileScan.h +++ b/vst/SfizzFileScan.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "FileTrie.h" #include #include #include @@ -23,7 +24,8 @@ private: typedef std::chrono::steady_clock clock; std::mutex mutex; absl::optional completion_time_; - std::unordered_map> file_index_; + FileTrie file_trie_; + std::unordered_map> file_index_; bool isExpired() const; void refreshScan(bool force = false); From 21ed20bce137214786510e5d91503263c90a59a9 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 30 Oct 2020 08:00:41 +0100 Subject: [PATCH 031/668] Ensure that default paths don't have duplicates --- vst/SfizzFileScan.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index ae2c4b60..c9251593 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -8,6 +8,7 @@ #include "SfizzForeignPaths.h" #include "NativeHelpers.h" #include +#include #include #include @@ -182,14 +183,18 @@ absl::Span sfzDefaultPaths() static const auto paths = []() -> std::vector { std::vector paths; paths.reserve(8); + auto addPath = [&paths](const fs::path& newPath) { + if (absl::c_find(paths, newPath) == paths.end()) + paths.push_back(newPath); + }; - paths.push_back(getUserDocumentsDirectory() / "SFZ instruments"); + addPath(getUserDocumentsDirectory() / "SFZ instruments"); for (const fs::path& foreign : { getAriaPathSetting("user_files_dir"), getAriaPathSetting("Converted_path") }) if (!foreign.empty() && foreign.is_absolute()) - paths.push_back(foreign); + addPath(foreign); paths.shrink_to_fit(); return paths; From f1053aa31be1e55ae00639590db822c356f3ae32 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 30 Oct 2020 08:05:54 +0100 Subject: [PATCH 032/668] Add a debugging helper to dump the trie --- vst/FileTrie.cpp | 10 ++++++++++ vst/FileTrie.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/vst/FileTrie.cpp b/vst/FileTrie.cpp index 2819c863..9db72286 100644 --- a/vst/FileTrie.cpp +++ b/vst/FileTrie.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "FileTrie.h" +#include #include #include @@ -37,6 +38,15 @@ fs::path FileTrie::pathFromEntry(size_t index) const return path; } +std::ostream& operator<<(std::ostream& os, const FileTrie& trie) +{ + os << '{' << '\n'; + for (size_t i = 0, n = trie.size(); i < n; ++i) + os << '\t' << i << ':' << ' ' << trie[i] << ',' << '\n'; + os << '}'; + return os; +} + //------------------------------------------------------------------------------ FileTrieBuilder::FileTrieBuilder(size_t initialCapacity) { diff --git a/vst/FileTrie.h b/vst/FileTrie.h index 8ea73559..63bf32d7 100644 --- a/vst/FileTrie.h +++ b/vst/FileTrie.h @@ -9,6 +9,7 @@ #include #include #include +#include #include class FileTrie { @@ -33,6 +34,8 @@ private: friend class FileTrieBuilder; }; +std::ostream& operator<<(std::ostream& os, const FileTrie& trie); + //------------------------------------------------------------------------------ class FileTrieBuilder { public: From 59e939e9077d5249a9b93cec21755986cccd0d06 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 30 Oct 2020 08:11:17 +0100 Subject: [PATCH 033/668] Ensure utf-8 to be used as path encoding --- vst/FileTrie.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vst/FileTrie.cpp b/vst/FileTrie.cpp index 9db72286..014ad626 100644 --- a/vst/FileTrie.cpp +++ b/vst/FileTrie.cpp @@ -27,12 +27,12 @@ fs::path FileTrie::operator[](size_t index) const fs::path FileTrie::pathFromEntry(size_t index) const { const Entry* currentEntry = &entries_[index]; - fs::path path { currentEntry->name }; + fs::path path = fs::u8path(currentEntry->name); size_t currentIndex; while ((currentIndex = currentEntry->parent) != npos) { currentEntry = &entries_[currentIndex]; - path = fs::path { currentEntry->name } / path; + path = fs::u8path(currentEntry->name) / path; } return path; From 73051b7135f79aa9f69502d076e7c2b792ee408e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 30 Oct 2020 08:17:20 +0100 Subject: [PATCH 034/668] Improve complexity of the file scoring --- vst/SfizzFileScan.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index c9251593..c9f47ea0 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -134,10 +134,8 @@ const fs::path& SfzFileScan::electBestMatch(const fs::path& path, absl::Span Date: Fri, 30 Oct 2020 08:36:52 +0100 Subject: [PATCH 035/668] Stop path scoring at the first component mismatch --- vst/SfizzFileScan.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index c9f47ea0..9971d6ab 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -155,7 +155,8 @@ const fs::path& SfzFileScan::electBestMatch(const fs::path& path, absl::Span Date: Fri, 30 Oct 2020 11:49:22 +0100 Subject: [PATCH 036/668] Free the audiofile structs on `st_close` Otherwise they leak --- external/st_audiofile/src/st_audiofile.c | 2 +- external/st_audiofile/src/st_audiofile_sndfile.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c index 81eb5d47..57511bb7 100644 --- a/external/st_audiofile/src/st_audiofile.c +++ b/external/st_audiofile/src/st_audiofile.c @@ -155,7 +155,7 @@ void st_close(st_audio_file* af) break; } - af->type = st_audio_file_null; + free(af); } int st_get_type(st_audio_file* af) diff --git a/external/st_audiofile/src/st_audiofile_sndfile.c b/external/st_audiofile/src/st_audiofile_sndfile.c index 5b3e9b9e..480daa34 100644 --- a/external/st_audiofile/src/st_audiofile_sndfile.c +++ b/external/st_audiofile/src/st_audiofile_sndfile.c @@ -52,10 +52,10 @@ st_audio_file* st_open_file_w(const wchar_t* filename) void st_close(st_audio_file* af) { - if (af->snd) { + if (af->snd) sf_close(af->snd); - af->snd = NULL; - } + + free(af); } int st_get_type(st_audio_file* af) From 1df11d072bd99e2e0391c8d44239c6cd8478d29f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 31 Oct 2020 12:09:40 +0100 Subject: [PATCH 037/668] Fix st-audiofile bug which may prevent opening MP3 --- external/st_audiofile/src/st_audiofile.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c index 57511bb7..64f1cccf 100644 --- a/external/st_audiofile/src/st_audiofile.c +++ b/external/st_audiofile/src/st_audiofile.c @@ -24,10 +24,6 @@ struct st_audio_file { } cache; }; -enum { - st_audio_file_null = -1, -}; - static st_audio_file* st_generic_open_file(const void* filename, int widepath) { #if !defined(_WIN32) @@ -95,7 +91,7 @@ static st_audio_file* st_generic_open_file(const void* filename, int widepath) } // Try MP3 - if (af->type == st_audio_file_null) { + { af->mp3 = (drmp3*)malloc(sizeof(drmp3)); if (!af->mp3) { free(af); From ef7a1969d3bbc79ff4415e6ba1244e7295c8be10 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 31 Oct 2020 11:59:45 +0100 Subject: [PATCH 038/668] Support loading AIFF files --- .gitmodules | 3 + benchmarks/BM_audioReaders.cpp | 26 +++++++++ external/st_audiofile/CMakeLists.txt | 5 +- external/st_audiofile/src/st_audiofile.c | 55 +++++++++++++++++++ external/st_audiofile/src/st_audiofile.h | 1 + .../st_audiofile/src/st_audiofile_common.c | 3 + external/st_audiofile/src/st_audiofile_libs.h | 1 + .../st_audiofile/src/st_audiofile_sndfile.c | 3 + external/st_audiofile/thirdparty/libaiff | 1 + 9 files changed, 97 insertions(+), 1 deletion(-) create mode 160000 external/st_audiofile/thirdparty/libaiff diff --git a/.gitmodules b/.gitmodules index c47fa23b..d97f8bae 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,3 +27,6 @@ path = external/st_audiofile/thirdparty/stb_vorbis url = https://github.com/sfztools/stb_vorbis.git shallow = true +[submodule "external/st_audiofile/thirdparty/libaiff"] + path = external/st_audiofile/thirdparty/libaiff + url = https://github.com/sfztools/libaiff.git diff --git a/benchmarks/BM_audioReaders.cpp b/benchmarks/BM_audioReaders.cpp index 98483a8d..3a4b23e7 100644 --- a/benchmarks/BM_audioReaders.cpp +++ b/benchmarks/BM_audioReaders.cpp @@ -94,6 +94,7 @@ public: static TemporaryFile fileWav; static TemporaryFile fileFlac; + static TemporaryFile fileAiff; static TemporaryFile fileOgg; std::vector workBuffer; @@ -101,6 +102,7 @@ public: TemporaryFile AudioReaderFixture::fileWav = createAudioFile(SF_FORMAT_WAV|SF_FORMAT_PCM_16); TemporaryFile AudioReaderFixture::fileFlac = createAudioFile(SF_FORMAT_FLAC|SF_FORMAT_PCM_16); +TemporaryFile AudioReaderFixture::fileAiff = createAudioFile(SF_FORMAT_AIFF|SF_FORMAT_PCM_16); TemporaryFile AudioReaderFixture::fileOgg = createAudioFile(SF_FORMAT_OGG|SF_FORMAT_VORBIS); TemporaryFile AudioReaderFixture::createAudioFile(int format) @@ -196,6 +198,27 @@ BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseFlac)(benchmark::State& state) } } +BENCHMARK_DEFINE_F(AudioReaderFixture, EntireAiff)(benchmark::State& state) +{ + for (auto _ : state) { + doEntireRead(fileAiff.path()); + } +} + +BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardAiff)(benchmark::State& state) +{ + for (auto _ : state) { + doReaderBenchmark(fileAiff.path(), workBuffer, sfz::AudioReaderType::Forward); + } +} + +BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseAiff)(benchmark::State& state) +{ + for (auto _ : state) { + doReaderBenchmark(fileAiff.path(), workBuffer, sfz::AudioReaderType::Reverse); + } +} + BENCHMARK_DEFINE_F(AudioReaderFixture, EntireOgg)(benchmark::State& state) { for (auto _ : state) { @@ -225,6 +248,9 @@ BENCHMARK_REGISTER_F(AudioReaderFixture, EntireWav)->Range(1, 1); BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardFlac)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseFlac)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); BENCHMARK_REGISTER_F(AudioReaderFixture, EntireFlac)->Range(1, 1); +BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardAiff)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); +BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseAiff)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); +BENCHMARK_REGISTER_F(AudioReaderFixture, EntireAiff)->Range(1, 1); BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); #if !defined(ST_AUDIO_FILE_USE_SNDFILE) BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10)); diff --git a/external/st_audiofile/CMakeLists.txt b/external/st_audiofile/CMakeLists.txt index e0fb1e4e..643c0992 100644 --- a/external/st_audiofile/CMakeLists.txt +++ b/external/st_audiofile/CMakeLists.txt @@ -19,7 +19,10 @@ add_executable(st_info target_link_libraries(st_info PRIVATE st_audiofile) -if(ST_AUDIO_FILE_USE_SNDFILE) +if(NOT ST_AUDIO_FILE_USE_SNDFILE) + add_subdirectory("thirdparty/libaiff" EXCLUDE_FROM_ALL) + target_link_libraries(st_audiofile PRIVATE aiff::aiff) +else() target_compile_definitions(st_audiofile PUBLIC "ST_AUDIO_FILE_USE_SNDFILE=1") if(ST_AUDIO_FILE_EXTERNAL_SNDFILE) diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c index 64f1cccf..f9d1e869 100644 --- a/external/st_audiofile/src/st_audiofile.c +++ b/external/st_audiofile/src/st_audiofile.c @@ -14,11 +14,13 @@ struct st_audio_file { union { drwav *wav; drflac *flac; + AIFF_Ref aiff; drmp3 *mp3; stb_vorbis* ogg; }; union { + struct { uint32_t channels; float sample_rate; uint64_t frames; } aiff; struct { uint64_t frames; } mp3; struct { uint32_t channels; float sample_rate; uint64_t frames; } ogg; } cache; @@ -68,6 +70,30 @@ static st_audio_file* st_generic_open_file(const void* filename, int widepath) } } + // Try AIFF + { + af->aiff = +#if defined(_WIN32) + widepath ? AIFF_OpenFileW((const wchar_t*)filename, F_RDONLY) : +#endif + AIFF_OpenFile((const char*)filename, F_RDONLY); + if (af->aiff) { + int channels; + double sample_rate; + uint64_t frames; + if (AIFF_GetAudioFormat(af->aiff, &frames, &channels, &sample_rate, NULL, NULL) == -1) { + AIFF_CloseFile(af->aiff); + free(af); + return NULL; + } + af->cache.aiff.channels = (uint32_t)channels; + af->cache.aiff.sample_rate = (float)sample_rate; + af->cache.aiff.frames = frames; + af->type = st_audio_file_aiff; + return af; + } + } + // Try OGG { af->ogg = @@ -142,6 +168,9 @@ void st_close(st_audio_file* af) case st_audio_file_flac: drflac_close(af->flac); break; + case st_audio_file_aiff: + AIFF_CloseFile(af->aiff); + break; case st_audio_file_ogg: stb_vorbis_close(af->ogg); break; @@ -170,6 +199,9 @@ uint32_t st_get_channels(st_audio_file* af) case st_audio_file_flac: channels = af->flac->channels; break; + case st_audio_file_aiff: + channels = af->cache.aiff.channels; + break; case st_audio_file_ogg: channels = af->cache.ogg.channels; break; @@ -192,6 +224,9 @@ float st_get_sample_rate(st_audio_file* af) case st_audio_file_flac: sample_rate = af->flac->sampleRate; break; + case st_audio_file_aiff: + sample_rate = af->cache.aiff.sample_rate; + break; case st_audio_file_ogg: sample_rate = af->cache.ogg.sample_rate; break; @@ -214,6 +249,9 @@ uint64_t st_get_frame_count(st_audio_file* af) case st_audio_file_flac: frames = af->flac->totalPCMFrameCount; break; + case st_audio_file_aiff: + frames = af->cache.aiff.frames; + break; case st_audio_file_ogg: frames = af->cache.ogg.frames; break; @@ -236,6 +274,9 @@ bool st_seek(st_audio_file* af, uint64_t frame) case st_audio_file_flac: success = drflac_seek_to_pcm_frame(af->flac, frame); break; + case st_audio_file_aiff: + success = AIFF_Seek(af->aiff, frame) != -1; + break; case st_audio_file_ogg: success = stb_vorbis_seek(af->ogg, (unsigned)frame) != 0; break; @@ -256,6 +297,13 @@ uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count) case st_audio_file_flac: count = drflac_read_pcm_frames_s16(af->flac, count, buffer); break; + case st_audio_file_aiff: + { + uint32_t channels = af->cache.aiff.channels; + unsigned samples = AIFF_ReadSamples16Bit(af->aiff, buffer, (unsigned)(channels * count)); + count = ((int)samples != -1) ? (samples / channels) : 0; + } + break; case st_audio_file_ogg: count = stb_vorbis_get_samples_short_interleaved( af->ogg, af->cache.ogg.channels, buffer, @@ -278,6 +326,13 @@ uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count) case st_audio_file_flac: count = drflac_read_pcm_frames_f32(af->flac, count, buffer); break; + case st_audio_file_aiff: + { + uint32_t channels = af->cache.aiff.channels; + unsigned samples = AIFF_ReadSamplesFloat(af->aiff, buffer, (unsigned)(channels * count)); + count = ((int)samples != -1) ? (samples / channels) : 0; + } + break; case st_audio_file_ogg: count = stb_vorbis_get_samples_float_interleaved( af->ogg, af->cache.ogg.channels, buffer, diff --git a/external/st_audiofile/src/st_audiofile.h b/external/st_audiofile/src/st_audiofile.h index fd62c77f..3fbcbfd8 100644 --- a/external/st_audiofile/src/st_audiofile.h +++ b/external/st_audiofile/src/st_audiofile.h @@ -23,6 +23,7 @@ typedef struct st_audio_file st_audio_file; typedef enum st_audio_file_type { st_audio_file_wav, st_audio_file_flac, + st_audio_file_aiff, st_audio_file_ogg, st_audio_file_mp3, st_audio_file_other, diff --git a/external/st_audiofile/src/st_audiofile_common.c b/external/st_audiofile/src/st_audiofile_common.c index d8e2ac6e..c3e14297 100644 --- a/external/st_audiofile/src/st_audiofile_common.c +++ b/external/st_audiofile/src/st_audiofile_common.c @@ -23,6 +23,9 @@ const char* st_type_string(int type) case st_audio_file_flac: type_string = "FLAC"; break; + case st_audio_file_aiff: + type_string = "AIFF"; + break; case st_audio_file_ogg: type_string = "OGG"; break; diff --git a/external/st_audiofile/src/st_audiofile_libs.h b/external/st_audiofile/src/st_audiofile_libs.h index 21727c6b..67aacaba 100644 --- a/external/st_audiofile/src/st_audiofile_libs.h +++ b/external/st_audiofile/src/st_audiofile_libs.h @@ -14,6 +14,7 @@ # undef STB_VORBIS_HEADER_ONLY #endif #include "stb_vorbis.c" +#include "libaiff/libaiff.h" #if defined(_WIN32) #include diff --git a/external/st_audiofile/src/st_audiofile_sndfile.c b/external/st_audiofile/src/st_audiofile_sndfile.c index 480daa34..c1b8fed8 100644 --- a/external/st_audiofile/src/st_audiofile_sndfile.c +++ b/external/st_audiofile/src/st_audiofile_sndfile.c @@ -69,6 +69,9 @@ int st_get_type(st_audio_file* af) case SF_FORMAT_FLAC: type = st_audio_file_flac; break; + case SF_FORMAT_AIFF: + type = st_audio_file_aiff; + break; case SF_FORMAT_OGG: type = st_audio_file_ogg; break; diff --git a/external/st_audiofile/thirdparty/libaiff b/external/st_audiofile/thirdparty/libaiff new file mode 160000 index 00000000..f18eefcd --- /dev/null +++ b/external/st_audiofile/thirdparty/libaiff @@ -0,0 +1 @@ +Subproject commit f18eefcd27108fdfdd0b6620426b404f132e39c4 From 0825f034c2ff37dc29bb5d980947baf8f7dfeb91 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 31 Oct 2020 15:30:13 +0100 Subject: [PATCH 039/668] Support the AIFF instrument --- src/sfizz/FileMetadata.cpp | 202 +++++++++++++++++++++++++++++++++++++ src/sfizz/FileMetadata.h | 10 ++ src/sfizz/FilePool.cpp | 2 +- tests/FileInstrument.cpp | 2 +- 4 files changed, 214 insertions(+), 2 deletions(-) diff --git a/src/sfizz/FileMetadata.cpp b/src/sfizz/FileMetadata.cpp index bb1d3d0c..8c684d37 100644 --- a/src/sfizz/FileMetadata.cpp +++ b/src/sfizz/FileMetadata.cpp @@ -39,6 +39,18 @@ static uint32_t u32be(const uint8_t *bytes) return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; } +#if 0 +static uint16_t u16le(const uint8_t *bytes) +{ + return bytes[0] | (bytes[1] << 8); +} +#endif + +static uint16_t u16be(const uint8_t *bytes) +{ + return (bytes[0] << 8) | bytes[1]; +} + static bool fread_u32le(FILE* stream, uint32_t& value) { uint8_t bytes[4]; @@ -57,14 +69,38 @@ static bool fread_u32be(FILE* stream, uint32_t& value) return true; } +#if 0 +static bool fread_u16le(FILE* stream, uint16_t& value) +{ + uint8_t bytes[2]; + if (fread(bytes, 2, 1, stream) != 1) + return false; + value = u16le(bytes); + return true; +} +#endif + +static bool fread_u16be(FILE* stream, uint16_t& value) +{ + uint8_t bytes[2]; + if (fread(bytes, 2, 1, stream) != 1) + return false; + value = u16be(bytes); + return true; +} + //------------------------------------------------------------------------------ struct FileMetadataReader::Impl { FILE_u stream_; std::vector riffChunks_; + enum class ChunkType { None, Riff, Aiff }; + ChunkType chunkType_ = ChunkType::None; + bool openFlac(); bool openRiff(); + bool openAiff(); bool extractClmWavetable(WavetableInfo &wt); bool extractSurgeWavetable(WavetableInfo &wt); @@ -108,12 +144,21 @@ bool FileMetadataReader::open(const fs::path& path) close(); return false; } + impl_->chunkType_ = Impl::ChunkType::Riff; } else if (count >= 4 && !memcmp(magic, "RIFF", 4)) { if (!impl_->openRiff()) { close(); return false; } + impl_->chunkType_ = Impl::ChunkType::Riff; + } + else if (count >= 4 && !memcmp(magic, "FORM", 4)) { + if (!impl_->openAiff()) { + close(); + return false; + } + impl_->chunkType_ = Impl::ChunkType::Aiff; } return true; @@ -193,6 +238,46 @@ bool FileMetadataReader::Impl::openRiff() return true; } +bool FileMetadataReader::Impl::openAiff() +{ + FILE* stream = stream_.get(); + + rewind(stream); + + char formId[4]; + uint32_t formSize; + if (fread(formId, 4, 1, stream) != 1 || memcmp(formId, "FORM", 4) || + !fread_u32be(stream, formSize)) + { + return false; + } + + char aiffId[4]; + if (fread(aiffId, 4, 1, stream) != 1 || + (memcmp(aiffId, "AIFF", 4) && memcmp(aiffId, "AIFC", 4))) + { + return false; + } + + std::vector& riffChunks = riffChunks_; + + char riffId[4]; + uint32_t riffChunkSize; + while (fread(riffId, 4, 1, stream) == 1 && fread_u32be(stream, riffChunkSize)) { + RiffChunkInfo info; + info.index = riffChunks.size(); + info.fileOffset = ftell(stream); + memcpy(info.id.data(), riffId, 4); + info.length = riffChunkSize; + riffChunks.push_back(info); + + if (fseek(stream, riffChunkSize + (riffChunkSize & 1), SEEK_CUR) != 0) + return false; + } + + return true; +} + size_t FileMetadataReader::riffChunkCount() const { return impl_->riffChunks_.size(); @@ -242,8 +327,22 @@ size_t FileMetadataReader::Impl::readRiffData(size_t index, void* buffer, size_t return fread(buffer, 1, count, stream); } +bool FileMetadataReader::extractInstrument(InstrumentInfo& ins) +{ + if (extractRiffInstrument(ins)) + return true; + + if (extractAiffInstrument(ins)) + return true; + + return false; +} + bool FileMetadataReader::extractRiffInstrument(InstrumentInfo& ins) { + if (impl_->chunkType_ != Impl::ChunkType::Riff) + return false; + const RiffChunkInfo* riff = riffChunkById(RiffChunkId{'s', 'm', 'p', 'l'}); if (!riff) return false; @@ -299,6 +398,109 @@ bool FileMetadataReader::extractRiffInstrument(InstrumentInfo& ins) return true; } +bool FileMetadataReader::extractAiffInstrument(InstrumentInfo& ins) +{ + if (impl_->chunkType_ != Impl::ChunkType::Aiff) + return false; + + const RiffChunkInfo* instChunk = riffChunkById(RiffChunkId{'I', 'N', 'S', 'T'}); + if (!instChunk) + return false; + + const RiffChunkInfo* markChunk = riffChunkById(RiffChunkId{'M', 'A', 'R', 'K'}); + + uint8_t insData[20]; + uint32_t length = readRiffData(instChunk->index, insData, sizeof(insData)); + if (length != 20) + return false; + + // + std::map markers; + if (markChunk) { + FILE* stream = impl_->stream_.get(); + if (fseek(stream, markChunk->fileOffset, SEEK_SET) != 0) + return false; + + uint16_t numMarkers; + if (!fread_u16be(stream, numMarkers)) + return false; + + for (uint32_t i = 0; i < numMarkers; ++i) { + uint16_t id; + uint32_t position; + uint8_t size; + char name[256]; + + if (!fread_u16be(stream, id) || !fread_u32be(stream, position) || fread(&size, 1, 1, stream) != 1 || fread(name, size, 1, stream) != 1) + return false; + name[size] = '\0'; + + if (i + 1 < numMarkers && ((~size) & 1)) { + if (fseek(stream, 1, SEEK_CUR) != 0) + return false; + } + + markers[id] = position; + } + } + + // + ins.basenote = insData[0]; + ins.detune = insData[1]; + ins.key_lo = insData[2]; + ins.key_hi = insData[3]; + ins.velocity_lo = insData[4]; + ins.velocity_hi = insData[5]; + ins.gain = (insData[6] << 8) | insData[7]; + + uint32_t loopCount = 0; + for (uint32_t loopIndex = 0; loopIndex < 2; ++loopIndex) { + const uint32_t loopOffset = 8 + loopIndex * 6; + + int mode; + switch ((insData[loopOffset] << 8) | insData[loopOffset + 1]) { + default: + mode = LoopNone; + break; + case 1: + mode = LoopForward; + break; + case 2: + mode = LoopBackward; + break; + } + + if (mode == LoopNone) + break; + + const uint16_t startId = (insData[loopOffset + 2] << 8) | insData[loopOffset + 3]; + const uint16_t endId = (insData[loopOffset + 4] << 8) | insData[loopOffset + 5]; + + // + uint32_t startPos = 0; + uint32_t endPos = 0; + + auto startIt = markers.find(startId); + auto endIt = markers.find(endId); + if (startIt != markers.end()) + startPos = startIt->second; + if (endIt != markers.end()) + endPos = endIt->second; + + // + ins.loops[loopIndex].mode = mode; + ins.loops[loopIndex].start = startPos; + ins.loops[loopIndex].end = endPos; + ins.loops[loopIndex].count = 0; + + ++loopCount; + } + + ins.loop_count = loopCount; + + return true; +} + bool FileMetadataReader::extractWavetableInfo(WavetableInfo& wt) { if (impl_->extractClmWavetable(wt)) diff --git a/src/sfizz/FileMetadata.h b/src/sfizz/FileMetadata.h index 74c6d9ad..b4094381 100644 --- a/src/sfizz/FileMetadata.h +++ b/src/sfizz/FileMetadata.h @@ -112,11 +112,21 @@ public: */ size_t readRiffData(size_t index, void* buffer, size_t count); + /** + * @brief Extract the instrument data and convert it to sndfile instrument + */ + bool extractInstrument(InstrumentInfo& ins); + /** * @brief Extract the RIFF 'smpl' data and convert it to sndfile instrument */ bool extractRiffInstrument(InstrumentInfo& ins); + /** + * @brief Extract the AIFF 'INST' data and convert it to sndfile instrument + */ + bool extractAiffInstrument(InstrumentInfo& ins); + /** * @brief Extract the wavetable information from various relevant RIFF chunks */ diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 5bea534c..6b39bbf7 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -243,7 +243,7 @@ absl::optional sfz::FilePool::getFileInformation(const Fil if (!haveInstrumentInfo) { // if no instrument, then try extracting from embedded RIFF chunks (flac) if (mdReaderOpened) - haveInstrumentInfo = mdReader.extractRiffInstrument(instrumentInfo); + haveInstrumentInfo = mdReader.extractInstrument(instrumentInfo); } if (mdReaderOpened) { diff --git a/tests/FileInstrument.cpp b/tests/FileInstrument.cpp index e759f481..0d553ac2 100644 --- a/tests/FileInstrument.cpp +++ b/tests/FileInstrument.cpp @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) return 1; } sfz::InstrumentInfo ins {}; - if (!reader.extractRiffInstrument(ins)) { + if (!reader.extractInstrument(ins)) { fprintf(stderr, "Cannot get instrument\n"); return 1; } From 03fb748fc1f7342b384dd7a0029ab87fc75493a2 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 31 Oct 2020 16:04:39 +0100 Subject: [PATCH 040/668] Update libaiff for PCM->float speedup --- external/st_audiofile/thirdparty/libaiff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/st_audiofile/thirdparty/libaiff b/external/st_audiofile/thirdparty/libaiff index f18eefcd..015f884a 160000 --- a/external/st_audiofile/thirdparty/libaiff +++ b/external/st_audiofile/thirdparty/libaiff @@ -1 +1 @@ -Subproject commit f18eefcd27108fdfdd0b6620426b404f132e39c4 +Subproject commit 015f884a0458240a9b5f1f0d945a6084243def46 From b40f93afba3aeeb9b4feb738de78f3b6baf2f427 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 31 Oct 2020 16:12:02 +0100 Subject: [PATCH 041/668] Skip building audiofile libs if using sndfile --- external/st_audiofile/src/st_audiofile_libs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/external/st_audiofile/src/st_audiofile_libs.c b/external/st_audiofile/src/st_audiofile_libs.c index 0bbcccca..635c19d4 100644 --- a/external/st_audiofile/src/st_audiofile_libs.c +++ b/external/st_audiofile/src/st_audiofile_libs.c @@ -4,6 +4,7 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz +#if !defined(ST_AUDIO_FILE_USE_SNDFILE) #define DR_WAV_IMPLEMENTATION #define DR_FLAC_IMPLEMENTATION #define DR_MP3_IMPLEMENTATION @@ -27,3 +28,5 @@ stb_vorbis* stb_vorbis_open_filename_w(const wchar_t* filename, int* error, cons return NULL; } #endif + +#endif // !defined(ST_AUDIO_FILE_USE_SNDFILE) From b39fa44c98cb738d346d5a6bb32d52ee20ebfdae Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 31 Oct 2020 16:15:35 +0100 Subject: [PATCH 042/668] Add libaiff to makefiles [ci skip] --- common.mk | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/common.mk b/common.mk index e7ada2c1..27acfbc2 100644 --- a/common.mk +++ b/common.mk @@ -156,6 +156,17 @@ SFIZZ_CXX_FLAGS += $(SFIZZ_SNDFILE_CXX_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1 SFIZZ_LINK_FLAGS += $(SFIZZ_SNDFILE_LINK_FLAGS) endif +# libaiff dependency + +ifneq ($(SFIZZ_USE_SNDFILE),1) +SFIZZ_SOURCES += \ + $(SFIZZ_DIR)/external/st_audiofile/thirdparty/libaiff/libaiff.all.c +SFIZZ_C_FLAGS += \ + -I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/libaiff +SFIZZ_CXX_FLAGS += \ + -I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/libaiff +endif + ### Abseil dependency SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/external/abseil-cpp From adc7bb9a8afd034c261c1a092beaf7adb0f991f9 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 20:52:38 +0100 Subject: [PATCH 043/668] enable tests on appveyor --- .appveyor.yml | 4 +++- scripts/appveyor/before_build.cmd | 2 +- scripts/appveyor/before_build.sh | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 91693aa9..ff607f84 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -33,7 +33,9 @@ for: before_build: - chmod +x ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/before_build.sh - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/before_build.sh - build_script: cd build && make -j2 + build_script: + - cd build && make -j2 + - tests/sfizz_tests after_build: - chmod +x ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/after_build.sh - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/after_build.sh diff --git a/scripts/appveyor/before_build.cmd b/scripts/appveyor/before_build.cmd index 6b7fa13e..a9fa0f65 100644 --- a/scripts/appveyor/before_build.cmd +++ b/scripts/appveyor/before_build.cmd @@ -8,7 +8,7 @@ if %platform%==x64 set RELEASE_ARCH=x64 cmake .. -G"Visual Studio 16 2019" -A"%RELEASE_ARCH%"^ -DSFIZZ_JACK=OFF^ -DSFIZZ_BENCHMARKS=OFF^ - -DSFIZZ_TESTS=OFF^ + -DSFIZZ_TESTS=ON^ -DSFIZZ_LV2=ON^ -DSFIZZ_VST=ON^ -DCMAKE_BUILD_TYPE=Release^ diff --git a/scripts/appveyor/before_build.sh b/scripts/appveyor/before_build.sh index bd242fbb..d7af42be 100644 --- a/scripts/appveyor/before_build.sh +++ b/scripts/appveyor/before_build.sh @@ -6,7 +6,7 @@ mkdir -p build/${INSTALL_DIR} && cd build cmake -DCMAKE_BUILD_TYPE=Release \ -DSFIZZ_VST=ON \ -DSFIZZ_AU=ON \ - -DSFIZZ_TESTS=OFF \ + -DSFIZZ_TESTS=ON \ -DCMAKE_CXX_STANDARD=14 \ -DLV2PLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/LV2 \ -DVSTPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/VST3 \ From 7bde1e32ec9ecce3072757751fcf3597bfd38ae6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 04:34:09 +0100 Subject: [PATCH 044/668] Process WAV chunk padding correctly --- src/sfizz/FileMetadata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/FileMetadata.cpp b/src/sfizz/FileMetadata.cpp index 8c684d37..65ba9677 100644 --- a/src/sfizz/FileMetadata.cpp +++ b/src/sfizz/FileMetadata.cpp @@ -231,7 +231,7 @@ bool FileMetadataReader::Impl::openRiff() info.length = riffChunkSize; riffChunks.push_back(info); - if (fseek(stream, riffChunkSize, SEEK_CUR) != 0) + if (fseek(stream, riffChunkSize + (riffChunkSize & 1), SEEK_CUR) != 0) return false; } From 89441894a8d74bb24b0df02d7b93298de21a0e1a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 07:18:11 +0100 Subject: [PATCH 045/668] Update libaiff for a compressed file speedup --- external/st_audiofile/thirdparty/libaiff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/st_audiofile/thirdparty/libaiff b/external/st_audiofile/thirdparty/libaiff index 015f884a..834cb569 160000 --- a/external/st_audiofile/thirdparty/libaiff +++ b/external/st_audiofile/thirdparty/libaiff @@ -1 +1 @@ -Subproject commit 015f884a0458240a9b5f1f0d945a6084243def46 +Subproject commit 834cb569a8e01c5c88162a1f1c1e1ab6dd242e2f From c0413720a605d68761220c38b648dc258cd77055 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 07:57:57 +0100 Subject: [PATCH 046/668] Accelerate the AIFF reader significantly --- external/st_audiofile/thirdparty/libaiff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/st_audiofile/thirdparty/libaiff b/external/st_audiofile/thirdparty/libaiff index 834cb569..0597c4a4 160000 --- a/external/st_audiofile/thirdparty/libaiff +++ b/external/st_audiofile/thirdparty/libaiff @@ -1 +1 @@ -Subproject commit 834cb569a8e01c5c88162a1f1c1e1ab6dd242e2f +Subproject commit 0597c4a47d6a414293b0e2369bef89b18d875858 From b646cfc8a174bd931e88f89f26a686a03ca35d7b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 08:08:50 +0100 Subject: [PATCH 047/668] Accelerate libaiff byte-swapping --- external/st_audiofile/thirdparty/libaiff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/st_audiofile/thirdparty/libaiff b/external/st_audiofile/thirdparty/libaiff index 0597c4a4..73cfb8b6 160000 --- a/external/st_audiofile/thirdparty/libaiff +++ b/external/st_audiofile/thirdparty/libaiff @@ -1 +1 @@ -Subproject commit 0597c4a47d6a414293b0e2369bef89b18d875858 +Subproject commit 73cfb8b647da93bed871a4dd7d0dca80d78a160a From 3214211a06571b98fc08adb2df0231db9363af37 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Fri, 30 Oct 2020 11:05:36 +0100 Subject: [PATCH 048/668] Refactor of Synth and Voice into a pimpl pattern --- src/sfizz/Synth.cpp | 1555 +++++++++++------ src/sfizz/Synth.h | 435 +---- src/sfizz/Voice.cpp | 1202 +++++++++---- src/sfizz/Voice.h | 276 +-- src/sfizz/VoiceList.h | 68 + .../modulations/sources/ADSREnvelope.cpp | 19 +- src/sfizz/modulations/sources/ADSREnvelope.h | 7 +- .../modulations/sources/FlexEnvelope.cpp | 13 +- src/sfizz/modulations/sources/FlexEnvelope.h | 5 +- src/sfizz/modulations/sources/LFO.cpp | 10 +- src/sfizz/modulations/sources/LFO.h | 6 +- tests/PolyphonyT.cpp | 4 + tests/SynthT.cpp | 13 +- 13 files changed, 1955 insertions(+), 1658 deletions(-) create mode 100644 src/sfizz/VoiceList.h diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 271e1e3e..43fac9bb 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -4,120 +4,469 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "Synth.h" -#include "Config.h" -#include "Debug.h" -#include "Macros.h" -#include "MidiState.h" -#include "TriggerEvent.h" -#include "ModifierHelpers.h" -#include "ScopedFTZ.h" -#include "StringViewHelpers.h" -#include "modulations/ModMatrix.h" -#include "modulations/ModKey.h" -#include "modulations/ModId.h" -#include "modulations/sources/Controller.h" -#include "modulations/sources/LFO.h" -#include "modulations/sources/FlexEnvelope.h" -#include "modulations/sources/ADSREnvelope.h" -#include "utility/XmlHelpers.h" -#include "pugixml.hpp" #include "absl/algorithm/container.h" #include "absl/memory/memory.h" #include "absl/strings/str_replace.h" +#include "Config.h" +#include "Debug.h" +#include "Effects.h" +#include "Macros.h" +#include "ModifierHelpers.h" +#include "modulations/ModId.h" +#include "modulations/ModKey.h" +#include "modulations/ModMatrix.h" +#include "modulations/sources/ADSREnvelope.h" +#include "modulations/sources/Controller.h" +#include "modulations/sources/FlexEnvelope.h" +#include "modulations/sources/LFO.h" +#include "PolyphonyGroup.h" +#include "pugixml.hpp" +#include "RegionSet.h" +#include "Resources.h" +#include "ScopedFTZ.h" #include "SisterVoiceRing.h" +#include "StringViewHelpers.h" +#include "Synth.h" +#include "TriggerEvent.h" +#include "utility/SpinMutex.h" +#include "utility/XmlHelpers.h" +#include "VoiceList.h" +#include "VoiceStealing.h" +#include +#include #include #include #include +#include #include -sfz::Synth::Synth() - : Synth(config::numVoices) +namespace sfz { + +struct Synth::Impl : public Voice::StateListener, public Parser::Listener { + Impl(); + ~Impl(); + + /** + * @brief The voice callback which is called during a change of state. + */ + void onVoiceStateChanged(NumericId idNumber, Voice::State state) final; + + /** + * @brief The parser callback; this is called by the parent object each time + * a new region, group, master, global, curve or control set of opcodes + * appears in the parser + * + * @param header the header for the set of opcodes + * @param members the opcode members + */ + void onParseFullBlock(const std::string& header, const std::vector& members) final; + + /** + * @brief The parser callback when an error occurs. + */ + void onParseError(const SourceRange& range, const std::string& message) final; + + /** + * @brief The parser callback when a warning occurs. + */ + void onParseWarning(const SourceRange& range, const std::string& message) final; + + + /** + * @brief change the group maximum polyphony + * + * @param groupIdx the group index + * @param polyphone the max polyphony + */ + void setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept; + + /** + * @brief Reset all CCs; to be used on CC 121 + * + * @param delay the delay for the controller reset + * + */ + void resetAllControllers(int delay) noexcept; + + /** + * @brief Remove all regions, resets all voices and clears everything + * to bring back the synth in its original state. + * + * The callback mutex should be taken to call this function. + */ + void clear(); + + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleGlobalOpcodes(const std::vector& members); + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleMasterOpcodes(const std::vector& members); + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleGroupOpcodes(const std::vector& members, const std::vector& masterMembers); + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleControlOpcodes(const std::vector& members); + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleEffectOpcodes(const std::vector& members); + /** + * @brief Helper function to merge all the currently active opcodes + * as set by the successive callbacks and create a new region to store + * in the synth. + * + * @param regionOpcodes the opcodes that are specific to the region + */ + void buildRegion(const std::vector& regionOpcodes); + /** + * @brief Resets and possibly changes the number of voices (polyphony) in + * the synth. + * + * @param numVoices + */ + void resetVoices(int numVoices); + /** + * @brief Make the stored settings take effect in all the voices + */ + void applySettingsPerVoice(); + + /** + * @brief Establish all connections of the modulation matrix. + */ + void setupModMatrix(); + + /** + * @brief Get the modification time of all included sfz files + * + * @return fs::file_time_type + */ + fs::file_time_type checkModificationTime(); + + /** + * @brief Check all regions and start voices for note on events + * + * @param delay + * @param noteNumber + * @param velocity + */ + void noteOnDispatch(int delay, int noteNumber, float velocity) noexcept; + + /** + * @brief Check all regions and start voices for note off events + * + * @param delay + * @param noteNumber + * @param velocity + */ + void noteOffDispatch(int delay, int noteNumber, float velocity) noexcept; + + /** + * @brief Check all regions and start voices for cc events + * + * @param delay + * @param ccNumber + * @param value + */ + void ccDispatch(int delay, int ccNumber, float value) noexcept; + + /** + * @brief Find a voice that is not currently playing + * + * @return Voice* + */ + + Voice* findFreeVoice() noexcept; + + /** + * @brief Check the region polyphony, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkRegionPolyphony(const Region* region, int delay) noexcept; + + /** + * @brief Check the note polyphony, releasing voices if necessary + * + * @param region + * @param delay + * @param triggerEvent + */ + void checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept; + + /** + * @brief Check the group polyphony, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkGroupPolyphony(const Region* region, int delay) noexcept; + + /** + * @brief Check the region set polyphony at all levels, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkSetPolyphony(const Region* region, int delay) noexcept; + + /** + * @brief Check the engine polyphony, fast releasing voices if necessary + * + * @param delay + */ + void checkEnginePolyphony(int delay) noexcept; + + /** + * @brief Start a voice for a specific region. + * This will do the needed polyphony checks and voice stealing. + * + * @param region + * @param delay + * @param triggerEvent + * @param ring + */ + void startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept; + + /** + * @brief Start all delayed release voices of the region if necessary + * + * @param region + * @param delay + * @param ring + */ + void startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept; + + /** + * @brief Check if a playing voice matches the release region + * + * @param releaseRegion + * @return true + * @return false + */ + bool playingAttackVoice(const Region* releaseRegion) noexcept; + + /** + * @brief Finalize SFZ loading, following a successful execution of the + * parsing step. + */ + void finalizeSfzLoad(); + + template + static void updateUsedCCsFromCCMap(std::bitset& usedCCs, const CCMap map) noexcept + { + for (auto& mod : map) + usedCCs[mod.cc] = true; + } + + static void updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); + static void updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); + + int numGroups_ { 0 }; + int numMasters_ { 0 }; + + // Opcode memory; these are used to build regions, as a new region + // will integrate opcodes from the group, master and global block + std::vector globalOpcodes_; + std::vector masterOpcodes_; + std::vector groupOpcodes_; + + // Names for the CC and notes as set by label_cc and label_key + std::vector ccLabels_; + std::vector keyLabels_; + std::vector keyswitchLabels_; + + // Set as sw_default if present in the file + absl::optional currentSwitch_; + std::vector unknownOpcodes_; + using RegionViewVector = std::vector; + using VoiceViewVector = std::vector; + using RegionPtr = std::unique_ptr; + using RegionSetPtr = std::unique_ptr; + std::vector regions_; + VoiceList voiceList_; + + // These are more general "groups" than sfz and encapsulates the full hierarchy + RegionSet* currentSet_ { nullptr }; + std::vector sets_; + // This region set holds the engine set of voices, which tries to respect the required + // engine polyphony + RegionSetPtr engineSet_; + + // These are the `group=` groups where you can off voices + std::vector polyphonyGroups_; + + // Views to speed up iteration over the regions and voices when events + // occur in the audio callback + VoiceViewVector tempPolyphonyArray_; + VoiceViewVector voiceViewArray_; + VoiceStealing stealer_; + + std::array lastKeyswitchLists_; + std::array downKeyswitchLists_; + std::array upKeyswitchLists_; + RegionViewVector previousKeyswitchLists_; + std::array noteActivationLists_; + std::array ccActivationLists_; + + // Effect factory and buses + EffectFactory effectFactory_; + typedef std::unique_ptr EffectBusPtr; + std::vector effectBuses_; // 0 is "main", 1-N are "fx1"-"fxN" + + int samplesPerBlock_ { config::defaultSamplesPerBlock }; + float sampleRate_ { config::defaultSampleRate }; + float volume_ { Default::globalVolume }; + int numRequiredVoices_ { config::numVoices }; + int numActualVoices_ { static_cast(config::numVoices * config::overflowVoiceMultiplier) }; + int activeVoices_ { 0 }; + Oversampling oversamplingFactor_ { config::defaultOversamplingFactor }; + + // Distribution used to generate random value for the *rand opcodes + std::uniform_real_distribution randNoteDistribution_ { 0, 1 }; + + SpinMutex callbackGuard_; + + // Singletons passed as references to the voices + Resources resources_; + + // Control opcodes + std::string defaultPath_ { "" }; + int noteOffset_ { 0 }; + int octaveOffset_ { 0 }; + + // Modulation source generators + std::unique_ptr genController_; + std::unique_ptr genLFO_; + std::unique_ptr genFlexEnvelope_; + std::unique_ptr genADSREnvelope_; + + // Settings per voice + struct SettingsPerVoice { + size_t maxFilters { 0 }; + size_t maxEQs { 0 }; + size_t maxLFOs { 0 }; + size_t maxFlexEGs { 0 }; + bool havePitchEG { false }; + bool haveFilterEG { false }; + }; + SettingsPerVoice settingsPerVoice_; + + Duration dispatchDuration_ { 0 }; + + std::chrono::time_point lastGarbageCollection_; + + Parser parser_; + fs::file_time_type modificationTime_ { }; +}; + +Synth::Synth() +: impl_(new Impl) { } -sfz::Synth::Synth(int numVoices) +// Need to define the dtor after Impl has been defined +Synth::~Synth() +{ + +} + +Synth::Impl::Impl() { initializeSIMDDispatchers(); - const std::lock_guard disableCallback { callbackGuard }; - engineSet = absl::make_unique(nullptr, OpcodeScope::kOpcodeScopeGeneric); - parser.setListener(this); - effectFactory.registerStandardEffectTypes(); - effectBuses.reserve(5); // sufficient room for main and fx1-4 - resetVoices(numVoices); + const std::lock_guard disableCallback { callbackGuard_ }; + engineSet_ = absl::make_unique(nullptr, OpcodeScope::kOpcodeScopeGeneric); + parser_.setListener(this); + effectFactory_.registerStandardEffectTypes(); + effectBuses_.reserve(5); // sufficient room for main and fx1-4 + resetVoices(config::numVoices); // modulation sources - genController.reset(new ControllerSource(resources)); - genLFO.reset(new LFOSource(*this)); - genFlexEnvelope.reset(new FlexEnvelopeSource(*this)); - genADSREnvelope.reset(new ADSREnvelopeSource(*this)); + genController_.reset(new ControllerSource(resources_)); + genLFO_.reset(new LFOSource(voiceList_)); + genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceList_)); + genADSREnvelope_.reset(new ADSREnvelopeSource(voiceList_, resources_.midiState)); } -sfz::Synth::~Synth() +Synth::Impl::~Impl() { - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { callbackGuard_ }; - for (auto& voice : voices) - voice->reset(); - - resources.filePool.emptyFileLoadingQueues(); + voiceList_.reset(); + resources_.filePool.emptyFileLoadingQueues(); } -void sfz::Synth::onVoiceStateChanged(NumericId id, Voice::State state) +void Synth::Impl::onVoiceStateChanged(NumericId id, Voice::State state) { (void)id; (void)state; if (state == Voice::State::idle) { - auto voice = getVoiceById(id); + auto voice = voiceList_.getVoiceById(id); RegionSet::removeVoiceFromHierarchy(voice->getRegion(), voice); - engineSet->removeVoice(voice); - polyphonyGroups[voice->getRegion()->group].removeVoice(voice); + engineSet_->removeVoice(voice); + polyphonyGroups_[voice->getRegion()->group].removeVoice(voice); } } -void sfz::Synth::onParseFullBlock(const std::string& header, const std::vector& members) +void Synth::Impl::onParseFullBlock(const std::string& header, const std::vector& members) { const auto newRegionSet = [&](OpcodeScope level) { - auto parent = currentSet; + auto parent = currentSet_; while (parent && parent->getLevel() >= level) parent = parent->getParent(); - sets.emplace_back(new RegionSet(parent, level)); - currentSet = sets.back().get(); + sets_.emplace_back(new RegionSet(parent, level)); + currentSet_ = sets_.back().get(); }; switch (hash(header)) { case hash("global"): - globalOpcodes = members; + globalOpcodes_ = members; newRegionSet(OpcodeScope::kOpcodeScopeGlobal); - groupOpcodes.clear(); - masterOpcodes.clear(); + groupOpcodes_.clear(); + masterOpcodes_.clear(); handleGlobalOpcodes(members); break; case hash("control"): - defaultPath = ""; // Always reset on a new control header + defaultPath_ = ""; // Always reset on a new control header handleControlOpcodes(members); break; case hash("master"): - masterOpcodes = members; + masterOpcodes_ = members; newRegionSet(OpcodeScope::kOpcodeScopeMaster); - groupOpcodes.clear(); + groupOpcodes_.clear(); handleMasterOpcodes(members); - numMasters++; + numMasters_++; break; case hash("group"): - groupOpcodes = members; + groupOpcodes_ = members; newRegionSet(OpcodeScope::kOpcodeScopeGroup); - handleGroupOpcodes(members, masterOpcodes); - numGroups++; + handleGroupOpcodes(members, masterOpcodes_); + numGroups_++; break; case hash("region"): buildRegion(members); break; case hash("curve"): - resources.curves.addCurveFromHeader(members); + resources_.curves.addCurveFromHeader(members); break; case hash("effect"): handleEffectOpcodes(members); @@ -127,39 +476,39 @@ void sfz::Synth::onParseFullBlock(const std::string& header, const std::vectorlexically_relative(parser.originalDirectory()); + const auto relativePath = range.start.filePath->lexically_relative(parser_.originalDirectory()); std::cerr << "Parse error in " << relativePath << " at line " << range.start.lineNumber + 1 << ": " << message << '\n'; } -void sfz::Synth::onParseWarning(const SourceRange& range, const std::string& message) +void Synth::Impl::onParseWarning(const SourceRange& range, const std::string& message) { - const auto relativePath = range.start.filePath->lexically_relative(parser.originalDirectory()); + const auto relativePath = range.start.filePath->lexically_relative(parser_.originalDirectory()); std::cerr << "Parse warning in " << relativePath << " at line " << range.start.lineNumber + 1 << ": " << message << '\n'; } -void sfz::Synth::buildRegion(const std::vector& regionOpcodes) +void Synth::Impl::buildRegion(const std::vector& regionOpcodes) { - int regionNumber = static_cast(regions.size()); - auto lastRegion = absl::make_unique(regionNumber, resources.midiState, defaultPath); + int regionNumber = static_cast(regions_.size()); + auto lastRegion = absl::make_unique(regionNumber, resources_.midiState, defaultPath_); // auto parseOpcodes = [&](const std::vector& opcodes) { for (auto& opcode : opcodes) { - const auto unknown = absl::c_find_if(unknownOpcodes, [&](absl::string_view sv) { return sv.compare(opcode.opcode) == 0; }); - if (unknown != unknownOpcodes.end()) { + const auto unknown = absl::c_find_if(unknownOpcodes_, [&](absl::string_view sv) { return sv.compare(opcode.opcode) == 0; }); + if (unknown != unknownOpcodes_.end()) { continue; } if (!lastRegion->parseOpcode(opcode)) - unknownOpcodes.emplace_back(opcode.opcode); + unknownOpcodes_.emplace_back(opcode.opcode); } }; - parseOpcodes(globalOpcodes); - parseOpcodes(masterOpcodes); - parseOpcodes(groupOpcodes); + parseOpcodes(globalOpcodes_); + parseOpcodes(masterOpcodes_); + parseOpcodes(groupOpcodes_); parseOpcodes(regionOpcodes); // Create the amplitude envelope @@ -172,137 +521,135 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) ModKey::createNXYZ(ModId::Envelope, lastRegion->id, *lastRegion->flexAmpEG), ModKey::createNXYZ(ModId::MasterAmplitude, lastRegion->id)).sourceDepth = 1.0f; - if (octaveOffset != 0 || noteOffset != 0) - lastRegion->offsetAllKeys(octaveOffset * 12 + noteOffset); + if (octaveOffset_ != 0 || noteOffset_ != 0) + lastRegion->offsetAllKeys(octaveOffset_ * 12 + noteOffset_); if (lastRegion->lastKeyswitch) - lastKeyswitchLists[*lastRegion->lastKeyswitch].push_back(lastRegion.get()); + lastKeyswitchLists_[*lastRegion->lastKeyswitch].push_back(lastRegion.get()); if (lastRegion->lastKeyswitchRange) { auto& range = *lastRegion->lastKeyswitchRange; for (uint8_t note = range.getStart(), end = range.getEnd(); note <= end; note++) - lastKeyswitchLists[note].push_back(lastRegion.get()); + lastKeyswitchLists_[note].push_back(lastRegion.get()); } if (lastRegion->upKeyswitch) - upKeyswitchLists[*lastRegion->upKeyswitch].push_back(lastRegion.get()); + upKeyswitchLists_[*lastRegion->upKeyswitch].push_back(lastRegion.get()); if (lastRegion->downKeyswitch) - downKeyswitchLists[*lastRegion->downKeyswitch].push_back(lastRegion.get()); + downKeyswitchLists_[*lastRegion->downKeyswitch].push_back(lastRegion.get()); if (lastRegion->previousKeyswitch) - previousKeyswitchLists.push_back(lastRegion.get()); + previousKeyswitchLists_.push_back(lastRegion.get()); if (lastRegion->defaultSwitch) - currentSwitch = *lastRegion->defaultSwitch; + currentSwitch_ = *lastRegion->defaultSwitch; // There was a combination of group= and polyphony= on a region, so set the group polyphony if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) setGroupPolyphony(lastRegion->group, lastRegion->polyphony); - if (currentSet != nullptr) { - 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()); - regions.push_back(std::move(lastRegion)); + regions_.push_back(std::move(lastRegion)); } -void sfz::Synth::clear() +void Synth::Impl::clear() { // Clear the background queues before removing everyone - resources.filePool.waitForBackgroundLoading(); + resources_.filePool.waitForBackgroundLoading(); - for (auto& voice : voices) - voice->reset(); - for (auto& list : lastKeyswitchLists) + voiceList_.reset(); + for (auto& list : lastKeyswitchLists_) list.clear(); - for (auto& list : downKeyswitchLists) + for (auto& list : downKeyswitchLists_) list.clear(); - for (auto& list : upKeyswitchLists) + for (auto& list : upKeyswitchLists_) list.clear(); - for (auto& list : noteActivationLists) + for (auto& list : noteActivationLists_) list.clear(); - for (auto& list : ccActivationLists) + for (auto& list : ccActivationLists_) list.clear(); - previousKeyswitchLists.clear(); + previousKeyswitchLists_.clear(); - currentSet = nullptr; - sets.clear(); - regions.clear(); - effectBuses.clear(); - effectBuses.emplace_back(new EffectBus); - effectBuses[0]->setGainToMain(1.0); - effectBuses[0]->setSamplesPerBlock(samplesPerBlock); - effectBuses[0]->setSampleRate(sampleRate); - effectBuses[0]->clearInputs(samplesPerBlock); - resources.clear(); - numGroups = 0; - numMasters = 0; - currentSwitch = absl::nullopt; - defaultPath = ""; - resources.midiState.reset(); - resources.filePool.clear(); - resources.filePool.setRamLoading(config::loadInRam); - stealer.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::Oldest); - ccLabels.clear(); - keyLabels.clear(); - keyswitchLabels.clear(); - globalOpcodes.clear(); - masterOpcodes.clear(); - groupOpcodes.clear(); - unknownOpcodes.clear(); - polyphonyGroups.clear(); - polyphonyGroups.emplace_back(); - polyphonyGroups.back().setPolyphonyLimit(config::maxVoices); - modificationTime = fs::file_time_type::min(); + currentSet_ = nullptr; + sets_.clear(); + regions_.clear(); + effectBuses_.clear(); + effectBuses_.emplace_back(new EffectBus); + effectBuses_[0]->setGainToMain(1.0); + effectBuses_[0]->setSamplesPerBlock(samplesPerBlock_); + effectBuses_[0]->setSampleRate(sampleRate_); + effectBuses_[0]->clearInputs(samplesPerBlock_); + resources_.clear(); + numGroups_ = 0; + numMasters_ = 0; + currentSwitch_ = absl::nullopt; + defaultPath_ = ""; + resources_.midiState.reset(); + resources_.filePool.clear(); + resources_.filePool.setRamLoading(config::loadInRam); + stealer_.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::Oldest); + ccLabels_.clear(); + keyLabels_.clear(); + keyswitchLabels_.clear(); + globalOpcodes_.clear(); + masterOpcodes_.clear(); + groupOpcodes_.clear(); + unknownOpcodes_.clear(); + polyphonyGroups_.clear(); + polyphonyGroups_.emplace_back(); + polyphonyGroups_.back().setPolyphonyLimit(config::maxVoices); + modificationTime_ = fs::file_time_type::min(); // set default controllers - fill(absl::MakeSpan(ccInitialValues), 0.0f); - initCc(7, 100); // volume - initHdcc(10, 0.5f); // pan - initHdcc(11, 1.0f); // expression + resources_.midiState.ccEvent(0, 7, normalizeCC(100)); // volume + resources_.midiState.ccEvent(0, 10, 0.5f); // pan + resources_.midiState.ccEvent(0, 11, 1.0f); // expression // set default controller labels - insertPairUniquely(ccLabels, 7, "Volume"); - insertPairUniquely(ccLabels, 10, "Pan"); - insertPairUniquely(ccLabels, 11, "Expression"); + insertPairUniquely(ccLabels_, 7, "Volume"); + insertPairUniquely(ccLabels_, 10, "Pan"); + insertPairUniquely(ccLabels_, 11, "Expression"); } -void sfz::Synth::handleMasterOpcodes(const std::vector& members) +void Synth::Impl::handleMasterOpcodes(const std::vector& members) { for (auto& rawMember : members) { const Opcode member = rawMember.cleanUp(kOpcodeScopeMaster); switch (member.lettersOnlyHash) { case hash("polyphony"): - ASSERT(currentSet != nullptr); + ASSERT(currentSet_ != nullptr); if (auto value = readOpcode(member.value, Default::polyphonyRange)) - currentSet->setPolyphonyLimit(*value); + currentSet_->setPolyphonyLimit(*value); break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch, Default::keyRange); + setValueFromOpcode(member, currentSwitch_, Default::keyRange); break; } } } -void sfz::Synth::handleGlobalOpcodes(const std::vector& members) +void Synth::Impl::handleGlobalOpcodes(const std::vector& members) { for (auto& rawMember : members) { const Opcode member = rawMember.cleanUp(kOpcodeScopeGlobal); switch (member.lettersOnlyHash) { case hash("polyphony"): - ASSERT(currentSet != nullptr); + ASSERT(currentSet_ != nullptr); if (auto value = readOpcode(member.value, Default::polyphonyRange)) - currentSet->setPolyphonyLimit(*value); + currentSet_->setPolyphonyLimit(*value); break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch, Default::keyRange); + setValueFromOpcode(member, currentSwitch_, Default::keyRange); break; case hash("volume"): // FIXME : Probably best not to mess with this and let the host control the volume @@ -312,7 +659,7 @@ void sfz::Synth::handleGlobalOpcodes(const std::vector& members) } } -void sfz::Synth::handleGroupOpcodes(const std::vector& members, const std::vector& masterMembers) +void Synth::Impl::handleGroupOpcodes(const std::vector& members, const std::vector& masterMembers) { absl::optional groupIdx; absl::optional maxPolyphony; @@ -328,7 +675,7 @@ void sfz::Synth::handleGroupOpcodes(const std::vector& members, const st setValueFromOpcode(member, maxPolyphony, Default::polyphonyRange); break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch, Default::keyRange); + setValueFromOpcode(member, currentSwitch_, Default::keyRange); break; } }; @@ -342,14 +689,14 @@ void sfz::Synth::handleGroupOpcodes(const std::vector& members, const st if (groupIdx && maxPolyphony) { setGroupPolyphony(*groupIdx, *maxPolyphony); } else if (maxPolyphony) { - ASSERT(currentSet != nullptr); - currentSet->setPolyphonyLimit(*maxPolyphony); - } else if (groupIdx && *groupIdx > polyphonyGroups.size()) { + ASSERT(currentSet_ != nullptr); + currentSet_->setPolyphonyLimit(*maxPolyphony); + } else if (groupIdx && *groupIdx > polyphonyGroups_.size()) { setGroupPolyphony(*groupIdx, config::maxVoices); } } -void sfz::Synth::handleControlOpcodes(const std::vector& members) +void Synth::Impl::handleControlOpcodes(const std::vector& members) { for (auto& rawMember : members) { const Opcode member = rawMember.cleanUp(kOpcodeScopeControl); @@ -359,63 +706,65 @@ void sfz::Synth::handleControlOpcodes(const std::vector& members) if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { const auto ccValue = readOpcode(member.value, Default::midi7Range); if (ccValue) - initCc(member.parameters.back(), *ccValue); + resources_.midiState.ccEvent( + 0, member.parameters.back(), normalizeCC(*ccValue)); } break; case hash("set_hdcc&"): if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { const auto ccValue = readOpcode(member.value, Default::normalizedRange); if (ccValue) - initHdcc(member.parameters.back(), *ccValue); + resources_.midiState.ccEvent( + 0, member.parameters.back(), *ccValue); } break; case hash("label_cc&"): if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) - insertPairUniquely(ccLabels, member.parameters.back(), std::string(member.value)); + insertPairUniquely(ccLabels_, member.parameters.back(), std::string(member.value)); break; case hash("label_key&"): if (member.parameters.back() <= Default::keyRange.getEnd()) { const auto noteNumber = static_cast(member.parameters.back()); - insertPairUniquely(keyLabels, noteNumber, std::string(member.value)); + insertPairUniquely(keyLabels_, noteNumber, std::string(member.value)); } break; case hash("default_path"): - defaultPath = absl::StrReplaceAll(trim(member.value), { { "\\", "/" } }); - DBG("Changing default sample path to " << defaultPath); + defaultPath_ = absl::StrReplaceAll(trim(member.value), { { "\\", "/" } }); + DBG("Changing default sample path to " << defaultPath_); break; case hash("note_offset"): - setValueFromOpcode(member, noteOffset, Default::noteOffsetRange); + setValueFromOpcode(member, noteOffset_, Default::noteOffsetRange); break; case hash("octave_offset"): - setValueFromOpcode(member, octaveOffset, Default::octaveOffsetRange); + setValueFromOpcode(member, octaveOffset_, Default::octaveOffsetRange); break; case hash("hint_ram_based"): if (member.value == "1") - resources.filePool.setRamLoading(true); + resources_.filePool.setRamLoading(true); else if (member.value == "0") - resources.filePool.setRamLoading(false); + resources_.filePool.setRamLoading(false); else DBG("Unsupported value for hint_ram_based: " << member.value); break; case hash("hint_stealing"): switch(hash(member.value)) { case hash("first"): - for (auto& voice : voices) - voice->disablePowerFollower(); + for (auto& voice : voiceList_) + voice.disablePowerFollower(); - stealer.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::First); + stealer_.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::First); break; case hash("oldest"): - for (auto& voice : voices) - voice->disablePowerFollower(); + for (auto& voice : voiceList_) + voice.disablePowerFollower(); - stealer.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::Oldest); + stealer_.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::Oldest); break; case hash("envelope_and_age"): - for (auto& voice : voices) - voice->enablePowerFollower(); + for (auto& voice : voiceList_) + voice.enablePowerFollower(); - stealer.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::EnvelopeAndAge); + stealer_.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::EnvelopeAndAge); break; default: DBG("Unsupported value for hint_stealing: " << member.value); @@ -428,19 +777,19 @@ void sfz::Synth::handleControlOpcodes(const std::vector& members) } } -void sfz::Synth::handleEffectOpcodes(const std::vector& rawMembers) +void Synth::Impl::handleEffectOpcodes(const std::vector& rawMembers) { absl::string_view busName = "main"; auto getOrCreateBus = [this](unsigned index) -> EffectBus& { - if (index + 1 > effectBuses.size()) - effectBuses.resize(index + 1); - EffectBusPtr& bus = effectBuses[index]; + if (index + 1 > effectBuses_.size()) + effectBuses_.resize(index + 1); + EffectBusPtr& bus = effectBuses_[index]; if (!bus) { bus.reset(new EffectBus); - bus->setSampleRate(sampleRate); - bus->setSamplesPerBlock(samplesPerBlock); - bus->clearInputs(samplesPerBlock); + bus->setSampleRate(sampleRate_); + bus->setSamplesPerBlock(samplesPerBlock_); + bus->clearInputs(samplesPerBlock_); } return *bus; }; @@ -491,61 +840,63 @@ void sfz::Synth::handleEffectOpcodes(const std::vector& rawMembers) // create the effect and add it EffectBus& bus = getOrCreateBus(busIndex); - auto fx = effectFactory.makeEffect(members); - fx->setSampleRate(sampleRate); - fx->setSamplesPerBlock(samplesPerBlock); + auto fx = effectFactory_.makeEffect(members); + fx->setSampleRate(sampleRate_); + fx->setSamplesPerBlock(samplesPerBlock_); bus.addEffect(std::move(fx)); } -bool sfz::Synth::loadSfzFile(const fs::path& file) +bool Synth::loadSfzFile(const fs::path& file) { - const std::lock_guard disableCallback { callbackGuard }; + Impl& impl = *impl_; + const std::lock_guard disableCallback { impl.callbackGuard_ }; - clear(); + impl.clear(); std::error_code ec; fs::path realFile = fs::canonical(file, ec); - parser.parseFile(ec ? file : realFile); - if (parser.getErrorCount() > 0) + impl.parser_.parseFile(ec ? file : realFile); + if (impl.parser_.getErrorCount() > 0) return false; - if (regions.empty()) + if (impl.regions_.empty()) return false; - finalizeSfzLoad(); + impl.finalizeSfzLoad(); return true; } -bool sfz::Synth::loadSfzString(const fs::path& path, absl::string_view text) +bool Synth::loadSfzString(const fs::path& path, absl::string_view text) { - const std::lock_guard disableCallback { callbackGuard }; + Impl& impl = *impl_; + const std::lock_guard disableCallback { impl.callbackGuard_ }; - clear(); + impl.clear(); - parser.parseString(path, text); - if (parser.getErrorCount() > 0) + impl.parser_.parseString(path, text); + if (impl.parser_.getErrorCount() > 0) return false; - if (regions.empty()) + if (impl.regions_.empty()) return false; - finalizeSfzLoad(); + impl.finalizeSfzLoad(); return true; } -void sfz::Synth::finalizeSfzLoad() +void Synth::Impl::finalizeSfzLoad() { - resources.filePool.setRootDirectory(parser.originalDirectory()); + resources_.filePool.setRootDirectory(parser_.originalDirectory()); size_t currentRegionIndex = 0; - size_t currentRegionCount = regions.size(); + size_t currentRegionCount = regions_.size(); auto removeCurrentRegion = [this, ¤tRegionIndex, ¤tRegionCount]() { - DBG("Removing the region with sample " << *regions[currentRegionIndex]->sampleId); - regions.erase(regions.begin() + currentRegionIndex); + DBG("Removing the region with sample " << *regions_[currentRegionIndex]->sampleId); + regions_.erase(regions_.begin() + currentRegionIndex); --currentRegionCount; }; @@ -559,17 +910,17 @@ void sfz::Synth::finalizeSfzLoad() FlexEGs::clearUnusedCurves(); while (currentRegionIndex < currentRegionCount) { - auto region = regions[currentRegionIndex].get(); + auto region = regions_[currentRegionIndex].get(); absl::optional 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; @@ -613,56 +964,56 @@ 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; } } if (region->lastKeyswitch) { - if (currentSwitch) - region->keySwitched = (*currentSwitch == *region->lastKeyswitch); + if (currentSwitch_) + region->keySwitched = (*currentSwitch_ == *region->lastKeyswitch); if (region->keyswitchLabel) - insertPairUniquely(keyswitchLabels, *region->lastKeyswitch, *region->keyswitchLabel); + insertPairUniquely(keyswitchLabels_, *region->lastKeyswitch, *region->keyswitchLabel); } if (region->lastKeyswitchRange) { auto& range = *region->lastKeyswitchRange; - if (currentSwitch) - region->keySwitched = range.containsWithEnd(*currentSwitch); + if (currentSwitch_) + region->keySwitched = range.containsWithEnd(*currentSwitch_); if (region->keyswitchLabel) { for (uint8_t note = range.getStart(), end = range.getEnd(); note <= end; note++) - insertPairUniquely(keyswitchLabels, note, *region->keyswitchLabel); + insertPairUniquely(keyswitchLabels_, note, *region->keyswitchLabel); } } // Some regions had group number but no "group-level" opcodes handled the polyphony - while (polyphonyGroups.size() <= region->group) { - polyphonyGroups.emplace_back(); - polyphonyGroups.back().setPolyphonyLimit(config::maxVoices); + while (polyphonyGroups_.size() <= region->group) { + polyphonyGroups_.emplace_back(); + polyphonyGroups_.back().setPolyphonyLimit(config::maxVoices); } for (auto note = 0; note < 128; note++) { if (region->keyRange.containsWithEnd(note)) - noteActivationLists[note].push_back(region); + noteActivationLists_[note].push_back(region); } for (int cc = 0; cc < config::numCCs; cc++) { if (region->ccTriggers.contains(cc) || region->ccConditions.contains(cc) || (cc == region->sustainCC && region->trigger == SfzTrigger::release)) - ccActivationLists[cc].push_back(region); + ccActivationLists_[cc].push_back(region); } // Defaults for (int cc = 0; cc < config::numCCs; cc++) { - region->registerCC(cc, resources.midiState.getCCValue(cc)); + region->registerCC(cc, resources_.midiState.getCCValue(cc)); } @@ -696,12 +1047,12 @@ void sfz::Synth::finalizeSfzLoad() ++currentRegionIndex; } - DBG("Removing " << (regions.size() - currentRegionCount) << " out of " << regions.size() << " regions"); - regions.resize(currentRegionCount); + DBG("Removing " << (regions_.size() - currentRegionCount) << " out of " << regions_.size() << " regions"); + regions_.resize(currentRegionCount); // collect all CCs used in regions, with matrix not yet connected std::bitset usedCCs; - for (const RegionPtr& regionPtr : regions) { + for (const RegionPtr& regionPtr : regions_) { const Region& region = *regionPtr; updateUsedCCsFromRegion(usedCCs, region); for (const Region::Connection& connection : region.connections) { @@ -710,7 +1061,7 @@ void sfz::Synth::finalizeSfzLoad() } } // connect default controllers, except if these CC are already used - for (const RegionPtr& regionPtr : regions) { + for (const RegionPtr& regionPtr : regions_) { Region& region = *regionPtr; constexpr unsigned defaultSmoothness = 10; if (!usedCCs.test(7)) { @@ -730,128 +1081,135 @@ void sfz::Synth::finalizeSfzLoad() } } - modificationTime = checkModificationTime(); + modificationTime_ = checkModificationTime(); - settingsPerVoice.maxFilters = maxFilters; - settingsPerVoice.maxEQs = maxEQs; - settingsPerVoice.maxLFOs = maxLFOs; - settingsPerVoice.maxFlexEGs = maxFlexEGs; - settingsPerVoice.havePitchEG = havePitchEG; - settingsPerVoice.haveFilterEG = haveFilterEG; + settingsPerVoice_.maxFilters = maxFilters; + settingsPerVoice_.maxEQs = maxEQs; + settingsPerVoice_.maxLFOs = maxLFOs; + settingsPerVoice_.maxFlexEGs = maxFlexEGs; + settingsPerVoice_.havePitchEG = havePitchEG; + settingsPerVoice_.haveFilterEG = haveFilterEG; applySettingsPerVoice(); setupModMatrix(); } -bool sfz::Synth::loadScalaFile(const fs::path& path) +bool Synth::loadScalaFile(const fs::path& path) { - return resources.tuning.loadScalaFile(path); + Impl& impl = *impl_; + return impl.resources_.tuning.loadScalaFile(path); } -bool sfz::Synth::loadScalaString(const std::string& text) +bool Synth::loadScalaString(const std::string& text) { - return resources.tuning.loadScalaString(text); + Impl& impl = *impl_; + return impl.resources_.tuning.loadScalaString(text); } -void sfz::Synth::setScalaRootKey(int rootKey) +void Synth::setScalaRootKey(int rootKey) { - resources.tuning.setScalaRootKey(rootKey); + Impl& impl = *impl_; + impl.resources_.tuning.setScalaRootKey(rootKey); } -int sfz::Synth::getScalaRootKey() const +int Synth::getScalaRootKey() const { - return resources.tuning.getScalaRootKey(); + Impl& impl = *impl_; + return impl.resources_.tuning.getScalaRootKey(); } -void sfz::Synth::setTuningFrequency(float frequency) +void Synth::setTuningFrequency(float frequency) { - resources.tuning.setTuningFrequency(frequency); + Impl& impl = *impl_; + impl.resources_.tuning.setTuningFrequency(frequency); } -float sfz::Synth::getTuningFrequency() const +float Synth::getTuningFrequency() const { - return resources.tuning.getTuningFrequency(); + Impl& impl = *impl_; + return impl.resources_.tuning.getTuningFrequency(); } -void sfz::Synth::loadStretchTuningByRatio(float ratio) +void Synth::loadStretchTuningByRatio(float ratio) { + Impl& impl = *impl_; SFIZZ_CHECK(ratio >= 0.0f && ratio <= 1.0f); ratio = clamp(ratio, 0.0f, 1.0f); if (ratio > 0.0f) - resources.stretch = StretchTuning::createRailsbackFromRatio(ratio); + impl.resources_.stretch = StretchTuning::createRailsbackFromRatio(ratio); else - resources.stretch.reset(); + impl.resources_.stretch.reset(); } -sfz::Voice* sfz::Synth::findFreeVoice() noexcept +Voice* Synth::Impl::findFreeVoice() noexcept { - auto freeVoice = absl::c_find_if(voices, [](const std::unique_ptr& voice) { - return voice->isFree(); + auto freeVoice = absl::c_find_if(voiceList_, [](const Voice& voice) { + return voice.isFree(); }); - if (freeVoice != voices.end()) - return freeVoice->get(); + if (freeVoice != voiceList_.end()) + return &*freeVoice; DBG("Engine hard polyphony reached"); return {}; } -int sfz::Synth::getNumActiveVoices(bool recompute) const noexcept +int Synth::getNumActiveVoices(bool recompute) const noexcept { + Impl& impl = *impl_; if (!recompute) - return activeVoices; + return impl.activeVoices_; int active { 0 }; - for (auto& voice: voices) { - if (!voice->isFree()) + for (auto& voice: impl.voiceList_) { + if (!voice.isFree()) active++; } return active; } -void sfz::Synth::garbageCollect() noexcept -{ -} - -void sfz::Synth::setSamplesPerBlock(int samplesPerBlock) noexcept +void Synth::setSamplesPerBlock(int samplesPerBlock) noexcept { + Impl& impl = *impl_; ASSERT(samplesPerBlock <= config::maxBlockSize); - const std::lock_guard disableCallback { callbackGuard }; + const std::lock_guard disableCallback { impl.callbackGuard_ }; - this->samplesPerBlock = samplesPerBlock; - for (auto& voice : voices) - voice->setSamplesPerBlock(samplesPerBlock); + impl.samplesPerBlock_ = samplesPerBlock; + for (auto& voice : impl.voiceList_) + voice.setSamplesPerBlock(samplesPerBlock); - resources.setSamplesPerBlock(samplesPerBlock); + impl.resources_.setSamplesPerBlock(samplesPerBlock); - for (auto& bus : effectBuses) { + for (auto& bus : impl.effectBuses_) { if (bus) bus->setSamplesPerBlock(samplesPerBlock); } } -void sfz::Synth::setSampleRate(float sampleRate) noexcept +void Synth::setSampleRate(float sampleRate) noexcept { - const std::lock_guard disableCallback { callbackGuard }; + Impl& impl = *impl_; + const std::lock_guard disableCallback { impl.callbackGuard_ }; - this->sampleRate = sampleRate; - for (auto& voice : voices) - voice->setSampleRate(sampleRate); + impl.sampleRate_ = sampleRate; + for (auto& voice : impl.voiceList_) + voice.setSampleRate(sampleRate); - resources.setSampleRate(sampleRate); + impl.resources_.setSampleRate(sampleRate); - for (auto& bus : effectBuses) { + for (auto& bus : impl.effectBuses_) { if (bus) bus->setSampleRate(sampleRate); } } -void sfz::Synth::renderBlock(AudioSpan buffer) noexcept +void Synth::renderBlock(AudioSpan buffer) noexcept { + Impl& impl = *impl_; ScopedFTZ ftz; CallbackBreakdown callbackBreakdown; @@ -860,74 +1218,74 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept buffer.fill(0.0f); } - if (resources.synthConfig.freeWheeling) - resources.filePool.waitForBackgroundLoading(); + if (impl.resources_.synthConfig.freeWheeling) + impl.resources_.filePool.waitForBackgroundLoading(); const auto now = std::chrono::high_resolution_clock::now(); const auto timeSinceLastCollection = - std::chrono::duration_cast(now - lastGarbageCollection); + std::chrono::duration_cast(now - impl.lastGarbageCollection_); if (timeSinceLastCollection.count() > config::fileClearingPeriod) { - lastGarbageCollection = now; - resources.filePool.triggerGarbageCollection(); + impl.lastGarbageCollection_ = now; + impl.resources_.filePool.triggerGarbageCollection(); } - const std::unique_lock lock { callbackGuard, std::try_to_lock }; + const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; if (!lock.owns_lock()) return; size_t numFrames = buffer.getNumFrames(); - auto tempSpan = resources.bufferPool.getStereoBuffer(numFrames); - auto tempMixSpan = resources.bufferPool.getStereoBuffer(numFrames); - auto rampSpan = resources.bufferPool.getBuffer(numFrames); + auto tempSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames); + auto tempMixSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames); + auto rampSpan = impl.resources_.bufferPool.getBuffer(numFrames); if (!tempSpan || !tempMixSpan || !rampSpan) { DBG("[sfizz] Could not get a temporary buffer; exiting callback... "); return; } - ModMatrix& mm = resources.modMatrix; + ModMatrix& mm = impl.resources_.modMatrix; mm.beginCycle(numFrames); { // Clear effect busses ScopedTiming logger { callbackBreakdown.effects }; - for (auto& bus : effectBuses) { + for (auto& bus : impl.effectBuses_) { if (bus) bus->clearInputs(numFrames); } } - activeVoices = 0; + impl.activeVoices_ = 0; { // Main render block ScopedTiming logger { callbackBreakdown.renderMethod, ScopedTiming::Operation::addToDuration }; tempMixSpan->fill(0.0f); - for (auto& voice : voices) { - if (voice->isFree()) + for (auto& voice : impl.voiceList_) { + if (voice.isFree()) continue; - mm.beginVoice(voice->getId(), voice->getRegion()->getId(), voice->getTriggerEvent().value); + mm.beginVoice(voice.getId(), voice.getRegion()->getId(), voice.getTriggerEvent().value); - activeVoices++; + impl.activeVoices_++; - const Region* region = voice->getRegion(); + const Region* region = voice.getRegion(); ASSERT(region != nullptr); - voice->renderBlock(*tempSpan); - for (size_t i = 0, n = effectBuses.size(); i < n; ++i) { - if (auto& bus = effectBuses[i]) { + voice.renderBlock(*tempSpan); + for (size_t i = 0, n = impl.effectBuses_.size(); i < n; ++i) { + if (auto& bus = impl.effectBuses_[i]) { float addGain = region->getGainToEffectBus(i); bus->addToInputs(*tempSpan, addGain, numFrames); } } - callbackBreakdown.data += voice->getLastDataDuration(); - callbackBreakdown.amplitude += voice->getLastAmplitudeDuration(); - callbackBreakdown.filters += voice->getLastFilterDuration(); - callbackBreakdown.panning += voice->getLastPanningDuration(); + callbackBreakdown.data += voice.getLastDataDuration(); + callbackBreakdown.amplitude += voice.getLastAmplitudeDuration(); + callbackBreakdown.filters += voice.getLastFilterDuration(); + callbackBreakdown.panning += voice.getLastPanningDuration(); mm.endVoice(); - if (voice->toBeCleanedUp()) - voice->reset(); + if (voice.toBeCleanedUp()) + voice.reset(); } } @@ -936,7 +1294,7 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept // without any , the signal is just going to flow through it. ScopedTiming logger { callbackBreakdown.effects, ScopedTiming::Operation::addToDuration }; - for (auto& bus : effectBuses) { + for (auto& bus : impl.effectBuses_) { if (bus) { bus->process(numFrames); bus->mixOutputsTo(buffer, *tempMixSpan, numFrames); @@ -951,21 +1309,21 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept buffer.add(*tempMixSpan); // Apply the master volume - buffer.applyGain(db2mag(volume)); + buffer.applyGain(db2mag(impl.volume_)); // Perform any remaining modulators mm.endCycle(); { // Clear events and advance midi time - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; - resources.midiState.advanceTime(buffer.getNumFrames()); + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; + impl.resources_.midiState.advanceTime(buffer.getNumFrames()); } - callbackBreakdown.dispatch = dispatchDuration; - resources.logger.logCallbackTime(callbackBreakdown, activeVoices, numFrames); + callbackBreakdown.dispatch = impl.dispatchDuration_; + impl.resources_.logger.logCallbackTime(callbackBreakdown, impl.activeVoices_, numFrames); // Reset the dispatch counter - dispatchDuration = Duration(0); + impl.dispatchDuration_ = Duration(0); ASSERT(!hasNanInf(buffer.getConstSpan(0))); ASSERT(!hasNanInf(buffer.getConstSpan(1))); @@ -973,46 +1331,48 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1))); } -void sfz::Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept +void Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept { ASSERT(noteNumber < 128); ASSERT(noteNumber >= 0); + Impl& impl = *impl_; const auto normalizedVelocity = normalizeVelocity(velocity); - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; - resources.midiState.noteOnEvent(delay, noteNumber, normalizedVelocity); + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; + impl.resources_.midiState.noteOnEvent(delay, noteNumber, normalizedVelocity); - const std::unique_lock lock { callbackGuard, std::try_to_lock }; + const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; if (!lock.owns_lock()) return; - noteOnDispatch(delay, noteNumber, normalizedVelocity); + impl.noteOnDispatch(delay, noteNumber, normalizedVelocity); } -void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept +void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept { ASSERT(noteNumber < 128); ASSERT(noteNumber >= 0); UNUSED(velocity); + Impl& impl = *impl_; const auto normalizedVelocity = normalizeVelocity(velocity); - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; - resources.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; + impl.resources_.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); - const std::unique_lock lock { callbackGuard, std::try_to_lock }; + const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; if (!lock.owns_lock()) return; // FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a // way in sfz to specify that a release trigger should NOT use the note-on velocity? - // auto replacedVelocity = (velocity == 0 ? sfz::getNoteVelocity(noteNumber) : velocity); - const auto replacedVelocity = resources.midiState.getNoteVelocity(noteNumber); + // auto replacedVelocity = (velocity == 0 ? getNoteVelocity(noteNumber) : velocity); + const auto replacedVelocity = impl.resources_.midiState.getNoteVelocity(noteNumber); - for (auto& voice : voices) - voice->registerNoteOff(delay, noteNumber, replacedVelocity); + for (auto& voice : impl.voiceList_) + voice.registerNoteOff(delay, noteNumber, replacedVelocity); - noteOffDispatch(delay, noteNumber, replacedVelocity); + impl.noteOffDispatch(delay, noteNumber, replacedVelocity); } -void sfz::Synth::startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept +void Synth::Impl::startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept { checkNotePolyphony(region, delay, triggerEvent); checkRegionPolyphony(region, delay); @@ -1027,42 +1387,42 @@ void sfz::Synth::startVoice(Region* region, int delay, const TriggerEvent& trigg ASSERT(selectedVoice->isFree()); selectedVoice->startVoice(region, delay, triggerEvent); ring.addVoiceToRing(selectedVoice); - engineSet->registerVoice(selectedVoice); + engineSet_->registerVoice(selectedVoice); RegionSet::registerVoiceInHierarchy(region, selectedVoice); - polyphonyGroups[region->group].registerVoice(selectedVoice); + polyphonyGroups_[region->group].registerVoice(selectedVoice); } -bool sfz::Synth::playingAttackVoice(const Region* releaseRegion) noexcept +bool Synth::Impl::playingAttackVoice(const Region* releaseRegion) noexcept { const auto compatibleVoice = [releaseRegion](const Voice* v) -> bool { - const sfz::TriggerEvent& event = v->getTriggerEvent(); + const TriggerEvent& event = v->getTriggerEvent(); return ( !v->isFree() - && event.type == sfz::TriggerEventType::NoteOn + && event.type == TriggerEventType::NoteOn && releaseRegion->keyRange.containsWithEnd(event.number) && releaseRegion->velocityRange.containsWithEnd(event.value) ); }; - if (absl::c_find_if(voiceViewArray, compatibleVoice) == voiceViewArray.end()) + if (absl::c_find_if(voiceViewArray_, compatibleVoice) == voiceViewArray_.end()) return false; else return true; } -void sfz::Synth::noteOffDispatch(int delay, int noteNumber, float velocity) noexcept +void Synth::Impl::noteOffDispatch(int delay, int noteNumber, float velocity) noexcept { - const auto randValue = randNoteDistribution(Random::randomGenerator); + const auto randValue = randNoteDistribution_(Random::randomGenerator); SisterVoiceRingBuilder ring; const TriggerEvent triggerEvent { TriggerEventType::NoteOff, noteNumber, velocity }; - for (auto& region : upKeyswitchLists[noteNumber]) + for (auto& region : upKeyswitchLists_[noteNumber]) region->keySwitched = true; - for (auto& region : downKeyswitchLists[noteNumber]) + for (auto& region : downKeyswitchLists_[noteNumber]) region->keySwitched = false; - for (auto& region : noteActivationLists[noteNumber]) { + for (auto& region : noteActivationLists_[noteNumber]) { if (region->registerNoteOff(noteNumber, velocity, randValue)) { if (region->trigger == SfzTrigger::release && !region->rtDead && !playingAttackVoice(region)) continue; @@ -1072,20 +1432,20 @@ void sfz::Synth::noteOffDispatch(int delay, int noteNumber, float velocity) noex } } -void sfz::Synth::checkRegionPolyphony(const Region* region, int delay) noexcept +void Synth::Impl::checkRegionPolyphony(const Region* region, int delay) noexcept { - tempPolyphonyArray.clear(); - absl::c_copy_if(voiceViewArray, - std::back_inserter(tempPolyphonyArray), + tempPolyphonyArray_.clear(); + absl::c_copy_if(voiceViewArray_, + std::back_inserter(tempPolyphonyArray_), [region](Voice* v) { return v->getRegion() == region && !v->releasedOrFree(); }); - if (tempPolyphonyArray.size() >= region->polyphony) { - const auto voiceToSteal = stealer.steal(absl::MakeSpan(tempPolyphonyArray)); + if (tempPolyphonyArray_.size() >= region->polyphony) { + const auto voiceToSteal = stealer_.steal(absl::MakeSpan(tempPolyphonyArray_)); SisterVoiceRing::offAllSisters(voiceToSteal, delay); } } -void sfz::Synth::checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept +void Synth::Impl::checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept { if (!region->notePolyphony) return; @@ -1093,8 +1453,8 @@ void sfz::Synth::checkNotePolyphony(const Region* region, int delay, const Trigg unsigned notePolyphonyCounter { 0 }; Voice* selfMaskCandidate { nullptr }; - for (Voice* voice : voiceViewArray) { - const sfz::TriggerEvent& voiceTriggerEvent = voice->getTriggerEvent(); + for (Voice* voice : voiceViewArray_) { + const TriggerEvent& voiceTriggerEvent = voice->getTriggerEvent(); const bool skipVoice = (triggerEvent.type == TriggerEventType::NoteOn && voice->releasedOrFree()) || voice->isFree(); if (!skipVoice && voice->getRegion()->group == region->group @@ -1122,30 +1482,30 @@ void sfz::Synth::checkNotePolyphony(const Region* region, int delay, const Trigg } } -void sfz::Synth::checkGroupPolyphony(const Region* region, int delay) noexcept +void Synth::Impl::checkGroupPolyphony(const Region* region, int delay) noexcept { - const auto& activeVoices = polyphonyGroups[region->group].getActiveVoices(); - tempPolyphonyArray.clear(); + const auto& activeVoices = polyphonyGroups_[region->group].getActiveVoices(); + tempPolyphonyArray_.clear(); absl::c_copy_if(activeVoices, - std::back_inserter(tempPolyphonyArray), [](Voice* v) { return !v->releasedOrFree(); }); + std::back_inserter(tempPolyphonyArray_), [](Voice* v) { return !v->releasedOrFree(); }); - if (tempPolyphonyArray.size() >= polyphonyGroups[region->group].getPolyphonyLimit()) { - const auto voiceToSteal = stealer.steal(absl::MakeSpan(tempPolyphonyArray)); + if (tempPolyphonyArray_.size() >= polyphonyGroups_[region->group].getPolyphonyLimit()) { + const auto voiceToSteal = stealer_.steal(absl::MakeSpan(tempPolyphonyArray_)); SisterVoiceRing::offAllSisters(voiceToSteal, delay); } } -void sfz::Synth::checkSetPolyphony(const Region* region, int delay) noexcept +void Synth::Impl::checkSetPolyphony(const Region* region, int delay) noexcept { auto parent = region->parent; while (parent != nullptr) { const auto& activeVoices = parent->getActiveVoices(); - tempPolyphonyArray.clear(); + tempPolyphonyArray_.clear(); absl::c_copy_if(activeVoices, - std::back_inserter(tempPolyphonyArray), [](Voice* v) { return !v->releasedOrFree(); }); + std::back_inserter(tempPolyphonyArray_), [](Voice* v) { return !v->releasedOrFree(); }); - if (tempPolyphonyArray.size() >= parent->getPolyphonyLimit()) { - const auto voiceToSteal = stealer.steal(absl::MakeSpan(tempPolyphonyArray)); + if (tempPolyphonyArray_.size() >= parent->getPolyphonyLimit()) { + const auto voiceToSteal = stealer_.steal(absl::MakeSpan(tempPolyphonyArray_)); SisterVoiceRing::offAllSisters(voiceToSteal, delay); } @@ -1153,47 +1513,47 @@ void sfz::Synth::checkSetPolyphony(const Region* region, int delay) noexcept } } -void sfz::Synth::checkEnginePolyphony(int delay) noexcept +void Synth::Impl::checkEnginePolyphony(int delay) noexcept { - auto& activeVoices = engineSet->getActiveVoices(); + auto& activeVoices = engineSet_->getActiveVoices(); - if (activeVoices.size() >= static_cast(numRequiredVoices)) { - tempPolyphonyArray.clear(); + if (activeVoices.size() >= static_cast(numRequiredVoices_)) { + tempPolyphonyArray_.clear(); absl::c_copy_if(activeVoices, - std::back_inserter(tempPolyphonyArray), [](Voice* v) { return !v->releasedOrFree(); }); - const auto voiceToSteal = stealer.steal(absl::MakeSpan(tempPolyphonyArray)); + std::back_inserter(tempPolyphonyArray_), [](Voice* v) { return !v->releasedOrFree(); }); + const auto voiceToSteal = stealer_.steal(absl::MakeSpan(tempPolyphonyArray_)); SisterVoiceRing::offAllSisters(voiceToSteal, delay, true); } } -void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexcept +void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noexcept { - const auto randValue = randNoteDistribution(Random::randomGenerator); + const auto randValue = randNoteDistribution_(Random::randomGenerator); SisterVoiceRingBuilder ring; const TriggerEvent triggerEvent { TriggerEventType::NoteOn, noteNumber, velocity }; - if (!lastKeyswitchLists[noteNumber].empty()) { - if (currentSwitch && *currentSwitch != noteNumber) { - for (auto& region : lastKeyswitchLists[*currentSwitch]) + if (!lastKeyswitchLists_[noteNumber].empty()) { + if (currentSwitch_ && *currentSwitch_ != noteNumber) { + for (auto& region : lastKeyswitchLists_[*currentSwitch_]) region->keySwitched = false; } - currentSwitch = noteNumber; + currentSwitch_ = noteNumber; } - for (auto& region : lastKeyswitchLists[noteNumber]) + for (auto& region : lastKeyswitchLists_[noteNumber]) region->keySwitched = true; - for (auto& region : upKeyswitchLists[noteNumber]) + for (auto& region : upKeyswitchLists_[noteNumber]) region->keySwitched = false; - for (auto& region : downKeyswitchLists[noteNumber]) + for (auto& region : downKeyswitchLists_[noteNumber]) region->keySwitched = true; - for (auto& region : noteActivationLists[noteNumber]) { + for (auto& region : noteActivationLists_[noteNumber]) { if (region->registerNoteOn(noteNumber, velocity, randValue)) { - for (auto& voice : voices) { - if (voice->checkOffGroup(region, delay, noteNumber)) { - const TriggerEvent& event = voice->getTriggerEvent(); + for (auto& voice : voiceList_) { + if (voice.checkOffGroup(region, delay, noteNumber)) { + const TriggerEvent& event = voice.getTriggerEvent(); noteOffDispatch(delay, event.number, event.value); } } @@ -1202,11 +1562,11 @@ void sfz::Synth::noteOnDispatch(int delay, int noteNumber, float velocity) noexc } } - for (auto& region : previousKeyswitchLists) + for (auto& region : previousKeyswitchLists_) region->previousKeySwitched = (*region->previousKeyswitch == noteNumber); } -void sfz::Synth::startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept +void Synth::Impl::startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept { if (!region->rtDead && !playingAttackVoice(region)) { region->delayedReleases.clear(); @@ -1222,17 +1582,17 @@ void sfz::Synth::startDelayedReleaseVoices(Region* region, int delay, SisterVoic } -void sfz::Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept +void Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept { const auto normalizedCC = normalizeCC(ccValue); hdcc(delay, ccNumber, normalizedCC); } -void sfz::Synth::ccDispatch(int delay, int ccNumber, float value) noexcept +void Synth::Impl::ccDispatch(int delay, int ccNumber, float value) noexcept { SisterVoiceRingBuilder ring; const TriggerEvent triggerEvent { TriggerEventType::CC, ccNumber, value }; - for (auto& region : ccActivationLists[ccNumber]) { + for (auto& region : ccActivationLists_[ccNumber]) { if (ccNumber == region->sustainCC) startDelayedReleaseVoices(region, delay, ring); @@ -1241,125 +1601,124 @@ void sfz::Synth::ccDispatch(int delay, int ccNumber, float value) noexcept } } -void sfz::Synth::hdcc(int delay, int ccNumber, float normValue) noexcept +void Synth::hdcc(int delay, int ccNumber, float normValue) noexcept { ASSERT(ccNumber < config::numCCs); ASSERT(ccNumber >= 0); - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; - resources.midiState.ccEvent(delay, ccNumber, normValue); + Impl& impl = *impl_; + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; + impl.resources_.midiState.ccEvent(delay, ccNumber, normValue); - const std::unique_lock lock { callbackGuard, std::try_to_lock }; + const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; if (!lock.owns_lock()) return; if (ccNumber == config::resetCC) { - resetAllControllers(delay); + impl.resetAllControllers(delay); return; } if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) { - for (auto& voice : voices) - voice->reset(); - resources.midiState.allNotesOff(delay); + for (auto& voice : impl.voiceList_) + voice.reset(); + impl.resources_.midiState.allNotesOff(delay); return; } - for (auto& voice : voices) - voice->registerCC(delay, ccNumber, normValue); + for (auto& voice : impl.voiceList_) + voice.registerCC(delay, ccNumber, normValue); - ccDispatch(delay, ccNumber, normValue); + impl.ccDispatch(delay, ccNumber, normValue); } -void sfz::Synth::initCc(int ccNumber, uint8_t ccValue) noexcept -{ - const float normValue = normalizeCC(ccValue); - initHdcc(ccNumber, normValue); -} - -void sfz::Synth::initHdcc(int ccNumber, float normValue) noexcept +float Synth::getHdcc(int ccNumber) { ASSERT(ccNumber >= 0); ASSERT(ccNumber < config::numCCs); - ccInitialValues[ccNumber] = normValue; - resources.midiState.ccEvent(0, ccNumber, normValue); + Impl& impl = *impl_; + return impl.resources_.midiState.getCCValue(ccNumber); } -float sfz::Synth::getHdccInit(int ccNumber) -{ - ASSERT(ccNumber >= 0); - ASSERT(ccNumber < config::numCCs); - return ccInitialValues[ccNumber]; -} - -void sfz::Synth::pitchWheel(int delay, int pitch) noexcept +void Synth::pitchWheel(int delay, int pitch) noexcept { ASSERT(pitch <= 8192); ASSERT(pitch >= -8192); + Impl& impl = *impl_; const auto normalizedPitch = normalizeBend(float(pitch)); - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; - resources.midiState.pitchBendEvent(delay, normalizedPitch); + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; + impl.resources_.midiState.pitchBendEvent(delay, normalizedPitch); - for (auto& region : regions) { + for (auto& region : impl.regions_) { region->registerPitchWheel(normalizedPitch); } - for (auto& voice : voices) { - voice->registerPitchWheel(delay, normalizedPitch); + for (auto& voice : impl.voiceList_) { + voice.registerPitchWheel(delay, normalizedPitch); } } -void sfz::Synth::aftertouch(int /* delay */, uint8_t /* aftertouch */) noexcept +void Synth::aftertouch(int /* delay */, uint8_t /* aftertouch */) noexcept { - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; + Impl& impl = *impl_; + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; } -void sfz::Synth::tempo(int /* delay */, float /* secondsPerQuarter */) noexcept +void Synth::tempo(int /* delay */, float /* secondsPerQuarter */) noexcept { - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; + Impl& impl = *impl_; + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; } -void sfz::Synth::timeSignature(int delay, int beatsPerBar, int beatUnit) +void Synth::timeSignature(int delay, int beatsPerBar, int beatUnit) { - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; + Impl& impl = *impl_; + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; (void)delay; (void)beatsPerBar; (void)beatUnit; } -void sfz::Synth::timePosition(int delay, int bar, float barBeat) +void Synth::timePosition(int delay, int bar, float barBeat) { - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; + Impl& impl = *impl_; + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; (void)delay; (void)bar; (void)barBeat; } -void sfz::Synth::playbackState(int delay, int playbackState) +void Synth::playbackState(int delay, int playbackState) { - ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; + Impl& impl = *impl_; + ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; (void)delay; (void)playbackState; } -int sfz::Synth::getNumRegions() const noexcept +int Synth::getNumRegions() const noexcept { - return static_cast(regions.size()); + Impl& impl = *impl_; + return static_cast(impl.regions_.size()); } -int sfz::Synth::getNumGroups() const noexcept +int Synth::getNumGroups() const noexcept { - return numGroups; + Impl& impl = *impl_; + return impl.numGroups_; } -int sfz::Synth::getNumMasters() const noexcept +int Synth::getNumMasters() const noexcept { - return numMasters; + Impl& impl = *impl_; + return impl.numMasters_; } -int sfz::Synth::getNumCurves() const noexcept +int Synth::getNumCurves() const noexcept { - return static_cast(resources.curves.getNumCurves()); + Impl& impl = *impl_; + return static_cast(impl.resources_.curves.getNumCurves()); } -std::string sfz::Synth::exportMidnam(absl::string_view model) const +std::string Synth::exportMidnam(absl::string_view model) const { + Impl& impl = *impl_; pugi::xml_document doc; absl::string_view manufacturer = config::midnamManufacturer; @@ -1421,7 +1780,7 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const pugi::xml_node cns = device.append_child("ControlNameList"); cns.append_attribute("Name").set_value("Controls"); - for (const auto& pair : ccLabels) { + for (const auto& pair : impl.ccLabels_) { anonymousCCs.set(pair.first, false); if (pair.first < 128) { pugi::xml_node cn = cns.append_child("Control"); @@ -1444,12 +1803,12 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const { pugi::xml_node nnl = device.append_child("NoteNameList"); nnl.append_attribute("Name").set_value("Notes"); - for (const auto& pair : keyswitchLabels) { + for (const auto& pair : impl.keyswitchLabels_) { pugi::xml_node nn = nnl.append_child("Note"); nn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); nn.append_attribute("Name").set_value(pair.second.c_str()); } - for (const auto& pair : keyLabels) { + for (const auto& pair : impl.keyLabels_) { pugi::xml_node nn = nnl.append_child("Note"); nn.append_attribute("Number").set_value(std::to_string(pair.first).c_str()); nn.append_attribute("Name").set_value(pair.second.c_str()); @@ -1461,29 +1820,34 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const return std::move(writer.str()); } -const sfz::Region* sfz::Synth::getRegionView(int idx) const noexcept +const Region* Synth::getRegionView(int idx) const noexcept { - return (size_t)idx < regions.size() ? regions[idx].get() : nullptr; + Impl& impl = *impl_; + return (size_t)idx < impl.regions_.size() ? impl.regions_[idx].get() : nullptr; } -const sfz::EffectBus* sfz::Synth::getEffectBusView(int idx) const noexcept +const EffectBus* Synth::getEffectBusView(int idx) const noexcept { - return (size_t)idx < effectBuses.size() ? effectBuses[idx].get() : nullptr; + Impl& impl = *impl_; + return (size_t)idx < impl.effectBuses_.size() ? impl.effectBuses_[idx].get() : nullptr; } -const sfz::RegionSet* sfz::Synth::getRegionSetView(int idx) const noexcept +const RegionSet* Synth::getRegionSetView(int idx) const noexcept { - return (size_t)idx < sets.size() ? sets[idx].get() : nullptr; + Impl& impl = *impl_; + return (size_t)idx < impl.sets_.size() ? impl.sets_[idx].get() : nullptr; } -const sfz::PolyphonyGroup* sfz::Synth::getPolyphonyGroupView(int idx) const noexcept +const PolyphonyGroup* Synth::getPolyphonyGroupView(int idx) const noexcept { - return (size_t)idx < polyphonyGroups.size() ? &polyphonyGroups[idx] : nullptr; + Impl& impl = *impl_; + return (size_t)idx < impl.polyphonyGroups_.size() ? &impl.polyphonyGroups_[idx] : nullptr; } -const sfz::Region* sfz::Synth::getRegionById(NumericId id) const noexcept +const Region* Synth::getRegionById(NumericId id) const noexcept { - const size_t size = regions.size(); + Impl& impl = *impl_; + const size_t size = impl.regions_.size(); if (size == 0 || !id.valid()) return nullptr; @@ -1492,72 +1856,61 @@ const sfz::Region* sfz::Synth::getRegionById(NumericId id) const noexcep size_t index = static_cast(id.number()); index = std::min(index, size - 1); - while (index > 0 && regions[index]->getId().number() > id.number()) + while (index > 0 && impl.regions_[index]->getId().number() > id.number()) --index; - return (regions[index]->getId() == id) ? regions[index].get() : nullptr; + return (impl.regions_[index]->getId() == id) ? impl.regions_[index].get() : nullptr; } -const sfz::Voice* sfz::Synth::getVoiceById(NumericId id) const noexcept +const Voice* Synth::getVoiceView(int idx) const noexcept { - const size_t size = voices.size(); - - if (size == 0 || !id.valid()) - return nullptr; - - // search a sequence of ordered identifiers with potential gaps - size_t index = static_cast(id.number()); - index = std::min(index, size - 1); - - while (index > 0 && voices[index]->getId().number() > id.number()) - --index; - - return (voices[index]->getId() == id) ? voices[index].get() : nullptr; + Impl& impl = *impl_; + return (size_t)idx < impl.voiceList_.size() ? &impl.voiceList_[idx] : nullptr; } -const sfz::Voice* sfz::Synth::getVoiceView(int idx) const noexcept +unsigned Synth::getNumPolyphonyGroups() const noexcept { - return (size_t)idx < voices.size() ? voices[idx].get() : nullptr; + Impl& impl = *impl_; + return impl.polyphonyGroups_.size(); } -unsigned sfz::Synth::getNumPolyphonyGroups() const noexcept +const std::vector& Synth::getUnknownOpcodes() const noexcept { - return polyphonyGroups.size(); + Impl& impl = *impl_; + return impl.unknownOpcodes_; +} +size_t Synth::getNumPreloadedSamples() const noexcept +{ + Impl& impl = *impl_; + return impl.resources_.filePool.getNumPreloadedSamples(); } -const std::vector& sfz::Synth::getUnknownOpcodes() const noexcept -{ - return unknownOpcodes; -} -size_t sfz::Synth::getNumPreloadedSamples() const noexcept -{ - return resources.filePool.getNumPreloadedSamples(); -} - -int sfz::Synth::getSampleQuality(ProcessMode mode) +int Synth::getSampleQuality(ProcessMode mode) { + Impl& impl = *impl_; switch (mode) { case ProcessLive: - return resources.synthConfig.liveSampleQuality; + return impl.resources_.synthConfig.liveSampleQuality; case ProcessFreewheeling: - return resources.synthConfig.freeWheelingSampleQuality; + return impl.resources_.synthConfig.freeWheelingSampleQuality; default: SFIZZ_CHECK(false); return 0; } } -void sfz::Synth::setSampleQuality(ProcessMode mode, int quality) +void Synth::setSampleQuality(ProcessMode mode, int quality) { SFIZZ_CHECK(quality >= 1 && quality <= 10); + Impl& impl = *impl_; quality = clamp(quality, 1, 10); switch (mode) { case ProcessLive: - resources.synthConfig.liveSampleQuality = quality; + impl.resources_.synthConfig.liveSampleQuality = quality; break; case ProcessFreewheeling: - resources.synthConfig.freeWheelingSampleQuality = quality; + impl.resources_.synthConfig.freeWheelingSampleQuality = quality; break; default: SFIZZ_CHECK(false); @@ -1565,93 +1918,94 @@ void sfz::Synth::setSampleQuality(ProcessMode mode, int quality) } } -float sfz::Synth::getVolume() const noexcept +float Synth::getVolume() const noexcept { - return volume; + Impl& impl = *impl_; + return impl.volume_; } -void sfz::Synth::setVolume(float volume) noexcept +void Synth::setVolume(float volume) noexcept { - this->volume = Default::volumeRange.clamp(volume); + Impl& impl = *impl_; + impl.volume_ = Default::volumeRange.clamp(volume); } -int sfz::Synth::getNumVoices() const noexcept +int Synth::getNumVoices() const noexcept { - return numRequiredVoices; + Impl& impl = *impl_; + return impl.numRequiredVoices_; } -void sfz::Synth::setNumVoices(int numVoices) noexcept +void Synth::setNumVoices(int numVoices) noexcept { ASSERT(numVoices > 0); - const std::lock_guard disableCallback { callbackGuard }; + Impl& impl = *impl_; + const std::lock_guard disableCallback { impl.callbackGuard_ }; // fast path - if (numVoices == this->numRequiredVoices) + if (numVoices == impl.numRequiredVoices_) return; - resetVoices(numVoices); + impl.resetVoices(numVoices); } -void sfz::Synth::resetVoices(int numVoices) +void Synth::Impl::resetVoices(int numVoices) { - numActualVoices = + numActualVoices_ = static_cast(config::overflowVoiceMultiplier * numVoices); - numRequiredVoices = numVoices; + numRequiredVoices_ = numVoices; - for (auto& set : sets) + for (auto& set : sets_) set->removeAllVoices(); - engineSet->removeAllVoices(); - engineSet->setPolyphonyLimit(numRequiredVoices); + engineSet_->removeAllVoices(); + engineSet_->setPolyphonyLimit(numRequiredVoices_); - voices.clear(); - voices.reserve(numActualVoices); + voiceList_.clear(); + voiceList_.reserve(numActualVoices_); - voiceViewArray.clear(); - voiceViewArray.reserve(numActualVoices); + voiceViewArray_.clear(); + voiceViewArray_.reserve(numActualVoices_); - tempPolyphonyArray.clear(); - tempPolyphonyArray.reserve(numActualVoices); + tempPolyphonyArray_.clear(); + tempPolyphonyArray_.reserve(numActualVoices_); - for (int i = 0; i < numActualVoices; ++i) { - auto voice = absl::make_unique(i, resources); - voice->setStateListener(this); - voiceViewArray.push_back(voice.get()); - voices.emplace_back(std::move(voice)); - } - - for (auto& voice : voices) { - voice->setSampleRate(this->sampleRate); - voice->setSamplesPerBlock(this->samplesPerBlock); + for (int i = 0; i < numActualVoices_; ++i) { + voiceList_.emplace_back(i, resources_); + Voice& lastVoice = voiceList_.back(); + lastVoice.setSampleRate(this->sampleRate_); + lastVoice.setSamplesPerBlock(this->samplesPerBlock_); + lastVoice.setStateListener(this); + voiceViewArray_.push_back(&lastVoice); } applySettingsPerVoice(); } -void sfz::Synth::applySettingsPerVoice() +void Synth::Impl::applySettingsPerVoice() { - for (auto& voice : voices) { - voice->setMaxFiltersPerVoice(settingsPerVoice.maxFilters); - voice->setMaxEQsPerVoice(settingsPerVoice.maxEQs); - voice->setMaxLFOsPerVoice(settingsPerVoice.maxLFOs); - voice->setMaxFlexEGsPerVoice(settingsPerVoice.maxFlexEGs); - voice->setPitchEGEnabledPerVoice(settingsPerVoice.havePitchEG); - voice->setFilterEGEnabledPerVoice(settingsPerVoice.haveFilterEG); + for (auto& voice : voiceList_) { + voice.setMaxFiltersPerVoice(settingsPerVoice_.maxFilters); + voice.setMaxEQsPerVoice(settingsPerVoice_.maxEQs); + voice.setMaxLFOsPerVoice(settingsPerVoice_.maxLFOs); + voice.setMaxFlexEGsPerVoice(settingsPerVoice_.maxFlexEGs); + voice.setPitchEGEnabledPerVoice(settingsPerVoice_.havePitchEG); + voice.setFilterEGEnabledPerVoice(settingsPerVoice_.haveFilterEG); } - if (stealer.getStealingAlgorithm() == + if (stealer_.getStealingAlgorithm() == VoiceStealing::StealingAlgorithm::EnvelopeAndAge) { - for (auto& voice : voices) - voice->enablePowerFollower(); + for (auto& voice : voiceList_) + voice.enablePowerFollower(); } else { - for (auto& voice : voices) - voice->disablePowerFollower(); + for (auto& voice : voiceList_) + voice.disablePowerFollower(); } } -void sfz::Synth::setupModMatrix() +void Synth::Impl::setupModMatrix() { - ModMatrix& mm = resources.modMatrix; + ModMatrix& mm = resources_.modMatrix; - for (const RegionPtr& region : regions) { + for (const RegionPtr& region : regions_) { for (const Region::Connection& conn : region->connections) { ModGenerator* gen = nullptr; @@ -1668,18 +2022,18 @@ void sfz::Synth::setupModMatrix() switch (sourceKey.id()) { case ModId::Controller: - gen = genController.get(); + gen = genController_.get(); break; case ModId::LFO: - gen = genLFO.get(); + gen = genLFO_.get(); break; case ModId::Envelope: - gen = genFlexEnvelope.get(); + gen = genFlexEnvelope_.get(); break; case ModId::AmpEG: case ModId::PitchEG: case ModId::FilEG: - gen = genADSREnvelope.get(); + gen = genADSREnvelope_.get(); break; default: DBG("[sfizz] Have unknown type of source generator"); @@ -1715,84 +2069,87 @@ void sfz::Synth::setupModMatrix() mm.init(); } -void sfz::Synth::setOversamplingFactor(sfz::Oversampling factor) noexcept +void Synth::setOversamplingFactor(Oversampling factor) noexcept { - const std::lock_guard disableCallback { callbackGuard }; + Impl& impl = *impl_; + const std::lock_guard disableCallback { impl.callbackGuard_ }; // fast path - if (factor == oversamplingFactor) + if (factor == impl.oversamplingFactor_) return; - for (auto& voice : voices) { + impl.voiceList_.reset(); - voice->reset(); - } - - resources.filePool.emptyFileLoadingQueues(); - resources.filePool.setOversamplingFactor(factor); - oversamplingFactor = factor; + impl.resources_.filePool.emptyFileLoadingQueues(); + impl.resources_.filePool.setOversamplingFactor(factor); + impl.oversamplingFactor_ = factor; } -sfz::Oversampling sfz::Synth::getOversamplingFactor() const noexcept +Oversampling Synth::getOversamplingFactor() const noexcept { - return oversamplingFactor; + Impl& impl = *impl_; + return impl.oversamplingFactor_; } -void sfz::Synth::setPreloadSize(uint32_t preloadSize) noexcept +void Synth::setPreloadSize(uint32_t preloadSize) noexcept { - const std::lock_guard disableCallback { callbackGuard }; + Impl& impl = *impl_; + const std::lock_guard disableCallback { impl.callbackGuard_ }; // fast path - if (preloadSize == resources.filePool.getPreloadSize()) + if (preloadSize == impl.resources_.filePool.getPreloadSize()) return; - resources.filePool.setPreloadSize(preloadSize); + impl.resources_.filePool.setPreloadSize(preloadSize); } -uint32_t sfz::Synth::getPreloadSize() const noexcept +uint32_t Synth::getPreloadSize() const noexcept { - return resources.filePool.getPreloadSize(); + Impl& impl = *impl_; + return impl.resources_.filePool.getPreloadSize(); } -void sfz::Synth::enableFreeWheeling() noexcept +void Synth::enableFreeWheeling() noexcept { - if (!resources.synthConfig.freeWheeling) { - resources.synthConfig.freeWheeling = true; + Impl& impl = *impl_; + if (!impl.resources_.synthConfig.freeWheeling) { + impl.resources_.synthConfig.freeWheeling = true; DBG("Enabling freewheeling"); } } -void sfz::Synth::disableFreeWheeling() noexcept +void Synth::disableFreeWheeling() noexcept { - if (resources.synthConfig.freeWheeling) { - resources.synthConfig.freeWheeling = false; + Impl& impl = *impl_; + if (impl.resources_.synthConfig.freeWheeling) { + impl.resources_.synthConfig.freeWheeling = false; DBG("Disabling freewheeling"); } } -void sfz::Synth::resetAllControllers(int delay) noexcept +void Synth::Impl::resetAllControllers(int delay) noexcept { - resources.midiState.resetAllControllers(delay); + resources_.midiState.resetAllControllers(delay); - const std::unique_lock lock { callbackGuard, std::try_to_lock }; + const std::unique_lock lock { callbackGuard_, std::try_to_lock }; if (!lock.owns_lock()) return; - for (auto& voice : voices) { - voice->registerPitchWheel(delay, 0); + for (auto& voice : voiceList_) { + voice.registerPitchWheel(delay, 0); for (int cc = 0; cc < config::numCCs; ++cc) - voice->registerCC(delay, cc, 0.0f); + voice.registerCC(delay, cc, 0.0f); } - for (auto& region : regions) { + for (auto& region : regions_) { for (int cc = 0; cc < config::numCCs; ++cc) region->registerCC(cc, 0.0f); } } -fs::file_time_type sfz::Synth::checkModificationTime() +fs::file_time_type Synth::Impl::checkModificationTime() { - auto returnedTime = modificationTime; - for (const auto& file : parser.getIncludedFiles()) { + auto returnedTime = modificationTime_; + for (const auto& file : parser_.getIncludedFiles()) { std::error_code ec; const auto fileTime = fs::last_write_time(file, ec); if (!ec && returnedTime < fileTime) @@ -1801,59 +2158,65 @@ fs::file_time_type sfz::Synth::checkModificationTime() return returnedTime; } -bool sfz::Synth::shouldReloadFile() +bool Synth::shouldReloadFile() { - return (checkModificationTime() > modificationTime); + Impl& impl = *impl_; + return (impl.checkModificationTime() > impl.modificationTime_); } -bool sfz::Synth::shouldReloadScala() +bool Synth::shouldReloadScala() { - return resources.tuning.shouldReloadScala(); + Impl& impl = *impl_; + return impl.resources_.tuning.shouldReloadScala(); } -void sfz::Synth::enableLogging(absl::string_view prefix) noexcept +void Synth::enableLogging(absl::string_view prefix) noexcept { - resources.logger.enableLogging(prefix); + Impl& impl = *impl_; + impl.resources_.logger.enableLogging(prefix); } -void sfz::Synth::setLoggingPrefix(absl::string_view prefix) noexcept +void Synth::setLoggingPrefix(absl::string_view prefix) noexcept { - resources.logger.setPrefix(prefix); + Impl& impl = *impl_; + impl.resources_.logger.setPrefix(prefix); } -void sfz::Synth::disableLogging() noexcept +void Synth::disableLogging() noexcept { - resources.logger.disableLogging(); + Impl& impl = *impl_; + impl.resources_.logger.disableLogging(); } -void sfz::Synth::allSoundOff() noexcept +void Synth::allSoundOff() noexcept { - const std::lock_guard disableCallback { callbackGuard }; + Impl& impl = *impl_; + const std::lock_guard disableCallback { impl.callbackGuard_ }; - for (auto& voice : voices) - voice->reset(); - for (auto& effectBus : effectBuses) + impl.voiceList_.reset(); + for (auto& effectBus : impl.effectBuses_) effectBus->clear(); } -void sfz::Synth::setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept +void Synth::Impl::setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept { - while (polyphonyGroups.size() <= groupIdx) - polyphonyGroups.emplace_back(); + while (polyphonyGroups_.size() <= groupIdx) + polyphonyGroups_.emplace_back(); - polyphonyGroups[groupIdx].setPolyphonyLimit(polyphony); + polyphonyGroups_[groupIdx].setPolyphonyLimit(polyphony); } -std::bitset sfz::Synth::getUsedCCs() const noexcept +std::bitset Synth::getUsedCCs() const noexcept { - std::bitset used; - for (const RegionPtr& region : regions) - updateUsedCCsFromRegion(used, *region); - updateUsedCCsFromModulations(used, resources.modMatrix); + Impl& impl = *impl_; + std::bitset used; + for (const Impl::RegionPtr& region : impl.regions_) + impl.updateUsedCCsFromRegion(used, *region); + impl.updateUsedCCsFromModulations(used, impl.resources_.modMatrix); return used; } -void sfz::Synth::updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region) +void Synth::Impl::updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region) { updateUsedCCsFromCCMap(usedCCs, region.offsetCC); updateUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccAttack); @@ -1887,11 +2250,11 @@ void sfz::Synth::updateUsedCCsFromRegion(std::bitset& usedC updateUsedCCsFromCCMap(usedCCs, region.crossfadeCCOutRange); } -void sfz::Synth::updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm) +void Synth::Impl::updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm) { class CCSourceCollector : public ModMatrix::KeyVisitor { public: - explicit CCSourceCollector(std::bitset& used) + explicit CCSourceCollector(std::bitset& used) : used_(used) { } @@ -1902,9 +2265,47 @@ void sfz::Synth::updateUsedCCsFromModulations(std::bitset& used_.set(key.parameters().cc); return true; } - std::bitset& used_; + std::bitset& used_; }; CCSourceCollector vtor(usedCCs); mm.visitSources(vtor); } + +Parser& Synth::getParser() noexcept +{ + Impl& impl = *impl_; + return impl.parser_; +} + +const Parser& Synth::getParser() const noexcept +{ + Impl& impl = *impl_; + return impl.parser_; +} + +const std::vector& Synth::getKeyLabels() const noexcept +{ + Impl& impl = *impl_; + return impl.keyLabels_; +} + +const std::vector& Synth::getCCLabels() const noexcept +{ + Impl& impl = *impl_; + return impl.ccLabels_; +} + +Resources& Synth::getResources() noexcept +{ + Impl& impl = *impl_; + return impl.resources_; +} + +const Resources& Synth::getResources() const noexcept +{ + Impl& impl = *impl_; + return impl.resources_; +} + +} // namespace sfz diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 40b5012e..37e095d2 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -5,31 +5,22 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once -#include "Resources.h" -#include "Parser.h" -#include "Voice.h" #include "Region.h" -#include "RegionSet.h" -#include "PolyphonyGroup.h" -#include "Effects.h" +#include "Voice.h" #include "LeakDetector.h" -#include "MidiState.h" #include "AudioSpan.h" #include "parser/Parser.h" -#include "VoiceStealing.h" -#include "utility/SpinMutex.h" -#include -#include #include -#include +#include #include #include namespace sfz { -class ControllerSource; -class LFOSource; -class FlexEnvelopeSource; -class ADSREnvelopeSource; + +// Forward declarations for the introspection methods +class RegionSet; +class PolyphonyGroup; +class EffectBus; /** * @brief This class is the core of the sfizz library. In C++ it is the main point @@ -68,11 +59,10 @@ class ADSREnvelopeSource; * The jack_client.cpp file contains examples of the most classical usage of the * synth and can be used as a reference. */ -class Synth final : public Voice::StateListener, public Parser::Listener { +class Synth final { public: /** - * @brief Construct a new Synth object with no voices. If you want sound - * you will need to call setNumVoices() before playing. + * @brief Construct a new Synth object with a default number of voices. * */ Synth(); @@ -80,13 +70,10 @@ public: * @brief Destructor */ ~Synth(); - /** - * @brief Construct a new Synth object with a specified number of voices. - * - * @param numVoices - */ - Synth(int numVoices); - + Synth(const Synth& other) = delete; + Synth& operator=(const Synth& other) = delete; + Synth(Synth&& other) = delete; + Synth& operator=(Synth&& other) = delete; /** * @brief Processing mode */ @@ -122,11 +109,6 @@ public: * @true otherwise. */ bool loadSfzString(const fs::path& path, absl::string_view text); - /** - * @brief Finalize SFZ loading, following a successful execution of the - * parsing step. - */ - void finalizeSfzLoad(); /** * @brief Sets the tuning from a Scala file loaded from the file system. * @@ -208,24 +190,6 @@ public: * @return const Region* */ const Region* getRegionById(NumericId id) const noexcept; - /** - * @brief Find the voice which is associated with the given identifier. - * - * @param id - * @return const Voice* - */ - const Voice* getVoiceById(NumericId id) const noexcept; - /** - * @brief Find the voice which is associated with the given identifier. - * - * @param id - * @return Voice* - */ - Voice* getVoiceById(NumericId id) noexcept - { - return const_cast( - const_cast(this)->getVoiceById(id)); - } /** * @brief Get a raw view into a specific region. This is mostly used * for testing. @@ -245,6 +209,7 @@ public: /** * @brief Get a raw view into a specific effect bus. This is mostly used * for testing. + * You'll need to include "Effects.h" to resolve the forward declaration. * * @param idx * @return const EffectBus* @@ -253,6 +218,7 @@ public: /** * @brief Get a raw view into a specific set of regions. This is mostly used * for testing. + * You'll need to include "RegionSet.h" to resolve the forward declaration. * * @param idx * @return const RegionSet* @@ -261,6 +227,7 @@ public: /** * @brief Get a raw view into a specific polyphony group. This is mostly used * for testing. + * You'll need to include "PolyphonyGroup.h" to resolve the forward declaration. * * @param idx * @return const PolyphonyGroup* @@ -370,29 +337,13 @@ public: * @param normValue the normalized cc value, in domain 0 to 1 */ void hdcc(int delay, int ccNumber, float normValue) noexcept; -private: /** - * @brief Set the initial value of a controller and send it to the synth + * @brief Get the current value of a controller under the current instrument * * @param ccNumber the cc number - * @param ccValue the cc value + * @return the current value */ - void initCc(int ccNumber, uint8_t ccValue) noexcept; - /** - * @brief Set the initial value of a controller and send it to the synth - * - * @param ccNumber the cc number - * @param normValue the normalized cc value, in domain 0 to 1 - */ - void initHdcc(int ccNumber, float normValue) noexcept; -public: - /** - * @brief Get the initial value of a controller under the current instrument - * - * @param ccNumber the cc number - * @return the initial value - */ - float getHdccInit(int ccNumber); + float getHdcc(int ccNumber); /** * @brief Send a pitch bend event to the synth * @@ -475,15 +426,6 @@ public: * @param numVoices */ void setNumVoices(int numVoices) noexcept; - /** - * @brief Trigger a garbage collection, which removes the samples that are - * loaded by the FilePool after being requested by the voices. This does - * not concern the preloaded samples, only the samples loaded to be played - * fully. This function is run regularly in a background thread so normally - * you should not need to call it explicitely. - * - */ - void garbageCollect() noexcept; /** * @brief Set the oversampling factor to a new value. @@ -551,8 +493,8 @@ public: */ void disableFreeWheeling() noexcept; - Resources& getResources() noexcept { return resources; } - const Resources& getResources() const noexcept { return resources; } + Resources& getResources() noexcept; + const Resources& getResources() const noexcept; /** * @brief Check if the SFZ should be reloaded. @@ -604,26 +546,26 @@ public: * * @return A reference to the parser. */ - Parser& getParser() noexcept { return parser; } + Parser& getParser() noexcept; /** * @brief Get the parser. * * @return A reference to the parser. */ - const Parser& getParser() const noexcept { return parser; } + const Parser& getParser() const noexcept; /** * @brief Get the key labels, if any * * @return const std::vector& */ - const std::vector& getKeyLabels() const noexcept { return keyLabels; } + const std::vector& getKeyLabels() const noexcept; /** * @brief Get the CC labels, if any * * @return const std::vector& */ - const std::vector& getCCLabels() const noexcept { return ccLabels; } + const std::vector& getCCLabels() const noexcept; /** * @brief Get the used CCs @@ -632,332 +574,9 @@ public: */ std::bitset getUsedCCs() const noexcept; -protected: - /** - * @brief The voice callback which is called during a change of state. - */ - void onVoiceStateChanged(NumericId idNumber, Voice::State state) override; - -protected: - /** - * @brief The parser callback; this is called by the parent object each time - * a new region, group, master, global, curve or control set of opcodes - * appears in the parser - * - * @param header the header for the set of opcodes - * @param members the opcode members - */ - void onParseFullBlock(const std::string& header, const std::vector& members) override; - - /** - * @brief The parser callback when an error occurs. - */ - void onParseError(const SourceRange& range, const std::string& message) override; - - /** - * @brief The parser callback when a warning occurs. - */ - void onParseWarning(const SourceRange& range, const std::string& message) override; - private: - /** - * @brief change the group maximum polyphony - * - * @param groupIdx the group index - * @param polyphone the max polyphony - */ - void setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept; - - /** - * @brief Reset all CCs; to be used on CC 121 - * - * @param delay the delay for the controller reset - * - */ - void resetAllControllers(int delay) noexcept; - - int numGroups { 0 }; - int numMasters { 0 }; - - /** - * @brief Remove all regions, resets all voices and clears everything - * to bring back the synth in its original state. - * - * The callback mutex should be taken to call this function. - */ - void clear(); - - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleGlobalOpcodes(const std::vector& members); - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleMasterOpcodes(const std::vector& members); - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleGroupOpcodes(const std::vector& members, const std::vector& masterMembers); - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleControlOpcodes(const std::vector& members); - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleEffectOpcodes(const std::vector& members); - /** - * @brief Helper function to merge all the currently active opcodes - * as set by the successive callbacks and create a new region to store - * in the synth. - * - * @param regionOpcodes the opcodes that are specific to the region - */ - void buildRegion(const std::vector& regionOpcodes); - /** - * @brief Resets and possibly changes the number of voices (polyphony) in - * the synth. - * - * @param numVoices - */ - void resetVoices(int numVoices); - /** - * @brief Make the stored settings take effect in all the voices - */ - void applySettingsPerVoice(); - - /** - * @brief Establish all connections of the modulation matrix. - */ - void setupModMatrix(); - - /** - * @brief Get the modification time of all included sfz files - * - * @return fs::file_time_type - */ - fs::file_time_type checkModificationTime(); - - /** - * @brief Check all regions and start voices for note on events - * - * @param delay - * @param noteNumber - * @param velocity - */ - void noteOnDispatch(int delay, int noteNumber, float velocity) noexcept; - - /** - * @brief Check all regions and start voices for note off events - * - * @param delay - * @param noteNumber - * @param velocity - */ - void noteOffDispatch(int delay, int noteNumber, float velocity) noexcept; - - /** - * @brief Check all regions and start voices for cc events - * - * @param delay - * @param ccNumber - * @param value - */ - void ccDispatch(int delay, int ccNumber, float value) noexcept; - - template - static void updateUsedCCsFromCCMap(std::bitset& usedCCs, const CCMap map) - { - for (auto& mod : map) - usedCCs[mod.cc] = true; - } - static void updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); - static void updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); - - // Opcode memory; these are used to build regions, as a new region - // will integrate opcodes from the group, master and global block - std::vector globalOpcodes; - std::vector masterOpcodes; - std::vector groupOpcodes; - - /** - * @brief Find a voice that is not currently playing - * - * @return Voice* - */ - Voice* findFreeVoice() noexcept; - - // Names for the CC and notes as set by label_cc and label_key - std::vector ccLabels; - std::vector keyLabels; - std::vector keyswitchLabels; - - // Set as sw_default if present in the file - absl::optional currentSwitch; - std::vector unknownOpcodes; - using RegionViewVector = std::vector; - using VoiceViewVector = std::vector; - using VoicePtr = std::unique_ptr; - using RegionPtr = std::unique_ptr; - using RegionSetPtr = std::unique_ptr; - std::vector regions; - std::vector voices; - - // These are more general "groups" than sfz and encapsulates the full hierarchy - RegionSet* currentSet { nullptr }; - std::vector sets; - // This region set holds the engine set of voices, which tries to respect the required - // engine polyphony - RegionSetPtr engineSet; - - // These are the `group=` groups where you can off voices - std::vector polyphonyGroups; - - // Views to speed up iteration over the regions and voices when events - // occur in the audio callback - VoiceViewVector tempPolyphonyArray; - VoiceViewVector voiceViewArray; - VoiceStealing stealer; - - /** - * @brief Check the region polyphony, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkRegionPolyphony(const Region* region, int delay) noexcept; - - /** - * @brief Check the note polyphony, releasing voices if necessary - * - * @param region - * @param delay - * @param triggerEvent - */ - void checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept; - - /** - * @brief Check the group polyphony, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkGroupPolyphony(const Region* region, int delay) noexcept; - - /** - * @brief Check the region set polyphony at all levels, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkSetPolyphony(const Region* region, int delay) noexcept; - - /** - * @brief Check the engine polyphony, fast releasing voices if necessary - * - * @param delay - */ - void checkEnginePolyphony(int delay) noexcept; - - /** - * @brief Start a voice for a specific region. - * This will do the needed polyphony checks and voice stealing. - * - * @param region - * @param delay - * @param triggerEvent - * @param ring - */ - void startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept; - - /** - * @brief Start all delayed release voices of the region if necessary - * - * @param region - * @param delay - * @param ring - */ - void startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept; - - /** - * @brief Check if a playing voice matches the release region - * - * @param releaseRegion - * @return true - * @return false - */ - bool playingAttackVoice(const Region* releaseRegion) noexcept; - - std::array lastKeyswitchLists; - std::array downKeyswitchLists; - std::array upKeyswitchLists; - RegionViewVector previousKeyswitchLists; - std::array noteActivationLists; - std::array ccActivationLists; - - // Effect factory and buses - EffectFactory effectFactory; - typedef std::unique_ptr EffectBusPtr; - std::vector effectBuses; // 0 is "main", 1-N are "fx1"-"fxN" - - int samplesPerBlock { config::defaultSamplesPerBlock }; - float sampleRate { config::defaultSampleRate }; - float volume { Default::globalVolume }; - int numRequiredVoices { config::numVoices }; - int numActualVoices { static_cast(config::numVoices * config::overflowVoiceMultiplier) }; - int activeVoices { 0 }; - Oversampling oversamplingFactor { config::defaultOversamplingFactor }; - - // Distribution used to generate random value for the *rand opcodes - std::uniform_real_distribution randNoteDistribution { 0, 1 }; - - SpinMutex callbackGuard; - - // Singletons passed as references to the voices - Resources resources; - - // Control opcodes - std::string defaultPath { "" }; - int noteOffset { 0 }; - int octaveOffset { 0 }; - - // Modulation source generators - std::unique_ptr genController; - std::unique_ptr genLFO; - std::unique_ptr genFlexEnvelope; - std::unique_ptr genADSREnvelope; - - // Settings per voice - struct SettingsPerVoice { - size_t maxFilters { 0 }; - size_t maxEQs { 0 }; - size_t maxLFOs { 0 }; - size_t maxFlexEGs { 0 }; - bool havePitchEG { false }; - bool haveFilterEG { false }; - }; - SettingsPerVoice settingsPerVoice; - - // Controller initial values - std::array ccInitialValues; - - Duration dispatchDuration { 0 }; - - std::chrono::time_point lastGarbageCollection; - - Parser parser; - fs::file_time_type modificationTime { }; + struct Impl; + std::unique_ptr impl_; LEAK_DETECTOR(Synth); }; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 3b2ee301..7f5faadc 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -4,58 +4,345 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "Voice.h" -#include "Macros.h" +#include "absl/algorithm/container.h" +#include "absl/types/span.h" +#include "AudioBuffer.h" +#include "Config.h" #include "Defaults.h" -#include "ModifierHelpers.h" -#include "MathHelpers.h" -#include "SIMDHelpers.h" -#include "Panning.h" -#include "SfzHelpers.h" -#include "LFO.h" +#include "EQPool.h" +#include "FilterPool.h" #include "FlexEnvelope.h" +#include "HistoricalBuffer.h" +#include "Interpolators.h" +#include "LFO.h" +#include "Macros.h" +#include "MathHelpers.h" +#include "ModifierHelpers.h" #include "modulations/ModId.h" #include "modulations/ModKey.h" #include "modulations/ModMatrix.h" -#include "Interpolators.h" -#include "absl/algorithm/container.h" +#include "OnePoleFilter.h" +#include "Panning.h" +#include "PowerFollower.h" +#include "SfzHelpers.h" +#include "SIMDHelpers.h" +#include "Smoothers.h" +#include "Voice.h" +#include -sfz::Voice::Voice(int voiceNumber, sfz::Resources& resources) -: id{voiceNumber}, stateListener(nullptr), resources(resources) +namespace sfz { + +struct Voice::Impl +{ + Impl() = delete; + Impl(int voiceNumber, Resources& resources); + /** + * @brief Fill a span with data from a file source. This is the first step + * in rendering each block of data. + * + * @param buffer + */ + void fillWithData(AudioSpan buffer) noexcept; + /** + * @brief Fill a span with data from a generator source. This is the first step + * in rendering each block of data. + * + * @param buffer + */ + void fillWithGenerator(AudioSpan buffer) noexcept; + + /** + * @brief Fill a destination with an interpolated source. + * + * @param source the source sample + * @param dest the destination buffer + * @param indices the integral parts of the source positions + * @param coeffs the fractional parts of the source positions + */ + template + static void fillInterpolated( + const AudioSpan& source, const AudioSpan& dest, + absl::Span indices, absl::Span coeffs, + absl::Span addingGains); + + /** + * @brief Fill a destination with an interpolated source, selecting + * interpolation type dynamically by quality level. + * + * @param source the source sample + * @param dest the destination buffer + * @param indices the integral parts of the source positions + * @param coeffs the fractional parts of the source positions + * @param quality the quality level 1-10 + */ + template + static void fillInterpolatedWithQuality( + const AudioSpan& source, const AudioSpan& dest, + absl::Span indices, absl::Span coeffs, + absl::Span addingGains, int quality); + + /** + * @brief Get a S-shaped curve that is applicable to loop crossfading. + */ + static const Curve& getSCurve(); + + /** + * @brief Compute the amplitude envelope, applied as a gain to a mono + * or stereo buffer + * + * @param modulationSpan + */ + void amplitudeEnvelope(absl::Span modulationSpan) noexcept; + + /** + * @brief Apply the crossfade envelope to a span. + * + * @param modulationSpan + */ + void applyCrossfades(absl::Span modulationSpan) noexcept; + void resetCrossfades() noexcept; + + /** + * @brief Amplitude stage for a mono source + * + * @param buffer + */ + void ampStageMono(AudioSpan buffer) noexcept; + /** + * @brief Amplitude stage for a stereo source + * + * @param buffer + */ + void ampStageStereo(AudioSpan buffer) noexcept; + /** + * @brief Amplitude stage for a mono source + * + * @param buffer + */ + void panStageMono(AudioSpan buffer) noexcept; + void panStageStereo(AudioSpan buffer) noexcept; + /** + * @brief Amplitude stage for a mono source + * + * @param buffer + */ + void filterStageMono(AudioSpan buffer) noexcept; + void filterStageStereo(AudioSpan buffer) noexcept; + /** + * @brief Compute the pitch envelope. This envelope is meant to multiply + * the frequency parameter for each sample (which translates to floating + * point intervals for sample-based voices, or phases for generators) + * + * @param pitchSpan + */ + void pitchEnvelope(absl::Span pitchSpan) noexcept; + + /** + * @brief Initialize frequency and gain coefficients for the oscillators. + */ + void setupOscillatorUnison(); + void updateChannelPowers(AudioSpan buffer); + + /** + * @brief Modify the voice state and notify any listeners. + */ + void switchState(State s); + + /** + * @brief Save the modulation targets to avoid recomputing them in every callback. + * Must be called during startVoice() ideally. + */ + void saveModulationTargets(const Region* region) noexcept; + + /** + * @brief Get the sample quality determined by the active region. + * + * @return int + */ + int getCurrentSampleQuality() const noexcept; + /** + * @brief Reset the loop information + * + */ + void resetLoopInformation() noexcept; + /** + * @brief Read the loop information data from the region. + * This requires that the region and promise is properly set. + * + */ + void updateLoopInformation() noexcept; + + const NumericId id_; + StateListener* stateListener_ = nullptr; + + Region* region_ { nullptr }; + + State state_ { State::idle }; + bool noteIsOff_ { false }; + + TriggerEvent triggerEvent_; + absl::optional triggerDelay_; + + float speedRatio_ { 1.0 }; + float pitchRatio_ { 1.0 }; + float baseVolumedB_ { 0.0 }; + float baseGain_ { 1.0 }; + float baseFrequency_ { 440.0 }; + + float floatPositionOffset_ { 0.0f }; + int sourcePosition_ { 0 }; + int initialDelay_ { 0 }; + int age_ { 0 }; + struct { + int start { 0 }; + int end { 0 }; + int size { 0 }; + int xfSize { 0 }; + int xfOutStart { 0 }; + int xfInStart { 0 }; + } loop_; + + FileDataHolder currentPromise_; + + int samplesPerBlock_ { config::defaultSamplesPerBlock }; + float sampleRate_ { config::defaultSampleRate }; + + Resources& resources_; + + std::vector filters_; + std::vector equalizers_; + std::vector> lfos_; + std::vector> flexEGs_; + + ADSREnvelope egAmplitude_; + std::unique_ptr> egPitch_; + std::unique_ptr> egFilter_; + float bendStepFactor_ { centsFactor(1) }; + + WavetableOscillator waveOscillators_[config::oscillatorsPerVoice]; + + // unison of oscillators + unsigned waveUnisonSize_ { 0 }; + float waveDetuneRatio_[config::oscillatorsPerVoice] {}; + float waveLeftGain_[config::oscillatorsPerVoice] {}; + float waveRightGain_[config::oscillatorsPerVoice] {}; + + Duration dataDuration_; + Duration amplitudeDuration_; + Duration panningDuration_; + Duration filterDuration_; + + fast_real_distribution uniformNoiseDist_ { -config::uniformNoiseBounds, config::uniformNoiseBounds }; + fast_gaussian_generator gaussianNoiseDist_ { 0.0f, config::noiseVariance }; + + Smoother gainSmoother_; + Smoother bendSmoother_; + Smoother xfadeSmoother_; + void resetSmoothers() noexcept; + + ModMatrix::TargetId masterAmplitudeTarget_; + ModMatrix::TargetId amplitudeTarget_; + ModMatrix::TargetId volumeTarget_; + ModMatrix::TargetId panTarget_; + ModMatrix::TargetId positionTarget_; + ModMatrix::TargetId widthTarget_; + ModMatrix::TargetId pitchTarget_; + ModMatrix::TargetId oscillatorDetuneTarget_; + ModMatrix::TargetId oscillatorModDepthTarget_; + + bool followPower_ { false }; + PowerFollower powerFollower_; +}; + +Voice::Voice(int voiceNumber, Resources& resources) +: impl_(new Impl(voiceNumber, resources)) +{ + +} + +// Need to define the dtor after Impl has been defined +Voice::~Voice() +{ + +} + +Voice::Voice(Voice&& other) { + ASSERT(other.impl_); + impl_ = std::move(other.impl_); + + if (other.nextSisterVoice_ != &other) { + nextSisterVoice_ = other.nextSisterVoice_; + other.nextSisterVoice_ = &other; + nextSisterVoice_->setPreviousSisterVoice(this); + } else { + nextSisterVoice_ = this; + } + + if (other.previousSisterVoice_ != &other) { + previousSisterVoice_ = other.previousSisterVoice_; + other.previousSisterVoice_ = &other; + previousSisterVoice_->setNextSisterVoice(this); + } else { + previousSisterVoice_ = this; + } +} + +Voice& Voice::operator=(Voice&& other) { + ASSERT(other.impl_); + impl_ = std::move(other.impl_); + + if (other.nextSisterVoice_ != &other) { + nextSisterVoice_ = other.nextSisterVoice_; + other.nextSisterVoice_ = &other; + nextSisterVoice_->setPreviousSisterVoice(this); + } else { + nextSisterVoice_ = this; + } + + if (other.previousSisterVoice_ != &other) { + previousSisterVoice_ = other.previousSisterVoice_; + other.previousSisterVoice_ = &other; + previousSisterVoice_->setNextSisterVoice(this); + } else { + previousSisterVoice_ = this; + } + + return *this; +} + +Voice::Impl::Impl(int voiceNumber, Resources& resources) +: id_ { voiceNumber }, stateListener_(nullptr), resources_(resources) { for (unsigned i = 0; i < config::filtersPerVoice; ++i) - filters.emplace_back(resources); + filters_.emplace_back(resources); for (unsigned i = 0; i < config::eqsPerVoice; ++i) - equalizers.emplace_back(resources); + equalizers_.emplace_back(resources); - for (WavetableOscillator& osc : waveOscillators) - osc.init(sampleRate); + for (WavetableOscillator& osc : waveOscillators_) + osc.init(sampleRate_); - gainSmoother.setSmoothing(config::gainSmoothing, sampleRate); - xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate); + gainSmoother_.setSmoothing(config::gainSmoothing, sampleRate_); + xfadeSmoother_.setSmoothing(config::xfadeSmoothing, sampleRate_); // prepare curves getSCurve(); } -sfz::Voice::~Voice() -{ -} - -void sfz::Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noexcept +void Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noexcept { + Impl& impl = *impl_; ASSERT(event.value >= 0.0f && event.value <= 1.0f); - this->region = region; + impl.region_ = region; if (region->disabled()) return; - triggerEvent = event; - if (triggerEvent.type == TriggerEventType::CC) - triggerEvent.number = region->pitchKeycenter; + impl.triggerEvent_ = event; + if (impl.triggerEvent_.type == TriggerEventType::CC) + impl.triggerEvent_.number = region->pitchKeycenter; - switchState(State::playing); + impl.switchState(State::playing); ASSERT(delay >= 0); if (delay < 0) @@ -64,116 +351,125 @@ 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 = impl.resources_.wavePool.getFileWave(region->sampleId->filename()); else { switch (hash(region->sampleId->filename())) { default: case hash("*silence"): break; case hash("*sine"): - wave = resources.wavePool.getWaveSin(); + wave = impl.resources_.wavePool.getWaveSin(); break; case hash("*triangle"): // fallthrough case hash("*tri"): - wave = resources.wavePool.getWaveTriangle(); + wave = impl.resources_.wavePool.getWaveTriangle(); break; case hash("*square"): - wave = resources.wavePool.getWaveSquare(); + wave = impl.resources_.wavePool.getWaveSquare(); break; case hash("*saw"): - wave = resources.wavePool.getWaveSaw(); + wave = impl.resources_.wavePool.getWaveSaw(); break; } } const float phase = region->getPhase(); const int quality = region->oscillatorQuality.value_or(Default::oscillatorQuality); - for (WavetableOscillator& osc : waveOscillators) { + for (WavetableOscillator& osc : impl.waveOscillators_) { osc.setWavetable(wave); osc.setPhase(phase); osc.setQuality(quality); } - setupOscillatorUnison(); + impl.setupOscillatorUnison(); } else { - currentPromise = resources.filePool.getFilePromise(region->sampleId); - if (!currentPromise) { - switchState(State::cleanMeUp); + impl.currentPromise_ = impl.resources_.filePool.getFilePromise(region->sampleId); + if (!impl.currentPromise_) { + impl.switchState(State::cleanMeUp); return; } - updateLoopInformation(); - speedRatio = static_cast(currentPromise->information.sampleRate / this->sampleRate); - sourcePosition = region->getOffset(resources.filePool.getOversamplingFactor()); + impl.updateLoopInformation(); + impl.speedRatio_ = static_cast(impl.currentPromise_->information.sampleRate / impl.sampleRate_); + impl.sourcePosition_ = region->getOffset(impl.resources_.filePool.getOversamplingFactor()); } // do Scala retuning and reconvert the frequency into a 12TET key number - const float numberRetuned = resources.tuning.getKeyFractional12TET(triggerEvent.number); + const float numberRetuned = impl.resources_.tuning.getKeyFractional12TET(impl.triggerEvent_.number); - pitchRatio = region->getBasePitchVariation(numberRetuned, triggerEvent.value); + impl.pitchRatio_ = region->getBasePitchVariation(numberRetuned, impl.triggerEvent_.value); // apply stretch tuning if set - if (resources.stretch) - pitchRatio *= resources.stretch->getRatioForFractionalKey(numberRetuned); + if (impl.resources_.stretch) + impl.pitchRatio_ *= impl.resources_.stretch->getRatioForFractionalKey(numberRetuned); - baseVolumedB = region->getBaseVolumedB(triggerEvent.number); - baseGain = region->getBaseGain(); - if (triggerEvent.type != TriggerEventType::CC) - baseGain *= region->getNoteGain(triggerEvent.number, triggerEvent.value); - gainSmoother.reset(); - resetCrossfades(); + impl.baseVolumedB_ = region->getBaseVolumedB(impl.triggerEvent_.number); + impl.baseGain_ = region->getBaseGain(); + if (impl.triggerEvent_.type != TriggerEventType::CC) + impl.baseGain_ *= region->getNoteGain(impl.triggerEvent_.number, impl.triggerEvent_.value); + impl.gainSmoother_.reset(); + impl.resetCrossfades(); for (unsigned i = 0; i < region->filters.size(); ++i) { - filters[i].setup(*region, i, triggerEvent.number, triggerEvent.value); + impl.filters_[i].setup(*region, i, impl.triggerEvent_.number, impl.triggerEvent_.value); } for (unsigned i = 0; i < region->equalizers.size(); ++i) { - equalizers[i].setup(*region, i, triggerEvent.value); + impl.equalizers_[i].setup(*region, i, impl.triggerEvent_.value); } - triggerDelay = delay; - initialDelay = delay + static_cast(region->getDelay() * sampleRate); - baseFrequency = resources.tuning.getFrequencyOfKey(triggerEvent.number); - bendStepFactor = centsFactor(region->bendStep); - bendSmoother.setSmoothing(region->bendSmooth, sampleRate); - bendSmoother.reset(centsFactor(region->getBendInCents(resources.midiState.getPitchBend()))); + impl.triggerDelay_ = delay; + impl.initialDelay_ = delay + static_cast(region->getDelay() * impl.sampleRate_); + impl.baseFrequency_ = impl.resources_.tuning.getFrequencyOfKey(impl.triggerEvent_.number); + impl.bendStepFactor_ = centsFactor(region->bendStep); + impl.bendSmoother_.setSmoothing(region->bendSmooth, impl.sampleRate_); + impl.bendSmoother_.reset(centsFactor(region->getBendInCents(impl.resources_.midiState.getPitchBend()))); - resources.modMatrix.initVoice(id, region->getId(), delay); - saveModulationTargets(region); + impl.resources_.modMatrix.initVoice(impl.id_, region->getId(), delay); + impl.saveModulationTargets(region); } -int sfz::Voice::getCurrentSampleQuality() const noexcept +int Voice::Impl::getCurrentSampleQuality() const noexcept { - return (region && region->sampleQuality) ? - *region->sampleQuality : resources.synthConfig.currentSampleQuality(); + return (region_ && region_->sampleQuality) ? + *region_->sampleQuality : resources_.synthConfig.currentSampleQuality(); } -bool sfz::Voice::isFree() const noexcept +int Voice::getCurrentSampleQuality() const noexcept { - return (state == State::idle); + Impl& impl = *impl_; + return impl.getCurrentSampleQuality(); } -void sfz::Voice::release(int delay) noexcept +bool Voice::isFree() const noexcept { - if (state != State::playing) + Impl& impl = *impl_; + return (impl.state_ == State::idle); +} + +void Voice::release(int delay) noexcept +{ + Impl& impl = *impl_; + if (impl.state_ != State::playing) return; - if (!region->flexAmpEG) { - if (egAmplitude.getRemainingDelay() > delay) - switchState(State::cleanMeUp); + if (!impl.region_->flexAmpEG) { + if (impl.egAmplitude_.getRemainingDelay() > delay) + impl.switchState(State::cleanMeUp); } else { - if (flexEGs[*region->flexAmpEG]->getRemainingDelay() > static_cast(delay)) - switchState(State::cleanMeUp); + if (impl.flexEGs_[*impl.region_->flexAmpEG]->getRemainingDelay() > static_cast(delay)) + impl.switchState(State::cleanMeUp); } - resources.modMatrix.releaseVoice(id, region->getId(), delay); + impl.resources_.modMatrix.releaseVoice(impl.id_, impl.region_->getId(), delay); } -void sfz::Voice::off(int delay, bool fast) noexcept +void Voice::off(int delay, bool fast) noexcept { - if (!region->flexAmpEG) { - if (region->offMode == SfzOffMode::fast || fast) { - egAmplitude.setReleaseTime(Default::offTime); - } else if (region->offMode == SfzOffMode::time) { - egAmplitude.setReleaseTime(region->offTime); + Impl& impl = *impl_; + if (!impl.region_->flexAmpEG) { + if (impl.region_->offMode == SfzOffMode::fast || fast) { + impl.egAmplitude_.setReleaseTime(Default::offTime); + } else if (impl.region_->offMode == SfzOffMode::time) { + impl.egAmplitude_.setReleaseTime(impl.region_->offTime); } } else { @@ -183,136 +479,146 @@ void sfz::Voice::off(int delay, bool fast) noexcept release(delay); } -void sfz::Voice::registerNoteOff(int delay, int noteNumber, float velocity) noexcept +void Voice::registerNoteOff(int delay, int noteNumber, float velocity) noexcept { ASSERT(velocity >= 0.0 && velocity <= 1.0); UNUSED(velocity); + Impl& impl = *impl_; - if (region == nullptr) + if (impl.region_ == nullptr) return; - if (state != State::playing) + if (impl.state_ != State::playing) return; - if (triggerEvent.number == noteNumber && triggerEvent.type == TriggerEventType::NoteOn) { - noteIsOff = true; + if (impl.triggerEvent_.number == noteNumber && impl.triggerEvent_.type == TriggerEventType::NoteOn) { + impl.noteIsOff_ = true; - if (region->loopMode == SfzLoopMode::one_shot) + if (impl.region_->loopMode == SfzLoopMode::one_shot) return; - if (!region->checkSustain || resources.midiState.getCCValue(region->sustainCC) < region->sustainThreshold) + if (!impl.region_->checkSustain + || impl.resources_.midiState.getCCValue(impl.region_->sustainCC) < impl.region_->sustainThreshold) release(delay); } } -void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept +void Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept { ASSERT(ccValue >= 0.0 && ccValue <= 1.0); - if (region == nullptr) + Impl& impl = *impl_; + if (impl.region_ == nullptr) return; - if (state != State::playing) + if (impl.state_ != State::playing) return; - if (region->checkSustain && noteIsOff && ccNumber == region->sustainCC && ccValue < region->sustainThreshold) + if (impl.region_->checkSustain + && impl.noteIsOff_ + && ccNumber == impl.region_->sustainCC + && ccValue < impl.region_->sustainThreshold) release(delay); } -void sfz::Voice::registerPitchWheel(int delay, float pitch) noexcept +void Voice::registerPitchWheel(int delay, float pitch) noexcept { - if (state != State::playing) + Impl& impl = *impl_; + if (impl.state_ != State::playing) return; UNUSED(delay); UNUSED(pitch); } -void sfz::Voice::registerAftertouch(int delay, uint8_t aftertouch) noexcept +void Voice::registerAftertouch(int delay, uint8_t aftertouch) noexcept { // TODO UNUSED(delay); UNUSED(aftertouch); } -void sfz::Voice::registerTempo(int delay, float secondsPerQuarter) noexcept +void Voice::registerTempo(int delay, float secondsPerQuarter) noexcept { // TODO UNUSED(delay); UNUSED(secondsPerQuarter); } -void sfz::Voice::setSampleRate(float sampleRate) noexcept +void Voice::setSampleRate(float sampleRate) noexcept { - this->sampleRate = sampleRate; - gainSmoother.setSmoothing(config::gainSmoothing, sampleRate); - xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate); + Impl& impl = *impl_; + impl.sampleRate_ = sampleRate; + impl.gainSmoother_.setSmoothing(config::gainSmoothing, sampleRate); + impl.xfadeSmoother_.setSmoothing(config::xfadeSmoothing, sampleRate); - for (WavetableOscillator& osc : waveOscillators) + for (WavetableOscillator& osc : impl.waveOscillators_) osc.init(sampleRate); - for (auto& lfo : lfos) + for (auto& lfo : impl.lfos_) lfo->setSampleRate(sampleRate); - for (auto& filter : filters) + for (auto& filter : impl.filters_) filter.setSampleRate(sampleRate); - for (auto& eq : equalizers) + for (auto& eq : impl.equalizers_) eq.setSampleRate(sampleRate); - powerFollower.setSampleRate(sampleRate); + impl.powerFollower_.setSampleRate(sampleRate); } -void sfz::Voice::setSamplesPerBlock(int samplesPerBlock) noexcept +void Voice::setSamplesPerBlock(int samplesPerBlock) noexcept { - this->samplesPerBlock = samplesPerBlock; - powerFollower.setSamplesPerBlock(samplesPerBlock); + Impl& impl = *impl_; + impl.samplesPerBlock_ = samplesPerBlock; + impl.powerFollower_.setSamplesPerBlock(samplesPerBlock); } -void sfz::Voice::renderBlock(AudioSpan buffer) noexcept +void Voice::renderBlock(AudioSpan buffer) noexcept { - ASSERT(static_cast(buffer.getNumFrames()) <= samplesPerBlock); + Impl& impl = *impl_; + ASSERT(static_cast(buffer.getNumFrames()) <= impl.samplesPerBlock_); buffer.fill(0.0f); - if (region == nullptr) + if (impl.region_ == nullptr) return; - const auto delay = min(static_cast(initialDelay), buffer.getNumFrames()); + const auto delay = min(static_cast(impl.initialDelay_), buffer.getNumFrames()); auto delayed_buffer = buffer.subspan(delay); - initialDelay -= static_cast(delay); + impl.initialDelay_ -= static_cast(delay); { // Fill buffer with raw data - ScopedTiming logger { dataDuration }; - if (region->isOscillator()) - fillWithGenerator(delayed_buffer); + ScopedTiming logger { impl.dataDuration_ }; + if (impl.region_->isOscillator()) + impl.fillWithGenerator(delayed_buffer); else - fillWithData(delayed_buffer); + impl.fillWithData(delayed_buffer); } - if (region->isStereo()) { - ampStageStereo(buffer); - panStageStereo(buffer); - filterStageStereo(buffer); + if (impl.region_->isStereo()) { + impl.ampStageStereo(buffer); + impl.panStageStereo(buffer); + impl.filterStageStereo(buffer); } else { - ampStageMono(buffer); - filterStageMono(buffer); - panStageMono(buffer); + impl.ampStageMono(buffer); + impl.filterStageMono(buffer); + impl.panStageMono(buffer); } - if (!region->flexAmpEG) { - if (!egAmplitude.isSmoothing()) - switchState(State::cleanMeUp); + if (!impl.region_->flexAmpEG) { + if (!impl.egAmplitude_.isSmoothing()) + impl.switchState(State::cleanMeUp); } else { - if (flexEGs[*region->flexAmpEG]->isFinished()) - switchState(State::cleanMeUp); + if (impl.flexEGs_[*impl.region_->flexAmpEG]->isFinished()) + impl.switchState(State::cleanMeUp); } - powerFollower.process(buffer); + impl.powerFollower_.process(buffer); - age += buffer.getNumFrames(); - if (triggerDelay) { + impl.age_ += buffer.getNumFrames(); + if (impl.triggerDelay_) { // Should be OK but just in case; - age = min(age - *triggerDelay, 0); - triggerDelay = absl::nullopt; + impl.age_ = min(impl.age_ - *impl.triggerDelay_, 0); + impl.triggerDelay_ = absl::nullopt; } #if 0 @@ -323,31 +629,31 @@ void sfz::Voice::renderBlock(AudioSpan buffer) noexcept #endif } -void sfz::Voice::resetCrossfades() noexcept +void Voice::Impl::resetCrossfades() noexcept { float xfadeValue { 1.0f }; - const auto xfCurve = region->crossfadeCCCurve; + const auto xfCurve = region_->crossfadeCCCurve; - for (const auto& mod : region->crossfadeCCInRange) { - const auto value = resources.midiState.getCCValue(mod.cc); + for (const auto& mod : region_->crossfadeCCInRange) { + const auto value = resources_.midiState.getCCValue(mod.cc); xfadeValue *= crossfadeIn(mod.data, value, xfCurve); } - for (const auto& mod : region->crossfadeCCOutRange) { - const auto value = resources.midiState.getCCValue(mod.cc); + for (const auto& mod : region_->crossfadeCCOutRange) { + const auto value = resources_.midiState.getCCValue(mod.cc); xfadeValue *= crossfadeOut(mod.data, value, xfCurve); } - xfadeSmoother.reset(xfadeValue); + xfadeSmoother_.reset(xfadeValue); } -void sfz::Voice::applyCrossfades(absl::Span modulationSpan) noexcept +void Voice::Impl::applyCrossfades(absl::Span modulationSpan) noexcept { const auto numSamples = modulationSpan.size(); - const auto xfCurve = region->crossfadeCCCurve; + const auto xfCurve = region_->crossfadeCCCurve; - auto tempSpan = resources.bufferPool.getBuffer(numSamples); - auto xfadeSpan = resources.bufferPool.getBuffer(numSamples); + auto tempSpan = resources_.bufferPool.getBuffer(numSamples); + auto xfadeSpan = resources_.bufferPool.getBuffer(numSamples); if (!tempSpan || !xfadeSpan) return; @@ -355,8 +661,8 @@ void sfz::Voice::applyCrossfades(absl::Span modulationSpan) noexcept fill(*xfadeSpan, 1.0f); bool canShortcut = true; - for (const auto& mod : region->crossfadeCCInRange) { - const auto& events = resources.midiState.getCCEvents(mod.cc); + for (const auto& mod : region_->crossfadeCCInRange) { + const auto& events = resources_.midiState.getCCEvents(mod.cc); canShortcut &= (events.size() == 1); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.data, x, xfCurve); @@ -364,8 +670,8 @@ void sfz::Voice::applyCrossfades(absl::Span modulationSpan) noexcept applyGain(*tempSpan, *xfadeSpan); } - for (const auto& mod : region->crossfadeCCOutRange) { - const auto& events = resources.midiState.getCCEvents(mod.cc); + for (const auto& mod : region_->crossfadeCCOutRange) { + const auto& events = resources_.midiState.getCCEvents(mod.cc); canShortcut &= (events.size() == 1); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.data, x, xfCurve); @@ -373,48 +679,48 @@ void sfz::Voice::applyCrossfades(absl::Span modulationSpan) noexcept applyGain(*tempSpan, *xfadeSpan); } - xfadeSmoother.process(*xfadeSpan, *xfadeSpan, canShortcut); + xfadeSmoother_.process(*xfadeSpan, *xfadeSpan, canShortcut); applyGain(*xfadeSpan, modulationSpan); } -void sfz::Voice::amplitudeEnvelope(absl::Span modulationSpan) noexcept +void Voice::Impl::amplitudeEnvelope(absl::Span modulationSpan) noexcept { const auto numSamples = modulationSpan.size(); - ModMatrix& mm = resources.modMatrix; + ModMatrix& mm = resources_.modMatrix; // Amplitude EG - absl::Span ampegOut(mm.getModulation(masterAmplitudeTarget), numSamples); + absl::Span ampegOut(mm.getModulation(masterAmplitudeTarget_), numSamples); ASSERT(ampegOut.data()); copy(ampegOut, modulationSpan); // Amplitude envelope - applyGain1(baseGain, modulationSpan); - if (float* mod = mm.getModulation(amplitudeTarget)) { + applyGain1(baseGain_, modulationSpan); + if (float* mod = mm.getModulation(amplitudeTarget_)) { for (size_t i = 0; i < numSamples; ++i) modulationSpan[i] *= normalizePercents(mod[i]); } // Volume envelope - applyGain1(db2mag(baseVolumedB), modulationSpan); - if (float* mod = mm.getModulation(volumeTarget)) { + applyGain1(db2mag(baseVolumedB_), modulationSpan); + if (float* mod = mm.getModulation(volumeTarget_)) { for (size_t i = 0; i < numSamples; ++i) modulationSpan[i] *= db2mag(mod[i]); } // Smooth the gain transitions - gainSmoother.process(modulationSpan, modulationSpan); + gainSmoother_.process(modulationSpan, modulationSpan); } -void sfz::Voice::ampStageMono(AudioSpan buffer) noexcept +void Voice::Impl::ampStageMono(AudioSpan buffer) noexcept { - ScopedTiming logger { amplitudeDuration }; + ScopedTiming logger { amplitudeDuration_ }; const auto numSamples = buffer.getNumFrames(); const auto leftBuffer = buffer.getSpan(0); - auto modulationSpan = resources.bufferPool.getBuffer(numSamples); + auto modulationSpan = resources_.bufferPool.getBuffer(numSamples); if (!modulationSpan) return; @@ -423,12 +729,12 @@ void sfz::Voice::ampStageMono(AudioSpan buffer) noexcept applyGain(*modulationSpan, leftBuffer); } -void sfz::Voice::ampStageStereo(AudioSpan buffer) noexcept +void Voice::Impl::ampStageStereo(AudioSpan buffer) noexcept { - ScopedTiming logger { amplitudeDuration }; + ScopedTiming logger { amplitudeDuration_ }; const auto numSamples = buffer.getNumFrames(); - auto modulationSpan = resources.bufferPool.getBuffer(numSamples); + auto modulationSpan = resources_.bufferPool.getBuffer(numSamples); if (!modulationSpan) return; @@ -437,63 +743,63 @@ void sfz::Voice::ampStageStereo(AudioSpan buffer) noexcept buffer.applyGain(*modulationSpan); } -void sfz::Voice::panStageMono(AudioSpan buffer) noexcept +void Voice::Impl::panStageMono(AudioSpan buffer) noexcept { - ScopedTiming logger { panningDuration }; + ScopedTiming logger { panningDuration_ }; const auto numSamples = buffer.getNumFrames(); const auto leftBuffer = buffer.getSpan(0); const auto rightBuffer = buffer.getSpan(1); - auto modulationSpan = resources.bufferPool.getBuffer(numSamples); + auto modulationSpan = resources_.bufferPool.getBuffer(numSamples); if (!modulationSpan) return; - ModMatrix& mm = resources.modMatrix; + ModMatrix& mm = resources_.modMatrix; // Prepare for stereo output copy(leftBuffer, rightBuffer); // Apply panning - fill(*modulationSpan, region->pan); - if (float* mod = mm.getModulation(panTarget)) { + fill(*modulationSpan, region_->pan); + if (float* mod = mm.getModulation(panTarget_)) { for (size_t i = 0; i < numSamples; ++i) (*modulationSpan)[i] += normalizePercents(mod[i]); } pan(*modulationSpan, leftBuffer, rightBuffer); } -void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept +void Voice::Impl::panStageStereo(AudioSpan buffer) noexcept { - ScopedTiming logger { panningDuration }; + ScopedTiming logger { panningDuration_ }; const auto numSamples = buffer.getNumFrames(); const auto leftBuffer = buffer.getSpan(0); const auto rightBuffer = buffer.getSpan(1); - auto modulationSpan = resources.bufferPool.getBuffer(numSamples); + auto modulationSpan = resources_.bufferPool.getBuffer(numSamples); if (!modulationSpan) return; - ModMatrix& mm = resources.modMatrix; + ModMatrix& mm = resources_.modMatrix; // Apply panning - fill(*modulationSpan, region->pan); - if (float* mod = mm.getModulation(panTarget)) { + fill(*modulationSpan, region_->pan); + if (float* mod = mm.getModulation(panTarget_)) { for (size_t i = 0; i < numSamples; ++i) (*modulationSpan)[i] += normalizePercents(mod[i]); } pan(*modulationSpan, leftBuffer, rightBuffer); // Apply the width/position process - fill(*modulationSpan, region->width); - if (float* mod = mm.getModulation(widthTarget)) { + fill(*modulationSpan, region_->width); + if (float* mod = mm.getModulation(widthTarget_)) { for (size_t i = 0; i < numSamples; ++i) (*modulationSpan)[i] += normalizePercents(mod[i]); } width(*modulationSpan, leftBuffer, rightBuffer); - fill(*modulationSpan, region->position); - if (float* mod = mm.getModulation(positionTarget)) { + fill(*modulationSpan, region_->position); + if (float* mod = mm.getModulation(positionTarget_)) { for (size_t i = 0; i < numSamples; ++i) (*modulationSpan)[i] += normalizePercents(mod[i]); } @@ -504,25 +810,25 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept applyGain1(1.4125375446227544f, rightBuffer); } -void sfz::Voice::filterStageMono(AudioSpan buffer) noexcept +void Voice::Impl::filterStageMono(AudioSpan buffer) noexcept { - ScopedTiming logger { filterDuration }; + ScopedTiming logger { filterDuration_ }; const auto numSamples = buffer.getNumFrames(); const auto leftBuffer = buffer.getSpan(0); const float* inputChannel[1] { leftBuffer.data() }; float* outputChannel[1] { leftBuffer.data() }; - for (unsigned i = 0; i < region->filters.size(); ++i) { - filters[i].process(inputChannel, outputChannel, numSamples); + for (unsigned i = 0; i < region_->filters.size(); ++i) { + filters_[i].process(inputChannel, outputChannel, numSamples); } - for (unsigned i = 0; i < region->equalizers.size(); ++i) { - equalizers[i].process(inputChannel, outputChannel, numSamples); + for (unsigned i = 0; i < region_->equalizers.size(); ++i) { + equalizers_[i].process(inputChannel, outputChannel, numSamples); } } -void sfz::Voice::filterStageStereo(AudioSpan buffer) noexcept +void Voice::Impl::filterStageStereo(AudioSpan buffer) noexcept { - ScopedTiming logger { filterDuration }; + ScopedTiming logger { filterDuration_ }; const auto numSamples = buffer.getNumFrames(); const auto leftBuffer = buffer.getSpan(0); const auto rightBuffer = buffer.getSpan(1); @@ -530,52 +836,52 @@ void sfz::Voice::filterStageStereo(AudioSpan buffer) noexcept const float* inputChannels[2] { leftBuffer.data(), rightBuffer.data() }; float* outputChannels[2] { leftBuffer.data(), rightBuffer.data() }; - for (unsigned i = 0; i < region->filters.size(); ++i) { - filters[i].process(inputChannels, outputChannels, numSamples); + for (unsigned i = 0; i < region_->filters.size(); ++i) { + filters_[i].process(inputChannels, outputChannels, numSamples); } - for (unsigned i = 0; i < region->equalizers.size(); ++i) { - equalizers[i].process(inputChannels, outputChannels, numSamples); + for (unsigned i = 0; i < region_->equalizers.size(); ++i) { + equalizers_[i].process(inputChannels, outputChannels, numSamples); } } -void sfz::Voice::fillWithData(AudioSpan buffer) noexcept +void Voice::Impl::fillWithData(AudioSpan buffer) noexcept { const auto numSamples = buffer.getNumFrames(); if (numSamples == 0) return; - if (!currentPromise) { + if (!currentPromise_) { DBG("[Voice] Missing promise during fillWithData"); return; } - auto source = currentPromise->getData(); + auto source = currentPromise_->getData(); // calculate interpolation data // indices: integral position in the source audio // coeffs: fractional position normalized 0-1 - auto coeffs = resources.bufferPool.getBuffer(numSamples); - auto indices = resources.bufferPool.getIndexBuffer(numSamples); + auto coeffs = resources_.bufferPool.getBuffer(numSamples); + auto indices = resources_.bufferPool.getIndexBuffer(numSamples); if (!indices || !coeffs) return; { - auto jumps = resources.bufferPool.getBuffer(numSamples); + auto jumps = resources_.bufferPool.getBuffer(numSamples); if (!jumps) return; - fill(*jumps, pitchRatio * speedRatio); + fill(*jumps, pitchRatio_ * speedRatio_); pitchEnvelope(*jumps); - jumps->front() += floatPositionOffset; + jumps->front() += floatPositionOffset_; cumsum(*jumps, *jumps); sfzInterpolationCast(*jumps, *indices, *coeffs); - add1(sourcePosition, *indices); + add1(sourcePosition_, *indices); } // calculate loop characteristics - const auto loop = this->loop; - const bool isLooping = region->shouldLoop() + const auto loop = this->loop_; + const bool isLooping = region_->shouldLoop() && (static_cast(loop.end) < source.getNumFrames()); /* @@ -606,7 +912,7 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept numPartitions = 1; } else { for (auto& buf : partitionBuffers) { - buf = resources.bufferPool.getIndexBuffer(numSamples); + buf = resources_.bufferPool.getIndexBuffer(numSamples); if (!buf) return; } @@ -647,27 +953,27 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept else { // cut short the voice at the instant of reaching end of sample const auto sampleEnd = min( - static_cast(currentPromise->information.end), + static_cast(currentPromise_->information.end), static_cast(source.getNumFrames()) ) - 1; for (unsigned i = 0; i < numSamples; ++i) { if ((*indices)[i] >= sampleEnd) { #ifndef NDEBUG // Check for underflow - if (source.getNumFrames() - 1 < currentPromise->information.end) { + if (source.getNumFrames() - 1 < currentPromise_->information.end) { DBG("[sfizz] Underflow: source available samples " << source.getNumFrames() << "/" - << currentPromise->information.end - << " for sample " << *region->sampleId); + << currentPromise_->information.end + << " for sample " << *region_->sampleId); } #endif - if (!region->flexAmpEG) { - egAmplitude.setReleaseTime(0.0f); - egAmplitude.startRelease(i); + if (!region_->flexAmpEG) { + egAmplitude_.setReleaseTime(0.0f); + egAmplitude_.startRelease(i); } else { // TODO(jpc): Flex AmpEG - flexEGs[*region->flexAmpEG]->release(i); + flexEGs_[*region_->flexAmpEG]->release(i); } fill(indices->subspan(i), sampleEnd); fill(coeffs->subspan(i), 1.0f); @@ -695,9 +1001,9 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept source, ptBuffer, ptIndices, ptCoeffs, {}, quality); if (ptType == kPartitionLoopXfade) { - auto xfTemp1 = resources.bufferPool.getBuffer(numSamples); - auto xfTemp2 = resources.bufferPool.getBuffer(numSamples); - auto xfIndicesTemp = resources.bufferPool.getIndexBuffer(numSamples); + auto xfTemp1 = resources_.bufferPool.getBuffer(numSamples); + auto xfTemp2 = resources_.bufferPool.getBuffer(numSamples); + auto xfIndicesTemp = resources_.bufferPool.getIndexBuffer(numSamples); if (!xfTemp1 || !xfTemp2 || !xfIndicesTemp) return; @@ -721,7 +1027,7 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept xfCurve[i] = xfIn.evalNormalized(1.0f - xfCurvePos[i]); } else IF_CONSTEXPR (config::loopXfadeCurve == 1) { - const Curve& xfOut = resources.curves.getCurve(6); + const Curve& xfOut = resources_.curves.getCurve(6); for (unsigned i = 0; i < ptSize; ++i) xfCurve[i] = xfOut.evalNormalized(xfCurvePos[i]); } @@ -771,7 +1077,7 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept xfCurve[i] = xfIn.evalNormalized(xfInCurvePos[i]); } else IF_CONSTEXPR (config::loopXfadeCurve == 1) { - const Curve& xfIn = resources.curves.getCurve(5); + const Curve& xfIn = resources_.curves.getCurve(5); for (unsigned i = 0; i < applySize; ++i) xfCurve[i] = xfIn.evalNormalized(xfInCurvePos[i]); } @@ -787,8 +1093,8 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept } } - sourcePosition = indices->back(); - floatPositionOffset = coeffs->back(); + sourcePosition_ = indices->back(); + floatPositionOffset_ = coeffs->back(); #if 1 ASSERT(!hasNanInf(buffer.getConstSpan(0))); @@ -798,9 +1104,9 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept #endif } -template -void sfz::Voice::fillInterpolated( - const sfz::AudioSpan& source, const sfz::AudioSpan& dest, +template +void Voice::Impl::fillInterpolated( + const AudioSpan& source, const AudioSpan& dest, absl::Span indices, absl::Span coeffs, absl::Span addingGains) { @@ -811,7 +1117,7 @@ void sfz::Voice::fillInterpolated( auto left = dest.getChannel(0); if (source.getNumChannels() == 1) { while (ind < indices.end()) { - auto output = sfz::interpolate(&leftSource[*ind], *coeff); + auto output = interpolate(&leftSource[*ind], *coeff); IF_CONSTEXPR(Adding) { float g = *addingGain++; *left += g * output; @@ -824,8 +1130,8 @@ void sfz::Voice::fillInterpolated( auto right = dest.getChannel(1); auto rightSource = source.getConstSpan(1); while (ind < indices.end()) { - auto leftOutput = sfz::interpolate(&leftSource[*ind], *coeff); - auto rightOutput = sfz::interpolate(&rightSource[*ind], *coeff); + auto leftOutput = interpolate(&leftSource[*ind], *coeff); + auto rightOutput = interpolate(&rightSource[*ind], *coeff); IF_CONSTEXPR(Adding) { float g = *addingGain++; *left += g * leftOutput; @@ -841,8 +1147,8 @@ void sfz::Voice::fillInterpolated( } template -void sfz::Voice::fillInterpolatedWithQuality( - const sfz::AudioSpan& source, const sfz::AudioSpan& dest, +void Voice::Impl::fillInterpolatedWithQuality( + const AudioSpan& source, const AudioSpan& dest, absl::Span indices, absl::Span coeffs, absl::Span addingGains, int quality) { @@ -872,7 +1178,7 @@ void sfz::Voice::fillInterpolatedWithQuality( } } -const sfz::Curve& sfz::Voice::getSCurve() +const Curve& Voice::Impl::getSCurve() { static const Curve curve = []() -> Curve { constexpr unsigned N = Curve::NumValues; @@ -886,51 +1192,51 @@ const sfz::Curve& sfz::Voice::getSCurve() return curve; } -void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept +void Voice::Impl::fillWithGenerator(AudioSpan 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); + 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.... auto gen = [&]() { - return gaussianNoiseDist(); + return gaussianNoiseDist_(); }; absl::c_generate(leftSpan, gen); absl::c_generate(rightSpan, gen); } else { const auto numFrames = buffer.getNumFrames(); - auto frequencies = resources.bufferPool.getBuffer(numFrames); + auto frequencies = resources_.bufferPool.getBuffer(numFrames); if (!frequencies) return; - float keycenterFrequency = midiNoteFrequency(region->pitchKeycenter); - fill(*frequencies, pitchRatio * keycenterFrequency); + float keycenterFrequency = midiNoteFrequency(region_->pitchKeycenter); + fill(*frequencies, pitchRatio_ * keycenterFrequency); pitchEnvelope(*frequencies); - auto detuneSpan = resources.bufferPool.getBuffer(numFrames); + auto detuneSpan = resources_.bufferPool.getBuffer(numFrames); if (!detuneSpan) return; - const int oscillatorMode = region->oscillatorMode; - const int oscillatorMulti = region->oscillatorMulti; + const int oscillatorMode = region_->oscillatorMode; + const int oscillatorMulti = region_->oscillatorMulti; if (oscillatorMode <= 0 && oscillatorMulti < 2) { // single oscillator - auto tempSpan = resources.bufferPool.getBuffer(numFrames); + auto tempSpan = resources_.bufferPool.getBuffer(numFrames); if (!tempSpan) return; - WavetableOscillator& osc = waveOscillators[0]; + WavetableOscillator& osc = waveOscillators_[0]; fill(*detuneSpan, 1.0f); osc.processModulated(frequencies->data(), detuneSpan->data(), tempSpan->data(), buffer.getNumFrames()); copy(*tempSpan, leftSpan); @@ -938,30 +1244,30 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept } else if (oscillatorMode <= 0 && oscillatorMulti >= 3) { // unison oscillator - auto tempSpan = resources.bufferPool.getBuffer(numFrames); - auto tempLeftSpan = resources.bufferPool.getBuffer(numFrames); - auto tempRightSpan = resources.bufferPool.getBuffer(numFrames); + auto tempSpan = resources_.bufferPool.getBuffer(numFrames); + auto tempLeftSpan = resources_.bufferPool.getBuffer(numFrames); + auto tempRightSpan = resources_.bufferPool.getBuffer(numFrames); if (!tempSpan || !tempLeftSpan || !tempRightSpan) return; - const float* detuneMod = resources.modMatrix.getModulation(oscillatorDetuneTarget); - for (unsigned u = 0, uSize = waveUnisonSize; u < uSize; ++u) { - WavetableOscillator& osc = waveOscillators[u]; + const float* detuneMod = resources_.modMatrix.getModulation(oscillatorDetuneTarget_); + for (unsigned u = 0, uSize = waveUnisonSize_; u < uSize; ++u) { + WavetableOscillator& osc = waveOscillators_[u]; if (!detuneMod) - fill(*detuneSpan, waveDetuneRatio[u]); + fill(*detuneSpan, waveDetuneRatio_[u]); else { for (size_t i = 0; i < numFrames; ++i) (*detuneSpan)[i] = centsFactor(detuneMod[i]); - applyGain1(waveDetuneRatio[u], *detuneSpan); + applyGain1(waveDetuneRatio_[u], *detuneSpan); } osc.processModulated(frequencies->data(), detuneSpan->data(), tempSpan->data(), numFrames); if (u == 0) { - applyGain1(waveLeftGain[u], *tempSpan, *tempLeftSpan); - applyGain1(waveRightGain[u], *tempSpan, *tempRightSpan); + applyGain1(waveLeftGain_[u], *tempSpan, *tempLeftSpan); + applyGain1(waveRightGain_[u], *tempSpan, *tempRightSpan); } else { - multiplyAdd1(waveLeftGain[u], *tempSpan, *tempLeftSpan); - multiplyAdd1(waveRightGain[u], *tempSpan, *tempRightSpan); + multiplyAdd1(waveLeftGain_[u], *tempSpan, *tempLeftSpan); + multiplyAdd1(waveRightGain_[u], *tempSpan, *tempRightSpan); } } @@ -970,39 +1276,39 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept } else { // modulated oscillator - auto tempSpan = resources.bufferPool.getBuffer(numFrames); + auto tempSpan = resources_.bufferPool.getBuffer(numFrames); if (!tempSpan) return; - WavetableOscillator& oscCar = waveOscillators[0]; - WavetableOscillator& oscMod = waveOscillators[1]; + WavetableOscillator& oscCar = waveOscillators_[0]; + WavetableOscillator& oscMod = waveOscillators_[1]; // compute the modulator - auto modulatorSpan = resources.bufferPool.getBuffer(numFrames); + auto modulatorSpan = resources_.bufferPool.getBuffer(numFrames); if (!modulatorSpan) return; - const float* detuneMod = resources.modMatrix.getModulation(oscillatorDetuneTarget); + const float* detuneMod = resources_.modMatrix.getModulation(oscillatorDetuneTarget_); if (!detuneMod) - fill(*detuneSpan, waveDetuneRatio[1]); + fill(*detuneSpan, waveDetuneRatio_[1]); else { for (size_t i = 0; i < numFrames; ++i) (*detuneSpan)[i] = centsFactor(detuneMod[i]); - applyGain1(waveDetuneRatio[1], *detuneSpan); + applyGain1(waveDetuneRatio_[1], *detuneSpan); } oscMod.processModulated(frequencies->data(), detuneSpan->data(), modulatorSpan->data(), numFrames); // scale the modulator - const float oscillatorModDepth = region->oscillatorModDepth; + const float oscillatorModDepth = region_->oscillatorModDepth; if (oscillatorModDepth != 1.0f) applyGain1(oscillatorModDepth, *modulatorSpan); - const float* modDepthMod = resources.modMatrix.getModulation(oscillatorModDepthTarget); + const float* modDepthMod = resources_.modMatrix.getModulation(oscillatorModDepthTarget_); if (modDepthMod) multiplyMul1(0.01f, absl::MakeConstSpan(modDepthMod, numFrames), *modulatorSpan); // compute carrier×modulator - switch (region->oscillatorMode) { + switch (region_->oscillatorMode) { case 0: // RM synthesis default: fill(*detuneSpan, 1.0f); @@ -1036,14 +1342,15 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept #endif } -bool sfz::Voice::checkOffGroup(const Region* other, int delay, int noteNumber) noexcept +bool Voice::checkOffGroup(const Region* other, int delay, int noteNumber) noexcept { - if (region == nullptr || other == nullptr) + Impl& impl = *impl_; + if (impl.region_ == nullptr || other == nullptr) return false; - if (triggerEvent.type == TriggerEventType::NoteOn - && region->offBy == other->group - && (region->group != other->group || noteNumber != triggerEvent.number)) { + if (impl.triggerEvent_.type == TriggerEventType::NoteOn + && impl.region_->offBy == other->group + && (impl.region_->group != other->group || noteNumber != impl.triggerEvent_.number)) { off(delay); return true; } @@ -1051,178 +1358,187 @@ bool sfz::Voice::checkOffGroup(const Region* other, int delay, int noteNumber) n return false; } -void sfz::Voice::reset() noexcept +void Voice::reset() noexcept { - switchState(State::idle); - region = nullptr; - currentPromise.reset(); - sourcePosition = 0; - age = 0; - floatPositionOffset = 0.0f; - noteIsOff = false; + Impl& impl = *impl_; + impl.switchState(State::idle); + impl.region_ = nullptr; + impl.currentPromise_.reset(); + impl.sourcePosition_ = 0; + impl.age_ = 0; + impl.floatPositionOffset_ = 0.0f; + impl.noteIsOff_ = false; - resetLoopInformation(); + impl.resetLoopInformation(); - powerFollower.clear(); + impl.powerFollower_.clear(); - for (auto& filter : filters) + for (auto& filter : impl.filters_) filter.reset(); - for (auto& eq : equalizers) + for (auto& eq : impl.equalizers_) eq.reset(); removeVoiceFromRing(); } -void sfz::Voice::resetLoopInformation() noexcept +void Voice::Impl::resetLoopInformation() noexcept { - loop.start = 0; - loop.end = 0; - loop.size = 0; - loop.xfSize = 0; - loop.xfOutStart = 0; - loop.xfInStart = 0; + loop_.start = 0; + loop_.end = 0; + loop_.size = 0; + loop_.xfSize = 0; + loop_.xfOutStart = 0; + loop_.xfInStart = 0; } -void sfz::Voice::updateLoopInformation() noexcept +void Voice::Impl::updateLoopInformation() noexcept { - if (!region || !currentPromise) + if (!region_ || !currentPromise_) return; - if (!region->shouldLoop()) + if (!region_->shouldLoop()) return; - const auto& info = currentPromise->information; - const auto factor = resources.filePool.getOversamplingFactor(); + const auto& info = currentPromise_->information; + const auto factor = resources_.filePool.getOversamplingFactor(); const auto rate = info.sampleRate; - loop.end = static_cast(region->loopEnd(factor)); - loop.start = static_cast(region->loopStart(factor)); - loop.size = loop.end + 1 - loop.start; - loop.xfSize = static_cast(lroundPositive(region->loopCrossfade * rate)); - loop.xfOutStart = loop.end + 1 - loop.xfSize; - loop.xfInStart = loop.start - loop.xfSize; + loop_.end = static_cast(region_->loopEnd(factor)); + loop_.start = static_cast(region_->loopStart(factor)); + loop_.size = loop_.end + 1 - loop_.start; + loop_.xfSize = static_cast(lroundPositive(region_->loopCrossfade * rate)); + loop_.xfOutStart = loop_.end + 1 - loop_.xfSize; + loop_.xfInStart = loop_.start - loop_.xfSize; } -void sfz::Voice::setNextSisterVoice(Voice* voice) noexcept +void Voice::setNextSisterVoice(Voice* voice) noexcept { // Should never be null ASSERT(voice); - nextSisterVoice = voice; + nextSisterVoice_ = voice; } -void sfz::Voice::setPreviousSisterVoice(Voice* voice) noexcept +void Voice::setPreviousSisterVoice(Voice* voice) noexcept { // Should never be null ASSERT(voice); - previousSisterVoice = voice; + previousSisterVoice_ = voice; } -void sfz::Voice::removeVoiceFromRing() noexcept +void Voice::removeVoiceFromRing() noexcept { - previousSisterVoice->setNextSisterVoice(nextSisterVoice); - nextSisterVoice->setPreviousSisterVoice(previousSisterVoice); - previousSisterVoice = this; - nextSisterVoice = this; + previousSisterVoice_->setNextSisterVoice(nextSisterVoice_); + nextSisterVoice_->setPreviousSisterVoice(previousSisterVoice_); + previousSisterVoice_ = this; + nextSisterVoice_ = this; } -float sfz::Voice::getAveragePower() const noexcept +float Voice::getAveragePower() const noexcept { - if (followPower) - return powerFollower.getAveragePower(); + Impl& impl = *impl_; + if (impl.followPower_) + return impl.powerFollower_.getAveragePower(); else return 0.0f; } -bool sfz::Voice::releasedOrFree() const noexcept +bool Voice::releasedOrFree() const noexcept { - if (state != State::playing) + Impl& impl = *impl_; + if (impl.state_ != State::playing) return true; - if (!region->flexAmpEG) - return egAmplitude.isReleased(); + if (!impl.region_->flexAmpEG) + return impl.egAmplitude_.isReleased(); else - return flexEGs[*region->flexAmpEG]->isReleased(); + return impl.flexEGs_[*impl.region_->flexAmpEG]->isReleased(); } -void sfz::Voice::setMaxFiltersPerVoice(size_t numFilters) +void Voice::setMaxFiltersPerVoice(size_t numFilters) { - if (numFilters == filters.size()) + Impl& impl = *impl_; + if (numFilters == impl.filters_.size()) return; - filters.clear(); + impl.filters_.clear(); for (unsigned i = 0; i < numFilters; ++i) - filters.emplace_back(resources); + impl.filters_.emplace_back(impl.resources_); } -void sfz::Voice::setMaxEQsPerVoice(size_t numFilters) +void Voice::setMaxEQsPerVoice(size_t numFilters) { - if (numFilters == equalizers.size()) + Impl& impl = *impl_; + if (numFilters == impl.equalizers_.size()) return; - equalizers.clear(); + impl.equalizers_.clear(); for (unsigned i = 0; i < numFilters; ++i) - equalizers.emplace_back(resources); + impl.equalizers_.emplace_back(impl.resources_); } -void sfz::Voice::setMaxLFOsPerVoice(size_t numLFOs) +void Voice::setMaxLFOsPerVoice(size_t numLFOs) { - lfos.resize(numLFOs); + Impl& impl = *impl_; + impl.lfos_.resize(numLFOs); for (size_t i = 0; i < numLFOs; ++i) { auto lfo = absl::make_unique(); - lfo->setSampleRate(sampleRate); - lfos[i] = std::move(lfo); + lfo->setSampleRate(impl.sampleRate_); + impl.lfos_[i] = std::move(lfo); } } -void sfz::Voice::setMaxFlexEGsPerVoice(size_t numFlexEGs) +void Voice::setMaxFlexEGsPerVoice(size_t numFlexEGs) { - flexEGs.resize(numFlexEGs); + Impl& impl = *impl_; + impl.flexEGs_.resize(numFlexEGs); for (size_t i = 0; i < numFlexEGs; ++i) { auto eg = absl::make_unique(); - eg->setSampleRate(sampleRate); - flexEGs[i] = std::move(eg); + eg->setSampleRate(impl.sampleRate_); + impl.flexEGs_[i] = std::move(eg); } } -void sfz::Voice::setPitchEGEnabledPerVoice(bool havePitchEG) +void Voice::setPitchEGEnabledPerVoice(bool havePitchEG) { + Impl& impl = *impl_; if (havePitchEG) - egPitch.reset(new ADSREnvelope); + impl.egPitch_.reset(new ADSREnvelope); else - egPitch.reset(); + impl.egPitch_.reset(); } -void sfz::Voice::setFilterEGEnabledPerVoice(bool haveFilterEG) +void Voice::setFilterEGEnabledPerVoice(bool haveFilterEG) { + Impl& impl = *impl_; if (haveFilterEG) - egFilter.reset(new ADSREnvelope); + impl.egFilter_.reset(new ADSREnvelope); else - egFilter.reset(); + impl.egFilter_.reset(); } -void sfz::Voice::setupOscillatorUnison() +void Voice::Impl::setupOscillatorUnison() { - const int m = region->oscillatorMulti; - const float d = region->oscillatorDetune; + const int m = region_->oscillatorMulti; + const float d = region_->oscillatorDetune; // 3-9: unison mode, 1: normal/RM, 2: PM/FM - if (m < 3 || region->oscillatorMode > 0) { - waveUnisonSize = 1; + if (m < 3 || region_->oscillatorMode > 0) { + waveUnisonSize_ = 1; // carrier - waveDetuneRatio[0] = 1.0; - waveLeftGain[0] = 1.0; - waveRightGain[0] = 1.0; + waveDetuneRatio_[0] = 1.0; + waveLeftGain_[0] = 1.0; + waveRightGain_[0] = 1.0; // modulator - const float modDepth = region->oscillatorModDepth; - waveDetuneRatio[1] = centsFactor(d); - waveLeftGain[1] = modDepth; - waveRightGain[1] = modDepth; + const float modDepth = region_->oscillatorModDepth; + waveDetuneRatio_[1] = centsFactor(d); + waveLeftGain_[1] = modDepth; + waveRightGain_[1] = modDepth; return; } // oscillator count, aka. unison size - waveUnisonSize = m; + waveUnisonSize_ = m; // detune (cents) float detunes[config::oscillatorsPerVoice]; @@ -1236,15 +1552,15 @@ void sfz::Voice::setupOscillatorUnison() // detune (ratio) for (int i = 0; i < m; ++i) - waveDetuneRatio[i] = centsFactor(detunes[i]); + waveDetuneRatio_[i] = centsFactor(detunes[i]); // gains - waveLeftGain[0] = 0.0; - waveRightGain[m - 1] = 0.0; + waveLeftGain_[0] = 0.0; + waveRightGain_[m - 1] = 0.0; for (int i = 0; i < m - 1; ++i) { float g = 1.0f - float(i) / float(m - 1); - waveLeftGain[m - 1 - i] = g; - waveRightGain[i] = g; + waveLeftGain_[m - 1 - i] = g; + waveRightGain_[i] = g; } #if 0 @@ -1263,69 +1579,181 @@ void sfz::Voice::setupOscillatorUnison() #endif } -void sfz::Voice::switchState(State s) +void Voice::Impl::switchState(State s) { - if (s != state) { - state = s; - if (stateListener) - stateListener->onVoiceStateChanged(id, s); + if (s != state_) { + state_ = s; + if (stateListener_) + stateListener_->onVoiceStateChanged(id_, s); } } -void sfz::Voice::pitchEnvelope(absl::Span pitchSpan) noexcept +void Voice::Impl::pitchEnvelope(absl::Span pitchSpan) noexcept { const auto numFrames = pitchSpan.size(); - auto bends = resources.bufferPool.getBuffer(numFrames); + auto bends = resources_.bufferPool.getBuffer(numFrames); if (!bends) return; - const auto events = resources.midiState.getPitchEvents(); + const auto events = resources_.midiState.getPitchEvents(); const auto bendLambda = [this](float bend) { - return centsFactor(region->getBendInCents(bend)); + return centsFactor(region_->getBendInCents(bend)); }; - if (region->bendStep > 1) - pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor); + if (region_->bendStep > 1) + pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor_); else pitchBendEnvelope(events, *bends, bendLambda); - bendSmoother.process(*bends, *bends); + bendSmoother_.process(*bends, *bends); applyGain(*bends, pitchSpan); - ModMatrix& mm = resources.modMatrix; + ModMatrix& mm = resources_.modMatrix; - if (float* mod = mm.getModulation(pitchTarget)) { + if (float* mod = mm.getModulation(pitchTarget_)) { for (size_t i = 0; i < numFrames; ++i) pitchSpan[i] *= centsFactor(mod[i]); } } -void sfz::Voice::resetSmoothers() noexcept +void Voice::Impl::resetSmoothers() noexcept { - bendSmoother.reset(1.0f); - gainSmoother.reset(0.0f); + bendSmoother_.reset(1.0f); + gainSmoother_.reset(0.0f); } -void sfz::Voice::saveModulationTargets(const Region* region) noexcept +void Voice::Impl::saveModulationTargets(const Region* region) noexcept { - ModMatrix& mm = resources.modMatrix; - masterAmplitudeTarget = mm.findTarget(ModKey::createNXYZ(ModId::MasterAmplitude, region->getId())); - amplitudeTarget = mm.findTarget(ModKey::createNXYZ(ModId::Amplitude, region->getId())); - volumeTarget = mm.findTarget(ModKey::createNXYZ(ModId::Volume, region->getId())); - panTarget = mm.findTarget(ModKey::createNXYZ(ModId::Pan, region->getId())); - positionTarget = mm.findTarget(ModKey::createNXYZ(ModId::Position, region->getId())); - widthTarget = mm.findTarget(ModKey::createNXYZ(ModId::Width, region->getId())); - pitchTarget = mm.findTarget(ModKey::createNXYZ(ModId::Pitch, region->getId())); - oscillatorDetuneTarget = mm.findTarget(ModKey::createNXYZ(ModId::OscillatorDetune, region->getId())); - oscillatorModDepthTarget = mm.findTarget(ModKey::createNXYZ(ModId::OscillatorModDepth, region->getId())); + ModMatrix& mm = resources_.modMatrix; + masterAmplitudeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::MasterAmplitude, region->getId())); + amplitudeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Amplitude, region->getId())); + volumeTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Volume, region->getId())); + panTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Pan, region->getId())); + positionTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Position, region->getId())); + widthTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Width, region->getId())); + pitchTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::Pitch, region->getId())); + oscillatorDetuneTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::OscillatorDetune, region->getId())); + oscillatorModDepthTarget_ = mm.findTarget(ModKey::createNXYZ(ModId::OscillatorModDepth, region->getId())); } -void sfz::Voice::enablePowerFollower() noexcept +void Voice::enablePowerFollower() noexcept { - followPower = true; - powerFollower.clear(); + Impl& impl = *impl_; + impl.followPower_ = true; + impl.powerFollower_.clear(); } -void sfz::Voice::disablePowerFollower() noexcept +void Voice::disablePowerFollower() noexcept { - followPower = false; + Impl& impl = *impl_; + impl.followPower_ = false; } + +float Voice::getSampleRate() const noexcept +{ + Impl& impl = *impl_; + return impl.sampleRate_; +} + +int Voice::getSamplesPerBlock() const noexcept +{ + Impl& impl = *impl_; + return impl.samplesPerBlock_; +} + +bool Voice::toBeCleanedUp() const +{ + Impl& impl = *impl_; + return impl.state_ == State::cleanMeUp; +} + +void Voice::setStateListener(StateListener *l) noexcept +{ + Impl& impl = *impl_; + impl.stateListener_ = l; +} + +NumericId Voice::getId() const noexcept +{ + Impl& impl = *impl_; + return impl.id_; +} + +const TriggerEvent& Voice::getTriggerEvent() const noexcept +{ + Impl& impl = *impl_; + return impl.triggerEvent_; +} + +const Region* Voice::getRegion() const noexcept +{ + Impl& impl = *impl_; + return impl.region_; +} + +LFO* Voice::getLFO(size_t index) +{ + Impl& impl = *impl_; + return impl.lfos_[index].get(); +} + +FlexEnvelope* Voice::getFlexEG(size_t index) +{ + Impl& impl = *impl_; + return impl.flexEGs_[index].get(); +} + +int Voice::getAge() const noexcept +{ + Impl& impl = *impl_; + return impl.age_; +} + +Duration Voice::getLastDataDuration() const noexcept +{ + Impl& impl = *impl_; + return impl.dataDuration_; +} + +Duration Voice::getLastAmplitudeDuration() const noexcept +{ + Impl& impl = *impl_; + return impl.amplitudeDuration_; +} + +Duration Voice::getLastFilterDuration() const noexcept +{ + Impl& impl = *impl_; + return impl.filterDuration_; +} + +Duration Voice::getLastPanningDuration() const noexcept +{ + Impl& impl = *impl_; + return impl.panningDuration_; +} + +ADSREnvelope* Voice::getAmplitudeEG() +{ + Impl& impl = *impl_; + return &impl.egAmplitude_; +} + +ADSREnvelope* Voice::getPitchEG() +{ + Impl& impl = *impl_; + return impl.egPitch_.get(); +} + +ADSREnvelope* Voice::getFilterEG() +{ + Impl& impl = *impl_; + return impl.egFilter_.get(); +} + +const TriggerEvent& Voice::getTriggerEvent() +{ + Impl& impl = *impl_; + return impl.triggerEvent_; +} + +} // namespace sfz diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 0503b6d7..c5e55bcb 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -5,24 +5,14 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once -#include "TriggerEvent.h" -#include "Config.h" #include "ADSREnvelope.h" -#include "HistoricalBuffer.h" +#include "TriggerEvent.h" #include "Region.h" -#include "AudioBuffer.h" #include "Resources.h" -#include "FilterPool.h" -#include "EQPool.h" -#include "Smoothers.h" #include "AudioSpan.h" #include "LeakDetector.h" -#include "OnePoleFilter.h" -#include "PowerFollower.h" #include "utility/NumericId.h" -#include "absl/types/span.h" #include -#include namespace sfz { enum InterpolatorModel : int; @@ -44,16 +34,16 @@ public: * @param midiState */ Voice(int voiceNumber, Resources& resources); - ~Voice(); + Voice(const Voice& other) = delete; + Voice& operator=(const Voice& other) = delete; + Voice(Voice&& other); + Voice& operator=(Voice&& other); /** * @brief Get the unique identifier of this voice in a synth */ - NumericId getId() const noexcept - { - return id; - } + NumericId getId() const noexcept; enum class State { idle, @@ -69,12 +59,12 @@ public: /** * @brief Return true if the voice is to be cleaned up (zombie state) */ - bool toBeCleanedUp() const { return state == State::cleanMeUp; } + bool toBeCleanedUp() const; /** * @brief Sets the listener which is called when the voice state changes. */ - void setStateListener(StateListener *l) noexcept { stateListener = l; } + void setStateListener(StateListener *l) noexcept; /** * @brief Change the sample rate of the voice. This is used to compute all @@ -98,13 +88,13 @@ public: * * @return float */ - float getSampleRate() const noexcept { return sampleRate; } + float getSampleRate() const noexcept; /** * @brief Get the expected block size. * * @return int */ - int getSamplesPerBlock() const noexcept { return samplesPerBlock; } + int getSamplesPerBlock() const noexcept; /** * @brief Start playing a region after a short delay for different triggers (note on, off, cc) @@ -199,7 +189,7 @@ public: * * @return int */ - const TriggerEvent& getTriggerEvent() const noexcept { return triggerEvent; } + const TriggerEvent& getTriggerEvent() const noexcept; /** * @brief Reset the voice to its initial values @@ -232,14 +222,14 @@ public: * * @return Voice* */ - Voice* getNextSisterVoice() const noexcept { return nextSisterVoice; }; + Voice* getNextSisterVoice() const noexcept { return nextSisterVoice_; }; /** * @brief Get the previous sister voice in the ring * * @return Voice* */ - Voice* getPreviousSisterVoice() const noexcept { return previousSisterVoice; }; + Voice* getPreviousSisterVoice() const noexcept { return previousSisterVoice_; }; /** * @brief Get the mean squared power of the last rendered block. This is used @@ -266,19 +256,19 @@ public: * * @return */ - const Region* getRegion() const noexcept { return region; } + const Region* getRegion() const noexcept; /** * @brief Get the LFO designated by the given index * * @param index */ - LFO* getLFO(size_t index) { return lfos[index].get(); } + LFO* getLFO(size_t index); /** * @brief Get the Flex EG designated by the given index * * @param index */ - FlexEnvelope* getFlexEG(size_t index) { return flexEGs[index].get(); } + FlexEnvelope* getFlexEG(size_t index); /** * @brief Set the max number of filters per voice * @@ -337,250 +327,42 @@ public: * * @return */ - int getAge() const noexcept { return age; } + int getAge() const noexcept; - Duration getLastDataDuration() const noexcept { return dataDuration; } - Duration getLastAmplitudeDuration() const noexcept { return amplitudeDuration; } - Duration getLastFilterDuration() const noexcept { return filterDuration; } - Duration getLastPanningDuration() const noexcept { return panningDuration; } + Duration getLastDataDuration() const noexcept; + Duration getLastAmplitudeDuration() const noexcept; + Duration getLastFilterDuration() const noexcept; + Duration getLastPanningDuration() const noexcept; /** * @brief Get the SFZv1 amplitude EG, if existing */ - ADSREnvelope* getAmplitudeEG() { return &egAmplitude; } + ADSREnvelope* getAmplitudeEG(); /** * @brief Get the SFZv1 pitch EG, if existing */ - ADSREnvelope* getPitchEG() { return egPitch.get(); } + ADSREnvelope* getPitchEG(); /** * @brief Get the SFZv1 filter EG, if existing */ - ADSREnvelope* getFilterEG() { return egFilter.get(); } + ADSREnvelope* getFilterEG(); /** * @brief Get the trigger event */ - const TriggerEvent& getTriggerEvent() { return triggerEvent; } + const TriggerEvent& getTriggerEvent(); private: - /** - * @brief Fill a span with data from a file source. This is the first step - * in rendering each block of data. - * - * @param buffer - */ - void fillWithData(AudioSpan buffer) noexcept; - /** - * @brief Fill a span with data from a generator source. This is the first step - * in rendering each block of data. - * - * @param buffer - */ - void fillWithGenerator(AudioSpan buffer) noexcept; - - /** - * @brief Fill a destination with an interpolated source. - * - * @param source the source sample - * @param dest the destination buffer - * @param indices the integral parts of the source positions - * @param coeffs the fractional parts of the source positions - */ - template - static void fillInterpolated( - const AudioSpan& source, const AudioSpan& dest, - absl::Span indices, absl::Span coeffs, - absl::Span addingGains); - - /** - * @brief Fill a destination with an interpolated source, selecting - * interpolation type dynamically by quality level. - * - * @param source the source sample - * @param dest the destination buffer - * @param indices the integral parts of the source positions - * @param coeffs the fractional parts of the source positions - * @param quality the quality level 1-10 - */ - template - static void fillInterpolatedWithQuality( - const AudioSpan& source, const AudioSpan& dest, - absl::Span indices, absl::Span coeffs, - absl::Span addingGains, int quality); - - /** - * @brief Get a S-shaped curve that is applicable to loop crossfading. - */ - static const Curve& getSCurve(); - - /** - * @brief Compute the amplitude envelope, applied as a gain to a mono - * or stereo buffer - * - * @param modulationSpan - */ - void amplitudeEnvelope(absl::Span modulationSpan) noexcept; - - /** - * @brief Apply the crossfade envelope to a span. - * - * @param modulationSpan - */ - void applyCrossfades(absl::Span modulationSpan) noexcept; - void resetCrossfades() noexcept; - - /** - * @brief Amplitude stage for a mono source - * - * @param buffer - */ - void ampStageMono(AudioSpan buffer) noexcept; - /** - * @brief Amplitude stage for a stereo source - * - * @param buffer - */ - void ampStageStereo(AudioSpan buffer) noexcept; - /** - * @brief Amplitude stage for a mono source - * - * @param buffer - */ - void panStageMono(AudioSpan buffer) noexcept; - void panStageStereo(AudioSpan buffer) noexcept; - /** - * @brief Amplitude stage for a mono source - * - * @param buffer - */ - void filterStageMono(AudioSpan buffer) noexcept; - void filterStageStereo(AudioSpan buffer) noexcept; - /** - * @brief Compute the pitch envelope. This envelope is meant to multiply - * the frequency parameter for each sample (which translates to floating - * point intervals for sample-based voices, or phases for generators) - * - * @param pitchSpan - */ - void pitchEnvelope(absl::Span pitchSpan) noexcept; + struct Impl; + std::unique_ptr impl_; /** * @brief Remove the voice from the sister ring * */ void removeVoiceFromRing() noexcept; - - /** - * @brief Initialize frequency and gain coefficients for the oscillators. - */ - void setupOscillatorUnison(); - void updateChannelPowers(AudioSpan buffer); - - /** - * @brief Modify the voice state and notify any listeners. - */ - void switchState(State s); - - /** - * @brief Save the modulation targets to avoid recomputing them in every callback. - * Must be called during startVoice() ideally. - */ - void saveModulationTargets(const Region* region) noexcept; - - const NumericId id; - StateListener* stateListener = nullptr; - - Region* region { nullptr }; - - State state { State::idle }; - bool noteIsOff { false }; - - TriggerEvent triggerEvent; - absl::optional triggerDelay; - - float speedRatio { 1.0 }; - float pitchRatio { 1.0 }; - float baseVolumedB { 0.0 }; - float baseGain { 1.0 }; - float baseFrequency { 440.0 }; - - float floatPositionOffset { 0.0f }; - int sourcePosition { 0 }; - int initialDelay { 0 }; - int age { 0 }; - struct { - int start { 0 }; - int end { 0 }; - int size { 0 }; - int xfSize { 0 }; - int xfOutStart { 0 }; - int xfInStart { 0 }; - } loop; - /** - * @brief Reset the loop information - * - */ - void resetLoopInformation() noexcept; - /** - * @brief Read the loop information data from the region. - * This requires that the region and promise is properly set. - * - */ - void updateLoopInformation() noexcept; - - FileDataHolder currentPromise; - - int samplesPerBlock { config::defaultSamplesPerBlock }; - float sampleRate { config::defaultSampleRate }; - - Resources& resources; - - std::vector filters; - std::vector equalizers; - std::vector> lfos; - std::vector> flexEGs; - - ADSREnvelope egAmplitude; - std::unique_ptr> egPitch; - std::unique_ptr> egFilter; - float bendStepFactor { centsFactor(1) }; - - WavetableOscillator waveOscillators[config::oscillatorsPerVoice]; - - // unison of oscillators - unsigned waveUnisonSize { 0 }; - float waveDetuneRatio[config::oscillatorsPerVoice] {}; - float waveLeftGain[config::oscillatorsPerVoice] {}; - float waveRightGain[config::oscillatorsPerVoice] {}; - - Duration dataDuration; - Duration amplitudeDuration; - Duration panningDuration; - Duration filterDuration; - - Voice* nextSisterVoice { this }; - Voice* previousSisterVoice { this }; - - fast_real_distribution uniformNoiseDist { -config::uniformNoiseBounds, config::uniformNoiseBounds }; - fast_gaussian_generator gaussianNoiseDist { 0.0f, config::noiseVariance }; - - Smoother gainSmoother; - Smoother bendSmoother; - Smoother xfadeSmoother; - void resetSmoothers() noexcept; - - ModMatrix::TargetId masterAmplitudeTarget; - ModMatrix::TargetId amplitudeTarget; - ModMatrix::TargetId volumeTarget; - ModMatrix::TargetId panTarget; - ModMatrix::TargetId positionTarget; - ModMatrix::TargetId widthTarget; - ModMatrix::TargetId pitchTarget; - ModMatrix::TargetId oscillatorDetuneTarget; - ModMatrix::TargetId oscillatorModDepthTarget; - - bool followPower { false }; - PowerFollower powerFollower; + Voice* nextSisterVoice_ { this }; + Voice* previousSisterVoice_ { this }; LEAK_DETECTOR(Voice); }; diff --git a/src/sfizz/VoiceList.h b/src/sfizz/VoiceList.h new file mode 100644 index 00000000..aae6f44f --- /dev/null +++ b/src/sfizz/VoiceList.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once + +#include "Voice.h" +#include + +namespace sfz { + +struct VoiceList +{ + /** + * @brief Find the voice which is associated with the given identifier. + * + * @param id + * @return const Voice* + */ + const Voice* getVoiceById(NumericId id) const noexcept + { + const size_t size = list.size(); + + if (size == 0 || !id.valid()) + return nullptr; + + // search a sequence of ordered identifiers with potential gaps + size_t index = static_cast(id.number()); + index = std::min(index, size - 1); + + while (index > 0 && list[index].getId().number() > id.number()) + --index; + + return (list[index].getId() == id) ? &list[index] : nullptr; + } + + Voice* getVoiceById(NumericId id) noexcept + { + return const_cast( + const_cast(this)->getVoiceById(id)); + } + + void reset() + { + for (auto& voice : list) + voice.reset(); + } + + typename std::vector::iterator begin() { return list.begin(); } + typename std::vector::const_iterator cbegin() const { return list.cbegin(); } + typename std::vector::iterator end() { return list.end(); } + typename std::vector::const_iterator cend() const { return list.cend(); } + typename std::vector::reference operator[] (size_t n) { return list[n]; } + typename std::vector::const_reference operator[] (size_t n) const { return list[n]; } + typename std::vector::reference back() { return list.back(); } + typename std::vector::const_reference back() const { return list.back(); } + size_t size() const { return list.size(); } + void clear() { list.clear(); } + void reserve(size_t n) { list.reserve(n); } + template< class... Args > + void emplace_back(Args&&... args) { list.emplace_back(std::forward(args)...); } +private: + std::vector list; +}; + +} // namespace sfz diff --git a/src/sfizz/modulations/sources/ADSREnvelope.cpp b/src/sfizz/modulations/sources/ADSREnvelope.cpp index 57f8ba7d..dfe67317 100644 --- a/src/sfizz/modulations/sources/ADSREnvelope.cpp +++ b/src/sfizz/modulations/sources/ADSREnvelope.cpp @@ -15,16 +15,14 @@ namespace sfz { -ADSREnvelopeSource::ADSREnvelopeSource(Synth &synth) - : synth_(&synth) +ADSREnvelopeSource::ADSREnvelopeSource(VoiceList& list, MidiState& state) + : voiceList_(list), midiState_(state) { } void ADSREnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { - Synth& synth = *synth_; - - Voice* voice = synth.getVoiceById(voiceId); + Voice* voice = voiceList_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -55,17 +53,14 @@ void ADSREnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, return; } - Resources& resources = synth.getResources(); const TriggerEvent& triggerEvent = voice->getTriggerEvent(); const float sampleRate = voice->getSampleRate(); - eg->reset(*desc, *region, resources.midiState, delay, triggerEvent.value, sampleRate); + eg->reset(*desc, *region, midiState_, delay, triggerEvent.value, sampleRate); } void ADSREnvelopeSource::release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { - Synth& synth = *synth_; - - Voice* voice = synth.getVoiceById(voiceId); + Voice* voice = voiceList_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -96,9 +91,7 @@ void ADSREnvelopeSource::release(const ModKey& sourceKey, NumericId voice void ADSREnvelopeSource::generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) { - Synth& synth = *synth_; - - Voice* voice = synth.getVoiceById(voiceId); + Voice* voice = voiceList_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; diff --git a/src/sfizz/modulations/sources/ADSREnvelope.h b/src/sfizz/modulations/sources/ADSREnvelope.h index b2644df9..a8835467 100644 --- a/src/sfizz/modulations/sources/ADSREnvelope.h +++ b/src/sfizz/modulations/sources/ADSREnvelope.h @@ -6,19 +6,22 @@ #pragma once #include "../ModGenerator.h" +#include "../../VoiceList.h" +#include "../../MidiState.h" namespace sfz { class Synth; class ADSREnvelopeSource : public ModGenerator { public: - explicit ADSREnvelopeSource(Synth &synth); + explicit ADSREnvelopeSource(VoiceList &synth, MidiState& state); void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) override; private: - Synth* synth_ = nullptr; + VoiceList& voiceList_; + MidiState& midiState_; }; } // namespace sfz diff --git a/src/sfizz/modulations/sources/FlexEnvelope.cpp b/src/sfizz/modulations/sources/FlexEnvelope.cpp index 13965373..db471ed1 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.cpp +++ b/src/sfizz/modulations/sources/FlexEnvelope.cpp @@ -14,17 +14,16 @@ namespace sfz { -FlexEnvelopeSource::FlexEnvelopeSource(Synth &synth) - : synth_(&synth) +FlexEnvelopeSource::FlexEnvelopeSource(VoiceList& list) + : voiceList_(list) { } void FlexEnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { - Synth& synth = *synth_; unsigned egIndex = sourceKey.parameters().N; - Voice* voice = synth.getVoiceById(voiceId); + Voice* voice = voiceList_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -49,10 +48,9 @@ void FlexEnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, void FlexEnvelopeSource::release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { - Synth& synth = *synth_; unsigned egIndex = sourceKey.parameters().N; - Voice* voice = synth.getVoiceById(voiceId); + Voice* voice = voiceList_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -70,10 +68,9 @@ void FlexEnvelopeSource::release(const ModKey& sourceKey, NumericId voice void FlexEnvelopeSource::generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) { - Synth& synth = *synth_; unsigned egIndex = sourceKey.parameters().N; - Voice* voice = synth.getVoiceById(voiceId); + Voice* voice = voiceList_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; diff --git a/src/sfizz/modulations/sources/FlexEnvelope.h b/src/sfizz/modulations/sources/FlexEnvelope.h index c4e50fc4..487efdba 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.h +++ b/src/sfizz/modulations/sources/FlexEnvelope.h @@ -6,19 +6,20 @@ #pragma once #include "../ModGenerator.h" +#include "../../VoiceList.h" namespace sfz { class Synth; class FlexEnvelopeSource : public ModGenerator { public: - explicit FlexEnvelopeSource(Synth &synth); + explicit FlexEnvelopeSource(VoiceList& list); void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) override; private: - Synth* synth_ = nullptr; + VoiceList& voiceList_; }; } // namespace sfz diff --git a/src/sfizz/modulations/sources/LFO.cpp b/src/sfizz/modulations/sources/LFO.cpp index 2f06c34f..8a603e43 100644 --- a/src/sfizz/modulations/sources/LFO.cpp +++ b/src/sfizz/modulations/sources/LFO.cpp @@ -14,17 +14,16 @@ namespace sfz { -LFOSource::LFOSource(Synth &synth) - : synth_(&synth) +LFOSource::LFOSource(VoiceList& list) + : voiceList_(list) { } void LFOSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { - Synth& synth = *synth_; unsigned lfoIndex = sourceKey.parameters().N; - Voice* voice = synth.getVoiceById(voiceId); + Voice* voice = voiceList_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -43,10 +42,9 @@ void LFOSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned void LFOSource::generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) { - Synth& synth = *synth_; const unsigned lfoIndex = sourceKey.parameters().N; - Voice* voice = synth.getVoiceById(voiceId); + Voice* voice = voiceList_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; fill(buffer, 0.0f); diff --git a/src/sfizz/modulations/sources/LFO.h b/src/sfizz/modulations/sources/LFO.h index cf7e702f..02c696c9 100644 --- a/src/sfizz/modulations/sources/LFO.h +++ b/src/sfizz/modulations/sources/LFO.h @@ -6,18 +6,18 @@ #pragma once #include "../ModGenerator.h" - +#include "../../VoiceList.h" namespace sfz { class Synth; class LFOSource : public ModGenerator { public: - explicit LFOSource(Synth &synth); + explicit LFOSource(VoiceList &list); void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) override; private: - Synth* synth_ = nullptr; + VoiceList& voiceList_; }; } // namespace sfz diff --git a/tests/PolyphonyT.cpp b/tests/PolyphonyT.cpp index c1d891d4..c7541391 100644 --- a/tests/PolyphonyT.cpp +++ b/tests/PolyphonyT.cpp @@ -10,6 +10,10 @@ #include #include "catch2/catch.hpp" +// Need these for the introspection of Synth +#include "sfizz/PolyphonyGroup.h" +#include "sfizz/RegionSet.h" + using namespace Catch::literals; using namespace sfz::literals; diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index 868cd7ca..f03efda0 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -14,6 +14,9 @@ using namespace Catch::literals; using namespace sfz::literals; +// Need these for the introspection of Synth +#include "sfizz/Effects.h" + constexpr int blockSize { 256 }; TEST_CASE("[Synth] Play and check active voices") @@ -1357,17 +1360,17 @@ TEST_CASE("[Synth] Initial values of CC") sample=*sine )"); - REQUIRE(synth.getHdccInit(111) == 0.0f); - REQUIRE(synth.getHdccInit(7) == Approx(100.0f / 127)); // default volume - REQUIRE(synth.getHdccInit(10) == 0.5f); // default pan + REQUIRE(synth.getHdcc(111) == 0.0f); + REQUIRE(synth.getHdcc(7) == Approx(100.0f / 127)); // default volume + REQUIRE(synth.getHdcc(10) == 0.5f); // default pan synth.loadSfzString(fs::current_path() / "init_cc.sfz", R"( set_hdcc111=0.1234 set_cc112=77 sample=*sine )"); - REQUIRE(synth.getHdccInit(111) == Approx(0.1234f)); - REQUIRE(synth.getHdccInit(112) == Approx(77.0f / 127)); + REQUIRE(synth.getHdcc(111) == Approx(0.1234f)); + REQUIRE(synth.getHdcc(112) == Approx(77.0f / 127)); } TEST_CASE("[Synth] Default ampeg_release") From 77e3562f2b6efcbfb38854eeee678b3f046f9564 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Fri, 30 Oct 2020 11:53:30 +0100 Subject: [PATCH 049/668] Mark moves noexcept and remove the assert --- src/sfizz/Voice.cpp | 6 ++---- src/sfizz/Voice.h | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 7f5faadc..e57dd627 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -266,8 +266,7 @@ Voice::~Voice() } -Voice::Voice(Voice&& other) { - ASSERT(other.impl_); +Voice::Voice(Voice&& other) noexcept { impl_ = std::move(other.impl_); if (other.nextSisterVoice_ != &other) { @@ -287,8 +286,7 @@ Voice::Voice(Voice&& other) { } } -Voice& Voice::operator=(Voice&& other) { - ASSERT(other.impl_); +Voice& Voice::operator=(Voice&& other) noexcept { impl_ = std::move(other.impl_); if (other.nextSisterVoice_ != &other) { diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index c5e55bcb..2e79584a 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -37,8 +37,8 @@ public: ~Voice(); Voice(const Voice& other) = delete; Voice& operator=(const Voice& other) = delete; - Voice(Voice&& other); - Voice& operator=(Voice&& other); + Voice(Voice&& other) noexcept; + Voice& operator=(Voice&& other) noexcept; /** * @brief Get the unique identifier of this voice in a synth From f21864cdc780f17063c48dcb9b03e76879a5e981 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Fri, 30 Oct 2020 19:27:46 +0100 Subject: [PATCH 050/668] Reinsert default hdcc --- src/sfizz/Synth.cpp | 40 +++++++++++++++++++++++++++++++++------- src/sfizz/Synth.h | 7 +++++++ tests/SynthT.cpp | 11 +++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 43fac9bb..70816935 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -278,6 +278,14 @@ struct Synth::Impl : public Voice::StateListener, public Parser::Listener { static void updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); static void updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); + /** + * @brief Set the default value for a CC + * + * @param ccNumber + * @param value + */ + void setDefaultHdcc(int ccNumber, float value); + int numGroups_ { 0 }; int numMasters_ { 0 }; @@ -374,6 +382,8 @@ struct Synth::Impl : public Voice::StateListener, public Parser::Listener { Parser parser_; fs::file_time_type modificationTime_ { }; + + std::array defaultCCValues_; }; Synth::Synth() @@ -609,9 +619,11 @@ void Synth::Impl::clear() modificationTime_ = fs::file_time_type::min(); // set default controllers - resources_.midiState.ccEvent(0, 7, normalizeCC(100)); // volume - resources_.midiState.ccEvent(0, 10, 0.5f); // pan - resources_.midiState.ccEvent(0, 11, 1.0f); // expression + resources_.midiState.resetAllControllers(0); + fill(absl::MakeSpan(defaultCCValues_), 0.0f); + setDefaultHdcc(7, normalizeCC(100)); + setDefaultHdcc(10, 0.5f); + setDefaultHdcc(11, 1.0f); // set default controller labels insertPairUniquely(ccLabels_, 7, "Volume"); @@ -706,16 +718,14 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { const auto ccValue = readOpcode(member.value, Default::midi7Range); if (ccValue) - resources_.midiState.ccEvent( - 0, member.parameters.back(), normalizeCC(*ccValue)); + setDefaultHdcc(member.parameters.back(), normalizeCC(*ccValue)); } break; case hash("set_hdcc&"): if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { const auto ccValue = readOpcode(member.value, Default::normalizedRange); if (ccValue) - resources_.midiState.ccEvent( - 0, member.parameters.back(), *ccValue); + setDefaultHdcc(member.parameters.back(), *ccValue); } break; case hash("label_cc&"): @@ -1632,6 +1642,14 @@ void Synth::hdcc(int delay, int ccNumber, float normValue) noexcept impl.ccDispatch(delay, ccNumber, normValue); } +void Synth::Impl::setDefaultHdcc(int ccNumber, float value) +{ + ASSERT(ccNumber >= 0); + ASSERT(ccNumber < config::numCCs); + defaultCCValues_[ccNumber] = value; + resources_.midiState.ccEvent(0, ccNumber, value); +} + float Synth::getHdcc(int ccNumber) { ASSERT(ccNumber >= 0); @@ -1640,6 +1658,14 @@ float Synth::getHdcc(int ccNumber) return impl.resources_.midiState.getCCValue(ccNumber); } +float Synth::getDefaultHdcc(int ccNumber) +{ + ASSERT(ccNumber >= 0); + ASSERT(ccNumber < config::numCCs); + Impl& impl = *impl_; + return impl.defaultCCValues_[ccNumber]; +} + void Synth::pitchWheel(int delay, int pitch) noexcept { ASSERT(pitch <= 8192); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 37e095d2..bb93ab6c 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -344,6 +344,13 @@ public: * @return the current value */ float getHdcc(int ccNumber); + /** + * @brief Get the default value of a controller under the current instrument + * + * @param ccNumber the cc number + * @return the default value + */ + float getDefaultHdcc(int ccNumber); /** * @brief Send a pitch bend event to the synth * diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index f03efda0..71303217 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -1361,8 +1361,17 @@ TEST_CASE("[Synth] Initial values of CC") )"); REQUIRE(synth.getHdcc(111) == 0.0f); + REQUIRE(synth.getDefaultHdcc(111) == 0.0f); REQUIRE(synth.getHdcc(7) == Approx(100.0f / 127)); // default volume + REQUIRE(synth.getDefaultHdcc(7) == Approx(100.0f / 127)); REQUIRE(synth.getHdcc(10) == 0.5f); // default pan + REQUIRE(synth.getDefaultHdcc(10) == 0.5f); + REQUIRE(synth.getHdcc(11) == 1.0f); // default expression + REQUIRE(synth.getDefaultHdcc(11) == 1.0f); + + synth.hdcc(0, 10, 0.7f); + REQUIRE(synth.getHdcc(10) == 0.7f); + REQUIRE(synth.getDefaultHdcc(10) == 0.5f); synth.loadSfzString(fs::current_path() / "init_cc.sfz", R"( set_hdcc111=0.1234 set_cc112=77 @@ -1370,7 +1379,9 @@ TEST_CASE("[Synth] Initial values of CC") )"); REQUIRE(synth.getHdcc(111) == Approx(0.1234f)); + REQUIRE(synth.getDefaultHdcc(111) == Approx(0.1234f)); REQUIRE(synth.getHdcc(112) == Approx(77.0f / 127)); + REQUIRE(synth.getDefaultHdcc(112) == Approx(77.0f / 127)); } TEST_CASE("[Synth] Default ampeg_release") From 887f475317edf93a9f1b9209f72a044e68a9f07a Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 09:00:53 +0100 Subject: [PATCH 051/668] Cosmetics --- src/sfizz/Synth.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 70816935..3e7155d7 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -366,15 +366,14 @@ struct Synth::Impl : public Voice::StateListener, public Parser::Listener { std::unique_ptr genADSREnvelope_; // Settings per voice - struct SettingsPerVoice { + struct { size_t maxFilters { 0 }; size_t maxEQs { 0 }; size_t maxLFOs { 0 }; size_t maxFlexEGs { 0 }; bool havePitchEG { false }; bool haveFilterEG { false }; - }; - SettingsPerVoice settingsPerVoice_; + } settingsPerVoice_; Duration dispatchDuration_ { 0 }; @@ -619,7 +618,7 @@ void Synth::Impl::clear() modificationTime_ = fs::file_time_type::min(); // set default controllers - resources_.midiState.resetAllControllers(0); + // midistate is reset above fill(absl::MakeSpan(defaultCCValues_), 0.0f); setDefaultHdcc(7, normalizeCC(100)); setDefaultHdcc(10, 0.5f); From 13ff2350d3fbdda5940da7344054c22af95a9852 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 09:07:36 +0100 Subject: [PATCH 052/668] Move the playing attack voice method in the voiceList --- src/sfizz/Synth.cpp | 31 ++----------------------- src/sfizz/VoiceList.h | 54 +++++++++++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 3e7155d7..02e3ff27 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -253,15 +253,6 @@ struct Synth::Impl : public Voice::StateListener, public Parser::Listener { */ void startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept; - /** - * @brief Check if a playing voice matches the release region - * - * @param releaseRegion - * @return true - * @return false - */ - bool playingAttackVoice(const Region* releaseRegion) noexcept; - /** * @brief Finalize SFZ loading, following a successful execution of the * parsing step. @@ -1401,24 +1392,6 @@ void Synth::Impl::startVoice(Region* region, int delay, const TriggerEvent& trig polyphonyGroups_[region->group].registerVoice(selectedVoice); } -bool Synth::Impl::playingAttackVoice(const Region* releaseRegion) noexcept -{ - const auto compatibleVoice = [releaseRegion](const Voice* v) -> bool { - const TriggerEvent& event = v->getTriggerEvent(); - return ( - !v->isFree() - && event.type == TriggerEventType::NoteOn - && releaseRegion->keyRange.containsWithEnd(event.number) - && releaseRegion->velocityRange.containsWithEnd(event.value) - ); - }; - - if (absl::c_find_if(voiceViewArray_, compatibleVoice) == voiceViewArray_.end()) - return false; - else - return true; -} - void Synth::Impl::noteOffDispatch(int delay, int noteNumber, float velocity) noexcept { const auto randValue = randNoteDistribution_(Random::randomGenerator); @@ -1433,7 +1406,7 @@ void Synth::Impl::noteOffDispatch(int delay, int noteNumber, float velocity) noe for (auto& region : noteActivationLists_[noteNumber]) { if (region->registerNoteOff(noteNumber, velocity, randValue)) { - if (region->trigger == SfzTrigger::release && !region->rtDead && !playingAttackVoice(region)) + if (region->trigger == SfzTrigger::release && !region->rtDead && !voiceList_.playingAttackVoice(region)) continue; startVoice(region, delay, triggerEvent, ring); @@ -1577,7 +1550,7 @@ void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noex void Synth::Impl::startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept { - if (!region->rtDead && !playingAttackVoice(region)) { + if (!region->rtDead && !voiceList_.playingAttackVoice(region)) { region->delayedReleases.clear(); return; } diff --git a/src/sfizz/VoiceList.h b/src/sfizz/VoiceList.h index aae6f44f..0903c0bb 100644 --- a/src/sfizz/VoiceList.h +++ b/src/sfizz/VoiceList.h @@ -7,7 +7,9 @@ #pragma once #include "Voice.h" +#include "Region.h" #include +#include namespace sfz { @@ -21,7 +23,7 @@ struct VoiceList */ const Voice* getVoiceById(NumericId id) const noexcept { - const size_t size = list.size(); + const size_t size = list_.size(); if (size == 0 || !id.valid()) return nullptr; @@ -30,10 +32,10 @@ struct VoiceList size_t index = static_cast(id.number()); index = std::min(index, size - 1); - while (index > 0 && list[index].getId().number() > id.number()) + while (index > 0 && list_[index].getId().number() > id.number()) --index; - return (list[index].getId() == id) ? &list[index] : nullptr; + return (list_[index].getId() == id) ? &list_[index] : nullptr; } Voice* getVoiceById(NumericId id) noexcept @@ -44,25 +46,43 @@ struct VoiceList void reset() { - for (auto& voice : list) + for (auto& voice : list_) voice.reset(); } - typename std::vector::iterator begin() { return list.begin(); } - typename std::vector::const_iterator cbegin() const { return list.cbegin(); } - typename std::vector::iterator end() { return list.end(); } - typename std::vector::const_iterator cend() const { return list.cend(); } - typename std::vector::reference operator[] (size_t n) { return list[n]; } - typename std::vector::const_reference operator[] (size_t n) const { return list[n]; } - typename std::vector::reference back() { return list.back(); } - typename std::vector::const_reference back() const { return list.back(); } - size_t size() const { return list.size(); } - void clear() { list.clear(); } - void reserve(size_t n) { list.reserve(n); } + bool playingAttackVoice(const Region* releaseRegion) noexcept + { + const auto compatibleVoice = [releaseRegion](const Voice& v) -> bool { + const TriggerEvent& event = v.getTriggerEvent(); + return ( + !v.isFree() + && event.type == TriggerEventType::NoteOn + && releaseRegion->keyRange.containsWithEnd(event.number) + && releaseRegion->velocityRange.containsWithEnd(event.value) + ); + }; + + if (absl::c_find_if(list_, compatibleVoice) == list_.end()) + return false; + else + return true; + } + + typename std::vector::iterator begin() { return list_.begin(); } + typename std::vector::const_iterator cbegin() const { return list_.cbegin(); } + typename std::vector::iterator end() { return list_.end(); } + typename std::vector::const_iterator cend() const { return list_.cend(); } + typename std::vector::reference operator[] (size_t n) { return list_[n]; } + typename std::vector::const_reference operator[] (size_t n) const { return list_[n]; } + typename std::vector::reference back() { return list_.back(); } + typename std::vector::const_reference back() const { return list_.back(); } + size_t size() const { return list_.size(); } + void clear() { list_.clear(); } + void reserve(size_t n) { list_.reserve(n); } template< class... Args > - void emplace_back(Args&&... args) { list.emplace_back(std::forward(args)...); } + void emplace_back(Args&&... args) { list_.emplace_back(std::forward(args)...); } private: - std::vector list; + std::vector list_; }; } // namespace sfz From 0f7fadc7a94c4a64798af4a751f7b53562c82167 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 09:18:13 +0100 Subject: [PATCH 053/668] Cave in for clang-tidy --- src/sfizz/Synth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 02e3ff27..585689d7 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -377,7 +377,7 @@ struct Synth::Impl : public Voice::StateListener, public Parser::Listener { }; Synth::Synth() -: impl_(new Impl) +: impl_(new Impl) // NOLINT: (paul) I don't get why clang-tidy complains here { } From ed151880d9f768108406c7f6f98d41513447a0c5 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 18:51:19 +0100 Subject: [PATCH 054/668] Move the polyphony logic in the voice list and refactor --- src/sfizz/PolyphonyGroup.h | 1 + src/sfizz/Synth.cpp | 246 +++--------------------------------- src/sfizz/Voice.cpp | 2 +- src/sfizz/Voice.h | 2 +- src/sfizz/VoiceList.h | 218 ++++++++++++++++++++++++++++++-- src/sfizz/VoiceStealing.cpp | 141 ++++++++++++++++----- src/sfizz/VoiceStealing.h | 95 +++++++------- 7 files changed, 384 insertions(+), 321 deletions(-) diff --git a/src/sfizz/PolyphonyGroup.h b/src/sfizz/PolyphonyGroup.h index 7a4281af..f3d47257 100644 --- a/src/sfizz/PolyphonyGroup.h +++ b/src/sfizz/PolyphonyGroup.h @@ -6,6 +6,7 @@ #pragma once +#include "Config.h" #include "Region.h" #include "Voice.h" #include "SwapAndPop.h" diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 585689d7..7c6fb08d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -31,7 +31,6 @@ #include "utility/SpinMutex.h" #include "utility/XmlHelpers.h" #include "VoiceList.h" -#include "VoiceStealing.h" #include #include #include @@ -42,15 +41,10 @@ namespace sfz { -struct Synth::Impl : public Voice::StateListener, public Parser::Listener { +struct Synth::Impl: public Parser::Listener { Impl(); ~Impl(); - /** - * @brief The voice callback which is called during a change of state. - */ - void onVoiceStateChanged(NumericId idNumber, Voice::State state) final; - /** * @brief The parser callback; this is called by the parent object each time * a new region, group, master, global, curve or control set of opcodes @@ -71,15 +65,6 @@ struct Synth::Impl : public Voice::StateListener, public Parser::Listener { */ void onParseWarning(const SourceRange& range, const std::string& message) final; - - /** - * @brief change the group maximum polyphony - * - * @param groupIdx the group index - * @param polyphone the max polyphony - */ - void setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept; - /** * @brief Reset all CCs; to be used on CC 121 * @@ -193,46 +178,6 @@ struct Synth::Impl : public Voice::StateListener, public Parser::Listener { Voice* findFreeVoice() noexcept; - /** - * @brief Check the region polyphony, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkRegionPolyphony(const Region* region, int delay) noexcept; - - /** - * @brief Check the note polyphony, releasing voices if necessary - * - * @param region - * @param delay - * @param triggerEvent - */ - void checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept; - - /** - * @brief Check the group polyphony, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkGroupPolyphony(const Region* region, int delay) noexcept; - - /** - * @brief Check the region set polyphony at all levels, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkSetPolyphony(const Region* region, int delay) noexcept; - - /** - * @brief Check the engine polyphony, fast releasing voices if necessary - * - * @param delay - */ - void checkEnginePolyphony(int delay) noexcept; - /** * @brief Start a voice for a specific region. * This will do the needed polyphony checks and voice stealing. @@ -308,14 +253,10 @@ struct Synth::Impl : public Voice::StateListener, public Parser::Listener { // engine polyphony RegionSetPtr engineSet_; - // These are the `group=` groups where you can off voices - std::vector polyphonyGroups_; - // Views to speed up iteration over the regions and voices when events // occur in the audio callback VoiceViewVector tempPolyphonyArray_; VoiceViewVector voiceViewArray_; - VoiceStealing stealer_; std::array lastKeyswitchLists_; std::array downKeyswitchLists_; @@ -413,19 +354,6 @@ Synth::Impl::~Impl() resources_.filePool.emptyFileLoadingQueues(); } -void Synth::Impl::onVoiceStateChanged(NumericId id, Voice::State state) -{ - (void)id; - (void)state; - if (state == Voice::State::idle) { - auto voice = voiceList_.getVoiceById(id); - RegionSet::removeVoiceFromHierarchy(voice->getRegion(), voice); - engineSet_->removeVoice(voice); - polyphonyGroups_[voice->getRegion()->group].removeVoice(voice); - } - -} - void Synth::Impl::onParseFullBlock(const std::string& header, const std::vector& members) { const auto newRegionSet = [&](OpcodeScope level) { @@ -546,8 +474,12 @@ void Synth::Impl::buildRegion(const std::vector& regionOpcodes) currentSwitch_ = *lastRegion->defaultSwitch; // There was a combination of group= and polyphony= on a region, so set the group polyphony - if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) - setGroupPolyphony(lastRegion->group, lastRegion->polyphony); + if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) { + voiceList_.setGroupPolyphony(lastRegion->group, lastRegion->polyphony); + } else { + // Just check that there are enough polyphony groups + voiceList_.ensureNumPolyphonyGroups(lastRegion->group); + } if (currentSet_ != nullptr) { lastRegion->parent = currentSet_; @@ -595,7 +527,6 @@ void Synth::Impl::clear() resources_.midiState.reset(); resources_.filePool.clear(); resources_.filePool.setRamLoading(config::loadInRam); - stealer_.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::Oldest); ccLabels_.clear(); keyLabels_.clear(); keyswitchLabels_.clear(); @@ -603,9 +534,6 @@ void Synth::Impl::clear() masterOpcodes_.clear(); groupOpcodes_.clear(); unknownOpcodes_.clear(); - polyphonyGroups_.clear(); - polyphonyGroups_.emplace_back(); - polyphonyGroups_.back().setPolyphonyLimit(config::maxVoices); modificationTime_ = fs::file_time_type::min(); // set default controllers @@ -689,12 +617,12 @@ void Synth::Impl::handleGroupOpcodes(const std::vector& members, const s parseOpcode(member); if (groupIdx && maxPolyphony) { - setGroupPolyphony(*groupIdx, *maxPolyphony); + voiceList_.setGroupPolyphony(*groupIdx, *maxPolyphony); } else if (maxPolyphony) { ASSERT(currentSet_ != nullptr); currentSet_->setPolyphonyLimit(*maxPolyphony); - } else if (groupIdx && *groupIdx > polyphonyGroups_.size()) { - setGroupPolyphony(*groupIdx, config::maxVoices); + } else if (groupIdx) { + voiceList_.ensureNumPolyphonyGroups(*groupIdx); } } @@ -749,22 +677,13 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) case hash("hint_stealing"): switch(hash(member.value)) { case hash("first"): - for (auto& voice : voiceList_) - voice.disablePowerFollower(); - - stealer_.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::First); + voiceList_.setStealingAlgorithm(StealingAlgorithm::First); break; case hash("oldest"): - for (auto& voice : voiceList_) - voice.disablePowerFollower(); - - stealer_.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::Oldest); + voiceList_.setStealingAlgorithm(StealingAlgorithm::Oldest); break; case hash("envelope_and_age"): - for (auto& voice : voiceList_) - voice.enablePowerFollower(); - - stealer_.setStealingAlgorithm(VoiceStealing::StealingAlgorithm::EnvelopeAndAge); + voiceList_.setStealingAlgorithm(StealingAlgorithm::EnvelopeAndAge); break; default: DBG("Unsupported value for hint_stealing: " << member.value); @@ -993,12 +912,6 @@ void Synth::Impl::finalizeSfzLoad() } } - // Some regions had group number but no "group-level" opcodes handled the polyphony - while (polyphonyGroups_.size() <= region->group) { - polyphonyGroups_.emplace_back(); - polyphonyGroups_.back().setPolyphonyLimit(config::maxVoices); - } - for (auto note = 0; note < 128; note++) { if (region->keyRange.containsWithEnd(note)) noteActivationLists_[note].push_back(region); @@ -1374,12 +1287,7 @@ void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept void Synth::Impl::startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept { - checkNotePolyphony(region, delay, triggerEvent); - checkRegionPolyphony(region, delay); - checkGroupPolyphony(region, delay); - checkSetPolyphony(region, delay); - checkEnginePolyphony(delay); - + voiceList_.checkPolyphony(region, delay, triggerEvent); Voice* selectedVoice = findFreeVoice(); if (selectedVoice == nullptr) return; @@ -1387,9 +1295,6 @@ void Synth::Impl::startVoice(Region* region, int delay, const TriggerEvent& trig ASSERT(selectedVoice->isFree()); selectedVoice->startVoice(region, delay, triggerEvent); ring.addVoiceToRing(selectedVoice); - engineSet_->registerVoice(selectedVoice); - RegionSet::registerVoiceInHierarchy(region, selectedVoice); - polyphonyGroups_[region->group].registerVoice(selectedVoice); } void Synth::Impl::noteOffDispatch(int delay, int noteNumber, float velocity) noexcept @@ -1414,100 +1319,6 @@ void Synth::Impl::noteOffDispatch(int delay, int noteNumber, float velocity) noe } } -void Synth::Impl::checkRegionPolyphony(const Region* region, int delay) noexcept -{ - tempPolyphonyArray_.clear(); - absl::c_copy_if(voiceViewArray_, - std::back_inserter(tempPolyphonyArray_), - [region](Voice* v) { return v->getRegion() == region && !v->releasedOrFree(); }); - - if (tempPolyphonyArray_.size() >= region->polyphony) { - const auto voiceToSteal = stealer_.steal(absl::MakeSpan(tempPolyphonyArray_)); - SisterVoiceRing::offAllSisters(voiceToSteal, delay); - } -} - -void Synth::Impl::checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept -{ - if (!region->notePolyphony) - return; - - unsigned notePolyphonyCounter { 0 }; - Voice* selfMaskCandidate { nullptr }; - - for (Voice* voice : voiceViewArray_) { - const TriggerEvent& voiceTriggerEvent = voice->getTriggerEvent(); - const bool skipVoice = (triggerEvent.type == TriggerEventType::NoteOn && voice->releasedOrFree()) || voice->isFree(); - if (!skipVoice - && voice->getRegion()->group == region->group - && voiceTriggerEvent.number == triggerEvent.number - && voiceTriggerEvent.type == triggerEvent.type) { - notePolyphonyCounter += 1; - switch (region->selfMask) { - case SfzSelfMask::mask: - if (voiceTriggerEvent.value <= triggerEvent.value) { - if (!selfMaskCandidate || selfMaskCandidate->getTriggerEvent().value > voiceTriggerEvent.value) { - selfMaskCandidate = voice; - } - } - break; - case SfzSelfMask::dontMask: - if (!selfMaskCandidate || selfMaskCandidate->getAge() < voice->getAge()) - selfMaskCandidate = voice; - break; - } - } - } - - if (notePolyphonyCounter >= *region->notePolyphony && selfMaskCandidate) { - SisterVoiceRing::offAllSisters(selfMaskCandidate, delay); - } -} - -void Synth::Impl::checkGroupPolyphony(const Region* region, int delay) noexcept -{ - const auto& activeVoices = polyphonyGroups_[region->group].getActiveVoices(); - tempPolyphonyArray_.clear(); - absl::c_copy_if(activeVoices, - std::back_inserter(tempPolyphonyArray_), [](Voice* v) { return !v->releasedOrFree(); }); - - if (tempPolyphonyArray_.size() >= polyphonyGroups_[region->group].getPolyphonyLimit()) { - const auto voiceToSteal = stealer_.steal(absl::MakeSpan(tempPolyphonyArray_)); - SisterVoiceRing::offAllSisters(voiceToSteal, delay); - } -} - -void Synth::Impl::checkSetPolyphony(const Region* region, int delay) noexcept -{ - auto parent = region->parent; - while (parent != nullptr) { - const auto& activeVoices = parent->getActiveVoices(); - tempPolyphonyArray_.clear(); - absl::c_copy_if(activeVoices, - std::back_inserter(tempPolyphonyArray_), [](Voice* v) { return !v->releasedOrFree(); }); - - if (tempPolyphonyArray_.size() >= parent->getPolyphonyLimit()) { - const auto voiceToSteal = stealer_.steal(absl::MakeSpan(tempPolyphonyArray_)); - SisterVoiceRing::offAllSisters(voiceToSteal, delay); - } - - parent = parent->getParent(); - } -} - -void Synth::Impl::checkEnginePolyphony(int delay) noexcept -{ - auto& activeVoices = engineSet_->getActiveVoices(); - - if (activeVoices.size() >= static_cast(numRequiredVoices_)) { - tempPolyphonyArray_.clear(); - absl::c_copy_if(activeVoices, - std::back_inserter(tempPolyphonyArray_), [](Voice* v) { return !v->releasedOrFree(); }); - const auto voiceToSteal = stealer_.steal(absl::MakeSpan(tempPolyphonyArray_)); - SisterVoiceRing::offAllSisters(voiceToSteal, delay, true); - } -} - void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noexcept { const auto randValue = randNoteDistribution_(Random::randomGenerator); @@ -1839,7 +1650,7 @@ const RegionSet* Synth::getRegionSetView(int idx) const noexcept const PolyphonyGroup* Synth::getPolyphonyGroupView(int idx) const noexcept { Impl& impl = *impl_; - return (size_t)idx < impl.polyphonyGroups_.size() ? &impl.polyphonyGroups_[idx] : nullptr; + return impl.voiceList_.getPolyphonyGroupView(idx); } const Region* Synth::getRegionById(NumericId id) const noexcept @@ -1869,7 +1680,7 @@ const Voice* Synth::getVoiceView(int idx) const noexcept unsigned Synth::getNumPolyphonyGroups() const noexcept { Impl& impl = *impl_; - return impl.polyphonyGroups_.size(); + return impl.voiceList_.getNumPolyphonyGroups(); } const std::vector& Synth::getUnknownOpcodes() const noexcept @@ -1971,7 +1782,7 @@ void Synth::Impl::resetVoices(int numVoices) Voice& lastVoice = voiceList_.back(); lastVoice.setSampleRate(this->sampleRate_); lastVoice.setSamplesPerBlock(this->samplesPerBlock_); - lastVoice.setStateListener(this); + lastVoice.setStateListener(&voiceList_); voiceViewArray_.push_back(&lastVoice); } @@ -1988,15 +1799,6 @@ void Synth::Impl::applySettingsPerVoice() voice.setPitchEGEnabledPerVoice(settingsPerVoice_.havePitchEG); voice.setFilterEGEnabledPerVoice(settingsPerVoice_.haveFilterEG); } - - if (stealer_.getStealingAlgorithm() == - VoiceStealing::StealingAlgorithm::EnvelopeAndAge) { - for (auto& voice : voiceList_) - voice.enablePowerFollower(); - } else { - for (auto& voice : voiceList_) - voice.disablePowerFollower(); - } } void Synth::Impl::setupModMatrix() @@ -2076,7 +1878,8 @@ void Synth::setOversamplingFactor(Oversampling factor) noexcept if (factor == impl.oversamplingFactor_) return; - impl.voiceList_.reset(); + for (auto& voice : impl.voiceList_) + voice.reset(); impl.resources_.filePool.emptyFileLoadingQueues(); impl.resources_.filePool.setOversamplingFactor(factor); @@ -2191,19 +1994,12 @@ void Synth::allSoundOff() noexcept Impl& impl = *impl_; const std::lock_guard disableCallback { impl.callbackGuard_ }; - impl.voiceList_.reset(); + for (auto& voice : impl.voiceList_) + voice.reset(); for (auto& effectBus : impl.effectBuses_) effectBus->clear(); } -void Synth::Impl::setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept -{ - while (polyphonyGroups_.size() <= groupIdx) - polyphonyGroups_.emplace_back(); - - polyphonyGroups_[groupIdx].setPolyphonyLimit(polyphony); -} - std::bitset Synth::getUsedCCs() const noexcept { Impl& impl = *impl_; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index e57dd627..dcdfccd2 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1582,7 +1582,7 @@ void Voice::Impl::switchState(State s) if (s != state_) { state_ = s; if (stateListener_) - stateListener_->onVoiceStateChanged(id_, s); + stateListener_->onVoiceStateChanging(id_, s); } } diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 2e79584a..35428a6b 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -53,7 +53,7 @@ public: class StateListener { public: - virtual void onVoiceStateChanged(NumericId /*id*/, State /*state*/) {} + virtual void onVoiceStateChanging(NumericId /*id*/, State /*state*/) {} }; /** diff --git a/src/sfizz/VoiceList.h b/src/sfizz/VoiceList.h index 0903c0bb..660c1090 100644 --- a/src/sfizz/VoiceList.h +++ b/src/sfizz/VoiceList.h @@ -7,14 +7,37 @@ #pragma once #include "Voice.h" +#include "Config.h" #include "Region.h" +#include "SisterVoiceRing.h" +#include "PolyphonyGroup.h" +#include "RegionSet.h" +#include "VoiceStealing.h" #include #include namespace sfz { -struct VoiceList +struct VoiceList : public Voice::StateListener { + /** + * @brief The voice callback which is called during a change of state. + */ + void onVoiceStateChanging(NumericId id, Voice::State state) final + { + (void)id; + if (state == Voice::State::idle) { + auto voice = getVoiceById(id); + RegionSet::removeVoiceFromHierarchy(voice->getRegion(), voice); + swapAndPopFirst(activeVoices_, [voice](const Voice* v) { return v == voice; }); + polyphonyGroups_[voice->getRegion()->group].removeVoice(voice); + } else if (state == Voice::State::playing) { + auto voice = getVoiceById(id); + activeVoices_.push_back(voice); + RegionSet::registerVoiceInHierarchy(voice->getRegion(), voice); + polyphonyGroups_[voice->getRegion()->group].registerVoice(voice); + } + } /** * @brief Find the voice which is associated with the given identifier. * @@ -48,6 +71,11 @@ struct VoiceList { for (auto& voice : list_) voice.reset(); + + polyphonyGroups_.clear(); + polyphonyGroups_.emplace_back(); + polyphonyGroups_.back().setPolyphonyLimit(config::maxVoices); + setStealingAlgorithm(StealingAlgorithm::Oldest); } bool playingAttackVoice(const Region* releaseRegion) noexcept @@ -68,21 +96,187 @@ struct VoiceList return true; } - typename std::vector::iterator begin() { return list_.begin(); } - typename std::vector::const_iterator cbegin() const { return list_.cbegin(); } - typename std::vector::iterator end() { return list_.end(); } - typename std::vector::const_iterator cend() const { return list_.cend(); } - typename std::vector::reference operator[] (size_t n) { return list_[n]; } - typename std::vector::const_reference operator[] (size_t n) const { return list_[n]; } - typename std::vector::reference back() { return list_.back(); } - typename std::vector::const_reference back() const { return list_.back(); } + void ensureNumPolyphonyGroups(unsigned groupIdx) noexcept + { + while (polyphonyGroups_.size() <= groupIdx) + polyphonyGroups_.emplace_back(); + } + + void setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept + { + ensureNumPolyphonyGroups(groupIdx); + polyphonyGroups_[groupIdx].setPolyphonyLimit(polyphony); + } + + size_t getNumPolyphonyGroups() const noexcept { return polyphonyGroups_.size(); } + + const PolyphonyGroup* getPolyphonyGroupView(int idx) const noexcept + { + return (size_t)idx < polyphonyGroups_.size() ? &polyphonyGroups_[idx] : nullptr; + } + + void clear() + { + reset(); + list_.clear(); + activeVoices_.clear(); + } + + void setStealingAlgorithm(StealingAlgorithm algorithm) + { + switch(algorithm){ + case StealingAlgorithm::First: // fallthrough + for (auto& voice : list_) + voice.disablePowerFollower(); + + stealer_ = absl::make_unique(); + break; + case StealingAlgorithm::Oldest: + for (auto& voice : list_) + voice.disablePowerFollower(); + + stealer_ = absl::make_unique(); + break; + case StealingAlgorithm::EnvelopeAndAge: + for (auto& voice : list_) + voice.enablePowerFollower(); + + stealer_ = absl::make_unique(); + break; + } + } + + void checkPolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept + { + checkNotePolyphony(region, delay, triggerEvent); + checkRegionPolyphony(region, delay); + checkGroupPolyphony(region, delay); + checkSetPolyphony(region, delay); + checkEnginePolyphony(delay); + } + +private: + std::vector list_; + std::vector activeVoices_; + std::vector temp_; + // These are the `group=` groups where you can off voices + std::vector polyphonyGroups_; + std::unique_ptr stealer_ { absl::make_unique() }; + + /** + * @brief Check the region polyphony, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkRegionPolyphony(const Region* region, int delay) noexcept + { + Voice* candidate = stealer_->checkRegionPolyphony(region, absl::MakeSpan(activeVoices_)); + SisterVoiceRing::offAllSisters(candidate, delay); + } + + /** + * @brief Check the note polyphony, releasing voices if necessary + * + * @param region + * @param delay + * @param triggerEvent + */ + void checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept + { + if (!region->notePolyphony) + return; + + unsigned notePolyphonyCounter { 0 }; + Voice* selfMaskCandidate { nullptr }; + + for (Voice* voice : activeVoices_) { + const TriggerEvent& voiceTriggerEvent = voice->getTriggerEvent(); + const bool skipVoice = (triggerEvent.type == TriggerEventType::NoteOn && voice->releasedOrFree()) || voice->isFree(); + if (!skipVoice + && voice->getRegion()->group == region->group + && voiceTriggerEvent.number == triggerEvent.number + && voiceTriggerEvent.type == triggerEvent.type) { + notePolyphonyCounter += 1; + switch (region->selfMask) { + case SfzSelfMask::mask: + if (voiceTriggerEvent.value <= triggerEvent.value) { + if (!selfMaskCandidate || selfMaskCandidate->getTriggerEvent().value > voiceTriggerEvent.value) { + selfMaskCandidate = voice; + } + } + break; + case SfzSelfMask::dontMask: + if (!selfMaskCandidate || selfMaskCandidate->getAge() < voice->getAge()) + selfMaskCandidate = voice; + break; + } + } + } + + if (notePolyphonyCounter >= *region->notePolyphony) { + SisterVoiceRing::offAllSisters(selfMaskCandidate, delay); + } + } + + /** + * @brief Check the group polyphony, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkGroupPolyphony(const Region* region, int delay) noexcept + { + auto& group = polyphonyGroups_[region->group]; + Voice* candidate = stealer_->checkPolyphony( + absl::MakeSpan(group.getActiveVoices()), group.getPolyphonyLimit()); + SisterVoiceRing::offAllSisters(candidate, delay); + } + + /** + * @brief Check the region set polyphony at all levels, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkSetPolyphony(const Region* region, int delay) noexcept + { + auto parent = region->parent; + while (parent != nullptr) { + Voice* candidate = stealer_->checkPolyphony( + absl::MakeSpan(parent->getActiveVoices()), parent->getPolyphonyLimit()); + SisterVoiceRing::offAllSisters(candidate, delay); + parent = parent->getParent(); + } + } + + /** + * @brief Check the engine polyphony, fast releasing voices if necessary + * + * @param delay + */ + void checkEnginePolyphony(int delay) noexcept + { + // TODO (paul): should have the "required" vs "actual" number of voices here + Voice* candidate = stealer_->checkPolyphony( + absl::MakeSpan(activeVoices_), list_.size()); + SisterVoiceRing::offAllSisters(candidate, delay); + } + +public: + // Vector shortcuts + typename decltype(list_)::iterator begin() { return list_.begin(); } + typename decltype(list_)::const_iterator cbegin() const { return list_.cbegin(); } + typename decltype(list_)::iterator end() { return list_.end(); } + typename decltype(list_)::const_iterator cend() const { return list_.cend(); } + typename decltype(list_)::reference operator[] (size_t n) { return list_[n]; } + typename decltype(list_)::const_reference operator[] (size_t n) const { return list_[n]; } + typename decltype(list_)::reference back() { return list_.back(); } + typename decltype(list_)::const_reference back() const { return list_.back(); } size_t size() const { return list_.size(); } - void clear() { list_.clear(); } void reserve(size_t n) { list_.reserve(n); } template< class... Args > void emplace_back(Args&&... args) { list_.emplace_back(std::forward(args)...); } -private: - std::vector list_; }; } // namespace sfz diff --git a/src/sfizz/VoiceStealing.cpp b/src/sfizz/VoiceStealing.cpp index 878f5fb8..6d06f6e6 100644 --- a/src/sfizz/VoiceStealing.cpp +++ b/src/sfizz/VoiceStealing.cpp @@ -1,57 +1,102 @@ #include "VoiceStealing.h" +#include "SisterVoiceRing.h" -sfz::VoiceStealing::VoiceStealing() +namespace sfz { + +/** + * @brief Generic polyphony checker + * A voice is counted as incrementing the voice count and "stealable" if voiceCond(voice) is true. + * For each stealable voice, the voice becomes the stealing candidate if candidateCont(voice, candidate) is true. + * + * @tparam F + * @tparam G + * @param candidates + * @param voiceCond a functor with signature bool(Voice* voice) + * @param candidateCond a functor with signature bool(Voice* voice, Voice* candidate) + * @return Voice* + */ +template +Voice* genericPolyphonyCheck(absl::Span candidates, unsigned polyphony, F&& voiceCond, G&& candidateCond) { - voiceScores.reserve(config::maxVoices); -} - -sfz::Voice* sfz::VoiceStealing::steal(absl::Span voices) noexcept -{ - if (voices.empty()) - return {}; - - switch(stealingAlgorithm) { - case StealingAlgorithm::First: - return stealFirst(voices); - case StealingAlgorithm::EnvelopeAndAge: - return stealEnvelopeAndAge(voices); - case StealingAlgorithm::Oldest: - default: - return stealOldest(voices); + Voice* candidate = nullptr; + unsigned numPlaying = 0; + for (const auto& voice : candidates) { + if (voiceCond(voice)) { + if (candidateCond(voice, candidate)) + candidate = voice; + numPlaying += 1; + } } + + if (numPlaying >= polyphony) + return candidate; + + return {}; } -void sfz::VoiceStealing::setStealingAlgorithm(StealingAlgorithm algorithm) noexcept +/** + * @brief Helper to ignore the voice if released depending on a boolean + * + * @param voice + * @param ignoreReleased + */ +constexpr bool ignoreVoice(const Voice* voice) { - stealingAlgorithm = algorithm; + return (voice == nullptr || voice->releasedOrFree()); } -sfz::Voice* sfz::VoiceStealing::stealFirst(absl::Span voices) noexcept +Voice* FirstStealer::checkRegionPolyphony(const Region* region, absl::Span candidates) { - return voices.front(); + ASSERT(region); + return genericPolyphonyCheck(candidates, region->polyphony, + [=](const Voice* v) { return (!ignoreVoice(v) && v->getRegion() == region); }, + [=](const Voice* v, const Voice* c) { return c == nullptr; }); } -sfz::Voice* sfz::VoiceStealing::stealOldest(absl::Span voices) noexcept +Voice* FirstStealer::checkPolyphony(absl::Span candidates, unsigned maxPolyphony) { - absl::c_sort(voices, voiceOrdering); - return voices.front(); + return genericPolyphonyCheck(candidates, maxPolyphony, + [=](const Voice* v) { return (!ignoreVoice(v)); }, + [=](const Voice* v, const Voice* c) { return c == nullptr; }); } -sfz::Voice* sfz::VoiceStealing::stealEnvelopeAndAge(absl::Span voices) noexcept +Voice* OldestStealer::checkRegionPolyphony(const Region* region, absl::Span candidates) +{ + ASSERT(region); + return genericPolyphonyCheck(candidates, region->polyphony, + [=](const Voice* v) { return (!ignoreVoice(v) && v->getRegion() == region); }, + [=](const Voice* v, const Voice* c) { return (c == nullptr || v->getAge() > c->getAge()); }); +} + +Voice* OldestStealer::checkPolyphony(absl::Span candidates, unsigned maxPolyphony) +{ + return genericPolyphonyCheck(candidates, maxPolyphony, + [=](const Voice* v) { return (!ignoreVoice(v)); }, + [=](const Voice* v, const Voice* c) { return (c == nullptr || v->getAge() > c->getAge()); }); +} + +/** + * @brief Stealer on envelope and age. + * The stealer checks that the power to try and kill voices with relative low contribution + * to the output compared to the rest. + * The stealer also checks the age so that voices have the time to build up attack + * This is not perfect because pad-type voices will take a long time to output + * their sound, but it's reasonable for sounds with a quick attack and longer + * release. + * + * @param voices + * @return sfz::Voice* + */ +sfz::Voice* stealEnvelopeAndAge(absl::Span voices) noexcept { absl::c_sort(voices, voiceOrdering); const auto sumPower = absl::c_accumulate(voices, 0.0f, [](float sum, const Voice* v) { return sum + v->getAveragePower(); }); - // We are checking the power to try and kill voices with relative low contribution - // to the output compared to the rest. + const auto powerThreshold = sumPower / static_cast(voices.size()) * config::stealingPowerCoeff; - // We are checking the age so that voices have the time to build up attack - // This is not perfect because pad-type voices will take a long time to output - // their sound, but it's reasonable for sounds with a quick attack and longer - // release. const auto ageThreshold = static_cast(voices.front()->getAge() * config::stealingAgeCoeff); @@ -82,3 +127,37 @@ sfz::Voice* sfz::VoiceStealing::stealEnvelopeAndAge(absl::Span voices) n return returnedVoice; } + +Voice* EnvelopeAndAgeStealer::checkRegionPolyphony(const Region* region, absl::Span candidates) +{ + ASSERT(region); + temp_.clear(); + absl::c_copy_if(candidates, std::back_inserter(temp_), [=](Voice* v) { + return (!ignoreVoice(v) && v->getRegion() == region); + }); + + if (temp_.size() >= region->polyphony) + return stealEnvelopeAndAge(absl::MakeSpan(temp_)); + + return {}; +} + +Voice* EnvelopeAndAgeStealer::checkPolyphony(absl::Span candidates, unsigned maxPolyphony) +{ + temp_.clear(); + absl::c_copy_if(candidates, std::back_inserter(temp_), [=](Voice* v) { + return !ignoreVoice(v); + }); + + if (temp_.size() >= maxPolyphony) + return stealEnvelopeAndAge(absl::MakeSpan(temp_)); + + return {}; +} + +EnvelopeAndAgeStealer::EnvelopeAndAgeStealer() +{ + temp_.reserve(config::maxVoices); +} + +} diff --git a/src/sfizz/VoiceStealing.h b/src/sfizz/VoiceStealing.h index 47eb8692..78e5000c 100644 --- a/src/sfizz/VoiceStealing.h +++ b/src/sfizz/VoiceStealing.h @@ -7,6 +7,7 @@ #pragma once #include "Config.h" +#include "Region.h" #include "Voice.h" #include "SisterVoiceRing.h" #include @@ -14,64 +15,56 @@ namespace sfz { -class VoiceStealing + +enum class StealingAlgorithm { + First, + Oldest, + EnvelopeAndAge +}; + +class VoiceStealer { public: - enum class StealingAlgorithm { - First, - Oldest, - EnvelopeAndAge - }; - - VoiceStealing(); /** - * @brief Get the current stealing algorithm + * @brief Check that the region polyphony is respected. * - * @return StealingAlgorithm + * @param region + * @param candidates + * @return Voice* a non-null voice if the region polyphony is not respected */ - StealingAlgorithm getStealingAlgorithm() const noexcept { return stealingAlgorithm; } + virtual Voice* checkRegionPolyphony(const Region* region, absl::Span candidates) = 0; /** - * @brief Set a default stealing algorithm + * @brief Check that then polyphony is respected. * - * @param algorithm + * @param region + * @param candidates + * @return Voice* a non-null voice if the region polyphony is not respected */ - void setStealingAlgorithm(StealingAlgorithm algorithm) noexcept; - /** - * @brief Propose a voice to steal from a set of voices - * - * @param voices - * @return Voice* - */ - Voice* steal(absl::Span voices) noexcept; -private: - StealingAlgorithm stealingAlgorithm { StealingAlgorithm::Oldest }; - Voice* stealFirst(absl::Span voices) noexcept; - Voice* stealOldest(absl::Span voices) noexcept; - Voice* stealEnvelopeAndAge(absl::Span voices) noexcept; - - struct VoiceScore - { - Voice* voice; - double score; - }; - - struct VoiceScoreComparator - { - bool operator()(const VoiceScore& voiceScore, const double& score) - { - return (voiceScore.score < score); - } - - bool operator()(const double& score, const VoiceScore& voiceScore) - { - return (score < voiceScore.score); - } - - bool operator()(const VoiceScore& lhs, const VoiceScore& rhs) - { - return (lhs.score < rhs.score); - } - }; - std::vector voiceScores; + virtual Voice* checkPolyphony(absl::Span candidates, unsigned maxPolyphony) = 0; }; + +class FirstStealer : public VoiceStealer +{ +public: + Voice* checkRegionPolyphony(const Region* region, absl::Span candidates) final; + Voice* checkPolyphony(absl::Span candidates, unsigned maxPolyphony) final; +}; + +class OldestStealer : public VoiceStealer +{ +public: + Voice* checkRegionPolyphony(const Region* region, absl::Span candidates) final; + Voice* checkPolyphony(absl::Span candidates, unsigned maxPolyphony) final; +}; + +class EnvelopeAndAgeStealer : public VoiceStealer +{ +public: + EnvelopeAndAgeStealer(); + Voice* checkRegionPolyphony(const Region* region, absl::Span candidates) final; + Voice* checkPolyphony(absl::Span candidates, unsigned maxPolyphony) final; +private: + std::vector temp_; +}; + } From 1fcfbdbaf7d86f363424f1255d9512328fcd7fd3 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 19:28:23 +0100 Subject: [PATCH 055/668] move getNumActiveVoices in the voiceList --- src/sfizz/Synth.cpp | 13 +-- src/sfizz/Synth.h | 2 +- src/sfizz/VoiceList.h | 5 ++ tests/FilesT.cpp | 6 +- tests/FlexEGT.cpp | 14 ++-- tests/PolyphonyT.cpp | 58 +++++++------- tests/RegionActivationT.cpp | 82 +++++++++---------- tests/SynthT.cpp | 154 ++++++++++++++++++------------------ 8 files changed, 165 insertions(+), 169 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 7c6fb08d..bc95c214 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -1069,19 +1069,10 @@ Voice* Synth::Impl::findFreeVoice() noexcept return {}; } -int Synth::getNumActiveVoices(bool recompute) const noexcept +int Synth::getNumActiveVoices() const noexcept { Impl& impl = *impl_; - if (!recompute) - return impl.activeVoices_; - - int active { 0 }; - for (auto& voice: impl.voiceList_) { - if (!voice.isFree()) - active++; - } - - return active; + return static_cast(impl.voiceList_.getNumActiveVoices()); } void Synth::setSamplesPerBlock(int samplesPerBlock) noexcept diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index bb93ab6c..b9611835 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -416,7 +416,7 @@ public: * * @return int */ - int getNumActiveVoices(bool recompute = false) const noexcept; + int getNumActiveVoices() const noexcept; /** * @brief Get the total number of voices in the synth (the polyphony) * diff --git a/src/sfizz/VoiceList.h b/src/sfizz/VoiceList.h index 660c1090..51013d5a 100644 --- a/src/sfizz/VoiceList.h +++ b/src/sfizz/VoiceList.h @@ -155,6 +155,11 @@ struct VoiceList : public Voice::StateListener checkEnginePolyphony(delay); } + unsigned getNumActiveVoices() const + { + return activeVoices_.size(); + } + private: std::vector list_; std::vector activeVoices_; diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index b0a19757..02004ab7 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -489,7 +489,7 @@ TEST_CASE("[Files] Off modes") synth.loadSfzFile(fs::current_path() / "tests/TestFiles/off_mode.sfz"); REQUIRE( synth.getNumRegions() == 3 ); synth.noteOn(0, 64, 63); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); const auto* fastVoice = synth.getVoiceView(0)->getRegion()->offMode == SfzOffMode::fast ? synth.getVoiceView(0) : @@ -499,12 +499,12 @@ TEST_CASE("[Files] Off modes") synth.getVoiceView(1) : synth.getVoiceView(0) ; synth.noteOn(100, 63, 63); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); REQUIRE( numPlayingVoices(synth) == 1 ); AudioBuffer buffer { 2, 256 }; for (unsigned i = 0; i < 10; ++i) // Not enough for the "normal" voice to die synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); REQUIRE( fastVoice->isFree() ); REQUIRE( !normalVoice->isFree() ); } diff --git a/tests/FlexEGT.cpp b/tests/FlexEGT.cpp index 439ead5c..a7a2e634 100644 --- a/tests/FlexEGT.cpp +++ b/tests/FlexEGT.cpp @@ -394,25 +394,25 @@ TEST_CASE("[FlexEG] Free-running flex AmpEG (no sustain)") synth.noteOn(0, 60, 0); sfz::AudioBuffer buffer { 2, 256 }; synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); for (unsigned i = 0; i < 100; ++i) synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 0); synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); for (unsigned i = 0; i < 100; ++i) synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 64, 0); synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); for (unsigned i = 0; i < 100; ++i) synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); synth.noteOff(0, 64, 0); // the release stage is 0 duration synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); } diff --git a/tests/PolyphonyT.cpp b/tests/PolyphonyT.cpp index c7541391..58a5cd54 100644 --- a/tests/PolyphonyT.cpp +++ b/tests/PolyphonyT.cpp @@ -84,7 +84,7 @@ TEST_CASE("[Polyphony] group polyphony limits") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } @@ -100,7 +100,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } @@ -116,7 +116,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (group)") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } @@ -133,7 +133,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (master)") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } @@ -155,7 +155,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (limit in another master)") synth.noteOn(0, 66, 64); synth.noteOn(0, 66, 64); synth.noteOn(0, 66, 64); - REQUIRE( synth.getNumActiveVoices(true) == 6); + REQUIRE( synth.getNumActiveVoices() == 6); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 5); // One is releasing } @@ -172,7 +172,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (global)") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } @@ -194,25 +194,25 @@ TEST_CASE("[Polyphony] Polyphony in master") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing synth.allSoundOff(); synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 0); + REQUIRE( synth.getNumActiveVoices() == 0); synth.noteOn(0, 63, 64); synth.noteOn(0, 63, 64); synth.noteOn(0, 63, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing synth.allSoundOff(); synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 0); + REQUIRE( synth.getNumActiveVoices() == 0); synth.noteOn(0, 61, 64); synth.noteOn(0, 61, 64); synth.noteOn(0, 61, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 3 ); } @@ -228,7 +228,7 @@ TEST_CASE("[Polyphony] Self-masking") synth.noteOn(0, 64, 63 ); synth.noteOn(0, 64, 62 ); synth.noteOn(0, 64, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); // One of these is releasing + REQUIRE( synth.getNumActiveVoices() == 3 ); // One of these is releasing synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); @@ -249,7 +249,7 @@ TEST_CASE("[Polyphony] Not self-masking") synth.noteOn(0, 66, 63 ); synth.noteOn(0, 66, 62 ); synth.noteOn(0, 66, 64); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); // One of these is releasing + REQUIRE( synth.getNumActiveVoices() == 3 ); // One of these is releasing synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); @@ -270,7 +270,7 @@ TEST_CASE("[Polyphony] Self-masking with the exact same velocity") synth.noteOn(0, 64, 64); synth.noteOn(0, 64, 63 ); synth.noteOn(0, 64, 63 ); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); // One of these is releasing + REQUIRE( synth.getNumActiveVoices() == 3 ); // One of these is releasing synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 2 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 64_norm); @@ -289,7 +289,7 @@ TEST_CASE("[Polyphony] Self-masking only works from low to high") )"); synth.noteOn(0, 64, 63 ); synth.noteOn(0, 64, 62 ); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); // Both notes are playing + REQUIRE( synth.getNumActiveVoices() == 2 ); // Both notes are playing REQUIRE( numPlayingVoices(synth) == 2 ); // id REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); REQUIRE(!synth.getVoiceView(0)->releasedOrFree()); @@ -307,7 +307,7 @@ TEST_CASE("[Polyphony] Note polyphony checks works across regions in the same po )"); synth.noteOn(0, 64, 62 ); synth.noteOn(0, 64, 63 ); - REQUIRE( synth.getNumActiveVoices(true) == 4); + REQUIRE( synth.getNumActiveVoices() == 4); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 1 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 62_norm); @@ -330,12 +330,12 @@ TEST_CASE("[Polyphony] Note polyphony checks works across regions in the same po sw_last=37 key=48 transpose=12 note_polyphony=1 sample=*tri )"); synth.noteOn(0, 48, 63 ); - REQUIRE( synth.getNumActiveVoices(true) == 1); + REQUIRE( synth.getNumActiveVoices() == 1); synth.cc(0, 64, 127); synth.noteOn(0, 37, 127); synth.noteOff(0, 37, 0); synth.noteOn(0, 48, 64); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 1 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); @@ -355,7 +355,7 @@ TEST_CASE("[Polyphony] Note polyphony do not operate across polyphony groups") )"); synth.noteOn(0, 64, 62 ); synth.noteOn(0, 64, 63 ); - REQUIRE( synth.getNumActiveVoices(true) == 4); // Both notes are playing + REQUIRE( synth.getNumActiveVoices() == 4); // Both notes are playing synth.renderBlock(buffer); REQUIRE(numPlayingVoices(synth) == 2 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 62_norm); @@ -378,12 +378,12 @@ TEST_CASE("[Polyphony] Note polyphony do not operate across polyphony groups (wi group=2 sw_last=37 key=48 transpose=12 note_polyphony=1 sample=*tri )"); synth.noteOn(0, 48, 63 ); - REQUIRE( synth.getNumActiveVoices(true) == 1); + REQUIRE( synth.getNumActiveVoices() == 1); synth.cc(0, 64, 127); synth.noteOn(0, 37, 127); synth.noteOff(0, 37, 0); synth.noteOn(0, 48, 64); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); synth.renderBlock(buffer); REQUIRE(numPlayingVoices(synth) == 2 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); @@ -401,10 +401,10 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices") )"); synth.noteOn(0, 48, 63 ); synth.noteOff(10, 48, 0 ); - REQUIRE( synth.getNumActiveVoices(true) == 1); + REQUIRE( synth.getNumActiveVoices() == 1); synth.noteOn(20, 48, 65 ); synth.noteOff(30, 48, 10 ); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); synth.renderBlock(buffer); REQUIRE(numPlayingVoices(synth) == 1 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); @@ -422,11 +422,11 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices (masking works )"); synth.noteOn(0, 48, 63 ); synth.noteOff(10, 48, 0 ); - REQUIRE( synth.getNumActiveVoices(true) == 1); + REQUIRE( synth.getNumActiveVoices() == 1); REQUIRE( numPlayingVoices(synth) == 1 ); synth.noteOn(20, 48, 61 ); synth.noteOff(30, 48, 10 ); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); REQUIRE( numPlayingVoices(synth) == 2 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); REQUIRE(!synth.getVoiceView(0)->releasedOrFree()); @@ -449,10 +449,10 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped synth.noteOff(3, 48, 0 ); synth.noteOn(4, 48, 63 ); synth.noteOff(5, 48, 0 ); - REQUIRE( synth.getNumActiveVoices(true) == 3); + REQUIRE( synth.getNumActiveVoices() == 3); REQUIRE( numPlayingVoices(synth) == 3 ); synth.cc(20, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 6 ); + REQUIRE( synth.getNumActiveVoices() == 6 ); REQUIRE( numPlayingVoices(synth) == 1 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 61_norm); REQUIRE( synth.getVoiceView(0)->releasedOrFree()); @@ -483,10 +483,10 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped synth.noteOff(3, 48, 0 ); synth.noteOn(4, 48, 61 ); synth.noteOff(5, 48, 0 ); - REQUIRE( synth.getNumActiveVoices(true) == 3); + REQUIRE( synth.getNumActiveVoices() == 3); REQUIRE( numPlayingVoices(synth) == 3 ); synth.cc(20, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 6 ); + REQUIRE( synth.getNumActiveVoices() == 6 ); REQUIRE( numPlayingVoices(synth) == 3 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); REQUIRE( synth.getVoiceView(0)->releasedOrFree()); diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index b67690ee..22723ff9 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -186,14 +186,14 @@ TEST_CASE("[Keyswitches] Normal lastKeyswitch range") sw_last=41 key=62 sample=*saw )"); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 41, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); } TEST_CASE("[Keyswitches] No lastKeyswitch range") @@ -204,19 +204,19 @@ TEST_CASE("[Keyswitches] No lastKeyswitch range") sw_last=41 key=62 sample=*saw )"); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); synth.noteOn(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 41, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); } TEST_CASE("[Keyswitches] Out of lastKeyswitch range") @@ -228,14 +228,14 @@ TEST_CASE("[Keyswitches] Out of lastKeyswitch range") sw_last=43 key=62 sample=*saw )"); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 43, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); } TEST_CASE("[Keyswitches] Overlapping key and lastKeyswitch range") @@ -247,19 +247,19 @@ TEST_CASE("[Keyswitches] Overlapping key and lastKeyswitch range") sw_last=41 key=62 sample=*saw )"); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 41, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); synth.noteOn(0, 43, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); synth.noteOn(0, 62, 64); - REQUIRE(synth.getNumActiveVoices(true) == 3); + REQUIRE(synth.getNumActiveVoices() == 3); } TEST_CASE("[Keyswitches] sw_down, in range") @@ -270,13 +270,13 @@ TEST_CASE("[Keyswitches] sw_down, in range") sw_down=40 key=60 sample=*sine )"); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); synth.noteOn(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOff(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); } TEST_CASE("[Keyswitches] sw_down, out of range") @@ -287,13 +287,13 @@ TEST_CASE("[Keyswitches] sw_down, out of range") sw_down=40 key=60 sample=*sine )"); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); synth.noteOn(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOff(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); } TEST_CASE("[Keyswitches] sw_up, in range") @@ -304,13 +304,13 @@ TEST_CASE("[Keyswitches] sw_up, in range") sw_up=40 key=60 sample=*sine )"); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOff(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); } TEST_CASE("[Keyswitches] sw_up, out of range") @@ -321,13 +321,13 @@ TEST_CASE("[Keyswitches] sw_up, out of range") sw_up=40 key=60 sample=*sine )"); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOn(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); synth.noteOff(0, 40, 64); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); } TEST_CASE("[Keyswitches] sw_default") @@ -387,18 +387,18 @@ TEST_CASE("[Keyswitches] sw_previous in range") // the test assumes that sw_previous regions are disabled by default REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); synth.noteOn(0, 51, 64); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); REQUIRE(synth.getRegionView(0)->isSwitchedOn()); synth.noteOn(0, 51, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(synth.getRegionView(0)->isSwitchedOn()); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); REQUIRE(synth.getRegionView(0)->isSwitchedOn()); } @@ -411,15 +411,15 @@ TEST_CASE("[Keyswitches] sw_previous out of range") )"); REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); synth.noteOn(0, 51, 64); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); REQUIRE(synth.getRegionView(0)->isSwitchedOn()); synth.noteOn(0, 51, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); synth.noteOn(0, 60, 64); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(synth.getRegionView(0)->isSwitchedOn()); synth.noteOn(0, 61, 64); REQUIRE(!synth.getRegionView(0)->isSwitchedOn()); diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index 71303217..d1cd9156 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -28,11 +28,11 @@ TEST_CASE("[Synth] Play and check active voices") synth.noteOn(0, 36, 24); synth.noteOn(0, 36, 89); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); // Render for a while for (int i = 0; i < 200; ++i) synth.renderBlock(buffer); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); } TEST_CASE("[Synth] All sound off") @@ -41,9 +41,9 @@ TEST_CASE("[Synth] All sound off") synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz"); synth.noteOn(0, 36, 24); synth.noteOn(0, 36, 89); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); synth.allSoundOff(); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); } TEST_CASE("[Synth] Change the number of voice while playing") @@ -56,9 +56,9 @@ TEST_CASE("[Synth] Change the number of voice while playing") synth.noteOn(0, 36, 24); synth.noteOn(0, 36, 89); synth.renderBlock(buffer); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE(synth.getNumActiveVoices() == 2); synth.setNumVoices(8); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE(synth.getNumActiveVoices() == 0); REQUIRE(synth.getNumVoices() == 8); } @@ -136,15 +136,15 @@ TEST_CASE("[Synth] All notes offs/all sounds off") )"); synth.noteOn(0, 60, 63); synth.noteOn(0, 62, 63); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); synth.cc(0, 120, 63); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 63); synth.noteOn(0, 60, 63); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); synth.cc(0, 123, 63); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); } TEST_CASE("[Synth] Reset all controllers") @@ -570,14 +570,14 @@ TEST_CASE("[Synth] sample quality") // default sample quality synth.noteOn(0, 60, 100); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality); synth.allSoundOff(); // default sample quality, freewheeling synth.enableFreeWheeling(); synth.noteOn(0, 60, 100); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQualityInFreewheelingMode); synth.allSoundOff(); synth.disableFreeWheeling(); @@ -585,7 +585,7 @@ TEST_CASE("[Synth] sample quality") // user-defined sample quality synth.setSampleQuality(sfz::Synth::ProcessLive, 3); synth.noteOn(0, 60, 100); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == 3); synth.allSoundOff(); @@ -593,21 +593,21 @@ TEST_CASE("[Synth] sample quality") synth.enableFreeWheeling(); synth.setSampleQuality(sfz::Synth::ProcessFreewheeling, 8); synth.noteOn(0, 60, 100); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == 8); synth.allSoundOff(); synth.disableFreeWheeling(); // region sample quality synth.noteOn(0, 61, 100); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == 5); synth.allSoundOff(); // region sample quality, freewheeling synth.enableFreeWheeling(); synth.noteOn(0, 61, 100); - REQUIRE(synth.getNumActiveVoices(true) == 1); + REQUIRE(synth.getNumActiveVoices() == 1); REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == 5); synth.allSoundOff(); synth.disableFreeWheeling(); @@ -630,7 +630,7 @@ TEST_CASE("[Synth] Sister voices") REQUIRE( synth.getVoiceView(0)->getNextSisterVoice() == synth.getVoiceView(0) ); REQUIRE( synth.getVoiceView(0)->getPreviousSisterVoice() == synth.getVoiceView(0) ); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); REQUIRE( sfz::SisterVoiceRing::countSisterVoices(synth.getVoiceView(1)) == 2 ); REQUIRE( synth.getVoiceView(1)->getNextSisterVoice() == synth.getVoiceView(2) ); REQUIRE( synth.getVoiceView(1)->getPreviousSisterVoice() == synth.getVoiceView(2) ); @@ -638,7 +638,7 @@ TEST_CASE("[Synth] Sister voices") REQUIRE( synth.getVoiceView(2)->getNextSisterVoice() == synth.getVoiceView(1) ); REQUIRE( synth.getVoiceView(2)->getPreviousSisterVoice() == synth.getVoiceView(1) ); synth.noteOn(0, 63, 85); - REQUIRE( synth.getNumActiveVoices(true) == 6 ); + REQUIRE( synth.getNumActiveVoices() == 6 ); REQUIRE( sfz::SisterVoiceRing::countSisterVoices(synth.getVoiceView(3)) == 3 ); REQUIRE( synth.getVoiceView(3)->getNextSisterVoice() == synth.getVoiceView(4) ); REQUIRE( synth.getVoiceView(3)->getPreviousSisterVoice() == synth.getVoiceView(5) ); @@ -678,15 +678,15 @@ TEST_CASE("[Synth] Sisters and off-by") group=2 key=63 sample=*saw )"); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); REQUIRE( sfz::SisterVoiceRing::countSisterVoices(synth.getVoiceView(0)) == 2 ); synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); synth.noteOn(0, 63, 85); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); for (unsigned i = 0; i < 100; ++i) synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); REQUIRE( sfz::SisterVoiceRing::countSisterVoices(synth.getVoiceView(0)) == 1 ); } @@ -750,9 +750,9 @@ TEST_CASE("[Synth] Release") synth.noteOn(0, 62, 85); synth.cc(0, 64, 127); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); synth.cc(0, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); } TEST_CASE("[Synth] Release (pedal was already down)") @@ -765,9 +765,9 @@ TEST_CASE("[Synth] Release (pedal was already down)") synth.cc(0, 64, 127); synth.noteOn(0, 62, 85); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); synth.cc(0, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); } @@ -780,12 +780,12 @@ TEST_CASE("[Synth] Release samples don't play unless there is another playing re )"); synth.noteOn(0, 62, 85); synth.noteOff(0, 62, 0); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.cc(0, 64, 127); synth.noteOn(0, 62, 85); synth.noteOff(0, 62, 0); synth.cc(0, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); } TEST_CASE("[Synth] Release key (Different sustain CC)") @@ -798,7 +798,7 @@ TEST_CASE("[Synth] Release key (Different sustain CC)") synth.noteOn(0, 62, 85); synth.cc(0, 54, 127); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); } TEST_CASE("[Synth] Release (Different sustain CC)") @@ -812,9 +812,9 @@ TEST_CASE("[Synth] Release (Different sustain CC)") synth.noteOn(0, 62, 85); synth.cc(0, 54, 127); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); synth.cc(0, 54, 0); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); } TEST_CASE("[Synth] Sustain threshold default") @@ -826,7 +826,7 @@ TEST_CASE("[Synth] Sustain threshold default") synth.noteOn(0, 62, 85); synth.cc(0, 64, 1); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); } TEST_CASE("[Synth] Sustain threshold") @@ -840,15 +840,15 @@ TEST_CASE("[Synth] Sustain threshold") synth.noteOn(0, 62, 85); synth.cc(0, 64, 1); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); synth.noteOn(0, 62, 85); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 4 ); + REQUIRE( synth.getNumActiveVoices() == 4 ); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 5 ); + REQUIRE( synth.getNumActiveVoices() == 5 ); synth.cc(0, 64, 64); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 5 ); + REQUIRE( synth.getNumActiveVoices() == 5 ); } TEST_CASE("[Synth] Release (Multiple notes, release_key ignores the pedal)") @@ -864,7 +864,7 @@ TEST_CASE("[Synth] Release (Multiple notes, release_key ignores the pedal)") synth.noteOff(0, 64, 0); synth.noteOff(0, 63, 2); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); std::vector requiredVelocities { 34_norm, 78_norm, 85_norm}; std::vector actualVelocities; @@ -890,9 +890,9 @@ TEST_CASE("[Synth] Release (Multiple notes, release, cleared the delayed voices synth.noteOff(0, 64, 0); synth.noteOff(0, 63, 2); synth.noteOff(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.cc(0, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 6 ); + REQUIRE( synth.getNumActiveVoices() == 6 ); std::vector requiredVelocities { 34_norm, 78_norm, 85_norm, 34_norm, 78_norm, 85_norm }; std::vector actualVelocities; @@ -920,9 +920,9 @@ TEST_CASE("[Synth] Release (Multiple notes after pedal is down, release, cleared synth.noteOff(2, 64, 0); synth.noteOff(2, 63, 2); synth.noteOff(2, 62, 3); - REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( synth.getNumActiveVoices() == 3 ); synth.cc(3, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 6 ); + REQUIRE( synth.getNumActiveVoices() == 6 ); std::vector requiredVelocities { 34_norm, 78_norm, 85_norm, 34_norm, 78_norm, 85_norm }; std::vector actualVelocities; @@ -948,9 +948,9 @@ TEST_CASE("[Synth] Release (Multiple note ons during pedal down)") synth.noteOff(0, 62, 0); synth.noteOn(0, 62, 78); synth.noteOff(0, 62, 2); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices() == 2 ); synth.cc(0, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 4 ); + REQUIRE( synth.getNumActiveVoices() == 4 ); std::vector requiredVelocities { 78_norm, 85_norm, 78_norm, 85_norm }; std::vector actualVelocities; @@ -974,25 +974,25 @@ TEST_CASE("[Synth] No release sample after the main sample stopped sounding by d loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1 )"); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); for (unsigned i = 0; i < 100; ++i) { synth.renderBlock(buffer); } - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOff(0, 62, 0); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 85); synth.cc(0, 64, 127); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); for (unsigned i = 0; i < 100; ++i) { synth.renderBlock(buffer); } - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOff(0, 62, 0); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.cc(0, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); REQUIRE( synth.getRegionView(1)->delayedReleases.empty() ); } @@ -1009,25 +1009,25 @@ TEST_CASE("[Synth] If rt_dead is active the release sample can sound after the a loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1 )"); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); for (unsigned i = 0; i < 100; ++i) { synth.renderBlock(buffer); } - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOff(0, 62, 0); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 85); synth.cc(0, 64, 127); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); for (unsigned i = 0; i < 100; ++i) { synth.renderBlock(buffer); } - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOff(0, 62, 0); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.cc(0, 64, 0); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); REQUIRE( synth.getRegionView(1)->delayedReleases.empty() ); } @@ -1041,9 +1041,9 @@ TEST_CASE("[Synth] sw_default works at a global level") sw_last=37 key=63 sample=*sine )"); synth.noteOn(0, 63, 85); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); } TEST_CASE("[Synth] sw_default works at a master level") @@ -1055,9 +1055,9 @@ TEST_CASE("[Synth] sw_default works at a master level") sw_last=37 key=63 sample=*sine )"); synth.noteOn(0, 63, 85); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); } TEST_CASE("[Synth] sw_default works at a group level") @@ -1069,9 +1069,9 @@ TEST_CASE("[Synth] sw_default works at a group level") sw_last=37 key=63 sample=*sine )"); synth.noteOn(0, 63, 85); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); } TEST_CASE("[Synth] Used CCs") @@ -1169,10 +1169,10 @@ TEST_CASE("[Synth] Activate also on the sustain CC") locc64=64 key=53 sample=*sine )"); synth.noteOn(0, 53, 127); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.cc(1, 64, 127); synth.noteOn(2, 53, 127); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); } TEST_CASE("[Synth] Trigger also on the sustain CC") @@ -1182,7 +1182,7 @@ TEST_CASE("[Synth] Trigger also on the sustain CC") on_locc64=64 sample=*sine )"); synth.cc(0, 64, 127); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); } TEST_CASE("[Synth] end=-1 voices are immediately killed after triggering but they kill other voices") @@ -1197,11 +1197,11 @@ TEST_CASE("[Synth] end=-1 voices are immediately killed after triggering but the key=63 end=-1 sample=*saw group=2 )"); synth.noteOn(0, 60, 85); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 61, 85); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); REQUIRE( numPlayingVoices(synth) == 1 ); synth.noteOn(1, 63, 85); synth.renderBlock(buffer); @@ -1220,11 +1220,11 @@ TEST_CASE("[Synth] end=0 voices are immediately killed after triggering but they key=63 end=0 sample=*saw group=2 )"); synth.noteOn(0, 60, 85); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 61, 85); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 62, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); REQUIRE( numPlayingVoices(synth) == 1 ); synth.noteOn(1, 63, 85); synth.renderBlock(buffer); @@ -1242,19 +1242,19 @@ TEST_CASE("[Synth] ampeg_sustain = 0 puts the ampeg envelope in free-running mod )"); synth.noteOn(0, 60, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); synth.noteOn(0, 61, 85); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); // Render a bit; this does not kill the voice for (unsigned i = 0; i < 5; ++i) synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 1 ); + REQUIRE( synth.getNumActiveVoices() == 1 ); // Render about half a second for (unsigned i = 0; i < 100; ++i) synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 0 ); + REQUIRE( synth.getNumActiveVoices() == 0 ); } TEST_CASE("[Synth] Off by standard") From 4aeb12446e6c4dfc1cb1f295894cd411758a0399 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 19:31:48 +0100 Subject: [PATCH 056/668] move findFreeVoice to the voiceList --- src/sfizz/Synth.cpp | 23 +---------------------- src/sfizz/VoiceList.h | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index bc95c214..4402664d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -170,14 +170,6 @@ struct Synth::Impl: public Parser::Listener { */ void ccDispatch(int delay, int ccNumber, float value) noexcept; - /** - * @brief Find a voice that is not currently playing - * - * @return Voice* - */ - - Voice* findFreeVoice() noexcept; - /** * @brief Start a voice for a specific region. * This will do the needed polyphony checks and voice stealing. @@ -1056,19 +1048,6 @@ void Synth::loadStretchTuningByRatio(float ratio) impl.resources_.stretch.reset(); } -Voice* Synth::Impl::findFreeVoice() noexcept -{ - auto freeVoice = absl::c_find_if(voiceList_, [](const Voice& voice) { - return voice.isFree(); - }); - - if (freeVoice != voiceList_.end()) - return &*freeVoice; - - DBG("Engine hard polyphony reached"); - return {}; -} - int Synth::getNumActiveVoices() const noexcept { Impl& impl = *impl_; @@ -1279,7 +1258,7 @@ void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept void Synth::Impl::startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept { voiceList_.checkPolyphony(region, delay, triggerEvent); - Voice* selectedVoice = findFreeVoice(); + Voice* selectedVoice = voiceList_.findFreeVoice(); if (selectedVoice == nullptr) return; diff --git a/src/sfizz/VoiceList.h b/src/sfizz/VoiceList.h index 51013d5a..bd347f84 100644 --- a/src/sfizz/VoiceList.h +++ b/src/sfizz/VoiceList.h @@ -155,11 +155,34 @@ struct VoiceList : public Voice::StateListener checkEnginePolyphony(delay); } + /** + * @brief Get the number of active voices + * + * @return unsigned + */ unsigned getNumActiveVoices() const { return activeVoices_.size(); } + /** + * @brief Find a voice that is not currently playing + * + * @return Voice* + */ + Voice* findFreeVoice() noexcept + { + auto freeVoice = absl::c_find_if(list_, [](const Voice& voice) { + return voice.isFree(); + }); + + if (freeVoice != list_.end()) + return &*freeVoice; + + DBG("Engine hard polyphony reached"); + return {}; + } + private: std::vector list_; std::vector activeVoices_; From 1b87fa3764e2570289fa014841a995ad320d5065 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 19:48:42 +0100 Subject: [PATCH 057/668] Move even more stuff in the voiceList_ --- src/sfizz/Synth.cpp | 39 ++++++++++----------------------------- src/sfizz/VoiceList.h | 30 +++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 4402664d..7f0d7b91 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -245,11 +245,6 @@ struct Synth::Impl: public Parser::Listener { // engine polyphony RegionSetPtr engineSet_; - // Views to speed up iteration over the regions and voices when events - // occur in the audio callback - VoiceViewVector tempPolyphonyArray_; - VoiceViewVector voiceViewArray_; - std::array lastKeyswitchLists_; std::array downKeyswitchLists_; std::array upKeyswitchLists_; @@ -265,8 +260,7 @@ struct Synth::Impl: public Parser::Listener { int samplesPerBlock_ { config::defaultSamplesPerBlock }; float sampleRate_ { config::defaultSampleRate }; float volume_ { Default::globalVolume }; - int numRequiredVoices_ { config::numVoices }; - int numActualVoices_ { static_cast(config::numVoices * config::overflowVoiceMultiplier) }; + int numVoices_ { config::numVoices }; int activeVoices_ { 0 }; Oversampling oversamplingFactor_ { config::defaultOversamplingFactor }; @@ -1644,7 +1638,7 @@ const Region* Synth::getRegionById(NumericId id) const noexcept const Voice* Synth::getVoiceView(int idx) const noexcept { Impl& impl = *impl_; - return (size_t)idx < impl.voiceList_.size() ? &impl.voiceList_[idx] : nullptr; + return idx < impl.numVoices_ ? &impl.voiceList_[idx] : nullptr; } unsigned Synth::getNumPolyphonyGroups() const noexcept @@ -1711,7 +1705,7 @@ void Synth::setVolume(float volume) noexcept int Synth::getNumVoices() const noexcept { Impl& impl = *impl_; - return impl.numRequiredVoices_; + return impl.numVoices_; } void Synth::setNumVoices(int numVoices) noexcept @@ -1721,7 +1715,7 @@ void Synth::setNumVoices(int numVoices) noexcept const std::lock_guard disableCallback { impl.callbackGuard_ }; // fast path - if (numVoices == impl.numRequiredVoices_) + if (numVoices == impl.numVoices_) return; impl.resetVoices(numVoices); @@ -1729,31 +1723,18 @@ void Synth::setNumVoices(int numVoices) noexcept void Synth::Impl::resetVoices(int numVoices) { - numActualVoices_ = - static_cast(config::overflowVoiceMultiplier * numVoices); - numRequiredVoices_ = numVoices; + numVoices_ = numVoices; for (auto& set : sets_) set->removeAllVoices(); engineSet_->removeAllVoices(); - engineSet_->setPolyphonyLimit(numRequiredVoices_); + engineSet_->setPolyphonyLimit(numVoices_); - voiceList_.clear(); - voiceList_.reserve(numActualVoices_); + voiceList_.requireNumVoices(numVoices_, resources_); - voiceViewArray_.clear(); - voiceViewArray_.reserve(numActualVoices_); - - tempPolyphonyArray_.clear(); - tempPolyphonyArray_.reserve(numActualVoices_); - - for (int i = 0; i < numActualVoices_; ++i) { - voiceList_.emplace_back(i, resources_); - Voice& lastVoice = voiceList_.back(); - lastVoice.setSampleRate(this->sampleRate_); - lastVoice.setSamplesPerBlock(this->samplesPerBlock_); - lastVoice.setStateListener(&voiceList_); - voiceViewArray_.push_back(&lastVoice); + for (auto& voice : voiceList_) { + voice.setSampleRate(this->sampleRate_); + voice.setSamplesPerBlock(this->samplesPerBlock_); } applySettingsPerVoice(); diff --git a/src/sfizz/VoiceList.h b/src/sfizz/VoiceList.h index bd347f84..5e9c572e 100644 --- a/src/sfizz/VoiceList.h +++ b/src/sfizz/VoiceList.h @@ -7,6 +7,7 @@ #pragma once #include "Voice.h" +#include "Resources.h" #include "Config.h" #include "Region.h" #include "SisterVoiceRing.h" @@ -183,10 +184,28 @@ struct VoiceList : public Voice::StateListener return {}; } + void requireNumVoices(int numVoices, Resources& resources) + { + numActualVoices_ = + static_cast(config::overflowVoiceMultiplier * numVoices); + numRequiredVoices_ = numVoices; + + clear(); + list_.reserve(numActualVoices_); + activeVoices_.reserve(numActualVoices_); + + for (int i = 0; i < numActualVoices_; ++i) { + list_.emplace_back(i, resources); + Voice& lastVoice = list_.back(); + lastVoice.setStateListener(this); + } + } + private: + int numRequiredVoices_ { config::numVoices }; + int numActualVoices_ { static_cast(config::numVoices * config::overflowVoiceMultiplier) }; std::vector list_; std::vector activeVoices_; - std::vector temp_; // These are the `group=` groups where you can off voices std::vector polyphonyGroups_; std::unique_ptr stealer_ { absl::make_unique() }; @@ -285,9 +304,8 @@ private: */ void checkEnginePolyphony(int delay) noexcept { - // TODO (paul): should have the "required" vs "actual" number of voices here Voice* candidate = stealer_->checkPolyphony( - absl::MakeSpan(activeVoices_), list_.size()); + absl::MakeSpan(activeVoices_), numRequiredVoices_); SisterVoiceRing::offAllSisters(candidate, delay); } @@ -299,12 +317,6 @@ public: typename decltype(list_)::const_iterator cend() const { return list_.cend(); } typename decltype(list_)::reference operator[] (size_t n) { return list_[n]; } typename decltype(list_)::const_reference operator[] (size_t n) const { return list_[n]; } - typename decltype(list_)::reference back() { return list_.back(); } - typename decltype(list_)::const_reference back() const { return list_.back(); } - size_t size() const { return list_.size(); } - void reserve(size_t n) { list_.reserve(n); } - template< class... Args > - void emplace_back(Args&&... args) { list_.emplace_back(std::forward(args)...); } }; } // namespace sfz From 81a4ed22ebbd305a716116881a412517398ff29e Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 20:11:23 +0100 Subject: [PATCH 058/668] Final refactor into VoiceManager Cleanups.. --- common.mk | 1 + src/CMakeLists.txt | 2 + src/sfizz/Synth.cpp | 72 ++-- src/sfizz/VoiceList.h | 322 ------------------ src/sfizz/VoiceManager.cpp | 242 +++++++++++++ src/sfizz/VoiceManager.h | 193 +++++++++++ .../modulations/sources/ADSREnvelope.cpp | 10 +- src/sfizz/modulations/sources/ADSREnvelope.h | 6 +- .../modulations/sources/FlexEnvelope.cpp | 10 +- src/sfizz/modulations/sources/FlexEnvelope.h | 6 +- src/sfizz/modulations/sources/LFO.cpp | 8 +- src/sfizz/modulations/sources/LFO.h | 6 +- 12 files changed, 497 insertions(+), 381 deletions(-) delete mode 100644 src/sfizz/VoiceList.h create mode 100644 src/sfizz/VoiceManager.cpp create mode 100644 src/sfizz/VoiceManager.h diff --git a/common.mk b/common.mk index 27acfbc2..40abb575 100644 --- a/common.mk +++ b/common.mk @@ -115,6 +115,7 @@ SFIZZ_SOURCES = \ src/sfizz/Tuning.cpp \ src/sfizz/utility/SpinMutex.cpp \ src/sfizz/Voice.cpp \ + src/sfizz/VoiceManager.cpp \ src/sfizz/VoiceStealing.cpp \ src/sfizz/Wavetables.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d005c794..539a2ec0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,6 +109,7 @@ set (SFIZZ_HEADERS sfizz/SynthConfig.h sfizz/Tuning.h sfizz/Voice.h + sfizz/VoiceManager.h sfizz/VoiceStealing.h sfizz/Wavetables.h sfizz.h @@ -137,6 +138,7 @@ set (SFIZZ_SOURCES sfizz/Tuning.cpp sfizz/RegionSet.cpp sfizz/PolyphonyGroup.cpp + sfizz/VoiceManager.cpp sfizz/VoiceStealing.cpp sfizz/RTSemaphore.cpp sfizz/Panning.cpp diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 7f0d7b91..f40823ea 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -30,7 +30,7 @@ #include "TriggerEvent.h" #include "utility/SpinMutex.h" #include "utility/XmlHelpers.h" -#include "VoiceList.h" +#include "VoiceManager.h" #include #include #include @@ -236,7 +236,7 @@ struct Synth::Impl: public Parser::Listener { using RegionPtr = std::unique_ptr; using RegionSetPtr = std::unique_ptr; std::vector regions_; - VoiceList voiceList_; + VoiceManager voiceManager_; // These are more general "groups" than sfz and encapsulates the full hierarchy RegionSet* currentSet_ { nullptr }; @@ -327,16 +327,16 @@ Synth::Impl::Impl() // modulation sources genController_.reset(new ControllerSource(resources_)); - genLFO_.reset(new LFOSource(voiceList_)); - genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceList_)); - genADSREnvelope_.reset(new ADSREnvelopeSource(voiceList_, resources_.midiState)); + genLFO_.reset(new LFOSource(voiceManager_)); + genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_)); + genADSREnvelope_.reset(new ADSREnvelopeSource(voiceManager_, resources_.midiState)); } Synth::Impl::~Impl() { const std::lock_guard disableCallback { callbackGuard_ }; - voiceList_.reset(); + voiceManager_.reset(); resources_.filePool.emptyFileLoadingQueues(); } @@ -461,10 +461,10 @@ void Synth::Impl::buildRegion(const std::vector& regionOpcodes) // There was a combination of group= and polyphony= on a region, so set the group polyphony if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) { - voiceList_.setGroupPolyphony(lastRegion->group, lastRegion->polyphony); + voiceManager_.setGroupPolyphony(lastRegion->group, lastRegion->polyphony); } else { // Just check that there are enough polyphony groups - voiceList_.ensureNumPolyphonyGroups(lastRegion->group); + voiceManager_.ensureNumPolyphonyGroups(lastRegion->group); } if (currentSet_ != nullptr) { @@ -483,7 +483,7 @@ void Synth::Impl::clear() // Clear the background queues before removing everyone resources_.filePool.waitForBackgroundLoading(); - voiceList_.reset(); + voiceManager_.reset(); for (auto& list : lastKeyswitchLists_) list.clear(); for (auto& list : downKeyswitchLists_) @@ -603,12 +603,12 @@ void Synth::Impl::handleGroupOpcodes(const std::vector& members, const s parseOpcode(member); if (groupIdx && maxPolyphony) { - voiceList_.setGroupPolyphony(*groupIdx, *maxPolyphony); + voiceManager_.setGroupPolyphony(*groupIdx, *maxPolyphony); } else if (maxPolyphony) { ASSERT(currentSet_ != nullptr); currentSet_->setPolyphonyLimit(*maxPolyphony); } else if (groupIdx) { - voiceList_.ensureNumPolyphonyGroups(*groupIdx); + voiceManager_.ensureNumPolyphonyGroups(*groupIdx); } } @@ -663,13 +663,13 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) case hash("hint_stealing"): switch(hash(member.value)) { case hash("first"): - voiceList_.setStealingAlgorithm(StealingAlgorithm::First); + voiceManager_.setStealingAlgorithm(StealingAlgorithm::First); break; case hash("oldest"): - voiceList_.setStealingAlgorithm(StealingAlgorithm::Oldest); + voiceManager_.setStealingAlgorithm(StealingAlgorithm::Oldest); break; case hash("envelope_and_age"): - voiceList_.setStealingAlgorithm(StealingAlgorithm::EnvelopeAndAge); + voiceManager_.setStealingAlgorithm(StealingAlgorithm::EnvelopeAndAge); break; default: DBG("Unsupported value for hint_stealing: " << member.value); @@ -1045,7 +1045,7 @@ void Synth::loadStretchTuningByRatio(float ratio) int Synth::getNumActiveVoices() const noexcept { Impl& impl = *impl_; - return static_cast(impl.voiceList_.getNumActiveVoices()); + return static_cast(impl.voiceManager_.getNumActiveVoices()); } void Synth::setSamplesPerBlock(int samplesPerBlock) noexcept @@ -1056,7 +1056,7 @@ void Synth::setSamplesPerBlock(int samplesPerBlock) noexcept const std::lock_guard disableCallback { impl.callbackGuard_ }; impl.samplesPerBlock_ = samplesPerBlock; - for (auto& voice : impl.voiceList_) + for (auto& voice : impl.voiceManager_) voice.setSamplesPerBlock(samplesPerBlock); impl.resources_.setSamplesPerBlock(samplesPerBlock); @@ -1073,7 +1073,7 @@ void Synth::setSampleRate(float sampleRate) noexcept const std::lock_guard disableCallback { impl.callbackGuard_ }; impl.sampleRate_ = sampleRate; - for (auto& voice : impl.voiceList_) + for (auto& voice : impl.voiceManager_) voice.setSampleRate(sampleRate); impl.resources_.setSampleRate(sampleRate); @@ -1136,7 +1136,7 @@ void Synth::renderBlock(AudioSpan buffer) noexcept ScopedTiming logger { callbackBreakdown.renderMethod, ScopedTiming::Operation::addToDuration }; tempMixSpan->fill(0.0f); - for (auto& voice : impl.voiceList_) { + for (auto& voice : impl.voiceManager_) { if (voice.isFree()) continue; @@ -1243,7 +1243,7 @@ void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept // auto replacedVelocity = (velocity == 0 ? getNoteVelocity(noteNumber) : velocity); const auto replacedVelocity = impl.resources_.midiState.getNoteVelocity(noteNumber); - for (auto& voice : impl.voiceList_) + for (auto& voice : impl.voiceManager_) voice.registerNoteOff(delay, noteNumber, replacedVelocity); impl.noteOffDispatch(delay, noteNumber, replacedVelocity); @@ -1251,8 +1251,8 @@ void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept void Synth::Impl::startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept { - voiceList_.checkPolyphony(region, delay, triggerEvent); - Voice* selectedVoice = voiceList_.findFreeVoice(); + voiceManager_.checkPolyphony(region, delay, triggerEvent); + Voice* selectedVoice = voiceManager_.findFreeVoice(); if (selectedVoice == nullptr) return; @@ -1275,7 +1275,7 @@ void Synth::Impl::noteOffDispatch(int delay, int noteNumber, float velocity) noe for (auto& region : noteActivationLists_[noteNumber]) { if (region->registerNoteOff(noteNumber, velocity, randValue)) { - if (region->trigger == SfzTrigger::release && !region->rtDead && !voiceList_.playingAttackVoice(region)) + if (region->trigger == SfzTrigger::release && !region->rtDead && !voiceManager_.playingAttackVoice(region)) continue; startVoice(region, delay, triggerEvent, ring); @@ -1308,7 +1308,7 @@ void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noex for (auto& region : noteActivationLists_[noteNumber]) { if (region->registerNoteOn(noteNumber, velocity, randValue)) { - for (auto& voice : voiceList_) { + for (auto& voice : voiceManager_) { if (voice.checkOffGroup(region, delay, noteNumber)) { const TriggerEvent& event = voice.getTriggerEvent(); noteOffDispatch(delay, event.number, event.value); @@ -1325,7 +1325,7 @@ void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noex void Synth::Impl::startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept { - if (!region->rtDead && !voiceList_.playingAttackVoice(region)) { + if (!region->rtDead && !voiceManager_.playingAttackVoice(region)) { region->delayedReleases.clear(); return; } @@ -1377,13 +1377,13 @@ void Synth::hdcc(int delay, int ccNumber, float normValue) noexcept } if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) { - for (auto& voice : impl.voiceList_) + for (auto& voice : impl.voiceManager_) voice.reset(); impl.resources_.midiState.allNotesOff(delay); return; } - for (auto& voice : impl.voiceList_) + for (auto& voice : impl.voiceManager_) voice.registerCC(delay, ccNumber, normValue); impl.ccDispatch(delay, ccNumber, normValue); @@ -1427,7 +1427,7 @@ void Synth::pitchWheel(int delay, int pitch) noexcept region->registerPitchWheel(normalizedPitch); } - for (auto& voice : impl.voiceList_) { + for (auto& voice : impl.voiceManager_) { voice.registerPitchWheel(delay, normalizedPitch); } } @@ -1614,7 +1614,7 @@ const RegionSet* Synth::getRegionSetView(int idx) const noexcept const PolyphonyGroup* Synth::getPolyphonyGroupView(int idx) const noexcept { Impl& impl = *impl_; - return impl.voiceList_.getPolyphonyGroupView(idx); + return impl.voiceManager_.getPolyphonyGroupView(idx); } const Region* Synth::getRegionById(NumericId id) const noexcept @@ -1638,13 +1638,13 @@ const Region* Synth::getRegionById(NumericId id) const noexcept const Voice* Synth::getVoiceView(int idx) const noexcept { Impl& impl = *impl_; - return idx < impl.numVoices_ ? &impl.voiceList_[idx] : nullptr; + return idx < impl.numVoices_ ? &impl.voiceManager_[idx] : nullptr; } unsigned Synth::getNumPolyphonyGroups() const noexcept { Impl& impl = *impl_; - return impl.voiceList_.getNumPolyphonyGroups(); + return impl.voiceManager_.getNumPolyphonyGroups(); } const std::vector& Synth::getUnknownOpcodes() const noexcept @@ -1730,9 +1730,9 @@ void Synth::Impl::resetVoices(int numVoices) engineSet_->removeAllVoices(); engineSet_->setPolyphonyLimit(numVoices_); - voiceList_.requireNumVoices(numVoices_, resources_); + voiceManager_.requireNumVoices(numVoices_, resources_); - for (auto& voice : voiceList_) { + for (auto& voice : voiceManager_) { voice.setSampleRate(this->sampleRate_); voice.setSamplesPerBlock(this->samplesPerBlock_); } @@ -1742,7 +1742,7 @@ void Synth::Impl::resetVoices(int numVoices) void Synth::Impl::applySettingsPerVoice() { - for (auto& voice : voiceList_) { + for (auto& voice : voiceManager_) { voice.setMaxFiltersPerVoice(settingsPerVoice_.maxFilters); voice.setMaxEQsPerVoice(settingsPerVoice_.maxEQs); voice.setMaxLFOsPerVoice(settingsPerVoice_.maxLFOs); @@ -1829,7 +1829,7 @@ void Synth::setOversamplingFactor(Oversampling factor) noexcept if (factor == impl.oversamplingFactor_) return; - for (auto& voice : impl.voiceList_) + for (auto& voice : impl.voiceManager_) voice.reset(); impl.resources_.filePool.emptyFileLoadingQueues(); @@ -1886,7 +1886,7 @@ void Synth::Impl::resetAllControllers(int delay) noexcept if (!lock.owns_lock()) return; - for (auto& voice : voiceList_) { + for (auto& voice : voiceManager_) { voice.registerPitchWheel(delay, 0); for (int cc = 0; cc < config::numCCs; ++cc) voice.registerCC(delay, cc, 0.0f); @@ -1945,7 +1945,7 @@ void Synth::allSoundOff() noexcept Impl& impl = *impl_; const std::lock_guard disableCallback { impl.callbackGuard_ }; - for (auto& voice : impl.voiceList_) + for (auto& voice : impl.voiceManager_) voice.reset(); for (auto& effectBus : impl.effectBuses_) effectBus->clear(); diff --git a/src/sfizz/VoiceList.h b/src/sfizz/VoiceList.h deleted file mode 100644 index 5e9c572e..00000000 --- a/src/sfizz/VoiceList.h +++ /dev/null @@ -1,322 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#pragma once - -#include "Voice.h" -#include "Resources.h" -#include "Config.h" -#include "Region.h" -#include "SisterVoiceRing.h" -#include "PolyphonyGroup.h" -#include "RegionSet.h" -#include "VoiceStealing.h" -#include -#include - -namespace sfz { - -struct VoiceList : public Voice::StateListener -{ - /** - * @brief The voice callback which is called during a change of state. - */ - void onVoiceStateChanging(NumericId id, Voice::State state) final - { - (void)id; - if (state == Voice::State::idle) { - auto voice = getVoiceById(id); - RegionSet::removeVoiceFromHierarchy(voice->getRegion(), voice); - swapAndPopFirst(activeVoices_, [voice](const Voice* v) { return v == voice; }); - polyphonyGroups_[voice->getRegion()->group].removeVoice(voice); - } else if (state == Voice::State::playing) { - auto voice = getVoiceById(id); - activeVoices_.push_back(voice); - RegionSet::registerVoiceInHierarchy(voice->getRegion(), voice); - polyphonyGroups_[voice->getRegion()->group].registerVoice(voice); - } - } - /** - * @brief Find the voice which is associated with the given identifier. - * - * @param id - * @return const Voice* - */ - const Voice* getVoiceById(NumericId id) const noexcept - { - const size_t size = list_.size(); - - if (size == 0 || !id.valid()) - return nullptr; - - // search a sequence of ordered identifiers with potential gaps - size_t index = static_cast(id.number()); - index = std::min(index, size - 1); - - while (index > 0 && list_[index].getId().number() > id.number()) - --index; - - return (list_[index].getId() == id) ? &list_[index] : nullptr; - } - - Voice* getVoiceById(NumericId id) noexcept - { - return const_cast( - const_cast(this)->getVoiceById(id)); - } - - void reset() - { - for (auto& voice : list_) - voice.reset(); - - polyphonyGroups_.clear(); - polyphonyGroups_.emplace_back(); - polyphonyGroups_.back().setPolyphonyLimit(config::maxVoices); - setStealingAlgorithm(StealingAlgorithm::Oldest); - } - - bool playingAttackVoice(const Region* releaseRegion) noexcept - { - const auto compatibleVoice = [releaseRegion](const Voice& v) -> bool { - const TriggerEvent& event = v.getTriggerEvent(); - return ( - !v.isFree() - && event.type == TriggerEventType::NoteOn - && releaseRegion->keyRange.containsWithEnd(event.number) - && releaseRegion->velocityRange.containsWithEnd(event.value) - ); - }; - - if (absl::c_find_if(list_, compatibleVoice) == list_.end()) - return false; - else - return true; - } - - void ensureNumPolyphonyGroups(unsigned groupIdx) noexcept - { - while (polyphonyGroups_.size() <= groupIdx) - polyphonyGroups_.emplace_back(); - } - - void setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept - { - ensureNumPolyphonyGroups(groupIdx); - polyphonyGroups_[groupIdx].setPolyphonyLimit(polyphony); - } - - size_t getNumPolyphonyGroups() const noexcept { return polyphonyGroups_.size(); } - - const PolyphonyGroup* getPolyphonyGroupView(int idx) const noexcept - { - return (size_t)idx < polyphonyGroups_.size() ? &polyphonyGroups_[idx] : nullptr; - } - - void clear() - { - reset(); - list_.clear(); - activeVoices_.clear(); - } - - void setStealingAlgorithm(StealingAlgorithm algorithm) - { - switch(algorithm){ - case StealingAlgorithm::First: // fallthrough - for (auto& voice : list_) - voice.disablePowerFollower(); - - stealer_ = absl::make_unique(); - break; - case StealingAlgorithm::Oldest: - for (auto& voice : list_) - voice.disablePowerFollower(); - - stealer_ = absl::make_unique(); - break; - case StealingAlgorithm::EnvelopeAndAge: - for (auto& voice : list_) - voice.enablePowerFollower(); - - stealer_ = absl::make_unique(); - break; - } - } - - void checkPolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept - { - checkNotePolyphony(region, delay, triggerEvent); - checkRegionPolyphony(region, delay); - checkGroupPolyphony(region, delay); - checkSetPolyphony(region, delay); - checkEnginePolyphony(delay); - } - - /** - * @brief Get the number of active voices - * - * @return unsigned - */ - unsigned getNumActiveVoices() const - { - return activeVoices_.size(); - } - - /** - * @brief Find a voice that is not currently playing - * - * @return Voice* - */ - Voice* findFreeVoice() noexcept - { - auto freeVoice = absl::c_find_if(list_, [](const Voice& voice) { - return voice.isFree(); - }); - - if (freeVoice != list_.end()) - return &*freeVoice; - - DBG("Engine hard polyphony reached"); - return {}; - } - - void requireNumVoices(int numVoices, Resources& resources) - { - numActualVoices_ = - static_cast(config::overflowVoiceMultiplier * numVoices); - numRequiredVoices_ = numVoices; - - clear(); - list_.reserve(numActualVoices_); - activeVoices_.reserve(numActualVoices_); - - for (int i = 0; i < numActualVoices_; ++i) { - list_.emplace_back(i, resources); - Voice& lastVoice = list_.back(); - lastVoice.setStateListener(this); - } - } - -private: - int numRequiredVoices_ { config::numVoices }; - int numActualVoices_ { static_cast(config::numVoices * config::overflowVoiceMultiplier) }; - std::vector list_; - std::vector activeVoices_; - // These are the `group=` groups where you can off voices - std::vector polyphonyGroups_; - std::unique_ptr stealer_ { absl::make_unique() }; - - /** - * @brief Check the region polyphony, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkRegionPolyphony(const Region* region, int delay) noexcept - { - Voice* candidate = stealer_->checkRegionPolyphony(region, absl::MakeSpan(activeVoices_)); - SisterVoiceRing::offAllSisters(candidate, delay); - } - - /** - * @brief Check the note polyphony, releasing voices if necessary - * - * @param region - * @param delay - * @param triggerEvent - */ - void checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept - { - if (!region->notePolyphony) - return; - - unsigned notePolyphonyCounter { 0 }; - Voice* selfMaskCandidate { nullptr }; - - for (Voice* voice : activeVoices_) { - const TriggerEvent& voiceTriggerEvent = voice->getTriggerEvent(); - const bool skipVoice = (triggerEvent.type == TriggerEventType::NoteOn && voice->releasedOrFree()) || voice->isFree(); - if (!skipVoice - && voice->getRegion()->group == region->group - && voiceTriggerEvent.number == triggerEvent.number - && voiceTriggerEvent.type == triggerEvent.type) { - notePolyphonyCounter += 1; - switch (region->selfMask) { - case SfzSelfMask::mask: - if (voiceTriggerEvent.value <= triggerEvent.value) { - if (!selfMaskCandidate || selfMaskCandidate->getTriggerEvent().value > voiceTriggerEvent.value) { - selfMaskCandidate = voice; - } - } - break; - case SfzSelfMask::dontMask: - if (!selfMaskCandidate || selfMaskCandidate->getAge() < voice->getAge()) - selfMaskCandidate = voice; - break; - } - } - } - - if (notePolyphonyCounter >= *region->notePolyphony) { - SisterVoiceRing::offAllSisters(selfMaskCandidate, delay); - } - } - - /** - * @brief Check the group polyphony, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkGroupPolyphony(const Region* region, int delay) noexcept - { - auto& group = polyphonyGroups_[region->group]; - Voice* candidate = stealer_->checkPolyphony( - absl::MakeSpan(group.getActiveVoices()), group.getPolyphonyLimit()); - SisterVoiceRing::offAllSisters(candidate, delay); - } - - /** - * @brief Check the region set polyphony at all levels, releasing voices if necessary - * - * @param region - * @param delay - */ - void checkSetPolyphony(const Region* region, int delay) noexcept - { - auto parent = region->parent; - while (parent != nullptr) { - Voice* candidate = stealer_->checkPolyphony( - absl::MakeSpan(parent->getActiveVoices()), parent->getPolyphonyLimit()); - SisterVoiceRing::offAllSisters(candidate, delay); - parent = parent->getParent(); - } - } - - /** - * @brief Check the engine polyphony, fast releasing voices if necessary - * - * @param delay - */ - void checkEnginePolyphony(int delay) noexcept - { - Voice* candidate = stealer_->checkPolyphony( - absl::MakeSpan(activeVoices_), numRequiredVoices_); - SisterVoiceRing::offAllSisters(candidate, delay); - } - -public: - // Vector shortcuts - typename decltype(list_)::iterator begin() { return list_.begin(); } - typename decltype(list_)::const_iterator cbegin() const { return list_.cbegin(); } - typename decltype(list_)::iterator end() { return list_.end(); } - typename decltype(list_)::const_iterator cend() const { return list_.cend(); } - typename decltype(list_)::reference operator[] (size_t n) { return list_[n]; } - typename decltype(list_)::const_reference operator[] (size_t n) const { return list_[n]; } -}; - -} // namespace sfz diff --git a/src/sfizz/VoiceManager.cpp b/src/sfizz/VoiceManager.cpp new file mode 100644 index 00000000..f8bf71f8 --- /dev/null +++ b/src/sfizz/VoiceManager.cpp @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "VoiceManager.h" +#include "SisterVoiceRing.h" +#include "RegionSet.h" +#include + +namespace sfz { + +void VoiceManager::onVoiceStateChanging(NumericId id, Voice::State state) +{ + (void)id; + if (state == Voice::State::idle) { + auto voice = getVoiceById(id); + RegionSet::removeVoiceFromHierarchy(voice->getRegion(), voice); + swapAndPopFirst(activeVoices_, [voice](const Voice* v) { return v == voice; }); + polyphonyGroups_[voice->getRegion()->group].removeVoice(voice); + } else if (state == Voice::State::playing) { + auto voice = getVoiceById(id); + activeVoices_.push_back(voice); + RegionSet::registerVoiceInHierarchy(voice->getRegion(), voice); + polyphonyGroups_[voice->getRegion()->group].registerVoice(voice); + } +} + +const Voice* VoiceManager::getVoiceById(NumericId id) const noexcept +{ + const size_t size = list_.size(); + + if (size == 0 || !id.valid()) + return nullptr; + + // search a sequence of ordered identifiers with potential gaps + size_t index = static_cast(id.number()); + index = std::min(index, size - 1); + + while (index > 0 && list_[index].getId().number() > id.number()) + --index; + + return (list_[index].getId() == id) ? &list_[index] : nullptr; +} + +Voice* VoiceManager::getVoiceById(NumericId id) noexcept +{ + return const_cast( + const_cast(this)->getVoiceById(id)); +} + +void VoiceManager::reset() +{ + for (auto& voice : list_) + voice.reset(); + + polyphonyGroups_.clear(); + polyphonyGroups_.emplace_back(); + polyphonyGroups_.back().setPolyphonyLimit(config::maxVoices); + setStealingAlgorithm(StealingAlgorithm::Oldest); +} + +bool VoiceManager::playingAttackVoice(const Region* releaseRegion) noexcept +{ + const auto compatibleVoice = [releaseRegion](const Voice& v) -> bool { + const TriggerEvent& event = v.getTriggerEvent(); + return ( + !v.isFree() + && event.type == TriggerEventType::NoteOn + && releaseRegion->keyRange.containsWithEnd(event.number) + && releaseRegion->velocityRange.containsWithEnd(event.value) + ); + }; + + if (absl::c_find_if(list_, compatibleVoice) == list_.end()) + return false; + else + return true; +} + +void VoiceManager::ensureNumPolyphonyGroups(unsigned groupIdx) noexcept +{ + while (polyphonyGroups_.size() <= groupIdx) + polyphonyGroups_.emplace_back(); +} + +void VoiceManager::setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept +{ + ensureNumPolyphonyGroups(groupIdx); + polyphonyGroups_[groupIdx].setPolyphonyLimit(polyphony); +} + + +const PolyphonyGroup* VoiceManager::getPolyphonyGroupView(int idx) const noexcept +{ + return (size_t)idx < polyphonyGroups_.size() ? &polyphonyGroups_[idx] : nullptr; +} + +void VoiceManager::clear() +{ + reset(); + list_.clear(); + activeVoices_.clear(); +} + +void VoiceManager::setStealingAlgorithm(StealingAlgorithm algorithm) +{ + switch(algorithm){ + case StealingAlgorithm::First: // fallthrough + for (auto& voice : list_) + voice.disablePowerFollower(); + + stealer_ = absl::make_unique(); + break; + case StealingAlgorithm::Oldest: + for (auto& voice : list_) + voice.disablePowerFollower(); + + stealer_ = absl::make_unique(); + break; + case StealingAlgorithm::EnvelopeAndAge: + for (auto& voice : list_) + voice.enablePowerFollower(); + + stealer_ = absl::make_unique(); + break; + } +} + +void VoiceManager::checkPolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept +{ + checkNotePolyphony(region, delay, triggerEvent); + checkRegionPolyphony(region, delay); + checkGroupPolyphony(region, delay); + checkSetPolyphony(region, delay); + checkEnginePolyphony(delay); +} + +Voice* VoiceManager::findFreeVoice() noexcept +{ + auto freeVoice = absl::c_find_if(list_, [](const Voice& voice) { + return voice.isFree(); + }); + + if (freeVoice != list_.end()) + return &*freeVoice; + + DBG("Engine hard polyphony reached"); + return {}; +} + +void VoiceManager::requireNumVoices(int numVoices, Resources& resources) +{ + numActualVoices_ = + static_cast(config::overflowVoiceMultiplier * numVoices); + numRequiredVoices_ = numVoices; + + clear(); + list_.reserve(numActualVoices_); + activeVoices_.reserve(numActualVoices_); + + for (int i = 0; i < numActualVoices_; ++i) { + list_.emplace_back(i, resources); + Voice& lastVoice = list_.back(); + lastVoice.setStateListener(this); + } +} + +void VoiceManager::checkRegionPolyphony(const Region* region, int delay) noexcept +{ + Voice* candidate = stealer_->checkRegionPolyphony(region, absl::MakeSpan(activeVoices_)); + SisterVoiceRing::offAllSisters(candidate, delay); +} + +void VoiceManager::checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept +{ + if (!region->notePolyphony) + return; + + unsigned notePolyphonyCounter { 0 }; + Voice* selfMaskCandidate { nullptr }; + + for (Voice* voice : activeVoices_) { + const TriggerEvent& voiceTriggerEvent = voice->getTriggerEvent(); + const bool skipVoice = + (triggerEvent.type == TriggerEventType::NoteOn && voice->releasedOrFree()) + || voice->isFree(); + if (!skipVoice + && voice->getRegion()->group == region->group + && voiceTriggerEvent.number == triggerEvent.number + && voiceTriggerEvent.type == triggerEvent.type) { + notePolyphonyCounter += 1; + switch (region->selfMask) { + case SfzSelfMask::mask: + if (voiceTriggerEvent.value <= triggerEvent.value) { + if (!selfMaskCandidate + || selfMaskCandidate->getTriggerEvent().value > voiceTriggerEvent.value) { + selfMaskCandidate = voice; + } + } + break; + case SfzSelfMask::dontMask: + if (!selfMaskCandidate || selfMaskCandidate->getAge() < voice->getAge()) + selfMaskCandidate = voice; + break; + } + } + } + + if (notePolyphonyCounter >= *region->notePolyphony) { + SisterVoiceRing::offAllSisters(selfMaskCandidate, delay); + } +} + +void VoiceManager::checkGroupPolyphony(const Region* region, int delay) noexcept +{ + auto& group = polyphonyGroups_[region->group]; + Voice* candidate = stealer_->checkPolyphony( + absl::MakeSpan(group.getActiveVoices()), group.getPolyphonyLimit()); + SisterVoiceRing::offAllSisters(candidate, delay); +} + +void VoiceManager::checkSetPolyphony(const Region* region, int delay) noexcept +{ + auto parent = region->parent; + while (parent != nullptr) { + Voice* candidate = stealer_->checkPolyphony( + absl::MakeSpan(parent->getActiveVoices()), parent->getPolyphonyLimit()); + SisterVoiceRing::offAllSisters(candidate, delay); + parent = parent->getParent(); + } +} + +void VoiceManager::checkEnginePolyphony(int delay) noexcept +{ + Voice* candidate = stealer_->checkPolyphony( + absl::MakeSpan(activeVoices_), numRequiredVoices_); + SisterVoiceRing::offAllSisters(candidate, delay); +} + +} // namespace sfz diff --git a/src/sfizz/VoiceManager.h b/src/sfizz/VoiceManager.h new file mode 100644 index 00000000..b9e8fff0 --- /dev/null +++ b/src/sfizz/VoiceManager.h @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once + +#include "Voice.h" +#include "Resources.h" +#include "Config.h" +#include "Region.h" +#include "PolyphonyGroup.h" +#include "VoiceStealing.h" +#include + +namespace sfz { + +struct VoiceManager : public Voice::StateListener +{ + /** + * @brief The voice callback which is called during a change of state. + */ + void onVoiceStateChanging(NumericId id, Voice::State state) final; + + /** + * @brief Find the voice which is associated with the given identifier. + * + * @param id + * @return const Voice* + */ + const Voice* getVoiceById(NumericId id) const noexcept; + + /** + * @brief Find the voice which is associated with the given identifier. + * + * @param id + * @return Voice* + */ + Voice* getVoiceById(NumericId id) noexcept; + + /** + * @brief Reset all voices and clear the polyphony groups + */ + void reset(); + + /** + * @brief Check if a compatible attack voice is playing for the release region. + * + * @param releaseRegion + * @return true + * @return false + */ + bool playingAttackVoice(const Region* releaseRegion) noexcept; + + /** + * @brief Ensures that the polyphony groups are at least this size. + * Call this each time a new `group=N` is given in an sfz file. + * + * @param groupIdx + */ + void ensureNumPolyphonyGroups(unsigned groupIdx) noexcept; + + /** + * @brief Set the polyphony for a given group + * If the number of polyphony groups is too small, it will + * be increased. + * + * @param groupIdx + * @param polyphony + */ + void setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept; + + /** + * @brief Get a view into a given polyphony group + * + * @param idx + * @return const PolyphonyGroup* + */ + const PolyphonyGroup* getPolyphonyGroupView(int idx) const noexcept; + + /** + * @brief Clear all voices and polyphony groups. + * Also resets the stealing algorithm to default. + */ + void clear(); + + /** + * @brief Set the stealing algorithm + * + * @param algorithm + */ + void setStealingAlgorithm(StealingAlgorithm algorithm); + + /** + * @brief Off voices as necessary depending on the trigger event and started region + * + * @param region + * @param delay + * @param triggerEvent + */ + void checkPolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept; + + /** + * @brief Get the number of active voices + * + * @return size_t + */ + size_t getNumActiveVoices() const { return activeVoices_.size(); } + + /** + * @brief Get the number of polyphony groups + * + * @return size_t + */ + size_t getNumPolyphonyGroups() const noexcept { return polyphonyGroups_.size(); } + + /** + * @brief Find a voice that is not currently playing + * + * @return Voice* + */ + Voice* findFreeVoice() noexcept; + /** + * @brief Require a number of voices from this manager. + * In practice, the manager will handle slightly more, in order to + * allow voices to die off upon reaching higher polyphony count. + * + * @param numVoices + * @param resources + */ + void requireNumVoices(int numVoices, Resources& resources); + +private: + int numRequiredVoices_ { config::numVoices }; + int numActualVoices_ { static_cast(config::numVoices * config::overflowVoiceMultiplier) }; + std::vector list_; + std::vector activeVoices_; + // These are the `group=` groups where you can off voices + std::vector polyphonyGroups_; + std::unique_ptr stealer_ { absl::make_unique() }; + + /** + * @brief Check the region polyphony, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkRegionPolyphony(const Region* region, int delay) noexcept; + + /** + * @brief Check the note polyphony, releasing voices if necessary + * + * @param region + * @param delay + * @param triggerEvent + */ + void checkNotePolyphony(const Region* region, int delay, const TriggerEvent& triggerEvent) noexcept; + + /** + * @brief Check the group polyphony, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkGroupPolyphony(const Region* region, int delay) noexcept; + + /** + * @brief Check the region set polyphony at all levels, releasing voices if necessary + * + * @param region + * @param delay + */ + void checkSetPolyphony(const Region* region, int delay) noexcept; + + /** + * @brief Check the engine polyphony, fast releasing voices if necessary + * + * @param delay + */ + void checkEnginePolyphony(int delay) noexcept; + +public: + // Vector shortcuts + typename decltype(list_)::iterator begin() { return list_.begin(); } + typename decltype(list_)::const_iterator cbegin() const { return list_.cbegin(); } + typename decltype(list_)::iterator end() { return list_.end(); } + typename decltype(list_)::const_iterator cend() const { return list_.cend(); } + typename decltype(list_)::reference operator[] (size_t n) { return list_[n]; } + typename decltype(list_)::const_reference operator[] (size_t n) const { return list_[n]; } +}; + +} // namespace sfz diff --git a/src/sfizz/modulations/sources/ADSREnvelope.cpp b/src/sfizz/modulations/sources/ADSREnvelope.cpp index dfe67317..2f589282 100644 --- a/src/sfizz/modulations/sources/ADSREnvelope.cpp +++ b/src/sfizz/modulations/sources/ADSREnvelope.cpp @@ -15,14 +15,14 @@ namespace sfz { -ADSREnvelopeSource::ADSREnvelopeSource(VoiceList& list, MidiState& state) - : voiceList_(list), midiState_(state) +ADSREnvelopeSource::ADSREnvelopeSource(VoiceManager& manager, MidiState& state) + : voiceManager_(manager), midiState_(state) { } void ADSREnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { - Voice* voice = voiceList_.getVoiceById(voiceId); + Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -60,7 +60,7 @@ void ADSREnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, void ADSREnvelopeSource::release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { - Voice* voice = voiceList_.getVoiceById(voiceId); + Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -91,7 +91,7 @@ void ADSREnvelopeSource::release(const ModKey& sourceKey, NumericId voice void ADSREnvelopeSource::generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) { - Voice* voice = voiceList_.getVoiceById(voiceId); + Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; diff --git a/src/sfizz/modulations/sources/ADSREnvelope.h b/src/sfizz/modulations/sources/ADSREnvelope.h index a8835467..d52a9ca0 100644 --- a/src/sfizz/modulations/sources/ADSREnvelope.h +++ b/src/sfizz/modulations/sources/ADSREnvelope.h @@ -6,7 +6,7 @@ #pragma once #include "../ModGenerator.h" -#include "../../VoiceList.h" +#include "../../VoiceManager.h" #include "../../MidiState.h" namespace sfz { @@ -14,13 +14,13 @@ class Synth; class ADSREnvelopeSource : public ModGenerator { public: - explicit ADSREnvelopeSource(VoiceList &synth, MidiState& state); + explicit ADSREnvelopeSource(VoiceManager &manager, MidiState& state); void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) override; private: - VoiceList& voiceList_; + VoiceManager& voiceManager_; MidiState& midiState_; }; diff --git a/src/sfizz/modulations/sources/FlexEnvelope.cpp b/src/sfizz/modulations/sources/FlexEnvelope.cpp index db471ed1..5cea2ad8 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.cpp +++ b/src/sfizz/modulations/sources/FlexEnvelope.cpp @@ -14,8 +14,8 @@ namespace sfz { -FlexEnvelopeSource::FlexEnvelopeSource(VoiceList& list) - : voiceList_(list) +FlexEnvelopeSource::FlexEnvelopeSource(VoiceManager& manager) + : voiceManager_(manager) { } @@ -23,7 +23,7 @@ void FlexEnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, { unsigned egIndex = sourceKey.parameters().N; - Voice* voice = voiceList_.getVoiceById(voiceId); + Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -50,7 +50,7 @@ void FlexEnvelopeSource::release(const ModKey& sourceKey, NumericId voice { unsigned egIndex = sourceKey.parameters().N; - Voice* voice = voiceList_.getVoiceById(voiceId); + Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -70,7 +70,7 @@ void FlexEnvelopeSource::generate(const ModKey& sourceKey, NumericId voic { unsigned egIndex = sourceKey.parameters().N; - Voice* voice = voiceList_.getVoiceById(voiceId); + Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; diff --git a/src/sfizz/modulations/sources/FlexEnvelope.h b/src/sfizz/modulations/sources/FlexEnvelope.h index 487efdba..1868ab10 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.h +++ b/src/sfizz/modulations/sources/FlexEnvelope.h @@ -6,20 +6,20 @@ #pragma once #include "../ModGenerator.h" -#include "../../VoiceList.h" +#include "../../VoiceManager.h" namespace sfz { class Synth; class FlexEnvelopeSource : public ModGenerator { public: - explicit FlexEnvelopeSource(VoiceList& list); + explicit FlexEnvelopeSource(VoiceManager& manager); void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) override; private: - VoiceList& voiceList_; + VoiceManager& voiceManager_; }; } // namespace sfz diff --git a/src/sfizz/modulations/sources/LFO.cpp b/src/sfizz/modulations/sources/LFO.cpp index 8a603e43..a485833d 100644 --- a/src/sfizz/modulations/sources/LFO.cpp +++ b/src/sfizz/modulations/sources/LFO.cpp @@ -14,8 +14,8 @@ namespace sfz { -LFOSource::LFOSource(VoiceList& list) - : voiceList_(list) +LFOSource::LFOSource(VoiceManager& manager) + : voiceManager_(manager) { } @@ -23,7 +23,7 @@ void LFOSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned { unsigned lfoIndex = sourceKey.parameters().N; - Voice* voice = voiceList_.getVoiceById(voiceId); + Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; return; @@ -44,7 +44,7 @@ void LFOSource::generate(const ModKey& sourceKey, NumericId voiceId, absl { const unsigned lfoIndex = sourceKey.parameters().N; - Voice* voice = voiceList_.getVoiceById(voiceId); + Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; fill(buffer, 0.0f); diff --git a/src/sfizz/modulations/sources/LFO.h b/src/sfizz/modulations/sources/LFO.h index 02c696c9..430f483a 100644 --- a/src/sfizz/modulations/sources/LFO.h +++ b/src/sfizz/modulations/sources/LFO.h @@ -6,18 +6,18 @@ #pragma once #include "../ModGenerator.h" -#include "../../VoiceList.h" +#include "../../VoiceManager.h" namespace sfz { class Synth; class LFOSource : public ModGenerator { public: - explicit LFOSource(VoiceList &list); + explicit LFOSource(VoiceManager &manager); void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; void generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) override; private: - VoiceList& voiceList_; + VoiceManager& voiceManager_; }; } // namespace sfz From cfae639d5f5416976cbbe98b9a233798e501bb3f Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 31 Oct 2020 20:29:08 +0100 Subject: [PATCH 059/668] Final cleanups --- src/sfizz/Oversampler.cpp | 2 +- src/sfizz/Synth.cpp | 15 +++------------ src/sfizz/VoiceManager.h | 2 +- src/sfizz/VoiceStealing.cpp | 4 ++-- src/sfizz/VoiceStealing.h | 7 ++++--- tests/SIMDHelpersT.cpp | 1 - 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/sfizz/Oversampler.cpp b/src/sfizz/Oversampler.cpp index b4f21621..954a6119 100644 --- a/src/sfizz/Oversampler.cpp +++ b/src/sfizz/Oversampler.cpp @@ -143,7 +143,7 @@ void sfz::Oversampler::stream(AudioSpan input, AudioSpan output, s void sfz::Oversampler::stream(AudioReader& input, AudioSpan output, std::atomic* framesReady) { - ASSERT(output.getNumFrames() >= input.frames() * static_cast(factor)); + ASSERT(output.getNumFrames() >= static_cast(input.frames() * static_cast(factor))); ASSERT(output.getNumChannels() == input.channels()); const auto numFrames = static_cast(input.frames()); diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index f40823ea..2515d1de 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -41,7 +41,7 @@ namespace sfz { -struct Synth::Impl: public Parser::Listener { +struct Synth::Impl final: public Parser::Listener { Impl(); ~Impl(); @@ -241,9 +241,6 @@ struct Synth::Impl: public Parser::Listener { // These are more general "groups" than sfz and encapsulates the full hierarchy RegionSet* currentSet_ { nullptr }; std::vector sets_; - // This region set holds the engine set of voices, which tries to respect the required - // engine polyphony - RegionSetPtr engineSet_; std::array lastKeyswitchLists_; std::array downKeyswitchLists_; @@ -261,7 +258,6 @@ struct Synth::Impl: public Parser::Listener { float sampleRate_ { config::defaultSampleRate }; float volume_ { Default::globalVolume }; int numVoices_ { config::numVoices }; - int activeVoices_ { 0 }; Oversampling oversamplingFactor_ { config::defaultOversamplingFactor }; // Distribution used to generate random value for the *rand opcodes @@ -319,7 +315,6 @@ Synth::Impl::Impl() initializeSIMDDispatchers(); const std::lock_guard disableCallback { callbackGuard_ }; - engineSet_ = absl::make_unique(nullptr, OpcodeScope::kOpcodeScopeGeneric); parser_.setListener(this); effectFactory_.registerStandardEffectTypes(); effectBuses_.reserve(5); // sufficient room for main and fx1-4 @@ -1131,7 +1126,6 @@ void Synth::renderBlock(AudioSpan buffer) noexcept } } - impl.activeVoices_ = 0; { // Main render block ScopedTiming logger { callbackBreakdown.renderMethod, ScopedTiming::Operation::addToDuration }; tempMixSpan->fill(0.0f); @@ -1142,8 +1136,6 @@ void Synth::renderBlock(AudioSpan buffer) noexcept mm.beginVoice(voice.getId(), voice.getRegion()->getId(), voice.getTriggerEvent().value); - impl.activeVoices_++; - const Region* region = voice.getRegion(); ASSERT(region != nullptr); @@ -1197,7 +1189,8 @@ void Synth::renderBlock(AudioSpan buffer) noexcept } callbackBreakdown.dispatch = impl.dispatchDuration_; - impl.resources_.logger.logCallbackTime(callbackBreakdown, impl.activeVoices_, numFrames); + impl.resources_.logger.logCallbackTime( + callbackBreakdown, impl.voiceManager_.getNumActiveVoices(), numFrames); // Reset the dispatch counter impl.dispatchDuration_ = Duration(0); @@ -1727,8 +1720,6 @@ void Synth::Impl::resetVoices(int numVoices) for (auto& set : sets_) set->removeAllVoices(); - engineSet_->removeAllVoices(); - engineSet_->setPolyphonyLimit(numVoices_); voiceManager_.requireNumVoices(numVoices_, resources_); diff --git a/src/sfizz/VoiceManager.h b/src/sfizz/VoiceManager.h index b9e8fff0..bdc3c6d1 100644 --- a/src/sfizz/VoiceManager.h +++ b/src/sfizz/VoiceManager.h @@ -16,7 +16,7 @@ namespace sfz { -struct VoiceManager : public Voice::StateListener +struct VoiceManager final : public Voice::StateListener { /** * @brief The voice callback which is called during a change of state. diff --git a/src/sfizz/VoiceStealing.cpp b/src/sfizz/VoiceStealing.cpp index 6d06f6e6..d99b447d 100644 --- a/src/sfizz/VoiceStealing.cpp +++ b/src/sfizz/VoiceStealing.cpp @@ -50,14 +50,14 @@ Voice* FirstStealer::checkRegionPolyphony(const Region* region, absl::Spanpolyphony, [=](const Voice* v) { return (!ignoreVoice(v) && v->getRegion() == region); }, - [=](const Voice* v, const Voice* c) { return c == nullptr; }); + [=](const Voice*, const Voice* c) { return c == nullptr; }); } Voice* FirstStealer::checkPolyphony(absl::Span candidates, unsigned maxPolyphony) { return genericPolyphonyCheck(candidates, maxPolyphony, [=](const Voice* v) { return (!ignoreVoice(v)); }, - [=](const Voice* v, const Voice* c) { return c == nullptr; }); + [=](const Voice*, const Voice* c) { return c == nullptr; }); } Voice* OldestStealer::checkRegionPolyphony(const Region* region, absl::Span candidates) diff --git a/src/sfizz/VoiceStealing.h b/src/sfizz/VoiceStealing.h index 78e5000c..6209fca3 100644 --- a/src/sfizz/VoiceStealing.h +++ b/src/sfizz/VoiceStealing.h @@ -25,6 +25,7 @@ enum class StealingAlgorithm { class VoiceStealer { public: + virtual ~VoiceStealer() {} /** * @brief Check that the region polyphony is respected. * @@ -43,21 +44,21 @@ public: virtual Voice* checkPolyphony(absl::Span candidates, unsigned maxPolyphony) = 0; }; -class FirstStealer : public VoiceStealer +class FirstStealer final : public VoiceStealer { public: Voice* checkRegionPolyphony(const Region* region, absl::Span candidates) final; Voice* checkPolyphony(absl::Span candidates, unsigned maxPolyphony) final; }; -class OldestStealer : public VoiceStealer +class OldestStealer final : public VoiceStealer { public: Voice* checkRegionPolyphony(const Region* region, absl::Span candidates) final; Voice* checkPolyphony(absl::Span candidates, unsigned maxPolyphony) final; }; -class EnvelopeAndAgeStealer : public VoiceStealer +class EnvelopeAndAgeStealer final : public VoiceStealer { public: EnvelopeAndAgeStealer(); diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index bbf9b70b..6bdf8cf6 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -19,7 +19,6 @@ using namespace Catch::literals; template using aligned_vector = std::vector>; -constexpr int smallBufferSize { 3 }; constexpr int bigBufferSize { 4095 }; constexpr int medBufferSize { 127 }; constexpr float fillValue { 1.3f }; From faadb70b022dc46b884bd1e0e004994e8fd70d7d Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 1 Nov 2020 09:00:22 +0100 Subject: [PATCH 060/668] Include cleanups --- src/sfizz/Synth.cpp | 11 ++++++----- src/sfizz/Synth.h | 12 ++++++++---- src/sfizz/Voice.cpp | 7 +++---- src/sfizz/VoiceManager.h | 6 +++--- src/sfizz/parser/Parser.h | 8 ++++---- tests/FilesT.cpp | 1 + tests/LFOT.cpp | 1 + tests/PlotLFO.cpp | 1 + tests/TestHelpers.h | 1 + 9 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 2515d1de..9f2bb846 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -4,14 +4,11 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "absl/algorithm/container.h" -#include "absl/memory/memory.h" -#include "absl/strings/str_replace.h" +#include "Synth.h" #include "Config.h" #include "Debug.h" #include "Effects.h" #include "Macros.h" -#include "ModifierHelpers.h" #include "modulations/ModId.h" #include "modulations/ModKey.h" #include "modulations/ModMatrix.h" @@ -21,16 +18,20 @@ #include "modulations/sources/LFO.h" #include "PolyphonyGroup.h" #include "pugixml.hpp" +#include "Region.h" #include "RegionSet.h" #include "Resources.h" #include "ScopedFTZ.h" #include "SisterVoiceRing.h" #include "StringViewHelpers.h" -#include "Synth.h" #include "TriggerEvent.h" #include "utility/SpinMutex.h" #include "utility/XmlHelpers.h" +#include "Voice.h" #include "VoiceManager.h" +#include +#include +#include #include #include #include diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index b9611835..386ac863 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -5,14 +5,16 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once -#include "Region.h" -#include "Voice.h" -#include "LeakDetector.h" #include "AudioSpan.h" +#include "LeakDetector.h" +#include "Resources.h" +#include "utility/NumericId.h" #include "parser/Parser.h" +#include #include #include -#include +#include +#include #include namespace sfz { @@ -21,6 +23,8 @@ namespace sfz { class RegionSet; class PolyphonyGroup; class EffectBus; +class Region; +class Voice; /** * @brief This class is the core of the sfizz library. In C++ it is the main point diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index dcdfccd2..7940908e 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -4,15 +4,13 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "absl/algorithm/container.h" -#include "absl/types/span.h" +#include "Voice.h" #include "AudioBuffer.h" #include "Config.h" #include "Defaults.h" #include "EQPool.h" #include "FilterPool.h" #include "FlexEnvelope.h" -#include "HistoricalBuffer.h" #include "Interpolators.h" #include "LFO.h" #include "Macros.h" @@ -27,7 +25,8 @@ #include "SfzHelpers.h" #include "SIMDHelpers.h" #include "Smoothers.h" -#include "Voice.h" +#include +#include #include namespace sfz { diff --git a/src/sfizz/VoiceManager.h b/src/sfizz/VoiceManager.h index bdc3c6d1..627fd600 100644 --- a/src/sfizz/VoiceManager.h +++ b/src/sfizz/VoiceManager.h @@ -6,11 +6,11 @@ #pragma once -#include "Voice.h" -#include "Resources.h" #include "Config.h" -#include "Region.h" #include "PolyphonyGroup.h" +#include "Region.h" +#include "Resources.h" +#include "Voice.h" #include "VoiceStealing.h" #include diff --git a/src/sfizz/parser/Parser.h b/src/sfizz/parser/Parser.h index 057143ad..827de0c6 100644 --- a/src/sfizz/parser/Parser.h +++ b/src/sfizz/parser/Parser.h @@ -6,10 +6,10 @@ #pragma once #include "../Opcode.h" -#include "ghc/fs_std.hpp" -#include "absl/types/optional.h" -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" +#include +#include +#include +#include #include #include diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 02004ab7..28c41dd9 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -6,6 +6,7 @@ #include "TestHelpers.h" #include "sfizz/Synth.h" +#include "sfizz/Voice.h" #include "sfizz/SfzHelpers.h" #include "sfizz/modulations/ModId.h" #include "sfizz/modulations/ModKey.h" diff --git a/tests/LFOT.cpp b/tests/LFOT.cpp index 2271c2a8..9a7ac3ab 100644 --- a/tests/LFOT.cpp +++ b/tests/LFOT.cpp @@ -7,6 +7,7 @@ #include "DataHelpers.h" #include "sfizz/Synth.h" #include "sfizz/LFO.h" +#include "sfizz/Region.h" #include "catch2/catch.hpp" static bool computeLFO(DataPoints& dp, const fs::path& sfzPath, double sampleRate, size_t numFrames) diff --git a/tests/PlotLFO.cpp b/tests/PlotLFO.cpp index 8ce0aff5..c55a192f 100644 --- a/tests/PlotLFO.cpp +++ b/tests/PlotLFO.cpp @@ -17,6 +17,7 @@ #include "sfizz/Synth.h" #include "sfizz/LFO.h" +#include "sfizz/Region.h" #include "sfizz/LFODescription.h" #include "sfizz/MathHelpers.h" #include "cxxopts.hpp" diff --git a/tests/TestHelpers.h b/tests/TestHelpers.h index 4d059c45..31c5feb5 100644 --- a/tests/TestHelpers.h +++ b/tests/TestHelpers.h @@ -7,6 +7,7 @@ #pragma once #include "sfizz/Synth.h" #include "sfizz/Region.h" +#include "sfizz/Voice.h" #include "sfizz/modulations/ModKey.h" class RegionCCView { From 2863e5aedf110d4362fa61d980e5adb63eea92a1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 10:05:33 +0100 Subject: [PATCH 061/668] Keep the cmake minimum required to 3.5 --- external/st_audiofile/thirdparty/libaiff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/st_audiofile/thirdparty/libaiff b/external/st_audiofile/thirdparty/libaiff index 73cfb8b6..c47d11b9 160000 --- a/external/st_audiofile/thirdparty/libaiff +++ b/external/st_audiofile/thirdparty/libaiff @@ -1 +1 @@ -Subproject commit 73cfb8b647da93bed871a4dd7d0dca80d78a160a +Subproject commit c47d11b98f25bf052c85cff7f5d5422375c18fcb From d8e8a467291fb1dfa3e329a1626e5edb5794a289 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 10:26:53 +0100 Subject: [PATCH 062/668] Fix a mismatch of struct/class --- src/sfizz/Synth.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 386ac863..dbfa21c5 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -23,7 +23,7 @@ namespace sfz { class RegionSet; class PolyphonyGroup; class EffectBus; -class Region; +struct Region; class Voice; /** From 3332687a4167fd9889024ccbb489fba92d297415 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 10:56:49 +0100 Subject: [PATCH 063/668] Move feature out of tests and in their own directory --- CMakeLists.txt | 5 +++ clients/CMakeLists.txt | 2 +- cmake/SfizzConfig.cmake | 6 ++- demos/CMakeLists.txt | 61 ++++++++++++++++++++++++++ {tests => demos}/DemoFilters.cpp | 0 {tests => demos}/DemoFilters.ui | 0 {tests => demos}/DemoParser.cpp | 0 {tests => demos}/DemoParser.ui | 0 {tests => demos}/DemoSmooth.cpp | 0 {tests => demos}/DemoSmooth.ui | 0 {tests => demos}/DemoStereo.cpp | 0 {tests => demos}/DemoStereo.ui | 0 {tests => demos}/DemoStretchTuning.cpp | 0 {tests => demos}/DemoStretchTuning.ui | 0 {tests => demos}/DemoWavetables.cpp | 0 {tests => demos}/DemoWavetables.ui | 0 {tests => demos}/EQ.cpp | 0 {tests => demos}/FileInstrument.cpp | 0 {tests => demos}/FileWavetable.cpp | 0 {tests => demos}/Filter.cpp | 0 {tests => demos}/PlotCurve.cpp | 0 {tests => demos}/PlotLFO.cpp | 0 {tests => demos}/PlotWavetables.cpp | 0 {tests => demos}/Tuning.cpp | 0 tests/CMakeLists.txt | 60 ------------------------- 25 files changed, 72 insertions(+), 62 deletions(-) create mode 100644 demos/CMakeLists.txt rename {tests => demos}/DemoFilters.cpp (100%) rename {tests => demos}/DemoFilters.ui (100%) rename {tests => demos}/DemoParser.cpp (100%) rename {tests => demos}/DemoParser.ui (100%) rename {tests => demos}/DemoSmooth.cpp (100%) rename {tests => demos}/DemoSmooth.ui (100%) rename {tests => demos}/DemoStereo.cpp (100%) rename {tests => demos}/DemoStereo.ui (100%) rename {tests => demos}/DemoStretchTuning.cpp (100%) rename {tests => demos}/DemoStretchTuning.ui (100%) rename {tests => demos}/DemoWavetables.cpp (100%) rename {tests => demos}/DemoWavetables.ui (100%) rename {tests => demos}/EQ.cpp (100%) rename {tests => demos}/FileInstrument.cpp (100%) rename {tests => demos}/FileWavetable.cpp (100%) rename {tests => demos}/Filter.cpp (100%) rename {tests => demos}/PlotCurve.cpp (100%) rename {tests => demos}/PlotLFO.cpp (100%) rename {tests => demos}/PlotWavetables.cpp (100%) rename {tests => demos}/Tuning.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3896ef5..83c8c5a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ option (SFIZZ_VST "Enable VST plug-in build [default: OFF]" OFF) option (SFIZZ_AU "Enable AU plug-in build [default: OFF]" OFF) option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF) option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF) +option (SFIZZ_DEMOS "Enable feature demos build [default: OFF]" OFF) option (SFIZZ_DEVTOOLS "Enable developer tools build [default: OFF]" OFF) option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON) option (SFIZZ_USE_SNDFILE "Enable use of the sndfile library [default: ON]" ON) @@ -75,6 +76,10 @@ if (SFIZZ_TESTS) add_subdirectory (tests) endif() +if (SFIZZ_DEMOS) + add_subdirectory (demos) +endif() + if (SFIZZ_DEVTOOLS) add_subdirectory (devtools) endif() diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index 80502f42..ae3080a3 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -21,7 +21,7 @@ if (SFIZZ_RENDER) target_compile_definitions(sfizz-fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1") add_executable(sfizz_render MidiHelpers.h sfizz_render.cpp) - target_link_libraries(sfizz_render PRIVATE sfizz::sfizz sfizz-fmidi sfizz-sndfile) + target_link_libraries(sfizz_render PRIVATE sfizz::sfizz sfizz-fmidi sfizz-sndfile sfizz-cxxopts) sfizz_enable_lto_if_needed (sfizz_render) install (TARGETS sfizz_render DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "render" OPTIONAL) endif() diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index b10a7a6f..20c9660a 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -88,8 +88,12 @@ endfunction() add_library(sfizz-jsl INTERFACE) target_include_directories(sfizz-jsl INTERFACE "external/jsl/include") +# The cxxopts library +add_library(sfizz-cxxopts INTERFACE) +target_include_directories(sfizz-cxxopts INTERFACE "external/cxxopts") + # The sndfile library -if (SFIZZ_USE_SNDFILE OR SFIZZ_TESTS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) +if (SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) add_library(sfizz-sndfile INTERFACE) if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") find_package(SndFile CONFIG REQUIRED) diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt new file mode 100644 index 00000000..16ebcce6 --- /dev/null +++ b/demos/CMakeLists.txt @@ -0,0 +1,61 @@ +find_package(PkgConfig) +if(PKGCONFIG_FOUND) + pkg_check_modules(JACK "jack") +endif() +find_package(Qt5 COMPONENTS Widgets) + +if(TARGET Qt5::Widgets) + if(JACK_FOUND) + add_executable(sfizz_demo_filters DemoFilters.cpp) + target_include_directories(sfizz_demo_filters PRIVATE ${JACK_INCLUDE_DIRS}) + target_link_libraries(sfizz_demo_filters PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) + set_target_properties(sfizz_demo_filters PROPERTIES AUTOUIC ON) + + add_executable(sfizz_demo_smooth DemoSmooth.cpp) + target_include_directories(sfizz_demo_smooth PRIVATE ${JACK_INCLUDE_DIRS}) + target_link_libraries(sfizz_demo_smooth PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) + set_target_properties(sfizz_demo_smooth PROPERTIES AUTOUIC ON) + + add_executable(sfizz_demo_stereo DemoStereo.cpp) + target_include_directories(sfizz_demo_stereo PRIVATE ${JACK_INCLUDE_DIRS}) + target_link_libraries(sfizz_demo_stereo PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) + set_target_properties(sfizz_demo_stereo PROPERTIES AUTOUIC ON) + + add_executable(sfizz_demo_wavetables DemoWavetables.cpp) + target_include_directories(sfizz_demo_wavetables PRIVATE ${JACK_INCLUDE_DIRS}) + target_link_libraries(sfizz_demo_wavetables PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) + set_target_properties(sfizz_demo_wavetables PROPERTIES AUTOUIC ON) + endif() + + add_executable(sfizz_demo_parser DemoParser.cpp) + target_link_libraries(sfizz_demo_parser PRIVATE sfizz_parser Qt5::Widgets) + set_target_properties(sfizz_demo_parser PROPERTIES AUTOUIC ON) + + add_executable(sfizz_demo_stretch_tuning DemoStretchTuning.cpp) + target_link_libraries(sfizz_demo_stretch_tuning PRIVATE sfizz::sfizz Qt5::Widgets) + set_target_properties(sfizz_demo_stretch_tuning PROPERTIES AUTOUIC ON) +endif() + +add_executable(eq_apply EQ.cpp) +target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz-sndfile sfizz-cxxopts) + +add_executable(filter_apply Filter.cpp) +target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz-sndfile sfizz-cxxopts) + +add_executable(sfizz_plot_curve PlotCurve.cpp) +target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz) + +add_executable(sfizz_plot_wavetables PlotWavetables.cpp) +target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::sfizz) + +add_executable(sfizz_plot_lfo PlotLFO.cpp) +target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz sfizz-sndfile sfizz-cxxopts) + +add_executable(sfizz_file_instrument FileInstrument.cpp) +target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz sfizz-sndfile) + +add_executable(sfizz_file_wavetable FileWavetable.cpp) +target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::sfizz) + +add_executable(sfizz_tuning Tuning.cpp) +target_link_libraries(sfizz_tuning PRIVATE sfizz::sfizz sfizz-cxxopts) diff --git a/tests/DemoFilters.cpp b/demos/DemoFilters.cpp similarity index 100% rename from tests/DemoFilters.cpp rename to demos/DemoFilters.cpp diff --git a/tests/DemoFilters.ui b/demos/DemoFilters.ui similarity index 100% rename from tests/DemoFilters.ui rename to demos/DemoFilters.ui diff --git a/tests/DemoParser.cpp b/demos/DemoParser.cpp similarity index 100% rename from tests/DemoParser.cpp rename to demos/DemoParser.cpp diff --git a/tests/DemoParser.ui b/demos/DemoParser.ui similarity index 100% rename from tests/DemoParser.ui rename to demos/DemoParser.ui diff --git a/tests/DemoSmooth.cpp b/demos/DemoSmooth.cpp similarity index 100% rename from tests/DemoSmooth.cpp rename to demos/DemoSmooth.cpp diff --git a/tests/DemoSmooth.ui b/demos/DemoSmooth.ui similarity index 100% rename from tests/DemoSmooth.ui rename to demos/DemoSmooth.ui diff --git a/tests/DemoStereo.cpp b/demos/DemoStereo.cpp similarity index 100% rename from tests/DemoStereo.cpp rename to demos/DemoStereo.cpp diff --git a/tests/DemoStereo.ui b/demos/DemoStereo.ui similarity index 100% rename from tests/DemoStereo.ui rename to demos/DemoStereo.ui diff --git a/tests/DemoStretchTuning.cpp b/demos/DemoStretchTuning.cpp similarity index 100% rename from tests/DemoStretchTuning.cpp rename to demos/DemoStretchTuning.cpp diff --git a/tests/DemoStretchTuning.ui b/demos/DemoStretchTuning.ui similarity index 100% rename from tests/DemoStretchTuning.ui rename to demos/DemoStretchTuning.ui diff --git a/tests/DemoWavetables.cpp b/demos/DemoWavetables.cpp similarity index 100% rename from tests/DemoWavetables.cpp rename to demos/DemoWavetables.cpp diff --git a/tests/DemoWavetables.ui b/demos/DemoWavetables.ui similarity index 100% rename from tests/DemoWavetables.ui rename to demos/DemoWavetables.ui diff --git a/tests/EQ.cpp b/demos/EQ.cpp similarity index 100% rename from tests/EQ.cpp rename to demos/EQ.cpp diff --git a/tests/FileInstrument.cpp b/demos/FileInstrument.cpp similarity index 100% rename from tests/FileInstrument.cpp rename to demos/FileInstrument.cpp diff --git a/tests/FileWavetable.cpp b/demos/FileWavetable.cpp similarity index 100% rename from tests/FileWavetable.cpp rename to demos/FileWavetable.cpp diff --git a/tests/Filter.cpp b/demos/Filter.cpp similarity index 100% rename from tests/Filter.cpp rename to demos/Filter.cpp diff --git a/tests/PlotCurve.cpp b/demos/PlotCurve.cpp similarity index 100% rename from tests/PlotCurve.cpp rename to demos/PlotCurve.cpp diff --git a/tests/PlotLFO.cpp b/demos/PlotLFO.cpp similarity index 100% rename from tests/PlotLFO.cpp rename to demos/PlotLFO.cpp diff --git a/tests/PlotWavetables.cpp b/demos/PlotWavetables.cpp similarity index 100% rename from tests/PlotWavetables.cpp rename to demos/PlotWavetables.cpp diff --git a/tests/Tuning.cpp b/demos/Tuning.cpp similarity index 100% rename from tests/Tuning.cpp rename to demos/Tuning.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 522042dd..f6f25d9c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -51,64 +51,4 @@ sfizz_enable_lto_if_needed(sfizz_tests) sfizz_enable_fast_math(sfizz_tests) # target_link_libraries(sfizz_tests PRIVATE absl::strings absl::str_format absl::flat_hash_map cnpy absl::span absl::algorithm) -find_package(PkgConfig) -if(PKGCONFIG_FOUND) -pkg_check_modules(JACK "jack") -endif() -find_package(Qt5 COMPONENTS Widgets) - -if(JACK_FOUND AND TARGET Qt5::Widgets) - add_executable(sfizz_demo_filters DemoFilters.cpp) - target_include_directories(sfizz_demo_filters PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_filters PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) - set_target_properties(sfizz_demo_filters PROPERTIES AUTOUIC ON) - - add_executable(sfizz_demo_smooth DemoSmooth.cpp) - target_include_directories(sfizz_demo_smooth PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_smooth PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) - set_target_properties(sfizz_demo_smooth PROPERTIES AUTOUIC ON) - - add_executable(sfizz_demo_stereo DemoStereo.cpp) - target_include_directories(sfizz_demo_stereo PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_stereo PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) - set_target_properties(sfizz_demo_stereo PROPERTIES AUTOUIC ON) - - add_executable(sfizz_demo_wavetables DemoWavetables.cpp) - target_include_directories(sfizz_demo_wavetables PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_wavetables PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) - set_target_properties(sfizz_demo_wavetables PROPERTIES AUTOUIC ON) - - add_executable(sfizz_demo_parser DemoParser.cpp) - target_link_libraries(sfizz_demo_parser PRIVATE sfizz_parser Qt5::Widgets) - set_target_properties(sfizz_demo_parser PROPERTIES AUTOUIC ON) - - add_executable(sfizz_demo_stretch_tuning DemoStretchTuning.cpp) - target_link_libraries(sfizz_demo_stretch_tuning PRIVATE sfizz::sfizz Qt5::Widgets) - set_target_properties(sfizz_demo_stretch_tuning PROPERTIES AUTOUIC ON) -endif() - -add_executable(eq_apply EQ.cpp) -target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz-sndfile) - -add_executable(filter_apply Filter.cpp) -target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz-sndfile) - -add_executable(sfizz_plot_curve PlotCurve.cpp) -target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz) - -add_executable(sfizz_plot_wavetables PlotWavetables.cpp) -target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::sfizz) - -add_executable(sfizz_plot_lfo PlotLFO.cpp) -target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz sfizz-sndfile) - -add_executable(sfizz_file_instrument FileInstrument.cpp) -target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz sfizz-sndfile) - -add_executable(sfizz_file_wavetable FileWavetable.cpp) -target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::sfizz) - -add_executable(sfizz_tuning Tuning.cpp) -target_link_libraries(sfizz_tuning PRIVATE sfizz::sfizz) - file(COPY "." DESTINATION ${CMAKE_BINARY_DIR}/tests) From f6b148aad30ca9fd3ceeae5ccd7600985d322c1b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 10:57:41 +0100 Subject: [PATCH 064/668] Organize cxxopts as external library --- external/cxxopts/LICENSE | 19 + {clients => external/cxxopts}/cxxopts.hpp | 653 ++++--- tests/cxxopts.hpp | 2104 --------------------- 3 files changed, 384 insertions(+), 2392 deletions(-) create mode 100644 external/cxxopts/LICENSE rename {clients => external/cxxopts}/cxxopts.hpp (76%) delete mode 100644 tests/cxxopts.hpp diff --git a/external/cxxopts/LICENSE b/external/cxxopts/LICENSE new file mode 100644 index 00000000..324a2035 --- /dev/null +++ b/external/cxxopts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Jarryd Beck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/clients/cxxopts.hpp b/external/cxxopts/cxxopts.hpp similarity index 76% rename from clients/cxxopts.hpp rename to external/cxxopts/cxxopts.hpp index 16446922..6ec7998a 100644 --- a/clients/cxxopts.hpp +++ b/external/cxxopts/cxxopts.hpp @@ -25,11 +25,12 @@ THE SOFTWARE. #ifndef CXXOPTS_HPP_INCLUDED #define CXXOPTS_HPP_INCLUDED -#include #include +#include #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ THE SOFTWARE. #include #include #include +#include #include #ifdef __cpp_lib_optional @@ -44,12 +46,18 @@ THE SOFTWARE. #define CXXOPTS_HAS_OPTIONAL #endif +#if __cplusplus >= 201603L +#define CXXOPTS_NODISCARD [[nodiscard]] +#else +#define CXXOPTS_NODISCARD +#endif + #ifndef CXXOPTS_VECTOR_DELIMITER #define CXXOPTS_VECTOR_DELIMITER ',' #endif -#define CXXOPTS__VERSION_MAJOR 2 -#define CXXOPTS__VERSION_MINOR 2 +#define CXXOPTS__VERSION_MAJOR 3 +#define CXXOPTS__VERSION_MINOR 0 #define CXXOPTS__VERSION_PATCH 0 namespace cxxopts @@ -61,7 +69,7 @@ namespace cxxopts CXXOPTS__VERSION_MINOR, CXXOPTS__VERSION_PATCH }; -} +} // namespace cxxopts //when we ask cxxopts to use Unicode, help strings are processed using ICU, //which results in the correct lengths being computed for strings when they @@ -139,9 +147,9 @@ namespace cxxopts inline String& - stringAppend(String& s, int n, UChar32 c) + stringAppend(String& s, size_t n, UChar32 c) { - for (int i = 0; i != n; ++i) + for (size_t i = 0; i != n; ++i) { s.append(c); } @@ -227,9 +235,9 @@ namespace cxxopts inline String& - stringAppend(String&s, String a) + stringAppend(String&s, const String& a) { - return s.append(std::move(a)); + return s.append(a); } inline @@ -259,7 +267,7 @@ namespace cxxopts { return s.empty(); } -} +} // namespace cxxopts //ifdef CXXOPTS_USE_UNICODE #endif @@ -275,8 +283,15 @@ namespace cxxopts const std::string LQUOTE("‘"); const std::string RQUOTE("’"); #endif - } + } // namespace +#if defined(__GNUC__) +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: +// warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic push +// This will be ignored under other compilers like LLVM clang. +#endif class Value : public std::enable_shared_from_this { public: @@ -320,17 +335,20 @@ namespace cxxopts virtual bool is_boolean() const = 0; }; - +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif class OptionException : public std::exception { public: - OptionException(const std::string& message) - : m_message(message) + explicit OptionException(std::string message) + : m_message(std::move(message)) { } - virtual const char* - what() const noexcept + CXXOPTS_NODISCARD + const char* + what() const noexcept override { return m_message.c_str(); } @@ -343,7 +361,7 @@ namespace cxxopts { public: - OptionSpecException(const std::string& message) + explicit OptionSpecException(const std::string& message) : OptionException(message) { } @@ -352,7 +370,7 @@ namespace cxxopts class OptionParseException : public OptionException { public: - OptionParseException(const std::string& message) + explicit OptionParseException(const std::string& message) : OptionException(message) { } @@ -361,7 +379,7 @@ namespace cxxopts class option_exists_error : public OptionSpecException { public: - option_exists_error(const std::string& option) + explicit option_exists_error(const std::string& option) : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") { } @@ -370,7 +388,7 @@ namespace cxxopts class invalid_option_format_error : public OptionSpecException { public: - invalid_option_format_error(const std::string& format) + explicit invalid_option_format_error(const std::string& format) : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) { } @@ -378,7 +396,7 @@ namespace cxxopts class option_syntax_exception : public OptionParseException { public: - option_syntax_exception(const std::string& text) + explicit option_syntax_exception(const std::string& text) : OptionParseException("Argument " + LQUOTE + text + RQUOTE + " starts with a - but has incorrect syntax") { @@ -388,7 +406,7 @@ namespace cxxopts class option_not_exists_exception : public OptionParseException { public: - option_not_exists_exception(const std::string& option) + explicit option_not_exists_exception(const std::string& option) : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") { } @@ -397,7 +415,7 @@ namespace cxxopts class missing_argument_exception : public OptionParseException { public: - missing_argument_exception(const std::string& option) + explicit missing_argument_exception(const std::string& option) : OptionParseException( "Option " + LQUOTE + option + RQUOTE + " is missing an argument" ) @@ -408,7 +426,7 @@ namespace cxxopts class option_requires_argument_exception : public OptionParseException { public: - option_requires_argument_exception(const std::string& option) + explicit option_requires_argument_exception(const std::string& option) : OptionParseException( "Option " + LQUOTE + option + RQUOTE + " requires an argument" ) @@ -436,16 +454,28 @@ namespace cxxopts class option_not_present_exception : public OptionParseException { public: - option_not_present_exception(const std::string& option) + explicit option_not_present_exception(const std::string& option) : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") { } }; + class option_has_no_value_exception : public OptionException + { + public: + explicit option_has_no_value_exception(const std::string& option) + : OptionException( + option.empty() ? + ("Option " + LQUOTE + option + RQUOTE + " has no value") : + "Option has no value") + { + } + }; + class argument_incorrect_type : public OptionParseException { public: - argument_incorrect_type + explicit argument_incorrect_type ( const std::string& arg ) @@ -459,7 +489,7 @@ namespace cxxopts class option_required_exception : public OptionParseException { public: - option_required_exception(const std::string& option) + explicit option_required_exception(const std::string& option) : OptionParseException( "Option " + LQUOTE + option + RQUOTE + " is required but not present" ) @@ -479,11 +509,10 @@ namespace cxxopts throw T{text}; #else // Otherwise manually instantiate the exception, print what() to stderr, - // and abort + // and exit T exception{text}; std::cerr << exception.what() << std::endl; - std::cerr << "Aborting (exceptions disabled)..." << std::endl; - std::abort(); + std::exit(EXIT_FAILURE); #endif } @@ -497,7 +526,7 @@ namespace cxxopts ("(t|T)(rue)?|1"); std::basic_regex falsy_pattern ("(f|F)(alse)?|0"); - } + } // namespace namespace detail { @@ -542,24 +571,23 @@ namespace cxxopts { SignedCheck::is_signed>()(negative, value, text); } - } + } // namespace detail template - R - checked_negate(T&& t, const std::string&, std::true_type) + void + checked_negate(R& r, T&& t, const std::string&, std::true_type) { // if we got to here, then `t` is a positive number that fits into // `R`. So to avoid MSVC C4146, we first cast it to `R`. // See https://github.com/jarro2783/cxxopts/issues/62 for more details. - return static_cast(-static_cast(t-1)-1); + r = static_cast(-static_cast(t-1)-1); } template - T - checked_negate(T&& t, const std::string& text, std::false_type) + void + checked_negate(R&, T&&, const std::string& text, std::false_type) { throw_or_mimic(text); - return t; } template @@ -624,9 +652,7 @@ namespace cxxopts if (negative) { - value = checked_negate(result, - text, - std::integral_constant()); + checked_negate(value, result, text, std::integral_constant()); } else { @@ -745,7 +771,7 @@ namespace cxxopts { std::stringstream in(text); std::string token; - while(in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { + while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { T v; parse_value(token, v); value.emplace_back(std::move(v)); @@ -798,12 +824,14 @@ namespace cxxopts { } - abstract_value(T* t) + explicit abstract_value(T* t) : m_store(t) { } - virtual ~abstract_value() = default; + ~abstract_value() override = default; + + abstract_value& operator=(const abstract_value&) = default; abstract_value(const abstract_value& rhs) { @@ -824,37 +852,37 @@ namespace cxxopts } void - parse(const std::string& text) const + parse(const std::string& text) const override { parse_value(text, *m_store); } bool - is_container() const + is_container() const override { return type_is_container::value; } void - parse() const + parse() const override { parse_value(m_default_value, *m_store); } bool - has_default() const + has_default() const override { return m_default; } bool - has_implicit() const + has_implicit() const override { return m_implicit; } std::shared_ptr - default_value(const std::string& value) + default_value(const std::string& value) override { m_default = true; m_default_value = value; @@ -862,7 +890,7 @@ namespace cxxopts } std::shared_ptr - implicit_value(const std::string& value) + implicit_value(const std::string& value) override { m_implicit = true; m_implicit_value = value; @@ -870,26 +898,26 @@ namespace cxxopts } std::shared_ptr - no_implicit_value() + no_implicit_value() override { m_implicit = false; return shared_from_this(); } std::string - get_default_value() const + get_default_value() const override { return m_default_value; } std::string - get_implicit_value() const + get_implicit_value() const override { return m_implicit_value; } bool - is_boolean() const + is_boolean() const override { return std::is_same::value; } @@ -901,21 +929,18 @@ namespace cxxopts { return *m_result; } - else - { - return *m_store; - } + return *m_store; } protected: - std::shared_ptr m_result; - T* m_store; + std::shared_ptr m_result{}; + T* m_store{}; bool m_default = false; bool m_implicit = false; - std::string m_default_value; - std::string m_implicit_value; + std::string m_default_value{}; + std::string m_implicit_value{}; }; template @@ -924,8 +949,9 @@ namespace cxxopts public: using abstract_value::abstract_value; + CXXOPTS_NODISCARD std::shared_ptr - clone() const + clone() const override { return std::make_shared>(*this); } @@ -935,21 +961,21 @@ namespace cxxopts class standard_value : public abstract_value { public: - ~standard_value() = default; + ~standard_value() override = default; standard_value() { set_default_and_implicit(); } - standard_value(bool* b) + explicit standard_value(bool* b) : abstract_value(b) { set_default_and_implicit(); } std::shared_ptr - clone() const + clone() const override { return std::make_shared>(*this); } @@ -965,7 +991,7 @@ namespace cxxopts m_implicit_value = "true"; } }; - } + } // namespace values template std::shared_ptr @@ -988,17 +1014,18 @@ namespace cxxopts public: OptionDetails ( - const std::string& short_, - const std::string& long_, - const String& desc, + std::string short_, + std::string long_, + String desc, std::shared_ptr val ) - : m_short(short_) - , m_long(long_) - , m_desc(desc) - , m_value(val) + : m_short(std::move(short_)) + , m_long(std::move(long_)) + , m_desc(std::move(desc)) + , m_value(std::move(val)) , m_count(0) { + m_hash = std::hash{}(m_long + m_short); } OptionDetails(const OptionDetails& rhs) @@ -1010,40 +1037,54 @@ namespace cxxopts OptionDetails(OptionDetails&& rhs) = default; + CXXOPTS_NODISCARD const String& description() const { return m_desc; } - const Value& value() const { + CXXOPTS_NODISCARD + const Value& + value() const { return *m_value; } + CXXOPTS_NODISCARD std::shared_ptr make_storage() const { return m_value->clone(); } + CXXOPTS_NODISCARD const std::string& short_name() const { return m_short; } + CXXOPTS_NODISCARD const std::string& long_name() const { return m_long; } + size_t + hash() const + { + return m_hash; + } + private: - std::string m_short; - std::string m_long; - String m_desc; - std::shared_ptr m_value; + std::string m_short{}; + std::string m_long{}; + String m_desc{}; + std::shared_ptr m_value{}; int m_count; + + size_t m_hash{}; }; struct HelpOptionDetails @@ -1062,9 +1103,9 @@ namespace cxxopts struct HelpGroupDetails { - std::string name; - std::string description; - std::vector options; + std::string name{}; + std::string description{}; + std::vector options{}; }; class OptionValue @@ -1073,23 +1114,26 @@ namespace cxxopts void parse ( - std::shared_ptr details, + const std::shared_ptr& details, const std::string& text ) { ensure_value(details); ++m_count; m_value->parse(text); + m_long_name = &details->long_name(); } void - parse_default(std::shared_ptr details) + parse_default(const std::shared_ptr& details) { ensure_value(details); m_default = true; + m_long_name = &details->long_name(); m_value->parse(); } + CXXOPTS_NODISCARD size_t count() const noexcept { @@ -1097,6 +1141,7 @@ namespace cxxopts } // TODO: maybe default options should count towards the number of arguments + CXXOPTS_NODISCARD bool has_default() const noexcept { @@ -1108,7 +1153,8 @@ namespace cxxopts as() const { if (m_value == nullptr) { - throw_or_mimic("No value"); + throw_or_mimic( + m_long_name == nullptr ? "" : *m_long_name); } #ifdef CXXOPTS_NO_RTTI @@ -1120,7 +1166,7 @@ namespace cxxopts private: void - ensure_value(std::shared_ptr details) + ensure_value(const std::shared_ptr& details) { if (m_value == nullptr) { @@ -1128,7 +1174,11 @@ namespace cxxopts } } - std::shared_ptr m_value; + + const std::string* m_long_name = nullptr; + // Holding this pointer is safe, since OptionValue's only exist in key-value pairs, + // where the key has the string we point to. + std::shared_ptr m_value{}; size_t m_count = 0; bool m_default = false; }; @@ -1142,15 +1192,15 @@ namespace cxxopts { } - const - std::string& + CXXOPTS_NODISCARD + const std::string& key() const { return m_key; } - const - std::string& + CXXOPTS_NODISCARD + const std::string& value() const { return m_value; @@ -1170,45 +1220,65 @@ namespace cxxopts std::string m_value; }; + using ParsedHashMap = std::unordered_map; + using NameHashMap = std::unordered_map; + class ParseResult { public: - ParseResult( - const std::shared_ptr< - std::unordered_map> - >, - std::vector, - bool allow_unrecognised, - int&, char**&); + ParseResult() {} + + ParseResult(const ParseResult&) = default; + + ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector sequential, std::vector&& unmatched_args) + : m_keys(std::move(keys)) + , m_values(std::move(values)) + , m_sequential(std::move(sequential)) + , m_unmatched(std::move(unmatched_args)) + { + } + + ParseResult& operator=(ParseResult&&) = default; + ParseResult& operator=(const ParseResult&) = default; size_t count(const std::string& o) const { - auto iter = m_options->find(o); - if (iter == m_options->end()) + auto iter = m_keys.find(o); + if (iter == m_keys.end()) { return 0; } - auto riter = m_results.find(iter->second); + auto viter = m_values.find(iter->second); - return riter->second.count(); + if (viter == m_values.end()) + { + return 0; + } + + return viter->second.count(); } const OptionValue& operator[](const std::string& option) const { - auto iter = m_options->find(option); + auto iter = m_keys.find(option); - if (iter == m_options->end()) + if (iter == m_keys.end()) { throw_or_mimic(option); } - auto riter = m_results.find(iter->second); + auto viter = m_values.find(iter->second); - return riter->second; + if (viter == m_values.end()) + { + throw_or_mimic(option); + } + + return viter->second; } const std::vector& @@ -1217,64 +1287,32 @@ namespace cxxopts return m_sequential; } + const std::vector& + unmatched() const + { + return m_unmatched; + } + private: - - void - parse(int& argc, char**& argv); - - void - add_to_option(const std::string& option, const std::string& arg); - - bool - consume_positional(std::string a); - - void - parse_option - ( - std::shared_ptr value, - const std::string& name, - const std::string& arg = "" - ); - - void - parse_default(std::shared_ptr details); - - void - checked_parse_arg - ( - int argc, - char* argv[], - int& current, - std::shared_ptr value, - const std::string& name - ); - - const std::shared_ptr< - std::unordered_map> - > m_options; - std::vector m_positional; - std::vector::iterator m_next_positional; - std::unordered_set m_positional_set; - std::unordered_map, OptionValue> m_results; - - bool m_allow_unrecognised; - - std::vector m_sequential; + NameHashMap m_keys{}; + ParsedHashMap m_values{}; + std::vector m_sequential{}; + std::vector m_unmatched{}; }; struct Option { Option ( - const std::string& opts, - const std::string& desc, - const std::shared_ptr& value = ::cxxopts::value(), - const std::string& arg_help = "" + std::string opts, + std::string desc, + std::shared_ptr value = ::cxxopts::value(), + std::string arg_help = "" ) - : opts_(opts) - , desc_(desc) - , value_(value) - , arg_help_(arg_help) + : opts_(std::move(opts)) + , desc_(std::move(desc)) + , value_(std::move(value)) + , arg_help_(std::move(arg_help)) { } @@ -1284,13 +1322,69 @@ namespace cxxopts std::string arg_help_; }; + using OptionMap = std::unordered_map>; + using PositionalList = std::vector; + using PositionalListIterator = PositionalList::const_iterator; + + class OptionParser + { + public: + OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised) + : m_options(options) + , m_positional(positional) + , m_allow_unrecognised(allow_unrecognised) + { + } + + ParseResult + parse(int argc, const char* const* argv); + + bool + consume_positional(const std::string& a, PositionalListIterator& next); + + void + checked_parse_arg + ( + int argc, + const char* const* argv, + int& current, + const std::shared_ptr& value, + const std::string& name + ); + + void + add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg); + + void + parse_option + ( + const std::shared_ptr& value, + const std::string& name, + const std::string& arg = "" + ); + + void + parse_default(const std::shared_ptr& details); + + private: + + void finalise_aliases(); + + const OptionMap& m_options; + const PositionalList& m_positional; + + std::vector m_sequential{}; + bool m_allow_unrecognised; + + ParsedHashMap m_parsed{}; + NameHashMap m_keys{}; + }; + class Options { - typedef std::unordered_map> - OptionMap; public: - Options(std::string program, std::string help_string = "") + explicit Options(std::string program, std::string help_string = "") : m_program(std::move(program)) , m_help_string(toLocalString(std::move(help_string))) , m_custom_help("[OPTION...]") @@ -1298,7 +1392,6 @@ namespace cxxopts , m_show_positional(false) , m_allow_unrecognised(false) , m_options(std::make_shared()) - , m_next_positional(m_positional.end()) { } @@ -1331,7 +1424,7 @@ namespace cxxopts } ParseResult - parse(int& argc, char**& argv); + parse(int argc, const char* const* argv); OptionAdder add_options(std::string group = ""); @@ -1357,7 +1450,7 @@ namespace cxxopts const std::string& s, const std::string& l, std::string desc, - std::shared_ptr value, + const std::shared_ptr& value, std::string arg_help ); @@ -1380,7 +1473,7 @@ namespace cxxopts std::string help(const std::vector& groups = {}) const; - const std::vector + std::vector groups() const; const HelpGroupDetails& @@ -1392,7 +1485,7 @@ namespace cxxopts add_one_option ( const std::string& option, - std::shared_ptr details + const std::shared_ptr& details ); String @@ -1408,20 +1501,22 @@ namespace cxxopts void generate_all_groups_help(String& result) const; - std::string m_program; - String m_help_string; - std::string m_custom_help; - std::string m_positional_help; + std::string m_program{}; + String m_help_string{}; + std::string m_custom_help{}; + std::string m_positional_help{}; bool m_show_positional; bool m_allow_unrecognised; std::shared_ptr m_options; - std::vector m_positional; - std::vector::iterator m_next_positional; - std::unordered_set m_positional_set; + std::vector m_positional{}; + std::unordered_set m_positional_set{}; //mapping from groups to help options - std::map m_help; + std::map m_help{}; + + std::list m_option_list{}; + std::unordered_map m_option_map{}; }; class OptionAdder @@ -1438,7 +1533,7 @@ namespace cxxopts ( const std::string& opts, const std::string& desc, - std::shared_ptr value + const std::shared_ptr& value = ::cxxopts::value(), std::string arg_help = "" ); @@ -1465,26 +1560,30 @@ namespace cxxopts const HelpOptionDetails& o ) { - auto& s = o.s; - auto& l = o.l; + const auto& s = o.s; + const auto& l = o.l; String result = " "; - if (s.size() > 0) + if (!s.empty()) { - result += "-" + toLocalString(s) + ","; + result += "-" + toLocalString(s); + if (!l.empty()) + { + result += ","; + } } else { result += " "; } - if (l.size() > 0) + if (!l.empty()) { result += " --" + toLocalString(l); } - auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg"; + auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) : "arg"; if (!o.is_boolean) { @@ -1513,7 +1612,7 @@ namespace cxxopts if (o.has_default && (!o.is_boolean || o.default_value != "false")) { - if(o.default_value != "") + if(!o.default_value.empty()) { desc += toLocalString(" (default: " + o.default_value + ")"); } @@ -1576,25 +1675,7 @@ namespace cxxopts return result; } - } - -inline -ParseResult::ParseResult -( - const std::shared_ptr< - std::unordered_map> - > options, - std::vector positional, - bool allow_unrecognised, - int& argc, char**& argv -) -: m_options(options) -, m_positional(std::move(positional)) -, m_next_positional(m_positional.begin()) -, m_allow_unrecognised(allow_unrecognised) -{ - parse(argc, argv); -} + } // namespace inline void @@ -1624,7 +1705,7 @@ OptionAdder::operator() ( const std::string& opts, const std::string& desc, - std::shared_ptr value, + const std::shared_ptr& value, std::string arg_help ) { @@ -1657,10 +1738,7 @@ OptionAdder::operator() { return std::make_tuple(long_.str(), short_.str()); } - else - { - return std::make_tuple(short_.str(), long_.str()); - } + return std::make_tuple(short_.str(), long_.str()); }(short_match, long_match); m_options.add_option @@ -1678,21 +1756,24 @@ OptionAdder::operator() inline void -ParseResult::parse_default(std::shared_ptr details) +OptionParser::parse_default(const std::shared_ptr& details) { - m_results[details].parse_default(details); + // TODO: remove the duplicate code here + auto& store = m_parsed[details->hash()]; + store.parse_default(details); } inline void -ParseResult::parse_option +OptionParser::parse_option ( - std::shared_ptr value, + const std::shared_ptr& value, const std::string& /*name*/, const std::string& arg ) { - auto& result = m_results[value]; + auto hash = value->hash(); + auto& result = m_parsed[hash]; result.parse(value, arg); m_sequential.emplace_back(value->long_name(), arg); @@ -1700,12 +1781,12 @@ ParseResult::parse_option inline void -ParseResult::checked_parse_arg +OptionParser::checked_parse_arg ( int argc, - char* argv[], + const char* const* argv, int& current, - std::shared_ptr value, + const std::shared_ptr& value, const std::string& name ) { @@ -1736,52 +1817,36 @@ ParseResult::checked_parse_arg inline void -ParseResult::add_to_option(const std::string& option, const std::string& arg) +OptionParser::add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg) { - auto iter = m_options->find(option); - - if (iter == m_options->end()) - { - throw_or_mimic(option); - } - parse_option(iter->second, option, arg); } inline bool -ParseResult::consume_positional(std::string a) +OptionParser::consume_positional(const std::string& a, PositionalListIterator& next) { - while (m_next_positional != m_positional.end()) + while (next != m_positional.end()) { - auto iter = m_options->find(*m_next_positional); - if (iter != m_options->end()) + auto iter = m_options.find(*next); + if (iter != m_options.end()) { - auto& result = m_results[iter->second]; + auto& result = m_parsed[iter->second->hash()]; if (!iter->second->value().is_container()) { if (result.count() == 0) { - add_to_option(*m_next_positional, a); - ++m_next_positional; + add_to_option(iter, *next, a); + ++next; return true; } - else - { - ++m_next_positional; - continue; - } - } - else - { - add_to_option(*m_next_positional, a); - return true; + ++next; + continue; } + add_to_option(iter, *next, a); + return true; } - else - { - throw_or_mimic(*m_next_positional); - } + throw_or_mimic(*next); } return false; @@ -1799,7 +1864,6 @@ void Options::parse_positional(std::vector options) { m_positional = std::move(options); - m_next_positional = m_positional.begin(); m_positional_set.insert(m_positional.begin(), m_positional.end()); } @@ -1808,26 +1872,26 @@ inline void Options::parse_positional(std::initializer_list options) { - parse_positional(std::vector(std::move(options))); + parse_positional(std::vector(options)); } inline ParseResult -Options::parse(int& argc, char**& argv) +Options::parse(int argc, const char* const* argv) { - ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv); - return result; + OptionParser parser(*m_options, m_positional, m_allow_unrecognised); + + return parser.parse(argc, argv); } -inline -void -ParseResult::parse(int& argc, char**& argv) +inline ParseResult +OptionParser::parse(int argc, const char* const* argv) { int current = 1; - - int nextKeep = 1; - bool consume_remaining = false; + PositionalListIterator next_positional = m_positional.begin(); + + std::vector unmatched; while (current != argc) { @@ -1854,13 +1918,12 @@ ParseResult::parse(int& argc, char**& argv) //if true is returned here then it was consumed, otherwise it is //ignored - if (consume_positional(argv[current])) + if (consume_positional(argv[current], next_positional)) { } else { - argv[nextKeep] = argv[current]; - ++nextKeep; + unmatched.push_back(argv[current]); } //if we return from here then it was parsed successfully, so continue } @@ -1874,19 +1937,16 @@ ParseResult::parse(int& argc, char**& argv) for (std::size_t i = 0; i != s.size(); ++i) { std::string name(1, s[i]); - auto iter = m_options->find(name); + auto iter = m_options.find(name); - if (iter == m_options->end()) + if (iter == m_options.end()) { if (m_allow_unrecognised) { continue; } - else - { - //error - throw_or_mimic(name); - } + //error + throw_or_mimic(name); } auto value = iter->second; @@ -1911,23 +1971,19 @@ ParseResult::parse(int& argc, char**& argv) { const std::string& name = result[1]; - auto iter = m_options->find(name); + auto iter = m_options.find(name); - if (iter == m_options->end()) + if (iter == m_options.end()) { if (m_allow_unrecognised) { // keep unrecognised options in argument list, skip to next argument - argv[nextKeep] = argv[current]; - ++nextKeep; + unmatched.push_back(argv[current]); ++current; continue; } - else - { - //error - throw_or_mimic(name); - } + //error + throw_or_mimic(name); } auto opt = iter->second; @@ -1951,12 +2007,12 @@ ParseResult::parse(int& argc, char**& argv) ++current; } - for (auto& opt : *m_options) + for (auto& opt : m_options) { auto& detail = opt.second; - auto& value = detail->value(); + const auto& value = detail->value(); - auto& store = m_results[detail]; + auto& store = m_parsed[detail->hash()]; if(value.has_default() && !store.count() && !store.has_default()){ parse_default(detail); @@ -1967,7 +2023,7 @@ ParseResult::parse(int& argc, char**& argv) { while (current < argc) { - if (!consume_positional(argv[current])) { + if (!consume_positional(argv[current], next_positional)) { break; } ++current; @@ -1975,14 +2031,30 @@ ParseResult::parse(int& argc, char**& argv) //adjust argv for any that couldn't be swallowed while (current != argc) { - argv[nextKeep] = argv[current]; - ++nextKeep; + unmatched.push_back(argv[current]); ++current; } } - argc = nextKeep; + finalise_aliases(); + ParseResult parsed(std::move(m_keys), std::move(m_parsed), std::move(m_sequential), std::move(unmatched)); + return parsed; +} + +inline +void +OptionParser::finalise_aliases() +{ + for (auto& option: m_options) + { + auto& detail = *option.second; + auto hash = detail.hash(); + m_keys[detail.short_name()] = hash; + m_keys[detail.long_name()] = hash; + + m_parsed.emplace(hash, OptionValue()); + } } inline @@ -2004,23 +2076,28 @@ Options::add_option const std::string& s, const std::string& l, std::string desc, - std::shared_ptr value, + const std::shared_ptr& value, std::string arg_help ) { auto stringDesc = toLocalString(std::move(desc)); auto option = std::make_shared(s, l, stringDesc, value); - if (s.size() > 0) + if (!s.empty()) { add_one_option(s, option); } - if (l.size() > 0) + if (!l.empty()) { add_one_option(l, option); } + m_option_list.push_front(*option.get()); + auto iter = m_option_list.begin(); + m_option_map[s] = iter; + m_option_map[l] = iter; + //add the help details auto& options = m_help[group]; @@ -2037,7 +2114,7 @@ void Options::add_one_option ( const std::string& option, - std::shared_ptr details + const std::shared_ptr& details ) { auto in = m_options->emplace(option, details); @@ -2052,7 +2129,7 @@ inline String Options::help_one_group(const std::string& g) const { - typedef std::vector> OptionHelp; + using OptionHelp = std::vector>; auto group = m_help.find(g); if (group == m_help.end()) @@ -2151,7 +2228,7 @@ Options::generate_all_groups_help(String& result) const std::vector all_groups; all_groups.reserve(m_help.size()); - for (auto& group : m_help) + for (const auto& group : m_help) { all_groups.push_back(group.first); } @@ -2166,13 +2243,13 @@ Options::help(const std::vector& help_groups) const String result = m_help_string + "\nUsage:\n " + toLocalString(m_program) + " " + toLocalString(m_custom_help); - if (m_positional.size() > 0 && m_positional_help.size() > 0) { + if (!m_positional.empty() && !m_positional_help.empty()) { result += " " + toLocalString(m_positional_help); } result += "\n\n"; - if (help_groups.size() == 0) + if (help_groups.empty()) { generate_all_groups_help(result); } @@ -2185,7 +2262,7 @@ Options::help(const std::vector& help_groups) const } inline -const std::vector +std::vector Options::groups() const { std::vector g; @@ -2210,6 +2287,6 @@ Options::group_help(const std::string& group) const return m_help.at(group); } -} +} // namespace cxxopts #endif //CXXOPTS_HPP_INCLUDED diff --git a/tests/cxxopts.hpp b/tests/cxxopts.hpp deleted file mode 100644 index 1381ab32..00000000 --- a/tests/cxxopts.hpp +++ /dev/null @@ -1,2104 +0,0 @@ -/* - -Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -*/ - -#ifndef CXXOPTS_HPP_INCLUDED -#define CXXOPTS_HPP_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cpp_lib_optional -#include -#define CXXOPTS_HAS_OPTIONAL -#endif - -#ifndef CXXOPTS_VECTOR_DELIMITER -#define CXXOPTS_VECTOR_DELIMITER ',' -#endif - -#define CXXOPTS__VERSION_MAJOR 2 -#define CXXOPTS__VERSION_MINOR 2 -#define CXXOPTS__VERSION_PATCH 0 - -namespace cxxopts -{ - static constexpr struct { - uint8_t major, minor, patch; - } version = { - CXXOPTS__VERSION_MAJOR, - CXXOPTS__VERSION_MINOR, - CXXOPTS__VERSION_PATCH - }; -} - -//when we ask cxxopts to use Unicode, help strings are processed using ICU, -//which results in the correct lengths being computed for strings when they -//are formatted for the help output -//it is necessary to make sure that can be found by the -//compiler, and that icu-uc is linked in to the binary. - -#ifdef CXXOPTS_USE_UNICODE -#include - -namespace cxxopts -{ - typedef icu::UnicodeString String; - - inline - String - toLocalString(std::string s) - { - return icu::UnicodeString::fromUTF8(std::move(s)); - } - - class UnicodeStringIterator : public - std::iterator - { - public: - - UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) - : s(string) - , i(pos) - { - } - - value_type - operator*() const - { - return s->char32At(i); - } - - bool - operator==(const UnicodeStringIterator& rhs) const - { - return s == rhs.s && i == rhs.i; - } - - bool - operator!=(const UnicodeStringIterator& rhs) const - { - return !(*this == rhs); - } - - UnicodeStringIterator& - operator++() - { - ++i; - return *this; - } - - UnicodeStringIterator - operator+(int32_t v) - { - return UnicodeStringIterator(s, i + v); - } - - private: - const icu::UnicodeString* s; - int32_t i; - }; - - inline - String& - stringAppend(String&s, String a) - { - return s.append(std::move(a)); - } - - inline - String& - stringAppend(String& s, int n, UChar32 c) - { - for (int i = 0; i != n; ++i) - { - s.append(c); - } - - return s; - } - - template - String& - stringAppend(String& s, Iterator begin, Iterator end) - { - while (begin != end) - { - s.append(*begin); - ++begin; - } - - return s; - } - - inline - size_t - stringLength(const String& s) - { - return s.length(); - } - - inline - std::string - toUTF8String(const String& s) - { - std::string result; - s.toUTF8String(result); - - return result; - } - - inline - bool - empty(const String& s) - { - return s.isEmpty(); - } -} - -namespace std -{ - inline - cxxopts::UnicodeStringIterator - begin(const icu::UnicodeString& s) - { - return cxxopts::UnicodeStringIterator(&s, 0); - } - - inline - cxxopts::UnicodeStringIterator - end(const icu::UnicodeString& s) - { - return cxxopts::UnicodeStringIterator(&s, s.length()); - } -} - -//ifdef CXXOPTS_USE_UNICODE -#else - -namespace cxxopts -{ - typedef std::string String; - - template - T - toLocalString(T&& t) - { - return std::forward(t); - } - - inline - size_t - stringLength(const String& s) - { - return s.length(); - } - - inline - String& - stringAppend(String&s, String a) - { - return s.append(std::move(a)); - } - - inline - String& - stringAppend(String& s, size_t n, char c) - { - return s.append(n, c); - } - - template - String& - stringAppend(String& s, Iterator begin, Iterator end) - { - return s.append(begin, end); - } - - template - std::string - toUTF8String(T&& t) - { - return std::forward(t); - } - - inline - bool - empty(const std::string& s) - { - return s.empty(); - } -} - -//ifdef CXXOPTS_USE_UNICODE -#endif - -namespace cxxopts -{ - namespace - { -#ifdef _WIN32 - const std::string LQUOTE("\'"); - const std::string RQUOTE("\'"); -#else - const std::string LQUOTE("‘"); - const std::string RQUOTE("’"); -#endif - } - - class Value : public std::enable_shared_from_this - { - public: - - virtual ~Value() = default; - - virtual - std::shared_ptr - clone() const = 0; - - virtual void - parse(const std::string& text) const = 0; - - virtual void - parse() const = 0; - - virtual bool - has_default() const = 0; - - virtual bool - is_container() const = 0; - - virtual bool - has_implicit() const = 0; - - virtual std::string - get_default_value() const = 0; - - virtual std::string - get_implicit_value() const = 0; - - virtual std::shared_ptr - default_value(const std::string& value) = 0; - - virtual std::shared_ptr - implicit_value(const std::string& value) = 0; - - virtual std::shared_ptr - no_implicit_value() = 0; - - virtual bool - is_boolean() const = 0; - }; - - class OptionException : public std::exception - { - public: - OptionException(const std::string& message) - : m_message(message) - { - } - - virtual const char* - what() const noexcept - { - return m_message.c_str(); - } - - private: - std::string m_message; - }; - - class OptionSpecException : public OptionException - { - public: - - OptionSpecException(const std::string& message) - : OptionException(message) - { - } - }; - - class OptionParseException : public OptionException - { - public: - OptionParseException(const std::string& message) - : OptionException(message) - { - } - }; - - class option_exists_error : public OptionSpecException - { - public: - option_exists_error(const std::string& option) - : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") - { - } - }; - - class invalid_option_format_error : public OptionSpecException - { - public: - invalid_option_format_error(const std::string& format) - : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) - { - } - }; - - class option_syntax_exception : public OptionParseException { - public: - option_syntax_exception(const std::string& text) - : OptionParseException("Argument " + LQUOTE + text + RQUOTE + - " starts with a - but has incorrect syntax") - { - } - }; - - class option_not_exists_exception : public OptionParseException - { - public: - option_not_exists_exception(const std::string& option) - : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") - { - } - }; - - class missing_argument_exception : public OptionParseException - { - public: - missing_argument_exception(const std::string& option) - : OptionParseException( - "Option " + LQUOTE + option + RQUOTE + " is missing an argument" - ) - { - } - }; - - class option_requires_argument_exception : public OptionParseException - { - public: - option_requires_argument_exception(const std::string& option) - : OptionParseException( - "Option " + LQUOTE + option + RQUOTE + " requires an argument" - ) - { - } - }; - - class option_not_has_argument_exception : public OptionParseException - { - public: - option_not_has_argument_exception - ( - const std::string& option, - const std::string& arg - ) - : OptionParseException( - "Option " + LQUOTE + option + RQUOTE + - " does not take an argument, but argument " + - LQUOTE + arg + RQUOTE + " given" - ) - { - } - }; - - class option_not_present_exception : public OptionParseException - { - public: - option_not_present_exception(const std::string& option) - : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") - { - } - }; - - class argument_incorrect_type : public OptionParseException - { - public: - argument_incorrect_type - ( - const std::string& arg - ) - : OptionParseException( - "Argument " + LQUOTE + arg + RQUOTE + " failed to parse" - ) - { - } - }; - - class option_required_exception : public OptionParseException - { - public: - option_required_exception(const std::string& option) - : OptionParseException( - "Option " + LQUOTE + option + RQUOTE + " is required but not present" - ) - { - } - }; - - namespace values - { - namespace - { - std::basic_regex integer_pattern - ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); - std::basic_regex truthy_pattern - ("(t|T)(rue)?|1"); - std::basic_regex falsy_pattern - ("(f|F)(alse)?|0"); - } - - namespace detail - { - template - struct SignedCheck; - - template - struct SignedCheck - { - template - void - operator()(bool negative, U u, const std::string& text) - { - if (negative) - { - if (u > static_cast((std::numeric_limits::min)())) - { - throw argument_incorrect_type(text); - } - } - else - { - if (u > static_cast((std::numeric_limits::max)())) - { - throw argument_incorrect_type(text); - } - } - } - }; - - template - struct SignedCheck - { - template - void - operator()(bool, U, const std::string&) {} - }; - - template - void - check_signed_range(bool negative, U value, const std::string& text) - { - SignedCheck::is_signed>()(negative, value, text); - } - } - - template - R - checked_negate(T&& t, const std::string&, std::true_type) - { - // if we got to here, then `t` is a positive number that fits into - // `R`. So to avoid MSVC C4146, we first cast it to `R`. - // See https://github.com/jarro2783/cxxopts/issues/62 for more details. - return -static_cast(t-1)-1; - } - - template - T - checked_negate(T&&, const std::string& text, std::false_type) - { - throw argument_incorrect_type(text); - } - - template - void - integer_parser(const std::string& text, T& value) - { - std::smatch match; - std::regex_match(text, match, integer_pattern); - - if (match.length() == 0) - { - throw argument_incorrect_type(text); - } - - if (match.length(4) > 0) - { - value = 0; - return; - } - - using US = typename std::make_unsigned::type; - - constexpr bool is_signed = std::numeric_limits::is_signed; - const bool negative = match.length(1) > 0; - const uint8_t base = match.length(2) > 0 ? 16 : 10; - - auto value_match = match[3]; - - US result = 0; - - for (auto iter = value_match.first; iter != value_match.second; ++iter) - { - US digit = 0; - - if (*iter >= '0' && *iter <= '9') - { - digit = static_cast(*iter - '0'); - } - else if (base == 16 && *iter >= 'a' && *iter <= 'f') - { - digit = static_cast(*iter - 'a' + 10); - } - else if (base == 16 && *iter >= 'A' && *iter <= 'F') - { - digit = static_cast(*iter - 'A' + 10); - } - else - { - throw argument_incorrect_type(text); - } - - US next = result * base + digit; - if (result > next) - { - throw argument_incorrect_type(text); - } - - result = next; - } - - detail::check_signed_range(negative, result, text); - - if (negative) - { - value = checked_negate(result, - text, - std::integral_constant()); - } - else - { - value = static_cast(result); - } - } - - template - void stringstream_parser(const std::string& text, T& value) - { - std::stringstream in(text); - in >> value; - if (!in) { - throw argument_incorrect_type(text); - } - } - - inline - void - parse_value(const std::string& text, uint8_t& value) - { - integer_parser(text, value); - } - - inline - void - parse_value(const std::string& text, int8_t& value) - { - integer_parser(text, value); - } - - inline - void - parse_value(const std::string& text, uint16_t& value) - { - integer_parser(text, value); - } - - inline - void - parse_value(const std::string& text, int16_t& value) - { - integer_parser(text, value); - } - - inline - void - parse_value(const std::string& text, uint32_t& value) - { - integer_parser(text, value); - } - - inline - void - parse_value(const std::string& text, int32_t& value) - { - integer_parser(text, value); - } - - inline - void - parse_value(const std::string& text, uint64_t& value) - { - integer_parser(text, value); - } - - inline - void - parse_value(const std::string& text, int64_t& value) - { - integer_parser(text, value); - } - - inline - void - parse_value(const std::string& text, bool& value) - { - std::smatch result; - std::regex_match(text, result, truthy_pattern); - - if (!result.empty()) - { - value = true; - return; - } - - std::regex_match(text, result, falsy_pattern); - if (!result.empty()) - { - value = false; - return; - } - - throw argument_incorrect_type(text); - } - - inline - void - parse_value(const std::string& text, std::string& value) - { - value = text; - } - - // The fallback parser. It uses the stringstream parser to parse all types - // that have not been overloaded explicitly. It has to be placed in the - // source code before all other more specialized templates. - template - void - parse_value(const std::string& text, T& value) { - stringstream_parser(text, value); - } - - template - void - parse_value(const std::string& text, std::vector& value) - { - std::stringstream in(text); - std::string token; - while(in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { - T v; - parse_value(token, v); - value.emplace_back(std::move(v)); - } - } - -#ifdef CXXOPTS_HAS_OPTIONAL - template - void - parse_value(const std::string& text, std::optional& value) - { - T result; - parse_value(text, result); - value = std::move(result); - } -#endif - - template - struct type_is_container - { - static constexpr bool value = false; - }; - - template - struct type_is_container> - { - static constexpr bool value = true; - }; - - template - class abstract_value : public Value - { - using Self = abstract_value; - - public: - abstract_value() - : m_result(std::make_shared()) - , m_store(m_result.get()) - { - } - - abstract_value(T* t) - : m_store(t) - { - } - - virtual ~abstract_value() = default; - - abstract_value(const abstract_value& rhs) - { - if (rhs.m_result) - { - m_result = std::make_shared(); - m_store = m_result.get(); - } - else - { - m_store = rhs.m_store; - } - - m_default = rhs.m_default; - m_implicit = rhs.m_implicit; - m_default_value = rhs.m_default_value; - m_implicit_value = rhs.m_implicit_value; - } - - void - parse(const std::string& text) const - { - parse_value(text, *m_store); - } - - bool - is_container() const - { - return type_is_container::value; - } - - void - parse() const - { - parse_value(m_default_value, *m_store); - } - - bool - has_default() const - { - return m_default; - } - - bool - has_implicit() const - { - return m_implicit; - } - - std::shared_ptr - default_value(const std::string& value) - { - m_default = true; - m_default_value = value; - return shared_from_this(); - } - - std::shared_ptr - implicit_value(const std::string& value) - { - m_implicit = true; - m_implicit_value = value; - return shared_from_this(); - } - - std::shared_ptr - no_implicit_value() - { - m_implicit = false; - return shared_from_this(); - } - - std::string - get_default_value() const - { - return m_default_value; - } - - std::string - get_implicit_value() const - { - return m_implicit_value; - } - - bool - is_boolean() const - { - return std::is_same::value; - } - - const T& - get() const - { - if (m_store == nullptr) - { - return *m_result; - } - else - { - return *m_store; - } - } - - protected: - std::shared_ptr m_result; - T* m_store; - - bool m_default = false; - bool m_implicit = false; - - std::string m_default_value; - std::string m_implicit_value; - }; - - template - class standard_value : public abstract_value - { - public: - using abstract_value::abstract_value; - - std::shared_ptr - clone() const - { - return std::make_shared>(*this); - } - }; - - template <> - class standard_value : public abstract_value - { - public: - ~standard_value() = default; - - standard_value() - { - set_default_and_implicit(); - } - - standard_value(bool* b) - : abstract_value(b) - { - set_default_and_implicit(); - } - - std::shared_ptr - clone() const - { - return std::make_shared>(*this); - } - - private: - - void - set_default_and_implicit() - { - m_default = true; - m_default_value = "false"; - m_implicit = true; - m_implicit_value = "true"; - } - }; - } - - template - std::shared_ptr - value() - { - return std::make_shared>(); - } - - template - std::shared_ptr - value(T& t) - { - return std::make_shared>(&t); - } - - class OptionAdder; - - class OptionDetails - { - public: - OptionDetails - ( - const std::string& short_, - const std::string& long_, - const String& desc, - std::shared_ptr val - ) - : m_short(short_) - , m_long(long_) - , m_desc(desc) - , m_value(val) - , m_count(0) - { - } - - OptionDetails(const OptionDetails& rhs) - : m_desc(rhs.m_desc) - , m_count(rhs.m_count) - { - m_value = rhs.m_value->clone(); - } - - OptionDetails(OptionDetails&& rhs) = default; - - const String& - description() const - { - return m_desc; - } - - const Value& value() const { - return *m_value; - } - - std::shared_ptr - make_storage() const - { - return m_value->clone(); - } - - const std::string& - short_name() const - { - return m_short; - } - - const std::string& - long_name() const - { - return m_long; - } - - private: - std::string m_short; - std::string m_long; - String m_desc; - std::shared_ptr m_value; - int m_count; - }; - - struct HelpOptionDetails - { - std::string s; - std::string l; - String desc; - bool has_default; - std::string default_value; - bool has_implicit; - std::string implicit_value; - std::string arg_help; - bool is_container; - bool is_boolean; - }; - - struct HelpGroupDetails - { - std::string name; - std::string description; - std::vector options; - }; - - class OptionValue - { - public: - void - parse - ( - std::shared_ptr details, - const std::string& text - ) - { - ensure_value(details); - ++m_count; - m_value->parse(text); - } - - void - parse_default(std::shared_ptr details) - { - ensure_value(details); - m_value->parse(); - } - - size_t - count() const - { - return m_count; - } - - template - const T& - as() const - { - if (m_value == nullptr) { - throw std::domain_error("No value"); - } - -#ifdef CXXOPTS_NO_RTTI - return static_cast&>(*m_value).get(); -#else - return dynamic_cast&>(*m_value).get(); -#endif - } - - private: - void - ensure_value(std::shared_ptr details) - { - if (m_value == nullptr) - { - m_value = details->make_storage(); - } - } - - std::shared_ptr m_value; - size_t m_count = 0; - }; - - class KeyValue - { - public: - KeyValue(std::string key_, std::string value_) - : m_key(std::move(key_)) - , m_value(std::move(value_)) - { - } - - const - std::string& - key() const - { - return m_key; - } - - const - std::string& - value() const - { - return m_value; - } - - template - T - as() const - { - T result; - values::parse_value(m_value, result); - return result; - } - - private: - std::string m_key; - std::string m_value; - }; - - class ParseResult - { - public: - - ParseResult( - const std::shared_ptr< - std::unordered_map> - >, - std::vector, - bool allow_unrecognised, - int&, char**&); - - size_t - count(const std::string& o) const - { - auto iter = m_options->find(o); - if (iter == m_options->end()) - { - return 0; - } - - auto riter = m_results.find(iter->second); - - return riter->second.count(); - } - - const OptionValue& - operator[](const std::string& option) const - { - auto iter = m_options->find(option); - - if (iter == m_options->end()) - { - throw option_not_present_exception(option); - } - - auto riter = m_results.find(iter->second); - - return riter->second; - } - - const std::vector& - arguments() const - { - return m_sequential; - } - - private: - - void - parse(int& argc, char**& argv); - - void - add_to_option(const std::string& option, const std::string& arg); - - bool - consume_positional(std::string a); - - void - parse_option - ( - std::shared_ptr value, - const std::string& name, - const std::string& arg = "" - ); - - void - parse_default(std::shared_ptr details); - - void - checked_parse_arg - ( - int argc, - char* argv[], - int& current, - std::shared_ptr value, - const std::string& name - ); - - const std::shared_ptr< - std::unordered_map> - > m_options; - std::vector m_positional; - std::vector::iterator m_next_positional; - std::unordered_set m_positional_set; - std::unordered_map, OptionValue> m_results; - - bool m_allow_unrecognised; - - std::vector m_sequential; - }; - - class Options - { - typedef std::unordered_map> - OptionMap; - public: - - Options(std::string program, std::string help_string = "") - : m_program(std::move(program)) - , m_help_string(toLocalString(std::move(help_string))) - , m_custom_help("[OPTION...]") - , m_positional_help("positional parameters") - , m_show_positional(false) - , m_allow_unrecognised(false) - , m_options(std::make_shared()) - , m_next_positional(m_positional.end()) - { - } - - Options& - positional_help(std::string help_text) - { - m_positional_help = std::move(help_text); - return *this; - } - - Options& - custom_help(std::string help_text) - { - m_custom_help = std::move(help_text); - return *this; - } - - Options& - show_positional_help() - { - m_show_positional = true; - return *this; - } - - Options& - allow_unrecognised_options() - { - m_allow_unrecognised = true; - return *this; - } - - ParseResult - parse(int& argc, char**& argv); - - OptionAdder - add_options(std::string group = ""); - - void - add_option - ( - const std::string& group, - const std::string& s, - const std::string& l, - std::string desc, - std::shared_ptr value, - std::string arg_help - ); - - //parse positional arguments into the given option - void - parse_positional(std::string option); - - void - parse_positional(std::vector options); - - void - parse_positional(std::initializer_list options); - - template - void - parse_positional(Iterator begin, Iterator end) { - parse_positional(std::vector{begin, end}); - } - - std::string - help(const std::vector& groups = {}) const; - - const std::vector - groups() const; - - const HelpGroupDetails& - group_help(const std::string& group) const; - - private: - - void - add_one_option - ( - const std::string& option, - std::shared_ptr details - ); - - String - help_one_group(const std::string& group) const; - - void - generate_group_help - ( - String& result, - const std::vector& groups - ) const; - - void - generate_all_groups_help(String& result) const; - - std::string m_program; - String m_help_string; - std::string m_custom_help; - std::string m_positional_help; - bool m_show_positional; - bool m_allow_unrecognised; - - std::shared_ptr m_options; - std::vector m_positional; - std::vector::iterator m_next_positional; - std::unordered_set m_positional_set; - - //mapping from groups to help options - std::map m_help; - }; - - class OptionAdder - { - public: - - OptionAdder(Options& options, std::string group) - : m_options(options), m_group(std::move(group)) - { - } - - OptionAdder& - operator() - ( - const std::string& opts, - const std::string& desc, - std::shared_ptr value - = ::cxxopts::value(), - std::string arg_help = "" - ); - - private: - Options& m_options; - std::string m_group; - }; - - namespace - { - constexpr int OPTION_LONGEST = 30; - constexpr int OPTION_DESC_GAP = 2; - - std::basic_regex option_matcher - ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); - - std::basic_regex option_specifier - ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); - - String - format_option - ( - const HelpOptionDetails& o - ) - { - auto& s = o.s; - auto& l = o.l; - - String result = " "; - - if (s.size() > 0) - { - result += "-" + toLocalString(s) + ","; - } - else - { - result += " "; - } - - if (l.size() > 0) - { - result += " --" + toLocalString(l); - } - - auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg"; - - if (!o.is_boolean) - { - if (o.has_implicit) - { - result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]"; - } - else - { - result += " " + arg; - } - } - - return result; - } - - String - format_description - ( - const HelpOptionDetails& o, - size_t start, - size_t width - ) - { - auto desc = o.desc; - - if (o.has_default && (!o.is_boolean || o.default_value != "false")) - { - desc += toLocalString(" (default: " + o.default_value + ")"); - } - - String result; - - auto current = std::begin(desc); - auto startLine = current; - auto lastSpace = current; - - auto size = size_t{}; - - while (current != std::end(desc)) - { - if (*current == ' ') - { - lastSpace = current; - } - - if (*current == '\n') - { - startLine = current + 1; - lastSpace = startLine; - } - else if (size > width) - { - if (lastSpace == startLine) - { - stringAppend(result, startLine, current + 1); - stringAppend(result, "\n"); - stringAppend(result, start, ' '); - startLine = current + 1; - lastSpace = startLine; - } - else - { - stringAppend(result, startLine, lastSpace); - stringAppend(result, "\n"); - stringAppend(result, start, ' '); - startLine = lastSpace + 1; - } - size = 0; - } - else - { - ++size; - } - - ++current; - } - - //append whatever is left - stringAppend(result, startLine, current); - - return result; - } - } - -inline -ParseResult::ParseResult -( - const std::shared_ptr< - std::unordered_map> - > options, - std::vector positional, - bool allow_unrecognised, - int& argc, char**& argv -) -: m_options(options) -, m_positional(std::move(positional)) -, m_next_positional(m_positional.begin()) -, m_allow_unrecognised(allow_unrecognised) -{ - parse(argc, argv); -} - -inline -OptionAdder -Options::add_options(std::string group) -{ - return OptionAdder(*this, std::move(group)); -} - -inline -OptionAdder& -OptionAdder::operator() -( - const std::string& opts, - const std::string& desc, - std::shared_ptr value, - std::string arg_help -) -{ - std::match_results result; - std::regex_match(opts.c_str(), result, option_specifier); - - if (result.empty()) - { - throw invalid_option_format_error(opts); - } - - const auto& short_match = result[2]; - const auto& long_match = result[3]; - - if (!short_match.length() && !long_match.length()) - { - throw invalid_option_format_error(opts); - } else if (long_match.length() == 1 && short_match.length()) - { - throw invalid_option_format_error(opts); - } - - auto option_names = [] - ( - const std::sub_match& short_, - const std::sub_match& long_ - ) - { - if (long_.length() == 1) - { - return std::make_tuple(long_.str(), short_.str()); - } - else - { - return std::make_tuple(short_.str(), long_.str()); - } - }(short_match, long_match); - - m_options.add_option - ( - m_group, - std::get<0>(option_names), - std::get<1>(option_names), - desc, - value, - std::move(arg_help) - ); - - return *this; -} - -inline -void -ParseResult::parse_default(std::shared_ptr details) -{ - m_results[details].parse_default(details); -} - -inline -void -ParseResult::parse_option -( - std::shared_ptr value, - const std::string& /*name*/, - const std::string& arg -) -{ - auto& result = m_results[value]; - result.parse(value, arg); - - m_sequential.emplace_back(value->long_name(), arg); -} - -inline -void -ParseResult::checked_parse_arg -( - int argc, - char* argv[], - int& current, - std::shared_ptr value, - const std::string& name -) -{ - if (current + 1 >= argc) - { - if (value->value().has_implicit()) - { - parse_option(value, name, value->value().get_implicit_value()); - } - else - { - throw missing_argument_exception(name); - } - } - else - { - if (value->value().has_implicit()) - { - parse_option(value, name, value->value().get_implicit_value()); - } - else - { - parse_option(value, name, argv[current + 1]); - ++current; - } - } -} - -inline -void -ParseResult::add_to_option(const std::string& option, const std::string& arg) -{ - auto iter = m_options->find(option); - - if (iter == m_options->end()) - { - throw option_not_exists_exception(option); - } - - parse_option(iter->second, option, arg); -} - -inline -bool -ParseResult::consume_positional(std::string a) -{ - while (m_next_positional != m_positional.end()) - { - auto iter = m_options->find(*m_next_positional); - if (iter != m_options->end()) - { - auto& result = m_results[iter->second]; - if (!iter->second->value().is_container()) - { - if (result.count() == 0) - { - add_to_option(*m_next_positional, a); - ++m_next_positional; - return true; - } - else - { - ++m_next_positional; - continue; - } - } - else - { - add_to_option(*m_next_positional, a); - return true; - } - } - else - { - throw option_not_exists_exception(*m_next_positional); - } - } - - return false; -} - -inline -void -Options::parse_positional(std::string option) -{ - parse_positional(std::vector{std::move(option)}); -} - -inline -void -Options::parse_positional(std::vector options) -{ - m_positional = std::move(options); - m_next_positional = m_positional.begin(); - - m_positional_set.insert(m_positional.begin(), m_positional.end()); -} - -inline -void -Options::parse_positional(std::initializer_list options) -{ - parse_positional(std::vector(std::move(options))); -} - -inline -ParseResult -Options::parse(int& argc, char**& argv) -{ - ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv); - return result; -} - -inline -void -ParseResult::parse(int& argc, char**& argv) -{ - int current = 1; - - int nextKeep = 1; - - bool consume_remaining = false; - - while (current != argc) - { - if (strcmp(argv[current], "--") == 0) - { - consume_remaining = true; - ++current; - break; - } - - std::match_results result; - std::regex_match(argv[current], result, option_matcher); - - if (result.empty()) - { - //not a flag - - // but if it starts with a `-`, then it's an error - if (argv[current][0] == '-' && argv[current][1] != '\0') { - if (!m_allow_unrecognised) { - throw option_syntax_exception(argv[current]); - } - } - - //if true is returned here then it was consumed, otherwise it is - //ignored - if (consume_positional(argv[current])) - { - } - else - { - argv[nextKeep] = argv[current]; - ++nextKeep; - } - //if we return from here then it was parsed successfully, so continue - } - else - { - //short or long option? - if (result[4].length() != 0) - { - const std::string& s = result[4]; - - for (std::size_t i = 0; i != s.size(); ++i) - { - std::string name(1, s[i]); - auto iter = m_options->find(name); - - if (iter == m_options->end()) - { - if (m_allow_unrecognised) - { - continue; - } - else - { - //error - throw option_not_exists_exception(name); - } - } - - auto value = iter->second; - - if (i + 1 == s.size()) - { - //it must be the last argument - checked_parse_arg(argc, argv, current, value, name); - } - else if (value->value().has_implicit()) - { - parse_option(value, name, value->value().get_implicit_value()); - } - else - { - //error - throw option_requires_argument_exception(name); - } - } - } - else if (result[1].length() != 0) - { - const std::string& name = result[1]; - - auto iter = m_options->find(name); - - if (iter == m_options->end()) - { - if (m_allow_unrecognised) - { - // keep unrecognised options in argument list, skip to next argument - argv[nextKeep] = argv[current]; - ++nextKeep; - ++current; - continue; - } - else - { - //error - throw option_not_exists_exception(name); - } - } - - auto opt = iter->second; - - //equals provided for long option? - if (result[2].length() != 0) - { - //parse the option given - - parse_option(opt, name, result[3]); - } - else - { - //parse the next argument - checked_parse_arg(argc, argv, current, opt, name); - } - } - - } - - ++current; - } - - for (auto& opt : *m_options) - { - auto& detail = opt.second; - auto& value = detail->value(); - - auto& store = m_results[detail]; - - if(!store.count() && value.has_default()){ - parse_default(detail); - } - } - - if (consume_remaining) - { - while (current < argc) - { - if (!consume_positional(argv[current])) { - break; - } - ++current; - } - - //adjust argv for any that couldn't be swallowed - while (current != argc) { - argv[nextKeep] = argv[current]; - ++nextKeep; - ++current; - } - } - - argc = nextKeep; - -} - -inline -void -Options::add_option -( - const std::string& group, - const std::string& s, - const std::string& l, - std::string desc, - std::shared_ptr value, - std::string arg_help -) -{ - auto stringDesc = toLocalString(std::move(desc)); - auto option = std::make_shared(s, l, stringDesc, value); - - if (s.size() > 0) - { - add_one_option(s, option); - } - - if (l.size() > 0) - { - add_one_option(l, option); - } - - //add the help details - auto& options = m_help[group]; - - options.options.emplace_back(HelpOptionDetails{s, l, stringDesc, - value->has_default(), value->get_default_value(), - value->has_implicit(), value->get_implicit_value(), - std::move(arg_help), - value->is_container(), - value->is_boolean()}); -} - -inline -void -Options::add_one_option -( - const std::string& option, - std::shared_ptr details -) -{ - auto in = m_options->emplace(option, details); - - if (!in.second) - { - throw option_exists_error(option); - } -} - -inline -String -Options::help_one_group(const std::string& g) const -{ - typedef std::vector> OptionHelp; - - auto group = m_help.find(g); - if (group == m_help.end()) - { - return ""; - } - - OptionHelp format; - - size_t longest = 0; - - String result; - - if (!g.empty()) - { - result += toLocalString(" " + g + " options:\n"); - } - - for (const auto& o : group->second.options) - { - if (m_positional_set.find(o.l) != m_positional_set.end() && - !m_show_positional) - { - continue; - } - - auto s = format_option(o); - longest = (std::max)(longest, stringLength(s)); - format.push_back(std::make_pair(s, String())); - } - - longest = (std::min)(longest, static_cast(OPTION_LONGEST)); - - //widest allowed description - auto allowed = size_t{76} - longest - OPTION_DESC_GAP; - - auto fiter = format.begin(); - for (const auto& o : group->second.options) - { - if (m_positional_set.find(o.l) != m_positional_set.end() && - !m_show_positional) - { - continue; - } - - auto d = format_description(o, longest + OPTION_DESC_GAP, allowed); - - result += fiter->first; - if (stringLength(fiter->first) > longest) - { - result += '\n'; - result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' ')); - } - else - { - result += toLocalString(std::string(longest + OPTION_DESC_GAP - - stringLength(fiter->first), - ' ')); - } - result += d; - result += '\n'; - - ++fiter; - } - - return result; -} - -inline -void -Options::generate_group_help -( - String& result, - const std::vector& print_groups -) const -{ - for (size_t i = 0; i != print_groups.size(); ++i) - { - const String& group_help_text = help_one_group(print_groups[i]); - if (empty(group_help_text)) - { - continue; - } - result += group_help_text; - if (i < print_groups.size() - 1) - { - result += '\n'; - } - } -} - -inline -void -Options::generate_all_groups_help(String& result) const -{ - std::vector all_groups; - all_groups.reserve(m_help.size()); - - for (auto& group : m_help) - { - all_groups.push_back(group.first); - } - - generate_group_help(result, all_groups); -} - -inline -std::string -Options::help(const std::vector& help_groups) const -{ - String result = m_help_string + "\nUsage:\n " + - toLocalString(m_program) + " " + toLocalString(m_custom_help); - - if (m_positional.size() > 0 && m_positional_help.size() > 0) { - result += " " + toLocalString(m_positional_help); - } - - result += "\n\n"; - - if (help_groups.size() == 0) - { - generate_all_groups_help(result); - } - else - { - generate_group_help(result, help_groups); - } - - return toUTF8String(result); -} - -inline -const std::vector -Options::groups() const -{ - std::vector g; - - std::transform( - m_help.begin(), - m_help.end(), - std::back_inserter(g), - [] (const std::map::value_type& pair) - { - return pair.first; - } - ); - - return g; -} - -inline -const HelpGroupDetails& -Options::group_help(const std::string& group) const -{ - return m_help.at(group); -} - -} - -#endif //CXXOPTS_HPP_INCLUDED From 3fc7d70f1f7c2bacaa6de78b997e56237c9981fd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 11:27:41 +0100 Subject: [PATCH 065/668] Update libaiff in attempt to fix MSVC errors --- external/st_audiofile/thirdparty/libaiff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/st_audiofile/thirdparty/libaiff b/external/st_audiofile/thirdparty/libaiff index c47d11b9..ce5a0167 160000 --- a/external/st_audiofile/thirdparty/libaiff +++ b/external/st_audiofile/thirdparty/libaiff @@ -1 +1 @@ -Subproject commit c47d11b98f25bf052c85cff7f5d5422375c18fcb +Subproject commit ce5a0167a3d636915d62ad59232e20367557164d From af7ee06a8193ba42867d1d49d36adbc191ce566f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 1 Nov 2020 15:11:14 +0100 Subject: [PATCH 066/668] Fix a pkg-config error in some situations --- vst/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 0ee8cddc..8e765c09 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -87,6 +87,7 @@ if(WIN32) elseif(APPLE) target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${APPLE_FOUNDATION_LIBRARY}) else() + find_package(PkgConfig REQUIRED) pkg_check_modules(GLIB REQUIRED glib-2.0) target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE ${GLIB_INCLUDE_DIRS}) target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${GLIB_LIBRARIES}) From a906b6e9272b66735be4b92f1281323732bca0ed Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 4 Nov 2020 08:28:44 +0100 Subject: [PATCH 067/668] Updated libaiff --- external/st_audiofile/thirdparty/libaiff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/st_audiofile/thirdparty/libaiff b/external/st_audiofile/thirdparty/libaiff index ce5a0167..78864a4a 160000 --- a/external/st_audiofile/thirdparty/libaiff +++ b/external/st_audiofile/thirdparty/libaiff @@ -1 +1 @@ -Subproject commit ce5a0167a3d636915d62ad59232e20367557164d +Subproject commit 78864a4a2e769e426be8cfd78ae7f5f72e236c33 From cda079eef8898221b0e00b487437f4b833d3f302 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 4 Nov 2020 08:45:57 +0100 Subject: [PATCH 068/668] Fix the sndfile conditional not well handled in demo programs The conditional ST_AUDIO_FILE_USE_SNDFILE appears in private headers, which are used by some demo programs. Linking to sfizz does not inherit this flag, and FileInstrument gets wrong values for loop constants. --- common.mk | 3 +++ src/CMakeLists.txt | 6 ++++++ src/sfizz/AudioReader.cpp | 10 +++++----- src/sfizz/FileMetadata.h | 4 ++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/common.mk b/common.mk index 40abb575..23d2c1c9 100644 --- a/common.mk +++ b/common.mk @@ -134,6 +134,9 @@ ifeq ($(SFIZZ_USE_SNDFILE),1) SFIZZ_SNDFILE_C_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --cflags sndfile) SFIZZ_SNDFILE_CXX_FLAGS ?= $(SFIZZ_SNDFILE_C_FLAGS) SFIZZ_SNDFILE_LINK_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --libs sndfile) + +SFIZZ_C_FLAGS += -DSFIZZ_USE_SNDFILE=1 +SFIZZ_CXX_FLAGS += -DSFIZZ_USE_SNDFILE=1 endif # st_audiofile dependency diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 539a2ec0..2eb30262 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -222,6 +222,9 @@ target_include_directories (sfizz_static PUBLIC external) target_link_libraries (sfizz_static PUBLIC absl::strings absl::span) target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp") +if(SFIZZ_USE_SNDFILE) + target_compile_definitions (sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) +endif() if (WIN32) target_compile_definitions (sfizz_static PRIVATE _USE_MATH_DEFINES) endif() @@ -248,6 +251,9 @@ if (SFIZZ_SHARED) target_include_directories (sfizz_shared PRIVATE .) target_include_directories (sfizz_shared PRIVATE external) target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) + if(SFIZZ_USE_SNDFILE) + target_compile_definitions (sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) + endif() if (WIN32) target_compile_definitions (sfizz_shared PRIVATE _USE_MATH_DEFINES) endif() diff --git a/src/sfizz/AudioReader.cpp b/src/sfizz/AudioReader.cpp index 6f9fe1b9..875195ef 100644 --- a/src/sfizz/AudioReader.cpp +++ b/src/sfizz/AudioReader.cpp @@ -7,7 +7,7 @@ #include "AudioReader.h" #include "FileMetadata.h" #include -#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#if defined(SFIZZ_USE_SNDFILE) #include #endif #include @@ -51,7 +51,7 @@ unsigned BasicSndfileReader::sampleRate() const bool BasicSndfileReader::getInstrument(InstrumentInfo* instrument) { -#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#if defined(SFIZZ_USE_SNDFILE) SNDFILE* sndfile = reinterpret_cast(handle_.get_sndfile_handle()); if (sf_command(sndfile, SFC_GET_INSTRUMENT, &instrument, sizeof(instrument)) == SF_TRUE) return true; @@ -238,7 +238,7 @@ void NoSeekReverseReader::readWholeFile() //------------------------------------------------------------------------------ -#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#if defined(SFIZZ_USE_SNDFILE) const std::error_category& sndfile_category() { class sndfile_category : public std::error_category { @@ -298,7 +298,7 @@ private: //------------------------------------------------------------------------------ -#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#if defined(SFIZZ_USE_SNDFILE) static bool formatHasFastSeeking(int format) { bool fast; @@ -348,7 +348,7 @@ static AudioReaderPtr createAudioReaderWithHandle(ST_AudioFile handle, bool reve else if (!reverse) reader.reset(new ForwardReader(std::move(handle))); else { -#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#if defined(SFIZZ_USE_SNDFILE) bool hasFastSeeking = formatHasFastSeeking(handle.get_sndfile_format()); #else bool hasFastSeeking = true; diff --git a/src/sfizz/FileMetadata.h b/src/sfizz/FileMetadata.h index b4094381..96facb03 100644 --- a/src/sfizz/FileMetadata.h +++ b/src/sfizz/FileMetadata.h @@ -5,7 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once -#if defined(ST_AUDIO_FILE_USE_SNDFILE) +#if defined(SFIZZ_USE_SNDFILE) #include #endif #include "ghc/fs_std.hpp" @@ -24,7 +24,7 @@ struct RiffChunkInfo { uint32_t length; }; -#if !defined(ST_AUDIO_FILE_USE_SNDFILE) +#if !defined(SFIZZ_USE_SNDFILE) /** @brief Loop mode, like SF_LOOP_* */ From 0bcf626786fcc00fbc964a14d8a1388cd40cf4ee Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 4 Nov 2020 08:55:34 +0100 Subject: [PATCH 069/668] Fix AudioReader::getInstrument under libsndfile --- src/sfizz/AudioReader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sfizz/AudioReader.cpp b/src/sfizz/AudioReader.cpp index 875195ef..029428b1 100644 --- a/src/sfizz/AudioReader.cpp +++ b/src/sfizz/AudioReader.cpp @@ -53,7 +53,8 @@ bool BasicSndfileReader::getInstrument(InstrumentInfo* instrument) { #if defined(SFIZZ_USE_SNDFILE) SNDFILE* sndfile = reinterpret_cast(handle_.get_sndfile_handle()); - if (sf_command(sndfile, SFC_GET_INSTRUMENT, &instrument, sizeof(instrument)) == SF_TRUE) + SF_INSTRUMENT* sfins = instrument; + if (sf_command(sndfile, SFC_GET_INSTRUMENT, sfins, sizeof(SF_INSTRUMENT)) == SF_TRUE) return true; #else (void)instrument; From d5f49595d3f331cbe9a033be7f58f71e998743d9 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 4 Nov 2020 09:53:59 +0100 Subject: [PATCH 070/668] Make sure to expose widechar sndfile API --- external/st_audiofile/src/st_audiofile.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/external/st_audiofile/src/st_audiofile.h b/external/st_audiofile/src/st_audiofile.h index 3fbcbfd8..64fd3230 100644 --- a/external/st_audiofile/src/st_audiofile.h +++ b/external/st_audiofile/src/st_audiofile.h @@ -6,6 +6,10 @@ #pragma once #if defined(ST_AUDIO_FILE_USE_SNDFILE) +#if defined(_WIN32) +#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 +#include +#endif #include #endif #include From 65ca3adf65e4d368f45b2352eeaf53d6d9343acf Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 4 Nov 2020 10:17:04 +0100 Subject: [PATCH 071/668] Allow sfizz library targets to expose st_audiofile publicly This fixes the problems with programs which link sfizz internal API: the tests, benchmarks, demos. The MSVC comfiguration would fail to fail "sndfile.h" while building the tests. --- src/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2eb30262..e8cb136c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -224,6 +224,7 @@ target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Thr set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp") if(SFIZZ_USE_SNDFILE) target_compile_definitions (sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) + target_link_libraries (sfizz_static PUBLIC st_audiofile) endif() if (WIN32) target_compile_definitions (sfizz_static PRIVATE _USE_MATH_DEFINES) @@ -253,6 +254,7 @@ if (SFIZZ_SHARED) target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions (sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) + target_link_libraries (sfizz_shared PUBLIC st_audiofile) endif() if (WIN32) target_compile_definitions (sfizz_shared PRIVATE _USE_MATH_DEFINES) From 722225f9f276059c71b534e071b056ce4370a3d9 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 19 Oct 2020 02:58:01 +0200 Subject: [PATCH 072/668] Add OSC and plugin-side communication --- common.mk | 2 + editor/CMakeLists.txt | 1 + editor/src/editor/Editor.cpp | 6 + editor/src/editor/EditorController.h | 10 + lv2/sfizz.c | 44 +++- lv2/sfizz.ttl.in | 7 +- lv2/sfizz_lv2.h | 4 + lv2/sfizz_ui.cpp | 43 +++- src/CMakeLists.txt | 24 +- src/sfizz.h | 74 ++++++ src/sfizz.hpp | 70 +++++ src/sfizz/Messaging.cpp | 367 +++++++++++++++++++++++++++ src/sfizz/Messaging.h | 31 +++ src/sfizz/Synth.cpp | 11 + src/sfizz/Synth.h | 22 ++ src/sfizz/SynthMessaging.cpp | 81 ++++++ src/sfizz/sfizz.cpp | 31 +++ src/sfizz/sfizz_wrapper.cpp | 33 +++ src/sfizz_message.h | 91 +++++++ tests/CMakeLists.txt | 1 + tests/MessagingT.cpp | 95 +++++++ vst/SfizzVstController.cpp | 30 +++ vst/SfizzVstController.h | 8 + vst/SfizzVstEditor.cpp | 34 ++- vst/SfizzVstEditor.h | 12 +- vst/SfizzVstProcessor.cpp | 147 ++++++++--- vst/SfizzVstProcessor.h | 12 +- 27 files changed, 1232 insertions(+), 59 deletions(-) create mode 100644 src/sfizz/Messaging.cpp create mode 100644 src/sfizz/Messaging.h create mode 100644 src/sfizz/SynthMessaging.cpp create mode 100644 src/sfizz_message.h create mode 100644 tests/MessagingT.cpp diff --git a/common.mk b/common.mk index 23d2c1c9..99c0881c 100644 --- a/common.mk +++ b/common.mk @@ -89,6 +89,7 @@ SFIZZ_SOURCES = \ src/sfizz/Logger.cpp \ src/sfizz/LFO.cpp \ src/sfizz/LFODescription.cpp \ + src/sfizz/Messaging.cpp \ src/sfizz/MidiState.cpp \ src/sfizz/OpcodeCleanup.cpp \ src/sfizz/Opcode.cpp \ @@ -112,6 +113,7 @@ SFIZZ_SOURCES = \ src/sfizz/simd/HelpersAVX.cpp \ src/sfizz/Smoothers.cpp \ src/sfizz/Synth.cpp \ + src/sfizz/SynthMessaging.cpp \ src/sfizz/Tuning.cpp \ src/sfizz/utility/SpinMutex.cpp \ src/sfizz/Voice.cpp \ diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 8f676d7e..0244666b 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -42,6 +42,7 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/utility/vstgui_after.h src/editor/utility/vstgui_before.h) target_include_directories(sfizz_editor PUBLIC "src") +target_link_libraries(sfizz_editor PUBLIC sfizz_messaging) target_link_libraries(sfizz_editor PRIVATE sfizz-vstgui) target_link_libraries(sfizz_editor PUBLIC absl::strings) if(APPLE) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index b4a4608e..5a4c5a05 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -100,6 +100,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { SPiano* piano_ = nullptr; void uiReceiveValue(EditId id, const EditValue& v) override; + void uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) override; void createFrameContents(); @@ -318,6 +319,11 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) } } +void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) +{ + // TODO handle the message... +} + void Editor::Impl::createFrameContents() { CViewContainer* mainView; diff --git a/editor/src/editor/EditorController.h b/editor/src/editor/EditorController.h index 4d3db4c9..bbe80115 100644 --- a/editor/src/editor/EditorController.h +++ b/editor/src/editor/EditorController.h @@ -6,6 +6,7 @@ #pragma once #include "EditValue.h" +#include #include #include #include @@ -20,6 +21,7 @@ public: virtual void uiBeginSend(EditId id) = 0; virtual void uiEndSend(EditId id) = 0; virtual void uiSendMIDI(const uint8_t* msg, uint32_t len) = 0; + virtual void uiSendMessage(const char* path, const char* sig, const sfizz_arg_t* args) = 0; class Receiver; void decorate(Receiver* r) { r_ = r; } @@ -27,10 +29,12 @@ public: public: virtual ~Receiver() {} virtual void uiReceiveValue(EditId id, const EditValue& v) = 0; + virtual void uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) = 0; }; // called by DSP void uiReceiveValue(EditId id, const EditValue& v); + void uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args); private: Receiver* r_ = nullptr; @@ -41,3 +45,9 @@ inline void EditorController::uiReceiveValue(EditId id, const EditValue& v) if (r_) r_->uiReceiveValue(id, v); } + +inline void EditorController::uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) +{ + if (r_) + r_->uiReceiveMessage(path, sig, args); +} diff --git a/lv2/sfizz.c b/lv2/sfizz.c index b68c527f..44d9077a 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -148,6 +148,7 @@ typedef struct LV2_URID sfizz_log_status_uri; LV2_URID sfizz_check_modification_uri; LV2_URID sfizz_active_voices_uri; + LV2_URID sfizz_osc_blob_uri; LV2_URID time_position_uri; LV2_URID time_bar_uri; LV2_URID time_bar_beat_uri; @@ -158,6 +159,7 @@ typedef struct // Sfizz related data sfizz_synth_t *synth; + sfizz_client_t *client; bool expect_nominal_block_length; char sfz_file_path[MAX_PATH_SIZE]; char scala_file_path[MAX_PATH_SIZE]; @@ -181,6 +183,9 @@ typedef struct // Paths char bundle_path[MAX_BUNDLE_PATH_SIZE]; + + // OSC + uint8_t osc_temp[OSC_TEMP_SIZE]; } sfizz_plugin_t; enum @@ -236,6 +241,7 @@ sfizz_lv2_map_required_uris(sfizz_plugin_t *self) self->sfizz_log_status_uri = map->map(map->handle, SFIZZ__logStatus); self->sfizz_log_status_uri = map->map(map->handle, SFIZZ__logStatus); self->sfizz_check_modification_uri = map->map(map->handle, SFIZZ__checkModification); + self->sfizz_osc_blob_uri = map->map(map->handle, SFIZZ__OSCBlob); self->time_position_uri = map->map(map->handle, LV2_TIME__Position); self->time_bar_uri = map->map(map->handle, LV2_TIME__bar); self->time_bar_beat_uri = map->map(map->handle, LV2_TIME__barBeat); @@ -423,6 +429,28 @@ sfizz_lv2_update_timeinfo(sfizz_plugin_t *self, int delay, int updates) sfizz_send_playback_state(self->synth, delay, self->speed > 0); } +static void +sfizz_lv2_receive_message(void* data, int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + (void)delay; + + sfizz_plugin_t *self = (sfizz_plugin_t *)data; + + // transmit to UI as OSC blob + uint8_t *osc_temp = self->osc_temp; + uint32_t osc_size = sfizz_prepare_message(osc_temp, OSC_TEMP_SIZE, path, sig, args); + if (osc_size > OSC_TEMP_SIZE) + return; + + bool write_ok = + lv2_atom_forge_frame_time(&self->forge, 0) && + lv2_atom_forge_atom(&self->forge, osc_size, self->sfizz_osc_blob_uri) && + lv2_atom_forge_raw(&self->forge, osc_temp, osc_size); + lv2_atom_forge_pad(&self->forge, osc_size); + + (void)write_ok; +} + static LV2_Handle instantiate(const LV2_Descriptor *descriptor, double rate, @@ -570,6 +598,9 @@ instantiate(const LV2_Descriptor *descriptor, } self->synth = sfizz_create_synth(); + self->client = sfizz_create_client(self); + sfizz_set_broadcast_callback(self->synth, &sfizz_lv2_receive_message, self); + sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message); sfizz_lv2_get_default_sfz_path(instance, self->sfz_file_path, MAX_PATH_SIZE); sfizz_lv2_get_default_scala_path(instance, self->scala_file_path, MAX_PATH_SIZE); @@ -586,6 +617,7 @@ static void cleanup(LV2_Handle instance) { sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + sfizz_delete_client(self->client); sfizz_free(self->synth); free(self); } @@ -952,12 +984,22 @@ run(LV2_Handle instance, uint32_t sample_count) self->unmap->unmap(self->unmap->handle, obj->body.otype)); continue; } - // Got an atom that is a MIDI event } else if (ev->body.type == self->midi_event_uri) { + // Got an atom that is a MIDI event sfizz_lv2_process_midi_event(self, ev); } + else if (ev->body.type == self->sfizz_osc_blob_uri) + { + // Got an atom that is a OSC event + const char *path; + const char *sig; + const sfizz_arg_t *args; + uint8_t buffer[1024]; + if (sfizz_extract_message(LV2_ATOM_BODY_CONST(&ev->body), ev->body.size, buffer, sizeof(buffer), &path, &sig, &args) > 0) + sfizz_send_message(self->synth, self->client, (int)ev->time.frames, path, sig, args); + } } diff --git a/lv2/sfizz.ttl.in b/lv2/sfizz.ttl.in index 5ddd0317..45494016 100644 --- a/lv2/sfizz.ttl.in +++ b/lv2/sfizz.ttl.in @@ -11,6 +11,7 @@ @prefix pprop: . @prefix rdf: . @prefix rdfs: . +@prefix rsz: . @prefix state: . @prefix time: . @prefix ui: . @@ -92,21 +93,23 @@ midnam:update a lv2:Feature . lv2:port [ a lv2:InputPort, atom:AtomPort ; atom:bufferType atom:Sequence ; - atom:supports patch:Message, midi:MidiEvent, time:Position ; + atom:supports patch:Message, midi:MidiEvent, time:Position, <@LV2PLUGIN_URI@:OSCBlob> ; lv2:designation lv2:control ; lv2:index 0 ; lv2:symbol "control" ; lv2:name "Control", "Contrôle"@fr ; + rsz:minimumSize 65536 ; ] , [ a lv2:OutputPort, atom:AtomPort ; atom:bufferType atom:Sequence ; - atom:supports patch:Message ; + atom:supports patch:Message, <@LV2PLUGIN_URI@:OSCBlob> ; lv2:designation lv2:control ; lv2:index 1 ; lv2:symbol "notify" ; lv2:name "Notify", "Notification"@fr ; + rsz:minimumSize 65536 ; ] , [ a lv2:AudioPort, lv2:OutputPort ; lv2:index 2 ; diff --git a/lv2/sfizz_lv2.h b/lv2/sfizz_lv2.h index b0eafe00..e8662cec 100644 --- a/lv2/sfizz_lv2.h +++ b/lv2/sfizz_lv2.h @@ -7,6 +7,8 @@ #pragma once #define MAX_PATH_SIZE 1024 +#define ATOM_TEMP_SIZE 8192 +#define OSC_TEMP_SIZE 8192 #define SFIZZ_URI "http://sfztools.github.io/sfizz" #define SFIZZ_UI_URI "http://sfztools.github.io/sfizz#ui" @@ -19,6 +21,8 @@ // These ones are just for the worker #define SFIZZ__logStatus SFIZZ_URI ":" "log_status" #define SFIZZ__checkModification SFIZZ_URI ":" "check_modification" +// OSC atoms +#define SFIZZ__OSCBlob SFIZZ_URI ":" "OSCBlob" enum { diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index 42866eb7..79e3f9fa 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -107,12 +107,17 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface { LV2_URID patch_value_uri; LV2_URID sfizz_sfz_file_uri; LV2_URID sfizz_scala_file_uri; + LV2_URID sfizz_osc_blob_uri; + + uint8_t osc_temp[OSC_TEMP_SIZE]; + alignas(LV2_Atom) uint8_t atom_temp[ATOM_TEMP_SIZE]; protected: void uiSendValue(EditId id, const EditValue& v) override; void uiBeginSend(EditId id) override; void uiEndSend(EditId id) override; void uiSendMIDI(const uint8_t* msg, uint32_t len) override; + void uiSendMessage(const char* path, const char* sig, const sfizz_arg_t* args) override; private: void uiTouch(EditId id, bool t); @@ -192,6 +197,7 @@ instantiate(const LV2UI_Descriptor *descriptor, self->patch_value_uri = map->map(map->handle, LV2_PATCH__value); self->sfizz_sfz_file_uri = map->map(map->handle, SFIZZ__sfzFile); self->sfizz_scala_file_uri = map->map(map->handle, SFIZZ__tuningfile); + self->sfizz_osc_blob_uri = map->map(map->handle, SFIZZ__OSCBlob); // set up the resource path // * on Linux, this is determined by going 2 folders back from the SO path @@ -335,6 +341,14 @@ port_event(LV2UI_Handle ui, } } } + else if (atom->type == self->sfizz_osc_blob_uri) { + const char *path; + const char *sig; + const sfizz_arg_t *args; + uint8_t buffer[1024]; + if (sfizz_extract_message(LV2_ATOM_BODY_CONST(atom), atom->size, buffer, sizeof(buffer), &path, &sig, &args) > 0) + self->uiReceiveMessage(path, sig, args); + } } (void)buffer_size; @@ -422,9 +436,8 @@ void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v) auto sendPath = [this](LV2_URID property, const std::string& value) { LV2_Atom_Forge *forge = &atom_forge; LV2_Atom_Forge_Frame frame; - alignas(LV2_Atom) uint8_t buffer[MAX_PATH_SIZE + 512]; - auto *atom = reinterpret_cast(buffer); - lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer)); + auto *atom = reinterpret_cast(atom_temp); + lv2_atom_forge_set_buffer(forge, atom_temp, sizeof(atom_temp)); if (lv2_atom_forge_object(forge, &frame, 0, patch_set_uri) && lv2_atom_forge_key(forge, patch_property_uri) && lv2_atom_forge_urid(forge, property) && @@ -514,12 +527,30 @@ void sfizz_ui_t::uiTouch(EditId id, bool t) void sfizz_ui_t::uiSendMIDI(const uint8_t* msg, uint32_t len) { LV2_Atom_Forge *forge = &atom_forge; - alignas(LV2_Atom) uint8_t buffer[512]; - auto *atom = reinterpret_cast(buffer); - lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer)); + auto *atom = reinterpret_cast(atom_temp); + lv2_atom_forge_set_buffer(forge, atom_temp, sizeof(atom_temp)); if (lv2_atom_forge_atom(forge, len, midi_event_uri) && lv2_atom_forge_write(forge, msg, len)) { write(con, SFIZZ_CONTROL, lv2_atom_total_size(atom), atom_event_transfer_uri, atom); } } + +void sfizz_ui_t::uiSendMessage(const char* path, const char* sig, const sfizz_arg_t* args) +{ + uint8_t *osc_temp = this->osc_temp; + uint32_t osc_size = sfizz_prepare_message(osc_temp, OSC_TEMP_SIZE, path, sig, args); + + if (osc_size > OSC_TEMP_SIZE) + return; + + LV2_Atom_Forge *forge = &atom_forge; + auto *atom = reinterpret_cast(atom_temp); + lv2_atom_forge_set_buffer(forge, atom_temp, sizeof(atom_temp)); + + if (lv2_atom_forge_atom(forge, osc_size, sfizz_osc_blob_uri) && + lv2_atom_forge_raw(forge, osc_temp, osc_size)) + { + write(con, SFIZZ_CONTROL, lv2_atom_total_size(atom), atom_event_transfer_uri, atom); + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8cb136c..f5ad3e7e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -148,6 +148,7 @@ set (SFIZZ_SOURCES sfizz/PowerFollower.cpp sfizz/FlexEGDescription.cpp sfizz/FlexEnvelope.cpp + sfizz/SynthMessaging.cpp sfizz/modulations/ModId.cpp sfizz/modulations/ModKey.cpp sfizz/modulations/ModKeyHash.cpp @@ -206,6 +207,7 @@ set (SFIZZ_PARSER_SOURCES set (SFIZZ_PARSER_OTHER sfizz/OpcodeCleanup.re) source_group ("Other Files" FILES ${SFIZZ_PARSER_OTHER}) +# Sfizz parser library add_library (sfizz_parser STATIC) target_sources (sfizz_parser PRIVATE ${SFIZZ_PARSER_HEADERS} ${SFIZZ_PARSER_SOURCES} ${SFIZZ_PARSER_OTHER}) @@ -213,6 +215,20 @@ target_include_directories (sfizz_parser PUBLIC sfizz) target_include_directories (sfizz_parser PUBLIC external) target_link_libraries (sfizz_parser PUBLIC absl::strings PRIVATE absl::flat_hash_map) +# OSC messaging library +set (SFIZZ_MESSAGING_HEADERS + sfizz/Messaging.h + sfizz_message.h) + +set (SFIZZ_MESSAGING_SOURCES + sfizz/Messaging.cpp) + +add_library (sfizz_messaging STATIC) +target_sources (sfizz_messaging PRIVATE + ${SFIZZ_MESSAGING_HEADERS} ${SFIZZ_MESSAGING_SOURCES}) +target_include_directories (sfizz_messaging PUBLIC ".") +target_link_libraries (sfizz_messaging PUBLIC absl::strings) + # Sfizz static library add_library(sfizz_static STATIC) target_sources(sfizz_static PRIVATE @@ -220,8 +236,8 @@ target_sources(sfizz_static PRIVATE target_include_directories (sfizz_static PUBLIC .) target_include_directories (sfizz_static PUBLIC external) target_link_libraries (sfizz_static PUBLIC absl::strings absl::span) -target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) -set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp") +target_link_libraries (sfizz_static PRIVATE sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) +set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") if(SFIZZ_USE_SNDFILE) target_compile_definitions (sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) target_link_libraries (sfizz_static PUBLIC st_audiofile) @@ -251,7 +267,7 @@ if (SFIZZ_SHARED) ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) target_include_directories (sfizz_shared PRIVATE .) target_include_directories (sfizz_shared PRIVATE external) - target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) + target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions (sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) target_link_libraries (sfizz_shared PUBLIC st_audiofile) @@ -263,7 +279,7 @@ if (SFIZZ_SHARED) target_compile_definitions (sfizz_shared PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") endif() target_compile_definitions(sfizz_shared PRIVATE SFIZZ_EXPORT_SYMBOLS) - set_target_properties (sfizz_shared PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp") + set_target_properties (sfizz_shared PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") sfizz_enable_lto_if_needed(sfizz_shared) sfizz_enable_fast_math(sfizz_shared) diff --git a/src/sfizz.h b/src/sfizz.h index ec47ad04..b20e7eae 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -10,6 +10,7 @@ */ #pragma once +#include "sfizz_message.h" #include #include @@ -731,6 +732,79 @@ SFIZZ_EXPORTED_API int sfizz_get_cc_label_number(sfizz_synth_t* synth, int label */ SFIZZ_EXPORTED_API const char * sfizz_get_cc_label_text(sfizz_synth_t* synth, int label_index); +/** + * @addtogroup Messaging + * @{ + */ + +/** + * @brief Client for communicating with the synth engine in either direction + * @since 0.6.0 + */ +typedef struct sfizz_client_t sfizz_client_t; + +/** + * @brief Create a new messaging client + * @since 0.6.0 + * + * @param data The opaque data pointer which is passed to the receiver. + * @return The new client. + */ +SFIZZ_EXPORTED_API sfizz_client_t* sfizz_create_client(void* data); + +/** + * @brief Destroy a messaging client + * @since 0.6.0 + * + * @param client The client. + */ +SFIZZ_EXPORTED_API void sfizz_delete_client(sfizz_client_t* client); + +/** + * @brief Get the client data + * @since 0.6.0 + * + * @param client The client. + * @return The client data. + */ +SFIZZ_EXPORTED_API void* sfizz_get_client_data(sfizz_client_t* client); + +/** + * @brief Set the function which receives reply messages from the synth engine. + * @since 0.6.0 + * + * @param client The client. + * @param receive The pointer to the receiving function. + */ +SFIZZ_EXPORTED_API void sfizz_set_receive_callback(sfizz_client_t* client, sfizz_receive_t* receive); + +/** + * @brief Send a message to the synth engine + * @since 0.6.0 + * + * @param synth The synth. + * @param client The client sending the message. + * @param delay The delay of the message in the block, in samples. + * @param path The OSC address pattern. + * @param sig The OSC type tag string. + * @param args The OSC arguments, whose number and format is determined the type tag string. + */ +SFIZZ_EXPORTED_API void sfizz_send_message(sfizz_synth_t* synth, sfizz_client_t* client, int delay, const char* path, const char* sig, const sfizz_arg_t* args); + +/** + * @brief Set the function which receives broadcast messages from the synth engine. + * @since 0.6.0 + * + * @param synth The synth. + * @param broadcast The pointer to the receiving function. + * @param data The opaque data pointer which is passed to the receiver. + */ +SFIZZ_EXPORTED_API void sfizz_set_broadcast_callback(sfizz_synth_t* synth, sfizz_receive_t* broadcast, void* data); + +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/src/sfizz.hpp b/src/sfizz.hpp index 81ba6cae..f86eea8a 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -10,6 +10,7 @@ */ #pragma once +#include "sfizz_message.h" #include #include #include @@ -28,6 +29,7 @@ namespace sfz { class Synth; +class Client; /** * @brief Main class. */ @@ -565,7 +567,75 @@ public: */ const std::vector>& getCCLabels() const noexcept; + /** + * @addtogroup Messaging + * @{ + */ + +private: + struct ClientDeleter { + void operator()(Client *client) const noexcept; + }; + +public: + using ClientPtr = std::unique_ptr; + + /** + * @brief Create a new messaging client + * @since 0.6.0 + * + * @param data The opaque data pointer which is passed to the receiver. + * @return The new client. + */ + static ClientPtr createClient(void* data); + + /** + * @brief Get the client data + * @since 0.6.0 + * + * @param client The client. + * @return The client data. + */ + static void* getClientData(Client& client); + + /** + * @brief Set the function which receives reply messages from the synth engine. + * @since 0.6.0 + * + * @param client The client. + * @param receive The pointer to the receiving function. + */ + static void setReceiveCallback(Client& client, sfizz_receive_t* receive); + + /** + * @brief Send a message to the synth engine + * @since 0.6.0 + * + * @param client The client sending the message. + * @param delay The delay of the message in the block, in samples. + * @param path The OSC address pattern. + * @param sig The OSC type tag string. + * @param args The OSC arguments, whose number and format is determined the type tag string. + */ + void sendMessage(Client& client, int delay, const char* path, const char* sig, const sfizz_arg_t* args); + + /** + * @brief Set the function which receives broadcast messages from the synth engine. + * @since 0.6.0 + * + * @param broadcast The pointer to the receiving function. + * @param data The opaque data pointer which is passed to the receiver. + */ + void setBroadcastCallback(sfizz_receive_t* broadcast, void* data); + + /** + * @} + */ + private: std::unique_ptr synth; }; + +using ClientPtr = Sfizz::ClientPtr; + } diff --git a/src/sfizz/Messaging.cpp b/src/sfizz/Messaging.cpp new file mode 100644 index 00000000..f8d1d731 --- /dev/null +++ b/src/sfizz/Messaging.cpp @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "Messaging.h" +#include +#include +#include +#include + +#ifdef __cplusplus +static_assert( + sizeof(sfizz_arg_t) == sizeof(int64_t) && alignof(sfizz_arg_t) == 8, + "The ABI stability check has failed."); +#endif + +template +static T paddingSize(T count, unsigned align) { + unsigned mask = align - 1; + return (align - (count & mask)) & mask; +}; + +/// +class OSCWriter { +public: + void setOutputBuffer(void* buffer, uint32_t capacity); + uint32_t writeMessage(const char* path, const char* sig, const sfizz_arg_t* args); + +private: + uint32_t appendBytes(const void* src, uint32_t count); + uint32_t appendZeros(uint32_t count); + template uint32_t appendInteger(T integer); + uint32_t appendFloat(float f); + uint32_t appendDouble(float d); + +private: + uint8_t* dstBuffer_ = nullptr; + uint32_t dstCapacity_ = 0; +}; + +class OSCReader { +public: + void setInputBuffer(const void* buffer, uint32_t capacity); + void setAllocationBuffer(void* buffer, uint32_t capacity); + int32_t extractMessage(const char** outPath, const char** outSig, const sfizz_arg_t** outArgs); + +private: + template T* allocate(uint32_t count); + bool extractString(const char*& outStr, uint32_t& outLen); + template bool extractInteger(T& outValue); + bool extractFloat(float& f); + bool extractDouble(double& d); + +private: + const uint8_t* srcBuffer_ = nullptr; + uint32_t srcCapacity_ = 0; + uint8_t* allocBuffer_ = nullptr; + uint32_t allocCapacity_ = 0; +}; + +/// +extern "C" uint32_t sfizz_prepare_message( + void* buffer, uint32_t capacity, + const char* path, const char* sig, const sfizz_arg_t* args) +{ + OSCWriter writer; + writer.setOutputBuffer(buffer, capacity); + return writer.writeMessage(path, sig, args); +} + +extern "C" int32_t sfizz_extract_message( + const void* srcBuffer, uint32_t srcCapacity, + void* argsBuffer, uint32_t argsCapacity, + const char** outPath, const char** outSig, const sfizz_arg_t** outArgs) +{ + OSCReader reader; + reader.setInputBuffer(srcBuffer, srcCapacity); + reader.setAllocationBuffer(argsBuffer, argsCapacity); + return reader.extractMessage(outPath, outSig, outArgs); +} + +/// +void OSCWriter::setOutputBuffer(void* buffer, uint32_t capacity) +{ + dstBuffer_ = reinterpret_cast(buffer); + dstCapacity_ = capacity; +} + +uint32_t OSCWriter::writeMessage(const char* path, const char* sig, const sfizz_arg_t* args) +{ + uint32_t msglen = 0; + + // write path, null byte, and 4byte padding + uint32_t pathlen = static_cast(strlen(path)); + msglen += appendBytes(path, pathlen + 1); + msglen += appendZeros(paddingSize(pathlen + 1, 4)); + + // write comma, signature, null byte, and 4byte padding + uint32_t siglen = static_cast(strlen(sig)); + msglen += appendBytes(",", 1); + msglen += appendBytes(sig, siglen + 1); + msglen += appendZeros(paddingSize(siglen + 2, 4)); + + // write arguments + for (uint32_t i = 0; i < siglen; ++i) { + switch (sig[i]) { + default: + return 0; + case 'i': + case 'c': + case 'r': + msglen += appendInteger(args[i].i); + break; + case 'm': + msglen += appendBytes(args[i].m, 4); + break; + case 'h': + msglen += appendInteger(args[i].h); + break; + case 'f': + msglen += appendFloat(args[i].f); + break; + case 'd': + msglen += appendDouble(args[i].d); + break; + case 's': + case 'S': + { + size_t len = strlen(args[i].s); + msglen += appendBytes(args[i].s, len + 1); + msglen += appendZeros(paddingSize(len + 1, 4)); + } + break; + case 'b': + { + msglen += appendInteger(args[i].b->size); + msglen += appendBytes(args[i].b->data, args[i].b->size); + msglen += appendZeros(paddingSize(args[i].b->size, 4)); + } + break; + case 'T': + case 'F': + case 'N': + case 'I': + break; + } + } + + return msglen; +} + +uint32_t OSCWriter::appendBytes(const void* src, uint32_t count) +{ + uint32_t written = std::min(dstCapacity_, count); + memcpy(dstBuffer_, src, written); + dstBuffer_ += written; + dstCapacity_ -= written; + return count; +} + +uint32_t OSCWriter::appendZeros(uint32_t count) +{ + uint32_t written = std::min(dstCapacity_, count); + memset(dstBuffer_, '\0', written); + dstBuffer_ += written; + dstCapacity_ -= written; + return count; +} + +template uint32_t OSCWriter::appendInteger(T integer) +{ + using U = typename std::make_unsigned::type; + const U uinteger = static_cast(integer); + uint8_t data[sizeof(U)]; + for (unsigned i = 0; i < sizeof(U); ++i) { + unsigned sh = 8 * (sizeof(U) - 1 - i); + data[i] = (uint8_t)((uinteger >> sh) & 0xff); + } + return appendBytes(data, sizeof(U)); +} + +uint32_t OSCWriter::appendFloat(float f) +{ + union { float f; uint32_t i; } u; + u.f = f; + return appendInteger(u.i); +} + +uint32_t OSCWriter::appendDouble(float d) +{ + union { double d; uint64_t i; } u; + u.d = d; + return appendInteger(u.i); +} + +/// +void OSCReader::setInputBuffer(const void* buffer, uint32_t capacity) +{ + srcBuffer_ = reinterpret_cast(buffer); + srcCapacity_ = capacity; +} + +void OSCReader::setAllocationBuffer(void* buffer, uint32_t capacity) +{ + allocBuffer_ = reinterpret_cast(buffer); + allocCapacity_ = capacity; +} + +int32_t OSCReader::extractMessage(const char** outPath, const char** outSig, const sfizz_arg_t** outArgs) +{ + const uint8_t* const srcStart = srcBuffer_; + + // read path, null byte + const char* path; + uint32_t pathlen; + if (!extractString(path, pathlen)) + return 0; + if (outPath) + *outPath = path; + + // read signature, null byte + const char* sig; + uint32_t siglen; + if (!extractString(sig, siglen) || sig[0] != ',') + return 0; + ++sig; + --siglen; + if (outSig) + *outSig = sig; + + // read arguments + sfizz_arg_t* args = allocate(siglen); + if (!args) + return -1; + if (outArgs) + *outArgs = args; + + for (uint32_t i = 0, n = siglen; i < n; ++i) { + switch (sig[i]) { + default: + return 0; + case 'i': + case 'c': + case 'r': + if (!extractInteger(args[i].i)) + return 0; + break; + case 'm': + if (srcCapacity_ < 4) + return 0; + memcpy(args[i].m, srcBuffer_, 4); + srcBuffer_ += 4; + srcCapacity_ -= 4; + break; + case 'h': + if (!extractInteger(args[i].h)) + return 0; + break; + case 'f': + if (!extractFloat(args[i].f)) + return 0; + break; + case 'd': + if (!extractDouble(args[i].d)) + return 0; + break; + case 's': + case 'S': + { + const char* str; + uint32_t len; + if (!extractString(str, len)) + return 0; + args[i].s = str; + } + break; + case 'b': + { + sfizz_blob_t* blob = allocate(1); + if (!blob) + return -1; + args[i].b = blob; + uint32_t len = blob->size; + if (!extractInteger(len)) + return 0; + uint32_t padlen = len + paddingSize(len, 4); + if (srcCapacity_ < padlen) + return 0; + blob->data = srcBuffer_; + blob->size = len; + srcBuffer_ += padlen; + srcCapacity_ -= padlen; + } + break; + case 'T': + case 'F': + case 'N': + case 'I': + break; + } + } + + return srcBuffer_ - srcStart; +} + +template T* OSCReader::allocate(uint32_t count) +{ + uintptr_t pad = paddingSize(reinterpret_cast(allocBuffer_), alignof(T)); + uint32_t size = count * sizeof(T); + if (allocCapacity_ < pad + size) + return nullptr; + void* ptr = allocBuffer_ + pad; + allocBuffer_ += pad + size; + allocCapacity_ -= pad + size; + return reinterpret_cast(ptr); +} + +bool OSCReader::extractString(const char*& outStr, uint32_t& outLen) +{ + const char* str = reinterpret_cast(srcBuffer_); + uint32_t len = static_cast(strnlen(str, srcCapacity_)); + if (len == srcCapacity_) + return false; + uint32_t padlen = len + 1 + paddingSize(len + 1, 4); + if (padlen > srcCapacity_) + return false; + srcBuffer_ += padlen; + srcCapacity_ -= padlen; + outStr = str; + outLen = len; + return true; +} + +template bool OSCReader::extractInteger(T& outValue) +{ + if (srcCapacity_ < sizeof(T)) + return false; + using U = typename std::make_unsigned::type; + U value = 0; + const uint8_t* src = reinterpret_cast(srcBuffer_); + for (unsigned i = 0; i < sizeof(T); ++i) + value = (value << 8) | src[i]; + srcBuffer_ += sizeof(T); + srcCapacity_ -= sizeof(T); + outValue = static_cast(value); + return true; +}; + +bool OSCReader::extractFloat(float& f) +{ + union { float f; uint32_t i; } u; + if (!extractInteger(u.i)) + return false; + f = u.f; + return true; +} + +bool OSCReader::extractDouble(double& d) +{ + union { double d; uint64_t i; } u; + if (!extractInteger(u.i)) + return false; + d = u.d; + return true; +} diff --git a/src/sfizz/Messaging.h b/src/sfizz/Messaging.h new file mode 100644 index 00000000..737fa1d4 --- /dev/null +++ b/src/sfizz/Messaging.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "sfizz_message.h" + +namespace sfz { + +class Client { +public: + explicit Client(void* data) : data_(data) {} + void* getClientData() const { return data_; } + void setReceiveCallback(sfizz_receive_t* receive) { receive_ = receive; } + bool canReceive() const { return receive_ != nullptr; } + void receive(int delay, const char* path, const char* sig, const sfizz_arg_t* args); + +private: + void* data_ = nullptr; + sfizz_receive_t* receive_ = nullptr; +}; + +inline void Client::receive(int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + if (receive_) + receive_(data_, delay, path, sig, args); +} + +} // namespace sfz diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 9f2bb846..66f19755 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -298,6 +298,10 @@ struct Synth::Impl final: public Parser::Listener { fs::file_time_type modificationTime_ { }; std::array defaultCCValues_; + + // Messaging + sfizz_receive_t* broadcastReceiver = nullptr; + void* broadcastData = nullptr; }; Synth::Synth() @@ -1953,6 +1957,13 @@ std::bitset Synth::getUsedCCs() const noexcept return used; } +void sfz::Synth::setBroadcastCallback(sfizz_receive_t* broadcast, void* data) +{ + Impl& impl = *impl_; + impl.broadcastReceiver = broadcast; + impl.broadcastData = data; +} + void Synth::Impl::updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region) { updateUsedCCsFromCCMap(usedCCs, region.offsetCC); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index dbfa21c5..1d971d80 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -8,6 +8,7 @@ #include "AudioSpan.h" #include "LeakDetector.h" #include "Resources.h" +#include "Messaging.h" #include "utility/NumericId.h" #include "parser/Parser.h" #include @@ -585,6 +586,27 @@ public: */ std::bitset getUsedCCs() const noexcept; + /** + * @brief Dispatch the incoming message to the synth engine + * @since 0.6.0 + * + * @param client The client sending the message. + * @param delay The delay of the message in the block, in samples. + * @param path The OSC address pattern. + * @param sig The OSC type tag string. + * @param args The OSC arguments, whose number and format is determined the type tag string. + */ + void dispatchMessage(Client& client, int delay, const char* path, const char* sig, const sfizz_arg_t* args); + + /** + * @brief Set the function which receives broadcast messages from the synth engine. + * @since 0.6.0 + * + * @param broadcast The pointer to the receiving function. + * @param data The opaque data pointer which is passed to the receiver. + */ + void setBroadcastCallback(sfizz_receive_t* broadcast, void* data); + private: struct Impl; std::unique_ptr impl_; diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp new file mode 100644 index 00000000..ed5c2bae --- /dev/null +++ b/src/sfizz/SynthMessaging.cpp @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "Synth.h" +#include "StringViewHelpers.h" +#include +#include + +namespace sfz { +static constexpr unsigned maxIndices = 8; + +static bool extractMessage(const char* pattern, const char* path, unsigned* indices); +static uint64_t hashMessagePath(const char* path, const char* sig); + +void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + unsigned indices[maxIndices]; + + switch (hashMessagePath(path, sig)) { + #define MATCH(p, s) case hash(p "," s): \ + if (extractMessage(p, path, indices) && !strcmp(sig, s)) + + MATCH("/hello", "") { + client.receive(delay, "/hello", "", nullptr); + break; + } + + // TODO... + } +} + +static bool extractMessage(const char* pattern, const char* path, unsigned* indices) +{ + unsigned nthIndex = 0; + + while (const char *endp = strchr(pattern, '&')) { + if (nthIndex == maxIndices) + return false; + + size_t length = endp - pattern; + if (strncmp(pattern, path, length)) + return false; + pattern += length; + path += length; + + length = 0; + while (absl::ascii_isdigit(path[length])) + ++length; + + if (!absl::SimpleAtoi(absl::string_view(path, length), &indices[nthIndex++])) + return false; + + pattern += 1; + path += length; + } + + return !strcmp(path, pattern); +} + +static uint64_t hashMessagePath(const char* path, const char* sig) +{ + uint64_t h = Fnv1aBasis; + while (unsigned char c = *path++) { + if (!absl::ascii_isdigit(c)) + h = hashByte(c, h); + else { + h = hashByte('&', h); + while (absl::ascii_isdigit(*path)) + ++path; + } + } + h = hashByte(','); + while (unsigned char c = *sig++) + h = hashByte(c, h); + return h; +} + +} // namespace sfz diff --git a/src/sfizz/sfizz.cpp b/src/sfizz/sfizz.cpp index 13cfd8a9..18b2a10c 100644 --- a/src/sfizz/sfizz.cpp +++ b/src/sfizz/sfizz.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Synth.h" +#include "Messaging.h" #include "sfizz.hpp" #include "absl/memory/memory.h" @@ -305,3 +306,33 @@ const std::vector>& sfz::Sfizz::getCCLabels() c { return synth->getCCLabels(); } + +void sfz::Sfizz::ClientDeleter::operator()(Client *client) const noexcept +{ + delete client; +} + +auto sfz::Sfizz::createClient(void* data) -> ClientPtr +{ + return ClientPtr(new Client(data)); +} + +void* sfz::Sfizz::getClientData(Client& client) +{ + return client.getClientData(); +} + +void sfz::Sfizz::setReceiveCallback(Client& client, sfizz_receive_t* receive) +{ + client.setReceiveCallback(receive); +} + +void sfz::Sfizz::sendMessage(Client& client, int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + synth->dispatchMessage(client, delay, path, sig, args); +} + +void sfz::Sfizz::setBroadcastCallback(sfizz_receive_t* broadcast, void* data) +{ + synth->setBroadcastCallback(broadcast, data); +} diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index 8dffaf6a..0ca6de29 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -7,6 +7,7 @@ #include "Config.h" #include "Macros.h" #include "Synth.h" +#include "Messaging.h" #include "sfizz.h" #include @@ -429,6 +430,38 @@ const char * sfizz_get_cc_label_text(sfizz_synth_t* synth, int label_index) return ccLabels[label_index].second.c_str(); } +sfizz_client_t* sfizz_create_client(void* data) +{ + return reinterpret_cast(new sfz::Client(data)); +} + +void sfizz_delete_client(sfizz_client_t* client) +{ + delete reinterpret_cast(client); +} + +void* sfizz_get_client_data(sfizz_client_t* client) +{ + return reinterpret_cast(client)->getClientData(); +} + +void sfizz_set_receive_callback(sfizz_client_t* client, sfizz_receive_t* receive) +{ + reinterpret_cast(client)->setReceiveCallback(receive); +} + +void sfizz_send_message(sfizz_synth_t* synth, sfizz_client_t* client, int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + auto* self = reinterpret_cast(synth); + self->dispatchMessage(*reinterpret_cast(client), delay, path, sig, args); +} + +void sfizz_set_broadcast_callback(sfizz_synth_t* synth, sfizz_receive_t* broadcast, void* data) +{ + auto* self = reinterpret_cast(synth); + self->setBroadcastCallback(broadcast, data); +} + #ifdef __cplusplus } #endif diff --git a/src/sfizz_message.h b/src/sfizz_message.h new file mode 100644 index 00000000..405fbb0f --- /dev/null +++ b/src/sfizz_message.h @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup Messaging + * @{ + */ + +/** + * @brief Representation of a binary blob in OSC format + * @since 0.6.0 + */ +typedef struct { + const uint8_t* data; + uint32_t size; +} sfizz_blob_t; + +/** + * @brief Representation of an argument of variant type in OSC format + * @since 0.6.0 + */ +typedef union { + int32_t i; + int64_t h; + float f; + double d; + const char* s; + const sfizz_blob_t* b; + uint8_t m[4]; +} sfizz_arg_t; + +/** + * @brief Generic message receiving function + * @since 0.6.0 + */ +typedef void (sfizz_receive_t)(void* data, int delay, const char* path, const char* sig, const sfizz_arg_t* args); + +/** + * @brief Convert the message to OSC using the provided output buffer + * @since 0.6.0 + * + * @param buffer The output buffer + * @param capacity The capacity of the buffer + * @param path The path + * @param sig The signature + * @param args The arguments + * @return The size necessary to store the converted message in + * entirety, <= capacity if the written message is valid. + */ +uint32_t sfizz_prepare_message( + void* buffer, uint32_t capacity, + const char* path, const char* sig, const sfizz_arg_t* args); + +/** + * @brief Extract the contents of an OSC message + * @since 0.6.0 + * + * @param srcBuffer The data of the OSC message + * @param srcCapacity The size of the OSC message + * @param argsBuffer A buffer where the function can allocate the arguments + * @param argsCapacity The capacity of the argument buffer + * @param outPath A pointer to the variable which receives the path + * @param outSig A pointer to the variable which receives the signature + * @param outArgs A pointer to the variable which receives the arguments + * @return On success, this is the number of bytes read. + * On failure, it is 0 if the OSC message is invalid, + * -1 if there was not enough buffer for the arguments. + */ +int32_t sfizz_extract_message( + const void* srcBuffer, uint32_t srcCapacity, + void* argsBuffer, uint32_t argsCapacity, + const char** outPath, const char** outSig, const sfizz_arg_t** outArgs); + +/** + * @} + */ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f6f25d9c..8e562df8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -41,6 +41,7 @@ set(SFIZZ_TEST_SOURCES ConcurrencyT.cpp ModulationsT.cpp LFOT.cpp + MessagingT.cpp DataHelpers.h DataHelpers.cpp ) diff --git a/tests/MessagingT.cpp b/tests/MessagingT.cpp new file mode 100644 index 00000000..e8a4938d --- /dev/null +++ b/tests/MessagingT.cpp @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "sfizz/Messaging.h" +#include "catch2/catch.hpp" +#include +#include + +TEST_CASE("[Messaging] OSC message creation") +{ + // http://opensoundcontrol.org/spec-1_0-examples + + { + const char* path = "/oscillator/4/frequency"; + const char* sig = "f"; + sfizz_arg_t args[1]; + args[0].f = 440.0f; + + const uint8_t expected[] = { + 0x2f, /* / */ 0x6f, /* o */ 0x73, /* s */ 0x63, /* c */ + 0x69, /* i */ 0x6c, /* l */ 0x6c, /* l */ 0x61, /* a */ + 0x74, /* t */ 0x6f, /* o */ 0x72, /* r */ 0x2f, /* / */ + 0x34, /* 4 */ 0x2f, /* / */ 0x66, /* f */ 0x72, /* r */ + 0x65, /* e */ 0x71, /* q */ 0x75, /* u */ 0x65, /* e */ + 0x6e, /* n */ 0x63, /* c */ 0x79, /* y */ 0x00, + 0x2c, /* , */ 0x66, /* f */ 0x00, 0x00, + 0x43, 0xdc, 0x00, 0x00, + }; + + uint32_t size = sfizz_prepare_message(nullptr, 0, path, sig, args); + REQUIRE(size == sizeof(expected)); + + uint8_t actual[sizeof(expected)]; + size = sfizz_prepare_message(actual, sizeof(actual), path, sig, args); + REQUIRE(size == sizeof(expected)); + REQUIRE(absl::MakeSpan(actual) == absl::MakeSpan(expected)); + + const char* path2; + const char* sig2; + const sfizz_arg_t* args2; + uint8_t buffer[256]; + REQUIRE(sfizz_extract_message(actual, sizeof(actual), buffer, sizeof(buffer), &path2, &sig2, &args2) > 0); + REQUIRE(!strcmp(path, path2)); + REQUIRE(!strcmp(sig, sig2)); + REQUIRE(args[0].f == 440.0f); + } + + { + const char* path = "/foo"; + const char* sig = "iisff"; + sfizz_arg_t args[5]; + args[0].i = 1000; + args[1].i = -1; + args[2].s = "hello"; + args[3].f = 1.234f; + args[4].f = 5.678f; + + const uint8_t expected[] = { + 0x2f, /* / */ 0x66, /* f */ 0x6f, /* o */ 0x6f, /* o */ + 0x00, 0x00, 0x00, 0x00, + 0x2c, /* , */ 0x69, /* i */ 0x69, /* i */ 0x73, /* s */ + 0x66, /* f */ 0x66, /* f */ 0x00, 0x00, + 0x00, 0x00, 0x03, 0xe8, + 0xff, 0xff, 0xff, 0xff, + 0x68, 0x65, 0x6c, 0x6c, + 0x6f, 0x00, 0x00, 0x00, + 0x3f, 0x9d, 0xf3, 0xb6, + 0x40, 0xb5, 0xb2, 0x2d, + }; + + uint32_t size = sfizz_prepare_message(nullptr, 0, path, sig, args); + REQUIRE(size == sizeof(expected)); + + uint8_t actual[sizeof(expected)]; + size = sfizz_prepare_message(actual, sizeof(actual), path, sig, args); + REQUIRE(size == sizeof(expected)); + REQUIRE(absl::MakeSpan(actual) == absl::MakeSpan(expected)); + + const char* path2; + const char* sig2; + const sfizz_arg_t* args2; + uint8_t buffer[256]; + REQUIRE(sfizz_extract_message(actual, sizeof(actual), buffer, sizeof(buffer), &path2, &sig2, &args2) > 0); + REQUIRE(!strcmp(path, path2)); + REQUIRE(!strcmp(sig, sig2)); + REQUIRE(args[0].i == 1000); + REQUIRE(args[1].i == -1); + REQUIRE(!strcmp(args[2].s, "hello")); + REQUIRE(args[3].f == 1.234f); + REQUIRE(args[4].f == 5.678f); + } +} diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 35eba7a0..970f3f1a 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -293,6 +293,24 @@ tresult SfizzVstController::notify(Vst::IMessage* message) _playState = *static_cast(data); } + else if (!strcmp(id, "ReceivedMessage")) { + const void* data = nullptr; + uint32 size = 0; + result = attr->getBinary("Message", data, size); + + if (result != kResultTrue) + return result; + + const char* path; + const char* sig; + const sfizz_arg_t* args; + uint8_t buffer[1024]; + + if (sfizz_extract_message(data, size, buffer, sizeof(buffer), &path, &sig, &args) > 0) { + for (MessageListener* listener : _messageListeners) + listener->onMessageReceived(path, sig, args); + } + } for (StateListener* listener : _stateListeners) listener->onStateChanged(); @@ -312,6 +330,18 @@ void SfizzVstController::removeSfizzStateListener(StateListener* listener) _stateListeners.erase(it); } +void SfizzVstController::addSfizzMessageListener(MessageListener* listener) +{ + _messageListeners.push_back(listener); +} + +void SfizzVstController::removeSfizzMessageListener(MessageListener* listener) +{ + auto it = std::find(_messageListeners.begin(), _messageListeners.end(), listener); + if (it != _messageListeners.end()) + _messageListeners.erase(it); +} + FUnknown* SfizzVstController::createInstance(void*) { return static_cast(new SfizzVstController); diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index bd363a2c..796d6628 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -9,6 +9,7 @@ #include "public.sdk/source/vst/vsteditcontroller.h" #include "public.sdk/source/vst/vstparameters.h" #include "vstgui/plugin-bindings/vst3editor.h" +#include class SfizzVstState; using namespace Steinberg; @@ -49,6 +50,9 @@ public: struct StateListener { virtual void onStateChanged() = 0; }; + struct MessageListener { + virtual void onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) = 0; + }; const SfizzVstState& getSfizzState() const { return _state; } SfizzVstState& getSfizzState() { return _state; } @@ -62,6 +66,9 @@ public: void addSfizzStateListener(StateListener* listener); void removeSfizzStateListener(StateListener* listener); + void addSfizzMessageListener(MessageListener* listener); + void removeSfizzMessageListener(MessageListener* listener); + /// static FUnknown* createInstance(void*); @@ -72,4 +79,5 @@ private: SfizzUiState _uiState; SfizzPlayState _playState {}; std::vector _stateListeners; + std::vector _messageListeners; }; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 9746cdf9..0f9bd231 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -16,15 +16,22 @@ using namespace VSTGUI; static ViewRect sfizzUiViewRect { 0, 0, Editor::viewWidth, Editor::viewHeight }; +enum { + kOscTempSize = 8192, +}; + SfizzVstEditor::SfizzVstEditor(void *controller) - : VSTGUIEditor(controller, &sfizzUiViewRect) + : VSTGUIEditor(controller, &sfizzUiViewRect), + oscTemp_(new uint8_t[kOscTempSize]) { getController()->addSfizzStateListener(this); + getController()->addSfizzMessageListener(this); } SfizzVstEditor::~SfizzVstEditor() { getController()->removeSfizzStateListener(this); + getController()->removeSfizzMessageListener(this); } bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& platformType) @@ -105,6 +112,11 @@ void SfizzVstEditor::onStateChanged() updateStateDisplay(); } +void SfizzVstEditor::onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) +{ + uiReceiveMessage(path, sig, args); +} + /// void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) { @@ -192,6 +204,26 @@ void SfizzVstEditor::uiSendMIDI(const uint8_t* data, uint32_t len) ctl->sendMessage(msg); } +void SfizzVstEditor::uiSendMessage(const char* path, const char* sig, const sfizz_arg_t* args) +{ + SfizzVstController* ctl = getController(); + + Steinberg::OPtr msg { ctl->allocateMessage() }; + if (!msg) { + fprintf(stderr, "[Sfizz] UI could not allocate message\n"); + return; + } + + uint8_t* oscTemp = oscTemp_.get(); + uint32_t oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args); + if (oscSize <= kOscTempSize) { + msg->setMessageID("OscMessage"); + Vst::IAttributeList* attr = msg->getAttributes(); + attr->setBinary("Data", oscTemp, oscSize); + ctl->sendMessage(msg); + } +} + /// void SfizzVstEditor::loadSfzFile(const std::string& filePath) { diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index a0730220..ad45f352 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -16,7 +16,10 @@ namespace VSTGUI { class RunLoop; } using namespace Steinberg; using namespace VSTGUI; -class SfizzVstEditor : public Vst::VSTGUIEditor, public SfizzVstController::StateListener, public EditorController { +class SfizzVstEditor : public Vst::VSTGUIEditor, + public SfizzVstController::StateListener, + public SfizzVstController::MessageListener, + public EditorController { public: explicit SfizzVstEditor(void *controller); ~SfizzVstEditor(); @@ -35,12 +38,16 @@ public: // SfizzVstController::StateListener void onStateChanged() override; + // SfizzVstController::MessageListener + void onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) override; + protected: // EditorController void uiSendValue(EditId id, const EditValue& v) override; void uiBeginSend(EditId id) override; void uiEndSend(EditId id) override; void uiSendMIDI(const uint8_t* data, uint32_t len) override; + void uiSendMessage(const char* path, const char* sig, const sfizz_arg_t* args) override; private: void loadSfzFile(const std::string& filePath); @@ -55,4 +62,7 @@ private: #if !defined(__APPLE__) && !defined(_WIN32) SharedPointer _runLoop; #endif + + // messaging + std::unique_ptr oscTemp_; }; diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 3825db65..93969467 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -24,10 +24,17 @@ static const char defaultSfzText[] = "sample=*sine" "\n" "ampeg_attack=0.02 ampeg_release=0.1" "\n"; -enum { kMidiEventMaximumSize = 4 }; +enum { + kMidiEventMaximumSize = 4, + kOscTempSize = 8192, +}; + +static const char* kRingIdMidi = "Mid"; +static const char* kRingIdOsc = "Osc"; SfizzVstProcessor::SfizzVstProcessor() - : _fifoToWorker(64 * 1024), _fifoMidiFromUi(64 * 1024) + : _fifoToWorker(64 * 1024), _fifoMessageFromUi(64 * 1024), + _oscTemp(new uint8_t[kOscTempSize]) { setControllerClass(SfizzVstController::cid); @@ -56,6 +63,16 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context) fprintf(stderr, "[sfizz] new synth\n"); _synth.reset(new sfz::Sfizz); + + auto onMessage = +[](void* data, int delay, const char* path, const char* sig, const sfizz_arg_t* args) + { + auto *self = reinterpret_cast(data); + self->receiveMessage(delay, path, sig, args); + }; + _client = _synth->createClient(this); + _synth->setReceiveCallback(*_client, onMessage); + _synth->setBroadcastCallback(onMessage, this); + _currentStretchedTuning = 0.0; loadSfzFileOrDefault(*_synth, {}); @@ -210,7 +227,7 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) else synth.disableFreeWheeling(); - processMidiFromUi(); + processMessagesFromUi(); if (Vst::IParameterChanges* pc = data.inputParameterChanges) processControllerChanges(*pc); @@ -404,36 +421,61 @@ void SfizzVstProcessor::processEvents(Vst::IEventList& events) } } -void SfizzVstProcessor::processMidiFromUi() +void SfizzVstProcessor::processMessagesFromUi() { sfz::Sfizz& synth = *_synth; + sfz::Client& client = *_client; + Ring_Buffer& fifo = _fifoMessageFromUi; + RTMessage header; - for (uint32 size = 0; _fifoMidiFromUi.peek(size) && - _fifoMidiFromUi.size_used() >= sizeof(size) + size; ) { - _fifoMidiFromUi.discard(sizeof(size)); + while (fifo.peek(header) && fifo.size_used() >= sizeof(header) + header.size) { + fifo.discard(sizeof(header)); - if (size > kMidiEventMaximumSize) { - _fifoMidiFromUi.discard(size); - continue; + if (header.type == kRingIdMidi) { + if (header.size > kMidiEventMaximumSize) { + fifo.discard(header.size); + continue; + } + + uint8_t data[kMidiEventMaximumSize] = {}; + fifo.get(data, header.size); + + // interpret the MIDI message + switch (data[0] & 0xf0) { + case 0x80: + synth.noteOff(0, data[1] & 0x7f, data[2] & 0x7f); + break; + case 0x90: + synth.noteOn(0, data[1] & 0x7f, data[2] & 0x7f); + break; + case 0xb0: + synth.cc(0, data[1] & 0x7f, data[2] & 0x7f); + break; + case 0xe0: + synth.pitchWheel(0, (data[2] << 7) + data[1] - 8192); + break; + } } + else if (header.type == kRingIdOsc) { + uint8_t* oscTemp = _oscTemp.get(); - uint8_t data[kMidiEventMaximumSize] = {}; - _fifoMidiFromUi.get(data, size); + if (header.size > kOscTempSize) { + fifo.discard(header.size); + continue; + } - // interpret the MIDI message - switch (data[0] & 0xf0) { - case 0x80: - synth.noteOff(0, data[1] & 0x7f, data[2] & 0x7f); - break; - case 0x90: - synth.noteOn(0, data[1] & 0x7f, data[2] & 0x7f); - break; - case 0xb0: - synth.cc(0, data[1] & 0x7f, data[2] & 0x7f); - break; - case 0xe0: - synth.pitchWheel(0, (data[2] << 7) + data[1] - 8192); - break; + fifo.get(oscTemp, header.size); + + const char* path; + const char* sig; + const sfizz_arg_t* args; + uint8_t buffer[1024]; + if (sfizz_extract_message(oscTemp, header.size, buffer, sizeof(buffer), &path, &sig, &args) > 0) + synth.sendMessage(client, 0, path, sig, args); + } + else { + assert(false); + return; } } } @@ -494,12 +536,14 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message) const void* data = nullptr; uint32 size = 0; result = attr->getBinary("Data", data, size); - if (size < kMidiEventMaximumSize) { - if (_fifoMidiFromUi.size_free() >= sizeof(size) + size) { - _fifoMidiFromUi.put(size); - _fifoMidiFromUi.put(reinterpret_cast(data), size); - } - } + if (size < kMidiEventMaximumSize) + writeMessage(_fifoMessageFromUi, kRingIdMidi, data, size); + } + else if (!std::strcmp(id, "OscMessage")) { + const void* data = nullptr; + uint32 size = 0; + result = attr->getBinary("Data", data, size); + writeMessage(_fifoMessageFromUi, kRingIdOsc, data, size); } return result; @@ -510,6 +554,14 @@ FUnknown* SfizzVstProcessor::createInstance(void*) return static_cast(new SfizzVstProcessor); } +void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + uint8_t* oscTemp = _oscTemp.get(); + uint32_t oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args); + if (oscSize <= kOscTempSize) + writeWorkerMessage("ReceiveMessage", oscTemp, oscSize); +} + void SfizzVstProcessor::loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath) { if (!filePath.empty()) @@ -563,6 +615,12 @@ void SfizzVstProcessor::doBackgroundWork() notification->getAttributes()->setBinary("PlayState", &playState, sizeof(playState)); sendMessage(notification); } + else if (!std::strcmp(id, "ReceiveMessage")) { + Steinberg::OPtr notification { allocateMessage() }; + notification->setMessageID("ReceivedMessage"); + notification->getAttributes()->setBinary("Message", msg->payload(), msg->size); + sendMessage(notification); + } } } @@ -585,16 +643,7 @@ void SfizzVstProcessor::stopBackgroundWork() bool SfizzVstProcessor::writeWorkerMessage(const char* type, const void* data, uintptr_t size) { - RTMessage header; - header.type = type; - header.size = size; - - if (_fifoToWorker.size_free() < sizeof(header) + size) - return false; - - _fifoToWorker.put(header); - _fifoToWorker.put(static_cast(data), size); - return true; + return writeMessage(_fifoToWorker, type, data, size); } SfizzVstProcessor::RTMessagePtr SfizzVstProcessor::readWorkerMessage() @@ -631,6 +680,20 @@ bool SfizzVstProcessor::discardWorkerMessage() return true; } +bool SfizzVstProcessor::writeMessage(Ring_Buffer& fifo, const char* type, const void* data, uintptr_t size) +{ + RTMessage header; + header.type = type; + header.size = size; + + if (fifo.size_free() < sizeof(header) + size) + return false; + + fifo.put(header); + fifo.put(static_cast(data), size); + return true; +} + /* Note(jpc) Generated at random with uuidgen. Can't find docs on it... maybe it's to register somewhere? diff --git a/vst/SfizzVstProcessor.h b/vst/SfizzVstProcessor.h index 7f388621..bbbf7490 100644 --- a/vst/SfizzVstProcessor.h +++ b/vst/SfizzVstProcessor.h @@ -35,7 +35,7 @@ public: void processParameterChanges(Vst::IParameterChanges& pc); void processControllerChanges(Vst::IParameterChanges& pc); void processEvents(Vst::IEventList& events); - void processMidiFromUi(); + void processMessagesFromUi(); static int convertVelocityFromFloat(float x); tresult PLUGIN_API notify(Vst::IMessage* message) override; @@ -51,6 +51,11 @@ private: SfizzVstState _state; float _currentStretchedTuning = 0; + // client + sfz::ClientPtr _client; + std::unique_ptr _oscTemp; + void receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args); + // misc static void loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath); @@ -59,7 +64,7 @@ private: volatile bool _workRunning = false; Ring_Buffer _fifoToWorker; RTSemaphore _semaToWorker; - Ring_Buffer _fifoMidiFromUi; + Ring_Buffer _fifoMessageFromUi; std::mutex _processMutex; // file modification periodic checker @@ -95,6 +100,9 @@ private: // reader RTMessagePtr readWorkerMessage(); bool discardWorkerMessage(); + + // generic + static bool writeMessage(Ring_Buffer& fifo, const char* type, const void* data, uintptr_t size); }; //------------------------------------------------------------------------------ From 406afc8aba9d58a0d76130080ba7566270e883a4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 2 Nov 2020 15:53:27 +0100 Subject: [PATCH 073/668] Fix some problems in the unit test --- tests/MessagingT.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/MessagingT.cpp b/tests/MessagingT.cpp index e8a4938d..2b52df56 100644 --- a/tests/MessagingT.cpp +++ b/tests/MessagingT.cpp @@ -45,7 +45,7 @@ TEST_CASE("[Messaging] OSC message creation") REQUIRE(sfizz_extract_message(actual, sizeof(actual), buffer, sizeof(buffer), &path2, &sig2, &args2) > 0); REQUIRE(!strcmp(path, path2)); REQUIRE(!strcmp(sig, sig2)); - REQUIRE(args[0].f == 440.0f); + REQUIRE(args2[0].f == 440.0f); } { @@ -86,10 +86,10 @@ TEST_CASE("[Messaging] OSC message creation") REQUIRE(sfizz_extract_message(actual, sizeof(actual), buffer, sizeof(buffer), &path2, &sig2, &args2) > 0); REQUIRE(!strcmp(path, path2)); REQUIRE(!strcmp(sig, sig2)); - REQUIRE(args[0].i == 1000); - REQUIRE(args[1].i == -1); - REQUIRE(!strcmp(args[2].s, "hello")); - REQUIRE(args[3].f == 1.234f); - REQUIRE(args[4].f == 5.678f); + REQUIRE(args2[0].i == 1000); + REQUIRE(args2[1].i == -1); + REQUIRE(!strcmp(args2[2].s, "hello")); + REQUIRE(args2[3].f == 1.234f); + REQUIRE(args2[4].f == 5.678f); } } From 92b01eecb25edf98d38316e37e77f53c806f0320 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 9 Nov 2020 08:22:01 +0100 Subject: [PATCH 074/668] Fix the hashing function for OSC dispatch --- src/sfizz/SynthMessaging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index ed5c2bae..aaeb56fd 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -72,7 +72,7 @@ static uint64_t hashMessagePath(const char* path, const char* sig) ++path; } } - h = hashByte(','); + h = hashByte(',', h); while (unsigned char c = *sig++) h = hashByte(c, h); return h; From bb5cd652f5348a37ef5df2641a5e27346509a669 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 8 Nov 2020 23:59:28 +0100 Subject: [PATCH 075/668] Move the Synth p-impl to the header file SynthPrivate --- src/CMakeLists.txt | 1 + src/sfizz/Synth.cpp | 272 +--------------------------------- src/sfizz/SynthMessaging.cpp | 2 +- src/sfizz/SynthPrivate.h | 277 +++++++++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+), 272 deletions(-) create mode 100644 src/sfizz/SynthPrivate.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f5ad3e7e..f8171541 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -107,6 +107,7 @@ set (SFIZZ_HEADERS sfizz/SwapAndPop.h sfizz/Synth.h sfizz/SynthConfig.h + sfizz/SynthPrivate.h sfizz/Tuning.h sfizz/Voice.h sfizz/VoiceManager.h diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 66f19755..d2788663 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -4,31 +4,23 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "Synth.h" +#include "SynthPrivate.h" #include "Config.h" #include "Debug.h" -#include "Effects.h" #include "Macros.h" #include "modulations/ModId.h" #include "modulations/ModKey.h" #include "modulations/ModMatrix.h" -#include "modulations/sources/ADSREnvelope.h" -#include "modulations/sources/Controller.h" -#include "modulations/sources/FlexEnvelope.h" -#include "modulations/sources/LFO.h" #include "PolyphonyGroup.h" #include "pugixml.hpp" #include "Region.h" #include "RegionSet.h" #include "Resources.h" #include "ScopedFTZ.h" -#include "SisterVoiceRing.h" #include "StringViewHelpers.h" -#include "TriggerEvent.h" #include "utility/SpinMutex.h" #include "utility/XmlHelpers.h" #include "Voice.h" -#include "VoiceManager.h" #include #include #include @@ -42,268 +34,6 @@ namespace sfz { -struct Synth::Impl final: public Parser::Listener { - Impl(); - ~Impl(); - - /** - * @brief The parser callback; this is called by the parent object each time - * a new region, group, master, global, curve or control set of opcodes - * appears in the parser - * - * @param header the header for the set of opcodes - * @param members the opcode members - */ - void onParseFullBlock(const std::string& header, const std::vector& members) final; - - /** - * @brief The parser callback when an error occurs. - */ - void onParseError(const SourceRange& range, const std::string& message) final; - - /** - * @brief The parser callback when a warning occurs. - */ - void onParseWarning(const SourceRange& range, const std::string& message) final; - - /** - * @brief Reset all CCs; to be used on CC 121 - * - * @param delay the delay for the controller reset - * - */ - void resetAllControllers(int delay) noexcept; - - /** - * @brief Remove all regions, resets all voices and clears everything - * to bring back the synth in its original state. - * - * The callback mutex should be taken to call this function. - */ - void clear(); - - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleGlobalOpcodes(const std::vector& members); - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleMasterOpcodes(const std::vector& members); - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleGroupOpcodes(const std::vector& members, const std::vector& masterMembers); - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleControlOpcodes(const std::vector& members); - /** - * @brief Helper function to dispatch opcodes - * - * @param members the opcodes of the block - */ - void handleEffectOpcodes(const std::vector& members); - /** - * @brief Helper function to merge all the currently active opcodes - * as set by the successive callbacks and create a new region to store - * in the synth. - * - * @param regionOpcodes the opcodes that are specific to the region - */ - void buildRegion(const std::vector& regionOpcodes); - /** - * @brief Resets and possibly changes the number of voices (polyphony) in - * the synth. - * - * @param numVoices - */ - void resetVoices(int numVoices); - /** - * @brief Make the stored settings take effect in all the voices - */ - void applySettingsPerVoice(); - - /** - * @brief Establish all connections of the modulation matrix. - */ - void setupModMatrix(); - - /** - * @brief Get the modification time of all included sfz files - * - * @return fs::file_time_type - */ - fs::file_time_type checkModificationTime(); - - /** - * @brief Check all regions and start voices for note on events - * - * @param delay - * @param noteNumber - * @param velocity - */ - void noteOnDispatch(int delay, int noteNumber, float velocity) noexcept; - - /** - * @brief Check all regions and start voices for note off events - * - * @param delay - * @param noteNumber - * @param velocity - */ - void noteOffDispatch(int delay, int noteNumber, float velocity) noexcept; - - /** - * @brief Check all regions and start voices for cc events - * - * @param delay - * @param ccNumber - * @param value - */ - void ccDispatch(int delay, int ccNumber, float value) noexcept; - - /** - * @brief Start a voice for a specific region. - * This will do the needed polyphony checks and voice stealing. - * - * @param region - * @param delay - * @param triggerEvent - * @param ring - */ - void startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept; - - /** - * @brief Start all delayed release voices of the region if necessary - * - * @param region - * @param delay - * @param ring - */ - void startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept; - - /** - * @brief Finalize SFZ loading, following a successful execution of the - * parsing step. - */ - void finalizeSfzLoad(); - - template - static void updateUsedCCsFromCCMap(std::bitset& usedCCs, const CCMap map) noexcept - { - for (auto& mod : map) - usedCCs[mod.cc] = true; - } - - static void updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); - static void updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); - - /** - * @brief Set the default value for a CC - * - * @param ccNumber - * @param value - */ - void setDefaultHdcc(int ccNumber, float value); - - int numGroups_ { 0 }; - int numMasters_ { 0 }; - - // Opcode memory; these are used to build regions, as a new region - // will integrate opcodes from the group, master and global block - std::vector globalOpcodes_; - std::vector masterOpcodes_; - std::vector groupOpcodes_; - - // Names for the CC and notes as set by label_cc and label_key - std::vector ccLabels_; - std::vector keyLabels_; - std::vector keyswitchLabels_; - - // Set as sw_default if present in the file - absl::optional currentSwitch_; - std::vector unknownOpcodes_; - using RegionViewVector = std::vector; - using VoiceViewVector = std::vector; - using RegionPtr = std::unique_ptr; - using RegionSetPtr = std::unique_ptr; - std::vector regions_; - VoiceManager voiceManager_; - - // These are more general "groups" than sfz and encapsulates the full hierarchy - RegionSet* currentSet_ { nullptr }; - std::vector sets_; - - std::array lastKeyswitchLists_; - std::array downKeyswitchLists_; - std::array upKeyswitchLists_; - RegionViewVector previousKeyswitchLists_; - std::array noteActivationLists_; - std::array ccActivationLists_; - - // Effect factory and buses - EffectFactory effectFactory_; - typedef std::unique_ptr EffectBusPtr; - std::vector effectBuses_; // 0 is "main", 1-N are "fx1"-"fxN" - - int samplesPerBlock_ { config::defaultSamplesPerBlock }; - float sampleRate_ { config::defaultSampleRate }; - float volume_ { Default::globalVolume }; - int numVoices_ { config::numVoices }; - Oversampling oversamplingFactor_ { config::defaultOversamplingFactor }; - - // Distribution used to generate random value for the *rand opcodes - std::uniform_real_distribution randNoteDistribution_ { 0, 1 }; - - SpinMutex callbackGuard_; - - // Singletons passed as references to the voices - Resources resources_; - - // Control opcodes - std::string defaultPath_ { "" }; - int noteOffset_ { 0 }; - int octaveOffset_ { 0 }; - - // Modulation source generators - std::unique_ptr genController_; - std::unique_ptr genLFO_; - std::unique_ptr genFlexEnvelope_; - std::unique_ptr genADSREnvelope_; - - // Settings per voice - struct { - size_t maxFilters { 0 }; - size_t maxEQs { 0 }; - size_t maxLFOs { 0 }; - size_t maxFlexEGs { 0 }; - bool havePitchEG { false }; - bool haveFilterEG { false }; - } settingsPerVoice_; - - Duration dispatchDuration_ { 0 }; - - std::chrono::time_point lastGarbageCollection_; - - Parser parser_; - fs::file_time_type modificationTime_ { }; - - std::array defaultCCValues_; - - // Messaging - sfizz_receive_t* broadcastReceiver = nullptr; - void* broadcastData = nullptr; -}; - Synth::Synth() : impl_(new Impl) // NOLINT: (paul) I don't get why clang-tidy complains here { diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index aaeb56fd..9aef0213 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -4,7 +4,7 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "Synth.h" +#include "SynthPrivate.h" #include "StringViewHelpers.h" #include #include diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h new file mode 100644 index 00000000..f65a9ae8 --- /dev/null +++ b/src/sfizz/SynthPrivate.h @@ -0,0 +1,277 @@ +#pragma once + +#include "Synth.h" +#include "Effects.h" +#include "SisterVoiceRing.h" +#include "TriggerEvent.h" +#include "VoiceManager.h" +#include "modulations/sources/ADSREnvelope.h" +#include "modulations/sources/Controller.h" +#include "modulations/sources/FlexEnvelope.h" +#include "modulations/sources/LFO.h" + +namespace sfz { + +struct Synth::Impl final: public Parser::Listener { + Impl(); + ~Impl(); + + /** + * @brief The parser callback; this is called by the parent object each time + * a new region, group, master, global, curve or control set of opcodes + * appears in the parser + * + * @param header the header for the set of opcodes + * @param members the opcode members + */ + void onParseFullBlock(const std::string& header, const std::vector& members) final; + + /** + * @brief The parser callback when an error occurs. + */ + void onParseError(const SourceRange& range, const std::string& message) final; + + /** + * @brief The parser callback when a warning occurs. + */ + void onParseWarning(const SourceRange& range, const std::string& message) final; + + /** + * @brief Reset all CCs; to be used on CC 121 + * + * @param delay the delay for the controller reset + * + */ + void resetAllControllers(int delay) noexcept; + + /** + * @brief Remove all regions, resets all voices and clears everything + * to bring back the synth in its original state. + * + * The callback mutex should be taken to call this function. + */ + void clear(); + + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleGlobalOpcodes(const std::vector& members); + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleMasterOpcodes(const std::vector& members); + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleGroupOpcodes(const std::vector& members, const std::vector& masterMembers); + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleControlOpcodes(const std::vector& members); + /** + * @brief Helper function to dispatch opcodes + * + * @param members the opcodes of the block + */ + void handleEffectOpcodes(const std::vector& members); + /** + * @brief Helper function to merge all the currently active opcodes + * as set by the successive callbacks and create a new region to store + * in the synth. + * + * @param regionOpcodes the opcodes that are specific to the region + */ + void buildRegion(const std::vector& regionOpcodes); + /** + * @brief Resets and possibly changes the number of voices (polyphony) in + * the synth. + * + * @param numVoices + */ + void resetVoices(int numVoices); + /** + * @brief Make the stored settings take effect in all the voices + */ + void applySettingsPerVoice(); + + /** + * @brief Establish all connections of the modulation matrix. + */ + void setupModMatrix(); + + /** + * @brief Get the modification time of all included sfz files + * + * @return fs::file_time_type + */ + fs::file_time_type checkModificationTime(); + + /** + * @brief Check all regions and start voices for note on events + * + * @param delay + * @param noteNumber + * @param velocity + */ + void noteOnDispatch(int delay, int noteNumber, float velocity) noexcept; + + /** + * @brief Check all regions and start voices for note off events + * + * @param delay + * @param noteNumber + * @param velocity + */ + void noteOffDispatch(int delay, int noteNumber, float velocity) noexcept; + + /** + * @brief Check all regions and start voices for cc events + * + * @param delay + * @param ccNumber + * @param value + */ + void ccDispatch(int delay, int ccNumber, float value) noexcept; + + /** + * @brief Start a voice for a specific region. + * This will do the needed polyphony checks and voice stealing. + * + * @param region + * @param delay + * @param triggerEvent + * @param ring + */ + void startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept; + + /** + * @brief Start all delayed release voices of the region if necessary + * + * @param region + * @param delay + * @param ring + */ + void startDelayedReleaseVoices(Region* region, int delay, SisterVoiceRingBuilder& ring) noexcept; + + /** + * @brief Finalize SFZ loading, following a successful execution of the + * parsing step. + */ + void finalizeSfzLoad(); + + template + static void updateUsedCCsFromCCMap(std::bitset& usedCCs, const CCMap map) noexcept + { + for (auto& mod : map) + usedCCs[mod.cc] = true; + } + + static void updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); + static void updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); + + /** + * @brief Set the default value for a CC + * + * @param ccNumber + * @param value + */ + void setDefaultHdcc(int ccNumber, float value); + + int numGroups_ { 0 }; + int numMasters_ { 0 }; + + // Opcode memory; these are used to build regions, as a new region + // will integrate opcodes from the group, master and global block + std::vector globalOpcodes_; + std::vector masterOpcodes_; + std::vector groupOpcodes_; + + // Names for the CC and notes as set by label_cc and label_key + std::vector ccLabels_; + std::vector keyLabels_; + std::vector keyswitchLabels_; + + // Set as sw_default if present in the file + absl::optional currentSwitch_; + std::vector unknownOpcodes_; + using RegionViewVector = std::vector; + using VoiceViewVector = std::vector; + using RegionPtr = std::unique_ptr; + using RegionSetPtr = std::unique_ptr; + std::vector regions_; + VoiceManager voiceManager_; + + // These are more general "groups" than sfz and encapsulates the full hierarchy + RegionSet* currentSet_ { nullptr }; + std::vector sets_; + + std::array lastKeyswitchLists_; + std::array downKeyswitchLists_; + std::array upKeyswitchLists_; + RegionViewVector previousKeyswitchLists_; + std::array noteActivationLists_; + std::array ccActivationLists_; + + // Effect factory and buses + EffectFactory effectFactory_; + typedef std::unique_ptr EffectBusPtr; + std::vector effectBuses_; // 0 is "main", 1-N are "fx1"-"fxN" + + int samplesPerBlock_ { config::defaultSamplesPerBlock }; + float sampleRate_ { config::defaultSampleRate }; + float volume_ { Default::globalVolume }; + int numVoices_ { config::numVoices }; + Oversampling oversamplingFactor_ { config::defaultOversamplingFactor }; + + // Distribution used to generate random value for the *rand opcodes + std::uniform_real_distribution randNoteDistribution_ { 0, 1 }; + + SpinMutex callbackGuard_; + + // Singletons passed as references to the voices + Resources resources_; + + // Control opcodes + std::string defaultPath_ { "" }; + int noteOffset_ { 0 }; + int octaveOffset_ { 0 }; + + // Modulation source generators + std::unique_ptr genController_; + std::unique_ptr genLFO_; + std::unique_ptr genFlexEnvelope_; + std::unique_ptr genADSREnvelope_; + + // Settings per voice + struct { + size_t maxFilters { 0 }; + size_t maxEQs { 0 }; + size_t maxLFOs { 0 }; + size_t maxFlexEGs { 0 }; + bool havePitchEG { false }; + bool haveFilterEG { false }; + } settingsPerVoice_; + + Duration dispatchDuration_ { 0 }; + + std::chrono::time_point lastGarbageCollection_; + + Parser parser_; + fs::file_time_type modificationTime_ { }; + + std::array defaultCCValues_; + + // Messaging + sfizz_receive_t* broadcastReceiver = nullptr; + void* broadcastData = nullptr; +}; + +} // namespace sfz From e1c607e28a3294de914c593e3de81eeef12c6bff Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 9 Nov 2020 14:04:45 +0100 Subject: [PATCH 076/668] Type-safe OSC message sending --- src/CMakeLists.txt | 1 + src/sfizz/Messaging.h | 20 +++++++---- src/sfizz/Messaging.hpp | 76 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/sfizz/Messaging.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8171541..6e68d803 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -219,6 +219,7 @@ target_link_libraries (sfizz_parser PUBLIC absl::strings PRIVATE absl::flat_hash # OSC messaging library set (SFIZZ_MESSAGING_HEADERS sfizz/Messaging.h + sfizz/Messaging.hpp sfizz_message.h) set (SFIZZ_MESSAGING_SOURCES diff --git a/src/sfizz/Messaging.h b/src/sfizz/Messaging.h index 737fa1d4..ab76237f 100644 --- a/src/sfizz/Messaging.h +++ b/src/sfizz/Messaging.h @@ -6,9 +6,14 @@ #pragma once #include "sfizz_message.h" +#include namespace sfz { +template struct OscDataTraits; +template using OscType = typename OscDataTraits::type; +template using OscDecayedType = typename std::decay>::type; + class Client { public: explicit Client(void* data) : data_(data) {} @@ -17,15 +22,18 @@ public: bool canReceive() const { return receive_ != nullptr; } void receive(int delay, const char* path, const char* sig, const sfizz_arg_t* args); + template + void receive(int delay, const char* path, OscDecayedType... values); + +private: + template + sfizz_arg_t make_arg(OscDecayedType value); + private: void* data_ = nullptr; sfizz_receive_t* receive_ = nullptr; }; -inline void Client::receive(int delay, const char* path, const char* sig, const sfizz_arg_t* args) -{ - if (receive_) - receive_(data_, delay, path, sig, args); -} - } // namespace sfz + +#include "Messaging.hpp" diff --git a/src/sfizz/Messaging.hpp b/src/sfizz/Messaging.hpp new file mode 100644 index 00000000..cabd30b6 --- /dev/null +++ b/src/sfizz/Messaging.hpp @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "Messaging.h" +#include +#include + +namespace sfz { + +/// +inline void Client::receive(int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + if (receive_) + receive_(data_, delay, path, sig, args); +} + +template +inline void Client::receive(int delay, const char* path, OscDecayedType... values) +{ + constexpr size_t size = sizeof...(Sig); + char sig[size + 1] { Sig..., '\0' }; + sfizz_arg_t args[size] { OscDataTraits::make_arg(values)... }; + receive(delay, path, sig, args); +} + +/// +#define OSC_SCALAR_TRAITS(tag, member) \ + template <> struct OscDataTraits { \ + typedef decltype(sfizz_arg_t::member) type; \ + static_assert(std::is_scalar::value, ""); \ + static inline sfizz_arg_t make_arg(type v) { \ + sfizz_arg_t a; a.member = v; return a; \ + } \ + } +#define OSC_BYTEARRAY_TRAITS(tag, member) \ + template <> struct OscDataTraits { \ + typedef decltype(sfizz_arg_t::member) type; \ + static_assert(std::is_array::value, ""); \ + static inline sfizz_arg_t make_arg(type v) { \ + sfizz_arg_t a; \ + std::memcpy(a.member, v, sizeof(a.member)); \ + return a; \ + } \ + } +#define OSC_VOID_TRAITS(tag) \ + template <> struct OscDataTraits { \ + typedef struct Nothing {} type; \ + static inline sfizz_arg_t make_arg(type v) { \ + sfizz_arg_t a; (void)v; return a; \ + } \ + } + +OSC_SCALAR_TRAITS('i', i); +OSC_SCALAR_TRAITS('c', i); +OSC_SCALAR_TRAITS('r', i); +OSC_BYTEARRAY_TRAITS('m', m); +OSC_SCALAR_TRAITS('h', h); +OSC_SCALAR_TRAITS('f', f); +OSC_SCALAR_TRAITS('d', d); +OSC_SCALAR_TRAITS('s', s); +OSC_SCALAR_TRAITS('S', s); +OSC_SCALAR_TRAITS('b', b); +OSC_VOID_TRAITS('T'); +OSC_VOID_TRAITS('F'); +OSC_VOID_TRAITS('N'); +OSC_VOID_TRAITS('I'); + +#undef OSC_SCALAR_TRAITS +#undef OSC_BYTEARRAY_TRAITS +#undef OSC_VOID_TRAITS + +} // namespace sfz From 9b044a4eb93eeca064fffcd3f202f36b7e2b1f3f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 9 Nov 2020 14:13:54 +0100 Subject: [PATCH 077/668] Skip message processing if no callback --- src/sfizz/Messaging.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sfizz/Messaging.hpp b/src/sfizz/Messaging.hpp index cabd30b6..e5df7537 100644 --- a/src/sfizz/Messaging.hpp +++ b/src/sfizz/Messaging.hpp @@ -21,10 +21,12 @@ inline void Client::receive(int delay, const char* path, const char* sig, const template inline void Client::receive(int delay, const char* path, OscDecayedType... values) { - constexpr size_t size = sizeof...(Sig); - char sig[size + 1] { Sig..., '\0' }; - sfizz_arg_t args[size] { OscDataTraits::make_arg(values)... }; - receive(delay, path, sig, args); + if (receive_) { + constexpr size_t size = sizeof...(Sig); + char sig[size + 1] { Sig..., '\0' }; + sfizz_arg_t args[size] { OscDataTraits::make_arg(values)... }; + receive_(data_, delay, path, sig, args); + } } /// From 425889c94957a19eff4eddd1b84f246a871d8acf Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 9 Nov 2020 14:43:25 +0100 Subject: [PATCH 078/668] Add test --- src/sfizz/Messaging.h | 3 +-- src/sfizz/Messaging.hpp | 48 ++++++++++++++++++++++------------------- tests/MessagingT.cpp | 30 ++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/sfizz/Messaging.h b/src/sfizz/Messaging.h index ab76237f..0f48587b 100644 --- a/src/sfizz/Messaging.h +++ b/src/sfizz/Messaging.h @@ -6,13 +6,12 @@ #pragma once #include "sfizz_message.h" -#include namespace sfz { template struct OscDataTraits; template using OscType = typename OscDataTraits::type; -template using OscDecayedType = typename std::decay>::type; +template using OscDecayedType = typename OscDataTraits::decayed_type; class Client { public: diff --git a/src/sfizz/Messaging.hpp b/src/sfizz/Messaging.hpp index e5df7537..587e671d 100644 --- a/src/sfizz/Messaging.hpp +++ b/src/sfizz/Messaging.hpp @@ -6,6 +6,7 @@ #pragma once #include "Messaging.h" +#include #include #include @@ -30,30 +31,33 @@ inline void Client::receive(int delay, const char* path, OscDecayedType... } /// -#define OSC_SCALAR_TRAITS(tag, member) \ - template <> struct OscDataTraits { \ - typedef decltype(sfizz_arg_t::member) type; \ - static_assert(std::is_scalar::value, ""); \ - static inline sfizz_arg_t make_arg(type v) { \ - sfizz_arg_t a; a.member = v; return a; \ - } \ +#define OSC_SCALAR_TRAITS(tag, member) \ + template <> struct OscDataTraits { \ + typedef decltype(sfizz_arg_t::member) type; \ + typedef type decayed_type; \ + static_assert(std::is_scalar::value, ""); \ + static inline sfizz_arg_t make_arg(decayed_type v) { \ + sfizz_arg_t a; a.member = v; return a; \ + } \ } -#define OSC_BYTEARRAY_TRAITS(tag, member) \ - template <> struct OscDataTraits { \ - typedef decltype(sfizz_arg_t::member) type; \ - static_assert(std::is_array::value, ""); \ - static inline sfizz_arg_t make_arg(type v) { \ - sfizz_arg_t a; \ - std::memcpy(a.member, v, sizeof(a.member)); \ - return a; \ - } \ +#define OSC_BYTEARRAY_TRAITS(tag, member) \ + template <> struct OscDataTraits { \ + typedef decltype(sfizz_arg_t::member) type; \ + static_assert(std::is_array::value, ""); \ + typedef const typename std::remove_all_extents::type* decayed_type; \ + static inline sfizz_arg_t make_arg(decayed_type v) { \ + sfizz_arg_t a; \ + std::memcpy(a.member, v, sizeof(a.member)); \ + return a; \ + } \ } -#define OSC_VOID_TRAITS(tag) \ - template <> struct OscDataTraits { \ - typedef struct Nothing {} type; \ - static inline sfizz_arg_t make_arg(type v) { \ - sfizz_arg_t a; (void)v; return a; \ - } \ +#define OSC_VOID_TRAITS(tag) \ + template <> struct OscDataTraits { \ + typedef struct Nothing {} type; \ + typedef type decayed_type; \ + static inline sfizz_arg_t make_arg(decayed_type v) { \ + sfizz_arg_t a; (void)v; return a; \ + } \ } OSC_SCALAR_TRAITS('i', i); diff --git a/tests/MessagingT.cpp b/tests/MessagingT.cpp index 2b52df56..5496ca82 100644 --- a/tests/MessagingT.cpp +++ b/tests/MessagingT.cpp @@ -93,3 +93,33 @@ TEST_CASE("[Messaging] OSC message creation") REQUIRE(args2[4].f == 5.678f); } } + +TEST_CASE("[Messaging] Type-safe client API") +{ + sfz::Client client(nullptr); + + static const int32_t i = 777; + static const int64_t h = 0x100000000LL; + static const float f = 3.14f; + static const double d = 6.28; + static const uint8_t m[4] = {0x90, 0x40, 0xFF}; + static const sfizz_blob_t b { reinterpret_cast("MyBinaryString"), 14 }; + static const char s[] = "Hello, World!"; + + client.setReceiveCallback(+[](void*, int, const char* path, const char* sig, const sfizz_arg_t* args) { + REQUIRE(!strcmp(path, "/test")); + REQUIRE(!strcmp(sig, "imhfdsbTFNI")); + unsigned index = 0; + REQUIRE(args[index++].i == i); + REQUIRE(!memcmp(args[index++].m, m, 4)); + REQUIRE(args[index++].h == h); + REQUIRE(args[index++].f == f); + REQUIRE(args[index++].d == d); + REQUIRE(!strcmp(args[index++].s, s)); + REQUIRE(args[index ].b->data == b.data); + REQUIRE(args[index++].b->size == b.size); + }); + + client.receive<'i', 'm', 'h', 'f', 'd', 's', 'b', 'T', 'F', 'N', 'I'>( + 0, "/test", i, m, h, f, d, s, &b, {}, {}, {}, {}); +} From e02a30f56cb2c81d7ba6a9fd4823475b927686f3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 11 Nov 2020 14:04:06 +0100 Subject: [PATCH 079/668] Rename some internal functions related to used CCs --- src/sfizz/Synth.cpp | 62 ++++++++++++++++++++-------------------- src/sfizz/SynthPrivate.h | 6 ++-- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index d2788663..cefacad2 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -683,7 +683,7 @@ void Synth::Impl::finalizeSfzLoad() std::bitset usedCCs; for (const RegionPtr& regionPtr : regions_) { const Region& region = *regionPtr; - updateUsedCCsFromRegion(usedCCs, region); + collectUsedCCsFromRegion(usedCCs, region); for (const Region::Connection& connection : region.connections) { if (connection.source.id() == ModId::Controller) usedCCs.set(connection.source.parameters().cc); @@ -1682,8 +1682,8 @@ std::bitset Synth::getUsedCCs() const noexcept Impl& impl = *impl_; std::bitset used; for (const Impl::RegionPtr& region : impl.regions_) - impl.updateUsedCCsFromRegion(used, *region); - impl.updateUsedCCsFromModulations(used, impl.resources_.modMatrix); + impl.collectUsedCCsFromRegion(used, *region); + impl.collectUsedCCsFromModulations(used, impl.resources_.modMatrix); return used; } @@ -1694,41 +1694,41 @@ void sfz::Synth::setBroadcastCallback(sfizz_receive_t* broadcast, void* data) impl.broadcastData = data; } -void Synth::Impl::updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region) +void Synth::Impl::collectUsedCCsFromRegion(std::bitset& usedCCs, const Region& region) { - updateUsedCCsFromCCMap(usedCCs, region.offsetCC); - updateUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccAttack); - updateUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccRelease); - updateUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccDecay); - updateUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccDelay); - updateUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccHold); - updateUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccStart); - updateUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccSustain); + collectUsedCCsFromCCMap(usedCCs, region.offsetCC); + collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccAttack); + collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccRelease); + collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccDecay); + collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccDelay); + collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccHold); + collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccStart); + collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccSustain); if (region.pitchEG) { - updateUsedCCsFromCCMap(usedCCs, region.pitchEG->ccAttack); - updateUsedCCsFromCCMap(usedCCs, region.pitchEG->ccRelease); - updateUsedCCsFromCCMap(usedCCs, region.pitchEG->ccDecay); - updateUsedCCsFromCCMap(usedCCs, region.pitchEG->ccDelay); - updateUsedCCsFromCCMap(usedCCs, region.pitchEG->ccHold); - updateUsedCCsFromCCMap(usedCCs, region.pitchEG->ccStart); - updateUsedCCsFromCCMap(usedCCs, region.pitchEG->ccSustain); + collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccAttack); + collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccRelease); + collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccDecay); + collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccDelay); + collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccHold); + collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccStart); + collectUsedCCsFromCCMap(usedCCs, region.pitchEG->ccSustain); } if (region.filterEG) { - updateUsedCCsFromCCMap(usedCCs, region.filterEG->ccAttack); - updateUsedCCsFromCCMap(usedCCs, region.filterEG->ccRelease); - updateUsedCCsFromCCMap(usedCCs, region.filterEG->ccDecay); - updateUsedCCsFromCCMap(usedCCs, region.filterEG->ccDelay); - updateUsedCCsFromCCMap(usedCCs, region.filterEG->ccHold); - updateUsedCCsFromCCMap(usedCCs, region.filterEG->ccStart); - updateUsedCCsFromCCMap(usedCCs, region.filterEG->ccSustain); + collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccAttack); + collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccRelease); + collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccDecay); + collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccDelay); + collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccHold); + collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccStart); + collectUsedCCsFromCCMap(usedCCs, region.filterEG->ccSustain); } - updateUsedCCsFromCCMap(usedCCs, region.ccConditions); - updateUsedCCsFromCCMap(usedCCs, region.ccTriggers); - updateUsedCCsFromCCMap(usedCCs, region.crossfadeCCInRange); - updateUsedCCsFromCCMap(usedCCs, region.crossfadeCCOutRange); + collectUsedCCsFromCCMap(usedCCs, region.ccConditions); + collectUsedCCsFromCCMap(usedCCs, region.ccTriggers); + collectUsedCCsFromCCMap(usedCCs, region.crossfadeCCInRange); + collectUsedCCsFromCCMap(usedCCs, region.crossfadeCCOutRange); } -void Synth::Impl::updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm) +void Synth::Impl::collectUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm) { class CCSourceCollector : public ModMatrix::KeyVisitor { public: diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index f65a9ae8..3c9569af 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -168,14 +168,14 @@ struct Synth::Impl final: public Parser::Listener { void finalizeSfzLoad(); template - static void updateUsedCCsFromCCMap(std::bitset& usedCCs, const CCMap map) noexcept + static void collectUsedCCsFromCCMap(std::bitset& usedCCs, const CCMap map) noexcept { for (auto& mod : map) usedCCs[mod.cc] = true; } - static void updateUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); - static void updateUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); + static void collectUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); + static void collectUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); /** * @brief Set the default value for a CC From d74bcd140f110004d1d184f2e8b6ef4401c8cd23 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 11 Nov 2020 14:17:26 +0100 Subject: [PATCH 080/668] Cache the set of used CCs for quick access --- src/sfizz/Synth.cpp | 20 ++++++++++++++------ src/sfizz/Synth.h | 2 +- src/sfizz/SynthPrivate.h | 3 +++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index cefacad2..3ea3236f 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -722,6 +722,9 @@ void Synth::Impl::finalizeSfzLoad() applySettingsPerVoice(); setupModMatrix(); + + // cache the set of used CCs for future access + currentUsedCCs_ = collectAllUsedCCs(); } bool Synth::loadScalaFile(const fs::path& path) @@ -1677,14 +1680,10 @@ void Synth::allSoundOff() noexcept effectBus->clear(); } -std::bitset Synth::getUsedCCs() const noexcept +const std::bitset& Synth::getUsedCCs() const noexcept { Impl& impl = *impl_; - std::bitset used; - for (const Impl::RegionPtr& region : impl.regions_) - impl.collectUsedCCsFromRegion(used, *region); - impl.collectUsedCCsFromModulations(used, impl.resources_.modMatrix); - return used; + return impl.currentUsedCCs_; } void sfz::Synth::setBroadcastCallback(sfizz_receive_t* broadcast, void* data) @@ -1750,6 +1749,15 @@ void Synth::Impl::collectUsedCCsFromModulations(std::bitset& use mm.visitSources(vtor); } +std::bitset Synth::Impl::collectAllUsedCCs() +{ + std::bitset used; + for (const Impl::RegionPtr& region : regions_) + collectUsedCCsFromRegion(used, *region); + collectUsedCCsFromModulations(used, resources_.modMatrix); + return used; +} + Parser& Synth::getParser() noexcept { Impl& impl = *impl_; diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 1d971d80..0e53b17e 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -584,7 +584,7 @@ public: * * @return const std::bitset& */ - std::bitset getUsedCCs() const noexcept; + const std::bitset& getUsedCCs() const noexcept; /** * @brief Dispatch the incoming message to the synth engine diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 3c9569af..5daf775b 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -177,6 +177,8 @@ struct Synth::Impl final: public Parser::Listener { static void collectUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); static void collectUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); + std::bitset collectAllUsedCCs(); + /** * @brief Set the default value for a CC * @@ -268,6 +270,7 @@ struct Synth::Impl final: public Parser::Listener { fs::file_time_type modificationTime_ { }; std::array defaultCCValues_; + std::bitset currentUsedCCs_; // Messaging sfizz_receive_t* broadcastReceiver = nullptr; From 95d3343341db5e16d390decccb3a4aa8c949c847 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 12 Nov 2020 08:04:55 +0100 Subject: [PATCH 081/668] Add API to process CC events received by automation --- src/sfizz.h | 17 ++++++++++++++ src/sfizz.hpp | 15 +++++++++++++ src/sfizz/Synth.cpp | 45 ++++++++++++++++++++++++------------- src/sfizz/Synth.h | 9 ++++++++ src/sfizz/SynthPrivate.h | 10 +++++++++ src/sfizz/sfizz.cpp | 5 +++++ src/sfizz/sfizz_wrapper.cpp | 5 +++++ 7 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/sfizz.h b/src/sfizz.h index b20e7eae..b2e74c62 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -321,6 +321,23 @@ SFIZZ_EXPORTED_API void sfizz_send_cc(sfizz_synth_t* synth, int delay, int cc_nu */ SFIZZ_EXPORTED_API void sfizz_send_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_value); +/** + * @brief Send a high precision CC automation to the synth. + * + * This updates the CC value known to the synth, but without performing + * additional MIDI-specific interpretations. (eg. the CC 120 and up) + * + * As with all MIDI events, this needs to happen before the call to + * sfizz_render_block() in each block and should appear in order of the delays. + * @since 0.6.0 + * + * @param synth The synth. + * @param delay The delay of the event in the block, in samples. + * @param cc_number The MIDI CC number. + * @param norm_value The normalized CC value, in domain 0 to 1. + */ +SFIZZ_EXPORTED_API void sfizz_automate_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_value); + /** * @brief Send a pitch wheel event. * diff --git a/src/sfizz.hpp b/src/sfizz.hpp index f86eea8a..426795e4 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -296,6 +296,21 @@ public: */ void hdcc(int delay, int ccNumber, float normValue) noexcept; + /** + * @brief Send a high precision CC automation to the synth + * + * This updates the CC value known to the synth, but without performing + * additional MIDI-specific interpretations. (eg. the CC 120 and up) + * + * @since 0.6.0 + * + * @param delay the delay at which the event occurs; this should be lower + * than the size of the block in the next call to renderBlock(). + * @param ccNumber the cc number. + * @param normValue the normalized cc value, in domain 0 to 1. + */ + void automateHdcc(int delay, int ccNumber, float normValue) noexcept; + /** * @brief Send a pitch bend event to the synth * @since 0.2.0 diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 3ea3236f..79651e4e 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -1090,34 +1090,47 @@ void Synth::Impl::ccDispatch(int delay, int ccNumber, float value) noexcept } void Synth::hdcc(int delay, int ccNumber, float normValue) noexcept +{ + Impl& impl = *impl_; + impl.performHdcc(delay, ccNumber, normValue, true); +} + +void Synth::automateHdcc(int delay, int ccNumber, float normValue) noexcept +{ + Impl& impl = *impl_; + impl.performHdcc(delay, ccNumber, normValue, false); +} + +void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asMidi) noexcept { ASSERT(ccNumber < config::numCCs); ASSERT(ccNumber >= 0); - Impl& impl = *impl_; - ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; - impl.resources_.midiState.ccEvent(delay, ccNumber, normValue); + ScopedTiming logger { dispatchDuration_, ScopedTiming::Operation::addToDuration }; + resources_.midiState.ccEvent(delay, ccNumber, normValue); - const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; + const std::unique_lock lock { callbackGuard_, std::try_to_lock }; if (!lock.owns_lock()) return; - if (ccNumber == config::resetCC) { - impl.resetAllControllers(delay); - return; + if (asMidi) { + if (ccNumber == config::resetCC) { + resetAllControllers(delay); + return; + } + + if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) { + for (auto& voice : voiceManager_) + voice.reset(); + resources_.midiState.allNotesOff(delay); + return; + } } - if (ccNumber == config::allNotesOffCC || ccNumber == config::allSoundOffCC) { - for (auto& voice : impl.voiceManager_) - voice.reset(); - impl.resources_.midiState.allNotesOff(delay); - return; - } - - for (auto& voice : impl.voiceManager_) + for (auto& voice : voiceManager_) voice.registerCC(delay, ccNumber, normValue); - impl.ccDispatch(delay, ccNumber, normValue); + ccDispatch(delay, ccNumber, normValue); } void Synth::Impl::setDefaultHdcc(int ccNumber, float value) diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 0e53b17e..b95f193f 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -342,6 +342,15 @@ public: * @param normValue the normalized cc value, in domain 0 to 1 */ void hdcc(int delay, int ccNumber, float normValue) noexcept; + /** + * @brief Send a high precision CC automation to the synth + * + * @param delay the delay at which the event occurs; this should be lower + * than the size of the block in the next call to renderBlock(). + * @param ccNumber the cc number. + * @param normValue the normalized cc value, in domain 0 to 1. + */ + void automateHdcc(int delay, int ccNumber, float normValue) noexcept; /** * @brief Get the current value of a controller under the current instrument * diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 5daf775b..bcc48e24 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -179,6 +179,16 @@ struct Synth::Impl final: public Parser::Listener { std::bitset collectAllUsedCCs(); + /** + * @brief Perform a CC event + * + * @param delay The delay + * @param ccNumber The CC number + * @param normValue The normalized value + * @param asMidi Whether to process as a MIDI event + */ + void performHdcc(int delay, int ccNumber, float normValue, bool asMidi) noexcept; + /** * @brief Set the default value for a CC * diff --git a/src/sfizz/sfizz.cpp b/src/sfizz/sfizz.cpp index 18b2a10c..a8cc7e7c 100644 --- a/src/sfizz/sfizz.cpp +++ b/src/sfizz/sfizz.cpp @@ -144,6 +144,11 @@ void sfz::Sfizz::hdcc(int delay, int ccNumber, float normValue) noexcept synth->hdcc(delay, ccNumber, normValue); } +void sfz::Sfizz::automateHdcc(int delay, int ccNumber, float normValue) noexcept +{ + synth->automateHdcc(delay, ccNumber, normValue); +} + void sfz::Sfizz::pitchWheel(int delay, int pitch) noexcept { synth->pitchWheel(delay, pitch); diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index 0ca6de29..f4d1866c 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -146,6 +146,11 @@ void sfizz_send_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_ auto* self = reinterpret_cast(synth); self->hdcc(delay, cc_number, norm_value); } +void sfizz_automate_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_value) +{ + auto* self = reinterpret_cast(synth); + self->automateHdcc(delay, cc_number, norm_value); +} void sfizz_send_pitch_wheel(sfizz_synth_t* synth, int delay, int pitch) { auto* self = reinterpret_cast(synth); From aa29e1a4110b80b0731ddfbd64627355d112ad58 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 12 Nov 2020 08:17:19 +0100 Subject: [PATCH 082/668] Add test --- tests/SynthT.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index d1cd9156..5565d5ff 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -1394,3 +1394,32 @@ TEST_CASE("[Synth] Default ampeg_release") REQUIRE(synth.getRegionView(0)->amplitudeEG.release > 0.0005f); } + +TEST_CASE("[Synth] Send CC vs. Automate CC") +{ + { + sfz::Synth synth; + + synth.loadSfzString(fs::current_path() / "send_cc.sfz", R"( + sample=*sine + )"); + + synth.noteOn(0, 60, 100); + synth.hdcc(1, 120, 0.0f); + + REQUIRE(synth.getNumActiveVoices() == 0); + } + + { + sfz::Synth synth; + + synth.loadSfzString(fs::current_path() / "automate_cc.sfz", R"( + sample=*sine + )"); + + synth.noteOn(0, 60, 100); + synth.automateHdcc(1, 120, 0.0f); + + REQUIRE(synth.getNumActiveVoices() == 1); + } +} From dcc7ac04721cec4204da64cc723a700a102a52d5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 12 Nov 2020 10:24:29 +0100 Subject: [PATCH 083/668] Add new alias: bendstep --- src/sfizz/OpcodeCleanup.cpp | 1293 ++++++++++++++++++----------------- src/sfizz/OpcodeCleanup.re | 2 +- tests/OpcodeT.cpp | 1 + 3 files changed, 656 insertions(+), 640 deletions(-) diff --git a/src/sfizz/OpcodeCleanup.cpp b/src/sfizz/OpcodeCleanup.cpp index 459ce514..d61d8933 100644 --- a/src/sfizz/OpcodeCleanup.cpp +++ b/src/sfizz/OpcodeCleanup.cpp @@ -1,4 +1,4 @@ -/* Generated by re2c 2.0.3 on Mon Sep 28 14:07:14 2020 */ +/* Generated by re2c 2.0.3 on Thu Nov 12 10:20:58 2020 */ #line 1 "src/sfizz/OpcodeCleanup.re" /* -*- mode: c++; -*- */ // SPDX-License-Identifier: BSD-2-Clause @@ -583,15 +583,18 @@ yy70: case 'd': yyt1 = YYCURSOR; goto yy93; - case 'u': + case 's': yyt1 = YYCURSOR; goto yy94; + case 'u': + yyt1 = YYCURSOR; + goto yy95; default: goto yy34; } yy71: yych = *++YYCURSOR; switch (yych) { - case 'f': goto yy95; + case 'f': goto yy96; default: goto yy34; } yy72: @@ -599,10 +602,10 @@ yy72: switch (yych) { case 'c': yyt2 = YYCURSOR; - goto yy96; + goto yy97; case 'r': yyt2 = YYCURSOR; - goto yy97; + goto yy98; default: goto yy34; } yy73: @@ -610,13 +613,13 @@ yy73: switch (yych) { case 'b': yyt2 = YYCURSOR; - goto yy98; + goto yy99; case 'f': yyt2 = YYCURSOR; - goto yy99; + goto yy100; case 'g': yyt2 = YYCURSOR; - goto yy100; + goto yy101; default: goto yy34; } yy74: @@ -632,17 +635,17 @@ yy74: case '7': case '8': case '9': goto yy74; - case 't': goto yy101; + case 't': goto yy102; default: goto yy34; } yy76: yych = *++YYCURSOR; yyt1 = YYCURSOR; - goto yy105; + goto yy106; yy77: yych = *++YYCURSOR; switch (yych) { - case 'y': goto yy106; + case 'y': goto yy107; default: goto yy34; } yy78: @@ -650,16 +653,16 @@ yy78: switch (yych) { case 0x00: yyt2 = yyt3 = NULL; - goto yy107; + goto yy108; case '_': yyt3 = YYCURSOR; - goto yy109; + goto yy110; default: goto yy34; } yy79: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy110; + case 'a': goto yy111; default: goto yy34; } yy80: @@ -675,7 +678,7 @@ yy80: case '7': case '8': case '9': goto yy80; - case '_': goto yy111; + case '_': goto yy112; default: goto yy34; } yy82: @@ -683,37 +686,37 @@ yy82: switch (yych) { case 'e': yyt1 = YYCURSOR; - goto yy112; + goto yy113; case 'm': yyt1 = YYCURSOR; - goto yy113; + goto yy114; case 's': yyt1 = YYCURSOR; - goto yy114; + goto yy115; default: goto yy34; } yy83: yych = *++YYCURSOR; switch (yych) { - case 'y': goto yy115; + case 'y': goto yy116; default: goto yy34; } yy84: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy116; + case 'o': goto yy117; default: goto yy34; } yy85: yych = *++YYCURSOR; switch (yych) { - case 'i': goto yy117; + case 'i': goto yy118; default: goto yy34; } yy86: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy117; + case 'o': goto yy118; default: goto yy34; } yy87: @@ -725,13 +728,13 @@ yy87: yy88: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy118; + case 'p': goto yy119; default: goto yy34; } yy89: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy119; + case 'n': goto yy120; default: goto yy34; } yy90: @@ -739,79 +742,85 @@ yy90: switch (yych) { case 0x00: yyt2 = yyt3 = NULL; - goto yy120; + goto yy121; case '_': yyt3 = YYCURSOR; - goto yy122; + goto yy123; default: goto yy34; } yy91: yych = *++YYCURSOR; switch (yych) { - case '_': goto yy124; + case '_': goto yy125; default: goto yy34; } yy92: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy125; + case 'o': goto yy126; default: goto yy34; } yy93: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy126; + case 'o': goto yy127; default: goto yy34; } yy94: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy127; + case 't': goto yy128; default: goto yy34; } yy95: yych = *++YYCURSOR; switch (yych) { - case 'f': goto yy128; + case 'p': goto yy129; default: goto yy34; } yy96: yych = *++YYCURSOR; switch (yych) { - case 'u': goto yy129; + case 'f': goto yy130; default: goto yy34; } yy97: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy130; + case 'u': goto yy131; default: goto yy34; } yy98: yych = *++YYCURSOR; switch (yych) { - case 'w': goto yy131; + case 'e': goto yy132; default: goto yy34; } yy99: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy132; + case 'w': goto yy133; default: goto yy34; } yy100: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy133; + case 'r': goto yy134; default: goto yy34; } yy101: yych = *++YYCURSOR; switch (yych) { - case 'y': goto yy134; + case 'a': goto yy135; default: goto yy34; } yy102: + yych = *++YYCURSOR; + switch (yych) { + case 'y': goto yy136; + default: goto yy34; + } +yy103: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; @@ -823,19 +832,19 @@ yy102: opcode = absl::StrCat("fil1_", group(1)); goto end_region; } -#line 827 "src/sfizz/OpcodeCleanup.cpp" -yy104: - yych = *++YYCURSOR; +#line 836 "src/sfizz/OpcodeCleanup.cpp" yy105: - if (yych <= 0x00) goto yy102; - goto yy104; + yych = *++YYCURSOR; yy106: + if (yych <= 0x00) goto yy103; + goto yy105; +yy107: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy135; + case 'p': goto yy137; default: goto yy34; } -yy107: +yy108: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; @@ -847,87 +856,87 @@ yy107: opcode = absl::StrCat("volume", group(1)); goto end_region; } -#line 851 "src/sfizz/OpcodeCleanup.cpp" -yy109: - yych = *++YYCURSOR; - switch (yych) { - case 'r': goto yy138; - default: goto yy137; - } +#line 860 "src/sfizz/OpcodeCleanup.cpp" yy110: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy139; - default: goto yy34; + case 'r': goto yy140; + default: goto yy139; } yy111: yych = *++YYCURSOR; switch (yych) { - case 'c': - yyt2 = YYCURSOR; - goto yy140; - case 'o': - yyt2 = YYCURSOR; - goto yy141; - case 'r': - yyt2 = YYCURSOR; - goto yy142; - case 's': - yyt2 = YYCURSOR; - goto yy143; - case 'w': - yyt2 = YYCURSOR; - goto yy144; + case 'l': goto yy141; default: goto yy34; } yy112: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy145; + case 'c': + yyt2 = YYCURSOR; + goto yy142; + case 'o': + yyt2 = YYCURSOR; + goto yy143; + case 'r': + yyt2 = YYCURSOR; + goto yy144; + case 's': + yyt2 = YYCURSOR; + goto yy145; + case 'w': + yyt2 = YYCURSOR; + goto yy146; default: goto yy34; } yy113: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy146; + case 'n': goto yy147; default: goto yy34; } yy114: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy147; + case 'o': goto yy148; default: goto yy34; } yy115: - yych = *++YYCURSOR; - if (yych <= 0x00) goto yy148; - goto yy34; -yy116: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy150; + case 't': goto yy149; default: goto yy34; } +yy116: + yych = *++YYCURSOR; + if (yych <= 0x00) goto yy150; + goto yy34; yy117: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy151; - case 'h': goto yy152; + case 'd': goto yy152; default: goto yy34; } yy118: yych = *++YYCURSOR; switch (yych) { - case 'h': goto yy153; + case 'c': goto yy153; + case 'h': goto yy154; default: goto yy34; } yy119: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy154; + case 'h': goto yy155; default: goto yy34; } yy120: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy156; + default: goto yy34; + } +yy121: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; @@ -939,56 +948,62 @@ yy120: opcode = absl::StrCat("pitch", group(1)); goto end_region; } -#line 943 "src/sfizz/OpcodeCleanup.cpp" -yy122: +#line 952 "src/sfizz/OpcodeCleanup.cpp" +yy123: yych = *++YYCURSOR; if (yych <= 0x00) { yyt2 = YYCURSOR; - goto yy120; + goto yy121; } - goto yy122; -yy124: + goto yy123; +yy125: yych = *++YYCURSOR; switch (yych) { case 'a': yyt2 = YYCURSOR; - goto yy155; + goto yy157; case 'd': yyt2 = YYCURSOR; - goto yy156; + goto yy158; case 'h': yyt2 = YYCURSOR; - goto yy157; + goto yy159; case 'r': yyt2 = YYCURSOR; - goto yy158; + goto yy160; case 's': yyt2 = YYCURSOR; - goto yy159; - default: goto yy34; - } -yy125: - yych = *++YYCURSOR; - switch (yych) { - case '_': goto yy160; + goto yy161; default: goto yy34; } yy126: yych = *++YYCURSOR; switch (yych) { - case 'w': goto yy161; + case '_': goto yy162; default: goto yy34; } yy127: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy162; - goto yy34; + switch (yych) { + case 'w': goto yy163; + default: goto yy34; + } yy128: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy95; + default: goto yy34; + } +yy129: + yych = *++YYCURSOR; + if (yych <= 0x00) goto yy164; + goto yy34; +yy130: yych = *++YYCURSOR; switch (yych) { case 0x00: yyt2 = yyt3 = NULL; - goto yy164; + goto yy166; case '0': case '1': case '2': @@ -1000,125 +1015,125 @@ yy128: case '8': case '9': yyt2 = YYCURSOR; - goto yy166; + goto yy168; case '_': yyt2 = yyt4 = NULL; yyt3 = YYCURSOR; - goto yy168; - default: goto yy34; - } -yy129: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy169; - default: goto yy34; - } -yy130: - yych = *++YYCURSOR; - switch (yych) { - case 's': goto yy170; + goto yy170; default: goto yy34; } yy131: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy171; + case 't': goto yy171; default: goto yy34; } yy132: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy172; + case 's': goto yy172; default: goto yy34; } yy133: yych = *++YYCURSOR; switch (yych) { - case 'i': goto yy173; + case 'c': goto yy173; default: goto yy34; } yy134: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy174; + case 'e': goto yy174; default: goto yy34; } yy135: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy175; + case 'i': goto yy175; default: goto yy34; } yy136: yych = *++YYCURSOR; -yy137: - if (yych <= 0x00) { - yyt2 = YYCURSOR; - goto yy107; - } - goto yy136; -yy138: - yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy176; - default: goto yy137; - } -yy139: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy177; + case 'p': goto yy176; default: goto yy34; } +yy137: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy177; + default: goto yy34; + } +yy138: + yych = *++YYCURSOR; +yy139: + if (yych <= 0x00) { + yyt2 = YYCURSOR; + goto yy108; + } + goto yy138; yy140: yych = *++YYCURSOR; switch (yych) { - case 'u': goto yy178; - default: goto yy34; + case 'a': goto yy178; + default: goto yy139; } yy141: yych = *++YYCURSOR; switch (yych) { - case 'f': goto yy179; + case 'c': goto yy179; default: goto yy34; } yy142: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy180; - case 'e': goto yy181; + case 'u': goto yy180; default: goto yy34; } yy143: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy182; + case 'f': goto yy181; default: goto yy34; } yy144: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy183; + case 'a': goto yy182; + case 'e': goto yy183; default: goto yy34; } yy145: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy184; + case 'c': goto yy184; default: goto yy34; } yy146: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy185; + case 'a': goto yy185; default: goto yy34; } yy147: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy186; + case 'd': goto yy186; default: goto yy34; } yy148: + yych = *++YYCURSOR; + switch (yych) { + case 'd': goto yy187; + default: goto yy34; + } +yy149: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy188; + default: goto yy34; + } +yy150: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; @@ -1130,53 +1145,41 @@ yy148: opcode = absl::StrCat("off_", group(1)); goto end_region; } -#line 1134 "src/sfizz/OpcodeCleanup.cpp" -yy150: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy115; - default: goto yy34; - } -yy151: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy187; - default: goto yy34; - } +#line 1149 "src/sfizz/OpcodeCleanup.cpp" yy152: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy188; + case 'e': goto yy116; default: goto yy34; } yy153: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy189; + case 'c': goto yy189; default: goto yy34; } yy154: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy190; + case 'd': goto yy190; default: goto yy34; } yy155: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy191; + case 'o': goto yy191; default: goto yy34; } yy156: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy192; + case 'n': goto yy192; default: goto yy34; } yy157: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy193; + case 't': goto yy193; default: goto yy34; } yy158: @@ -1188,28 +1191,40 @@ yy158: yy159: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy195; - case 'u': goto yy196; + case 'o': goto yy195; default: goto yy34; } yy160: yych = *++YYCURSOR; switch (yych) { - case 'd': - yyt2 = YYCURSOR; - goto yy197; - case 'f': - yyt2 = YYCURSOR; - goto yy198; + case 'e': goto yy196; default: goto yy34; } yy161: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy127; + case 't': goto yy197; + case 'u': goto yy198; default: goto yy34; } yy162: + yych = *++YYCURSOR; + switch (yych) { + case 'd': + yyt2 = YYCURSOR; + goto yy199; + case 'f': + yyt2 = YYCURSOR; + goto yy200; + default: goto yy34; + } +yy163: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy129; + default: goto yy34; + } +yy164: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; @@ -1221,8 +1236,8 @@ yy162: opcode = absl::StrCat("bend_", group(1)); goto end_region; } -#line 1225 "src/sfizz/OpcodeCleanup.cpp" -yy164: +#line 1240 "src/sfizz/OpcodeCleanup.cpp" +yy166: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; @@ -1234,8 +1249,8 @@ yy164: opcode = absl::StrCat("cutoff1", group(1)); goto end_region; } -#line 1238 "src/sfizz/OpcodeCleanup.cpp" -yy166: +#line 1253 "src/sfizz/OpcodeCleanup.cpp" +yy168: yych = *++YYCURSOR; switch (yych) { case '0': @@ -1247,80 +1262,68 @@ yy166: case '6': case '7': case '8': - case '9': goto yy166; + case '9': goto yy168; case '_': yyt4 = YYCURSOR; - goto yy199; - default: goto yy34; - } -yy168: - yych = *++YYCURSOR; - switch (yych) { - case 'r': goto yy202; - default: goto yy201; - } -yy169: - yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy203; + goto yy201; default: goto yy34; } yy170: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy204; - default: goto yy34; + case 'r': goto yy204; + default: goto yy203; } yy171: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy205; + case 'o': goto yy205; default: goto yy34; } yy172: yych = *++YYCURSOR; switch (yych) { - case 'q': goto yy131; + case 'o': goto yy206; default: goto yy34; } yy173: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy131; + case 'c': goto yy207; default: goto yy34; } yy174: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy206; + case 'q': goto yy133; default: goto yy34; } yy175: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy207; - goto yy34; + switch (yych) { + case 'n': goto yy133; + default: goto yy34; + } yy176: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy209; - default: goto yy137; + case 'e': goto yy208; + default: goto yy34; } yy177: yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy210; - default: goto yy34; - } + if (yych <= 0x00) goto yy209; + goto yy34; yy178: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy211; - default: goto yy34; + case 'n': goto yy211; + default: goto yy139; } yy179: yych = *++YYCURSOR; switch (yych) { - case 'f': goto yy212; + case 'c': goto yy212; default: goto yy34; } yy180: @@ -1332,38 +1335,50 @@ yy180: yy181: yych = *++YYCURSOR; switch (yych) { - case 's': goto yy214; + case 'f': goto yy214; default: goto yy34; } yy182: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy215; + case 't': goto yy215; default: goto yy34; } yy183: yych = *++YYCURSOR; switch (yych) { - case 'v': goto yy216; + case 's': goto yy216; default: goto yy34; } yy184: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy217; - goto yy34; + switch (yych) { + case 'a': goto yy217; + default: goto yy34; + } yy185: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy184; + case 'v': goto yy218; default: goto yy34; } yy186: + yych = *++YYCURSOR; + if (yych <= 0x00) goto yy219; + goto yy34; +yy187: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy219; + case 'e': goto yy186; default: goto yy34; } -yy187: +yy188: + yych = *++YYCURSOR; + switch (yych) { + case 'r': goto yy221; + default: goto yy34; + } +yy189: yych = *++YYCURSOR; switch (yych) { case '0': @@ -1377,19 +1392,7 @@ yy187: case '8': case '9': yyt1 = YYCURSOR; - goto yy220; - default: goto yy34; - } -yy188: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy222; - default: goto yy34; - } -yy189: - yych = *++YYCURSOR; - switch (yych) { - case 'n': goto yy223; + goto yy222; default: goto yy34; } yy190: @@ -1401,86 +1404,98 @@ yy190: yy191: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy225; + case 'n': goto yy225; default: goto yy34; } yy192: yych = *++YYCURSOR; switch (yych) { - case 'c': - case 'l': goto yy226; + case 'c': goto yy226; default: goto yy34; } yy193: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy227; + case 't': goto yy227; default: goto yy34; } yy194: yych = *++YYCURSOR; switch (yych) { + case 'c': case 'l': goto yy228; default: goto yy34; } yy195: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy229; + case 'l': goto yy229; default: goto yy34; } yy196: yych = *++YYCURSOR; switch (yych) { - case 's': goto yy230; + case 'l': goto yy230; default: goto yy34; } yy197: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy231; + case 'a': goto yy231; default: goto yy34; } yy198: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy232; - case 'r': goto yy233; + case 's': goto yy232; default: goto yy34; } yy199: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy234; + case 'e': goto yy233; default: goto yy34; } yy200: yych = *++YYCURSOR; -yy201: - if (yych <= 0x00) { - yyt2 = YYCURSOR; - goto yy164; - } - goto yy200; -yy202: - yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy235; - default: goto yy201; - } -yy203: - yych = *++YYCURSOR; - switch (yych) { - case 'f': goto yy236; + case 'a': goto yy234; + case 'r': goto yy235; default: goto yy34; } +yy201: + yych = *++YYCURSOR; + switch (yych) { + case 'r': goto yy236; + default: goto yy34; + } +yy202: + yych = *++YYCURSOR; +yy203: + if (yych <= 0x00) { + yyt2 = YYCURSOR; + goto yy166; + } + goto yy202; yy204: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy237; - default: goto yy34; + case 'a': goto yy237; + default: goto yy203; } yy205: + yych = *++YYCURSOR; + switch (yych) { + case 'f': goto yy238; + default: goto yy34; + } +yy206: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy239; + default: goto yy34; + } +yy207: yych = *++YYCURSOR; switch (yych) { case '0': @@ -1494,14 +1509,14 @@ yy205: case '8': case '9': yyt3 = YYCURSOR; - goto yy238; + goto yy240; default: goto yy34; } -yy206: +yy208: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy240; + if (yych <= 0x00) goto yy242; goto yy34; -yy207: +yy209: ++YYCURSOR; yynmatch = 1; yypmatch[0] = YYCURSOR - 8; @@ -1511,14 +1526,14 @@ yy207: opcode = absl::StrCat("fil1_type"); goto end_region; } -#line 1515 "src/sfizz/OpcodeCleanup.cpp" -yy209: +#line 1530 "src/sfizz/OpcodeCleanup.cpp" +yy211: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy242; - default: goto yy137; + case 'd': goto yy244; + default: goto yy139; } -yy210: +yy212: yych = *++YYCURSOR; switch (yych) { case '0': @@ -1532,46 +1547,46 @@ yy210: case '8': case '9': yyt1 = YYCURSOR; - goto yy243; - default: goto yy34; - } -yy211: - yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy245; - default: goto yy34; - } -yy212: - yych = *++YYCURSOR; - switch (yych) { - case 's': goto yy246; + goto yy245; default: goto yy34; } yy213: yych = *++YYCURSOR; switch (yych) { - case 'i': goto yy247; + case 'o': goto yy247; default: goto yy34; } yy214: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy248; + case 's': goto yy248; default: goto yy34; } yy215: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy216; + case 'i': goto yy249; default: goto yy34; } yy216: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy249; + case 'o': goto yy250; default: goto yy34; } yy217: + yych = *++YYCURSOR; + switch (yych) { + case 'l': goto yy218; + default: goto yy34; + } +yy218: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy251; + default: goto yy34; + } +yy219: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; @@ -1583,129 +1598,17 @@ yy217: opcode = absl::StrCat("loop_", group(1)); goto end_region; } -#line 1587 "src/sfizz/OpcodeCleanup.cpp" -yy219: +#line 1602 "src/sfizz/OpcodeCleanup.cpp" +yy221: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy184; - default: goto yy34; - } -yy220: - yych = *++YYCURSOR; - switch (yych) { - case 0x00: goto yy250; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': goto yy220; + case 't': goto yy186; default: goto yy34; } yy222: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy252; - default: goto yy34; - } -yy223: - yych = *++YYCURSOR; - switch (yych) { - case 'y': goto yy253; - default: goto yy34; - } -yy224: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy254; - default: goto yy34; - } -yy225: - yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy255; - default: goto yy34; - } -yy226: - yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy256; - default: goto yy34; - } -yy227: - yych = *++YYCURSOR; - switch (yych) { - case 'd': goto yy257; - default: goto yy34; - } -yy228: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy258; - default: goto yy34; - } -yy229: - yych = *++YYCURSOR; - switch (yych) { - case 'r': goto yy259; - default: goto yy34; - } -yy230: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy260; - default: goto yy34; - } -yy231: - yych = *++YYCURSOR; - switch (yych) { - case 'p': goto yy261; - default: goto yy34; - } -yy232: - yych = *++YYCURSOR; - switch (yych) { - case 'd': goto yy262; - default: goto yy34; - } -yy233: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy263; - default: goto yy34; - } -yy234: - yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy264; - default: goto yy34; - } -yy235: - yych = *++YYCURSOR; - switch (yych) { - case 'n': goto yy265; - default: goto yy201; - } -yy236: - yych = *++YYCURSOR; - switch (yych) { - case 'f': goto yy266; - default: goto yy34; - } -yy237: - yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy267; - default: goto yy34; - } -yy238: - yych = *++YYCURSOR; - switch (yych) { - case 0x00: goto yy268; + case 0x00: goto yy252; case '0': case '1': case '2': @@ -1715,10 +1618,122 @@ yy238: case '6': case '7': case '8': - case '9': goto yy238; + case '9': goto yy222; + default: goto yy34; + } +yy224: + yych = *++YYCURSOR; + switch (yych) { + case 'c': goto yy254; + default: goto yy34; + } +yy225: + yych = *++YYCURSOR; + switch (yych) { + case 'y': goto yy255; + default: goto yy34; + } +yy226: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy256; + default: goto yy34; + } +yy227: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy257; + default: goto yy34; + } +yy228: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy258; + default: goto yy34; + } +yy229: + yych = *++YYCURSOR; + switch (yych) { + case 'd': goto yy259; + default: goto yy34; + } +yy230: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy260; + default: goto yy34; + } +yy231: + yych = *++YYCURSOR; + switch (yych) { + case 'r': goto yy261; + default: goto yy34; + } +yy232: + yych = *++YYCURSOR; + switch (yych) { + case 't': goto yy262; + default: goto yy34; + } +yy233: + yych = *++YYCURSOR; + switch (yych) { + case 'p': goto yy263; + default: goto yy34; + } +yy234: + yych = *++YYCURSOR; + switch (yych) { + case 'd': goto yy264; + default: goto yy34; + } +yy235: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy265; + default: goto yy34; + } +yy236: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy266; + default: goto yy34; + } +yy237: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy267; + default: goto yy203; + } +yy238: + yych = *++YYCURSOR; + switch (yych) { + case 'f': goto yy268; + default: goto yy34; + } +yy239: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy269; default: goto yy34; } yy240: + yych = *++YYCURSOR; + switch (yych) { + case 0x00: goto yy270; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy240; + default: goto yy34; + } +yy242: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; @@ -1730,17 +1745,17 @@ yy240: opcode = absl::StrCat("fil", group(1), "_type"); goto end_region; } -#line 1734 "src/sfizz/OpcodeCleanup.cpp" -yy242: +#line 1749 "src/sfizz/OpcodeCleanup.cpp" +yy244: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy270; - default: goto yy137; + case 'o': goto yy272; + default: goto yy139; } -yy243: +yy245: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy271; + case 0x00: goto yy273; case '0': case '1': case '2': @@ -1750,38 +1765,38 @@ yy243: case '6': case '7': case '8': - case '9': goto yy243; - default: goto yy34; - } -yy245: - yych = *++YYCURSOR; - switch (yych) { - case 'f': goto yy273; - default: goto yy34; - } -yy246: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy274; + case '9': goto yy245; default: goto yy34; } yy247: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy249; + case 'f': goto yy275; default: goto yy34; } yy248: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy275; + case 'e': goto yy276; default: goto yy34; } yy249: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy276; - goto yy34; + switch (yych) { + case 'o': goto yy251; + default: goto yy34; + } yy250: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy277; + default: goto yy34; + } +yy251: + yych = *++YYCURSOR; + if (yych <= 0x00) goto yy278; + goto yy34; +yy252: ++YYCURSOR; yynmatch = 3; yypmatch[4] = yyt1; @@ -1795,8 +1810,8 @@ yy250: opcode = absl::StrCat("start_", group(1), "cc", group(2)); goto end_region; } -#line 1799 "src/sfizz/OpcodeCleanup.cpp" -yy252: +#line 1814 "src/sfizz/OpcodeCleanup.cpp" +yy254: yych = *++YYCURSOR; switch (yych) { case '0': @@ -1810,111 +1825,111 @@ yy252: case '8': case '9': yyt1 = YYCURSOR; - goto yy278; - default: goto yy34; - } -yy253: - yych = *++YYCURSOR; - switch (yych) { - case '_': goto yy280; - default: goto yy34; - } -yy254: - yych = *++YYCURSOR; - switch (yych) { - case 0x00: - yyt2 = yyt3 = NULL; - goto yy281; - case '_': - yyt3 = YYCURSOR; - goto yy283; + goto yy280; default: goto yy34; } yy255: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy285; + case '_': goto yy282; default: goto yy34; } yy256: yych = *++YYCURSOR; switch (yych) { - case 'y': goto yy257; + case 0x00: + yyt2 = yyt3 = NULL; + goto yy283; + case '_': + yyt3 = YYCURSOR; + goto yy285; default: goto yy34; } yy257: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy286; + case 'c': goto yy287; default: goto yy34; } yy258: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy287; + case 'y': goto yy259; default: goto yy34; } yy259: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy257; + case 'c': goto yy288; default: goto yy34; } yy260: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy288; + case 'a': goto yy289; default: goto yy34; } yy261: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy289; + case 't': goto yy259; default: goto yy34; } yy262: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy290; + case 'a': goto yy290; default: goto yy34; } yy263: yych = *++YYCURSOR; switch (yych) { - case 'q': goto yy290; + case 't': goto yy291; default: goto yy34; } yy264: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy291; + case 'e': goto yy292; default: goto yy34; } yy265: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy292; - default: goto yy201; + case 'q': goto yy292; + default: goto yy34; } yy266: yych = *++YYCURSOR; switch (yych) { - case 0x00: - yyt4 = yyt5 = NULL; - yyt3 = YYCURSOR; - goto yy293; - case '_': - yyt3 = yyt5 = YYCURSOR; - goto yy295; + case 'n': goto yy293; default: goto yy34; } yy267: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy297; - default: goto yy34; + case 'd': goto yy294; + default: goto yy203; } yy268: + yych = *++YYCURSOR; + switch (yych) { + case 0x00: + yyt4 = yyt5 = NULL; + yyt3 = YYCURSOR; + goto yy295; + case '_': + yyt3 = yyt5 = YYCURSOR; + goto yy297; + default: goto yy34; + } +yy269: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy299; + default: goto yy34; + } +yy270: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -1930,14 +1945,14 @@ yy268: opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); goto end_region; } -#line 1934 "src/sfizz/OpcodeCleanup.cpp" -yy270: +#line 1949 "src/sfizz/OpcodeCleanup.cpp" +yy272: yych = *++YYCURSOR; switch (yych) { - case 'm': goto yy298; - default: goto yy137; + case 'm': goto yy300; + default: goto yy139; } -yy271: +yy273: ++YYCURSOR; yynmatch = 3; yypmatch[4] = yyt1; @@ -1951,26 +1966,26 @@ yy271: opcode = absl::StrCat(group(1), "hdcc", group(2)); goto end_region; } -#line 1955 "src/sfizz/OpcodeCleanup.cpp" -yy273: - yych = *++YYCURSOR; - switch (yych) { - case 'f': goto yy299; - default: goto yy34; - } -yy274: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy249; - default: goto yy34; - } +#line 1970 "src/sfizz/OpcodeCleanup.cpp" yy275: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy300; + case 'f': goto yy301; default: goto yy34; } yy276: + yych = *++YYCURSOR; + switch (yych) { + case 't': goto yy251; + default: goto yy34; + } +yy277: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy302; + default: goto yy34; + } +yy278: ++YYCURSOR; yynmatch = 3; yypmatch[2] = yyt1; @@ -1984,11 +1999,11 @@ yy276: opcode = absl::StrCat(group(1), "_", group(2), "1"); goto end_region; } -#line 1988 "src/sfizz/OpcodeCleanup.cpp" -yy278: +#line 2003 "src/sfizz/OpcodeCleanup.cpp" +yy280: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy301; + case 0x00: goto yy303; case '0': case '1': case '2': @@ -1998,16 +2013,16 @@ yy278: case '6': case '7': case '8': - case '9': goto yy278; + case '9': goto yy280; default: goto yy34; } -yy280: +yy282: yych = *++YYCURSOR; switch (yych) { - case 'g': goto yy303; + case 'g': goto yy305; default: goto yy34; } -yy281: +yy283: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; @@ -2019,63 +2034,63 @@ yy281: opcode = absl::StrCat("resonance1", group(1)); goto end_region; } -#line 2023 "src/sfizz/OpcodeCleanup.cpp" -yy283: +#line 2038 "src/sfizz/OpcodeCleanup.cpp" +yy285: yych = *++YYCURSOR; if (yych <= 0x00) { yyt2 = YYCURSOR; - goto yy281; - } - goto yy283; -yy285: - yych = *++YYCURSOR; - switch (yych) { - case 'k': goto yy257; - default: goto yy34; - } -yy286: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy304; - default: goto yy34; + goto yy283; } + goto yy285; yy287: yych = *++YYCURSOR; switch (yych) { - case 's': goto yy305; + case 'k': goto yy259; default: goto yy34; } yy288: yych = *++YYCURSOR; switch (yych) { - case 'i': goto yy306; + case 'c': goto yy306; default: goto yy34; } yy289: yych = *++YYCURSOR; switch (yych) { - case 'h': goto yy290; + case 's': goto yy307; default: goto yy34; } yy290: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy307; + case 'i': goto yy308; default: goto yy34; } yy291: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy308; + case 'h': goto yy292; default: goto yy34; } yy292: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy309; - default: goto yy201; + case 'c': goto yy309; + default: goto yy34; } yy293: + yych = *++YYCURSOR; + switch (yych) { + case 'd': goto yy310; + default: goto yy34; + } +yy294: + yych = *++YYCURSOR; + switch (yych) { + case 'o': goto yy311; + default: goto yy203; + } +yy295: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -2091,43 +2106,43 @@ yy293: opcode = absl::StrCat(group(1), "_", group(2), "1", group(3)); goto end_region; } -#line 2095 "src/sfizz/OpcodeCleanup.cpp" -yy295: +#line 2110 "src/sfizz/OpcodeCleanup.cpp" +yy297: yych = *++YYCURSOR; if (yych <= 0x00) { yyt4 = YYCURSOR; - goto yy293; + goto yy295; } - goto yy295; -yy297: + goto yy297; +yy299: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy310; + case 'c': goto yy312; default: goto yy34; } -yy298: +yy300: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy311; - goto yy136; -yy299: + if (yych <= 0x00) goto yy313; + goto yy138; +yy301: yych = *++YYCURSOR; switch (yych) { case 0x00: yyt4 = yyt5 = NULL; yyt3 = YYCURSOR; - goto yy313; + goto yy315; case '_': yyt3 = yyt5 = YYCURSOR; - goto yy315; + goto yy317; default: goto yy34; } -yy300: +yy302: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy317; + case 'n': goto yy319; default: goto yy34; } -yy301: +yy303: ++YYCURSOR; yynmatch = 3; yypmatch[4] = yyt1; @@ -2141,14 +2156,14 @@ yy301: opcode = absl::StrCat("start_", group(1), "hdcc", group(2)); goto end_region; } -#line 2145 "src/sfizz/OpcodeCleanup.cpp" -yy303: +#line 2160 "src/sfizz/OpcodeCleanup.cpp" +yy305: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy318; + case 'r': goto yy320; default: goto yy34; } -yy304: +yy306: yych = *++YYCURSOR; switch (yych) { case '0': @@ -2162,46 +2177,46 @@ yy304: case '8': case '9': yyt3 = YYCURSOR; - goto yy319; - default: goto yy34; - } -yy305: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy257; - default: goto yy34; - } -yy306: - yych = *++YYCURSOR; - switch (yych) { - case 'n': goto yy257; + goto yy321; default: goto yy34; } yy307: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy321; + case 'e': goto yy259; default: goto yy34; } yy308: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy322; + case 'n': goto yy259; default: goto yy34; } yy309: yych = *++YYCURSOR; switch (yych) { - case 'm': goto yy323; - default: goto yy201; + case 'c': goto yy323; + default: goto yy34; } yy310: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy266; + case 'o': goto yy324; default: goto yy34; } yy311: + yych = *++YYCURSOR; + switch (yych) { + case 'm': goto yy325; + default: goto yy203; + } +yy312: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy268; + default: goto yy34; + } +yy313: ++YYCURSOR; yynmatch = 1; yypmatch[0] = YYCURSOR - 12; @@ -2211,8 +2226,8 @@ yy311: opcode = "amp_random"; goto end_region; } -#line 2215 "src/sfizz/OpcodeCleanup.cpp" -yy313: +#line 2230 "src/sfizz/OpcodeCleanup.cpp" +yy315: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -2228,30 +2243,30 @@ yy313: opcode = absl::StrCat(group(1), "_", group(2), "1", group(3)); goto end_region; } -#line 2232 "src/sfizz/OpcodeCleanup.cpp" -yy315: +#line 2247 "src/sfizz/OpcodeCleanup.cpp" +yy317: yych = *++YYCURSOR; if (yych <= 0x00) { yyt4 = YYCURSOR; - goto yy313; - } - goto yy315; -yy317: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy324; - default: goto yy34; - } -yy318: - yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy325; - default: goto yy34; + goto yy315; } + goto yy317; yy319: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy326; + case 'c': goto yy326; + default: goto yy34; + } +yy320: + yych = *++YYCURSOR; + switch (yych) { + case 'o': goto yy327; + default: goto yy34; + } +yy321: + yych = *++YYCURSOR; + switch (yych) { + case 0x00: goto yy328; case '0': case '1': case '2': @@ -2261,10 +2276,10 @@ yy319: case '6': case '7': case '8': - case '9': goto yy319; + case '9': goto yy321; default: goto yy34; } -yy321: +yy323: yych = *++YYCURSOR; switch (yych) { case '0': @@ -2278,32 +2293,32 @@ yy321: case '8': case '9': yyt3 = YYCURSOR; - goto yy328; + goto yy330; default: goto yy34; } -yy322: - yych = *++YYCURSOR; - switch (yych) { - case 'm': goto yy330; - default: goto yy34; - } -yy323: - yych = *++YYCURSOR; - if (yych <= 0x00) goto yy331; - goto yy200; yy324: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy299; + case 'm': goto yy332; default: goto yy34; } yy325: + yych = *++YYCURSOR; + if (yych <= 0x00) goto yy333; + goto yy202; +yy326: yych = *++YYCURSOR; switch (yych) { - case 'u': goto yy333; + case 'e': goto yy301; default: goto yy34; } -yy326: +yy327: + yych = *++YYCURSOR; + switch (yych) { + case 'u': goto yy335; + default: goto yy34; + } +yy328: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -2319,11 +2334,11 @@ yy326: opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); goto end_region; } -#line 2323 "src/sfizz/OpcodeCleanup.cpp" -yy328: +#line 2338 "src/sfizz/OpcodeCleanup.cpp" +yy330: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy334; + case 0x00: goto yy336; case '0': case '1': case '2': @@ -2333,13 +2348,13 @@ yy328: case '6': case '7': case '8': - case '9': goto yy328; + case '9': goto yy330; default: goto yy34; } -yy330: +yy332: yych = *++YYCURSOR; if (yych >= 0x01) goto yy34; -yy331: +yy333: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; @@ -2351,14 +2366,14 @@ yy331: opcode = absl::StrCat("fil", group(1), "_random"); goto again_region; } -#line 2355 "src/sfizz/OpcodeCleanup.cpp" -yy333: +#line 2370 "src/sfizz/OpcodeCleanup.cpp" +yy335: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy336; + case 'p': goto yy338; default: goto yy34; } -yy334: +yy336: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -2374,8 +2389,8 @@ yy334: opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); goto end_region; } -#line 2378 "src/sfizz/OpcodeCleanup.cpp" -yy336: +#line 2393 "src/sfizz/OpcodeCleanup.cpp" +yy338: yych = *++YYCURSOR; if (yych >= 0x01) goto yy34; ++YYCURSOR; @@ -2387,7 +2402,7 @@ yy336: opcode = "group"; goto end_region; } -#line 2391 "src/sfizz/OpcodeCleanup.cpp" +#line 2406 "src/sfizz/OpcodeCleanup.cpp" } #line 191 "src/sfizz/OpcodeCleanup.re" @@ -2404,80 +2419,80 @@ end_region: YYCURSOR = opcode.c_str(); -#line 2408 "src/sfizz/OpcodeCleanup.cpp" +#line 2423 "src/sfizz/OpcodeCleanup.cpp" { char yych; yych = *YYCURSOR; switch (yych) { - case 's': goto yy343; - default: goto yy341; + case 's': goto yy345; + default: goto yy343; } -yy341: +yy343: ++YYCURSOR; -yy342: +yy344: #line 211 "src/sfizz/OpcodeCleanup.re" { goto end_control; } -#line 2423 "src/sfizz/OpcodeCleanup.cpp" -yy343: +#line 2438 "src/sfizz/OpcodeCleanup.cpp" +yy345: yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case 'e': goto yy344; - default: goto yy342; + case 'e': goto yy346; + default: goto yy344; } -yy344: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy346; - default: goto yy345; - } -yy345: - YYCURSOR = YYMARKER; - goto yy342; yy346: yych = *++YYCURSOR; switch (yych) { - case '_': goto yy347; - default: goto yy345; + case 't': goto yy348; + default: goto yy347; } yy347: - yych = *++YYCURSOR; - switch (yych) { - case 'r': goto yy348; - default: goto yy345; - } + YYCURSOR = YYMARKER; + goto yy344; yy348: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy349; - default: goto yy345; + case '_': goto yy349; + default: goto yy347; } yy349: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy350; - default: goto yy345; + case 'r': goto yy350; + default: goto yy347; } yy350: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy351; - default: goto yy345; + case 'e': goto yy351; + default: goto yy347; } yy351: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy352; - default: goto yy345; + case 'a': goto yy352; + default: goto yy347; } yy352: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy353; - default: goto yy345; + case 'l': goto yy353; + default: goto yy347; } yy353: + yych = *++YYCURSOR; + switch (yych) { + case 'c': goto yy354; + default: goto yy347; + } +yy354: + yych = *++YYCURSOR; + switch (yych) { + case 'c': goto yy355; + default: goto yy347; + } +yy355: yych = *++YYCURSOR; switch (yych) { case '0': @@ -2491,13 +2506,13 @@ yy353: case '8': case '9': yyt1 = YYCURSOR; - goto yy354; - default: goto yy345; + goto yy356; + default: goto yy347; } -yy354: +yy356: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy356; + case 0x00: goto yy358; case '0': case '1': case '2': @@ -2507,10 +2522,10 @@ yy354: case '6': case '7': case '8': - case '9': goto yy354; - default: goto yy345; + case '9': goto yy356; + default: goto yy347; } -yy356: +yy358: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; @@ -2522,7 +2537,7 @@ yy356: opcode = absl::StrCat("set_hdcc", group(1)); goto end_control; } -#line 2526 "src/sfizz/OpcodeCleanup.cpp" +#line 2541 "src/sfizz/OpcodeCleanup.cpp" } #line 215 "src/sfizz/OpcodeCleanup.re" diff --git a/src/sfizz/OpcodeCleanup.re b/src/sfizz/OpcodeCleanup.re index 245f62d5..c9a3d5c4 100644 --- a/src/sfizz/OpcodeCleanup.re +++ b/src/sfizz/OpcodeCleanup.re @@ -120,7 +120,7 @@ end_region_oncc: opcode = absl::StrCat("off_", group(1)); goto end_region; } - "bend" ("up"|"down") END { + "bend" ("up"|"down"|"step") END { opcode = absl::StrCat("bend_", group(1)); goto end_region; } diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 336907f7..b5115243 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -212,6 +212,7 @@ TEST_CASE("[Opcode] Normalization") {"offmode", "off_mode"}, {"bendup", "bend_up"}, {"benddown", "bend_down"}, + {"bendstep", "bend_step"}, {"filtype", "fil1_type"}, {"fil21type", "fil21_type"}, // ARIA aliases From 895e8f2a64079be3336b19cf19375ef4aa0408c5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 14 Nov 2020 13:57:20 +0100 Subject: [PATCH 084/668] Bundle the dylibs where the code signer can find them --- cmake/BundleDylibs.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/BundleDylibs.cmake b/cmake/BundleDylibs.cmake index abee5c18..f7c0628a 100644 --- a/cmake/BundleDylibs.cmake +++ b/cmake/BundleDylibs.cmake @@ -13,7 +13,7 @@ function(bundle_dylibs NAME PATH) return() endif() - set(_relative_libdir "../libs") + set(_relative_libdir "../Frameworks") get_filename_component(_dir "${PATH}" DIRECTORY) set(_dir "${_dir}/${_relative_libdir}") From 96b4c490e23492ae5c6e61629884ea7ecaff99f2 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 14 Nov 2020 14:04:41 +0100 Subject: [PATCH 085/668] Do not store text files at the root of VST and AU bundles --- vst/CMakeLists.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 8e765c09..ccb73714 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -123,8 +123,15 @@ else() LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux/$<0:>") endif() -file(COPY "gpl-3.0.txt" - DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") +# Copy the license +if(APPLE) + # on macOS, files are not permitted at the bundle root, during code signing + file(COPY "gpl-3.0.txt" + DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/SharedSupport/License") +else() + file(COPY "gpl-3.0.txt" + DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") +endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_compile_options(${VSTPLUGIN_PRJ_NAME} PRIVATE @@ -280,7 +287,7 @@ elseif(SFIZZ_AU) DESTINATION "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Resources") file(COPY "gpl-3.0.txt" - DESTINATION "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}") + DESTINATION "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/SharedSupport/License") # Add the resource fork if (FALSE) From 3cb80b4e4a4bfc321520bcaddaff9f650152c813 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 14 Nov 2020 15:53:22 +0100 Subject: [PATCH 086/668] Set up the code-signing key pair for macOS --- .appveyor.yml | 13 +++++++++-- scripts/appveyor/install.sh | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 scripts/appveyor/install.sh diff --git a/.appveyor.yml b/.appveyor.yml index ff607f84..595fed6d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,6 +19,15 @@ environment: VCPKG_TRIPLET: x64-windows-static PATH: C:\Program Files (x86)\Inno Setup 6;%PATH% + # Made with https://github.com/sfztools/code-signing + CODESIGN_IDENTITY: codesign.sfz.tools + CODESIGN_P12: + secure: 9GwD/vqCwHVJBohmtmYRTumfxBx91vtF5dyS8gLAVw8INzBgvZLHxHc7D4Kcgzs1RCpch3Ts/KA/PH8wDSLnWzXgyfVTqTY4XE5NAP+i9y+s6WwR3JBPperkrsfKinP+PhRwxwXlEeZ09asDIYFwgTturFEUUJY55fA7uofiV+Hb1/QgqoLr3xYZZAzEFFsx0aOZXmgbYRpGr9DWjhFI7ei0gnrAnJGUR9Fq9Teg6iF2aZgk77bZOJ9SK0bBJUcm0l0KOqqKnnxvOMqCt4AEpjaAFjNCyrtYYZatUP6KSKCrZjyKbXqjxqk+OsPZA+wXUGOR0w8M3ARpDqmvK0KqYJGs+L6QGDMkHobwRdkUammIk+CVpG0DWEXCJGlNZgSvrg6f0m7hFNf53RxsjgL2jGN2mxJ/nVe9EpuJnL8UFACH5O3w1Q/b9kMNDHuROMpNNXl5UICMb9gsWnW4js+R02cBAlLzPGcyZhu8AJxyMcJ9tNqYherAkWQ37i09QpuRycZDvuhxQ0gWnqIRWUB8iXarHTRl1Jvc/GvlLCoOv3OSKxQV1dfzyhvBJBk1jDFgZ/AhZhZIQxIFVY0KCIuoWe2OdZEZ+4jws4BeK0sA4LtsRAePXvR6iAtWczbt6vJGjL7JvCznRJMz8KA+oLdw1iuJCIrK9e4JkTIfIAlFqrAHZoZwxE6Gmn7aG3OGEhNRL4q76dI3xQaUI6Ff6GT1B+rbBv6UggNYtv+kTq/Qb0HerpFtjCPzr/p6gCYNJkkjpPu0lAxEY5QY13y2JEK0Ef5Avy65iIauZvOGDnfCngaBfNK9exqSnLEXUbILSBawdJvZsOZSakeqqCsxJE+pE4AoJVKiJHae2FqQaBRbxLgApfv6J7k0UCzLMQZG2xQGIQe/9B/ExXxNJWSg/nZ9WIWJ9klBn5MiFOm74guApJK1qVeQLz9q1shANpAZFIzp46XiNR7FJAWSvBdnU2HmI4iB2yr/gWGu3ibZrYwFJmwCG8lNwztGsHsAPPu/rITx5RJK+eRRsxU9snihBNlSK03HXK+ZFa3JxMVokr8Smo7AwZnMFYlrgpnYSBEhIKEJM+KTAn8Bm3aqg5M42yB94IlFpp8BOlqjkuZwblA1Ap7wxwoc5OaxC9B8PLhFZmgLZA/P043gIoAAUH8pPg7UT2l1tfxSotE7OaUnIuSv4S9RWKbXG7d9qiNdmjLE0EXpCI2ovpNLbCwJhonnCnlRSVnhC2MjL0MZ0v0vmDKE/7mAheFJ5D5pI5yC87e6Dnr6dFI9CDoewrdylzfjYpLhQUfuihpzs/Z4Cus68cI9wXhYxbpsO8SMz1d86OZGnS9J34hY0KzlHPCtxQIo921n4q7UHPCL/yHPW/zFDBiXMyoXhW+2Z3r0TVSBP3Z9oAOFUFQ/8VkuPuz2paRqDNAYDgoGWmNvaDby8sZWZoT6i3rdoz3jqE1A5MDXIbM6mtB1XMC8+TDWJKHs0IECMz0HcBQToHhUFl0fxfAJ3JNk6elmQiCkqhx+qC5d/1RHkjXuYRHFh+BsJLXTTKTzykCk3fIS5xjWOBjaSMDTTHaOrPFbt1beNeydAsBnMuElitwQhs6f6b8Y+CK8zrFDEzSiS+VmLzA+vY4uO6M7EHUID7Od6mg6hkh9Bh0Qr+vxwlHjZeigvpOPzTB/7oSKkWIEboR+pp6r2Ffyyl8E3cpplxkguRkzyr5uF/sJL7R6/HMI+S2eTlwv4geUlHs3VhJliclRtOk1xz3oblvEcjqF2B+OsFOOrESaPi1U8U3Hnw9sp429kOHhI7gcYwqLIKL5d2JtKZ2JyURFFqh5mbjQIcnENCSxfJYjdcdTusT+kD8nCd16E1YXkqzEdGTnhWLjZWPqsQg/OYYH/BACQz0B1C2+QByBhnf2UVtf1ZwMTjgb5cnYbDKXDu7oItvmeWiTvdJvH4IkOlXoT63ByoqpZrA0e48Ay/9883Q87fDSZZ8/qmlEariEqz9IaoJz3YHi1YWU5C2E7GFJtlBA3Knzs6GUuKUnvdceVUEQKMTfBQYmropm3M+UzBGkWqFuOvD2h7hfLcE3NHrJVyv4HlocRcmIL8WLyrZJh5EgUxqJGfyzsOUVdFv46djx93jZOESyAl7Af3GRNcQgjX2WJci+/1YaNyNwh93mKzhzKlx2u9FwvB0sugK24IRJMDGk31IbT72APxL7gn2jIyf7dJFKTyNknf0FHj/hQPGkpUeGCSI4pIqllwK77ghbJOqKW7o6t2cE5njMF+mS2BqpnPgZyA+1s0FpkbOFiSZOiqyC9WkEUY0jjSMH2eUonSIAOpGV+dTfBoJq3HW05voreKfpCVE2JZt4IN0eHWsXYgyims7oYyRUt0n7++yKMl/qAjubvmJzm1KC2ijsqmLSK//mmHUDopxEirNlBDEdDNDwqLtcK9jKJ/MB2Ou4Ga5oEi69y4sLiNGBv44yptb3iShVxC4sRDpvqmxubwi+Ov6MNq/YstokMygvVTz2HGLBwHTUhPArvsxulECeWf6XfYAsiec7tncZkIW6G43EL0uzsGt2FIIDZp9EUu+K4qOhbqvWxOpOBUEvobXAmHp0X3fpUanzZfn4PcHs/Egm0f4zWgd2Jd94dciGiHPaap0oPnKuH4U/YdiVgsesLRpum1S+iPayeqtMwzMwWkihOJ38Kneubd60qLLj2X7fL7UTFhHRSxRY9QE+yBCEGVHSmsO6piTSZvDOL07DjUhKXN/d7YCeRg1gWVgPc5hZHnqov/hoo3N8FneVhlkEfGhcvt7IBhfVn7ntuMVhyg6IKlJb6GJXJntOVX2iT4TvgL+hnur7PtDjKppA69TX6klDz/W3cM0YUe0iR4lJuzIUZZpK5p9S7BWWbtdCP9IstsHu57kb/HCGo7Bg6Yxvks9dy//LWAwfmsz+bFb+PM2tBFWBNhUhBMs6jRPiFmLyZCZ6Tx0fdTNXuUrsewu5s58X2fr5/cwGPfYxAaK3XM95cMGR1CBS//hhYdA6EUn8IleC+yjzKzuoKrh3dj/zEWd8LSUQ+TTmNj8qCFaLl6oFQw0VGvcGzUSobVa4Rsmh26IyZd1oadGH/stIPrh8V4T2HU8Pm/2LOaWmOpUtG/LAGQ9OHFlLCcgB9d9w5is+jWZL3T1jUuH2VqGCzMr7agIUyFyLovpN4uS2EdJUqEMJ0G1kAT1RMdj4UExG1GVBhabiVwPytZO/rIB84F+HZZdU9kMbThjOl30tPm7EmEvhf4QEgM19Ke922lRHXSsuqb9Y/dSoKOegQs/v0lsOjFXTCcQuKTLYK5H1dVJ7DdBrtP2ndqpt6zL7exkfKhSPvftma0vJXak3DZL/eNRW3WdmFrbNYKCxwTo3Uo4gDTxTDa20PSFm7TK81D1Yk8S0x7s20uJVfbLBVqQ6wvTJrJPe4l8Rtk4GDIsY0RLHyxAq5QBp/uLcoS0Uuhq1aOOkZxqm5+S/Ekl6eYEhjpV/oSzjLd8L7M8gMIcCkS3/7Brn/XlIp+5XaPiAxo9jaTbun/VntmCn0EAt7PvdLqks3whcrwFrTZrt/rXxYl57ABsUzFtczxyXXpYp+HYi9CNZOULPLMAriXzBjg3PDnuW2IJwR20xfE9QbU92eAV6nWPEIgOQCSBjdhiD3sq23eTQmoa2qZUO3LIUQXvytRc2TzKQblOgQY4ZiubqU0dHFZLMnEQo/oQccO3jD5S01F9a0DYV3lXi1kx5+YcUs6R5sXnXiEiHCcs9flAZoPsozLU4LjLXeAPLCc7j0FwH1JJ1dcHSHacD4DhWCxrQWz0iWBJPWMT7IIEtU1p9qmphKkkADQt9LQ8wygWmP2txAwAnw0TOZlW3mr0EwprewQW8utiR4CW2TYJzxuAx60r0fngClS8V3uofV7NhPS6BMVbAu2qzeDDpqY64HMuToIJ486IDdsd/aX/07dqlRteHX0ltHOOk1L8BxNTPQ7dfnfwB36aGS5oZL3oWVOr5ITD1IobUj9Rf2bx98XUEeVpKvqFRDwKM9jfyl6Fx07+bOfJq2UsH1skdGuVm9pSsCsEAo/tbDaLAsier1mQLwQ3hpGo7Z+BIVo3h4sfbDuiHNfBDSTitDGogSzxaJVJX9WzmCZAOH9TDRFF5i4VwnOVjgBDj9WOWAbPLkANpCN5+kOLclywnhA5IGJiKb9NqG/5zc+Io11Aa78XN/CEniu4xbXXYMuG6QL9l5qcUThtgxjWKhcs+T5O+sR+kMZ8r5UUsHnvEVRj0CExZ0EDBdA2t5QpGIGhD6bL25CTasAz1PDGNvST+hWUoxKr1xe1mdgXblymR2WipuKDaEgFQW5S1qcRF6vQDqKT7 + CODESIGN_PASSWORD: + secure: MdBjjykL0JHVnXeh3KbZ+8S1YtSi5rYz3tOxrlot3/FQrw7LeuISY8T+K/Xf1kZB4oQH/k8ht1DNxJOQ+k84AulqtHhWfuMYOHK4rm5RTho= + SFZTOOLS_CRT: + secure: OWNh97s3+yJBO6NfaF82v8fZzhw4cBLVEneVOS7Vab6kGaUcRs1E2VdYPzxKvnZmgLxWWbV9SCiHFpyJ4TFk35A1PVrEO9zzvVHJ0c9lfaJ3O1O57kgjwVMZErEiDbbU2MvaBIji43+L66sLYabBZpeIdM//J+MUGF0jw7ouujTT7bMGawKnkCzxsCH9BtAtRUyTMCC521CKcGqg+PeOfIxjoM3oW6KigZPCs7H+gOZ/PxeI3/VMcz3Ab4iDuDdof+rwuEO0NIKo9d1BFyW4OPp1/8vYJvv57X1w4mp4XWUt/4UUtrvKhkFg/k4ZmpTsYY99mAnGtmBCt8VNx5wxMXikHjP8/oPsGatAXYa5Yw0k0ZP0Vp41EItNsGoW1mX8/5Cr7Mk29LMkONnupTw//aeNIf/OXuiKvLSbBzhpIhbKacZlKLXix2ri9N7RudY1eJZQQD9YY3j/SzXnb6x/OGtS3EyR/VUcb5enL2G3Tp3JDVYGWyShuwjc8jBk1WthPAk+EEz4CaJQ3IM/I3tGPuiHvV6zOOIvza3yDS8s5EHlrszpvMsuL++BPNfhNV02vwAxT0eiQd2FNnV0lP93e63qRcw/Zl4x43p91jEKB1BxfeKfWUsQsczdrpTtmNV7IC1dUyAkBFFXfb3yxoJDU35e6f3Ile33PFVcs8rp04Tbv8aQxftEXbiiWtQ8wgbtBS4NyRWk4BoiaufIxqC6fqlq0sL6y2L32b1U3C2Yrpt/CcifUMS52sR9gvV43LYjlnU6KKZAz7Eb8jY6/VAnuwLjGjVFz5Ecr71oDnVRfDDsBSEuLUtFKx0mvkOvuPcYp9y24WLwjN6s1kUhZxLS6TAP3Ipt5pYpQC379IflIE8wiRjWcvf5rhWBw51hPP+G3iJ6C5aW2SBBo2GjzwY0uNPfJ2FOb/85bHVIe2XjW2Krwfc7EfOxdFCPW3lDLOt42+M3eMQxXzZjLVZ+W0wJu5apLj9cJKqNXJBZ7LPcAq3Y2enG49UT3Dbx3XX3GpPMVff++LmX9E+e5JkNzfD4bhYJQYI5QpjJEaJ9AW8F8c3e/Gm+C4z14JGU/kTWycJnm5KnoaR2mrmzZ5StL84nYLhKkyX7qvnQ0bARgxggoqu0aM1sy1TPzGbpb+9NnR3I7KtRz5d9NNjVvZja4jfq56e6GlEaPYpM098QuwW3HM6Q61Gv/F5cci00kcZda7i3QRjyjdMtsaukynfxvrZFHocsKF+37pFbhjrSz5JQbFGSYRlRlhwfz94wQy4BGQLz5WvQj/y5cwjPQ5bc30PFrcwa8w4qN8cgprV4fp0DavyjkeKWswh1s5vyccdO/WXJcmCRP7mh/+MF5Xq9o1qS9oTqZjxFHkwMWvlNrwAKYKZsyPGGaWS9axe8R+6b79YUIE8a48EUv8kGA4HW3LXW2oGiykULo3jY+VnTeDCfuAxmr0U7tiB7UUom2dYpH9aY7FbZUQq5pSpE5CPXSzF0QfFET57Kf3Y1MS4LAn50LNkaWhVSW5nlIIu2hiIpE6TRDXYaDZ2L+UWLrUwGjwyc/wXJmK4+nyzfSuAq06blDJmn8ODkk0ZKml2J4ovBUfIzkIAQeLtteXRQSxAaAGk9QKJmy//MiPRE098x109fTKNwnvDphKRZATBzrDyp0P3Grza8tynVYqUNzFZhLWUEg8VjVMrmW5LklWo3W1SQYDTT6LZS1uBs/Q5M0rz0+AZeHB9yP9PCkBN+KIOxTTtqxRBH3/OBG5SCuaSVi7z4WBSrfpgG/9M2Ll+Tx/OpKZAaloWI/0oJqVLhod4+BdTXGYz2D25PB/qKJtGMvBntsOzerXQjbHEZ9nXtZNZ3RqgsWFwuhd3Ej/5NixJBT3HuDw== + for: - matrix: only: @@ -28,8 +37,8 @@ for: - cmake --version - gcc -v install: - - brew install jack - - brew install dylibbundler + - chmod +x ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/install.sh + - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/install.sh before_build: - chmod +x ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/before_build.sh - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/before_build.sh diff --git a/scripts/appveyor/install.sh b/scripts/appveyor/install.sh new file mode 100644 index 00000000..49171879 --- /dev/null +++ b/scripts/appveyor/install.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +set -e +# do not `set -x` until after processing the secrets + +# -- secret -- +echo "* Set up code-signing" + +if test -z "${CODESIGN_PASSWORD}"; then + echo "! Secrets not available, skip code-signing" +else + echo "1. Extract PKCS12" + echo "${CODESIGN_P12}" | base64 -D -o codesign.p12 + stat codesign.p12 + echo "2. Extract CA certificate" + echo "${SFZTOOLS_CRT}" | base64 -D -o sfztools.crt + stat sfztools.crt + + echo "3. Create a new keychain" + security create-keychain -p dummypasswd build.keychain + echo "4. Configure the new keychain as default" + security default-keychain -s build.keychain + echo "5. Unlock the new keychain" + security unlock-keychain -p dummypasswd build.keychain + + echo "6. Import the code-signing key pair" + security import codesign.p12 -k build.keychain -P "${CODESIGN_PASSWORD}" -T /usr/bin/codesign + rm -f codesign.p12 + echo "7. Import the trusted CA certificate" + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain sfztools.crt + rm -f sfztools.crt + + echo "8. Set up the code-signing ACL" + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k dummypasswd build.keychain + + echo "9. Check the code-signing identity" + security find-identity -p codesigning build.keychain +fi +# -- /secret -- + +set -x + +brew install jack +brew install dylibbundler From c7136b66218fa14e911087e306866ea0e2b5ec40 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 14 Nov 2020 16:56:21 +0100 Subject: [PATCH 087/668] Perform macOS code-signing --- scripts/appveyor/after_build.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/scripts/appveyor/after_build.sh b/scripts/appveyor/after_build.sh index 2eb8e9af..1934da64 100755 --- a/scripts/appveyor/after_build.sh +++ b/scripts/appveyor/after_build.sh @@ -2,6 +2,30 @@ set -ex make DESTDIR=${PWD}/${INSTALL_DIR} install + +# Perform code-signing +if test -z "${CODESIGN_PASSWORD}"; then + echo "! Secrets not available, skip code-signing" +else + # unlock the keychain + security unlock-keychain -p dummypasswd build.keychain + # code-sign VST3 and dylibs + codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --verbose \ + "${INSTALL_DIR}"/Library/Audio/Plug-Ins/VST3/sfizz.vst3 + # code-sign AudioUnit and dylibs + codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --verbose \ + "${INSTALL_DIR}"/Library/Audio/Plug-Ins/Components/sfizz.component + codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --verbose \ + "${INSTALL_DIR}"/Library/Audio/Plug-Ins/Components/sfizz.component/Contents/Resources/plugin.vst3 + # code-sign LV2 and dylibs (note: manual, LV2 are not real bundles) + codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --verbose \ + "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Binary/*.so + if ls "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Frameworks/*.dylib &> /dev/null; then + codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --verbose \ + "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Frameworks/*.dylib + fi +fi + tar -zcvf "${INSTALL_DIR}.tar.gz" ${INSTALL_DIR} # Only release a tarball if there is a tag From c8354ce18e5c02ae2976cbe0020f7ab65691ca83 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 14 Nov 2020 17:41:11 +0100 Subject: [PATCH 088/668] Also sign bin/ and lib/ --- scripts/appveyor/after_build.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/scripts/appveyor/after_build.sh b/scripts/appveyor/after_build.sh index 1934da64..5f9f5d72 100755 --- a/scripts/appveyor/after_build.sh +++ b/scripts/appveyor/after_build.sh @@ -10,20 +10,28 @@ else # unlock the keychain security unlock-keychain -p dummypasswd build.keychain # code-sign VST3 and dylibs - codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --verbose \ + codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --force --verbose \ "${INSTALL_DIR}"/Library/Audio/Plug-Ins/VST3/sfizz.vst3 # code-sign AudioUnit and dylibs - codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --verbose \ + codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --force --verbose \ "${INSTALL_DIR}"/Library/Audio/Plug-Ins/Components/sfizz.component - codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --verbose \ + codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --force --verbose \ "${INSTALL_DIR}"/Library/Audio/Plug-Ins/Components/sfizz.component/Contents/Resources/plugin.vst3 # code-sign LV2 and dylibs (note: manual, LV2 are not real bundles) - codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --verbose \ + codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Binary/*.so if ls "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Frameworks/*.dylib &> /dev/null; then - codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --verbose \ + codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Frameworks/*.dylib fi + if ls "${INSTALL_DIR}"/usr/local/bin/* &> /dev/null; then + codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ + "${INSTALL_DIR}"/usr/local/bin/* + fi + if ls "${INSTALL_DIR}"/usr/local/lib/*.dylib &> /dev/null; then + codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ + "${INSTALL_DIR}"/usr/local/lib/*.dylib + fi fi tar -zcvf "${INSTALL_DIR}.tar.gz" ${INSTALL_DIR} From baf228802b33d0f9e85f91f98b33b71af3285c42 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 14 Aug 2020 04:18:58 +0200 Subject: [PATCH 089/668] Add the beat clock --- common.mk | 2 + lv2/sfizz.c | 6 +- src/CMakeLists.txt | 4 + src/sfizz.h | 2 +- src/sfizz.hpp | 2 +- src/sfizz/BeatClock.cpp | 230 ++++++++++++++++++++++++++++++++++++ src/sfizz/BeatClock.h | 160 +++++++++++++++++++++++++ src/sfizz/Metronome.cpp | 110 +++++++++++++++++ src/sfizz/Metronome.h | 59 +++++++++ src/sfizz/Resources.h | 9 ++ src/sfizz/Synth.cpp | 31 +++-- src/sfizz/Synth.h | 2 +- src/sfizz/sfizz.cpp | 2 +- src/sfizz/sfizz_wrapper.cpp | 2 +- vst/SfizzVstProcessor.cpp | 2 +- 15 files changed, 604 insertions(+), 19 deletions(-) create mode 100644 src/sfizz/BeatClock.cpp create mode 100644 src/sfizz/BeatClock.h create mode 100644 src/sfizz/Metronome.cpp create mode 100644 src/sfizz/Metronome.h diff --git a/common.mk b/common.mk index 99c0881c..4f3289fa 100644 --- a/common.mk +++ b/common.mk @@ -48,6 +48,7 @@ SFIZZ_CXX_FLAGS = $(SFIZZ_C_FLAGS) SFIZZ_SOURCES = \ src/sfizz/ADSREnvelope.cpp \ src/sfizz/AudioReader.cpp \ + src/sfizz/BeatClock.cpp \ src/sfizz/Curve.cpp \ src/sfizz/effects/Apan.cpp \ src/sfizz/Effects.cpp \ @@ -90,6 +91,7 @@ SFIZZ_SOURCES = \ src/sfizz/LFO.cpp \ src/sfizz/LFODescription.cpp \ src/sfizz/Messaging.cpp \ + src/sfizz/Metronome.cpp \ src/sfizz/MidiState.cpp \ src/sfizz/OpcodeCleanup.cpp \ src/sfizz/Opcode.cpp \ diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 44d9077a..58edd5bb 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -175,11 +175,11 @@ typedef struct // Timing data int bar; - float bar_beat; + double bar_beat; int beats_per_bar; int beat_unit; - float bpm_tempo; - float speed; + double bpm_tempo; + double speed; // Paths char bundle_path[MAX_BUNDLE_PATH_SIZE]; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8171541..b98fbf7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,6 +21,7 @@ set (SFIZZ_HEADERS sfizz/AudioBuffer.h sfizz/AudioReader.h sfizz/AudioSpan.h + sfizz/BeatClock.h sfizz/Buffer.h sfizz/BufferPool.h sfizz/CCMap.h @@ -79,6 +80,7 @@ set (SFIZZ_HEADERS sfizz/LFO.h sfizz/LFODescription.h sfizz/MathHelpers.h + sfizz/Metronome.h sfizz/MidiState.h sfizz/ModifierHelpers.h sfizz/OnePoleFilter.h @@ -149,6 +151,8 @@ set (SFIZZ_SOURCES sfizz/PowerFollower.cpp sfizz/FlexEGDescription.cpp sfizz/FlexEnvelope.cpp + sfizz/BeatClock.cpp + sfizz/Metronome.cpp sfizz/SynthMessaging.cpp sfizz/modulations/ModId.cpp sfizz/modulations/ModKey.cpp diff --git a/src/sfizz.h b/src/sfizz.h index b20e7eae..953bf2a0 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -375,7 +375,7 @@ SFIZZ_EXPORTED_API void sfizz_send_time_signature(sfizz_synth_t* synth, int dela * @param bar The current bar. * @param bar_beat The fractional position of the current beat within the bar. */ -SFIZZ_EXPORTED_API void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, float bar_beat); +SFIZZ_EXPORTED_API void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, double bar_beat); /** * @brief Send the playback state. diff --git a/src/sfizz.hpp b/src/sfizz.hpp index f86eea8a..3a85e31d 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -344,7 +344,7 @@ public: * @param bar The current bar. * @param barBeat The fractional position of the current beat within the bar. */ - void timePosition(int delay, int bar, float barBeat); + void timePosition(int delay, int bar, double barBeat); /** * @brief Send the playback state. diff --git a/src/sfizz/BeatClock.cpp b/src/sfizz/BeatClock.cpp new file mode 100644 index 00000000..3b35f4e7 --- /dev/null +++ b/src/sfizz/BeatClock.cpp @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "BeatClock.h" +#include "Config.h" +#include "Debug.h" +#include +#include + +namespace sfz { + +bool TimeSignature::operator==(const TimeSignature& other) const +{ + return beatsPerBar == other.beatsPerBar && beatUnit == other.beatUnit; +} + +bool TimeSignature::operator!=(const TimeSignature& other) const +{ + return !operator==(other); +} + +/// +BBT BBT::toSignature(TimeSignature oldSig, TimeSignature newSig) const +{ + double beatsInOldSig = toBeats(oldSig); + double beatsInNewSig = beatsInOldSig * newSig.beatUnit / oldSig.beatUnit; + return BBT::fromBeats(newSig, beatsInNewSig); +} + +double BBT::toBeats(TimeSignature sig) const +{ + return beat + bar * sig.beatsPerBar; +} + +BBT BBT::fromBeats(TimeSignature sig, double beats) +{ + int newBar = static_cast(beats / sig.beatsPerBar); + double newBeat = beats - newBar * sig.beatsPerBar; + return BBT(newBar, newBeat); +} + +double BBT::toBars(TimeSignature sig) const +{ + return bar + beat / sig.beatsPerBar; +} + +/// +constexpr int BeatClock::resolution; + +auto BeatClock::quantize(double beats) -> qbeats_t +{ + double d = beats * (1 << resolution); + d = std::copysign(0.5 + std::fabs(d), d); + return static_cast(d); +} + +template +T BeatClock::dequantize(qbeats_t qbeats) +{ + return qbeats / static_cast(1 << resolution); +} + +/// +BeatClock::BeatClock() +{ + setSampleRate(config::defaultSampleRate); + setSamplesPerBlock(config::defaultSamplesPerBlock); +} + +void BeatClock::clear() +{ + beatsPerSecond_ = 2.0; + timeSig_ = { 4, 4 }; + isPlaying_ = false; + + lastHostPos_ = { 0, 0 }; + lastClientPos_ = { 0, 0 }; +} + +void BeatClock::beginCycle(unsigned numFrames) +{ + currentCycleFrames_ = numFrames; + currentCycleFill_ = 0; + currentCycleStartPos_ = lastClientPos_; +} + +void BeatClock::endCycle() +{ + fillBufferUpTo(currentCycleFrames_); +} + +void BeatClock::setSampleRate(double sampleRate) +{ + samplePeriod_ = 1.0 / sampleRate; +} + +void BeatClock::setSamplesPerBlock(unsigned samplesPerBlock) +{ + runningBeat_.resize(samplesPerBlock); + runningBeatsPerBar_.resize(samplesPerBlock); +} + +void BeatClock::setTempo(unsigned delay, double secondsPerBeat) +{ + fillBufferUpTo(delay); + + beatsPerSecond_ = 1.0 / secondsPerBeat; +} + +void BeatClock::setTimeSignature(unsigned delay, TimeSignature newSig) +{ + fillBufferUpTo(delay); + + if (!newSig.valid()) { + CHECKFALSE; + return; + } + + TimeSignature oldSig = timeSig_; + if (oldSig == newSig) + return; + + timeSig_ = newSig; + + // convert time to new signature + lastHostPos_ = lastHostPos_.toSignature(oldSig, newSig); + lastClientPos_ = lastClientPos_.toSignature(oldSig, newSig); +} + +void BeatClock::setTimePosition(unsigned delay, BBT newPos) +{ + fillBufferUpTo(delay); + + lastHostPos_ = newPos; + + // apply host position in the next frame + mustApplyHostPos_ = true; +} + +void BeatClock::setPlaying(unsigned delay, bool playing) +{ + fillBufferUpTo(delay); + + isPlaying_ = playing; +} + +absl::Span BeatClock::getRunningBeat() +{ + fillBufferUpTo(currentCycleFrames_); + + return absl::MakeConstSpan(runningBeat_.data(), currentCycleFrames_); +} + +absl::Span BeatClock::getRunningBeatsPerBar() +{ + fillBufferUpTo(currentCycleFrames_); + + return absl::MakeConstSpan(runningBeatsPerBar_.data(), currentCycleFrames_); +} + +void BeatClock::fillBufferUpTo(unsigned delay) +{ + int *beatData = runningBeat_.data(); + int *beatsPerBarData = runningBeatsPerBar_.data(); + unsigned fill = currentCycleFill_; + + const TimeSignature sig = timeSig_; + for (unsigned i = fill; i < delay; ++i) + beatsPerBarData[i] = sig.beatsPerBar; + + if (!isPlaying_) { + for (; fill < delay; ++fill) + beatData[fill] = 0; + currentCycleFill_ = fill; + return; + } + + BBT clientPos = lastClientPos_; + const double beatsPerFrame = beatsPerSecond_ * samplePeriod_; + + const BBT hostPos = lastHostPos_; + bool mustApplyHostPos = mustApplyHostPos_; + + for (; fill < delay; ++fill) { + clientPos = BBT::fromBeats(sig, clientPos.toBeats(sig) + beatsPerFrame); + clientPos = mustApplyHostPos ? hostPos : clientPos; + mustApplyHostPos = false; + + // quantization to nearest for prevention of rounding errors + beatData[fill] = dequantize(quantize(clientPos.toBeats(sig))); + +#if 0 + BBT oldClientPos = clientPos; + + // quantization to nearest for prevention of rounding errors + qbeats_t oldQbeats = quantize(oldClientPos.toBeats(sig)); + qbeats_t qbeats = quantize(clientPos.toBeats(sig)); + + int oldBeatNumber = dequantize(oldQbeats); + int beatNumber = dequantize(qbeats); + + int beatIncrement = std::max(0, beatNumber - oldBeatNumber); + int beatDistanceToNextBar = sig.beatsPerBar - (oldBeatNumber % sig.beatsPerBar); + int barIncrement = (beatIncrement < beatDistanceToNextBar) ? 0 : + (1 + (beatIncrement - beatDistanceToNextBar) / sig.beatsPerBar); + + beatData[fill] = beatIncrement; + barData[fill] = barIncrement; +#endif + } + + currentCycleFill_ = fill; + lastClientPos_ = clientPos; + mustApplyHostPos_ = mustApplyHostPos; +} + +} // namespace sfz + +std::ostream& operator<<(std::ostream& os, const sfz::BBT& pos) +{ + return os << pos.bar << ':' << std::fixed << pos.beat; +} + +std::ostream& operator<<(std::ostream& os, const sfz::TimeSignature& sig) +{ + return os << sig.beatsPerBar << '/' << sig.beatUnit; +} diff --git a/src/sfizz/BeatClock.h b/src/sfizz/BeatClock.h new file mode 100644 index 00000000..e5fbfcba --- /dev/null +++ b/src/sfizz/BeatClock.h @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include +#include + +namespace sfz { + +/** + * @brief Musical time signature + */ +struct TimeSignature { + TimeSignature() {} + TimeSignature(int beatsPerBar, int beatUnit) : beatsPerBar(beatsPerBar), beatUnit(beatUnit) {} + + /** + * @brief Check the signature validity. + * Valid signatures have a strictly positive numerator and denominator. + */ + bool valid() const { return beatsPerBar > 0 && beatUnit > 0; } + + bool operator==(const TimeSignature& other) const; + bool operator!=(const TimeSignature& other) const; + + /** + * @brief Time signature numerator, indicating the number of beats in a bar + */ + int beatsPerBar = 0; + /** + * @brief Time signature denominator, indicating the type of note (4=quarter) + */ + int beatUnit = 0; +}; + +/** + * @brief Musical time in BBT form + */ +struct BBT { + BBT() {} + BBT(int bar, double beat) : bar(bar), beat(beat) {} + + /** + * @brief Convert the time to a different signature. + */ + BBT toSignature(TimeSignature oldSig, TimeSignature newSig) const; + /** + * @brief Convert the time to a fractional quantity in beats. + */ + double toBeats(TimeSignature sig) const; + /** + * @brief Convert the time to a fractional quantity in bars. + */ + double toBars(TimeSignature sig) const; + /** + * @brief Convert the fractional quantity in beats to musical time. + */ + static BBT fromBeats(TimeSignature sig, double beats); + + /** + * @brief Bar number + */ + int bar = 0; + /** + * @brief Beat and tick, stored in the integral and fractional parts + */ + double beat = 0; +}; + +class BeatClock { +public: + BeatClock(); + + /** + * @brief Set the sample rate. + */ + void setSampleRate(double sampleRate); + /** + * @brief Set the block size. + */ + void setSamplesPerBlock(unsigned samplesPerBlock); + /** + * @brief Reinitialize the current state. + */ + void clear(); + /** + * @brief Start a new cycle of clock processing. + */ + void beginCycle(unsigned numFrames); + /** + * @brief End the current cycle of clock processing. + */ + void endCycle(); + /** + * @brief Set the tempo. + */ + void setTempo(unsigned delay, double secondsPerBeat); + /** + * @brief Set the time signature. + */ + void setTimeSignature(unsigned delay, TimeSignature newSig); + /** + * @brief Set the time position. + */ + void setTimePosition(unsigned delay, BBT newPos); + /** + * @brief Set whether the clock is ticking or stopped. + */ + void setPlaying(unsigned delay, bool playing); + /** + * @brief Get the beat number for each frame of the current cycle. + */ + absl::Span getRunningBeat(); + /** + * @brief Get the time signature numerator for each frame of the current cycle. + */ + absl::Span getRunningBeatsPerBar(); + +private: + void fillBufferUpTo(unsigned delay); + +private: + double samplePeriod_ = 0; + + // quantization + typedef int64_t qbeats_t; + static constexpr int resolution = 16; // bits + static qbeats_t quantize(int beats) { return beats * (1 << resolution); } + static qbeats_t quantize(double beats); + template static T dequantize(qbeats_t qbeats); + + // status of current cycle + unsigned currentCycleFrames_ = 0; + unsigned currentCycleFill_ = 0; + BBT currentCycleStartPos_; + + // musical time information from host + double beatsPerSecond_ = 2.0; + TimeSignature timeSig_ { 4, 4 }; + bool isPlaying_ = false; + + // last time position received from host + BBT lastHostPos_; + bool mustApplyHostPos_ = false; + + // plugin-side counter + BBT lastClientPos_; + + std::vector runningBeat_; + std::vector runningBeatsPerBar_; +}; + +} // namespace sfz + +std::ostream& operator<<(std::ostream& os, const sfz::BBT& pos); +std::ostream& operator<<(std::ostream& os, const sfz::TimeSignature& sig); diff --git a/src/sfizz/Metronome.cpp b/src/sfizz/Metronome.cpp new file mode 100644 index 00000000..5b0b1ff0 --- /dev/null +++ b/src/sfizz/Metronome.cpp @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "Metronome.h" +#include "Config.h" + +namespace sfz { + +Metronome::Metronome() +{ + fGain = 0.5f; + init(config::defaultSampleRate); +} + +void Metronome::init(float sampleRate) +{ + fConst0 = std::min(192000.0f, std::max(1.0f, float(sampleRate))); + fConst1 = std::cos((2764.60156f / fConst0)); + fConst2 = std::sqrt(std::max(0.0f, ((fConst1 + 1.0f) / (1.0f - fConst1)))); + fConst3 = (1.0f / fConst2); + fConst4 = std::cos((5529.20312f / fConst0)); + fConst5 = std::sqrt(std::max(0.0f, ((fConst4 + 1.0f) / (1.0f - fConst4)))); + fConst6 = (1.0f / fConst5); + fConst7 = std::max(1.0f, (0.00499999989f * fConst0)); + fConst8 = (1.0f / fConst7); + fConst9 = (1.0f / std::max(1.0f, (0.100000001f * fConst0))); + clear(); +} + +void Metronome::clear() +{ + for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { + iVec0[l0] = 0; + } + for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { + iVec1[l1] = 0; + } + for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { + iVec2[l2] = 0; + } + for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { + iRec0[l3] = 0; + } + for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { + fVec3[l4] = 0.0f; + } + for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { + fRec1[l5] = 0.0f; + } + for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { + fRec2[l6] = 0.0f; + } + for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) { + fVec4[l7] = 0.0f; + } + for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { + fRec3[l8] = 0.0f; + } + for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { + fRec4[l9] = 0.0f; + } + for (int l10 = 0; (l10 < 2); l10 = (l10 + 1)) { + iRec5[l10] = 0; + } +} + +void Metronome::processAdding(const int* beats, const int* beatsPerBar, float* outputL, float* outputR, int numFrames) +{ + float fSlow0 = float(fGain); + for (int i = 0; (i < numFrames); i = (i + 1)) { + int iTemp0 = int(beats[i]); + iVec0[0] = iTemp0; + iVec1[0] = 1; + int iTemp1 = ((iTemp0 - iVec0[1]) > 0); + iVec2[0] = iTemp1; + iRec0[0] = (iTemp1 ? ((iTemp0 % int(beatsPerBar[i])) == 0) : iRec0[1]); + fVec3[0] = fConst2; + float fTemp2 = float((1 - iVec1[1])); + float fTemp3 = (fConst3 * (fRec2[1] * (fTemp2 + fVec3[1]))); + float fTemp4 = (fConst1 * (fTemp3 + fRec1[1])); + fRec1[0] = (fTemp4 + (fTemp2 + fTemp3)); + fRec2[0] = (fTemp4 - fRec1[1]); + fVec4[0] = fConst5; + float fTemp5 = (fConst6 * (fRec4[1] * (fTemp2 + fVec4[1]))); + float fTemp6 = (fConst4 * (fTemp5 + fRec3[1])); + fRec3[0] = (fTemp6 + (fTemp2 + fTemp5)); + fRec4[0] = (fTemp6 - fRec3[1]); + iRec5[0] = (((iRec5[1] + (iRec5[1] > 0)) * (iTemp1 <= iVec2[1])) + (iTemp1 > iVec2[1])); + float fTemp7 = float(iRec5[0]); + float fTemp8 = (fSlow0 * ((iRec0[0] ? (0.0f - (fConst5 * fRec4[0])) : (0.0f - (fConst2 * fRec2[0]))) * std::max(0.0f, std::min((fConst8 * fTemp7), ((fConst9 * (fConst7 - fTemp7)) + 1.0f))))); + outputL[i] += float(fTemp8); + outputR[i] += float(fTemp8); + iVec0[1] = iVec0[0]; + iVec1[1] = iVec1[0]; + iVec2[1] = iVec2[0]; + iRec0[1] = iRec0[0]; + fVec3[1] = fVec3[0]; + fRec1[1] = fRec1[0]; + fRec2[1] = fRec2[0]; + fVec4[1] = fVec4[0]; + fRec3[1] = fRec3[0]; + fRec4[1] = fRec4[0]; + iRec5[1] = iRec5[0]; + } +} + +} // namespace sfz diff --git a/src/sfizz/Metronome.h b/src/sfizz/Metronome.h new file mode 100644 index 00000000..55be83bc --- /dev/null +++ b/src/sfizz/Metronome.h @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include + +namespace sfz { + +class Metronome { +public: + Metronome(); + void init(float sampleRate); + void clear(); + void processAdding(const int* beats, const int* beatsPerBar, float* outputL, float* outputR, int numFrames); + void setGain(float gain) { fGain = gain; } + +private: + float fGain; + int iVec0[2]; + int iVec1[2]; + int iVec2[2]; + int iRec0[2]; + float fConst0; + float fConst1; + float fConst2; + float fVec3[2]; + float fConst3; + float fRec1[2]; + float fRec2[2]; + float fConst4; + float fConst5; + float fVec4[2]; + float fConst6; + float fRec3[2]; + float fRec4[2]; + float fConst7; + float fConst8; + int iRec5[2]; + float fConst9; + + /* + import("stdfaust.lib"); + + process(beats, beatsPerBar) = tone : *(envelope) <: (_, _) with { + gain = hslider("[1] Gain", 0.5, 0.0, 1.0, 0.001); + beatNumber = int(beats); + beatIncrement = beatNumber-beatNumber'; + tone = (os.oscws(440.0), os.oscws(880.0)) : select2(toneSelect); + toneSelect = x letrec { 'x = ba.if(beatIncrement>0, (beatNumber%int(beatsPerBar))==0, x); }; + envelope = (beatIncrement>0) : en.ar(5e-3, 100e-3) : *(gain); + }; + */ +}; + +} // namespace sfz diff --git a/src/sfizz/Resources.h b/src/sfizz/Resources.h index 577ff756..27de6f1c 100644 --- a/src/sfizz/Resources.h +++ b/src/sfizz/Resources.h @@ -13,6 +13,8 @@ #include "Wavetables.h" #include "Curve.h" #include "Tuning.h" +#include "BeatClock.h" +#include "Metronome.h" #include "modulations/ModMatrix.h" #include "absl/types/optional.h" @@ -32,11 +34,15 @@ struct Resources Tuning tuning; absl::optional stretch; ModMatrix modMatrix; + BeatClock beatClock; + Metronome metronome; void setSampleRate(float samplerate) { midiState.setSampleRate(samplerate); modMatrix.setSampleRate(samplerate); + beatClock.setSampleRate(samplerate); + metronome.init(samplerate); } void setSamplesPerBlock(int samplesPerBlock) @@ -44,6 +50,7 @@ struct Resources bufferPool.setBufferSize(samplesPerBlock); midiState.setSamplesPerBlock(samplesPerBlock); modMatrix.setSamplesPerBlock(samplesPerBlock); + beatClock.setSamplesPerBlock(samplesPerBlock); } void clear() @@ -54,6 +61,8 @@ struct Resources logger.clear(); midiState.reset(); modMatrix.clear(); + beatClock.clear(); + metronome.clear(); } }; } diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 3ea3236f..458aca2b 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -856,6 +856,9 @@ void Synth::renderBlock(AudioSpan buffer) noexcept ModMatrix& mm = impl.resources_.modMatrix; mm.beginCycle(numFrames); + BeatClock& bc = impl.resources_.beatClock; + bc.beginCycle(numFrames); + { // Clear effect busses ScopedTiming logger { callbackBreakdown.effects }; for (auto& bus : impl.effectBuses_) { @@ -918,9 +921,20 @@ void Synth::renderBlock(AudioSpan buffer) noexcept // Apply the master volume buffer.applyGain(db2mag(impl.volume_)); + // Process the metronome (debugging tool for host time info) + constexpr bool metronomeEnabled = false; + if (metronomeEnabled) { + impl.resources_.metronome.processAdding( + bc.getRunningBeat().data(), bc.getRunningBeatsPerBar().data(), + buffer.getChannel(0), buffer.getChannel(1), numFrames); + } + // Perform any remaining modulators mm.endCycle(); + // Advance the clock to the end of cycle + bc.endCycle(); + { // Clear events and advance midi time ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; impl.resources_.midiState.advanceTime(buffer.getNumFrames()); @@ -1167,36 +1181,33 @@ void Synth::aftertouch(int /* delay */, uint8_t /* aftertouch */) noexcept Impl& impl = *impl_; ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; } -void Synth::tempo(int /* delay */, float /* secondsPerQuarter */) noexcept +void Synth::tempo(int delay, float secondsPerBeat) noexcept { Impl& impl = *impl_; ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; + + impl.resources_.beatClock.setTempo(delay, secondsPerBeat); } void Synth::timeSignature(int delay, int beatsPerBar, int beatUnit) { Impl& impl = *impl_; ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; - (void)delay; - (void)beatsPerBar; - (void)beatUnit; + impl.resources_.beatClock.setTimeSignature(delay, TimeSignature(beatsPerBar, beatUnit)); } -void Synth::timePosition(int delay, int bar, float barBeat) +void Synth::timePosition(int delay, int bar, double barBeat) { Impl& impl = *impl_; ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; - (void)delay; - (void)bar; - (void)barBeat; + impl.resources_.beatClock.setTimePosition(delay, BBT(bar, barBeat)); } void Synth::playbackState(int delay, int playbackState) { Impl& impl = *impl_; ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; - (void)delay; - (void)playbackState; + impl.resources_.beatClock.setPlaying(delay, playbackState == 1); } int Synth::getNumRegions() const noexcept diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 0e53b17e..6e0a715f 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -396,7 +396,7 @@ public: * @param bar The current bar. * @param bar_beat The fractional position of the current beat within the bar. */ - void timePosition(int delay, int bar, float barBeat); + void timePosition(int delay, int bar, double barBeat); /** * @brief Send the playback state. * diff --git a/src/sfizz/sfizz.cpp b/src/sfizz/sfizz.cpp index 18b2a10c..9ed4a0d8 100644 --- a/src/sfizz/sfizz.cpp +++ b/src/sfizz/sfizz.cpp @@ -164,7 +164,7 @@ void sfz::Sfizz::timeSignature(int delay, int beatsPerBar, int beatUnit) synth->timeSignature(delay, beatsPerBar, beatUnit); } -void sfz::Sfizz::timePosition(int delay, int bar, float barBeat) +void sfz::Sfizz::timePosition(int delay, int bar, double barBeat) { synth->timePosition(delay, bar, barBeat); } diff --git a/src/sfizz/sfizz_wrapper.cpp b/src/sfizz/sfizz_wrapper.cpp index 0ca6de29..3e7088c3 100644 --- a/src/sfizz/sfizz_wrapper.cpp +++ b/src/sfizz/sfizz_wrapper.cpp @@ -166,7 +166,7 @@ void sfizz_send_time_signature(sfizz_synth_t* synth, int delay, int beats_per_ba auto* self = reinterpret_cast(synth); self->timeSignature(delay, beats_per_bar, beat_unit); } -void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, float bar_beat) +void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, double bar_beat) { auto* self = reinterpret_cast(synth); self->timePosition(delay, bar, bar_beat); diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 93969467..0380d3c7 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -286,7 +286,7 @@ void SfizzVstProcessor::updateTimeInfo(const Vst::ProcessContext& context) double beats = context.projectTimeMusic * 0.25 * _timeSigDenominator; double bars = beats / _timeSigNumerator; beats -= int(bars) * _timeSigNumerator; - synth.timePosition(0, int(bars), float(beats)); + synth.timePosition(0, int(bars), beats); } synth.playbackState(0, (context.state & context.kPlaying) != 0); From 04fdfc4de21d4c42f32a06584709dbb62f4cfec0 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 01:00:06 +0100 Subject: [PATCH 090/668] Remove old clock code which suffers rounding errors --- src/sfizz/BeatClock.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/sfizz/BeatClock.cpp b/src/sfizz/BeatClock.cpp index 3b35f4e7..f9ef6c14 100644 --- a/src/sfizz/BeatClock.cpp +++ b/src/sfizz/BeatClock.cpp @@ -191,25 +191,6 @@ void BeatClock::fillBufferUpTo(unsigned delay) // quantization to nearest for prevention of rounding errors beatData[fill] = dequantize(quantize(clientPos.toBeats(sig))); - -#if 0 - BBT oldClientPos = clientPos; - - // quantization to nearest for prevention of rounding errors - qbeats_t oldQbeats = quantize(oldClientPos.toBeats(sig)); - qbeats_t qbeats = quantize(clientPos.toBeats(sig)); - - int oldBeatNumber = dequantize(oldQbeats); - int beatNumber = dequantize(qbeats); - - int beatIncrement = std::max(0, beatNumber - oldBeatNumber); - int beatDistanceToNextBar = sig.beatsPerBar - (oldBeatNumber % sig.beatsPerBar); - int barIncrement = (beatIncrement < beatDistanceToNextBar) ? 0 : - (1 + (beatIncrement - beatDistanceToNextBar) / sig.beatsPerBar); - - beatData[fill] = beatIncrement; - barData[fill] = barIncrement; -#endif } currentCycleFill_ = fill; From e31bf1381feea8a26eebf31024b26a3e1ccbf002 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 11:23:02 +0100 Subject: [PATCH 091/668] Provide the interpolated beat position --- src/sfizz/BeatClock.cpp | 26 +++++++++++++------------- src/sfizz/BeatClock.h | 24 ++++++++++++++++++------ src/sfizz/Synth.cpp | 2 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/sfizz/BeatClock.cpp b/src/sfizz/BeatClock.cpp index f9ef6c14..154cf138 100644 --- a/src/sfizz/BeatClock.cpp +++ b/src/sfizz/BeatClock.cpp @@ -64,12 +64,6 @@ T BeatClock::dequantize(qbeats_t qbeats) } /// -BeatClock::BeatClock() -{ - setSampleRate(config::defaultSampleRate); - setSamplesPerBlock(config::defaultSamplesPerBlock); -} - void BeatClock::clear() { beatsPerSecond_ = 2.0; @@ -99,7 +93,8 @@ void BeatClock::setSampleRate(double sampleRate) void BeatClock::setSamplesPerBlock(unsigned samplesPerBlock) { - runningBeat_.resize(samplesPerBlock); + runningBeatNumber_.resize(samplesPerBlock); + runningBeatPosition_.resize(samplesPerBlock); runningBeatsPerBar_.resize(samplesPerBlock); } @@ -147,11 +142,11 @@ void BeatClock::setPlaying(unsigned delay, bool playing) isPlaying_ = playing; } -absl::Span BeatClock::getRunningBeat() +absl::Span BeatClock::getRunningBeatNumber() { fillBufferUpTo(currentCycleFrames_); - return absl::MakeConstSpan(runningBeat_.data(), currentCycleFrames_); + return absl::MakeConstSpan(runningBeatNumber_.data(), currentCycleFrames_); } absl::Span BeatClock::getRunningBeatsPerBar() @@ -163,7 +158,8 @@ absl::Span BeatClock::getRunningBeatsPerBar() void BeatClock::fillBufferUpTo(unsigned delay) { - int *beatData = runningBeat_.data(); + int *beatNumberData = runningBeatNumber_.data(); + float *beatNumberPosition = runningBeatPosition_.data(); int *beatsPerBarData = runningBeatsPerBar_.data(); unsigned fill = currentCycleFill_; @@ -172,8 +168,10 @@ void BeatClock::fillBufferUpTo(unsigned delay) beatsPerBarData[i] = sig.beatsPerBar; if (!isPlaying_) { - for (; fill < delay; ++fill) - beatData[fill] = 0; + for (; fill < delay; ++fill) { + beatNumberData[fill] = 0; + beatNumberPosition[fill] = 0; + } currentCycleFill_ = fill; return; } @@ -190,7 +188,9 @@ void BeatClock::fillBufferUpTo(unsigned delay) mustApplyHostPos = false; // quantization to nearest for prevention of rounding errors - beatData[fill] = dequantize(quantize(clientPos.toBeats(sig))); + double beats = clientPos.toBeats(sig); + beatNumberData[fill] = dequantize(quantize(beats)); + beatNumberPosition[fill] = static_cast(beats); } currentCycleFill_ = fill; diff --git a/src/sfizz/BeatClock.h b/src/sfizz/BeatClock.h index e5fbfcba..b75ba182 100644 --- a/src/sfizz/BeatClock.h +++ b/src/sfizz/BeatClock.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "Buffer.h" #include #include #include @@ -73,8 +74,6 @@ struct BBT { class BeatClock { public: - BeatClock(); - /** * @brief Set the sample rate. */ @@ -113,8 +112,20 @@ public: void setPlaying(unsigned delay, bool playing); /** * @brief Get the beat number for each frame of the current cycle. + * + * This signal is quantized to a fixed resolution, such that it never + * suffers 1-off errors due to imprecision in the host time position. */ - absl::Span getRunningBeat(); + absl::Span getRunningBeatNumber(); + /** + * @brief Get the beat position for each frame of the current cycle. + * + * This is a fractional equivalent of the beat number, however the beat + * boundaries can be traversed erratically due to approximation errors. + * If you need to perform work on exact beat transitions, prefer + * `getRunningBeatNumber` instead. + */ + absl::Span getRunningBeatPosition(); /** * @brief Get the time signature numerator for each frame of the current cycle. */ @@ -124,7 +135,7 @@ private: void fillBufferUpTo(unsigned delay); private: - double samplePeriod_ = 0; + double samplePeriod_ { 1.0 / config::defaultSampleRate }; // quantization typedef int64_t qbeats_t; @@ -150,8 +161,9 @@ private: // plugin-side counter BBT lastClientPos_; - std::vector runningBeat_; - std::vector runningBeatsPerBar_; + Buffer runningBeatNumber_ { config::defaultSamplesPerBlock }; + Buffer runningBeatPosition_ { config::defaultSamplesPerBlock }; + Buffer runningBeatsPerBar_ { config::defaultSamplesPerBlock }; }; } // namespace sfz diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 458aca2b..92fdc619 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -925,7 +925,7 @@ void Synth::renderBlock(AudioSpan buffer) noexcept constexpr bool metronomeEnabled = false; if (metronomeEnabled) { impl.resources_.metronome.processAdding( - bc.getRunningBeat().data(), bc.getRunningBeatsPerBar().data(), + bc.getRunningBeatNumber().data(), bc.getRunningBeatsPerBar().data(), buffer.getChannel(0), buffer.getChannel(1), numFrames); } From ee056bcea828e373605ec1cdd81d53dd421472b3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 11:27:34 +0100 Subject: [PATCH 092/668] Use SIMD helpers for zero-filling --- src/sfizz/BeatClock.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sfizz/BeatClock.cpp b/src/sfizz/BeatClock.cpp index 154cf138..32e997c7 100644 --- a/src/sfizz/BeatClock.cpp +++ b/src/sfizz/BeatClock.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "BeatClock.h" +#include "SIMDHelpers.h" #include "Config.h" #include "Debug.h" #include @@ -161,18 +162,18 @@ void BeatClock::fillBufferUpTo(unsigned delay) int *beatNumberData = runningBeatNumber_.data(); float *beatNumberPosition = runningBeatPosition_.data(); int *beatsPerBarData = runningBeatsPerBar_.data(); - unsigned fill = currentCycleFill_; + unsigned fillIdx = currentCycleFill_; const TimeSignature sig = timeSig_; - for (unsigned i = fill; i < delay; ++i) + for (unsigned i = fillIdx; i < delay; ++i) beatsPerBarData[i] = sig.beatsPerBar; if (!isPlaying_) { - for (; fill < delay; ++fill) { - beatNumberData[fill] = 0; - beatNumberPosition[fill] = 0; + if (fillIdx < delay) { + fill(absl::MakeSpan(&beatNumberData[fillIdx], delay - fillIdx), 0); + fill(absl::MakeSpan(&beatNumberPosition[fillIdx], delay - fillIdx), 0.0f); } - currentCycleFill_ = fill; + currentCycleFill_ = fillIdx; return; } @@ -182,18 +183,18 @@ void BeatClock::fillBufferUpTo(unsigned delay) const BBT hostPos = lastHostPos_; bool mustApplyHostPos = mustApplyHostPos_; - for (; fill < delay; ++fill) { + for (; fillIdx < delay; ++fillIdx) { clientPos = BBT::fromBeats(sig, clientPos.toBeats(sig) + beatsPerFrame); clientPos = mustApplyHostPos ? hostPos : clientPos; mustApplyHostPos = false; // quantization to nearest for prevention of rounding errors double beats = clientPos.toBeats(sig); - beatNumberData[fill] = dequantize(quantize(beats)); - beatNumberPosition[fill] = static_cast(beats); + beatNumberData[fillIdx] = dequantize(quantize(beats)); + beatNumberPosition[fillIdx] = static_cast(beats); } - currentCycleFill_ = fill; + currentCycleFill_ = fillIdx; lastClientPos_ = clientPos; mustApplyHostPos_ = mustApplyHostPos; } From 1983894bc8c4fdb085775c9510fd7f2278592596 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 12:04:01 +0100 Subject: [PATCH 093/668] Add the phase generator by beat clock --- src/sfizz/BeatClock.cpp | 34 ++++++++++++++++++++++++++++++++++ src/sfizz/BeatClock.h | 10 ++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/sfizz/BeatClock.cpp b/src/sfizz/BeatClock.cpp index 32e997c7..acc5e382 100644 --- a/src/sfizz/BeatClock.cpp +++ b/src/sfizz/BeatClock.cpp @@ -199,6 +199,40 @@ void BeatClock::fillBufferUpTo(unsigned delay) mustApplyHostPos_ = mustApplyHostPos; } +void BeatClock::calculatePhase(float beatPeriod, float* phaseOut) +{ + const unsigned numFrames = currentCycleFrames_; + + if (beatPeriod == 0.0f) { + fill(absl::MakeSpan(phaseOut, numFrames), 0.0f); + return; + } + + const float invBeatPeriod = 1.0f / beatPeriod; + const float* beatPositionData = getRunningBeatPosition().data(); + + for (unsigned i = 0; i < numFrames; ++i) { + float beatPosition = std::max(0.0f, beatPositionData[i]); + float phase = beatPosition * invBeatPeriod; + phase -= static_cast(phase); + phaseOut[i] = phase; + } +} + +void BeatClock::calculatePhaseModulated(const float* beatPeriodData, float* phaseOut) +{ + const unsigned numFrames = currentCycleFrames_; + const float* beatPositionData = getRunningBeatPosition().data(); + + for (unsigned i = 0; i < numFrames; ++i) { + float beatPeriod = beatPeriodData[i]; + float beatPosition = std::max(0.0f, beatPositionData[i]); + float phase = beatPosition / beatPeriod; + phase -= static_cast(phase); + phaseOut[i] = (beatPeriod != 0.0f) ? phase : 0.0f; + } +} + } // namespace sfz std::ostream& operator<<(std::ostream& os, const sfz::BBT& pos) diff --git a/src/sfizz/BeatClock.h b/src/sfizz/BeatClock.h index b75ba182..cccc76e8 100644 --- a/src/sfizz/BeatClock.h +++ b/src/sfizz/BeatClock.h @@ -130,6 +130,16 @@ public: * @brief Get the time signature numerator for each frame of the current cycle. */ absl::Span getRunningBeatsPerBar(); + /** + * @brief Create a normalized phase signal for LFO which completes a + * period every N-th beat. + */ + void calculatePhase(float beatPeriod, float* phaseOut); + /** + * @brief Create a normalized phase signal for LFO which completes a + * period every N-th beat, where N can vary over time. + */ + void calculatePhaseModulated(const float* beatPeriodData, float* phaseOut); private: void fillBufferUpTo(unsigned delay); From 1d2ffaf4300fdac64a3b56231e61e791312488a7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 12:46:32 +0100 Subject: [PATCH 094/668] Add the missing implementation of getRunningBeatPosition --- src/sfizz/BeatClock.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sfizz/BeatClock.cpp b/src/sfizz/BeatClock.cpp index acc5e382..126c6ca6 100644 --- a/src/sfizz/BeatClock.cpp +++ b/src/sfizz/BeatClock.cpp @@ -150,6 +150,13 @@ absl::Span BeatClock::getRunningBeatNumber() return absl::MakeConstSpan(runningBeatNumber_.data(), currentCycleFrames_); } +absl::Span BeatClock::getRunningBeatPosition() +{ + fillBufferUpTo(currentCycleFrames_); + + return absl::MakeConstSpan(runningBeatPosition_.data(), currentCycleFrames_); +} + absl::Span BeatClock::getRunningBeatsPerBar() { fillBufferUpTo(currentCycleFrames_); From 7ded48b7d436fd4c1f5b1d7812e99089706d1b7e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 14:38:05 +0100 Subject: [PATCH 095/668] Revise the range check of beatPeriod --- src/sfizz/BeatClock.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sfizz/BeatClock.cpp b/src/sfizz/BeatClock.cpp index 126c6ca6..70ef5856 100644 --- a/src/sfizz/BeatClock.cpp +++ b/src/sfizz/BeatClock.cpp @@ -210,7 +210,7 @@ void BeatClock::calculatePhase(float beatPeriod, float* phaseOut) { const unsigned numFrames = currentCycleFrames_; - if (beatPeriod == 0.0f) { + if (beatPeriod <= 0.0f) { fill(absl::MakeSpan(phaseOut, numFrames), 0.0f); return; } @@ -236,7 +236,7 @@ void BeatClock::calculatePhaseModulated(const float* beatPeriodData, float* phas float beatPosition = std::max(0.0f, beatPositionData[i]); float phase = beatPosition / beatPeriod; phase -= static_cast(phase); - phaseOut[i] = (beatPeriod != 0.0f) ? phase : 0.0f; + phaseOut[i] = (beatPeriod > 0.0f) ? phase : 0.0f; } } From 574691d3cd888f253fe3d147c3f2a8183685d88c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 14:46:11 +0100 Subject: [PATCH 096/668] Add a helper to check whether the transport plays --- src/sfizz/BeatClock.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sfizz/BeatClock.h b/src/sfizz/BeatClock.h index cccc76e8..880c2134 100644 --- a/src/sfizz/BeatClock.h +++ b/src/sfizz/BeatClock.h @@ -110,6 +110,10 @@ public: * @brief Set whether the clock is ticking or stopped. */ void setPlaying(unsigned delay, bool playing); + /** + * Check whether the clock is currently ticking. + */ + bool isPlaying() const noexcept { return isPlaying_; } /** * @brief Get the beat number for each frame of the current cycle. * From c1306f8a71a4134bce8c67ed113914f01405fea9 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 13:23:59 +0100 Subject: [PATCH 097/668] lfo: decouple the wave generator and the phase generator --- demos/PlotLFO.cpp | 14 +++-- src/sfizz/BufferPool.h | 1 + src/sfizz/LFO.cpp | 132 +++++++++++++++++++++++------------------ src/sfizz/LFO.h | 14 +++-- src/sfizz/Voice.cpp | 2 +- tests/LFOT.cpp | 13 ++-- 6 files changed, 104 insertions(+), 72 deletions(-) diff --git a/demos/PlotLFO.cpp b/demos/PlotLFO.cpp index c55a192f..61ca0371 100644 --- a/demos/PlotLFO.cpp +++ b/demos/PlotLFO.cpp @@ -108,25 +108,29 @@ int main(int argc, char* argv[]) return 1; } + sfz::BufferPool bufferPool; + size_t numLfos = desc.size(); - std::vector lfos(numLfos); + std::vector> lfos(numLfos); for (size_t l = 0; l < numLfos; ++l) { - lfos[l].setSampleRate(sampleRate); - lfos[l].configure(&desc[l]); + sfz::LFO* lfo = new sfz::LFO(bufferPool); + lfos[l].reset(lfo); + lfo->setSampleRate(sampleRate); + lfo->configure(&desc[l]); } size_t numFrames = (size_t)std::ceil(sampleRate * duration); std::vector outputMemory(numLfos * numFrames); for (size_t l = 0; l < numLfos; ++l) { - lfos[l].start(0); + lfos[l]->start(0); } std::vector> lfoOutputs(numLfos); for (size_t l = 0; l < numLfos; ++l) { lfoOutputs[l] = absl::MakeSpan(&outputMemory[l * numFrames], numFrames); - lfos[l].process(lfoOutputs[l]); + lfos[l]->process(lfoOutputs[l]); } if (saveFlac) { diff --git a/src/sfizz/BufferPool.h b/src/sfizz/BufferPool.h index b9971fcf..e1e253e8 100644 --- a/src/sfizz/BufferPool.h +++ b/src/sfizz/BufferPool.h @@ -9,6 +9,7 @@ #include "Debug.h" #include "Buffer.h" #include "AudioBuffer.h" +#include "AudioSpan.h" #include #include #include diff --git a/src/sfizz/LFO.cpp b/src/sfizz/LFO.cpp index 06c823b5..ce2a2a38 100644 --- a/src/sfizz/LFO.cpp +++ b/src/sfizz/LFO.cpp @@ -6,6 +6,7 @@ #include "LFO.h" #include "LFODescription.h" +#include "BufferPool.h" #include "MathHelpers.h" #include "SIMDHelpers.h" #include "Config.h" @@ -16,6 +17,14 @@ namespace sfz { struct LFO::Impl { + explicit Impl(BufferPool& bufferPool) + : bufferPool_(bufferPool), + sampleRate_(config::defaultSampleRate), + desc_(&LFODescription::getDefault()) + { + } + + BufferPool& bufferPool_; float sampleRate_ = 0; // control @@ -26,13 +35,12 @@ struct LFO::Impl { float fadePosition_ = 0; std::array subPhases_ {{}}; std::array sampleHoldMem_ {{}}; + std::array sampleHoldState_ {{}}; }; -LFO::LFO() - : impl_(new Impl) +LFO::LFO(BufferPool& bufferPool) + : impl_(new Impl(bufferPool)) { - impl_->sampleRate_ = config::defaultSampleRate; - impl_->desc_ = &LFODescription::getDefault(); } LFO::~LFO() @@ -55,8 +63,9 @@ void LFO::start(unsigned triggerDelay) const LFODescription& desc = *impl.desc_; const float sampleRate = impl.sampleRate_; - impl.subPhases_.fill(desc.phase0); + impl.subPhases_.fill(0.0f); impl.sampleHoldMem_.fill(0.0f); + impl.sampleHoldState_.fill(0); const float delay = desc.delay; size_t delayFrames = (delay > 0) ? static_cast(std::ceil(sampleRate * delay)) : 0u; @@ -118,75 +127,57 @@ inline float LFO::eval(float phase) } template -void LFO::processWave(unsigned nth, absl::Span out) +void LFO::processWave(unsigned nth, absl::Span out, const float* phaseIn) { Impl& impl = *impl_; const LFODescription& desc = *impl.desc_; const LFODescription::Sub& sub = desc.sub[nth]; const size_t numFrames = out.size(); - const float samplePeriod = 1.0f / impl.sampleRate_; - const float baseFreq = desc.freq; const float offset = sub.offset; - const float ratio = sub.ratio; const float scale = sub.scale; - float phase = impl.subPhases_[nth]; for (size_t i = 0; i < numFrames; ++i) { + float phase = phaseIn[i]; out[i] += offset + scale * eval(phase); - - // TODO(jpc) lfoN_count: number of repetitions - - float incrPhase = ratio * samplePeriod * baseFreq; - phase += incrPhase; - int numWraps = (int)phase; - phase -= numWraps; } - - impl.subPhases_[nth] = phase; } template -void LFO::processSH(unsigned nth, absl::Span out) +void LFO::processSH(unsigned nth, absl::Span out, const float* phaseIn) { Impl& impl = *impl_; const LFODescription& desc = *impl.desc_; const LFODescription::Sub& sub = desc.sub[nth]; const size_t numFrames = out.size(); - const float samplePeriod = 1.0f / impl.sampleRate_; - const float baseFreq = desc.freq; const float offset = sub.offset; - const float ratio = sub.ratio; const float scale = sub.scale; float sampleHoldValue = impl.sampleHoldMem_[nth]; - float phase = impl.subPhases_[nth]; + int sampleHoldState = impl.sampleHoldState_[nth]; for (size_t i = 0; i < numFrames; ++i) { out[i] += offset + scale * sampleHoldValue; // TODO(jpc) lfoN_count: number of repetitions - float incrPhase = ratio * samplePeriod * baseFreq; + float phase = phaseIn[i]; + + int oldState = sampleHoldState; + sampleHoldState = phase > 0.5f; // value updates twice every period - bool updateValue = (int)(phase * 2.0) != (int)((phase + incrPhase) * 2.0); - - phase += incrPhase; - int numWraps = (int)phase; - phase -= numWraps; - - if (updateValue) { + if (sampleHoldState != oldState) { std::uniform_real_distribution dist(-1.0f, +1.0f); sampleHoldValue = dist(Random::randomGenerator); } } - impl.subPhases_[nth] = phase; impl.sampleHoldMem_[nth] = sampleHoldValue; + impl.sampleHoldState_[nth] = sampleHoldState; } -void LFO::processSteps(absl::Span out) +void LFO::processSteps(absl::Span out, const float* phaseIn) { unsigned nth = 0; Impl& impl = *impl_; @@ -201,26 +192,14 @@ void LFO::processSteps(absl::Span out) if (numSteps <= 0) return; - const float samplePeriod = 1.0f / impl.sampleRate_; - const float baseFreq = desc.freq; const float offset = sub.offset; - const float ratio = sub.ratio; const float scale = sub.scale; - float phase = impl.subPhases_[nth]; for (size_t i = 0; i < numFrames; ++i) { + float phase = phaseIn[i]; float step = steps[static_cast(phase * numSteps)]; out[i] += offset + scale * step; - - // TODO(jpc) lfoN_count: number of repetitions - - float incrPhase = ratio * samplePeriod * baseFreq; - phase += incrPhase; - int numWraps = (int)phase; - phase -= numWraps; } - - impl.subPhases_[nth] = phase; } void LFO::process(absl::Span out) @@ -244,39 +223,50 @@ void LFO::process(absl::Span out) if (countSubs < 1) return; + auto phasesTemp = impl.bufferPool_.getBuffer(numFrames); + if (!phasesTemp) { + ASSERTFALSE; + fill(out, 0.0f); + return; + } + + absl::Span phases = *phasesTemp; + if (desc.seq) { - processSteps(out); + generatePhase(0, phases); + processSteps(out, phases.data()); ++subno; } for (; subno < countSubs; ++subno) { + generatePhase(subno, phases); switch (desc.sub[subno].wave) { case LFOWave::Triangle: - processWave(subno, out); + processWave(subno, out, phases.data()); break; case LFOWave::Sine: - processWave(subno, out); + processWave(subno, out, phases.data()); break; case LFOWave::Pulse75: - processWave(subno, out); + processWave(subno, out, phases.data()); break; case LFOWave::Square: - processWave(subno, out); + processWave(subno, out, phases.data()); break; case LFOWave::Pulse25: - processWave(subno, out); + processWave(subno, out, phases.data()); break; case LFOWave::Pulse12_5: - processWave(subno, out); + processWave(subno, out, phases.data()); break; case LFOWave::Ramp: - processWave(subno, out); + processWave(subno, out, phases.data()); break; case LFOWave::Saw: - processWave(subno, out); + processWave(subno, out, phases.data()); break; case LFOWave::RandomSH: - processSH(subno, out); + processSH(subno, out, phases.data()); break; } } @@ -306,4 +296,32 @@ void LFO::processFadeIn(absl::Span out) impl.fadePosition_ = fadePosition; } +void LFO::generatePhase(unsigned nth, absl::Span phases) +{ + Impl& impl = *impl_; + const LFODescription& desc = *impl.desc_; + const LFODescription::Sub& sub = desc.sub[nth]; + const float samplePeriod = 1.0f / impl.sampleRate_; + const float baseFreq = desc.freq; + const float phaseOffset = desc.phase0; + const float ratio = sub.ratio; + float phase = impl.subPhases_[nth]; + + for (size_t i = 0, n = phases.size(); i < n; ++i) { + float withOffset = phase + phaseOffset; + withOffset -= (int)withOffset; + + phases[i] = withOffset; + + // TODO(jpc) lfoN_count: number of repetitions + + float incr = ratio * samplePeriod * baseFreq; + phase += incr; + int numWraps = (int)phase; + phase -= numWraps; + } + + impl.subPhases_[nth] = phase; +} + } // namespace sfz diff --git a/src/sfizz/LFO.h b/src/sfizz/LFO.h index 7a43fd13..764cd65a 100644 --- a/src/sfizz/LFO.h +++ b/src/sfizz/LFO.h @@ -9,6 +9,7 @@ #include namespace sfz { +class BufferPool; enum class LFOWave : int; struct LFODescription; @@ -49,7 +50,7 @@ struct LFODescription; class LFO { public: - LFO(); + explicit LFO(BufferPool& bufferPool); ~LFO(); /** @@ -91,24 +92,29 @@ private: on wave type inside the frame loop. */ template - void processWave(unsigned nth, absl::Span out); + void processWave(unsigned nth, absl::Span out, const float* phaseIn); /** Process a sample-and-hold subwaveform, adding to the buffer. */ template - void processSH(unsigned nth, absl::Span out); + void processSH(unsigned nth, absl::Span out, const float* phaseIn); /** Process the step sequencer, adding to the buffer. */ - void processSteps(absl::Span out); + void processSteps(absl::Span out, const float* phaseIn); /** Process the fade in gain, and apply it to the buffer. */ void processFadeIn(absl::Span out); + /** + Generate the phase of the N-th generator + */ + void generatePhase(unsigned nth, absl::Span phases); + private: struct Impl; std::unique_ptr impl_; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 7940908e..45976aea 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1478,7 +1478,7 @@ void Voice::setMaxLFOsPerVoice(size_t numLFOs) impl.lfos_.resize(numLFOs); for (size_t i = 0; i < numLFOs; ++i) { - auto lfo = absl::make_unique(); + auto lfo = absl::make_unique(impl.resources_.bufferPool); lfo->setSampleRate(impl.sampleRate_); impl.lfos_[i] = std::move(lfo); } diff --git a/tests/LFOT.cpp b/tests/LFOT.cpp index 9a7ac3ab..e2a625f4 100644 --- a/tests/LFOT.cpp +++ b/tests/LFOT.cpp @@ -13,6 +13,7 @@ static bool computeLFO(DataPoints& dp, const fs::path& sfzPath, double sampleRate, size_t numFrames) { sfz::Synth synth; + sfz::Resources& resources = synth.getResources(); if (!synth.loadSfzFile(sfzPath)) return false; @@ -22,23 +23,25 @@ static bool computeLFO(DataPoints& dp, const fs::path& sfzPath, double sampleRat const std::vector& desc = synth.getRegionView(0)->lfos; size_t numLfos = desc.size(); - std::vector lfos(numLfos); + std::vector> lfos(numLfos); for (size_t l = 0; l < numLfos; ++l) { - lfos[l].setSampleRate(sampleRate); - lfos[l].configure(&desc[l]); + sfz::LFO* lfo = new sfz::LFO(resources.bufferPool); + lfos[l].reset(lfo); + lfo->setSampleRate(sampleRate); + lfo->configure(&desc[l]); } std::vector outputMemory(numLfos * numFrames); for (size_t l = 0; l < numLfos; ++l) { - lfos[l].start(0); + lfos[l]->start(0); } std::vector> lfoOutputs(numLfos); for (size_t l = 0; l < numLfos; ++l) { lfoOutputs[l] = absl::MakeSpan(&outputMemory[l * numFrames], numFrames); - lfos[l].process(lfoOutputs[l]); + lfos[l]->process(lfoOutputs[l]); } dp.rows = numFrames; From d8dcb2e56f8f21dba87b8be161a5a257e0a61f66 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 15:00:51 +0100 Subject: [PATCH 098/668] Implement lfoN_beats --- src/sfizz/Defaults.h | 1 + src/sfizz/LFO.cpp | 47 ++++++++++++++++++++++++++++---------- src/sfizz/LFO.h | 5 +++- src/sfizz/LFODescription.h | 1 + src/sfizz/Region.cpp | 10 ++++++++ src/sfizz/Voice.cpp | 4 +++- 6 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 290c1248..f20db102 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -222,6 +222,7 @@ namespace Default constexpr int numLFOSubs { 2 }; constexpr int numLFOSteps { 8 }; constexpr Range lfoFreqRange { 0.0, 100.0 }; + constexpr Range lfoBeatsRange { 0.0, 1000.0 }; constexpr Range lfoPhaseRange { 0.0, 1.0 }; constexpr Range lfoDelayRange { 0.0, 30.0 }; constexpr Range lfoFadeRange { 0.0, 30.0 }; diff --git a/src/sfizz/LFO.cpp b/src/sfizz/LFO.cpp index ce2a2a38..6dd5c168 100644 --- a/src/sfizz/LFO.cpp +++ b/src/sfizz/LFO.cpp @@ -6,6 +6,7 @@ #include "LFO.h" #include "LFODescription.h" +#include "BeatClock.h" #include "BufferPool.h" #include "MathHelpers.h" #include "SIMDHelpers.h" @@ -17,14 +18,16 @@ namespace sfz { struct LFO::Impl { - explicit Impl(BufferPool& bufferPool) + explicit Impl(BufferPool& bufferPool, BeatClock* beatClock) : bufferPool_(bufferPool), + beatClock_(beatClock), sampleRate_(config::defaultSampleRate), desc_(&LFODescription::getDefault()) { } BufferPool& bufferPool_; + BeatClock* beatClock_ = nullptr; float sampleRate_ = 0; // control @@ -38,8 +41,8 @@ struct LFO::Impl { std::array sampleHoldState_ {{}}; }; -LFO::LFO(BufferPool& bufferPool) - : impl_(new Impl(bufferPool)) +LFO::LFO(BufferPool& bufferPool, BeatClock* beatClock) + : impl_(new Impl(bufferPool, beatClock)) { } @@ -299,26 +302,46 @@ void LFO::processFadeIn(absl::Span out) void LFO::generatePhase(unsigned nth, absl::Span phases) { Impl& impl = *impl_; + BeatClock* beatClock = impl.beatClock_; const LFODescription& desc = *impl.desc_; const LFODescription::Sub& sub = desc.sub[nth]; const float samplePeriod = 1.0f / impl.sampleRate_; const float baseFreq = desc.freq; + const float beats = desc.beats; const float phaseOffset = desc.phase0; const float ratio = sub.ratio; float phase = impl.subPhases_[nth]; + const size_t numFrames = phases.size(); - for (size_t i = 0, n = phases.size(); i < n; ++i) { - float withOffset = phase + phaseOffset; - withOffset -= (int)withOffset; + if (beatClock && beatClock->isPlaying() && beats > 0) { + // generate using the beat clock + float beatRatio = (ratio > 0) ? (1.0f / ratio) : 0.0f; + beatClock->calculatePhase(beats * beatRatio, phases.data()); - phases[i] = withOffset; + for (size_t i = 0; i < numFrames; ++i) { + float withOffset = phase + phaseOffset; + withOffset -= (int)withOffset; - // TODO(jpc) lfoN_count: number of repetitions + phases[i] = withOffset; - float incr = ratio * samplePeriod * baseFreq; - phase += incr; - int numWraps = (int)phase; - phase -= numWraps; + // TODO(jpc) lfoN_count: number of repetitions + } + } + else { + // generate using the frequency + for (size_t i = 0; i < numFrames; ++i) { + float withOffset = phase + phaseOffset; + withOffset -= (int)withOffset; + + phases[i] = withOffset; + + // TODO(jpc) lfoN_count: number of repetitions + + float incr = ratio * samplePeriod * baseFreq; + phase += incr; + int numWraps = (int)phase; + phase -= numWraps; + } } impl.subPhases_[nth] = phase; diff --git a/src/sfizz/LFO.h b/src/sfizz/LFO.h index 764cd65a..1a908932 100644 --- a/src/sfizz/LFO.h +++ b/src/sfizz/LFO.h @@ -10,6 +10,7 @@ namespace sfz { class BufferPool; +class BeatClock; enum class LFOWave : int; struct LFODescription; @@ -50,7 +51,9 @@ struct LFODescription; class LFO { public: - explicit LFO(BufferPool& bufferPool); + explicit LFO( + BufferPool& bufferPool, + BeatClock* beatClock = nullptr); ~LFO(); /** diff --git a/src/sfizz/LFODescription.h b/src/sfizz/LFODescription.h index 8f5344c9..2628430f 100644 --- a/src/sfizz/LFODescription.h +++ b/src/sfizz/LFODescription.h @@ -28,6 +28,7 @@ struct LFODescription { ~LFODescription(); static const LFODescription& getDefault(); float freq = 0; // lfoN_freq + float beats = 0; // lfoN_beats float phase0 = 0; // lfoN_phase float delay = 0; // lfoN_delay float fade = 0; // lfoN_fade diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index f131febf..88813c7e 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -866,6 +866,16 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) setValueFromOpcode(opcode, lfos[lfoNumber - 1].freq, Default::lfoFreqRange); } break; + case hash("lfo&_beats"): + { + const auto lfoNumber = opcode.parameters.front(); + if (lfoNumber == 0) + return false; + if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) + return false; + setValueFromOpcode(opcode, lfos[lfoNumber - 1].beats, Default::lfoBeatsRange); + } + break; case hash("lfo&_phase"): { const auto lfoNumber = opcode.parameters.front(); diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 45976aea..e3181121 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1475,10 +1475,12 @@ void Voice::setMaxEQsPerVoice(size_t numFilters) void Voice::setMaxLFOsPerVoice(size_t numLFOs) { Impl& impl = *impl_; + Resources& resources = impl.resources_; + impl.lfos_.resize(numLFOs); for (size_t i = 0; i < numLFOs; ++i) { - auto lfo = absl::make_unique(impl.resources_.bufferPool); + auto lfo = absl::make_unique(resources.bufferPool, &resources.beatClock); lfo->setSampleRate(impl.sampleRate_); impl.lfos_[i] = std::move(lfo); } From 04ff815cab74968e028984fbea7eaaeb22d0bd1b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 16:32:35 +0100 Subject: [PATCH 099/668] Assign LFOs their respective ID numbers --- demos/PlotLFO.cpp | 3 ++- src/sfizz/LFO.cpp | 15 +++++++++++---- src/sfizz/LFO.h | 4 ++++ src/sfizz/Voice.cpp | 3 ++- tests/LFOT.cpp | 3 ++- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/demos/PlotLFO.cpp b/demos/PlotLFO.cpp index 61ca0371..6f77f2f5 100644 --- a/demos/PlotLFO.cpp +++ b/demos/PlotLFO.cpp @@ -114,7 +114,8 @@ int main(int argc, char* argv[]) std::vector> lfos(numLfos); for (size_t l = 0; l < numLfos; ++l) { - sfz::LFO* lfo = new sfz::LFO(bufferPool); + const NumericId id { static_cast(l) }; + sfz::LFO* lfo = new sfz::LFO(id, bufferPool); lfos[l].reset(lfo); lfo->setSampleRate(sampleRate); lfo->configure(&desc[l]); diff --git a/src/sfizz/LFO.cpp b/src/sfizz/LFO.cpp index 6dd5c168..353ab899 100644 --- a/src/sfizz/LFO.cpp +++ b/src/sfizz/LFO.cpp @@ -18,14 +18,16 @@ namespace sfz { struct LFO::Impl { - explicit Impl(BufferPool& bufferPool, BeatClock* beatClock) - : bufferPool_(bufferPool), + explicit Impl(NumericId id, BufferPool& bufferPool, BeatClock* beatClock) + : id_(id), + bufferPool_(bufferPool), beatClock_(beatClock), sampleRate_(config::defaultSampleRate), desc_(&LFODescription::getDefault()) { } + NumericId id_; BufferPool& bufferPool_; BeatClock* beatClock_ = nullptr; float sampleRate_ = 0; @@ -41,8 +43,8 @@ struct LFO::Impl { std::array sampleHoldState_ {{}}; }; -LFO::LFO(BufferPool& bufferPool, BeatClock* beatClock) - : impl_(new Impl(bufferPool, beatClock)) +LFO::LFO(NumericId id, BufferPool& bufferPool, BeatClock* beatClock) + : impl_(new Impl(id, bufferPool, beatClock)) { } @@ -50,6 +52,11 @@ LFO::~LFO() { } +NumericId LFO::getId() const noexcept +{ + return impl_->id_; +} + void LFO::setSampleRate(double sampleRate) { impl_->sampleRate_ = sampleRate; diff --git a/src/sfizz/LFO.h b/src/sfizz/LFO.h index 1a908932..fecadc8b 100644 --- a/src/sfizz/LFO.h +++ b/src/sfizz/LFO.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "utility/NumericId.h" #include #include @@ -52,10 +53,13 @@ struct LFODescription; class LFO { public: explicit LFO( + NumericId id, BufferPool& bufferPool, BeatClock* beatClock = nullptr); ~LFO(); + NumericId getId() const noexcept; + /** Sets the sample rate. */ diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index e3181121..6c25eee8 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1480,7 +1480,8 @@ void Voice::setMaxLFOsPerVoice(size_t numLFOs) impl.lfos_.resize(numLFOs); for (size_t i = 0; i < numLFOs; ++i) { - auto lfo = absl::make_unique(resources.bufferPool, &resources.beatClock); + const NumericId id { static_cast(i) }; + auto lfo = absl::make_unique(id, resources.bufferPool, &resources.beatClock); lfo->setSampleRate(impl.sampleRate_); impl.lfos_[i] = std::move(lfo); } diff --git a/tests/LFOT.cpp b/tests/LFOT.cpp index e2a625f4..4f2b6a6d 100644 --- a/tests/LFOT.cpp +++ b/tests/LFOT.cpp @@ -26,7 +26,8 @@ static bool computeLFO(DataPoints& dp, const fs::path& sfzPath, double sampleRat std::vector> lfos(numLfos); for (size_t l = 0; l < numLfos; ++l) { - sfz::LFO* lfo = new sfz::LFO(resources.bufferPool); + const NumericId id { static_cast(l) }; + sfz::LFO* lfo = new sfz::LFO(id, resources.bufferPool); lfos[l].reset(lfo); lfo->setSampleRate(sampleRate); lfo->configure(&desc[l]); From f06ed50c574b860cf52c8bca6716ac0467f01290 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 17:22:18 +0100 Subject: [PATCH 100/668] Implement lfoN_beats_onccX, lfoN_freq_onccX --- src/sfizz/Defaults.h | 2 + src/sfizz/LFO.cpp | 92 +++++++++++++++++++-------- src/sfizz/LFO.h | 9 ++- src/sfizz/Region.cpp | 20 ++++++ src/sfizz/Voice.cpp | 2 +- src/sfizz/modulations/ModId.cpp | 4 ++ src/sfizz/modulations/ModId.h | 2 + src/sfizz/modulations/ModKey.cpp | 4 ++ src/sfizz/modulations/sources/LFO.cpp | 2 +- 9 files changed, 106 insertions(+), 31 deletions(-) diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index f20db102..eb7f7d25 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -222,7 +222,9 @@ namespace Default constexpr int numLFOSubs { 2 }; constexpr int numLFOSteps { 8 }; constexpr Range lfoFreqRange { 0.0, 100.0 }; + constexpr Range lfoFreqModRange { -100.0, 100.0 }; constexpr Range lfoBeatsRange { 0.0, 1000.0 }; + constexpr Range lfoBeatsModRange { -1000.0, 1000.0 }; constexpr Range lfoPhaseRange { 0.0, 1.0 }; constexpr Range lfoDelayRange { 0.0, 30.0 }; constexpr Range lfoFadeRange { 0.0, 30.0 }; diff --git a/src/sfizz/LFO.cpp b/src/sfizz/LFO.cpp index 353ab899..636ba74f 100644 --- a/src/sfizz/LFO.cpp +++ b/src/sfizz/LFO.cpp @@ -11,6 +11,9 @@ #include "MathHelpers.h" #include "SIMDHelpers.h" #include "Config.h" +#include "modulations/ModMatrix.h" +#include "modulations/ModKey.h" +#include "modulations/ModId.h" #include #include #include @@ -18,10 +21,11 @@ namespace sfz { struct LFO::Impl { - explicit Impl(NumericId id, BufferPool& bufferPool, BeatClock* beatClock) + explicit Impl(NumericId id, BufferPool& bufferPool, BeatClock* beatClock, ModMatrix* modMatrix) : id_(id), bufferPool_(bufferPool), beatClock_(beatClock), + modMatrix_(modMatrix), sampleRate_(config::defaultSampleRate), desc_(&LFODescription::getDefault()) { @@ -30,6 +34,7 @@ struct LFO::Impl { NumericId id_; BufferPool& bufferPool_; BeatClock* beatClock_ = nullptr; + ModMatrix* modMatrix_ = nullptr; float sampleRate_ = 0; // control @@ -43,8 +48,8 @@ struct LFO::Impl { std::array sampleHoldState_ {{}}; }; -LFO::LFO(NumericId id, BufferPool& bufferPool, BeatClock* beatClock) - : impl_(new Impl(id, bufferPool, beatClock)) +LFO::LFO(NumericId id, BufferPool& bufferPool, BeatClock* beatClock, ModMatrix* modMatrix) + : impl_(new Impl(id, bufferPool, beatClock, modMatrix)) { } @@ -212,7 +217,7 @@ void LFO::processSteps(absl::Span out, const float* phaseIn) } } -void LFO::process(absl::Span out) +void LFO::process(absl::Span out, NumericId regionId) { Impl& impl = *impl_; const LFODescription& desc = *impl.desc_; @@ -243,13 +248,13 @@ void LFO::process(absl::Span out) absl::Span phases = *phasesTemp; if (desc.seq) { - generatePhase(0, phases); + generatePhase(0, phases, regionId); processSteps(out, phases.data()); ++subno; } for (; subno < countSubs; ++subno) { - generatePhase(subno, phases); + generatePhase(subno, phases, regionId); switch (desc.sub[subno].wave) { case LFOWave::Triangle: processWave(subno, out, phases.data()); @@ -306,10 +311,13 @@ void LFO::processFadeIn(absl::Span out) impl.fadePosition_ = fadePosition; } -void LFO::generatePhase(unsigned nth, absl::Span phases) +void LFO::generatePhase(unsigned nth, absl::Span phases, NumericId regionId) { Impl& impl = *impl_; + BufferPool& bufferPool = impl.bufferPool_; BeatClock* beatClock = impl.beatClock_; + ModMatrix* modMatrix = impl.modMatrix_; + const NumericId id { impl.id_ }; const LFODescription& desc = *impl.desc_; const LFODescription::Sub& sub = desc.sub[nth]; const float samplePeriod = 1.0f / impl.sampleRate_; @@ -320,35 +328,67 @@ void LFO::generatePhase(unsigned nth, absl::Span phases) float phase = impl.subPhases_[nth]; const size_t numFrames = phases.size(); + // TODO(jpc) lfoN_count: number of repetitions + if (beatClock && beatClock->isPlaying() && beats > 0) { // generate using the beat clock float beatRatio = (ratio > 0) ? (1.0f / ratio) : 0.0f; - beatClock->calculatePhase(beats * beatRatio, phases.data()); - for (size_t i = 0; i < numFrames; ++i) { - float withOffset = phase + phaseOffset; - withOffset -= (int)withOffset; + const float* beatsMod = nullptr; + if (modMatrix && id && regionId) { + ModKey beatsKey = ModKey::createNXYZ(ModId::LFOBeats, regionId, id.number()); + beatsMod = modMatrix->getModulationByKey(beatsKey); + } - phases[i] = withOffset; - - // TODO(jpc) lfoN_count: number of repetitions + if (!beatsMod) + beatClock->calculatePhase(beats * beatRatio, phases.data()); + else { + auto temp = bufferPool.getBuffer(numFrames); + if (!temp) { + ASSERTFALSE; + beatClock->calculatePhase(beats * beatRatio, phases.data()); + } + else { + fill(*temp, beats); + add(absl::MakeConstSpan(beatsMod, numFrames), *temp); + applyGain1(beatRatio, *temp); + beatClock->calculatePhaseModulated(temp->data(), phases.data()); + } } } else { // generate using the frequency - for (size_t i = 0; i < numFrames; ++i) { - float withOffset = phase + phaseOffset; - withOffset -= (int)withOffset; - - phases[i] = withOffset; - - // TODO(jpc) lfoN_count: number of repetitions - - float incr = ratio * samplePeriod * baseFreq; - phase += incr; - int numWraps = (int)phase; - phase -= numWraps; + const float* freqMod = nullptr; + if (modMatrix && id && regionId) { + ModKey freqKey = ModKey::createNXYZ(ModId::LFOFrequency, regionId, id.number()); + freqMod = modMatrix->getModulationByKey(freqKey); } + + if (!freqMod) { + for (size_t i = 0; i < numFrames; ++i) { + phases[i] = phase; + float incr = ratio * samplePeriod * baseFreq; + phase += incr; + int numWraps = (int)phase; + phase -= numWraps; + } + } + else { + for (size_t i = 0; i < numFrames; ++i) { + phases[i] = phase; + float incr = ratio * samplePeriod * (baseFreq + freqMod[i]); + phase += incr; + int numWraps = (int)phase; + phase -= numWraps; + } + } + } + + // apply phase offsets + for (size_t i = 0; i < numFrames; ++i) { + float withOffset = phases[i] + phaseOffset; + withOffset -= (int)withOffset; + phases[i] = withOffset; } impl.subPhases_[nth] = phase; diff --git a/src/sfizz/LFO.h b/src/sfizz/LFO.h index fecadc8b..caac1c27 100644 --- a/src/sfizz/LFO.h +++ b/src/sfizz/LFO.h @@ -12,6 +12,8 @@ namespace sfz { class BufferPool; class BeatClock; +class ModMatrix; +struct Region; enum class LFOWave : int; struct LFODescription; @@ -55,7 +57,8 @@ public: explicit LFO( NumericId id, BufferPool& bufferPool, - BeatClock* beatClock = nullptr); + BeatClock* beatClock = nullptr, + ModMatrix* modMatrix = nullptr); ~LFO(); NumericId getId() const noexcept; @@ -82,7 +85,7 @@ public: TODO(jpc) frequency modulations */ - void process(absl::Span out); + void process(absl::Span out, NumericId regionId = {}); private: /** @@ -120,7 +123,7 @@ private: /** Generate the phase of the N-th generator */ - void generatePhase(unsigned nth, absl::Span phases); + void generatePhase(unsigned nth, absl::Span phases, NumericId regionId); private: struct Impl; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 88813c7e..4f0ce8f2 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -866,6 +866,16 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) setValueFromOpcode(opcode, lfos[lfoNumber - 1].freq, Default::lfoFreqRange); } break; + case_any_ccN("lfo&_freq"): + { + const auto lfoNumber = opcode.parameters.front(); + if (lfoNumber == 0) + return false; + if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) + return false; + processGenericCc(opcode, Default::lfoFreqModRange, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber - 1)); + } + break; case hash("lfo&_beats"): { const auto lfoNumber = opcode.parameters.front(); @@ -876,6 +886,16 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) setValueFromOpcode(opcode, lfos[lfoNumber - 1].beats, Default::lfoBeatsRange); } break; + case_any_ccN("lfo&_beats"): + { + const auto lfoNumber = opcode.parameters.front(); + if (lfoNumber == 0) + return false; + if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) + return false; + processGenericCc(opcode, Default::lfoBeatsModRange, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber - 1)); + } + break; case hash("lfo&_phase"): { const auto lfoNumber = opcode.parameters.front(); diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 6c25eee8..fa6e4262 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1481,7 +1481,7 @@ void Voice::setMaxLFOsPerVoice(size_t numLFOs) for (size_t i = 0; i < numLFOs; ++i) { const NumericId id { static_cast(i) }; - auto lfo = absl::make_unique(id, resources.bufferPool, &resources.beatClock); + auto lfo = absl::make_unique(id, resources.bufferPool, &resources.beatClock, &resources.modMatrix); lfo->setSampleRate(impl.sampleRate_); impl.lfos_[i] = std::move(lfo); } diff --git a/src/sfizz/modulations/ModId.cpp b/src/sfizz/modulations/ModId.cpp index 3d837ec5..388da189 100644 --- a/src/sfizz/modulations/ModId.cpp +++ b/src/sfizz/modulations/ModId.cpp @@ -68,6 +68,10 @@ int ModIds::flags(ModId id) noexcept return kModIsPerVoice|kModIsAdditive; case ModId::OscillatorModDepth: return kModIsPerVoice|kModIsPercentMultiplicative; + case ModId::LFOFrequency: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOBeats: + return kModIsPerVoice|kModIsAdditive; // unknown default: diff --git a/src/sfizz/modulations/ModId.h b/src/sfizz/modulations/ModId.h index 48d9b2d9..f4c45965 100644 --- a/src/sfizz/modulations/ModId.h +++ b/src/sfizz/modulations/ModId.h @@ -49,6 +49,8 @@ enum class ModId : int { EqBandwidth, OscillatorDetune, OscillatorModDepth, + LFOFrequency, + LFOBeats, _TargetsEnd, // [/targets] -------------------------------------------------------------- diff --git a/src/sfizz/modulations/ModKey.cpp b/src/sfizz/modulations/ModKey.cpp index 051a4f8e..7b75c8f5 100644 --- a/src/sfizz/modulations/ModKey.cpp +++ b/src/sfizz/modulations/ModKey.cpp @@ -118,6 +118,10 @@ std::string ModKey::toString() const return absl::StrCat("OscillatorDetune {", region_.number(), ", N=", 1 + params_.N, "}"); case ModId::OscillatorModDepth: return absl::StrCat("OscillatorModDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOFrequency: + return absl::StrCat("LFOFrequency {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOBeats: + return absl::StrCat("LFOBeats {", region_.number(), ", N=", 1 + params_.N, "}"); default: return {}; diff --git a/src/sfizz/modulations/sources/LFO.cpp b/src/sfizz/modulations/sources/LFO.cpp index a485833d..206f0ca1 100644 --- a/src/sfizz/modulations/sources/LFO.cpp +++ b/src/sfizz/modulations/sources/LFO.cpp @@ -59,7 +59,7 @@ void LFOSource::generate(const ModKey& sourceKey, NumericId voiceId, absl } LFO* lfo = voice->getLFO(lfoIndex); - lfo->process(buffer); + lfo->process(buffer, region->getId()); } } // namespace sfz From 555356528b7b6b53434db58672de77ae3e47bc0f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 18:24:26 +0100 Subject: [PATCH 101/668] Ensure to generate continuous modulations --- src/sfizz/LFO.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sfizz/LFO.cpp b/src/sfizz/LFO.cpp index 636ba74f..547e296c 100644 --- a/src/sfizz/LFO.cpp +++ b/src/sfizz/LFO.cpp @@ -330,16 +330,22 @@ void LFO::generatePhase(unsigned nth, absl::Span phases, NumericIdgetModulationByKey(beatsKey); + freqMod = modMatrix->getModulationByKey(freqKey); + } + if (beatClock && beatClock->isPlaying() && beats > 0) { // generate using the beat clock float beatRatio = (ratio > 0) ? (1.0f / ratio) : 0.0f; - const float* beatsMod = nullptr; - if (modMatrix && id && regionId) { - ModKey beatsKey = ModKey::createNXYZ(ModId::LFOBeats, regionId, id.number()); - beatsMod = modMatrix->getModulationByKey(beatsKey); - } - if (!beatsMod) beatClock->calculatePhase(beats * beatRatio, phases.data()); else { @@ -358,12 +364,6 @@ void LFO::generatePhase(unsigned nth, absl::Span phases, NumericIdgetModulationByKey(freqKey); - } - if (!freqMod) { for (size_t i = 0; i < numFrames; ++i) { phases[i] = phase; From 782aa484bda9745cae5878f44b0f94ff6603a8c9 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 17 Nov 2020 19:57:52 +0100 Subject: [PATCH 102/668] Fix a crash with scala files under LV2 --- lv2/sfizz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 44d9077a..89abeb37 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -1430,7 +1430,7 @@ work(LV2_Handle instance, else if (atom->type == self->sfizz_scala_file_uri) { const char *scala_file_path = LV2_ATOM_BODY_CONST(atom); - if (sfizz_lv2_load_scala_file(self->synth, scala_file_path)) { + if (sfizz_lv2_load_scala_file(self, scala_file_path)) { lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", scala_file_path); } else { lv2_log_error(&self->logger, From 26ba0417f7bd95f8c7e80e12e1dc2491ee7f347f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 17 Nov 2020 19:59:36 +0100 Subject: [PATCH 103/668] Fix the second occurrence of the same problem --- lv2/sfizz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 89abeb37..0ebe5313 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -1493,7 +1493,7 @@ work(LV2_Handle instance, lv2_log_note(&self->logger, "[sfizz] Scala file %s seems to have been updated, reloading\n", self->scala_file_path); - if (sfizz_lv2_load_scala_file(self->synth, self->scala_file_path)) { + if (sfizz_lv2_load_scala_file(self, self->scala_file_path)) { lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", self->scala_file_path); } else { lv2_log_error(&self->logger, From d9ac783b2494ca071f5635f9aca853319a5ca108 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 22 Nov 2020 23:43:07 +0100 Subject: [PATCH 104/668] Update to VST 3.7.1 --- .gitmodules | 4 ++-- vst/external/VST_SDK/VST3_SDK/base | 2 +- vst/external/VST_SDK/VST3_SDK/pluginterfaces | 2 +- vst/external/VST_SDK/VST3_SDK/public.sdk | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index d97f8bae..cbe668dc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,11 +9,11 @@ shallow = true [submodule "vst/external/VST_SDK/VST3_SDK/pluginterfaces"] path = vst/external/VST_SDK/VST3_SDK/pluginterfaces - url = https://github.com/sfztools/vst3_pluginterfaces.git + url = https://github.com/steinbergmedia/vst3_pluginterfaces.git shallow = true [submodule "vst/external/VST_SDK/VST3_SDK/public.sdk"] path = vst/external/VST_SDK/VST3_SDK/public.sdk - url = https://github.com/sfztools/vst3_public_sdk.git + url = https://github.com/steinbergmedia/vst3_public_sdk.git shallow = true [submodule "vst/external/VST_SDK/VST3_SDK/vstgui4"] path = editor/external/vstgui4 diff --git a/vst/external/VST_SDK/VST3_SDK/base b/vst/external/VST_SDK/VST3_SDK/base index 4f6a7184..7b977c03 160000 --- a/vst/external/VST_SDK/VST3_SDK/base +++ b/vst/external/VST_SDK/VST3_SDK/base @@ -1 +1 @@ -Subproject commit 4f6a7184f20f40a7c940a6717e6e0d8b35eeea63 +Subproject commit 7b977c031f42a6bab08e8b10f4f8df0a1f516c38 diff --git a/vst/external/VST_SDK/VST3_SDK/pluginterfaces b/vst/external/VST_SDK/VST3_SDK/pluginterfaces index 8c07a58d..fe202edc 160000 --- a/vst/external/VST_SDK/VST3_SDK/pluginterfaces +++ b/vst/external/VST_SDK/VST3_SDK/pluginterfaces @@ -1 +1 @@ -Subproject commit 8c07a58d84c544a73e1ccad2efae200505796773 +Subproject commit fe202edc93e9a01a1f79a614cc9a292dc9bf3e6e diff --git a/vst/external/VST_SDK/VST3_SDK/public.sdk b/vst/external/VST_SDK/VST3_SDK/public.sdk index b63097eb..a3a3ed1b 160000 --- a/vst/external/VST_SDK/VST3_SDK/public.sdk +++ b/vst/external/VST_SDK/VST3_SDK/public.sdk @@ -1 +1 @@ -Subproject commit b63097ebce2105845aa97d04808fca4dfd51307c +Subproject commit a3a3ed1b1620df0b064564f1fd5423ae110234a0 From 5351ef410b703707c5feb360b6e08f77f8b664cd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 23 Nov 2020 00:19:35 +0100 Subject: [PATCH 105/668] Convert some case problems with minGW at CI-time --- .travis/script_mingw.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis/script_mingw.sh b/.travis/script_mingw.sh index 85aac04e..cdd4b941 100755 --- a/.travis/script_mingw.sh +++ b/.travis/script_mingw.sh @@ -3,6 +3,11 @@ set -ex . .travis/docker_container.sh +# need to convert some includes to lower case (as of VST 3.7.1) +find vst/external/VST_SDK -type d -name source -exec \ + find {} -type f -name '*.[hc]' -o -name '*.[hc]pp' -print0 \; | \ + xargs -0 sed -i 's///' + mkdir -p build/${INSTALL_DIR} && cd build if [[ ${CROSS_COMPILE} == "mingw32" ]]; then buildenv i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=Release \ From 2ecf35d15465f5f0ca3fe5bf50f42c0a074a95db Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 23 Nov 2020 00:22:56 +0100 Subject: [PATCH 106/668] Add the common IIDs to AudioUnit --- vst/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index ccb73714..8f993b8c 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -242,6 +242,7 @@ elseif(SFIZZ_AU) "${VST3SDK_BASEDIR}/pluginterfaces/base/coreiids.cpp" "${VST3SDK_BASEDIR}/pluginterfaces/base/funknown.cpp" "${VST3SDK_BASEDIR}/pluginterfaces/base/ustring.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/common/commoniids.cpp" "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstinitiids.cpp") # Add VST hosting classes From af21c5775d299f1af00eb3a172ad36c1c0838ff0 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 23 Nov 2020 01:18:49 +0100 Subject: [PATCH 107/668] Fix a VSTGUI include which will be needed after update --- editor/src/editor/GUIComponents.h | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/src/editor/GUIComponents.h b/editor/src/editor/GUIComponents.h index 5a807b98..e08ccf3d 100644 --- a/editor/src/editor/GUIComponents.h +++ b/editor/src/editor/GUIComponents.h @@ -13,6 +13,7 @@ #include "vstgui/lib/controls/ctextlabel.h" #include "vstgui/lib/controls/cbuttons.h" #include "vstgui/lib/controls/coptionmenu.h" +#include "vstgui/lib/controls/icontrollistener.h" #include "vstgui/lib/cviewcontainer.h" #include "vstgui/lib/ccolor.h" #include "vstgui/lib/dragging.h" From 8a7a223777e22717dde9f36f5b9f19cdcbb82cdf Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 24 Nov 2020 01:35:42 +0100 Subject: [PATCH 108/668] Make sure to null the editor frame after closing --- vst/SfizzVstEditor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 0f9bd231..e972b9bf 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -79,6 +79,7 @@ void PLUGIN_API SfizzVstEditor::close() frame->forget(); else frame->close(); + this->frame = nullptr; } } From 03cc5d2e5ffa5493310463ce30942287ae650f78 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 24 Nov 2020 07:24:24 +0100 Subject: [PATCH 109/668] Delayed UI updates with locking --- vst/SfizzVstController.cpp | 86 ++++++++++++++-------------------- vst/SfizzVstController.h | 26 +---------- vst/SfizzVstEditor.cpp | 96 ++++++++++++++++++++++++++------------ vst/SfizzVstEditor.h | 26 +++++++---- 4 files changed, 122 insertions(+), 112 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 970f3f1a..089cafd3 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -139,7 +139,20 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) if (name != Vst::ViewType::kEditor) return nullptr; - return new SfizzVstEditor(this); + if (_editor) { + _uiState = _editor->getCurrentUiState(); + _editor.reset(); + } + + SfizzVstEditor* editor = new SfizzVstEditor(this); + _editor = Steinberg::owned(editor); + + editor->updateState(_state); + editor->updateUiState(_uiState); + editor->updatePlayState(_playState); + + editor->remember(); + return editor; } tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst::ParamValue normValue) @@ -190,20 +203,15 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: } } - bool update = false; - if (slotF32 && *slotF32 != value) { *slotF32 = value; - update = true; + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); } else if (slotI32 && *slotI32 != (int32)value) { *slotI32 = (int32)value; - update = true; - } - - if (update) { - for (StateListener* listener : _stateListeners) - listener->onStateChanged(); + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); } return kResultTrue; @@ -219,14 +227,17 @@ tresult PLUGIN_API SfizzVstController::setState(IBStream* state) _uiState = s; - for (StateListener* listener : _stateListeners) - listener->onStateChanged(); + if (SfizzVstEditor* editor = _editor) + editor->updateUiState(_uiState); return kResultTrue; } tresult PLUGIN_API SfizzVstController::getState(IBStream* state) { + if (_editor) + _uiState = _editor->getCurrentUiState(); + return _uiState.store(state); } @@ -248,8 +259,8 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) setParamNormalized(kPidTuningFrequency, kParamTuningFrequencyRange.normalize(s.tuningFrequency)); setParamNormalized(kPidStretchedTuning, kParamStretchedTuningRange.normalize(s.stretchedTuning)); - for (StateListener* listener : _stateListeners) - listener->onStateChanged(); + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); return kResultTrue; } @@ -272,6 +283,9 @@ tresult SfizzVstController::notify(Vst::IMessage* message) return result; _state.sfzFile.assign(static_cast(data), size); + + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); } else if (!strcmp(id, "LoadedScala")) { const void* data = nullptr; @@ -282,6 +296,9 @@ tresult SfizzVstController::notify(Vst::IMessage* message) return result; _state.scalaFile.assign(static_cast(data), size); + + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); } else if (!strcmp(id, "NotifiedPlayState")) { const void* data = nullptr; @@ -292,6 +309,9 @@ tresult SfizzVstController::notify(Vst::IMessage* message) return result; _playState = *static_cast(data); + + if (SfizzVstEditor* editor = _editor) + editor->updatePlayState(_playState); } else if (!strcmp(id, "ReceivedMessage")) { const void* data = nullptr; @@ -301,47 +321,13 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - const char* path; - const char* sig; - const sfizz_arg_t* args; - uint8_t buffer[1024]; - - if (sfizz_extract_message(data, size, buffer, sizeof(buffer), &path, &sig, &args) > 0) { - for (MessageListener* listener : _messageListeners) - listener->onMessageReceived(path, sig, args); - } + if (SfizzVstEditor* editor = _editor) + editor->receiveMessage(data, size); } - for (StateListener* listener : _stateListeners) - listener->onStateChanged(); - return result; } -void SfizzVstController::addSfizzStateListener(StateListener* listener) -{ - _stateListeners.push_back(listener); -} - -void SfizzVstController::removeSfizzStateListener(StateListener* listener) -{ - auto it = std::find(_stateListeners.begin(), _stateListeners.end(), listener); - if (it != _stateListeners.end()) - _stateListeners.erase(it); -} - -void SfizzVstController::addSfizzMessageListener(MessageListener* listener) -{ - _messageListeners.push_back(listener); -} - -void SfizzVstController::removeSfizzMessageListener(MessageListener* listener) -{ - auto it = std::find(_messageListeners.begin(), _messageListeners.end(), listener); - if (it != _messageListeners.end()) - _messageListeners.erase(it); -} - FUnknown* SfizzVstController::createInstance(void*) { return static_cast(new SfizzVstController); diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index 796d6628..69670a55 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -11,6 +11,7 @@ #include "vstgui/plugin-bindings/vst3editor.h" #include class SfizzVstState; +class SfizzVstEditor; using namespace Steinberg; using namespace VSTGUI; @@ -47,28 +48,6 @@ public: tresult PLUGIN_API setComponentState(IBStream* state) override; tresult PLUGIN_API notify(Vst::IMessage* message) override; - struct StateListener { - virtual void onStateChanged() = 0; - }; - struct MessageListener { - virtual void onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) = 0; - }; - - const SfizzVstState& getSfizzState() const { return _state; } - SfizzVstState& getSfizzState() { return _state; } - - const SfizzUiState& getSfizzUiState() const { return _uiState; } - SfizzUiState& getSfizzUiState() { return _uiState; } - - const SfizzPlayState& getSfizzPlayState() const { return _playState; } - SfizzPlayState& getSfizzPlayState() { return _playState; } - - void addSfizzStateListener(StateListener* listener); - void removeSfizzStateListener(StateListener* listener); - - void addSfizzMessageListener(MessageListener* listener); - void removeSfizzMessageListener(MessageListener* listener); - /// static FUnknown* createInstance(void*); @@ -78,6 +57,5 @@ private: SfizzVstState _state; SfizzUiState _uiState; SfizzPlayState _playState {}; - std::vector _stateListeners; - std::vector _messageListeners; + Steinberg::IPtr _editor; }; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index e972b9bf..a37602c1 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -20,18 +20,14 @@ enum { kOscTempSize = 8192, }; -SfizzVstEditor::SfizzVstEditor(void *controller) +SfizzVstEditor::SfizzVstEditor(SfizzVstController* controller) : VSTGUIEditor(controller, &sfizzUiViewRect), oscTemp_(new uint8_t[kOscTempSize]) { - getController()->addSfizzStateListener(this); - getController()->addSfizzMessageListener(this); } SfizzVstEditor::~SfizzVstEditor() { - getController()->removeSfizzStateListener(this); - getController()->removeSfizzMessageListener(this); } bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& platformType) @@ -105,17 +101,48 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message) } #endif + if (message == CVSTGUITimer::kMsgTimer) + updateStateDisplay(); + return result; } -void SfizzVstEditor::onStateChanged() +void SfizzVstEditor::updateState(const SfizzVstState& state) { - updateStateDisplay(); + std::lock_guard lock(stateMutex_); + state_ = state; + mustRedisplayState_ = true; } -void SfizzVstEditor::onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) +void SfizzVstEditor::updateUiState(const SfizzUiState& uiState) { - uiReceiveMessage(path, sig, args); + std::lock_guard lock(stateMutex_); + uiState_ = uiState; + mustRedisplayUiState_ = true; +} + +void SfizzVstEditor::updatePlayState(const SfizzPlayState& playState) +{ + std::lock_guard lock(stateMutex_); + playState_ = playState; + mustRedisplayPlayState_ = true; +} + +SfizzUiState SfizzVstEditor::getCurrentUiState() const +{ + std::lock_guard lock(stateMutex_); + return uiState_; +} + +void SfizzVstEditor::receiveMessage(const void* data, uint32_t size) +{ + const char* path; + const char* sig; + const sfizz_arg_t* args; + uint8_t buffer[1024]; + + if (sfizz_extract_message(data, size, buffer, sizeof(buffer), &path, &sig, &args) > 0) + uiReceiveMessage(path, sig, args); } /// @@ -166,7 +193,7 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) break; case EditId::UIActivePanel: - ctrl->getSfizzUiState().activePanel = static_cast(v.to_float()); + uiState_.activePanel = static_cast(v.to_float()); break; default: @@ -263,32 +290,41 @@ void SfizzVstEditor::updateStateDisplay() if (!frame) return; - SfizzVstController* controller = getController(); - const SfizzVstState& state = controller->getSfizzState(); - const SfizzUiState& uiState = controller->getSfizzUiState(); - const SfizzPlayState& playState = controller->getSfizzPlayState(); + if (!(mustRedisplayState_ || mustRedisplayUiState_ || mustRedisplayPlayState_)) + return; + + std::lock_guard lock(stateMutex_); /// - uiReceiveValue(EditId::SfzFile, state.sfzFile); - uiReceiveValue(EditId::Volume, state.volume); - uiReceiveValue(EditId::Polyphony, state.numVoices); - uiReceiveValue(EditId::Oversampling, 1u << state.oversamplingLog2); - uiReceiveValue(EditId::PreloadSize, state.preloadSize); - uiReceiveValue(EditId::ScalaFile, state.scalaFile); - uiReceiveValue(EditId::ScalaRootKey, state.scalaRootKey); - uiReceiveValue(EditId::TuningFrequency, state.tuningFrequency); - uiReceiveValue(EditId::StretchTuning, state.stretchedTuning); + if (mustRedisplayState_) { + uiReceiveValue(EditId::SfzFile, state_.sfzFile); + uiReceiveValue(EditId::Volume, state_.volume); + uiReceiveValue(EditId::Polyphony, state_.numVoices); + uiReceiveValue(EditId::Oversampling, 1u << state_.oversamplingLog2); + uiReceiveValue(EditId::PreloadSize, state_.preloadSize); + uiReceiveValue(EditId::ScalaFile, state_.scalaFile); + uiReceiveValue(EditId::ScalaRootKey, state_.scalaRootKey); + uiReceiveValue(EditId::TuningFrequency, state_.tuningFrequency); + uiReceiveValue(EditId::StretchTuning, state_.stretchedTuning); + mustRedisplayState_ = false; + } /// - uiReceiveValue(EditId::UINumCurves, playState.curves); - uiReceiveValue(EditId::UINumMasters, playState.masters); - uiReceiveValue(EditId::UINumGroups, playState.groups); - uiReceiveValue(EditId::UINumRegions, playState.regions); - uiReceiveValue(EditId::UINumPreloadedSamples, playState.preloadedSamples); - uiReceiveValue(EditId::UINumActiveVoices, playState.activeVoices); + if (mustRedisplayUiState_) { + uiReceiveValue(EditId::UIActivePanel, uiState_.activePanel); + mustRedisplayUiState_ = false; + } /// - uiReceiveValue(EditId::UIActivePanel, uiState.activePanel); + if (mustRedisplayPlayState_) { + uiReceiveValue(EditId::UINumCurves, playState_.curves); + uiReceiveValue(EditId::UINumMasters, playState_.masters); + uiReceiveValue(EditId::UINumGroups, playState_.groups); + uiReceiveValue(EditId::UINumRegions, playState_.regions); + uiReceiveValue(EditId::UINumPreloadedSamples, playState_.preloadedSamples); + uiReceiveValue(EditId::UINumActiveVoices, playState_.activeVoices); + mustRedisplayPlayState_ = false; + } } Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id) diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index ad45f352..e3bb1126 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -8,6 +8,7 @@ #include "SfizzVstController.h" #include "editor/EditorController.h" #include "public.sdk/source/vst/vstguieditor.h" +#include class Editor; #if !defined(__APPLE__) && !defined(_WIN32) namespace VSTGUI { class RunLoop; } @@ -17,11 +18,9 @@ using namespace Steinberg; using namespace VSTGUI; class SfizzVstEditor : public Vst::VSTGUIEditor, - public SfizzVstController::StateListener, - public SfizzVstController::MessageListener, public EditorController { public: - explicit SfizzVstEditor(void *controller); + explicit SfizzVstEditor(SfizzVstController* controller); ~SfizzVstEditor(); bool PLUGIN_API open(void* parent, const VSTGUI::PlatformType& platformType = VSTGUI::kDefaultNative) override; @@ -35,11 +34,12 @@ public: // VSTGUIEditor CMessageResult notify(CBaseObject* sender, const char* message) override; - // SfizzVstController::StateListener - void onStateChanged() override; - - // SfizzVstController::MessageListener - void onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) override; + // + void updateState(const SfizzVstState& state); + void updateUiState(const SfizzUiState& uiState); + void updatePlayState(const SfizzPlayState& playState); + SfizzUiState getCurrentUiState() const; + void receiveMessage(const void* data, uint32_t size); protected: // EditorController @@ -65,4 +65,14 @@ private: // messaging std::unique_ptr oscTemp_; + + // editor state + // note: might be updated from a non-UI thread + mutable std::recursive_mutex stateMutex_; + SfizzVstState state_; + SfizzUiState uiState_; + SfizzPlayState playState_; + volatile bool mustRedisplayState_ = false; + volatile bool mustRedisplayUiState_ = false; + volatile bool mustRedisplayPlayState_ = false; }; From ae1c4e2245edaeaa58db2cfe13f51ff20dcbe0fb Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 24 Nov 2020 07:51:45 +0100 Subject: [PATCH 110/668] Redisplay all state on VST editor opened --- vst/SfizzVstEditor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index a37602c1..5d27aeb0 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -53,6 +53,10 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p editor = new Editor(*this); editor_.reset(editor); } + + mustRedisplayState_ = true; + mustRedisplayUiState_ = true; + mustRedisplayPlayState_ = true; updateStateDisplay(); if (!frame->open(parent, platformType, config)) { From 41dae2fe24a590692c1df740fd199430e7eacf06 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 24 Nov 2020 08:24:39 +0100 Subject: [PATCH 111/668] Also process OSC in idle callback --- vst/SfizzVstEditor.cpp | 43 ++++++++++++++++++++++++++++++++++++++++-- vst/SfizzVstEditor.h | 5 +++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 5d27aeb0..21a0f862 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -18,12 +18,14 @@ static ViewRect sfizzUiViewRect { 0, 0, Editor::viewWidth, Editor::viewHeight }; enum { kOscTempSize = 8192, + kOscQueueSize = 65536, }; SfizzVstEditor::SfizzVstEditor(SfizzVstController* controller) : VSTGUIEditor(controller, &sfizzUiViewRect), oscTemp_(new uint8_t[kOscTempSize]) { + oscQueue_.reserve(kOscQueueSize); } SfizzVstEditor::~SfizzVstEditor() @@ -57,6 +59,8 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p mustRedisplayState_ = true; mustRedisplayUiState_ = true; mustRedisplayPlayState_ = true; + flushOscQueue(); + updateStateDisplay(); if (!frame->open(parent, platformType, config)) { @@ -81,6 +85,8 @@ void PLUGIN_API SfizzVstEditor::close() frame->close(); this->frame = nullptr; } + + flushOscQueue(); } /// @@ -105,8 +111,10 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message) } #endif - if (message == CVSTGUITimer::kMsgTimer) + if (message == CVSTGUITimer::kMsgTimer) { + processOscQueue(); updateStateDisplay(); + } return result; } @@ -140,13 +148,44 @@ SfizzUiState SfizzVstEditor::getCurrentUiState() const void SfizzVstEditor::receiveMessage(const void* data, uint32_t size) { + if (!frame) { + // only accumulate if message processing is active + return; + } + + std::lock_guard lock(stateMutex_); + std::copy( + reinterpret_cast(data), + reinterpret_cast(data) + size, + std::back_inserter(oscQueue_)); +} + +void SfizzVstEditor::processOscQueue() +{ + std::lock_guard lock(stateMutex_); + + const uint8_t* oscData = oscQueue_.data(); + size_t oscSize = oscQueue_.size(); + const char* path; const char* sig; const sfizz_arg_t* args; uint8_t buffer[1024]; - if (sfizz_extract_message(data, size, buffer, sizeof(buffer), &path, &sig, &args) > 0) + uint32_t msgSize; + while ((msgSize = sfizz_extract_message(oscData, oscSize, buffer, sizeof(buffer), &path, &sig, &args)) > 0) { uiReceiveMessage(path, sig, args); + oscData += msgSize; + oscSize -= msgSize; + } + + oscQueue_.clear(); +} + +void SfizzVstEditor::flushOscQueue() +{ + std::lock_guard lock(stateMutex_); + oscQueue_.clear(); } /// diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index e3bb1126..e6b48478 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -41,6 +41,10 @@ public: SfizzUiState getCurrentUiState() const; void receiveMessage(const void* data, uint32_t size); +private: + void processOscQueue(); + void flushOscQueue(); + protected: // EditorController void uiSendValue(EditId id, const EditValue& v) override; @@ -75,4 +79,5 @@ private: volatile bool mustRedisplayState_ = false; volatile bool mustRedisplayUiState_ = false; volatile bool mustRedisplayPlayState_ = false; + std::vector oscQueue_; }; From 5709fedb94318ad8ab44c4689e43f74f7f452b66 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 24 Nov 2020 08:29:20 +0100 Subject: [PATCH 112/668] Fix a bug which gets the worker stuck on semaphore --- vst/SfizzVstProcessor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 93969467..77de7c43 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -558,8 +558,10 @@ void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char* { uint8_t* oscTemp = _oscTemp.get(); uint32_t oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args); - if (oscSize <= kOscTempSize) - writeWorkerMessage("ReceiveMessage", oscTemp, oscSize); + if (oscSize <= kOscTempSize) { + if (writeWorkerMessage("ReceiveMessage", oscTemp, oscSize)) + _semaToWorker.post(); + } } void SfizzVstProcessor::loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath) From afba7e4bc712d00b0439d6837d23a0ebbb91bec8 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 24 Nov 2020 20:56:00 +0100 Subject: [PATCH 113/668] Fix uninitialized memory with sndfile --- external/st_audiofile/src/st_audiofile_sndfile.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/external/st_audiofile/src/st_audiofile_sndfile.c b/external/st_audiofile/src/st_audiofile_sndfile.c index c1b8fed8..31cc115d 100644 --- a/external/st_audiofile/src/st_audiofile_sndfile.c +++ b/external/st_audiofile/src/st_audiofile_sndfile.c @@ -12,6 +12,7 @@ #endif #include #include +#include struct st_audio_file { SNDFILE* snd; @@ -24,6 +25,8 @@ st_audio_file* st_open_file(const char* filename) if (!af) return NULL; + memset(&af->info, 0, sizeof(SF_INFO)); + af->snd = sf_open(filename, SFM_READ, &af->info); if (!af->snd) { free(af); From a0e6abceda99b81a3aff06b5940fdeda1e6bd4c6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 27 Nov 2020 00:08:08 +0100 Subject: [PATCH 114/668] Enable the fast-math equivalent of MSVC --- cmake/SfizzConfig.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 20c9660a..95e599cc 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -81,6 +81,8 @@ endif() function(sfizz_enable_fast_math NAME) if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_compile_options("${NAME}" PRIVATE "-ffast-math") + elseif(MSVC) + target_compile_options("${NAME}" PRIVATE "/fp:fast") endif() endfunction() From bea7195c656a08c17fb2f6e23c32d094c7fd189a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 7 Dec 2020 09:41:36 +0100 Subject: [PATCH 115/668] Add more thread-safety in VST --- vst/SfizzVstController.cpp | 96 +++++++++++++--------- vst/SfizzVstController.h | 19 +++-- vst/SfizzVstEditor.cpp | 161 +++++++++++++++++++------------------ vst/SfizzVstEditor.h | 18 +++-- 4 files changed, 166 insertions(+), 128 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 089cafd3..2e6854f1 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -140,16 +140,20 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) return nullptr; if (_editor) { - _uiState = _editor->getCurrentUiState(); + withStateLock([this]() { + _uiState = _editor->getCurrentUiState(); + }); _editor.reset(); } SfizzVstEditor* editor = new SfizzVstEditor(this); _editor = Steinberg::owned(editor); - editor->updateState(_state); - editor->updateUiState(_uiState); - editor->updatePlayState(_playState); + withStateLock([this, editor]() { + editor->updateState(_state); + editor->updateUiState(_uiState); + editor->updatePlayState(_playState); + }); editor->remember(); return editor; @@ -204,53 +208,61 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: } if (slotF32 && *slotF32 != value) { - *slotF32 = value; - if (SfizzVstEditor* editor = _editor) - editor->updateState(_state); + withStateLock([this, slotF32, value]() { + *slotF32 = value; + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); + }); } else if (slotI32 && *slotI32 != (int32)value) { - *slotI32 = (int32)value; - if (SfizzVstEditor* editor = _editor) - editor->updateState(_state); + withStateLock([this, slotI32, value]() { + *slotI32 = (int32)value; + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); + }); } return kResultTrue; } -tresult PLUGIN_API SfizzVstController::setState(IBStream* state) +tresult PLUGIN_API SfizzVstController::setState(IBStream* stream) { SfizzUiState s; - tresult r = s.load(state); + tresult r = s.load(stream); if (r != kResultTrue) return r; - _uiState = s; - - if (SfizzVstEditor* editor = _editor) - editor->updateUiState(_uiState); + withStateLock([this, &s]() { + _uiState = s; + if (SfizzVstEditor* editor = _editor) + editor->updateUiState(_uiState); + }); return kResultTrue; } -tresult PLUGIN_API SfizzVstController::getState(IBStream* state) +tresult PLUGIN_API SfizzVstController::getState(IBStream* stream) { - if (_editor) - _uiState = _editor->getCurrentUiState(); + tresult result; - return _uiState.store(state); + withStateLock([this, stream, &result]() { + if (_editor) + _uiState = _editor->getCurrentUiState(); + result = _uiState.store(stream); + }); + + return result; } -tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) +tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* stream) { SfizzVstState s; - tresult r = s.load(state); + tresult r = s.load(stream); if (r != kResultTrue) return r; - _state = s; - setParamNormalized(kPidVolume, kParamVolumeRange.normalize(s.volume)); setParamNormalized(kPidNumVoices, kParamNumVoicesRange.normalize(s.numVoices)); setParamNormalized(kPidOversampling, kParamOversamplingRange.normalize(s.oversamplingLog2)); @@ -259,14 +271,19 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) setParamNormalized(kPidTuningFrequency, kParamTuningFrequencyRange.normalize(s.tuningFrequency)); setParamNormalized(kPidStretchedTuning, kParamStretchedTuningRange.normalize(s.stretchedTuning)); - if (SfizzVstEditor* editor = _editor) - editor->updateState(_state); + withStateLock([this, &s]() { + _state = s; + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); + }); return kResultTrue; } tresult SfizzVstController::notify(Vst::IMessage* message) { + // Note: may be called from any thread (Reaper) + tresult result = SfizzVstControllerNoUi::notify(message); if (result != kResultFalse) return result; @@ -282,10 +299,11 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - _state.sfzFile.assign(static_cast(data), size); - - if (SfizzVstEditor* editor = _editor) - editor->updateState(_state); + withStateLock([this, data, size]() { + _state.sfzFile.assign(static_cast(data), size); + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); + }); } else if (!strcmp(id, "LoadedScala")) { const void* data = nullptr; @@ -295,10 +313,11 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - _state.scalaFile.assign(static_cast(data), size); - - if (SfizzVstEditor* editor = _editor) - editor->updateState(_state); + withStateLock([this, data, size]() { + _state.scalaFile.assign(static_cast(data), size); + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); + }); } else if (!strcmp(id, "NotifiedPlayState")) { const void* data = nullptr; @@ -308,10 +327,11 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - _playState = *static_cast(data); - - if (SfizzVstEditor* editor = _editor) - editor->updatePlayState(_playState); + withStateLock([this, data]() { + _playState = *static_cast(data); + if (SfizzVstEditor* editor = _editor) + editor->updatePlayState(_playState); + }); } else if (!strcmp(id, "ReceivedMessage")) { const void* data = nullptr; diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index 69670a55..9e5ba8d4 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -10,6 +10,7 @@ #include "public.sdk/source/vst/vstparameters.h" #include "vstgui/plugin-bindings/vst3editor.h" #include +#include class SfizzVstState; class SfizzVstEditor; @@ -43,9 +44,9 @@ public: IPlugView* PLUGIN_API createView(FIDString name) override; tresult PLUGIN_API setParamNormalized(Vst::ParamID tag, Vst::ParamValue value) override; - tresult PLUGIN_API setState(IBStream* state) override; - tresult PLUGIN_API getState(IBStream* state) override; - tresult PLUGIN_API setComponentState(IBStream* state) override; + tresult PLUGIN_API setState(IBStream* stream) override; + tresult PLUGIN_API getState(IBStream* stream) override; + tresult PLUGIN_API setComponentState(IBStream* stream) override; tresult PLUGIN_API notify(Vst::IMessage* message) override; /// @@ -54,8 +55,16 @@ public: static FUID cid; private: - SfizzVstState _state; - SfizzUiState _uiState; + template void withStateLock(F&& fn) const + { + std::lock_guard lock(_stateMutex); + fn(); + } + +private: + mutable std::mutex _stateMutex; // for R/W the state data + SfizzVstState _state {}; + SfizzUiState _uiState {}; // updated on UI open/close/state-request SfizzPlayState _playState {}; Steinberg::IPtr _editor; }; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 21a0f862..c04b5d1d 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -25,7 +25,6 @@ SfizzVstEditor::SfizzVstEditor(SfizzVstController* controller) : VSTGUIEditor(controller, &sfizzUiViewRect), oscTemp_(new uint8_t[kOscTempSize]) { - oscQueue_.reserve(kOscQueueSize); } SfizzVstEditor::~SfizzVstEditor() @@ -56,10 +55,14 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p editor_.reset(editor); } - mustRedisplayState_ = true; - mustRedisplayUiState_ = true; - mustRedisplayPlayState_ = true; - flushOscQueue(); + withStateLock([this]() { + mustRedisplayState_ = true; + mustRedisplayUiState_ = true; + mustRedisplayPlayState_ = true; + OscByteVec* queue = new OscByteVec; + oscQueue_.reset(queue); + queue->reserve(kOscQueueSize); + }); updateStateDisplay(); @@ -86,7 +89,9 @@ void PLUGIN_API SfizzVstEditor::close() this->frame = nullptr; } - flushOscQueue(); + withStateLock([this]() { + oscQueue_.reset(); + }); } /// @@ -121,71 +126,73 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message) void SfizzVstEditor::updateState(const SfizzVstState& state) { - std::lock_guard lock(stateMutex_); - state_ = state; - mustRedisplayState_ = true; + withStateLock([this, &state]() { + state_ = state; + mustRedisplayState_ = true; + }); } void SfizzVstEditor::updateUiState(const SfizzUiState& uiState) { - std::lock_guard lock(stateMutex_); - uiState_ = uiState; - mustRedisplayUiState_ = true; + withStateLock([this, &uiState]() { + uiState_ = uiState; + mustRedisplayUiState_ = true; + }); } void SfizzVstEditor::updatePlayState(const SfizzPlayState& playState) { - std::lock_guard lock(stateMutex_); - playState_ = playState; - mustRedisplayPlayState_ = true; + withStateLock([this, &playState]() { + playState_ = playState; + mustRedisplayPlayState_ = true; + }); } SfizzUiState SfizzVstEditor::getCurrentUiState() const { - std::lock_guard lock(stateMutex_); - return uiState_; + SfizzUiState uiState; + withStateLock([this, &uiState]() { + uiState = uiState_; + }); + return uiState; } void SfizzVstEditor::receiveMessage(const void* data, uint32_t size) { - if (!frame) { - // only accumulate if message processing is active - return; - } + // Note: may be called from non-UI thread (Reaper) - std::lock_guard lock(stateMutex_); - std::copy( - reinterpret_cast(data), - reinterpret_cast(data) + size, - std::back_inserter(oscQueue_)); + withStateLock([this, data, size]() { + if (OscByteVec* queue = oscQueue_.get()) { + const uint8_t* bytes = reinterpret_cast(data); + std::copy(bytes, bytes + size, std::back_inserter(*queue)); + } + }); } void SfizzVstEditor::processOscQueue() { - std::lock_guard lock(stateMutex_); + withStateLock([this]() { + OscByteVec* queue = oscQueue_.get(); + if (!queue) + return; - const uint8_t* oscData = oscQueue_.data(); - size_t oscSize = oscQueue_.size(); + const uint8_t* oscData = queue->data(); + size_t oscSize = queue->size(); - const char* path; - const char* sig; - const sfizz_arg_t* args; - uint8_t buffer[1024]; + const char* path; + const char* sig; + const sfizz_arg_t* args; + uint8_t buffer[1024]; - uint32_t msgSize; - while ((msgSize = sfizz_extract_message(oscData, oscSize, buffer, sizeof(buffer), &path, &sig, &args)) > 0) { - uiReceiveMessage(path, sig, args); - oscData += msgSize; - oscSize -= msgSize; - } + uint32_t msgSize; + while ((msgSize = sfizz_extract_message(oscData, oscSize, buffer, sizeof(buffer), &path, &sig, &args)) > 0) { + uiReceiveMessage(path, sig, args); + oscData += msgSize; + oscSize -= msgSize; + } - oscQueue_.clear(); -} - -void SfizzVstEditor::flushOscQueue() -{ - std::lock_guard lock(stateMutex_); - oscQueue_.clear(); + queue->clear(); + }); } /// @@ -333,41 +340,37 @@ void SfizzVstEditor::updateStateDisplay() if (!frame) return; - if (!(mustRedisplayState_ || mustRedisplayUiState_ || mustRedisplayPlayState_)) - return; + withStateLock([this]() { + if (mustRedisplayState_) { + uiReceiveValue(EditId::SfzFile, state_.sfzFile); + uiReceiveValue(EditId::Volume, state_.volume); + uiReceiveValue(EditId::Polyphony, state_.numVoices); + uiReceiveValue(EditId::Oversampling, 1u << state_.oversamplingLog2); + uiReceiveValue(EditId::PreloadSize, state_.preloadSize); + uiReceiveValue(EditId::ScalaFile, state_.scalaFile); + uiReceiveValue(EditId::ScalaRootKey, state_.scalaRootKey); + uiReceiveValue(EditId::TuningFrequency, state_.tuningFrequency); + uiReceiveValue(EditId::StretchTuning, state_.stretchedTuning); + mustRedisplayState_ = false; + } - std::lock_guard lock(stateMutex_); + /// + if (mustRedisplayUiState_) { + uiReceiveValue(EditId::UIActivePanel, uiState_.activePanel); + mustRedisplayUiState_ = false; + } - /// - if (mustRedisplayState_) { - uiReceiveValue(EditId::SfzFile, state_.sfzFile); - uiReceiveValue(EditId::Volume, state_.volume); - uiReceiveValue(EditId::Polyphony, state_.numVoices); - uiReceiveValue(EditId::Oversampling, 1u << state_.oversamplingLog2); - uiReceiveValue(EditId::PreloadSize, state_.preloadSize); - uiReceiveValue(EditId::ScalaFile, state_.scalaFile); - uiReceiveValue(EditId::ScalaRootKey, state_.scalaRootKey); - uiReceiveValue(EditId::TuningFrequency, state_.tuningFrequency); - uiReceiveValue(EditId::StretchTuning, state_.stretchedTuning); - mustRedisplayState_ = false; - } - - /// - if (mustRedisplayUiState_) { - uiReceiveValue(EditId::UIActivePanel, uiState_.activePanel); - mustRedisplayUiState_ = false; - } - - /// - if (mustRedisplayPlayState_) { - uiReceiveValue(EditId::UINumCurves, playState_.curves); - uiReceiveValue(EditId::UINumMasters, playState_.masters); - uiReceiveValue(EditId::UINumGroups, playState_.groups); - uiReceiveValue(EditId::UINumRegions, playState_.regions); - uiReceiveValue(EditId::UINumPreloadedSamples, playState_.preloadedSamples); - uiReceiveValue(EditId::UINumActiveVoices, playState_.activeVoices); - mustRedisplayPlayState_ = false; - } + /// + if (mustRedisplayPlayState_) { + uiReceiveValue(EditId::UINumCurves, playState_.curves); + uiReceiveValue(EditId::UINumMasters, playState_.masters); + uiReceiveValue(EditId::UINumGroups, playState_.groups); + uiReceiveValue(EditId::UINumRegions, playState_.regions); + uiReceiveValue(EditId::UINumPreloadedSamples, playState_.preloadedSamples); + uiReceiveValue(EditId::UINumActiveVoices, playState_.activeVoices); + mustRedisplayPlayState_ = false; + } + }); } Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id) diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index e6b48478..e5fa0d8d 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -43,7 +43,12 @@ public: private: void processOscQueue(); - void flushOscQueue(); + + template void withStateLock(F&& fn) const + { + std::lock_guard lock(stateMutex_); + fn(); + } protected: // EditorController @@ -72,12 +77,13 @@ private: // editor state // note: might be updated from a non-UI thread - mutable std::recursive_mutex stateMutex_; - SfizzVstState state_; - SfizzUiState uiState_; - SfizzPlayState playState_; + mutable std::recursive_mutex stateMutex_; // for R/W the state data, and OSC queue + SfizzVstState state_ {}; + SfizzUiState uiState_ {}; + SfizzPlayState playState_ {}; volatile bool mustRedisplayState_ = false; volatile bool mustRedisplayUiState_ = false; volatile bool mustRedisplayPlayState_ = false; - std::vector oscQueue_; + typedef std::vector OscByteVec; + std::unique_ptr oscQueue_; }; From 4d4ffdeb46fec10e1196aa513cb8de628669d566 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 7 Dec 2020 10:55:35 +0100 Subject: [PATCH 116/668] Move some builds and deployments to github actions --- .github/workflows/build.yml | 335 ++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..44e48225 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,335 @@ +name: build + +on: + push: + branches: + - '*' + tags: + - '[0-9]*' + - 'v[0-9]*' + pull_request: + branches: + - '*' +env: + BUILD_TYPE: Release + +jobs: + clang_tidy: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up dependencies + run: | + sudo apt-get update && \ + sudo apt-get install \ + clang-tidy \ + libsndfile1-dev + - name: Clang Tidy + working-directory: ${{runner.workspace}} + run: cd "$GITHUB_WORKSPACE" && scripts/run_clang_tidy.sh + + build_for_linux: + runs-on: ubuntu-18.04 + steps: + - name: Set install name + run: | + echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV" + echo "install_name=sfizz-${GITHUB_REF##*/}-linux" >> "$GITHUB_ENV" + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up dependencies + run: | + sudo apt-get update && \ + sudo apt-get install \ + libjack-jackd2-dev \ + libsndfile1-dev \ + libcairo2-dev \ + libfontconfig1-dev \ + libx11-xcb-dev \ + libxcb-util-dev \ + libxcb-cursor-dev \ + libxcb-xkb-dev \ + libxkbcommon-dev \ + libxkbcommon-x11-dev \ + libxcb-keysyms1-dev + - name: Create Build Environment + shell: bash + working-directory: ${{runner.workspace}} + run: cmake -E make_directory build + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: | + cmake "$GITHUB_WORKSPACE" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ + -DSFIZZ_JACK=ON \ + -DSFIZZ_VST=ON \ + -DSFIZZ_LV2_UI=ON \ + -DSFIZZ_TESTS=ON \ + -DSFIZZ_SHARED=OFF \ + -DSFIZZ_STATIC_DEPENDENCIES=OFF \ + -DSFIZZ_LV2=ON \ + -DCMAKE_CXX_STANDARD=17 + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake --build . --config "$BUILD_TYPE" -j 2 + - name: Test + working-directory: ${{runner.workspace}}/build + shell: bash + run: tests/sfizz_tests + - name: Install + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + DESTDIR="$(pwd)/$install_name" cmake --build . --config "$BUILD_TYPE" --target install + tar czvf "$install_name".tar.gz "$install_name" + - uses: actions/upload-artifact@v2 + with: + name: Linux tarball + path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz + + build_for_mod: + runs-on: ubuntu-18.04 + container: + image: jpcima/mod-plugin-builder + options: --user 0 + steps: + - name: Set install name + run: | + echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV" + echo "install_name=sfizz-${GITHUB_REF##*/}-moddevices" >> "$GITHUB_ENV" + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Fix up MOD environment + shell: bash + run: ln -sf /home/builder/mod-workdir ~/mod-workdir + - name: Create Build Environment + shell: bash + working-directory: ${{runner.workspace}} + run: mod-plugin-builder /usr/local/bin/cmake -E make_directory build + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: | + mod-plugin-builder /usr/local/bin/cmake "$GITHUB_WORKSPACE" \ + -DSFIZZ_SYSTEM_PROCESSOR=armv7-a \ + -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_LV2_UI=OFF + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/build + run: mod-plugin-builder /usr/local/bin/cmake --build . --config "$BUILD_TYPE" -- -j 2 + - name: Install + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + DESTDIR="$(pwd)/$install_name" mod-plugin-builder /usr/local/bin/cmake --build . --config "$BUILD_TYPE" --target install + tar czvf "$install_name".tar.gz "$install_name" + - uses: actions/upload-artifact@v2 + with: + name: MOD devices tarball + path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz + + build_for_mingw32: + runs-on: ubuntu-18.04 + container: + image: archlinux + steps: + - name: Set install name + run: | + echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV" + echo "install_name=sfizz-${GITHUB_REF##*/}-mingw32" >> "$GITHUB_ENV" + - name: Configure pacman repositories + shell: bash + run: | + cat >>/etc/pacman.conf <//' + - name: Create Build Environment + shell: bash + working-directory: ${{runner.workspace}} + run: cmake -E make_directory build + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: | + i686-w64-mingw32-cmake "$GITHUB_WORKSPACE" \ + -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ + -DENABLE_LTO=OFF \ + -DSFIZZ_JACK=OFF \ + -DSFIZZ_VST=ON \ + -DSFIZZ_STATIC_DEPENDENCIES=ON \ + -DCMAKE_CXX_STANDARD=17 + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/build + run: i686-w64-mingw32-cmake --build . --config "$BUILD_TYPE" -j 2 + - name: Install + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + DESTDIR="$(pwd)/$install_name" i686-w64-mingw32-cmake --build . --config "$BUILD_TYPE" --target install + tar czvf "$install_name".tar.gz "$install_name" + - uses: actions/upload-artifact@v2 + with: + name: Win32 MinGW tarball + path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz + + build_for_mingw64: + runs-on: ubuntu-18.04 + container: + image: archlinux + steps: + - name: Set install name + run: | + echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV" + echo "install_name=sfizz-${GITHUB_REF##*/}-mingw64" >> "$GITHUB_ENV" + - name: Configure pacman repositories + shell: bash + run: | + cat >>/etc/pacman.conf <//' + - name: Create Build Environment + shell: bash + working-directory: ${{runner.workspace}} + run: cmake -E make_directory build + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: | + x86_64-w64-mingw32-cmake "$GITHUB_WORKSPACE" \ + -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ + -DENABLE_LTO=OFF \ + -DSFIZZ_JACK=OFF \ + -DSFIZZ_VST=ON \ + -DSFIZZ_STATIC_DEPENDENCIES=ON \ + -DCMAKE_CXX_STANDARD=17 + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/build + run: x86_64-w64-mingw32-cmake --build . --config "$BUILD_TYPE" -j 2 + - name: Install + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + DESTDIR="$(pwd)/$install_name" x86_64-w64-mingw32-cmake --build . --config "$BUILD_TYPE" --target install + tar czvf "$install_name".tar.gz "$install_name" + - uses: actions/upload-artifact@v2 + with: + name: Win64 MinGW tarball + path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz + + archive_source_code: + runs-on: ubuntu-18.04 + if: startsWith(github.ref, 'refs/tags/') + steps: + - name: Set install name + run: | + echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV" + echo "install_name=sfizz-${GITHUB_REF##*/}" >> "$GITHUB_ENV" + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Set up dependencies + run: | + sudo apt-get update && \ + sudo apt-get install \ + python-pip + sudo pip install git-archive-all + - name: Archive source code + shell: bash + run: | + cd "$GITHUB_WORKSPACE" && \ + git-archive-all --prefix="${install_name}/" -9 "${{runner.workspace}}/${install_name}.tar.gz" + - uses: actions/upload-artifact@v2 + with: + name: Source code tarball + path: ${{runner.workspace}}/${{env.install_name}}.tar.gz + + deploy: + runs-on: ubuntu-18.04 + if: startsWith(github.ref, 'refs/tags/') + needs: + - build_for_linux + - build_for_mod + - build_for_mingw32 + - build_for_mingw64 + - archive_source_code + steps: + - name: Set install name + run: | + echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV" + - uses: actions/download-artifact@v2 + with: + name: Linux tarball + - uses: actions/download-artifact@v2 + with: + name: MOD devices tarball + - uses: actions/download-artifact@v2 + with: + name: Win32 MinGW tarball + - uses: actions/download-artifact@v2 + with: + name: Win64 MinGW tarball + - uses: actions/download-artifact@v2 + with: + name: Source code tarball + - name: Display file information + shell: bash + run: ls -lR + ## Note: not using `actions/create-release@v1` + ## because it cannot update an existing release + ## see https://github.com/actions/create-release/issues/29 + - uses: softprops/action-gh-release@v1 + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + with: + tag_name: ${{env.install_ref}} + name: Release ${{env.install_ref}} + draft: false + prerelease: false + files: | + sfizz-${{env.install_ref}}-* + sfizz-${{env.install_ref}}.* From 872cebd74af082bc2cd8bf30a6abe7d446acf138 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 8 Dec 2020 05:43:32 +0100 Subject: [PATCH 117/668] Remove old travis jobs --- .travis.yml | 98 ---------------------------- .travis/before_install_mingw.sh | 17 ----- .travis/before_install_moddevices.sh | 6 -- .travis/docker_container.sh | 25 ------- .travis/download_vst_sdk.sh | 11 ---- .travis/install_mingw.sh | 8 --- .travis/install_moddevices.sh | 4 -- .travis/no_container.sh | 7 -- .travis/prepare_tarball.sh | 8 +-- .travis/script_mingw.sh | 30 --------- .travis/script_moddevices.sh | 11 ---- .travis/script_osx.sh | 16 ----- 12 files changed, 1 insertion(+), 240 deletions(-) delete mode 100755 .travis/before_install_mingw.sh delete mode 100755 .travis/before_install_moddevices.sh delete mode 100755 .travis/docker_container.sh delete mode 100755 .travis/download_vst_sdk.sh delete mode 100755 .travis/install_mingw.sh delete mode 100755 .travis/install_moddevices.sh delete mode 100755 .travis/no_container.sh delete mode 100755 .travis/script_mingw.sh delete mode 100755 .travis/script_moddevices.sh delete mode 100755 .travis/script_osx.sh diff --git a/.travis.yml b/.travis.yml index 8ed0c817..2ddb256c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,36 +8,6 @@ cache: jobs: include: - - name: "clang-tidy checks" - addons: - apt: - packages: - - clang-tidy - - wget - - unzip - - libsndfile-dev - install: .travis/download_vst_sdk.sh - script: scripts/run_clang_tidy.sh - - - name: "Linux amd64 test and build" - arch: amd64 - addons: - apt: - packages: - - libjack-jackd2-dev - - libsndfile1-dev - - libcairo2-dev - - libfontconfig1-dev - - libx11-xcb-dev - - libxcb-util-dev - - libxcb-cursor-dev - - libxcb-xkb-dev - - libxkbcommon-dev - - libxkbcommon-x11-dev - - libxcb-keysyms1-dev - install: .travis/download_cmake.sh - script: .travis/script_test_and_build.sh - - name: "Linux arm64 test and build" arch: arm64-graviton2 group: edge @@ -59,37 +29,6 @@ jobs: install: .travis/download_cmake.sh script: .travis/script_test_and_build.sh - - name: "MOD devices arm" - env: - - CONTAINER=jpcima/mod-plugin-builder - - CROSS_COMPILE=moddevices-arm - - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-moddevices" - - DEPLOY_BUILD=true - before_install: .travis/before_install_moddevices.sh - install: .travis/install_moddevices.sh - script: .travis/script_moddevices.sh - after_success: .travis/prepare_tarball.sh - - - name: "Windows mingw32" - env: - - CROSS_COMPILE=mingw32 - - CONTAINER=archlinux - - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-mingw32" - before_install: .travis/before_install_mingw.sh - install: .travis/install_mingw.sh - script: .travis/script_mingw.sh - after_success: .travis/prepare_tarball.sh - - - name: "Windows mingw64" - env: - - CROSS_COMPILE=mingw64 - - CONTAINER=archlinux - - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-mingw64" - before_install: .travis/before_install_mingw.sh - install: .travis/install_mingw.sh - script: .travis/script_mingw.sh - after_success: .travis/prepare_tarball.sh - - name: "Linux arm64 static plugins" arch: arm64-graviton2 group: edge @@ -109,43 +48,6 @@ jobs: script: .travis/script_plugins.sh after_success: .travis/prepare_tarball.sh - - name: "Linux amd64 static plugins" - env: - - INSTALL_DIR="sfizz-plugins-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}" - - ENABLE_VST_PLUGIN=ON - - ENABLE_LV2_UI=ON - addons: - apt: - packages: - - libjack-jackd2-dev - - libsndfile1-dev - - libcairo2-dev - - libfontconfig1-dev - - libx11-xcb-dev - - libxcb-util-dev - - libxcb-cursor-dev - - libxcb-xkb-dev - - libxkbcommon-dev - - libxkbcommon-x11-dev - - libxcb-keysyms1-dev - install: - - .travis/download_cmake.sh - - .travis/download_static_libs.sh - script: .travis/script_plugins.sh - after_success: .travis/prepare_tarball.sh - - - stage: "Deploy" - name: "Source packaging" - if: (tag =~ /^v?[0-9]/) AND (type = push) - env: - - INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-src" - addons: - apt: - packages: - - python-pip - install: sudo pip install git-archive-all - script: git-archive-all --prefix="sfizz-${TRAVIS_BRANCH}/" -9 "${INSTALL_DIR}.tar.gz" - - name: "Discord Webhook" install: skip script: bash ${TRAVIS_BUILD_DIR}/.travis/discord_webhook.sh success diff --git a/.travis/before_install_mingw.sh b/.travis/before_install_mingw.sh deleted file mode 100755 index 069f5929..00000000 --- a/.travis/before_install_mingw.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -ex -. .travis/docker_container.sh - -buildenv bash -c "echo Hello from container" # ensure to start the container -docker cp "$container":/etc/pacman.conf pacman.conf -cat >>pacman.conf < ${TRAVIS_BUILD_DIR}/docker-container-id - fi -} diff --git a/.travis/download_vst_sdk.sh b/.travis/download_vst_sdk.sh deleted file mode 100755 index 3eee309e..00000000 --- a/.travis/download_vst_sdk.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -ex - -vst_download_prefix="vst/download" -vst_sdk_archive="vst-sdk_3.6.14_build-24_2019-11-29.zip" -mkdir -p ${vst_download_prefix} -if ! [[ -f "${vst_download_prefix}/${vst_sdk_archive}" ]]; then - wget -P ${vst_download_prefix} "https://download.steinberg.net/sdk_downloads/${vst_sdk_archive}" -fi -mkdir -p vst/external -unzip -ouq "${vst_download_prefix}/${vst_sdk_archive}" -d "vst/external" diff --git a/.travis/install_mingw.sh b/.travis/install_mingw.sh deleted file mode 100755 index 882b5d52..00000000 --- a/.travis/install_mingw.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -ex -. .travis/docker_container.sh - -buildenv_as_root pacman -Sqyu --noconfirm -buildenv_as_root pacman -Sq --noconfirm base-devel wget mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile -buildenv i686-w64-mingw32-gcc -v && buildenv i686-w64-mingw32-g++ -v && buildenv i686-w64-mingw32-cmake --version diff --git a/.travis/install_moddevices.sh b/.travis/install_moddevices.sh deleted file mode 100755 index e28460cb..00000000 --- a/.travis/install_moddevices.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -set -ex -. .travis/docker_container.sh diff --git a/.travis/no_container.sh b/.travis/no_container.sh deleted file mode 100755 index 528915f2..00000000 --- a/.travis/no_container.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -ex - -buildenv() { - "$@" -} diff --git a/.travis/prepare_tarball.sh b/.travis/prepare_tarball.sh index 1447feea..d19ce65d 100755 --- a/.travis/prepare_tarball.sh +++ b/.travis/prepare_tarball.sh @@ -2,14 +2,8 @@ set -ex -if ! [ -z "$CONTAINER" ]; then - . .travis/docker_container.sh -else - . .travis/no_container.sh -fi - cd build -buildenv make DESTDIR=${PWD}/${INSTALL_DIR} install +make DESTDIR=${PWD}/${INSTALL_DIR} install tar -zcvf "${INSTALL_DIR}.tar.gz" ${INSTALL_DIR} # Only release a tarball if there is a tag diff --git a/.travis/script_mingw.sh b/.travis/script_mingw.sh deleted file mode 100755 index cdd4b941..00000000 --- a/.travis/script_mingw.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -ex -. .travis/docker_container.sh - -# need to convert some includes to lower case (as of VST 3.7.1) -find vst/external/VST_SDK -type d -name source -exec \ - find {} -type f -name '*.[hc]' -o -name '*.[hc]pp' -print0 \; | \ - xargs -0 sed -i 's///' - -mkdir -p build/${INSTALL_DIR} && cd build -if [[ ${CROSS_COMPILE} == "mingw32" ]]; then - buildenv i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=Release \ - -DENABLE_LTO=OFF \ - -DSFIZZ_JACK=OFF \ - -DSFIZZ_VST=ON \ - -DSFIZZ_STATIC_DEPENDENCIES=ON \ - -DCMAKE_CXX_STANDARD=17 \ - .. - buildenv make -j2 -elif [[ ${CROSS_COMPILE} == "mingw64" ]]; then - buildenv x86_64-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=Release \ - -DENABLE_LTO=OFF \ - -DSFIZZ_JACK=OFF \ - -DSFIZZ_VST=ON \ - -DSFIZZ_STATIC_DEPENDENCIES=ON \ - -DCMAKE_CXX_STANDARD=17 \ - .. - buildenv make -j2 -fi diff --git a/.travis/script_moddevices.sh b/.travis/script_moddevices.sh deleted file mode 100755 index 3654590d..00000000 --- a/.travis/script_moddevices.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -ex -. .travis/docker_container.sh - -mkdir -p build/${INSTALL_DIR} && cd build - -buildenv mod-plugin-builder /usr/local/bin/cmake \ - -DSFIZZ_SYSTEM_PROCESSOR=armv7-a \ - -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_LV2_UI=OFF .. -buildenv mod-plugin-builder make -j2 diff --git a/.travis/script_osx.sh b/.travis/script_osx.sh deleted file mode 100755 index 0385f8c3..00000000 --- a/.travis/script_osx.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -set -ex - -mkdir -p build/${INSTALL_DIR} && cd build -cmake -DCMAKE_BUILD_TYPE=Release \ - -DSFIZZ_VST=ON \ - -DSFIZZ_AU=ON \ - -DSFIZZ_TESTS=OFF \ - -DCMAKE_CXX_STANDARD=14 \ - -DLV2PLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/LV2 \ - -DVSTPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/VST3 \ - -DAUPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/Components \ - .. -make -j$(sysctl -n hw.ncpu) -# Xcode not currently supported, see https://gitlab.kitware.com/cmake/cmake/issues/18088 -# xcodebuild -project sfizz.xcodeproj -alltargets -configuration Debug build From 0acbce5274729649bb2b1947d9cb63c1cf7d2235 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 9 Dec 2020 08:58:04 +0100 Subject: [PATCH 118/668] Global settings access for VST --- vst/CMakeLists.txt | 6 +- vst/SfizzForeignPaths.cpp | 27 +++--- vst/SfizzSettings.cpp | 173 ++++++++++++++++++++++++++++++++++++++ vst/SfizzSettings.h | 16 ++++ vst/SfizzSettings.mm | 38 +++++++++ 5 files changed, 247 insertions(+), 13 deletions(-) create mode 100644 vst/SfizzSettings.cpp create mode 100644 vst/SfizzSettings.h create mode 100644 vst/SfizzSettings.mm diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 8f993b8c..9d13eac0 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -19,6 +19,7 @@ set(VSTPLUGIN_SOURCES SfizzVstState.cpp SfizzFileScan.cpp SfizzForeignPaths.cpp + SfizzSettings.cpp VstPluginFactory.cpp X11RunLoop.cpp NativeHelpers.cpp @@ -31,6 +32,7 @@ set(VSTPLUGIN_HEADERS SfizzVstState.h SfizzFileScan.h SfizzForeignPaths.h + SfizzSettings.h X11RunLoop.h NativeHelpers.h FileTrie.h) @@ -38,6 +40,7 @@ set(VSTPLUGIN_HEADERS if(APPLE) set(VSTPLUGIN_MAC_SOURCES SfizzForeignPaths.mm + SfizzSettings.mm NativeHelpers.mm) list(APPEND VSTPLUGIN_SOURCES ${VSTPLUGIN_MAC_SOURCES}) set_property(SOURCE ${VSTPLUGIN_MAC_SOURCES} APPEND_STRING @@ -53,7 +56,8 @@ if(WIN32) endif() target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} - PRIVATE sfizz_editor) + PRIVATE sfizz_editor + PRIVATE sfizz-pugixml) target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES diff --git a/vst/SfizzForeignPaths.cpp b/vst/SfizzForeignPaths.cpp index 17319997..df7009df 100644 --- a/vst/SfizzForeignPaths.cpp +++ b/vst/SfizzForeignPaths.cpp @@ -15,8 +15,6 @@ fs::path getAriaPathSetting(const char* name) { fs::path path; - HKEY key = 0; - std::unique_ptr nameW; unsigned nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0); if (nameSize == 0) @@ -27,17 +25,22 @@ fs::path getAriaPathSetting(const char* name) const WCHAR ariaKeyPath[] = L"Software\\Plogue Art et Technologie, Inc\\Aria"; - if (RegOpenKeyExW(HKEY_CURRENT_USER, ariaKeyPath, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { - WCHAR valueBuffer[32768 + 1]; - DWORD valueSize = sizeof(valueBuffer) - sizeof(WCHAR); - if (RegQueryValueExW(key, nameW.get(), nullptr, nullptr, reinterpret_cast(valueBuffer), &valueSize) == ERROR_SUCCESS) { - valueBuffer[32768] = L'\0'; - path = fs::path(valueBuffer); - } - RegCloseKey(key); - } + HKEY key = nullptr; + LSTATUS status = RegOpenKeyExW(HKEY_CURRENT_USER, ariaKeyPath, 0, KEY_QUERY_VALUE, &key); + if (status != ERROR_SUCCESS) + return {}; - return path; + WCHAR valueW[32768]; + DWORD valueSize = sizeof(valueW); + DWORD valueType; + status = RegQueryValueExW( + key, nameW.get(), nullptr, + &valueType, reinterpret_cast(valueW), &valueSize); + RegCloseKey(key); + if (status != ERROR_SUCCESS || (valueType != REG_SZ && valueType != REG_EXPAND_SZ)) + return {}; + + return fs::path(valueW); } #elif defined(__APPLE__) // implementation in SfizzForeignPaths.mm diff --git a/vst/SfizzSettings.cpp b/vst/SfizzSettings.cpp new file mode 100644 index 00000000..9560d16d --- /dev/null +++ b/vst/SfizzSettings.cpp @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzSettings.h" +#include + +std::string SfizzSettings::load_or(const char* key, absl::string_view defaultValue) +{ + absl::optional optValue = load(key); + return optValue ? *optValue : std::string(defaultValue); +} + +#if defined(_WIN32) +#include + +static HKEY openRegistryKey() +{ + LSTATUS status; + HKEY root = HKEY_CURRENT_USER; + HKEY parent = root; + HKEY key = nullptr; + for (const WCHAR* component : {L"Software", L"SFZTools", L"sfizz"}) { + status = RegCreateKeyExW( + parent, component, 0, nullptr, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, &key, nullptr); + if (parent != root) + RegCloseKey(parent); + if (status != ERROR_SUCCESS) + return nullptr; + parent = key; + } + return key; +} + +static WCHAR* stringToWideChar(const char *str, int strCch = -1) +{ + unsigned strSize = MultiByteToWideChar(CP_UTF8, 0, str, strCch, nullptr, 0); + if (strSize == 0) + return {}; + std::unique_ptr strW(new WCHAR[strSize]); + if (MultiByteToWideChar(CP_UTF8, 0, str, strCch, strW.get(), strSize) == 0) + return {}; + return strW.release(); +} + +static char* stringToUTF8(const wchar_t *strW, int strWCch = -1) +{ + unsigned strSize = WideCharToMultiByte(CP_UTF8, 0, strW, strWCch, nullptr, 0, nullptr, nullptr); + if (strSize == 0) + return {}; + std::unique_ptr str(new char[strSize]); + if (WideCharToMultiByte(CP_UTF8, 0, strW, strWCch, str.get(), strSize, nullptr, nullptr) == 0) + return {}; + return str.release(); +} + +absl::optional SfizzSettings::load(const char* name) +{ + std::unique_ptr nameW { stringToWideChar(name) }; + if (!nameW) + return {}; + + HKEY key = openRegistryKey(); + if (!key) + return {}; + + WCHAR valueW[32768]; + DWORD valueSize = sizeof(valueW); + DWORD valueType; + LSTATUS status = RegQueryValueExW( + key, nameW.get(), nullptr, + &valueType, reinterpret_cast(valueW), &valueSize); + RegCloseKey(key); + if (status != ERROR_SUCCESS || (valueType != REG_SZ && valueType != REG_EXPAND_SZ)) + return {}; + + std::unique_ptr value { stringToUTF8(valueW) }; + if (!value) + return {}; + + return std::string(value.get()); +} + +bool SfizzSettings::store(const char* name, absl::string_view value) +{ + std::unique_ptr nameW { stringToWideChar(name) }; + std::unique_ptr valueW { stringToWideChar(std::string(value).c_str()) }; + if (!nameW || !valueW) + return false; + + HKEY key = openRegistryKey(); + if (!key) + return {}; + + LSTATUS status = RegSetValueExW( + key, nameW.get(), 0, RRF_RT_REG_SZ, + reinterpret_cast(valueW.get()), + (wcslen(valueW.get()) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + return status == ERROR_SUCCESS; +} +#elif defined(__APPLE__) + // implementation in SfizzSettings.mm +#else +#include +#include + +static const fs::path getSettingsPath() +{ + fs::path dirPath; + const char* env; + if ((env = getenv("XDG_CONFIG_HOME")) && env[0] == '/') + dirPath = fs::path(env); + else if ((env = getenv("HOME")) && env[0] == '/') + dirPath = fs::path(env) / ".config"; + else + return {}; + dirPath /= "SFZTools"; + dirPath /= "sfizz"; + std::error_code ec; + if (!fs::create_directories(dirPath, ec)) + return {}; + return dirPath / "settings.xml"; +} + +absl::optional SfizzSettings::load(const char* key) +{ + const fs::path path = getSettingsPath(); + if (path.empty()) + return {}; + + pugi::xml_document doc; + if (!doc.load_file(path.c_str())) + return {}; + + pugi::xml_node root = doc.child("properties"); + if (!root) + return {}; + + pugi::xml_node entry = root.find_child_by_attribute("entry", "key", key); + if (!entry) + return {}; + + return std::string(entry.text().get()); +} + +bool SfizzSettings::store(const char* key, absl::string_view value) +{ + const fs::path path = getSettingsPath(); + if (path.empty()) + return false; + + pugi::xml_document doc; + doc.load_file(path.c_str()); + + pugi::xml_node root = doc.child("properties"); + if (!root) + root = doc.append_child("properties"); + + pugi::xml_node entry = root.find_child_by_attribute("entry", "key", key); + if (!entry) { + entry = root.append_child("entry"); + entry.append_attribute("key").set_value(key); + } + entry.text().set(std::string(value).c_str()); + + return doc.save_file(path.c_str()); +} +#endif diff --git a/vst/SfizzSettings.h b/vst/SfizzSettings.h new file mode 100644 index 00000000..2fcc2927 --- /dev/null +++ b/vst/SfizzSettings.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include + +class SfizzSettings { +public: + absl::optional load(const char* key); + std::string load_or(const char* key, absl::string_view defaultValue); + bool store(const char* key, absl::string_view value); +}; diff --git a/vst/SfizzSettings.mm b/vst/SfizzSettings.mm new file mode 100644 index 00000000..9ddbaeb4 --- /dev/null +++ b/vst/SfizzSettings.mm @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzSettings.h" + +#if defined(__APPLE__) +#import +#if !__has_feature(objc_arc) +#error This source file requires ARC +#endif + +static NSUserDefaults* getUserDefaults() +{ + return [[NSUserDefaults alloc] initWithSuiteName:@"tools.sfz.sfizz"];; +} + +absl::optional SfizzSettings::load(const char* key) +{ + NSUserDefaults* ud = getUserDefaults(); + NSString* value = [ud stringForKey:[NSString stringWithUTF8String:key]]; + if (!value) + return {}; + return std::string(value.UTF8String); +} + +bool SfizzSettings::store(const char* key, absl::string_view value) +{ + NSUserDefaults* ud = getUserDefaults(); + NSString* object = + [[NSString alloc] initWithBytes:value.data() + length:(NSUInteger)value.size() encoding:NSUTF8StringEncoding]; + [ud setObject:object forKey:[NSString stringWithUTF8String:key]]; + return true; +} +#endif From 0cb1b67bfab45963440d3cde36e875bfc1591019 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 9 Dec 2020 15:40:42 +0100 Subject: [PATCH 119/668] Use a custom SFZ path set in user configuration --- vst/SfizzFileScan.cpp | 64 ++++++++++++++++++++++++--------------- vst/SfizzFileScan.h | 7 +++-- vst/SfizzVstProcessor.cpp | 13 +++++++- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index 9971d6ab..a56f2e4a 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -6,10 +6,10 @@ #include "SfizzFileScan.h" #include "SfizzForeignPaths.h" +#include "SfizzSettings.h" #include "NativeHelpers.h" #include #include -#include #include // wait at least this much before refreshing the file rescan @@ -63,7 +63,7 @@ void SfzFileScan::refreshScan(bool force) FileTrieBuilder builder; - for (const fs::path& dirPath : SfizzPaths::sfzDefaultPaths()) { + for (const fs::path& dirPath : SfizzPaths::getSfzSearchPaths()) { std::error_code ec; const fs::directory_options dirOpts = fs::directory_options::skip_permission_denied; @@ -183,36 +183,52 @@ const fs::path& SfzFileScan::electBestMatch(const fs::path& path, absl::Span sfzDefaultPaths() +std::vector getSfzSearchPaths() { - static const auto paths = []() -> std::vector { - std::vector paths; - paths.reserve(8); - auto addPath = [&paths](const fs::path& newPath) { - if (absl::c_find(paths, newPath) == paths.end()) - paths.push_back(newPath); - }; + std::vector paths; + paths.reserve(8); + auto addPath = [&paths](const fs::path& newPath) { + if (absl::c_find(paths, newPath) == paths.end()) + paths.push_back(newPath); + }; - addPath(getUserDocumentsDirectory() / "SFZ instruments"); + absl::optional configDefaultPath = getSfzConfigDefaultPath(); + fs::path fallbackDefaultPath = getSfzFallbackDefaultPath(); - for (const fs::path& foreign : { - getAriaPathSetting("user_files_dir"), - getAriaPathSetting("Converted_path") }) - if (!foreign.empty() && foreign.is_absolute()) - addPath(foreign); + if (configDefaultPath) + addPath(*configDefaultPath); + addPath(fallbackDefaultPath); - paths.shrink_to_fit(); - return paths; - }(); + for (const fs::path& foreign : { + getAriaPathSetting("user_files_dir"), + getAriaPathSetting("Converted_path") }) + if (!foreign.empty() && foreign.is_absolute()) + addPath(foreign); + + paths.shrink_to_fit(); return paths; } -void createSfzDefaultPaths() +absl::optional getSfzConfigDefaultPath() { - for (const fs::path& path : sfzDefaultPaths()) { - std::error_code ec; - fs::create_directory(path, ec); - } + SfizzSettings settings; + fs::path path = fs::u8path(settings.load_or("user_files_dir", {})); + if (path.empty() || !path.is_absolute()) + return {}; + return std::move(path); +} + +void setSfzConfigDefaultPath(const fs::path& path) +{ + if (path.empty() || !path.is_absolute()) + return; + SfizzSettings settings; + settings.store("user_files_dir", path.u8string()); +} + +fs::path getSfzFallbackDefaultPath() +{ + return getUserDocumentsDirectory() / "SFZ instruments"; } } // namespace SfizzPaths diff --git a/vst/SfizzFileScan.h b/vst/SfizzFileScan.h index 2626ef15..19dabf56 100644 --- a/vst/SfizzFileScan.h +++ b/vst/SfizzFileScan.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ private: }; namespace SfizzPaths { -absl::Span sfzDefaultPaths(); -void createSfzDefaultPaths(); +std::vector getSfzSearchPaths(); +absl::optional getSfzConfigDefaultPath(); +void setSfzConfigDefaultPath(const fs::path& path); +fs::path getSfzFallbackDefaultPath(); } // namespace SfizzPaths diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 77de7c43..708979eb 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -38,7 +38,18 @@ SfizzVstProcessor::SfizzVstProcessor() { setControllerClass(SfizzVstController::cid); - SfizzPaths::createSfzDefaultPaths(); + // ensure the SFZ path exists: + // the one specified in the configuration, otherwise the fallback + absl::optional configDefaultPath = SfizzPaths::getSfzConfigDefaultPath(); + if (configDefaultPath) { + std::error_code ec; + fs::create_directory(*configDefaultPath, ec); + } + else { + fs::path fallbackDefaultPath = SfizzPaths::getSfzFallbackDefaultPath(); + std::error_code ec; + fs::create_directory(fallbackDefaultPath, ec); + } } SfizzVstProcessor::~SfizzVstProcessor() From ccdba9d6c7bd11d29296c0b74f0ea8e0281f5427 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 9 Dec 2020 16:27:15 +0100 Subject: [PATCH 120/668] Add ability in the editor to change the user directory --- editor/layout/main.fl | 25 ++++++++++++++--- editor/src/editor/EditIds.h | 2 ++ editor/src/editor/Editor.cpp | 45 +++++++++++++++++++++++++++++++ editor/src/editor/layout/main.hpp | 18 +++++++++---- lv2/sfizz_ui.cpp | 4 +++ vst/SfizzVstEditor.cpp | 9 +++++++ 6 files changed, 94 insertions(+), 9 deletions(-) diff --git a/editor/layout/main.fl b/editor/layout/main.fl index 59d22a06..59ed5298 100644 --- a/editor/layout/main.fl +++ b/editor/layout/main.fl @@ -11,7 +11,7 @@ widget_class mainView {open class Background } Fl_Group {} { - comment {theme=darkTheme} open + comment {theme=darkTheme} xywh {0 0 800 110} class LogicalGroup } { @@ -138,7 +138,7 @@ widget_class mainView {open } } Fl_Group {subPanels_[kPanelGeneral]} { - xywh {5 110 791 285} + xywh {5 110 791 285} hide class LogicalGroup } { Fl_Group {} {open @@ -213,7 +213,7 @@ widget_class mainView {open } } Fl_Group {subPanels_[kPanelSettings]} {open - xywh {5 109 790 286} hide + xywh {5 109 790 316} class LogicalGroup } { Fl_Group {} { @@ -304,8 +304,25 @@ widget_class mainView {open class ValueMenu } } + Fl_Group userFilesGroup_ { + label Files open selected + xywh {620 270 139 100} box ROUNDED_BOX labelsize 12 align 17 + class TitleGroup + } { + Fl_Box {} { + label {User SFZ folder} + xywh {640 290 100 25} labelsize 12 + class ValueLabel + } + Fl_Button userFilesDirButton_ { + label DefaultPath + comment {tag=kTagChooseUserFilesDir} + xywh {640 330 100 25} labelsize 12 + class ValueButton + } + } } - Fl_Box piano_ {selected + Fl_Box piano_ { xywh {5 400 790 70} labelsize 12 class Piano } diff --git a/editor/src/editor/EditIds.h b/editor/src/editor/EditIds.h index 660853db..8645210a 100644 --- a/editor/src/editor/EditIds.h +++ b/editor/src/editor/EditIds.h @@ -17,6 +17,8 @@ enum class EditId : int { ScalaRootKey, TuningFrequency, StretchTuning, + CanEditUserFilesDir, + UserFilesDir, UINumCurves, UINumMasters, UINumGroups, diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 5a4c5a05..f6b16897 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -63,6 +63,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { kTagSetScalaRootKey, kTagSetTuningFrequency, kTagSetStretchedTuning, + kTagChooseUserFilesDir, kTagFirstChangePanel, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, }; @@ -86,6 +87,9 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { CControl *stretchedTuningSlider_ = nullptr; CTextLabel* stretchedTuningLabel_ = nullptr; + STitleContainer* userFilesGroup_ = nullptr; + STextButton* userFilesDirButton_ = nullptr; + CTextLabel* infoCurvesLabel_ = nullptr; CTextLabel* infoMastersLabel_ = nullptr; CTextLabel* infoGroupsLabel_ = nullptr; @@ -118,6 +122,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void changeToNextSfzFile(long offset); void chooseScalaFile(); void changeScalaFile(const std::string& filePath); + void chooseUserFilesDir(); static bool scanDirectoryFiles(const fs::path& dirPath, std::function filter, std::vector& fileNames); @@ -125,6 +130,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void updateSfzFileLabel(const std::string& filePath); void updateScalaFileLabel(const std::string& filePath); + void updateUserFilesDirLabel(const std::string& filePath); static void updateLabelWithFileName(CTextLabel* label, const std::string& filePath, absl::string_view removedSuffix); static void updateButtonWithFileName(STextButton* button, const std::string& filePath, absl::string_view removedSuffix); static void updateSButtonWithFileName(STextButton* button, const std::string& filePath, absl::string_view removedSuffix); @@ -268,6 +274,17 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) updateStretchedTuningLabel(value); } break; + case EditId::CanEditUserFilesDir: + { + if (STitleContainer* group = userFilesGroup_) + group->setVisible(v.to_float()); + break; + } + case EditId::UserFilesDir: + { + updateUserFilesDirLabel(v.to_string()); + break; + } case EditId::UINumCurves: { const int value = static_cast(v.to_float()); @@ -836,6 +853,22 @@ void Editor::Impl::changeScalaFile(const std::string& filePath) updateScalaFileLabel(filePath); } +void Editor::Impl::chooseUserFilesDir() +{ + SharedPointer fs = owned( + CNewFileSelector::create(frame_, CNewFileSelector::kSelectDirectory)); + + fs->setTitle("Set user files directory"); + + if (fs->runModal()) { + UTF8StringPtr dir = fs->getSelectedFile(0); + if (dir) { + updateUserFilesDirLabel(dir); + ctrl_->uiSendValue(EditId::UserFilesDir, std::string(dir)); + } + } +} + bool Editor::Impl::scanDirectoryFiles(const fs::path& dirPath, std::function filter, std::vector& fileNames) { std::error_code ec; @@ -898,6 +931,11 @@ void Editor::Impl::updateScalaFileLabel(const std::string& filePath) updateButtonWithFileName(scalaFileButton_, filePath, ".scl"); } +void Editor::Impl::updateUserFilesDirLabel(const std::string& filePath) +{ + updateButtonWithFileName(userFilesDirButton_, filePath, {}); +} + void Editor::Impl::updateLabelWithFileName(CTextLabel* label, const std::string& filePath, absl::string_view removedSuffix) { if (!label) @@ -1137,6 +1175,13 @@ void Editor::Impl::valueChanged(CControl* ctl) updateStretchedTuningLabel(value); break; + case kTagChooseUserFilesDir: + if (value != 1) + break; + + Call::later([this]() { chooseUserFilesDir(); }); + break; + default: if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) { int panelId = tag - kTagFirstChangePanel; diff --git a/editor/src/editor/layout/main.hpp b/editor/src/editor/layout/main.hpp index 0c9c61e2..6f4da9e3 100644 --- a/editor/src/editor/layout/main.hpp +++ b/editor/src/editor/layout/main.hpp @@ -69,6 +69,7 @@ enterTheme(defaultTheme); LogicalGroup* const view__28 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); subPanels_[kPanelGeneral] = view__28; view__0->addView(view__28); +view__28->setVisible(false); RoundedGroup* const view__29 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); view__28->addView(view__29); Label* const view__30 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); @@ -104,10 +105,9 @@ RoundedGroup* const view__41 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", view__40->addView(view__41); Label* const view__42 = createLabel(CRect(0, 0, 790, 285), -1, "Controls not available", kCenterText, 40); view__41->addView(view__42); -LogicalGroup* const view__43 = createLogicalGroup(CRect(5, 109, 795, 395), -1, "", kCenterText, 14); +LogicalGroup* const view__43 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); subPanels_[kPanelSettings] = view__43; view__0->addView(view__43); -view__43->setVisible(false); TitleGroup* const view__44 = createTitleGroup(CRect(255, 26, 535, 126), -1, "Engine", kCenterText, 12); view__43->addView(view__44); ValueMenu* const view__45 = createValueMenu(CRect(25, 60, 85, 85), kTagSetNumVoices, "", kCenterText, 12); @@ -150,6 +150,14 @@ view__51->addView(view__59); ValueMenu* const view__60 = createValueMenu(CRect(170, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); scalaRootOctaveSlider_ = view__60; view__51->addView(view__60); -Piano* const view__61 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); -piano_ = view__61; -view__0->addView(view__61); +TitleGroup* const view__61 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); +userFilesGroup_ = view__61; +view__43->addView(view__61); +ValueLabel* const view__62 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); +view__61->addView(view__62); +ValueButton* const view__63 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); +userFilesDirButton_ = view__63; +view__61->addView(view__63); +Piano* const view__64 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); +piano_ = view__64; +view__0->addView(view__64); diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index 79e3f9fa..47faf8a4 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -239,6 +239,10 @@ instantiate(const LV2UI_Descriptor *descriptor, self->editor.reset(editor); editor->open(*uiFrame); + // user files dir is not relevant to LV2 (not yet?) + // LV2 has its own path management mechanism + self->uiReceiveValue(EditId::CanEditUserFilesDir, 0); + *widget = reinterpret_cast(uiFrame->getPlatformFrame()->getPlatformRepresentation()); if (self->resize) diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index c04b5d1d..69bc7ace 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -6,6 +6,7 @@ #include "SfizzVstEditor.h" #include "SfizzVstState.h" +#include "SfizzFileScan.h" #include "editor/Editor.h" #include "editor/EditIds.h" #if !defined(__APPLE__) && !defined(_WIN32) @@ -73,6 +74,10 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p editor->open(*frame); + absl::optional userFilesDir = SfizzPaths::getSfzConfigDefaultPath(); + uiReceiveValue(EditId::CanEditUserFilesDir, 1); + uiReceiveValue(EditId::UserFilesDir, userFilesDir.value_or(fs::path()).u8string()); + return true; } @@ -242,6 +247,10 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) normalizeAndSet(kPidStretchedTuning, kParamStretchedTuningRange, v.to_float()); break; + case EditId::UserFilesDir: + SfizzPaths::setSfzConfigDefaultPath(fs::u8path(v.to_string())); + break; + case EditId::UIActivePanel: uiState_.activePanel = static_cast(v.to_float()); break; From a848d8e94eb9052ae7957cc29d51a36fadc10bfd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 9 Dec 2020 17:06:05 +0100 Subject: [PATCH 121/668] Fix the file search by filename key --- vst/SfizzFileScan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index a56f2e4a..441f9e80 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -31,7 +31,7 @@ bool SfzFileScan::locateRealFile(const fs::path& pathOrig, fs::path& pathFound) std::unique_lock lock { mutex }; refreshScan(); - auto it = file_index_.find(keyOf(pathOrig)); + auto it = file_index_.find(keyOf(pathOrig.filename())); if (it == file_index_.end()) return false; From cc24203f2d4f4d4bc5771639380d5029c88f4628 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 9 Dec 2020 17:08:27 +0100 Subject: [PATCH 122/668] Log the found file with full path --- vst/SfizzVstProcessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 708979eb..674e27b8 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -132,7 +132,7 @@ tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream) if (!fileScan.locateRealFile(pathOrig, pathFound)) fprintf(stderr, "[Sfizz] file not found: %s\n", pathOrig.filename().u8string().c_str()); else { - fprintf(stderr, "[Sfizz] file found: %s\n", pathFound.filename().u8string().c_str()); + fprintf(stderr, "[Sfizz] file found: %s\n", pathFound.u8string().c_str()); *statePath = pathFound.u8string(); } } From 0d6f1b0837e9ad770b0c9b650d5e3f5f474bee79 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 11 Dec 2020 02:53:20 +0100 Subject: [PATCH 123/668] vst: workaround in case the documents folder is missing --- vst/NativeHelpers.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/vst/NativeHelpers.cpp b/vst/NativeHelpers.cpp index 2015a194..3ada4d93 100644 --- a/vst/NativeHelpers.cpp +++ b/vst/NativeHelpers.cpp @@ -6,6 +6,7 @@ #include "NativeHelpers.h" #include +#include #if defined(_WIN32) #include @@ -30,9 +31,14 @@ const fs::path& getUserDocumentsDirectory() { static const fs::path directory = []() -> fs::path { const gchar* path = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS); - if (!path) + if (path) + return fs::path(path); + else { + const char* home = getenv("HOME"); + if (home && home[0] == '/') + return fs::path(home) / "Documents"; throw std::runtime_error("Cannot get the document directory."); - return fs::path(path); + } }(); return directory; } From 66dec90846b3bf839279d6dc6fb81c5e8d18027c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 11 Dec 2020 07:21:33 +0100 Subject: [PATCH 124/668] Weak pointer for VST --- vst/CMakeLists.txt | 3 +- vst/SfizzVstController.cpp | 1 - vst/SfizzVstEditor.h | 10 ++- vst/WeakPtr.h | 122 +++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 vst/WeakPtr.h diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 9d13eac0..404c897d 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -35,7 +35,8 @@ set(VSTPLUGIN_HEADERS SfizzSettings.h X11RunLoop.h NativeHelpers.h - FileTrie.h) + FileTrie.h + WeakPtr.h) if(APPLE) set(VSTPLUGIN_MAC_SOURCES diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 2e6854f1..9e5bf897 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -143,7 +143,6 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) withStateLock([this]() { _uiState = _editor->getCurrentUiState(); }); - _editor.reset(); } SfizzVstEditor* editor = new SfizzVstEditor(this); diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index e5fa0d8d..b23f7a4f 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -7,6 +7,7 @@ #pragma once #include "SfizzVstController.h" #include "editor/EditorController.h" +#include "WeakPtr.h" #include "public.sdk/source/vst/vstguieditor.h" #include class Editor; @@ -18,8 +19,11 @@ using namespace Steinberg; using namespace VSTGUI; class SfizzVstEditor : public Vst::VSTGUIEditor, - public EditorController { + public EditorController, + public Weakable { public: + using Self = SfizzVstEditor; + explicit SfizzVstEditor(SfizzVstController* controller); ~SfizzVstEditor(); @@ -41,6 +45,10 @@ public: SfizzUiState getCurrentUiState() const; void receiveMessage(const void* data, uint32_t size); + void remember() override { SfizzVstEditor::addRef(); } + void forget() override { SfizzVstEditor::release(); } + WEAKABLE_REFCOUNT_METHODS(SfizzVstEditor) + private: void processOscQueue(); diff --git a/vst/WeakPtr.h b/vst/WeakPtr.h new file mode 100644 index 00000000..55481e35 --- /dev/null +++ b/vst/WeakPtr.h @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "base/source/fobject.h" +#include +#include + +/** + * A weak reference implementation for Steinberg FObject. + * + * Implementation + * ============== + * + * This takes over the ordinary addRef() and release() methods. + * The variable `refCount` is accessed manually, under a shared mutex. + * There is a unique data block which is shared with all weak pointers, the + * system will null it atomically when the reference count hits zero. + * + * Usage + * ===== + * + * class MyObject : public FObject, public Weakable { + * [...] + * WEAKABLE_REFCOUNT_METHODS(MyObject) + * }; + * + * WeakPtr ptr = myObject.getWeakPtr(); + */ + +template +class Weakable; + +#define WEAKABLE_REFCOUNT_METHODS(T) \ +public: \ + Steinberg::uint32 PLUGIN_API addRef() SMTG_OVERRIDE { return weakAddRef(); } \ + Steinberg::uint32 PLUGIN_API release() SMTG_OVERRIDE { return weakRelease(); } \ +private: \ + friend class Weakable; \ + friend class WeakPtr; + +/// +template +struct WeakPtrSharedData : public std::enable_shared_from_this> { + explicit WeakPtrSharedData(T* self) : self_(self) {} + std::mutex mutex_; + T* self_ = nullptr; +}; + +/// +template +class WeakPtr { + friend class Weakable; + using SharedData = WeakPtrSharedData; + +public: + WeakPtr() = default; + + Steinberg::IPtr lock() + { + std::shared_ptr data = data_.lock(); + if (!data) + return nullptr; + std::lock_guard lock { data->mutex_ }; + T* self = data->self_; + if (self) + ++self->refCount; // manually because we are holding the lock + return Steinberg::IPtr(self, false); + } + +private: + explicit WeakPtr(std::weak_ptr data) : data_(data) {} + std::weak_ptr data_; +}; + +/// +template +class Weakable { + using SharedData = WeakPtrSharedData; + +public: + Weakable() + : weakData_(new SharedData(static_cast(this))) + { + } + + WeakPtr getWeakPtr() + { + return WeakPtr(weakData_); + } + +protected: + Steinberg::uint32 weakAddRef() //override + { + T* self = static_cast(this); + std::lock_guard lock { weakData_->mutex_ }; + return ++self->refCount; + } + + Steinberg::uint32 weakRelease() //override + { + T* self = static_cast(this); + std::shared_ptr data = weakData_; + std::unique_lock lock { data->mutex_ }; + Steinberg::uint32 count = --self->refCount; + if (count == 0) { + data->self_ = nullptr; + weakData_.reset(); + self->refCount = -1000; + lock.unlock(); + delete self; + return 0; + } + return count; + } + +private: + std::shared_ptr weakData_; +}; From 219babcb7a46a4f99e7663b6e8119f0ecb79ebd4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 11 Dec 2020 07:52:19 +0100 Subject: [PATCH 125/668] Avoid making the controller take a reference on the editor --- vst/SfizzVstController.cpp | 30 +++++++++++++++--------------- vst/SfizzVstController.h | 3 ++- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 9e5bf897..9ac894c4 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -139,14 +139,14 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) if (name != Vst::ViewType::kEditor) return nullptr; - if (_editor) { - withStateLock([this]() { - _uiState = _editor->getCurrentUiState(); + if (IPtr editor = _editor.lock()) { + withStateLock([this, editor]() { + _uiState = editor->getCurrentUiState(); }); } - SfizzVstEditor* editor = new SfizzVstEditor(this); - _editor = Steinberg::owned(editor); + IPtr editor = Steinberg::owned(new SfizzVstEditor(this)); + _editor = editor->getWeakPtr(); withStateLock([this, editor]() { editor->updateState(_state); @@ -209,14 +209,14 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: if (slotF32 && *slotF32 != value) { withStateLock([this, slotF32, value]() { *slotF32 = value; - if (SfizzVstEditor* editor = _editor) + if (IPtr editor = _editor.lock()) editor->updateState(_state); }); } else if (slotI32 && *slotI32 != (int32)value) { withStateLock([this, slotI32, value]() { *slotI32 = (int32)value; - if (SfizzVstEditor* editor = _editor) + if (IPtr editor = _editor.lock()) editor->updateState(_state); }); } @@ -234,7 +234,7 @@ tresult PLUGIN_API SfizzVstController::setState(IBStream* stream) withStateLock([this, &s]() { _uiState = s; - if (SfizzVstEditor* editor = _editor) + if (IPtr editor = _editor.lock()) editor->updateUiState(_uiState); }); @@ -246,8 +246,8 @@ tresult PLUGIN_API SfizzVstController::getState(IBStream* stream) tresult result; withStateLock([this, stream, &result]() { - if (_editor) - _uiState = _editor->getCurrentUiState(); + if (IPtr editor = _editor.lock()) + _uiState = editor->getCurrentUiState(); result = _uiState.store(stream); }); @@ -272,7 +272,7 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* stream) withStateLock([this, &s]() { _state = s; - if (SfizzVstEditor* editor = _editor) + if (IPtr editor = _editor.lock()) editor->updateState(_state); }); @@ -300,7 +300,7 @@ tresult SfizzVstController::notify(Vst::IMessage* message) withStateLock([this, data, size]() { _state.sfzFile.assign(static_cast(data), size); - if (SfizzVstEditor* editor = _editor) + if (IPtr editor = _editor.lock()) editor->updateState(_state); }); } @@ -314,7 +314,7 @@ tresult SfizzVstController::notify(Vst::IMessage* message) withStateLock([this, data, size]() { _state.scalaFile.assign(static_cast(data), size); - if (SfizzVstEditor* editor = _editor) + if (IPtr editor = _editor.lock()) editor->updateState(_state); }); } @@ -328,7 +328,7 @@ tresult SfizzVstController::notify(Vst::IMessage* message) withStateLock([this, data]() { _playState = *static_cast(data); - if (SfizzVstEditor* editor = _editor) + if (IPtr editor = _editor.lock()) editor->updatePlayState(_playState); }); } @@ -340,7 +340,7 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - if (SfizzVstEditor* editor = _editor) + if (IPtr editor = _editor.lock()) editor->receiveMessage(data, size); } diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index 9e5ba8d4..42094b8f 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -9,6 +9,7 @@ #include "public.sdk/source/vst/vsteditcontroller.h" #include "public.sdk/source/vst/vstparameters.h" #include "vstgui/plugin-bindings/vst3editor.h" +#include "WeakPtr.h" #include #include class SfizzVstState; @@ -66,5 +67,5 @@ private: SfizzVstState _state {}; SfizzUiState _uiState {}; // updated on UI open/close/state-request SfizzPlayState _playState {}; - Steinberg::IPtr _editor; + WeakPtr _editor; }; From bfbcdb2b43cd0394633ec170164378b9db32ae31 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 11 Dec 2020 19:12:00 +0100 Subject: [PATCH 126/668] Static link strategy for AudioUnit --- .gitmodules | 3 ++ scripts/appveyor/after_build.sh | 2 - vst/CMakeLists.txt | 65 +++++++++++++++------------------ vst/cmake/Vst3.cmake | 2 +- vst/external/sfzt_auwrapper | 1 + 5 files changed, 35 insertions(+), 38 deletions(-) create mode 160000 vst/external/sfzt_auwrapper diff --git a/.gitmodules b/.gitmodules index cbe668dc..fcf2c98f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -30,3 +30,6 @@ [submodule "external/st_audiofile/thirdparty/libaiff"] path = external/st_audiofile/thirdparty/libaiff url = https://github.com/sfztools/libaiff.git +[submodule "vst/external/sfzt_auwrapper"] + path = vst/external/sfzt_auwrapper + url = https://github.com/sfztools/sfzt_auwrapper.git diff --git a/scripts/appveyor/after_build.sh b/scripts/appveyor/after_build.sh index 5f9f5d72..330ffc9b 100755 --- a/scripts/appveyor/after_build.sh +++ b/scripts/appveyor/after_build.sh @@ -15,8 +15,6 @@ else # code-sign AudioUnit and dylibs codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --force --verbose \ "${INSTALL_DIR}"/Library/Audio/Plug-Ins/Components/sfizz.component - codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --force --verbose \ - "${INSTALL_DIR}"/Library/Audio/Plug-Ins/Components/sfizz.component/Contents/Resources/plugin.vst3 # code-sign LV2 and dylibs (note: manual, LV2 are not real bundles) codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Binary/*.so diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 9d13eac0..af9fbdef 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -2,6 +2,8 @@ set (VSTPLUGIN_PRJ_NAME "${PROJECT_NAME}_vst3") set (VSTPLUGIN_BUNDLE_NAME "${PROJECT_NAME}.vst3") set (VST3SDK_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/VST_SDK/VST3_SDK") +#set (AUWRAPPER_BASEDIR "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper") +set (AUWRAPPER_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/sfzt_auwrapper") # VST plugin specific settings include (VSTConfig) @@ -71,11 +73,13 @@ plugin_add_vstgui(${VSTPLUGIN_PRJ_NAME}) set (RINGBUFFER_HEADERS "external/ring_buffer/ring_buffer/ring_buffer.h" "external/ring_buffer/ring_buffer/ring_buffer.tcc") -source_group ("Header Files" FILES ${RINGBUFFER_HEADERS}) -target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE "external/ring_buffer") -target_sources(${VSTPLUGIN_PRJ_NAME} PRIVATE +add_library(sfizz_ring_buffer STATIC "external/ring_buffer/ring_buffer/ring_buffer.cpp" ${RINGBUFFER_HEADERS}) +source_group ("Header Files" FILES ${RINGBUFFER_HEADERS}) +target_include_directories(sfizz_ring_buffer INTERFACE "external/ring_buffer") + +target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE sfizz_ring_buffer) if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE @@ -174,11 +178,13 @@ elseif(SFIZZ_AU) set(AUPLUGIN_BUNDLE_NAME "${PROJECT_NAME}.component") add_library(${AUPLUGIN_PRJ_NAME} MODULE - "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper/aucarbonview.mm" - "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper/aucocoaview.mm" - "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper/ausdk.mm" - "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper/auwrapper.mm" - "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper/NSDataIBStream.mm") + "${AUWRAPPER_BASEDIR}/aucarbonview.mm" + "${AUWRAPPER_BASEDIR}/aucocoaview.mm" + "${AUWRAPPER_BASEDIR}/ausdk.mm" + "${AUWRAPPER_BASEDIR}/auwrapper.mm" + "${AUWRAPPER_BASEDIR}/NSDataIBStream.mm" + ${VSTPLUGIN_HEADERS} + ${VSTPLUGIN_SOURCES}) target_include_directories(${AUPLUGIN_PRJ_NAME} PRIVATE "${VST3SDK_BASEDIR}") target_link_libraries(${AUPLUGIN_PRJ_NAME} PRIVATE @@ -190,10 +196,19 @@ elseif(SFIZZ_AU) "${APPLE_COREAUDIO_LIBRARY}" "${APPLE_COREMIDI_LIBRARY}") + target_link_libraries(${AUPLUGIN_PRJ_NAME} + PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} + PRIVATE sfizz_editor + PRIVATE sfizz-pugixml) + target_include_directories(${AUPLUGIN_PRJ_NAME} + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(${AUPLUGIN_PRJ_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}" PREFIX "") + plugin_add_vst3sdk(${AUPLUGIN_PRJ_NAME}) + plugin_add_vstgui(${AUPLUGIN_PRJ_NAME}) + # Get Core Audio utility classes if missing set(CA_UTILITY_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/CoreAudioUtilityClasses") @@ -229,26 +244,6 @@ elseif(SFIZZ_AU) "${CA_UTILITY_BASEDIR}/CoreAudio/AudioUnits/AUPublic/Utility" "${CA_UTILITY_BASEDIR}/CoreAudio/PublicUtility") - # Add VST base classes - target_sources(${AUPLUGIN_PRJ_NAME} PRIVATE - "${VST3SDK_BASEDIR}/base/source/baseiids.cpp" - "${VST3SDK_BASEDIR}/base/source/fbuffer.cpp" - "${VST3SDK_BASEDIR}/base/source/fdebug.cpp" - "${VST3SDK_BASEDIR}/base/source/fdynlib.cpp" - "${VST3SDK_BASEDIR}/base/source/fobject.cpp" - "${VST3SDK_BASEDIR}/base/source/fstreamer.cpp" - "${VST3SDK_BASEDIR}/base/source/fstring.cpp" - "${VST3SDK_BASEDIR}/base/source/timer.cpp" - "${VST3SDK_BASEDIR}/base/source/updatehandler.cpp" - "${VST3SDK_BASEDIR}/base/thread/source/fcondition.cpp" - "${VST3SDK_BASEDIR}/base/thread/source/flock.cpp" - "${VST3SDK_BASEDIR}/pluginterfaces/base/conststringtable.cpp" - "${VST3SDK_BASEDIR}/pluginterfaces/base/coreiids.cpp" - "${VST3SDK_BASEDIR}/pluginterfaces/base/funknown.cpp" - "${VST3SDK_BASEDIR}/pluginterfaces/base/ustring.cpp" - "${VST3SDK_BASEDIR}/public.sdk/source/common/commoniids.cpp" - "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstinitiids.cpp") - # Add VST hosting classes target_sources(${AUPLUGIN_PRJ_NAME} PRIVATE "${VST3SDK_BASEDIR}/public.sdk/source/vst/hosting/eventlist.cpp" @@ -257,6 +252,9 @@ elseif(SFIZZ_AU) "${VST3SDK_BASEDIR}/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "${VST3SDK_BASEDIR}/public.sdk/source/vst/hosting/processdata.cpp") + # Add the ring buffer + target_link_libraries(${AUPLUGIN_PRJ_NAME} PRIVATE sfizz_ring_buffer) + # Add generated source file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include") target_include_directories(${AUPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include") @@ -269,6 +267,9 @@ elseif(SFIZZ_AU) # Create the bundle execute_process( COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Resources") + copy_editor_resources( + "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources" + "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Resources") set_target_properties(${AUPLUGIN_PRJ_NAME} PROPERTIES SUFFIX "" LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/MacOS/$<0:>") @@ -315,7 +316,7 @@ elseif(SFIZZ_AU) "-I" "${CMAKE_CURRENT_BINARY_DIR}/include" # generated audiounitconfig.h "-o" "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Resources/${PROJECT_NAME}.rsrc" "-useDF" - "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper/auresource.r") + "${AUWRAPPER_BASEDIR}/auresource.r") endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") @@ -336,14 +337,8 @@ elseif(SFIZZ_AU) install(DIRECTORY "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}" DESTINATION "${AUPLUGIN_INSTALL_DIR}" COMPONENT "au") - install(DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/" - DESTINATION "${AUPLUGIN_INSTALL_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Resources/plugin.vst3" - COMPONENT "au") bundle_dylibs(au "${AUPLUGIN_INSTALL_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/MacOS/sfizz" COMPONENT "au") - bundle_dylibs(au-vst - "${AUPLUGIN_INSTALL_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Resources/plugin.vst3/Contents/MacOS/sfizz" - COMPONENT "au") endif() endif() diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 259f62a2..20eee6b3 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -10,7 +10,7 @@ function(plugin_add_vst3sdk NAME) "${VST3SDK_BASEDIR}/base/source/fobject.cpp" "${VST3SDK_BASEDIR}/base/source/fstreamer.cpp" "${VST3SDK_BASEDIR}/base/source/fstring.cpp" - # "${VST3SDK_BASEDIR}/base/source/timer.cpp" + "${VST3SDK_BASEDIR}/base/source/timer.cpp" "${VST3SDK_BASEDIR}/base/source/updatehandler.cpp" "${VST3SDK_BASEDIR}/base/thread/source/fcondition.cpp" "${VST3SDK_BASEDIR}/base/thread/source/flock.cpp" diff --git a/vst/external/sfzt_auwrapper b/vst/external/sfzt_auwrapper new file mode 160000 index 00000000..014311ae --- /dev/null +++ b/vst/external/sfzt_auwrapper @@ -0,0 +1 @@ +Subproject commit 014311ae45b86571e1ae3aaa03ebbd7db8b3a32e From 31103d11a205b7704e4d9574864d1fe5ab121af1 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Tue, 17 Nov 2020 18:35:46 +0100 Subject: [PATCH 127/668] Add moves to the ModKey::Parameters --- src/sfizz/modulations/ModKey.cpp | 18 ++++++++++++++++++ src/sfizz/modulations/ModKey.h | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/sfizz/modulations/ModKey.cpp b/src/sfizz/modulations/ModKey.cpp index 051a4f8e..55807863 100644 --- a/src/sfizz/modulations/ModKey.cpp +++ b/src/sfizz/modulations/ModKey.cpp @@ -38,6 +38,24 @@ ModKey::Parameters& ModKey::Parameters::operator=(const Parameters& other) noexc return *this; } +ModKey::Parameters::Parameters(Parameters&& other) noexcept +{ + std::memcpy( + static_cast(this), + static_cast(&other), + sizeof(RawParameters)); +} + +ModKey::Parameters& ModKey::Parameters::operator=(Parameters&& other) noexcept +{ + if (this != &other) + std::memcpy( + static_cast(this), + static_cast(&other), + sizeof(RawParameters)); + return *this; +} + ModKey ModKey::createCC(uint16_t cc, uint8_t curve, uint8_t smooth, float step) { ModKey::Parameters p; diff --git a/src/sfizz/modulations/ModKey.h b/src/sfizz/modulations/ModKey.h index ce16c7a2..5653386f 100644 --- a/src/sfizz/modulations/ModKey.h +++ b/src/sfizz/modulations/ModKey.h @@ -59,8 +59,8 @@ public: Parameters(const Parameters& other) noexcept; Parameters& operator=(const Parameters& other) noexcept; - Parameters(Parameters&&) = delete; - Parameters &operator=(Parameters&&) = delete; + Parameters(Parameters&&) noexcept; + Parameters &operator=(Parameters&&) noexcept; bool operator==(const Parameters& other) const noexcept { From 171a5e508333505f7253a5f92fb7d64143ee3922 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 8 Nov 2020 23:59:28 +0100 Subject: [PATCH 128/668] Initial --- src/sfizz/BufferPool.h | 6 +- src/sfizz/CCMap.h | 17 + src/sfizz/Defaults.h | 4 +- src/sfizz/Messaging.h | 2 - src/sfizz/Messaging.hpp | 2 +- src/sfizz/Region.cpp | 28 + src/sfizz/Region.h | 20 +- src/sfizz/Synth.cpp | 5 +- src/sfizz/SynthMessaging.cpp | 1096 +++++++++- tests/CMakeLists.txt | 3 +- tests/DirectRegionT.cpp | 112 + tests/RegionT.cpp | 1894 ----------------- tests/RegionValueComputationsT.cpp | 114 +- tests/RegionValuesT.cpp | 3033 ++++++++++++++++++++++++++++ 14 files changed, 4390 insertions(+), 1946 deletions(-) create mode 100644 tests/DirectRegionT.cpp delete mode 100644 tests/RegionT.cpp create mode 100644 tests/RegionValuesT.cpp diff --git a/src/sfizz/BufferPool.h b/src/sfizz/BufferPool.h index b9971fcf..eea96b56 100644 --- a/src/sfizz/BufferPool.h +++ b/src/sfizz/BufferPool.h @@ -144,9 +144,9 @@ public: #ifndef NDEBUG ~BufferPool() { - DBG("Max buffers used: " << maxBuffersUsed); - DBG("Max index buffers used: " << maxIndexBuffersUsed); - DBG("Max stereo buffers used: " << maxStereoBuffersUsed); + // DBG("Max buffers used: " << maxBuffersUsed); + // DBG("Max index buffers used: " << maxIndexBuffersUsed); + // DBG("Max stereo buffers used: " << maxStereoBuffersUsed); } #endif diff --git a/src/sfizz/CCMap.h b/src/sfizz/CCMap.h index 4fcc13f8..8354ad64 100644 --- a/src/sfizz/CCMap.h +++ b/src/sfizz/CCMap.h @@ -9,6 +9,7 @@ #include "SfzHelpers.h" #include #include +#include namespace sfz { /** @@ -57,6 +58,22 @@ public: } } + /** + * @brief Returns the held object at the index, or a default value if not present + * + * @param index + * @return const ValueType& + */ + absl::optional get(int index) const noexcept + { + auto it = absl::c_lower_bound(container, index, CCDataComparator {}); + if (it == container.end() || it->cc != index) { + return {}; + } else { + return it->data; + } + } + /** * @brief Get the value at index or emplace a new one if not present * diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 290c1248..7ddfcf37 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -207,8 +207,8 @@ namespace Default constexpr Range pitchVeltrackRange { -12000, 12000 }; constexpr int transpose { 0 }; constexpr Range transposeRange { -127, 127 }; - constexpr int tune { 0 }; - constexpr Range tuneRange { -12000, 12000 }; // ±100 in SFZv1, more in ARIA + constexpr float tune { 0 }; + constexpr Range tuneRange { -12000, 12000 }; // ±100 in SFZv1, more in ARIA constexpr Range tuneCCRange { -12000, 12000 }; constexpr Range bendBoundRange { -12000, 12000 }; constexpr Range bendStepRange { 1, 1200 }; diff --git a/src/sfizz/Messaging.h b/src/sfizz/Messaging.h index 0f48587b..68839869 100644 --- a/src/sfizz/Messaging.h +++ b/src/sfizz/Messaging.h @@ -27,8 +27,6 @@ public: private: template sfizz_arg_t make_arg(OscDecayedType value); - -private: void* data_ = nullptr; sfizz_receive_t* receive_ = nullptr; }; diff --git a/src/sfizz/Messaging.hpp b/src/sfizz/Messaging.hpp index 587e671d..33c9127a 100644 --- a/src/sfizz/Messaging.hpp +++ b/src/sfizz/Messaging.hpp @@ -56,7 +56,7 @@ inline void Client::receive(int delay, const char* path, OscDecayedType... typedef struct Nothing {} type; \ typedef type decayed_type; \ static inline sfizz_arg_t make_arg(decayed_type v) { \ - sfizz_arg_t a; (void)v; return a; \ + sfizz_arg_t a {}; (void)v; return a; \ } \ } diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index f131febf..0c0b84c7 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1936,3 +1936,31 @@ bool sfz::Region::disabled() const noexcept { return (sampleEnd == 0); } + +absl::optional sfz::Region::ccModDepth(int cc, ModId id) const noexcept +{ + const ModKey target = ModKey::createNXYZ(id, getId()); + for (const sfz::Region::Connection& conn : connections) { + if (conn.source.id() == sfz::ModId::Controller && conn.target == target) { + auto p = conn.source.parameters(); + if (p.cc == cc) + return conn.sourceDepth; + } + } + + return {}; +} + +absl::optional sfz::Region::ccModParameters(int cc, ModId id) const noexcept +{ + const ModKey target = ModKey::createNXYZ(id, getId()); + for (const sfz::Region::Connection& conn : connections) { + if (conn.source.id() == sfz::ModId::Controller && conn.target == target) { + auto p = conn.source.parameters(); + if (p.cc == cc) + return p; + } + } + + return {}; +} diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 932aecf4..384b090f 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -303,6 +303,24 @@ struct Region { */ bool disabled() const noexcept; + /** + * @brief Extract the source depth modifier for a given cc and id. + * + * @param cc + * @param id + * @return absl::optional + */ + absl::optional ccModDepth(int cc, ModId id) const noexcept; + + /** + * @brief Extract the parameters for a given modulation cc and id. + * + * @param cc + * @param id + * @return float + */ + absl::optional ccModParameters(int cc, ModId id) const noexcept; + const NumericId id; // Sound source: sample playback @@ -412,7 +430,7 @@ struct Region { float pitchRandom { Default::pitchRandom }; // pitch_random int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack int transpose { Default::transpose }; // transpose - int tune { Default::tune }; // tune + float tune { Default::tune }; // tune int bendUp { Default::bendUp }; int bendDown { Default::bendDown }; int bendStep { Default::bendStep }; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 79651e4e..6a2e6e08 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -676,7 +676,10 @@ void Synth::Impl::finalizeSfzLoad() ++currentRegionIndex; } - DBG("Removing " << (regions_.size() - currentRegionCount) << " out of " << regions_.size() << " regions"); + if (currentRegionCount < regions_.size()) { + DBG("Removing " << (regions_.size() - currentRegionCount) + << " out of " << regions_.size() << " regions"); + } regions_.resize(currentRegionCount); // collect all CCs used in regions, with matrix not yet connected diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 9aef0213..4e3285fa 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -17,17 +17,1109 @@ static uint64_t hashMessagePath(const char* path, const char* sig); void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, const char* sig, const sfizz_arg_t* args) { + UNUSED(args); + Impl& impl = *impl_; unsigned indices[maxIndices]; switch (hashMessagePath(path, sig)) { #define MATCH(p, s) case hash(p "," s): \ if (extractMessage(p, path, indices) && !strcmp(sig, s)) + #define GET_REGION_OR_BREAK(idx) \ + if (idx >= impl.regions_.size()) \ + break; \ + const auto& region = *impl.regions_[idx]; + MATCH("/hello", "") { client.receive(delay, "/hello", "", nullptr); - break; - } + } break; + MATCH("/region&/delay", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.delay); + } break; + + MATCH("/region&/sample", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'s'>(delay, path, region.sampleId->filename().c_str()); + } break; + + MATCH("/region&/direction", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.sampleId->isReverse()) + client.receive<'s'>(delay, path, "reverse"); + else + client.receive<'s'>(delay, path, "forward"); + } break; + + MATCH("/region&/delay_random", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.delayRandom); + } break; + + MATCH("/region&/offset", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'h'>(delay, path, region.offset); + } break; + + MATCH("/region&/offset_random", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'h'>(delay, path, region.offsetRandom); + } break; + + MATCH("/region&/offset_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'h'>(delay, path, region.offsetCC.getWithDefault(indices[1])); + } break; + + MATCH("/region&/end", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'h'>(delay, path, region.sampleEnd); + } break; + + MATCH("/region&/enabled", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.disabled()) { + client.receive<'F'>(delay, path, {}); + } else { + client.receive<'T'>(delay, path, {}); + } + } break; + + MATCH("/region&/count", "") { + GET_REGION_OR_BREAK(indices[0]) + if (!region.sampleCount) { + client.receive<'N'>(delay, path, {}); + } else { + client.receive<'h'>(delay, path, *region.sampleCount); + } + } break; + + MATCH("/region&/loop_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].h = region.loopRange.getStart(); + args[1].h = region.loopRange.getEnd(); + client.receive(delay, path, "hh", args); + } break; + + MATCH("/region&/loop_mode", "") { + GET_REGION_OR_BREAK(indices[0]) + if (!region.loopMode) { + client.receive<'s'>(delay, path, "no_loop"); + break; + } + + switch (*region.loopMode) { + case SfzLoopMode::no_loop: + client.receive<'s'>(delay, path, "no_loop"); + break; + case SfzLoopMode::loop_continuous: + client.receive<'s'>(delay, path, "loop_continuous"); + break; + case SfzLoopMode::loop_sustain: + client.receive<'s'>(delay, path, "loop_sustain"); + break; + case SfzLoopMode::one_shot: + client.receive<'s'>(delay, path, "one_shot"); + break; + } + } break; + + MATCH("/region&/loop_crossfade", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.loopCrossfade); + } break; + + MATCH("/region&/group", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'h'>(delay, path, region.group); + } break; + + MATCH("/region&/off_by", "") { + GET_REGION_OR_BREAK(indices[0]) + if (!region.offBy) { + client.receive<'N'>(delay, path, {}); + } else { + client.receive<'h'>(delay, path, *region.offBy); + } + } break; + + MATCH("/region&/off_mode", "") { + GET_REGION_OR_BREAK(indices[0]) + switch (region.offMode) { + case SfzOffMode::time: + client.receive<'s'>(delay, path, "time"); + break; + case SfzOffMode::normal: + client.receive<'s'>(delay, path, "normal"); + break; + case SfzOffMode::fast: + client.receive<'s'>(delay, path, "fast"); + break; + } + } break; + + MATCH("/region&/key_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].i = region.keyRange.getStart(); + args[1].i = region.keyRange.getEnd(); + client.receive(delay, path, "ii", args); + } break; + + MATCH("/region&/off_time", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.offTime); + } break; + + MATCH("/region&/pitch_keycenter", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.pitchKeycenter); + } break; + + MATCH("/region&/vel_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].f = region.velocityRange.getStart(); + args[1].f = region.velocityRange.getEnd(); + client.receive(delay, path, "ff", args); + } break; + + MATCH("/region&/bend_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].f = region.bendRange.getStart(); + args[1].f = region.bendRange.getEnd(); + client.receive(delay, path, "ff", args); + } break; + + MATCH("/region&/cc_range&", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + const auto& conditions = region.ccConditions.getWithDefault(indices[1]); + args[0].f = conditions.getStart(); + args[1].f = conditions.getEnd(); + client.receive(delay, path, "ff", args); + } break; + + MATCH("/region&/sw_last", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.lastKeyswitch) { + client.receive<'i'>(delay, path, *region.lastKeyswitch); + } else if (region.lastKeyswitchRange) { + sfizz_arg_t args[2]; + args[0].i = region.lastKeyswitchRange->getStart(); + args[1].i = region.lastKeyswitchRange->getEnd(); + client.receive(delay, path, "ii", args); + } else { + client.receive<'N'>(delay, path, {}); + } + + } break; + + MATCH("/region&/sw_label", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.keyswitchLabel) { + client.receive<'s'>(delay, path, region.keyswitchLabel->c_str()); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/sw_up", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.upKeyswitch) { + client.receive<'i'>(delay, path, *region.upKeyswitch); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/sw_down", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.downKeyswitch) { + client.receive<'i'>(delay, path, *region.downKeyswitch); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/sw_previous", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.previousKeyswitch) { + client.receive<'i'>(delay, path, *region.previousKeyswitch); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/sw_vel", "") { + GET_REGION_OR_BREAK(indices[0]) + switch (region.velocityOverride) { + case SfzVelocityOverride::current: + client.receive<'s'>(delay, path, "current"); + break; + case SfzVelocityOverride::previous: + client.receive<'s'>(delay, path, "previous"); + break; + } + } break; + + MATCH("/region&/chanaft_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].i = region.aftertouchRange.getStart(); + args[1].i = region.aftertouchRange.getEnd(); + client.receive(delay, path, "ii", args); + } break; + + MATCH("/region&/bpm_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].f = region.bpmRange.getStart(); + args[1].f = region.bpmRange.getEnd(); + client.receive(delay, path, "ff", args); + } break; + + MATCH("/region&/rand_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].f = region.randRange.getStart(); + args[1].f = region.randRange.getEnd(); + client.receive(delay, path, "ff", args); + } break; + + MATCH("/region&/seq_length", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'h'>(delay, path, region.sequenceLength); + } break; + + MATCH("/region&/seq_position", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'h'>(delay, path, region.sequencePosition); + } break; + + MATCH("/region&/trigger", "") { + GET_REGION_OR_BREAK(indices[0]) + switch (region.trigger) { + case SfzTrigger::attack: + client.receive<'s'>(delay, path, "attack"); + break; + case SfzTrigger::first: + client.receive<'s'>(delay, path, "first"); + break; + case SfzTrigger::release: + client.receive<'s'>(delay, path, "release"); + break; + case SfzTrigger::release_key: + client.receive<'s'>(delay, path, "release_key"); + break; + case SfzTrigger::legato: + client.receive<'s'>(delay, path, "legato"); + break; + } + } break; + + MATCH("/region&/start_cc_range&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto trigger = region.ccTriggers.get(indices[1]); + if (trigger) { + sfizz_arg_t args[2]; + args[0].f = trigger->getStart(); + args[1].f = trigger->getEnd(); + client.receive(delay, path, "ff", args); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/volume", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.volume); + } break; + + MATCH("/region&/volume_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto value = region.ccModDepth(indices[1], ModId::Volume); + if (value) { + client.receive<'f'>(delay, path, *value); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/volume_stepcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Volume); + if (params) { + client.receive<'f'>(delay, path, params->step); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/volume_smoothcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Volume); + if (params) { + client.receive<'i'>(delay, path, params->smooth); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/volume_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Volume); + if (params) { + client.receive<'i'>(delay, path, params->curve); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/pan", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.pan * 100.0f); + } break; + + MATCH("/region&/pan_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto value = region.ccModDepth(indices[1], ModId::Pan); + if (value) { + client.receive<'f'>(delay, path, *value); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/pan_stepcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Pan); + if (params) { + client.receive<'f'>(delay, path, params->step); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/pan_smoothcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Pan); + if (params) { + client.receive<'i'>(delay, path, params->smooth); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/pan_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Pan); + if (params) { + client.receive<'i'>(delay, path, params->curve); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/width", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.width * 100.0f); + } break; + + MATCH("/region&/width_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto value = region.ccModDepth(indices[1], ModId::Width); + if (value) { + client.receive<'f'>(delay, path, *value); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/width_stepcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Width); + if (params) { + client.receive<'f'>(delay, path, params->step); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/width_smoothcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Width); + if (params) { + client.receive<'i'>(delay, path, params->smooth); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/width_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Width); + if (params) { + client.receive<'i'>(delay, path, params->curve); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/position", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.position * 100.0f); + } break; + + MATCH("/region&/position_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto value = region.ccModDepth(indices[1], ModId::Position); + if (value) { + client.receive<'f'>(delay, path, *value); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/position_stepcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Position); + if (params) { + client.receive<'f'>(delay, path, params->step); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/position_smoothcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Position); + if (params) { + client.receive<'i'>(delay, path, params->smooth); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/position_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Position); + if (params) { + client.receive<'i'>(delay, path, params->curve); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/amplitude", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.amplitude * 100.0f); + } break; + + MATCH("/region&/amplitude_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto value = region.ccModDepth(indices[1], ModId::Amplitude); + if (value) { + client.receive<'f'>(delay, path, *value); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/amplitude_stepcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Amplitude); + if (params) { + client.receive<'f'>(delay, path, params->step); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/amplitude_smoothcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Amplitude); + if (params) { + client.receive<'i'>(delay, path, params->smooth); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/amplitude_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Amplitude); + if (params) { + client.receive<'i'>(delay, path, params->curve); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/amp_keycenter", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.ampKeycenter); + } break; + + MATCH("/region&/amp_keytrack", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.ampKeytrack); + } break; + + MATCH("/region&/amp_veltrack", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.ampVeltrack * 100.0f); + } break; + + MATCH("/region&/amp_random", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.ampRandom); + } break; + + MATCH("/region&/xfin_key_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].i = region.crossfadeKeyInRange.getStart(); + args[1].i = region.crossfadeKeyInRange.getEnd(); + client.receive(delay, path, "ii", args); + } break; + + MATCH("/region&/xfout_key_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].i = region.crossfadeKeyOutRange.getStart(); + args[1].i = region.crossfadeKeyOutRange.getEnd(); + client.receive(delay, path, "ii", args); + } break; + + MATCH("/region&/xfin_vel_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].f = region.crossfadeVelInRange.getStart(); + args[1].f = region.crossfadeVelInRange.getEnd(); + client.receive(delay, path, "ff", args); + } break; + + MATCH("/region&/xfout_vel_range", "") { + GET_REGION_OR_BREAK(indices[0]) + sfizz_arg_t args[2]; + args[0].f = region.crossfadeVelOutRange.getStart(); + args[1].f = region.crossfadeVelOutRange.getEnd(); + client.receive(delay, path, "ff", args); + } break; + + MATCH("/region&/xfin_cc_range&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto range = region.crossfadeCCInRange.get(indices[1]); + if (range) { + sfizz_arg_t args[2]; + args[0].f = range->getStart(); + args[1].f = range->getEnd(); + client.receive(delay, path, "ff", args); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/xfout_cc_range&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto range = region.crossfadeCCOutRange.get(indices[1]); + if (range) { + sfizz_arg_t args[2]; + args[0].f = range->getStart(); + args[1].f = range->getEnd(); + client.receive(delay, path, "ff", args); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/xf_keycurve", "") { + GET_REGION_OR_BREAK(indices[0]) + switch (region.crossfadeKeyCurve) { + case SfzCrossfadeCurve::gain: + client.receive<'s'>(delay, path, "gain"); + break; + case SfzCrossfadeCurve::power: + client.receive<'s'>(delay, path, "power"); + break; + } + } break; + + MATCH("/region&/xf_velcurve", "") { + GET_REGION_OR_BREAK(indices[0]) + switch (region.crossfadeVelCurve) { + case SfzCrossfadeCurve::gain: + client.receive<'s'>(delay, path, "gain"); + break; + case SfzCrossfadeCurve::power: + client.receive<'s'>(delay, path, "power"); + break; + } + } break; + + MATCH("/region&/xf_cccurve", "") { + GET_REGION_OR_BREAK(indices[0]) + switch (region.crossfadeCCCurve) { + case SfzCrossfadeCurve::gain: + client.receive<'s'>(delay, path, "gain"); + break; + case SfzCrossfadeCurve::power: + client.receive<'s'>(delay, path, "power"); + break; + } + } break; + + MATCH("/region&/global_volume", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.globalVolume); + } break; + + MATCH("/region&/master_volume", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.masterVolume); + } break; + + MATCH("/region&/group_volume", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.groupVolume); + } break; + + MATCH("/region&/global_amplitude", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.globalAmplitude * 100.0f); + } break; + + MATCH("/region&/master_amplitude", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.masterAmplitude * 100.0f); + } break; + + MATCH("/region&/group_amplitude", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.groupAmplitude * 100.0f); + } break; + + MATCH("/region&/pitch_keytrack", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.pitchKeytrack); + } break; + + MATCH("/region&/pitch_veltrack", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.pitchVeltrack); + } break; + + MATCH("/region&/pitch_random", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.pitchRandom); + } break; + + MATCH("/region&/transpose", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.transpose); + } break; + + MATCH("/region&/tune", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.tune); + } break; + + MATCH("/region&/tune_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto value = region.ccModDepth(indices[1], ModId::Pitch); + if (value) { + client.receive<'f'>(delay, path, *value); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/tune_stepcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Pitch); + if (params) { + client.receive<'f'>(delay, path, params->step); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/tune_smoothcc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Pitch); + if (params) { + client.receive<'i'>(delay, path, params->smooth); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/tune_curvecc&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto params = region.ccModParameters(indices[1], ModId::Pitch); + if (params) { + client.receive<'i'>(delay, path, params->curve); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/bend_up", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.bendUp); + } break; + + MATCH("/region&/bend_down", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.bendDown); + } break; + + MATCH("/region&/bend_step", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.bendStep); + } break; + + MATCH("/region&/bend_smooth", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.bendSmooth); + } break; + + MATCH("/region&/ampeg_attack", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.amplitudeEG.attack); + } break; + + MATCH("/region&/ampeg_delay", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.amplitudeEG.delay); + } break; + + MATCH("/region&/ampeg_decay", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.amplitudeEG.decay); + } break; + + MATCH("/region&/ampeg_hold", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.amplitudeEG.hold); + } break; + + MATCH("/region&/ampeg_release", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.amplitudeEG.release); + } break; + + MATCH("/region&/ampeg_start", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.amplitudeEG.start); + } break; + + MATCH("/region&/ampeg_sustain", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.amplitudeEG.sustain); + } break; + + MATCH("/region&/ampeg_depth", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.amplitudeEG.depth); + } break; + + MATCH("/region&/ampeg_vel&attack", "") { + GET_REGION_OR_BREAK(indices[0]) + if (indices[1] != 2) + break; + client.receive<'f'>(delay, path, region.amplitudeEG.vel2attack); + } break; + + MATCH("/region&/ampeg_vel&delay", "") { + GET_REGION_OR_BREAK(indices[0]) + if (indices[1] != 2) + break; + client.receive<'f'>(delay, path, region.amplitudeEG.vel2delay); + } break; + + MATCH("/region&/ampeg_vel&decay", "") { + GET_REGION_OR_BREAK(indices[0]) + if (indices[1] != 2) + break; + client.receive<'f'>(delay, path, region.amplitudeEG.vel2decay); + } break; + + MATCH("/region&/ampeg_vel&hold", "") { + GET_REGION_OR_BREAK(indices[0]) + if (indices[1] != 2) + break; + client.receive<'f'>(delay, path, region.amplitudeEG.vel2hold); + } break; + + MATCH("/region&/ampeg_vel&release", "") { + GET_REGION_OR_BREAK(indices[0]) + if (indices[1] != 2) + break; + client.receive<'f'>(delay, path, region.amplitudeEG.vel2release); + } break; + + MATCH("/region&/ampeg_vel&sustain", "") { + GET_REGION_OR_BREAK(indices[0]) + if (indices[1] != 2) + break; + client.receive<'f'>(delay, path, region.amplitudeEG.vel2sustain); + } break; + + MATCH("/region&/ampeg_vel&depth", "") { + GET_REGION_OR_BREAK(indices[0]) + if (indices[1] != 2) + break; + client.receive<'i'>(delay, path, region.amplitudeEG.vel2depth); + } break; + + MATCH("/region&/note_polyphony", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.notePolyphony) { + client.receive<'i'>(delay, path, *region.notePolyphony); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/note_selfmask", "") { + GET_REGION_OR_BREAK(indices[0]) + switch(region.selfMask) { + case SfzSelfMask::mask: + client.receive(delay, path, "T", nullptr); + break; + case SfzSelfMask::dontMask: + client.receive(delay, path, "F", nullptr); + break; + } + } break; + + MATCH("/region&/rt_dead", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.rtDead) { + client.receive(delay, path, "T", nullptr); + } else { + client.receive(delay, path, "F", nullptr); + } + } break; + + MATCH("/region&/sustain_sw", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.checkSustain) { + client.receive(delay, path, "T", nullptr); + } else { + client.receive(delay, path, "F", nullptr); + } + } break; + + MATCH("/region&/sostenuto_sw", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.checkSostenuto) { + client.receive(delay, path, "T", nullptr); + } else { + client.receive(delay, path, "F", nullptr); + } + } break; + + MATCH("/region&/sustain_cc", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.sustainCC); + } break; + + MATCH("/region&/sustain_lo", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.sustainThreshold); + } break; + + MATCH("/region&/oscillator_phase", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.oscillatorPhase); + } break; + + MATCH("/region&/effect&", "") { + GET_REGION_OR_BREAK(indices[0]) + auto effectIdx = indices[1]; + if (indices[1] == 0) + break; + + if (effectIdx < region.gainToEffect.size()) + client.receive<'f'>(delay, path, region.gainToEffect[effectIdx] * 100.0f); + } break; + + MATCH("/region&/ampeg_attack_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + float value = region.amplitudeEG.ccAttack.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, value); + } break; + + MATCH("/region&/ampeg_decay_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + float value = region.amplitudeEG.ccDecay.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, value); + } break; + + MATCH("/region&/ampeg_delay_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + float value = region.amplitudeEG.ccDelay.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, value); + } break; + + MATCH("/region&/ampeg_hold_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + float value = region.amplitudeEG.ccHold.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, value); + } break; + + MATCH("/region&/ampeg_release_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + float value = region.amplitudeEG.ccRelease.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, value); + } break; + + MATCH("/region&/ampeg_start_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + float value = region.amplitudeEG.ccStart.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, value); + } break; + + MATCH("/region&/ampeg_sustain_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + float value = region.amplitudeEG.ccSustain.getWithDefault(indices[1]); + client.receive<'f'>(delay, path, value); + } break; + + #define GET_FILTER_OR_BREAK(idx) \ + if (idx >= region.filters.size()) \ + break; \ + const auto& filter = region.filters[idx]; + + MATCH("/region&/filter&/cutoff", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + client.receive<'f'>(delay, path, filter.cutoff); + } break; + + MATCH("/region&/filter&/resonance", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + client.receive<'f'>(delay, path, filter.resonance); + } break; + + MATCH("/region&/filter&/gain", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + client.receive<'f'>(delay, path, filter.gain); + } break; + + MATCH("/region&/filter&/keycenter", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + client.receive<'i'>(delay, path, filter.keycenter); + } break; + + MATCH("/region&/filter&/keytrack", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + client.receive<'i'>(delay, path, filter.keytrack); + } break; + + MATCH("/region&/filter&/veltrack", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + client.receive<'i'>(delay, path, filter.veltrack); + } break; + + MATCH("/region&/filter&/type", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_FILTER_OR_BREAK(indices[1]) + switch (filter.type) { + case FilterType::kFilterLpf1p: client.receive<'s'>(delay, path, "lpf_1p"); break; + case FilterType::kFilterHpf1p: client.receive<'s'>(delay, path, "hpf_1p"); break; + case FilterType::kFilterLpf2p: client.receive<'s'>(delay, path, "lpf_2p"); break; + case FilterType::kFilterHpf2p: client.receive<'s'>(delay, path, "hpf_2p"); break; + case FilterType::kFilterBpf2p: client.receive<'s'>(delay, path, "bpf_2p"); break; + case FilterType::kFilterBrf2p: client.receive<'s'>(delay, path, "brf_2p"); break; + case FilterType::kFilterBpf1p: client.receive<'s'>(delay, path, "bpf_1p"); break; + case FilterType::kFilterBrf1p: client.receive<'s'>(delay, path, "brf_1p"); break; + case FilterType::kFilterApf1p: client.receive<'s'>(delay, path, "apf_1p"); break; + case FilterType::kFilterLpf2pSv: client.receive<'s'>(delay, path, "lpf_2p_sv"); break; + case FilterType::kFilterHpf2pSv: client.receive<'s'>(delay, path, "hpf_2p_sv"); break; + case FilterType::kFilterBpf2pSv: client.receive<'s'>(delay, path, "bpf_2p_sv"); break; + case FilterType::kFilterBrf2pSv: client.receive<'s'>(delay, path, "brf_2p_sv"); break; + case FilterType::kFilterLpf4p: client.receive<'s'>(delay, path, "lpf_4p"); break; + case FilterType::kFilterHpf4p: client.receive<'s'>(delay, path, "hpf_4p"); break; + case FilterType::kFilterLpf6p: client.receive<'s'>(delay, path, "lpf_6p"); break; + case FilterType::kFilterHpf6p: client.receive<'s'>(delay, path, "hpf_6p"); break; + case FilterType::kFilterPink: client.receive<'s'>(delay, path, "pink"); break; + case FilterType::kFilterLsh: client.receive<'s'>(delay, path, "lsh"); break; + case FilterType::kFilterHsh: client.receive<'s'>(delay, path, "hsh"); break; + case FilterType::kFilterPeq: client.receive<'s'>(delay, path, "peq"); break; + case FilterType::kFilterBpf4p: client.receive<'s'>(delay, path, "bpf_4p"); break; + case FilterType::kFilterBpf6p: client.receive<'s'>(delay, path, "bpf_6p"); break; + case FilterType::kFilterNone: client.receive<'s'>(delay, path, "none"); break; + } + } break; + + #undef GET_FILTER_OR_BREAK + + #define GET_EQ_OR_BREAK(idx) \ + if (idx >= region.equalizers.size()) \ + break; \ + const auto& eq = region.equalizers[idx]; + + MATCH("/region&/eq&/gain", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EQ_OR_BREAK(indices[1]) + client.receive<'f'>(delay, path, eq.gain); + } break; + + MATCH("/region&/eq&/bandwidth", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EQ_OR_BREAK(indices[1]) + client.receive<'f'>(delay, path, eq.bandwidth); + } break; + + MATCH("/region&/eq&/frequency", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EQ_OR_BREAK(indices[1]) + client.receive<'f'>(delay, path, eq.frequency); + } break; + + MATCH("/region&/eq&/vel&freq", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EQ_OR_BREAK(indices[1]) + if (indices[2] != 2) + break; + client.receive<'f'>(delay, path, eq.vel2frequency); + } break; + + MATCH("/region&/eq&/vel&gain", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EQ_OR_BREAK(indices[1]) + if (indices[2] != 2) + break; + client.receive<'f'>(delay, path, eq.vel2gain); + } break; + + MATCH("/region&/eq&/type", "") { + GET_REGION_OR_BREAK(indices[0]) + GET_EQ_OR_BREAK(indices[1]) + switch (eq.type) { + case EqType::kEqNone: client.receive<'s'>(delay, path, "none"); break; + case EqType::kEqPeak: client.receive<'s'>(delay, path, "peak"); break; + case EqType::kEqLowShelf: client.receive<'s'>(delay, path, "lshelf"); break; + case EqType::kEqHighShelf: client.receive<'s'>(delay, path, "hshelf"); break; + } + } break; + + #undef GET_EQ_OR_BREAK + + #undef GET_REGION_OR_BREAK + #undef MATCH // TODO... } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8e562df8..afee85a8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,7 +4,8 @@ project(sfizz) set(SFIZZ_TEST_SOURCES - RegionT.cpp + DirectRegionT.cpp + RegionValuesT.cpp TestHelpers.h TestHelpers.cpp ParsingT.cpp diff --git a/tests/DirectRegionT.cpp b/tests/DirectRegionT.cpp new file mode 100644 index 00000000..2ae1d821 --- /dev/null +++ b/tests/DirectRegionT.cpp @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "TestHelpers.h" +#include "sfizz/MidiState.h" +#include "sfizz/Region.h" +#include "sfizz/SfzHelpers.h" +#include "sfizz/modulations/ModId.h" +#include "sfizz/modulations/ModKey.h" +#include "catch2/catch.hpp" +#include +using namespace Catch::literals; +using namespace sfz::literals; +using namespace sfz; + +TEST_CASE("[Direct Region Tests] amp_velcurve") +{ + MidiState midiState; + Region region { 0, midiState }; + region.parseOpcode({ "amp_velcurve_6", "0.4" }); + REQUIRE(region.velocityPoints.back() == std::pair(6, 0.4f)); + region.parseOpcode({ "amp_velcurve_127", "-1.0" }); + REQUIRE(region.velocityPoints.back() == std::pair(127, 0.0f)); + region.parseOpcode({ "amp_velcurve_008", "0.3" }); + REQUIRE(region.velocityPoints.back() == std::pair(8, 0.3f)); + region.parseOpcode({ "amp_velcurve_064", "0.9" }); + REQUIRE(region.velocityPoints.back() == std::pair(64, 0.9f)); +} + +TEST_CASE("[Direct Region Tests] Release and release key") +{ + MidiState midiState; + Region region { 0, midiState }; + region.parseOpcode({ "lokey", "63" }); + region.parseOpcode({ "hikey", "65" }); + region.parseOpcode({ "sample", "*sine" }); + SECTION("Release key without sustain") + { + region.parseOpcode({ "trigger", "release_key" }); + midiState.ccEvent(0, 64, 0.0f); + REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); + REQUIRE( region.registerNoteOff(63, 0.5f, 0.0f) ); + } + SECTION("Release key with sustain") + { + region.parseOpcode({ "trigger", "release_key" }); + midiState.ccEvent(0, 64, 1.0f); + REQUIRE( !region.registerCC(64, 1.0f) ); + REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); + REQUIRE( region.registerNoteOff(63, 0.5f, 0.0f) ); + } + + SECTION("Release without sustain") + { + region.parseOpcode({ "trigger", "release" }); + midiState.ccEvent(0, 64, 0.0f); + REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); + REQUIRE( region.registerNoteOff(63, 0.5f, 0.0f) ); + } + + SECTION("Release with sustain") + { + region.parseOpcode({ "trigger", "release" }); + midiState.ccEvent(0, 64, 1.0f); + midiState.noteOnEvent(0, 63, 0.5f); + REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); + REQUIRE( !region.registerNoteOff(63, 0.5f, 0.0f) ); + REQUIRE( region.delayedReleases.size() == 1 ); + std::vector> expected = { + { 63, 0.5f } + }; + REQUIRE( region.delayedReleases == expected ); + } + + SECTION("Release with sustain and 2 notes") + { + region.parseOpcode({ "trigger", "release" }); + midiState.ccEvent(0, 64, 1.0f); + midiState.noteOnEvent(0, 63, 0.5f); + REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); + midiState.noteOnEvent(0, 64, 0.6f); + REQUIRE( !region.registerNoteOn(64, 0.6f, 0.0f) ); + REQUIRE( !region.registerNoteOff(63, 0.0f, 0.0f) ); + REQUIRE( !region.registerNoteOff(64, 0.2f, 0.0f) ); + REQUIRE( region.delayedReleases.size() == 2 ); + std::vector> expected = { + { 63, 0.5f }, + { 64, 0.6f } + }; + REQUIRE( region.delayedReleases == expected ); + } + + SECTION("Release with sustain and 2 notes but 1 outside") + { + region.parseOpcode({ "trigger", "release" }); + midiState.ccEvent(0, 64, 1.0f); + midiState.noteOnEvent(0, 63, 0.5f); + REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); + midiState.noteOnEvent(0, 66, 0.6f); + REQUIRE( !region.registerNoteOn(66, 0.6f, 0.0f) ); + REQUIRE( !region.registerNoteOff(63, 0.0f, 0.0f) ); + REQUIRE( !region.registerNoteOff(66, 0.2f, 0.0f) ); + REQUIRE( region.delayedReleases.size() == 1 ); + std::vector> expected = { + { 63, 0.5f } + }; + REQUIRE( region.delayedReleases == expected ); + } +} diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp deleted file mode 100644 index 312d17a0..00000000 --- a/tests/RegionT.cpp +++ /dev/null @@ -1,1894 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "TestHelpers.h" -#include "sfizz/MidiState.h" -#include "sfizz/Region.h" -#include "sfizz/SfzHelpers.h" -#include "sfizz/modulations/ModId.h" -#include "sfizz/modulations/ModKey.h" -#include "catch2/catch.hpp" -#include -using namespace Catch::literals; -using namespace sfz::literals; -using namespace sfz; - -TEST_CASE("[Region] Parsing opcodes") -{ - MidiState midiState; - Region region { 0, midiState }; - - SECTION("sample") - { - REQUIRE(region.sampleId->filename() == ""); - region.parseOpcode({ "sample", "dummy.wav" }); - REQUIRE(region.sampleId->filename() == "dummy.wav"); - } - - SECTION("direction") - { - REQUIRE(!region.sampleId->isReverse()); - region.parseOpcode({ "direction", "reverse" }); - REQUIRE(region.sampleId->isReverse()); - region.parseOpcode({ "direction", "forward" }); - REQUIRE(!region.sampleId->isReverse()); - } - - SECTION("delay") - { - REQUIRE(region.delay == 0.0); - region.parseOpcode({ "delay", "1.0" }); - REQUIRE(region.delay == 1.0); - region.parseOpcode({ "delay", "-1.0" }); - REQUIRE(region.delay == 0.0); - region.parseOpcode({ "delay", "110.0" }); - REQUIRE(region.delay == 100.0); - } - - SECTION("delay_random") - { - REQUIRE(region.delayRandom == 0.0); - region.parseOpcode({ "delay_random", "1.0" }); - REQUIRE(region.delayRandom == 1.0); - region.parseOpcode({ "delay_random", "-1.0" }); - REQUIRE(region.delayRandom == 0.0); - region.parseOpcode({ "delay_random", "110.0" }); - REQUIRE(region.delayRandom == 100.0); - } - - SECTION("offset") - { - REQUIRE(region.offset == 0); - region.parseOpcode({ "offset", "1" }); - REQUIRE(region.offset == 1); - region.parseOpcode({ "offset", "-1" }); - REQUIRE(region.offset == 0); - } - SECTION("offset_cc") - { - REQUIRE(region.offsetCC.empty()); - region.parseOpcode({ "offset_cc1", "1" }); - REQUIRE(region.offsetCC.contains(1)); - REQUIRE(region.offsetCC[1] == 1); - region.parseOpcode({ "offset_cc2", "15420" }); - REQUIRE(region.offsetCC.contains(2)); - REQUIRE(region.offsetCC[2] == 15420); - region.parseOpcode({ "offset_cc2", "-1" }); - REQUIRE(region.offsetCC[2] == 0); - } - - - SECTION("offset_random") - { - REQUIRE(region.offsetRandom == 0); - region.parseOpcode({ "offset_random", "1" }); - REQUIRE(region.offsetRandom == 1); - region.parseOpcode({ "offset_random", "-1" }); - REQUIRE(region.offsetRandom == 0); - } - - SECTION("end") - { - region.parseOpcode({ "end", "184" }); - REQUIRE(region.sampleEnd == 184); - region.parseOpcode({ "end", "-1" }); - REQUIRE(region.disabled()); - region.parseOpcode({ "end", "2" }); - REQUIRE(!region.disabled()); - REQUIRE(region.sampleEnd == 2); - region.parseOpcode({ "end", "0" }); - REQUIRE(region.disabled()); - } - - SECTION("count") - { - REQUIRE(!region.sampleCount); - region.parseOpcode({ "count", "184" }); - REQUIRE(region.sampleCount); - REQUIRE(*region.sampleCount == 184); - region.parseOpcode({ "count", "-1" }); - REQUIRE(region.sampleCount); - REQUIRE(*region.sampleCount == 0); - } - - SECTION("loop_mode") - { - REQUIRE( !region.loopMode ); - region.parseOpcode({ "loop_mode", "no_loop" }); - REQUIRE(region.loopMode == SfzLoopMode::no_loop); - region.parseOpcode({ "loop_mode", "one_shot" }); - REQUIRE(region.loopMode == SfzLoopMode::one_shot); - region.parseOpcode({ "loop_mode", "loop_continuous" }); - REQUIRE(region.loopMode == SfzLoopMode::loop_continuous); - region.parseOpcode({ "loop_mode", "loop_sustain" }); - REQUIRE(region.loopMode == SfzLoopMode::loop_sustain); - } - - SECTION("loopmode") - { - REQUIRE( !region.loopMode ); - region.parseOpcode({ "loopmode", "no_loop" }); - REQUIRE(region.loopMode == SfzLoopMode::no_loop); - region.parseOpcode({ "loopmode", "one_shot" }); - REQUIRE(region.loopMode == SfzLoopMode::one_shot); - region.parseOpcode({ "loopmode", "loop_continuous" }); - REQUIRE(region.loopMode == SfzLoopMode::loop_continuous); - region.parseOpcode({ "loopmode", "loop_sustain" }); - REQUIRE(region.loopMode == SfzLoopMode::loop_sustain); - } - - SECTION("loop_end") - { - REQUIRE(region.loopRange == Range(0, 4294967295)); - region.parseOpcode({ "loop_end", "184" }); - REQUIRE(region.loopRange == Range(0, 184)); - region.parseOpcode({ "loop_end", "-1" }); - REQUIRE(region.loopRange == Range(0, 0)); - } - - SECTION("loop_start") - { - region.parseOpcode({ "loop_start", "184" }); - REQUIRE(region.loopRange == Range(184, 4294967295)); - region.parseOpcode({ "loop_start", "-1" }); - REQUIRE(region.loopRange == Range(0, 4294967295)); - } - - SECTION("loopend") - { - REQUIRE(region.loopRange == Range(0, 4294967295)); - region.parseOpcode({ "loopend", "184" }); - REQUIRE(region.loopRange == Range(0, 184)); - region.parseOpcode({ "loopend", "-1" }); - REQUIRE(region.loopRange == Range(0, 0)); - } - - SECTION("loopstart") - { - region.parseOpcode({ "loopstart", "184" }); - REQUIRE(region.loopRange == Range(184, 4294967295)); - region.parseOpcode({ "loopstart", "-1" }); - REQUIRE(region.loopRange == Range(0, 4294967295)); - } - - SECTION("loop_crossfade") - { - region.parseOpcode({ "loop_crossfade", "0.5" }); - REQUIRE(region.loopCrossfade == Approx(0.5f)); - region.parseOpcode({ "loop_crossfade", "0" }); - REQUIRE(region.loopCrossfade > 0); - } - - SECTION("group") - { - REQUIRE(region.group == 0); - region.parseOpcode({ "group", "5" }); - REQUIRE(region.group == 5); - region.parseOpcode({ "group", "-1" }); - REQUIRE(region.group == 0); - } - - SECTION("off_by") - { - REQUIRE(!region.offBy); - region.parseOpcode({ "off_by", "5" }); - REQUIRE(region.offBy); - REQUIRE(*region.offBy == 5); - region.parseOpcode({ "off_by", "-1" }); - REQUIRE(!region.offBy); - } - - SECTION("off_mode") - { - REQUIRE(region.offMode == SfzOffMode::fast); - region.parseOpcode({ "off_mode", "fast" }); - REQUIRE(region.offMode == SfzOffMode::fast); - region.parseOpcode({ "off_mode", "normal" }); - REQUIRE(region.offMode == SfzOffMode::normal); - region.parseOpcode({ "off_mode", "time" }); - REQUIRE(region.offMode == SfzOffMode::time); - } - - SECTION("off_time") - { - REQUIRE(region.offTime == 0.006f); - REQUIRE(region.offMode == SfzOffMode::fast); - region.parseOpcode({ "off_time", "0.1" }); - REQUIRE(region.offTime == 0.1f); - REQUIRE(region.offMode == SfzOffMode::time); - region.parseOpcode({ "off_time", "0" }); - REQUIRE(region.offTime == 0.0f); - region.parseOpcode({ "off_time", "0.1" }); - region.parseOpcode({ "off_time", "-1" }); - REQUIRE(region.offTime == 0.0f); - } - - SECTION("lokey, hikey, and key") - { - REQUIRE(region.keyRange == Range(0, 127)); - region.parseOpcode({ "lokey", "37" }); - REQUIRE(region.keyRange == Range(37, 127)); - region.parseOpcode({ "lokey", "c4" }); - REQUIRE(region.keyRange == Range(60, 127)); - region.parseOpcode({ "lokey", "128" }); - REQUIRE(region.keyRange == Range(127, 127)); - region.parseOpcode({ "lokey", "-3" }); - REQUIRE(region.keyRange == Range(0, 127)); - region.parseOpcode({ "hikey", "65" }); - REQUIRE(region.keyRange == Range(0, 65)); - region.parseOpcode({ "hikey", "c4" }); - REQUIRE(region.keyRange == Range(0, 60)); - region.parseOpcode({ "hikey", "-1" }); - REQUIRE(region.keyRange == Range(0, 0)); - region.parseOpcode({ "hikey", "128" }); - REQUIRE(region.keyRange == Range(0, 127)); - region.parseOpcode({ "key", "26" }); - REQUIRE(region.keyRange == Range(26, 26)); - REQUIRE(region.pitchKeycenter == 26); - region.parseOpcode({ "key", "-26" }); - REQUIRE(region.keyRange == Range(0, 0)); - REQUIRE(region.pitchKeycenter == 0); - region.parseOpcode({ "key", "234" }); - REQUIRE(region.keyRange == Range(127, 127)); - REQUIRE(region.pitchKeycenter == 127); - region.parseOpcode({ "key", "c4" }); - REQUIRE(region.keyRange == Range(60, 60)); - REQUIRE(region.pitchKeycenter == 60); - } - - SECTION("lovel, hivel") - { - REQUIRE(region.velocityRange == Range(0_norm, 127_norm)); - region.parseOpcode({ "lovel", "37" }); - REQUIRE(region.velocityRange == Range(37_norm, 127_norm)); - region.parseOpcode({ "lovel", "128" }); - REQUIRE(region.velocityRange == Range(127_norm, 127_norm)); - region.parseOpcode({ "lovel", "-3" }); - REQUIRE(region.velocityRange == Range(0_norm, 127_norm)); - region.parseOpcode({ "hivel", "65" }); - REQUIRE(region.velocityRange == Range(0_norm, 65_norm)); - region.parseOpcode({ "hivel", "-1" }); - REQUIRE(region.velocityRange == Range(0_norm, 0_norm)); - region.parseOpcode({ "hivel", "128" }); - REQUIRE(region.velocityRange == Range(0_norm, 127_norm)); - } - - SECTION("lobend, hibend") - { - REQUIRE(region.bendRange == Range(-1.0f, 1.0f)); - region.parseOpcode({ "lobend", "400" }); - REQUIRE(region.bendRange.getStart() == Approx(normalizeBend(400))); - REQUIRE(region.bendRange.getEnd() == 1.0_a); - region.parseOpcode({ "lobend", "-128" }); - REQUIRE(region.bendRange.getStart() == Approx(normalizeBend(-128))); - REQUIRE(region.bendRange.getEnd() == 1.0_a); - region.parseOpcode({ "lobend", "-10000" }); - REQUIRE(region.bendRange == Range(-1.0f, 1.0f)); - region.parseOpcode({ "hibend", "13" }); - REQUIRE(region.bendRange.getStart() == -1.0_a); - REQUIRE(region.bendRange.getEnd() == Approx(normalizeBend(13))); - region.parseOpcode({ "hibend", "-1" }); - REQUIRE(region.bendRange.getStart() == -1.0_a); - REQUIRE(region.bendRange.getEnd() == Approx(normalizeBend(-1))); - region.parseOpcode({ "hibend", "10000" }); - REQUIRE(region.bendRange == Range(-1.0f, 1.0f)); - } - - SECTION("locc, hicc") - { - REQUIRE(region.ccConditions.getWithDefault(0) == Range(0_norm, 127_norm)); - REQUIRE(region.ccConditions[127] == Range(0_norm, 127_norm)); - region.parseOpcode({ "locc6", "4" }); - REQUIRE(region.ccConditions[6] == Range(4_norm, 127_norm)); - region.parseOpcode({ "locc12", "-128" }); - REQUIRE(region.ccConditions[12] == Range(0_norm, 127_norm)); - region.parseOpcode({ "hicc65", "39" }); - REQUIRE(region.ccConditions[65] == Range(0_norm, 39_norm)); - region.parseOpcode({ "hicc127", "135" }); - REQUIRE(region.ccConditions[127] == Range(0_norm, 127_norm)); - } - - SECTION("lohdcc, hihdcc") - { - region.parseOpcode({ "lohdcc7", "0.12" }); - REQUIRE(region.ccConditions[7].getStart() == Approx(0.12f)); - REQUIRE(region.ccConditions[7].getEnd() == 1.0f); - region.parseOpcode({ "lohdcc13", "-1.0" }); - REQUIRE(region.ccConditions[13] == sfz::Range(0.0f, 1.0f)); - region.parseOpcode({ "hihdcc64", "0.45" }); - REQUIRE(region.ccConditions[64].getStart() == 0.0f); - REQUIRE(region.ccConditions[64].getEnd() == Approx(0.45f)); - region.parseOpcode({ "hihdcc126", "1.2" }); - REQUIRE(region.ccConditions[126] == sfz::Range(0.0f, 1.0f)); - } - - SECTION("lorealcc, hirealcc") - { - region.parseOpcode({ "lorealcc8", "0.12" }); - REQUIRE(region.ccConditions[8].getStart() == Approx(0.12f)); - REQUIRE(region.ccConditions[8].getEnd() == 1.0f); - region.parseOpcode({ "lorealcc14", "-1.0" }); - REQUIRE(region.ccConditions[14] == sfz::Range(0.0f, 1.0f)); - region.parseOpcode({ "hirealcc63", "0.45" }); - REQUIRE(region.ccConditions[63].getStart() == 0.0f); - REQUIRE(region.ccConditions[63].getEnd() == Approx(0.45f)); - region.parseOpcode({ "hirealcc125", "1.2" }); - REQUIRE(region.ccConditions[125] == sfz::Range(0.0f, 1.0f)); - } - - SECTION("sw_label") - { - REQUIRE(!region.keyswitchLabel); - region.parseOpcode({ "sw_label", "note" }); - REQUIRE(region.keyswitchLabel == "note"); - region.parseOpcode({ "sw_label", "ring" }); - REQUIRE(region.keyswitchLabel == "ring"); - } - - SECTION("sw_last") - { - REQUIRE(!region.lastKeyswitch); - region.parseOpcode({ "sw_last", "4" }); - REQUIRE(region.lastKeyswitch); - REQUIRE(*region.lastKeyswitch == 4); - region.parseOpcode({ "sw_last", "128" }); - REQUIRE(region.lastKeyswitch); - REQUIRE(*region.lastKeyswitch == 127); - region.parseOpcode({ "sw_last", "-1" }); - REQUIRE(region.lastKeyswitch); - REQUIRE(*region.lastKeyswitch == 0); - } - - SECTION("sw_lolast/hilast") - { - REQUIRE(!region.lastKeyswitchRange); - region.parseOpcode({ "sw_lolast", "4" }); - REQUIRE(region.lastKeyswitchRange); - REQUIRE(*region.lastKeyswitchRange == Range(4, 4)); - region.parseOpcode({ "sw_hilast", "128" }); - REQUIRE(*region.lastKeyswitchRange == Range(4, 127)); - region.parseOpcode({ "sw_hilast", "63" }); - REQUIRE(*region.lastKeyswitchRange == Range(4, 63)); - region.parseOpcode({ "sw_lolast", "64" }); - REQUIRE(*region.lastKeyswitchRange == Range(64, 64)); - region.parseOpcode({ "sw_lolast", "-1" }); - REQUIRE(*region.lastKeyswitchRange == Range(0, 64)); - } - - SECTION("sw_hilast disables sw_last") - { - REQUIRE(!region.lastKeyswitchRange); - REQUIRE(!region.lastKeyswitch); - region.parseOpcode({ "sw_last", "4" }); - REQUIRE(region.lastKeyswitch); - region.parseOpcode({ "sw_hilast", "63" }); - REQUIRE(region.lastKeyswitchRange); - REQUIRE(!region.lastKeyswitch); - region.parseOpcode({ "sw_last", "4" }); - REQUIRE(!region.lastKeyswitch); - } - - SECTION("sw_lolast disables sw_last") - { - REQUIRE(!region.lastKeyswitchRange); - REQUIRE(!region.lastKeyswitch); - region.parseOpcode({ "sw_last", "4" }); - REQUIRE(region.lastKeyswitch); - region.parseOpcode({ "sw_lolast", "63" }); - REQUIRE(region.lastKeyswitchRange); - REQUIRE(!region.lastKeyswitch); - region.parseOpcode({ "sw_last", "4" }); - REQUIRE(!region.lastKeyswitch); - } - - SECTION("sw_up") - { - REQUIRE(!region.upKeyswitch); - region.parseOpcode({ "sw_up", "4" }); - REQUIRE(region.upKeyswitch); - REQUIRE(*region.upKeyswitch == 4); - region.parseOpcode({ "sw_up", "128" }); - REQUIRE(region.upKeyswitch); - REQUIRE(*region.upKeyswitch == 127); - region.parseOpcode({ "sw_up", "-1" }); - REQUIRE(region.upKeyswitch); - REQUIRE(*region.upKeyswitch == 0); - } - - SECTION("sw_down") - { - REQUIRE(!region.downKeyswitch); - region.parseOpcode({ "sw_down", "4" }); - REQUIRE(region.downKeyswitch); - REQUIRE(*region.downKeyswitch == 4); - region.parseOpcode({ "sw_down", "128" }); - REQUIRE(region.downKeyswitch); - REQUIRE(*region.downKeyswitch == 127); - region.parseOpcode({ "sw_down", "-1" }); - REQUIRE(region.downKeyswitch); - REQUIRE(*region.downKeyswitch == 0); - } - - SECTION("sw_previous") - { - REQUIRE(!region.previousKeyswitch); - region.parseOpcode({ "sw_previous", "4" }); - REQUIRE(region.previousKeyswitch); - REQUIRE(*region.previousKeyswitch == 4); - region.parseOpcode({ "sw_previous", "128" }); - REQUIRE(region.previousKeyswitch); - REQUIRE(*region.previousKeyswitch == 127); - region.parseOpcode({ "sw_previous", "-1" }); - REQUIRE(region.previousKeyswitch); - REQUIRE(*region.previousKeyswitch == 0); - } - - SECTION("sw_vel") - { - REQUIRE(region.velocityOverride == SfzVelocityOverride::current); - region.parseOpcode({ "sw_vel", "current" }); - REQUIRE(region.velocityOverride == SfzVelocityOverride::current); - region.parseOpcode({ "sw_vel", "previous" }); - REQUIRE(region.velocityOverride == SfzVelocityOverride::previous); - } - - SECTION("lochanaft, hichanaft") - { - REQUIRE(region.aftertouchRange == Range(0, 127)); - region.parseOpcode({ "lochanaft", "4" }); - REQUIRE(region.aftertouchRange == Range(4, 127)); - region.parseOpcode({ "lochanaft", "128" }); - REQUIRE(region.aftertouchRange == Range(127, 127)); - region.parseOpcode({ "lochanaft", "0" }); - REQUIRE(region.aftertouchRange == Range(0, 127)); - region.parseOpcode({ "hichanaft", "39" }); - REQUIRE(region.aftertouchRange == Range(0, 39)); - region.parseOpcode({ "hichanaft", "135" }); - REQUIRE(region.aftertouchRange == Range(0, 127)); - region.parseOpcode({ "hichanaft", "-1" }); - REQUIRE(region.aftertouchRange == Range(0, 0)); - } - - SECTION("lobpm, hibpm") - { - REQUIRE(region.bpmRange == Range(0, 500)); - region.parseOpcode({ "lobpm", "47.5" }); - REQUIRE(region.bpmRange == Range(47.5, 500)); - region.parseOpcode({ "lobpm", "594" }); - REQUIRE(region.bpmRange == Range(500, 500)); - region.parseOpcode({ "lobpm", "0" }); - REQUIRE(region.bpmRange == Range(0, 500)); - region.parseOpcode({ "hibpm", "78" }); - REQUIRE(region.bpmRange == Range(0, 78)); - region.parseOpcode({ "hibpm", "895.4" }); - REQUIRE(region.bpmRange == Range(0, 500)); - region.parseOpcode({ "hibpm", "-1" }); - REQUIRE(region.bpmRange == Range(0, 0)); - } - - SECTION("lorand, hirand") - { - REQUIRE(region.randRange == Range(0, 1)); - region.parseOpcode({ "lorand", "0.5" }); - REQUIRE(region.randRange == Range(0.5, 1)); - region.parseOpcode({ "lorand", "4" }); - REQUIRE(region.randRange == Range(1, 1)); - region.parseOpcode({ "lorand", "0" }); - REQUIRE(region.randRange == Range(0, 1)); - region.parseOpcode({ "hirand", "39" }); - REQUIRE(region.randRange == Range(0, 1)); - region.parseOpcode({ "hirand", "0.7" }); - REQUIRE(region.randRange == Range(0, 0.7f)); - region.parseOpcode({ "hirand", "-1" }); - REQUIRE(region.randRange == Range(0, 0)); - } - - SECTION("seq_length") - { - REQUIRE(region.sequenceLength == 1); - region.parseOpcode({ "seq_length", "89" }); - REQUIRE(region.sequenceLength == 89); - region.parseOpcode({ "seq_length", "189" }); - REQUIRE(region.sequenceLength == 100); - region.parseOpcode({ "seq_length", "-1" }); - REQUIRE(region.sequenceLength == 1); - } - - SECTION("seq_position") - { - REQUIRE(region.sequencePosition == 1); - region.parseOpcode({ "seq_position", "89" }); - REQUIRE(region.sequencePosition == 89); - region.parseOpcode({ "seq_position", "189" }); - REQUIRE(region.sequencePosition == 100); - region.parseOpcode({ "seq_position", "-1" }); - REQUIRE(region.sequencePosition == 1); - } - - SECTION("trigger") - { - REQUIRE(region.trigger == SfzTrigger::attack); - region.parseOpcode({ "trigger", "attack" }); - REQUIRE(region.trigger == SfzTrigger::attack); - region.parseOpcode({ "trigger", "release" }); - REQUIRE(region.trigger == SfzTrigger::release); - region.parseOpcode({ "trigger", "release_key" }); - REQUIRE(region.trigger == SfzTrigger::release_key); - region.parseOpcode({ "trigger", "first" }); - REQUIRE(region.trigger == SfzTrigger::first); - region.parseOpcode({ "trigger", "legato" }); - REQUIRE(region.trigger == SfzTrigger::legato); - } - - SECTION("on_locc, on_hicc") - { - for (int ccIdx = 1; ccIdx < 128; ++ccIdx) { - REQUIRE(!region.ccTriggers.contains(ccIdx)); - } - region.parseOpcode({ "on_locc45", "15" }); - REQUIRE(region.ccTriggers.contains(45)); - REQUIRE(region.ccTriggers[45] == Range(15_norm, 127_norm)); - region.parseOpcode({ "on_hicc4", "47" }); - REQUIRE(region.ccTriggers.contains(45)); - REQUIRE(region.ccTriggers[4] == Range(0_norm, 47_norm)); - } - - SECTION("on_lohdcc, on_hihdcc") - { - for (int ccIdx = 1; ccIdx < 128; ++ccIdx) { - REQUIRE(!region.ccTriggers.contains(ccIdx)); - } - region.parseOpcode({ "on_lohdcc46", "0.15" }); - REQUIRE(region.ccTriggers.contains(46)); - REQUIRE(region.ccTriggers[46].getStart() == Approx(0.15f)); - REQUIRE(region.ccTriggers[46].getEnd() == 1.0f); - region.parseOpcode({ "on_hihdcc5", "0.47" }); - REQUIRE(region.ccTriggers.contains(5)); - REQUIRE(region.ccTriggers[5].getStart() == 0.0f); - REQUIRE(region.ccTriggers[5].getEnd() == Approx(0.47f)); - } - - SECTION("volume") - { - REQUIRE(region.volume == 0.0f); - region.parseOpcode({ "volume", "4.2" }); - REQUIRE(region.volume == 4.2f); - region.parseOpcode({ "volume", "-4.2" }); - REQUIRE(region.volume == -4.2f); - region.parseOpcode({ "volume", "-123" }); - REQUIRE(region.volume == -123.0f); - region.parseOpcode({ "volume", "-185" }); - REQUIRE(region.volume == -144.0f); - region.parseOpcode({ "volume", "79" }); - REQUIRE(region.volume == 48.0f); - } - - SECTION("pan") - { - REQUIRE(region.pan == 0.0f); - region.parseOpcode({ "pan", "4.2" }); - REQUIRE(region.pan == 0.042_a); - region.parseOpcode({ "pan", "-4.2" }); - REQUIRE(region.pan == -0.042_a); - region.parseOpcode({ "pan", "-123" }); - REQUIRE(region.pan == -1.0_a); - region.parseOpcode({ "pan", "132" }); - REQUIRE(region.pan == 1.0_a); - } - - SECTION("pan_oncc") - { - const ModKey target = ModKey::createNXYZ(ModId::Pan, region.getId()); - const RegionCCView view(region, target); - REQUIRE(view.empty()); - region.parseOpcode({ "pan_oncc45", "4.2" }); - REQUIRE(view.valueAt(45) == 4.2_a); - region.parseOpcode({ "pan_curvecc17", "18" }); - REQUIRE(view.at(17).curve == 18); - region.parseOpcode({ "pan_curvecc17", "15482" }); - REQUIRE(view.at(17).curve == 255); - region.parseOpcode({ "pan_curvecc17", "-2" }); - REQUIRE(view.at(17).curve == 0); - region.parseOpcode({ "pan_smoothcc14", "85" }); - REQUIRE(view.at(14).smooth == 85); - region.parseOpcode({ "pan_smoothcc14", "15482" }); - REQUIRE(view.at(14).smooth == 100); - region.parseOpcode({ "pan_smoothcc14", "-2" }); - REQUIRE(view.at(14).smooth == 0); - region.parseOpcode({ "pan_stepcc120", "24" }); - REQUIRE(view.at(120).step == 24.0_a); - region.parseOpcode({ "pan_stepcc120", "15482" }); - REQUIRE(view.at(120).step == 200.0_a); - region.parseOpcode({ "pan_stepcc120", "-2" }); - REQUIRE(view.at(120).step == 0.0f); - } - - SECTION("width") - { - REQUIRE(region.width == 1.0_a); - region.parseOpcode({ "width", "4.2" }); - REQUIRE(region.width == 0.042_a); - region.parseOpcode({ "width", "-4.2" }); - REQUIRE(region.width == -0.042_a); - region.parseOpcode({ "width", "-123" }); - REQUIRE(region.width == -1.0_a); - region.parseOpcode({ "width", "132" }); - REQUIRE(region.width == 1.0_a); - } - - SECTION("width_oncc") - { - const ModKey target = ModKey::createNXYZ(ModId::Width, region.getId()); - const RegionCCView view(region, target); - REQUIRE(view.empty()); - region.parseOpcode({ "width_oncc45", "4.2" }); - REQUIRE(view.valueAt(45) == 4.2_a); - region.parseOpcode({ "width_curvecc17", "18" }); - REQUIRE(view.at(17).curve == 18); - region.parseOpcode({ "width_curvecc17", "15482" }); - REQUIRE(view.at(17).curve == 255); - region.parseOpcode({ "width_curvecc17", "-2" }); - REQUIRE(view.at(17).curve == 0); - region.parseOpcode({ "width_smoothcc14", "85" }); - REQUIRE(view.at(14).smooth == 85); - region.parseOpcode({ "width_smoothcc14", "15482" }); - REQUIRE(view.at(14).smooth == 100); - region.parseOpcode({ "width_smoothcc14", "-2" }); - REQUIRE(view.at(14).smooth == 0); - region.parseOpcode({ "width_stepcc120", "24" }); - REQUIRE(view.at(120).step == 24.0_a); - region.parseOpcode({ "width_stepcc120", "15482" }); - REQUIRE(view.at(120).step == 200.0_a); - region.parseOpcode({ "width_stepcc120", "-20" }); - REQUIRE(view.at(120).step == 0.0f); - } - - SECTION("position") - { - REQUIRE(region.position == 0.0f); - region.parseOpcode({ "position", "4.2" }); - REQUIRE(region.position == 0.042_a); - region.parseOpcode({ "position", "-4.2" }); - REQUIRE(region.position == -0.042_a); - region.parseOpcode({ "position", "-123" }); - REQUIRE(region.position == -1.0_a); - region.parseOpcode({ "position", "132" }); - REQUIRE(region.position == 1.0_a); - } - - SECTION("position_oncc") - { - const ModKey target = ModKey::createNXYZ(ModId::Position, region.getId()); - const RegionCCView view(region, target); - REQUIRE(view.empty()); - region.parseOpcode({ "position_oncc45", "4.2" }); - REQUIRE(view.valueAt(45) == 4.2_a); - region.parseOpcode({ "position_curvecc17", "18" }); - REQUIRE(view.at(17).curve == 18); - region.parseOpcode({ "position_curvecc17", "15482" }); - REQUIRE(view.at(17).curve == 255); - region.parseOpcode({ "position_curvecc17", "-2" }); - REQUIRE(view.at(17).curve == 0); - region.parseOpcode({ "position_smoothcc14", "85" }); - REQUIRE(view.at(14).smooth == 85); - region.parseOpcode({ "position_smoothcc14", "15482" }); - REQUIRE(view.at(14).smooth == 100); - region.parseOpcode({ "position_smoothcc14", "-2" }); - REQUIRE(view.at(14).smooth == 0); - region.parseOpcode({ "position_stepcc120", "24" }); - REQUIRE(view.at(120).step == 24.0_a); - region.parseOpcode({ "position_stepcc120", "15482" }); - REQUIRE(view.at(120).step == 200.0_a); - region.parseOpcode({ "position_stepcc120", "-2" }); - REQUIRE(view.at(120).step == 0.0f); - } - - SECTION("amp_keycenter") - { - REQUIRE(region.ampKeycenter == 60); - region.parseOpcode({ "amp_keycenter", "40" }); - REQUIRE(region.ampKeycenter == 40); - region.parseOpcode({ "amp_keycenter", "-1" }); - REQUIRE(region.ampKeycenter == 0); - region.parseOpcode({ "amp_keycenter", "132" }); - REQUIRE(region.ampKeycenter == 127); - } - - SECTION("amp_keytrack") - { - REQUIRE(region.ampKeytrack == 0.0f); - region.parseOpcode({ "amp_keytrack", "4.2" }); - REQUIRE(region.ampKeytrack == 4.2f); - region.parseOpcode({ "amp_keytrack", "-4.2" }); - REQUIRE(region.ampKeytrack == -4.2f); - region.parseOpcode({ "amp_keytrack", "-123" }); - REQUIRE(region.ampKeytrack == -96.0f); - region.parseOpcode({ "amp_keytrack", "132" }); - REQUIRE(region.ampKeytrack == 12.0f); - } - - SECTION("amp_veltrack") - { - REQUIRE(region.ampVeltrack == 1.0f); - region.parseOpcode({ "amp_veltrack", "4.2" }); - REQUIRE(region.ampVeltrack == Approx(0.042f)); - region.parseOpcode({ "amp_veltrack", "-4.2" }); - REQUIRE(region.ampVeltrack == Approx(-0.042f)); - region.parseOpcode({ "amp_veltrack", "-123" }); - REQUIRE(region.ampVeltrack == -1.0f); - region.parseOpcode({ "amp_veltrack", "132" }); - REQUIRE(region.ampVeltrack == 1.0f); - } - - SECTION("amp_random") - { - REQUIRE(region.ampRandom == 0.0f); - region.parseOpcode({ "amp_random", "4.2" }); - REQUIRE(region.ampRandom == 4.2f); - region.parseOpcode({ "amp_random", "-4.2" }); - REQUIRE(region.ampRandom == 0.0f); - region.parseOpcode({ "amp_random", "132" }); - REQUIRE(region.ampRandom == 24.0f); - } - - SECTION("amp_velcurve") - { - region.parseOpcode({ "amp_velcurve_6", "0.4" }); - REQUIRE(region.velocityPoints.back() == std::pair(6, 0.4f)); - region.parseOpcode({ "amp_velcurve_127", "-1.0" }); - REQUIRE(region.velocityPoints.back() == std::pair(127, 0.0f)); - region.parseOpcode({ "amp_velcurve_008", "0.3" }); - REQUIRE(region.velocityPoints.back() == std::pair(8, 0.3f)); - region.parseOpcode({ "amp_velcurve_064", "0.9" }); - REQUIRE(region.velocityPoints.back() == std::pair(64, 0.9f)); - } - - SECTION("xfin_lokey, xfin_hikey") - { - REQUIRE(region.crossfadeKeyInRange == Range(0, 0)); - region.parseOpcode({ "xfin_lokey", "4" }); - REQUIRE(region.crossfadeKeyInRange == Range(4, 4)); - region.parseOpcode({ "xfin_lokey", "128" }); - REQUIRE(region.crossfadeKeyInRange == Range(127, 127)); - region.parseOpcode({ "xfin_lokey", "59" }); - REQUIRE(region.crossfadeKeyInRange == Range(59, 127)); - region.parseOpcode({ "xfin_hikey", "59" }); - REQUIRE(region.crossfadeKeyInRange == Range(59, 59)); - region.parseOpcode({ "xfin_hikey", "128" }); - REQUIRE(region.crossfadeKeyInRange == Range(59, 127)); - region.parseOpcode({ "xfin_hikey", "0" }); - REQUIRE(region.crossfadeKeyInRange == Range(0, 0)); - region.parseOpcode({ "xfin_hikey", "-1" }); - REQUIRE(region.crossfadeKeyInRange == Range(0, 0)); - } - - SECTION("xfin_lovel, xfin_hivel") - { - REQUIRE(region.crossfadeVelInRange == Range(0_norm, 0_norm)); - region.parseOpcode({ "xfin_lovel", "4" }); - REQUIRE(region.crossfadeVelInRange == Range(4_norm, 4_norm)); - region.parseOpcode({ "xfin_lovel", "128" }); - REQUIRE(region.crossfadeVelInRange == Range(127_norm, 127_norm)); - region.parseOpcode({ "xfin_lovel", "59" }); - REQUIRE(region.crossfadeVelInRange == Range(59_norm, 127_norm)); - region.parseOpcode({ "xfin_hivel", "59" }); - REQUIRE(region.crossfadeVelInRange == Range(59_norm, 59_norm)); - region.parseOpcode({ "xfin_hivel", "128" }); - REQUIRE(region.crossfadeVelInRange == Range(59_norm, 127_norm)); - region.parseOpcode({ "xfin_hivel", "0" }); - REQUIRE(region.crossfadeVelInRange == Range(0_norm, 0_norm)); - region.parseOpcode({ "xfin_hivel", "-1" }); - REQUIRE(region.crossfadeVelInRange == Range(0_norm, 0_norm)); - } - - SECTION("xfout_lokey, xfout_hikey") - { - REQUIRE(region.crossfadeKeyOutRange == Range(127, 127)); - region.parseOpcode({ "xfout_lokey", "4" }); - REQUIRE(region.crossfadeKeyOutRange == Range(4, 127)); - region.parseOpcode({ "xfout_lokey", "128" }); - REQUIRE(region.crossfadeKeyOutRange == Range(127, 127)); - region.parseOpcode({ "xfout_lokey", "59" }); - REQUIRE(region.crossfadeKeyOutRange == Range(59, 127)); - region.parseOpcode({ "xfout_hikey", "59" }); - REQUIRE(region.crossfadeKeyOutRange == Range(59, 59)); - region.parseOpcode({ "xfout_hikey", "128" }); - REQUIRE(region.crossfadeKeyOutRange == Range(59, 127)); - region.parseOpcode({ "xfout_hikey", "0" }); - REQUIRE(region.crossfadeKeyOutRange == Range(0, 0)); - region.parseOpcode({ "xfout_hikey", "-1" }); - REQUIRE(region.crossfadeKeyOutRange == Range(0, 0)); - } - - SECTION("xfout_lovel, xfout_hivel") - { - REQUIRE(region.crossfadeVelOutRange == Range(127_norm, 127_norm)); - region.parseOpcode({ "xfout_lovel", "4" }); - REQUIRE(region.crossfadeVelOutRange == Range(4_norm, 127_norm)); - region.parseOpcode({ "xfout_lovel", "128" }); - REQUIRE(region.crossfadeVelOutRange == Range(127_norm, 127_norm)); - region.parseOpcode({ "xfout_lovel", "59" }); - REQUIRE(region.crossfadeVelOutRange == Range(59_norm, 127_norm)); - region.parseOpcode({ "xfout_hivel", "59" }); - REQUIRE(region.crossfadeVelOutRange == Range(59_norm, 59_norm)); - region.parseOpcode({ "xfout_hivel", "128" }); - REQUIRE(region.crossfadeVelOutRange == Range(59_norm, 127_norm)); - region.parseOpcode({ "xfout_hivel", "0" }); - REQUIRE(region.crossfadeVelOutRange == Range(0_norm, 0_norm)); - region.parseOpcode({ "xfout_hivel", "-1" }); - REQUIRE(region.crossfadeVelOutRange == Range(0_norm, 0_norm)); - } - - SECTION("xfin_locc, xfin_hicc") - { - REQUIRE(!region.crossfadeCCInRange.contains(4)); - region.parseOpcode({ "xfin_locc4", "4" }); - REQUIRE(region.crossfadeCCInRange[4] == Range(4_norm, 4_norm)); - region.parseOpcode({ "xfin_locc4", "128" }); - REQUIRE(region.crossfadeCCInRange[4] == Range(127_norm, 127_norm)); - region.parseOpcode({ "xfin_locc4", "59" }); - REQUIRE(region.crossfadeCCInRange[4] == Range(59_norm, 127_norm)); - region.parseOpcode({ "xfin_hicc4", "59" }); - REQUIRE(region.crossfadeCCInRange[4] == Range(59_norm, 59_norm)); - region.parseOpcode({ "xfin_hicc4", "128" }); - REQUIRE(region.crossfadeCCInRange[4] == Range(59_norm, 127_norm)); - region.parseOpcode({ "xfin_hicc4", "0" }); - REQUIRE(region.crossfadeCCInRange[4] == Range(0_norm, 0_norm)); - region.parseOpcode({ "xfin_hicc4", "-1" }); - REQUIRE(region.crossfadeCCInRange[4] == Range(0_norm, 0_norm)); - } - - SECTION("xfout_locc, xfout_hicc") - { - REQUIRE(!region.crossfadeCCOutRange.contains(4)); - region.parseOpcode({ "xfout_locc4", "4" }); - REQUIRE(region.crossfadeCCOutRange[4] == Range(4_norm, 127_norm)); - region.parseOpcode({ "xfout_locc4", "128" }); - REQUIRE(region.crossfadeCCOutRange[4] == Range(127_norm, 127_norm)); - region.parseOpcode({ "xfout_locc4", "59" }); - REQUIRE(region.crossfadeCCOutRange[4] == Range(59_norm, 127_norm)); - region.parseOpcode({ "xfout_hicc4", "59" }); - REQUIRE(region.crossfadeCCOutRange[4] == Range(59_norm, 59_norm)); - region.parseOpcode({ "xfout_hicc4", "128" }); - REQUIRE(region.crossfadeCCOutRange[4] == Range(59_norm, 127_norm)); - region.parseOpcode({ "xfout_hicc4", "0" }); - REQUIRE(region.crossfadeCCOutRange[4] == Range(0_norm, 0_norm)); - region.parseOpcode({ "xfout_hicc4", "-1" }); - REQUIRE(region.crossfadeCCOutRange[4] == Range(0_norm, 0_norm)); - } - - SECTION("xf_keycurve") - { - REQUIRE(region.crossfadeKeyCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_keycurve", "gain" }); - REQUIRE(region.crossfadeKeyCurve == SfzCrossfadeCurve::gain); - region.parseOpcode({ "xf_keycurve", "power" }); - REQUIRE(region.crossfadeKeyCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_keycurve", "something" }); - REQUIRE(region.crossfadeKeyCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_keycurve", "gain" }); - region.parseOpcode({ "xf_keycurve", "something" }); - REQUIRE(region.crossfadeKeyCurve == SfzCrossfadeCurve::gain); - } - - SECTION("xf_velcurve") - { - REQUIRE(region.crossfadeVelCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_velcurve", "gain" }); - REQUIRE(region.crossfadeVelCurve == SfzCrossfadeCurve::gain); - region.parseOpcode({ "xf_velcurve", "power" }); - REQUIRE(region.crossfadeVelCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_velcurve", "something" }); - REQUIRE(region.crossfadeVelCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_velcurve", "gain" }); - region.parseOpcode({ "xf_velcurve", "something" }); - REQUIRE(region.crossfadeVelCurve == SfzCrossfadeCurve::gain); - } - - SECTION("xf_cccurve") - { - REQUIRE(region.crossfadeCCCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_cccurve", "gain" }); - REQUIRE(region.crossfadeCCCurve == SfzCrossfadeCurve::gain); - region.parseOpcode({ "xf_cccurve", "power" }); - REQUIRE(region.crossfadeCCCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_cccurve", "something" }); - REQUIRE(region.crossfadeCCCurve == SfzCrossfadeCurve::power); - region.parseOpcode({ "xf_cccurve", "gain" }); - region.parseOpcode({ "xf_cccurve", "something" }); - REQUIRE(region.crossfadeCCCurve == SfzCrossfadeCurve::gain); - } - - SECTION("*_volume") - { - const std::pair assoc_pairs[] = { - {"global_volume", ®ion.globalVolume}, - {"master_volume", ®ion.masterVolume}, - {"group_volume", ®ion.groupVolume}, - }; - for (auto a : assoc_pairs) { - REQUIRE(region.volume == 0.0f); - region.parseOpcode({ a.first, "4.2" }); - REQUIRE(*a.second == 4.2f); - region.parseOpcode({ a.first, "-4.2" }); - REQUIRE(*a.second == -4.2f); - region.parseOpcode({ a.first, "-123" }); - REQUIRE(*a.second == -123.0f); - region.parseOpcode({ a.first, "-185" }); - REQUIRE(*a.second == -144.0f); - region.parseOpcode({ a.first, "79" }); - REQUIRE(*a.second == 48.0f); - } - } - - SECTION("*_amplitude") - { - const std::pair assoc_pairs[] = { - {"global_amplitude", ®ion.globalAmplitude}, - {"master_amplitude", ®ion.masterAmplitude}, - {"group_amplitude", ®ion.groupAmplitude}, - }; - for (auto a : assoc_pairs) { - REQUIRE(*a.second == 1.0_a); - region.parseOpcode({ a.first, "40" }); - REQUIRE(*a.second == 0.4_a); - region.parseOpcode({ a.first, "-40" }); - REQUIRE(*a.second == 0_a); - region.parseOpcode({ a.first, "140" }); - REQUIRE(*a.second == 1.4_a); - } - } - - SECTION("pitch_keycenter") - { - REQUIRE(region.pitchKeycenter == 60); - region.parseOpcode({ "pitch_keycenter", "40" }); - REQUIRE(region.pitchKeycenter == 40); - region.parseOpcode({ "pitch_keycenter", "-1" }); - REQUIRE(region.pitchKeycenter == 0); - region.parseOpcode({ "pitch_keycenter", "132" }); - REQUIRE(region.pitchKeycenter == 127); - } - - SECTION("pitch_keytrack") - { - REQUIRE(region.pitchKeytrack == 100); - region.parseOpcode({ "pitch_keytrack", "40" }); - REQUIRE(region.pitchKeytrack == 40); - region.parseOpcode({ "pitch_keytrack", "-1" }); - REQUIRE(region.pitchKeytrack == -1); - region.parseOpcode({ "pitch_keytrack", "1320" }); - REQUIRE(region.pitchKeytrack == 1200); - region.parseOpcode({ "pitch_keytrack", "-1320" }); - REQUIRE(region.pitchKeytrack == -1200); - } - - SECTION("pitch_random") - { - REQUIRE(region.pitchRandom == 0); - region.parseOpcode({ "pitch_random", "40" }); - REQUIRE(region.pitchRandom == 40); - region.parseOpcode({ "pitch_random", "-1" }); - REQUIRE(region.pitchRandom == 0); - region.parseOpcode({ "pitch_random", "12320" }); - REQUIRE(region.pitchRandom == 12000); - } - - SECTION("pitch_veltrack") - { - REQUIRE(region.pitchVeltrack == 0); - region.parseOpcode({ "pitch_veltrack", "40" }); - REQUIRE(region.pitchVeltrack == 40); - region.parseOpcode({ "pitch_veltrack", "-1" }); - REQUIRE(region.pitchVeltrack == -1); - region.parseOpcode({ "pitch_veltrack", "13020" }); - REQUIRE(region.pitchVeltrack == 12000); - region.parseOpcode({ "pitch_veltrack", "-13020" }); - REQUIRE(region.pitchVeltrack == -12000); - } - - SECTION("transpose") - { - REQUIRE(region.transpose == 0); - region.parseOpcode({ "transpose", "40" }); - REQUIRE(region.transpose == 40); - region.parseOpcode({ "transpose", "-1" }); - REQUIRE(region.transpose == -1); - region.parseOpcode({ "transpose", "154" }); - REQUIRE(region.transpose == 127); - region.parseOpcode({ "transpose", "-154" }); - REQUIRE(region.transpose == -127); - } - - SECTION("tune") - { - REQUIRE(region.tune == 0); - region.parseOpcode({ "tune", "40" }); - REQUIRE(region.tune == 40); - region.parseOpcode({ "tune", "-1" }); - REQUIRE(region.tune == -1); - region.parseOpcode({ "tune", "15432" }); - REQUIRE(region.tune == 12000); - region.parseOpcode({ "tune", "-15432" }); - REQUIRE(region.tune == -12000); - } - - SECTION("bend_up, bend_down, bend_step, bend_smooth") - { - REQUIRE(region.bendUp == 200); - REQUIRE(region.bendDown == -200); - REQUIRE(region.bendStep == 1); - region.parseOpcode({ "bend_up", "400" }); - REQUIRE(region.bendUp == 400); - region.parseOpcode({ "bend_up", "-200" }); - REQUIRE(region.bendUp == -200); - region.parseOpcode({ "bend_up", "12700" }); - REQUIRE(region.bendUp == 12000); - region.parseOpcode({ "bend_up", "-12700" }); - REQUIRE(region.bendUp == -12000); - region.parseOpcode({ "bend_down", "400" }); - REQUIRE(region.bendDown == 400); - region.parseOpcode({ "bend_down", "-200" }); - REQUIRE(region.bendDown == -200); - region.parseOpcode({ "bend_down", "12700" }); - REQUIRE(region.bendDown == 12000); - region.parseOpcode({ "bend_down", "-12700" }); - REQUIRE(region.bendDown == -12000); - region.parseOpcode({ "bend_step", "400" }); - REQUIRE(region.bendStep == 400); - region.parseOpcode({ "bend_step", "-200" }); - REQUIRE(region.bendStep == 1); - region.parseOpcode({ "bend_step", "9700" }); - REQUIRE(region.bendStep == 1200); - region.parseOpcode({ "bend_smooth", "10" }); - REQUIRE(region.bendSmooth == 10); - region.parseOpcode({ "bend_smooth", "120" }); - REQUIRE(region.bendSmooth == 100); - region.parseOpcode({ "bend_smooth", "-2" }); - REQUIRE(region.bendSmooth == 0); - } - - SECTION("ampeg") - { - // Defaults - REQUIRE(region.amplitudeEG.attack == 0.0f); - REQUIRE(region.amplitudeEG.decay == 0.0f); - REQUIRE(region.amplitudeEG.delay == 0.0f); - REQUIRE(region.amplitudeEG.hold == 0.0f); - REQUIRE(region.amplitudeEG.release == 0.001f); - REQUIRE(region.amplitudeEG.start == 0.0f); - REQUIRE(region.amplitudeEG.sustain == 100.0f); - REQUIRE(region.amplitudeEG.depth == 0); - REQUIRE(region.amplitudeEG.vel2attack == 0.0f); - REQUIRE(region.amplitudeEG.vel2decay == 0.0f); - REQUIRE(region.amplitudeEG.vel2delay == 0.0f); - REQUIRE(region.amplitudeEG.vel2hold == 0.0f); - REQUIRE(region.amplitudeEG.vel2release == 0.0f); - REQUIRE(region.amplitudeEG.vel2sustain == 0.0f); - REQUIRE(region.amplitudeEG.vel2depth == 0); - // - region.parseOpcode({ "ampeg_attack", "1" }); - region.parseOpcode({ "ampeg_decay", "2" }); - region.parseOpcode({ "ampeg_delay", "3" }); - region.parseOpcode({ "ampeg_hold", "4" }); - region.parseOpcode({ "ampeg_release", "5" }); - region.parseOpcode({ "ampeg_start", "6" }); - region.parseOpcode({ "ampeg_sustain", "7" }); - region.parseOpcode({ "ampeg_depth", "8" }); - region.parseOpcode({ "ampeg_vel2attack", "9" }); - region.parseOpcode({ "ampeg_vel2decay", "10" }); - region.parseOpcode({ "ampeg_vel2delay", "11" }); - region.parseOpcode({ "ampeg_vel2hold", "12" }); - region.parseOpcode({ "ampeg_vel2release", "13" }); - region.parseOpcode({ "ampeg_vel2sustain", "14" }); - region.parseOpcode({ "ampeg_vel2depth", "15" }); - REQUIRE(region.amplitudeEG.attack == 1.0f); - REQUIRE(region.amplitudeEG.decay == 2.0f); - REQUIRE(region.amplitudeEG.delay == 3.0f); - REQUIRE(region.amplitudeEG.hold == 4.0f); - REQUIRE(region.amplitudeEG.release == 5.0f); - REQUIRE(region.amplitudeEG.start == 6.0f); - REQUIRE(region.amplitudeEG.sustain == 7.0f); - REQUIRE(region.amplitudeEG.depth == 0); // ignored for ampeg - REQUIRE(region.amplitudeEG.vel2attack == 9.0f); - REQUIRE(region.amplitudeEG.vel2decay == 10.0f); - REQUIRE(region.amplitudeEG.vel2delay == 11.0f); - REQUIRE(region.amplitudeEG.vel2hold == 12.0f); - REQUIRE(region.amplitudeEG.vel2release == 13.0f); - REQUIRE(region.amplitudeEG.vel2sustain == 14.0f); - REQUIRE(region.amplitudeEG.vel2depth == 0); // ignored for ampeg - // - region.parseOpcode({ "ampeg_attack", "1000" }); - region.parseOpcode({ "ampeg_decay", "1000" }); - region.parseOpcode({ "ampeg_delay", "1000" }); - region.parseOpcode({ "ampeg_hold", "1000" }); - region.parseOpcode({ "ampeg_release", "1000" }); - region.parseOpcode({ "ampeg_start", "1000" }); - region.parseOpcode({ "ampeg_sustain", "1000" }); - region.parseOpcode({ "ampeg_depth", "1000" }); - region.parseOpcode({ "ampeg_vel2attack", "1000" }); - region.parseOpcode({ "ampeg_vel2decay", "1000" }); - region.parseOpcode({ "ampeg_vel2delay", "1000" }); - region.parseOpcode({ "ampeg_vel2hold", "1000" }); - region.parseOpcode({ "ampeg_vel2release", "1000" }); - region.parseOpcode({ "ampeg_vel2sustain", "1000" }); - region.parseOpcode({ "ampeg_vel2depth", "1000" }); - REQUIRE(region.amplitudeEG.attack == 100.0f); - REQUIRE(region.amplitudeEG.decay == 100.0f); - REQUIRE(region.amplitudeEG.delay == 100.0f); - REQUIRE(region.amplitudeEG.hold == 100.0f); - REQUIRE(region.amplitudeEG.release == 100.0f); - REQUIRE(region.amplitudeEG.start == 100.0f); - REQUIRE(region.amplitudeEG.sustain == 100.0f); - REQUIRE(region.amplitudeEG.depth == 0); // ignored for ampeg - REQUIRE(region.amplitudeEG.vel2attack == 100.0f); - REQUIRE(region.amplitudeEG.vel2decay == 100.0f); - REQUIRE(region.amplitudeEG.vel2delay == 100.0f); - REQUIRE(region.amplitudeEG.vel2hold == 100.0f); - REQUIRE(region.amplitudeEG.vel2release == 100.0f); - REQUIRE(region.amplitudeEG.vel2sustain == 100.0f); - REQUIRE(region.amplitudeEG.vel2depth == 0); // ignored for ampeg - // - region.parseOpcode({ "ampeg_attack", "-101" }); - region.parseOpcode({ "ampeg_decay", "-101" }); - region.parseOpcode({ "ampeg_delay", "-101" }); - region.parseOpcode({ "ampeg_hold", "-101" }); - region.parseOpcode({ "ampeg_release", "-101" }); - region.parseOpcode({ "ampeg_start", "-101" }); - region.parseOpcode({ "ampeg_sustain", "-101" }); - region.parseOpcode({ "ampeg_depth", "-101" }); - region.parseOpcode({ "ampeg_vel2attack", "-101" }); - region.parseOpcode({ "ampeg_vel2decay", "-101" }); - region.parseOpcode({ "ampeg_vel2delay", "-101" }); - region.parseOpcode({ "ampeg_vel2hold", "-101" }); - region.parseOpcode({ "ampeg_vel2release", "-101" }); - region.parseOpcode({ "ampeg_vel2sustain", "-101" }); - region.parseOpcode({ "ampeg_vel2depth", "-101" }); - REQUIRE(region.amplitudeEG.attack == 0.0f); - REQUIRE(region.amplitudeEG.decay == 0.0f); - REQUIRE(region.amplitudeEG.delay == 0.0f); - REQUIRE(region.amplitudeEG.hold == 0.0f); - REQUIRE(region.amplitudeEG.release == 0.0f); - REQUIRE(region.amplitudeEG.start == 0.0f); - REQUIRE(region.amplitudeEG.sustain == 0.0f); - REQUIRE(region.amplitudeEG.depth == 0); // ignored for ampeg - REQUIRE(region.amplitudeEG.vel2attack == -100.0f); - REQUIRE(region.amplitudeEG.vel2decay == -100.0f); - REQUIRE(region.amplitudeEG.vel2delay == -100.0f); - REQUIRE(region.amplitudeEG.vel2hold == -100.0f); - REQUIRE(region.amplitudeEG.vel2release == -100.0f); - REQUIRE(region.amplitudeEG.vel2sustain == -100.0f); - } - - SECTION("ampeg_XX_onccNN") - { - // Defaults - REQUIRE(region.amplitudeEG.ccAttack.empty()); - REQUIRE(region.amplitudeEG.ccDecay.empty()); - REQUIRE(region.amplitudeEG.ccDelay.empty()); - REQUIRE(region.amplitudeEG.ccHold.empty()); - REQUIRE(region.amplitudeEG.ccRelease.empty()); - REQUIRE(region.amplitudeEG.ccStart.empty()); - REQUIRE(region.amplitudeEG.ccSustain.empty()); - // - region.parseOpcode({ "ampeg_attack_oncc1", "1" }); - region.parseOpcode({ "ampeg_decay_oncc2", "2" }); - region.parseOpcode({ "ampeg_delay_oncc3", "3" }); - region.parseOpcode({ "ampeg_hold_oncc4", "4" }); - region.parseOpcode({ "ampeg_release_oncc5", "5" }); - region.parseOpcode({ "ampeg_start_oncc6", "6" }); - region.parseOpcode({ "ampeg_sustain_oncc7", "7" }); - REQUIRE(region.amplitudeEG.ccAttack.contains(1)); - REQUIRE(region.amplitudeEG.ccDecay.contains(2)); - REQUIRE(region.amplitudeEG.ccDelay.contains(3)); - REQUIRE(region.amplitudeEG.ccHold.contains(4)); - REQUIRE(region.amplitudeEG.ccRelease.contains(5)); - REQUIRE(region.amplitudeEG.ccStart.contains(6)); - REQUIRE(region.amplitudeEG.ccSustain.contains(7)); - REQUIRE(region.amplitudeEG.ccAttack[1] == 1.0f); - REQUIRE(region.amplitudeEG.ccDecay[2] == 2.0f); - REQUIRE(region.amplitudeEG.ccDelay[3] == 3.0f); - REQUIRE(region.amplitudeEG.ccHold[4] == 4.0f); - REQUIRE(region.amplitudeEG.ccRelease[5] == 5.0f); - REQUIRE(region.amplitudeEG.ccStart[6] == 6.0f); - REQUIRE(region.amplitudeEG.ccSustain[7] == 7.0f); - // - region.parseOpcode({ "ampeg_attack_oncc1", "101" }); - region.parseOpcode({ "ampeg_decay_oncc2", "101" }); - region.parseOpcode({ "ampeg_delay_oncc3", "101" }); - region.parseOpcode({ "ampeg_hold_oncc4", "101" }); - region.parseOpcode({ "ampeg_release_oncc5", "101" }); - region.parseOpcode({ "ampeg_start_oncc6", "101" }); - region.parseOpcode({ "ampeg_sustain_oncc7", "101" }); - REQUIRE(region.amplitudeEG.ccAttack[1] == 100.0f); - REQUIRE(region.amplitudeEG.ccDecay[2] == 100.0f); - REQUIRE(region.amplitudeEG.ccDelay[3] == 100.0f); - REQUIRE(region.amplitudeEG.ccHold[4] == 100.0f); - REQUIRE(region.amplitudeEG.ccRelease[5] == 100.0f); - REQUIRE(region.amplitudeEG.ccStart[6] == 100.0f); - REQUIRE(region.amplitudeEG.ccSustain[7] == 100.0f); - // - region.parseOpcode({ "ampeg_attack_oncc1", "-101" }); - region.parseOpcode({ "ampeg_decay_oncc2", "-101" }); - region.parseOpcode({ "ampeg_delay_oncc3", "-101" }); - region.parseOpcode({ "ampeg_hold_oncc4", "-101" }); - region.parseOpcode({ "ampeg_release_oncc5", "-101" }); - region.parseOpcode({ "ampeg_start_oncc6", "-101" }); - region.parseOpcode({ "ampeg_sustain_oncc7", "-101" }); - REQUIRE(region.amplitudeEG.ccAttack[1] == -100.0f); - REQUIRE(region.amplitudeEG.ccDecay[2] == -100.0f); - REQUIRE(region.amplitudeEG.ccDelay[3] == -100.0f); - REQUIRE(region.amplitudeEG.ccHold[4] == -100.0f); - REQUIRE(region.amplitudeEG.ccRelease[5] == -100.0f); - REQUIRE(region.amplitudeEG.ccStart[6] == -100.0f); - REQUIRE(region.amplitudeEG.ccSustain[7] == -100.0f); - // - region.parseOpcode({ "ampeg_attack_oncc1", "1" }); - region.parseOpcode({ "ampeg_decay_oncc2", "2" }); - region.parseOpcode({ "ampeg_delay_oncc3", "3" }); - region.parseOpcode({ "ampeg_hold_oncc4", "4" }); - region.parseOpcode({ "ampeg_release_oncc5", "5" }); - region.parseOpcode({ "ampeg_start_oncc6", "6" }); - region.parseOpcode({ "ampeg_sustain_oncc7", "7" }); - region.parseOpcode({ "ampeg_attack_oncc2", "2" }); - region.parseOpcode({ "ampeg_decay_oncc3", "3" }); - region.parseOpcode({ "ampeg_delay_oncc4", "4" }); - region.parseOpcode({ "ampeg_hold_oncc5", "5" }); - region.parseOpcode({ "ampeg_release_oncc6", "6" }); - region.parseOpcode({ "ampeg_start_oncc7", "7" }); - region.parseOpcode({ "ampeg_sustain_oncc8", "8" }); - REQUIRE(region.amplitudeEG.ccAttack.contains(1)); - REQUIRE(region.amplitudeEG.ccDecay.contains(2)); - REQUIRE(region.amplitudeEG.ccDelay.contains(3)); - REQUIRE(region.amplitudeEG.ccHold.contains(4)); - REQUIRE(region.amplitudeEG.ccRelease.contains(5)); - REQUIRE(region.amplitudeEG.ccStart.contains(6)); - REQUIRE(region.amplitudeEG.ccSustain.contains(7)); - REQUIRE(region.amplitudeEG.ccAttack.contains(2)); - REQUIRE(region.amplitudeEG.ccDecay.contains(3)); - REQUIRE(region.amplitudeEG.ccDelay.contains(4)); - REQUIRE(region.amplitudeEG.ccHold.contains(5)); - REQUIRE(region.amplitudeEG.ccRelease.contains(6)); - REQUIRE(region.amplitudeEG.ccStart.contains(7)); - REQUIRE(region.amplitudeEG.ccSustain.contains(8)); - REQUIRE(region.amplitudeEG.ccAttack[1] == 1.0f); - REQUIRE(region.amplitudeEG.ccDecay[2] == 2.0f); - REQUIRE(region.amplitudeEG.ccDelay[3] == 3.0f); - REQUIRE(region.amplitudeEG.ccHold[4] == 4.0f); - REQUIRE(region.amplitudeEG.ccRelease[5] == 5.0f); - REQUIRE(region.amplitudeEG.ccStart[6] == 6.0f); - REQUIRE(region.amplitudeEG.ccSustain[7] == 7.0f); - REQUIRE(region.amplitudeEG.ccAttack[2] == 2.0f); - REQUIRE(region.amplitudeEG.ccDecay[3] == 3.0f); - REQUIRE(region.amplitudeEG.ccDelay[4] == 4.0f); - REQUIRE(region.amplitudeEG.ccHold[5] == 5.0f); - REQUIRE(region.amplitudeEG.ccRelease[6] == 6.0f); - REQUIRE(region.amplitudeEG.ccStart[7] == 7.0f); - REQUIRE(region.amplitudeEG.ccSustain[8] == 8.0f); - } - - SECTION("sustain_sw and sostenuto_sw") - { - REQUIRE(region.checkSustain); - REQUIRE(region.checkSostenuto); - region.parseOpcode({ "sustain_sw", "off" }); - REQUIRE(!region.checkSustain); - region.parseOpcode({ "sustain_sw", "on" }); - REQUIRE(region.checkSustain); - region.parseOpcode({ "sustain_sw", "off" }); - region.parseOpcode({ "sustain_sw", "obladi" }); - REQUIRE(region.checkSustain); - region.parseOpcode({ "sostenuto_sw", "off" }); - REQUIRE(!region.checkSostenuto); - region.parseOpcode({ "sostenuto_sw", "on" }); - REQUIRE(region.checkSostenuto); - region.parseOpcode({ "sostenuto_sw", "off" }); - region.parseOpcode({ "sostenuto_sw", "obladi" }); - REQUIRE(region.checkSostenuto); - } - - SECTION("sustain_cc") - { - REQUIRE(region.sustainCC == 64); - region.parseOpcode({ "sustain_cc", "63" }); - REQUIRE(region.sustainCC == 63); - region.parseOpcode({ "sustain_cc", "-1" }); - REQUIRE(region.sustainCC == 0); - } - - SECTION("sustain_lo") - { - REQUIRE(region.sustainThreshold == Approx(0.5_norm).margin(1e-3)); - region.parseOpcode({ "sustain_lo", "-1" }); - REQUIRE(region.sustainThreshold == 0_norm); - region.parseOpcode({ "sustain_lo", "1" }); - REQUIRE(region.sustainThreshold == 1_norm); - region.parseOpcode({ "sustain_lo", "63" }); - REQUIRE(region.sustainThreshold == 63_norm); - region.parseOpcode({ "sustain_lo", "128" }); - REQUIRE(region.sustainThreshold == 127_norm); - } - - SECTION("Filter stacking and cutoffs") - { - REQUIRE(region.filters.empty()); - - region.parseOpcode({ "cutoff", "500" }); - REQUIRE(region.filters.size() == 1); - REQUIRE(region.filters[0].cutoff == 500.0f); - // Check filter defaults - REQUIRE(region.filters[0].keycenter == 60); - REQUIRE(region.filters[0].type == FilterType::kFilterLpf2p); - REQUIRE(region.filters[0].keytrack == 0); - REQUIRE(region.filters[0].gain == 0); - REQUIRE(region.filters[0].veltrack == 0); - REQUIRE(region.filters[0].resonance == 0.0f); - - region.parseOpcode({ "cutoff2", "5000" }); - REQUIRE(region.filters.size() == 2); - REQUIRE(region.filters[1].cutoff == 5000.0f); - // Check filter defaults - REQUIRE(region.filters[1].keycenter == 60); - REQUIRE(region.filters[1].type == FilterType::kFilterLpf2p); - REQUIRE(region.filters[1].keytrack == 0); - REQUIRE(region.filters[1].gain == 0); - REQUIRE(region.filters[1].veltrack == 0); - REQUIRE(region.filters[1].resonance == 0.0f); - - region.parseOpcode({ "cutoff4", "50" }); - REQUIRE(region.filters.size() == 4); - REQUIRE(region.filters[2].cutoff == 0.0f); - REQUIRE(region.filters[3].cutoff == 50.0f); - // Check filter defaults - REQUIRE(region.filters[2].keycenter == 60); - REQUIRE(region.filters[2].type == FilterType::kFilterLpf2p); - REQUIRE(region.filters[2].keytrack == 0); - REQUIRE(region.filters[2].gain == 0); - REQUIRE(region.filters[2].veltrack == 0); - REQUIRE(region.filters[2].resonance == 0.0f); - REQUIRE(region.filters[3].keycenter == 60); - REQUIRE(region.filters[3].type == FilterType::kFilterLpf2p); - REQUIRE(region.filters[3].keytrack == 0); - REQUIRE(region.filters[3].gain == 0); - REQUIRE(region.filters[3].veltrack == 0); - REQUIRE(region.filters[3].resonance == 0.0f); - } - - SECTION("Filter parameter dispatch") - { - region.parseOpcode({ "cutoff3", "50" }); - REQUIRE(region.filters.size() == 3); - REQUIRE(region.filters[2].cutoff == 50.0f); - region.parseOpcode({ "resonance2", "3" }); - REQUIRE(region.filters[1].resonance == 3.0f); - region.parseOpcode({ "fil2_gain", "-5" }); - REQUIRE(region.filters[1].gain == -5.0f); - region.parseOpcode({ "fil_gain", "5" }); - REQUIRE(region.filters[0].gain == 5.0f); - region.parseOpcode({ "fil1_gain", "-5" }); - REQUIRE(region.filters[0].gain == -5.0f); - region.parseOpcode({ "fil2_veltrack", "-100" }); - REQUIRE(region.filters[1].veltrack == -100); - region.parseOpcode({ "fil3_keytrack", "100" }); - REQUIRE(region.filters[2].keytrack == 100); - - } - - SECTION("Filter values") - { - REQUIRE(region.filters.empty()); - - region.parseOpcode({ "cutoff", "500" }); - REQUIRE(region.filters.size() == 1); - REQUIRE(region.filters[0].cutoff == 500.0f); - region.parseOpcode({ "cutoff", "-100" }); - REQUIRE(region.filters[0].cutoff == 0.0f); - region.parseOpcode({ "cutoff", "2000000" }); - REQUIRE(region.filters[0].cutoff == 20000.0f); - - REQUIRE(region.filters[0].resonance == 0.0f); - region.parseOpcode({ "resonance", "5" }); - REQUIRE(region.filters[0].resonance == 5.0f); - region.parseOpcode({ "resonance", "-5" }); - REQUIRE(region.filters[0].resonance == 0.0f); - region.parseOpcode({ "resonance", "500" }); - REQUIRE(region.filters[0].resonance == 96.0f); - - REQUIRE(region.filters[0].veltrack == 0); - region.parseOpcode({ "fil_veltrack", "50" }); - REQUIRE(region.filters[0].veltrack == 50); - region.parseOpcode({ "fil_veltrack", "-5" }); - REQUIRE(region.filters[0].veltrack == -5); - region.parseOpcode({ "fil_veltrack", "13000" }); - REQUIRE(region.filters[0].veltrack == 12000); - region.parseOpcode({ "fil_veltrack", "-13000" }); - REQUIRE(region.filters[0].veltrack == -12000); - - REQUIRE(region.filters[0].keycenter == 60); - region.parseOpcode({ "fil_keycenter", "50" }); - REQUIRE(region.filters[0].keycenter == 50); - region.parseOpcode({ "fil_keycenter", "-2" }); - REQUIRE(region.filters[0].keycenter == 0); - region.parseOpcode({ "fil_keycenter", "1000" }); - REQUIRE(region.filters[0].keycenter == 127); - region.parseOpcode({ "fil_keycenter", "c4" }); - REQUIRE(region.filters[0].keycenter == 60); - - region.parseOpcode({ "fil_gain", "250" }); - REQUIRE(region.filters[0].gain == 96.0f); - region.parseOpcode({ "fil_gain", "-200" }); - REQUIRE(region.filters[0].gain == -96.0f); - } - - SECTION("Filter types") - { - REQUIRE(region.filters.empty()); - - region.parseOpcode({ "fil_type", "lpf_1p" }); - REQUIRE(region.filters.size() == 1); - REQUIRE(region.filters[0].type == FilterType::kFilterLpf1p); - region.parseOpcode({ "fil_type", "lpf_2p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterLpf2p); - region.parseOpcode({ "fil_type", "hpf_1p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterHpf1p); - region.parseOpcode({ "fil_type", "hpf_2p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterHpf2p); - region.parseOpcode({ "fil_type", "bpf_2p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterBpf2p); - region.parseOpcode({ "fil_type", "brf_2p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterBrf2p); - region.parseOpcode({ "fil_type", "bpf_1p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterBpf1p); - region.parseOpcode({ "fil_type", "brf_1p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterBrf1p); - region.parseOpcode({ "fil_type", "apf_1p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterApf1p); - region.parseOpcode({ "fil_type", "lpf_2p_sv" }); - REQUIRE(region.filters[0].type == FilterType::kFilterLpf2pSv); - region.parseOpcode({ "fil_type", "hpf_2p_sv" }); - REQUIRE(region.filters[0].type == FilterType::kFilterHpf2pSv); - region.parseOpcode({ "fil_type", "bpf_2p_sv" }); - REQUIRE(region.filters[0].type == FilterType::kFilterBpf2pSv); - region.parseOpcode({ "fil_type", "brf_2p_sv" }); - REQUIRE(region.filters[0].type == FilterType::kFilterBrf2pSv); - region.parseOpcode({ "fil_type", "lpf_4p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterLpf4p); - region.parseOpcode({ "fil_type", "hpf_4p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterHpf4p); - region.parseOpcode({ "fil_type", "lpf_6p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterLpf6p); - region.parseOpcode({ "fil_type", "hpf_6p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterHpf6p); - region.parseOpcode({ "fil_type", "pink" }); - REQUIRE(region.filters[0].type == FilterType::kFilterPink); - region.parseOpcode({ "fil_type", "lsh" }); - REQUIRE(region.filters[0].type == FilterType::kFilterLsh); - region.parseOpcode({ "fil_type", "hsh" }); - REQUIRE(region.filters[0].type == FilterType::kFilterHsh); - region.parseOpcode({ "fil_type", "peq" }); - REQUIRE(region.filters[0].type == FilterType::kFilterPeq); - region.parseOpcode({ "fil_type", "lpf_1p" }); - region.parseOpcode({ "fil_type", "pkf_2p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterPeq); - region.parseOpcode({ "fil_type", "lpf_1p" }); - region.parseOpcode({ "fil_type", "bpk_2p" }); - REQUIRE(region.filters[0].type == FilterType::kFilterPeq); - region.parseOpcode({ "fil_type", "unknown" }); - REQUIRE(region.filters[0].type == FilterType::kFilterNone); - } - - SECTION("EQ stacking and gains") - { - REQUIRE(region.equalizers.empty()); - - region.parseOpcode({ "eq1_gain", "6" }); - REQUIRE(region.equalizers.size() == 1); - REQUIRE(region.equalizers[0].gain == 6.0f); - // Check defaults - REQUIRE(region.equalizers[0].type == EqType::kEqPeak); - REQUIRE(region.equalizers[0].bandwidth == 1.0f); - REQUIRE(region.equalizers[0].frequency == 0.0f); - REQUIRE(region.equalizers[0].vel2frequency == 0); - REQUIRE(region.equalizers[0].vel2gain == 0); - - region.parseOpcode({ "eq2_gain", "-400" }); - REQUIRE(region.equalizers.size() == 2); - REQUIRE(region.equalizers[1].gain == -96.0f); - // Check defaults - REQUIRE(region.equalizers[1].type == EqType::kEqPeak); - REQUIRE(region.equalizers[1].bandwidth == 1.0f); - REQUIRE(region.equalizers[1].frequency == 0.0f); - REQUIRE(region.equalizers[1].vel2frequency == 0); - REQUIRE(region.equalizers[1].vel2gain == 0); - - region.parseOpcode({ "eq4_gain", "500" }); - REQUIRE(region.equalizers.size() == 4); - REQUIRE(region.equalizers[2].gain == 0.0f); - REQUIRE(region.equalizers[3].type == EqType::kEqPeak); - REQUIRE(region.equalizers[3].gain == 96.0f); - // Check defaults - REQUIRE(region.equalizers[2].bandwidth == 1.0f); - REQUIRE(region.equalizers[2].frequency == 0.0f); - REQUIRE(region.equalizers[2].vel2frequency == 0); - REQUIRE(region.equalizers[2].vel2gain == 0); - REQUIRE(region.equalizers[3].bandwidth == 1.0f); - REQUIRE(region.equalizers[3].frequency == 0.0f); - REQUIRE(region.equalizers[3].vel2frequency == 0); - REQUIRE(region.equalizers[3].vel2gain == 0); - } - - SECTION("EQ types") - { - region.parseOpcode({ "eq1_type", "hshelf" }); - REQUIRE(region.equalizers[0].type == EqType::kEqHighShelf); - region.parseOpcode({ "eq1_type", "somethingsomething" }); - REQUIRE(region.equalizers[0].type == EqType::kEqNone); - region.parseOpcode({ "eq1_type", "lshelf" }); - REQUIRE(region.equalizers[0].type == EqType::kEqLowShelf); - region.parseOpcode({ "eq1_type", "peak" }); - REQUIRE(region.equalizers[0].type == EqType::kEqPeak); - } - - SECTION("EQ parameter dispatch") - { - region.parseOpcode({ "eq3_bw", "2" }); - REQUIRE(region.equalizers.size() == 3); - REQUIRE(region.equalizers[2].bandwidth == 2.0f); - region.parseOpcode({ "eq1_gain", "-25" }); - REQUIRE(region.equalizers[0].gain == -25.0f); - region.parseOpcode({ "eq2_freq", "300" }); - REQUIRE(region.equalizers[1].frequency == 300.0f); - region.parseOpcode({ "eq3_type", "lshelf" }); - REQUIRE(region.equalizers[2].type == EqType::kEqLowShelf); - region.parseOpcode({ "eq3_vel2gain", "10" }); - REQUIRE(region.equalizers[2].vel2gain == 10.0f); - region.parseOpcode({ "eq1_vel2freq", "100" }); - REQUIRE(region.equalizers[0].vel2frequency == 100.0f); - region.parseOpcode({ "eq1_type", "hshelf" }); - REQUIRE(region.equalizers[0].type == EqType::kEqHighShelf); - } - - SECTION("EQ parameter values") - { - region.parseOpcode({ "eq1_bw", "2" }); - REQUIRE(region.equalizers.size() == 1); - REQUIRE(region.equalizers[0].bandwidth == 2.0f); - region.parseOpcode({ "eq1_bw", "5" }); - REQUIRE(region.equalizers[0].bandwidth == 4.0f); - region.parseOpcode({ "eq1_bw", "0" }); - REQUIRE(region.equalizers[0].bandwidth == 0.001f); - region.parseOpcode({ "eq1_freq", "300" }); - REQUIRE(region.equalizers[0].frequency == 300.0f); - region.parseOpcode({ "eq1_freq", "-300" }); - REQUIRE(region.equalizers[0].frequency == 0.0f); - region.parseOpcode({ "eq1_freq", "35000" }); - REQUIRE(region.equalizers[0].frequency == 30000.0f); - region.parseOpcode({ "eq1_vel2gain", "4" }); - REQUIRE(region.equalizers[0].vel2gain == 4.0f); - region.parseOpcode({ "eq1_vel2gain", "250" }); - REQUIRE(region.equalizers[0].vel2gain == 96.0f); - region.parseOpcode({ "eq1_vel2gain", "-123" }); - REQUIRE(region.equalizers[0].vel2gain == -96.0f); - region.parseOpcode({ "eq1_vel2freq", "40" }); - REQUIRE(region.equalizers[0].vel2frequency == 40.0f); - region.parseOpcode({ "eq1_vel2freq", "35000" }); - REQUIRE(region.equalizers[0].vel2frequency == 30000.0f); - region.parseOpcode({ "eq1_vel2freq", "-35000" }); - REQUIRE(region.equalizers[0].vel2frequency == -30000.0f); - } - - SECTION("Effects send") - { - REQUIRE(region.gainToEffect.size() == 1); - REQUIRE(region.gainToEffect[0] == 1.0f); - region.parseOpcode({ "effect1", "50.4" }); - REQUIRE(region.gainToEffect.size() == 2); - REQUIRE(region.gainToEffect[1] == 0.504f); - region.parseOpcode({ "effect3", "100" }); - REQUIRE(region.gainToEffect.size() == 4); - REQUIRE(region.gainToEffect[2] == 0.0f); - REQUIRE(region.gainToEffect[3] == 1.0f); - region.parseOpcode({ "effect3", "150.1" }); - REQUIRE(region.gainToEffect[3] == 1.0f); - region.parseOpcode({ "effect3", "-50.65" }); - REQUIRE(region.gainToEffect[3] == 0.0f); - } - - SECTION("Wavetable phase") - { - REQUIRE(region.oscillatorPhase == 0.0f); - region.parseOpcode({ "oscillator_phase", "0.25" }); - REQUIRE(region.oscillatorPhase == 0.25f); - region.parseOpcode({ "oscillator_phase", "0.3" }); - REQUIRE(region.oscillatorPhase == 0.3_a); - region.parseOpcode({ "oscillator_phase", "-1" }); - REQUIRE(region.oscillatorPhase == -1.0f); - region.parseOpcode({ "oscillator_phase", "1.1" }); - REQUIRE(region.oscillatorPhase == 0.0f); - } - - SECTION("Note polyphony") - { - REQUIRE(!region.notePolyphony); - region.parseOpcode({ "note_polyphony", "45" }); - REQUIRE(region.notePolyphony); - REQUIRE(*region.notePolyphony == 45); - region.parseOpcode({ "note_polyphony", "-1" }); - REQUIRE(region.notePolyphony); - REQUIRE(*region.notePolyphony == 0); - } - - SECTION("Note selfmask") - { - REQUIRE(region.selfMask == SfzSelfMask::mask); - region.parseOpcode({ "note_selfmask", "off" }); - REQUIRE(region.selfMask == SfzSelfMask::dontMask); - region.parseOpcode({ "note_selfmask", "on" }); - REQUIRE(region.selfMask == SfzSelfMask::mask); - region.parseOpcode({ "note_selfmask", "off" }); - region.parseOpcode({ "note_selfmask", "garbage" }); - REQUIRE(region.selfMask == SfzSelfMask::dontMask); - } - - SECTION("Release dead") - { - REQUIRE(region.rtDead == false); - region.parseOpcode({ "rt_dead", "on" }); - REQUIRE(region.rtDead == true); - region.parseOpcode({ "rt_dead", "off" }); - REQUIRE(region.rtDead == false); - region.parseOpcode({ "rt_dead", "on" }); - region.parseOpcode({ "rt_dead", "garbage" }); - REQUIRE(region.rtDead == true); - } - - SECTION("amplitude") - { - REQUIRE(region.amplitude == 1.0_a); - region.parseOpcode({ "amplitude", "40" }); - REQUIRE(region.amplitude == 0.4_a); - region.parseOpcode({ "amplitude", "-40" }); - REQUIRE(region.amplitude == 0_a); - region.parseOpcode({ "amplitude", "140" }); - REQUIRE(region.amplitude == 1.4_a); - } - - SECTION("amplitude_cc") - { - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, region.getId()); - const RegionCCView view(region, target); - REQUIRE(view.empty()); - region.parseOpcode({ "amplitude_cc1", "40" }); - REQUIRE(view.valueAt(1) == 40.0_a); - region.parseOpcode({ "amplitude_oncc2", "30" }); - REQUIRE(view.valueAt(2) == 30.0_a); - region.parseOpcode({ "amplitude_curvecc17", "18" }); - REQUIRE(view.at(17).curve == 18); - region.parseOpcode({ "amplitude_curvecc17", "15482" }); - REQUIRE(view.at(17).curve == 255); - region.parseOpcode({ "amplitude_curvecc17", "-2" }); - REQUIRE(view.at(17).curve == 0); - region.parseOpcode({ "amplitude_smoothcc14", "85" }); - REQUIRE(view.at(14).smooth == 85); - region.parseOpcode({ "amplitude_smoothcc14", "15482" }); - REQUIRE(view.at(14).smooth == 100); - region.parseOpcode({ "amplitude_smoothcc14", "-2" }); - REQUIRE(view.at(14).smooth == 0); - region.parseOpcode({ "amplitude_stepcc120", "24" }); - REQUIRE(view.at(120).step == 24.0_a); - region.parseOpcode({ "amplitude_stepcc120", "15482" }); - REQUIRE(view.at(120).step == 15482.0_a); - region.parseOpcode({ "amplitude_stepcc120", "-2" }); - REQUIRE(view.at(120).step == 0.0f); - } - - SECTION("volume_oncc/gain_cc") - { - const ModKey target = ModKey::createNXYZ(ModId::Volume, region.getId()); - const RegionCCView view(region, target); - REQUIRE(view.empty()); - region.parseOpcode({ "gain_cc1", "40" }); - REQUIRE(view.valueAt(1) == 40_a); - region.parseOpcode({ "volume_oncc2", "-76" }); - REQUIRE(view.valueAt(2) == -76.0_a); - region.parseOpcode({ "gain_oncc4", "-1" }); - REQUIRE(view.valueAt(4) == -1.0_a); - region.parseOpcode({ "volume_curvecc17", "18" }); - REQUIRE(view.at(17).curve == 18); - region.parseOpcode({ "volume_curvecc17", "15482" }); - REQUIRE(view.at(17).curve == 255); - region.parseOpcode({ "volume_curvecc17", "-2" }); - REQUIRE(view.at(17).curve == 0); - region.parseOpcode({ "volume_smoothcc14", "85" }); - REQUIRE(view.at(14).smooth == 85); - region.parseOpcode({ "volume_smoothcc14", "15482" }); - REQUIRE(view.at(14).smooth == 100); - region.parseOpcode({ "volume_smoothcc14", "-2" }); - REQUIRE(view.at(14).smooth == 0); - region.parseOpcode({ "volume_stepcc120", "24" }); - REQUIRE(view.at(120).step == 24.0f); - region.parseOpcode({ "volume_stepcc120", "15482" }); - REQUIRE(view.at(120).step == 144.0f); - region.parseOpcode({ "volume_stepcc120", "-2" }); - REQUIRE(view.at(120).step == 0.0f); - } - - SECTION("tune_cc/pitch_cc") - { - const ModKey target = ModKey::createNXYZ(ModId::Pitch, region.getId()); - const RegionCCView view(region, target); - REQUIRE(view.empty()); - region.parseOpcode({ "pitch_cc1", "40" }); - REQUIRE(view.valueAt(1) == 40.0); - region.parseOpcode({ "tune_oncc2", "-76" }); - REQUIRE(view.valueAt(2) == -76.0); - region.parseOpcode({ "pitch_oncc4", "-1" }); - REQUIRE(view.valueAt(4) == -1.0); - region.parseOpcode({ "tune_curvecc17", "18" }); - REQUIRE(view.at(17).curve == 18); - region.parseOpcode({ "pitch_curvecc17", "15482" }); - REQUIRE(view.at(17).curve == 255); - region.parseOpcode({ "tune_curvecc17", "-2" }); - REQUIRE(view.at(17).curve == 0); - region.parseOpcode({ "pitch_smoothcc14", "85" }); - REQUIRE(view.at(14).smooth == 85); - region.parseOpcode({ "tune_smoothcc14", "15482" }); - REQUIRE(view.at(14).smooth == 100); - region.parseOpcode({ "pitch_smoothcc14", "-2" }); - REQUIRE(view.at(14).smooth == 0); - region.parseOpcode({ "tune_stepcc120", "24" }); - REQUIRE(view.at(120).step == 24.0f); - region.parseOpcode({ "pitch_stepcc120", "15482" }); - REQUIRE(view.at(120).step == 12000.0f); - region.parseOpcode({ "tune_stepcc120", "-2" }); - REQUIRE(view.at(120).step == 0.0f); - } -} - -// Specific region bugs -TEST_CASE("[Region] Non-conforming floating point values in integer opcodes") -{ - MidiState midiState; - Region region { 0, midiState }; - region.parseOpcode({ "offset", "2014.5" }); - REQUIRE(region.offset == 2014); - region.parseOpcode({ "pitch_keytrack", "-2.1" }); - REQUIRE(region.pitchKeytrack == -2); -} - - -TEST_CASE("[Region] Release and release key") -{ - MidiState midiState; - Region region { 0, midiState }; - region.parseOpcode({ "lokey", "63" }); - region.parseOpcode({ "hikey", "65" }); - region.parseOpcode({ "sample", "*sine" }); - SECTION("Release key without sustain") - { - region.parseOpcode({ "trigger", "release_key" }); - midiState.ccEvent(0, 64, 0.0f); - REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); - REQUIRE( region.registerNoteOff(63, 0.5f, 0.0f) ); - } - SECTION("Release key with sustain") - { - region.parseOpcode({ "trigger", "release_key" }); - midiState.ccEvent(0, 64, 1.0f); - REQUIRE( !region.registerCC(64, 1.0f) ); - REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); - REQUIRE( region.registerNoteOff(63, 0.5f, 0.0f) ); - } - - SECTION("Release without sustain") - { - region.parseOpcode({ "trigger", "release" }); - midiState.ccEvent(0, 64, 0.0f); - REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); - REQUIRE( region.registerNoteOff(63, 0.5f, 0.0f) ); - } - - SECTION("Release with sustain") - { - region.parseOpcode({ "trigger", "release" }); - midiState.ccEvent(0, 64, 1.0f); - midiState.noteOnEvent(0, 63, 0.5f); - REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); - REQUIRE( !region.registerNoteOff(63, 0.5f, 0.0f) ); - REQUIRE( region.delayedReleases.size() == 1 ); - std::vector> expected = { - { 63, 0.5f } - }; - REQUIRE( region.delayedReleases == expected ); - } - - SECTION("Release with sustain and 2 notes") - { - region.parseOpcode({ "trigger", "release" }); - midiState.ccEvent(0, 64, 1.0f); - midiState.noteOnEvent(0, 63, 0.5f); - REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); - midiState.noteOnEvent(0, 64, 0.6f); - REQUIRE( !region.registerNoteOn(64, 0.6f, 0.0f) ); - REQUIRE( !region.registerNoteOff(63, 0.0f, 0.0f) ); - REQUIRE( !region.registerNoteOff(64, 0.2f, 0.0f) ); - REQUIRE( region.delayedReleases.size() == 2 ); - std::vector> expected = { - { 63, 0.5f }, - { 64, 0.6f } - }; - REQUIRE( region.delayedReleases == expected ); - } - - SECTION("Release with sustain and 2 notes but 1 outside") - { - region.parseOpcode({ "trigger", "release" }); - midiState.ccEvent(0, 64, 1.0f); - midiState.noteOnEvent(0, 63, 0.5f); - REQUIRE( !region.registerNoteOn(63, 0.5f, 0.0f) ); - midiState.noteOnEvent(0, 66, 0.6f); - REQUIRE( !region.registerNoteOn(66, 0.6f, 0.0f) ); - REQUIRE( !region.registerNoteOff(63, 0.0f, 0.0f) ); - REQUIRE( !region.registerNoteOff(66, 0.2f, 0.0f) ); - REQUIRE( region.delayedReleases.size() == 1 ); - std::vector> expected = { - { 63, 0.5f } - }; - REQUIRE( region.delayedReleases == expected ); - } -} - -TEST_CASE("[Region] Offsets with CCs") -{ - MidiState midiState; - Region region { 0, midiState }; - - region.parseOpcode({ "offset_cc4", "255" }); - region.parseOpcode({ "offset", "10" }); - REQUIRE( region.getOffset() == 10 ); - midiState.ccEvent(0, 4, 127_norm); - REQUIRE( region.getOffset() == 265 ); - midiState.ccEvent(0, 4, 100_norm); - REQUIRE( region.getOffset() == 210 ); - midiState.ccEvent(0, 4, 10_norm); - REQUIRE( region.getOffset() == 30 ); - midiState.ccEvent(0, 4, 0); - REQUIRE( region.getOffset() == 10 ); -} - -TEST_CASE("[Region] Pitch variation with veltrack") -{ - MidiState midiState; - Region region { 0, midiState }; - - REQUIRE(region.getBasePitchVariation(60.0, 0_norm) == 1.0); - REQUIRE(region.getBasePitchVariation(60.0, 64_norm) == 1.0); - REQUIRE(region.getBasePitchVariation(60.0, 127_norm) == 1.0); - region.parseOpcode({ "pitch_veltrack", "1200" }); - REQUIRE(region.getBasePitchVariation(60.0, 0_norm) == 1.0); - REQUIRE(region.getBasePitchVariation(60.0, 64_norm) == Approx(centsFactor(600.0)).margin(0.01f)); - REQUIRE(region.getBasePitchVariation(60.0, 127_norm) == Approx(centsFactor(1200.0)).margin(0.01f)); -} diff --git a/tests/RegionValueComputationsT.cpp b/tests/RegionValueComputationsT.cpp index 3b2d3e32..60937f3d 100644 --- a/tests/RegionValueComputationsT.cpp +++ b/tests/RegionValueComputationsT.cpp @@ -6,17 +6,20 @@ #include "sfizz/Defaults.h" #include "sfizz/Region.h" +#include "sfizz/MidiState.h" #include "sfizz/SfzHelpers.h" #include "catch2/catch.hpp" #include #include using namespace Catch::literals; using namespace sfz::literals; +using namespace sfz; constexpr int numRandomTests { 64 }; + TEST_CASE("[Region] Crossfade in on key") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lokey", "1" }); region.parseOpcode({ "xfin_hikey", "3" }); @@ -27,8 +30,8 @@ TEST_CASE("[Region] Crossfade in on key") TEST_CASE("[Region] Crossfade in on key - 2") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lokey", "1" }); region.parseOpcode({ "xfin_hikey", "5" }); @@ -42,8 +45,8 @@ TEST_CASE("[Region] Crossfade in on key - 2") TEST_CASE("[Region] Crossfade in on key - gain") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lokey", "1" }); region.parseOpcode({ "xfin_hikey", "5" }); @@ -57,8 +60,8 @@ TEST_CASE("[Region] Crossfade in on key - gain") TEST_CASE("[Region] Crossfade out on key") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_lokey", "51" }); region.parseOpcode({ "xfout_hikey", "55" }); @@ -73,8 +76,8 @@ TEST_CASE("[Region] Crossfade out on key") TEST_CASE("[Region] Crossfade out on key - gain") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_lokey", "51" }); region.parseOpcode({ "xfout_hikey", "55" }); @@ -90,8 +93,8 @@ TEST_CASE("[Region] Crossfade out on key - gain") TEST_CASE("[Region] Crossfade in on velocity") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lovel", "20" }); region.parseOpcode({ "xfin_hivel", "24" }); @@ -107,8 +110,8 @@ TEST_CASE("[Region] Crossfade in on velocity") TEST_CASE("[Region] Crossfade in on vel - gain") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lovel", "20" }); region.parseOpcode({ "xfin_hivel", "24" }); @@ -125,8 +128,8 @@ TEST_CASE("[Region] Crossfade in on vel - gain") TEST_CASE("[Region] Crossfade out on vel") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_lovel", "51" }); region.parseOpcode({ "xfout_hivel", "55" }); @@ -142,8 +145,8 @@ TEST_CASE("[Region] Crossfade out on vel") TEST_CASE("[Region] Crossfade out on vel - gain") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_lovel", "51" }); region.parseOpcode({ "xfout_hivel", "55" }); @@ -160,8 +163,8 @@ TEST_CASE("[Region] Crossfade out on vel - gain") TEST_CASE("[Region] Crossfade in on CC") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_locc24", "20" }); region.parseOpcode({ "xfin_hicc24", "24" }); @@ -184,8 +187,8 @@ TEST_CASE("[Region] Crossfade in on CC") TEST_CASE("[Region] Crossfade in on CC - gain") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_locc24", "20" }); region.parseOpcode({ "xfin_hicc24", "24" }); @@ -208,8 +211,8 @@ TEST_CASE("[Region] Crossfade in on CC - gain") } TEST_CASE("[Region] Crossfade out on CC") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_locc24", "20" }); region.parseOpcode({ "xfout_hicc24", "24" }); @@ -232,8 +235,8 @@ TEST_CASE("[Region] Crossfade out on CC") TEST_CASE("[Region] Crossfade out on CC - gain") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_locc24", "20" }); region.parseOpcode({ "xfout_hicc24", "24" }); @@ -257,8 +260,8 @@ TEST_CASE("[Region] Crossfade out on CC - gain") TEST_CASE("[Region] Velocity bug for extreme values - veltrack at 0") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "amp_veltrack", "0" }); REQUIRE(region.getNoteGain(64, 127_norm) == 1.0_a); @@ -268,8 +271,8 @@ TEST_CASE("[Region] Velocity bug for extreme values - veltrack at 0") TEST_CASE("[Region] Velocity bug for extreme values - positive veltrack") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "amp_veltrack", "100" }); REQUIRE(region.getNoteGain(64, 127_norm) == 1.0_a); @@ -278,8 +281,8 @@ TEST_CASE("[Region] Velocity bug for extreme values - positive veltrack") TEST_CASE("[Region] Velocity bug for extreme values - negative veltrack") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "amp_veltrack", "-100" }); REQUIRE(region.getNoteGain(64, 127_norm) == Approx(0.0).margin(0.0001)); @@ -288,29 +291,29 @@ TEST_CASE("[Region] Velocity bug for extreme values - negative veltrack") TEST_CASE("[Region] rt_decay") { - sfz::MidiState midiState; + MidiState midiState; midiState.setSampleRate(1000); - sfz::Region region { 0, midiState }; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "trigger", "release" }); region.parseOpcode({ "rt_decay", "10" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume - 1.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 1.0f).margin(0.1) ); region.parseOpcode({ "rt_decay", "20" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume - 2.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 2.0f).margin(0.1) ); region.parseOpcode({ "trigger", "attack" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume).margin(0.1) ); } TEST_CASE("[Region] Base delay") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "delay", "10" }); REQUIRE( region.getDelay() == 10.0f ); @@ -322,3 +325,36 @@ TEST_CASE("[Region] Base delay") REQUIRE( (delay >= 10.0 && delay <= 20.0) ); } } + +TEST_CASE("[Region] Offsets with CCs") +{ + MidiState midiState; + Region region { 0, midiState }; + + region.parseOpcode({ "offset_cc4", "255" }); + region.parseOpcode({ "offset", "10" }); + REQUIRE( region.getOffset() == 10 ); + midiState.ccEvent(0, 4, 127_norm); + REQUIRE( region.getOffset() == 265 ); + midiState.ccEvent(0, 4, 100_norm); + REQUIRE( region.getOffset() == 210 ); + midiState.ccEvent(0, 4, 10_norm); + REQUIRE( region.getOffset() == 30 ); + midiState.ccEvent(0, 4, 0); + REQUIRE( region.getOffset() == 10 ); +} + +TEST_CASE("[Region] Pitch variation with veltrack") +{ + MidiState midiState; + Region region { 0, midiState }; + + REQUIRE(region.getBasePitchVariation(60.0, 0_norm) == 1.0); + REQUIRE(region.getBasePitchVariation(60.0, 64_norm) == 1.0); + REQUIRE(region.getBasePitchVariation(60.0, 127_norm) == 1.0); + region.parseOpcode({ "pitch_veltrack", "1200" }); + REQUIRE(region.getBasePitchVariation(60.0, 0_norm) == 1.0); + REQUIRE(region.getBasePitchVariation(60.0, 64_norm) == Approx(centsFactor(600.0)).margin(0.01f)); + REQUIRE(region.getBasePitchVariation(60.0, 127_norm) == Approx(centsFactor(1200.0)).margin(0.01f)); +} + diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp new file mode 100644 index 00000000..f0274fd1 --- /dev/null +++ b/tests/RegionValuesT.cpp @@ -0,0 +1,3033 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "TestHelpers.h" +#include "sfizz/Synth.h" +#include "sfizz/Messaging.h" +#include "catch2/catch.hpp" +#include +#include +#include +using namespace Catch::literals; +using namespace sfz; + +void simpleMessageReceiver(void* data, int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + (void)delay; + auto& messageList = *reinterpret_cast*>(data); + + std::string newMessage = absl::StrCat(path, ",", sig, " : { "); + for (unsigned i = 0, n = strlen(sig); i < n; ++i) { + switch(sig[i]){ + case 'i': + absl::StrAppend(&newMessage, args[i].i); + break; + case 'f': + absl::StrAppend(&newMessage, args[i].f); + break; + case 'd': + absl::StrAppend(&newMessage, args[i].d); + break; + case 'h': + absl::StrAppend(&newMessage, args[i].h); + break; + case 's': + absl::StrAppend(&newMessage, args[i].s); + break; + } + + if (i == (n - 1)) + absl::StrAppend(&newMessage, " }"); + else + absl::StrAppend(&newMessage, ", "); + } + + messageList.push_back(std::move(newMessage)); +} + +TEST_CASE("[Values] Delay") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=*sine + sample=*sine delay=1 + sample=*sine delay=-1 + sample=*sine delay=1 delay=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/delay", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/delay", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/delay", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region3/delay", "", nullptr); + std::vector expected { + "/region0/delay,f : { 0 }", + "/region1/delay,f : { 1 }", + "/region2/delay,f : { 0 }", + // TODO: activate for the new region parser ; ignore the second value + // "/region3/delay,f : { 1 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Random") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=*sine + sample=*sine delay_random=1 + sample=*sine delay_random=-1 + sample=*sine delay_random=1 delay_random=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/delay_random", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/delay_random", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/delay_random", "", nullptr); + // synth.dispatchMessage(client, 0, "/region3/delay_random", "", nullptr); + std::vector expected { + "/region0/delay_random,f : { 0 }", + "/region1/delay_random,f : { 1 }", + "/region2/delay_random,f : { 0 }", + // "/region3/delay_random,f : { 1 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Sample and direction") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=*sine + sample=kick.wav + sample=kick.wav direction=reverse + )"); + synth.dispatchMessage(client, 0, "/region0/sample", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sample", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/direction", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/direction", "", nullptr); + std::vector expected { + "/region0/sample,s : { *sine }", + "/region1/sample,s : { kick.wav }", + "/region1/direction,s : { forward }", + "/region2/direction,s : { reverse }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Offset") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav offset=12 + sample=kick.wav offset=-1 + sample=kick.wav offset=12 offset=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/offset", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/offset", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/offset", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region3/offset", "", nullptr); + std::vector expected { + "/region0/offset,h : { 0 }", + "/region1/offset,h : { 12 }", + "/region2/offset,h : { 0 }", + // TODO: activate for the new region parser ; ignore the second value + // "/region3/offset,f : { 12 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Random") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav offset_random=1 + sample=kick.wav offset_random=-1 + sample=kick.wav offset_random=1 offset_random=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/offset_random", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/offset_random", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/offset_random", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region3/offset_random", "", nullptr); + std::vector expected { + "/region0/offset_random,h : { 0 }", + "/region1/offset_random,h : { 1 }", + "/region2/offset_random,h : { 0 }", + // "/region3/offset_random,f : { 1 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav offset_cc12=12 + sample=kick.wav offset_cc12=-12 + sample=kick.wav offset_cc14=14 offset_cc12=12 offset_cc12=-12 + )"); + synth.dispatchMessage(client, 0, "/region0/offset_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/offset_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/offset_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/offset_cc14", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region3/offset_cc12", "", nullptr); + std::vector expected { + "/region0/offset_cc12,h : { 0 }", + "/region1/offset_cc12,h : { 12 }", + "/region2/offset_cc12,h : { 0 }", + "/region3/offset_cc14,h : { 14 }", + // "/region3/offset_cc12,h : { 12 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] End") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav end=194 + sample=kick.wav end=-1 + sample=kick.wav end=0 + sample=kick.wav end=194 end=-1 + sample=kick.wav end=0 end=194 + )"); + synth.dispatchMessage(client, 0, "/region0/end", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/enabled", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/enabled", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/enabled", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/enabled", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/enabled", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/end", "", nullptr); + std::vector expected { + "/region0/end,h : { 194 }", + "/region0/enabled,T : { }", + "/region1/enabled,F : { }", + "/region2/enabled,F : { }", + "/region3/enabled,F : { }", + "/region4/enabled,T : { }", + "/region4/end,h : { 194 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Count") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav count=2 + sample=kick.wav count=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/count", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/count", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/count", "", nullptr); + std::vector expected { + "/region0/count,N : { }", + "/region1/count,h : { 2 }", + "/region2/count,h : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Loop mode") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav loop_mode=one_shot + sample=kick.wav loopmode=one_shot + sample=kick.wav loop_mode=loop_sustain + sample=kick.wav loop_mode=loop_continuous + sample=kick.wav loop_mode=loop_continuous loop_mode=no_loop + )"); + synth.dispatchMessage(client, 0, "/region0/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/loop_mode", "", nullptr); + std::vector expected { + "/region0/loop_mode,s : { no_loop }", + "/region1/loop_mode,s : { one_shot }", + "/region2/loop_mode,s : { one_shot }", + "/region3/loop_mode,s : { loop_sustain }", + "/region4/loop_mode,s : { loop_continuous }", + "/region5/loop_mode,s : { no_loop }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Loops") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav loop_mode=one_shot + sample=kick.wav loopmode=one_shot + sample=kick.wav loop_mode=loop_sustain + sample=kick.wav loop_mode=loop_continuous + sample=kick.wav loop_mode=loop_continuous loop_mode=no_loop + )"); + synth.dispatchMessage(client, 0, "/region0/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/loop_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/loop_mode", "", nullptr); + std::vector expected { + "/region0/loop_mode,s : { no_loop }", + "/region1/loop_mode,s : { one_shot }", + "/region2/loop_mode,s : { one_shot }", + "/region3/loop_mode,s : { loop_sustain }", + "/region4/loop_mode,s : { loop_continuous }", + "/region5/loop_mode,s : { no_loop }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Loop range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav loop_start=10 loop_end=100 + sample=kick.wav loopstart=10 loopend=100 + sample=kick.wav loop_start=-1 loopend=-100 + )"); + synth.dispatchMessage(client, 0, "/region0/loop_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/loop_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/loop_range", "", nullptr); + std::vector expected { + "/region0/loop_range,hh : { 10, 100 }", + "/region1/loop_range,hh : { 10, 100 }", + "/region2/loop_range,hh : { 0, 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Loop crossfade") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav loop_crossfade=0.5 + sample=kick.wav loop_crossfade=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/loop_crossfade", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/loop_crossfade", "", nullptr); + std::vector expected { + "/region0/loop_crossfade,f : { 0.5 }", + "/region1/loop_crossfade,f : { 0.001 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Group") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav group=5 + sample=kick.wav group=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/group", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/group", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/group", "", nullptr); + std::vector expected { + "/region0/group,h : { 0 }", + "/region1/group,h : { 5 }", + "/region2/group,h : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Off by") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav off_by=5 + sample=kick.wav off_by=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/off_by", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/off_by", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/off_by", "", nullptr); + std::vector expected { + "/region0/off_by,N : { }", + "/region1/off_by,h : { 5 }", + "/region2/off_by,N : { }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Off mode") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav off_mode=fast + sample=kick.wav off_mode=normal + sample=kick.wav off_mode=time + sample=kick.wav off_mode=time off_mode=normal + sample=kick.wav off_mode=nothing + )"); + synth.dispatchMessage(client, 0, "/region0/off_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/off_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/off_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/off_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/off_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/off_mode", "", nullptr); + std::vector expected { + "/region0/off_mode,s : { fast }", + "/region1/off_mode,s : { fast }", + "/region2/off_mode,s : { normal }", + "/region3/off_mode,s : { time }", + "/region4/off_mode,s : { normal }", + "/region5/off_mode,s : { fast }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Off time") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav off_time=0.1 + sample=kick.wav off_time=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/off_time", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/off_time", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/off_time", "", nullptr); + std::vector expected { + "/region0/off_time,f : { 0.006 }", + "/region1/off_time,f : { 0.1 }", + "/region2/off_time,f : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Key range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav lokey=34 hikey=60 + sample=kick.wav lokey=c4 hikey=b5 + sample=kick.wav lokey=-3 hikey=60 + sample=kick.wav hikey=-1 + sample=kick.wav pitch_keycenter=32 + sample=kick.wav pitch_keycenter=-1 + sample=kick.wav key=26 + )"); + synth.dispatchMessage(client, 0, "/region0/key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/pitch_keycenter", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region6/pitch_keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region7/key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region7/pitch_keycenter", "", nullptr); + std::vector expected { + "/region0/key_range,ii : { 0, 127 }", + "/region1/key_range,ii : { 34, 60 }", + "/region2/key_range,ii : { 60, 83 }", + "/region3/key_range,ii : { 0, 60 }", + "/region4/key_range,ii : { 0, 0 }", + "/region0/pitch_keycenter,i : { 60 }", + "/region5/pitch_keycenter,i : { 32 }", + // "/region6/pitch_keycenter,i : { 60 }", + "/region7/key_range,ii : { 26, 26 }", + "/region7/pitch_keycenter,i : { 26 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Velocity range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav lovel=34 hivel=60 + sample=kick.wav lovel=-3 hivel=60 + sample=kick.wav hivel=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/vel_range", "", nullptr); + std::vector expected { + "/region0/vel_range,ff : { 0, 1 }", + "/region1/vel_range,ff : { 0.267717, 0.472441 }", + "/region2/vel_range,ff : { 0, 0.472441 }", + "/region3/vel_range,ff : { 0, 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Bend range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav lobend=891 hibend=2000 + sample=kick.wav lobend=-891 hibend=891 + sample=kick.wav hibend=-10000 + )"); + synth.dispatchMessage(client, 0, "/region0/bend_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/bend_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/bend_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/bend_range", "", nullptr); + std::vector expected { + "/region0/bend_range,ff : { -1, 1 }", + "/region1/bend_range,ff : { 0.108778, 0.24417 }", + "/region2/bend_range,ff : { -0.108778, 0.108778 }", + "/region3/bend_range,ff : { -1, -1 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] CC condition range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav locc1=0 hicc1=54 + sample=kick.wav locc1=0 hicc1=54 locc2=2 hicc2=10 + sample=kick.wav locc1=10 hicc1=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/cc_range2", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/cc_range1", "", nullptr); + std::vector expected { + "/region0/cc_range1,ff : { 0, 1 }", + "/region1/cc_range1,ff : { 0, 0.425197 }", + "/region2/cc_range1,ff : { 0, 0.425197 }", + "/region2/cc_range2,ff : { 0.015748, 0.0787402 }", + "/region3/cc_range1,ff : { 0, 0 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("hdcc") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav lohdcc1=0 hihdcc1=0.1 + sample=kick.wav lohdcc1=0 hihdcc1=0.1 lohdcc2=0.1 hihdcc2=0.2 + sample=kick.wav lohdcc1=0.1 hihdcc1=-0.1 + )"); + synth.dispatchMessage(client, 0, "/region0/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/cc_range2", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/cc_range1", "", nullptr); + std::vector expected { + "/region0/cc_range1,ff : { 0, 1 }", + "/region1/cc_range1,ff : { 0, 0.1 }", + "/region2/cc_range1,ff : { 0, 0.1 }", + "/region2/cc_range2,ff : { 0.1, 0.2 }", + "/region3/cc_range1,ff : { 0, 0 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("realcc") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav lorealcc1=0 hirealcc1=0.1 + sample=kick.wav lorealcc1=0 hirealcc1=0.1 lorealcc2=0.1 hirealcc2=0.2 + sample=kick.wav lorealcc1=0.1 hirealcc1=-0.1 + )"); + synth.dispatchMessage(client, 0, "/region0/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/cc_range2", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/cc_range1", "", nullptr); + std::vector expected { + "/region0/cc_range1,ff : { 0, 1 }", + "/region1/cc_range1,ff : { 0, 0.1 }", + "/region2/cc_range1,ff : { 0, 0.1 }", + "/region2/cc_range2,ff : { 0.1, 0.2 }", + "/region3/cc_range1,ff : { 0, 0 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Last keyswitch") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sw_last=12 + sample=kick.wav sw_last=c4 + sample=kick.wav sw_lolast=14 sw_hilast=16 + sample=kick.wav sw_lolast=c4 sw_hilast=b5 + sample=kick.wav sw_last=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/sw_last", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sw_last", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sw_last", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sw_last", "", nullptr); + // TODO: activate for the new region parser ; can handle note names + // synth.dispatchMessage(client, 0, "/region4/sw_last", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region5/sw_last", "", nullptr); + std::vector expected { + "/region0/sw_last,N : { }", + "/region1/sw_last,i : { 12 }", + "/region2/sw_last,i : { 60 }", + "/region3/sw_last,ii : { 14, 16 }", + // "/region4/sw_last,ii : { 60, 83 }", + // "/region5/sw_last,ii : { 0, 0 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("sw_lolast disables sw_last over the whole region") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav sw_last=12 sw_lolast=14 sw_last=16 + )"); + synth.dispatchMessage(client, 0, "/region0/sw_last", "", nullptr); + std::vector expected { + "/region0/sw_last,ii : { 14, 14 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Keyswitch label") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sw_label=hello + )"); + synth.dispatchMessage(client, 0, "/region0/sw_label", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sw_label", "", nullptr); + std::vector expected { + "/region0/sw_label,N : { }", + "/region1/sw_label,s : { hello }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Upswitch") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sw_up=16 + sample=kick.wav sw_up=-1 + sample=kick.wav sw_up=128 + sample=kick.wav sw_up=c4 + sample=kick.wav sw_up=64 sw_up=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/sw_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sw_up", "", nullptr); + // TODO: activate for the new region parser; ignore oob + // synth.dispatchMessage(client, 0, "/region2/sw_up", "", nullptr); + // synth.dispatchMessage(client, 0, "/region3/sw_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/sw_up", "", nullptr); + // TODO: activate for the new region parser; ignore the second value + // synth.dispatchMessage(client, 0, "/region5/sw_up", "", nullptr); + std::vector expected { + "/region0/sw_up,N : { }", + "/region1/sw_up,i : { 16 }", + // "/region2/sw_up,N : { }", + // "/region3/sw_up,N : { }", + "/region4/sw_up,i : { 60 }", + // "/region5/sw_up,i : { 64 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Downswitch") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sw_down=16 + sample=kick.wav sw_down=-1 + sample=kick.wav sw_down=128 + sample=kick.wav sw_down=c4 + sample=kick.wav sw_down=64 sw_down=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/sw_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sw_down", "", nullptr); + // TODO: activate for the new region parser; ignore oob + // synth.dispatchMessage(client, 0, "/region2/sw_down", "", nullptr); + // synth.dispatchMessage(client, 0, "/region3/sw_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/sw_down", "", nullptr); + // TODO: activate for the new region parser; ignore the second value + // synth.dispatchMessage(client, 0, "/region5/sw_down", "", nullptr); + std::vector expected { + "/region0/sw_down,N : { }", + "/region1/sw_down,i : { 16 }", + // "/region2/sw_down,N : { }", + // "/region3/sw_down,N : { }", + "/region4/sw_down,i : { 60 }", + // "/region5/sw_down,i : { 64 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Previous keyswitch") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sw_previous=16 + sample=kick.wav sw_previous=-1 + sample=kick.wav sw_previous=128 + sample=kick.wav sw_previous=c4 + sample=kick.wav sw_previous=64 sw_previous=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/sw_previous", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sw_previous", "", nullptr); + // TODO: activate for the new region parser; ignore oob + // synth.dispatchMessage(client, 0, "/region2/sw_previous", "", nullptr); + // synth.dispatchMessage(client, 0, "/region3/sw_previous", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/sw_previous", "", nullptr); + // TODO: activate for the new region parser; ignore the second value + // synth.dispatchMessage(client, 0, "/region5/sw_previous", "", nullptr); + std::vector expected { + "/region0/sw_previous,N : { }", + "/region1/sw_previous,i : { 16 }", + // "/region2/sw_previous,N : { }", + // "/region3/sw_previous,N : { }", + "/region4/sw_previous,i : { 60 }", + // "/region5/sw_previous,i : { 64 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Velocity override") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sw_vel=current + sample=kick.wav sw_vel=previous + sample=kick.wav sw_vel=previous sw_vel=current + )"); + synth.dispatchMessage(client, 0, "/region0/sw_vel", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sw_vel", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sw_vel", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sw_vel", "", nullptr); + std::vector expected { + "/region0/sw_vel,s : { current }", + "/region1/sw_vel,s : { current }", + "/region2/sw_vel,s : { previous }", + "/region3/sw_vel,s : { current }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Aftertouch range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav lochanaft=34 hichanaft=60 + sample=kick.wav lochanaft=-3 hichanaft=60 + sample=kick.wav lochanaft=20 hichanaft=-1 + sample=kick.wav lochanaft=20 hichanaft=10 + )"); + synth.dispatchMessage(client, 0, "/region0/chanaft_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/chanaft_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/chanaft_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/chanaft_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/chanaft_range", "", nullptr); + std::vector expected { + "/region0/chanaft_range,ii : { 0, 127 }", + "/region1/chanaft_range,ii : { 34, 60 }", + "/region2/chanaft_range,ii : { 0, 60 }", + "/region3/chanaft_range,ii : { 0, 0 }", + "/region4/chanaft_range,ii : { 10, 10 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] BPM range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav lobpm=34.1 hibpm=60.2 + sample=kick.wav lobpm=-3 hibpm=60 + sample=kick.wav lobpm=20 hibpm=-1 + sample=kick.wav lobpm=20 hibpm=10 + )"); + synth.dispatchMessage(client, 0, "/region0/bpm_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/bpm_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/bpm_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/bpm_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/bpm_range", "", nullptr); + std::vector expected { + "/region0/bpm_range,ff : { 0, 500 }", + "/region1/bpm_range,ff : { 34.1, 60.2 }", + "/region2/bpm_range,ff : { 0, 60 }", + "/region3/bpm_range,ff : { 0, 0 }", + "/region4/bpm_range,ff : { 10, 10 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Rand range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav lorand=0.2 hirand=0.4 + sample=kick.wav lorand=-0.1 hirand=0.4 + sample=kick.wav lorand=0.2 hirand=-0.1 + sample=kick.wav lorand=0.2 hirand=0.1 + )"); + synth.dispatchMessage(client, 0, "/region0/rand_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/rand_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/rand_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/rand_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/rand_range", "", nullptr); + std::vector expected { + "/region0/rand_range,ff : { 0, 1 }", + "/region1/rand_range,ff : { 0.2, 0.4 }", + "/region2/rand_range,ff : { 0, 0.4 }", + "/region3/rand_range,ff : { 0, 0 }", + "/region4/rand_range,ff : { 0.1, 0.1 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Sequence length") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav seq_length=12 + sample=kick.wav seq_length=-1 + sample=kick.wav seq_length=12 seq_length=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/seq_length", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/seq_length", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/seq_length", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region3/seq_length", "", nullptr); + std::vector expected { + "/region0/seq_length,h : { 1 }", + "/region1/seq_length,h : { 12 }", + "/region2/seq_length,h : { 1 }", + // TODO: activate for the new region parser ; ignore the second value + // "/region3/seq_length,f : { 12 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Sequence position") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav seq_position=12 + sample=kick.wav seq_position=-1 + sample=kick.wav seq_position=12 seq_position=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/seq_position", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/seq_position", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/seq_position", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region3/seq_position", "", nullptr); + std::vector expected { + "/region0/seq_position,h : { 1 }", + "/region1/seq_position,h : { 12 }", + "/region2/seq_position,h : { 1 }", + // TODO: activate for the new region parser ; ignore the second value + // "/region3/seq_position,f : { 12 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Trigger type") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav trigger=release + sample=kick.wav trigger=release_key + sample=kick.wav trigger=legato + sample=kick.wav trigger=first + sample=kick.wav trigger=nothing + sample=kick.wav trigger=release trigger=attack + )"); + synth.dispatchMessage(client, 0, "/region0/trigger", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/trigger", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/trigger", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/trigger", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/trigger", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/trigger", "", nullptr); + synth.dispatchMessage(client, 0, "/region6/trigger", "", nullptr); + std::vector expected { + "/region0/trigger,s : { attack }", + "/region1/trigger,s : { release }", + "/region2/trigger,s : { release_key }", + "/region3/trigger,s : { legato }", + "/region4/trigger,s : { first }", + "/region5/trigger,s : { attack }", + "/region6/trigger,s : { attack }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Start on cc range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav on_locc1=15 + sample=kick.wav on_hicc1=84 + sample=kick.wav on_locc1=15 on_hicc1=84 + sample=kick.wav on_lohdcc2=0.1 + sample=kick.wav on_hihdcc2=0.4 + sample=kick.wav on_lohdcc2=0.1 on_hihdcc2=0.4 + )"); + synth.dispatchMessage(client, 0, "/region0/start_cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/start_cc_range2", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/start_cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/start_cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/start_cc_range1", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/start_cc_range2", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/start_cc_range2", "", nullptr); + synth.dispatchMessage(client, 0, "/region6/start_cc_range2", "", nullptr); + std::vector expected { + "/region0/start_cc_range1,N : { }", + "/region0/start_cc_range2,N : { }", + "/region1/start_cc_range1,ff : { 0.11811, 1 }", + "/region2/start_cc_range1,ff : { 0, 0.661417 }", + "/region3/start_cc_range1,ff : { 0.11811, 0.661417 }", + "/region4/start_cc_range2,ff : { 0.1, 1 }", + "/region5/start_cc_range2,ff : { 0, 0.4 }", + "/region6/start_cc_range2,ff : { 0.1, 0.4 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Volume") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav volume=4.2 + sample=kick.wav gain=-200 + )"); + synth.dispatchMessage(client, 0, "/region0/volume", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/volume", "", nullptr); + // TODO: activate for the new region parser ; allow oob + // synth.dispatchMessage(client, 0, "/region2/volume", "", nullptr); + std::vector expected { + "/region0/volume,f : { 0 }", + "/region1/volume,f : { 4.2 }", + // "/region2/volume,f : { -200 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Depth") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav volume_oncc42=4.2 + sample=kick.wav gain_oncc2=-10 + )"); + synth.dispatchMessage(client, 0, "/region0/volume_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/volume_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/volume_cc2", "", nullptr); + std::vector expected { + "/region0/volume_cc42,N : { }", + "/region1/volume_cc42,f : { 4.2 }", + "/region2/volume_cc2,f : { -10 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Params") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav volume_stepcc42=4.2 + sample=kick.wav volume_smoothcc42=4 + sample=kick.wav volume_curvecc42=2 + sample=kick.wav volume_stepcc42=-1 + sample=kick.wav volume_smoothcc42=-4 + sample=kick.wav volume_curvecc42=300 + )"); + synth.dispatchMessage(client, 0, "/region0/volume_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/volume_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/volume_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/volume_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/volume_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/volume_curvecc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/volume_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/volume_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/volume_curvecc42", "", nullptr); + std::vector expected { + "/region0/volume_stepcc42,N : { }", + "/region0/volume_smoothcc42,N : { }", + "/region0/volume_curvecc42,N : { }", + "/region1/volume_stepcc42,f : { 4.2 }", + "/region2/volume_smoothcc42,i : { 4 }", + "/region3/volume_curvecc42,i : { 2 }", + // "/region4/volume_stepcc42,N : { }", + // "/region5/volume_smoothcc42,N : { }", + // "/region6/volume_curvecc42,N : { }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Params (with gain_)") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav gain_stepcc42=4.2 + sample=kick.wav gain_smoothcc42=4 + sample=kick.wav gain_curvecc42=2 + sample=kick.wav gain_stepcc42=-1 + sample=kick.wav gain_smoothcc42=-4 + sample=kick.wav gain_curvecc42=300 + )"); + synth.dispatchMessage(client, 0, "/region0/volume_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/volume_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/volume_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/volume_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/volume_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/volume_curvecc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/volume_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/volume_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/volume_curvecc42", "", nullptr); + std::vector expected { + "/region0/volume_stepcc42,N : { }", + "/region0/volume_smoothcc42,N : { }", + "/region0/volume_curvecc42,N : { }", + "/region1/volume_stepcc42,f : { 4.2 }", + "/region2/volume_smoothcc42,i : { 4 }", + "/region3/volume_curvecc42,i : { 2 }", + // "/region4/volume_stepcc42,N : { }", + // "/region5/volume_smoothcc42,N : { }", + // "/region6/volume_curvecc42,N : { }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Pan") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pan=4.2 + sample=kick.wav pan=-200 + )"); + synth.dispatchMessage(client, 0, "/region0/pan", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pan", "", nullptr); + // TODO: activate for the new region parser ; accept oob + // synth.dispatchMessage(client, 0, "/region2/pan", "", nullptr); + std::vector expected { + "/region0/pan,f : { 0 }", + "/region1/pan,f : { 4.2 }", + // TODO: activate for the new region parser ; accept oob + // "/region2/pan,f : { -200 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Depth") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pan_oncc42=4.2 + sample=kick.wav pan_oncc2=-10 + )"); + synth.dispatchMessage(client, 0, "/region0/pan_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pan_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pan_cc2", "", nullptr); + std::vector expected { + "/region0/pan_cc42,N : { }", + "/region1/pan_cc42,f : { 4.2 }", + "/region2/pan_cc2,f : { -10 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Params") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pan_stepcc42=4.2 + sample=kick.wav pan_smoothcc42=4 + sample=kick.wav pan_curvecc42=2 + sample=kick.wav pan_stepcc42=-1 + sample=kick.wav pan_smoothcc42=-4 + sample=kick.wav pan_curvecc42=300 + )"); + synth.dispatchMessage(client, 0, "/region0/pan_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pan_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pan_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pan_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pan_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/pan_curvecc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/pan_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/pan_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/pan_curvecc42", "", nullptr); + std::vector expected { + "/region0/pan_stepcc42,N : { }", + "/region0/pan_smoothcc42,N : { }", + "/region0/pan_curvecc42,N : { }", + "/region1/pan_stepcc42,f : { 4.2 }", + "/region2/pan_smoothcc42,i : { 4 }", + "/region3/pan_curvecc42,i : { 2 }", + // "/region4/pan_stepcc42,N : { }", + // "/region5/pan_smoothcc42,N : { }", + // "/region6/pan_curvecc42,N : { }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Width") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav width=4.2 + sample=kick.wav width=-200 + )"); + synth.dispatchMessage(client, 0, "/region0/width", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/width", "", nullptr); + // TODO: activate for the new region parser ; accept oob + // synth.dispatchMessage(client, 0, "/region2/width", "", nullptr); + std::vector expected { + "/region0/width,f : { 100 }", + "/region1/width,f : { 4.2 }", + // TODO: activate for the new region parser ; accept oob + // "/region2/width,f : { -200 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Depth") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav width_oncc42=4.2 + sample=kick.wav width_oncc2=-10 + )"); + synth.dispatchMessage(client, 0, "/region0/width_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/width_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/width_cc2", "", nullptr); + std::vector expected { + "/region0/width_cc42,N : { }", + "/region1/width_cc42,f : { 4.2 }", + "/region2/width_cc2,f : { -10 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Params") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav width_stepcc42=4.2 + sample=kick.wav width_smoothcc42=4 + sample=kick.wav width_curvecc42=2 + sample=kick.wav width_stepcc42=-1 + sample=kick.wav width_smoothcc42=-4 + sample=kick.wav width_curvecc42=300 + )"); + synth.dispatchMessage(client, 0, "/region0/width_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/width_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/width_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/width_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/width_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/width_curvecc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/width_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/width_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/width_curvecc42", "", nullptr); + std::vector expected { + "/region0/width_stepcc42,N : { }", + "/region0/width_smoothcc42,N : { }", + "/region0/width_curvecc42,N : { }", + "/region1/width_stepcc42,f : { 4.2 }", + "/region2/width_smoothcc42,i : { 4 }", + "/region3/width_curvecc42,i : { 2 }", + // "/region4/width_stepcc42,N : { }", + // "/region5/width_smoothcc42,N : { }", + // "/region6/width_curvecc42,N : { }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Position") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav position=4.2 + sample=kick.wav position=-200 + )"); + synth.dispatchMessage(client, 0, "/region0/position", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/position", "", nullptr); + // TODO: activate for the new region parser; accept oob + // synth.dispatchMessage(client, 0, "/region2/position", "", nullptr); + std::vector expected { + "/region0/position,f : { 0 }", + "/region1/position,f : { 4.2 }", + // TODO: activate for the new region parser; accept oob + // "/region2/position,f : { -200 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Depth") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav position_oncc42=4.2 + sample=kick.wav position_oncc2=-10 + )"); + synth.dispatchMessage(client, 0, "/region0/position_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/position_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/position_cc2", "", nullptr); + std::vector expected { + "/region0/position_cc42,N : { }", + "/region1/position_cc42,f : { 4.2 }", + "/region2/position_cc2,f : { -10 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Params") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav position_stepcc42=4.2 + sample=kick.wav position_smoothcc42=4 + sample=kick.wav position_curvecc42=2 + sample=kick.wav position_stepcc42=-1 + sample=kick.wav position_smoothcc42=-4 + sample=kick.wav position_curvecc42=300 + )"); + synth.dispatchMessage(client, 0, "/region0/position_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/position_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/position_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/position_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/position_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/position_curvecc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/position_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/position_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/position_curvecc42", "", nullptr); + std::vector expected { + "/region0/position_stepcc42,N : { }", + "/region0/position_smoothcc42,N : { }", + "/region0/position_curvecc42,N : { }", + "/region1/position_stepcc42,f : { 4.2 }", + "/region2/position_smoothcc42,i : { 4 }", + "/region3/position_curvecc42,i : { 2 }", + // "/region4/position_stepcc42,N : { }", + // "/region5/position_smoothcc42,N : { }", + // "/region6/position_curvecc42,N : { }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Amplitude") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amplitude=4.2 + sample=kick.wav amplitude=-200 + )"); + synth.dispatchMessage(client, 0, "/region0/amplitude", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amplitude", "", nullptr); + // TODO: activate for the new region parser; ignore oob + // synth.dispatchMessage(client, 0, "/region2/amplitude", "", nullptr); + std::vector expected { + "/region0/amplitude,f : { 100 }", + "/region1/amplitude,f : { 4.2 }", + // "/region2/amplitude,f : { 100 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Depth") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amplitude_oncc42=4.2 + sample=kick.wav amplitude_oncc2=-10 + )"); + synth.dispatchMessage(client, 0, "/region0/amplitude_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amplitude_cc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region2/amplitude_cc2", "", nullptr); + std::vector expected { + "/region0/amplitude_cc42,N : { }", + "/region1/amplitude_cc42,f : { 4.2 }", + // "/region2/amplitude_cc2,N : { }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Params") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amplitude_stepcc42=4.2 + sample=kick.wav amplitude_smoothcc42=4 + sample=kick.wav amplitude_curvecc42=2 + sample=kick.wav amplitude_stepcc42=-1 + sample=kick.wav amplitude_smoothcc42=-4 + sample=kick.wav amplitude_curvecc42=300 + )"); + synth.dispatchMessage(client, 0, "/region0/amplitude_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/amplitude_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/amplitude_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amplitude_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/amplitude_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/amplitude_curvecc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/amplitude_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/amplitude_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/amplitude_curvecc42", "", nullptr); + std::vector expected { + "/region0/amplitude_stepcc42,N : { }", + "/region0/amplitude_smoothcc42,N : { }", + "/region0/amplitude_curvecc42,N : { }", + "/region1/amplitude_stepcc42,f : { 4.2 }", + "/region2/amplitude_smoothcc42,i : { 4 }", + "/region3/amplitude_curvecc42,i : { 2 }", + // "/region4/amplitude_stepcc42,N : { }", + // "/region5/amplitude_smoothcc42,N : { }", + // "/region6/amplitude_curvecc42,N : { }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Amp Keycenter") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amp_keycenter=40 + sample=kick.wav amp_keycenter=-1 + sample=kick.wav amp_keycenter=c3 + )"); + synth.dispatchMessage(client, 0, "/region0/amp_keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amp_keycenter", "", nullptr); + // TODO: activate for the new region parser ; ignore oob and parse note + // synth.dispatchMessage(client, 0, "/region2/amp_keycenter", "", nullptr); + // synth.dispatchMessage(client, 0, "/region3/amp_keycenter", "", nullptr); + std::vector expected { + "/region0/amp_keycenter,i : { 60 }", + "/region1/amp_keycenter,i : { 40 }", + // "/region2/amp_keycenter,i : { 60 }", + // "/region3/amp_keycenter,i : { 48 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Amp Keytrack") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amp_keytrack=10.1 + sample=kick.wav amp_keytrack=40 + )"); + synth.dispatchMessage(client, 0, "/region0/amp_keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amp_keytrack", "", nullptr); + // TODO: activate for the new region parser ; accept oob + // synth.dispatchMessage(client, 0, "/region2/amp_keytrack", "", nullptr); + std::vector expected { + "/region0/amp_keytrack,f : { 0 }", + "/region1/amp_keytrack,f : { 10.1 }", + // "/region2/amp_keytrack,f : { 40 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Amp Veltrack") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amp_veltrack=10.1 + sample=kick.wav amp_veltrack=-132 + )"); + synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amp_veltrack", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr); + std::vector expected { + "/region0/amp_veltrack,f : { 100 }", + "/region1/amp_veltrack,f : { 10.1 }", + // "/region2/amp_veltrack,f : { 100 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Amp Random") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav amp_random=10.1 + sample=kick.wav amp_random=-4 + )"); + synth.dispatchMessage(client, 0, "/region0/amp_random", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/amp_random", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region2/amp_random", "", nullptr); + std::vector expected { + "/region0/amp_random,f : { 0 }", + "/region1/amp_random,f : { 10.1 }", + // "/region2/amp_random,f : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Crossfade key range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Xfin") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xfin_lokey=10 xfin_hikey=40 + sample=kick.wav xfin_lokey=c4 xfin_hikey=b5 + sample=kick.wav xfin_lokey=-10 xfin_hikey=40 + sample=kick.wav xfin_lokey=10 xfin_hikey=140 + )"); + synth.dispatchMessage(client, 0, "/region0/xfin_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xfin_key_range", "", nullptr); + // TODO: activate for the new region parser ; parse note value + // synth.dispatchMessage(client, 0, "/region2/xfin_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xfin_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/xfin_key_range", "", nullptr); + std::vector expected { + "/region0/xfin_key_range,ii : { 0, 0 }", + "/region1/xfin_key_range,ii : { 10, 40 }", + // "/region2/xfin_key_range,ii : { 60, 83 }", + "/region3/xfin_key_range,ii : { 0, 40 }", + "/region4/xfin_key_range,ii : { 10, 127 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Xfout") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xfout_lokey=10 xfout_hikey=40 + sample=kick.wav xfout_lokey=c4 xfout_hikey=b5 + sample=kick.wav xfout_lokey=-10 xfout_hikey=40 + sample=kick.wav xfout_lokey=10 xfout_hikey=140 + )"); + synth.dispatchMessage(client, 0, "/region0/xfout_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xfout_key_range", "", nullptr); + // TODO: activate for the new region parser ; parse note value + // synth.dispatchMessage(client, 0, "/region2/xfout_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xfout_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/xfout_key_range", "", nullptr); + std::vector expected { + "/region0/xfout_key_range,ii : { 127, 127 }", + "/region1/xfout_key_range,ii : { 10, 40 }", + // "/region2/xfout_key_range,ii : { 60, 83 }", + "/region3/xfout_key_range,ii : { 0, 40 }", + "/region4/xfout_key_range,ii : { 10, 127 }", + }; + REQUIRE(messageList == expected); + } +} + + +TEST_CASE("[Values] Crossfade velocity range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Xfin") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xfin_lovel=10 xfin_hivel=40 + sample=kick.wav xfin_lovel=-10 xfin_hivel=40 + sample=kick.wav xfin_lovel=10 xfin_hivel=140 + )"); + synth.dispatchMessage(client, 0, "/region0/xfin_vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xfin_vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xfin_vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xfin_vel_range", "", nullptr); + std::vector expected { + "/region0/xfin_vel_range,ff : { 0, 0 }", + "/region1/xfin_vel_range,ff : { 0.0787402, 0.314961 }", + "/region2/xfin_vel_range,ff : { 0, 0.314961 }", + "/region3/xfin_vel_range,ff : { 0.0787402, 1 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Xfout") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xfout_lovel=10 xfout_hivel=40 + sample=kick.wav xfout_lovel=-10 xfout_hivel=40 + sample=kick.wav xfout_lovel=10 xfout_hivel=140 + )"); + synth.dispatchMessage(client, 0, "/region0/xfout_vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xfout_vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xfout_vel_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xfout_vel_range", "", nullptr); + std::vector expected { + "/region0/xfout_vel_range,ff : { 1, 1 }", + "/region1/xfout_vel_range,ff : { 0.0787402, 0.314961 }", + "/region2/xfout_vel_range,ff : { 0, 0.314961 }", + "/region3/xfout_vel_range,ff : { 0.0787402, 1 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Crossfade curves") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Key") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xf_keycurve=gain + sample=kick.wav xf_keycurve=something + sample=kick.wav xf_keycurve=gain xf_keycurve=power + )"); + synth.dispatchMessage(client, 0, "/region0/xf_keycurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xf_keycurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xf_keycurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xf_keycurve", "", nullptr); + std::vector expected { + "/region0/xf_keycurve,s : { power }", + "/region1/xf_keycurve,s : { gain }", + "/region2/xf_keycurve,s : { power }", + "/region3/xf_keycurve,s : { power }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Velocity") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xf_velcurve=gain + sample=kick.wav xf_velcurve=something + sample=kick.wav xf_velcurve=gain xf_velcurve=power + )"); + synth.dispatchMessage(client, 0, "/region0/xf_velcurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xf_velcurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xf_velcurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xf_velcurve", "", nullptr); + std::vector expected { + "/region0/xf_velcurve,s : { power }", + "/region1/xf_velcurve,s : { gain }", + "/region2/xf_velcurve,s : { power }", + "/region3/xf_velcurve,s : { power }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xf_cccurve=gain + sample=kick.wav xf_cccurve=something + sample=kick.wav xf_cccurve=gain xf_cccurve=power + )"); + synth.dispatchMessage(client, 0, "/region0/xf_cccurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xf_cccurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xf_cccurve", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xf_cccurve", "", nullptr); + std::vector expected { + "/region0/xf_cccurve,s : { power }", + "/region1/xf_cccurve,s : { gain }", + "/region2/xf_cccurve,s : { power }", + "/region3/xf_cccurve,s : { power }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Crossfade CC range") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Xfin") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xfin_locc4=10 xfin_hicc4=40 + sample=kick.wav xfin_locc4=-10 xfin_hicc4=40 + sample=kick.wav xfin_locc4=10 xfin_hicc4=140 + )"); + synth.dispatchMessage(client, 0, "/region0/xfin_cc_range4", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xfin_cc_range4", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xfin_cc_range4", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xfin_cc_range4", "", nullptr); + std::vector expected { + "/region0/xfin_cc_range4,N : { }", + "/region1/xfin_cc_range4,ff : { 0.0787402, 0.314961 }", + "/region2/xfin_cc_range4,ff : { 0, 0.314961 }", + "/region3/xfin_cc_range4,ff : { 0.0787402, 1 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Xfout") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav xfout_locc4=10 xfout_hicc4=40 + sample=kick.wav xfout_locc4=-10 xfout_hicc4=40 + sample=kick.wav xfout_locc4=10 xfout_hicc4=140 + )"); + synth.dispatchMessage(client, 0, "/region0/xfout_cc_range4", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/xfout_cc_range4", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xfout_cc_range4", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/xfout_cc_range4", "", nullptr); + std::vector expected { + "/region0/xfout_cc_range4,N : { }", + "/region1/xfout_cc_range4,ff : { 0.0787402, 0.314961 }", + "/region2/xfout_cc_range4,ff : { 0, 0.314961 }", + "/region3/xfout_cc_range4,ff : { 0.0787402, 1 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Global volumes and amplitudes") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Volumes") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + global_volume=4.4 + master_volume=5.5 + group_volume=6.6 + sample=kick.wav + )"); + synth.dispatchMessage(client, 0, "/region0/global_volume", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/master_volume", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/group_volume", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/global_volume", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/master_volume", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/group_volume", "", nullptr); + std::vector expected { + "/region0/global_volume,f : { 0 }", + "/region0/master_volume,f : { 0 }", + "/region0/group_volume,f : { 0 }", + "/region1/global_volume,f : { 4.4 }", + "/region1/master_volume,f : { 5.5 }", + "/region1/group_volume,f : { 6.6 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Amplitudes") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + global_amplitude=4.4 + master_amplitude=5.5 + group_amplitude=6.6 + sample=kick.wav + )"); + synth.dispatchMessage(client, 0, "/region0/global_amplitude", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/master_amplitude", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/group_amplitude", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/global_amplitude", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/master_amplitude", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/group_amplitude", "", nullptr); + std::vector expected { + "/region0/global_amplitude,f : { 100 }", + "/region0/master_amplitude,f : { 100 }", + "/region0/group_amplitude,f : { 100 }", + "/region1/global_amplitude,f : { 4.4 }", + "/region1/master_amplitude,f : { 5.5 }", + "/region1/group_amplitude,f : { 6.6 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Pitch Keytrack") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pitch_keytrack=1000 + sample=kick.wav pitch_keytrack=-100 + )"); + synth.dispatchMessage(client, 0, "/region0/pitch_keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_keytrack", "", nullptr); + std::vector expected { + "/region0/pitch_keytrack,i : { 100 }", + "/region1/pitch_keytrack,i : { 1000 }", + "/region2/pitch_keytrack,i : { -100 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Pitch Veltrack") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pitch_veltrack=10 + sample=kick.wav pitch_veltrack=-132 + )"); + synth.dispatchMessage(client, 0, "/region0/pitch_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr); + std::vector expected { + "/region0/pitch_veltrack,i : { 0 }", + "/region1/pitch_veltrack,i : { 10 }", + "/region2/pitch_veltrack,i : { -132 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Pitch Random") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pitch_random=10 + sample=kick.wav pitch_random=-4 + )"); + synth.dispatchMessage(client, 0, "/region0/pitch_random", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_random", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region2/pitch_random", "", nullptr); + std::vector expected { + "/region0/pitch_random,f : { 0 }", + "/region1/pitch_random,f : { 10 }", + // "/region2/pitch_random,f : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Transpose") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav transpose=10 + sample=kick.wav transpose=-4 + sample=kick.wav transpose=-400 + sample=kick.wav transpose=400 + )"); + synth.dispatchMessage(client, 0, "/region0/transpose", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/transpose", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/transpose", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region3/transpose", "", nullptr); + // synth.dispatchMessage(client, 0, "/region4/transpose", "", nullptr); + std::vector expected { + "/region0/transpose,i : { 0 }", + "/region1/transpose,i : { 10 }", + "/region2/transpose,i : { -4 }", + // "/region3/transpose,i : { 0 }", + // "/region4/transpose,i : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Pitch/Tune") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pitch=4.2 + sample=kick.wav tune=-200 + )"); + synth.dispatchMessage(client, 0, "/region0/tune", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/tune", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/tune", "", nullptr); + std::vector expected { + "/region0/tune,f : { 0 }", + "/region1/tune,f : { 4.2 }", + "/region2/tune,f : { -200 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Depth") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav tune_oncc42=4.2 + sample=kick.wav pitch_oncc2=-10 + )"); + synth.dispatchMessage(client, 0, "/region0/tune_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/tune_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/tune_cc2", "", nullptr); + std::vector expected { + "/region0/tune_cc42,N : { }", + "/region1/tune_cc42,f : { 4.2 }", + "/region2/tune_cc2,f : { -10 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Params") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav tune_stepcc42=4.2 + sample=kick.wav tune_smoothcc42=4 + sample=kick.wav tune_curvecc42=2 + sample=kick.wav tune_stepcc42=-1 + sample=kick.wav tune_smoothcc42=-4 + sample=kick.wav tune_curvecc42=300 + )"); + synth.dispatchMessage(client, 0, "/region0/tune_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/tune_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/tune_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/tune_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/tune_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/tune_curvecc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/tune_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/tune_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/tune_curvecc42", "", nullptr); + std::vector expected { + "/region0/tune_stepcc42,N : { }", + "/region0/tune_smoothcc42,N : { }", + "/region0/tune_curvecc42,N : { }", + "/region1/tune_stepcc42,f : { 4.2 }", + "/region2/tune_smoothcc42,i : { 4 }", + "/region3/tune_curvecc42,i : { 2 }", + // "/region4/tune_stepcc42,N : { }", + // "/region5/tune_smoothcc42,N : { }", + // "/region6/tune_curvecc42,N : { }", + }; + REQUIRE(messageList == expected); + } + + SECTION("CC Params (with pitch_)") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav pitch_stepcc42=4.2 + sample=kick.wav pitch_smoothcc42=4 + sample=kick.wav pitch_curvecc42=2 + sample=kick.wav pitch_stepcc42=-1 + sample=kick.wav pitch_smoothcc42=-4 + sample=kick.wav pitch_curvecc42=300 + )"); + synth.dispatchMessage(client, 0, "/region0/tune_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/tune_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/tune_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/tune_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/tune_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/tune_curvecc42", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/tune_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/tune_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/tune_curvecc42", "", nullptr); + std::vector expected { + "/region0/tune_stepcc42,N : { }", + "/region0/tune_smoothcc42,N : { }", + "/region0/tune_curvecc42,N : { }", + "/region1/tune_stepcc42,f : { 4.2 }", + "/region2/tune_smoothcc42,i : { 4 }", + "/region3/tune_curvecc42,i : { 2 }", + // "/region4/tune_stepcc42,N : { }", + // "/region5/tune_smoothcc42,N : { }", + // "/region6/tune_curvecc42,N : { }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Bend behavior") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav bend_up=100 bend_down=-400 bend_step=10 bend_smooth=10 + sample=kick.wav bend_up=-100 bend_down=400 bend_step=-10 bend_smooth=-10 + )"); + synth.dispatchMessage(client, 0, "/region0/bend_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/bend_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/bend_step", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/bend_smooth", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/bend_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/bend_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/bend_step", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/bend_smooth", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/bend_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/bend_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/bend_step", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/bend_smooth", "", nullptr); + std::vector expected { + "/region0/bend_up,i : { 200 }", + "/region0/bend_down,i : { -200 }", + "/region0/bend_step,i : { 1 }", + "/region0/bend_smooth,i : { 0 }", + "/region1/bend_up,i : { 100 }", + "/region1/bend_down,i : { -400 }", + "/region1/bend_step,i : { 10 }", + "/region1/bend_smooth,i : { 10 }", + "/region2/bend_up,i : { -100 }", + "/region2/bend_down,i : { 400 }", + "/region2/bend_step,i : { 1 }", + "/region2/bend_smooth,i : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] ampeg") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav + ampeg_attack=1 ampeg_delay=2 ampeg_decay=3 + ampeg_hold=4 ampeg_release=5 ampeg_start=6 + ampeg_sustain=7 ampeg_depth=8 + sample=kick.wav + ampeg_attack=-1 ampeg_delay=-2 ampeg_decay=-3 + ampeg_hold=-4 ampeg_release=-5 ampeg_start=-6 + ampeg_sustain=-7 ampeg_depth=-8 + )"); + synth.dispatchMessage(client, 0, "/region0/ampeg_attack", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_delay", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_decay", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_hold", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_release", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_start", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_sustain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_depth", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_attack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_delay", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_decay", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_hold", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_release", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_start", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_sustain", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_depth", "", nullptr); + // TODO after new parser : ignore oob + // synth.dispatchMessage(client, 0, "/region2/ampeg_attack", "", nullptr); + // synth.dispatchMessage(client, 0, "/region2/ampeg_delay", "", nullptr); + // synth.dispatchMessage(client, 0, "/region2/ampeg_decay", "", nullptr); + // synth.dispatchMessage(client, 0, "/region2/ampeg_hold", "", nullptr); + // synth.dispatchMessage(client, 0, "/region2/ampeg_release", "", nullptr); + // synth.dispatchMessage(client, 0, "/region2/ampeg_start", "", nullptr); + // synth.dispatchMessage(client, 0, "/region2/ampeg_sustain", "", nullptr); + // synth.dispatchMessage(client, 0, "/region2/ampeg_depth", "", nullptr); + std::vector expected { + "/region0/ampeg_attack,f : { 0 }", + "/region0/ampeg_delay,f : { 0 }", + "/region0/ampeg_decay,f : { 0 }", + "/region0/ampeg_hold,f : { 0 }", + "/region0/ampeg_release,f : { 0.001 }", + "/region0/ampeg_start,f : { 0 }", + "/region0/ampeg_sustain,f : { 100 }", + "/region0/ampeg_depth,i : { 0 }", + "/region1/ampeg_attack,f : { 1 }", + "/region1/ampeg_delay,f : { 2 }", + "/region1/ampeg_decay,f : { 3 }", + "/region1/ampeg_hold,f : { 4 }", + "/region1/ampeg_release,f : { 5 }", + "/region1/ampeg_start,f : { 6 }", + "/region1/ampeg_sustain,f : { 7 }", + "/region1/ampeg_depth,i : { 0 }", + // "/region2/ampeg_attack,f : { 0 }", + // "/region2/ampeg_delay,f : { 0 }", + // "/region2/ampeg_decay,f : { 0 }", + // "/region2/ampeg_hold,f : { 0 }", + // "/region2/ampeg_release,f : { 0.001 }", + // "/region2/ampeg_start,f : { 0 }", + // "/region2/ampeg_sustain,f : { 100 }", + // "/region2/ampeg_depth,i : { 0 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Velocity") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav + ampeg_vel2attack=1 ampeg_vel2delay=2 ampeg_vel2decay=3 + ampeg_vel2hold=4 ampeg_vel2release=5 + ampeg_vel2sustain=7 ampeg_vel2depth=8 + )"); + synth.dispatchMessage(client, 0, "/region0/ampeg_vel2attack", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_vel2delay", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_vel2decay", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_vel2hold", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_vel2release", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_vel2sustain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_vel2depth", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_vel2attack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_vel2delay", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_vel2decay", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_vel2hold", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_vel2release", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_vel2sustain", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/ampeg_vel2depth", "", nullptr); + std::vector expected { + "/region0/ampeg_vel2attack,f : { 0 }", + "/region0/ampeg_vel2delay,f : { 0 }", + "/region0/ampeg_vel2decay,f : { 0 }", + "/region0/ampeg_vel2hold,f : { 0 }", + "/region0/ampeg_vel2release,f : { 0 }", + "/region0/ampeg_vel2sustain,f : { 0 }", + "/region0/ampeg_vel2depth,i : { 0 }", + "/region1/ampeg_vel2attack,f : { 1 }", + "/region1/ampeg_vel2delay,f : { 2 }", + "/region1/ampeg_vel2decay,f : { 3 }", + "/region1/ampeg_vel2hold,f : { 4 }", + "/region1/ampeg_vel2release,f : { 5 }", + "/region1/ampeg_vel2sustain,f : { 7 }", + "/region1/ampeg_vel2depth,i : { 0 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Note polyphony") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav note_polyphony=10 + sample=kick.wav note_polyphony=-4 + sample=kick.wav note_polyphony=10 note_polyphony=-4 + )"); + synth.dispatchMessage(client, 0, "/region0/note_polyphony", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/note_polyphony", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region2/note_polyphony", "", nullptr); + // synth.dispatchMessage(client, 0, "/region3/note_polyphony", "", nullptr); + std::vector expected { + "/region0/note_polyphony,N : { }", + "/region1/note_polyphony,i : { 10 }", + // "/region2/note_polyphony,N : { }", + // "/region3/note_polyphony,i : { 10 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Self-mask") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav note_selfmask=off + sample=kick.wav note_selfmask=off note_selfmask=on + sample=kick.wav note_selfmask=off note_selfmask=garbage + )"); + synth.dispatchMessage(client, 0, "/region0/note_selfmask", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/note_selfmask", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/note_selfmask", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/note_selfmask", "", nullptr); + std::vector expected { + "/region0/note_selfmask,T : { }", + "/region1/note_selfmask,F : { }", + "/region2/note_selfmask,T : { }", + "/region3/note_selfmask,F : { }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] RT dead") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav rt_dead=on + sample=kick.wav rt_dead=on rt_dead=off + sample=kick.wav rt_dead=on rt_dead=garbage + )"); + synth.dispatchMessage(client, 0, "/region0/rt_dead", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/rt_dead", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/rt_dead", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/rt_dead", "", nullptr); + std::vector expected { + "/region0/rt_dead,F : { }", + "/region1/rt_dead,T : { }", + "/region2/rt_dead,F : { }", + "/region3/rt_dead,T : { }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Sustain switch") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sustain_sw=off + sample=kick.wav sustain_sw=off sustain_sw=on + sample=kick.wav sustain_sw=off sustain_sw=garbage + )"); + synth.dispatchMessage(client, 0, "/region0/sustain_sw", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sustain_sw", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sustain_sw", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sustain_sw", "", nullptr); + std::vector expected { + "/region0/sustain_sw,T : { }", + "/region1/sustain_sw,F : { }", + "/region2/sustain_sw,T : { }", + "/region3/sustain_sw,T : { }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Sostenuto switch") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sostenuto_sw=off + sample=kick.wav sostenuto_sw=off sostenuto_sw=on + sample=kick.wav sostenuto_sw=off sostenuto_sw=garbage + )"); + synth.dispatchMessage(client, 0, "/region0/sostenuto_sw", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sostenuto_sw", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sostenuto_sw", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sostenuto_sw", "", nullptr); + std::vector expected { + "/region0/sostenuto_sw,T : { }", + "/region1/sostenuto_sw,F : { }", + "/region2/sostenuto_sw,T : { }", + "/region3/sostenuto_sw,T : { }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Sustain CC") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sustain_cc=10 + sample=kick.wav sustain_cc=20 sustain_cc=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/sustain_cc", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sustain_cc", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region2/sustain_cc", "", nullptr); + std::vector expected { + "/region0/sustain_cc,i : { 64 }", + "/region1/sustain_cc,i : { 10 }", + // "/region2/sustain_cc,i : { 20 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Sustain low") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav sustain_lo=10 + sample=kick.wav sustain_lo=10 sustain_lo=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/sustain_lo", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/sustain_lo", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region2/sustain_lo", "", nullptr); + std::vector expected { + "/region0/sustain_lo,f : { 0.0039 }", + "/region1/sustain_lo,f : { 0.0787402 }", + // "/region2/sustain_lo,f : { 0.0787402 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Oscillator phase") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav oscillator_phase=0.1 + sample=kick.wav oscillator_phase=1.1 + sample=kick.wav oscillator_phase=-1.2 + )"); + synth.dispatchMessage(client, 0, "/region0/oscillator_phase", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/oscillator_phase", "", nullptr); + // TODO: activate for the new region parser ; properly wrap + // synth.dispatchMessage(client, 0, "/region2/oscillator_phase", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/oscillator_phase", "", nullptr); + std::vector expected { + "/region0/oscillator_phase,f : { 0 }", + "/region1/oscillator_phase,f : { 0.1 }", + // "/region2/oscillator_phase,f : { 0.1 }", + "/region3/oscillator_phase,f : { -1 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Effect sends") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav effect1=10 + sample=kick.wav effect2=50.4 + sample=kick.wav effect1=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/effect1", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/effect1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/effect1", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/effect2", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr); + std::vector expected { + // No reply to the first question + "/region1/effect1,f : { 10 }", + "/region2/effect1,f : { 0 }", + "/region2/effect2,f : { 50.4 }", + // "/region4/effect1,f : { 100 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Support floating point for int values") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav offset=1042.5 + sample=kick.wav pitch_keytrack=-2.1 + )"); + synth.dispatchMessage(client, 0, "/region0/offset", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_keytrack", "", nullptr); + // TODO: activate for the new region parser ; ignore oob + // synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr); + std::vector expected { + "/region0/offset,h : { 1042 }", + "/region1/pitch_keytrack,i : { -2 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] ampeg CC") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + )"); + synth.dispatchMessage(client, 0, "/region0/ampeg_attack_cc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_delay_cc2", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_decay_cc3", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_hold_cc4", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_release_cc5", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_start_cc6", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_sustain_cc7", "", nullptr); + std::vector expected { + "/region0/ampeg_attack_cc1,f : { 0 }", + "/region0/ampeg_delay_cc2,f : { 0 }", + "/region0/ampeg_decay_cc3,f : { 0 }", + "/region0/ampeg_hold_cc4,f : { 0 }", + "/region0/ampeg_release_cc5,f : { 0 }", + "/region0/ampeg_start_cc6,f : { 0 }", + "/region0/ampeg_sustain_cc7,f : { 0 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Positive values") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + ampeg_attack_oncc1=1 ampeg_delay_oncc2=2 ampeg_decay_oncc3=3 + ampeg_hold_oncc4=4 ampeg_release_oncc5=5 ampeg_start_oncc6=6 + ampeg_sustain_oncc7=7 + )"); + synth.dispatchMessage(client, 0, "/region0/ampeg_attack_cc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_delay_cc2", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_decay_cc3", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_hold_cc4", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_release_cc5", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_start_cc6", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_sustain_cc7", "", nullptr); + std::vector expected { + "/region0/ampeg_attack_cc1,f : { 1 }", + "/region0/ampeg_delay_cc2,f : { 2 }", + "/region0/ampeg_decay_cc3,f : { 3 }", + "/region0/ampeg_hold_cc4,f : { 4 }", + "/region0/ampeg_release_cc5,f : { 5 }", + "/region0/ampeg_start_cc6,f : { 6 }", + "/region0/ampeg_sustain_cc7,f : { 7 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Basic") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + ampeg_attack_cc1=-1 ampeg_delay_cc2=-2 ampeg_decay_cc3=-3 + ampeg_hold_cc4=-4 ampeg_release_cc5=-5 ampeg_start_cc6=-6 + ampeg_sustain_cc7=-7 + )"); + synth.dispatchMessage(client, 0, "/region0/ampeg_attack_cc1", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_delay_cc2", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_decay_cc3", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_hold_cc4", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_release_cc5", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_start_cc6", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/ampeg_sustain_cc7", "", nullptr); + std::vector expected { + "/region0/ampeg_attack_cc1,f : { -1 }", + "/region0/ampeg_delay_cc2,f : { -2 }", + "/region0/ampeg_decay_cc3,f : { -3 }", + "/region0/ampeg_hold_cc4,f : { -4 }", + "/region0/ampeg_release_cc5,f : { -5 }", + "/region0/ampeg_start_cc6,f : { -6 }", + "/region0/ampeg_sustain_cc7,f : { -7 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Filter stacking and cutoffs") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav cutoff=50 + sample=kick.wav cutoff2=500 + )"); + + SECTION("Test first region") + { + synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/type", "", nullptr); + std::vector expected { + // No filters + }; + REQUIRE(messageList == expected); + } + + SECTION("Test second region") + { + synth.dispatchMessage(client, 0, "/region1/filter0/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter1/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter1/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter1/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter1/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter1/keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter1/veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter1/type", "", nullptr); + std::vector expected { + "/region1/filter0/cutoff,f : { 50 }", + "/region1/filter0/gain,f : { 0 }", + "/region1/filter0/resonance,f : { 0 }", + "/region1/filter0/keycenter,i : { 60 }", + "/region1/filter0/keytrack,i : { 0 }", + "/region1/filter0/veltrack,i : { 0 }", + "/region1/filter0/type,s : { lpf_2p }", + // No second filter + }; + REQUIRE(messageList == expected); + } + + SECTION("Test third region") + { + synth.dispatchMessage(client, 0, "/region2/filter0/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter1/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter1/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter1/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter1/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter1/keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter1/veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter1/type", "", nullptr); + std::vector expected { + // The first filter is default-filled + "/region2/filter0/cutoff,f : { 0 }", + "/region2/filter0/gain,f : { 0 }", + "/region2/filter0/resonance,f : { 0 }", + "/region2/filter0/keycenter,i : { 60 }", + "/region2/filter0/keytrack,i : { 0 }", + "/region2/filter0/veltrack,i : { 0 }", + "/region2/filter0/type,s : { lpf_2p }", + "/region2/filter1/cutoff,f : { 500 }", + "/region2/filter1/gain,f : { 0 }", + "/region2/filter1/resonance,f : { 0 }", + "/region2/filter1/keycenter,i : { 60 }", + "/region2/filter1/keytrack,i : { 0 }", + "/region2/filter1/veltrack,i : { 0 }", + "/region2/filter1/type,s : { lpf_2p }", + // No second filter + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] Filter types") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav fil_type=lpf_1p + sample=kick.wav fil_type=hpf_1p + sample=kick.wav fil_type=lpf_2p + sample=kick.wav fil_type=hpf_2p + sample=kick.wav fil_type=bpf_2p + sample=kick.wav fil_type=brf_2p + sample=kick.wav fil_type=bpf_1p + sample=kick.wav fil_type=brf_1p + sample=kick.wav fil_type=apf_1p + sample=kick.wav fil_type=lpf_2p_sv + sample=kick.wav fil_type=hpf_2p_sv + sample=kick.wav fil_type=bpf_2p_sv + sample=kick.wav fil_type=brf_2p_sv + sample=kick.wav fil_type=lpf_4p + sample=kick.wav fil_type=hpf_4p + sample=kick.wav fil_type=lpf_6p + sample=kick.wav fil_type=hpf_6p + sample=kick.wav fil_type=pink + sample=kick.wav fil_type=lsh + sample=kick.wav fil_type=hsh + sample=kick.wav fil_type=peq + sample=kick.wav fil2_type=peq + sample=kick.wav fil2_type=something + )"); + + synth.dispatchMessage(client, 0, "/region0/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region6/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region7/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region8/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region9/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region10/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region11/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region12/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region13/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region14/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region15/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region16/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region17/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region18/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region19/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region20/filter0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region21/filter1/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region22/filter1/type", "", nullptr); + std::vector expected { + "/region0/filter0/type,s : { lpf_1p }", + "/region1/filter0/type,s : { hpf_1p }", + "/region2/filter0/type,s : { lpf_2p }", + "/region3/filter0/type,s : { hpf_2p }", + "/region4/filter0/type,s : { bpf_2p }", + "/region5/filter0/type,s : { brf_2p }", + "/region6/filter0/type,s : { bpf_1p }", + "/region7/filter0/type,s : { brf_1p }", + "/region8/filter0/type,s : { apf_1p }", + "/region9/filter0/type,s : { lpf_2p_sv }", + "/region10/filter0/type,s : { hpf_2p_sv }", + "/region11/filter0/type,s : { bpf_2p_sv }", + "/region12/filter0/type,s : { brf_2p_sv }", + "/region13/filter0/type,s : { lpf_4p }", + "/region14/filter0/type,s : { hpf_4p }", + "/region15/filter0/type,s : { lpf_6p }", + "/region16/filter0/type,s : { hpf_6p }", + "/region17/filter0/type,s : { pink }", + "/region18/filter0/type,s : { lsh }", + "/region19/filter0/type,s : { hsh }", + "/region20/filter0/type,s : { peq }", + "/region21/filter1/type,s : { peq }", + "/region22/filter1/type,s : { none }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Filter dispatching") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + cutoff3=50 resonance2=3 fil2_gain=-5 fil3_keytrack=100 + fil_gain=5 fil1_gain=-5 fil2_veltrack=-100 + )"); + + synth.dispatchMessage(client, 0, "/region0/filter2/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter2/keytrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter1/veltrack", "", nullptr); + std::vector expected { + "/region0/filter2/cutoff,f : { 50 }", + "/region0/filter1/resonance,f : { 3 }", + "/region0/filter1/gain,f : { -5 }", + "/region0/filter2/keytrack,i : { 100 }", + "/region0/filter0/gain,f : { -5 }", + "/region0/filter1/veltrack,i : { -100 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Filter value bounds") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Cutoff") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav cutoff=20000000 // Bound this to 20k + sample=kick.wav cutoff=50 cutoff=-100 + )"); + synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); + // TODO: activate after new parser; ignore OOB + // synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); + std::vector expected { + "/region0/filter0/cutoff,f : { 20000 }", + // "/region0/filter0/cutoff,f : { 50 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Cutoff") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav resonance=5 resonance=-5 + )"); + // TODO: activate after new parser; ignore OOB + // synth.dispatchMessage(client, 0, "/region0/filter0/resonance", "", nullptr); + std::vector expected { + // "/region0/filter0/resonance,f : { 5 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Keycenter") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav keycenter=40 keycenter=-5 + sample=kick.wav keycenter=40 keycenter=1000 + sample=kick.wav keycenter=c3 + )"); + // TODO: activate after new parser; ignore OOB + // synth.dispatchMessage(client, 0, "/region0/filter0/keycenter", "", nullptr); + // synth.dispatchMessage(client, 0, "/region1/filter0/keycenter", "", nullptr); + // TODO: activate after new parser; parse note + // synth.dispatchMessage(client, 0, "/region2/filter0/keycenter", "", nullptr); + std::vector expected { + // "/region0/filter0/keycenter,i : { 40 }", + // "/region1/filter0/keycenter,i : { 40 }", + // "/region2/filter0/keycenter,i : { 48 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] EQ stacking and gains") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav eq1_gain=3 + sample=kick.wav eq4_gain=6 + )"); + + SECTION("Test first region") + { + synth.dispatchMessage(client, 0, "/region0/eq0/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/vel2gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/vel2freq", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq1/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq1/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq1/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq1/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq1/vel2gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq1/vel2freq", "", nullptr); + std::vector expected { + // No eqs + }; + REQUIRE(messageList == expected); + } + + SECTION("Test second region") + { + synth.dispatchMessage(client, 0, "/region1/eq0/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq0/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq0/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq0/vel2gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq0/vel2freq", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq1/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq1/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq1/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq1/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq1/vel2gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq1/vel2freq", "", nullptr); + std::vector expected { + "/region1/eq0/gain,f : { 3 }", + "/region1/eq0/type,s : { peak }", + "/region1/eq0/bandwidth,f : { 1 }", + "/region1/eq0/frequency,f : { 50 }", + "/region1/eq0/vel2gain,f : { 0 }", + "/region1/eq0/vel2freq,f : { 0 }", + // No second eq + }; + REQUIRE(messageList == expected); + } + + SECTION("Test third region") + { + synth.dispatchMessage(client, 0, "/region2/eq0/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq0/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq0/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq0/vel2gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq0/vel2freq", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq3/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq3/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq3/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq3/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq3/vel2gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq3/vel2freq", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq1/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq2/frequency", "", nullptr); + std::vector expected { + // The first eq is default-filled + "/region2/eq0/gain,f : { 0 }", + "/region2/eq0/type,s : { peak }", + "/region2/eq0/bandwidth,f : { 1 }", + "/region2/eq0/frequency,f : { 50 }", + "/region2/eq0/vel2gain,f : { 0 }", + "/region2/eq0/vel2freq,f : { 0 }", + "/region2/eq3/gain,f : { 6 }", + "/region2/eq3/type,s : { peak }", + "/region2/eq3/bandwidth,f : { 1 }", + "/region2/eq3/frequency,f : { 0 }", + "/region2/eq3/vel2gain,f : { 0 }", + "/region2/eq3/vel2freq,f : { 0 }", + "/region2/eq1/frequency,f : { 500 }", + "/region2/eq2/frequency,f : { 5000 }", + }; + REQUIRE(messageList == expected); + } +} + +TEST_CASE("[Values] EQ types") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav eq1_type=hshelf + sample=kick.wav eq1_type=lshelf + sample=kick.wav eq1_type=hshelf eq1_type=peak + sample=kick.wav eq1_type=something + )"); + + synth.dispatchMessage(client, 0, "/region0/eq0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/eq0/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/eq0/type", "", nullptr); + std::vector expected { + "/region0/eq0/type,s : { hshelf }", + "/region1/eq0/type,s : { lshelf }", + "/region2/eq0/type,s : { peak }", + "/region3/eq0/type,s : { none }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] EQ dispatching") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + eq3_bw=2 eq1_gain=-25 eq2_freq=300 eq3_type=lshelf + eq3_vel2gain=10 eq1_vel2freq=100 + )"); + + synth.dispatchMessage(client, 0, "/region0/eq2/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq1/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq2/type", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq2/vel2gain", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/vel2freq", "", nullptr); + std::vector expected { + "/region0/eq2/bandwidth,f : { 2 }", + "/region0/eq0/gain,f : { -25 }", + "/region0/eq1/frequency,f : { 300 }", + "/region0/eq2/type,s : { lshelf }", + "/region0/eq2/vel2gain,f : { 10 }", + "/region0/eq0/vel2freq,f : { 100 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] EQ value bounds") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + SECTION("Frequency") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav eq1_freq=20000000 // Bound this to 30k + sample=kick.wav eq1_freq=50 eq1_freq=-100 + )"); + synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); + // TODO: activate after new parser; ignore OOB + // synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); + std::vector expected { + "/region0/eq0/frequency,f : { 30000 }", + // "/region0/eq0/frequency,f : { 50 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Bandwidth") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav eq1_bw=5 eq1_bw=-5 + )"); + // TODO: activate after new parser; ignore OOB + // synth.dispatchMessage(client, 0, "/region0/eq0/bandwidth", "", nullptr); + std::vector expected { + // "/region0/eq0/bandwidth,f : { 5 }", + }; + REQUIRE(messageList == expected); + } +} From c8e5483c59b969c8800b1e61363804c253b2e712 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 12 Dec 2020 11:48:47 +0100 Subject: [PATCH 129/668] Clean up ccModDepth/ccModParameters --- src/sfizz/Region.cpp | 46 +++++++++++++++++++++++--------------------- src/sfizz/Region.h | 22 ++++++++++++--------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 0c0b84c7..816211ba 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1932,35 +1932,37 @@ sfz::Region::Connection& sfz::Region::getOrCreateConnection(const ModKey& source return connections.back(); } +sfz::Region::Connection* sfz::Region::getConnectionFromCC(int sourceCC, const ModKey& target) +{ + for (sfz::Region::Connection& conn : connections) { + if (conn.source.id() == sfz::ModId::Controller && conn.target == target) { + auto p = conn.source.parameters(); + if (p.cc == sourceCC) + return &conn; + } + } + return nullptr; +} + bool sfz::Region::disabled() const noexcept { return (sampleEnd == 0); } -absl::optional sfz::Region::ccModDepth(int cc, ModId id) const noexcept +absl::optional sfz::Region::ccModDepth(int cc, ModId id, uint8_t N, uint8_t X, uint8_t Y, uint8_t Z) const noexcept { - const ModKey target = ModKey::createNXYZ(id, getId()); - for (const sfz::Region::Connection& conn : connections) { - if (conn.source.id() == sfz::ModId::Controller && conn.target == target) { - auto p = conn.source.parameters(); - if (p.cc == cc) - return conn.sourceDepth; - } - } - - return {}; + const ModKey target = ModKey::createNXYZ(id, getId(), N, X, Y, Z); + const Connection *conn = const_cast(this)->getConnectionFromCC(cc, target); + if (!conn) + return {}; + return conn->sourceDepth; } -absl::optional sfz::Region::ccModParameters(int cc, ModId id) const noexcept +absl::optional sfz::Region::ccModParameters(int cc, ModId id, uint8_t N, uint8_t X, uint8_t Y, uint8_t Z) const noexcept { - const ModKey target = ModKey::createNXYZ(id, getId()); - for (const sfz::Region::Connection& conn : connections) { - if (conn.source.id() == sfz::ModId::Controller && conn.target == target) { - auto p = conn.source.parameters(); - if (p.cc == cc) - return p; - } - } - - return {}; + const ModKey target = ModKey::createNXYZ(id, getId(), N, X, Y, Z); + const Connection *conn = const_cast(this)->getConnectionFromCC(cc, target); + if (!conn) + return {}; + return conn->source.parameters(); } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 384b090f..92ecf255 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -304,22 +304,25 @@ struct Region { bool disabled() const noexcept; /** - * @brief Extract the source depth modifier for a given cc and id. + * @brief Extract the source depth of the unique connection identified + * by a given CC and NXYZ target. * - * @param cc - * @param id + * @param cc the CC number of the modulation source + * @param id the ID of the modulation target, which must be regional * @return absl::optional */ - absl::optional ccModDepth(int cc, ModId id) const noexcept; + absl::optional ccModDepth(int cc, ModId id, uint8_t N = 0, uint8_t X = 0, uint8_t Y = 0, uint8_t Z = 0) const noexcept; /** - * @brief Extract the parameters for a given modulation cc and id. + * @brief Extract the source parameters of the unique connection identified + * by a given CC and NXYZ target. * - * @param cc - * @param id - * @return float + * @param cc the CC number of the modulation source + * @param cc the CC number of the modulation source + * @param id the ID of the modulation target, which must be regional + * @return absl::optional */ - absl::optional ccModParameters(int cc, ModId id) const noexcept; + absl::optional ccModParameters(int cc, ModId id, uint8_t N = 0, uint8_t X = 0, uint8_t Y = 0, uint8_t Z = 0) const noexcept; const NumericId id; @@ -466,6 +469,7 @@ struct Region { std::vector connections; Connection* getConnection(const ModKey& source, const ModKey& target); Connection& getOrCreateConnection(const ModKey& source, const ModKey& target); + Connection* getConnectionFromCC(int sourceCC, const ModKey& target); // Parent RegionSet* parent { nullptr }; From 686f285294bef819efa155ca2f17a7e0ec0c411d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 12 Dec 2020 11:52:09 +0100 Subject: [PATCH 130/668] Clean up indentation --- tests/RegionValueComputationsT.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/RegionValueComputationsT.cpp b/tests/RegionValueComputationsT.cpp index 60937f3d..f3b1abca 100644 --- a/tests/RegionValueComputationsT.cpp +++ b/tests/RegionValueComputationsT.cpp @@ -18,7 +18,7 @@ constexpr int numRandomTests { 64 }; TEST_CASE("[Region] Crossfade in on key") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lokey", "1" }); @@ -30,7 +30,7 @@ TEST_CASE("[Region] Crossfade in on key") TEST_CASE("[Region] Crossfade in on key - 2") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lokey", "1" }); @@ -45,7 +45,7 @@ TEST_CASE("[Region] Crossfade in on key - 2") TEST_CASE("[Region] Crossfade in on key - gain") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lokey", "1" }); @@ -60,7 +60,7 @@ TEST_CASE("[Region] Crossfade in on key - gain") TEST_CASE("[Region] Crossfade out on key") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_lokey", "51" }); @@ -76,7 +76,7 @@ TEST_CASE("[Region] Crossfade out on key") TEST_CASE("[Region] Crossfade out on key - gain") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_lokey", "51" }); @@ -93,7 +93,7 @@ TEST_CASE("[Region] Crossfade out on key - gain") TEST_CASE("[Region] Crossfade in on velocity") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lovel", "20" }); @@ -110,7 +110,7 @@ TEST_CASE("[Region] Crossfade in on velocity") TEST_CASE("[Region] Crossfade in on vel - gain") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_lovel", "20" }); @@ -128,7 +128,7 @@ TEST_CASE("[Region] Crossfade in on vel - gain") TEST_CASE("[Region] Crossfade out on vel") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_lovel", "51" }); @@ -145,7 +145,7 @@ TEST_CASE("[Region] Crossfade out on vel") TEST_CASE("[Region] Crossfade out on vel - gain") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_lovel", "51" }); @@ -163,7 +163,7 @@ TEST_CASE("[Region] Crossfade out on vel - gain") TEST_CASE("[Region] Crossfade in on CC") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_locc24", "20" }); @@ -187,7 +187,7 @@ TEST_CASE("[Region] Crossfade in on CC") TEST_CASE("[Region] Crossfade in on CC - gain") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfin_locc24", "20" }); @@ -211,7 +211,7 @@ TEST_CASE("[Region] Crossfade in on CC - gain") } TEST_CASE("[Region] Crossfade out on CC") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_locc24", "20" }); @@ -235,7 +235,7 @@ TEST_CASE("[Region] Crossfade out on CC") TEST_CASE("[Region] Crossfade out on CC - gain") { - MidiState midiState; + MidiState midiState; Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "xfout_locc24", "20" }); From 7ddf89bf5eba1e183ca9d126dac1069d09f0c730 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 12 Dec 2020 11:55:54 +0100 Subject: [PATCH 131/668] Add comment regarding performance [ci skip] --- src/sfizz/SynthMessaging.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 4e3285fa..cabb85ec 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -9,6 +9,8 @@ #include #include +// TODO: `ccModDepth` and `ccModParameters` are O(N), need better implementation + namespace sfz { static constexpr unsigned maxIndices = 8; From ec12e97a8872bd5af2ec5b82d61e5ebd0dd8b154 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 12 Dec 2020 13:46:33 +0100 Subject: [PATCH 132/668] Simplify the processing of vel2 opcodes --- src/sfizz/OpcodeCleanup.cpp | 1612 ++++++++++++++++++----------------- src/sfizz/OpcodeCleanup.re | 8 + src/sfizz/Region.cpp | 78 +- 3 files changed, 886 insertions(+), 812 deletions(-) diff --git a/src/sfizz/OpcodeCleanup.cpp b/src/sfizz/OpcodeCleanup.cpp index d61d8933..28c4aad8 100644 --- a/src/sfizz/OpcodeCleanup.cpp +++ b/src/sfizz/OpcodeCleanup.cpp @@ -1,4 +1,4 @@ -/* Generated by re2c 2.0.3 on Thu Nov 12 10:20:58 2020 */ +/* Generated by re2c 2.0.3 on Sat Dec 12 13:32:03 2020 */ #line 1 "src/sfizz/OpcodeCleanup.re" /* -*- mode: c++; -*- */ // SPDX-License-Identifier: BSD-2-Clause @@ -219,7 +219,7 @@ end_region_oncc: yy19: ++YYCURSOR; yy20: -#line 187 "src/sfizz/OpcodeCleanup.re" +#line 195 "src/sfizz/OpcodeCleanup.re" { goto end_region; } @@ -620,6 +620,7 @@ yy73: case 'g': yyt2 = YYCURSOR; goto yy101; + case 'v': goto yy102; default: goto yy34; } yy74: @@ -635,17 +636,17 @@ yy74: case '7': case '8': case '9': goto yy74; - case 't': goto yy102; + case 't': goto yy103; default: goto yy34; } yy76: yych = *++YYCURSOR; yyt1 = YYCURSOR; - goto yy106; + goto yy107; yy77: yych = *++YYCURSOR; switch (yych) { - case 'y': goto yy107; + case 'y': goto yy108; default: goto yy34; } yy78: @@ -653,16 +654,16 @@ yy78: switch (yych) { case 0x00: yyt2 = yyt3 = NULL; - goto yy108; + goto yy109; case '_': yyt3 = YYCURSOR; - goto yy110; + goto yy111; default: goto yy34; } yy79: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy111; + case 'a': goto yy112; default: goto yy34; } yy80: @@ -678,7 +679,7 @@ yy80: case '7': case '8': case '9': goto yy80; - case '_': goto yy112; + case '_': goto yy113; default: goto yy34; } yy82: @@ -686,37 +687,37 @@ yy82: switch (yych) { case 'e': yyt1 = YYCURSOR; - goto yy113; + goto yy114; case 'm': yyt1 = YYCURSOR; - goto yy114; + goto yy115; case 's': yyt1 = YYCURSOR; - goto yy115; + goto yy116; default: goto yy34; } yy83: yych = *++YYCURSOR; switch (yych) { - case 'y': goto yy116; + case 'y': goto yy117; default: goto yy34; } yy84: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy117; + case 'o': goto yy118; default: goto yy34; } yy85: yych = *++YYCURSOR; switch (yych) { - case 'i': goto yy118; + case 'i': goto yy119; default: goto yy34; } yy86: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy118; + case 'o': goto yy119; default: goto yy34; } yy87: @@ -728,13 +729,13 @@ yy87: yy88: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy119; + case 'p': goto yy120; default: goto yy34; } yy89: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy120; + case 'n': goto yy121; default: goto yy34; } yy90: @@ -742,268 +743,275 @@ yy90: switch (yych) { case 0x00: yyt2 = yyt3 = NULL; - goto yy121; + goto yy122; case '_': yyt3 = YYCURSOR; - goto yy123; + goto yy124; default: goto yy34; } yy91: yych = *++YYCURSOR; switch (yych) { - case '_': goto yy125; + case '_': goto yy126; default: goto yy34; } yy92: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy126; + case 'o': goto yy127; default: goto yy34; } yy93: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy127; + case 'o': goto yy128; default: goto yy34; } yy94: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy128; + case 't': goto yy129; default: goto yy34; } yy95: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy129; + case 'p': goto yy130; default: goto yy34; } yy96: yych = *++YYCURSOR; switch (yych) { - case 'f': goto yy130; + case 'f': goto yy131; default: goto yy34; } yy97: yych = *++YYCURSOR; switch (yych) { - case 'u': goto yy131; + case 'u': goto yy132; default: goto yy34; } yy98: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy132; + case 'e': goto yy133; default: goto yy34; } yy99: yych = *++YYCURSOR; switch (yych) { - case 'w': goto yy133; + case 'w': goto yy134; default: goto yy34; } yy100: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy134; + case 'r': goto yy135; default: goto yy34; } yy101: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy135; + case 'a': goto yy136; default: goto yy34; } yy102: yych = *++YYCURSOR; switch (yych) { - case 'y': goto yy136; + case 'e': goto yy137; default: goto yy34; } yy103: + yych = *++YYCURSOR; + switch (yych) { + case 'y': goto yy138; + default: goto yy34; + } +yy104: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; yypmatch[0] = yyt1 - 4; yypmatch[1] = YYCURSOR; yypmatch[3] = YYCURSOR - 1; -#line 169 "src/sfizz/OpcodeCleanup.re" +#line 177 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("fil1_", group(1)); goto end_region; } -#line 836 "src/sfizz/OpcodeCleanup.cpp" -yy105: - yych = *++YYCURSOR; +#line 843 "src/sfizz/OpcodeCleanup.cpp" yy106: - if (yych <= 0x00) goto yy103; - goto yy105; + yych = *++YYCURSOR; yy107: + if (yych <= 0x00) goto yy104; + goto yy106; +yy108: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy137; + case 'p': goto yy139; default: goto yy34; } -yy108: +yy109: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; yypmatch[2] = yyt3; yypmatch[3] = yyt2; yypmatch[1] = YYCURSOR; -#line 146 "src/sfizz/OpcodeCleanup.re" +#line 154 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("volume", group(1)); goto end_region; } -#line 860 "src/sfizz/OpcodeCleanup.cpp" -yy110: - yych = *++YYCURSOR; - switch (yych) { - case 'r': goto yy140; - default: goto yy139; - } +#line 867 "src/sfizz/OpcodeCleanup.cpp" yy111: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy141; - default: goto yy34; + case 'r': goto yy142; + default: goto yy141; } yy112: yych = *++YYCURSOR; switch (yych) { - case 'c': - yyt2 = YYCURSOR; - goto yy142; - case 'o': - yyt2 = YYCURSOR; - goto yy143; - case 'r': - yyt2 = YYCURSOR; - goto yy144; - case 's': - yyt2 = YYCURSOR; - goto yy145; - case 'w': - yyt2 = YYCURSOR; - goto yy146; + case 'l': goto yy143; default: goto yy34; } yy113: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy147; + case 'c': + yyt2 = YYCURSOR; + goto yy144; + case 'o': + yyt2 = YYCURSOR; + goto yy145; + case 'r': + yyt2 = YYCURSOR; + goto yy146; + case 's': + yyt2 = YYCURSOR; + goto yy147; + case 'w': + yyt2 = YYCURSOR; + goto yy148; default: goto yy34; } yy114: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy148; + case 'n': goto yy149; default: goto yy34; } yy115: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy149; + case 'o': goto yy150; default: goto yy34; } yy116: - yych = *++YYCURSOR; - if (yych <= 0x00) goto yy150; - goto yy34; -yy117: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy152; + case 't': goto yy151; default: goto yy34; } +yy117: + yych = *++YYCURSOR; + if (yych <= 0x00) goto yy152; + goto yy34; yy118: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy153; - case 'h': goto yy154; + case 'd': goto yy154; default: goto yy34; } yy119: yych = *++YYCURSOR; switch (yych) { - case 'h': goto yy155; + case 'c': goto yy155; + case 'h': goto yy156; default: goto yy34; } yy120: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy156; + case 'h': goto yy157; default: goto yy34; } yy121: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy158; + default: goto yy34; + } +yy122: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; yypmatch[2] = yyt3; yypmatch[3] = yyt2; yypmatch[1] = YYCURSOR; -#line 150 "src/sfizz/OpcodeCleanup.re" +#line 158 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("pitch", group(1)); goto end_region; } -#line 952 "src/sfizz/OpcodeCleanup.cpp" -yy123: +#line 959 "src/sfizz/OpcodeCleanup.cpp" +yy124: yych = *++YYCURSOR; if (yych <= 0x00) { yyt2 = YYCURSOR; - goto yy121; + goto yy122; } - goto yy123; -yy125: + goto yy124; +yy126: yych = *++YYCURSOR; switch (yych) { case 'a': yyt2 = YYCURSOR; - goto yy157; + goto yy159; case 'd': yyt2 = YYCURSOR; - goto yy158; + goto yy160; case 'h': yyt2 = YYCURSOR; - goto yy159; + goto yy161; case 'r': yyt2 = YYCURSOR; - goto yy160; + goto yy162; case 's': yyt2 = YYCURSOR; - goto yy161; - default: goto yy34; - } -yy126: - yych = *++YYCURSOR; - switch (yych) { - case '_': goto yy162; + goto yy163; + case 'v': goto yy164; default: goto yy34; } yy127: yych = *++YYCURSOR; switch (yych) { - case 'w': goto yy163; + case '_': goto yy165; default: goto yy34; } yy128: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy95; + case 'w': goto yy166; default: goto yy34; } yy129: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy164; - goto yy34; + switch (yych) { + case 'e': goto yy95; + default: goto yy34; + } yy130: + yych = *++YYCURSOR; + if (yych <= 0x00) goto yy167; + goto yy34; +yy131: yych = *++YYCURSOR; switch (yych) { case 0x00: yyt2 = yyt3 = NULL; - goto yy166; + goto yy169; case '0': case '1': case '2': @@ -1015,242 +1023,254 @@ yy130: case '8': case '9': yyt2 = YYCURSOR; - goto yy168; + goto yy171; case '_': yyt2 = yyt4 = NULL; yyt3 = YYCURSOR; - goto yy170; - default: goto yy34; - } -yy131: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy171; + goto yy173; default: goto yy34; } yy132: yych = *++YYCURSOR; switch (yych) { - case 's': goto yy172; + case 't': goto yy174; default: goto yy34; } yy133: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy173; + case 's': goto yy175; default: goto yy34; } yy134: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy174; + case 'c': goto yy176; default: goto yy34; } yy135: yych = *++YYCURSOR; switch (yych) { - case 'i': goto yy175; + case 'e': goto yy177; default: goto yy34; } yy136: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy176; + case 'i': goto yy178; default: goto yy34; } yy137: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy177; + case 'l': goto yy179; default: goto yy34; } yy138: yych = *++YYCURSOR; -yy139: - if (yych <= 0x00) { - yyt2 = YYCURSOR; - goto yy108; - } - goto yy138; -yy140: - yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy178; - default: goto yy139; - } -yy141: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy179; + case 'p': goto yy180; default: goto yy34; } +yy139: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy181; + default: goto yy34; + } +yy140: + yych = *++YYCURSOR; +yy141: + if (yych <= 0x00) { + yyt2 = YYCURSOR; + goto yy109; + } + goto yy140; yy142: yych = *++YYCURSOR; switch (yych) { - case 'u': goto yy180; - default: goto yy34; + case 'a': goto yy182; + default: goto yy141; } yy143: yych = *++YYCURSOR; switch (yych) { - case 'f': goto yy181; + case 'c': goto yy183; default: goto yy34; } yy144: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy182; - case 'e': goto yy183; + case 'u': goto yy184; default: goto yy34; } yy145: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy184; + case 'f': goto yy185; default: goto yy34; } yy146: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy185; + case 'a': goto yy186; + case 'e': goto yy187; default: goto yy34; } yy147: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy186; + case 'c': goto yy188; default: goto yy34; } yy148: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy187; + case 'a': goto yy189; default: goto yy34; } yy149: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy188; + case 'd': goto yy190; default: goto yy34; } yy150: + yych = *++YYCURSOR; + switch (yych) { + case 'd': goto yy191; + default: goto yy34; + } +yy151: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy192; + default: goto yy34; + } +yy152: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; yypmatch[0] = yyt1 - 3; yypmatch[1] = YYCURSOR; yypmatch[3] = YYCURSOR - 1; -#line 119 "src/sfizz/OpcodeCleanup.re" +#line 127 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("off_", group(1)); goto end_region; } -#line 1149 "src/sfizz/OpcodeCleanup.cpp" -yy152: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy116; - default: goto yy34; - } -yy153: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy189; - default: goto yy34; - } +#line 1163 "src/sfizz/OpcodeCleanup.cpp" yy154: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy190; + case 'e': goto yy117; default: goto yy34; } yy155: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy191; + case 'c': goto yy193; default: goto yy34; } yy156: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy192; + case 'd': goto yy194; default: goto yy34; } yy157: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy193; + case 'o': goto yy195; default: goto yy34; } yy158: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy194; + case 'n': goto yy196; default: goto yy34; } yy159: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy195; + case 't': goto yy197; default: goto yy34; } yy160: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy196; + case 'e': goto yy198; default: goto yy34; } yy161: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy197; - case 'u': goto yy198; + case 'o': goto yy199; default: goto yy34; } yy162: yych = *++YYCURSOR; switch (yych) { - case 'd': - yyt2 = YYCURSOR; - goto yy199; - case 'f': - yyt2 = YYCURSOR; - goto yy200; + case 'e': goto yy200; default: goto yy34; } yy163: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy129; + case 't': goto yy201; + case 'u': goto yy202; default: goto yy34; } yy164: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy203; + default: goto yy34; + } +yy165: + yych = *++YYCURSOR; + switch (yych) { + case 'd': + yyt2 = YYCURSOR; + goto yy204; + case 'f': + yyt2 = YYCURSOR; + goto yy205; + default: goto yy34; + } +yy166: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy130; + default: goto yy34; + } +yy167: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; yypmatch[0] = yyt1 - 4; yypmatch[1] = YYCURSOR; yypmatch[3] = YYCURSOR - 1; -#line 123 "src/sfizz/OpcodeCleanup.re" +#line 131 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("bend_", group(1)); goto end_region; } -#line 1240 "src/sfizz/OpcodeCleanup.cpp" -yy166: +#line 1260 "src/sfizz/OpcodeCleanup.cpp" +yy169: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; yypmatch[2] = yyt3; yypmatch[3] = yyt2; yypmatch[1] = YYCURSOR; -#line 173 "src/sfizz/OpcodeCleanup.re" +#line 181 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("cutoff1", group(1)); goto end_region; } -#line 1253 "src/sfizz/OpcodeCleanup.cpp" -yy168: +#line 1273 "src/sfizz/OpcodeCleanup.cpp" +yy171: yych = *++YYCURSOR; switch (yych) { case '0': @@ -1262,123 +1282,129 @@ yy168: case '6': case '7': case '8': - case '9': goto yy168; + case '9': goto yy171; case '_': yyt4 = YYCURSOR; - goto yy201; - default: goto yy34; - } -yy170: - yych = *++YYCURSOR; - switch (yych) { - case 'r': goto yy204; - default: goto yy203; - } -yy171: - yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy205; - default: goto yy34; - } -yy172: - yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy206; + goto yy206; default: goto yy34; } yy173: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy207; - default: goto yy34; + case 'r': goto yy209; + default: goto yy208; } yy174: yych = *++YYCURSOR; switch (yych) { - case 'q': goto yy133; + case 'o': goto yy210; default: goto yy34; } yy175: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy133; + case 'o': goto yy211; default: goto yy34; } yy176: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy208; + case 'c': goto yy212; default: goto yy34; } yy177: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy209; - goto yy34; + switch (yych) { + case 'q': goto yy134; + default: goto yy34; + } yy178: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy211; - default: goto yy139; + case 'n': goto yy134; + default: goto yy34; } yy179: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy212; + case '2': goto yy213; default: goto yy34; } yy180: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy213; + case 'e': goto yy214; default: goto yy34; } yy181: yych = *++YYCURSOR; - switch (yych) { - case 'f': goto yy214; - default: goto yy34; - } + if (yych <= 0x00) goto yy215; + goto yy34; yy182: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy215; - default: goto yy34; + case 'n': goto yy217; + default: goto yy141; } yy183: yych = *++YYCURSOR; switch (yych) { - case 's': goto yy216; + case 'c': goto yy218; default: goto yy34; } yy184: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy217; + case 't': goto yy219; default: goto yy34; } yy185: yych = *++YYCURSOR; switch (yych) { - case 'v': goto yy218; + case 'f': goto yy220; default: goto yy34; } yy186: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy219; - goto yy34; + switch (yych) { + case 't': goto yy221; + default: goto yy34; + } yy187: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy186; + case 's': goto yy222; default: goto yy34; } yy188: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy221; + case 'a': goto yy223; default: goto yy34; } yy189: + yych = *++YYCURSOR; + switch (yych) { + case 'v': goto yy224; + default: goto yy34; + } +yy190: + yych = *++YYCURSOR; + if (yych <= 0x00) goto yy225; + goto yy34; +yy191: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy190; + default: goto yy34; + } +yy192: + yych = *++YYCURSOR; + switch (yych) { + case 'r': goto yy227; + default: goto yy34; + } +yy193: yych = *++YYCURSOR; switch (yych) { case '0': @@ -1392,146 +1418,114 @@ yy189: case '8': case '9': yyt1 = YYCURSOR; - goto yy222; - default: goto yy34; - } -yy190: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy224; - default: goto yy34; - } -yy191: - yych = *++YYCURSOR; - switch (yych) { - case 'n': goto yy225; - default: goto yy34; - } -yy192: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy226; - default: goto yy34; - } -yy193: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy227; + goto yy228; default: goto yy34; } yy194: yych = *++YYCURSOR; switch (yych) { - case 'c': - case 'l': goto yy228; + case 'c': goto yy230; default: goto yy34; } yy195: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy229; + case 'n': goto yy231; default: goto yy34; } yy196: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy230; + case 'c': goto yy232; default: goto yy34; } yy197: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy231; + case 't': goto yy233; default: goto yy34; } yy198: yych = *++YYCURSOR; switch (yych) { - case 's': goto yy232; + case 'c': + case 'l': goto yy234; default: goto yy34; } yy199: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy233; + case 'l': goto yy235; default: goto yy34; } yy200: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy234; - case 'r': goto yy235; + case 'l': goto yy236; default: goto yy34; } yy201: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy236; + case 'a': goto yy237; default: goto yy34; } yy202: yych = *++YYCURSOR; -yy203: - if (yych <= 0x00) { - yyt2 = YYCURSOR; - goto yy166; + switch (yych) { + case 's': goto yy238; + default: goto yy34; + } +yy203: + yych = *++YYCURSOR; + switch (yych) { + case 'l': goto yy239; + default: goto yy34; } - goto yy202; yy204: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy237; - default: goto yy203; + case 'e': goto yy240; + default: goto yy34; } yy205: yych = *++YYCURSOR; switch (yych) { - case 'f': goto yy238; + case 'a': goto yy241; + case 'r': goto yy242; default: goto yy34; } yy206: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy239; + case 'r': goto yy243; default: goto yy34; } yy207: yych = *++YYCURSOR; +yy208: + if (yych <= 0x00) { + yyt2 = YYCURSOR; + goto yy169; + } + goto yy207; +yy209: + yych = *++YYCURSOR; switch (yych) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - yyt3 = YYCURSOR; - goto yy240; + case 'a': goto yy244; + default: goto yy208; + } +yy210: + yych = *++YYCURSOR; + switch (yych) { + case 'f': goto yy245; default: goto yy34; } -yy208: - yych = *++YYCURSOR; - if (yych <= 0x00) goto yy242; - goto yy34; -yy209: - ++YYCURSOR; - yynmatch = 1; - yypmatch[0] = YYCURSOR - 8; - yypmatch[1] = YYCURSOR; -#line 127 "src/sfizz/OpcodeCleanup.re" - { - opcode = absl::StrCat("fil1_type"); - goto end_region; - } -#line 1530 "src/sfizz/OpcodeCleanup.cpp" yy211: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy244; - default: goto yy139; + case 'n': goto yy246; + default: goto yy34; } yy212: yych = *++YYCURSOR; @@ -1546,272 +1540,36 @@ yy212: case '7': case '8': case '9': - yyt1 = YYCURSOR; - goto yy245; + yyt3 = YYCURSOR; + goto yy247; default: goto yy34; } yy213: yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy247; - default: goto yy34; - } + yyt2 = YYCURSOR; + goto yy252; yy214: yych = *++YYCURSOR; - switch (yych) { - case 's': goto yy248; - default: goto yy34; - } + if (yych <= 0x00) goto yy253; + goto yy34; yy215: - yych = *++YYCURSOR; - switch (yych) { - case 'i': goto yy249; - default: goto yy34; - } -yy216: - yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy250; - default: goto yy34; - } + ++YYCURSOR; + yynmatch = 1; + yypmatch[0] = YYCURSOR - 8; + yypmatch[1] = YYCURSOR; +#line 135 "src/sfizz/OpcodeCleanup.re" + { + opcode = absl::StrCat("fil1_type"); + goto end_region; + } +#line 1566 "src/sfizz/OpcodeCleanup.cpp" yy217: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy218; - default: goto yy34; + case 'd': goto yy255; + default: goto yy141; } yy218: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy251; - default: goto yy34; - } -yy219: - ++YYCURSOR; - yynmatch = 2; - yypmatch[2] = yyt1; - yypmatch[0] = yyt1 - 4; - yypmatch[1] = YYCURSOR; - yypmatch[3] = YYCURSOR - 1; -#line 115 "src/sfizz/OpcodeCleanup.re" - { - opcode = absl::StrCat("loop_", group(1)); - goto end_region; - } -#line 1602 "src/sfizz/OpcodeCleanup.cpp" -yy221: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy186; - default: goto yy34; - } -yy222: - yych = *++YYCURSOR; - switch (yych) { - case 0x00: goto yy252; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': goto yy222; - default: goto yy34; - } -yy224: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy254; - default: goto yy34; - } -yy225: - yych = *++YYCURSOR; - switch (yych) { - case 'y': goto yy255; - default: goto yy34; - } -yy226: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy256; - default: goto yy34; - } -yy227: - yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy257; - default: goto yy34; - } -yy228: - yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy258; - default: goto yy34; - } -yy229: - yych = *++YYCURSOR; - switch (yych) { - case 'd': goto yy259; - default: goto yy34; - } -yy230: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy260; - default: goto yy34; - } -yy231: - yych = *++YYCURSOR; - switch (yych) { - case 'r': goto yy261; - default: goto yy34; - } -yy232: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy262; - default: goto yy34; - } -yy233: - yych = *++YYCURSOR; - switch (yych) { - case 'p': goto yy263; - default: goto yy34; - } -yy234: - yych = *++YYCURSOR; - switch (yych) { - case 'd': goto yy264; - default: goto yy34; - } -yy235: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy265; - default: goto yy34; - } -yy236: - yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy266; - default: goto yy34; - } -yy237: - yych = *++YYCURSOR; - switch (yych) { - case 'n': goto yy267; - default: goto yy203; - } -yy238: - yych = *++YYCURSOR; - switch (yych) { - case 'f': goto yy268; - default: goto yy34; - } -yy239: - yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy269; - default: goto yy34; - } -yy240: - yych = *++YYCURSOR; - switch (yych) { - case 0x00: goto yy270; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': goto yy240; - default: goto yy34; - } -yy242: - ++YYCURSOR; - yynmatch = 2; - yypmatch[2] = yyt1; - yypmatch[0] = yyt1 - 3; - yypmatch[1] = YYCURSOR; - yypmatch[3] = YYCURSOR - 5; -#line 131 "src/sfizz/OpcodeCleanup.re" - { - opcode = absl::StrCat("fil", group(1), "_type"); - goto end_region; - } -#line 1749 "src/sfizz/OpcodeCleanup.cpp" -yy244: - yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy272; - default: goto yy139; - } -yy245: - yych = *++YYCURSOR; - switch (yych) { - case 0x00: goto yy273; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': goto yy245; - default: goto yy34; - } -yy247: - yych = *++YYCURSOR; - switch (yych) { - case 'f': goto yy275; - default: goto yy34; - } -yy248: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy276; - default: goto yy34; - } -yy249: - yych = *++YYCURSOR; - switch (yych) { - case 'o': goto yy251; - default: goto yy34; - } -yy250: - yych = *++YYCURSOR; - switch (yych) { - case 'n': goto yy277; - default: goto yy34; - } -yy251: - yych = *++YYCURSOR; - if (yych <= 0x00) goto yy278; - goto yy34; -yy252: - ++YYCURSOR; - yynmatch = 3; - yypmatch[4] = yyt1; - yypmatch[0] = yyt1 - 7; - yypmatch[1] = YYCURSOR; - yypmatch[2] = yyt1 - 4; - yypmatch[3] = yyt1 - 2; - yypmatch[5] = YYCURSOR - 1; -#line 155 "src/sfizz/OpcodeCleanup.re" - { - opcode = absl::StrCat("start_", group(1), "cc", group(2)); - goto end_region; - } -#line 1814 "src/sfizz/OpcodeCleanup.cpp" -yy254: yych = *++YYCURSOR; switch (yych) { case '0': @@ -1825,111 +1583,419 @@ yy254: case '8': case '9': yyt1 = YYCURSOR; - goto yy280; + goto yy256; default: goto yy34; } +yy219: + yych = *++YYCURSOR; + switch (yych) { + case 'o': goto yy258; + default: goto yy34; + } +yy220: + yych = *++YYCURSOR; + switch (yych) { + case 's': goto yy259; + default: goto yy34; + } +yy221: + yych = *++YYCURSOR; + switch (yych) { + case 'i': goto yy260; + default: goto yy34; + } +yy222: + yych = *++YYCURSOR; + switch (yych) { + case 'o': goto yy261; + default: goto yy34; + } +yy223: + yych = *++YYCURSOR; + switch (yych) { + case 'l': goto yy224; + default: goto yy34; + } +yy224: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy262; + default: goto yy34; + } +yy225: + ++YYCURSOR; + yynmatch = 2; + yypmatch[2] = yyt1; + yypmatch[0] = yyt1 - 4; + yypmatch[1] = YYCURSOR; + yypmatch[3] = YYCURSOR - 1; +#line 123 "src/sfizz/OpcodeCleanup.re" + { + opcode = absl::StrCat("loop_", group(1)); + goto end_region; + } +#line 1638 "src/sfizz/OpcodeCleanup.cpp" +yy227: + yych = *++YYCURSOR; + switch (yych) { + case 't': goto yy190; + default: goto yy34; + } +yy228: + yych = *++YYCURSOR; + switch (yych) { + case 0x00: goto yy263; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy228; + default: goto yy34; + } +yy230: + yych = *++YYCURSOR; + switch (yych) { + case 'c': goto yy265; + default: goto yy34; + } +yy231: + yych = *++YYCURSOR; + switch (yych) { + case 'y': goto yy266; + default: goto yy34; + } +yy232: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy267; + default: goto yy34; + } +yy233: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy268; + default: goto yy34; + } +yy234: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy269; + default: goto yy34; + } +yy235: + yych = *++YYCURSOR; + switch (yych) { + case 'd': goto yy270; + default: goto yy34; + } +yy236: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy271; + default: goto yy34; + } +yy237: + yych = *++YYCURSOR; + switch (yych) { + case 'r': goto yy272; + default: goto yy34; + } +yy238: + yych = *++YYCURSOR; + switch (yych) { + case 't': goto yy273; + default: goto yy34; + } +yy239: + yych = *++YYCURSOR; + switch (yych) { + case '2': goto yy274; + default: goto yy34; + } +yy240: + yych = *++YYCURSOR; + switch (yych) { + case 'p': goto yy275; + default: goto yy34; + } +yy241: + yych = *++YYCURSOR; + switch (yych) { + case 'd': goto yy276; + default: goto yy34; + } +yy242: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy277; + default: goto yy34; + } +yy243: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy278; + default: goto yy34; + } +yy244: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy279; + default: goto yy208; + } +yy245: + yych = *++YYCURSOR; + switch (yych) { + case 'f': goto yy280; + default: goto yy34; + } +yy246: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy281; + default: goto yy34; + } +yy247: + yych = *++YYCURSOR; + switch (yych) { + case 0x00: goto yy282; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy247; + default: goto yy34; + } +yy249: + ++YYCURSOR; + yynmatch = 3; + yypmatch[2] = yyt1; + yypmatch[4] = yyt2; + yypmatch[0] = yyt1; + yypmatch[1] = YYCURSOR; + yypmatch[3] = yyt2 - 5; + yypmatch[5] = YYCURSOR - 1; +#line 107 "src/sfizz/OpcodeCleanup.re" + { + opcode = absl::StrCat(group(1), "_velto", group(2)); + goto end_region; + } +#line 1793 "src/sfizz/OpcodeCleanup.cpp" +yy251: + yych = *++YYCURSOR; +yy252: + if (yych <= 0x00) goto yy249; + goto yy251; +yy253: + ++YYCURSOR; + yynmatch = 2; + yypmatch[2] = yyt1; + yypmatch[0] = yyt1 - 3; + yypmatch[1] = YYCURSOR; + yypmatch[3] = YYCURSOR - 5; +#line 139 "src/sfizz/OpcodeCleanup.re" + { + opcode = absl::StrCat("fil", group(1), "_type"); + goto end_region; + } +#line 1811 "src/sfizz/OpcodeCleanup.cpp" yy255: yych = *++YYCURSOR; switch (yych) { - case '_': goto yy282; - default: goto yy34; + case 'o': goto yy284; + default: goto yy141; } yy256: yych = *++YYCURSOR; switch (yych) { - case 0x00: - yyt2 = yyt3 = NULL; - goto yy283; - case '_': - yyt3 = YYCURSOR; - goto yy285; - default: goto yy34; - } -yy257: - yych = *++YYCURSOR; - switch (yych) { - case 'c': goto yy287; + case 0x00: goto yy285; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy256; default: goto yy34; } yy258: yych = *++YYCURSOR; switch (yych) { - case 'y': goto yy259; + case 'f': goto yy287; default: goto yy34; } yy259: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy288; + case 'e': goto yy288; default: goto yy34; } yy260: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy289; + case 'o': goto yy262; default: goto yy34; } yy261: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy259; + case 'n': goto yy289; default: goto yy34; } yy262: yych = *++YYCURSOR; - switch (yych) { - case 'a': goto yy290; - default: goto yy34; - } + if (yych <= 0x00) goto yy290; + goto yy34; yy263: - yych = *++YYCURSOR; - switch (yych) { - case 't': goto yy291; - default: goto yy34; - } -yy264: - yych = *++YYCURSOR; - switch (yych) { - case 'e': goto yy292; - default: goto yy34; - } + ++YYCURSOR; + yynmatch = 3; + yypmatch[4] = yyt1; + yypmatch[0] = yyt1 - 7; + yypmatch[1] = YYCURSOR; + yypmatch[2] = yyt1 - 4; + yypmatch[3] = yyt1 - 2; + yypmatch[5] = YYCURSOR - 1; +#line 163 "src/sfizz/OpcodeCleanup.re" + { + opcode = absl::StrCat("start_", group(1), "cc", group(2)); + goto end_region; + } +#line 1876 "src/sfizz/OpcodeCleanup.cpp" yy265: yych = *++YYCURSOR; switch (yych) { - case 'q': goto yy292; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + yyt1 = YYCURSOR; + goto yy292; default: goto yy34; } yy266: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy293; + case '_': goto yy294; default: goto yy34; } yy267: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy294; - default: goto yy203; + case 0x00: + yyt2 = yyt3 = NULL; + goto yy295; + case '_': + yyt3 = YYCURSOR; + goto yy297; + default: goto yy34; } yy268: yych = *++YYCURSOR; switch (yych) { - case 0x00: - yyt4 = yyt5 = NULL; - yyt3 = YYCURSOR; - goto yy295; - case '_': - yyt3 = yyt5 = YYCURSOR; - goto yy297; + case 'c': goto yy299; default: goto yy34; } yy269: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy299; + case 'y': goto yy270; default: goto yy34; } yy270: + yych = *++YYCURSOR; + switch (yych) { + case 'c': goto yy300; + default: goto yy34; + } +yy271: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy301; + default: goto yy34; + } +yy272: + yych = *++YYCURSOR; + switch (yych) { + case 't': goto yy270; + default: goto yy34; + } +yy273: + yych = *++YYCURSOR; + switch (yych) { + case 'a': goto yy302; + default: goto yy34; + } +yy274: + yych = *++YYCURSOR; + yyt2 = YYCURSOR; + goto yy306; +yy275: + yych = *++YYCURSOR; + switch (yych) { + case 't': goto yy307; + default: goto yy34; + } +yy276: + yych = *++YYCURSOR; + switch (yych) { + case 'e': goto yy308; + default: goto yy34; + } +yy277: + yych = *++YYCURSOR; + switch (yych) { + case 'q': goto yy308; + default: goto yy34; + } +yy278: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy309; + default: goto yy34; + } +yy279: + yych = *++YYCURSOR; + switch (yych) { + case 'd': goto yy310; + default: goto yy208; + } +yy280: + yych = *++YYCURSOR; + switch (yych) { + case 0x00: + yyt4 = yyt5 = NULL; + yyt3 = YYCURSOR; + goto yy311; + case '_': + yyt3 = yyt5 = YYCURSOR; + goto yy313; + default: goto yy34; + } +yy281: + yych = *++YYCURSOR; + switch (yych) { + case 'n': goto yy315; + default: goto yy34; + } +yy282: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -1940,19 +2006,19 @@ yy270: yypmatch[3] = yyt2 - 1; yypmatch[5] = yyt3 - 2; yypmatch[7] = YYCURSOR - 1; -#line 99 "src/sfizz/OpcodeCleanup.re" +#line 103 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); goto end_region; } -#line 1949 "src/sfizz/OpcodeCleanup.cpp" -yy272: +#line 2015 "src/sfizz/OpcodeCleanup.cpp" +yy284: yych = *++YYCURSOR; switch (yych) { - case 'm': goto yy300; - default: goto yy139; + case 'm': goto yy316; + default: goto yy141; } -yy273: +yy285: ++YYCURSOR; yynmatch = 3; yypmatch[4] = yyt1; @@ -1961,31 +2027,31 @@ yy273: yypmatch[2] = yyt1 - 8; yypmatch[3] = yyt1 - 6; yypmatch[5] = YYCURSOR - 1; -#line 182 "src/sfizz/OpcodeCleanup.re" +#line 190 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat(group(1), "hdcc", group(2)); goto end_region; } -#line 1970 "src/sfizz/OpcodeCleanup.cpp" -yy275: +#line 2036 "src/sfizz/OpcodeCleanup.cpp" +yy287: yych = *++YYCURSOR; switch (yych) { - case 'f': goto yy301; + case 'f': goto yy317; default: goto yy34; } -yy276: +yy288: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy251; + case 't': goto yy262; default: goto yy34; } -yy277: +yy289: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy302; + case 'a': goto yy318; default: goto yy34; } -yy278: +yy290: ++YYCURSOR; yynmatch = 3; yypmatch[2] = yyt1; @@ -1994,16 +2060,16 @@ yy278: yypmatch[1] = YYCURSOR; yypmatch[3] = yyt2 - 1; yypmatch[5] = YYCURSOR - 1; -#line 103 "src/sfizz/OpcodeCleanup.re" +#line 111 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat(group(1), "_", group(2), "1"); goto end_region; } -#line 2003 "src/sfizz/OpcodeCleanup.cpp" -yy280: +#line 2069 "src/sfizz/OpcodeCleanup.cpp" +yy292: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy303; + case 0x00: goto yy319; case '0': case '1': case '2': @@ -2013,84 +2079,104 @@ yy280: case '6': case '7': case '8': - case '9': goto yy280; + case '9': goto yy292; default: goto yy34; } -yy282: +yy294: yych = *++YYCURSOR; switch (yych) { - case 'g': goto yy305; + case 'g': goto yy321; default: goto yy34; } -yy283: +yy295: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; yypmatch[2] = yyt3; yypmatch[3] = yyt2; yypmatch[1] = YYCURSOR; -#line 177 "src/sfizz/OpcodeCleanup.re" +#line 185 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("resonance1", group(1)); goto end_region; } -#line 2038 "src/sfizz/OpcodeCleanup.cpp" -yy285: +#line 2104 "src/sfizz/OpcodeCleanup.cpp" +yy297: yych = *++YYCURSOR; if (yych <= 0x00) { yyt2 = YYCURSOR; - goto yy283; + goto yy295; } - goto yy285; -yy287: + goto yy297; +yy299: yych = *++YYCURSOR; switch (yych) { - case 'k': goto yy259; + case 'k': goto yy270; default: goto yy34; } -yy288: +yy300: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy306; + case 'c': goto yy322; default: goto yy34; } -yy289: +yy301: yych = *++YYCURSOR; switch (yych) { - case 's': goto yy307; + case 's': goto yy323; default: goto yy34; } -yy290: +yy302: yych = *++YYCURSOR; switch (yych) { - case 'i': goto yy308; + case 'i': goto yy324; default: goto yy34; } -yy291: +yy303: + ++YYCURSOR; + yynmatch = 3; + yypmatch[2] = yyt1; + yypmatch[4] = yyt2; + yypmatch[0] = yyt1; + yypmatch[1] = YYCURSOR; + yypmatch[3] = yyt2 - 5; + yypmatch[5] = YYCURSOR - 1; +#line 99 "src/sfizz/OpcodeCleanup.re" + { + opcode = absl::StrCat(group(1), "_velto", group(2)); + goto end_region; + } +#line 2150 "src/sfizz/OpcodeCleanup.cpp" +yy305: + yych = *++YYCURSOR; +yy306: + if (yych <= 0x00) goto yy303; + goto yy305; +yy307: yych = *++YYCURSOR; switch (yych) { - case 'h': goto yy292; + case 'h': goto yy308; default: goto yy34; } -yy292: +yy308: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy309; + case 'c': goto yy325; default: goto yy34; } -yy293: +yy309: yych = *++YYCURSOR; switch (yych) { - case 'd': goto yy310; + case 'd': goto yy326; default: goto yy34; } -yy294: +yy310: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy311; - default: goto yy203; + case 'o': goto yy327; + default: goto yy208; } -yy295: +yy311: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -2101,48 +2187,48 @@ yy295: yypmatch[0] = yyt1; yypmatch[1] = YYCURSOR; yypmatch[3] = yyt2 - 1; -#line 111 "src/sfizz/OpcodeCleanup.re" +#line 119 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat(group(1), "_", group(2), "1", group(3)); goto end_region; } -#line 2110 "src/sfizz/OpcodeCleanup.cpp" -yy297: +#line 2196 "src/sfizz/OpcodeCleanup.cpp" +yy313: yych = *++YYCURSOR; if (yych <= 0x00) { yyt4 = YYCURSOR; - goto yy295; + goto yy311; } - goto yy297; -yy299: + goto yy313; +yy315: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy312; + case 'c': goto yy328; default: goto yy34; } -yy300: +yy316: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy313; - goto yy138; -yy301: + if (yych <= 0x00) goto yy329; + goto yy140; +yy317: yych = *++YYCURSOR; switch (yych) { case 0x00: yyt4 = yyt5 = NULL; yyt3 = YYCURSOR; - goto yy315; + goto yy331; case '_': yyt3 = yyt5 = YYCURSOR; - goto yy317; + goto yy333; default: goto yy34; } -yy302: +yy318: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy319; + case 'n': goto yy335; default: goto yy34; } -yy303: +yy319: ++YYCURSOR; yynmatch = 3; yypmatch[4] = yyt1; @@ -2151,19 +2237,19 @@ yy303: yypmatch[2] = yyt1 - 6; yypmatch[3] = yyt1 - 4; yypmatch[5] = YYCURSOR - 1; -#line 159 "src/sfizz/OpcodeCleanup.re" +#line 167 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("start_", group(1), "hdcc", group(2)); goto end_region; } -#line 2160 "src/sfizz/OpcodeCleanup.cpp" -yy305: +#line 2246 "src/sfizz/OpcodeCleanup.cpp" +yy321: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy320; + case 'r': goto yy336; default: goto yy34; } -yy306: +yy322: yych = *++YYCURSOR; switch (yych) { case '0': @@ -2177,57 +2263,57 @@ yy306: case '8': case '9': yyt3 = YYCURSOR; - goto yy321; + goto yy337; default: goto yy34; } -yy307: +yy323: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy259; + case 'e': goto yy270; default: goto yy34; } -yy308: +yy324: yych = *++YYCURSOR; switch (yych) { - case 'n': goto yy259; + case 'n': goto yy270; default: goto yy34; } -yy309: +yy325: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy323; + case 'c': goto yy339; default: goto yy34; } -yy310: +yy326: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy324; + case 'o': goto yy340; default: goto yy34; } -yy311: +yy327: yych = *++YYCURSOR; switch (yych) { - case 'm': goto yy325; - default: goto yy203; + case 'm': goto yy341; + default: goto yy208; } -yy312: +yy328: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy268; + case 'e': goto yy280; default: goto yy34; } -yy313: +yy329: ++YYCURSOR; yynmatch = 1; yypmatch[0] = YYCURSOR - 12; yypmatch[1] = YYCURSOR; -#line 141 "src/sfizz/OpcodeCleanup.re" +#line 149 "src/sfizz/OpcodeCleanup.re" { opcode = "amp_random"; goto end_region; } -#line 2230 "src/sfizz/OpcodeCleanup.cpp" -yy315: +#line 2316 "src/sfizz/OpcodeCleanup.cpp" +yy331: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -2238,35 +2324,35 @@ yy315: yypmatch[0] = yyt1; yypmatch[1] = YYCURSOR; yypmatch[3] = yyt2 - 1; -#line 107 "src/sfizz/OpcodeCleanup.re" +#line 115 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat(group(1), "_", group(2), "1", group(3)); goto end_region; } -#line 2247 "src/sfizz/OpcodeCleanup.cpp" -yy317: +#line 2333 "src/sfizz/OpcodeCleanup.cpp" +yy333: yych = *++YYCURSOR; if (yych <= 0x00) { yyt4 = YYCURSOR; - goto yy315; + goto yy331; } - goto yy317; -yy319: + goto yy333; +yy335: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy326; + case 'c': goto yy342; default: goto yy34; } -yy320: +yy336: yych = *++YYCURSOR; switch (yych) { - case 'o': goto yy327; + case 'o': goto yy343; default: goto yy34; } -yy321: +yy337: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy328; + case 0x00: goto yy344; case '0': case '1': case '2': @@ -2276,10 +2362,10 @@ yy321: case '6': case '7': case '8': - case '9': goto yy321; + case '9': goto yy337; default: goto yy34; } -yy323: +yy339: yych = *++YYCURSOR; switch (yych) { case '0': @@ -2293,32 +2379,32 @@ yy323: case '8': case '9': yyt3 = YYCURSOR; - goto yy330; + goto yy346; default: goto yy34; } -yy324: +yy340: yych = *++YYCURSOR; switch (yych) { - case 'm': goto yy332; + case 'm': goto yy348; default: goto yy34; } -yy325: +yy341: yych = *++YYCURSOR; - if (yych <= 0x00) goto yy333; - goto yy202; -yy326: + if (yych <= 0x00) goto yy349; + goto yy207; +yy342: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy301; + case 'e': goto yy317; default: goto yy34; } -yy327: +yy343: yych = *++YYCURSOR; switch (yych) { - case 'u': goto yy335; + case 'u': goto yy351; default: goto yy34; } -yy328: +yy344: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -2334,11 +2420,11 @@ yy328: opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); goto end_region; } -#line 2338 "src/sfizz/OpcodeCleanup.cpp" -yy330: +#line 2424 "src/sfizz/OpcodeCleanup.cpp" +yy346: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy336; + case 0x00: goto yy352; case '0': case '1': case '2': @@ -2348,32 +2434,32 @@ yy330: case '6': case '7': case '8': - case '9': goto yy330; + case '9': goto yy346; default: goto yy34; } -yy332: +yy348: yych = *++YYCURSOR; if (yych >= 0x01) goto yy34; -yy333: +yy349: ++YYCURSOR; yynmatch = 2; yypmatch[0] = yyt1; yypmatch[2] = yyt2; yypmatch[3] = yyt4; yypmatch[1] = YYCURSOR; -#line 164 "src/sfizz/OpcodeCleanup.re" +#line 172 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("fil", group(1), "_random"); goto again_region; } -#line 2370 "src/sfizz/OpcodeCleanup.cpp" -yy335: +#line 2456 "src/sfizz/OpcodeCleanup.cpp" +yy351: yych = *++YYCURSOR; switch (yych) { - case 'p': goto yy338; + case 'p': goto yy354; default: goto yy34; } -yy336: +yy352: ++YYCURSOR; yynmatch = 4; yypmatch[2] = yyt1; @@ -2389,22 +2475,22 @@ yy336: opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); goto end_region; } -#line 2393 "src/sfizz/OpcodeCleanup.cpp" -yy338: +#line 2479 "src/sfizz/OpcodeCleanup.cpp" +yy354: yych = *++YYCURSOR; if (yych >= 0x01) goto yy34; ++YYCURSOR; yynmatch = 1; yypmatch[0] = YYCURSOR - 16; yypmatch[1] = YYCURSOR; -#line 136 "src/sfizz/OpcodeCleanup.re" +#line 144 "src/sfizz/OpcodeCleanup.re" { opcode = "group"; goto end_region; } -#line 2406 "src/sfizz/OpcodeCleanup.cpp" +#line 2492 "src/sfizz/OpcodeCleanup.cpp" } -#line 191 "src/sfizz/OpcodeCleanup.re" +#line 199 "src/sfizz/OpcodeCleanup.re" end_region: @@ -2419,80 +2505,80 @@ end_region: YYCURSOR = opcode.c_str(); -#line 2423 "src/sfizz/OpcodeCleanup.cpp" +#line 2509 "src/sfizz/OpcodeCleanup.cpp" { char yych; yych = *YYCURSOR; switch (yych) { - case 's': goto yy345; - default: goto yy343; + case 's': goto yy361; + default: goto yy359; } -yy343: +yy359: ++YYCURSOR; -yy344: -#line 211 "src/sfizz/OpcodeCleanup.re" +yy360: +#line 219 "src/sfizz/OpcodeCleanup.re" { goto end_control; } -#line 2438 "src/sfizz/OpcodeCleanup.cpp" -yy345: +#line 2524 "src/sfizz/OpcodeCleanup.cpp" +yy361: yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case 'e': goto yy346; - default: goto yy344; + case 'e': goto yy362; + default: goto yy360; } -yy346: +yy362: yych = *++YYCURSOR; switch (yych) { - case 't': goto yy348; - default: goto yy347; + case 't': goto yy364; + default: goto yy363; } -yy347: +yy363: YYCURSOR = YYMARKER; - goto yy344; -yy348: + goto yy360; +yy364: yych = *++YYCURSOR; switch (yych) { - case '_': goto yy349; - default: goto yy347; + case '_': goto yy365; + default: goto yy363; } -yy349: +yy365: yych = *++YYCURSOR; switch (yych) { - case 'r': goto yy350; - default: goto yy347; + case 'r': goto yy366; + default: goto yy363; } -yy350: +yy366: yych = *++YYCURSOR; switch (yych) { - case 'e': goto yy351; - default: goto yy347; + case 'e': goto yy367; + default: goto yy363; } -yy351: +yy367: yych = *++YYCURSOR; switch (yych) { - case 'a': goto yy352; - default: goto yy347; + case 'a': goto yy368; + default: goto yy363; } -yy352: +yy368: yych = *++YYCURSOR; switch (yych) { - case 'l': goto yy353; - default: goto yy347; + case 'l': goto yy369; + default: goto yy363; } -yy353: +yy369: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy354; - default: goto yy347; + case 'c': goto yy370; + default: goto yy363; } -yy354: +yy370: yych = *++YYCURSOR; switch (yych) { - case 'c': goto yy355; - default: goto yy347; + case 'c': goto yy371; + default: goto yy363; } -yy355: +yy371: yych = *++YYCURSOR; switch (yych) { case '0': @@ -2506,13 +2592,13 @@ yy355: case '8': case '9': yyt1 = YYCURSOR; - goto yy356; - default: goto yy347; + goto yy372; + default: goto yy363; } -yy356: +yy372: yych = *++YYCURSOR; switch (yych) { - case 0x00: goto yy358; + case 0x00: goto yy374; case '0': case '1': case '2': @@ -2522,24 +2608,24 @@ yy356: case '6': case '7': case '8': - case '9': goto yy356; - default: goto yy347; + case '9': goto yy372; + default: goto yy363; } -yy358: +yy374: ++YYCURSOR; yynmatch = 2; yypmatch[2] = yyt1; yypmatch[0] = yyt1 - 10; yypmatch[1] = YYCURSOR; yypmatch[3] = YYCURSOR - 1; -#line 206 "src/sfizz/OpcodeCleanup.re" +#line 214 "src/sfizz/OpcodeCleanup.re" { opcode = absl::StrCat("set_hdcc", group(1)); goto end_control; } -#line 2541 "src/sfizz/OpcodeCleanup.cpp" +#line 2627 "src/sfizz/OpcodeCleanup.cpp" } -#line 215 "src/sfizz/OpcodeCleanup.re" +#line 223 "src/sfizz/OpcodeCleanup.re" end_control: diff --git a/src/sfizz/OpcodeCleanup.re b/src/sfizz/OpcodeCleanup.re index c9a3d5c4..b2906b6b 100644 --- a/src/sfizz/OpcodeCleanup.re +++ b/src/sfizz/OpcodeCleanup.re @@ -96,10 +96,18 @@ end_region_oncc: opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); goto end_region; } + (egV1) "_vel2" (any) END { + opcode = absl::StrCat(group(1), "_velto", group(2)); + goto end_region; + } (eqV1) "_" ("bw"|"freq"|"gain") "cc" (number) END { opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); goto end_region; } + (eqV1) "_vel2" (any) END { + opcode = absl::StrCat(group(1), "_velto", group(2)); + goto end_region; + } (lfoV2) "_" ("wave"|"offset"|"ratio"|"scale") END { opcode = absl::StrCat(group(1), "_", group(2), "1"); goto end_region; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 816211ba..e9f682c0 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -759,11 +759,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) processGenericCc(opcode, Default::eqFrequencyModRange, ModKey::createNXYZ(ModId::EqFrequency, id, eqIndex)); } break; - case hash("eq&_vel&freq"): + case hash("eq&_veltofreq"): // also eq&_vel2freq { const auto eqIndex = opcode.parameters.front() - 1; - if (opcode.parameters[1] != 2) - return false; // was eqN_vel3freq or something else than eqN_vel2freq if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; @@ -787,11 +785,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) processGenericCc(opcode, Default::eqGainModRange, ModKey::createNXYZ(ModId::EqGain, id, eqIndex)); } break; - case hash("eq&_vel&gain"): + case hash("eq&_veltogain"): // also eq&_vel2gain { const auto eqIndex = opcode.parameters.front() - 1; - if (opcode.parameters[1] != 2) - return false; // was eqN_vel3gain or something else than eqN_vel2gain if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; @@ -1212,12 +1208,12 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("ampeg_release"): case hash("ampeg_start"): case hash("ampeg_sustain"): - case hash("ampeg_vel&attack"): - case hash("ampeg_vel&decay"): - case hash("ampeg_vel&delay"): - case hash("ampeg_vel&hold"): - case hash("ampeg_vel&release"): - case hash("ampeg_vel&sustain"): + case hash("ampeg_veltoattack"): // also ampeg_vel2attack + case hash("ampeg_veltodecay"): // also ampeg_vel2decay + case hash("ampeg_veltodelay"): // also ampeg_vel2delay + case hash("ampeg_veltohold"): // also ampeg_vel2hold + case hash("ampeg_veltorelease"): // also ampeg_vel2release + case hash("ampeg_veltosustain"): // also ampeg_vel2sustain case hash("ampeg_attack_oncc&"): // also ampeg_attackcc& case hash("ampeg_decay_oncc&"): // also ampeg_decaycc& case hash("ampeg_delay_oncc&"): // also ampeg_delaycc& @@ -1235,12 +1231,12 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("pitcheg_release"): case hash("pitcheg_start"): case hash("pitcheg_sustain"): - case hash("pitcheg_vel&attack"): - case hash("pitcheg_vel&decay"): - case hash("pitcheg_vel&delay"): - case hash("pitcheg_vel&hold"): - case hash("pitcheg_vel&release"): - case hash("pitcheg_vel&sustain"): + case hash("pitcheg_veltoattack"): // also pitcheg_vel2attack + case hash("pitcheg_veltodecay"): // also pitcheg_vel2decay + case hash("pitcheg_veltodelay"): // also pitcheg_vel2delay + case hash("pitcheg_veltohold"): // also pitcheg_vel2hold + case hash("pitcheg_veltorelease"): // also pitcheg_vel2release + case hash("pitcheg_veltosustain"): // also pitcheg_vel2sustain case hash("pitcheg_attack_oncc&"): // also pitcheg_attackcc& case hash("pitcheg_decay_oncc&"): // also pitcheg_decaycc& case hash("pitcheg_delay_oncc&"): // also pitcheg_delaycc& @@ -1261,12 +1257,12 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("fileg_release"): case hash("fileg_start"): case hash("fileg_sustain"): - case hash("fileg_vel&attack"): - case hash("fileg_vel&decay"): - case hash("fileg_vel&delay"): - case hash("fileg_vel&hold"): - case hash("fileg_vel&release"): - case hash("fileg_vel&sustain"): + case hash("fileg_veltoattack"): // also fileg_vel2attack + case hash("fileg_veltodecay"): // also fileg_vel2decay + case hash("fileg_veltodelay"): // also fileg_vel2delay + case hash("fileg_veltohold"): // also fileg_vel2hold + case hash("fileg_veltorelease"): // also fileg_vel2release + case hash("fileg_veltosustain"): // also fileg_vel2sustain case hash("fileg_attack_oncc&"): // also fileg_attackcc& case hash("fileg_decay_oncc&"): // also fileg_decaycc& case hash("fileg_delay_oncc&"): // also fileg_delaycc& @@ -1293,17 +1289,13 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = *value; break; - case hash("pitcheg_vel&depth"): - if (opcode.parameters.front() != 2) - return false; // Was not vel2... + case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth if (auto value = readOpcode(opcode.value, Default::pitchEgDepthRange)) getOrCreateConnection( ModKey::createNXYZ(ModId::PitchEG, id), ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = *value; break; - case hash("fileg_vel&depth"): - if (opcode.parameters.front() != 2) - return false; // Was not vel2... + case hash("fileg_veltodepth"): // also fileg_vel2depth if (auto value = readOpcode(opcode.value, Default::filterEgDepthRange)) getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), @@ -1398,7 +1390,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("hichan"): case hash("lochan"): case hash("ampeg_depth"): - case hash("ampeg_vel&depth"): + case hash("ampeg_veltodepth"): // also ampeg_vel2depth break; default: return false; @@ -1439,34 +1431,22 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) case_any_eg("sustain"): setValueFromOpcode(opcode, eg.sustain, Default::egPercentRange); break; - case_any_eg("vel&attack"): - if (opcode.parameters.front() != 2) - return false; // Was not vel2... + case_any_eg("veltoattack"): // also vel2attack setValueFromOpcode(opcode, eg.vel2attack, Default::egOnCCTimeRange); break; - case_any_eg("vel&decay"): - if (opcode.parameters.front() != 2) - return false; // Was not vel2... + case_any_eg("veltodecay"): // also vel2decay setValueFromOpcode(opcode, eg.vel2decay, Default::egOnCCTimeRange); break; - case_any_eg("vel&delay"): - if (opcode.parameters.front() != 2) - return false; // Was not vel2... + case_any_eg("veltodelay"): // also vel2delay setValueFromOpcode(opcode, eg.vel2delay, Default::egOnCCTimeRange); break; - case_any_eg("vel&hold"): - if (opcode.parameters.front() != 2) - return false; // Was not vel2... + case_any_eg("veltohold"): // also vel2hold setValueFromOpcode(opcode, eg.vel2hold, Default::egOnCCTimeRange); break; - case_any_eg("vel&release"): - if (opcode.parameters.front() != 2) - return false; // Was not vel2... + case_any_eg("veltorelease"): // also vel2release setValueFromOpcode(opcode, eg.vel2release, Default::egOnCCTimeRange); break; - case_any_eg("vel&sustain"): - if (opcode.parameters.front() != 2) - return false; // Was not vel2... + case_any_eg("veltosustain"): // also vel2sustain setValueFromOpcode(opcode, eg.vel2sustain, Default::egOnCCPercentRange); break; case_any_eg("attack_oncc&"): // also attackcc& From dab5944755288621a8700b4e8efbead7cd9d43da Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 13 Dec 2020 08:06:24 +0100 Subject: [PATCH 133/668] Add vel2 tests --- tests/OpcodeT.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index b5115243..23cfdda0 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -239,6 +239,16 @@ TEST_CASE("[Opcode] Normalization") {"cutoff1_random", "fil1_random"}, {"cutoff2_random", "fil2_random"}, {"gain_random", "amp_random"}, + // Internal transformations + {"ampeg_vel2delay", "ampeg_veltodelay"}, + {"fileg_vel2attack", "fileg_veltoattack"}, + {"pitcheg_vel2decay", "pitcheg_veltodecay"}, + {"ampeg_vel2hold", "ampeg_veltohold"}, + {"fileg_vel2sustain", "fileg_veltosustain"}, + {"pitcheg_vel2release", "pitcheg_veltorelease"}, + {"fileg_vel2depth", "fileg_veltodepth"}, + {"eq21_vel2freq", "eq21_veltofreq"}, + {"eq22_vel2gain", "eq22_veltogain"}, }; for (auto pair : regionSpecific) { From 118f1cc21bdd47d1b260904d3dafb7e896f63c5a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 13 Dec 2020 09:33:07 +0100 Subject: [PATCH 134/668] Remove old icon for macOS --- vst/mac/Info.au.plist | 2 -- vst/mac/Info.vst3.plist | 2 -- vst/mac/Plugin.icns | Bin 34703 -> 0 bytes 3 files changed, 4 deletions(-) delete mode 100644 vst/mac/Plugin.icns diff --git a/vst/mac/Info.au.plist b/vst/mac/Info.au.plist index d7bac21e..44dd255f 100644 --- a/vst/mac/Info.au.plist +++ b/vst/mac/Info.au.plist @@ -6,8 +6,6 @@ English CFBundleExecutable @SFIZZ_AU_BUNDLE_EXECUTABLE@ - CFBundleIconFile - Plugin.icns CFBundleIdentifier @SFIZZ_AU_BUNDLE_IDENTIFIER@ CFBundleName diff --git a/vst/mac/Info.vst3.plist b/vst/mac/Info.vst3.plist index f55f661d..7e3b3a73 100644 --- a/vst/mac/Info.vst3.plist +++ b/vst/mac/Info.vst3.plist @@ -6,8 +6,6 @@ English CFBundleExecutable @SFIZZ_VST3_BUNDLE_EXECUTABLE@ - CFBundleIconFile - Plugin.icns CFBundleIdentifier tools.sfz.sfizz.vst CFBundleName diff --git a/vst/mac/Plugin.icns b/vst/mac/Plugin.icns deleted file mode 100644 index f8ce53c4c6ff49a7b7db1d70664f955ff0e68c83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34703 zcmeFZ1z1&E*C@Q`?(RlGTDrTtLAo2ILAs6R9x5fP9M6{Hk_{qGHe zc=Xi!o%i|vd+(X(nxn^DGsYZit_8N{POboO>yE9%RSp0EctOC$pN~IaAmC@*f!EO< z0ALZpy8r(wj2M619vwjl9|QVVQYHXE&MyY$aJZmfMZOd)mZSs~AP&H|fc;{ES@>5j^0B$V7?m99cN)5dxTuJv z#2G>I8-VNOhjvB-5M{o#3jjn%j9(k->_<33~>5Bv;;DA01!07zy`9Y5w3obhw8@*0B|z$V58uIA;Si~ z3hJh125qB>5?qNQstELgFyK_>z*mVIC=i4+#GhyA4#2|sOi0}fE zDJcmu0EL`+3qM^Uwy^SK05u>==Y@kBFl?qA&}2xcdP38j;U`@5ni3==yXZ~(OdD5SwCp)0x6$y)tU z=R#ZqTwrVf;5t~x8UPfHpaFr)KgvQd=sX+BZ&W;OK%5CK5RBOo`!azm4#?*C+u{r> zZ=;6}p&B9sfSWcrIs(EjCwI!g|65@&ZVrwN=sM;yFn}2tV-C9@LMeU$IRh`9#(h%b z8zN_gg!5_=X^uoUc55Nt9;?G#v zL;xmuTHrhVBo63;Wl~D+OvR0ZKy8_)3ixZF-S^Z0q33TJ0{~b?;J}Un%0OlfY^r|}@KZo}aKI$Uj~C?O`+DIx1`uu_Iq`&QZTDRR zPS5mYe}fJtNCi1FgAU1gS&3v|Z+ihoT{y}Dr%gk(wmj`YC}k_`QxeK&BjRIyf6!Ba z7Yjfyy9U@FgTAg)oiI^EY`iQW5JIfq)swb>VV=YoJzx;T3-F?l55+RoF=1S_VF3V2 zJyQ$)%jdTY$7yD5rA={S1^{S5rGR}s>gf0pDCHZ;nDQHNp~95DOAP=P9f*%U(gG<( z01SZ53I&|@I`IgUCS1n_FE-s~{u?DHC%euwz3oY(oeR4?q}zW)86NL6`slqi1qbpIvAJMNWnQ zOA!FnSpgF`044wc>=7-%Q}d4sGYh~c3mzXSfDfE4;hX%n*}v75$D}fb(5wM#$nCp& z{8r#MxB=RY6N(kADWoO>=RJQ|%sozL61^_CRp9cykAJNe@NJ?3C4X|G-_*}{6!u@+ z`?j*?4}HP5r+@3;GM0<^R2X@&EeWyPZ4@i2k)G^^dQ?e+~ZI1ON8G zzdi785B%E$|MtMYJ@7y70ogx$F#8{S_(KB-E0AaH|Gi@Vb@qR=1E59%mPP;f?jDd^ zLWz(5U-Vz+0tk=%(m&kULDVm~{}7RF0~LV%@QX8DfNkLPZ0sL$bY_O>$Ga*B1T!9k z&x(Ij;6t`S=kJ4l!}}khQ%M)q>9-&UW5%TyX%LuwxSe|SO-+`WQRGr<>Ep#F#0lSj)k&Hv2DA8GL}!2s0DX9sNrdpxJY0;A_j7};~; zr$~X(Iq@F@ZpVR5B}RO+7t#6+fcbE?*2LcBV16T}+kON7R)zXU(opXpH%zcbb|M77 zdfvm2Pxl~%s5Px~{Y2Mu@NWR+rK&$p=8L)lZ=fJ(VAcsyXYE|lv} zE+D@IRi6Kn{HMfB$KQw`YCT;|lZC_BJb7#N8|Lq$GR?ow`y-CwPrEq);5u}DXwCa0 zt)F=!-RCr%OZ-YEZV?a5+Fnj4|2U`5WzGSTkH3_-6as!L^>+%-jFne3*yY&j(eAs! z`hvt@X9I=2itoGk?-?8aXA&3sy6iYVI~{RWQlxWFE|q`o9!T^$m;Z+Wx92CB!Jk-F ztNRlH2%FeEwJ=HZmm~GN+TPWF#XW$z{imHolKmBQ(EAQFMDx4OerEXnrMm~~b&LG0 z`~yYt0|>NEPXoR-|3LpkB(V1TJorOFAT;og`MO_0Adn+WC-{2!(paD2D5XVu#6-d?d2Z9$_VJ#>Z(LaH! zCH_Dl1>zUP1OS$!TMcx7Ao!gHb?0xn2i#8ctnUUcK=hEo2feyL`BM<;?%#6{uyy>t z%|eKKknisc{KSDu_?zwlsQKTWRXW#N~QtfXIp#BW%8JOFHG$QaDDHIg+ zcNYGs7FF`N{5O4I6KsqN{9)4q2&4fX%oT`n5acQJ7bWiaCWLBs@YU*^E7`T~`ImOR za}BDD1^e>{JK!VO-P|ScXTnJaUZ~f6^s7bJ%7Lo61Jd% zk9QOyoUJh=VWJPO-5QZ|>**5l2r5kjp!2hzLn9Xqx_1 z_Tp9W`K;xS2WJ<#XE1uuM#2xD$wL^}y%6ii;K>I7G!PJU1pYqj*Z?uUb8@~V8hmO2J`42uWNko|pL#yIKDlWA z6ozGU$Y0oLiB$dV1Sij4umbN`zbw!XL7;`3ro|x8S6cwUJIOqvPb5VHPb%yt&<5mQ zHR9Nh*6!)q7VSd(KR;>WiNMK)SShe>XQ|Lx@aG_a5%XnH8TGs9Zz1_gu*HMXILOqr zf!N+ZJ>e4dg-Fs&fTrjmKqW{Y?c^qqltOPSLng?#LZBF2y|GZ{EAwMiIb(x=6T=|B zd$;F~)~{CHsT2~%H|dk^k3U63y}`A>ItaA&emKoYdIKc#P3U5Ey>xE9Dp>i#ncPM0 zcNl@!Id6KkB2WSUJMCxar2F^4%K`HHFjnAosQ}5tzm>Na?)hBxaSi1;{HFk(VsOpJ z*&+|IlkdcTA#Me61(|jf_24bm5x81(vWm3>&K&-e64iJ+v_*w+nZ2qV)eg06+@`C`&#_tWy4`RPT6c#AIQy?+8WfdHE-OfhjI}gAMzkmRy z^+?W3d5}x>G!zQmzywQEuai^j*MyE07Ofh8O3j9gAiAtud^7MTRerZY`n#1}qaQNVCkAI)&`+}*dL6W1=fQS1na*Uo#m}IK_LKd`p!|%GmVOE$EuGAoMcOmQe^jGHeDCxN z1{Tj|q`}+M>=1Jck^_MY)WTW6`aA@qBpbhN`ia#4@B(*)c4~oV?JSVjs-IF=K7MNm zfVmFdan!2+hpv99PPuVPCYe_{7E_F!CP=EAN3{sp{ukeU9_^`d0@}{2|YyJ9PU|<{!d_t^kB@zb&|PlM$idFRZ4{(G%d&uO2{u6!}lE zO%$~LlSl1~%Df}sDG_&(0{&wVs6XQW42HP|_xurLw0|hjOP7E)$sb7nC4^--qxs_0 z|K{diAlB+noBe;I35uYx^HlnReStRy85hw19%#Qz`77g4v%CM5X!nz^z|+*?Cwjyu z#Gh#Y4Z^QFAL55K|G(kwZ`l0nIqlyt`mgA}J@9W2{M!Tn_Q1bA@NWfk@u2Qdo= z3kyJj3;-NaQCV5li~m4|04~%osnEZq!u(8)15OSpx%|K`5@rG~W2tK9IR8`!U&egB z9mJHme&r6lo>U_GYoq>5DHOhtVu{(2kOwL&NSx%n_QtxO?;7A;5oTtMgwLBr<00h6 zj!#s2OO7qyLz(@m{DAdqU|`@t^J{;2*KHwb2|2YnLmV+N&aAObwkGg_@ZeMeRTZgr z*@x$QJ1)^*2jg3k()4sH$OyRg`~6qFukz_d6IPkw4J?Kx?1YgtB^p8x1`53UY^;UB8NDe(S)rrnSXXbwG7>MCJKqUwXJZ z&aa>FvgG4ywck!6bal0-Yu@A?KyIetR@K1xnCV1hLTgV{d)>83H=)|$u!VVFQ+j#7 z*QA$Ufo929l5!}_Eh>*E?mDuv1dj_B3~%vZ`;(;Unro#Ry=f2jt=pbIG}P}5L-*G4 zk9^cRkAQ8DWuZ=bfb#64I4+&Hvt^L)mnzT|mdfrJOSmO^7{n?5tDJ%P^-P6dL_a@w zMY^$JRaU~m95pTg|2!r^RbQ+EpNkjfS%mMD8Cz?1d!bjKfn-5poGiX5-2eViNo<(eNbpwR`#o_|FDOw-P@xb{c1Iy-}2xb+%|Ji z$X@u$eyMmLec=USB)z3>yoZPN%llLn`fcJ0Oud%IIMo`)&!Q+??rq5jHYc=D-`RJ1 zi4lOrv3pc_C!wH8`pL&oF0^rZ8^(xRs@)h~y)FC>Se2%`EXVatogCBr`C?_oOmgmn zGGzjH>a|M;j0v7E9~=>Y=krYZ(Mzh_QQ9L5n0+ti|~ir-#yoSQ)at#dZ`DaksK-YT zFA}Im(yj=8P}`<{TfJw>CKA`pddc5XK4~`g)4IT?>%Ll;2N~o=Zn97SUhkM%)V(cn z0p(3PLCh!33^#pVVcl4Ofh7R`8HJ5hiMG<{>|JM+QK@K^B%R`1a`xp<%$+&C&|)kc|(-Cc$zSRdS* zee%hpV4M@4pU&SadsdgL45oqs=yo(uM!+3PbxR2r*k?7?C89PRD6_jFA?;0^8QeCD z+w(4pa}4V6Xn*GMoe_BqUimi!qSMG3!Fj34MhG;jf||r)g!w3A7$Ix!$G}n^S=OM@ z+CyBQmRCp;a9@XCQ?ndC6ZXO6f7R67{;{=v@?ozZyrvvm+Qaw`k|-Xu-8j4FHrK+k zT(?caJ4B7jMKLlE=VFHEawNwHP>m*yE@NH~IL=&2Co!AnXeeiH_nwdT?kTAxev4`- ziDs%SL3O!@PD*QQ%!h33ibG=CR|il2`g%D9*C@2QdyiZ56%G%{Iy=IiU*FqJ48c&@ zLfFI!8n6z9LM|ouo?SA{XeSERdaeg6Wl9yZMoivX)7au0v6CKlpf1QA;5FeWL&9`v zTr6HU+1PPbsj9Shw2cK-Vm!#XQwEt*Q!Q*n6YIDUN$*oyXwGt~lb@l`WrSNVv8htb z#Eq6d_^0S<=(+1s+7upe!OPx9YTR&sU;LC@HTt+K2gc&r>o?Wj{`ymLm%}=4ITT*X zS!EvYK+_Duw6nm*Jx(#UAdfYlU0y}oe&^Z({6KT1-bB=?awiQMMVM@&~{PqW}GVHGyw&jS) zDmeXb$ZcLAZ;wk#Pa2^q?F8CUuQ^+x0Flj|7o{ufH$=6cbnE&L9}^&l z*0^N73fsl+G+U$UxU>Iy`U;WlVdRLARuDSNJoNEfx-!Y?s0Zrlg~bjcdSYvG*ki7a z_K|H{$K;|li53%3f#HdKjkZ0kP@V1f=_zyx`{nm`tnkfo-zvlGHgnhY`(ArfG@u3t zS47Voa9df=#S^Co$$>W)u#;4&XZ*^iZK+L6d4oDqYSg{|F<%%}KOH>o?IC~PiZc4f zs2F9j`tYKxBtv#Sl4UNr1w|qc-d)aPhwTD^Y`THF&q);`DCcgDzn6=Zdi^+ekg}1d zLpb5H`unvwPe}OB$oKnlV6QSTtT?7K5~m|(YPtSAe5^ZuD`v3_y@sWt9BrrXn1%un zyK|G869vER0jFjqpqr-7w#fodAsVjJA14(5q2O-fh|7c;gRN=Fey13!?Lj0q`Aah` zqmTMG6vIUeaqoCsopBlyuJ44(vT~WdYNGZ$!ALDO{;50b2VNQ9#H$-S>_)-jBY}*u z5n4m=a5%~GjAW$t*^i%T-d^5(IZW?#Yxy2w?{g6+q1K?hJgR42VmCF&3XPb;F16~G z`4Dd8@Dba^OgqQ<9o(d|f0BA=GrHJc8uK=pN+;sBw0gw5$3fM{k(O`WDLi`=;#A5A z^hvH8f5@D9TgZguk>bOfvk+_`PfdT>1`FZcbI+!+ptZetnE^GNS81QE?BC_Fcq8~d zJ+KZ>E$`SIYEG7LCdVgIR&mq1-#YHxdy|cPQ(7qF(ZiXQWTK^K`VZa&J8#qtxAh}C z=WUU7bh(h_j|PD(KjH+^I7e>jJEFquRFs6a6mpW1u^Lc)B9G&3=E5csCKZNyU?2w~ zC^qBn9lhMuMA|8e@sQVV*K-j)P=e^Py z4*lT!3U$|JizN#qcvUBLH`7Wfhn_NVb~W({8^*s{C;5a~#wm1=KS43=J|W`x+Wr|2 zwDUw_U0HHv_xrnO4w)2z?%{eU{zzBvR1AaIKsx=$SY*I8>g4kb3~YHQGObX;%ID^=AY z`Z|_*^}nF&nGJ)9w>ZwoG0<%GeWO8WExt$^!A;2dQPEoOJ}%ZLdOU_py|BS3X_U|- zx(yb7t{b^qxAmf2#1|e^$C$exQ=75&4K-RdycE5fO_2Ghn zz#$K>xw~3s%k_(|$+V-U``|S%*{ggxG*FbdeUEwFaK}p$4f_)5TjiE9CP6a?M9Hsu zcYOPE(I0b%y-O*(=f;i^8_gDDK%lXJ?6g^7$Xq!8Dq1Vt?2 zsw=00^HZIYtUksRO6=JbzIgN7h;&V<64yZ2EGEg+6`*3GKJ9RoKdNBlbL)1yBTP%* zTg&Sdahp#yLfH&{bg@1yPz2A}b^Mm`E%rW9D}NRGJ06(x#0VZQREU~WtarsPTQn|) ziQ?6|dVZOlMn;zx>?-%8t9D6@ygAlHz{a_l22;y zIG`c`2&AOCzGh8#`D{)KWVFdQdNYh zzfaK1;>?isg^;q30A|jO;^kVKsnQ6?)ujTp{r=@w?@{DSD%4k}gkdy7%e_K^cQe#< z@};R1q}@Gq*f)YxXNeEt1=O7yA1DPTSMgt01{uR-*^P6AV5{sKhOxnEha>jf2_`3e zse!a=d}|+2bU(-80$h9776@#Kr;xv(su&B{+C7Uwn%EPD?tu7=H<=$ocIC!;9JorAB z7fbxfZc4@%m^YVhjLk?*%t0~U500Bjc@zHh!|P}q86dx(S(x*n%n~7~Hi|-`8w8zq z_{gr7q9#hq(i%>Ges1n&S0hB}&6daCWF}`EM$D7*-OEg)ppLwjzKWa7h8nkp z7TSTKaM^rUT{AykHbx&hq^A9R)0X$9H6QlLTq7+AQaYq0Dp7)~Kyq}n4{m;pmrwRv zJ@y?`hxg>*LDp7gvOLP|VM7Amen^8C<6bkZwA92(_xaoBA1!h4a%0 zDxvdr;@Y_z&e^iVn=}1S$oimtdRm)taqnf% zqtr|1rm^7dBOi^B7PR=+f?3(9EyHCjG`^0YwAN;(xm)q%8%?5Ot{9w-S<*( z2_2#%x0;vdIGD&5#u8>ZI7Lz)sSr?-lF-|3NeEgFv%;ZLqZSyhEzdq`_gJ>qzaQJm zg0<&=y>yu_TFWv|QtdtKmxHL?NQ9@)^Y49DqHt@=*e`6}>5cWUL^C^(BdUZ~_mdUJ zQ{JWvrE4%GiQdt<_CWU1rQ9Pj>{nF1ZeC%g+NqAXd=s~KdC3Uh!OXI3i{EHiaUv@d zJBDr&39}1PhbyQ>&Lj<%2_czT#9nQ9rVk!bH1)&BHcHdG$%q?}^&v3Ir-U=@k-3infGu#3C{?E$0~uX3 z{6lZXhAs~mSvW{_{oaCkrKqj0^Z*Ms^*Xn1_Xi#S?H9BX!rH1XeQ7-rT~xWwWd!#$ z?<>Skspaz5Q5$9^bOlI*PXHstw#a4PD14n+Oxp2tK+)G3bpISLOzE2a^vUHUbNm+v zh%h2wUUDMpu)HrLV0}HW7rbaVsuUW?S+blIjF)?7Zc+qhB_6(!k9+dHbTdrweN6&& zsbe;?&}%n|3q<9wj0uE!4M@C5`rJ~)7T@Pe4$Y4h%pu)sE9{N(6<)i?#4dv&GgcCb zJLTO}ha1fhvJC1TbSXpYQ|>2(cCioDQ?dEV3yR-83ph^LHI&r*%$E2JDpH$an-K$> zlf~i1q2UIf3AAK|9Hs3nk2i5#2$j>q{?|w9Yi~*;6hB$%F4a4`SGgw?$>1s&%z8cJ zTTyuS2%VdGK6wbcpIaAA!9hI08-~7tOCPWDYGtH=0#fL~)e)YLFi*y}{e21%JW1d# z*EFQ^=)2XvHB*E$thr>a96I@hGdE|7{rHQ`=S_yaurAwP;I2gioy#o=1FV~mgJ@E- zgk$mPLx}jJt{G%go5oV}M0}FI+ZJ3*dtKyxGS!#d@RBZ=aSEoKC{)Ui zGr6|A?v;q0F@j!S6UW~Ya+@ReXv0mg8VLx5TJ`bqO7>AQ<&BHdimZ61u1l0VCF!b$ zHEr*bxAPyybk~FqIl1R_PJN9U%Lzzfzc$L)#W7*qKK;QsSZk2z>H5>=MBd%W#JF2D zn4{vCDsPhAF|Sh(56$(|+NBUk1nJ5nHMEW8372}jux%Yfu-pTp)+4Qt1bKB zt4SHeY{$ON=Xf8UUgd6^s)W(ub$kW+8sAshlHjG#P2FfY1&~AwQgOyu())m~FAK`A z9yxc7sqMFQ4ZXy4zr9~I^-N_<&hb5s%4Ig2B~lp5`rb`f{LVVM?ovr<~;=!4>-dx^KfPpQkBE90NtMh^w99Fs{|Z?1TLc6)UwfOt&CZTi&*{-^=l|7~f2 zvy90WvifVoE_&44@a!nv)+rb<4ZS`ze5vnMM`I3+W-?w&1EdojO}r{~CHa{LOcS*C z!e`UQt@Y~&8HaG(#sjs5t3=FWpQcF=CXv(rpB)-`PvKOjP zkB_|?{Z-iV#WrPAu{Y5h%OdDQ`|OnXpqcD$oTnn>cV{}2pr0JSN?@N83`g0jcxR_v zv?1GxUAB}$Nq6yAFgL4q z9pH%X@te?8z4Yz3ys5bI#kMQtZe|r(7t|79cOxF~Q0ZhBNxZ`ioABs`FT3_5(Kw6c z8q6CpuQi{qy8Z5(8@zNgbou3lwBf19ThHp4tsf+PGj%^T?Cdq zshnPpmSOT)D?U0Hz=twA5yK^9k~C7xYK1Nnt05=j$w{ao;iuuFtQp(U<;#)oCAsb$ zd3c2Qn}|sCzG!6p$PU*@ZBX^)D0>iVc8NTH=62eqN?h+^8?veI^aklZ|JC6A&3FY;zh(T9 zyfq4+Qlf4Xl~!Xv>N#eK%q_iK{rWlWmO&Vjbo1@%cU@UBuel$8tr^#u5>V$PO6r#H z(oG%5z*)#&2r_57q(nTsCn2-Fn%)1P%31Gq1cRt;bA$#uv;;6oG(a;<`9bFCh1e2{N~#Hdj&NvMwpw`%*^*?tfcXvR%DwDLR8_{ zvQ)1b`^pgX!P@w=Q&-jbbaxcj7j6u9I9wLUE0x#cvx2Yw`>~88EBC=cf3{X%OZWE zkt%CFR2_Z!+Ixj$L@Thq z?j>>7YilZ29lSarUnU#Gzbir?5ph{JmnSgN{vnA` zw}_Q4nw->=$C<(O0=Tr5cEfEq1;=xr#tjpY>9BpS_#|lxMA)vc0>-507 zlGPS)*NIC-)FgL`u0j;vN_2%Dk7QaHr}FtQ-19Mhy?e0Jq48N;AxwhS!<4cD8QU}%ysmeTw!UV}(o}jH8 z{2p%%UC1-~t_L4|#i987*M3fRc#r5@CyzeViMfwwEsvG6zLm;Z-V&&N$D;nY%$@)z zJu-sNre+0GLh!b;x^uCx#uMQXsp08Cl~{@;zRjNdr4-KTg8g49^vP#x%Yr(ts?PF1 z>?jG6!t@#=iPYnd{V3k3)*l#Pc?I=uX+naumB3WH1S>A@oC8sWg0dAI!@{nR;Ch7j z>Lm(9vlO+fx*_T}UFlv3zW;)md1a`;K7Edypt1!&dybvoy1aMHXO%t~#+C#XP-kw{ zRmfAM6Xvs-+r~*g{G=xhzJ|euQwt?9uYMJJ_BeQUfa*^LcK;8q6OqTqdW`0&C0m#O2_ zk)J3T-fINAn(Qlmv2u%|IL2lu!JrOAn>8`pDF(^ikKnjW9lF$MN2H89g1Yf#qEV__ zkrn5Sp8~)U`nde2GoSXhqEz{{yxN4D?fTta{;;*tfe!l)mLKU-++R*Iud63pyId~! zzPn%F=y#b@f`BuY4rIcG{j~YYa#r<(z|Q<8MSE()&^TfDSmNqtW@9M*SX9Pqe6dnW z6-{V8TQ3ZRtV>J}39ey6PLVwlba!EjNOt z)LjVGKY9(|<`{67y>gsh*Z~ujROXwZd8^>%>J$F9ZLty!=fT-(#0#DxeBCGNRGpjdbxxkK~tc_N|3GP0<2hqooYpWG#Q)5*W0q&qY3-~F10pk1p0X+diz=F4b$xuHq+R|OX%NJ?)`Y)F7UnwqJ5_EB&KPEyS1sgdS;6{mNuR=Muk{3ryX;H0GYZD zy7=g)^gWvJg;>VT(c9ki_hX7>3$B=y%sdMf*ndCCGIY@QLf2W<*?BA-nMkYSUfF`g zyrYd4EPtuNN1>VqIQ$YXtPg!M-4f*T(m{C})oWD>cm>biK;7xr(z-I*VE-k4nS0H= zoZxj@a>hG6ZJZRD;=2#t(>|2z%HcLZp4jzTS?_vjf>WWV%B#gwbNGDuYtV~stD7+< zi<@#B-iwBNj-BPiWr~Wlk4QpWZj65b;teRx-~?x4+&Xi|#I)FZ@Q23V;?lVKz6>j- zpXnVJvst=t{jnyMD!kko&o{dF#tv!%o!X8hRi2?%SL>(Ap6df*qr&T&+}{t<@HkQuLY1C;*CuE@zh(OG;2d?2@Ej#wVsh%>kWb z%k(Ms(OBqFBLye7we4^Mow3_0PnUOdeet<-_vRK+;#h+7#xfdd?8Aaa>$nSMYHGHF z!cn$tRmi<0C?easpCl4NQlyhSqJlU<%e`NkKLvHG^vB`P(J?>A#p6II9fbs9(fVj@QcMs%$;goog95qcjdqyMYb zvaqJ{)N+in$5I2bC=_lnY8Ji(LGL1TrK&PqV%qZ+R!T2wRBqWOoYLMd zX@p6YeFuSf8kJU2NHK@ClT1HJc?U( zkhTJ1Xxm#{Dapl;_cbRHLc+1X8YH|WHV2q(duN?xu^SbA$%UWVNA2$3cszP}v**U7 z5^|pzPeZ>!oR8kvI_t2`&$ln#WNvGB$#|+@Hu4fzook|@46WPj5I1m} z=`*c#Dfhf~BDCVG()IuoN7E2I5sT0xJUUpi%=G@Y+w{m^pJDb{b7p#!T$30!$5dz$ zKtrB*Fh}2`D4W)}{Sbe`&pg>YL1v}Db1dW?SPuS^- zF~x#IkTc!#{Y%60WO{o`KUnsg8Ho?b)Ks*&E@G4(dVWoNph}_7Cdgn#hI@c ziVE`(p&zM{HTSV^r)83Sh?GXx(-I3I!aHR?Q#n>hDbKmD87^`J9_C;V4Y5CTfqnb% z9<5h#ENfqy@^V+4a@SR6ed{el ztsruX^S{~VaVupHtC59sB^{GD^B~Zof#>GYr2G}A=W9k4d*cpeaxl`P>^h}c)g3Cv zKk1HvFv&B0urbCfmc}jy1qYYCM`Kc?tA;a;MS1d8B273i9|W^nT;55Kd2zY$ zU{9o?yYaquZ7icF>zg)Isg0vMJz3@`PHi(KLT(5ZJ(X8H(-jrQot$sF%W~S6>;JwWIh3y677FQqC9n!C|q~@R6L*Aq$v|~gKvESHa;r-kcO^M3WZIp03 zI565(3BJHdk->UJ{gAKBN`c#J!ER50t0N(a>sC0Me!(LFbswH0{V>Fyg-7dpi;)E} zy=&L;O4CqnYh-ct6)?t7+ji5eXg1unKNb?fQaSGmhMMb>4!r&Joa2fJmRbW#rAL>r zdiC6P9o=tl2T7I@2EvSE&nlpd`tV^xf@ErQbeVGjG!roYEa3F2gna zsMZJOLlF5ms!NMoy~XUS*`4==8Ig-EtqC zn?dr>;~PQKGfm6M)?<`ZtC~kmH&L;PSC@l!uMfH8hPD{K@v&XBSF&rveshEioKo>3s*|Q9hX~*(5J+%dAkHu*iaA~ zwFia!15I zOe+Ua=2iM;OM;ts9f0o3j8<%_i^J>gJ#Y;+OubpHAv!zI4g12pp_RzR{uFoW_H!nV za?OZ2ud$Oy8ZOb3)dn4JXF6sR(QNF>79K3-`(c7m!=xJQRW)!-u9O#*&GR}uV3As{ z+8SN)cTmM9h^`ovSbRaX^6|4mQeL!bBsdLtHx-@O-GQpmjqAe2c)(~2&ioKaHr=N-zUY+@(=Q8 zWg$bRTeU(V|Ge8U9W^((y*T88Q;jowscOR~*pAvSs`4{)a3SNJ&e^?AylDQ^TQO&08^(qq; z^^G)6FL^*>O;4_No56e3?um8cF4T`2R8+2KT85LQ*J7og_eywH>IrI8x0%rJgCzwC!;5YgNsNO zTiIU-u~zA-?$9SZ~^YaxL4!mKo5oT;wKF?ng|(4b@1VG#i#Fg|Hz0~dX}19Rhs@GTTI z#6q{CctljwTrBR{!EJm@^AAKK-TT5^zN`TM5{H&`P=!STxscC>PP^bv9xx%<>IY|tvQq(l^mFQyH{v1GKF6+ z`RlNh2cdj&r)zjG9eA(3oSc92 zm7~C6+D`wwE|;dJ1=zkz%O49Ex&zxe?1Sa3ql`CpW|at$*^Xg+c-c~6gL_{^Y-9^1 zP`6IoU8}bDMD~5-H6b_6lRBPond{?WGY{RpPRfzdp zA`pBsV@+N=gzsDl0J4|w4_Vy5s}fUm&FI*o>(XkG3Ow%mKul9U`i^^D-PQd-MS||A zCnl{(xs`(Rw~45E$^=7@ONVWopSR9du55P5&aSTO%kCA!ea#5)K`#^^(Q;WA?@JYG zW?;s`t;jiq3VY3zf1Pb0NMF?k(Z1AFXPA>a^d*<8tL2^Ixr(^lz~xIsE@`1rTn%&` zd-1xaI`z35z`b@ssT>~7z$p`2r}ii!yIj*n!BQUpE%D#5JR-IT|}S8Hhudlty+dAuY^_JB|Bf zl#zx(J9Oo28eS{(b{t4D=_jljFk=`?<)g8~+KUQAuD|}=m+2FVFKJL1C_v)Y3#FIn zuA@PKgaj&KHz0$5>*0LdGyBnYGP-W7YrFMTitn6p$4v6f)3_&uF1Mkk(#hCpzH8P7EtYfc@2rKS+>^Y$CAt(1hugfGQ zIN8RuvgLYhvbZ_UmOk2l#<5J8@Ma44-j~`3PkV1~Yi`vClUVArAg?2<*9rQ~9QT+A zo2ERH4@#{nG zjd6ohUSh_aGDMRzk?uHdQ7BH@Oz5?=Z;SrF0N4U2{b{w80XQGcES~(yIM_H{1OpGm zyR2(kP;$aR3OkWufp|v++JlPw3RNo3tE5I;PJ#@u3vzg9AqQohh6e3pW_+-*i{Q%m znuJL60?m;MeTk-$$xv)2h3e_n)7{tYH-`xmPq|QZljrcS8_OxNR%4N5(O#j?@P$jm z=`>18ywF$COT7<`8voE%%IzsF&32%MQOKPU@6EP43sr- z2?r*2x#ET?F4xHz1pbrwDMz}HOP8?Jk7yirM5*&x3jypE5;WIDsT?U>s69l7?C4!C zpV1MtyUu5^*`voT>!ZDux$0Tu^LHA~O16}8$Lv`~6!eaJzuXuDn=Aiqt?9nWyl<)< zEM+*lXtht*BcZxZWufA<4OL(+1J{N$MHqqS$m;y($nR6?vOx@QrP9k62v8;s z^_EBrg>s|qff@e{L*du%!e|y4NE`Zp4?bdaTq~Qzi#@geq=`wd*p;ZOSMXSFxuk`0 z8H`Yuhww~%nPsZlvQNgFwLzs|#fTA>Y&Uv6?4ptMV8JQRA8fk9CT$L$U=R{OFN`e)0tZcq0Je>tjE>N2$7Vq5(o(*jf&*UGkeJvBl{$K-}wj z!4KLP#vEC*T|r^BNd?Va>cgYgd`{mmookC6m(wL~jxw>r^WDMf_keb(-?@@FTy9j8 zL#q&=5OD*i)xi=sypQhn%sNlF7dC`eEjPE8rFq~JkJ&^5i}2NRV)!Mj=Va}GD$4!D k^U37#W?<;F(YfGJb=39B1hbI(?)x}Meq^T9tQCL%*>4!^4gdfE From f2523f8b38371bc38c513f38178cfa96a7ce8437 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 13 Dec 2020 09:47:20 +0100 Subject: [PATCH 135/668] Prepare a basic macOS package with DMG format --- .appveyor.yml | 6 +++--- scripts/appveyor/after_build.sh | 22 +++++++++++++++------- scripts/appveyor/before_build.sh | 9 ++++++--- scripts/appveyor/install.sh | 3 +-- vst/CMakeLists.txt | 4 ---- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 595fed6d..dcb4e9b6 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -50,8 +50,8 @@ for: - ${APPVEYOR_BUILD_FOLDER}/scripts/appveyor/after_build.sh test: off artifacts: - - name: macOS Tarball - path: "sfizz-*.tar.gz" + - name: macOS DMG + path: "sfizz-*.dmg" - matrix: only: @@ -81,7 +81,7 @@ deploy: - provider: GitHub auth_token: secure: xOugGAynvnZdc0DXaL3rlgMf4CICFLkdO8JxoRfLQMKJhkj/kZ4d8h7NCFneDzXG - artifact: macOS Tarball,x86 Setup,x64 Setup + artifact: macOS DMG,x86 Setup,x64 Setup draft: false prerelease: false force_update: true diff --git a/scripts/appveyor/after_build.sh b/scripts/appveyor/after_build.sh index 330ffc9b..1591f363 100755 --- a/scripts/appveyor/after_build.sh +++ b/scripts/appveyor/after_build.sh @@ -3,6 +3,12 @@ set -ex make DESTDIR=${PWD}/${INSTALL_DIR} install +# Set bundle icons +bundle_icns=/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/KEXT.icns +for bundle in sfizz.vst3 sfizz.component sfizz.lv2; do + fileicon set "${INSTALL_DIR}"/"$bundle" "$bundle_icns" +done + # Perform code-signing if test -z "${CODESIGN_PASSWORD}"; then echo "! Secrets not available, skip code-signing" @@ -11,16 +17,16 @@ else security unlock-keychain -p dummypasswd build.keychain # code-sign VST3 and dylibs codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --force --verbose \ - "${INSTALL_DIR}"/Library/Audio/Plug-Ins/VST3/sfizz.vst3 + "${INSTALL_DIR}"/sfizz.vst3 # code-sign AudioUnit and dylibs codesign --sign "${CODESIGN_IDENTITY}" --deep --keychain build.keychain --force --verbose \ - "${INSTALL_DIR}"/Library/Audio/Plug-Ins/Components/sfizz.component + "${INSTALL_DIR}"/sfizz.component # code-sign LV2 and dylibs (note: manual, LV2 are not real bundles) codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ - "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Binary/*.so - if ls "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Frameworks/*.dylib &> /dev/null; then + "${INSTALL_DIR}"/sfizz.lv2/Contents/Binary/*.so + if ls "${INSTALL_DIR}"/sfizz.lv2/Contents/Frameworks/*.dylib &> /dev/null; then codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ - "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2/sfizz.lv2/Contents/Frameworks/*.dylib + "${INSTALL_DIR}"/sfizz.lv2/Contents/Frameworks/*.dylib fi if ls "${INSTALL_DIR}"/usr/local/bin/* &> /dev/null; then codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ @@ -32,11 +38,13 @@ else fi fi -tar -zcvf "${INSTALL_DIR}.tar.gz" ${INSTALL_DIR} +# Need the flag --skip-jenkins to prevent CI hanging +# https://github.com/create-dmg/create-dmg/issues/72 +create-dmg --skip-jenkins "${INSTALL_DIR}.dmg" ${INSTALL_DIR} # Only release a tarball if there is a tag if [[ ${APPVEYOR_REPO_TAG} ]]; then - mv "${INSTALL_DIR}.tar.gz" ${APPVEYOR_BUILD_FOLDER} + mv "${INSTALL_DIR}.dmg" ${APPVEYOR_BUILD_FOLDER} fi cd ${APPVEYOR_BUILD_FOLDER} diff --git a/scripts/appveyor/before_build.sh b/scripts/appveyor/before_build.sh index d7af42be..329b6c1f 100644 --- a/scripts/appveyor/before_build.sh +++ b/scripts/appveyor/before_build.sh @@ -6,9 +6,12 @@ mkdir -p build/${INSTALL_DIR} && cd build cmake -DCMAKE_BUILD_TYPE=Release \ -DSFIZZ_VST=ON \ -DSFIZZ_AU=ON \ + -DSFIZZ_JACK=OFF \ + -DSFIZZ_RENDER=OFF \ + -DSFIZZ_SHARED=OFF \ -DSFIZZ_TESTS=ON \ -DCMAKE_CXX_STANDARD=14 \ - -DLV2PLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/LV2 \ - -DVSTPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/VST3 \ - -DAUPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/Components \ + -DLV2PLUGIN_INSTALL_DIR=/ \ + -DVSTPLUGIN_INSTALL_DIR=/ \ + -DAUPLUGIN_INSTALL_DIR=/ \ .. diff --git a/scripts/appveyor/install.sh b/scripts/appveyor/install.sh index 49171879..c927cc1f 100644 --- a/scripts/appveyor/install.sh +++ b/scripts/appveyor/install.sh @@ -40,5 +40,4 @@ fi set -x -brew install jack -brew install dylibbundler +brew install libsndfile dylibbundler fileicon create-dmg diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 9fefab3b..cf082daf 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -125,8 +125,6 @@ elseif(APPLE) set(SFIZZ_VST3_BUNDLE_VERSION "${PROJECT_VERSION}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.vst3.plist" "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Info.plist" @ONLY) - file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/Plugin.icns" - DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") else() set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux/$<0:>") @@ -290,8 +288,6 @@ elseif(SFIZZ_AU) OUTPUT_STRIP_TRAILING_WHITESPACE) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.au.plist" "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Info.plist" @ONLY) - file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/Plugin.icns" - DESTINATION "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Resources") file(COPY "gpl-3.0.txt" DESTINATION "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/SharedSupport/License") From 64480f50a983e2592a77062f7372afe3ff45fa93 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 13 Dec 2020 12:08:09 +0100 Subject: [PATCH 136/668] Improve DMG and code-sign --- mac/dmg-back.png | Bin 0 -> 18921 bytes mac/dmg-back.svg | 251 ++++++++++++++++++++++++++++++++ mac/dmg-back@2x.png | Bin 0 -> 40969 bytes scripts/appveyor/after_build.sh | 36 +++-- scripts/appveyor/install.sh | 5 +- 5 files changed, 280 insertions(+), 12 deletions(-) create mode 100644 mac/dmg-back.png create mode 100644 mac/dmg-back.svg create mode 100644 mac/dmg-back@2x.png diff --git a/mac/dmg-back.png b/mac/dmg-back.png new file mode 100644 index 0000000000000000000000000000000000000000..bb1ebf5d93fb3c7203ad705972a92cca7bd533b3 GIT binary patch literal 18921 zcmeHvg;$hO_w~>qElNm(f`XJZNS8==w}9l(Lx)I-fPhH1bW4LYNOyO4cf)t*{r$dw z;alrl>vb)bE}7?YK2oHqCmLMJr$6ZlUOCkag_6{wjL%*eqM0)xSrEo`kEO^obJnV}Bmi3jgr zfEVGxU!-c`WNiv@G_!Dbr?Q5cL&Nq_Ccy8=;J*`bcKQr;fT%)^EsPx9spy?;&5Y=& zWQ-i39bfZlmQ29wh~cjjb1*e>vVhuBsan{WLf)~yV`XCHWMbnA7tE;yuhIO^YoK;+ z4i@I0ogiXjtW=85#?}@lRN_z@BMVz9anny0CjWDX&rVKud@L*`|GA@!sR`7^25RdF ze`prF|6KFwKbNq$n>s*Q*qB*a{;f7#Lm*TTX>k!%*QC99nCr9kR+OXi#H#J*%F?*x zqK6|M_~HqgiiK$z#@96yR`nC1DB@*QUvjC?l_kXa(ti($xgSzD*hI}=KcG*`$WBjx zl8H-NJnhSTSRl_KttFY}6P?XqTNs%l<~-&kl_;X=zV#aIU|iCL;urm1P>o z=k*j7n*;*kfzgqXHa;L|l!%MrA*&EZ&Ikh#{dP!!uY{(krWTMq3!`PH#oX91bKM$# zr8qvZvb9M6Bkl(>oYfkz%Z$yM*Hs z*+0%8Eu<6ROY0hm;5X_$3P6@3=_$UHm#Y*+sHv-mgKL(J$6ld-fe;ay%f`LOX`vRm zVPLL&3i8*7m8$!{NXPaV#B7$t|H3JYVol7<*Ovx`9z@->Q6bGj&A8Fo^1?atw(h)w z+uAtc!RiB!fF`gccX!#hi+Jhp}d~U_YVi`HSjfA%tnsM+S-QIFp_lULuh3 zJG2^Z{{9Ews;8<-N+Fp(lxPsy6u#jlSkLgJaVhkW(r$Mx@H%t@5kk|(LVT7qhS&K5 z4_|s{xG5t2&!4AWq8@FtoxN$B9~B0hFKn7b6fuJ%-OTgnC0;%zE`d2v3j^%Fqzt=b(H5(`v zj1hC%BJYu7dBl2duRQ;qmEBep&G=8@MS(M));ls(zDgMhiH;8ny}}k2Z}J%m6t$E> zW@fZCwX{TxihRS0u)!f&J{TrpW**p+mT^)!tK9t%tnf9uoIvvX3)>+_H4Tl`5}`*_ zh-@-fypgRjmXjrsD#P;?<5m0h5w+jHf2aSh5kE62Dk=gH5L7%bI@Dm!t*PU9$LK6u zS;;{5{)h-f$L}`;SdDAjAtpJB%DP{E6t|!s^u({ohWW|UWvLh7dka3L4^I)bx3@0{ zS5i{)E6~WWKmW+l=MqoN`WgbZH50a|&&odf5TLH2;-4EF8eB^ex{_f$mTzeUJ@jp+ z^1&h({7Ud?$Y%AdoAue;Yhe((?&k+aLypf0pRJ6AjQ;5U1aK!xWKd#-b*TH(pK^!N z)yd?pfu7-6HY+PDd{Tm-sW_fHwQ%E~iKo7^Xu zKazfaXE)j`{j}|MbaFDLLlW|kS6GPksv|46u+U07zbH?_Sq}Rx(_2F$3j}~fQ&UsT z!`5w&7Gwspj-__}auZ4bFx-uCGDI8cEI>gwjPQsN(!uFAmXx<%#c zT1R@MH6};zv3|liH8o>6hkW0MtzgqBOrOc`c=PsR{~GCw;gwd<{{BAROo>8fs)o9{ z@vg$G4%VqV0CFCev#&}A?jN+lVOEY(!3XGAR(9OgZL3TADz-jqmj{fKO$2Q zYUi+E{q>_uoYKpiv_E3vu@w|>vB)@@(>7`5!Fl-%(nXoqtbFdcWoFV~PtOyvKy1qs z*kq=OQ(f-sw{O2vp_5Ta_2(BANvN(#Bni4nI?^*ocQ0)ohQcGFQit_@!~5Ag?w4R$ zR(24HG>DuIhvg_Gh>G&_pZHL`#}dI~T^+D+=0qB^g}&uh=nDx}WZD19g_=JI& zVq0cn)>5Gx+&wgNb9#bUMIW3;H)PW+(=CD-QUt$;Y-XH$B&6i;G}MCl;IoJyE|$Y^ zzf-V3^?vZ~N43z>A}Q8y40JSai;PT}UV@pKnGsL-{eJOL{nlsScH-|Nvt-$4MpNj!b`nR^A@Zcwk zIy$6%I*wmyAODO-j&v`LMQ`2M{BtJQ@Qa?l5lUlqH@2N{*6?POu4TMGOKv@5 z)+d8M0|_jt$%U=0Java<3*#rqA@qD3&i z_+ly%RifTBw;XyjdiqcIx`S*oo7V2Up!DK#CVeSv5CPp1 z0qnbGg{z>hF8@D?g*<|s$i!$&As>S?QasC@6-7+qtxt+>wb!qiM+BvAD<%X= zhEX6uDOt#b+@FSEguG@c@zrGxDi0;7b3XhwY$9p@u@|SfDw}Y&>OlCD>$5cn-t57o zFJ-HpABx*_96>U*-!h!Hv@AbN7&l6}+=nktOx%y$^Mkp;K_ZG23P}bfG4NCg%iIhx zAIFTD$JlEebg*==~6Qgd3#ANE+K(}ic9i(8^=evMVQ|ITf`*A zmI(E~0!t`HThdO<&z~y=l?Jr@{Ad&u2bwoq{vbbF?iiD(NlMazf*>F(>s9t(g4xc> z4|H%4bK9?87TqGFR7MEXBkue{xp&x~>>6xB5E3$YUv;-^roj{aXOzB`Di=jIjsph= z=K=&w2o)%dKh%Bv_>og3yQ;$N+BLo|R~+K|XXIU>PCbR2+co+Voc2`(!4c{QOKp#DAEBz9l(o9WosMyqcXO zQ&Q5MDOsQjv_HS*x@nZ?wk?ZE85$Y+b;b%IN=c!?@AT?bmg{xaWSQycpd@cgrrvUXPiAp*bLBs=HoX=jhCt?+!L`UGZB$ z>Eu#;5&UmR_pXF&9#Bk8*NM42(F4PXElW?gqLY)E7CbjOGgDy`dnBL-5H%Kk>T);} z>V~=Tq5*5{9jZG&EjnWBpu|%1gMU}|!1%1a8pHFbr_qr=I1VB*vRAXM*R9+yaZsldujuc7M88>0EBtCb~g`7uH8nD zQ)Ppx*qxOH!*<{leDT;I*?X^SWM&qKM)4Q-u<=|loPsyp&mWD7s(GaFM$8D&|{@%EEA|=&7{b#I(;cW>&2qMDyddRO| zzZ46`c?eu^o-i_MzIkTn;_@{oCud@O43r@6-n~;&Rz=KG4*B-2juYY8w>nFET--}Z z%-SSDl0ciLJ>P-?%oI;E5?$RSC4K#HkPLo4n2?KPJff(I3tTgV28_BzXkau4E~^0?>iLEaZX7AsG8by`Bbd7q}p7qC!c1Tm1sc!?ms4QxlMlDp2EcVy|58FUSIod(?$y(i+~WPG9WJghs7A#d`4` zufhEi8A8VE`E0g&-?}t4Cg%Aa(%sT%2O1aGgyQRGcvNEnx)QIHl}CO=MP-~jTA4$G zn$sXo4vzlG4dghKH>4n+#m8%1S?*6N=Bak|^w=I>_k4N>+6+lUMJh6~JtG?v?0^_V zHMJN3`Qj~Mh#+@nl$Mru{E16UY?~~>1l_Tbi3ySwsa0HeKUgil{CtK_zs+gb*f7){ zKW~t7xI!qr_o!u)I4G9QX@C6s6>cIWZ+O>U#*`BAJ;-kXhinRlR}b6goWAzB+{R#J zJZ^JxaB!II=u?`RsY#5AkIZwXbQz1T`a+7r z0m^~&n!DoH{A{Pr8JpZaUxm2!^vtQ_Q1x7r?$=~KB(O4|jU$2lh)Vj_6^zN$h=bsV zpvVwY=xRl8&s&C;#X!M}4vICMxu%*LWYF4wkd_y*mL+?- zLXb$7Kb`|+N$!lE7=)OAEXuPT?CG1})0Lx(-RAf?FjgWa<9Y8{d0^7Tzg!j7ZF;nw zvB+6-dB~3*^DzKkEP=ueQo36`ul>l3huDhz= za<`zdB;k5cA?zwh-(1ax6y;;t_r1U;V- z(1%U((fDG8`q|QSMkGIb{*6`=r!6Y$vfAx)FlhDR8A&>tp6X`C8I+E=7I_w1^EuV> zoq4&r&0(b6GpdAMM-~!klPrXzPod=bCq;#YOPeM4%$f!RfytxpLFi-iegajpbI-C5 z4wBE6IFx>VeARe+rKj5mLD-3r z@$p&CP4db7%gdbl+9<6%Zish)=Wq>(YMxp(x^Xdj%Urm!`IMM!ARi+9&SC z-nsb(b_a(uZt9=Z?H#WS`)Y<0e2AVsqY^Tx4m|_ON8F%3Jf*=Mj)zkPsSi3BZAwT?%v9Nw?|%^FeIsGzoUh9)6`?=x z{DL6|*O>3LvQxOEu&|ZLY9cfLqsO@GBf>qa>C8*opC7q{aLHSy**7Z>%#Dn~O%(+5 zFLBi2aVaP5Uy#UHce#ZMLFf09+}*^3AR-~zUiR)`Q+Hi-8{gdy&xNOnyhQJQ;rg{F4Bx5Jfceka0*cAWrP;5;sn<}9VLbDAUAuKZ7`0FjeYjQ0f}W&HE4G>D^!CD z9r5O@XqP=ICO&L!?U|BEiT@WQ&Q1(0oX;*zg6Ynk2ctO}{;3M_TqFa`&Z(Q;_hQ54 z=D5)j^pl<00OhDpXds41KSV$mxH$+ayL(!D;w`!~MNNzQQdM=;gu1w*sDy;<^IGTQ z@k7OzZ0*Q(v9T9!^q5T$^#%09=uJZJ zr+4pfu9W>Rh-xXwRfx8@iH!2{@;c6U*|d96A%4{rsgsyba9Yo|;!uTl7cvv++L@S` zhKoG7bsL>fAd2eh6Q87b#n`#Ir4;R`92`#-HHS{VFcqmOD}SpP7KxWA7Hy6MbW2i9lIWp>DoE-+((?eeW`>YBXNrw=iO6WP|{N&3jB%2WS@& zj#n-IGIF}9*pJ;$z_YX{FDq*q9eg|Lww0c~zP@2}Uk6QBFQ^m@vKY-VY;Jx)Wm2&G z$bc;3``FKm1b98gqC!HothupvE)ltk%**}BoEAYqn-e;FirD~!VrhEtalNj5Y?FHQ z!UfC>wo7r%lq*EI`ati0T3@UiZ{<^PSgE3WhZ>}~l_-BL!VX$=pnpTxet%LS(qUxV z-&_#XmxSgF^!NKK=Z$GsF*oXc*DlTm(G`C0@i?Td4so@fZezls<_JjGdEr^*UX<&y zVmn`N+~{YOw!^$JLJi2abv+HF=%}QbG%^Buh0lLH-^FA3iTH(ulaP(@klkL`@QA2< zer!Bt`3w8MUH}`Mk7#JO>OvEy|zXce)zOOp*M+tN=t{Xb-SgV)%F@2^+4>7 zj8<~jM;fsX$$dH+5?LwnU0pez>4h4fccxNHeo{++6I?6CEy3@c5R8cpc&+{(o$M%( z;!B#I!OZ!sF0jrhhX#MI+w@$La)s;&9Bgg*(rdhB-+GS;ffuPeJ1<;aYpg8aMMXz( zu5V2WJ-cMl`kt27ENOanc4F-yTbY@O1ZqLfTQ^ttv{Ru3toQHdhHD*j)Y1Ngg<(J3 zUs%~WI9QLbIyyKixyYFR{rXkBD1wB|fp}veG4r%mS$QWr%EjKV3c?$ebD#)Ek%L#h|9aP?g;9^nPn>l!7)ot$CcxTUjg<2#p~3-@$;M$io@ zJk+B;e;%XVJ5#QK+m|Rb3IAA;O%cmek*nIhEYaOZW9+?Q4hU+G+-|$KiII^gB6tvz zQoCc%u21jY*1<$F9Z=D@8~IC!$nKgjeTRkw~k(cM+bmhDsF?n7K$Rk3a zh66nETTS>4`UeJDN_1d`9V(2+%N~@gvQt{o2KbnkBC5DB0|Hg6oE!@SQK- z%v=Y)dY)BK7|e_x@ueLU!$vO?CHCt-A0zf#+XSjBYEF{uO=O4MRHFa;UMn_={|5wQ z*vyH4Ju0`yT$;|zgjizyL4`rnkb2BCXd%lTrpYs{R%c6^h&ZMGQhzcx54FtUl1R(>9ZW(Bt-ClC!hHw;3ZDg2rY>_Q2=5^O zUZnB(E1Td%{@B|kSei(Cy%r-+avL;;gV(I?Z1~`lbidGuZ!+ehN^1oVgJUq zRXEmh_7{on(auJaM1_nr;w3VvO*UR_$+Ts~OB zdNWqh@#>YcpSR$r{O(3@|#S_r^4%Z=_`uQ~Mdfd9U1 zuexB;TWTQE>?aZT5bw6&3sn#tndC#yV?n?MbSwmSZbabp0U ziYmI>ZgRf-_{8cFO@T$B;cFcgIymK>|F9E}#s~(NhFaPb3n~WrCbaW1@+-qAxAJKC z+H31-TmN;5WU3dGZH%(~h>b0&^i0uDarK<0m1IgKj%C*WS2F7oe52!eRTi|gYkp@I z_U+^ey6F6C)HGYodBCb9Hk1O+{~tK&I)%0+L{FaJL)F z9*}NYT2FlXG0y$;eKepuf&%1fw+WFM{=4%zM1tD)6mW_Uq(u?aEbk3R7G~xa?%k%g zbbp`abg5sTvvbFCekO{=Xd8cX*}0LHfd74OP<_x0>;n}C=0GioVG%^K+P$dU>H+QA z(RGf2uv$TbmifvW1~K~u4(-qUvK#G^n>SA6WczGxJMDy&j+;qZuip%N2l0Xyq39Ii zHcYo92AI~%gf=gMITIf_djGLru}}Rkl!3gnfPsixPHmWdYOy2SFWo< zl#O93^zuj$RGb$>X-xsi$>bYMaiQ@r`Oez%WxLX9=mjDoT-8%=JbSAgrEF+ofs&Sti==iJK=CQk`dMBXgEh0YxQ1Z7SY*Ais zQLE(Dzd~Lh7_@DsdQ#`Nt^CZ3o>|Xe6tbTBKBc)o>M=7tZM2R#*gPT}S{zIrn+TeQ zTw5;g?*6``-HCnIv*VydufAXXP0bzSpo_c#8jzv6`KH2+KniaVK$*8*XCi>M zYiv1;c<{nn^lU&F@391+3wVuuvxrK7$MD7O2#sa+X_*ImCGYR@;O|4$ic896m0wRw zo3XUMAHWOiZ_OR1wWr>p@t$qO1dfn|PT<3+p3Z}nmpdMfZWwTM^4ssdTr+dHa@qdU zSNK+yv4HbdK2d2>rqNsZkT%VJ-Ps9@P#VwwG1ks8R#jC6l%_v*Z+vX_trNZEy6lLzs_|K%EOQ=@ z0yUcp0X0s?@8AqQcw)|Lk>{&3<5u7y&oz(dRBRYx<6JCNDpEshhk(rldJ;O1$K`n{ z0Qe-p3qYYk07GW?>|U!#%gDhiE{S=+dFRVLI{)sez5V?cXLVJjrM~gCB;Ipp?D{v8 zr(qY16~|JbdH>!13GADZh3WK~eQ!_CkNC)tuA|p|22*#QXXmt#9df}lZlF(4$M(LM zdoy|aP%j7Aw`!5*e83!DT?9#vZxXTSww@0DMP>|$nV>^7RU4(%d&gd03cD2Si|4Oz z8O)?%Ub?G2B8+fjtWUJr?dWh`ec0b4tv-%kF2la(0;>8j$kQo$*Bp)0N3RZa{t(+% z_c0aqx}0^{1MYt!`{d5CEHs--<;;$-T=RQQta&ty{>EkPNC_A|Sc=voyFa;_t&eVv zb@wlsjz~yIyb^RhYy#ZC$PL-e*?w3+=tg2)7bGp-@qQxVg$KU}AoOQHV~jbP57L6Z z7pwuOG+w^s@Hu`?N`PCb9aeMY`tv7;-l{U-NWNbEbIhf0r>A1(YV4k5W~U_pBJ%JO zj}N8bx35=U=`LAbzZO?Fb14wKJ)bSn@eylb>MfX~I_``8@tKEs^VCDqH$9=+!C?RzXU{vCn(c52MI8{~qox zE#0m8I9{D`k=%52;8MNyjSBs0<IUqA%jkybWypx2p!1j+XdYqT zNdg8Z3jakb2vJ)$oZm13!r3T?w7MxoNmKJHpoxk$(b11aPuVBrRr~$?5)pfPd*Ri* zm{yjT_8cHdbP5|eV?dA4v8`fW@ymcYb`{V*qn@?ZXtv37pm94neIVL8Uv11R(d&#a zEr<9vJ-q*ZR`DHmkbc8m)-gx|wAB6H`1ne42LvP()A{@xCx0C7&P?=zAM2d?pI~Cn zI-xO}@w>0_6iaoc0XDhGcD{Jj1gdBEMxe-c0gdHwBd9HMnRV!uq%B?NSLxN`?t}>Z zk;>z`{(c+46IbqdRx?XX&zad2`6fmd`~clh<@X%wL_}bUGB216&VTCc=-2@-=dK(w z>grt1UvSw@z1@L+?iRbOuFtdJpVw{WU}u*(Ex&QD2bQ=EN^em&H(u|BKb6C$wF`Z@ zPet(XNC|SLSr};Yhkwgi#=HRNqeEUAghT#sJKAXK^j0vLf_6LQJm7pn zCwzj!NV(GQHa@*KuD*F-8z1NF8tC?miBZe6aPH=rnXE?JmIDqw*WG#Up-gjJCCZ*q zA{H?`CraC>q?dFYUSWJb+>o{P^~^i7h}mCULP%UFcU4|QAbpfnVgaKF&{$91lO2UA zpJ0X_4c``kCapp+C=&L)8Cck4_0}Xo2WtdQ^4OSazqnkZcVmJ>PEOY9xEeGqE$vv( z&RgF*I`buP=K#k?{&We@5$un#3pP!RjXC$bi>6g88UBOnqlk-j{YjkUC5^`{cbB8M z9PF(j^DDp$d3I>R7hBo*ixI?IzV>tA0S$X_%i+Uv!cckr%yl`-+{n~4>s(ArRr711 z&Vh0JM|^uC>u(sQJ01(w6cx17i zdp)G>4O|iLD~;pxLg!w_%Le`^7Ev6}=df83Y4O7rB*4H3<1ZeE%FSnW{%hx&VOjC~ zsg^DANGyHp~AG3Y2ZE+lr+uvN= z?5g;<_bU^in z6Xp8EgbQ`OdglPDF|}wUXR%553qlRYaaDeICnwp=dr+NlOwr$Y<B%&K}lZEX`Lh zbOH<>%YK1amIzD%chHN7T8H%)$Rffe3j)}W*}&|&MebY0o3Z+K z*YQ)4$a4JyQ>tA687&u1zkCsWS;e~6|6`1S6ZkYF@`K+*oKsi$evcuo?Sw%}LYt){7ggt%iU0#?h9s376%jlnRzt4GZNz%mTV2hp+RvMWg zu>k{>TFKwBwJ+q^KS5?v5PXmwvnz-%&rY-+ey#`TLvljGjT$^>d^I&SpqeJA4ON7M zhKbqO6qyx&>FN3Sn}aPf>SLCuxcIYw3dEsZM_uaJ8ujGk2E?XjpJ-TEaFgfxtLu56 z@jYEghe3=B2A%XoIo`aH-euF%)8iNweGv*SP6#$tIrmDpznj9iYjljropkRgSKuN( z7^MLAkH5DUXc_Lju-%F05$_wv#v}+kW@cUh%}ER>#WbzEfpOP2E`C0~sS}%ds_MXA zE$vuXGj(N_sN4!2D0F%76pwB~+u0z2m&}mW3Mi>Vc|}EgX=0@hy+TqT6*~5>pjWFV zX^9`CrSozvwY>1yD`fGIYieq?oOIb%|K20rVV@*vN2R1t=fg?`k$`1@Jhe!lamTq4 zv_f-iWFjmbBDamXEV)V?@u&u>&xe>Hz7da*125_kqso$5QvaZ#$xAdRt&@5_K%}MRmZI1DEQSIapwRO|0_c}kz`;barh9uy z(Og?T(omVLCd@J zGQLL;HdOSL?;H_}N3`eCs+kr7c3} zG3|12xmDs6c)-E7`3vFPVF0X+FP~X#7bWlCA4R9bM?ncl*d~JlXL?}2kaf$TPL=Uh za5}MD=Lal`cZ!>8p_Z1Gb_aWIcYjT-LPKTddKMNaqUjWdw%@<$&eQfd(bm*#?(DoG zZ+c1)P1?}-xKGCZS|28(!#QqR-t%)t}b z!0IAx?%fhM4*tG@JKeqaUWQZhV}RvuY-|KM3c0aSaBJ@X2iUNH`B<1aRxD2ysEMe+ zm<9w+VF%@R88j?au6Nn*Yt9go3ubp`2X$6PJ7%}Wdt+i^fFXKnaV5IxmtF z7*=m7G{2XdYwPz?-Dq<#K-+{L-Fnr*`WNU&)B;)+5TIg3>L#~UN0gMivb5oET8(s>cW0_ zvUu^AUolh=7$)C4KZU@z7p|}f8$yB#DhaH`xHD3#tpk*`Y<>=~8goG@p?ACEk5+0@ zzrJ1}7j@#Ib9mpn85>7UIJmjHw~qAu>EC>JeoJq*i#{kqR8_^L=`@H4`sG4{%dm|r zg-x7vbm}ZcSm0H44$~mUcSl8GZ>AS|9)?>G#~8X>nq&( z$vqQLflF|gd>C)G-zshvSa-wy=nWjG;@PM|C_O|`j zml`;6n0Wr%jxd9c~kNGwdohA?sEB(xpB*)t?&3+lBzeMe&e5%O7<5 zYt8_-<-fE<6)m)RQ3E8yJrP1+JK&?L; zHJ6q6+|-Eb=9B9TL@2mR(d~3|rPF|GC1z6H2O}$S&YqdjkV#Di->(-_SyJ8 zh}bwbEBDY_psfJrV|(2*v-7*JD>*?waOTpdbM188LS*2LN^edN_=@ATKhJ~1LfY2e z5FGdHKECVX&9foi`W+3|43c?Nc2(02yvqp%JgN@sHE1ARKuj``NfoxY4>9B9fBo@7r{7mNVQ}4-qJ&^D8K74af!_0|LnE~fP~(uJ1D(U=L4P0WmoJG8 z3LnXUaf^uP1Sc>nwm1s58chv!{4S_120l`}uigFQN^6kInOxJfql ziII|>qJI4NeU8~OI*RlJsmkl=wocPSy6XdA{K0BI_z1RUg~lR`6*(Stn^VFiW;$GL z6YJt)=Bu^SN6VY}z4>xVD;}PtS}KGZ^QM&$^wSUUtMTdisH}07x?>+CzKLp%<{`!DWR+ zJp$huTyVFS)cUtPP(aSmj|6q5xFUme5O8wh@Vx>X#B5mn+{iB z%o=1-xz0`v1(+`Uu`+y_@ zV#W2LHkO02EFOq&1|@&L`ZSz81?NqUqV;A9IFk=N4A~|MZ;^3uoJWNp&sJGnPtU8< z^VOE)H&g!2)o;d~Fj14U4oO#lg!~`=xdhA{NWR97Gy>5Ff}OqQ@Sy{YLLRU5sKF`R z{zLNxUL;a3FUMJf8Xzy4oSRb`O-Dzx0nZa4rmvQSD2?_vovjvxz_oErN45m9QBFox zcX{*=Hant2`_ymu-U9nmO@|klH8?uT#3jiS7Y}3ygFBjU3hfT&+~6>=S7;69CZ2&A zNl@ptevco8i!Q*X2l9#vkp>4Sl=4RDR_`MgBYJBR?n8YtL-PG;cUKv>dr&7iBR3xOEr3@kND-~#&2t_CQD zH_*xD@L^iH>pwu1#Yq;=1A#OPZ7k4=&*#M??3V)aUYIHaP21`5@xQMjt9bbMA#uB9 zS6-78U|=mnqeLHowVj<^^O!~SFwmcYQ;LS3UV~-x-l!KfcRZg?*$N~j7K&9MyteS zGxxnR)n|G|5S*Q+!&%^?fYHW$>v9F2&LiMjnW{V208@Ez-LRzbfdv@_jdO~H=KWJr zZtD?Hj5C2sVQq60@Ke_3Y+wkcbS)i?)nWv>tN%fR+GB6a-t(gS#qS(bVIac+xtYyp zd0zL)IajCfp&_$=4Kh8wRPqF}f}C`R|E19PcTAYVfH223@To2?l6Yx3S*%<84YuHk z3#KsOlY)I(qh)8qK^$U@JFi~Rt%B12xD%MddwRIEugS>BSnW?-f!z}&{r-jveH+ZE zTsfU@CM>%G^Tt0?XalOjBC{kTB?%5vgTLEVODCAD{i?C(N%+L1usF|*yG&D36p9DXk zK%7fA{h|+E|X25o=cFHepGU?#s zQ(!>AKvu`S%t412?%R#CzNhWNhr$#-pLpS{%1y0kx-h6wmOxCPp`op9E;a+0Rnpac zdoy+Db%jHx5dV8{<>@@viNk5>@@&{tr6YHK!S2NS%k7o0X~%Nu74)@;XAzzyJeK6mTA$k-;3<*TTNH5Z};H zOyK+Qm$-cETOL~ekit{Rh;@cT!*GH~;eEvBPv!x9WSWmmvjZW3oGbNNMA(}-=6`Cd z#W3DGi%Bbm-5DH7%W7ySG&MWByPtG@%?$^Xuc?@wi$M__pGyv>3(yFe^n<%q=(zF& z>9>v2V0a3GWr#Tn0o(UAz@-6jVZ|X&{L$`uOs+naP6lc< z=$LeM--7}I1V`}Q9qDTZ22pA0H^9NhVKTVCXARV~7BJkF%vTGNECJA|kB;nunwltq zp>RA`L%>-VyaN^A4c~&>sZfo>b-sT1=FZNy>c>+$KzS6$t^(qD7Myc*(0M2G`*bP@ zJ$$K|s!=Bg^OA-OUuxm;0K95rju;`qxlDk6Q~V_U>|x3W;9_KOgv@9AC`>R*h($a^ z3E#H0yl4(9Is$y9+g9PjrH?W)@R5*=3>skW6V_5gL6ef=;pa~W_SCEE>x8;s@ZBSb z|MPVtJRvOq{Z^9yU%r&(>=9am1ONUW2*GeTNYK`|JPjmW4_LhBbkt7oQH_W@!m|@nTWKFaHOK!G=u$ literal 0 HcmV?d00001 diff --git a/mac/dmg-back.svg b/mac/dmg-back.svg new file mode 100644 index 00000000..1b8e61a5 --- /dev/null +++ b/mac/dmg-back.svg @@ -0,0 +1,251 @@ + + + sfizz logo + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + sfizz logo + 2020-05-16 + + + Tobiasz 'unfa' Karoń + + + + + CC-0 + + + + + + + + + + + + + + + diff --git a/mac/dmg-back@2x.png b/mac/dmg-back@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a9d91d753d3fa1f61af2628b25f0845679a1188b GIT binary patch literal 40969 zcmeFY^;^^L`#+4LVuFfRp_woG~?w>v$$BxPJdS2HVk2n|dT21lRb-L>$BqX<#Udq2AAt7BR-mYE&kEmvk zE`YmhPA}g=Nk|xjh_?$-i#wL!!TYWXdajxfD_0Lw7fTWk4-Xz2M?0vwsgorS#Kk&! zQ;H6}=r-|1S~jlsmLyOs8*lFi_7H1G#Kz@u@Eim2xo2*!?;$QES`afEQ>ga?HaABr zQ?>`nrY?|<&xI_1&B5zviLaA$u{3qHfjBS$*Tsh(fjur zh?AF#jrDt15;-}(2d~}C>}|{+$U_`VZ5$uSTUywd|L+stySh3_@ba4f`$Tt3bBKcj z#1TqdG_TXY_gMUU3$M4O3xt=ShmRMIX+9<)c|f8h|4hp>WqroOb<{eE?IiE<$BPd> z@rzsAJ6&Y^CH9vAIfLmJR~gv*(RjFCU+E!|(kQwvU1^Pxu9VEQ_Lit^oT)*%qa5h@ z#3vn+Q+`{>U-?L4S+L3M*rS8F#8F_Zls+Jy(zaDnSj!aqN_)R#j$R5MOmK zAM=2FlG}q9z*4SVlmP#K{PZaq3CV{`SHXdid?mTS2=4Aa$RH&ld3y1ZEBNE(hY#f7 z?%My}bm9Nr^nV-ie-ZJ2squd`;{S@}|8vJ9tlIW7rp&v=jPO3-Dw!c0*=DBr5lBkLrx5OD;0?1C1hDQsbsea0#mR@K-meyrq zHXIYee|Ru8)Tq8CrA_90+Zv$4jIg&yyIEm>yyWFYk|P*V?(nqQ19*h!K=6IRvZyR3 zmJ2`rFaT7z{JdW)Euz`yz;D@&j*iZ3zk33$I7hHqpKd8KzfLOioroEYURqjOT2xNO z!6@0(gCS=-6Xv_4N_Xy*@JRa9a2Ox$EAO;p)H`-CY`ccyM9BG+=FOWo!>dQXS^_kj zf3h%nF3%oK)5xB+gtcokNHECahj`Jk$6?tg&)pPbub(o7wO;`5`QB%RVJ4j8ozJI_ zbvD`pDI&<2T6j+mxT8vvYdbj^hhohq`fJfiYq=eRrgFr4MG<=E_2u$TtGQ+~ zP0fG1?ruLv<%f?|BwRSdZEHR~eEjb+1pkJf^II(c74!VbvbwfrfLvQ!%PuY!3cSTk z_vOnMe(&D=1OYb}Ep2Uu#g*}*mWlCE_(6#zdih&6|NHF>c23TXWoFU_Mj{$-$T&a4 zcT`WPMm01vh`AiSSN7SGX*U1UzQc`R&0*!YTwS1*G1Fs^^p+|tGNAA&E0&_9pMZoS zkw{tz`{@t|OAtS%-UT4b0&6&i1fiOA%JLwT~{h77siT-hIrwhS!JXtI2 zx9ZCEwo2+?eHPymAC=C>vor%$+}oI_?W?{>q#3SCsG7}SnlzvC#k!wA`C4{1%3cu8 z&v@#~&hX^z=r78cg)U7RBON_G+6iM>>80LO#*PkYl$M~Y$G^ApN8F0o86X_BiTTtN z=4>n(K*CX5O&b+>dq>B}YDj66Hm6BM1F|8EXKSWWx3^_uyl$ysmkb1GhMgakF;^vp<$zT)fRlQ|ue{*jE*)MZ?HbV1}y4a*fE>Y{U1!W%bR9(DKN z7xw%!Isbk04X^X5x%P2xltCmJ#eD`7{8Bv9Ve;6Z(H-#zq`<0l+sd4VmexJdIdAi6 zfwd)e4i5Wxd{C)8pmQI1ve1L`M=MdYGdkSSUG4ELC-qU&Iwd7^^z@j%iHY{r*wzS8 zI>3c%&ayeS;%e%=ky^Nsc{w5r9J~y2_GpK~pIVWe*}L)?-q6-H7X}8 z9ue1v(%)!4kJQLkgwGt#QUzQwnKBiAX3g?1_6B@>?X)K(L&L(%$5WEcmsAC_^7Gj#sGfWO@9l9-6n%!kGXXWmUUC;RX1?VFZ&FX-M3_Bx!tL-{0fK+f$eH8IO1%DYFb z(dp;&_>wuokyyGKKV z&6Mcm{r9y6em;i?jI3AIq8K=+iPrsCV$w1doxJbs>njI4sn=kkpkzIS_aa&mv7BYtq=uf&B8X7Xp9pfO1TeHo(dSi>?Zo95r zhCkWew~)A&c=Z&ahnvkXG!Ht97vNkFdCm6r0t0>4NoWR#cxS6Fg0BKxAJe4Y-(_%=tQ+` zBetb63seYoszn_Q4O3z!A4RtwW!D`vtk9IaX!RIq@x<&4dlix+Tp7vBR{l(G8Y~IQ<;7ONjR-NnhKj{H z&})ck4fazKXX3q><#ZltFXA(FAGb20wiaBG(RK|a`qw%fmbX1Lr%1oAtp!tx%Kq`= z@mx;zltJS`dp~2NzJF<_{IqLNFDNax`?wYyWG_L(8CN2@)M)>nCa?~iKbo4`@UEMi z8#f{#=w>K@2m|H{^+VIs3?QHe3mxFSYnXGgt%$dkkPu5{UHEt(DyybOVa`6m4y7%~sHh zCDhH0XZ@(G;^Mumwd+_{nu`)o>4ii^5ywz$c0=xyioU7*va+b$+}utJ0m#6OUip}N zG>UKEzP%TJ58G%+B9YjaTm%1jMy4Mb7J40%hF@AN&zgQ)<)kz^I$Fi>ukV4qlG3?! z%$7mwdvkw(-x<_A25A?rNCt5_w#fA0!b)xD^V2UnbEmKbCTVZ^IsZisV`C=LG6q`W z_GQWiwg3Gckd+@4Z%(3b_x^qG7hYc5eHmy^adI}{!?{;6hbZVBOpuoHny~@*t+PWh zO|@Dq<-=cOV(xo->&SXZ_YGf8@^#rsThIAL&~<{N+0;6~_L&WAHgj)WzI>VAY#}&- z&)G1XURLBqIPEO!64k{)5ze@h&`Rrp8ix4z!;pH9-Y#&6xM9eWV$Jc4lZ?%7J4g;+ zCeBYnpgU|i&p&swNB$HaFPpio7|F2l^%81Zg6@ZtS9D$x>&EpZIpxbjKcs-R!8{lv#WdiF=%1I z!BB0i*<$F}4t&int2~pxtXfM~7jfc7Z+_Mgp)s1xo~x3`Ffrq#s*)hqG81$zEF#j; z(u_CTO7n9rT{SeUd(8+=Kto^ut|jQ(e;)>zq1&(VZ+CMdtI0oXI-ZB!$j)rZT=ZP% zyyLv#HiFaBa1;U`aT-ruLx=Pq;TFV%ew@{P@cb!RLp^{9dZ*pPwEiH-^*P{T`kUjrBV0I!rf-WEM7r1`o21<*J1kz(wxs!~=)_SY9fEo$HVp~clmR=j| z`P6r+lK!-TMyy(6$}gX*%TH@Hbq#0+q|OZOr<%Cuatz~^mX;ImCj3X>eHsS3^d_gf*sT0cgX@FGAWhl)4C1~E(uX6JJ@!Qh-KPo~CMI((QudRB3H-PdkcTTfHrJPRh{>mZ zy51$`w(8oV+!a#mz7ZKfM&8kSB1+i(PE9W1zV3Ot?IRn4!=hxo-%Ui;qC04eBh`I( z=S2=L4;pi*>%z;k5t!v6b7ypW7qJ|tNO(1j$xPSBby;LV=637M{!;Nff!lWXM*gGgZ?*s03(74zJFU2IZYu5F-uzlNe7aD^FoKO>}r*Z-hL zXKvQxvY=zr{P#az+GF)c^N0Q^BbjGqtp`@&^r9lUMo_o@lS_4mpwT*S|H>5e{QH_= z62`|tt}XB2U=%d*tdq){x(&{F zso+0$_TaZr$MeaF0T4c;l&!Y$UWWk5GU%!%BR4twNKaeff$+&%2yA_}n$3M{mXZh{ zg$Kli0el1d_+oLTd$P${S-wd+=IoG$vl--jwqjI2!P&3vMAdowZ)O}Oi%G$m5OBCu z&hk0@FsS(&Z{FPf^5rsMNCWwR)dU8fFwYZ;CW1s(5)~3)AZH%mYATBP6Jdm=(74mGARX0OUE; z4*YKm%k8^D-HX}H5C^G7Xj0a%xo|jqvc$+}$m>6U{8mw7<{XQs!YT?7aJ#R?1=<(Q>|H zj=;R9*Rdyv9c)fbl%A2!Xm(__l`r+V5m9M=>G|Jx_((JwO)KiJ0*H?kXeUfWDQT9m;uS zA!pXGP|D~&XMCCMKI`!r#q`LgN$6ASCt&~H04ahEw&Q9j275S{QAXFlMmr$tFXg?#MSw5`h@dY%#p65@wd8+VkKH2HsYcl+ z3JMB;#GT%f>oPbH$adA9OOFfA(U*Wdog7InuE+*!AI!AIzP$R4};$1-b#^SS0Lsp zMudL==pX%>fVcSJ|LH`DqO-UCO3qW8CSZ6g2JzF)B({!@4&o&%fq;tvl2HeskH`{2 zR#sMm|3($DSc4c^x9oE+E-j7p^Py;8ibyu^S#n_Zxsm1p7=xt1<#-W!K5&(*tE=v^ z0kZ~A$z*aXt^481ygb1`dGP;hH*$0hV|L(BX|_7r6@S{G=s!9>4*zsqqF6p74sqOD ziB4BI$*8;oPIggrpmmhz%t|1!Zf7Zxe``|`>3fh{T+CJ4;Qh+bZ9nEcINu0*QN(I& z89Xz9irEV_>*tN=rH9ll;Ct^`0G{!4Mv*%FzF>n9o=l=OFfdTB#zKM1pn`>tj%U^~ z8!)}n#`B~EX%8Kcw_Frd!_;NHCeyYb$2qT%2T#@Zb(<>;)`P|xUyd)4X69TlF61P; z6+Ym5UQR1)YtfJA0Wl=nTgT&=;B3So=ESE{=F2VOFv$S;+?LN7z|!^W;=}w`TPZK#?JzA$>3PYn0OoHE!=6~Z~4SR(79kdmt ztJ_RX)I6%Ix5!~zQb5@mT*9es9%GH)3%{`g`js<4=>X!m%3PEfWMz>0vuj3FuxdG9L@o&Cbnz;@IT%A|^K0*u53Q78#Z*>Av`LczkJ= zpUr!3dC2jMG*umtJ1+gY$8lWx)PP9S7|GZl{q)?^r07T}H#G{0Kq0t)d_2S#0?BQq?IX@7G@auc>ZTep*Y|Da>@ zB0xOoW9(PxxBdS&3!o1va>sFt!U06Z=~20=fxTD}2DBv5E!ky!ZkazDO(BEpO4*;# zVP);$-%682O{)X35d-8%#7Q;1%j>a5u)$IXQ|ePuw86o(9uayq_6l5{E3skJxm;Xa z;V8#+Mvoc4yoqogi~Vk0O#2QcHv$N=&I4y2*m9QTrc16FBdBUz3D8`8)lOEy(fZCS zr#BaGj7S8KF*S+SKxSrb9eoV?8nOL7$auzOZ?!ZjDs`!I3m`lH&FUd`rgS_y&pf!Y z(5M^GDf9VH9VN)kdWiAfs&-r+*jG?e)gUuT`{D)+n~{x6@DH2~n=A^%N~}ouOG#9L zYmWJQECiepsnCDaDqkW)5CuBC)NxoI&&kD~AgPFAQ5}Bve?)(5$k^E5`Prz}L=^+Y zeE~7YRKMdJNzXk1^-9%;LZL)(%I3GfIU>1P2X$0Cc{LTDIHCB2CCwMD8{f?9t)%4a zyM#-RBsKyR`h!|teZ9Cp?zE@eY^p=j=4O-2JKy=9bcc8cj;_|w(6*hEHAs!E&q6eX z+my!p!8>5fG*PWvPXVU&-J_BXoPs(wuS>%vlj*IDnTcGE#v}ozR5V9JLxTVURs?D* z#qNmZHc^6)f^CmXo{gvJY=CZH)mJYJIs&P?$MT;v{1|R%dT;Yjwyt_IUGx+6UQj2F z-J;a9p2o)(m5c%11RZAp=~gmH?byE4hC$68TQNvEvDY|GQA0M6jEE@4s2ene2Bn%n z$07E4z<>E|c0VUbS-y#hGd|aWJe_bxAB7y9%bu~TrHD-xHvg!4+_D!tfEX>xT__Nc z_ygZh{znxNK%?I2WMl3JD-Z^iDzC;I-=ESen=a&Kwg>iskzz#fx9k_~fYwmn zft39+1ZZDDK{`uO^u7j(VGHv_ePSQra&R-{(VuO=R)U ziw@`NYX?F;l9qLvYYz$^EnIfhuNJN*!rPQR;eA_c@7Ztvb&4sI`(}VD568&*p|ga! za#d3AnVchOn*Ci#mE*ah0EFR2_?_%UdL7Qjf+SwM4T5d$*T(>HgJ!?eqjK>TvJ6fG zKs-H{3a~uh8_kyEeLIuZGB(aX9sjN;R+b;d=9D0rycaIuk#dp5t95$^bG+zXW^Bnn z+0sP9yc&Bs3^2|Y}TPWa=K;l~c`BztGXI??tJLmavx%a(_uQmWZ zak&bx@UPMSpykqoV`lTa;HnU2^43K|YzyE^UmVILtV{FBBJm@p1g*_yko*6@fz19S zTT{?;@@rrb)v&pbDJjpGrQNm23ok4uEwxth5ktPH=KJvXqXTA`AUu(2v}An_mN8ai zJCbX{XpZnAf69}{e#!L}AaVfj8LFMoiP-C@om^P9rEacR$a0!3(tUfnl1?ahn!QCu zQ=4XeK3+Pbq2Vm1KK671(2>+P9lt|U_J!?_22=Jg4{A3xtX3cOm6_O%=@`$lov*`= z)xsHsS=6<^sRKk529Sh7q@ArT`k!R$d@9dW^r;jOR*4*tGk}nwPRn%5Ds-4dNP_iR z-Q`YqL-Mlg>+2WyDR7$sto1(#*sU#xO}NBDg-rS5-cYRO~b2v{Xyvd5LOp`2t!iHPo(zuT24 z(ROpEE*95kjc7LkoH^Q@^W(L(v&HG%cfIw$kJ9@VEx6nkm<%J|jvUETLwFF*eTeLF zSK_Uf7A@=uF&F$>?#g1L)LrMk>JiKhlT&+n`5xTD_WYxrwk?7fkW*#R0qc zX^~M&6HAP4A%5QNJCFgk^PpCIo)~P?SJ@!<0j0?qJf8b1Lcy_N5l%$A2GtIzhDZMU z3zc4lR~xQ?U~vWgvcK!V_RgKQ7h(bAUxA;slP+}!5y=D@J1>y+6e_KE_f9KhaXXZD zQlECk_3Aiq#+8NY>JmiMsh(kpHLqXtLURcLG=iH_dS z`+n`5mqCm2nm}Pu5zgp&zokIp(P_L4J&?d5`_o>lA$gcz=K;q&6cVh&1-VpXS2LdJ zzKCK{5MQ~GQHiYZT2t^zHIcPxe-7JxDu;VuY4?QY1dP4+9aBO+6*NEhq{;^hgn-vY1Fz9ROQ!KCssY zeM8>JXeQ`D1Jp{;SBLV{)7iIlnVNm}LxFQZEB5}~P0&>WZ!+EmZQX59Jth!{?AF$U zC4b3XtpS_$KMhESALD5Bk=}djcVI_~bHU%gf0xo3uf9ifcshtFHJd&vC%Psbm8~ak z$|#@}nE}Bj_th`f+k+1k!6}#@mP(gHv89vEcIpf=zK;PiK#p1)85xa^jde^_YTsf0 zx#dAL`bL+(@%x|F0ol$soJo*_sNlG^{wE1!3m^e6{3x5J4km3VSGYlgAZoVNeoN4( z`$jS5#EJmjs^cCndCP1Lj|?RmOmnQ&$;5m2)@n%+hw0(rgK5Fm$ZM1cpMft?|5e(c zBrs}!1yZGK|LJH99?qk@(!wPg&BMWrZBY;@B(D)-oAGg$S z^!w01Cc5Q3z4iQXs1-&?*^8~ngB`1kV*e^f{HMu=*cUZS4hUs&-<+hfn>CD&ZfVG_ zsHh;KvD$*D5`!8<;66Q6OXE-z)EH2QKl;WyPZ5a^VQ+%K4J<1Iq+`n>oan2>APSeS zgU!Rpp0^TM)zT$qhDChae;)O;p2TZtElfY~y$54;3ITg*HiNtcNF} zN#yB&+#f9%DR0q(q1Q z7r7bGs3&VT0b`g2WZ8)5SF_BXOYK)O6Qs^}%g!zD-J5)QUFIeBSc}~2rzLLObC*UP zK^zV+dey&yJl0tUx4pFqQQ#8m5{)F_0;2Y1ba_mufDhZcj6h~2tqi9 z=${)OY)Re*@X1U{oCM^g&?K zxyHgdGn;mpz&@g4<-SIE!yxO=0x@a2$s~~9)<3J|`)idDZ@bKAJ&;*x(CR2>KT}b% zSO?&6%V{;Qp{qz`O|HoK0nAsFj&3y@c%j5R&B}>UP8S#QO z&%sUY5L^oVk$D zsG@xP%;7YZAS7wXC3%Mu4j{Ny^@-H}nzczV(RVtD!7d$>8UdTW75n$M+)gv>$UjBQ zSzs>5H6I}8?53tBqpfW8YsUlLt@S{U!P7?2vJ|5j`jkuRRB|_ z+~+V&%(-b}s}^V^{O;2UL>rQ5&Rn_GB5-oBfx3${dHeIo&qM#M7);|PqsU_*#?dso zZ$_Ts4{G(LwgAi#AZ`gQp%G!Vx2!>we4|p-bbu|3h)NBXZai!`n{29<>`xI#fpW}6?eWc~O75LqQLasbtLoVy5Hx1{N4b8z|G3bU~mzC5es`Z#7l>%TtfM4_6t#D0~^p z&Swwx-UF^i?HmzsqCq&vyP04IOoH>$eV?=(MDW&D#m2<7Teohn5K(Daj>CSTE~dZH zu~t-~iQ)pIzcr}YJL_fssnaz!jEjNyCu;2o{b{X5+5In=yN9+9f|qq}ynLn$1umlJ zan9uuBw!5L8gKN63rhfjWg>L(BKKtUz;ueRaCN*N-q02dx&YBEzf{fq;{-?$L-*~z z>cEr0{9;Htqm4g)b&cQdfSVskNO3i5rL7`Q)D!PX)@+3b*V3%w$214vCZ}aEB#$sr zhm~uR-rE2wc9+L}FJTOv9$8HYm80q(KkE-BmoR_r%r1JPor;>erl-a?jp7*V;dCr9 zVtzP$gIBT7=fy}kt+*5s0f&{=zMub|vJvy_Fc#okYuRJ3(?%Gf%;44<)9d@!t zKEue&x&|$1;ciZ|DU^7ZcC~ zaS0T3u9kVoPzuk9g6KT6sbQ-B?GFuizK&OeKpJdQ)S;maRG}uF+js7Od=3NS8P&G* zl8!2d9%t1h$TV1u!+`j5=q1;NYDSa?oR^7UnI}Ox%!I_Rd&#$F2Gr9#&LrNV7pZEi z*%SAjyy!eQ(|kJoM<*;zHBmymG|hcXVFKTWnzyo`@oPi_oPZ&m*Y1=+ zU}ukLgda)YFgEra`g%_Em~UZLnA{&oLLZl)EX8J#Dt? zwV(Si3-D~vP3NfK<)4?GiDNv=-?GKMdV`icKh}A8${5PvGq5Jsp6g&NFJz3<#6f$F z4Ja!#Mq88RnDW)bQV(%>Br~Y_DG{Kc))b@%2Ll3HJt_h0GBE>fDs^D6h#V>-3Q9{u zj(NF*5i+=fxSGti!1j_##}I8!o!YAA?KK*6#N2-~k1|&Ye?=BqmG` zfoe2BD`4SdD1OwvJXdA{TysTW+!0+Co3}O=ER;aK)X>$X0oa+xFh3HC?N=C^D$FmI zqK}P@bv_wgNrAC5@Vj_6_VW6d0R`QyCw6CUAoxzbWaFMGaJ|QuN&achyE0hJHjw)=Kyon~UI^ho zL)!3r?Y7hMyR<7n&v~=~N(bJf5D}vin_uLHB<3ak!1tQNDO_-{92tdMXr(G+W_EuD z*7jpv@Ik>8wTZ(BCs~`{896fdaI5C7@)%JjBSxq{fVo!BGSf2u*$`8!@2w0me zwWOakoPZImcyyS_xvw(n!-X^R{^_Zbnhb;OUCxUVr;*?~H8qVW)n#^y+}B#0nxr;U zJbZ{+J7^FCHgm*o1YAH`Fz(cw1htcw2Zu~UEDRv{J92L&^Lj}pMkc@j6dJ9Dy$+QZYY#9AQ)CWRW;lNZ5v*yM@yU3jnR^4luqU(1;oBs5EIb?|DZ$JfsDbqi17Qw!#=Ox$H3MW~%q)I0@}n-fy-l*mp%D>D$6;r|C|wr%^%r6F z2Oz&Qsd{u3w6#$(VomA5i17TIiAT@kw}^&T$|2zyaY7|gv@e)=1Aut4+|Rn{_$0{_ z7g4QYfS>mnilmd~xI)1+x+$#xVADbOW)sUR7-Vk#zy*wasGZyg&?#BbzbPHqKnUHI zIQL&RMey8Q&w~}LOAFf`P0Q&qQR+{|Cjz^5sL`X0K`W*-Fc5wOO74zy3hi7oTvZ^0kV+1279_V(fN#)gBd!i4T;q~>56KtBxzQjwZRkHLhH%gg)> zBy^XEwfRm~jyUrZQQ%@9^{4wwZq1!iQ&YpW0pTkuO``)UueDhpy&W-f%dHRbuwRK@ zn0>}K@eem4Yx(mVckYlu_Yx@RXJt@ZZtdg##|J&>vQ%SRQ$7+jR&yepOVc8pY<>|8 z;w*Wbj(N)n*&`bOKNqV8hzf=1tdL-y-x3ljyoT8;7~w{cmibEFJZn+7L5*Fn_FAv= zAU&ybHa9;*-V$GlulbLg`>b;!oG7@GmeSq^V;8oy5@5~`bu?-oRde!YyR>mDczw|J4UIdcCX4;6?+1U%*f#CU=GNuY);dmW*hyX;A`|+g7XE7aj7&w* zC0WGo(@JIT(+9Wt!V1XG-A?(;543(f&Oj1M% zs%q4(r1r|HBKO|ldVXu>OI4+gStER6^A(bJmX=?@r~OfR2j|Lt7#5}e>o;jD-&s>_ zdG+tA`_V<~>+cP0UvaSfd6aY5cgbq`f%T>R-JBwJ9v&+f6?%HRy5?%bZbYq!rxepj z>xC?aa=mgwD=Vv6^?)n>@DJ7A`iz`+c`yQ#X?NH^*?RcZHJvlQG|M20$JT-DVS`#N zq38CWuktLvF^cL59XK4WLt8plwzWYmZ782 z6^$?Sc+xpAfEZUrX&AQW;;xZM$xvwK!7eGXDO&N5Esm>hUbR>o=eBgY6)ewUSnnD; z#qW3K`x~?K;}9U&`3)n|ot2NE2CR;IVJUog6w34M?LzH{P69jyn_I6(sQ zsChM|wM5Mb7Qxul)pbp+BzEB9`R*cTu<~U1pG#LRJGIc#7XElF!aBabzW&b6x+g;c zZa%k3`clOr`ChrlobmfvmJc>6a;)E8{#?UKd+rNF*i1hQxU#HpjXgyElYyus^!yxE z19?NO#N?LNduU~(-L36H<-crGO&^_JY zOkXBwV)sLu=KMGw2h)3SJHr7#Ugvb)%KEIg$z~=~+ z1OnQh^n@>>falwtfp0rH=hwiQj6zcKdPq05}6ho8_^kz?Tzfh;^x=Z9#zhmble%ty`cKw zZiv%fFdC-o?(V+5xBFC0jr`4b%_9E~-`M~A@AtT>Y_``s5@eObWj1Rz3rov+e<$|M znIT{6qy7ya+Pztl6+eQ6zmvQBcVoluzOIfD#K54?)0$n9hwu*)%kA%*yc6LTNXXN7 zA6~4b&^P{QfBd8@IWI47*0)QiV{PJXXP;l&4)bDkUwkgOolt8iBWY*?I)O|ie2#H;s`6@Vo7B$`mhC*sUB^g-YUDv!j) zbC3v8`MV*P9v;fwago(RseW6@0JW~lp7C=fEIr<_k(uE+NQSDL1Qf?Z0^7YM!4S<_ zN5&`4!De^SQ{fr($|5d0+1L+D75!_1A$p%S3_Mr_qgCHF3V?wYg&A+RM7WR^D=X_{ zg^i>O)Flzlxc}SfD8GL1p0WmSmUx%!%(Rh4W!!p2nosRitPUv&;krxGHYm1Z8jkmx zl`7%G>B$^?eSX7=l-rJZ9%3}6cKA_vmgS9ic6QlX^uZ@Ta(}S!h(uPFxFzeP;4?ER z5+4V#$}?+_rPAKY{7G^*M1CZ8*9>&W{>vc%{`fpKdsmew#XT{ZX%UX>LvQm<(Qn(Nk?)_iJ%A zhc+5HiodW~(WP10f>uDcPsJN^Xg@Dgu4YhX|8_a~Zz%kSy!(Dr1nd0$qMPW_Ql6@q z?CTWInbCXc)*!kMoe)2|D8*TeUUqEG)(64*jV$O!8goVAstj#HxlcY{g68p%T@j9- z!fvL%d->R2k(JZHu2kiT?ZSNdV4ua6W$cLm%PG^9Tc1%%1ds}#u?#_ z{qLQbE}N^0gxpSjMy!4ucrp{l;yjJ-q5LIShsTeWi*xHn_71vpnqRen_)mDEd-v+4 z1Yv7BE^h9G4k3#!rT-=?p|T?hadFfM!X6TrE?yX^Ta8PLi;U+rQQAUH>Sd>;u-?sl zNRhxaF+6-x*jDTG?L2nNU}Kv37Tq{DhOheP&!;oqRJ`1rx2d)0cx6rWN->oxQ#C z&wVdi8-!&%?LPy@WK*H^dHLq6yNcm~YDHSl|KBV?LBW5~-vSE1kKK0f&b2G*9`C0n zCl72Ddd3p>;G4!9Y4b$qjBvEs9WV_NC<>W;jNugYAJ)sR|N5iw)2EAID);j9hmHL- zQHVCM#Xq{b_PQ#q=Tlnoff4kd5ZL}dx0i0*VWetvy)=WEP+Ss&R8~}cY7C|#$mJC9jqO!kXg z`Y_{fq&^hgkHy|-V@p$sQJKqsYbq@jUo^I&DPJZdJy@X)igwcOx(zMXzb){V#lf{3 zH>{1-l#S1zQ+^9<--?2pkXT5W5^q^X28oaRCg>^Ok7xFaL~qmW{?tdXC25}f^a_>d` zy;T(D?5uHTS64>~eXTPN?m#C!VLCs5hn)) zPNCfDYGJFs#C|Ttz)T;e+{0JKierXn-QwBEcad0Y9U&U60Fm)5ATFvNg?2Zt|LmS2ZL2dFL#5p<$4jzuQv z$&y4Ir79YByJTd5@ZvN3@1CCMx5ePsXxb+VAM+zEKZ%(qqWd|XrNqa_&${c3vhwm$ z(8H!bq0Odjs=Cp*;{*|?fT5ugF&V|h#lf&BJ(w#>=vV;H@cSegWAlR}L+7XC;~97! zJ)$i5uRtYgZE2}+5cv+WMfdaPYpxyB%B5J>LC)jUa%Wc;dBR6Oet)#y-tw60Jgz9L zo0lHcA8b?E-Me=m7PH)W@Gvlt7!=$4`=%0O4urG-kRd~`cP3W+U9h{fst_#h_(k+K zmyFD}yX^%Z0d_p#mfTq_;hN&wW1iIA^fq8oW{G>(1K;ShNcn*~yCXN4k-6^bo7RFY_8p&FW2&8YmPZ@t6`rLWdu>{H#71ZFi_SfI(D#_C~EYDoEgy>qUMN)6e zDat)=e?N(w>NY~+Y%M?77L5Uo_zJz!r@9~Q766S} zycdaMy%6eoAaoPx*cK8e%j@gmD}s4i`e~u3Yzyb4r~8OG6%$fX4_%eSgNL3{Xa2X^ z&G^mC%yO`S1K8{ub?(G7v>Ap&3Wx}&UlYHDOq5j?x~;Dkb06XkOLq4)Eku+mKjeDu zZI}N+2n&7WPSUL_{xvX1BW&mWD9-uIHMgFD9z|r4P+hb3>`$GIq?AMDyV*AmJ}=)m zYaD$MeEpODl|t6dqWH3(jvJz2)R@dzAnl4>I7m!j1Shr^zAbtZE!GgZnBQC_+WCm-zDWpFn2OM{JToE7xbfYzo+u=0sc`@S+STFmJ!GOI4yUKj)8ylt&2-}$-OGF0cBRSCfwNzA9 zhpK&Os+r`ts4+-_cs%-uJK?=VWX_JDNA`SHVP(`W2!iOyZ!-!aydl$7DL z+WPoZ1lIH@-}E}O?l-+dy_(r zx$A5uy)}I)2BjGXu060xmKKERwi<$*1EKl3iQyUq`@9P<$hF=HI-4608;DqZ*>!8E zT3`1(mX$ip89&Zge0<8uWmLyNNNFT7ZF#+c5WcjtW8V^!oSfV?_VSe;E1!h*Y|I04 zQOGp>xRNFTzE?OOLXoEe;MP~8lf&z!M)mzdxl!s4;mKlgHYyIB>D4GrHSwVz^2Z|q zjjn6$1@TOy0=M_++2e*1+N1&OV$Y3I>?P4%V)vh#k;Jo8M$UZgD+E1Z!-y4Zk^KonBBi^*D4Yb76jd zlZrLu(F?>-*BxnZ_qN2=0h{%NkPxNGMm&kXxa&P`1F}rNpc*0%;}tBmeSWdX#dKCU z9L<1TYAJC4lo#qr@Aav!z5Vg}i5Ermp~?LlH*WN%${Li}QQ5swapgML692U){IjM8 zo^mYs@U~V8t08mF<2;xC=)Ao3hWWic*F>m|sp-eVK=SWX9;0M!J5zZkT3(x+YxcVB zt&y$Mb#ZZVWBMaA`Ob0)Nr^7wvv$vGH;u&7qudYNX-{XLGRSz!XK!>4(3l}=jKqBZ zUR`Hg|C$!}yZC!}SvrNa)raP0=~;RS+92}NKac$t1cn74P=|>V%A}=d#JA$xKR*_- zLF$!kJdoF=Jr~t|zTmla_Uxx+j7p9K81!()AXR-UH+^~&B*^gY%ug-ap}8jVx1K$} zm^}2(Jh8OTMd?F%ilEo$=MVi){2u{PI01h4e)aJv-*?-Kh2FTOTmGm1k3wnPTR_-U5c%gl__C~ zUG-0g>y#cPByq?XTY$QQfhU!OIGCFUJZzhdo|-LEr|^uSUm1%53i4yN9KN*_z`Mee z`Ccq#xdSM-z?1q;>G9o%Y;5tBeSN7u#wN{KO)~ACuK}@PwX?GePZ!cD3bAsjfI4li z%O0(d@bba>%@}08?-mr;uj;K;0#r+6pbHH2J@1`-8Is$de%NszWW9UMf41g^Qb?By zq2K3VGtzwn^&Y>nav6X;fFQuuZs+3s1JrI1Pc_O8%qVkR{ zPvYs+Rqv@jfPeh(x`qTlkhyk+Kx1Bol%Z4iP5gW|_GT zvswT=m!TDXmF=K0QPL*4@w&|4sJ;v}xx<`)c65K`ehNlHT-?Q9-EJ_1pQu>qZy;+G z;!9JjW^R(?4w()R2emF{`_g@u#iR8SMaIH!kON@{wjBr^7yz}4M@(vM8d4cbR| z>SrIXk2y_Pf-t8&{vCWBHpi9m-zWX**LL*Xt?G;njADm^1p#W|SKS6fG?MvjQpQ&k zbr!r9Zmdt$Q&i^mbu2}o!g+2;6UA%^ju?6Y}$JpqBjb-tUI70GYKH*N^cDXFPNjEI@Gi0Hp+sqk=SBTF7ig@YkWFmn6Byq?_I3rsrc z*pUZ?-`u>~5YQ}*O{wUvd>$+_IHykeoR*I=!E~qMa{k*MgSC;K?z!tX!ko@lZ~3;k z+@kI`_%s4b(D;$Gdj?>8U{Lt z+U~8sL{6bH3BOtduw(7*msemz}O{6k7gde2|B>izxT14g6{-tWiq zvgZ`Lj~fOxiOhI$i`Qz)$I_9BX>)m`49!YmIW0XsSPNsWu6|TG4Pe4RKtx2u-XX*# z0;=*@YAhV#1u$ge3ep91jY=I~K*;Aw~grKr&VYnqw%VV%`Rk_vjc zVXw;d>KA*S=~0pIP@NY5+u{Npdh^uC84s9%cJ@aoHhy?55wLzD`i~)B_D(zvlWIF@M4Zzj-Z3tyx5E&8zHuwSKjfgu+oFNbWDB8&i5v zX4`DrCj}_K-R4b|Gzq2ox7@&Ip%qlyVddDOU}g~|d#XSuR2)^-`ZlcE1om;(&xhkw zY#fLL+1ujxr7SX#ui}BE*==80aSrKFb(%m54UD6<(56zv=`QH26{S!WC zjDtD`u%Erx+B4qsHRt*`lwYb`@Il3%;GR##NngF{W6Qf9C&!Es(|$Z3=8VDZW0+Ty zr6a=%HL|Ot$6us)cD>wR03jjgQ2oHlXH@8fNG1lG>;5M-}qs6glWpc z(ktrhe0r}u3fCQEVDT&Y`;VKaPm3Sx4)P~y^D*N|Tdf|8uxeM~&v{(dHrfqyacR@V z3~=)EG_hPnt8 zjAZhar4+UA9#kd~NlQ<(SQ?~#%Tq6pO!!gFtXXBh;>JGAR_^J#y&K;Qyq8>oxA``Z_8X*U>|i!G~E{97P604ln8P4LN(dyB~YbQvwF-F?*93 ze}SM-|J)*j69oJsoq@!A5ea1Ex|MkC<(W5Q9x*fDNbYN2<0LX#%g2Pj{VMY6quOS1qMtr&IwW))YxY*doCx^w$YkVmM(?J4sk~k6Tl+0iHR`sX7 zah9&~b<@yPueV~*KWgojT#?Uesa9{>+9?+{1?MENh$af-iJ4!aUfwx=G3AiAH*&^v z;?(->HOEtwr*l{Cf3qY~MZkF7r3qEyKYb9^?p0ao9Cc1a-09GNd*w#&rQX{jy%2hd zzV+kBw6y9At2;sVbNQ|7V%Kd2^^~iTzXx7`6!8G-!5xU*Zt4DaoSbXA8eb$_4V7sB%6JYikydd*NwhFmH{cpFS`V! z`X8P5#cIdm@uzF{i!iF|&*EHYkilm3#0Iy8Q0T4pxh`ELRk&8@_Wwm)n=Xx*jz#TB zpiOb+lJJ&V814`Qh3V6QmbF!(it(dR2%RA$CtB_6Oh%={MSlYYhZ6LA67bOH|Ni~- z=g(>d4Q1e0s2X_P-T%&*+`d?%F;*Xh*L2Um|8CZ&fPlMb*wmk*^VIdOXT6}Bma@g5 z^a^s7;~pXOyV$LTASQU~h}FhhB>eeU``%r9^94oQycEX?2T#{If$9Chm zQDH}o<8Mz83kFe(DCtz|-)pP7=u;GY6RIi5`HXMUHmM1J@U%4d`M`wU=cZXiH?PZ;;C_a)pdi% z#}UDoKd!fqD2AH{mxFK#2!a$CJ*4dHSW$GA*5(V}>G?KH`G!&Y78>CV8W664p1@=5 z4HEXp;ff#K*MHHlHqxFopPlGzzJ$tSq{HZr-vc%_DwL&OQRe#TH;OWl>`^*}HH%O5 z?9sJ+5*r6&FK zX{86(ZAUbeS|GGy+{v6T>$P>!-pPlF*TJMbm=MAYueZF?D7yXFfA2VQVL_cSy{Y+gYr z^5Sw#EjBLhhX#WEiD_2OP=1a|KHY}B@uQb_q@+rA`jxW~=MnAlct;QJq4ejwYedDc zfGJEAI>5PyA)T3#kf4!bJtTQ=b*H1Rt3AyxY;S*A8s$@QG1u(+_-EJP{bC8lm&`By zMUg&wq+xLnSy(MGBl5mOi?i3h<2m24m^o>ooDPwc)yZExZxM{<+)Az-rA(!WZxISh zhSo}wY;;+xn#y{zO5prm;)J*KY%I3MBgto{{xsZ} zN?$ZNOwHCPJCD6Me=$lUnI-x_4VQ)_tgz6^ZaeiN-UNl;`GSzzTU2lGSqxw(~1L?Xe9@v|l+C zSeFUMxV{Lw9ki0_>v*)Ey0lW)xPql&EynL%d`GgpVNNTWTgO4PR=?VOEJjF;+%bvy7m^4%)Mlz7uc{6t|!;oUpOCxH z|7B^h)<7ki=H_P2sh;pg8_6$4k*fMUU$lxd${RiQ@Pb;$PZk;01*MeFu$X#cWwIHF zgZ7%s#a@jK{C=`@*@$lT!wJjixxQ{AcxKf%Ox0oOw;gt-gCI_QcK=O2S7LN@sI5`& zb9&}y9(8Y)OS?F<>%>7pgLPCfF+ZOAF6s zbaOM&{}8Ha(%*504+`)DMn>7{KfuLd02{Nm%^BX*9rb9*ffl!jKQ5Thzltfd`Q`OXU*elnp zwV_I8)#zAHyqQiCsi=l+yR`c@F6angvhkB4VzZeNsuwn$0a4*E=}#7iwN+0$R&9h< zExS5;8^fEWINdwVK*_izFoDb^kzS!Yp%z!ny}oD=V-Bf2SQptCbRjd??%-}_1Pc>W z!;BEZ>a33|%Axo3V9={4VH_&23ol&1<34{ux90u$!DEsX{Z+?-qJ!#}@_h};%qZ(?M>+}F_wN(;u6Ak1E0(3)_LiCLwq{=} z8-He9UR_@78rj%=qU6X<-SPy4<*An$<&2NjJ+Vnw&|Tn}@m>_Z%^-|oK5-KzX8n!< zb#p^bEVb7*_sYzsI}d|uK*Atqjms>q}{!)FVszqf?p<#;h6#50^D20@^^eLwu zV-NTU$@Xd{IXi>=nW&!0%e_`!_k8nCZ#k^qZJk+Et?XN|yrc`7sOFVgdeXs@^J7I% zZ|9x-OWYX6t2hEMuIWM1i=E4+gXREP6ggcDnmG2(LGR>GD7|zC=+`TqbGkZiskkiF zKH0}VScWutdt(s6Bt9GIPp1Y#vH`yIli&D(ZM8FLfrwZz&f=B@e%vK&z6M&_ z-jT{2EeA*Py6IzB_2C>9l_`07#_@?sn_k(|UQ85zets0DBtiF;Lp3PVDezx4-wE5j ze@MGZ8Xn%KRQ30rs;d8Z?6qjMxOimp3N=2y`ttchK|!=261QOR1$!q01gz?Xm~h8L zE(IVHFC1zc5nA*?X>aeagUd$`!$%yc9`IUD`zq95ekP(R_}1$`xFpL&sGPH@3%pf@ zBcCdp`6JhYIyOcjsWVs6WO*Vk{{c|!Y034VU=*4(*P1=TQfS{U34LJiHpo&UBEA*5 zZ^-49q3Q^czn^O7m+W6$B#3LVwzB$E>m?GQTBX;Q@9wlG9BACFoagm;t@g8wKKbvw z1W&_gmDFxXqEh7Nv}E-E74LhN!>j+~9AdeqwhTMM+KLKLEUDizl|g-=(cRCWZ1uzH zpWKQ3(6wJ5{+I~Es)(Ekj6;#+Co)P)!W?_Takqq<-&Cy zAA3`zrKIYay=Juy)x0jA(l#T0K%wiHXlZHlkLhy(G3`HOS>*+W4j$r%WDpk*+<=y8 zOi&wmElyEEwV?d`tf#ch;%qW%BQeWi5|@IYogO=^ovUKtZ{V9R{HN^NRe`ofR}c#| z4^b7b_HYMIqpf&xOX z5RX8r`CJ<%Z_G|%T(EZJf8t5(U=W$Cr3LU6SSMwnUfAPM6#N-}9Tvl`B{>`vSUhHA z_yLLcksAk9SpeN)wU_M4;uczH|q&m!Cf6gLx!X}>_`vx zKNJs-cdb^ZJt0UGXHh$ccee8NShkcTv)C7EGTNz19IU%}4wMGeX{?|K&j?9#2zJ=& zTlmg>&B~Gg?Cen;P3DrtHA10VgMgaCV>{Yz)>=ZJT;~&{paF``}gpFX;?kJFjYgw&MdvOhUFUsR>8qCaZa?2BRgh(w^Wkuhc0hT3_X5d z@1T%D1t!OOc~B{&?1g6eX092K>59h!lA`S}sdL1|OodNnSGGd)8w`Ny6}8y581YEP zO)dCu*`9E5JrDanQ|LS;AA2%iVKP>bm!F!dmni1=EU*15qlgHVv$L~|9@(VJzrYqw z=2z{j2UrVUTv<5pv4pqF~%g9K@ zICtT$t(%dfeD%zX@(msOnaq?g*dU<&Lc)=q?9KW6OV%E^#+Pz(Z~5ii+-_(o(NT!7 z+&QLRdLR20-m}vK3&4OjKAR534XyH@%0ijf!9wNQ_V8Q8V?IvW0Nc6dAx%SMB?)Oi ztPKqfN%@^nc+E~xw}eWRHi~+aPW_B$KE5dYXLjSMIUSNe5Gt##rs(eJ$(eoYC*pje zXi;XYq^hBz-_edi`#AHPXdqLj%5b@i>`hy>^<262y1aZqtt^7r0@!~La1A!oV)P>^Ae%~ydw2-2J8EJseSmjB`r5;I3T z$0iGD1SazYViq>ZX2zmN+!RO+6Il;mI*! zH_x$6mtvt8K5GWieNU z)cYQXX@pns^QJY<&d&Zlz`Bl4tB_#j`klh+u2rlJyTr2o>ig+j!&k(eH2Z{T*jU-H zN8K(*%K!BA7?3*-ui-)L9treMt1h<$(hM$jwY z!^`ER%*!T7PGhfYJBl60L~oUve9mP(p5t8F%UNu%OpXihc=dX9VL^|ZNF5y&`EF@t zLp^PyPAy12I`4y)D-ZV)ErW^Gy1AJQD?R?mSUFjfy2*>5KYykaev)nb8_#pZ=XG8; zb7%K3z|8MCk!%7_;~jlT&Jg224i5mf^ZQ`-$hk`w~;_s**gVjc9bU0ZNQjHeIbp zKWYXih>S*Df}gMn+V-!LzCQ64o0jnZYy)hck#_Ef@51b~w5X7I z$mlCe(BpT|e|Z~Slq(jN&U0R2eMx+Ea>_+uJvl!e+bek7wo`u@@YN(2m4g5;L1=bfg!@`1$Z0dlqKKfl|_f8KVqUyVPMX?jE z-$8-}H*95P)sJ+;0|T5e2~lXMj|v!H)=MWmfMAeDKeWKoytgtqBp_-c(|XaD$a94y zPAo-mXu7$%DJPhOlJcEFqAOyX%YANrKcsI_$%(pThBvxgGK8W-xW3S68WB`qU(mF} zBaVrRv}v|Td9O|O!*yfU1A#|z#x;R&&=CJ3%G(slcuYr!tHV1Xr*$he6!8|<9T8G# z_I{;50QG9%>Xaa?AI;M&P^8-IM4IZ0uDs_D10U6U@NKG9bR*q?m94FT%e4P4dMiRn z=avZ1L!ws!M18*kgF>E5R+%L^K97n!C2vGjbR2-fy7Ad8Ux6d_~`($_Pg;V9*PeRrgH7JG*b z8XOdlKRR>%Ko8;(EpDv!vFY?rJa(;$mdy$upBMfCp-7sTd4}Tw>$~~B+`rWb&R<_J z3>y*Rv2Mrf1R%PC88xmZGf~J46$2(!0I8WYIVWw5738cN;-%UHL*j zWscVo;XB3HKoA?Yu5fUN{A9iYEZ9 zcF4YqPv+pR$eOujQ(rFZ+?~hU|5J@XmdEcu)K(l*!prw4?xFc3+-$KRSJ-s`I>eTg zM^np%@d>5SUJ@j)>g}HoBFh z6u<**Qxz5euHr>OFWMM$_dDd~mFDX_Tpz=L(v>0k(3_~pNS&FOx%)ya3C7b%M&uFg zi%63G#3>k)%cr{S0mOtJygkfMDubk3AkoTJ=UmR?;cGiu_3fRQc*Vf^!N%s^>cQ;9 z#9ba!=NL~WTC_0m@}%e*8V*POw{M^ps}kvsOaR{K61OWu1}eytijA&QLAza&O1jV4 zzf|hkGi1*F!MT;Wu4=6)1X1uAdqe*=ydRtYhL2Vw?*_Zzv6WN1Y?PS^tpN`irBxFU z5|nfNE$bXn5wHM=mpCC)qvWA<4sYIv==amL&>%e^{P-#Ir8Po^xi_0kCgal6eI}vN9N|{g_{u%A9Hc#RH5EdDR|$U72)~V9gC83 zv&imLFE%z7@C!0R(Ryy2R};>}L9I4YNtc(Gf0dep)=kNkI|L8?O@KkDu5~*NRLG-c zU?5(9&FXjKb%d_VSZ?Ft>0n4to_?m|hglBz-K(2JRpzE>o>bmzH2+j!X zhQv7!a{oD>pZxPMityRoqy$;T5MO$Xt0FVw=K@HG;;e=dxHwE(4Xo)0H z?2jd81}h1LcIg-n-uQ3+@yZ?|J4yGRY&&ibhOb+*L;^HbnH_2bmz)K}q8w$j| ziA1Y6JIku-pGwo?w>&1t8qG9Y%GQayFBijM0wSLN)<1h>%p$1Hr8oQ-Vu&AGnVBTO z?u_PM;h&zK%4mC86SSo~GWejJ09Xcap;6y=Kw1b-U~!!22coA5w;AqRs+H%u5Vn9v|&T7^(E|AZ&Vb!+!K41PEt0-xg|M0D$Fh89r8d`|iHMuj-)$$TBW!+!%`NDvLYbQKs>n3scKy_Dw(+6D|=^ z54Rz}>mWRQgUxt6gh=>`oBW5{u=?1X({9{VMjxLY3KYFBn8IIrLu%c*2_#D zH>T(VB1nD#88rjYs)|_VgPa=&iUTDx^bA^n@VooIvU3|wlwf6um%X$_+2#56POT^y zzooLOszLpxG-;&u)utG~<1tMJC$#SsIZcSi4Uj*WLxvDg*Z`XjpV231m9wBx_Cr*1 zoyX~*Qsw#4`c%*ar;qrL>Ap<=-PNxzBXfpn@dI{2!1tc@Oc}mjuP)!QrdCl@46erH z&?8tLfx6_?)%4~T5&^>Cgly7jb>=wUf}B>cS#b*MzC?t@`|5zTUxU5#5S#4@@84eG zNWAHYvX(kGEhB(VuR&ofO31$M^b%->u0ydtVHk_D`~W)iY}Pzur-;v%8Jt1zQ1k zdq%-CM#aX?E~%%7AEDaz`%2jN?JL2j2+961O3^@}^5qz>cgkCnrAR^<0=9{|+B>n@ ziMa~p*Z`vRax=V@d3s>@>us~Nix^P(<(4zy69vAGSS33R8FZ0gCgRw&uS9kGfZuZ1 zp78A(%WdhcotocRO@oSeC+ugKOZ{!)sy(ZoA5o21L;KtyqtNp}f)RNeK5*{CeRf{0 zA1pOt)S_)o&eDY+uim|{gO*9C6u#!*rEFyEQeNnx;7!XmDDTx2Y?^J<%G;9nmygV6 zQ9R1%n)supr=%AGNVp-}(F)10P`G!PfpdQdQ3%qRsM;xK)au**yaY#NM_z0l+UV%0 zYLN|@d&ej~P!gh-F1A_`VxD4bj&r(nvqt;zL9Kedk;lJ}R_zq#@}$S)2JI)6m6g|K z(-KCf6esdb5$smh%Z7uVr~5<}GgWLecTiloWOQEo*QL^1xBLx|ZsB)I*&ncVrWSMg z0swqN;{d9N>(Nt?Vcz68$nuoDv4&C=kRG{#@@N)>9*TIHg{S zJ^1oTCcorRDWrxvMn+xq(fRs3t(qzssRl6htiaf4e^m3If@#+BcprYyzh%-|1 zl*<2#ka)>LaVe5QpJx8M6rjNGyg-Qj4nUM#aW;n?xIO^o`olIRbnsRxBrj5)0={7? ztWgsPuc9L{{82!(oa$iV2hTyuW?A~m{R zDRYK2oO=T9ml*E%84Jj)KW_TPh2TPuAdFX?vsyT@1a@B{sp{(2TnhESu>wDk#Tt8N zWS4UnV36#~*D`HGjD1L#0?D|<7TF4tC9*#wETvA9v6I1!7<;ZFnDCDQU=Q5nhNZ-j z(ePW=01$sMl3&ND$yRih-<+)^;n0%cGz+oT6FL8s4tZCj*eb{CDW~O5p5SDDY%LyP zfpZ>=kAcA4D|W_Wqv-a%j%bR4`6SD>`sm<83mp+2n=`fAQ?gl+AZ`Iz$5MPb7ZmgL zX!OM-`7BR=l`M-aZwPME3*amI*%RyimwrZOJ1Ty8!xSm!#i4Ivau1Znipt8SnHenX z&``Kv=71k8;Z&eKBu zT=|r)T|aJGZcMtf5WkD*St1Pb0=_e@<$?E_A0)wPP`w;He-Ms-eoP%%y%U*5lYLQt ze^V`1M%GTRMlzI~J)*Mq=g(X9l)_CDyl%sfL)>v_C1@bbC#8qDtoii^3qA$_3WK8A zKRL?wM9t{&)XsqYEj1yN%1}`z;eiVG(BU)j;QkhzcH3?3Dkm~dn`~p?q4Zn+=rU8W zY^w2p7fHhwL=_emS*lC!O%(NODUSvKSs>N(x-Q-fLY}aU3IeY~gtk$5{Moyyo_;mB z9%z}(LOTxqYu5T#+I<>IfQPNiR6e#33Jo-jRFp5zC?6tJ9T^~W+#2$;9S8mx0Me$~ z>PD2;QjZ<4YVMeh9J^Ha7S^DKK1nT^%4RY8Cc z64{^~R{&~ZSy5Zf?P7y6WX=Psdt!YY4x{{6=W9H12?huih*kAJXow6pukG38Av;ONK~e5P~DXzIt!`ahbI`j(b{ z0tX*9(h1(hLGA-EM|t-#bmaeqV^jvuLDDT=?OkH6zVChEw-SZxWdto7kOrsDeX1L; zHl^wPE`noyH^I2Ms&}%DoJKaz8};V7v51!=VcG{HUS3|S2wVGETr#~c6;IBd@TkUQ zxnQsJyh*A{YKCF?^WAf+KOeq?fe=V3y$~MNlcaRHq`4Q+z+ip6V>|hgd4TKq*g>_* zt*HC_B@?0Eki3R~CyVsqbGMggPb0;VkG(q z8w8nNeW>jnbcj$q2C(7dSY2NCF=R;d1!8ixS8_mBVrpn;$nu8a)}~$R@`#tTK-&dS zFl_@7^*S?rrUQ9WDz#Kf1sVnHP`&UW$n2`4BnAqzKhoU2a+y6e91Rb-$MIV zH>PuMlGhq|N%oh@Yxn)|O1o*;m*B%8s=+ejfan#0Vb?z#|dlE_Dmf8 zz=id$8r%G*nCr-{M4o!-E)0%iD|_kO+behC*25ed*P->{1X@47Mn|*PS{fPo!7d~1 z!RHZIgf4gSSv_Op07xd%j0(14=EE~5)mvY7W~6p&alQR~Ozi`c0Sbm9^nIXMOU%b4 zx79f`VQ^)}ds1M3lfyq)?M&uz-O%7x5eNnByI1LPtnktEU`mnHe^js1p*t_qV-qal z z=-51dS6`=Tb+P}m_Se`yhHcS;!ob^UR#&2;z+i}VI}H|nLqlXv@C6!Qx_3N;tOJX^ zZ=kHOC8nv&X`l}<%q|wbxvaU6_V)!(-qPMm#~?_|@m-2mP>{Tc(;DESr%(kcUIg+D z{8XC5miq3|!RLZxj(8r^8}c0ThVA_&YzbvZiI};4Z}+evT>lPPi9fD5)Eluy;~$4a zv~=b8GCFKdqM1^d#$5slufI|v@bZ=1zz43J5`Ba+EIJ7avT*`OGIVHS0t>=@QeHhK zN=hoLe@i?5K_O!f5!oT|o=z}I_vbj`#LfBmz0f%hc1}bMVV@DyA6aGLo&Xy`4pRQx za3}{O$7Xc@c?yL?5J|r#Bw)aZhX-%(-n-`wo!>tSQ&8|Dquse;16!m~P^jZyNjy{J z;ryH)MRejuO-V&HzqE;NWMsrIDA+X9ENeN|r1D|lA{_~jEb~*%8i#SzUwwHNgih;? z(g4)bW5;80xzhna^mMnXMr>FumdYUt>zWET2v!^#x$jKHo_UizMJqWYs{EFmfq^B- z6Pf@#L)1A?tm25$5VFCSWt%T~6YV%+N`M2R>TIGMfh1cP`~bZhuaa!Vvyp%hZfU1W zk`EAa3`G~ezVp#~KjyQzAca8Mn`_7zQ0iY$c}o&>jGU-fd#V6DJwA)rX|URjH%e}m zhE)0QtL_mHh(h9#RXj9xqzQ@$CltIY>(AHyLeT3RlZ(yIa<1O#;ZZ+AaPHJhQL~7hOQe7B$@Q0R zsc<+F1Ue;~fCLls?K$>V;lAx@0Rrf!dEm(Tr>daP0c|3t+0NdigrLZY4>QNVMRSCE zjpwOFMtrzU2JohHjJcyqOG~fwLT%t7hM1(yyWi98FvjCq*iRCo|j@R_ZcnSzIocK<84Lkf7R`XXP<3y;{V^w}?!KBl-%M4h@f7*SXo1hu`%?m* zxM#R5DsG|pZv*T+VW@%I=@Ge?w1c!i10?LYsmcQbW|IAv7a?g^0<_*A6_8I@|CqbC z3{Y`ajS@=nA8)qxs}P&MJlgK;4ePaeeF=@XFUsm;iCI%P% z;j-%e%m2TH2SnB1rP1(K5`GJwxW6IHl*DY7!d`Sk6La1t3|irM@$A`Wcsx#-B6X)% zrmE`dCho&A7TI%XnE%3}l0BOqX{#`R_>8g2(FpS`1}~w9RXOj95XLzuAf_U4y`;dL z`cKk7e5i6_kY5D?yAi%0Sc(ytoe(>@m88KDXh50c{S648)B9_NJ zRAzm+^1vt!A|UdQw6txX|9e2X5YW%ghK`oNX(a%pxUE|5!S+SH?5`OhIkXwFaXuv_hxe$B zLXm-SIt|CS>d?5gQ0S-{FGUz}TTH*)-r1SKYMWL&2#<(pp15ipABct4LWcO4{%?_N zxP*BsX_RUj<~BSZkrm>Vla+J(j}y%P2NRTlo)>5Iy)b!g;uA*oALnsJ4SrIc=3xc} z0u9O6wzc($H9_%Zdjl~>lUby*ttThW55P5y9@7Jq$i%rGPjB3{a{^ z%`R+d@x0Y#8g0s9de*Ur}bTh2@a4q zwbPFt#wpDI)#;-rruD{Mh7wAObWHC{d3h-(CvUszH%u*15N{Y7x@rG!H2ho@LmC5g zPAc|%cJw+|ng`)86?zz!?fy;U&0QX1{ZlM-g9Bz!lHIG|oXKkjD&spS&;{jIqxWc* z;>k+|*@rDm|Gk^UFs_pvppAC|p`{_ni6Ge2VeKhO-nin5(2UtXKXVN9Z(`rcw{Q61 z+p(a98~vUMDz)~Nk%Jf75i(q=ak@$!%-Zu70sZ+uOvO+ZB7UD~cW5PiY_#Gwjf1^x zR$f-t1PREuxM$DMb&(07`0xSbTcCDAM0QW~a+3i4){S)sSfEQ+ z9KG$$+b}FAcXw}gmIt^bG`IcrCoo6KIJHBv0LG8;+ic=OK&vn>3ghb9TC8b0=$-7L zH?53H11VV8^F`p^_=MnRReX130eh#ShR=CzCJh9xAf-^A^|ZUOPqygL@{q=L5}YFp zhP0{ab?cefhR7Y-H7Jo&AkI#p?r(Ns&DHx|pf65NcKp|t0tN<2UqOkjCcs({ODz7G z*EZ1dVvr?Y%sDds`)?(CI|E<*D$F+>owobZ_Uc9i^kYEI82^e=9G!L(RG72+<87|G zuKo9aPYmb-KHv8jCr$nI6h(^2%v4RT;qC2Vb)j4Wsj$`YA0u+6Tk95Ezm+zq{WUh8 znwB!BR#=q~y?KWE?A8|v2h91Jk4FkPECZf@UR-$0oeZpYBn7FQ9XNkK5A7-lb!i;$pT&v)aLW8>fyUM$`G#=5diGh3hm<-WIPp94*kC+I6fM z?-GeM>9UcxXlmr~FrUKl2yM~rcymm@`)+32(O8HEORrR@AorD3$4-lYncnx5o45H^ zycHIGRt${==vyOQc75sG`qbhobcxmLW?{%myR5;$eDK_k#{A(?Q z#rb#fW{W_BVM<8}eedb0T2VVSO;Ga1+G>&8={_P~Ht7jl=w;KM^}iVTfHX13VZpGY zz>~4^tvi@=V#iaSbEINdbrlzbEDJ{yJ_7m0Z(d7F!EVs)aN1M;WQhzSZS23u`!7)w2ixZy@N=T*KSV`SJ=Bn#q?{(eYK{-@4z7oy-N*d$l!^Bs1SW@3*``;$;t){;KAgxm^;-|LwJiX_7Hb zA@+>=C+=wo%X<*n1m46UrzT(&Cg!L;v{48nVACiI4o|}l>GRxMTYEF0>xBRjyA5k> zjxgrEopJ8_N}Ie5Iw>l0ZIOduK<`a+tv|cqu03tMIH2KZyW1Z6=#Qira^UOLmC)8M zMj@Gct&9D8>j@?6({z>mBP^GV0rKJyb}u-x#IPH0_D!*=za9sJ~gdxDfD4 zeo}`00UR^1@GC7WxH*iJD6dn){P2n~*@@ZX^Z;XFgsdRXKF@rL*Sfd7FZA+wE_2uG z1{OpAkGPy{b;2o&sr&&?dE|Uew*}+dr^mt%^k8WCUYGWD?tN3#e(ns}B;r*M#6>Kp zdz<>$q{R@g9J#GH@)H5EGiF*lrj-5$wwm}t7WHd$YZ#@xj_|Q1Sm}lNth^%UMC~X zyc~N})JhzJXq--FuVZDeTpRq7hiIm`zAs71pR2P0A8XcmHL2qGUy=1hx=KrSRL*Es zo%IA|ZURte`Ivnl*E3NF1wQT z9G+vTFM<~Kr3->JEbH8pGPCV|t>Lb^ZRC9$ryj zoohRy_uQdYi_z>?^>z)Tht)O?#_^S}@bKZZhD$wXjd3l<);2jYfw(n9yj$`J6e1eOi0-RT; zVI*_s=b=wd&YY$k%T?{xA*YN5Qo z&Z<@_>u7C2Bvfc#n)9MTw`e(9gZJZ>5{pXfQb%9gA^~ITVwij&EVY_{IE5zE+}su- zT-&s6A_6~q9fRB)h<17L?0%d?UB5dVN2tDq_74DdFgL zA2S$4t|SsYCdoExjyq~a@$}^cXdUMC5jZs-Fr@xs!HA^gq~`0$t-tm%8AyGB+?7c} zj)D0?b|G4|u9AJDLqc)X#7Qxw+b@icif8;mmtHzBy5L_0r!ttPN6{fa?e!{%y8y zu1MfLAxBi79cBgBBB;o3-tlBUJKE6bXBFRV8gA0KX#RY;7VebXpmE(Y@pZ zM_Hs+Rk@^zl@G~@EbP)rwP)f8RlE(Aza1Y6clhC7WY(TfS{U27^HM@5ZL%m+@AZJQ ztOy!PzzCcrokqaWHscr?77!*{HmlinT@Q1&)-)$r;0`H(RS2Ml-HEW6Nv*MWrjx($ zfI~$%_0NK1d5_X#dAHJ?j3>J|ms_)n^jZU5F5S+Lr;vy0>9ss-){oJ2v{*9!objOl z2bsV@j#2wfPxr#C_K#mJV4Iq@X%Q_iYnk6k@j#wK^y3aqs2@!{ZkQPFBjx<}6MuOo z%jei3xhGDlwhIlto*m9}_d6b_yL1?U@ogV#?KhY>IKom>Lo7?mOq665VJ8O7y0Byu zE4HSV&j$Kn5Vvir73=pVR>C$I)1OVSl!S#s>lrW7ZzuhYfJ0gIR1awirD_dPc`d=_ z2CNszg!NHgRrdT_2dkJDdAq#0gf4-7$p~I2&XH0fu)=C!1OxY+m z8TnUhIoYKi4GY7T3KKeEE;}(80c3RaF=J$Zr@9v_8J&8p2 z_E@eqwOMdlXKQcuVGye8aTxM{O~W%RWeCbr$Y>4XkPATm3A5nzM!P49%qD)z@-`D|n8AQ9Wr;DW zDoHpeCRIMU^Vg;V*-X{eTCUAscN+`iyWD@2RNfa)v^cA&sa>pPt_Inn@CGR7sn;UB z&%}C?>+d5!tL;?+f@iyP;3k^c^ea*k0!_dH1!U1KP!4$6g7kf=X z8}@RW84mr8bPI`aaEJL+neo53&?xi}zO8$qb!4v{gCkVKqN;S(sD(F!eabPw(&L=Q}^m3GH&~ZKR1Jl($EHryrP_! z9nenWD!g5F@ZD**z%yuaa#HeKGhHL94H-Ph)3{i{z`&DQTYXfNPay_R@yI458&ibpCX&(&Rtj(?IXuU4yS*KRvwzKYHtyApC>=|9%AZe?RiSC-%P$^S}4yf93*dPXA{u|K}|J=PUmg hD*XRMN}sQ9&I!V=#{zPQep{|74dVSE4p literal 0 HcmV?d00001 diff --git a/scripts/appveyor/after_build.sh b/scripts/appveyor/after_build.sh index 1591f363..cb59f11d 100755 --- a/scripts/appveyor/after_build.sh +++ b/scripts/appveyor/after_build.sh @@ -28,19 +28,33 @@ else codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ "${INSTALL_DIR}"/sfizz.lv2/Contents/Frameworks/*.dylib fi - if ls "${INSTALL_DIR}"/usr/local/bin/* &> /dev/null; then - codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ - "${INSTALL_DIR}"/usr/local/bin/* - fi - if ls "${INSTALL_DIR}"/usr/local/lib/*.dylib &> /dev/null; then - codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose \ - "${INSTALL_DIR}"/usr/local/lib/*.dylib - fi fi -# Need the flag --skip-jenkins to prevent CI hanging -# https://github.com/create-dmg/create-dmg/issues/72 -create-dmg --skip-jenkins "${INSTALL_DIR}.dmg" ${INSTALL_DIR} +# Create the DMG +cat > sfizz-dmg.json << EOF +{ + "title": "sfizz", + "background": "${APPVEYOR_BUILD_FOLDER}/mac/dmg-back.png", + "window": { + "size": { "width": 500, "height": 500 } + }, + "contents": [ + { "x": 100, "y": 50, "type": "file", "path": "${INSTALL_DIR}/sfizz.vst3" }, + { "x": 250, "y": 50, "type": "file", "path": "${INSTALL_DIR}/sfizz.component" }, + { "x": 400, "y": 50, "type": "file", "path": "${INSTALL_DIR}/sfizz.lv2" }, + { "x": 100, "y": 400, "type": "link", "path": "/Library/Audio/Plug-Ins/VST3" }, + { "x": 250, "y": 400, "type": "link", "path": "/Library/Audio/Plug-Ins/Components" }, + { "x": 400, "y": 400, "type": "link", "path": "/Library/Audio/Plug-Ins/LV2" } + ] +} +EOF +~/node_modules/appdmg/bin/appdmg.js sfizz-dmg.json "${INSTALL_DIR}.dmg" + +# Code-sign the DMG +if test ! -z "${CODESIGN_PASSWORD}"; then + security unlock-keychain -p dummypasswd build.keychain + codesign --sign "${CODESIGN_IDENTITY}" --keychain build.keychain --force --verbose "${INSTALL_DIR}.dmg" +fi # Only release a tarball if there is a tag if [[ ${APPVEYOR_REPO_TAG} ]]; then diff --git a/scripts/appveyor/install.sh b/scripts/appveyor/install.sh index c927cc1f..2755a0e3 100644 --- a/scripts/appveyor/install.sh +++ b/scripts/appveyor/install.sh @@ -40,4 +40,7 @@ fi set -x -brew install libsndfile dylibbundler fileicon create-dmg +brew install libsndfile dylibbundler fileicon + +cd ~; npm install appdmg; cd - +~/node_modules/appdmg/bin/appdmg.js --version From 9331ff504fe65778e41a24e9d5eb583f2bf11c68 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 13 Dec 2020 13:11:51 +0100 Subject: [PATCH 137/668] Disable fileicon, rejected by code-signing --- scripts/appveyor/after_build.sh | 11 +++++++---- scripts/appveyor/install.sh | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/appveyor/after_build.sh b/scripts/appveyor/after_build.sh index cb59f11d..fd686383 100755 --- a/scripts/appveyor/after_build.sh +++ b/scripts/appveyor/after_build.sh @@ -4,10 +4,13 @@ set -ex make DESTDIR=${PWD}/${INSTALL_DIR} install # Set bundle icons -bundle_icns=/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/KEXT.icns -for bundle in sfizz.vst3 sfizz.component sfizz.lv2; do - fileicon set "${INSTALL_DIR}"/"$bundle" "$bundle_icns" -done +# Note: disabled, rejected by the code-sign step +if false; then + bundle_icns=/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/KEXT.icns + for bundle in sfizz.vst3 sfizz.component sfizz.lv2; do + fileicon set "${INSTALL_DIR}"/"$bundle" "$bundle_icns" + done +fi # Perform code-signing if test -z "${CODESIGN_PASSWORD}"; then diff --git a/scripts/appveyor/install.sh b/scripts/appveyor/install.sh index 2755a0e3..1372da19 100644 --- a/scripts/appveyor/install.sh +++ b/scripts/appveyor/install.sh @@ -40,7 +40,7 @@ fi set -x -brew install libsndfile dylibbundler fileicon +brew install libsndfile dylibbundler cd ~; npm install appdmg; cd - ~/node_modules/appdmg/bin/appdmg.js --version From 4b0e4383a4fc9f8e234e661fd5ccada80cc6c57e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 13 Dec 2020 14:35:30 +0100 Subject: [PATCH 138/668] Check the existence of flag -faligned-new and add it --- cmake/SfizzConfig.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 95e599cc..52aefdc1 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -1,4 +1,5 @@ include(CMakeDependentOption) +include(CheckCXXCompilerFlag) set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used") set(CMAKE_C_STANDARD 99 CACHE STRING "C standard to be used") @@ -72,6 +73,10 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") add_compile_options(-mfloat-abi=hard) endif() endif() + check_cxx_compiler_flag(-faligned-new SFIZZ_HAVE_FALIGNED_NEW) + if(SFIZZ_HAVE_FALIGNED_NEW) + add_compile_options($<$:-faligned-new>) + endif() elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(CMAKE_CXX_STANDARD 17) add_compile_options(/Zc:__cplusplus) From 88e7dc0526611a982cb36784bd0edce67bc9ff1c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 13 Dec 2020 16:11:53 +0100 Subject: [PATCH 139/668] Add CMake helper for GNU warnings --- cmake/GNUWarnings.cmake | 94 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 cmake/GNUWarnings.cmake diff --git a/cmake/GNUWarnings.cmake b/cmake/GNUWarnings.cmake new file mode 100644 index 00000000..62362ed2 --- /dev/null +++ b/cmake/GNUWarnings.cmake @@ -0,0 +1,94 @@ +# A CMake module to use GNU warning flags with C and C++ +# and detect their availability. +# +# Usage: +# gw_warn(...) +# gw_warn_c(...) +# gw_warn_cxx(...) +# gw_target_warn( ...) +# gw_target_warn_c( ...) +# gw_target_warn_cxx( ...) +# +# Copyright 2020, Jean Pierre Cimalando +# SPDX-License-Identifier: BSD-2-Clause + +function(gw_warn) + gw_warn_c(${ARGN}) + gw_warn_cxx(${ARGN}) +endfunction() + +function(gw_warn_c) + if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + foreach(flag ${ARGN}) + _gw_check_c_flag_is_silent("${flag}") + if("${GNUWARNINGS_C_FLAG_${flag}_SILENT}") + add_compile_options("$<$:${flag}>") + endif() + endforeach() + endif() +endfunction() + +function(gw_warn_cxx) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + foreach(flag ${ARGN}) + _gw_check_cxx_flag_is_silent("${flag}") + if("${GNUWARNINGS_CXX_FLAG_${flag}_SILENT}") + add_compile_options("$<$:${flag}>") + endif() + endforeach() + endif() +endfunction() + +function(gw_target_warn TARGET DOMAIN) + gw_target_warn_c("${TARGET}" "${DOMAIN}" ${ARGN}) + gw_target_warn_cxx("${TARGET}" "${DOMAIN}" ${ARGN}) +endfunction() + +function(gw_target_warn_c TARGET DOMAIN) + if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + foreach(flag ${ARGN}) + _gw_check_c_flag_is_silent("${flag}") + if("${GNUWARNINGS_C_FLAG_${flag}_SILENT}") + target_compile_options("${TARGET}" "${DOMAIN}" "$<$:${flag}>") + endif() + endforeach() + endif() +endfunction() + +function(gw_target_warn_cxx TARGET DOMAIN) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + foreach(flag ${ARGN}) + _gw_check_cxx_flag_is_silent("${flag}") + if("${GNUWARNINGS_CXX_FLAG_${flag}_SILENT}") + target_compile_options("${TARGET}" "${DOMAIN}" "$<$:${flag}>") + endif() + endforeach() + endif() +endfunction() + +function(_gw_check_c_flag_is_silent FLAG) + if(NOT DEFINED "GNUWARNINGS_C_FLAG_${FLAG}_SILENT") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.c" "") + _gw_check_command_succeeds_silently(_result "${CMAKE_C_COMPILER}" "${FLAG}" "-c" "-o" "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.o" "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.c") + message(STATUS "Have C warning ${flag}: ${_result}") + set("GNUWARNINGS_C_FLAG_${FLAG}_SILENT" "${_result}" CACHE BOOL "Have C warning ${flag}") + endif() +endfunction() + +function(_gw_check_cxx_flag_is_silent FLAG) + if(NOT DEFINED "GNUWARNINGS_CXX_FLAG_${FLAG}_SILENT") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.cpp" "") + _gw_check_command_succeeds_silently(_result "${CMAKE_CXX_COMPILER}" "${FLAG}" "-c" "-o" "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.o" "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.cpp") + message(STATUS "Have C++ warning ${flag}: ${_result}") + set("GNUWARNINGS_CXX_FLAG_${FLAG}_SILENT" "${_result}" CACHE BOOL "Have C++ warning ${flag}") + endif() +endfunction() + +function(_gw_check_command_succeeds_silently RESULT_VARIABLE) + execute_process(COMMAND ${ARGN} RESULT_VARIABLE _result OUTPUT_VARIABLE _output ERROR_VARIABLE _error OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE) + if(_result EQUAL 0 AND _output STREQUAL "" AND _error STREQUAL "") + set("${RESULT_VARIABLE}" TRUE PARENT_SCOPE) + else() + set("${RESULT_VARIABLE}" FALSE PARENT_SCOPE) + endif() +endfunction() From b19ab25af38259e5fd0159784c924b91085ec12e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 13 Dec 2020 16:12:15 +0100 Subject: [PATCH 140/668] Use only GNU warnings recognized by compiler --- cmake/SfizzConfig.cmake | 6 ++---- editor/cmake/Vstgui.cmake | 2 +- vst/CMakeLists.txt | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 52aefdc1..cfc910b0 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -1,5 +1,6 @@ include(CMakeDependentOption) include(CheckCXXCompilerFlag) +include(GNUWarnings) set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used") set(CMAKE_C_STANDARD 99 CACHE STRING "C standard to be used") @@ -61,10 +62,7 @@ endif() # Add required flags for the builds if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - add_compile_options(-Wall) - add_compile_options(-Wextra) - add_compile_options(-Wno-multichar) - add_compile_options(-Werror=return-type) + gw_warn(-Wall -Wextra -Wno-multichar -Werror=return-type) if (SFIZZ_SYSTEM_PROCESSOR MATCHES "^(i.86|x86_64)$") add_compile_options(-msse2) elseif(SFIZZ_SYSTEM_PROCESSOR MATCHES "^(arm.*)$") diff --git a/editor/cmake/Vstgui.cmake b/editor/cmake/Vstgui.cmake index 56e32ffb..a3cf5dc0 100644 --- a/editor/cmake/Vstgui.cmake +++ b/editor/cmake/Vstgui.cmake @@ -213,7 +213,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - target_compile_options(sfizz-vstgui PRIVATE + gw_target_warn(sfizz-vstgui PRIVATE "-Wno-deprecated-copy" "-Wno-deprecated-declarations" "-Wno-extra" diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index cf082daf..02421af5 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -141,7 +141,7 @@ else() endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - target_compile_options(${VSTPLUGIN_PRJ_NAME} PRIVATE + gw_target_warn(${VSTPLUGIN_PRJ_NAME} PRIVATE "-Wno-extra" "-Wno-multichar" "-Wno-reorder" @@ -317,7 +317,7 @@ elseif(SFIZZ_AU) endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - target_compile_options(${AUPLUGIN_PRJ_NAME} PRIVATE + gw_target_warn(${AUPLUGIN_PRJ_NAME} PRIVATE "-Wno-extra" "-Wno-multichar" "-Wno-reorder" From 61c0791d71554e68a5371c5d6b8c1e4a9522851f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 07:40:41 +0100 Subject: [PATCH 141/668] Mark the submodules as shallow --- .gitmodules | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitmodules b/.gitmodules index fcf2c98f..1fa82a18 100644 --- a/.gitmodules +++ b/.gitmodules @@ -30,6 +30,8 @@ [submodule "external/st_audiofile/thirdparty/libaiff"] path = external/st_audiofile/thirdparty/libaiff url = https://github.com/sfztools/libaiff.git + shallow = true [submodule "vst/external/sfzt_auwrapper"] path = vst/external/sfzt_auwrapper url = https://github.com/sfztools/sfzt_auwrapper.git + shallow = true From 8b56f89688ab7f84c7fb92bf4509d8a0f713831d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 07:49:02 +0100 Subject: [PATCH 142/668] Update cmake files formatting --- benchmarks/CMakeLists.txt | 79 ++++++++++++----------- clients/CMakeLists.txt | 22 +++---- cmake/CheckIPO.cmake | 28 ++++---- cmake/LV2Config.cmake | 32 +++++----- cmake/SfizzConfig.cmake | 58 ++++++++--------- cmake/SfizzSIMDSourceFiles.cmake | 6 +- cmake/SfizzUninstall.cmake | 4 +- cmake/VSTConfig.cmake | 22 +++---- lv2/CMakeLists.txt | 74 ++++++++++----------- src/CMakeLists.txt | 106 +++++++++++++++---------------- vst/CMakeLists.txt | 42 ++++++------ 11 files changed, 236 insertions(+), 237 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 2f33e648..ee39bea5 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,7 +1,7 @@ project(sfizz) # Check SIMD -include (SfizzSIMDSourceFiles) +include(SfizzSIMDSourceFiles) set(BENCHMARK_SIMD_SOURCES) sfizz_add_simd_sources(BENCHMARK_SIMD_SOURCES "../src") find_package(benchmark CONFIG REQUIRED) @@ -23,16 +23,16 @@ target_include_directories(bm_simd PRIVATE ../src/external) add_library(bm_ftz STATIC ../src/sfizz/ScopedFTZ.cpp) macro(sfizz_add_benchmark TARGET) - add_executable("${TARGET}" ${ARGN}) - target_link_libraries("${TARGET}" - PRIVATE absl::span absl::algorithm - PRIVATE benchmark::benchmark benchmark::benchmark_main + add_executable("${TARGET}" ${ARGN}) + target_link_libraries("${TARGET}" + PRIVATE absl::span absl::algorithm + PRIVATE benchmark::benchmark benchmark::benchmark_main PRIVATE bm_simd bm_ftz) - if (LIBATOMIC_FOUND) - target_link_libraries ("${TARGET}" PRIVATE atomic) + if(LIBATOMIC_FOUND) + target_link_libraries("${TARGET}" PRIVATE atomic) endif() - target_include_directories("${TARGET}" PRIVATE ../src/sfizz ../src/external) - sfizz_enable_fast_math("${TARGET}") + target_include_directories("${TARGET}" PRIVATE ../src/sfizz ../src/external) + sfizz_enable_fast_math("${TARGET}") endmacro() sfizz_add_benchmark(bm_opf_high_vs_low BM_OPF_high_vs_low.cpp) @@ -72,7 +72,7 @@ target_link_libraries(bm_smoothers PRIVATE sfizz::sfizz) sfizz_add_benchmark(bm_powerFollower BM_powerFollower.cpp) target_link_libraries(bm_powerFollower PRIVATE sfizz::sfizz) -if (TARGET sfizz-samplerate) +if(TARGET sfizz-samplerate) sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES}) target_link_libraries(bm_resample PRIVATE sfizz-samplerate sfizz-sndfile sfizz-cpuid) endif() @@ -115,39 +115,38 @@ target_link_libraries(bm_stringResonator PRIVATE sfizz-sndfile) add_custom_target(sfizz_benchmarks) add_dependencies(sfizz_benchmarks - bm_opf_high_vs_low - bm_write - bm_clock - bm_pointerIterationOrOffsets - bm_read - bm_mean - bm_meanSquared - bm_cumsum - bm_diff - bm_mathfuns - bm_gain - bm_divide - bm_ramp - bm_ADSR - bm_add - bm_logger - bm_subtract - bm_multiplyAdd - bm_readChunk - bm_resampleChunk - bm_envelopes - bm_wavfile - bm_flacfile - bm_filterModulation - bm_filterStereoMono - bm_stringResonator -) + bm_opf_high_vs_low + bm_write + bm_clock + bm_pointerIterationOrOffsets + bm_read + bm_mean + bm_meanSquared + bm_cumsum + bm_diff + bm_mathfuns + bm_gain + bm_divide + bm_ramp + bm_ADSR + bm_add + bm_logger + bm_subtract + bm_multiplyAdd + bm_readChunk + bm_resampleChunk + bm_envelopes + bm_wavfile + bm_flacfile + bm_filterModulation + bm_filterStereoMono + bm_stringResonator) -if (TARGET bm_resample) - add_dependencies(sfizz_benchmarks bm_resample) +if(TARGET bm_resample) + add_dependencies(sfizz_benchmarks bm_resample) endif() -if (SFIZZ_SYSTEM_PROCESSOR MATCHES "armv7l") +if(SFIZZ_SYSTEM_PROCESSOR MATCHES "armv7l") sfizz_add_benchmark(bm_pan_arm BM_pan_arm.cpp ../src/sfizz/Panning.cpp) target_link_libraries(bm_pan_arm PRIVATE sfizz-jsl) add_dependencies(sfizz_benchmarks bm_pan_arm) diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index ae3080a3..d975c257 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -1,19 +1,19 @@ -project (sfizz) +project(sfizz) -if (SFIZZ_JACK) +if(SFIZZ_JACK) find_package(PkgConfig REQUIRED) pkg_check_modules(JACK "jack" REQUIRED) - link_directories (${JACK_LIBRARY_DIRS}) + link_directories(${JACK_LIBRARY_DIRS}) - add_executable (sfizz_jack MidiHelpers.h jack_client.cpp) - target_include_directories (sfizz_jack PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries (sfizz_jack PRIVATE sfizz::sfizz absl::flags_parse ${JACK_LIBRARIES}) - sfizz_enable_lto_if_needed (sfizz_jack) - install (TARGETS sfizz_jack DESTINATION ${CMAKE_INSTALL_BINDIR} + add_executable(sfizz_jack MidiHelpers.h jack_client.cpp) + target_include_directories(sfizz_jack PRIVATE ${JACK_INCLUDE_DIRS}) + target_link_libraries(sfizz_jack PRIVATE sfizz::sfizz absl::flags_parse ${JACK_LIBRARIES}) + sfizz_enable_lto_if_needed(sfizz_jack) + install(TARGETS sfizz_jack DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "jack" OPTIONAL) endif() -if (SFIZZ_RENDER) +if(SFIZZ_RENDER) add_library(sfizz-fmidi STATIC "external/fmidi/sources/fmidi/fmidi.h" "external/fmidi/sources/fmidi/fmidi_mini.cpp") @@ -22,6 +22,6 @@ if (SFIZZ_RENDER) add_executable(sfizz_render MidiHelpers.h sfizz_render.cpp) target_link_libraries(sfizz_render PRIVATE sfizz::sfizz sfizz-fmidi sfizz-sndfile sfizz-cxxopts) - sfizz_enable_lto_if_needed (sfizz_render) - install (TARGETS sfizz_render DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "render" OPTIONAL) + sfizz_enable_lto_if_needed(sfizz_render) + install(TARGETS sfizz_render DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "render" OPTIONAL) endif() diff --git a/cmake/CheckIPO.cmake b/cmake/CheckIPO.cmake index 5b524df7..058a5f8a 100644 --- a/cmake/CheckIPO.cmake +++ b/cmake/CheckIPO.cmake @@ -1,37 +1,37 @@ # Added in CMake 3.9 -if (CMAKE_VERSION VERSION_LESS 3.9) - message (WARNING "\nIPO checks are only available on CMake 3.9 and later.") +if(CMAKE_VERSION VERSION_LESS 3.9) + message(WARNING "\nIPO checks are only available on CMake 3.9 and later.") set(ENABLE_LTO OFF CACHE BOOL "" FORCE) - function (SFIZZ_ENABLE_LTO_IF_NEEDED TARGET) + function(SFIZZ_ENABLE_LTO_IF_NEEDED TARGET) endfunction() return() endif() -include (CheckIPOSupported) -check_ipo_supported (RESULT result OUTPUT output) +include(CheckIPOSupported) +check_ipo_supported(RESULT result OUTPUT output) -if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l) +if(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l) set(ENABLE_LTO OFF CACHE BOOL "" FORCE) endif() -if (result AND ENABLE_LTO AND CMAKE_BUILD_TYPE STREQUAL "Release") - message (STATUS "\nLTO enabled.") +if(result AND ENABLE_LTO AND CMAKE_BUILD_TYPE STREQUAL "Release") + message(STATUS "\nLTO enabled.") else() - if (${output}) - message (WARNING "\nIPO disabled: ${output}") + if(${output}) + message(WARNING "\nIPO disabled: ${output}") else() - message (WARNING "\nIPO was disabled or not in a Release build.") + message(WARNING "\nIPO was disabled or not in a Release build.") endif() set(ENABLE_LTO OFF CACHE BOOL "" FORCE) endif() -function (SFIZZ_ENABLE_LTO_IF_NEEDED TARGET) - if (${ENABLE_LTO}) +function(SFIZZ_ENABLE_LTO_IF_NEEDED TARGET) + if(${ENABLE_LTO}) message(STATUS "Enabling LTO on ${TARGET}") - set_property (TARGET ${TARGET} PROPERTY INTERPROCEDURAL_OPTIMIZATION True) + set_property(TARGET ${TARGET} PROPERTY INTERPROCEDURAL_OPTIMIZATION True) endif() endfunction() diff --git a/cmake/LV2Config.cmake b/cmake/LV2Config.cmake index 0cfc911f..ab7a1652 100644 --- a/cmake/LV2Config.cmake +++ b/cmake/LV2Config.cmake @@ -1,17 +1,17 @@ # Configuration for this plugin # TODO: generate version from git -set (LV2PLUGIN_VERSION_MINOR 6) -set (LV2PLUGIN_VERSION_MICRO 0) -set (LV2PLUGIN_NAME "sfizz") -set (LV2PLUGIN_COMMENT "SFZ sampler") -set (LV2PLUGIN_URI "http://sfztools.github.io/sfizz") -set (LV2PLUGIN_REPOSITORY "https://github.com/sfztools/sfizz") -set (LV2PLUGIN_AUTHOR "SFZTools") -set (LV2PLUGIN_EMAIL "paul@ferrand.cc") -if (SFIZZ_USE_VCPKG) - set (LV2PLUGIN_SPDX_LICENSE_ID "LGPL-3.0-only") +set(LV2PLUGIN_VERSION_MINOR 6) +set(LV2PLUGIN_VERSION_MICRO 0) +set(LV2PLUGIN_NAME "sfizz") +set(LV2PLUGIN_COMMENT "SFZ sampler") +set(LV2PLUGIN_URI "http://sfztools.github.io/sfizz") +set(LV2PLUGIN_REPOSITORY "https://github.com/sfztools/sfizz") +set(LV2PLUGIN_AUTHOR "SFZTools") +set(LV2PLUGIN_EMAIL "paul@ferrand.cc") +if(SFIZZ_USE_VCPKG) + set(LV2PLUGIN_SPDX_LICENSE_ID "LGPL-3.0-only") else() - set (LV2PLUGIN_SPDX_LICENSE_ID "ISC") + set(LV2PLUGIN_SPDX_LICENSE_ID "ISC") endif() if(SFIZZ_LV2_UI) @@ -30,13 +30,13 @@ else() set(LV2_UI_TYPE "X11UI") endif() -if (APPLE) - set (LV2PLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/LV2" CACHE STRING +if(APPLE) + set(LV2PLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/LV2" CACHE STRING "Install destination for LV2 bundle [default: $ENV{HOME}/Library/Audio/Plug-Ins/LV2]") -elseif (MSVC) - set (LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lv2" CACHE STRING +elseif(MSVC) + set(LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lv2" CACHE STRING "Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lv2]") else() - set (LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/lv2" CACHE STRING + set(LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/lv2" CACHE STRING "Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/lv2]") endif() diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index cfc910b0..6935b874 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -6,26 +6,26 @@ set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used") set(CMAKE_C_STANDARD 99 CACHE STRING "C standard to be used") # Export the compile_commands.json file -set (CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Only install what's explicitely said -set (CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true) -set (CMAKE_POSITION_INDEPENDENT_CODE ON) -set (CMAKE_CXX_VISIBILITY_PRESET hidden) -set (CMAKE_VISIBILITY_INLINES_HIDDEN ON) +set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Set Windows compatibility level to 7 -if (WIN32) +if(WIN32) add_compile_definitions(_WIN32_WINNT=0x601) endif() # Set macOS compatibility level -if (APPLE) +if(APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9") endif() # Do not define macros `min` and `max` -if (WIN32) +if(WIN32) add_compile_definitions(NOMINMAX) endif() @@ -46,13 +46,13 @@ if(APPLE) # and https://stackoverflow.com/a/21692023 # Apparently this is not needed in Travis CI using addons # but it is in Appveyor instead - list (APPEND CMAKE_PREFIX_PATH /usr/local) + list(APPEND CMAKE_PREFIX_PATH /usr/local) endif() # The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio... # see https://gitlab.kitware.com/cmake/cmake/issues/15170 -if (NOT SFIZZ_SYSTEM_PROCESSOR) +if(NOT SFIZZ_SYSTEM_PROCESSOR) if(MSVC) set(SFIZZ_SYSTEM_PROCESSOR "${MSVC_CXX_ARCHITECTURE_ID}") else() @@ -61,13 +61,13 @@ if (NOT SFIZZ_SYSTEM_PROCESSOR) endif() # Add required flags for the builds -if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") gw_warn(-Wall -Wextra -Wno-multichar -Werror=return-type) - if (SFIZZ_SYSTEM_PROCESSOR MATCHES "^(i.86|x86_64)$") + if(SFIZZ_SYSTEM_PROCESSOR MATCHES "^(i.86|x86_64)$") add_compile_options(-msse2) elseif(SFIZZ_SYSTEM_PROCESSOR MATCHES "^(arm.*)$") add_compile_options(-mfpu=neon) - if (NOT ANDROID) + if(NOT ANDROID) add_compile_options(-mfloat-abi=hard) endif() endif() @@ -75,14 +75,14 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") if(SFIZZ_HAVE_FALIGNED_NEW) add_compile_options($<$:-faligned-new>) endif() -elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") +elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(CMAKE_CXX_STANDARD 17) add_compile_options(/Zc:__cplusplus) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() function(sfizz_enable_fast_math NAME) - if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_compile_options("${NAME}" PRIVATE "-ffast-math") elseif(MSVC) target_compile_options("${NAME}" PRIVATE "/fp:fast") @@ -98,9 +98,9 @@ add_library(sfizz-cxxopts INTERFACE) target_include_directories(sfizz-cxxopts INTERFACE "external/cxxopts") # The sndfile library -if (SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) +if(SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) add_library(sfizz-sndfile INTERFACE) - if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + if(SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") find_package(SndFile CONFIG REQUIRED) find_path(SNDFILE_INCLUDE_DIR "sndfile.hh") target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}") @@ -109,7 +109,7 @@ if (SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) find_package(PkgConfig REQUIRED) pkg_check_modules(SNDFILE "sndfile" REQUIRED) target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS}) - if (SFIZZ_STATIC_DEPENDENCIES) + if(SFIZZ_STATIC_DEPENDENCIES) target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES}) else() target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES}) @@ -119,7 +119,7 @@ if (SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) endif() # The st_audiofile library -if (SFIZZ_USE_SNDFILE) +if(SFIZZ_USE_SNDFILE) set(ST_AUDIO_FILE_USE_SNDFILE ON CACHE BOOL "" FORCE) set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "sfizz-sndfile" CACHE STRING "" FORCE) else() @@ -131,7 +131,7 @@ add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL) # If we build with Clang, optionally use libc++. Enabled by default on Apple OS. cmake_dependent_option(USE_LIBCPP "Use libc++ with clang" "${APPLE}" "CMAKE_CXX_COMPILER_ID MATCHES Clang" OFF) -if (USE_LIBCPP) +if(USE_LIBCPP) add_compile_options(-stdlib=libc++) # Presumably need the above for linking too, maybe other options missing as well add_link_options(-stdlib=libc++) # New command on CMake master, not in 3.12 release @@ -147,25 +147,25 @@ target_include_directories(sfizz-spline PUBLIC "src/external/spline") add_library(sfizz-tunings STATIC "src/external/tunings/src/Tunings.cpp") target_include_directories(sfizz-tunings PUBLIC "src/external/tunings/include") -include (CheckLibraryExists) -add_library (sfizz-atomic INTERFACE) -if (UNIX AND NOT APPLE) +include(CheckLibraryExists) +add_library(sfizz-atomic INTERFACE) +if(UNIX AND NOT APPLE) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" "int main() { return 0; }") try_compile(SFIZZ_LINK_LIBATOMIC "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic" SOURCES "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" LINK_LIBRARIES "atomic") - if (SFIZZ_LINK_LIBATOMIC) - target_link_libraries (sfizz-atomic INTERFACE "atomic") + if(SFIZZ_LINK_LIBATOMIC) + target_link_libraries(sfizz-atomic INTERFACE "atomic") endif() else() set(SFIZZ_LINK_LIBATOMIC FALSE) endif() # Don't show build information when building a different project -function (show_build_info_if_needed) - if (CMAKE_PROJECT_NAME STREQUAL "sfizz") - message (STATUS " +function(show_build_info_if_needed) + if(CMAKE_PROJECT_NAME STREQUAL "sfizz") + message(STATUS " Project name: ${PROJECT_NAME} Build type: ${CMAKE_BUILD_TYPE} Build processor: ${SFIZZ_SYSTEM_PROCESSOR} @@ -195,4 +195,4 @@ Compiler CXX min size flags: ${CMAKE_CXX_FLAGS_MINSIZEREL} endif() endfunction() -find_package (Threads REQUIRED) +find_package(Threads REQUIRED) diff --git a/cmake/SfizzSIMDSourceFiles.cmake b/cmake/SfizzSIMDSourceFiles.cmake index 83957c5d..9e588e93 100644 --- a/cmake/SfizzSIMDSourceFiles.cmake +++ b/cmake/SfizzSIMDSourceFiles.cmake @@ -1,7 +1,7 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX) # It needs a macro, otherwise the source properties cannot take effect. - list (APPEND ${SOURCES_VAR} + list(APPEND ${SOURCES_VAR} ${PREFIX}/sfizz/SIMDHelpers.cpp ${PREFIX}/sfizz/simd/HelpersNEON.cpp ${PREFIX}/sfizz/simd/HelpersSSE.cpp @@ -9,10 +9,10 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX) # For CPU-dispatched X86 sources # Always build them for all X86 targets. - if (SFIZZ_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64|x64|X64|i.86|x86|X86)$") + if(SFIZZ_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64|x64|X64|i.86|x86|X86)$") # on GCC, it requires to set ISA support flags on individual files # to be able to use the intrinsics - if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") set_source_files_properties( ${PREFIX}/sfizz/effects/impl/ResonantStringAVX.cpp ${PREFIX}/sfizz/effects/impl/ResonantArrayAVX.cpp diff --git a/cmake/SfizzUninstall.cmake b/cmake/SfizzUninstall.cmake index 6c1d7f12..6286832c 100644 --- a/cmake/SfizzUninstall.cmake +++ b/cmake/SfizzUninstall.cmake @@ -7,12 +7,12 @@ if(NOT TARGET uninstall) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/MakeUninstall.cmake) - if (SFIZZ_LV2 AND LV2PLUGIN_INSTALL_DIR) + if(SFIZZ_LV2 AND LV2PLUGIN_INSTALL_DIR) add_custom_command(TARGET uninstall COMMAND rm -rv "${LV2PLUGIN_INSTALL_DIR}/${PROJECT_NAME}.lv2") endif() - if (SFIZZ_VST AND VSTPLUGIN_INSTALL_DIR) + if(SFIZZ_VST AND VSTPLUGIN_INSTALL_DIR) add_custom_command(TARGET uninstall COMMAND rm -rv "${VSTPLUGIN_INSTALL_DIR}/${PROJECT_NAME}.vst3") endif() diff --git a/cmake/VSTConfig.cmake b/cmake/VSTConfig.cmake index c4c8f44a..8d23c1df 100644 --- a/cmake/VSTConfig.cmake +++ b/cmake/VSTConfig.cmake @@ -1,22 +1,22 @@ -set (VSTPLUGIN_NAME "sfizz") -set (VSTPLUGIN_VENDOR "Paul Ferrand") -set (VSTPLUGIN_URL "http://sfztools.github.io/sfizz") -set (VSTPLUGIN_EMAIL "paul@ferrand.cc") +set(VSTPLUGIN_NAME "sfizz") +set(VSTPLUGIN_VENDOR "Paul Ferrand") +set(VSTPLUGIN_URL "http://sfztools.github.io/sfizz") +set(VSTPLUGIN_EMAIL "paul@ferrand.cc") -if (APPLE) - set (VSTPLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/VST3" CACHE STRING +if(APPLE) + set(VSTPLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/VST3" CACHE STRING "Install destination for VST bundle [default: $ENV{HOME}/Library/Audio/Plug-Ins/VST3]") - set (AUPLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/Components" CACHE STRING + set(AUPLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/Components" CACHE STRING "Install destination for AudioUnit bundle [default: $ENV{HOME}/Library/Audio/Plug-Ins/Components]") -elseif (MSVC) - set (VSTPLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/vst3" CACHE STRING +elseif(MSVC) + set(VSTPLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/vst3" CACHE STRING "Install destination for VST bundle [default: ${CMAKE_INSTALL_PREFIX}/vst3]") else() - set (VSTPLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/vst3" CACHE STRING + set(VSTPLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/vst3" CACHE STRING "Install destination for VST bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/vst3]") endif() -if (NOT VST3_SYSTEM_PROCESSOR) +if(NOT VST3_SYSTEM_PROCESSOR) set(VST3_SYSTEM_PROCESSOR "${SFIZZ_SYSTEM_PROCESSOR}") endif() diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index 743b26d2..a5b8b61a 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -1,85 +1,85 @@ -set (LV2PLUGIN_PRJ_NAME "${PROJECT_NAME}_lv2") +set(LV2PLUGIN_PRJ_NAME "${PROJECT_NAME}_lv2") # Set the build directory as /lv2/.lv2/ -set (PROJECT_BINARY_DIR "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.lv2") +set(PROJECT_BINARY_DIR "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.lv2") # LV2 plugin specific settings -include (LV2Config) +include(LV2Config) # Keep non build turtle files in IDE -set (LV2PLUGIN_TTL_SRC_FILES +set(LV2PLUGIN_TTL_SRC_FILES manifest.ttl.in ${PROJECT_NAME}.ttl.in ) -if (SFIZZ_LV2_UI) +if(SFIZZ_LV2_UI) list(APPEND LV2PLUGIN_TTL_SRC_FILES ${PROJECT_NAME}_ui.ttl.in) endif() source_group("Turtle Files" FILES ${LV2PLUGIN_TTL_SRC_FILES} ) -add_library (${LV2PLUGIN_PRJ_NAME} MODULE +add_library(${LV2PLUGIN_PRJ_NAME} MODULE ${PROJECT_NAME}.c atomic_compat.h ${LV2PLUGIN_TTL_SRC_FILES}) -target_link_libraries (${LV2PLUGIN_PRJ_NAME} ${PROJECT_NAME}::${PROJECT_NAME}) +target_link_libraries(${LV2PLUGIN_PRJ_NAME} ${PROJECT_NAME}::${PROJECT_NAME}) -if (SFIZZ_LV2_UI) - add_library (${LV2PLUGIN_PRJ_NAME}_ui MODULE +if(SFIZZ_LV2_UI) + add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE ${PROJECT_NAME}_ui.cpp vstgui_helpers.h vstgui_helpers.cpp) - target_link_libraries (${LV2PLUGIN_PRJ_NAME}_ui sfizz_editor sfizz-vstgui) + target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui sfizz_editor sfizz-vstgui) endif() # Explicitely strip all symbols on Linux but lv2_descriptor() # MacOS linker does not support this apparently https://bugs.webkit.org/show_bug.cgi?id=144555 -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") file(COPY lv2.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,--version-script=lv2.version") # target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,-u,lv2_descriptor") - if (SFIZZ_LV2_UI) + if(SFIZZ_LV2_UI) file(COPY lv2ui.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,--version-script=lv2ui.version") # target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,-u,lv2ui_descriptor") endif() endif() target_include_directories(${LV2PLUGIN_PRJ_NAME} PRIVATE . external/ardour) -sfizz_enable_lto_if_needed (${LV2PLUGIN_PRJ_NAME}) -if (MINGW) - set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static") +sfizz_enable_lto_if_needed(${LV2PLUGIN_PRJ_NAME}) +if(MINGW) + set_target_properties(${LV2PLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static") endif() -if (SFIZZ_LV2_UI) +if(SFIZZ_LV2_UI) target_include_directories(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE . external/ardour) - sfizz_enable_lto_if_needed (${LV2PLUGIN_PRJ_NAME}_ui) - if (MINGW) - set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES LINK_FLAGS "-static") + sfizz_enable_lto_if_needed(${LV2PLUGIN_PRJ_NAME}_ui) + if(MINGW) + set_target_properties(${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES LINK_FLAGS "-static") endif() endif() # Remove the "lib" prefix, rename the target name and build it in the .lv build dir # /lv2/_lv2. to # /lv2/.lv2/. -set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES PREFIX "") -set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") -set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary/$<0:>") +set_target_properties(${LV2PLUGIN_PRJ_NAME} PROPERTIES PREFIX "") +set_target_properties(${LV2PLUGIN_PRJ_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") +set_target_properties(${LV2PLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary/$<0:>") -if (SFIZZ_LV2_UI) - set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES PREFIX "") - set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES OUTPUT_NAME "${PROJECT_NAME}_ui") - set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary/$<0:>") +if(SFIZZ_LV2_UI) + set_target_properties(${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES PREFIX "") + set_target_properties(${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES OUTPUT_NAME "${PROJECT_NAME}_ui") + set_target_properties(${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary/$<0:>") endif() # Generate *.ttl files from *.in sources, # create the destination directory if it doesn't exists and copy needed files -file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}) -configure_file (manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl) -configure_file (${PROJECT_NAME}.ttl.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.ttl) -if (SFIZZ_LV2_UI) - configure_file (${PROJECT_NAME}_ui.ttl.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}_ui.ttl) +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}) +configure_file(manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl) +configure_file(${PROJECT_NAME}.ttl.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.ttl) +if(SFIZZ_LV2_UI) + configure_file(${PROJECT_NAME}_ui.ttl.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}_ui.ttl) endif() -configure_file (LICENSE.md.in ${PROJECT_BINARY_DIR}/LICENSE.md) -if (SFIZZ_USE_VCPKG OR SFIZZ_STATIC_DEPENDENCIES OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") +configure_file(LICENSE.md.in ${PROJECT_BINARY_DIR}/LICENSE.md) +if(SFIZZ_USE_VCPKG OR SFIZZ_STATIC_DEPENDENCIES OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") file(COPY "lgpl-3.0.txt" DESTINATION ${PROJECT_BINARY_DIR}) endif() @@ -90,13 +90,13 @@ set(LV2_RESOURCES execute_process( COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/Contents/Resources") foreach(res ${LV2_RESOURCES}) - file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/${res}" + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/${res}" DESTINATION "${PROJECT_BINARY_DIR}/Contents/Resources") endforeach() # Copy editor resources -if (SFIZZ_LV2_UI) - execute_process ( +if(SFIZZ_LV2_UI) + execute_process( COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/Contents/Resources") copy_editor_resources( "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources" @@ -104,7 +104,7 @@ if (SFIZZ_LV2_UI) endif() # Installation -if (NOT MSVC) +if(NOT MSVC) install(DIRECTORY ${PROJECT_BINARY_DIR} DESTINATION ${LV2PLUGIN_INSTALL_DIR} COMPONENT "lv2") bundle_dylibs(lv2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca0ebed0..caf58f07 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,9 @@ -include (GNUInstallDirs) +include(GNUInstallDirs) add_subdirectory(external/kiss_fft) add_subdirectory(external/cpuid) -set (FAUST_FILES +set(FAUST_FILES sfizz/dsp/filters/filters_modulable.dsp sfizz/dsp/filters/rbj_filters.dsp sfizz/dsp/filters/sallenkey_modulable.dsp @@ -14,9 +14,9 @@ set (FAUST_FILES sfizz/effects/dsp/gate.dsp sfizz/effects/dsp/disto_stage.dsp sfizz/effects/dsp/fverb.dsp) -source_group ("Faust Files" FILES ${FAUST_FILES}) +source_group("Faust Files" FILES ${FAUST_FILES}) -set (SFIZZ_HEADERS +set(SFIZZ_HEADERS sfizz/ADSREnvelope.h sfizz/AudioBuffer.h sfizz/AudioReader.h @@ -118,7 +118,7 @@ set (SFIZZ_HEADERS sfizz.h sfizz.hpp) -set (SFIZZ_SOURCES +set(SFIZZ_SOURCES sfizz/Synth.cpp sfizz/FileId.cpp sfizz/FilePool.cpp @@ -184,11 +184,11 @@ set (SFIZZ_SOURCES sfizz/effects/impl/ResonantArraySSE.cpp sfizz/effects/impl/ResonantArrayAVX.cpp) -include (SfizzSIMDSourceFiles) -sfizz_add_simd_sources (SFIZZ_SOURCES ".") +include(SfizzSIMDSourceFiles) +sfizz_add_simd_sources(SFIZZ_SOURCES ".") # Parser core library -set (SFIZZ_PARSER_HEADERS +set(SFIZZ_PARSER_HEADERS sfizz/Defaults.h sfizz/LeakDetector.h sfizz/Range.h @@ -201,7 +201,7 @@ set (SFIZZ_PARSER_HEADERS sfizz/SfzHelpers.h sfizz/StringViewHelpers.h) -set (SFIZZ_PARSER_SOURCES +set(SFIZZ_PARSER_SOURCES sfizz/Parser.cpp sfizz/Opcode.cpp sfizz/OpcodeCleanup.cpp @@ -209,94 +209,94 @@ set (SFIZZ_PARSER_SOURCES sfizz/parser/Parser.cpp sfizz/parser/ParserPrivate.cpp) -set (SFIZZ_PARSER_OTHER sfizz/OpcodeCleanup.re) -source_group ("Other Files" FILES ${SFIZZ_PARSER_OTHER}) +set(SFIZZ_PARSER_OTHER sfizz/OpcodeCleanup.re) +source_group("Other Files" FILES ${SFIZZ_PARSER_OTHER}) # Sfizz parser library -add_library (sfizz_parser STATIC) -target_sources (sfizz_parser PRIVATE +add_library(sfizz_parser STATIC) +target_sources(sfizz_parser PRIVATE ${SFIZZ_PARSER_HEADERS} ${SFIZZ_PARSER_SOURCES} ${SFIZZ_PARSER_OTHER}) -target_include_directories (sfizz_parser PUBLIC sfizz) -target_include_directories (sfizz_parser PUBLIC external) -target_link_libraries (sfizz_parser PUBLIC absl::strings PRIVATE absl::flat_hash_map) +target_include_directories(sfizz_parser PUBLIC sfizz) +target_include_directories(sfizz_parser PUBLIC external) +target_link_libraries(sfizz_parser PUBLIC absl::strings PRIVATE absl::flat_hash_map) # OSC messaging library -set (SFIZZ_MESSAGING_HEADERS +set(SFIZZ_MESSAGING_HEADERS sfizz/Messaging.h sfizz/Messaging.hpp sfizz_message.h) -set (SFIZZ_MESSAGING_SOURCES +set(SFIZZ_MESSAGING_SOURCES sfizz/Messaging.cpp) -add_library (sfizz_messaging STATIC) -target_sources (sfizz_messaging PRIVATE +add_library(sfizz_messaging STATIC) +target_sources(sfizz_messaging PRIVATE ${SFIZZ_MESSAGING_HEADERS} ${SFIZZ_MESSAGING_SOURCES}) -target_include_directories (sfizz_messaging PUBLIC ".") -target_link_libraries (sfizz_messaging PUBLIC absl::strings) +target_include_directories(sfizz_messaging PUBLIC ".") +target_link_libraries(sfizz_messaging PUBLIC absl::strings) # Sfizz static library add_library(sfizz_static STATIC) target_sources(sfizz_static PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) -target_include_directories (sfizz_static PUBLIC .) -target_include_directories (sfizz_static PUBLIC external) -target_link_libraries (sfizz_static PUBLIC absl::strings absl::span) -target_link_libraries (sfizz_static PRIVATE sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) -set_target_properties (sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") +target_include_directories(sfizz_static PUBLIC .) +target_include_directories(sfizz_static PUBLIC external) +target_link_libraries(sfizz_static PUBLIC absl::strings absl::span) +target_link_libraries(sfizz_static PRIVATE sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) +set_target_properties(sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") if(SFIZZ_USE_SNDFILE) - target_compile_definitions (sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) - target_link_libraries (sfizz_static PUBLIC st_audiofile) + target_compile_definitions(sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) + target_link_libraries(sfizz_static PUBLIC st_audiofile) endif() -if (WIN32) - target_compile_definitions (sfizz_static PRIVATE _USE_MATH_DEFINES) +if(WIN32) + target_compile_definitions(sfizz_static PRIVATE _USE_MATH_DEFINES) endif() -if (SFIZZ_RELEASE_ASSERTS) - target_compile_definitions (sfizz_static PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") +if(SFIZZ_RELEASE_ASSERTS) + target_compile_definitions(sfizz_static PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") endif() sfizz_enable_fast_math(sfizz_static) if(WIN32) include(VSTConfig) - configure_file (${PROJECT_SOURCE_DIR}/scripts/innosetup.iss.in ${PROJECT_BINARY_DIR}/innosetup.iss @ONLY) + configure_file(${PROJECT_SOURCE_DIR}/scripts/innosetup.iss.in ${PROJECT_BINARY_DIR}/innosetup.iss @ONLY) endif() -configure_file (${PROJECT_SOURCE_DIR}/scripts/doxygen/Doxyfile.in ${PROJECT_SOURCE_DIR}/Doxyfile @ONLY) +configure_file(${PROJECT_SOURCE_DIR}/scripts/doxygen/Doxyfile.in ${PROJECT_SOURCE_DIR}/Doxyfile @ONLY) -add_library (sfizz::parser ALIAS sfizz_parser) -add_library (sfizz::sfizz ALIAS sfizz_static) +add_library(sfizz::parser ALIAS sfizz_parser) +add_library(sfizz::sfizz ALIAS sfizz_static) # Shared library and installation target -if (SFIZZ_SHARED) - add_library (sfizz_shared SHARED) +if(SFIZZ_SHARED) + add_library(sfizz_shared SHARED) target_sources(sfizz_shared PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) - target_include_directories (sfizz_shared PRIVATE .) - target_include_directories (sfizz_shared PRIVATE external) - target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) + target_include_directories(sfizz_shared PRIVATE .) + target_include_directories(sfizz_shared PRIVATE external) + target_link_libraries(sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) if(SFIZZ_USE_SNDFILE) - target_compile_definitions (sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) - target_link_libraries (sfizz_shared PUBLIC st_audiofile) + target_compile_definitions(sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) + target_link_libraries(sfizz_shared PUBLIC st_audiofile) endif() - if (WIN32) - target_compile_definitions (sfizz_shared PRIVATE _USE_MATH_DEFINES) + if(WIN32) + target_compile_definitions(sfizz_shared PRIVATE _USE_MATH_DEFINES) endif() - if (SFIZZ_RELEASE_ASSERTS) - target_compile_definitions (sfizz_shared PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") + if(SFIZZ_RELEASE_ASSERTS) + target_compile_definitions(sfizz_shared PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") endif() target_compile_definitions(sfizz_shared PRIVATE SFIZZ_EXPORT_SYMBOLS) - set_target_properties (sfizz_shared PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") + set_target_properties(sfizz_shared PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") sfizz_enable_lto_if_needed(sfizz_shared) sfizz_enable_fast_math(sfizz_shared) - if (NOT MSVC) - install (TARGETS sfizz_shared + if(NOT MSVC) + install(TARGETS sfizz_shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "runtime" LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT "runtime" ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT "development" PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT "development") - configure_file (${PROJECT_SOURCE_DIR}/scripts/sfizz.pc.in sfizz.pc @ONLY) - install (FILES ${CMAKE_BINARY_DIR}/src/sfizz.pc + configure_file(${PROJECT_SOURCE_DIR}/scripts/sfizz.pc.in sfizz.pc @ONLY) + install(FILES ${CMAKE_BINARY_DIR}/src/sfizz.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT "development") endif() diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 02421af5..6fef1424 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -1,14 +1,14 @@ -set (VSTPLUGIN_PRJ_NAME "${PROJECT_NAME}_vst3") -set (VSTPLUGIN_BUNDLE_NAME "${PROJECT_NAME}.vst3") +set(VSTPLUGIN_PRJ_NAME "${PROJECT_NAME}_vst3") +set(VSTPLUGIN_BUNDLE_NAME "${PROJECT_NAME}.vst3") -set (VST3SDK_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/VST_SDK/VST3_SDK") -#set (AUWRAPPER_BASEDIR "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper") -set (AUWRAPPER_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/sfzt_auwrapper") +set(VST3SDK_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/VST_SDK/VST3_SDK") +#set(AUWRAPPER_BASEDIR "${VST3SDK_BASEDIR}/public.sdk/source/vst/auwrapper") +set(AUWRAPPER_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/sfzt_auwrapper") # VST plugin specific settings -include (VSTConfig) +include(VSTConfig) -configure_file (VstPluginDefs.h.in "${CMAKE_CURRENT_BINARY_DIR}/VstPluginDefs.h") +configure_file(VstPluginDefs.h.in "${CMAKE_CURRENT_BINARY_DIR}/VstPluginDefs.h") # Build VST3 SDK include("cmake/Vst3.cmake") @@ -71,24 +71,24 @@ plugin_add_vst3sdk(${VSTPLUGIN_PRJ_NAME}) plugin_add_vstgui(${VSTPLUGIN_PRJ_NAME}) # Add the ring buffer -set (RINGBUFFER_HEADERS +set(RINGBUFFER_HEADERS "external/ring_buffer/ring_buffer/ring_buffer.h" "external/ring_buffer/ring_buffer/ring_buffer.tcc") add_library(sfizz_ring_buffer STATIC "external/ring_buffer/ring_buffer/ring_buffer.cpp" ${RINGBUFFER_HEADERS}) -source_group ("Header Files" FILES ${RINGBUFFER_HEADERS}) +source_group("Header Files" FILES ${RINGBUFFER_HEADERS}) target_include_directories(sfizz_ring_buffer INTERFACE "external/ring_buffer") target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE sfizz_ring_buffer) -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/vst3.version") endif() -sfizz_enable_lto_if_needed (${VSTPLUGIN_PRJ_NAME}) -if (MINGW) - set_target_properties (${VSTPLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static") +sfizz_enable_lto_if_needed(${VSTPLUGIN_PRJ_NAME}) +if(MINGW) + set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static") endif() # Link system dependencies @@ -102,8 +102,8 @@ else() target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${GLIB_LIBRARIES}) endif() -# Create the bundle (see "VST 3 Locations / Format") -execute_process ( +# Create the bundle(see "VST 3 Locations / Format") +execute_process( COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") copy_editor_resources( "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources" @@ -140,7 +140,7 @@ else() DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") endif() -if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") gw_target_warn(${VSTPLUGIN_PRJ_NAME} PRIVATE "-Wno-extra" "-Wno-multichar" @@ -154,12 +154,12 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") endif() # To help debugging the link only -if (FALSE) +if(FALSE) target_link_options(${VSTPLUGIN_PRJ_NAME} PRIVATE "-Wl,-no-undefined") endif() # Installation -if (NOT MSVC) +if(NOT MSVC) install(DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}" DESTINATION "${VSTPLUGIN_INSTALL_DIR}" COMPONENT "vst") @@ -261,7 +261,7 @@ elseif(SFIZZ_AU) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/include/aucocoaclassprefix.h" "#define SMTG_AU_NAMESPACE SMTGAUCocoa${SFIZZ_AU_CLASS_PREFIX_NUMBER}_") - sfizz_enable_lto_if_needed (${AUPLUGIN_PRJ_NAME}) + sfizz_enable_lto_if_needed(${AUPLUGIN_PRJ_NAME}) # Create the bundle execute_process( @@ -293,7 +293,7 @@ elseif(SFIZZ_AU) DESTINATION "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/SharedSupport/License") # Add the resource fork - if (FALSE) + if(FALSE) execute_process(COMMAND "xcrun" "--find" "Rez" OUTPUT_VARIABLE OSX_REZ_COMMAND OUTPUT_STRIP_TRAILING_WHITESPACE) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include") @@ -316,7 +316,7 @@ elseif(SFIZZ_AU) "${AUWRAPPER_BASEDIR}/auresource.r") endif() - if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") gw_target_warn(${AUPLUGIN_PRJ_NAME} PRIVATE "-Wno-extra" "-Wno-multichar" From 96dc4791e44bba964d1aaa19de9cc8aac23dd6f7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 07:53:34 +0100 Subject: [PATCH 143/668] Fix the preprocessor, cxxopts missing --- devtools/CMakeLists.txt | 2 +- devtools/Preprocessor.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/devtools/CMakeLists.txt b/devtools/CMakeLists.txt index e5ea35f6..d64f6ba4 100644 --- a/devtools/CMakeLists.txt +++ b/devtools/CMakeLists.txt @@ -15,4 +15,4 @@ if(JACK_FOUND AND TARGET Qt5::Widgets) endif() add_executable(sfizz_preprocessor Preprocessor.cpp) -target_link_libraries(sfizz_preprocessor sfizz_parser) +target_link_libraries(sfizz_preprocessor PRIVATE sfizz_parser sfizz-cxxopts) diff --git a/devtools/Preprocessor.cpp b/devtools/Preprocessor.cpp index f9dbfba6..9476d356 100644 --- a/devtools/Preprocessor.cpp +++ b/devtools/Preprocessor.cpp @@ -13,8 +13,8 @@ */ #include "parser/Parser.h" -#include "../tests/cxxopts.hpp" -#include "absl/strings/string_view.h" +#include +#include #include class MyParserListener : public sfz::Parser::Listener { From 3a9accba4b6bed660d4f5532f066f7bb0b52896d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 08:20:01 +0100 Subject: [PATCH 144/668] Put dependency libraries in namespaces --- benchmarks/CMakeLists.txt | 33 +++++++++---------- clients/CMakeLists.txt | 9 +++--- cmake/SfizzConfig.cmake | 47 ++++++++++++++++------------ demos/CMakeLists.txt | 10 +++--- devtools/CMakeLists.txt | 4 +-- editor/CMakeLists.txt | 2 +- editor/cmake/Vstgui.cmake | 34 ++++++++++---------- lv2/CMakeLists.txt | 2 +- src/CMakeLists.txt | 4 +-- src/external/cpuid/CMakeLists.txt | 9 +++--- src/external/kiss_fft/CMakeLists.txt | 7 +++-- tests/CMakeLists.txt | 2 +- vst/CMakeLists.txt | 4 +-- vst/cmake/Vst3.cmake | 2 +- 14 files changed, 91 insertions(+), 78 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index ee39bea5..a72c9f6c 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -12,13 +12,14 @@ find_path(SAMPLERATE_INCLUDE_DIR "samplerate.h") message(STATUS "Checking samplerate library: ${SAMPLERATE_LIBRARY}") message(STATUS "Checking samplerate includes: ${SAMPLERATE_INCLUDE_DIR}") if(SAMPLERATE_LIBRARY AND SAMPLERATE_INCLUDE_DIR) - add_library(sfizz-samplerate INTERFACE) - target_include_directories(sfizz-samplerate INTERFACE "${SAMPLERATE_INCLUDE_DIR}") - target_link_libraries(sfizz-samplerate INTERFACE "${SAMPLERATE_LIBRARY}") + add_library(sfizz_samplerate INTERFACE) + add_library(sfizz::samplerate ALIAS sfizz_samplerate) + target_include_directories(sfizz_samplerate INTERFACE "${SAMPLERATE_INCLUDE_DIR}") + target_link_libraries(sfizz_samplerate INTERFACE "${SAMPLERATE_LIBRARY}") endif() add_library(bm_simd STATIC ${BENCHMARK_SIMD_SOURCES}) -target_link_libraries(bm_simd PRIVATE absl::span sfizz-cpuid) +target_link_libraries(bm_simd PRIVATE absl::span sfizz::cpuid) target_include_directories(bm_simd PRIVATE ../src/external) add_library(bm_ftz STATIC ../src/sfizz/ScopedFTZ.cpp) @@ -72,37 +73,37 @@ target_link_libraries(bm_smoothers PRIVATE sfizz::sfizz) sfizz_add_benchmark(bm_powerFollower BM_powerFollower.cpp) target_link_libraries(bm_powerFollower PRIVATE sfizz::sfizz) -if(TARGET sfizz-samplerate) +if(TARGET sfizz::samplerate) sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES}) -target_link_libraries(bm_resample PRIVATE sfizz-samplerate sfizz-sndfile sfizz-cpuid) +target_link_libraries(bm_resample PRIVATE sfizz::samplerate sfizz::sndfile sfizz::cpuid) endif() sfizz_add_benchmark(bm_envelopes BM_envelopes.cpp) sfizz_add_benchmark(bm_wavfile BM_wavfile.cpp) -target_link_libraries(bm_wavfile PRIVATE sfizz-sndfile) +target_link_libraries(bm_wavfile PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_flacfile BM_flacfile.cpp) -target_link_libraries(bm_flacfile PRIVATE sfizz-sndfile) +target_link_libraries(bm_flacfile PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_audioReaders BM_audioReaders.cpp ../src/sfizz/AudioReader.cpp) -target_link_libraries(bm_audioReaders PRIVATE st_audiofile sfizz-sndfile) +target_link_libraries(bm_audioReaders PRIVATE st_audiofile sfizz::sndfile) sfizz_add_benchmark(bm_readChunk BM_readChunk.cpp) -target_link_libraries(bm_readChunk PRIVATE sfizz-sndfile) +target_link_libraries(bm_readChunk PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_readChunkFlac BM_readChunkFlac.cpp) -target_link_libraries(bm_readChunkFlac PRIVATE sfizz-sndfile) +target_link_libraries(bm_readChunkFlac PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_resampleChunk BM_resampleChunk.cpp) -target_link_libraries(bm_resampleChunk PRIVATE sfizz-sndfile) +target_link_libraries(bm_resampleChunk PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_interpolators BM_interpolators.cpp) sfizz_add_benchmark(bm_filterModulation BM_filterModulation.cpp ../src/sfizz/SfzFilter.cpp) -target_link_libraries(bm_filterModulation PRIVATE sfizz-sndfile) +target_link_libraries(bm_filterModulation PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_filterStereoMono BM_filterStereoMono.cpp ../src/sfizz/SfzFilter.cpp) -target_link_libraries(bm_filterStereoMono PRIVATE sfizz-sndfile) +target_link_libraries(bm_filterStereoMono PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_stringResonator BM_stringResonator.cpp ../src/sfizz/effects/impl/ResonantArray.cpp @@ -111,7 +112,7 @@ sfizz_add_benchmark(bm_stringResonator BM_stringResonator.cpp ../src/sfizz/effects/impl/ResonantString.cpp ../src/sfizz/effects/impl/ResonantStringSSE.cpp ../src/sfizz/effects/impl/ResonantStringAVX.cpp) -target_link_libraries(bm_stringResonator PRIVATE sfizz-sndfile) +target_link_libraries(bm_stringResonator PRIVATE sfizz::sndfile) add_custom_target(sfizz_benchmarks) add_dependencies(sfizz_benchmarks @@ -148,7 +149,7 @@ endif() if(SFIZZ_SYSTEM_PROCESSOR MATCHES "armv7l") sfizz_add_benchmark(bm_pan_arm BM_pan_arm.cpp ../src/sfizz/Panning.cpp) - target_link_libraries(bm_pan_arm PRIVATE sfizz-jsl) + target_link_libraries(bm_pan_arm PRIVATE sfizz::jsl) add_dependencies(sfizz_benchmarks bm_pan_arm) endif() diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index d975c257..7b9e3453 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -14,14 +14,15 @@ if(SFIZZ_JACK) endif() if(SFIZZ_RENDER) - add_library(sfizz-fmidi STATIC + add_library(sfizz_fmidi STATIC "external/fmidi/sources/fmidi/fmidi.h" "external/fmidi/sources/fmidi/fmidi_mini.cpp") - target_include_directories(sfizz-fmidi PUBLIC "external/fmidi/sources") - target_compile_definitions(sfizz-fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1") + add_library(sfizz::fmidi ALIAS sfizz_fmidi) + target_include_directories(sfizz_fmidi PUBLIC "external/fmidi/sources") + target_compile_definitions(sfizz_fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1") add_executable(sfizz_render MidiHelpers.h sfizz_render.cpp) - target_link_libraries(sfizz_render PRIVATE sfizz::sfizz sfizz-fmidi sfizz-sndfile sfizz-cxxopts) + target_link_libraries(sfizz_render PRIVATE sfizz::sfizz sfizz::fmidi sfizz::sndfile sfizz::cxxopts) sfizz_enable_lto_if_needed(sfizz_render) install(TARGETS sfizz_render DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "render" OPTIONAL) endif() diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 6935b874..cfe1e559 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -1,5 +1,6 @@ include(CMakeDependentOption) include(CheckCXXCompilerFlag) +include(CheckLibraryExists) include(GNUWarnings) set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used") @@ -90,29 +91,32 @@ function(sfizz_enable_fast_math NAME) endfunction() # The jsl utility library for C++ -add_library(sfizz-jsl INTERFACE) -target_include_directories(sfizz-jsl INTERFACE "external/jsl/include") +add_library(sfizz_jsl INTERFACE) +add_library(sfizz::jsl ALIAS sfizz_jsl) +target_include_directories(sfizz_jsl INTERFACE "external/jsl/include") # The cxxopts library -add_library(sfizz-cxxopts INTERFACE) -target_include_directories(sfizz-cxxopts INTERFACE "external/cxxopts") +add_library(sfizz_cxxopts INTERFACE) +add_library(sfizz::cxxopts ALIAS sfizz_cxxopts) +target_include_directories(sfizz_cxxopts INTERFACE "external/cxxopts") # The sndfile library if(SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) - add_library(sfizz-sndfile INTERFACE) + add_library(sfizz_sndfile INTERFACE) + add_library(sfizz::sndfile ALIAS sfizz_sndfile) if(SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") find_package(SndFile CONFIG REQUIRED) find_path(SNDFILE_INCLUDE_DIR "sndfile.hh") - target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}") - target_link_libraries(sfizz-sndfile INTERFACE SndFile::sndfile) + target_include_directories(sfizz_sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}") + target_link_libraries(sfizz_sndfile INTERFACE SndFile::sndfile) else() find_package(PkgConfig REQUIRED) pkg_check_modules(SNDFILE "sndfile" REQUIRED) - target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS}) + target_include_directories(sfizz_sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS}) if(SFIZZ_STATIC_DEPENDENCIES) - target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES}) + target_link_libraries(sfizz_sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES}) else() - target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES}) + target_link_libraries(sfizz_sndfile INTERFACE ${SNDFILE_LIBRARIES}) endif() link_directories(${SNDFILE_LIBRARY_DIRS}) endif() @@ -121,7 +125,7 @@ endif() # The st_audiofile library if(SFIZZ_USE_SNDFILE) set(ST_AUDIO_FILE_USE_SNDFILE ON CACHE BOOL "" FORCE) - set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "sfizz-sndfile" CACHE STRING "" FORCE) + set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "sfizz::sndfile" CACHE STRING "" FORCE) else() set(ST_AUDIO_FILE_USE_SNDFILE OFF CACHE BOOL "" FORCE) set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "" CACHE STRING "" FORCE) @@ -138,17 +142,20 @@ if(USE_LIBCPP) add_link_options(-lc++abi) # New command on CMake master, not in 3.12 release endif() -add_library(sfizz-pugixml STATIC "src/external/pugixml/src/pugixml.cpp") -target_include_directories(sfizz-pugixml PUBLIC "src/external/pugixml/src") +add_library(sfizz_pugixml STATIC "src/external/pugixml/src/pugixml.cpp") +add_library(sfizz::pugixml ALIAS sfizz_pugixml) +target_include_directories(sfizz_pugixml PUBLIC "src/external/pugixml/src") -add_library(sfizz-spline STATIC "src/external/spline/spline/spline.cpp") -target_include_directories(sfizz-spline PUBLIC "src/external/spline") +add_library(sfizz_spline STATIC "src/external/spline/spline/spline.cpp") +add_library(sfizz::spline ALIAS sfizz_spline) +target_include_directories(sfizz_spline PUBLIC "src/external/spline") -add_library(sfizz-tunings STATIC "src/external/tunings/src/Tunings.cpp") -target_include_directories(sfizz-tunings PUBLIC "src/external/tunings/include") +add_library(sfizz_tunings STATIC "src/external/tunings/src/Tunings.cpp") +add_library(sfizz::tunings ALIAS sfizz_tunings) +target_include_directories(sfizz_tunings PUBLIC "src/external/tunings/include") -include(CheckLibraryExists) -add_library(sfizz-atomic INTERFACE) +add_library(sfizz_atomic INTERFACE) +add_library(sfizz::atomic ALIAS sfizz_atomic) if(UNIX AND NOT APPLE) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" "int main() { return 0; }") @@ -156,7 +163,7 @@ if(UNIX AND NOT APPLE) SOURCES "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" LINK_LIBRARIES "atomic") if(SFIZZ_LINK_LIBATOMIC) - target_link_libraries(sfizz-atomic INTERFACE "atomic") + target_link_libraries(sfizz_atomic INTERFACE "atomic") endif() else() set(SFIZZ_LINK_LIBATOMIC FALSE) diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 16ebcce6..ba349140 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -37,10 +37,10 @@ if(TARGET Qt5::Widgets) endif() add_executable(eq_apply EQ.cpp) -target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz-sndfile sfizz-cxxopts) +target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts) add_executable(filter_apply Filter.cpp) -target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz-sndfile sfizz-cxxopts) +target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts) add_executable(sfizz_plot_curve PlotCurve.cpp) target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz) @@ -49,13 +49,13 @@ add_executable(sfizz_plot_wavetables PlotWavetables.cpp) target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::sfizz) add_executable(sfizz_plot_lfo PlotLFO.cpp) -target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz sfizz-sndfile sfizz-cxxopts) +target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts) add_executable(sfizz_file_instrument FileInstrument.cpp) -target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz sfizz-sndfile) +target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz sfizz::sndfile) add_executable(sfizz_file_wavetable FileWavetable.cpp) target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::sfizz) add_executable(sfizz_tuning Tuning.cpp) -target_link_libraries(sfizz_tuning PRIVATE sfizz::sfizz sfizz-cxxopts) +target_link_libraries(sfizz_tuning PRIVATE sfizz::sfizz sfizz::cxxopts) diff --git a/devtools/CMakeLists.txt b/devtools/CMakeLists.txt index d64f6ba4..ac2790e6 100644 --- a/devtools/CMakeLists.txt +++ b/devtools/CMakeLists.txt @@ -10,9 +10,9 @@ find_package(Qt5 COMPONENTS Widgets) if(JACK_FOUND AND TARGET Qt5::Widgets) add_executable(sfizz_capture_eg CaptureEG.h CaptureEG.cpp) target_include_directories(sfizz_capture_eg PRIVATE . ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_capture_eg PRIVATE sfizz-sndfile Qt5::Widgets ${JACK_LIBRARIES}) + target_link_libraries(sfizz_capture_eg PRIVATE sfizz::sndfile Qt5::Widgets ${JACK_LIBRARIES}) set_target_properties(sfizz_capture_eg PROPERTIES AUTOUIC ON) endif() add_executable(sfizz_preprocessor Preprocessor.cpp) -target_link_libraries(sfizz_preprocessor PRIVATE sfizz_parser sfizz-cxxopts) +target_link_libraries(sfizz_preprocessor PRIVATE sfizz_parser sfizz::cxxopts) diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 0244666b..9517c51e 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -43,7 +43,7 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/utility/vstgui_before.h) target_include_directories(sfizz_editor PUBLIC "src") target_link_libraries(sfizz_editor PUBLIC sfizz_messaging) -target_link_libraries(sfizz_editor PRIVATE sfizz-vstgui) +target_link_libraries(sfizz_editor PRIVATE sfizz::vstgui) target_link_libraries(sfizz_editor PUBLIC absl::strings) if(APPLE) find_library(APPLE_APPKIT_LIBRARY "AppKit") diff --git a/editor/cmake/Vstgui.cmake b/editor/cmake/Vstgui.cmake index a3cf5dc0..41cafa99 100644 --- a/editor/cmake/Vstgui.cmake +++ b/editor/cmake/Vstgui.cmake @@ -1,4 +1,4 @@ -add_library(sfizz-vstgui STATIC EXCLUDE_FROM_ALL +add_library(sfizz_vstgui STATIC EXCLUDE_FROM_ALL "${VSTGUI_BASEDIR}/vstgui/lib/animation/animations.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/animation/animator.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/animation/timingfunctions.cpp" @@ -58,8 +58,10 @@ add_library(sfizz-vstgui STATIC EXCLUDE_FROM_ALL "${VSTGUI_BASEDIR}/vstgui/lib/platform/platformfactory.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/vstguidebug.cpp") +add_library(sfizz::vstgui ALIAS sfizz_vstgui) + if(WIN32) - target_sources(sfizz-vstgui PRIVATE + target_sources(sfizz_vstgui PRIVATE "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/fileresourceinputstream.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/direct2d/d2dbitmap.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/direct2d/d2ddrawcontext.cpp" @@ -78,7 +80,7 @@ if(WIN32) "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/winstring.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/wintimer.cpp") elseif(APPLE) - target_sources(sfizz-vstgui PRIVATE + target_sources(sfizz_vstgui PRIVATE "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/fileresourceinputstream.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/genericoptionmenu.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/generictextedit.cpp" @@ -104,7 +106,7 @@ elseif(APPLE) "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/mactimer.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/quartzgraphicspath.cpp") else() - target_sources(sfizz-vstgui PRIVATE + target_sources(sfizz_vstgui PRIVATE "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/fileresourceinputstream.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/generictextedit.cpp" "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/cairobitmap.cpp" @@ -122,12 +124,12 @@ else() "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/x11utils.cpp") endif() -target_include_directories(sfizz-vstgui PUBLIC "${VSTGUI_BASEDIR}") +target_include_directories(sfizz_vstgui PUBLIC "${VSTGUI_BASEDIR}") if(WIN32) if (NOT MSVC) # autolinked on MSVC with pragmas - target_link_libraries(sfizz-vstgui PRIVATE + target_link_libraries(sfizz_vstgui PRIVATE "opengl32" "d2d1" "dwrite" @@ -136,7 +138,7 @@ if(WIN32) "shlwapi") endif() elseif(APPLE) - target_link_libraries(sfizz-vstgui PRIVATE + target_link_libraries(sfizz_vstgui PRIVATE "${APPLE_COREFOUNDATION_LIBRARY}" "${APPLE_FOUNDATION_LIBRARY}" "${APPLE_COCOA_LIBRARY}" @@ -161,7 +163,7 @@ else() pkg_check_modules(CAIRO REQUIRED cairo) pkg_check_modules(FONTCONFIG REQUIRED fontconfig) pkg_check_modules(GLIB REQUIRED glib-2.0) - target_include_directories(sfizz-vstgui PRIVATE + target_include_directories(sfizz_vstgui PRIVATE ${X11_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} ${LIBXCB_INCLUDE_DIRS} @@ -174,7 +176,7 @@ else() ${CAIRO_INCLUDE_DIRS} ${FONTCONFIG_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS}) - target_link_libraries(sfizz-vstgui PRIVATE + target_link_libraries(sfizz_vstgui PRIVATE ${X11_LIBRARIES} ${FREETYPE_LIBRARIES} ${LIBXCB_LIBRARIES} @@ -189,31 +191,31 @@ else() ${GLIB_LIBRARIES}) find_library(DL_LIBRARY "dl") if(DL_LIBRARY) - target_link_libraries(sfizz-vstgui PRIVATE "${DL_LIBRARY}") + target_link_libraries(sfizz_vstgui PRIVATE "${DL_LIBRARY}") endif() endif() if(${CMAKE_BUILD_TYPE} MATCHES "Debug") - target_compile_definitions(sfizz-vstgui PUBLIC "DEVELOPMENT") + target_compile_definitions(sfizz_vstgui PUBLIC "DEVELOPMENT") endif() if(${CMAKE_BUILD_TYPE} MATCHES "Release") - target_compile_definitions(sfizz-vstgui PUBLIC "RELEASE") + target_compile_definitions(sfizz_vstgui PUBLIC "RELEASE") endif() if(CMAKE_SYSTEM_NAME STREQUAL "Windows") # higher C++ requirement on Windows - set_property(TARGET sfizz-vstgui PROPERTY CXX_STANDARD 14) + set_property(TARGET sfizz_vstgui PROPERTY CXX_STANDARD 14) # Windows 10 RS2 DDI for custom fonts - target_compile_definitions(sfizz-vstgui PRIVATE "NTDDI_VERSION=0x0A000003") + target_compile_definitions(sfizz_vstgui PRIVATE "NTDDI_VERSION=0x0A000003") # disable custom fonts while dwrite3 API is unavailable in MinGW if(MINGW) - target_compile_definitions(sfizz-vstgui PRIVATE "VSTGUI_WIN32_CUSTOMFONT_SUPPORT=0") + target_compile_definitions(sfizz_vstgui PRIVATE "VSTGUI_WIN32_CUSTOMFONT_SUPPORT=0") endif() endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - gw_target_warn(sfizz-vstgui PRIVATE + gw_target_warn(sfizz_vstgui PRIVATE "-Wno-deprecated-copy" "-Wno-deprecated-declarations" "-Wno-extra" diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index a5b8b61a..c84a93ab 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -29,7 +29,7 @@ if(SFIZZ_LV2_UI) ${PROJECT_NAME}_ui.cpp vstgui_helpers.h vstgui_helpers.cpp) - target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui sfizz_editor sfizz-vstgui) + target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui sfizz_editor sfizz::vstgui) endif() # Explicitely strip all symbols on Linux but lv2_descriptor() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index caf58f07..ed93df85 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -242,7 +242,7 @@ target_sources(sfizz_static PRIVATE target_include_directories(sfizz_static PUBLIC .) target_include_directories(sfizz_static PUBLIC external) target_link_libraries(sfizz_static PUBLIC absl::strings absl::span) -target_link_libraries(sfizz_static PRIVATE sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) +target_link_libraries(sfizz_static PRIVATE sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::atomic) set_target_properties(sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) @@ -273,7 +273,7 @@ if(SFIZZ_SHARED) ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) target_include_directories(sfizz_shared PRIVATE .) target_include_directories(sfizz_shared PRIVATE external) - target_link_libraries(sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz-pugixml sfizz-spline sfizz-tunings sfizz-kissfft sfizz-cpuid sfizz-jsl sfizz-atomic) + target_link_libraries(sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) target_link_libraries(sfizz_shared PUBLIC st_audiofile) diff --git a/src/external/cpuid/CMakeLists.txt b/src/external/cpuid/CMakeLists.txt index d4e779be..c2a25fe5 100644 --- a/src/external/cpuid/CMakeLists.txt +++ b/src/external/cpuid/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required (VERSION 3.5) -project(sfizz-cpuid) +project(sfizz_cpuid) -add_library(sfizz-cpuid STATIC src/cpuid/cpuinfo.cpp src/cpuid/version.cpp) -set_property(TARGET sfizz-cpuid PROPERTY CXX_STANDARD 11) -target_include_directories(sfizz-cpuid PUBLIC src PRIVATE platform/src) +add_library(sfizz_cpuid STATIC src/cpuid/cpuinfo.cpp src/cpuid/version.cpp) +add_library(sfizz::cpuid ALIAS sfizz_cpuid) +set_property(TARGET sfizz_cpuid PROPERTY CXX_STANDARD 11) +target_include_directories(sfizz_cpuid PUBLIC src PRIVATE platform/src) diff --git a/src/external/kiss_fft/CMakeLists.txt b/src/external/kiss_fft/CMakeLists.txt index dc5c22e9..e43afb1d 100644 --- a/src/external/kiss_fft/CMakeLists.txt +++ b/src/external/kiss_fft/CMakeLists.txt @@ -2,11 +2,12 @@ cmake_minimum_required(VERSION 3.5) -project(sfizz-kissfft VERSION "1.3.0" LANGUAGES C) +project(sfizz_kissfft VERSION "1.3.0" LANGUAGES C) -add_library(sfizz-kissfft STATIC +add_library(sfizz_kissfft STATIC kiss_fft.c tools/kiss_fftr.c) -target_include_directories(sfizz-kissfft +add_library(sfizz::kissfft ALIAS sfizz_kissfft) +target_include_directories(sfizz_kissfft PUBLIC "." PUBLIC "tools") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index afee85a8..8d4d34a2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -48,7 +48,7 @@ set(SFIZZ_TEST_SOURCES ) add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES}) -target_link_libraries(sfizz_tests PRIVATE sfizz::sfizz sfizz-jsl) +target_link_libraries(sfizz_tests PRIVATE sfizz::sfizz sfizz::jsl) sfizz_enable_lto_if_needed(sfizz_tests) sfizz_enable_fast_math(sfizz_tests) # target_link_libraries(sfizz_tests PRIVATE absl::strings absl::str_format absl::flat_hash_map cnpy absl::span absl::algorithm) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 6fef1424..468b6f1f 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -60,7 +60,7 @@ endif() target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} PRIVATE sfizz_editor - PRIVATE sfizz-pugixml) + PRIVATE sfizz::pugixml) target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES @@ -198,7 +198,7 @@ elseif(SFIZZ_AU) target_link_libraries(${AUPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} PRIVATE sfizz_editor - PRIVATE sfizz-pugixml) + PRIVATE sfizz::pugixml) target_include_directories(${AUPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(${AUPLUGIN_PRJ_NAME} PROPERTIES diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 20eee6b3..449467ce 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -63,7 +63,7 @@ endfunction() # --- VSTGUI --- function(plugin_add_vstgui NAME) - target_link_libraries("${NAME}" PRIVATE sfizz-vstgui) + target_link_libraries("${NAME}" PRIVATE sfizz::vstgui) target_sources("${NAME}" PRIVATE "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstguieditor.cpp") target_compile_definitions("${NAME}" PRIVATE "SMTG_MODULE_IS_BUNDLE=1") endfunction() From 361160dfc8b349b8ccee0ff39c50cf89e98ea7e6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 10:31:02 +0100 Subject: [PATCH 145/668] Search the SFZ folders defined by variable SFZ_PATH --- vst/SfizzFileScan.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++ vst/SfizzFileScan.h | 1 + 2 files changed, 50 insertions(+) diff --git a/vst/SfizzFileScan.cpp b/vst/SfizzFileScan.cpp index 441f9e80..1dd313f6 100644 --- a/vst/SfizzFileScan.cpp +++ b/vst/SfizzFileScan.cpp @@ -199,6 +199,9 @@ std::vector getSfzSearchPaths() addPath(*configDefaultPath); addPath(fallbackDefaultPath); + for (const fs::path& path : getEnvironmentSfzPaths()) + addPath(path); + for (const fs::path& foreign : { getAriaPathSetting("user_files_dir"), getAriaPathSetting("Converted_path") }) @@ -231,4 +234,50 @@ fs::path getSfzFallbackDefaultPath() return getUserDocumentsDirectory() / "SFZ instruments"; } +std::vector getEnvironmentSfzPaths() +{ + std::vector paths; + +#if defined(_WIN32) + std::unique_ptr buf; + + DWORD bufsize = GetEnvironmentVariableW(L"SFZ_PATH", nullptr, 0); + if (bufsize == 0) + return {}; + + buf.reset(new WCHAR[bufsize]); + if (GetEnvironmentVariableW(L"SFZ_PATH", buf.get(), bufsize) != bufsize - 1) + return {}; + + paths.reserve(8); + + const WCHAR* env = buf.get(); + while (*env) { + const WCHAR* endp; + for (endp = env; *endp && *endp != L';'; ++endp); + fs::path path = fs::path(env, endp); + if (!path.empty() && path.is_absolute()) + paths.push_back(std::move(path)); + env = *endp ? (endp + 1) : endp; + } +#else + const char* env = getenv("SFZ_PATH"); + if (!env) + return {}; + + paths.reserve(8); + + while (*env) { + const char* endp; + for (endp = env; *endp != ':' && *endp != '\0'; ++endp); + fs::path path = fs::u8path(env, endp); + if (!path.empty() && path.is_absolute()) + paths.push_back(std::move(path)); + env = *endp ? (endp + 1) : endp; + } +#endif + + return paths; +} + } // namespace SfizzPaths diff --git a/vst/SfizzFileScan.h b/vst/SfizzFileScan.h index 19dabf56..9a6b0a08 100644 --- a/vst/SfizzFileScan.h +++ b/vst/SfizzFileScan.h @@ -40,4 +40,5 @@ std::vector getSfzSearchPaths(); absl::optional getSfzConfigDefaultPath(); void setSfzConfigDefaultPath(const fs::path& path); fs::path getSfzFallbackDefaultPath(); +std::vector getEnvironmentSfzPaths(); } // namespace SfizzPaths From 186942a58886aca034837c85bef480468fc8b0cd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 11:01:23 +0100 Subject: [PATCH 146/668] Add ghc::filesystem as a submodule --- .gitmodules | 4 + external/filesystem | 1 + src/external/ghc/filesystem.hpp | 5191 ------------------------------ src/external/ghc/fs_fwd.hpp | 46 - src/external/ghc/fs_impl.hpp | 43 - src/external/ghc/fs_std.hpp | 64 - src/external/ghc/fs_std_fwd.hpp | 68 - src/external/ghc/fs_std_impl.hpp | 51 - 8 files changed, 5 insertions(+), 5463 deletions(-) create mode 160000 external/filesystem delete mode 100644 src/external/ghc/filesystem.hpp delete mode 100644 src/external/ghc/fs_fwd.hpp delete mode 100644 src/external/ghc/fs_impl.hpp delete mode 100644 src/external/ghc/fs_std.hpp delete mode 100644 src/external/ghc/fs_std_fwd.hpp delete mode 100644 src/external/ghc/fs_std_impl.hpp diff --git a/.gitmodules b/.gitmodules index 1fa82a18..8be5575f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -35,3 +35,7 @@ path = vst/external/sfzt_auwrapper url = https://github.com/sfztools/sfzt_auwrapper.git shallow = true +[submodule "external/filesystem"] + path = external/filesystem + url = https://github.com/gulrak/filesystem.git + shallow = true diff --git a/external/filesystem b/external/filesystem new file mode 160000 index 00000000..1edf4a33 --- /dev/null +++ b/external/filesystem @@ -0,0 +1 @@ +Subproject commit 1edf4a333930f126f5dcd2f7919f0bf4fa3acecc diff --git a/src/external/ghc/filesystem.hpp b/src/external/ghc/filesystem.hpp deleted file mode 100644 index 56b2f718..00000000 --- a/src/external/ghc/filesystem.hpp +++ /dev/null @@ -1,5191 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++147/C++17 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//--------------------------------------------------------------------------------------- -// -// To dynamically select std::filesystem where available, you could use: -// -// #if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) && __has_include() -// #include -// namespace fs = std::filesystem; -// #else -// #include -// namespace fs = ghc::filesystem; -// #endif -// -//--------------------------------------------------------------------------------------- -#ifndef GHC_FILESYSTEM_H -#define GHC_FILESYSTEM_H - -#ifndef GHC_OS_DETECTED -#if defined(__APPLE__) && defined(__MACH__) -#define GHC_OS_MACOS -#elif defined(__linux__) -#define GHC_OS_LINUX -#if defined(__ANDROID__) -#define GHC_OS_ANDROID -#endif -#elif defined(_WIN64) -#define GHC_OS_WINDOWS -#define GHC_OS_WIN64 -#elif defined(_WIN32) -#define GHC_OS_WINDOWS -#define GHC_OS_WIN32 -#else -#error "Operating system currently not supported!" -#endif -#define GHC_OS_DETECTED -#endif - -#if defined(GHC_FILESYSTEM_IMPLEMENTATION) -#define GHC_EXPAND_IMPL -#define GHC_INLINE -#ifdef GHC_OS_WINDOWS -#define GHC_FS_API -#define GHC_FS_API_CLASS -#else -#define GHC_FS_API __attribute__((visibility("default"))) -#define GHC_FS_API_CLASS __attribute__((visibility("default"))) -#endif -#elif defined(GHC_FILESYSTEM_FWD) -#define GHC_INLINE -#ifdef GHC_OS_WINDOWS -#define GHC_FS_API extern -#define GHC_FS_API_CLASS -#else -#define GHC_FS_API extern -#define GHC_FS_API_CLASS -#endif -#else -#define GHC_EXPAND_IMPL -#define GHC_INLINE inline -#define GHC_FS_API -#define GHC_FS_API_CLASS -#endif - -#ifdef GHC_EXPAND_IMPL - -#ifdef GHC_OS_WINDOWS -#include -// additional includes -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef GHC_OS_ANDROID -#include -#endif -#endif -#ifdef GHC_OS_MACOS -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#else // GHC_EXPAND_IMPL -#include -#include -#include -#include -#include -#include -#include -#ifdef GHC_OS_WINDOWS -#include -#endif -#endif // GHC_EXPAND_IMPL - -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp): -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories -// configure LWG conformance () -#define LWG_2682_BEHAVIOUR -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular -// file with that name, it is superceded by P1164R1, so only activate if really needed -// #define LWG_2935_BEHAVIOUR -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) -#define LWG_2937_BEHAVIOUR -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// UTF8-Everywhere is the original behaviour of ghc::filesystem. With this define you can -// enable the more standard conforming implementation option that uses wstring on Windows -// as ghc::filesystem::string_type. -// #define GHC_WIN_WSTRING_STRING_TYPE -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found, -// instead of replacing them with the unicode replacement character (U+FFFD). -// #define GHC_RAISE_UNICODE_ERRORS -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) -#define GHC_FILESYSTEM_VERSION 10300L - -namespace ghc { -namespace filesystem { - -// temporary existing exception type for yet unimplemented parts -class GHC_FS_API_CLASS not_implemented_exception : public std::logic_error -{ -public: - not_implemented_exception() - : std::logic_error("function not implemented yet.") - { - } -}; - -template -class path_helper_base -{ -public: - using value_type = char_type; -#ifdef GHC_OS_WINDOWS - static constexpr value_type preferred_separator = '\\'; -#else - static constexpr value_type preferred_separator = '/'; -#endif -}; - -#if __cplusplus < 201703L -template -constexpr char_type path_helper_base::preferred_separator; -#endif - -// 30.10.8 class path -class GHC_FS_API_CLASS path -#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_WSTRING_STRING_TYPE) -#define GHC_USE_WCHAR_T - : private path_helper_base -{ -public: - using path_helper_base::value_type; -#else - : private path_helper_base -{ -public: - using path_helper_base::value_type; -#endif - using string_type = std::basic_string; - using path_helper_base::preferred_separator; - - // 30.10.10.1 enumeration format - /// The path format in wich the constructor argument is given. - enum format { - generic_format, ///< The generic format, internally used by - ///< ghc::filesystem::path with slashes - native_format, ///< The format native to the current platform this code - ///< is build for - auto_format, ///< Try to auto-detect the format, fallback to native - }; - - template - struct _is_basic_string : std::false_type - { - }; - template - struct _is_basic_string> : std::true_type - { - }; -#ifdef __cpp_lib_string_view - template - struct _is_basic_string> : std::true_type - { - }; -#endif - - template - using path_type = typename std::enable_if::value, path>::type; -#ifdef GHC_USE_WCHAR_T - template - using path_from_string = typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || - std::is_same::type>::value || std::is_same::type>::value, - path>::type; - template - using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value, path>::type; -#else - template - using path_from_string = typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value, path>::type; - template - using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, path>::type; -#endif - // 30.10.8.4.1 constructors and destructor - path() noexcept; - path(const path& p); - path(path&& p) noexcept; - path(string_type&& source, format fmt = auto_format); - template > - path(const Source& source, format fmt = auto_format); - template - path(InputIterator first, InputIterator last, format fmt = auto_format); - template > - path(const Source& source, const std::locale& loc, format fmt = auto_format); - template - path(InputIterator first, InputIterator last, const std::locale& loc, format fmt = auto_format); - ~path(); - - // 30.10.8.4.2 assignments - path& operator=(const path& p); - path& operator=(path&& p) noexcept; - path& operator=(string_type&& source); - path& assign(string_type&& source); - template - path& operator=(const Source& source); - template - path& assign(const Source& source); - template - path& assign(InputIterator first, InputIterator last); - - // 30.10.8.4.3 appends - path& operator/=(const path& p); - template - path& operator/=(const Source& source); - template - path& append(const Source& source); - template - path& append(InputIterator first, InputIterator last); - - // 30.10.8.4.4 concatenation - path& operator+=(const path& x); - path& operator+=(const string_type& x); -#ifdef __cpp_lib_string_view - path& operator+=(std::basic_string_view x); -#endif - path& operator+=(const value_type* x); - path& operator+=(value_type x); - template - path_from_string& operator+=(const Source& x); - template - path_type_EcharT& operator+=(EcharT x); - template - path& concat(const Source& x); - template - path& concat(InputIterator first, InputIterator last); - - // 30.10.8.4.5 modifiers - void clear() noexcept; - path& make_preferred(); - path& remove_filename(); - path& replace_filename(const path& replacement); - path& replace_extension(const path& replacement = path()); - void swap(path& rhs) noexcept; - - // 30.10.8.4.6 native format observers - const string_type& native() const; // this implementation doesn't support noexcept for native() - const value_type* c_str() const; // this implementation doesn't support noexcept for c_str() - operator string_type() const; - template , class Allocator = std::allocator> - std::basic_string string(const Allocator& a = Allocator()) const; - std::string string() const; - std::wstring wstring() const; - std::string u8string() const; - std::u16string u16string() const; - std::u32string u32string() const; - - // 30.10.8.4.7 generic format observers - template , class Allocator = std::allocator> - std::basic_string generic_string(const Allocator& a = Allocator()) const; - const std::string& generic_string() const; // this is different from the standard, that returns by value - std::wstring generic_wstring() const; - std::string generic_u8string() const; - std::u16string generic_u16string() const; - std::u32string generic_u32string() const; - - // 30.10.8.4.8 compare - int compare(const path& p) const noexcept; - int compare(const string_type& s) const; -#ifdef __cpp_lib_string_view - int compare(std::basic_string_view s) const; -#endif - int compare(const value_type* s) const; - - // 30.10.8.4.9 decomposition - path root_name() const; - path root_directory() const; - path root_path() const; - path relative_path() const; - path parent_path() const; - path filename() const; - path stem() const; - path extension() const; - - // 30.10.8.4.10 query - bool empty() const noexcept; - bool has_root_name() const; - bool has_root_directory() const; - bool has_root_path() const; - bool has_relative_path() const; - bool has_parent_path() const; - bool has_filename() const; - bool has_stem() const; - bool has_extension() const; - bool is_absolute() const; - bool is_relative() const; - - // 30.10.8.4.11 generation - path lexically_normal() const; - path lexically_relative(const path& base) const; - path lexically_proximate(const path& base) const; - - // 30.10.8.5 iterators - class iterator; - using const_iterator = iterator; - iterator begin() const; - iterator end() const; - -private: - using impl_value_type = std::string::value_type; - using impl_string_type = std::basic_string; - friend class directory_iterator; - void append_name(const char* name); - static constexpr impl_value_type generic_separator = '/'; - template - class input_iterator_range - { - public: - typedef InputIterator iterator; - typedef InputIterator const_iterator; - typedef typename InputIterator::difference_type difference_type; - - input_iterator_range(const InputIterator& first, const InputIterator& last) - : _first(first) - , _last(last) - { - } - - InputIterator begin() const { return _first; } - InputIterator end() const { return _last; } - - private: - InputIterator _first; - InputIterator _last; - }; - friend void swap(path& lhs, path& rhs) noexcept; - friend size_t hash_value(const path& p) noexcept; - static void postprocess_path_with_format(impl_string_type& p, format fmt); - impl_string_type _path; -#ifdef GHC_OS_WINDOWS - impl_string_type native_impl() const; - mutable string_type _native_cache; -#else - const impl_string_type& native_impl() const; -#endif -}; - -// 30.10.8.6 path non-member functions -GHC_FS_API void swap(path& lhs, path& rhs) noexcept; -GHC_FS_API size_t hash_value(const path& p) noexcept; -GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept; -GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept; - -GHC_FS_API path operator/(const path& lhs, const path& rhs); - -// 30.10.8.6.1 path inserter and extractor -template -std::basic_ostream& operator<<(std::basic_ostream& os, const path& p); -template -std::basic_istream& operator>>(std::basic_istream& is, path& p); - -// 30.10.8.6.2 path factory functions -template > -path u8path(const Source& source); -template -path u8path(InputIterator first, InputIterator last); - -// 30.10.9 class filesystem_error -class GHC_FS_API_CLASS filesystem_error : public std::system_error -{ -public: - filesystem_error(const std::string& what_arg, std::error_code ec); - filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec); - filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec); - const path& path1() const noexcept; - const path& path2() const noexcept; - const char* what() const noexcept override; - -private: - std::string _what_arg; - std::error_code _ec; - path _p1, _p2; -}; - -class GHC_FS_API_CLASS path::iterator -{ -public: - using value_type = const path; - using difference_type = std::ptrdiff_t; - using pointer = const path*; - using reference = const path&; - using iterator_category = std::bidirectional_iterator_tag; - - iterator(); - iterator(const impl_string_type::const_iterator& first, const impl_string_type::const_iterator& last, const impl_string_type::const_iterator& pos); - iterator& operator++(); - iterator operator++(int); - iterator& operator--(); - iterator operator--(int); - bool operator==(const iterator& other) const; - bool operator!=(const iterator& other) const; - reference operator*() const; - pointer operator->() const; - -private: - impl_string_type::const_iterator increment(const std::string::const_iterator& pos) const; - impl_string_type::const_iterator decrement(const std::string::const_iterator& pos) const; - void updateCurrent(); - impl_string_type::const_iterator _first; - impl_string_type::const_iterator _last; - impl_string_type::const_iterator _root; - impl_string_type::const_iterator _iter; - path _current; -}; - -struct space_info -{ - uintmax_t capacity; - uintmax_t free; - uintmax_t available; -}; - -// 30.10.10, enumerations -enum class file_type { - none, - not_found, - regular, - directory, - symlink, - block, - character, - fifo, - socket, - unknown, -}; - -enum class perms : uint16_t { - none = 0, - - owner_read = 0400, - owner_write = 0200, - owner_exec = 0100, - owner_all = 0700, - - group_read = 040, - group_write = 020, - group_exec = 010, - group_all = 070, - - others_read = 04, - others_write = 02, - others_exec = 01, - others_all = 07, - - all = 0777, - set_uid = 04000, - set_gid = 02000, - sticky_bit = 01000, - - mask = 07777, - unknown = 0xffff -}; - -enum class perm_options : uint16_t { - replace = 3, - add = 1, - remove = 2, - nofollow = 4, -}; - -enum class copy_options : uint16_t { - none = 0, - - skip_existing = 1, - overwrite_existing = 2, - update_existing = 4, - - recursive = 8, - - copy_symlinks = 0x10, - skip_symlinks = 0x20, - - directories_only = 0x40, - create_symlinks = 0x80, - create_hard_links = 0x100 -}; - -enum class directory_options : uint16_t { - none = 0, - follow_directory_symlink = 1, - skip_permission_denied = 2, -}; - -// 30.10.11 class file_status -class GHC_FS_API_CLASS file_status -{ -public: - // 30.10.11.1 constructors and destructor - file_status() noexcept; - explicit file_status(file_type ft, perms prms = perms::unknown) noexcept; - file_status(const file_status&) noexcept; - file_status(file_status&&) noexcept; - ~file_status(); - // assignments: - file_status& operator=(const file_status&) noexcept; - file_status& operator=(file_status&&) noexcept; - // 30.10.11.3 modifiers - void type(file_type ft) noexcept; - void permissions(perms prms) noexcept; - // 30.10.11.2 observers - file_type type() const noexcept; - perms permissions() const noexcept; - -private: - file_type _type; - perms _perms; -}; - -using file_time_type = std::chrono::time_point; - -// 30.10.12 Class directory_entry -class GHC_FS_API_CLASS directory_entry -{ -public: - // 30.10.12.1 constructors and destructor - directory_entry() noexcept = default; - directory_entry(const directory_entry&) = default; - directory_entry(directory_entry&&) noexcept = default; - explicit directory_entry(const path& p); - directory_entry(const path& p, std::error_code& ec); - ~directory_entry(); - - // assignments: - directory_entry& operator=(const directory_entry&) = default; - directory_entry& operator=(directory_entry&&) noexcept = default; - - // 30.10.12.2 modifiers - void assign(const path& p); - void assign(const path& p, std::error_code& ec); - void replace_filename(const path& p); - void replace_filename(const path& p, std::error_code& ec); - void refresh(); - void refresh(std::error_code& ec) noexcept; - - // 30.10.12.3 observers - const filesystem::path& path() const noexcept; - operator const filesystem::path&() const noexcept; - bool exists() const; - bool exists(std::error_code& ec) const noexcept; - bool is_block_file() const; - bool is_block_file(std::error_code& ec) const noexcept; - bool is_character_file() const; - bool is_character_file(std::error_code& ec) const noexcept; - bool is_directory() const; - bool is_directory(std::error_code& ec) const noexcept; - bool is_fifo() const; - bool is_fifo(std::error_code& ec) const noexcept; - bool is_other() const; - bool is_other(std::error_code& ec) const noexcept; - bool is_regular_file() const; - bool is_regular_file(std::error_code& ec) const noexcept; - bool is_socket() const; - bool is_socket(std::error_code& ec) const noexcept; - bool is_symlink() const; - bool is_symlink(std::error_code& ec) const noexcept; - uintmax_t file_size() const; - uintmax_t file_size(std::error_code& ec) const noexcept; - uintmax_t hard_link_count() const; - uintmax_t hard_link_count(std::error_code& ec) const noexcept; - file_time_type last_write_time() const; - file_time_type last_write_time(std::error_code& ec) const noexcept; - - file_status status() const; - file_status status(std::error_code& ec) const noexcept; - - file_status symlink_status() const; - file_status symlink_status(std::error_code& ec) const noexcept; - bool operator<(const directory_entry& rhs) const noexcept; - bool operator==(const directory_entry& rhs) const noexcept; - bool operator!=(const directory_entry& rhs) const noexcept; - bool operator<=(const directory_entry& rhs) const noexcept; - bool operator>(const directory_entry& rhs) const noexcept; - bool operator>=(const directory_entry& rhs) const noexcept; - -private: - friend class directory_iterator; - filesystem::path _path; - file_status _status; - file_status _symlink_status; - uintmax_t _file_size = 0; -#ifndef GHC_OS_WINDOWS - uintmax_t _hard_link_count = 0; -#endif - time_t _last_write_time = 0; -}; - -// 30.10.13 Class directory_iterator -class GHC_FS_API_CLASS directory_iterator -{ -public: - class GHC_FS_API_CLASS proxy - { - public: - const directory_entry& operator*() const& noexcept { return _dir_entry; } - directory_entry operator*() && noexcept { return std::move(_dir_entry); } - - private: - explicit proxy(const directory_entry& dir_entry) - : _dir_entry(dir_entry) - { - } - friend class directory_iterator; - friend class recursive_directory_iterator; - directory_entry _dir_entry; - }; - using iterator_category = std::input_iterator_tag; - using value_type = directory_entry; - using difference_type = std::ptrdiff_t; - using pointer = const directory_entry*; - using reference = const directory_entry&; - - // 30.10.13.1 member functions - directory_iterator() noexcept; - explicit directory_iterator(const path& p); - directory_iterator(const path& p, directory_options options); - directory_iterator(const path& p, std::error_code& ec) noexcept; - directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; - directory_iterator(const directory_iterator& rhs); - directory_iterator(directory_iterator&& rhs) noexcept; - ~directory_iterator(); - directory_iterator& operator=(const directory_iterator& rhs); - directory_iterator& operator=(directory_iterator&& rhs) noexcept; - const directory_entry& operator*() const; - const directory_entry* operator->() const; - directory_iterator& operator++(); - directory_iterator& increment(std::error_code& ec) noexcept; - - // other members as required by 27.2.3, input iterators - proxy operator++(int) - { - proxy p{**this}; - ++*this; - return p; - } - bool operator==(const directory_iterator& rhs) const; - bool operator!=(const directory_iterator& rhs) const; - -private: - friend class recursive_directory_iterator; - class impl; - std::shared_ptr _impl; -}; - -// 30.10.13.2 directory_iterator non-member functions -GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept; -GHC_FS_API directory_iterator end(const directory_iterator&) noexcept; - -// 30.10.14 class recursive_directory_iterator -class GHC_FS_API_CLASS recursive_directory_iterator -{ -public: - using iterator_category = std::input_iterator_tag; - using value_type = directory_entry; - using difference_type = std::ptrdiff_t; - using pointer = const directory_entry*; - using reference = const directory_entry&; - - // 30.10.14.1 constructors and destructor - recursive_directory_iterator() noexcept; - explicit recursive_directory_iterator(const path& p); - recursive_directory_iterator(const path& p, directory_options options); - recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; - recursive_directory_iterator(const path& p, std::error_code& ec) noexcept; - recursive_directory_iterator(const recursive_directory_iterator& rhs); - recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept; - ~recursive_directory_iterator(); - - // 30.10.14.1 observers - directory_options options() const; - int depth() const; - bool recursion_pending() const; - - const directory_entry& operator*() const; - const directory_entry* operator->() const; - - // 30.10.14.1 modifiers recursive_directory_iterator& - recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs); - recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept; - recursive_directory_iterator& operator++(); - recursive_directory_iterator& increment(std::error_code& ec) noexcept; - - void pop(); - void pop(std::error_code& ec); - void disable_recursion_pending(); - - // other members as required by 27.2.3, input iterators - directory_iterator::proxy operator++(int) - { - directory_iterator::proxy proxy{**this}; - ++*this; - return proxy; - } - bool operator==(const recursive_directory_iterator& rhs) const; - bool operator!=(const recursive_directory_iterator& rhs) const; - -private: - struct recursive_directory_iterator_impl - { - directory_options _options; - bool _recursion_pending; - std::stack _dir_iter_stack; - recursive_directory_iterator_impl(directory_options options, bool recursion_pending) - : _options(options) - , _recursion_pending(recursion_pending) - { - } - }; - std::shared_ptr _impl; -}; - -// 30.10.14.2 directory_iterator non-member functions -GHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; -GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; - -// 30.10.15 filesystem operations -GHC_FS_API path absolute(const path& p); -GHC_FS_API path absolute(const path& p, std::error_code& ec); - -GHC_FS_API path canonical(const path& p); -GHC_FS_API path canonical(const path& p, std::error_code& ec); - -GHC_FS_API void copy(const path& from, const path& to); -GHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept; -GHC_FS_API void copy(const path& from, const path& to, copy_options options); -GHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept; - -GHC_FS_API bool copy_file(const path& from, const path& to); -GHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept; -GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option); -GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept; - -GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink); -GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept; - -GHC_FS_API bool create_directories(const path& p); -GHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API bool create_directory(const path& p); -GHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API bool create_directory(const path& p, const path& attributes); -GHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept; - -GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink); -GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; - -GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link); -GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept; - -GHC_FS_API void create_symlink(const path& to, const path& new_symlink); -GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; - -GHC_FS_API path current_path(); -GHC_FS_API path current_path(std::error_code& ec); -GHC_FS_API void current_path(const path& p); -GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API bool exists(file_status s) noexcept; -GHC_FS_API bool exists(const path& p); -GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API bool equivalent(const path& p1, const path& p2); -GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept; - -GHC_FS_API uintmax_t file_size(const path& p); -GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API uintmax_t hard_link_count(const path& p); -GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API bool is_block_file(file_status s) noexcept; -GHC_FS_API bool is_block_file(const path& p); -GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_character_file(file_status s) noexcept; -GHC_FS_API bool is_character_file(const path& p); -GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_directory(file_status s) noexcept; -GHC_FS_API bool is_directory(const path& p); -GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_empty(const path& p); -GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_fifo(file_status s) noexcept; -GHC_FS_API bool is_fifo(const path& p); -GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_other(file_status s) noexcept; -GHC_FS_API bool is_other(const path& p); -GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_regular_file(file_status s) noexcept; -GHC_FS_API bool is_regular_file(const path& p); -GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_socket(file_status s) noexcept; -GHC_FS_API bool is_socket(const path& p); -GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept; -GHC_FS_API bool is_symlink(file_status s) noexcept; -GHC_FS_API bool is_symlink(const path& p); -GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API file_time_type last_write_time(const path& p); -GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept; -GHC_FS_API void last_write_time(const path& p, file_time_type new_time); -GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept; - -GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace); -GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept; -GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec); - -GHC_FS_API path proximate(const path& p, std::error_code& ec); -GHC_FS_API path proximate(const path& p, const path& base = current_path()); -GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec); - -GHC_FS_API path read_symlink(const path& p); -GHC_FS_API path read_symlink(const path& p, std::error_code& ec); - -GHC_FS_API path relative(const path& p, std::error_code& ec); -GHC_FS_API path relative(const path& p, const path& base = current_path()); -GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec); - -GHC_FS_API bool remove(const path& p); -GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API uintmax_t remove_all(const path& p); -GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API void rename(const path& from, const path& to); -GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept; - -GHC_FS_API void resize_file(const path& p, uintmax_t size); -GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept; - -GHC_FS_API space_info space(const path& p); -GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API file_status status(const path& p); -GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API bool status_known(file_status s) noexcept; - -GHC_FS_API file_status symlink_status(const path& p); -GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept; - -GHC_FS_API path temp_directory_path(); -GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept; - -GHC_FS_API path weakly_canonical(const path& p); -GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept; - -// Non-C++17 add-on std::fstream wrappers with path -template > -class basic_filebuf : public std::basic_filebuf -{ -public: - basic_filebuf() {} - ~basic_filebuf() override {} - basic_filebuf(const basic_filebuf&) = delete; - const basic_filebuf& operator=(const basic_filebuf&) = delete; - basic_filebuf* open(const path& p, std::ios_base::openmode mode) - { -#if defined(GHC_OS_WINDOWS) && !defined(__GNUC__) - return std::basic_filebuf::open(p.wstring().c_str(), mode) ? this : 0; -#else - return std::basic_filebuf::open(p.string().c_str(), mode) ? this : 0; -#endif - } -}; - -template > -class basic_ifstream : public std::basic_ifstream -{ -public: - basic_ifstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GNUC__) - explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) - : std::basic_ifstream(p.wstring().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream::open(p.wstring().c_str(), mode); } -#else - explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) - : std::basic_ifstream(p.string().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream::open(p.string().c_str(), mode); } -#endif - basic_ifstream(const basic_ifstream&) = delete; - const basic_ifstream& operator=(const basic_ifstream&) = delete; - ~basic_ifstream() override {} -}; - -template > -class basic_ofstream : public std::basic_ofstream -{ -public: - basic_ofstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GNUC__) - explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) - : std::basic_ofstream(p.wstring().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream::open(p.wstring().c_str(), mode); } -#else - explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) - : std::basic_ofstream(p.string().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream::open(p.string().c_str(), mode); } -#endif - basic_ofstream(const basic_ofstream&) = delete; - const basic_ofstream& operator=(const basic_ofstream&) = delete; - ~basic_ofstream() override {} -}; - -template > -class basic_fstream : public std::basic_fstream -{ -public: - basic_fstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GNUC__) - explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - : std::basic_fstream(p.wstring().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream::open(p.wstring().c_str(), mode); } -#else - explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - : std::basic_fstream(p.string().c_str(), mode) - { - } - void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream::open(p.string().c_str(), mode); } -#endif - basic_fstream(const basic_fstream&) = delete; - const basic_fstream& operator=(const basic_fstream&) = delete; - ~basic_fstream() override {} -}; - -typedef basic_filebuf filebuf; -typedef basic_filebuf wfilebuf; -typedef basic_ifstream ifstream; -typedef basic_ifstream wifstream; -typedef basic_ofstream ofstream; -typedef basic_ofstream wofstream; -typedef basic_fstream fstream; -typedef basic_fstream wfstream; - -class GHC_FS_API_CLASS u8arguments -{ -public: - u8arguments(int& argc, char**& argv); - ~u8arguments() - { - _refargc = _argc; - _refargv = _argv; - } - - bool valid() const { return _isvalid; } - -private: - int _argc; - char** _argv; - int& _refargc; - char**& _refargv; - bool _isvalid; -#ifdef GHC_OS_WINDOWS - std::vector _args; - std::vector _argp; -#endif -}; - -//------------------------------------------------------------------------------------------------- -// Implementation -//------------------------------------------------------------------------------------------------- - -namespace detail { -// GHC_FS_API void postprocess_path_with_format(path::impl_string_type& p, path::format fmt); -enum utf8_states_t { S_STRT = 0, S_RJCT = 8 }; -GHC_FS_API void appendUTF8(std::string& str, uint32_t unicode); -GHC_FS_API bool is_surrogate(uint32_t c); -GHC_FS_API bool is_high_surrogate(uint32_t c); -GHC_FS_API bool is_low_surrogate(uint32_t c); -GHC_FS_API unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint); -enum class portable_error { - none = 0, - exists, - not_found, - not_supported, - not_implemented, - invalid_argument, - is_a_directory, -}; -GHC_FS_API std::error_code make_error_code(portable_error err); -#ifdef GHC_OS_WINDOWS -GHC_FS_API std::error_code make_system_error(uint32_t err = 0); -#else -GHC_FS_API std::error_code make_system_error(int err = 0); -#endif -} // namespace detail - -namespace detail { - -#ifdef GHC_EXPAND_IMPL - -GHC_INLINE std::error_code make_error_code(portable_error err) -{ -#ifdef GHC_OS_WINDOWS - switch (err) { - case portable_error::none: - return std::error_code(); - case portable_error::exists: - return std::error_code(ERROR_ALREADY_EXISTS, std::system_category()); - case portable_error::not_found: - return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category()); - case portable_error::not_supported: - return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); - case portable_error::not_implemented: - return std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category()); - case portable_error::invalid_argument: - return std::error_code(ERROR_INVALID_PARAMETER, std::system_category()); - case portable_error::is_a_directory: -#ifdef ERROR_DIRECTORY_NOT_SUPPORTED - return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); -#else - return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); -#endif - } -#else - switch (err) { - case portable_error::none: - return std::error_code(); - case portable_error::exists: - return std::error_code(EEXIST, std::system_category()); - case portable_error::not_found: - return std::error_code(ENOENT, std::system_category()); - case portable_error::not_supported: - return std::error_code(ENOTSUP, std::system_category()); - case portable_error::not_implemented: - return std::error_code(ENOSYS, std::system_category()); - case portable_error::invalid_argument: - return std::error_code(EINVAL, std::system_category()); - case portable_error::is_a_directory: - return std::error_code(EISDIR, std::system_category()); - } -#endif - return std::error_code(); -} - -#ifdef GHC_OS_WINDOWS -GHC_INLINE std::error_code make_system_error(uint32_t err) -{ - return std::error_code(err ? static_cast(err) : static_cast(::GetLastError()), std::system_category()); -} -#else -GHC_INLINE std::error_code make_system_error(int err) -{ - return std::error_code(err ? err : errno, std::system_category()); -} -#endif - -#endif // GHC_EXPAND_IMPL - -template -using EnableBitmask = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, Enum>::type; -} // namespace detail - -template -detail::EnableBitmask operator&(Enum X, Enum Y) -{ - using underlying = typename std::underlying_type::type; - return static_cast(static_cast(X) & static_cast(Y)); -} - -template -detail::EnableBitmask operator|(Enum X, Enum Y) -{ - using underlying = typename std::underlying_type::type; - return static_cast(static_cast(X) | static_cast(Y)); -} - -template -detail::EnableBitmask operator^(Enum X, Enum Y) -{ - using underlying = typename std::underlying_type::type; - return static_cast(static_cast(X) ^ static_cast(Y)); -} - -template -detail::EnableBitmask operator~(Enum X) -{ - using underlying = typename std::underlying_type::type; - return static_cast(~static_cast(X)); -} - -template -detail::EnableBitmask& operator&=(Enum& X, Enum Y) -{ - X = X & Y; - return X; -} - -template -detail::EnableBitmask& operator|=(Enum& X, Enum Y) -{ - X = X | Y; - return X; -} - -template -detail::EnableBitmask& operator^=(Enum& X, Enum Y) -{ - X = X ^ Y; - return X; -} - -#ifdef GHC_EXPAND_IMPL - -namespace detail { - -GHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi) -{ - return (static_cast(c - lo) < (hi - lo + 1)); -} - -GHC_INLINE bool is_surrogate(uint32_t c) -{ - return in_range(c, 0xd800, 0xdfff); -} - -GHC_INLINE bool is_high_surrogate(uint32_t c) -{ - return (c & 0xfffffc00) == 0xd800; -} - -GHC_INLINE bool is_low_surrogate(uint32_t c) -{ - return (c & 0xfffffc00) == 0xdc00; -} - -GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode) -{ - if (unicode <= 0x7f) { - str.push_back(static_cast(unicode)); - } - else if (unicode >= 0x80 && unicode <= 0x7ff) { - str.push_back(static_cast((unicode >> 6) + 192)); - str.push_back(static_cast((unicode & 0x3f) + 128)); - } - else if ((unicode >= 0x800 && unicode <= 0xd7ff) || (unicode >= 0xe000 && unicode <= 0xffff)) { - str.push_back(static_cast((unicode >> 12) + 224)); - str.push_back(static_cast(((unicode & 0xfff) >> 6) + 128)); - str.push_back(static_cast((unicode & 0x3f) + 128)); - } - else if (unicode >= 0x10000 && unicode <= 0x10ffff) { - str.push_back(static_cast((unicode >> 18) + 240)); - str.push_back(static_cast(((unicode & 0x3ffff) >> 12) + 128)); - str.push_back(static_cast(((unicode & 0xfff) >> 6) + 128)); - str.push_back(static_cast((unicode & 0x3f) + 128)); - } - else { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal code point for unicode character.", str, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - appendUTF8(str, 0xfffd); -#endif - } -} - -// Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/) -// and Taylor R Campbell for the ideas to this DFA approach of UTF-8 decoding; -// Generating debugging and shrinking my own DFA from scratch was a day of fun! -GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint) -{ - static const uint32_t utf8_state_info[] = { - // encoded states - 0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u, - 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u, 0u, 0u, - }; - uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf; - codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu) : (0xffu >> category) & fragment); - return state == S_RJCT ? static_cast(S_RJCT) : static_cast((utf8_state_info[category + 16] >> (state << 2)) & 0xf); -} - -GHC_INLINE bool validUtf8(const std::string& utf8String) -{ - std::string::const_iterator iter = utf8String.begin(); - unsigned utf8_state = S_STRT; - std::uint32_t codepoint = 0; - while (iter < utf8String.end()) { - if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_RJCT) { - return false; - } - } - if (utf8_state) { - return false; - } - return true; -} - -} // namespace detail - -#endif - -namespace detail { - -template ::type* = nullptr> -inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - return StringType(utf8String.begin(), utf8String.end(), alloc); -} - -template ::type* = nullptr> -inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - StringType result(alloc); - result.reserve(utf8String.length()); - std::string::const_iterator iter = utf8String.begin(); - unsigned utf8_state = S_STRT; - std::uint32_t codepoint = 0; - while (iter < utf8String.end()) { - if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_STRT) { - if (codepoint <= 0xffff) { - result += static_cast(codepoint); - } - else { - codepoint -= 0x10000; - result += static_cast((codepoint >> 10) + 0xd800); - result += static_cast((codepoint & 0x3ff) + 0xdc00); - } - codepoint = 0; - } - else if (utf8_state == S_RJCT) { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - result += static_cast(0xfffd); - utf8_state = S_STRT; - codepoint = 0; -#endif - } - } - if (utf8_state) { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - result += static_cast(0xfffd); -#endif - } - return result; -} - -template ::type* = nullptr> -inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) -{ - StringType result(alloc); - result.reserve(utf8String.length()); - std::string::const_iterator iter = utf8String.begin(); - unsigned utf8_state = S_STRT; - std::uint32_t codepoint = 0; - while (iter < utf8String.end()) { - if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_STRT) { - result += static_cast(codepoint); - codepoint = 0; - } - else if (utf8_state == S_RJCT) { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - result += static_cast(0xfffd); - utf8_state = S_STRT; - codepoint = 0; -#endif - } - } - if (utf8_state) { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - result += static_cast(0xfffd); -#endif - } - return result; -} - -template ::type size = 1> -inline std::string toUtf8(const std::basic_string& unicodeString) -{ - return std::string(unicodeString.begin(), unicodeString.end()); -} - -template ::type size = 2> -inline std::string toUtf8(const std::basic_string& unicodeString) -{ - std::string result; - for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) { - char32_t c = *iter; - if (is_surrogate(c)) { - ++iter; - if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) { - appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00); - } - else { -#ifdef GHC_RAISE_UNICODE_ERRORS - throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence)); -#else - appendUTF8(result, 0xfffd); - if(iter == unicodeString.end()) { - break; - } -#endif - } - } - else { - appendUTF8(result, c); - } - } - return result; -} - -template ::type size = 4> -inline std::string toUtf8(const std::basic_string& unicodeString) -{ - std::string result; - for (auto c : unicodeString) { - appendUTF8(result, static_cast(c)); - } - return result; -} - -template -inline std::string toUtf8(const charT* unicodeString) -{ - return toUtf8(std::basic_string>(unicodeString)); -} - -} // namespace detail - -#ifdef GHC_EXPAND_IMPL - -namespace detail { - -GHC_INLINE bool startsWith(const std::string& what, const std::string& with) -{ - return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin()); -} - -} // namespace detail - -GHC_INLINE void path::postprocess_path_with_format(path::impl_string_type& p, path::format fmt) -{ -#ifdef GHC_RAISE_UNICODE_ERRORS - if(!detail::validUtf8(p)) { - path t; - t._path = p; - throw filesystem_error("Illegal byte sequence for unicode character.", t, std::make_error_code(std::errc::illegal_byte_sequence)); - } -#endif - switch (fmt) { -#ifndef GHC_OS_WINDOWS - case path::auto_format: - case path::native_format: -#endif - case path::generic_format: - // nothing to do - break; -#ifdef GHC_OS_WINDOWS - case path::auto_format: - case path::native_format: - if (detail::startsWith(p, std::string("\\\\?\\"))) { - // remove Windows long filename marker - p.erase(0, 4); - if (detail::startsWith(p, std::string("UNC\\"))) { - p.erase(0, 2); - p[0] = '\\'; - } - } - for (auto& c : p) { - if (c == '\\') { - c = '/'; - } - } - break; -#endif - } - if (p.length() > 2 && p[0] == '/' && p[1] == '/' && p[2] != '/') { - std::string::iterator new_end = std::unique(p.begin() + 2, p.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == '/'; }); - p.erase(new_end, p.end()); - } - else { - std::string::iterator new_end = std::unique(p.begin(), p.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == '/'; }); - p.erase(new_end, p.end()); - } -} - -#endif // GHC_EXPAND_IMPL - -template -inline path::path(const Source& source, format fmt) - : _path(detail::toUtf8(source)) -{ - postprocess_path_with_format(_path, fmt); -} -template <> -inline path::path(const std::wstring& source, format fmt) -{ - _path = detail::toUtf8(source); - postprocess_path_with_format(_path, fmt); -} -template <> -inline path::path(const std::u16string& source, format fmt) -{ - _path = detail::toUtf8(source); - postprocess_path_with_format(_path, fmt); -} -template <> -inline path::path(const std::u32string& source, format fmt) -{ - _path = detail::toUtf8(source); - postprocess_path_with_format(_path, fmt); -} - -#ifdef __cpp_lib_string_view -template <> -inline path::path(const std::string_view& source, format fmt) -{ - _path = detail::toUtf8(std::string(source)); - postprocess_path_with_format(_path, fmt); -} -#endif - -template -inline path u8path(const Source& source) -{ - return path(source); -} -template -inline path u8path(InputIterator first, InputIterator last) -{ - return path(first, last); -} - -template -inline path::path(InputIterator first, InputIterator last, format fmt) - : path(std::basic_string::value_type>(first, last), fmt) -{ - // delegated -} - -#ifdef GHC_EXPAND_IMPL - -namespace detail { - -GHC_INLINE bool equals_simple_insensitive(const char* str1, const char* str2) -{ -#ifdef GHC_OS_WINDOWS -#ifdef __GNUC__ - while (::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2++)) { - if (*str1++ == 0) - return true; - } - return false; -#else - return 0 == ::_stricmp(str1, str2); -#endif -#else - return 0 == ::strcasecmp(str1, str2); -#endif -} - -GHC_INLINE const char* strerror_adapter(char* gnu, char*) -{ - return gnu; -} - -GHC_INLINE const char* strerror_adapter(int posix, char* buffer) -{ - if(posix) { - return "Error in strerror_r!"; - } - return buffer; -} - -template -GHC_INLINE std::string systemErrorText(ErrorNumber code = 0) -{ -#if defined(GHC_OS_WINDOWS) - LPVOID msgBuf; - DWORD dw = code ? static_cast(code) : ::GetLastError(); - FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL); - std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf)); - LocalFree(msgBuf); - return msg; -#else - char buffer[512]; - return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer); -#endif -} - -#ifdef GHC_OS_WINDOWS -using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD); -using CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); - -GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec) -{ - std::error_code tec; - auto fs = status(target_name, tec); - if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) { - ec = detail::make_error_code(detail::portable_error::not_supported); - return; - } -#if defined(__GNUC__) && __GNUC__ >= 8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - static CreateSymbolicLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); -#if defined(__GNUC__) && __GNUC__ >= 8 -#pragma GCC diagnostic pop -#endif - if (api_call) { - if (api_call(detail::fromUtf8(new_symlink.u8string()).c_str(), detail::fromUtf8(target_name.u8string()).c_str(), to_directory ? 1 : 0) == 0) { - auto result = ::GetLastError(); - if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(detail::fromUtf8(new_symlink.u8string()).c_str(), detail::fromUtf8(target_name.u8string()).c_str(), to_directory ? 3 : 2) != 0) { - return; - } - ec = detail::make_system_error(result); - } - } - else { - ec = detail::make_system_error(ERROR_NOT_SUPPORTED); - } -} - -GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) -{ -#if defined(__GNUC__) && __GNUC__ >= 8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - static CreateHardLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); -#if defined(__GNUC__) && __GNUC__ >= 8 -#pragma GCC diagnostic pop -#endif - if (api_call) { - if (api_call(detail::fromUtf8(new_hardlink.u8string()).c_str(), detail::fromUtf8(target_name.u8string()).c_str(), NULL) == 0) { - ec = detail::make_system_error(); - } - } - else { - ec = detail::make_system_error(ERROR_NOT_SUPPORTED); - } -} -#else -GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec) -{ - if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) { - ec = detail::make_system_error(); - } -} - -GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) -{ - if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) { - ec = detail::make_system_error(); - } -} -#endif - -template -GHC_INLINE file_status file_status_from_st_mode(T mode) -{ -#ifdef GHC_OS_WINDOWS - file_type ft = file_type::unknown; - if ((mode & _S_IFDIR) == _S_IFDIR) { - ft = file_type::directory; - } - else if ((mode & _S_IFREG) == _S_IFREG) { - ft = file_type::regular; - } - else if ((mode & _S_IFCHR) == _S_IFCHR) { - ft = file_type::character; - } - perms prms = static_cast(mode & 0xfff); - return file_status(ft, prms); -#else - file_type ft = file_type::unknown; - if (S_ISDIR(mode)) { - ft = file_type::directory; - } - else if (S_ISREG(mode)) { - ft = file_type::regular; - } - else if (S_ISCHR(mode)) { - ft = file_type::character; - } - else if (S_ISBLK(mode)) { - ft = file_type::block; - } - else if (S_ISFIFO(mode)) { - ft = file_type::fifo; - } - else if (S_ISLNK(mode)) { - ft = file_type::symlink; - } - else if (S_ISSOCK(mode)) { - ft = file_type::socket; - } - perms prms = static_cast(mode & 0xfff); - return file_status(ft, prms); -#endif -} - -GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) -{ -#ifdef GHC_OS_WINDOWS -#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE - typedef struct _REPARSE_DATA_BUFFER - { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union - { - struct - { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct - { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct - { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - } DUMMYUNIONNAME; - } REPARSE_DATA_BUFFER; -#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) -#endif -#endif - - std::shared_ptr file(CreateFileW(p.wstring().c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); - if (file.get() == INVALID_HANDLE_VALUE) { - ec = detail::make_system_error(); - return path(); - } - - std::shared_ptr reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free); - ULONG bufferUsed; - path result; - if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { - if (IsReparseTagMicrosoft(reparseData->ReparseTag)) { - switch (reparseData->ReparseTag) { - case IO_REPARSE_TAG_SYMLINK: - result = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR)); - break; - case IO_REPARSE_TAG_MOUNT_POINT: - result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR)); - break; - default: - break; - } - } - } - else { - ec = detail::make_system_error(); - } - return result; -#else - size_t bufferSize = 256; - while (true) { - std::vector buffer(bufferSize, static_cast(0)); - auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size()); - if (rc < 0) { - ec = detail::make_system_error(); - return path(); - } - else if (rc < static_cast(bufferSize)) { - return path(std::string(buffer.data(), static_cast(rc))); - } - bufferSize *= 2; - } - return path(); -#endif -} - -#ifdef GHC_OS_WINDOWS -GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft) -{ - ULARGE_INTEGER ull; - ull.LowPart = ft.dwLowDateTime; - ull.HighPart = ft.dwHighDateTime; - return static_cast(ull.QuadPart / 10000000ULL - 11644473600ULL); -} - -GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) -{ - LONGLONG ll; - ll = Int32x32To64(t, 10000000) + 116444736000000000; - ft.dwLowDateTime = static_cast(ll); - ft.dwHighDateTime = static_cast(ll >> 32); -} - -template -GHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info) -{ - return static_cast(-1); -} - -template <> -GHC_INLINE uintmax_t hard_links_from_INFO(const BY_HANDLE_FILE_INFORMATION* info) -{ - return info->nNumberOfLinks; -} - -template -GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code&, uintmax_t* sz = nullptr, time_t* lwt = nullptr) noexcept -{ - file_type ft = file_type::unknown; - if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { - ft = file_type::symlink; - } - else { - if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - ft = file_type::directory; - } - else { - ft = file_type::regular; - } - } - perms prms = perms::owner_read | perms::group_read | perms::others_read; - if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { - prms = prms | perms::owner_write | perms::group_write | perms::others_write; - } - std::string ext = p.extension().generic_string(); - if (equals_simple_insensitive(ext.c_str(), ".exe") || equals_simple_insensitive(ext.c_str(), ".cmd") || equals_simple_insensitive(ext.c_str(), ".bat") || equals_simple_insensitive(ext.c_str(), ".com")) { - prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec; - } - if (sz) { - *sz = static_cast(info->nFileSizeHigh) << (sizeof(info->nFileSizeHigh) * 8) | info->nFileSizeLow; - } - if (lwt) { - *lwt = detail::timeFromFILETIME(info->ftLastWriteTime); - } - return file_status(ft, prms); -} - -#endif - -GHC_INLINE bool is_not_found_error(std::error_code& ec) -{ -#ifdef GHC_OS_WINDOWS - return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND || ec.value() == ERROR_INVALID_NAME; -#else - return ec.value() == ENOENT || ec.value() == ENOTDIR; -#endif -} - -GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept -{ -#ifdef GHC_OS_WINDOWS - file_status fs; - WIN32_FILE_ATTRIBUTE_DATA attr; - if (!GetFileAttributesExW(detail::fromUtf8(p.u8string()).c_str(), GetFileExInfoStandard, &attr)) { - ec = detail::make_system_error(); - } - else { - ec.clear(); - fs = detail::status_from_INFO(p, &attr, ec, sz, lwt); - if (nhl) { - *nhl = 0; - } - if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - fs.type(file_type::symlink); - } - } - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found); - } - return ec ? file_status(file_type::none) : fs; -#else - (void)sz; - (void)nhl; - (void)lwt; - struct ::stat fs; - auto result = ::lstat(p.c_str(), &fs); - if (result == 0) { - ec.clear(); - file_status f_s = detail::file_status_from_st_mode(fs.st_mode); - return f_s; - } - ec = detail::make_system_error(); - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found, perms::unknown); - } - return file_status(file_type::none); -#endif -} - -GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - if (recurse_count > 16) { - ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/); - return file_status(file_type::unknown); - } - WIN32_FILE_ATTRIBUTE_DATA attr; - if (!::GetFileAttributesExW(p.wstring().c_str(), GetFileExInfoStandard, &attr)) { - ec = detail::make_system_error(); - } - else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - path target = resolveSymlink(p, ec); - file_status result; - if (!ec && !target.empty()) { - if (sls) { - *sls = status_from_INFO(p, &attr, ec); - } - return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1); - } - return file_status(file_type::unknown); - } - if (ec) { - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found); - } - return file_status(file_type::none); - } - if (nhl) { - *nhl = 0; - } - return detail::status_from_INFO(p, &attr, ec, sz, lwt); -#else - (void)recurse_count; - struct ::stat st; - auto result = ::lstat(p.c_str(), &st); - if (result == 0) { - ec.clear(); - file_status fs = detail::file_status_from_st_mode(st.st_mode); - if (fs.type() == file_type::symlink) { - result = ::stat(p.c_str(), &st); - if (result == 0) { - if (sls) { - *sls = fs; - } - fs = detail::file_status_from_st_mode(st.st_mode); - } - } - if (sz) { - *sz = static_cast(st.st_size); - } - if (nhl) { - *nhl = st.st_nlink; - } - if (lwt) { - *lwt = st.st_mtime; - } - return fs; - } - else { - ec = detail::make_system_error(); - if (detail::is_not_found_error(ec)) { - return file_status(file_type::not_found, perms::unknown); - } - return file_status(file_type::none); - } -#endif -} - -} // namespace detail - -GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv) - : _argc(argc) - , _argv(argv) - , _refargc(argc) - , _refargv(argv) - , _isvalid(false) -{ -#ifdef GHC_OS_WINDOWS - LPWSTR* p; - p = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - _args.reserve(static_cast(argc)); - _argp.reserve(static_cast(argc)); - for (size_t i = 0; i < static_cast(argc); ++i) { - _args.push_back(detail::toUtf8(std::wstring(p[i]))); - _argp.push_back((char*)_args[i].data()); - } - argv = _argp.data(); - ::LocalFree(p); - _isvalid = true; -#else - std::setlocale(LC_ALL, ""); -#if defined(__ANDROID__) && __ANDROID_API__ < 26 - _isvalid = true; -#else - if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), "UTF-8")) { - _isvalid = true; - } -#endif -#endif -} - -//----------------------------------------------------------------------------- -// 30.10.8.4.1 constructors and destructor - -GHC_INLINE path::path() noexcept {} - -GHC_INLINE path::path(const path& p) - : _path(p._path) -{ -} - -GHC_INLINE path::path(path&& p) noexcept - : _path(std::move(p._path)) -{ -} - -GHC_INLINE path::path(string_type&& source, format fmt) -#ifdef GHC_USE_WCHAR_T - : _path(detail::toUtf8(source)) -#else - : _path(std::move(source)) -#endif -{ - postprocess_path_with_format(_path, fmt); -} - -#endif // GHC_EXPAND_IMPL - -template -inline path::path(const Source& source, const std::locale& loc, format fmt) - : path(source, fmt) -{ - std::string locName = loc.name(); - if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { - throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); - } -} - -template -inline path::path(InputIterator first, InputIterator last, const std::locale& loc, format fmt) - : path(std::basic_string::value_type>(first, last), fmt) -{ - std::string locName = loc.name(); - if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { - throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); - } -} - -#ifdef GHC_EXPAND_IMPL - -GHC_INLINE path::~path() {} - -//----------------------------------------------------------------------------- -// 30.10.8.4.2 assignments - -GHC_INLINE path& path::operator=(const path& p) -{ - _path = p._path; - return *this; -} - -GHC_INLINE path& path::operator=(path&& p) noexcept -{ - _path = std::move(p._path); - return *this; -} - -GHC_INLINE path& path::operator=(path::string_type&& source) -{ - return assign(source); -} - -GHC_INLINE path& path::assign(path::string_type&& source) -{ -#ifdef GHC_USE_WCHAR_T - _path = detail::toUtf8(source); -#else - _path = std::move(source); -#endif - postprocess_path_with_format(_path, native_format); - return *this; -} - -#endif // GHC_EXPAND_IMPL - -template -inline path& path::operator=(const Source& source) -{ - return assign(source); -} - -template -inline path& path::assign(const Source& source) -{ - _path.assign(detail::toUtf8(source)); - postprocess_path_with_format(_path, native_format); - return *this; -} - -template <> -inline path& path::assign(const path& source) -{ - _path = source._path; - return *this; -} - -template -inline path& path::assign(InputIterator first, InputIterator last) -{ - _path.assign(first, last); - postprocess_path_with_format(_path, native_format); - return *this; -} - -#ifdef GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// 30.10.8.4.3 appends - -GHC_INLINE path& path::operator/=(const path& p) -{ - if (p.empty()) { - // was: if ((!has_root_directory() && is_absolute()) || has_filename()) - if (!_path.empty() && _path[_path.length() - 1] != '/' && _path[_path.length() - 1] != ':') { - _path += '/'; - } - return *this; - } - if ((p.is_absolute() && (_path != root_name() || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) { - assign(p); - return *this; - } - if (p.has_root_directory()) { - assign(root_name()); - } - else if ((!has_root_directory() && is_absolute()) || has_filename()) { - _path += '/'; - } - auto iter = p.begin(); - bool first = true; - if (p.has_root_name()) { - ++iter; - } - while (iter != p.end()) { - if (!first && !(!_path.empty() && _path[_path.length() - 1] == '/')) { - _path += '/'; - } - first = false; - _path += (*iter++).generic_string(); - } - return *this; -} - -GHC_INLINE void path::append_name(const char* name) -{ - if (_path.empty()) { - this->operator/=(path(name)); - } - else { - if (_path.back() != path::generic_separator) { - _path.push_back(path::generic_separator); - } - _path += name; - } -} - -#endif // GHC_EXPAND_IMPL - -template -inline path& path::operator/=(const Source& source) -{ - return append(source); -} - -template -inline path& path::append(const Source& source) -{ - return this->operator/=(path(detail::toUtf8(source))); -} - -template <> -inline path& path::append(const path& p) -{ - return this->operator/=(p); -} - -template -inline path& path::append(InputIterator first, InputIterator last) -{ - std::basic_string::value_type> part(first, last); - return append(part); -} - -#ifdef GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// 30.10.8.4.4 concatenation - -GHC_INLINE path& path::operator+=(const path& x) -{ - return concat(x._path); -} - -GHC_INLINE path& path::operator+=(const string_type& x) -{ - return concat(x); -} - -#ifdef __cpp_lib_string_view -GHC_INLINE path& path::operator+=(std::basic_string_view x) -{ - return concat(x); -} -#endif - -GHC_INLINE path& path::operator+=(const value_type* x) -{ - return concat(string_type(x)); -} - -GHC_INLINE path& path::operator+=(value_type x) -{ -#ifdef GHC_OS_WINDOWS - if (x == '\\') { - x = generic_separator; - } -#endif - if (_path.empty() || _path.back() != generic_separator) { -#ifdef GHC_USE_WCHAR_T - _path += detail::toUtf8(string_type(1, x)); -#else - _path += x; -#endif - } - return *this; -} - -#endif // GHC_EXPAND_IMPL - -template -inline path::path_from_string& path::operator+=(const Source& x) -{ - return concat(x); -} - -template -inline path::path_type_EcharT& path::operator+=(EcharT x) -{ - std::basic_string part(1, x); - concat(detail::toUtf8(part)); - return *this; -} - -template -inline path& path::concat(const Source& x) -{ - path p(x); - postprocess_path_with_format(p._path, native_format); - _path += p._path; - return *this; -} -template -inline path& path::concat(InputIterator first, InputIterator last) -{ - _path.append(first, last); - postprocess_path_with_format(_path, native_format); - return *this; -} - -#ifdef GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// 30.10.8.4.5 modifiers -GHC_INLINE void path::clear() noexcept -{ - _path.clear(); -} - -GHC_INLINE path& path::make_preferred() -{ - // as this filesystem implementation only uses generic_format - // internally, this must be a no-op - return *this; -} - -GHC_INLINE path& path::remove_filename() -{ - if (has_filename()) { - _path.erase(_path.size() - filename()._path.size()); - } - return *this; -} - -GHC_INLINE path& path::replace_filename(const path& replacement) -{ - remove_filename(); - return append(replacement); -} - -GHC_INLINE path& path::replace_extension(const path& replacement) -{ - if (has_extension()) { - _path.erase(_path.size() - extension()._path.size()); - } - if (!replacement.empty() && replacement._path[0] != '.') { - _path += '.'; - } - return concat(replacement); -} - -GHC_INLINE void path::swap(path& rhs) noexcept -{ - _path.swap(rhs._path); -} - -//----------------------------------------------------------------------------- -// 30.10.8.4.6, native format observers -#ifdef GHC_OS_WINDOWS -GHC_INLINE path::impl_string_type path::native_impl() const -{ - impl_string_type result; - if (is_absolute() && _path.length() > MAX_PATH - 10) { - // expand long Windows filenames with marker - if (has_root_name() && _path[0] == '/') { - result = "\\\\?\\UNC" + _path.substr(1); - } - else { - result = "\\\\?\\" + _path; - } - } - else { - result = _path; - } - /*if (has_root_name() && root_name()._path[0] == '/') { - return _path; - }*/ - for (auto& c : result) { - if (c == '/') { - c = '\\'; - } - } - return result; -} -#else -GHC_INLINE const path::impl_string_type& path::native_impl() const -{ - return _path; -} -#endif - -GHC_INLINE const path::string_type& path::native() const -{ -#ifdef GHC_OS_WINDOWS -#ifdef GHC_USE_WCHAR_T - _native_cache = detail::fromUtf8(native_impl()); -#else - _native_cache = native_impl(); -#endif - return _native_cache; -#else - return _path; -#endif -} - -GHC_INLINE const path::value_type* path::c_str() const -{ - return native().c_str(); -} - -GHC_INLINE path::operator path::string_type() const -{ - return native(); -} - -#endif // GHC_EXPAND_IMPL - -template -inline std::basic_string path::string(const Allocator& a) const -{ - return detail::fromUtf8>(native_impl(), a); -} - -#ifdef GHC_EXPAND_IMPL - -GHC_INLINE std::string path::string() const -{ - return native_impl(); -} - -GHC_INLINE std::wstring path::wstring() const -{ -#ifdef GHC_USE_WCHAR_T - return native(); -#else - return detail::fromUtf8(native()); -#endif -} - -GHC_INLINE std::string path::u8string() const -{ - return native_impl(); -} - -GHC_INLINE std::u16string path::u16string() const -{ - return detail::fromUtf8(native_impl()); -} - -GHC_INLINE std::u32string path::u32string() const -{ - return detail::fromUtf8(native_impl()); -} - -#endif // GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// 30.10.8.4.7, generic format observers -template -inline std::basic_string path::generic_string(const Allocator& a) const -{ - return detail::fromUtf8>(_path, a); -} - -#ifdef GHC_EXPAND_IMPL - -GHC_INLINE const std::string& path::generic_string() const -{ - return _path; -} - -GHC_INLINE std::wstring path::generic_wstring() const -{ - return detail::fromUtf8(_path); -} - -GHC_INLINE std::string path::generic_u8string() const -{ - return _path; -} - -GHC_INLINE std::u16string path::generic_u16string() const -{ - return detail::fromUtf8(_path); -} - -GHC_INLINE std::u32string path::generic_u32string() const -{ - return detail::fromUtf8(_path); -} - -//----------------------------------------------------------------------------- -// 30.10.8.4.8, compare -GHC_INLINE int path::compare(const path& p) const noexcept -{ - return native().compare(p.native()); -} - -GHC_INLINE int path::compare(const string_type& s) const -{ - return native().compare(path(s).native()); -} - -#ifdef __cpp_lib_string_view -GHC_INLINE int path::compare(std::basic_string_view s) const -{ - return native().compare(path(s).native()); -} -#endif - -GHC_INLINE int path::compare(const value_type* s) const -{ - return native().compare(path(s).native()); -} - -//----------------------------------------------------------------------------- -// 30.10.8.4.9, decomposition -GHC_INLINE path path::root_name() const -{ -#ifdef GHC_OS_WINDOWS - if (_path.length() >= 2 && std::toupper(static_cast(_path[0])) >= 'A' && std::toupper(static_cast(_path[0])) <= 'Z' && _path[1] == ':') { - return path(_path.substr(0, 2)); - } -#endif - if (_path.length() > 2 && _path[0] == '/' && _path[1] == '/' && _path[2] != '/' && std::isprint(_path[2])) { - impl_string_type::size_type pos = _path.find_first_of("/\\", 3); - if (pos == impl_string_type::npos) { - return path(_path); - } - else { - return path(_path.substr(0, pos)); - } - } - return path(); -} - -GHC_INLINE path path::root_directory() const -{ - path root = root_name(); - if (_path.length() > root._path.length() && _path[root._path.length()] == '/') { - return path("/"); - } - return path(); -} - -GHC_INLINE path path::root_path() const -{ - return root_name().generic_string() + root_directory().generic_string(); -} - -GHC_INLINE path path::relative_path() const -{ - std::string root = root_path()._path; - return path(_path.substr((std::min)(root.length(), _path.length())), generic_format); -} - -GHC_INLINE path path::parent_path() const -{ - if (has_relative_path()) { - if (empty() || begin() == --end()) { - return path(); - } - else { - path pp; - for (string_type s : input_iterator_range(begin(), --end())) { - if (s == "/") { - // don't use append to join a path- - pp += s; - } - else { - pp /= s; - } - } - return pp; - } - } - else { - return *this; - } -} - -GHC_INLINE path path::filename() const -{ - return relative_path().empty() ? path() : path(*--end()); -} - -GHC_INLINE path path::stem() const -{ - impl_string_type fn = filename().string(); - if (fn != "." && fn != "..") { - impl_string_type::size_type n = fn.rfind('.'); - if (n != impl_string_type::npos && n != 0) { - return path{fn.substr(0, n)}; - } - } - return path{fn}; -} - -GHC_INLINE path path::extension() const -{ - impl_string_type fn = filename().string(); - impl_string_type::size_type pos = fn.find_last_of('.'); - if (pos == std::string::npos || pos == 0) { - return ""; - } - return fn.substr(pos); -} - -//----------------------------------------------------------------------------- -// 30.10.8.4.10, query -GHC_INLINE bool path::empty() const noexcept -{ - return _path.empty(); -} - -GHC_INLINE bool path::has_root_name() const -{ - return !root_name().empty(); -} - -GHC_INLINE bool path::has_root_directory() const -{ - return !root_directory().empty(); -} - -GHC_INLINE bool path::has_root_path() const -{ - return !root_path().empty(); -} - -GHC_INLINE bool path::has_relative_path() const -{ - return !relative_path().empty(); -} - -GHC_INLINE bool path::has_parent_path() const -{ - return !parent_path().empty(); -} - -GHC_INLINE bool path::has_filename() const -{ - return !filename().empty(); -} - -GHC_INLINE bool path::has_stem() const -{ - return !stem().empty(); -} - -GHC_INLINE bool path::has_extension() const -{ - return !extension().empty(); -} - -GHC_INLINE bool path::is_absolute() const -{ -#ifdef GHC_OS_WINDOWS - return has_root_name() && has_root_directory(); -#else - return has_root_directory(); -#endif -} - -GHC_INLINE bool path::is_relative() const -{ - return !is_absolute(); -} - -//----------------------------------------------------------------------------- -// 30.10.8.4.11, generation -GHC_INLINE path path::lexically_normal() const -{ - path dest; - bool lastDotDot = false; - for (string_type s : *this) { - if (s == ".") { - dest /= ""; - continue; - } - else if (s == ".." && !dest.empty()) { - auto root = root_path(); - if (dest == root) { - continue; - } - else if (*(--dest.end()) != "..") { - if (dest._path.back() == generic_separator) { - dest._path.pop_back(); - } - dest.remove_filename(); - continue; - } - } - if (!(s.empty() && lastDotDot)) { - dest /= s; - } - lastDotDot = s == ".."; - } - if (dest.empty()) { - dest = "."; - } - return dest; -} - -GHC_INLINE path path::lexically_relative(const path& base) const -{ - if (root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory())) { - return path(); - } - const_iterator a = begin(), b = base.begin(); - while (a != end() && b != base.end() && *a == *b) { - ++a; - ++b; - } - if (a == end() && b == base.end()) { - return path("."); - } - int count = 0; - for (const auto& element : input_iterator_range(b, base.end())) { - if (element != "." && element != "..") { - ++count; - } - else if (element == "..") { - --count; - } - } - if (count < 0) { - return path(); - } - path result; - for (int i = 0; i < count; ++i) { - result /= ".."; - } - for (const auto& element : input_iterator_range(a, end())) { - result /= element; - } - return result; -} - -GHC_INLINE path path::lexically_proximate(const path& base) const -{ - path result = lexically_relative(base); - return result.empty() ? *this : result; -} - -//----------------------------------------------------------------------------- -// 30.10.8.5, iterators -GHC_INLINE path::iterator::iterator() {} - -GHC_INLINE path::iterator::iterator(const path::impl_string_type::const_iterator& first, const path::impl_string_type::const_iterator& last, const path::impl_string_type::const_iterator& pos) - : _first(first) - , _last(last) - , _iter(pos) -{ - updateCurrent(); - // find the position of a potential root directory slash -#ifdef GHC_OS_WINDOWS - if (_last - _first >= 3 && std::toupper(static_cast(*first)) >= 'A' && std::toupper(static_cast(*first)) <= 'Z' && *(first + 1) == ':' && *(first + 2) == '/') { - _root = _first + 2; - } - else -#endif - { - if (_first != _last && *_first == '/') { - if (_last - _first >= 2 && *(_first + 1) == '/' && !(_last - _first >= 3 && *(_first + 2) == '/')) { - _root = increment(_first); - } - else { - _root = _first; - } - } - else { - _root = _last; - } - } -} - -GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const -{ - path::impl_string_type::const_iterator i = pos; - bool fromStart = i == _first; - if (i != _last) { - // we can only sit on a slash if it is a network name or a root - if (*i++ == '/') { - if (i != _last && *i == '/') { - if (fromStart && !(i + 1 != _last && *(i + 1) == '/')) { - // leadind double slashes detected, treat this and the - // following until a slash as one unit - i = std::find(++i, _last, '/'); - } - else { - // skip redundant slashes - while (i != _last && *i == '/') { - ++i; - } - } - } - } - else { - if (fromStart && i != _last && *i == ':') { - ++i; - } - else { - i = std::find(i, _last, '/'); - } - } - } - return i; -} - -GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const -{ - path::impl_string_type::const_iterator i = pos; - if (i != _first) { - --i; - // if this is now the root slash or the trailing slash, we are done, - // else check for network name - if (i != _root && (pos != _last || *i != '/')) { -#ifdef GHC_OS_WINDOWS - static const std::string seps = "/:"; - i = std::find_first_of(std::reverse_iterator(i), std::reverse_iterator(_first), seps.begin(), seps.end()).base(); - if (i > _first && *i == ':') { - i++; - } -#else - i = std::find(std::reverse_iterator(i), std::reverse_iterator(_first), '/').base(); -#endif - // Now we have to check if this is a network name - if (i - _first == 2 && *_first == '/' && *(_first + 1) == '/') { - i -= 2; - } - } - } - return i; -} - -GHC_INLINE void path::iterator::updateCurrent() -{ - if (_iter != _first && _iter != _last && (*_iter == '/' && _iter != _root) && (_iter + 1 == _last)) { - _current = ""; - } - else { - _current.assign(_iter, increment(_iter)); - if (_current.generic_string().size() > 1 && _current.generic_string()[0] == '/' && _current.generic_string()[_current.generic_string().size() - 1] == '/') { - // shrink successive slashes to one - _current = "/"; - } - } -} - -GHC_INLINE path::iterator& path::iterator::operator++() -{ - _iter = increment(_iter); - while (_iter != _last && // we didn't reach the end - _iter != _root && // this is not a root position - *_iter == '/' && // we are on a slash - (_iter + 1) != _last // the slash is not the last char - ) { - ++_iter; - } - updateCurrent(); - return *this; -} - -GHC_INLINE path::iterator path::iterator::operator++(int) -{ - path::iterator i{*this}; - ++(*this); - return i; -} - -GHC_INLINE path::iterator& path::iterator::operator--() -{ - _iter = decrement(_iter); - updateCurrent(); - return *this; -} - -GHC_INLINE path::iterator path::iterator::operator--(int) -{ - auto i = *this; - --(*this); - return i; -} - -GHC_INLINE bool path::iterator::operator==(const path::iterator& other) const -{ - return _iter == other._iter; -} - -GHC_INLINE bool path::iterator::operator!=(const path::iterator& other) const -{ - return _iter != other._iter; -} - -GHC_INLINE path::iterator::reference path::iterator::operator*() const -{ - return _current; -} - -GHC_INLINE path::iterator::pointer path::iterator::operator->() const -{ - return &_current; -} - -GHC_INLINE path::iterator path::begin() const -{ - return iterator(_path.begin(), _path.end(), _path.begin()); -} - -GHC_INLINE path::iterator path::end() const -{ - return iterator(_path.begin(), _path.end(), _path.end()); -} - -//----------------------------------------------------------------------------- -// 30.10.8.6, path non-member functions -GHC_INLINE void swap(path& lhs, path& rhs) noexcept -{ - swap(lhs._path, rhs._path); -} - -GHC_INLINE size_t hash_value(const path& p) noexcept -{ - return std::hash()(p.generic_string()); -} - -GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept -{ - return lhs.generic_string() == rhs.generic_string(); -} - -GHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept -{ - return lhs.generic_string() != rhs.generic_string(); -} - -GHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept -{ - return lhs.generic_string() < rhs.generic_string(); -} - -GHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept -{ - return lhs.generic_string() <= rhs.generic_string(); -} - -GHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept -{ - return lhs.generic_string() > rhs.generic_string(); -} - -GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept -{ - return lhs.generic_string() >= rhs.generic_string(); -} - -GHC_INLINE path operator/(const path& lhs, const path& rhs) -{ - path result(lhs); - result /= rhs; - return result; -} - -#endif // GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// 30.10.8.6.1 path inserter and extractor -template -inline std::basic_ostream& operator<<(std::basic_ostream& os, const path& p) -{ - os << "\""; - auto ps = p.string(); - for (auto c : ps) { - if (c == '"' || c == '\\') { - os << '\\'; - } - os << c; - } - os << "\""; - return os; -} - -template -inline std::basic_istream& operator>>(std::basic_istream& is, path& p) -{ - std::basic_string tmp; - auto c = is.get(); - if (c == '"') { - auto sf = is.flags(); - is >> std::noskipws; - while (is) { - c = is.get(); - if (is) { - if (c == '\\') { - c = is.get(); - if (is) { - tmp += static_cast(c); - } - } - else if (c == '"') { - break; - } - else { - tmp += static_cast(c); - } - } - } - if ((sf & std::ios_base::skipws) == std::ios_base::skipws) { - is >> std::skipws; - } - p = path(tmp); - } - else { - is >> tmp; - p = path(static_cast(c) + tmp); - } - return is; -} - -#ifdef GHC_EXPAND_IMPL - -//----------------------------------------------------------------------------- -// 30.10.9 Class filesystem_error -GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, std::error_code ec) - : std::system_error(ec, what_arg) - , _what_arg(what_arg) - , _ec(ec) -{ -} - -GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec) - : std::system_error(ec, what_arg) - , _what_arg(what_arg) - , _ec(ec) - , _p1(p1) -{ - if (!_p1.empty()) { - _what_arg += ": '" + _p1.u8string() + "'"; - } -} - -GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec) - : std::system_error(ec, what_arg) - , _what_arg(what_arg) - , _ec(ec) - , _p1(p1) - , _p2(p2) -{ - if (!_p1.empty()) { - _what_arg += ": '" + _p1.u8string() + "'"; - } - if (!_p2.empty()) { - _what_arg += ", '" + _p2.u8string() + "'"; - } -} - -GHC_INLINE const path& filesystem_error::path1() const noexcept -{ - return _p1; -} - -GHC_INLINE const path& filesystem_error::path2() const noexcept -{ - return _p2; -} - -GHC_INLINE const char* filesystem_error::what() const noexcept -{ - return _what_arg.c_str(); -} - -//----------------------------------------------------------------------------- -// 30.10.15, filesystem operations -GHC_INLINE path absolute(const path& p) -{ - std::error_code ec; - path result = absolute(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE path absolute(const path& p, std::error_code& ec) -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - if (p.empty()) { - return absolute(current_path(ec), ec) / ""; - } - ULONG size = ::GetFullPathNameW(p.wstring().c_str(), 0, 0, 0); - if (size) { - std::vector buf(size, 0); - ULONG s2 = GetFullPathNameW(p.wstring().c_str(), size, buf.data(), nullptr); - if (s2 && s2 < size) { - path result = path(std::wstring(buf.data(), s2)); - if (p.filename() == ".") { - result /= "."; - } - return result; - } - } - ec = detail::make_system_error(); - return path(); -#else - path base = current_path(ec); - if (!ec) { - if (p.empty()) { - return base / p; - } - if (p.has_root_name()) { - if (p.has_root_directory()) { - return p; - } - else { - return p.root_name() / base.root_directory() / base.relative_path() / p.relative_path(); - } - } - else { - if (p.has_root_directory()) { - return base.root_name() / p; - } - else { - return base / p; - } - } - } - ec = detail::make_system_error(); - return path(); -#endif -} - -GHC_INLINE path canonical(const path& p) -{ - std::error_code ec; - auto result = canonical(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE path canonical(const path& p, std::error_code& ec) -{ - if (p.empty()) { - ec = detail::make_error_code(detail::portable_error::not_found); - return path(); - } - path work = p.is_absolute() ? p : absolute(p, ec); - path root = work.root_path(); - path result; - - auto fs = status(work, ec); - if (ec) { - return path(); - } - if (fs.type() == file_type::not_found) { - ec = detail::make_error_code(detail::portable_error::not_found); - return path(); - } - bool redo; - do { - redo = false; - result.clear(); - for (auto pe : work) { - if (pe.empty() || pe == ".") { - continue; - } - else if (pe == "..") { - result = result.parent_path(); - continue; - } - else if ((result / pe).string().length() <= root.string().length()) { - result /= pe; - continue; - } - auto sls = symlink_status(result / pe, ec); - if (ec) { - return path(); - } - if (is_symlink(sls)) { - redo = true; - auto target = read_symlink(result / pe, ec); - if (ec) { - return path(); - } - if (target.is_absolute()) { - result = target; - continue; - } - else { - result /= target; - continue; - } - } - else { - result /= pe; - } - } - work = result; - } while (redo); - ec.clear(); - return result; -} - -GHC_INLINE void copy(const path& from, const path& to) -{ - copy(from, to, copy_options::none); -} - -GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept -{ - copy(from, to, copy_options::none, ec); -} - -GHC_INLINE void copy(const path& from, const path& to, copy_options options) -{ - std::error_code ec; - copy(from, to, options, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); - } -} - -GHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept -{ - std::error_code tec; - file_status fs_from, fs_to; - ec.clear(); - if ((options & (copy_options::skip_symlinks | copy_options::copy_symlinks | copy_options::create_symlinks)) != copy_options::none) { - fs_from = symlink_status(from, ec); - } - else { - fs_from = status(from, ec); - } - if (!exists(fs_from)) { - if (!ec) { - ec = detail::make_error_code(detail::portable_error::not_found); - } - return; - } - if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) { - fs_to = symlink_status(to, tec); - } - else { - fs_to = status(to, tec); - } - if (is_other(fs_from) || is_other(fs_to) || (is_directory(fs_from) && is_regular_file(fs_to)) || (exists(fs_to) && equivalent(from, to, ec))) { - ec = detail::make_error_code(detail::portable_error::invalid_argument); - } - else if (is_symlink(fs_from)) { - if ((options & copy_options::skip_symlinks) == copy_options::none) { - if (!exists(fs_to) && (options & copy_options::copy_symlinks) != copy_options::none) { - copy_symlink(from, to, ec); - } - else { - ec = detail::make_error_code(detail::portable_error::invalid_argument); - } - } - } - else if (is_regular_file(fs_from)) { - if ((options & copy_options::directories_only) == copy_options::none) { - if ((options & copy_options::create_symlinks) != copy_options::none) { - create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec); - } - else if ((options & copy_options::create_hard_links) != copy_options::none) { - create_hard_link(from, to, ec); - } - else if (is_directory(fs_to)) { - copy_file(from, to / from.filename(), options, ec); - } - else { - copy_file(from, to, options, ec); - } - } - } -#ifdef LWG_2682_BEHAVIOUR - else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) { - ec = detail::make_error_code(detail::portable_error::is_a_directory); - } -#endif - else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) != copy_options::none)) { - if (!exists(fs_to)) { - create_directory(to, from, ec); - if (ec) { - return; - } - } - for (auto iter = directory_iterator(from, ec); iter != directory_iterator(); iter.increment(ec)) { - if (!ec) { - copy(iter->path(), to / iter->path().filename(), options | static_cast(0x8000), ec); - } - if (ec) { - return; - } - } - } - return; -} - -GHC_INLINE bool copy_file(const path& from, const path& to) -{ - return copy_file(from, to, copy_options::none); -} - -GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept -{ - return copy_file(from, to, copy_options::none, ec); -} - -GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option) -{ - std::error_code ec; - auto result = copy_file(from, to, option, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); - } - return result; -} - -GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept -{ - std::error_code tecf, tect; - auto sf = status(from, tecf); - auto st = status(to, tect); - bool overwrite = false; - ec.clear(); - if (!is_regular_file(sf)) { - ec = tecf; - return false; - } - if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) { - ec = tect ? tect : detail::make_error_code(detail::portable_error::exists); - return false; - } - if (exists(st)) { - if ((options & copy_options::update_existing) == copy_options::update_existing) { - auto from_time = last_write_time(from, ec); - if (ec) { - ec = detail::make_system_error(); - return false; - } - auto to_time = last_write_time(to, ec); - if (ec) { - ec = detail::make_system_error(); - return false; - } - if (from_time <= to_time) { - return false; - } - } - overwrite = true; - } -#ifdef GHC_OS_WINDOWS - if (!::CopyFileW(detail::fromUtf8(from.u8string()).c_str(), detail::fromUtf8(to.u8string()).c_str(), !overwrite)) { - ec = detail::make_system_error(); - return false; - } - return true; -#else - std::vector buffer(16384, '\0'); - int in = -1, out = -1; - if ((in = ::open(from.c_str(), O_RDONLY)) < 0) { - ec = detail::make_system_error(); - return false; - } - std::shared_ptr guard_in(nullptr, [in](void*) { ::close(in); }); - int mode = O_CREAT | O_WRONLY | O_TRUNC; - if (!overwrite) { - mode |= O_EXCL; - } - if ((out = ::open(to.c_str(), mode, static_cast(sf.permissions() & perms::all))) < 0) { - ec = detail::make_system_error(); - return false; - } - std::shared_ptr guard_out(nullptr, [out](void*) { ::close(out); }); - ssize_t br, bw; - while ((br = ::read(in, buffer.data(), buffer.size())) > 0) { - ssize_t offset = 0; - do { - if ((bw = ::write(out, buffer.data() + offset, static_cast(br))) > 0) { - br -= bw; - offset += bw; - } - else if (bw < 0) { - ec = detail::make_system_error(); - return false; - } - } while (br); - } - return true; -#endif -} - -GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink) -{ - std::error_code ec; - copy_symlink(existing_symlink, new_symlink, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), existing_symlink, new_symlink, ec); - } -} - -GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept -{ - ec.clear(); - auto to = read_symlink(existing_symlink, ec); - if (!ec) { - if (exists(to, ec) && is_directory(to, ec)) { - create_directory_symlink(to, new_symlink, ec); - } - else { - create_symlink(to, new_symlink, ec); - } - } -} - -GHC_INLINE bool create_directories(const path& p) -{ - std::error_code ec; - auto result = create_directories(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept -{ - path current; - ec.clear(); - for (path::string_type part : p) { - current /= part; - if (current != p.root_name() && current != p.root_path()) { - std::error_code tec; - auto fs = status(current, tec); - if (tec && fs.type() != file_type::not_found) { - ec = tec; - return false; - } - if (!exists(fs)) { - create_directory(current, ec); - if (ec) { - std::error_code tmp_ec; - if (is_directory(current, tmp_ec)) { - ec.clear(); - } else { - return false; - } - } - } -#ifndef LWG_2935_BEHAVIOUR - else if (!is_directory(fs)) { - ec = detail::make_error_code(detail::portable_error::exists); - return false; - } -#endif - } - } - return true; -} - -GHC_INLINE bool create_directory(const path& p) -{ - std::error_code ec; - auto result = create_directory(p, path(), ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE bool create_directory(const path& p, std::error_code& ec) noexcept -{ - return create_directory(p, path(), ec); -} - -GHC_INLINE bool create_directory(const path& p, const path& attributes) -{ - std::error_code ec; - auto result = create_directory(p, attributes, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept -{ - std::error_code tec; - ec.clear(); - auto fs = status(p, tec); -#ifdef LWG_2935_BEHAVIOUR - if (status_known(fs) && exists(fs)) { - return false; - } -#else - if (status_known(fs) && exists(fs) && is_directory(fs)) { - return false; - } -#endif -#ifdef GHC_OS_WINDOWS - if (!attributes.empty()) { - if (!::CreateDirectoryExW(detail::fromUtf8(attributes.u8string()).c_str(), detail::fromUtf8(p.u8string()).c_str(), NULL)) { - ec = detail::make_system_error(); - return false; - } - } - else if (!::CreateDirectoryW(detail::fromUtf8(p.u8string()).c_str(), NULL)) { - ec = detail::make_system_error(); - return false; - } -#else - ::mode_t attribs = static_cast(perms::all); - if (!attributes.empty()) { - struct ::stat fileStat; - if (::stat(attributes.c_str(), &fileStat) != 0) { - ec = detail::make_system_error(); - return false; - } - attribs = fileStat.st_mode; - } - if (::mkdir(p.c_str(), attribs) != 0) { - ec = detail::make_system_error(); - return false; - } -#endif - return true; -} - -GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink) -{ - std::error_code ec; - create_directory_symlink(to, new_symlink, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); - } -} - -GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept -{ - detail::create_symlink(to, new_symlink, true, ec); -} - -GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link) -{ - std::error_code ec; - create_hard_link(to, new_hard_link, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), to, new_hard_link, ec); - } -} - -GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept -{ - detail::create_hardlink(to, new_hard_link, ec); -} - -GHC_INLINE void create_symlink(const path& to, const path& new_symlink) -{ - std::error_code ec; - create_symlink(to, new_symlink, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); - } -} - -GHC_INLINE void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept -{ - detail::create_symlink(to, new_symlink, false, ec); -} - -GHC_INLINE path current_path() -{ - std::error_code ec; - auto result = current_path(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), ec); - } - return result; -} - -GHC_INLINE path current_path(std::error_code& ec) -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - DWORD pathlen = ::GetCurrentDirectoryW(0, 0); - std::unique_ptr buffer(new wchar_t[size_t(pathlen) + 1]); - if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) { - ec = detail::make_system_error(); - return path(); - } - return path(std::wstring(buffer.get()), path::native_format); -#else - size_t pathlen = static_cast(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX))); - std::unique_ptr buffer(new char[pathlen + 1]); - if (::getcwd(buffer.get(), pathlen) == nullptr) { - ec = detail::make_system_error(); - return path(); - } - return path(buffer.get()); -#endif -} - -GHC_INLINE void current_path(const path& p) -{ - std::error_code ec; - current_path(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } -} - -GHC_INLINE void current_path(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - if (!::SetCurrentDirectoryW(detail::fromUtf8(p.u8string()).c_str())) { - ec = detail::make_system_error(); - } -#else - if (::chdir(p.string().c_str()) == -1) { - ec = detail::make_system_error(); - } -#endif -} - -GHC_INLINE bool exists(file_status s) noexcept -{ - return status_known(s) && s.type() != file_type::not_found; -} - -GHC_INLINE bool exists(const path& p) -{ - return exists(status(p)); -} - -GHC_INLINE bool exists(const path& p, std::error_code& ec) noexcept -{ - file_status s = status(p, ec); - if (status_known(s)) { - ec.clear(); - } - return exists(s); -} - -GHC_INLINE bool equivalent(const path& p1, const path& p2) -{ - std::error_code ec; - bool result = equivalent(p1, p2, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec); - } - return result; -} - -GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - std::shared_ptr file1(::CreateFileW(p1.wstring().c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); - auto e1 = ::GetLastError(); - std::shared_ptr file2(::CreateFileW(p2.wstring().c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); - if (file1.get() == INVALID_HANDLE_VALUE || file2.get() == INVALID_HANDLE_VALUE) { -#ifdef LWG_2937_BEHAVIOUR - ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); -#else - if (file1 == file2) { - ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); - } -#endif - return false; - } - BY_HANDLE_FILE_INFORMATION inf1, inf2; - if (!::GetFileInformationByHandle(file1.get(), &inf1)) { - ec = detail::make_system_error(); - return false; - } - if (!::GetFileInformationByHandle(file2.get(), &inf2)) { - ec = detail::make_system_error(); - return false; - } - return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow && - inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber; -#else - struct ::stat s1, s2; - auto rc1 = ::stat(p1.c_str(), &s1); - auto e1 = errno; - auto rc2 = ::stat(p2.c_str(), &s2); - if (rc1 || rc2) { -#ifdef LWG_2937_BEHAVIOUR - ec = detail::make_system_error(e1 ? e1 : errno); -#else - if (rc1 && rc2) { - ec = detail::make_system_error(e1 ? e1 : errno); - } -#endif - return false; - } - return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; -#endif -} - -GHC_INLINE uintmax_t file_size(const path& p) -{ - std::error_code ec; - auto result = file_size(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - WIN32_FILE_ATTRIBUTE_DATA attr; - if (!GetFileAttributesExW(detail::fromUtf8(p.u8string()).c_str(), GetFileExInfoStandard, &attr)) { - ec = detail::make_system_error(); - return static_cast(-1); - } - return static_cast(attr.nFileSizeHigh) << (sizeof(attr.nFileSizeHigh) * 8) | attr.nFileSizeLow; -#else - struct ::stat fileStat; - if (::stat(p.c_str(), &fileStat) == -1) { - ec = detail::make_system_error(); - return static_cast(-1); - } - return static_cast(fileStat.st_size); -#endif -} - -GHC_INLINE uintmax_t hard_link_count(const path& p) -{ - std::error_code ec; - auto result = hard_link_count(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - uintmax_t result = static_cast(-1); - std::shared_ptr file(::CreateFileW(p.wstring().c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); - BY_HANDLE_FILE_INFORMATION inf; - if (file.get() == INVALID_HANDLE_VALUE) { - ec = detail::make_system_error(); - } - else { - if (!::GetFileInformationByHandle(file.get(), &inf)) { - ec = detail::make_system_error(); - } - else { - result = inf.nNumberOfLinks; - } - } - return result; -#else - uintmax_t result = 0; - file_status fs = detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr); - if (fs.type() == file_type::not_found) { - ec = detail::make_error_code(detail::portable_error::not_found); - } - return ec ? static_cast(-1) : result; -#endif -} - -GHC_INLINE bool is_block_file(file_status s) noexcept -{ - return s.type() == file_type::block; -} - -GHC_INLINE bool is_block_file(const path& p) -{ - return is_block_file(status(p)); -} - -GHC_INLINE bool is_block_file(const path& p, std::error_code& ec) noexcept -{ - return is_block_file(status(p, ec)); -} - -GHC_INLINE bool is_character_file(file_status s) noexcept -{ - return s.type() == file_type::character; -} - -GHC_INLINE bool is_character_file(const path& p) -{ - return is_character_file(status(p)); -} - -GHC_INLINE bool is_character_file(const path& p, std::error_code& ec) noexcept -{ - return is_character_file(status(p, ec)); -} - -GHC_INLINE bool is_directory(file_status s) noexcept -{ - return s.type() == file_type::directory; -} - -GHC_INLINE bool is_directory(const path& p) -{ - return is_directory(status(p)); -} - -GHC_INLINE bool is_directory(const path& p, std::error_code& ec) noexcept -{ - return is_directory(status(p, ec)); -} - -GHC_INLINE bool is_empty(const path& p) -{ - if (is_directory(p)) { - return directory_iterator(p) == directory_iterator(); - } - else { - return file_size(p) == 0; - } -} - -GHC_INLINE bool is_empty(const path& p, std::error_code& ec) noexcept -{ - auto fs = status(p, ec); - if (ec) { - return false; - } - if (is_directory(fs)) { - directory_iterator iter(p, ec); - if (ec) { - return false; - } - return iter == directory_iterator(); - } - else { - auto sz = file_size(p, ec); - if (ec) { - return false; - } - return sz == 0; - } -} - -GHC_INLINE bool is_fifo(file_status s) noexcept -{ - return s.type() == file_type::fifo; -} - -GHC_INLINE bool is_fifo(const path& p) -{ - return is_fifo(status(p)); -} - -GHC_INLINE bool is_fifo(const path& p, std::error_code& ec) noexcept -{ - return is_fifo(status(p, ec)); -} - -GHC_INLINE bool is_other(file_status s) noexcept -{ - return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s); -} - -GHC_INLINE bool is_other(const path& p) -{ - return is_other(status(p)); -} - -GHC_INLINE bool is_other(const path& p, std::error_code& ec) noexcept -{ - return is_other(status(p, ec)); -} - -GHC_INLINE bool is_regular_file(file_status s) noexcept -{ - return s.type() == file_type::regular; -} - -GHC_INLINE bool is_regular_file(const path& p) -{ - return is_regular_file(status(p)); -} - -GHC_INLINE bool is_regular_file(const path& p, std::error_code& ec) noexcept -{ - return is_regular_file(status(p, ec)); -} - -GHC_INLINE bool is_socket(file_status s) noexcept -{ - return s.type() == file_type::socket; -} - -GHC_INLINE bool is_socket(const path& p) -{ - return is_socket(status(p)); -} - -GHC_INLINE bool is_socket(const path& p, std::error_code& ec) noexcept -{ - return is_socket(status(p, ec)); -} - -GHC_INLINE bool is_symlink(file_status s) noexcept -{ - return s.type() == file_type::symlink; -} - -GHC_INLINE bool is_symlink(const path& p) -{ - return is_symlink(symlink_status(p)); -} - -GHC_INLINE bool is_symlink(const path& p, std::error_code& ec) noexcept -{ - return is_symlink(symlink_status(p, ec)); -} - -GHC_INLINE file_time_type last_write_time(const path& p) -{ - std::error_code ec; - auto result = last_write_time(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept -{ - time_t result = 0; - ec.clear(); - file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result); - return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result); -} - -GHC_INLINE void last_write_time(const path& p, file_time_type new_time) -{ - std::error_code ec; - last_write_time(p, new_time, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } -} - -GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept -{ - ec.clear(); - auto d = new_time.time_since_epoch(); -#ifdef GHC_OS_WINDOWS - std::shared_ptr file(::CreateFileW(p.wstring().c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL), ::CloseHandle); - FILETIME ft; - auto tt = std::chrono::duration_cast(d).count() * 10 + 116444736000000000; - ft.dwLowDateTime = static_cast(tt); - ft.dwHighDateTime = static_cast(tt >> 32); - if (!::SetFileTime(file.get(), 0, 0, &ft)) { - ec = detail::make_system_error(); - } -#elif defined(GHC_OS_MACOS) -#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED -#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 - struct ::stat fs; - if (::stat(p.c_str(), &fs) == 0) { - struct ::timeval tv[2]; - tv[0].tv_sec = fs.st_atimespec.tv_sec; - tv[0].tv_usec = static_cast(fs.st_atimespec.tv_nsec / 1000); - tv[1].tv_sec = std::chrono::duration_cast(d).count(); - tv[1].tv_usec = static_cast(std::chrono::duration_cast(d).count() % 1000000); - if (::utimes(p.c_str(), tv) == 0) { - return; - } - } - ec = detail::make_system_error(); - return; -#else - struct ::timespec times[2]; - times[0].tv_sec = 0; - times[0].tv_nsec = UTIME_OMIT; - times[1].tv_sec = std::chrono::duration_cast(d).count(); - times[1].tv_nsec = std::chrono::duration_cast(d).count() % 1000000000; - if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { - ec = detail::make_system_error(); - } - return; -#endif -#endif -#else - struct ::timespec times[2]; - times[0].tv_sec = 0; - times[0].tv_nsec = UTIME_OMIT; - times[1].tv_sec = std::chrono::duration_cast(d).count(); - times[1].tv_nsec = std::chrono::duration_cast(d).count() % 1000000000; - if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { - ec = detail::make_system_error(); - } - return; -#endif -} - -GHC_INLINE void permissions(const path& p, perms prms, perm_options opts) -{ - std::error_code ec; - permissions(p, prms, opts, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } -} - -GHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noexcept -{ - permissions(p, prms, perm_options::replace, ec); -} - -GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) -{ - if (static_cast(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) { - ec = detail::make_error_code(detail::portable_error::invalid_argument); - return; - } - auto fs = symlink_status(p, ec); - if ((opts & perm_options::replace) != perm_options::replace) { - if ((opts & perm_options::add) == perm_options::add) { - prms = fs.permissions() | prms; - } - else { - prms = fs.permissions() & ~prms; - } - } -#ifdef GHC_OS_WINDOWS -#ifdef __GNUC__ - auto oldAttr = GetFileAttributesW(p.wstring().c_str()); - if (oldAttr != INVALID_FILE_ATTRIBUTES) { - DWORD newAttr = ((prms & perms::owner_write) == perms::owner_write) ? oldAttr & ~(static_cast(FILE_ATTRIBUTE_READONLY)) : oldAttr | FILE_ATTRIBUTE_READONLY; - if (oldAttr == newAttr || SetFileAttributesW(p.wstring().c_str(), newAttr)) { - return; - } - } - ec = detail::make_system_error(); -#else - int mode = 0; - if ((prms & perms::owner_read) == perms::owner_read) { - mode |= _S_IREAD; - } - if ((prms & perms::owner_write) == perms::owner_write) { - mode |= _S_IWRITE; - } - if (::_wchmod(p.wstring().c_str(), mode) != 0) { - ec = detail::make_system_error(); - } -#endif -#else - if ((opts & perm_options::nofollow) != perm_options::nofollow) { - if (::chmod(p.c_str(), static_cast(prms)) != 0) { - ec = detail::make_system_error(); - } - } -#endif -} - -GHC_INLINE path proximate(const path& p, std::error_code& ec) -{ - return proximate(p, current_path(), ec); -} - -GHC_INLINE path proximate(const path& p, const path& base) -{ - return weakly_canonical(p).lexically_proximate(weakly_canonical(base)); -} - -GHC_INLINE path proximate(const path& p, const path& base, std::error_code& ec) -{ - return weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec)); -} - -GHC_INLINE path read_symlink(const path& p) -{ - std::error_code ec; - auto result = read_symlink(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE path read_symlink(const path& p, std::error_code& ec) -{ - file_status fs = symlink_status(p, ec); - if (fs.type() != file_type::symlink) { - ec = detail::make_error_code(detail::portable_error::invalid_argument); - return path(); - } - auto result = detail::resolveSymlink(p, ec); - return ec ? path() : result; -} - -GHC_INLINE path relative(const path& p, std::error_code& ec) -{ - return relative(p, current_path(ec), ec); -} - -GHC_INLINE path relative(const path& p, const path& base) -{ - return weakly_canonical(p).lexically_relative(weakly_canonical(base)); -} - -GHC_INLINE path relative(const path& p, const path& base, std::error_code& ec) -{ - return weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec)); -} - -GHC_INLINE bool remove(const path& p) -{ - std::error_code ec; - auto result = remove(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - std::wstring np = detail::fromUtf8(p.u8string()); - DWORD attr = GetFileAttributesW(np.c_str()); - if (attr == INVALID_FILE_ATTRIBUTES) { - auto error = ::GetLastError(); - if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) { - return false; - } - ec = detail::make_system_error(error); - } - if (!ec) { - if (attr & FILE_ATTRIBUTE_DIRECTORY) { - if (!RemoveDirectoryW(np.c_str())) { - ec = detail::make_system_error(); - } - } - else { - if (!DeleteFileW(np.c_str())) { - ec = detail::make_system_error(); - } - } - } -#else - if (::remove(p.c_str()) == -1) { - auto error = errno; - if (error == ENOENT) { - return false; - } - ec = detail::make_system_error(); - } -#endif - return ec ? false : true; -} - -GHC_INLINE uintmax_t remove_all(const path& p) -{ - std::error_code ec; - auto result = remove_all(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); - uintmax_t count = 0; - if (p == "/") { - ec = detail::make_error_code(detail::portable_error::not_supported); - return static_cast(-1); - } - std::error_code tec; - auto fs = status(p, tec); - if (exists(fs) && is_directory(fs)) { - for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) { - if (ec) { - break; - } - if (!iter->is_symlink() && iter->is_directory()) { - count += remove_all(iter->path(), ec); - if (ec) { - return static_cast(-1); - } - } - else { - remove(iter->path(), ec); - if (ec) { - return static_cast(-1); - } - ++count; - } - } - } - if (!ec) { - if (remove(p, ec)) { - ++count; - } - } - if (ec) { - return static_cast(-1); - } - return count; -} - -GHC_INLINE void rename(const path& from, const path& to) -{ - std::error_code ec; - rename(from, to, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); - } -} - -GHC_INLINE void rename(const path& from, const path& to, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - if (from != to) { - if (!MoveFileExW(detail::fromUtf8(from.u8string()).c_str(), detail::fromUtf8(to.u8string()).c_str(), (DWORD)MOVEFILE_REPLACE_EXISTING)) { - ec = detail::make_system_error(); - } - } -#else - if (from != to) { - if (::rename(from.c_str(), to.c_str()) != 0) { - ec = detail::make_system_error(); - } - } -#endif -} - -GHC_INLINE void resize_file(const path& p, uintmax_t size) -{ - std::error_code ec; - resize_file(p, size, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } -} - -GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - LARGE_INTEGER lisize; - lisize.QuadPart = static_cast(size); - if(lisize.QuadPart < 0) { - ec = detail::make_system_error(ERROR_FILE_TOO_LARGE); - return; - } - std::shared_ptr file(CreateFileW(detail::fromUtf8(p.u8string()).c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), CloseHandle); - if (file.get() == INVALID_HANDLE_VALUE) { - ec = detail::make_system_error(); - } - else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) { - ec = detail::make_system_error(); - } -#else - if (::truncate(p.c_str(), static_cast(size)) != 0) { - ec = detail::make_system_error(); - } -#endif -} - -GHC_INLINE space_info space(const path& p) -{ - std::error_code ec; - auto result = space(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - ULARGE_INTEGER freeBytesAvailableToCaller = {0, 0}; - ULARGE_INTEGER totalNumberOfBytes = {0, 0}; - ULARGE_INTEGER totalNumberOfFreeBytes = {0, 0}; - if (!GetDiskFreeSpaceExW(detail::fromUtf8(p.u8string()).c_str(), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { - ec = detail::make_system_error(); - return {static_cast(-1), static_cast(-1), static_cast(-1)}; - } - return {static_cast(totalNumberOfBytes.QuadPart), static_cast(totalNumberOfFreeBytes.QuadPart), static_cast(freeBytesAvailableToCaller.QuadPart)}; -#elif !defined(__ANDROID__) || __ANDROID_API__ >= 19 - struct ::statvfs sfs; - if (::statvfs(p.c_str(), &sfs) != 0) { - ec = detail::make_system_error(); - return {static_cast(-1), static_cast(-1), static_cast(-1)}; - } - return {static_cast(sfs.f_blocks * sfs.f_frsize), static_cast(sfs.f_bfree * sfs.f_frsize), static_cast(sfs.f_bavail * sfs.f_frsize)}; -#else - (void)p; - ec = detail::make_error_code(detail::portable_error::not_supported); - return {static_cast(-1), static_cast(-1), static_cast(-1)}; -#endif -} - -GHC_INLINE file_status status(const path& p) -{ - std::error_code ec; - auto result = status(p, ec); - if (result.type() == file_type::none) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE file_status status(const path& p, std::error_code& ec) noexcept -{ - return detail::status_ex(p, ec); -} - -GHC_INLINE bool status_known(file_status s) noexcept -{ - return s.type() != file_type::none; -} - -GHC_INLINE file_status symlink_status(const path& p) -{ - std::error_code ec; - auto result = symlink_status(p, ec); - if (result.type() == file_type::none) { - throw filesystem_error(detail::systemErrorText(ec.value()), ec); - } - return result; -} - -GHC_INLINE file_status symlink_status(const path& p, std::error_code& ec) noexcept -{ - return detail::symlink_status_ex(p, ec); -} - -GHC_INLINE path temp_directory_path() -{ - std::error_code ec; - path result = temp_directory_path(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), ec); - } - return result; -} - -GHC_INLINE path temp_directory_path(std::error_code& ec) noexcept -{ - ec.clear(); -#ifdef GHC_OS_WINDOWS - wchar_t buffer[512]; - auto rc = GetTempPathW(511, buffer); - if (!rc || rc > 511) { - ec = detail::make_system_error(); - return path(); - } - return path(std::wstring(buffer)); -#else - static const char* temp_vars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr}; - const char* temp_path = nullptr; - for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) { - temp_path = std::getenv(*temp_name); - if (temp_path) { - return path(temp_path); - } - } - return path("/tmp"); -#endif -} - -GHC_INLINE path weakly_canonical(const path& p) -{ - std::error_code ec; - auto result = weakly_canonical(p, ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); - } - return result; -} - -GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept -{ - path result; - ec.clear(); - bool scan = true; - for (auto pe : p) { - if (scan) { - std::error_code tec; - if (exists(result / pe, tec)) { - result /= pe; - } - else { - if (ec) { - return path(); - } - scan = false; - if (!result.empty()) { - result = canonical(result, ec) / pe; - if (ec) { - break; - } - } - else { - result /= pe; - } - } - } - else { - result /= pe; - } - } - if (scan) { - if (!result.empty()) { - result = canonical(result, ec); - } - } - return ec ? path() : result.lexically_normal(); -} - -//----------------------------------------------------------------------------- -// 30.10.11 class file_status -// 30.10.11.1 constructors and destructor -GHC_INLINE file_status::file_status() noexcept - : file_status(file_type::none) -{ -} - -GHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept - : _type(ft) - , _perms(prms) -{ -} - -GHC_INLINE file_status::file_status(const file_status& other) noexcept - : _type(other._type) - , _perms(other._perms) -{ -} - -GHC_INLINE file_status::file_status(file_status&& other) noexcept - : _type(other._type) - , _perms(other._perms) -{ -} - -GHC_INLINE file_status::~file_status() {} - -// assignments: -GHC_INLINE file_status& file_status::operator=(const file_status& rhs) noexcept -{ - _type = rhs._type; - _perms = rhs._perms; - return *this; -} - -GHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept -{ - _type = rhs._type; - _perms = rhs._perms; - return *this; -} - -// 30.10.11.3 modifiers -GHC_INLINE void file_status::type(file_type ft) noexcept -{ - _type = ft; -} - -GHC_INLINE void file_status::permissions(perms prms) noexcept -{ - _perms = prms; -} - -// 30.10.11.2 observers -GHC_INLINE file_type file_status::type() const noexcept -{ - return _type; -} - -GHC_INLINE perms file_status::permissions() const noexcept -{ - return _perms; -} - -//----------------------------------------------------------------------------- -// 30.10.12 class directory_entry -// 30.10.12.1 constructors and destructor -// directory_entry::directory_entry() noexcept = default; -// directory_entry::directory_entry(const directory_entry&) = default; -// directory_entry::directory_entry(directory_entry&&) noexcept = default; -GHC_INLINE directory_entry::directory_entry(const filesystem::path& p) - : _path(p) - , _file_size(0) -#ifndef GHC_OS_WINDOWS - , _hard_link_count(0) -#endif - , _last_write_time(0) -{ - refresh(); -} - -GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec) - : _path(p) - , _file_size(0) -#ifndef GHC_OS_WINDOWS - , _hard_link_count(0) -#endif - , _last_write_time(0) -{ - refresh(ec); -} - -GHC_INLINE directory_entry::~directory_entry() {} - -// assignments: -// directory_entry& directory_entry::operator=(const directory_entry&) = default; -// directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default; - -// 30.10.12.2 directory_entry modifiers -GHC_INLINE void directory_entry::assign(const filesystem::path& p) -{ - _path = p; - refresh(); -} - -GHC_INLINE void directory_entry::assign(const filesystem::path& p, std::error_code& ec) -{ - _path = p; - refresh(ec); -} - -GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p) -{ - _path.replace_filename(p); - refresh(); -} - -GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p, std::error_code& ec) -{ - _path.replace_filename(p); - refresh(ec); -} - -GHC_INLINE void directory_entry::refresh() -{ - std::error_code ec; - refresh(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec); - } -} - -GHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept -{ -#ifdef GHC_OS_WINDOWS - _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, nullptr, &_last_write_time); -#else - _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, &_hard_link_count, &_last_write_time); -#endif -} - -// 30.10.12.3 directory_entry observers -GHC_INLINE const filesystem::path& directory_entry::path() const noexcept -{ - return _path; -} - -GHC_INLINE directory_entry::operator const filesystem::path&() const noexcept -{ - return _path; -} - -GHC_INLINE bool directory_entry::exists() const -{ - return filesystem::exists(status()); -} - -GHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept -{ - return filesystem::exists(status(ec)); -} - -GHC_INLINE bool directory_entry::is_block_file() const -{ - return filesystem::is_block_file(status()); -} -GHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept -{ - return filesystem::is_block_file(status(ec)); -} - -GHC_INLINE bool directory_entry::is_character_file() const -{ - return filesystem::is_character_file(status()); -} - -GHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept -{ - return filesystem::is_character_file(status(ec)); -} - -GHC_INLINE bool directory_entry::is_directory() const -{ - return filesystem::is_directory(status()); -} - -GHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept -{ - return filesystem::is_directory(status(ec)); -} - -GHC_INLINE bool directory_entry::is_fifo() const -{ - return filesystem::is_fifo(status()); -} - -GHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept -{ - return filesystem::is_fifo(status(ec)); -} - -GHC_INLINE bool directory_entry::is_other() const -{ - return filesystem::is_other(status()); -} - -GHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept -{ - return filesystem::is_other(status(ec)); -} - -GHC_INLINE bool directory_entry::is_regular_file() const -{ - return filesystem::is_regular_file(status()); -} - -GHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept -{ - return filesystem::is_regular_file(status(ec)); -} - -GHC_INLINE bool directory_entry::is_socket() const -{ - return filesystem::is_socket(status()); -} - -GHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept -{ - return filesystem::is_socket(status(ec)); -} - -GHC_INLINE bool directory_entry::is_symlink() const -{ - return filesystem::is_symlink(symlink_status()); -} - -GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept -{ - return filesystem::is_symlink(symlink_status(ec)); -} - -GHC_INLINE uintmax_t directory_entry::file_size() const -{ - if (_status.type() != file_type::none) { - return _file_size; - } - return filesystem::file_size(path()); -} - -GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept -{ - if (_status.type() != file_type::none) { - return _file_size; - } - return filesystem::file_size(path(), ec); -} - -GHC_INLINE uintmax_t directory_entry::hard_link_count() const -{ -#ifndef GHC_OS_WINDOWS - if (_status.type() != file_type::none) { - return _hard_link_count; - } -#endif - return filesystem::hard_link_count(path()); -} - -GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept -{ -#ifndef GHC_OS_WINDOWS - if (_status.type() != file_type::none) { - return _hard_link_count; - } -#endif - return filesystem::hard_link_count(path(), ec); -} - -GHC_INLINE file_time_type directory_entry::last_write_time() const -{ - if (_status.type() != file_type::none) { - return std::chrono::system_clock::from_time_t(_last_write_time); - } - return filesystem::last_write_time(path()); -} - -GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept -{ - if (_status.type() != file_type::none) { - return std::chrono::system_clock::from_time_t(_last_write_time); - } - return filesystem::last_write_time(path(), ec); -} - -GHC_INLINE file_status directory_entry::status() const -{ - if (_status.type() != file_type::none) { - return _status; - } - return filesystem::status(path()); -} - -GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept -{ - if (_status.type() != file_type::none) { - return _status; - } - return filesystem::status(path(), ec); -} - -GHC_INLINE file_status directory_entry::symlink_status() const -{ - if (_symlink_status.type() != file_type::none) { - return _symlink_status; - } - return filesystem::symlink_status(path()); -} - -GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept -{ - if (_symlink_status.type() != file_type::none) { - return _symlink_status; - } - return filesystem::symlink_status(path(), ec); -} - -GHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept -{ - return _path < rhs._path; -} - -GHC_INLINE bool directory_entry::operator==(const directory_entry& rhs) const noexcept -{ - return _path == rhs._path; -} - -GHC_INLINE bool directory_entry::operator!=(const directory_entry& rhs) const noexcept -{ - return _path != rhs._path; -} - -GHC_INLINE bool directory_entry::operator<=(const directory_entry& rhs) const noexcept -{ - return _path <= rhs._path; -} - -GHC_INLINE bool directory_entry::operator>(const directory_entry& rhs) const noexcept -{ - return _path > rhs._path; -} - -GHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const noexcept -{ - return _path >= rhs._path; -} - -//----------------------------------------------------------------------------- -// 30.10.13 class directory_iterator - -#ifdef GHC_OS_WINDOWS -class directory_iterator::impl -{ -public: - impl(const path& p, directory_options options) - : _base(p) - , _options(options) - , _dirHandle(INVALID_HANDLE_VALUE) - { - if (!_base.empty()) { - ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW)); - if ((_dirHandle = FindFirstFileW(detail::fromUtf8((_base / "*").u8string()).c_str(), &_findData)) != INVALID_HANDLE_VALUE) { - if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") { - increment(_ec); - } - else { - _current = _base / std::wstring(_findData.cFileName); - copyToDirEntry(_ec); - } - } - else { - auto error = ::GetLastError(); - _base = filesystem::path(); - if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) { - _ec = detail::make_system_error(); - } - } - } - } - impl(const impl& other) = delete; - ~impl() - { - if (_dirHandle != INVALID_HANDLE_VALUE) { - FindClose(_dirHandle); - _dirHandle = INVALID_HANDLE_VALUE; - } - } - void increment(std::error_code& ec) - { - if (_dirHandle != INVALID_HANDLE_VALUE) { - do { - if (FindNextFileW(_dirHandle, &_findData)) { - _current = _base; - try { - _current.append_name(detail::toUtf8(_findData.cFileName).c_str()); - } - catch(filesystem_error& fe) { - ec = fe.code(); - return; - } - copyToDirEntry(ec); - } - else { - auto err = ::GetLastError(); - if(err != ERROR_NO_MORE_FILES) { - _ec = ec = detail::make_system_error(err); - } - FindClose(_dirHandle); - _dirHandle = INVALID_HANDLE_VALUE; - _current = filesystem::path(); - break; - } - } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L".."); - } - else { - ec = _ec; - } - } - void copyToDirEntry(std::error_code& ec) - { - _dir_entry._path = _current; - if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - _dir_entry._status = detail::status_ex(_current, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time); - } - else { - _dir_entry._status = detail::status_from_INFO(_current, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time); - _dir_entry._symlink_status = _dir_entry._status; - } - if (ec) { - if (_dir_entry._status.type() != file_type::none && _dir_entry._symlink_status.type() != file_type::none) { - ec.clear(); - } - else { - _dir_entry._file_size = static_cast(-1); - _dir_entry._last_write_time = 0; - } - } - } - path _base; - directory_options _options; - WIN32_FIND_DATAW _findData; - HANDLE _dirHandle; - path _current; - directory_entry _dir_entry; - std::error_code _ec; -}; -#else -// POSIX implementation -class directory_iterator::impl -{ -public: - impl(const path& path, directory_options options) - : _base(path) - , _options(options) - , _dir(nullptr) - , _entry(nullptr) - { - if (!path.empty()) { - _dir = ::opendir(path.native().c_str()); - } - if (!path.empty()) { - if (!_dir) { - auto error = errno; - _base = filesystem::path(); - if (error != EACCES || (options & directory_options::skip_permission_denied) == directory_options::none) { - _ec = detail::make_system_error(); - } - } - else { - increment(_ec); - } - } - } - impl(const impl& other) = delete; - ~impl() - { - if (_dir) { - ::closedir(_dir); - } - } - void increment(std::error_code& ec) - { - if (_dir) { - do { - errno = 0; - _entry = readdir(_dir); - if (_entry) { - _current = _base; - _current.append_name(_entry->d_name); - _dir_entry = directory_entry(_current, ec); - } - else { - ::closedir(_dir); - _dir = nullptr; - _current = path(); - if (errno) { - ec = detail::make_system_error(); - } - break; - } - } while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); - } - } - path _base; - directory_options _options; - path _current; - DIR* _dir; - struct ::dirent* _entry; - directory_entry _dir_entry; - std::error_code _ec; -}; -#endif - -// 30.10.13.1 member functions -GHC_INLINE directory_iterator::directory_iterator() noexcept - : _impl(new impl(path(), directory_options::none)) -{ -} - -GHC_INLINE directory_iterator::directory_iterator(const path& p) - : _impl(new impl(p, directory_options::none)) -{ - if (_impl->_ec) { - throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); - } - _impl->_ec.clear(); -} - -GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options) - : _impl(new impl(p, options)) -{ - if (_impl->_ec) { - throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); - } -} - -GHC_INLINE directory_iterator::directory_iterator(const path& p, std::error_code& ec) noexcept - : _impl(new impl(p, directory_options::none)) -{ - if (_impl->_ec) { - ec = _impl->_ec; - } -} - -GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept - : _impl(new impl(p, options)) -{ - if (_impl->_ec) { - ec = _impl->_ec; - } -} - -GHC_INLINE directory_iterator::directory_iterator(const directory_iterator& rhs) - : _impl(rhs._impl) -{ -} - -GHC_INLINE directory_iterator::directory_iterator(directory_iterator&& rhs) noexcept - : _impl(std::move(rhs._impl)) -{ -} - -GHC_INLINE directory_iterator::~directory_iterator() {} - -GHC_INLINE directory_iterator& directory_iterator::operator=(const directory_iterator& rhs) -{ - _impl = rhs._impl; - return *this; -} - -GHC_INLINE directory_iterator& directory_iterator::operator=(directory_iterator&& rhs) noexcept -{ - _impl = std::move(rhs._impl); - return *this; -} - -GHC_INLINE const directory_entry& directory_iterator::operator*() const -{ - return _impl->_dir_entry; -} - -GHC_INLINE const directory_entry* directory_iterator::operator->() const -{ - return &_impl->_dir_entry; -} - -GHC_INLINE directory_iterator& directory_iterator::operator++() -{ - std::error_code ec; - _impl->increment(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_current, ec); - } - return *this; -} - -GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept -{ - _impl->increment(ec); - return *this; -} - -GHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const -{ - return _impl->_current == rhs._impl->_current; -} - -GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const -{ - return _impl->_current != rhs._impl->_current; -} - -// 30.10.13.2 directory_iterator non-member functions - -GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept -{ - return iter; -} - -GHC_INLINE directory_iterator end(const directory_iterator&) noexcept -{ - return directory_iterator(); -} - -//----------------------------------------------------------------------------- -// 30.10.14 class recursive_directory_iterator - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept - : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator()); -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p) - : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator(p)); -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options) - : _impl(new recursive_directory_iterator_impl(options, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator(p, options)); -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept - : _impl(new recursive_directory_iterator_impl(options, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator(p, options, ec)); -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept - : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) -{ - _impl->_dir_iter_stack.push(directory_iterator(p, ec)); -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs) - : _impl(rhs._impl) -{ -} - -GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept - : _impl(std::move(rhs._impl)) -{ -} - -GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {} - -// 30.10.14.1 observers -GHC_INLINE directory_options recursive_directory_iterator::options() const -{ - return _impl->_options; -} - -GHC_INLINE int recursive_directory_iterator::depth() const -{ - return static_cast(_impl->_dir_iter_stack.size() - 1); -} - -GHC_INLINE bool recursive_directory_iterator::recursion_pending() const -{ - return _impl->_recursion_pending; -} - -GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const -{ - return *(_impl->_dir_iter_stack.top()); -} - -GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const -{ - return &(*(_impl->_dir_iter_stack.top())); -} - -// 30.10.14.1 modifiers recursive_directory_iterator& -GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs) -{ - _impl = rhs._impl; - return *this; -} - -GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept -{ - _impl = std::move(rhs._impl); - return *this; -} - -GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++() -{ - std::error_code ec; - increment(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); - } - return *this; -} - -GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept -{ - if (recursion_pending() && is_directory((*this)->status()) && (!is_symlink((*this)->symlink_status()) || (options() & directory_options::follow_directory_symlink) != directory_options::none)) { - _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec)); - } - else { - _impl->_dir_iter_stack.top().increment(ec); - } - if (!ec) { - while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { - _impl->_dir_iter_stack.pop(); - _impl->_dir_iter_stack.top().increment(ec); - } - } - else if (!_impl->_dir_iter_stack.empty()) { - _impl->_dir_iter_stack.pop(); - } - _impl->_recursion_pending = true; - return *this; -} - -GHC_INLINE void recursive_directory_iterator::pop() -{ - std::error_code ec; - pop(ec); - if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); - } -} - -GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec) -{ - if (depth() == 0) { - *this = recursive_directory_iterator(); - } - else { - do { - _impl->_dir_iter_stack.pop(); - _impl->_dir_iter_stack.top().increment(ec); - } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()); - } -} - -GHC_INLINE void recursive_directory_iterator::disable_recursion_pending() -{ - _impl->_recursion_pending = false; -} - -// other members as required by 27.2.3, input iterators -GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const -{ - return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top(); -} - -GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const -{ - return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top(); -} - -// 30.10.14.2 directory_iterator non-member functions -GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept -{ - return iter; -} - -GHC_INLINE recursive_directory_iterator end(const recursive_directory_iterator&) noexcept -{ - return recursive_directory_iterator(); -} - -#endif // GHC_EXPAND_IMPL - -} // namespace filesystem -} // namespace ghc - -// cleanup some macros -#undef GHC_INLINE -#undef GHC_EXPAND_IMPL - -#endif // GHC_FILESYSTEM_H diff --git a/src/external/ghc/fs_fwd.hpp b/src/external/ghc/fs_fwd.hpp deleted file mode 100644 index 197b69e8..00000000 --- a/src/external/ghc/fs_fwd.hpp +++ /dev/null @@ -1,46 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors -// may be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -//--------------------------------------------------------------------------------------- -// fs_fwd.hpp - The forwarding header for the header/implementation seperated usage of -// ghc::filesystem. -// This file can be include at any place, where ghc::filesystem api is needed while -// not bleeding implementation details (e.g. system includes) into the global namespace, -// as long as one cpp includes fs_impl.hpp to deliver the matching implementations. -//--------------------------------------------------------------------------------------- -#ifndef GHC_FILESYSTEM_FWD_H -#define GHC_FILESYSTEM_FWD_H -#define GHC_FILESYSTEM_FWD -#include -#endif // GHC_FILESYSTEM_FWD_H diff --git a/src/external/ghc/fs_impl.hpp b/src/external/ghc/fs_impl.hpp deleted file mode 100644 index 34bb2fea..00000000 --- a/src/external/ghc/fs_impl.hpp +++ /dev/null @@ -1,43 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors -// may be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -//--------------------------------------------------------------------------------------- -// fs_impl.hpp - The implementation header for the header/implementation seperated usage of -// ghc::filesystem. -// This file can be used to hide the implementation of ghc::filesystem into a single cpp. -// The cpp has to include this before including fs_fwd.hpp directly or via a different -// header to work. -//--------------------------------------------------------------------------------------- -#define GHC_FILESYSTEM_IMPLEMENTATION -#include diff --git a/src/external/ghc/fs_std.hpp b/src/external/ghc/fs_std.hpp deleted file mode 100644 index 63231c59..00000000 --- a/src/external/ghc/fs_std.hpp +++ /dev/null @@ -1,64 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors -// may be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -//--------------------------------------------------------------------------------------- -// fs_std.hpp - The dynamic switching header that includes std::filesystem if detected -// or ghc::filesystem if not, and makes the resulting API available in the -// namespace fs. -//--------------------------------------------------------------------------------------- -#ifndef GHC_FILESYSTEM_STD_H -#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) -#if __has_include() -#define GHC_USE_STD_FS -#include -namespace fs { -using namespace std::filesystem; -using ifstream = std::ifstream; -using ofstream = std::ofstream; -using fstream = std::fstream; -} -#endif -#endif -#ifndef GHC_USE_STD_FS -#define GHC_WIN_WSTRING_STRING_TYPE -#include -namespace fs { -using namespace ghc::filesystem; -using ifstream = ghc::filesystem::ifstream; -using ofstream = ghc::filesystem::ofstream; -using fstream = ghc::filesystem::fstream; -} -#endif -#endif // GHC_FILESYSTEM_STD_H - diff --git a/src/external/ghc/fs_std_fwd.hpp b/src/external/ghc/fs_std_fwd.hpp deleted file mode 100644 index 6d2ebfb0..00000000 --- a/src/external/ghc/fs_std_fwd.hpp +++ /dev/null @@ -1,68 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors -// may be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -//--------------------------------------------------------------------------------------- -// fs_std_fwd.hpp - The forwarding header for the header/implementation seperated usage of -// ghc::filesystem that uses std::filesystem if it detects it. -// This file can be include at any place, where fs::filesystem api is needed while -// not bleeding implementation details (e.g. system includes) into the global namespace, -// as long as one cpp includes fs_std_impl.hpp to deliver the matching implementations. -//--------------------------------------------------------------------------------------- -#ifndef GHC_FILESYSTEM_STD_FWD_H -#define GHC_FILESYSTEM_STD_FWD_H -#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) -#if __has_include() -#define GHC_USE_STD_FS -#include -namespace fs { -using namespace std::filesystem; -using ifstream = std::ifstream; -using ofstream = std::ofstream; -using fstream = std::fstream; -} -#endif -#endif -#ifndef GHC_USE_STD_FS -#define GHC_WIN_WSTRING_STRING_TYPE -#define GHC_FILESYSTEM_FWD -#include -namespace fs { -using namespace ghc::filesystem; -using ifstream = ghc::filesystem::ifstream; -using ofstream = ghc::filesystem::ofstream; -using fstream = ghc::filesystem::fstream; -} -#endif -#endif // GHC_FILESYSTEM_STD_FWD_H - diff --git a/src/external/ghc/fs_std_impl.hpp b/src/external/ghc/fs_std_impl.hpp deleted file mode 100644 index 005ec584..00000000 --- a/src/external/ghc/fs_std_impl.hpp +++ /dev/null @@ -1,51 +0,0 @@ -//--------------------------------------------------------------------------------------- -// -// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 -// -//--------------------------------------------------------------------------------------- -// -// Copyright (c) 2018, Steffen Schümann -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors -// may be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -//--------------------------------------------------------------------------------------- -// fs_std_impl.hpp - The implementation header for the header/implementation seperated usage of -// ghc::filesystem that does nothing if std::filesystem is detected. -// This file can be used to hide the implementation of ghc::filesystem into a single cpp. -// The cpp has to include this before including fs_std_fwd.hpp directly or via a different -// header to work. -//--------------------------------------------------------------------------------------- -#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) -#if __has_include() -#define GHC_USE_STD_FS -#endif -#endif -#ifndef GHC_USE_STD_FS -#define GHC_WIN_WSTRING_STRING_TYPE -#define GHC_FILESYSTEM_IMPLEMENTATION -#include -#endif From f15554310ef16668ec5d2c0721507353945bbd12 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 11:06:41 +0100 Subject: [PATCH 147/668] Move hiir --- src/external/hiir/{ => hiir}/Downsampler2xFpu.h | 0 src/external/hiir/{ => hiir}/Downsampler2xFpu.hpp | 0 src/external/hiir/{ => hiir}/Downsampler2xNeon.h | 0 src/external/hiir/{ => hiir}/Downsampler2xNeon.hpp | 0 src/external/hiir/{ => hiir}/Downsampler2xSse.h | 0 src/external/hiir/{ => hiir}/Downsampler2xSse.hpp | 0 src/external/hiir/{ => hiir}/StageDataNeon.h | 0 src/external/hiir/{ => hiir}/StageDataSse.h | 0 src/external/hiir/{ => hiir}/StageProcFpu.h | 0 src/external/hiir/{ => hiir}/StageProcFpu.hpp | 0 src/external/hiir/{ => hiir}/StageProcNeon.h | 0 src/external/hiir/{ => hiir}/StageProcNeon.hpp | 0 src/external/hiir/{ => hiir}/StageProcSse.h | 0 src/external/hiir/{ => hiir}/StageProcSse.hpp | 0 src/external/hiir/{ => hiir}/Upsampler2xFpu.h | 0 src/external/hiir/{ => hiir}/Upsampler2xFpu.hpp | 0 src/external/hiir/{ => hiir}/Upsampler2xNeon.h | 0 src/external/hiir/{ => hiir}/Upsampler2xNeon.hpp | 0 src/external/hiir/{ => hiir}/Upsampler2xSse.h | 0 src/external/hiir/{ => hiir}/Upsampler2xSse.hpp | 0 src/external/hiir/{ => hiir}/def.h | 0 src/external/hiir/{ => hiir}/fnc.h | 0 src/external/hiir/{ => hiir}/fnc.hpp | 0 src/external/hiir/license.txt | 13 +++++++++++++ 24 files changed, 13 insertions(+) rename src/external/hiir/{ => hiir}/Downsampler2xFpu.h (100%) rename src/external/hiir/{ => hiir}/Downsampler2xFpu.hpp (100%) rename src/external/hiir/{ => hiir}/Downsampler2xNeon.h (100%) rename src/external/hiir/{ => hiir}/Downsampler2xNeon.hpp (100%) rename src/external/hiir/{ => hiir}/Downsampler2xSse.h (100%) rename src/external/hiir/{ => hiir}/Downsampler2xSse.hpp (100%) rename src/external/hiir/{ => hiir}/StageDataNeon.h (100%) rename src/external/hiir/{ => hiir}/StageDataSse.h (100%) rename src/external/hiir/{ => hiir}/StageProcFpu.h (100%) rename src/external/hiir/{ => hiir}/StageProcFpu.hpp (100%) rename src/external/hiir/{ => hiir}/StageProcNeon.h (100%) rename src/external/hiir/{ => hiir}/StageProcNeon.hpp (100%) rename src/external/hiir/{ => hiir}/StageProcSse.h (100%) rename src/external/hiir/{ => hiir}/StageProcSse.hpp (100%) rename src/external/hiir/{ => hiir}/Upsampler2xFpu.h (100%) rename src/external/hiir/{ => hiir}/Upsampler2xFpu.hpp (100%) rename src/external/hiir/{ => hiir}/Upsampler2xNeon.h (100%) rename src/external/hiir/{ => hiir}/Upsampler2xNeon.hpp (100%) rename src/external/hiir/{ => hiir}/Upsampler2xSse.h (100%) rename src/external/hiir/{ => hiir}/Upsampler2xSse.hpp (100%) rename src/external/hiir/{ => hiir}/def.h (100%) rename src/external/hiir/{ => hiir}/fnc.h (100%) rename src/external/hiir/{ => hiir}/fnc.hpp (100%) create mode 100644 src/external/hiir/license.txt diff --git a/src/external/hiir/Downsampler2xFpu.h b/src/external/hiir/hiir/Downsampler2xFpu.h similarity index 100% rename from src/external/hiir/Downsampler2xFpu.h rename to src/external/hiir/hiir/Downsampler2xFpu.h diff --git a/src/external/hiir/Downsampler2xFpu.hpp b/src/external/hiir/hiir/Downsampler2xFpu.hpp similarity index 100% rename from src/external/hiir/Downsampler2xFpu.hpp rename to src/external/hiir/hiir/Downsampler2xFpu.hpp diff --git a/src/external/hiir/Downsampler2xNeon.h b/src/external/hiir/hiir/Downsampler2xNeon.h similarity index 100% rename from src/external/hiir/Downsampler2xNeon.h rename to src/external/hiir/hiir/Downsampler2xNeon.h diff --git a/src/external/hiir/Downsampler2xNeon.hpp b/src/external/hiir/hiir/Downsampler2xNeon.hpp similarity index 100% rename from src/external/hiir/Downsampler2xNeon.hpp rename to src/external/hiir/hiir/Downsampler2xNeon.hpp diff --git a/src/external/hiir/Downsampler2xSse.h b/src/external/hiir/hiir/Downsampler2xSse.h similarity index 100% rename from src/external/hiir/Downsampler2xSse.h rename to src/external/hiir/hiir/Downsampler2xSse.h diff --git a/src/external/hiir/Downsampler2xSse.hpp b/src/external/hiir/hiir/Downsampler2xSse.hpp similarity index 100% rename from src/external/hiir/Downsampler2xSse.hpp rename to src/external/hiir/hiir/Downsampler2xSse.hpp diff --git a/src/external/hiir/StageDataNeon.h b/src/external/hiir/hiir/StageDataNeon.h similarity index 100% rename from src/external/hiir/StageDataNeon.h rename to src/external/hiir/hiir/StageDataNeon.h diff --git a/src/external/hiir/StageDataSse.h b/src/external/hiir/hiir/StageDataSse.h similarity index 100% rename from src/external/hiir/StageDataSse.h rename to src/external/hiir/hiir/StageDataSse.h diff --git a/src/external/hiir/StageProcFpu.h b/src/external/hiir/hiir/StageProcFpu.h similarity index 100% rename from src/external/hiir/StageProcFpu.h rename to src/external/hiir/hiir/StageProcFpu.h diff --git a/src/external/hiir/StageProcFpu.hpp b/src/external/hiir/hiir/StageProcFpu.hpp similarity index 100% rename from src/external/hiir/StageProcFpu.hpp rename to src/external/hiir/hiir/StageProcFpu.hpp diff --git a/src/external/hiir/StageProcNeon.h b/src/external/hiir/hiir/StageProcNeon.h similarity index 100% rename from src/external/hiir/StageProcNeon.h rename to src/external/hiir/hiir/StageProcNeon.h diff --git a/src/external/hiir/StageProcNeon.hpp b/src/external/hiir/hiir/StageProcNeon.hpp similarity index 100% rename from src/external/hiir/StageProcNeon.hpp rename to src/external/hiir/hiir/StageProcNeon.hpp diff --git a/src/external/hiir/StageProcSse.h b/src/external/hiir/hiir/StageProcSse.h similarity index 100% rename from src/external/hiir/StageProcSse.h rename to src/external/hiir/hiir/StageProcSse.h diff --git a/src/external/hiir/StageProcSse.hpp b/src/external/hiir/hiir/StageProcSse.hpp similarity index 100% rename from src/external/hiir/StageProcSse.hpp rename to src/external/hiir/hiir/StageProcSse.hpp diff --git a/src/external/hiir/Upsampler2xFpu.h b/src/external/hiir/hiir/Upsampler2xFpu.h similarity index 100% rename from src/external/hiir/Upsampler2xFpu.h rename to src/external/hiir/hiir/Upsampler2xFpu.h diff --git a/src/external/hiir/Upsampler2xFpu.hpp b/src/external/hiir/hiir/Upsampler2xFpu.hpp similarity index 100% rename from src/external/hiir/Upsampler2xFpu.hpp rename to src/external/hiir/hiir/Upsampler2xFpu.hpp diff --git a/src/external/hiir/Upsampler2xNeon.h b/src/external/hiir/hiir/Upsampler2xNeon.h similarity index 100% rename from src/external/hiir/Upsampler2xNeon.h rename to src/external/hiir/hiir/Upsampler2xNeon.h diff --git a/src/external/hiir/Upsampler2xNeon.hpp b/src/external/hiir/hiir/Upsampler2xNeon.hpp similarity index 100% rename from src/external/hiir/Upsampler2xNeon.hpp rename to src/external/hiir/hiir/Upsampler2xNeon.hpp diff --git a/src/external/hiir/Upsampler2xSse.h b/src/external/hiir/hiir/Upsampler2xSse.h similarity index 100% rename from src/external/hiir/Upsampler2xSse.h rename to src/external/hiir/hiir/Upsampler2xSse.h diff --git a/src/external/hiir/Upsampler2xSse.hpp b/src/external/hiir/hiir/Upsampler2xSse.hpp similarity index 100% rename from src/external/hiir/Upsampler2xSse.hpp rename to src/external/hiir/hiir/Upsampler2xSse.hpp diff --git a/src/external/hiir/def.h b/src/external/hiir/hiir/def.h similarity index 100% rename from src/external/hiir/def.h rename to src/external/hiir/hiir/def.h diff --git a/src/external/hiir/fnc.h b/src/external/hiir/hiir/fnc.h similarity index 100% rename from src/external/hiir/fnc.h rename to src/external/hiir/hiir/fnc.h diff --git a/src/external/hiir/fnc.hpp b/src/external/hiir/hiir/fnc.hpp similarity index 100% rename from src/external/hiir/fnc.hpp rename to src/external/hiir/hiir/fnc.hpp diff --git a/src/external/hiir/license.txt b/src/external/hiir/license.txt new file mode 100644 index 00000000..1c93089b --- /dev/null +++ b/src/external/hiir/license.txt @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. From bd3f660c1239233d6d63bfa37fab4ff817274339 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 11:09:04 +0100 Subject: [PATCH 148/668] Add hiir and filesystem as interface libraries --- cmake/SfizzConfig.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index cfe1e559..c656fd78 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -154,6 +154,14 @@ add_library(sfizz_tunings STATIC "src/external/tunings/src/Tunings.cpp") add_library(sfizz::tunings ALIAS sfizz_tunings) target_include_directories(sfizz_tunings PUBLIC "src/external/tunings/include") +add_library(sfizz_hiir INTERFACE) +add_library(sfizz::hiir ALIAS sfizz_hiir) +target_include_directories(sfizz_hiir INTERFACE "src/external/hiir") + +add_library(sfizz_filesystem INTERFACE) +add_library(sfizz::filesystem ALIAS sfizz_filesystem) +target_include_directories(sfizz_filesystem INTERFACE "external/filesystem/include") + add_library(sfizz_atomic INTERFACE) add_library(sfizz::atomic ALIAS sfizz_atomic) if(UNIX AND NOT APPLE) From 96a462e20d12515aa5bccdd8fb487717f871cce5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 11:43:47 +0100 Subject: [PATCH 149/668] Use hiir and filesystem as interface libraries --- benchmarks/CMakeLists.txt | 9 ++++----- common.mk | 9 ++++++++- demos/CMakeLists.txt | 4 ++-- editor/CMakeLists.txt | 2 +- scripts/run_clang_tidy.sh | 2 +- src/CMakeLists.txt | 15 +++++++++------ vst/CMakeLists.txt | 4 ++-- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index a72c9f6c..89c85a56 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -20,19 +20,18 @@ endif() add_library(bm_simd STATIC ${BENCHMARK_SIMD_SOURCES}) target_link_libraries(bm_simd PRIVATE absl::span sfizz::cpuid) -target_include_directories(bm_simd PRIVATE ../src/external) add_library(bm_ftz STATIC ../src/sfizz/ScopedFTZ.cpp) macro(sfizz_add_benchmark TARGET) add_executable("${TARGET}" ${ARGN}) target_link_libraries("${TARGET}" - PRIVATE absl::span absl::algorithm + PRIVATE sfizz::filesystem absl::span absl::algorithm PRIVATE benchmark::benchmark benchmark::benchmark_main PRIVATE bm_simd bm_ftz) if(LIBATOMIC_FOUND) target_link_libraries("${TARGET}" PRIVATE atomic) endif() - target_include_directories("${TARGET}" PRIVATE ../src/sfizz ../src/external) + target_include_directories("${TARGET}" PRIVATE ../src/sfizz) sfizz_enable_fast_math("${TARGET}") endmacro() @@ -75,7 +74,7 @@ target_link_libraries(bm_powerFollower PRIVATE sfizz::sfizz) if(TARGET sfizz::samplerate) sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES}) -target_link_libraries(bm_resample PRIVATE sfizz::samplerate sfizz::sndfile sfizz::cpuid) +target_link_libraries(bm_resample PRIVATE sfizz::samplerate sfizz::sndfile sfizz::cpuid sfizz::hiir) endif() sfizz_add_benchmark(bm_envelopes BM_envelopes.cpp) @@ -95,7 +94,7 @@ sfizz_add_benchmark(bm_readChunkFlac BM_readChunkFlac.cpp) target_link_libraries(bm_readChunkFlac PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_resampleChunk BM_resampleChunk.cpp) -target_link_libraries(bm_resampleChunk PRIVATE sfizz::sndfile) +target_link_libraries(bm_resampleChunk PRIVATE sfizz::sndfile sfizz::hiir) sfizz_add_benchmark(bm_interpolators BM_interpolators.cpp) diff --git a/common.mk b/common.mk index 4f3289fa..cda6e2e4 100644 --- a/common.mk +++ b/common.mk @@ -126,7 +126,6 @@ SFIZZ_SOURCES = \ ### Other internal SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/src/sfizz -SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/src/external # Pkg-config dependency @@ -175,6 +174,14 @@ SFIZZ_CXX_FLAGS += \ -I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/libaiff endif +# hiir dependency + +SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/src/external/hiir + +# ghc::filesystem dependency + +SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/external/filesystem/include + ### Abseil dependency SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/external/abseil-cpp diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index ba349140..b2d715f8 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -37,10 +37,10 @@ if(TARGET Qt5::Widgets) endif() add_executable(eq_apply EQ.cpp) -target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts) +target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts sfizz::filesystem) add_executable(filter_apply Filter.cpp) -target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts) +target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts sfizz::filesystem) add_executable(sfizz_plot_curve PlotCurve.cpp) target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz) diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 9517c51e..34405afb 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -69,7 +69,7 @@ else() target_include_directories(sfizz_editor PRIVATE ${sfizz-gio_INCLUDE_DIRS}) target_link_libraries(sfizz_editor PRIVATE ${sfizz-gio_LIBRARIES}) endif() -target_include_directories(sfizz_editor PRIVATE "../src/external") # ghc::filesystem +target_link_libraries(sfizz_editor PRIVATE sfizz::filesystem) # layout tool if(NOT CMAKE_CROSSCOMPILING) diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index 18d0b08f..7c2894aa 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -30,7 +30,7 @@ clang-tidy \ vst/SfizzVstProcessor.cpp \ vst/SfizzVstEditor.cpp \ vst/SfizzVstState.cpp \ - -- -Iexternal/abseil-cpp -Iexternal/jsl/include -Isrc/external -Isrc/external/pugixml/src \ + -- -Iexternal/abseil-cpp -Iexternal/jsl/include -Iexternal/filesystem/include -Isrc/external/hiir -Isrc/external/pugixml/src \ -Iexternal/st_audiofile/src -Iexternal/st_audiofile/thirdparty/dr_libs \ -Isrc/sfizz -Isrc -Isrc/external/spline -Isrc/external/cpuid/src \ -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed93df85..a10b3aa7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -214,11 +214,13 @@ source_group("Other Files" FILES ${SFIZZ_PARSER_OTHER}) # Sfizz parser library add_library(sfizz_parser STATIC) +add_library(sfizz::parser ALIAS sfizz_parser) target_sources(sfizz_parser PRIVATE ${SFIZZ_PARSER_HEADERS} ${SFIZZ_PARSER_SOURCES} ${SFIZZ_PARSER_OTHER}) target_include_directories(sfizz_parser PUBLIC sfizz) -target_include_directories(sfizz_parser PUBLIC external) -target_link_libraries(sfizz_parser PUBLIC absl::strings PRIVATE absl::flat_hash_map) +target_link_libraries(sfizz_parser + PUBLIC sfizz::filesystem absl::strings + PRIVATE absl::flat_hash_map) # OSC messaging library set(SFIZZ_MESSAGING_HEADERS @@ -237,12 +239,13 @@ target_link_libraries(sfizz_messaging PUBLIC absl::strings) # Sfizz static library add_library(sfizz_static STATIC) +add_library(sfizz::static ALIAS sfizz_static) target_sources(sfizz_static PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) target_include_directories(sfizz_static PUBLIC .) target_include_directories(sfizz_static PUBLIC external) -target_link_libraries(sfizz_static PUBLIC absl::strings absl::span) -target_link_libraries(sfizz_static PRIVATE sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::atomic) +target_link_libraries(sfizz_static PUBLIC absl::strings absl::span sfizz::filesystem) +target_link_libraries(sfizz_static PRIVATE sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::atomic) set_target_properties(sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) @@ -263,17 +266,17 @@ endif() configure_file(${PROJECT_SOURCE_DIR}/scripts/doxygen/Doxyfile.in ${PROJECT_SOURCE_DIR}/Doxyfile @ONLY) -add_library(sfizz::parser ALIAS sfizz_parser) add_library(sfizz::sfizz ALIAS sfizz_static) # Shared library and installation target if(SFIZZ_SHARED) add_library(sfizz_shared SHARED) + add_library(sfizz::shared ALIAS sfizz_shared) target_sources(sfizz_shared PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) target_include_directories(sfizz_shared PRIVATE .) target_include_directories(sfizz_shared PRIVATE external) - target_link_libraries(sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::atomic) + target_link_libraries(sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::filesystem sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) target_link_libraries(sfizz_shared PUBLIC st_audiofile) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 468b6f1f..2b215fc5 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -60,7 +60,7 @@ endif() target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} PRIVATE sfizz_editor - PRIVATE sfizz::pugixml) + PRIVATE sfizz::pugixml sfizz::filesystem) target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES @@ -198,7 +198,7 @@ elseif(SFIZZ_AU) target_link_libraries(${AUPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} PRIVATE sfizz_editor - PRIVATE sfizz::pugixml) + PRIVATE sfizz::pugixml sfizz::filesystem) target_include_directories(${AUPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(${AUPLUGIN_PRJ_NAME} PROPERTIES From 6211665120f46f33b76803d8355d5b7dbc3716b1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 11:47:09 +0100 Subject: [PATCH 150/668] Use alias for sfizz::messaging --- editor/CMakeLists.txt | 2 +- src/CMakeLists.txt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 34405afb..853e95c6 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -42,7 +42,7 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/utility/vstgui_after.h src/editor/utility/vstgui_before.h) target_include_directories(sfizz_editor PUBLIC "src") -target_link_libraries(sfizz_editor PUBLIC sfizz_messaging) +target_link_libraries(sfizz_editor PUBLIC sfizz::messaging) target_link_libraries(sfizz_editor PRIVATE sfizz::vstgui) target_link_libraries(sfizz_editor PUBLIC absl::strings) if(APPLE) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a10b3aa7..88b1bf78 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -232,6 +232,7 @@ set(SFIZZ_MESSAGING_SOURCES sfizz/Messaging.cpp) add_library(sfizz_messaging STATIC) +add_library(sfizz::messaging ALIAS sfizz_messaging) target_sources(sfizz_messaging PRIVATE ${SFIZZ_MESSAGING_HEADERS} ${SFIZZ_MESSAGING_SOURCES}) target_include_directories(sfizz_messaging PUBLIC ".") @@ -245,7 +246,7 @@ target_sources(sfizz_static PRIVATE target_include_directories(sfizz_static PUBLIC .) target_include_directories(sfizz_static PUBLIC external) target_link_libraries(sfizz_static PUBLIC absl::strings absl::span sfizz::filesystem) -target_link_libraries(sfizz_static PRIVATE sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::atomic) +target_link_libraries(sfizz_static PRIVATE sfizz_parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::atomic) set_target_properties(sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) @@ -276,7 +277,7 @@ if(SFIZZ_SHARED) ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) target_include_directories(sfizz_shared PRIVATE .) target_include_directories(sfizz_shared PRIVATE external) - target_link_libraries(sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz_messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::filesystem sfizz::atomic) + target_link_libraries(sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::filesystem sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) target_link_libraries(sfizz_shared PUBLIC st_audiofile) From f9185fe9908493463b93b5812ad86071dc02e780 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 11:48:30 +0100 Subject: [PATCH 151/668] Use alias sfizz::editor --- editor/CMakeLists.txt | 1 + lv2/CMakeLists.txt | 2 +- vst/CMakeLists.txt | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 853e95c6..379e7899 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -41,6 +41,7 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/layout/main.hpp src/editor/utility/vstgui_after.h src/editor/utility/vstgui_before.h) +add_library(sfizz::editor ALIAS sfizz_editor) target_include_directories(sfizz_editor PUBLIC "src") target_link_libraries(sfizz_editor PUBLIC sfizz::messaging) target_link_libraries(sfizz_editor PRIVATE sfizz::vstgui) diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index c84a93ab..c5a4e861 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -29,7 +29,7 @@ if(SFIZZ_LV2_UI) ${PROJECT_NAME}_ui.cpp vstgui_helpers.h vstgui_helpers.cpp) - target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui sfizz_editor sfizz::vstgui) + target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui sfizz::editor sfizz::vstgui) endif() # Explicitely strip all symbols on Linux but lv2_descriptor() diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 2b215fc5..02afabef 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -59,7 +59,7 @@ if(WIN32) endif() target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} - PRIVATE sfizz_editor + PRIVATE sfizz::editor PRIVATE sfizz::pugixml sfizz::filesystem) target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") @@ -197,7 +197,7 @@ elseif(SFIZZ_AU) target_link_libraries(${AUPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} - PRIVATE sfizz_editor + PRIVATE sfizz::editor PRIVATE sfizz::pugixml sfizz::filesystem) target_include_directories(${AUPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") From 0c8fb5fbc4f3ccfe6d16a1071a7db1e9b9577dd0 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 12:48:19 +0100 Subject: [PATCH 152/668] Update atomic_queue for a bugfix --- src/external/atomic_queue/atomic_queue.h | 23 +++++++++++++---------- src/external/atomic_queue/defs.h | 7 ++++--- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/external/atomic_queue/atomic_queue.h b/src/external/atomic_queue/atomic_queue.h index f679d32c..1319f6f9 100644 --- a/src/external/atomic_queue/atomic_queue.h +++ b/src/external/atomic_queue/atomic_queue.h @@ -55,15 +55,13 @@ struct GetIndexShuffleBits { // the element within the cache line) with the next N bits (which are the index of the cache line) // of the element index. template -constexpr unsigned remap_index_with_mix(unsigned index, unsigned mix) -{ +constexpr unsigned remap_index_with_mix(unsigned index, unsigned mix) { return index ^ mix ^ (mix << BITS); } template constexpr unsigned remap_index(unsigned index) noexcept { - return remap_index_with_mix( - index, (index ^ (index >> BITS)) & ((1u << BITS) - 1)); + return remap_index_with_mix(index, (index ^ (index >> BITS)) & ((1u << BITS) - 1)); } template<> @@ -133,7 +131,7 @@ protected: // The special member functions are not thread-safe. - AtomicQueueCommon() = default; + AtomicQueueCommon() noexcept = default; AtomicQueueCommon(AtomicQueueCommon const& b) noexcept : head_(b.head_.load(X)) @@ -213,7 +211,7 @@ protected: else { for(;;) { unsigned char expected = STORED; - if(ATOMIC_QUEUE_LIKELY(state.compare_exchange_strong(expected, LOADING, X, X))) { + if(ATOMIC_QUEUE_LIKELY(state.compare_exchange_strong(expected, LOADING, A, X))) { T element{std::move(q_element)}; state.store(EMPTY, R); return element; @@ -238,7 +236,7 @@ protected: else { for(;;) { unsigned char expected = EMPTY; - if(ATOMIC_QUEUE_LIKELY(state.compare_exchange_strong(expected, STORING, X, X))) { + if(ATOMIC_QUEUE_LIKELY(state.compare_exchange_strong(expected, STORING, A, X))) { q_element = std::forward(element); state.store(STORED, R); return; @@ -318,11 +316,16 @@ public: } bool was_empty() const noexcept { - return static_cast(head_.load(X) - tail_.load(X)) <= 0; + return !was_size(); } bool was_full() const noexcept { - return static_cast(head_.load(X) - tail_.load(X)) >= static_cast(static_cast(*this).size_); + return was_size() >= static_cast(static_cast(*this).size_); + } + + unsigned was_size() const noexcept { + // tail_ can be greater than head_ because of consumers doing pop, rather that try_pop, when the queue is empty. + return std::max(static_cast(head_.load(X) - tail_.load(X)), 0); } unsigned capacity() const noexcept { @@ -400,7 +403,7 @@ class AtomicQueue2 : public AtomicQueueCommon(expr), 1) #define ATOMIC_QUEUE_UNLIKELY(expr) __builtin_expect(static_cast(expr), 0) +#define ATOMIC_QUEUE_NOINLINE __attribute__((noinline)) #else -#define ATOMIC_QUEUE_LIKELY(expr) expr -#define ATOMIC_QUEUE_UNLIKELY(expr) expr +#define ATOMIC_QUEUE_LIKELY(expr) (expr) +#define ATOMIC_QUEUE_UNLIKELY(expr) (expr) +#define ATOMIC_QUEUE_NOINLINE #endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// From c6d96f8b4e5990649c3da8ddd8d9a31997df5060 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 13:04:27 +0100 Subject: [PATCH 153/668] Attempt to fix build problem with atomic_queue --- src/sfizz/FilePool.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 41068598..7f8be842 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -342,13 +342,9 @@ private: struct QueuedFileData { using TimePoint = std::chrono::time_point; - QueuedFileData() = default; - QueuedFileData(std::weak_ptr id, FileData* data, TimePoint queuedTime) + QueuedFileData() noexcept {} + QueuedFileData(std::weak_ptr id, FileData* data, TimePoint queuedTime) noexcept : id(id), data(data), queuedTime(queuedTime) {} - QueuedFileData(const QueuedFileData&) = default; - QueuedFileData& operator=(const QueuedFileData&) = default; - QueuedFileData(QueuedFileData&&) = default; - QueuedFileData& operator=(QueuedFileData&&) = default; std::weak_ptr id; FileData* data { nullptr }; TimePoint queuedTime {}; From f063062f7cf8caa561213cad5933a0969939dd04 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 12:54:16 +0100 Subject: [PATCH 154/668] Make a separate target for sfizz::internal, for tests and benchmarks --- benchmarks/CMakeLists.txt | 8 +- clients/CMakeLists.txt | 2 +- cmake/SfizzConfig.cmake | 8 ++ common.mk | 8 ++ demos/CMakeLists.txt | 28 +++---- external/atomic_queue/LICENSE | 21 +++++ .../include}/atomic_queue/atomic_queue.h | 0 .../atomic_queue/include}/atomic_queue/defs.h | 0 .../threadpool/ThreadPool.h | 0 src/CMakeLists.txt | 76 +++++++++---------- src/sfizz/FilePool.cpp | 2 +- tests/CMakeLists.txt | 3 +- 12 files changed, 93 insertions(+), 63 deletions(-) create mode 100644 external/atomic_queue/LICENSE rename {src/external => external/atomic_queue/include}/atomic_queue/atomic_queue.h (100%) rename {src/external => external/atomic_queue/include}/atomic_queue/defs.h (100%) rename {src/external => external}/threadpool/ThreadPool.h (100%) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 89c85a56..c73e23cf 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -44,7 +44,7 @@ sfizz_add_benchmark(bm_gain BM_gain.cpp) sfizz_add_benchmark(bm_divide BM_divide.cpp) sfizz_add_benchmark(bm_ramp BM_ramp.cpp) sfizz_add_benchmark(bm_ADSR BM_ADSR.cpp) -target_link_libraries(bm_ADSR PRIVATE sfizz::sfizz) +target_link_libraries(bm_ADSR PRIVATE sfizz::internal) sfizz_add_benchmark(bm_add BM_add.cpp) sfizz_add_benchmark(bm_multiplyAdd BM_multiplyAdd.cpp) @@ -66,11 +66,11 @@ sfizz_add_benchmark(bm_clamp BM_clamp.cpp) sfizz_add_benchmark(bm_allWithin BM_allWithin.cpp) sfizz_add_benchmark(bm_logger BM_logger.cpp) -target_link_libraries(bm_logger PRIVATE sfizz::sfizz) +target_link_libraries(bm_logger PRIVATE sfizz::internal) sfizz_add_benchmark(bm_smoothers BM_smoothers.cpp) -target_link_libraries(bm_smoothers PRIVATE sfizz::sfizz) +target_link_libraries(bm_smoothers PRIVATE sfizz::internal) sfizz_add_benchmark(bm_powerFollower BM_powerFollower.cpp) -target_link_libraries(bm_powerFollower PRIVATE sfizz::sfizz) +target_link_libraries(bm_powerFollower PRIVATE sfizz::internal) if(TARGET sfizz::samplerate) sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES}) diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index 7b9e3453..5c59c26a 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -22,7 +22,7 @@ if(SFIZZ_RENDER) target_compile_definitions(sfizz_fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1") add_executable(sfizz_render MidiHelpers.h sfizz_render.cpp) - target_link_libraries(sfizz_render PRIVATE sfizz::sfizz sfizz::fmidi sfizz::sndfile sfizz::cxxopts) + target_link_libraries(sfizz_render PRIVATE sfizz::internal sfizz::fmidi sfizz::sndfile sfizz::cxxopts) sfizz_enable_lto_if_needed(sfizz_render) install(TARGETS sfizz_render DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "render" OPTIONAL) endif() diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index c656fd78..4b6727c4 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -158,6 +158,14 @@ add_library(sfizz_hiir INTERFACE) add_library(sfizz::hiir ALIAS sfizz_hiir) target_include_directories(sfizz_hiir INTERFACE "src/external/hiir") +add_library(sfizz_threadpool INTERFACE) +add_library(sfizz::threadpool ALIAS sfizz_threadpool) +target_include_directories(sfizz_threadpool INTERFACE "external/threadpool") + +add_library(sfizz_atomic_queue INTERFACE) +add_library(sfizz::atomic_queue ALIAS sfizz_atomic_queue) +target_include_directories(sfizz_atomic_queue INTERFACE "external/atomic_queue/include") + add_library(sfizz_filesystem INTERFACE) add_library(sfizz::filesystem ALIAS sfizz_filesystem) target_include_directories(sfizz_filesystem INTERFACE "external/filesystem/include") diff --git a/common.mk b/common.mk index cda6e2e4..d4a63262 100644 --- a/common.mk +++ b/common.mk @@ -178,6 +178,14 @@ endif SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/src/external/hiir +# threadpool dependency + +SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/external/threadpool + +# atomic_queue dependency + +SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/external/atomic_queue/include + # ghc::filesystem dependency SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/external/filesystem/include diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index b2d715f8..ff0be6ff 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -8,54 +8,54 @@ if(TARGET Qt5::Widgets) if(JACK_FOUND) add_executable(sfizz_demo_filters DemoFilters.cpp) target_include_directories(sfizz_demo_filters PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_filters PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) + target_link_libraries(sfizz_demo_filters PRIVATE sfizz::internal Qt5::Widgets ${JACK_LIBRARIES}) set_target_properties(sfizz_demo_filters PROPERTIES AUTOUIC ON) add_executable(sfizz_demo_smooth DemoSmooth.cpp) target_include_directories(sfizz_demo_smooth PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_smooth PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) + target_link_libraries(sfizz_demo_smooth PRIVATE sfizz::internal Qt5::Widgets ${JACK_LIBRARIES}) set_target_properties(sfizz_demo_smooth PROPERTIES AUTOUIC ON) add_executable(sfizz_demo_stereo DemoStereo.cpp) target_include_directories(sfizz_demo_stereo PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_stereo PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) + target_link_libraries(sfizz_demo_stereo PRIVATE sfizz::internal Qt5::Widgets ${JACK_LIBRARIES}) set_target_properties(sfizz_demo_stereo PROPERTIES AUTOUIC ON) add_executable(sfizz_demo_wavetables DemoWavetables.cpp) target_include_directories(sfizz_demo_wavetables PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_wavetables PRIVATE sfizz::sfizz Qt5::Widgets ${JACK_LIBRARIES}) + target_link_libraries(sfizz_demo_wavetables PRIVATE sfizz::internal Qt5::Widgets ${JACK_LIBRARIES}) set_target_properties(sfizz_demo_wavetables PROPERTIES AUTOUIC ON) endif() add_executable(sfizz_demo_parser DemoParser.cpp) - target_link_libraries(sfizz_demo_parser PRIVATE sfizz_parser Qt5::Widgets) + target_link_libraries(sfizz_demo_parser PRIVATE sfizz::parser Qt5::Widgets) set_target_properties(sfizz_demo_parser PROPERTIES AUTOUIC ON) add_executable(sfizz_demo_stretch_tuning DemoStretchTuning.cpp) - target_link_libraries(sfizz_demo_stretch_tuning PRIVATE sfizz::sfizz Qt5::Widgets) + target_link_libraries(sfizz_demo_stretch_tuning PRIVATE sfizz::internal Qt5::Widgets) set_target_properties(sfizz_demo_stretch_tuning PROPERTIES AUTOUIC ON) endif() add_executable(eq_apply EQ.cpp) -target_link_libraries(eq_apply PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts sfizz::filesystem) +target_link_libraries(eq_apply PRIVATE sfizz::internal sfizz::sndfile sfizz::cxxopts sfizz::filesystem) add_executable(filter_apply Filter.cpp) -target_link_libraries(filter_apply PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts sfizz::filesystem) +target_link_libraries(filter_apply PRIVATE sfizz::internal sfizz::sndfile sfizz::cxxopts sfizz::filesystem) add_executable(sfizz_plot_curve PlotCurve.cpp) -target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz) +target_link_libraries(sfizz_plot_curve PRIVATE sfizz::internal) add_executable(sfizz_plot_wavetables PlotWavetables.cpp) -target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::sfizz) +target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::internal) add_executable(sfizz_plot_lfo PlotLFO.cpp) -target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz sfizz::sndfile sfizz::cxxopts) +target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::internal sfizz::sndfile sfizz::cxxopts) add_executable(sfizz_file_instrument FileInstrument.cpp) -target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz sfizz::sndfile) +target_link_libraries(sfizz_file_instrument PRIVATE sfizz::internal sfizz::sndfile) add_executable(sfizz_file_wavetable FileWavetable.cpp) -target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::sfizz) +target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::internal) add_executable(sfizz_tuning Tuning.cpp) -target_link_libraries(sfizz_tuning PRIVATE sfizz::sfizz sfizz::cxxopts) +target_link_libraries(sfizz_tuning PRIVATE sfizz::internal sfizz::cxxopts) diff --git a/external/atomic_queue/LICENSE b/external/atomic_queue/LICENSE new file mode 100644 index 00000000..c1d34669 --- /dev/null +++ b/external/atomic_queue/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Maxim Egorushkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/external/atomic_queue/atomic_queue.h b/external/atomic_queue/include/atomic_queue/atomic_queue.h similarity index 100% rename from src/external/atomic_queue/atomic_queue.h rename to external/atomic_queue/include/atomic_queue/atomic_queue.h diff --git a/src/external/atomic_queue/defs.h b/external/atomic_queue/include/atomic_queue/defs.h similarity index 100% rename from src/external/atomic_queue/defs.h rename to external/atomic_queue/include/atomic_queue/defs.h diff --git a/src/external/threadpool/ThreadPool.h b/external/threadpool/ThreadPool.h similarity index 100% rename from src/external/threadpool/ThreadPool.h rename to external/threadpool/ThreadPool.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88b1bf78..ecc2376c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -238,60 +238,42 @@ target_sources(sfizz_messaging PRIVATE target_include_directories(sfizz_messaging PUBLIC ".") target_link_libraries(sfizz_messaging PUBLIC absl::strings) -# Sfizz static library -add_library(sfizz_static STATIC) -add_library(sfizz::static ALIAS sfizz_static) -target_sources(sfizz_static PRIVATE - ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) -target_include_directories(sfizz_static PUBLIC .) -target_include_directories(sfizz_static PUBLIC external) -target_link_libraries(sfizz_static PUBLIC absl::strings absl::span sfizz::filesystem) -target_link_libraries(sfizz_static PRIVATE sfizz_parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::atomic) -set_target_properties(sfizz_static PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") +# Sfizz internals (use this for testing) +add_library(sfizz_internal STATIC) +add_library(sfizz::internal ALIAS sfizz_internal) +target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES}) +target_include_directories(sfizz_internal PUBLIC .) +target_link_libraries(sfizz_internal + PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue + PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) if(SFIZZ_USE_SNDFILE) - target_compile_definitions(sfizz_static PUBLIC SFIZZ_USE_SNDFILE=1) - target_link_libraries(sfizz_static PUBLIC st_audiofile) + target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") + target_link_libraries(sfizz_internal PUBLIC st_audiofile) endif() if(WIN32) - target_compile_definitions(sfizz_static PRIVATE _USE_MATH_DEFINES) + target_compile_definitions(sfizz_internal PRIVATE _USE_MATH_DEFINES) endif() if(SFIZZ_RELEASE_ASSERTS) - target_compile_definitions(sfizz_static PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") + target_compile_definitions(sfizz_internal PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") endif() -sfizz_enable_fast_math(sfizz_static) +sfizz_enable_fast_math(sfizz_internal) -if(WIN32) - include(VSTConfig) - configure_file(${PROJECT_SOURCE_DIR}/scripts/innosetup.iss.in ${PROJECT_BINARY_DIR}/innosetup.iss @ONLY) -endif() - -configure_file(${PROJECT_SOURCE_DIR}/scripts/doxygen/Doxyfile.in ${PROJECT_SOURCE_DIR}/Doxyfile @ONLY) - -add_library(sfizz::sfizz ALIAS sfizz_static) +# Sfizz static library +add_library(sfizz_static STATIC sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) +add_library(sfizz::static ALIAS sfizz_static) +target_include_directories(sfizz_static PUBLIC .) +target_link_libraries(sfizz_static PRIVATE sfizz::internal) +set_target_properties(sfizz_static PROPERTIES OUTPUT_NAME "sfizz" PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") # Shared library and installation target if(SFIZZ_SHARED) - add_library(sfizz_shared SHARED) + add_library(sfizz_shared SHARED sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) add_library(sfizz::shared ALIAS sfizz_shared) - target_sources(sfizz_shared PRIVATE - ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp) - target_include_directories(sfizz_shared PRIVATE .) - target_include_directories(sfizz_shared PRIVATE external) - target_link_libraries(sfizz_shared PRIVATE absl::strings absl::span sfizz_parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::jsl sfizz::filesystem sfizz::atomic) - if(SFIZZ_USE_SNDFILE) - target_compile_definitions(sfizz_shared PUBLIC SFIZZ_USE_SNDFILE=1) - target_link_libraries(sfizz_shared PUBLIC st_audiofile) - endif() - if(WIN32) - target_compile_definitions(sfizz_shared PRIVATE _USE_MATH_DEFINES) - endif() - if(SFIZZ_RELEASE_ASSERTS) - target_compile_definitions(sfizz_shared PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") - endif() + target_include_directories(sfizz_shared PUBLIC .) + target_link_libraries(sfizz_shared PRIVATE sfizz::internal) target_compile_definitions(sfizz_shared PRIVATE SFIZZ_EXPORT_SYMBOLS) - set_target_properties(sfizz_shared PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") + set_target_properties(sfizz_shared PROPERTIES SOVERSION "${PROJECT_VERSION_MAJOR}" OUTPUT_NAME "sfizz" PUBLIC_HEADER "sfizz.h;sfizz.hpp;sfizz_message.h") sfizz_enable_lto_if_needed(sfizz_shared) - sfizz_enable_fast_math(sfizz_shared) if(NOT MSVC) install(TARGETS sfizz_shared @@ -305,3 +287,15 @@ if(SFIZZ_SHARED) COMPONENT "development") endif() endif() + +# Generic library alias +add_library(sfizz::sfizz ALIAS sfizz_static) + +# Windows installer +if(WIN32) + include(VSTConfig) + configure_file(${PROJECT_SOURCE_DIR}/scripts/innosetup.iss.in ${PROJECT_BINARY_DIR}/innosetup.iss @ONLY) +endif() + +# Doxygen +configure_file(${PROJECT_SOURCE_DIR}/scripts/doxygen/Doxyfile.in ${PROJECT_SOURCE_DIR}/Doxyfile @ONLY) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 6b39bbf7..b86bf76f 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -32,6 +32,7 @@ #include "Config.h" #include "Debug.h" #include "Oversampler.h" +#include #include "absl/types/span.h" #include "absl/strings/match.h" #include "absl/memory/memory.h" @@ -44,7 +45,6 @@ #else #include #endif -#include "threadpool/ThreadPool.h" using namespace std::placeholders; static std::weak_ptr globalThreadPoolWeakPtr; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8d4d34a2..83370842 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -48,9 +48,8 @@ set(SFIZZ_TEST_SOURCES ) add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES}) -target_link_libraries(sfizz_tests PRIVATE sfizz::sfizz sfizz::jsl) +target_link_libraries(sfizz_tests PRIVATE sfizz::internal sfizz::jsl) sfizz_enable_lto_if_needed(sfizz_tests) sfizz_enable_fast_math(sfizz_tests) -# target_link_libraries(sfizz_tests PRIVATE absl::strings absl::str_format absl::flat_hash_map cnpy absl::span absl::algorithm) file(COPY "." DESTINATION ${CMAKE_BINARY_DIR}/tests) From f3c1b664dddf48b43d9c4ee23a14f42bf420a0c4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 13:56:52 +0100 Subject: [PATCH 155/668] Remove project() where not necessary --- benchmarks/CMakeLists.txt | 2 -- clients/CMakeLists.txt | 2 -- tests/CMakeLists.txt | 2 -- 3 files changed, 6 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index c73e23cf..209faaf5 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,5 +1,3 @@ -project(sfizz) - # Check SIMD include(SfizzSIMDSourceFiles) set(BENCHMARK_SIMD_SOURCES) diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index 5c59c26a..633dc727 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -1,5 +1,3 @@ -project(sfizz) - if(SFIZZ_JACK) find_package(PkgConfig REQUIRED) pkg_check_modules(JACK "jack" REQUIRED) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 83370842..15c1d0d6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,8 +1,6 @@ ############################### # Test application -project(sfizz) - set(SFIZZ_TEST_SOURCES DirectRegionT.cpp RegionValuesT.cpp From a3f93f5d0b41bdbf6a18c763e4d8e743d7fbf05d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 14:11:57 +0100 Subject: [PATCH 156/668] Reorganize the dependency checking --- CMakeLists.txt | 1 + clients/CMakeLists.txt | 14 +- cmake/SfizzConfig.cmake | 109 ------------ cmake/SfizzDeps.cmake | 165 ++++++++++++++++++ demos/CMakeLists.txt | 42 ++--- devtools/CMakeLists.txt | 14 +- .../external => external}/fmidi/LICENSE.md | 0 .../fmidi/sources/fmidi/fmidi.h | 0 .../fmidi/sources/fmidi/fmidi_mini.cpp | 0 src/CMakeLists.txt | 3 - src/external/cpuid/CMakeLists.txt | 7 - src/external/kiss_fft/CMakeLists.txt | 13 -- 12 files changed, 187 insertions(+), 181 deletions(-) create mode 100644 cmake/SfizzDeps.cmake rename {clients/external => external}/fmidi/LICENSE.md (100%) rename {clients/external => external}/fmidi/sources/fmidi/fmidi.h (100%) rename {clients/external => external}/fmidi/sources/fmidi/fmidi_mini.cpp (100%) delete mode 100644 src/external/cpuid/CMakeLists.txt delete mode 100644 src/external/kiss_fft/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 83c8c5a5..e26cc1bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ option (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically [default: OFF]" option (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds [default: OFF]" OFF) include (SfizzConfig) +include (SfizzDeps) # Don't use IPO in non Release builds include (CheckIPO) diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index 633dc727..a48af11a 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -1,24 +1,12 @@ if(SFIZZ_JACK) - find_package(PkgConfig REQUIRED) - pkg_check_modules(JACK "jack" REQUIRED) - link_directories(${JACK_LIBRARY_DIRS}) - add_executable(sfizz_jack MidiHelpers.h jack_client.cpp) - target_include_directories(sfizz_jack PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_jack PRIVATE sfizz::sfizz absl::flags_parse ${JACK_LIBRARIES}) + target_link_libraries(sfizz_jack PRIVATE sfizz::sfizz sfizz::jack absl::flags_parse) sfizz_enable_lto_if_needed(sfizz_jack) install(TARGETS sfizz_jack DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "jack" OPTIONAL) endif() if(SFIZZ_RENDER) - add_library(sfizz_fmidi STATIC - "external/fmidi/sources/fmidi/fmidi.h" - "external/fmidi/sources/fmidi/fmidi_mini.cpp") - add_library(sfizz::fmidi ALIAS sfizz_fmidi) - target_include_directories(sfizz_fmidi PUBLIC "external/fmidi/sources") - target_compile_definitions(sfizz_fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1") - add_executable(sfizz_render MidiHelpers.h sfizz_render.cpp) target_link_libraries(sfizz_render PRIVATE sfizz::internal sfizz::fmidi sfizz::sndfile sfizz::cxxopts) sfizz_enable_lto_if_needed(sfizz_render) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 4b6727c4..56580ed3 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -1,6 +1,5 @@ include(CMakeDependentOption) include(CheckCXXCompilerFlag) -include(CheckLibraryExists) include(GNUWarnings) set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used") @@ -30,26 +29,6 @@ if(WIN32) add_compile_definitions(NOMINMAX) endif() -# Find macOS system libraries -if(APPLE) - find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation") - find_library(APPLE_FOUNDATION_LIBRARY "Foundation") - find_library(APPLE_COCOA_LIBRARY "Cocoa") - find_library(APPLE_CARBON_LIBRARY "Carbon") - find_library(APPLE_OPENGL_LIBRARY "OpenGL") - find_library(APPLE_ACCELERATE_LIBRARY "Accelerate") - find_library(APPLE_QUARTZCORE_LIBRARY "QuartzCore") - find_library(APPLE_AUDIOTOOLBOX_LIBRARY "AudioToolbox") - find_library(APPLE_AUDIOUNIT_LIBRARY "AudioUnit") - find_library(APPLE_COREAUDIO_LIBRARY "CoreAudio") - find_library(APPLE_COREMIDI_LIBRARY "CoreMIDI") - # See https://stackoverflow.com/a/54103956 - # and https://stackoverflow.com/a/21692023 - # Apparently this is not needed in Travis CI using addons - # but it is in Appveyor instead - list(APPEND CMAKE_PREFIX_PATH /usr/local) -endif() - # The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio... # see https://gitlab.kitware.com/cmake/cmake/issues/15170 @@ -90,48 +69,6 @@ function(sfizz_enable_fast_math NAME) endif() endfunction() -# The jsl utility library for C++ -add_library(sfizz_jsl INTERFACE) -add_library(sfizz::jsl ALIAS sfizz_jsl) -target_include_directories(sfizz_jsl INTERFACE "external/jsl/include") - -# The cxxopts library -add_library(sfizz_cxxopts INTERFACE) -add_library(sfizz::cxxopts ALIAS sfizz_cxxopts) -target_include_directories(sfizz_cxxopts INTERFACE "external/cxxopts") - -# The sndfile library -if(SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) - add_library(sfizz_sndfile INTERFACE) - add_library(sfizz::sndfile ALIAS sfizz_sndfile) - if(SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - find_package(SndFile CONFIG REQUIRED) - find_path(SNDFILE_INCLUDE_DIR "sndfile.hh") - target_include_directories(sfizz_sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}") - target_link_libraries(sfizz_sndfile INTERFACE SndFile::sndfile) - else() - find_package(PkgConfig REQUIRED) - pkg_check_modules(SNDFILE "sndfile" REQUIRED) - target_include_directories(sfizz_sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS}) - if(SFIZZ_STATIC_DEPENDENCIES) - target_link_libraries(sfizz_sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES}) - else() - target_link_libraries(sfizz_sndfile INTERFACE ${SNDFILE_LIBRARIES}) - endif() - link_directories(${SNDFILE_LIBRARY_DIRS}) - endif() -endif() - -# The st_audiofile library -if(SFIZZ_USE_SNDFILE) - set(ST_AUDIO_FILE_USE_SNDFILE ON CACHE BOOL "" FORCE) - set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "sfizz::sndfile" CACHE STRING "" FORCE) -else() - set(ST_AUDIO_FILE_USE_SNDFILE OFF CACHE BOOL "" FORCE) - set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "" CACHE STRING "" FORCE) -endif() -add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL) - # If we build with Clang, optionally use libc++. Enabled by default on Apple OS. cmake_dependent_option(USE_LIBCPP "Use libc++ with clang" "${APPLE}" "CMAKE_CXX_COMPILER_ID MATCHES Clang" OFF) @@ -142,49 +79,6 @@ if(USE_LIBCPP) add_link_options(-lc++abi) # New command on CMake master, not in 3.12 release endif() -add_library(sfizz_pugixml STATIC "src/external/pugixml/src/pugixml.cpp") -add_library(sfizz::pugixml ALIAS sfizz_pugixml) -target_include_directories(sfizz_pugixml PUBLIC "src/external/pugixml/src") - -add_library(sfizz_spline STATIC "src/external/spline/spline/spline.cpp") -add_library(sfizz::spline ALIAS sfizz_spline) -target_include_directories(sfizz_spline PUBLIC "src/external/spline") - -add_library(sfizz_tunings STATIC "src/external/tunings/src/Tunings.cpp") -add_library(sfizz::tunings ALIAS sfizz_tunings) -target_include_directories(sfizz_tunings PUBLIC "src/external/tunings/include") - -add_library(sfizz_hiir INTERFACE) -add_library(sfizz::hiir ALIAS sfizz_hiir) -target_include_directories(sfizz_hiir INTERFACE "src/external/hiir") - -add_library(sfizz_threadpool INTERFACE) -add_library(sfizz::threadpool ALIAS sfizz_threadpool) -target_include_directories(sfizz_threadpool INTERFACE "external/threadpool") - -add_library(sfizz_atomic_queue INTERFACE) -add_library(sfizz::atomic_queue ALIAS sfizz_atomic_queue) -target_include_directories(sfizz_atomic_queue INTERFACE "external/atomic_queue/include") - -add_library(sfizz_filesystem INTERFACE) -add_library(sfizz::filesystem ALIAS sfizz_filesystem) -target_include_directories(sfizz_filesystem INTERFACE "external/filesystem/include") - -add_library(sfizz_atomic INTERFACE) -add_library(sfizz::atomic ALIAS sfizz_atomic) -if(UNIX AND NOT APPLE) - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic") - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" "int main() { return 0; }") - try_compile(SFIZZ_LINK_LIBATOMIC "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic" - SOURCES "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" - LINK_LIBRARIES "atomic") - if(SFIZZ_LINK_LIBATOMIC) - target_link_libraries(sfizz_atomic INTERFACE "atomic") - endif() -else() - set(SFIZZ_LINK_LIBATOMIC FALSE) -endif() - # Don't show build information when building a different project function(show_build_info_if_needed) if(CMAKE_PROJECT_NAME STREQUAL "sfizz") @@ -204,7 +98,6 @@ Build tests: ${SFIZZ_TESTS} Use sndfile: ${SFIZZ_USE_SNDFILE} Use vcpkg: ${SFIZZ_USE_VCPKG} Statically link dependencies: ${SFIZZ_STATIC_DEPENDENCIES} -Link libatomic: ${SFIZZ_LINK_LIBATOMIC} Use clang libc++: ${USE_LIBCPP} Release asserts: ${SFIZZ_RELEASE_ASSERTS} @@ -217,5 +110,3 @@ Compiler CXX min size flags: ${CMAKE_CXX_FLAGS_MINSIZEREL} ") endif() endfunction() - -find_package(Threads REQUIRED) diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake new file mode 100644 index 00000000..a5dcee06 --- /dev/null +++ b/cmake/SfizzDeps.cmake @@ -0,0 +1,165 @@ +# Find system threads +find_package(Threads REQUIRED) + +# Find macOS system libraries +if(APPLE) + find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation") + find_library(APPLE_FOUNDATION_LIBRARY "Foundation") + find_library(APPLE_COCOA_LIBRARY "Cocoa") + find_library(APPLE_CARBON_LIBRARY "Carbon") + find_library(APPLE_OPENGL_LIBRARY "OpenGL") + find_library(APPLE_ACCELERATE_LIBRARY "Accelerate") + find_library(APPLE_QUARTZCORE_LIBRARY "QuartzCore") + find_library(APPLE_AUDIOTOOLBOX_LIBRARY "AudioToolbox") + find_library(APPLE_AUDIOUNIT_LIBRARY "AudioUnit") + find_library(APPLE_COREAUDIO_LIBRARY "CoreAudio") + find_library(APPLE_COREMIDI_LIBRARY "CoreMIDI") +endif() + +# Set up macOS library paths +if(APPLE) + # See https://stackoverflow.com/a/54103956 + # and https://stackoverflow.com/a/21692023 + # Apparently this is not needed in Travis CI using addons + # but it is in Appveyor instead + list(APPEND CMAKE_PREFIX_PATH /usr/local) +endif() + +# The jsl utility library for C++ +add_library(sfizz_jsl INTERFACE) +add_library(sfizz::jsl ALIAS sfizz_jsl) +target_include_directories(sfizz_jsl INTERFACE "external/jsl/include") + +# The cxxopts library +add_library(sfizz_cxxopts INTERFACE) +add_library(sfizz::cxxopts ALIAS sfizz_cxxopts) +target_include_directories(sfizz_cxxopts INTERFACE "external/cxxopts") + +# The sndfile library +if(SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_BENCHMARKS OR SFIZZ_RENDER) + add_library(sfizz_sndfile INTERFACE) + add_library(sfizz::sndfile ALIAS sfizz_sndfile) + if(SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + find_package(SndFile CONFIG REQUIRED) + find_path(SNDFILE_INCLUDE_DIR "sndfile.hh") + target_include_directories(sfizz_sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}") + target_link_libraries(sfizz_sndfile INTERFACE SndFile::sndfile) + else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(SNDFILE "sndfile" REQUIRED) + target_include_directories(sfizz_sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS}) + if(SFIZZ_STATIC_DEPENDENCIES) + target_link_libraries(sfizz_sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES}) + else() + target_link_libraries(sfizz_sndfile INTERFACE ${SNDFILE_LIBRARIES}) + endif() + link_directories(${SNDFILE_LIBRARY_DIRS}) + endif() +endif() + +# The st_audiofile library +if(SFIZZ_USE_SNDFILE) + set(ST_AUDIO_FILE_USE_SNDFILE ON CACHE BOOL "" FORCE) + set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "sfizz::sndfile" CACHE STRING "" FORCE) +else() + set(ST_AUDIO_FILE_USE_SNDFILE OFF CACHE BOOL "" FORCE) + set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "" CACHE STRING "" FORCE) +endif() +add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL) + +# The pugixml library +add_library(sfizz_pugixml STATIC "src/external/pugixml/src/pugixml.cpp") +add_library(sfizz::pugixml ALIAS sfizz_pugixml) +target_include_directories(sfizz_pugixml PUBLIC "src/external/pugixml/src") + +# The spline library +add_library(sfizz_spline STATIC "src/external/spline/spline/spline.cpp") +add_library(sfizz::spline ALIAS sfizz_spline) +target_include_directories(sfizz_spline PUBLIC "src/external/spline") + +# The tunings library +add_library(sfizz_tunings STATIC "src/external/tunings/src/Tunings.cpp") +add_library(sfizz::tunings ALIAS sfizz_tunings) +target_include_directories(sfizz_tunings PUBLIC "src/external/tunings/include") + +# The hiir library +add_library(sfizz_hiir INTERFACE) +add_library(sfizz::hiir ALIAS sfizz_hiir) +target_include_directories(sfizz_hiir INTERFACE "src/external/hiir") + +# The kissfft library +add_library(sfizz_kissfft STATIC + "src/external/kiss_fft/kiss_fft.c" + "src/external/kiss_fft/tools/kiss_fftr.c") +add_library(sfizz::kissfft ALIAS sfizz_kissfft) +target_include_directories(sfizz_kissfft + PUBLIC "src/external/kiss_fft" + PUBLIC "src/external/kiss_fft/tools") + +# The cpuid library +add_library(sfizz_cpuid STATIC + "src/external/cpuid/src/cpuid/cpuinfo.cpp" + "src/external/cpuid/src/cpuid/version.cpp") +add_library(sfizz::cpuid ALIAS sfizz_cpuid) +set_property(TARGET sfizz_cpuid PROPERTY CXX_STANDARD 11) +target_include_directories(sfizz_cpuid + PUBLIC "src/external/cpuid/src" + PRIVATE "src/external/cpuid/platform/src") + +# The threadpool library +add_library(sfizz_threadpool INTERFACE) +add_library(sfizz::threadpool ALIAS sfizz_threadpool) +target_include_directories(sfizz_threadpool INTERFACE "external/threadpool") + +# The atomic_queue library +add_library(sfizz_atomic_queue INTERFACE) +add_library(sfizz::atomic_queue ALIAS sfizz_atomic_queue) +target_include_directories(sfizz_atomic_queue INTERFACE "external/atomic_queue/include") + +# The ghc::filesystem library +add_library(sfizz_filesystem INTERFACE) +add_library(sfizz::filesystem ALIAS sfizz_filesystem) +target_include_directories(sfizz_filesystem INTERFACE "external/filesystem/include") + +# The atomic library +add_library(sfizz_atomic INTERFACE) +add_library(sfizz::atomic ALIAS sfizz_atomic) +if(UNIX AND NOT APPLE) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" "int main() { return 0; }") + try_compile(SFIZZ_LINK_LIBATOMIC "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic" + SOURCES "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" + LINK_LIBRARIES "atomic") + if(SFIZZ_LINK_LIBATOMIC) + target_link_libraries(sfizz_atomic INTERFACE "atomic") + endif() +endif() + +# The jack library +if(SFIZZ_JACK) + find_package(PkgConfig REQUIRED) + pkg_check_modules(JACK "jack" REQUIRED) +elseif() + find_package(PkgConfig) + if(PKGCONFIG_FOUND) + pkg_check_modules(JACK "jack") + endif() +endif() +if(JACK_FOUND) + add_library(sfizz_jacklib INTERFACE) + add_library(sfizz::jack ALIAS sfizz_jacklib) + target_include_directories(sfizz_jacklib INTERFACE ${JACK_INCLUDE_DIRS}) + target_link_libraries(sfizz_jacklib INTERFACE ${JACK_LIBRARIES}) + link_directories(${JACK_LIBRARY_DIRS}) +endif() + +# The Qt library +find_package(Qt5 COMPONENTS Widgets) + +# The fmidi library +add_library(sfizz_fmidi STATIC + "external/fmidi/sources/fmidi/fmidi.h" + "external/fmidi/sources/fmidi/fmidi_mini.cpp") +add_library(sfizz::fmidi ALIAS sfizz_fmidi) +target_include_directories(sfizz_fmidi PUBLIC "external/fmidi/sources") +target_compile_definitions(sfizz_fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1") diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index ff0be6ff..22e8b319 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -1,32 +1,22 @@ -find_package(PkgConfig) -if(PKGCONFIG_FOUND) - pkg_check_modules(JACK "jack") +if(TARGET Qt5::Widgets AND TARGET sfizz::jack) + add_executable(sfizz_demo_filters DemoFilters.cpp) + target_link_libraries(sfizz_demo_filters PRIVATE sfizz::internal sfizz::jack Qt5::Widgets) + set_target_properties(sfizz_demo_filters PROPERTIES AUTOUIC ON) + + add_executable(sfizz_demo_smooth DemoSmooth.cpp) + target_link_libraries(sfizz_demo_smooth PRIVATE sfizz::internal sfizz::jack Qt5::Widgets) + set_target_properties(sfizz_demo_smooth PROPERTIES AUTOUIC ON) + + add_executable(sfizz_demo_stereo DemoStereo.cpp) + target_link_libraries(sfizz_demo_stereo PRIVATE sfizz::internal sfizz::jack Qt5::Widgets) + set_target_properties(sfizz_demo_stereo PROPERTIES AUTOUIC ON) + + add_executable(sfizz_demo_wavetables DemoWavetables.cpp) + target_link_libraries(sfizz_demo_wavetables PRIVATE sfizz::internal sfizz::jack Qt5::Widgets) + set_target_properties(sfizz_demo_wavetables PROPERTIES AUTOUIC ON) endif() -find_package(Qt5 COMPONENTS Widgets) if(TARGET Qt5::Widgets) - if(JACK_FOUND) - add_executable(sfizz_demo_filters DemoFilters.cpp) - target_include_directories(sfizz_demo_filters PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_filters PRIVATE sfizz::internal Qt5::Widgets ${JACK_LIBRARIES}) - set_target_properties(sfizz_demo_filters PROPERTIES AUTOUIC ON) - - add_executable(sfizz_demo_smooth DemoSmooth.cpp) - target_include_directories(sfizz_demo_smooth PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_smooth PRIVATE sfizz::internal Qt5::Widgets ${JACK_LIBRARIES}) - set_target_properties(sfizz_demo_smooth PROPERTIES AUTOUIC ON) - - add_executable(sfizz_demo_stereo DemoStereo.cpp) - target_include_directories(sfizz_demo_stereo PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_stereo PRIVATE sfizz::internal Qt5::Widgets ${JACK_LIBRARIES}) - set_target_properties(sfizz_demo_stereo PROPERTIES AUTOUIC ON) - - add_executable(sfizz_demo_wavetables DemoWavetables.cpp) - target_include_directories(sfizz_demo_wavetables PRIVATE ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_demo_wavetables PRIVATE sfizz::internal Qt5::Widgets ${JACK_LIBRARIES}) - set_target_properties(sfizz_demo_wavetables PROPERTIES AUTOUIC ON) - endif() - add_executable(sfizz_demo_parser DemoParser.cpp) target_link_libraries(sfizz_demo_parser PRIVATE sfizz::parser Qt5::Widgets) set_target_properties(sfizz_demo_parser PROPERTIES AUTOUIC ON) diff --git a/devtools/CMakeLists.txt b/devtools/CMakeLists.txt index ac2790e6..d9abd170 100644 --- a/devtools/CMakeLists.txt +++ b/devtools/CMakeLists.txt @@ -1,18 +1,12 @@ ############################### # Developer tools -find_package(PkgConfig) -if(PKGCONFIG_FOUND) -pkg_check_modules(JACK "jack") -endif() -find_package(Qt5 COMPONENTS Widgets) - -if(JACK_FOUND AND TARGET Qt5::Widgets) +if(TARGET sfizz::jack AND TARGET Qt5::Widgets) add_executable(sfizz_capture_eg CaptureEG.h CaptureEG.cpp) - target_include_directories(sfizz_capture_eg PRIVATE . ${JACK_INCLUDE_DIRS}) - target_link_libraries(sfizz_capture_eg PRIVATE sfizz::sndfile Qt5::Widgets ${JACK_LIBRARIES}) + target_include_directories(sfizz_capture_eg PRIVATE .) + target_link_libraries(sfizz_capture_eg PRIVATE sfizz::sndfile Qt5::Widgets sfizz::jack) set_target_properties(sfizz_capture_eg PROPERTIES AUTOUIC ON) endif() add_executable(sfizz_preprocessor Preprocessor.cpp) -target_link_libraries(sfizz_preprocessor PRIVATE sfizz_parser sfizz::cxxopts) +target_link_libraries(sfizz_preprocessor PRIVATE sfizz::parser sfizz::cxxopts) diff --git a/clients/external/fmidi/LICENSE.md b/external/fmidi/LICENSE.md similarity index 100% rename from clients/external/fmidi/LICENSE.md rename to external/fmidi/LICENSE.md diff --git a/clients/external/fmidi/sources/fmidi/fmidi.h b/external/fmidi/sources/fmidi/fmidi.h similarity index 100% rename from clients/external/fmidi/sources/fmidi/fmidi.h rename to external/fmidi/sources/fmidi/fmidi.h diff --git a/clients/external/fmidi/sources/fmidi/fmidi_mini.cpp b/external/fmidi/sources/fmidi/fmidi_mini.cpp similarity index 100% rename from clients/external/fmidi/sources/fmidi/fmidi_mini.cpp rename to external/fmidi/sources/fmidi/fmidi_mini.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ecc2376c..bf1c3edd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,5 @@ include(GNUInstallDirs) -add_subdirectory(external/kiss_fft) -add_subdirectory(external/cpuid) - set(FAUST_FILES sfizz/dsp/filters/filters_modulable.dsp sfizz/dsp/filters/rbj_filters.dsp diff --git a/src/external/cpuid/CMakeLists.txt b/src/external/cpuid/CMakeLists.txt deleted file mode 100644 index c2a25fe5..00000000 --- a/src/external/cpuid/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required (VERSION 3.5) -project(sfizz_cpuid) - -add_library(sfizz_cpuid STATIC src/cpuid/cpuinfo.cpp src/cpuid/version.cpp) -add_library(sfizz::cpuid ALIAS sfizz_cpuid) -set_property(TARGET sfizz_cpuid PROPERTY CXX_STANDARD 11) -target_include_directories(sfizz_cpuid PUBLIC src PRIVATE platform/src) diff --git a/src/external/kiss_fft/CMakeLists.txt b/src/external/kiss_fft/CMakeLists.txt deleted file mode 100644 index e43afb1d..00000000 --- a/src/external/kiss_fft/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# This CMake build file is part of sfizz - -cmake_minimum_required(VERSION 3.5) - -project(sfizz_kissfft VERSION "1.3.0" LANGUAGES C) - -add_library(sfizz_kissfft STATIC - kiss_fft.c - tools/kiss_fftr.c) -add_library(sfizz::kissfft ALIAS sfizz_kissfft) -target_include_directories(sfizz_kissfft - PUBLIC "." - PUBLIC "tools") From 1f696e943e36bbffd68754538c03c847d2de7832 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 14:32:55 +0100 Subject: [PATCH 157/668] Move the libsamplerate library check --- benchmarks/CMakeLists.txt | 12 ------------ cmake/SfizzDeps.cmake | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 209faaf5..f9e3732c 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -4,18 +4,6 @@ set(BENCHMARK_SIMD_SOURCES) sfizz_add_simd_sources(BENCHMARK_SIMD_SOURCES "../src") find_package(benchmark CONFIG REQUIRED) -# Check libsamplerate -find_library(SAMPLERATE_LIBRARY "samplerate") -find_path(SAMPLERATE_INCLUDE_DIR "samplerate.h") -message(STATUS "Checking samplerate library: ${SAMPLERATE_LIBRARY}") -message(STATUS "Checking samplerate includes: ${SAMPLERATE_INCLUDE_DIR}") -if(SAMPLERATE_LIBRARY AND SAMPLERATE_INCLUDE_DIR) - add_library(sfizz_samplerate INTERFACE) - add_library(sfizz::samplerate ALIAS sfizz_samplerate) - target_include_directories(sfizz_samplerate INTERFACE "${SAMPLERATE_INCLUDE_DIR}") - target_link_libraries(sfizz_samplerate INTERFACE "${SAMPLERATE_LIBRARY}") -endif() - add_library(bm_simd STATIC ${BENCHMARK_SIMD_SOURCES}) target_link_libraries(bm_simd PRIVATE absl::span sfizz::cpuid) add_library(bm_ftz STATIC ../src/sfizz/ScopedFTZ.cpp) diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index a5dcee06..24ce0916 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -163,3 +163,28 @@ add_library(sfizz_fmidi STATIC add_library(sfizz::fmidi ALIAS sfizz_fmidi) target_include_directories(sfizz_fmidi PUBLIC "external/fmidi/sources") target_compile_definitions(sfizz_fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1") + +# The samplerate library +find_package(PkgConfig) +if(PKGCONFIG_FOUND) + pkg_check_modules(SAMPLERATE "samplerate") + if(SAMPLERATE_FOUND) + add_library(sfizz_samplerate INTERFACE) + add_library(sfizz::samplerate ALIAS sfizz_samplerate) + target_include_directories(sfizz_samplerate INTERFACE ${SAMPLERATE_INCLUDE_DIRS}) + target_link_libraries(sfizz_samplerate INTERFACE ${SAMPLERATE_LIBRARIES}) + link_directories(${SAMPLERATE_LIBRARY_DIRS}) + endif() +endif() +if(NOT TARGET sfizz::samplerate) + find_library(SAMPLERATE_LIBRARY "samplerate") + find_path(SAMPLERATE_INCLUDE_DIR "samplerate.h") + message(STATUS "Checking samplerate library: ${SAMPLERATE_LIBRARY}") + message(STATUS "Checking samplerate includes: ${SAMPLERATE_INCLUDE_DIR}") + if(SAMPLERATE_LIBRARY AND SAMPLERATE_INCLUDE_DIR) + add_library(sfizz_samplerate INTERFACE) + add_library(sfizz::samplerate ALIAS sfizz_samplerate) + target_include_directories(sfizz_samplerate INTERFACE "${SAMPLERATE_INCLUDE_DIR}") + target_link_libraries(sfizz_samplerate INTERFACE "${SAMPLERATE_LIBRARY}") + endif() +endif() From c33b9a990ef55b8f5d9f0a6a2c1bbfdaff7014c8 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 14:40:19 +0100 Subject: [PATCH 158/668] Additional cleanup in benchmarks --- benchmarks/CMakeLists.txt | 33 ++++----------------------------- cmake/SfizzDeps.cmake | 5 +++++ src/CMakeLists.txt | 4 ++-- 3 files changed, 11 insertions(+), 31 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index f9e3732c..0c06b046 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,23 +1,8 @@ -# Check SIMD -include(SfizzSIMDSourceFiles) -set(BENCHMARK_SIMD_SOURCES) -sfizz_add_simd_sources(BENCHMARK_SIMD_SOURCES "../src") -find_package(benchmark CONFIG REQUIRED) - -add_library(bm_simd STATIC ${BENCHMARK_SIMD_SOURCES}) -target_link_libraries(bm_simd PRIVATE absl::span sfizz::cpuid) -add_library(bm_ftz STATIC ../src/sfizz/ScopedFTZ.cpp) - macro(sfizz_add_benchmark TARGET) add_executable("${TARGET}" ${ARGN}) target_link_libraries("${TARGET}" - PRIVATE sfizz::filesystem absl::span absl::algorithm - PRIVATE benchmark::benchmark benchmark::benchmark_main - PRIVATE bm_simd bm_ftz) - if(LIBATOMIC_FOUND) - target_link_libraries("${TARGET}" PRIVATE atomic) - endif() - target_include_directories("${TARGET}" PRIVATE ../src/sfizz) + PRIVATE sfizz::internal sfizz::filesystem absl::span absl::algorithm + PRIVATE benchmark::benchmark benchmark::benchmark_main) sfizz_enable_fast_math("${TARGET}") endmacro() @@ -30,7 +15,6 @@ sfizz_add_benchmark(bm_gain BM_gain.cpp) sfizz_add_benchmark(bm_divide BM_divide.cpp) sfizz_add_benchmark(bm_ramp BM_ramp.cpp) sfizz_add_benchmark(bm_ADSR BM_ADSR.cpp) -target_link_libraries(bm_ADSR PRIVATE sfizz::internal) sfizz_add_benchmark(bm_add BM_add.cpp) sfizz_add_benchmark(bm_multiplyAdd BM_multiplyAdd.cpp) @@ -52,15 +36,12 @@ sfizz_add_benchmark(bm_clamp BM_clamp.cpp) sfizz_add_benchmark(bm_allWithin BM_allWithin.cpp) sfizz_add_benchmark(bm_logger BM_logger.cpp) -target_link_libraries(bm_logger PRIVATE sfizz::internal) sfizz_add_benchmark(bm_smoothers BM_smoothers.cpp) -target_link_libraries(bm_smoothers PRIVATE sfizz::internal) sfizz_add_benchmark(bm_powerFollower BM_powerFollower.cpp) -target_link_libraries(bm_powerFollower PRIVATE sfizz::internal) if(TARGET sfizz::samplerate) sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES}) -target_link_libraries(bm_resample PRIVATE sfizz::samplerate sfizz::sndfile sfizz::cpuid sfizz::hiir) +target_link_libraries(bm_resample PRIVATE sfizz::samplerate sfizz::sndfile sfizz::hiir) endif() sfizz_add_benchmark(bm_envelopes BM_envelopes.cpp) @@ -90,13 +71,7 @@ target_link_libraries(bm_filterModulation PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_filterStereoMono BM_filterStereoMono.cpp ../src/sfizz/SfzFilter.cpp) target_link_libraries(bm_filterStereoMono PRIVATE sfizz::sndfile) -sfizz_add_benchmark(bm_stringResonator BM_stringResonator.cpp - ../src/sfizz/effects/impl/ResonantArray.cpp - ../src/sfizz/effects/impl/ResonantArraySSE.cpp - ../src/sfizz/effects/impl/ResonantArrayAVX.cpp - ../src/sfizz/effects/impl/ResonantString.cpp - ../src/sfizz/effects/impl/ResonantStringSSE.cpp - ../src/sfizz/effects/impl/ResonantStringAVX.cpp) +sfizz_add_benchmark(bm_stringResonator BM_stringResonator.cpp) target_link_libraries(bm_stringResonator PRIVATE sfizz::sndfile) add_custom_target(sfizz_benchmarks) diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 24ce0916..1348b558 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -188,3 +188,8 @@ if(NOT TARGET sfizz::samplerate) target_link_libraries(sfizz_samplerate INTERFACE "${SAMPLERATE_LIBRARY}") endif() endif() + +# The benchmark library +if(SFIZZ_BENCHMARKS) + find_package(benchmark CONFIG REQUIRED) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bf1c3edd..df68a26b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -239,7 +239,7 @@ target_link_libraries(sfizz_messaging PUBLIC absl::strings) add_library(sfizz_internal STATIC) add_library(sfizz::internal ALIAS sfizz_internal) target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES}) -target_include_directories(sfizz_internal PUBLIC .) +target_include_directories(sfizz_internal PUBLIC "." "sfizz") target_link_libraries(sfizz_internal PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) @@ -251,7 +251,7 @@ if(WIN32) target_compile_definitions(sfizz_internal PRIVATE _USE_MATH_DEFINES) endif() if(SFIZZ_RELEASE_ASSERTS) - target_compile_definitions(sfizz_internal PRIVATE "SFIZZ_ENABLE_RELEASE_ASSERT=1") + target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_ENABLE_RELEASE_ASSERT=1") endif() sfizz_enable_fast_math(sfizz_internal) From b64d2146c2aad612f5e95a6813187b754c10eb31 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 18 Dec 2020 21:23:24 +0100 Subject: [PATCH 159/668] Allow the preprocessor to output as xml --- devtools/CMakeLists.txt | 2 +- devtools/Preprocessor.cpp | 42 +++++++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/devtools/CMakeLists.txt b/devtools/CMakeLists.txt index d9abd170..352c5cd1 100644 --- a/devtools/CMakeLists.txt +++ b/devtools/CMakeLists.txt @@ -9,4 +9,4 @@ if(TARGET sfizz::jack AND TARGET Qt5::Widgets) endif() add_executable(sfizz_preprocessor Preprocessor.cpp) -target_link_libraries(sfizz_preprocessor PRIVATE sfizz::parser sfizz::cxxopts) +target_link_libraries(sfizz_preprocessor PRIVATE sfizz::parser sfizz::pugixml sfizz::cxxopts) diff --git a/devtools/Preprocessor.cpp b/devtools/Preprocessor.cpp index 9476d356..b6b96036 100644 --- a/devtools/Preprocessor.cpp +++ b/devtools/Preprocessor.cpp @@ -13,10 +13,18 @@ */ #include "parser/Parser.h" +#include #include #include #include +namespace { + enum Mode { OutputSFZ, OutputXML }; + Mode g_mode = OutputSFZ; + + pugi::xml_document g_xml_doc; +} + class MyParserListener : public sfz::Parser::Listener { public: explicit MyParserListener(sfz::Parser& parser) @@ -27,10 +35,20 @@ public: protected: void onParseFullBlock(const std::string& header, const std::vector& opcodes) override { - std::cout << '\n'; - std::cout << '<' << header << '>' << '\n'; - for (const sfz::Opcode& opc : opcodes) - std::cout << opc.opcode << '=' << opc.value << '\n'; + if (g_mode == OutputSFZ) { + std::cout << '\n'; + std::cout << '<' << header << '>' << '\n'; + for (const sfz::Opcode& opc : opcodes) + std::cout << opc.opcode << '=' << opc.value << '\n'; + } + else if (g_mode == OutputXML) { + pugi::xml_node block_node = g_xml_doc.append_child(header.c_str()); + for (const sfz::Opcode& opc : opcodes) { + pugi::xml_node opcode_node = block_node.append_child("opcode"); + opcode_node.append_attribute("name").set_value(opc.opcode.c_str()); + opcode_node.append_attribute("value").set_value(opc.value.c_str()); + } + } } void onParseError(const sfz::SourceRange& range, const std::string& message) override @@ -58,6 +76,7 @@ int main(int argc, char *argv[]) options.add_options() ("D,define", "Add external definition", cxxopts::value>()) ("i,input", "Input SFZ file", cxxopts::value()) + ("m,mode", "Mode of operation (sfz, xml)", cxxopts::value()) ("h,help", "Print usage"); options.parse_positional({"input"}); @@ -81,6 +100,18 @@ int main(int argc, char *argv[]) return 1; } + if (result.count("mode")) { + const std::string& modeString = result["mode"].as(); + if (modeString == "sfz") + g_mode = OutputSFZ; + else if (modeString == "xml") + g_mode = OutputXML; + else { + std::cerr << "Unknown mode of operation: " << modeString << "\n"; + return 1; + } + } + const fs::path sfzFilePath { result["input"].as() }; sfz::Parser parser; @@ -106,5 +137,8 @@ int main(int argc, char *argv[]) if (parser.getErrorCount() > 0) return 1; + if (g_mode == OutputXML) + g_xml_doc.save(std::cout); + return 0; } From cbcc875aef05ca161a962e0e529c38ae149ffc45 Mon Sep 17 00:00:00 2001 From: redtide Date: Sat, 19 Dec 2020 16:38:51 +0100 Subject: [PATCH 160/668] Updated .gitignore for QtCreator IDE files --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b1f6f768..b9446b3c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ CMakeFiles/ cmake_install.cmake compile_commands.json *.a -*.txt.user +*.user* *.autosave /Doxyfile .DS_Store From 2f3ed1619718b1a197fa261f49d70f8081bd142f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 2 Jan 2021 20:05:44 +0100 Subject: [PATCH 161/668] Add gitattributes to ignore unused files --- .gitattributes | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.gitattributes b/.gitattributes index fac64928..94df7fba 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,30 @@ .*/** export-ignore appveyor.yml export-ignore /scripts/appveyor/** export-ignore + +/vst/external/VST_SDK/VST3_SDK/**/CMakeLists.txt export-ignore +/vst/external/VST_SDK/VST3_SDK/public.sdk/samples export-ignore +/vst/external/VST_SDK/VST3_SDK/public.sdk/source/vst/*wrapper/** export-ignore +/vst/external/VST_SDK/VST3_SDK/public.sdk/source/vst/interappaudio/** export-ignore +/vst/external/VST_SDK/VST3_SDK/public.sdk/source/vst/testsuite/** export-ignore +/vst/external/VST_SDK/VST3_SDK/public.sdk/source/vst/utility/test/** export-ignore + +/editor/external/vstgui4/**/CMakeLists.txt export-ignore +/editor/external/vstgui4/vstgui/Documentation/** export-ignore +/editor/external/vstgui4/vstgui/doxygen/** export-ignore +/editor/external/vstgui4/vstgui/standalone/** export-ignore +/editor/external/vstgui4/vstgui/tests/** export-ignore +/editor/external/vstgui4/vstgui/tools/** export-ignore +/editor/external/vstgui4/vstgui/uidescription/** export-ignore +/editor/external/vstgui4/vstgui/uidescription/icontroller.h -export-ignore +/editor/external/vstgui4/vstgui/vstgui_standalone* export-ignore +/editor/external/vstgui4/vstgui/vstgui_uidescription* export-ignore + +/external/st_audiofile/thirdparty/dr_libs/old/** export-ignore +/external/st_audiofile/thirdparty/dr_libs/tests/** export-ignore + +/external/filesystem/test/** export-ignore + +/external/abseil-cpp/conanfile.py export-ignore +/external/abseil-cpp/**/BUILD.bazel export-ignore +/external/abseil-cpp/ci/** export-ignore From 445b92a5fa3b5fc76b0f77e6c5b491c413a488d2 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 4 Jan 2021 02:04:43 +0100 Subject: [PATCH 162/668] Add copyright headers in source files --- editor/tools/layout-maker/sources/layout.h | 8 ++++++++ editor/tools/layout-maker/sources/main.cpp | 8 ++++++++ editor/tools/layout-maker/sources/reader.cpp | 8 ++++++++ editor/tools/layout-maker/sources/reader.h | 8 ++++++++ external/jsl/include/jsl/allocator | 7 +++++++ .../jsl/include/jsl/bits/allocator/aligned_allocator.tcc | 8 ++++++++ .../jsl/include/jsl/bits/allocator/ordinary_allocator.tcc | 8 ++++++++ .../jsl/include/jsl/bits/allocator/stdc_allocator.tcc | 8 ++++++++ 8 files changed, 63 insertions(+) diff --git a/editor/tools/layout-maker/sources/layout.h b/editor/tools/layout-maker/sources/layout.h index 35a1978e..d68627f5 100644 --- a/editor/tools/layout-maker/sources/layout.h +++ b/editor/tools/layout-maker/sources/layout.h @@ -1,3 +1,11 @@ +// -*- C++ -*- +// SPDX-License-Identifier: BSL-1.0 +// +// Copyright Jean Pierre Cimalando 2019-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// #pragma once #include #include diff --git a/editor/tools/layout-maker/sources/main.cpp b/editor/tools/layout-maker/sources/main.cpp index 06e5283b..31fc0bfa 100644 --- a/editor/tools/layout-maker/sources/main.cpp +++ b/editor/tools/layout-maker/sources/main.cpp @@ -1,3 +1,11 @@ +// -*- C++ -*- +// SPDX-License-Identifier: BSL-1.0 +// +// Copyright Jean Pierre Cimalando 2019-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// #include "layout.h" #include "reader.h" #include diff --git a/editor/tools/layout-maker/sources/reader.cpp b/editor/tools/layout-maker/sources/reader.cpp index 5890951b..eef4aaaa 100644 --- a/editor/tools/layout-maker/sources/reader.cpp +++ b/editor/tools/layout-maker/sources/reader.cpp @@ -1,3 +1,11 @@ +// -*- C++ -*- +// SPDX-License-Identifier: BSL-1.0 +// +// Copyright Jean Pierre Cimalando 2019-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// #include "reader.h" #include #include diff --git a/editor/tools/layout-maker/sources/reader.h b/editor/tools/layout-maker/sources/reader.h index 589bd307..3dc6b4ba 100644 --- a/editor/tools/layout-maker/sources/reader.h +++ b/editor/tools/layout-maker/sources/reader.h @@ -1,3 +1,11 @@ +// -*- C++ -*- +// SPDX-License-Identifier: BSL-1.0 +// +// Copyright Jean Pierre Cimalando 2019-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// #pragma once #include "layout.h" #include diff --git a/external/jsl/include/jsl/allocator b/external/jsl/include/jsl/allocator index e97c25a3..0fd48a0a 100644 --- a/external/jsl/include/jsl/allocator +++ b/external/jsl/include/jsl/allocator @@ -1,4 +1,11 @@ // -*- C++ -*- +// SPDX-License-Identifier: BSL-1.0 +// +// Copyright Jean Pierre Cimalando 2018-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// #pragma once #include #include diff --git a/external/jsl/include/jsl/bits/allocator/aligned_allocator.tcc b/external/jsl/include/jsl/bits/allocator/aligned_allocator.tcc index d42e6585..4bb3cfed 100644 --- a/external/jsl/include/jsl/bits/allocator/aligned_allocator.tcc +++ b/external/jsl/include/jsl/bits/allocator/aligned_allocator.tcc @@ -1,3 +1,11 @@ +// -*- C++ -*- +// SPDX-License-Identifier: BSL-1.0 +// +// Copyright Jean Pierre Cimalando 2018-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// #include "../../allocator" #include #if defined(_WIN32) diff --git a/external/jsl/include/jsl/bits/allocator/ordinary_allocator.tcc b/external/jsl/include/jsl/bits/allocator/ordinary_allocator.tcc index cfb54b03..2bab8c08 100644 --- a/external/jsl/include/jsl/bits/allocator/ordinary_allocator.tcc +++ b/external/jsl/include/jsl/bits/allocator/ordinary_allocator.tcc @@ -1,3 +1,11 @@ +// -*- C++ -*- +// SPDX-License-Identifier: BSL-1.0 +// +// Copyright Jean Pierre Cimalando 2018-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// #include "../../allocator" #include diff --git a/external/jsl/include/jsl/bits/allocator/stdc_allocator.tcc b/external/jsl/include/jsl/bits/allocator/stdc_allocator.tcc index 960ea5ad..6942cc77 100644 --- a/external/jsl/include/jsl/bits/allocator/stdc_allocator.tcc +++ b/external/jsl/include/jsl/bits/allocator/stdc_allocator.tcc @@ -1,3 +1,11 @@ +// -*- C++ -*- +// SPDX-License-Identifier: BSL-1.0 +// +// Copyright Jean Pierre Cimalando 2018-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// #include "../../allocator" #include From 767e350ee8cd896bdc5feca26715dfe959ab76b7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 21 Jan 2021 09:58:23 +0100 Subject: [PATCH 163/668] Hermite interpolator as default; has less HF attenuation --- src/sfizz/Voice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index fa6e4262..a759dee5 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1162,11 +1162,11 @@ void Voice::Impl::fillInterpolatedWithQuality( break; case 2: high: { -#if 1 +#if 0 // B-spline response has faster decay of aliasing, but not zero-crossings at integer positions constexpr auto itp = kInterpolatorBspline3; #else - // Hermite polynomial + // Hermite polynomial, has less pass-band attenuation constexpr auto itp = kInterpolatorHermite3; #endif fillInterpolated(source, dest, indices, coeffs, addingGains); From 7b81a5f86de0840685473cee6957a0def45d12d9 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 21 Jan 2021 21:54:54 +0100 Subject: [PATCH 164/668] Make tuning frequency editable by wheel --- editor/src/editor/EditIds.h | 1 + editor/src/editor/Editor.cpp | 1 + editor/src/editor/GUIComponents.cpp | 19 +++++++++++++++++++ editor/src/editor/GUIComponents.h | 1 + 4 files changed, 22 insertions(+) diff --git a/editor/src/editor/EditIds.h b/editor/src/editor/EditIds.h index 8645210a..1edec8b4 100644 --- a/editor/src/editor/EditIds.h +++ b/editor/src/editor/EditIds.h @@ -35,5 +35,6 @@ struct EditRange { constexpr EditRange() = default; constexpr EditRange(float def, float min, float max) : def(def), min(min), max(max) {} + float extent() const noexcept { return max - min; } static EditRange get(EditId id); }; diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index f6b16897..525689bf 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -636,6 +636,7 @@ void Editor::Impl::createFrameContents() static_cast(EditRange::get(EditId::ScalaRootKey).def) / 12); } adjustMinMaxToEditRange(tuningFrequencySlider_, EditId::TuningFrequency); + tuningFrequencySlider_->setWheelInc(0.1f / EditRange::get(EditId::TuningFrequency).extent()); adjustMinMaxToEditRange(stretchedTuningSlider_, EditId::StretchTuning); for (int value : {1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 224, 256}) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 803698dd..4e62a721 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -160,6 +160,7 @@ SValueMenu::SValueMenu(const CRect& bounds, IControlListener* listener, int32_t { setListener(listener); setTag(tag); + setWheelInc(0.0f); } CMenuItem* SValueMenu::addEntry(CMenuItem* item, float value, int32_t index) @@ -226,6 +227,24 @@ CMouseEventResult SValueMenu::onMouseDown(CPoint& where, const CButtonState& but return kMouseEventNotHandled; } +bool SValueMenu::onWheel(const CPoint& where, const CMouseWheelAxis& axis, const float& distance, const CButtonState& buttons) +{ + (void)where; + (void)buttons; + + if (axis != kMouseWheelAxisY) + return false; + + float wheelInc = getWheelInc(); + if (wheelInc != 0) { + float oldValue = getValue(); + setValueNormalized(getValueNormalized() + distance * wheelInc); + if (getValue() != oldValue) + valueChanged(); + } + return true; +} + void SValueMenu::onItemClicked(int32_t index) { float oldValue = getValue(); diff --git a/editor/src/editor/GUIComponents.h b/editor/src/editor/GUIComponents.h index e08ccf3d..8f497a15 100644 --- a/editor/src/editor/GUIComponents.h +++ b/editor/src/editor/GUIComponents.h @@ -94,6 +94,7 @@ public: protected: CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override; + bool onWheel(const CPoint& where, const CMouseWheelAxis& axis, const float& distance, const CButtonState& buttons) override; private: class MenuListener; From 2a82e5000bbd4c422f80fa24a97689a9c1fac20f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 22 Jan 2021 03:51:00 +0100 Subject: [PATCH 165/668] Update SValueMenu display after value change --- editor/src/editor/GUIComponents.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 4e62a721..16ad7dd9 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -239,8 +239,10 @@ bool SValueMenu::onWheel(const CPoint& where, const CMouseWheelAxis& axis, const if (wheelInc != 0) { float oldValue = getValue(); setValueNormalized(getValueNormalized() + distance * wheelInc); - if (getValue() != oldValue) + if (getValue() != oldValue) { valueChanged(); + invalid(); + } } return true; } @@ -249,8 +251,10 @@ void SValueMenu::onItemClicked(int32_t index) { float oldValue = getValue(); setValue(menuItemValues_[index]); - if (getValue() != oldValue) + if (getValue() != oldValue) { valueChanged(); + invalid(); + } } /// From 10935e7be87267761c60ec5b572f7b37a0004e8e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 30 Jan 2021 12:17:49 +0100 Subject: [PATCH 166/668] Permit loading SFZ which contain errors (Hindu Flute) --- src/sfizz/Synth.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index d951b39a..ef54fe98 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -492,8 +492,11 @@ bool Synth::loadSfzFile(const fs::path& file) fs::path realFile = fs::canonical(file, ec); impl.parser_.parseFile(ec ? file : realFile); - if (impl.parser_.getErrorCount() > 0) - return false; + // permissive parsing for compatibility + if (false) { + if (impl.parser_.getErrorCount() > 0) + return false; + } if (impl.regions_.empty()) return false; @@ -511,8 +514,11 @@ bool Synth::loadSfzString(const fs::path& path, absl::string_view text) impl.clear(); impl.parser_.parseString(path, text); - if (impl.parser_.getErrorCount() > 0) - return false; + // permissive parsing for compatibility + if (false) { + if (impl.parser_.getErrorCount() > 0) + return false; + } if (impl.regions_.empty()) return false; From 3a59fc77e970052a18ee9adee9fe01cd2a01cb56 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 31 Jan 2021 23:23:23 +0100 Subject: [PATCH 167/668] cmake improvement for benchmarks --- benchmarks/CMakeLists.txt | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 0c06b046..89d7c8e3 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,5 +1,9 @@ macro(sfizz_add_benchmark TARGET) + if (NOT TARGET sfizz_benchmarks) + add_custom_target(sfizz_benchmarks) + endif() add_executable("${TARGET}" ${ARGN}) + add_dependencies(sfizz_benchmarks "${TARGET}") target_link_libraries("${TARGET}" PRIVATE sfizz::internal sfizz::filesystem absl::span absl::algorithm PRIVATE benchmark::benchmark benchmark::benchmark_main) @@ -74,43 +78,9 @@ target_link_libraries(bm_filterStereoMono PRIVATE sfizz::sndfile) sfizz_add_benchmark(bm_stringResonator BM_stringResonator.cpp) target_link_libraries(bm_stringResonator PRIVATE sfizz::sndfile) -add_custom_target(sfizz_benchmarks) -add_dependencies(sfizz_benchmarks - bm_opf_high_vs_low - bm_write - bm_clock - bm_pointerIterationOrOffsets - bm_read - bm_mean - bm_meanSquared - bm_cumsum - bm_diff - bm_mathfuns - bm_gain - bm_divide - bm_ramp - bm_ADSR - bm_add - bm_logger - bm_subtract - bm_multiplyAdd - bm_readChunk - bm_resampleChunk - bm_envelopes - bm_wavfile - bm_flacfile - bm_filterModulation - bm_filterStereoMono - bm_stringResonator) - -if(TARGET bm_resample) - add_dependencies(sfizz_benchmarks bm_resample) -endif() - if(SFIZZ_SYSTEM_PROCESSOR MATCHES "armv7l") sfizz_add_benchmark(bm_pan_arm BM_pan_arm.cpp ../src/sfizz/Panning.cpp) target_link_libraries(bm_pan_arm PRIVATE sfizz::jsl) - add_dependencies(sfizz_benchmarks bm_pan_arm) endif() configure_file("sample.wav" "${CMAKE_BINARY_DIR}/benchmarks/sample1.wav" COPYONLY) From 75c169217d54ba649a1d520bb9e6f941246afc23 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 30 Jan 2021 18:26:34 +0100 Subject: [PATCH 168/668] Add the kaiser window helper --- cmake/SfizzDeps.cmake | 6 ++ external/cephes/LICENSE.txt | 119 +++++++++++++++++++++ external/cephes/src/chbevl.c | 82 +++++++++++++++ external/cephes/src/i0.c | 193 +++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 2 +- src/sfizz/MathHelpers.h | 55 ++++++++++ 6 files changed, 456 insertions(+), 1 deletion(-) create mode 100644 external/cephes/LICENSE.txt create mode 100644 external/cephes/src/chbevl.c create mode 100644 external/cephes/src/i0.c diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 1348b558..3dcb1916 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -96,6 +96,12 @@ target_include_directories(sfizz_kissfft PUBLIC "src/external/kiss_fft" PUBLIC "src/external/kiss_fft/tools") +# The cephes library +add_library(sfizz_cephes STATIC + "external/cephes/src/chbevl.c" + "external/cephes/src/i0.c") +add_library(sfizz::cephes ALIAS sfizz_cephes) + # The cpuid library add_library(sfizz_cpuid STATIC "src/external/cpuid/src/cpuid/cpuinfo.cpp" diff --git a/external/cephes/LICENSE.txt b/external/cephes/LICENSE.txt new file mode 100644 index 00000000..666ddb13 --- /dev/null +++ b/external/cephes/LICENSE.txt @@ -0,0 +1,119 @@ +==== NOTE ==== +The actual cephes library, shipped with and wrapped by this package, is available on The Netlib at http://www.netlib.org/cephes/ . It does not have any license specified. However, its original authors, Stephen Moshier, has kindly granted permission for inclusion in a BSD-licensed package. See email snippet below for reference. + +Return-Path: +X-Original-To: julien@cornebise.com +Delivered-To: julien@cornebise.com +Received: from atl4mhob11.myregisteredsite.com (atl4mhob11.myregisteredsite.com [209.17.115.49]) + by cornebise.com (Postfix) with ESMTP id D47B139FC0 + for ; Fri, 25 Oct 2013 16:32:40 +0200 (CEST) +Received: from mailpod1.hostingplatform.com ([10.30.71.116]) + by atl4mhob11.myregisteredsite.com (8.14.4/8.14.4) with ESMTP id r9PEWcwQ003543 + for ; Fri, 25 Oct 2013 10:32:38 -0400 +Received: (qmail 11948 invoked by uid 0); 25 Oct 2013 12:36:20 -0000 +X-TCPREMOTEIP: 76.24.25.74 +X-Authenticated-UID: steve@moshier.net +Received: from unknown (HELO d510.local) (steve@moshier.net@76.24.25.74) + by 0 with ESMTPA; 25 Oct 2013 12:36:20 -0000 +Date: Fri, 25 Oct 2013 08:36:19 -0400 (EDT) +From: Stephen Moshier +X-X-Sender: steve@d510 +To: Julien Cornebise +Subject: Re: Cephes: permission to wrap+distribute for Lua +In-Reply-To: <52653AD3.1010004@cornebise.com> +Message-ID: +References: <52653AD3.1010004@cornebise.com> +User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed + + +Julien, thank you for writing. +BSD license is fine, modification is OK. +There are more build scripts available in the web site distributions than +there are on the Netlib. I think there is an update to Planck's radiation +function that I haven't sent to Netlib yet. But Netlib is a more stable +site, so it is better to cite that as a reference. + + +On Mon, 21 Oct 2013, Julien Cornebise wrote: + +> -----BEGIN PGP SIGNED MESSAGE----- +> Hash: SHA1 +> +> Dear Mr Moshier +> +> I am a researcher in mathematics and machine learning in London, and +> am writing about your awesome Cephes library, whom I found at the +> heart of Scipy. +> +> It is so useful that, with your permission, I would like to wrap it +> for Lua and Torch (a machine learning overlay to Lua, specialized in +> neural nets, see http://www.torch.ch). I would like to distribute it +> as a package for Torch, including your source code along the wrapping +> code. +> This wouldbe a public package, distributed under BSD License. I have +> put a first draft on github: +> https://github.com/jucor/torch-cephes +> +> Hence my three questions, please: +> +> 1/ How would you like to be acknowledged, beyond the comments that are +> already in your code? Do you have any standard header/disclaimer that +> I could add to the documentation? +> +> 2/ At the moment, your code is left untouched. However, if I ever need +> to modify bits of the code, what are the conditions/restrictions? +> Nothing huge -- I definitely do not want to mess with it: I was +> planning to use the natural completion of some functions on the +> completed real line (e.g. CDF returing 1 when called with "infinity", +> or quantiles returning -Infinity when called with 0), either natively +> if supported, or by setting a specific flag via mtherr(). +> +> 3/ I am currently using the source from Netlib. Do you recommend using +> the source from your website instead ? +> +> Thank you very much for your attention, +> and, more importantly, for the time and effort your poured into Cephes. +> +> Best regards, +> +> Julien Cornebise, Ph.D. +> London, UK +> http://www.cornebise.com/julien +> -----BEGIN PGP SIGNATURE----- +> Version: GnuPG v1.4.14 (Darwin) +> Comment: GPGTools - http://gpgtools.org +> Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ +> +> iEYEARECAAYFAlJlOtEACgkQKYR3gC0rw/gIpQCfZKu6+iDh9ghhm6QfsLXnldKN +> BuIAn2zZHu1c/IrRAevhjM7N7xGg0LHO +> =WeP5 +> -----END PGP SIGNATURE----- + + +==== LICENSE ==== +Copyright (c) 2013, Julien Cornebise +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/external/cephes/src/chbevl.c b/external/cephes/src/chbevl.c new file mode 100644 index 00000000..53938816 --- /dev/null +++ b/external/cephes/src/chbevl.c @@ -0,0 +1,82 @@ +/* chbevl.c + * + * Evaluate Chebyshev series + * + * + * + * SYNOPSIS: + * + * int N; + * double x, y, coef[N], chebevl(); + * + * y = chbevl( x, coef, N ); + * + * + * + * DESCRIPTION: + * + * Evaluates the series + * + * N-1 + * - ' + * y = > coef[i] T (x/2) + * - i + * i=0 + * + * of Chebyshev polynomials Ti at argument x/2. + * + * Coefficients are stored in reverse order, i.e. the zero + * order term is last in the array. Note N is the number of + * coefficients, not the order. + * + * If coefficients are for the interval a to b, x must + * have been transformed to x -> 2(2x - b - a)/(b-a) before + * entering the routine. This maps x from (a, b) to (-1, 1), + * over which the Chebyshev polynomials are defined. + * + * If the coefficients are for the inverted interval, in + * which (a, b) is mapped to (1/b, 1/a), the transformation + * required is x -> 2(2ab/x - b - a)/(b-a). If b is infinity, + * this becomes x -> 4a/x - 1. + * + * + * + * SPEED: + * + * Taking advantage of the recurrence properties of the + * Chebyshev polynomials, the routine requires one more + * addition per loop than evaluating a nested polynomial of + * the same degree. + * + */ + /* chbevl.c */ + +/* +Cephes Math Library Release 2.0: April, 1987 +Copyright 1985, 1987 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ + +double chbevl( x, array, n ) +double x; +double array[]; +int n; +{ +double b0, b1, b2, *p; +int i; + +p = array; +b0 = *p++; +b1 = 0.0; +i = n - 1; + +do + { + b2 = b1; + b1 = b0; + b0 = x * b1 - b2 + *p++; + } +while( --i ); + +return( 0.5*(b0-b2) ); +} diff --git a/external/cephes/src/i0.c b/external/cephes/src/i0.c new file mode 100644 index 00000000..307398e9 --- /dev/null +++ b/external/cephes/src/i0.c @@ -0,0 +1,193 @@ +/* i0.c + * + * Modified Bessel function of order zero + * + * + * + * SYNOPSIS: + * + * double x, y, i0(); + * + * y = i0( x ); + * + * + * + * DESCRIPTION: + * + * Returns modified Bessel function of order zero of the + * argument. + * + * The function is defined as i0(x) = j0( ix ). + * + * The range is partitioned into the two intervals [0,8] and + * (8, infinity). Chebyshev polynomial expansions are employed + * in each interval. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC 0,30 6000 8.2e-17 1.9e-17 + * IEEE 0,30 30000 5.8e-16 1.4e-16 + * + */ + /* i0e.c + * + * Modified Bessel function of order zero, + * exponentially scaled + * + * + * + * SYNOPSIS: + * + * double x, y, i0e(); + * + * y = i0e( x ); + * + * + * + * DESCRIPTION: + * + * Returns exponentially scaled modified Bessel function + * of order zero of the argument. + * + * The function is defined as i0e(x) = exp(-|x|) j0( ix ). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0,30 30000 5.4e-16 1.2e-16 + * See i0(). + * + */ + +/* i0.c */ + + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*/ + +#include + +/* Chebyshev coefficients for exp(-x) I0(x) + * in the interval [0,8]. + * + * lim(x->0){ exp(-x) I0(x) } = 1. + */ + +static double A[] = +{ +-4.41534164647933937950E-18, + 3.33079451882223809783E-17, +-2.43127984654795469359E-16, + 1.71539128555513303061E-15, +-1.16853328779934516808E-14, + 7.67618549860493561688E-14, +-4.85644678311192946090E-13, + 2.95505266312963983461E-12, +-1.72682629144155570723E-11, + 9.67580903537323691224E-11, +-5.18979560163526290666E-10, + 2.65982372468238665035E-9, +-1.30002500998624804212E-8, + 6.04699502254191894932E-8, +-2.67079385394061173391E-7, + 1.11738753912010371815E-6, +-4.41673835845875056359E-6, + 1.64484480707288970893E-5, +-5.75419501008210370398E-5, + 1.88502885095841655729E-4, +-5.76375574538582365885E-4, + 1.63947561694133579842E-3, +-4.32430999505057594430E-3, + 1.05464603945949983183E-2, +-2.37374148058994688156E-2, + 4.93052842396707084878E-2, +-9.49010970480476444210E-2, + 1.71620901522208775349E-1, +-3.04682672343198398683E-1, + 6.76795274409476084995E-1 +}; + + +/* Chebyshev coefficients for exp(-x) sqrt(x) I0(x) + * in the inverted interval [8,infinity]. + * + * lim(x->inf){ exp(-x) sqrt(x) I0(x) } = 1/sqrt(2pi). + */ + +static double B[] = +{ +-7.23318048787475395456E-18, +-4.83050448594418207126E-18, + 4.46562142029675999901E-17, + 3.46122286769746109310E-17, +-2.82762398051658348494E-16, +-3.42548561967721913462E-16, + 1.77256013305652638360E-15, + 3.81168066935262242075E-15, +-9.55484669882830764870E-15, +-4.15056934728722208663E-14, + 1.54008621752140982691E-14, + 3.85277838274214270114E-13, + 7.18012445138366623367E-13, +-1.79417853150680611778E-12, +-1.32158118404477131188E-11, +-3.14991652796324136454E-11, + 1.18891471078464383424E-11, + 4.94060238822496958910E-10, + 3.39623202570838634515E-9, + 2.26666899049817806459E-8, + 2.04891858946906374183E-7, + 2.89137052083475648297E-6, + 6.88975834691682398426E-5, + 3.36911647825569408990E-3, + 8.04490411014108831608E-1 +}; + + +extern double chbevl ( double, void *, int ); + +double i0(x) +double x; +{ +double y; + +if( x < 0 ) + x = -x; +if( x <= 8.0 ) + { + y = (x/2.0) - 2.0; + return( exp(x) * chbevl( y, A, 30 ) ); + } + +return( exp(x) * chbevl( 32.0/x - 2.0, B, 25 ) / sqrt(x) ); + +} + + + + +double i0e( x ) +double x; +{ +double y; + +if( x < 0 ) + x = -x; +if( x <= 8.0 ) + { + y = (x/2.0) - 2.0; + return( chbevl( y, A, 30 ) ); + } + +return( chbevl( 32.0/x - 2.0, B, 25 ) / sqrt(x) ); + +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index df68a26b..47c24210 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -242,7 +242,7 @@ target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_ target_include_directories(sfizz_internal PUBLIC "." "sfizz") target_link_libraries(sfizz_internal PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue - PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) + PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") target_link_libraries(sfizz_internal PUBLIC st_audiofile) diff --git a/src/sfizz/MathHelpers.h b/src/sfizz/MathHelpers.h index 50b012bd..d04793fc 100644 --- a/src/sfizz/MathHelpers.h +++ b/src/sfizz/MathHelpers.h @@ -25,6 +25,13 @@ #include #endif +#if __cplusplus >= 201703L +static double i0(double x) { return std::cyl_bessel_i(0.0, x); } +#else +// external Bessel function from cephes +extern "C" double i0(double x); +#endif + template constexpr T max(T op1, T op2) { @@ -465,6 +472,54 @@ bool isReasonableAudio(absl::Span span) return true; } +/** + * @brief Compute the Kaiser window + * + * @param b Kaiser parameter beta + * @param window Span of real which receives the window + */ +template +void kaiserWindow(double b, absl::Span window) +{ + double i0b = i0(b); + for (size_t i = 0, n = window.size(); i < n; ++i) { + double x = i / static_cast(n - 1); + double t = x + x - 1.0; + window[i] = static_cast(i0(b * std::sqrt(1.0 - t * t)) / i0b); + } +} + +/** + * @brief Compute a single point of the Kaiser window + * This is less efficient than calculating the whole window at once. + * + * @param b Kaiser parameter beta + * @param x Point to evaluate, normalized in 0 to 1 + */ +inline double kaiserWindowSinglePoint(double b, double x) +{ + double t = x + x - 1.0; + return i0(b * std::sqrt(1.0 - t * t)) / i0(b); +} + +/** + * @brief Compute the cardinal sine + */ +template +T sinc(T x) +{ + return (x == T(0)) ? T(1) : (std::sin(x) / x); +} + +/** + * @brief Compute the normalized cardinal sine + */ +template +T normalizedSinc(T x) +{ + return sinc(pi() * x); +} + /** * @brief Finds the minimum size of 2 spans * From bf3f41482fa7996c402623391407ea907e3977cc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 31 Jan 2021 14:04:30 +0100 Subject: [PATCH 169/668] Increase file padding, for longer windowed sinc kernels --- src/sfizz/Config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 349a9c12..2a597c67 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -67,7 +67,7 @@ namespace config { constexpr int chunkSize { 1024 }; constexpr unsigned int defaultAlignment { 16 }; constexpr int filtersInPool { maxVoices * 2 }; - constexpr int excessFileFrames { 8 }; + constexpr int excessFileFrames { 64 }; constexpr int maxLFOSubs { 8 }; constexpr int maxLFOSteps { 128 }; /** From 4dbe8bd6020f0e0cb0a051c17c138b3437826123 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 31 Jan 2021 15:00:56 +0100 Subject: [PATCH 170/668] Add windowed sinc interpolation --- common.mk | 4 +- src/CMakeLists.txt | 4 ++ src/sfizz/Interpolators.cpp | 23 +++++++ src/sfizz/Interpolators.h | 28 ++++++++ src/sfizz/Interpolators.hpp | 132 ++++++++++++++++++++++++++++++++++++ src/sfizz/Synth.cpp | 2 + src/sfizz/Voice.cpp | 62 +++++++++++++++-- src/sfizz/WindowedSinc.cpp | 39 +++++++++++ src/sfizz/WindowedSinc.h | 111 ++++++++++++++++++++++++++++++ src/sfizz/WindowedSinc.hpp | 45 ++++++++++++ tests/InterpolatorsT.cpp | 57 ++++++++++++++++ 11 files changed, 500 insertions(+), 7 deletions(-) create mode 100644 src/sfizz/Interpolators.cpp create mode 100644 src/sfizz/WindowedSinc.cpp create mode 100644 src/sfizz/WindowedSinc.h create mode 100644 src/sfizz/WindowedSinc.hpp diff --git a/common.mk b/common.mk index d4a63262..fe7341b7 100644 --- a/common.mk +++ b/common.mk @@ -87,6 +87,7 @@ SFIZZ_SOURCES = \ src/sfizz/FlexEGDescription.cpp \ src/sfizz/FlexEnvelope.cpp \ src/sfizz/FloatEnvelopes.cpp \ + src/sfizz/Interpolators.cpp \ src/sfizz/Logger.cpp \ src/sfizz/LFO.cpp \ src/sfizz/LFODescription.cpp \ @@ -121,7 +122,8 @@ SFIZZ_SOURCES = \ src/sfizz/Voice.cpp \ src/sfizz/VoiceManager.cpp \ src/sfizz/VoiceStealing.cpp \ - src/sfizz/Wavetables.cpp + src/sfizz/Wavetables.cpp \ + src/sfizz/WindowedSinc.cpp ### Other internal diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47c24210..26de3632 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -112,6 +112,8 @@ set(SFIZZ_HEADERS sfizz/VoiceManager.h sfizz/VoiceStealing.h sfizz/Wavetables.h + sfizz/WindowedSinc.h + sfizz/WindowedSinc.hpp sfizz.h sfizz.hpp) @@ -151,6 +153,8 @@ set(SFIZZ_SOURCES sfizz/BeatClock.cpp sfizz/Metronome.cpp sfizz/SynthMessaging.cpp + sfizz/WindowedSinc.cpp + sfizz/Interpolators.cpp sfizz/modulations/ModId.cpp sfizz/modulations/ModKey.cpp sfizz/modulations/ModKeyHash.cpp diff --git a/src/sfizz/Interpolators.cpp b/src/sfizz/Interpolators.cpp new file mode 100644 index 00000000..5fc37a25 --- /dev/null +++ b/src/sfizz/Interpolators.cpp @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "Interpolators.h" + +namespace sfz { + +void initializeInterpolators() +{ + SincInterpolatorTraits<8>::initialize(); + SincInterpolatorTraits<12>::initialize(); + SincInterpolatorTraits<16>::initialize(); + SincInterpolatorTraits<24>::initialize(); + SincInterpolatorTraits<36>::initialize(); + SincInterpolatorTraits<48>::initialize(); + SincInterpolatorTraits<60>::initialize(); + SincInterpolatorTraits<72>::initialize(); +} + +} // namespace sfz diff --git a/src/sfizz/Interpolators.h b/src/sfizz/Interpolators.h index c4fdbbd9..db17b720 100644 --- a/src/sfizz/Interpolators.h +++ b/src/sfizz/Interpolators.h @@ -17,8 +17,36 @@ enum InterpolatorModel : int { kInterpolatorHermite3, // a B-spline 3rd order interpolator kInterpolatorBspline3, + // a windowed-sinc 8-point interpolator + kInterpolatorSinc8, + // a windowed-sinc 12-point interpolator + kInterpolatorSinc12, + // a windowed-sinc 16-point interpolator + kInterpolatorSinc16, + // a windowed-sinc 24-point interpolator + kInterpolatorSinc24, + // a windowed-sinc 36-point interpolator + kInterpolatorSinc36, + // a windowed-sinc 48-point interpolator + kInterpolatorSinc48, + // a windowed-sinc 60-point interpolator + kInterpolatorSinc60, + // a windowed-sinc 72-point interpolator + kInterpolatorSinc72, }; +/** + * @brief Initialize interpolators + * + * This precomputes windowed-sinc tables globally. + * It needs to be called at least once, before using the windowed-sinc models. + * + * These are not computed at static initialization time, to prevent slowing down + * an audio plugin library scan (eg. VST). The static-local-variable method is + * avoided also, because we don't want this overhead on a frame-by-frame basis. + */ +void initializeInterpolators(); + /** * @brief Interpolate from a vector of values * diff --git a/src/sfizz/Interpolators.hpp b/src/sfizz/Interpolators.hpp index 5c302900..9cef3d7d 100644 --- a/src/sfizz/Interpolators.hpp +++ b/src/sfizz/Interpolators.hpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Interpolators.h" +#include "WindowedSinc.h" #include "MathHelpers.h" #include "SIMDConfig.h" @@ -133,4 +134,135 @@ public: } }; +//------------------------------------------------------------------------------ +// Windowed sinc + +namespace SincInterpolatorDetail { + // See sfizz wiki page "Resampling". + constexpr size_t PointsMin = 8; + constexpr size_t PointsMax = 72; + + // Adjust Kaiser window Beta as necessary. + constexpr double BetaMin = 6.0; + constexpr double BetaMax = 10.0; + + constexpr double getBetaForNumPoints(size_t points) + { + return BetaMin + (BetaMax - BetaMin) * + (double(points - PointsMin) / double(PointsMax - PointsMin)); + } + + constexpr size_t getTableSizeForNumPoints(size_t /*points*/) + { + return 1u << 16; + } +} + +/// +template +struct SincInterpolatorTraits { + static_assert(Points == 8 || Points == 12 || Points == 16 || + Points == 24 || Points == 36 || Points == 48 || + Points == 60 || Points == 72, + "Windowed sinc size is not acceptable"); + + enum { + TableSize = SincInterpolatorDetail::getTableSizeForNumPoints(Points) + }; + + static void initialize() + { + static const FixedWindowedSinc globalInstance( + SincInterpolatorDetail::getBetaForNumPoints(Points)); + windowedSinc = &globalInstance; + } + + static const FixedWindowedSinc* windowedSinc; +}; + +template +const FixedWindowedSinc::TableSize>* +SincInterpolatorTraits::windowedSinc = nullptr; + +/// +template +class SincInterpolator; + +//------------------------------------------------------------------------------ +// Windowed sinc any order, SSE specialization +#if SFIZZ_HAVE_SSE +template +class SincInterpolator +{ +public: + static_assert(Points % 4 == 0, "Windowed sinc must be multiple of 4"); + + static inline float process(const float* values, float coeff) + { + const auto &ws = *SincInterpolatorTraits::windowedSinc; + + int j0 = 1 - int(Points) / 2; + + __m128 h[Points / 4]; + for (int i = 0; i < int(Points); ++i) + reinterpret_cast(h)[i] = ws.getUnchecked(j0 - coeff + i); + + __m128 y = _mm_mul_ps(h[0], _mm_loadu_ps(&values[j0])); + for (int i = 1; i < int(Points / 4); ++i) + y = _mm_add_ps(y, _mm_mul_ps(h[i], _mm_loadu_ps(&values[j0 + 4 * i]))); + + // sum 4 to 1 + __m128 xmm0 = y; + __m128 xmm1 = _mm_shuffle_ps(xmm0, xmm0, 0xe5); + __m128 xmm2 = _mm_movehl_ps(xmm0, xmm0); + xmm1 = _mm_add_ss(xmm1, xmm0); + xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0xe7); + xmm2 = _mm_add_ss(xmm2, xmm1); + xmm0 = _mm_add_ss(xmm0, xmm2); + return _mm_cvtss_f32(xmm0); + } +}; +#endif + +//------------------------------------------------------------------------------ +// Windowed sinc any order, generic +template +class SincInterpolator +{ +public: + static inline R process(const R* values, R coeff) + { + const auto &ws = *SincInterpolatorTraits::windowedSinc; + + int j0 = 1 - int(Points) / 2; + + R h[Points]; + for (int i = 0; i < int(Points); ++i) + h[i] = R(ws.getUnchecked(j0 - coeff + i)); + + R y = h[0] * values[j0]; + for (int i = 1; i < int(Points); ++i) + y += h[i] * values[j0 + i]; + + return y; + } +}; + +template +class Interpolator : public SincInterpolator {}; +template +class Interpolator : public SincInterpolator {}; +template +class Interpolator : public SincInterpolator {}; +template +class Interpolator : public SincInterpolator {}; +template +class Interpolator : public SincInterpolator {}; +template +class Interpolator : public SincInterpolator {}; +template +class Interpolator : public SincInterpolator {}; +template +class Interpolator : public SincInterpolator {}; + } // namespace sfz diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index ef54fe98..ed7bf3b0 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -21,6 +21,7 @@ #include "utility/SpinMutex.h" #include "utility/XmlHelpers.h" #include "Voice.h" +#include "Interpolators.h" #include #include #include @@ -48,6 +49,7 @@ Synth::~Synth() Synth::Impl::Impl() { initializeSIMDDispatchers(); + initializeInterpolators(); const std::lock_guard disableCallback { callbackGuard_ }; parser_.setListener(this); diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index a759dee5..a93c925a 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1149,18 +1149,20 @@ void Voice::Impl::fillInterpolatedWithQuality( absl::Span indices, absl::Span coeffs, absl::Span addingGains, int quality) { - switch (quality) { - default: - if (quality > 2) - goto high; // TODO sinc, not implemented - // fall through + switch (clamp(quality, 0, 10)) { + case 0: + { + constexpr auto itp = kInterpolatorNearest; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; case 1: { constexpr auto itp = kInterpolatorLinear; fillInterpolated(source, dest, indices, coeffs, addingGains); } break; - case 2: high: + case 2: { #if 0 // B-spline response has faster decay of aliasing, but not zero-crossings at integer positions @@ -1172,6 +1174,54 @@ void Voice::Impl::fillInterpolatedWithQuality( fillInterpolated(source, dest, indices, coeffs, addingGains); } break; + case 3: + { + constexpr auto itp = kInterpolatorSinc8; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; + case 4: + { + constexpr auto itp = kInterpolatorSinc12; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; + case 5: + { + constexpr auto itp = kInterpolatorSinc16; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; + case 6: + { + constexpr auto itp = kInterpolatorSinc24; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; + case 7: + { + constexpr auto itp = kInterpolatorSinc36; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; + case 8: + { + constexpr auto itp = kInterpolatorSinc48; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; + case 9: + { + constexpr auto itp = kInterpolatorSinc60; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; + case 10: + { + constexpr auto itp = kInterpolatorSinc72; + fillInterpolated(source, dest, indices, coeffs, addingGains); + } + break; } } diff --git a/src/sfizz/WindowedSinc.cpp b/src/sfizz/WindowedSinc.cpp new file mode 100644 index 00000000..94aec536 --- /dev/null +++ b/src/sfizz/WindowedSinc.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "WindowedSinc.h" +#include "MathHelpers.h" +#include + +namespace sfz { + +void WindowedSincDetail::calculateTable(absl::Span table, size_t sincExtent, double beta, size_t extra) +{ + size_t tableSize = table.size(); + + auto window = absl::make_unique(tableSize); + kaiserWindow(beta, absl::MakeSpan(window.get(), tableSize)); + + // table domain [-N/2:+N/2] + double scale = sincExtent / static_cast(tableSize - 1); + double offset = sincExtent / -2.0; + + for (size_t i = 0; i < tableSize; ++i) { + double x = i * scale + offset; + table[i] = window[i] * normalizedSinc(x); + } + + for (size_t i = 0; i < extra; ++i) + table[extra + i] = table[tableSize - 1]; +} + +double WindowedSincDetail::calculateExact(double x, size_t sincExtent, double beta) +{ + return normalizedSinc(x) * + kaiserWindowSinglePoint(beta, (x + sincExtent / 2.0f) / sincExtent); +} + +} // namespace sfz diff --git a/src/sfizz/WindowedSinc.h b/src/sfizz/WindowedSinc.h new file mode 100644 index 00000000..94a8a9de --- /dev/null +++ b/src/sfizz/WindowedSinc.h @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include + +namespace sfz { + +namespace WindowedSincDetail { + void calculateTable(absl::Span table, size_t sincExtent, double beta, size_t extra); + double calculateExact(double x, size_t sincExtent, double beta); +}; + +template +class AbstractWindowedSinc { +protected: + explicit AbstractWindowedSinc(double beta) noexcept : beta_(beta) {} + +public: + virtual ~AbstractWindowedSinc() noexcept {} + + // interpolate f(x), where x must be in domain [-Points/2:+Points/2] + float getUnchecked(float x) const noexcept; + + // calculate exact f(x), where x must be in domain [-Points/2:+Points/2] + double getExact(double x) const noexcept; + + // get the Kaiser window Beta parameter + double getBeta() const noexcept { return beta_; } + +protected: + void fillTable() noexcept; + + // allows interpolating f(Points/2), provided for safety + enum { TableExtra = 1 }; + +private: + double beta_ {}; +}; + +/** + * @brief Windowed-sinc using fixed compile-time parameters + * This can help to save some instructions in a resampler loop. + */ +template +class FixedWindowedSinc final : + public AbstractWindowedSinc> { +public: + using Self = FixedWindowedSinc; + using Super = AbstractWindowedSinc; + + explicit FixedWindowedSinc(double beta) : Super(beta) { Super::fillTable(); } + + // the number of points where this sinc will be evaluated (zero crossings + 1) + static constexpr size_t getNumPoints() noexcept { return Points; } + + // the size of the lookup table + static constexpr size_t getTableSize() noexcept { return TableSize; } + + // the lookup table + const float* getTablePointer() const noexcept { return table_; } + + // the lookup table + absl::Span getTableSpan() const noexcept { return absl::MakeConstSpan(table_, TableSize); } + +protected: + using Super::TableExtra; + +private: + float table_[TableSize + TableExtra]; +}; + +/** + * @brief Windowed-sinc using run-time parameters + */ +class WindowedSinc final : public AbstractWindowedSinc +{ +public: + using Self = WindowedSinc; + using Super = AbstractWindowedSinc; + + WindowedSinc(size_t points, size_t tableSize, double beta) + : Super(beta), points_(points), tableSize_(tableSize), + table_(new float[tableSize + TableExtra]) + { Super::fillTable(); } + + // the number of points where this sinc will be evaluated (zero crossings + 1) + size_t getNumPoints() const noexcept { return points_; } + + // the size of the lookup table + size_t getTableSize() const noexcept { return tableSize_; } + + // the lookup table + const float* getTablePointer() const noexcept { return table_.get(); } + + // the lookup table + absl::Span getTableSpan() const noexcept { return absl::MakeConstSpan(table_.get(), tableSize_); } + +private: + size_t points_ {}; + size_t tableSize_ {}; + std::unique_ptr table_; +}; + +} // namespace sfz + +#include "WindowedSinc.hpp" diff --git a/src/sfizz/WindowedSinc.hpp b/src/sfizz/WindowedSinc.hpp new file mode 100644 index 00000000..47d2c89d --- /dev/null +++ b/src/sfizz/WindowedSinc.hpp @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "WindowedSinc.h" + +namespace sfz { + +template +inline void AbstractWindowedSinc::fillTable() noexcept +{ + float* table = const_cast(static_cast(this)->getTablePointer()); + size_t points = static_cast(this)->getNumPoints(); + size_t tableSize = static_cast(this)->getTableSize(); + + WindowedSincDetail::calculateTable( + absl::MakeSpan(table, tableSize), points, beta_, TableExtra); +} + +template +inline float AbstractWindowedSinc::getUnchecked(float x) const noexcept +{ + const float* table = static_cast(this)->getTablePointer(); + size_t points = static_cast(this)->getNumPoints(); + size_t tableSize = static_cast(this)->getTableSize(); + + float ix = (x + points / 2.0f) * ((tableSize - 1) / points); + int i0 = static_cast(ix); + float mu = ix - i0; + float y0 = table[i0]; + float dy = table[i0 + 1] - y0; + return y0 + mu * dy; +} + +template +inline double AbstractWindowedSinc::getExact(double x) const noexcept +{ + size_t points = static_cast(this)->getNumPoints(); + return WindowedSincDetail::calculateExact(x, points, beta_); +} + +} // namespace sfz diff --git a/tests/InterpolatorsT.cpp b/tests/InterpolatorsT.cpp index 93193a12..ed9c03d9 100644 --- a/tests/InterpolatorsT.cpp +++ b/tests/InterpolatorsT.cpp @@ -70,3 +70,60 @@ TEST_CASE("[Interpolators] Squares") == Approx(expected).margin(1e-2)); } } + +template +static std::pair windowedSincError(WS& ws, double step = 0.1, bool verbose = false) +{ + size_t points = ws.getNumPoints(); + double x1 = points / -2.0; + double x2 = points / +2.0; + double maxAbsErr = 0.0; + double meanAbsErr = 0.0; + //double meanSquareErr = 0.0; + + double x; + size_t n; + for (n = 0; (x = x1 + n * step) < x2; ++n) { + double val = ws.getUnchecked(x); + double ref = ws.getExact(x); + double absErr = std::fabs(val - ref); + maxAbsErr = std::max(maxAbsErr, absErr); + meanAbsErr += absErr; + //meanSquareErr += absErr * absErr; + } + meanAbsErr /= n; + //meanSquareErr /= n; + + if (verbose) { + std::cerr << "MaxAbsErr=" << maxAbsErr + << " MeanAbsErr=" << meanAbsErr + //<< " MeanSquareErr=" << meanSquareErr + << " with Points=" << points + << " TableSize=" << ws.getTableSize() + << "\n"; + } + + return { maxAbsErr, meanAbsErr }; +} + +TEST_CASE("[Interpolators] Windowed sinc precision") +{ + sfz::initializeInterpolators(); + + double maxAbsTolerance = 5e-2; + double meanAbsTolerance = 1e-3; + + auto Check = [=](std::pair maxAndMeanErr) { + REQUIRE(maxAndMeanErr.first < maxAbsTolerance); + REQUIRE(maxAndMeanErr.second < meanAbsTolerance); + }; + + Check(windowedSincError(*sfz::SincInterpolatorTraits<8>::windowedSinc)); + Check(windowedSincError(*sfz::SincInterpolatorTraits<12>::windowedSinc)); + Check(windowedSincError(*sfz::SincInterpolatorTraits<16>::windowedSinc)); + Check(windowedSincError(*sfz::SincInterpolatorTraits<24>::windowedSinc)); + Check(windowedSincError(*sfz::SincInterpolatorTraits<36>::windowedSinc)); + Check(windowedSincError(*sfz::SincInterpolatorTraits<48>::windowedSinc)); + Check(windowedSincError(*sfz::SincInterpolatorTraits<60>::windowedSinc)); + Check(windowedSincError(*sfz::SincInterpolatorTraits<72>::windowedSinc)); +} From d5bb51488d34531f75de273d44bc2393c077d6a1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 31 Jan 2021 22:56:48 +0100 Subject: [PATCH 171/668] Improve the x64 code output slightly --- src/sfizz/WindowedSinc.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sfizz/WindowedSinc.hpp b/src/sfizz/WindowedSinc.hpp index 47d2c89d..7908b5aa 100644 --- a/src/sfizz/WindowedSinc.hpp +++ b/src/sfizz/WindowedSinc.hpp @@ -6,6 +6,7 @@ #pragma once #include "WindowedSinc.h" +#include namespace sfz { @@ -28,7 +29,7 @@ inline float AbstractWindowedSinc::getUnchecked(float x) const noexcept size_t tableSize = static_cast(this)->getTableSize(); float ix = (x + points / 2.0f) * ((tableSize - 1) / points); - int i0 = static_cast(ix); + intptr_t i0 = static_cast(ix); float mu = ix - i0; float y0 = table[i0]; float dy = table[i0 + 1] - y0; From 0629a6b30d560389610c42070e6f3ffb5ac518bf Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 31 Jan 2021 23:52:39 +0100 Subject: [PATCH 172/668] Add the windowed-sinc benchmark --- benchmarks/BM_interpolators.cpp | 57 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/benchmarks/BM_interpolators.cpp b/benchmarks/BM_interpolators.cpp index 77337576..dd44900e 100644 --- a/benchmarks/BM_interpolators.cpp +++ b/benchmarks/BM_interpolators.cpp @@ -13,6 +13,11 @@ class Interpolators : public benchmark::Fixture { public: + Interpolators() + { + sfz::initializeInterpolators(); + } + void SetUp(const ::benchmark::State& state) { std::random_device rd { }; @@ -55,33 +60,27 @@ static void doInterpolation(absl::Span input, absl::Span out } } -BENCHMARK_DEFINE_F(Interpolators, Linear)(benchmark::State& state) -{ - ScopedFTZ ftz; +#define ADD_INTERPOLATOR_BENCHMARK(Type) \ + BENCHMARK_DEFINE_F(Interpolators, Type)(benchmark::State& state) \ + { \ + ScopedFTZ ftz; \ + for (auto _ : state) { \ + absl::Span span = absl::MakeSpan(output); \ + doInterpolation(input, span); \ + } \ + } \ + BENCHMARK_REGISTER_F(Interpolators, Type) \ + ->RangeMultiplier(4)->Range(1 << 4, 1 << 12); - for (auto _ : state) { - doInterpolation(input, absl::MakeSpan(output)); - } -} - -BENCHMARK_DEFINE_F(Interpolators, Hermite3)(benchmark::State& state) -{ - ScopedFTZ ftz; - - for (auto _ : state) { - doInterpolation(input, absl::MakeSpan(output)); - } -} - -BENCHMARK_DEFINE_F(Interpolators, Bspline3)(benchmark::State& state) -{ - ScopedFTZ ftz; - - for (auto _ : state) { - doInterpolation(input, absl::MakeSpan(output)); - } -} - -BENCHMARK_REGISTER_F(Interpolators, Linear)->RangeMultiplier(4)->Range(1 << 4, 1 << 12); -BENCHMARK_REGISTER_F(Interpolators, Hermite3)->RangeMultiplier(4)->Range(1 << 4, 1 << 12); -BENCHMARK_REGISTER_F(Interpolators, Bspline3)->RangeMultiplier(4)->Range(1 << 4, 1 << 12); +ADD_INTERPOLATOR_BENCHMARK(Nearest) +ADD_INTERPOLATOR_BENCHMARK(Linear) +ADD_INTERPOLATOR_BENCHMARK(Hermite3) +ADD_INTERPOLATOR_BENCHMARK(Bspline3) +ADD_INTERPOLATOR_BENCHMARK(Sinc8) +ADD_INTERPOLATOR_BENCHMARK(Sinc12) +ADD_INTERPOLATOR_BENCHMARK(Sinc16) +ADD_INTERPOLATOR_BENCHMARK(Sinc24) +ADD_INTERPOLATOR_BENCHMARK(Sinc36) +ADD_INTERPOLATOR_BENCHMARK(Sinc48) +ADD_INTERPOLATOR_BENCHMARK(Sinc60) +ADD_INTERPOLATOR_BENCHMARK(Sinc72) From c7a75ee2fc3f06492753e05623b1308d11b3f504 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 00:53:21 +0100 Subject: [PATCH 173/668] Accelerate windowed sinc SSE2 --- src/sfizz/Interpolators.hpp | 21 ++++++++++++--------- src/sfizz/WindowedSinc.h | 13 +++++++++++-- src/sfizz/WindowedSinc.hpp | 30 ++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/sfizz/Interpolators.hpp b/src/sfizz/Interpolators.hpp index 9cef3d7d..a75c9608 100644 --- a/src/sfizz/Interpolators.hpp +++ b/src/sfizz/Interpolators.hpp @@ -190,7 +190,7 @@ class SincInterpolator; //------------------------------------------------------------------------------ // Windowed sinc any order, SSE specialization -#if SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 template class SincInterpolator { @@ -201,15 +201,18 @@ public: { const auto &ws = *SincInterpolatorTraits::windowedSinc; - int j0 = 1 - int(Points) / 2; + constexpr int j0 = 1 - int(Points) / 2; + float x0 = j0 - coeff; - __m128 h[Points / 4]; - for (int i = 0; i < int(Points); ++i) - reinterpret_cast(h)[i] = ws.getUnchecked(j0 - coeff + i); - - __m128 y = _mm_mul_ps(h[0], _mm_loadu_ps(&values[j0])); - for (int i = 1; i < int(Points / 4); ++i) - y = _mm_add_ps(y, _mm_mul_ps(h[i], _mm_loadu_ps(&values[j0 + 4 * i]))); + __m128 y = _mm_set1_ps(0.0f); + __m128 x = _mm_add_ps(_mm_set1_ps(x0), _mm_setr_ps(0, 1, 2, 3)); + size_t i = 0; + do { + __m128 h = ws.getUncheckedX4(x); + y = _mm_add_ps(y, _mm_mul_ps(h, _mm_loadu_ps(&values[j0 + i]))); + x = _mm_add_ps(x, _mm_set1_ps(4.0f)); + i += 4; + } while (i < Points); // sum 4 to 1 __m128 xmm0 = y; diff --git a/src/sfizz/WindowedSinc.h b/src/sfizz/WindowedSinc.h index 94a8a9de..b8beb582 100644 --- a/src/sfizz/WindowedSinc.h +++ b/src/sfizz/WindowedSinc.h @@ -5,8 +5,12 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "SIMDConfig.h" #include #include +#if SFIZZ_HAVE_SSE2 +#include +#endif namespace sfz { @@ -26,6 +30,11 @@ public: // interpolate f(x), where x must be in domain [-Points/2:+Points/2] float getUnchecked(float x) const noexcept; +#if SFIZZ_HAVE_SSE2 + // interpolate f(x), 4 values at once + __m128 getUncheckedX4(__m128 x) const noexcept; +#endif + // calculate exact f(x), where x must be in domain [-Points/2:+Points/2] double getExact(double x) const noexcept; @@ -35,8 +44,8 @@ public: protected: void fillTable() noexcept; - // allows interpolating f(Points/2), provided for safety - enum { TableExtra = 1 }; + // allows interpolating f(Points/2), and SSE, provided for safety + enum { TableExtra = 4 }; private: double beta_ {}; diff --git a/src/sfizz/WindowedSinc.hpp b/src/sfizz/WindowedSinc.hpp index 7908b5aa..1bd4f19c 100644 --- a/src/sfizz/WindowedSinc.hpp +++ b/src/sfizz/WindowedSinc.hpp @@ -36,6 +36,36 @@ inline float AbstractWindowedSinc::getUnchecked(float x) const noexcept return y0 + mu * dy; } +#if SFIZZ_HAVE_SSE2 +template +inline __m128 AbstractWindowedSinc::getUncheckedX4(__m128 x) const noexcept +{ + const float* table = static_cast(this)->getTablePointer(); + size_t points = static_cast(this)->getNumPoints(); + size_t tableSize = static_cast(this)->getTableSize(); + + __m128 ix = _mm_mul_ps( + _mm_add_ps(x, _mm_set1_ps(points / 2.0f)), + _mm_set1_ps((tableSize - 1) / points)); + alignas(__m128i) int j0[4]; + __m128i i0 = _mm_cvttps_epi32(ix); + _mm_store_si128((__m128i*)j0, i0); + __m128 mu = _mm_sub_ps(ix, _mm_cvtepi32_ps(i0)); + + // reference: Interpolated table lookups using SSE2 [2/2] + // https://rawstudio.org/blog/?p=482 + __m128 p0p1 = _mm_castsi128_ps(_mm_loadl_epi64((__m128i*)&table[j0[0]])); + __m128 p2p3 = _mm_castsi128_ps(_mm_loadl_epi64((__m128i*)&table[j0[2]])); + p0p1 = _mm_loadh_pi(p0p1, (__m64*)&table[j0[1]]); + p2p3 = _mm_loadh_pi(p2p3, (__m64*)&table[j0[3]]); + __m128 y0 = _mm_shuffle_ps(p0p1, p2p3, _MM_SHUFFLE(2, 0, 2, 0)); + __m128 y1 = _mm_shuffle_ps(p0p1, p2p3, _MM_SHUFFLE(3, 1, 3, 1)); + + __m128 dy = _mm_sub_ps(y1, y0); + return _mm_add_ps(y0, _mm_mul_ps(mu, dy)); +} +#endif + template inline double AbstractWindowedSinc::getExact(double x) const noexcept { From c27e8f409f4dee2affa5ad92feee64ef26f634a7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 02:47:40 +0100 Subject: [PATCH 174/668] System-dependent options --- .github/workflows/build.yml | 2 +- CMakeLists.txt | 34 ++++++++++++++++--------------- cmake/OptionEx.cmake | 19 +++++++++++++++++ scripts/appveyor/before_build.cmd | 1 - scripts/appveyor/before_build.sh | 1 - 5 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 cmake/OptionEx.cmake diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 44e48225..78270416 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -117,7 +117,7 @@ jobs: run: | mod-plugin-builder /usr/local/bin/cmake "$GITHUB_WORKSPACE" \ -DSFIZZ_SYSTEM_PROCESSOR=armv7-a \ - -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_LV2_UI=OFF + -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_VST=OFF -DSFIZZ_LV2_UI=OFF - name: Build shell: bash working-directory: ${{runner.workspace}}/build diff --git a/CMakeLists.txt b/CMakeLists.txt index e26cc1bb..3e2149df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,24 +16,26 @@ set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake") include (BuildType) # Build Options +include (OptionEx) + set (BUILD_TESTING OFF CACHE BOOL "Disable Abseil's tests [default: OFF]") -option (ENABLE_LTO "Enable Link Time Optimization [default: ON]" ON) -option (SFIZZ_JACK "Enable JACK stand-alone build [default: ON]" ON) -option (SFIZZ_RENDER "Enable renderer of SMF files [default: ON]" ON) -option (SFIZZ_LV2 "Enable LV2 plug-in build [default: ON]" ON) -option (SFIZZ_LV2_UI "Enable LV2 plug-in user interface [default: ON]" ON) -option (SFIZZ_VST "Enable VST plug-in build [default: OFF]" OFF) -option (SFIZZ_AU "Enable AU plug-in build [default: OFF]" OFF) -option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF) -option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF) -option (SFIZZ_DEMOS "Enable feature demos build [default: OFF]" OFF) -option (SFIZZ_DEVTOOLS "Enable developer tools build [default: OFF]" OFF) -option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON) -option (SFIZZ_USE_SNDFILE "Enable use of the sndfile library [default: ON]" ON) -option (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg [default: OFF]" OFF) -option (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically [default: OFF]" OFF) -option (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds [default: OFF]" OFF) +option_ex (ENABLE_LTO "Enable Link Time Optimization" ON) +option_ex (SFIZZ_JACK "Enable JACK stand-alone build" CMAKE_SYSTEM_NAME STREQUAL "Linux") +option_ex (SFIZZ_RENDER "Enable renderer of SMF files" ON) +option_ex (SFIZZ_LV2 "Enable LV2 plug-in build" ON) +option_ex (SFIZZ_LV2_UI "Enable LV2 plug-in user interface" ON) +option_ex (SFIZZ_VST "Enable VST plug-in build" ON) +option_ex (SFIZZ_AU "Enable AU plug-in build" APPLE) +option_ex (SFIZZ_BENCHMARKS "Enable benchmarks build" OFF) +option_ex (SFIZZ_TESTS "Enable tests build" OFF) +option_ex (SFIZZ_DEMOS "Enable feature demos build" OFF) +option_ex (SFIZZ_DEVTOOLS "Enable developer tools build" OFF) +option_ex (SFIZZ_SHARED "Enable shared library build" ON) +option_ex (SFIZZ_USE_SNDFILE "Enable use of the sndfile library" ON) +option_ex (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg" OFF) +option_ex (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically" OFF) +option_ex (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds" OFF) include (SfizzConfig) include (SfizzDeps) diff --git a/cmake/OptionEx.cmake b/cmake/OptionEx.cmake new file mode 100644 index 00000000..fda33a95 --- /dev/null +++ b/cmake/OptionEx.cmake @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: BSD-2-Clause + +# This code is part of the sfizz library and is licensed under a BSD 2-clause +# license. You should have receive a LICENSE.md file along with the code. +# If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +# Macro: option_ex(OPTION DOC [CONDITION]) +# Defines an option, with these characteristics: +# - A suffix [default: ON/OFF] is appended to the documentation +# - The value is interpreted like a conditional expression +macro(option_ex option doc) + if(${ARGN}) + set(_value ON) + else() + set(_value OFF) + endif() + option("${option}" "${doc} [default: ${_value}]" "${_value}") + unset(_value) +endmacro() diff --git a/scripts/appveyor/before_build.cmd b/scripts/appveyor/before_build.cmd index a9fa0f65..0b7804cd 100644 --- a/scripts/appveyor/before_build.cmd +++ b/scripts/appveyor/before_build.cmd @@ -6,7 +6,6 @@ if %platform%==x86 set RELEASE_ARCH=Win32 if %platform%==x64 set RELEASE_ARCH=x64 cmake .. -G"Visual Studio 16 2019" -A"%RELEASE_ARCH%"^ - -DSFIZZ_JACK=OFF^ -DSFIZZ_BENCHMARKS=OFF^ -DSFIZZ_TESTS=ON^ -DSFIZZ_LV2=ON^ diff --git a/scripts/appveyor/before_build.sh b/scripts/appveyor/before_build.sh index 329b6c1f..213ab8a3 100644 --- a/scripts/appveyor/before_build.sh +++ b/scripts/appveyor/before_build.sh @@ -6,7 +6,6 @@ mkdir -p build/${INSTALL_DIR} && cd build cmake -DCMAKE_BUILD_TYPE=Release \ -DSFIZZ_VST=ON \ -DSFIZZ_AU=ON \ - -DSFIZZ_JACK=OFF \ -DSFIZZ_RENDER=OFF \ -DSFIZZ_SHARED=OFF \ -DSFIZZ_TESTS=ON \ From 9cb0a457a5e53a9ff9651819e83bca30baba403b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 10:30:17 +0100 Subject: [PATCH 175/668] Make ADSREnvelope not a template --- benchmarks/BM_ADSR.cpp | 2 +- common.mk | 1 - src/CMakeLists.txt | 2 +- src/sfizz/ADSREnvelope.cpp | 56 ++++++------------- src/sfizz/ADSREnvelope.h | 41 +++++++------- src/sfizz/FloatEnvelopes.cpp | 16 ------ src/sfizz/Voice.cpp | 16 +++--- src/sfizz/Voice.h | 6 +- .../modulations/sources/ADSREnvelope.cpp | 6 +- tests/ADSREnvelopeT.cpp | 20 +++---- 10 files changed, 62 insertions(+), 104 deletions(-) delete mode 100644 src/sfizz/FloatEnvelopes.cpp diff --git a/benchmarks/BM_ADSR.cpp b/benchmarks/BM_ADSR.cpp index c17a1a31..3dcfd6b1 100644 --- a/benchmarks/BM_ADSR.cpp +++ b/benchmarks/BM_ADSR.cpp @@ -36,7 +36,7 @@ public: sfz::MidiState midiState; sfz::Region region{0, midiState}; - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; std::vector output; }; diff --git a/common.mk b/common.mk index fe7341b7..4efdbc57 100644 --- a/common.mk +++ b/common.mk @@ -86,7 +86,6 @@ SFIZZ_SOURCES = \ src/sfizz/FilterPool.cpp \ src/sfizz/FlexEGDescription.cpp \ src/sfizz/FlexEnvelope.cpp \ - src/sfizz/FloatEnvelopes.cpp \ src/sfizz/Interpolators.cpp \ src/sfizz/Logger.cpp \ src/sfizz/LFO.cpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 26de3632..6786663e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -131,7 +131,7 @@ set(SFIZZ_SOURCES sfizz/MidiState.cpp sfizz/SfzHelpers.cpp sfizz/Oversampler.cpp - sfizz/FloatEnvelopes.cpp + sfizz/ADSREnvelope.cpp sfizz/Logger.cpp sfizz/SfzFilter.cpp sfizz/Curve.cpp diff --git a/src/sfizz/ADSREnvelope.cpp b/src/sfizz/ADSREnvelope.cpp index 803adbb6..b6fab78e 100644 --- a/src/sfizz/ADSREnvelope.cpp +++ b/src/sfizz/ADSREnvelope.cpp @@ -11,33 +11,31 @@ namespace sfz { -template -Type ADSREnvelope::secondsToSamples (Type timeInSeconds) const noexcept +using Float = ADSREnvelope::Float; + +Float ADSREnvelope::secondsToSamples(Float timeInSeconds) const noexcept { return static_cast(timeInSeconds * sampleRate); }; -template -Type ADSREnvelope::secondsToLinRate (Type timeInSeconds) const noexcept +Float ADSREnvelope::secondsToLinRate(Float timeInSeconds) const noexcept { if (timeInSeconds == 0) - return 1.0f; + return Float(1); return 1 / (sampleRate * timeInSeconds); }; -template -Type ADSREnvelope::secondsToExpRate (Type timeInSeconds) const noexcept +Float ADSREnvelope::secondsToExpRate(Float timeInSeconds) const noexcept { if (timeInSeconds == 0) - return 0.0f; + return Float(0.0); - timeInSeconds = std::max(25e-3, timeInSeconds); - return std::exp(-9.0 / (timeInSeconds * sampleRate)); + timeInSeconds = std::max(Float(25e-3), timeInSeconds); + return std::exp(Float(-9.0) / (timeInSeconds * sampleRate)); }; -template -void ADSREnvelope::reset(const EGDescription& desc, const Region& region, const MidiState& state, int delay, float velocity, float sampleRate) noexcept +void ADSREnvelope::reset(const EGDescription& desc, const Region& region, const MidiState& state, int delay, float velocity, float sampleRate) noexcept { this->sampleRate = sampleRate; @@ -54,15 +52,14 @@ void ADSREnvelope::reset(const EGDescription& desc, const Region& region, sustainThreshold = this->sustain + config::virtuallyZero; shouldRelease = false; freeRunning = ( - (this->sustain == 0.0f) + (this->sustain == Float(0.0)) || (region.loopMode == SfzLoopMode::one_shot && region.isOscillator()) ); currentValue = this->start; currentState = State::Delay; } -template -Type ADSREnvelope::getNextValue() noexcept +Float ADSREnvelope::getNextValue() noexcept { if (shouldRelease && releaseDelay-- == 0) currentState = State::Release; @@ -113,11 +110,10 @@ Type ADSREnvelope::getNextValue() noexcept } } -template -void ADSREnvelope::getBlock(absl::Span output) noexcept +void ADSREnvelope::getBlock(absl::Span output) noexcept { State currentState = this->currentState; - Type currentValue = this->currentValue; + Float currentValue = this->currentValue; bool shouldRelease = this->shouldRelease; int releaseDelay = this->releaseDelay; @@ -203,33 +199,13 @@ void ADSREnvelope::getBlock(absl::Span output) noexcept ASSERT(!hasNanInf(output)); } -template -bool ADSREnvelope::isSmoothing() const noexcept -{ - return (currentState != State::Done); -} - -template -bool ADSREnvelope::isReleased() const noexcept -{ - return (currentState == State::Release) || shouldRelease; -} - -template -int ADSREnvelope::getRemainingDelay() const noexcept -{ - return delay; -} - -template -void ADSREnvelope::startRelease(int releaseDelay) noexcept +void ADSREnvelope::startRelease(int releaseDelay) noexcept { shouldRelease = true; this->releaseDelay = releaseDelay; } -template -void ADSREnvelope::setReleaseTime(Type timeInSeconds) noexcept +void ADSREnvelope::setReleaseTime(Float timeInSeconds) noexcept { releaseRate = secondsToExpRate(timeInSeconds); } diff --git a/src/sfizz/ADSREnvelope.h b/src/sfizz/ADSREnvelope.h index eafd2f90..648267d4 100644 --- a/src/sfizz/ADSREnvelope.h +++ b/src/sfizz/ADSREnvelope.h @@ -13,12 +13,11 @@ namespace sfz { /** * @brief Describe an attack/delay/sustain/release envelope that can * produce its coefficient in a blockwise manner for SIMD-type operations. - * - * @tparam Type the underlying type */ -template class ADSREnvelope { public: + using Float = float; + ADSREnvelope() = default; /** * @brief Resets the ADSR envelope given a Region, the current midi state, and a delay and @@ -34,22 +33,22 @@ public: /** * @brief Get the next value for the envelope * - * @return Type + * @return Float */ - Type getNextValue() noexcept; + Float getNextValue() noexcept; /** * @brief Get a block of values for the envelope. This method tries hard to be efficient * and hopefully it is. * * @param output */ - void getBlock(absl::Span output) noexcept; + void getBlock(absl::Span output) noexcept; /** * @brief Set the release time for the envelope * * @param timeInSeconds */ - void setReleaseTime(Type timeInSeconds) noexcept; + void setReleaseTime(Float timeInSeconds) noexcept; /** * @brief Start the envelope release after a delay. * @@ -62,26 +61,26 @@ public: * @return true * @return false */ - bool isSmoothing() const noexcept; + bool isSmoothing() const noexcept { return currentState != State::Done; } /** * @brief Is the envelope released? * * @return true * @return false */ - bool isReleased() const noexcept; + bool isReleased() const noexcept { return currentState == State::Release || shouldRelease; } /** * @brief Get the remaining delay samples * * @return int */ - int getRemainingDelay() const noexcept; + int getRemainingDelay() const noexcept { return delay; } private: float sampleRate { config::defaultSampleRate }; - Type secondsToSamples (Type timeInSeconds) const noexcept; - Type secondsToLinRate (Type timeInSeconds) const noexcept; - Type secondsToExpRate (Type timeInSeconds) const noexcept; + Float secondsToSamples(Float timeInSeconds) const noexcept; + Float secondsToLinRate(Float timeInSeconds) const noexcept; + Float secondsToExpRate(Float timeInSeconds) const noexcept; enum class State { Delay, @@ -93,16 +92,16 @@ private: Done }; State currentState { State::Done }; - Type currentValue { 0.0 }; + Float currentValue { 0.0 }; int delay { 0 }; - Type attackStep { 0 }; - Type decayRate { 0 }; - Type releaseRate { 0 }; + Float attackStep { 0 }; + Float decayRate { 0 }; + Float releaseRate { 0 }; int hold { 0 }; - Type start { 0 }; - Type peak { 0 }; - Type sustain { 0 }; - Type sustainThreshold { config::virtuallyZero }; + Float start { 0 }; + Float peak { 0 }; + Float sustain { 0 }; + Float sustainThreshold { config::virtuallyZero }; int releaseDelay { 0 }; bool shouldRelease { false }; bool freeRunning { false }; diff --git a/src/sfizz/FloatEnvelopes.cpp b/src/sfizz/FloatEnvelopes.cpp deleted file mode 100644 index e4c5289c..00000000 --- a/src/sfizz/FloatEnvelopes.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "ADSREnvelope.h" - -// Include the generic implementations -#include "ADSREnvelope.cpp" - -// And explicitely instantiate the float version -namespace sfz -{ - template class ADSREnvelope; -} diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index a93c925a..cdad7af7 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -213,9 +213,9 @@ struct Voice::Impl std::vector> lfos_; std::vector> flexEGs_; - ADSREnvelope egAmplitude_; - std::unique_ptr> egPitch_; - std::unique_ptr> egFilter_; + ADSREnvelope egAmplitude_; + std::unique_ptr egPitch_; + std::unique_ptr egFilter_; float bendStepFactor_ { centsFactor(1) }; WavetableOscillator waveOscillators_[config::oscillatorsPerVoice]; @@ -1553,7 +1553,7 @@ void Voice::setPitchEGEnabledPerVoice(bool havePitchEG) { Impl& impl = *impl_; if (havePitchEG) - impl.egPitch_.reset(new ADSREnvelope); + impl.egPitch_.reset(new ADSREnvelope); else impl.egPitch_.reset(); } @@ -1562,7 +1562,7 @@ void Voice::setFilterEGEnabledPerVoice(bool haveFilterEG) { Impl& impl = *impl_; if (haveFilterEG) - impl.egFilter_.reset(new ADSREnvelope); + impl.egFilter_.reset(new ADSREnvelope); else impl.egFilter_.reset(); } @@ -1782,19 +1782,19 @@ Duration Voice::getLastPanningDuration() const noexcept return impl.panningDuration_; } -ADSREnvelope* Voice::getAmplitudeEG() +ADSREnvelope* Voice::getAmplitudeEG() { Impl& impl = *impl_; return &impl.egAmplitude_; } -ADSREnvelope* Voice::getPitchEG() +ADSREnvelope* Voice::getPitchEG() { Impl& impl = *impl_; return impl.egPitch_.get(); } -ADSREnvelope* Voice::getFilterEG() +ADSREnvelope* Voice::getFilterEG() { Impl& impl = *impl_; return impl.egFilter_.get(); diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 35428a6b..b6a07d38 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -337,15 +337,15 @@ public: /** * @brief Get the SFZv1 amplitude EG, if existing */ - ADSREnvelope* getAmplitudeEG(); + ADSREnvelope* getAmplitudeEG(); /** * @brief Get the SFZv1 pitch EG, if existing */ - ADSREnvelope* getPitchEG(); + ADSREnvelope* getPitchEG(); /** * @brief Get the SFZv1 filter EG, if existing */ - ADSREnvelope* getFilterEG(); + ADSREnvelope* getFilterEG(); /** * @brief Get the trigger event diff --git a/src/sfizz/modulations/sources/ADSREnvelope.cpp b/src/sfizz/modulations/sources/ADSREnvelope.cpp index 2f589282..fb4640e0 100644 --- a/src/sfizz/modulations/sources/ADSREnvelope.cpp +++ b/src/sfizz/modulations/sources/ADSREnvelope.cpp @@ -29,7 +29,7 @@ void ADSREnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, } const Region* region = voice->getRegion(); - ADSREnvelope* eg = nullptr; + ADSREnvelope* eg = nullptr; const EGDescription* desc = nullptr; switch (sourceKey.id()) { @@ -66,7 +66,7 @@ void ADSREnvelopeSource::release(const ModKey& sourceKey, NumericId voice return; } - ADSREnvelope* eg = nullptr; + ADSREnvelope* eg = nullptr; switch (sourceKey.id()) { case ModId::AmpEG: @@ -97,7 +97,7 @@ void ADSREnvelopeSource::generate(const ModKey& sourceKey, NumericId voic return; } - ADSREnvelope* eg = nullptr; + ADSREnvelope* eg = nullptr; switch (sourceKey.id()) { case ModId::AmpEG: diff --git a/tests/ADSREnvelopeT.cpp b/tests/ADSREnvelopeT.cpp index 424d8273..f0e12b79 100644 --- a/tests/ADSREnvelopeT.cpp +++ b/tests/ADSREnvelopeT.cpp @@ -16,7 +16,7 @@ using namespace Catch::literals; TEST_CASE("[ADSREnvelope] Basic state") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; std::array output; std::array expected { 0.0, 0.0, 0.0, 0.0, 0.0 }; envelope.getBlock(absl::MakeSpan(output)); @@ -29,7 +29,7 @@ TEST_CASE("[ADSREnvelope] Basic state") TEST_CASE("[ADSREnvelope] Attack") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.02f; @@ -48,7 +48,7 @@ TEST_CASE("[ADSREnvelope] Attack") TEST_CASE("[ADSREnvelope] Attack again") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.03f; @@ -67,7 +67,7 @@ TEST_CASE("[ADSREnvelope] Attack again") TEST_CASE("[ADSREnvelope] Release") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.02f; @@ -89,7 +89,7 @@ TEST_CASE("[ADSREnvelope] Release") TEST_CASE("[ADSREnvelope] Delay") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.02f; @@ -111,7 +111,7 @@ TEST_CASE("[ADSREnvelope] Delay") TEST_CASE("[ADSREnvelope] Lower sustain") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.02f; @@ -132,7 +132,7 @@ TEST_CASE("[ADSREnvelope] Lower sustain") TEST_CASE("[ADSREnvelope] Decay") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.02f; @@ -154,7 +154,7 @@ TEST_CASE("[ADSREnvelope] Decay") TEST_CASE("[ADSREnvelope] Hold") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.02f; @@ -177,7 +177,7 @@ TEST_CASE("[ADSREnvelope] Hold") TEST_CASE("[ADSREnvelope] Hold with release") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.02f; @@ -202,7 +202,7 @@ TEST_CASE("[ADSREnvelope] Hold with release") TEST_CASE("[ADSREnvelope] Hold with release 2") { - sfz::ADSREnvelope envelope; + sfz::ADSREnvelope envelope; sfz::MidiState state; sfz::Region region { state }; region.amplitudeEG.attack = 0.02f; From 42271fd682562e729b6eaf643b58f0b2c0d002e0 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 12:56:22 +0100 Subject: [PATCH 176/668] Match LFO behavior to ARIA: pulse and sine --- src/sfizz/LFO.cpp | 14 +++++++++----- src/sfizz/effects/CommonLFO.hpp | 14 +++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/sfizz/LFO.cpp b/src/sfizz/LFO.cpp index 547e296c..053ef1b1 100644 --- a/src/sfizz/LFO.cpp +++ b/src/sfizz/LFO.cpp @@ -102,31 +102,35 @@ template <> inline float LFO::eval(float phase) { float x = phase + phase - 1; - return 4 * x * (1 - std::fabs(x)); + return -4 * x * (1 - std::fabs(x)); } +// Pulse and Square levels +static constexpr float loPulse = 0.0f; // 0 in ARIA, -1 in Cakewalk +static constexpr float hiPulse = 1.0f; + template <> inline float LFO::eval(float phase) { - return (phase < 0.75f) ? +1.0f : -1.0f; + return (phase < 0.75f) ? hiPulse : loPulse; } template <> inline float LFO::eval(float phase) { - return (phase < 0.5f) ? +1.0f : -1.0f; + return (phase < 0.5f) ? hiPulse : loPulse; } template <> inline float LFO::eval(float phase) { - return (phase < 0.25f) ? +1.0f : -1.0f; + return (phase < 0.25f) ? hiPulse : loPulse; } template <> inline float LFO::eval(float phase) { - return (phase < 0.125f) ? +1.0f : -1.0f; + return (phase < 0.125f) ? hiPulse : loPulse; } template <> diff --git a/src/sfizz/effects/CommonLFO.hpp b/src/sfizz/effects/CommonLFO.hpp index ef6eef36..d43c0e88 100644 --- a/src/sfizz/effects/CommonLFO.hpp +++ b/src/sfizz/effects/CommonLFO.hpp @@ -11,6 +11,10 @@ namespace sfz { namespace fx { namespace lfo { + // Pulse and Square levels + static constexpr float loPulse = 0.0f; // 0 in ARIA, -1 in Cakewalk + static constexpr float hiPulse = 1.0f; + template <> inline float evaluateAtPhase(float phase) { @@ -24,31 +28,31 @@ namespace lfo { inline float evaluateAtPhase(float phase) { float x = phase + phase - 1; - return 4 * x * (1 - std::fabs(x)); + return -4 * x * (1 - std::fabs(x)); } template <> inline float evaluateAtPhase(float phase) { - return (phase < 0.75f) ? +1.0f : -1.0f; + return (phase < 0.75f) ? hiPulse : loPulse; } template <> inline float evaluateAtPhase(float phase) { - return (phase < 0.5f) ? +1.0f : -1.0f; + return (phase < 0.5f) ? hiPulse : loPulse; } template <> inline float evaluateAtPhase(float phase) { - return (phase < 0.25f) ? +1.0f : -1.0f; + return (phase < 0.25f) ? hiPulse : loPulse; } template <> inline float evaluateAtPhase(float phase) { - return (phase < 0.125f) ? +1.0f : -1.0f; + return (phase < 0.125f) ? hiPulse : loPulse; } template <> From bdc388bd69573637029f964ef1da61b3c8309c86 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 13:05:15 +0100 Subject: [PATCH 177/668] Update tests --- demos/PlotLFO.cpp | 7 +- src/sfizz/Synth.cpp | 6 + src/sfizz/Synth.h | 6 + tests/LFOT.cpp | 7 +- tests/lfo/lfo_fade_and_delay_reference.dat | 400 ++++---- tests/lfo/lfo_subwave_reference.dat | 1000 ++++++++++---------- tests/lfo/lfo_waves_reference.dat | 998 +++++++++---------- 7 files changed, 1223 insertions(+), 1201 deletions(-) diff --git a/demos/PlotLFO.cpp b/demos/PlotLFO.cpp index 6f77f2f5..680ee721 100644 --- a/demos/PlotLFO.cpp +++ b/demos/PlotLFO.cpp @@ -108,7 +108,9 @@ int main(int argc, char* argv[]) return 1; } + constexpr size_t bufferSize = 1024; sfz::BufferPool bufferPool; + bufferPool.setBufferSize(bufferSize); size_t numLfos = desc.size(); std::vector> lfos(numLfos); @@ -131,7 +133,10 @@ int main(int argc, char* argv[]) std::vector> lfoOutputs(numLfos); for (size_t l = 0; l < numLfos; ++l) { lfoOutputs[l] = absl::MakeSpan(&outputMemory[l * numFrames], numFrames); - lfos[l]->process(lfoOutputs[l]); + for (size_t i = 0, currentFrames; i < numFrames; i += currentFrames) { + currentFrames = std::min(numFrames - i, bufferSize); + lfos[l]->process(lfoOutputs[l].subspan(i, currentFrames)); + } } if (saveFlac) { diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index ed7bf3b0..f6362faa 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -811,6 +811,12 @@ void Synth::setSamplesPerBlock(int samplesPerBlock) noexcept } } +int Synth::getSamplesPerBlock() const noexcept +{ + Impl& impl = *impl_; + return impl.samplesPerBlock_; +} + void Synth::setSampleRate(float sampleRate) noexcept { Impl& impl = *impl_; diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 3a05b3c9..9afb3104 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -270,6 +270,12 @@ public: * @param samplesPerBlock */ void setSamplesPerBlock(int samplesPerBlock) noexcept; + /** + * @brief Get the maximum size of the blocks for the callback. The actual + * size can be lower in each callback but should not be larger + * than this value. + */ + int getSamplesPerBlock() const noexcept; /** * @brief Set the sample rate. If you do not call it it is initialized * to sfz::config::defaultSampleRate. diff --git a/tests/LFOT.cpp b/tests/LFOT.cpp index 4f2b6a6d..26bd0fb1 100644 --- a/tests/LFOT.cpp +++ b/tests/LFOT.cpp @@ -21,6 +21,8 @@ static bool computeLFO(DataPoints& dp, const fs::path& sfzPath, double sampleRat if (synth.getNumRegions() != 1) return false; + size_t bufferSize = static_cast(synth.getSamplesPerBlock()); + const std::vector& desc = synth.getRegionView(0)->lfos; size_t numLfos = desc.size(); std::vector> lfos(numLfos); @@ -42,7 +44,10 @@ static bool computeLFO(DataPoints& dp, const fs::path& sfzPath, double sampleRat std::vector> lfoOutputs(numLfos); for (size_t l = 0; l < numLfos; ++l) { lfoOutputs[l] = absl::MakeSpan(&outputMemory[l * numFrames], numFrames); - lfos[l]->process(lfoOutputs[l]); + for (size_t i = 0, currentFrames; i < numFrames; i += currentFrames) { + currentFrames = std::min(numFrames - i, bufferSize); + lfos[l]->process(lfoOutputs[l].subspan(i, currentFrames)); + } } dp.rows = numFrames; diff --git a/tests/lfo/lfo_fade_and_delay_reference.dat b/tests/lfo/lfo_fade_and_delay_reference.dat index fa6a155f..4d345820 100644 --- a/tests/lfo/lfo_fade_and_delay_reference.dat +++ b/tests/lfo/lfo_fade_and_delay_reference.dat @@ -99,56 +99,56 @@ 0.98 0.48 0.99 0.49 1 0.5 -1.01 -0.51 -1.02 -0.52 -1.03 -0.53 -1.04 -0.54 -1.05 -0.55 -1.06 -0.56 -1.07 -0.57 -1.08 -0.58 -1.09 -0.59 -1.1 -0.6 -1.11 -0.61 -1.12 -0.62 -1.13 -0.63 -1.14 -0.64 -1.15 -0.65 -1.16 -0.66 -1.17 -0.67 -1.18 -0.68 -1.19 -0.69 -1.2 -0.7 -1.21 -0.71 -1.22 -0.72 -1.23 -0.73 -1.24 -0.74 -1.25 -0.75 -1.26 -0.76 -1.27 -0.77 -1.28 -0.78 -1.29 -0.79 -1.3 -0.8 -1.31 -0.81 -1.32 -0.82 -1.33 -0.83 -1.34 -0.839999 -1.35 -0.849999 -1.36 -0.859999 -1.37 -0.869999 -1.38 -0.879999 -1.39 -0.889999 -1.4 -0.899999 -1.41 -0.909999 -1.42 -0.919999 -1.43 -0.929999 -1.44 -0.939999 -1.45 -0.949999 -1.46 -0.959999 -1.47 -0.969999 -1.48 -0.979999 -1.49 -0.989999 -1.5 -0.999999 +1.01 0 +1.02 0 +1.03 0 +1.04 0 +1.05 0 +1.06 0 +1.07 0 +1.08 0 +1.09 0 +1.1 0 +1.11 0 +1.12 0 +1.13 0 +1.14 0 +1.15 0 +1.16 0 +1.17 0 +1.18 0 +1.19 0 +1.2 0 +1.21 0 +1.22 0 +1.23 0 +1.24 0 +1.25 0 +1.26 0 +1.27 0 +1.28 0 +1.29 0 +1.3 0 +1.31 0 +1.32 0 +1.33 0 +1.34 0 +1.35 0 +1.36 0 +1.37 0 +1.38 0 +1.39 0 +1.4 0 +1.41 0 +1.42 0 +1.43 0 +1.44 0 +1.45 0 +1.46 0 +1.47 0 +1.48 0 +1.49 0 +1.5 0 1.51 1 1.52 1 1.53 1 @@ -199,56 +199,56 @@ 1.98 1 1.99 1 2 1 -2.01 -1 -2.02 -1 -2.03 -1 -2.04 -1 -2.05 -1 -2.06 -1 -2.07 -1 -2.08 -1 -2.09 -1 -2.1 -1 -2.11 -1 -2.12 -1 -2.13 -1 -2.14 -1 -2.15 -1 -2.16 -1 -2.17 -1 -2.18 -1 -2.19 -1 -2.2 -1 -2.21 -1 -2.22 -1 -2.23 -1 -2.24 -1 -2.25 -1 -2.26 -1 -2.27 -1 -2.28 -1 -2.29 -1 -2.3 -1 -2.31 -1 -2.32 -1 -2.33 -1 -2.34 -1 -2.35 -1 -2.36 -1 -2.37 -1 -2.38 -1 -2.39 -1 -2.4 -1 -2.41 -1 -2.42 -1 -2.43 -1 -2.44 -1 -2.45 -1 -2.46 -1 -2.47 -1 -2.48 -1 -2.49 -1 -2.5 -1 +2.01 0 +2.02 0 +2.03 0 +2.04 0 +2.05 0 +2.06 0 +2.07 0 +2.08 0 +2.09 0 +2.1 0 +2.11 0 +2.12 0 +2.13 0 +2.14 0 +2.15 0 +2.16 0 +2.17 0 +2.18 0 +2.19 0 +2.2 0 +2.21 0 +2.22 0 +2.23 0 +2.24 0 +2.25 0 +2.26 0 +2.27 0 +2.28 0 +2.29 0 +2.3 0 +2.31 0 +2.32 0 +2.33 0 +2.34 0 +2.35 0 +2.36 0 +2.37 0 +2.38 0 +2.39 0 +2.4 0 +2.41 0 +2.42 0 +2.43 0 +2.44 0 +2.45 0 +2.46 0 +2.47 0 +2.48 0 +2.49 0 +2.5 0 2.51 1 2.52 1 2.53 1 @@ -299,56 +299,56 @@ 2.98 1 2.99 1 3 1 -3.01 -1 -3.02 -1 -3.03 -1 -3.04 -1 -3.05 -1 -3.06 -1 -3.07 -1 -3.08 -1 -3.09 -1 -3.1 -1 -3.11 -1 -3.12 -1 -3.13 -1 -3.14 -1 -3.15 -1 -3.16 -1 -3.17 -1 -3.18 -1 -3.19 -1 -3.2 -1 -3.21 -1 -3.22 -1 -3.23 -1 -3.24 -1 -3.25 -1 -3.26 -1 -3.27 -1 -3.28 -1 -3.29 -1 -3.3 -1 -3.31 -1 -3.32 -1 -3.33 -1 -3.34 -1 -3.35 -1 -3.36 -1 -3.37 -1 -3.38 -1 -3.39 -1 -3.4 -1 -3.41 -1 -3.42 -1 -3.43 -1 -3.44 -1 -3.45 -1 -3.46 -1 -3.47 -1 -3.48 -1 -3.49 -1 -3.5 -1 +3.01 0 +3.02 0 +3.03 0 +3.04 0 +3.05 0 +3.06 0 +3.07 0 +3.08 0 +3.09 0 +3.1 0 +3.11 0 +3.12 0 +3.13 0 +3.14 0 +3.15 0 +3.16 0 +3.17 0 +3.18 0 +3.19 0 +3.2 0 +3.21 0 +3.22 0 +3.23 0 +3.24 0 +3.25 0 +3.26 0 +3.27 0 +3.28 0 +3.29 0 +3.3 0 +3.31 0 +3.32 0 +3.33 0 +3.34 0 +3.35 0 +3.36 0 +3.37 0 +3.38 0 +3.39 0 +3.4 0 +3.41 0 +3.42 0 +3.43 0 +3.44 0 +3.45 0 +3.46 0 +3.47 0 +3.48 0 +3.49 0 +3.5 0 3.51 1 3.52 1 3.53 1 @@ -399,56 +399,56 @@ 3.98 1 3.99 1 4 1 -4.01 -1 -4.02 -1 -4.03 -1 -4.04 -1 -4.05 -1 -4.06 -1 -4.07 -1 -4.08 -1 -4.09 -1 -4.1 -1 -4.11 -1 -4.12 -1 -4.13 -1 -4.14 -1 -4.15 -1 -4.16 -1 -4.17 -1 -4.18 -1 -4.19 -1 -4.2 -1 -4.21 -1 -4.22 -1 -4.23 -1 -4.24 -1 -4.25 -1 -4.26 -1 -4.27 -1 -4.28 -1 -4.29 -1 -4.3 -1 -4.31 -1 -4.32 -1 -4.33 -1 -4.34 -1 -4.35 -1 -4.36 -1 -4.37 -1 -4.38 -1 -4.39 -1 -4.4 -1 -4.41 -1 -4.42 -1 -4.43 -1 -4.44 -1 -4.45 -1 -4.46 -1 -4.47 -1 -4.48 -1 -4.49 -1 -4.5 -1 +4.01 0 +4.02 0 +4.03 0 +4.04 0 +4.05 0 +4.06 0 +4.07 0 +4.08 0 +4.09 0 +4.1 0 +4.11 0 +4.12 0 +4.13 0 +4.14 0 +4.15 0 +4.16 0 +4.17 0 +4.18 0 +4.19 0 +4.2 0 +4.21 0 +4.22 0 +4.23 0 +4.24 0 +4.25 0 +4.26 0 +4.27 0 +4.28 0 +4.29 0 +4.3 0 +4.31 0 +4.32 0 +4.33 0 +4.34 0 +4.35 0 +4.36 0 +4.37 0 +4.38 0 +4.39 0 +4.4 0 +4.41 0 +4.42 0 +4.43 0 +4.44 0 +4.45 0 +4.46 0 +4.47 0 +4.48 0 +4.49 0 +4.5 0 4.51 1 4.52 1 4.53 1 diff --git a/tests/lfo/lfo_subwave_reference.dat b/tests/lfo/lfo_subwave_reference.dat index c4dd0ef1..188604b3 100644 --- a/tests/lfo/lfo_subwave_reference.dat +++ b/tests/lfo/lfo_subwave_reference.dat @@ -1,500 +1,500 @@ -0 -1 -1 -1 -0.5 -0.01 -1 -0.9216 -0.8464 -0.4232 -0.02 -1 -0.8464 -0.7056 -0.3528 -0.03 -1 -0.7744 -0.5776 -0.2888 -0.04 -1 -0.7056 -0.4624 -0.2312 -0.05 -1 -0.64 -0.36 -0.18 -0.06 -1 -0.5776 -0.2704 -0.1352 -0.07 -1 -0.5184 -0.1936 -0.0968002 -0.08 -1 -0.4624 -0.1296 -0.0648002 -0.09 -1 -0.4096 -0.0784004 -0.0392002 -0.1 -1 -0.36 -0.0400003 -0.0200002 -0.11 -1 -0.3136 -0.0144002 -0.00720009 -0.12 -1 -0.2704 -0.00160009 -0.000800043 -0.13 -1 -0.230401 -0.00159991 -0.000799954 -0.14 -1 -0.1936 -0.0143998 -0.00719988 -0.15 -1 -0.16 -0.0399995 -0.0199998 -0.16 -1 -0.1296 -0.0783993 -0.0391997 -0.17 -1 -0.1024 -0.129599 -0.0647995 -0.18 -1 -0.0784004 -0.193599 -0.0967994 -0.19 -1 -0.0576003 -0.270398 -0.135199 -0.2 -1 -0.0400003 -0.359998 -0.179999 -0.21 -1 -0.0256003 -0.462398 -0.231199 -0.22 -1 -0.0144002 -0.577597 -0.288799 -0.23 -1 -0.00640017 -0.705597 -0.352799 -0.24 -1 -0.00160009 -0.846397 -0.423198 -0.25 -1 0 -0.999996 -0.499998 -0.26 -1 -0.00159991 -1.1536 -0.576798 -0.27 -1 -0.00639981 -1.2944 -0.647198 -0.28 -1 -0.0143998 -1.4224 -0.711198 -0.29 -1 -0.0255997 -1.5376 -0.768799 -0.3 -1 -0.0399995 -1.64 -0.819999 -0.31 -1 -0.0575994 -1.7296 -0.864799 -0.32 -1 -0.0783993 -1.8064 -0.903199 -0.33 -1 -0.102399 -1.8704 -0.935199 -0.34 -1 -0.129599 -1.9216 -0.960799 -0.35 -1 -0.159999 -1.96 -0.98 -0.36 -1 -0.193599 -1.9856 -0.9928 -0.37 -1 -0.230399 -1.9984 -0.9992 -0.38 -1 -0.270398 -1.9984 -0.9992 -0.39 -1 -0.313598 -1.9856 -0.9928 -0.4 -1 -0.359998 -1.96 -0.98 -0.41 -1 -0.409598 -1.9216 -0.960801 -0.42 -1 -0.462398 -1.8704 -0.935201 -0.43 -1 -0.518398 -1.8064 -0.903201 -0.44 -1 -0.577597 -1.7296 -0.864801 -0.45 -1 -0.639997 -1.64 -0.820001 -0.46 -1 -0.705597 -1.5376 -0.768801 -0.47 -1 -0.774397 -1.4224 -0.711201 -0.48 -1 -0.846397 -1.2944 -0.647201 -0.49 -1 -0.921596 -1.1536 -0.576801 -0.5 -1 -0.999996 -1 -0.500002 -0.51 1 0.921604 1.1536 1.5768 -0.52 1 0.846404 1.2944 1.6472 -0.53 1 0.774403 1.4224 1.7112 -0.54 1 0.705603 1.5376 1.7688 -0.55 1 0.640003 1.64 1.82 -0.56 1 0.577603 1.7296 1.8648 -0.57 1 0.518403 1.8064 1.9032 -0.58 1 0.462403 1.8704 1.9352 -0.59 1 0.409603 1.9216 1.9608 -0.6 1 0.360002 1.96 1.98 -0.61 1 0.313602 1.9856 1.9928 -0.62 1 0.270402 1.9984 1.9992 -0.63 1 0.230402 1.9984 1.9992 -0.64 1 0.193602 1.9856 1.9928 -0.65 1 0.160002 1.96 1.98 -0.66 1 0.129601 1.9216 1.9608 -0.67 1 0.102401 1.8704 1.9352 -0.68 1 0.078401 1.8064 1.9032 -0.69 1 0.0576009 1.7296 1.8648 -0.7 1 0.0400007 1.64 1.82 -0.71 1 0.0256006 1.5376 1.7688 -0.72 1 0.0144004 1.4224 1.7112 -0.73 1 0.00640029 1.29441 1.6472 -0.74 1 0.00160015 1.15361 1.5768 -0.75 1 0 1.00001 1.5 -0.76 1 0.00159985 0.846406 1.4232 -0.77 1 0.00639969 0.705606 1.3528 -0.78 1 0.0143996 0.577605 1.2888 -0.79 1 0.0255994 0.462405 1.2312 -0.8 1 0.0399992 0.360004 1.18 -0.81 1 0.0575991 0.270404 1.1352 -0.82 1 0.0783989 0.193603 1.0968 -0.83 1 0.102399 0.129602 1.0648 -0.84 1 0.129599 0.078402 1.0392 -0.85 1 0.159998 0.0400014 1.02 -0.86 1 0.193598 0.0144008 1.0072 -0.87 1 0.230398 0.00160027 1.0008 -0.88 1 0.270398 0.00159973 1.0008 -0.89 1 0.313598 0.0143992 1.0072 -0.9 1 0.359997 0.0399987 1.02 -0.91 1 0.409597 0.0783981 1.0392 -0.92 1 0.462397 0.129598 1.0648 -0.93 1 0.518397 0.193597 1.0968 -0.94 1 0.577596 0.270397 1.1352 -0.95 1 0.639996 0.359996 1.18 -0.96 1 0.705596 0.462396 1.2312 -0.97 1 0.774396 0.577595 1.2888 -0.98 1 0.846395 0.705595 1.3528 -0.99 1 0.921595 0.846394 1.4232 -1 1 0.999995 0.999994 1.5 -1.01 -1 -0.921605 -0.846405 -0.423203 -1.02 -1 -0.846405 -0.705605 -0.352803 -1.03 -1 -0.774405 -0.577605 -0.288802 -1.04 -1 -0.705605 -0.462404 -0.231202 -1.05 -1 -0.640005 -0.360004 -0.180002 -1.06 -1 -0.577604 -0.270403 -0.135202 -1.07 -1 -0.518404 -0.193603 -0.0968015 -1.08 -1 -0.462404 -0.129602 -0.0648012 -1.09 -1 -0.409604 -0.078402 -0.039201 -1.1 -1 -0.360004 -0.0400015 -0.0200007 -1.11 -1 -0.313603 -0.0144009 -0.00720045 -1.12 -1 -0.270403 -0.00160033 -0.000800163 -1.13 -1 -0.230403 -0.00159967 -0.000799835 -1.14 -1 -0.193603 -0.0143991 -0.00719953 -1.15 -1 -0.160003 -0.0399984 -0.0199992 -1.16 -1 -0.129602 -0.0783977 -0.0391988 -1.17 -1 -0.102402 -0.129597 -0.0647985 -1.18 -1 -0.0784019 -0.193596 -0.0967982 -1.19 -1 -0.0576016 -0.270396 -0.135198 -1.2 -1 -0.0400013 -0.359995 -0.179997 -1.21 -1 -0.0256011 -0.462394 -0.231197 -1.22 -1 -0.0144008 -0.577593 -0.288797 -1.23 -1 -0.00640059 -0.705592 -0.352796 -1.24 -1 -0.00160027 -0.846391 -0.423196 -1.25 -1 0 -0.99999 -0.499995 -1.26 -1 -0.00159973 -1.15359 -0.576796 -1.27 -1 -0.00639939 -1.29439 -0.647196 -1.28 -1 -0.0143991 -1.42239 -0.711196 -1.29 -1 -0.0255988 -1.53759 -0.768797 -1.3 -1 -0.0399985 -1.63999 -0.819997 -1.31 -1 -0.0575982 -1.72959 -0.864797 -1.32 -1 -0.0783979 -1.8064 -0.903198 -1.33 -1 -0.102398 -1.8704 -0.935198 -1.34 -1 -0.129597 -1.9216 -0.960799 -1.35 -1 -0.159997 -1.96 -0.979999 -1.36 -1 -0.193596 -1.9856 -0.992799 -1.37 -1 -0.230396 -1.9984 -0.9992 -1.38 -1 -0.270396 -1.9984 -0.9992 -1.39 -1 -0.313595 -1.9856 -0.992801 -1.4 -1 -0.359995 -1.96 -0.980001 -1.41 -1 -0.409595 -1.9216 -0.960801 -1.42 -1 -0.462394 -1.8704 -0.935202 -1.43 -1 -0.518394 -1.8064 -0.903202 -1.44 -1 -0.577593 -1.7296 -0.864802 -1.45 -1 -0.639993 -1.64001 -0.820003 -1.46 -1 -0.705593 -1.53761 -0.768803 -1.47 -1 -0.774392 -1.42241 -0.711203 -1.48 -1 -0.846392 -1.29441 -0.647204 -1.49 -1 -0.921591 -1.15361 -0.576804 -1.5 -1 -0.999991 -1.00001 -0.500004 -1.51 1 0.921608 1.15359 1.5768 -1.52 1 0.846408 1.29439 1.6472 -1.53 1 0.774408 1.42239 1.7112 -1.54 1 0.705607 1.53759 1.7688 -1.55 1 0.640007 1.63999 1.82 -1.56 1 0.577606 1.7296 1.8648 -1.57 1 0.518406 1.8064 1.9032 -1.58 1 0.462406 1.8704 1.9352 -1.59 1 0.409606 1.9216 1.9608 -1.6 1 0.360005 1.96 1.98 -1.61 1 0.313605 1.9856 1.9928 -1.62 1 0.270405 1.9984 1.9992 -1.63 1 0.230404 1.9984 1.9992 -1.64 1 0.193604 1.9856 1.9928 -1.65 1 0.160003 1.96 1.98 -1.66 1 0.129603 1.9216 1.9608 -1.67 1 0.102403 1.8704 1.9352 -1.68 1 0.0784024 1.80641 1.9032 -1.69 1 0.057602 1.72961 1.8648 -1.7 1 0.0400017 1.64001 1.82 -1.71 1 0.0256013 1.53761 1.7688 -1.72 1 0.014401 1.42241 1.7112 -1.73 1 0.00640064 1.29441 1.64721 -1.74 1 0.00160033 1.15361 1.57681 -1.75 1 0 1.00001 1.50001 -1.76 1 0.00159967 0.846412 1.42321 -1.77 1 0.00639933 0.705611 1.35281 -1.78 1 0.014399 0.57761 1.2888 -1.79 1 0.0255986 0.462409 1.2312 -1.8 1 0.0399983 0.360008 1.18 -1.81 1 0.0575979 0.270407 1.1352 -1.82 1 0.0783976 0.193605 1.0968 -1.83 1 0.102397 0.129605 1.0648 -1.84 1 0.129597 0.0784036 1.0392 -1.85 1 0.159996 0.0400025 1.02 -1.86 1 0.193596 0.0144015 1.0072 -1.87 1 0.230396 0.0016005 1.0008 -1.88 1 0.270395 0.00159949 1.0008 -1.89 1 0.313595 0.0143985 1.0072 -1.9 1 0.359994 0.0399975 1.02 -1.91 1 0.409594 0.0783965 1.0392 -1.92 1 0.462394 0.129596 1.0648 -1.93 1 0.518393 0.193595 1.0968 -1.94 1 0.577593 0.270394 1.1352 -1.95 1 0.639992 0.359993 1.18 -1.96 1 0.705592 0.462392 1.2312 -1.97 1 0.774391 0.577591 1.2888 -1.98 1 0.846391 0.70559 1.3528 -1.99 1 0.92159 0.846389 1.42319 -2 1 0.99999 0.999988 1.49999 -2.01 -1 -0.92161 -0.846411 -0.423205 -2.02 -1 -0.846409 -0.70561 -0.352805 -2.03 -1 -0.774409 -0.577609 -0.288805 -2.04 -1 -0.705609 -0.462408 -0.231204 -2.05 -1 -0.640008 -0.360007 -0.180004 -2.06 -1 -0.577608 -0.270406 -0.135203 -2.07 -1 -0.518408 -0.193605 -0.0968027 -2.08 -1 -0.462407 -0.129605 -0.0648023 -2.09 -1 -0.409607 -0.0784036 -0.0392018 -2.1 -1 -0.360006 -0.0400026 -0.0200013 -2.11 -1 -0.313606 -0.0144016 -0.00720078 -2.12 -1 -0.270406 -0.0016005 -0.000800252 -2.13 -1 -0.230405 -0.00159949 -0.000799745 -2.14 -1 -0.193605 -0.0143984 -0.0071992 -2.15 -1 -0.160004 -0.0399973 -0.0199986 -2.16 -1 -0.129604 -0.0783961 -0.0391981 -2.17 -1 -0.102404 -0.129595 -0.0647975 -2.18 -1 -0.0784032 -0.193594 -0.0967969 -2.19 -1 -0.0576028 -0.270393 -0.135196 -2.2 -1 -0.0400023 -0.359991 -0.179996 -2.21 -1 -0.0256019 -0.46239 -0.231195 -2.22 -1 -0.0144014 -0.577589 -0.288794 -2.23 -1 -0.00640094 -0.705587 -0.352794 -2.24 -1 -0.00160044 -0.846386 -0.423193 -2.25 -1 0 -0.999985 -0.499992 -2.26 -1 -0.00159949 -1.15359 -0.576793 -2.27 -1 -0.00639904 -1.29439 -0.647194 -2.28 -1 -0.0143985 -1.42239 -0.711194 -2.29 -1 -0.025598 -1.53759 -0.768795 -2.3 -1 -0.0399975 -1.63999 -0.819995 -2.31 -1 -0.057597 -1.72959 -0.864796 -2.32 -1 -0.0783965 -1.80639 -0.903197 -2.33 -1 -0.102396 -1.87039 -0.935197 -2.34 -1 -0.129595 -1.9216 -0.960798 -2.35 -1 -0.159995 -1.96 -0.979998 -2.36 -1 -0.193594 -1.9856 -0.992799 -2.37 -1 -0.230394 -1.9984 -0.9992 -2.38 -1 -0.270393 -1.9984 -0.9992 -2.39 -1 -0.313593 -1.9856 -0.992801 -2.4 -1 -0.359992 -1.96 -0.980002 -2.41 -1 -0.409592 -1.9216 -0.960802 -2.42 -1 -0.462391 -1.87041 -0.935203 -2.43 -1 -0.51839 -1.80641 -0.903203 -2.44 -1 -0.57759 -1.72961 -0.864804 -2.45 -1 -0.639989 -1.64001 -0.820004 -2.46 -1 -0.705589 -1.53761 -0.768805 -2.47 -1 -0.774388 -1.42241 -0.711206 -2.48 -1 -0.846387 -1.29441 -0.647206 -2.49 -1 -0.921587 -1.15361 -0.576807 -2.5 -1 -0.999986 -1.00001 -0.500007 -2.51 1 0.921613 1.15359 1.57679 -2.52 1 0.846412 1.29439 1.64719 -2.53 1 0.774412 1.42239 1.71119 -2.54 1 0.705611 1.53759 1.76879 -2.55 1 0.640011 1.63999 1.82 -2.56 1 0.57761 1.72959 1.8648 -2.57 1 0.51841 1.80639 1.9032 -2.58 1 0.462409 1.87039 1.9352 -2.59 1 0.409609 1.9216 1.9608 -2.6 1 0.360008 1.96 1.98 -2.61 1 0.313608 1.9856 1.9928 -2.62 1 0.270407 1.9984 1.9992 -2.63 1 0.230406 1.9984 1.9992 -2.64 1 0.193606 1.9856 1.9928 -2.65 1 0.160005 1.96 1.98 -2.66 1 0.129605 1.9216 1.9608 -2.67 1 0.102404 1.87041 1.9352 -2.68 1 0.0784037 1.80641 1.9032 -2.69 1 0.0576032 1.72961 1.8648 -2.7 1 0.0400026 1.64001 1.82001 -2.71 1 0.0256021 1.53761 1.76881 -2.72 1 0.0144016 1.42241 1.71121 -2.73 1 0.00640106 1.29441 1.64721 -2.74 1 0.0016005 1.15362 1.57681 -2.75 1 0 1.00002 1.50001 -2.76 1 0.00159949 0.846417 1.42321 -2.77 1 0.00639898 0.705615 1.35281 -2.78 1 0.0143985 0.577614 1.28881 -2.79 1 0.0255979 0.462412 1.23121 -2.8 1 0.0399973 0.360011 1.18001 -2.81 1 0.0575968 0.27041 1.1352 -2.82 1 0.0783963 0.193608 1.0968 -2.83 1 0.102396 0.129607 1.0648 -2.84 1 0.129595 0.0784052 1.0392 -2.85 1 0.159995 0.0400037 1.02 -2.86 1 0.193594 0.0144022 1.0072 -2.87 1 0.230393 0.00160074 1.0008 -2.88 1 0.270393 0.00159925 1.0008 -2.89 1 0.313592 0.0143978 1.0072 -2.9 1 0.359992 0.0399963 1.02 -2.91 1 0.409591 0.0783949 1.0392 -2.92 1 0.46239 0.129593 1.0648 -2.93 1 0.51839 0.193592 1.0968 -2.94 1 0.577589 0.270391 1.1352 -2.95 1 0.639988 0.359989 1.17999 -2.96 1 0.705588 0.462388 1.23119 -2.97 1 0.774387 0.577587 1.28879 -2.98 1 0.846387 0.705585 1.35279 -2.99 1 0.921586 0.846384 1.42319 -3 1 0.999985 0.999983 1.49999 -3.01 -1 -0.921614 -0.846416 -0.423208 -3.02 -1 -0.846414 -0.705615 -0.352807 -3.03 -1 -0.774413 -0.577613 -0.288807 -3.04 -1 -0.705613 -0.462412 -0.231206 -3.05 -1 -0.640012 -0.360011 -0.180005 -3.06 -1 -0.577612 -0.270409 -0.135205 -3.07 -1 -0.518411 -0.193608 -0.096804 -3.08 -1 -0.46241 -0.129607 -0.0648033 -3.09 -1 -0.40961 -0.0784052 -0.0392026 -3.1 -1 -0.360009 -0.0400037 -0.0200019 -3.11 -1 -0.313609 -0.0144023 -0.00720114 -3.12 -1 -0.270408 -0.00160074 -0.000800371 -3.13 -1 -0.230408 -0.00159925 -0.000799626 -3.14 -1 -0.193607 -0.0143977 -0.00719884 -3.15 -1 -0.160006 -0.0399961 -0.019998 -3.16 -1 -0.129606 -0.0783945 -0.0391973 -3.17 -1 -0.102405 -0.129593 -0.0647964 -3.18 -1 -0.0784045 -0.193591 -0.0967956 -3.19 -1 -0.0576039 -0.27039 -0.135195 -3.2 -1 -0.0400032 -0.359988 -0.179994 -3.21 -1 -0.0256026 -0.462386 -0.231193 -3.22 -1 -0.014402 -0.577584 -0.288792 -3.23 -1 -0.0064013 -0.705583 -0.352791 -3.24 -1 -0.00160068 -0.846381 -0.42319 -3.25 -1 0 -0.999979 -0.49999 -3.26 -1 -0.00159931 -1.15358 -0.57679 -3.27 -1 -0.00639868 -1.29438 -0.647191 -3.28 -1 -0.014398 -1.42238 -0.711192 -3.29 -1 -0.0255973 -1.53759 -0.768793 -3.3 -1 -0.0399966 -1.63999 -0.819994 -3.31 -1 -0.0575959 -1.72959 -0.864794 -3.32 -1 -0.0783952 -1.80639 -0.903195 -3.33 -1 -0.102394 -1.87039 -0.935196 -3.34 -1 -0.129594 -1.92159 -0.960797 -3.35 -1 -0.159993 -1.96 -0.979998 -3.36 -1 -0.193592 -1.9856 -0.992799 -3.37 -1 -0.230392 -1.9984 -0.9992 -3.38 -1 -0.270391 -1.9984 -0.9992 -3.39 -1 -0.31359 -1.9856 -0.992801 -3.4 -1 -0.359989 -1.96 -0.980002 -3.41 -1 -0.409589 -1.92161 -0.960803 -3.42 -1 -0.462388 -1.87041 -0.935204 -3.43 -1 -0.518387 -1.80641 -0.903205 -3.44 -1 -0.577586 -1.72961 -0.864805 -3.45 -1 -0.639985 -1.64001 -0.820006 -3.46 -1 -0.705585 -1.53761 -0.768807 -3.47 -1 -0.774384 -1.42242 -0.711208 -3.48 -1 -0.846383 -1.29442 -0.647209 -3.49 -1 -0.921582 -1.15362 -0.576809 -3.5 -1 -0.999981 -1.00002 -0.50001 -3.51 1 0.921617 1.15358 1.57679 -3.52 1 0.846417 1.29438 1.64719 -3.53 1 0.774416 1.42238 1.71119 -3.54 1 0.705615 1.53759 1.76879 -3.55 1 0.640015 1.63999 1.81999 -3.56 1 0.577614 1.72959 1.86479 -3.57 1 0.518413 1.80639 1.9032 -3.58 1 0.462412 1.87039 1.9352 -3.59 1 0.409612 1.92159 1.9608 -3.6 1 0.360011 1.96 1.98 -3.61 1 0.31361 1.9856 1.9928 -3.62 1 0.27041 1.9984 1.9992 -3.63 1 0.230409 1.9984 1.9992 -3.64 1 0.193608 1.9856 1.9928 -3.65 1 0.160007 1.96 1.98 -3.66 1 0.129607 1.92161 1.9608 -3.67 1 0.102406 1.87041 1.9352 -3.68 1 0.0784051 1.80641 1.90321 -3.69 1 0.0576044 1.72961 1.86481 -3.7 1 0.0400036 1.64001 1.82001 -3.71 1 0.0256029 1.53762 1.76881 -3.72 1 0.0144022 1.42242 1.71121 -3.73 1 0.00640142 1.29442 1.64721 -3.74 1 0.00160068 1.15362 1.57681 -3.75 1 0 1.00002 1.50001 -3.76 1 0.00159931 0.846422 1.42321 -3.77 1 0.00639856 0.70562 1.35281 -3.78 1 0.0143979 0.577618 1.28881 -3.79 1 0.0255972 0.462416 1.23121 -3.8 1 0.0399964 0.360014 1.18001 -3.81 1 0.0575957 0.270413 1.13521 -3.82 1 0.0783949 0.193611 1.09681 -3.83 1 0.102394 0.129609 1.0648 -3.84 1 0.129593 0.0784068 1.0392 -3.85 1 0.159993 0.0400048 1.02 -3.86 1 0.193592 0.0144029 1.0072 -3.87 1 0.230391 0.00160098 1.0008 -3.88 1 0.27039 0.00159901 1.0008 -3.89 1 0.31359 0.0143971 1.0072 -3.9 1 0.359989 0.0399952 1.02 -3.91 1 0.409588 0.0783933 1.0392 -3.92 1 0.462387 0.129591 1.0648 -3.93 1 0.518386 0.19359 1.09679 -3.94 1 0.577585 0.270388 1.13519 -3.95 1 0.639985 0.359986 1.17999 -3.96 1 0.705584 0.462384 1.23119 -3.97 1 0.774383 0.577582 1.28879 -3.98 1 0.846382 0.70558 1.35279 -3.99 1 0.921581 0.846379 1.42319 -4 1 0.99998 0.999977 1.49999 -4.01 -1 -0.921619 -0.846421 -0.423211 -4.02 -1 -0.846418 -0.705619 -0.35281 -4.03 -1 -0.774417 -0.577618 -0.288809 -4.04 -1 -0.705617 -0.462416 -0.231208 -4.05 -1 -0.640016 -0.360014 -0.180007 -4.06 -1 -0.577615 -0.270412 -0.135206 -4.07 -1 -0.518414 -0.193611 -0.0968053 -4.08 -1 -0.462414 -0.129609 -0.0648043 -4.09 -1 -0.409613 -0.0784068 -0.0392034 -4.1 -1 -0.360012 -0.0400049 -0.0200025 -4.11 -1 -0.313611 -0.0144029 -0.00720146 -4.12 -1 -0.270411 -0.00160098 -0.00080049 -4.13 -1 -0.23041 -0.00159901 -0.000799507 -4.14 -1 -0.193609 -0.014397 -0.00719851 -4.15 -1 -0.160008 -0.039995 -0.0199975 -4.16 -1 -0.129607 -0.0783929 -0.0391965 -4.17 -1 -0.102407 -0.129591 -0.0647954 -4.18 -1 -0.0784059 -0.193589 -0.0967944 -4.19 -1 -0.057605 -0.270387 -0.135193 -4.2 -1 -0.0400042 -0.359984 -0.179992 -4.21 -1 -0.0256034 -0.462382 -0.231191 -4.22 -1 -0.0144026 -0.57758 -0.28879 -4.23 -1 -0.00640172 -0.705578 -0.352789 -4.24 -1 -0.00160086 -0.846376 -0.423188 -4.25 -1 0 -0.999973 -0.499987 -4.26 -1 -0.00159913 -1.15358 -0.576788 -4.27 -1 -0.00639826 -1.29438 -0.647189 -4.28 -1 -0.0143974 -1.42238 -0.71119 -4.29 -1 -0.0255965 -1.53758 -0.768791 -4.3 -1 -0.0399956 -1.63998 -0.819992 -4.31 -1 -0.0575947 -1.72959 -0.864793 -4.32 -1 -0.0783938 -1.80639 -0.903194 -4.33 -1 -0.102393 -1.87039 -0.935195 -4.34 -1 -0.129592 -1.92159 -0.960796 -4.35 -1 -0.159991 -1.95999 -0.979997 -4.36 -1 -0.19359 -1.9856 -0.992798 -4.37 -1 -0.230389 -1.9984 -0.999199 -4.38 -1 -0.270388 -1.9984 -0.999201 -4.39 -1 -0.313587 -1.9856 -0.992802 -4.4 -1 -0.359986 -1.96001 -0.980003 -4.41 -1 -0.409585 -1.92161 -0.960804 -4.42 -1 -0.462385 -1.87041 -0.935205 -4.43 -1 -0.518384 -1.80641 -0.903206 -4.44 -1 -0.577583 -1.72961 -0.864807 -4.45 -1 -0.639982 -1.64002 -0.820008 -4.46 -1 -0.705581 -1.53762 -0.768809 -4.47 -1 -0.77438 -1.42242 -0.71121 -4.48 -1 -0.846379 -1.29442 -0.647211 -4.49 -1 -0.921578 -1.15362 -0.576812 -4.5 -1 -0.999977 -1.00003 -0.500013 -4.51 1 0.921622 1.15358 1.57679 -4.52 1 0.846421 1.29438 1.64719 -4.53 1 0.77442 1.42238 1.71119 -4.54 1 0.705619 1.53758 1.76879 -4.55 1 0.640018 1.63998 1.81999 -4.56 1 0.577617 1.72959 1.86479 -4.57 1 0.518417 1.80639 1.90319 -4.58 1 0.462416 1.87039 1.9352 -4.59 1 0.409615 1.92159 1.9608 -4.6 1 0.360014 1.95999 1.98 -4.61 1 0.313613 1.9856 1.9928 -4.62 1 0.270412 1.9984 1.9992 -4.63 1 0.230411 1.9984 1.9992 -4.64 1 0.19361 1.9856 1.9928 -4.65 1 0.160009 1.96001 1.98 -4.66 1 0.129608 1.92161 1.9608 -4.67 1 0.102407 1.87041 1.93521 -4.68 1 0.0784064 1.80641 1.90321 -4.69 1 0.0576055 1.72961 1.86481 -4.7 1 0.0400046 1.64002 1.82001 -4.71 1 0.0256036 1.53762 1.76881 -4.72 1 0.0144027 1.42242 1.71121 -4.73 1 0.00640184 1.29442 1.64721 -4.74 1 0.00160092 1.15363 1.57681 -4.75 1 0 1.00003 1.50001 -4.76 1 0.00159907 0.846427 1.42321 -4.77 1 0.0063982 0.705625 1.35281 -4.78 1 0.0143973 0.577623 1.28881 -4.79 1 0.0255964 0.46242 1.23121 -4.8 1 0.0399954 0.360018 1.18001 -4.81 1 0.0575945 0.270415 1.13521 -4.82 1 0.0783936 0.193613 1.09681 -4.83 1 0.102393 0.129611 1.06481 -4.84 1 0.129592 0.0784084 1.0392 -4.85 1 0.159991 0.040006 1.02 -4.86 1 0.19359 0.0144036 1.0072 -4.87 1 0.230389 0.00160122 1.0008 -4.88 1 0.270388 0.00159878 1.0008 -4.89 1 0.313587 0.0143964 1.0072 -4.9 1 0.359986 0.0399941 1.02 -4.91 1 0.409585 0.0783917 1.0392 -4.92 1 0.462384 0.129589 1.06479 -4.93 1 0.518383 0.193587 1.09679 -4.94 1 0.577582 0.270385 1.13519 -4.95 1 0.639981 0.359982 1.17999 -4.96 1 0.70558 0.46238 1.23119 -4.97 1 0.774379 0.577578 1.28879 -4.98 1 0.846378 0.705576 1.35279 -4.99 1 0.921577 0.846373 1.42319 +0 0 0 0 0.5 +0.01 0 -0.0783999 -0.1536 0.4232 +0.02 0 -0.1536 -0.2944 0.3528 +0.03 0 -0.2256 -0.4224 0.2888 +0.04 0 -0.2944 -0.5376 0.2312 +0.05 0 -0.36 -0.64 0.18 +0.06 0 -0.4224 -0.7296 0.1352 +0.07 0 -0.4816 -0.8064 0.0968 +0.08 0 -0.5376 -0.8704 0.0648001 +0.09 0 -0.5904 -0.9216 0.0392001 +0.1 0 -0.64 -0.96 0.02 +0.11 0 -0.6864 -0.9856 0.0072 +0.12 0 -0.7296 -0.9984 0.000800014 +0.13 0 -0.7696 -0.9984 0.000799984 +0.14 0 -0.8064 -0.9856 0.00719997 +0.15 0 -0.84 -0.96 0.02 +0.16 0 -0.8704 -0.9216 0.0392 +0.17 0 -0.8976 -0.8704 0.0648001 +0.18 0 -0.9216 -0.8064 0.0968 +0.19 0 -0.9424 -0.7296 0.1352 +0.2 0 -0.96 -0.64 0.18 +0.21 0 -0.9744 -0.5376 0.2312 +0.22 0 -0.9856 -0.4224 0.2888 +0.23 0 -0.9936 -0.2944 0.3528 +0.24 0 -0.9984 -0.153599 0.4232 +0.25 0 -1 0 0.5 +0.26 0 -0.9984 0.1536 0.5768 +0.27 0 -0.9936 0.2944 0.6472 +0.28 0 -0.9856 0.4224 0.7112 +0.29 0 -0.9744 0.5376 0.7688 +0.3 0 -0.96 0.64 0.82 +0.31 0 -0.9424 0.7296 0.8648 +0.32 0 -0.9216 0.8064 0.9032 +0.33 0 -0.8976 0.8704 0.9352 +0.34 0 -0.8704 0.9216 0.9608 +0.35 0 -0.84 0.96 0.98 +0.36 0 -0.8064 0.9856 0.9928 +0.37 0 -0.7696 0.9984 0.9992 +0.38 0 -0.7296 0.9984 0.9992 +0.39 0 -0.686401 0.9856 0.9928 +0.4 0 -0.640001 0.96 0.98 +0.41 0 -0.590401 0.921601 0.9608 +0.42 0 -0.537601 0.870401 0.9352 +0.43 0 -0.481601 0.806401 0.903201 +0.44 0 -0.422401 0.729602 0.864801 +0.45 0 -0.360001 0.640002 0.820001 +0.46 0 -0.294401 0.537602 0.768801 +0.47 0 -0.225601 0.422403 0.711201 +0.48 0 -0.153602 0.294403 0.647201 +0.49 0 -0.0784018 0.153603 0.576802 +0.5 0 -1.90735e-06 3.81469e-06 0.500002 +0.51 1 1.0784 0.846403 1.4232 +0.52 1 1.1536 0.705603 1.3528 +0.53 1 1.2256 0.577602 1.2888 +0.54 1 1.2944 0.462402 1.2312 +0.55 1 1.36 0.360002 1.18 +0.56 1 1.4224 0.270401 1.1352 +0.57 1 1.4816 0.193601 1.0968 +0.58 1 1.5376 0.129601 1.0648 +0.59 1 1.5904 0.0784009 1.0392 +0.6 1 1.64 0.0400007 1.02 +0.61 1 1.6864 0.0144004 1.0072 +0.62 1 1.7296 0.00160015 1.0008 +0.63 1 1.7696 0.00159991 1.0008 +0.64 1 1.8064 0.0143996 1.0072 +0.65 1 1.84 0.0399994 1.02 +0.66 1 1.8704 0.0783992 1.0392 +0.67 1 1.8976 0.129599 1.0648 +0.68 1 1.9216 0.193599 1.0968 +0.69 1 1.9424 0.270398 1.1352 +0.7 1 1.96 0.359998 1.18 +0.71 1 1.9744 0.462398 1.2312 +0.72 1 1.9856 0.577598 1.2888 +0.73 1 1.9936 0.705598 1.3528 +0.74 1 1.9984 0.846398 1.4232 +0.75 1 2 0.999998 1.5 +0.76 1 1.9984 1.1536 1.5768 +0.77 1 1.9936 1.2944 1.6472 +0.78 1 1.9856 1.4224 1.7112 +0.79 1 1.9744 1.5376 1.7688 +0.8 1 1.96 1.64 1.82 +0.81 1 1.9424 1.7296 1.8648 +0.82 1 1.9216 1.8064 1.9032 +0.83 1 1.8976 1.8704 1.9352 +0.84 1 1.8704 1.9216 1.9608 +0.85 1 1.84 1.96 1.98 +0.86 1 1.8064 1.9856 1.9928 +0.87 1 1.7696 1.9984 1.9992 +0.88 1 1.7296 1.9984 1.9992 +0.89 1 1.6864 1.9856 1.9928 +0.9 1 1.64 1.96 1.98 +0.91 1 1.5904 1.9216 1.9608 +0.92 1 1.5376 1.8704 1.9352 +0.93 1 1.4816 1.8064 1.9032 +0.94 1 1.4224 1.7296 1.8648 +0.95 1 1.36 1.64 1.82 +0.96 1 1.2944 1.5376 1.7688 +0.97 1 1.2256 1.4224 1.7112 +0.98 1 1.15361 1.2944 1.6472 +0.99 1 1.07841 1.15361 1.5768 +1 1 1.00001 1.00001 1.5 +1.01 0 -0.0783954 -0.153595 0.423203 +1.02 0 -0.153595 -0.294395 0.352803 +1.03 0 -0.225596 -0.422396 0.288802 +1.04 0 -0.294396 -0.537596 0.231202 +1.05 0 -0.359996 -0.639996 0.180002 +1.06 0 -0.422396 -0.729597 0.135201 +1.07 0 -0.481597 -0.806397 0.0968013 +1.08 0 -0.537597 -0.870398 0.0648011 +1.09 0 -0.590397 -0.921598 0.0392009 +1.1 0 -0.639997 -0.959999 0.0200006 +1.11 0 -0.686397 -0.985599 0.00720036 +1.12 0 -0.729598 -0.9984 0.000800133 +1.13 0 -0.769598 -0.9984 0.000799894 +1.14 0 -0.806398 -0.985601 0.00719965 +1.15 0 -0.839998 -0.960001 0.0199994 +1.16 0 -0.870398 -0.921602 0.0391992 +1.17 0 -0.897599 -0.870402 0.064799 +1.18 0 -0.921599 -0.806402 0.0967988 +1.19 0 -0.942399 -0.729603 0.135199 +1.2 0 -0.959999 -0.640003 0.179998 +1.21 0 -0.974399 -0.537603 0.231198 +1.22 0 -0.985599 -0.422404 0.288798 +1.23 0 -0.9936 -0.294405 0.352798 +1.24 0 -0.9984 -0.153605 0.423198 +1.25 0 -1 -4.76837e-06 0.499998 +1.26 0 -0.9984 0.153595 0.576798 +1.27 0 -0.9936 0.294396 0.647198 +1.28 0 -0.985601 0.422396 0.711198 +1.29 0 -0.974401 0.537596 0.768798 +1.3 0 -0.960001 0.639997 0.819998 +1.31 0 -0.942401 0.729597 0.864799 +1.32 0 -0.921601 0.806397 0.903199 +1.33 0 -0.897602 0.870398 0.935199 +1.34 0 -0.870402 0.921598 0.960799 +1.35 0 -0.840002 0.959999 0.979999 +1.36 0 -0.806402 0.985599 0.9928 +1.37 0 -0.769602 0.9984 0.9992 +1.38 0 -0.729603 0.9984 0.9992 +1.39 0 -0.686403 0.985601 0.9928 +1.4 0 -0.640003 0.960001 0.980001 +1.41 0 -0.590404 0.921602 0.960801 +1.42 0 -0.537604 0.870403 0.935201 +1.43 0 -0.481604 0.806403 0.903202 +1.44 0 -0.422404 0.729604 0.864802 +1.45 0 -0.360005 0.640005 0.820002 +1.46 0 -0.294405 0.537605 0.768803 +1.47 0 -0.225605 0.422406 0.711203 +1.48 0 -0.153606 0.294407 0.647203 +1.49 0 -0.0784059 0.153608 0.576804 +1.5 0 -6.19887e-06 8.58305e-06 0.500004 +1.51 1 1.07839 0.846408 1.4232 +1.52 1 1.15359 0.705607 1.3528 +1.53 1 1.22559 0.577606 1.2888 +1.54 1 1.29439 0.462406 1.2312 +1.55 1 1.36 0.360005 1.18 +1.56 1 1.4224 0.270404 1.1352 +1.57 1 1.4816 0.193604 1.0968 +1.58 1 1.5376 0.129603 1.0648 +1.59 1 1.5904 0.0784025 1.0392 +1.6 1 1.64 0.0400018 1.02 +1.61 1 1.6864 0.0144011 1.0072 +1.62 1 1.7296 0.00160038 1.0008 +1.63 1 1.7696 0.00159967 1.0008 +1.64 1 1.8064 0.0143989 1.0072 +1.65 1 1.84 0.0399982 1.02 +1.66 1 1.8704 0.0783976 1.0392 +1.67 1 1.8976 0.129597 1.0648 +1.68 1 1.9216 0.193596 1.0968 +1.69 1 1.9424 0.270396 1.1352 +1.7 1 1.96 0.359995 1.18 +1.71 1 1.9744 0.462395 1.2312 +1.72 1 1.9856 0.577594 1.2888 +1.73 1 1.9936 0.705593 1.3528 +1.74 1 1.9984 0.846393 1.4232 +1.75 1 2 0.999992 1.5 +1.76 1 1.9984 1.15359 1.5768 +1.77 1 1.9936 1.29439 1.6472 +1.78 1 1.9856 1.42239 1.7112 +1.79 1 1.9744 1.53759 1.7688 +1.8 1 1.96 1.63999 1.82 +1.81 1 1.9424 1.7296 1.8648 +1.82 1 1.9216 1.8064 1.9032 +1.83 1 1.8976 1.8704 1.9352 +1.84 1 1.8704 1.9216 1.9608 +1.85 1 1.84 1.96 1.98 +1.86 1 1.8064 1.9856 1.9928 +1.87 1 1.7696 1.9984 1.9992 +1.88 1 1.7296 1.9984 1.9992 +1.89 1 1.6864 1.9856 1.9928 +1.9 1 1.64001 1.96 1.98 +1.91 1 1.59041 1.9216 1.9608 +1.92 1 1.53761 1.8704 1.9352 +1.93 1 1.48161 1.8064 1.9032 +1.94 1 1.42241 1.72961 1.8648 +1.95 1 1.36001 1.64001 1.82 +1.96 1 1.29441 1.53761 1.7688 +1.97 1 1.22561 1.42241 1.7112 +1.98 1 1.15361 1.29441 1.6472 +1.99 1 1.07841 1.15361 1.57681 +2 1 1.00001 1.00001 1.50001 +2.01 0 -0.0783908 -0.153589 0.423205 +2.02 0 -0.153591 -0.29439 0.352805 +2.03 0 -0.225591 -0.422391 0.288804 +2.04 0 -0.294392 -0.537592 0.231204 +2.05 0 -0.359992 -0.639993 0.180004 +2.06 0 -0.422393 -0.729594 0.135203 +2.07 0 -0.481593 -0.806395 0.0968025 +2.08 0 -0.537593 -0.870396 0.0648021 +2.09 0 -0.590394 -0.921597 0.0392016 +2.1 0 -0.639994 -0.959998 0.0200012 +2.11 0 -0.686394 -0.985599 0.00720069 +2.12 0 -0.729595 -0.9984 0.000800222 +2.13 0 -0.769595 -0.9984 0.000799775 +2.14 0 -0.806396 -0.985601 0.00719929 +2.15 0 -0.839996 -0.960002 0.0199988 +2.16 0 -0.870396 -0.921603 0.0391984 +2.17 0 -0.897597 -0.870404 0.064798 +2.18 0 -0.921597 -0.806405 0.0967975 +2.19 0 -0.942398 -0.729606 0.135197 +2.2 0 -0.959998 -0.640007 0.179997 +2.21 0 -0.974398 -0.537607 0.231196 +2.22 0 -0.985599 -0.422408 0.288796 +2.23 0 -0.993599 -0.294409 0.352795 +2.24 0 -0.9984 -0.15361 0.423195 +2.25 0 -1 -1.04904e-05 0.499995 +2.26 0 -0.9984 0.15359 0.576795 +2.27 0 -0.993601 0.294391 0.647195 +2.28 0 -0.985601 0.422392 0.711196 +2.29 0 -0.974401 0.537592 0.768796 +2.3 0 -0.960002 0.639993 0.819997 +2.31 0 -0.942402 0.729594 0.864797 +2.32 0 -0.921603 0.806395 0.903197 +2.33 0 -0.897603 0.870396 0.935198 +2.34 0 -0.870404 0.921597 0.960798 +2.35 0 -0.840004 0.959998 0.979999 +2.36 0 -0.806404 0.985599 0.992799 +2.37 0 -0.769605 0.998399 0.9992 +2.38 0 -0.729605 0.998401 0.9992 +2.39 0 -0.686406 0.985602 0.992801 +2.4 0 -0.640006 0.960003 0.980001 +2.41 0 -0.590407 0.921604 0.960802 +2.42 0 -0.537607 0.870405 0.935202 +2.43 0 -0.481608 0.806406 0.903203 +2.44 0 -0.422408 0.729607 0.864803 +2.45 0 -0.360008 0.640008 0.820004 +2.46 0 -0.294409 0.537609 0.768805 +2.47 0 -0.225609 0.422411 0.711205 +2.48 0 -0.15361 0.294412 0.647206 +2.49 0 -0.0784105 0.153613 0.576806 +2.5 0 -1.09672e-05 1.43051e-05 0.500007 +2.51 1 1.07839 0.846413 1.42321 +2.52 1 1.15359 0.705612 1.35281 +2.53 1 1.22559 0.577611 1.28881 +2.54 1 1.29439 0.46241 1.2312 +2.55 1 1.35999 0.360009 1.18 +2.56 1 1.42239 0.270407 1.1352 +2.57 1 1.48159 0.193606 1.0968 +2.58 1 1.53759 0.129605 1.0648 +2.59 1 1.59039 0.0784041 1.0392 +2.6 1 1.63999 0.040003 1.02 +2.61 1 1.68639 0.0144017 1.0072 +2.62 1 1.72959 0.00160056 1.0008 +2.63 1 1.76959 0.00159943 1.0008 +2.64 1 1.80639 0.0143983 1.0072 +2.65 1 1.83999 0.039997 1.02 +2.66 1 1.8704 0.078396 1.0392 +2.67 1 1.8976 0.129595 1.0648 +2.68 1 1.9216 0.193594 1.0968 +2.69 1 1.9424 0.270393 1.1352 +2.7 1 1.96 0.359992 1.18 +2.71 1 1.9744 0.462391 1.2312 +2.72 1 1.9856 0.57759 1.28879 +2.73 1 1.9936 0.705588 1.35279 +2.74 1 1.9984 0.846387 1.42319 +2.75 1 2 0.999987 1.49999 +2.76 1 1.9984 1.15359 1.57679 +2.77 1 1.9936 1.29439 1.64719 +2.78 1 1.9856 1.42239 1.71119 +2.79 1 1.9744 1.53759 1.7688 +2.8 1 1.96 1.63999 1.82 +2.81 1 1.9424 1.72959 1.8648 +2.82 1 1.9216 1.80639 1.9032 +2.83 1 1.8976 1.87039 1.9352 +2.84 1 1.87041 1.9216 1.9608 +2.85 1 1.84001 1.96 1.98 +2.86 1 1.80641 1.9856 1.9928 +2.87 1 1.76961 1.9984 1.9992 +2.88 1 1.72961 1.9984 1.9992 +2.89 1 1.68641 1.9856 1.9928 +2.9 1 1.64001 1.96 1.98 +2.91 1 1.59041 1.9216 1.9608 +2.92 1 1.53761 1.87041 1.9352 +2.93 1 1.48161 1.80641 1.9032 +2.94 1 1.42241 1.72961 1.8648 +2.95 1 1.36001 1.64001 1.82 +2.96 1 1.29441 1.53761 1.76881 +2.97 1 1.22561 1.42241 1.71121 +2.98 1 1.15361 1.29441 1.64721 +2.99 1 1.07841 1.15362 1.57681 +3 1 1.00002 1.00002 1.50001 +3.01 0 -0.0783862 -0.153584 0.423208 +3.02 0 -0.153587 -0.294385 0.352807 +3.03 0 -0.225587 -0.422387 0.288806 +3.04 0 -0.294388 -0.537588 0.231206 +3.05 0 -0.359989 -0.63999 0.180005 +3.06 0 -0.422389 -0.729591 0.135204 +3.07 0 -0.48159 -0.806392 0.0968038 +3.08 0 -0.53759 -0.870394 0.0648031 +3.09 0 -0.590391 -0.921595 0.0392025 +3.1 0 -0.639991 -0.959996 0.0200018 +3.11 0 -0.686392 -0.985598 0.00720105 +3.12 0 -0.729593 -0.998399 0.000800341 +3.13 0 -0.769593 -0.998401 0.000799656 +3.14 0 -0.806394 -0.985602 0.00719896 +3.15 0 -0.839994 -0.960003 0.0199983 +3.16 0 -0.870395 -0.921605 0.0391976 +3.17 0 -0.897595 -0.870406 0.064797 +3.18 0 -0.921596 -0.806408 0.0967962 +3.19 0 -0.942397 -0.729609 0.135196 +3.2 0 -0.959997 -0.64001 0.179995 +3.21 0 -0.974398 -0.537611 0.231194 +3.22 0 -0.985598 -0.422413 0.288794 +3.23 0 -0.993599 -0.294414 0.352793 +3.24 0 -0.998399 -0.153615 0.423192 +3.25 0 -1 -1.62124e-05 0.499992 +3.26 0 -0.998401 0.153585 0.576792 +3.27 0 -0.993601 0.294386 0.647193 +3.28 0 -0.985602 0.422387 0.711194 +3.29 0 -0.974402 0.537589 0.768794 +3.3 0 -0.960003 0.63999 0.819995 +3.31 0 -0.942403 0.729591 0.864796 +3.32 0 -0.921604 0.806392 0.903196 +3.33 0 -0.897605 0.870394 0.935197 +3.34 0 -0.870405 0.921595 0.960798 +3.35 0 -0.840006 0.959996 0.979998 +3.36 0 -0.806406 0.985598 0.992799 +3.37 0 -0.769607 0.998399 0.9992 +3.38 0 -0.729608 0.998401 0.9992 +3.39 0 -0.686408 0.985602 0.992801 +3.4 0 -0.640009 0.960004 0.980002 +3.41 0 -0.59041 0.921605 0.960803 +3.42 0 -0.53761 0.870407 0.935203 +3.43 0 -0.481611 0.806408 0.903204 +3.44 0 -0.422412 0.72961 0.864805 +3.45 0 -0.360012 0.640012 0.820006 +3.46 0 -0.294413 0.537613 0.768807 +3.47 0 -0.225614 0.422415 0.711207 +3.48 0 -0.153614 0.294417 0.647208 +3.49 0 -0.078415 0.153618 0.576809 +3.5 0 -1.57356e-05 2.00271e-05 0.50001 +3.51 1 1.07839 0.846419 1.42321 +3.52 1 1.15359 0.705617 1.35281 +3.53 1 1.22559 0.577615 1.28881 +3.54 1 1.29439 0.462414 1.23121 +3.55 1 1.35999 0.360012 1.18001 +3.56 1 1.42239 0.27041 1.13521 +3.57 1 1.48159 0.193609 1.0968 +3.58 1 1.53759 0.129607 1.0648 +3.59 1 1.59039 0.0784057 1.0392 +3.6 1 1.63999 0.0400041 1.02 +3.61 1 1.68639 0.0144024 1.0072 +3.62 1 1.72959 0.0016008 1.0008 +3.63 1 1.76959 0.00159919 1.0008 +3.64 1 1.80639 0.0143976 1.0072 +3.65 1 1.83999 0.0399959 1.02 +3.66 1 1.87039 0.0783944 1.0392 +3.67 1 1.89759 0.129593 1.0648 +3.68 1 1.9216 0.193591 1.0968 +3.69 1 1.9424 0.27039 1.13519 +3.7 1 1.96 0.359988 1.17999 +3.71 1 1.9744 0.462387 1.23119 +3.72 1 1.9856 0.577585 1.28879 +3.73 1 1.9936 0.705583 1.35279 +3.74 1 1.9984 0.846382 1.42319 +3.75 1 2 0.999981 1.49999 +3.76 1 1.9984 1.15358 1.57679 +3.77 1 1.9936 1.29438 1.64719 +3.78 1 1.9856 1.42239 1.71119 +3.79 1 1.9744 1.53759 1.76879 +3.8 1 1.96 1.63999 1.81999 +3.81 1 1.9424 1.72959 1.86479 +3.82 1 1.9216 1.80639 1.9032 +3.83 1 1.89761 1.87039 1.9352 +3.84 1 1.87041 1.92159 1.9608 +3.85 1 1.84001 1.96 1.98 +3.86 1 1.80641 1.9856 1.9928 +3.87 1 1.76961 1.9984 1.9992 +3.88 1 1.72961 1.9984 1.9992 +3.89 1 1.68641 1.9856 1.9928 +3.9 1 1.64001 1.96 1.98 +3.91 1 1.59041 1.92161 1.9608 +3.92 1 1.53761 1.87041 1.9352 +3.93 1 1.48161 1.80641 1.9032 +3.94 1 1.42241 1.72961 1.86481 +3.95 1 1.36001 1.64001 1.82001 +3.96 1 1.29442 1.53762 1.76881 +3.97 1 1.22562 1.42242 1.71121 +3.98 1 1.15362 1.29442 1.64721 +3.99 1 1.07842 1.15362 1.57681 +4 1 1.00002 1.00002 1.50001 +4.01 0 -0.0783816 -0.153579 0.423211 +4.02 0 -0.153582 -0.294381 0.35281 +4.03 0 -0.225583 -0.422383 0.288809 +4.04 0 -0.294384 -0.537584 0.231208 +4.05 0 -0.359985 -0.639986 0.180007 +4.06 0 -0.422386 -0.729588 0.135206 +4.07 0 -0.481586 -0.80639 0.0968051 +4.08 0 -0.537587 -0.870392 0.0648042 +4.09 0 -0.590388 -0.921593 0.0392033 +4.1 0 -0.639988 -0.959995 0.0200023 +4.11 0 -0.686389 -0.985597 0.00720137 +4.12 0 -0.72959 -0.998399 0.000800461 +4.13 0 -0.769591 -0.998401 0.000799537 +4.14 0 -0.806392 -0.985603 0.0071986 +4.15 0 -0.839992 -0.960005 0.0199977 +4.16 0 -0.870393 -0.921606 0.0391968 +4.17 0 -0.897594 -0.870408 0.0647959 +4.18 0 -0.921595 -0.80641 0.096795 +4.19 0 -0.942395 -0.729612 0.135194 +4.2 0 -0.959996 -0.640014 0.179993 +4.21 0 -0.974397 -0.537615 0.231192 +4.22 0 -0.985598 -0.422417 0.288791 +4.23 0 -0.993598 -0.294419 0.352791 +4.24 0 -0.998399 -0.15362 0.42319 +4.25 0 -1 -2.19344e-05 0.499989 +4.26 0 -0.998401 0.15358 0.57679 +4.27 0 -0.993602 0.294381 0.647191 +4.28 0 -0.985602 0.422383 0.711191 +4.29 0 -0.974403 0.537585 0.768792 +4.3 0 -0.960004 0.639986 0.819993 +4.31 0 -0.942405 0.729588 0.864794 +4.32 0 -0.921605 0.80639 0.903195 +4.33 0 -0.897606 0.870392 0.935196 +4.34 0 -0.870407 0.921593 0.960797 +4.35 0 -0.840008 0.959995 0.979998 +4.36 0 -0.806409 0.985597 0.992799 +4.37 0 -0.769609 0.998399 0.9992 +4.38 0 -0.72961 0.998401 0.9992 +4.39 0 -0.686411 0.985603 0.992801 +4.4 0 -0.640012 0.960005 0.980002 +4.41 0 -0.590413 0.921607 0.960803 +4.42 0 -0.537614 0.870409 0.935204 +4.43 0 -0.481614 0.806411 0.903205 +4.44 0 -0.422415 0.729613 0.864806 +4.45 0 -0.360016 0.640015 0.820008 +4.46 0 -0.294417 0.537617 0.768809 +4.47 0 -0.225618 0.422419 0.71121 +4.48 0 -0.153619 0.294421 0.647211 +4.49 0 -0.0784196 0.153624 0.576812 +4.5 0 -2.05039e-05 2.5749e-05 0.500013 +4.51 1 1.07838 0.846424 1.42321 +4.52 1 1.15358 0.705622 1.35281 +4.53 1 1.22558 0.57762 1.28881 +4.54 1 1.29438 0.462418 1.23121 +4.55 1 1.35998 0.360016 1.18001 +4.56 1 1.42238 0.270413 1.13521 +4.57 1 1.48158 0.193611 1.09681 +4.58 1 1.53759 0.129609 1.0648 +4.59 1 1.59039 0.0784073 1.0392 +4.6 1 1.63999 0.0400053 1.02 +4.61 1 1.68639 0.0144031 1.0072 +4.62 1 1.72959 0.00160104 1.0008 +4.63 1 1.76959 0.00159895 1.0008 +4.64 1 1.80639 0.0143969 1.0072 +4.65 1 1.83999 0.0399948 1.02 +4.66 1 1.87039 0.0783928 1.0392 +4.67 1 1.89759 0.129591 1.0648 +4.68 1 1.92159 0.193589 1.09679 +4.69 1 1.94239 0.270387 1.13519 +4.7 1 1.96 0.359985 1.17999 +4.71 1 1.9744 0.462383 1.23119 +4.72 1 1.9856 0.577581 1.28879 +4.73 1 1.9936 0.705579 1.35279 +4.74 1 1.9984 0.846377 1.42319 +4.75 1 2 0.999975 1.49999 +4.76 1 1.9984 1.15358 1.57679 +4.77 1 1.9936 1.29438 1.64719 +4.78 1 1.9856 1.42238 1.71119 +4.79 1 1.9744 1.53758 1.76879 +4.8 1 1.96 1.63998 1.81999 +4.81 1 1.94241 1.72959 1.86479 +4.82 1 1.92161 1.80639 1.90319 +4.83 1 1.89761 1.87039 1.9352 +4.84 1 1.87041 1.92159 1.9608 +4.85 1 1.84001 1.95999 1.98 +4.86 1 1.80641 1.9856 1.9928 +4.87 1 1.76961 1.9984 1.9992 +4.88 1 1.72961 1.9984 1.9992 +4.89 1 1.68641 1.9856 1.9928 +4.9 1 1.64001 1.96001 1.98 +4.91 1 1.59042 1.92161 1.9608 +4.92 1 1.53762 1.87041 1.9352 +4.93 1 1.48162 1.80641 1.90321 +4.94 1 1.42242 1.72961 1.86481 +4.95 1 1.36002 1.64002 1.82001 +4.96 1 1.29442 1.53762 1.76881 +4.97 1 1.22562 1.42242 1.71121 +4.98 1 1.15362 1.29442 1.64721 +4.99 1 1.07842 1.15363 1.57681 diff --git a/tests/lfo/lfo_waves_reference.dat b/tests/lfo/lfo_waves_reference.dat index 9a65cdf2..d74ff55e 100644 --- a/tests/lfo/lfo_waves_reference.dat +++ b/tests/lfo/lfo_waves_reference.dat @@ -1,500 +1,500 @@ 0 0 0 0.5 1 1.5 1 0 1 -0.01 0.04 -0.12288 0.5 1 1.5 1 0.02 0.96 -0.02 0.08 -0.23552 0.5 1 1.5 1 0.04 0.92 -0.03 0.12 -0.33792 0.5 1 1.5 1 0.0599999 0.88 -0.04 0.16 -0.43008 0.5 1 1.5 1 0.0799999 0.84 -0.05 0.2 -0.512 0.5 1 1.5 1 0.0999999 0.8 -0.06 0.24 -0.58368 0.5 1 1.5 1 0.12 0.76 -0.07 0.28 -0.64512 0.5 1 1.5 -1 0.14 0.72 -0.08 0.32 -0.69632 0.5 1 1.5 -1 0.16 0.68 -0.09 0.36 -0.73728 0.5 1 1.5 -1 0.18 0.64 -0.1 0.4 -0.768 0.5 1 1.5 -1 0.2 0.6 -0.11 0.44 -0.78848 0.5 1 1.5 -1 0.22 0.56 -0.12 0.48 -0.79872 0.5 1 1.5 -1 0.24 0.52 -0.13 0.52 -0.79872 0.5 -1 1.5 -1 0.26 0.48 -0.14 0.56 -0.78848 0.5 -1 1.5 -1 0.28 0.44 -0.15 0.6 -0.768 0.5 -1 1.5 -1 0.3 0.4 -0.16 0.64 -0.73728 0.5 -1 1.5 -1 0.32 0.36 -0.17 0.68 -0.69632 0.5 -1 1.5 -1 0.34 0.32 -0.18 0.72 -0.64512 0.5 -1 1.5 -1 0.36 0.28 -0.19 0.76 -0.58368 0.5 -1 1.5 -1 0.38 0.24 -0.2 0.8 -0.512 0.5 -1 1.5 -1 0.4 0.2 -0.21 0.84 -0.43008 0.5 -1 1.5 -1 0.42 0.16 -0.22 0.88 -0.33792 0.5 -1 1.5 -1 0.44 0.12 -0.23 0.92 -0.23552 0.5 -1 1.5 -1 0.46 0.0799999 -0.24 0.96 -0.12288 0.5 -1 1.5 -1 0.48 0.0399998 -0.25 1 3.8147e-07 0.5 1 -0.5 -1 0.5 -1.19209e-07 -0.26 0.96 0.12288 0.5 1 -0.5 -1 0.52 -0.0400001 -0.27 0.92 0.23552 0.5 1 -0.5 -1 0.539999 -0.08 -0.28 0.88 0.33792 0.5 1 -0.5 -1 0.559999 -0.12 -0.29 0.84 0.43008 0.5 1 -0.5 -1 0.579999 -0.16 -0.3 0.8 0.512 0.5 1 -0.5 -1 0.599999 -0.2 -0.31 0.76 0.58368 0.5 1 -0.5 -1 0.619999 -0.24 -0.32 0.72 0.64512 0.5 1 -0.5 -1 0.639999 -0.28 -0.33 0.68 0.69632 0.5 1 -0.5 -1 0.659999 -0.32 -0.34 0.64 0.73728 0.5 1 -0.5 -1 0.679999 -0.36 -0.35 0.6 0.768 0.5 1 -0.5 -1 0.699999 -0.4 -0.36 0.56 0.78848 0.5 1 -0.5 -1 0.719999 -0.44 -0.37 0.52 0.79872 0.5 1 -0.5 -1 0.739999 -0.48 -0.38 0.48 0.79872 0.5 -1 -0.5 -1 0.759999 -0.52 -0.39 0.44 0.78848 0.5 -1 -0.5 -1 0.779999 -0.56 -0.4 0.4 0.768 0.5 -1 -0.5 -1 0.799999 -0.6 -0.41 0.36 0.73728 0.5 -1 -0.5 -1 0.819999 -0.64 -0.42 0.320001 0.696321 0.5 -1 -0.5 -1 0.839999 -0.679999 -0.43 0.280001 0.645121 0.5 -1 -0.5 -1 0.859999 -0.719999 -0.44 0.240001 0.583681 0.5 -1 -0.5 -1 0.879999 -0.759999 -0.45 0.200001 0.512001 0.5 -1 -0.5 -1 0.899999 -0.799999 -0.46 0.160001 0.430081 0.5 -1 -0.5 -1 0.919999 -0.839999 -0.47 0.120001 0.337922 0.5 -1 -0.5 -1 0.939999 -0.879999 -0.48 0.0800008 0.235522 0.5 -1 -0.5 -1 0.959999 -0.919999 -0.49 0.0400008 0.122882 0.5 -1 -0.5 -1 0.979999 -0.959999 -0.5 8.34465e-07 2.67029e-06 0.5 1 -0.5 -1 0.999999 -0.999999 -0.51 -0.0399992 -0.122878 0.5 1 -0.5 1 -0.980001 0.960001 -0.52 -0.0799992 -0.235518 0.5 1 -0.5 1 -0.960001 0.920001 -0.53 -0.119999 -0.337918 0.5 1 -0.5 1 -0.940001 0.880001 -0.54 -0.159999 -0.430078 0.5 1 -0.5 1 -0.920001 0.840001 -0.55 -0.199999 -0.511998 0.5 1 -0.5 1 -0.900001 0.800001 -0.56 -0.239999 -0.583679 0.5 1 -0.5 1 -0.880001 0.760001 -0.57 -0.279999 -0.645119 0.5 1 -0.5 -1 -0.860001 0.720001 -0.58 -0.319999 -0.696319 0.5 1 -0.5 -1 -0.840001 0.680001 -0.59 -0.359999 -0.737279 0.5 1 -0.5 -1 -0.820001 0.640001 -0.6 -0.399999 -0.767999 0.5 1 -0.5 -1 -0.800001 0.600001 -0.61 -0.439999 -0.78848 0.5 1 -0.5 -1 -0.780001 0.560001 -0.62 -0.479999 -0.79872 0.5 1 -0.5 -1 -0.760001 0.520001 -0.63 -0.519999 -0.79872 0.5 -1 -0.5 -1 -0.740001 0.480001 -0.64 -0.559999 -0.78848 0.5 -1 -0.5 -1 -0.720001 0.440001 -0.65 -0.599999 -0.768001 0.5 -1 -0.5 -1 -0.700001 0.400001 -0.66 -0.639999 -0.737281 0.5 -1 -0.5 -1 -0.680001 0.360001 -0.67 -0.679999 -0.696321 0.5 -1 -0.5 -1 -0.660001 0.320001 -0.68 -0.719999 -0.645121 0.5 -1 -0.5 -1 -0.640001 0.280001 -0.69 -0.759999 -0.583681 0.5 -1 -0.5 -1 -0.620001 0.240001 -0.7 -0.799999 -0.512001 0.5 -1 -0.5 -1 -0.600001 0.200001 -0.71 -0.839998 -0.430081 0.5 -1 -0.5 -1 -0.580001 0.160001 -0.72 -0.879998 -0.337921 0.5 -1 -0.5 -1 -0.560001 0.120001 -0.73 -0.919998 -0.235522 0.5 -1 -0.5 -1 -0.540001 0.0800006 -0.74 -0.959998 -0.122882 0.5 -1 -0.5 -1 -0.520001 0.0400006 -0.75 -0.999998 -1.71661e-06 0.5 1 -0.5 -1 -0.500001 5.36442e-07 -0.76 -0.960002 0.122878 -0.5 1 -0.5 -1 -0.480001 -0.0399995 -0.77 -0.920002 0.235519 -0.5 1 -0.5 -1 -0.460001 -0.0799994 -0.78 -0.880002 0.337919 -0.5 1 -0.5 -1 -0.440001 -0.119999 -0.79 -0.840002 0.430079 -0.5 1 -0.5 -1 -0.420001 -0.159999 -0.8 -0.800002 0.511999 -0.5 1 -0.5 -1 -0.400001 -0.199999 -0.81 -0.760002 0.583679 -0.5 1 -0.5 -1 -0.380001 -0.239999 -0.82 -0.720002 0.645119 -0.5 1 -0.5 -1 -0.360001 -0.279999 -0.83 -0.680002 0.696319 -0.5 1 -0.5 -1 -0.340001 -0.319999 -0.84 -0.640002 0.737279 -0.5 1 -0.5 -1 -0.320001 -0.359999 -0.85 -0.600002 0.767999 -0.5 1 -0.5 -1 -0.300001 -0.399999 -0.86 -0.560002 0.78848 -0.5 1 -0.5 -1 -0.280001 -0.439999 -0.87 -0.520002 0.79872 -0.5 1 -0.5 -1 -0.260001 -0.479999 -0.88 -0.480002 0.79872 -0.5 -1 -0.5 -1 -0.240001 -0.519999 -0.89 -0.440002 0.78848 -0.5 -1 -0.5 -1 -0.220001 -0.559999 -0.9 -0.400002 0.768001 -0.5 -1 -0.5 -1 -0.200001 -0.599999 -0.91 -0.360002 0.737281 -0.5 -1 -0.5 -1 -0.180001 -0.639999 -0.92 -0.320002 0.696321 -0.5 -1 -0.5 -1 -0.160001 -0.679999 -0.93 -0.280002 0.645122 -0.5 -1 -0.5 -1 -0.140001 -0.719999 -0.94 -0.240002 0.583682 -0.5 -1 -0.5 -1 -0.120001 -0.759999 -0.95 -0.200002 0.512002 -0.5 -1 -0.5 -1 -0.100001 -0.799999 -0.96 -0.160002 0.430083 -0.5 -1 -0.5 -1 -0.0800012 -0.839999 -0.97 -0.120003 0.337923 -0.5 -1 -0.5 -1 -0.0600013 -0.879999 -0.98 -0.0800025 0.235524 -0.5 -1 -0.5 -1 -0.0400013 -0.919999 -0.99 -0.0400026 0.122884 -0.5 -1 -0.5 -1 -0.0200013 -0.959999 -1 -2.6226e-06 4.57763e-06 -0.5 1 -0.5 -1 -1.3113e-06 -0.999999 -1.01 0.0399976 -0.122876 0.5 1 1.5 1 0.0199987 0.960001 -1.02 0.0799976 -0.235516 0.5 1 1.5 1 0.0399987 0.920001 -1.03 0.119998 -0.337916 0.5 1 1.5 1 0.0599986 0.880001 -1.04 0.159998 -0.430077 0.5 1 1.5 1 0.0799986 0.840001 -1.05 0.199998 -0.511997 0.5 1 1.5 1 0.0999986 0.800002 -1.06 0.239998 -0.583678 0.5 1 1.5 1 0.119999 0.760001 -1.07 0.279998 -0.645118 0.5 1 1.5 -1 0.139999 0.720001 -1.08 0.319998 -0.696318 0.5 1 1.5 -1 0.159999 0.680001 -1.09 0.359998 -0.737279 0.5 1 1.5 -1 0.179999 0.640002 -1.1 0.399998 -0.767999 0.5 1 1.5 -1 0.199998 0.600002 -1.11 0.439998 -0.788479 0.5 1 1.5 -1 0.219998 0.560001 -1.12 0.479998 -0.79872 0.5 1 1.5 -1 0.239998 0.520002 -1.13 0.519998 -0.79872 0.5 -1 1.5 -1 0.259998 0.480002 -1.14 0.559998 -0.788481 0.5 -1 1.5 -1 0.279998 0.440001 -1.15 0.599998 -0.768001 0.5 -1 1.5 -1 0.299998 0.400001 -1.16 0.639998 -0.737281 0.5 -1 1.5 -1 0.319998 0.360001 -1.17 0.679998 -0.696322 0.5 -1 1.5 -1 0.339998 0.320001 -1.18 0.719998 -0.645122 0.5 -1 1.5 -1 0.359998 0.280001 -1.19 0.759998 -0.583682 0.5 -1 1.5 -1 0.379998 0.240001 -1.2 0.799998 -0.512003 0.5 -1 1.5 -1 0.399998 0.200001 -1.21 0.839998 -0.430083 0.5 -1 1.5 -1 0.419998 0.160001 -1.22 0.879998 -0.337923 0.5 -1 1.5 -1 0.439998 0.120001 -1.23 0.919998 -0.235523 0.5 -1 1.5 -1 0.459998 0.0800013 -1.24 0.959998 -0.122884 0.5 -1 1.5 -1 0.479998 0.0400013 -1.25 0.999998 -4.00543e-06 0.5 1 1.5 -1 0.499998 1.2517e-06 -1.26 0.960002 0.122876 0.5 1 -0.5 -1 0.519998 -0.0399988 -1.27 0.920002 0.235517 0.5 1 -0.5 -1 0.539998 -0.0799987 -1.28 0.880002 0.337917 0.5 1 -0.5 -1 0.559998 -0.119999 -1.29 0.840002 0.430077 0.5 1 -0.5 -1 0.579998 -0.159999 -1.3 0.800002 0.511997 0.5 1 -0.5 -1 0.599998 -0.199999 -1.31 0.760002 0.583678 0.5 1 -0.5 -1 0.619998 -0.239999 -1.32 0.720002 0.645118 0.5 1 -0.5 -1 0.639998 -0.279999 -1.33 0.680002 0.696318 0.5 1 -0.5 -1 0.659998 -0.319999 -1.34 0.640002 0.737279 0.5 1 -0.5 -1 0.679998 -0.359998 -1.35 0.600003 0.767999 0.5 1 -0.5 -1 0.699998 -0.399998 -1.36 0.560003 0.788479 0.5 1 -0.5 -1 0.719998 -0.439998 -1.37 0.520003 0.79872 0.5 1 -0.5 -1 0.739998 -0.479998 -1.38 0.480003 0.79872 0.5 -1 -0.5 -1 0.759998 -0.519998 -1.39 0.440003 0.788481 0.5 -1 -0.5 -1 0.779998 -0.559998 -1.4 0.400003 0.768001 0.5 -1 -0.5 -1 0.799998 -0.599998 -1.41 0.360003 0.737282 0.5 -1 -0.5 -1 0.819998 -0.639998 -1.42 0.320003 0.696322 0.5 -1 -0.5 -1 0.839998 -0.679998 -1.43 0.280003 0.645123 0.5 -1 -0.5 -1 0.859998 -0.719998 -1.44 0.240003 0.583683 0.5 -1 -0.5 -1 0.879998 -0.759998 -1.45 0.200003 0.512004 0.5 -1 -0.5 -1 0.899998 -0.799998 -1.46 0.160003 0.430084 0.5 -1 -0.5 -1 0.919998 -0.839998 -1.47 0.120003 0.337925 0.5 -1 -0.5 -1 0.939998 -0.879998 -1.48 0.080003 0.235526 0.5 -1 -0.5 -1 0.959998 -0.919998 -1.49 0.0400031 0.122886 0.5 -1 -0.5 -1 0.979998 -0.959998 -1.5 3.09944e-06 6.86644e-06 0.5 1 -0.5 -1 0.999998 -0.999998 -1.51 -0.0399969 -0.122874 0.5 1 -0.5 1 -0.980002 0.960002 -1.52 -0.0799968 -0.235514 0.5 1 -0.5 1 -0.960002 0.920002 -1.53 -0.119997 -0.337915 0.5 1 -0.5 1 -0.940002 0.880002 -1.54 -0.159997 -0.430075 0.5 1 -0.5 1 -0.920002 0.840002 -1.55 -0.199997 -0.511996 0.5 1 -0.5 1 -0.900002 0.800002 -1.56 -0.239997 -0.583676 0.5 1 -0.5 1 -0.880002 0.760002 -1.57 -0.279997 -0.645117 0.5 1 -0.5 -1 -0.860002 0.720002 -1.58 -0.319997 -0.696317 0.5 1 -0.5 -1 -0.840002 0.680002 -1.59 -0.359997 -0.737278 0.5 1 -0.5 -1 -0.820002 0.640002 -1.6 -0.399997 -0.767999 0.5 1 -0.5 -1 -0.800002 0.600002 -1.61 -0.439996 -0.788479 0.5 1 -0.5 -1 -0.780002 0.560002 -1.62 -0.479996 -0.79872 0.5 1 -0.5 -1 -0.760002 0.520002 -1.63 -0.519996 -0.79872 0.5 -1 -0.5 -1 -0.740002 0.480002 -1.64 -0.559996 -0.788481 0.5 -1 -0.5 -1 -0.720002 0.440002 -1.65 -0.599996 -0.768001 0.5 -1 -0.5 -1 -0.700002 0.400002 -1.66 -0.639996 -0.737282 0.5 -1 -0.5 -1 -0.680002 0.360002 -1.67 -0.679996 -0.696322 0.5 -1 -0.5 -1 -0.660002 0.320002 -1.68 -0.719996 -0.645123 0.5 -1 -0.5 -1 -0.640002 0.280002 -1.69 -0.759996 -0.583683 0.5 -1 -0.5 -1 -0.620002 0.240002 -1.7 -0.799996 -0.512004 0.5 -1 -0.5 -1 -0.600002 0.200002 -1.71 -0.839996 -0.430084 0.5 -1 -0.5 -1 -0.580002 0.160002 -1.72 -0.879996 -0.337925 0.5 -1 -0.5 -1 -0.560002 0.120002 -1.73 -0.919996 -0.235525 0.5 -1 -0.5 -1 -0.540002 0.080002 -1.74 -0.959996 -0.122886 0.5 -1 -0.5 -1 -0.520002 0.040002 -1.75 -0.999996 -6.29424e-06 0.5 1 -0.5 -1 -0.500002 1.96695e-06 -1.76 -0.960004 0.122874 -0.5 1 -0.5 -1 -0.480002 -0.0399981 -1.77 -0.920004 0.235515 -0.5 1 -0.5 -1 -0.460002 -0.079998 -1.78 -0.880004 0.337915 -0.5 1 -0.5 -1 -0.440002 -0.119998 -1.79 -0.840004 0.430076 -0.5 1 -0.5 -1 -0.420002 -0.159998 -1.8 -0.800004 0.511996 -0.5 1 -0.5 -1 -0.400002 -0.199998 -1.81 -0.760004 0.583676 -0.5 1 -0.5 -1 -0.380002 -0.239998 -1.82 -0.720004 0.645117 -0.5 1 -0.5 -1 -0.360002 -0.279998 -1.83 -0.680004 0.696317 -0.5 1 -0.5 -1 -0.340002 -0.319998 -1.84 -0.640004 0.737278 -0.5 1 -0.5 -1 -0.320002 -0.359998 -1.85 -0.600004 0.767999 -0.5 1 -0.5 -1 -0.300002 -0.399998 -1.86 -0.560004 0.788479 -0.5 1 -0.5 -1 -0.280002 -0.439998 -1.87 -0.520005 0.79872 -0.5 1 -0.5 -1 -0.260002 -0.479998 -1.88 -0.480005 0.79872 -0.5 -1 -0.5 -1 -0.240002 -0.519998 -1.89 -0.440005 0.788481 -0.5 -1 -0.5 -1 -0.220002 -0.559998 -1.9 -0.400005 0.768002 -0.5 -1 -0.5 -1 -0.200002 -0.599998 -1.91 -0.360005 0.737282 -0.5 -1 -0.5 -1 -0.180002 -0.639997 -1.92 -0.320005 0.696323 -0.5 -1 -0.5 -1 -0.160002 -0.679997 -1.93 -0.280005 0.645124 -0.5 -1 -0.5 -1 -0.140002 -0.719997 -1.94 -0.240005 0.583684 -0.5 -1 -0.5 -1 -0.120002 -0.759997 -1.95 -0.200005 0.512005 -0.5 -1 -0.5 -1 -0.100002 -0.799997 -1.96 -0.160005 0.430086 -0.5 -1 -0.5 -1 -0.0800024 -0.839997 -1.97 -0.120005 0.337927 -0.5 -1 -0.5 -1 -0.0600024 -0.879997 -1.98 -0.0800049 0.235527 -0.5 -1 -0.5 -1 -0.0400025 -0.919997 -1.99 -0.040005 0.122888 -0.5 -1 -0.5 -1 -0.0200025 -0.959997 -2 -5.00679e-06 9.15525e-06 -0.5 1 -0.5 -1 -2.5034e-06 -0.999997 -2.01 0.0399952 -0.122871 0.5 1 1.5 1 0.0199975 0.960003 -2.02 0.0799952 -0.235512 0.5 1 1.5 1 0.0399975 0.920003 -2.03 0.119995 -0.337913 0.5 1 1.5 1 0.0599974 0.880003 -2.04 0.159995 -0.430074 0.5 1 1.5 1 0.0799974 0.840003 -2.05 0.199995 -0.511994 0.5 1 1.5 1 0.0999974 0.800003 -2.06 0.239995 -0.583675 0.5 1 1.5 1 0.119997 0.760003 -2.07 0.279995 -0.645116 0.5 1 1.5 -1 0.139997 0.720003 -2.08 0.319995 -0.696317 0.5 1 1.5 -1 0.159997 0.680003 -2.09 0.359995 -0.737277 0.5 1 1.5 -1 0.179997 0.640003 -2.1 0.399995 -0.767998 0.5 1 1.5 -1 0.199997 0.600003 -2.11 0.439995 -0.788479 0.5 1 1.5 -1 0.219997 0.560003 -2.12 0.479995 -0.79872 0.5 1 1.5 -1 0.239997 0.520003 -2.13 0.519995 -0.79872 0.5 -1 1.5 -1 0.259997 0.480003 -2.14 0.559995 -0.788481 0.5 -1 1.5 -1 0.279997 0.440003 -2.15 0.599995 -0.768002 0.5 -1 1.5 -1 0.299997 0.400003 -2.16 0.639995 -0.737283 0.5 -1 1.5 -1 0.319997 0.360003 -2.17 0.679995 -0.696323 0.5 -1 1.5 -1 0.339997 0.320003 -2.18 0.719995 -0.645124 0.5 -1 1.5 -1 0.359997 0.280003 -2.19 0.759995 -0.583685 0.5 -1 1.5 -1 0.379997 0.240003 -2.2 0.799995 -0.512005 0.5 -1 1.5 -1 0.399997 0.200003 -2.21 0.839995 -0.430086 0.5 -1 1.5 -1 0.419997 0.160003 -2.22 0.879995 -0.337927 0.5 -1 1.5 -1 0.439997 0.120003 -2.23 0.919995 -0.235527 0.5 -1 1.5 -1 0.459997 0.0800027 -2.24 0.959995 -0.122888 0.5 -1 1.5 -1 0.479997 0.0400027 -2.25 0.999995 -8.58305e-06 0.5 1 1.5 -1 0.499997 2.68221e-06 -2.26 0.960005 0.122872 0.5 1 -0.5 -1 0.519997 -0.0399973 -2.27 0.920005 0.235513 0.5 1 -0.5 -1 0.539997 -0.0799973 -2.28 0.880005 0.337913 0.5 1 -0.5 -1 0.559997 -0.119997 -2.29 0.840005 0.430074 0.5 1 -0.5 -1 0.579997 -0.159997 -2.3 0.800005 0.511995 0.5 1 -0.5 -1 0.599997 -0.199997 -2.31 0.760005 0.583675 0.5 1 -0.5 -1 0.619997 -0.239997 -2.32 0.720005 0.645116 0.5 1 -0.5 -1 0.639997 -0.279997 -2.33 0.680005 0.696317 0.5 1 -0.5 -1 0.659997 -0.319997 -2.34 0.640005 0.737277 0.5 1 -0.5 -1 0.679997 -0.359997 -2.35 0.600005 0.767998 0.5 1 -0.5 -1 0.699997 -0.399997 -2.36 0.560005 0.788479 0.5 1 -0.5 -1 0.719997 -0.439997 -2.37 0.520005 0.79872 0.5 1 -0.5 -1 0.739997 -0.479997 -2.38 0.480005 0.79872 0.5 -1 -0.5 -1 0.759997 -0.519997 -2.39 0.440005 0.788481 0.5 -1 -0.5 -1 0.779997 -0.559997 -2.4 0.400005 0.768002 0.5 -1 -0.5 -1 0.799997 -0.599997 -2.41 0.360005 0.737283 0.5 -1 -0.5 -1 0.819997 -0.639997 -2.42 0.320005 0.696324 0.5 -1 -0.5 -1 0.839997 -0.679997 -2.43 0.280005 0.645125 0.5 -1 -0.5 -1 0.859997 -0.719997 -2.44 0.240005 0.583686 0.5 -1 -0.5 -1 0.879997 -0.759997 -2.45 0.200005 0.512007 0.5 -1 -0.5 -1 0.899997 -0.799997 -2.46 0.160005 0.430087 0.5 -1 -0.5 -1 0.919997 -0.839997 -2.47 0.120005 0.337928 0.5 -1 -0.5 -1 0.939997 -0.879997 -2.48 0.0800054 0.235529 0.5 -1 -0.5 -1 0.959997 -0.919997 -2.49 0.0400054 0.12289 0.5 -1 -0.5 -1 0.979997 -0.959996 -2.5 5.48363e-06 1.14441e-05 0.5 1 -0.5 -1 0.999997 -0.999996 -2.51 -0.0399945 -0.122869 0.5 1 -0.5 1 -0.980003 0.960004 -2.52 -0.0799944 -0.23551 0.5 1 -0.5 1 -0.960003 0.920004 -2.53 -0.119994 -0.337911 0.5 1 -0.5 1 -0.940003 0.880004 -2.54 -0.159994 -0.430072 0.5 1 -0.5 1 -0.920003 0.840004 -2.55 -0.199994 -0.511993 0.5 1 -0.5 1 -0.900003 0.800004 -2.56 -0.239994 -0.583674 0.5 1 -0.5 1 -0.880003 0.760004 -2.57 -0.279994 -0.645115 0.5 1 -0.5 -1 -0.860003 0.720004 -2.58 -0.319994 -0.696316 0.5 1 -0.5 -1 -0.840003 0.680004 -2.59 -0.359994 -0.737277 0.5 1 -0.5 -1 -0.820003 0.640004 -2.6 -0.399994 -0.767998 0.5 1 -0.5 -1 -0.800003 0.600004 -2.61 -0.439994 -0.788479 0.5 1 -0.5 -1 -0.780003 0.560004 -2.62 -0.479994 -0.79872 0.5 1 -0.5 -1 -0.760003 0.520004 -2.63 -0.519994 -0.79872 0.5 -1 -0.5 -1 -0.740003 0.480004 -2.64 -0.559994 -0.788481 0.5 -1 -0.5 -1 -0.720003 0.440004 -2.65 -0.599994 -0.768002 0.5 -1 -0.5 -1 -0.700003 0.400004 -2.66 -0.639994 -0.737283 0.5 -1 -0.5 -1 -0.680003 0.360004 -2.67 -0.679994 -0.696324 0.5 -1 -0.5 -1 -0.660003 0.320004 -2.68 -0.719994 -0.645125 0.5 -1 -0.5 -1 -0.640003 0.280004 -2.69 -0.759994 -0.583686 0.5 -1 -0.5 -1 -0.620003 0.240004 -2.7 -0.799994 -0.512007 0.5 -1 -0.5 -1 -0.600003 0.200004 -2.71 -0.839994 -0.430088 0.5 -1 -0.5 -1 -0.580003 0.160003 -2.72 -0.879994 -0.337928 0.5 -1 -0.5 -1 -0.560003 0.120003 -2.73 -0.919994 -0.235529 0.5 -1 -0.5 -1 -0.540003 0.0800034 -2.74 -0.959994 -0.12289 0.5 -1 -0.5 -1 -0.520003 0.0400034 -2.75 -0.999994 -1.08719e-05 0.5 1 -0.5 -1 -0.500003 3.39746e-06 -2.76 -0.960006 0.12287 -0.5 1 -0.5 -1 -0.480003 -0.0399966 -2.77 -0.920007 0.235511 -0.5 1 -0.5 -1 -0.460003 -0.0799966 -2.78 -0.880007 0.337912 -0.5 1 -0.5 -1 -0.440003 -0.119997 -2.79 -0.840007 0.430072 -0.5 1 -0.5 -1 -0.420003 -0.159997 -2.8 -0.800007 0.511993 -0.5 1 -0.5 -1 -0.400003 -0.199996 -2.81 -0.760007 0.583674 -0.5 1 -0.5 -1 -0.380003 -0.239996 -2.82 -0.720007 0.645115 -0.5 1 -0.5 -1 -0.360003 -0.279996 -2.83 -0.680007 0.696316 -0.5 1 -0.5 -1 -0.340003 -0.319996 -2.84 -0.640007 0.737277 -0.5 1 -0.5 -1 -0.320003 -0.359996 -2.85 -0.600007 0.767998 -0.5 1 -0.5 -1 -0.300003 -0.399996 -2.86 -0.560007 0.788479 -0.5 1 -0.5 -1 -0.280003 -0.439996 -2.87 -0.520007 0.79872 -0.5 1 -0.5 -1 -0.260003 -0.479996 -2.88 -0.480007 0.79872 -0.5 -1 -0.5 -1 -0.240003 -0.519996 -2.89 -0.440007 0.788482 -0.5 -1 -0.5 -1 -0.220003 -0.559996 -2.9 -0.400007 0.768003 -0.5 -1 -0.5 -1 -0.200004 -0.599996 -2.91 -0.360007 0.737284 -0.5 -1 -0.5 -1 -0.180004 -0.639996 -2.92 -0.320007 0.696325 -0.5 -1 -0.5 -1 -0.160004 -0.679996 -2.93 -0.280007 0.645126 -0.5 -1 -0.5 -1 -0.140004 -0.719996 -2.94 -0.240007 0.583687 -0.5 -1 -0.5 -1 -0.120004 -0.759996 -2.95 -0.200007 0.512008 -0.5 -1 -0.5 -1 -0.100004 -0.799996 -2.96 -0.160007 0.430089 -0.5 -1 -0.5 -1 -0.0800036 -0.839996 -2.97 -0.120007 0.33793 -0.5 -1 -0.5 -1 -0.0600036 -0.879996 -2.98 -0.0800073 0.235531 -0.5 -1 -0.5 -1 -0.0400037 -0.919996 -2.99 -0.0400074 0.122893 -0.5 -1 -0.5 -1 -0.0200037 -0.959996 -3 -7.39098e-06 1.37329e-05 -0.5 1 -0.5 -1 -3.69549e-06 -0.999996 -3.01 0.0399928 -0.122867 0.5 1 1.5 1 0.0199963 0.960004 -3.02 0.0799928 -0.235508 0.5 1 1.5 1 0.0399963 0.920004 -3.03 0.119993 -0.337909 0.5 1 1.5 1 0.0599962 0.880004 -3.04 0.159993 -0.430071 0.5 1 1.5 1 0.0799962 0.840004 -3.05 0.199993 -0.511992 0.5 1 1.5 1 0.0999962 0.800004 -3.06 0.239993 -0.583673 0.5 1 1.5 1 0.119996 0.760004 -3.07 0.279993 -0.645114 0.5 1 1.5 -1 0.139996 0.720004 -3.08 0.319993 -0.696315 0.5 1 1.5 -1 0.159996 0.680004 -3.09 0.359993 -0.737276 0.5 1 1.5 -1 0.179996 0.640004 -3.1 0.399993 -0.767997 0.5 1 1.5 -1 0.199996 0.600004 -3.11 0.439993 -0.788478 0.5 1 1.5 -1 0.219996 0.560004 -3.12 0.479993 -0.798719 0.5 1 1.5 -1 0.239996 0.520004 -3.13 0.519993 -0.798721 0.5 -1 1.5 -1 0.259996 0.480004 -3.14 0.559993 -0.788482 0.5 -1 1.5 -1 0.279996 0.440004 -3.15 0.599993 -0.768003 0.5 -1 1.5 -1 0.299996 0.400004 -3.16 0.639993 -0.737284 0.5 -1 1.5 -1 0.319996 0.360004 -3.17 0.679993 -0.696325 0.5 -1 1.5 -1 0.339996 0.320004 -3.18 0.719993 -0.645126 0.5 -1 1.5 -1 0.359996 0.280004 -3.19 0.759993 -0.583687 0.5 -1 1.5 -1 0.379996 0.240004 -3.2 0.799993 -0.512008 0.5 -1 1.5 -1 0.399996 0.200004 -3.21 0.839993 -0.430089 0.5 -1 1.5 -1 0.419996 0.160004 -3.22 0.879993 -0.33793 0.5 -1 1.5 -1 0.439996 0.120004 -3.23 0.919993 -0.235531 0.5 -1 1.5 -1 0.459996 0.0800042 -3.24 0.959993 -0.122892 0.5 -1 1.5 -1 0.479996 0.0400041 -3.25 0.999993 -1.31607e-05 0.5 1 1.5 -1 0.499996 4.11272e-06 -3.26 0.960007 0.122868 0.5 1 -0.5 -1 0.519996 -0.0399959 -3.27 0.920007 0.235509 0.5 1 -0.5 -1 0.539996 -0.0799959 -3.28 0.880007 0.33791 0.5 1 -0.5 -1 0.559996 -0.119996 -3.29 0.840007 0.430071 0.5 1 -0.5 -1 0.579996 -0.159996 -3.3 0.800007 0.511992 0.5 1 -0.5 -1 0.599996 -0.199996 -3.31 0.760007 0.583673 0.5 1 -0.5 -1 0.619996 -0.239996 -3.32 0.720007 0.645114 0.5 1 -0.5 -1 0.639996 -0.279996 -3.33 0.680007 0.696315 0.5 1 -0.5 -1 0.659996 -0.319996 -3.34 0.640007 0.737276 0.5 1 -0.5 -1 0.679996 -0.359996 -3.35 0.600007 0.767997 0.5 1 -0.5 -1 0.699996 -0.399996 -3.36 0.560007 0.788478 0.5 1 -0.5 -1 0.719996 -0.439996 -3.37 0.520007 0.798719 0.5 1 -0.5 -1 0.739996 -0.479995 -3.38 0.480007 0.798721 0.5 -1 -0.5 -1 0.759996 -0.519995 -3.39 0.440007 0.788482 0.5 -1 -0.5 -1 0.779996 -0.559995 -3.4 0.400007 0.768003 0.5 -1 -0.5 -1 0.799996 -0.599995 -3.41 0.360008 0.737284 0.5 -1 -0.5 -1 0.819996 -0.639995 -3.42 0.320008 0.696325 0.5 -1 -0.5 -1 0.839996 -0.679995 -3.43 0.280008 0.645127 0.5 -1 -0.5 -1 0.859995 -0.719995 -3.44 0.240008 0.583688 0.5 -1 -0.5 -1 0.879995 -0.759995 -3.45 0.200008 0.512009 0.5 -1 -0.5 -1 0.899995 -0.799995 -3.46 0.160008 0.430091 0.5 -1 -0.5 -1 0.919995 -0.839995 -3.47 0.120008 0.337932 0.5 -1 -0.5 -1 0.939995 -0.879995 -3.48 0.0800078 0.235533 0.5 -1 -0.5 -1 0.959995 -0.919995 -3.49 0.0400078 0.122895 0.5 -1 -0.5 -1 0.979995 -0.959995 -3.5 7.86781e-06 1.60216e-05 0.5 1 -0.5 -1 0.999995 -0.999995 -3.51 -0.0399921 -0.122865 0.5 1 -0.5 1 -0.980005 0.960005 -3.52 -0.0799921 -0.235507 0.5 1 -0.5 1 -0.960005 0.920005 -3.53 -0.119992 -0.337908 0.5 1 -0.5 1 -0.940005 0.880005 -3.54 -0.159992 -0.430069 0.5 1 -0.5 1 -0.920005 0.840005 -3.55 -0.199992 -0.51199 0.5 1 -0.5 1 -0.900005 0.800005 -3.56 -0.239992 -0.583672 0.5 1 -0.5 1 -0.880005 0.760005 -3.57 -0.279992 -0.645113 0.5 1 -0.5 -1 -0.860005 0.720005 -3.58 -0.319992 -0.696314 0.5 1 -0.5 -1 -0.840005 0.680005 -3.59 -0.359992 -0.737275 0.5 1 -0.5 -1 -0.820005 0.640005 -3.6 -0.399992 -0.767997 0.5 1 -0.5 -1 -0.800005 0.600005 -3.61 -0.439992 -0.788478 0.5 1 -0.5 -1 -0.780005 0.560005 -3.62 -0.479992 -0.798719 0.5 1 -0.5 -1 -0.760005 0.520005 -3.63 -0.519992 -0.798721 0.5 -1 -0.5 -1 -0.740005 0.480005 -3.64 -0.559992 -0.788482 0.5 -1 -0.5 -1 -0.720005 0.440005 -3.65 -0.599992 -0.768003 0.5 -1 -0.5 -1 -0.700005 0.400005 -3.66 -0.639992 -0.737284 0.5 -1 -0.5 -1 -0.680005 0.360005 -3.67 -0.679991 -0.696326 0.5 -1 -0.5 -1 -0.660004 0.320005 -3.68 -0.719991 -0.645127 0.5 -1 -0.5 -1 -0.640005 0.280005 -3.69 -0.759991 -0.583688 0.5 -1 -0.5 -1 -0.620005 0.240005 -3.7 -0.799991 -0.512009 0.5 -1 -0.5 -1 -0.600004 0.200005 -3.71 -0.839991 -0.430091 0.5 -1 -0.5 -1 -0.580004 0.160005 -3.72 -0.879991 -0.337932 0.5 -1 -0.5 -1 -0.560004 0.120005 -3.73 -0.919991 -0.235533 0.5 -1 -0.5 -1 -0.540004 0.0800049 -3.74 -0.959991 -0.122894 0.5 -1 -0.5 -1 -0.520004 0.0400048 -3.75 -0.999991 -1.54495e-05 0.5 1 -0.5 -1 -0.500004 4.82798e-06 -3.76 -0.960009 0.122866 -0.5 1 -0.5 -1 -0.480004 -0.0399952 -3.77 -0.920009 0.235507 -0.5 1 -0.5 -1 -0.460004 -0.0799952 -3.78 -0.880009 0.337908 -0.5 1 -0.5 -1 -0.440004 -0.119995 -3.79 -0.840009 0.430069 -0.5 1 -0.5 -1 -0.420004 -0.159995 -3.8 -0.800009 0.51199 -0.5 1 -0.5 -1 -0.400005 -0.199995 -3.81 -0.760009 0.583672 -0.5 1 -0.5 -1 -0.380005 -0.239995 -3.82 -0.720009 0.645113 -0.5 1 -0.5 -1 -0.360005 -0.279995 -3.83 -0.680009 0.696314 -0.5 1 -0.5 -1 -0.340005 -0.319995 -3.84 -0.640009 0.737275 -0.5 1 -0.5 -1 -0.320005 -0.359995 -3.85 -0.600009 0.767997 -0.5 1 -0.5 -1 -0.300005 -0.399995 -3.86 -0.560009 0.788478 -0.5 1 -0.5 -1 -0.280005 -0.439995 -3.87 -0.520009 0.798719 -0.5 1 -0.5 -1 -0.260005 -0.479995 -3.88 -0.480009 0.798721 -0.5 -1 -0.5 -1 -0.240005 -0.519995 -3.89 -0.440009 0.788482 -0.5 -1 -0.5 -1 -0.220005 -0.559995 -3.9 -0.400009 0.768003 -0.5 -1 -0.5 -1 -0.200005 -0.599995 -3.91 -0.360009 0.737285 -0.5 -1 -0.5 -1 -0.180005 -0.639995 -3.92 -0.320009 0.696326 -0.5 -1 -0.5 -1 -0.160005 -0.679995 -3.93 -0.28001 0.645128 -0.5 -1 -0.5 -1 -0.140005 -0.719995 -3.94 -0.24001 0.583689 -0.5 -1 -0.5 -1 -0.120005 -0.759995 -3.95 -0.20001 0.512011 -0.5 -1 -0.5 -1 -0.100005 -0.799994 -3.96 -0.16001 0.430092 -0.5 -1 -0.5 -1 -0.0800048 -0.839994 -3.97 -0.12001 0.337934 -0.5 -1 -0.5 -1 -0.0600048 -0.879994 -3.98 -0.0800097 0.235535 -0.5 -1 -0.5 -1 -0.0400048 -0.919994 -3.99 -0.0400097 0.122897 -0.5 -1 -0.5 -1 -0.0200049 -0.959994 -4 -9.77516e-06 1.83104e-05 -0.5 1 -0.5 -1 -4.88758e-06 -0.999994 -4.01 0.0399904 -0.122863 0.5 1 1.5 1 0.0199951 0.960006 -4.02 0.0799904 -0.235505 0.5 1 1.5 1 0.0399951 0.920006 -4.03 0.11999 -0.337906 0.5 1 1.5 1 0.0599951 0.880006 -4.04 0.15999 -0.430068 0.5 1 1.5 1 0.079995 0.840006 -4.05 0.19999 -0.511989 0.5 1 1.5 1 0.099995 0.800006 -4.06 0.23999 -0.58367 0.5 1 1.5 1 0.119995 0.760006 -4.07 0.27999 -0.645112 0.5 1 1.5 -1 0.139995 0.720006 -4.08 0.31999 -0.696313 0.5 1 1.5 -1 0.159995 0.680006 -4.09 0.35999 -0.737275 0.5 1 1.5 -1 0.179995 0.640006 -4.1 0.39999 -0.767996 0.5 1 1.5 -1 0.199995 0.600006 -4.11 0.43999 -0.788478 0.5 1 1.5 -1 0.219995 0.560006 -4.12 0.47999 -0.798719 0.5 1 1.5 -1 0.239995 0.520006 -4.13 0.51999 -0.798721 0.5 -1 1.5 -1 0.259995 0.480006 -4.14 0.55999 -0.788482 0.5 -1 1.5 -1 0.279995 0.440006 -4.15 0.59999 -0.768004 0.5 -1 1.5 -1 0.299995 0.400006 -4.16 0.63999 -0.737285 0.5 -1 1.5 -1 0.319995 0.360006 -4.17 0.67999 -0.696327 0.5 -1 1.5 -1 0.339995 0.320006 -4.18 0.71999 -0.645128 0.5 -1 1.5 -1 0.359995 0.280006 -4.19 0.759991 -0.583689 0.5 -1 1.5 -1 0.379995 0.240006 -4.2 0.799991 -0.512011 0.5 -1 1.5 -1 0.399995 0.200006 -4.21 0.839991 -0.430092 0.5 -1 1.5 -1 0.419995 0.160006 -4.22 0.879991 -0.337934 0.5 -1 1.5 -1 0.439995 0.120006 -4.23 0.919991 -0.235535 0.5 -1 1.5 -1 0.459995 0.0800056 -4.24 0.959991 -0.122896 0.5 -1 1.5 -1 0.479995 0.0400056 -4.25 0.999991 -1.77382e-05 0.5 1 1.5 -1 0.499995 5.54323e-06 -4.26 0.960009 0.122864 0.5 1 -0.5 -1 0.519995 -0.0399945 -4.27 0.920009 0.235505 0.5 1 -0.5 -1 0.539995 -0.0799944 -4.28 0.880009 0.337906 0.5 1 -0.5 -1 0.559995 -0.119994 -4.29 0.840009 0.430068 0.5 1 -0.5 -1 0.579995 -0.159994 -4.3 0.800009 0.511989 0.5 1 -0.5 -1 0.599995 -0.199994 -4.31 0.76001 0.58367 0.5 1 -0.5 -1 0.619995 -0.239994 -4.32 0.72001 0.645112 0.5 1 -0.5 -1 0.639995 -0.279994 -4.33 0.68001 0.696313 0.5 1 -0.5 -1 0.659994 -0.319994 -4.34 0.64001 0.737275 0.5 1 -0.5 -1 0.679994 -0.359994 -4.35 0.60001 0.767996 0.5 1 -0.5 -1 0.699994 -0.399994 -4.36 0.56001 0.788478 0.5 1 -0.5 -1 0.719994 -0.439994 -4.37 0.52001 0.798719 0.5 1 -0.5 -1 0.739994 -0.479994 -4.38 0.48001 0.798721 0.5 -1 -0.5 -1 0.759994 -0.519994 -4.39 0.44001 0.788482 0.5 -1 -0.5 -1 0.779994 -0.559994 -4.4 0.40001 0.768004 0.5 -1 -0.5 -1 0.799994 -0.599994 -4.41 0.36001 0.737285 0.5 -1 -0.5 -1 0.819994 -0.639994 -4.42 0.32001 0.696327 0.5 -1 -0.5 -1 0.839994 -0.679994 -4.43 0.28001 0.645129 0.5 -1 -0.5 -1 0.859994 -0.719994 -4.44 0.24001 0.58369 0.5 -1 -0.5 -1 0.879994 -0.759994 -4.45 0.20001 0.512012 0.5 -1 -0.5 -1 0.899994 -0.799994 -4.46 0.16001 0.430094 0.5 -1 -0.5 -1 0.919994 -0.839994 -4.47 0.12001 0.337935 0.5 -1 -0.5 -1 0.939994 -0.879994 -4.48 0.0800102 0.235537 0.5 -1 -0.5 -1 0.959994 -0.919994 -4.49 0.0400102 0.122899 0.5 -1 -0.5 -1 0.979994 -0.959994 -4.5 1.0252e-05 2.05992e-05 0.5 1 -0.5 -1 0.999994 -0.999994 -4.51 -0.0399897 -0.122861 0.5 1 -0.5 1 -0.980006 0.960006 -4.52 -0.0799897 -0.235503 0.5 1 -0.5 1 -0.960006 0.920006 -4.53 -0.11999 -0.337904 0.5 1 -0.5 1 -0.940006 0.880006 -4.54 -0.15999 -0.430066 0.5 1 -0.5 1 -0.920006 0.840006 -4.55 -0.19999 -0.511988 0.5 1 -0.5 1 -0.900006 0.800007 -4.56 -0.23999 -0.583669 0.5 1 -0.5 1 -0.880006 0.760006 -4.57 -0.279989 -0.645111 0.5 1 -0.5 -1 -0.860006 0.720006 -4.58 -0.319989 -0.696313 0.5 1 -0.5 -1 -0.840006 0.680007 -4.59 -0.359989 -0.737274 0.5 1 -0.5 -1 -0.820006 0.640007 -4.6 -0.399989 -0.767996 0.5 1 -0.5 -1 -0.800006 0.600007 -4.61 -0.439989 -0.788477 0.5 1 -0.5 -1 -0.780006 0.560006 -4.62 -0.479989 -0.798719 0.5 1 -0.5 -1 -0.760006 0.520007 -4.63 -0.519989 -0.798721 0.5 -1 -0.5 -1 -0.740006 0.480007 -4.64 -0.559989 -0.788483 0.5 -1 -0.5 -1 -0.720006 0.440006 -4.65 -0.599989 -0.768004 0.5 -1 -0.5 -1 -0.700006 0.400006 -4.66 -0.639989 -0.737286 0.5 -1 -0.5 -1 -0.680006 0.360006 -4.67 -0.679989 -0.696327 0.5 -1 -0.5 -1 -0.660006 0.320006 -4.68 -0.719989 -0.645129 0.5 -1 -0.5 -1 -0.640006 0.280006 -4.69 -0.759989 -0.583691 0.5 -1 -0.5 -1 -0.620006 0.240006 -4.7 -0.799989 -0.512012 0.5 -1 -0.5 -1 -0.600006 0.200006 -4.71 -0.839989 -0.430094 0.5 -1 -0.5 -1 -0.580006 0.160006 -4.72 -0.879989 -0.337935 0.5 -1 -0.5 -1 -0.560006 0.120006 -4.73 -0.919989 -0.235537 0.5 -1 -0.5 -1 -0.540006 0.0800063 -4.74 -0.959989 -0.122898 0.5 -1 -0.5 -1 -0.520006 0.0400063 -4.75 -0.999989 -2.0027e-05 0.5 1 -0.5 -1 -0.500006 6.25849e-06 -4.76 -0.960011 0.122862 -0.5 1 -0.5 -1 -0.480006 -0.0399938 -4.77 -0.920011 0.235503 -0.5 1 -0.5 -1 -0.460006 -0.0799937 -4.78 -0.880011 0.337905 -0.5 1 -0.5 -1 -0.440006 -0.119994 -4.79 -0.840011 0.430066 -0.5 1 -0.5 -1 -0.420006 -0.159994 -4.8 -0.800011 0.511988 -0.5 1 -0.5 -1 -0.400006 -0.199994 -4.81 -0.760011 0.583669 -0.5 1 -0.5 -1 -0.380006 -0.239994 -4.82 -0.720011 0.645111 -0.5 1 -0.5 -1 -0.360006 -0.279994 -4.83 -0.680012 0.696312 -0.5 1 -0.5 -1 -0.340006 -0.319993 -4.84 -0.640012 0.737274 -0.5 1 -0.5 -1 -0.320006 -0.359993 -4.85 -0.600012 0.767996 -0.5 1 -0.5 -1 -0.300006 -0.399993 -4.86 -0.560012 0.788477 -0.5 1 -0.5 -1 -0.280006 -0.439993 -4.87 -0.520012 0.798719 -0.5 1 -0.5 -1 -0.260006 -0.479993 -4.88 -0.480012 0.798721 -0.5 -1 -0.5 -1 -0.240006 -0.519993 -4.89 -0.440012 0.788483 -0.5 -1 -0.5 -1 -0.220006 -0.559993 -4.9 -0.400012 0.768004 -0.5 -1 -0.5 -1 -0.200006 -0.599993 -4.91 -0.360012 0.737286 -0.5 -1 -0.5 -1 -0.180006 -0.639993 -4.92 -0.320012 0.696328 -0.5 -1 -0.5 -1 -0.160006 -0.679993 -4.93 -0.280012 0.64513 -0.5 -1 -0.5 -1 -0.140006 -0.719993 -4.94 -0.240012 0.583692 -0.5 -1 -0.5 -1 -0.120006 -0.759993 -4.95 -0.200012 0.512013 -0.5 -1 -0.5 -1 -0.100006 -0.799993 -4.96 -0.160012 0.430095 -0.5 -1 -0.5 -1 -0.080006 -0.839993 -4.97 -0.120012 0.337937 -0.5 -1 -0.5 -1 -0.060006 -0.879993 -4.98 -0.0800121 0.235539 -0.5 -1 -0.5 -1 -0.040006 -0.919993 -4.99 -0.0400121 0.122901 -0.5 -1 -0.5 -1 -0.0200061 -0.959993 +0.01 0.04 0.12288 0.5 1 1.5 1 0.02 0.96 +0.02 0.08 0.23552 0.5 1 1.5 1 0.04 0.92 +0.03 0.12 0.33792 0.5 1 1.5 1 0.0599999 0.88 +0.04 0.16 0.43008 0.5 1 1.5 1 0.08 0.84 +0.05 0.2 0.512 0.5 1 1.5 1 0.1 0.8 +0.06 0.24 0.58368 0.5 1 1.5 1 0.12 0.76 +0.07 0.28 0.64512 0.5 1 1.5 0 0.14 0.72 +0.08 0.32 0.69632 0.5 1 1.5 0 0.16 0.68 +0.09 0.36 0.73728 0.5 1 1.5 0 0.18 0.64 +0.1 0.4 0.768 0.5 1 1.5 0 0.2 0.6 +0.11 0.44 0.78848 0.5 1 1.5 0 0.22 0.56 +0.12 0.48 0.79872 0.5 1 1.5 0 0.24 0.52 +0.13 0.52 0.79872 0.5 0 1.5 0 0.26 0.48 +0.14 0.56 0.78848 0.5 0 1.5 0 0.28 0.44 +0.15 0.6 0.768 0.5 0 1.5 0 0.3 0.4 +0.16 0.64 0.73728 0.5 0 1.5 0 0.32 0.36 +0.17 0.68 0.69632 0.5 0 1.5 0 0.34 0.32 +0.18 0.72 0.64512 0.5 0 1.5 0 0.36 0.28 +0.19 0.76 0.58368 0.5 0 1.5 0 0.38 0.24 +0.2 0.8 0.512 0.5 0 1.5 0 0.4 0.2 +0.21 0.84 0.43008 0.5 0 1.5 0 0.42 0.16 +0.22 0.88 0.33792 0.5 0 1.5 0 0.44 0.12 +0.23 0.92 0.23552 0.5 0 1.5 0 0.46 0.0799999 +0.24 0.96 0.12288 0.5 0 1.5 0 0.48 0.0399998 +0.25 1 -3.8147e-07 0.5 1 0.5 0 0.5 -1.19209e-07 +0.26 0.96 -0.12288 0.5 1 0.5 0 0.52 -0.0400001 +0.27 0.92 -0.23552 0.5 1 0.5 0 0.54 -0.08 +0.28 0.88 -0.33792 0.5 1 0.5 0 0.56 -0.12 +0.29 0.84 -0.43008 0.5 1 0.5 0 0.58 -0.16 +0.3 0.8 -0.512 0.5 1 0.5 0 0.6 -0.2 +0.31 0.76 -0.58368 0.5 1 0.5 0 0.62 -0.24 +0.32 0.72 -0.64512 0.5 1 0.5 0 0.64 -0.28 +0.33 0.68 -0.69632 0.5 1 0.5 0 0.66 -0.32 +0.34 0.64 -0.73728 0.5 1 0.5 0 0.68 -0.36 +0.35 0.6 -0.768 0.5 1 0.5 0 0.7 -0.4 +0.36 0.56 -0.78848 0.5 1 0.5 0 0.72 -0.44 +0.37 0.52 -0.79872 0.5 1 0.5 0 0.74 -0.48 +0.38 0.48 -0.79872 0.5 0 0.5 0 0.76 -0.52 +0.39 0.44 -0.78848 0.5 0 0.5 0 0.78 -0.56 +0.4 0.4 -0.768 0.5 0 0.5 0 0.8 -0.6 +0.41 0.36 -0.73728 0.5 0 0.5 0 0.82 -0.64 +0.42 0.320001 -0.696321 0.5 0 0.5 0 0.84 -0.679999 +0.43 0.280001 -0.645121 0.5 0 0.5 0 0.86 -0.719999 +0.44 0.240001 -0.583681 0.5 0 0.5 0 0.88 -0.759999 +0.45 0.200001 -0.512001 0.5 0 0.5 0 0.9 -0.799999 +0.46 0.160001 -0.430081 0.5 0 0.5 0 0.92 -0.839999 +0.47 0.120001 -0.337922 0.5 0 0.5 0 0.94 -0.879999 +0.48 0.0800008 -0.235522 0.5 0 0.5 0 0.96 -0.919999 +0.49 0.0400008 -0.122882 0.5 0 0.5 0 0.98 -0.959999 +0.5 8.34465e-07 -2.67029e-06 0.5 1 0.5 0 1 -0.999999 +0.51 -0.0399992 0.122878 0.5 1 0.5 1 -0.98 0.960001 +0.52 -0.0799992 0.235518 0.5 1 0.5 1 -0.960001 0.920001 +0.53 -0.119999 0.337918 0.5 1 0.5 1 -0.940001 0.880001 +0.54 -0.159999 0.430078 0.5 1 0.5 1 -0.920001 0.840001 +0.55 -0.199999 0.511998 0.5 1 0.5 1 -0.900001 0.800001 +0.56 -0.239999 0.583679 0.5 1 0.5 1 -0.880001 0.760001 +0.57 -0.279999 0.645119 0.5 1 0.5 0 -0.860001 0.720001 +0.58 -0.319999 0.696319 0.5 1 0.5 0 -0.840001 0.680001 +0.59 -0.359999 0.737279 0.5 1 0.5 0 -0.820001 0.640001 +0.6 -0.399999 0.767999 0.5 1 0.5 0 -0.800001 0.600001 +0.61 -0.439999 0.78848 0.5 1 0.5 0 -0.780001 0.560001 +0.62 -0.479999 0.79872 0.5 1 0.5 0 -0.760001 0.520001 +0.63 -0.519999 0.79872 0.5 0 0.5 0 -0.740001 0.480001 +0.64 -0.559999 0.78848 0.5 0 0.5 0 -0.720001 0.440001 +0.65 -0.599999 0.768001 0.5 0 0.5 0 -0.700001 0.400001 +0.66 -0.639999 0.737281 0.5 0 0.5 0 -0.680001 0.360001 +0.67 -0.679999 0.696321 0.5 0 0.5 0 -0.660001 0.320001 +0.68 -0.719999 0.645121 0.5 0 0.5 0 -0.640001 0.280001 +0.69 -0.759999 0.583681 0.5 0 0.5 0 -0.620001 0.240001 +0.7 -0.799999 0.512001 0.5 0 0.5 0 -0.600001 0.200001 +0.71 -0.839998 0.430081 0.5 0 0.5 0 -0.580001 0.160001 +0.72 -0.879998 0.337921 0.5 0 0.5 0 -0.560001 0.120001 +0.73 -0.919998 0.235522 0.5 0 0.5 0 -0.540001 0.0800006 +0.74 -0.959998 0.122882 0.5 0 0.5 0 -0.520001 0.0400006 +0.75 -0.999998 1.71661e-06 0.5 1 0.5 0 -0.500001 5.36442e-07 +0.76 -0.960002 -0.122878 0 1 0.5 0 -0.480001 -0.0399995 +0.77 -0.920002 -0.235519 0 1 0.5 0 -0.460001 -0.0799994 +0.78 -0.880002 -0.337919 0 1 0.5 0 -0.440001 -0.119999 +0.79 -0.840002 -0.430079 0 1 0.5 0 -0.420001 -0.159999 +0.8 -0.800002 -0.511999 0 1 0.5 0 -0.400001 -0.199999 +0.81 -0.760002 -0.583679 0 1 0.5 0 -0.380001 -0.239999 +0.82 -0.720002 -0.645119 0 1 0.5 0 -0.360001 -0.279999 +0.83 -0.680002 -0.696319 0 1 0.5 0 -0.340001 -0.319999 +0.84 -0.640002 -0.737279 0 1 0.5 0 -0.320001 -0.359999 +0.85 -0.600002 -0.767999 0 1 0.5 0 -0.300001 -0.399999 +0.86 -0.560002 -0.78848 0 1 0.5 0 -0.280001 -0.439999 +0.87 -0.520002 -0.79872 0 1 0.5 0 -0.260001 -0.479999 +0.88 -0.480002 -0.79872 0 0 0.5 0 -0.240001 -0.519999 +0.89 -0.440002 -0.78848 0 0 0.5 0 -0.220001 -0.559999 +0.9 -0.400002 -0.768001 0 0 0.5 0 -0.200001 -0.599999 +0.91 -0.360002 -0.737281 0 0 0.5 0 -0.180001 -0.639999 +0.92 -0.320002 -0.696321 0 0 0.5 0 -0.160001 -0.679999 +0.93 -0.280002 -0.645122 0 0 0.5 0 -0.140001 -0.719999 +0.94 -0.240002 -0.583682 0 0 0.5 0 -0.120001 -0.759999 +0.95 -0.200002 -0.512002 0 0 0.5 0 -0.100001 -0.799999 +0.96 -0.160002 -0.430083 0 0 0.5 0 -0.0800014 -0.839999 +0.97 -0.120003 -0.337923 0 0 0.5 0 -0.0600014 -0.879999 +0.98 -0.0800025 -0.235524 0 0 0.5 0 -0.0400014 -0.919999 +0.99 -0.0400026 -0.122884 0 0 0.5 0 -0.0200014 -0.959999 +1 -2.6226e-06 -4.57763e-06 0 1 0.5 0 -1.43051e-06 -0.999999 +1.01 0.0399976 0.122876 0.5 1 1.5 1 0.0199988 0.960001 +1.02 0.0799976 0.235516 0.5 1 1.5 1 0.0399988 0.920001 +1.03 0.119998 0.337916 0.5 1 1.5 1 0.0599988 0.880001 +1.04 0.159998 0.430077 0.5 1 1.5 1 0.0799987 0.840001 +1.05 0.199998 0.511997 0.5 1 1.5 1 0.0999988 0.800002 +1.06 0.239998 0.583678 0.5 1 1.5 1 0.119999 0.760001 +1.07 0.279998 0.645118 0.5 1 1.5 0 0.139999 0.720001 +1.08 0.319998 0.696318 0.5 1 1.5 0 0.159999 0.680001 +1.09 0.359998 0.737279 0.5 1 1.5 0 0.179999 0.640002 +1.1 0.399998 0.767999 0.5 1 1.5 0 0.199999 0.600002 +1.11 0.439998 0.788479 0.5 1 1.5 0 0.219999 0.560001 +1.12 0.479998 0.79872 0.5 1 1.5 0 0.239999 0.520002 +1.13 0.519998 0.79872 0.5 0 1.5 0 0.259999 0.480002 +1.14 0.559998 0.788481 0.5 0 1.5 0 0.279999 0.440001 +1.15 0.599998 0.768001 0.5 0 1.5 0 0.299999 0.400001 +1.16 0.639998 0.737281 0.5 0 1.5 0 0.319999 0.360001 +1.17 0.679998 0.696322 0.5 0 1.5 0 0.339999 0.320001 +1.18 0.719998 0.645122 0.5 0 1.5 0 0.359999 0.280001 +1.19 0.759998 0.583682 0.5 0 1.5 0 0.379999 0.240001 +1.2 0.799998 0.512003 0.5 0 1.5 0 0.399999 0.200001 +1.21 0.839998 0.430083 0.5 0 1.5 0 0.419999 0.160001 +1.22 0.879998 0.337923 0.5 0 1.5 0 0.439999 0.120001 +1.23 0.919998 0.235523 0.5 0 1.5 0 0.459999 0.0800013 +1.24 0.959998 0.122884 0.5 0 1.5 0 0.479999 0.0400013 +1.25 0.999998 4.00543e-06 0.5 1 1.5 0 0.499999 1.2517e-06 +1.26 0.960002 -0.122876 0.5 1 0.5 0 0.519999 -0.0399988 +1.27 0.920002 -0.235517 0.5 1 0.5 0 0.539999 -0.0799987 +1.28 0.880002 -0.337917 0.5 1 0.5 0 0.559999 -0.119999 +1.29 0.840002 -0.430077 0.5 1 0.5 0 0.579999 -0.159999 +1.3 0.800002 -0.511997 0.5 1 0.5 0 0.599999 -0.199999 +1.31 0.760002 -0.583678 0.5 1 0.5 0 0.619999 -0.239999 +1.32 0.720002 -0.645118 0.5 1 0.5 0 0.639999 -0.279999 +1.33 0.680002 -0.696318 0.5 1 0.5 0 0.659999 -0.319999 +1.34 0.640002 -0.737279 0.5 1 0.5 0 0.679999 -0.359998 +1.35 0.600003 -0.767999 0.5 1 0.5 0 0.699999 -0.399998 +1.36 0.560003 -0.788479 0.5 1 0.5 0 0.719999 -0.439998 +1.37 0.520003 -0.79872 0.5 1 0.5 0 0.739999 -0.479998 +1.38 0.480003 -0.79872 0.5 0 0.5 0 0.759999 -0.519998 +1.39 0.440003 -0.788481 0.5 0 0.5 0 0.779999 -0.559998 +1.4 0.400003 -0.768001 0.5 0 0.5 0 0.799999 -0.599998 +1.41 0.360003 -0.737282 0.5 0 0.5 0 0.819999 -0.639998 +1.42 0.320003 -0.696322 0.5 0 0.5 0 0.839999 -0.679998 +1.43 0.280003 -0.645123 0.5 0 0.5 0 0.859999 -0.719998 +1.44 0.240003 -0.583683 0.5 0 0.5 0 0.879999 -0.759998 +1.45 0.200003 -0.512004 0.5 0 0.5 0 0.899999 -0.799998 +1.46 0.160003 -0.430084 0.5 0 0.5 0 0.919999 -0.839998 +1.47 0.120003 -0.337925 0.5 0 0.5 0 0.939999 -0.879998 +1.48 0.080003 -0.235526 0.5 0 0.5 0 0.959998 -0.919998 +1.49 0.0400031 -0.122886 0.5 0 0.5 0 0.979998 -0.959998 +1.5 3.09944e-06 -6.86644e-06 0.5 1 0.5 0 0.999998 -0.999998 +1.51 -0.0399969 0.122874 0.5 1 0.5 1 -0.980001 0.960002 +1.52 -0.0799968 0.235514 0.5 1 0.5 1 -0.960001 0.920002 +1.53 -0.119997 0.337915 0.5 1 0.5 1 -0.940001 0.880002 +1.54 -0.159997 0.430075 0.5 1 0.5 1 -0.920002 0.840002 +1.55 -0.199997 0.511996 0.5 1 0.5 1 -0.900002 0.800002 +1.56 -0.239997 0.583676 0.5 1 0.5 1 -0.880002 0.760002 +1.57 -0.279997 0.645117 0.5 1 0.5 0 -0.860002 0.720002 +1.58 -0.319997 0.696317 0.5 1 0.5 0 -0.840002 0.680002 +1.59 -0.359997 0.737278 0.5 1 0.5 0 -0.820002 0.640002 +1.6 -0.399997 0.767999 0.5 1 0.5 0 -0.800002 0.600002 +1.61 -0.439996 0.788479 0.5 1 0.5 0 -0.780002 0.560002 +1.62 -0.479996 0.79872 0.5 1 0.5 0 -0.760002 0.520002 +1.63 -0.519996 0.79872 0.5 0 0.5 0 -0.740002 0.480002 +1.64 -0.559996 0.788481 0.5 0 0.5 0 -0.720002 0.440002 +1.65 -0.599996 0.768001 0.5 0 0.5 0 -0.700002 0.400002 +1.66 -0.639996 0.737282 0.5 0 0.5 0 -0.680002 0.360002 +1.67 -0.679996 0.696322 0.5 0 0.5 0 -0.660002 0.320002 +1.68 -0.719996 0.645123 0.5 0 0.5 0 -0.640002 0.280002 +1.69 -0.759996 0.583683 0.5 0 0.5 0 -0.620002 0.240002 +1.7 -0.799996 0.512004 0.5 0 0.5 0 -0.600002 0.200002 +1.71 -0.839996 0.430084 0.5 0 0.5 0 -0.580002 0.160002 +1.72 -0.879996 0.337925 0.5 0 0.5 0 -0.560002 0.120002 +1.73 -0.919996 0.235525 0.5 0 0.5 0 -0.540002 0.080002 +1.74 -0.959996 0.122886 0.5 0 0.5 0 -0.520002 0.040002 +1.75 -0.999996 6.29424e-06 0.5 1 0.5 0 -0.500002 1.96695e-06 +1.76 -0.960004 -0.122874 0 1 0.5 0 -0.480002 -0.0399981 +1.77 -0.920004 -0.235515 0 1 0.5 0 -0.460002 -0.079998 +1.78 -0.880004 -0.337915 0 1 0.5 0 -0.440002 -0.119998 +1.79 -0.840004 -0.430076 0 1 0.5 0 -0.420002 -0.159998 +1.8 -0.800004 -0.511996 0 1 0.5 0 -0.400002 -0.199998 +1.81 -0.760004 -0.583676 0 1 0.5 0 -0.380002 -0.239998 +1.82 -0.720004 -0.645117 0 1 0.5 0 -0.360002 -0.279998 +1.83 -0.680004 -0.696317 0 1 0.5 0 -0.340002 -0.319998 +1.84 -0.640004 -0.737278 0 1 0.5 0 -0.320002 -0.359998 +1.85 -0.600004 -0.767999 0 1 0.5 0 -0.300002 -0.399998 +1.86 -0.560004 -0.788479 0 1 0.5 0 -0.280002 -0.439998 +1.87 -0.520005 -0.79872 0 1 0.5 0 -0.260002 -0.479998 +1.88 -0.480005 -0.79872 0 0 0.5 0 -0.240002 -0.519998 +1.89 -0.440005 -0.788481 0 0 0.5 0 -0.220002 -0.559998 +1.9 -0.400005 -0.768002 0 0 0.5 0 -0.200002 -0.599998 +1.91 -0.360005 -0.737282 0 0 0.5 0 -0.180002 -0.639997 +1.92 -0.320005 -0.696323 0 0 0.5 0 -0.160002 -0.679997 +1.93 -0.280005 -0.645124 0 0 0.5 0 -0.140002 -0.719997 +1.94 -0.240005 -0.583684 0 0 0.5 0 -0.120002 -0.759997 +1.95 -0.200005 -0.512005 0 0 0.5 0 -0.100002 -0.799997 +1.96 -0.160005 -0.430086 0 0 0.5 0 -0.0800023 -0.839997 +1.97 -0.120005 -0.337927 0 0 0.5 0 -0.0600023 -0.879997 +1.98 -0.0800049 -0.235527 0 0 0.5 0 -0.0400023 -0.919997 +1.99 -0.040005 -0.122888 0 0 0.5 0 -0.0200024 -0.959997 +2 -5.00679e-06 -9.15525e-06 0 1 0.5 0 -2.38419e-06 -0.999997 +2.01 0.0399952 0.122871 0.5 1 1.5 1 0.0199976 0.960003 +2.02 0.0799952 0.235512 0.5 1 1.5 1 0.0399976 0.920003 +2.03 0.119995 0.337913 0.5 1 1.5 1 0.0599976 0.880003 +2.04 0.159995 0.430074 0.5 1 1.5 1 0.0799975 0.840003 +2.05 0.199995 0.511994 0.5 1 1.5 1 0.0999976 0.800003 +2.06 0.239995 0.583675 0.5 1 1.5 1 0.119998 0.760003 +2.07 0.279995 0.645116 0.5 1 1.5 0 0.139998 0.720003 +2.08 0.319995 0.696317 0.5 1 1.5 0 0.159998 0.680003 +2.09 0.359995 0.737277 0.5 1 1.5 0 0.179998 0.640003 +2.1 0.399995 0.767998 0.5 1 1.5 0 0.199998 0.600003 +2.11 0.439995 0.788479 0.5 1 1.5 0 0.219998 0.560003 +2.12 0.479995 0.79872 0.5 1 1.5 0 0.239998 0.520003 +2.13 0.519995 0.79872 0.5 0 1.5 0 0.259998 0.480003 +2.14 0.559995 0.788481 0.5 0 1.5 0 0.279998 0.440003 +2.15 0.599995 0.768002 0.5 0 1.5 0 0.299998 0.400003 +2.16 0.639995 0.737283 0.5 0 1.5 0 0.319998 0.360003 +2.17 0.679995 0.696323 0.5 0 1.5 0 0.339998 0.320003 +2.18 0.719995 0.645124 0.5 0 1.5 0 0.359998 0.280003 +2.19 0.759995 0.583685 0.5 0 1.5 0 0.379998 0.240003 +2.2 0.799995 0.512005 0.5 0 1.5 0 0.399998 0.200003 +2.21 0.839995 0.430086 0.5 0 1.5 0 0.419998 0.160003 +2.22 0.879995 0.337927 0.5 0 1.5 0 0.439998 0.120003 +2.23 0.919995 0.235527 0.5 0 1.5 0 0.459998 0.0800027 +2.24 0.959995 0.122888 0.5 0 1.5 0 0.479998 0.0400027 +2.25 0.999995 8.58305e-06 0.5 1 1.5 0 0.499998 2.68221e-06 +2.26 0.960005 -0.122872 0.5 1 0.5 0 0.519998 -0.0399973 +2.27 0.920005 -0.235513 0.5 1 0.5 0 0.539998 -0.0799973 +2.28 0.880005 -0.337913 0.5 1 0.5 0 0.559998 -0.119997 +2.29 0.840005 -0.430074 0.5 1 0.5 0 0.579998 -0.159997 +2.3 0.800005 -0.511995 0.5 1 0.5 0 0.599998 -0.199997 +2.31 0.760005 -0.583675 0.5 1 0.5 0 0.619998 -0.239997 +2.32 0.720005 -0.645116 0.5 1 0.5 0 0.639998 -0.279997 +2.33 0.680005 -0.696317 0.5 1 0.5 0 0.659998 -0.319997 +2.34 0.640005 -0.737277 0.5 1 0.5 0 0.679998 -0.359997 +2.35 0.600005 -0.767998 0.5 1 0.5 0 0.699998 -0.399997 +2.36 0.560005 -0.788479 0.5 1 0.5 0 0.719998 -0.439997 +2.37 0.520005 -0.79872 0.5 1 0.5 0 0.739998 -0.479997 +2.38 0.480005 -0.79872 0.5 0 0.5 0 0.759997 -0.519997 +2.39 0.440005 -0.788481 0.5 0 0.5 0 0.779997 -0.559997 +2.4 0.400005 -0.768002 0.5 0 0.5 0 0.799997 -0.599997 +2.41 0.360005 -0.737283 0.5 0 0.5 0 0.819997 -0.639997 +2.42 0.320005 -0.696324 0.5 0 0.5 0 0.839997 -0.679997 +2.43 0.280005 -0.645125 0.5 0 0.5 0 0.859997 -0.719997 +2.44 0.240005 -0.583686 0.5 0 0.5 0 0.879997 -0.759997 +2.45 0.200005 -0.512007 0.5 0 0.5 0 0.899997 -0.799997 +2.46 0.160005 -0.430087 0.5 0 0.5 0 0.919997 -0.839997 +2.47 0.120005 -0.337928 0.5 0 0.5 0 0.939997 -0.879997 +2.48 0.0800054 -0.235529 0.5 0 0.5 0 0.959997 -0.919997 +2.49 0.0400054 -0.12289 0.5 0 0.5 0 0.979997 -0.959996 +2.5 5.48363e-06 -1.14441e-05 0.5 1 0.5 0 0.999997 -0.999996 +2.51 -0.0399945 0.122869 0.5 1 0.5 1 -0.980003 0.960004 +2.52 -0.0799944 0.23551 0.5 1 0.5 1 -0.960003 0.920004 +2.53 -0.119994 0.337911 0.5 1 0.5 1 -0.940003 0.880004 +2.54 -0.159994 0.430072 0.5 1 0.5 1 -0.920003 0.840004 +2.55 -0.199994 0.511993 0.5 1 0.5 1 -0.900003 0.800004 +2.56 -0.239994 0.583674 0.5 1 0.5 1 -0.880003 0.760004 +2.57 -0.279994 0.645115 0.5 1 0.5 0 -0.860003 0.720004 +2.58 -0.319994 0.696316 0.5 1 0.5 0 -0.840003 0.680004 +2.59 -0.359994 0.737277 0.5 1 0.5 0 -0.820003 0.640004 +2.6 -0.399994 0.767998 0.5 1 0.5 0 -0.800003 0.600004 +2.61 -0.439994 0.788479 0.5 1 0.5 0 -0.780003 0.560004 +2.62 -0.479994 0.79872 0.5 1 0.5 0 -0.760003 0.520004 +2.63 -0.519994 0.79872 0.5 0 0.5 0 -0.740003 0.480004 +2.64 -0.559994 0.788481 0.5 0 0.5 0 -0.720003 0.440004 +2.65 -0.599994 0.768002 0.5 0 0.5 0 -0.700003 0.400004 +2.66 -0.639994 0.737283 0.5 0 0.5 0 -0.680003 0.360004 +2.67 -0.679994 0.696324 0.5 0 0.5 0 -0.660003 0.320004 +2.68 -0.719994 0.645125 0.5 0 0.5 0 -0.640003 0.280004 +2.69 -0.759994 0.583686 0.5 0 0.5 0 -0.620003 0.240004 +2.7 -0.799994 0.512007 0.5 0 0.5 0 -0.600003 0.200004 +2.71 -0.839994 0.430088 0.5 0 0.5 0 -0.580003 0.160003 +2.72 -0.879994 0.337928 0.5 0 0.5 0 -0.560003 0.120003 +2.73 -0.919994 0.235529 0.5 0 0.5 0 -0.540003 0.0800034 +2.74 -0.959994 0.12289 0.5 0 0.5 0 -0.520003 0.0400034 +2.75 -0.999994 1.08719e-05 0.5 1 0.5 0 -0.500003 3.39746e-06 +2.76 -0.960006 -0.12287 0 1 0.5 0 -0.480003 -0.0399966 +2.77 -0.920007 -0.235511 0 1 0.5 0 -0.460003 -0.0799966 +2.78 -0.880007 -0.337912 0 1 0.5 0 -0.440003 -0.119997 +2.79 -0.840007 -0.430072 0 1 0.5 0 -0.420003 -0.159997 +2.8 -0.800007 -0.511993 0 1 0.5 0 -0.400003 -0.199996 +2.81 -0.760007 -0.583674 0 1 0.5 0 -0.380003 -0.239996 +2.82 -0.720007 -0.645115 0 1 0.5 0 -0.360003 -0.279996 +2.83 -0.680007 -0.696316 0 1 0.5 0 -0.340003 -0.319996 +2.84 -0.640007 -0.737277 0 1 0.5 0 -0.320004 -0.359996 +2.85 -0.600007 -0.767998 0 1 0.5 0 -0.300004 -0.399996 +2.86 -0.560007 -0.788479 0 1 0.5 0 -0.280004 -0.439996 +2.87 -0.520007 -0.79872 0 1 0.5 0 -0.260004 -0.479996 +2.88 -0.480007 -0.79872 0 0 0.5 0 -0.240004 -0.519996 +2.89 -0.440007 -0.788482 0 0 0.5 0 -0.220004 -0.559996 +2.9 -0.400007 -0.768003 0 0 0.5 0 -0.200004 -0.599996 +2.91 -0.360007 -0.737284 0 0 0.5 0 -0.180004 -0.639996 +2.92 -0.320007 -0.696325 0 0 0.5 0 -0.160004 -0.679996 +2.93 -0.280007 -0.645126 0 0 0.5 0 -0.140004 -0.719996 +2.94 -0.240007 -0.583687 0 0 0.5 0 -0.120004 -0.759996 +2.95 -0.200007 -0.512008 0 0 0.5 0 -0.100004 -0.799996 +2.96 -0.160007 -0.430089 0 0 0.5 0 -0.0800037 -0.839996 +2.97 -0.120007 -0.33793 0 0 0.5 0 -0.0600038 -0.879996 +2.98 -0.0800073 -0.235531 0 0 0.5 0 -0.0400038 -0.919996 +2.99 -0.0400074 -0.122893 0 0 0.5 0 -0.0200038 -0.959996 +3 -7.39098e-06 -1.37329e-05 0 1 0.5 0 -3.8147e-06 -0.999996 +3.01 0.0399928 0.122867 0.5 1 1.5 1 0.0199964 0.960004 +3.02 0.0799928 0.235508 0.5 1 1.5 1 0.0399964 0.920004 +3.03 0.119993 0.337909 0.5 1 1.5 1 0.0599964 0.880004 +3.04 0.159993 0.430071 0.5 1 1.5 1 0.0799963 0.840004 +3.05 0.199993 0.511992 0.5 1 1.5 1 0.0999964 0.800004 +3.06 0.239993 0.583673 0.5 1 1.5 1 0.119996 0.760004 +3.07 0.279993 0.645114 0.5 1 1.5 0 0.139996 0.720004 +3.08 0.319993 0.696315 0.5 1 1.5 0 0.159996 0.680004 +3.09 0.359993 0.737276 0.5 1 1.5 0 0.179996 0.640004 +3.1 0.399993 0.767997 0.5 1 1.5 0 0.199996 0.600004 +3.11 0.439993 0.788478 0.5 1 1.5 0 0.219996 0.560004 +3.12 0.479993 0.798719 0.5 1 1.5 0 0.239996 0.520004 +3.13 0.519993 0.798721 0.5 0 1.5 0 0.259996 0.480004 +3.14 0.559993 0.788482 0.5 0 1.5 0 0.279996 0.440004 +3.15 0.599993 0.768003 0.5 0 1.5 0 0.299996 0.400004 +3.16 0.639993 0.737284 0.5 0 1.5 0 0.319996 0.360004 +3.17 0.679993 0.696325 0.5 0 1.5 0 0.339996 0.320004 +3.18 0.719993 0.645126 0.5 0 1.5 0 0.359996 0.280004 +3.19 0.759993 0.583687 0.5 0 1.5 0 0.379996 0.240004 +3.2 0.799993 0.512008 0.5 0 1.5 0 0.399997 0.200004 +3.21 0.839993 0.430089 0.5 0 1.5 0 0.419997 0.160004 +3.22 0.879993 0.33793 0.5 0 1.5 0 0.439996 0.120004 +3.23 0.919993 0.235531 0.5 0 1.5 0 0.459996 0.0800042 +3.24 0.959993 0.122892 0.5 0 1.5 0 0.479996 0.0400041 +3.25 0.999993 1.31607e-05 0.5 1 1.5 0 0.499997 4.11272e-06 +3.26 0.960007 -0.122868 0.5 1 0.5 0 0.519997 -0.0399959 +3.27 0.920007 -0.235509 0.5 1 0.5 0 0.539997 -0.0799959 +3.28 0.880007 -0.33791 0.5 1 0.5 0 0.559996 -0.119996 +3.29 0.840007 -0.430071 0.5 1 0.5 0 0.579996 -0.159996 +3.3 0.800007 -0.511992 0.5 1 0.5 0 0.599996 -0.199996 +3.31 0.760007 -0.583673 0.5 1 0.5 0 0.619996 -0.239996 +3.32 0.720007 -0.645114 0.5 1 0.5 0 0.639996 -0.279996 +3.33 0.680007 -0.696315 0.5 1 0.5 0 0.659996 -0.319996 +3.34 0.640007 -0.737276 0.5 1 0.5 0 0.679996 -0.359996 +3.35 0.600007 -0.767997 0.5 1 0.5 0 0.699996 -0.399996 +3.36 0.560007 -0.788478 0.5 1 0.5 0 0.719996 -0.439996 +3.37 0.520007 -0.798719 0.5 1 0.5 0 0.739996 -0.479995 +3.38 0.480007 -0.798721 0.5 0 0.5 0 0.759996 -0.519995 +3.39 0.440007 -0.788482 0.5 0 0.5 0 0.779996 -0.559995 +3.4 0.400007 -0.768003 0.5 0 0.5 0 0.799996 -0.599995 +3.41 0.360008 -0.737284 0.5 0 0.5 0 0.819996 -0.639995 +3.42 0.320008 -0.696325 0.5 0 0.5 0 0.839996 -0.679995 +3.43 0.280008 -0.645127 0.5 0 0.5 0 0.859996 -0.719995 +3.44 0.240008 -0.583688 0.5 0 0.5 0 0.879996 -0.759995 +3.45 0.200008 -0.512009 0.5 0 0.5 0 0.899996 -0.799995 +3.46 0.160008 -0.430091 0.5 0 0.5 0 0.919996 -0.839995 +3.47 0.120008 -0.337932 0.5 0 0.5 0 0.939996 -0.879995 +3.48 0.0800078 -0.235533 0.5 0 0.5 0 0.959996 -0.919995 +3.49 0.0400078 -0.122895 0.5 0 0.5 0 0.979996 -0.959995 +3.5 7.86781e-06 -1.60216e-05 0.5 1 0.5 0 0.999996 -0.999995 +3.51 -0.0399921 0.122865 0.5 1 0.5 1 -0.980004 0.960005 +3.52 -0.0799921 0.235507 0.5 1 0.5 1 -0.960004 0.920005 +3.53 -0.119992 0.337908 0.5 1 0.5 1 -0.940004 0.880005 +3.54 -0.159992 0.430069 0.5 1 0.5 1 -0.920004 0.840005 +3.55 -0.199992 0.51199 0.5 1 0.5 1 -0.900004 0.800005 +3.56 -0.239992 0.583672 0.5 1 0.5 1 -0.880004 0.760005 +3.57 -0.279992 0.645113 0.5 1 0.5 0 -0.860004 0.720005 +3.58 -0.319992 0.696314 0.5 1 0.5 0 -0.840004 0.680005 +3.59 -0.359992 0.737275 0.5 1 0.5 0 -0.820004 0.640005 +3.6 -0.399992 0.767997 0.5 1 0.5 0 -0.800004 0.600005 +3.61 -0.439992 0.788478 0.5 1 0.5 0 -0.780004 0.560005 +3.62 -0.479992 0.798719 0.5 1 0.5 0 -0.760004 0.520005 +3.63 -0.519992 0.798721 0.5 0 0.5 0 -0.740004 0.480005 +3.64 -0.559992 0.788482 0.5 0 0.5 0 -0.720004 0.440005 +3.65 -0.599992 0.768003 0.5 0 0.5 0 -0.700004 0.400005 +3.66 -0.639992 0.737284 0.5 0 0.5 0 -0.680004 0.360005 +3.67 -0.679991 0.696326 0.5 0 0.5 0 -0.660004 0.320005 +3.68 -0.719991 0.645127 0.5 0 0.5 0 -0.640004 0.280005 +3.69 -0.759991 0.583688 0.5 0 0.5 0 -0.620004 0.240005 +3.7 -0.799991 0.512009 0.5 0 0.5 0 -0.600004 0.200005 +3.71 -0.839991 0.430091 0.5 0 0.5 0 -0.580004 0.160005 +3.72 -0.879991 0.337932 0.5 0 0.5 0 -0.560004 0.120005 +3.73 -0.919991 0.235533 0.5 0 0.5 0 -0.540004 0.0800049 +3.74 -0.959991 0.122894 0.5 0 0.5 0 -0.520004 0.0400048 +3.75 -0.999991 1.54495e-05 0.5 1 0.5 0 -0.500004 4.82798e-06 +3.76 -0.960009 -0.122866 0 1 0.5 0 -0.480004 -0.0399952 +3.77 -0.920009 -0.235507 0 1 0.5 0 -0.460004 -0.0799952 +3.78 -0.880009 -0.337908 0 1 0.5 0 -0.440004 -0.119995 +3.79 -0.840009 -0.430069 0 1 0.5 0 -0.420004 -0.159995 +3.8 -0.800009 -0.51199 0 1 0.5 0 -0.400004 -0.199995 +3.81 -0.760009 -0.583672 0 1 0.5 0 -0.380004 -0.239995 +3.82 -0.720009 -0.645113 0 1 0.5 0 -0.360004 -0.279995 +3.83 -0.680009 -0.696314 0 1 0.5 0 -0.340004 -0.319995 +3.84 -0.640009 -0.737275 0 1 0.5 0 -0.320004 -0.359995 +3.85 -0.600009 -0.767997 0 1 0.5 0 -0.300004 -0.399995 +3.86 -0.560009 -0.788478 0 1 0.5 0 -0.280005 -0.439995 +3.87 -0.520009 -0.798719 0 1 0.5 0 -0.260005 -0.479995 +3.88 -0.480009 -0.798721 0 0 0.5 0 -0.240005 -0.519995 +3.89 -0.440009 -0.788482 0 0 0.5 0 -0.220005 -0.559995 +3.9 -0.400009 -0.768003 0 0 0.5 0 -0.200005 -0.599995 +3.91 -0.360009 -0.737285 0 0 0.5 0 -0.180005 -0.639995 +3.92 -0.320009 -0.696326 0 0 0.5 0 -0.160005 -0.679995 +3.93 -0.28001 -0.645128 0 0 0.5 0 -0.140005 -0.719995 +3.94 -0.24001 -0.583689 0 0 0.5 0 -0.120005 -0.759995 +3.95 -0.20001 -0.512011 0 0 0.5 0 -0.100005 -0.799994 +3.96 -0.16001 -0.430092 0 0 0.5 0 -0.0800047 -0.839994 +3.97 -0.12001 -0.337934 0 0 0.5 0 -0.0600047 -0.879994 +3.98 -0.0800097 -0.235535 0 0 0.5 0 -0.0400047 -0.919994 +3.99 -0.0400097 -0.122897 0 0 0.5 0 -0.0200047 -0.959994 +4 -9.77516e-06 -1.83104e-05 0 1 0.5 0 -4.76837e-06 -0.999994 +4.01 0.0399904 0.122863 0.5 1 1.5 1 0.0199952 0.960006 +4.02 0.0799904 0.235505 0.5 1 1.5 1 0.0399952 0.920006 +4.03 0.11999 0.337906 0.5 1 1.5 1 0.0599952 0.880006 +4.04 0.15999 0.430068 0.5 1 1.5 1 0.0799952 0.840006 +4.05 0.19999 0.511989 0.5 1 1.5 1 0.0999953 0.800006 +4.06 0.23999 0.58367 0.5 1 1.5 1 0.119995 0.760006 +4.07 0.27999 0.645112 0.5 1 1.5 0 0.139995 0.720006 +4.08 0.31999 0.696313 0.5 1 1.5 0 0.159995 0.680006 +4.09 0.35999 0.737275 0.5 1 1.5 0 0.179995 0.640006 +4.1 0.39999 0.767996 0.5 1 1.5 0 0.199995 0.600006 +4.11 0.43999 0.788478 0.5 1 1.5 0 0.219995 0.560006 +4.12 0.47999 0.798719 0.5 1 1.5 0 0.239995 0.520006 +4.13 0.51999 0.798721 0.5 0 1.5 0 0.259995 0.480006 +4.14 0.55999 0.788482 0.5 0 1.5 0 0.279995 0.440006 +4.15 0.59999 0.768004 0.5 0 1.5 0 0.299995 0.400006 +4.16 0.63999 0.737285 0.5 0 1.5 0 0.319995 0.360006 +4.17 0.67999 0.696327 0.5 0 1.5 0 0.339995 0.320006 +4.18 0.71999 0.645128 0.5 0 1.5 0 0.359995 0.280006 +4.19 0.759991 0.583689 0.5 0 1.5 0 0.379995 0.240006 +4.2 0.799991 0.512011 0.5 0 1.5 0 0.399995 0.200006 +4.21 0.839991 0.430092 0.5 0 1.5 0 0.419995 0.160006 +4.22 0.879991 0.337934 0.5 0 1.5 0 0.439995 0.120006 +4.23 0.919991 0.235535 0.5 0 1.5 0 0.459995 0.0800056 +4.24 0.959991 0.122896 0.5 0 1.5 0 0.479995 0.0400056 +4.25 0.999991 1.77382e-05 0.5 1 1.5 0 0.499995 5.54323e-06 +4.26 0.960009 -0.122864 0.5 1 0.5 0 0.519995 -0.0399945 +4.27 0.920009 -0.235505 0.5 1 0.5 0 0.539995 -0.0799944 +4.28 0.880009 -0.337906 0.5 1 0.5 0 0.559995 -0.119994 +4.29 0.840009 -0.430068 0.5 1 0.5 0 0.579995 -0.159994 +4.3 0.800009 -0.511989 0.5 1 0.5 0 0.599995 -0.199994 +4.31 0.76001 -0.58367 0.5 1 0.5 0 0.619995 -0.239994 +4.32 0.72001 -0.645112 0.5 1 0.5 0 0.639995 -0.279994 +4.33 0.68001 -0.696313 0.5 1 0.5 0 0.659995 -0.319994 +4.34 0.64001 -0.737275 0.5 1 0.5 0 0.679995 -0.359994 +4.35 0.60001 -0.767996 0.5 1 0.5 0 0.699995 -0.399994 +4.36 0.56001 -0.788478 0.5 1 0.5 0 0.719995 -0.439994 +4.37 0.52001 -0.798719 0.5 1 0.5 0 0.739995 -0.479994 +4.38 0.48001 -0.798721 0.5 0 0.5 0 0.759995 -0.519994 +4.39 0.44001 -0.788482 0.5 0 0.5 0 0.779995 -0.559994 +4.4 0.40001 -0.768004 0.5 0 0.5 0 0.799995 -0.599994 +4.41 0.36001 -0.737285 0.5 0 0.5 0 0.819995 -0.639994 +4.42 0.32001 -0.696327 0.5 0 0.5 0 0.839995 -0.679994 +4.43 0.28001 -0.645129 0.5 0 0.5 0 0.859995 -0.719994 +4.44 0.24001 -0.58369 0.5 0 0.5 0 0.879995 -0.759994 +4.45 0.20001 -0.512012 0.5 0 0.5 0 0.899995 -0.799994 +4.46 0.16001 -0.430094 0.5 0 0.5 0 0.919995 -0.839994 +4.47 0.12001 -0.337935 0.5 0 0.5 0 0.939995 -0.879994 +4.48 0.0800102 -0.235537 0.5 0 0.5 0 0.959995 -0.919994 +4.49 0.0400102 -0.122899 0.5 0 0.5 0 0.979995 -0.959994 +4.5 1.0252e-05 -2.05992e-05 0.5 1 0.5 0 0.999995 -0.999994 +4.51 -0.0399897 0.122861 0.5 1 0.5 1 -0.980005 0.960006 +4.52 -0.0799897 0.235503 0.5 1 0.5 1 -0.960005 0.920006 +4.53 -0.11999 0.337904 0.5 1 0.5 1 -0.940005 0.880006 +4.54 -0.15999 0.430066 0.5 1 0.5 1 -0.920005 0.840006 +4.55 -0.19999 0.511988 0.5 1 0.5 1 -0.900005 0.800007 +4.56 -0.23999 0.583669 0.5 1 0.5 1 -0.880005 0.760006 +4.57 -0.279989 0.645111 0.5 1 0.5 0 -0.860005 0.720006 +4.58 -0.319989 0.696313 0.5 1 0.5 0 -0.840005 0.680007 +4.59 -0.359989 0.737274 0.5 1 0.5 0 -0.820005 0.640007 +4.6 -0.399989 0.767996 0.5 1 0.5 0 -0.800005 0.600007 +4.61 -0.439989 0.788477 0.5 1 0.5 0 -0.780005 0.560006 +4.62 -0.479989 0.798719 0.5 1 0.5 0 -0.760005 0.520007 +4.63 -0.519989 0.798721 0.5 0 0.5 0 -0.740005 0.480007 +4.64 -0.559989 0.788483 0.5 0 0.5 0 -0.720006 0.440006 +4.65 -0.599989 0.768004 0.5 0 0.5 0 -0.700006 0.400006 +4.66 -0.639989 0.737286 0.5 0 0.5 0 -0.680006 0.360006 +4.67 -0.679989 0.696327 0.5 0 0.5 0 -0.660006 0.320006 +4.68 -0.719989 0.645129 0.5 0 0.5 0 -0.640006 0.280006 +4.69 -0.759989 0.583691 0.5 0 0.5 0 -0.620006 0.240006 +4.7 -0.799989 0.512012 0.5 0 0.5 0 -0.600006 0.200006 +4.71 -0.839989 0.430094 0.5 0 0.5 0 -0.580006 0.160006 +4.72 -0.879989 0.337935 0.5 0 0.5 0 -0.560006 0.120006 +4.73 -0.919989 0.235537 0.5 0 0.5 0 -0.540006 0.0800063 +4.74 -0.959989 0.122898 0.5 0 0.5 0 -0.520006 0.0400063 +4.75 -0.999989 2.0027e-05 0.5 1 0.5 0 -0.500006 6.25849e-06 +4.76 -0.960011 -0.122862 0 1 0.5 0 -0.480006 -0.0399938 +4.77 -0.920011 -0.235503 0 1 0.5 0 -0.460006 -0.0799937 +4.78 -0.880011 -0.337905 0 1 0.5 0 -0.440006 -0.119994 +4.79 -0.840011 -0.430066 0 1 0.5 0 -0.420006 -0.159994 +4.8 -0.800011 -0.511988 0 1 0.5 0 -0.400006 -0.199994 +4.81 -0.760011 -0.583669 0 1 0.5 0 -0.380006 -0.239994 +4.82 -0.720011 -0.645111 0 1 0.5 0 -0.360006 -0.279994 +4.83 -0.680012 -0.696312 0 1 0.5 0 -0.340006 -0.319993 +4.84 -0.640012 -0.737274 0 1 0.5 0 -0.320006 -0.359993 +4.85 -0.600012 -0.767996 0 1 0.5 0 -0.300006 -0.399993 +4.86 -0.560012 -0.788477 0 1 0.5 0 -0.280006 -0.439993 +4.87 -0.520012 -0.798719 0 1 0.5 0 -0.260006 -0.479993 +4.88 -0.480012 -0.798721 0 0 0.5 0 -0.240006 -0.519993 +4.89 -0.440012 -0.788483 0 0 0.5 0 -0.220006 -0.559993 +4.9 -0.400012 -0.768004 0 0 0.5 0 -0.200006 -0.599993 +4.91 -0.360012 -0.737286 0 0 0.5 0 -0.180006 -0.639993 +4.92 -0.320012 -0.696328 0 0 0.5 0 -0.160006 -0.679993 +4.93 -0.280012 -0.64513 0 0 0.5 0 -0.140006 -0.719993 +4.94 -0.240012 -0.583692 0 0 0.5 0 -0.120006 -0.759993 +4.95 -0.200012 -0.512013 0 0 0.5 0 -0.100006 -0.799993 +4.96 -0.160012 -0.430095 0 0 0.5 0 -0.0800061 -0.839993 +4.97 -0.120012 -0.337937 0 0 0.5 0 -0.0600061 -0.879993 +4.98 -0.0800121 -0.235539 0 0 0.5 0 -0.0400062 -0.919993 +4.99 -0.0400121 -0.122901 0 0 0.5 0 -0.0200062 -0.959993 From 4ec9fd1f3d6a3213c3452bb5e04c0cecf77061b6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 14:12:56 +0100 Subject: [PATCH 178/668] Update README.md [ci skip] --- README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d55e2f0e..d155591e 100644 --- a/README.md +++ b/README.md @@ -42,21 +42,37 @@ The sfizz library makes primary use of: - [atomic_queue] by Maxim Egorushkin, licensed under the MIT license - [filesystem] by Steffen Schümann, licensed under the BSD 3-Clause license - [hiir] by Laurent de Soras, licensed under the WTFPL v2 license +- [KISS FFT] by Mark Borgerding, licensed under the BSD 3-Clause license +- [Surge tuning] by Paul Walker, licensed under the MIT license +- [pugixml] by Arseny Kapoulkine, licensed under the MIT license +- [cephes] by Stephen Moshier, licensed under the BSD 3-Clause license +- [cpuid] by Steinwurf ApS, licensed under the BSD 3-Clause license The sfizz library also uses in some subprojects: - [Catch2], licensed under the Boost Software License 1.0 - [benchmark], licensed under the Apache License 2.0 - [LV2], licensed under the ISC license - [JACK], licensed under the GNU Lesser General Public License v2.1 +- [cxxopts] by Jarryd Beck, licensed under the MIT license +- [fmidi] by Jean Pierre Cimalando, licensed under the Boost Software License 1.0 +- [libsamplerate], licensed under the BSD 2-Clause license -[Abseil]: https://github.com/abseil/abseil-cpp +[Abseil]: https://abseil.io/ [atomic_queue]: https://github.com/max0x7ba/atomic_queue [benchmark]: https://github.com/google/benchmark [Catch2]: https://github.com/catchorg/Catch2 [filesystem]: https://github.com/gulrak/filesystem +[Surge tuning]: https://surge-synth-team.org/tuning-library/ +[pugixml]: https://pugixml.org/ +[cephes]: https://www.netlib.org/cephes/ +[cpuid]: https://github.com/steinwurf/cpuid [hiir]: http://ldesoras.free.fr/prod.html#src_hiir +[KISS FFT]: http://kissfft.sourceforge.net/ [JACK]: https://github.com/jackaudio/jack2 -[libsndfile]: https://github.com/erikd/libsndfile/ +[cxxopts]: https://github.com/jarro2783/cxxopts +[fmidi]: https://github.com/jpcima/fmidi +[libsamplerate]: http://www.mega-nerd.com/SRC/ +[libsndfile]: http://www.mega-nerd.com/libsndfile/ [LV2]: https://lv2plug.in/ [our website]: https://sfz.tools/sfizz [releases]: https://github.com/sfztools/sfizz/releases From 519bcb2f7f56a19536ee5fd7bfdef85911e16f42 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 16:25:13 +0100 Subject: [PATCH 179/668] Avoid reloading invalid files in a loop --- src/sfizz/Synth.cpp | 68 ++++++++++++++++++++++++------------- src/sfizz/SynthPrivate.h | 6 ++-- src/sfizz/parser/Parser.cpp | 4 +-- src/sfizz/parser/Parser.h | 3 +- 4 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index f6362faa..0316b397 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -35,6 +35,9 @@ namespace sfz { +// unless set to permissive, the loader rejects sfz files with errors +static constexpr bool loaderParsesPermissively = true; + Synth::Synth() : impl_(new Impl) // NOLINT: (paul) I don't get why clang-tidy complains here { @@ -252,7 +255,7 @@ void Synth::Impl::clear() masterOpcodes_.clear(); groupOpcodes_.clear(); unknownOpcodes_.clear(); - modificationTime_ = fs::file_time_type::min(); + modificationTime_ = absl::nullopt; // set default controllers // midistate is reset above @@ -493,18 +496,22 @@ bool Synth::loadSfzFile(const fs::path& file) std::error_code ec; fs::path realFile = fs::canonical(file, ec); - impl.parser_.parseFile(ec ? file : realFile); + bool success = true; + Parser& parser = impl.parser_; + parser.parseFile(ec ? file : realFile); + // permissive parsing for compatibility - if (false) { - if (impl.parser_.getErrorCount() > 0) - return false; + if (!loaderParsesPermissively) + success = parser.getErrorCount() == 0; + + success = success && !impl.regions_.empty(); + + if (!success) { + parser.clear(); + return false; } - if (impl.regions_.empty()) - return false; - impl.finalizeSfzLoad(); - return true; } @@ -515,18 +522,22 @@ bool Synth::loadSfzString(const fs::path& path, absl::string_view text) impl.clear(); - impl.parser_.parseString(path, text); + bool success = true; + Parser& parser = impl.parser_; + parser.parseString(path, text); + // permissive parsing for compatibility - if (false) { - if (impl.parser_.getErrorCount() > 0) - return false; + if (!loaderParsesPermissively) + success = parser.getErrorCount() == 0; + + success = success && !impl.regions_.empty(); + + if (!success) { + parser.clear(); + return false; } - if (impl.regions_.empty()) - return false; - impl.finalizeSfzLoad(); - return true; } @@ -1668,22 +1679,33 @@ void Synth::Impl::resetAllControllers(int delay) noexcept } } -fs::file_time_type Synth::Impl::checkModificationTime() +absl::optional Synth::Impl::checkModificationTime() const { - auto returnedTime = modificationTime_; + absl::optional resultTime; for (const auto& file : parser_.getIncludedFiles()) { std::error_code ec; const auto fileTime = fs::last_write_time(file, ec); - if (!ec && returnedTime < fileTime) - returnedTime = fileTime; + if (!ec) { + if (!resultTime || fileTime > *resultTime) + resultTime = fileTime; + } } - return returnedTime; + return resultTime; } bool Synth::shouldReloadFile() { Impl& impl = *impl_; - return (impl.checkModificationTime() > impl.modificationTime_); + + absl::optional then = impl.modificationTime_; + if (!then) // file not loaded or failed + return false; + + absl::optional now = impl.checkModificationTime(); + if (!now) // file not currently existing + return false; + + return *now > *then; } bool Synth::shouldReloadScala() diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index bcc48e24..488979be 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -110,9 +110,9 @@ struct Synth::Impl final: public Parser::Listener { /** * @brief Get the modification time of all included sfz files * - * @return fs::file_time_type + * @return absl::optional */ - fs::file_time_type checkModificationTime(); + absl::optional checkModificationTime() const; /** * @brief Check all regions and start voices for note on events @@ -277,7 +277,7 @@ struct Synth::Impl final: public Parser::Listener { std::chrono::time_point lastGarbageCollection_; Parser parser_; - fs::file_time_type modificationTime_ { }; + absl::optional modificationTime_ { }; std::array defaultCCValues_; std::bitset currentUsedCCs_; diff --git a/src/sfizz/parser/Parser.cpp b/src/sfizz/parser/Parser.cpp index 9ed460c2..ba35fc96 100644 --- a/src/sfizz/parser/Parser.cpp +++ b/src/sfizz/parser/Parser.cpp @@ -19,7 +19,7 @@ Parser::~Parser() { } -void Parser::reset() +void Parser::clear() { _pathsIncluded.clear(); _currentDefinitions = _externalDefinitions; @@ -51,7 +51,7 @@ void Parser::parseString(const fs::path& path, absl::string_view sfzView) void Parser::parseVirtualFile(const fs::path& path, std::unique_ptr reader) { - reset(); + clear(); if (_listener) _listener->onParseBegin(); diff --git a/src/sfizz/parser/Parser.h b/src/sfizz/parser/Parser.h index 827de0c6..1be51361 100644 --- a/src/sfizz/parser/Parser.h +++ b/src/sfizz/parser/Parser.h @@ -27,6 +27,8 @@ public: Parser(); ~Parser(); + void clear(); + void addExternalDefinition(absl::string_view id, absl::string_view value); void clearExternalDefinitions(); @@ -71,7 +73,6 @@ private: void processDirective(); void processHeader(); void processOpcode(); - void reset(); // errors and warnings void emitError(const SourceRange& range, const std::string& message); From 49721cbf1784cf374211eb3ebfa6b18a80392499 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 17:04:50 +0100 Subject: [PATCH 180/668] Allow the build to pass in some Linux x86 --- src/sfizz/Messaging.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sfizz/Messaging.cpp b/src/sfizz/Messaging.cpp index f8d1d731..17d63081 100644 --- a/src/sfizz/Messaging.cpp +++ b/src/sfizz/Messaging.cpp @@ -10,11 +10,11 @@ #include #include -#ifdef __cplusplus +// ensure that `sfizz_arg_t` has the same storage characteristics as `int64_t` static_assert( - sizeof(sfizz_arg_t) == sizeof(int64_t) && alignof(sfizz_arg_t) == 8, + sizeof(sfizz_arg_t) == sizeof(int64_t) && + alignof(sfizz_arg_t) == alignof(int64_t), "The ABI stability check has failed."); -#endif template static T paddingSize(T count, unsigned align) { From 56dcb6de4bf5dcd3f801559351c1a2d39c2bab3c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 17:56:48 +0100 Subject: [PATCH 181/668] Ignore the alignment check for sfizz_arg_t, fails on old gcc 32bit --- src/sfizz/Messaging.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sfizz/Messaging.cpp b/src/sfizz/Messaging.cpp index 17d63081..cc5e3ea9 100644 --- a/src/sfizz/Messaging.cpp +++ b/src/sfizz/Messaging.cpp @@ -11,9 +11,10 @@ #include // ensure that `sfizz_arg_t` has the same storage characteristics as `int64_t` +// Note(jpc) alignment checks fail on old gcc i386 static_assert( - sizeof(sfizz_arg_t) == sizeof(int64_t) && - alignof(sfizz_arg_t) == alignof(int64_t), + sizeof(sfizz_arg_t) == sizeof(int64_t) /* && + alignof(sfizz_arg_t) == alignof(int64_t) */, "The ABI stability check has failed."); template From 00f2e7e2618b4eae1e90ded7d8eaa36e8258a758 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 18:22:10 +0100 Subject: [PATCH 182/668] Remove unneeded includes --- src/sfizz/EQPool.h | 2 -- src/sfizz/FilterPool.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/sfizz/EQPool.h b/src/sfizz/EQPool.h index 30ce889a..4670daac 100644 --- a/src/sfizz/EQPool.h +++ b/src/sfizz/EQPool.h @@ -2,10 +2,8 @@ #include "SfzFilter.h" #include "Region.h" #include "Resources.h" -#include "utility/SpinMutex.h" #include #include -#include namespace sfz { diff --git a/src/sfizz/FilterPool.h b/src/sfizz/FilterPool.h index 76074a0c..d995e0db 100644 --- a/src/sfizz/FilterPool.h +++ b/src/sfizz/FilterPool.h @@ -3,10 +3,8 @@ #include "Region.h" #include "Resources.h" #include "Defaults.h" -#include "utility/SpinMutex.h" #include #include -#include namespace sfz { From 53fc2a03fa8ee0b54bd6a3676e8bb7087bb530fa Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Feb 2021 12:28:32 +0100 Subject: [PATCH 183/668] Fix voice groups destroyed after polyphony changed --- src/sfizz/PolyphonyGroup.cpp | 5 +++++ src/sfizz/PolyphonyGroup.h | 4 ++++ src/sfizz/VoiceManager.cpp | 27 +++++++++++++++++---------- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/sfizz/PolyphonyGroup.cpp b/src/sfizz/PolyphonyGroup.cpp index d5b1615c..18b7a34f 100644 --- a/src/sfizz/PolyphonyGroup.cpp +++ b/src/sfizz/PolyphonyGroup.cpp @@ -17,6 +17,11 @@ void sfz::PolyphonyGroup::removeVoice(const Voice* voice) noexcept swapAndPopFirst(voices, [voice](const Voice* v) { return v == voice; }); } +void sfz::PolyphonyGroup::removeAllVoices() noexcept +{ + voices.clear(); +} + unsigned sfz::PolyphonyGroup::numPlayingVoices() const noexcept { return absl::c_count_if(voices, [](const Voice* v) { diff --git a/src/sfizz/PolyphonyGroup.h b/src/sfizz/PolyphonyGroup.h index f3d47257..6a87d05f 100644 --- a/src/sfizz/PolyphonyGroup.h +++ b/src/sfizz/PolyphonyGroup.h @@ -35,6 +35,10 @@ public: * @param voice */ void removeVoice(const Voice* voice) noexcept; + /** + * @brief Remove all the voices from this polyphony group. + */ + void removeAllVoices() noexcept; /** * @brief Get the polyphony limit for this group * diff --git a/src/sfizz/VoiceManager.cpp b/src/sfizz/VoiceManager.cpp index f8bf71f8..b4d93e13 100644 --- a/src/sfizz/VoiceManager.cpp +++ b/src/sfizz/VoiceManager.cpp @@ -13,17 +13,22 @@ namespace sfz { void VoiceManager::onVoiceStateChanging(NumericId id, Voice::State state) { - (void)id; if (state == Voice::State::idle) { - auto voice = getVoiceById(id); - RegionSet::removeVoiceFromHierarchy(voice->getRegion(), voice); + Voice* voice = getVoiceById(id); + const Region* region = voice->getRegion(); + const uint32_t group = region->group; + RegionSet::removeVoiceFromHierarchy(region, voice); swapAndPopFirst(activeVoices_, [voice](const Voice* v) { return v == voice; }); - polyphonyGroups_[voice->getRegion()->group].removeVoice(voice); + ASSERT(group < polyphonyGroups_.size()); + polyphonyGroups_[group].removeVoice(voice); } else if (state == Voice::State::playing) { - auto voice = getVoiceById(id); + Voice* voice = getVoiceById(id); + const Region* region = voice->getRegion(); + const uint32_t group = region->group; activeVoices_.push_back(voice); - RegionSet::registerVoiceInHierarchy(voice->getRegion(), voice); - polyphonyGroups_[voice->getRegion()->group].registerVoice(voice); + RegionSet::registerVoiceInHierarchy(region, voice); + ASSERT(group < polyphonyGroups_.size()); + polyphonyGroups_[group].registerVoice(voice); } } @@ -81,8 +86,9 @@ bool VoiceManager::playingAttackVoice(const Region* releaseRegion) noexcept void VoiceManager::ensureNumPolyphonyGroups(unsigned groupIdx) noexcept { - while (polyphonyGroups_.size() <= groupIdx) - polyphonyGroups_.emplace_back(); + size_t neededSize = static_cast(groupIdx) + 1; + if (polyphonyGroups_.size() < neededSize) + polyphonyGroups_.resize(neededSize); } void VoiceManager::setGroupPolyphony(unsigned groupIdx, unsigned polyphony) noexcept @@ -99,7 +105,8 @@ const PolyphonyGroup* VoiceManager::getPolyphonyGroupView(int idx) const noexcep void VoiceManager::clear() { - reset(); + for (PolyphonyGroup& pg : polyphonyGroups_) + pg.removeAllVoices(); list_.clear(); activeVoices_.clear(); } From 7d0347263d6e91acf3610e98a297f3743047187d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Feb 2021 14:09:35 +0100 Subject: [PATCH 184/668] Fix a variety of xrun situations --- src/sfizz/Config.h | 11 +++++++++++ src/sfizz/PolyphonyGroup.cpp | 6 +++++- src/sfizz/PolyphonyGroup.h | 2 ++ src/sfizz/RegionSet.cpp | 9 ++++++++- src/sfizz/RegionSet.h | 7 +------ src/sfizz/Voice.cpp | 2 +- src/sfizz/VoiceManager.cpp | 9 ++++----- src/sfizz/VoiceManager.h | 2 +- 8 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 2a597c67..451a5bcc 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -139,6 +139,17 @@ namespace config { */ static constexpr float overflowVoiceMultiplier { 1.5f }; static_assert(overflowVoiceMultiplier >= 1.0f, "This needs to add voices"); + + /** + * @brief Calculate the effective voice number for the polyphony setting, + * accounting for the overflow factor. + */ + inline constexpr int calculateActualVoices(int polyphony) + { + return + (int(polyphony * config::overflowVoiceMultiplier) < int(config::maxVoices)) ? + int(polyphony * config::overflowVoiceMultiplier) : int(config::maxVoices); + } } // namespace config } // namespace sfz diff --git a/src/sfizz/PolyphonyGroup.cpp b/src/sfizz/PolyphonyGroup.cpp index 18b7a34f..dcb608f8 100644 --- a/src/sfizz/PolyphonyGroup.cpp +++ b/src/sfizz/PolyphonyGroup.cpp @@ -1,9 +1,13 @@ #include "PolyphonyGroup.h" +sfz::PolyphonyGroup::PolyphonyGroup() +{ + voices.reserve(config::maxVoices); +} + void sfz::PolyphonyGroup::setPolyphonyLimit(unsigned limit) noexcept { polyphonyLimit = limit; - voices.reserve(limit); } void sfz::PolyphonyGroup::registerVoice(Voice* voice) noexcept diff --git a/src/sfizz/PolyphonyGroup.h b/src/sfizz/PolyphonyGroup.h index 6a87d05f..015c3a75 100644 --- a/src/sfizz/PolyphonyGroup.h +++ b/src/sfizz/PolyphonyGroup.h @@ -16,6 +16,8 @@ namespace sfz { class PolyphonyGroup { public: + PolyphonyGroup(); + /** * @brief Set the polyphony limit for this polyphony group. * diff --git a/src/sfizz/RegionSet.cpp b/src/sfizz/RegionSet.cpp index bfceb4e2..dfd85872 100644 --- a/src/sfizz/RegionSet.cpp +++ b/src/sfizz/RegionSet.cpp @@ -1,9 +1,16 @@ #include "RegionSet.h" +sfz::RegionSet::RegionSet(RegionSet* parentSet, OpcodeScope level) + : parent(parentSet), level(level) +{ + voices.reserve(config::maxVoices); + if (parentSet != nullptr) + parentSet->addSubset(this); +} + void sfz::RegionSet::setPolyphonyLimit(unsigned limit) noexcept { polyphonyLimit = limit; - voices.reserve(limit); } void sfz::RegionSet::addRegion(Region* region) noexcept diff --git a/src/sfizz/RegionSet.h b/src/sfizz/RegionSet.h index 4077fbe7..66b11d2f 100644 --- a/src/sfizz/RegionSet.h +++ b/src/sfizz/RegionSet.h @@ -18,12 +18,7 @@ namespace sfz class RegionSet { public: RegionSet() = delete; - RegionSet(RegionSet* parentSet, OpcodeScope level) - : parent(parentSet), level(level) - { - if (parentSet != nullptr) - parentSet->addSubset(this); - } + RegionSet(RegionSet* parentSet, OpcodeScope level); /** * @brief Set the polyphony limit for the set * diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index cdad7af7..084d4a81 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1645,7 +1645,7 @@ void Voice::Impl::pitchEnvelope(absl::Span pitchSpan) noexcept if (!bends) return; - const auto events = resources_.midiState.getPitchEvents(); + const EventVector& events = resources_.midiState.getPitchEvents(); const auto bendLambda = [this](float bend) { return centsFactor(region_->getBendInCents(bend)); }; diff --git a/src/sfizz/VoiceManager.cpp b/src/sfizz/VoiceManager.cpp index b4d93e13..490927b2 100644 --- a/src/sfizz/VoiceManager.cpp +++ b/src/sfizz/VoiceManager.cpp @@ -159,15 +159,14 @@ Voice* VoiceManager::findFreeVoice() noexcept void VoiceManager::requireNumVoices(int numVoices, Resources& resources) { - numActualVoices_ = - static_cast(config::overflowVoiceMultiplier * numVoices); numRequiredVoices_ = numVoices; + const int numEffectiveVoices = getNumEffectiveVoices(); clear(); - list_.reserve(numActualVoices_); - activeVoices_.reserve(numActualVoices_); + list_.reserve(numEffectiveVoices); + activeVoices_.reserve(numEffectiveVoices); - for (int i = 0; i < numActualVoices_; ++i) { + for (int i = 0; i < numEffectiveVoices; ++i) { list_.emplace_back(i, resources); Voice& lastVoice = list_.back(); lastVoice.setStateListener(this); diff --git a/src/sfizz/VoiceManager.h b/src/sfizz/VoiceManager.h index 627fd600..e924ae96 100644 --- a/src/sfizz/VoiceManager.h +++ b/src/sfizz/VoiceManager.h @@ -133,7 +133,7 @@ struct VoiceManager final : public Voice::StateListener private: int numRequiredVoices_ { config::numVoices }; - int numActualVoices_ { static_cast(config::numVoices * config::overflowVoiceMultiplier) }; + int getNumEffectiveVoices() const noexcept { return config::calculateActualVoices(numRequiredVoices_); } std::vector list_; std::vector activeVoices_; // These are the `group=` groups where you can off voices From 8b8caf49376e92bd4ce873a4f6c460f8203121c7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 21:08:57 +0100 Subject: [PATCH 185/668] Remove callback guard where useless --- src/sfizz/Synth.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 0316b397..71bdd49d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -54,7 +54,6 @@ Synth::Impl::Impl() initializeSIMDDispatchers(); initializeInterpolators(); - const std::lock_guard disableCallback { callbackGuard_ }; parser_.setListener(this); effectFactory_.registerStandardEffectTypes(); effectBuses_.reserve(5); // sufficient room for main and fx1-4 @@ -69,8 +68,6 @@ Synth::Impl::Impl() Synth::Impl::~Impl() { - const std::lock_guard disableCallback { callbackGuard_ }; - voiceManager_.reset(); resources_.filePool.emptyFileLoadingQueues(); } From e178ae25e6e7456370ddd87e91afd2af1e210964 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 21:29:12 +0100 Subject: [PATCH 186/668] Remove all callback guards --- src/sfizz/Synth.cpp | 32 -------------------------------- src/sfizz/SynthPrivate.h | 2 -- 2 files changed, 34 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 71bdd49d..2a12f683 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -18,7 +18,6 @@ #include "Resources.h" #include "ScopedFTZ.h" #include "StringViewHelpers.h" -#include "utility/SpinMutex.h" #include "utility/XmlHelpers.h" #include "Voice.h" #include "Interpolators.h" @@ -486,7 +485,6 @@ void Synth::Impl::handleEffectOpcodes(const std::vector& rawMembers) bool Synth::loadSfzFile(const fs::path& file) { Impl& impl = *impl_; - const std::lock_guard disableCallback { impl.callbackGuard_ }; impl.clear(); @@ -515,7 +513,6 @@ bool Synth::loadSfzFile(const fs::path& file) bool Synth::loadSfzString(const fs::path& path, absl::string_view text) { Impl& impl = *impl_; - const std::lock_guard disableCallback { impl.callbackGuard_ }; impl.clear(); @@ -805,8 +802,6 @@ void Synth::setSamplesPerBlock(int samplesPerBlock) noexcept Impl& impl = *impl_; ASSERT(samplesPerBlock <= config::maxBlockSize); - const std::lock_guard disableCallback { impl.callbackGuard_ }; - impl.samplesPerBlock_ = samplesPerBlock; for (auto& voice : impl.voiceManager_) voice.setSamplesPerBlock(samplesPerBlock); @@ -828,7 +823,6 @@ int Synth::getSamplesPerBlock() const noexcept void Synth::setSampleRate(float sampleRate) noexcept { Impl& impl = *impl_; - const std::lock_guard disableCallback { impl.callbackGuard_ }; impl.sampleRate_ = sampleRate; for (auto& voice : impl.voiceManager_) @@ -865,10 +859,6 @@ void Synth::renderBlock(AudioSpan buffer) noexcept impl.resources_.filePool.triggerGarbageCollection(); } - const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; - if (!lock.owns_lock()) - return; - size_t numFrames = buffer.getNumFrames(); auto tempSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames); auto tempMixSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames); @@ -986,11 +976,6 @@ void Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept const auto normalizedVelocity = normalizeVelocity(velocity); ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; impl.resources_.midiState.noteOnEvent(delay, noteNumber, normalizedVelocity); - - const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; - if (!lock.owns_lock()) - return; - impl.noteOnDispatch(delay, noteNumber, normalizedVelocity); } @@ -1004,10 +989,6 @@ void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; impl.resources_.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); - const std::unique_lock lock { impl.callbackGuard_, std::try_to_lock }; - if (!lock.owns_lock()) - return; - // FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a // way in sfz to specify that a release trigger should NOT use the note-on velocity? // auto replacedVelocity = (velocity == 0 ? getNoteVelocity(noteNumber) : velocity); @@ -1148,10 +1129,6 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM ScopedTiming logger { dispatchDuration_, ScopedTiming::Operation::addToDuration }; resources_.midiState.ccEvent(delay, ccNumber, normValue); - const std::unique_lock lock { callbackGuard_, std::try_to_lock }; - if (!lock.owns_lock()) - return; - if (asMidi) { if (ccNumber == config::resetCC) { resetAllControllers(delay); @@ -1492,7 +1469,6 @@ void Synth::setNumVoices(int numVoices) noexcept { ASSERT(numVoices > 0); Impl& impl = *impl_; - const std::lock_guard disableCallback { impl.callbackGuard_ }; // fast path if (numVoices == impl.numVoices_) @@ -1601,7 +1577,6 @@ void Synth::Impl::setupModMatrix() void Synth::setOversamplingFactor(Oversampling factor) noexcept { Impl& impl = *impl_; - const std::lock_guard disableCallback { impl.callbackGuard_ }; // fast path if (factor == impl.oversamplingFactor_) @@ -1624,7 +1599,6 @@ Oversampling Synth::getOversamplingFactor() const noexcept void Synth::setPreloadSize(uint32_t preloadSize) noexcept { Impl& impl = *impl_; - const std::lock_guard disableCallback { impl.callbackGuard_ }; // fast path if (preloadSize == impl.resources_.filePool.getPreloadSize()) @@ -1660,10 +1634,6 @@ void Synth::Impl::resetAllControllers(int delay) noexcept { resources_.midiState.resetAllControllers(delay); - const std::unique_lock lock { callbackGuard_, std::try_to_lock }; - if (!lock.owns_lock()) - return; - for (auto& voice : voiceManager_) { voice.registerPitchWheel(delay, 0); for (int cc = 0; cc < config::numCCs; ++cc) @@ -1732,8 +1702,6 @@ void Synth::disableLogging() noexcept void Synth::allSoundOff() noexcept { Impl& impl = *impl_; - const std::lock_guard disableCallback { impl.callbackGuard_ }; - for (auto& voice : impl.voiceManager_) voice.reset(); for (auto& effectBus : impl.effectBuses_) diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 488979be..42063ed0 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -246,8 +246,6 @@ struct Synth::Impl final: public Parser::Listener { // Distribution used to generate random value for the *rand opcodes std::uniform_real_distribution randNoteDistribution_ { 0, 1 }; - SpinMutex callbackGuard_; - // Singletons passed as references to the voices Resources resources_; From c110acc966258ceffe5937ca669ed0b87173f306 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 22:04:02 +0100 Subject: [PATCH 187/668] Provide the spin mutex as internal library --- common.mk | 6 ++- src/CMakeLists.txt | 14 +++++-- src/sfizz/FilePool.h | 3 +- .../utility/{ => spin_mutex}/SpinMutex.cpp | 0 .../utility/{ => spin_mutex}/SpinMutex.h | 0 src/sfizz/utility/spin_mutex/spin_mutex.cpp | 37 +++++++++++++++++++ src/sfizz/utility/spin_mutex/spin_mutex.h | 24 ++++++++++++ tests/CMakeLists.txt | 2 +- tests/ConcurrencyT.cpp | 2 +- 9 files changed, 79 insertions(+), 9 deletions(-) rename src/sfizz/utility/{ => spin_mutex}/SpinMutex.cpp (100%) rename src/sfizz/utility/{ => spin_mutex}/SpinMutex.h (100%) create mode 100644 src/sfizz/utility/spin_mutex/spin_mutex.cpp create mode 100644 src/sfizz/utility/spin_mutex/spin_mutex.h diff --git a/common.mk b/common.mk index 4efdbc57..5c7cf10f 100644 --- a/common.mk +++ b/common.mk @@ -117,7 +117,7 @@ SFIZZ_SOURCES = \ src/sfizz/Synth.cpp \ src/sfizz/SynthMessaging.cpp \ src/sfizz/Tuning.cpp \ - src/sfizz/utility/SpinMutex.cpp \ + src/sfizz/utility/spin_mutex/SpinMutex.cpp \ src/sfizz/Voice.cpp \ src/sfizz/VoiceManager.cpp \ src/sfizz/VoiceStealing.cpp \ @@ -126,7 +126,9 @@ SFIZZ_SOURCES = \ ### Other internal -SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/src/sfizz +SFIZZ_C_FLAGS += \ + -I$(SFIZZ_DIR)/src/sfizz \ + -I$(SFIZZ_DIR)/src/sfizz/utility/spin_mutex # Pkg-config dependency diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6786663e..2a574522 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,7 +26,6 @@ set(SFIZZ_HEADERS sfizz/Curve.h sfizz/Debug.h sfizz/utility/NumericId.h - sfizz/utility/SpinMutex.h sfizz/utility/XmlHelpers.h sfizz/modulations/ModId.h sfizz/modulations/ModKey.h @@ -163,7 +162,6 @@ set(SFIZZ_SOURCES sfizz/modulations/sources/FlexEnvelope.cpp sfizz/modulations/sources/ADSREnvelope.cpp sfizz/modulations/sources/LFO.cpp - sfizz/utility/SpinMutex.cpp sfizz/effects/Nothing.cpp sfizz/effects/Filter.cpp sfizz/effects/Eq.cpp @@ -239,13 +237,23 @@ target_sources(sfizz_messaging PRIVATE target_include_directories(sfizz_messaging PUBLIC ".") target_link_libraries(sfizz_messaging PUBLIC absl::strings) +# Sfizz spinlock mutex +add_library(sfizz_spin_mutex STATIC + sfizz/utility/spin_mutex/spin_mutex.h + sfizz/utility/spin_mutex/spin_mutex.cpp + sfizz/utility/spin_mutex/SpinMutex.h + sfizz/utility/spin_mutex/SpinMutex.cpp) +target_include_directories(sfizz_spin_mutex PUBLIC sfizz/utility/spin_mutex) +target_link_libraries(sfizz_spin_mutex PRIVATE sfizz::atomic_queue) +add_library(sfizz::spin_mutex ALIAS sfizz_spin_mutex) + # Sfizz internals (use this for testing) add_library(sfizz_internal STATIC) add_library(sfizz::internal ALIAS sfizz_internal) target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES}) target_include_directories(sfizz_internal PUBLIC "." "sfizz") target_link_libraries(sfizz_internal - PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue + PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 7f8be842..fa67db72 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -33,7 +33,7 @@ #include "FileId.h" #include "FileMetadata.h" #include "SIMDHelpers.h" -#include "utility/SpinMutex.h" +#include #include "ghc/fs_std.hpp" #include #include @@ -43,7 +43,6 @@ #include #include #include -#include "utility/SpinMutex.h" class ThreadPool; namespace sfz { diff --git a/src/sfizz/utility/SpinMutex.cpp b/src/sfizz/utility/spin_mutex/SpinMutex.cpp similarity index 100% rename from src/sfizz/utility/SpinMutex.cpp rename to src/sfizz/utility/spin_mutex/SpinMutex.cpp diff --git a/src/sfizz/utility/SpinMutex.h b/src/sfizz/utility/spin_mutex/SpinMutex.h similarity index 100% rename from src/sfizz/utility/SpinMutex.h rename to src/sfizz/utility/spin_mutex/SpinMutex.h diff --git a/src/sfizz/utility/spin_mutex/spin_mutex.cpp b/src/sfizz/utility/spin_mutex/spin_mutex.cpp new file mode 100644 index 00000000..af786711 --- /dev/null +++ b/src/sfizz/utility/spin_mutex/spin_mutex.cpp @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "spin_mutex.h" +#include "SpinMutex.h" + +struct spin_mutex_ { + SpinMutex mtx; +}; + +spin_mutex_t* spin_mutex_create() +{ + return new spin_mutex_t; +} + +void spin_mutex_destroy(spin_mutex_t* mtx) +{ + delete mtx; +} + +void spin_mutex_lock(spin_mutex_t* mtx) +{ + mtx->mtx.lock(); +} + +void spin_mutex_unlock(spin_mutex_t* mtx) +{ + mtx->mtx.unlock(); +} + +bool spin_mutex_trylock(spin_mutex_t* mtx) +{ + return mtx->mtx.try_lock(); +} diff --git a/src/sfizz/utility/spin_mutex/spin_mutex.h b/src/sfizz/utility/spin_mutex/spin_mutex.h new file mode 100644 index 00000000..63c9053f --- /dev/null +++ b/src/sfizz/utility/spin_mutex/spin_mutex.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef struct spin_mutex_ spin_mutex_t; + +spin_mutex_t* spin_mutex_create(); +void spin_mutex_destroy(spin_mutex_t* mtx); +void spin_mutex_lock(spin_mutex_t* mtx); +void spin_mutex_unlock(spin_mutex_t* mtx); +bool spin_mutex_trylock(spin_mutex_t* mtx); + +#if defined(__cplusplus) +} // extern "C" +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 15c1d0d6..6e28170f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -46,7 +46,7 @@ set(SFIZZ_TEST_SOURCES ) add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES}) -target_link_libraries(sfizz_tests PRIVATE sfizz::internal sfizz::jsl) +target_link_libraries(sfizz_tests PRIVATE sfizz::internal sfizz::spin_mutex sfizz::jsl) sfizz_enable_lto_if_needed(sfizz_tests) sfizz_enable_fast_math(sfizz_tests) diff --git a/tests/ConcurrencyT.cpp b/tests/ConcurrencyT.cpp index 9ec72cd5..f82e20bd 100644 --- a/tests/ConcurrencyT.cpp +++ b/tests/ConcurrencyT.cpp @@ -4,8 +4,8 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "sfizz/utility/SpinMutex.h" #include "catch2/catch.hpp" +#include #include #include #include From 1d6b06aa2e66f4c4bd6afa9abc0c2ddc67d5d061 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 22:46:02 +0100 Subject: [PATCH 188/668] Thread-safety at LV2 level --- lv2/CMakeLists.txt | 8 +++--- lv2/sfizz.c | 64 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index c5a4e861..d247dd14 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -22,25 +22,25 @@ add_library(${LV2PLUGIN_PRJ_NAME} MODULE ${PROJECT_NAME}.c atomic_compat.h ${LV2PLUGIN_TTL_SRC_FILES}) -target_link_libraries(${LV2PLUGIN_PRJ_NAME} ${PROJECT_NAME}::${PROJECT_NAME}) +target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::spin_mutex) if(SFIZZ_LV2_UI) add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE ${PROJECT_NAME}_ui.cpp vstgui_helpers.h vstgui_helpers.cpp) - target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui sfizz::editor sfizz::vstgui) + target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE sfizz::editor sfizz::vstgui) endif() # Explicitely strip all symbols on Linux but lv2_descriptor() # MacOS linker does not support this apparently https://bugs.webkit.org/show_bug.cgi?id=144555 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") file(COPY lv2.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) - target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,--version-script=lv2.version") + target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE "-Wl,--version-script=lv2.version") # target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,-u,lv2_descriptor") if(SFIZZ_LV2_UI) file(COPY lv2ui.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) - target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,--version-script=lv2ui.version") + target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE "-Wl,--version-script=lv2ui.version") # target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,-u,lv2ui_descriptor") endif() endif() diff --git a/lv2/sfizz.c b/lv2/sfizz.c index 57d80846..115fea48 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -53,6 +53,8 @@ #include +#include + #include #include #include @@ -160,6 +162,7 @@ typedef struct // Sfizz related data sfizz_synth_t *synth; sfizz_client_t *client; + spin_mutex_t *synth_mutex; bool expect_nominal_block_length; char sfz_file_path[MAX_PATH_SIZE]; char scala_file_path[MAX_PATH_SIZE]; @@ -599,6 +602,7 @@ instantiate(const LV2_Descriptor *descriptor, self->synth = sfizz_create_synth(); self->client = sfizz_create_client(self); + self->synth_mutex = spin_mutex_create(); sfizz_set_broadcast_callback(self->synth, &sfizz_lv2_receive_message, self); sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message); @@ -617,6 +621,7 @@ static void cleanup(LV2_Handle instance) { sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + spin_mutex_destroy(self->synth_mutex); sfizz_delete_client(self->client); sfizz_free(self->synth); free(self); @@ -876,8 +881,14 @@ static void run(LV2_Handle instance, uint32_t sample_count) { sfizz_plugin_t *self = (sfizz_plugin_t *)instance; - if (!self->control_port || !self->notify_port) + assert(self->control_port && self->notify_port); + + if (!spin_mutex_trylock(self->synth_mutex)) + { + for (int channel = 0; channel < 2; ++channel) + memset(self->output_buffers[channel], 0, sample_count * sizeof(float)); return; + } // Set up forge to write directly to notify output port. const size_t notify_capacity = self->notify_port->atom.size; @@ -1048,6 +1059,8 @@ run(LV2_Handle instance, uint32_t sample_count) // Render the block sfizz_render_block(self->synth, self->output_buffers, 2, (int)sample_count); + spin_mutex_unlock(self->synth_mutex); + if (self->midnam && atomic_exchange(&self->must_update_midnam, 0)) { self->midnam->update(self->midnam->handle); @@ -1099,7 +1112,9 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options) if (opt->key == self->sample_rate_uri) { sfizz_lv2_parse_sample_rate(self, opt); + spin_mutex_lock(self->synth_mutex); sfizz_set_sample_rate(self->synth, self->sample_rate); + spin_mutex_unlock(self->synth_mutex); } else if (!self->expect_nominal_block_length && opt->key == self->max_block_length_uri) { @@ -1109,7 +1124,9 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options) continue; } self->max_block_size = *(int *)opt->value; + spin_mutex_lock(self->synth_mutex); sfizz_set_samples_per_block(self->synth, self->max_block_size); + spin_mutex_unlock(self->synth_mutex); } else if (opt->key == self->nominal_block_length_uri) { @@ -1119,7 +1136,9 @@ lv2_set_options(LV2_Handle instance, const LV2_Options_Option *options) continue; } self->max_block_size = *(int *)opt->value; + spin_mutex_lock(self->synth_mutex); sfizz_set_samples_per_block(self->synth, self->max_block_size); + spin_mutex_unlock(self->synth_mutex); } } return LV2_OPTIONS_SUCCESS; @@ -1263,6 +1282,7 @@ restore(LV2_Handle instance, } // Sync the parameters to the synth + spin_mutex_lock(self->synth_mutex); // Load an empty file to remove the default sine, and then the new file. sfizz_load_string(self->synth, "empty.sfz", ""); @@ -1299,6 +1319,8 @@ restore(LV2_Handle instance, lv2_log_note(&self->logger, "[sfizz] Restoring the oversampling to %d\n", self->oversampling); sfizz_set_oversampling_factor(self->synth, self->oversampling); + spin_mutex_unlock(self->synth_mutex); + return status; } @@ -1419,7 +1441,12 @@ work(LV2_Handle instance, if (atom->type == self->sfizz_sfz_file_uri) { const char *sfz_file_path = LV2_ATOM_BODY_CONST(atom); - if (!sfizz_lv2_load_file(self, sfz_file_path)) { + + spin_mutex_lock(self->synth_mutex); + bool success = sfizz_lv2_load_file(self, sfz_file_path); + spin_mutex_unlock(self->synth_mutex); + + if (!success) { lv2_log_error(&self->logger, "[sfizz] Error with %s; no file should be loaded\n", sfz_file_path); } @@ -1430,7 +1457,12 @@ work(LV2_Handle instance, else if (atom->type == self->sfizz_scala_file_uri) { const char *scala_file_path = LV2_ATOM_BODY_CONST(atom); - if (sfizz_lv2_load_scala_file(self, scala_file_path)) { + + spin_mutex_lock(self->synth_mutex); + bool success = sfizz_lv2_load_scala_file(self, scala_file_path); + spin_mutex_unlock(self->synth_mutex); + + if (success) { lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", scala_file_path); } else { lv2_log_error(&self->logger, @@ -1443,7 +1475,11 @@ work(LV2_Handle instance, else if (atom->type == self->sfizz_num_voices_uri) { const int num_voices = *(const int *)LV2_ATOM_BODY_CONST(atom); + + spin_mutex_lock(self->synth_mutex); sfizz_set_num_voices(self->synth, num_voices); + spin_mutex_unlock(self->synth_mutex); + if (sfizz_get_num_voices(self->synth) == num_voices) { lv2_log_note(&self->logger, "[sfizz] Number of voices changed to: %d\n", num_voices); } else { @@ -1453,7 +1489,11 @@ work(LV2_Handle instance, else if (atom->type == self->sfizz_preload_size_uri) { const unsigned int preload_size = *(const unsigned int *)LV2_ATOM_BODY_CONST(atom); + + spin_mutex_lock(self->synth_mutex); sfizz_set_preload_size(self->synth, preload_size); + spin_mutex_unlock(self->synth_mutex); + if (sfizz_get_preload_size(self->synth) == preload_size) { lv2_log_note(&self->logger, "[sfizz] Preload size changed to: %d\n", preload_size); } else { @@ -1464,7 +1504,11 @@ work(LV2_Handle instance, { const sfizz_oversampling_factor_t oversampling = *(const sfizz_oversampling_factor_t *)LV2_ATOM_BODY_CONST(atom); + + spin_mutex_lock(self->synth_mutex); sfizz_set_oversampling_factor(self->synth, oversampling); + spin_mutex_unlock(self->synth_mutex); + if (sfizz_get_oversampling_factor(self->synth) == oversampling) { lv2_log_note(&self->logger, "[sfizz] Oversampling changed to: %d\n", oversampling); } else { @@ -1482,7 +1526,12 @@ work(LV2_Handle instance, lv2_log_note(&self->logger, "[sfizz] File %s seems to have been updated, reloading\n", self->sfz_file_path); - if (!sfizz_lv2_load_file(self, self->sfz_file_path)) { + + spin_mutex_lock(self->synth_mutex); + bool success = sfizz_lv2_load_file(self, self->sfz_file_path); + spin_mutex_unlock(self->synth_mutex); + + if (!success) { lv2_log_error(&self->logger, "[sfizz] Error with %s; no file should be loaded\n", self->sfz_file_path); } @@ -1493,7 +1542,12 @@ work(LV2_Handle instance, lv2_log_note(&self->logger, "[sfizz] Scala file %s seems to have been updated, reloading\n", self->scala_file_path); - if (sfizz_lv2_load_scala_file(self, self->scala_file_path)) { + + spin_mutex_lock(self->synth_mutex); + bool success = sfizz_lv2_load_scala_file(self, self->scala_file_path); + spin_mutex_unlock(self->synth_mutex); + + if (success) { lv2_log_note(&self->logger, "[sfizz] Scala file loaded: %s\n", self->scala_file_path); } else { lv2_log_error(&self->logger, From e0a7fb1dbc7d4d07dce947a43686901dcfa1798a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 22:51:24 +0100 Subject: [PATCH 189/668] Thread-safety at VST level --- vst/CMakeLists.txt | 3 ++- vst/SfizzVstProcessor.cpp | 15 ++++++++++----- vst/SfizzVstProcessor.h | 4 ++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 02afabef..a2c07724 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -58,8 +58,9 @@ if(WIN32) target_sources(${VSTPLUGIN_PRJ_NAME} PRIVATE vst3.def) endif() target_link_libraries(${VSTPLUGIN_PRJ_NAME} - PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} + PRIVATE sfizz::sfizz PRIVATE sfizz::editor + PRIVATE sfizz::spin_mutex PRIVATE sfizz::pugixml sfizz::filesystem) target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index c77365da..6a22e52f 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -138,7 +138,7 @@ tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream) } // - std::lock_guard lock(_processMutex); + std::lock_guard lock(_processMutex); _state = s; syncStateToSynth(); @@ -148,7 +148,7 @@ tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream) tresult PLUGIN_API SfizzVstProcessor::getState(IBStream* stream) { - std::lock_guard lock(_processMutex); + std::lock_guard lock(_processMutex); return _state.store(stream); } @@ -224,7 +224,7 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) for (unsigned c = 0; c < numChannels; ++c) outputs[c] = data.outputs[0].channelBuffers32[c]; - std::unique_lock lock(_processMutex, std::try_to_lock); + std::unique_lock lock(_processMutex, std::try_to_lock); if (!lock.owns_lock()) { for (unsigned c = 0; c < numChannels; ++c) @@ -515,7 +515,7 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - std::unique_lock lock(_processMutex); + std::unique_lock lock(_processMutex); _state.sfzFile.assign(static_cast(data), size); loadSfzFileOrDefault(*_synth, _state.sfzFile); lock.unlock(); @@ -533,7 +533,7 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - std::unique_lock lock(_processMutex); + std::unique_lock lock(_processMutex); _state.scalaFile.assign(static_cast(data), size); _synth->loadScalaFile(_state.scalaFile); lock.unlock(); @@ -601,23 +601,28 @@ void SfizzVstProcessor::doBackgroundWork() if (!std::strcmp(id, "SetNumVoices")) { int32 value = *msg->payload(); + std::lock_guard lock(_processMutex); _synth->setNumVoices(value); } else if (!std::strcmp(id, "SetOversampling")) { int32 value = *msg->payload(); + std::lock_guard lock(_processMutex); _synth->setOversamplingFactor(1 << value); } else if (!std::strcmp(id, "SetPreloadSize")) { int32 value = *msg->payload(); + std::lock_guard lock(_processMutex); _synth->setPreloadSize(value); } else if (!std::strcmp(id, "CheckShouldReload")) { if (_synth->shouldReloadFile()) { fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n"); + std::lock_guard lock(_processMutex); loadSfzFileOrDefault(*_synth, _state.sfzFile); } else if (_synth->shouldReloadScala()) { fprintf(stderr, "[Sfizz] scala file has changed, reloading\n"); + std::lock_guard lock(_processMutex); _synth->loadScalaFile(_state.scalaFile); } } diff --git a/vst/SfizzVstProcessor.h b/vst/SfizzVstProcessor.h index bbbf7490..e8408169 100644 --- a/vst/SfizzVstProcessor.h +++ b/vst/SfizzVstProcessor.h @@ -10,8 +10,8 @@ #include "ring_buffer/ring_buffer.h" #include "public.sdk/source/vst/vstaudioeffect.h" #include +#include #include -#include #include #include @@ -65,7 +65,7 @@ private: Ring_Buffer _fifoToWorker; RTSemaphore _semaToWorker; Ring_Buffer _fifoMessageFromUi; - std::mutex _processMutex; + SpinMutex _processMutex; // file modification periodic checker uint32 _fileChangeCounter = 0; From 62ec01a3620877fcb5e2225e6c6d256aa5656ede Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Feb 2021 23:12:29 +0100 Subject: [PATCH 190/668] Thread-safety for the JACK client --- clients/CMakeLists.txt | 2 +- clients/jack_client.cpp | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index a48af11a..367acc04 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -1,6 +1,6 @@ if(SFIZZ_JACK) add_executable(sfizz_jack MidiHelpers.h jack_client.cpp) - target_link_libraries(sfizz_jack PRIVATE sfizz::sfizz sfizz::jack absl::flags_parse) + target_link_libraries(sfizz_jack PRIVATE sfizz::sfizz sfizz::jack sfizz::spin_mutex absl::flags_parse) sfizz_enable_lto_if_needed(sfizz_jack) install(TARGETS sfizz_jack DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "jack" OPTIONAL) diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index b9e5f5dd..46fff6b2 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -38,11 +39,14 @@ #include #include #include +#include +#include static jack_port_t* midiInputPort; static jack_port_t* outputPort1; static jack_port_t* outputPort2; static jack_client_t* client; +static SpinMutex processMutex; int process(jack_nframes_t numFrames, void* arg) { @@ -51,6 +55,16 @@ int process(jack_nframes_t numFrames, void* arg) auto* buffer = jack_port_get_buffer(midiInputPort, numFrames); assert(buffer); + auto* leftOutput = reinterpret_cast(jack_port_get_buffer(outputPort1, numFrames)); + auto* rightOutput = reinterpret_cast(jack_port_get_buffer(outputPort2, numFrames)); + + std::unique_lock lock { processMutex, std::try_to_lock }; + if (!lock.owns_lock()) { + std::fill_n(leftOutput, numFrames, 0.0f); + std::fill_n(rightOutput, numFrames, 0.0f); + return 0; + } + auto numMidiEvents = jack_midi_get_event_count(buffer); jack_midi_event_t event; @@ -96,9 +110,6 @@ int process(jack_nframes_t numFrames, void* arg) } } - auto* leftOutput = reinterpret_cast(jack_port_get_buffer(outputPort1, numFrames)); - auto* rightOutput = reinterpret_cast(jack_port_get_buffer(outputPort2, numFrames)); - float* stereoOutput[] = { leftOutput, rightOutput }; synth->renderBlock(stereoOutput, numFrames); @@ -112,6 +123,7 @@ int sampleBlockChanged(jack_nframes_t nframes, void* arg) auto* synth = reinterpret_cast(arg); // DBG("Sample per block changed to " << nframes); + std::lock_guard lock { processMutex }; synth->setSamplesPerBlock(nframes); return 0; } @@ -123,6 +135,7 @@ int sampleRateChanged(jack_nframes_t nframes, void* arg) auto* synth = reinterpret_cast(arg); // DBG("Sample rate changed to " << nframes); + std::lock_guard lock { processMutex }; synth->setSampleRate(nframes); return 0; } From 3fea4ba0e5a6cd2a30455e0dce2b59711dca5afe Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Feb 2021 00:28:08 +0100 Subject: [PATCH 191/668] Fix AudioUnit with spin mutex --- vst/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index a2c07724..cc73ce59 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -199,6 +199,7 @@ elseif(SFIZZ_AU) target_link_libraries(${AUPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} PRIVATE sfizz::editor + PRIVATE sfizz::spin_mutex PRIVATE sfizz::pugixml sfizz::filesystem) target_include_directories(${AUPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") From cb91698144af1bcdd5847ad2522987f86939e653 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Feb 2021 15:46:11 +0100 Subject: [PATCH 192/668] Update doc with thread-safety constraints --- src/sfizz.h | 160 +++++++++++++++++++++++++++++++++++++---- src/sfizz.hpp | 195 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 325 insertions(+), 30 deletions(-) diff --git a/src/sfizz.h b/src/sfizz.h index 5deaea5f..343d73a0 100644 --- a/src/sfizz.h +++ b/src/sfizz.h @@ -5,9 +5,28 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz /** - @file - @brief sfizz public C API. -*/ + * @file + * @brief sfizz public C API. + * + * sfizz is a synthesizer for SFZ instruments. + * + * The synthesizer must be operated under indicated constraints in order to + * guarantee thread-safety. + * + * At any given time, no more than 2 tasks must interact in parallel with this + * library: + * - a processing tasks @b RT for audio and MIDI, which can be real-time + * - a Control tasks @b CT + * + * The tasks RT and CT can be assumed by different threads over the lifetime, as + * long as the switch is adequately synchronized. If real-time processing is not + * required, it's acceptable for the 2 tasks can be assumed by a single thread. + * + * Where one or more following items are indicated on a function, the constraints apply. + * - @b RT: the function must be invoked from the Real-time thread + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions + */ #pragma once #include "sfizz_message.h" @@ -84,6 +103,10 @@ SFIZZ_EXPORTED_API void sfizz_free(sfizz_synth_t* synth); * * @return @true when file loading went OK, * @false if some error occured while loading. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API bool sfizz_load_file(sfizz_synth_t* synth, const char* path); @@ -101,6 +124,10 @@ SFIZZ_EXPORTED_API bool sfizz_load_file(sfizz_synth_t* synth, const char* path); * * @return @true when file loading went OK, * @false if some error occured while loading. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API bool sfizz_load_string(sfizz_synth_t* synth, const char* path, const char* text); @@ -113,6 +140,10 @@ SFIZZ_EXPORTED_API bool sfizz_load_string(sfizz_synth_t* synth, const char* path * * @return @true when tuning scale loaded OK, * @false if some error occurred. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API bool sfizz_load_scala_file(sfizz_synth_t* synth, const char* path); @@ -125,6 +156,10 @@ SFIZZ_EXPORTED_API bool sfizz_load_scala_file(sfizz_synth_t* synth, const char* * * @return @true when tuning scale loaded OK, * @false if some error occurred. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API bool sfizz_load_scala_string(sfizz_synth_t* synth, const char* text); @@ -134,6 +169,9 @@ SFIZZ_EXPORTED_API bool sfizz_load_scala_string(sfizz_synth_t* synth, const char * * @param synth The synth. * @param root_key The MIDI number of the Scala root key (default 60 for C4). + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_set_scala_root_key(sfizz_synth_t* synth, int root_key); @@ -153,6 +191,9 @@ SFIZZ_EXPORTED_API int sfizz_get_scala_root_key(sfizz_synth_t* synth); * * @param synth The synth. * @param frequency The frequency which indicates where standard tuning A4 is (default 440 Hz). + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_set_tuning_frequency(sfizz_synth_t* synth, float frequency); @@ -174,6 +215,9 @@ SFIZZ_EXPORTED_API float sfizz_get_tuning_frequency(sfizz_synth_t* synth); * * @param synth The synth. * @param ratio The parameter in domain 0-1. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_load_stretch_tuning_by_ratio(sfizz_synth_t* synth, float ratio); @@ -249,6 +293,10 @@ SFIZZ_EXPORTED_API int sfizz_get_num_active_voices(sfizz_synth_t* synth); * * @param synth The synth. * @param samples_per_block The number of samples per block. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API void sfizz_set_samples_per_block(sfizz_synth_t* synth, int samples_per_block); @@ -260,6 +308,10 @@ SFIZZ_EXPORTED_API void sfizz_set_samples_per_block(sfizz_synth_t* synth, int sa * * @param synth The synth * @param sample_rate The sample rate. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API void sfizz_set_sample_rate(sfizz_synth_t* synth, float sample_rate); @@ -274,6 +326,9 @@ SFIZZ_EXPORTED_API void sfizz_set_sample_rate(sfizz_synth_t* synth, float sample * @param delay The delay of the event in the block, in samples. * @param note_number The MIDI note number. * @param velocity The MIDI velocity. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_note_on(sfizz_synth_t* synth, int delay, int note_number, char velocity); @@ -290,6 +345,9 @@ SFIZZ_EXPORTED_API void sfizz_send_note_on(sfizz_synth_t* synth, int delay, int * @param delay The delay of the event in the block, in samples. * @param note_number The MIDI note number. * @param velocity The MIDI velocity. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_note_off(sfizz_synth_t* synth, int delay, int note_number, char velocity); @@ -304,6 +362,9 @@ SFIZZ_EXPORTED_API void sfizz_send_note_off(sfizz_synth_t* synth, int delay, int * @param delay The delay of the event in the block, in samples. * @param cc_number The MIDI CC number. * @param cc_value The MIDI CC value. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_cc(sfizz_synth_t* synth, int delay, int cc_number, char cc_value); @@ -318,6 +379,9 @@ SFIZZ_EXPORTED_API void sfizz_send_cc(sfizz_synth_t* synth, int delay, int cc_nu * @param delay The delay of the event in the block, in samples. * @param cc_number The MIDI CC number. * @param norm_value The normalized CC value, in domain 0 to 1. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_value); @@ -335,6 +399,9 @@ SFIZZ_EXPORTED_API void sfizz_send_hdcc(sfizz_synth_t* synth, int delay, int cc_ * @param delay The delay of the event in the block, in samples. * @param cc_number The MIDI CC number. * @param norm_value The normalized CC value, in domain 0 to 1. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_automate_hdcc(sfizz_synth_t* synth, int delay, int cc_number, float norm_value); @@ -348,6 +415,9 @@ SFIZZ_EXPORTED_API void sfizz_automate_hdcc(sfizz_synth_t* synth, int delay, int * @param synth The synth. * @param delay The delay. * @param pitch The pitch. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_pitch_wheel(sfizz_synth_t* synth, int delay, int pitch); @@ -357,8 +427,11 @@ SFIZZ_EXPORTED_API void sfizz_send_pitch_wheel(sfizz_synth_t* synth, int delay, * * @param synth The synth. * @param delay The delay at which the event occurs; this should be lower - * than the size of the block in the next call to renderBlock(). + * than the size of the block in the next call to renderBlock(). * @param aftertouch The aftertouch value. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_aftertouch(sfizz_synth_t* synth, int delay, char aftertouch); @@ -369,6 +442,9 @@ SFIZZ_EXPORTED_API void sfizz_send_aftertouch(sfizz_synth_t* synth, int delay, c * @param synth The synth. * @param delay The delay. * @param seconds_per_beat The seconds per beat. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_tempo(sfizz_synth_t* synth, int delay, float seconds_per_beat); @@ -380,6 +456,9 @@ SFIZZ_EXPORTED_API void sfizz_send_tempo(sfizz_synth_t* synth, int delay, float * @param delay The delay. * @param beats_per_bar The number of beats per bar, or time signature numerator. * @param beat_unit The note corresponding to one beat, or time signature denominator. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_time_signature(sfizz_synth_t* synth, int delay, int beats_per_bar, int beat_unit); @@ -391,6 +470,9 @@ SFIZZ_EXPORTED_API void sfizz_send_time_signature(sfizz_synth_t* synth, int dela * @param delay The delay. * @param bar The current bar. * @param bar_beat The fractional position of the current beat within the bar. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, double bar_beat); @@ -401,6 +483,9 @@ SFIZZ_EXPORTED_API void sfizz_send_time_position(sfizz_synth_t* synth, int delay * @param synth The synth. * @param delay The delay. * @param playback_state The playback state, 1 if playing, 0 if stopped. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_playback_state(sfizz_synth_t* synth, int delay, int playback_state); @@ -419,6 +504,9 @@ SFIZZ_EXPORTED_API void sfizz_send_playback_state(sfizz_synth_t* synth, int dela * @param num_channels Should be equal to 2 for the time being. * @param num_frames Number of frames to fill. This should be less than * or equal to the expected samples_per_block. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_render_block(sfizz_synth_t* synth, float** channels, int num_channels, int num_frames); @@ -443,6 +531,10 @@ SFIZZ_EXPORTED_API unsigned int sfizz_get_preload_size(sfizz_synth_t* synth); * * @param synth The synth. * @param[in] preload_size The preload size. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API void sfizz_set_preload_size(sfizz_synth_t* synth, unsigned int preload_size); @@ -471,16 +563,16 @@ SFIZZ_EXPORTED_API sfizz_oversampling_factor_t sfizz_get_oversampling_factor(sfi * the loading speed. You can tweak the size of the preloaded data to compensate * for the memory increase, but the full loading will need to take place anyway. * - * This function takes a lock and disables the callback; prefer calling it out - * of the RT thread. It can also take a long time to return. - * If the new oversampling factor is the same as the current one, it will - * release the lock immediately and exit. * @since 0.2.0 * * @param synth The synth. * @param[in] oversampling The oversampling factor. * * @return @true if the oversampling factor was correct, @false otherwise. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API bool sfizz_set_oversampling_factor(sfizz_synth_t* synth, sfizz_oversampling_factor_t oversampling); @@ -512,6 +604,9 @@ SFIZZ_EXPORTED_API int sfizz_get_sample_quality(sfizz_synth_t* synth, sfizz_proc * @param synth The synth. * @param[in] mode The processing mode. * @param[in] quality The desired sample quality, in the range 1 to 10. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_set_sample_quality(sfizz_synth_t* synth, sfizz_process_mode_t mode, int quality); @@ -521,6 +616,9 @@ SFIZZ_EXPORTED_API void sfizz_set_sample_quality(sfizz_synth_t* synth, sfizz_pro * * @param synth The synth. * @param volume The new volume. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_set_volume(sfizz_synth_t* synth, float volume); @@ -535,14 +633,14 @@ SFIZZ_EXPORTED_API float sfizz_get_volume(sfizz_synth_t* synth); /** * @brief Set the number of voices used by the synth. * - * This function takes a lock and disables the callback; prefer calling - * it out of the RT thread. It can also take a long time to return. - * If the new number of voices is the same as the current one, it will - * release the lock immediately and exit. * @since 0.2.0 * * @param synth The synth. * @param num_voices The number of voices. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ SFIZZ_EXPORTED_API void sfizz_set_num_voices(sfizz_synth_t* synth, int num_voices); @@ -578,6 +676,9 @@ SFIZZ_EXPORTED_API int sfizz_get_num_bytes(sfizz_synth_t* synth); * @since 0.2.0 * * @param synth The synth. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_enable_freewheeling(sfizz_synth_t* synth); @@ -586,6 +687,9 @@ SFIZZ_EXPORTED_API void sfizz_enable_freewheeling(sfizz_synth_t* synth); * @since 0.2.0 * * @param synth The synth. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_disable_freewheeling(sfizz_synth_t* synth); @@ -609,7 +713,10 @@ SFIZZ_EXPORTED_API char* sfizz_get_unknown_opcodes(sfizz_synth_t* synth); * @param synth The synth. * * @return @true if any included files (including the root file) - have been modified since the sfz file was loaded, @false otherwise. + * have been modified since the sfz file was loaded, @false otherwise. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread */ SFIZZ_EXPORTED_API bool sfizz_should_reload_file(sfizz_synth_t* synth); @@ -622,6 +729,9 @@ SFIZZ_EXPORTED_API bool sfizz_should_reload_file(sfizz_synth_t* synth); * @param synth The synth. * * @return @true if the scala file has been modified since loading. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread */ SFIZZ_EXPORTED_API bool sfizz_should_reload_scala(sfizz_synth_t* synth); @@ -632,6 +742,9 @@ SFIZZ_EXPORTED_API bool sfizz_should_reload_scala(sfizz_synth_t* synth); * @note This can produce many outputs so use with caution. * * @param synth The synth. + * + * @par Thread-safety constraints + * - TBD ? */ SFIZZ_EXPORTED_API void sfizz_enable_logging(sfizz_synth_t* synth); @@ -640,6 +753,9 @@ SFIZZ_EXPORTED_API void sfizz_enable_logging(sfizz_synth_t* synth); * @since 0.3.0 * * @param synth The synth. + * + * @par Thread-safety constraints + * - TBD ? */ SFIZZ_EXPORTED_API void sfizz_disable_logging(sfizz_synth_t* synth); @@ -651,6 +767,9 @@ SFIZZ_EXPORTED_API void sfizz_disable_logging(sfizz_synth_t* synth); * * @param synth The synth. * @param prefix The prefix. + * + * @par Thread-safety constraints + * - TBD ? */ SFIZZ_EXPORTED_API void sfizz_set_logging_prefix(sfizz_synth_t* synth, const char* prefix); @@ -659,6 +778,9 @@ SFIZZ_EXPORTED_API void sfizz_set_logging_prefix(sfizz_synth_t* synth, const cha * @since 0.3.2 * * @param synth The synth. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_all_sound_off(sfizz_synth_t* synth); @@ -672,6 +794,9 @@ SFIZZ_EXPORTED_API void sfizz_all_sound_off(sfizz_synth_t* synth); * @param synth The synth. * @param id The definition variable name. * @param value The definition value. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread */ SFIZZ_EXPORTED_API void sfizz_add_external_definitions(sfizz_synth_t* synth, const char* id, const char* value); @@ -680,6 +805,9 @@ SFIZZ_EXPORTED_API void sfizz_add_external_definitions(sfizz_synth_t* synth, con * @since 0.4.0 * * @param synth The synth. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread */ SFIZZ_EXPORTED_API void sfizz_clear_external_definitions(sfizz_synth_t* synth); @@ -805,6 +933,9 @@ SFIZZ_EXPORTED_API void sfizz_set_receive_callback(sfizz_client_t* client, sfizz * @param path The OSC address pattern. * @param sig The OSC type tag string. * @param args The OSC arguments, whose number and format is determined the type tag string. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_send_message(sfizz_synth_t* synth, sfizz_client_t* client, int delay, const char* path, const char* sig, const sfizz_arg_t* args); @@ -815,6 +946,9 @@ SFIZZ_EXPORTED_API void sfizz_send_message(sfizz_synth_t* synth, sfizz_client_t* * @param synth The synth. * @param broadcast The pointer to the receiving function. * @param data The opaque data pointer which is passed to the receiver. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ SFIZZ_EXPORTED_API void sfizz_set_broadcast_callback(sfizz_synth_t* synth, sfizz_receive_t* broadcast, void* data); diff --git a/src/sfizz.hpp b/src/sfizz.hpp index e6b34daf..dfef34f1 100644 --- a/src/sfizz.hpp +++ b/src/sfizz.hpp @@ -31,8 +31,25 @@ namespace sfz class Synth; class Client; /** - * @brief Main class. - */ + * @brief Synthesizer for SFZ instruments +* +* The synthesizer must be operated under indicated constraints in order to +* guarantee thread-safety. +* +* At any given time, no more than 2 tasks must interact in parallel with this +* library: +* - a processing tasks @b RT for audio and MIDI, which can be real-time +* - a Control tasks @b CT +* +* The tasks RT and CT can be assumed by different threads over the lifetime, as +* long as the switch is adequately synchronized. If real-time processing is not +* required, it's acceptable for the 2 tasks can be assumed by a single thread. +* +* Where one or more following items are indicated on a function, the constraints apply. +* - @b RT: the function must be invoked from the Real-time thread +* - @b CT: the function must be invoked from the Control thread +* - @b OFF: the function cannot be invoked while a thread is calling @b RT functions +*/ class SFIZZ_EXPORTED_API Sfizz { public: @@ -57,15 +74,16 @@ public: /** * @brief Empties the current regions and load a new SFZ file into the synth. * - * This function will disable all callbacks so it is safe to call from a - * UI thread for example, although it may generate a click. However it is - * not reentrant, so you should not call it from concurrent threads. * @since 0.2.0 * * @param path The path to the file to load, as string. * * @return @false if the file was not found or no regions were loaded, * @true otherwise. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ bool loadSfzFile(const std::string& path); @@ -76,6 +94,7 @@ public: * This accepts a virtual path name for the imaginary sfz file, which is not * required to exist on disk. The purpose of the virtual path is to locate * samples with relative paths. + * * @since 0.4.0 * * @param path The virtual path of the SFZ file, as string. @@ -83,36 +102,54 @@ public: * * @return @false if no regions were loaded, * @true otherwise. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ bool loadSfzString(const std::string& path, const std::string& text); /** * @brief Sets the tuning from a Scala file loaded from the file system. + * * @since 0.4.0 * * @param path The path to the file in Scala format. * * @return @true when tuning scale loaded OK, * @false if some error occurred. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ bool loadScalaFile(const std::string& path); /** * @brief Sets the tuning from a Scala file loaded from memory. + * * @since 0.4.0 * * @param text The contents of the file in Scala format. * * @return @true when tuning scale loaded OK, * @false if some error occurred. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ bool loadScalaString(const std::string& text); /** * @brief Sets the scala root key. + * * @since 0.4.0 * * @param rootKey The MIDI number of the Scala root key (default 60 for C4). + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void setScalaRootKey(int rootKey); @@ -126,9 +163,13 @@ public: /** * @brief Sets the reference tuning frequency. + * * @since 0.4.0 * * @param frequency The frequency which indicates where standard tuning A4 is (default 440 Hz). + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void setTuningFrequency(float frequency); @@ -144,9 +185,13 @@ public: * @brief Configure stretch tuning using a predefined parametric Railsback curve. * * A ratio 1/2 is supposed to match the average piano; 0 disables (the default). + * * @since 0.4.0 * * @param ratio The parameter in domain 0-1. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void loadStretchTuningByRatio(float ratio); @@ -191,9 +236,14 @@ public: * * The actual size can be lower in each callback but should not be larger * than this value. + * * @since 0.2.0 * * @param samplesPerBlock The number of samples per block. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ void setSamplesPerBlock(int samplesPerBlock) noexcept; @@ -201,9 +251,14 @@ public: * @brief Set the sample rate. * * If you do not call it it is initialized to `sfz::config::defaultSampleRate`. + * * @since 0.2.0 * * @param sampleRate The sample rate. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ void setSampleRate(float sampleRate) noexcept; @@ -229,10 +284,14 @@ public: * does not use the opcode `sample_quality`. The engine uses distinct * default quality settings for live mode and freewheeling mode, * which both can be accessed by the means of this function. + * * @since 0.4.0 * * @param[in] mode The processing mode. * @param[in] quality The desired sample quality, in the range 1 to 10. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void setSampleQuality(ProcessMode mode, int quality); @@ -246,53 +305,73 @@ public: * @brief Set the value for the volume. * * This value will be clamped within `sfz::default::volumeRange`. + * * @since 0.2.0 * * @param volume The new volume. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void setVolume(float volume) noexcept; /** * @brief Send a note on event to the synth. + * * @since 0.2.0 * * @param delay the delay at which the event occurs; this should be lower * than the size of the block in the next call to renderBlock(). * @param noteNumber the midi note number. * @param velocity the midi note velocity. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void noteOn(int delay, int noteNumber, uint8_t velocity) noexcept; /** * @brief Send a note off event to the synth. + * * @since 0.2.0 * * @param delay the delay at which the event occurs; this should be lower * than the size of the block in the next call to renderBlock(). * @param noteNumber the midi note number. * @param velocity the midi note velocity. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void noteOff(int delay, int noteNumber, uint8_t velocity) noexcept; /** * @brief Send a CC event to the synth + * * @since 0.2.0 * * @param delay the delay at which the event occurs; this should be lower * than the size of the block in the next call to renderBlock(). * @param ccNumber the cc number. * @param ccValue the cc value. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void cc(int delay, int ccNumber, uint8_t ccValue) noexcept; /** * @brief Send a high precision CC event to the synth + * * @since 0.4.0 * * @param delay the delay at which the event occurs; this should be lower * than the size of the block in the next call to renderBlock(). * @param ccNumber the cc number. * @param normValue the normalized cc value, in domain 0 to 1. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void hdcc(int delay, int ccNumber, float normValue) noexcept; @@ -308,65 +387,92 @@ public: * than the size of the block in the next call to renderBlock(). * @param ccNumber the cc number. * @param normValue the normalized cc value, in domain 0 to 1. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void automateHdcc(int delay, int ccNumber, float normValue) noexcept; /** * @brief Send a pitch bend event to the synth + * * @since 0.2.0 * * @param delay the delay at which the event occurs; this should be lower * than the size of the block in the next call to renderBlock(). * @param pitch the pitch value centered between -8192 and 8192. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void pitchWheel(int delay, int pitch) noexcept; /** * @brief Send a aftertouch event to the synth. (CURRENTLY UNIMPLEMENTED) + * * @since 0.2.0 * * @param delay the delay at which the event occurs; this should be lower * than the size of the block in the next call to renderBlock(). * @param aftertouch the aftertouch value. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void aftertouch(int delay, uint8_t aftertouch) noexcept; /** * @brief Send a tempo event to the synth. + * * @since 0.2.0 * * @param delay the delay at which the event occurs; this should be lower * than the size of the block in the next call to renderBlock(). * @param secondsPerBeat the new period of the beat. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void tempo(int delay, float secondsPerBeat) noexcept; /** * @brief Send the time signature. + * * @since 0.5.0 * * @param delay The delay. * @param beatsPerBar The number of beats per bar, or time signature numerator. * @param beatUnit The note corresponding to one beat, or time signature denominator. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void timeSignature(int delay, int beatsPerBar, int beatUnit); /** * @brief Send the time position. + * * @since 0.5.0 * * @param delay The delay. * @param bar The current bar. * @param barBeat The fractional position of the current beat within the bar. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void timePosition(int delay, int bar, double barBeat); /** * @brief Send the playback state. + * * @since 0.5.0 * * @param delay The delay. * @param playbackState The playback state, 1 if playing, 0 if stopped. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void playbackState(int delay, int playbackState); @@ -375,11 +481,15 @@ public: * * This call will reset the synth in its waiting state for the next batch * of events. The buffers must be float[numSamples][numOutputs * 2]. + * * @since 0.2.0 * * @param buffers the buffers to write the next block into. * @param numFrames the number of stereo frames in the block. * @param numOutputs the number of stereo outputs. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void renderBlock(float** buffers, size_t numFrames, int numOutputs = 1) noexcept; @@ -398,13 +508,13 @@ public: /** * @brief Change the number of voices (the polyphony). * - * This function takes a lock and disables the callback; prefer calling - * it out of the RT thread. It can also take a long time to return. - * If the new number of voices is the same as the current one, it will - * release the lock immediately and exit. * @since 0.2.0 * * @param numVoices The number of voices. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ void setNumVoices(int numVoices) noexcept; @@ -424,15 +534,15 @@ public: * to compensate for the memory increase, but the full loading will * need to take place anyway. * - * This function takes a lock and disables the callback; prefer calling - * it out of the RT thread. It can also take a long time to return. - * If the new oversampling factor is the same as the current one, it will - * release the lock immediately and exit. * @since 0.2.0 * * @param factor The oversampling factor. * * @return @true if the factor did indeed change, @false otherwise. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ bool setOversamplingFactor(int factor) noexcept; @@ -445,13 +555,13 @@ public: /** * @brief Set the preloaded file size. * - * This function takes a lock and disables the callback; prefer calling - * it out of the RT thread. It can also take a long time to return. - * If the new preload size is the same as the current one, it will - * release the lock immediately and exit. * @since 0.2.0 * * @param preloadSize The preload size. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread + * - @b OFF: the function cannot be invoked while a thread is calling @b RT functions */ void setPreloadSize(uint32_t preloadSize) noexcept; @@ -478,7 +588,11 @@ public: * * This will wait for background loaded files to finish loading * before each render callback to ensure that there will be no dropouts. + * * @since 0.2.0 + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void enableFreeWheeling() noexcept; @@ -487,7 +601,11 @@ public: * * You should disable freewheeling before live use of the plugin * otherwise the audio thread will lock. + * * @since 0.2.0 + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void disableFreeWheeling() noexcept; @@ -495,10 +613,14 @@ public: * @brief Check if the SFZ should be reloaded. * * Depending on the platform this can create file descriptors. + * * @since 0.2.0 * * @return @true if any included files (including the root file) have * been modified since the sfz file was loaded, @false otherwise. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread */ bool shouldReloadFile(); @@ -506,9 +628,13 @@ public: * @brief Check if the tuning (scala) file should be reloaded. * * Depending on the platform this can create file descriptors. + * * @since 0.4.0 * * @return @true if a scala file has been loaded and has changed, @false otherwise. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread */ bool shouldReloadScala(); @@ -519,41 +645,61 @@ public: * @note This can produce many outputs so use with caution. * * @param prefix the file prefix to use for logging. + * + * @par Thread-safety constraints + * - TBD ? */ void enableLogging() noexcept; /** * @brief Enable logging of timings to sidecar CSV files. + * * @since 0.3.2 * * @note This can produce many outputs so use with caution. * * @param prefix the file prefix to use for logging. + * + * @par Thread-safety constraints + * - TBD ? */ void enableLogging(const std::string& prefix) noexcept; /** * @brief Set the logging prefix. + * * @since 0.3.2 * * @param prefix + * + * @par Thread-safety constraints + * - TBD ? */ void setLoggingPrefix(const std::string& prefix) noexcept; /** * @brief Disable logging of timings to sidecar CSV files. + * * @since 0.3.0 + * + * @par Thread-safety constraints + * - TBD ? */ void disableLogging() noexcept; /** * @brief Shuts down the current processing, clear buffers and reset the voices. + * * @since 0.3.2 + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void allSoundOff() noexcept; /** * @brief Add external definitions prior to loading. + * * @since 0.4.0 * * @note These do not get reset by loading or resetting the synth. @@ -561,12 +707,19 @@ public: * * @param id The definition variable name. * @param value The definition value. + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread */ void addExternalDefinition(const std::string& id, const std::string& value); /** * @brief Clears external definitions for the next file loading. + * * @since 0.4.0 + * + * @par Thread-safety constraints + * - @b CT: the function must be invoked from the Control thread */ void clearExternalDefinitions(); @@ -624,6 +777,7 @@ public: /** * @brief Send a message to the synth engine + * * @since 0.6.0 * * @param client The client sending the message. @@ -631,15 +785,22 @@ public: * @param path The OSC address pattern. * @param sig The OSC type tag string. * @param args The OSC arguments, whose number and format is determined the type tag string. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void sendMessage(Client& client, int delay, const char* path, const char* sig, const sfizz_arg_t* args); /** * @brief Set the function which receives broadcast messages from the synth engine. + * * @since 0.6.0 * * @param broadcast The pointer to the receiving function. * @param data The opaque data pointer which is passed to the receiver. + * + * @par Thread-safety constraints + * - @b RT: the function must be invoked from the Real-time thread */ void setBroadcastCallback(sfizz_receive_t* broadcast, void* data); From bc466866c3db0e56417b15456ad471e0d5422e35 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Feb 2021 17:03:24 +0100 Subject: [PATCH 193/668] Handle unicode note names --- src/sfizz/Opcode.cpp | 33 +++++++++++++++++++++------------ tests/OpcodeT.cpp | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index ff6cbc6d..1a60ff78 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -132,18 +132,27 @@ absl::optional readNoteValue(absl::string_view value) absl::string_view validFlatLetters = "degab"; /// - char sharpOrFlatLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front()); - if (sharpOrFlatLetter == '#') { - if (validSharpLetters.find(noteLetter) == absl::string_view::npos) - return {}; - ++noteNumber; - value.remove_prefix(1); - } - else if (sharpOrFlatLetter == 'b') { - if (validFlatLetters.find(noteLetter) == absl::string_view::npos) - return {}; - --noteNumber; - value.remove_prefix(1); + std::pair flatSharpPrefixes[] = { + { "#", +1 }, + { u8"♯", +1 }, + { "b", -1 }, + { u8"♭", -1 }, + }; + + for (const auto& prefix : flatSharpPrefixes) { + if (absl::StartsWith(value, prefix.first)) { + if (prefix.second == +1) { + if (validSharpLetters.find(noteLetter) == absl::string_view::npos) + return {}; + } + else if (prefix.second == -1) { + if (validFlatLetters.find(noteLetter) == absl::string_view::npos) + return {}; + } + noteNumber += prefix.second; + value.remove_prefix(prefix.first.size()); + break; + } } int octaveNumber; diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 23cfdda0..24d6a98c 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -134,23 +134,43 @@ TEST_CASE("[Opcode] Note values") noteValue = sfz::readNoteValue("c#4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); + noteValue = sfz::readNoteValue(u8"c♯4"); + REQUIRE(noteValue); + REQUIRE(*noteValue == 61); noteValue = sfz::readNoteValue("C#4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); + noteValue = sfz::readNoteValue(u8"C♯4"); + REQUIRE(noteValue); + REQUIRE(*noteValue == 61); noteValue = sfz::readNoteValue("e#4"); REQUIRE(!noteValue); + noteValue = sfz::readNoteValue(u8"e♯4"); + REQUIRE(!noteValue); noteValue = sfz::readNoteValue("E#4"); REQUIRE(!noteValue); + noteValue = sfz::readNoteValue(u8"E♯4"); + REQUIRE(!noteValue); noteValue = sfz::readNoteValue("db4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); + noteValue = sfz::readNoteValue(u8"d♭4"); + REQUIRE(noteValue); + REQUIRE(*noteValue == 61); noteValue = sfz::readNoteValue("Db4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); + noteValue = sfz::readNoteValue(u8"D♭4"); + REQUIRE(noteValue); + REQUIRE(*noteValue == 61); noteValue = sfz::readNoteValue("fb4"); REQUIRE(!noteValue); + noteValue = sfz::readNoteValue(u8"f♭4"); + REQUIRE(!noteValue); noteValue = sfz::readNoteValue("Fb4"); REQUIRE(!noteValue); + noteValue = sfz::readNoteValue(u8"F♭4"); + REQUIRE(!noteValue); } TEST_CASE("[Opcode] Categories") From f5aa3c7b9c57ed249f3d108ade016978351777de Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Feb 2021 17:15:24 +0100 Subject: [PATCH 194/668] Do not count overflow voices which are over limit --- src/sfizz/Synth.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 2a12f683..93617268 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -794,7 +794,15 @@ void Synth::loadStretchTuningByRatio(float ratio) int Synth::getNumActiveVoices() const noexcept { Impl& impl = *impl_; - return static_cast(impl.voiceManager_.getNumActiveVoices()); + + int activeVoices = static_cast(impl.voiceManager_.getNumActiveVoices()); + + // do not count overflow voices which are over limit + int resultVoices = activeVoices; + if (config::overflowVoiceMultiplier > 1) + resultVoices = std::min(impl.numVoices_, activeVoices); + + return resultVoices; } void Synth::setSamplesPerBlock(int samplesPerBlock) noexcept From 82899edc45ea93f73a6b3e450afb722ab55300dd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Feb 2021 17:25:39 +0100 Subject: [PATCH 195/668] Update clang-tidy --- scripts/run_clang_tidy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index 7c2894aa..ef805736 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -32,7 +32,7 @@ clang-tidy \ vst/SfizzVstState.cpp \ -- -Iexternal/abseil-cpp -Iexternal/jsl/include -Iexternal/filesystem/include -Isrc/external/hiir -Isrc/external/pugixml/src \ -Iexternal/st_audiofile/src -Iexternal/st_audiofile/thirdparty/dr_libs \ - -Isrc/sfizz -Isrc -Isrc/external/spline -Isrc/external/cpuid/src \ + -Isrc/sfizz -Isrc -Isrc/sfizz/utility/spin_mutex -Isrc/external/spline -Isrc/external/cpuid/src \ -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer \ -Ieditor/src \ -DNDEBUG -std=c++17 From c793af2e01aca32e2afd00f7c731c34af7a294f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20W=C3=BCrtz?= Date: Tue, 2 Feb 2021 08:35:08 +0100 Subject: [PATCH 196/668] Respect region end opcode --- src/sfizz/Voice.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index cdad7af7..3845d2b8 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -950,9 +950,11 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept else { // cut short the voice at the instant of reaching end of sample const auto sampleEnd = min( - static_cast(currentPromise_->information.end), - static_cast(source.getNumFrames()) - ) - 1; + int(region_->trueSampleEnd(resources_.filePool.getOversamplingFactor())), + int(currentPromise_->information.end), + int(source.getNumFrames())) + - 1; + for (unsigned i = 0; i < numSamples; ++i) { if ((*indices)[i] >= sampleEnd) { #ifndef NDEBUG From a69497e7bf5c9598edee7770425198b2938ff9ab Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Feb 2021 19:51:54 +0100 Subject: [PATCH 197/668] Add @dwuertz to contributors --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 4a97b0ed..0ef3a605 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -10,3 +10,4 @@ Contributors to `sfizz`, in chronologic order: - Tobiasz "unfa" Karoń (2020) - Kinwie (2020) - Atsushi Eno (2020) +- Dominique Würtz (2021) From c81f74100b4e1e7251d81ee58f3227200dd3dcc1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 19:35:21 +0100 Subject: [PATCH 198/668] Add CC message processing for OSC --- src/sfizz/Synth.cpp | 34 +++++++++++++++++++++++++----- src/sfizz/SynthMessaging.cpp | 41 ++++++++++++++++++++++++++++++++++++ src/sfizz/SynthPrivate.h | 5 +++++ 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 93617268..e50df231 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -244,7 +244,7 @@ void Synth::Impl::clear() resources_.midiState.reset(); resources_.filePool.clear(); resources_.filePool.setRamLoading(config::loadInRam); - ccLabels_.clear(); + clearCCLabels(); keyLabels_.clear(); keyswitchLabels_.clear(); globalOpcodes_.clear(); @@ -261,9 +261,9 @@ void Synth::Impl::clear() setDefaultHdcc(11, 1.0f); // set default controller labels - insertPairUniquely(ccLabels_, 7, "Volume"); - insertPairUniquely(ccLabels_, 10, "Pan"); - insertPairUniquely(ccLabels_, 11, "Expression"); + setCCLabel(7, "Volume"); + setCCLabel(10, "Pan"); + setCCLabel(11, "Expression"); } void Synth::Impl::handleMasterOpcodes(const std::vector& members) @@ -365,7 +365,7 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) break; case hash("label_cc&"): if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) - insertPairUniquely(ccLabels_, member.parameters.back(), std::string(member.value)); + setCCLabel(member.parameters.back(), std::string(member.value)); break; case hash("label_key&"): if (member.parameters.back() <= Default::keyRange.getEnd()) { @@ -1794,6 +1794,30 @@ std::bitset Synth::Impl::collectAllUsedCCs() return used; } +const std::string* Synth::Impl::getCCLabel(int ccNumber) +{ + auto it = ccLabelsMap_.find(ccNumber); + return (it == ccLabelsMap_.end()) ? nullptr : &ccLabels_[it->second].second; +} + +void Synth::Impl::setCCLabel(int ccNumber, std::string name) +{ + auto it = ccLabelsMap_.find(ccNumber); + if (it != ccLabelsMap_.end()) + ccLabels_[it->second].second = std::move(name); + else { + size_t index = ccLabels_.size(); + ccLabels_.emplace_back(ccNumber, std::move(name)); + ccLabelsMap_[ccNumber] = index; + } +} + +void Synth::Impl::clearCCLabels() +{ + ccLabels_.clear(); + ccLabelsMap_.clear(); +} + Parser& Synth::getParser() noexcept { Impl& impl = *impl_; diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index cabb85ec..68dbf362 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -36,6 +36,47 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive(delay, "/hello", "", nullptr); } break; + //---------------------------------------------------------------------- + + MATCH("/cc/slots", "") { + uint8_t data[(config::numCCs + 7) / 8] = {}; + + const std::bitset& ccs = impl.currentUsedCCs_; + for (unsigned i = 0; i < config::numCCs; ++i) + data[i / 8] |= ccs.test(i) << (i % 8); + + sfizz_blob_t blob { data, sizeof(data) }; + client.receive<'b'>(delay, path, &blob); + } break; + + MATCH("/cc&/default", "") { + if (indices[0] >= config::numCCs) + break; + client.receive<'f'>(delay, path, impl.defaultCCValues_[indices[0]]); + } break; + + MATCH("/cc&/value", "") { + if (indices[0] >= config::numCCs) + break; + // Note: result value is not frame-exact + client.receive<'f'>(delay, path, impl.resources_.midiState.getCCValue(indices[0])); + } break; + + MATCH("/cc&/value", "f") { + if (indices[0] >= config::numCCs) + break; + impl.resources_.midiState.ccEvent(delay, indices[0], args[0].f); + } break; + + MATCH("/cc&/label", "") { + if (indices[0] >= config::numCCs) + break; + const std::string* label = impl.getCCLabel(indices[0]); + client.receive<'s'>(delay, path, label ? label->c_str() : ""); + } break; + + //---------------------------------------------------------------------- + MATCH("/region&/delay", "") { GET_REGION_OR_BREAK(indices[0]) client.receive<'f'>(delay, path, region.delay); diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 42063ed0..43c5b5a8 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -179,6 +179,10 @@ struct Synth::Impl final: public Parser::Listener { std::bitset collectAllUsedCCs(); + const std::string* getCCLabel(int ccNumber); + void setCCLabel(int ccNumber, std::string name); + void clearCCLabels(); + /** * @brief Perform a CC event * @@ -208,6 +212,7 @@ struct Synth::Impl final: public Parser::Listener { // Names for the CC and notes as set by label_cc and label_key std::vector ccLabels_; + std::map ccLabelsMap_; std::vector keyLabels_; std::vector keyswitchLabels_; From 751e4f96bb2d21c8a7ed07f26b258fa1380ecca7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 14 Dec 2020 21:14:35 +0100 Subject: [PATCH 199/668] Add the reception of CC messages for editor --- editor/src/editor/Editor.cpp | 125 ++++++++++++++++++++++++++++++++++- src/sfizz/Synth.cpp | 20 +++--- src/sfizz/Synth.h | 3 +- src/sfizz/SynthMessaging.cpp | 9 +-- src/sfizz/SynthPrivate.h | 13 ++-- src/sfizz/utility/BitArray.h | 81 +++++++++++++++++++++++ tests/SynthT.cpp | 73 ++++++++++---------- 7 files changed, 263 insertions(+), 61 deletions(-) create mode 100644 src/sfizz/utility/BitArray.h diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 525689bf..72c99ed7 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -13,14 +13,17 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include #include +#include #include "utility/vstgui_before.h" #include "vstgui/vstgui.h" @@ -106,6 +109,13 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void uiReceiveValue(EditId id, const EditValue& v) override; void uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) override; + // queued OSC API; sends OSC with intermediate delay between messages + // to prevent message bursts overloading the buffer + void sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args); + void tickOSCQueue(CVSTGUITimer* timer); + std::queue oscSendQueue_; + SharedPointer oscSendQueueTimer_; + void createFrameContents(); template @@ -142,6 +152,10 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void updateTuningFrequencyLabel(float tuningFrequency); void updateStretchedTuningLabel(float stretchedTuning); + void updateCCUsed(unsigned cc, bool used); + void updateCCValue(unsigned cc, float value); + void updateCCLabel(unsigned cc, const char* label); + void setActivePanel(unsigned panelId); static void formatLabel(CTextLabel* label, const char* fmt, ...); @@ -164,6 +178,11 @@ Editor::Editor(EditorController& ctrl) ctrl.decorate(&impl); impl.createFrameContents(); + + uint32_t oscSendInterval = 1; // milliseconds + impl.oscSendQueueTimer_ = makeOwned( + [this](CVSTGUITimer* timer) { impl_->tickOSCQueue(timer); }, + oscSendInterval, false); } Editor::~Editor() @@ -182,6 +201,9 @@ void Editor::open(CFrame& frame) impl.frame_ = &frame; frame.addView(impl.mainView_.get()); + + // request the whole CC information + impl.sendQueuedOSC("/cc/slots", "", nullptr); } void Editor::close() @@ -336,9 +358,92 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) } } +/// +static constexpr unsigned kMessageMaxIndices = 8; + +static bool matchMessage(const char* pattern, const char* path, unsigned* indices) +{ + unsigned nthIndex = 0; + + while (const char *endp = strchr(pattern, '&')) { + if (nthIndex == kMessageMaxIndices) + return false; + + size_t length = endp - pattern; + if (strncmp(pattern, path, length)) + return false; + pattern += length; + path += length; + + length = 0; + while (absl::ascii_isdigit(path[length])) + ++length; + + if (!absl::SimpleAtoi(absl::string_view(path, length), &indices[nthIndex++])) + return false; + + pattern += 1; + path += length; + } + + return !strcmp(path, pattern); +} + +/// void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) { - // TODO handle the message... + unsigned indices[kMessageMaxIndices]; + + if (!strcmp(path, "/cc/slots") && !strcmp(sig, "b")) { + const uint8_t* bitChunks = args[0].b->data; + uint32_t byteSize = args[0].b->size; + + for (unsigned cc = 0; cc < 8 * byteSize; ++cc) { + bool used = bitChunks[cc / 8] & (1u << (cc % 8)); + updateCCUsed(cc, used); + if (used) { + char pathBuf[256]; + sprintf(pathBuf, "/cc%u/value", cc); + sendQueuedOSC(pathBuf, "", nullptr); + sprintf(pathBuf, "/cc%u/label", cc); + sendQueuedOSC(pathBuf, "", nullptr); + } + } + } + else if (matchMessage("/cc&/value", path, indices) && !strcmp(sig, "f")) { + updateCCValue(indices[0], args[0].f); + } + else if (matchMessage("/cc&/label", path, indices) && !strcmp(sig, "s")) { + updateCCLabel(indices[0], args[0].s); + } + else { + //fprintf(stderr, "Receive unhandled OSC: %s\n", path); + } +} + +void Editor::Impl::sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args) +{ + uint32_t oscSize = sfizz_prepare_message(nullptr, 0, path, sig, args); + std::string oscData(oscSize, '\0'); + sfizz_prepare_message(&oscData[0], oscSize, path, sig, args); + oscSendQueue_.push(std::move(oscData)); + oscSendQueueTimer_->start(); +} + +void Editor::Impl::tickOSCQueue(CVSTGUITimer* timer) +{ + if (oscSendQueue_.empty()) { + timer->stop(); + return; + } + const std::string& msg = oscSendQueue_.front(); + const char* path; + const char* sig; + const sfizz_arg_t* args; + uint8_t buffer[1024]; + if (sfizz_extract_message(msg.data(), msg.size(), buffer, sizeof(buffer), &path, &sig, &args) > 0) + ctrl_->uiSendMessage(path, sig, args); + oscSendQueue_.pop(); } void Editor::Impl::createFrameContents() @@ -1062,6 +1167,24 @@ void Editor::Impl::updateStretchedTuningLabel(float stretchedTuning) label->setText(text); } +void Editor::Impl::updateCCUsed(unsigned cc, bool used) +{ + // TODO + fprintf(stderr, "CC%u used: %d\n", cc, used); +} + +void Editor::Impl::updateCCValue(unsigned cc, float value) +{ + // TODO + fprintf(stderr, "CC%u value: %f\n", cc, value); +} + +void Editor::Impl::updateCCLabel(unsigned cc, const char* label) +{ + // TODO + fprintf(stderr, "CC%u label: %s\n", cc, label); +} + void Editor::Impl::setActivePanel(unsigned panelId) { panelId = std::max(0, std::min(kNumPanels - 1, static_cast(panelId))); diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index e50df231..6e736690 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -696,7 +696,7 @@ void Synth::Impl::finalizeSfzLoad() regions_.resize(currentRegionCount); // collect all CCs used in regions, with matrix not yet connected - std::bitset usedCCs; + BitArray usedCCs; for (const RegionPtr& regionPtr : regions_) { const Region& region = *regionPtr; collectUsedCCsFromRegion(usedCCs, region); @@ -1328,8 +1328,8 @@ std::string Synth::exportMidnam(absl::string_view model) const } } - for (unsigned i = 0, n = std::min(128, anonymousCCs.size()); i < n; ++i) { - if (anonymousCCs[i]) { + for (unsigned i = 0, n = std::min(128, anonymousCCs.bit_size()); i < n; ++i) { + if (anonymousCCs.test(i)) { pugi::xml_node cn = cns.append_child("Control"); cn.append_attribute("Type").set_value("7bit"); cn.append_attribute("Number").set_value(std::to_string(i).c_str()); @@ -1716,7 +1716,7 @@ void Synth::allSoundOff() noexcept effectBus->clear(); } -const std::bitset& Synth::getUsedCCs() const noexcept +const BitArray& Synth::getUsedCCs() const noexcept { Impl& impl = *impl_; return impl.currentUsedCCs_; @@ -1729,7 +1729,7 @@ void sfz::Synth::setBroadcastCallback(sfizz_receive_t* broadcast, void* data) impl.broadcastData = data; } -void Synth::Impl::collectUsedCCsFromRegion(std::bitset& usedCCs, const Region& region) +void Synth::Impl::collectUsedCCsFromRegion(BitArray& usedCCs, const Region& region) { collectUsedCCsFromCCMap(usedCCs, region.offsetCC); collectUsedCCsFromCCMap(usedCCs, region.amplitudeEG.ccAttack); @@ -1763,11 +1763,11 @@ void Synth::Impl::collectUsedCCsFromRegion(std::bitset& usedCCs, collectUsedCCsFromCCMap(usedCCs, region.crossfadeCCOutRange); } -void Synth::Impl::collectUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm) +void Synth::Impl::collectUsedCCsFromModulations(BitArray& usedCCs, const ModMatrix& mm) { class CCSourceCollector : public ModMatrix::KeyVisitor { public: - explicit CCSourceCollector(std::bitset& used) + explicit CCSourceCollector(BitArray& used) : used_(used) { } @@ -1778,16 +1778,16 @@ void Synth::Impl::collectUsedCCsFromModulations(std::bitset& use used_.set(key.parameters().cc); return true; } - std::bitset& used_; + BitArray& used_; }; CCSourceCollector vtor(usedCCs); mm.visitSources(vtor); } -std::bitset Synth::Impl::collectAllUsedCCs() +BitArray Synth::Impl::collectAllUsedCCs() { - std::bitset used; + BitArray used; for (const Impl::RegionPtr& region : regions_) collectUsedCCsFromRegion(used, *region); collectUsedCCsFromModulations(used, resources_.modMatrix); diff --git a/src/sfizz/Synth.h b/src/sfizz/Synth.h index 9afb3104..168900f9 100644 --- a/src/sfizz/Synth.h +++ b/src/sfizz/Synth.h @@ -17,6 +17,7 @@ #include #include #include +template class BitArray; namespace sfz { @@ -599,7 +600,7 @@ public: * * @return const std::bitset& */ - const std::bitset& getUsedCCs() const noexcept; + const BitArray& getUsedCCs() const noexcept; /** * @brief Dispatch the incoming message to the synth engine diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 68dbf362..9902b58b 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -39,13 +39,8 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co //---------------------------------------------------------------------- MATCH("/cc/slots", "") { - uint8_t data[(config::numCCs + 7) / 8] = {}; - - const std::bitset& ccs = impl.currentUsedCCs_; - for (unsigned i = 0; i < config::numCCs; ++i) - data[i / 8] |= ccs.test(i) << (i % 8); - - sfizz_blob_t blob { data, sizeof(data) }; + const BitArray& ccs = impl.currentUsedCCs_; + sfizz_blob_t blob { ccs.data(), static_cast(ccs.byte_size()) }; client.receive<'b'>(delay, path, &blob); } break; diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 43c5b5a8..893e436e 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -9,6 +9,7 @@ #include "modulations/sources/Controller.h" #include "modulations/sources/FlexEnvelope.h" #include "modulations/sources/LFO.h" +#include "utility/BitArray.h" namespace sfz { @@ -168,16 +169,16 @@ struct Synth::Impl final: public Parser::Listener { void finalizeSfzLoad(); template - static void collectUsedCCsFromCCMap(std::bitset& usedCCs, const CCMap map) noexcept + static void collectUsedCCsFromCCMap(BitArray& usedCCs, const CCMap map) noexcept { for (auto& mod : map) - usedCCs[mod.cc] = true; + usedCCs.set(mod.cc); } - static void collectUsedCCsFromRegion(std::bitset& usedCCs, const Region& region); - static void collectUsedCCsFromModulations(std::bitset& usedCCs, const ModMatrix& mm); + static void collectUsedCCsFromRegion(BitArray& usedCCs, const Region& region); + static void collectUsedCCsFromModulations(BitArray& usedCCs, const ModMatrix& mm); - std::bitset collectAllUsedCCs(); + BitArray collectAllUsedCCs(); const std::string* getCCLabel(int ccNumber); void setCCLabel(int ccNumber, std::string name); @@ -283,7 +284,7 @@ struct Synth::Impl final: public Parser::Listener { absl::optional modificationTime_ { }; std::array defaultCCValues_; - std::bitset currentUsedCCs_; + BitArray currentUsedCCs_; // Messaging sfizz_receive_t* broadcastReceiver = nullptr; diff --git a/src/sfizz/utility/BitArray.h b/src/sfizz/utility/BitArray.h new file mode 100644 index 00000000..020a7433 --- /dev/null +++ b/src/sfizz/utility/BitArray.h @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include +#include + +/// +class ConstBitSpan { +public: + ConstBitSpan() noexcept = default; + ConstBitSpan(const uint8_t* data, size_t bits) noexcept : data_(data), bits_(bits) {} + const uint8_t* data() const noexcept { return data_; } + size_t bit_size() const noexcept { return bits_; } + size_t byte_size() const noexcept { return (bits_ + 7) / 8; } + bool test(size_t i) const noexcept { return data_[i / 8] & (1u << (i % 8)); } + bool all() const noexcept + { + size_t n = bits_; + for (size_t i = 0; i < n / 8; ++i) { + if (data_[i] != 0xff) + return false; + } + return n % 8 == 0 || data_[n / 8] == (1u << (n % 8)) - 1u; + } + bool any() const noexcept + { + size_t n = bits_; + for (size_t i = 0; i < n / 8; ++i) { + if (data_[i] != 0x00) + return true; + } + return n % 8 != 0 && (data_[n / 8] & ((1u << (n % 8)) - 1u)) != 0; + } + bool none() const noexcept { return !any(); } + +private: + const uint8_t* data_ = nullptr; + size_t bits_ = 0; +}; + +/// +class BitSpan : public ConstBitSpan { +public: + BitSpan() noexcept = default; + BitSpan(const uint8_t* data, size_t bits) noexcept : ConstBitSpan(data, bits) {} + uint8_t* data() const noexcept { return const_cast(ConstBitSpan::data()); } + void clear() { memset(data(), 0, byte_size()); } + void set(size_t i) noexcept { data()[i / 8] |= 1u << (i % 8); } + void set(size_t i, bool b) noexcept { if (b) set(i); else reset(i); } + void reset(size_t i) noexcept { data()[i / 8] &= ~(1u << (i % 8)); } + void flip(size_t i) noexcept { data()[i / 8] ^= 1u << (i % 8); } +}; + +/// +template +class BitArray { +public: + BitArray() noexcept = default; + uint8_t* data() noexcept { return data_; } + const uint8_t* data() const noexcept { return data_; } + static constexpr size_t bit_size() noexcept { return N; } + static constexpr size_t byte_size() noexcept { return (N + 7) / 8; } + BitSpan span() noexcept { return BitSpan(data_, N); }; + ConstBitSpan span() const noexcept { return ConstBitSpan(data_, N); }; + bool test(size_t i) const noexcept { return span().test(i); } + void set(size_t i) noexcept { span().set(i); } + void set(size_t i, bool b) noexcept { span().set(i, b); } + void reset(size_t i) noexcept { span().reset(i); } + void flip(size_t i) noexcept { span().flip(i); } + bool all() const noexcept { return span().all(); } + bool any() const noexcept { return span().any(); } + bool none() const noexcept { return span().none(); } + +private: + uint8_t data_[byte_size()] {}; +}; diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index 5565d5ff..b9bf7ab8 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -8,6 +8,7 @@ #include "sfizz/SisterVoiceRing.h" #include "sfizz/SfzHelpers.h" #include "sfizz/utility/NumericId.h" +#include "sfizz/utility/BitArray.h" #include "TestHelpers.h" #include #include "catch2/catch.hpp" @@ -1087,18 +1088,18 @@ TEST_CASE("[Synth] Used CCs") start_locc44=200 hikey=-1 sample=*sine )"); auto usedCCs = synth.getUsedCCs(); - REQUIRE( usedCCs[1] ); - REQUIRE( usedCCs[2] ); - REQUIRE( !usedCCs[3] ); - REQUIRE( usedCCs[4] ); - REQUIRE( usedCCs[5] ); - REQUIRE( !usedCCs[6] ); - REQUIRE( usedCCs[42] ); - REQUIRE( usedCCs[44] ); - REQUIRE( usedCCs[56] ); - REQUIRE( usedCCs[67] ); - REQUIRE( usedCCs[98] ); - REQUIRE( !usedCCs[127] ); + REQUIRE( usedCCs.test(1) ); + REQUIRE( usedCCs.test(2) ); + REQUIRE( !usedCCs.test(3) ); + REQUIRE( usedCCs.test(4) ); + REQUIRE( usedCCs.test(5) ); + REQUIRE( !usedCCs.test(6) ); + REQUIRE( usedCCs.test(42) ); + REQUIRE( usedCCs.test(44) ); + REQUIRE( usedCCs.test(56) ); + REQUIRE( usedCCs.test(67) ); + REQUIRE( usedCCs.test(98) ); + REQUIRE( !usedCCs.test(127) ); } TEST_CASE("[Synth] Used CCs EGs") @@ -1135,31 +1136,31 @@ TEST_CASE("[Synth] Used CCs EGs") sample=*sine )"); auto usedCCs = synth.getUsedCCs(); - REQUIRE( usedCCs[1] ); - REQUIRE( usedCCs[2] ); - REQUIRE( usedCCs[3] ); - REQUIRE( usedCCs[4] ); - REQUIRE( usedCCs[5] ); - REQUIRE( usedCCs[6] ); - REQUIRE( usedCCs[7] ); + REQUIRE( usedCCs.test(1) ); + REQUIRE( usedCCs.test(2) ); + REQUIRE( usedCCs.test(3) ); + REQUIRE( usedCCs.test(4) ); + REQUIRE( usedCCs.test(5) ); + REQUIRE( usedCCs.test(6) ); + REQUIRE( usedCCs.test(7) ); // FIXME: enable when supported - // REQUIRE( !usedCCs[8] ); - // REQUIRE( usedCCs[11] ); - // REQUIRE( usedCCs[12] ); - // REQUIRE( usedCCs[13] ); - // REQUIRE( usedCCs[14] ); - // REQUIRE( usedCCs[15] ); - // REQUIRE( usedCCs[16] ); - // REQUIRE( usedCCs[17] ); - // REQUIRE( !usedCCs[18] ); - // REQUIRE( usedCCs[21] ); - // REQUIRE( usedCCs[22] ); - // REQUIRE( usedCCs[23] ); - // REQUIRE( usedCCs[24] ); - // REQUIRE( usedCCs[25] ); - // REQUIRE( usedCCs[26] ); - // REQUIRE( usedCCs[27] ); - // REQUIRE( !usedCCs[28] ); + // REQUIRE( !usedCCs.test(8) ); + // REQUIRE( usedCCs.test(11) ); + // REQUIRE( usedCCs.test(12) ); + // REQUIRE( usedCCs.test(13) ); + // REQUIRE( usedCCs.test(14) ); + // REQUIRE( usedCCs.test(15) ); + // REQUIRE( usedCCs.test(16) ); + // REQUIRE( usedCCs.test(17) ); + // REQUIRE( !usedCCs.test(18) ); + // REQUIRE( usedCCs.test(21) ); + // REQUIRE( usedCCs.test(22) ); + // REQUIRE( usedCCs.test(23) ); + // REQUIRE( usedCCs.test(24) ); + // REQUIRE( usedCCs.test(25) ); + // REQUIRE( usedCCs.test(26) ); + // REQUIRE( usedCCs.test(27) ); + // REQUIRE( !usedCCs.test(28) ); } TEST_CASE("[Synth] Activate also on the sustain CC") From 2ede8fd710c661529e73a35dfa866f6e99550777 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 02:05:50 +0100 Subject: [PATCH 200/668] User interface with CC knobs --- editor/layout/main.fl | 19 ++- editor/src/editor/Editor.cpp | 57 +++++++- editor/src/editor/GUIComponents.cpp | 206 ++++++++++++++++++++++++++++ editor/src/editor/GUIComponents.h | 58 ++++++++ editor/src/editor/layout/main.hpp | 5 +- 5 files changed, 327 insertions(+), 18 deletions(-) diff --git a/editor/layout/main.fl b/editor/layout/main.fl index 59ed5298..b96960f6 100644 --- a/editor/layout/main.fl +++ b/editor/layout/main.fl @@ -3,7 +3,7 @@ version 1.0305 header_name {.h} code_name {.cxx} widget_class mainView {open - xywh {576 416 800 475} type Double + xywh {571 362 800 475} type Double class LogicalGroup visible } { Fl_Box {} { @@ -197,23 +197,22 @@ widget_class mainView {open } } } - Fl_Group {subPanels_[kPanelControls]} { - xywh {5 110 790 285} hide + Fl_Group {subPanels_[kPanelControls]} {open + xywh {5 110 790 285} class LogicalGroup } { Fl_Group {} {open xywh {5 110 790 285} box ROUNDED_BOX class RoundedGroup } { - Fl_Box {} { - label {Controls not available} - xywh {5 110 790 285} labelsize 40 - class Label - } + Fl_Group controlsPanel_ {open selected + xywh {5 110 790 285} box THIN_DOWN_FRAME + class ControlsPanel + } {} } } Fl_Group {subPanels_[kPanelSettings]} {open - xywh {5 109 790 316} + xywh {5 109 790 316} hide class LogicalGroup } { Fl_Group {} { @@ -305,7 +304,7 @@ widget_class mainView {open } } Fl_Group userFilesGroup_ { - label Files open selected + label Files open xywh {620 270 139 100} box ROUNDED_BOX labelsize 12 align 17 class TitleGroup } { diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 72c99ed7..3390e290 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -106,6 +106,8 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { SPiano* piano_ = nullptr; + SControlsPanel* controlsPanel_ = nullptr; + void uiReceiveValue(EditId id, const EditValue& v) override; void uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) override; @@ -156,6 +158,11 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void updateCCValue(unsigned cc, float value); void updateCCLabel(unsigned cc, const char* label); + // edition of CC by UI + void performCCValueChange(unsigned cc, float value); + void performCCBeginEdit(unsigned cc); + void performCCEndEdit(unsigned cc); + void setActivePanel(unsigned panelId); static void formatLabel(CTextLabel* label, const char* fmt, ...); @@ -533,6 +540,7 @@ void Editor::Impl::createFrameContents() typedef STextButton NextFileButton; typedef SPiano Piano; typedef SActionMenu ChevronDropDown; + typedef SControlsPanel ControlsPanel; auto createLogicalGroup = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { CViewContainer* container = new CViewContainer(bounds); @@ -706,6 +714,10 @@ void Editor::Impl::createFrameContents() container->setBackground(background); return container; }; + auto createControlsPanel = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { + auto* panel = new SControlsPanel(bounds); + return panel; + }; #include "layout/main.hpp" @@ -844,6 +856,18 @@ void Editor::Impl::createFrameContents() }; } + if (SControlsPanel* panel = controlsPanel_) { + panel->ValueChangeFunction = [this](uint32_t cc, float value) { + performCCValueChange(cc, value); + }; + panel->BeginEditFunction = [this](uint32_t cc) { + performCCBeginEdit(cc); + }; + panel->EndEditFunction = [this](uint32_t cc) { + performCCEndEdit(cc); + }; + } + /// CViewContainer* panel; activePanel_ = 0; @@ -1169,20 +1193,41 @@ void Editor::Impl::updateStretchedTuningLabel(float stretchedTuning) void Editor::Impl::updateCCUsed(unsigned cc, bool used) { - // TODO - fprintf(stderr, "CC%u used: %d\n", cc, used); + if (SControlsPanel* panel = controlsPanel_) + panel->setControlUsed(cc, used); } void Editor::Impl::updateCCValue(unsigned cc, float value) { - // TODO - fprintf(stderr, "CC%u value: %f\n", cc, value); + if (SControlsPanel* panel = controlsPanel_) + panel->setControlValue(cc, value); } void Editor::Impl::updateCCLabel(unsigned cc, const char* label) { - // TODO - fprintf(stderr, "CC%u label: %s\n", cc, label); + if (SControlsPanel* panel = controlsPanel_) + panel->setControlLabelText(cc, label); +} + +void Editor::Impl::performCCValueChange(unsigned cc, float value) +{ + // TODO(jpc) CC as parameters and automation + + char pathBuf[256]; + sprintf(pathBuf, "/cc%u/value", cc); + sfizz_arg_t args[1]; + args[0].f = value; + sendQueuedOSC(pathBuf, "f", args); +} + +void Editor::Impl::performCCBeginEdit(unsigned cc) +{ + // TODO(jpc) CC as parameters and automation +} + +void Editor::Impl::performCCEndEdit(unsigned cc) +{ + // TODO(jpc) CC as parameters and automation } void Editor::Impl::setActivePanel(unsigned panelId) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 16ad7dd9..5f7f7e0f 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -516,3 +516,209 @@ void SStyledKnob::draw(CDrawContext* dc) dc->drawLine(p1, p2); } } + +/// +SControlsPanel::SControlsPanel(const CRect& size) + : CScrollView( + size, CRect(), + CScrollView::kVerticalScrollbar|CScrollView::kDontDrawFrame|CScrollView::kAutoHideScrollbars), + listener_(new ControlSlotListener(this)) +{ + setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); + + setScrollbarWidth(10.0); +} + +void SControlsPanel::setControlUsed(uint32_t index, bool used) +{ + bool changed = false; + + if (used) { + if (index + 1 > slots_.size()) + slots_.resize(index + 1); + ControlSlot* slot = slots_[index].get(); + changed = !slot; + if (changed) { + slot = new ControlSlot; + slots_[index].reset(slot); + + // create controls etc... + CCoord knobWidth = 48.0; + CCoord knobHeight = 72.0; + CCoord labelWidth = 96.0; + CCoord labelHeight = 24.0; + CCoord verticalPadding = -12.0; + + CCoord totalWidth = std::max(knobWidth, labelWidth); + CCoord knobX = (totalWidth - knobWidth) / 2.0; + CCoord labelX = (totalWidth - labelWidth) / 2.0; + + CRect knobBounds(knobX, 0.0, knobX + knobWidth, knobHeight); + CRect labelBounds(labelX, knobHeight + verticalPadding, labelX + labelWidth, knobHeight + verticalPadding + labelHeight); + CRect boxBounds = CRect(knobBounds).unite(labelBounds); + + SharedPointer knob = owned(new SStyledKnob(knobBounds, listener_.get(), index)); + SharedPointer label = owned(new CTextLabel(labelBounds)); + SharedPointer box = owned(new CViewContainer(boxBounds)); + + box->addView(knob); + knob->remember(); + box->addView(label); + label->remember(); + + box->setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setStyle(CTextLabel::kRoundRectStyle); + label->setRoundRectRadius(5.0); + label->setBackColor(CColor(0x2e, 0x34, 0x36)); + label->setText(("CC " + std::to_string(index)).c_str()); + knob->setActiveTrackColor(CColor(0x00, 0xb6, 0x2a)); + knob->setInactiveTrackColor(CColor(0x30, 0x30, 0x30)); + knob->setLineIndicatorColor(CColor(0x00, 0x00, 0x00)); + + slot->knob = knob; + slot->label = label; + slot->box = box; + } + } + else { + if (index < slots_.size() && slots_[index]) { + changed = true; + slots_[index].reset(); + } + } + + if (changed) + updateLayout(); +} + +void SControlsPanel::setControlValue(uint32_t index, float value) +{ + if (index >= slots_.size()) + return; + + ControlSlot* slot = slots_[index].get(); + if (!slot) + return; + + slot->knob->setValue(value); +} + +void SControlsPanel::setControlLabelText(uint32_t index, UTF8StringPtr text) +{ + if (index >= slots_.size()) + return; + + ControlSlot* slot = slots_[index].get(); + if (!slot) + return; + + slot->label->setText(text); +} + +void SControlsPanel::recalculateSubViews() +{ + CScrollView::recalculateSubViews(); + + // maybe the operation just created the scroll bar + if (CScrollbar* vsb = getVerticalScrollbar()) { + // update scrollbar style + vsb->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + vsb->setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); + vsb->setScrollerColor(CColor(0x00, 0x00, 0x00, 0x80)); + } +} + +void SControlsPanel::updateLayout() +{ + removeAll(); + + const CRect viewBounds = getViewSize(); + + bool isFirstSlot = true; + CCoord itemWidth {}; + CCoord itemHeight {}; + CCoord itemOffsetX {}; + + int numColumns {}; + const CCoord horizontalPadding = 24.0; + const CCoord verticalPadding = 5.0; + + int currentRow = 0; + int currentColumn = 0; + int containerBottom = 0; + + uint32_t numSlots = static_cast(slots_.size()); + for (uint32_t i = 0; i < numSlots; ++i) { + ControlSlot* slot = slots_[i].get(); + if (!slot) + continue; + + CViewContainer* box = slot->box; + + if (isFirstSlot) { + itemWidth = box->getWidth(); + itemHeight = box->getHeight(); + isFirstSlot = false; + numColumns = int((viewBounds.getWidth() - horizontalPadding) / + (itemWidth + horizontalPadding)); + numColumns = std::max(1, numColumns); + itemOffsetX = (viewBounds.getWidth() - horizontalPadding - + numColumns * (itemWidth + horizontalPadding)) / 2.0; + } + + CRect itemBounds = box->getViewSize(); + itemBounds.moveTo( + itemOffsetX + horizontalPadding + currentColumn * (horizontalPadding + itemWidth), + verticalPadding + currentRow * (verticalPadding + itemHeight)); + + box->setViewSize(itemBounds); + + containerBottom = itemBounds.bottom; + + addView(box); + box->remember(); + + if (++currentColumn == numColumns) { + currentColumn = 0; + ++currentRow; + } + } + + CRect containerSize = getContainerSize(); + containerSize.bottom = containerBottom; + setContainerSize(CRect(0.0, 0.0, viewBounds.getWidth(), containerBottom + verticalPadding)); +} + +void SControlsPanel::ControlSlotListener::valueChanged(CControl* pControl) +{ + if (panel_->ValueChangeFunction) + panel_->ValueChangeFunction(pControl->getTag(), pControl->getValue()); +} + +void SControlsPanel::ControlSlotListener::controlBeginEdit(CControl* pControl) +{ + if (panel_->BeginEditFunction) + panel_->BeginEditFunction(pControl->getTag()); +} + +void SControlsPanel::ControlSlotListener::controlEndEdit(CControl* pControl) +{ + if (panel_->EndEditFunction) + panel_->EndEditFunction(pControl->getTag()); +} + +/// +SPlaceHolder::SPlaceHolder(const CRect& size, const CColor& color) + : CView(size), color_(color) +{ +} + +void SPlaceHolder::draw(CDrawContext* dc) +{ + const CRect bounds = getViewSize(); + dc->setDrawMode(kAliasing); + dc->setFrameColor(color_); + dc->drawRect(bounds); + dc->drawLine(bounds.getTopLeft(), bounds.getBottomRight()); + dc->drawLine(bounds.getTopRight(), bounds.getBottomLeft()); +} diff --git a/editor/src/editor/GUIComponents.h b/editor/src/editor/GUIComponents.h index 8f497a15..a5899550 100644 --- a/editor/src/editor/GUIComponents.h +++ b/editor/src/editor/GUIComponents.h @@ -6,6 +6,9 @@ #pragma once #include +#include +#include +#include #include "utility/vstgui_before.h" #include "vstgui/lib/controls/cslider.h" @@ -13,8 +16,10 @@ #include "vstgui/lib/controls/ctextlabel.h" #include "vstgui/lib/controls/cbuttons.h" #include "vstgui/lib/controls/coptionmenu.h" +#include "vstgui/lib/controls/cscrollbar.h" #include "vstgui/lib/controls/icontrollistener.h" #include "vstgui/lib/cviewcontainer.h" +#include "vstgui/lib/cscrollview.h" #include "vstgui/lib/ccolor.h" #include "vstgui/lib/dragging.h" #include "utility/vstgui_after.h" @@ -210,3 +215,56 @@ private: CColor inactiveTrackColor_; CColor lineIndicatorColor_; }; + +/// +class SControlsPanel : public CScrollView { +public: + explicit SControlsPanel(const CRect& size); + + void setControlUsed(uint32_t index, bool used); + void setControlValue(uint32_t index, float value); + void setControlLabelText(uint32_t index, UTF8StringPtr text); + + std::function ValueChangeFunction; + std::function BeginEditFunction; + std::function EndEditFunction; + +protected: + void recalculateSubViews() override; + +private: + void updateLayout(); + +private: + struct ControlSlot { + SharedPointer knob; + SharedPointer label; + SharedPointer box; + }; + + class ControlSlotListener : public IControlListener { + public: + explicit ControlSlotListener(SControlsPanel* panel) : panel_(panel) {} + void valueChanged(CControl* pControl) override; + void controlBeginEdit(CControl* pControl) override; + void controlEndEdit(CControl* pControl) override; + + private: + SControlsPanel* panel_ = nullptr; + }; + + std::vector> slots_; + std::unique_ptr listener_; +}; + +/// +class SPlaceHolder : public CView { +public: + explicit SPlaceHolder(const CRect& size, const CColor& color = {0xff, 0x00, 0x00, 0xff}); + +protected: + void draw(CDrawContext* dc) override; + +private: + CColor color_; +}; diff --git a/editor/src/editor/layout/main.hpp b/editor/src/editor/layout/main.hpp index 6f4da9e3..6ea0a316 100644 --- a/editor/src/editor/layout/main.hpp +++ b/editor/src/editor/layout/main.hpp @@ -100,14 +100,15 @@ view__29->addView(view__39); LogicalGroup* const view__40 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); subPanels_[kPanelControls] = view__40; view__0->addView(view__40); -view__40->setVisible(false); RoundedGroup* const view__41 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); view__40->addView(view__41); -Label* const view__42 = createLabel(CRect(0, 0, 790, 285), -1, "Controls not available", kCenterText, 40); +ControlsPanel* const view__42 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); +controlsPanel_ = view__42; view__41->addView(view__42); LogicalGroup* const view__43 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); subPanels_[kPanelSettings] = view__43; view__0->addView(view__43); +view__43->setVisible(false); TitleGroup* const view__44 = createTitleGroup(CRect(255, 26, 535, 126), -1, "Engine", kCenterText, 12); view__43->addView(view__44); ValueMenu* const view__45 = createValueMenu(CRect(25, 60, 85, 85), kTagSetNumVoices, "", kCenterText, 12); From 80eb73f4cb41169c5bf83b5f165667209ee0fa14 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 11:39:26 +0100 Subject: [PATCH 201/668] Also receive CC default value --- editor/src/editor/Editor.cpp | 12 ++++++++++++ editor/src/editor/GUIComponents.cpp | 12 ++++++++++++ editor/src/editor/GUIComponents.h | 1 + 3 files changed, 25 insertions(+) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 3390e290..21462e79 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -156,6 +156,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void updateCCUsed(unsigned cc, bool used); void updateCCValue(unsigned cc, float value); + void updateCCDefaultValue(unsigned cc, float value); void updateCCLabel(unsigned cc, const char* label); // edition of CC by UI @@ -412,6 +413,8 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi char pathBuf[256]; sprintf(pathBuf, "/cc%u/value", cc); sendQueuedOSC(pathBuf, "", nullptr); + sprintf(pathBuf, "/cc%u/default", cc); + sendQueuedOSC(pathBuf, "", nullptr); sprintf(pathBuf, "/cc%u/label", cc); sendQueuedOSC(pathBuf, "", nullptr); } @@ -420,6 +423,9 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi else if (matchMessage("/cc&/value", path, indices) && !strcmp(sig, "f")) { updateCCValue(indices[0], args[0].f); } + else if (matchMessage("/cc&/default", path, indices) && !strcmp(sig, "f")) { + updateCCDefaultValue(indices[0], args[0].f); + } else if (matchMessage("/cc&/label", path, indices) && !strcmp(sig, "s")) { updateCCLabel(indices[0], args[0].s); } @@ -1203,6 +1209,12 @@ void Editor::Impl::updateCCValue(unsigned cc, float value) panel->setControlValue(cc, value); } +void Editor::Impl::updateCCDefaultValue(unsigned cc, float value) +{ + if (SControlsPanel* panel = controlsPanel_) + panel->setControlDefaultValue(cc, value); +} + void Editor::Impl::updateCCLabel(unsigned cc, const char* label) { if (SControlsPanel* panel = controlsPanel_) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 5f7f7e0f..24efe68b 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -603,6 +603,18 @@ void SControlsPanel::setControlValue(uint32_t index, float value) slot->knob->setValue(value); } +void SControlsPanel::setControlDefaultValue(uint32_t index, float value) +{ + if (index >= slots_.size()) + return; + + ControlSlot* slot = slots_[index].get(); + if (!slot) + return; + + slot->knob->setDefaultValue(value); +} + void SControlsPanel::setControlLabelText(uint32_t index, UTF8StringPtr text) { if (index >= slots_.size()) diff --git a/editor/src/editor/GUIComponents.h b/editor/src/editor/GUIComponents.h index a5899550..5ba9a6df 100644 --- a/editor/src/editor/GUIComponents.h +++ b/editor/src/editor/GUIComponents.h @@ -223,6 +223,7 @@ public: void setControlUsed(uint32_t index, bool used); void setControlValue(uint32_t index, float value); + void setControlDefaultValue(uint32_t index, float value); void setControlLabelText(uint32_t index, UTF8StringPtr text); std::function ValueChangeFunction; From 4c833b17491a1bb3ff990a2edd4f436b05ec2c5d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 11:48:43 +0100 Subject: [PATCH 202/668] Workaround for knob behavior --- editor/src/editor/GUIComponents.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 24efe68b..36217278 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -544,10 +544,10 @@ void SControlsPanel::setControlUsed(uint32_t index, bool used) // create controls etc... CCoord knobWidth = 48.0; - CCoord knobHeight = 72.0; + CCoord knobHeight = knobWidth; CCoord labelWidth = 96.0; CCoord labelHeight = 24.0; - CCoord verticalPadding = -12.0; + CCoord verticalPadding = 0.0; CCoord totalWidth = std::max(knobWidth, labelWidth); CCoord knobX = (totalWidth - knobWidth) / 2.0; @@ -653,7 +653,7 @@ void SControlsPanel::updateLayout() int numColumns {}; const CCoord horizontalPadding = 24.0; - const CCoord verticalPadding = 5.0; + const CCoord verticalPadding = 18.0; int currentRow = 0; int currentColumn = 0; From 27ec95566a28e10b3f213786a2665ce8de0152a3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 14:30:16 +0100 Subject: [PATCH 203/668] Notify editor of CC changed by MIDI --- editor/src/editor/Editor.cpp | 12 ++++++++++++ src/sfizz/Synth.cpp | 20 +++++++++++++++++++- src/sfizz/SynthPrivate.h | 8 ++++++++ src/sfizz/utility/BitArray.h | 1 + 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 21462e79..128dd9df 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -420,6 +420,18 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi } } } + else if (!strcmp(path, "/cc/changed") && !strcmp(sig, "b")) { + const uint8_t* bitChunks = args[0].b->data; + uint32_t byteSize = args[0].b->size; + for (unsigned cc = 0; cc < 8 * byteSize; ++cc) { + bool changed = bitChunks[cc / 8] & (1u << (cc % 8)); + if (changed) { + char pathBuf[256]; + sprintf(pathBuf, "/cc%u/value", cc); + sendQueuedOSC(pathBuf, "", nullptr); + } + } + } else if (matchMessage("/cc&/value", path, indices) && !strcmp(sig, "f")) { updateCCValue(indices[0], args[0].f); } diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 6e736690..d9ecb85e 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -245,6 +245,8 @@ void Synth::Impl::clear() resources_.filePool.clear(); resources_.filePool.setRamLoading(config::loadInRam); clearCCLabels(); + currentUsedCCs_.clear(); + changedCCsThisCycle_.clear(); keyLabels_.clear(); keyswitchLabels_.clear(); globalOpcodes_.clear(); @@ -855,6 +857,12 @@ void Synth::renderBlock(AudioSpan buffer) noexcept buffer.fill(0.0f); } + const size_t numFrames = buffer.getNumFrames(); + if (numFrames < 1) { + CHECKFALSE; + return; + } + if (impl.resources_.synthConfig.freeWheeling) impl.resources_.filePool.waitForBackgroundLoading(); @@ -867,7 +875,6 @@ void Synth::renderBlock(AudioSpan buffer) noexcept impl.resources_.filePool.triggerGarbageCollection(); } - size_t numFrames = buffer.getNumFrames(); auto tempSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames); auto tempMixSpan = impl.resources_.bufferPool.getStereoBuffer(numFrames); auto rampSpan = impl.resources_.bufferPool.getBuffer(numFrames); @@ -958,6 +965,15 @@ void Synth::renderBlock(AudioSpan buffer) noexcept // Advance the clock to the end of cycle bc.endCycle(); + // Send the set of changed CCs + Client broadcaster = impl.getBroadcaster(); + const BitArray& changedCCs = impl.changedCCsThisCycle_; + if (broadcaster.canReceive()) { + sfizz_blob_t blob { changedCCs.data(), static_cast(changedCCs.byte_size()) }; + broadcaster.receive<'b'>(numFrames - 1, "/cc/changed", &blob); + } + impl.changedCCsThisCycle_.clear(); + { // Clear events and advance midi time ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; impl.resources_.midiState.advanceTime(buffer.getNumFrames()); @@ -1137,6 +1153,8 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM ScopedTiming logger { dispatchDuration_, ScopedTiming::Operation::addToDuration }; resources_.midiState.ccEvent(delay, ccNumber, normValue); + changedCCsThisCycle_.set(ccNumber); + if (asMidi) { if (ccNumber == config::resetCC) { resetAllControllers(delay); diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 893e436e..0e251024 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -285,10 +285,18 @@ struct Synth::Impl final: public Parser::Listener { std::array defaultCCValues_; BitArray currentUsedCCs_; + BitArray changedCCsThisCycle_; // Messaging sfizz_receive_t* broadcastReceiver = nullptr; void* broadcastData = nullptr; + + Client getBroadcaster() const + { + Client client(broadcastData); + client.setReceiveCallback(broadcastReceiver); + return client; + } }; } // namespace sfz diff --git a/src/sfizz/utility/BitArray.h b/src/sfizz/utility/BitArray.h index 020a7433..a55dccaf 100644 --- a/src/sfizz/utility/BitArray.h +++ b/src/sfizz/utility/BitArray.h @@ -67,6 +67,7 @@ public: static constexpr size_t byte_size() noexcept { return (N + 7) / 8; } BitSpan span() noexcept { return BitSpan(data_, N); }; ConstBitSpan span() const noexcept { return ConstBitSpan(data_, N); }; + void clear() { span().clear(); } bool test(size_t i) const noexcept { return span().test(i); } void set(size_t i) noexcept { span().set(i); } void set(size_t i, bool b) noexcept { span().set(i, b); } From 3a70c37d931cab7972a3839205dec6571e2c2db3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 14:37:07 +0100 Subject: [PATCH 204/668] Default text for CC labels --- editor/src/editor/GUIComponents.cpp | 12 ++++++++++-- editor/src/editor/GUIComponents.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 36217278..157b6b49 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -570,7 +570,7 @@ void SControlsPanel::setControlUsed(uint32_t index, bool used) label->setStyle(CTextLabel::kRoundRectStyle); label->setRoundRectRadius(5.0); label->setBackColor(CColor(0x2e, 0x34, 0x36)); - label->setText(("CC " + std::to_string(index)).c_str()); + label->setText(getDefaultLabelText(index)); knob->setActiveTrackColor(CColor(0x00, 0xb6, 0x2a)); knob->setInactiveTrackColor(CColor(0x30, 0x30, 0x30)); knob->setLineIndicatorColor(CColor(0x00, 0x00, 0x00)); @@ -591,6 +591,11 @@ void SControlsPanel::setControlUsed(uint32_t index, bool used) updateLayout(); } +std::string SControlsPanel::getDefaultLabelText(uint32_t index) +{ + return "CC " + std::to_string(index); +} + void SControlsPanel::setControlValue(uint32_t index, float value) { if (index >= slots_.size()) @@ -624,7 +629,10 @@ void SControlsPanel::setControlLabelText(uint32_t index, UTF8StringPtr text) if (!slot) return; - slot->label->setText(text); + if (text && text[0] != '\0') + slot->label->setText(text); + else + slot->label->setText(getDefaultLabelText(index).c_str()); } void SControlsPanel::recalculateSubViews() diff --git a/editor/src/editor/GUIComponents.h b/editor/src/editor/GUIComponents.h index 5ba9a6df..e2c987f6 100644 --- a/editor/src/editor/GUIComponents.h +++ b/editor/src/editor/GUIComponents.h @@ -235,6 +235,7 @@ protected: private: void updateLayout(); + static std::string getDefaultLabelText(uint32_t index); private: struct ControlSlot { From 20d5d93b7ec47d57d7ee3be3226c97f59e024efe Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 14:41:16 +0100 Subject: [PATCH 205/668] Request all CC slots on file change --- editor/src/editor/Editor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 128dd9df..01923b98 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -924,6 +924,9 @@ void Editor::Impl::changeSfzFile(const std::string& filePath) ctrl_->uiSendValue(EditId::SfzFile, filePath); currentSfzFile_ = filePath; updateSfzFileLabel(filePath); + + // request the whole CC information + sendQueuedOSC("/cc/slots", "", nullptr); } void Editor::Impl::changeToNextSfzFile(long offset) From fb012c4bf8e60da3f85cc53f6770a969496a8aaa Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 14:42:24 +0100 Subject: [PATCH 206/668] Redraw CC panel on layout --- editor/src/editor/GUIComponents.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 157b6b49..3f126dcb 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -707,6 +707,8 @@ void SControlsPanel::updateLayout() CRect containerSize = getContainerSize(); containerSize.bottom = containerBottom; setContainerSize(CRect(0.0, 0.0, viewBounds.getWidth(), containerBottom + verticalPadding)); + + invalid(); } void SControlsPanel::ControlSlotListener::valueChanged(CControl* pControl) From 36672546bc9892cb4b390ce1788e4c3d6252703f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 14:54:21 +0100 Subject: [PATCH 207/668] Update CC slots on SFZ file changed externally (LV2) --- editor/src/editor/Editor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 01923b98..ed85232f 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -232,6 +232,9 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) const std::string& value = v.to_string(); currentSfzFile_ = value; updateSfzFileLabel(value); + + // request the whole CC information + sendQueuedOSC("/cc/slots", "", nullptr); } break; case EditId::Volume: From 660dcb01d11153c687588d989ae7b3d138415528 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 15:22:08 +0100 Subject: [PATCH 208/668] Fix: do not activate the timer while UI is closed --- editor/src/editor/Editor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index ed85232f..69d0f0ff 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -451,6 +451,9 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi void Editor::Impl::sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args) { + if (!frame_) + return; + uint32_t oscSize = sfizz_prepare_message(nullptr, 0, path, sig, args); std::string oscData(oscSize, '\0'); sfizz_prepare_message(&oscData[0], oscSize, path, sig, args); From 787f388a268050c24b30fe8dd01ff0927368eb43 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 15:25:33 +0100 Subject: [PATCH 209/668] Invalidate the controls after changes --- editor/src/editor/GUIComponents.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 3f126dcb..5051e952 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -606,6 +606,7 @@ void SControlsPanel::setControlValue(uint32_t index, float value) return; slot->knob->setValue(value); + slot->knob->invalid(); } void SControlsPanel::setControlDefaultValue(uint32_t index, float value) @@ -633,6 +634,7 @@ void SControlsPanel::setControlLabelText(uint32_t index, UTF8StringPtr text) slot->label->setText(text); else slot->label->setText(getDefaultLabelText(index).c_str()); + slot->label->invalid(); } void SControlsPanel::recalculateSubViews() From e431591d418fc528b95f769e20f6dead38e521ad Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 16:00:45 +0100 Subject: [PATCH 210/668] Clear OSC queue on editor closed --- editor/src/editor/Editor.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 69d0f0ff..a8a90650 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -114,6 +114,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { // queued OSC API; sends OSC with intermediate delay between messages // to prevent message bursts overloading the buffer void sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args); + void clearQueuedOSC(); void tickOSCQueue(CVSTGUITimer* timer); std::queue oscSendQueue_; SharedPointer oscSendQueueTimer_; @@ -218,6 +219,8 @@ void Editor::close() { Impl& impl = *impl_; + impl.clearQueuedOSC(); + if (impl.frame_) { impl.frame_->removeView(impl.mainView_.get(), false); impl.frame_ = nullptr; @@ -461,6 +464,12 @@ void Editor::Impl::sendQueuedOSC(const char* path, const char* sig, const sfizz_ oscSendQueueTimer_->start(); } +void Editor::Impl::clearQueuedOSC() +{ + while (!oscSendQueue_.empty()) + oscSendQueue_.pop(); +} + void Editor::Impl::tickOSCQueue(CVSTGUITimer* timer) { if (oscSendQueue_.empty()) { From a06a220866b9f082b5a29ffc63968f1ab4798814 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 18:10:18 +0100 Subject: [PATCH 211/668] Fix a crash that makes VST fail pluginval --- vst/SfizzVstProcessor.cpp | 18 +++++++++++++++--- vst/SfizzVstProcessor.h | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 6a22e52f..ec1d77d0 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -182,6 +182,9 @@ tresult PLUGIN_API SfizzVstProcessor::setActive(TBool state) { sfz::Sfizz* synth = _synth.get(); + if (bool(state) == _isActive) + return kResultTrue; + if (!synth) return kResultFalse; @@ -192,13 +195,13 @@ tresult PLUGIN_API SfizzVstProcessor::setActive(TBool state) _fileChangePeriod = static_cast(1.0 * processSetup.sampleRate); _playStateChangePeriod = static_cast(50e-3 * processSetup.sampleRate); - _workRunning = true; - _worker = std::thread([this]() { doBackgroundWork(); }); + startBackgroundWork(); } else { - synth->allSoundOff(); stopBackgroundWork(); + synth->allSoundOff(); } + _isActive = bool(state); return kResultTrue; } @@ -642,6 +645,15 @@ void SfizzVstProcessor::doBackgroundWork() } } +void SfizzVstProcessor::startBackgroundWork() +{ + if (_workRunning) + return; + + _workRunning = true; + _worker = std::thread([this]() { doBackgroundWork(); }); +} + void SfizzVstProcessor::stopBackgroundWork() { if (!_workRunning) diff --git a/vst/SfizzVstProcessor.h b/vst/SfizzVstProcessor.h index e8408169..1401780b 100644 --- a/vst/SfizzVstProcessor.h +++ b/vst/SfizzVstProcessor.h @@ -48,6 +48,7 @@ public: private: // synth state. acquire processMutex before accessing std::unique_ptr _synth; + bool _isActive = false; SfizzVstState _state; float _currentStretchedTuning = 0; @@ -94,6 +95,7 @@ private: // worker void doBackgroundWork(); + void startBackgroundWork(); void stopBackgroundWork(); // writer bool writeWorkerMessage(const char* type, const void* data, uintptr_t size); From 3ee7812bd870745056b2ea93e3da335080f959a3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 19:06:36 +0100 Subject: [PATCH 212/668] Update clang-tidy include paths --- scripts/run_clang_tidy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index ef805736..dea7d0ea 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -30,9 +30,9 @@ clang-tidy \ vst/SfizzVstProcessor.cpp \ vst/SfizzVstEditor.cpp \ vst/SfizzVstState.cpp \ - -- -Iexternal/abseil-cpp -Iexternal/jsl/include -Iexternal/filesystem/include -Isrc/external/hiir -Isrc/external/pugixml/src \ + -- -Iexternal/abseil-cpp -Iexternal/jsl/include -Iexternal/filesystem/include -Iexternal/atomic_queue/include -Iexternal/threadpool -Isrc/external/hiir -Isrc/external/pugixml/src \ -Iexternal/st_audiofile/src -Iexternal/st_audiofile/thirdparty/dr_libs \ -Isrc/sfizz -Isrc -Isrc/sfizz/utility/spin_mutex -Isrc/external/spline -Isrc/external/cpuid/src \ - -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer \ + -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ieditor/external/vstgui4 -Ivst/external/ring_buffer \ -Ieditor/src \ -DNDEBUG -std=c++17 From 6eef90149fd2732e63d6b59f7cd029d6eb870edf Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 19:14:51 +0100 Subject: [PATCH 213/668] Delete the old parser --- common.mk | 2 - scripts/run_clang_tidy.sh | 2 - src/CMakeLists.txt | 4 -- src/sfizz/Parser.cpp | 132 -------------------------------------- src/sfizz/Parser.h | 36 ----------- src/sfizz/SfzHelpers.cpp | 106 ------------------------------ src/sfizz/SfzHelpers.h | 62 ------------------ tests/ParsingT.cpp | 120 ---------------------------------- 8 files changed, 464 deletions(-) delete mode 100644 src/sfizz/Parser.cpp delete mode 100644 src/sfizz/Parser.h delete mode 100644 src/sfizz/SfzHelpers.cpp diff --git a/common.mk b/common.mk index 5c7cf10f..ea5553ff 100644 --- a/common.mk +++ b/common.mk @@ -97,7 +97,6 @@ SFIZZ_SOURCES = \ src/sfizz/Opcode.cpp \ src/sfizz/Oversampler.cpp \ src/sfizz/Panning.cpp \ - src/sfizz/Parser.cpp \ src/sfizz/parser/Parser.cpp \ src/sfizz/parser/ParserPrivate.cpp \ src/sfizz/PolyphonyGroup.cpp \ @@ -109,7 +108,6 @@ SFIZZ_SOURCES = \ src/sfizz/sfizz.cpp \ src/sfizz/sfizz_wrapper.cpp \ src/sfizz/SfzFilter.cpp \ - src/sfizz/SfzHelpers.cpp \ src/sfizz/SIMDHelpers.cpp \ src/sfizz/simd/HelpersSSE.cpp \ src/sfizz/simd/HelpersAVX.cpp \ diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index dea7d0ea..041d331a 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -12,11 +12,9 @@ clang-tidy \ src/sfizz/MidiState.cpp \ src/sfizz/Opcode.cpp \ src/sfizz/Oversampler.cpp \ - src/sfizz/Parser.cpp \ src/sfizz/Panning.cpp \ src/sfizz/sfizz.cpp \ src/sfizz/Region.cpp \ - src/sfizz/SfzHelpers.cpp \ src/sfizz/SIMDHelpers.cpp \ src/sfizz/simd/HelpersSSE.cpp \ src/sfizz/simd/HelpersAVX.cpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a574522..d548788c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -128,7 +128,6 @@ set(SFIZZ_SOURCES sfizz/Voice.cpp sfizz/ScopedFTZ.cpp sfizz/MidiState.cpp - sfizz/SfzHelpers.cpp sfizz/Oversampler.cpp sfizz/ADSREnvelope.cpp sfizz/Logger.cpp @@ -193,7 +192,6 @@ set(SFIZZ_PARSER_HEADERS sfizz/Range.h sfizz/Opcode.h sfizz/Macros.h - sfizz/Parser.h sfizz/parser/Parser.h sfizz/parser/ParserPrivate.h sfizz/parser/ParserPrivate.hpp @@ -201,10 +199,8 @@ set(SFIZZ_PARSER_HEADERS sfizz/StringViewHelpers.h) set(SFIZZ_PARSER_SOURCES - sfizz/Parser.cpp sfizz/Opcode.cpp sfizz/OpcodeCleanup.cpp - sfizz/SfzHelpers.cpp sfizz/parser/Parser.cpp sfizz/parser/ParserPrivate.cpp) diff --git a/src/sfizz/Parser.cpp b/src/sfizz/Parser.cpp deleted file mode 100644 index 541ac592..00000000 --- a/src/sfizz/Parser.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "Parser.h" -#include "StringViewHelpers.h" -#include "SfzHelpers.h" -#include "absl/strings/str_join.h" -#include "absl/strings/str_cat.h" -#include -#include - -void removeCommentOnLine(absl::string_view& line) -{ - auto position = line.find("//"); - if (position != line.npos) - line.remove_suffix(line.size() - position); -} - -bool sfz::OldParser::loadSfzFile(const fs::path& file) -{ - includedFiles.clear(); - - const auto sfzFile = - (file.empty() || file.is_absolute()) ? file : originalDirectory / file; - if (!fs::exists(sfzFile)) - return false; - - originalDirectory = sfzFile.parent_path(); - includedFiles.push_back(sfzFile); - std::vector lines; - readSfzFile(sfzFile, lines); - - aggregatedContent = absl::StrJoin(lines, " "); - absl::string_view aggregatedView { aggregatedContent }; - - absl::string_view header; - absl::string_view members; - - std::vector currentMembers; - - while (findHeader(aggregatedView, header, members)) { - absl::string_view opcode; - absl::string_view value; - - // Store or handle members - while(findOpcode(members, opcode, value)) - currentMembers.emplace_back(opcode, value); - - callback(header, currentMembers); - currentMembers.clear(); - } - - return true; -} - -void sfz::OldParser::readSfzFile(const fs::path& fileName, std::vector& lines) noexcept -{ - std::ifstream fileStream(fileName.c_str()); - if (!fileStream) - return; - - std::string tmpString; - std::string includePath; - absl::string_view variable; - absl::string_view value; - while (std::getline(fileStream, tmpString)) { - absl::string_view tmpView { tmpString }; - - removeCommentOnLine(tmpView); - trimInPlace(tmpView); - - if (tmpView.empty()) - continue; - - // New #include - if (findInclude(tmpView, includePath)) { - std::replace(includePath.begin(), includePath.end(), '\\', '/'); - const auto newFile = originalDirectory / includePath; - auto alreadyIncluded = std::find(includedFiles.begin(), includedFiles.end(), newFile); - if (fs::exists(newFile)) { - if (alreadyIncluded == includedFiles.end()) { - includedFiles.push_back(newFile); - readSfzFile(newFile, lines); - } else if (!recursiveIncludeGuard) { - readSfzFile(newFile, lines); - } - } - continue; - } - - // New #define - if (findDefine(tmpView, variable, value)) { - - defines[std::string(variable)] = std::string(value); - continue; - } - - // Replace defined variables starting with $ - std::string newString; - newString.reserve(tmpView.length()); - std::string::size_type lastPos = 0; - std::string::size_type findPos = tmpView.find(sfz::config::defineCharacter, lastPos); - - while (findPos < tmpView.npos) { - absl::StrAppend(&newString, tmpView.substr(lastPos, findPos - lastPos)); - - const auto defineEnd = tmpView.find_first_of("= \r\t\n\f\v", findPos); - const auto candidate = tmpView.substr(findPos, defineEnd - findPos); - for (auto& definePair : defines) { - if (candidate == definePair.first) { - absl::StrAppend(&newString, definePair.second); - lastPos = findPos + definePair.first.length(); - break; - } - } - - if (lastPos <= findPos) { - newString += sfz::config::defineCharacter; - lastPos = findPos + 1; - } - - findPos = tmpView.find(sfz::config::defineCharacter, lastPos); - } - - // Copy the rest of the string - absl::StrAppend(&newString, tmpView.substr(lastPos)); - lines.push_back(std::move(newString)); - } -} diff --git a/src/sfizz/Parser.h b/src/sfizz/Parser.h deleted file mode 100644 index e1be5971..00000000 --- a/src/sfizz/Parser.h +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#pragma once -#include "Config.h" -#include "Opcode.h" -#include "ghc/fs_std.hpp" -#include -#include -#include "absl/strings/string_view.h" -#include - -namespace sfz { -class OldParser { -public: - virtual ~OldParser() = default; - virtual bool loadSfzFile(const fs::path& file); - const std::map& getDefines() const noexcept { return defines; } - const std::vector& getIncludedFiles() const noexcept { return includedFiles; } - void disableRecursiveIncludeGuard() { recursiveIncludeGuard = false; } - void enableRecursiveIncludeGuard() { recursiveIncludeGuard = true; } -protected: - virtual void callback(absl::string_view header, const std::vector& members) = 0; - fs::path originalDirectory { fs::current_path() }; -private: - bool recursiveIncludeGuard { false }; - std::map defines; - std::vector includedFiles; - std::string aggregatedContent {}; - void readSfzFile(const fs::path& fileName, std::vector& lines) noexcept; -}; - -} // namespace sfz diff --git a/src/sfizz/SfzHelpers.cpp b/src/sfizz/SfzHelpers.cpp deleted file mode 100644 index 581315f8..00000000 --- a/src/sfizz/SfzHelpers.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "SfzHelpers.h" -#include "StringViewHelpers.h" - -namespace sfz { - -bool findHeader(absl::string_view& source, absl::string_view& header, absl::string_view& members) -{ - auto openHeader = source.find("<"); - if (openHeader == absl::string_view::npos) - return false; - - auto closeHeader = source.find(">", openHeader); - if (openHeader == absl::string_view::npos) - return false; - - auto nextHeader = source.find("<", closeHeader); - header = source.substr(openHeader + 1, closeHeader - openHeader - 1); - if (nextHeader == absl::string_view::npos) { - members = trim(source.substr(closeHeader + 1)); - source.remove_prefix(source.length()); - } else { - members = trim(source.substr(closeHeader + 1, nextHeader - closeHeader - 1)); - source.remove_prefix(nextHeader); - } - - return true; -} - -bool findOpcode(absl::string_view& source, absl::string_view& opcode, absl::string_view& value) -{ - auto opcodeEnd = source.find("="); - if (opcodeEnd == absl::string_view::npos) - return false; - - const auto valueStart = opcodeEnd + 1; - const auto nextOpcodeEnd = source.find("=", valueStart); - - if (nextOpcodeEnd == absl::string_view::npos) { - opcode = source.substr(0, opcodeEnd); - value = source.substr(valueStart); - source.remove_prefix(source.length()); - return true; - } - - auto valueEnd = nextOpcodeEnd; - while (source[valueEnd] != ' ' && valueEnd != valueStart) - valueEnd--; - - opcode = source.substr(0, opcodeEnd); - value = source.substr(valueStart, valueEnd - valueStart); - source.remove_prefix(valueEnd); - return true; -} - - -bool findDefine(absl::string_view line, absl::string_view& variable, absl::string_view& value) -{ - const auto defPosition = line.find("#define"); - if (defPosition == absl::string_view::npos) - return false; - - const auto variableStart = line.find("$", 7); - if (variableStart == absl::string_view::npos) - return false; - - const auto variableEnd = line.find_first_of(" \r\t\n\f\v", variableStart); - if (variableEnd == absl::string_view::npos) - return false; - - const auto valueStart = line.find_first_not_of(" \r\t\n\f\v", variableEnd); - if (valueStart == absl::string_view::npos) - return false; - - const auto valueEnd = line.find_first_of(" \r\t\n\f\v", valueStart); - variable = line.substr(variableStart, variableEnd - variableStart); - value = valueEnd != absl::string_view::npos - ? line.substr(valueStart, valueEnd - valueStart) - : line.substr(valueStart); - return true; -} - -bool findInclude(absl::string_view line, std::string& path) -{ - const auto defPosition = line.find("#include"); - if (defPosition == absl::string_view::npos) - return false; - - const auto pathStart = line.find("\"", 8); - if (pathStart == absl::string_view::npos) - return false; - - const auto pathEnd = line.find("\"", pathStart + 1); - if (pathEnd == absl::string_view::npos) - return false; - - path = std::string(line.substr(pathStart + 1, pathEnd - pathStart - 1)); - return true; -} - -} diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index a2d2439e..b26f6560 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -250,66 +250,4 @@ bool insertPairUniquely(std::vector

& pairVector, const T& key, U value, bool return result; } -/** - * @brief From a source view, find the next sfz header and its members and - * return them, while updating the source by removing this header - * and members from the beginning. The function "consumes" the - * header and its members from the source if found. - * - * No check is made to see if the header is "valid" in the sfz sense. - * The output parameters are set only if the method returns true. - * - * @param source A source view; can be updated and shortened - * @param header An output view on the header, without the <> - * @param members An output view on the members, untrimmed - * @return true if a header was found - * @return false otherwise - */ -bool findHeader(absl::string_view& source, absl::string_view& header, absl::string_view& members); -/** - * @brief From a source view, find the next sfz member opcode and its value. - * Return them while updating the source by removing this opcode - * and value from the beginning. The function "consumes" the - * opcode from the source if one is found. - * - * No check is made to see if the opcode is "valid" in the sfz sense. - * The output parameters are set only if the method returns true. - * - * @param source A source view; can be updated and shortened - * @param opcode An output view on the opcode name - * @param value An output view on the opcode value - * @return true if an opcode was found - * @return false - */ -bool findOpcode(absl::string_view& source, absl::string_view& opcode, absl::string_view& value); - -/** - * @brief Find an SFZ #define statement on a line and return the variable and value as views. - * - * This function assums that there is a single define per line and that the variable and value - * are separated by whitespace. - * The output parameters are set only if the method returns true. - * - * @param line The source line - * @param variable An output view on the define variable - * @param value An output view on the define value - * @return true If a define was found - * @return false - */ -bool findDefine(absl::string_view line, absl::string_view& variable, absl::string_view& value); - -/** - * @brief Find an SFZ #include statement on a line and return included path. - * - * This function assums that there is a single include per line and that the - * include path is within quotes. - * The output parameter is set only if the method returns true. - * - * @param line The source line - * @param path The path, if found - * @return true If an include was found - * @return false - */ -bool findInclude(absl::string_view line, std::string& path); - } // namespace sfz diff --git a/tests/ParsingT.cpp b/tests/ParsingT.cpp index 1224b46c..ce35830d 100644 --- a/tests/ParsingT.cpp +++ b/tests/ParsingT.cpp @@ -11,126 +11,6 @@ #include "absl/strings/string_view.h" using namespace Catch::literals; -void includeTest(const std::string& line, const std::string& fileName) -{ - std::string parsedPath; - auto found = sfz::findInclude(line, parsedPath); - if (!found) - std::cerr << "Include test failed: " << line << '\n'; - REQUIRE(found); - REQUIRE(parsedPath == fileName); -} - -TEST_CASE("[Parsing] #include") -{ - includeTest("#include \"file.sfz\"", "file.sfz"); - includeTest("#include \"../Programs/file.sfz\"", "../Programs/file.sfz"); - includeTest("#include \"..\\Programs\\file.sfz\"", "..\\Programs\\file.sfz"); - includeTest("#include \"file-1.sfz\"", "file-1.sfz"); - includeTest("#include \"file~1.sfz\"", "file~1.sfz"); - includeTest("#include \"file_1.sfz\"", "file_1.sfz"); - includeTest("#include \"file$1.sfz\"", "file$1.sfz"); - includeTest("#include \"file,1.sfz\"", "file,1.sfz"); - includeTest("#include \"rubbishCharactersAfter.sfz\" blabldaljf///df", "rubbishCharactersAfter.sfz"); - includeTest("#include \"lazyMatching.sfz\" b\"", "lazyMatching.sfz"); -} - -void defineTest(const std::string& line, const std::string& variable, const std::string& value) -{ - absl::string_view variableMatch; - absl::string_view valueMatch; - - auto found = sfz::findDefine(line, variableMatch, valueMatch); - REQUIRE(found); - REQUIRE(variableMatch == variable); - REQUIRE(valueMatch == value); -} - -void defineFail(const std::string& line) -{ - absl::string_view variableMatch; - absl::string_view valueMatch; - auto found = sfz::findDefine(line, variableMatch, valueMatch); - REQUIRE(!found); -} - -TEST_CASE("[Parsing] #define") -{ - defineTest("#define $number 1", "$number", "1"); - defineTest("#define $letters QWERasdf", "$letters", "QWERasdf"); - defineTest("#define $alphanum asr1t44", "$alphanum", "asr1t44"); - defineTest("#define $whitespace asr1t44 ", "$whitespace", "asr1t44"); - defineTest("#define $lazyMatching matched bfasd ", "$lazyMatching", "matched"); - defineTest("#define $stircut -12", "$stircut", "-12"); - defineTest("#define $_ht_under_score_ 3fd", "$_ht_under_score_", "3fd"); - defineTest("#define $ht_under_score 3fd", "$ht_under_score", "3fd"); - // defineFail("#define $symbols# 1"); - // defineFail("#define $symbolsAgain $1"); - // defineFail("#define $trailingSymbols 1$"); -} - -TEST_CASE("[Parsing] Header") -{ - SECTION("Basic header match") - { - absl::string_view header; - absl::string_view members; - absl::string_view line { "

param1=value1 param2=value2" }; - auto found = sfz::findHeader(line, header, members); - REQUIRE(found); - REQUIRE(header == "header"); - REQUIRE(members == "param1=value1 param2=value2"); - REQUIRE(line == ""); - } - SECTION("EOL header match") - { - absl::string_view header; - absl::string_view members; - absl::string_view line { "
param1=value1 param2=value2" }; - auto found = sfz::findHeader(line, header, members); - REQUIRE(found); - REQUIRE(header == "header"); - REQUIRE(members == "param1=value1 param2=value2"); - REQUIRE(line == ""); - } -} - -void memberTest(const std::string& line, const std::string& opcode, const std::string& value) -{ - absl::string_view opcodeMatched; - absl::string_view valueMatched; - absl::string_view lineView { line }; - auto found = sfz::findOpcode(lineView, opcodeMatched, valueMatched); - REQUIRE(found); - REQUIRE(opcodeMatched == opcode); - REQUIRE(valueMatched == value); -} - -TEST_CASE("[Parsing] Member") -{ - memberTest("param=value", "param", "value"); - memberTest("param=113", "param", "113"); - memberTest("param1=value", "param1", "value"); - memberTest("param_1=value", "param_1", "value"); - memberTest("param_1=value", "param_1", "value"); - memberTest("ampeg_sustain_oncc74=-100", "ampeg_sustain_oncc74", "-100"); - memberTest("lorand=0.750", "lorand", "0.750"); - memberTest("sample=value", "sample", "value"); - memberTest("sample=value-()*", "sample", "value-()*"); - memberTest("sample=../sample.wav", "sample", "../sample.wav"); - memberTest("sample=..\\sample.wav", "sample", "..\\sample.wav"); - memberTest("sample=subdir\\subdir\\sample.wav", "sample", "subdir\\subdir\\sample.wav"); - memberTest("sample=subdir/subdir/sample.wav", "sample", "subdir/subdir/sample.wav"); - memberTest("sample=subdir_underscore\\sample.wav", "sample", "subdir_underscore\\sample.wav"); - memberTest("sample=subdir space\\sample.wav", "sample", "subdir space\\sample.wav"); - memberTest("sample=subdir space\\sample.wav next_member=value", "sample", "subdir space\\sample.wav"); - memberTest("sample=..\\Samples\\pizz\\a0_vl3_rr3.wav", "sample", "..\\Samples\\pizz\\a0_vl3_rr3.wav"); - memberTest("sample=..\\Samples\\SMD Cymbals Stereo (Samples)\\Hi-Hat (Samples)\\01 Hat Tight 1\\RR1\\09_Hat_Tight_Cnt_RR1.wav", "sample", "..\\Samples\\SMD Cymbals Stereo (Samples)\\Hi-Hat (Samples)\\01 Hat Tight 1\\RR1\\09_Hat_Tight_Cnt_RR1.wav"); - memberTest("sample=..\\G&S CW-Drum Kit-1\\SnareFX\\SNR-OFF-V08-CustomWorks-6x13.wav", "sample", "..\\G&S CW-Drum Kit-1\\SnareFX\\SNR-OFF-V08-CustomWorks-6x13.wav"); -} - -// New parser - struct ParsingMocker: sfz::Parser::Listener { void onParseBegin() override From 6ff6acad71e9c6e8dacd68fb28a88fb6a52b7ce6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 3 Feb 2021 19:25:24 +0100 Subject: [PATCH 214/668] Fix a clang-tidy problem --- src/sfizz/Synth.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index d9ecb85e..b82cb372 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -800,11 +800,8 @@ int Synth::getNumActiveVoices() const noexcept int activeVoices = static_cast(impl.voiceManager_.getNumActiveVoices()); // do not count overflow voices which are over limit - int resultVoices = activeVoices; - if (config::overflowVoiceMultiplier > 1) - resultVoices = std::min(impl.numVoices_, activeVoices); - - return resultVoices; + return (config::overflowVoiceMultiplier > 1) ? + std::min(impl.numVoices_, activeVoices) : activeVoices; } void Synth::setSamplesPerBlock(int samplesPerBlock) noexcept From 74285a14927488d717babd2acdf236ab394b86a2 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 4 Feb 2021 02:48:49 +0100 Subject: [PATCH 215/668] Refactor VST with UpdateHandler --- vst/CMakeLists.txt | 7 +- vst/IdleUpdateHandler.h | 47 +++++++ vst/SfizzVstController.cpp | 260 +++++++++++++++-------------------- vst/SfizzVstController.h | 34 ++--- vst/SfizzVstEditor.cpp | 269 +++++++++++++++++++------------------ vst/SfizzVstEditor.h | 39 ++---- vst/SfizzVstParameters.h | 91 +++++++++++++ vst/SfizzVstProcessor.cpp | 19 +-- vst/SfizzVstState.cpp | 32 ----- vst/SfizzVstState.h | 64 --------- vst/SfizzVstUpdates.cpp | 37 +++++ vst/SfizzVstUpdates.h | 129 ++++++++++++++++++ vst/WeakPtr.h | 122 ----------------- 13 files changed, 595 insertions(+), 555 deletions(-) create mode 100644 vst/IdleUpdateHandler.h create mode 100644 vst/SfizzVstParameters.h create mode 100644 vst/SfizzVstUpdates.cpp create mode 100644 vst/SfizzVstUpdates.h delete mode 100644 vst/WeakPtr.h diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index cc73ce59..8f328512 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -19,6 +19,7 @@ set(VSTPLUGIN_SOURCES SfizzVstController.cpp SfizzVstEditor.cpp SfizzVstState.cpp + SfizzVstUpdates.cpp SfizzFileScan.cpp SfizzForeignPaths.cpp SfizzSettings.cpp @@ -32,13 +33,15 @@ set(VSTPLUGIN_HEADERS SfizzVstController.h SfizzVstEditor.h SfizzVstState.h + SfizzVstParameters.h + SfizzVstUpdates.h SfizzFileScan.h SfizzForeignPaths.h SfizzSettings.h X11RunLoop.h + IdleUpdateHandler.h NativeHelpers.h - FileTrie.h - WeakPtr.h) + FileTrie.h) if(APPLE) set(VSTPLUGIN_MAC_SOURCES diff --git a/vst/IdleUpdateHandler.h b/vst/IdleUpdateHandler.h new file mode 100644 index 00000000..37488c9b --- /dev/null +++ b/vst/IdleUpdateHandler.h @@ -0,0 +1,47 @@ +// This file is part of VSTGUI. It is subject to the license terms +// in the LICENSE file found in the top-level directory of this +// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE + +#pragma once +#include "base/source/updatehandler.h" +#include + +/// @cond ignore +namespace Steinberg { + +class IdleUpdateHandler +{ +public: + static void start () + { + auto& instance = get (); + if (++instance.users == 1) + { + instance.timer = VSTGUI::makeOwned ( + [] (VSTGUI::CVSTGUITimer*) { return UpdateHandler::instance ()->triggerDeferedUpdates (); }, + 1000 / 30); + } + } + + static void stop () + { + auto& instance = get (); + if (--instance.users == 0) + { + instance.timer = nullptr; + } + } + +protected: + static IdleUpdateHandler& get () + { + static IdleUpdateHandler gInstance; + return gInstance; + } + + VSTGUI::SharedPointer timer; + std::atomic users {0}; +}; + +} // namespace Steinberg +/// @endcond ignore diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 9ac894c4..b6ac8945 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -6,7 +6,9 @@ #include "SfizzVstController.h" #include "SfizzVstEditor.h" +#include "SfizzVstParameters.h" #include "base/source/fstreamer.h" +#include "base/source/updatehandler.h" #include "pluginterfaces/vst/ivstmidicontrollers.h" tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) @@ -15,35 +17,46 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) if (result != kResultTrue) return result; + // initialize the update handler + Steinberg::UpdateHandler::instance(); + + // create update objects + oscUpdate_ = Steinberg::owned(new OSCUpdate); + sfzPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateSfz)); + scalaPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateScala)); + processorStateUpdate_ = Steinberg::owned(new ProcessorStateUpdate); + playStateUpdate_ = Steinberg::owned(new PlayStateUpdate); + + // Parameters Vst::ParamID pid = 0; // Ordinary parameters parameters.addParameter( - kParamVolumeRange.createParameter( + SfizzRange::getForParameter(kPidVolume).createParameter( Steinberg::String("Volume"), pid++, Steinberg::String("dB"), 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamNumVoicesRange.createParameter( + SfizzRange::getForParameter(kPidNumVoices).createParameter( Steinberg::String("Polyphony"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamOversamplingRange.createParameter( + SfizzRange::getForParameter(kPidOversampling).createParameter( Steinberg::String("Oversampling"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamPreloadSizeRange.createParameter( + SfizzRange::getForParameter(kPidPreloadSize).createParameter( Steinberg::String("Preload size"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamScalaRootKeyRange.createParameter( + SfizzRange::getForParameter(kPidScalaRootKey).createParameter( Steinberg::String("Scala root key"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamTuningFrequencyRange.createParameter( + SfizzRange::getForParameter(kPidTuningFrequency).createParameter( Steinberg::String("Tuning frequency"), pid++, Steinberg::String("Hz"), 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamStretchedTuningRange.createParameter( + SfizzRange::getForParameter(kPidStretchedTuning).createParameter( Steinberg::String("Stretched tuning"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); @@ -96,7 +109,8 @@ tresult PLUGIN_API SfizzVstControllerNoUi::getParamStringByValue(Vst::ParamID ta switch (tag) { case kPidOversampling: { - auto factorLog2 = static_cast(kParamOversamplingRange.denormalize(valueNormalized)); + const SfizzRange range = SfizzRange::getForParameter(tag); + const int factorLog2 = static_cast(range.denormalize(valueNormalized)); Steinberg::String buf; buf.printf("%dX", 1 << factorLog2); buf.copyTo(string); @@ -113,14 +127,11 @@ tresult PLUGIN_API SfizzVstControllerNoUi::getParamValueByString(Vst::ParamID ta case kPidOversampling: { int32 factor; - if (!Steinberg::String::scanInt32(string, factor, false) || factor < 1) + if (!Steinberg::String::scanInt32(string, factor, false)) factor = 1; - int32 log2Factor = 0; - for (int32 f = factor; f > 1; f /= 2) - ++log2Factor; - - valueNormalized = kParamOversamplingRange.normalize(log2Factor); + const SfizzRange range = SfizzRange::getForParameter(tag); + valueNormalized = range.normalize(integerLog2(factor)); return kResultTrue; } } @@ -128,133 +139,52 @@ tresult PLUGIN_API SfizzVstControllerNoUi::getParamValueByString(Vst::ParamID ta return EditController::getParamValueByString(tag, string, valueNormalized); } -// --- Controller with UI --- // - -IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) +tresult SfizzVstControllerNoUi::setParam(Vst::ParamID tag, float value) { - ConstString name(_name); - - fprintf(stderr, "[sfizz] about to create view: %s\n", _name); - - if (name != Vst::ViewType::kEditor) - return nullptr; - - if (IPtr editor = _editor.lock()) { - withStateLock([this, editor]() { - _uiState = editor->getCurrentUiState(); - }); - } - - IPtr editor = Steinberg::owned(new SfizzVstEditor(this)); - _editor = editor->getWeakPtr(); - - withStateLock([this, editor]() { - editor->updateState(_state); - editor->updateUiState(_uiState); - editor->updatePlayState(_playState); - }); - - editor->remember(); - return editor; + const SfizzRange range = SfizzRange::getForParameter(tag); + return setParamNormalized(tag, range.normalize(value)); } -tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst::ParamValue normValue) +tresult PLUGIN_API SfizzVstControllerNoUi::setParamNormalized(Vst::ParamID tag, Vst::ParamValue normValue) { - tresult r = SfizzVstControllerNoUi::setParamNormalized(tag, normValue); + tresult r = EditController::setParamNormalized(tag, normValue); if (r != kResultTrue) return r; - float *slotF32 = nullptr; - int32 *slotI32 = nullptr; - float value = 0; + SfizzVstState state = processorStateUpdate_->getState(); + + const SfizzRange range = SfizzRange::getForParameter(tag); switch (tag) { - case kPidVolume: { - slotF32 = &_state.volume; - value = kParamVolumeRange.denormalize(normValue); + case kPidVolume: + state.volume = range.denormalize(normValue); break; - } - case kPidNumVoices: { - slotI32 = &_state.numVoices; - value = kParamNumVoicesRange.denormalize(normValue); + case kPidNumVoices: + state.numVoices = (int32)range.denormalize(normValue); break; - } - case kPidOversampling: { - slotI32 = &_state.oversamplingLog2; - value = kParamOversamplingRange.denormalize(normValue); + case kPidOversampling: + state.oversamplingLog2 = (int32)range.denormalize(normValue); break; - } - case kPidPreloadSize: { - slotI32 = &_state.preloadSize; - value = kParamPreloadSizeRange.denormalize(normValue); + case kPidPreloadSize: + state.preloadSize = (int32)range.denormalize(normValue); break; - } - case kPidScalaRootKey: { - slotI32 = &_state.scalaRootKey; - value = kParamScalaRootKeyRange.denormalize(normValue); + case kPidScalaRootKey: + state.scalaRootKey = (int32)range.denormalize(normValue); break; - } - case kPidTuningFrequency: { - slotF32 = &_state.tuningFrequency; - value = kParamTuningFrequencyRange.denormalize(normValue); + case kPidTuningFrequency: + state.tuningFrequency = (float)range.denormalize(normValue); break; - } - case kPidStretchedTuning: { - slotF32 = &_state.stretchedTuning; - value = kParamStretchedTuningRange.denormalize(normValue); + case kPidStretchedTuning: + state.stretchedTuning = range.denormalize(normValue); break; } - } - if (slotF32 && *slotF32 != value) { - withStateLock([this, slotF32, value]() { - *slotF32 = value; - if (IPtr editor = _editor.lock()) - editor->updateState(_state); - }); - } - else if (slotI32 && *slotI32 != (int32)value) { - withStateLock([this, slotI32, value]() { - *slotI32 = (int32)value; - if (IPtr editor = _editor.lock()) - editor->updateState(_state); - }); - } + processorStateUpdate_->setState(state); return kResultTrue; } -tresult PLUGIN_API SfizzVstController::setState(IBStream* stream) -{ - SfizzUiState s; - - tresult r = s.load(stream); - if (r != kResultTrue) - return r; - - withStateLock([this, &s]() { - _uiState = s; - if (IPtr editor = _editor.lock()) - editor->updateUiState(_uiState); - }); - - return kResultTrue; -} - -tresult PLUGIN_API SfizzVstController::getState(IBStream* stream) -{ - tresult result; - - withStateLock([this, stream, &result]() { - if (IPtr editor = _editor.lock()) - _uiState = editor->getCurrentUiState(); - result = _uiState.store(stream); - }); - - return result; -} - -tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* stream) +tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream) { SfizzVstState s; @@ -262,28 +192,29 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* stream) if (r != kResultTrue) return r; - setParamNormalized(kPidVolume, kParamVolumeRange.normalize(s.volume)); - setParamNormalized(kPidNumVoices, kParamNumVoicesRange.normalize(s.numVoices)); - setParamNormalized(kPidOversampling, kParamOversamplingRange.normalize(s.oversamplingLog2)); - setParamNormalized(kPidPreloadSize, kParamPreloadSizeRange.normalize(s.preloadSize)); - setParamNormalized(kPidScalaRootKey, kParamScalaRootKeyRange.normalize(s.scalaRootKey)); - setParamNormalized(kPidTuningFrequency, kParamTuningFrequencyRange.normalize(s.tuningFrequency)); - setParamNormalized(kPidStretchedTuning, kParamStretchedTuningRange.normalize(s.stretchedTuning)); + processorStateUpdate_->setState(s); - withStateLock([this, &s]() { - _state = s; - if (IPtr editor = _editor.lock()) - editor->updateState(_state); - }); + setParam(kPidVolume, s.volume); + setParam(kPidNumVoices, s.numVoices); + setParam(kPidOversampling, s.oversamplingLog2); + setParam(kPidPreloadSize, s.preloadSize); + setParam(kPidScalaRootKey, s.scalaRootKey); + setParam(kPidTuningFrequency, s.tuningFrequency); + setParam(kPidStretchedTuning, s.stretchedTuning); + + sfzPathUpdate_->setPath(s.sfzFile); + sfzPathUpdate_->deferUpdate(); + scalaPathUpdate_->setPath(s.scalaFile); + scalaPathUpdate_->deferUpdate(); return kResultTrue; } -tresult SfizzVstController::notify(Vst::IMessage* message) +tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message) { // Note: may be called from any thread (Reaper) - tresult result = SfizzVstControllerNoUi::notify(message); + tresult result = EditController::notify(message); if (result != kResultFalse) return result; @@ -298,11 +229,12 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - withStateLock([this, data, size]() { - _state.sfzFile.assign(static_cast(data), size); - if (IPtr editor = _editor.lock()) - editor->updateState(_state); - }); + SfizzVstState state = processorStateUpdate_->getState(); + state.sfzFile.assign(static_cast(data), size); + processorStateUpdate_->setState(state); + + sfzPathUpdate_->setPath(state.sfzFile); + sfzPathUpdate_->deferUpdate(); } else if (!strcmp(id, "LoadedScala")) { const void* data = nullptr; @@ -312,11 +244,12 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - withStateLock([this, data, size]() { - _state.scalaFile.assign(static_cast(data), size); - if (IPtr editor = _editor.lock()) - editor->updateState(_state); - }); + SfizzVstState state = processorStateUpdate_->getState(); + state.scalaFile.assign(static_cast(data), size); + processorStateUpdate_->setState(state); + + scalaPathUpdate_->setPath(state.scalaFile); + scalaPathUpdate_->deferUpdate(); } else if (!strcmp(id, "NotifiedPlayState")) { const void* data = nullptr; @@ -326,11 +259,8 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - withStateLock([this, data]() { - _playState = *static_cast(data); - if (IPtr editor = _editor.lock()) - editor->updatePlayState(_playState); - }); + playStateUpdate_->setState(*static_cast(data)); + playStateUpdate_->deferUpdate(); } else if (!strcmp(id, "ReceivedMessage")) { const void* data = nullptr; @@ -340,13 +270,43 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - if (IPtr editor = _editor.lock()) - editor->receiveMessage(data, size); + // this is a synchronous send, because the update object gets reused + oscUpdate_->setMessage(data, size, false); + oscUpdate_->changed(); + oscUpdate_->clear(); } return result; } +// --- Controller with UI --- // + +IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) +{ + ConstString name(_name); + + fprintf(stderr, "[sfizz] about to create view: %s\n", _name); + + if (name != Vst::ViewType::kEditor) + return nullptr; + + std::vector continuousUpdates; + continuousUpdates.push_back(sfzPathUpdate_); + continuousUpdates.push_back(scalaPathUpdate_); + continuousUpdates.push_back(playStateUpdate_); + for (uint32 i = 0, n = parameters.getParameterCount(); i < n; ++i) + continuousUpdates.push_back(parameters.getParameterByIndex(i)); + + std::vector triggerUpdates; + triggerUpdates.push_back(oscUpdate_); + + IPtr editor = Steinberg::owned( + new SfizzVstEditor(this, absl::MakeSpan(continuousUpdates), absl::MakeSpan(triggerUpdates))); + + editor->remember(); + return editor; +} + FUnknown* SfizzVstController::createInstance(void*) { return static_cast(new SfizzVstController); diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index 42094b8f..2365417b 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -6,10 +6,10 @@ #pragma once #include "SfizzVstState.h" +#include "SfizzVstUpdates.h" #include "public.sdk/source/vst/vsteditcontroller.h" #include "public.sdk/source/vst/vstparameters.h" #include "vstgui/plugin-bindings/vst3editor.h" -#include "WeakPtr.h" #include #include class SfizzVstState; @@ -31,6 +31,10 @@ public: tresult PLUGIN_API getParamStringByValue(Vst::ParamID tag, Vst::ParamValue valueNormalized, Vst::String128 string) override; tresult PLUGIN_API getParamValueByString(Vst::ParamID tag, Vst::TChar* string, Vst::ParamValue& valueNormalized) override; + tresult setParam(Vst::ParamID tag, float value); + tresult PLUGIN_API setParamNormalized(Vst::ParamID tag, Vst::ParamValue value) override; + tresult PLUGIN_API setComponentState(IBStream* stream) override; + tresult PLUGIN_API notify(Vst::IMessage* message) override; // interfaces OBJ_METHODS(SfizzVstControllerNoUi, Vst::EditController) @@ -38,34 +42,20 @@ public: DEF_INTERFACE(Vst::IMidiMapping) END_DEFINE_INTERFACES(Vst::EditController) REFCOUNT_METHODS(Vst::EditController) + +protected: + Steinberg::IPtr oscUpdate_; + Steinberg::IPtr sfzPathUpdate_; + Steinberg::IPtr scalaPathUpdate_; + Steinberg::IPtr processorStateUpdate_; + Steinberg::IPtr playStateUpdate_; }; class SfizzVstController : public SfizzVstControllerNoUi, public VSTGUI::VST3EditorDelegate { public: IPlugView* PLUGIN_API createView(FIDString name) override; - tresult PLUGIN_API setParamNormalized(Vst::ParamID tag, Vst::ParamValue value) override; - tresult PLUGIN_API setState(IBStream* stream) override; - tresult PLUGIN_API getState(IBStream* stream) override; - tresult PLUGIN_API setComponentState(IBStream* stream) override; - tresult PLUGIN_API notify(Vst::IMessage* message) override; - - /// static FUnknown* createInstance(void*); static FUID cid; - -private: - template void withStateLock(F&& fn) const - { - std::lock_guard lock(_stateMutex); - fn(); - } - -private: - mutable std::mutex _stateMutex; // for R/W the state data - SfizzVstState _state {}; - SfizzUiState _uiState {}; // updated on UI open/close/state-request - SfizzPlayState _playState {}; - WeakPtr _editor; }; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 69bc7ace..1d920dfa 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -6,9 +6,12 @@ #include "SfizzVstEditor.h" #include "SfizzVstState.h" +#include "SfizzVstParameters.h" +#include "SfizzVstUpdates.h" #include "SfizzFileScan.h" #include "editor/Editor.h" #include "editor/EditIds.h" +#include "IdleUpdateHandler.h" #if !defined(__APPLE__) && !defined(_WIN32) #include "X11RunLoop.h" #endif @@ -22,9 +25,14 @@ enum { kOscQueueSize = 65536, }; -SfizzVstEditor::SfizzVstEditor(SfizzVstController* controller) +SfizzVstEditor::SfizzVstEditor( + SfizzVstController* controller, + absl::Span continuousUpdates, + absl::Span triggerUpdates) : VSTGUIEditor(controller, &sfizzUiViewRect), - oscTemp_(new uint8_t[kOscTempSize]) + oscTemp_(new uint8_t[kOscTempSize]), + continuousUpdates_(continuousUpdates.begin(), continuousUpdates.end()), + triggerUpdates_(triggerUpdates.begin(), triggerUpdates.end()) { } @@ -56,16 +64,12 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p editor_.reset(editor); } - withStateLock([this]() { - mustRedisplayState_ = true; - mustRedisplayUiState_ = true; - mustRedisplayPlayState_ = true; + { + std::lock_guard lock(oscQueueMutex_); OscByteVec* queue = new OscByteVec; oscQueue_.reset(queue); queue->reserve(kOscQueueSize); - }); - - updateStateDisplay(); + } if (!frame->open(parent, platformType, config)) { fprintf(stderr, "[sfizz] error opening frame\n"); @@ -74,6 +78,16 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p editor->open(*frame); + for (FObject* update : continuousUpdates_) + update->addDependent(this); + for (FObject* update : triggerUpdates_) + update->addDependent(this); + + Steinberg::IdleUpdateHandler::start(); + + for (FObject* update : continuousUpdates_) + update->deferUpdate(); + absl::optional userFilesDir = SfizzPaths::getSfzConfigDefaultPath(); uiReceiveValue(EditId::CanEditUserFilesDir, 1); uiReceiveValue(EditId::UserFilesDir, userFilesDir.value_or(fs::path()).u8string()); @@ -85,6 +99,13 @@ void PLUGIN_API SfizzVstEditor::close() { CFrame *frame = this->frame; if (frame) { + Steinberg::IdleUpdateHandler::stop(); + + for (FObject* update : continuousUpdates_) + update->removeDependent(this); + for (FObject* update : triggerUpdates_) + update->removeDependent(this); + if (editor_) editor_->close(); if (frame->getNbReference() != 1) @@ -94,9 +115,8 @@ void PLUGIN_API SfizzVstEditor::close() this->frame = nullptr; } - withStateLock([this]() { - oscQueue_.reset(); - }); + std::lock_guard lock(oscQueueMutex_); + oscQueue_.reset(); } /// @@ -123,81 +143,119 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message) if (message == CVSTGUITimer::kMsgTimer) { processOscQueue(); - updateStateDisplay(); } return result; } -void SfizzVstEditor::updateState(const SfizzVstState& state) +void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message) { - withStateLock([this, &state]() { - state_ = state; - mustRedisplayState_ = true; - }); -} - -void SfizzVstEditor::updateUiState(const SfizzUiState& uiState) -{ - withStateLock([this, &uiState]() { - uiState_ = uiState; - mustRedisplayUiState_ = true; - }); -} - -void SfizzVstEditor::updatePlayState(const SfizzPlayState& playState) -{ - withStateLock([this, &playState]() { - playState_ = playState; - mustRedisplayPlayState_ = true; - }); -} - -SfizzUiState SfizzVstEditor::getCurrentUiState() const -{ - SfizzUiState uiState; - withStateLock([this, &uiState]() { - uiState = uiState_; - }); - return uiState; -} - -void SfizzVstEditor::receiveMessage(const void* data, uint32_t size) -{ - // Note: may be called from non-UI thread (Reaper) - - withStateLock([this, data, size]() { - if (OscByteVec* queue = oscQueue_.get()) { - const uint8_t* bytes = reinterpret_cast(data); - std::copy(bytes, bytes + size, std::back_inserter(*queue)); + if (OSCUpdate* update = FCast(changedUnknown)) { + // this update is synchronous: may happen from non-UI thread + uint32 size = update->size(); + if (size > 0) { + const uint8_t* bytes = reinterpret_cast(update->data()); + std::lock_guard lock(oscQueueMutex_); + if (OscByteVec* queue = oscQueue_.get()) + std::copy(bytes, bytes + size, std::back_inserter(*queue)); } - }); + return; + } + + if (FilePathUpdate* update = FCast(changedUnknown)) { + const std::string path = update->getPath(); + switch (update->getType()) { + case kFilePathUpdateSfz: + uiReceiveValue(EditId::SfzFile, path); + break; + case kFilePathUpdateScala: + uiReceiveValue(EditId::ScalaFile, path); + break; + } + return; + } + + if (ProcessorStateUpdate* update = FCast(changedUnknown)) { + const SfizzVstState state = update->getState(); + uiReceiveValue(EditId::SfzFile, state.sfzFile); + uiReceiveValue(EditId::Volume, state.volume); + uiReceiveValue(EditId::Polyphony, state.numVoices); + uiReceiveValue(EditId::Oversampling, 1u << state.oversamplingLog2); + uiReceiveValue(EditId::PreloadSize, state.preloadSize); + uiReceiveValue(EditId::ScalaFile, state.scalaFile); + uiReceiveValue(EditId::ScalaRootKey, state.scalaRootKey); + uiReceiveValue(EditId::TuningFrequency, state.tuningFrequency); + uiReceiveValue(EditId::StretchTuning, state.stretchedTuning); + } + + if (PlayStateUpdate* update = FCast(changedUnknown)) { + const SfizzPlayState playState = update->getState(); + uiReceiveValue(EditId::UINumCurves, playState.curves); + uiReceiveValue(EditId::UINumMasters, playState.masters); + uiReceiveValue(EditId::UINumGroups, playState.groups); + uiReceiveValue(EditId::UINumRegions, playState.regions); + uiReceiveValue(EditId::UINumPreloadedSamples, playState.preloadedSamples); + uiReceiveValue(EditId::UINumActiveVoices, playState.activeVoices); + return; + } + + if (Vst::RangeParameter* param = Steinberg::FCast(changedUnknown)) { + const Vst::ParamValue value = param->getNormalized(); + const Vst::ParamID id = param->getInfo().id; + const SfizzRange range = SfizzRange::getForParameter(id); + switch (id) { + case kPidVolume: + uiReceiveValue(EditId::Volume, range.denormalize(value)); + break; + case kPidNumVoices: + uiReceiveValue(EditId::Polyphony, range.denormalize(value)); + break; + case kPidOversampling: + uiReceiveValue(EditId::Oversampling, 1u << (int32)range.denormalize(value)); + break; + case kPidPreloadSize: + uiReceiveValue(EditId::PreloadSize, range.denormalize(value)); + break; + case kPidScalaRootKey: + uiReceiveValue(EditId::ScalaRootKey, range.denormalize(value)); + break; + case kPidTuningFrequency: + uiReceiveValue(EditId::TuningFrequency, range.denormalize(value)); + break; + case kPidStretchedTuning: + uiReceiveValue(EditId::StretchTuning, range.denormalize(value)); + break; + } + return; + } + + Vst::VSTGUIEditor::update(changedUnknown, message); } void SfizzVstEditor::processOscQueue() { - withStateLock([this]() { - OscByteVec* queue = oscQueue_.get(); - if (!queue) - return; + std::lock_guard lock(oscQueueMutex_); - const uint8_t* oscData = queue->data(); - size_t oscSize = queue->size(); + OscByteVec* queue = oscQueue_.get(); + if (!queue) + return; - const char* path; - const char* sig; - const sfizz_arg_t* args; - uint8_t buffer[1024]; + const uint8_t* oscData = queue->data(); + size_t oscSize = queue->size(); - uint32_t msgSize; - while ((msgSize = sfizz_extract_message(oscData, oscSize, buffer, sizeof(buffer), &path, &sig, &args)) > 0) { - uiReceiveMessage(path, sig, args); - oscData += msgSize; - oscSize -= msgSize; - } + const char* path; + const char* sig; + const sfizz_arg_t* args; + uint8_t buffer[1024]; - queue->clear(); - }); + uint32_t msgSize; + while ((msgSize = sfizz_extract_message(oscData, oscSize, buffer, sizeof(buffer), &path, &sig, &args)) > 0) { + uiReceiveMessage(path, sig, args); + oscData += msgSize; + oscSize -= msgSize; + } + + queue->clear(); } /// @@ -210,51 +268,42 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) else { SfizzVstController* ctrl = getController(); - auto normalizeAndSet = [ctrl](Vst::ParamID pid, const SfizzParameterRange& range, float value) { - float normValue = range.normalize(value); + auto normalizeAndSet = [ctrl](Vst::ParamID pid, float value) { + float normValue = SfizzRange::getForParameter(pid).normalize(value); ctrl->setParamNormalized(pid, normValue); ctrl->performEdit(pid, normValue); }; switch (id) { case EditId::Volume: - normalizeAndSet(kPidVolume, kParamVolumeRange, v.to_float()); + normalizeAndSet(kPidVolume, v.to_float()); break; case EditId::Polyphony: - normalizeAndSet(kPidNumVoices, kParamNumVoicesRange, v.to_float()); + normalizeAndSet(kPidNumVoices, v.to_float()); break; case EditId::Oversampling: { - const int32 value = static_cast(v.to_float()); - - int32 log2Value = 0; - for (int32 f = value; f > 1; f /= 2) - ++log2Value; - - normalizeAndSet(kPidOversampling, kParamOversamplingRange, log2Value); + const int32 factor = static_cast(v.to_float()); + normalizeAndSet(kPidOversampling, integerLog2(factor)); } break; case EditId::PreloadSize: - normalizeAndSet(kPidPreloadSize, kParamPreloadSizeRange, v.to_float()); + normalizeAndSet(kPidPreloadSize, v.to_float()); break; case EditId::ScalaRootKey: - normalizeAndSet(kPidScalaRootKey, kParamScalaRootKeyRange, v.to_float()); + normalizeAndSet(kPidScalaRootKey, v.to_float()); break; case EditId::TuningFrequency: - normalizeAndSet(kPidTuningFrequency, kParamTuningFrequencyRange, v.to_float()); + normalizeAndSet(kPidTuningFrequency, v.to_float()); break; case EditId::StretchTuning: - normalizeAndSet(kPidStretchedTuning, kParamStretchedTuningRange, v.to_float()); + normalizeAndSet(kPidStretchedTuning, v.to_float()); break; case EditId::UserFilesDir: SfizzPaths::setSfzConfigDefaultPath(fs::u8path(v.to_string())); break; - case EditId::UIActivePanel: - uiState_.activePanel = static_cast(v.to_float()); - break; - default: break; } @@ -344,44 +393,6 @@ void SfizzVstEditor::loadScalaFile(const std::string& filePath) ctl->sendMessage(msg); } -void SfizzVstEditor::updateStateDisplay() -{ - if (!frame) - return; - - withStateLock([this]() { - if (mustRedisplayState_) { - uiReceiveValue(EditId::SfzFile, state_.sfzFile); - uiReceiveValue(EditId::Volume, state_.volume); - uiReceiveValue(EditId::Polyphony, state_.numVoices); - uiReceiveValue(EditId::Oversampling, 1u << state_.oversamplingLog2); - uiReceiveValue(EditId::PreloadSize, state_.preloadSize); - uiReceiveValue(EditId::ScalaFile, state_.scalaFile); - uiReceiveValue(EditId::ScalaRootKey, state_.scalaRootKey); - uiReceiveValue(EditId::TuningFrequency, state_.tuningFrequency); - uiReceiveValue(EditId::StretchTuning, state_.stretchedTuning); - mustRedisplayState_ = false; - } - - /// - if (mustRedisplayUiState_) { - uiReceiveValue(EditId::UIActivePanel, uiState_.activePanel); - mustRedisplayUiState_ = false; - } - - /// - if (mustRedisplayPlayState_) { - uiReceiveValue(EditId::UINumCurves, playState_.curves); - uiReceiveValue(EditId::UINumMasters, playState_.masters); - uiReceiveValue(EditId::UINumGroups, playState_.groups); - uiReceiveValue(EditId::UINumRegions, playState_.regions); - uiReceiveValue(EditId::UINumPreloadedSamples, playState_.preloadedSamples); - uiReceiveValue(EditId::UINumActiveVoices, playState_.activeVoices); - mustRedisplayPlayState_ = false; - } - }); -} - Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id) { switch (id) { diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index b23f7a4f..a03302a5 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -7,8 +7,8 @@ #pragma once #include "SfizzVstController.h" #include "editor/EditorController.h" -#include "WeakPtr.h" #include "public.sdk/source/vst/vstguieditor.h" +#include #include class Editor; #if !defined(__APPLE__) && !defined(_WIN32) @@ -19,12 +19,14 @@ using namespace Steinberg; using namespace VSTGUI; class SfizzVstEditor : public Vst::VSTGUIEditor, - public EditorController, - public Weakable { + public EditorController { public: using Self = SfizzVstEditor; - explicit SfizzVstEditor(SfizzVstController* controller); + SfizzVstEditor( + SfizzVstController* controller, + absl::Span continuousUpdates, + absl::Span triggerUpdates); ~SfizzVstEditor(); bool PLUGIN_API open(void* parent, const VSTGUI::PlatformType& platformType = VSTGUI::kDefaultNative) override; @@ -37,27 +39,16 @@ public: // VSTGUIEditor CMessageResult notify(CBaseObject* sender, const char* message) override; + // FObject + void PLUGIN_API update(FUnknown* changedUnknown, int32 message) override; // void updateState(const SfizzVstState& state); - void updateUiState(const SfizzUiState& uiState); void updatePlayState(const SfizzPlayState& playState); - SfizzUiState getCurrentUiState() const; - void receiveMessage(const void* data, uint32_t size); - - void remember() override { SfizzVstEditor::addRef(); } - void forget() override { SfizzVstEditor::release(); } - WEAKABLE_REFCOUNT_METHODS(SfizzVstEditor) private: void processOscQueue(); - template void withStateLock(F&& fn) const - { - std::lock_guard lock(stateMutex_); - fn(); - } - protected: // EditorController void uiSendValue(EditId id, const EditValue& v) override; @@ -70,8 +61,6 @@ private: void loadSfzFile(const std::string& filePath); void loadScalaFile(const std::string& filePath); - void updateStateDisplay(); - Vst::ParamID parameterOfEditId(EditId id); std::unique_ptr editor_; @@ -85,13 +74,11 @@ private: // editor state // note: might be updated from a non-UI thread - mutable std::recursive_mutex stateMutex_; // for R/W the state data, and OSC queue - SfizzVstState state_ {}; - SfizzUiState uiState_ {}; - SfizzPlayState playState_ {}; - volatile bool mustRedisplayState_ = false; - volatile bool mustRedisplayUiState_ = false; - volatile bool mustRedisplayPlayState_ = false; typedef std::vector OscByteVec; std::unique_ptr oscQueue_; + std::mutex oscQueueMutex_; + + // subscribed updates + std::vector> continuousUpdates_; + std::vector> triggerUpdates_; }; diff --git a/vst/SfizzVstParameters.h b/vst/SfizzVstParameters.h new file mode 100644 index 00000000..4b1ef007 --- /dev/null +++ b/vst/SfizzVstParameters.h @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "public.sdk/source/vst/vstparameters.h" +#include + +using namespace Steinberg; + +// number of MIDI CC +enum { + kNumControllerParams = 128, +}; + +// parameters +enum { + kPidVolume, + kPidNumVoices, + kPidOversampling, + kPidPreloadSize, + kPidScalaRootKey, + kPidTuningFrequency, + kPidStretchedTuning, + kPidMidiAftertouch, + kPidMidiPitchBend, + kPidMidiCC0, + kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, + /* Reserved */ +}; + +struct SfizzRange { + float def = 0.0; + float min = 0.0; + float max = 1.0; + + constexpr SfizzRange() {} + constexpr SfizzRange(float def, float min, float max) : def(def), min(min), max(max) {} + + constexpr float normalize(float x) const noexcept + { + return (x - min) / (max - min); + } + + constexpr float denormalize(float x) const noexcept + { + return min + x * (max - min); + } + + Vst::RangeParameter* createParameter(const Vst::TChar *title, Vst::ParamID tag, const Vst::TChar *units = nullptr, int32 stepCount = 0, int32 flags = Vst::ParameterInfo::kCanAutomate, Vst::UnitID unitID = Vst::kRootUnitId, const Vst::TChar *shortTitle = nullptr) const + { + return new Vst::RangeParameter(title, tag, units, min, max, def, stepCount, flags, unitID, shortTitle); + } + + static SfizzRange getForParameter(Vst::ParamID id) + { + switch (id) { + case kPidVolume: + return {0.0, -60.0, +6.0}; + case kPidNumVoices: + return {64.0, 1.0, 256.0}; + case kPidOversampling: + return {0.0, 0.0, 3.0}; + case kPidPreloadSize: + return {8192.0, 1024.0, 65536.0}; + case kPidScalaRootKey: + return {60.0, 0.0, 127.0}; + case kPidTuningFrequency: + return {440.0, 300.0, 500.0}; + case kPidStretchedTuning: + return {0.0, 0.0, 1.0}; + case kPidMidiAftertouch: + return {0.0, 0.0, 1.0}; + case kPidMidiPitchBend: + return {0.0, 0.0, 1.0}; + default: + if (id >= kPidMidiCC0 && id <= kPidMidiCCLast) + return {0.0, 0.0, 1.0}; + throw std::runtime_error("Bad parameter ID"); + } + } +}; + +inline int32 integerLog2(int32 x) +{ + int32 l = 0; + for (; x > 1; x /= 2) ++l; + return l; +} diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index ec1d77d0..f318b269 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -7,6 +7,7 @@ #include "SfizzVstProcessor.h" #include "SfizzVstController.h" #include "SfizzVstState.h" +#include "SfizzVstParameters.h" #include "SfizzFileScan.h" #include "base/source/fstreamer.h" #include "pluginterfaces/vst/ivstevents.h" @@ -315,7 +316,9 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) if (!vq) continue; - Vst::ParamID id = vq->getParameterId(); + const Vst::ParamID id = vq->getParameterId(); + const SfizzRange range = SfizzRange::getForParameter(id); + uint32 pointCount = vq->getPointCount(); int32 sampleOffset; Vst::ParamValue value; @@ -323,11 +326,11 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) switch (id) { case kPidVolume: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) - _state.volume = kParamVolumeRange.denormalize(value); + _state.volume = range.denormalize(value); break; case kPidNumVoices: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { - int32 data = static_cast(kParamNumVoicesRange.denormalize(value)); + int32 data = static_cast(range.denormalize(value)); _state.numVoices = data; if (writeWorkerMessage("SetNumVoices", &data, sizeof(data))) _semaToWorker.post(); @@ -335,7 +338,7 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) break; case kPidOversampling: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { - int32 data = static_cast(kParamOversamplingRange.denormalize(value)); + int32 data = static_cast(range.denormalize(value)); _state.oversamplingLog2 = data; if (writeWorkerMessage("SetOversampling", &data, sizeof(data))) _semaToWorker.post(); @@ -343,7 +346,7 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) break; case kPidPreloadSize: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { - int32 data = static_cast(kParamPreloadSizeRange.denormalize(value)); + int32 data = static_cast(range.denormalize(value)); _state.preloadSize = data; if (writeWorkerMessage("SetPreloadSize", &data, sizeof(data))) _semaToWorker.post(); @@ -351,15 +354,15 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) break; case kPidScalaRootKey: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) - _state.scalaRootKey = static_cast(kParamScalaRootKeyRange.denormalize(value)); + _state.scalaRootKey = static_cast(range.denormalize(value)); break; case kPidTuningFrequency: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) - _state.tuningFrequency = kParamTuningFrequencyRange.denormalize(value); + _state.tuningFrequency = range.denormalize(value); break; case kPidStretchedTuning: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) - _state.stretchedTuning = kParamStretchedTuningRange.denormalize(value); + _state.stretchedTuning = range.denormalize(value); break; } } diff --git a/vst/SfizzVstState.cpp b/vst/SfizzVstState.cpp index 1eaac01f..2c3a6d09 100644 --- a/vst/SfizzVstState.cpp +++ b/vst/SfizzVstState.cpp @@ -102,35 +102,3 @@ tresult SfizzVstState::store(IBStream* state) const } constexpr uint64 SfizzVstState::currentStateVersion; - -tresult SfizzUiState::load(IBStream* state) -{ - IBStreamer s(state, kLittleEndian); - - uint64 version = 0; - if (!s.readInt64u(version)) - return kResultFalse; - - if (!s.readInt32u(activePanel)) - return kResultFalse; - - if (version > 0) - return kResultFalse; - - return kResultTrue; -} - -tresult SfizzUiState::store(IBStream* state) const -{ - IBStreamer s(state, kLittleEndian); - - if (!s.writeInt64u(currentStateVersion)) - return kResultFalse; - - if (!s.writeInt32u(activePanel)) - return kResultFalse; - - return kResultTrue; -} - -constexpr uint64 SfizzUiState::currentStateVersion; diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index 531e2dac..de35acb8 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -6,32 +6,10 @@ #pragma once #include "base/source/fstreamer.h" -#include "public.sdk/source/vst/vstparameters.h" #include using namespace Steinberg; -// number of MIDI CC -enum { - kNumControllerParams = 128, -}; - -// parameters -enum { - kPidVolume, - kPidNumVoices, - kPidOversampling, - kPidPreloadSize, - kPidScalaRootKey, - kPidTuningFrequency, - kPidStretchedTuning, - kPidMidiAftertouch, - kPidMidiPitchBend, - kPidMidiCC0, - kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, - /* Reserved */ -}; - class SfizzVstState { public: SfizzVstState() { sfzFile.reserve(8192); scalaFile.reserve(8192); } @@ -52,16 +30,6 @@ public: tresult store(IBStream* state) const; }; -class SfizzUiState { -public: - uint32 activePanel = 0; - - static constexpr uint64 currentStateVersion = 0; - - tresult load(IBStream* state); - tresult store(IBStream* state) const; -}; - struct SfizzPlayState { uint32 curves; uint32 masters; @@ -70,35 +38,3 @@ struct SfizzPlayState { uint32 preloadedSamples; uint32 activeVoices; }; - -struct SfizzParameterRange { - float def = 0.0; - float min = 0.0; - float max = 1.0; - - constexpr SfizzParameterRange() {} - constexpr SfizzParameterRange(float def, float min, float max) : def(def), min(min), max(max) {} - - constexpr float normalize(float x) const noexcept - { - return (x - min) / (max - min); - } - - constexpr float denormalize(float x) const noexcept - { - return min + x * (max - min); - } - - Vst::RangeParameter* createParameter(const Vst::TChar *title, Vst::ParamID tag, const Vst::TChar *units = nullptr, int32 stepCount = 0, int32 flags = Vst::ParameterInfo::kCanAutomate, Vst::UnitID unitID = Vst::kRootUnitId, const Vst::TChar *shortTitle = nullptr) const - { - return new Vst::RangeParameter(title, tag, units, min, max, def, stepCount, flags, unitID, shortTitle); - } -}; - -static constexpr SfizzParameterRange kParamVolumeRange(0.0, -60.0, +6.0); -static constexpr SfizzParameterRange kParamNumVoicesRange(64.0, 1.0, 256.0); -static constexpr SfizzParameterRange kParamOversamplingRange(0.0, 0.0, 3.0); -static constexpr SfizzParameterRange kParamPreloadSizeRange(8192.0, 1024.0, 65536.0); -static constexpr SfizzParameterRange kParamScalaRootKeyRange(60.0, 0.0, 127.0); -static constexpr SfizzParameterRange kParamTuningFrequencyRange(440.0, 300.0, 500.0); -static constexpr SfizzParameterRange kParamStretchedTuningRange(0.0, 0.0, 1.0); diff --git a/vst/SfizzVstUpdates.cpp b/vst/SfizzVstUpdates.cpp new file mode 100644 index 00000000..bed9b5a4 --- /dev/null +++ b/vst/SfizzVstUpdates.cpp @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzVstUpdates.h" +#include + +OSCUpdate::~OSCUpdate() +{ + clear(); +} + +void OSCUpdate::clear() +{ + if (allocated_) + delete[] reinterpret_cast(data_); + data_ = nullptr; + size_ = 0; + allocated_ = false; +} + +void OSCUpdate::setMessage(const void* data, Steinberg::uint32 size, bool copy) +{ + clear(); + + if (copy) { + uint8_t *buffer = new uint8_t[size]; + std::memcpy(buffer, data, size); + data = buffer; + } + + data_ = data; + size_ = size; + allocated_ = copy; +} diff --git a/vst/SfizzVstUpdates.h b/vst/SfizzVstUpdates.h new file mode 100644 index 00000000..26e80cee --- /dev/null +++ b/vst/SfizzVstUpdates.h @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "SfizzVstState.h" +#include +#include +#include +#include +#include + +/** + * @brief Update which notifies a single OSC message + * Is is supposed to be used synchronously. + * (ie. FObject::changed or UpdateHandler::triggerUpdates) + */ +class OSCUpdate : public Steinberg::FObject { +public: + OSCUpdate() noexcept = default; + ~OSCUpdate(); + void clear(); + void setMessage(const void* data, uint32_t size, bool copy); + + const void* data() const noexcept { return data_; } + const uint32_t size() const noexcept { return size_; } + + OBJ_METHODS(OSCUpdate, FObject) + +private: + const void* data_ = nullptr; + uint32_t size_ = 0; + bool allocated_ = false; + +private: + OSCUpdate(const OSCUpdate&) = delete; + OSCUpdate& operator=(const OSCUpdate&) = delete; +}; + +/** + * @brief Update which notifies a change of file path pseudo-parameter + * The message ID is used to indicate which path it is. + */ +class FilePathUpdate : public Steinberg::FObject { +public: + explicit FilePathUpdate(int32 type) + : type_(type) + { + } + + int32 getType() const noexcept + { + return type_; + } + + void setPath(std::string newPath) + { + std::lock_guard lock(mutex_); + path_ = std::move(newPath); + } + + std::string getPath() const + { + std::lock_guard lock(mutex_); + return path_; + } + + OBJ_METHODS(FilePathUpdate, FObject) + +private: + int32 type_ {}; + std::string path_; + mutable std::mutex mutex_; +}; + +enum { + kFilePathUpdateSfz, + kFilePathUpdateScala, +}; + +/** + * @brief Update which indicates the processor status. + */ +class ProcessorStateUpdate : public Steinberg::FObject { +public: + void setState(SfizzVstState newState) + { + std::lock_guard lock(mutex_); + state_ = std::move(newState); + } + + SfizzVstState getState() const + { + std::lock_guard lock(mutex_); + return state_; + } + + OBJ_METHODS(ProcessorStateUpdate, FObject) + +private: + SfizzVstState state_; + mutable std::mutex mutex_; +}; + +/** + * @brief Update which indicates the playing SFZ status. + */ +class PlayStateUpdate : public Steinberg::FObject { +public: + void setState(SfizzPlayState newState) + { + std::lock_guard lock(mutex_); + state_ = std::move(newState); + } + + SfizzPlayState getState() const + { + std::lock_guard lock(mutex_); + return state_; + } + + OBJ_METHODS(PlayStateUpdate, FObject) + +private: + SfizzPlayState state_; + mutable std::mutex mutex_; +}; diff --git a/vst/WeakPtr.h b/vst/WeakPtr.h deleted file mode 100644 index 55481e35..00000000 --- a/vst/WeakPtr.h +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#pragma once -#include "base/source/fobject.h" -#include -#include - -/** - * A weak reference implementation for Steinberg FObject. - * - * Implementation - * ============== - * - * This takes over the ordinary addRef() and release() methods. - * The variable `refCount` is accessed manually, under a shared mutex. - * There is a unique data block which is shared with all weak pointers, the - * system will null it atomically when the reference count hits zero. - * - * Usage - * ===== - * - * class MyObject : public FObject, public Weakable { - * [...] - * WEAKABLE_REFCOUNT_METHODS(MyObject) - * }; - * - * WeakPtr ptr = myObject.getWeakPtr(); - */ - -template -class Weakable; - -#define WEAKABLE_REFCOUNT_METHODS(T) \ -public: \ - Steinberg::uint32 PLUGIN_API addRef() SMTG_OVERRIDE { return weakAddRef(); } \ - Steinberg::uint32 PLUGIN_API release() SMTG_OVERRIDE { return weakRelease(); } \ -private: \ - friend class Weakable; \ - friend class WeakPtr; - -/// -template -struct WeakPtrSharedData : public std::enable_shared_from_this> { - explicit WeakPtrSharedData(T* self) : self_(self) {} - std::mutex mutex_; - T* self_ = nullptr; -}; - -/// -template -class WeakPtr { - friend class Weakable; - using SharedData = WeakPtrSharedData; - -public: - WeakPtr() = default; - - Steinberg::IPtr lock() - { - std::shared_ptr data = data_.lock(); - if (!data) - return nullptr; - std::lock_guard lock { data->mutex_ }; - T* self = data->self_; - if (self) - ++self->refCount; // manually because we are holding the lock - return Steinberg::IPtr(self, false); - } - -private: - explicit WeakPtr(std::weak_ptr data) : data_(data) {} - std::weak_ptr data_; -}; - -/// -template -class Weakable { - using SharedData = WeakPtrSharedData; - -public: - Weakable() - : weakData_(new SharedData(static_cast(this))) - { - } - - WeakPtr getWeakPtr() - { - return WeakPtr(weakData_); - } - -protected: - Steinberg::uint32 weakAddRef() //override - { - T* self = static_cast(this); - std::lock_guard lock { weakData_->mutex_ }; - return ++self->refCount; - } - - Steinberg::uint32 weakRelease() //override - { - T* self = static_cast(this); - std::shared_ptr data = weakData_; - std::unique_lock lock { data->mutex_ }; - Steinberg::uint32 count = --self->refCount; - if (count == 0) { - data->self_ = nullptr; - weakData_.reset(); - self->refCount = -1000; - lock.unlock(); - delete self; - return 0; - } - return count; - } - -private: - std::shared_ptr weakData_; -}; From 35e92405401290fea82f04ff9669f7af07e4d1f7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 4 Feb 2021 08:16:17 +0100 Subject: [PATCH 216/668] Make it build --- vst/SfizzVstUpdates.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vst/SfizzVstUpdates.h b/vst/SfizzVstUpdates.h index 26e80cee..7eebc0be 100644 --- a/vst/SfizzVstUpdates.h +++ b/vst/SfizzVstUpdates.h @@ -19,7 +19,7 @@ */ class OSCUpdate : public Steinberg::FObject { public: - OSCUpdate() noexcept = default; + OSCUpdate() = default; ~OSCUpdate(); void clear(); void setMessage(const void* data, uint32_t size, bool copy); From 96d4eca1ae0331ae95e58858a7266d7475066268 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 4 Feb 2021 08:29:57 +0100 Subject: [PATCH 217/668] More efficient (and safer?) --- vst/SfizzVstController.cpp | 75 ++++++++++++++++++-------------------- vst/SfizzVstUpdates.h | 7 ++++ 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index b6ac8945..c1ab5c73 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -151,35 +151,32 @@ tresult PLUGIN_API SfizzVstControllerNoUi::setParamNormalized(Vst::ParamID tag, if (r != kResultTrue) return r; - SfizzVstState state = processorStateUpdate_->getState(); - - const SfizzRange range = SfizzRange::getForParameter(tag); - - switch (tag) { - case kPidVolume: - state.volume = range.denormalize(normValue); - break; - case kPidNumVoices: - state.numVoices = (int32)range.denormalize(normValue); - break; - case kPidOversampling: - state.oversamplingLog2 = (int32)range.denormalize(normValue); - break; - case kPidPreloadSize: - state.preloadSize = (int32)range.denormalize(normValue); - break; - case kPidScalaRootKey: - state.scalaRootKey = (int32)range.denormalize(normValue); - break; - case kPidTuningFrequency: - state.tuningFrequency = (float)range.denormalize(normValue); - break; - case kPidStretchedTuning: - state.stretchedTuning = range.denormalize(normValue); - break; - } - - processorStateUpdate_->setState(state); + processorStateUpdate_->access([tag, normValue](SfizzVstState& state) { + const SfizzRange range = SfizzRange::getForParameter(tag); + switch (tag) { + case kPidVolume: + state.volume = range.denormalize(normValue); + break; + case kPidNumVoices: + state.numVoices = (int32)range.denormalize(normValue); + break; + case kPidOversampling: + state.oversamplingLog2 = (int32)range.denormalize(normValue); + break; + case kPidPreloadSize: + state.preloadSize = (int32)range.denormalize(normValue); + break; + case kPidScalaRootKey: + state.scalaRootKey = (int32)range.denormalize(normValue); + break; + case kPidTuningFrequency: + state.tuningFrequency = (float)range.denormalize(normValue); + break; + case kPidStretchedTuning: + state.stretchedTuning = range.denormalize(normValue); + break; + } + }); return kResultTrue; } @@ -229,11 +226,11 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - SfizzVstState state = processorStateUpdate_->getState(); - state.sfzFile.assign(static_cast(data), size); - processorStateUpdate_->setState(state); - - sfzPathUpdate_->setPath(state.sfzFile); + std::string sfzFile(static_cast(data), size); + processorStateUpdate_->access([&sfzFile](SfizzVstState& state) { + state.sfzFile = sfzFile; + }); + sfzPathUpdate_->setPath(std::move(sfzFile)); sfzPathUpdate_->deferUpdate(); } else if (!strcmp(id, "LoadedScala")) { @@ -244,11 +241,11 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - SfizzVstState state = processorStateUpdate_->getState(); - state.scalaFile.assign(static_cast(data), size); - processorStateUpdate_->setState(state); - - scalaPathUpdate_->setPath(state.scalaFile); + std::string scalaFile(static_cast(data), size); + processorStateUpdate_->access([&scalaFile](SfizzVstState& state) { + state.scalaFile = scalaFile; + }); + scalaPathUpdate_->setPath(std::move(scalaFile)); scalaPathUpdate_->deferUpdate(); } else if (!strcmp(id, "NotifiedPlayState")) { diff --git a/vst/SfizzVstUpdates.h b/vst/SfizzVstUpdates.h index 7eebc0be..0837a047 100644 --- a/vst/SfizzVstUpdates.h +++ b/vst/SfizzVstUpdates.h @@ -97,6 +97,13 @@ public: return state_; } + template + void access(F&& fn) + { + std::lock_guard lock(mutex_); + fn(state_); + } + OBJ_METHODS(ProcessorStateUpdate, FObject) private: From 9e0af1c6a4550d61aad865a9ff4955ca49e5edfc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 4 Feb 2021 09:04:23 +0100 Subject: [PATCH 218/668] Fix for Visual Studio build --- vst/SfizzVstUpdates.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vst/SfizzVstUpdates.cpp b/vst/SfizzVstUpdates.cpp index bed9b5a4..ab6c69f5 100644 --- a/vst/SfizzVstUpdates.cpp +++ b/vst/SfizzVstUpdates.cpp @@ -21,7 +21,7 @@ void OSCUpdate::clear() allocated_ = false; } -void OSCUpdate::setMessage(const void* data, Steinberg::uint32 size, bool copy) +void OSCUpdate::setMessage(const void* data, uint32_t size, bool copy) { clear(); From d3a53e05d43c477f998c9f9a90fa941eceb529de Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 4 Feb 2021 13:34:44 +0100 Subject: [PATCH 219/668] VST pitch bend should default to middle --- vst/SfizzVstParameters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vst/SfizzVstParameters.h b/vst/SfizzVstParameters.h index 4b1ef007..abaa55e6 100644 --- a/vst/SfizzVstParameters.h +++ b/vst/SfizzVstParameters.h @@ -74,7 +74,7 @@ struct SfizzRange { case kPidMidiAftertouch: return {0.0, 0.0, 1.0}; case kPidMidiPitchBend: - return {0.0, 0.0, 1.0}; + return {0.5, 0.0, 1.0}; default: if (id >= kPidMidiCC0 && id <= kPidMidiCCLast) return {0.0, 0.0, 1.0}; From 629d6818900d7812a1d978ef17d0e2fde9fd8d95 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 4 Feb 2021 16:20:06 +0100 Subject: [PATCH 220/668] Fix linking LV2 with version file --- lv2/CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index d247dd14..39c447ec 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -35,12 +35,10 @@ endif() # Explicitely strip all symbols on Linux but lv2_descriptor() # MacOS linker does not support this apparently https://bugs.webkit.org/show_bug.cgi?id=144555 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - file(COPY lv2.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) - target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE "-Wl,--version-script=lv2.version") + target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/lv2.version") # target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,-u,lv2_descriptor") if(SFIZZ_LV2_UI) - file(COPY lv2ui.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) - target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE "-Wl,--version-script=lv2ui.version") + target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/lv2ui.version") # target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,-u,lv2ui_descriptor") endif() endif() From 4dbba3f1cc42c94e3fdea103b2b6b4d6003f786b Mon Sep 17 00:00:00 2001 From: redtide Date: Thu, 4 Feb 2021 20:43:55 +0100 Subject: [PATCH 221/668] Added missing build options status --- cmake/SfizzConfig.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 56580ed3..a838f951 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -89,12 +89,15 @@ Build processor: ${SFIZZ_SYSTEM_PROCESSOR} Build using LTO: ${ENABLE_LTO} Build as shared library: ${SFIZZ_SHARED} Build JACK stand-alone client: ${SFIZZ_JACK} +Build render client: ${SFIZZ_RENDER} Build LV2 plug-in: ${SFIZZ_LV2} Build LV2 user interface: ${SFIZZ_LV2_UI} Build VST plug-in: ${SFIZZ_VST} Build AU plug-in: ${SFIZZ_AU} Build benchmarks: ${SFIZZ_BENCHMARKS} Build tests: ${SFIZZ_TESTS} +Build demos: ${SFIZZ_DEMOS} +Build devtools: ${SFIZZ_DEVTOOLS} Use sndfile: ${SFIZZ_USE_SNDFILE} Use vcpkg: ${SFIZZ_USE_VCPKG} Statically link dependencies: ${SFIZZ_STATIC_DEPENDENCIES} From 4f359e456cd36149df4d4fc4894ff8c0773e9eaf Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 4 Feb 2021 21:04:31 +0100 Subject: [PATCH 222/668] Update makefile --- common.mk | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/common.mk b/common.mk index ea5553ff..81d513df 100644 --- a/common.mk +++ b/common.mk @@ -146,10 +146,10 @@ endif # st_audiofile dependency SFIZZ_SOURCES += \ - $(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile.c \ - $(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_common.c \ - $(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_libs.c \ - $(SFIZZ_DIR)/external/st_audiofile/src/st_audiofile_sndfile.c + external/st_audiofile/src/st_audiofile.c \ + external/st_audiofile/src/st_audiofile_common.c \ + external/st_audiofile/src/st_audiofile_libs.c \ + external/st_audiofile/src/st_audiofile_sndfile.c SFIZZ_C_FLAGS += \ -I$(SFIZZ_DIR)/external/st_audiofile/src \ @@ -339,6 +339,12 @@ SFIZZ_SOURCES += \ SFIZZ_CXX_FLAGS += \ -I$(SFIZZ_DIR)/external/jsl/include +### cephes dependency + +SFIZZ_SOURCES += \ + external/cephes/src/chbevl.c \ + external/cephes/src/i0.c + ### math dependency ifdef SFIZZ_OS_LINUX From cbd1f6027106e1c726a205fba2eb8dc32f36c646 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 5 Feb 2021 17:33:16 +0100 Subject: [PATCH 223/668] Notify VST when SFZ is changed by reload --- vst/SfizzVstProcessor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index f318b269..972b34dc 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -625,6 +625,11 @@ void SfizzVstProcessor::doBackgroundWork() fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n"); std::lock_guard lock(_processMutex); loadSfzFileOrDefault(*_synth, _state.sfzFile); + + Steinberg::OPtr reply { allocateMessage() }; + reply->setMessageID("LoadedSfz"); + reply->getAttributes()->setBinary("File", _state.sfzFile.data(), _state.sfzFile.size()); + sendMessage(reply); } else if (_synth->shouldReloadScala()) { fprintf(stderr, "[Sfizz] scala file has changed, reloading\n"); From 595301ab3491f7976aeca8c7c6e2e89e319450af Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 5 Feb 2021 17:42:24 +0100 Subject: [PATCH 224/668] Text truncation for CC labels --- editor/src/editor/GUIComponents.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 5051e952..e188dbf5 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -570,6 +570,8 @@ void SControlsPanel::setControlUsed(uint32_t index, bool used) label->setStyle(CTextLabel::kRoundRectStyle); label->setRoundRectRadius(5.0); label->setBackColor(CColor(0x2e, 0x34, 0x36)); + label->setTextTruncateMode(CTextLabel::kTruncateTail); + label->setTextInset({4.0, 0.0}); label->setText(getDefaultLabelText(index)); knob->setActiveTrackColor(CColor(0x00, 0xb6, 0x2a)); knob->setInactiveTrackColor(CColor(0x30, 0x30, 0x30)); @@ -630,11 +632,12 @@ void SControlsPanel::setControlLabelText(uint32_t index, UTF8StringPtr text) if (!slot) return; + CTextLabel* label = slot->label; if (text && text[0] != '\0') - slot->label->setText(text); + label->setText(text); else - slot->label->setText(getDefaultLabelText(index).c_str()); - slot->label->invalid(); + label->setText(getDefaultLabelText(index).c_str()); + label->invalid(); } void SControlsPanel::recalculateSubViews() From 60ae910faf01025ed0fbbfcd95e5a9bef5422060 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 7 Feb 2021 00:18:47 +0100 Subject: [PATCH 225/668] Corrected a compile error on gcc 9.3 Removed the leak detector, which allows for POD data structures with no default functions. This way the `noexcept` specifier on the `atomic_queue` is actually valid, since the `FileTime` and `CallbackTime` objects can be built without throwing. --- src/sfizz/Logger.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/sfizz/Logger.h b/src/sfizz/Logger.h index de7e8beb..4e39471b 100644 --- a/src/sfizz/Logger.h +++ b/src/sfizz/Logger.h @@ -48,18 +48,10 @@ struct ScopedTiming struct FileTime { - FileTime() = default; - FileTime(Duration waitDuration, Duration loadDuration, uint32_t fileSize, absl::string_view filename) - : waitDuration(waitDuration), loadDuration(loadDuration), fileSize(fileSize), filename(filename) { } - FileTime(const FileTime&) = default; - FileTime& operator=(const FileTime&) = default; - FileTime(FileTime&&) = default; - FileTime& operator=(FileTime&&) = default; Duration waitDuration { 0 }; Duration loadDuration { 0 }; uint32_t fileSize { 0 }; absl::string_view filename {}; - LEAK_DETECTOR(FileTime); }; struct CallbackBreakdown @@ -71,22 +63,13 @@ struct CallbackBreakdown Duration filters { 0 }; Duration panning { 0 }; Duration effects { 0 }; - LEAK_DETECTOR(CallbackBreakdown); }; struct CallbackTime { - CallbackTime() = default; - CallbackTime(const CallbackBreakdown& breakdown, int numVoices, size_t numSamples) - : breakdown(breakdown), numVoices(numVoices), numSamples(numSamples) { } - CallbackTime(const CallbackTime&) = default; - CallbackTime& operator=(const CallbackTime&) = default; - CallbackTime(CallbackTime&&) = default; - CallbackTime& operator=(CallbackTime&&) = default; CallbackBreakdown breakdown {}; int numVoices { 0 }; size_t numSamples { 0 }; - LEAK_DETECTOR(CallbackTime); }; class Logger From a7cfb8429c2995b5db93d2e47abc1a36a1f45a7f Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 8 Feb 2021 12:02:26 +0100 Subject: [PATCH 226/668] Fixups for MOD --- src/sfizz/Logger.cpp | 13 +++++++++++-- src/sfizz/Logger.h | 3 +++ tests/SynthT.cpp | 8 ++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sfizz/Logger.cpp b/src/sfizz/Logger.cpp index 73b07e86..89e77767 100644 --- a/src/sfizz/Logger.cpp +++ b/src/sfizz/Logger.cpp @@ -102,7 +102,11 @@ void sfz::Logger::logCallbackTime(const CallbackBreakdown& breakdown, int numVoi if (!loggingEnabled) return; - callbackTimeQueue.try_push({ breakdown, numVoices, numSamples }); + CallbackTime callbackTime; + callbackTime.breakdown = breakdown; + callbackTime.numVoices = numVoices; + callbackTime.numSamples = numSamples; + callbackTimeQueue.try_push(callbackTime); } void sfz::Logger::logFileTime(std::chrono::duration waitDuration, std::chrono::duration loadDuration, uint32_t fileSize, absl::string_view filename) @@ -110,7 +114,12 @@ void sfz::Logger::logFileTime(std::chrono::duration waitDuration, std::c if (!loggingEnabled) return; - fileTimeQueue.try_push({ waitDuration, loadDuration, fileSize, filename }); + FileTime fileTime; + fileTime.waitDuration = waitDuration; + fileTime.loadDuration = loadDuration; + fileTime.fileSize = fileSize; + fileTime.filename = filename; + fileTimeQueue.try_push(fileTime); } void sfz::Logger::setPrefix(absl::string_view prefix) diff --git a/src/sfizz/Logger.h b/src/sfizz/Logger.h index 4e39471b..aa0d3953 100644 --- a/src/sfizz/Logger.h +++ b/src/sfizz/Logger.h @@ -52,6 +52,7 @@ struct FileTime Duration loadDuration { 0 }; uint32_t fileSize { 0 }; absl::string_view filename {}; + LEAK_DETECTOR(FileTime); }; struct CallbackBreakdown @@ -63,6 +64,7 @@ struct CallbackBreakdown Duration filters { 0 }; Duration panning { 0 }; Duration effects { 0 }; + LEAK_DETECTOR(CallbackBreakdown); }; struct CallbackTime @@ -70,6 +72,7 @@ struct CallbackTime CallbackBreakdown breakdown {}; int numVoices { 0 }; size_t numSamples { 0 }; + LEAK_DETECTOR(CallbackTime); }; class Logger diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index b9bf7ab8..2420df44 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -515,10 +515,10 @@ TEST_CASE("[Synth] veltrack") }; const VeltrackData veltrackdata[] = { - { 25, veldata25 }, - { 50, veldata50 }, - { 75, veldata75 }, - { 100, veldata100 }, + { 25, absl::MakeConstSpan(veldata25) }, + { 50, absl::MakeConstSpan(veldata50) }, + { 75, absl::MakeConstSpan(veldata75) }, + { 100, absl::MakeConstSpan(veldata100) }, }; for (const VeltrackData& vt : veltrackdata) { From f6d92916ae43febc90d4d7700dc3ea1ebca79805 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 15:41:21 +0100 Subject: [PATCH 227/668] Move plugins to subdirectories --- .gitmodules | 10 +++++----- CMakeLists.txt | 6 +++--- {editor => plugins/editor}/CMakeLists.txt | 0 {editor => plugins/editor}/cmake/Vstgui.cmake | 0 {editor => plugins/editor}/external/vstgui4 | 0 {editor => plugins/editor}/layout/main.fl | 0 .../editor}/resources/Fonts/Roboto-Regular.ttf | Bin .../resources/Fonts/sfizz-fluentui-system-r20.ttf | Bin {editor => plugins/editor}/resources/background.png | Bin .../editor}/resources/background@2x.png | Bin {editor => plugins/editor}/resources/icon_white.png | Bin {editor => plugins/editor}/resources/icon_white.svg | 0 .../editor}/resources/icon_white@2x.png | Bin {editor => plugins/editor}/resources/knob.knob | Bin {editor => plugins/editor}/resources/knob48.png | Bin {editor => plugins/editor}/resources/knob48@2x.png | Bin {editor => plugins/editor}/resources/logo.png | Bin {editor => plugins/editor}/resources/logo.svg | 0 {editor => plugins/editor}/resources/logo_text.png | Bin {editor => plugins/editor}/resources/logo_text.svg | 0 .../editor}/resources/logo_text@2x.png | Bin .../editor}/resources/logo_text_white.png | Bin .../editor}/resources/logo_text_white@2x.png | Bin {editor => plugins/editor}/src/editor/EditIds.cpp | 0 {editor => plugins/editor}/src/editor/EditIds.h | 0 {editor => plugins/editor}/src/editor/EditValue.h | 0 {editor => plugins/editor}/src/editor/Editor.cpp | 0 {editor => plugins/editor}/src/editor/Editor.h | 0 .../editor}/src/editor/EditorController.h | 0 .../editor}/src/editor/GUIComponents.cpp | 0 .../editor}/src/editor/GUIComponents.h | 0 {editor => plugins/editor}/src/editor/GUIPiano.cpp | 0 {editor => plugins/editor}/src/editor/GUIPiano.h | 0 .../editor}/src/editor/NativeHelpers.cpp | 0 .../editor}/src/editor/NativeHelpers.h | 0 .../editor}/src/editor/NativeHelpers.mm | 0 .../editor}/src/editor/layout/main.hpp | 0 .../editor}/src/editor/utility/vstgui_after.h | 0 .../editor}/src/editor/utility/vstgui_before.h | 0 .../editor}/tools/layout-maker/LICENSE | 0 .../editor}/tools/layout-maker/README | 0 .../editor}/tools/layout-maker/sources/layout.h | 0 .../editor}/tools/layout-maker/sources/main.cpp | 0 .../editor}/tools/layout-maker/sources/reader.cpp | 0 .../editor}/tools/layout-maker/sources/reader.h | 0 {lv2 => plugins/lv2}/CMakeLists.txt | 0 {lv2 => plugins/lv2}/LICENSE.md.in | 0 {lv2 => plugins/lv2}/atomic_compat.h | 0 .../lv2}/external/ardour/ardour/lv2_extensions.h | 0 {lv2 => plugins/lv2}/lgpl-3.0.txt | 0 {lv2 => plugins/lv2}/lv2.version | 0 {lv2 => plugins/lv2}/lv2/atom/atom-test-utils.c | 0 {lv2 => plugins/lv2}/lv2/atom/atom-test.c | 0 {lv2 => plugins/lv2}/lv2/atom/atom.h | 0 {lv2 => plugins/lv2}/lv2/atom/atom.ttl | 0 {lv2 => plugins/lv2}/lv2/atom/forge-overflow-test.c | 0 {lv2 => plugins/lv2}/lv2/atom/forge.h | 0 {lv2 => plugins/lv2}/lv2/atom/lv2-atom.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/atom/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/atom/util.h | 0 {lv2 => plugins/lv2}/lv2/buf-size/buf-size.h | 0 {lv2 => plugins/lv2}/lv2/buf-size/buf-size.ttl | 0 .../lv2}/lv2/buf-size/lv2-buf-size.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/buf-size/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/core/attributes.h | 0 {lv2 => plugins/lv2}/lv2/core/lv2.h | 0 {lv2 => plugins/lv2}/lv2/core/lv2_util.h | 0 {lv2 => plugins/lv2}/lv2/core/lv2core.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/core/lv2core.ttl | 0 {lv2 => plugins/lv2}/lv2/core/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/core/meta.ttl | 0 {lv2 => plugins/lv2}/lv2/data-access/data-access.h | 0 .../lv2}/lv2/data-access/data-access.ttl | 0 .../lv2}/lv2/data-access/lv2-data-access.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/data-access/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/dynmanifest/dynmanifest.h | 0 .../lv2}/lv2/dynmanifest/dynmanifest.ttl | 0 .../lv2}/lv2/dynmanifest/lv2-dynmanifest.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/dynmanifest/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/event/event-helpers.h | 0 {lv2 => plugins/lv2}/lv2/event/event.h | 0 {lv2 => plugins/lv2}/lv2/event/event.ttl | 0 {lv2 => plugins/lv2}/lv2/event/lv2-event.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/event/manifest.ttl | 0 .../lv2}/lv2/instance-access/instance-access.h | 0 .../lv2}/lv2/instance-access/instance-access.ttl | 0 .../instance-access/lv2-instance-access.doap.ttl | 0 .../lv2}/lv2/instance-access/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/log/log.h | 0 {lv2 => plugins/lv2}/lv2/log/log.ttl | 0 {lv2 => plugins/lv2}/lv2/log/logger.h | 0 {lv2 => plugins/lv2}/lv2/log/lv2-log.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/log/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/midi/lv2-midi.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/midi/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/midi/midi.h | 0 {lv2 => plugins/lv2}/lv2/midi/midi.ttl | 0 {lv2 => plugins/lv2}/lv2/morph/lv2-morph.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/morph/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/morph/morph.h | 0 {lv2 => plugins/lv2}/lv2/morph/morph.ttl | 0 .../lv2}/lv2/options/lv2-options.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/options/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/options/options.h | 0 {lv2 => plugins/lv2}/lv2/options/options.ttl | 0 .../lv2}/lv2/parameters/lv2-parameters.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/parameters/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/parameters/parameters.h | 0 {lv2 => plugins/lv2}/lv2/parameters/parameters.ttl | 0 {lv2 => plugins/lv2}/lv2/patch/lv2-patch.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/patch/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/patch/patch.h | 0 {lv2 => plugins/lv2}/lv2/patch/patch.ttl | 0 .../lv2}/lv2/port-groups/lv2-port-groups.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/port-groups/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/port-groups/port-groups.h | 0 .../lv2}/lv2/port-groups/port-groups.ttl | 0 .../lv2}/lv2/port-props/lv2-port-props.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/port-props/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/port-props/port-props.h | 0 {lv2 => plugins/lv2}/lv2/port-props/port-props.ttl | 0 .../lv2}/lv2/presets/lv2-presets.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/presets/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/presets/presets.h | 0 {lv2 => plugins/lv2}/lv2/presets/presets.ttl | 0 .../lv2}/lv2/resize-port/lv2-resize-port.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/resize-port/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/resize-port/resize-port.h | 0 .../lv2}/lv2/resize-port/resize-port.ttl | 0 {lv2 => plugins/lv2}/lv2/state/lv2-state.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/state/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/state/state.h | 0 {lv2 => plugins/lv2}/lv2/state/state.ttl | 0 {lv2 => plugins/lv2}/lv2/time/lv2-time.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/time/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/time/time.h | 0 {lv2 => plugins/lv2}/lv2/time/time.ttl | 0 {lv2 => plugins/lv2}/lv2/ui/lv2-ui.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/ui/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/ui/ui.h | 0 {lv2 => plugins/lv2}/lv2/ui/ui.ttl | 0 {lv2 => plugins/lv2}/lv2/units/lv2-units.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/units/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/units/units.h | 0 {lv2 => plugins/lv2}/lv2/units/units.ttl | 0 .../lv2}/lv2/uri-map/lv2-uri-map.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/uri-map/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/uri-map/uri-map.h | 0 {lv2 => plugins/lv2}/lv2/uri-map/uri-map.ttl | 0 {lv2 => plugins/lv2}/lv2/urid/lv2-urid.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/urid/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/urid/urid.h | 0 {lv2 => plugins/lv2}/lv2/urid/urid.ttl | 0 {lv2 => plugins/lv2}/lv2/worker/lv2-worker.doap.ttl | 0 {lv2 => plugins/lv2}/lv2/worker/manifest.ttl | 0 {lv2 => plugins/lv2}/lv2/worker/worker.h | 0 {lv2 => plugins/lv2}/lv2/worker/worker.ttl | 0 {lv2 => plugins/lv2}/lv2ui.version | 0 {lv2 => plugins/lv2}/manifest.ttl.in | 0 .../lv2}/resources/DefaultInstrument.sfz | 0 {lv2 => plugins/lv2}/resources/DefaultScale.scl | 0 {lv2 => plugins/lv2}/sfizz.c | 0 {lv2 => plugins/lv2}/sfizz.ttl.in | 0 {lv2 => plugins/lv2}/sfizz_lv2.h | 0 {lv2 => plugins/lv2}/sfizz_ui.cpp | 0 {lv2 => plugins/lv2}/sfizz_ui.ttl.in | 0 {lv2 => plugins/lv2}/vstgui_helpers.cpp | 0 {lv2 => plugins/lv2}/vstgui_helpers.h | 0 {vst => plugins/vst}/CMakeLists.txt | 0 {vst => plugins/vst}/FileTrie.cpp | 0 {vst => plugins/vst}/FileTrie.h | 0 {vst => plugins/vst}/IdleUpdateHandler.h | 0 {vst => plugins/vst}/NativeHelpers.cpp | 0 {vst => plugins/vst}/NativeHelpers.h | 0 {vst => plugins/vst}/NativeHelpers.mm | 0 {vst => plugins/vst}/SfizzFileScan.cpp | 0 {vst => plugins/vst}/SfizzFileScan.h | 0 {vst => plugins/vst}/SfizzForeignPaths.cpp | 0 {vst => plugins/vst}/SfizzForeignPaths.h | 0 {vst => plugins/vst}/SfizzForeignPaths.mm | 0 {vst => plugins/vst}/SfizzSettings.cpp | 0 {vst => plugins/vst}/SfizzSettings.h | 0 {vst => plugins/vst}/SfizzSettings.mm | 0 {vst => plugins/vst}/SfizzVstController.cpp | 0 {vst => plugins/vst}/SfizzVstController.h | 0 {vst => plugins/vst}/SfizzVstEditor.cpp | 0 {vst => plugins/vst}/SfizzVstEditor.h | 0 {vst => plugins/vst}/SfizzVstParameters.h | 0 {vst => plugins/vst}/SfizzVstProcessor.cpp | 0 {vst => plugins/vst}/SfizzVstProcessor.h | 0 {vst => plugins/vst}/SfizzVstState.cpp | 0 {vst => plugins/vst}/SfizzVstState.h | 0 {vst => plugins/vst}/SfizzVstUpdates.cpp | 0 {vst => plugins/vst}/SfizzVstUpdates.h | 0 {vst => plugins/vst}/VstPluginDefs.h.in | 0 {vst => plugins/vst}/VstPluginFactory.cpp | 0 {vst => plugins/vst}/X11RunLoop.cpp | 0 {vst => plugins/vst}/X11RunLoop.h | 0 {vst => plugins/vst}/cmake/Vst3.cmake | 0 {vst => plugins/vst}/external/VST_SDK/VST3_SDK/base | 0 .../vst}/external/VST_SDK/VST3_SDK/pluginterfaces | 0 .../vst}/external/VST_SDK/VST3_SDK/public.sdk | 0 {vst => plugins/vst}/external/ring_buffer/LICENSE | 0 .../ring_buffer/ring_buffer/ring_buffer.cpp | 0 .../external/ring_buffer/ring_buffer/ring_buffer.h | 0 .../ring_buffer/ring_buffer/ring_buffer.tcc | 0 {vst => plugins/vst}/external/sfzt_auwrapper | 0 {vst => plugins/vst}/gpl-3.0.txt | 0 {vst => plugins/vst}/mac/Info.au.plist | 0 {vst => plugins/vst}/mac/Info.vst3.plist | 0 {vst => plugins/vst}/mac/PkgInfo | 0 {vst => plugins/vst}/mac/audiounitconfig.h.in | 0 {vst => plugins/vst}/vst3.def | 0 {vst => plugins/vst}/vst3.version | 0 {vst => plugins/vst}/win/Plugin.ico | Bin {vst => plugins/vst}/win/desktop.ini | 0 216 files changed, 8 insertions(+), 8 deletions(-) rename {editor => plugins/editor}/CMakeLists.txt (100%) rename {editor => plugins/editor}/cmake/Vstgui.cmake (100%) rename {editor => plugins/editor}/external/vstgui4 (100%) rename {editor => plugins/editor}/layout/main.fl (100%) rename {editor => plugins/editor}/resources/Fonts/Roboto-Regular.ttf (100%) rename {editor => plugins/editor}/resources/Fonts/sfizz-fluentui-system-r20.ttf (100%) rename {editor => plugins/editor}/resources/background.png (100%) rename {editor => plugins/editor}/resources/background@2x.png (100%) rename {editor => plugins/editor}/resources/icon_white.png (100%) rename {editor => plugins/editor}/resources/icon_white.svg (100%) rename {editor => plugins/editor}/resources/icon_white@2x.png (100%) rename {editor => plugins/editor}/resources/knob.knob (100%) rename {editor => plugins/editor}/resources/knob48.png (100%) rename {editor => plugins/editor}/resources/knob48@2x.png (100%) rename {editor => plugins/editor}/resources/logo.png (100%) rename {editor => plugins/editor}/resources/logo.svg (100%) rename {editor => plugins/editor}/resources/logo_text.png (100%) rename {editor => plugins/editor}/resources/logo_text.svg (100%) rename {editor => plugins/editor}/resources/logo_text@2x.png (100%) rename {editor => plugins/editor}/resources/logo_text_white.png (100%) rename {editor => plugins/editor}/resources/logo_text_white@2x.png (100%) rename {editor => plugins/editor}/src/editor/EditIds.cpp (100%) rename {editor => plugins/editor}/src/editor/EditIds.h (100%) rename {editor => plugins/editor}/src/editor/EditValue.h (100%) rename {editor => plugins/editor}/src/editor/Editor.cpp (100%) rename {editor => plugins/editor}/src/editor/Editor.h (100%) rename {editor => plugins/editor}/src/editor/EditorController.h (100%) rename {editor => plugins/editor}/src/editor/GUIComponents.cpp (100%) rename {editor => plugins/editor}/src/editor/GUIComponents.h (100%) rename {editor => plugins/editor}/src/editor/GUIPiano.cpp (100%) rename {editor => plugins/editor}/src/editor/GUIPiano.h (100%) rename {editor => plugins/editor}/src/editor/NativeHelpers.cpp (100%) rename {editor => plugins/editor}/src/editor/NativeHelpers.h (100%) rename {editor => plugins/editor}/src/editor/NativeHelpers.mm (100%) rename {editor => plugins/editor}/src/editor/layout/main.hpp (100%) rename {editor => plugins/editor}/src/editor/utility/vstgui_after.h (100%) rename {editor => plugins/editor}/src/editor/utility/vstgui_before.h (100%) rename {editor => plugins/editor}/tools/layout-maker/LICENSE (100%) rename {editor => plugins/editor}/tools/layout-maker/README (100%) rename {editor => plugins/editor}/tools/layout-maker/sources/layout.h (100%) rename {editor => plugins/editor}/tools/layout-maker/sources/main.cpp (100%) rename {editor => plugins/editor}/tools/layout-maker/sources/reader.cpp (100%) rename {editor => plugins/editor}/tools/layout-maker/sources/reader.h (100%) rename {lv2 => plugins/lv2}/CMakeLists.txt (100%) rename {lv2 => plugins/lv2}/LICENSE.md.in (100%) rename {lv2 => plugins/lv2}/atomic_compat.h (100%) rename {lv2 => plugins/lv2}/external/ardour/ardour/lv2_extensions.h (100%) rename {lv2 => plugins/lv2}/lgpl-3.0.txt (100%) rename {lv2 => plugins/lv2}/lv2.version (100%) rename {lv2 => plugins/lv2}/lv2/atom/atom-test-utils.c (100%) rename {lv2 => plugins/lv2}/lv2/atom/atom-test.c (100%) rename {lv2 => plugins/lv2}/lv2/atom/atom.h (100%) rename {lv2 => plugins/lv2}/lv2/atom/atom.ttl (100%) rename {lv2 => plugins/lv2}/lv2/atom/forge-overflow-test.c (100%) rename {lv2 => plugins/lv2}/lv2/atom/forge.h (100%) rename {lv2 => plugins/lv2}/lv2/atom/lv2-atom.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/atom/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/atom/util.h (100%) rename {lv2 => plugins/lv2}/lv2/buf-size/buf-size.h (100%) rename {lv2 => plugins/lv2}/lv2/buf-size/buf-size.ttl (100%) rename {lv2 => plugins/lv2}/lv2/buf-size/lv2-buf-size.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/buf-size/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/core/attributes.h (100%) rename {lv2 => plugins/lv2}/lv2/core/lv2.h (100%) rename {lv2 => plugins/lv2}/lv2/core/lv2_util.h (100%) rename {lv2 => plugins/lv2}/lv2/core/lv2core.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/core/lv2core.ttl (100%) rename {lv2 => plugins/lv2}/lv2/core/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/core/meta.ttl (100%) rename {lv2 => plugins/lv2}/lv2/data-access/data-access.h (100%) rename {lv2 => plugins/lv2}/lv2/data-access/data-access.ttl (100%) rename {lv2 => plugins/lv2}/lv2/data-access/lv2-data-access.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/data-access/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/dynmanifest/dynmanifest.h (100%) rename {lv2 => plugins/lv2}/lv2/dynmanifest/dynmanifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/dynmanifest/lv2-dynmanifest.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/dynmanifest/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/event/event-helpers.h (100%) rename {lv2 => plugins/lv2}/lv2/event/event.h (100%) rename {lv2 => plugins/lv2}/lv2/event/event.ttl (100%) rename {lv2 => plugins/lv2}/lv2/event/lv2-event.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/event/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/instance-access/instance-access.h (100%) rename {lv2 => plugins/lv2}/lv2/instance-access/instance-access.ttl (100%) rename {lv2 => plugins/lv2}/lv2/instance-access/lv2-instance-access.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/instance-access/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/log/log.h (100%) rename {lv2 => plugins/lv2}/lv2/log/log.ttl (100%) rename {lv2 => plugins/lv2}/lv2/log/logger.h (100%) rename {lv2 => plugins/lv2}/lv2/log/lv2-log.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/log/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/midi/lv2-midi.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/midi/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/midi/midi.h (100%) rename {lv2 => plugins/lv2}/lv2/midi/midi.ttl (100%) rename {lv2 => plugins/lv2}/lv2/morph/lv2-morph.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/morph/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/morph/morph.h (100%) rename {lv2 => plugins/lv2}/lv2/morph/morph.ttl (100%) rename {lv2 => plugins/lv2}/lv2/options/lv2-options.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/options/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/options/options.h (100%) rename {lv2 => plugins/lv2}/lv2/options/options.ttl (100%) rename {lv2 => plugins/lv2}/lv2/parameters/lv2-parameters.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/parameters/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/parameters/parameters.h (100%) rename {lv2 => plugins/lv2}/lv2/parameters/parameters.ttl (100%) rename {lv2 => plugins/lv2}/lv2/patch/lv2-patch.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/patch/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/patch/patch.h (100%) rename {lv2 => plugins/lv2}/lv2/patch/patch.ttl (100%) rename {lv2 => plugins/lv2}/lv2/port-groups/lv2-port-groups.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/port-groups/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/port-groups/port-groups.h (100%) rename {lv2 => plugins/lv2}/lv2/port-groups/port-groups.ttl (100%) rename {lv2 => plugins/lv2}/lv2/port-props/lv2-port-props.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/port-props/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/port-props/port-props.h (100%) rename {lv2 => plugins/lv2}/lv2/port-props/port-props.ttl (100%) rename {lv2 => plugins/lv2}/lv2/presets/lv2-presets.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/presets/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/presets/presets.h (100%) rename {lv2 => plugins/lv2}/lv2/presets/presets.ttl (100%) rename {lv2 => plugins/lv2}/lv2/resize-port/lv2-resize-port.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/resize-port/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/resize-port/resize-port.h (100%) rename {lv2 => plugins/lv2}/lv2/resize-port/resize-port.ttl (100%) rename {lv2 => plugins/lv2}/lv2/state/lv2-state.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/state/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/state/state.h (100%) rename {lv2 => plugins/lv2}/lv2/state/state.ttl (100%) rename {lv2 => plugins/lv2}/lv2/time/lv2-time.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/time/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/time/time.h (100%) rename {lv2 => plugins/lv2}/lv2/time/time.ttl (100%) rename {lv2 => plugins/lv2}/lv2/ui/lv2-ui.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/ui/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/ui/ui.h (100%) rename {lv2 => plugins/lv2}/lv2/ui/ui.ttl (100%) rename {lv2 => plugins/lv2}/lv2/units/lv2-units.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/units/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/units/units.h (100%) rename {lv2 => plugins/lv2}/lv2/units/units.ttl (100%) rename {lv2 => plugins/lv2}/lv2/uri-map/lv2-uri-map.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/uri-map/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/uri-map/uri-map.h (100%) rename {lv2 => plugins/lv2}/lv2/uri-map/uri-map.ttl (100%) rename {lv2 => plugins/lv2}/lv2/urid/lv2-urid.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/urid/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/urid/urid.h (100%) rename {lv2 => plugins/lv2}/lv2/urid/urid.ttl (100%) rename {lv2 => plugins/lv2}/lv2/worker/lv2-worker.doap.ttl (100%) rename {lv2 => plugins/lv2}/lv2/worker/manifest.ttl (100%) rename {lv2 => plugins/lv2}/lv2/worker/worker.h (100%) rename {lv2 => plugins/lv2}/lv2/worker/worker.ttl (100%) rename {lv2 => plugins/lv2}/lv2ui.version (100%) rename {lv2 => plugins/lv2}/manifest.ttl.in (100%) rename {lv2 => plugins/lv2}/resources/DefaultInstrument.sfz (100%) rename {lv2 => plugins/lv2}/resources/DefaultScale.scl (100%) rename {lv2 => plugins/lv2}/sfizz.c (100%) rename {lv2 => plugins/lv2}/sfizz.ttl.in (100%) rename {lv2 => plugins/lv2}/sfizz_lv2.h (100%) rename {lv2 => plugins/lv2}/sfizz_ui.cpp (100%) rename {lv2 => plugins/lv2}/sfizz_ui.ttl.in (100%) rename {lv2 => plugins/lv2}/vstgui_helpers.cpp (100%) rename {lv2 => plugins/lv2}/vstgui_helpers.h (100%) rename {vst => plugins/vst}/CMakeLists.txt (100%) rename {vst => plugins/vst}/FileTrie.cpp (100%) rename {vst => plugins/vst}/FileTrie.h (100%) rename {vst => plugins/vst}/IdleUpdateHandler.h (100%) rename {vst => plugins/vst}/NativeHelpers.cpp (100%) rename {vst => plugins/vst}/NativeHelpers.h (100%) rename {vst => plugins/vst}/NativeHelpers.mm (100%) rename {vst => plugins/vst}/SfizzFileScan.cpp (100%) rename {vst => plugins/vst}/SfizzFileScan.h (100%) rename {vst => plugins/vst}/SfizzForeignPaths.cpp (100%) rename {vst => plugins/vst}/SfizzForeignPaths.h (100%) rename {vst => plugins/vst}/SfizzForeignPaths.mm (100%) rename {vst => plugins/vst}/SfizzSettings.cpp (100%) rename {vst => plugins/vst}/SfizzSettings.h (100%) rename {vst => plugins/vst}/SfizzSettings.mm (100%) rename {vst => plugins/vst}/SfizzVstController.cpp (100%) rename {vst => plugins/vst}/SfizzVstController.h (100%) rename {vst => plugins/vst}/SfizzVstEditor.cpp (100%) rename {vst => plugins/vst}/SfizzVstEditor.h (100%) rename {vst => plugins/vst}/SfizzVstParameters.h (100%) rename {vst => plugins/vst}/SfizzVstProcessor.cpp (100%) rename {vst => plugins/vst}/SfizzVstProcessor.h (100%) rename {vst => plugins/vst}/SfizzVstState.cpp (100%) rename {vst => plugins/vst}/SfizzVstState.h (100%) rename {vst => plugins/vst}/SfizzVstUpdates.cpp (100%) rename {vst => plugins/vst}/SfizzVstUpdates.h (100%) rename {vst => plugins/vst}/VstPluginDefs.h.in (100%) rename {vst => plugins/vst}/VstPluginFactory.cpp (100%) rename {vst => plugins/vst}/X11RunLoop.cpp (100%) rename {vst => plugins/vst}/X11RunLoop.h (100%) rename {vst => plugins/vst}/cmake/Vst3.cmake (100%) rename {vst => plugins/vst}/external/VST_SDK/VST3_SDK/base (100%) rename {vst => plugins/vst}/external/VST_SDK/VST3_SDK/pluginterfaces (100%) rename {vst => plugins/vst}/external/VST_SDK/VST3_SDK/public.sdk (100%) rename {vst => plugins/vst}/external/ring_buffer/LICENSE (100%) rename {vst => plugins/vst}/external/ring_buffer/ring_buffer/ring_buffer.cpp (100%) rename {vst => plugins/vst}/external/ring_buffer/ring_buffer/ring_buffer.h (100%) rename {vst => plugins/vst}/external/ring_buffer/ring_buffer/ring_buffer.tcc (100%) rename {vst => plugins/vst}/external/sfzt_auwrapper (100%) rename {vst => plugins/vst}/gpl-3.0.txt (100%) rename {vst => plugins/vst}/mac/Info.au.plist (100%) rename {vst => plugins/vst}/mac/Info.vst3.plist (100%) rename {vst => plugins/vst}/mac/PkgInfo (100%) rename {vst => plugins/vst}/mac/audiounitconfig.h.in (100%) rename {vst => plugins/vst}/vst3.def (100%) rename {vst => plugins/vst}/vst3.version (100%) rename {vst => plugins/vst}/win/Plugin.ico (100%) rename {vst => plugins/vst}/win/desktop.ini (100%) diff --git a/.gitmodules b/.gitmodules index 8be5575f..9cbfac18 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,19 +4,19 @@ branch = lts_2020_02_25 shallow = true [submodule "vst/external/VST_SDK/VST3_SDK/base"] - path = vst/external/VST_SDK/VST3_SDK/base + path = plugins/vst/external/VST_SDK/VST3_SDK/base url = https://github.com/steinbergmedia/vst3_base.git shallow = true [submodule "vst/external/VST_SDK/VST3_SDK/pluginterfaces"] - path = vst/external/VST_SDK/VST3_SDK/pluginterfaces + path = plugins/vst/external/VST_SDK/VST3_SDK/pluginterfaces url = https://github.com/steinbergmedia/vst3_pluginterfaces.git shallow = true [submodule "vst/external/VST_SDK/VST3_SDK/public.sdk"] - path = vst/external/VST_SDK/VST3_SDK/public.sdk + path = plugins/vst/external/VST_SDK/VST3_SDK/public.sdk url = https://github.com/steinbergmedia/vst3_public_sdk.git shallow = true [submodule "vst/external/VST_SDK/VST3_SDK/vstgui4"] - path = editor/external/vstgui4 + path = plugins/editor/external/vstgui4 url = https://github.com/sfztools/vstgui.git shallow = true [submodule "external/st_audiofile/thirdparty/dr_libs"] @@ -32,7 +32,7 @@ url = https://github.com/sfztools/libaiff.git shallow = true [submodule "vst/external/sfzt_auwrapper"] - path = vst/external/sfzt_auwrapper + path = plugins/vst/external/sfzt_auwrapper url = https://github.com/sfztools/sfzt_auwrapper.git shallow = true [submodule "external/filesystem"] diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e2149df..44d5ec51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,15 +56,15 @@ add_subdirectory (src) add_subdirectory (clients) if ((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST) - add_subdirectory (editor) + add_subdirectory (plugins/editor) endif() if (SFIZZ_LV2) - add_subdirectory (lv2) + add_subdirectory (plugins/lv2) endif() if (SFIZZ_VST) - add_subdirectory (vst) + add_subdirectory (plugins/vst) else() if (SFIZZ_AU) message(WARNING "Audio Unit requires VST to be enabled") diff --git a/editor/CMakeLists.txt b/plugins/editor/CMakeLists.txt similarity index 100% rename from editor/CMakeLists.txt rename to plugins/editor/CMakeLists.txt diff --git a/editor/cmake/Vstgui.cmake b/plugins/editor/cmake/Vstgui.cmake similarity index 100% rename from editor/cmake/Vstgui.cmake rename to plugins/editor/cmake/Vstgui.cmake diff --git a/editor/external/vstgui4 b/plugins/editor/external/vstgui4 similarity index 100% rename from editor/external/vstgui4 rename to plugins/editor/external/vstgui4 diff --git a/editor/layout/main.fl b/plugins/editor/layout/main.fl similarity index 100% rename from editor/layout/main.fl rename to plugins/editor/layout/main.fl diff --git a/editor/resources/Fonts/Roboto-Regular.ttf b/plugins/editor/resources/Fonts/Roboto-Regular.ttf similarity index 100% rename from editor/resources/Fonts/Roboto-Regular.ttf rename to plugins/editor/resources/Fonts/Roboto-Regular.ttf diff --git a/editor/resources/Fonts/sfizz-fluentui-system-r20.ttf b/plugins/editor/resources/Fonts/sfizz-fluentui-system-r20.ttf similarity index 100% rename from editor/resources/Fonts/sfizz-fluentui-system-r20.ttf rename to plugins/editor/resources/Fonts/sfizz-fluentui-system-r20.ttf diff --git a/editor/resources/background.png b/plugins/editor/resources/background.png similarity index 100% rename from editor/resources/background.png rename to plugins/editor/resources/background.png diff --git a/editor/resources/background@2x.png b/plugins/editor/resources/background@2x.png similarity index 100% rename from editor/resources/background@2x.png rename to plugins/editor/resources/background@2x.png diff --git a/editor/resources/icon_white.png b/plugins/editor/resources/icon_white.png similarity index 100% rename from editor/resources/icon_white.png rename to plugins/editor/resources/icon_white.png diff --git a/editor/resources/icon_white.svg b/plugins/editor/resources/icon_white.svg similarity index 100% rename from editor/resources/icon_white.svg rename to plugins/editor/resources/icon_white.svg diff --git a/editor/resources/icon_white@2x.png b/plugins/editor/resources/icon_white@2x.png similarity index 100% rename from editor/resources/icon_white@2x.png rename to plugins/editor/resources/icon_white@2x.png diff --git a/editor/resources/knob.knob b/plugins/editor/resources/knob.knob similarity index 100% rename from editor/resources/knob.knob rename to plugins/editor/resources/knob.knob diff --git a/editor/resources/knob48.png b/plugins/editor/resources/knob48.png similarity index 100% rename from editor/resources/knob48.png rename to plugins/editor/resources/knob48.png diff --git a/editor/resources/knob48@2x.png b/plugins/editor/resources/knob48@2x.png similarity index 100% rename from editor/resources/knob48@2x.png rename to plugins/editor/resources/knob48@2x.png diff --git a/editor/resources/logo.png b/plugins/editor/resources/logo.png similarity index 100% rename from editor/resources/logo.png rename to plugins/editor/resources/logo.png diff --git a/editor/resources/logo.svg b/plugins/editor/resources/logo.svg similarity index 100% rename from editor/resources/logo.svg rename to plugins/editor/resources/logo.svg diff --git a/editor/resources/logo_text.png b/plugins/editor/resources/logo_text.png similarity index 100% rename from editor/resources/logo_text.png rename to plugins/editor/resources/logo_text.png diff --git a/editor/resources/logo_text.svg b/plugins/editor/resources/logo_text.svg similarity index 100% rename from editor/resources/logo_text.svg rename to plugins/editor/resources/logo_text.svg diff --git a/editor/resources/logo_text@2x.png b/plugins/editor/resources/logo_text@2x.png similarity index 100% rename from editor/resources/logo_text@2x.png rename to plugins/editor/resources/logo_text@2x.png diff --git a/editor/resources/logo_text_white.png b/plugins/editor/resources/logo_text_white.png similarity index 100% rename from editor/resources/logo_text_white.png rename to plugins/editor/resources/logo_text_white.png diff --git a/editor/resources/logo_text_white@2x.png b/plugins/editor/resources/logo_text_white@2x.png similarity index 100% rename from editor/resources/logo_text_white@2x.png rename to plugins/editor/resources/logo_text_white@2x.png diff --git a/editor/src/editor/EditIds.cpp b/plugins/editor/src/editor/EditIds.cpp similarity index 100% rename from editor/src/editor/EditIds.cpp rename to plugins/editor/src/editor/EditIds.cpp diff --git a/editor/src/editor/EditIds.h b/plugins/editor/src/editor/EditIds.h similarity index 100% rename from editor/src/editor/EditIds.h rename to plugins/editor/src/editor/EditIds.h diff --git a/editor/src/editor/EditValue.h b/plugins/editor/src/editor/EditValue.h similarity index 100% rename from editor/src/editor/EditValue.h rename to plugins/editor/src/editor/EditValue.h diff --git a/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp similarity index 100% rename from editor/src/editor/Editor.cpp rename to plugins/editor/src/editor/Editor.cpp diff --git a/editor/src/editor/Editor.h b/plugins/editor/src/editor/Editor.h similarity index 100% rename from editor/src/editor/Editor.h rename to plugins/editor/src/editor/Editor.h diff --git a/editor/src/editor/EditorController.h b/plugins/editor/src/editor/EditorController.h similarity index 100% rename from editor/src/editor/EditorController.h rename to plugins/editor/src/editor/EditorController.h diff --git a/editor/src/editor/GUIComponents.cpp b/plugins/editor/src/editor/GUIComponents.cpp similarity index 100% rename from editor/src/editor/GUIComponents.cpp rename to plugins/editor/src/editor/GUIComponents.cpp diff --git a/editor/src/editor/GUIComponents.h b/plugins/editor/src/editor/GUIComponents.h similarity index 100% rename from editor/src/editor/GUIComponents.h rename to plugins/editor/src/editor/GUIComponents.h diff --git a/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp similarity index 100% rename from editor/src/editor/GUIPiano.cpp rename to plugins/editor/src/editor/GUIPiano.cpp diff --git a/editor/src/editor/GUIPiano.h b/plugins/editor/src/editor/GUIPiano.h similarity index 100% rename from editor/src/editor/GUIPiano.h rename to plugins/editor/src/editor/GUIPiano.h diff --git a/editor/src/editor/NativeHelpers.cpp b/plugins/editor/src/editor/NativeHelpers.cpp similarity index 100% rename from editor/src/editor/NativeHelpers.cpp rename to plugins/editor/src/editor/NativeHelpers.cpp diff --git a/editor/src/editor/NativeHelpers.h b/plugins/editor/src/editor/NativeHelpers.h similarity index 100% rename from editor/src/editor/NativeHelpers.h rename to plugins/editor/src/editor/NativeHelpers.h diff --git a/editor/src/editor/NativeHelpers.mm b/plugins/editor/src/editor/NativeHelpers.mm similarity index 100% rename from editor/src/editor/NativeHelpers.mm rename to plugins/editor/src/editor/NativeHelpers.mm diff --git a/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp similarity index 100% rename from editor/src/editor/layout/main.hpp rename to plugins/editor/src/editor/layout/main.hpp diff --git a/editor/src/editor/utility/vstgui_after.h b/plugins/editor/src/editor/utility/vstgui_after.h similarity index 100% rename from editor/src/editor/utility/vstgui_after.h rename to plugins/editor/src/editor/utility/vstgui_after.h diff --git a/editor/src/editor/utility/vstgui_before.h b/plugins/editor/src/editor/utility/vstgui_before.h similarity index 100% rename from editor/src/editor/utility/vstgui_before.h rename to plugins/editor/src/editor/utility/vstgui_before.h diff --git a/editor/tools/layout-maker/LICENSE b/plugins/editor/tools/layout-maker/LICENSE similarity index 100% rename from editor/tools/layout-maker/LICENSE rename to plugins/editor/tools/layout-maker/LICENSE diff --git a/editor/tools/layout-maker/README b/plugins/editor/tools/layout-maker/README similarity index 100% rename from editor/tools/layout-maker/README rename to plugins/editor/tools/layout-maker/README diff --git a/editor/tools/layout-maker/sources/layout.h b/plugins/editor/tools/layout-maker/sources/layout.h similarity index 100% rename from editor/tools/layout-maker/sources/layout.h rename to plugins/editor/tools/layout-maker/sources/layout.h diff --git a/editor/tools/layout-maker/sources/main.cpp b/plugins/editor/tools/layout-maker/sources/main.cpp similarity index 100% rename from editor/tools/layout-maker/sources/main.cpp rename to plugins/editor/tools/layout-maker/sources/main.cpp diff --git a/editor/tools/layout-maker/sources/reader.cpp b/plugins/editor/tools/layout-maker/sources/reader.cpp similarity index 100% rename from editor/tools/layout-maker/sources/reader.cpp rename to plugins/editor/tools/layout-maker/sources/reader.cpp diff --git a/editor/tools/layout-maker/sources/reader.h b/plugins/editor/tools/layout-maker/sources/reader.h similarity index 100% rename from editor/tools/layout-maker/sources/reader.h rename to plugins/editor/tools/layout-maker/sources/reader.h diff --git a/lv2/CMakeLists.txt b/plugins/lv2/CMakeLists.txt similarity index 100% rename from lv2/CMakeLists.txt rename to plugins/lv2/CMakeLists.txt diff --git a/lv2/LICENSE.md.in b/plugins/lv2/LICENSE.md.in similarity index 100% rename from lv2/LICENSE.md.in rename to plugins/lv2/LICENSE.md.in diff --git a/lv2/atomic_compat.h b/plugins/lv2/atomic_compat.h similarity index 100% rename from lv2/atomic_compat.h rename to plugins/lv2/atomic_compat.h diff --git a/lv2/external/ardour/ardour/lv2_extensions.h b/plugins/lv2/external/ardour/ardour/lv2_extensions.h similarity index 100% rename from lv2/external/ardour/ardour/lv2_extensions.h rename to plugins/lv2/external/ardour/ardour/lv2_extensions.h diff --git a/lv2/lgpl-3.0.txt b/plugins/lv2/lgpl-3.0.txt similarity index 100% rename from lv2/lgpl-3.0.txt rename to plugins/lv2/lgpl-3.0.txt diff --git a/lv2/lv2.version b/plugins/lv2/lv2.version similarity index 100% rename from lv2/lv2.version rename to plugins/lv2/lv2.version diff --git a/lv2/lv2/atom/atom-test-utils.c b/plugins/lv2/lv2/atom/atom-test-utils.c similarity index 100% rename from lv2/lv2/atom/atom-test-utils.c rename to plugins/lv2/lv2/atom/atom-test-utils.c diff --git a/lv2/lv2/atom/atom-test.c b/plugins/lv2/lv2/atom/atom-test.c similarity index 100% rename from lv2/lv2/atom/atom-test.c rename to plugins/lv2/lv2/atom/atom-test.c diff --git a/lv2/lv2/atom/atom.h b/plugins/lv2/lv2/atom/atom.h similarity index 100% rename from lv2/lv2/atom/atom.h rename to plugins/lv2/lv2/atom/atom.h diff --git a/lv2/lv2/atom/atom.ttl b/plugins/lv2/lv2/atom/atom.ttl similarity index 100% rename from lv2/lv2/atom/atom.ttl rename to plugins/lv2/lv2/atom/atom.ttl diff --git a/lv2/lv2/atom/forge-overflow-test.c b/plugins/lv2/lv2/atom/forge-overflow-test.c similarity index 100% rename from lv2/lv2/atom/forge-overflow-test.c rename to plugins/lv2/lv2/atom/forge-overflow-test.c diff --git a/lv2/lv2/atom/forge.h b/plugins/lv2/lv2/atom/forge.h similarity index 100% rename from lv2/lv2/atom/forge.h rename to plugins/lv2/lv2/atom/forge.h diff --git a/lv2/lv2/atom/lv2-atom.doap.ttl b/plugins/lv2/lv2/atom/lv2-atom.doap.ttl similarity index 100% rename from lv2/lv2/atom/lv2-atom.doap.ttl rename to plugins/lv2/lv2/atom/lv2-atom.doap.ttl diff --git a/lv2/lv2/atom/manifest.ttl b/plugins/lv2/lv2/atom/manifest.ttl similarity index 100% rename from lv2/lv2/atom/manifest.ttl rename to plugins/lv2/lv2/atom/manifest.ttl diff --git a/lv2/lv2/atom/util.h b/plugins/lv2/lv2/atom/util.h similarity index 100% rename from lv2/lv2/atom/util.h rename to plugins/lv2/lv2/atom/util.h diff --git a/lv2/lv2/buf-size/buf-size.h b/plugins/lv2/lv2/buf-size/buf-size.h similarity index 100% rename from lv2/lv2/buf-size/buf-size.h rename to plugins/lv2/lv2/buf-size/buf-size.h diff --git a/lv2/lv2/buf-size/buf-size.ttl b/plugins/lv2/lv2/buf-size/buf-size.ttl similarity index 100% rename from lv2/lv2/buf-size/buf-size.ttl rename to plugins/lv2/lv2/buf-size/buf-size.ttl diff --git a/lv2/lv2/buf-size/lv2-buf-size.doap.ttl b/plugins/lv2/lv2/buf-size/lv2-buf-size.doap.ttl similarity index 100% rename from lv2/lv2/buf-size/lv2-buf-size.doap.ttl rename to plugins/lv2/lv2/buf-size/lv2-buf-size.doap.ttl diff --git a/lv2/lv2/buf-size/manifest.ttl b/plugins/lv2/lv2/buf-size/manifest.ttl similarity index 100% rename from lv2/lv2/buf-size/manifest.ttl rename to plugins/lv2/lv2/buf-size/manifest.ttl diff --git a/lv2/lv2/core/attributes.h b/plugins/lv2/lv2/core/attributes.h similarity index 100% rename from lv2/lv2/core/attributes.h rename to plugins/lv2/lv2/core/attributes.h diff --git a/lv2/lv2/core/lv2.h b/plugins/lv2/lv2/core/lv2.h similarity index 100% rename from lv2/lv2/core/lv2.h rename to plugins/lv2/lv2/core/lv2.h diff --git a/lv2/lv2/core/lv2_util.h b/plugins/lv2/lv2/core/lv2_util.h similarity index 100% rename from lv2/lv2/core/lv2_util.h rename to plugins/lv2/lv2/core/lv2_util.h diff --git a/lv2/lv2/core/lv2core.doap.ttl b/plugins/lv2/lv2/core/lv2core.doap.ttl similarity index 100% rename from lv2/lv2/core/lv2core.doap.ttl rename to plugins/lv2/lv2/core/lv2core.doap.ttl diff --git a/lv2/lv2/core/lv2core.ttl b/plugins/lv2/lv2/core/lv2core.ttl similarity index 100% rename from lv2/lv2/core/lv2core.ttl rename to plugins/lv2/lv2/core/lv2core.ttl diff --git a/lv2/lv2/core/manifest.ttl b/plugins/lv2/lv2/core/manifest.ttl similarity index 100% rename from lv2/lv2/core/manifest.ttl rename to plugins/lv2/lv2/core/manifest.ttl diff --git a/lv2/lv2/core/meta.ttl b/plugins/lv2/lv2/core/meta.ttl similarity index 100% rename from lv2/lv2/core/meta.ttl rename to plugins/lv2/lv2/core/meta.ttl diff --git a/lv2/lv2/data-access/data-access.h b/plugins/lv2/lv2/data-access/data-access.h similarity index 100% rename from lv2/lv2/data-access/data-access.h rename to plugins/lv2/lv2/data-access/data-access.h diff --git a/lv2/lv2/data-access/data-access.ttl b/plugins/lv2/lv2/data-access/data-access.ttl similarity index 100% rename from lv2/lv2/data-access/data-access.ttl rename to plugins/lv2/lv2/data-access/data-access.ttl diff --git a/lv2/lv2/data-access/lv2-data-access.doap.ttl b/plugins/lv2/lv2/data-access/lv2-data-access.doap.ttl similarity index 100% rename from lv2/lv2/data-access/lv2-data-access.doap.ttl rename to plugins/lv2/lv2/data-access/lv2-data-access.doap.ttl diff --git a/lv2/lv2/data-access/manifest.ttl b/plugins/lv2/lv2/data-access/manifest.ttl similarity index 100% rename from lv2/lv2/data-access/manifest.ttl rename to plugins/lv2/lv2/data-access/manifest.ttl diff --git a/lv2/lv2/dynmanifest/dynmanifest.h b/plugins/lv2/lv2/dynmanifest/dynmanifest.h similarity index 100% rename from lv2/lv2/dynmanifest/dynmanifest.h rename to plugins/lv2/lv2/dynmanifest/dynmanifest.h diff --git a/lv2/lv2/dynmanifest/dynmanifest.ttl b/plugins/lv2/lv2/dynmanifest/dynmanifest.ttl similarity index 100% rename from lv2/lv2/dynmanifest/dynmanifest.ttl rename to plugins/lv2/lv2/dynmanifest/dynmanifest.ttl diff --git a/lv2/lv2/dynmanifest/lv2-dynmanifest.doap.ttl b/plugins/lv2/lv2/dynmanifest/lv2-dynmanifest.doap.ttl similarity index 100% rename from lv2/lv2/dynmanifest/lv2-dynmanifest.doap.ttl rename to plugins/lv2/lv2/dynmanifest/lv2-dynmanifest.doap.ttl diff --git a/lv2/lv2/dynmanifest/manifest.ttl b/plugins/lv2/lv2/dynmanifest/manifest.ttl similarity index 100% rename from lv2/lv2/dynmanifest/manifest.ttl rename to plugins/lv2/lv2/dynmanifest/manifest.ttl diff --git a/lv2/lv2/event/event-helpers.h b/plugins/lv2/lv2/event/event-helpers.h similarity index 100% rename from lv2/lv2/event/event-helpers.h rename to plugins/lv2/lv2/event/event-helpers.h diff --git a/lv2/lv2/event/event.h b/plugins/lv2/lv2/event/event.h similarity index 100% rename from lv2/lv2/event/event.h rename to plugins/lv2/lv2/event/event.h diff --git a/lv2/lv2/event/event.ttl b/plugins/lv2/lv2/event/event.ttl similarity index 100% rename from lv2/lv2/event/event.ttl rename to plugins/lv2/lv2/event/event.ttl diff --git a/lv2/lv2/event/lv2-event.doap.ttl b/plugins/lv2/lv2/event/lv2-event.doap.ttl similarity index 100% rename from lv2/lv2/event/lv2-event.doap.ttl rename to plugins/lv2/lv2/event/lv2-event.doap.ttl diff --git a/lv2/lv2/event/manifest.ttl b/plugins/lv2/lv2/event/manifest.ttl similarity index 100% rename from lv2/lv2/event/manifest.ttl rename to plugins/lv2/lv2/event/manifest.ttl diff --git a/lv2/lv2/instance-access/instance-access.h b/plugins/lv2/lv2/instance-access/instance-access.h similarity index 100% rename from lv2/lv2/instance-access/instance-access.h rename to plugins/lv2/lv2/instance-access/instance-access.h diff --git a/lv2/lv2/instance-access/instance-access.ttl b/plugins/lv2/lv2/instance-access/instance-access.ttl similarity index 100% rename from lv2/lv2/instance-access/instance-access.ttl rename to plugins/lv2/lv2/instance-access/instance-access.ttl diff --git a/lv2/lv2/instance-access/lv2-instance-access.doap.ttl b/plugins/lv2/lv2/instance-access/lv2-instance-access.doap.ttl similarity index 100% rename from lv2/lv2/instance-access/lv2-instance-access.doap.ttl rename to plugins/lv2/lv2/instance-access/lv2-instance-access.doap.ttl diff --git a/lv2/lv2/instance-access/manifest.ttl b/plugins/lv2/lv2/instance-access/manifest.ttl similarity index 100% rename from lv2/lv2/instance-access/manifest.ttl rename to plugins/lv2/lv2/instance-access/manifest.ttl diff --git a/lv2/lv2/log/log.h b/plugins/lv2/lv2/log/log.h similarity index 100% rename from lv2/lv2/log/log.h rename to plugins/lv2/lv2/log/log.h diff --git a/lv2/lv2/log/log.ttl b/plugins/lv2/lv2/log/log.ttl similarity index 100% rename from lv2/lv2/log/log.ttl rename to plugins/lv2/lv2/log/log.ttl diff --git a/lv2/lv2/log/logger.h b/plugins/lv2/lv2/log/logger.h similarity index 100% rename from lv2/lv2/log/logger.h rename to plugins/lv2/lv2/log/logger.h diff --git a/lv2/lv2/log/lv2-log.doap.ttl b/plugins/lv2/lv2/log/lv2-log.doap.ttl similarity index 100% rename from lv2/lv2/log/lv2-log.doap.ttl rename to plugins/lv2/lv2/log/lv2-log.doap.ttl diff --git a/lv2/lv2/log/manifest.ttl b/plugins/lv2/lv2/log/manifest.ttl similarity index 100% rename from lv2/lv2/log/manifest.ttl rename to plugins/lv2/lv2/log/manifest.ttl diff --git a/lv2/lv2/midi/lv2-midi.doap.ttl b/plugins/lv2/lv2/midi/lv2-midi.doap.ttl similarity index 100% rename from lv2/lv2/midi/lv2-midi.doap.ttl rename to plugins/lv2/lv2/midi/lv2-midi.doap.ttl diff --git a/lv2/lv2/midi/manifest.ttl b/plugins/lv2/lv2/midi/manifest.ttl similarity index 100% rename from lv2/lv2/midi/manifest.ttl rename to plugins/lv2/lv2/midi/manifest.ttl diff --git a/lv2/lv2/midi/midi.h b/plugins/lv2/lv2/midi/midi.h similarity index 100% rename from lv2/lv2/midi/midi.h rename to plugins/lv2/lv2/midi/midi.h diff --git a/lv2/lv2/midi/midi.ttl b/plugins/lv2/lv2/midi/midi.ttl similarity index 100% rename from lv2/lv2/midi/midi.ttl rename to plugins/lv2/lv2/midi/midi.ttl diff --git a/lv2/lv2/morph/lv2-morph.doap.ttl b/plugins/lv2/lv2/morph/lv2-morph.doap.ttl similarity index 100% rename from lv2/lv2/morph/lv2-morph.doap.ttl rename to plugins/lv2/lv2/morph/lv2-morph.doap.ttl diff --git a/lv2/lv2/morph/manifest.ttl b/plugins/lv2/lv2/morph/manifest.ttl similarity index 100% rename from lv2/lv2/morph/manifest.ttl rename to plugins/lv2/lv2/morph/manifest.ttl diff --git a/lv2/lv2/morph/morph.h b/plugins/lv2/lv2/morph/morph.h similarity index 100% rename from lv2/lv2/morph/morph.h rename to plugins/lv2/lv2/morph/morph.h diff --git a/lv2/lv2/morph/morph.ttl b/plugins/lv2/lv2/morph/morph.ttl similarity index 100% rename from lv2/lv2/morph/morph.ttl rename to plugins/lv2/lv2/morph/morph.ttl diff --git a/lv2/lv2/options/lv2-options.doap.ttl b/plugins/lv2/lv2/options/lv2-options.doap.ttl similarity index 100% rename from lv2/lv2/options/lv2-options.doap.ttl rename to plugins/lv2/lv2/options/lv2-options.doap.ttl diff --git a/lv2/lv2/options/manifest.ttl b/plugins/lv2/lv2/options/manifest.ttl similarity index 100% rename from lv2/lv2/options/manifest.ttl rename to plugins/lv2/lv2/options/manifest.ttl diff --git a/lv2/lv2/options/options.h b/plugins/lv2/lv2/options/options.h similarity index 100% rename from lv2/lv2/options/options.h rename to plugins/lv2/lv2/options/options.h diff --git a/lv2/lv2/options/options.ttl b/plugins/lv2/lv2/options/options.ttl similarity index 100% rename from lv2/lv2/options/options.ttl rename to plugins/lv2/lv2/options/options.ttl diff --git a/lv2/lv2/parameters/lv2-parameters.doap.ttl b/plugins/lv2/lv2/parameters/lv2-parameters.doap.ttl similarity index 100% rename from lv2/lv2/parameters/lv2-parameters.doap.ttl rename to plugins/lv2/lv2/parameters/lv2-parameters.doap.ttl diff --git a/lv2/lv2/parameters/manifest.ttl b/plugins/lv2/lv2/parameters/manifest.ttl similarity index 100% rename from lv2/lv2/parameters/manifest.ttl rename to plugins/lv2/lv2/parameters/manifest.ttl diff --git a/lv2/lv2/parameters/parameters.h b/plugins/lv2/lv2/parameters/parameters.h similarity index 100% rename from lv2/lv2/parameters/parameters.h rename to plugins/lv2/lv2/parameters/parameters.h diff --git a/lv2/lv2/parameters/parameters.ttl b/plugins/lv2/lv2/parameters/parameters.ttl similarity index 100% rename from lv2/lv2/parameters/parameters.ttl rename to plugins/lv2/lv2/parameters/parameters.ttl diff --git a/lv2/lv2/patch/lv2-patch.doap.ttl b/plugins/lv2/lv2/patch/lv2-patch.doap.ttl similarity index 100% rename from lv2/lv2/patch/lv2-patch.doap.ttl rename to plugins/lv2/lv2/patch/lv2-patch.doap.ttl diff --git a/lv2/lv2/patch/manifest.ttl b/plugins/lv2/lv2/patch/manifest.ttl similarity index 100% rename from lv2/lv2/patch/manifest.ttl rename to plugins/lv2/lv2/patch/manifest.ttl diff --git a/lv2/lv2/patch/patch.h b/plugins/lv2/lv2/patch/patch.h similarity index 100% rename from lv2/lv2/patch/patch.h rename to plugins/lv2/lv2/patch/patch.h diff --git a/lv2/lv2/patch/patch.ttl b/plugins/lv2/lv2/patch/patch.ttl similarity index 100% rename from lv2/lv2/patch/patch.ttl rename to plugins/lv2/lv2/patch/patch.ttl diff --git a/lv2/lv2/port-groups/lv2-port-groups.doap.ttl b/plugins/lv2/lv2/port-groups/lv2-port-groups.doap.ttl similarity index 100% rename from lv2/lv2/port-groups/lv2-port-groups.doap.ttl rename to plugins/lv2/lv2/port-groups/lv2-port-groups.doap.ttl diff --git a/lv2/lv2/port-groups/manifest.ttl b/plugins/lv2/lv2/port-groups/manifest.ttl similarity index 100% rename from lv2/lv2/port-groups/manifest.ttl rename to plugins/lv2/lv2/port-groups/manifest.ttl diff --git a/lv2/lv2/port-groups/port-groups.h b/plugins/lv2/lv2/port-groups/port-groups.h similarity index 100% rename from lv2/lv2/port-groups/port-groups.h rename to plugins/lv2/lv2/port-groups/port-groups.h diff --git a/lv2/lv2/port-groups/port-groups.ttl b/plugins/lv2/lv2/port-groups/port-groups.ttl similarity index 100% rename from lv2/lv2/port-groups/port-groups.ttl rename to plugins/lv2/lv2/port-groups/port-groups.ttl diff --git a/lv2/lv2/port-props/lv2-port-props.doap.ttl b/plugins/lv2/lv2/port-props/lv2-port-props.doap.ttl similarity index 100% rename from lv2/lv2/port-props/lv2-port-props.doap.ttl rename to plugins/lv2/lv2/port-props/lv2-port-props.doap.ttl diff --git a/lv2/lv2/port-props/manifest.ttl b/plugins/lv2/lv2/port-props/manifest.ttl similarity index 100% rename from lv2/lv2/port-props/manifest.ttl rename to plugins/lv2/lv2/port-props/manifest.ttl diff --git a/lv2/lv2/port-props/port-props.h b/plugins/lv2/lv2/port-props/port-props.h similarity index 100% rename from lv2/lv2/port-props/port-props.h rename to plugins/lv2/lv2/port-props/port-props.h diff --git a/lv2/lv2/port-props/port-props.ttl b/plugins/lv2/lv2/port-props/port-props.ttl similarity index 100% rename from lv2/lv2/port-props/port-props.ttl rename to plugins/lv2/lv2/port-props/port-props.ttl diff --git a/lv2/lv2/presets/lv2-presets.doap.ttl b/plugins/lv2/lv2/presets/lv2-presets.doap.ttl similarity index 100% rename from lv2/lv2/presets/lv2-presets.doap.ttl rename to plugins/lv2/lv2/presets/lv2-presets.doap.ttl diff --git a/lv2/lv2/presets/manifest.ttl b/plugins/lv2/lv2/presets/manifest.ttl similarity index 100% rename from lv2/lv2/presets/manifest.ttl rename to plugins/lv2/lv2/presets/manifest.ttl diff --git a/lv2/lv2/presets/presets.h b/plugins/lv2/lv2/presets/presets.h similarity index 100% rename from lv2/lv2/presets/presets.h rename to plugins/lv2/lv2/presets/presets.h diff --git a/lv2/lv2/presets/presets.ttl b/plugins/lv2/lv2/presets/presets.ttl similarity index 100% rename from lv2/lv2/presets/presets.ttl rename to plugins/lv2/lv2/presets/presets.ttl diff --git a/lv2/lv2/resize-port/lv2-resize-port.doap.ttl b/plugins/lv2/lv2/resize-port/lv2-resize-port.doap.ttl similarity index 100% rename from lv2/lv2/resize-port/lv2-resize-port.doap.ttl rename to plugins/lv2/lv2/resize-port/lv2-resize-port.doap.ttl diff --git a/lv2/lv2/resize-port/manifest.ttl b/plugins/lv2/lv2/resize-port/manifest.ttl similarity index 100% rename from lv2/lv2/resize-port/manifest.ttl rename to plugins/lv2/lv2/resize-port/manifest.ttl diff --git a/lv2/lv2/resize-port/resize-port.h b/plugins/lv2/lv2/resize-port/resize-port.h similarity index 100% rename from lv2/lv2/resize-port/resize-port.h rename to plugins/lv2/lv2/resize-port/resize-port.h diff --git a/lv2/lv2/resize-port/resize-port.ttl b/plugins/lv2/lv2/resize-port/resize-port.ttl similarity index 100% rename from lv2/lv2/resize-port/resize-port.ttl rename to plugins/lv2/lv2/resize-port/resize-port.ttl diff --git a/lv2/lv2/state/lv2-state.doap.ttl b/plugins/lv2/lv2/state/lv2-state.doap.ttl similarity index 100% rename from lv2/lv2/state/lv2-state.doap.ttl rename to plugins/lv2/lv2/state/lv2-state.doap.ttl diff --git a/lv2/lv2/state/manifest.ttl b/plugins/lv2/lv2/state/manifest.ttl similarity index 100% rename from lv2/lv2/state/manifest.ttl rename to plugins/lv2/lv2/state/manifest.ttl diff --git a/lv2/lv2/state/state.h b/plugins/lv2/lv2/state/state.h similarity index 100% rename from lv2/lv2/state/state.h rename to plugins/lv2/lv2/state/state.h diff --git a/lv2/lv2/state/state.ttl b/plugins/lv2/lv2/state/state.ttl similarity index 100% rename from lv2/lv2/state/state.ttl rename to plugins/lv2/lv2/state/state.ttl diff --git a/lv2/lv2/time/lv2-time.doap.ttl b/plugins/lv2/lv2/time/lv2-time.doap.ttl similarity index 100% rename from lv2/lv2/time/lv2-time.doap.ttl rename to plugins/lv2/lv2/time/lv2-time.doap.ttl diff --git a/lv2/lv2/time/manifest.ttl b/plugins/lv2/lv2/time/manifest.ttl similarity index 100% rename from lv2/lv2/time/manifest.ttl rename to plugins/lv2/lv2/time/manifest.ttl diff --git a/lv2/lv2/time/time.h b/plugins/lv2/lv2/time/time.h similarity index 100% rename from lv2/lv2/time/time.h rename to plugins/lv2/lv2/time/time.h diff --git a/lv2/lv2/time/time.ttl b/plugins/lv2/lv2/time/time.ttl similarity index 100% rename from lv2/lv2/time/time.ttl rename to plugins/lv2/lv2/time/time.ttl diff --git a/lv2/lv2/ui/lv2-ui.doap.ttl b/plugins/lv2/lv2/ui/lv2-ui.doap.ttl similarity index 100% rename from lv2/lv2/ui/lv2-ui.doap.ttl rename to plugins/lv2/lv2/ui/lv2-ui.doap.ttl diff --git a/lv2/lv2/ui/manifest.ttl b/plugins/lv2/lv2/ui/manifest.ttl similarity index 100% rename from lv2/lv2/ui/manifest.ttl rename to plugins/lv2/lv2/ui/manifest.ttl diff --git a/lv2/lv2/ui/ui.h b/plugins/lv2/lv2/ui/ui.h similarity index 100% rename from lv2/lv2/ui/ui.h rename to plugins/lv2/lv2/ui/ui.h diff --git a/lv2/lv2/ui/ui.ttl b/plugins/lv2/lv2/ui/ui.ttl similarity index 100% rename from lv2/lv2/ui/ui.ttl rename to plugins/lv2/lv2/ui/ui.ttl diff --git a/lv2/lv2/units/lv2-units.doap.ttl b/plugins/lv2/lv2/units/lv2-units.doap.ttl similarity index 100% rename from lv2/lv2/units/lv2-units.doap.ttl rename to plugins/lv2/lv2/units/lv2-units.doap.ttl diff --git a/lv2/lv2/units/manifest.ttl b/plugins/lv2/lv2/units/manifest.ttl similarity index 100% rename from lv2/lv2/units/manifest.ttl rename to plugins/lv2/lv2/units/manifest.ttl diff --git a/lv2/lv2/units/units.h b/plugins/lv2/lv2/units/units.h similarity index 100% rename from lv2/lv2/units/units.h rename to plugins/lv2/lv2/units/units.h diff --git a/lv2/lv2/units/units.ttl b/plugins/lv2/lv2/units/units.ttl similarity index 100% rename from lv2/lv2/units/units.ttl rename to plugins/lv2/lv2/units/units.ttl diff --git a/lv2/lv2/uri-map/lv2-uri-map.doap.ttl b/plugins/lv2/lv2/uri-map/lv2-uri-map.doap.ttl similarity index 100% rename from lv2/lv2/uri-map/lv2-uri-map.doap.ttl rename to plugins/lv2/lv2/uri-map/lv2-uri-map.doap.ttl diff --git a/lv2/lv2/uri-map/manifest.ttl b/plugins/lv2/lv2/uri-map/manifest.ttl similarity index 100% rename from lv2/lv2/uri-map/manifest.ttl rename to plugins/lv2/lv2/uri-map/manifest.ttl diff --git a/lv2/lv2/uri-map/uri-map.h b/plugins/lv2/lv2/uri-map/uri-map.h similarity index 100% rename from lv2/lv2/uri-map/uri-map.h rename to plugins/lv2/lv2/uri-map/uri-map.h diff --git a/lv2/lv2/uri-map/uri-map.ttl b/plugins/lv2/lv2/uri-map/uri-map.ttl similarity index 100% rename from lv2/lv2/uri-map/uri-map.ttl rename to plugins/lv2/lv2/uri-map/uri-map.ttl diff --git a/lv2/lv2/urid/lv2-urid.doap.ttl b/plugins/lv2/lv2/urid/lv2-urid.doap.ttl similarity index 100% rename from lv2/lv2/urid/lv2-urid.doap.ttl rename to plugins/lv2/lv2/urid/lv2-urid.doap.ttl diff --git a/lv2/lv2/urid/manifest.ttl b/plugins/lv2/lv2/urid/manifest.ttl similarity index 100% rename from lv2/lv2/urid/manifest.ttl rename to plugins/lv2/lv2/urid/manifest.ttl diff --git a/lv2/lv2/urid/urid.h b/plugins/lv2/lv2/urid/urid.h similarity index 100% rename from lv2/lv2/urid/urid.h rename to plugins/lv2/lv2/urid/urid.h diff --git a/lv2/lv2/urid/urid.ttl b/plugins/lv2/lv2/urid/urid.ttl similarity index 100% rename from lv2/lv2/urid/urid.ttl rename to plugins/lv2/lv2/urid/urid.ttl diff --git a/lv2/lv2/worker/lv2-worker.doap.ttl b/plugins/lv2/lv2/worker/lv2-worker.doap.ttl similarity index 100% rename from lv2/lv2/worker/lv2-worker.doap.ttl rename to plugins/lv2/lv2/worker/lv2-worker.doap.ttl diff --git a/lv2/lv2/worker/manifest.ttl b/plugins/lv2/lv2/worker/manifest.ttl similarity index 100% rename from lv2/lv2/worker/manifest.ttl rename to plugins/lv2/lv2/worker/manifest.ttl diff --git a/lv2/lv2/worker/worker.h b/plugins/lv2/lv2/worker/worker.h similarity index 100% rename from lv2/lv2/worker/worker.h rename to plugins/lv2/lv2/worker/worker.h diff --git a/lv2/lv2/worker/worker.ttl b/plugins/lv2/lv2/worker/worker.ttl similarity index 100% rename from lv2/lv2/worker/worker.ttl rename to plugins/lv2/lv2/worker/worker.ttl diff --git a/lv2/lv2ui.version b/plugins/lv2/lv2ui.version similarity index 100% rename from lv2/lv2ui.version rename to plugins/lv2/lv2ui.version diff --git a/lv2/manifest.ttl.in b/plugins/lv2/manifest.ttl.in similarity index 100% rename from lv2/manifest.ttl.in rename to plugins/lv2/manifest.ttl.in diff --git a/lv2/resources/DefaultInstrument.sfz b/plugins/lv2/resources/DefaultInstrument.sfz similarity index 100% rename from lv2/resources/DefaultInstrument.sfz rename to plugins/lv2/resources/DefaultInstrument.sfz diff --git a/lv2/resources/DefaultScale.scl b/plugins/lv2/resources/DefaultScale.scl similarity index 100% rename from lv2/resources/DefaultScale.scl rename to plugins/lv2/resources/DefaultScale.scl diff --git a/lv2/sfizz.c b/plugins/lv2/sfizz.c similarity index 100% rename from lv2/sfizz.c rename to plugins/lv2/sfizz.c diff --git a/lv2/sfizz.ttl.in b/plugins/lv2/sfizz.ttl.in similarity index 100% rename from lv2/sfizz.ttl.in rename to plugins/lv2/sfizz.ttl.in diff --git a/lv2/sfizz_lv2.h b/plugins/lv2/sfizz_lv2.h similarity index 100% rename from lv2/sfizz_lv2.h rename to plugins/lv2/sfizz_lv2.h diff --git a/lv2/sfizz_ui.cpp b/plugins/lv2/sfizz_ui.cpp similarity index 100% rename from lv2/sfizz_ui.cpp rename to plugins/lv2/sfizz_ui.cpp diff --git a/lv2/sfizz_ui.ttl.in b/plugins/lv2/sfizz_ui.ttl.in similarity index 100% rename from lv2/sfizz_ui.ttl.in rename to plugins/lv2/sfizz_ui.ttl.in diff --git a/lv2/vstgui_helpers.cpp b/plugins/lv2/vstgui_helpers.cpp similarity index 100% rename from lv2/vstgui_helpers.cpp rename to plugins/lv2/vstgui_helpers.cpp diff --git a/lv2/vstgui_helpers.h b/plugins/lv2/vstgui_helpers.h similarity index 100% rename from lv2/vstgui_helpers.h rename to plugins/lv2/vstgui_helpers.h diff --git a/vst/CMakeLists.txt b/plugins/vst/CMakeLists.txt similarity index 100% rename from vst/CMakeLists.txt rename to plugins/vst/CMakeLists.txt diff --git a/vst/FileTrie.cpp b/plugins/vst/FileTrie.cpp similarity index 100% rename from vst/FileTrie.cpp rename to plugins/vst/FileTrie.cpp diff --git a/vst/FileTrie.h b/plugins/vst/FileTrie.h similarity index 100% rename from vst/FileTrie.h rename to plugins/vst/FileTrie.h diff --git a/vst/IdleUpdateHandler.h b/plugins/vst/IdleUpdateHandler.h similarity index 100% rename from vst/IdleUpdateHandler.h rename to plugins/vst/IdleUpdateHandler.h diff --git a/vst/NativeHelpers.cpp b/plugins/vst/NativeHelpers.cpp similarity index 100% rename from vst/NativeHelpers.cpp rename to plugins/vst/NativeHelpers.cpp diff --git a/vst/NativeHelpers.h b/plugins/vst/NativeHelpers.h similarity index 100% rename from vst/NativeHelpers.h rename to plugins/vst/NativeHelpers.h diff --git a/vst/NativeHelpers.mm b/plugins/vst/NativeHelpers.mm similarity index 100% rename from vst/NativeHelpers.mm rename to plugins/vst/NativeHelpers.mm diff --git a/vst/SfizzFileScan.cpp b/plugins/vst/SfizzFileScan.cpp similarity index 100% rename from vst/SfizzFileScan.cpp rename to plugins/vst/SfizzFileScan.cpp diff --git a/vst/SfizzFileScan.h b/plugins/vst/SfizzFileScan.h similarity index 100% rename from vst/SfizzFileScan.h rename to plugins/vst/SfizzFileScan.h diff --git a/vst/SfizzForeignPaths.cpp b/plugins/vst/SfizzForeignPaths.cpp similarity index 100% rename from vst/SfizzForeignPaths.cpp rename to plugins/vst/SfizzForeignPaths.cpp diff --git a/vst/SfizzForeignPaths.h b/plugins/vst/SfizzForeignPaths.h similarity index 100% rename from vst/SfizzForeignPaths.h rename to plugins/vst/SfizzForeignPaths.h diff --git a/vst/SfizzForeignPaths.mm b/plugins/vst/SfizzForeignPaths.mm similarity index 100% rename from vst/SfizzForeignPaths.mm rename to plugins/vst/SfizzForeignPaths.mm diff --git a/vst/SfizzSettings.cpp b/plugins/vst/SfizzSettings.cpp similarity index 100% rename from vst/SfizzSettings.cpp rename to plugins/vst/SfizzSettings.cpp diff --git a/vst/SfizzSettings.h b/plugins/vst/SfizzSettings.h similarity index 100% rename from vst/SfizzSettings.h rename to plugins/vst/SfizzSettings.h diff --git a/vst/SfizzSettings.mm b/plugins/vst/SfizzSettings.mm similarity index 100% rename from vst/SfizzSettings.mm rename to plugins/vst/SfizzSettings.mm diff --git a/vst/SfizzVstController.cpp b/plugins/vst/SfizzVstController.cpp similarity index 100% rename from vst/SfizzVstController.cpp rename to plugins/vst/SfizzVstController.cpp diff --git a/vst/SfizzVstController.h b/plugins/vst/SfizzVstController.h similarity index 100% rename from vst/SfizzVstController.h rename to plugins/vst/SfizzVstController.h diff --git a/vst/SfizzVstEditor.cpp b/plugins/vst/SfizzVstEditor.cpp similarity index 100% rename from vst/SfizzVstEditor.cpp rename to plugins/vst/SfizzVstEditor.cpp diff --git a/vst/SfizzVstEditor.h b/plugins/vst/SfizzVstEditor.h similarity index 100% rename from vst/SfizzVstEditor.h rename to plugins/vst/SfizzVstEditor.h diff --git a/vst/SfizzVstParameters.h b/plugins/vst/SfizzVstParameters.h similarity index 100% rename from vst/SfizzVstParameters.h rename to plugins/vst/SfizzVstParameters.h diff --git a/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp similarity index 100% rename from vst/SfizzVstProcessor.cpp rename to plugins/vst/SfizzVstProcessor.cpp diff --git a/vst/SfizzVstProcessor.h b/plugins/vst/SfizzVstProcessor.h similarity index 100% rename from vst/SfizzVstProcessor.h rename to plugins/vst/SfizzVstProcessor.h diff --git a/vst/SfizzVstState.cpp b/plugins/vst/SfizzVstState.cpp similarity index 100% rename from vst/SfizzVstState.cpp rename to plugins/vst/SfizzVstState.cpp diff --git a/vst/SfizzVstState.h b/plugins/vst/SfizzVstState.h similarity index 100% rename from vst/SfizzVstState.h rename to plugins/vst/SfizzVstState.h diff --git a/vst/SfizzVstUpdates.cpp b/plugins/vst/SfizzVstUpdates.cpp similarity index 100% rename from vst/SfizzVstUpdates.cpp rename to plugins/vst/SfizzVstUpdates.cpp diff --git a/vst/SfizzVstUpdates.h b/plugins/vst/SfizzVstUpdates.h similarity index 100% rename from vst/SfizzVstUpdates.h rename to plugins/vst/SfizzVstUpdates.h diff --git a/vst/VstPluginDefs.h.in b/plugins/vst/VstPluginDefs.h.in similarity index 100% rename from vst/VstPluginDefs.h.in rename to plugins/vst/VstPluginDefs.h.in diff --git a/vst/VstPluginFactory.cpp b/plugins/vst/VstPluginFactory.cpp similarity index 100% rename from vst/VstPluginFactory.cpp rename to plugins/vst/VstPluginFactory.cpp diff --git a/vst/X11RunLoop.cpp b/plugins/vst/X11RunLoop.cpp similarity index 100% rename from vst/X11RunLoop.cpp rename to plugins/vst/X11RunLoop.cpp diff --git a/vst/X11RunLoop.h b/plugins/vst/X11RunLoop.h similarity index 100% rename from vst/X11RunLoop.h rename to plugins/vst/X11RunLoop.h diff --git a/vst/cmake/Vst3.cmake b/plugins/vst/cmake/Vst3.cmake similarity index 100% rename from vst/cmake/Vst3.cmake rename to plugins/vst/cmake/Vst3.cmake diff --git a/vst/external/VST_SDK/VST3_SDK/base b/plugins/vst/external/VST_SDK/VST3_SDK/base similarity index 100% rename from vst/external/VST_SDK/VST3_SDK/base rename to plugins/vst/external/VST_SDK/VST3_SDK/base diff --git a/vst/external/VST_SDK/VST3_SDK/pluginterfaces b/plugins/vst/external/VST_SDK/VST3_SDK/pluginterfaces similarity index 100% rename from vst/external/VST_SDK/VST3_SDK/pluginterfaces rename to plugins/vst/external/VST_SDK/VST3_SDK/pluginterfaces diff --git a/vst/external/VST_SDK/VST3_SDK/public.sdk b/plugins/vst/external/VST_SDK/VST3_SDK/public.sdk similarity index 100% rename from vst/external/VST_SDK/VST3_SDK/public.sdk rename to plugins/vst/external/VST_SDK/VST3_SDK/public.sdk diff --git a/vst/external/ring_buffer/LICENSE b/plugins/vst/external/ring_buffer/LICENSE similarity index 100% rename from vst/external/ring_buffer/LICENSE rename to plugins/vst/external/ring_buffer/LICENSE diff --git a/vst/external/ring_buffer/ring_buffer/ring_buffer.cpp b/plugins/vst/external/ring_buffer/ring_buffer/ring_buffer.cpp similarity index 100% rename from vst/external/ring_buffer/ring_buffer/ring_buffer.cpp rename to plugins/vst/external/ring_buffer/ring_buffer/ring_buffer.cpp diff --git a/vst/external/ring_buffer/ring_buffer/ring_buffer.h b/plugins/vst/external/ring_buffer/ring_buffer/ring_buffer.h similarity index 100% rename from vst/external/ring_buffer/ring_buffer/ring_buffer.h rename to plugins/vst/external/ring_buffer/ring_buffer/ring_buffer.h diff --git a/vst/external/ring_buffer/ring_buffer/ring_buffer.tcc b/plugins/vst/external/ring_buffer/ring_buffer/ring_buffer.tcc similarity index 100% rename from vst/external/ring_buffer/ring_buffer/ring_buffer.tcc rename to plugins/vst/external/ring_buffer/ring_buffer/ring_buffer.tcc diff --git a/vst/external/sfzt_auwrapper b/plugins/vst/external/sfzt_auwrapper similarity index 100% rename from vst/external/sfzt_auwrapper rename to plugins/vst/external/sfzt_auwrapper diff --git a/vst/gpl-3.0.txt b/plugins/vst/gpl-3.0.txt similarity index 100% rename from vst/gpl-3.0.txt rename to plugins/vst/gpl-3.0.txt diff --git a/vst/mac/Info.au.plist b/plugins/vst/mac/Info.au.plist similarity index 100% rename from vst/mac/Info.au.plist rename to plugins/vst/mac/Info.au.plist diff --git a/vst/mac/Info.vst3.plist b/plugins/vst/mac/Info.vst3.plist similarity index 100% rename from vst/mac/Info.vst3.plist rename to plugins/vst/mac/Info.vst3.plist diff --git a/vst/mac/PkgInfo b/plugins/vst/mac/PkgInfo similarity index 100% rename from vst/mac/PkgInfo rename to plugins/vst/mac/PkgInfo diff --git a/vst/mac/audiounitconfig.h.in b/plugins/vst/mac/audiounitconfig.h.in similarity index 100% rename from vst/mac/audiounitconfig.h.in rename to plugins/vst/mac/audiounitconfig.h.in diff --git a/vst/vst3.def b/plugins/vst/vst3.def similarity index 100% rename from vst/vst3.def rename to plugins/vst/vst3.def diff --git a/vst/vst3.version b/plugins/vst/vst3.version similarity index 100% rename from vst/vst3.version rename to plugins/vst/vst3.version diff --git a/vst/win/Plugin.ico b/plugins/vst/win/Plugin.ico similarity index 100% rename from vst/win/Plugin.ico rename to plugins/vst/win/Plugin.ico diff --git a/vst/win/desktop.ini b/plugins/vst/win/desktop.ini similarity index 100% rename from vst/win/desktop.ini rename to plugins/vst/win/desktop.ini From af551ab96f9a6c9c8331af8357860728f082ce62 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 16:31:12 +0100 Subject: [PATCH 228/668] Build LV2 with C++ --- plugins/lv2/CMakeLists.txt | 3 +- plugins/lv2/atomic_compat.h | 64 ------- plugins/lv2/{sfizz.c => sfizz.cpp} | 273 +++++++++++++++-------------- 3 files changed, 139 insertions(+), 201 deletions(-) delete mode 100644 plugins/lv2/atomic_compat.h rename plugins/lv2/{sfizz.c => sfizz.cpp} (90%) diff --git a/plugins/lv2/CMakeLists.txt b/plugins/lv2/CMakeLists.txt index 39c447ec..e6623c1f 100644 --- a/plugins/lv2/CMakeLists.txt +++ b/plugins/lv2/CMakeLists.txt @@ -19,8 +19,7 @@ source_group("Turtle Files" FILES ${LV2PLUGIN_TTL_SRC_FILES} ) add_library(${LV2PLUGIN_PRJ_NAME} MODULE - ${PROJECT_NAME}.c - atomic_compat.h + ${PROJECT_NAME}.cpp ${LV2PLUGIN_TTL_SRC_FILES}) target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::spin_mutex) diff --git a/plugins/lv2/atomic_compat.h b/plugins/lv2/atomic_compat.h deleted file mode 100644 index 0778356b..00000000 --- a/plugins/lv2/atomic_compat.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - SPDX-License-Identifier: ISC - - Sfizz LV2 plugin - - Copyright 2019-2020, Paul Ferrand - - This file was based on skeleton and example code from the LV2 plugin - distribution available at http://lv2plug.in/ - - The LV2 sample plugins have the following copyright and notice, which are - extended to the current work: - Copyright 2011-2016 David Robillard - Copyright 2011 Gabriel M. Beddingfield - Copyright 2011 James Morris - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - Compiling this plugin statically against libsndfile implies distributing it - under the terms of the LGPL v3 license. See the LICENSE.md file for more - information. If you did not receive a LICENSE.md file, inform the current - maintainer. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#if defined(__cplusplus) - -#include - -#elif defined(_MSC_VER) - -#include - -typedef volatile int atomic_int; - -inline int atomic_exchange(atomic_int *d, int x) -{ - return _InterlockedExchange((volatile long *)d, (long)x); -} - -inline void atomic_store(atomic_int *d, int x) -{ - _InterlockedExchange((volatile long *)d, (long)x); -} - -inline int atomic_load(const atomic_int *d) -{ - return _InterlockedOr((volatile long *)d, 0); -} - -#else - -#include - -#endif diff --git a/plugins/lv2/sfizz.c b/plugins/lv2/sfizz.cpp similarity index 90% rename from plugins/lv2/sfizz.c rename to plugins/lv2/sfizz.cpp index 115fea48..6409627e 100644 --- a/plugins/lv2/sfizz.c +++ b/plugins/lv2/sfizz.cpp @@ -61,7 +61,7 @@ #include #include -#include "atomic_compat.h" +#include #define CHANNEL_MASK 0x0F #define MIDI_CHANNEL(byte) (byte & CHANNEL_MASK) @@ -86,110 +86,110 @@ #define LV2_DEBUG(...) #endif -typedef struct +struct sfizz_plugin_t { // Features - LV2_URID_Map *map; - LV2_URID_Unmap *unmap; - LV2_Worker_Schedule *worker; - LV2_Log_Log *log; - LV2_Midnam *midnam; + LV2_URID_Map *map {}; + LV2_URID_Unmap *unmap {}; + LV2_Worker_Schedule *worker {}; + LV2_Log_Log *log {}; + LV2_Midnam *midnam {}; // Ports - const LV2_Atom_Sequence *control_port; - LV2_Atom_Sequence *notify_port; - float *output_buffers[2]; - const float *volume_port; - const float *polyphony_port; - const float *oversampling_port; - const float *preload_port; - const float *freewheel_port; - const float *scala_root_key_port; - const float *tuning_frequency_port; - const float *stretch_tuning_port; - float *active_voices_port; - float *num_curves_port; - float *num_masters_port; - float *num_groups_port; - float *num_regions_port; - float *num_samples_port; + const LV2_Atom_Sequence *control_port {}; + LV2_Atom_Sequence *notify_port {}; + float *output_buffers[2] {}; + const float *volume_port {}; + const float *polyphony_port {}; + const float *oversampling_port {}; + const float *preload_port {}; + const float *freewheel_port {}; + const float *scala_root_key_port {}; + const float *tuning_frequency_port {}; + const float *stretch_tuning_port {}; + float *active_voices_port {}; + float *num_curves_port {}; + float *num_masters_port {}; + float *num_groups_port {}; + float *num_regions_port {}; + float *num_samples_port {}; // Atom forge - LV2_Atom_Forge forge; ///< Forge for writing atoms in run thread - LV2_Atom_Forge forge_secondary; ///< Forge for writing into other buffers + LV2_Atom_Forge forge {}; ///< Forge for writing atoms in run thread + LV2_Atom_Forge forge_secondary {}; ///< Forge for writing into other buffers // Logger - LV2_Log_Logger logger; + LV2_Log_Logger logger {}; // URIs - LV2_URID midi_event_uri; - LV2_URID options_interface_uri; - LV2_URID max_block_length_uri; - LV2_URID nominal_block_length_uri; - LV2_URID sample_rate_uri; - LV2_URID atom_object_uri; - LV2_URID atom_blank_uri; - LV2_URID atom_float_uri; - LV2_URID atom_double_uri; - LV2_URID atom_int_uri; - LV2_URID atom_long_uri; - LV2_URID atom_urid_uri; - LV2_URID atom_path_uri; - LV2_URID patch_set_uri; - LV2_URID patch_get_uri; - LV2_URID patch_put_uri; - LV2_URID patch_property_uri; - LV2_URID patch_value_uri; - LV2_URID patch_body_uri; - LV2_URID state_changed_uri; - LV2_URID sfizz_sfz_file_uri; - LV2_URID sfizz_scala_file_uri; - LV2_URID sfizz_num_voices_uri; - LV2_URID sfizz_preload_size_uri; - LV2_URID sfizz_oversampling_uri; - LV2_URID sfizz_log_status_uri; - LV2_URID sfizz_check_modification_uri; - LV2_URID sfizz_active_voices_uri; - LV2_URID sfizz_osc_blob_uri; - LV2_URID time_position_uri; - LV2_URID time_bar_uri; - LV2_URID time_bar_beat_uri; - LV2_URID time_beat_unit_uri; - LV2_URID time_beats_per_bar_uri; - LV2_URID time_beats_per_minute_uri; - LV2_URID time_speed_uri; + LV2_URID midi_event_uri {}; + LV2_URID options_interface_uri {}; + LV2_URID max_block_length_uri {}; + LV2_URID nominal_block_length_uri {}; + LV2_URID sample_rate_uri {}; + LV2_URID atom_object_uri {}; + LV2_URID atom_blank_uri {}; + LV2_URID atom_float_uri {}; + LV2_URID atom_double_uri {}; + LV2_URID atom_int_uri {}; + LV2_URID atom_long_uri {}; + LV2_URID atom_urid_uri {}; + LV2_URID atom_path_uri {}; + LV2_URID patch_set_uri {}; + LV2_URID patch_get_uri {}; + LV2_URID patch_put_uri {}; + LV2_URID patch_property_uri {}; + LV2_URID patch_value_uri {}; + LV2_URID patch_body_uri {}; + LV2_URID state_changed_uri {}; + LV2_URID sfizz_sfz_file_uri {}; + LV2_URID sfizz_scala_file_uri {}; + LV2_URID sfizz_num_voices_uri {}; + LV2_URID sfizz_preload_size_uri {}; + LV2_URID sfizz_oversampling_uri {}; + LV2_URID sfizz_log_status_uri {}; + LV2_URID sfizz_check_modification_uri {}; + LV2_URID sfizz_active_voices_uri {}; + LV2_URID sfizz_osc_blob_uri {}; + LV2_URID time_position_uri {}; + LV2_URID time_bar_uri {}; + LV2_URID time_bar_beat_uri {}; + LV2_URID time_beat_unit_uri {}; + LV2_URID time_beats_per_bar_uri {}; + LV2_URID time_beats_per_minute_uri {}; + LV2_URID time_speed_uri {}; // Sfizz related data - sfizz_synth_t *synth; - sfizz_client_t *client; - spin_mutex_t *synth_mutex; - bool expect_nominal_block_length; - char sfz_file_path[MAX_PATH_SIZE]; - char scala_file_path[MAX_PATH_SIZE]; - int num_voices; - unsigned int preload_size; - sfizz_oversampling_factor_t oversampling; - float stretch_tuning; - volatile bool check_modification; - int max_block_size; - int sample_counter; - float sample_rate; - atomic_int must_update_midnam; + sfizz_synth_t *synth {}; + sfizz_client_t *client {}; + spin_mutex_t *synth_mutex {}; + bool expect_nominal_block_length {}; + char sfz_file_path[MAX_PATH_SIZE] {}; + char scala_file_path[MAX_PATH_SIZE] {}; + int num_voices {}; + unsigned int preload_size {}; + sfizz_oversampling_factor_t oversampling {}; + float stretch_tuning {}; + volatile bool check_modification {}; + int max_block_size {}; + int sample_counter {}; + float sample_rate {}; + std::atomic must_update_midnam {}; // Timing data - int bar; - double bar_beat; - int beats_per_bar; - int beat_unit; - double bpm_tempo; - double speed; + int bar {}; + double bar_beat {}; + int beats_per_bar {}; + int beat_unit {}; + double bpm_tempo {}; + double speed {}; // Paths - char bundle_path[MAX_BUNDLE_PATH_SIZE]; + char bundle_path[MAX_BUNDLE_PATH_SIZE] {}; // OSC - uint8_t osc_temp[OSC_TEMP_SIZE]; -} sfizz_plugin_t; + uint8_t osc_temp[OSC_TEMP_SIZE] {}; +}; enum { @@ -209,8 +209,8 @@ sfizz_lv2_state_free_path(LV2_State_Free_Path_Handle handle, static LV2_State_Free_Path sfizz_State_Free_Path = { - .handle = NULL, - .free_path = &sfizz_lv2_state_free_path, + NULL, + &sfizz_lv2_state_free_path, }; static void @@ -467,7 +467,7 @@ instantiate(const LV2_Descriptor *descriptor, bool supports_fixed_block_size = false; // Allocate and initialise instance structure. - sfizz_plugin_t *self = (sfizz_plugin_t *)calloc(1, sizeof(sfizz_plugin_t)); + sfizz_plugin_t *self = new sfizz_plugin_t; if (!self) return NULL; @@ -500,31 +500,34 @@ instantiate(const LV2_Descriptor *descriptor, // Get the features from the host and populate the structure for (const LV2_Feature *const *f = features; *f; f++) { + const char *uri = (**f).URI; + void *data = (**f).data; + // lv2_log_note(&self->logger, "Feature URI: %s\n", (**f).URI); - if (!strcmp((**f).URI, LV2_URID__map)) - self->map = (**f).data; + if (!strcmp(uri, LV2_URID__map)) + self->map = (LV2_URID_Map *)data; - if (!strcmp((**f).URI, LV2_URID__unmap)) - self->unmap = (**f).data; + if (!strcmp(uri, LV2_URID__unmap)) + self->unmap = (LV2_URID_Unmap *)data; - if (!strcmp((**f).URI, LV2_BUF_SIZE__boundedBlockLength)) + if (!strcmp(uri, LV2_BUF_SIZE__boundedBlockLength)) supports_bounded_block_size = true; - if (!strcmp((**f).URI, LV2_BUF_SIZE__fixedBlockLength)) + if (!strcmp(uri, LV2_BUF_SIZE__fixedBlockLength)) supports_fixed_block_size = true; - if (!strcmp((**f).URI, LV2_OPTIONS__options)) - options = (**f).data; + if (!strcmp(uri, LV2_OPTIONS__options)) + options = (LV2_Options_Option *)data; - if (!strcmp((**f).URI, LV2_WORKER__schedule)) - self->worker = (**f).data; + if (!strcmp(uri, LV2_WORKER__schedule)) + self->worker = (LV2_Worker_Schedule *)data; - if (!strcmp((**f).URI, LV2_LOG__log)) - self->log = (**f).data; + if (!strcmp(uri, LV2_LOG__log)) + self->log = (LV2_Log_Log *)data; - if (!strcmp((**f).URI, LV2_MIDNAM__update)) - self->midnam = (**f).data; + if (!strcmp(uri, LV2_MIDNAM__update)) + self->midnam = (LV2_Midnam *)data; } // Setup the loggers @@ -534,7 +537,7 @@ instantiate(const LV2_Descriptor *descriptor, if (!self->map) { lv2_log_error(&self->logger, "Map feature not found, aborting..\n"); - free(self); + delete self; return NULL; } @@ -542,7 +545,7 @@ instantiate(const LV2_Descriptor *descriptor, if (!self->worker) { lv2_log_error(&self->logger, "Worker feature not found, aborting..\n"); - free(self); + delete self; return NULL; } @@ -596,7 +599,7 @@ instantiate(const LV2_Descriptor *descriptor, { lv2_log_error(&self->logger, "Bounded block size not supported and options gave no block size, aborting..\n"); - free(self); + delete self; return NULL; } @@ -624,7 +627,7 @@ cleanup(LV2_Handle instance) spin_mutex_destroy(self->synth_mutex); sfizz_delete_client(self->client); sfizz_free(self->synth); - free(self); + delete self; } static void @@ -633,7 +636,7 @@ activate(LV2_Handle instance) sfizz_plugin_t *self = (sfizz_plugin_t *)instance; sfizz_set_samples_per_block(self->synth, self->max_block_size); sfizz_set_sample_rate(self->synth, self->sample_rate); - atomic_store(&self->must_update_midnam, 1); + self->must_update_midnam.store(1); } static void @@ -703,7 +706,9 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj) LV2_Atom_Forge *forge = &self->forge_secondary; sfizz_path_atom_buffer_t buffer; lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer)); - if (lv2_atom_forge_typed_string(forge, self->sfizz_sfz_file_uri, LV2_ATOM_BODY_CONST(atom), strnlen(LV2_ATOM_BODY_CONST(atom), atom->size))) + const char *body = (const char *)LV2_ATOM_BODY_CONST(atom); + uint32_t size = (uint32_t)strnlen(body, atom->size); + if (lv2_atom_forge_typed_string(forge, self->sfizz_sfz_file_uri, body, size)) self->worker->schedule_work(self->worker->handle, lv2_atom_total_size(&buffer.atom), &buffer.atom); self->check_modification = false; } @@ -712,7 +717,9 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj) LV2_Atom_Forge *forge = &self->forge_secondary; sfizz_path_atom_buffer_t buffer; lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer)); - if (lv2_atom_forge_typed_string(forge, self->sfizz_scala_file_uri, LV2_ATOM_BODY_CONST(atom), strnlen(LV2_ATOM_BODY_CONST(atom), atom->size))) + const char *body = (const char *)LV2_ATOM_BODY_CONST(atom); + uint32_t size = (uint32_t)strnlen(body, atom->size); + if (lv2_atom_forge_typed_string(forge, self->sfizz_scala_file_uri, body, size)) self->worker->schedule_work(self->worker->handle, lv2_atom_total_size(&buffer.atom), &buffer.atom); self->check_modification = false; } @@ -798,11 +805,10 @@ sfizz_lv2_check_oversampling(sfizz_plugin_t* self) self->oversampling = (sfizz_oversampling_factor_t)port_value; - LV2_Atom_Int atom = { - .atom.type = self->sfizz_oversampling_uri, - .atom.size = sizeof(int), - .body = self->oversampling - }; + LV2_Atom_Int atom; + atom.atom.type = self->sfizz_oversampling_uri; + atom.atom.size = sizeof(int); + atom.body = self->oversampling; if (self->worker->schedule_work(self->worker->handle, lv2_atom_total_size((LV2_Atom *)&atom), &atom) != LV2_WORKER_SUCCESS) @@ -817,11 +823,10 @@ sfizz_lv2_check_preload_size(sfizz_plugin_t* self) unsigned int preload_size = (int)*self->preload_port; if (preload_size != self->preload_size) { - LV2_Atom_Int atom = { - .atom.type = self->sfizz_preload_size_uri, - .atom.size = sizeof(int), - .body = preload_size - }; + LV2_Atom_Int atom; + atom.atom.type = self->sfizz_preload_size_uri; + atom.atom.size = sizeof(int); + atom.body = preload_size; if (self->worker->schedule_work(self->worker->handle, lv2_atom_total_size((LV2_Atom *)&atom), &atom) != LV2_WORKER_SUCCESS) @@ -838,11 +843,10 @@ sfizz_lv2_check_num_voices(sfizz_plugin_t* self) int num_voices = (int)*self->polyphony_port; if (num_voices != self->num_voices) { - LV2_Atom_Int atom = { - .atom.type = self->sfizz_num_voices_uri, - .atom.size = sizeof(int), - .body = num_voices - }; + LV2_Atom_Int atom; + atom.atom.type = self->sfizz_num_voices_uri; + atom.atom.size = sizeof(int); + atom.body = num_voices; if (self->worker->schedule_work(self->worker->handle, lv2_atom_total_size((LV2_Atom *)&atom), &atom) != LV2_WORKER_SUCCESS) @@ -1061,7 +1065,7 @@ run(LV2_Handle instance, uint32_t sample_count) spin_mutex_unlock(self->synth_mutex); - if (self->midnam && atomic_exchange(&self->must_update_midnam, 0)) + if (self->midnam && self->must_update_midnam.exchange(0)) { self->midnam->update(self->midnam->handle); } @@ -1162,7 +1166,7 @@ sfizz_lv2_update_file_info(sfizz_plugin_t* self, const char *file_path) lv2_log_note(&self->logger, "[sfizz] Number of groups: %d\n", sfizz_get_num_groups(self->synth)); lv2_log_note(&self->logger, "[sfizz] Number of regions: %d\n", sfizz_get_num_regions(self->synth)); - atomic_store(&self->must_update_midnam, 1); + self->must_update_midnam.store(1); } static bool @@ -1415,10 +1419,9 @@ sfizz_lv2_activate_file_checking( LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle) { - LV2_Atom check_modification_atom = { - .size = 0, - .type = self->sfizz_check_modification_uri - }; + LV2_Atom check_modification_atom; + check_modification_atom.size = 0; + check_modification_atom.type = self->sfizz_check_modification_uri; respond(handle, lv2_atom_total_size(&check_modification_atom), &check_modification_atom); } @@ -1440,7 +1443,7 @@ work(LV2_Handle instance, const LV2_Atom *atom = (const LV2_Atom *)data; if (atom->type == self->sfizz_sfz_file_uri) { - const char *sfz_file_path = LV2_ATOM_BODY_CONST(atom); + const char *sfz_file_path = (const char *)LV2_ATOM_BODY_CONST(atom); spin_mutex_lock(self->synth_mutex); bool success = sfizz_lv2_load_file(self, sfz_file_path); @@ -1456,7 +1459,7 @@ work(LV2_Handle instance, } else if (atom->type == self->sfizz_scala_file_uri) { - const char *scala_file_path = LV2_ATOM_BODY_CONST(atom); + const char *scala_file_path = (const char *)LV2_ATOM_BODY_CONST(atom); spin_mutex_lock(self->synth_mutex); bool success = sfizz_lv2_load_scala_file(self, scala_file_path); @@ -1600,7 +1603,7 @@ work_response(LV2_Handle instance, static char * midnam_model(LV2_Handle instance) { - char *model = malloc(64); + char *model = (char *)malloc(64); if (!model) return NULL; From 360d441eaa04d1a2c73203c8656601f2b6a47b7f Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 8 Feb 2021 19:22:56 +0100 Subject: [PATCH 229/668] Simplified the skipVoice check in note polyphony checks Removed the trigger type check; both attack and release can choke each other --- src/sfizz/VoiceManager.cpp | 8 ++--- tests/PolyphonyT.cpp | 66 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/sfizz/VoiceManager.cpp b/src/sfizz/VoiceManager.cpp index 490927b2..122b87a7 100644 --- a/src/sfizz/VoiceManager.cpp +++ b/src/sfizz/VoiceManager.cpp @@ -189,13 +189,9 @@ void VoiceManager::checkNotePolyphony(const Region* region, int delay, const Tri for (Voice* voice : activeVoices_) { const TriggerEvent& voiceTriggerEvent = voice->getTriggerEvent(); - const bool skipVoice = - (triggerEvent.type == TriggerEventType::NoteOn && voice->releasedOrFree()) - || voice->isFree(); - if (!skipVoice + if (!voice->releasedOrFree() && voice->getRegion()->group == region->group - && voiceTriggerEvent.number == triggerEvent.number - && voiceTriggerEvent.type == triggerEvent.type) { + && voiceTriggerEvent.number == triggerEvent.number) { notePolyphonyCounter += 1; switch (region->selfMask) { case SfzSelfMask::mask: diff --git a/tests/PolyphonyT.cpp b/tests/PolyphonyT.cpp index 58a5cd54..c2c75aa3 100644 --- a/tests/PolyphonyT.cpp +++ b/tests/PolyphonyT.cpp @@ -439,7 +439,7 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped sfz::Synth synth; sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( - key=48 sample=*silence + key=48 sample=*sine key=48 note_polyphony=1 sample=*saw trigger=release ampeg_attack=1 ampeg_decay=1 )"); synth.cc(0, 64, 127); @@ -450,9 +450,17 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped synth.noteOn(4, 48, 63 ); synth.noteOff(5, 48, 0 ); REQUIRE( synth.getNumActiveVoices() == 3); + REQUIRE( synth.getVoiceView(0)->getRegion()->sampleId->filename() == "*sine"); + REQUIRE( synth.getVoiceView(1)->getRegion()->sampleId->filename() == "*sine"); + REQUIRE( synth.getVoiceView(2)->getRegion()->sampleId->filename() == "*sine"); + synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 3 ); synth.cc(20, 64, 0); REQUIRE( synth.getNumActiveVoices() == 6 ); + REQUIRE( synth.getVoiceView(3)->getRegion()->sampleId->filename() == "*saw"); + REQUIRE( synth.getVoiceView(4)->getRegion()->sampleId->filename() == "*saw"); + REQUIRE( synth.getVoiceView(5)->getRegion()->sampleId->filename() == "*saw"); + synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 1 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 61_norm); REQUIRE( synth.getVoiceView(0)->releasedOrFree()); @@ -473,7 +481,7 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped sfz::Synth synth; sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( - key=48 sample=*silence + key=48 sample=*sine key=48 note_polyphony=1 sample=*saw trigger=release ampeg_attack=1 ampeg_decay=1 )"); synth.cc(0, 64, 127); @@ -484,9 +492,17 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped synth.noteOn(4, 48, 61 ); synth.noteOff(5, 48, 0 ); REQUIRE( synth.getNumActiveVoices() == 3); + REQUIRE( synth.getVoiceView(0)->getRegion()->sampleId->filename() == "*sine"); + REQUIRE( synth.getVoiceView(1)->getRegion()->sampleId->filename() == "*sine"); + REQUIRE( synth.getVoiceView(2)->getRegion()->sampleId->filename() == "*sine"); + synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 3 ); synth.cc(20, 64, 0); REQUIRE( synth.getNumActiveVoices() == 6 ); + REQUIRE( synth.getVoiceView(3)->getRegion()->sampleId->filename() == "*saw"); + REQUIRE( synth.getVoiceView(4)->getRegion()->sampleId->filename() == "*saw"); + REQUIRE( synth.getVoiceView(5)->getRegion()->sampleId->filename() == "*saw"); + synth.renderBlock(buffer); REQUIRE( numPlayingVoices(synth) == 3 ); REQUIRE( synth.getVoiceView(0)->getTriggerEvent().value == 63_norm); REQUIRE( synth.getVoiceView(0)->releasedOrFree()); @@ -501,3 +517,49 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped REQUIRE( synth.getVoiceView(5)->getTriggerEvent().value == 61_norm); REQUIRE(!synth.getVoiceView(5)->releasedOrFree()); } + +TEST_CASE("[Polyphony] Bi-directional choking (with polyphony)") +{ + sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + key=60 polyphony=1 + sample=kick.wav loop_mode=one_shot + sample=snare.wav trigger=release + )"); + synth.noteOn(0, 60, 63 ); + REQUIRE( synth.getNumActiveVoices() == 1); + REQUIRE( numPlayingVoices(synth) == 1 ); + REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "kick.wav" ); + synth.noteOff(10, 60, 63 ); + REQUIRE( synth.getNumActiveVoices() == 2); + REQUIRE( numPlayingVoices(synth) == 1 ); + REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "snare.wav" ); + synth.noteOn(20, 60, 63 ); + REQUIRE( synth.getNumActiveVoices() == 3); + REQUIRE( numPlayingVoices(synth) == 1 ); + REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "kick.wav" ); +} + +TEST_CASE("[Polyphony] Bi-directional choking (with note_polyphony)") +{ + sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + key=60 note_polyphony=1 + sample=kick.wav loop_mode=one_shot + sample=snare.wav trigger=release + )"); + synth.noteOn(0, 60, 63 ); + REQUIRE( synth.getNumActiveVoices() == 1); + REQUIRE( numPlayingVoices(synth) == 1 ); + REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "kick.wav" ); + synth.noteOff(10, 60, 63 ); + REQUIRE( synth.getNumActiveVoices() == 2); + REQUIRE( numPlayingVoices(synth) == 1 ); + REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "snare.wav" ); + synth.noteOn(20, 60, 63 ); + REQUIRE( synth.getNumActiveVoices() == 3); + REQUIRE( numPlayingVoices(synth) == 1 ); + REQUIRE( getPlayingVoices(synth).front()->getRegion()->sampleId->filename() == "kick.wav" ); +} From 9e2b914a081098ed4e793af87653c63a6fbe283b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 19:53:31 +0100 Subject: [PATCH 230/668] Update control panel for efficient updates, preserving values --- plugins/editor/src/editor/GUIComponents.cpp | 166 ++++++++++---------- plugins/editor/src/editor/GUIComponents.h | 6 + 2 files changed, 88 insertions(+), 84 deletions(-) diff --git a/plugins/editor/src/editor/GUIComponents.cpp b/plugins/editor/src/editor/GUIComponents.cpp index e188dbf5..b349ecef 100644 --- a/plugins/editor/src/editor/GUIComponents.cpp +++ b/plugins/editor/src/editor/GUIComponents.cpp @@ -11,6 +11,7 @@ #include "utility/vstgui_before.h" #include "vstgui/lib/cdrawcontext.h" #include "vstgui/lib/cgraphicspath.h" +#include "vstgui/lib/cvstguitimer.h" #include "vstgui/lib/cframe.h" #include "utility/vstgui_after.h" @@ -527,70 +528,23 @@ SControlsPanel::SControlsPanel(const CRect& size) setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); setScrollbarWidth(10.0); + + relayoutTrigger_ = makeOwned( + [this](CVSTGUITimer* timer) { timer->stop(); updateLayout(); }, + 1, false); } void SControlsPanel::setControlUsed(uint32_t index, bool used) { - bool changed = false; - - if (used) { - if (index + 1 > slots_.size()) - slots_.resize(index + 1); - ControlSlot* slot = slots_[index].get(); - changed = !slot; - if (changed) { - slot = new ControlSlot; - slots_[index].reset(slot); - - // create controls etc... - CCoord knobWidth = 48.0; - CCoord knobHeight = knobWidth; - CCoord labelWidth = 96.0; - CCoord labelHeight = 24.0; - CCoord verticalPadding = 0.0; - - CCoord totalWidth = std::max(knobWidth, labelWidth); - CCoord knobX = (totalWidth - knobWidth) / 2.0; - CCoord labelX = (totalWidth - labelWidth) / 2.0; - - CRect knobBounds(knobX, 0.0, knobX + knobWidth, knobHeight); - CRect labelBounds(labelX, knobHeight + verticalPadding, labelX + labelWidth, knobHeight + verticalPadding + labelHeight); - CRect boxBounds = CRect(knobBounds).unite(labelBounds); - - SharedPointer knob = owned(new SStyledKnob(knobBounds, listener_.get(), index)); - SharedPointer label = owned(new CTextLabel(labelBounds)); - SharedPointer box = owned(new CViewContainer(boxBounds)); - - box->addView(knob); - knob->remember(); - box->addView(label); - label->remember(); - - box->setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setStyle(CTextLabel::kRoundRectStyle); - label->setRoundRectRadius(5.0); - label->setBackColor(CColor(0x2e, 0x34, 0x36)); - label->setTextTruncateMode(CTextLabel::kTruncateTail); - label->setTextInset({4.0, 0.0}); - label->setText(getDefaultLabelText(index)); - knob->setActiveTrackColor(CColor(0x00, 0xb6, 0x2a)); - knob->setInactiveTrackColor(CColor(0x30, 0x30, 0x30)); - knob->setLineIndicatorColor(CColor(0x00, 0x00, 0x00)); - - slot->knob = knob; - slot->label = label; - slot->box = box; - } + ControlSlot* slot = getSlot(index); + if (!slot && !used) + return; + if (!slot) + slot = getOrCreateSlot(index); + if (used != slot->used) { + slot->used = used; + relayoutTrigger_->start(); } - else { - if (index < slots_.size() && slots_[index]) { - changed = true; - slots_[index].reset(); - } - } - - if (changed) - updateLayout(); } std::string SControlsPanel::getDefaultLabelText(uint32_t index) @@ -598,40 +552,84 @@ std::string SControlsPanel::getDefaultLabelText(uint32_t index) return "CC " + std::to_string(index); } +SControlsPanel::ControlSlot* SControlsPanel::getSlot(uint32_t index) +{ + ControlSlot* slot = nullptr; + if (index < slots_.size()) + slot = slots_[index].get(); + return slot; +} + +SControlsPanel::ControlSlot* SControlsPanel::getOrCreateSlot(uint32_t index) +{ + ControlSlot* slot = getSlot(index); + if (slot) + return slot; + + if (index + 1 > slots_.size()) + slots_.resize(index + 1); + + slot = new ControlSlot; + slots_[index].reset(slot); + + // create controls etc... + CCoord knobWidth = 48.0; + CCoord knobHeight = knobWidth; + CCoord labelWidth = 96.0; + CCoord labelHeight = 24.0; + CCoord verticalPadding = 0.0; + + CCoord totalWidth = std::max(knobWidth, labelWidth); + CCoord knobX = (totalWidth - knobWidth) / 2.0; + CCoord labelX = (totalWidth - labelWidth) / 2.0; + + CRect knobBounds(knobX, 0.0, knobX + knobWidth, knobHeight); + CRect labelBounds(labelX, knobHeight + verticalPadding, labelX + labelWidth, knobHeight + verticalPadding + labelHeight); + CRect boxBounds = CRect(knobBounds).unite(labelBounds); + + SharedPointer knob = owned(new SStyledKnob(knobBounds, listener_.get(), index)); + SharedPointer label = owned(new CTextLabel(labelBounds)); + SharedPointer box = owned(new CViewContainer(boxBounds)); + + box->addView(knob); + knob->remember(); + box->addView(label); + label->remember(); + + box->setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setStyle(CTextLabel::kRoundRectStyle); + label->setRoundRectRadius(5.0); + label->setBackColor(CColor(0x2e, 0x34, 0x36)); + label->setText(getDefaultLabelText(index)); + knob->setActiveTrackColor(CColor(0x00, 0xb6, 0x2a)); + knob->setInactiveTrackColor(CColor(0x30, 0x30, 0x30)); + knob->setLineIndicatorColor(CColor(0x00, 0x00, 0x00)); + + slot->knob = knob; + slot->label = label; + slot->box = box; + + return slot; +} + void SControlsPanel::setControlValue(uint32_t index, float value) { - if (index >= slots_.size()) - return; - - ControlSlot* slot = slots_[index].get(); - if (!slot) - return; - - slot->knob->setValue(value); - slot->knob->invalid(); + ControlSlot* slot = getOrCreateSlot(index); + CControl* knob = slot->knob; + knob->setValue(value); + knob->invalid(); } void SControlsPanel::setControlDefaultValue(uint32_t index, float value) { - if (index >= slots_.size()) - return; - - ControlSlot* slot = slots_[index].get(); - if (!slot) - return; - - slot->knob->setDefaultValue(value); + ControlSlot* slot = getOrCreateSlot(index); + CControl* knob = slot->knob; + knob->setDefaultValue(value); } void SControlsPanel::setControlLabelText(uint32_t index, UTF8StringPtr text) { - if (index >= slots_.size()) - return; - - ControlSlot* slot = slots_[index].get(); - if (!slot) - return; - + ControlSlot* slot = getOrCreateSlot(index); CTextLabel* label = slot->label; if (text && text[0] != '\0') label->setText(text); @@ -675,7 +673,7 @@ void SControlsPanel::updateLayout() uint32_t numSlots = static_cast(slots_.size()); for (uint32_t i = 0; i < numSlots; ++i) { ControlSlot* slot = slots_[i].get(); - if (!slot) + if (!slot || !slot->used) continue; CViewContainer* box = slot->box; diff --git a/plugins/editor/src/editor/GUIComponents.h b/plugins/editor/src/editor/GUIComponents.h index e2c987f6..8c2237ec 100644 --- a/plugins/editor/src/editor/GUIComponents.h +++ b/plugins/editor/src/editor/GUIComponents.h @@ -237,8 +237,13 @@ private: void updateLayout(); static std::string getDefaultLabelText(uint32_t index); + struct ControlSlot; + ControlSlot* getSlot(uint32_t index); + ControlSlot* getOrCreateSlot(uint32_t index); + private: struct ControlSlot { + bool used = false; SharedPointer knob; SharedPointer label; SharedPointer box; @@ -257,6 +262,7 @@ private: std::vector> slots_; std::unique_ptr listener_; + SharedPointer relayoutTrigger_; }; /// From 6b319c590730d20f46dc8377ef1283f8763a1944 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 19:59:38 +0100 Subject: [PATCH 231/668] Remove the unused variable --- plugins/editor/src/editor/GUIComponents.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/editor/src/editor/GUIComponents.cpp b/plugins/editor/src/editor/GUIComponents.cpp index b349ecef..bc3d718b 100644 --- a/plugins/editor/src/editor/GUIComponents.cpp +++ b/plugins/editor/src/editor/GUIComponents.cpp @@ -707,8 +707,6 @@ void SControlsPanel::updateLayout() } } - CRect containerSize = getContainerSize(); - containerSize.bottom = containerBottom; setContainerSize(CRect(0.0, 0.0, viewBounds.getWidth(), containerBottom + verticalPadding)); invalid(); From 89a6830e1eb1d91d4f49e84c6de949a877b014d8 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 20:07:43 +0100 Subject: [PATCH 232/668] Add controller edit IDs (not used yet) --- plugins/editor/src/editor/EditIds.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/plugins/editor/src/editor/EditIds.h b/plugins/editor/src/editor/EditIds.h index 1edec8b4..d9b43957 100644 --- a/plugins/editor/src/editor/EditIds.h +++ b/plugins/editor/src/editor/EditIds.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "sfizz/Config.h" #include enum class EditId : int { @@ -19,6 +20,10 @@ enum class EditId : int { StretchTuning, CanEditUserFilesDir, UserFilesDir, + // + Controller0, + ControllerLast = Controller0 + sfz::config::numCCs - 1, + // UINumCurves, UINumMasters, UINumGroups, @@ -38,3 +43,17 @@ struct EditRange { float extent() const noexcept { return max - min; } static EditRange get(EditId id); }; + +inline EditId editIdForCC(int cc) +{ + return EditId(int(EditId::Controller0) + cc); +} +inline int ccForEditId(EditId id) +{ + return int(id) - int(EditId::Controller0); +} +inline bool editIdIsCC(EditId id) +{ + return int(id) >= int(EditId::Controller0) && + int(id) <= int(EditId::ControllerLast); +} From 77719d788e530cb7a976f0bf95e5cc0e17518f77 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 20:12:48 +0100 Subject: [PATCH 233/668] Keep CC assignments in array, so they may be reassigned --- plugins/vst/SfizzVstController.cpp | 45 +++++++++++++++++++----------- plugins/vst/SfizzVstController.h | 2 ++ plugins/vst/SfizzVstParameters.h | 8 ++---- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/plugins/vst/SfizzVstController.cpp b/plugins/vst/SfizzVstController.cpp index c1ab5c73..122936e1 100644 --- a/plugins/vst/SfizzVstController.cpp +++ b/plugins/vst/SfizzVstController.cpp @@ -9,7 +9,6 @@ #include "SfizzVstParameters.h" #include "base/source/fstreamer.h" #include "base/source/updatehandler.h" -#include "pluginterfaces/vst/ivstmidicontrollers.h" tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) { @@ -65,7 +64,7 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) parameters.addParameter(Steinberg::String("Pitch bend"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId); // MIDI controllers - for (unsigned i = 0; i < kNumControllerParams; ++i) { + for (unsigned i = 0; i < sfz::config::numCCs; ++i) { Steinberg::String title; Steinberg::String shortTitle; title.printf("Controller %u", i); @@ -76,6 +75,24 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) pid++, Vst::kRootUnitId, shortTitle); } + // Initial MIDI mapping + for (int32 i = 0; i < Vst::kCountCtrlNumber; ++i) { + Vst::ParamID id = Vst::kNoParamId; + switch (i) { + case Vst::kAfterTouch: + id = kPidMidiAftertouch; + break; + case Vst::kPitchBend: + id = kPidMidiPitchBend; + break; + default: + if (i < 128) + id = kPidMidiCC0 + i; + break; + } + midiMapping_[i] = id; + } + return kResultTrue; } @@ -86,22 +103,16 @@ tresult PLUGIN_API SfizzVstControllerNoUi::terminate() tresult PLUGIN_API SfizzVstControllerNoUi::getMidiControllerAssignment(int32 busIndex, int16 channel, Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id) { - switch (midiControllerNumber) { - case Vst::kAfterTouch: - id = kPidMidiAftertouch; - return kResultTrue; - - case Vst::kPitchBend: - id = kPidMidiPitchBend; - return kResultTrue; - - default: - if (midiControllerNumber < 0 || midiControllerNumber >= kNumControllerParams) - return kResultFalse; - - id = kPidMidiCC0 + midiControllerNumber; - return kResultTrue; + if (midiControllerNumber < 0 || midiControllerNumber >= Vst::kCountCtrlNumber) { + id = Vst::kNoParamId; + return kResultFalse; } + + id = midiMapping_[midiControllerNumber]; + if (id == Vst::kNoParamId) + return kResultFalse; + + return kResultTrue; } tresult PLUGIN_API SfizzVstControllerNoUi::getParamStringByValue(Vst::ParamID tag, Vst::ParamValue valueNormalized, Vst::String128 string) diff --git a/plugins/vst/SfizzVstController.h b/plugins/vst/SfizzVstController.h index 2365417b..2c207e23 100644 --- a/plugins/vst/SfizzVstController.h +++ b/plugins/vst/SfizzVstController.h @@ -9,6 +9,7 @@ #include "SfizzVstUpdates.h" #include "public.sdk/source/vst/vsteditcontroller.h" #include "public.sdk/source/vst/vstparameters.h" +#include "pluginterfaces/vst/ivstmidicontrollers.h" #include "vstgui/plugin-bindings/vst3editor.h" #include #include @@ -49,6 +50,7 @@ protected: Steinberg::IPtr scalaPathUpdate_; Steinberg::IPtr processorStateUpdate_; Steinberg::IPtr playStateUpdate_; + Vst::ParamID midiMapping_[Vst::kCountCtrlNumber] {}; }; class SfizzVstController : public SfizzVstControllerNoUi, public VSTGUI::VST3EditorDelegate { diff --git a/plugins/vst/SfizzVstParameters.h b/plugins/vst/SfizzVstParameters.h index abaa55e6..7d5c5253 100644 --- a/plugins/vst/SfizzVstParameters.h +++ b/plugins/vst/SfizzVstParameters.h @@ -5,16 +5,12 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "sfizz/Config.h" #include "public.sdk/source/vst/vstparameters.h" #include using namespace Steinberg; -// number of MIDI CC -enum { - kNumControllerParams = 128, -}; - // parameters enum { kPidVolume, @@ -27,7 +23,7 @@ enum { kPidMidiAftertouch, kPidMidiPitchBend, kPidMidiCC0, - kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, + kPidMidiCCLast = kPidMidiCC0 + sfz::config::numCCs - 1, /* Reserved */ }; From e75c148c670e5371c0e76096a8f84127acb90af1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 20:14:07 +0100 Subject: [PATCH 234/668] Rename VST CC, not necessarily MIDI --- plugins/vst/SfizzVstController.cpp | 6 +++--- plugins/vst/SfizzVstParameters.h | 14 +++++++------- plugins/vst/SfizzVstProcessor.cpp | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/vst/SfizzVstController.cpp b/plugins/vst/SfizzVstController.cpp index 122936e1..6717f685 100644 --- a/plugins/vst/SfizzVstController.cpp +++ b/plugins/vst/SfizzVstController.cpp @@ -80,14 +80,14 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) Vst::ParamID id = Vst::kNoParamId; switch (i) { case Vst::kAfterTouch: - id = kPidMidiAftertouch; + id = kPidAftertouch; break; case Vst::kPitchBend: - id = kPidMidiPitchBend; + id = kPidPitchBend; break; default: if (i < 128) - id = kPidMidiCC0 + i; + id = kPidCC0 + i; break; } midiMapping_[i] = id; diff --git a/plugins/vst/SfizzVstParameters.h b/plugins/vst/SfizzVstParameters.h index 7d5c5253..e9367c8d 100644 --- a/plugins/vst/SfizzVstParameters.h +++ b/plugins/vst/SfizzVstParameters.h @@ -20,10 +20,10 @@ enum { kPidScalaRootKey, kPidTuningFrequency, kPidStretchedTuning, - kPidMidiAftertouch, - kPidMidiPitchBend, - kPidMidiCC0, - kPidMidiCCLast = kPidMidiCC0 + sfz::config::numCCs - 1, + kPidAftertouch, + kPidPitchBend, + kPidCC0, + kPidCCLast = kPidCC0 + sfz::config::numCCs - 1, /* Reserved */ }; @@ -67,12 +67,12 @@ struct SfizzRange { return {440.0, 300.0, 500.0}; case kPidStretchedTuning: return {0.0, 0.0, 1.0}; - case kPidMidiAftertouch: + case kPidAftertouch: return {0.0, 0.0, 1.0}; - case kPidMidiPitchBend: + case kPidPitchBend: return {0.5, 0.0, 1.0}; default: - if (id >= kPidMidiCC0 && id <= kPidMidiCCLast) + if (id >= kPidCC0 && id <= kPidCCLast) return {0.0, 0.0, 1.0}; throw std::runtime_error("Bad parameter ID"); } diff --git a/plugins/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp index 972b34dc..cde5c319 100644 --- a/plugins/vst/SfizzVstProcessor.cpp +++ b/plugins/vst/SfizzVstProcessor.cpp @@ -385,8 +385,8 @@ void SfizzVstProcessor::processControllerChanges(Vst::IParameterChanges& pc) switch (id) { default: - if (id >= kPidMidiCC0 && id <= kPidMidiCCLast) { - auto ccNumber = static_cast(id - kPidMidiCC0); + if (id >= kPidCC0 && id <= kPidCCLast) { + auto ccNumber = static_cast(id - kPidCC0); for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) synth.cc(sampleOffset, ccNumber, fastRound(value * 127.0)); @@ -394,14 +394,14 @@ void SfizzVstProcessor::processControllerChanges(Vst::IParameterChanges& pc) } break; - case kPidMidiAftertouch: + case kPidAftertouch: for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) synth.aftertouch(sampleOffset, fastRound(value * 127.0)); } break; - case kPidMidiPitchBend: + case kPidPitchBend: for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) synth.pitchWheel(sampleOffset, fastRound(value * 16383) - 8192); From 65c3ef8b6b1f164dc2263251de158ede9bb0dcdd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 20:15:48 +0100 Subject: [PATCH 235/668] Have VST send HD controller values --- plugins/vst/SfizzVstProcessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp index cde5c319..39b021f3 100644 --- a/plugins/vst/SfizzVstProcessor.cpp +++ b/plugins/vst/SfizzVstProcessor.cpp @@ -389,7 +389,7 @@ void SfizzVstProcessor::processControllerChanges(Vst::IParameterChanges& pc) auto ccNumber = static_cast(id - kPidCC0); for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) - synth.cc(sampleOffset, ccNumber, fastRound(value * 127.0)); + synth.hdcc(sampleOffset, ccNumber, value); } } break; From 15b6f1509307c3491f695336c5b8bdb635d54d96 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 20:31:53 +0100 Subject: [PATCH 236/668] Update .gitignore --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b9446b3c..5e36b900 100644 --- a/.gitignore +++ b/.gitignore @@ -19,9 +19,9 @@ compile_commands.json clients/sfizz_jack clients/sfzprint -/vst/download/ +/plugins/vst/download/ -/editor/external/fluentui-system-icons/ +/plugins/editor/external/fluentui-system-icons/ *.sublime-* *.code-* From f1d240b88b62344fab52d51e497fca5c5ced1ea4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 20:39:24 +0100 Subject: [PATCH 237/668] Make a common lib for plugins, move OSC there --- CMakeLists.txt | 17 +--------- plugins/CMakeLists.txt | 24 ++++++++++++++ plugins/common/plugin/MessageUtils.cpp | 39 ++++++++++++++++++++++ plugins/common/plugin/MessageUtils.h | 19 +++++++++++ plugins/editor/CMakeLists.txt | 3 +- plugins/editor/src/editor/Editor.cpp | 45 ++++---------------------- plugins/lv2/CMakeLists.txt | 4 +-- plugins/vst/CMakeLists.txt | 4 +-- 8 files changed, 95 insertions(+), 60 deletions(-) create mode 100644 plugins/CMakeLists.txt create mode 100644 plugins/common/plugin/MessageUtils.cpp create mode 100644 plugins/common/plugin/MessageUtils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 44d5ec51..f01465d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,22 +54,7 @@ add_subdirectory (src) # Optional targets add_subdirectory (clients) - -if ((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST) - add_subdirectory (plugins/editor) -endif() - -if (SFIZZ_LV2) - add_subdirectory (plugins/lv2) -endif() - -if (SFIZZ_VST) - add_subdirectory (plugins/vst) -else() - if (SFIZZ_AU) - message(WARNING "Audio Unit requires VST to be enabled") - endif() -endif() +add_subdirectory (plugins) if (SFIZZ_BENCHMARKS) add_subdirectory (benchmarks) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt new file mode 100644 index 00000000..a2105364 --- /dev/null +++ b/plugins/CMakeLists.txt @@ -0,0 +1,24 @@ +add_library(plugins-common STATIC EXCLUDE_FROM_ALL + "common/plugin/MessageUtils.h" + "common/plugin/MessageUtils.cpp") +target_include_directories(plugins-common PUBLIC "common") +target_link_libraries(plugins-common + PUBLIC sfizz::spin_mutex + PUBLIC absl::strings) +add_library(sfizz::plugins-common ALIAS plugins-common) + +if((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST) + add_subdirectory(editor) +endif() + +if(SFIZZ_LV2) + add_subdirectory(lv2) +endif() + +if(SFIZZ_VST) + add_subdirectory(vst) +else() + if(SFIZZ_AU) + message(WARNING "Audio Unit requires VST to be enabled") + endif() +endif() diff --git a/plugins/common/plugin/MessageUtils.cpp b/plugins/common/plugin/MessageUtils.cpp new file mode 100644 index 00000000..84e1b5f9 --- /dev/null +++ b/plugins/common/plugin/MessageUtils.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "MessageUtils.h" +#include +#include +#include + +namespace Messages { + +bool matchOSC(const char* pattern, const char* path, unsigned* indices) +{ + unsigned nthIndex = 0; + + while (const char *endp = std::strchr(pattern, '&')) { + size_t length = endp - pattern; + if (std::strncmp(pattern, path, length)) + return false; + pattern += length; + path += length; + + length = 0; + while (absl::ascii_isdigit(path[length])) + ++length; + + if (!absl::SimpleAtoi(absl::string_view(path, length), &indices[nthIndex++])) + return false; + + pattern += 1; + path += length; + } + + return !std::strcmp(path, pattern); +} + +} // namespace Messages diff --git a/plugins/common/plugin/MessageUtils.h b/plugins/common/plugin/MessageUtils.h new file mode 100644 index 00000000..0faf54a5 --- /dev/null +++ b/plugins/common/plugin/MessageUtils.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once + +namespace Messages { + +/** + * Simple matcher for message handling in O(N) + * @param[in] pattern Pattern to match, where '&' characters match positive integer numbers + * @param[in] path Path to match against the pattern + * @param[out] indices Table which received the indices, with size >= the number of '&' in the pattern + */ +bool matchOSC(const char* pattern, const char* path, unsigned* indices); + +} // namespace Messages diff --git a/plugins/editor/CMakeLists.txt b/plugins/editor/CMakeLists.txt index 379e7899..ee8b259d 100644 --- a/plugins/editor/CMakeLists.txt +++ b/plugins/editor/CMakeLists.txt @@ -43,9 +43,8 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/utility/vstgui_before.h) add_library(sfizz::editor ALIAS sfizz_editor) target_include_directories(sfizz_editor PUBLIC "src") -target_link_libraries(sfizz_editor PUBLIC sfizz::messaging) +target_link_libraries(sfizz_editor PUBLIC sfizz::messaging sfizz::plugins-common) target_link_libraries(sfizz_editor PRIVATE sfizz::vstgui) -target_link_libraries(sfizz_editor PUBLIC absl::strings) if(APPLE) find_library(APPLE_APPKIT_LIBRARY "AppKit") find_library(APPLE_CORESERVICES_LIBRARY "CoreServices") diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index a8a90650..0b5c6e5a 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -10,6 +10,7 @@ #include "GUIComponents.h" #include "GUIPiano.h" #include "NativeHelpers.h" +#include "plugin/MessageUtils.h" #include #include #include @@ -372,43 +373,11 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) } } -/// -static constexpr unsigned kMessageMaxIndices = 8; - -static bool matchMessage(const char* pattern, const char* path, unsigned* indices) -{ - unsigned nthIndex = 0; - - while (const char *endp = strchr(pattern, '&')) { - if (nthIndex == kMessageMaxIndices) - return false; - - size_t length = endp - pattern; - if (strncmp(pattern, path, length)) - return false; - pattern += length; - path += length; - - length = 0; - while (absl::ascii_isdigit(path[length])) - ++length; - - if (!absl::SimpleAtoi(absl::string_view(path, length), &indices[nthIndex++])) - return false; - - pattern += 1; - path += length; - } - - return !strcmp(path, pattern); -} - -/// void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) { - unsigned indices[kMessageMaxIndices]; + unsigned indices[8]; - if (!strcmp(path, "/cc/slots") && !strcmp(sig, "b")) { + if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) { const uint8_t* bitChunks = args[0].b->data; uint32_t byteSize = args[0].b->size; @@ -426,7 +395,7 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi } } } - else if (!strcmp(path, "/cc/changed") && !strcmp(sig, "b")) { + else if (Messages::matchOSC("/cc/changed", path, indices) && !strcmp(sig, "b")) { const uint8_t* bitChunks = args[0].b->data; uint32_t byteSize = args[0].b->size; for (unsigned cc = 0; cc < 8 * byteSize; ++cc) { @@ -438,13 +407,13 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi } } } - else if (matchMessage("/cc&/value", path, indices) && !strcmp(sig, "f")) { + else if (Messages::matchOSC("/cc&/value", path, indices) && !strcmp(sig, "f")) { updateCCValue(indices[0], args[0].f); } - else if (matchMessage("/cc&/default", path, indices) && !strcmp(sig, "f")) { + else if (Messages::matchOSC("/cc&/default", path, indices) && !strcmp(sig, "f")) { updateCCDefaultValue(indices[0], args[0].f); } - else if (matchMessage("/cc&/label", path, indices) && !strcmp(sig, "s")) { + else if (Messages::matchOSC("/cc&/label", path, indices) && !strcmp(sig, "s")) { updateCCLabel(indices[0], args[0].s); } else { diff --git a/plugins/lv2/CMakeLists.txt b/plugins/lv2/CMakeLists.txt index e6623c1f..ee07b3da 100644 --- a/plugins/lv2/CMakeLists.txt +++ b/plugins/lv2/CMakeLists.txt @@ -21,14 +21,14 @@ source_group("Turtle Files" FILES add_library(${LV2PLUGIN_PRJ_NAME} MODULE ${PROJECT_NAME}.cpp ${LV2PLUGIN_TTL_SRC_FILES}) -target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::spin_mutex) +target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::plugins-common) if(SFIZZ_LV2_UI) add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE ${PROJECT_NAME}_ui.cpp vstgui_helpers.h vstgui_helpers.cpp) - target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE sfizz::editor sfizz::vstgui) + target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE sfizz::editor sfizz::vstgui sfizz::plugins-common) endif() # Explicitely strip all symbols on Linux but lv2_descriptor() diff --git a/plugins/vst/CMakeLists.txt b/plugins/vst/CMakeLists.txt index 8f328512..a3cba79b 100644 --- a/plugins/vst/CMakeLists.txt +++ b/plugins/vst/CMakeLists.txt @@ -63,7 +63,7 @@ endif() target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz PRIVATE sfizz::editor - PRIVATE sfizz::spin_mutex + PRIVATE sfizz::plugins-common PRIVATE sfizz::pugixml sfizz::filesystem) target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") @@ -202,7 +202,7 @@ elseif(SFIZZ_AU) target_link_libraries(${AUPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} PRIVATE sfizz::editor - PRIVATE sfizz::spin_mutex + PRIVATE sfizz::plugins-common PRIVATE sfizz::pugixml sfizz::filesystem) target_include_directories(${AUPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") From 118f1236346833809767d8919d86780901bfe403 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Feb 2021 20:45:55 +0100 Subject: [PATCH 238/668] Use the enum value --- plugins/vst/SfizzVstEditor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/vst/SfizzVstEditor.cpp b/plugins/vst/SfizzVstEditor.cpp index 1d920dfa..d5788b48 100644 --- a/plugins/vst/SfizzVstEditor.cpp +++ b/plugins/vst/SfizzVstEditor.cpp @@ -313,14 +313,14 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) void SfizzVstEditor::uiBeginSend(EditId id) { Vst::ParamID pid = parameterOfEditId(id); - if (pid != -1) + if (pid != Vst::kNoParamId) getController()->beginEdit(pid); } void SfizzVstEditor::uiEndSend(EditId id) { Vst::ParamID pid = parameterOfEditId(id); - if (pid != -1) + if (pid != Vst::kNoParamId) getController()->endEdit(pid); } @@ -403,6 +403,6 @@ Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id) case EditId::ScalaRootKey: return kPidScalaRootKey; case EditId::TuningFrequency: return kPidTuningFrequency; case EditId::StretchTuning: return kPidStretchedTuning; - default: return -1; + default: return Vst::kNoParamId; } } From 6deb3d37d72449c7df42e15cf4ea80a4a21132e5 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Fri, 5 Feb 2021 00:39:07 +0100 Subject: [PATCH 239/668] Preliminary work for aftertouch handling - Add the aftertouch modulation source - Dispatch aftertouch events and track the aftertouch status in the midi state - Parse cutoff_chanaft - Convert aftertouch messages to an extended CC message --- clients/jack_client.cpp | 12 +-- common.mk | 1 + .../include/atomic_queue/atomic_queue.h | 4 +- plugins/lv2/sfizz.cpp | 5 + src/CMakeLists.txt | 4 +- src/sfizz/Config.h | 13 +++ src/sfizz/MidiState.cpp | 92 ++++++++++++------- src/sfizz/MidiState.h | 31 +++++++ src/sfizz/Region.cpp | 13 +++ src/sfizz/SfzHelpers.h | 1 + src/sfizz/Synth.cpp | 27 +++++- src/sfizz/SynthPrivate.h | 2 + src/sfizz/modulations/ModId.cpp | 2 + src/sfizz/modulations/ModId.h | 1 + src/sfizz/modulations/ModKey.cpp | 2 + src/sfizz/modulations/ModKey.h | 2 +- .../modulations/sources/ChannelAftertouch.cpp | 42 +++++++++ .../modulations/sources/ChannelAftertouch.h | 27 ++++++ tests/ModulationsT.cpp | 15 +++ 19 files changed, 249 insertions(+), 47 deletions(-) create mode 100644 src/sfizz/modulations/sources/ChannelAftertouch.cpp create mode 100644 src/sfizz/modulations/sources/ChannelAftertouch.h diff --git a/clients/jack_client.cpp b/clients/jack_client.cpp index 46fff6b2..ca610027 100644 --- a/clients/jack_client.cpp +++ b/clients/jack_client.cpp @@ -78,34 +78,30 @@ int process(jack_nframes_t numFrames, void* arg) switch (midi::status(event.buffer[0])) { case midi::noteOff: noteoff: - // DBG("[MIDI] Note " << +event.buffer[1] << " OFF at time " << event.time); synth->noteOff(event.time, event.buffer[1], event.buffer[2]); break; case midi::noteOn: if (event.buffer[2] == 0) goto noteoff; - // DBG("[MIDI] Note " << +event.buffer[1] << " ON at time " << event.time); synth->noteOn(event.time, event.buffer[1], event.buffer[2]); break; case midi::polyphonicPressure: - // DBG("[MIDI] Polyphonic pressure on at time " << event.time); + // Not implemented break; case midi::controlChange: - // DBG("[MIDI] CC " << +event.buffer[1] << " at time " << event.time); synth->cc(event.time, event.buffer[1], event.buffer[2]); break; case midi::programChange: - // DBG("[MIDI] Program change at time " << event.time); + // Not implemented break; case midi::channelPressure: - // DBG("[MIDI] Channel pressure at time " << event.time); + synth->aftertouch(event.time, event.buffer[1]); break; case midi::pitchBend: synth->pitchWheel(event.time, midi::buildAndCenterPitch(event.buffer[1], event.buffer[2])); - // DBG("[MIDI] Pitch bend at time " << event.time); break; case midi::systemMessage: - // DBG("[MIDI] System message at time " << event.time); + // Not implemented break; } } diff --git a/common.mk b/common.mk index 81d513df..06d9fc0d 100644 --- a/common.mk +++ b/common.mk @@ -57,6 +57,7 @@ SFIZZ_SOURCES = \ src/sfizz/modulations/ModKeyHash.cpp \ src/sfizz/modulations/ModMatrix.cpp \ src/sfizz/modulations/sources/ADSREnvelope.cpp \ + src/sfizz/modulations/sources/ChannelAftertouch.cpp \ src/sfizz/modulations/sources/Controller.cpp \ src/sfizz/modulations/sources/FlexEnvelope.cpp \ src/sfizz/modulations/sources/LFO.cpp \ diff --git a/external/atomic_queue/include/atomic_queue/atomic_queue.h b/external/atomic_queue/include/atomic_queue/atomic_queue.h index 1319f6f9..21dc029b 100644 --- a/external/atomic_queue/include/atomic_queue/atomic_queue.h +++ b/external/atomic_queue/include/atomic_queue/atomic_queue.h @@ -131,7 +131,7 @@ protected: // The special member functions are not thread-safe. - AtomicQueueCommon() noexcept = default; + AtomicQueueCommon() = default; AtomicQueueCommon(AtomicQueueCommon const& b) noexcept : head_(b.head_.load(X)) @@ -403,7 +403,7 @@ class AtomicQueue2 : public AtomicQueueCommonsynth, + (int)ev->time.frames, + msg[1]); + break; case LV2_MIDI_MSG_BENDER: sfizz_send_pitch_wheel(self->synth, (int)ev->time.frames, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d548788c..c82a21c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,7 @@ set(SFIZZ_HEADERS sfizz/modulations/ModMatrix.h sfizz/modulations/ModGenerator.h sfizz/modulations/sources/ADSREnvelope.h + sfizz/modulations/sources/ChannelAftertouch.h sfizz/modulations/sources/Controller.h sfizz/modulations/sources/FlexEnvelope.h sfizz/modulations/sources/LFO.h @@ -157,9 +158,10 @@ set(SFIZZ_SOURCES sfizz/modulations/ModKey.cpp sfizz/modulations/ModKeyHash.cpp sfizz/modulations/ModMatrix.cpp + sfizz/modulations/sources/ADSREnvelope.cpp + sfizz/modulations/sources/ChannelAftertouch.cpp sfizz/modulations/sources/Controller.cpp sfizz/modulations/sources/FlexEnvelope.cpp - sfizz/modulations/sources/ADSREnvelope.cpp sfizz/modulations/sources/LFO.cpp sfizz/effects/Nothing.cpp sfizz/effects/Filter.cpp diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 451a5bcc..aa344251 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -24,6 +24,19 @@ enum class Oversampling: int { x8 = 8 }; +enum ExtendedCCs { + pitchBend = 128, + channelAftertouch, + polyphonicAftertouch, + noteOnVelocity, + noteOffVelocity, + keyboardNoteNumber, + keyboardNoteGate, + unipolarRandom, + bipolarRandom, + alternate +}; + namespace config { constexpr float defaultSampleRate { 48000 }; constexpr float maxSampleRate { 192000 }; diff --git a/src/sfizz/MidiState.cpp b/src/sfizz/MidiState.cpp index 03e65a9e..1f6cc4b5 100644 --- a/src/sfizz/MidiState.cpp +++ b/src/sfizz/MidiState.cpp @@ -56,28 +56,33 @@ void sfz::MidiState::setSampleRate(float sampleRate) noexcept void sfz::MidiState::advanceTime(int numSamples) noexcept { + auto clearEvents = [] (EventVector& events) { + ASSERT(!events.empty()); // CC event vectors should never be empty + events.front().value = events.back().value; + events.front().delay = 0; + events.resize(1); + }; + internalClock += numSamples; - for (auto& ccEvents : cc) { - ASSERT(!ccEvents.empty()); // CC event vectors should never be empty - ccEvents.front().value = ccEvents.back().value; - ccEvents.front().delay = 0; - ccEvents.resize(1); - } - ASSERT(!pitchEvents.empty()); - pitchEvents.front().value = pitchEvents.back().value; - pitchEvents.front().delay = 0; - pitchEvents.resize(1); + for (auto& ccEvents : cc) + clearEvents(ccEvents); + + clearEvents(pitchEvents); + clearEvents(channelAftertouchEvents); } void sfz::MidiState::setSamplesPerBlock(int samplesPerBlock) noexcept { + auto updateEventBufferSize = [=] (EventVector& events) { + events.shrink_to_fit(); + events.reserve(samplesPerBlock); + }; this->samplesPerBlock = samplesPerBlock; - for (auto& ccEvents : cc) { - ccEvents.shrink_to_fit(); - ccEvents.reserve(samplesPerBlock); - } - pitchEvents.shrink_to_fit(); - pitchEvents.reserve(samplesPerBlock); + for (auto& ccEvents : cc) + updateEventBufferSize(ccEvents); + + updateEventBufferSize(pitchEvents); + updateEventBufferSize(channelAftertouchEvents); } float sfz::MidiState::getNoteDuration(int noteNumber, int delay) const @@ -100,15 +105,19 @@ float sfz::MidiState::getNoteVelocity(int noteNumber) const noexcept return lastNoteVelocities[noteNumber]; } +void sfz::MidiState::insertEventInVector(EventVector& events, int delay, float value) +{ + const auto insertionPoint = absl::c_upper_bound(events, delay, MidiEventDelayComparator {}); + if (insertionPoint == events.end() || insertionPoint->delay != delay) + events.insert(insertionPoint, { delay, value }); + else + insertionPoint->value = value; +} + void sfz::MidiState::pitchBendEvent(int delay, float pitchBendValue) noexcept { ASSERT(pitchBendValue >= -1.0f && pitchBendValue <= 1.0f); - - const auto insertionPoint = absl::c_upper_bound(pitchEvents, delay, MidiEventDelayComparator {}); - if (insertionPoint == pitchEvents.end() || insertionPoint->delay != delay) - pitchEvents.insert(insertionPoint, { delay, pitchBendValue }); - else - insertionPoint->value = pitchBendValue; + insertEventInVector(pitchEvents, delay, pitchBendValue); } float sfz::MidiState::getPitchBend() const noexcept @@ -117,20 +126,27 @@ float sfz::MidiState::getPitchBend() const noexcept return pitchEvents.back().value; } +void sfz::MidiState::channelAftertouchEvent(int delay, float aftertouch) noexcept +{ + ASSERT(aftertouch >= -1.0f && aftertouch <= 1.0f); + insertEventInVector(channelAftertouchEvents, delay, aftertouch); +} + +float sfz::MidiState::getChannelAftertouch() const noexcept +{ + ASSERT(channelAftertouchEvents.size() > 0); + return channelAftertouchEvents.back().value; +} + void sfz::MidiState::ccEvent(int delay, int ccNumber, float ccValue) noexcept { ASSERT(ccValue >= 0.0 && ccValue <= 1.0); - const auto insertionPoint = absl::c_upper_bound(cc[ccNumber], delay, MidiEventDelayComparator {}); - if (insertionPoint == cc[ccNumber].end() || insertionPoint->delay != delay) - cc[ccNumber].insert(insertionPoint, { delay, ccValue }); - else - insertionPoint->value = ccValue; + insertEventInVector(cc[ccNumber], delay, ccValue); } float sfz::MidiState::getCCValue(int ccNumber) const noexcept { ASSERT(ccNumber >= 0 && ccNumber < config::numCCs); - return cc[ccNumber].back().value; } @@ -139,13 +155,16 @@ void sfz::MidiState::reset() noexcept for (auto& velocity: lastNoteVelocities) velocity = 0; - for (auto& ccEvents : cc) { - ccEvents.clear(); - ccEvents.push_back({ 0, 0.0f }); - } + auto clearEvents = [] (EventVector& events) { + events.clear(); + events.push_back({ 0, 0.0f }); + }; - pitchEvents.clear(); - pitchEvents.push_back({ 0, 0.0f }); + for (auto& ccEvents : cc) + clearEvents(ccEvents); + + clearEvents(pitchEvents); + clearEvents(channelAftertouchEvents); activeNotes = 0; internalClock = 0; @@ -173,3 +192,8 @@ const sfz::EventVector& sfz::MidiState::getPitchEvents() const noexcept { return pitchEvents; } + +const sfz::EventVector& sfz::MidiState::getChannelAftertouchEvents() const noexcept +{ + return channelAftertouchEvents; +} diff --git a/src/sfizz/MidiState.h b/src/sfizz/MidiState.h index f4875510..bbdf58e1 100644 --- a/src/sfizz/MidiState.h +++ b/src/sfizz/MidiState.h @@ -98,6 +98,20 @@ public: */ float getPitchBend() const noexcept; + /** + * @brief Register a channel aftertouch event + * + * @param aftertouch + */ + void channelAftertouchEvent(int delay, float aftertouch) noexcept; + + /** + * @brief Get the channel aftertouch status + + * @return int + */ + float getChannelAftertouch() const noexcept; + /** * @brief Register a CC event * @@ -135,8 +149,19 @@ public: const EventVector& getCCEvents(int ccIdx) const noexcept; const EventVector& getPitchEvents() const noexcept; + const EventVector& getChannelAftertouchEvents() const noexcept; private: + + /** + * @brief Insert events in a sorted event vector. + * + * @param events + * @param delay + * @param value + */ + void insertEventInVector(EventVector& events, int delay, float value); + int activeNotes { 0 }; /** @@ -175,6 +200,12 @@ private: * @brief Pitch bend status */ EventVector pitchEvents; + + /** + * @brief Aftertouch status + */ + EventVector channelAftertouchEvents; + float sampleRate { config::defaultSampleRate }; int samplesPerBlock { config::defaultSamplesPerBlock }; unsigned internalClock { 0 }; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index fbbee939..a1defa97 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -652,6 +652,19 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) processGenericCc(opcode, Default::filterResonanceModRange, ModKey::createNXYZ(ModId::FilResonance, id, filterIndex)); } break; + case hash("cutoff&_chanaft"): + { + const auto filterIndex = opcode.parameters.front() - 1; + if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) + return false; + + if (auto value = readOpcode(opcode.value, Default::filterCutoffModRange)) { + const ModKey source = ModKey::createNXYZ(ModId::ChannelAftertouch); + const ModKey target = ModKey::createNXYZ(ModId::FilCutoff, id, filterIndex); + getOrCreateConnection(source, target).sourceDepth = *value; + } + } + break; case hash("fil&_keytrack"): // also fil_keytrack { const auto filterIndex = opcode.parameters.front() - 1; diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index b26f6560..ace6733c 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -54,6 +54,7 @@ struct MidiEvent { int delay; float value; }; + using EventVector = std::vector; struct MidiEventDelayComparator { diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b82cb372..242f6bba 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -63,6 +63,7 @@ Synth::Impl::Impl() genLFO_.reset(new LFOSource(voiceManager_)); genFlexEnvelope_.reset(new FlexEnvelopeSource(voiceManager_)); genADSREnvelope_.reset(new ADSREnvelopeSource(voiceManager_, resources_.midiState)); + genChannelAftertouch_.reset(new ChannelAftertouchSource(voiceManager_, resources_.midiState)); } Synth::Impl::~Impl() @@ -1214,11 +1215,26 @@ void Synth::pitchWheel(int delay, int pitch) noexcept voice.registerPitchWheel(delay, normalizedPitch); } } -void Synth::aftertouch(int /* delay */, uint8_t /* aftertouch */) noexcept + +void Synth::aftertouch(int delay, uint8_t aftertouch) noexcept { Impl& impl = *impl_; ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; + + const auto normalizedAftertouch = normalize7Bits(aftertouch); + impl.resources_.midiState.channelAftertouchEvent(delay, normalizedAftertouch); + impl.resources_.midiState.ccEvent(delay, ExtendedCCs::channelAftertouch, normalizedAftertouch); + + + for (auto& region : impl.regions_) { + region->registerAftertouch(aftertouch); + } + + for (auto& voice : impl.voiceManager_) { + voice.registerAftertouch(delay, aftertouch); + } } + void Synth::tempo(int delay, float secondsPerBeat) noexcept { Impl& impl = *impl_; @@ -1226,6 +1242,7 @@ void Synth::tempo(int delay, float secondsPerBeat) noexcept impl.resources_.beatClock.setTempo(delay, secondsPerBeat); } + void Synth::timeSignature(int delay, int beatsPerBar, int beatUnit) { Impl& impl = *impl_; @@ -1233,6 +1250,7 @@ void Synth::timeSignature(int delay, int beatsPerBar, int beatUnit) impl.resources_.beatClock.setTimeSignature(delay, TimeSignature(beatsPerBar, beatUnit)); } + void Synth::timePosition(int delay, int bar, double barBeat) { Impl& impl = *impl_; @@ -1240,6 +1258,7 @@ void Synth::timePosition(int delay, int bar, double barBeat) impl.resources_.beatClock.setTimePosition(delay, BBT(bar, barBeat)); } + void Synth::playbackState(int delay, int playbackState) { Impl& impl = *impl_; @@ -1253,16 +1272,19 @@ int Synth::getNumRegions() const noexcept Impl& impl = *impl_; return static_cast(impl.regions_.size()); } + int Synth::getNumGroups() const noexcept { Impl& impl = *impl_; return impl.numGroups_; } + int Synth::getNumMasters() const noexcept { Impl& impl = *impl_; return impl.numMasters_; } + int Synth::getNumCurves() const noexcept { Impl& impl = *impl_; @@ -1563,6 +1585,9 @@ void Synth::Impl::setupModMatrix() case ModId::FilEG: gen = genADSREnvelope_.get(); break; + case ModId::ChannelAftertouch: + gen = genChannelAftertouch_.get(); + break; default: DBG("[sfizz] Have unknown type of source generator"); break; diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 0e251024..185d6b11 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -8,6 +8,7 @@ #include "modulations/sources/ADSREnvelope.h" #include "modulations/sources/Controller.h" #include "modulations/sources/FlexEnvelope.h" +#include "modulations/sources/ChannelAftertouch.h" #include "modulations/sources/LFO.h" #include "utility/BitArray.h" @@ -265,6 +266,7 @@ struct Synth::Impl final: public Parser::Listener { std::unique_ptr genLFO_; std::unique_ptr genFlexEnvelope_; std::unique_ptr genADSREnvelope_; + std::unique_ptr genChannelAftertouch_; // Settings per voice struct { diff --git a/src/sfizz/modulations/ModId.cpp b/src/sfizz/modulations/ModId.cpp index 388da189..374b0887 100644 --- a/src/sfizz/modulations/ModId.cpp +++ b/src/sfizz/modulations/ModId.cpp @@ -36,6 +36,8 @@ int ModIds::flags(ModId id) noexcept return kModIsPerVoice; case ModId::FilEG: return kModIsPerVoice; + case ModId::ChannelAftertouch: + return kModIsPerCycle; // targets case ModId::MasterAmplitude: diff --git a/src/sfizz/modulations/ModId.h b/src/sfizz/modulations/ModId.h index f4c45965..055dacdc 100644 --- a/src/sfizz/modulations/ModId.h +++ b/src/sfizz/modulations/ModId.h @@ -26,6 +26,7 @@ enum class ModId : int { AmpEG, PitchEG, FilEG, + ChannelAftertouch, _SourcesEnd, diff --git a/src/sfizz/modulations/ModKey.cpp b/src/sfizz/modulations/ModKey.cpp index 474ca622..1cb95991 100644 --- a/src/sfizz/modulations/ModKey.cpp +++ b/src/sfizz/modulations/ModKey.cpp @@ -105,6 +105,8 @@ std::string ModKey::toString() const return absl::StrCat("PitchEG {", region_.number(), "}"); case ModId::FilEG: return absl::StrCat("FilterEG {", region_.number(), "}"); + case ModId::ChannelAftertouch: + return absl::StrCat("ChannelAftertouch"); case ModId::MasterAmplitude: return absl::StrCat("MasterAmplitude {", region_.number(), "}"); diff --git a/src/sfizz/modulations/ModKey.h b/src/sfizz/modulations/ModKey.h index 5653386f..9498ee39 100644 --- a/src/sfizz/modulations/ModKey.h +++ b/src/sfizz/modulations/ModKey.h @@ -29,7 +29,7 @@ public: : id_(id), region_(region), params_(params), flags_(ModIds::flags(id_)) {} static ModKey createCC(uint16_t cc, uint8_t curve, uint8_t smooth, float step); - static ModKey createNXYZ(ModId id, NumericId region, uint8_t N = 0, uint8_t X = 0, uint8_t Y = 0, uint8_t Z = 0); + static ModKey createNXYZ(ModId id, NumericId region = {}, uint8_t N = 0, uint8_t X = 0, uint8_t Y = 0, uint8_t Z = 0); explicit operator bool() const noexcept { return id_ != ModId(); } diff --git a/src/sfizz/modulations/sources/ChannelAftertouch.cpp b/src/sfizz/modulations/sources/ChannelAftertouch.cpp new file mode 100644 index 00000000..3bee93df --- /dev/null +++ b/src/sfizz/modulations/sources/ChannelAftertouch.cpp @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "ChannelAftertouch.h" +#include "../../ModifierHelpers.h" +#include "../../ADSREnvelope.h" + +// TODO(jpc): also matrix the ampeg + +namespace sfz { + +ChannelAftertouchSource::ChannelAftertouchSource(VoiceManager& manager, MidiState& state) + : voiceManager_(manager), midiState_(state) +{ +} + +void ChannelAftertouchSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) +{ + UNUSED(sourceKey); + UNUSED(voiceId); + UNUSED(delay); +} + +void ChannelAftertouchSource::release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) +{ + UNUSED(sourceKey); + UNUSED(voiceId); + UNUSED(delay); +} + +void ChannelAftertouchSource::generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) +{ + UNUSED(sourceKey); + UNUSED(voiceId); + const EventVector& events = midiState_.getChannelAftertouchEvents(); + linearEnvelope(events, buffer, [](float x) { return x; }); +} + +} // namespace sfz diff --git a/src/sfizz/modulations/sources/ChannelAftertouch.h b/src/sfizz/modulations/sources/ChannelAftertouch.h new file mode 100644 index 00000000..6ed9ac2c --- /dev/null +++ b/src/sfizz/modulations/sources/ChannelAftertouch.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "../ModGenerator.h" +#include "../../VoiceManager.h" +#include "../../MidiState.h" + +namespace sfz { +class Synth; + +class ChannelAftertouchSource : public ModGenerator { +public: + explicit ChannelAftertouchSource(VoiceManager &manager, MidiState& state); + void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; + void release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) override; + void generate(const ModKey& sourceKey, NumericId voiceId, absl::Span buffer) override; + +private: + VoiceManager& voiceManager_; + MidiState& midiState_; +}; + +} // namespace sfz diff --git a/tests/ModulationsT.cpp b/tests/ModulationsT.cpp index 0e1a863b..72c38cb6 100644 --- a/tests/ModulationsT.cpp +++ b/tests/ModulationsT.cpp @@ -339,3 +339,18 @@ TEST_CASE("[Modulations] Override the default pan controller") R"("Controller 7 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")", })); } + +TEST_CASE("[Modulations] Aftertouch connections") +{ + sfz::Synth synth; + synth.loadSfzString("/modulation.sfz", R"( + sample=*sine cutoff_chanaft=1000 + sample=*sine cutoff2_chanaft=1000 + )"); + + const std::string graph = synth.getResources().modMatrix.toDotGraph(); + REQUIRE(graph == createDefaultGraph({ + R"("ChannelAftertouch" -> "FilterCutoff {0, N=1}")", + R"("ChannelAftertouch" -> "FilterCutoff {1, N=2}")", + }, 2)); +} From d1d659bb42eb1e2c86ce81455c7c6cb440f8fda0 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 8 Feb 2021 12:20:10 +0100 Subject: [PATCH 240/668] Use the normal CC codepath, to also trigger notes --- src/sfizz/Synth.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 242f6bba..00ee4bee 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -1223,8 +1223,6 @@ void Synth::aftertouch(int delay, uint8_t aftertouch) noexcept const auto normalizedAftertouch = normalize7Bits(aftertouch); impl.resources_.midiState.channelAftertouchEvent(delay, normalizedAftertouch); - impl.resources_.midiState.ccEvent(delay, ExtendedCCs::channelAftertouch, normalizedAftertouch); - for (auto& region : impl.regions_) { region->registerAftertouch(aftertouch); @@ -1233,6 +1231,8 @@ void Synth::aftertouch(int delay, uint8_t aftertouch) noexcept for (auto& voice : impl.voiceManager_) { voice.registerAftertouch(delay, aftertouch); } + + impl.performHdcc(delay, ExtendedCCs::channelAftertouch, normalizedAftertouch, false); } void Synth::tempo(int delay, float secondsPerBeat) noexcept From 6b4f535d9c35da2a881502129ce8fb31e10ee80d Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 8 Feb 2021 17:46:07 +0100 Subject: [PATCH 241/668] Add tests for extended cc triggers on aftertouch --- tests/SynthT.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index b9bf7ab8..46a42651 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -1424,3 +1424,18 @@ TEST_CASE("[Synth] Send CC vs. Automate CC") REQUIRE(synth.getNumActiveVoices() == 1); } } + +TEST_CASE("[Keyswitches] Trigger from aftertouch extended CC") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/aftertouch_trigger.sfz", R"( + start_locc129=100 start_hicc129=127 sample=*saw + )"); + REQUIRE(synth.getNumActiveVoices() == 0); + synth.aftertouch(0, 90); + REQUIRE(synth.getNumActiveVoices() == 0); + synth.aftertouch(0, 110); + REQUIRE(synth.getNumActiveVoices() == 1); + synth.aftertouch(0, 120); + REQUIRE(synth.getNumActiveVoices() == 2); +} From b1f7a4bd660d2ce616996c61f38e39e2c7045a24 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 8 Nov 2020 10:26:45 +0100 Subject: [PATCH 242/668] Change the way the defaults and bounds for the opcodes are handled and read --- benchmarks/BM_opcodeSpec.cpp | 72 ++++ benchmarks/BM_opcodeSpec.h | 14 + benchmarks/BM_opcodeSpec_def.cpp | 3 + benchmarks/CMakeLists.txt | 1 + src/CMakeLists.txt | 1 + src/sfizz/Config.h | 4 + src/sfizz/Curve.cpp | 6 +- src/sfizz/Defaults.cpp | 143 ++++++++ src/sfizz/Defaults.h | 417 ++++++++++------------- src/sfizz/EGDescription.h | 44 +-- src/sfizz/EQDescription.h | 10 +- src/sfizz/EQPool.h | 6 +- src/sfizz/Effects.h | 5 +- src/sfizz/FilePool.h | 6 +- src/sfizz/FilterDescription.h | 14 +- src/sfizz/FilterPool.cpp | 4 +- src/sfizz/FilterPool.h | 8 +- src/sfizz/FlexEGDescription.h | 10 +- src/sfizz/LFODescription.h | 21 +- src/sfizz/Opcode.cpp | 235 +++++++------ src/sfizz/Opcode.h | 88 +---- src/sfizz/Region.cpp | 510 ++++++++++++++++------------- src/sfizz/Region.h | 116 +++---- src/sfizz/SfzHelpers.h | 9 +- src/sfizz/Smoothers.cpp | 6 +- src/sfizz/Smoothers.h | 5 - src/sfizz/Synth.cpp | 65 ++-- src/sfizz/SynthConfig.h | 4 +- src/sfizz/SynthMessaging.cpp | 71 +++- src/sfizz/SynthPrivate.h | 4 +- src/sfizz/Voice.cpp | 7 +- src/sfizz/effects/Apan.cpp | 12 +- src/sfizz/effects/Apan.h | 16 +- src/sfizz/effects/Compressor.cpp | 12 +- src/sfizz/effects/Disto.cpp | 27 +- src/sfizz/effects/Eq.cpp | 9 +- src/sfizz/effects/Filter.cpp | 9 +- src/sfizz/effects/Fverb.cpp | 29 +- src/sfizz/effects/Gain.cpp | 3 +- src/sfizz/effects/Gate.cpp | 8 +- src/sfizz/effects/Lofi.cpp | 6 +- src/sfizz/effects/Rectify.cpp | 3 +- src/sfizz/effects/Strings.cpp | 6 +- src/sfizz/effects/Strings.h | 4 +- src/sfizz/effects/Width.cpp | 3 +- tests/FilesT.cpp | 15 +- tests/OpcodeT.cpp | 328 ++++++++++++++----- tests/RegionValueComputationsT.cpp | 6 +- tests/RegionValuesT.cpp | 335 ++++++++++++------- tests/SynthT.cpp | 6 +- tests/TestFiles/note_offset.sfz | 12 - 51 files changed, 1623 insertions(+), 1135 deletions(-) create mode 100644 benchmarks/BM_opcodeSpec.cpp create mode 100644 benchmarks/BM_opcodeSpec.h create mode 100644 benchmarks/BM_opcodeSpec_def.cpp create mode 100644 src/sfizz/Defaults.cpp delete mode 100644 tests/TestFiles/note_offset.sfz diff --git a/benchmarks/BM_opcodeSpec.cpp b/benchmarks/BM_opcodeSpec.cpp new file mode 100644 index 00000000..da31a30a --- /dev/null +++ b/benchmarks/BM_opcodeSpec.cpp @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "BM_opcodeSpec.h" +#include +#include +#include +#include +#include +#include + +class OpcodeSpecFixture : public benchmark::Fixture { +public: + void SetUp(const ::benchmark::State& state) { + std::random_device rd { }; + std::mt19937 gen { rd() }; + std::uniform_real_distribution dist { 0.0f, 1.0f }; + value = dist(gen); + } + + void TearDown(const ::benchmark::State& /* state */) { + + } + + float value; + float returned; +}; + +BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstexprClamp)(benchmark::State& state) { + for (auto _ : state) + { + if (constexprSpec.flags | (1 << 2)) + returned = constexprSpec.bounds.clamp(value); + benchmark::DoNotOptimize(returned); + } +} + +BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstexprDontClamp)(benchmark::State& state) { + for (auto _ : state) + { + if (constexprSpec.flags | (1 << 1)) + returned = constexprSpec.bounds.clamp(value); + benchmark::DoNotOptimize(returned); + } +} + +BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstClamp)(benchmark::State& state) { + for (auto _ : state) + { + if (constSpec.flags | (1 << 2)) + returned = constSpec.bounds.clamp(value); + benchmark::DoNotOptimize(returned); + } +} + +BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstDontClamp)(benchmark::State& state) { + for (auto _ : state) + { + if (constSpec.flags | (1 << 1)) + returned = constSpec.bounds.clamp(value); + benchmark::DoNotOptimize(returned); + } +} + +BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstexprClamp); +BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstexprDontClamp); +BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstClamp); +BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstDontClamp); +BENCHMARK_MAIN(); diff --git a/benchmarks/BM_opcodeSpec.h b/benchmarks/BM_opcodeSpec.h new file mode 100644 index 00000000..8efcbe43 --- /dev/null +++ b/benchmarks/BM_opcodeSpec.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Range.h" + +template +struct OpcodeSpec +{ + T defaultValue; + sfz::Range bounds; + int flags { 0 }; +}; + +constexpr OpcodeSpec constexprSpec { 0.0f, sfz::Range(0.0f, 0.5f), 1 << 2 }; +extern const OpcodeSpec constSpec; diff --git a/benchmarks/BM_opcodeSpec_def.cpp b/benchmarks/BM_opcodeSpec_def.cpp new file mode 100644 index 00000000..076dd27d --- /dev/null +++ b/benchmarks/BM_opcodeSpec_def.cpp @@ -0,0 +1,3 @@ +#include "BM_opcodeSpec.h" + +const OpcodeSpec constSpec { 0.0f, sfz::Range(0.0f, 0.5f), 1 << 2 }; diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 89d7c8e3..77652c3e 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -38,6 +38,7 @@ sfizz_add_benchmark(bm_mapVsArray BM_mapVsArray.cpp) sfizz_add_benchmark(bm_random BM_random.cpp) sfizz_add_benchmark(bm_clamp BM_clamp.cpp) sfizz_add_benchmark(bm_allWithin BM_allWithin.cpp) +sfizz_add_benchmark(bm_opcodeSpec BM_opcodeSpec.cpp BM_opcodeSpec_def.cpp) sfizz_add_benchmark(bm_logger BM_logger.cpp) sfizz_add_benchmark(bm_smoothers BM_smoothers.cpp) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d548788c..d3c1f2bc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,6 +137,7 @@ set(SFIZZ_SOURCES sfizz/Wavetables.cpp sfizz/Tuning.cpp sfizz/RegionSet.cpp + sfizz/Defaults.cpp sfizz/PolyphonyGroup.cpp sfizz/VoiceManager.cpp sfizz/VoiceStealing.cpp diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 451a5bcc..faa06de3 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -150,6 +150,10 @@ namespace config { (int(polyphony * config::overflowVoiceMultiplier) < int(config::maxVoices)) ? int(polyphony * config::overflowVoiceMultiplier) : int(config::maxVoices); } + /** + * @brief The smoothing time constant per "smooth" steps + */ + constexpr float smoothTauPerStep { 3e-3 }; } // namespace config } // namespace sfz diff --git a/src/sfizz/Curve.cpp b/src/sfizz/Curve.cpp index 8d204a39..b4dcb93f 100644 --- a/src/sfizz/Curve.cpp +++ b/src/sfizz/Curve.cpp @@ -21,7 +21,7 @@ Curve Curve::buildCurveFromHeader( { Curve curve; bool fillStatus[NumValues] = {}; - const Range fullRange { -HUGE_VALF, +HUGE_VALF }; + const OpcodeSpec fullRange {0.0f, Range(-HUGE_VALF, +HUGE_VALF), 0 }; auto setPoint = [&curve, &fillStatus](int i, float x) { curve._points[i] = x; @@ -40,7 +40,7 @@ Curve Curve::buildCurveFromHeader( if (index >= NumValues) continue; - auto valueOpt = readOpcode(opc.value, fullRange); + auto valueOpt = opc.read(fullRange); if (!valueOpt) continue; @@ -268,7 +268,7 @@ void CurveSet::addCurveFromHeader(absl::Span members) Curve::Interpolator itp = Curve::Interpolator::Linear; if (const Opcode* opc = findOpcode(hash("curve_index"))) { - if (auto opt = readOpcode(opc->value, {0, 255})) + if (auto opt = opc->read(Default::curveCC)) curveIndex = *opt; else DBG("Invalid value for curve index: " << opc->value); diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp new file mode 100644 index 00000000..b7a77769 --- /dev/null +++ b/src/sfizz/Defaults.cpp @@ -0,0 +1,143 @@ +#include "Defaults.h" + +namespace sfz { + +namespace Default { +constexpr auto uint32_t_max = std::numeric_limits::max(); + +extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), kEnforceLowerBound }; +extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), kEnforceLowerBound }; +extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), kEnforceLowerBound }; +extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, uint32_t_max), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec sampleCount { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopRange { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec oscillatorPhase { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), kIgnoreOOB }; +extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), kIgnoreOOB }; +extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kEnforceLowerBound }; +extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), kEnforceLowerBound }; +extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), kIgnoreOOB }; +extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec polyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; +extern const OpcodeSpec notePolyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; +extern const OpcodeSpec key { 60, Range(0, 127), kIgnoreOOB | kCanBeNote }; +extern const OpcodeSpec midi7 { 0, Range(0, 127), kIgnoreOOB }; +extern const OpcodeSpec float7 { 0.0f , Range(0.0f, 127.0f), kIgnoreOOB }; +extern const OpcodeSpec bend { 0.0f, Range(-8192.0f, 8192.0f), kIgnoreOOB }; +extern const OpcodeSpec normalized { 0.0f, Range(0.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec bipolar { 0.0f, Range(-1.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec ccNumber { 0, Range(0, config::numCCs), kIgnoreOOB }; +extern const OpcodeSpec smoothCC { 0, Range(0, 100), kIgnoreOOB }; +extern const OpcodeSpec curveCC { 0, Range(0, 255), kIgnoreOOB }; +extern const OpcodeSpec sustainCC { 64, Range(0, 127), kIgnoreOOB }; +extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec bpm { 0.0f, Range(0.0f, 500.0f), kEnforceLowerBound }; +extern const OpcodeSpec sequence { 1, Range(1, 100), kIgnoreOOB }; +extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; +extern const OpcodeSpec volumeMod { 0.0f, Range(-144.0f, 48.0f), 0 }; +extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), 0 }; +extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), 0 }; +extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), 0 }; +extern const OpcodeSpec crossfadeIn { 0, Range(0, 127), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec crossfadeOut { 127, Range(0, 127), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), 0 }; +extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), kEnforceLowerBound }; +extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterGain { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec filterGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec filterRandom { 0.0f, Range(0.0f, 12000.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), kEnforceLowerBound }; +extern const OpcodeSpec filterVeltrack { 0, Range(-12000, 12000), 0 }; +extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), kEnforceLowerBound }; +extern const OpcodeSpec eqBandwidthMod { 0.0f, Range(-4.0f, 4.0f), 0 }; +extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 30000.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-30000.0f, 30000.0f), 0 }; +extern const OpcodeSpec eqGain { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec eqGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec eqVel2Frequency { 0.0f, Range(-30000.0f, 30000.0f), 0 }; +extern const OpcodeSpec eqVel2Gain { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec pitchKeytrack { 100, Range(-1200, 1200), 0 }; +extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), kEnforceLowerBound }; +extern const OpcodeSpec pitchVeltrack { 0, Range(-12000, 12000), 0 }; +extern const OpcodeSpec transpose { 0, Range(-127, 127), kIgnoreOOB }; +extern const OpcodeSpec pitch { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec pitchMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec bendUp { 200.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec bendDown { -200.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), kIgnoreOOB }; +extern const OpcodeSpec lfoFreq { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec lfoFreqMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec lfoBeats { 0.0f, Range(0.0f, 1000.0f), 0 }; +extern const OpcodeSpec lfoBeatsMod { 0.0f, Range(-1000.0f, 1000.0f), 0 }; +extern const OpcodeSpec lfoPhase { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec lfoDelay { 0.0f, Range(0.0f, 30.0f), 0 }; +extern const OpcodeSpec lfoFade { 0.0f, Range(0.0f, 30.0f), 0 }; +extern const OpcodeSpec lfoCount { 0, Range(0, 1000), 0 }; +extern const OpcodeSpec lfoSteps { 0, Range(0, static_cast(config::maxLFOSteps)), 0 }; +extern const OpcodeSpec lfoStepX { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec lfoWave { 0, Range(0, 15), 0 }; +extern const OpcodeSpec lfoOffset { 0.0f, Range(-1.0f, 1.0f), 0 }; +extern const OpcodeSpec lfoRatio { 1.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec lfoScale { 1.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec egTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egRelease { 0.001f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egTimeMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egPercentMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec egDepth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec egVel2Depth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), kIgnoreOOB }; +extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), kIgnoreOOB }; +extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec flexEGPointLevel { 0.0f, Range(-1.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec flexEGPointShape { 0.0f, Range(-100.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec sampleQuality { 1, Range(1, 10), kIgnoreOOB }; +extern const OpcodeSpec octaveOffset { 0, Range(-10, 10), 0 }; +extern const OpcodeSpec noteOffset { 0, Range(-127, 127), 0 }; +extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec apanWaveform { 0, Range(0, std::numeric_limits::max()), 0 }; +extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), kEnforceLowerBound }; +extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec apanLevel { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec distoTone { 100.0f, Range(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), kEnforceLowerBound }; +extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; +extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), kIgnoreOOB }; +extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec gateThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; +extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), kEnforceLowerBound }; +} // namespace Default + +} // namespace sfz diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 2ebca118..899094d1 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -38,253 +38,196 @@ enum class SfzSelfMask { mask, dontMask }; namespace sfz { + +enum OpcodeFlags : int { + kIgnoreOOB = 1, + kEnforceLowerBound = 1 << 1, + kEnforceUpperBound = 1 << 2, + kCanBeNote = 1 << 3, +}; + +template +struct OpcodeSpec +{ + T value; + Range bounds; + int flags; +}; + namespace Default { - // The categories match http://sfzformat.com/ - // ******* SFZ 1 ******* - // Sound source: sample playback - constexpr float delay { 0.0 }; - constexpr float delayRandom { 0.0 }; - constexpr Range delayRange { 0.0, 100.0 }; - constexpr int64_t offset { 0 }; - constexpr int64_t offsetRandom { 0 }; - constexpr Range offsetRange { 0, std::numeric_limits::max() }; - constexpr Range offsetCCRange = offsetRange; - constexpr Range sampleEndRange { 0, std::numeric_limits::max() }; - constexpr Range sampleCountRange { 0, std::numeric_limits::max() }; - constexpr SfzLoopMode loopMode { SfzLoopMode::no_loop }; - constexpr Range loopRange { 0, std::numeric_limits::max() }; - constexpr float loopCrossfade { 1e-3 }; - constexpr Range loopCrossfadeRange { loopCrossfade, 1.0 }; + extern const OpcodeSpec delay; + extern const OpcodeSpec delayRandom; + extern const OpcodeSpec offset; + extern const OpcodeSpec offsetMod; + extern const OpcodeSpec offsetRandom; + extern const OpcodeSpec sampleEnd; + extern const OpcodeSpec sampleCount; + extern const OpcodeSpec loopRange; + extern const OpcodeSpec loopCrossfade; + extern const OpcodeSpec oscillatorPhase; + extern const OpcodeSpec oscillatorMode; + extern const OpcodeSpec oscillatorMulti; + extern const OpcodeSpec oscillatorDetune; + extern const OpcodeSpec oscillatorDetuneMod; + extern const OpcodeSpec oscillatorModDepth; + extern const OpcodeSpec oscillatorModDepthMod; + extern const OpcodeSpec oscillatorQuality; + extern const OpcodeSpec group; + extern const OpcodeSpec offTime; + extern const OpcodeSpec polyphony; + extern const OpcodeSpec notePolyphony; + extern const OpcodeSpec key; + extern const OpcodeSpec midi7; + extern const OpcodeSpec float7; + extern const OpcodeSpec bend; + extern const OpcodeSpec normalized; + extern const OpcodeSpec bipolar; + extern const OpcodeSpec ccNumber; + extern const OpcodeSpec curveCC; + extern const OpcodeSpec smoothCC; + extern const OpcodeSpec sustainCC; + extern const OpcodeSpec sustainThreshold; + extern const OpcodeSpec bpm; + extern const OpcodeSpec sequence; + extern const OpcodeSpec volume; + extern const OpcodeSpec volumeMod; + extern const OpcodeSpec amplitude; + extern const OpcodeSpec amplitudeMod; + extern const OpcodeSpec pan; + extern const OpcodeSpec panMod; + extern const OpcodeSpec position; + extern const OpcodeSpec positionMod; + extern const OpcodeSpec width; + extern const OpcodeSpec widthMod; + extern const OpcodeSpec crossfadeIn; + extern const OpcodeSpec crossfadeInNorm; + extern const OpcodeSpec crossfadeOut; + extern const OpcodeSpec crossfadeOutNorm; + extern const OpcodeSpec ampKeytrack; + extern const OpcodeSpec ampVeltrack; + extern const OpcodeSpec ampVelcurve; + extern const OpcodeSpec ampRandom; + extern const OpcodeSpec rtDecay; + extern const OpcodeSpec filterCutoff; + extern const OpcodeSpec filterCutoffMod; + extern const OpcodeSpec filterResonance; + extern const OpcodeSpec filterResonanceMod; + extern const OpcodeSpec filterGain; + extern const OpcodeSpec filterGainMod; + extern const OpcodeSpec filterRandom; + extern const OpcodeSpec filterKeytrack; + extern const OpcodeSpec filterVeltrack; + extern const OpcodeSpec eqBandwidth; + extern const OpcodeSpec eqBandwidthMod; + extern const OpcodeSpec eqFrequency; + extern const OpcodeSpec eqFrequencyMod; + extern const OpcodeSpec eqGain; + extern const OpcodeSpec eqGainMod; + extern const OpcodeSpec eqVel2Frequency; + extern const OpcodeSpec eqVel2Gain; + extern const OpcodeSpec pitchKeytrack; + extern const OpcodeSpec pitchRandom; + extern const OpcodeSpec pitchVeltrack; + extern const OpcodeSpec transpose; + extern const OpcodeSpec pitch; + extern const OpcodeSpec pitchMod; + extern const OpcodeSpec bendUp; + extern const OpcodeSpec bendDown; + extern const OpcodeSpec bendStep; + extern const OpcodeSpec lfoFreq; + extern const OpcodeSpec lfoFreqMod; + extern const OpcodeSpec lfoBeats; + extern const OpcodeSpec lfoBeatsMod; + extern const OpcodeSpec lfoPhase; + extern const OpcodeSpec lfoDelay; + extern const OpcodeSpec lfoFade; + extern const OpcodeSpec lfoCount; + extern const OpcodeSpec lfoSteps; + extern const OpcodeSpec lfoStepX; + extern const OpcodeSpec lfoWave; + extern const OpcodeSpec lfoOffset; + extern const OpcodeSpec lfoRatio; + extern const OpcodeSpec lfoScale; + extern const OpcodeSpec egTime; + extern const OpcodeSpec egRelease; + extern const OpcodeSpec egTimeMod; + extern const OpcodeSpec egPercent; + extern const OpcodeSpec egPercentMod; + extern const OpcodeSpec egDepth; + extern const OpcodeSpec egVel2Depth; + extern const OpcodeSpec flexEGDynamic; + extern const OpcodeSpec flexEGSustain; + extern const OpcodeSpec flexEGPointTime; + extern const OpcodeSpec flexEGPointLevel; + extern const OpcodeSpec flexEGPointShape; + extern const OpcodeSpec sampleQuality; + extern const OpcodeSpec octaveOffset; + extern const OpcodeSpec noteOffset; + extern const OpcodeSpec effect; + extern const OpcodeSpec apanWaveform; + extern const OpcodeSpec apanFrequency; + extern const OpcodeSpec apanPhase; + extern const OpcodeSpec apanLevel; + extern const OpcodeSpec distoTone; + extern const OpcodeSpec distoDepth; + extern const OpcodeSpec distoStages; + extern const OpcodeSpec compAttack; + extern const OpcodeSpec compRelease; + extern const OpcodeSpec compThreshold; + extern const OpcodeSpec compRatio; + extern const OpcodeSpec compGain; + extern const OpcodeSpec fverbSize; + extern const OpcodeSpec fverbPredelay; + extern const OpcodeSpec fverbTone; + extern const OpcodeSpec fverbDamp; + extern const OpcodeSpec gateAttack; + extern const OpcodeSpec gateRelease; + extern const OpcodeSpec gateHold; + extern const OpcodeSpec gateThreshold; + extern const OpcodeSpec lofiBitred; + extern const OpcodeSpec lofiDecim; + extern const OpcodeSpec rectify; + extern const OpcodeSpec stringsNumber; - // common defaults - constexpr Range midi7Range { 0, 127 }; - constexpr Range float7Range { 0.0f, 127.0f }; - constexpr Range normalizedRange { 0.0f, 1.0f }; - constexpr Range symmetricNormalizedRange { -1.0, 1.0 }; + // Boolean default values + constexpr bool rtDead { false }; + constexpr bool checkSustain { true }; // sustain_sw + constexpr bool checkSostenuto { true }; // sostenuto_sw - // Wavetable oscillator - constexpr float oscillatorPhase { 0.0 }; - constexpr Range oscillatorPhaseRange { -1.0, 1.0 }; - constexpr int oscillatorMode { 0 }; - constexpr int oscillatorMulti { 1 }; - constexpr Range oscillatorModeRange { 0, 2 }; - constexpr Range oscillatorMultiRange { 1, config::oscillatorsPerVoice }; - constexpr float oscillatorDetune { 0 }; - constexpr Range oscillatorDetuneRange { -12000, 12000 }; - constexpr Range oscillatorDetuneCCRange { -12000, 12000 }; - constexpr float oscillatorModDepth { 0 }; - constexpr Range oscillatorModDepthRange { 0, 10000 }; // depth%, allowed to be >100 for FM - constexpr Range oscillatorModDepthCCRange { 0, 10000 }; - constexpr int oscillatorQuality { 1 }; - constexpr Range oscillatorQualityRange { 0, 3 }; + // Default/max count for objects + constexpr int numEQs { 3 }; + constexpr int numFilters { 2 }; + constexpr int numFlexEGs { 4 }; + constexpr int numFlexEGPoints { 8 }; + constexpr int numLFOs { 4 }; + constexpr int numLFOSubs { 2 }; + constexpr int numLFOSteps { 8 }; + constexpr int maxDistoStages { 4 }; + constexpr unsigned maxStrings { 88 }; - // Instrument setting: voice lifecycle - constexpr uint32_t group { 0 }; - constexpr Range groupRange { 0, std::numeric_limits::max() }; - constexpr SfzOffMode offMode { SfzOffMode::fast }; - constexpr float offTime { 6e-3f }; - constexpr Range polyphonyRange { 0, config::maxVoices }; + // Default values for enums + constexpr SfzTrigger trigger { SfzTrigger::attack }; + constexpr SfzOffMode offMode { SfzOffMode::fast }; + constexpr SfzVelocityOverride velocityOverride { SfzVelocityOverride::current }; constexpr SfzSelfMask selfMask { SfzSelfMask::mask }; + constexpr SfzCrossfadeCurve crossfadeKeyCurve { SfzCrossfadeCurve::power }; + constexpr SfzCrossfadeCurve crossfadeVelCurve { SfzCrossfadeCurve::power }; + constexpr SfzCrossfadeCurve crossfadeCCCurve { SfzCrossfadeCurve::power }; - // Region logic: key mapping - constexpr Range keyRange { 0, 127 }; - constexpr auto velocityRange = normalizedRange; - - // Region logic: MIDI conditions - constexpr Range channelRange { 1, 16 }; - constexpr Range midiChannelRange { 0, 15 }; - constexpr Range smoothCCRange { 0, 100 }; - constexpr float smoothTauPerStep { 3e-3 }; - constexpr Range curveCCRange { 0, 255 }; - constexpr Range ccNumberRange { 0, config::numCCs }; - constexpr auto ccValueRange = normalizedRange; - constexpr Range bendRange = { -8192, 8192 }; - constexpr Range bendValueRange = symmetricNormalizedRange; - constexpr int bend { 0 }; - constexpr SfzVelocityOverride velocityOverride { SfzVelocityOverride::current }; - - // Region logic: internal conditions - constexpr Range randRange { 0.0, 1.0 }; - constexpr Range aftertouchRange { 0, 127 }; - constexpr uint8_t aftertouch { 0 }; - constexpr Range bpmRange { 0.0, 500.0 }; - constexpr float bpm { 120.0 }; - constexpr uint8_t sequenceLength{ 1 }; - constexpr uint8_t sequencePosition{ 1 }; - constexpr Range sequenceRange { 1, 100 }; - - // Region logic: Triggers - constexpr SfzTrigger trigger { SfzTrigger::attack }; - constexpr Range ccTriggerValueRange = normalizedRange; - - // Performance parameters: amplifier - constexpr float globalVolume { -7.35f }; - constexpr float volume { 0.0f }; - constexpr Range volumeRange { -144.0, 48.0 }; - constexpr Range volumeCCRange { -144.0, 48.0 }; - constexpr float amplitude { 100.0 }; - constexpr Range amplitudeRange { 0.0, 1e8 }; - constexpr float pan { 0.0 }; - constexpr Range panRange { -100.0, 100.0 }; - constexpr Range panCCRange { -200.0, 200.0 }; - constexpr float position { 0.0 }; - constexpr Range positionRange { -100.0, 100.0 }; - constexpr Range positionCCRange { -200.0, 200.0 }; - constexpr float width { 100.0 }; - constexpr Range widthRange { -100.0, 100.0 }; - constexpr Range widthCCRange { -200.0, 200.0 }; - constexpr uint8_t ampKeycenter { 60 }; - constexpr float ampKeytrack { 0.0 }; - constexpr Range ampKeytrackRange { -96, 12 }; - constexpr float ampVeltrack { 100.0 }; - constexpr Range ampVeltrackRange { -100.0, 100.0 }; - constexpr Range ampVelcurveRange { 0.0, 1.0 }; - constexpr float ampRandom { 0.0 }; - constexpr Range ampRandomRange { 0.0, 24.0 }; - constexpr Range crossfadeKeyInRange { 0, 0 }; - constexpr Range crossfadeKeyOutRange { 127, 127 }; + // Default values for ranges + constexpr Range crossfadeKeyInRange { 0, 0 }; + constexpr Range crossfadeKeyOutRange { 127, 127 }; constexpr Range crossfadeVelInRange { 0.0f, 0.0f }; constexpr Range crossfadeVelOutRange { 1.0f, 1.0f }; constexpr Range crossfadeCCInRange { 0.0f, 0.0f }; constexpr Range crossfadeCCOutRange { 1.0f, 1.0f }; - constexpr SfzCrossfadeCurve crossfadeKeyCurve { SfzCrossfadeCurve::power }; - constexpr SfzCrossfadeCurve crossfadeVelCurve { SfzCrossfadeCurve::power }; - constexpr SfzCrossfadeCurve crossfadeCCCurve { SfzCrossfadeCurve::power }; - constexpr float rtDecay { 0.0f }; - constexpr bool rtDead { false }; - constexpr Range rtDecayRange { 0.0f, 200.0f }; - // Performance parameters: Filters - constexpr int numFilters { 2 }; - constexpr float filterCutoff { 0 }; - constexpr float filterResonance { 0 }; - constexpr float filterGain { 0 }; - constexpr int filterKeytrack { 0 }; - constexpr uint8_t filterKeycenter { 60 }; - constexpr float filterRandom { 0 }; - constexpr int filterVeltrack { 0 }; - constexpr float filterCutoffCC { 0 }; - constexpr float filterResonanceCC { 0 }; - constexpr float filterGainCC { 0 }; - constexpr Range filterCutoffRange { 0.0f, 20000.0f }; - constexpr Range filterCutoffModRange { -12000, 12000 }; - constexpr Range filterGainRange { -96.0f, 96.0f }; - constexpr Range filterGainModRange { -96.0f, 96.0f }; - constexpr Range filterKeytrackRange { 0, 1200 }; - constexpr Range filterRandomRange { 0, 12000 }; - constexpr Range filterVeltrackRange { -12000, 12000 }; - constexpr Range filterResonanceRange { 0.0f, 96.0f }; - constexpr Range filterResonanceModRange { 0.0f, 96.0f }; + // Various defaut values + // e.g. "additional" or multiple defautl values + constexpr int freewheelingQuality { 10 }; + constexpr float globalVolume { -7.35f }; + constexpr float defaultEQFreq [numEQs] { 50.0f, 500.0f, 5000.0f }; +} // namespace Default - // Performance parameters: EQ - constexpr int numEQs { 3 }; - constexpr float eqBandwidth { 1.0f }; - constexpr float eqBandwidthCC { 0.0f }; - constexpr float eqFrequencyUnset { 0.0f }; - constexpr float eqFrequency1 { 50.0f }; - constexpr float eqFrequency2 { 500.0f }; - constexpr float eqFrequency3 { 5000.0f }; - constexpr float eqFrequencyCC { 0.0f }; - constexpr float eqGain { 0.0f }; - constexpr float eqGainCC { 0.0f }; - constexpr float eqVel2frequency { 0.0f }; - constexpr float eqVel2gain { 0.0f }; - constexpr Range eqBandwidthRange { 0.001f, 4.0f }; - constexpr Range eqBandwidthModRange { -4.0f, 4.0f }; - constexpr Range eqFrequencyRange { 0.0f, 30000.0f }; - constexpr Range eqFrequencyModRange { -30000.0f, 30000.0f }; - constexpr Range eqGainRange { -96.0f, 96.0f }; - constexpr Range eqGainModRange { -96.0f, 96.0f }; - - // Performance parameters: pitch - constexpr uint8_t pitchKeycenter { 60 }; - constexpr int pitchKeytrack { 100 }; - constexpr Range pitchKeytrackRange { -1200, 1200 }; - constexpr float pitchRandom { 0 }; - constexpr Range pitchRandomRange { 0, 12000 }; - constexpr int pitchVeltrack { 0 }; - constexpr Range pitchVeltrackRange { -12000, 12000 }; - constexpr int transpose { 0 }; - constexpr Range transposeRange { -127, 127 }; - constexpr float tune { 0 }; - constexpr Range tuneRange { -12000, 12000 }; // ±100 in SFZv1, more in ARIA - constexpr Range tuneCCRange { -12000, 12000 }; - constexpr Range bendBoundRange { -12000, 12000 }; - constexpr Range bendStepRange { 1, 1200 }; - constexpr int bendUp { 200 }; // No range here because the bounds can be inverted - constexpr int bendDown { -200 }; - constexpr int bendStep { 1 }; - constexpr uint8_t bendSmooth { 0 }; - - // Modulation: LFO - constexpr int numLFOs { 4 }; - constexpr int numLFOSubs { 2 }; - constexpr int numLFOSteps { 8 }; - constexpr Range lfoFreqRange { 0.0, 100.0 }; - constexpr Range lfoFreqModRange { -100.0, 100.0 }; - constexpr Range lfoBeatsRange { 0.0, 1000.0 }; - constexpr Range lfoBeatsModRange { -1000.0, 1000.0 }; - constexpr Range lfoPhaseRange { 0.0, 1.0 }; - constexpr Range lfoDelayRange { 0.0, 30.0 }; - constexpr Range lfoFadeRange { 0.0, 30.0 }; - constexpr Range lfoCountRange { 0, 1000 }; - constexpr Range lfoStepsRange { 0, static_cast(config::maxLFOSteps) }; - constexpr Range lfoStepXRange { -100.0, 100.0 }; - constexpr Range lfoWaveRange { 0, 15 }; - constexpr Range lfoOffsetRange { -1.0, 1.0 }; - constexpr Range lfoRatioRange { 0.0, 100.0 }; - constexpr Range lfoScaleRange { 0.0, 1.0 }; - - // Envelope generators - constexpr float attack { 0 }; - constexpr float decay { 0 }; - constexpr float delayEG { 0 }; - constexpr float hold { 0 }; - constexpr float release { 0 }; - constexpr float ampegRelease { 0.001 }; // Default release to avoid clicks - constexpr float vel2release { 0.0f }; - constexpr float start { 0.0 }; - constexpr float sustain { 100.0 }; - constexpr uint16_t sustainCC { 64 }; - constexpr float sustainThreshold { 0.0039f }; // sforzando default (0.5f/127.0f) - constexpr float vel2sustain { 0.0 }; - constexpr int depth { 0 }; - constexpr Range egTimeRange { 0.0, 100.0 }; - constexpr Range egPercentRange { 0.0, 100.0 }; - constexpr Range egDepthRange { -12000, 12000 }; - constexpr Range egOnCCTimeRange { -100.0, 100.0 }; - constexpr Range egOnCCPercentRange { -100.0, 100.0 }; - constexpr Range pitchEgDepthRange { -12000.0, 12000.0 }; - constexpr Range filterEgDepthRange { -12000.0, 12000.0 }; - - // Flex envelope generators - constexpr int numFlexEGs { 4 }; - constexpr int numFlexEGPoints { 8 }; - constexpr int flexEGDynamic { 0 }; - constexpr int flexEGSustain { 0 }; - constexpr float flexEGPointTime { 0 }; - constexpr float flexEGPointLevel { 0 }; - constexpr float flexEGPointShape { 0 }; - constexpr Range flexEGDynamicRange { 0, 1 }; - constexpr Range flexEGSustainRange { 0, 100 }; - constexpr Range flexEGPointTimeRange { 0.0f, 100.0f }; - constexpr Range flexEGPointLevelRange { -1.0f, 1.0f }; - constexpr Range flexEGPointShapeRange { -100.0f, 100.0f }; - - // ***** SFZ v2 ******** - constexpr int sampleQuality { 1 }; - constexpr int sampleQualityInFreewheelingMode { 10 }; // for future use, possibly excessive - constexpr Range sampleQualityRange { 1, 10 }; // sample_quality - - constexpr bool checkSustain { true }; // sustain_sw - constexpr bool checkSostenuto { true }; // sostenuto_sw - constexpr Range octaveOffsetRange { -10, 10 }; // octave_offset - constexpr Range noteOffsetRange { -127, 127 }; // note_offset - - constexpr Range apanWaveformRange { 0, std::numeric_limits::max() }; - constexpr Range apanFrequencyRange { 0, std::numeric_limits::max() }; - constexpr Range apanPhaseRange { 0.0, 1.0 }; - constexpr Range apanLevelRange { 0.0, 100.0 }; -} -} +} // namespace sfz diff --git a/src/sfizz/EGDescription.h b/src/sfizz/EGDescription.h index 5cfe0d94..89edfde2 100644 --- a/src/sfizz/EGDescription.h +++ b/src/sfizz/EGDescription.h @@ -66,21 +66,21 @@ struct EGDescription { EGDescription& operator=(const EGDescription&) = default; EGDescription& operator=(EGDescription&&) = default; - float attack { Default::attack }; - float decay { Default::decay }; - float delay { Default::delayEG }; - float hold { Default::hold }; - float release { Default::release }; - float start { Default::start }; - float sustain { Default::sustain }; - int depth { Default::depth }; - float vel2attack { Default::attack }; - float vel2decay { Default::decay }; - float vel2delay { Default::delayEG }; - float vel2hold { Default::hold }; - float vel2release { Default::vel2release }; - float vel2sustain { Default::vel2sustain }; - int vel2depth { Default::depth }; + float attack { Default::egTime.value }; + float decay { Default::egTime.value }; + float delay { Default::egTime.value }; + float hold { Default::egTime.value }; + float release { Default::egTime.value }; + float start { Default::egPercent.bounds.getStart() }; + float sustain { Default::egPercent.bounds.getEnd() }; + float depth { Default::egDepth.value }; + float vel2attack { Default::egTimeMod.value }; + float vel2decay { Default::egTimeMod.value }; + float vel2delay { Default::egTimeMod.value }; + float vel2hold { Default::egTimeMod.value }; + float vel2release { Default::egPercentMod.value }; + float vel2sustain { Default::egPercentMod.value }; + float vel2depth { Default::egVel2Depth.value }; CCMap ccAttack; CCMap ccDecay; @@ -104,7 +104,7 @@ struct EGDescription { for (auto& mod: ccAttack) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the decay with possibly a CC modifier and a velocity modifier @@ -120,7 +120,7 @@ struct EGDescription { for (auto& mod: ccDecay) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the delay with possibly a CC modifier and a velocity modifier @@ -136,7 +136,7 @@ struct EGDescription { for (auto& mod: ccDelay) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the holding duration with possibly a CC modifier and a velocity modifier @@ -152,7 +152,7 @@ struct EGDescription { for (auto& mod: ccHold) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the release duration with possibly a CC modifier and a velocity modifier @@ -168,7 +168,7 @@ struct EGDescription { for (auto& mod: ccRelease) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the starting level with possibly a CC modifier and a velocity modifier @@ -184,7 +184,7 @@ struct EGDescription { for (auto& mod: ccStart) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egPercentRange.clamp(returnedValue); + return Default::egPercent.bounds.clamp(returnedValue); } /** * @brief Get the sustain level with possibly a CC modifier and a velocity modifier @@ -200,7 +200,7 @@ struct EGDescription { for (auto& mod: ccSustain) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egPercentRange.clamp(returnedValue); + return Default::egPercent.bounds.clamp(returnedValue); } LEAK_DETECTOR(EGDescription); }; diff --git a/src/sfizz/EQDescription.h b/src/sfizz/EQDescription.h index c109a4a0..246d545b 100644 --- a/src/sfizz/EQDescription.h +++ b/src/sfizz/EQDescription.h @@ -14,11 +14,11 @@ namespace sfz { struct EQDescription { - float bandwidth { Default::eqBandwidth }; - float frequency { Default::eqFrequencyUnset }; - float gain { Default::eqGain }; - float vel2frequency { Default::eqVel2frequency }; - float vel2gain { Default::eqVel2gain }; + float bandwidth { Default::eqBandwidth.value }; + float frequency { Default::eqFrequency.value }; + float gain { Default::eqGain.value }; + float vel2frequency { Default::eqVel2Frequency.value }; + float vel2gain { Default::eqVel2Gain.value }; EqType type { EqType::kEqPeak }; }; } diff --git a/src/sfizz/EQPool.h b/src/sfizz/EQPool.h index 4670daac..63ba5dde 100644 --- a/src/sfizz/EQPool.h +++ b/src/sfizz/EQPool.h @@ -43,9 +43,9 @@ private: Resources& resources; const EQDescription* description; std::unique_ptr eq; - float baseBandwidth { Default::eqBandwidth }; - float baseFrequency { Default::eqFrequency1 }; - float baseGain { Default::eqGain }; + float baseBandwidth { Default::eqBandwidth.value }; + float baseFrequency { Default::eqFrequency.value }; + float baseGain { Default::eqGain.value }; bool prepared { false }; ModMatrix::TargetId gainTarget; ModMatrix::TargetId frequencyTarget; diff --git a/src/sfizz/Effects.h b/src/sfizz/Effects.h index 2056cac2..838557a8 100644 --- a/src/sfizz/Effects.h +++ b/src/sfizz/Effects.h @@ -6,6 +6,7 @@ #pragma once #include "AudioBuffer.h" +#include "Defaults.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include @@ -178,8 +179,8 @@ private: std::vector> _effects; AudioBuffer _inputs { EffectChannels, config::defaultSamplesPerBlock }; AudioBuffer _outputs { EffectChannels, config::defaultSamplesPerBlock }; - float _gainToMain = 0.0; - float _gainToMix = 0.0; + float _gainToMain { Default::effect.value }; + float _gainToMix { Default::effect.value }; }; } // namespace sfz diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index fa67db72..2c77f6d9 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -51,10 +51,10 @@ using FileAudioBuffer = AudioBuffer; struct FileInformation { - uint32_t end { Default::sampleEndRange.getEnd() }; + uint32_t end { Default::sampleEnd.value }; uint32_t maxOffset { 0 }; - uint32_t loopBegin { Default::loopRange.getStart() }; - uint32_t loopEnd { Default::loopRange.getEnd() }; + uint32_t loopBegin { Default::loopRange.bounds.getStart() }; + uint32_t loopEnd { Default::loopRange.bounds.getEnd() }; bool hasLoop { false }; double sampleRate { config::defaultSampleRate }; int numChannels { 0 }; diff --git a/src/sfizz/FilterDescription.h b/src/sfizz/FilterDescription.h index 2f3193a0..7bdc39b6 100644 --- a/src/sfizz/FilterDescription.h +++ b/src/sfizz/FilterDescription.h @@ -14,13 +14,13 @@ namespace sfz { struct FilterDescription { - float cutoff { Default::filterCutoff }; - float resonance { Default::filterCutoff }; - float gain { Default::filterGain }; - int keytrack { Default::filterKeytrack }; - uint8_t keycenter { Default::filterKeycenter }; - int veltrack { Default::filterVeltrack }; - float random { Default::filterRandom }; + float cutoff { Default::filterCutoff.value }; + float resonance { Default::filterCutoff.value }; + float gain { Default::filterGain.value }; + int keytrack { Default::filterKeytrack.value }; + uint8_t keycenter { Default::key.value }; + int veltrack { Default::filterVeltrack.value }; + float random { Default::filterRandom.value }; FilterType type { FilterType::kFilterLpf2p }; }; } diff --git a/src/sfizz/FilterPool.cpp b/src/sfizz/FilterPool.cpp index d8c16e40..46b38d41 100644 --- a/src/sfizz/FilterPool.cpp +++ b/src/sfizz/FilterPool.cpp @@ -37,7 +37,7 @@ void sfz::FilterHolder::setup(const Region& region, unsigned filterId, int noteN baseCutoff *= centsFactor(keytrack); const auto veltrack = static_cast(description->veltrack) * velocity; baseCutoff *= centsFactor(veltrack); - baseCutoff = Default::filterCutoffRange.clamp(baseCutoff); + baseCutoff = Default::filterCutoff.bounds.clamp(baseCutoff); baseGain = description->gain; baseResonance = description->resonance; @@ -75,7 +75,7 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned for (size_t i = 0; i < numFrames; ++i) (*cutoffSpan)[i] *= centsFactor(mod[i]); } - sfz::clampAll(*cutoffSpan, Default::filterCutoffRange); + sfz::clampAll(*cutoffSpan, Default::filterCutoff.bounds); fill(*resonanceSpan, baseResonance); if (float* mod = mm.getModulation(resonanceTarget)) diff --git a/src/sfizz/FilterPool.h b/src/sfizz/FilterPool.h index d995e0db..13ecbb94 100644 --- a/src/sfizz/FilterPool.h +++ b/src/sfizz/FilterPool.h @@ -22,7 +22,7 @@ public: * @param noteNumber the triggering note number * @param velocity the triggering note velocity/value */ - void setup(const Region& region, unsigned filterId, int noteNumber = static_cast(Default::filterKeycenter), float velocity = 0); + void setup(const Region& region, unsigned filterId, int noteNumber = static_cast(Default::key.value), float velocity = 0); /** * @brief Process a block of stereo inputs * @@ -45,9 +45,9 @@ private: Resources& resources; const FilterDescription* description; std::unique_ptr filter; - float baseCutoff { Default::filterCutoff }; - float baseResonance { Default::filterResonance }; - float baseGain { Default::filterGain }; + float baseCutoff { Default::filterCutoff.value }; + float baseResonance { Default::filterResonance.value }; + float baseGain { Default::filterGain.value }; ModMatrix::TargetId gainTarget; ModMatrix::TargetId cutoffTarget; ModMatrix::TargetId resonanceTarget; diff --git a/src/sfizz/FlexEGDescription.h b/src/sfizz/FlexEGDescription.h index b8a0f59b..84d9078c 100644 --- a/src/sfizz/FlexEGDescription.h +++ b/src/sfizz/FlexEGDescription.h @@ -18,21 +18,21 @@ namespace FlexEGs { }; struct FlexEGPoint { - float time { Default::flexEGPointTime }; // duration until next step (s) - float level { Default::flexEGPointLevel }; // normalized amplitude + float time { Default::flexEGPointTime.value }; // duration until next step (s) + float level { Default::flexEGPointLevel.value }; // normalized amplitude void setShape(float shape); float shape() const noexcept { return shape_; } const Curve& curve() const; private: - float shape_ { Default::flexEGPointShape }; // 0: linear, positive: exp, negative: log + float shape_ { Default::flexEGPointShape.value }; // 0: linear, positive: exp, negative: log std::shared_ptr shapeCurve_; }; struct FlexEGDescription { - int dynamic { Default::flexEGDynamic }; // whether parameters can be modulated while EG runs - int sustain { Default::flexEGSustain }; // index of the sustain point (default to 0 in ARIA) + int dynamic { Default::flexEGDynamic.value }; // whether parameters can be modulated while EG runs + int sustain { Default::flexEGSustain.value }; // index of the sustain point (default to 0 in ARIA) std::vector points; // ARIA bool ampeg = false; // replaces the SFZv1 AmpEG (lowest with this bit wins) diff --git a/src/sfizz/LFODescription.h b/src/sfizz/LFODescription.h index 2628430f..ea312bca 100644 --- a/src/sfizz/LFODescription.h +++ b/src/sfizz/LFODescription.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "Defaults.h" #include #include @@ -27,17 +28,17 @@ struct LFODescription { LFODescription(); ~LFODescription(); static const LFODescription& getDefault(); - float freq = 0; // lfoN_freq - float beats = 0; // lfoN_beats - float phase0 = 0; // lfoN_phase - float delay = 0; // lfoN_delay - float fade = 0; // lfoN_fade - unsigned count = 0; // lfoN_count + float freq { Default::lfoFreq.value }; // lfoN_freq + float beats { Default::lfoBeats.value }; // lfoN_beats + float phase0 { Default::lfoPhase.value }; // lfoN_phase + float delay { Default::lfoDelay.value }; // lfoN_delay + float fade { Default::lfoFade.value }; // lfoN_fade + unsigned count { Default::lfoCount.value }; // lfoN_count struct Sub { - LFOWave wave = LFOWave::Triangle; // lfoN_wave[X] - float offset = 0; // lfoN_offset[X] - float ratio = 1; // lfoN_ratio[X] - float scale = 1; // lfoN_scale[X] + LFOWave wave { static_cast(Default::lfoWave.value) }; // lfoN_wave[X] + float offset { Default::lfoOffset.value }; // lfoN_offset[X] + float ratio { Default::lfoRatio.value }; // lfoN_ratio[X] + float scale { Default::lfoScale.value }; // lfoN_scale[X] }; struct StepSequence { std::vector steps {}; // lfoN_stepX - normalized to unity diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 1a60ff78..87f2e109 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -117,6 +117,116 @@ OpcodeCategory Opcode::identifyCategory(absl::string_view name) return category; } +template +absl::optional readInt_(OpcodeSpec spec, absl::string_view v) +{ + size_t numberEnd = 0; + + if (numberEnd < v.size() && (v[numberEnd] == '+' || v[numberEnd] == '-')) + ++numberEnd; + + while (numberEnd < v.size() && absl::ascii_isdigit(v[numberEnd])) + ++numberEnd; + + if (numberEnd == 0 && (spec.flags & kCanBeNote)) + return readNoteValue(v); + + v = v.substr(0, numberEnd); + + int64_t returnedValue; + if (!absl::SimpleAtoi(v, &returnedValue)) + return absl::nullopt; + + if (returnedValue > static_cast(spec.bounds.getEnd())) { + if (spec.flags & kEnforceUpperBound) + return spec.bounds.getEnd(); + + if (spec.flags & kIgnoreOOB) + return {}; + } + + if (returnedValue < static_cast(spec.bounds.getStart())) { + if (spec.flags & kEnforceLowerBound) + return spec.bounds.getStart(); + + if (spec.flags & kIgnoreOOB) + return {}; + } + + T castValue = static_cast(returnedValue); + if ((castValue != returnedValue) & kIgnoreOOB) + return {}; + + return castValue; +} + +#define INSTANTIATE_FOR_INTEGRAL(T) \ + template <> \ + absl::optional Opcode::read(OpcodeSpec spec) const \ + { \ + return readInt_(spec, value); \ + } + +INSTANTIATE_FOR_INTEGRAL(uint8_t) +INSTANTIATE_FOR_INTEGRAL(uint16_t) +INSTANTIATE_FOR_INTEGRAL(uint32_t) +INSTANTIATE_FOR_INTEGRAL(int8_t) +INSTANTIATE_FOR_INTEGRAL(int16_t) +INSTANTIATE_FOR_INTEGRAL(int32_t) +INSTANTIATE_FOR_INTEGRAL(int64_t) + + +template +absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) +{ + size_t numberEnd = 0; + + if (numberEnd < v.size() && (v[numberEnd] == '+' || v[numberEnd] == '-')) + ++numberEnd; + while (numberEnd < v.size() && absl::ascii_isdigit(v[numberEnd])) + ++numberEnd; + + if (numberEnd < v.size() && v[numberEnd] == '.') { + ++numberEnd; + while (numberEnd < v.size() && absl::ascii_isdigit(v[numberEnd])) + ++numberEnd; + } + + v = v.substr(0, numberEnd); + + float returnedValue; + if (!absl::SimpleAtof(v, &returnedValue)) + return absl::nullopt; + + if (returnedValue > static_cast(spec.bounds.getEnd())) { + if (spec.flags & kEnforceUpperBound) + return spec.bounds.getEnd(); + + if (spec.flags & kIgnoreOOB) + return {}; + } + + if (returnedValue < static_cast(spec.bounds.getStart())) { + if (spec.flags & kEnforceLowerBound) + return spec.bounds.getStart(); + + if (spec.flags & kIgnoreOOB) + return {}; + } + + return returnedValue; +} + +#define INSTANTIATE_FOR_FLOATING_POINT(T) \ + template <> \ + absl::optional Opcode::read(OpcodeSpec spec) const \ + { \ + return readFloat_(spec, value); \ + } + +INSTANTIATE_FOR_FLOATING_POINT(float) +INSTANTIATE_FOR_FLOATING_POINT(double) + absl::optional readNoteValue(absl::string_view value) { char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front()); @@ -167,56 +277,6 @@ absl::optional readNoteValue(absl::string_view value) return static_cast(noteNumber); } -/// -template ::value, int>> -absl::optional readOpcode(absl::string_view value, const Range& validRange) -{ - size_t numberEnd = 0; - - if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-')) - ++numberEnd; - while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) - ++numberEnd; - - value = value.substr(0, numberEnd); - - int64_t returnedValue; - if (!absl::SimpleAtoi(value, &returnedValue)) - return absl::nullopt; - - if (returnedValue > std::numeric_limits::max()) - returnedValue = std::numeric_limits::max(); - if (returnedValue < std::numeric_limits::min()) - returnedValue = std::numeric_limits::min(); - - return validRange.clamp(static_cast(returnedValue)); -} - -template ::value, int>> -absl::optional readOpcode(absl::string_view value, const Range& validRange) -{ - size_t numberEnd = 0; - - if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-')) - ++numberEnd; - while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) - ++numberEnd; - - if (numberEnd < value.size() && value[numberEnd] == '.') { - ++numberEnd; - while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) - ++numberEnd; - } - - value = value.substr(0, numberEnd); - - float returnedValue; - if (!absl::SimpleAtof(value, &returnedValue)) - return absl::nullopt; - - return validRange.clamp(returnedValue); -} - absl::optional readBooleanFromOpcode(const Opcode& opcode) { // Cakewalk-style booleans, case-insensitive @@ -227,84 +287,13 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) // ARIA-style booleans? (seen in egN_dynamic=1 for example) // TODO check this - if (auto value = readOpcode(opcode.value, Range::wholeRange())) + const OpcodeSpec fullInt64 { 0, Range::wholeRange(), 0 }; + if (auto value = opcode.read(fullInt64)) return *value != 0; return absl::nullopt; } -template -void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (!value) // Try and read a note rather than a number - value = readNoteValue(opcode.value); - if (value) - target = *value; -} - -template -inline void setValueFromOpcode(const Opcode& opcode, absl::optional& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (!value) // Try and read a note rather than a number - value = readNoteValue(opcode.value); - if (value) - target = *value; -} - -template -void setRangeEndFromOpcode(const Opcode& opcode, Range& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (!value) // Try and read a note rather than a number - value = readNoteValue(opcode.value); - if (value) - target.setEnd(*value); -} - -template -void setRangeStartFromOpcode(const Opcode& opcode, Range& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (!value) // Try and read a note rather than a number - value = readNoteValue(opcode.value); - if (value) - target.setStart(*value); -} - -template -void setCCPairFromOpcode(const Opcode& opcode, absl::optional>& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back())) - target = { opcode.parameters.back(), *value }; - else - target = {}; -} - -/// -#define INSTANCIATE_FOR(T) \ - template absl::optional readOpcode(absl::string_view value, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setValueFromOpcode(const Opcode& opcode, T& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setValueFromOpcode(const Opcode& opcode, absl::optional& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setRangeEndFromOpcode(const Opcode& opcode, Range& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setRangeStartFromOpcode(const Opcode& opcode, Range& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setCCPairFromOpcode(const Opcode& opcode, absl::optional>& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ - -INSTANCIATE_FOR(float) -INSTANCIATE_FOR(double) -INSTANCIATE_FOR(int8_t) -INSTANCIATE_FOR(int16_t) -INSTANCIATE_FOR(int32_t) -INSTANCIATE_FOR(int64_t) -INSTANCIATE_FOR(uint8_t) -INSTANCIATE_FOR(uint16_t) -INSTANCIATE_FOR(uint32_t) -//INSTANCIATE_FOR(uint64_t) - -#undef INSTANCIATE_FOR - } // namespace sfz std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode) diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index a6c3a1d6..51ff6088 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -101,6 +101,9 @@ struct Opcode { category == kOpcodeStepCcN || category == kOpcodeSmoothCcN; } + template + absl::optional read(OpcodeSpec spec) const; + private: static OpcodeCategory identifyCategory(absl::string_view name); LEAK_DETECTOR(Opcode); @@ -114,96 +117,11 @@ private: */ absl::optional readNoteValue(absl::string_view value); -/** - * @brief Read a value from the sfz file and cast it to the destination parameter along - * with a proper clamping into range if needed. This particular template version acts on - * integral target types, but can accept floats as an input. - * - * @tparam ValueType the target casting type - * @param value the string value to be read and stored - * @param validRange the range of admitted values - * @return absl::optional the cast value, or null - */ -template ::value, int> = 0> -absl::optional readOpcode(absl::string_view value, const Range& validRange); - -/** - * @brief Read a value from the sfz file and cast it to the destination parameter along - * with a proper clamping into range if needed. This particular template version acts on - * floating types. - * - * @tparam ValueType the target casting type - * @param value the string value to be read and stored - * @param validRange the range of admitted values - * @return absl::optional the cast value, or null - */ -template ::value, int> = 0> -absl::optional readOpcode(absl::string_view value, const Range& validRange); - /** * @brief Read a boolean value from the sfz file and cast it to the destination parameter. */ absl::optional readBooleanFromOpcode(const Opcode& opcode); -/** - * @brief Set a target parameter from an opcode value, with possibly a textual note rather - * than a number - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the value to update - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range& validRange); - -/** - * @brief Set a target parameter from an opcode value, with possibly a textual note rather - * than a number - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the value to update - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setValueFromOpcode(const Opcode& opcode, absl::optional& target, const Range& validRange); - -/** - * @brief Set a target end of a range from an opcode value, with possibly a textual note rather - * than a number - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the value to update - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setRangeEndFromOpcode(const Opcode& opcode, Range& target, const Range& validRange); - -/** - * @brief Set a target beginning of a range from an opcode value, with possibly a textual note rather - * than a number - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the value to update - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setRangeStartFromOpcode(const Opcode& opcode, Range& target, const Range& validRange); - -/** - * @brief Set a CC modulation parameter from an opcode value. - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the new CC modulation parameter - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setCCPairFromOpcode(const Opcode& opcode, absl::optional>& target, const Range& validRange); - } std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index fbbee939..d84fbc52 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -33,6 +33,18 @@ bool extendIfNecessary(std::vector& vec, unsigned size, unsigned defaultCapac return true; } +sfz::Region::Region(int regionNumber, const MidiState& midiState, absl::string_view defaultPath) +: id{regionNumber}, midiState(midiState), defaultPath(std::move(defaultPath)) +{ + ccSwitched.set(); + + gainToEffect.reserve(5); // sufficient room for main and fx1-4 + gainToEffect.push_back(1.0); // contribute 100% into the main bus + + // Default amplitude release + amplitudeEG.release = Default::egRelease.value; +} + bool sfz::Region::parseOpcode(const Opcode& rawOpcode) { const Opcode opcode = rawOpcode.cleanUp(kOpcodeScopeRegion); @@ -45,7 +57,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash(x "_stepcc&"): \ case hash(x "_smoothcc&") - #define LFO_EG_filter_EQ_target(sourceKey, targetKey, range) \ + #define LFO_EG_filter_EQ_target(sourceKey, targetKey, spec) \ { \ const auto number = opcode.parameters.front(); \ if (number == 0) \ @@ -55,7 +67,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \ return false; \ \ - if (auto value = readOpcode(opcode.value, range)) { \ + if (auto value = opcode.read(spec)) { \ const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \ const ModKey target = ModKey::createNXYZ(targetKey, id, index); \ getOrCreateConnection(source, target).sourceDepth = *value; \ @@ -82,8 +94,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) { if (opcode.value == "-1") sampleQuality.reset(); - else - setValueFromOpcode(opcode, sampleQuality, Default::sampleQualityRange); + else if (auto value = opcode.read(Default::sampleQuality)) + sampleQuality = *value; break; } break; @@ -91,28 +103,29 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) *sampleId = sampleId->reversed(opcode.value == "reverse"); break; case hash("delay"): - setValueFromOpcode(opcode, delay, Default::delayRange); + delay = opcode.read(Default::delay).value_or(delay); break; case hash("delay_random"): - setValueFromOpcode(opcode, delayRandom, Default::delayRange); + delayRandom = opcode.read(Default::delayRandom).value_or(delayRandom); break; case hash("offset"): - setValueFromOpcode(opcode, offset, Default::offsetRange); + offset = opcode.read(Default::offset).value_or(offset); break; case hash("offset_random"): - setValueFromOpcode(opcode, offsetRandom, Default::offsetRange); + offsetRandom = opcode.read(Default::offsetRandom).value_or(offsetRandom); break; case hash("offset_oncc&"): // also offset_cc& if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::offsetCCRange)) + if (auto value = opcode.read(Default::offsetMod)) offsetCC[opcode.parameters.back()] = *value; break; case hash("end"): - setValueFromOpcode(opcode, sampleEnd, Default::sampleEndRange); + sampleEnd = opcode.read(Default::sampleEnd).value_or(sampleEnd); break; case hash("count"): - setValueFromOpcode(opcode, sampleCount, Default::sampleCountRange); + if (auto value = opcode.read(Default::sampleCount)) + sampleCount = *value; break; case hash("loop_mode"): // also loopmode switch (hash(opcode.value)) { @@ -133,18 +146,20 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("loop_end"): // also loopend - setRangeEndFromOpcode(opcode, loopRange, Default::loopRange); + if (auto value = opcode.read(Default::loopRange)) + loopRange.setEnd(*value); break; case hash("loop_start"): // also loopstart - setRangeStartFromOpcode(opcode, loopRange, Default::loopRange); + if (auto value = opcode.read(Default::loopRange)) + loopRange.setStart(*value); break; case hash("loop_crossfade"): - setValueFromOpcode(opcode, loopCrossfade, Default::loopCrossfadeRange); + loopCrossfade = opcode.read(Default::loopCrossfade).value_or(loopCrossfade); break; // Wavetable oscillator case hash("oscillator_phase"): - if (auto value = readOpcode(opcode.value, Default::oscillatorPhaseRange)) + if (auto value = opcode.read(Default::oscillatorPhase)) oscillatorPhase = (*value >= 0) ? wrapPhase(*value) : -1.0f; break; case hash("oscillator"): @@ -152,40 +167,42 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) oscillatorEnabled = *value ? OscillatorEnabled::On : OscillatorEnabled::Off; break; case hash("oscillator_mode"): - setValueFromOpcode(opcode, oscillatorMode, Default::oscillatorModeRange); + oscillatorMode = opcode.read(Default::oscillatorMode).value_or(oscillatorMode); break; case hash("oscillator_multi"): - setValueFromOpcode(opcode, oscillatorMulti, Default::oscillatorMultiRange); + oscillatorMulti = opcode.read(Default::oscillatorMulti).value_or(oscillatorMulti); break; case hash("oscillator_detune"): - setValueFromOpcode(opcode, oscillatorDetune, Default::oscillatorDetuneRange); + oscillatorDetune = opcode.read(Default::oscillatorDetune).value_or(oscillatorDetune); break; case_any_ccN("oscillator_detune"): - processGenericCc(opcode, Default::oscillatorDetuneCCRange, ModKey::createNXYZ(ModId::OscillatorDetune, id)); + processGenericCc(opcode, Default::oscillatorDetuneMod, + ModKey::createNXYZ(ModId::OscillatorDetune, id)); break; case hash("oscillator_mod_depth"): - if (auto value = readOpcode(opcode.value, Default::oscillatorModDepthRange)) + if (auto value = opcode.read(Default::oscillatorModDepth)) oscillatorModDepth = normalizePercents(*value); break; case_any_ccN("oscillator_mod_depth"): - processGenericCc(opcode, Default::oscillatorModDepthCCRange, ModKey::createNXYZ(ModId::OscillatorModDepth, id)); + processGenericCc(opcode, Default::oscillatorModDepthMod, + ModKey::createNXYZ(ModId::OscillatorModDepth, id)); break; case hash("oscillator_quality"): if (opcode.value == "-1") oscillatorQuality.reset(); - else - setValueFromOpcode(opcode, oscillatorQuality, Default::oscillatorQualityRange); + else if (auto value = opcode.read(Default::oscillatorQuality)) + oscillatorQuality = *value; break; // Instrument settings: voice lifecycle case hash("group"): // also polyphony_group - setValueFromOpcode(opcode, group, Default::groupRange); + group = opcode.read(Default::group).value_or(group); break; case hash("off_by"): // also offby if (opcode.value == "-1") offBy.reset(); - else - setValueFromOpcode(opcode, offBy, Default::groupRange); + else if (auto value = opcode.read(Default::group)) + offBy = *value; break; case hash("off_mode"): // also offmode switch (hash(opcode.value)) { @@ -204,14 +221,13 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("off_time"): offMode = SfzOffMode::time; - setValueFromOpcode(opcode, offTime, Default::egTimeRange); + offTime = opcode.read(Default::offTime).value_or(offTime); break; case hash("polyphony"): - if (auto value = readOpcode(opcode.value, Default::polyphonyRange)) - polyphony = *value; + polyphony = opcode.read(Default::polyphony).value_or(polyphony); break; case hash("note_polyphony"): - if (auto value = readOpcode(opcode.value, Default::polyphonyRange)) + if (auto value = opcode.read(Default::notePolyphony)) notePolyphony = *value; break; case hash("note_selfmask"): @@ -237,72 +253,79 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; // Region logic: key mapping case hash("lokey"): - triggerOnNote = true; - setRangeStartFromOpcode(opcode, keyRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) { + triggerOnNote = true; + keyRange.setStart(*value); + } break; case hash("hikey"): triggerOnNote = (opcode.value != "-1"); - setRangeEndFromOpcode(opcode, keyRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + keyRange.setEnd(*value); break; case hash("key"): triggerOnNote = (opcode.value != "-1"); - setRangeStartFromOpcode(opcode, keyRange, Default::keyRange); - setRangeEndFromOpcode(opcode, keyRange, Default::keyRange); - setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); + if (auto value = opcode.read(Default::key)) { + keyRange.setStart(*value); + keyRange.setEnd(*value); + pitchKeycenter = *value; + } break; case hash("lovel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::midi7)) velocityRange.setStart(normalizeVelocity(*value)); break; case hash("hivel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::midi7)) velocityRange.setEnd(normalizeVelocity(*value)); break; // Region logic: MIDI conditions case hash("lobend"): - if (auto value = readOpcode(opcode.value, Default::bendRange)) + if (auto value = opcode.read(Default::bend)) bendRange.setStart(normalizeBend(*value)); break; case hash("hibend"): - if (auto value = readOpcode(opcode.value, Default::bendRange)) + if (auto value = opcode.read(Default::bend)) bendRange.setEnd(normalizeBend(*value)); break; case hash("locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::midi7)) ccConditions[opcode.parameters.back()].setStart(normalizeCC(*value)); break; case hash("hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::midi7)) ccConditions[opcode.parameters.back()].setEnd(normalizeCC(*value)); break; case hash("lohdcc&"): // also lorealcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::normalizedRange)) + if (auto value = opcode.read(Default::normalized)) ccConditions[opcode.parameters.back()].setStart(*value); break; case hash("hihdcc&"): // also hirealcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::normalizedRange)) + if (auto value = opcode.read(Default::normalized)) ccConditions[opcode.parameters.back()].setEnd(*value); break; case hash("sw_lokey"): // fallthrough case hash("sw_hikey"): break; case hash("sw_last"): - if (!lastKeyswitchRange) { - setValueFromOpcode(opcode, lastKeyswitch, Default::keyRange); - keySwitched = false; + if (auto value = opcode.read(Default::key)) { + if (!lastKeyswitchRange) { + lastKeyswitch = *value; + keySwitched = false; + } } break; case hash("sw_lolast"): - if (auto value = readOpcode(opcode.value, Default::keyRange)) { + if (auto value = opcode.read(Default::key)) { if (!lastKeyswitchRange) lastKeyswitchRange.emplace(*value, *value); else @@ -313,7 +336,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("sw_hilast"): - if (auto value = readOpcode(opcode.value, Default::keyRange)) { + if (auto value = opcode.read(Default::key)) { if (!lastKeyswitchRange) lastKeyswitchRange.emplace(*value, *value); else @@ -327,15 +350,21 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) keyswitchLabel = opcode.value; break; case hash("sw_down"): - setValueFromOpcode(opcode, downKeyswitch, Default::keyRange); - keySwitched = false; + if (auto value = opcode.read(Default::key)) { + downKeyswitch = *value; + keySwitched = false; + } break; case hash("sw_up"): - setValueFromOpcode(opcode, upKeyswitch, Default::keyRange); + if (auto value = opcode.read(Default::key)) { + upKeyswitch = *value; + } break; case hash("sw_previous"): - setValueFromOpcode(opcode, previousKeyswitch, Default::keyRange); - previousKeySwitched = false; + if (auto value = opcode.read(Default::key)) { + previousKeyswitch = *value; + previousKeySwitched = false; + } break; case hash("sw_vel"): switch (hash(opcode.value)) { @@ -351,12 +380,11 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("sustain_cc"): - setValueFromOpcode(opcode, sustainCC, Default::ccNumberRange); + sustainCC = opcode.read(Default::sustainCC).value_or(sustainCC); break; case hash("sustain_lo"): - if (auto value = readOpcode(opcode.value, Default::float7Range)) { + if (auto value = opcode.read(Default::float7)) sustainThreshold = normalizeCC(*value); - } break; case hash("sustain_sw"): checkSustain = readBooleanFromOpcode(opcode).value_or(Default::checkSustain); @@ -366,28 +394,34 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; // Region logic: internal conditions case hash("lochanaft"): - setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange); + if (auto value = opcode.read(Default::midi7)) + aftertouchRange.setStart(*value); break; case hash("hichanaft"): - setRangeEndFromOpcode(opcode, aftertouchRange, Default::aftertouchRange); + if (auto value = opcode.read(Default::midi7)) + aftertouchRange.setEnd(*value); break; case hash("lobpm"): - setRangeStartFromOpcode(opcode, bpmRange, Default::bpmRange); + if (auto value = opcode.read(Default::bpm)) + bpmRange.setStart(*value); break; case hash("hibpm"): - setRangeEndFromOpcode(opcode, bpmRange, Default::bpmRange); + if (auto value = opcode.read(Default::bpm)) + bpmRange.setEnd(*value); break; case hash("lorand"): - setRangeStartFromOpcode(opcode, randRange, Default::randRange); + if (auto value = opcode.read(Default::normalized)) + randRange.setStart(*value); break; case hash("hirand"): - setRangeEndFromOpcode(opcode, randRange, Default::randRange); + if (auto value = opcode.read(Default::normalized)) + randRange.setEnd(*value); break; case hash("seq_length"): - setValueFromOpcode(opcode, sequenceLength, Default::sequenceRange); + sequenceLength = opcode.read(Default::sequence).value_or(sequenceLength); break; case hash("seq_position"): - setValueFromOpcode(opcode, sequencePosition, Default::sequenceRange); + sequencePosition = opcode.read(Default::sequence).value_or(sequencePosition); sequenceSwitched = false; break; // Region logic: triggers @@ -415,7 +449,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("start_locc&"): // also on_locc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) { + if (auto value = opcode.read(Default::midi7)) { triggerOnCC = true; ccTriggers[opcode.parameters.back()].setStart(normalizeCC(*value)); } @@ -423,7 +457,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("start_hicc&"): // also on_hicc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) { + if (auto value = opcode.read(Default::midi7)) { triggerOnCC = true; ccTriggers[opcode.parameters.back()].setEnd(normalizeCC(*value)); } @@ -431,7 +465,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("start_lohdcc&"): // also on_lohdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::normalizedRange)) { + if (auto value = opcode.read(Default::normalized)) { triggerOnCC = true; ccTriggers[opcode.parameters.back()].setStart(*value); } @@ -439,7 +473,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("start_hihdcc&"): // also on_hihdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::normalizedRange)) { + if (auto value = opcode.read(Default::normalized)) { triggerOnCC = true; ccTriggers[opcode.parameters.back()].setEnd(*value); } @@ -447,55 +481,55 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) // Performance parameters: amplifier case hash("volume"): // also gain - setValueFromOpcode(opcode, volume, Default::volumeRange); + volume = opcode.read(Default::volume).value_or(volume); break; case_any_ccN("volume"): // also gain - processGenericCc(opcode, Default::volumeCCRange, ModKey::createNXYZ(ModId::Volume, id)); + processGenericCc(opcode, Default::volumeMod, ModKey::createNXYZ(ModId::Volume, id)); break; case hash("amplitude"): - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + if (auto value = opcode.read(Default::amplitude)) amplitude = normalizePercents(*value); break; case_any_ccN("amplitude"): - processGenericCc(opcode, Default::amplitudeRange, ModKey::createNXYZ(ModId::Amplitude, id)); + processGenericCc(opcode, Default::amplitudeMod, ModKey::createNXYZ(ModId::Amplitude, id)); break; case hash("pan"): - if (auto value = readOpcode(opcode.value, Default::panRange)) + if (auto value = opcode.read(Default::pan)) pan = normalizePercents(*value); break; case_any_ccN("pan"): - processGenericCc(opcode, Default::panCCRange, ModKey::createNXYZ(ModId::Pan, id)); + processGenericCc(opcode, Default::panMod, ModKey::createNXYZ(ModId::Pan, id)); break; case hash("position"): - if (auto value = readOpcode(opcode.value, Default::positionRange)) + if (auto value = opcode.read(Default::position)) position = normalizePercents(*value); break; case_any_ccN("position"): - processGenericCc(opcode, Default::positionCCRange, ModKey::createNXYZ(ModId::Position, id)); + processGenericCc(opcode, Default::positionMod, ModKey::createNXYZ(ModId::Position, id)); break; case hash("width"): - if (auto value = readOpcode(opcode.value, Default::widthRange)) + if (auto value = opcode.read(Default::width)) width = normalizePercents(*value); break; case_any_ccN("width"): - processGenericCc(opcode, Default::widthCCRange, ModKey::createNXYZ(ModId::Width, id)); + processGenericCc(opcode, Default::widthMod, ModKey::createNXYZ(ModId::Width, id)); break; case hash("amp_keycenter"): - setValueFromOpcode(opcode, ampKeycenter, Default::keyRange); + ampKeycenter = opcode.read(Default::key).value_or(ampKeycenter); break; case hash("amp_keytrack"): - setValueFromOpcode(opcode, ampKeytrack, Default::ampKeytrackRange); + ampKeytrack = opcode.read(Default::ampKeytrack).value_or(ampKeytrack); break; case hash("amp_veltrack"): - if (auto value = readOpcode(opcode.value, Default::ampVeltrackRange)) + if (auto value = opcode.read(Default::ampVeltrack)) ampVeltrack = normalizePercents(*value); break; case hash("amp_random"): - setValueFromOpcode(opcode, ampRandom, Default::ampRandomRange); + ampRandom = opcode.read(Default::ampRandom).value_or(ampRandom); break; case hash("amp_velcurve_&"): { - auto value = readOpcode(opcode.value, Default::ampVelcurveRange); + auto value = opcode.read(Default::ampVelcurve); if (opcode.parameters.back() > 127) return false; @@ -505,31 +539,35 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("xfin_lokey"): - setRangeStartFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + crossfadeKeyInRange.setStart(*value); break; case hash("xfin_hikey"): - setRangeEndFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + crossfadeKeyInRange.setEnd(*value); break; case hash("xfout_lokey"): - setRangeStartFromOpcode(opcode, crossfadeKeyOutRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + crossfadeKeyOutRange.setStart(*value); break; case hash("xfout_hikey"): - setRangeEndFromOpcode(opcode, crossfadeKeyOutRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + crossfadeKeyOutRange.setEnd(*value); break; case hash("xfin_lovel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeIn)) crossfadeVelInRange.setStart(normalizeVelocity(*value)); break; case hash("xfin_hivel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeIn)) crossfadeVelInRange.setEnd(normalizeVelocity(*value)); break; case hash("xfout_lovel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeOut)) crossfadeVelOutRange.setStart(normalizeVelocity(*value)); break; case hash("xfout_hivel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeOut)) crossfadeVelOutRange.setEnd(normalizeVelocity(*value)); break; case hash("xf_keycurve"): @@ -559,25 +597,25 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("xfin_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeIn)) crossfadeCCInRange[opcode.parameters.back()].setStart(normalizeCC(*value)); break; case hash("xfin_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeIn)) crossfadeCCInRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); break; case hash("xfout_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeOut)) crossfadeCCOutRange[opcode.parameters.back()].setStart(normalizeCC(*value)); break; case hash("xfout_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeOut)) crossfadeCCOutRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); break; case hash("xf_cccurve"): @@ -593,28 +631,28 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("rt_decay"): - setValueFromOpcode(opcode, rtDecay, Default::rtDecayRange); + rtDecay = opcode.read(Default::rtDecay).value_or(rtDecay); break; case hash("global_amplitude"): - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + if (auto value = opcode.read(Default::amplitude)) globalAmplitude = normalizePercents(*value); break; case hash("master_amplitude"): - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + if (auto value = opcode.read(Default::amplitude)) masterAmplitude = normalizePercents(*value); break; case hash("group_amplitude"): - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + if (auto value = opcode.read(Default::amplitude)) groupAmplitude = normalizePercents(*value); break; case hash("global_volume"): - setValueFromOpcode(opcode, globalVolume, Default::volumeRange); + globalVolume = opcode.read(Default::volume).value_or(globalVolume); break; case hash("master_volume"): - setValueFromOpcode(opcode, masterVolume, Default::volumeRange); + masterVolume = opcode.read(Default::volume).value_or(masterVolume); break; case hash("group_volume"): - setValueFromOpcode(opcode, groupVolume, Default::volumeRange); + groupVolume = opcode.read(Default::volume).value_or(groupVolume); break; // Performance parameters: filters @@ -623,7 +661,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1); if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - setValueFromOpcode(opcode, filters[filterIndex].cutoff, Default::filterCutoffRange); + if (auto value = opcode.read(Default::filterCutoff)) + filters[filterIndex].cutoff = *value; } break; case hash("resonance&"): // also resonance @@ -631,7 +670,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1); if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - setValueFromOpcode(opcode, filters[filterIndex].resonance, Default::filterResonanceRange); + if (auto value = opcode.read(Default::filterResonance)) + filters[filterIndex].resonance = *value; } break; case_any_ccN("cutoff&"): // also cutoff_oncc&, cutoff_cc&, cutoff&_cc& @@ -640,7 +680,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - processGenericCc(opcode, Default::filterCutoffModRange, ModKey::createNXYZ(ModId::FilCutoff, id, filterIndex)); + processGenericCc(opcode, Default::filterCutoffMod, ModKey::createNXYZ(ModId::FilCutoff, id, filterIndex)); } break; case_any_ccN("resonance&"): // also resonance_oncc&, resonance_cc&, resonance&_cc& @@ -649,7 +689,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - processGenericCc(opcode, Default::filterResonanceModRange, ModKey::createNXYZ(ModId::FilResonance, id, filterIndex)); + processGenericCc(opcode, Default::filterResonanceMod, ModKey::createNXYZ(ModId::FilResonance, id, filterIndex)); } break; case hash("fil&_keytrack"): // also fil_keytrack @@ -657,8 +697,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].keytrack, Default::filterKeytrackRange); + if (auto value = opcode.read(Default::filterKeytrack)) + filters[filterIndex].keytrack = *value; } break; case hash("fil&_keycenter"): // also fil_keycenter @@ -666,8 +706,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].keycenter, Default::keyRange); + if (auto value = opcode.read(Default::key)) + filters[filterIndex].keycenter = *value; } break; case hash("fil&_veltrack"): // also fil_veltrack @@ -675,8 +715,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].veltrack, Default::filterVeltrackRange); + if (auto value = opcode.read(Default::filterVeltrack)) + filters[filterIndex].veltrack = *value; } break; case hash("fil&_random"): // also fil_random, cutoff_random, cutoff&_random @@ -684,8 +724,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].random, Default::filterRandomRange); + if (auto value = opcode.read(Default::filterRandom)) + filters[filterIndex].random = *value; } break; case hash("fil&_gain"): // also fil_gain @@ -693,8 +733,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].gain, Default::filterGainRange); + if (auto value = opcode.read(Default::filterGain)) + filters[filterIndex].gain = *value; } break; case_any_ccN("fil&_gain"): // also fil_gain_oncc& @@ -703,7 +743,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - processGenericCc(opcode, Default::filterGainModRange, ModKey::createNXYZ(ModId::FilGain, id, filterIndex)); + processGenericCc(opcode, Default::filterGainMod, ModKey::createNXYZ(ModId::FilGain, id, filterIndex)); } break; case hash("fil&_type"): // also fil_type, filtype @@ -729,8 +769,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - - setValueFromOpcode(opcode, equalizers[eqIndex].bandwidth, Default::eqBandwidthRange); + if (auto value = opcode.read(Default::eqBandwidth)) + equalizers[eqIndex].bandwidth = *value; } break; case_any_ccN("eq&_bw"): // also eq&_bwcc& @@ -739,7 +779,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - processGenericCc(opcode, Default::eqBandwidthModRange, ModKey::createNXYZ(ModId::EqBandwidth, id, eqIndex)); + processGenericCc(opcode, Default::eqBandwidthMod, ModKey::createNXYZ(ModId::EqBandwidth, id, eqIndex)); } break; case hash("eq&_freq"): @@ -747,7 +787,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - setValueFromOpcode(opcode, equalizers[eqIndex].frequency, Default::eqFrequencyRange); + if (auto value = opcode.read(Default::eqFrequency)) + equalizers[eqIndex].frequency = *value; } break; case_any_ccN("eq&_freq"): // also eq&_freqcc& @@ -756,7 +797,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - processGenericCc(opcode, Default::eqFrequencyModRange, ModKey::createNXYZ(ModId::EqFrequency, id, eqIndex)); + processGenericCc(opcode, Default::eqFrequencyMod, ModKey::createNXYZ(ModId::EqFrequency, id, eqIndex)); } break; case hash("eq&_veltofreq"): // also eq&_vel2freq @@ -764,8 +805,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - - setValueFromOpcode(opcode, equalizers[eqIndex].vel2frequency, Default::eqFrequencyModRange); + if (auto value = opcode.read(Default::eqVel2Frequency)) + equalizers[eqIndex].vel2frequency = *value; } break; case hash("eq&_gain"): @@ -773,7 +814,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - setValueFromOpcode(opcode, equalizers[eqIndex].gain, Default::eqGainRange); + if (auto value = opcode.read(Default::eqGain)) + equalizers[eqIndex].gain = *value; } break; case_any_ccN("eq&_gain"): // also eq&_gaincc& @@ -782,7 +824,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - processGenericCc(opcode, Default::eqGainModRange, ModKey::createNXYZ(ModId::EqGain, id, eqIndex)); + processGenericCc(opcode, Default::eqGainMod, ModKey::createNXYZ(ModId::EqGain, id, eqIndex)); } break; case hash("eq&_veltogain"): // also eq&_vel2gain @@ -790,8 +832,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - - setValueFromOpcode(opcode, equalizers[eqIndex].vel2gain, Default::eqGainModRange); + if (auto value = opcode.read(Default::eqVel2Gain)) + equalizers[eqIndex].vel2gain = *value; } break; case hash("eq&_type"): @@ -817,38 +859,38 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) pitchKeycenterFromSample = true; else { pitchKeycenterFromSample = false; - setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); + pitchKeycenter = opcode.read(Default::key).value_or(pitchKeycenter); } break; case hash("pitch_keytrack"): - setValueFromOpcode(opcode, pitchKeytrack, Default::pitchKeytrackRange); + pitchKeytrack = opcode.read(Default::pitchKeytrack).value_or(pitchKeytrack); break; case hash("pitch_veltrack"): - setValueFromOpcode(opcode, pitchVeltrack, Default::pitchVeltrackRange); + pitchVeltrack = opcode.read(Default::pitchVeltrack).value_or(pitchVeltrack); break; case hash("pitch_random"): - setValueFromOpcode(opcode, pitchRandom, Default::pitchRandomRange); + pitchRandom = opcode.read(Default::pitchRandom).value_or(pitchRandom); break; case hash("transpose"): - setValueFromOpcode(opcode, transpose, Default::transposeRange); + transpose = opcode.read(Default::transpose).value_or(transpose); break; case hash("pitch"): // also tune - setValueFromOpcode(opcode, tune, Default::tuneRange); + pitch = opcode.read(Default::pitch).value_or(pitch); break; case_any_ccN("pitch"): // also tune - processGenericCc(opcode, Default::tuneCCRange, ModKey::createNXYZ(ModId::Pitch, id)); + processGenericCc(opcode, Default::pitchMod, ModKey::createNXYZ(ModId::Pitch, id)); break; case hash("bend_up"): // also bendup - setValueFromOpcode(opcode, bendUp, Default::bendBoundRange); + bendUp = opcode.read(Default::bendUp).value_or(bendUp); break; case hash("bend_down"): // also benddown - setValueFromOpcode(opcode, bendDown, Default::bendBoundRange); + bendDown = opcode.read(Default::bendDown).value_or(bendDown); break; case hash("bend_step"): - setValueFromOpcode(opcode, bendStep, Default::bendStepRange); + bendStep = opcode.read(Default::bendStep).value_or(bendStep); break; case hash("bend_smooth"): - setValueFromOpcode(opcode, bendSmooth, Default::smoothCCRange); + bendSmooth = opcode.read(Default::smoothCC).value_or(bendSmooth); break; // Modulation: LFO @@ -859,7 +901,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].freq, Default::lfoFreqRange); + if (auto value = opcode.read(Default::lfoFreq)) + lfos[lfoNumber - 1].freq = *value; } break; case_any_ccN("lfo&_freq"): @@ -869,7 +912,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - processGenericCc(opcode, Default::lfoFreqModRange, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber - 1)); + processGenericCc(opcode, Default::lfoFreqMod, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber - 1)); } break; case hash("lfo&_beats"): @@ -879,7 +922,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].beats, Default::lfoBeatsRange); + if (auto value = opcode.read(Default::lfoBeats)) + lfos[lfoNumber - 1].beats = *value; } break; case_any_ccN("lfo&_beats"): @@ -889,7 +933,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - processGenericCc(opcode, Default::lfoBeatsModRange, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber - 1)); + processGenericCc(opcode, Default::lfoBeatsMod, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber - 1)); } break; case hash("lfo&_phase"): @@ -899,7 +943,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoPhaseRange)) + if (auto value = opcode.read(Default::lfoPhase)) lfos[lfoNumber - 1].phase0 = wrapPhase(*value); } break; @@ -910,7 +954,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].delay, Default::lfoDelayRange); + if (auto value = opcode.read(Default::lfoDelay)) + lfos[lfoNumber - 1].delay = *value; } break; case hash("lfo&_fade"): @@ -920,7 +965,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].fade, Default::lfoFadeRange); + if (auto value = opcode.read(Default::lfoFade)) + lfos[lfoNumber - 1].fade = *value; } break; case hash("lfo&_count"): @@ -930,7 +976,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].count, Default::lfoCountRange); + if (auto value = opcode.read(Default::lfoCount)) + lfos[lfoNumber - 1].count = *value; } break; case hash("lfo&_steps"): @@ -940,7 +987,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoStepsRange)) { + if (auto value = opcode.read(Default::lfoSteps)) { if (!lfos[lfoNumber - 1].seq) lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); lfos[lfoNumber - 1].seq->steps.resize(*value); @@ -955,7 +1002,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoStepXRange)) { + if (auto value = opcode.read(Default::lfoStepX)) { if (!lfos[lfoNumber - 1].seq) lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); if (!extendIfNecessary(lfos[lfoNumber - 1].seq->steps, stepNumber, Default::numLFOSteps)) @@ -972,7 +1019,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoWaveRange)) { + if (auto value = opcode.read(Default::lfoWave)) { if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; lfos[lfoNumber - 1].sub[subNumber - 1].wave = static_cast(*value); @@ -987,7 +1034,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoOffsetRange)) { + if (auto value = opcode.read(Default::lfoOffset)) { if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; lfos[lfoNumber - 1].sub[subNumber - 1].offset = *value; @@ -1002,7 +1049,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoRatioRange)) { + if (auto value = opcode.read(Default::lfoRatio)) { if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; lfos[lfoNumber - 1].sub[subNumber - 1].ratio = *value; @@ -1017,7 +1064,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoScaleRange)) { + if (auto value = opcode.read(Default::lfoScale)) { if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; lfos[lfoNumber - 1].sub[subNumber - 1].scale = *value; @@ -1031,7 +1078,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) { + if (auto value = opcode.read(Default::amplitudeMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1043,7 +1090,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::panCCRange)) { + if (auto value = opcode.read(Default::panMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Pan, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1055,7 +1102,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::widthCCRange)) { + if (auto value = opcode.read(Default::widthMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Width, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1067,7 +1114,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::positionCCRange)) { + if (auto value = opcode.read(Default::positionMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Position, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1079,7 +1126,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::tuneCCRange)) { + if (auto value = opcode.read(Default::pitchMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1091,7 +1138,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::volumeCCRange)) { + if (auto value = opcode.read(Default::volumeMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Volume, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1099,22 +1146,22 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("lfo&_cutoff&"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffMod); break; case hash("lfo&_resonance&"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceMod); break; case hash("lfo&_fil&gain"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainMod); break; case hash("lfo&_eq&gain"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainMod); break; case hash("lfo&_eq&freq"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyMod); break; case hash("lfo&_eq&bw"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthMod); break; // Modulation: Flex EG (targets) @@ -1123,7 +1170,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) { + if (auto value = opcode.read(Default::amplitudeMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1135,7 +1182,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::panCCRange)) { + if (auto value = opcode.read(Default::panMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Pan, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1147,7 +1194,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::widthCCRange)) { + if (auto value = opcode.read(Default::widthMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Width, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1159,7 +1206,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::positionCCRange)) { + if (auto value = opcode.read(Default::positionMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Position, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1171,7 +1218,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::tuneCCRange)) { + if (auto value = opcode.read(Default::pitchMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1183,7 +1230,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::volumeCCRange)) { + if (auto value = opcode.read(Default::volumeMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Volume, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1191,22 +1238,22 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("eg&_cutoff&"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffMod); break; case hash("eg&_resonance&"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceMod); break; case hash("eg&_fil&gain"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainMod); break; case hash("eg&_eq&gain"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainMod); break; case hash("eg&_eq&freq"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyMod); break; case hash("eg&_eq&bw"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthMod); break; case hash("eg&_ampeg"): @@ -1307,26 +1354,26 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("pitcheg_depth"): - if (auto value = readOpcode(opcode.value, Default::pitchEgDepthRange)) + if (auto value = opcode.read(Default::egDepth)) getOrCreateConnection( ModKey::createNXYZ(ModId::PitchEG, id), ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = *value; break; case hash("fileg_depth"): - if (auto value = readOpcode(opcode.value, Default::filterEgDepthRange)) + if (auto value = opcode.read(Default::egDepth)) getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = *value; break; case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth - if (auto value = readOpcode(opcode.value, Default::pitchEgDepthRange)) + if (auto value = opcode.read(Default::egVel2Depth)) getOrCreateConnection( ModKey::createNXYZ(ModId::PitchEG, id), ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = *value; break; case hash("fileg_veltodepth"): // also fileg_vel2depth - if (auto value = readOpcode(opcode.value, Default::filterEgDepthRange)) + if (auto value = opcode.read(Default::egVel2Depth)) getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = *value; @@ -1341,7 +1388,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; auto& eg = flexEGs[egNumber - 1]; - setValueFromOpcode(opcode, eg.dynamic, Default::flexEGDynamicRange); + eg.dynamic = opcode.read(Default::flexEGDynamic).value_or(eg.dynamic); } break; case hash("eg&_sustain"): @@ -1352,7 +1399,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; auto& eg = flexEGs[egNumber - 1]; - setValueFromOpcode(opcode, eg.sustain, Default::flexEGSustainRange); + eg.sustain = opcode.read(Default::flexEGSustain).value_or(eg.sustain); } break; case hash("eg&_time&"): @@ -1366,7 +1413,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - setValueFromOpcode(opcode, eg.points[pointNumber].time, Default::flexEGPointTimeRange); + if (auto value = opcode.read(Default::flexEGPointTime)) + eg.points[pointNumber].time = *value; } break; case hash("eg&_level&"): @@ -1380,7 +1428,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - setValueFromOpcode(opcode, eg.points[pointNumber].level, Default::flexEGPointLevelRange); + if (auto value = opcode.read(Default::flexEGPointLevel)) + eg.points[pointNumber].level = *value; } break; case hash("eg&_shape&"): @@ -1394,7 +1443,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - if (auto value = readOpcode(opcode.value, Default::flexEGPointShapeRange)) + if (auto value = opcode.read(Default::flexEGPointShape)) eg.points[pointNumber].setShape(*value); } break; @@ -1404,7 +1453,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto effectNumber = opcode.parameters.back(); if (!effectNumber || effectNumber < 1 || effectNumber > config::maxEffectBuses) break; - auto value = readOpcode(opcode.value, { 0, 100 }); + auto value = opcode.read(Default::effect); if (!value) break; if (static_cast(effectNumber + 1) > gainToEffect.size()) @@ -1413,7 +1462,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; } case hash("sw_default"): - setValueFromOpcode(opcode, defaultSwitch, Default::keyRange); + if (auto value = opcode.read(Default::key)) + defaultSwitch = *value; break; // Ignored opcodes @@ -1441,49 +1491,49 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) switch (opcode.lettersOnlyHash) { case_any_eg("attack"): - setValueFromOpcode(opcode, eg.attack, Default::egTimeRange); + eg.attack = opcode.read(Default::egTime).value_or(eg.attack); break; case_any_eg("decay"): - setValueFromOpcode(opcode, eg.decay, Default::egTimeRange); + eg.decay = opcode.read(Default::egTime).value_or(eg.decay); break; case_any_eg("delay"): - setValueFromOpcode(opcode, eg.delay, Default::egTimeRange); + eg.delay = opcode.read(Default::egTime).value_or(eg.delay); break; case_any_eg("hold"): - setValueFromOpcode(opcode, eg.hold, Default::egTimeRange); + eg.hold = opcode.read(Default::egTime).value_or(eg.hold); break; case_any_eg("release"): - setValueFromOpcode(opcode, eg.release, Default::egTimeRange); + eg.release = opcode.read(Default::egRelease).value_or(eg.release); break; case_any_eg("start"): - setValueFromOpcode(opcode, eg.start, Default::egPercentRange); + eg.start = opcode.read(Default::egPercent).value_or(eg.start); break; case_any_eg("sustain"): - setValueFromOpcode(opcode, eg.sustain, Default::egPercentRange); + eg.sustain = opcode.read(Default::egPercent).value_or(eg.sustain); break; case_any_eg("veltoattack"): // also vel2attack - setValueFromOpcode(opcode, eg.vel2attack, Default::egOnCCTimeRange); + eg.vel2attack = opcode.read(Default::egTimeMod).value_or(eg.vel2attack); break; case_any_eg("veltodecay"): // also vel2decay - setValueFromOpcode(opcode, eg.vel2decay, Default::egOnCCTimeRange); + eg.vel2decay = opcode.read(Default::egTimeMod).value_or(eg.vel2decay); break; case_any_eg("veltodelay"): // also vel2delay - setValueFromOpcode(opcode, eg.vel2delay, Default::egOnCCTimeRange); + eg.vel2delay = opcode.read(Default::egTimeMod).value_or(eg.vel2delay); break; case_any_eg("veltohold"): // also vel2hold - setValueFromOpcode(opcode, eg.vel2hold, Default::egOnCCTimeRange); + eg.vel2hold = opcode.read(Default::egTimeMod).value_or(eg.vel2hold); break; case_any_eg("veltorelease"): // also vel2release - setValueFromOpcode(opcode, eg.vel2release, Default::egOnCCTimeRange); + eg.vel2release = opcode.read(Default::egTimeMod).value_or(eg.vel2release); break; case_any_eg("veltosustain"): // also vel2sustain - setValueFromOpcode(opcode, eg.vel2sustain, Default::egOnCCPercentRange); + eg.vel2sustain = opcode.read(Default::egPercentMod).value_or(eg.vel2sustain); break; case_any_eg("attack_oncc&"): // also attackcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccAttack[opcode.parameters.back()] = *value; break; @@ -1491,7 +1541,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccDecay[opcode.parameters.back()] = *value; break; @@ -1499,7 +1549,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccDelay[opcode.parameters.back()] = *value; break; @@ -1507,7 +1557,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccHold[opcode.parameters.back()] = *value; break; @@ -1515,7 +1565,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccRelease[opcode.parameters.back()] = *value; break; @@ -1523,7 +1573,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCPercentRange)) + if (auto value = opcode.read(Default::egPercentMod)) eg.ccStart[opcode.parameters.back()] = *value; break; @@ -1531,7 +1581,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCPercentRange)) + if (auto value = opcode.read(Default::egPercentMod)) eg.ccSustain[opcode.parameters.back()] = *value; break; @@ -1557,7 +1607,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, absl::optional range, const ModKey& target) +bool sfz::Region::processGenericCc(const Opcode& opcode, OpcodeSpec spec, const ModKey& target) { if (!opcode.isAnyCcN()) return false; @@ -1591,19 +1641,21 @@ bool sfz::Region::processGenericCc(const Opcode& opcode, Range range, con ModKey::Parameters p = conn->source.parameters(); switch (opcode.category) { case kOpcodeOnCcN: - setValueFromOpcode(opcode, conn->sourceDepth, range); + conn->sourceDepth = opcode.read(spec).value_or(conn->sourceDepth); break; case kOpcodeCurveCcN: - setValueFromOpcode(opcode, p.curve, Default::curveCCRange); + p.curve = opcode.read(Default::curveCC).value_or(p.curve); break; case kOpcodeStepCcN: { - const Range stepCCRange { 0.0f, std::max(std::abs(range.getStart()), std::abs(range.getEnd())) }; - setValueFromOpcode(opcode, p.step, stepCCRange); + const float maxStep = + max(std::abs(spec.bounds.getStart()), std::abs(spec.bounds.getEnd())); + const OpcodeSpec stepCC { 0.0f, Range(0.0f, maxStep), kEnforceLowerBound | kEnforceUpperBound }; + p.step = opcode.read(stepCC).value_or(p.step); } break; case kOpcodeSmoothCcN: - setValueFromOpcode(opcode, p.smooth, Default::smoothCCRange); + p.smooth = opcode.read(Default::smoothCC).value_or(p.smooth); break; default: assert(false); @@ -1734,7 +1786,7 @@ float sfz::Region::getBasePitchVariation(float noteNumber, float velocity) const fast_real_distribution pitchDistribution { -pitchRandom, pitchRandom }; auto pitchVariationInCents = pitchKeytrack * (noteNumber - pitchKeycenter); // note difference with pitch center - pitchVariationInCents += tune; // sample tuning + pitchVariationInCents += pitch; // sample tuning pitchVariationInCents += config::centPerSemitone * transpose; // sample transpose pitchVariationInCents += velocity * pitchVeltrack; // track velocity pitchVariationInCents += pitchDistribution(Random::randomGenerator); // random pitch changes @@ -1782,7 +1834,7 @@ uint64_t sfz::Region::getOffset(Oversampling factor) const noexcept uint64_t finalOffset = offset + offsetDistribution(Random::randomGenerator); for (const auto& mod: offsetCC) finalOffset += static_cast(mod.data * midiState.getCCValue(mod.cc)); - return Default::offsetRange.clamp(finalOffset) * static_cast(factor); + return Default::offset.bounds.clamp(finalOffset) * static_cast(factor); } float sfz::Region::getDelay() const noexcept @@ -1871,37 +1923,37 @@ float sfz::Region::velocityCurve(float velocity) const noexcept void sfz::Region::offsetAllKeys(int offset) noexcept { // Offset key range - if (keyRange != Default::keyRange) { + if (keyRange != Default::key.bounds) { const auto start = keyRange.getStart(); const auto end = keyRange.getEnd(); - keyRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); - keyRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); + keyRange.setStart(offsetAndClampKey(start, offset)); + keyRange.setEnd(offsetAndClampKey(end, offset)); } - pitchKeycenter = offsetAndClampKey(pitchKeycenter, offset, Default::keyRange); + pitchKeycenter = offsetAndClampKey(pitchKeycenter, offset); // Offset key switches if (upKeyswitch) - upKeyswitch = offsetAndClampKey(*upKeyswitch, offset, Default::keyRange); + upKeyswitch = offsetAndClampKey(*upKeyswitch, offset); if (lastKeyswitch) - lastKeyswitch = offsetAndClampKey(*lastKeyswitch, offset, Default::keyRange); + lastKeyswitch = offsetAndClampKey(*lastKeyswitch, offset); if (downKeyswitch) - downKeyswitch = offsetAndClampKey(*downKeyswitch, offset, Default::keyRange); + downKeyswitch = offsetAndClampKey(*downKeyswitch, offset); if (previousKeyswitch) - previousKeyswitch = offsetAndClampKey(*previousKeyswitch, offset, Default::keyRange); + previousKeyswitch = offsetAndClampKey(*previousKeyswitch, offset); // Offset crossfade ranges if (crossfadeKeyInRange != Default::crossfadeKeyInRange) { const auto start = crossfadeKeyInRange.getStart(); const auto end = crossfadeKeyInRange.getEnd(); - crossfadeKeyInRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); - crossfadeKeyInRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); + crossfadeKeyInRange.setStart(offsetAndClampKey(start, offset)); + crossfadeKeyInRange.setEnd(offsetAndClampKey(end, offset)); } if (crossfadeKeyOutRange != Default::crossfadeKeyOutRange) { const auto start = crossfadeKeyOutRange.getStart(); const auto end = crossfadeKeyOutRange.getEnd(); - crossfadeKeyOutRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); - crossfadeKeyOutRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); + crossfadeKeyOutRange.setStart(offsetAndClampKey(start, offset)); + crossfadeKeyOutRange.setEnd(offsetAndClampKey(end, offset)); } } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 92ecf255..87f39984 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -43,17 +43,7 @@ class RegionSet; * */ struct Region { - Region(int regionNumber, const MidiState& midiState, absl::string_view defaultPath = "") - : id{regionNumber}, midiState(midiState), defaultPath(std::move(defaultPath)) - { - ccSwitched.set(); - - gainToEffect.reserve(5); // sufficient room for main and fx1-4 - gainToEffect.push_back(1.0); // contribute 100% into the main bus - - // Default amplitude release - amplitudeEG.release = Default::ampegRelease; - } + Region(int regionNumber, const MidiState& midiState, absl::string_view defaultPath = ""); Region(const Region&) = default; ~Region() = default; @@ -280,12 +270,12 @@ struct Region { * @brief Process a generic CC opcode, and fill the modulation parameters. * * @param opcode - * @param range + * @param spec * @param target * @return true if the opcode was properly read and stored. * @return false */ - bool processGenericCc(const Opcode& opcode, Range range, const ModKey& target); + bool processGenericCc(const Opcode& opcode, OpcodeSpec spec, const ModKey& target); void offsetAllKeys(int offset) noexcept; @@ -329,45 +319,45 @@ struct Region { // Sound source: sample playback std::shared_ptr sampleId { new FileId }; // Sample absl::optional sampleQuality {}; - float delay { Default::delay }; // delay - float delayRandom { Default::delayRandom }; // delay_random - int64_t offset { Default::offset }; // offset - int64_t offsetRandom { Default::offsetRandom }; // offset_random - CCMap offsetCC { Default::offset }; - uint32_t sampleEnd { Default::sampleEndRange.getEnd() }; // end + float delay { Default::delay.value }; // delay + float delayRandom { Default::delayRandom.value }; // delay_random + int64_t offset { Default::offset.value }; // offset + int64_t offsetRandom { Default::offsetRandom.value }; // offset_random + CCMap offsetCC { Default::offsetMod.value }; + uint32_t sampleEnd { Default::sampleEnd.value }; // end absl::optional sampleCount {}; // count absl::optional loopMode {}; // loopmode - Range loopRange { Default::loopRange }; //loopstart and loopend - float loopCrossfade { Default::loopCrossfade }; // loop_crossfade + Range loopRange { Default::loopRange.bounds }; //loopstart and loopend + float loopCrossfade { Default::loopCrossfade.value }; // loop_crossfade // Wavetable oscillator - float oscillatorPhase { Default::oscillatorPhase }; + float oscillatorPhase { Default::oscillatorPhase.value }; enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; - OscillatorEnabled oscillatorEnabled = OscillatorEnabled::Auto; // oscillator - bool hasWavetableSample = false; // (set according to sample file) - int oscillatorMode = Default::oscillatorMode; - int oscillatorMulti = Default::oscillatorMulti; - float oscillatorDetune = Default::oscillatorDetune; - float oscillatorModDepth = Default::oscillatorModDepth; + OscillatorEnabled oscillatorEnabled { OscillatorEnabled::Auto }; // oscillator + bool hasWavetableSample { false }; // (set according to sample file) + int oscillatorMode { Default::oscillatorMode.value }; + int oscillatorMulti { Default::oscillatorMulti.value }; + float oscillatorDetune { Default::oscillatorDetune.value }; + float oscillatorModDepth { Default::oscillatorModDepth.value }; absl::optional oscillatorQuality; // Instrument settings: voice lifecycle - uint32_t group { Default::group }; // group + uint32_t group { Default::group.value }; // group absl::optional offBy {}; // off_by SfzOffMode offMode { Default::offMode }; // off_mode - float offTime { Default::offTime }; // off_mode + float offTime { Default::offTime.value }; // off_mode absl::optional notePolyphony {}; // note_polyphony - unsigned polyphony { config::maxVoices }; // polyphony + uint32_t polyphony { config::maxVoices }; // polyphony SfzSelfMask selfMask { Default::selfMask }; bool rtDead { Default::rtDead }; // Region logic: key mapping - Range keyRange { Default::keyRange }; //lokey, hikey and key - Range velocityRange { Default::velocityRange }; // hivel and lovel + Range keyRange { Default::key.bounds }; //lokey, hikey and key + Range velocityRange { Default::normalized.bounds }; // hivel and lovel // Region logic: MIDI conditions - Range bendRange { Default::bendValueRange }; // hibend and lobend - CCMap> ccConditions { Default::ccValueRange }; + Range bendRange { Default::bipolar.bounds }; // hibend and lobend + CCMap> ccConditions { Default::normalized.bounds }; absl::optional lastKeyswitch {}; // sw_last absl::optional> lastKeyswitchRange {}; // sw_last absl::optional keyswitchLabel {}; @@ -378,32 +368,32 @@ struct Region { SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel bool checkSustain { Default::checkSustain }; // sustain_sw bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw - uint16_t sustainCC { Default::sustainCC }; // sustain_cc - float sustainThreshold { Default::sustainThreshold }; // sustain_cc + uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc + float sustainThreshold { Default::sustainThreshold.value }; // sustain_cc // Region logic: internal conditions - Range aftertouchRange { Default::aftertouchRange }; // hichanaft and lochanaft - Range bpmRange { Default::bpmRange }; // hibpm and lobpm - Range randRange { Default::randRange }; // hirand and lorand - uint8_t sequenceLength { Default::sequenceLength }; // seq_length - uint8_t sequencePosition { Default::sequencePosition }; // seq_position + Range aftertouchRange { Default::midi7.bounds }; // hichanaft and lochanaft + Range bpmRange { Default::bpm.bounds }; // hibpm and lobpm + Range randRange { Default::normalized.bounds }; // hirand and lorand + uint8_t sequenceLength { Default::sequence.value }; // seq_length + uint8_t sequencePosition { Default::sequence.value }; // seq_position // Region logic: triggers SfzTrigger trigger { Default::trigger }; // trigger - CCMap> ccTriggers { Default::ccTriggerValueRange }; // on_loccN on_hiccN + CCMap> ccTriggers { Default::normalized.bounds }; // on_loccN on_hiccN // Performance parameters: amplifier - float volume { Default::volume }; // volume - float amplitude { normalizePercents(Default::amplitude) }; // amplitude - float pan { normalizePercents(Default::pan) }; // pan - float width { normalizePercents(Default::width) }; // width - float position { normalizePercents(Default::position) }; // position - uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter - float ampKeytrack { Default::ampKeytrack }; // amp_keytrack - float ampVeltrack { normalizePercents(Default::ampVeltrack) }; // amp_keytrack + float volume { Default::volume.value }; // volume + float amplitude { normalizePercents(Default::amplitude.value) }; // amplitude + float pan { normalizePercents(Default::pan.value) }; // pan + float width { normalizePercents(Default::width.value) }; // width + float position { normalizePercents(Default::position.value) }; // position + uint8_t ampKeycenter { Default::key.value }; // amp_keycenter + float ampKeytrack { Default::ampKeytrack.value }; // amp_keytrack + float ampVeltrack { normalizePercents(Default::ampVeltrack.value) }; // amp_veltrack std::vector> velocityPoints; // amp_velcurve_N absl::optional velCurve {}; - float ampRandom { Default::ampRandom }; // amp_random + float ampRandom { Default::ampRandom.value }; // amp_random Range crossfadeKeyInRange { Default::crossfadeKeyInRange }; Range crossfadeKeyOutRange { Default::crossfadeKeyOutRange }; Range crossfadeVelInRange { Default::crossfadeVelInRange }; @@ -413,7 +403,7 @@ struct Region { SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCCCurve }; CCMap> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN - float rtDecay { Default::rtDecay }; // rt_decay + float rtDecay { Default::rtDecay.value }; // rt_decay float globalAmplitude { 1.0 }; // global_amplitude float masterAmplitude { 1.0 }; // master_amplitude @@ -427,17 +417,17 @@ struct Region { std::vector filters; // Performance parameters: pitch - uint8_t pitchKeycenter { Default::pitchKeycenter }; // pitch_keycenter + uint8_t pitchKeycenter { Default::key.value }; // pitch_keycenter bool pitchKeycenterFromSample { false }; - int pitchKeytrack { Default::pitchKeytrack }; // pitch_keytrack - float pitchRandom { Default::pitchRandom }; // pitch_random - int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack - int transpose { Default::transpose }; // transpose - float tune { Default::tune }; // tune - int bendUp { Default::bendUp }; - int bendDown { Default::bendDown }; - int bendStep { Default::bendStep }; - uint8_t bendSmooth { Default::bendSmooth }; + int pitchKeytrack { Default::pitchKeytrack.value }; // pitch_keytrack + float pitchRandom { Default::pitchRandom.value }; // pitch_random + int pitchVeltrack { Default::pitchVeltrack.value }; // pitch_veltrack + int transpose { Default::transpose.value }; // transpose + float pitch { Default::pitch.value }; // tune + float bendUp { Default::bendUp.value }; + float bendDown { Default::bendDown.value }; + float bendStep { Default::bendStep.value }; + uint8_t bendSmooth { Default::smoothCC.value }; // Envelopes EGDescription amplitudeEG; diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index b26f6560..7577d60d 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -182,18 +182,17 @@ constexpr float normalizeBend(float bendValue) * * @param key * @param offset - * @param range * @return uint8_t */ -inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset, sfz::Range range) +inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset) { const int offsetKey { key + offset }; if (offsetKey > std::numeric_limits::max()) - return range.getEnd(); + return Default::key.bounds.getEnd(); if (offsetKey < std::numeric_limits::min()) - return range.getStart(); + return Default::key.bounds.getStart(); - return range.clamp(static_cast(offsetKey)); + return Default::key.bounds.clamp(static_cast(offsetKey)); } namespace literals { diff --git a/src/sfizz/Smoothers.cpp b/src/sfizz/Smoothers.cpp index fda61be0..c2f6e2fb 100644 --- a/src/sfizz/Smoothers.cpp +++ b/src/sfizz/Smoothers.cpp @@ -5,6 +5,10 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Smoothers.h" +#include "Config.h" +#include "MathHelpers.h" +#include "SfzHelpers.h" +#include "SIMDHelpers.h" namespace sfz { @@ -16,7 +20,7 @@ void Smoother::setSmoothing(uint8_t smoothValue, float sampleRate) { smoothing = (smoothValue > 0); if (smoothing) { - filter.setGain(std::tan(1.0f / (2 * Default::smoothTauPerStep * smoothValue * sampleRate))); + filter.setGain(std::tan(1.0f / (2 * config::smoothTauPerStep * smoothValue * sampleRate))); } } diff --git a/src/sfizz/Smoothers.h b/src/sfizz/Smoothers.h index 598dd203..50f99821 100644 --- a/src/sfizz/Smoothers.h +++ b/src/sfizz/Smoothers.h @@ -6,12 +6,7 @@ #pragma once -#include "Config.h" -#include "Defaults.h" -#include "MathHelpers.h" -#include "SfzHelpers.h" #include "OnePoleFilter.h" -#include "SIMDHelpers.h" #include namespace sfz { diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b82cb372..43ac6241 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -191,7 +191,7 @@ void Synth::Impl::buildRegion(const std::vector& regionOpcodes) currentSwitch_ = *lastRegion->defaultSwitch; // There was a combination of group= and polyphony= on a region, so set the group polyphony - if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) { + if (lastRegion->group != Default::group.value && lastRegion->polyphony != config::maxVoices) { voiceManager_.setGroupPolyphony(lastRegion->group, lastRegion->polyphony); } else { // Just check that there are enough polyphony groups @@ -276,11 +276,12 @@ void Synth::Impl::handleMasterOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("polyphony"): ASSERT(currentSet_ != nullptr); - if (auto value = readOpcode(member.value, Default::polyphonyRange)) + if (auto value = member.read(Default::polyphony)) currentSet_->setPolyphonyLimit(*value); break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch_, Default::keyRange); + if (auto value = member.read(Default::key)) + currentSwitch_ = *value; break; } } @@ -294,15 +295,16 @@ void Synth::Impl::handleGlobalOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("polyphony"): ASSERT(currentSet_ != nullptr); - if (auto value = readOpcode(member.value, Default::polyphonyRange)) + if (auto value = member.read(Default::polyphony)) currentSet_->setPolyphonyLimit(*value); break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch_, Default::keyRange); + if (auto value = member.read(Default::key)) + currentSwitch_ = *value; break; case hash("volume"): // FIXME : Probably best not to mess with this and let the host control the volume - // setValueFromOpcode(member, volume, Default::volumeRange); + // setValueFromOpcode(member, volume, OldDefault::volumeRange); break; } } @@ -318,13 +320,16 @@ void Synth::Impl::handleGroupOpcodes(const std::vector& members, const s switch (member.lettersOnlyHash) { case hash("group"): - setValueFromOpcode(member, groupIdx, Default::groupRange); + if (auto value = member.read(Default::group)) + groupIdx = *value; break; case hash("polyphony"): - setValueFromOpcode(member, maxPolyphony, Default::polyphonyRange); + if (auto value = member.read(Default::polyphony)) + maxPolyphony = *value; break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch_, Default::keyRange); + if (auto value = member.read(Default::key)) + currentSwitch_ = *value; break; } }; @@ -352,15 +357,15 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("set_cc&"): - if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { - const auto ccValue = readOpcode(member.value, Default::midi7Range); + if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) { + const auto ccValue = member.read(Default::midi7); if (ccValue) setDefaultHdcc(member.parameters.back(), normalizeCC(*ccValue)); } break; case hash("set_hdcc&"): - if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { - const auto ccValue = readOpcode(member.value, Default::normalizedRange); + if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) { + const auto ccValue = member.read(Default::normalized); if (ccValue) setDefaultHdcc(member.parameters.back(), *ccValue); } @@ -370,7 +375,7 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) setCCLabel(member.parameters.back(), std::string(member.value)); break; case hash("label_key&"): - if (member.parameters.back() <= Default::keyRange.getEnd()) { + if (member.parameters.back() <= Default::key.bounds.getEnd()) { const auto noteNumber = static_cast(member.parameters.back()); insertPairUniquely(keyLabels_, noteNumber, std::string(member.value)); } @@ -380,10 +385,10 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) DBG("Changing default sample path to " << defaultPath_); break; case hash("note_offset"): - setValueFromOpcode(member, noteOffset_, Default::noteOffsetRange); + noteOffset_ = member.read(Default::noteOffset).value_or(noteOffset_); break; case hash("octave_offset"): - setValueFromOpcode(member, octaveOffset_, Default::octaveOffsetRange); + octaveOffset_ = member.read(Default::octaveOffset).value_or(octaveOffset_); break; case hash("hint_ram_based"): if (member.value == "1") @@ -446,21 +451,21 @@ void Synth::Impl::handleEffectOpcodes(const std::vector& rawMembers) // note(jpc): gain opcodes are linear volumes in % units case hash("directtomain"): - if (auto valueOpt = readOpcode(opcode.value, { 0, 100 })) + if (auto valueOpt = opcode.read(Default::effect)) getOrCreateBus(0).setGainToMain(*valueOpt / 100); break; case hash("fx&tomain"): // fx&tomain if (opcode.parameters.front() < 1 || opcode.parameters.front() > config::maxEffectBuses) break; - if (auto valueOpt = readOpcode(opcode.value, { 0, 100 })) + if (auto valueOpt = opcode.read(Default::effect)) getOrCreateBus(opcode.parameters.front()).setGainToMain(*valueOpt / 100); break; case hash("fx&tomix"): // fx&tomix if (opcode.parameters.front() < 1 || opcode.parameters.front() > config::maxEffectBuses) break; - if (auto valueOpt = readOpcode(opcode.value, { 0, 100 })) + if (auto valueOpt = opcode.read(Default::effect)) getOrCreateBus(opcode.parameters.front()).setGainToMix(*valueOpt / 100); break; } @@ -584,10 +589,10 @@ void Synth::Impl::finalizeSfzLoad() region->sampleEnd = std::min(region->sampleEnd, fileInformation->end); if (fileInformation->hasLoop) { - if (region->loopRange.getStart() == Default::loopRange.getStart()) + if (region->loopRange.getStart() == Default::loopRange.bounds.getStart()) region->loopRange.setStart(fileInformation->loopBegin); - if (region->loopRange.getEnd() == Default::loopRange.getEnd()) + if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) region->loopRange.setEnd(fileInformation->loopEnd); if (!region->loopMode) @@ -597,7 +602,7 @@ void Synth::Impl::finalizeSfzLoad() if (region->isRelease() && !region->loopMode) region->loopMode = SfzLoopMode::one_shot; - if (region->loopRange.getEnd() == Default::loopRange.getEnd()) + if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) region->loopRange.setEnd(region->sampleEnd); if (fileInformation->numChannels == 2) @@ -611,7 +616,7 @@ void Synth::Impl::finalizeSfzLoad() uint64_t sumOffsetCC = region->offset + region->offsetRandom; for (const auto& offsets : region->offsetCC) sumOffsetCC += offsets.data; - return Default::offsetCCRange.clamp(sumOffsetCC); + return Default::offsetMod.bounds.clamp(sumOffsetCC); }(); if (!resources_.filePool.preloadFile(*region->sampleId, maxOffset)) @@ -663,14 +668,14 @@ void Synth::Impl::finalizeSfzLoad() // Set the default frequencies on equalizers if needed if (region->equalizers.size() > 0 - && region->equalizers[0].frequency == Default::eqFrequencyUnset) { - region->equalizers[0].frequency = Default::eqFrequency1; + && region->equalizers[0].frequency == Default::eqFrequency.value) { + region->equalizers[0].frequency = Default::defaultEQFreq[0]; if (region->equalizers.size() > 1 - && region->equalizers[1].frequency == Default::eqFrequencyUnset) { - region->equalizers[1].frequency = Default::eqFrequency2; + && region->equalizers[1].frequency == Default::eqFrequency.value) { + region->equalizers[1].frequency = Default::defaultEQFreq[1]; if (region->equalizers.size() > 2 - && region->equalizers[2].frequency == Default::eqFrequencyUnset) { - region->equalizers[2].frequency = Default::eqFrequency3; + && region->equalizers[2].frequency == Default::eqFrequency.value) { + region->equalizers[2].frequency = Default::defaultEQFreq[2]; } } } @@ -1479,7 +1484,7 @@ float Synth::getVolume() const noexcept void Synth::setVolume(float volume) noexcept { Impl& impl = *impl_; - impl.volume_ = Default::volumeRange.clamp(volume); + impl.volume_ = Default::volume.bounds.clamp(volume); } int Synth::getNumVoices() const noexcept diff --git a/src/sfizz/SynthConfig.h b/src/sfizz/SynthConfig.h index 3f710f89..47d265e6 100644 --- a/src/sfizz/SynthConfig.h +++ b/src/sfizz/SynthConfig.h @@ -13,8 +13,8 @@ struct SynthConfig { bool freeWheeling { false }; - int liveSampleQuality { sfz::Default::sampleQuality }; - int freeWheelingSampleQuality { sfz::Default::sampleQualityInFreewheelingMode }; + int liveSampleQuality { Default::sampleQuality.value }; + int freeWheelingSampleQuality { Default::freewheelingQuality }; int currentSampleQuality() const noexcept { diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 9902b58b..0f6bd10b 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -124,6 +124,24 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } } break; + MATCH("/region&/trigger_on_note", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.triggerOnNote) { + client.receive<'T'>(delay, path, {}); + } else { + client.receive<'F'>(delay, path, {}); + } + } break; + + MATCH("/region&/trigger_on_cc", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.triggerOnCC) { + client.receive<'T'>(delay, path, {}); + } else { + client.receive<'F'>(delay, path, {}); + } + } break; + MATCH("/region&/count", "") { GET_REGION_OR_BREAK(indices[0]) if (!region.sampleCount) { @@ -761,12 +779,12 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'i'>(delay, path, region.transpose); } break; - MATCH("/region&/tune", "") { + MATCH("/region&/pitch", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'f'>(delay, path, region.tune); + client.receive<'f'>(delay, path, region.pitch); } break; - MATCH("/region&/tune_cc&", "") { + MATCH("/region&/pitch_cc&", "") { GET_REGION_OR_BREAK(indices[0]) auto value = region.ccModDepth(indices[1], ModId::Pitch); if (value) { @@ -776,7 +794,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } } break; - MATCH("/region&/tune_stepcc&", "") { + MATCH("/region&/pitch_stepcc&", "") { GET_REGION_OR_BREAK(indices[0]) auto params = region.ccModParameters(indices[1], ModId::Pitch); if (params) { @@ -786,7 +804,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } } break; - MATCH("/region&/tune_smoothcc&", "") { + MATCH("/region&/pitch_smoothcc&", "") { GET_REGION_OR_BREAK(indices[0]) auto params = region.ccModParameters(indices[1], ModId::Pitch); if (params) { @@ -796,7 +814,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } } break; - MATCH("/region&/tune_curvecc&", "") { + MATCH("/region&/pitch_curvecc&", "") { GET_REGION_OR_BREAK(indices[0]) auto params = region.ccModParameters(indices[1], ModId::Pitch); if (params) { @@ -808,17 +826,17 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/bend_up", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'i'>(delay, path, region.bendUp); + client.receive<'f'>(delay, path, region.bendUp); } break; MATCH("/region&/bend_down", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'i'>(delay, path, region.bendDown); + client.receive<'f'>(delay, path, region.bendDown); } break; MATCH("/region&/bend_step", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'i'>(delay, path, region.bendStep); + client.receive<'f'>(delay, path, region.bendStep); } break; MATCH("/region&/bend_smooth", "") { @@ -863,7 +881,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/ampeg_depth", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'i'>(delay, path, region.amplitudeEG.depth); + client.receive<'f'>(delay, path, region.amplitudeEG.depth); } break; MATCH("/region&/ampeg_vel&attack", "") { @@ -912,7 +930,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co GET_REGION_OR_BREAK(indices[0]) if (indices[1] != 2) break; - client.receive<'i'>(delay, path, region.amplitudeEG.vel2depth); + client.receive<'f'>(delay, path, region.amplitudeEG.vel2depth); } break; MATCH("/region&/note_polyphony", "") { @@ -978,6 +996,37 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'f'>(delay, path, region.oscillatorPhase); } break; + MATCH("/region&/oscillator_quality", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.oscillatorQuality) { + client.receive<'i'>(delay, path, *region.oscillatorQuality); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/oscillator_mode", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.oscillatorMode); + } break; + + MATCH("/region&/oscillator_multi", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.oscillatorMulti); + } break; + + MATCH("/region&/oscillator_detune", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.oscillatorDetune); + } break; + + MATCH("/region&/oscillator_mod_depth", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.oscillatorModDepth * 100.0f); + } break; + + // TODO: detune cc, mod depth cc + MATCH("/region&/effect&", "") { GET_REGION_OR_BREAK(indices[0]) auto effectIdx = indices[1]; diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 0e251024..bd34ec22 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -257,8 +257,8 @@ struct Synth::Impl final: public Parser::Listener { // Control opcodes std::string defaultPath_ { "" }; - int noteOffset_ { 0 }; - int octaveOffset_ { 0 }; + int noteOffset_ { Default::noteOffset.value }; + int octaveOffset_ { Default::octaveOffset.value }; // Modulation source generators std::unique_ptr genController_; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 64ddebe9..4ba91ba1 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -370,7 +370,8 @@ void Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe } } const float phase = region->getPhase(); - const int quality = region->oscillatorQuality.value_or(Default::oscillatorQuality); + const int quality = + region->oscillatorQuality.value_or(Default::oscillatorQuality.value); for (WavetableOscillator& osc : impl.waveOscillators_) { osc.setWavetable(wave); osc.setPhase(phase); @@ -464,7 +465,7 @@ void Voice::off(int delay, bool fast) noexcept Impl& impl = *impl_; if (!impl.region_->flexAmpEG) { if (impl.region_->offMode == SfzOffMode::fast || fast) { - impl.egAmplitude_.setReleaseTime(Default::offTime); + impl.egAmplitude_.setReleaseTime(Default::offTime.value); } else if (impl.region_->offMode == SfzOffMode::time) { impl.egAmplitude_.setReleaseTime(impl.region_->offTime); } @@ -1652,7 +1653,7 @@ void Voice::Impl::pitchEnvelope(absl::Span pitchSpan) noexcept return centsFactor(region_->getBendInCents(bend)); }; - if (region_->bendStep > 1) + if (region_->bendStep > 1.0f) pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor_); else pitchBendEnvelope(events, *bends, bendLambda); diff --git a/src/sfizz/effects/Apan.cpp b/src/sfizz/effects/Apan.cpp index a51f4a4e..9151188a 100644 --- a/src/sfizz/effects/Apan.cpp +++ b/src/sfizz/effects/Apan.cpp @@ -81,27 +81,27 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("apan_waveform"): - if (auto value = readOpcode(opc.value, Default::apanWaveformRange)) + if (auto value = opc.read(Default::apanWaveform)) apan->_lfoWave = *value; break; case hash("apan_freq"): - if (auto value = readOpcode(opc.value, Default::apanFrequencyRange)) + if (auto value = opc.read(Default::apanFrequency)) apan->_lfoFrequency = *value; break; case hash("apan_phase"): - if (auto value = readOpcode(opc.value, Default::apanPhaseRange)) + if (auto value = opc.read(Default::apanPhase)) apan->_lfoPhaseOffset = wrapPhase(*value); break; case hash("apan_dry"): - if (auto value = readOpcode(opc.value, Default::apanLevelRange)) + if (auto value = opc.read(Default::apanLevel)) apan->_dry = *value / 100.0f; break; case hash("apan_wet"): - if (auto value = readOpcode(opc.value, Default::apanLevelRange)) + if (auto value = opc.read(Default::apanLevel)) apan->_wet = *value / 100.0f; break; case hash("apan_depth"): - if (auto value = readOpcode(opc.value, Default::apanLevelRange)) + if (auto value = opc.read(Default::apanLevel)) apan->_depth = *value / 100.0f; break; } diff --git a/src/sfizz/effects/Apan.h b/src/sfizz/effects/Apan.h index 52b85dc6..ac72e524 100644 --- a/src/sfizz/effects/Apan.h +++ b/src/sfizz/effects/Apan.h @@ -47,20 +47,20 @@ namespace fx { template void computeLfos(float* left, float* right, unsigned nframes); private: - float _samplePeriod = 0.0; + float _samplePeriod { 0.0f }; sfz::Buffer _lfoOutLeft { config::defaultSamplesPerBlock }; sfz::Buffer _lfoOutRight { config::defaultSamplesPerBlock }; // Controls - float _dry = 0.0; - float _wet = 0.0; - float _depth = 0.0; - int _lfoWave = 0; - float _lfoFrequency = 0.0; - float _lfoPhaseOffset = 0.5; + float _dry { Default::apanLevel.value }; + float _wet { Default::apanLevel.value }; + float _depth { Default::apanLevel.value }; + int _lfoWave { Default::apanWaveform.value }; + float _lfoFrequency { Default::apanFrequency.value }; + float _lfoPhaseOffset { Default::apanPhase.value }; // State - float _lfoPhase = 0.0; + float _lfoPhase { 0.0f }; }; } // namespace fx diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index 3aaf04a3..06b805ee 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -32,7 +32,7 @@ namespace fx { struct Compressor::Impl { faustCompressor _compressor[2]; bool _stlink = false; - float _inputGain = 1.0; + float _inputGain { Default::compGain.value }; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; hiir::Downsampler2xFpu<12> _downsampler2x[EffectChannels]; @@ -163,31 +163,31 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("comp_attack"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::compAttack)) { for (size_t c = 0; c < 2; ++c) impl.set_Attack(c, *value); } break; case hash("comp_release"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::compRelease)) { for (size_t c = 0; c < 2; ++c) impl.set_Release(c, *value); } break; case hash("comp_threshold"): - if (auto value = readOpcode(opc.value, {-100.0, 0.0})) { + if (auto value = opc.read(Default::compThreshold)) { for (size_t c = 0; c < 2; ++c) impl.set_Threshold(c, *value); } break; case hash("comp_ratio"): - if (auto value = readOpcode(opc.value, {1.0, 50.0})) { + if (auto value = opc.read(Default::compRatio)) { for (size_t c = 0; c < 2; ++c) impl.set_Ratio(c, *value); } break; case hash("comp_gain"): - if (auto value = readOpcode(opc.value, {-100.0, 100.0})) + if (auto value = opc.read(Default::compGain)) impl._inputGain = db2mag(*value); break; case hash("comp_stlink"): diff --git a/src/sfizz/effects/Disto.cpp b/src/sfizz/effects/Disto.cpp index 9e83856a..c3939f9e 100644 --- a/src/sfizz/effects/Disto.cpp +++ b/src/sfizz/effects/Disto.cpp @@ -37,15 +37,15 @@ namespace fx { struct Disto::Impl { enum { maxStages = 4 }; - float _samplePeriod = 1.0 / config::defaultSampleRate; - float _tone = 100.0; - float _depth = 0.0; - float _dry = 0.0; - float _wet = 0.0; - unsigned _numStages = 1; + float _samplePeriod { 1.0f / config::defaultSampleRate }; + float _tone { Default::distoTone.value }; + float _depth { Default::distoDepth.value }; + float _dry { Default::effect.value }; + float _wet { Default::effect.value }; + unsigned _numStages = { Default::distoStages.value }; float _toneLpfMem[EffectChannels] = {}; - faustDisto _stages[EffectChannels][maxStages]; + faustDisto _stages[EffectChannels][Default::maxDistoStages]; hiir::Upsampler2xFpu<12> _up2x[EffectChannels]; hiir::Upsampler2xFpu<4> _up4x[EffectChannels]; @@ -205,20 +205,23 @@ std::unique_ptr Disto::makeInstance(absl::Span members) for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("disto_tone"): - setValueFromOpcode(opc, impl._tone, {0.0f, 100.0f}); + if (auto value = opc.read(Default::distoTone)) + impl._tone = *value; break; case hash("disto_depth"): - setValueFromOpcode(opc, impl._depth, {0.0f, 100.0f}); + if (auto value = opc.read(Default::distoDepth)) + impl._depth = *value; break; case hash("disto_stages"): - setValueFromOpcode(opc, impl._numStages, {1, Impl::maxStages}); + if (auto value = opc.read(Default::distoStages)) + impl._numStages = *value; break; case hash("disto_dry"): - if (auto value = readOpcode(opc.value, {0.0f, 100.0f})) + if (auto value = opc.read(Default::effect)) impl._dry = *value * 0.01f; break; case hash("disto_wet"): - if (auto value = readOpcode(opc.value, {0.0f, 100.0f})) + if (auto value = opc.read(Default::effect)) impl._wet = *value * 0.01f; break; } diff --git a/src/sfizz/effects/Eq.cpp b/src/sfizz/effects/Eq.cpp index 1eda27e4..7c9b5594 100644 --- a/src/sfizz/effects/Eq.cpp +++ b/src/sfizz/effects/Eq.cpp @@ -70,13 +70,16 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("eq_freq"): - setValueFromOpcode(opc, desc.frequency, Default::eqFrequencyRange); + if (auto value = opc.read(Default::eqFrequency)) + desc.frequency = *value; break; case hash("eq_bw"): - setValueFromOpcode(opc, desc.bandwidth, Default::eqBandwidthRange); + if (auto value = opc.read(Default::eqBandwidth)) + desc.bandwidth = *value; break; case hash("eq_gain"): - setValueFromOpcode(opc, desc.gain, Default::eqGainRange); + if (auto value = opc.read(Default::eqGain)) + desc.gain = *value; break; case hash("eq_type"): { diff --git a/src/sfizz/effects/Filter.cpp b/src/sfizz/effects/Filter.cpp index d39d74f1..836306f3 100644 --- a/src/sfizz/effects/Filter.cpp +++ b/src/sfizz/effects/Filter.cpp @@ -72,10 +72,12 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("filter_cutoff"): - setValueFromOpcode(opc, desc.cutoff, Default::filterCutoffRange); + if (auto value = opc.read(Default::filterCutoff)) + desc.cutoff = *value; break; case hash("filter_resonance"): - setValueFromOpcode(opc, desc.resonance, Default::filterResonanceRange); + if (auto value = opc.read(Default::filterResonance)) + desc.resonance = *value; break; case hash("filter_type"): { @@ -90,7 +92,8 @@ namespace fx { } // extension case hash("sfizz:filter_gain"): - setValueFromOpcode(opc, desc.gain, Default::filterGainRange); + if (auto value = opc.read(Default::filterGain)) + desc.gain = *value; break; } } diff --git a/src/sfizz/effects/Fverb.cpp b/src/sfizz/effects/Fverb.cpp index 71e73efa..c3a1f408 100644 --- a/src/sfizz/effects/Fverb.cpp +++ b/src/sfizz/effects/Fverb.cpp @@ -180,13 +180,13 @@ namespace fx { std::unique_ptr fx { reverb }; const Impl::Profile* profile = &Impl::largeHall; - float dry = 0; - float wet = 0; - float input = 0; - float size = 0; - float predelay = 0; - float tone = 100; - float damp = 0; + float dry { Default::effect.value }; + float wet { Default::effect.value }; + float input { Default::effect.value }; + float size { Default::fverbSize.value }; + float predelay { Default::fverbPredelay.value }; + float tone { Default::fverbTone.value }; + float damp { Default::fverbDamp.value }; for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { @@ -211,25 +211,26 @@ namespace fx { } break; case hash("reverb_dry"): - setValueFromOpcode(opc, dry, {0.0f, 100.0f}); + + dry = opc.read(Default::effect).value_or(dry); break; case hash("reverb_wet"): - setValueFromOpcode(opc, wet, {0.0f, 100.0f}); + wet = opc.read(Default::effect).value_or(wet); break; case hash("reverb_input"): - setValueFromOpcode(opc, input, {0.0f, 100.0f}); + input = opc.read(Default::effect).value_or(input); break; case hash("reverb_size"): - setValueFromOpcode(opc, size, {0.0f, 100.0f}); + size = opc.read(Default::fverbSize).value_or(size); break; case hash("reverb_predelay"): - setValueFromOpcode(opc, predelay, {0.0f, 10.0f}); + predelay = opc.read(Default::fverbPredelay).value_or(predelay); break; case hash("reverb_tone"): - setValueFromOpcode(opc, tone, {0.0f, 100.0f}); + tone = opc.read(Default::fverbTone).value_or(tone); break; case hash("reverb_damp"): - setValueFromOpcode(opc, damp, {0.0f, 100.0f}); + damp = opc.read(Default::fverbDamp).value_or(damp); break; } } diff --git a/src/sfizz/effects/Gain.cpp b/src/sfizz/effects/Gain.cpp index 04cca832..7ad9fb9f 100644 --- a/src/sfizz/effects/Gain.cpp +++ b/src/sfizz/effects/Gain.cpp @@ -62,7 +62,8 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("gain"): - setValueFromOpcode(opc, gain->_gain, {-96.0f, 96.0f}); + if (auto value = opc.read(Default::volume)) + gain->_gain = *value; break; } } diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index b7a819d5..792060e6 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -166,25 +166,25 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("gate_attack"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::gateAttack)) { for (size_t c = 0; c < 2; ++c) impl.set_Attack(c, *value); } break; case hash("gate_hold"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::gateHold)) { for (size_t c = 0; c < 2; ++c) impl.set_Hold(c, *value); } break; case hash("gate_release"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::gateRelease)) { for (size_t c = 0; c < 2; ++c) impl.set_Release(c, *value); } break; case hash("gate_threshold"): - if (auto value = readOpcode(opc.value, {-100.0, 0.0})) { + if (auto value = opc.read(Default::gateThreshold)) { for (size_t c = 0; c < 2; ++c) impl.set_Threshold(c, *value); } diff --git a/src/sfizz/effects/Lofi.cpp b/src/sfizz/effects/Lofi.cpp index 12d7759f..00a11128 100644 --- a/src/sfizz/effects/Lofi.cpp +++ b/src/sfizz/effects/Lofi.cpp @@ -85,10 +85,12 @@ namespace fx { for (const Opcode& opcode : members) { switch (opcode.lettersOnlyHash) { case hash("bitred"): - setValueFromOpcode(opcode, lofi->_bitred_depth, { 0.0, 100.0 }); + if (auto value = opcode.read(Default::lofiBitred)) + lofi->_bitred_depth = *value; break; case hash("decim"): - setValueFromOpcode(opcode, lofi->_decim_depth, { 0.0, 100.0 }); + if (auto value = opcode.read(Default::lofiDecim)) + lofi->_decim_depth = *value; break; } } diff --git a/src/sfizz/effects/Rectify.cpp b/src/sfizz/effects/Rectify.cpp index 56be4682..f8d271dd 100644 --- a/src/sfizz/effects/Rectify.cpp +++ b/src/sfizz/effects/Rectify.cpp @@ -95,7 +95,8 @@ namespace fx { rectify->_full = false; break; case hash("rectify"): - setValueFromOpcode(opc, rectify->_amount, { 0.0, 100.0 }); + if (auto value = opc.read(Default::rectify)) + rectify->_amount = *value; break; } } diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index 9e7295d4..6538b68a 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -132,10 +132,12 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("strings_number"): - setValueFromOpcode(opc, strings->_numStrings, {0, MaximumNumStrings}); + if (auto value = opc.read(Default::stringsNumber)) + strings->_numStrings = *value; break; case hash("strings_wet"): - setValueFromOpcode(opc, strings->_wet, {0.0f, 100.0f}); + if (auto value = opc.read(Default::effect)) + strings->_wet = *value; break; } } diff --git a/src/sfizz/effects/Strings.h b/src/sfizz/effects/Strings.h index 2f46254b..f20ae8a8 100644 --- a/src/sfizz/effects/Strings.h +++ b/src/sfizz/effects/Strings.h @@ -51,8 +51,8 @@ namespace fx { private: enum { MaximumNumStrings = 88 }; - unsigned _numStrings = MaximumNumStrings; - float _wet = 0; + unsigned _numStrings { Default::maxStrings }; + float _wet { Default::effect.value }; std::unique_ptr _stringsArray; diff --git a/src/sfizz/effects/Width.cpp b/src/sfizz/effects/Width.cpp index a9c3c202..2a3cdc92 100644 --- a/src/sfizz/effects/Width.cpp +++ b/src/sfizz/effects/Width.cpp @@ -69,7 +69,8 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("width"): - setValueFromOpcode(opc, width->_width, {-100.0f, 100.0f}); + if (auto value = opc.read(Default::width)) + width->_width = *value; break; } } diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 28c41dd9..1072d188 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -447,7 +447,20 @@ TEST_CASE("[Files] Set RealCC applies properly") TEST_CASE("[Files] Note and octave offsets") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/note_offset.sfz"); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/note_offset.sfz", R"( + note_offset=1 + key=63 sample=*sine + lokey=50 hikey=55 pitch_keycenter=50 sample=*sine + lokey=40 hikey=44 pitch_keycenter=40 xfin_lokey=36 xfin_hikey=40 xfout_lokey=44 xfout_hikey=48 sample=*sine + note_offset=-1 + key=63 sw_lokey=24 sw_hikey=28 sw_last=25 sw_up=25 sw_down=25 sw_previous=62 sample=*sine + note_offset=1 octave_offset=1 + key=63 sample=*sine + note_offset=-1 octave_offset=-1 + key=63 sample=*sine + // Check that this does not reset either note or octave offset + key=63 sample=*sine + )"); REQUIRE( synth.getNumRegions() == 7 ); REQUIRE(synth.getRegionView(0)->keyRange == Range(64, 64)); diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 24d6a98c..61971b39 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -7,12 +7,13 @@ #include "sfizz/Region.h" #include "catch2/catch.hpp" using namespace Catch::literals; +using namespace sfz; TEST_CASE("[Opcode] Construction") { SECTION("Normal construction") { - sfz::Opcode opcode { "sample", "dummy" }; + Opcode opcode { "sample", "dummy" }; REQUIRE(opcode.opcode == "sample"); REQUIRE(opcode.lettersOnlyHash == hash("sample")); REQUIRE(opcode.parameters.empty()); @@ -21,7 +22,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with underscore") { - sfz::Opcode opcode { "sample_underscore", "dummy" }; + Opcode opcode { "sample_underscore", "dummy" }; REQUIRE(opcode.opcode == "sample_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore")); REQUIRE(opcode.parameters.empty()); @@ -30,7 +31,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with ampersand") { - sfz::Opcode opcode { "sample&_ampersand", "dummy" }; + Opcode opcode { "sample&_ampersand", "dummy" }; REQUIRE(opcode.opcode == "sample&_ampersand"); REQUIRE(opcode.lettersOnlyHash == hash("sample_ampersand")); REQUIRE(opcode.parameters.empty()); @@ -39,7 +40,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with multiple ampersands") { - sfz::Opcode opcode { "&sample&_ampersand&", "dummy" }; + Opcode opcode { "&sample&_ampersand&", "dummy" }; REQUIRE(opcode.opcode == "&sample&_ampersand&"); REQUIRE(opcode.lettersOnlyHash == hash("sample_ampersand")); REQUIRE(opcode.parameters.empty()); @@ -48,7 +49,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode") { - sfz::Opcode opcode { "sample123", "dummy" }; + Opcode opcode { "sample123", "dummy" }; REQUIRE(opcode.opcode == "sample123"); REQUIRE(opcode.lettersOnlyHash == hash("sample&")); REQUIRE(opcode.value == "dummy"); @@ -58,7 +59,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode with ampersand") { - sfz::Opcode opcode { "sample&123", "dummy" }; + Opcode opcode { "sample&123", "dummy" }; REQUIRE(opcode.opcode == "sample&123"); REQUIRE(opcode.lettersOnlyHash == hash("sample&")); REQUIRE(opcode.value == "dummy"); @@ -68,7 +69,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode with underscore") { - sfz::Opcode opcode { "sample_underscore123", "dummy" }; + Opcode opcode { "sample_underscore123", "dummy" }; REQUIRE(opcode.opcode == "sample_underscore123"); REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore&")); REQUIRE(opcode.value == "dummy"); @@ -77,7 +78,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode") { - sfz::Opcode opcode { "sample1_underscore", "dummy" }; + Opcode opcode { "sample1_underscore", "dummy" }; REQUIRE(opcode.opcode == "sample1_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_underscore")); REQUIRE(opcode.value == "dummy"); @@ -86,7 +87,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode") { - sfz::Opcode opcode { "sample123_underscore", "dummy" }; + Opcode opcode { "sample123_underscore", "dummy" }; REQUIRE(opcode.opcode == "sample123_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_underscore")); REQUIRE(opcode.value == "dummy"); @@ -96,7 +97,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode twice") { - sfz::Opcode opcode { "sample123_double44_underscore", "dummy" }; + Opcode opcode { "sample123_double44_underscore", "dummy" }; REQUIRE(opcode.opcode == "sample123_double44_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_double&_underscore")); REQUIRE(opcode.value == "dummy"); @@ -108,7 +109,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode twice, with a back parameter") { - sfz::Opcode opcode { "sample123_double44_underscore23", "dummy" }; + Opcode opcode { "sample123_double44_underscore23", "dummy" }; REQUIRE(opcode.opcode == "sample123_double44_underscore23"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_double&_underscore&")); REQUIRE(opcode.value == "dummy"); @@ -119,86 +120,86 @@ TEST_CASE("[Opcode] Construction") TEST_CASE("[Opcode] Note values") { - auto noteValue = sfz::readNoteValue("c-1"); + auto noteValue = readNoteValue("c-1"); REQUIRE(noteValue); REQUIRE(*noteValue == 0); - noteValue = sfz::readNoteValue("C-1"); + noteValue = readNoteValue("C-1"); REQUIRE(noteValue); REQUIRE(*noteValue == 0); - noteValue = sfz::readNoteValue("g9"); + noteValue = readNoteValue("g9"); REQUIRE(noteValue); REQUIRE(*noteValue == 127); - noteValue = sfz::readNoteValue("G9"); + noteValue = readNoteValue("G9"); REQUIRE(noteValue); REQUIRE(*noteValue == 127); - noteValue = sfz::readNoteValue("c#4"); + noteValue = readNoteValue("c#4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue(u8"c♯4"); + noteValue = readNoteValue(u8"c♯4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue("C#4"); + noteValue = readNoteValue("C#4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue(u8"C♯4"); + noteValue = readNoteValue(u8"C♯4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue("e#4"); + noteValue = readNoteValue("e#4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue(u8"e♯4"); + noteValue = readNoteValue(u8"e♯4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue("E#4"); + noteValue = readNoteValue("E#4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue(u8"E♯4"); + noteValue = readNoteValue(u8"E♯4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue("db4"); + noteValue = readNoteValue("db4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue(u8"d♭4"); + noteValue = readNoteValue(u8"d♭4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue("Db4"); + noteValue = readNoteValue("Db4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue(u8"D♭4"); + noteValue = readNoteValue(u8"D♭4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue("fb4"); + noteValue = readNoteValue("fb4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue(u8"f♭4"); + noteValue = readNoteValue(u8"f♭4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue("Fb4"); + noteValue = readNoteValue("Fb4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue(u8"F♭4"); + noteValue = readNoteValue(u8"F♭4"); REQUIRE(!noteValue); } TEST_CASE("[Opcode] Categories") { - REQUIRE(sfz::Opcode("sample", "").category == sfz::kOpcodeNormal); - REQUIRE(sfz::Opcode("amplitude_oncc11", "").category == sfz::kOpcodeOnCcN); - REQUIRE(sfz::Opcode("cutoff_cc22", "").category == sfz::kOpcodeOnCcN); - REQUIRE(sfz::Opcode("lfo01_pitch_curvecc33", "").category == sfz::kOpcodeCurveCcN); - REQUIRE(sfz::Opcode("pan_stepcc44", "").category == sfz::kOpcodeStepCcN); - REQUIRE(sfz::Opcode("noise_level_smoothcc55", "").category == sfz::kOpcodeSmoothCcN); + REQUIRE(Opcode("sample", "").category == kOpcodeNormal); + REQUIRE(Opcode("amplitude_oncc11", "").category == kOpcodeOnCcN); + REQUIRE(Opcode("cutoff_cc22", "").category == kOpcodeOnCcN); + REQUIRE(Opcode("lfo01_pitch_curvecc33", "").category == kOpcodeCurveCcN); + REQUIRE(Opcode("pan_stepcc44", "").category == kOpcodeStepCcN); + REQUIRE(Opcode("noise_level_smoothcc55", "").category == kOpcodeSmoothCcN); } TEST_CASE("[Opcode] Derived names") { - REQUIRE(sfz::Opcode("sample", "").getDerivedName(sfz::kOpcodeNormal) == "sample"); - REQUIRE(sfz::Opcode("cutoff_cc22", "").getDerivedName(sfz::kOpcodeNormal) == "cutoff"); - REQUIRE(sfz::Opcode("lfo01_pitch_curvecc33", "").getDerivedName(sfz::kOpcodeOnCcN) == "lfo01_pitch_oncc33"); - REQUIRE(sfz::Opcode("pan_stepcc44", "").getDerivedName(sfz::kOpcodeCurveCcN) == "pan_curvecc44"); - REQUIRE(sfz::Opcode("noise_level_smoothcc55", "").getDerivedName(sfz::kOpcodeStepCcN) == "noise_level_stepcc55"); - REQUIRE(sfz::Opcode("sample", "").getDerivedName(sfz::kOpcodeSmoothCcN, 66) == "sample_smoothcc66"); + REQUIRE(Opcode("sample", "").getDerivedName(kOpcodeNormal) == "sample"); + REQUIRE(Opcode("cutoff_cc22", "").getDerivedName(kOpcodeNormal) == "cutoff"); + REQUIRE(Opcode("lfo01_pitch_curvecc33", "").getDerivedName(kOpcodeOnCcN) == "lfo01_pitch_oncc33"); + REQUIRE(Opcode("pan_stepcc44", "").getDerivedName(kOpcodeCurveCcN) == "pan_curvecc44"); + REQUIRE(Opcode("noise_level_smoothcc55", "").getDerivedName(kOpcodeStepCcN) == "noise_level_stepcc55"); + REQUIRE(Opcode("sample", "").getDerivedName(kOpcodeSmoothCcN, 66) == "sample_smoothcc66"); } TEST_CASE("[Opcode] Normalization") { // *_ccN - REQUIRE(sfz::Opcode("foo_cc7", "").cleanUp(sfz::kOpcodeScopeRegion).opcode == "foo_oncc7"); - REQUIRE(sfz::Opcode("foo_cc7", "").cleanUp(sfz::kOpcodeScopeControl).opcode == "foo_cc7"); + REQUIRE(Opcode("foo_cc7", "").cleanUp(kOpcodeScopeRegion).opcode == "foo_oncc7"); + REQUIRE(Opcode("foo_cc7", "").cleanUp(kOpcodeScopeControl).opcode == "foo_cc7"); // @@ -274,8 +275,8 @@ TEST_CASE("[Opcode] Normalization") for (auto pair : regionSpecific) { absl::string_view input = pair.first; absl::string_view expected = pair.second; - REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeRegion).opcode == expected); - REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeGeneric).opcode == input); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeRegion).opcode == expected); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeGeneric).opcode == input); } // @@ -288,42 +289,221 @@ TEST_CASE("[Opcode] Normalization") for (auto pair : controlSpecific) { absl::string_view input = pair.first; absl::string_view expected = pair.second; - REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeControl).opcode == expected); - REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeGeneric).opcode == input); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeControl).opcode == expected); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeGeneric).opcode == input); } // case - REQUIRE(sfz::Opcode("SaMpLe", "").cleanUp(sfz::kOpcodeScopeRegion).opcode == "sample"); + REQUIRE(Opcode("SaMpLe", "").cleanUp(kOpcodeScopeRegion).opcode == "sample"); } -TEST_CASE("[Opcode] readOpcode") +TEST_CASE("[Opcode] opcode read (uint8_t)") { - REQUIRE( sfz::readOpcode("16", sfz::Range(0, 100)).value() == 16 ); - REQUIRE( sfz::readOpcode("+16", sfz::Range(0, 100)).value() == 16 ); - REQUIRE( sfz::readOpcode("110", sfz::Range(0, 100)).value() == 100 ); - REQUIRE( sfz::readOpcode("-1", sfz::Range(0, 100)).value() == 0 ); - REQUIRE( sfz::readOpcode("12.5", sfz::Range(-100, 100)).value() == 12 ); - REQUIRE( sfz::readOpcode("+12.5", sfz::Range(-100, 100)).value() == 12 ); - REQUIRE( sfz::readOpcode("-40", sfz::Range(-100, 100)).value() == -40 ); - REQUIRE( sfz::readOpcode("-140", sfz::Range(-100, 100)).value() == -100 ); - REQUIRE( sfz::readOpcode("12.5", sfz::Range(0.0f, 100.0f)).value() == 12.5_a ); - REQUIRE( sfz::readOpcode("+12.5", sfz::Range(0.0f, 100.0f)).value() == 12.5_a ); - REQUIRE( sfz::readOpcode("-22.5", sfz::Range(-20.0f, 100.0f)).value() == -20.0_a ); - REQUIRE( sfz::readOpcode("150.5", sfz::Range(-20.0f, 100.0f)).value() == 100.0_a ); - REQUIRE( sfz::readOpcode("50.25garbage", sfz::Range(-20.0f, 100.0f)).value() == 50.25_a ); - REQUIRE( sfz::readOpcode("50.25garbage", sfz::Range(-20, 100)).value() == 50 ); - REQUIRE( !sfz::readOpcode("garbage50.25", sfz::Range(-20, 100)) ); - REQUIRE( !sfz::readOpcode("garbage", sfz::Range(-20, 100)) ); + SECTION("Basic") + { + Opcode opcode { "", "16" }; + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 16); + } + + SECTION("Sign") + { + Opcode opcode { "", "+16" }; + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 16); + } + + SECTION("Ignore") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0, Range(0, 100), kIgnoreOOB }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Clamp upper") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0, Range(0, 100), kEnforceUpperBound }; + REQUIRE( opcode.read(spec) == 100 ); + } + + SECTION("Clamp lower") + { + Opcode opcode { "", "10" }; + OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == 20 ); + } + + SECTION("Floating point") + { + Opcode opcode { "", "10.5" }; + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 10 ); + } + + SECTION("Text after") + { + Opcode opcode { "", "10garbage" }; + OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == 20 ); + } + + SECTION("Text before") + { + Opcode opcode { "", "garbage10" }; + OpcodeSpec spec { 0, Range(20, 100), 0 }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Can be note") + { + Opcode opcode { "", "c4" }; + OpcodeSpec spec { 0, Range(20, 100), kCanBeNote }; + REQUIRE( opcode.read(spec) == 60 ); + } +} + +TEST_CASE("[Opcode] opcode read (int)") +{ + SECTION("Basic") + { + Opcode opcode { "", "16" }; + OpcodeSpec spec { 0, Range(-100, 100), 0 }; + REQUIRE( opcode.read(spec) == 16); + } + + SECTION("Sign") + { + Opcode opcode { "", "+16" }; + OpcodeSpec spec { 0, Range(-100, 100), 0 }; + REQUIRE( opcode.read(spec) == 16); + } + + SECTION("Sign") + { + Opcode opcode { "", "-16" }; + OpcodeSpec spec { 0, Range(-100, 100), 0 }; + REQUIRE( opcode.read(spec) == -16); + } + + SECTION("Ignore") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0, Range(-100, 100), kIgnoreOOB }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Clamp upper") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0, Range(-100, 100), kEnforceUpperBound }; + REQUIRE( opcode.read(spec) == 100 ); + } + + SECTION("Clamp lower") + { + Opcode opcode { "", "-110" }; + OpcodeSpec spec { 0, Range(-100, 100), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == -100 ); + } + + SECTION("Floating point") + { + Opcode opcode { "", "10.5" }; + OpcodeSpec spec { 0, Range(-100, 100), 0 }; + REQUIRE( opcode.read(spec) == 10 ); + } + + SECTION("Text after") + { + Opcode opcode { "", "10garbage" }; + OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == 20 ); + } + + SECTION("Text before") + { + Opcode opcode { "", "garbage10" }; + OpcodeSpec spec { 0, Range(20, 100), 0 }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Can be note") + { + Opcode opcode { "", "c4" }; + OpcodeSpec spec { 0, Range(20, 100), kCanBeNote }; + REQUIRE( opcode.read(spec) == 60 ); + } +} + + +TEST_CASE("[Opcode] opcode read (float)") +{ + SECTION("Basic") + { + Opcode opcode { "", "16.4" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; + REQUIRE( opcode.read(spec) == 16.4_a); + } + + SECTION("Plus sign") + { + Opcode opcode { "", "+16.4" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; + REQUIRE( opcode.read(spec) == 16.4_a); + } + + SECTION("Minus sign") + { + Opcode opcode { "", "-16.4" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; + REQUIRE( opcode.read(spec) == -16.4_a); + } + + SECTION("Ignore") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Clamp upper") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), kEnforceUpperBound }; + REQUIRE( opcode.read(spec) == 100.0f ); + } + + SECTION("Clamp lower") + { + Opcode opcode { "", "-110" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == -100.0f ); + } + + SECTION("Text after") + { + Opcode opcode { "", "10.5garbage" }; + OpcodeSpec spec { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == 10.5f ); + } + + SECTION("Text before") + { + Opcode opcode { "", "garbage10" }; + OpcodeSpec spec { 0.0f, Range(0.0f, 100.0f), 0 }; + REQUIRE( !opcode.read(spec) ); + } } TEST_CASE("[Opcode] readBooleanFromOpcode") { - REQUIRE(sfz::readBooleanFromOpcode({"", "1"}) == true); - REQUIRE(sfz::readBooleanFromOpcode({"", "0"}) == false); - REQUIRE(sfz::readBooleanFromOpcode({"", "777"}) == true); - REQUIRE(sfz::readBooleanFromOpcode({"", "on"}) == true); - REQUIRE(sfz::readBooleanFromOpcode({"", "off"}) == false); - REQUIRE(sfz::readBooleanFromOpcode({"", "On"}) == true); - REQUIRE(sfz::readBooleanFromOpcode({"", "oFf"}) == false); + REQUIRE(readBooleanFromOpcode({"", "1"}) == true); + REQUIRE(readBooleanFromOpcode({"", "0"}) == false); + REQUIRE(readBooleanFromOpcode({"", "777"}) == true); + REQUIRE(readBooleanFromOpcode({"", "on"}) == true); + REQUIRE(readBooleanFromOpcode({"", "off"}) == false); + REQUIRE(readBooleanFromOpcode({"", "On"}) == true); + REQUIRE(readBooleanFromOpcode({"", "oFf"}) == false); } diff --git a/tests/RegionValueComputationsT.cpp b/tests/RegionValueComputationsT.cpp index f3b1abca..39412b95 100644 --- a/tests/RegionValueComputationsT.cpp +++ b/tests/RegionValueComputationsT.cpp @@ -299,15 +299,15 @@ TEST_CASE("[Region] rt_decay") region.parseOpcode({ "rt_decay", "10" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 1.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value - 1.0f).margin(0.1) ); region.parseOpcode({ "rt_decay", "20" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 2.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value - 2.0f).margin(0.1) ); region.parseOpcode({ "trigger", "attack" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value).margin(0.1) ); } TEST_CASE("[Region] Base delay") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index f0274fd1..0e2a38c0 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -250,7 +250,7 @@ TEST_CASE("[Values] Count") std::vector expected { "/region0/count,N : { }", "/region1/count,h : { 2 }", - "/region2/count,h : { 0 }", + "/region2/count,N : { }", }; REQUIRE(messageList == expected); } @@ -324,6 +324,7 @@ TEST_CASE("[Values] Loop range") Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav sample=kick.wav loop_start=10 loop_end=100 sample=kick.wav loopstart=10 loopend=100 sample=kick.wav loop_start=-1 loopend=-100 @@ -331,10 +332,12 @@ TEST_CASE("[Values] Loop range") synth.dispatchMessage(client, 0, "/region0/loop_range", "", nullptr); synth.dispatchMessage(client, 0, "/region1/loop_range", "", nullptr); synth.dispatchMessage(client, 0, "/region2/loop_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/loop_range", "", nullptr); std::vector expected { - "/region0/loop_range,hh : { 10, 100 }", + "/region0/loop_range,hh : { 0, 44011 }", // Default loop points in the file "/region1/loop_range,hh : { 10, 100 }", - "/region2/loop_range,hh : { 0, 0 }", + "/region2/loop_range,hh : { 10, 100 }", + "/region3/loop_range,hh : { 0, 44011 }", }; REQUIRE(messageList == expected); } @@ -487,7 +490,7 @@ TEST_CASE("[Values] Key range") "/region1/key_range,ii : { 34, 60 }", "/region2/key_range,ii : { 60, 83 }", "/region3/key_range,ii : { 0, 60 }", - "/region4/key_range,ii : { 0, 0 }", + "/region4/key_range,ii : { 0, 127 }", "/region0/pitch_keycenter,i : { 60 }", "/region5/pitch_keycenter,i : { 32 }", // "/region6/pitch_keycenter,i : { 60 }", @@ -497,6 +500,32 @@ TEST_CASE("[Values] Key range") REQUIRE(messageList == expected); } +TEST_CASE("[Values] Triggers on note") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav hikey=-1 + sample=kick.wav key=-1 + sample=kick.wav hikey=-1 lokey=12 + )"); + synth.dispatchMessage(client, 0, "/region0/trigger_on_note", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/trigger_on_note", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/trigger_on_note", "", nullptr); + // TODO: Double check with Sforzando/rgc + synth.dispatchMessage(client, 0, "/region3/trigger_on_note", "", nullptr); + std::vector expected { + "/region0/trigger_on_note,T : { }", + "/region1/trigger_on_note,F : { }", + "/region2/trigger_on_note,F : { }", + "/region3/trigger_on_note,T : { }", + }; + REQUIRE(messageList == expected); +} + TEST_CASE("[Values] Velocity range") { Synth synth; @@ -517,7 +546,7 @@ TEST_CASE("[Values] Velocity range") "/region0/vel_range,ff : { 0, 1 }", "/region1/vel_range,ff : { 0.267717, 0.472441 }", "/region2/vel_range,ff : { 0, 0.472441 }", - "/region3/vel_range,ff : { 0, 0 }", + "/region3/vel_range,ff : { 0, 1 }", }; REQUIRE(messageList == expected); } @@ -542,7 +571,7 @@ TEST_CASE("[Values] Bend range") "/region0/bend_range,ff : { -1, 1 }", "/region1/bend_range,ff : { 0.108778, 0.24417 }", "/region2/bend_range,ff : { -0.108778, 0.108778 }", - "/region3/bend_range,ff : { -1, -1 }", + "/region3/bend_range,ff : { -1, 1 }", }; REQUIRE(messageList == expected); } @@ -572,7 +601,7 @@ TEST_CASE("[Values] CC condition range") "/region1/cc_range1,ff : { 0, 0.425197 }", "/region2/cc_range1,ff : { 0, 0.425197 }", "/region2/cc_range2,ff : { 0.015748, 0.0787402 }", - "/region3/cc_range1,ff : { 0, 0 }", + "/region3/cc_range1,ff : { 0.0787402, 1 }", }; REQUIRE(messageList == expected); } @@ -595,7 +624,7 @@ TEST_CASE("[Values] CC condition range") "/region1/cc_range1,ff : { 0, 0.1 }", "/region2/cc_range1,ff : { 0, 0.1 }", "/region2/cc_range2,ff : { 0.1, 0.2 }", - "/region3/cc_range1,ff : { 0, 0 }", + "/region3/cc_range1,ff : { 0.1, 1 }", }; REQUIRE(messageList == expected); } @@ -618,7 +647,7 @@ TEST_CASE("[Values] CC condition range") "/region1/cc_range1,ff : { 0, 0.1 }", "/region2/cc_range1,ff : { 0, 0.1 }", "/region2/cc_range2,ff : { 0.1, 0.2 }", - "/region3/cc_range1,ff : { 0, 0 }", + "/region3/cc_range1,ff : { 0.1, 1 }", }; REQUIRE(messageList == expected); } @@ -708,19 +737,17 @@ TEST_CASE("[Values] Upswitch") )"); synth.dispatchMessage(client, 0, "/region0/sw_up", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sw_up", "", nullptr); - // TODO: activate for the new region parser; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sw_up", "", nullptr); - // synth.dispatchMessage(client, 0, "/region3/sw_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sw_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sw_up", "", nullptr); synth.dispatchMessage(client, 0, "/region4/sw_up", "", nullptr); - // TODO: activate for the new region parser; ignore the second value - // synth.dispatchMessage(client, 0, "/region5/sw_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/sw_up", "", nullptr); std::vector expected { "/region0/sw_up,N : { }", "/region1/sw_up,i : { 16 }", - // "/region2/sw_up,N : { }", - // "/region3/sw_up,N : { }", + "/region2/sw_up,N : { }", + "/region3/sw_up,N : { }", "/region4/sw_up,i : { 60 }", - // "/region5/sw_up,i : { 64 }", + "/region5/sw_up,i : { 64 }", }; REQUIRE(messageList == expected); } @@ -741,19 +768,17 @@ TEST_CASE("[Values] Downswitch") )"); synth.dispatchMessage(client, 0, "/region0/sw_down", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sw_down", "", nullptr); - // TODO: activate for the new region parser; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sw_down", "", nullptr); - // synth.dispatchMessage(client, 0, "/region3/sw_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sw_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sw_down", "", nullptr); synth.dispatchMessage(client, 0, "/region4/sw_down", "", nullptr); - // TODO: activate for the new region parser; ignore the second value - // synth.dispatchMessage(client, 0, "/region5/sw_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/sw_down", "", nullptr); std::vector expected { "/region0/sw_down,N : { }", "/region1/sw_down,i : { 16 }", - // "/region2/sw_down,N : { }", - // "/region3/sw_down,N : { }", + "/region2/sw_down,N : { }", + "/region3/sw_down,N : { }", "/region4/sw_down,i : { 60 }", - // "/region5/sw_down,i : { 64 }", + "/region5/sw_down,i : { 64 }", }; REQUIRE(messageList == expected); } @@ -774,19 +799,17 @@ TEST_CASE("[Values] Previous keyswitch") )"); synth.dispatchMessage(client, 0, "/region0/sw_previous", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sw_previous", "", nullptr); - // TODO: activate for the new region parser; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sw_previous", "", nullptr); - // synth.dispatchMessage(client, 0, "/region3/sw_previous", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sw_previous", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sw_previous", "", nullptr); synth.dispatchMessage(client, 0, "/region4/sw_previous", "", nullptr); - // TODO: activate for the new region parser; ignore the second value - // synth.dispatchMessage(client, 0, "/region5/sw_previous", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/sw_previous", "", nullptr); std::vector expected { "/region0/sw_previous,N : { }", "/region1/sw_previous,i : { 16 }", - // "/region2/sw_previous,N : { }", - // "/region3/sw_previous,N : { }", + "/region2/sw_previous,N : { }", + "/region3/sw_previous,N : { }", "/region4/sw_previous,i : { 60 }", - // "/region5/sw_previous,i : { 64 }", + "/region5/sw_previous,i : { 64 }", }; REQUIRE(messageList == expected); } @@ -838,7 +861,7 @@ TEST_CASE("[Values] Aftertouch range") "/region0/chanaft_range,ii : { 0, 127 }", "/region1/chanaft_range,ii : { 34, 60 }", "/region2/chanaft_range,ii : { 0, 60 }", - "/region3/chanaft_range,ii : { 0, 0 }", + "/region3/chanaft_range,ii : { 20, 127 }", "/region4/chanaft_range,ii : { 10, 10 }", }; REQUIRE(messageList == expected); @@ -894,7 +917,7 @@ TEST_CASE("[Values] Rand range") "/region0/rand_range,ff : { 0, 1 }", "/region1/rand_range,ff : { 0.2, 0.4 }", "/region2/rand_range,ff : { 0, 0.4 }", - "/region3/rand_range,ff : { 0, 0 }", + "/region3/rand_range,ff : { 0.2, 1 }", "/region4/rand_range,ff : { 0.1, 0.1 }", }; REQUIRE(messageList == expected); @@ -1582,16 +1605,15 @@ TEST_CASE("[Values] Crossfade key range") )"); synth.dispatchMessage(client, 0, "/region0/xfin_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region1/xfin_key_range", "", nullptr); - // TODO: activate for the new region parser ; parse note value - // synth.dispatchMessage(client, 0, "/region2/xfin_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xfin_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region3/xfin_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region4/xfin_key_range", "", nullptr); std::vector expected { "/region0/xfin_key_range,ii : { 0, 0 }", "/region1/xfin_key_range,ii : { 10, 40 }", - // "/region2/xfin_key_range,ii : { 60, 83 }", + "/region2/xfin_key_range,ii : { 60, 83 }", "/region3/xfin_key_range,ii : { 0, 40 }", - "/region4/xfin_key_range,ii : { 10, 127 }", + "/region4/xfin_key_range,ii : { 10, 10 }", }; REQUIRE(messageList == expected); } @@ -1607,15 +1629,14 @@ TEST_CASE("[Values] Crossfade key range") )"); synth.dispatchMessage(client, 0, "/region0/xfout_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region1/xfout_key_range", "", nullptr); - // TODO: activate for the new region parser ; parse note value - // synth.dispatchMessage(client, 0, "/region2/xfout_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xfout_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region3/xfout_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region4/xfout_key_range", "", nullptr); std::vector expected { "/region0/xfout_key_range,ii : { 127, 127 }", "/region1/xfout_key_range,ii : { 10, 40 }", - // "/region2/xfout_key_range,ii : { 60, 83 }", - "/region3/xfout_key_range,ii : { 0, 40 }", + "/region2/xfout_key_range,ii : { 60, 83 }", + "/region3/xfout_key_range,ii : { 40, 40 }", "/region4/xfout_key_range,ii : { 10, 127 }", }; REQUIRE(messageList == expected); @@ -1968,13 +1989,13 @@ TEST_CASE("[Values] Pitch/Tune") sample=kick.wav pitch=4.2 sample=kick.wav tune=-200 )"); - synth.dispatchMessage(client, 0, "/region0/tune", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/tune", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/tune", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch", "", nullptr); std::vector expected { - "/region0/tune,f : { 0 }", - "/region1/tune,f : { 4.2 }", - "/region2/tune,f : { -200 }", + "/region0/pitch,f : { 0 }", + "/region1/pitch,f : { 4.2 }", + "/region2/pitch,f : { -200 }", }; REQUIRE(messageList == expected); } @@ -1983,16 +2004,16 @@ TEST_CASE("[Values] Pitch/Tune") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( sample=kick.wav - sample=kick.wav tune_oncc42=4.2 + sample=kick.wav pitch_oncc42=4.2 sample=kick.wav pitch_oncc2=-10 )"); - synth.dispatchMessage(client, 0, "/region0/tune_cc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/tune_cc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/tune_cc2", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_cc2", "", nullptr); std::vector expected { - "/region0/tune_cc42,N : { }", - "/region1/tune_cc42,f : { 4.2 }", - "/region2/tune_cc2,f : { -10 }", + "/region0/pitch_cc42,N : { }", + "/region1/pitch_cc42,f : { 4.2 }", + "/region2/pitch_cc2,f : { -10 }", }; REQUIRE(messageList == expected); } @@ -2001,33 +2022,33 @@ TEST_CASE("[Values] Pitch/Tune") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( sample=kick.wav - sample=kick.wav tune_stepcc42=4.2 - sample=kick.wav tune_smoothcc42=4 - sample=kick.wav tune_curvecc42=2 - sample=kick.wav tune_stepcc42=-1 - sample=kick.wav tune_smoothcc42=-4 - sample=kick.wav tune_curvecc42=300 + sample=kick.wav pitch_stepcc42=4.2 + sample=kick.wav pitch_smoothcc42=4 + sample=kick.wav pitch_curvecc42=2 + sample=kick.wav pitch_stepcc42=-1 + sample=kick.wav pitch_smoothcc42=-4 + sample=kick.wav pitch_curvecc42=300 )"); - synth.dispatchMessage(client, 0, "/region0/tune_stepcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region0/tune_smoothcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region0/tune_curvecc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/tune_stepcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/tune_smoothcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region3/tune_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/pitch_curvecc42", "", nullptr); // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region4/tune_stepcc42", "", nullptr); - // synth.dispatchMessage(client, 0, "/region5/tune_smoothcc42", "", nullptr); - // synth.dispatchMessage(client, 0, "/region6/tune_curvecc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region4/pitch_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/pitch_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/pitch_curvecc42", "", nullptr); std::vector expected { - "/region0/tune_stepcc42,N : { }", - "/region0/tune_smoothcc42,N : { }", - "/region0/tune_curvecc42,N : { }", - "/region1/tune_stepcc42,f : { 4.2 }", - "/region2/tune_smoothcc42,i : { 4 }", - "/region3/tune_curvecc42,i : { 2 }", - // "/region4/tune_stepcc42,N : { }", - // "/region5/tune_smoothcc42,N : { }", - // "/region6/tune_curvecc42,N : { }", + "/region0/pitch_stepcc42,N : { }", + "/region0/pitch_smoothcc42,N : { }", + "/region0/pitch_curvecc42,N : { }", + "/region1/pitch_stepcc42,f : { 4.2 }", + "/region2/pitch_smoothcc42,i : { 4 }", + "/region3/pitch_curvecc42,i : { 2 }", + // "/region4/pitch_stepcc42,N : { }", + // "/region5/pitch_smoothcc42,N : { }", + // "/region6/pitch_curvecc42,N : { }", }; REQUIRE(messageList == expected); } @@ -2043,26 +2064,26 @@ TEST_CASE("[Values] Pitch/Tune") sample=kick.wav pitch_smoothcc42=-4 sample=kick.wav pitch_curvecc42=300 )"); - synth.dispatchMessage(client, 0, "/region0/tune_stepcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region0/tune_smoothcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region0/tune_curvecc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/tune_stepcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/tune_smoothcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region3/tune_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/pitch_curvecc42", "", nullptr); // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region4/tune_stepcc42", "", nullptr); - // synth.dispatchMessage(client, 0, "/region5/tune_smoothcc42", "", nullptr); - // synth.dispatchMessage(client, 0, "/region6/tune_curvecc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region4/pitch_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/pitch_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/pitch_curvecc42", "", nullptr); std::vector expected { - "/region0/tune_stepcc42,N : { }", - "/region0/tune_smoothcc42,N : { }", - "/region0/tune_curvecc42,N : { }", - "/region1/tune_stepcc42,f : { 4.2 }", - "/region2/tune_smoothcc42,i : { 4 }", - "/region3/tune_curvecc42,i : { 2 }", - // "/region4/tune_stepcc42,N : { }", - // "/region5/tune_smoothcc42,N : { }", - // "/region6/tune_curvecc42,N : { }", + "/region0/pitch_stepcc42,N : { }", + "/region0/pitch_smoothcc42,N : { }", + "/region0/pitch_curvecc42,N : { }", + "/region1/pitch_stepcc42,f : { 4.2 }", + "/region2/pitch_smoothcc42,i : { 4 }", + "/region3/pitch_curvecc42,i : { 2 }", + // "/region4/pitch_stepcc42,N : { }", + // "/region5/pitch_smoothcc42,N : { }", + // "/region6/pitch_curvecc42,N : { }", }; REQUIRE(messageList == expected); } @@ -2093,17 +2114,17 @@ TEST_CASE("[Values] Bend behavior") synth.dispatchMessage(client, 0, "/region2/bend_step", "", nullptr); synth.dispatchMessage(client, 0, "/region2/bend_smooth", "", nullptr); std::vector expected { - "/region0/bend_up,i : { 200 }", - "/region0/bend_down,i : { -200 }", - "/region0/bend_step,i : { 1 }", + "/region0/bend_up,f : { 200 }", + "/region0/bend_down,f : { -200 }", + "/region0/bend_step,f : { 1 }", "/region0/bend_smooth,i : { 0 }", - "/region1/bend_up,i : { 100 }", - "/region1/bend_down,i : { -400 }", - "/region1/bend_step,i : { 10 }", + "/region1/bend_up,f : { 100 }", + "/region1/bend_down,f : { -400 }", + "/region1/bend_step,f : { 10 }", "/region1/bend_smooth,i : { 10 }", - "/region2/bend_up,i : { -100 }", - "/region2/bend_down,i : { 400 }", - "/region2/bend_step,i : { 1 }", + "/region2/bend_up,f : { -100 }", + "/region2/bend_down,f : { 400 }", + "/region2/bend_step,f : { 1 }", "/region2/bend_smooth,i : { 0 }", }; REQUIRE(messageList == expected); @@ -2162,7 +2183,7 @@ TEST_CASE("[Values] ampeg") "/region0/ampeg_release,f : { 0.001 }", "/region0/ampeg_start,f : { 0 }", "/region0/ampeg_sustain,f : { 100 }", - "/region0/ampeg_depth,i : { 0 }", + "/region0/ampeg_depth,f : { 0 }", "/region1/ampeg_attack,f : { 1 }", "/region1/ampeg_delay,f : { 2 }", "/region1/ampeg_decay,f : { 3 }", @@ -2170,7 +2191,7 @@ TEST_CASE("[Values] ampeg") "/region1/ampeg_release,f : { 5 }", "/region1/ampeg_start,f : { 6 }", "/region1/ampeg_sustain,f : { 7 }", - "/region1/ampeg_depth,i : { 0 }", + "/region1/ampeg_depth,f : { 0 }", // "/region2/ampeg_attack,f : { 0 }", // "/region2/ampeg_delay,f : { 0 }", // "/region2/ampeg_decay,f : { 0 }", @@ -2178,7 +2199,7 @@ TEST_CASE("[Values] ampeg") // "/region2/ampeg_release,f : { 0.001 }", // "/region2/ampeg_start,f : { 0 }", // "/region2/ampeg_sustain,f : { 100 }", - // "/region2/ampeg_depth,i : { 0 }", + // "/region2/ampeg_depth,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -2213,14 +2234,14 @@ TEST_CASE("[Values] ampeg") "/region0/ampeg_vel2hold,f : { 0 }", "/region0/ampeg_vel2release,f : { 0 }", "/region0/ampeg_vel2sustain,f : { 0 }", - "/region0/ampeg_vel2depth,i : { 0 }", + "/region0/ampeg_vel2depth,f : { 0 }", "/region1/ampeg_vel2attack,f : { 1 }", "/region1/ampeg_vel2delay,f : { 2 }", "/region1/ampeg_vel2decay,f : { 3 }", "/region1/ampeg_vel2hold,f : { 4 }", "/region1/ampeg_vel2release,f : { 5 }", "/region1/ampeg_vel2sustain,f : { 7 }", - "/region1/ampeg_vel2depth,i : { 0 }", + "/region1/ampeg_vel2depth,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -2420,18 +2441,102 @@ TEST_CASE("[Values] Oscillator phase") )"); synth.dispatchMessage(client, 0, "/region0/oscillator_phase", "", nullptr); synth.dispatchMessage(client, 0, "/region1/oscillator_phase", "", nullptr); - // TODO: activate for the new region parser ; properly wrap - // synth.dispatchMessage(client, 0, "/region2/oscillator_phase", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/oscillator_phase", "", nullptr); synth.dispatchMessage(client, 0, "/region3/oscillator_phase", "", nullptr); std::vector expected { "/region0/oscillator_phase,f : { 0 }", "/region1/oscillator_phase,f : { 0.1 }", - // "/region2/oscillator_phase,f : { 0.1 }", + "/region2/oscillator_phase,f : { 0.1 }", "/region3/oscillator_phase,f : { -1 }", }; REQUIRE(messageList == expected); } +TEST_CASE("[Values] Oscillator quality") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav oscillator_quality=2 + sample=kick.wav oscillator_quality=0 oscillator_quality=-2 + )"); + synth.dispatchMessage(client, 0, "/region0/oscillator_quality", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/oscillator_quality", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/oscillator_quality", "", nullptr); + std::vector expected { + "/region0/oscillator_quality,N : { }", + "/region1/oscillator_quality,i : { 2 }", + "/region2/oscillator_quality,i : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Oscillator mode/multi") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav oscillator_mode=2 + sample=kick.wav oscillator_mode=1 oscillator_mode=-2 + sample=kick.wav oscillator_multi=9 + sample=kick.wav oscillator_multi=-2 + )"); + synth.dispatchMessage(client, 0, "/region0/oscillator_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/oscillator_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/oscillator_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/oscillator_multi", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/oscillator_multi", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/oscillator_multi", "", nullptr); + std::vector expected { + "/region0/oscillator_mode,i : { 0 }", + "/region1/oscillator_mode,i : { 2 }", + "/region2/oscillator_mode,i : { 1 }", + "/region0/oscillator_multi,i : { 1 }", + "/region3/oscillator_multi,i : { 9 }", + "/region4/oscillator_multi,i : { 1 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Oscillator detune/mod depth") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav oscillator_detune=9.2 + sample=kick.wav oscillator_detune=-1200.2 + sample=kick.wav oscillator_mod_depth=1564.75 + sample=kick.wav oscillator_mod_depth=-2.2 + )"); + synth.dispatchMessage(client, 0, "/region0/oscillator_detune", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/oscillator_detune", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/oscillator_detune", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/oscillator_mod_depth", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/oscillator_mod_depth", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/oscillator_mod_depth", "", nullptr); + std::vector expected { + "/region0/oscillator_detune,f : { 0 }", + "/region1/oscillator_detune,f : { 9.2 }", + "/region2/oscillator_detune,f : { -1200.2 }", + "/region0/oscillator_mod_depth,f : { 0 }", + "/region3/oscillator_mod_depth,f : { 1564.75 }", + "/region4/oscillator_mod_depth,f : { 0 }", + }; + REQUIRE(messageList == expected); +} + TEST_CASE("[Values] Effect sends") { Synth synth; diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index b9bf7ab8..fa5cb076 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -572,14 +572,14 @@ TEST_CASE("[Synth] sample quality") // default sample quality synth.noteOn(0, 60, 100); REQUIRE(synth.getNumActiveVoices() == 1); - REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality); + REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality.value); synth.allSoundOff(); // default sample quality, freewheeling synth.enableFreeWheeling(); synth.noteOn(0, 60, 100); REQUIRE(synth.getNumActiveVoices() == 1); - REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQualityInFreewheelingMode); + REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::freewheelingQuality); synth.allSoundOff(); synth.disableFreeWheeling(); @@ -1085,7 +1085,7 @@ TEST_CASE("[Synth] Used CCs") locc4=64 hicc67=32 pan_cc5=200 sample=*sine width_cc98=200 sample=*sine position_cc42=200 pitch_oncc56=200 sample=*sine - start_locc44=200 hikey=-1 sample=*sine + start_locc44=120 hikey=-1 sample=*sine )"); auto usedCCs = synth.getUsedCCs(); REQUIRE( usedCCs.test(1) ); diff --git a/tests/TestFiles/note_offset.sfz b/tests/TestFiles/note_offset.sfz deleted file mode 100644 index 40760e49..00000000 --- a/tests/TestFiles/note_offset.sfz +++ /dev/null @@ -1,12 +0,0 @@ - note_offset=1 - key=63 sample=*sine - lokey=50 hikey=55 pitch_keycenter=50 sample=*sine - lokey=40 hikey=44 pitch_keycenter=40 xfin_lokey=36 xfin_hikey=40 xfout_lokey=44 xfout_hikey=48 sample=*sine - note_offset=-1 - key=63 sw_lokey=24 sw_hikey=28 sw_last=25 sw_up=25 sw_down=25 sw_previous=62 sample=*sine - note_offset=1 octave_offset=1 - key=63 sample=*sine - note_offset=-1 octave_offset=-1 - key=63 sample=*sine - // Check that this does not reset either note or octave offset - key=63 sample=*sine From 24f77f46ebcee89014d283ac6064444e7fc735ad Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 22 Nov 2020 20:54:58 +0100 Subject: [PATCH 243/668] Superfluous std::move --- src/sfizz/Region.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index d84fbc52..57848885 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -34,7 +34,7 @@ bool extendIfNecessary(std::vector& vec, unsigned size, unsigned defaultCapac } sfz::Region::Region(int regionNumber, const MidiState& midiState, absl::string_view defaultPath) -: id{regionNumber}, midiState(midiState), defaultPath(std::move(defaultPath)) +: id{regionNumber}, midiState(midiState), defaultPath(defaultPath) { ccSwitched.set(); From 0ab836787f564b3a2e1b714dd13b4fe273aa967e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 12 Dec 2020 14:34:00 +0100 Subject: [PATCH 244/668] Add new sources to makefile --- common.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/common.mk b/common.mk index 81d513df..ba379cfe 100644 --- a/common.mk +++ b/common.mk @@ -50,6 +50,7 @@ SFIZZ_SOURCES = \ src/sfizz/AudioReader.cpp \ src/sfizz/BeatClock.cpp \ src/sfizz/Curve.cpp \ + src/sfizz/Defaults.cpp \ src/sfizz/effects/Apan.cpp \ src/sfizz/Effects.cpp \ src/sfizz/modulations/ModId.cpp \ From 17594241e7d5d6fca5990e39d576d9f948683070 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 30 Dec 2020 01:16:39 +0100 Subject: [PATCH 245/668] Read booleans as a template overload --- src/sfizz/Defaults.cpp | 7 +++++++ src/sfizz/Defaults.h | 26 +++++++++++++++----------- src/sfizz/FlexEGDescription.h | 2 +- src/sfizz/Opcode.cpp | 16 ++++++++++++++++ src/sfizz/Range.h | 4 +++- src/sfizz/Region.cpp | 17 +++++------------ src/sfizz/Region.h | 9 ++++----- src/sfizz/effects/Compressor.cpp | 5 ++--- src/sfizz/effects/Gate.cpp | 6 ++---- tests/FilesT.cpp | 20 ++++++++++---------- tests/RegionValuesT.cpp | 4 ++-- 11 files changed, 67 insertions(+), 49 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index b7a77769..aa768dd7 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -14,6 +14,7 @@ extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, u extern const OpcodeSpec sampleCount { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopRange { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec oscillator { OscillatorEnabled::Auto, Range(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 }; extern const OpcodeSpec oscillatorPhase { 0.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), kIgnoreOOB }; extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), kIgnoreOOB }; @@ -37,6 +38,8 @@ extern const OpcodeSpec smoothCC { 0, Range(0, 100), kIgnoreOO extern const OpcodeSpec curveCC { 0, Range(0, 255), kIgnoreOOB }; extern const OpcodeSpec sustainCC { 64, Range(0, 127), kIgnoreOOB }; extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; +extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; extern const OpcodeSpec bpm { 0.0f, Range(0.0f, 500.0f), kEnforceLowerBound }; extern const OpcodeSpec sequence { 1, Range(1, 100), kIgnoreOOB }; extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; @@ -57,6 +60,7 @@ extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), kEnforceLowerBound }; +extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), kEnforceLowerBound }; extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceLowerBound | kEnforceUpperBound }; extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), kEnforceLowerBound }; @@ -105,6 +109,7 @@ extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), kEn extern const OpcodeSpec egPercentMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec egDepth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec egVel2Depth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec flexEGAmpeg { false, Range(0, 1), 0 }; extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), kIgnoreOOB }; extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), kIgnoreOOB }; extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; @@ -123,6 +128,7 @@ extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), kE extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), kEnforceLowerBound }; extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec compSTLink { false, Range(0, 1), 0 }; extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), kIgnoreOOB }; extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), 0 }; @@ -130,6 +136,7 @@ extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), kEn extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec gateSTLink { false, Range(0, 1), 0 }; extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 899094d1..9025265e 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -29,16 +29,18 @@ #include #include -enum class SfzTrigger { attack, release, release_key, first, legato }; -enum class SfzLoopMode { no_loop, one_shot, loop_continuous, loop_sustain }; -enum class SfzOffMode { fast, normal, time }; -enum class SfzVelocityOverride { current, previous }; -enum class SfzCrossfadeCurve { gain, power }; -enum class SfzSelfMask { mask, dontMask }; +enum class SfzTrigger { attack = 0, release, release_key, first, legato }; +enum class SfzLoopMode { no_loop = 0, one_shot, loop_continuous, loop_sustain }; +enum class SfzOffMode { fast = 0, normal, time }; +enum class SfzVelocityOverride { current = 0, previous }; +enum class SfzCrossfadeCurve { gain = 0, power }; +enum class SfzSelfMask { mask = 0, dontMask }; namespace sfz { +enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; + enum OpcodeFlags : int { kIgnoreOOB = 1, kEnforceLowerBound = 1 << 1, @@ -66,6 +68,7 @@ namespace Default extern const OpcodeSpec loopRange; extern const OpcodeSpec loopCrossfade; extern const OpcodeSpec oscillatorPhase; + extern const OpcodeSpec oscillator; extern const OpcodeSpec oscillatorMode; extern const OpcodeSpec oscillatorMulti; extern const OpcodeSpec oscillatorDetune; @@ -87,6 +90,8 @@ namespace Default extern const OpcodeSpec curveCC; extern const OpcodeSpec smoothCC; extern const OpcodeSpec sustainCC; + extern const OpcodeSpec checkSustain; + extern const OpcodeSpec checkSostenuto; extern const OpcodeSpec sustainThreshold; extern const OpcodeSpec bpm; extern const OpcodeSpec sequence; @@ -108,6 +113,7 @@ namespace Default extern const OpcodeSpec ampVeltrack; extern const OpcodeSpec ampVelcurve; extern const OpcodeSpec ampRandom; + extern const OpcodeSpec rtDead; extern const OpcodeSpec rtDecay; extern const OpcodeSpec filterCutoff; extern const OpcodeSpec filterCutoffMod; @@ -156,6 +162,7 @@ namespace Default extern const OpcodeSpec egPercentMod; extern const OpcodeSpec egDepth; extern const OpcodeSpec egVel2Depth; + extern const OpcodeSpec flexEGAmpeg; extern const OpcodeSpec flexEGDynamic; extern const OpcodeSpec flexEGSustain; extern const OpcodeSpec flexEGPointTime; @@ -175,6 +182,7 @@ namespace Default extern const OpcodeSpec compAttack; extern const OpcodeSpec compRelease; extern const OpcodeSpec compThreshold; + extern const OpcodeSpec compSTLink; extern const OpcodeSpec compRatio; extern const OpcodeSpec compGain; extern const OpcodeSpec fverbSize; @@ -183,6 +191,7 @@ namespace Default extern const OpcodeSpec fverbDamp; extern const OpcodeSpec gateAttack; extern const OpcodeSpec gateRelease; + extern const OpcodeSpec gateSTLink; extern const OpcodeSpec gateHold; extern const OpcodeSpec gateThreshold; extern const OpcodeSpec lofiBitred; @@ -190,11 +199,6 @@ namespace Default extern const OpcodeSpec rectify; extern const OpcodeSpec stringsNumber; - // Boolean default values - constexpr bool rtDead { false }; - constexpr bool checkSustain { true }; // sustain_sw - constexpr bool checkSostenuto { true }; // sostenuto_sw - // Default/max count for objects constexpr int numEQs { 3 }; constexpr int numFilters { 2 }; diff --git a/src/sfizz/FlexEGDescription.h b/src/sfizz/FlexEGDescription.h index 84d9078c..7788329d 100644 --- a/src/sfizz/FlexEGDescription.h +++ b/src/sfizz/FlexEGDescription.h @@ -35,7 +35,7 @@ struct FlexEGDescription { int sustain { Default::flexEGSustain.value }; // index of the sustain point (default to 0 in ARIA) std::vector points; // ARIA - bool ampeg = false; // replaces the SFZv1 AmpEG (lowest with this bit wins) + bool ampeg { Default::flexEGAmpeg.value }; // replaces the SFZv1 AmpEG (lowest with this bit wins) }; } // namespace sfz diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 87f2e109..e7e3222a 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -294,6 +294,22 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) return absl::nullopt; } +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + auto v = readBooleanFromOpcode(*this); + if (!v) + return absl::nullopt; + + return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + return readBooleanFromOpcode(*this); +} + } // namespace sfz std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode) diff --git a/src/sfizz/Range.h b/src/sfizz/Range.h index 7bbe369f..04240553 100644 --- a/src/sfizz/Range.h +++ b/src/sfizz/Range.h @@ -19,7 +19,9 @@ namespace sfz */ template class Range { - static_assert(std::is_arithmetic::value, "The Type should be arithmetic"); + // static_assert(std::is_arithmetic::value + // || (std::is_enum::value && std::is_same::type, int>::value), + // "The Type should be arithmetic"); public: constexpr Range() = default; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 57848885..cc73a2d1 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -163,8 +163,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) oscillatorPhase = (*value >= 0) ? wrapPhase(*value) : -1.0f; break; case hash("oscillator"): - if (auto value = readBooleanFromOpcode(opcode)) - oscillatorEnabled = *value ? OscillatorEnabled::On : OscillatorEnabled::Off; + oscillatorEnabled = opcode.read(Default::oscillator).value_or(oscillatorEnabled); break; case hash("oscillator_mode"): oscillatorMode = opcode.read(Default::oscillatorMode).value_or(oscillatorMode); @@ -243,13 +242,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("rt_dead"): - if (opcode.value == "on") { - rtDead = true; - } else if (opcode.value == "off") { - rtDead = false; - } else { - DBG("Unkown rt_dead value:" << opcode.value); - } + rtDead = opcode.read(Default::rtDead).value_or(rtDead); break; // Region logic: key mapping case hash("lokey"): @@ -387,10 +380,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) sustainThreshold = normalizeCC(*value); break; case hash("sustain_sw"): - checkSustain = readBooleanFromOpcode(opcode).value_or(Default::checkSustain); + checkSustain = opcode.read(Default::checkSustain).value_or(checkSustain); break; case hash("sostenuto_sw"): - checkSostenuto = readBooleanFromOpcode(opcode).value_or(Default::checkSostenuto); + checkSostenuto = opcode.read(Default::checkSostenuto).value_or(checkSostenuto); break; // Region logic: internal conditions case hash("lochanaft"): @@ -1263,7 +1256,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; - if (auto ampeg = readBooleanFromOpcode(opcode)) { + if (auto ampeg = opcode.read(Default::flexEGAmpeg)) { FlexEGDescription& desc = flexEGs[egNumber - 1]; if (desc.ampeg != *ampeg) { desc.ampeg = *ampeg; diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 87f39984..d7784767 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -332,8 +332,7 @@ struct Region { // Wavetable oscillator float oscillatorPhase { Default::oscillatorPhase.value }; - enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; - OscillatorEnabled oscillatorEnabled { OscillatorEnabled::Auto }; // oscillator + OscillatorEnabled oscillatorEnabled { Default::oscillator.value }; // oscillator bool hasWavetableSample { false }; // (set according to sample file) int oscillatorMode { Default::oscillatorMode.value }; int oscillatorMulti { Default::oscillatorMulti.value }; @@ -349,7 +348,7 @@ struct Region { absl::optional notePolyphony {}; // note_polyphony uint32_t polyphony { config::maxVoices }; // polyphony SfzSelfMask selfMask { Default::selfMask }; - bool rtDead { Default::rtDead }; + bool rtDead { Default::rtDead.value }; // Region logic: key mapping Range keyRange { Default::key.bounds }; //lokey, hikey and key @@ -366,8 +365,8 @@ struct Region { absl::optional previousKeyswitch {}; // sw_previous absl::optional defaultSwitch {}; SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel - bool checkSustain { Default::checkSustain }; // sustain_sw - bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw + bool checkSustain { Default::checkSustain.value }; // sustain_sw + bool checkSostenuto { Default::checkSostenuto.value }; // sostenuto_sw uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc float sustainThreshold { Default::sustainThreshold.value }; // sustain_cc diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index 06b805ee..94f4b242 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -31,7 +31,7 @@ namespace fx { struct Compressor::Impl { faustCompressor _compressor[2]; - bool _stlink = false; + bool _stlink { Default::compSTLink.value }; float _inputGain { Default::compGain.value }; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; @@ -191,8 +191,7 @@ namespace fx { impl._inputGain = db2mag(*value); break; case hash("comp_stlink"): - if (auto value = readBooleanFromOpcode(opc)) - impl._stlink = *value; + impl._stlink = opc.read(Default::compSTLink).value_or(impl._stlink); break; } } diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index 792060e6..a4a916a3 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -34,7 +34,7 @@ namespace fx { struct Gate::Impl { faustGate _gate[2]; - bool _stlink = false; + bool _stlink { Default::gateSTLink.value }; float _inputGain = 1.0; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; @@ -190,9 +190,7 @@ namespace fx { } break; case hash("gate_stlink"): - if (auto value = readBooleanFromOpcode(opc)) - impl._stlink = *value; - break; + impl._stlink = opc.read(Default::gateSTLink).value_or(impl._stlink); } } diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 1072d188..2ed037a7 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -282,7 +282,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // generator with multi region = synth.getRegionView(regionNumber++); @@ -290,7 +290,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(region->isStereo()); REQUIRE(region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // explicit wavetable region = synth.getRegionView(regionNumber++); @@ -298,7 +298,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::On); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::On); // explicit wavetable with multi region = synth.getRegionView(regionNumber++); @@ -306,7 +306,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::On); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::On); // explicit disabled wavetable region = synth.getRegionView(regionNumber++); @@ -314,7 +314,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(!region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Off); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Off); // explicit disabled wavetable with multi region = synth.getRegionView(regionNumber++); @@ -322,7 +322,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(!region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Off); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Off); // implicit wavetable (sound file < 3000 frames) region = synth.getRegionView(regionNumber++); @@ -330,7 +330,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // implicit non-wavetable (sound file >= 3000 frames) region = synth.getRegionView(regionNumber++); @@ -338,7 +338,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(!region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // generator with multi=1 (single) region = synth.getRegionView(regionNumber++); @@ -346,7 +346,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // generator with multi=2 (ring modulation) region = synth.getRegionView(regionNumber++); @@ -354,7 +354,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); } TEST_CASE("[Files] wrong (overlapping) replacement for defines") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index 0e2a38c0..a3e02417 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -2347,7 +2347,7 @@ TEST_CASE("[Values] Sustain switch") "/region0/sustain_sw,T : { }", "/region1/sustain_sw,F : { }", "/region2/sustain_sw,T : { }", - "/region3/sustain_sw,T : { }", + "/region3/sustain_sw,F : { }", }; REQUIRE(messageList == expected); } @@ -2373,7 +2373,7 @@ TEST_CASE("[Values] Sostenuto switch") "/region0/sostenuto_sw,T : { }", "/region1/sostenuto_sw,F : { }", "/region2/sostenuto_sw,T : { }", - "/region3/sostenuto_sw,T : { }", + "/region3/sostenuto_sw,F : { }", }; REQUIRE(messageList == expected); } From 60b5783753af8024f0617fc643ca84f63d51d7d0 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 3 Jan 2021 22:54:25 +0100 Subject: [PATCH 246/668] Read enums through opcode.read --- src/sfizz/Defaults.cpp | 7 +++ src/sfizz/Defaults.h | 17 +++--- src/sfizz/Opcode.cpp | 111 +++++++++++++++++++++++++++++++++++ src/sfizz/Region.cpp | 100 ++++--------------------------- src/sfizz/Region.h | 14 ++--- src/sfizz/SfzFilter.cpp | 46 --------------- src/sfizz/SfzFilter.h | 10 ---- src/sfizz/effects/Eq.cpp | 8 +-- src/sfizz/effects/Filter.cpp | 8 +-- 9 files changed, 147 insertions(+), 174 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index aa768dd7..fc8be532 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -145,6 +145,13 @@ extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), kI extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), kEnforceLowerBound }; +extern const OpcodeSpec trigger { SfzTrigger::attack, Range(SfzTrigger::attack, SfzTrigger::release_key), 0}; +extern const OpcodeSpec crossfadeCurve { SfzCrossfadeCurve::power, Range(SfzCrossfadeCurve::gain, SfzCrossfadeCurve::power), 0}; +extern const OpcodeSpec offMode { SfzOffMode::fast, Range(SfzOffMode::fast, SfzOffMode::time), 0}; +extern const OpcodeSpec velocityOverride { SfzVelocityOverride::current, Range(SfzVelocityOverride::current, SfzVelocityOverride::previous), 0}; +extern const OpcodeSpec selfMask { SfzSelfMask::mask, Range(SfzSelfMask::mask, SfzSelfMask::dontMask), 0}; +extern const OpcodeSpec filter { FilterType::kFilterNone, Range(FilterType::kFilterNone, FilterType::kFilterPeq), 0}; +extern const OpcodeSpec eq { EqType::kEqNone, Range(EqType::kEqNone, EqType::kEqHighShelf), 0}; } // namespace Default } // namespace sfz diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 9025265e..2c307e0c 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -26,6 +26,7 @@ #pragma once #include "Range.h" #include "Config.h" +#include "SfzFilter.h" #include #include @@ -198,6 +199,13 @@ namespace Default extern const OpcodeSpec lofiDecim; extern const OpcodeSpec rectify; extern const OpcodeSpec stringsNumber; + extern const OpcodeSpec trigger; + extern const OpcodeSpec offMode; + extern const OpcodeSpec crossfadeCurve; + extern const OpcodeSpec velocityOverride; + extern const OpcodeSpec selfMask; + extern const OpcodeSpec filter; + extern const OpcodeSpec eq; // Default/max count for objects constexpr int numEQs { 3 }; @@ -210,15 +218,6 @@ namespace Default constexpr int maxDistoStages { 4 }; constexpr unsigned maxStrings { 88 }; - // Default values for enums - constexpr SfzTrigger trigger { SfzTrigger::attack }; - constexpr SfzOffMode offMode { SfzOffMode::fast }; - constexpr SfzVelocityOverride velocityOverride { SfzVelocityOverride::current }; - constexpr SfzSelfMask selfMask { SfzSelfMask::mask }; - constexpr SfzCrossfadeCurve crossfadeKeyCurve { SfzCrossfadeCurve::power }; - constexpr SfzCrossfadeCurve crossfadeVelCurve { SfzCrossfadeCurve::power }; - constexpr SfzCrossfadeCurve crossfadeCCCurve { SfzCrossfadeCurve::power }; - // Default values for ranges constexpr Range crossfadeKeyInRange { 0, 0 }; constexpr Range crossfadeKeyOutRange { 127, 127 }; diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index e7e3222a..a2609ca6 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -304,6 +304,117 @@ absl::optional Opcode::read(OpcodeSpec) co return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; } +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("attack"): return SfzTrigger::attack; + case hash("first"): return SfzTrigger::first; + case hash("legato"): return SfzTrigger::legato; + case hash("release"): return SfzTrigger::release; + case hash("release_key"): return SfzTrigger::release_key; + } + + DBG("Unknown trigger value: " << value); + return absl::nullopt; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("power"): return SfzCrossfadeCurve::power; + case hash("gain"): return SfzCrossfadeCurve::gain; + } + + DBG("Unknown crossfade power curve: " << value); + return absl::nullopt; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("fast"): return SfzOffMode::fast; + case hash("normal"): return SfzOffMode::normal; + case hash("time"): return SfzOffMode::time; + } + + DBG("Unknown off mode: " << value); + return absl::nullopt; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("lpf_1p"): return kFilterLpf1p; + case hash("hpf_1p"): return kFilterHpf1p; + case hash("lpf_2p"): return kFilterLpf2p; + case hash("hpf_2p"): return kFilterHpf2p; + case hash("bpf_2p"): return kFilterBpf2p; + case hash("brf_2p"): return kFilterBrf2p; + case hash("bpf_1p"): return kFilterBpf1p; + case hash("brf_1p"): return kFilterBrf1p; + case hash("apf_1p"): return kFilterApf1p; + case hash("lpf_2p_sv"): return kFilterLpf2pSv; + case hash("hpf_2p_sv"): return kFilterHpf2pSv; + case hash("bpf_2p_sv"): return kFilterBpf2pSv; + case hash("brf_2p_sv"): return kFilterBrf2pSv; + case hash("lpf_4p"): return kFilterLpf4p; + case hash("hpf_4p"): return kFilterHpf4p; + case hash("lpf_6p"): return kFilterLpf6p; + case hash("hpf_6p"): return kFilterHpf6p; + case hash("pink"): return kFilterPink; + case hash("lsh"): return kFilterLsh; + case hash("hsh"): return kFilterHsh; + case hash("bpk_2p"): //fallthrough + case hash("pkf_2p"): //fallthrough + case hash("peq"): return kFilterPeq; + } + + DBG("Unknown filter type: " << value); + return kFilterNone; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("peak"): return kEqPeak; + case hash("lshelf"): return kEqLowShelf; + case hash("hshelf"): return kEqHighShelf; + } + + DBG("Unknown EQ type: " << value); + return kEqNone; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("current"): return SfzVelocityOverride::current; + case hash("previous"): return SfzVelocityOverride::previous; + } + + DBG("Unknown velocity override: " << value); + return absl::nullopt; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("on"): + case hash("mask"): return SfzSelfMask::mask; + case hash("off"): return SfzSelfMask::dontMask; + } + + DBG("Unknown velocity override: " << value); + return absl::nullopt; +} + template <> absl::optional Opcode::read(OpcodeSpec) const { diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index cc73a2d1..22e0ef54 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -204,19 +204,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) offBy = *value; break; case hash("off_mode"): // also offmode - switch (hash(opcode.value)) { - case hash("fast"): - offMode = SfzOffMode::fast; - break; - case hash("normal"): - offMode = SfzOffMode::normal; - break; - case hash("time"): - offMode = SfzOffMode::time; - break; - default: - DBG("Unkown off mode:" << opcode.value); - } + offMode = opcode.read(Default::offMode).value_or(offMode); break; case hash("off_time"): offMode = SfzOffMode::time; @@ -360,16 +348,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("sw_vel"): - switch (hash(opcode.value)) { - case hash("current"): - velocityOverride = SfzVelocityOverride::current; - break; - case hash("previous"): - velocityOverride = SfzVelocityOverride::previous; - break; - default: - DBG("Unknown velocity mode: " << opcode.value); - } + velocityOverride = + opcode.read(Default::velocityOverride).value_or(velocityOverride); break; case hash("sustain_cc"): @@ -419,25 +399,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; // Region logic: triggers case hash("trigger"): - switch (hash(opcode.value)) { - case hash("attack"): - trigger = SfzTrigger::attack; - break; - case hash("first"): - trigger = SfzTrigger::first; - break; - case hash("legato"): - trigger = SfzTrigger::legato; - break; - case hash("release"): - trigger = SfzTrigger::release; - break; - case hash("release_key"): - trigger = SfzTrigger::release_key; - break; - default: - DBG("Unknown trigger mode: " << opcode.value); - } + trigger = opcode.read(Default::trigger).value_or(trigger); break; case hash("start_locc&"): // also on_locc& if (opcode.parameters.back() >= config::numCCs) @@ -564,28 +526,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) crossfadeVelOutRange.setEnd(normalizeVelocity(*value)); break; case hash("xf_keycurve"): - switch (hash(opcode.value)) { - case hash("power"): - crossfadeKeyCurve = SfzCrossfadeCurve::power; - break; - case hash("gain"): - crossfadeKeyCurve = SfzCrossfadeCurve::gain; - break; - default: - DBG("Unknown crossfade power curve: " << opcode.value); - } + crossfadeKeyCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeKeyCurve); break; case hash("xf_velcurve"): - switch (hash(opcode.value)) { - case hash("power"): - crossfadeVelCurve = SfzCrossfadeCurve::power; - break; - case hash("gain"): - crossfadeVelCurve = SfzCrossfadeCurve::gain; - break; - default: - DBG("Unknown crossfade power curve: " << opcode.value); - } + crossfadeVelCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeVelCurve); break; case hash("xfin_locc&"): if (opcode.parameters.back() >= config::numCCs) @@ -612,16 +556,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) crossfadeCCOutRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); break; case hash("xf_cccurve"): - switch (hash(opcode.value)) { - case hash("power"): - crossfadeCCCurve = SfzCrossfadeCurve::power; - break; - case hash("gain"): - crossfadeCCCurve = SfzCrossfadeCurve::gain; - break; - default: - DBG("Unknown crossfade power curve: " << opcode.value); - } + crossfadeCCCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeCCCurve); break; case hash("rt_decay"): rtDecay = opcode.read(Default::rtDecay).value_or(rtDecay); @@ -745,14 +680,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - absl::optional ftype = Filter::typeFromName(opcode.value); - - if (ftype) - filters[filterIndex].type = *ftype; - else { - filters[filterIndex].type = FilterType::kFilterNone; - DBG("Unknown filter type: " << opcode.value); - } + filters[filterIndex].type = + opcode.read(Default::filter).value_or(filters[filterIndex].type); } break; @@ -835,15 +764,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - absl::optional ftype = FilterEq::typeFromName(opcode.value); + equalizers[eqIndex].type = + opcode.read(Default::eq).value_or(equalizers[eqIndex].type); - if (ftype) - equalizers[eqIndex].type = *ftype; - else { - equalizers[eqIndex].type = EqType::kEqNone; - DBG("Unknown EQ type: " << opcode.value); - } - } + } break; // Performance parameters: pitch diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index d7784767..e064e1b6 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -343,11 +343,11 @@ struct Region { // Instrument settings: voice lifecycle uint32_t group { Default::group.value }; // group absl::optional offBy {}; // off_by - SfzOffMode offMode { Default::offMode }; // off_mode + SfzOffMode offMode { Default::offMode.value }; // off_mode float offTime { Default::offTime.value }; // off_mode absl::optional notePolyphony {}; // note_polyphony uint32_t polyphony { config::maxVoices }; // polyphony - SfzSelfMask selfMask { Default::selfMask }; + SfzSelfMask selfMask { Default::selfMask.value }; bool rtDead { Default::rtDead.value }; // Region logic: key mapping @@ -364,7 +364,7 @@ struct Region { absl::optional downKeyswitch {}; // sw_down absl::optional previousKeyswitch {}; // sw_previous absl::optional defaultSwitch {}; - SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel + SfzVelocityOverride velocityOverride { Default::velocityOverride.value }; // sw_vel bool checkSustain { Default::checkSustain.value }; // sustain_sw bool checkSostenuto { Default::checkSostenuto.value }; // sostenuto_sw uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc @@ -378,7 +378,7 @@ struct Region { uint8_t sequencePosition { Default::sequence.value }; // seq_position // Region logic: triggers - SfzTrigger trigger { Default::trigger }; // trigger + SfzTrigger trigger { Default::trigger.value }; // trigger CCMap> ccTriggers { Default::normalized.bounds }; // on_loccN on_hiccN // Performance parameters: amplifier @@ -397,9 +397,9 @@ struct Region { Range crossfadeKeyOutRange { Default::crossfadeKeyOutRange }; Range crossfadeVelInRange { Default::crossfadeVelInRange }; Range crossfadeVelOutRange { Default::crossfadeVelOutRange }; - SfzCrossfadeCurve crossfadeKeyCurve { Default::crossfadeKeyCurve }; - SfzCrossfadeCurve crossfadeVelCurve { Default::crossfadeVelCurve }; - SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCCCurve }; + SfzCrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve.value }; + SfzCrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve.value }; + SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve.value }; CCMap> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN float rtDecay { Default::rtDecay.value }; // rt_decay diff --git a/src/sfizz/SfzFilter.cpp b/src/sfizz/SfzFilter.cpp index 039dddb2..a1d22239 100644 --- a/src/sfizz/SfzFilter.cpp +++ b/src/sfizz/SfzFilter.cpp @@ -204,39 +204,6 @@ void Filter::setType(FilterType type) } } -absl::optional Filter::typeFromName(absl::string_view name) -{ - absl::optional ftype; - - switch (hash(name)) { - case hash("lpf_1p"): ftype = kFilterLpf1p; break; - case hash("hpf_1p"): ftype = kFilterHpf1p; break; - case hash("lpf_2p"): ftype = kFilterLpf2p; break; - case hash("hpf_2p"): ftype = kFilterHpf2p; break; - case hash("bpf_2p"): ftype = kFilterBpf2p; break; - case hash("brf_2p"): ftype = kFilterBrf2p; break; - case hash("bpf_1p"): ftype = kFilterBpf1p; break; - case hash("brf_1p"): ftype = kFilterBrf1p; break; - case hash("apf_1p"): ftype = kFilterApf1p; break; - case hash("lpf_2p_sv"): ftype = kFilterLpf2pSv; break; - case hash("hpf_2p_sv"): ftype = kFilterHpf2pSv; break; - case hash("bpf_2p_sv"): ftype = kFilterBpf2pSv; break; - case hash("brf_2p_sv"): ftype = kFilterBrf2pSv; break; - case hash("lpf_4p"): ftype = kFilterLpf4p; break; - case hash("hpf_4p"): ftype = kFilterHpf4p; break; - case hash("lpf_6p"): ftype = kFilterLpf6p; break; - case hash("hpf_6p"): ftype = kFilterHpf6p; break; - case hash("pink"): ftype = kFilterPink; break; - case hash("lsh"): ftype = kFilterLsh; break; - case hash("hsh"): ftype = kFilterHsh; break; - case hash("bpk_2p"): //fallthrough - case hash("pkf_2p"): //fallthrough - case hash("peq"): ftype = kFilterPeq; break; - } - - return ftype; -} - sfzFilterDsp *Filter::Impl::getDsp(unsigned channels, FilterType type) { switch (idDsp(channels, type)) { @@ -444,19 +411,6 @@ void FilterEq::setType(EqType type) } } -absl::optional FilterEq::typeFromName(absl::string_view name) -{ - absl::optional ftype; - - switch (hash(name)) { - case hash("peak"): ftype = kEqPeak; break; - case hash("lshelf"): ftype = kEqLowShelf; break; - case hash("hshelf"): ftype = kEqHighShelf; break; - } - - return ftype; -} - sfzFilterDsp *FilterEq::Impl::getDsp(unsigned channels, EqType type) { switch (idDsp(channels, type)) { diff --git a/src/sfizz/SfzFilter.h b/src/sfizz/SfzFilter.h index 62cba612..b64ffe8e 100644 --- a/src/sfizz/SfzFilter.h +++ b/src/sfizz/SfzFilter.h @@ -84,11 +84,6 @@ public: */ void setType(FilterType type); - /** - Get the filter type associated with the given name. - */ - static absl::optional typeFromName(absl::string_view name); - private: struct Impl; std::unique_ptr P; @@ -194,11 +189,6 @@ public: */ void setType(EqType type); - /** - Get the filter type associated with the given name. - */ - static absl::optional typeFromName(absl::string_view name); - private: struct Impl; std::unique_ptr P; diff --git a/src/sfizz/effects/Eq.cpp b/src/sfizz/effects/Eq.cpp index 7c9b5594..751ccc12 100644 --- a/src/sfizz/effects/Eq.cpp +++ b/src/sfizz/effects/Eq.cpp @@ -83,13 +83,7 @@ namespace fx { break; case hash("eq_type"): { - absl::optional ftype = sfz::FilterEq::typeFromName(opc.value); - if (ftype) - desc.type = *ftype; - else { - desc.type = EqType::kEqNone; - DBG("Unknown EQ type: " << std::string(opc.value)); - } + desc.type = opc.read(Default::eq).value_or(desc.type); break; } } diff --git a/src/sfizz/effects/Filter.cpp b/src/sfizz/effects/Filter.cpp index 836306f3..b3765b61 100644 --- a/src/sfizz/effects/Filter.cpp +++ b/src/sfizz/effects/Filter.cpp @@ -81,13 +81,7 @@ namespace fx { break; case hash("filter_type"): { - absl::optional ftype = sfz::Filter::typeFromName(opc.value); - if (ftype) - desc.type = *ftype; - else { - desc.type = FilterType::kFilterNone; - DBG("Unknown filter type: " << std::string(opc.value)); - } + desc.type = opc.read(Default::filter).value_or(desc.type); break; } // extension From e9941b4337a7c65272ee9145b3c496b7748dd1be Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 3 Jan 2021 23:29:33 +0100 Subject: [PATCH 247/668] Scope the enums in sfz and remove the prefix --- src/sfizz/ADSREnvelope.cpp | 2 +- src/sfizz/Defaults.cpp | 10 ++--- src/sfizz/Defaults.h | 22 +++++----- src/sfizz/FileMetadata.h | 4 +- src/sfizz/ModifierHelpers.h | 12 ++--- src/sfizz/Opcode.cpp | 38 ++++++++-------- src/sfizz/Region.cpp | 26 +++++------ src/sfizz/Region.h | 20 ++++----- src/sfizz/Synth.cpp | 8 ++-- src/sfizz/SynthMessaging.cpp | 44 +++++++++---------- src/sfizz/Voice.cpp | 6 +-- src/sfizz/VoiceManager.cpp | 4 +- .../modulations/sources/FlexEnvelope.cpp | 2 +- tests/FilesT.cpp | 28 ++++++------ 14 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/sfizz/ADSREnvelope.cpp b/src/sfizz/ADSREnvelope.cpp index b6fab78e..be5b3199 100644 --- a/src/sfizz/ADSREnvelope.cpp +++ b/src/sfizz/ADSREnvelope.cpp @@ -53,7 +53,7 @@ void ADSREnvelope::reset(const EGDescription& desc, const Region& region, const shouldRelease = false; freeRunning = ( (this->sustain == Float(0.0)) - || (region.loopMode == SfzLoopMode::one_shot && region.isOscillator()) + || (region.loopMode == LoopMode::one_shot && region.isOscillator()) ); currentValue = this->start; currentState = State::Delay; diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index fc8be532..622b72f4 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -145,11 +145,11 @@ extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), kI extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), kEnforceLowerBound }; -extern const OpcodeSpec trigger { SfzTrigger::attack, Range(SfzTrigger::attack, SfzTrigger::release_key), 0}; -extern const OpcodeSpec crossfadeCurve { SfzCrossfadeCurve::power, Range(SfzCrossfadeCurve::gain, SfzCrossfadeCurve::power), 0}; -extern const OpcodeSpec offMode { SfzOffMode::fast, Range(SfzOffMode::fast, SfzOffMode::time), 0}; -extern const OpcodeSpec velocityOverride { SfzVelocityOverride::current, Range(SfzVelocityOverride::current, SfzVelocityOverride::previous), 0}; -extern const OpcodeSpec selfMask { SfzSelfMask::mask, Range(SfzSelfMask::mask, SfzSelfMask::dontMask), 0}; +extern const OpcodeSpec trigger { Trigger::attack, Range(Trigger::attack, Trigger::release_key), 0}; +extern const OpcodeSpec crossfadeCurve { CrossfadeCurve::power, Range(CrossfadeCurve::gain, CrossfadeCurve::power), 0}; +extern const OpcodeSpec offMode { OffMode::fast, Range(OffMode::fast, OffMode::time), 0}; +extern const OpcodeSpec velocityOverride { VelocityOverride::current, Range(VelocityOverride::current, VelocityOverride::previous), 0}; +extern const OpcodeSpec selfMask { SelfMask::mask, Range(SelfMask::mask, SelfMask::dontMask), 0}; extern const OpcodeSpec filter { FilterType::kFilterNone, Range(FilterType::kFilterNone, FilterType::kFilterPeq), 0}; extern const OpcodeSpec eq { EqType::kEqNone, Range(EqType::kEqNone, EqType::kEqHighShelf), 0}; } // namespace Default diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 2c307e0c..98d34919 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -30,16 +30,16 @@ #include #include -enum class SfzTrigger { attack = 0, release, release_key, first, legato }; -enum class SfzLoopMode { no_loop = 0, one_shot, loop_continuous, loop_sustain }; -enum class SfzOffMode { fast = 0, normal, time }; -enum class SfzVelocityOverride { current = 0, previous }; -enum class SfzCrossfadeCurve { gain = 0, power }; -enum class SfzSelfMask { mask = 0, dontMask }; namespace sfz { +enum class Trigger { attack = 0, release, release_key, first, legato }; +enum class LoopMode { no_loop = 0, one_shot, loop_continuous, loop_sustain }; +enum class OffMode { fast = 0, normal, time }; +enum class VelocityOverride { current = 0, previous }; +enum class CrossfadeCurve { gain = 0, power }; +enum class SelfMask { mask = 0, dontMask }; enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; enum OpcodeFlags : int { @@ -199,11 +199,11 @@ namespace Default extern const OpcodeSpec lofiDecim; extern const OpcodeSpec rectify; extern const OpcodeSpec stringsNumber; - extern const OpcodeSpec trigger; - extern const OpcodeSpec offMode; - extern const OpcodeSpec crossfadeCurve; - extern const OpcodeSpec velocityOverride; - extern const OpcodeSpec selfMask; + extern const OpcodeSpec trigger; + extern const OpcodeSpec offMode; + extern const OpcodeSpec crossfadeCurve; + extern const OpcodeSpec velocityOverride; + extern const OpcodeSpec selfMask; extern const OpcodeSpec filter; extern const OpcodeSpec eq; diff --git a/src/sfizz/FileMetadata.h b/src/sfizz/FileMetadata.h index 96facb03..a6a152be 100644 --- a/src/sfizz/FileMetadata.h +++ b/src/sfizz/FileMetadata.h @@ -28,7 +28,7 @@ struct RiffChunkInfo { /** @brief Loop mode, like SF_LOOP_* */ -enum LoopMode { +enum FileLoopMode { LoopNone, LoopForward, LoopBackward, @@ -52,7 +52,7 @@ struct InstrumentInfo { } loops[16]; }; #else -enum LoopMode { +enum FileLoopMode { LoopNone = SF_LOOP_NONE, LoopForward = SF_LOOP_FORWARD, LoopBackward = SF_LOOP_BACKWARD, diff --git a/src/sfizz/ModifierHelpers.h b/src/sfizz/ModifierHelpers.h index e9b76361..f3061111 100644 --- a/src/sfizz/ModifierHelpers.h +++ b/src/sfizz/ModifierHelpers.h @@ -16,7 +16,7 @@ namespace sfz { * @brief Compute a crossfade in value with respect to a crossfade range (note, velocity, cc, ...) */ template -float crossfadeIn(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCurve curve) +float crossfadeIn(const sfz::Range& crossfadeRange, U value, CrossfadeCurve curve) { if (value < crossfadeRange.getStart()) return 0.0f; @@ -27,9 +27,9 @@ float crossfadeIn(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCurv else if (value < crossfadeRange.getEnd()) { const auto crossfadePosition = static_cast(value - crossfadeRange.getStart()) / length; - if (curve == SfzCrossfadeCurve::power) + if (curve == CrossfadeCurve::power) return sqrt(crossfadePosition); - if (curve == SfzCrossfadeCurve::gain) + if (curve == CrossfadeCurve::gain) return crossfadePosition; } @@ -40,7 +40,7 @@ float crossfadeIn(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCurv * @brief Compute a crossfade out value with respect to a crossfade range (note, velocity, cc, ...) */ template -float crossfadeOut(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCurve curve) +float crossfadeOut(const sfz::Range& crossfadeRange, U value, CrossfadeCurve curve) { if (value > crossfadeRange.getEnd()) return 0.0f; @@ -51,9 +51,9 @@ float crossfadeOut(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCur else if (value > crossfadeRange.getStart()) { const auto crossfadePosition = static_cast(value - crossfadeRange.getStart()) / length; - if (curve == SfzCrossfadeCurve::power) + if (curve == CrossfadeCurve::power) return std::sqrt(1 - crossfadePosition); - if (curve == SfzCrossfadeCurve::gain) + if (curve == CrossfadeCurve::gain) return 1 - crossfadePosition; } diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index a2609ca6..7f5f59d1 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -305,14 +305,14 @@ absl::optional Opcode::read(OpcodeSpec) co } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { - case hash("attack"): return SfzTrigger::attack; - case hash("first"): return SfzTrigger::first; - case hash("legato"): return SfzTrigger::legato; - case hash("release"): return SfzTrigger::release; - case hash("release_key"): return SfzTrigger::release_key; + case hash("attack"): return Trigger::attack; + case hash("first"): return Trigger::first; + case hash("legato"): return Trigger::legato; + case hash("release"): return Trigger::release; + case hash("release_key"): return Trigger::release_key; } DBG("Unknown trigger value: " << value); @@ -320,11 +320,11 @@ absl::optional Opcode::read(OpcodeSpec) const } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { - case hash("power"): return SfzCrossfadeCurve::power; - case hash("gain"): return SfzCrossfadeCurve::gain; + case hash("power"): return CrossfadeCurve::power; + case hash("gain"): return CrossfadeCurve::gain; } DBG("Unknown crossfade power curve: " << value); @@ -332,12 +332,12 @@ absl::optional Opcode::read(OpcodeSpec) co } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { - case hash("fast"): return SfzOffMode::fast; - case hash("normal"): return SfzOffMode::normal; - case hash("time"): return SfzOffMode::time; + case hash("fast"): return OffMode::fast; + case hash("normal"): return OffMode::normal; + case hash("time"): return OffMode::time; } DBG("Unknown off mode: " << value); @@ -391,11 +391,11 @@ absl::optional Opcode::read(OpcodeSpec) const } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { - case hash("current"): return SfzVelocityOverride::current; - case hash("previous"): return SfzVelocityOverride::previous; + case hash("current"): return VelocityOverride::current; + case hash("previous"): return VelocityOverride::previous; } DBG("Unknown velocity override: " << value); @@ -403,12 +403,12 @@ absl::optional Opcode::read(OpcodeSpec } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { case hash("on"): - case hash("mask"): return SfzSelfMask::mask; - case hash("off"): return SfzSelfMask::dontMask; + case hash("mask"): return SelfMask::mask; + case hash("off"): return SelfMask::dontMask; } DBG("Unknown velocity override: " << value); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 22e0ef54..70d071ef 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -130,16 +130,16 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("loop_mode"): // also loopmode switch (hash(opcode.value)) { case hash("no_loop"): - loopMode = SfzLoopMode::no_loop; + loopMode = LoopMode::no_loop; break; case hash("one_shot"): - loopMode = SfzLoopMode::one_shot; + loopMode = LoopMode::one_shot; break; case hash("loop_continuous"): - loopMode = SfzLoopMode::loop_continuous; + loopMode = LoopMode::loop_continuous; break; case hash("loop_sustain"): - loopMode = SfzLoopMode::loop_sustain; + loopMode = LoopMode::loop_sustain; break; default: DBG("Unkown loop mode:" << opcode.value); @@ -207,7 +207,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) offMode = opcode.read(Default::offMode).value_or(offMode); break; case hash("off_time"): - offMode = SfzOffMode::time; + offMode = OffMode::time; offTime = opcode.read(Default::offTime).value_or(offTime); break; case hash("polyphony"): @@ -220,10 +220,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("note_selfmask"): switch (hash(opcode.value)) { case hash("on"): - selfMask = SfzSelfMask::mask; + selfMask = SelfMask::mask; break; case hash("off"): - selfMask = SfzSelfMask::dontMask; + selfMask = SelfMask::dontMask; break; default: DBG("Unkown self mask value:" << opcode.value); @@ -1608,9 +1608,9 @@ bool sfz::Region::registerNoteOn(int noteNumber, float velocity, float randValue const bool velOk = velocityRange.containsWithEnd(velocity); const bool randOk = randRange.contains(randValue) || (randValue == 1.0f && randRange.getEnd() == 1.0f); - const bool firstLegatoNote = (trigger == SfzTrigger::first && midiState.getActiveNotes() == 1); - const bool attackTrigger = (trigger == SfzTrigger::attack); - const bool notFirstLegatoNote = (trigger == SfzTrigger::legato && midiState.getActiveNotes() > 1); + const bool firstLegatoNote = (trigger == Trigger::first && midiState.getActiveNotes() == 1); + const bool attackTrigger = (trigger == Trigger::attack); + const bool notFirstLegatoNote = (trigger == Trigger::legato && midiState.getActiveNotes() > 1); return keyOk && velOk && randOk && (attackTrigger || firstLegatoNote || notFirstLegatoNote); } @@ -1636,10 +1636,10 @@ bool sfz::Region::registerNoteOff(int noteNumber, float velocity, float randValu // Release logic - if (trigger == SfzTrigger::release_key) + if (trigger == Trigger::release_key) return true; - if (trigger == SfzTrigger::release) { + if (trigger == Trigger::release) { if (midiState.getCCValue(sustainCC) < sustainThreshold) return true; @@ -1717,7 +1717,7 @@ float sfz::Region::getBaseVolumedB(int noteNumber) const noexcept baseVolumedB += globalVolume; baseVolumedB += masterVolume; baseVolumedB += groupVolume; - if (trigger == SfzTrigger::release || trigger == SfzTrigger::release_key) + if (trigger == Trigger::release || trigger == Trigger::release_key) baseVolumedB -= rtDecay * midiState.getNoteDuration(noteNumber); return baseVolumedB; } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index e064e1b6..9260b8e7 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -61,7 +61,7 @@ struct Region { * @return true * @return false */ - bool isRelease() const noexcept { return trigger == SfzTrigger::release || trigger == SfzTrigger::release_key; } + bool isRelease() const noexcept { return trigger == Trigger::release || trigger == Trigger::release_key; } /** * @brief Is a generator (*sine or *silence mostly)? * @@ -97,7 +97,7 @@ struct Region { * @return true * @return false */ - bool shouldLoop() const noexcept { return (loopMode == SfzLoopMode::loop_continuous || loopMode == SfzLoopMode::loop_sustain); } + bool shouldLoop() const noexcept { return (loopMode == LoopMode::loop_continuous || loopMode == LoopMode::loop_sustain); } /** * @brief Given the current midi state, is the region switched on? * @@ -326,7 +326,7 @@ struct Region { CCMap offsetCC { Default::offsetMod.value }; uint32_t sampleEnd { Default::sampleEnd.value }; // end absl::optional sampleCount {}; // count - absl::optional loopMode {}; // loopmode + absl::optional loopMode {}; // loopmode Range loopRange { Default::loopRange.bounds }; //loopstart and loopend float loopCrossfade { Default::loopCrossfade.value }; // loop_crossfade @@ -343,11 +343,11 @@ struct Region { // Instrument settings: voice lifecycle uint32_t group { Default::group.value }; // group absl::optional offBy {}; // off_by - SfzOffMode offMode { Default::offMode.value }; // off_mode + OffMode offMode { Default::offMode.value }; // off_mode float offTime { Default::offTime.value }; // off_mode absl::optional notePolyphony {}; // note_polyphony uint32_t polyphony { config::maxVoices }; // polyphony - SfzSelfMask selfMask { Default::selfMask.value }; + SelfMask selfMask { Default::selfMask.value }; bool rtDead { Default::rtDead.value }; // Region logic: key mapping @@ -364,7 +364,7 @@ struct Region { absl::optional downKeyswitch {}; // sw_down absl::optional previousKeyswitch {}; // sw_previous absl::optional defaultSwitch {}; - SfzVelocityOverride velocityOverride { Default::velocityOverride.value }; // sw_vel + VelocityOverride velocityOverride { Default::velocityOverride.value }; // sw_vel bool checkSustain { Default::checkSustain.value }; // sustain_sw bool checkSostenuto { Default::checkSostenuto.value }; // sostenuto_sw uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc @@ -378,7 +378,7 @@ struct Region { uint8_t sequencePosition { Default::sequence.value }; // seq_position // Region logic: triggers - SfzTrigger trigger { Default::trigger.value }; // trigger + Trigger trigger { Default::trigger.value }; // trigger CCMap> ccTriggers { Default::normalized.bounds }; // on_loccN on_hiccN // Performance parameters: amplifier @@ -397,9 +397,9 @@ struct Region { Range crossfadeKeyOutRange { Default::crossfadeKeyOutRange }; Range crossfadeVelInRange { Default::crossfadeVelInRange }; Range crossfadeVelOutRange { Default::crossfadeVelOutRange }; - SfzCrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve.value }; - SfzCrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve.value }; - SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve.value }; + CrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve.value }; + CrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve.value }; + CrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve.value }; CCMap> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN float rtDecay { Default::rtDecay.value }; // rt_decay diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 43ac6241..76f935d4 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -596,11 +596,11 @@ void Synth::Impl::finalizeSfzLoad() region->loopRange.setEnd(fileInformation->loopEnd); if (!region->loopMode) - region->loopMode = SfzLoopMode::loop_continuous; + region->loopMode = LoopMode::loop_continuous; } if (region->isRelease() && !region->loopMode) - region->loopMode = SfzLoopMode::one_shot; + region->loopMode = LoopMode::one_shot; if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) region->loopRange.setEnd(region->sampleEnd); @@ -656,7 +656,7 @@ void Synth::Impl::finalizeSfzLoad() for (int cc = 0; cc < config::numCCs; cc++) { if (region->ccTriggers.contains(cc) || region->ccConditions.contains(cc) - || (cc == region->sustainCC && region->trigger == SfzTrigger::release)) + || (cc == region->sustainCC && region->trigger == Trigger::release)) ccActivationLists_[cc].push_back(region); } @@ -1052,7 +1052,7 @@ void Synth::Impl::noteOffDispatch(int delay, int noteNumber, float velocity) noe for (auto& region : noteActivationLists_[noteNumber]) { if (region->registerNoteOff(noteNumber, velocity, randValue)) { - if (region->trigger == SfzTrigger::release && !region->rtDead && !voiceManager_.playingAttackVoice(region)) + if (region->trigger == Trigger::release && !region->rtDead && !voiceManager_.playingAttackVoice(region)) continue; startVoice(region, delay, triggerEvent, ring); diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 0f6bd10b..62335993 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -167,16 +167,16 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } switch (*region.loopMode) { - case SfzLoopMode::no_loop: + case LoopMode::no_loop: client.receive<'s'>(delay, path, "no_loop"); break; - case SfzLoopMode::loop_continuous: + case LoopMode::loop_continuous: client.receive<'s'>(delay, path, "loop_continuous"); break; - case SfzLoopMode::loop_sustain: + case LoopMode::loop_sustain: client.receive<'s'>(delay, path, "loop_sustain"); break; - case SfzLoopMode::one_shot: + case LoopMode::one_shot: client.receive<'s'>(delay, path, "one_shot"); break; } @@ -204,13 +204,13 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/off_mode", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.offMode) { - case SfzOffMode::time: + case OffMode::time: client.receive<'s'>(delay, path, "time"); break; - case SfzOffMode::normal: + case OffMode::normal: client.receive<'s'>(delay, path, "normal"); break; - case SfzOffMode::fast: + case OffMode::fast: client.receive<'s'>(delay, path, "fast"); break; } @@ -313,10 +313,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/sw_vel", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.velocityOverride) { - case SfzVelocityOverride::current: + case VelocityOverride::current: client.receive<'s'>(delay, path, "current"); break; - case SfzVelocityOverride::previous: + case VelocityOverride::previous: client.receive<'s'>(delay, path, "previous"); break; } @@ -359,19 +359,19 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/trigger", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.trigger) { - case SfzTrigger::attack: + case Trigger::attack: client.receive<'s'>(delay, path, "attack"); break; - case SfzTrigger::first: + case Trigger::first: client.receive<'s'>(delay, path, "first"); break; - case SfzTrigger::release: + case Trigger::release: client.receive<'s'>(delay, path, "release"); break; - case SfzTrigger::release_key: + case Trigger::release_key: client.receive<'s'>(delay, path, "release_key"); break; - case SfzTrigger::legato: + case Trigger::legato: client.receive<'s'>(delay, path, "legato"); break; } @@ -696,10 +696,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/xf_keycurve", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.crossfadeKeyCurve) { - case SfzCrossfadeCurve::gain: + case CrossfadeCurve::gain: client.receive<'s'>(delay, path, "gain"); break; - case SfzCrossfadeCurve::power: + case CrossfadeCurve::power: client.receive<'s'>(delay, path, "power"); break; } @@ -708,10 +708,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/xf_velcurve", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.crossfadeVelCurve) { - case SfzCrossfadeCurve::gain: + case CrossfadeCurve::gain: client.receive<'s'>(delay, path, "gain"); break; - case SfzCrossfadeCurve::power: + case CrossfadeCurve::power: client.receive<'s'>(delay, path, "power"); break; } @@ -720,10 +720,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/xf_cccurve", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.crossfadeCCCurve) { - case SfzCrossfadeCurve::gain: + case CrossfadeCurve::gain: client.receive<'s'>(delay, path, "gain"); break; - case SfzCrossfadeCurve::power: + case CrossfadeCurve::power: client.receive<'s'>(delay, path, "power"); break; } @@ -945,10 +945,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/note_selfmask", "") { GET_REGION_OR_BREAK(indices[0]) switch(region.selfMask) { - case SfzSelfMask::mask: + case SelfMask::mask: client.receive(delay, path, "T", nullptr); break; - case SfzSelfMask::dontMask: + case SelfMask::dontMask: client.receive(delay, path, "F", nullptr); break; } diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 4ba91ba1..dae62336 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -464,9 +464,9 @@ void Voice::off(int delay, bool fast) noexcept { Impl& impl = *impl_; if (!impl.region_->flexAmpEG) { - if (impl.region_->offMode == SfzOffMode::fast || fast) { + if (impl.region_->offMode == OffMode::fast || fast) { impl.egAmplitude_.setReleaseTime(Default::offTime.value); - } else if (impl.region_->offMode == SfzOffMode::time) { + } else if (impl.region_->offMode == OffMode::time) { impl.egAmplitude_.setReleaseTime(impl.region_->offTime); } } @@ -492,7 +492,7 @@ void Voice::registerNoteOff(int delay, int noteNumber, float velocity) noexcept if (impl.triggerEvent_.number == noteNumber && impl.triggerEvent_.type == TriggerEventType::NoteOn) { impl.noteIsOff_ = true; - if (impl.region_->loopMode == SfzLoopMode::one_shot) + if (impl.region_->loopMode == LoopMode::one_shot) return; if (!impl.region_->checkSustain diff --git a/src/sfizz/VoiceManager.cpp b/src/sfizz/VoiceManager.cpp index 490927b2..ff978f18 100644 --- a/src/sfizz/VoiceManager.cpp +++ b/src/sfizz/VoiceManager.cpp @@ -198,7 +198,7 @@ void VoiceManager::checkNotePolyphony(const Region* region, int delay, const Tri && voiceTriggerEvent.type == triggerEvent.type) { notePolyphonyCounter += 1; switch (region->selfMask) { - case SfzSelfMask::mask: + case SelfMask::mask: if (voiceTriggerEvent.value <= triggerEvent.value) { if (!selfMaskCandidate || selfMaskCandidate->getTriggerEvent().value > voiceTriggerEvent.value) { @@ -206,7 +206,7 @@ void VoiceManager::checkNotePolyphony(const Region* region, int delay, const Tri } } break; - case SfzSelfMask::dontMask: + case SelfMask::dontMask: if (!selfMaskCandidate || selfMaskCandidate->getAge() < voice->getAge()) selfMaskCandidate = voice; break; diff --git a/src/sfizz/modulations/sources/FlexEnvelope.cpp b/src/sfizz/modulations/sources/FlexEnvelope.cpp index 5cea2ad8..c9112376 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.cpp +++ b/src/sfizz/modulations/sources/FlexEnvelope.cpp @@ -38,7 +38,7 @@ void FlexEnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, FlexEnvelope* eg = voice->getFlexEG(egIndex); eg->configure(®ion->flexEGs[egIndex]); bool freeRunning = ( - (region->loopMode == SfzLoopMode::one_shot && region->isOscillator()) + (region->loopMode == LoopMode::one_shot && region->isOscillator()) ); if (freeRunning && region->flexAmpEG && egIndex == *region->flexAmpEG) eg->setFreeRunning(true); diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 2ed037a7..0c25cfc9 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -51,7 +51,7 @@ TEST_CASE("[Files] Underscore opcodes (underscore_opcodes.sfz)") Synth synth; synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/underscore_opcodes.sfz"); REQUIRE(synth.getNumRegions() == 1); - REQUIRE(synth.getRegionView(0)->loopMode == SfzLoopMode::loop_sustain); + REQUIRE(synth.getRegionView(0)->loopMode == LoopMode::loop_sustain); } TEST_CASE("[Files] (regions_bad.sfz)") @@ -505,11 +505,11 @@ TEST_CASE("[Files] Off modes") synth.noteOn(0, 64, 63); REQUIRE( synth.getNumActiveVoices() == 2 ); const auto* fastVoice = - synth.getVoiceView(0)->getRegion()->offMode == SfzOffMode::fast ? + synth.getVoiceView(0)->getRegion()->offMode == OffMode::fast ? synth.getVoiceView(0) : synth.getVoiceView(1) ; const auto* normalVoice = - synth.getVoiceView(0)->getRegion()->offMode == SfzOffMode::fast ? + synth.getVoiceView(0)->getRegion()->offMode == OffMode::fast ? synth.getVoiceView(1) : synth.getVoiceView(0) ; synth.noteOn(100, 63, 63); @@ -530,9 +530,9 @@ TEST_CASE("[Files] Looped regions taken from files and possibly overriden") synth.setSampleRate(44100); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/looped_regions.sfz"); REQUIRE( synth.getNumRegions() == 3 ); - REQUIRE( synth.getRegionView(0)->loopMode == SfzLoopMode::loop_continuous ); - REQUIRE( synth.getRegionView(1)->loopMode == SfzLoopMode::no_loop ); - REQUIRE( synth.getRegionView(2)->loopMode == SfzLoopMode::loop_continuous ); + REQUIRE( synth.getRegionView(0)->loopMode == LoopMode::loop_continuous ); + REQUIRE( synth.getRegionView(1)->loopMode == LoopMode::no_loop ); + REQUIRE( synth.getRegionView(2)->loopMode == LoopMode::loop_continuous ); REQUIRE(synth.getRegionView(0)->loopRange == Range { 77554, 186581 }); REQUIRE(synth.getRegionView(1)->loopRange == Range { 77554, 186581 }); @@ -546,7 +546,7 @@ TEST_CASE("[Files] Looped regions can start at 0") sample=wavetable_with_loop_at_endings.wav )"); REQUIRE( synth.getNumRegions() == 1 ); - REQUIRE( synth.getRegionView(0)->loopMode == SfzLoopMode::loop_continuous ); + REQUIRE( synth.getRegionView(0)->loopMode == LoopMode::loop_continuous ); REQUIRE( synth.getRegionView(0)->loopRange == Range { 0, synth.getRegionView(0)->sampleEnd } ); } @@ -563,13 +563,13 @@ TEST_CASE("[Synth] Release triggers automatically sets the loop mode") sample=kick.wav pitch_keycenter=69 trigger=release )"); REQUIRE( synth.getNumRegions() == 7 ); - REQUIRE( synth.getRegionView(0)->loopMode == SfzLoopMode::loop_sustain ); - REQUIRE( synth.getRegionView(1)->loopMode == SfzLoopMode::loop_sustain ); - REQUIRE( synth.getRegionView(2)->loopMode == SfzLoopMode::loop_sustain ); - REQUIRE( synth.getRegionView(3)->loopMode == SfzLoopMode::loop_sustain ); - REQUIRE( synth.getRegionView(4)->loopMode == SfzLoopMode::loop_continuous ); - REQUIRE( synth.getRegionView(5)->loopMode == SfzLoopMode::one_shot ); - REQUIRE( synth.getRegionView(6)->loopMode == SfzLoopMode::one_shot ); + REQUIRE( synth.getRegionView(0)->loopMode == LoopMode::loop_sustain ); + REQUIRE( synth.getRegionView(1)->loopMode == LoopMode::loop_sustain ); + REQUIRE( synth.getRegionView(2)->loopMode == LoopMode::loop_sustain ); + REQUIRE( synth.getRegionView(3)->loopMode == LoopMode::loop_sustain ); + REQUIRE( synth.getRegionView(4)->loopMode == LoopMode::loop_continuous ); + REQUIRE( synth.getRegionView(5)->loopMode == LoopMode::one_shot ); + REQUIRE( synth.getRegionView(6)->loopMode == LoopMode::one_shot ); } TEST_CASE("[Files] Case sentitiveness") From 293e7a935fd0285c029b66e3015ce82049e8d636 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 10 Jan 2021 19:01:20 +0100 Subject: [PATCH 248/668] WIP --- src/sfizz/Curve.cpp | 14 +- src/sfizz/Defaults.cpp | 195 ++++---- src/sfizz/Defaults.h | 54 ++- src/sfizz/EGDescription.h | 26 +- src/sfizz/EQDescription.h | 10 +- src/sfizz/EQPool.h | 6 +- src/sfizz/Effects.h | 4 +- src/sfizz/FilePool.cpp | 8 +- src/sfizz/FilePool.h | 6 +- src/sfizz/FilterDescription.h | 14 +- src/sfizz/FilterPool.h | 8 +- src/sfizz/FlexEGDescription.h | 12 +- src/sfizz/LFODescription.h | 33 +- src/sfizz/Opcode.cpp | 101 ++-- src/sfizz/Opcode.h | 2 +- src/sfizz/Region.cpp | 710 ++++++++++++----------------- src/sfizz/Region.h | 118 ++--- src/sfizz/Synth.cpp | 58 +-- src/sfizz/SynthConfig.h | 2 +- src/sfizz/SynthMessaging.cpp | 6 +- src/sfizz/SynthPrivate.h | 4 +- src/sfizz/Voice.cpp | 4 +- src/sfizz/effects/Apan.cpp | 18 +- src/sfizz/effects/Apan.h | 12 +- src/sfizz/effects/Compressor.cpp | 29 +- src/sfizz/effects/Disto.cpp | 25 +- src/sfizz/effects/Eq.cpp | 15 +- src/sfizz/effects/Filter.cpp | 15 +- src/sfizz/effects/Fverb.cpp | 28 +- src/sfizz/effects/Gain.cpp | 3 +- src/sfizz/effects/Gate.cpp | 24 +- src/sfizz/effects/Lofi.cpp | 6 +- src/sfizz/effects/Rectify.cpp | 3 +- src/sfizz/effects/Strings.cpp | 6 +- src/sfizz/effects/Strings.h | 2 +- src/sfizz/effects/Width.cpp | 3 +- tests/OpcodeT.cpp | 27 +- tests/RegionValueComputationsT.cpp | 6 +- tests/RegionValuesT.cpp | 10 +- tests/SynthT.cpp | 2 +- 40 files changed, 753 insertions(+), 876 deletions(-) diff --git a/src/sfizz/Curve.cpp b/src/sfizz/Curve.cpp index b4dcb93f..1f1c792b 100644 --- a/src/sfizz/Curve.cpp +++ b/src/sfizz/Curve.cpp @@ -40,11 +40,7 @@ Curve Curve::buildCurveFromHeader( if (index >= NumValues) continue; - auto valueOpt = opc.read(fullRange); - if (!valueOpt) - continue; - - setPoint(static_cast(index), *valueOpt); + setPoint(static_cast(index), opc.read(fullRange)); } curve.fill(itp, fillStatus); @@ -267,12 +263,8 @@ void CurveSet::addCurveFromHeader(absl::Span members) int curveIndex = -1; Curve::Interpolator itp = Curve::Interpolator::Linear; - if (const Opcode* opc = findOpcode(hash("curve_index"))) { - if (auto opt = opc->read(Default::curveCC)) - curveIndex = *opt; - else - DBG("Invalid value for curve index: " << opc->value); - } + if (const Opcode* opc = findOpcode(hash("curve_index"))) + curveIndex = opc->read(Default::curveCC); #if 0 // potential sfizz extension if (const Opcode* opc = findOpcode(hash("sfizz:curve_interpolator"))) { diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 622b72f4..ee712e58 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -1,150 +1,163 @@ #include "Defaults.h" +#include "MathHelpers.h" +#include "SfzHelpers.h" namespace sfz { namespace Default { constexpr auto uint32_t_max = std::numeric_limits::max(); -extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), kEnforceLowerBound }; -extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), kEnforceLowerBound }; -extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), kEnforceLowerBound }; -extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, uint32_t_max), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec sampleCount { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec loopRange { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, uint32_t_max), kEnforceLowerBound }; +extern const OpcodeSpec sampleCount { 1, Range(1, uint32_t_max), 0 }; +extern const OpcodeSpec loopStart { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopEnd { uint32_t_max, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), 0 }; extern const OpcodeSpec oscillator { OscillatorEnabled::Auto, Range(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 }; extern const OpcodeSpec oscillatorPhase { 0.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), kIgnoreOOB }; -extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), kIgnoreOOB }; +extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), 0 }; +extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), 0 }; extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kEnforceLowerBound }; -extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), kEnforceLowerBound }; -extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), kIgnoreOOB }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), 0 }; +extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), 0 }; extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec polyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; extern const OpcodeSpec notePolyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; -extern const OpcodeSpec key { 60, Range(0, 127), kIgnoreOOB | kCanBeNote }; -extern const OpcodeSpec midi7 { 0, Range(0, 127), kIgnoreOOB }; -extern const OpcodeSpec float7 { 0.0f , Range(0.0f, 127.0f), kIgnoreOOB }; -extern const OpcodeSpec bend { 0.0f, Range(-8192.0f, 8192.0f), kIgnoreOOB }; -extern const OpcodeSpec normalized { 0.0f, Range(0.0f, 1.0f), kIgnoreOOB }; -extern const OpcodeSpec bipolar { 0.0f, Range(-1.0f, 1.0f), kIgnoreOOB }; -extern const OpcodeSpec ccNumber { 0, Range(0, config::numCCs), kIgnoreOOB }; -extern const OpcodeSpec smoothCC { 0, Range(0, 100), kIgnoreOOB }; -extern const OpcodeSpec curveCC { 0, Range(0, 255), kIgnoreOOB }; -extern const OpcodeSpec sustainCC { 64, Range(0, 127), kIgnoreOOB }; -extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec key { 60, Range(0, 127), kCanBeNote }; +extern const OpcodeSpec loKey { 0, Range(0, 127), kCanBeNote }; +extern const OpcodeSpec hiKey { 127, Range(0, 127), kCanBeNote }; +extern const OpcodeSpec loCC { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiCC { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loVel { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiVel { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loChannelAftertouch { 0, Range(0, 127), 0 }; +extern const OpcodeSpec hiChannelAftertouch { 127, Range(0, 127), 0 }; +extern const OpcodeSpec loBend { -1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec hiBend { 1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec loNormalized { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec hiNormalized { 1.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec loBipolar { -1.0f, Range(-1.0f, 1.0f), 0 }; +extern const OpcodeSpec hiBipolar { 1.0f, Range(-1.0f, 1.0f), 0 }; +extern const OpcodeSpec ccNumber { 0, Range(0, config::numCCs), 0 }; +extern const OpcodeSpec smoothCC { 0, Range(0, 100), 0 }; +extern const OpcodeSpec curveCC { 0, Range(0, 255), 0 }; +extern const OpcodeSpec sustainCC { 64, Range(0, 127), 0 }; +extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; -extern const OpcodeSpec bpm { 0.0f, Range(0.0f, 500.0f), kEnforceLowerBound }; -extern const OpcodeSpec sequence { 1, Range(1, 100), kIgnoreOOB }; +extern const OpcodeSpec loBPM { 0.0f, Range(0.0f, 500.0f), 0 }; +extern const OpcodeSpec hiBPM { 500.0f, Range(0.0f, 500.0f), 0 }; +extern const OpcodeSpec sequence { 1, Range(1, 100), 0 }; extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; extern const OpcodeSpec volumeMod { 0.0f, Range(-144.0f, 48.0f), 0 }; -extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec crossfadeIn { 0, Range(0, 127), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec crossfadeOut { 127, Range(0, 127), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec crossfadeIn { 0.0f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec crossfadeOut { 1.0f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), 0 }; -extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), kEnforceLowerBound }; +extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), 0 }; extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; -extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), kEnforceLowerBound }; -extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), kEnforceLowerBound }; -extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), kEnforceLowerBound }; -extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), kEnforceLowerBound }; +extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), 0 }; +extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), 0 }; +extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), 0 }; +extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), 0 }; extern const OpcodeSpec filterGain { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec filterGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; -extern const OpcodeSpec filterRandom { 0.0f, Range(0.0f, 12000.0f), kEnforceLowerBound }; -extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), kEnforceLowerBound }; +extern const OpcodeSpec filterRandom { 0.0f, Range(0.0f, 12000.0f), 0 }; +extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), 0 }; extern const OpcodeSpec filterVeltrack { 0, Range(-12000, 12000), 0 }; -extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), kEnforceLowerBound }; +extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), 0 }; extern const OpcodeSpec eqBandwidthMod { 0.0f, Range(-4.0f, 4.0f), 0 }; -extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 30000.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 30000.0f), 0 }; extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-30000.0f, 30000.0f), 0 }; extern const OpcodeSpec eqGain { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec eqGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec eqVel2Frequency { 0.0f, Range(-30000.0f, 30000.0f), 0 }; extern const OpcodeSpec eqVel2Gain { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec pitchKeytrack { 100, Range(-1200, 1200), 0 }; -extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), kEnforceLowerBound }; +extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), 0 }; extern const OpcodeSpec pitchVeltrack { 0, Range(-12000, 12000), 0 }; -extern const OpcodeSpec transpose { 0, Range(-127, 127), kIgnoreOOB }; +extern const OpcodeSpec transpose { 0, Range(-127, 127), 0 }; extern const OpcodeSpec pitch { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec pitchMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec bendUp { 200.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec bendDown { -200.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), kIgnoreOOB }; +extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), 0 }; extern const OpcodeSpec lfoFreq { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec lfoFreqMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec lfoBeats { 0.0f, Range(0.0f, 1000.0f), 0 }; extern const OpcodeSpec lfoBeatsMod { 0.0f, Range(-1000.0f, 1000.0f), 0 }; -extern const OpcodeSpec lfoPhase { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec lfoPhase { 0.0f, Range(0.0f, 1.0f), kWrapPhase }; extern const OpcodeSpec lfoDelay { 0.0f, Range(0.0f, 30.0f), 0 }; extern const OpcodeSpec lfoFade { 0.0f, Range(0.0f, 30.0f), 0 }; extern const OpcodeSpec lfoCount { 0, Range(0, 1000), 0 }; extern const OpcodeSpec lfoSteps { 0, Range(0, static_cast(config::maxLFOSteps)), 0 }; -extern const OpcodeSpec lfoStepX { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec lfoWave { 0, Range(0, 15), 0 }; +extern const OpcodeSpec lfoStepX { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec lfoWave { LFOWave::Triangle, Range(LFOWave::Triangle, LFOWave::RandomSH), 0 }; extern const OpcodeSpec lfoOffset { 0.0f, Range(-1.0f, 1.0f), 0 }; extern const OpcodeSpec lfoRatio { 1.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec lfoScale { 1.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec egTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec egRelease { 0.001f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egTime { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec egRelease { 0.001f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec egTimeMod { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec egPercentMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec egDepth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec egVel2Depth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec flexEGAmpeg { false, Range(0, 1), 0 }; -extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), kIgnoreOOB }; -extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), kIgnoreOOB }; -extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec flexEGPointLevel { 0.0f, Range(-1.0f, 1.0f), kIgnoreOOB }; -extern const OpcodeSpec flexEGPointShape { 0.0f, Range(-100.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec sampleQuality { 1, Range(1, 10), kIgnoreOOB }; +extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), 0 }; +extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), 0 }; +extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec flexEGPointLevel { 0.0f, Range(-1.0f, 1.0f), 0 }; +extern const OpcodeSpec flexEGPointShape { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec sampleQuality { 1, Range(1, 10), 0 }; extern const OpcodeSpec octaveOffset { 0, Range(-10, 10), 0 }; extern const OpcodeSpec noteOffset { 0, Range(-127, 127), 0 }; -extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; extern const OpcodeSpec apanWaveform { 0, Range(0, std::numeric_limits::max()), 0 }; -extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), kEnforceLowerBound }; -extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec apanLevel { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec distoTone { 100.0f, Range(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), kEnforceLowerBound }; -extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), 0 }; +extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), kWrapPhase }; +extern const OpcodeSpec apanLevel { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec distoTone { 100.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), 0 }; +extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), 0 }; extern const OpcodeSpec compSTLink { false, Range(0, 1), 0 }; -extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; -extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), kIgnoreOOB }; -extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; +extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), 0 }; +extern const OpcodeSpec compGain { 1.0f, Range(-100.0f, 100.0f), kDb2Mag }; +extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec gateSTLink { false, Range(0, 1), 0 }; -extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec gateThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; -extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), kEnforceLowerBound }; +extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec gateThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; +extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), 0 }; extern const OpcodeSpec trigger { Trigger::attack, Range(Trigger::attack, Trigger::release_key), 0}; extern const OpcodeSpec crossfadeCurve { CrossfadeCurve::power, Range(CrossfadeCurve::gain, CrossfadeCurve::power), 0}; extern const OpcodeSpec offMode { OffMode::fast, Range(OffMode::fast, OffMode::time), 0}; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 98d34919..27f5481c 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -41,20 +41,37 @@ enum class VelocityOverride { current = 0, previous }; enum class CrossfadeCurve { gain = 0, power }; enum class SelfMask { mask = 0, dontMask }; enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; +enum class LFOWave : int { + Triangle, + Sine, + Pulse75, + Square, + Pulse25, + Pulse12_5, + Ramp, + Saw, + // ARIA extra + RandomSH = 12, +}; enum OpcodeFlags : int { - kIgnoreOOB = 1, + kCanBeNote = 1, kEnforceLowerBound = 1 << 1, kEnforceUpperBound = 1 << 2, - kCanBeNote = 1 << 3, + kNormalizePercent = 1 << 3, + kNormalizeMidi = 1 << 4, + kNormalizeBend = 1 << 5, + kWrapPhase = 1 << 6, + kDb2Mag = 1 << 7, }; template struct OpcodeSpec { - T value; + T defaultValue; Range bounds; int flags; + operator T() const { return defaultValue; } }; namespace Default @@ -66,7 +83,8 @@ namespace Default extern const OpcodeSpec offsetRandom; extern const OpcodeSpec sampleEnd; extern const OpcodeSpec sampleCount; - extern const OpcodeSpec loopRange; + extern const OpcodeSpec loopStart; + extern const OpcodeSpec loopEnd; extern const OpcodeSpec loopCrossfade; extern const OpcodeSpec oscillatorPhase; extern const OpcodeSpec oscillator; @@ -82,11 +100,20 @@ namespace Default extern const OpcodeSpec polyphony; extern const OpcodeSpec notePolyphony; extern const OpcodeSpec key; - extern const OpcodeSpec midi7; - extern const OpcodeSpec float7; - extern const OpcodeSpec bend; - extern const OpcodeSpec normalized; - extern const OpcodeSpec bipolar; + extern const OpcodeSpec loKey; + extern const OpcodeSpec hiKey; + extern const OpcodeSpec loVel; + extern const OpcodeSpec hiVel; + extern const OpcodeSpec loCC; + extern const OpcodeSpec hiCC; + extern const OpcodeSpec loBend; + extern const OpcodeSpec hiBend; + extern const OpcodeSpec loNormalized; + extern const OpcodeSpec hiNormalized; + extern const OpcodeSpec loBipolar; + extern const OpcodeSpec hiBipolar; + extern const OpcodeSpec loChannelAftertouch; + extern const OpcodeSpec hiChannelAftertouch; extern const OpcodeSpec ccNumber; extern const OpcodeSpec curveCC; extern const OpcodeSpec smoothCC; @@ -94,7 +121,8 @@ namespace Default extern const OpcodeSpec checkSustain; extern const OpcodeSpec checkSostenuto; extern const OpcodeSpec sustainThreshold; - extern const OpcodeSpec bpm; + extern const OpcodeSpec loBPM; + extern const OpcodeSpec hiBPM; extern const OpcodeSpec sequence; extern const OpcodeSpec volume; extern const OpcodeSpec volumeMod; @@ -106,9 +134,9 @@ namespace Default extern const OpcodeSpec positionMod; extern const OpcodeSpec width; extern const OpcodeSpec widthMod; - extern const OpcodeSpec crossfadeIn; + extern const OpcodeSpec crossfadeIn; extern const OpcodeSpec crossfadeInNorm; - extern const OpcodeSpec crossfadeOut; + extern const OpcodeSpec crossfadeOut; extern const OpcodeSpec crossfadeOutNorm; extern const OpcodeSpec ampKeytrack; extern const OpcodeSpec ampVeltrack; @@ -152,7 +180,7 @@ namespace Default extern const OpcodeSpec lfoCount; extern const OpcodeSpec lfoSteps; extern const OpcodeSpec lfoStepX; - extern const OpcodeSpec lfoWave; + extern const OpcodeSpec lfoWave; extern const OpcodeSpec lfoOffset; extern const OpcodeSpec lfoRatio; extern const OpcodeSpec lfoScale; diff --git a/src/sfizz/EGDescription.h b/src/sfizz/EGDescription.h index 89edfde2..5bf81ca4 100644 --- a/src/sfizz/EGDescription.h +++ b/src/sfizz/EGDescription.h @@ -66,21 +66,21 @@ struct EGDescription { EGDescription& operator=(const EGDescription&) = default; EGDescription& operator=(EGDescription&&) = default; - float attack { Default::egTime.value }; - float decay { Default::egTime.value }; - float delay { Default::egTime.value }; - float hold { Default::egTime.value }; - float release { Default::egTime.value }; + float attack { Default::egTime }; + float decay { Default::egTime }; + float delay { Default::egTime }; + float hold { Default::egTime }; + float release { Default::egTime }; float start { Default::egPercent.bounds.getStart() }; float sustain { Default::egPercent.bounds.getEnd() }; - float depth { Default::egDepth.value }; - float vel2attack { Default::egTimeMod.value }; - float vel2decay { Default::egTimeMod.value }; - float vel2delay { Default::egTimeMod.value }; - float vel2hold { Default::egTimeMod.value }; - float vel2release { Default::egPercentMod.value }; - float vel2sustain { Default::egPercentMod.value }; - float vel2depth { Default::egVel2Depth.value }; + float depth { Default::egDepth }; + float vel2attack { Default::egTimeMod }; + float vel2decay { Default::egTimeMod }; + float vel2delay { Default::egTimeMod }; + float vel2hold { Default::egTimeMod }; + float vel2release { Default::egPercentMod }; + float vel2sustain { Default::egPercentMod }; + float vel2depth { Default::egVel2Depth }; CCMap ccAttack; CCMap ccDecay; diff --git a/src/sfizz/EQDescription.h b/src/sfizz/EQDescription.h index 246d545b..7860d756 100644 --- a/src/sfizz/EQDescription.h +++ b/src/sfizz/EQDescription.h @@ -14,11 +14,11 @@ namespace sfz { struct EQDescription { - float bandwidth { Default::eqBandwidth.value }; - float frequency { Default::eqFrequency.value }; - float gain { Default::eqGain.value }; - float vel2frequency { Default::eqVel2Frequency.value }; - float vel2gain { Default::eqVel2Gain.value }; + float bandwidth { Default::eqBandwidth }; + float frequency { Default::eqFrequency }; + float gain { Default::eqGain }; + float vel2frequency { Default::eqVel2Frequency }; + float vel2gain { Default::eqVel2Gain }; EqType type { EqType::kEqPeak }; }; } diff --git a/src/sfizz/EQPool.h b/src/sfizz/EQPool.h index 63ba5dde..54567b2f 100644 --- a/src/sfizz/EQPool.h +++ b/src/sfizz/EQPool.h @@ -43,9 +43,9 @@ private: Resources& resources; const EQDescription* description; std::unique_ptr eq; - float baseBandwidth { Default::eqBandwidth.value }; - float baseFrequency { Default::eqFrequency.value }; - float baseGain { Default::eqGain.value }; + float baseBandwidth { Default::eqBandwidth }; + float baseFrequency { Default::eqFrequency }; + float baseGain { Default::eqGain }; bool prepared { false }; ModMatrix::TargetId gainTarget; ModMatrix::TargetId frequencyTarget; diff --git a/src/sfizz/Effects.h b/src/sfizz/Effects.h index 838557a8..8cc5d63f 100644 --- a/src/sfizz/Effects.h +++ b/src/sfizz/Effects.h @@ -179,8 +179,8 @@ private: std::vector> _effects; AudioBuffer _inputs { EffectChannels, config::defaultSamplesPerBlock }; AudioBuffer _outputs { EffectChannels, config::defaultSamplesPerBlock }; - float _gainToMain { Default::effect.value }; - float _gainToMix { Default::effect.value }; + float _gainToMain { Default::effect }; + float _gainToMix { Default::effect }; }; } // namespace sfz diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index b86bf76f..50617169 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -255,7 +255,7 @@ absl::optional sfz::FilePool::getFileInformation(const Fil if (!fileId.isReverse()) { if (haveInstrumentInfo && instrumentInfo.loop_count > 0) { returnedValue.hasLoop = true; - returnedValue.loopBegin = instrumentInfo.loops[0].start; + returnedValue.loopStart = instrumentInfo.loops[0].start; returnedValue.loopEnd = min(returnedValue.end, instrumentInfo.loops[0].end - 1); } } else { @@ -297,7 +297,7 @@ bool sfz::FilePool::preloadFile(const FileId& fileId, uint32_t maxOffset) noexce const auto factor = static_cast(oversamplingFactor); fileInformation->sampleRate = factor * static_cast(reader->sampleRate()); fileInformation->end = static_cast(factor * fileInformation->end); - fileInformation->loopBegin = static_cast(factor * fileInformation->loopBegin); + fileInformation->loopStart = static_cast(factor * fileInformation->loopStart); fileInformation->loopEnd = static_cast(factor * fileInformation->loopEnd); auto insertedPair = preloadedFiles.insert_or_assign(fileId, { readFromFile(*reader, framesToLoad, oversamplingFactor), @@ -329,7 +329,7 @@ sfz::FileDataHolder sfz::FilePool::loadFile(const FileId& fileId) noexcept const auto factor = static_cast(oversamplingFactor); fileInformation->sampleRate = factor * static_cast(reader->sampleRate()); fileInformation->end = static_cast(factor * fileInformation->end); - fileInformation->loopBegin = static_cast(factor * fileInformation->loopBegin); + fileInformation->loopStart = static_cast(factor * fileInformation->loopStart); fileInformation->loopEnd = static_cast(factor * fileInformation->loopEnd); auto insertedPair = preloadedFiles.insert_or_assign(fileId, { readFromFile(*reader, frames, oversamplingFactor), @@ -461,7 +461,7 @@ void sfz::FilePool::setOversamplingFactor(sfz::Oversampling factor) noexcept FileInformation& information = preloadedFile.second.information; information.sampleRate *= samplerateChange; information.end = static_cast(samplerateChange * information.end); - information.loopBegin = static_cast(samplerateChange * information.loopBegin); + information.loopStart = static_cast(samplerateChange * information.loopStart); information.loopEnd = static_cast(samplerateChange * information.loopEnd); if (preloadedFile.second.status == FileData::Status::Done) { diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 2c77f6d9..6936fb63 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -51,10 +51,10 @@ using FileAudioBuffer = AudioBuffer; struct FileInformation { - uint32_t end { Default::sampleEnd.value }; + uint32_t end { Default::sampleEnd }; uint32_t maxOffset { 0 }; - uint32_t loopBegin { Default::loopRange.bounds.getStart() }; - uint32_t loopEnd { Default::loopRange.bounds.getEnd() }; + uint32_t loopStart { Default::loopStart }; + uint32_t loopEnd { Default::loopEnd }; bool hasLoop { false }; double sampleRate { config::defaultSampleRate }; int numChannels { 0 }; diff --git a/src/sfizz/FilterDescription.h b/src/sfizz/FilterDescription.h index 7bdc39b6..612d1e58 100644 --- a/src/sfizz/FilterDescription.h +++ b/src/sfizz/FilterDescription.h @@ -14,13 +14,13 @@ namespace sfz { struct FilterDescription { - float cutoff { Default::filterCutoff.value }; - float resonance { Default::filterCutoff.value }; - float gain { Default::filterGain.value }; - int keytrack { Default::filterKeytrack.value }; - uint8_t keycenter { Default::key.value }; - int veltrack { Default::filterVeltrack.value }; - float random { Default::filterRandom.value }; + float cutoff { Default::filterCutoff }; + float resonance { Default::filterCutoff }; + float gain { Default::filterGain }; + int keytrack { Default::filterKeytrack }; + uint8_t keycenter { Default::key }; + int veltrack { Default::filterVeltrack }; + float random { Default::filterRandom }; FilterType type { FilterType::kFilterLpf2p }; }; } diff --git a/src/sfizz/FilterPool.h b/src/sfizz/FilterPool.h index 13ecbb94..ab761124 100644 --- a/src/sfizz/FilterPool.h +++ b/src/sfizz/FilterPool.h @@ -22,7 +22,7 @@ public: * @param noteNumber the triggering note number * @param velocity the triggering note velocity/value */ - void setup(const Region& region, unsigned filterId, int noteNumber = static_cast(Default::key.value), float velocity = 0); + void setup(const Region& region, unsigned filterId, int noteNumber = static_cast(Default::key), float velocity = 0); /** * @brief Process a block of stereo inputs * @@ -45,9 +45,9 @@ private: Resources& resources; const FilterDescription* description; std::unique_ptr filter; - float baseCutoff { Default::filterCutoff.value }; - float baseResonance { Default::filterResonance.value }; - float baseGain { Default::filterGain.value }; + float baseCutoff { Default::filterCutoff }; + float baseResonance { Default::filterResonance }; + float baseGain { Default::filterGain }; ModMatrix::TargetId gainTarget; ModMatrix::TargetId cutoffTarget; ModMatrix::TargetId resonanceTarget; diff --git a/src/sfizz/FlexEGDescription.h b/src/sfizz/FlexEGDescription.h index 7788329d..8ba22069 100644 --- a/src/sfizz/FlexEGDescription.h +++ b/src/sfizz/FlexEGDescription.h @@ -18,24 +18,24 @@ namespace FlexEGs { }; struct FlexEGPoint { - float time { Default::flexEGPointTime.value }; // duration until next step (s) - float level { Default::flexEGPointLevel.value }; // normalized amplitude + float time { Default::flexEGPointTime }; // duration until next step (s) + float level { Default::flexEGPointLevel }; // normalized amplitude void setShape(float shape); float shape() const noexcept { return shape_; } const Curve& curve() const; private: - float shape_ { Default::flexEGPointShape.value }; // 0: linear, positive: exp, negative: log + float shape_ { Default::flexEGPointShape }; // 0: linear, positive: exp, negative: log std::shared_ptr shapeCurve_; }; struct FlexEGDescription { - int dynamic { Default::flexEGDynamic.value }; // whether parameters can be modulated while EG runs - int sustain { Default::flexEGSustain.value }; // index of the sustain point (default to 0 in ARIA) + int dynamic { Default::flexEGDynamic }; // whether parameters can be modulated while EG runs + int sustain { Default::flexEGSustain }; // index of the sustain point (default to 0 in ARIA) std::vector points; // ARIA - bool ampeg { Default::flexEGAmpeg.value }; // replaces the SFZv1 AmpEG (lowest with this bit wins) + bool ampeg { Default::flexEGAmpeg }; // replaces the SFZv1 AmpEG (lowest with this bit wins) }; } // namespace sfz diff --git a/src/sfizz/LFODescription.h b/src/sfizz/LFODescription.h index ea312bca..82859779 100644 --- a/src/sfizz/LFODescription.h +++ b/src/sfizz/LFODescription.h @@ -11,34 +11,21 @@ namespace sfz { -enum class LFOWave : int { - Triangle, - Sine, - Pulse75, - Square, - Pulse25, - Pulse12_5, - Ramp, - Saw, - // ARIA extra - RandomSH = 12, -}; - struct LFODescription { LFODescription(); ~LFODescription(); static const LFODescription& getDefault(); - float freq { Default::lfoFreq.value }; // lfoN_freq - float beats { Default::lfoBeats.value }; // lfoN_beats - float phase0 { Default::lfoPhase.value }; // lfoN_phase - float delay { Default::lfoDelay.value }; // lfoN_delay - float fade { Default::lfoFade.value }; // lfoN_fade - unsigned count { Default::lfoCount.value }; // lfoN_count + float freq { Default::lfoFreq }; // lfoN_freq + float beats { Default::lfoBeats }; // lfoN_beats + float phase0 { Default::lfoPhase }; // lfoN_phase + float delay { Default::lfoDelay }; // lfoN_delay + float fade { Default::lfoFade }; // lfoN_fade + unsigned count { Default::lfoCount }; // lfoN_count struct Sub { - LFOWave wave { static_cast(Default::lfoWave.value) }; // lfoN_wave[X] - float offset { Default::lfoOffset.value }; // lfoN_offset[X] - float ratio { Default::lfoRatio.value }; // lfoN_ratio[X] - float scale { Default::lfoScale.value }; // lfoN_scale[X] + LFOWave wave { Default::lfoWave }; // lfoN_wave[X] + float offset { Default::lfoOffset }; // lfoN_offset[X] + float ratio { Default::lfoRatio }; // lfoN_ratio[X] + float scale { Default::lfoScale }; // lfoN_scale[X] }; struct StepSequence { std::vector steps {}; // lfoN_stepX - normalized to unity diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 7f5f59d1..a3e747fc 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Opcode.h" +#include "LFODescription.h" #include "StringViewHelpers.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" @@ -141,30 +142,22 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); - if (spec.flags & kIgnoreOOB) - return {}; - } - - if (returnedValue < static_cast(spec.bounds.getStart())) { + return {}; + } else if (returnedValue < static_cast(spec.bounds.getStart())) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); - if (spec.flags & kIgnoreOOB) - return {}; + return {}; } - T castValue = static_cast(returnedValue); - if ((castValue != returnedValue) & kIgnoreOOB) - return {}; - - return castValue; + return returnedValue; } #define INSTANTIATE_FOR_INTEGRAL(T) \ template <> \ - absl::optional Opcode::read(OpcodeSpec spec) const \ + T Opcode::read(OpcodeSpec spec) const \ { \ - return readInt_(spec, value); \ + return readInt_(spec, value).value_or(spec.defaultValue); \ } INSTANTIATE_FOR_INTEGRAL(uint8_t) @@ -198,30 +191,37 @@ absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) if (!absl::SimpleAtof(v, &returnedValue)) return absl::nullopt; - if (returnedValue > static_cast(spec.bounds.getEnd())) { + if (spec.flags & kWrapPhase) + returnedValue = wrapPhase(returnedValue); + else if (returnedValue > static_cast(spec.bounds.getEnd())) { if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); - if (spec.flags & kIgnoreOOB) - return {}; - } - - if (returnedValue < static_cast(spec.bounds.getStart())) { + return {}; + } else if (returnedValue < static_cast(spec.bounds.getStart())) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); - if (spec.flags & kIgnoreOOB) - return {}; + return {}; } + if (spec.flags & kNormalizeMidi) + returnedValue = normalize7Bits(returnedValue); + else if (spec.flags & kNormalizePercent) + returnedValue = normalizePercents(returnedValue); + else if (spec.flags & kNormalizeBend) + returnedValue = normalizeBend(returnedValue); + else if (spec.flags & kDb2Mag) + returnedValue = db2mag(returnedValue); + return returnedValue; } #define INSTANTIATE_FOR_FLOATING_POINT(T) \ template <> \ - absl::optional Opcode::read(OpcodeSpec spec) const \ + T Opcode::read(OpcodeSpec spec) const \ { \ - return readFloat_(spec, value); \ + return readFloat_(spec, value).value_or(spec.defaultValue); \ } INSTANTIATE_FOR_FLOATING_POINT(float) @@ -288,24 +288,21 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) // ARIA-style booleans? (seen in egN_dynamic=1 for example) // TODO check this const OpcodeSpec fullInt64 { 0, Range::wholeRange(), 0 }; - if (auto value = opcode.read(fullInt64)) - return *value != 0; - - return absl::nullopt; + return opcode.read(fullInt64); } template <> -absl::optional Opcode::read(OpcodeSpec) const +OscillatorEnabled Opcode::read(OpcodeSpec spec) const { auto v = readBooleanFromOpcode(*this); if (!v) - return absl::nullopt; + return spec.defaultValue; return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; } template <> -absl::optional Opcode::read(OpcodeSpec) const +Trigger Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("attack"): return Trigger::attack; @@ -316,11 +313,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown trigger value: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +CrossfadeCurve Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("power"): return CrossfadeCurve::power; @@ -328,11 +325,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown crossfade power curve: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +OffMode Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("fast"): return OffMode::fast; @@ -341,11 +338,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown off mode: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +FilterType Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("lpf_1p"): return kFilterLpf1p; @@ -374,11 +371,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown filter type: " << value); - return kFilterNone; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +EqType Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("peak"): return kEqPeak; @@ -387,11 +384,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown EQ type: " << value); - return kEqNone; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +VelocityOverride Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("current"): return VelocityOverride::current; @@ -399,11 +396,11 @@ absl::optional Opcode::read(OpcodeSpec) cons } DBG("Unknown velocity override: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +SelfMask Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("on"): @@ -412,13 +409,25 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown velocity override: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +bool Opcode::read(OpcodeSpec spec) const { - return readBooleanFromOpcode(*this); + return readBooleanFromOpcode(*this).value_or(spec.defaultValue); +} + +template <> +LFOWave Opcode::read(OpcodeSpec spec) const +{ + const OpcodeSpec intSpec { + static_cast(spec.defaultValue), + Range(static_cast(spec.bounds.getStart()), static_cast(spec.bounds.getEnd())), + 0 + }; + int value = read(intSpec); + return static_cast(value); } } // namespace sfz diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index 51ff6088..3df4ed08 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -102,7 +102,7 @@ struct Opcode { } template - absl::optional read(OpcodeSpec spec) const; + T read(OpcodeSpec spec) const; private: static OpcodeCategory identifyCategory(absl::string_view name); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 70d071ef..0f86c802 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -42,7 +42,7 @@ sfz::Region::Region(int regionNumber, const MidiState& midiState, absl::string_v gainToEffect.push_back(1.0); // contribute 100% into the main bus // Default amplitude release - amplitudeEG.release = Default::egRelease.value; + amplitudeEG.release = Default::egRelease; } bool sfz::Region::parseOpcode(const Opcode& rawOpcode) @@ -57,21 +57,19 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash(x "_stepcc&"): \ case hash(x "_smoothcc&") - #define LFO_EG_filter_EQ_target(sourceKey, targetKey, spec) \ - { \ - const auto number = opcode.parameters.front(); \ - if (number == 0) \ - return false; \ - \ - const auto index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; \ - if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \ - return false; \ - \ - if (auto value = opcode.read(spec)) { \ - const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \ - const ModKey target = ModKey::createNXYZ(targetKey, id, index); \ - getOrCreateConnection(source, target).sourceDepth = *value; \ - } \ + #define LFO_EG_filter_EQ_target(sourceKey, targetKey, spec) \ + { \ + const auto number = opcode.parameters.front(); \ + if (number == 0) \ + return false; \ + \ + const auto index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; \ + if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \ + return false; \ + \ + const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \ + const ModKey target = ModKey::createNXYZ(targetKey, id, index); \ + getOrCreateConnection(source, target).sourceDepth = opcode.read(spec); \ } // Sound source: sample playback @@ -91,41 +89,34 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("sample_quality"): - { - if (opcode.value == "-1") - sampleQuality.reset(); - else if (auto value = opcode.read(Default::sampleQuality)) - sampleQuality = *value; - break; - } + sampleQuality = opcode.read(Default::sampleQuality); break; case hash("direction"): *sampleId = sampleId->reversed(opcode.value == "reverse"); break; case hash("delay"): - delay = opcode.read(Default::delay).value_or(delay); + delay = opcode.read(Default::delay); break; case hash("delay_random"): - delayRandom = opcode.read(Default::delayRandom).value_or(delayRandom); + delayRandom = opcode.read(Default::delayRandom); break; case hash("offset"): - offset = opcode.read(Default::offset).value_or(offset); + offset = opcode.read(Default::offset); break; case hash("offset_random"): - offsetRandom = opcode.read(Default::offsetRandom).value_or(offsetRandom); + offsetRandom = opcode.read(Default::offsetRandom); break; case hash("offset_oncc&"): // also offset_cc& if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = opcode.read(Default::offsetMod)) - offsetCC[opcode.parameters.back()] = *value; + + offsetCC[opcode.parameters.back()] = opcode.read(Default::offsetMod); break; case hash("end"): - sampleEnd = opcode.read(Default::sampleEnd).value_or(sampleEnd); + sampleEnd = opcode.read(Default::sampleEnd); break; case hash("count"): - if (auto value = opcode.read(Default::sampleCount)) - sampleCount = *value; + sampleCount = opcode.read(Default::sampleCount); break; case hash("loop_mode"): // also loopmode switch (hash(opcode.value)) { @@ -146,76 +137,71 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("loop_end"): // also loopend - if (auto value = opcode.read(Default::loopRange)) - loopRange.setEnd(*value); + loopRange.setEnd(opcode.read(Default::loopEnd)); break; case hash("loop_start"): // also loopstart - if (auto value = opcode.read(Default::loopRange)) - loopRange.setStart(*value); + loopRange.setStart(opcode.read(Default::loopStart)); break; case hash("loop_crossfade"): - loopCrossfade = opcode.read(Default::loopCrossfade).value_or(loopCrossfade); + loopCrossfade = opcode.read(Default::loopCrossfade); break; // Wavetable oscillator case hash("oscillator_phase"): - if (auto value = opcode.read(Default::oscillatorPhase)) - oscillatorPhase = (*value >= 0) ? wrapPhase(*value) : -1.0f; + { + auto phase = opcode.read(Default::oscillatorPhase); + oscillatorPhase = (phase >= 0) ? wrapPhase(phase) : -1.0f; + } break; case hash("oscillator"): - oscillatorEnabled = opcode.read(Default::oscillator).value_or(oscillatorEnabled); + oscillatorEnabled = opcode.read(Default::oscillator); break; case hash("oscillator_mode"): - oscillatorMode = opcode.read(Default::oscillatorMode).value_or(oscillatorMode); + oscillatorMode = opcode.read(Default::oscillatorMode); break; case hash("oscillator_multi"): - oscillatorMulti = opcode.read(Default::oscillatorMulti).value_or(oscillatorMulti); + oscillatorMulti = opcode.read(Default::oscillatorMulti); break; case hash("oscillator_detune"): - oscillatorDetune = opcode.read(Default::oscillatorDetune).value_or(oscillatorDetune); + oscillatorDetune = opcode.read(Default::oscillatorDetune); break; case_any_ccN("oscillator_detune"): processGenericCc(opcode, Default::oscillatorDetuneMod, ModKey::createNXYZ(ModId::OscillatorDetune, id)); break; case hash("oscillator_mod_depth"): - if (auto value = opcode.read(Default::oscillatorModDepth)) - oscillatorModDepth = normalizePercents(*value); + oscillatorModDepth = opcode.read(Default::oscillatorModDepth); break; case_any_ccN("oscillator_mod_depth"): processGenericCc(opcode, Default::oscillatorModDepthMod, ModKey::createNXYZ(ModId::OscillatorModDepth, id)); break; case hash("oscillator_quality"): - if (opcode.value == "-1") - oscillatorQuality.reset(); - else if (auto value = opcode.read(Default::oscillatorQuality)) - oscillatorQuality = *value; + oscillatorQuality = opcode.read(Default::oscillatorQuality); break; // Instrument settings: voice lifecycle case hash("group"): // also polyphony_group - group = opcode.read(Default::group).value_or(group); + group = opcode.read(Default::group); break; case hash("off_by"): // also offby if (opcode.value == "-1") offBy.reset(); - else if (auto value = opcode.read(Default::group)) - offBy = *value; + else + offBy = opcode.read(Default::group); break; case hash("off_mode"): // also offmode - offMode = opcode.read(Default::offMode).value_or(offMode); + offMode = opcode.read(Default::offMode); break; case hash("off_time"): offMode = OffMode::time; - offTime = opcode.read(Default::offTime).value_or(offTime); + offTime = opcode.read(Default::offTime); break; case hash("polyphony"): - polyphony = opcode.read(Default::polyphony).value_or(polyphony); + polyphony = opcode.read(Default::polyphony); break; case hash("note_polyphony"): - if (auto value = opcode.read(Default::notePolyphony)) - notePolyphony = *value; + notePolyphony = opcode.read(Default::notePolyphony); break; case hash("note_selfmask"): switch (hash(opcode.value)) { @@ -230,98 +216,96 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("rt_dead"): - rtDead = opcode.read(Default::rtDead).value_or(rtDead); + rtDead = opcode.read(Default::rtDead); break; // Region logic: key mapping case hash("lokey"): - if (auto value = opcode.read(Default::key)) { - triggerOnNote = true; - keyRange.setStart(*value); - } + triggerOnNote = true; + keyRange.setStart(opcode.read(Default::loKey)); break; case hash("hikey"): triggerOnNote = (opcode.value != "-1"); - if (auto value = opcode.read(Default::key)) - keyRange.setEnd(*value); + keyRange.setEnd(opcode.read(Default::hiKey)); break; case hash("key"): triggerOnNote = (opcode.value != "-1"); - if (auto value = opcode.read(Default::key)) { - keyRange.setStart(*value); - keyRange.setEnd(*value); - pitchKeycenter = *value; + { + auto value = opcode.read(Default::key); + keyRange.setStart(value); + keyRange.setEnd(value); + pitchKeycenter = value; } break; case hash("lovel"): - if (auto value = opcode.read(Default::midi7)) - velocityRange.setStart(normalizeVelocity(*value)); + velocityRange.setStart(opcode.read(Default::loVel)); break; case hash("hivel"): - if (auto value = opcode.read(Default::midi7)) - velocityRange.setEnd(normalizeVelocity(*value)); + velocityRange.setEnd(opcode.read(Default::hiVel)); break; // Region logic: MIDI conditions case hash("lobend"): - if (auto value = opcode.read(Default::bend)) - bendRange.setStart(normalizeBend(*value)); + bendRange.setStart(opcode.read(Default::loBend)); break; case hash("hibend"): - if (auto value = opcode.read(Default::bend)) - bendRange.setEnd(normalizeBend(*value)); + bendRange.setEnd(opcode.read(Default::hiBend)); break; case hash("locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::midi7)) - ccConditions[opcode.parameters.back()].setStart(normalizeCC(*value)); + ccConditions[opcode.parameters.back()].setStart( + opcode.read(Default::loCC) + ); break; case hash("hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::midi7)) - ccConditions[opcode.parameters.back()].setEnd(normalizeCC(*value)); + ccConditions[opcode.parameters.back()].setEnd( + opcode.read(Default::hiCC) + ); break; case hash("lohdcc&"): // also lorealcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::normalized)) - ccConditions[opcode.parameters.back()].setStart(*value); + ccConditions[opcode.parameters.back()].setStart( + opcode.read(Default::loNormalized) + ); break; case hash("hihdcc&"): // also hirealcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::normalized)) - ccConditions[opcode.parameters.back()].setEnd(*value); + ccConditions[opcode.parameters.back()].setEnd( + opcode.read(Default::hiNormalized) + ); break; case hash("sw_lokey"): // fallthrough case hash("sw_hikey"): break; case hash("sw_last"): - if (auto value = opcode.read(Default::key)) { - if (!lastKeyswitchRange) { - lastKeyswitch = *value; - keySwitched = false; - } + if (!lastKeyswitchRange) { + lastKeyswitch = opcode.read(Default::key); + keySwitched = false; } break; case hash("sw_lolast"): - if (auto value = opcode.read(Default::key)) { + { + auto value = opcode.read(Default::key); if (!lastKeyswitchRange) - lastKeyswitchRange.emplace(*value, *value); + lastKeyswitchRange.emplace(value, value); else - lastKeyswitchRange->setStart(*value); + lastKeyswitchRange->setStart(value); keySwitched = false; lastKeyswitch = absl::nullopt; } break; case hash("sw_hilast"): - if (auto value = opcode.read(Default::key)) { + { + auto value = opcode.read(Default::key); if (!lastKeyswitchRange) - lastKeyswitchRange.emplace(*value, *value); + lastKeyswitchRange.emplace(value, value); else - lastKeyswitchRange->setEnd(*value); + lastKeyswitchRange->setEnd(value); keySwitched = false; lastKeyswitch = absl::nullopt; @@ -331,256 +315,228 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) keyswitchLabel = opcode.value; break; case hash("sw_down"): - if (auto value = opcode.read(Default::key)) { - downKeyswitch = *value; - keySwitched = false; - } + downKeyswitch = opcode.read(Default::key); + keySwitched = false; break; case hash("sw_up"): - if (auto value = opcode.read(Default::key)) { - upKeyswitch = *value; - } + upKeyswitch = opcode.read(Default::key); break; case hash("sw_previous"): - if (auto value = opcode.read(Default::key)) { - previousKeyswitch = *value; - previousKeySwitched = false; - } + previousKeyswitch = opcode.read(Default::key); + previousKeySwitched = false; break; case hash("sw_vel"): velocityOverride = - opcode.read(Default::velocityOverride).value_or(velocityOverride); + opcode.read(Default::velocityOverride); break; case hash("sustain_cc"): - sustainCC = opcode.read(Default::sustainCC).value_or(sustainCC); + sustainCC = opcode.read(Default::sustainCC); break; case hash("sustain_lo"): - if (auto value = opcode.read(Default::float7)) - sustainThreshold = normalizeCC(*value); + sustainThreshold = normalizeCC(opcode.read(Default::sustainThreshold)); break; case hash("sustain_sw"): - checkSustain = opcode.read(Default::checkSustain).value_or(checkSustain); + checkSustain = opcode.read(Default::checkSustain); break; case hash("sostenuto_sw"): - checkSostenuto = opcode.read(Default::checkSostenuto).value_or(checkSostenuto); + checkSostenuto = opcode.read(Default::checkSostenuto); break; // Region logic: internal conditions case hash("lochanaft"): - if (auto value = opcode.read(Default::midi7)) - aftertouchRange.setStart(*value); + aftertouchRange.setStart(opcode.read(Default::loChannelAftertouch)); break; case hash("hichanaft"): - if (auto value = opcode.read(Default::midi7)) - aftertouchRange.setEnd(*value); + aftertouchRange.setEnd(opcode.read(Default::hiChannelAftertouch)); break; case hash("lobpm"): - if (auto value = opcode.read(Default::bpm)) - bpmRange.setStart(*value); + bpmRange.setStart(opcode.read(Default::loBPM)); break; case hash("hibpm"): - if (auto value = opcode.read(Default::bpm)) - bpmRange.setEnd(*value); + bpmRange.setEnd(opcode.read(Default::hiBPM)); break; case hash("lorand"): - if (auto value = opcode.read(Default::normalized)) - randRange.setStart(*value); + randRange.setStart(opcode.read(Default::loNormalized)); break; case hash("hirand"): - if (auto value = opcode.read(Default::normalized)) - randRange.setEnd(*value); + randRange.setEnd(opcode.read(Default::hiNormalized)); break; case hash("seq_length"): - sequenceLength = opcode.read(Default::sequence).value_or(sequenceLength); + sequenceLength = opcode.read(Default::sequence); break; case hash("seq_position"): - sequencePosition = opcode.read(Default::sequence).value_or(sequencePosition); + sequencePosition = opcode.read(Default::sequence); sequenceSwitched = false; break; // Region logic: triggers case hash("trigger"): - trigger = opcode.read(Default::trigger).value_or(trigger); + trigger = opcode.read(Default::trigger); break; case hash("start_locc&"): // also on_locc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::midi7)) { - triggerOnCC = true; - ccTriggers[opcode.parameters.back()].setStart(normalizeCC(*value)); - } + triggerOnCC = true; + ccTriggers[opcode.parameters.back()].setStart( + opcode.read(Default::loCC) + ); break; case hash("start_hicc&"): // also on_hicc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::midi7)) { - triggerOnCC = true; - ccTriggers[opcode.parameters.back()].setEnd(normalizeCC(*value)); - } + triggerOnCC = true; + ccTriggers[opcode.parameters.back()].setEnd( + opcode.read(Default::hiCC) + ); break; case hash("start_lohdcc&"): // also on_lohdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::normalized)) { - triggerOnCC = true; - ccTriggers[opcode.parameters.back()].setStart(*value); - } + triggerOnCC = true; + ccTriggers[opcode.parameters.back()].setStart( + opcode.read(Default::loNormalized) + ); break; case hash("start_hihdcc&"): // also on_hihdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::normalized)) { - triggerOnCC = true; - ccTriggers[opcode.parameters.back()].setEnd(*value); - } + ccTriggers[opcode.parameters.back()].setEnd( + opcode.read(Default::hiNormalized) + ); break; // Performance parameters: amplifier case hash("volume"): // also gain - volume = opcode.read(Default::volume).value_or(volume); + volume = opcode.read(Default::volume); break; case_any_ccN("volume"): // also gain processGenericCc(opcode, Default::volumeMod, ModKey::createNXYZ(ModId::Volume, id)); break; case hash("amplitude"): - if (auto value = opcode.read(Default::amplitude)) - amplitude = normalizePercents(*value); + amplitude = opcode.read(Default::amplitude); break; case_any_ccN("amplitude"): processGenericCc(opcode, Default::amplitudeMod, ModKey::createNXYZ(ModId::Amplitude, id)); break; case hash("pan"): - if (auto value = opcode.read(Default::pan)) - pan = normalizePercents(*value); + pan = opcode.read(Default::pan); break; case_any_ccN("pan"): processGenericCc(opcode, Default::panMod, ModKey::createNXYZ(ModId::Pan, id)); break; case hash("position"): - if (auto value = opcode.read(Default::position)) - position = normalizePercents(*value); + position = opcode.read(Default::position); break; case_any_ccN("position"): processGenericCc(opcode, Default::positionMod, ModKey::createNXYZ(ModId::Position, id)); break; case hash("width"): - if (auto value = opcode.read(Default::width)) - width = normalizePercents(*value); + width = opcode.read(Default::width); break; case_any_ccN("width"): processGenericCc(opcode, Default::widthMod, ModKey::createNXYZ(ModId::Width, id)); break; case hash("amp_keycenter"): - ampKeycenter = opcode.read(Default::key).value_or(ampKeycenter); + ampKeycenter = opcode.read(Default::key); break; case hash("amp_keytrack"): - ampKeytrack = opcode.read(Default::ampKeytrack).value_or(ampKeytrack); + ampKeytrack = opcode.read(Default::ampKeytrack); break; case hash("amp_veltrack"): - if (auto value = opcode.read(Default::ampVeltrack)) - ampVeltrack = normalizePercents(*value); + ampVeltrack = opcode.read(Default::ampVeltrack); break; case hash("amp_random"): - ampRandom = opcode.read(Default::ampRandom).value_or(ampRandom); + ampRandom = opcode.read(Default::ampRandom); break; case hash("amp_velcurve_&"): { - auto value = opcode.read(Default::ampVelcurve); if (opcode.parameters.back() > 127) return false; const auto inputVelocity = static_cast(opcode.parameters.back()); - if (value) - velocityPoints.emplace_back(inputVelocity, *value); + velocityPoints.emplace_back(inputVelocity, opcode.read(Default::ampVelcurve)); } break; case hash("xfin_lokey"): - if (auto value = opcode.read(Default::key)) - crossfadeKeyInRange.setStart(*value); + crossfadeKeyInRange.setStart(opcode.read(Default::loKey)); break; case hash("xfin_hikey"): - if (auto value = opcode.read(Default::key)) - crossfadeKeyInRange.setEnd(*value); + crossfadeKeyInRange.setEnd(opcode.read(Default::hiKey)); break; case hash("xfout_lokey"): - if (auto value = opcode.read(Default::key)) - crossfadeKeyOutRange.setStart(*value); + crossfadeKeyOutRange.setStart(opcode.read(Default::loKey)); break; case hash("xfout_hikey"): - if (auto value = opcode.read(Default::key)) - crossfadeKeyOutRange.setEnd(*value); + crossfadeKeyOutRange.setEnd(opcode.read(Default::hiKey)); break; case hash("xfin_lovel"): - if (auto value = opcode.read(Default::crossfadeIn)) - crossfadeVelInRange.setStart(normalizeVelocity(*value)); + crossfadeVelInRange.setStart(opcode.read(Default::loVel)); break; case hash("xfin_hivel"): - if (auto value = opcode.read(Default::crossfadeIn)) - crossfadeVelInRange.setEnd(normalizeVelocity(*value)); + crossfadeVelInRange.setEnd(opcode.read(Default::hiVel)); break; case hash("xfout_lovel"): - if (auto value = opcode.read(Default::crossfadeOut)) - crossfadeVelOutRange.setStart(normalizeVelocity(*value)); + crossfadeVelOutRange.setStart(opcode.read(Default::loVel)); break; case hash("xfout_hivel"): - if (auto value = opcode.read(Default::crossfadeOut)) - crossfadeVelOutRange.setEnd(normalizeVelocity(*value)); + crossfadeVelOutRange.setEnd(opcode.read(Default::hiVel)); break; case hash("xf_keycurve"): - crossfadeKeyCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeKeyCurve); + crossfadeKeyCurve = opcode.read(Default::crossfadeCurve); break; case hash("xf_velcurve"): - crossfadeVelCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeVelCurve); + crossfadeVelCurve = opcode.read(Default::crossfadeCurve); break; case hash("xfin_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::crossfadeIn)) - crossfadeCCInRange[opcode.parameters.back()].setStart(normalizeCC(*value)); + crossfadeCCInRange[opcode.parameters.back()].setStart( + opcode.read(Default::loCC) + ); break; case hash("xfin_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::crossfadeIn)) - crossfadeCCInRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); + crossfadeCCInRange[opcode.parameters.back()].setEnd( + opcode.read(Default::loCC) + ); break; case hash("xfout_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::crossfadeOut)) - crossfadeCCOutRange[opcode.parameters.back()].setStart(normalizeCC(*value)); + crossfadeCCOutRange[opcode.parameters.back()].setStart( + opcode.read(Default::loCC) + ); break; case hash("xfout_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::crossfadeOut)) - crossfadeCCOutRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); + crossfadeCCOutRange[opcode.parameters.back()].setEnd( + opcode.read(Default::loCC) + ); break; case hash("xf_cccurve"): - crossfadeCCCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeCCCurve); + crossfadeCCCurve = opcode.read(Default::crossfadeCurve); break; case hash("rt_decay"): - rtDecay = opcode.read(Default::rtDecay).value_or(rtDecay); + rtDecay = opcode.read(Default::rtDecay); break; case hash("global_amplitude"): - if (auto value = opcode.read(Default::amplitude)) - globalAmplitude = normalizePercents(*value); + globalAmplitude = opcode.read(Default::amplitude); break; case hash("master_amplitude"): - if (auto value = opcode.read(Default::amplitude)) - masterAmplitude = normalizePercents(*value); + masterAmplitude = opcode.read(Default::amplitude); break; case hash("group_amplitude"): - if (auto value = opcode.read(Default::amplitude)) - groupAmplitude = normalizePercents(*value); + groupAmplitude = opcode.read(Default::amplitude); break; case hash("global_volume"): - globalVolume = opcode.read(Default::volume).value_or(globalVolume); + globalVolume = opcode.read(Default::volume); break; case hash("master_volume"): - masterVolume = opcode.read(Default::volume).value_or(masterVolume); + masterVolume = opcode.read(Default::volume); break; case hash("group_volume"): - groupVolume = opcode.read(Default::volume).value_or(groupVolume); + groupVolume = opcode.read(Default::volume); break; // Performance parameters: filters @@ -589,8 +545,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1); if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterCutoff)) - filters[filterIndex].cutoff = *value; + filters[filterIndex].cutoff = opcode.read(Default::filterCutoff); } break; case hash("resonance&"): // also resonance @@ -598,8 +553,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1); if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterResonance)) - filters[filterIndex].resonance = *value; + filters[filterIndex].resonance = opcode.read(Default::filterResonance); } break; case_any_ccN("cutoff&"): // also cutoff_oncc&, cutoff_cc&, cutoff&_cc& @@ -625,8 +579,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterKeytrack)) - filters[filterIndex].keytrack = *value; + filters[filterIndex].keytrack = opcode.read(Default::filterKeytrack); } break; case hash("fil&_keycenter"): // also fil_keycenter @@ -634,8 +587,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::key)) - filters[filterIndex].keycenter = *value; + filters[filterIndex].keycenter = opcode.read(Default::key); } break; case hash("fil&_veltrack"): // also fil_veltrack @@ -643,8 +595,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterVeltrack)) - filters[filterIndex].veltrack = *value; + filters[filterIndex].veltrack = opcode.read(Default::filterVeltrack); } break; case hash("fil&_random"): // also fil_random, cutoff_random, cutoff&_random @@ -652,8 +603,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterRandom)) - filters[filterIndex].random = *value; + filters[filterIndex].random = opcode.read(Default::filterRandom); } break; case hash("fil&_gain"): // also fil_gain @@ -661,8 +611,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterGain)) - filters[filterIndex].gain = *value; + filters[filterIndex].gain = opcode.read(Default::filterGain); } break; case_any_ccN("fil&_gain"): // also fil_gain_oncc& @@ -680,8 +629,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - filters[filterIndex].type = - opcode.read(Default::filter).value_or(filters[filterIndex].type); + filters[filterIndex].type = opcode.read(Default::filter); } break; @@ -691,8 +639,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqBandwidth)) - equalizers[eqIndex].bandwidth = *value; + equalizers[eqIndex].bandwidth = opcode.read(Default::eqBandwidth); } break; case_any_ccN("eq&_bw"): // also eq&_bwcc& @@ -709,8 +656,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqFrequency)) - equalizers[eqIndex].frequency = *value; + equalizers[eqIndex].frequency = opcode.read(Default::eqFrequency); } break; case_any_ccN("eq&_freq"): // also eq&_freqcc& @@ -727,8 +673,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqVel2Frequency)) - equalizers[eqIndex].vel2frequency = *value; + equalizers[eqIndex].vel2frequency = opcode.read(Default::eqVel2Frequency); } break; case hash("eq&_gain"): @@ -736,8 +681,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqGain)) - equalizers[eqIndex].gain = *value; + equalizers[eqIndex].gain = opcode.read(Default::eqGain); } break; case_any_ccN("eq&_gain"): // also eq&_gaincc& @@ -754,8 +698,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqVel2Gain)) - equalizers[eqIndex].vel2gain = *value; + equalizers[eqIndex].vel2gain = opcode.read(Default::eqVel2Gain); } break; case hash("eq&_type"): @@ -765,7 +708,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; equalizers[eqIndex].type = - opcode.read(Default::eq).value_or(equalizers[eqIndex].type); + opcode.read(Default::eq); } break; @@ -776,38 +719,38 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) pitchKeycenterFromSample = true; else { pitchKeycenterFromSample = false; - pitchKeycenter = opcode.read(Default::key).value_or(pitchKeycenter); + pitchKeycenter = opcode.read(Default::key); } break; case hash("pitch_keytrack"): - pitchKeytrack = opcode.read(Default::pitchKeytrack).value_or(pitchKeytrack); + pitchKeytrack = opcode.read(Default::pitchKeytrack); break; case hash("pitch_veltrack"): - pitchVeltrack = opcode.read(Default::pitchVeltrack).value_or(pitchVeltrack); + pitchVeltrack = opcode.read(Default::pitchVeltrack); break; case hash("pitch_random"): - pitchRandom = opcode.read(Default::pitchRandom).value_or(pitchRandom); + pitchRandom = opcode.read(Default::pitchRandom); break; case hash("transpose"): - transpose = opcode.read(Default::transpose).value_or(transpose); + transpose = opcode.read(Default::transpose); break; case hash("pitch"): // also tune - pitch = opcode.read(Default::pitch).value_or(pitch); + pitch = opcode.read(Default::pitch); break; case_any_ccN("pitch"): // also tune processGenericCc(opcode, Default::pitchMod, ModKey::createNXYZ(ModId::Pitch, id)); break; case hash("bend_up"): // also bendup - bendUp = opcode.read(Default::bendUp).value_or(bendUp); + bendUp = opcode.read(Default::bendUp); break; case hash("bend_down"): // also benddown - bendDown = opcode.read(Default::bendDown).value_or(bendDown); + bendDown = opcode.read(Default::bendDown); break; case hash("bend_step"): - bendStep = opcode.read(Default::bendStep).value_or(bendStep); + bendStep = opcode.read(Default::bendStep); break; case hash("bend_smooth"): - bendSmooth = opcode.read(Default::smoothCC).value_or(bendSmooth); + bendSmooth = opcode.read(Default::smoothCC); break; // Modulation: LFO @@ -818,8 +761,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoFreq)) - lfos[lfoNumber - 1].freq = *value; + lfos[lfoNumber - 1].freq = opcode.read(Default::lfoFreq); } break; case_any_ccN("lfo&_freq"): @@ -839,8 +781,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoBeats)) - lfos[lfoNumber - 1].beats = *value; + lfos[lfoNumber - 1].beats = opcode.read(Default::lfoBeats); } break; case_any_ccN("lfo&_beats"): @@ -860,8 +801,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoPhase)) - lfos[lfoNumber - 1].phase0 = wrapPhase(*value); + lfos[lfoNumber - 1].phase0 = opcode.read(Default::lfoPhase); } break; case hash("lfo&_delay"): @@ -871,8 +811,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoDelay)) - lfos[lfoNumber - 1].delay = *value; + lfos[lfoNumber - 1].delay = opcode.read(Default::lfoDelay); } break; case hash("lfo&_fade"): @@ -882,8 +821,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoFade)) - lfos[lfoNumber - 1].fade = *value; + lfos[lfoNumber - 1].fade = opcode.read(Default::lfoFade); } break; case hash("lfo&_count"): @@ -893,8 +831,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoCount)) - lfos[lfoNumber - 1].count = *value; + lfos[lfoNumber - 1].count = opcode.read(Default::lfoCount); } break; case hash("lfo&_steps"): @@ -904,11 +841,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoSteps)) { - if (!lfos[lfoNumber - 1].seq) - lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); - lfos[lfoNumber - 1].seq->steps.resize(*value); - } + if (!lfos[lfoNumber - 1].seq) + lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); + lfos[lfoNumber - 1].seq->steps.resize(opcode.read(Default::lfoSteps)); } break; case hash("lfo&_step&"): @@ -919,13 +854,11 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoStepX)) { - if (!lfos[lfoNumber - 1].seq) - lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); - if (!extendIfNecessary(lfos[lfoNumber - 1].seq->steps, stepNumber, Default::numLFOSteps)) - return false; - lfos[lfoNumber - 1].seq->steps[stepNumber - 1] = *value * 0.01f; - } + if (!lfos[lfoNumber - 1].seq) + lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); + if (!extendIfNecessary(lfos[lfoNumber - 1].seq->steps, stepNumber, Default::numLFOSteps)) + return false; + lfos[lfoNumber - 1].seq->steps[stepNumber - 1] = opcode.read(Default::lfoStepX); } break; case hash("lfo&_wave&"): // also lfo&_wave @@ -936,11 +869,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoWave)) { - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) + if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; - lfos[lfoNumber - 1].sub[subNumber - 1].wave = static_cast(*value); - } + lfos[lfoNumber - 1].sub[subNumber - 1].wave = opcode.read(Default::lfoWave); } break; case hash("lfo&_offset&"): // also lfo&_offset @@ -951,11 +882,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoOffset)) { - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].offset = *value; - } + if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) + return false; + lfos[lfoNumber - 1].sub[subNumber - 1].offset = opcode.read(Default::lfoOffset); } break; case hash("lfo&_ratio&"): // also lfo&_ratio @@ -966,11 +895,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoRatio)) { - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].ratio = *value; - } + if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) + return false; + lfos[lfoNumber - 1].sub[subNumber - 1].ratio = opcode.read(Default::lfoRatio); } break; case hash("lfo&_scale&"): // also lfo&_scale @@ -981,11 +908,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoScale)) { - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].scale = *value; - } + if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) + return false; + lfos[lfoNumber - 1].sub[subNumber - 1].scale = opcode.read(Default::lfoScale); } break; @@ -995,11 +920,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::amplitudeMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::amplitudeMod); } break; case hash("lfo&_pan"): @@ -1007,11 +931,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::panMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pan, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Pan, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::panMod); } break; case hash("lfo&_width"): @@ -1019,11 +942,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::widthMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Width, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Width, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::widthMod); } break; case hash("lfo&_position"): // sfizz extension @@ -1031,11 +953,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::positionMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Position, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Position, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::positionMod); } break; case hash("lfo&_pitch"): @@ -1043,11 +964,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::pitchMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::pitchMod); } break; case hash("lfo&_volume"): @@ -1055,11 +975,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::volumeMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Volume, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Volume, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::volumeMod); } break; case hash("lfo&_cutoff&"): @@ -1087,11 +1006,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::amplitudeMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::amplitudeMod); } break; case hash("eg&_pan"): @@ -1099,11 +1017,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::panMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pan, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Pan, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::panMod); } break; case hash("eg&_width"): @@ -1111,11 +1028,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::widthMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Width, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Width, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::widthMod); } break; case hash("eg&_position"): // sfizz extension @@ -1123,11 +1039,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::positionMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Position, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Position, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::positionMod); } break; case hash("eg&_pitch"): @@ -1135,11 +1050,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::pitchMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::pitchMod); } break; case hash("eg&_volume"): @@ -1147,11 +1061,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::volumeMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Volume, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Volume, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::volumeMod); } break; case hash("eg&_cutoff&"): @@ -1180,15 +1093,14 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; - if (auto ampeg = opcode.read(Default::flexEGAmpeg)) { - FlexEGDescription& desc = flexEGs[egNumber - 1]; - if (desc.ampeg != *ampeg) { - desc.ampeg = *ampeg; - flexAmpEG = absl::nullopt; - for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) { - if (flexEGs[i].ampeg) - flexAmpEG = static_cast(i); - } + auto ampeg = opcode.read(Default::flexEGAmpeg); + FlexEGDescription& desc = flexEGs[egNumber - 1]; + if (desc.ampeg != ampeg) { + desc.ampeg = ampeg; + flexAmpEG = absl::nullopt; + for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) { + if (flexEGs[i].ampeg) + flexAmpEG = static_cast(i); } } break; @@ -1271,29 +1183,25 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("pitcheg_depth"): - if (auto value = opcode.read(Default::egDepth)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::PitchEG, id), - ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = *value; + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchEG, id), + ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = opcode.read(Default::egDepth); break; case hash("fileg_depth"): - if (auto value = opcode.read(Default::egDepth)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = *value; + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilEG, id), + ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = opcode.read(Default::egDepth); break; case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth - if (auto value = opcode.read(Default::egVel2Depth)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::PitchEG, id), - ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = *value; + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchEG, id), + ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = opcode.read(Default::egVel2Depth); break; case hash("fileg_veltodepth"): // also fileg_vel2depth - if (auto value = opcode.read(Default::egVel2Depth)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = *value; + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilEG, id), + ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = opcode.read(Default::egVel2Depth); break; // Flex envelopes @@ -1305,7 +1213,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; auto& eg = flexEGs[egNumber - 1]; - eg.dynamic = opcode.read(Default::flexEGDynamic).value_or(eg.dynamic); + eg.dynamic = opcode.read(Default::flexEGDynamic); } break; case hash("eg&_sustain"): @@ -1316,7 +1224,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; auto& eg = flexEGs[egNumber - 1]; - eg.sustain = opcode.read(Default::flexEGSustain).value_or(eg.sustain); + eg.sustain = opcode.read(Default::flexEGSustain); } break; case hash("eg&_time&"): @@ -1330,8 +1238,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - if (auto value = opcode.read(Default::flexEGPointTime)) - eg.points[pointNumber].time = *value; + eg.points[pointNumber].time = opcode.read(Default::flexEGPointTime); } break; case hash("eg&_level&"): @@ -1345,8 +1252,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - if (auto value = opcode.read(Default::flexEGPointLevel)) - eg.points[pointNumber].level = *value; + eg.points[pointNumber].level = opcode.read(Default::flexEGPointLevel); } break; case hash("eg&_shape&"): @@ -1360,8 +1266,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - if (auto value = opcode.read(Default::flexEGPointShape)) - eg.points[pointNumber].setShape(*value); + eg.points[pointNumber].setShape(opcode.read(Default::flexEGPointShape)); } break; @@ -1370,17 +1275,13 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto effectNumber = opcode.parameters.back(); if (!effectNumber || effectNumber < 1 || effectNumber > config::maxEffectBuses) break; - auto value = opcode.read(Default::effect); - if (!value) - break; if (static_cast(effectNumber + 1) > gainToEffect.size()) gainToEffect.resize(effectNumber + 1); - gainToEffect[effectNumber] = *value / 100; + gainToEffect[effectNumber] = opcode.read(Default::effect); break; } case hash("sw_default"): - if (auto value = opcode.read(Default::key)) - defaultSwitch = *value; + defaultSwitch = opcode.read(Default::key); break; // Ignored opcodes @@ -1408,98 +1309,91 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) switch (opcode.lettersOnlyHash) { case_any_eg("attack"): - eg.attack = opcode.read(Default::egTime).value_or(eg.attack); + eg.attack = opcode.read(Default::egTime); break; case_any_eg("decay"): - eg.decay = opcode.read(Default::egTime).value_or(eg.decay); + eg.decay = opcode.read(Default::egTime); break; case_any_eg("delay"): - eg.delay = opcode.read(Default::egTime).value_or(eg.delay); + eg.delay = opcode.read(Default::egTime); break; case_any_eg("hold"): - eg.hold = opcode.read(Default::egTime).value_or(eg.hold); + eg.hold = opcode.read(Default::egTime); break; case_any_eg("release"): - eg.release = opcode.read(Default::egRelease).value_or(eg.release); + eg.release = opcode.read(Default::egRelease); break; case_any_eg("start"): - eg.start = opcode.read(Default::egPercent).value_or(eg.start); + eg.start = opcode.read(Default::egPercent); break; case_any_eg("sustain"): - eg.sustain = opcode.read(Default::egPercent).value_or(eg.sustain); + eg.sustain = opcode.read(Default::egPercent); break; case_any_eg("veltoattack"): // also vel2attack - eg.vel2attack = opcode.read(Default::egTimeMod).value_or(eg.vel2attack); + eg.vel2attack = opcode.read(Default::egTimeMod); break; case_any_eg("veltodecay"): // also vel2decay - eg.vel2decay = opcode.read(Default::egTimeMod).value_or(eg.vel2decay); + eg.vel2decay = opcode.read(Default::egTimeMod); break; case_any_eg("veltodelay"): // also vel2delay - eg.vel2delay = opcode.read(Default::egTimeMod).value_or(eg.vel2delay); + eg.vel2delay = opcode.read(Default::egTimeMod); break; case_any_eg("veltohold"): // also vel2hold - eg.vel2hold = opcode.read(Default::egTimeMod).value_or(eg.vel2hold); + eg.vel2hold = opcode.read(Default::egTimeMod); break; case_any_eg("veltorelease"): // also vel2release - eg.vel2release = opcode.read(Default::egTimeMod).value_or(eg.vel2release); + eg.vel2release = opcode.read(Default::egTimeMod); break; case_any_eg("veltosustain"): // also vel2sustain - eg.vel2sustain = opcode.read(Default::egPercentMod).value_or(eg.vel2sustain); + eg.vel2sustain = opcode.read(Default::egPercentMod); break; case_any_eg("attack_oncc&"): // also attackcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccAttack[opcode.parameters.back()] = *value; + eg.ccAttack[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("decay_oncc&"): // also decaycc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccDecay[opcode.parameters.back()] = *value; + eg.ccDecay[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("delay_oncc&"): // also delaycc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccDelay[opcode.parameters.back()] = *value; + eg.ccDelay[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("hold_oncc&"): // also holdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccHold[opcode.parameters.back()] = *value; + eg.ccHold[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("release_oncc&"): // also releasecc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccRelease[opcode.parameters.back()] = *value; + eg.ccRelease[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("start_oncc&"): // also startcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egPercentMod)) - eg.ccStart[opcode.parameters.back()] = *value; + eg.ccStart[opcode.parameters.back()] = opcode.read(Default::egPercentMod); break; case_any_eg("sustain_oncc&"): // also sustaincc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egPercentMod)) - eg.ccSustain[opcode.parameters.back()] = *value; + eg.ccSustain[opcode.parameters.back()] = opcode.read(Default::egPercentMod); break; default: @@ -1558,21 +1452,21 @@ bool sfz::Region::processGenericCc(const Opcode& opcode, OpcodeSpec spec, ModKey::Parameters p = conn->source.parameters(); switch (opcode.category) { case kOpcodeOnCcN: - conn->sourceDepth = opcode.read(spec).value_or(conn->sourceDepth); + conn->sourceDepth = opcode.read(spec); break; case kOpcodeCurveCcN: - p.curve = opcode.read(Default::curveCC).value_or(p.curve); + p.curve = opcode.read(Default::curveCC); break; case kOpcodeStepCcN: { const float maxStep = max(std::abs(spec.bounds.getStart()), std::abs(spec.bounds.getEnd())); - const OpcodeSpec stepCC { 0.0f, Range(0.0f, maxStep), kEnforceLowerBound | kEnforceUpperBound }; - p.step = opcode.read(stepCC).value_or(p.step); + const OpcodeSpec stepCC { 0.0f, Range(0.0f, maxStep), 0 }; + p.step = opcode.read(stepCC); } break; case kOpcodeSmoothCcN: - p.smooth = opcode.read(Default::smoothCC).value_or(p.smooth); + p.smooth = opcode.read(Default::smoothCC); break; default: assert(false); diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 9260b8e7..4a7324f8 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -319,44 +319,44 @@ struct Region { // Sound source: sample playback std::shared_ptr sampleId { new FileId }; // Sample absl::optional sampleQuality {}; - float delay { Default::delay.value }; // delay - float delayRandom { Default::delayRandom.value }; // delay_random - int64_t offset { Default::offset.value }; // offset - int64_t offsetRandom { Default::offsetRandom.value }; // offset_random - CCMap offsetCC { Default::offsetMod.value }; - uint32_t sampleEnd { Default::sampleEnd.value }; // end - absl::optional sampleCount {}; // count + float delay { Default::delay }; // delay + float delayRandom { Default::delayRandom }; // delay_random + int64_t offset { Default::offset }; // offset + int64_t offsetRandom { Default::offsetRandom }; // offset_random + CCMap offsetCC { Default::offsetMod }; + uint32_t sampleEnd { Default::sampleEnd }; // end + uint32_t sampleCount { Default::sampleCount }; // count absl::optional loopMode {}; // loopmode - Range loopRange { Default::loopRange.bounds }; //loopstart and loopend - float loopCrossfade { Default::loopCrossfade.value }; // loop_crossfade + Range loopRange { Default::loopStart, Default::loopEnd }; //loopstart and loopend + float loopCrossfade { Default::loopCrossfade }; // loop_crossfade // Wavetable oscillator - float oscillatorPhase { Default::oscillatorPhase.value }; - OscillatorEnabled oscillatorEnabled { Default::oscillator.value }; // oscillator + float oscillatorPhase { Default::oscillatorPhase }; + OscillatorEnabled oscillatorEnabled { Default::oscillator }; // oscillator bool hasWavetableSample { false }; // (set according to sample file) - int oscillatorMode { Default::oscillatorMode.value }; - int oscillatorMulti { Default::oscillatorMulti.value }; - float oscillatorDetune { Default::oscillatorDetune.value }; - float oscillatorModDepth { Default::oscillatorModDepth.value }; + int oscillatorMode { Default::oscillatorMode }; + int oscillatorMulti { Default::oscillatorMulti }; + float oscillatorDetune { Default::oscillatorDetune }; + float oscillatorModDepth { Default::oscillatorModDepth }; absl::optional oscillatorQuality; // Instrument settings: voice lifecycle - uint32_t group { Default::group.value }; // group + uint32_t group { Default::group }; // group absl::optional offBy {}; // off_by - OffMode offMode { Default::offMode.value }; // off_mode - float offTime { Default::offTime.value }; // off_mode + OffMode offMode { Default::offMode }; // off_mode + float offTime { Default::offTime }; // off_mode absl::optional notePolyphony {}; // note_polyphony uint32_t polyphony { config::maxVoices }; // polyphony - SelfMask selfMask { Default::selfMask.value }; - bool rtDead { Default::rtDead.value }; + SelfMask selfMask { Default::selfMask }; + bool rtDead { Default::rtDead }; // Region logic: key mapping - Range keyRange { Default::key.bounds }; //lokey, hikey and key - Range velocityRange { Default::normalized.bounds }; // hivel and lovel + Range keyRange { Default::loKey, Default::hiKey }; //lokey, hikey and key + Range velocityRange { Default::loVel, Default::hiVel }; // hivel and lovel // Region logic: MIDI conditions - Range bendRange { Default::bipolar.bounds }; // hibend and lobend - CCMap> ccConditions { Default::normalized.bounds }; + Range bendRange { Default::loBend, Default::hiBend }; // hibend and lobend + CCMap> ccConditions {{ Default::loCC, Default::hiCC }}; absl::optional lastKeyswitch {}; // sw_last absl::optional> lastKeyswitchRange {}; // sw_last absl::optional keyswitchLabel {}; @@ -364,45 +364,45 @@ struct Region { absl::optional downKeyswitch {}; // sw_down absl::optional previousKeyswitch {}; // sw_previous absl::optional defaultSwitch {}; - VelocityOverride velocityOverride { Default::velocityOverride.value }; // sw_vel - bool checkSustain { Default::checkSustain.value }; // sustain_sw - bool checkSostenuto { Default::checkSostenuto.value }; // sostenuto_sw - uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc - float sustainThreshold { Default::sustainThreshold.value }; // sustain_cc + VelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel + bool checkSustain { Default::checkSustain }; // sustain_sw + bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw + uint16_t sustainCC { Default::sustainCC }; // sustain_cc + float sustainThreshold { Default::sustainThreshold }; // sustain_cc // Region logic: internal conditions - Range aftertouchRange { Default::midi7.bounds }; // hichanaft and lochanaft - Range bpmRange { Default::bpm.bounds }; // hibpm and lobpm - Range randRange { Default::normalized.bounds }; // hirand and lorand - uint8_t sequenceLength { Default::sequence.value }; // seq_length - uint8_t sequencePosition { Default::sequence.value }; // seq_position + Range aftertouchRange { Default::loChannelAftertouch, Default::hiChannelAftertouch }; // hichanaft and lochanaft + Range bpmRange { Default::loBPM, Default::hiBPM }; // hibpm and lobpm + Range randRange { Default::loNormalized, Default::hiNormalized }; // hirand and lorand + uint8_t sequenceLength { Default::sequence }; // seq_length + uint8_t sequencePosition { Default::sequence }; // seq_position // Region logic: triggers - Trigger trigger { Default::trigger.value }; // trigger - CCMap> ccTriggers { Default::normalized.bounds }; // on_loccN on_hiccN + Trigger trigger { Default::trigger }; // trigger + CCMap> ccTriggers {{ Default::loCC, Default::hiCC }}; // on_loccN on_hiccN // Performance parameters: amplifier - float volume { Default::volume.value }; // volume - float amplitude { normalizePercents(Default::amplitude.value) }; // amplitude - float pan { normalizePercents(Default::pan.value) }; // pan - float width { normalizePercents(Default::width.value) }; // width - float position { normalizePercents(Default::position.value) }; // position - uint8_t ampKeycenter { Default::key.value }; // amp_keycenter - float ampKeytrack { Default::ampKeytrack.value }; // amp_keytrack - float ampVeltrack { normalizePercents(Default::ampVeltrack.value) }; // amp_veltrack + float volume { Default::volume }; // volume + float amplitude { normalizePercents(Default::amplitude) }; // amplitude + float pan { normalizePercents(Default::pan) }; // pan + float width { normalizePercents(Default::width) }; // width + float position { normalizePercents(Default::position) }; // position + uint8_t ampKeycenter { Default::key }; // amp_keycenter + float ampKeytrack { Default::ampKeytrack }; // amp_keytrack + float ampVeltrack { normalizePercents(Default::ampVeltrack) }; // amp_veltrack std::vector> velocityPoints; // amp_velcurve_N absl::optional velCurve {}; - float ampRandom { Default::ampRandom.value }; // amp_random + float ampRandom { Default::ampRandom }; // amp_random Range crossfadeKeyInRange { Default::crossfadeKeyInRange }; Range crossfadeKeyOutRange { Default::crossfadeKeyOutRange }; Range crossfadeVelInRange { Default::crossfadeVelInRange }; Range crossfadeVelOutRange { Default::crossfadeVelOutRange }; - CrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve.value }; - CrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve.value }; - CrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve.value }; + CrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve }; + CrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve }; + CrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve }; CCMap> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN - float rtDecay { Default::rtDecay.value }; // rt_decay + float rtDecay { Default::rtDecay }; // rt_decay float globalAmplitude { 1.0 }; // global_amplitude float masterAmplitude { 1.0 }; // master_amplitude @@ -416,17 +416,17 @@ struct Region { std::vector filters; // Performance parameters: pitch - uint8_t pitchKeycenter { Default::key.value }; // pitch_keycenter + uint8_t pitchKeycenter { Default::key }; // pitch_keycenter bool pitchKeycenterFromSample { false }; - int pitchKeytrack { Default::pitchKeytrack.value }; // pitch_keytrack - float pitchRandom { Default::pitchRandom.value }; // pitch_random - int pitchVeltrack { Default::pitchVeltrack.value }; // pitch_veltrack - int transpose { Default::transpose.value }; // transpose - float pitch { Default::pitch.value }; // tune - float bendUp { Default::bendUp.value }; - float bendDown { Default::bendDown.value }; - float bendStep { Default::bendStep.value }; - uint8_t bendSmooth { Default::smoothCC.value }; + int pitchKeytrack { Default::pitchKeytrack }; // pitch_keytrack + float pitchRandom { Default::pitchRandom }; // pitch_random + int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack + int transpose { Default::transpose }; // transpose + float pitch { Default::pitch }; // tune + float bendUp { Default::bendUp }; + float bendDown { Default::bendDown }; + float bendStep { Default::bendStep }; + uint8_t bendSmooth { Default::smoothCC }; // Envelopes EGDescription amplitudeEG; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 76f935d4..fefa48d4 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -191,7 +191,7 @@ void Synth::Impl::buildRegion(const std::vector& regionOpcodes) currentSwitch_ = *lastRegion->defaultSwitch; // There was a combination of group= and polyphony= on a region, so set the group polyphony - if (lastRegion->group != Default::group.value && lastRegion->polyphony != config::maxVoices) { + if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) { voiceManager_.setGroupPolyphony(lastRegion->group, lastRegion->polyphony); } else { // Just check that there are enough polyphony groups @@ -276,12 +276,10 @@ void Synth::Impl::handleMasterOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("polyphony"): ASSERT(currentSet_ != nullptr); - if (auto value = member.read(Default::polyphony)) - currentSet_->setPolyphonyLimit(*value); + currentSet_->setPolyphonyLimit(member.read(Default::polyphony)); break; case hash("sw_default"): - if (auto value = member.read(Default::key)) - currentSwitch_ = *value; + currentSwitch_ = member.read(Default::key); break; } } @@ -295,12 +293,10 @@ void Synth::Impl::handleGlobalOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("polyphony"): ASSERT(currentSet_ != nullptr); - if (auto value = member.read(Default::polyphony)) - currentSet_->setPolyphonyLimit(*value); + currentSet_->setPolyphonyLimit(member.read(Default::polyphony)); break; case hash("sw_default"): - if (auto value = member.read(Default::key)) - currentSwitch_ = *value; + currentSwitch_ = member.read(Default::key); break; case hash("volume"): // FIXME : Probably best not to mess with this and let the host control the volume @@ -320,16 +316,13 @@ void Synth::Impl::handleGroupOpcodes(const std::vector& members, const s switch (member.lettersOnlyHash) { case hash("group"): - if (auto value = member.read(Default::group)) - groupIdx = *value; + groupIdx = member.read(Default::group); break; case hash("polyphony"): - if (auto value = member.read(Default::polyphony)) - maxPolyphony = *value; + maxPolyphony = member.read(Default::polyphony); break; case hash("sw_default"): - if (auto value = member.read(Default::key)) - currentSwitch_ = *value; + currentSwitch_ = member.read(Default::key); break; } }; @@ -358,16 +351,12 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("set_cc&"): if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) { - const auto ccValue = member.read(Default::midi7); - if (ccValue) - setDefaultHdcc(member.parameters.back(), normalizeCC(*ccValue)); + setDefaultHdcc(member.parameters.back(), member.read(Default::loCC)); } break; case hash("set_hdcc&"): if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) { - const auto ccValue = member.read(Default::normalized); - if (ccValue) - setDefaultHdcc(member.parameters.back(), *ccValue); + setDefaultHdcc(member.parameters.back(), member.read(Default::loNormalized)); } break; case hash("label_cc&"): @@ -385,10 +374,10 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) DBG("Changing default sample path to " << defaultPath_); break; case hash("note_offset"): - noteOffset_ = member.read(Default::noteOffset).value_or(noteOffset_); + noteOffset_ = member.read(Default::noteOffset); break; case hash("octave_offset"): - octaveOffset_ = member.read(Default::octaveOffset).value_or(octaveOffset_); + octaveOffset_ = member.read(Default::octaveOffset); break; case hash("hint_ram_based"): if (member.value == "1") @@ -451,22 +440,19 @@ void Synth::Impl::handleEffectOpcodes(const std::vector& rawMembers) // note(jpc): gain opcodes are linear volumes in % units case hash("directtomain"): - if (auto valueOpt = opcode.read(Default::effect)) - getOrCreateBus(0).setGainToMain(*valueOpt / 100); + getOrCreateBus(0).setGainToMain(opcode.read(Default::effect)); break; case hash("fx&tomain"): // fx&tomain if (opcode.parameters.front() < 1 || opcode.parameters.front() > config::maxEffectBuses) break; - if (auto valueOpt = opcode.read(Default::effect)) - getOrCreateBus(opcode.parameters.front()).setGainToMain(*valueOpt / 100); + getOrCreateBus(opcode.parameters.front()).setGainToMain(opcode.read(Default::effect)); break; case hash("fx&tomix"): // fx&tomix if (opcode.parameters.front() < 1 || opcode.parameters.front() > config::maxEffectBuses) break; - if (auto valueOpt = opcode.read(Default::effect)) - getOrCreateBus(opcode.parameters.front()).setGainToMix(*valueOpt / 100); + getOrCreateBus(opcode.parameters.front()).setGainToMix(opcode.read(Default::effect)); break; } } @@ -589,10 +575,10 @@ void Synth::Impl::finalizeSfzLoad() region->sampleEnd = std::min(region->sampleEnd, fileInformation->end); if (fileInformation->hasLoop) { - if (region->loopRange.getStart() == Default::loopRange.bounds.getStart()) - region->loopRange.setStart(fileInformation->loopBegin); + if (region->loopRange.getStart() == Default::loopStart) + region->loopRange.setStart(fileInformation->loopStart); - if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) + if (region->loopRange.getEnd() == Default::loopEnd) region->loopRange.setEnd(fileInformation->loopEnd); if (!region->loopMode) @@ -602,7 +588,7 @@ void Synth::Impl::finalizeSfzLoad() if (region->isRelease() && !region->loopMode) region->loopMode = LoopMode::one_shot; - if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) + if (region->loopRange.getEnd() == Default::loopEnd) region->loopRange.setEnd(region->sampleEnd); if (fileInformation->numChannels == 2) @@ -668,13 +654,13 @@ void Synth::Impl::finalizeSfzLoad() // Set the default frequencies on equalizers if needed if (region->equalizers.size() > 0 - && region->equalizers[0].frequency == Default::eqFrequency.value) { + && region->equalizers[0].frequency == Default::eqFrequency) { region->equalizers[0].frequency = Default::defaultEQFreq[0]; if (region->equalizers.size() > 1 - && region->equalizers[1].frequency == Default::eqFrequency.value) { + && region->equalizers[1].frequency == Default::eqFrequency) { region->equalizers[1].frequency = Default::defaultEQFreq[1]; if (region->equalizers.size() > 2 - && region->equalizers[2].frequency == Default::eqFrequency.value) { + && region->equalizers[2].frequency == Default::eqFrequency) { region->equalizers[2].frequency = Default::defaultEQFreq[2]; } } diff --git a/src/sfizz/SynthConfig.h b/src/sfizz/SynthConfig.h index 47d265e6..8fdbd510 100644 --- a/src/sfizz/SynthConfig.h +++ b/src/sfizz/SynthConfig.h @@ -13,7 +13,7 @@ struct SynthConfig { bool freeWheeling { false }; - int liveSampleQuality { Default::sampleQuality.value }; + int liveSampleQuality { Default::sampleQuality }; int freeWheelingSampleQuality { Default::freewheelingQuality }; int currentSampleQuality() const noexcept diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 62335993..123fac10 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -144,11 +144,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/count", "") { GET_REGION_OR_BREAK(indices[0]) - if (!region.sampleCount) { - client.receive<'N'>(delay, path, {}); - } else { - client.receive<'h'>(delay, path, *region.sampleCount); - } + client.receive<'h'>(delay, path, region.sampleCount); } break; MATCH("/region&/loop_range", "") { diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index bd34ec22..b71e9810 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -257,8 +257,8 @@ struct Synth::Impl final: public Parser::Listener { // Control opcodes std::string defaultPath_ { "" }; - int noteOffset_ { Default::noteOffset.value }; - int octaveOffset_ { Default::octaveOffset.value }; + int noteOffset_ { Default::noteOffset }; + int octaveOffset_ { Default::octaveOffset }; // Modulation source generators std::unique_ptr genController_; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index dae62336..8a13834f 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -371,7 +371,7 @@ void Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe } const float phase = region->getPhase(); const int quality = - region->oscillatorQuality.value_or(Default::oscillatorQuality.value); + region->oscillatorQuality.value_or(Default::oscillatorQuality); for (WavetableOscillator& osc : impl.waveOscillators_) { osc.setWavetable(wave); osc.setPhase(phase); @@ -465,7 +465,7 @@ void Voice::off(int delay, bool fast) noexcept Impl& impl = *impl_; if (!impl.region_->flexAmpEG) { if (impl.region_->offMode == OffMode::fast || fast) { - impl.egAmplitude_.setReleaseTime(Default::offTime.value); + impl.egAmplitude_.setReleaseTime(Default::offTime); } else if (impl.region_->offMode == OffMode::time) { impl.egAmplitude_.setReleaseTime(impl.region_->offTime); } diff --git a/src/sfizz/effects/Apan.cpp b/src/sfizz/effects/Apan.cpp index 9151188a..d100361f 100644 --- a/src/sfizz/effects/Apan.cpp +++ b/src/sfizz/effects/Apan.cpp @@ -81,28 +81,22 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("apan_waveform"): - if (auto value = opc.read(Default::apanWaveform)) - apan->_lfoWave = *value; + apan->_lfoWave = opc.read(Default::apanWaveform); break; case hash("apan_freq"): - if (auto value = opc.read(Default::apanFrequency)) - apan->_lfoFrequency = *value; + apan->_lfoFrequency = opc.read(Default::apanFrequency); break; case hash("apan_phase"): - if (auto value = opc.read(Default::apanPhase)) - apan->_lfoPhaseOffset = wrapPhase(*value); + apan->_lfoPhaseOffset = opc.read(Default::apanPhase); break; case hash("apan_dry"): - if (auto value = opc.read(Default::apanLevel)) - apan->_dry = *value / 100.0f; + apan->_dry = opc.read(Default::apanLevel); break; case hash("apan_wet"): - if (auto value = opc.read(Default::apanLevel)) - apan->_wet = *value / 100.0f; + apan->_wet = opc.read(Default::apanLevel); break; case hash("apan_depth"): - if (auto value = opc.read(Default::apanLevel)) - apan->_depth = *value / 100.0f; + apan->_depth = opc.read(Default::apanLevel); break; } } diff --git a/src/sfizz/effects/Apan.h b/src/sfizz/effects/Apan.h index ac72e524..9e30c144 100644 --- a/src/sfizz/effects/Apan.h +++ b/src/sfizz/effects/Apan.h @@ -52,12 +52,12 @@ namespace fx { sfz::Buffer _lfoOutRight { config::defaultSamplesPerBlock }; // Controls - float _dry { Default::apanLevel.value }; - float _wet { Default::apanLevel.value }; - float _depth { Default::apanLevel.value }; - int _lfoWave { Default::apanWaveform.value }; - float _lfoFrequency { Default::apanFrequency.value }; - float _lfoPhaseOffset { Default::apanPhase.value }; + float _dry { Default::apanLevel }; + float _wet { Default::apanLevel }; + float _depth { Default::apanLevel }; + int _lfoWave { Default::apanWaveform }; + float _lfoFrequency { Default::apanFrequency }; + float _lfoPhaseOffset { Default::apanPhase }; // State float _lfoPhase { 0.0f }; diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index 94f4b242..8fffd680 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -31,8 +31,8 @@ namespace fx { struct Compressor::Impl { faustCompressor _compressor[2]; - bool _stlink { Default::compSTLink.value }; - float _inputGain { Default::compGain.value }; + bool _stlink { Default::compSTLink }; + float _inputGain { Default::compGain }; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; hiir::Downsampler2xFpu<12> _downsampler2x[EffectChannels]; @@ -163,35 +163,38 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("comp_attack"): - if (auto value = opc.read(Default::compAttack)) { + { + auto value = opc.read(Default::compAttack); for (size_t c = 0; c < 2; ++c) - impl.set_Attack(c, *value); + impl.set_Attack(c, value); } break; case hash("comp_release"): - if (auto value = opc.read(Default::compRelease)) { + { + auto value = opc.read(Default::compRelease); for (size_t c = 0; c < 2; ++c) - impl.set_Release(c, *value); + impl.set_Release(c, value); } break; case hash("comp_threshold"): - if (auto value = opc.read(Default::compThreshold)) { + { + auto value = opc.read(Default::compThreshold); for (size_t c = 0; c < 2; ++c) - impl.set_Threshold(c, *value); + impl.set_Threshold(c, value); } break; case hash("comp_ratio"): - if (auto value = opc.read(Default::compRatio)) { + { + auto value = opc.read(Default::compRatio); for (size_t c = 0; c < 2; ++c) - impl.set_Ratio(c, *value); + impl.set_Ratio(c, value); } break; case hash("comp_gain"): - if (auto value = opc.read(Default::compGain)) - impl._inputGain = db2mag(*value); + impl._inputGain = opc.read(Default::compGain); break; case hash("comp_stlink"): - impl._stlink = opc.read(Default::compSTLink).value_or(impl._stlink); + impl._stlink = opc.read(Default::compSTLink); break; } } diff --git a/src/sfizz/effects/Disto.cpp b/src/sfizz/effects/Disto.cpp index c3939f9e..946fdae6 100644 --- a/src/sfizz/effects/Disto.cpp +++ b/src/sfizz/effects/Disto.cpp @@ -38,11 +38,11 @@ struct Disto::Impl { enum { maxStages = 4 }; float _samplePeriod { 1.0f / config::defaultSampleRate }; - float _tone { Default::distoTone.value }; - float _depth { Default::distoDepth.value }; - float _dry { Default::effect.value }; - float _wet { Default::effect.value }; - unsigned _numStages = { Default::distoStages.value }; + float _tone { Default::distoTone }; + float _depth { Default::distoDepth }; + float _dry { Default::effect }; + float _wet { Default::effect }; + unsigned _numStages = { Default::distoStages }; float _toneLpfMem[EffectChannels] = {}; faustDisto _stages[EffectChannels][Default::maxDistoStages]; @@ -205,24 +205,19 @@ std::unique_ptr Disto::makeInstance(absl::Span members) for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("disto_tone"): - if (auto value = opc.read(Default::distoTone)) - impl._tone = *value; + impl._tone = opc.read(Default::distoTone); break; case hash("disto_depth"): - if (auto value = opc.read(Default::distoDepth)) - impl._depth = *value; + impl._depth = opc.read(Default::distoDepth); break; case hash("disto_stages"): - if (auto value = opc.read(Default::distoStages)) - impl._numStages = *value; + impl._numStages = opc.read(Default::distoStages); break; case hash("disto_dry"): - if (auto value = opc.read(Default::effect)) - impl._dry = *value * 0.01f; + impl._dry = opc.read(Default::effect); break; case hash("disto_wet"): - if (auto value = opc.read(Default::effect)) - impl._wet = *value * 0.01f; + impl._wet = opc.read(Default::effect); break; } } diff --git a/src/sfizz/effects/Eq.cpp b/src/sfizz/effects/Eq.cpp index 751ccc12..25036195 100644 --- a/src/sfizz/effects/Eq.cpp +++ b/src/sfizz/effects/Eq.cpp @@ -70,22 +70,17 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("eq_freq"): - if (auto value = opc.read(Default::eqFrequency)) - desc.frequency = *value; + desc.frequency = opc.read(Default::eqFrequency); break; case hash("eq_bw"): - if (auto value = opc.read(Default::eqBandwidth)) - desc.bandwidth = *value; + desc.bandwidth = opc.read(Default::eqBandwidth); break; case hash("eq_gain"): - if (auto value = opc.read(Default::eqGain)) - desc.gain = *value; + desc.gain = opc.read(Default::eqGain); break; case hash("eq_type"): - { - desc.type = opc.read(Default::eq).value_or(desc.type); - break; - } + desc.type = opc.read(Default::eq); + break; } } diff --git a/src/sfizz/effects/Filter.cpp b/src/sfizz/effects/Filter.cpp index b3765b61..8b2dff72 100644 --- a/src/sfizz/effects/Filter.cpp +++ b/src/sfizz/effects/Filter.cpp @@ -72,22 +72,17 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("filter_cutoff"): - if (auto value = opc.read(Default::filterCutoff)) - desc.cutoff = *value; + desc.cutoff = opc.read(Default::filterCutoff); break; case hash("filter_resonance"): - if (auto value = opc.read(Default::filterResonance)) - desc.resonance = *value; + desc.resonance = opc.read(Default::filterResonance); break; case hash("filter_type"): - { - desc.type = opc.read(Default::filter).value_or(desc.type); - break; - } + desc.type = opc.read(Default::filter); + break; // extension case hash("sfizz:filter_gain"): - if (auto value = opc.read(Default::filterGain)) - desc.gain = *value; + desc.gain = opc.read(Default::filterGain); break; } } diff --git a/src/sfizz/effects/Fverb.cpp b/src/sfizz/effects/Fverb.cpp index c3a1f408..c8ab7938 100644 --- a/src/sfizz/effects/Fverb.cpp +++ b/src/sfizz/effects/Fverb.cpp @@ -180,13 +180,13 @@ namespace fx { std::unique_ptr fx { reverb }; const Impl::Profile* profile = &Impl::largeHall; - float dry { Default::effect.value }; - float wet { Default::effect.value }; - float input { Default::effect.value }; - float size { Default::fverbSize.value }; - float predelay { Default::fverbPredelay.value }; - float tone { Default::fverbTone.value }; - float damp { Default::fverbDamp.value }; + float dry { Default::effect }; + float wet { Default::effect }; + float input { Default::effect }; + float size { Default::fverbSize }; + float predelay { Default::fverbPredelay }; + float tone { Default::fverbTone }; + float damp { Default::fverbDamp }; for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { @@ -212,25 +212,25 @@ namespace fx { break; case hash("reverb_dry"): - dry = opc.read(Default::effect).value_or(dry); + dry = opc.read(Default::effect); break; case hash("reverb_wet"): - wet = opc.read(Default::effect).value_or(wet); + wet = opc.read(Default::effect); break; case hash("reverb_input"): - input = opc.read(Default::effect).value_or(input); + input = opc.read(Default::effect); break; case hash("reverb_size"): - size = opc.read(Default::fverbSize).value_or(size); + size = opc.read(Default::fverbSize); break; case hash("reverb_predelay"): - predelay = opc.read(Default::fverbPredelay).value_or(predelay); + predelay = opc.read(Default::fverbPredelay); break; case hash("reverb_tone"): - tone = opc.read(Default::fverbTone).value_or(tone); + tone = opc.read(Default::fverbTone); break; case hash("reverb_damp"): - damp = opc.read(Default::fverbDamp).value_or(damp); + damp = opc.read(Default::fverbDamp); break; } } diff --git a/src/sfizz/effects/Gain.cpp b/src/sfizz/effects/Gain.cpp index 7ad9fb9f..aa8d6d03 100644 --- a/src/sfizz/effects/Gain.cpp +++ b/src/sfizz/effects/Gain.cpp @@ -62,8 +62,7 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("gain"): - if (auto value = opc.read(Default::volume)) - gain->_gain = *value; + gain->_gain = opc.read(Default::volume); break; } } diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index a4a916a3..7bbc158a 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -34,7 +34,7 @@ namespace fx { struct Gate::Impl { faustGate _gate[2]; - bool _stlink { Default::gateSTLink.value }; + bool _stlink { Default::gateSTLink }; float _inputGain = 1.0; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; @@ -166,31 +166,35 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("gate_attack"): - if (auto value = opc.read(Default::gateAttack)) { + { + auto value = opc.read(Default::gateAttack); for (size_t c = 0; c < 2; ++c) - impl.set_Attack(c, *value); + impl.set_Attack(c, value); } break; case hash("gate_hold"): - if (auto value = opc.read(Default::gateHold)) { + { + auto value = opc.read(Default::gateHold); for (size_t c = 0; c < 2; ++c) - impl.set_Hold(c, *value); + impl.set_Hold(c, value); } break; case hash("gate_release"): - if (auto value = opc.read(Default::gateRelease)) { + { + auto value = opc.read(Default::gateRelease); for (size_t c = 0; c < 2; ++c) - impl.set_Release(c, *value); + impl.set_Release(c, value); } break; case hash("gate_threshold"): - if (auto value = opc.read(Default::gateThreshold)) { + { + auto value = opc.read(Default::gateThreshold); for (size_t c = 0; c < 2; ++c) - impl.set_Threshold(c, *value); + impl.set_Threshold(c, value); } break; case hash("gate_stlink"): - impl._stlink = opc.read(Default::gateSTLink).value_or(impl._stlink); + impl._stlink = opc.read(Default::gateSTLink); } } diff --git a/src/sfizz/effects/Lofi.cpp b/src/sfizz/effects/Lofi.cpp index 00a11128..24aaf772 100644 --- a/src/sfizz/effects/Lofi.cpp +++ b/src/sfizz/effects/Lofi.cpp @@ -85,12 +85,10 @@ namespace fx { for (const Opcode& opcode : members) { switch (opcode.lettersOnlyHash) { case hash("bitred"): - if (auto value = opcode.read(Default::lofiBitred)) - lofi->_bitred_depth = *value; + lofi->_bitred_depth = opcode.read(Default::lofiBitred); break; case hash("decim"): - if (auto value = opcode.read(Default::lofiDecim)) - lofi->_decim_depth = *value; + lofi->_decim_depth = opcode.read(Default::lofiDecim); break; } } diff --git a/src/sfizz/effects/Rectify.cpp b/src/sfizz/effects/Rectify.cpp index f8d271dd..5d25be46 100644 --- a/src/sfizz/effects/Rectify.cpp +++ b/src/sfizz/effects/Rectify.cpp @@ -95,8 +95,7 @@ namespace fx { rectify->_full = false; break; case hash("rectify"): - if (auto value = opc.read(Default::rectify)) - rectify->_amount = *value; + rectify->_amount = opc.read(Default::rectify); break; } } diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index 6538b68a..2ef50f7c 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -132,12 +132,10 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("strings_number"): - if (auto value = opc.read(Default::stringsNumber)) - strings->_numStrings = *value; + strings->_numStrings = opc.read(Default::stringsNumber); break; case hash("strings_wet"): - if (auto value = opc.read(Default::effect)) - strings->_wet = *value; + strings->_wet = opc.read(Default::effect); break; } } diff --git a/src/sfizz/effects/Strings.h b/src/sfizz/effects/Strings.h index f20ae8a8..29121174 100644 --- a/src/sfizz/effects/Strings.h +++ b/src/sfizz/effects/Strings.h @@ -52,7 +52,7 @@ namespace fx { enum { MaximumNumStrings = 88 }; unsigned _numStrings { Default::maxStrings }; - float _wet { Default::effect.value }; + float _wet { Default::effect }; std::unique_ptr _stringsArray; diff --git a/src/sfizz/effects/Width.cpp b/src/sfizz/effects/Width.cpp index 2a3cdc92..98906e52 100644 --- a/src/sfizz/effects/Width.cpp +++ b/src/sfizz/effects/Width.cpp @@ -69,8 +69,7 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("width"): - if (auto value = opc.read(Default::width)) - width->_width = *value; + width->_width = opc.read(Default::width); break; } } diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 61971b39..7439a306 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -317,8 +317,8 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") SECTION("Ignore") { Opcode opcode { "", "110" }; - OpcodeSpec spec { 0, Range(0, 100), kIgnoreOOB }; - REQUIRE( !opcode.read(spec) ); + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == spec.defaultValue ); } SECTION("Clamp upper") @@ -345,21 +345,21 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") SECTION("Text after") { Opcode opcode { "", "10garbage" }; - OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; - REQUIRE( opcode.read(spec) == 20 ); + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 10 ); } SECTION("Text before") { Opcode opcode { "", "garbage10" }; - OpcodeSpec spec { 0, Range(20, 100), 0 }; - REQUIRE( !opcode.read(spec) ); + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == spec.defaultValue ); } SECTION("Can be note") { Opcode opcode { "", "c4" }; - OpcodeSpec spec { 0, Range(20, 100), kCanBeNote }; + OpcodeSpec spec { 0, Range(0, 100), kCanBeNote }; REQUIRE( opcode.read(spec) == 60 ); } } @@ -387,13 +387,6 @@ TEST_CASE("[Opcode] opcode read (int)") REQUIRE( opcode.read(spec) == -16); } - SECTION("Ignore") - { - Opcode opcode { "", "110" }; - OpcodeSpec spec { 0, Range(-100, 100), kIgnoreOOB }; - REQUIRE( !opcode.read(spec) ); - } - SECTION("Clamp upper") { Opcode opcode { "", "110" }; @@ -418,7 +411,7 @@ TEST_CASE("[Opcode] opcode read (int)") SECTION("Text after") { Opcode opcode { "", "10garbage" }; - OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; + OpcodeSpec spec { 0, Range(20, 100), 0 }; REQUIRE( opcode.read(spec) == 20 ); } @@ -464,8 +457,8 @@ TEST_CASE("[Opcode] opcode read (float)") SECTION("Ignore") { Opcode opcode { "", "110" }; - OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; - REQUIRE( !opcode.read(spec) ); + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; + REQUIRE( opcode.read(spec) == spec.defaultValue ); } SECTION("Clamp upper") diff --git a/tests/RegionValueComputationsT.cpp b/tests/RegionValueComputationsT.cpp index 39412b95..f3b1abca 100644 --- a/tests/RegionValueComputationsT.cpp +++ b/tests/RegionValueComputationsT.cpp @@ -299,15 +299,15 @@ TEST_CASE("[Region] rt_decay") region.parseOpcode({ "rt_decay", "10" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value - 1.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 1.0f).margin(0.1) ); region.parseOpcode({ "rt_decay", "20" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value - 2.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 2.0f).margin(0.1) ); region.parseOpcode({ "trigger", "attack" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume).margin(0.1) ); } TEST_CASE("[Region] Base delay") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index a3e02417..a457607b 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -248,9 +248,9 @@ TEST_CASE("[Values] Count") synth.dispatchMessage(client, 0, "/region1/count", "", nullptr); synth.dispatchMessage(client, 0, "/region2/count", "", nullptr); std::vector expected { - "/region0/count,N : { }", + "/region0/count,h : { 1 }", "/region1/count,h : { 2 }", - "/region2/count,N : { }", + "/region2/count,h : { 1 }", }; REQUIRE(messageList == expected); } @@ -453,7 +453,7 @@ TEST_CASE("[Values] Off time") std::vector expected { "/region0/off_time,f : { 0.006 }", "/region1/off_time,f : { 0.1 }", - "/region2/off_time,f : { 0 }", + "/region2/off_time,f : { 0.006 }", }; REQUIRE(messageList == expected); } @@ -747,7 +747,7 @@ TEST_CASE("[Values] Upswitch") "/region2/sw_up,N : { }", "/region3/sw_up,N : { }", "/region4/sw_up,i : { 60 }", - "/region5/sw_up,i : { 64 }", + "/region5/sw_up,i : { 60 }", }; REQUIRE(messageList == expected); } @@ -778,7 +778,7 @@ TEST_CASE("[Values] Downswitch") "/region2/sw_down,N : { }", "/region3/sw_down,N : { }", "/region4/sw_down,i : { 60 }", - "/region5/sw_down,i : { 64 }", + "/region5/sw_down,i : { 60 }", }; REQUIRE(messageList == expected); } diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index fa5cb076..78701e5b 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -572,7 +572,7 @@ TEST_CASE("[Synth] sample quality") // default sample quality synth.noteOn(0, 60, 100); REQUIRE(synth.getNumActiveVoices() == 1); - REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality.value); + REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality); synth.allSoundOff(); // default sample quality, freewheeling From 9a1e3971a9ac2599b0a85d8e190c64fa82f512e8 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 3 Feb 2021 10:43:05 +0100 Subject: [PATCH 249/668] WIP --- src/CMakeLists.txt | 2 +- src/sfizz/Defaults.cpp | 32 ++++++++++---------- src/sfizz/Defaults.h | 41 ++++++++++++++++++++++--- src/sfizz/Opcode.cpp | 66 +++++++++++++++++++---------------------- src/sfizz/Opcode.h | 5 +++- src/sfizz/Region.cpp | 14 ++++----- src/sfizz/Region.h | 2 +- src/sfizz/SfzHelpers.h | 13 +++++--- tests/OpcodeT.cpp | 6 ++-- tests/RegionValuesT.cpp | 13 ++++---- 10 files changed, 113 insertions(+), 81 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d3c1f2bc..c2e40836 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,7 +137,6 @@ set(SFIZZ_SOURCES sfizz/Wavetables.cpp sfizz/Tuning.cpp sfizz/RegionSet.cpp - sfizz/Defaults.cpp sfizz/PolyphonyGroup.cpp sfizz/VoiceManager.cpp sfizz/VoiceStealing.cpp @@ -201,6 +200,7 @@ set(SFIZZ_PARSER_HEADERS set(SFIZZ_PARSER_SOURCES sfizz/Opcode.cpp + sfizz/Defaults.cpp sfizz/OpcodeCleanup.cpp sfizz/parser/Parser.cpp sfizz/parser/ParserPrivate.cpp) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index ee712e58..f883bc20 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -1,6 +1,4 @@ #include "Defaults.h" -#include "MathHelpers.h" -#include "SfzHelpers.h" namespace sfz { @@ -23,7 +21,7 @@ extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), 0 }; extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), 0 }; extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), 0 }; extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; @@ -33,14 +31,14 @@ extern const OpcodeSpec notePolyphony { config::maxVoices, Range key { 60, Range(0, 127), kCanBeNote }; extern const OpcodeSpec loKey { 0, Range(0, 127), kCanBeNote }; extern const OpcodeSpec hiKey { 127, Range(0, 127), kCanBeNote }; -extern const OpcodeSpec loCC { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec hiCC { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec loVel { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec hiVel { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loCC { 0, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiCC { 127, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loVel { 0, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiVel { 127, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec loChannelAftertouch { 0, Range(0, 127), 0 }; extern const OpcodeSpec hiChannelAftertouch { 127, Range(0, 127), 0 }; -extern const OpcodeSpec loBend { -1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; -extern const OpcodeSpec hiBend { 1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec loBend { -8192, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec hiBend { 8192, Range(-8192.0f, 8192.0f), kNormalizeBend }; extern const OpcodeSpec loNormalized { 0.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec hiNormalized { 1.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec loBipolar { -1.0f, Range(-1.0f, 1.0f), 0 }; @@ -49,7 +47,7 @@ extern const OpcodeSpec ccNumber { 0, Range(0, config::numCC extern const OpcodeSpec smoothCC { 0, Range(0, 100), 0 }; extern const OpcodeSpec curveCC { 0, Range(0, 255), 0 }; extern const OpcodeSpec sustainCC { 64, Range(0, 127), 0 }; -extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec sustainThreshold { 1, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; extern const OpcodeSpec loBPM { 0.0f, Range(0.0f, 500.0f), 0 }; @@ -58,19 +56,19 @@ extern const OpcodeSpec sequence { 1, Range(1, 100), 0 }; extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; extern const OpcodeSpec volumeMod { 0.0f, Range(-144.0f, 48.0f), 0 }; extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 10000.0f), kNormalizePercent }; -extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec crossfadeIn { 0.0f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec crossfadeOut { 1.0f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec crossfadeOut { 127.0f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), 0 }; -extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), 0 }; extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; @@ -144,7 +142,7 @@ extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), 0 extern const OpcodeSpec compSTLink { false, Range(0, 1), 0 }; extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), 0 }; -extern const OpcodeSpec compGain { 1.0f, Range(-100.0f, 100.0f), kDb2Mag }; +extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), kDb2Mag }; extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), 0 }; extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), 0 }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 27f5481c..8e25ec5e 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -24,11 +24,14 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once +#include +#include +#include #include "Range.h" #include "Config.h" #include "SfzFilter.h" -#include -#include +#include "SfzHelpers.h" +#include "MathHelpers.h" namespace sfz @@ -68,10 +71,40 @@ enum OpcodeFlags : int { template struct OpcodeSpec { - T defaultValue; + T defaultInputValue; Range bounds; int flags; - operator T() const { return defaultValue; } + template + typename std::enable_if::value, U>::type normalizeInput(U input) const + { + constexpr auto needsOperation { + kNormalizePercent | + kNormalizeMidi | + kNormalizeBend | + kDb2Mag + }; + + if (!(flags & needsOperation)) + return input; + else if (flags & kNormalizePercent) + return normalizePercents(input); + else if (flags & kNormalizeMidi) + return normalize7Bits(input); + else if (flags & kNormalizeBend) + return normalizeBend(input); + else if (flags & kDb2Mag) + return db2mag(input); + else // just in case + return input; + } + + template + typename std::enable_if::value, U>::type normalizeInput(U input) const + { + return input; + } + + operator T() const { return normalizeInput(defaultInputValue); } }; namespace Default diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index a3e747fc..fcc323a8 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -155,9 +155,9 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) #define INSTANTIATE_FOR_INTEGRAL(T) \ template <> \ - T Opcode::read(OpcodeSpec spec) const \ + absl::optional Opcode::readOptional(OpcodeSpec spec) const \ { \ - return readInt_(spec, value).value_or(spec.defaultValue); \ + return readInt_(spec, value); \ } INSTANTIATE_FOR_INTEGRAL(uint8_t) @@ -205,23 +205,14 @@ absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) return {}; } - if (spec.flags & kNormalizeMidi) - returnedValue = normalize7Bits(returnedValue); - else if (spec.flags & kNormalizePercent) - returnedValue = normalizePercents(returnedValue); - else if (spec.flags & kNormalizeBend) - returnedValue = normalizeBend(returnedValue); - else if (spec.flags & kDb2Mag) - returnedValue = db2mag(returnedValue); - - return returnedValue; + return spec.normalizeInput(returnedValue); } #define INSTANTIATE_FOR_FLOATING_POINT(T) \ template <> \ - T Opcode::read(OpcodeSpec spec) const \ + absl::optional Opcode::readOptional(OpcodeSpec spec) const \ { \ - return readFloat_(spec, value).value_or(spec.defaultValue); \ + return readFloat_(spec, value); \ } INSTANTIATE_FOR_FLOATING_POINT(float) @@ -292,17 +283,17 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) } template <> -OscillatorEnabled Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { auto v = readBooleanFromOpcode(*this); if (!v) - return spec.defaultValue; + return {}; return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; } template <> -Trigger Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("attack"): return Trigger::attack; @@ -313,11 +304,11 @@ Trigger Opcode::read(OpcodeSpec spec) const } DBG("Unknown trigger value: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -CrossfadeCurve Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("power"): return CrossfadeCurve::power; @@ -325,11 +316,11 @@ CrossfadeCurve Opcode::read(OpcodeSpec spec) const } DBG("Unknown crossfade power curve: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -OffMode Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("fast"): return OffMode::fast; @@ -338,11 +329,11 @@ OffMode Opcode::read(OpcodeSpec spec) const } DBG("Unknown off mode: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -FilterType Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("lpf_1p"): return kFilterLpf1p; @@ -371,11 +362,11 @@ FilterType Opcode::read(OpcodeSpec spec) const } DBG("Unknown filter type: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -EqType Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("peak"): return kEqPeak; @@ -384,11 +375,11 @@ EqType Opcode::read(OpcodeSpec spec) const } DBG("Unknown EQ type: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -VelocityOverride Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("current"): return VelocityOverride::current; @@ -396,11 +387,11 @@ VelocityOverride Opcode::read(OpcodeSpec spec) const } DBG("Unknown velocity override: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -SelfMask Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("on"): @@ -409,25 +400,28 @@ SelfMask Opcode::read(OpcodeSpec spec) const } DBG("Unknown velocity override: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -bool Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { - return readBooleanFromOpcode(*this).value_or(spec.defaultValue); + return readBooleanFromOpcode(*this); } template <> -LFOWave Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec spec) const { const OpcodeSpec intSpec { - static_cast(spec.defaultValue), + static_cast(spec.defaultInputValue), Range(static_cast(spec.bounds.getStart()), static_cast(spec.bounds.getEnd())), 0 }; - int value = read(intSpec); - return static_cast(value); + + if (auto value = readOptional(intSpec)) + return static_cast(*value); + + return absl::nullopt; } } // namespace sfz diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index 3df4ed08..314e64f0 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -102,7 +102,10 @@ struct Opcode { } template - T read(OpcodeSpec spec) const; + absl::optional readOptional(OpcodeSpec spec) const; + + template + T read(OpcodeSpec spec) const { return readOptional(spec).value_or(spec); } private: static OpcodeCategory identifyCategory(absl::string_view name); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 0f86c802..d892bd68 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -283,8 +283,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("sw_last"): if (!lastKeyswitchRange) { - lastKeyswitch = opcode.read(Default::key); - keySwitched = false; + lastKeyswitch = opcode.readOptional(Default::key); + keySwitched = !lastKeyswitch.has_value(); } break; case hash("sw_lolast"): @@ -315,15 +315,15 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) keyswitchLabel = opcode.value; break; case hash("sw_down"): - downKeyswitch = opcode.read(Default::key); - keySwitched = false; + downKeyswitch = opcode.readOptional(Default::key); + keySwitched = !downKeyswitch.has_value(); break; case hash("sw_up"): - upKeyswitch = opcode.read(Default::key); + upKeyswitch = opcode.readOptional(Default::key); break; case hash("sw_previous"): - previousKeyswitch = opcode.read(Default::key); - previousKeySwitched = false; + previousKeyswitch = opcode.readOptional(Default::key); + previousKeySwitched = !previousKeyswitch.has_value(); break; case hash("sw_vel"): velocityOverride = diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 4a7324f8..c0ea5968 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -389,7 +389,7 @@ struct Region { float position { normalizePercents(Default::position) }; // position uint8_t ampKeycenter { Default::key }; // amp_keycenter float ampKeytrack { Default::ampKeytrack }; // amp_keytrack - float ampVeltrack { normalizePercents(Default::ampVeltrack) }; // amp_veltrack + float ampVeltrack { Default::ampVeltrack }; // amp_veltrack std::vector> velocityPoints; // amp_velcurve_N absl::optional velCurve {}; float ampRandom { Default::ampRandom }; // amp_random diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 7577d60d..8fd15b33 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -16,7 +16,6 @@ #include "MathHelpers.h" #include "SIMDHelpers.h" #include "absl/meta/type_traits.h" -#include "Defaults.h" namespace sfz { @@ -126,6 +125,12 @@ constexpr float normalize7Bits(T value) return static_cast(min(max(value, T { 0 }), T { 127 })) / 127.0f; } +template <> +constexpr float normalize7Bits(bool value) +{ + return value ? 1.0f : 0.0f; +} + /** * @brief Normalize a CC value between 0.0 and 1.0 * @@ -188,11 +193,11 @@ inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset) { const int offsetKey { key + offset }; if (offsetKey > std::numeric_limits::max()) - return Default::key.bounds.getEnd(); + return 127; if (offsetKey < std::numeric_limits::min()) - return Default::key.bounds.getStart(); + return 0; - return Default::key.bounds.clamp(static_cast(offsetKey)); + return clamp(static_cast(offsetKey), 0, 127); } namespace literals { diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 7439a306..b01201a5 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -318,7 +318,7 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") { Opcode opcode { "", "110" }; OpcodeSpec spec { 0, Range(0, 100), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Clamp upper") @@ -353,7 +353,7 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0, Range(0, 100), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Can be note") @@ -458,7 +458,7 @@ TEST_CASE("[Opcode] opcode read (float)") { Opcode opcode { "", "110" }; OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Clamp upper") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index a457607b..c0e85444 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -747,7 +747,7 @@ TEST_CASE("[Values] Upswitch") "/region2/sw_up,N : { }", "/region3/sw_up,N : { }", "/region4/sw_up,i : { 60 }", - "/region5/sw_up,i : { 60 }", + "/region5/sw_up,N : { }", }; REQUIRE(messageList == expected); } @@ -778,7 +778,7 @@ TEST_CASE("[Values] Downswitch") "/region2/sw_down,N : { }", "/region3/sw_down,N : { }", "/region4/sw_down,i : { 60 }", - "/region5/sw_down,i : { 60 }", + "/region5/sw_down,N : { }", }; REQUIRE(messageList == expected); } @@ -809,7 +809,7 @@ TEST_CASE("[Values] Previous keyswitch") "/region2/sw_previous,N : { }", "/region3/sw_previous,N : { }", "/region4/sw_previous,i : { 60 }", - "/region5/sw_previous,i : { 64 }", + "/region5/sw_previous,N : { }", }; REQUIRE(messageList == expected); } @@ -889,7 +889,7 @@ TEST_CASE("[Values] BPM range") "/region0/bpm_range,ff : { 0, 500 }", "/region1/bpm_range,ff : { 34.1, 60.2 }", "/region2/bpm_range,ff : { 0, 60 }", - "/region3/bpm_range,ff : { 0, 0 }", + "/region3/bpm_range,ff : { 20, 500 }", "/region4/bpm_range,ff : { 10, 10 }", }; REQUIRE(messageList == expected); @@ -1553,12 +1553,11 @@ TEST_CASE("[Values] Amp Veltrack") )"); synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr); synth.dispatchMessage(client, 0, "/region1/amp_veltrack", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr); std::vector expected { "/region0/amp_veltrack,f : { 100 }", "/region1/amp_veltrack,f : { 10.1 }", - // "/region2/amp_veltrack,f : { 100 }", + "/region2/amp_veltrack,f : { 100 }", }; REQUIRE(messageList == expected); } From 49d749e35481fae9f66d67791d0eeb8bff02337f Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 3 Feb 2021 21:57:17 +0100 Subject: [PATCH 250/668] WIP --- src/sfizz/Defaults.h | 8 ++++---- src/sfizz/Region.h | 8 ++++---- src/sfizz/Synth.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 8e25ec5e..65e7215f 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -87,13 +87,13 @@ struct OpcodeSpec if (!(flags & needsOperation)) return input; else if (flags & kNormalizePercent) - return normalizePercents(input); + return static_cast(normalizePercents(input)); else if (flags & kNormalizeMidi) - return normalize7Bits(input); + return static_cast(normalize7Bits(input)); else if (flags & kNormalizeBend) - return normalizeBend(input); + return static_cast(normalizeBend(input)); else if (flags & kDb2Mag) - return db2mag(input); + return static_cast(db2mag(input)); else // just in case return input; } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index c0ea5968..4b3ee6c2 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -383,10 +383,10 @@ struct Region { // Performance parameters: amplifier float volume { Default::volume }; // volume - float amplitude { normalizePercents(Default::amplitude) }; // amplitude - float pan { normalizePercents(Default::pan) }; // pan - float width { normalizePercents(Default::width) }; // width - float position { normalizePercents(Default::position) }; // position + float amplitude { Default::amplitude }; // amplitude + float pan { Default::pan }; // pan + float width { Default::width }; // width + float position { Default::position }; // position uint8_t ampKeycenter { Default::key }; // amp_keycenter float ampKeytrack { Default::ampKeytrack }; // amp_keytrack float ampVeltrack { Default::ampVeltrack }; // amp_veltrack diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index fefa48d4..58c04f4d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -360,7 +360,7 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) } break; case hash("label_cc&"): - if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) + if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) setCCLabel(member.parameters.back(), std::string(member.value)); break; case hash("label_key&"): From cb2caf4b15586705a42bfc74e8e49ab681a24f86 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Thu, 4 Feb 2021 00:19:11 +0100 Subject: [PATCH 251/668] Working tests --- src/sfizz/Curve.cpp | 3 +- src/sfizz/Defaults.cpp | 12 ++--- src/sfizz/Opcode.cpp | 12 +++-- src/sfizz/Region.cpp | 18 +++---- tests/OpcodeT.cpp | 13 +++-- tests/RegionValuesT.cpp | 106 +++++++++++++++++----------------------- 6 files changed, 79 insertions(+), 85 deletions(-) diff --git a/src/sfizz/Curve.cpp b/src/sfizz/Curve.cpp index 1f1c792b..30418d12 100644 --- a/src/sfizz/Curve.cpp +++ b/src/sfizz/Curve.cpp @@ -21,8 +21,7 @@ Curve Curve::buildCurveFromHeader( { Curve curve; bool fillStatus[NumValues] = {}; - const OpcodeSpec fullRange {0.0f, Range(-HUGE_VALF, +HUGE_VALF), 0 }; - + const OpcodeSpec fullRange {0.0f, Range{ -1e16, 1e16 }, 0 }; auto setPoint = [&curve, &fillStatus](int i, float x) { curve._points[i] = x; fillStatus[i] = true; diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index f883bc20..e56171cb 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -16,13 +16,13 @@ extern const OpcodeSpec loopStart { 0, Range(0, uint32_t_max extern const OpcodeSpec loopEnd { uint32_t_max, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), 0 }; extern const OpcodeSpec oscillator { OscillatorEnabled::Auto, Range(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 }; -extern const OpcodeSpec oscillatorPhase { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec oscillatorPhase { 0.0f, Range(-1000.0f, 1000.0f), 0 }; extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), 0 }; extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), 0 }; extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), 0 }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), 0 }; extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), 0 }; @@ -47,7 +47,7 @@ extern const OpcodeSpec ccNumber { 0, Range(0, config::numCC extern const OpcodeSpec smoothCC { 0, Range(0, 100), 0 }; extern const OpcodeSpec curveCC { 0, Range(0, 255), 0 }; extern const OpcodeSpec sustainCC { 64, Range(0, 127), 0 }; -extern const OpcodeSpec sustainThreshold { 1, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec sustainThreshold { 1.0f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; extern const OpcodeSpec loBPM { 0.0f, Range(0.0f, 500.0f), 0 }; @@ -94,8 +94,8 @@ extern const OpcodeSpec pitchKeytrack { 100, Range(-1200, 1200), 0 }; extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), 0 }; extern const OpcodeSpec pitchVeltrack { 0, Range(-12000, 12000), 0 }; extern const OpcodeSpec transpose { 0, Range(-127, 127), 0 }; -extern const OpcodeSpec pitch { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec pitchMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec pitch { 0.0f, Range(-2400.0f, 2400.0f), 0 }; +extern const OpcodeSpec pitchMod { 0.0f, Range(-2400.0f, 2400.0f), 0 }; extern const OpcodeSpec bendUp { 200.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec bendDown { -200.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), 0 }; diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index fcc323a8..201709de 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -142,12 +142,12 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); - return {}; + return absl::nullopt; } else if (returnedValue < static_cast(spec.bounds.getStart())) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); - return {}; + return absl::nullopt; } return returnedValue; @@ -273,13 +273,19 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) // Cakewalk-style booleans, case-insensitive if (absl::EqualsIgnoreCase(opcode.value, "off")) return false; + if (absl::EqualsIgnoreCase(opcode.value, "on")) return true; // ARIA-style booleans? (seen in egN_dynamic=1 for example) // TODO check this const OpcodeSpec fullInt64 { 0, Range::wholeRange(), 0 }; - return opcode.read(fullInt64); + const auto v = opcode.readOptional(fullInt64); + + if (v) + return v != 0; + + return absl::nullopt; } template <> diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index d892bd68..d2710e0e 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -177,7 +177,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) ModKey::createNXYZ(ModId::OscillatorModDepth, id)); break; case hash("oscillator_quality"): - oscillatorQuality = opcode.read(Default::oscillatorQuality); + oscillatorQuality = opcode.readOptional(Default::oscillatorQuality); break; // Instrument settings: voice lifecycle @@ -334,7 +334,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) sustainCC = opcode.read(Default::sustainCC); break; case hash("sustain_lo"): - sustainThreshold = normalizeCC(opcode.read(Default::sustainThreshold)); + sustainThreshold = opcode.read(Default::sustainThreshold); break; case hash("sustain_sw"): checkSustain = opcode.read(Default::checkSustain); @@ -460,10 +460,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) crossfadeKeyInRange.setStart(opcode.read(Default::loKey)); break; case hash("xfin_hikey"): - crossfadeKeyInRange.setEnd(opcode.read(Default::hiKey)); + crossfadeKeyInRange.setEnd(opcode.read(Default::loKey)); // loKey for the proper default break; case hash("xfout_lokey"): - crossfadeKeyOutRange.setStart(opcode.read(Default::loKey)); + crossfadeKeyOutRange.setStart(opcode.read(Default::hiKey)); // hiKey for the proper default break; case hash("xfout_hikey"): crossfadeKeyOutRange.setEnd(opcode.read(Default::hiKey)); @@ -472,10 +472,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) crossfadeVelInRange.setStart(opcode.read(Default::loVel)); break; case hash("xfin_hivel"): - crossfadeVelInRange.setEnd(opcode.read(Default::hiVel)); + crossfadeVelInRange.setEnd(opcode.read(Default::loVel)); // loVel for the proper default break; case hash("xfout_lovel"): - crossfadeVelOutRange.setStart(opcode.read(Default::loVel)); + crossfadeVelOutRange.setStart(opcode.read(Default::hiVel)); // hiVel for the proper default break; case hash("xfout_hivel"): crossfadeVelOutRange.setEnd(opcode.read(Default::hiVel)); @@ -497,21 +497,21 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (opcode.parameters.back() >= config::numCCs) return false; crossfadeCCInRange[opcode.parameters.back()].setEnd( - opcode.read(Default::loCC) + opcode.read(Default::loCC) // loCC for the proper default ); break; case hash("xfout_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; crossfadeCCOutRange[opcode.parameters.back()].setStart( - opcode.read(Default::loCC) + opcode.read(Default::hiCC) // hiCC for the proper default ); break; case hash("xfout_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; crossfadeCCOutRange[opcode.parameters.back()].setEnd( - opcode.read(Default::loCC) + opcode.read(Default::hiCC) ); break; case hash("xf_cccurve"): diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index b01201a5..20ce6a24 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -353,7 +353,8 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0, Range(0, 100), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultInputValue ); + REQUIRE( !opcode.readOptional(spec) ); + REQUIRE( opcode.read(spec) == 0 ); } SECTION("Can be note") @@ -411,15 +412,16 @@ TEST_CASE("[Opcode] opcode read (int)") SECTION("Text after") { Opcode opcode { "", "10garbage" }; - OpcodeSpec spec { 0, Range(20, 100), 0 }; - REQUIRE( opcode.read(spec) == 20 ); + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 10 ); } SECTION("Text before") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0, Range(20, 100), 0 }; - REQUIRE( !opcode.read(spec) ); + REQUIRE( !opcode.readOptional(spec) ); + REQUIRE( opcode.read(spec) == 0 ); } SECTION("Can be note") @@ -486,7 +488,8 @@ TEST_CASE("[Opcode] opcode read (float)") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0.0f, Range(0.0f, 100.0f), 0 }; - REQUIRE( !opcode.read(spec) ); + REQUIRE( !opcode.readOptional(spec) ); + REQUIRE( opcode.read(spec) == 0.0f ); } } diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index c0e85444..c34b6787 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -481,8 +481,7 @@ TEST_CASE("[Values] Key range") synth.dispatchMessage(client, 0, "/region4/key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region0/pitch_keycenter", "", nullptr); synth.dispatchMessage(client, 0, "/region5/pitch_keycenter", "", nullptr); - // TODO: activate for the new region parser ; ignore the second value - // synth.dispatchMessage(client, 0, "/region6/pitch_keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region6/pitch_keycenter", "", nullptr); synth.dispatchMessage(client, 0, "/region7/key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region7/pitch_keycenter", "", nullptr); std::vector expected { @@ -493,7 +492,7 @@ TEST_CASE("[Values] Key range") "/region4/key_range,ii : { 0, 127 }", "/region0/pitch_keycenter,i : { 60 }", "/region5/pitch_keycenter,i : { 32 }", - // "/region6/pitch_keycenter,i : { 60 }", + "/region6/pitch_keycenter,i : { 60 }", "/region7/key_range,ii : { 26, 26 }", "/region7/pitch_keycenter,i : { 26 }", }; @@ -1612,7 +1611,7 @@ TEST_CASE("[Values] Crossfade key range") "/region1/xfin_key_range,ii : { 10, 40 }", "/region2/xfin_key_range,ii : { 60, 83 }", "/region3/xfin_key_range,ii : { 0, 40 }", - "/region4/xfin_key_range,ii : { 10, 10 }", + "/region4/xfin_key_range,ii : { 0, 0 }", }; REQUIRE(messageList == expected); } @@ -1666,7 +1665,7 @@ TEST_CASE("[Values] Crossfade velocity range") "/region0/xfin_vel_range,ff : { 0, 0 }", "/region1/xfin_vel_range,ff : { 0.0787402, 0.314961 }", "/region2/xfin_vel_range,ff : { 0, 0.314961 }", - "/region3/xfin_vel_range,ff : { 0.0787402, 1 }", + "/region3/xfin_vel_range,ff : { 0, 0 }", }; REQUIRE(messageList == expected); } @@ -1686,7 +1685,7 @@ TEST_CASE("[Values] Crossfade velocity range") std::vector expected { "/region0/xfout_vel_range,ff : { 1, 1 }", "/region1/xfout_vel_range,ff : { 0.0787402, 0.314961 }", - "/region2/xfout_vel_range,ff : { 0, 0.314961 }", + "/region2/xfout_vel_range,ff : { 0.314961, 0.314961 }", "/region3/xfout_vel_range,ff : { 0.0787402, 1 }", }; REQUIRE(messageList == expected); @@ -1787,7 +1786,7 @@ TEST_CASE("[Values] Crossfade CC range") "/region0/xfin_cc_range4,N : { }", "/region1/xfin_cc_range4,ff : { 0.0787402, 0.314961 }", "/region2/xfin_cc_range4,ff : { 0, 0.314961 }", - "/region3/xfin_cc_range4,ff : { 0.0787402, 1 }", + "/region3/xfin_cc_range4,ff : { 0, 0 }", }; REQUIRE(messageList == expected); } @@ -1807,7 +1806,7 @@ TEST_CASE("[Values] Crossfade CC range") std::vector expected { "/region0/xfout_cc_range4,N : { }", "/region1/xfout_cc_range4,ff : { 0.0787402, 0.314961 }", - "/region2/xfout_cc_range4,ff : { 0, 0.314961 }", + "/region2/xfout_cc_range4,ff : { 0.314961, 0.314961 }", "/region3/xfout_cc_range4,ff : { 0.0787402, 1 }", }; REQUIRE(messageList == expected); @@ -1934,12 +1933,11 @@ TEST_CASE("[Values] Pitch Random") )"); synth.dispatchMessage(client, 0, "/region0/pitch_random", "", nullptr); synth.dispatchMessage(client, 0, "/region1/pitch_random", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/pitch_random", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_random", "", nullptr); std::vector expected { "/region0/pitch_random,f : { 0 }", "/region1/pitch_random,f : { 10 }", - // "/region2/pitch_random,f : { 0 }", + "/region2/pitch_random,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -1961,15 +1959,14 @@ TEST_CASE("[Values] Transpose") synth.dispatchMessage(client, 0, "/region0/transpose", "", nullptr); synth.dispatchMessage(client, 0, "/region1/transpose", "", nullptr); synth.dispatchMessage(client, 0, "/region2/transpose", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region3/transpose", "", nullptr); - // synth.dispatchMessage(client, 0, "/region4/transpose", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/transpose", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/transpose", "", nullptr); std::vector expected { "/region0/transpose,i : { 0 }", "/region1/transpose,i : { 10 }", "/region2/transpose,i : { -4 }", - // "/region3/transpose,i : { 0 }", - // "/region4/transpose,i : { 0 }", + "/region3/transpose,i : { 0 }", + "/region4/transpose,i : { 0 }", }; REQUIRE(messageList == expected); } @@ -2320,7 +2317,7 @@ TEST_CASE("[Values] RT dead") "/region0/rt_dead,F : { }", "/region1/rt_dead,T : { }", "/region2/rt_dead,F : { }", - "/region3/rt_dead,T : { }", + "/region3/rt_dead,F : { }", }; REQUIRE(messageList == expected); } @@ -2346,7 +2343,7 @@ TEST_CASE("[Values] Sustain switch") "/region0/sustain_sw,T : { }", "/region1/sustain_sw,F : { }", "/region2/sustain_sw,T : { }", - "/region3/sustain_sw,F : { }", + "/region3/sustain_sw,T : { }", }; REQUIRE(messageList == expected); } @@ -2372,7 +2369,7 @@ TEST_CASE("[Values] Sostenuto switch") "/region0/sostenuto_sw,T : { }", "/region1/sostenuto_sw,F : { }", "/region2/sostenuto_sw,T : { }", - "/region3/sostenuto_sw,F : { }", + "/region3/sostenuto_sw,T : { }", }; REQUIRE(messageList == expected); } @@ -2391,12 +2388,11 @@ TEST_CASE("[Values] Sustain CC") )"); synth.dispatchMessage(client, 0, "/region0/sustain_cc", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sustain_cc", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sustain_cc", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sustain_cc", "", nullptr); std::vector expected { "/region0/sustain_cc,i : { 64 }", "/region1/sustain_cc,i : { 10 }", - // "/region2/sustain_cc,i : { 20 }", + "/region2/sustain_cc,i : { 64 }", }; REQUIRE(messageList == expected); } @@ -2415,12 +2411,11 @@ TEST_CASE("[Values] Sustain low") )"); synth.dispatchMessage(client, 0, "/region0/sustain_lo", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sustain_lo", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sustain_lo", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sustain_lo", "", nullptr); std::vector expected { - "/region0/sustain_lo,f : { 0.0039 }", + "/region0/sustain_lo,f : { 0.00787402 }", "/region1/sustain_lo,f : { 0.0787402 }", - // "/region2/sustain_lo,f : { 0.0787402 }", + "/region2/sustain_lo,f : { 0.00787402 }", }; REQUIRE(messageList == expected); } @@ -2469,7 +2464,7 @@ TEST_CASE("[Values] Oscillator quality") std::vector expected { "/region0/oscillator_quality,N : { }", "/region1/oscillator_quality,i : { 2 }", - "/region2/oscillator_quality,i : { 0 }", + "/region2/oscillator_quality,N : { }", }; REQUIRE(messageList == expected); } @@ -2497,7 +2492,7 @@ TEST_CASE("[Values] Oscillator mode/multi") std::vector expected { "/region0/oscillator_mode,i : { 0 }", "/region1/oscillator_mode,i : { 2 }", - "/region2/oscillator_mode,i : { 1 }", + "/region2/oscillator_mode,i : { 0 }", "/region0/oscillator_multi,i : { 1 }", "/region3/oscillator_multi,i : { 9 }", "/region4/oscillator_multi,i : { 1 }", @@ -2553,14 +2548,13 @@ TEST_CASE("[Values] Effect sends") synth.dispatchMessage(client, 0, "/region1/effect1", "", nullptr); synth.dispatchMessage(client, 0, "/region2/effect1", "", nullptr); synth.dispatchMessage(client, 0, "/region2/effect2", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr); std::vector expected { // No reply to the first question "/region1/effect1,f : { 10 }", "/region2/effect1,f : { 0 }", "/region2/effect2,f : { 50.4 }", - // "/region4/effect1,f : { 100 }", + // No reply to the last question }; REQUIRE(messageList == expected); } @@ -2578,8 +2572,6 @@ TEST_CASE("[Values] Support floating point for int values") )"); synth.dispatchMessage(client, 0, "/region0/offset", "", nullptr); synth.dispatchMessage(client, 0, "/region1/pitch_keytrack", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr); std::vector expected { "/region0/offset,h : { 1042 }", "/region1/pitch_keytrack,i : { -2 }", @@ -2899,15 +2891,14 @@ TEST_CASE("[Values] Filter value bounds") SECTION("Cutoff") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav cutoff=20000000 // Bound this to 20k + sample=kick.wav cutoff=20000000 // Ignore the value sample=kick.wav cutoff=50 cutoff=-100 )"); synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/cutoff", "", nullptr); std::vector expected { - "/region0/filter0/cutoff,f : { 20000 }", - // "/region0/filter0/cutoff,f : { 50 }", + "/region0/filter0/cutoff,f : { 0 }", + "/region1/filter0/cutoff,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -2917,10 +2908,9 @@ TEST_CASE("[Values] Filter value bounds") synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( sample=kick.wav resonance=5 resonance=-5 )"); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/filter0/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/resonance", "", nullptr); std::vector expected { - // "/region0/filter0/resonance,f : { 5 }", + "/region0/filter0/resonance,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -2928,19 +2918,17 @@ TEST_CASE("[Values] Filter value bounds") SECTION("Keycenter") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav keycenter=40 keycenter=-5 - sample=kick.wav keycenter=40 keycenter=1000 - sample=kick.wav keycenter=c3 + sample=kick.wav fil_keycenter=40 + sample=kick.wav fil_keycenter=40 fil_keycenter=1000 + sample=kick.wav fil_keycenter=c3 )"); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/filter0/keycenter", "", nullptr); - // synth.dispatchMessage(client, 0, "/region1/filter0/keycenter", "", nullptr); - // TODO: activate after new parser; parse note - // synth.dispatchMessage(client, 0, "/region2/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/keycenter", "", nullptr); std::vector expected { - // "/region0/filter0/keycenter,i : { 40 }", - // "/region1/filter0/keycenter,i : { 40 }", - // "/region2/filter0/keycenter,i : { 48 }", + "/region0/filter0/keycenter,i : { 40 }", + "/region1/filter0/keycenter,i : { 60 }", + "/region2/filter0/keycenter,i : { 48 }", }; REQUIRE(messageList == expected); } @@ -3109,15 +3097,14 @@ TEST_CASE("[Values] EQ value bounds") SECTION("Frequency") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav eq1_freq=20000000 // Bound this to 30k + sample=kick.wav eq1_freq=20000000 // Ignore sample=kick.wav eq1_freq=50 eq1_freq=-100 )"); synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq0/frequency", "", nullptr); std::vector expected { - "/region0/eq0/frequency,f : { 30000 }", - // "/region0/eq0/frequency,f : { 50 }", + "/region0/eq0/frequency,f : { 50 }", + "/region1/eq0/frequency,f : { 50 }", }; REQUIRE(messageList == expected); } @@ -3127,10 +3114,9 @@ TEST_CASE("[Values] EQ value bounds") synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( sample=kick.wav eq1_bw=5 eq1_bw=-5 )"); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/eq0/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/bandwidth", "", nullptr); std::vector expected { - // "/region0/eq0/bandwidth,f : { 5 }", + "/region0/eq0/bandwidth,f : { 1 }", }; REQUIRE(messageList == expected); } From f62b1ba834d3dc1ea6e2a6c09165b7f95533b72f Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Thu, 4 Feb 2021 00:22:42 +0100 Subject: [PATCH 252/668] C++11 error --- src/sfizz/Defaults.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 65e7215f..2db5216c 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -77,7 +77,7 @@ struct OpcodeSpec template typename std::enable_if::value, U>::type normalizeInput(U input) const { - constexpr auto needsOperation { + constexpr int needsOperation { kNormalizePercent | kNormalizeMidi | kNormalizeBend | From 16e32f0bd1be0db7dc9090e901f0aaeac843b6a0 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Thu, 4 Feb 2021 01:08:07 +0100 Subject: [PATCH 253/668] Release test errors --- src/sfizz/Region.cpp | 2 ++ tests/RegionActivationT.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index d2710e0e..1355fc67 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1546,9 +1546,11 @@ bool sfz::Region::registerNoteOff(int noteNumber, float velocity, float randValu return false; } + #include bool sfz::Region::registerCC(int ccNumber, float ccValue) noexcept { ASSERT(ccValue >= 0.0f && ccValue <= 1.0f); + if (ccConditions.getWithDefault(ccNumber).containsWithEnd(ccValue)) ccSwitched.set(ccNumber, true); else diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index 22723ff9..89a4254a 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -56,8 +56,8 @@ TEST_CASE("Region activation", "Region tests") REQUIRE(!region.isSwitchedOn()); region.registerCC(54, 19_norm); REQUIRE(region.isSwitchedOn()); - region.registerCC(54, 18_norm); - REQUIRE(region.isSwitchedOn()); + region.registerCC(54, 17_norm); + REQUIRE(!region.isSwitchedOn()); region.registerCC(54, 27_norm); REQUIRE(region.isSwitchedOn()); region.registerCC(4, 56_norm); From 2fd8c892cf4cd5a3ad219d77bfda45ba5817bf2b Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 4 Feb 2021 11:02:09 +0100 Subject: [PATCH 254/668] Last test errors --- tests/FilesT.cpp | 23 ++++++++++++----------- tests/TestHelpers.h | 9 +++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 0c25cfc9..07d12c03 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -147,11 +147,12 @@ TEST_CASE("[Files] Group from AVL") REQUIRE(synth.getRegionView(i)->volume == 6.0f); REQUIRE(synth.getRegionView(i)->keyRange == Range(36, 36)); } - REQUIRE(synth.getRegionView(0)->velocityRange == Range(1_norm, 26_norm)); - REQUIRE(synth.getRegionView(1)->velocityRange == Range(27_norm, 52_norm)); - REQUIRE(synth.getRegionView(2)->velocityRange == Range(53_norm, 77_norm)); - REQUIRE(synth.getRegionView(3)->velocityRange == Range(78_norm, 102_norm)); - REQUIRE(synth.getRegionView(4)->velocityRange == Range(103_norm, 127_norm)); + + almostEqualRanges(synth.getRegionView(0)->velocityRange, { 1_norm, 26_norm }); + almostEqualRanges(synth.getRegionView(1)->velocityRange, { 27_norm, 52_norm }); + almostEqualRanges(synth.getRegionView(2)->velocityRange, { 53_norm, 77_norm }); + almostEqualRanges(synth.getRegionView(3)->velocityRange, { 78_norm, 102_norm }); + almostEqualRanges(synth.getRegionView(4)->velocityRange, { 103_norm, 127_norm }); } TEST_CASE("[Files] Full hierarchy") @@ -242,14 +243,14 @@ TEST_CASE("[Files] Pizz basic") REQUIRE(synth.getNumRegions() == 4); for (int i = 0; i < synth.getNumRegions(); ++i) { REQUIRE(synth.getRegionView(i)->keyRange == Range(12, 22)); - REQUIRE(synth.getRegionView(i)->velocityRange == Range(97_norm, 127_norm)); + almostEqualRanges(synth.getRegionView(i)->velocityRange, { 97_norm, 127_norm }); REQUIRE(synth.getRegionView(i)->pitchKeycenter == 21); - REQUIRE(synth.getRegionView(i)->ccConditions.getWithDefault(107) == Range(0_norm, 13_norm)); + almostEqualRanges(synth.getRegionView(i)->ccConditions.getWithDefault(107), { 0_norm, 13_norm }); } - REQUIRE(synth.getRegionView(0)->randRange == Range(0, 0.25)); - REQUIRE(synth.getRegionView(1)->randRange == Range(0.25, 0.5)); - REQUIRE(synth.getRegionView(2)->randRange == Range(0.5, 0.75)); - REQUIRE(synth.getRegionView(3)->randRange == Range(0.75, 1.0)); + almostEqualRanges(synth.getRegionView(0)->randRange, { 0, 0.25 }); + almostEqualRanges(synth.getRegionView(1)->randRange, { 0.25, 0.5 }); + almostEqualRanges(synth.getRegionView(2)->randRange, { 0.5, 0.75 }); + almostEqualRanges(synth.getRegionView(3)->randRange, { 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)"); diff --git a/tests/TestHelpers.h b/tests/TestHelpers.h index 31c5feb5..6a5fda7e 100644 --- a/tests/TestHelpers.h +++ b/tests/TestHelpers.h @@ -5,9 +5,11 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "catch2/catch.hpp" #include "sfizz/Synth.h" #include "sfizz/Region.h" #include "sfizz/Voice.h" +#include "sfizz/Range.h" #include "sfizz/modulations/ModKey.h" class RegionCCView { @@ -30,6 +32,13 @@ private: sfz::ModKey target_; }; +template +void almostEqualRanges(const sfz::Range& lhs, const sfz::Range& rhs) +{ + REQUIRE(lhs.getStart() == Approx(rhs.getStart())); + REQUIRE(lhs.getEnd() == Approx(rhs.getEnd())); +} + template void sortAll(C& container) { From dc6805498116236b77328e06969b1b6ad8eb64a5 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 4 Feb 2021 11:52:20 +0100 Subject: [PATCH 255/668] Cleanups --- src/sfizz/Defaults.cpp | 7 ++++--- src/sfizz/Defaults.h | 16 ++++++++++++++++ src/sfizz/Opcode.cpp | 30 ++++++++++++++++++++++-------- src/sfizz/Region.cpp | 17 +---------------- tests/RegionValuesT.cpp | 8 ++++---- tests/TestHelpers.h | 2 +- 6 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index e56171cb..8ac6d3af 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -73,7 +73,7 @@ extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), 0 } extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), 0 }; extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), 0 }; -extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), 0 }; +extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceUpperBound }; extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), 0 }; extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), 0 }; @@ -84,8 +84,8 @@ extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), 0 }; extern const OpcodeSpec filterVeltrack { 0, Range(-12000, 12000), 0 }; extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), 0 }; extern const OpcodeSpec eqBandwidthMod { 0.0f, Range(-4.0f, 4.0f), 0 }; -extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 30000.0f), 0 }; -extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-30000.0f, 30000.0f), 0 }; +extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 20000.0f), kEnforceUpperBound }; +extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-20000.0f, 20000.0f), 0 }; extern const OpcodeSpec eqGain { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec eqGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec eqVel2Frequency { 0.0f, Range(-30000.0f, 30000.0f), 0 }; @@ -159,6 +159,7 @@ extern const OpcodeSpec stringsNumber { maxStrings, Range(0, extern const OpcodeSpec trigger { Trigger::attack, Range(Trigger::attack, Trigger::release_key), 0}; extern const OpcodeSpec crossfadeCurve { CrossfadeCurve::power, Range(CrossfadeCurve::gain, CrossfadeCurve::power), 0}; extern const OpcodeSpec offMode { OffMode::fast, Range(OffMode::fast, OffMode::time), 0}; +extern const OpcodeSpec loopMode { LoopMode::no_loop, Range(LoopMode::no_loop, LoopMode::loop_sustain), 0}; extern const OpcodeSpec velocityOverride { VelocityOverride::current, Range(VelocityOverride::current, VelocityOverride::previous), 0}; extern const OpcodeSpec selfMask { SelfMask::mask, Range(SelfMask::mask, SelfMask::dontMask), 0}; extern const OpcodeSpec filter { FilterType::kFilterNone, Range(FilterType::kFilterNone, FilterType::kFilterPeq), 0}; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 2db5216c..557ae19f 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -74,6 +74,14 @@ struct OpcodeSpec T defaultInputValue; Range bounds; int flags; + + /** + * @brief Normalizes an input as needed for the spec + * + * @tparam U + * @param input + * @return U + */ template typename std::enable_if::value, U>::type normalizeInput(U input) const { @@ -98,6 +106,13 @@ struct OpcodeSpec return input; } + /** + * @brief Normalizes an input as needed for the spec + * + * @tparam U + * @param input + * @return U + */ template typename std::enable_if::value, U>::type normalizeInput(U input) const { @@ -262,6 +277,7 @@ namespace Default extern const OpcodeSpec stringsNumber; extern const OpcodeSpec trigger; extern const OpcodeSpec offMode; + extern const OpcodeSpec loopMode; extern const OpcodeSpec crossfadeCurve; extern const OpcodeSpec velocityOverride; extern const OpcodeSpec selfMask; diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 201709de..1628f292 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -197,12 +197,12 @@ absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); - return {}; + return absl::nullopt; } else if (returnedValue < static_cast(spec.bounds.getStart())) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); - return {}; + return absl::nullopt; } return spec.normalizeInput(returnedValue); @@ -223,7 +223,7 @@ absl::optional readNoteValue(absl::string_view value) char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front()); value.remove_prefix(1); if (noteLetter < 'a' || noteLetter > 'g') - return {}; + return absl::nullopt; constexpr int offsetsABCDEFG[] = { 9, 11, 0, 2, 4, 5, 7 }; int noteNumber = offsetsABCDEFG[noteLetter - 'a']; @@ -244,11 +244,11 @@ absl::optional readNoteValue(absl::string_view value) if (absl::StartsWith(value, prefix.first)) { if (prefix.second == +1) { if (validSharpLetters.find(noteLetter) == absl::string_view::npos) - return {}; + return absl::nullopt; } else if (prefix.second == -1) { if (validFlatLetters.find(noteLetter) == absl::string_view::npos) - return {}; + return absl::nullopt; } noteNumber += prefix.second; value.remove_prefix(prefix.first.size()); @@ -258,12 +258,12 @@ absl::optional readNoteValue(absl::string_view value) int octaveNumber; if (!absl::SimpleAtoi(value, &octaveNumber)) - return {}; + return absl::nullopt; noteNumber += (octaveNumber + 1) * 12; if (noteNumber < 0 || noteNumber >= 128) - return {}; + return absl::nullopt; return static_cast(noteNumber); } @@ -293,7 +293,7 @@ absl::optional Opcode::readOptional(OpcodeSpec Opcode::readOptional(OpcodeSpec) const return absl::nullopt; } +template <> +absl::optional Opcode::readOptional(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("no_loop"): return LoopMode::no_loop; + case hash("one_shot"): return LoopMode::one_shot; + case hash("loop_continuous"): return LoopMode::loop_continuous; + case hash("loop_sustain"): return LoopMode::loop_sustain; + } + + DBG("Unknown loop mode: " << value); + return absl::nullopt; +} + template <> absl::optional Opcode::readOptional(OpcodeSpec) const { diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 1355fc67..72324fdb 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -119,22 +119,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) sampleCount = opcode.read(Default::sampleCount); break; case hash("loop_mode"): // also loopmode - switch (hash(opcode.value)) { - case hash("no_loop"): - loopMode = LoopMode::no_loop; - break; - case hash("one_shot"): - loopMode = LoopMode::one_shot; - break; - case hash("loop_continuous"): - loopMode = LoopMode::loop_continuous; - break; - case hash("loop_sustain"): - loopMode = LoopMode::loop_sustain; - break; - default: - DBG("Unkown loop mode:" << opcode.value); - } + loopMode = opcode.readOptional(Default::loopMode); break; case hash("loop_end"): // also loopend loopRange.setEnd(opcode.read(Default::loopEnd)); diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index c34b6787..dc88297c 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -2891,13 +2891,13 @@ TEST_CASE("[Values] Filter value bounds") SECTION("Cutoff") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav cutoff=20000000 // Ignore the value + sample=kick.wav cutoff=20000000 // Clamp the value sample=kick.wav cutoff=50 cutoff=-100 )"); synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); synth.dispatchMessage(client, 0, "/region1/filter0/cutoff", "", nullptr); std::vector expected { - "/region0/filter0/cutoff,f : { 0 }", + "/region0/filter0/cutoff,f : { 20000 }", "/region1/filter0/cutoff,f : { 0 }", }; REQUIRE(messageList == expected); @@ -3097,13 +3097,13 @@ TEST_CASE("[Values] EQ value bounds") SECTION("Frequency") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav eq1_freq=20000000 // Ignore + sample=kick.wav eq1_freq=20000000 // Clamp the value sample=kick.wav eq1_freq=50 eq1_freq=-100 )"); synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); synth.dispatchMessage(client, 0, "/region1/eq0/frequency", "", nullptr); std::vector expected { - "/region0/eq0/frequency,f : { 50 }", + "/region0/eq0/frequency,f : { 20000 }", "/region1/eq0/frequency,f : { 50 }", }; REQUIRE(messageList == expected); diff --git a/tests/TestHelpers.h b/tests/TestHelpers.h index 6a5fda7e..0c60fb91 100644 --- a/tests/TestHelpers.h +++ b/tests/TestHelpers.h @@ -5,11 +5,11 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once -#include "catch2/catch.hpp" #include "sfizz/Synth.h" #include "sfizz/Region.h" #include "sfizz/Voice.h" #include "sfizz/Range.h" +#include "catch2/catch.hpp" #include "sfizz/modulations/ModKey.h" class RegionCCView { From acb860e984ccdfeb054b8af7d39e3433f4e4b664 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 4 Feb 2021 21:40:21 +0100 Subject: [PATCH 256/668] Cleanups --- src/sfizz/Region.cpp | 16 ++-------------- src/sfizz/Region.h | 2 +- tests/RegionValuesT.cpp | 2 +- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 72324fdb..3d3008bf 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -170,10 +170,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) group = opcode.read(Default::group); break; case hash("off_by"): // also offby - if (opcode.value == "-1") - offBy.reset(); - else - offBy = opcode.read(Default::group); + offBy = opcode.readOptional(Default::group); break; case hash("off_mode"): // also offmode offMode = opcode.read(Default::offMode); @@ -189,16 +186,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) notePolyphony = opcode.read(Default::notePolyphony); break; case hash("note_selfmask"): - switch (hash(opcode.value)) { - case hash("on"): - selfMask = SelfMask::mask; - break; - case hash("off"): - selfMask = SelfMask::dontMask; - break; - default: - DBG("Unkown self mask value:" << opcode.value); - } + selfMask = opcode.read(Default::selfMask); break; case hash("rt_dead"): rtDead = opcode.read(Default::rtDead); diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 4b3ee6c2..d8d6368e 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -474,7 +474,7 @@ struct Region { bool bpmSwitched { true }; bool aftertouchSwitched { true }; std::bitset ccSwitched; - absl::string_view defaultPath { "" }; + std::string defaultPath { "" }; int sequenceCounter { 0 }; LEAK_DETECTOR(Region); diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index dc88297c..197fe80a 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -2291,7 +2291,7 @@ TEST_CASE("[Values] Self-mask") "/region0/note_selfmask,T : { }", "/region1/note_selfmask,F : { }", "/region2/note_selfmask,T : { }", - "/region3/note_selfmask,F : { }", + "/region3/note_selfmask,T : { }", }; REQUIRE(messageList == expected); } From b5cb624697783d78310fcc2d91dff0c6cd26fd1d Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Fri, 12 Feb 2021 10:16:39 +0100 Subject: [PATCH 257/668] Merge booboo between the PRs --- src/sfizz/Region.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index bd7342d6..ec07ad48 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -553,11 +553,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = readOpcode(opcode.value, Default::filterCutoffModRange)) { - const ModKey source = ModKey::createNXYZ(ModId::ChannelAftertouch); - const ModKey target = ModKey::createNXYZ(ModId::FilCutoff, id, filterIndex); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::ChannelAftertouch); + const ModKey target = ModKey::createNXYZ(ModId::FilCutoff, id, filterIndex); + getOrCreateConnection(source, target).sourceDepth = opcode.read(Default::filterCutoffMod); } break; case hash("fil&_keytrack"): // also fil_keytrack @@ -1532,7 +1530,6 @@ bool sfz::Region::registerNoteOff(int noteNumber, float velocity, float randValu return false; } - #include bool sfz::Region::registerCC(int ccNumber, float ccValue) noexcept { ASSERT(ccValue >= 0.0f && ccValue <= 1.0f); From dde3547d4e8bfa40ce608b895c138768edb55caa Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 17 Feb 2021 07:14:37 +0100 Subject: [PATCH 258/668] Try custom mingw container --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78270416..ffe7585f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -136,7 +136,7 @@ jobs: build_for_mingw32: runs-on: ubuntu-18.04 container: - image: archlinux + image: ghcr.io/sfztools/archlinux steps: - name: Set install name run: | @@ -200,7 +200,7 @@ jobs: build_for_mingw64: runs-on: ubuntu-18.04 container: - image: archlinux + image: ghcr.io/sfztools/archlinux steps: - name: Set install name run: | From 02bc67d84c6e26515913caf83b24cb769a52c887 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 17 Feb 2021 08:11:50 +0100 Subject: [PATCH 259/668] Update paths of mingw build --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ffe7585f..933351a2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -164,7 +164,7 @@ jobs: shell: bash # need to convert some includes to lower case (as of VST 3.7.1) run: | - find "$GITHUB_WORKSPACE"/vst/external/VST_SDK -type d -name source -exec \ + find "$GITHUB_WORKSPACE"/plugins/vst/external/VST_SDK -type d -name source -exec \ find {} -type f -name '*.[hc]' -o -name '*.[hc]pp' -print0 \; | \ xargs -0 sed -i 's///' - name: Create Build Environment @@ -228,7 +228,7 @@ jobs: shell: bash # need to convert some includes to lower case (as of VST 3.7.1) run: | - find "$GITHUB_WORKSPACE"/vst/external/VST_SDK -type d -name source -exec \ + find "$GITHUB_WORKSPACE"/plugins/vst/external/VST_SDK -type d -name source -exec \ find {} -type f -name '*.[hc]' -o -name '*.[hc]pp' -print0 \; | \ xargs -0 sed -i 's///' - name: Create Build Environment From e2a5c07edb6aeee57780440bf63848a4965451dd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 21 Feb 2021 23:29:41 +0100 Subject: [PATCH 260/668] Remove BM_opcodeSpec --- benchmarks/BM_opcodeSpec.cpp | 72 -------------------------------- benchmarks/BM_opcodeSpec.h | 14 ------- benchmarks/BM_opcodeSpec_def.cpp | 3 -- benchmarks/CMakeLists.txt | 1 - 4 files changed, 90 deletions(-) delete mode 100644 benchmarks/BM_opcodeSpec.cpp delete mode 100644 benchmarks/BM_opcodeSpec.h delete mode 100644 benchmarks/BM_opcodeSpec_def.cpp diff --git a/benchmarks/BM_opcodeSpec.cpp b/benchmarks/BM_opcodeSpec.cpp deleted file mode 100644 index da31a30a..00000000 --- a/benchmarks/BM_opcodeSpec.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "BM_opcodeSpec.h" -#include -#include -#include -#include -#include -#include - -class OpcodeSpecFixture : public benchmark::Fixture { -public: - void SetUp(const ::benchmark::State& state) { - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 0.0f, 1.0f }; - value = dist(gen); - } - - void TearDown(const ::benchmark::State& /* state */) { - - } - - float value; - float returned; -}; - -BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstexprClamp)(benchmark::State& state) { - for (auto _ : state) - { - if (constexprSpec.flags | (1 << 2)) - returned = constexprSpec.bounds.clamp(value); - benchmark::DoNotOptimize(returned); - } -} - -BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstexprDontClamp)(benchmark::State& state) { - for (auto _ : state) - { - if (constexprSpec.flags | (1 << 1)) - returned = constexprSpec.bounds.clamp(value); - benchmark::DoNotOptimize(returned); - } -} - -BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstClamp)(benchmark::State& state) { - for (auto _ : state) - { - if (constSpec.flags | (1 << 2)) - returned = constSpec.bounds.clamp(value); - benchmark::DoNotOptimize(returned); - } -} - -BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstDontClamp)(benchmark::State& state) { - for (auto _ : state) - { - if (constSpec.flags | (1 << 1)) - returned = constSpec.bounds.clamp(value); - benchmark::DoNotOptimize(returned); - } -} - -BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstexprClamp); -BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstexprDontClamp); -BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstClamp); -BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstDontClamp); -BENCHMARK_MAIN(); diff --git a/benchmarks/BM_opcodeSpec.h b/benchmarks/BM_opcodeSpec.h deleted file mode 100644 index 8efcbe43..00000000 --- a/benchmarks/BM_opcodeSpec.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "Range.h" - -template -struct OpcodeSpec -{ - T defaultValue; - sfz::Range bounds; - int flags { 0 }; -}; - -constexpr OpcodeSpec constexprSpec { 0.0f, sfz::Range(0.0f, 0.5f), 1 << 2 }; -extern const OpcodeSpec constSpec; diff --git a/benchmarks/BM_opcodeSpec_def.cpp b/benchmarks/BM_opcodeSpec_def.cpp deleted file mode 100644 index 076dd27d..00000000 --- a/benchmarks/BM_opcodeSpec_def.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "BM_opcodeSpec.h" - -const OpcodeSpec constSpec { 0.0f, sfz::Range(0.0f, 0.5f), 1 << 2 }; diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 77652c3e..89d7c8e3 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -38,7 +38,6 @@ sfizz_add_benchmark(bm_mapVsArray BM_mapVsArray.cpp) sfizz_add_benchmark(bm_random BM_random.cpp) sfizz_add_benchmark(bm_clamp BM_clamp.cpp) sfizz_add_benchmark(bm_allWithin BM_allWithin.cpp) -sfizz_add_benchmark(bm_opcodeSpec BM_opcodeSpec.cpp BM_opcodeSpec_def.cpp) sfizz_add_benchmark(bm_logger BM_logger.cpp) sfizz_add_benchmark(bm_smoothers BM_smoothers.cpp) From a9cf45b0c985f0f0249abc41f20c8d050d64d19f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 16 Feb 2021 00:07:42 +0100 Subject: [PATCH 261/668] Add simde 0.7.2 --- .gitmodules | 3 +++ external/simde | 1 + 2 files changed, 4 insertions(+) create mode 160000 external/simde diff --git a/.gitmodules b/.gitmodules index 9cbfac18..7850d1b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -39,3 +39,6 @@ path = external/filesystem url = https://github.com/gulrak/filesystem.git shallow = true +[submodule "external/simde"] + path = external/simde + url = https://github.com/simd-everywhere/simde.git diff --git a/external/simde b/external/simde new file mode 160000 index 00000000..12069d72 --- /dev/null +++ b/external/simde @@ -0,0 +1 @@ +Subproject commit 12069d720f43830ae9791e8b0f4c4fa3c88012a0 From a338ec7368c80baad5977e1d34fc3c8ec791e225 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 16 Feb 2021 00:08:57 +0100 Subject: [PATCH 262/668] Add simde as project library --- cmake/SfizzDeps.cmake | 5 +++++ common.mk | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 3dcb1916..79020bcd 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -67,6 +67,11 @@ else() endif() add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL) +# The simde library +add_library(sfizz_simde INTERFACE) +add_library(sfizz::simde ALIAS sfizz_simde) +target_include_directories(sfizz_simde INTERFACE "external/simde") + # The pugixml library add_library(sfizz_pugixml STATIC "src/external/pugixml/src/pugixml.cpp") add_library(sfizz::pugixml ALIAS sfizz_pugixml) diff --git a/common.mk b/common.mk index ae100d0d..7909df12 100644 --- a/common.mk +++ b/common.mk @@ -315,6 +315,10 @@ SFIZZ_SOURCES += \ src/external/cpuid/src/cpuid/cpuinfo.cpp \ src/external/cpuid/src/cpuid/version.cpp +### simde dependency +SFIZZ_C_FLAGS += \ + -I$(SFIZZ_DIR)/external/simde + ### Pugixml dependency SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/src/external/pugixml/src From d7b9dc2285aae952ec648455e8b986eac685da77 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 16 Feb 2021 00:25:57 +0100 Subject: [PATCH 263/668] Interpolators with simde --- src/CMakeLists.txt | 2 +- src/sfizz/Interpolators.hpp | 80 +++++++++++++++++++------------------ src/sfizz/WindowedSinc.h | 9 +++-- src/sfizz/WindowedSinc.hpp | 37 +++++++++-------- 4 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d75cd15f..fec1ef51 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -252,7 +252,7 @@ add_library(sfizz::internal ALIAS sfizz_internal) target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES}) target_include_directories(sfizz_internal PUBLIC "." "sfizz") target_link_libraries(sfizz_internal - PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex + PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex sfizz::simde PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") diff --git a/src/sfizz/Interpolators.hpp b/src/sfizz/Interpolators.hpp index a75c9608..8080dbdc 100644 --- a/src/sfizz/Interpolators.hpp +++ b/src/sfizz/Interpolators.hpp @@ -8,6 +8,10 @@ #include "WindowedSinc.h" #include "MathHelpers.h" #include "SIMDConfig.h" +#include +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) +#include +#endif namespace sfz { @@ -49,25 +53,25 @@ public: //------------------------------------------------------------------------------ // Hermite 3rd order, SSE specialization -#if SFIZZ_HAVE_SSE +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) template <> class Interpolator { public: static inline float process(const float* values, float coeff) { - __m128 x = _mm_sub_ps(_mm_setr_ps(-1, 0, 1, 2), _mm_set1_ps(coeff)); - __m128 h = hermite3x4(x); - __m128 y = _mm_mul_ps(h, _mm_loadu_ps(values - 1)); + simde__m128 x = simde_mm_sub_ps(simde_mm_setr_ps(-1, 0, 1, 2), simde_mm_set1_ps(coeff)); + simde__m128 h = hermite3x4(x); + simde__m128 y = simde_mm_mul_ps(h, simde_mm_loadu_ps(values - 1)); // sum 4 to 1 - __m128 xmm0 = y; - __m128 xmm1 = _mm_shuffle_ps(xmm0, xmm0, 0xe5); - __m128 xmm2 = _mm_movehl_ps(xmm0, xmm0); - xmm1 = _mm_add_ss(xmm1, xmm0); - xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0xe7); - xmm2 = _mm_add_ss(xmm2, xmm1); - xmm0 = _mm_add_ss(xmm0, xmm2); - return _mm_cvtss_f32(xmm0); + simde__m128 xmm0 = y; + simde__m128 xmm1 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe5); + simde__m128 xmm2 = simde_mm_movehl_ps(xmm0, xmm0); + xmm1 = simde_mm_add_ss(xmm1, xmm0); + xmm0 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe7); + xmm2 = simde_mm_add_ss(xmm2, xmm1); + xmm0 = simde_mm_add_ss(xmm0, xmm2); + return simde_mm_cvtss_f32(xmm0); } }; #endif @@ -93,25 +97,25 @@ public: //------------------------------------------------------------------------------ // B-spline 3rd order, SSE specialization -#if SFIZZ_HAVE_SSE +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) template <> class Interpolator { public: static inline float process(const float* values, float coeff) { - __m128 x = _mm_sub_ps(_mm_setr_ps(-1, 0, 1, 2), _mm_set1_ps(coeff)); - __m128 h = bspline3x4(x); - __m128 y = _mm_mul_ps(h, _mm_loadu_ps(values - 1)); + simde__m128 x = simde_mm_sub_ps(simde_mm_setr_ps(-1, 0, 1, 2), simde_mm_set1_ps(coeff)); + simde__m128 h = bspline3x4(x); + simde__m128 y = simde_mm_mul_ps(h, simde_mm_loadu_ps(values - 1)); // sum 4 to 1 - __m128 xmm0 = y; - __m128 xmm1 = _mm_shuffle_ps(xmm0, xmm0, 0xe5); - __m128 xmm2 = _mm_movehl_ps(xmm0, xmm0); - xmm1 = _mm_add_ss(xmm1, xmm0); - xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0xe7); - xmm2 = _mm_add_ss(xmm2, xmm1); - xmm0 = _mm_add_ss(xmm0, xmm2); - return _mm_cvtss_f32(xmm0); + simde__m128 xmm0 = y; + simde__m128 xmm1 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe5); + simde__m128 xmm2 = simde_mm_movehl_ps(xmm0, xmm0); + xmm1 = simde_mm_add_ss(xmm1, xmm0); + xmm0 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe7); + xmm2 = simde_mm_add_ss(xmm2, xmm1); + xmm0 = simde_mm_add_ss(xmm0, xmm2); + return simde_mm_cvtss_f32(xmm0); } }; #endif @@ -190,7 +194,7 @@ class SincInterpolator; //------------------------------------------------------------------------------ // Windowed sinc any order, SSE specialization -#if SFIZZ_HAVE_SSE2 +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) template class SincInterpolator { @@ -204,25 +208,25 @@ public: constexpr int j0 = 1 - int(Points) / 2; float x0 = j0 - coeff; - __m128 y = _mm_set1_ps(0.0f); - __m128 x = _mm_add_ps(_mm_set1_ps(x0), _mm_setr_ps(0, 1, 2, 3)); + simde__m128 y = simde_mm_set1_ps(0.0f); + simde__m128 x = simde_mm_add_ps(simde_mm_set1_ps(x0), simde_mm_setr_ps(0, 1, 2, 3)); size_t i = 0; do { - __m128 h = ws.getUncheckedX4(x); - y = _mm_add_ps(y, _mm_mul_ps(h, _mm_loadu_ps(&values[j0 + i]))); - x = _mm_add_ps(x, _mm_set1_ps(4.0f)); + simde__m128 h = ws.getUncheckedX4(x); + y = simde_mm_add_ps(y, simde_mm_mul_ps(h, simde_mm_loadu_ps(&values[j0 + i]))); + x = simde_mm_add_ps(x, simde_mm_set1_ps(4.0f)); i += 4; } while (i < Points); // sum 4 to 1 - __m128 xmm0 = y; - __m128 xmm1 = _mm_shuffle_ps(xmm0, xmm0, 0xe5); - __m128 xmm2 = _mm_movehl_ps(xmm0, xmm0); - xmm1 = _mm_add_ss(xmm1, xmm0); - xmm0 = _mm_shuffle_ps(xmm0, xmm0, 0xe7); - xmm2 = _mm_add_ss(xmm2, xmm1); - xmm0 = _mm_add_ss(xmm0, xmm2); - return _mm_cvtss_f32(xmm0); + simde__m128 xmm0 = y; + simde__m128 xmm1 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe5); + simde__m128 xmm2 = simde_mm_movehl_ps(xmm0, xmm0); + xmm1 = simde_mm_add_ss(xmm1, xmm0); + xmm0 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe7); + xmm2 = simde_mm_add_ss(xmm2, xmm1); + xmm0 = simde_mm_add_ss(xmm0, xmm2); + return simde_mm_cvtss_f32(xmm0); } }; #endif diff --git a/src/sfizz/WindowedSinc.h b/src/sfizz/WindowedSinc.h index b8beb582..dc7143f2 100644 --- a/src/sfizz/WindowedSinc.h +++ b/src/sfizz/WindowedSinc.h @@ -8,8 +8,9 @@ #include "SIMDConfig.h" #include #include -#if SFIZZ_HAVE_SSE2 -#include +#include +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) +#include #endif namespace sfz { @@ -30,9 +31,9 @@ public: // interpolate f(x), where x must be in domain [-Points/2:+Points/2] float getUnchecked(float x) const noexcept; -#if SFIZZ_HAVE_SSE2 +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) // interpolate f(x), 4 values at once - __m128 getUncheckedX4(__m128 x) const noexcept; + simde__m128 getUncheckedX4(simde__m128 x) const noexcept; #endif // calculate exact f(x), where x must be in domain [-Points/2:+Points/2] diff --git a/src/sfizz/WindowedSinc.hpp b/src/sfizz/WindowedSinc.hpp index 1bd4f19c..eb8b3b75 100644 --- a/src/sfizz/WindowedSinc.hpp +++ b/src/sfizz/WindowedSinc.hpp @@ -7,6 +7,9 @@ #pragma once #include "WindowedSinc.h" #include +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) +#include +#endif namespace sfz { @@ -36,33 +39,33 @@ inline float AbstractWindowedSinc::getUnchecked(float x) const noexcept return y0 + mu * dy; } -#if SFIZZ_HAVE_SSE2 +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) template -inline __m128 AbstractWindowedSinc::getUncheckedX4(__m128 x) const noexcept +inline simde__m128 AbstractWindowedSinc::getUncheckedX4(simde__m128 x) const noexcept { const float* table = static_cast(this)->getTablePointer(); size_t points = static_cast(this)->getNumPoints(); size_t tableSize = static_cast(this)->getTableSize(); - __m128 ix = _mm_mul_ps( - _mm_add_ps(x, _mm_set1_ps(points / 2.0f)), - _mm_set1_ps((tableSize - 1) / points)); - alignas(__m128i) int j0[4]; - __m128i i0 = _mm_cvttps_epi32(ix); - _mm_store_si128((__m128i*)j0, i0); - __m128 mu = _mm_sub_ps(ix, _mm_cvtepi32_ps(i0)); + simde__m128 ix = simde_mm_mul_ps( + simde_mm_add_ps(x, simde_mm_set1_ps(points / 2.0f)), + simde_mm_set1_ps((tableSize - 1) / points)); + alignas(simde__m128i) int j0[4]; + simde__m128i i0 = simde_mm_cvttps_epi32(ix); + simde_mm_store_si128((simde__m128i*)j0, i0); + simde__m128 mu = simde_mm_sub_ps(ix, simde_mm_cvtepi32_ps(i0)); // reference: Interpolated table lookups using SSE2 [2/2] // https://rawstudio.org/blog/?p=482 - __m128 p0p1 = _mm_castsi128_ps(_mm_loadl_epi64((__m128i*)&table[j0[0]])); - __m128 p2p3 = _mm_castsi128_ps(_mm_loadl_epi64((__m128i*)&table[j0[2]])); - p0p1 = _mm_loadh_pi(p0p1, (__m64*)&table[j0[1]]); - p2p3 = _mm_loadh_pi(p2p3, (__m64*)&table[j0[3]]); - __m128 y0 = _mm_shuffle_ps(p0p1, p2p3, _MM_SHUFFLE(2, 0, 2, 0)); - __m128 y1 = _mm_shuffle_ps(p0p1, p2p3, _MM_SHUFFLE(3, 1, 3, 1)); + simde__m128 p0p1 = simde_mm_castsi128_ps(simde_mm_loadl_epi64((simde__m128i*)&table[j0[0]])); + simde__m128 p2p3 = simde_mm_castsi128_ps(simde_mm_loadl_epi64((simde__m128i*)&table[j0[2]])); + p0p1 = simde_mm_loadh_pi(p0p1, (simde__m64*)&table[j0[1]]); + p2p3 = simde_mm_loadh_pi(p2p3, (simde__m64*)&table[j0[3]]); + simde__m128 y0 = simde_mm_shuffle_ps(p0p1, p2p3, SIMDE_MM_SHUFFLE(2, 0, 2, 0)); + simde__m128 y1 = simde_mm_shuffle_ps(p0p1, p2p3, SIMDE_MM_SHUFFLE(3, 1, 3, 1)); - __m128 dy = _mm_sub_ps(y1, y0); - return _mm_add_ps(y0, _mm_mul_ps(mu, dy)); + simde__m128 dy = simde_mm_sub_ps(y1, y0); + return simde_mm_add_ps(y0, simde_mm_mul_ps(mu, dy)); } #endif From cfb2b9453250210f2d264aba01fa523daf9362aa Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 16 Feb 2021 00:26:51 +0100 Subject: [PATCH 264/668] Let clang-tidy find simde --- scripts/run_clang_tidy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index 041d331a..ceb29530 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -30,7 +30,7 @@ clang-tidy \ vst/SfizzVstState.cpp \ -- -Iexternal/abseil-cpp -Iexternal/jsl/include -Iexternal/filesystem/include -Iexternal/atomic_queue/include -Iexternal/threadpool -Isrc/external/hiir -Isrc/external/pugixml/src \ -Iexternal/st_audiofile/src -Iexternal/st_audiofile/thirdparty/dr_libs \ - -Isrc/sfizz -Isrc -Isrc/sfizz/utility/spin_mutex -Isrc/external/spline -Isrc/external/cpuid/src \ + -Isrc/sfizz -Isrc -Isrc/sfizz/utility/spin_mutex -Isrc/external/spline -Isrc/external/cpuid/src -Iexternal/simde \ -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ieditor/external/vstgui4 -Ivst/external/ring_buffer \ -Ieditor/src \ -DNDEBUG -std=c++17 From cb9cc622d06097dbfcf99a4ab4520ce51a0c02cc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 16 Feb 2021 00:36:46 +0100 Subject: [PATCH 265/668] Rewrite SIMD sum 4-to-1 --- src/sfizz/Interpolators.hpp | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/sfizz/Interpolators.hpp b/src/sfizz/Interpolators.hpp index 8080dbdc..2585704e 100644 --- a/src/sfizz/Interpolators.hpp +++ b/src/sfizz/Interpolators.hpp @@ -11,6 +11,7 @@ #include #if SIMDE_NATURAL_VECTOR_SIZE_GE(128) #include +#include #endif namespace sfz { @@ -63,15 +64,7 @@ public: simde__m128 x = simde_mm_sub_ps(simde_mm_setr_ps(-1, 0, 1, 2), simde_mm_set1_ps(coeff)); simde__m128 h = hermite3x4(x); simde__m128 y = simde_mm_mul_ps(h, simde_mm_loadu_ps(values - 1)); - // sum 4 to 1 - simde__m128 xmm0 = y; - simde__m128 xmm1 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe5); - simde__m128 xmm2 = simde_mm_movehl_ps(xmm0, xmm0); - xmm1 = simde_mm_add_ss(xmm1, xmm0); - xmm0 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe7); - xmm2 = simde_mm_add_ss(xmm2, xmm1); - xmm0 = simde_mm_add_ss(xmm0, xmm2); - return simde_mm_cvtss_f32(xmm0); + return simde_vaddvq_f32(y); } }; #endif @@ -107,15 +100,7 @@ public: simde__m128 x = simde_mm_sub_ps(simde_mm_setr_ps(-1, 0, 1, 2), simde_mm_set1_ps(coeff)); simde__m128 h = bspline3x4(x); simde__m128 y = simde_mm_mul_ps(h, simde_mm_loadu_ps(values - 1)); - // sum 4 to 1 - simde__m128 xmm0 = y; - simde__m128 xmm1 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe5); - simde__m128 xmm2 = simde_mm_movehl_ps(xmm0, xmm0); - xmm1 = simde_mm_add_ss(xmm1, xmm0); - xmm0 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe7); - xmm2 = simde_mm_add_ss(xmm2, xmm1); - xmm0 = simde_mm_add_ss(xmm0, xmm2); - return simde_mm_cvtss_f32(xmm0); + return simde_vaddvq_f32(y); } }; #endif @@ -218,15 +203,7 @@ public: i += 4; } while (i < Points); - // sum 4 to 1 - simde__m128 xmm0 = y; - simde__m128 xmm1 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe5); - simde__m128 xmm2 = simde_mm_movehl_ps(xmm0, xmm0); - xmm1 = simde_mm_add_ss(xmm1, xmm0); - xmm0 = simde_mm_shuffle_ps(xmm0, xmm0, 0xe7); - xmm2 = simde_mm_add_ss(xmm2, xmm1); - xmm0 = simde_mm_add_ss(xmm0, xmm2); - return simde_mm_cvtss_f32(xmm0); + return simde_vaddvq_f32(y); } }; #endif From 36d99ec1f3a0e5c61aeedeb7b0ffb2ccb75d46ae Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 16 Feb 2021 02:31:22 +0100 Subject: [PATCH 266/668] Convert the math helpers to simde --- src/CMakeLists.txt | 2 +- src/sfizz/MathHelpers.h | 63 ++++++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fec1ef51..616e401e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -217,7 +217,7 @@ target_sources(sfizz_parser PRIVATE ${SFIZZ_PARSER_HEADERS} ${SFIZZ_PARSER_SOURCES} ${SFIZZ_PARSER_OTHER}) target_include_directories(sfizz_parser PUBLIC sfizz) target_link_libraries(sfizz_parser - PUBLIC sfizz::filesystem absl::strings + PUBLIC sfizz::filesystem sfizz::simde absl::strings PRIVATE absl::flat_hash_map) # OSC messaging library diff --git a/src/sfizz/MathHelpers.h b/src/sfizz/MathHelpers.h index d04793fc..69dcae82 100644 --- a/src/sfizz/MathHelpers.h +++ b/src/sfizz/MathHelpers.h @@ -21,8 +21,9 @@ #include #include #include -#if SFIZZ_HAVE_SSE -#include +#include +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) +#include #endif #if __cplusplus >= 201703L @@ -195,26 +196,28 @@ R hermite3(R x) return y; } -#if SFIZZ_HAVE_SSE +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) /** * @brief Compute 4 parallel elements of the 3rd-order Hermite interpolation polynomial. * * @param x - * @return __m128 + * @return simde__m128 */ -inline __m128 hermite3x4(__m128 x) +inline simde__m128 hermite3x4(simde__m128 x) { - x = _mm_andnot_ps(_mm_set1_ps(-0.0f), x); - __m128 x2 = _mm_mul_ps(x, x); - __m128 x3 = _mm_mul_ps(x2, x); - __m128 y = _mm_set1_ps(0.0f); - __m128 q = _mm_mul_ps(_mm_set1_ps(5./2.), x2); - __m128 p1 = _mm_add_ps(_mm_sub_ps(_mm_set1_ps(1), q), _mm_mul_ps(_mm_set1_ps(3./2.), x3)); - __m128 p2 = _mm_sub_ps(_mm_add_ps(_mm_sub_ps(_mm_set1_ps(2), _mm_mul_ps(_mm_set1_ps(4), x)), q), _mm_mul_ps(_mm_set1_ps(1./2.), x3)); - __m128 m2 = _mm_cmple_ps(x, _mm_set1_ps(2)); - y = _mm_or_ps(_mm_and_ps(m2, p2), _mm_andnot_ps(m2, y)); - __m128 m1 = _mm_cmple_ps(x, _mm_set1_ps(1)); - y = _mm_or_ps(_mm_and_ps(m1, p1), _mm_andnot_ps(m1, y)); + // Note(jpc) replace with `simde_x_mm_abs_ps` when fixed + // https://github.com/simd-everywhere/simde/issues/704 + x = simde_mm_andnot_ps(simde_mm_set1_ps(-0.0f), x); + simde__m128 x2 = simde_mm_mul_ps(x, x); + simde__m128 x3 = simde_mm_mul_ps(x2, x); + simde__m128 y = simde_mm_set1_ps(0.0f); + simde__m128 q = simde_mm_mul_ps(simde_mm_set1_ps(5./2.), x2); + simde__m128 p1 = simde_mm_add_ps(simde_mm_sub_ps(simde_mm_set1_ps(1), q), simde_mm_mul_ps(simde_mm_set1_ps(3./2.), x3)); + simde__m128 p2 = simde_mm_sub_ps(simde_mm_add_ps(simde_mm_sub_ps(simde_mm_set1_ps(2), simde_mm_mul_ps(simde_mm_set1_ps(4), x)), q), simde_mm_mul_ps(simde_mm_set1_ps(1./2.), x3)); + simde__m128 m2 = simde_mm_cmple_ps(x, simde_mm_set1_ps(2)); + y = simde_mm_or_ps(simde_mm_and_ps(m2, p2), simde_mm_andnot_ps(m2, y)); + simde__m128 m1 = simde_mm_cmple_ps(x, simde_mm_set1_ps(1)); + y = simde_mm_or_ps(simde_mm_and_ps(m1, p1), simde_mm_andnot_ps(m1, y)); return y; } #endif @@ -240,25 +243,27 @@ R bspline3(R x) return y; } -#if SFIZZ_HAVE_SSE +#if SIMDE_NATURAL_VECTOR_SIZE_GE(128) /** * @brief Compute 4 parallel elements of the 3rd-order B-spline interpolation polynomial. * * @param x - * @return __m128 + * @return simde__m128 */ -inline __m128 bspline3x4(__m128 x) +inline simde__m128 bspline3x4(simde__m128 x) { - x = _mm_andnot_ps(_mm_set1_ps(-0.0f), x); - __m128 x2 = _mm_mul_ps(x, x); - __m128 x3 = _mm_mul_ps(x2, x); - __m128 y = _mm_set1_ps(0.0f); - __m128 p1 = _mm_add_ps(_mm_sub_ps(_mm_set1_ps(2./3.), x2), _mm_mul_ps(_mm_set1_ps(1./2.), x3)); - __m128 p2 = _mm_sub_ps(_mm_add_ps(_mm_sub_ps(_mm_set1_ps(4./3.), _mm_mul_ps(_mm_set1_ps(2), x)), x2), _mm_mul_ps(_mm_set1_ps(1./6.), x3)); - __m128 m2 = _mm_cmple_ps(x, _mm_set1_ps(2)); - y = _mm_or_ps(_mm_and_ps(m2, p2), _mm_andnot_ps(m2, y)); - __m128 m1 = _mm_cmple_ps(x, _mm_set1_ps(1)); - y = _mm_or_ps(_mm_and_ps(m1, p1), _mm_andnot_ps(m1, y)); + // Note(jpc) replace with `simde_x_mm_abs_ps` when fixed + // https://github.com/simd-everywhere/simde/issues/704 + x = simde_mm_andnot_ps(simde_mm_set1_ps(-0.0f), x); + simde__m128 x2 = simde_mm_mul_ps(x, x); + simde__m128 x3 = simde_mm_mul_ps(x2, x); + simde__m128 y = simde_mm_set1_ps(0.0f); + simde__m128 p1 = simde_mm_add_ps(simde_mm_sub_ps(simde_mm_set1_ps(2./3.), x2), simde_mm_mul_ps(simde_mm_set1_ps(1./2.), x3)); + simde__m128 p2 = simde_mm_sub_ps(simde_mm_add_ps(simde_mm_sub_ps(simde_mm_set1_ps(4./3.), simde_mm_mul_ps(simde_mm_set1_ps(2), x)), x2), simde_mm_mul_ps(simde_mm_set1_ps(1./6.), x3)); + simde__m128 m2 = simde_mm_cmple_ps(x, simde_mm_set1_ps(2)); + y = simde_mm_or_ps(simde_mm_and_ps(m2, p2), simde_mm_andnot_ps(m2, y)); + simde__m128 m1 = simde_mm_cmple_ps(x, simde_mm_set1_ps(1)); + y = simde_mm_or_ps(simde_mm_and_ps(m1, p1), simde_mm_andnot_ps(m1, y)); return y; } #endif From 16a074bc500a1ebd9dd9b1627351cd762e72588f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 21 Feb 2021 22:15:41 +0100 Subject: [PATCH 267/668] Use simde custom fork Until simd-everywhere/simde#704 gets fixed --- .gitmodules | 2 +- external/simde | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 7850d1b8..92f842e7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -41,4 +41,4 @@ shallow = true [submodule "external/simde"] path = external/simde - url = https://github.com/simd-everywhere/simde.git + url = https://github.com/sfztools/simde.git diff --git a/external/simde b/external/simde index 12069d72..0ba9d8fd 160000 --- a/external/simde +++ b/external/simde @@ -1 +1 @@ -Subproject commit 12069d720f43830ae9791e8b0f4c4fa3c88012a0 +Subproject commit 0ba9d8fdc0569e5a887dc42c6ddfa2a27a9f6867 From b682fa28e42bc2db811a41750ca80c8ff4ad7582 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 21 Feb 2021 22:18:17 +0100 Subject: [PATCH 268/668] Use simde_x_mm_abs_ps --- src/sfizz/MathHelpers.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sfizz/MathHelpers.h b/src/sfizz/MathHelpers.h index 69dcae82..066b8e04 100644 --- a/src/sfizz/MathHelpers.h +++ b/src/sfizz/MathHelpers.h @@ -205,9 +205,7 @@ R hermite3(R x) */ inline simde__m128 hermite3x4(simde__m128 x) { - // Note(jpc) replace with `simde_x_mm_abs_ps` when fixed - // https://github.com/simd-everywhere/simde/issues/704 - x = simde_mm_andnot_ps(simde_mm_set1_ps(-0.0f), x); + x = simde_x_mm_abs_ps(x); simde__m128 x2 = simde_mm_mul_ps(x, x); simde__m128 x3 = simde_mm_mul_ps(x2, x); simde__m128 y = simde_mm_set1_ps(0.0f); @@ -252,9 +250,7 @@ R bspline3(R x) */ inline simde__m128 bspline3x4(simde__m128 x) { - // Note(jpc) replace with `simde_x_mm_abs_ps` when fixed - // https://github.com/simd-everywhere/simde/issues/704 - x = simde_mm_andnot_ps(simde_mm_set1_ps(-0.0f), x); + x = simde_x_mm_abs_ps(x); simde__m128 x2 = simde_mm_mul_ps(x, x); simde__m128 x3 = simde_mm_mul_ps(x2, x); simde__m128 y = simde_mm_set1_ps(0.0f); From 2473c57cc69a844bfc65028ac1fc49a042605a47 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 21 Feb 2021 22:34:41 +0100 Subject: [PATCH 269/668] Enable use of OpenMP simd pragmas --- cmake/SfizzDeps.cmake | 13 +++++++++++++ common.mk | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 79020bcd..864f1225 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -1,6 +1,16 @@ # Find system threads find_package(Threads REQUIRED) +# Find OpenMP +find_package(OpenMP) +if(OPENMP_FOUND) + add_library(sfizz_openmp INTERFACE) + add_library(sfizz::openmp ALIAS sfizz_openmp) + target_compile_options(sfizz_openmp INTERFACE + $<$:${OpenMP_C_FLAGS}> + $<$:${OpenMP_CXX_FLAGS}>) +endif() + # Find macOS system libraries if(APPLE) find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation") @@ -71,6 +81,9 @@ add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL) add_library(sfizz_simde INTERFACE) add_library(sfizz::simde ALIAS sfizz_simde) target_include_directories(sfizz_simde INTERFACE "external/simde") +if(TARGET sfizz::openmp) + target_link_libraries(sfizz_simde INTERFACE sfizz::openmp) +endif() # The pugixml library add_library(sfizz_pugixml STATIC "src/external/pugixml/src/pugixml.cpp") diff --git a/common.mk b/common.mk index 7909df12..ca23cad7 100644 --- a/common.mk +++ b/common.mk @@ -364,3 +364,9 @@ SFIZZ_C_FLAGS += -pthread SFIZZ_CXX_FLAGS += -pthread SFIZZ_LINK_FLAGS += -pthread endif + +### OpenMP dependency + +SFIZZ_C_FLAGS += -fopenmp +SFIZZ_CXX_FLAGS += -fopenmp +SFIZZ_LINK_FLAGS += -fopenmp From e154c135fc52966e70f205958b8d91300e855b61 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 15 Feb 2021 04:56:10 +0100 Subject: [PATCH 270/668] Add the filter designer from hiir --- cmake/SfizzDeps.cmake | 6 + .../hiir/hiir/PolyphaseIir2Designer.cpp | 444 ++++++++++++++++++ .../hiir/hiir/PolyphaseIir2Designer.h | 143 ++++++ 3 files changed, 593 insertions(+) create mode 100644 src/external/hiir/hiir/PolyphaseIir2Designer.cpp create mode 100644 src/external/hiir/hiir/PolyphaseIir2Designer.h diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 864f1225..464d6186 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -105,6 +105,12 @@ add_library(sfizz_hiir INTERFACE) add_library(sfizz::hiir ALIAS sfizz_hiir) target_include_directories(sfizz_hiir INTERFACE "src/external/hiir") +# The hiir filter designer +add_library(sfizz_hiir_polyphase_iir2designer STATIC + "src/external/hiir/hiir/PolyphaseIir2Designer.cpp") +add_library(sfizz::hiir_polyphase_iir2designer ALIAS sfizz_hiir_polyphase_iir2designer) +target_link_libraries(sfizz_hiir_polyphase_iir2designer PUBLIC sfizz::hiir) + # The kissfft library add_library(sfizz_kissfft STATIC "src/external/kiss_fft/kiss_fft.c" diff --git a/src/external/hiir/hiir/PolyphaseIir2Designer.cpp b/src/external/hiir/hiir/PolyphaseIir2Designer.cpp new file mode 100644 index 00000000..d36883d6 --- /dev/null +++ b/src/external/hiir/hiir/PolyphaseIir2Designer.cpp @@ -0,0 +1,444 @@ +/***************************************************************************** + + PolyphaseIir2Designer.cpp + Author: Laurent de Soras, 2005 + +--- Legal stuff --- + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +*Tab=3***********************************************************************/ + + + +#if defined (_MSC_VER) + #pragma warning (1 : 4130) // "'operator' : logical operation on address of string constant" + #pragma warning (1 : 4223) // "nonstandard extension used : non-lvalue array converted to pointer" + #pragma warning (1 : 4705) // "statement has no effect" + #pragma warning (1 : 4706) // "assignment within conditional expression" + #pragma warning (4 : 4786) // "identifier was truncated to '255' characters in the debug information" + #pragma warning (4 : 4800) // "forcing value to bool 'true' or 'false' (performance warning)" + #pragma warning (4 : 4355) // "'this' : used in base member initializer list" +#endif + + + +/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +#include "hiir/def.h" +#include "hiir/fnc.h" +#include "hiir/PolyphaseIir2Designer.h" + +#include +#include + + + +namespace hiir +{ + + + +/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +/* +============================================================================== +Name: compute_nbr_coefs_from_proto +Description: + Finds the minimum number of coefficients for a given filter specification +Input parameters: + - attenuation: stopband attenuation, dB. > 0. + - transition: normalized transition bandwith. Range ]0 ; 1/2[ +Returns: Number of coefficients, > 0 +Throws: Nothing +============================================================================== +*/ + +int PolyphaseIir2Designer::compute_nbr_coefs_from_proto (double attenuation, double transition) +{ + assert (attenuation > 0); + assert (transition > 0); + assert (transition < 0.5); + + double k; + double q; + compute_transition_param (k, q, transition); + const int order = compute_order (attenuation, q); + const int nbr_coefs = (order - 1) / 2; + + return nbr_coefs; +} + + + +/* +============================================================================== +Name: compute_atten_from_order_tbw +Description: + Compute the attenuation correspounding to a given number of coefficients + and the transition bandwith. +Input parameters: + - nbr_coefs: Number of desired coefficients. > 0. + - transition: normalized transition bandwith. Range ]0 ; 1/2[ +Returns: stopband attenuation, dB. > 0. +Throws: Nothing +============================================================================== +*/ + +double PolyphaseIir2Designer::compute_atten_from_order_tbw (int nbr_coefs, double transition) +{ + assert (nbr_coefs > 0); + assert (transition > 0); + assert (transition < 0.5); + + double k; + double q; + compute_transition_param (k, q, transition); + const int order = nbr_coefs * 2 + 1; + const double attenuation = compute_atten (q, order); + + return attenuation; +} + + + +/* +============================================================================== +Name: compute_coefs +Description: + Computes coefficients for a half-band polyphase IIR filter, function of a + given stopband gain / transition bandwidth specification. + Order is automatically calculated. +Input parameters: + - attenuation: stopband attenuation, dB. > 0. + - transition: normalized transition bandwith. Range ]0 ; 1/2[ +Output parameters: + - coef_arr: Coefficient list, must be large enough to store all the + coefficients. Filter order = nbr_coefs * 2 + 1 +Returns: number of coefficients +Throws: Nothing +============================================================================== +*/ + +int PolyphaseIir2Designer::compute_coefs (double coef_arr [], double attenuation, double transition) +{ + assert (attenuation > 0); + assert (transition > 0); + assert (transition < 0.5); + + double k; + double q; + compute_transition_param (k, q, transition); + + // Computes number of required coefficients + const int order = compute_order (attenuation, q); + const int nbr_coefs = (order - 1) / 2; + + // Coefficient calculation + for (int index = 0; index < nbr_coefs; ++index) + { + coef_arr [index] = compute_coef (index, k, q, order); + } + + return nbr_coefs; +} + + + +/* +============================================================================== +Name: compute_coefs_spec_order_tbw +Description: + Computes coefficients for a half-band polyphase IIR filter, function of a + given transition bandwidth and desired filter order. Bandstop attenuation + is set to the maximum value for these constraints. +Input parameters: + - nbr_coefs: Number of desired coefficients. > 0. + - transition: normalized transition bandwith. Range ]0 ; 1/2[ +Output parameters: + - coef_arr: Coefficient list, must be large enough to store all the + coefficients. +Throws: Nothing +============================================================================== +*/ + +void PolyphaseIir2Designer::compute_coefs_spec_order_tbw (double coef_arr [], int nbr_coefs, double transition) +{ + assert (nbr_coefs > 0); + assert (transition > 0); + assert (transition < 0.5); + + double k; + double q; + compute_transition_param (k, q, transition); + const int order = nbr_coefs * 2 + 1; + + // Coefficient calculation + for (int index = 0; index < nbr_coefs; ++index) + { + coef_arr [index] = compute_coef (index, k, q, order); + } +} + + + +/* +============================================================================== +Name: compute_phase_delay +Description: + Computes the phase delay introduced by a single filtering unit at a + specified frequency. + The delay is given for a constant sampling rate between input and output. +Input parameters: + - a: coefficient for the cell, [0 ; 1] + - f_fs: frequency relative to the sampling rate, [0 ; 0.5]. +Returns: + The phase delay in samples, >= 0. +Throws: Nothing +============================================================================== +*/ + +double PolyphaseIir2Designer::compute_phase_delay (double a, double f_fs) +{ + assert (a >= 0); + assert (a <= 1); + assert (f_fs >= 0); + assert (f_fs < 0.5); + + const double w = 2 * hiir::PI * f_fs; + const double c = cos (w); + const double s = sin (w); + const double x = a + c + a * (c * (a + c) + s * s); + const double y = a * a * s - s; + double ph = atan2 (y, x); + if (ph < 0) + { + ph += 2 * hiir::PI; + } + const double dly = ph / w; + + return dly; +} + + + +/* +============================================================================== +Name: compute_group_delay +Description: + Computes the group delay introduced by a single filtering unit at a + specified frequency. + The delay is given for a constant sampling rate between input and output. + To compute the group delay of a complete filter, add the group delays + of all the units in A0 (z). +Input parameters: + - a: coefficient for the cell, [0 ; 1] + - f_fs: frequency relative to the sampling rate, [0 ; 0.5]. + - ph_flag: set if filtering unit is used in pi/2-phaser mode, in the form + (a - z^-2) / (1 - az^-2) +Returns: + The group delay in samples, >= 0. +Throws: Nothing +============================================================================== +*/ + +double PolyphaseIir2Designer::compute_group_delay (double a, double f_fs, bool ph_flag) +{ + assert (a >= 0); + assert (a <= 1); + assert (f_fs >= 0); + assert (f_fs < 0.5); + + const double w = 2 * hiir::PI * f_fs; + const double a2 = a * a; + const double sig = (ph_flag) ? -2 : 2; + const double dly = 2 * (1 - a2) / (a2 + sig * a * cos (2 * w) + 1); + + return dly; +} + + + +/* +============================================================================== +Name: compute_group_delay +Description: + Computes the group delay introduced by a complete filter at a specified + frequency. + The delay is given for a constant sampling rate between input and output. +Input parameters: + - coef_arr: filter coefficient, as given by the designing functions + - nbr_coefs: Number of filter coefficients. > 0. + - f_fs: frequency relative to the sampling rate, [0 ; 0.5]. + - ph_flag: set if filter is used in pi/2-phaser mode, in the form + (a - z^-2) / (1 - az^-2) +Returns: + The group delay in samples, >= 0. +Throws: Nothing +============================================================================== +*/ + +double PolyphaseIir2Designer::compute_group_delay (const double coef_arr [], int nbr_coefs, double f_fs, bool ph_flag) +{ + assert (nbr_coefs > 0); + assert (f_fs >= 0); + assert (f_fs < 0.5); + + double dly_total = 0; + for (int k = 0; k < nbr_coefs; ++k) + { + const double dly = compute_group_delay (coef_arr [k], f_fs, ph_flag); + dly_total += dly; + } + + return dly_total; +} + + + +/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +void PolyphaseIir2Designer::compute_transition_param (double &k, double &q, double transition) +{ + assert (transition > 0); + assert (transition < 0.5); + + k = tan ((1 - transition * 2) * hiir::PI / 4); + k *= k; + assert (k < 1); + assert (k > 0); + double kksqrt = pow (1 - k * k, 0.25); + const double e = 0.5 * (1 - kksqrt) / (1 + kksqrt); + const double e2 = e * e; + const double e4 = e2 * e2; + q = e * (1 + e4 * (2 + e4 * (15 + 150 * e4))); + assert (q > 0); +} + + + +int PolyphaseIir2Designer::compute_order (double attenuation, double q) +{ + assert (attenuation > 0); + assert (q > 0); + + const double attn_p2 = pow (10.0, -attenuation / 10); + const double a = attn_p2 / (1 - attn_p2); + int order = hiir::ceil_int (log (a * a / 16) / log (q)); + if ((order & 1) == 0) + { + ++ order; + } + if (order == 1) + { + order = 3; + } + + return order; +} + + + +double PolyphaseIir2Designer::compute_atten (double q, int order) +{ + assert (q > 0); + assert (order > 0); + assert ((order & 1) == 1); + + const double a = 4 * exp (order * 0.5 * log (q)); + assert (a != -1.0); + const double attn_p2 = a / (1 + a); + const double attenuation = -10 * log10 (attn_p2); + assert (attenuation > 0); + + return attenuation; +} + + + +double PolyphaseIir2Designer::compute_coef (int index, double k, double q, int order) +{ + assert (index >= 0); + assert (index * 2 < order); + + const int c = index + 1; + const double num = compute_acc_num (q, order, c) * pow (q, 0.25); + const double den = compute_acc_den (q, order, c) + 0.5; + const double ww = num / den; + const double wwsq = ww * ww; + + const double x = sqrt ((1 - wwsq * k) * (1 - wwsq / k)) / (1 + wwsq); + const double coef = (1 - x) / (1 + x); + + return coef; +} + + + +double PolyphaseIir2Designer::compute_acc_num (double q, int order, int c) +{ + assert (c >= 1); + assert (c < order * 2); + + int i = 0; + int j = 1; + double acc = 0; + double q_ii1; + do + { + q_ii1 = hiir::ipowp (q, i * (i + 1)); + q_ii1 *= sin ((i * 2 + 1) * c * hiir::PI / order) * j; + acc += q_ii1; + + j = -j; + ++i; + } + while (fabs (q_ii1) > 1e-100); + + return acc; +} + + + +double PolyphaseIir2Designer::compute_acc_den (double q, int order, int c) +{ + assert (c >= 1); + assert (c < order * 2); + + int i = 1; + int j = -1; + double acc = 0; + double q_i2; + do + { + q_i2 = hiir::ipowp (q, i * i); + q_i2 *= cos (i * 2 * c * hiir::PI / order) * j; + acc += q_i2; + + j = -j; + ++i; + } + while (fabs (q_i2) > 1e-100); + + return acc; +} + + + +} // namespace hiir + + + +/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ diff --git a/src/external/hiir/hiir/PolyphaseIir2Designer.h b/src/external/hiir/hiir/PolyphaseIir2Designer.h new file mode 100644 index 00000000..db3b4d09 --- /dev/null +++ b/src/external/hiir/hiir/PolyphaseIir2Designer.h @@ -0,0 +1,143 @@ +/***************************************************************************** + + PolyphaseIir2Designer.h + Author: Laurent de Soras, 2005 + +Compute coefficients for 2-path polyphase IIR filter, half-band filter or +Pi/2 phaser. + + -2 + a + z + N/2-1 2k +A0 (z) = Prod ---------- + k = 0 -2 + 1 + a z + 2k + + -2 + a + z + -1 (N-1)/2 2k+1 +A1 (z) = z . Prod ------------ + k = 0 -2 + 1 + a z + 2k+1 + + 1 +H (z) = - (A0 (z) + A1 (z)) + 2 + +Sum of A0 and A1 gives a low-pass filter. +Difference of A0 and A1 gives the complementary high-pass filter. + +For the Pi/2 phaser, product form is (a - z^-2) / (1 - az^-2) +Sum and difference of A0 and A1 have a Pi/2 phase difference. + +References: + +* Artur Krukowski + Polyphase Two-Path Filter Designer in Java + http://www.cmsa.wmin.ac.uk/~artur/Poly.html + +* R.A. Valenzuela, A.G. Constantinides + Digital Signal Processing Schemes for Efficient Interpolation and Decimation + IEE Proceedings, Dec 1983 + +* Scott Wardle + A Hilbert-Transformer Frequency Shifter for Audio + International Conference on Digital Audio Effects (DAFx) 1998 + http://www.iua.upf.es/dafx98/papers/WAR19.PS + +--- Legal stuff --- + +This program is free software. It comes without any warranty, to +the extent permitted by applicable law. You can redistribute it +and/or modify it under the terms of the Do What The Fuck You Want +To Public License, Version 2, as published by Sam Hocevar. See +http://sam.zoy.org/wtfpl/COPYING for more details. + +*Tab=3***********************************************************************/ + + + +#if ! defined (hiir_PolyphaseIir2Designer_HEADER_INCLUDED) +#define hiir_PolyphaseIir2Designer_HEADER_INCLUDED + +#if defined (_MSC_VER) + #pragma once + #pragma warning (4 : 4250) // "Inherits via dominance." +#endif + + + +/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + + + +namespace hiir +{ + + + +class PolyphaseIir2Designer +{ + +/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +public: + + static int compute_nbr_coefs_from_proto (double attenuation, double transition); + static double compute_atten_from_order_tbw (int nbr_coefs, double transition); + + static int compute_coefs (double coef_arr [], double attenuation, double transition); + static void compute_coefs_spec_order_tbw (double coef_arr [], int nbr_coefs, double transition); + + static double compute_phase_delay (double a, double f_fs); + static double compute_group_delay (double a, double f_fs, bool ph_flag); + static double compute_group_delay (const double coef_arr [], int nbr_coefs, double f_fs, bool ph_flag); + + + +/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +protected: + + + +/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +private: + + static void compute_transition_param (double &k, double &q, double transition); + static int compute_order (double attenuation, double q); + static double compute_atten (double q, int order); + static double compute_coef (int index, double k, double q, int order); + static double compute_acc_num (double q, int order, int c); + static double compute_acc_den (double q, int order, int c); + + + +/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ + +private: + + PolyphaseIir2Designer (); + ~PolyphaseIir2Designer (); + PolyphaseIir2Designer (const PolyphaseIir2Designer &other); + PolyphaseIir2Designer & + operator = (const PolyphaseIir2Designer &other); + bool operator == (const PolyphaseIir2Designer &other); + bool operator != (const PolyphaseIir2Designer &other); + +}; // class PolyphaseIir2Designer + + + +} // namespace hiir + + + +#endif // hiir_PolyphaseIir2Designer_HEADER_INCLUDED + + + +/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ From 0034fe59034791600b04ce0c4cf0a75c05a4a6e3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 15 Feb 2021 06:39:35 +0100 Subject: [PATCH 271/668] Add tool to generate oversampler coeffs and code --- devtools/CMakeLists.txt | 3 + devtools/HIIRDesigner.cpp | 365 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 368 insertions(+) create mode 100644 devtools/HIIRDesigner.cpp diff --git a/devtools/CMakeLists.txt b/devtools/CMakeLists.txt index 352c5cd1..e1bc85f6 100644 --- a/devtools/CMakeLists.txt +++ b/devtools/CMakeLists.txt @@ -10,3 +10,6 @@ endif() add_executable(sfizz_preprocessor Preprocessor.cpp) target_link_libraries(sfizz_preprocessor PRIVATE sfizz::parser sfizz::pugixml sfizz::cxxopts) + +add_executable(sfizz_hiir_designer HIIRDesigner.cpp) +target_link_libraries(sfizz_hiir_designer PRIVATE sfizz::hiir_polyphase_iir2designer) diff --git a/devtools/HIIRDesigner.cpp b/devtools/HIIRDesigner.cpp new file mode 100644 index 00000000..d857a449 --- /dev/null +++ b/devtools/HIIRDesigner.cpp @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include +#include +#include +#include +#include +#include +#include + +using FD = hiir::PolyphaseIir2Designer; + +struct Stage { + int factor; + double tbw; + int nbr_coefs; + std::unique_ptr coefs; +}; + +static std::vector calculate_stages(int oversampling, double attenuation, double transition); +static void generate_cpp_prologue(int argc, char *argv[]); +static void generate_cpp_epilogue(); +static void generate_cpp_coefs(const Stage *stages, int num_stages); +static void generate_cpp_upsampler(const Stage *stages, int num_stages); +static void generate_cpp_downsampler(const Stage *stages, int num_stages); + +int main(int argc, char *argv[]) +{ + double attenuation = 0.0; + double transition = 0.0; + int oversampling = 16; + bool have_a = false; + bool have_t = false; + + for (int argi = 1; argi < argc; ++argi) { + const char *arg = argv[argi]; + if (!strcmp(arg, "-a")) { + if (++argi >= argc) { + fprintf(stderr, "The option %s expects a value.\n", arg); + return 1; + } + arg = argv[argi]; + attenuation = atof(arg); + have_a = true; + } + else if (!strcmp(arg, "-t")) { + if (++argi >= argc) { + fprintf(stderr, "The option %s expects a value.\n", arg); + return 1; + } + arg = argv[argi]; + transition = atof(arg); + have_t = true; + } + else if (!strcmp(arg, "-o")) { + if (++argi >= argc) { + fprintf(stderr, "The option %s expects a value.\n", arg); + return 1; + } + arg = argv[argi]; + oversampling = atoi(arg); + } + else { + fprintf(stderr, "Unrecognized argument: %s\n", arg); + return 1; + } + } + + if (!have_a) { + fprintf(stderr, "No attenuation given (-a)\n"); + return 1; + } + if (!have_t) { + fprintf(stderr, "No transition bandwidth given (-t)\n"); + return 1; + } + else if (attenuation < 0.0) { + fprintf(stderr, "Invalid attenuation\n"); + return 1; + } + else if (transition <= 0.0 || transition >= 0.5) { + fprintf(stderr, "Invalid transition bandwidth\n"); + return 1; + } + else if (oversampling < 2) { + fprintf(stderr, "Invalid oversampling\n"); + return 1; + } + + std::vector stages = calculate_stages(oversampling, attenuation, transition); + int num_stages = (int)stages.size(); + + // generate the coeffs + generate_cpp_prologue(argc, argv); + printf("\n"); + generate_cpp_coefs(stages.data(), num_stages); + printf("\n"); + generate_cpp_upsampler(stages.data(), num_stages); + printf("\n"); + generate_cpp_downsampler(stages.data(), num_stages); + printf("\n"); + generate_cpp_epilogue(); + + return 0; +} + +static std::vector calculate_stages(int oversampling, double attenuation, double transition) +{ + std::vector stages; + stages.reserve(8); + + bool done = false; + for (int num_stage = 0; !done; ++num_stage) { + if (num_stage > 0) + printf("\n"); + + Stage stage; + stage.factor = 2 << num_stage; + stage.tbw = transition * + std::pow(0.5, num_stage) + 0.5 * (1 - std::pow(0.5, num_stage)); + + stage.nbr_coefs = FD::compute_nbr_coefs_from_proto(attenuation, stage.tbw); + double *coefs = new double[stage.nbr_coefs]{}; + stage.coefs.reset(coefs); + + FD::compute_coefs(coefs, attenuation, stage.tbw); + + done = stage.factor >= oversampling; + + stages.push_back(std::move(stage)); + } + + return stages; +} + +static void generate_cpp_prologue(int argc, char *argv[]) +{ + printf("// This is generated by the Sfizz HIIR designer\n"); + printf("// Using options:"); + for (int i = 1; i < argc; ++i) + printf(" %s", argv[i]); + printf("\n"); + + printf("\n"); + + printf( + "#pragma once\n" + "#include \"OversamplerHelpers.h\"\n" + "\n" + "namespace sfz {\n" + ); +} + +static void generate_cpp_epilogue() +{ + printf("} // namespace sfz\n"); +} + +static void generate_cpp_coefs(const Stage *stages, int num_stages) +{ + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[i]; + const double *coefs = stage.coefs.get(); + printf("// %dx <-> %dx: TBW = %g\n", stage.factor, stage.factor / 2, stage.tbw); + printf("static constexpr double OSCoeffs%dx[%d] = {\n", stage.factor, stage.nbr_coefs); + for (int i = 0; i < stage.nbr_coefs; ++i) { + printf("\t" "%.18f,\n", coefs[i]); + } + printf("};\n"); + } +} + +static void generate_cpp_upsampler(const Stage *stages, int num_stages) +{ + printf("class Upsampler {\n"); + printf("public:\n"); + + printf("\t" "Upsampler()\n"); + printf("\t" "{\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[i]; + printf("\t\t" "up%d_.set_coefs(OSCoeffs%dx);\n", stage.factor, stage.factor); + } + printf("\t" "}\n"); + + printf("\t" "void clear()\n"); + printf("\t" "{\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[i]; + printf("\t\t" "up%d_.clear_buffers();\n", stage.factor); + } + printf("\t" "}\n"); + + printf("\t" "static int recommendedBuffer(int factor, int spl)\n"); + printf("\t" "{\n"); + printf("\t\t" "return factor * spl;\n"); + printf("\t" "}\n"); + + printf("\t" "static bool canProcess(int factor)\n"); + printf("\t" "{\n"); + printf("\t\t" "switch (factor) {\n"); + printf("\t\t" "case 1:\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[i]; + printf("\t\t" "case %d:\n", stage.factor); + } + printf("\t\t\t" "return true;\n"); + printf("\t\t" "default:\n"); + printf("\t\t\t" "return false;\n"); + printf("\t\t" "}\n"); + printf("\t" "}\n"); + + printf("\t" "void process(int factor, const float *in, float *out, int spl, float *temp, int ntemp)\n"); + printf("\t" "{\n"); + printf("\t\t" "switch (factor) {\n"); + printf("\t\t" "case 1:\n"); + printf("\t\t\t" "if (in != out) std::memcpy(out, in, spl * sizeof(float));\n"); + printf("\t\t\t" "break;\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[i]; + printf("\t\t" "case %d:\n", stage.factor); + printf("\t\t\t" "process%dx(in, out, spl, temp, ntemp);\n", stage.factor); + printf("\t\t\t" "break;\n"); + } + printf("\t\t" "default:\n"); + printf("\t\t\t" "ASSERTFALSE;\n"); + printf("\t\t\t" "break;\n"); + printf("\t\t" "}\n"); + printf("\t" "}\n"); + + for (int n = 1; n <= num_stages; ++n) { + printf("\t" "void process%dx(const float *in, float *out, int spl, float *temp, int ntemp)\n", stages[n - 1].factor); + printf("\t" "{\n"); + printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor); + printf("\t\t" "ASSERT(maxspl >= 0);\n"); + printf("\t\t" "float *t1 = temp;\n"); + printf("\t\t" "float *t2 = temp + %d * maxspl;\n", stages[n - 1].factor / 2); + printf("\t\t" "(void)t1;\n"); + printf("\t\t" "(void)t2;\n"); + printf("\t\t" "while (spl > 0) {\n"); + printf("\t\t\t" "int curspl = (spl < maxspl) ? spl : maxspl;\n"); + for (int i = 0; i < n; ++i) { + const Stage &stage = stages[i]; + const char *tempnames[] = {"t1", "t2"}; + const char *outname = tempnames[i & 1]; + const char *inname = tempnames[1 - (i & 1)]; + if (i == 0) + inname = "in"; + if (i + 1 == n) + outname = "out"; + printf("\t\t\t" "up%d_.process_block(%s, %s, %d * curspl);\n", stage.factor, outname, inname, stage.factor / 2); + } + printf("\t\t\t" "in += curspl;\n"); + printf("\t\t\t" "out += curspl;\n"); + printf("\t\t\t" "spl -= curspl;\n"); + printf("\t\t" "}\n"); + printf("\t" "}\n"); + } + + printf("private:\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[i]; + printf("\t" "hiir::Upsampler2x<%d> up%d_;\n", stage.nbr_coefs, stage.factor); + } + printf("};\n"); +} + +static void generate_cpp_downsampler(const Stage *stages, int num_stages) +{ + printf("class Downsampler {\n"); + printf("public:\n"); + + printf("\t" "Downsampler()\n"); + printf("\t" "{\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[num_stages - 1 - i]; + printf("\t\t" "down%d_.set_coefs(OSCoeffs%dx);\n", stage.factor, stage.factor); + } + printf("\t" "}\n"); + + printf("\t" "void clear()\n"); + printf("\t" "{\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[num_stages - 1 - i]; + printf("\t\t" "down%d_.clear_buffers();\n", stage.factor); + } + printf("\t" "}\n"); + + printf("\t" "static int recommendedBuffer(int factor, int spl)\n"); + printf("\t" "{\n"); + printf("\t\t" "return factor * spl;\n"); + printf("\t" "}\n"); + + printf("\t" "static bool canProcess(int factor)\n"); + printf("\t" "{\n"); + printf("\t\t" "switch (factor) {\n"); + printf("\t\t" "case 1:\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[i]; + printf("\t\t" "case %d:\n", stage.factor); + } + printf("\t\t\t" "return true;\n"); + printf("\t\t" "default:\n"); + printf("\t\t\t" "return false;\n"); + printf("\t\t" "}\n"); + printf("\t" "}\n"); + + printf("\t" "void process(int factor, const float *in, float *out, int spl, float *temp, int ntemp)\n"); + printf("\t" "{\n"); + printf("\t\t" "switch (factor) {\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[num_stages - 1 - i]; + printf("\t\t" "case %d:\n", stage.factor); + printf("\t\t\t" "process%dx(in, out, spl, temp, ntemp);\n", stage.factor); + printf("\t\t\t" "break;\n"); + } + printf("\t\t" "case 1:\n"); + printf("\t\t\t" "if (in != out) std::memcpy(out, in, spl * sizeof(float));\n"); + printf("\t\t\t" "break;\n"); + printf("\t\t" "default:\n"); + printf("\t\t\t" "ASSERTFALSE;\n"); + printf("\t\t\t" "break;\n"); + printf("\t\t" "}\n"); + printf("\t" "}\n"); + + for (int n = 1; n <= num_stages; ++n) { + printf("\t" "void process%dx(const float *in, float *out, int spl, float *temp, int ntemp)\n", stages[n - 1].factor); + printf("\t" "{\n"); + printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor); + printf("\t\t" "ASSERT(maxspl >= 0);\n"); + printf("\t\t" "float *t1 = temp;\n"); + printf("\t\t" "float *t2 = temp + %d * maxspl;\n", stages[n - 1].factor / 2); + printf("\t\t" "(void)t1;\n"); + printf("\t\t" "(void)t2;\n"); + printf("\t\t" "while (spl > 0) {\n"); + printf("\t\t\t" "int curspl = (spl < maxspl) ? spl : maxspl;\n"); + for (int i = 0; i < n; ++i) { + const Stage &stage = stages[n - 1 - i]; + const char *tempnames[] = {"t1", "t2"}; + const char *outname = tempnames[i & 1]; + const char *inname = tempnames[1 - (i & 1)]; + if (i == 0) + inname = "in"; + if (i + 1 == n) + outname = "out"; + printf("\t\t\t" "down%d_.process_block(%s, %s, %d * curspl);\n", stage.factor, outname, inname, stage.factor / 2); + } + printf("\t\t\t" "in += curspl;\n"); + printf("\t\t\t" "out += curspl;\n"); + printf("\t\t\t" "spl -= curspl;\n"); + printf("\t\t" "}\n"); + printf("\t" "}\n"); + } + + printf("private:\n"); + for (int i = 0; i < num_stages; ++i) { + const Stage &stage = stages[num_stages - 1 - i]; + printf("\t" "hiir::Downsampler2x<%d> down%d_;\n", stage.nbr_coefs, stage.factor); + } + printf("};\n"); +} From 090619cfa4bc33dda4b18a090d4ec0bcab62aff5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 15 Feb 2021 14:06:42 +0100 Subject: [PATCH 272/668] Add the generated oversampling code --- src/sfizz/OversamplerHelpers.h | 50 ++++ src/sfizz/OversamplerHelpers.hxx | 496 +++++++++++++++++++++++++++++++ 2 files changed, 546 insertions(+) create mode 100644 src/sfizz/OversamplerHelpers.h create mode 100644 src/sfizz/OversamplerHelpers.hxx diff --git a/src/sfizz/OversamplerHelpers.h b/src/sfizz/OversamplerHelpers.h new file mode 100644 index 00000000..ae7e6771 --- /dev/null +++ b/src/sfizz/OversamplerHelpers.h @@ -0,0 +1,50 @@ +#pragma once +#include "SIMDConfig.h" +#include "Config.h" +#include "Debug.h" +#include +#include + +namespace sfz { +class Upsampler; +class Downsampler; +} // namespace sfz + +#include +#include + +// Note: according to HIIR documentation, FPU versions are +// more efficient than SIMD below 12 coefficients. + +#if SFIZZ_HAVE_SSE +#include +#include + +namespace hiir { +template using Upsampler2x = typename std::conditional= 12, + hiir::Upsampler2xSse, hiir::Upsampler2xFpu>::type; +template using Downsampler2x = typename std::conditional= 12, + hiir::Downsampler2xSse, hiir::Downsampler2xFpu>::type; +} // namespace hiir + +#elif SFIZZ_HAVE_NEON +#include +#include + +namespace hiir { +template using Upsampler2x = typename std::conditional= 12, + hiir::Upsampler2xNeon, hiir::Upsampler2xFpu>::type; +template using Downsampler2x = typename std::conditional= 12, + hiir::Downsampler2xNeon, hiir::Downsampler2xFpu>::type; +} // namespace hiir + +#else + +namespace hiir { +template using Upsampler2x = hiir::Upsampler2xFpu; +template using Downsampler2x = hiir::Downsampler2xFpu; +} // namespace hiir + +#endif + +#include "OversamplerHelpers.hxx" diff --git a/src/sfizz/OversamplerHelpers.hxx b/src/sfizz/OversamplerHelpers.hxx new file mode 100644 index 00000000..bca26547 --- /dev/null +++ b/src/sfizz/OversamplerHelpers.hxx @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +// This is generated by the Sfizz HIIR designer +// Using options: -a 96 -t 0.01 -o 128 + +#pragma once +#include "OversamplerHelpers.h" + +namespace sfz { + +// 2x <-> 1x: TBW = 0.01 +static constexpr double OSCoeffs2x[12] = { + 0.036681502163648017, + 0.136547624631957715, + 0.274631759379454110, + 0.423138617436566666, + 0.561098697879194752, + 0.677540049974161618, + 0.769741833863226588, + 0.839889624849638028, + 0.892260818003878908, + 0.931541959963183896, + 0.962094548378083947, + 0.987816370732897076, +}; +// 4x <-> 2x: TBW = 0.255 +static constexpr double OSCoeffs4x[4] = { + 0.041893991997656171, + 0.168903482439952013, + 0.390560772921165922, + 0.743895748268478152, +}; +// 8x <-> 4x: TBW = 0.3775 +static constexpr double OSCoeffs8x[3] = { + 0.055748680811302048, + 0.243051195741530918, + 0.646699131192682297, +}; +// 16x <-> 8x: TBW = 0.43875 +static constexpr double OSCoeffs16x[2] = { + 0.107172166664564611, + 0.530904350331903085, +}; +// 32x <-> 16x: TBW = 0.469375 +static constexpr double OSCoeffs32x[2] = { + 0.105969237763476387, + 0.528620279623742473, +}; +// 64x <-> 32x: TBW = 0.484687 +static constexpr double OSCoeffs64x[1] = { + 0.333526281707771211, +}; +// 128x <-> 64x: TBW = 0.492344 +static constexpr double OSCoeffs128x[1] = { + 0.333381553051105561, +}; + +class Upsampler { +public: + Upsampler() + { + up2_.set_coefs(OSCoeffs2x); + up4_.set_coefs(OSCoeffs4x); + up8_.set_coefs(OSCoeffs8x); + up16_.set_coefs(OSCoeffs16x); + up32_.set_coefs(OSCoeffs32x); + up64_.set_coefs(OSCoeffs64x); + up128_.set_coefs(OSCoeffs128x); + } + void clear() + { + up2_.clear_buffers(); + up4_.clear_buffers(); + up8_.clear_buffers(); + up16_.clear_buffers(); + up32_.clear_buffers(); + up64_.clear_buffers(); + up128_.clear_buffers(); + } + static int recommendedBuffer(int factor, int spl) + { + return factor * spl; + } + static bool canProcess(int factor) + { + switch (factor) { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + return true; + default: + return false; + } + } + void process(int factor, const float *in, float *out, int spl, float *temp, int ntemp) + { + switch (factor) { + case 1: + if (in != out) std::memcpy(out, in, spl * sizeof(float)); + break; + case 2: + process2x(in, out, spl, temp, ntemp); + break; + case 4: + process4x(in, out, spl, temp, ntemp); + break; + case 8: + process8x(in, out, spl, temp, ntemp); + break; + case 16: + process16x(in, out, spl, temp, ntemp); + break; + case 32: + process32x(in, out, spl, temp, ntemp); + break; + case 64: + process64x(in, out, spl, temp, ntemp); + break; + case 128: + process128x(in, out, spl, temp, ntemp); + break; + default: + ASSERTFALSE; + break; + } + } + void process2x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 2; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 1 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + up2_.process_block(out, in, 1 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process4x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 4; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 2 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + up2_.process_block(t1, in, 1 * curspl); + up4_.process_block(out, t1, 2 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process8x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 8; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 4 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + up2_.process_block(t1, in, 1 * curspl); + up4_.process_block(t2, t1, 2 * curspl); + up8_.process_block(out, t2, 4 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process16x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 16; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 8 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + up2_.process_block(t1, in, 1 * curspl); + up4_.process_block(t2, t1, 2 * curspl); + up8_.process_block(t1, t2, 4 * curspl); + up16_.process_block(out, t1, 8 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process32x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 32; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 16 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + up2_.process_block(t1, in, 1 * curspl); + up4_.process_block(t2, t1, 2 * curspl); + up8_.process_block(t1, t2, 4 * curspl); + up16_.process_block(t2, t1, 8 * curspl); + up32_.process_block(out, t2, 16 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process64x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 64; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 32 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + up2_.process_block(t1, in, 1 * curspl); + up4_.process_block(t2, t1, 2 * curspl); + up8_.process_block(t1, t2, 4 * curspl); + up16_.process_block(t2, t1, 8 * curspl); + up32_.process_block(t1, t2, 16 * curspl); + up64_.process_block(out, t1, 32 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process128x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 128; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 64 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + up2_.process_block(t1, in, 1 * curspl); + up4_.process_block(t2, t1, 2 * curspl); + up8_.process_block(t1, t2, 4 * curspl); + up16_.process_block(t2, t1, 8 * curspl); + up32_.process_block(t1, t2, 16 * curspl); + up64_.process_block(t2, t1, 32 * curspl); + up128_.process_block(out, t2, 64 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } +private: + hiir::Upsampler2x<12> up2_; + hiir::Upsampler2x<4> up4_; + hiir::Upsampler2x<3> up8_; + hiir::Upsampler2x<2> up16_; + hiir::Upsampler2x<2> up32_; + hiir::Upsampler2x<1> up64_; + hiir::Upsampler2x<1> up128_; +}; + +class Downsampler { +public: + Downsampler() + { + down128_.set_coefs(OSCoeffs128x); + down64_.set_coefs(OSCoeffs64x); + down32_.set_coefs(OSCoeffs32x); + down16_.set_coefs(OSCoeffs16x); + down8_.set_coefs(OSCoeffs8x); + down4_.set_coefs(OSCoeffs4x); + down2_.set_coefs(OSCoeffs2x); + } + void clear() + { + down128_.clear_buffers(); + down64_.clear_buffers(); + down32_.clear_buffers(); + down16_.clear_buffers(); + down8_.clear_buffers(); + down4_.clear_buffers(); + down2_.clear_buffers(); + } + static int recommendedBuffer(int factor, int spl) + { + return factor * spl; + } + static bool canProcess(int factor) + { + switch (factor) { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + return true; + default: + return false; + } + } + void process(int factor, const float *in, float *out, int spl, float *temp, int ntemp) + { + switch (factor) { + case 128: + process128x(in, out, spl, temp, ntemp); + break; + case 64: + process64x(in, out, spl, temp, ntemp); + break; + case 32: + process32x(in, out, spl, temp, ntemp); + break; + case 16: + process16x(in, out, spl, temp, ntemp); + break; + case 8: + process8x(in, out, spl, temp, ntemp); + break; + case 4: + process4x(in, out, spl, temp, ntemp); + break; + case 2: + process2x(in, out, spl, temp, ntemp); + break; + case 1: + if (in != out) std::memcpy(out, in, spl * sizeof(float)); + break; + default: + ASSERTFALSE; + break; + } + } + void process2x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 2; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 1 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + down2_.process_block(out, in, 1 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process4x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 4; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 2 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + down4_.process_block(t1, in, 2 * curspl); + down2_.process_block(out, t1, 1 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process8x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 8; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 4 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + down8_.process_block(t1, in, 4 * curspl); + down4_.process_block(t2, t1, 2 * curspl); + down2_.process_block(out, t2, 1 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process16x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 16; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 8 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + down16_.process_block(t1, in, 8 * curspl); + down8_.process_block(t2, t1, 4 * curspl); + down4_.process_block(t1, t2, 2 * curspl); + down2_.process_block(out, t1, 1 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process32x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 32; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 16 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + down32_.process_block(t1, in, 16 * curspl); + down16_.process_block(t2, t1, 8 * curspl); + down8_.process_block(t1, t2, 4 * curspl); + down4_.process_block(t2, t1, 2 * curspl); + down2_.process_block(out, t2, 1 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process64x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 64; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 32 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + down64_.process_block(t1, in, 32 * curspl); + down32_.process_block(t2, t1, 16 * curspl); + down16_.process_block(t1, t2, 8 * curspl); + down8_.process_block(t2, t1, 4 * curspl); + down4_.process_block(t1, t2, 2 * curspl); + down2_.process_block(out, t1, 1 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } + void process128x(const float *in, float *out, int spl, float *temp, int ntemp) + { + int maxspl = ntemp / 128; + ASSERT(maxspl >= 0); + float *t1 = temp; + float *t2 = temp + 64 * maxspl; + (void)t1; + (void)t2; + while (spl > 0) { + int curspl = (spl < maxspl) ? spl : maxspl; + down128_.process_block(t1, in, 64 * curspl); + down64_.process_block(t2, t1, 32 * curspl); + down32_.process_block(t1, t2, 16 * curspl); + down16_.process_block(t2, t1, 8 * curspl); + down8_.process_block(t1, t2, 4 * curspl); + down4_.process_block(t2, t1, 2 * curspl); + down2_.process_block(out, t2, 1 * curspl); + in += curspl; + out += curspl; + spl -= curspl; + } + } +private: + hiir::Downsampler2x<1> down128_; + hiir::Downsampler2x<1> down64_; + hiir::Downsampler2x<2> down32_; + hiir::Downsampler2x<2> down16_; + hiir::Downsampler2x<3> down8_; + hiir::Downsampler2x<4> down4_; + hiir::Downsampler2x<12> down2_; +}; + +} // namespace sfz From 4b6497272d54c02f24e03b97b5100e8c5ad29685 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 15 Feb 2021 15:25:50 +0100 Subject: [PATCH 273/668] Implement sfizz oversampler using new code --- src/sfizz/Oversampler.cpp | 169 ++++++-------------------------------- 1 file changed, 24 insertions(+), 145 deletions(-) diff --git a/src/sfizz/Oversampler.cpp b/src/sfizz/Oversampler.cpp index 954a6119..b0d1ed5f 100644 --- a/src/sfizz/Oversampler.cpp +++ b/src/sfizz/Oversampler.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Oversampler.h" +#include "OversamplerHelpers.h" #include "Buffer.h" #include "AudioSpan.h" #include "AudioReader.h" @@ -14,52 +15,6 @@ template using aligned_vector = std::vector>; -constexpr std::array coeffsStage2x { - 0.036681502163648017, - 0.13654762463195771, - 0.27463175937945411, - 0.42313861743656667, - 0.56109869787919475, - 0.67754004997416162, - 0.76974183386322659, - 0.83988962484963803, - 0.89226081800387891, - 0.9315419599631839, - 0.96209454837808395, - 0.98781637073289708 -}; - -constexpr std::array coeffsStage4x { - 0.042448989488488006, - 0.17072114107630679, - 0.39329183835224008, - 0.74569514831986694 -}; - -constexpr std::array coeffsStage8x { - 0.055748680811302048, - 0.24305119574153092, - 0.6466991311926823 -}; - - -#if SFIZZ_HAVE_SSE -#include "hiir/Upsampler2xSse.h" -using Upsampler2x = hiir::Upsampler2xSse; -using Upsampler4x = hiir::Upsampler2xSse; -using Upsampler8x = hiir::Upsampler2xSse; -#elif SFIZZ_HAVE_NEON -#include "hiir/Upsampler2xNeon.h" -using Upsampler2x = hiir::Upsampler2xNeon; -using Upsampler4x = hiir::Upsampler2xNeon; -using Upsampler8x = hiir::Upsampler2xNeon; -#else -#include "hiir/Upsampler2xFpu.h" -using Upsampler2x = hiir::Upsampler2xFpu; -using Upsampler4x = hiir::Upsampler2xFpu; -using Upsampler8x = hiir::Upsampler2xFpu; -#endif - sfz::Oversampler::Oversampler(sfz::Oversampling factor, size_t chunkSize) : factor(factor), chunkSize(chunkSize) { @@ -74,36 +29,10 @@ void sfz::Oversampler::stream(AudioSpan input, AudioSpan output, s const auto numFrames = input.getNumFrames(); const auto numChannels = input.getNumChannels(); - aligned_vector upsampler2x; - aligned_vector upsampler4x; - aligned_vector upsampler8x; + aligned_vector upsampler(numChannels); - switch(factor) - { - case Oversampling::x8: - upsampler8x.resize(numChannels); - for (auto& upsampler: upsampler8x) - upsampler.set_coefs(coeffsStage8x.data()); - // fallthrough - case Oversampling::x4: - upsampler4x.resize(numChannels); - for (auto& upsampler: upsampler4x) - upsampler.set_coefs(coeffsStage4x.data()); - // fallthrough - case Oversampling::x2: - upsampler2x.resize(numChannels); - for (auto& upsampler: upsampler2x) - upsampler.set_coefs(coeffsStage2x.data()); - break; - case Oversampling::x1: - break; - } - - // Intermediate buffers - sfz::Buffer buffer1 { chunkSize * 2 }; - sfz::Buffer buffer2 { chunkSize * 4 }; - auto span1 = absl::MakeSpan(buffer1); - auto span2 = absl::MakeSpan(buffer2); + // Intermediate buffer + sfz::Buffer temp { std::max(128, Upsampler::recommendedBuffer(16, chunkSize)) }; size_t inputFrameCounter { 0 }; size_t outputFrameCounter { 0 }; @@ -115,23 +44,10 @@ void sfz::Oversampler::stream(AudioSpan input, AudioSpan output, s for (size_t chanIdx = 0; chanIdx < numChannels; chanIdx++) { const auto inputChunk = input.getSpan(chanIdx).subspan(inputFrameCounter, thisChunkSize); const auto outputChunk = output.getSpan(chanIdx).subspan(outputFrameCounter, outputChunkSize); - switch (factor) { - case Oversampling::x1: - copy(inputChunk, outputChunk); - break; - case Oversampling::x2: - upsampler2x[chanIdx].process_block(outputChunk.data(), inputChunk.data(), static_cast(thisChunkSize)); - break; - case Oversampling::x4: - upsampler2x[chanIdx].process_block(span1.data(), inputChunk.data(), static_cast(thisChunkSize)); - upsampler4x[chanIdx].process_block(outputChunk.data(), span1.data(), static_cast(thisChunkSize * 2)); - break; - case Oversampling::x8: - upsampler2x[chanIdx].process_block(span1.data(), inputChunk.data(), static_cast(thisChunkSize)); - upsampler4x[chanIdx].process_block(span2.data(), span1.data(), static_cast(thisChunkSize * 2)); - upsampler8x[chanIdx].process_block(outputChunk.data(), span2.data(), static_cast(thisChunkSize * 4)); - break; - } + upsampler[chanIdx].process( + static_cast(factor), + inputChunk.data(), outputChunk.data(), static_cast(inputChunk.size()), + temp.data(), static_cast(temp.size())); } inputFrameCounter += thisChunkSize; outputFrameCounter += outputChunkSize; @@ -149,47 +65,18 @@ void sfz::Oversampler::stream(AudioReader& input, AudioSpan output, std:: const auto numFrames = static_cast(input.frames()); const auto numChannels = input.channels(); - aligned_vector upsampler2x; - aligned_vector upsampler4x; - aligned_vector upsampler8x; - - switch(factor) - { - case Oversampling::x8: - upsampler8x.resize(numChannels); - for (auto& upsampler: upsampler8x) - upsampler.set_coefs(coeffsStage8x.data()); - // fallthrough - case Oversampling::x4: - upsampler4x.resize(numChannels); - for (auto& upsampler: upsampler4x) - upsampler.set_coefs(coeffsStage4x.data()); - // fallthrough - case Oversampling::x2: - upsampler2x.resize(numChannels); - for (auto& upsampler: upsampler2x) - upsampler.set_coefs(coeffsStage2x.data()); - break; - case Oversampling::x1: - break; - } + aligned_vector upsampler(numChannels); // Intermediate buffers sfz::Buffer fileBlock { chunkSize * numChannels }; - sfz::Buffer buffer1 { chunkSize * 2 }; - sfz::Buffer buffer2 { chunkSize * 4 }; - auto span1 = absl::MakeSpan(buffer1); - auto span2 = absl::MakeSpan(buffer2); + sfz::Buffer channelBlock { chunkSize }; + sfz::Buffer temp { std::max(128, Upsampler::recommendedBuffer(16, chunkSize)) }; - auto upsample2xFromInterleaved = [numChannels]( - Upsampler2x& upsampler, float* output, const float* input, - size_t numInputFrames, unsigned chanIdx) + auto deinterleave = [numChannels]( + float* output, const float* input, size_t numFrames, unsigned chanIdx) { - for (size_t i = 0; i < numInputFrames; ++i) { - float* outp = &output[2 * i]; - const float* inp = &input[i * numChannels + chanIdx]; - upsampler.process_sample(outp[0], outp[1], inp[0]); - } + for (size_t i = 0; i < numFrames; ++i) + output[i] = input[i * numChannels + chanIdx]; }; size_t inputFrameCounter { 0 }; @@ -211,23 +98,15 @@ void sfz::Oversampler::stream(AudioReader& input, AudioSpan output, std:: for (size_t chanIdx = 0; chanIdx < numChannels; chanIdx++) { const auto outputChunk = output.getSpan(chanIdx).subspan(outputFrameCounter, outputChunkSize); - switch (factor) { - case Oversampling::x1: - for (size_t i = 0; i < thisChunkSize; ++i) - outputChunk[i] = fileBlock[i * numChannels + chanIdx]; - break; - case Oversampling::x2: - upsample2xFromInterleaved(upsampler2x[chanIdx], outputChunk.data(), fileBlock.data(), thisChunkSize, chanIdx); - break; - case Oversampling::x4: - upsample2xFromInterleaved(upsampler2x[chanIdx], span1.data(), fileBlock.data(), thisChunkSize, chanIdx); - upsampler4x[chanIdx].process_block(outputChunk.data(), span1.data(), static_cast(thisChunkSize * 2)); - break; - case Oversampling::x8: - upsample2xFromInterleaved(upsampler2x[chanIdx], span1.data(), fileBlock.data(), thisChunkSize, chanIdx); - upsampler4x[chanIdx].process_block(span2.data(), span1.data(), static_cast(thisChunkSize * 2)); - upsampler8x[chanIdx].process_block(outputChunk.data(), span2.data(), static_cast(thisChunkSize * 4)); - break; + + if (factor == Oversampling::x1) + deinterleave(outputChunk.data(), fileBlock.data(), thisChunkSize, chanIdx); + else { + deinterleave(channelBlock.data(), fileBlock.data(), thisChunkSize, chanIdx); + upsampler[chanIdx].process( + static_cast(factor), + channelBlock.data(), outputChunk.data(), static_cast(thisChunkSize), + temp.data(), static_cast(temp.size())); } } inputFrameCounter += thisChunkSize; From 69729b386bb4fed4ac35548633a39fb9c6f02d8f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 00:55:33 +0100 Subject: [PATCH 274/668] Comment emphasis about the generated file --- devtools/HIIRDesigner.cpp | 2 ++ src/sfizz/OversamplerHelpers.hxx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/devtools/HIIRDesigner.cpp b/devtools/HIIRDesigner.cpp index d857a449..bbb640fd 100644 --- a/devtools/HIIRDesigner.cpp +++ b/devtools/HIIRDesigner.cpp @@ -139,11 +139,13 @@ static std::vector calculate_stages(int oversampling, double attenuation, static void generate_cpp_prologue(int argc, char *argv[]) { + printf("//------------------------------------------------------------------------------\n"); printf("// This is generated by the Sfizz HIIR designer\n"); printf("// Using options:"); for (int i = 1; i < argc; ++i) printf(" %s", argv[i]); printf("\n"); + printf("//------------------------------------------------------------------------------\n"); printf("\n"); diff --git a/src/sfizz/OversamplerHelpers.hxx b/src/sfizz/OversamplerHelpers.hxx index bca26547..49cf3f60 100644 --- a/src/sfizz/OversamplerHelpers.hxx +++ b/src/sfizz/OversamplerHelpers.hxx @@ -4,8 +4,10 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz +//------------------------------------------------------------------------------ // This is generated by the Sfizz HIIR designer // Using options: -a 96 -t 0.01 -o 128 +//------------------------------------------------------------------------------ #pragma once #include "OversamplerHelpers.h" From 781f2167adb6bfd73e0a76653ffd5928c1504d78 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 01:20:57 +0100 Subject: [PATCH 275/668] Update disto fx with new oversampler --- src/sfizz/effects/Disto.cpp | 58 ++++++++++--------------------------- 1 file changed, 15 insertions(+), 43 deletions(-) diff --git a/src/sfizz/effects/Disto.cpp b/src/sfizz/effects/Disto.cpp index 946fdae6..0ee5534e 100644 --- a/src/sfizz/effects/Disto.cpp +++ b/src/sfizz/effects/Disto.cpp @@ -22,8 +22,7 @@ #include "Opcode.h" #include "Config.h" #include "MathHelpers.h" -#include -#include +#include "OversamplerHelpers.h" #include #include @@ -47,15 +46,9 @@ struct Disto::Impl { float _toneLpfMem[EffectChannels] = {}; faustDisto _stages[EffectChannels][Default::maxDistoStages]; - hiir::Upsampler2xFpu<12> _up2x[EffectChannels]; - hiir::Upsampler2xFpu<4> _up4x[EffectChannels]; - hiir::Upsampler2xFpu<3> _up8x[EffectChannels]; - - hiir::Downsampler2xFpu<12> _down2x[EffectChannels]; - hiir::Downsampler2xFpu<4> _down4x[EffectChannels]; - hiir::Downsampler2xFpu<3> _down8x[EffectChannels]; - - std::unique_ptr _temp8x[2]; + sfz::Upsampler _upsampler[EffectChannels]; + sfz::Downsampler _downsampler[EffectChannels]; + std::unique_ptr _temp[2]; // use the same formula as reverb float toneCutoff() const noexcept @@ -97,27 +90,14 @@ void Disto::setSampleRate(double sampleRate) stage.instanceConstants(sampleRate); } } - - static constexpr double coefs2x[12] = { 0.036681502163648017, 0.13654762463195794, 0.27463175937945444, 0.42313861743656711, 0.56109869787919531, 0.67754004997416184, 0.76974183386322703, 0.83988962484963892, 0.89226081800387902, 0.9315419599631839, 0.96209454837808417, 0.98781637073289585 }; - static constexpr double coefs4x[4] = { 0.042448989488488006, 0.17072114107630679, 0.39329183835224008, 0.74569514831986694 }; - static constexpr double coefs8x[3] = { 0.055748680811302048, 0.24305119574153092, 0.6466991311926823 }; - - for (unsigned c = 0; c < EffectChannels; ++c) { - impl._down2x[c].set_coefs(coefs2x); - impl._down4x[c].set_coefs(coefs4x); - impl._down8x[c].set_coefs(coefs8x); - impl._up2x[c].set_coefs(coefs2x); - impl._up4x[c].set_coefs(coefs4x); - impl._up8x[c].set_coefs(coefs8x); - } } void Disto::setSamplesPerBlock(int samplesPerBlock) { Impl& impl = *_impl; - for (std::unique_ptr& temp : impl._temp8x) - temp.reset(new float[8 * samplesPerBlock]); + for (std::unique_ptr& temp : impl._temp) + temp.reset(new float[_oversampling * samplesPerBlock]); } void Disto::clear() @@ -130,12 +110,8 @@ void Disto::clear() for (unsigned c = 0; c < EffectChannels; ++c) { impl._toneLpfMem[c] = 0.0f; - impl._up2x[c].clear_buffers(); - impl._up4x[c].clear_buffers(); - impl._up8x[c].clear_buffers(); - impl._down2x[c].clear_buffers(); - impl._down4x[c].clear_buffers(); - impl._down8x[c].clear_buffers(); + impl._downsampler[c].clear(); + impl._upsampler[c].clear(); } } @@ -162,14 +138,12 @@ void Disto::process(const float* const inputs[], float* const outputs[], unsigne } impl._toneLpfMem[c] = lpfMem; - // upsample to 8x + // upsample absl::Span temp[2] = { - absl::Span(impl._temp8x[0].get(), 8 * nframes), - absl::Span(impl._temp8x[1].get(), 8 * nframes), + absl::Span(impl._temp[0].get(), _oversampling * nframes), + absl::Span(impl._temp[1].get(), _oversampling * nframes), }; - impl._up2x[c].process_block(temp[0].data(), lpfOut.data(), nframes); - impl._up4x[c].process_block(temp[1].data(), temp[0].data(), 2 * nframes); - impl._up8x[c].process_block(temp[0].data(), temp[1].data(), 4 * nframes); + impl._upsampler[c].process(_oversampling, lpfOut.data(), temp[0].data(), nframes, temp[1].data(), static_cast(temp[1].size())); absl::Span upsamplerOut = temp[0]; // run disto stages @@ -180,13 +154,11 @@ void Disto::process(const float* const inputs[], float* const outputs[], unsigne // float *faustIn[] = { stageInOut.data() }; float *faustOut[] = { stageInOut.data() }; - impl._stages[c][s].compute(8 * nframes, faustIn, faustOut); + impl._stages[c][s].compute(_oversampling * nframes, faustIn, faustOut); } - // downsample to 1x - impl._down8x[c].process_block(temp[1].data(), stageInOut.data(), 4 * nframes); - impl._down4x[c].process_block(temp[0].data(), temp[1].data(), 2 * nframes); - impl._down2x[c].process_block(outputs[c], temp[0].data(), nframes); + // downsample + impl._downsampler[c].process(_oversampling, stageInOut.data(), outputs[c], nframes, temp[1].data(), static_cast(temp[1].size())); // dry/wet mix absl::Span mixOut(outputs[c], nframes); From ff359df5cd599feb79d276cdce260fa60af8ee5a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 02:03:21 +0100 Subject: [PATCH 276/668] Oversampler special cases 2x 4x --- devtools/HIIRDesigner.cpp | 60 +++++++++++++---- src/sfizz/OversamplerHelpers.hxx | 112 +++++++++++-------------------- 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/devtools/HIIRDesigner.cpp b/devtools/HIIRDesigner.cpp index bbb640fd..d021764a 100644 --- a/devtools/HIIRDesigner.cpp +++ b/devtools/HIIRDesigner.cpp @@ -199,7 +199,14 @@ static void generate_cpp_upsampler(const Stage *stages, int num_stages) printf("\t" "static int recommendedBuffer(int factor, int spl)\n"); printf("\t" "{\n"); - printf("\t\t" "return factor * spl;\n"); + printf("\t\t" "switch (factor) {\n"); + printf("\t\t" "case 2:\n"); + printf("\t\t\t" "return 0;\n"); + printf("\t\t" "case 4:\n"); + printf("\t\t\t" "return 2 * spl;\n"); + printf("\t\t" "default:\n"); + printf("\t\t\t" "return factor * spl;\n"); + printf("\t\t" "}\n"); printf("\t" "}\n"); printf("\t" "static bool canProcess(int factor)\n"); @@ -235,14 +242,25 @@ static void generate_cpp_upsampler(const Stage *stages, int num_stages) printf("\t" "}\n"); for (int n = 1; n <= num_stages; ++n) { + // special case factor=2, buffer not required + if (stages[n - 1].factor == 2) { + printf("\t" "void process2x(const float *in, float *out, int spl, float * = nullptr, int = 0)\n"); + printf("\t" "{\n"); + printf("\t\t" "up2_.process_block(out, in, spl);\n"); + printf("\t" "}\n"); + continue; + } printf("\t" "void process%dx(const float *in, float *out, int spl, float *temp, int ntemp)\n", stages[n - 1].factor); printf("\t" "{\n"); - printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor); - printf("\t\t" "ASSERT(maxspl >= 0);\n"); + // special case factor=4, only 1 buffer required + if (stages[n - 1].factor > 4) + printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor); + else + printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor / 2); + printf("\t\t" "ASSERT(maxspl > 0);\n"); printf("\t\t" "float *t1 = temp;\n"); - printf("\t\t" "float *t2 = temp + %d * maxspl;\n", stages[n - 1].factor / 2); - printf("\t\t" "(void)t1;\n"); - printf("\t\t" "(void)t2;\n"); + if (stages[n - 1].factor > 4) + printf("\t\t" "float *t2 = temp + %d * maxspl;\n", stages[n - 1].factor / 2); printf("\t\t" "while (spl > 0) {\n"); printf("\t\t\t" "int curspl = (spl < maxspl) ? spl : maxspl;\n"); for (int i = 0; i < n; ++i) { @@ -294,7 +312,14 @@ static void generate_cpp_downsampler(const Stage *stages, int num_stages) printf("\t" "static int recommendedBuffer(int factor, int spl)\n"); printf("\t" "{\n"); - printf("\t\t" "return factor * spl;\n"); + printf("\t\t" "switch (factor) {\n"); + printf("\t\t" "case 2:\n"); + printf("\t\t\t" "return 0;\n"); + printf("\t\t" "case 4:\n"); + printf("\t\t\t" "return 2 * spl;\n"); + printf("\t\t" "default:\n"); + printf("\t\t\t" "return factor * spl;\n"); + printf("\t\t" "}\n"); printf("\t" "}\n"); printf("\t" "static bool canProcess(int factor)\n"); @@ -330,14 +355,25 @@ static void generate_cpp_downsampler(const Stage *stages, int num_stages) printf("\t" "}\n"); for (int n = 1; n <= num_stages; ++n) { + // special case factor=2, buffer not required + if (stages[n - 1].factor == 2) { + printf("\t" "void process2x(const float *in, float *out, int spl, float * = nullptr, int = 0)\n"); + printf("\t" "{\n"); + printf("\t\t" "down2_.process_block(out, in, spl);\n"); + printf("\t" "}\n"); + continue; + } printf("\t" "void process%dx(const float *in, float *out, int spl, float *temp, int ntemp)\n", stages[n - 1].factor); printf("\t" "{\n"); - printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor); - printf("\t\t" "ASSERT(maxspl >= 0);\n"); + // special case factor=4, only 1 buffer required + if (stages[n - 1].factor > 4) + printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor); + else + printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor / 2); + printf("\t\t" "ASSERT(maxspl > 0);\n"); printf("\t\t" "float *t1 = temp;\n"); - printf("\t\t" "float *t2 = temp + %d * maxspl;\n", stages[n - 1].factor / 2); - printf("\t\t" "(void)t1;\n"); - printf("\t\t" "(void)t2;\n"); + if (stages[n - 1].factor > 4) + printf("\t\t" "float *t2 = temp + %d * maxspl;\n", stages[n - 1].factor / 2); printf("\t\t" "while (spl > 0) {\n"); printf("\t\t\t" "int curspl = (spl < maxspl) ? spl : maxspl;\n"); for (int i = 0; i < n; ++i) { diff --git a/src/sfizz/OversamplerHelpers.hxx b/src/sfizz/OversamplerHelpers.hxx index 49cf3f60..8e1bef52 100644 --- a/src/sfizz/OversamplerHelpers.hxx +++ b/src/sfizz/OversamplerHelpers.hxx @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: BSD-2-Clause -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + + + + //------------------------------------------------------------------------------ // This is generated by the Sfizz HIIR designer @@ -85,7 +85,14 @@ public: } static int recommendedBuffer(int factor, int spl) { - return factor * spl; + switch (factor) { + case 2: + return 0; + case 4: + return 2 * spl; + default: + return factor * spl; + } } static bool canProcess(int factor) { @@ -135,30 +142,15 @@ public: break; } } - void process2x(const float *in, float *out, int spl, float *temp, int ntemp) + void process2x(const float *in, float *out, int spl, float * = nullptr, int = 0) { - int maxspl = ntemp / 2; - ASSERT(maxspl >= 0); - float *t1 = temp; - float *t2 = temp + 1 * maxspl; - (void)t1; - (void)t2; - while (spl > 0) { - int curspl = (spl < maxspl) ? spl : maxspl; - up2_.process_block(out, in, 1 * curspl); - in += curspl; - out += curspl; - spl -= curspl; - } + up2_.process_block(out, in, spl); } void process4x(const float *in, float *out, int spl, float *temp, int ntemp) { - int maxspl = ntemp / 4; - ASSERT(maxspl >= 0); + int maxspl = ntemp / 2; + ASSERT(maxspl > 0); float *t1 = temp; - float *t2 = temp + 2 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; up2_.process_block(t1, in, 1 * curspl); @@ -171,11 +163,9 @@ public: void process8x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 8; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 4 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; up2_.process_block(t1, in, 1 * curspl); @@ -189,11 +179,9 @@ public: void process16x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 16; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 8 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; up2_.process_block(t1, in, 1 * curspl); @@ -208,11 +196,9 @@ public: void process32x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 32; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 16 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; up2_.process_block(t1, in, 1 * curspl); @@ -228,11 +214,9 @@ public: void process64x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 64; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 32 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; up2_.process_block(t1, in, 1 * curspl); @@ -249,11 +233,9 @@ public: void process128x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 128; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 64 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; up2_.process_block(t1, in, 1 * curspl); @@ -302,7 +284,14 @@ public: } static int recommendedBuffer(int factor, int spl) { - return factor * spl; + switch (factor) { + case 2: + return 0; + case 4: + return 2 * spl; + default: + return factor * spl; + } } static bool canProcess(int factor) { @@ -352,30 +341,15 @@ public: break; } } - void process2x(const float *in, float *out, int spl, float *temp, int ntemp) + void process2x(const float *in, float *out, int spl, float * = nullptr, int = 0) { - int maxspl = ntemp / 2; - ASSERT(maxspl >= 0); - float *t1 = temp; - float *t2 = temp + 1 * maxspl; - (void)t1; - (void)t2; - while (spl > 0) { - int curspl = (spl < maxspl) ? spl : maxspl; - down2_.process_block(out, in, 1 * curspl); - in += curspl; - out += curspl; - spl -= curspl; - } + down2_.process_block(out, in, spl); } void process4x(const float *in, float *out, int spl, float *temp, int ntemp) { - int maxspl = ntemp / 4; - ASSERT(maxspl >= 0); + int maxspl = ntemp / 2; + ASSERT(maxspl > 0); float *t1 = temp; - float *t2 = temp + 2 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; down4_.process_block(t1, in, 2 * curspl); @@ -388,11 +362,9 @@ public: void process8x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 8; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 4 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; down8_.process_block(t1, in, 4 * curspl); @@ -406,11 +378,9 @@ public: void process16x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 16; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 8 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; down16_.process_block(t1, in, 8 * curspl); @@ -425,11 +395,9 @@ public: void process32x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 32; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 16 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; down32_.process_block(t1, in, 16 * curspl); @@ -445,11 +413,9 @@ public: void process64x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 64; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 32 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; down64_.process_block(t1, in, 32 * curspl); @@ -466,11 +432,9 @@ public: void process128x(const float *in, float *out, int spl, float *temp, int ntemp) { int maxspl = ntemp / 128; - ASSERT(maxspl >= 0); + ASSERT(maxspl > 0); float *t1 = temp; float *t2 = temp + 64 * maxspl; - (void)t1; - (void)t2; while (spl > 0) { int curspl = (spl < maxspl) ? spl : maxspl; down128_.process_block(t1, in, 64 * curspl); From 25dd348191372f91079834c91a8ab3c82c5276ed Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 02:27:46 +0100 Subject: [PATCH 277/668] Deduplication of hiir coefs in effects --- src/sfizz/effects/Compressor.cpp | 11 +++++------ src/sfizz/effects/Compressor.h | 2 -- src/sfizz/effects/Gate.cpp | 11 +++++------ src/sfizz/effects/Gate.h | 2 -- src/sfizz/effects/Limiter.cpp | 6 ++---- src/sfizz/effects/Limiter.h | 7 +++---- src/sfizz/effects/Lofi.cpp | 6 ++---- src/sfizz/effects/Lofi.h | 6 +++--- src/sfizz/effects/Rectify.cpp | 6 ++---- src/sfizz/effects/Rectify.h | 7 +++---- 10 files changed, 25 insertions(+), 39 deletions(-) diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index 8fffd680..e5a0c2e5 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -20,6 +20,7 @@ #include "Opcode.h" #include "AudioSpan.h" #include "MathHelpers.h" +#include "OversamplerHelpers.h" #include "absl/memory/memory.h" static constexpr int _oversampling = 2; @@ -35,8 +36,8 @@ namespace fx { float _inputGain { Default::compGain }; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; - hiir::Downsampler2xFpu<12> _downsampler2x[EffectChannels]; - hiir::Upsampler2xFpu<12> _upsampler2x[EffectChannels]; + hiir::Downsampler2x<12> _downsampler2x[EffectChannels]; + hiir::Upsampler2x<12> _upsampler2x[EffectChannels]; #define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \ float get_##ident(size_t i) const noexcept { return _compressor[i].var; } \ @@ -65,11 +66,9 @@ namespace fx { comp.instanceConstants(sampleRate); } - static constexpr double coefs2x[12] = { 0.036681502163648017, 0.13654762463195794, 0.27463175937945444, 0.42313861743656711, 0.56109869787919531, 0.67754004997416184, 0.76974183386322703, 0.83988962484963892, 0.89226081800387902, 0.9315419599631839, 0.96209454837808417, 0.98781637073289585 }; - for (unsigned c = 0; c < EffectChannels; ++c) { - impl._downsampler2x[c].set_coefs(coefs2x); - impl._upsampler2x[c].set_coefs(coefs2x); + impl._downsampler2x[c].set_coefs(OSCoeffs2x); + impl._upsampler2x[c].set_coefs(OSCoeffs2x); } clear(); diff --git a/src/sfizz/effects/Compressor.h b/src/sfizz/effects/Compressor.h index ed2b0e5d..531803a8 100644 --- a/src/sfizz/effects/Compressor.h +++ b/src/sfizz/effects/Compressor.h @@ -6,8 +6,6 @@ #pragma once #include "Effects.h" -#include "hiir/Downsampler2xFpu.h" -#include "hiir/Upsampler2xFpu.h" #include namespace sfz { diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index 7bbc158a..b97ffd4a 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -23,6 +23,7 @@ #include "Opcode.h" #include "AudioSpan.h" #include "MathHelpers.h" +#include "OversamplerHelpers.h" #include "absl/memory/memory.h" static constexpr int _oversampling = 2; @@ -38,8 +39,8 @@ namespace fx { float _inputGain = 1.0; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; - hiir::Downsampler2xFpu<12> _downsampler2x[EffectChannels]; - hiir::Upsampler2xFpu<12> _upsampler2x[EffectChannels]; + hiir::Downsampler2x<12> _downsampler2x[EffectChannels]; + hiir::Upsampler2x<12> _upsampler2x[EffectChannels]; #define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \ float get_##ident(size_t i) const noexcept { return _gate[i].var; } \ @@ -68,11 +69,9 @@ namespace fx { gate.instanceConstants(sampleRate); } - static constexpr double coefs2x[12] = { 0.036681502163648017, 0.13654762463195794, 0.27463175937945444, 0.42313861743656711, 0.56109869787919531, 0.67754004997416184, 0.76974183386322703, 0.83988962484963892, 0.89226081800387902, 0.9315419599631839, 0.96209454837808417, 0.98781637073289585 }; - for (unsigned c = 0; c < EffectChannels; ++c) { - impl._downsampler2x[c].set_coefs(coefs2x); - impl._upsampler2x[c].set_coefs(coefs2x); + impl._downsampler2x[c].set_coefs(OSCoeffs2x); + impl._upsampler2x[c].set_coefs(OSCoeffs2x); } clear(); diff --git a/src/sfizz/effects/Gate.h b/src/sfizz/effects/Gate.h index bfe3ccfd..c461b9e7 100644 --- a/src/sfizz/effects/Gate.h +++ b/src/sfizz/effects/Gate.h @@ -6,8 +6,6 @@ #pragma once #include "Effects.h" -#include "hiir/Downsampler2xFpu.h" -#include "hiir/Upsampler2xFpu.h" #include namespace sfz { diff --git a/src/sfizz/effects/Limiter.cpp b/src/sfizz/effects/Limiter.cpp index 9c28ce73..4560ebbd 100644 --- a/src/sfizz/effects/Limiter.cpp +++ b/src/sfizz/effects/Limiter.cpp @@ -36,11 +36,9 @@ namespace fx { _limiter->classInit(sampleRate); _limiter->instanceConstants(sampleRate); - static constexpr double coefs2x[12] = { 0.036681502163648017, 0.13654762463195794, 0.27463175937945444, 0.42313861743656711, 0.56109869787919531, 0.67754004997416184, 0.76974183386322703, 0.83988962484963892, 0.89226081800387902, 0.9315419599631839, 0.96209454837808417, 0.98781637073289585 }; - for (unsigned c = 0; c < EffectChannels; ++c) { - _downsampler2x[c].set_coefs(coefs2x); - _upsampler2x[c].set_coefs(coefs2x); + _downsampler2x[c].set_coefs(OSCoeffs2x); + _upsampler2x[c].set_coefs(OSCoeffs2x); } clear(); diff --git a/src/sfizz/effects/Limiter.h b/src/sfizz/effects/Limiter.h index 30737377..e32cc9a9 100644 --- a/src/sfizz/effects/Limiter.h +++ b/src/sfizz/effects/Limiter.h @@ -6,8 +6,7 @@ #pragma once #include "Effects.h" -#include "hiir/Downsampler2xFpu.h" -#include "hiir/Upsampler2xFpu.h" +#include "OversamplerHelpers.h" class faustLimiter; namespace sfz { @@ -50,8 +49,8 @@ namespace fx { private: std::unique_ptr _limiter; AudioBuffer _tempBuffer2x { 2, 2 * config::defaultSamplesPerBlock }; - hiir::Downsampler2xFpu<12> _downsampler2x[EffectChannels]; - hiir::Upsampler2xFpu<12> _upsampler2x[EffectChannels]; + hiir::Downsampler2x<12> _downsampler2x[EffectChannels]; + hiir::Upsampler2x<12> _upsampler2x[EffectChannels]; }; } // namespace fx diff --git a/src/sfizz/effects/Lofi.cpp b/src/sfizz/effects/Lofi.cpp index 24aaf772..591be3a9 100644 --- a/src/sfizz/effects/Lofi.cpp +++ b/src/sfizz/effects/Lofi.cpp @@ -101,8 +101,7 @@ namespace fx { { (void)sampleRate; - static constexpr double coefs2x[12] = { 0.036681502163648017, 0.13654762463195794, 0.27463175937945444, 0.42313861743656711, 0.56109869787919531, 0.67754004997416184, 0.76974183386322703, 0.83988962484963892, 0.89226081800387902, 0.9315419599631839, 0.96209454837808417, 0.98781637073289585 }; - fDownsampler2x.set_coefs(coefs2x); + fDownsampler2x.set_coefs(OSCoeffs2x); } void Lofi::Bitred::clear() @@ -153,8 +152,7 @@ namespace fx { { fSampleTime = 1.0f / static_cast(sampleRate); - static constexpr double coefs2x[12] = { 0.036681502163648017, 0.13654762463195794, 0.27463175937945444, 0.42313861743656711, 0.56109869787919531, 0.67754004997416184, 0.76974183386322703, 0.83988962484963892, 0.89226081800387902, 0.9315419599631839, 0.96209454837808417, 0.98781637073289585 }; - fDownsampler2x.set_coefs(coefs2x); + fDownsampler2x.set_coefs(OSCoeffs2x); } void Lofi::Decim::clear() diff --git a/src/sfizz/effects/Lofi.h b/src/sfizz/effects/Lofi.h index 9b97c6e3..54cfa12e 100644 --- a/src/sfizz/effects/Lofi.h +++ b/src/sfizz/effects/Lofi.h @@ -6,7 +6,7 @@ #pragma once #include "Effects.h" -#include "hiir/Downsampler2xFpu.h" +#include "OversamplerHelpers.h" namespace sfz { namespace fx { @@ -57,7 +57,7 @@ namespace fx { private: float fDepth = 0.0; float fLastValue = 0.0; - hiir::Downsampler2xFpu<12> fDownsampler2x; + hiir::Downsampler2x<12> fDownsampler2x; }; /// @@ -73,7 +73,7 @@ namespace fx { float fDepth = 0.0; float fPhase = 0.0; float fLastValue = 0.0; - hiir::Downsampler2xFpu<12> fDownsampler2x; + hiir::Downsampler2x<12> fDownsampler2x; }; /// diff --git a/src/sfizz/effects/Rectify.cpp b/src/sfizz/effects/Rectify.cpp index 5d25be46..dbc92997 100644 --- a/src/sfizz/effects/Rectify.cpp +++ b/src/sfizz/effects/Rectify.cpp @@ -28,11 +28,9 @@ namespace fx { { (void)sampleRate; - static constexpr double coefs2x[12] = { 0.036681502163648017, 0.13654762463195794, 0.27463175937945444, 0.42313861743656711, 0.56109869787919531, 0.67754004997416184, 0.76974183386322703, 0.83988962484963892, 0.89226081800387902, 0.9315419599631839, 0.96209454837808417, 0.98781637073289585 }; - for (unsigned c = 0; c < EffectChannels; ++c) { - _downsampler2x[c].set_coefs(coefs2x); - _upsampler2x[c].set_coefs(coefs2x); + _downsampler2x[c].set_coefs(OSCoeffs2x); + _upsampler2x[c].set_coefs(OSCoeffs2x); } } diff --git a/src/sfizz/effects/Rectify.h b/src/sfizz/effects/Rectify.h index b6c27a84..7497a7c7 100644 --- a/src/sfizz/effects/Rectify.h +++ b/src/sfizz/effects/Rectify.h @@ -6,8 +6,7 @@ #pragma once #include "Effects.h" -#include "hiir/Downsampler2xFpu.h" -#include "hiir/Upsampler2xFpu.h" +#include "OversamplerHelpers.h" namespace sfz { namespace fx { @@ -47,8 +46,8 @@ namespace fx { private: AudioBuffer _tempBuffer { 1, config::defaultSamplesPerBlock }; - hiir::Downsampler2xFpu<12> _downsampler2x[2]; - hiir::Upsampler2xFpu<12> _upsampler2x[2]; + hiir::Downsampler2x<12> _downsampler2x[2]; + hiir::Upsampler2x<12> _upsampler2x[2]; float _amount = 0; bool _full = false; From 5f93729b538ae44cfbd872f5560870d6eee13fa3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 02:33:48 +0100 Subject: [PATCH 278/668] Restore the license header --- src/sfizz/OversamplerHelpers.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sfizz/OversamplerHelpers.hxx b/src/sfizz/OversamplerHelpers.hxx index 8e1bef52..458cdd87 100644 --- a/src/sfizz/OversamplerHelpers.hxx +++ b/src/sfizz/OversamplerHelpers.hxx @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: BSD-2-Clause - - - - +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz //------------------------------------------------------------------------------ // This is generated by the Sfizz HIIR designer From d0b20459c9d0e7b2d4af5ca2e12778777ccc886e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 03:42:58 +0100 Subject: [PATCH 279/668] Hermite interpolator for oscillators --- src/sfizz/Wavetables.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sfizz/Wavetables.cpp b/src/sfizz/Wavetables.cpp index a5655ce6..179db945 100644 --- a/src/sfizz/Wavetables.cpp +++ b/src/sfizz/Wavetables.cpp @@ -155,10 +155,10 @@ void WavetableOscillator::process(float frequency, float detuneRatio, float* out processSingle(frequency, detuneRatio, output, nframes); break; case 2: - processSingle(frequency, detuneRatio, output, nframes); + processSingle(frequency, detuneRatio, output, nframes); break; case 3: - processDual(frequency, detuneRatio, output, nframes); + processDual(frequency, detuneRatio, output, nframes); break; } } @@ -175,10 +175,10 @@ void WavetableOscillator::processModulated(const float* frequencies, const float processModulatedSingle(frequencies, detuneRatios, output, nframes); break; case 2: - processModulatedSingle(frequencies, detuneRatios, output, nframes); + processModulatedSingle(frequencies, detuneRatios, output, nframes); break; case 3: - processModulatedDual(frequencies, detuneRatios, output, nframes); + processModulatedDual(frequencies, detuneRatios, output, nframes); break; } } From 7627f7c074a118e38bb6b78d2acd78f91542b0e3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 07:40:30 +0100 Subject: [PATCH 280/668] Have the file chooser automatically open SFZ dir --- plugins/editor/src/editor/EditIds.h | 1 + plugins/editor/src/editor/Editor.cpp | 46 ++++++++++++++++++++++------ plugins/vst/SfizzVstEditor.cpp | 1 + 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/plugins/editor/src/editor/EditIds.h b/plugins/editor/src/editor/EditIds.h index d9b43957..869d1c44 100644 --- a/plugins/editor/src/editor/EditIds.h +++ b/plugins/editor/src/editor/EditIds.h @@ -20,6 +20,7 @@ enum class EditId : int { StretchTuning, CanEditUserFilesDir, UserFilesDir, + FallbackFilesDir, // Controller0, ControllerLast = Controller0 + sfz::config::numCCs - 1, diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 0b5c6e5a..5afaa804 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -42,6 +42,8 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { std::string currentSfzFile_; std::string currentScalaFile_; + std::string userFilesDir_; + std::string fallbackFilesDir_; enum { kPanelGeneral, @@ -137,6 +139,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void chooseScalaFile(); void changeScalaFile(const std::string& filePath); void chooseUserFilesDir(); + std::string getFileChooserInitialDir(const std::string& previousFilePath) const; static bool scanDirectoryFiles(const fs::path& dirPath, std::function filter, std::vector& fileNames); @@ -319,7 +322,13 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) } case EditId::UserFilesDir: { - updateUserFilesDirLabel(v.to_string()); + userFilesDir_ = v.to_string(); + updateUserFilesDirLabel(userFilesDir_); + break; + } + case EditId::FallbackFilesDir: + { + fallbackFilesDir_ = v.to_string(); break; } case EditId::UINumCurves: @@ -891,10 +900,10 @@ void Editor::Impl::chooseSfzFile() fs->setTitle("Load SFZ file"); fs->setDefaultExtension(CFileExtension("SFZ", "sfz")); - if (!currentSfzFile_.empty()) { - std::string initialDir = fs::path(currentSfzFile_).parent_path().u8string() + '/'; + + std::string initialDir = getFileChooserInitialDir(currentSfzFile_); + if (!initialDir.empty()) fs->setInitialDirectory(initialDir.c_str()); - } if (fs->runModal()) { UTF8StringPtr file = fs->getSelectedFile(0); @@ -969,10 +978,10 @@ void Editor::Impl::chooseScalaFile() fs->setTitle("Load Scala file"); fs->setDefaultExtension(CFileExtension("SCL", "scl")); - if (!currentScalaFile_.empty()) { - std::string initialDir = fs::path(currentScalaFile_).parent_path().u8string() + '/'; + + std::string initialDir = getFileChooserInitialDir(currentScalaFile_); + if (!initialDir.empty()) fs->setInitialDirectory(initialDir.c_str()); - } if (fs->runModal()) { UTF8StringPtr file = fs->getSelectedFile(0); @@ -998,12 +1007,31 @@ void Editor::Impl::chooseUserFilesDir() if (fs->runModal()) { UTF8StringPtr dir = fs->getSelectedFile(0); if (dir) { - updateUserFilesDirLabel(dir); - ctrl_->uiSendValue(EditId::UserFilesDir, std::string(dir)); + userFilesDir_ = std::string(dir); + updateUserFilesDirLabel(userFilesDir_); + ctrl_->uiSendValue(EditId::UserFilesDir, userFilesDir_); } } } +std::string Editor::Impl::getFileChooserInitialDir(const std::string& previousFilePath) const +{ + fs::path initialPath; + + if (!previousFilePath.empty()) + initialPath = fs::u8path(previousFilePath).parent_path(); + else if (!userFilesDir_.empty()) + initialPath = fs::u8path(userFilesDir_); + else if (!fallbackFilesDir_.empty()) + initialPath = fs::u8path(fallbackFilesDir_); + + std::string initialDir = initialPath.u8string(); + if (!initialDir.empty()) + initialDir.push_back('/'); + + return initialDir; +} + bool Editor::Impl::scanDirectoryFiles(const fs::path& dirPath, std::function filter, std::vector& fileNames) { std::error_code ec; diff --git a/plugins/vst/SfizzVstEditor.cpp b/plugins/vst/SfizzVstEditor.cpp index d5788b48..8345c274 100644 --- a/plugins/vst/SfizzVstEditor.cpp +++ b/plugins/vst/SfizzVstEditor.cpp @@ -91,6 +91,7 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p absl::optional userFilesDir = SfizzPaths::getSfzConfigDefaultPath(); uiReceiveValue(EditId::CanEditUserFilesDir, 1); uiReceiveValue(EditId::UserFilesDir, userFilesDir.value_or(fs::path()).u8string()); + uiReceiveValue(EditId::FallbackFilesDir, SfizzPaths::getSfzFallbackDefaultPath().u8string()); return true; } From bd1326004654191b1d60eade4a179b75a20a3523 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 08:06:06 +0100 Subject: [PATCH 281/668] Add native helper to open a directory --- plugins/editor/src/editor/NativeHelpers.cpp | 29 +++++++++++++++++++-- plugins/editor/src/editor/NativeHelpers.h | 1 + plugins/editor/src/editor/NativeHelpers.mm | 22 +++++++++------- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/plugins/editor/src/editor/NativeHelpers.cpp b/plugins/editor/src/editor/NativeHelpers.cpp index ab760d73..a8cbb255 100644 --- a/plugins/editor/src/editor/NativeHelpers.cpp +++ b/plugins/editor/src/editor/NativeHelpers.cpp @@ -27,14 +27,29 @@ bool openFileInExternalEditor(const char *filename) return ShellExecuteExW(&info); } + +bool openDirectoryInExplorer(const char *filename) +{ + std::wstring path = fs::u8path(filename).wstring(); + + SHELLEXECUTEINFOW info; + memset(&info, 0, sizeof(info)); + + info.cbSize = sizeof(info); + info.lpVerb = L"explore"; + info.lpFile = path.c_str(); + info.nShow = SW_SHOW; + + return ShellExecuteExW(&info); +} #elif defined(__APPLE__) // implemented in NativeHelpers.mm #else #include -bool openFileInExternalEditor(const char *filename) +static bool openFileByMimeType(const char *filename, const char *mimetype) { - GAppInfo* appinfo = g_app_info_get_default_for_type("text/plain", FALSE); + GAppInfo* appinfo = g_app_info_get_default_for_type(mimetype, FALSE); if (!appinfo) return 1; @@ -47,4 +62,14 @@ bool openFileInExternalEditor(const char *filename) g_object_unref(appinfo); return success == TRUE; } + +bool openFileInExternalEditor(const char *filename) +{ + return openFileByMimeType(filename, "text/plain"); +} + +bool openDirectoryInExplorer(const char *filename) +{ + return openFileByMimeType(filename, "inode/directory"); +} #endif diff --git a/plugins/editor/src/editor/NativeHelpers.h b/plugins/editor/src/editor/NativeHelpers.h index b9c29bb6..3ca310f7 100644 --- a/plugins/editor/src/editor/NativeHelpers.h +++ b/plugins/editor/src/editor/NativeHelpers.h @@ -7,3 +7,4 @@ #pragma once bool openFileInExternalEditor(const char *filename); +bool openDirectoryInExplorer(const char *filename); diff --git a/plugins/editor/src/editor/NativeHelpers.mm b/plugins/editor/src/editor/NativeHelpers.mm index 9cb8cd28..7fea74e8 100644 --- a/plugins/editor/src/editor/NativeHelpers.mm +++ b/plugins/editor/src/editor/NativeHelpers.mm @@ -11,20 +11,24 @@ #import #import -bool openFileInExternalEditor(const char *fileNameUTF8) +static bool openFileWithApplication(const char *fileName, NSString *application) { - BOOL wasOpened = NO; + NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; + NSString* fileNameNs = [NSString stringWithUTF8String:fileName]; + return [workspace openFile:fileNameNs withApplication:application] == YES; +} +bool openFileInExternalEditor(const char *fileName) +{ NSURL* applicationURL = (__bridge_transfer NSURL*)LSCopyDefaultApplicationURLForContentType( kUTTypePlainText, kLSRolesEditor, nil); - if (!applicationURL) + if (!applicationURL || ![applicationURL isFileURL]) return false; - if ([applicationURL isFileURL]) { - NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; - NSString* fileName = [NSString stringWithUTF8String:fileNameUTF8]; - wasOpened = [workspace openFile:fileName withApplication:[applicationURL path]]; - } + return openFileWithApplication(fileName, [applicationURL path]); +} - return wasOpened == YES; +bool openDirectoryInExplorer(const char *fileName) +{ + return openFileWithApplication(fileName, @"Finder"); } #endif From 2dbfbf3148caf06a14c1c40b4a21a38c282ca7f3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 08:11:47 +0100 Subject: [PATCH 282/668] Add editor action to open SFZ dir --- plugins/editor/src/editor/Editor.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 5afaa804..281e1796 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -58,6 +58,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { enum { kTagLoadSfzFile, kTagEditSfzFile, + kTagOpenSfzFolder, kTagPreviousSfzFile, kTagNextSfzFile, kTagFileOperations, @@ -848,6 +849,7 @@ void Editor::Impl::createFrameContents() if (SActionMenu* menu = fileOperationsMenu_) { menu->addEntry("Load file", kTagLoadSfzFile); menu->addEntry("Edit file", kTagEditSfzFile); + menu->addEntry("Open SFZ folder", kTagOpenSfzFolder); } if (SPiano* piano = piano_) { @@ -1320,6 +1322,16 @@ void Editor::Impl::valueChanged(CControl* ctl) openFileInExternalEditor(currentSfzFile_.c_str()); break; + case kTagOpenSfzFolder: + if (value != 1) + break; + + if (!userFilesDir_.empty()) + openDirectoryInExplorer(userFilesDir_.c_str()); + else if (!fallbackFilesDir_.empty()) + openDirectoryInExplorer(fallbackFilesDir_.c_str()); + break; + case kTagPreviousSfzFile: if (value != 1) break; From 8de978df9130a72b954846df86c41bf463c43e7c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 09:11:16 +0100 Subject: [PATCH 283/668] Add native helper for the question dialog --- plugins/editor/src/editor/NativeHelpers.cpp | 77 ++++++++++++++++++++- plugins/editor/src/editor/NativeHelpers.h | 1 + plugins/editor/src/editor/NativeHelpers.mm | 10 +++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/plugins/editor/src/editor/NativeHelpers.cpp b/plugins/editor/src/editor/NativeHelpers.cpp index a8cbb255..0a3ac516 100644 --- a/plugins/editor/src/editor/NativeHelpers.cpp +++ b/plugins/editor/src/editor/NativeHelpers.cpp @@ -11,9 +11,20 @@ #include #include +static WCHAR *stringToWideChar(const char *str, int strCch = -1) +{ + unsigned strSize = MultiByteToWideChar(CP_UTF8, 0, str, strCch, nullptr, 0); + if (strSize == 0) + return {}; + std::unique_ptr strW(new WCHAR[strSize]); + if (MultiByteToWideChar(CP_UTF8, 0, str, strCch, strW.get(), strSize) == 0) + return {}; + return strW.release(); +} + bool openFileInExternalEditor(const char *filename) { - std::wstring path = fs::u8path(filename).wstring(); + std::wstring path = stringToWideChar(filename); SHELLEXECUTEINFOW info; memset(&info, 0, sizeof(info)); @@ -30,7 +41,7 @@ bool openFileInExternalEditor(const char *filename) bool openDirectoryInExplorer(const char *filename) { - std::wstring path = fs::u8path(filename).wstring(); + std::wstring path = stringToWideChar(filename); SHELLEXECUTEINFOW info; memset(&info, 0, sizeof(info)); @@ -42,10 +53,23 @@ bool openDirectoryInExplorer(const char *filename) return ShellExecuteExW(&info); } + +bool askQuestion(const char *text) +{ + int ret = MessageBoxW(nullptr, stringToWideChar(text), L"Question", MB_YESNO); + return ret == IDYES; +} #elif defined(__APPLE__) // implemented in NativeHelpers.mm #else #include +#include +#include +#include +#include +#include +#include +extern "C" { extern char **environ; } static bool openFileByMimeType(const char *filename, const char *mimetype) { @@ -72,4 +96,53 @@ bool openDirectoryInExplorer(const char *filename) { return openFileByMimeType(filename, "inode/directory"); } + +static std::vector createForkEnviron() +{ + std::vector newEnv; + newEnv.reserve(256); + for (char **envp = environ; *envp; ++envp) { + // ensure the process will link with system libraries, + // and not these from the Ardour bundle. + if (strncmp(*envp, "LD_LIBRARY_PATH=", 16) == 0) + continue; + newEnv.push_back(*envp); + } + newEnv.push_back(nullptr); + return newEnv; +} + +bool askQuestion(const char *text) +{ + char *argv[] = { + const_cast("/usr/bin/zenity"), + const_cast("--question"), + const_cast("--text"), + const_cast(text), + nullptr, + }; + + std::vector newEnv = createForkEnviron(); + char **envp = newEnv.data(); + + pid_t forkPid = vfork(); + if (forkPid == -1) + return false; + + if (forkPid == 0) { + execve(argv[0], argv, envp); + _exit(1); + } + + int wret; + int wstatus; + do { + wret = waitpid(forkPid, &wstatus, 0); + } while (wret == -1 && errno == EINTR); + + if (wret == -1 || !WIFEXITED(wstatus)) + return false; + + return WEXITSTATUS(wstatus) == 0; +} #endif diff --git a/plugins/editor/src/editor/NativeHelpers.h b/plugins/editor/src/editor/NativeHelpers.h index 3ca310f7..9ccb5410 100644 --- a/plugins/editor/src/editor/NativeHelpers.h +++ b/plugins/editor/src/editor/NativeHelpers.h @@ -8,3 +8,4 @@ bool openFileInExternalEditor(const char *filename); bool openDirectoryInExplorer(const char *filename); +bool askQuestion(const char *text); diff --git a/plugins/editor/src/editor/NativeHelpers.mm b/plugins/editor/src/editor/NativeHelpers.mm index 7fea74e8..56c1143d 100644 --- a/plugins/editor/src/editor/NativeHelpers.mm +++ b/plugins/editor/src/editor/NativeHelpers.mm @@ -31,4 +31,14 @@ bool openDirectoryInExplorer(const char *fileName) { return openFileWithApplication(fileName, @"Finder"); } + +bool askQuestion(const char *text) +{ + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:[NSString stringWithUTF8String:text]]; + [alert addButtonWithTitle:@"OK"]; + [alert addButtonWithTitle:@"Cancel"]; + NSInteger button = [alert runModal]; + return button == NSAlertFirstButtonReturn; +} #endif From 36279561a47de1350d719f10d7f6e6092bd05351 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 10:18:25 +0100 Subject: [PATCH 284/668] Add action for creating new SFZ --- plugins/editor/src/editor/Editor.cpp | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 281e1796..f56b7f0a 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { enum { kTagLoadSfzFile, kTagEditSfzFile, + kTagCreateNewSfzFile, kTagOpenSfzFolder, kTagPreviousSfzFile, kTagNextSfzFile, @@ -135,6 +137,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { } void chooseSfzFile(); + void createNewSfzFile(); void changeSfzFile(const std::string& filePath); void changeToNextSfzFile(long offset); void chooseScalaFile(); @@ -849,6 +852,7 @@ void Editor::Impl::createFrameContents() if (SActionMenu* menu = fileOperationsMenu_) { menu->addEntry("Load file", kTagLoadSfzFile); menu->addEntry("Edit file", kTagEditSfzFile); + menu->addEntry("Create new file", kTagCreateNewSfzFile); menu->addEntry("Open SFZ folder", kTagOpenSfzFolder); } @@ -914,6 +918,44 @@ void Editor::Impl::chooseSfzFile() } } +/// +static const char defaultSfzText[] = + "sample=*sine" "\n" + "ampeg_attack=0.02 ampeg_release=0.1" "\n"; + +static void createDefaultSfzFileIfNotExisting(const fs::path& path) +{ + if (!fs::exists(path)) + fs::ofstream { path } << defaultSfzText; +} + +/// +void Editor::Impl::createNewSfzFile() +{ + SharedPointer fs = owned(CNewFileSelector::create(frame_, CNewFileSelector::kSelectSaveFile)); + + fs->setTitle("Create SFZ file"); + fs->setDefaultExtension(CFileExtension("SFZ", "sfz")); + + std::string initialDir = getFileChooserInitialDir(currentSfzFile_); + if (!initialDir.empty()) + fs->setInitialDirectory(initialDir.c_str()); + + if (fs->runModal()) { + UTF8StringPtr file = fs->getSelectedFile(0); + std::string fileStr; + if (file && !absl::EndsWithIgnoreCase(file, ".sfz")) { + fileStr = std::string(file) + ".sfz"; + file = fileStr.c_str(); + } + if (file) { + createDefaultSfzFileIfNotExisting(fs::u8path(file)); + changeSfzFile(file); + openFileInExternalEditor(file); + } + } +} + void Editor::Impl::changeSfzFile(const std::string& filePath) { ctrl_->uiSendValue(EditId::SfzFile, filePath); @@ -1322,6 +1364,13 @@ void Editor::Impl::valueChanged(CControl* ctl) openFileInExternalEditor(currentSfzFile_.c_str()); break; + case kTagCreateNewSfzFile: + if (value != 1) + break; + + createNewSfzFile(); + break; + case kTagOpenSfzFolder: if (value != 1) break; From 1fdf900725cde37f1836d5e88d7085f1c55ebb2d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 19:15:49 +0100 Subject: [PATCH 285/668] Fix release asserts never enabled in parser/messaging --- src/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 616e401e..b98cf69b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -219,6 +219,9 @@ target_include_directories(sfizz_parser PUBLIC sfizz) target_link_libraries(sfizz_parser PUBLIC sfizz::filesystem sfizz::simde absl::strings PRIVATE absl::flat_hash_map) +if(SFIZZ_RELEASE_ASSERTS) + target_compile_definitions(sfizz_parser PUBLIC "SFIZZ_ENABLE_RELEASE_ASSERT=1") +endif() # OSC messaging library set(SFIZZ_MESSAGING_HEADERS @@ -235,6 +238,9 @@ target_sources(sfizz_messaging PRIVATE ${SFIZZ_MESSAGING_HEADERS} ${SFIZZ_MESSAGING_SOURCES}) target_include_directories(sfizz_messaging PUBLIC ".") target_link_libraries(sfizz_messaging PUBLIC absl::strings) +if(SFIZZ_RELEASE_ASSERTS) + target_compile_definitions(sfizz_messaging PUBLIC "SFIZZ_ENABLE_RELEASE_ASSERT=1") +endif() # Sfizz spinlock mutex add_library(sfizz_spin_mutex STATIC From 10ffad5d4b4f3cd641e2145e4d3a33ffbfc6235a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 19:16:27 +0100 Subject: [PATCH 286/668] Rename Opcode member "opcode" to "name" --- devtools/Preprocessor.cpp | 4 ++-- src/sfizz/Opcode.cpp | 31 ++++++++++++++++--------------- src/sfizz/Opcode.h | 2 +- src/sfizz/OpcodeCleanup.cpp | 2 +- src/sfizz/OpcodeCleanup.re | 2 +- src/sfizz/Synth.cpp | 6 +++--- tests/OpcodeT.cpp | 36 ++++++++++++++++++------------------ tests/ParsingT.cpp | 6 +++--- 8 files changed, 45 insertions(+), 44 deletions(-) diff --git a/devtools/Preprocessor.cpp b/devtools/Preprocessor.cpp index b6b96036..43ca8047 100644 --- a/devtools/Preprocessor.cpp +++ b/devtools/Preprocessor.cpp @@ -39,13 +39,13 @@ protected: std::cout << '\n'; std::cout << '<' << header << '>' << '\n'; for (const sfz::Opcode& opc : opcodes) - std::cout << opc.opcode << '=' << opc.value << '\n'; + std::cout << opc.name << '=' << opc.value << '\n'; } else if (g_mode == OutputXML) { pugi::xml_node block_node = g_xml_doc.append_child(header.c_str()); for (const sfz::Opcode& opc : opcodes) { pugi::xml_node opcode_node = block_node.append_child("opcode"); - opcode_node.append_attribute("name").set_value(opc.opcode.c_str()); + opcode_node.append_attribute("name").set_value(opc.name.c_str()); opcode_node.append_attribute("value").set_value(opc.value.c_str()); } } diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 1628f292..2c47e882 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -7,6 +7,7 @@ #include "Opcode.h" #include "LFODescription.h" #include "StringViewHelpers.h" +#include "Debug.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" @@ -17,31 +18,31 @@ namespace sfz { Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue) - : opcode(trim(inputOpcode)) + : name(trim(inputOpcode)) , value(trim(inputValue)) , category(identifyCategory(inputOpcode)) { size_t nextCharIndex { 0 }; int parameterPosition { 0 }; - auto nextNumIndex = opcode.find_first_of("1234567890"); - while (nextNumIndex != opcode.npos) { + auto nextNumIndex = name.find_first_of("1234567890"); + while (nextNumIndex != name.npos) { const auto numLetters = nextNumIndex - nextCharIndex; parameterPosition += numLetters; - lettersOnlyHash = hashNoAmpersand(opcode.substr(nextCharIndex, numLetters), lettersOnlyHash); - nextCharIndex = opcode.find_first_not_of("1234567890", nextNumIndex); + lettersOnlyHash = hashNoAmpersand(name.substr(nextCharIndex, numLetters), lettersOnlyHash); + nextCharIndex = name.find_first_not_of("1234567890", nextNumIndex); uint32_t returnedValue; - const auto numDigits = (nextCharIndex == opcode.npos) ? opcode.npos : nextCharIndex - nextNumIndex; - if (absl::SimpleAtoi(opcode.substr(nextNumIndex, numDigits), &returnedValue)) { + const auto numDigits = (nextCharIndex == name.npos) ? name.npos : nextCharIndex - nextNumIndex; + if (absl::SimpleAtoi(name.substr(nextNumIndex, numDigits), &returnedValue)) { lettersOnlyHash = hash("&", lettersOnlyHash); parameters.push_back(returnedValue); } - nextNumIndex = opcode.find_first_of("1234567890", nextCharIndex); + nextNumIndex = name.find_first_of("1234567890", nextCharIndex); } - if (nextCharIndex != opcode.npos) - lettersOnlyHash = hashNoAmpersand(opcode.substr(nextCharIndex), lettersOnlyHash); + if (nextCharIndex != name.npos) + lettersOnlyHash = hashNoAmpersand(name.substr(nextCharIndex), lettersOnlyHash); } static absl::string_view extractBackInteger(absl::string_view opcodeName) @@ -54,7 +55,7 @@ static absl::string_view extractBackInteger(absl::string_view opcodeName) std::string Opcode::getDerivedName(OpcodeCategory newCategory, unsigned number) const { - std::string derivedName(opcode); + std::string derivedName(name); switch (category) { case kOpcodeNormal: @@ -65,8 +66,8 @@ std::string Opcode::getDerivedName(OpcodeCategory newCategory, unsigned number) case kOpcodeSmoothCcN: { // when the input is cc, first delete the suffix `_*cc` - size_t pos = opcode.rfind('_'); - assert(pos != opcode.npos); + size_t pos = name.rfind('_'); + ASSERT(pos != name.npos); derivedName.resize(pos); } break; @@ -75,7 +76,7 @@ std::string Opcode::getDerivedName(OpcodeCategory newCategory, unsigned number) // helper to extract the cc number optionally if the next part needs it auto ccNumberSuffix = [this, number]() -> std::string { return (number != ~0u) ? std::to_string(number) : - std::string(extractBackInteger(opcode)); + std::string(extractBackInteger(name)); }; switch (newCategory) { @@ -448,5 +449,5 @@ absl::optional Opcode::readOptional(OpcodeSpec spec) const std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode) { - return os << opcode.opcode << '=' << '"' << opcode.value << '"'; + return os << opcode.name << '=' << '"' << opcode.value << '"'; } diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index 314e64f0..ad4d4acc 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -66,7 +66,7 @@ enum OpcodeScope { struct Opcode { Opcode() = delete; Opcode(absl::string_view inputOpcode, absl::string_view inputValue); - std::string opcode {}; + std::string name {}; std::string value {}; uint64_t lettersOnlyHash { Fnv1aBasis }; // This is to handle the integer parameters of some opcodes diff --git a/src/sfizz/OpcodeCleanup.cpp b/src/sfizz/OpcodeCleanup.cpp index 28c4aad8..b5945440 100644 --- a/src/sfizz/OpcodeCleanup.cpp +++ b/src/sfizz/OpcodeCleanup.cpp @@ -2643,7 +2643,7 @@ end_control: Opcode Opcode::cleanUp(OpcodeScope scope) const { - return Opcode(cleanUpOpcodeName(opcode, scope), value); + return Opcode(cleanUpOpcodeName(name, scope), value); } } // namespace sfz diff --git a/src/sfizz/OpcodeCleanup.re b/src/sfizz/OpcodeCleanup.re index b2906b6b..36d933e2 100644 --- a/src/sfizz/OpcodeCleanup.re +++ b/src/sfizz/OpcodeCleanup.re @@ -237,7 +237,7 @@ end_control: Opcode Opcode::cleanUp(OpcodeScope scope) const { - return Opcode(cleanUpOpcodeName(opcode, scope), value); + return Opcode(cleanUpOpcodeName(name, scope), value); } } // namespace sfz diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b359601f..c43302b7 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -142,13 +142,13 @@ void Synth::Impl::buildRegion(const std::vector& regionOpcodes) // auto parseOpcodes = [&](const std::vector& opcodes) { for (auto& opcode : opcodes) { - const auto unknown = absl::c_find_if(unknownOpcodes_, [&](absl::string_view sv) { return sv.compare(opcode.opcode) == 0; }); + const auto unknown = absl::c_find_if(unknownOpcodes_, [&](absl::string_view sv) { return sv.compare(opcode.name) == 0; }); if (unknown != unknownOpcodes_.end()) { continue; } if (!lastRegion->parseOpcode(opcode)) - unknownOpcodes_.emplace_back(opcode.opcode); + unknownOpcodes_.emplace_back(opcode.name); } }; @@ -405,7 +405,7 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) break; default: // Unsupported control opcode - DBG("Unsupported control opcode: " << member.opcode); + DBG("Unsupported control opcode: " << member.name); } } } diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 20ce6a24..abdac3d6 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -14,7 +14,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction") { Opcode opcode { "sample", "dummy" }; - REQUIRE(opcode.opcode == "sample"); + REQUIRE(opcode.name == "sample"); REQUIRE(opcode.lettersOnlyHash == hash("sample")); REQUIRE(opcode.parameters.empty()); REQUIRE(opcode.value == "dummy"); @@ -23,7 +23,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with underscore") { Opcode opcode { "sample_underscore", "dummy" }; - REQUIRE(opcode.opcode == "sample_underscore"); + REQUIRE(opcode.name == "sample_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore")); REQUIRE(opcode.parameters.empty()); REQUIRE(opcode.value == "dummy"); @@ -32,7 +32,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with ampersand") { Opcode opcode { "sample&_ampersand", "dummy" }; - REQUIRE(opcode.opcode == "sample&_ampersand"); + REQUIRE(opcode.name == "sample&_ampersand"); REQUIRE(opcode.lettersOnlyHash == hash("sample_ampersand")); REQUIRE(opcode.parameters.empty()); REQUIRE(opcode.value == "dummy"); @@ -41,7 +41,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with multiple ampersands") { Opcode opcode { "&sample&_ampersand&", "dummy" }; - REQUIRE(opcode.opcode == "&sample&_ampersand&"); + REQUIRE(opcode.name == "&sample&_ampersand&"); REQUIRE(opcode.lettersOnlyHash == hash("sample_ampersand")); REQUIRE(opcode.parameters.empty()); REQUIRE(opcode.value == "dummy"); @@ -50,7 +50,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode") { Opcode opcode { "sample123", "dummy" }; - REQUIRE(opcode.opcode == "sample123"); + REQUIRE(opcode.name == "sample123"); REQUIRE(opcode.lettersOnlyHash == hash("sample&")); REQUIRE(opcode.value == "dummy"); REQUIRE(opcode.parameters.size() == 1); @@ -60,7 +60,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode with ampersand") { Opcode opcode { "sample&123", "dummy" }; - REQUIRE(opcode.opcode == "sample&123"); + REQUIRE(opcode.name == "sample&123"); REQUIRE(opcode.lettersOnlyHash == hash("sample&")); REQUIRE(opcode.value == "dummy"); REQUIRE(opcode.parameters.size() == 1); @@ -70,7 +70,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode with underscore") { Opcode opcode { "sample_underscore123", "dummy" }; - REQUIRE(opcode.opcode == "sample_underscore123"); + REQUIRE(opcode.name == "sample_underscore123"); REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore&")); REQUIRE(opcode.value == "dummy"); REQUIRE(opcode.parameters == std::vector({ 123 })); @@ -79,7 +79,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode") { Opcode opcode { "sample1_underscore", "dummy" }; - REQUIRE(opcode.opcode == "sample1_underscore"); + REQUIRE(opcode.name == "sample1_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_underscore")); REQUIRE(opcode.value == "dummy"); REQUIRE(opcode.parameters == std::vector({ 1 })); @@ -88,7 +88,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode") { Opcode opcode { "sample123_underscore", "dummy" }; - REQUIRE(opcode.opcode == "sample123_underscore"); + REQUIRE(opcode.name == "sample123_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_underscore")); REQUIRE(opcode.value == "dummy"); REQUIRE(opcode.parameters.size() == 1); @@ -98,7 +98,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode twice") { Opcode opcode { "sample123_double44_underscore", "dummy" }; - REQUIRE(opcode.opcode == "sample123_double44_underscore"); + REQUIRE(opcode.name == "sample123_double44_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_double&_underscore")); REQUIRE(opcode.value == "dummy"); REQUIRE(opcode.parameters.size() == 2); @@ -110,7 +110,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode twice, with a back parameter") { Opcode opcode { "sample123_double44_underscore23", "dummy" }; - REQUIRE(opcode.opcode == "sample123_double44_underscore23"); + REQUIRE(opcode.name == "sample123_double44_underscore23"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_double&_underscore&")); REQUIRE(opcode.value == "dummy"); REQUIRE(opcode.parameters.size() == 3); @@ -198,8 +198,8 @@ TEST_CASE("[Opcode] Normalization") { // *_ccN - REQUIRE(Opcode("foo_cc7", "").cleanUp(kOpcodeScopeRegion).opcode == "foo_oncc7"); - REQUIRE(Opcode("foo_cc7", "").cleanUp(kOpcodeScopeControl).opcode == "foo_cc7"); + REQUIRE(Opcode("foo_cc7", "").cleanUp(kOpcodeScopeRegion).name == "foo_oncc7"); + REQUIRE(Opcode("foo_cc7", "").cleanUp(kOpcodeScopeControl).name == "foo_cc7"); // @@ -275,8 +275,8 @@ TEST_CASE("[Opcode] Normalization") for (auto pair : regionSpecific) { absl::string_view input = pair.first; absl::string_view expected = pair.second; - REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeRegion).opcode == expected); - REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeGeneric).opcode == input); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeRegion).name == expected); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeGeneric).name == input); } // @@ -289,13 +289,13 @@ TEST_CASE("[Opcode] Normalization") for (auto pair : controlSpecific) { absl::string_view input = pair.first; absl::string_view expected = pair.second; - REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeControl).opcode == expected); - REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeGeneric).opcode == input); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeControl).name == expected); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeGeneric).name == input); } // case - REQUIRE(Opcode("SaMpLe", "").cleanUp(kOpcodeScopeRegion).opcode == "sample"); + REQUIRE(Opcode("SaMpLe", "").cleanUp(kOpcodeScopeRegion).name == "sample"); } TEST_CASE("[Opcode] opcode read (uint8_t)") diff --git a/tests/ParsingT.cpp b/tests/ParsingT.cpp index ce35830d..99afbefd 100644 --- a/tests/ParsingT.cpp +++ b/tests/ParsingT.cpp @@ -95,7 +95,7 @@ TEST_CASE("[Parsing] Empty2") namespace sfz{ bool operator==(const Opcode& lhs, const Opcode& rhs) { - return (lhs.opcode == rhs.opcode) && (lhs.value == rhs.value); + return (lhs.name == rhs.name) && (lhs.value == rhs.value); } } @@ -142,10 +142,10 @@ void memberTestNew(absl::string_view member, absl::string_view opcode, absl::str REQUIRE(mock.fullBlockHeaders.size() == 1); REQUIRE(mock.fullBlockMembers.size() == 1); REQUIRE(mock.headers[0] == "region"); - REQUIRE(mock.opcodes[0].opcode == opcode); + REQUIRE(mock.opcodes[0].name == opcode); REQUIRE(mock.opcodes[0].value == value); REQUIRE(mock.fullBlockHeaders[0] == "region"); - REQUIRE(mock.fullBlockMembers[0][0].opcode == opcode); + REQUIRE(mock.fullBlockMembers[0][0].name == opcode); REQUIRE(mock.fullBlockMembers[0][0].value == value); } From bf9ec425bb1b066aa9a2fe14ff88c5608eac25c8 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 22 Feb 2021 19:57:50 +0100 Subject: [PATCH 287/668] Send key ranges to editor --- plugins/editor/src/editor/Editor.cpp | 14 ++++++++++---- src/sfizz/Synth.cpp | 10 ++++++++++ src/sfizz/SynthMessaging.cpp | 8 ++++++++ src/sfizz/SynthPrivate.h | 1 + 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index f56b7f0a..fa0bb186 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -219,7 +219,8 @@ void Editor::open(CFrame& frame) impl.frame_ = &frame; frame.addView(impl.mainView_.get()); - // request the whole CC information + // request the whole Key and CC information + impl.sendQueuedOSC("/key/slots", "", nullptr); impl.sendQueuedOSC("/cc/slots", "", nullptr); } @@ -244,7 +245,8 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) currentSfzFile_ = value; updateSfzFileLabel(value); - // request the whole CC information + // request the whole Key and CC information + sendQueuedOSC("/key/slots", "", nullptr); sendQueuedOSC("/cc/slots", "", nullptr); } break; @@ -390,7 +392,10 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi { unsigned indices[8]; - if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) { + if (Messages::matchOSC("/key/slots", path, indices) && !strcmp(sig, "b")) { + // TODO(jpc) key ranges + } + else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) { const uint8_t* bitChunks = args[0].b->data; uint32_t byteSize = args[0].b->size; @@ -962,7 +967,8 @@ void Editor::Impl::changeSfzFile(const std::string& filePath) currentSfzFile_ = filePath; updateSfzFileLabel(filePath); - // request the whole CC information + // request the whole Key and CC information + sendQueuedOSC("/key/slots", "", nullptr); sendQueuedOSC("/cc/slots", "", nullptr); } diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index c43302b7..c2f73319 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -249,6 +249,7 @@ void Synth::Impl::clear() currentUsedCCs_.clear(); changedCCsThisCycle_.clear(); keyLabels_.clear(); + keySlots_.clear(); keyswitchLabels_.clear(); globalOpcodes_.clear(); masterOpcodes_.clear(); @@ -735,6 +736,15 @@ void Synth::Impl::finalizeSfzLoad() // cache the set of used CCs for future access currentUsedCCs_ = collectAllUsedCCs(); + + // cache the set of keys assigned + for (const RegionPtr& regionPtr : regions_) { + Range keyRange = regionPtr->keyRange; + unsigned loKey = keyRange.getStart(); + unsigned hiKey = keyRange.getEnd(); + for (unsigned key = loKey; key <= hiKey; ++key) + keySlots_.set(key); + } } bool Synth::loadScalaFile(const fs::path& path) diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 123fac10..f8672cca 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -38,6 +38,14 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co //---------------------------------------------------------------------- + MATCH("/key/slots", "") { + const BitArray<128>& keys = impl.keySlots_; + sfizz_blob_t blob { keys.data(), static_cast(keys.byte_size()) }; + client.receive<'b'>(delay, path, &blob); + } break; + + //---------------------------------------------------------------------- + MATCH("/cc/slots", "") { const BitArray& ccs = impl.currentUsedCCs_; sfizz_blob_t blob { ccs.data(), static_cast(ccs.byte_size()) }; diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 08c3fcca..e0d3124a 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -216,6 +216,7 @@ struct Synth::Impl final: public Parser::Listener { std::vector ccLabels_; std::map ccLabelsMap_; std::vector keyLabels_; + BitArray<128> keySlots_; std::vector keyswitchLabels_; // Set as sw_default if present in the file From 6852bd76e28ebfb4f48d00968c05658e8ff8dd0b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 00:38:44 +0100 Subject: [PATCH 288/668] Add option SFIZZ_USE_SYSTEM_ABSEIL --- CMakeLists.txt | 4 +--- cmake/SfizzDeps.cmake | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f01465d7..36341f05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ option_ex (SFIZZ_DEVTOOLS "Enable developer tools build" OFF) option_ex (SFIZZ_SHARED "Enable shared library build" ON) option_ex (SFIZZ_USE_SNDFILE "Enable use of the sndfile library" ON) option_ex (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg" OFF) +option_ex (SFIZZ_USE_SYSTEM_ABSEIL "Use Abseil libraries preinstalled on system" OFF) option_ex (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically" OFF) option_ex (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds" OFF) @@ -46,9 +47,6 @@ include (CheckIPO) # Dylib bunder for macOS include (BundleDylibs) -# Add Abseil -add_subdirectory (external/abseil-cpp EXCLUDE_FROM_ALL) - # Add the static library targets and sources add_subdirectory (src) diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 464d6186..128c43eb 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -35,6 +35,13 @@ if(APPLE) list(APPEND CMAKE_PREFIX_PATH /usr/local) endif() +# Add Abseil +if(SFIZZ_USE_SYSTEM_ABSEIL) + find_package(absl REQUIRED) +else() + add_subdirectory("external/abseil-cpp" EXCLUDE_FROM_ALL) +endif() + # The jsl utility library for C++ add_library(sfizz_jsl INTERFACE) add_library(sfizz::jsl ALIAS sfizz_jsl) From 51f35d4474135c8eff8a30c285536e19acc8c9b5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 01:11:22 +0100 Subject: [PATCH 289/668] Add option SFIZZ_USE_SYSTEM_SIMDE --- CMakeLists.txt | 1 + cmake/SfizzDeps.cmake | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 36341f05..dce2d0da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ option_ex (SFIZZ_SHARED "Enable shared library build" ON) option_ex (SFIZZ_USE_SNDFILE "Enable use of the sndfile library" ON) option_ex (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg" OFF) option_ex (SFIZZ_USE_SYSTEM_ABSEIL "Use Abseil libraries preinstalled on system" OFF) +option_ex (SFIZZ_USE_SYSTEM_SIMDE "Use SIMDe libraries preinstalled on system" OFF) option_ex (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically" OFF) option_ex (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds" OFF) diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 128c43eb..dc39f499 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -87,7 +87,19 @@ add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL) # The simde library add_library(sfizz_simde INTERFACE) add_library(sfizz::simde ALIAS sfizz_simde) -target_include_directories(sfizz_simde INTERFACE "external/simde") +if(SFIZZ_USE_SYSTEM_SIMDE) + find_package(PkgConfig REQUIRED) + pkg_check_modules(SIMDE "simde" REQUIRED) + target_include_directories(sfizz_simde INTERFACE "${SIMDE_INCLUDE_DIRS}") + if(NOT SIMDE_VERSION OR SIMDE_VERSION VERSION_LESS_EQUAL "0.7.2") + message(WARNING "The version of SIMDe on this system has known issues. \ +It is recommended to either update if a newer version is available, or use the \ +version bundled with this package. Refer to following issues: \ +simd-everywhere/simde#704, simd-everywhere/simde#706") + endif() +else() + target_include_directories(sfizz_simde INTERFACE "external/simde") +endif() if(TARGET sfizz::openmp) target_link_libraries(sfizz_simde INTERFACE sfizz::openmp) endif() From c118ad6cbe0db6c7e96af25b18bdeb571abc40ad Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 23 Feb 2021 01:39:25 +0100 Subject: [PATCH 290/668] Add sw_vel Also add some introspection for voices using OSC and tests --- src/sfizz/MidiState.cpp | 7 +++ src/sfizz/MidiState.h | 12 ++++ src/sfizz/Synth.cpp | 11 ++-- src/sfizz/SynthMessaging.cpp | 39 +++++++++++++ tests/RegionTriggersT.cpp | 109 +++++++++++++++++++++++++++++++++-- tests/RegionValuesT.cpp | 35 ----------- tests/TestHelpers.cpp | 34 +++++++++++ tests/TestHelpers.h | 6 ++ 8 files changed, 210 insertions(+), 43 deletions(-) diff --git a/src/sfizz/MidiState.cpp b/src/sfizz/MidiState.cpp index 1f6cc4b5..52c7f188 100644 --- a/src/sfizz/MidiState.cpp +++ b/src/sfizz/MidiState.cpp @@ -21,6 +21,7 @@ void sfz::MidiState::noteOnEvent(int delay, int noteNumber, float velocity) noex if (noteNumber >= 0 && noteNumber < 128) { lastNoteVelocities[noteNumber] = velocity; noteOnTimes[noteNumber] = internalClock + static_cast(delay); + lastNotePlayed = noteNumber; activeNotes++; } @@ -105,6 +106,11 @@ float sfz::MidiState::getNoteVelocity(int noteNumber) const noexcept return lastNoteVelocities[noteNumber]; } +float sfz::MidiState::getLastVelocity() const noexcept +{ + return lastNoteVelocities[lastNotePlayed]; +} + void sfz::MidiState::insertEventInVector(EventVector& events, int delay, float value) { const auto insertionPoint = absl::c_upper_bound(events, delay, MidiEventDelayComparator {}); @@ -168,6 +174,7 @@ void sfz::MidiState::reset() noexcept activeNotes = 0; internalClock = 0; + lastNotePlayed = 0; absl::c_fill(noteOnTimes, 0); absl::c_fill(noteOffTimes, 0); } diff --git a/src/sfizz/MidiState.h b/src/sfizz/MidiState.h index bbdf58e1..03306d77 100644 --- a/src/sfizz/MidiState.h +++ b/src/sfizz/MidiState.h @@ -84,6 +84,13 @@ public: */ float getNoteVelocity(int noteNumber) const noexcept; + /** + * @brief Get the velocity of the last note played + * + * @return float + */ + float getLastVelocity() const noexcept; + /** * @brief Register a pitch bend event * @@ -184,6 +191,11 @@ private: */ MidiNoteArray lastNoteVelocities; + /** + * @brief Last note played + */ + int lastNotePlayed { 0 }; + /** * @brief Current known values for the CCs. * diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b359601f..2a0b9f43 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -988,8 +988,8 @@ void Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept Impl& impl = *impl_; const auto normalizedVelocity = normalizeVelocity(velocity); ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; - impl.resources_.midiState.noteOnEvent(delay, noteNumber, normalizedVelocity); impl.noteOnDispatch(delay, noteNumber, normalizedVelocity); + impl.resources_.midiState.noteOnEvent(delay, noteNumber, normalizedVelocity); } void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept @@ -1000,7 +1000,6 @@ void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept Impl& impl = *impl_; const auto normalizedVelocity = normalizeVelocity(velocity); ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; - impl.resources_.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); // FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a // way in sfz to specify that a release trigger should NOT use the note-on velocity? @@ -1011,6 +1010,7 @@ void Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept voice.registerNoteOff(delay, noteNumber, replacedVelocity); impl.noteOffDispatch(delay, noteNumber, replacedVelocity); + impl.resources_.midiState.noteOffEvent(delay, noteNumber, normalizedVelocity); } void Synth::Impl::startVoice(Region* region, int delay, const TriggerEvent& triggerEvent, SisterVoiceRingBuilder& ring) noexcept @@ -1051,7 +1051,6 @@ void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noex { const auto randValue = randNoteDistribution_(Random::randomGenerator); SisterVoiceRingBuilder ring; - const TriggerEvent triggerEvent { TriggerEventType::NoteOn, noteNumber, velocity }; if (!lastKeyswitchLists_[noteNumber].empty()) { if (currentSwitch_ && *currentSwitch_ != noteNumber) { @@ -1079,6 +1078,10 @@ void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noex } } + TriggerEvent triggerEvent { TriggerEventType::NoteOn, noteNumber, velocity }; + if (region->velocityOverride == VelocityOverride::previous) + triggerEvent.value = resources_.midiState.getLastVelocity(); + startVoice(region, delay, triggerEvent, ring); } } @@ -1140,7 +1143,6 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM ASSERT(ccNumber >= 0); ScopedTiming logger { dispatchDuration_, ScopedTiming::Operation::addToDuration }; - resources_.midiState.ccEvent(delay, ccNumber, normValue); changedCCsThisCycle_.set(ccNumber); @@ -1162,6 +1164,7 @@ void Synth::Impl::performHdcc(int delay, int ccNumber, float normValue, bool asM voice.registerCC(delay, ccNumber, normValue); ccDispatch(delay, ccNumber, normValue); + resources_.midiState.ccEvent(delay, ccNumber, normValue); } void Synth::Impl::setDefaultHdcc(int ccNumber, float value) diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 123fac10..1faa7786 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -1202,6 +1202,45 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co #undef GET_EQ_OR_BREAK #undef GET_REGION_OR_BREAK + + MATCH("/num_active_voices", "") { + client.receive<'i'>(delay, path, impl.voiceManager_.getNumActiveVoices()); + } break; + + #define GET_VOICE_OR_BREAK(idx) \ + if (static_cast(idx) >= impl.numVoices_) \ + break; \ + const auto& voice = impl.voiceManager_[idx]; \ + if (voice.isFree()) \ + break; + + MATCH("/voice&/trigger_value", "") { + GET_VOICE_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, voice.getTriggerEvent().value); + } break; + + MATCH("/voice&/trigger_number", "") { + GET_VOICE_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, voice.getTriggerEvent().number); + } break; + + MATCH("/voice&/trigger_type", "") { + GET_VOICE_OR_BREAK(indices[0]) + const auto& event = voice.getTriggerEvent(); + switch (event.type) { + case TriggerEventType::CC: + client.receive<'s'>(delay, path, "cc"); + break; + case TriggerEventType::NoteOn: + client.receive<'s'>(delay, path, "note_on"); + break; + case TriggerEventType::NoteOff: + client.receive<'s'>(delay, path, "note_on"); + break; + } + + } break; + #undef MATCH // TODO... } diff --git a/tests/RegionTriggersT.cpp b/tests/RegionTriggersT.cpp index 0226f263..fa8b5f59 100644 --- a/tests/RegionTriggersT.cpp +++ b/tests/RegionTriggersT.cpp @@ -4,16 +4,19 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz +#include "TestHelpers.h" +#include "sfizz/Synth.h" #include "sfizz/Region.h" #include "sfizz/SfzHelpers.h" #include "catch2/catch.hpp" using namespace Catch::literals; using namespace sfz::literals; +using namespace sfz; TEST_CASE("Basic triggers", "Region triggers") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); SECTION("key") @@ -163,8 +166,8 @@ TEST_CASE("Basic triggers", "Region triggers") TEST_CASE("Legato triggers", "Region triggers") { - sfz::MidiState midiState; - sfz::Region region { 0, midiState }; + MidiState midiState; + Region region { 0, midiState }; region.parseOpcode({ "sample", "*sine" }); SECTION("First note playing") { @@ -200,3 +203,101 @@ TEST_CASE("Legato triggers", "Region triggers") REQUIRE(!region.registerNoteOn(42, 64_norm, 0.5f)); } } + +TEST_CASE("[Triggers] sw_vel, basic") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + key=60 sample=kick.wav + key=62 sw_previous=60 sw_vel=previous sample=snare.wav + )"); + synth.noteOn(0, 60, 127); + synth.noteOn(10, 62, 10); + synth.dispatchMessage(client, 0, "/num_active_voices", "", nullptr); + synth.dispatchMessage(client, 0, "/voice0/trigger_value", "", nullptr); + synth.dispatchMessage(client, 0, "/voice1/trigger_value", "", nullptr); + std::vector expected { + "/num_active_voices,i : { 2 }", + "/voice0/trigger_value,f : { 1 }", + "/voice1/trigger_value,f : { 1 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Triggers] sw_vel, without sw_previous") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + key=60 sample=kick.wav + key=62 sw_vel=previous sample=snare.wav + )"); + synth.noteOn(0, 60, 127); + synth.noteOn(10, 62, 10); + synth.dispatchMessage(client, 0, "/num_active_voices", "", nullptr); + synth.dispatchMessage(client, 0, "/voice0/trigger_value", "", nullptr); + synth.dispatchMessage(client, 0, "/voice1/trigger_value", "", nullptr); + std::vector expected { + "/num_active_voices,i : { 2 }", + "/voice0/trigger_value,f : { 1 }", + "/voice1/trigger_value,f : { 1 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Triggers] sw_vel, with a note in between") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + key=60 sample=kick.wav + key=62 sw_vel=previous sample=snare.wav + key=64 sample=closedhat.wav + )"); + synth.noteOn(0, 60, 127); + synth.noteOn(5, 64, 63); + synth.noteOn(10, 62, 10); + synth.dispatchMessage(client, 0, "/num_active_voices", "", nullptr); + synth.dispatchMessage(client, 0, "/voice0/trigger_value", "", nullptr); + synth.dispatchMessage(client, 0, "/voice1/trigger_value", "", nullptr); + synth.dispatchMessage(client, 0, "/voice2/trigger_value", "", nullptr); + std::vector expected { + "/num_active_voices,i : { 3 }", + "/voice0/trigger_value,f : { 1 }", + "/voice1/trigger_value,f : { 0.496063 }", + "/voice2/trigger_value,f : { 0.496063 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Triggers] sw_vel, with a note in between and sw_previous") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + key=60 sample=kick.wav + key=62 sw_previous=60 sw_vel=previous sample=snare.wav + key=64 sample=closedhat.wav + )"); + synth.noteOn(0, 60, 127); + synth.noteOn(5, 64, 63); + synth.noteOn(10, 62, 10); + synth.dispatchMessage(client, 0, "/num_active_voices", "", nullptr); + synth.dispatchMessage(client, 0, "/voice0/trigger_value", "", nullptr); + synth.dispatchMessage(client, 0, "/voice1/trigger_value", "", nullptr); + std::vector expected { + "/num_active_voices,i : { 2 }", + "/voice0/trigger_value,f : { 1 }", + "/voice1/trigger_value,f : { 0.496063 }", + }; + REQUIRE(messageList == expected); +} diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index 197fe80a..a26044ec 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -6,7 +6,6 @@ #include "TestHelpers.h" #include "sfizz/Synth.h" -#include "sfizz/Messaging.h" #include "catch2/catch.hpp" #include #include @@ -14,40 +13,6 @@ using namespace Catch::literals; using namespace sfz; -void simpleMessageReceiver(void* data, int delay, const char* path, const char* sig, const sfizz_arg_t* args) -{ - (void)delay; - auto& messageList = *reinterpret_cast*>(data); - - std::string newMessage = absl::StrCat(path, ",", sig, " : { "); - for (unsigned i = 0, n = strlen(sig); i < n; ++i) { - switch(sig[i]){ - case 'i': - absl::StrAppend(&newMessage, args[i].i); - break; - case 'f': - absl::StrAppend(&newMessage, args[i].f); - break; - case 'd': - absl::StrAppend(&newMessage, args[i].d); - break; - case 'h': - absl::StrAppend(&newMessage, args[i].h); - break; - case 's': - absl::StrAppend(&newMessage, args[i].s); - break; - } - - if (i == (n - 1)) - absl::StrAppend(&newMessage, " }"); - else - absl::StrAppend(&newMessage, ", "); - } - - messageList.push_back(std::move(newMessage)); -} - TEST_CASE("[Values] Delay") { Synth synth; diff --git a/tests/TestHelpers.cpp b/tests/TestHelpers.cpp index 0f3f76f6..6c572e7e 100644 --- a/tests/TestHelpers.cpp +++ b/tests/TestHelpers.cpp @@ -124,3 +124,37 @@ std::string createModulationDotGraph(std::vector lines) return graph; } + +void simpleMessageReceiver(void* data, int delay, const char* path, const char* sig, const sfizz_arg_t* args) +{ + (void)delay; + auto& messageList = *reinterpret_cast*>(data); + + std::string newMessage = absl::StrCat(path, ",", sig, " : { "); + for (unsigned i = 0, n = strlen(sig); i < n; ++i) { + switch(sig[i]){ + case 'i': + absl::StrAppend(&newMessage, args[i].i); + break; + case 'f': + absl::StrAppend(&newMessage, args[i].f); + break; + case 'd': + absl::StrAppend(&newMessage, args[i].d); + break; + case 'h': + absl::StrAppend(&newMessage, args[i].h); + break; + case 's': + absl::StrAppend(&newMessage, args[i].s); + break; + } + + if (i == (n - 1)) + absl::StrAppend(&newMessage, " }"); + else + absl::StrAppend(&newMessage, ", "); + } + + messageList.push_back(std::move(newMessage)); +} diff --git a/tests/TestHelpers.h b/tests/TestHelpers.h index 0c60fb91..feb6823f 100644 --- a/tests/TestHelpers.h +++ b/tests/TestHelpers.h @@ -9,6 +9,7 @@ #include "sfizz/Region.h" #include "sfizz/Voice.h" #include "sfizz/Range.h" +#include "sfizz/Messaging.h" #include "catch2/catch.hpp" #include "sfizz/modulations/ModKey.h" @@ -104,3 +105,8 @@ inline bool approxEqual(absl::Span lhs, absl::Span rhs, return true; } + +/** + * @brief Simple helper function that feeds all received messages into a std::vector* in data. + */ +void simpleMessageReceiver(void* data, int delay, const char* path, const char* sig, const sfizz_arg_t* args); From 563df57177ea32a996064c035f7c220a9d7d9a61 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 01:40:43 +0100 Subject: [PATCH 291/668] Add gitattributes for simde --- .gitattributes | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitattributes b/.gitattributes index 94df7fba..fa2ba7d8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -29,3 +29,10 @@ appveyor.yml export-ignore /external/abseil-cpp/conanfile.py export-ignore /external/abseil-cpp/**/BUILD.bazel export-ignore /external/abseil-cpp/ci/** export-ignore + +/external/simde/docker/** export-ignore +/external/simde/test/** export-ignore +/external/simde/meson* export-ignore +/external/simde/*.py export-ignore +/external/simde/*.yml export-ignore +/external/simde/*.toml export-ignore From d95c70aa684befb78650bad7f18169f71e9c22d6 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 23 Feb 2021 01:42:34 +0100 Subject: [PATCH 292/668] Add a test for the midistate last velocity --- tests/MidiStateT.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/MidiStateT.cpp b/tests/MidiStateT.cpp index 9e25f162..5bec78ee 100644 --- a/tests/MidiStateT.cpp +++ b/tests/MidiStateT.cpp @@ -82,3 +82,11 @@ TEST_CASE("[MidiState] Extended CCs") sfz::MidiState state; state.ccEvent(0, 142, 64_norm); // should not trap } + +TEST_CASE("[MidiState] Last note velocity") +{ + sfz::MidiState state; + state.noteOnEvent(0, 62, 64_norm); + state.noteOnEvent(0, 60, 10_norm); + REQUIRE(state.getLastVelocity() == 10_norm); +} From e45dfbc50b3b43f57a470ed15718a655aa7fb7d1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 02:57:28 +0100 Subject: [PATCH 293/668] Have bit_array as a distinct library --- common.mk | 1 + src/CMakeLists.txt | 7 ++++++- src/sfizz/SynthPrivate.h | 2 +- src/sfizz/utility/{ => bit_array}/BitArray.h | 0 tests/SynthT.cpp | 2 +- 5 files changed, 9 insertions(+), 3 deletions(-) rename src/sfizz/utility/{ => bit_array}/BitArray.h (100%) diff --git a/common.mk b/common.mk index ca23cad7..d27836e8 100644 --- a/common.mk +++ b/common.mk @@ -128,6 +128,7 @@ SFIZZ_SOURCES = \ SFIZZ_C_FLAGS += \ -I$(SFIZZ_DIR)/src/sfizz \ + -I$(SFIZZ_DIR)/src/sfizz/utility/bit_array \ -I$(SFIZZ_DIR)/src/sfizz/utility/spin_mutex # Pkg-config dependency diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b98cf69b..9779d698 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -252,13 +252,18 @@ target_include_directories(sfizz_spin_mutex PUBLIC sfizz/utility/spin_mutex) target_link_libraries(sfizz_spin_mutex PRIVATE sfizz::atomic_queue) add_library(sfizz::spin_mutex ALIAS sfizz_spin_mutex) +# Sfizz bit array +add_library(sfizz_bit_array INTERFACE) +target_include_directories(sfizz_bit_array INTERFACE sfizz/utility/bit_array) +add_library(sfizz::bit_array ALIAS sfizz_bit_array) + # Sfizz internals (use this for testing) add_library(sfizz_internal STATIC) add_library(sfizz::internal ALIAS sfizz_internal) target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES}) target_include_directories(sfizz_internal PUBLIC "." "sfizz") target_link_libraries(sfizz_internal - PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex sfizz::simde + PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex sfizz::bit_array sfizz::simde PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index e0d3124a..aaf6f72a 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -5,12 +5,12 @@ #include "SisterVoiceRing.h" #include "TriggerEvent.h" #include "VoiceManager.h" +#include "BitArray.h" #include "modulations/sources/ADSREnvelope.h" #include "modulations/sources/Controller.h" #include "modulations/sources/FlexEnvelope.h" #include "modulations/sources/ChannelAftertouch.h" #include "modulations/sources/LFO.h" -#include "utility/BitArray.h" namespace sfz { diff --git a/src/sfizz/utility/BitArray.h b/src/sfizz/utility/bit_array/BitArray.h similarity index 100% rename from src/sfizz/utility/BitArray.h rename to src/sfizz/utility/bit_array/BitArray.h diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index c21fcc9e..cd309176 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -8,7 +8,7 @@ #include "sfizz/SisterVoiceRing.h" #include "sfizz/SfzHelpers.h" #include "sfizz/utility/NumericId.h" -#include "sfizz/utility/BitArray.h" +#include "BitArray.h" #include "TestHelpers.h" #include #include "catch2/catch.hpp" From 9de0648075ea31692c0ee874c5d4a16f8fdcba7b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 03:03:10 +0100 Subject: [PATCH 294/668] Convert the editor to use BitArray --- plugins/editor/CMakeLists.txt | 2 +- plugins/editor/src/editor/Editor.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/editor/CMakeLists.txt b/plugins/editor/CMakeLists.txt index ee8b259d..1c10dab7 100644 --- a/plugins/editor/CMakeLists.txt +++ b/plugins/editor/CMakeLists.txt @@ -69,7 +69,7 @@ else() target_include_directories(sfizz_editor PRIVATE ${sfizz-gio_INCLUDE_DIRS}) target_link_libraries(sfizz_editor PRIVATE ${sfizz-gio_LIBRARIES}) endif() -target_link_libraries(sfizz_editor PRIVATE sfizz::filesystem) +target_link_libraries(sfizz_editor PRIVATE sfizz::bit_array sfizz::filesystem) # layout tool if(NOT CMAKE_CROSSCOMPILING) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index fa0bb186..14987bf1 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -10,6 +10,7 @@ #include "GUIComponents.h" #include "GUIPiano.h" #include "NativeHelpers.h" +#include "BitArray.h" #include "plugin/MessageUtils.h" #include #include @@ -396,11 +397,10 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi // TODO(jpc) key ranges } else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) { - const uint8_t* bitChunks = args[0].b->data; - uint32_t byteSize = args[0].b->size; - - for (unsigned cc = 0; cc < 8 * byteSize; ++cc) { - bool used = bitChunks[cc / 8] & (1u << (cc % 8)); + size_t numBits = 8 * args[0].b->size; + ConstBitSpan bits { args[0].b->data, numBits }; + for (unsigned cc = 0; cc < numBits; ++cc) { + bool used = bits.test(cc); updateCCUsed(cc, used); if (used) { char pathBuf[256]; @@ -414,10 +414,10 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi } } else if (Messages::matchOSC("/cc/changed", path, indices) && !strcmp(sig, "b")) { - const uint8_t* bitChunks = args[0].b->data; - uint32_t byteSize = args[0].b->size; - for (unsigned cc = 0; cc < 8 * byteSize; ++cc) { - bool changed = bitChunks[cc / 8] & (1u << (cc % 8)); + size_t numBits = 8 * args[0].b->size; + ConstBitSpan bits { args[0].b->data, numBits }; + for (unsigned cc = 0; cc < numBits; ++cc) { + bool changed = bits.test(cc); if (changed) { char pathBuf[256]; sprintf(pathBuf, "/cc%u/value", cc); From 6de95ce2af6fe7398c682556576ce7e74d184c61 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 03:43:29 +0100 Subject: [PATCH 295/668] Update clang-tidy script --- scripts/run_clang_tidy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index ceb29530..097e4760 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -30,7 +30,7 @@ clang-tidy \ vst/SfizzVstState.cpp \ -- -Iexternal/abseil-cpp -Iexternal/jsl/include -Iexternal/filesystem/include -Iexternal/atomic_queue/include -Iexternal/threadpool -Isrc/external/hiir -Isrc/external/pugixml/src \ -Iexternal/st_audiofile/src -Iexternal/st_audiofile/thirdparty/dr_libs \ - -Isrc/sfizz -Isrc -Isrc/sfizz/utility/spin_mutex -Isrc/external/spline -Isrc/external/cpuid/src -Iexternal/simde \ + -Isrc/sfizz -Isrc -Isrc/sfizz/utility/bit_array -Isrc/sfizz/utility/spin_mutex -Isrc/external/spline -Isrc/external/cpuid/src -Iexternal/simde \ -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ieditor/external/vstgui4 -Ivst/external/ring_buffer \ -Ieditor/src \ -DNDEBUG -std=c++17 From 0cfe4b8c7c7c2676e1aaa96d46b2c71c89ac4836 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 05:18:54 +0100 Subject: [PATCH 296/668] Add subset of GLSL-Color-Spaces library (HCY) --- plugins/editor/CMakeLists.txt | 6 +- .../external/color-spaces/ColorSpaces.h | 129 ++++++++++++++++++ plugins/editor/external/color-spaces/LICENSE | 22 +++ 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 plugins/editor/external/color-spaces/ColorSpaces.h create mode 100644 plugins/editor/external/color-spaces/LICENSE diff --git a/plugins/editor/CMakeLists.txt b/plugins/editor/CMakeLists.txt index 1c10dab7..8edb39b1 100644 --- a/plugins/editor/CMakeLists.txt +++ b/plugins/editor/CMakeLists.txt @@ -59,6 +59,10 @@ if(APPLE) endif() # dependencies +add_library(sfizz_colorspaces INTERFACE) +add_library(sfizz::colorspaces ALIAS sfizz_colorspaces) +target_include_directories(sfizz_colorspaces INTERFACE "external/color-spaces") + if(WIN32) # elseif(APPLE) @@ -69,7 +73,7 @@ else() target_include_directories(sfizz_editor PRIVATE ${sfizz-gio_INCLUDE_DIRS}) target_link_libraries(sfizz_editor PRIVATE ${sfizz-gio_LIBRARIES}) endif() -target_link_libraries(sfizz_editor PRIVATE sfizz::bit_array sfizz::filesystem) +target_link_libraries(sfizz_editor PRIVATE sfizz::colorspaces sfizz::bit_array sfizz::filesystem) # layout tool if(NOT CMAKE_CROSSCOMPILING) diff --git a/plugins/editor/external/color-spaces/ColorSpaces.h b/plugins/editor/external/color-spaces/ColorSpaces.h new file mode 100644 index 00000000..06af231a --- /dev/null +++ b/plugins/editor/external/color-spaces/ColorSpaces.h @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: MIT +/* +GLSL Color Space Utility Functions +(c) 2015 tobspr + +Porting a subset to C++ +(c) 2020 Jean Pierre Cimalando + +------------------------------------------------------------------------------- + +The MIT License (MIT) + +Copyright (c) 2015 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- + +Most formulars / matrices are from: +https://en.wikipedia.org/wiki/SRGB + +Some are from: +http://www.chilliant.com/rgb2hsv.html +https://www.fourcc.org/fccyvrgb.php +*/ + +#pragma once +#include +#include +#include + +namespace ColorSpaces { + +template using vec = std::array; +using vec3 = vec<3>; +using vec4 = vec<4>; + +template +T clamp(T x, T lo, T hi) +{ + return std::max(lo, std::min(hi, x)); +} + +template +vec saturate(vec x) +{ + for (std::size_t i = 0; i < N; ++i) + x[i] = clamp(x[i], 0.0f, 1.0f); + return x; +} + +float dot(vec3 a, vec3 b) +{ + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +// Constants +static constexpr float HCV_EPSILON = 1e-10; +static constexpr float HCY_EPSILON = 1e-10; + +// Converts a value from linear RGB to HCV (Hue, Chroma, Value) +vec3 rgb_to_hcv(vec3 rgb) +{ + // Based on work by Sam Hocevar and Emil Persson + vec4 P = (rgb[1] < rgb[2]) ? vec4{{rgb[2], rgb[1], -1.0, 2.0/3.0}} : vec4{{rgb[1], rgb[2], 0.0, -1.0/3.0}}; + vec4 Q = (rgb[0] < P[0]) ? vec4{{P[0], P[1], P[3], rgb[0]}} : vec4{{rgb[0], P[1], P[2], P[0]}}; + float C = Q[0] - std::min(Q[3], Q[1]); + float H = std::abs((Q[3] - Q[1]) / (6 * C + HCV_EPSILON) + Q[2]); + return vec3{{H, C, Q[0]}}; +} + +// Converts from pure Hue to linear RGB +vec3 hue_to_rgb(float hue) +{ + float R = std::fabs(hue * 6 - 3) - 1; + float G = 2 - std::fabs(hue * 6 - 2); + float B = 2 - std::fabs(hue * 6 - 4); + return saturate(vec3{{R,G,B}}); +} + +// Converts from HCY to linear RGB +vec3 hcy_to_rgb(vec3 hcy) +{ + const vec3 HCYwts{{0.299, 0.587, 0.114}}; + vec3 RGB = hue_to_rgb(hcy[0]); + float Z = dot(RGB, HCYwts); + if (hcy[2] < Z) { + hcy[1] *= hcy[2] / Z; + } else if (Z < 1) { + hcy[1] *= (1 - hcy[2]) / (1 - Z); + } + return vec3{{(RGB[0] - Z) * hcy[1] + hcy[2], + (RGB[1] - Z) * hcy[1] + hcy[2], + (RGB[2] - Z) * hcy[1] + hcy[2]}}; +} + +// Converts from rgb to hcy (Hue, Chroma, Luminance) +vec3 rgb_to_hcy(vec3 rgb) +{ + const vec3 HCYwts = vec3{{0.299, 0.587, 0.114}}; + // Corrected by David Schaeffer + vec3 HCV = rgb_to_hcv(rgb); + float Y = dot(rgb, HCYwts); + float Z = dot(hue_to_rgb(HCV[0]), HCYwts); + if (Y < Z) { + HCV[1] *= Z / (HCY_EPSILON + Y); + } else { + HCV[1] *= (1 - Z) / (HCY_EPSILON + 1 - Y); + } + return vec3{{HCV[0], HCV[1], Y}}; +} + +} // namespace ColorSpaces diff --git a/plugins/editor/external/color-spaces/LICENSE b/plugins/editor/external/color-spaces/LICENSE new file mode 100644 index 00000000..20efd1b3 --- /dev/null +++ b/plugins/editor/external/color-spaces/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + From 535b332982c6dac0548e67c53b3397b641e6fa1e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 06:03:58 +0100 Subject: [PATCH 297/668] Add color helpers --- plugins/editor/CMakeLists.txt | 2 + plugins/editor/src/editor/ColorHelpers.cpp | 46 ++++++++++++++++++++++ plugins/editor/src/editor/ColorHelpers.h | 33 ++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 plugins/editor/src/editor/ColorHelpers.cpp create mode 100644 plugins/editor/src/editor/ColorHelpers.h diff --git a/plugins/editor/CMakeLists.txt b/plugins/editor/CMakeLists.txt index 8edb39b1..d2153d32 100644 --- a/plugins/editor/CMakeLists.txt +++ b/plugins/editor/CMakeLists.txt @@ -36,6 +36,8 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/GUIComponents.cpp src/editor/GUIPiano.h src/editor/GUIPiano.cpp + src/editor/ColorHelpers.h + src/editor/ColorHelpers.cpp src/editor/NativeHelpers.h src/editor/NativeHelpers.cpp src/editor/layout/main.hpp diff --git a/plugins/editor/src/editor/ColorHelpers.cpp b/plugins/editor/src/editor/ColorHelpers.cpp new file mode 100644 index 00000000..0d92ce27 --- /dev/null +++ b/plugins/editor/src/editor/ColorHelpers.cpp @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "ColorHelpers.h" +#include + +SColorRGB::SColorRGB(const CColor &cc) +{ + r = cc.normRed(); + g = cc.normGreen(); + b = cc.normBlue(); + a = cc.normAlpha(); +} + +SColorRGB::SColorRGB(const SColorHCY &hcy) +{ + ColorSpaces::vec3 vhcy{{hcy.h, hcy.c, hcy.y}}; + ColorSpaces::vec3 vrgb = ColorSpaces::hcy_to_rgb(vhcy); + r = vrgb[0]; + g = vrgb[1]; + b = vrgb[2]; + a = hcy.a; +} + +CColor SColorRGB::toColor() const +{ + CColor cc; + cc.setNormRed(r); + cc.setNormGreen(g); + cc.setNormBlue(b); + cc.setNormAlpha(a); + return cc; +} + +SColorHCY::SColorHCY(const SColorRGB &rgb) +{ + ColorSpaces::vec3 vrgb{{rgb.r, rgb.g, rgb.b}}; + ColorSpaces::vec3 vhcy = ColorSpaces::rgb_to_hcy(vrgb); + h = vhcy[0]; + c = vhcy[1]; + y = vhcy[2]; + a = rgb.a; +} diff --git a/plugins/editor/src/editor/ColorHelpers.h b/plugins/editor/src/editor/ColorHelpers.h new file mode 100644 index 00000000..fd484799 --- /dev/null +++ b/plugins/editor/src/editor/ColorHelpers.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "vstgui/lib/ccolor.h" + +using namespace VSTGUI; + +struct SColorRGB; +struct SColorHCY; + +struct SColorRGB { + SColorRGB() = default; + explicit SColorRGB(const CColor &cc); + explicit SColorRGB(const SColorHCY &hcy); + SColorRGB(float r, float g, float b, float a = 1.0) : r(r), g(g), b(b), a(a) {} + CColor toColor() const; + + float r {}, g {}, b {}, a { 1.0 }; +}; + +struct SColorHCY { + SColorHCY() = default; + explicit SColorHCY(const CColor &cc) : SColorHCY(SColorRGB(cc)) {} + explicit SColorHCY(const SColorRGB &rgb); + SColorHCY(float h, float c, float y, float a = 1.0) : h(h), c(c), y(y), a(a) {} + CColor toColor() const { return SColorRGB(*this).toColor(); } + + float h {}, c {}, y {}, a { 1.0 }; +}; From 2638ef0cffc8ed87c606df87ada635483213a20a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 07:00:25 +0100 Subject: [PATCH 298/668] Represent the active key range with color --- plugins/editor/src/editor/Editor.cpp | 14 ++++++++++- plugins/editor/src/editor/GUIPiano.cpp | 34 +++++++++++++++++++++++--- plugins/editor/src/editor/GUIPiano.h | 13 +++++++--- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 14987bf1..173d7166 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -164,6 +164,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void updateTuningFrequencyLabel(float tuningFrequency); void updateStretchedTuningLabel(float stretchedTuning); + void updateKeyUsed(unsigned key, bool used); void updateCCUsed(unsigned cc, bool used); void updateCCValue(unsigned cc, float value); void updateCCDefaultValue(unsigned cc, float value); @@ -394,7 +395,12 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi unsigned indices[8]; if (Messages::matchOSC("/key/slots", path, indices) && !strcmp(sig, "b")) { - // TODO(jpc) key ranges + size_t numBits = 8 * args[0].b->size; + ConstBitSpan bits { args[0].b->data, numBits }; + for (unsigned key = 0; key < 128; ++key) { + bool used = key < numBits && bits.test(key); + updateKeyUsed(key, used); + } } else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) { size_t numBits = 8 * args[0].b->size; @@ -1274,6 +1280,12 @@ void Editor::Impl::updateStretchedTuningLabel(float stretchedTuning) label->setText(text); } +void Editor::Impl::updateKeyUsed(unsigned key, bool used) +{ + if (SPiano* piano = piano_) + piano->setKeyUsed(key, used); +} + void Editor::Impl::updateCCUsed(unsigned cc, bool used) { if (SControlsPanel* panel = controlsPanel_) diff --git a/plugins/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp index 2c17ddc4..b2c00459 100644 --- a/plugins/editor/src/editor/GUIPiano.cpp +++ b/plugins/editor/src/editor/GUIPiano.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "GUIPiano.h" +#include "ColorHelpers.h" #include "utility/vstgui_before.h" #include "vstgui/lib/cdrawcontext.h" #include "vstgui/lib/cgraphicspath.h" @@ -37,6 +38,18 @@ void SPiano::setNumOctaves(unsigned octs) invalid(); } +void SPiano::setKeyUsed(unsigned key, bool used) +{ + if (key >= 128) + return; + + if (keyUsed_.test(key) == used) + return; + + keyUsed_.set(key, used); + invalid(); +} + void SPiano::draw(CDrawContext* dc) { const Dimensions dim = getDimensions(false); @@ -56,9 +69,17 @@ void SPiano::draw(CDrawContext* dc) for (unsigned key = 0; key < keyCount; ++key) { if (!black[key % 12]) { CRect rect = keyRect(key); - CColor keycolor = whiteFill_; + + SColorHCY hcy(keyUsedHue_, 1.0, whiteKeyLuma_); + if (!keyUsed_[key]) { + hcy.y = 1.0; + if (keyval_[key]) + hcy.c = 0.0; + } if (keyval_[key]) - keycolor = pressedFill_; + hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_); + + CColor keycolor = hcy.toColor(); dc->setFillColor(keycolor); dc->drawRect(rect, kDrawFilled); } @@ -76,9 +97,14 @@ void SPiano::draw(CDrawContext* dc) for (unsigned key = 0; key < keyCount; ++key) { if (black[key % 12]) { CRect rect = keyRect(key); - CColor keycolor = blackFill_; + + SColorHCY hcy(keyUsedHue_, 1.0, blackKeyLuma_); + if (!keyUsed_[key]) + hcy.c = 0.0; if (keyval_[key]) - keycolor = pressedFill_; + hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_); + + CColor keycolor = hcy.toColor(); dc->setFillColor(keycolor); dc->drawRect(rect, kDrawFilled); dc->setFrameColor(outline_); diff --git a/plugins/editor/src/editor/GUIPiano.h b/plugins/editor/src/editor/GUIPiano.h index 6927b06f..13e3ac4e 100644 --- a/plugins/editor/src/editor/GUIPiano.h +++ b/plugins/editor/src/editor/GUIPiano.h @@ -11,6 +11,7 @@ #include "utility/vstgui_after.h" #include #include +#include using namespace VSTGUI; @@ -24,6 +25,8 @@ public: unsigned getNumOctaves() const { return octs_; } void setNumOctaves(unsigned octs); + void setKeyUsed(unsigned key, bool used); + std::function onKeyPressed; std::function onKeyReleased; @@ -52,6 +55,7 @@ private: private: unsigned octs_ {}; std::vector keyval_; + std::bitset<128> keyUsed_; unsigned mousePressedKey_ = ~0u; CCoord innerPaddingX_ = 4.0; @@ -60,9 +64,12 @@ private: CColor backgroundFill_ { 0xca, 0xca, 0xca, 0xff }; float backgroundRadius_ = 5.0; - CColor whiteFill_ { 0xee, 0xee, 0xec, 0xff }; - CColor blackFill_ { 0x2e, 0x34, 0x36, 0xff }; - CColor pressedFill_ { 0xa0, 0xa0, 0xa0, 0xff }; + + float keyUsedHue_ = 0.55; + float whiteKeyLuma_ = 0.5; + float blackKeyLuma_ = 0.25; + float keyLumaPressDelta_ = 0.20; + CColor outline_ { 0x00, 0x00, 0x00, 0xff }; CColor shadeOutline_ { 0x80, 0x80, 0x80, 0xff }; CColor labelStroke_ { 0x63, 0x63, 0x63, 0xff }; From 68340fe1f423b283a387fb58ce213425fc3b22a7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 07:07:41 +0100 Subject: [PATCH 299/668] Special case: don't color keys if range full --- plugins/editor/src/editor/GUIPiano.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp index b2c00459..22ec4681 100644 --- a/plugins/editor/src/editor/GUIPiano.cpp +++ b/plugins/editor/src/editor/GUIPiano.cpp @@ -55,6 +55,7 @@ void SPiano::draw(CDrawContext* dc) const Dimensions dim = getDimensions(false); const unsigned octs = octs_; const unsigned keyCount = octs * 12; + const bool allKeysUsed = keyUsed_.all(); dc->setDrawMode(kAntiAliasing); @@ -71,7 +72,7 @@ void SPiano::draw(CDrawContext* dc) CRect rect = keyRect(key); SColorHCY hcy(keyUsedHue_, 1.0, whiteKeyLuma_); - if (!keyUsed_[key]) { + if (!keyUsed_[key] || allKeysUsed) { hcy.y = 1.0; if (keyval_[key]) hcy.c = 0.0; @@ -99,7 +100,7 @@ void SPiano::draw(CDrawContext* dc) CRect rect = keyRect(key); SColorHCY hcy(keyUsedHue_, 1.0, blackKeyLuma_); - if (!keyUsed_[key]) + if (!keyUsed_[key] || allKeysUsed) hcy.c = 0.0; if (keyval_[key]) hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_); From 2e28707367748852c3128ae451ed56bbfb0d5053 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 07:10:50 +0100 Subject: [PATCH 300/668] Add mention of authorship regarding GLSL-Color-Spaces --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d155591e..70add6c8 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ The sfizz library also uses in some subprojects: - [cxxopts] by Jarryd Beck, licensed under the MIT license - [fmidi] by Jean Pierre Cimalando, licensed under the Boost Software License 1.0 - [libsamplerate], licensed under the BSD 2-Clause license +- [GLSL-Color-Spaces] by tobspr, licensed under the MIT license [Abseil]: https://abseil.io/ [atomic_queue]: https://github.com/max0x7ba/atomic_queue @@ -74,6 +75,7 @@ The sfizz library also uses in some subprojects: [libsamplerate]: http://www.mega-nerd.com/SRC/ [libsndfile]: http://www.mega-nerd.com/libsndfile/ [LV2]: https://lv2plug.in/ +[GLSL-Color-Spaces]: https://github.com/tobspr/GLSL-Color-Spaces [our website]: https://sfz.tools/sfizz [releases]: https://github.com/sfztools/sfizz/releases [Carla]: https://kx.studio/Applications:Carla From 3aded2fecfb7841f3a1dee9740498a167ea02449 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 07:29:35 +0100 Subject: [PATCH 301/668] Increase key luma --- plugins/editor/src/editor/GUIPiano.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/editor/src/editor/GUIPiano.h b/plugins/editor/src/editor/GUIPiano.h index 13e3ac4e..c35f8741 100644 --- a/plugins/editor/src/editor/GUIPiano.h +++ b/plugins/editor/src/editor/GUIPiano.h @@ -66,9 +66,9 @@ private: float backgroundRadius_ = 5.0; float keyUsedHue_ = 0.55; - float whiteKeyLuma_ = 0.5; - float blackKeyLuma_ = 0.25; - float keyLumaPressDelta_ = 0.20; + float whiteKeyLuma_ = 0.9; + float blackKeyLuma_ = 0.5; + float keyLumaPressDelta_ = 0.2; CColor outline_ { 0x00, 0x00, 0x00, 0xff }; CColor shadeOutline_ { 0x80, 0x80, 0x80, 0xff }; From c5c7e2bb63d473322c8b92ee649d6dcecfcad53c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 07:57:18 +0100 Subject: [PATCH 302/668] Try fixing MSVC warning which pollutes the log --- src/sfizz/Opcode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 2c47e882..47fbb98f 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -151,7 +151,7 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) return absl::nullopt; } - return returnedValue; + return static_cast(returnedValue); } #define INSTANTIATE_FOR_INTEGRAL(T) \ From 34ca6d69e39bc9759d90e250fdb060d436a2398a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 09:27:20 +0100 Subject: [PATCH 303/668] Display key events on VK, with VST --- plugins/editor/src/editor/EditIds.h | 16 ++++++++ plugins/editor/src/editor/Editor.cpp | 8 ++++ plugins/editor/src/editor/GUIPiano.cpp | 14 +++++++ plugins/editor/src/editor/GUIPiano.h | 3 +- plugins/vst/SfizzVstController.cpp | 16 ++++++++ plugins/vst/SfizzVstController.h | 1 + plugins/vst/SfizzVstEditor.cpp | 43 ++++++++++++++++++++- plugins/vst/SfizzVstEditor.h | 4 ++ plugins/vst/SfizzVstProcessor.cpp | 52 ++++++++++++++++++++++---- plugins/vst/SfizzVstProcessor.h | 4 ++ plugins/vst/SfizzVstUpdates.cpp | 30 +++++++++++++++ plugins/vst/SfizzVstUpdates.h | 27 +++++++++++++ 12 files changed, 207 insertions(+), 11 deletions(-) diff --git a/plugins/editor/src/editor/EditIds.h b/plugins/editor/src/editor/EditIds.h index 869d1c44..fd1556bc 100644 --- a/plugins/editor/src/editor/EditIds.h +++ b/plugins/editor/src/editor/EditIds.h @@ -22,6 +22,9 @@ enum class EditId : int { UserFilesDir, FallbackFilesDir, // + Key0, + KeyLast = Key0 + 128 - 1, + // Controller0, ControllerLast = Controller0 + sfz::config::numCCs - 1, // @@ -58,3 +61,16 @@ inline bool editIdIsCC(EditId id) return int(id) >= int(EditId::Controller0) && int(id) <= int(EditId::ControllerLast); } + +inline EditId editIdForKey(int key) +{ + return EditId(int(EditId::Key0) + key); +} +inline int keyForEditId(EditId id) +{ + return int(id) - int(EditId::Key0); +} +inline bool editIdIsKey(EditId id) +{ + return int(id) >= int(EditId::Key0) && int(id) <= int(EditId::KeyLast); +} diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 173d7166..83507bd6 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -387,6 +387,14 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) setActivePanel(value); } break; + default: + if (editIdIsKey(id)) { + const int key = keyForEditId(id); + const float value = v.to_float(); + if (SPiano* piano = piano_) + piano->setKeyValue(key, value); + } + break; } } diff --git a/plugins/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp index 22ec4681..6dc990f1 100644 --- a/plugins/editor/src/editor/GUIPiano.cpp +++ b/plugins/editor/src/editor/GUIPiano.cpp @@ -50,6 +50,20 @@ void SPiano::setKeyUsed(unsigned key, bool used) invalid(); } +void SPiano::setKeyValue(unsigned key, float value) +{ + if (key >= 128) + return; + + value = std::max(0.0f, std::min(1.0f, value)); + + if (keyval_[key] == value) + return; + + keyval_[key] = value; + invalid(); +} + void SPiano::draw(CDrawContext* dc) { const Dimensions dim = getDimensions(false); diff --git a/plugins/editor/src/editor/GUIPiano.h b/plugins/editor/src/editor/GUIPiano.h index c35f8741..eafe115c 100644 --- a/plugins/editor/src/editor/GUIPiano.h +++ b/plugins/editor/src/editor/GUIPiano.h @@ -26,6 +26,7 @@ public: void setNumOctaves(unsigned octs); void setKeyUsed(unsigned key, bool used); + void setKeyValue(unsigned key, float value); std::function onKeyPressed; std::function onKeyReleased; @@ -54,7 +55,7 @@ private: private: unsigned octs_ {}; - std::vector keyval_; + std::vector keyval_; std::bitset<128> keyUsed_; unsigned mousePressedKey_ = ~0u; diff --git a/plugins/vst/SfizzVstController.cpp b/plugins/vst/SfizzVstController.cpp index 6717f685..2c3cb320 100644 --- a/plugins/vst/SfizzVstController.cpp +++ b/plugins/vst/SfizzVstController.cpp @@ -21,6 +21,7 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) // create update objects oscUpdate_ = Steinberg::owned(new OSCUpdate); + noteUpdate_ = Steinberg::owned(new NoteUpdate); sfzPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateSfz)); scalaPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateScala)); processorStateUpdate_ = Steinberg::owned(new ProcessorStateUpdate); @@ -283,6 +284,20 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message) oscUpdate_->changed(); oscUpdate_->clear(); } + else if (!strcmp(id, "NoteEvents")) { + const void* data = nullptr; + uint32 size = 0; + result = attr->getBinary("Events", data, size); + + const auto* events = reinterpret_cast< + const std::pair*>(data); + uint32 numEvents = size / sizeof(events[0]); + + // this is a synchronous send, because the update object gets reused + noteUpdate_->setEvents(events, numEvents, false); + noteUpdate_->changed(); + noteUpdate_->clear(); + } return result; } @@ -307,6 +322,7 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) std::vector triggerUpdates; triggerUpdates.push_back(oscUpdate_); + triggerUpdates.push_back(noteUpdate_); IPtr editor = Steinberg::owned( new SfizzVstEditor(this, absl::MakeSpan(continuousUpdates), absl::MakeSpan(triggerUpdates))); diff --git a/plugins/vst/SfizzVstController.h b/plugins/vst/SfizzVstController.h index 2c207e23..83e94eff 100644 --- a/plugins/vst/SfizzVstController.h +++ b/plugins/vst/SfizzVstController.h @@ -46,6 +46,7 @@ public: protected: Steinberg::IPtr oscUpdate_; + Steinberg::IPtr noteUpdate_; Steinberg::IPtr sfzPathUpdate_; Steinberg::IPtr scalaPathUpdate_; Steinberg::IPtr processorStateUpdate_; diff --git a/plugins/vst/SfizzVstEditor.cpp b/plugins/vst/SfizzVstEditor.cpp index 8345c274..e42721ef 100644 --- a/plugins/vst/SfizzVstEditor.cpp +++ b/plugins/vst/SfizzVstEditor.cpp @@ -23,6 +23,7 @@ static ViewRect sfizzUiViewRect { 0, 0, Editor::viewWidth, Editor::viewHeight }; enum { kOscTempSize = 8192, kOscQueueSize = 65536, + kNoteEventQueueSize = 8192, }; SfizzVstEditor::SfizzVstEditor( @@ -70,6 +71,12 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p oscQueue_.reset(queue); queue->reserve(kOscQueueSize); } + { + std::lock_guard lock(noteEventQueueMutex_); + NoteEventsVec* queue = new NoteEventsVec; + noteEventQueue_.reset(queue); + queue->reserve(kNoteEventQueueSize); + } if (!frame->open(parent, platformType, config)) { fprintf(stderr, "[sfizz] error opening frame\n"); @@ -116,8 +123,14 @@ void PLUGIN_API SfizzVstEditor::close() this->frame = nullptr; } - std::lock_guard lock(oscQueueMutex_); - oscQueue_.reset(); + { + std::lock_guard lock(oscQueueMutex_); + oscQueue_.reset(); + } + { + std::lock_guard lock(noteEventQueueMutex_); + noteEventQueue_.reset(); + } } /// @@ -144,6 +157,7 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message) if (message == CVSTGUITimer::kMsgTimer) { processOscQueue(); + processNoteEventQueue(); } return result; @@ -163,6 +177,17 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message) return; } + if (NoteUpdate* update = FCast(changedUnknown)) { + // this update is synchronous: may happen from non-UI thread + uint32 count = update->count(); + if (count > 0) { + const auto* events = update->events(); + std::lock_guard lock(noteEventQueueMutex_); + if (NoteEventsVec* queue = noteEventQueue_.get()) + std::copy(events, events + count, std::back_inserter(*queue)); + } + } + if (FilePathUpdate* update = FCast(changedUnknown)) { const std::string path = update->getPath(); switch (update->getType()) { @@ -259,6 +284,20 @@ void SfizzVstEditor::processOscQueue() queue->clear(); } +void SfizzVstEditor::processNoteEventQueue() +{ + std::lock_guard lock(noteEventQueueMutex_); + + NoteEventsVec* queue = noteEventQueue_.get(); + if (!queue) + return; + + for (std::pair event : *queue) + uiReceiveValue(editIdForKey(event.first), event.second); + + queue->clear(); +} + /// void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) { diff --git a/plugins/vst/SfizzVstEditor.h b/plugins/vst/SfizzVstEditor.h index a03302a5..79cbb0ee 100644 --- a/plugins/vst/SfizzVstEditor.h +++ b/plugins/vst/SfizzVstEditor.h @@ -48,6 +48,7 @@ public: private: void processOscQueue(); + void processNoteEventQueue(); protected: // EditorController @@ -77,6 +78,9 @@ private: typedef std::vector OscByteVec; std::unique_ptr oscQueue_; std::mutex oscQueueMutex_; + typedef std::vector> NoteEventsVec; + std::unique_ptr noteEventQueue_; + std::mutex noteEventQueueMutex_; // subscribed updates std::vector> continuousUpdates_; diff --git a/plugins/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp index 39b021f3..609de2f8 100644 --- a/plugins/vst/SfizzVstProcessor.cpp +++ b/plugins/vst/SfizzVstProcessor.cpp @@ -95,6 +95,8 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context) _synth->timePosition(0, 0, 0); _synth->playbackState(0, 0); + _noteEventsCurrentCycle.fill(-1.0f); + return result; } @@ -281,6 +283,21 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) _semaToWorker.post(); } + // + std::pair noteEvents[128]; + size_t numNoteEvents = 0; + for (uint32 key = 0; key < 128; ++key) { + float value = _noteEventsCurrentCycle[key]; + if (value < 0.0f) + continue; + noteEvents[numNoteEvents++] = std::make_pair(key, value); + _noteEventsCurrentCycle[key] = -1.0f; + } + if (numNoteEvents > 0) { + if (writeWorkerMessage("NoteEvents", noteEvents, numNoteEvents * sizeof(noteEvents[0]))) + _semaToWorker.post(); + } + return kResultTrue; } @@ -422,15 +439,28 @@ void SfizzVstProcessor::processEvents(Vst::IEventList& events) continue; switch (e.type) { - case Vst::Event::kNoteOnEvent: - if (e.noteOn.velocity == 0.0f) - synth.noteOff(e.sampleOffset, e.noteOn.pitch, 0); - else - synth.noteOn(e.sampleOffset, e.noteOn.pitch, convertVelocityFromFloat(e.noteOn.velocity)); + case Vst::Event::kNoteOnEvent: { + int pitch = e.noteOn.pitch; + if (pitch < 0 || pitch >= 128) + break; + if (e.noteOn.velocity <= 0.0f) { + synth.noteOff(e.sampleOffset, pitch, 0); + _noteEventsCurrentCycle[pitch] = 0.0f; + } + else { + synth.noteOn(e.sampleOffset, pitch, convertVelocityFromFloat(e.noteOn.velocity)); + _noteEventsCurrentCycle[pitch] = e.noteOn.velocity; + } break; - case Vst::Event::kNoteOffEvent: - synth.noteOff(e.sampleOffset, e.noteOff.pitch, convertVelocityFromFloat(e.noteOff.velocity)); + } + case Vst::Event::kNoteOffEvent: { + int pitch = e.noteOn.pitch; + if (pitch < 0 || pitch >= 128) + break; + synth.noteOff(e.sampleOffset, pitch, convertVelocityFromFloat(e.noteOff.velocity)); + _noteEventsCurrentCycle[pitch] = 0.0f; break; + } // case Vst::Event::kPolyPressureEvent: // synth.aftertouch(e.sampleOffset, convertVelocityFromFloat(e.polyPressure.pressure)); // break; @@ -574,7 +604,7 @@ FUnknown* SfizzVstProcessor::createInstance(void*) void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args) { uint8_t* oscTemp = _oscTemp.get(); - uint32_t oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args); + uint32 oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args); if (oscSize <= kOscTempSize) { if (writeWorkerMessage("ReceiveMessage", oscTemp, oscSize)) _semaToWorker.post(); @@ -650,6 +680,12 @@ void SfizzVstProcessor::doBackgroundWork() notification->getAttributes()->setBinary("Message", msg->payload(), msg->size); sendMessage(notification); } + else if (!std::strcmp(id, "NoteEvents")) { + Steinberg::OPtr notification { allocateMessage() }; + notification->setMessageID("NoteEvents"); + notification->getAttributes()->setBinary("Events", msg->payload(), msg->size); + sendMessage(notification); + } } } diff --git a/plugins/vst/SfizzVstProcessor.h b/plugins/vst/SfizzVstProcessor.h index 1401780b..2219ab6a 100644 --- a/plugins/vst/SfizzVstProcessor.h +++ b/plugins/vst/SfizzVstProcessor.h @@ -11,6 +11,7 @@ #include "public.sdk/source/vst/vstaudioeffect.h" #include #include +#include #include #include #include @@ -60,6 +61,9 @@ private: // misc static void loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath); + // note event tracking + std::array _noteEventsCurrentCycle; // 0: off, >0: on, <0: no change + // worker and thread sync std::thread _worker; volatile bool _workRunning = false; diff --git a/plugins/vst/SfizzVstUpdates.cpp b/plugins/vst/SfizzVstUpdates.cpp index ab6c69f5..d9921bdb 100644 --- a/plugins/vst/SfizzVstUpdates.cpp +++ b/plugins/vst/SfizzVstUpdates.cpp @@ -35,3 +35,33 @@ void OSCUpdate::setMessage(const void* data, uint32_t size, bool copy) size_ = size; allocated_ = copy; } + +/// +NoteUpdate::~NoteUpdate() +{ + clear(); +} + +void NoteUpdate::clear() +{ + if (allocated_) + delete[] events_; + events_ = nullptr; + count_ = 0; + allocated_ = false; +} + +void NoteUpdate::setEvents(const std::pair* events, uint32_t count, bool copy) +{ + clear(); + + if (copy) { + auto *buffer = new std::pair[count]; + std::memcpy(buffer, events, count); + events = buffer; + } + + events_ = events; + count_ = count; + allocated_ = copy; +} diff --git a/plugins/vst/SfizzVstUpdates.h b/plugins/vst/SfizzVstUpdates.h index 0837a047..0fbd8d3a 100644 --- a/plugins/vst/SfizzVstUpdates.h +++ b/plugins/vst/SfizzVstUpdates.h @@ -39,6 +39,33 @@ private: OSCUpdate& operator=(const OSCUpdate&) = delete; }; +/** + * @brief Update which notifies one or more note on/off events + * Is is supposed to be used synchronously. + * (ie. FObject::changed or UpdateHandler::triggerUpdates) + */ +class NoteUpdate : public Steinberg::FObject { +public: + NoteUpdate() = default; + ~NoteUpdate(); + void clear(); + void setEvents(const std::pair* events, uint32_t count, bool copy); + + const std::pair* events() const noexcept { return events_; } + const uint32_t count() const noexcept { return count_; } + + OBJ_METHODS(NoteUpdate, FObject) + +private: + const std::pair* events_ = nullptr; + uint32_t count_ = 0; + bool allocated_ = false; + +private: + NoteUpdate(const NoteUpdate&) = delete; + NoteUpdate& operator=(const NoteUpdate&) = delete; +}; + /** * @brief Update which notifies a change of file path pseudo-parameter * The message ID is used to indicate which path it is. From d112cfaf2dc11875d457b3faab5f2d3d239cbb1e Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 23 Feb 2021 12:02:02 +0100 Subject: [PATCH 304/668] Add delay_cc and delay_oncc --- src/sfizz/Defaults.cpp | 1 + src/sfizz/Defaults.h | 1 + src/sfizz/Region.cpp | 12 +++++++++++- src/sfizz/Region.h | 1 + src/sfizz/SynthMessaging.cpp | 5 +++++ tests/RegionValuesT.cpp | 24 ++++++++++++++++++++++++ 6 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 8ac6d3af..7a53d54d 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -7,6 +7,7 @@ constexpr auto uint32_t_max = std::numeric_limits::max(); extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec delayMod { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), 0 }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 557ae19f..289b8d7d 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -126,6 +126,7 @@ namespace Default { extern const OpcodeSpec delay; extern const OpcodeSpec delayRandom; + extern const OpcodeSpec delayMod; extern const OpcodeSpec offset; extern const OpcodeSpec offsetMod; extern const OpcodeSpec offsetRandom; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index ec07ad48..fd68bb02 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -97,6 +97,12 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("delay"): delay = opcode.read(Default::delay); break; + case hash("delay_oncc&"): // also delay_cc& + if (opcode.parameters.back() > config::numCCs) + return false; + + delayCC[opcode.parameters.back()] = opcode.read(Default::delayMod); + break; case hash("delay_random"): delayRandom = opcode.read(Default::delayRandom); break; @@ -1636,7 +1642,11 @@ uint64_t sfz::Region::getOffset(Oversampling factor) const noexcept float sfz::Region::getDelay() const noexcept { fast_real_distribution delayDistribution { 0, delayRandom }; - return delay + delayDistribution(Random::randomGenerator); + float finalDelay { delay }; + finalDelay += delayDistribution(Random::randomGenerator); + for (const auto& mod: delayCC) + finalDelay += mod.data * midiState.getCCValue(mod.cc); + return Default::delay.bounds.clamp(finalDelay); } uint32_t sfz::Region::trueSampleEnd(Oversampling factor) const noexcept diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index d8d6368e..98dda576 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -321,6 +321,7 @@ struct Region { absl::optional sampleQuality {}; float delay { Default::delay }; // delay float delayRandom { Default::delayRandom }; // delay_random + CCMap delayCC { Default::delayMod }; int64_t offset { Default::offset }; // offset int64_t offsetRandom { Default::offsetRandom }; // offset_random CCMap offsetCC { Default::offsetMod }; diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index f8672cca..e905cdb9 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -103,6 +103,11 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'f'>(delay, path, region.delayRandom); } break; + MATCH("/region&/delay_cc&", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.delayCC.getWithDefault(indices[1])); + } break; + MATCH("/region&/offset", "") { GET_REGION_OR_BREAK(indices[0]) client.receive<'h'>(delay, path, region.offset); diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index 197fe80a..a9a7a63f 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -98,6 +98,30 @@ TEST_CASE("[Values] Delay") }; REQUIRE(messageList == expected); } + + SECTION("CC") + { + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav delay_cc12=1.5 + sample=kick.wav delay_cc12=-1.5 + sample=kick.wav delay_cc14=3 delay_cc12=2 delay_cc12=-12 + )"); + synth.dispatchMessage(client, 0, "/region0/delay_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/delay_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/delay_cc12", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/delay_cc14", "", nullptr); + // TODO: activate for the new region parser ; ignore the second value + // synth.dispatchMessage(client, 0, "/region3/delay_cc12", "", nullptr); + std::vector expected { + "/region0/delay_cc12,f : { 0 }", + "/region1/delay_cc12,f : { 1.5 }", + "/region2/delay_cc12,f : { 0 }", + "/region3/delay_cc14,f : { 3 }", + // "/region3/delay_cc12,f : { 2 }", + }; + REQUIRE(messageList == expected); + } } TEST_CASE("[Values] Sample and direction") From 669f7ff79eb703b3bac0b04e227089d9e8cb7b9d Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 23 Feb 2021 13:45:29 +0100 Subject: [PATCH 305/668] Consider the previous velocity for triggers --- src/sfizz/Region.cpp | 3 +++ tests/RegionTriggersT.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index ec07ad48..230a18a8 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1484,6 +1484,9 @@ bool sfz::Region::registerNoteOn(int noteNumber, float velocity, float randValue if (!triggerOnNote) return false; + if (velocityOverride == VelocityOverride::previous) + velocity = midiState.getLastVelocity(); + const bool velOk = velocityRange.containsWithEnd(velocity); const bool randOk = randRange.contains(randValue) || (randValue == 1.0f && randRange.getEnd() == 1.0f); const bool firstLegatoNote = (trigger == Trigger::first && midiState.getActiveNotes() == 1); diff --git a/tests/RegionTriggersT.cpp b/tests/RegionTriggersT.cpp index fa8b5f59..6817acb5 100644 --- a/tests/RegionTriggersT.cpp +++ b/tests/RegionTriggersT.cpp @@ -301,3 +301,42 @@ TEST_CASE("[Triggers] sw_vel, with a note in between and sw_previous") }; REQUIRE(messageList == expected); } + +TEST_CASE("[Triggers] sw_vel, consider the previous velocity for triggers") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + key=60 sample=kick.wav + key=62 sw_previous=60 sw_vel=previous sample=snare.wav lovel=63 + )"); + + SECTION("Should trigger") { + synth.noteOn(0, 60, 127); + synth.noteOn(10, 62, 10); + synth.dispatchMessage(client, 0, "/num_active_voices", "", nullptr); + synth.dispatchMessage(client, 0, "/voice0/trigger_value", "", nullptr); + synth.dispatchMessage(client, 0, "/voice1/trigger_value", "", nullptr); + std::vector expected { + "/num_active_voices,i : { 2 }", + "/voice0/trigger_value,f : { 1 }", + "/voice1/trigger_value,f : { 1 }", + }; + REQUIRE(messageList == expected); + } + + SECTION("Should not trigger") { + synth.noteOn(0, 60, 10); + synth.noteOn(10, 62, 127); + synth.dispatchMessage(client, 0, "/num_active_voices", "", nullptr); + synth.dispatchMessage(client, 0, "/voice0/trigger_value", "", nullptr); + synth.dispatchMessage(client, 0, "/voice1/trigger_value", "", nullptr); + std::vector expected { + "/num_active_voices,i : { 1 }", + "/voice0/trigger_value,f : { 0.0787402 }", + }; + REQUIRE(messageList == expected); + } +} From 7d53fd9a488d3d64fb418e1fb4b00e0aac79a1ab Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 23 Feb 2021 14:14:51 +0100 Subject: [PATCH 306/668] Delay every modulation by the initial voice delay This includes ampeg as in #432 --- src/sfizz/Voice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 8a13834f..20e84be0 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -420,7 +420,7 @@ void Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe impl.bendSmoother_.setSmoothing(region->bendSmooth, impl.sampleRate_); impl.bendSmoother_.reset(centsFactor(region->getBendInCents(impl.resources_.midiState.getPitchBend()))); - impl.resources_.modMatrix.initVoice(impl.id_, region->getId(), delay); + impl.resources_.modMatrix.initVoice(impl.id_, region->getId(), impl.initialDelay_); impl.saveModulationTargets(region); } From c1e47b070256f35cec7f02fb917d134347f8074e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 17:59:00 +0100 Subject: [PATCH 307/668] Allow to request the keyswitch ranges --- src/sfizz/Synth.cpp | 13 +++++++++++++ src/sfizz/SynthMessaging.cpp | 8 ++++++++ src/sfizz/SynthPrivate.h | 1 + 3 files changed, 22 insertions(+) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index c2f73319..48295c40 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -250,6 +250,7 @@ void Synth::Impl::clear() changedCCsThisCycle_.clear(); keyLabels_.clear(); keySlots_.clear(); + swSlots_.clear(); keyswitchLabels_.clear(); globalOpcodes_.clear(); masterOpcodes_.clear(); @@ -745,6 +746,18 @@ void Synth::Impl::finalizeSfzLoad() for (unsigned key = loKey; key <= hiKey; ++key) keySlots_.set(key); } + // cache the set of keyswitches assigned + for (const RegionPtr& regionPtr : regions_) { + if (absl::optional sw = regionPtr->lastKeyswitch) { + swSlots_.set(*sw); + } + else if (absl::optional> swRange = regionPtr->lastKeyswitchRange) { + unsigned loKey = swRange->getStart(); + unsigned hiKey = swRange->getEnd(); + for (unsigned key = loKey; key <= hiKey; ++key) + swSlots_.set(key); + } + } } bool Synth::loadScalaFile(const fs::path& path) diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index f8672cca..c441807e 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -46,6 +46,14 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co //---------------------------------------------------------------------- + MATCH("/sw/slots", "") { + const BitArray<128>& switches = impl.swSlots_; + sfizz_blob_t blob { switches.data(), static_cast(switches.byte_size()) }; + client.receive<'b'>(delay, path, &blob); + } break; + + //---------------------------------------------------------------------- + MATCH("/cc/slots", "") { const BitArray& ccs = impl.currentUsedCCs_; sfizz_blob_t blob { ccs.data(), static_cast(ccs.byte_size()) }; diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index aaf6f72a..5c8b4479 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -217,6 +217,7 @@ struct Synth::Impl final: public Parser::Listener { std::map ccLabelsMap_; std::vector keyLabels_; BitArray<128> keySlots_; + BitArray<128> swSlots_; std::vector keyswitchLabels_; // Set as sw_default if present in the file From 1e2115731bc336d41f0e0309f0cc135f135492f5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 19:04:26 +0100 Subject: [PATCH 308/668] Keyswitch display in editor --- plugins/editor/src/editor/Editor.cpp | 18 ++++++++ plugins/editor/src/editor/GUIPiano.cpp | 58 ++++++++++++++++++++++++-- plugins/editor/src/editor/GUIPiano.h | 11 +++++ 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 83507bd6..64f5d91b 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -165,6 +165,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void updateStretchedTuningLabel(float stretchedTuning); void updateKeyUsed(unsigned key, bool used); + void updateKeyswitchUsed(unsigned key, bool used); void updateCCUsed(unsigned cc, bool used); void updateCCValue(unsigned cc, float value); void updateCCDefaultValue(unsigned cc, float value); @@ -223,6 +224,7 @@ void Editor::open(CFrame& frame) // request the whole Key and CC information impl.sendQueuedOSC("/key/slots", "", nullptr); + impl.sendQueuedOSC("/sw/slots", "", nullptr); impl.sendQueuedOSC("/cc/slots", "", nullptr); } @@ -249,6 +251,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) // request the whole Key and CC information sendQueuedOSC("/key/slots", "", nullptr); + sendQueuedOSC("/sw/slots", "", nullptr); sendQueuedOSC("/cc/slots", "", nullptr); } break; @@ -410,6 +413,14 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi updateKeyUsed(key, used); } } + else if (Messages::matchOSC("/sw/slots", path, indices) && !strcmp(sig, "b")) { + size_t numBits = 8 * args[0].b->size; + ConstBitSpan bits { args[0].b->data, numBits }; + for (unsigned key = 0; key < 128; ++key) { + bool used = key < numBits && bits.test(key); + updateKeyswitchUsed(key, used); + } + } else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) { size_t numBits = 8 * args[0].b->size; ConstBitSpan bits { args[0].b->data, numBits }; @@ -983,6 +994,7 @@ void Editor::Impl::changeSfzFile(const std::string& filePath) // request the whole Key and CC information sendQueuedOSC("/key/slots", "", nullptr); + sendQueuedOSC("/sw/slots", "", nullptr); sendQueuedOSC("/cc/slots", "", nullptr); } @@ -1294,6 +1306,12 @@ void Editor::Impl::updateKeyUsed(unsigned key, bool used) piano->setKeyUsed(key, used); } +void Editor::Impl::updateKeyswitchUsed(unsigned key, bool used) +{ + if (SPiano* piano = piano_) + piano->setKeyswitchUsed(key, used); +} + void Editor::Impl::updateCCUsed(unsigned cc, bool used) { if (SControlsPanel* panel = controlsPanel_) diff --git a/plugins/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp index 6dc990f1..0aa16586 100644 --- a/plugins/editor/src/editor/GUIPiano.cpp +++ b/plugins/editor/src/editor/GUIPiano.cpp @@ -50,6 +50,18 @@ void SPiano::setKeyUsed(unsigned key, bool used) invalid(); } +void SPiano::setKeyswitchUsed(unsigned key, bool used) +{ + if (key >= 128) + return; + + if (keyswitchUsed_.test(key) == used) + return; + + keyswitchUsed_.set(key, used); + invalid(); +} + void SPiano::setKeyValue(unsigned key, float value) { if (key >= 128) @@ -64,6 +76,19 @@ void SPiano::setKeyValue(unsigned key, float value) invalid(); } +SPiano::KeyRole SPiano::getKeyRole(unsigned key) +{ + if (key >= 128) + return KeyRole::Unused; + + if (keyUsed_.test(key)) + return KeyRole::Note; + if (keyswitchUsed_.test(key)) + return KeyRole::Switch; + + return KeyRole::Unused; +} + void SPiano::draw(CDrawContext* dc) { const Dimensions dim = getDimensions(false); @@ -85,12 +110,24 @@ void SPiano::draw(CDrawContext* dc) if (!black[key % 12]) { CRect rect = keyRect(key); - SColorHCY hcy(keyUsedHue_, 1.0, whiteKeyLuma_); - if (!keyUsed_[key] || allKeysUsed) { + SColorHCY hcy(0.0, 1.0, whiteKeyLuma_); + + switch (getKeyRole(key)) { + case KeyRole::Note: + if (allKeysUsed) + goto whiteKeyDefault; + hcy.h = keyUsedHue_; + break; + case KeyRole::Switch: + hcy.h = keySwitchHue_; + break; + default: whiteKeyDefault: hcy.y = 1.0; if (keyval_[key]) hcy.c = 0.0; + break; } + if (keyval_[key]) hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_); @@ -113,9 +150,22 @@ void SPiano::draw(CDrawContext* dc) if (black[key % 12]) { CRect rect = keyRect(key); - SColorHCY hcy(keyUsedHue_, 1.0, blackKeyLuma_); - if (!keyUsed_[key] || allKeysUsed) + SColorHCY hcy(0.0, 1.0, blackKeyLuma_); + + switch (getKeyRole(key)) { + case KeyRole::Note: + if (allKeysUsed) + goto blackKeyDefault; + hcy.h = keyUsedHue_; + break; + case KeyRole::Switch: + hcy.h = keySwitchHue_; + break; + default: blackKeyDefault: hcy.c = 0.0; + break; + } + if (keyval_[key]) hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_); diff --git a/plugins/editor/src/editor/GUIPiano.h b/plugins/editor/src/editor/GUIPiano.h index eafe115c..b01603c0 100644 --- a/plugins/editor/src/editor/GUIPiano.h +++ b/plugins/editor/src/editor/GUIPiano.h @@ -26,8 +26,17 @@ public: void setNumOctaves(unsigned octs); void setKeyUsed(unsigned key, bool used); + void setKeyswitchUsed(unsigned key, bool used); void setKeyValue(unsigned key, float value); + enum class KeyRole { + Unused, + Note, + Switch, + }; + + KeyRole getKeyRole(unsigned key); + std::function onKeyPressed; std::function onKeyReleased; @@ -57,6 +66,7 @@ private: unsigned octs_ {}; std::vector keyval_; std::bitset<128> keyUsed_; + std::bitset<128> keyswitchUsed_; unsigned mousePressedKey_ = ~0u; CCoord innerPaddingX_ = 4.0; @@ -67,6 +77,7 @@ private: float backgroundRadius_ = 5.0; float keyUsedHue_ = 0.55; + float keySwitchHue_ = 0.0; float whiteKeyLuma_ = 0.9; float blackKeyLuma_ = 0.5; float keyLumaPressDelta_ = 0.2; From 45bab7289f0acffc1c517c94eadb63df60820591 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 20:02:11 +0100 Subject: [PATCH 309/668] Load equal temperament if scl loading fails --- src/sfizz/Tuning.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/sfizz/Tuning.cpp b/src/sfizz/Tuning.cpp index 82ccdfe8..5130fe4a 100644 --- a/src/sfizz/Tuning.cpp +++ b/src/sfizz/Tuning.cpp @@ -162,50 +162,59 @@ Tuning::~Tuning() bool Tuning::loadScalaFile(const fs::path& path) { + Tunings::Scale scl; fs::ifstream stream(path); + if (stream.bad()) { DBG("Cannot open scale file: " << path); - return false; + goto failure; } - Tunings::Scale scl; try { scl = Tunings::readSCLStream(stream); } catch (Tunings::TuningError& error) { DBG("Tuning: " << error.what()); - return false; + goto failure; } if (scl.count <= 0) { DBG("The scale file is empty: " << path); - return false; + goto failure; } impl_->updateScale(scl, path); return true; + +failure: + loadEqualTemperamentScale(); + return false; } bool Tuning::loadScalaString(const std::string& text) { + Tunings::Scale scl; std::istringstream stream(text); - Tunings::Scale scl; try { scl = Tunings::readSCLStream(stream); } catch (Tunings::TuningError& error) { DBG("Tuning: " << error.what()); - return false; + goto failure; } if (scl.count <= 0) { DBG("Error loading scala string: " << text); - return false; + goto failure; } impl_->updateScale(scl); return true; + +failure: + loadEqualTemperamentScale(); + return false; } void Tuning::setScalaRootKey(int rootKey) From 8fcc374cd70272f5f1b7d0546154f48606a91aac Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 21:43:58 +0100 Subject: [PATCH 310/668] Check zenity presence, and block editor with message if missing --- plugins/editor/src/editor/Editor.cpp | 25 +++++++++++++++++++++ plugins/editor/src/editor/NativeHelpers.cpp | 9 +++++++- plugins/editor/src/editor/NativeHelpers.h | 4 ++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 64f5d91b..3d90ef38 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -768,6 +768,31 @@ void Editor::Impl::createFrameContents() mainView->setBackgroundColor(frameBackground); +#if LINUX + if (!isZenityAvailable()) { + CRect bounds = mainView->getViewSize(); + + CViewContainer* box = new CViewContainer(bounds); + mainView->addView(box); + box->setBackgroundColor(CColor(0x00, 0x00, 0x00, 0xc0)); + + CRect textSize = CRect(0, 0, 400, 80).centerInside(bounds); + CMultiLineTextLabel* textLabel = new CMultiLineTextLabel(textSize); + box->addView(textLabel); + textLabel->setTextInset(CPoint(10.0, 10.0)); + textLabel->setStyle(CParamDisplay::kRoundRectStyle); + textLabel->setRoundRectRadius(10.0); + textLabel->setFrameColor(CColor(0xb2, 0xb2, 0xb2)); + textLabel->setBackColor(CColor(0x2e, 0x34, 0x36)); + auto font = makeOwned("Roboto", 16.0); + textLabel->setFont(font); + textLabel->setLineLayout(CMultiLineTextLabel::LineLayout::wrap); + textLabel->setText( + "The required program \"zenity\" is missing.\n" + "Install this software package first, and restart sfizz."); + } +#endif + mainView_ = owned(mainView); } diff --git a/plugins/editor/src/editor/NativeHelpers.cpp b/plugins/editor/src/editor/NativeHelpers.cpp index 0a3ac516..393c3f8b 100644 --- a/plugins/editor/src/editor/NativeHelpers.cpp +++ b/plugins/editor/src/editor/NativeHelpers.cpp @@ -112,10 +112,12 @@ static std::vector createForkEnviron() return newEnv; } +static constexpr char zenityPath[] = "/usr/bin/zenity"; + bool askQuestion(const char *text) { char *argv[] = { - const_cast("/usr/bin/zenity"), + const_cast(zenityPath), const_cast("--question"), const_cast("--text"), const_cast(text), @@ -145,4 +147,9 @@ bool askQuestion(const char *text) return WEXITSTATUS(wstatus) == 0; } + +bool isZenityAvailable() +{ + return access(zenityPath, X_OK) == 0; +} #endif diff --git a/plugins/editor/src/editor/NativeHelpers.h b/plugins/editor/src/editor/NativeHelpers.h index 9ccb5410..92201d85 100644 --- a/plugins/editor/src/editor/NativeHelpers.h +++ b/plugins/editor/src/editor/NativeHelpers.h @@ -9,3 +9,7 @@ bool openFileInExternalEditor(const char *filename); bool openDirectoryInExplorer(const char *filename); bool askQuestion(const char *text); + +#if !defined(_WIN32) && !defined(__APPLE__) +bool isZenityAvailable(); +#endif From f16151e2c2f5fec0e30add6c7fde03884a9ae52d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 22:22:36 +0100 Subject: [PATCH 311/668] Add UI for scala file reset --- plugins/editor/layout/main.fl | 19 ++++++---- plugins/editor/src/editor/Editor.cpp | 15 ++++++++ plugins/editor/src/editor/layout/main.hpp | 43 ++++++++++++----------- 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index b96960f6..ebaf09ee 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -197,22 +197,22 @@ widget_class mainView {open } } } - Fl_Group {subPanels_[kPanelControls]} {open - xywh {5 110 790 285} + Fl_Group {subPanels_[kPanelControls]} { + xywh {5 110 790 285} hide class LogicalGroup } { Fl_Group {} {open xywh {5 110 790 285} box ROUNDED_BOX class RoundedGroup } { - Fl_Group controlsPanel_ {open selected + Fl_Group controlsPanel_ {open xywh {5 110 790 285} box THIN_DOWN_FRAME class ControlsPanel } {} } } Fl_Group {subPanels_[kPanelSettings]} {open - xywh {5 109 790 316} hide + xywh {5 109 790 316} class LogicalGroup } { Fl_Group {} { @@ -253,7 +253,7 @@ widget_class mainView {open } Fl_Group {} { label Tuning open - xywh {205 270 390 100} box ROUNDED_BOX labelsize 12 align 17 + xywh {175 270 415 100} box ROUNDED_BOX labelsize 12 align 17 class TitleGroup } { Fl_Box {} { @@ -283,13 +283,13 @@ widget_class mainView {open } Fl_Box {} { label {Scala file} - xywh {225 290 100 25} labelsize 12 + xywh {195 290 100 25} labelsize 12 class ValueLabel } Fl_Button scalaFileButton_ { label DefaultScale comment {tag=kTagLoadScalaFile} - xywh {225 330 100 25} labelsize 12 + xywh {195 330 100 25} labelsize 12 class ValueButton } Fl_Spinner scalaRootKeySlider_ { @@ -302,6 +302,11 @@ widget_class mainView {open xywh {375 330 30 25} labelsize 12 textsize 12 class ValueMenu } + Fl_Button scalaResetButton_ { + comment {tag=kTagResetScalaFile} selected + xywh {295 330 25 25} labelsize 12 + class ResetSomethingButton + } } Fl_Group userFilesGroup_ { label Files open diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 3d90ef38..98d06a60 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -70,6 +70,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { kTagSetOversampling, kTagSetPreloadSize, kTagLoadScalaFile, + kTagResetScalaFile, kTagSetScalaRootKey, kTagSetTuningFrequency, kTagSetStretchedTuning, @@ -81,6 +82,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { STextButton* sfzFileLabel_ = nullptr; CTextLabel* scalaFileLabel_ = nullptr; STextButton* scalaFileButton_ = nullptr; + STextButton* scalaResetButton_ = nullptr; CControl *volumeSlider_ = nullptr; CTextLabel* volumeLabel_ = nullptr; SValueMenu *numVoicesSlider_ = nullptr; @@ -583,6 +585,7 @@ void Editor::Impl::createFrameContents() typedef STextButton EditFileButton; typedef STextButton PreviousFileButton; typedef STextButton NextFileButton; + typedef STextButton ResetSomethingButton; typedef SPiano Piano; typedef SActionMenu ChevronDropDown; typedef SControlsPanel ControlsPanel; @@ -738,6 +741,11 @@ void Editor::Impl::createFrameContents() auto createNextFileButton = [&createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) { return createGlyphButton(u8"\ue0da", bounds, tag, fontsize); }; + auto createResetSomethingButton = [&createValueButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) { + STextButton* btn = createValueButton(bounds, tag, u8"\ue13a", kCenterText, fontsize); + btn->setFont(makeOwned("Sfizz Fluent System R20", fontsize)); + return btn; + }; auto createPiano = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int fontsize) { SPiano* piano = new SPiano(bounds); auto font = makeOwned("Roboto", fontsize); @@ -1471,6 +1479,13 @@ void Editor::Impl::valueChanged(CControl* ctl) Call::later([this]() { chooseScalaFile(); }); break; + case kTagResetScalaFile: + if (value != 1) + break; + + // TODO(jpc) Reset Scala File + break; + case kTagSetVolume: ctrl.uiSendValue(EditId::Volume, value); updateVolumeLabel(value); diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index 6ea0a316..d127a3bf 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -100,6 +100,7 @@ view__29->addView(view__39); LogicalGroup* const view__40 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); subPanels_[kPanelControls] = view__40; view__0->addView(view__40); +view__40->setVisible(false); RoundedGroup* const view__41 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); view__40->addView(view__41); ControlsPanel* const view__42 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); @@ -108,7 +109,6 @@ view__41->addView(view__42); LogicalGroup* const view__43 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); subPanels_[kPanelSettings] = view__43; view__0->addView(view__43); -view__43->setVisible(false); TitleGroup* const view__44 = createTitleGroup(CRect(255, 26, 535, 126), -1, "Engine", kCenterText, 12); view__43->addView(view__44); ValueMenu* const view__45 = createValueMenu(CRect(25, 60, 85, 85), kTagSetNumVoices, "", kCenterText, 12); @@ -126,39 +126,42 @@ view__44->addView(view__49); ValueMenu* const view__50 = createValueMenu(CRect(195, 60, 255, 85), kTagSetPreloadSize, "", kCenterText, 12); preloadSizeSlider_ = view__50; view__44->addView(view__50); -TitleGroup* const view__51 = createTitleGroup(CRect(200, 161, 590, 261), -1, "Tuning", kCenterText, 12); +TitleGroup* const view__51 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); view__43->addView(view__51); -ValueLabel* const view__52 = createValueLabel(CRect(125, 20, 205, 45), -1, "Root key", kCenterText, 12); +ValueLabel* const view__52 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); view__51->addView(view__52); -ValueMenu* const view__53 = createValueMenu(CRect(220, 60, 280, 85), kTagSetTuningFrequency, "", kCenterText, 12); +ValueMenu* const view__53 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); tuningFrequencySlider_ = view__53; view__51->addView(view__53); -ValueLabel* const view__54 = createValueLabel(CRect(210, 20, 290, 45), -1, "Frequency", kCenterText, 12); +ValueLabel* const view__54 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); view__51->addView(view__54); -StyledKnob* const view__55 = createStyledKnob(CRect(310, 45, 358, 93), kTagSetStretchedTuning, "", kCenterText, 14); +StyledKnob* const view__55 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); stretchedTuningSlider_ = view__55; view__51->addView(view__55); -ValueLabel* const view__56 = createValueLabel(CRect(295, 20, 375, 45), -1, "Stretch", kCenterText, 12); +ValueLabel* const view__56 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); view__51->addView(view__56); ValueLabel* const view__57 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); view__51->addView(view__57); ValueButton* const view__58 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); scalaFileButton_ = view__58; view__51->addView(view__58); -ValueMenu* const view__59 = createValueMenu(CRect(135, 60, 170, 85), kTagSetScalaRootKey, "", kCenterText, 12); +ValueMenu* const view__59 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); scalaRootKeySlider_ = view__59; view__51->addView(view__59); -ValueMenu* const view__60 = createValueMenu(CRect(170, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); +ValueMenu* const view__60 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); scalaRootOctaveSlider_ = view__60; view__51->addView(view__60); -TitleGroup* const view__61 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); -userFilesGroup_ = view__61; -view__43->addView(view__61); -ValueLabel* const view__62 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); -view__61->addView(view__62); -ValueButton* const view__63 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); -userFilesDirButton_ = view__63; -view__61->addView(view__63); -Piano* const view__64 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); -piano_ = view__64; -view__0->addView(view__64); +ResetSomethingButton* const view__61 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); +scalaResetButton_ = view__61; +view__51->addView(view__61); +TitleGroup* const view__62 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); +userFilesGroup_ = view__62; +view__43->addView(view__62); +ValueLabel* const view__63 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); +view__62->addView(view__63); +ValueButton* const view__64 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); +userFilesDirButton_ = view__64; +view__62->addView(view__64); +Piano* const view__65 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); +piano_ = view__65; +view__0->addView(view__65); From dc0f8692f228b5fe4bb019a4a4ffd13badc6b8e1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 23 Feb 2021 22:52:35 +0100 Subject: [PATCH 312/668] Add button to reset scala file --- plugins/editor/src/editor/Editor.cpp | 2 +- plugins/lv2/sfizz.cpp | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 98d06a60..b4f3f08e 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -1483,7 +1483,7 @@ void Editor::Impl::valueChanged(CControl* ctl) if (value != 1) break; - // TODO(jpc) Reset Scala File + changeScalaFile(std::string()); break; case kTagSetVolume: diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 3ab874ed..61d6c581 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -1178,6 +1178,14 @@ static bool sfizz_lv2_load_file(LV2_Handle instance, const char *file_path) { sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + + char buf[MAX_PATH_SIZE]; + if (file_path[0] == '\0') + { + sfizz_lv2_get_default_sfz_path(instance, buf, MAX_PATH_SIZE); + file_path = buf; + } + bool status = sfizz_load_file(self->synth, file_path); sfizz_lv2_update_file_info(self, file_path); return status; @@ -1187,6 +1195,14 @@ static bool sfizz_lv2_load_scala_file(LV2_Handle instance, const char *file_path) { sfizz_plugin_t *self = (sfizz_plugin_t *)instance; + + char buf[MAX_PATH_SIZE]; + if (file_path[0] == '\0') + { + sfizz_lv2_get_default_scala_path(instance, buf, MAX_PATH_SIZE); + file_path = buf; + } + bool status = sfizz_load_scala_file(self->synth, file_path); if (file_path != self->scala_file_path) strcpy(self->scala_file_path, file_path); @@ -1308,7 +1324,7 @@ restore(LV2_Handle instance, "[sfizz] Error while restoring the file %s\n", self->sfz_file_path); } - if (sfizz_load_scala_file(self->synth, self->scala_file_path)) + if (sfizz_lv2_load_scala_file(self->synth, self->scala_file_path)) { lv2_log_note(&self->logger, "[sfizz] Restoring the scale %s\n", self->scala_file_path); From 95fb11ee3422c3ae25078693d21cdd8147042238 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 01:07:35 +0100 Subject: [PATCH 313/668] Chevron menu for polyphony --- plugins/editor/layout/main.fl | 33 ++- plugins/editor/src/editor/Editor.cpp | 20 +- plugins/editor/src/editor/GUIComponents.cpp | 30 +++ plugins/editor/src/editor/GUIComponents.h | 9 + plugins/editor/src/editor/layout/main.hpp | 220 ++++++++++---------- 5 files changed, 176 insertions(+), 136 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index ebaf09ee..84a6f380 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -11,7 +11,7 @@ widget_class mainView {open class Background } Fl_Group {} { - comment {theme=darkTheme} + comment {theme=darkTheme} open xywh {0 0 800 110} class LogicalGroup } { @@ -95,7 +95,7 @@ widget_class mainView {open class Label } Fl_Box numVoicesLabel_ { - xywh {380 76 50 25} labelsize 12 align 16 + xywh {380 76 35 25} labelsize 12 align 16 class Label } Fl_Box {} { @@ -107,6 +107,11 @@ widget_class mainView {open xywh {500 76 50 25} labelsize 12 align 16 class Label } + Fl_Button numVoicesSlider_ { + comment {tag=kTagSetNumVoices} + xywh {415 80 20 20} labelsize 16 + class ChevronValueDropDown + } } Fl_Group {} {open xywh {570 5 225 100} box ROUNDED_BOX @@ -211,43 +216,33 @@ widget_class mainView {open } {} } } - Fl_Group {subPanels_[kPanelSettings]} {open + Fl_Group {subPanels_[kPanelSettings]} {open selected xywh {5 109 790 316} class LogicalGroup } { Fl_Group {} { label Engine open - xywh {260 135 280 100} box ROUNDED_BOX labelsize 12 align 17 + xywh {295 135 205 100} box ROUNDED_BOX labelsize 12 align 17 class TitleGroup } { - Fl_Spinner numVoicesSlider_ { - comment {tag=kTagSetNumVoices} - xywh {285 195 60 25} labelsize 12 textsize 12 - class ValueMenu - } - Fl_Box {} { - label Polyphony - xywh {275 155 80 25} labelsize 12 - class ValueLabel - } Fl_Spinner oversamplingSlider_ { comment {tag=kTagSetOversampling} - xywh {370 195 60 25} labelsize 12 textsize 12 + xywh {330 195 60 25} labelsize 12 textsize 12 class ValueMenu } Fl_Box {} { label Oversampling - xywh {360 155 80 25} labelsize 12 + xywh {320 155 80 25} labelsize 12 class ValueLabel } Fl_Box {} { label {Preload size} - xywh {445 155 80 25} labelsize 12 + xywh {405 155 80 25} labelsize 12 class ValueLabel } Fl_Spinner preloadSizeSlider_ { comment {tag=kTagSetPreloadSize} - xywh {455 195 60 25} labelsize 12 textsize 12 + xywh {415 195 60 25} labelsize 12 textsize 12 class ValueMenu } } @@ -303,7 +298,7 @@ widget_class mainView {open class ValueMenu } Fl_Button scalaResetButton_ { - comment {tag=kTagResetScalaFile} selected + comment {tag=kTagResetScalaFile} xywh {295 330 25 25} labelsize 12 class ResetSomethingButton } diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index b4f3f08e..d5c5fc58 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -588,6 +588,7 @@ void Editor::Impl::createFrameContents() typedef STextButton ResetSomethingButton; typedef SPiano Piano; typedef SActionMenu ChevronDropDown; + typedef SValueMenu ChevronValueDropDown; typedef SControlsPanel ControlsPanel; auto createLogicalGroup = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { @@ -762,6 +763,19 @@ void Editor::Impl::createFrameContents() menu->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); return menu; }; + auto createChevronValueDropDown = [this, &theme](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) { + SValueMenu* menu = new SValueMenu(bounds, this, tag); + menu->setValueToStringFunction2([](float, std::string& result, CParamDisplay*) -> bool { + result = u8"\ue0d7"; + return true; + }); + menu->setFont(makeOwned("Sfizz Fluent System R20", fontsize)); + menu->setFontColor(theme->icon); + menu->setHoverColor(theme->iconHighlight); + menu->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + menu->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + return menu; + }; auto createBackground = [&background](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { CViewContainer* container = new CViewContainer(bounds); container->setBackground(background); @@ -836,12 +850,6 @@ void Editor::Impl::createFrameContents() for (int value : {1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 224, 256}) numVoicesSlider_->addEntry(std::to_string(value), value); - numVoicesSlider_->setValueToStringFunction2( - [](float value, std::string& result, CParamDisplay*) -> bool - { - result = std::to_string(static_cast(value)); - return true; - }); for (int log2value = 0; log2value <= 3; ++log2value) { int value = 1 << log2value; diff --git a/plugins/editor/src/editor/GUIComponents.cpp b/plugins/editor/src/editor/GUIComponents.cpp index bc3d718b..c0025af0 100644 --- a/plugins/editor/src/editor/GUIComponents.cpp +++ b/plugins/editor/src/editor/GUIComponents.cpp @@ -164,6 +164,12 @@ SValueMenu::SValueMenu(const CRect& bounds, IControlListener* listener, int32_t setWheelInc(0.0f); } +void SValueMenu::setHoverColor(const CColor& color) +{ + hoverColor_ = color; + invalid(); +} + CMenuItem* SValueMenu::addEntry(CMenuItem* item, float value, int32_t index) { if (index < 0 || index > getNbEntries()) { @@ -197,6 +203,30 @@ int32_t SValueMenu::getNbEntries() const return static_cast(menuItems_.size()); } +void SValueMenu::draw(CDrawContext* dc) +{ + CColor backupColor = fontColor; + if (hovered_) + fontColor = hoverColor_; + CParamDisplay::draw(dc); + if (hovered_) + fontColor = backupColor; +} + +CMouseEventResult SValueMenu::onMouseEntered(CPoint& where, const CButtonState& buttons) +{ + hovered_ = true; + invalid(); + return CParamDisplay::onMouseEntered(where, buttons); +} + +CMouseEventResult SValueMenu::onMouseExited(CPoint& where, const CButtonState& buttons) +{ + hovered_ = false; + invalid(); + return CParamDisplay::onMouseExited(where, buttons); +} + CMouseEventResult SValueMenu::onMouseDown(CPoint& where, const CButtonState& buttons) { (void)where; diff --git a/plugins/editor/src/editor/GUIComponents.h b/plugins/editor/src/editor/GUIComponents.h index 8c2237ec..b7de29ff 100644 --- a/plugins/editor/src/editor/GUIComponents.h +++ b/plugins/editor/src/editor/GUIComponents.h @@ -92,16 +92,25 @@ private: class SValueMenu : public CParamDisplay { public: explicit SValueMenu(const CRect& bounds, IControlListener* listener, int32_t tag); + CColor getHoverColor() const { return hoverColor_; } + void setHoverColor(const CColor& color); CMenuItem* addEntry(CMenuItem* item, float value, int32_t index = -1); CMenuItem* addEntry(const UTF8String& title, float value, int32_t index = -1, int32_t itemFlags = CMenuItem::kNoFlags); CMenuItem* addSeparator(int32_t index = -1); int32_t getNbEntries() const; protected: + void draw(CDrawContext* dc) override; + CMouseEventResult onMouseEntered(CPoint& where, const CButtonState& buttons) override; + CMouseEventResult onMouseExited(CPoint& where, const CButtonState& buttons) override; CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override; bool onWheel(const CPoint& where, const CMouseWheelAxis& axis, const float& distance, const CButtonState& buttons) override; private: + CColor hoverColor_; + bool hovered_ = false; + + // class MenuListener; // diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index d127a3bf..ed8b7d10 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -41,7 +41,7 @@ infoVoicesLabel_ = view__17; view__8->addView(view__17); Label* const view__18 = createLabel(CRect(130, 71, 190, 96), -1, "Max:", kRightText, 12); view__8->addView(view__18); -Label* const view__19 = createLabel(CRect(195, 71, 245, 96), -1, "", kCenterText, 12); +Label* const view__19 = createLabel(CRect(195, 71, 230, 96), -1, "", kCenterText, 12); numVoicesLabel_ = view__19; view__8->addView(view__19); Label* const view__20 = createLabel(CRect(250, 71, 310, 96), -1, "Memory:", kRightText, 12); @@ -49,119 +49,117 @@ view__8->addView(view__20); Label* const view__21 = createLabel(CRect(315, 71, 365, 96), -1, "", kCenterText, 12); memoryLabel_ = view__21; view__8->addView(view__21); -RoundedGroup* const view__22 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14); -view__2->addView(view__22); -Knob48* const view__23 = createKnob48(CRect(45, 15, 93, 63), -1, "", kCenterText, 14); -view__22->addView(view__23); -view__23->setVisible(false); -ValueLabel* const view__24 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12); -view__22->addView(view__24); +ChevronValueDropDown* const view__22 = createChevronValueDropDown(CRect(230, 75, 250, 95), kTagSetNumVoices, "", kCenterText, 16); +numVoicesSlider_ = view__22; +view__8->addView(view__22); +RoundedGroup* const view__23 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14); +view__2->addView(view__23); +Knob48* const view__24 = createKnob48(CRect(45, 15, 93, 63), -1, "", kCenterText, 14); +view__23->addView(view__24); view__24->setVisible(false); -StyledKnob* const view__25 = createStyledKnob(CRect(110, 15, 158, 63), kTagSetVolume, "", kCenterText, 14); -volumeSlider_ = view__25; -view__22->addView(view__25); -ValueLabel* const view__26 = createValueLabel(CRect(105, 65, 165, 87), -1, "0.0 dB", kCenterText, 12); -volumeLabel_ = view__26; -view__22->addView(view__26); -VMeter* const view__27 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); -view__22->addView(view__27); +ValueLabel* const view__25 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12); +view__23->addView(view__25); +view__25->setVisible(false); +StyledKnob* const view__26 = createStyledKnob(CRect(110, 15, 158, 63), kTagSetVolume, "", kCenterText, 14); +volumeSlider_ = view__26; +view__23->addView(view__26); +ValueLabel* const view__27 = createValueLabel(CRect(105, 65, 165, 87), -1, "0.0 dB", kCenterText, 12); +volumeLabel_ = view__27; +view__23->addView(view__27); +VMeter* const view__28 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); +view__23->addView(view__28); enterTheme(defaultTheme); -LogicalGroup* const view__28 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); -subPanels_[kPanelGeneral] = view__28; -view__0->addView(view__28); -view__28->setVisible(false); -RoundedGroup* const view__29 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); -view__28->addView(view__29); -Label* const view__30 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); +LogicalGroup* const view__29 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); +subPanels_[kPanelGeneral] = view__29; +view__0->addView(view__29); +view__29->setVisible(false); +RoundedGroup* const view__30 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); view__29->addView(view__30); -Label* const view__31 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14); -view__29->addView(view__31); -Label* const view__32 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14); -view__29->addView(view__32); -Label* const view__33 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14); -view__29->addView(view__33); -Label* const view__34 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14); -view__29->addView(view__34); -Label* const view__35 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14); -infoCurvesLabel_ = view__35; -view__29->addView(view__35); -Label* const view__36 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14); -infoMastersLabel_ = view__36; -view__29->addView(view__36); -Label* const view__37 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14); -infoGroupsLabel_ = view__37; -view__29->addView(view__37); -Label* const view__38 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14); -infoRegionsLabel_ = view__38; -view__29->addView(view__38); -Label* const view__39 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14); -infoSamplesLabel_ = view__39; -view__29->addView(view__39); -LogicalGroup* const view__40 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); -subPanels_[kPanelControls] = view__40; -view__0->addView(view__40); -view__40->setVisible(false); -RoundedGroup* const view__41 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); -view__40->addView(view__41); -ControlsPanel* const view__42 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); -controlsPanel_ = view__42; +Label* const view__31 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); +view__30->addView(view__31); +Label* const view__32 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14); +view__30->addView(view__32); +Label* const view__33 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14); +view__30->addView(view__33); +Label* const view__34 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14); +view__30->addView(view__34); +Label* const view__35 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14); +view__30->addView(view__35); +Label* const view__36 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14); +infoCurvesLabel_ = view__36; +view__30->addView(view__36); +Label* const view__37 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14); +infoMastersLabel_ = view__37; +view__30->addView(view__37); +Label* const view__38 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14); +infoGroupsLabel_ = view__38; +view__30->addView(view__38); +Label* const view__39 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14); +infoRegionsLabel_ = view__39; +view__30->addView(view__39); +Label* const view__40 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14); +infoSamplesLabel_ = view__40; +view__30->addView(view__40); +LogicalGroup* const view__41 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); +subPanels_[kPanelControls] = view__41; +view__0->addView(view__41); +view__41->setVisible(false); +RoundedGroup* const view__42 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); view__41->addView(view__42); -LogicalGroup* const view__43 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); -subPanels_[kPanelSettings] = view__43; -view__0->addView(view__43); -TitleGroup* const view__44 = createTitleGroup(CRect(255, 26, 535, 126), -1, "Engine", kCenterText, 12); -view__43->addView(view__44); -ValueMenu* const view__45 = createValueMenu(CRect(25, 60, 85, 85), kTagSetNumVoices, "", kCenterText, 12); -numVoicesSlider_ = view__45; +ControlsPanel* const view__43 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); +controlsPanel_ = view__43; +view__42->addView(view__43); +LogicalGroup* const view__44 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); +subPanels_[kPanelSettings] = view__44; +view__0->addView(view__44); +TitleGroup* const view__45 = createTitleGroup(CRect(290, 26, 495, 126), -1, "Engine", kCenterText, 12); view__44->addView(view__45); -ValueLabel* const view__46 = createValueLabel(CRect(15, 20, 95, 45), -1, "Polyphony", kCenterText, 12); -view__44->addView(view__46); -ValueMenu* const view__47 = createValueMenu(CRect(110, 60, 170, 85), kTagSetOversampling, "", kCenterText, 12); -oversamplingSlider_ = view__47; -view__44->addView(view__47); -ValueLabel* const view__48 = createValueLabel(CRect(100, 20, 180, 45), -1, "Oversampling", kCenterText, 12); -view__44->addView(view__48); -ValueLabel* const view__49 = createValueLabel(CRect(185, 20, 265, 45), -1, "Preload size", kCenterText, 12); -view__44->addView(view__49); -ValueMenu* const view__50 = createValueMenu(CRect(195, 60, 255, 85), kTagSetPreloadSize, "", kCenterText, 12); -preloadSizeSlider_ = view__50; +ValueMenu* const view__46 = createValueMenu(CRect(35, 60, 95, 85), kTagSetOversampling, "", kCenterText, 12); +oversamplingSlider_ = view__46; +view__45->addView(view__46); +ValueLabel* const view__47 = createValueLabel(CRect(25, 20, 105, 45), -1, "Oversampling", kCenterText, 12); +view__45->addView(view__47); +ValueLabel* const view__48 = createValueLabel(CRect(110, 20, 190, 45), -1, "Preload size", kCenterText, 12); +view__45->addView(view__48); +ValueMenu* const view__49 = createValueMenu(CRect(120, 60, 180, 85), kTagSetPreloadSize, "", kCenterText, 12); +preloadSizeSlider_ = view__49; +view__45->addView(view__49); +TitleGroup* const view__50 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); view__44->addView(view__50); -TitleGroup* const view__51 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); -view__43->addView(view__51); -ValueLabel* const view__52 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); -view__51->addView(view__52); -ValueMenu* const view__53 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); -tuningFrequencySlider_ = view__53; -view__51->addView(view__53); -ValueLabel* const view__54 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); -view__51->addView(view__54); -StyledKnob* const view__55 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); -stretchedTuningSlider_ = view__55; -view__51->addView(view__55); -ValueLabel* const view__56 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); -view__51->addView(view__56); -ValueLabel* const view__57 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); -view__51->addView(view__57); -ValueButton* const view__58 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); -scalaFileButton_ = view__58; -view__51->addView(view__58); -ValueMenu* const view__59 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); -scalaRootKeySlider_ = view__59; -view__51->addView(view__59); -ValueMenu* const view__60 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); -scalaRootOctaveSlider_ = view__60; -view__51->addView(view__60); -ResetSomethingButton* const view__61 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); -scalaResetButton_ = view__61; -view__51->addView(view__61); -TitleGroup* const view__62 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); -userFilesGroup_ = view__62; -view__43->addView(view__62); -ValueLabel* const view__63 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); -view__62->addView(view__63); -ValueButton* const view__64 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); -userFilesDirButton_ = view__64; -view__62->addView(view__64); -Piano* const view__65 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); -piano_ = view__65; -view__0->addView(view__65); +ValueLabel* const view__51 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); +view__50->addView(view__51); +ValueMenu* const view__52 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); +tuningFrequencySlider_ = view__52; +view__50->addView(view__52); +ValueLabel* const view__53 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); +view__50->addView(view__53); +StyledKnob* const view__54 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); +stretchedTuningSlider_ = view__54; +view__50->addView(view__54); +ValueLabel* const view__55 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); +view__50->addView(view__55); +ValueLabel* const view__56 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); +view__50->addView(view__56); +ValueButton* const view__57 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); +scalaFileButton_ = view__57; +view__50->addView(view__57); +ValueMenu* const view__58 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); +scalaRootKeySlider_ = view__58; +view__50->addView(view__58); +ValueMenu* const view__59 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); +scalaRootOctaveSlider_ = view__59; +view__50->addView(view__59); +ResetSomethingButton* const view__60 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); +scalaResetButton_ = view__60; +view__50->addView(view__60); +TitleGroup* const view__61 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); +userFilesGroup_ = view__61; +view__44->addView(view__61); +ValueLabel* const view__62 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); +view__61->addView(view__62); +ValueButton* const view__63 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); +userFilesDirButton_ = view__63; +view__61->addView(view__63); +Piano* const view__64 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); +piano_ = view__64; +view__0->addView(view__64); From c6934924624ad1d9bb87d6fbebefb3e3105a76b7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 01:08:40 +0100 Subject: [PATCH 314/668] Fix some warnings --- plugins/editor/src/editor/Editor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index d5c5fc58..c45e0509 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -1391,11 +1391,13 @@ void Editor::Impl::performCCValueChange(unsigned cc, float value) void Editor::Impl::performCCBeginEdit(unsigned cc) { // TODO(jpc) CC as parameters and automation + (void)cc; } void Editor::Impl::performCCEndEdit(unsigned cc) { // TODO(jpc) CC as parameters and automation + (void)cc; } void Editor::Impl::setActivePanel(unsigned panelId) From 79b6f3228113db6b854e61297743ecf8bcb3c5e4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 01:12:22 +0100 Subject: [PATCH 315/668] Make simpler: remove the typedefs --- plugins/editor/src/editor/Editor.cpp | 30 ---- plugins/editor/src/editor/layout/main.hpp | 130 +++++++++--------- .../tools/layout-maker/sources/main.cpp | 2 +- 3 files changed, 66 insertions(+), 96 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index c45e0509..5b3ef16f 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -561,36 +561,6 @@ void Editor::Impl::createFrameContents() Theme* theme = &defaultTheme; auto enterTheme = [&theme](Theme& t) { theme = &t; }; - typedef CViewContainer LogicalGroup; - typedef SBoxContainer RoundedGroup; - typedef STitleContainer TitleGroup; - typedef CKickButton SfizzMainButton; - typedef CTextLabel Label; - typedef CViewContainer HLine; - typedef CAnimKnob Knob48; - typedef SStyledKnob StyledKnob; - typedef CTextLabel ValueLabel; - typedef CViewContainer VMeter; - typedef SValueMenu ValueMenu; - typedef CViewContainer Background; -#if 0 - typedef CTextButton Button; -#endif - typedef STextButton ClickableLabel; - typedef STextButton ValueButton; - typedef STextButton LoadFileButton; - typedef STextButton CCButton; - typedef STextButton HomeButton; - typedef STextButton SettingsButton; - typedef STextButton EditFileButton; - typedef STextButton PreviousFileButton; - typedef STextButton NextFileButton; - typedef STextButton ResetSomethingButton; - typedef SPiano Piano; - typedef SActionMenu ChevronDropDown; - typedef SValueMenu ChevronValueDropDown; - typedef SControlsPanel ControlsPanel; - auto createLogicalGroup = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { CViewContainer* container = new CViewContainer(bounds); container->setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index ed8b7d10..469887fc 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -1,165 +1,165 @@ /* This file is generated by the layout maker tool. */ -LogicalGroup* const view__0 = createLogicalGroup(CRect(0, 0, 800, 475), -1, "", kCenterText, 14); +auto* const view__0 = createLogicalGroup(CRect(0, 0, 800, 475), -1, "", kCenterText, 14); mainView = view__0; -Background* const view__1 = createBackground(CRect(190, 110, 790, 390), -1, "", kCenterText, 14); +auto* const view__1 = createBackground(CRect(190, 110, 790, 390), -1, "", kCenterText, 14); view__0->addView(view__1); enterTheme(darkTheme); -LogicalGroup* const view__2 = createLogicalGroup(CRect(0, 0, 800, 110), -1, "", kCenterText, 14); +auto* const view__2 = createLogicalGroup(CRect(0, 0, 800, 110), -1, "", kCenterText, 14); view__0->addView(view__2); -RoundedGroup* const view__3 = createRoundedGroup(CRect(5, 4, 180, 105), -1, "", kCenterText, 14); +auto* const view__3 = createRoundedGroup(CRect(5, 4, 180, 105), -1, "", kCenterText, 14); view__2->addView(view__3); -SfizzMainButton* const view__4 = createSfizzMainButton(CRect(30, 5, 150, 65), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 14); +auto* const view__4 = createSfizzMainButton(CRect(30, 5, 150, 65), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 14); view__3->addView(view__4); -HomeButton* const view__5 = createHomeButton(CRect(44, 69, 69, 94), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 24); +auto* const view__5 = createHomeButton(CRect(44, 69, 69, 94), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 24); view__3->addView(view__5); -CCButton* const view__6 = createCCButton(CRect(76, 69, 101, 94), kTagFirstChangePanel+kPanelControls, "", kCenterText, 24); +auto* const view__6 = createCCButton(CRect(76, 69, 101, 94), kTagFirstChangePanel+kPanelControls, "", kCenterText, 24); view__3->addView(view__6); -SettingsButton* const view__7 = createSettingsButton(CRect(107, 69, 132, 94), kTagFirstChangePanel+kPanelSettings, "", kCenterText, 24); +auto* const view__7 = createSettingsButton(CRect(107, 69, 132, 94), kTagFirstChangePanel+kPanelSettings, "", kCenterText, 24); view__3->addView(view__7); -RoundedGroup* const view__8 = createRoundedGroup(CRect(185, 5, 565, 105), -1, "", kCenterText, 14); +auto* const view__8 = createRoundedGroup(CRect(185, 5, 565, 105), -1, "", kCenterText, 14); view__2->addView(view__8); -HLine* const view__9 = createHLine(CRect(10, 36, 370, 41), -1, "", kCenterText, 14); +auto* const view__9 = createHLine(CRect(10, 36, 370, 41), -1, "", kCenterText, 14); view__8->addView(view__9); -HLine* const view__10 = createHLine(CRect(10, 68, 370, 73), -1, "", kCenterText, 14); +auto* const view__10 = createHLine(CRect(10, 68, 370, 73), -1, "", kCenterText, 14); view__8->addView(view__10); -ClickableLabel* const view__11 = createClickableLabel(CRect(10, 6, 260, 37), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20); +auto* const view__11 = createClickableLabel(CRect(10, 6, 260, 37), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20); sfzFileLabel_ = view__11; view__8->addView(view__11); -Label* const view__12 = createLabel(CRect(10, 39, 260, 69), -1, "Key switch:", kLeftText, 20); +auto* const view__12 = createLabel(CRect(10, 39, 260, 69), -1, "Key switch:", kLeftText, 20); view__8->addView(view__12); -Label* const view__13 = createLabel(CRect(10, 71, 70, 96), -1, "Voices:", kRightText, 12); +auto* const view__13 = createLabel(CRect(10, 71, 70, 96), -1, "Voices:", kRightText, 12); view__8->addView(view__13); -PreviousFileButton* const view__14 = createPreviousFileButton(CRect(295, 9, 320, 34), kTagPreviousSfzFile, "", kCenterText, 24); +auto* const view__14 = createPreviousFileButton(CRect(295, 9, 320, 34), kTagPreviousSfzFile, "", kCenterText, 24); view__8->addView(view__14); -NextFileButton* const view__15 = createNextFileButton(CRect(320, 9, 345, 34), kTagNextSfzFile, "", kCenterText, 24); +auto* const view__15 = createNextFileButton(CRect(320, 9, 345, 34), kTagNextSfzFile, "", kCenterText, 24); view__8->addView(view__15); -ChevronDropDown* const view__16 = createChevronDropDown(CRect(345, 9, 370, 34), kTagFileOperations, "", kCenterText, 24); +auto* const view__16 = createChevronDropDown(CRect(345, 9, 370, 34), kTagFileOperations, "", kCenterText, 24); fileOperationsMenu_ = view__16; view__8->addView(view__16); -Label* const view__17 = createLabel(CRect(75, 71, 125, 96), -1, "", kCenterText, 12); +auto* const view__17 = createLabel(CRect(75, 71, 125, 96), -1, "", kCenterText, 12); infoVoicesLabel_ = view__17; view__8->addView(view__17); -Label* const view__18 = createLabel(CRect(130, 71, 190, 96), -1, "Max:", kRightText, 12); +auto* const view__18 = createLabel(CRect(130, 71, 190, 96), -1, "Max:", kRightText, 12); view__8->addView(view__18); -Label* const view__19 = createLabel(CRect(195, 71, 230, 96), -1, "", kCenterText, 12); +auto* const view__19 = createLabel(CRect(195, 71, 230, 96), -1, "", kCenterText, 12); numVoicesLabel_ = view__19; view__8->addView(view__19); -Label* const view__20 = createLabel(CRect(250, 71, 310, 96), -1, "Memory:", kRightText, 12); +auto* const view__20 = createLabel(CRect(250, 71, 310, 96), -1, "Memory:", kRightText, 12); view__8->addView(view__20); -Label* const view__21 = createLabel(CRect(315, 71, 365, 96), -1, "", kCenterText, 12); +auto* const view__21 = createLabel(CRect(315, 71, 365, 96), -1, "", kCenterText, 12); memoryLabel_ = view__21; view__8->addView(view__21); -ChevronValueDropDown* const view__22 = createChevronValueDropDown(CRect(230, 75, 250, 95), kTagSetNumVoices, "", kCenterText, 16); +auto* const view__22 = createChevronValueDropDown(CRect(230, 75, 250, 95), kTagSetNumVoices, "", kCenterText, 16); numVoicesSlider_ = view__22; view__8->addView(view__22); -RoundedGroup* const view__23 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14); +auto* const view__23 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14); view__2->addView(view__23); -Knob48* const view__24 = createKnob48(CRect(45, 15, 93, 63), -1, "", kCenterText, 14); +auto* const view__24 = createKnob48(CRect(45, 15, 93, 63), -1, "", kCenterText, 14); view__23->addView(view__24); view__24->setVisible(false); -ValueLabel* const view__25 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12); +auto* const view__25 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12); view__23->addView(view__25); view__25->setVisible(false); -StyledKnob* const view__26 = createStyledKnob(CRect(110, 15, 158, 63), kTagSetVolume, "", kCenterText, 14); +auto* const view__26 = createStyledKnob(CRect(110, 15, 158, 63), kTagSetVolume, "", kCenterText, 14); volumeSlider_ = view__26; view__23->addView(view__26); -ValueLabel* const view__27 = createValueLabel(CRect(105, 65, 165, 87), -1, "0.0 dB", kCenterText, 12); +auto* const view__27 = createValueLabel(CRect(105, 65, 165, 87), -1, "0.0 dB", kCenterText, 12); volumeLabel_ = view__27; view__23->addView(view__27); -VMeter* const view__28 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); +auto* const view__28 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); view__23->addView(view__28); enterTheme(defaultTheme); -LogicalGroup* const view__29 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); +auto* const view__29 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); subPanels_[kPanelGeneral] = view__29; view__0->addView(view__29); view__29->setVisible(false); -RoundedGroup* const view__30 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); +auto* const view__30 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); view__29->addView(view__30); -Label* const view__31 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); +auto* const view__31 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); view__30->addView(view__31); -Label* const view__32 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14); +auto* const view__32 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14); view__30->addView(view__32); -Label* const view__33 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14); +auto* const view__33 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14); view__30->addView(view__33); -Label* const view__34 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14); +auto* const view__34 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14); view__30->addView(view__34); -Label* const view__35 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14); +auto* const view__35 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14); view__30->addView(view__35); -Label* const view__36 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14); +auto* const view__36 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14); infoCurvesLabel_ = view__36; view__30->addView(view__36); -Label* const view__37 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14); +auto* const view__37 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14); infoMastersLabel_ = view__37; view__30->addView(view__37); -Label* const view__38 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14); +auto* const view__38 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14); infoGroupsLabel_ = view__38; view__30->addView(view__38); -Label* const view__39 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14); +auto* const view__39 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14); infoRegionsLabel_ = view__39; view__30->addView(view__39); -Label* const view__40 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14); +auto* const view__40 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14); infoSamplesLabel_ = view__40; view__30->addView(view__40); -LogicalGroup* const view__41 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); +auto* const view__41 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); subPanels_[kPanelControls] = view__41; view__0->addView(view__41); view__41->setVisible(false); -RoundedGroup* const view__42 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); +auto* const view__42 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); view__41->addView(view__42); -ControlsPanel* const view__43 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); +auto* const view__43 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); controlsPanel_ = view__43; view__42->addView(view__43); -LogicalGroup* const view__44 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); +auto* const view__44 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); subPanels_[kPanelSettings] = view__44; view__0->addView(view__44); -TitleGroup* const view__45 = createTitleGroup(CRect(290, 26, 495, 126), -1, "Engine", kCenterText, 12); +auto* const view__45 = createTitleGroup(CRect(290, 26, 495, 126), -1, "Engine", kCenterText, 12); view__44->addView(view__45); -ValueMenu* const view__46 = createValueMenu(CRect(35, 60, 95, 85), kTagSetOversampling, "", kCenterText, 12); +auto* const view__46 = createValueMenu(CRect(35, 60, 95, 85), kTagSetOversampling, "", kCenterText, 12); oversamplingSlider_ = view__46; view__45->addView(view__46); -ValueLabel* const view__47 = createValueLabel(CRect(25, 20, 105, 45), -1, "Oversampling", kCenterText, 12); +auto* const view__47 = createValueLabel(CRect(25, 20, 105, 45), -1, "Oversampling", kCenterText, 12); view__45->addView(view__47); -ValueLabel* const view__48 = createValueLabel(CRect(110, 20, 190, 45), -1, "Preload size", kCenterText, 12); +auto* const view__48 = createValueLabel(CRect(110, 20, 190, 45), -1, "Preload size", kCenterText, 12); view__45->addView(view__48); -ValueMenu* const view__49 = createValueMenu(CRect(120, 60, 180, 85), kTagSetPreloadSize, "", kCenterText, 12); +auto* const view__49 = createValueMenu(CRect(120, 60, 180, 85), kTagSetPreloadSize, "", kCenterText, 12); preloadSizeSlider_ = view__49; view__45->addView(view__49); -TitleGroup* const view__50 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); +auto* const view__50 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); view__44->addView(view__50); -ValueLabel* const view__51 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); +auto* const view__51 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); view__50->addView(view__51); -ValueMenu* const view__52 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); +auto* const view__52 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); tuningFrequencySlider_ = view__52; view__50->addView(view__52); -ValueLabel* const view__53 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); +auto* const view__53 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); view__50->addView(view__53); -StyledKnob* const view__54 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); +auto* const view__54 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); stretchedTuningSlider_ = view__54; view__50->addView(view__54); -ValueLabel* const view__55 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); +auto* const view__55 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); view__50->addView(view__55); -ValueLabel* const view__56 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); +auto* const view__56 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); view__50->addView(view__56); -ValueButton* const view__57 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); +auto* const view__57 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); scalaFileButton_ = view__57; view__50->addView(view__57); -ValueMenu* const view__58 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); +auto* const view__58 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); scalaRootKeySlider_ = view__58; view__50->addView(view__58); -ValueMenu* const view__59 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); +auto* const view__59 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); scalaRootOctaveSlider_ = view__59; view__50->addView(view__59); -ResetSomethingButton* const view__60 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); +auto* const view__60 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); scalaResetButton_ = view__60; view__50->addView(view__60); -TitleGroup* const view__61 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); +auto* const view__61 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); userFilesGroup_ = view__61; view__44->addView(view__61); -ValueLabel* const view__62 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); +auto* const view__62 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); view__61->addView(view__62); -ValueButton* const view__63 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); +auto* const view__63 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); userFilesDirButton_ = view__63; view__61->addView(view__63); -Piano* const view__64 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); +auto* const view__64 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); piano_ = view__64; view__0->addView(view__64); diff --git a/plugins/editor/tools/layout-maker/sources/main.cpp b/plugins/editor/tools/layout-maker/sources/main.cpp index 31fc0bfa..3ef47982 100644 --- a/plugins/editor/tools/layout-maker/sources/main.cpp +++ b/plugins/editor/tools/layout-maker/sources/main.cpp @@ -95,7 +95,7 @@ static void codegen_item(int& idCounter, int parentId, int parentX, int parentY, else if (item.align & 8) align = "kRightText"; - std::cout << item.classname << "* const view__" << id << " = create" << item.classname << "(CRect(" << relX << ", " << relY << ", " << (relX + item.w) << ", " << (relY + item.h) << "), " << tag << ", \"" << label << "\", " << align << ", " << item.labelsize << ");\n"; + std::cout << "auto"/*item.classname*/ << "* const view__" << id << " = create" << item.classname << "(CRect(" << relX << ", " << relY << ", " << (relX + item.w) << ", " << (relY + item.h) << "), " << tag << ", \"" << label << "\", " << align << ", " << item.labelsize << ");\n"; if (!item.id.empty()) std::cout << item.id << " = view__" << id << ";\n"; From 10d81de41cb67412c8f0a959eb7d70dd342e8bf2 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 01:13:16 +0100 Subject: [PATCH 316/668] Eliminate the rest of warnings --- plugins/editor/src/editor/Editor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 5b3ef16f..d64e60d7 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -700,12 +700,14 @@ void Editor::Impl::createFrameContents() auto createSettingsButton = [&createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) { return createGlyphButton(u8"\ue2e4", bounds, tag, fontsize); }; +#if 0 auto createEditFileButton = [&createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) { return createGlyphButton(u8"\ue148", bounds, tag, fontsize); }; auto createLoadFileButton = [&createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) { return createGlyphButton(u8"\ue1a3", bounds, tag, fontsize); }; +#endif auto createPreviousFileButton = [&createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) { return createGlyphButton(u8"\ue0d9", bounds, tag, fontsize); }; From 57a002972dee1f126fd46f48a64d4d64bf4c7957 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 01:39:51 +0100 Subject: [PATCH 317/668] Convert BufferCounter to size_t for GiB range --- src/sfizz/Buffer.h | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/src/sfizz/Buffer.h b/src/sfizz/Buffer.h index 9644f17d..0fd8dc29 100644 --- a/src/sfizz/Buffer.h +++ b/src/sfizz/Buffer.h @@ -65,44 +65,32 @@ protected: } public: - void newBuffer(int size) noexcept + template + void newBuffer(I size) noexcept { - numBuffers++; - bytes.fetch_add(size); + ++numBuffers; + bytes.fetch_add(static_cast(size)); } - void bufferResized(int oldSize, int newSize) noexcept + template + void bufferResized(I oldSize, I newSize) noexcept { - bytes.fetch_add(newSize); - bytes.fetch_sub(oldSize); + bytes.fetch_add(static_cast(newSize)); + bytes.fetch_sub(static_cast(oldSize)); } - void bufferDeleted(int size) noexcept + template + void bufferDeleted(I size) noexcept { - numBuffers--; - bytes.fetch_sub(size); + --numBuffers; + bytes.fetch_sub(static_cast(size)); } - void bufferDeleted(size_t size) noexcept - { - bufferDeleted(static_cast(size)); - } - - void bufferResized(size_t oldSize, size_t newSize) noexcept - { - bufferResized(static_cast(oldSize), static_cast(newSize)); - } - - void newBuffer(size_t size) noexcept - { - newBuffer(static_cast(size)); - } - - int getNumBuffers() const noexcept { return numBuffers; } - int getTotalBytes() const noexcept { return bytes; } + size_t getNumBuffers() const noexcept { return numBuffers; } + size_t getTotalBytes() const noexcept { return bytes; } private: - std::atomic numBuffers { 0 }; - std::atomic bytes { 0 }; + std::atomic numBuffers { 0 }; + std::atomic bytes { 0 }; }; From d1be18c0d999e44e8411afbb741326cc2bba995c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 01:41:20 +0100 Subject: [PATCH 318/668] Memory reporting by OSC --- src/sfizz/SynthMessaging.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 6dda0d0c..f8451d4f 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -88,6 +88,13 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co //---------------------------------------------------------------------- + MATCH("/mem/buffers", "") { + uint64_t total = BufferCounter::counter().getTotalBytes(); + client.receive<'h'>(delay, path, total); + } break; + + //---------------------------------------------------------------------- + MATCH("/region&/delay", "") { GET_REGION_OR_BREAK(indices[0]) client.receive<'f'>(delay, path, region.delay); From 51b85bc17ebc82d336dd650d55232b01766f954f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 02:14:10 +0100 Subject: [PATCH 319/668] Display the memory usage --- plugins/editor/src/editor/Editor.cpp | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index d64e60d7..9dad19ba 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -47,6 +47,8 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { std::string userFilesDir_; std::string fallbackFilesDir_; + SharedPointer memQueryTimer_; + enum { kPanelGeneral, kPanelControls, @@ -172,6 +174,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void updateCCValue(unsigned cc, float value); void updateCCDefaultValue(unsigned cc, float value); void updateCCLabel(unsigned cc, const char* label); + void updateMemoryUsed(uint64_t mem); // edition of CC by UI void performCCValueChange(unsigned cc, float value); @@ -224,6 +227,10 @@ void Editor::open(CFrame& frame) impl.frame_ = &frame; frame.addView(impl.mainView_.get()); + impl.memQueryTimer_ = makeOwned([this](CVSTGUITimer*) { + impl_->sendQueuedOSC("/mem/buffers", "", nullptr); + }, 1000, true); + // request the whole Key and CC information impl.sendQueuedOSC("/key/slots", "", nullptr); impl.sendQueuedOSC("/sw/slots", "", nullptr); @@ -236,6 +243,8 @@ void Editor::close() impl.clearQueuedOSC(); + impl.memQueryTimer_ = nullptr; + if (impl.frame_) { impl.frame_->removeView(impl.mainView_.get(), false); impl.frame_ = nullptr; @@ -461,6 +470,9 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi else if (Messages::matchOSC("/cc&/label", path, indices) && !strcmp(sig, "s")) { updateCCLabel(indices[0], args[0].s); } + else if (Messages::matchOSC("/mem/buffers", path, indices) && !strcmp(sig, "h")) { + updateMemoryUsed(args[0].h); + } else { //fprintf(stderr, "Receive unhandled OSC: %s\n", path); } @@ -1349,6 +1361,27 @@ void Editor::Impl::updateCCLabel(unsigned cc, const char* label) panel->setControlLabelText(cc, label); } +void Editor::Impl::updateMemoryUsed(uint64_t mem) +{ + if (CTextLabel* label = memoryLabel_) { + double value = mem / 1e3; + const char* unit = "kB"; + int precision = 0; + if (value >= 1e3) { + value /= 1e3; + unit = "MB"; + } + if (value >= 1e3) { + value /= 1e3; + unit = "GB"; + precision = 1; + } + char textbuf[128]; + snprintf(textbuf, sizeof(textbuf), "%.*f %s", precision, value, unit); + label->setText(textbuf); + } +} + void Editor::Impl::performCCValueChange(unsigned cc, float value) { // TODO(jpc) CC as parameters and automation From 2b80d77e50d092bb853ec0b3b85e313f1fff47a4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 02:20:26 +0100 Subject: [PATCH 320/668] Arrange row items horizontally --- plugins/editor/layout/main.fl | 16 ++++++++-------- plugins/editor/src/editor/layout/main.hpp | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 84a6f380..340b20b5 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -86,30 +86,30 @@ widget_class mainView {open class ChevronDropDown } Fl_Box infoVoicesLabel_ { - xywh {260 76 50 25} labelsize 12 align 16 + xywh {260 76 40 25} labelsize 12 align 16 class Label } Fl_Box {} { label {Max:} - xywh {315 76 60 25} labelsize 12 align 24 + xywh {315 76 40 25} labelsize 12 align 24 class Label } Fl_Box numVoicesLabel_ { - xywh {380 76 35 25} labelsize 12 align 16 + xywh {360 76 35 25} labelsize 12 align 16 class Label } Fl_Box {} { label {Memory:} - xywh {435 76 60 25} labelsize 12 align 24 + xywh {425 76 60 25} labelsize 12 align 24 class Label } - Fl_Box memoryLabel_ { - xywh {500 76 50 25} labelsize 12 align 16 + Fl_Box memoryLabel_ {selected + xywh {490 76 60 25} labelsize 12 align 16 class Label } Fl_Button numVoicesSlider_ { comment {tag=kTagSetNumVoices} - xywh {415 80 20 20} labelsize 16 + xywh {395 80 20 20} labelsize 16 class ChevronValueDropDown } } @@ -216,7 +216,7 @@ widget_class mainView {open } {} } } - Fl_Group {subPanels_[kPanelSettings]} {open selected + Fl_Group {subPanels_[kPanelSettings]} {open xywh {5 109 790 316} class LogicalGroup } { diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index 469887fc..259e889e 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -36,20 +36,20 @@ view__8->addView(view__15); auto* const view__16 = createChevronDropDown(CRect(345, 9, 370, 34), kTagFileOperations, "", kCenterText, 24); fileOperationsMenu_ = view__16; view__8->addView(view__16); -auto* const view__17 = createLabel(CRect(75, 71, 125, 96), -1, "", kCenterText, 12); +auto* const view__17 = createLabel(CRect(75, 71, 115, 96), -1, "", kCenterText, 12); infoVoicesLabel_ = view__17; view__8->addView(view__17); -auto* const view__18 = createLabel(CRect(130, 71, 190, 96), -1, "Max:", kRightText, 12); +auto* const view__18 = createLabel(CRect(130, 71, 170, 96), -1, "Max:", kRightText, 12); view__8->addView(view__18); -auto* const view__19 = createLabel(CRect(195, 71, 230, 96), -1, "", kCenterText, 12); +auto* const view__19 = createLabel(CRect(175, 71, 210, 96), -1, "", kCenterText, 12); numVoicesLabel_ = view__19; view__8->addView(view__19); -auto* const view__20 = createLabel(CRect(250, 71, 310, 96), -1, "Memory:", kRightText, 12); +auto* const view__20 = createLabel(CRect(240, 71, 300, 96), -1, "Memory:", kRightText, 12); view__8->addView(view__20); -auto* const view__21 = createLabel(CRect(315, 71, 365, 96), -1, "", kCenterText, 12); +auto* const view__21 = createLabel(CRect(305, 71, 365, 96), -1, "", kCenterText, 12); memoryLabel_ = view__21; view__8->addView(view__21); -auto* const view__22 = createChevronValueDropDown(CRect(230, 75, 250, 95), kTagSetNumVoices, "", kCenterText, 16); +auto* const view__22 = createChevronValueDropDown(CRect(210, 75, 230, 95), kTagSetNumVoices, "", kCenterText, 16); numVoicesSlider_ = view__22; view__8->addView(view__22); auto* const view__23 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14); From a0d8b23bff03b65e99862924e4118367e85406e4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 02:28:25 +0100 Subject: [PATCH 321/668] Fix warning in tests --- tests/BufferT.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/BufferT.cpp b/tests/BufferT.cpp index ed5f986f..025f9eae 100644 --- a/tests/BufferT.cpp +++ b/tests/BufferT.cpp @@ -151,13 +151,13 @@ TEST_CASE("[Buffer] Buffer counter") sfz::BufferCounter& counter = sfz::Buffer::counter(); // handle the eventuality that the buffer counter does not start at zero - const int initialNumBuffers = counter.getNumBuffers(); - const int initialTotalBytes = counter.getTotalBytes(); - auto haveNumBuffers = [&](int n) -> bool { + const size_t initialNumBuffers = counter.getNumBuffers(); + const size_t initialTotalBytes = counter.getTotalBytes(); + auto haveNumBuffers = [&](size_t n) -> bool { return n == counter.getNumBuffers() - initialNumBuffers; }; - auto haveTotalAllocation = [&](int n) -> bool { - return n * static_cast(sizeof(float)) == counter.getTotalBytes() - initialTotalBytes; + auto haveTotalAllocation = [&](size_t n) -> bool { + return n * sizeof(float) == counter.getTotalBytes() - initialTotalBytes; }; // create an empty buffer From 7d885bd2979414265e40867d53e98a1b86ddf940 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 02:35:47 +0100 Subject: [PATCH 322/668] Adjust box for symmetry --- plugins/editor/layout/main.fl | 6 +++--- plugins/editor/src/editor/layout/main.hpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 340b20b5..588466f1 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -103,7 +103,7 @@ widget_class mainView {open xywh {425 76 60 25} labelsize 12 align 24 class Label } - Fl_Box memoryLabel_ {selected + Fl_Box memoryLabel_ { xywh {490 76 60 25} labelsize 12 align 16 class Label } @@ -221,8 +221,8 @@ widget_class mainView {open class LogicalGroup } { Fl_Group {} { - label Engine open - xywh {295 135 205 100} box ROUNDED_BOX labelsize 12 align 17 + label Engine open selected + xywh {305 135 195 100} box ROUNDED_BOX labelsize 12 align 17 class TitleGroup } { Fl_Spinner oversamplingSlider_ { diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index 259e889e..e53cdeff 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -112,16 +112,16 @@ view__42->addView(view__43); auto* const view__44 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); subPanels_[kPanelSettings] = view__44; view__0->addView(view__44); -auto* const view__45 = createTitleGroup(CRect(290, 26, 495, 126), -1, "Engine", kCenterText, 12); +auto* const view__45 = createTitleGroup(CRect(300, 26, 495, 126), -1, "Engine", kCenterText, 12); view__44->addView(view__45); -auto* const view__46 = createValueMenu(CRect(35, 60, 95, 85), kTagSetOversampling, "", kCenterText, 12); +auto* const view__46 = createValueMenu(CRect(25, 60, 85, 85), kTagSetOversampling, "", kCenterText, 12); oversamplingSlider_ = view__46; view__45->addView(view__46); -auto* const view__47 = createValueLabel(CRect(25, 20, 105, 45), -1, "Oversampling", kCenterText, 12); +auto* const view__47 = createValueLabel(CRect(15, 20, 95, 45), -1, "Oversampling", kCenterText, 12); view__45->addView(view__47); -auto* const view__48 = createValueLabel(CRect(110, 20, 190, 45), -1, "Preload size", kCenterText, 12); +auto* const view__48 = createValueLabel(CRect(100, 20, 180, 45), -1, "Preload size", kCenterText, 12); view__45->addView(view__48); -auto* const view__49 = createValueMenu(CRect(120, 60, 180, 85), kTagSetPreloadSize, "", kCenterText, 12); +auto* const view__49 = createValueMenu(CRect(110, 60, 170, 85), kTagSetPreloadSize, "", kCenterText, 12); preloadSizeSlider_ = view__49; view__45->addView(view__49); auto* const view__50 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); From 1818f2e9279b285a8450fd4e5858e7e84c74a6d6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 03:27:46 +0100 Subject: [PATCH 323/668] Add methods to get oversampler factor given in/out rates --- devtools/HIIRDesigner.cpp | 17 +++++++++++++++++ src/CMakeLists.txt | 4 ++-- src/sfizz/MathHelpers.h | 19 +++++++++++++++++++ src/sfizz/OversamplerHelpers.hxx | 15 +++++++++++++++ tests/CMakeLists.txt | 1 + tests/OversamplerT.cpp | 21 +++++++++++++++++++++ 6 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/OversamplerT.cpp diff --git a/devtools/HIIRDesigner.cpp b/devtools/HIIRDesigner.cpp index d021764a..33be312c 100644 --- a/devtools/HIIRDesigner.cpp +++ b/devtools/HIIRDesigner.cpp @@ -152,6 +152,7 @@ static void generate_cpp_prologue(int argc, char *argv[]) printf( "#pragma once\n" "#include \"OversamplerHelpers.h\"\n" + "#include \"MathHelpers\"\n" "\n" "namespace sfz {\n" ); @@ -209,6 +210,14 @@ static void generate_cpp_upsampler(const Stage *stages, int num_stages) printf("\t\t" "}\n"); printf("\t" "}\n"); + printf("\t" "static unsigned conversionFactor(double sourceRate, double targetRate)\n"); + printf("\t" "{\n"); + printf("\t\t" "int factor = static_cast(std::ceil(targetRate / sourceRate));\n"); + printf("\t\t" "factor = (factor > 1) ? factor : 1;\n"); + printf("\t\t" "factor = (factor < 128) ? factor : 128;\n"); + printf("\t\t" "return nextPow2(factor);\n"); + printf("\t" "}\n"); + printf("\t" "static bool canProcess(int factor)\n"); printf("\t" "{\n"); printf("\t\t" "switch (factor) {\n"); @@ -322,6 +331,14 @@ static void generate_cpp_downsampler(const Stage *stages, int num_stages) printf("\t\t" "}\n"); printf("\t" "}\n"); + printf("\t" "static unsigned conversionFactor(double sourceRate, double targetRate)\n"); + printf("\t" "{\n"); + printf("\t\t" "int factor = static_cast(std::ceil(targetRate / sourceRate));\n"); + printf("\t\t" "factor = (factor > 1) ? factor : 1;\n"); + printf("\t\t" "factor = (factor < 128) ? factor : 128;\n"); + printf("\t\t" "return nextPow2(factor);\n"); + printf("\t" "}\n"); + printf("\t" "static bool canProcess(int factor)\n"); printf("\t" "{\n"); printf("\t\t" "switch (factor) {\n"); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9779d698..ee7dbc3b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -263,8 +263,8 @@ add_library(sfizz::internal ALIAS sfizz_internal) target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_FILES}) target_include_directories(sfizz_internal PUBLIC "." "sfizz") target_link_libraries(sfizz_internal - PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex sfizz::bit_array sfizz::simde - PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::hiir sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) + PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex sfizz::bit_array sfizz::simde sfizz::hiir + PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::jsl sfizz::atomic) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") target_link_libraries(sfizz_internal PUBLIC st_audiofile) diff --git a/src/sfizz/MathHelpers.h b/src/sfizz/MathHelpers.h index 066b8e04..fa86b8a4 100644 --- a/src/sfizz/MathHelpers.h +++ b/src/sfizz/MathHelpers.h @@ -296,6 +296,25 @@ constexpr long int lroundPositive(T value) return static_cast(0.5f + value); // NOLINT } +/** + * @brief Compute the next power of 2 + * + * @param v An integer + * @return The next power of 2, inclusive from @p v + */ +inline uint32_t nextPow2(uint32_t v) +{ + // Bit Twiddling Hacks + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + /** @brief Wrap a normalized phase into the domain [0;1[ */ diff --git a/src/sfizz/OversamplerHelpers.hxx b/src/sfizz/OversamplerHelpers.hxx index 458cdd87..66a5f1f4 100644 --- a/src/sfizz/OversamplerHelpers.hxx +++ b/src/sfizz/OversamplerHelpers.hxx @@ -11,6 +11,7 @@ #pragma once #include "OversamplerHelpers.h" +#include "MathHelpers.h" namespace sfz { @@ -94,6 +95,13 @@ public: return factor * spl; } } + static unsigned conversionFactor(double sourceRate, double targetRate) + { + int factor = static_cast(std::ceil(targetRate / sourceRate)); + factor = (factor > 1) ? factor : 1; + factor = (factor < 128) ? factor : 128; + return nextPow2(factor); + } static bool canProcess(int factor) { switch (factor) { @@ -293,6 +301,13 @@ public: return factor * spl; } } + static unsigned conversionFactor(double sourceRate, double targetRate) + { + int factor = static_cast(std::ceil(targetRate / sourceRate)); + factor = (factor > 1) ? factor : 1; + factor = (factor < 128) ? factor : 128; + return nextPow2(factor); + } static bool canProcess(int factor) { switch (factor) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6e28170f..497ca0e2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -41,6 +41,7 @@ set(SFIZZ_TEST_SOURCES ModulationsT.cpp LFOT.cpp MessagingT.cpp + OversamplerT.cpp DataHelpers.h DataHelpers.cpp ) diff --git a/tests/OversamplerT.cpp b/tests/OversamplerT.cpp new file mode 100644 index 00000000..84e179e6 --- /dev/null +++ b/tests/OversamplerT.cpp @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "sfizz/OversamplerHelpers.h" +#include "catch2/catch.hpp" + +TEST_CASE("[Oversampler] Conversion factor") +{ + REQUIRE(sfz::Upsampler::conversionFactor(44100.0, 44100.0) == 1); + REQUIRE(sfz::Upsampler::conversionFactor(44100.0, 44101.0) == 2); + REQUIRE(sfz::Upsampler::conversionFactor(44100.0, 88200.0) == 2); + REQUIRE(sfz::Upsampler::conversionFactor(44100.0, 88201.0) == 4); + REQUIRE(sfz::Upsampler::conversionFactor(44100.0, 176400.0) == 4); + REQUIRE(sfz::Upsampler::conversionFactor(44100.0, 176401.0) == 8); + // low and high limits + REQUIRE(sfz::Upsampler::conversionFactor(44100.0, 1.0) == 1); + REQUIRE(sfz::Upsampler::conversionFactor(44100.0, 1e10) == 128); +} From 4a3c920f406046789d50aaec382e8ac429dab0fe Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 23:40:26 +0100 Subject: [PATCH 324/668] Rename faust files with consistency --- src/sfizz/SfzFilterImpls.hpp | 104 +++++++++--------- src/sfizz/effects/Compressor.cpp | 2 +- src/sfizz/effects/Disto.cpp | 2 +- src/sfizz/effects/Fverb.cpp | 2 +- src/sfizz/effects/Gate.cpp | 2 +- src/sfizz/effects/Limiter.cpp | 2 +- .../gen/{compressor.cxx => compressor.hxx} | 0 .../gen/{disto_stage.cxx => disto_stage.hxx} | 0 .../effects/gen/{fverb.cxx => fverb.hxx} | 0 src/sfizz/effects/gen/{gate.cxx => gate.hxx} | 0 .../effects/gen/{limiter.cpp => limiter.hxx} | 0 .../{sfz2chApf1p.cxx => sfz2chApf1p.hxx} | 0 .../{sfz2chBpf1p.cxx => sfz2chBpf1p.hxx} | 0 .../{sfz2chBpf2p.cxx => sfz2chBpf2p.hxx} | 0 .../{sfz2chBpf2pSv.cxx => sfz2chBpf2pSv.hxx} | 0 .../{sfz2chBpf4p.cxx => sfz2chBpf4p.hxx} | 0 .../{sfz2chBpf6p.cxx => sfz2chBpf6p.hxx} | 0 .../{sfz2chBrf1p.cxx => sfz2chBrf1p.hxx} | 0 .../{sfz2chBrf2p.cxx => sfz2chBrf2p.hxx} | 0 .../{sfz2chBrf2pSv.cxx => sfz2chBrf2pSv.hxx} | 0 ...{sfz2chEqHshelf.cxx => sfz2chEqHshelf.hxx} | 0 ...{sfz2chEqLshelf.cxx => sfz2chEqLshelf.hxx} | 0 .../{sfz2chEqPeak.cxx => sfz2chEqPeak.hxx} | 0 .../{sfz2chHpf1p.cxx => sfz2chHpf1p.hxx} | 0 .../{sfz2chHpf2p.cxx => sfz2chHpf2p.hxx} | 0 .../{sfz2chHpf2pSv.cxx => sfz2chHpf2pSv.hxx} | 0 .../{sfz2chHpf4p.cxx => sfz2chHpf4p.hxx} | 0 .../{sfz2chHpf6p.cxx => sfz2chHpf6p.hxx} | 0 .../filters/{sfz2chHsh.cxx => sfz2chHsh.hxx} | 0 .../{sfz2chLpf1p.cxx => sfz2chLpf1p.hxx} | 0 .../{sfz2chLpf2p.cxx => sfz2chLpf2p.hxx} | 0 .../{sfz2chLpf2pSv.cxx => sfz2chLpf2pSv.hxx} | 0 .../{sfz2chLpf4p.cxx => sfz2chLpf4p.hxx} | 0 .../{sfz2chLpf6p.cxx => sfz2chLpf6p.hxx} | 0 .../filters/{sfz2chLsh.cxx => sfz2chLsh.hxx} | 0 .../filters/{sfz2chPeq.cxx => sfz2chPeq.hxx} | 0 .../{sfz2chPink.cxx => sfz2chPink.hxx} | 0 .../filters/{sfzApf1p.cxx => sfzApf1p.hxx} | 0 .../filters/{sfzBpf1p.cxx => sfzBpf1p.hxx} | 0 .../filters/{sfzBpf2p.cxx => sfzBpf2p.hxx} | 0 .../{sfzBpf2pSv.cxx => sfzBpf2pSv.hxx} | 0 .../filters/{sfzBpf4p.cxx => sfzBpf4p.hxx} | 0 .../filters/{sfzBpf6p.cxx => sfzBpf6p.hxx} | 0 .../filters/{sfzBrf1p.cxx => sfzBrf1p.hxx} | 0 .../filters/{sfzBrf2p.cxx => sfzBrf2p.hxx} | 0 .../{sfzBrf2pSv.cxx => sfzBrf2pSv.hxx} | 0 .../{sfzEqHshelf.cxx => sfzEqHshelf.hxx} | 0 .../{sfzEqLshelf.cxx => sfzEqLshelf.hxx} | 0 .../filters/{sfzEqPeak.cxx => sfzEqPeak.hxx} | 0 .../filters/{sfzHpf1p.cxx => sfzHpf1p.hxx} | 0 .../filters/{sfzHpf2p.cxx => sfzHpf2p.hxx} | 0 .../{sfzHpf2pSv.cxx => sfzHpf2pSv.hxx} | 0 .../filters/{sfzHpf4p.cxx => sfzHpf4p.hxx} | 0 .../filters/{sfzHpf6p.cxx => sfzHpf6p.hxx} | 0 .../gen/filters/{sfzHsh.cxx => sfzHsh.hxx} | 0 .../filters/{sfzLpf1p.cxx => sfzLpf1p.hxx} | 0 .../filters/{sfzLpf2p.cxx => sfzLpf2p.hxx} | 0 .../{sfzLpf2pSv.cxx => sfzLpf2pSv.hxx} | 0 .../filters/{sfzLpf4p.cxx => sfzLpf4p.hxx} | 0 .../filters/{sfzLpf6p.cxx => sfzLpf6p.hxx} | 0 .../gen/filters/{sfzLsh.cxx => sfzLsh.hxx} | 0 .../gen/filters/{sfzPeq.cxx => sfzPeq.hxx} | 0 .../gen/filters/{sfzPink.cxx => sfzPink.hxx} | 0 63 files changed, 57 insertions(+), 57 deletions(-) rename src/sfizz/effects/gen/{compressor.cxx => compressor.hxx} (100%) rename src/sfizz/effects/gen/{disto_stage.cxx => disto_stage.hxx} (100%) rename src/sfizz/effects/gen/{fverb.cxx => fverb.hxx} (100%) rename src/sfizz/effects/gen/{gate.cxx => gate.hxx} (100%) rename src/sfizz/effects/gen/{limiter.cpp => limiter.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chApf1p.cxx => sfz2chApf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chBpf1p.cxx => sfz2chBpf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chBpf2p.cxx => sfz2chBpf2p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chBpf2pSv.cxx => sfz2chBpf2pSv.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chBpf4p.cxx => sfz2chBpf4p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chBpf6p.cxx => sfz2chBpf6p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chBrf1p.cxx => sfz2chBrf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chBrf2p.cxx => sfz2chBrf2p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chBrf2pSv.cxx => sfz2chBrf2pSv.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chEqHshelf.cxx => sfz2chEqHshelf.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chEqLshelf.cxx => sfz2chEqLshelf.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chEqPeak.cxx => sfz2chEqPeak.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chHpf1p.cxx => sfz2chHpf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chHpf2p.cxx => sfz2chHpf2p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chHpf2pSv.cxx => sfz2chHpf2pSv.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chHpf4p.cxx => sfz2chHpf4p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chHpf6p.cxx => sfz2chHpf6p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chHsh.cxx => sfz2chHsh.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chLpf1p.cxx => sfz2chLpf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chLpf2p.cxx => sfz2chLpf2p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chLpf2pSv.cxx => sfz2chLpf2pSv.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chLpf4p.cxx => sfz2chLpf4p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chLpf6p.cxx => sfz2chLpf6p.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chLsh.cxx => sfz2chLsh.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chPeq.cxx => sfz2chPeq.hxx} (100%) rename src/sfizz/gen/filters/{sfz2chPink.cxx => sfz2chPink.hxx} (100%) rename src/sfizz/gen/filters/{sfzApf1p.cxx => sfzApf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfzBpf1p.cxx => sfzBpf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfzBpf2p.cxx => sfzBpf2p.hxx} (100%) rename src/sfizz/gen/filters/{sfzBpf2pSv.cxx => sfzBpf2pSv.hxx} (100%) rename src/sfizz/gen/filters/{sfzBpf4p.cxx => sfzBpf4p.hxx} (100%) rename src/sfizz/gen/filters/{sfzBpf6p.cxx => sfzBpf6p.hxx} (100%) rename src/sfizz/gen/filters/{sfzBrf1p.cxx => sfzBrf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfzBrf2p.cxx => sfzBrf2p.hxx} (100%) rename src/sfizz/gen/filters/{sfzBrf2pSv.cxx => sfzBrf2pSv.hxx} (100%) rename src/sfizz/gen/filters/{sfzEqHshelf.cxx => sfzEqHshelf.hxx} (100%) rename src/sfizz/gen/filters/{sfzEqLshelf.cxx => sfzEqLshelf.hxx} (100%) rename src/sfizz/gen/filters/{sfzEqPeak.cxx => sfzEqPeak.hxx} (100%) rename src/sfizz/gen/filters/{sfzHpf1p.cxx => sfzHpf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfzHpf2p.cxx => sfzHpf2p.hxx} (100%) rename src/sfizz/gen/filters/{sfzHpf2pSv.cxx => sfzHpf2pSv.hxx} (100%) rename src/sfizz/gen/filters/{sfzHpf4p.cxx => sfzHpf4p.hxx} (100%) rename src/sfizz/gen/filters/{sfzHpf6p.cxx => sfzHpf6p.hxx} (100%) rename src/sfizz/gen/filters/{sfzHsh.cxx => sfzHsh.hxx} (100%) rename src/sfizz/gen/filters/{sfzLpf1p.cxx => sfzLpf1p.hxx} (100%) rename src/sfizz/gen/filters/{sfzLpf2p.cxx => sfzLpf2p.hxx} (100%) rename src/sfizz/gen/filters/{sfzLpf2pSv.cxx => sfzLpf2pSv.hxx} (100%) rename src/sfizz/gen/filters/{sfzLpf4p.cxx => sfzLpf4p.hxx} (100%) rename src/sfizz/gen/filters/{sfzLpf6p.cxx => sfzLpf6p.hxx} (100%) rename src/sfizz/gen/filters/{sfzLsh.cxx => sfzLsh.hxx} (100%) rename src/sfizz/gen/filters/{sfzPeq.cxx => sfzPeq.hxx} (100%) rename src/sfizz/gen/filters/{sfzPink.cxx => sfzPink.hxx} (100%) diff --git a/src/sfizz/SfzFilterImpls.hpp b/src/sfizz/SfzFilterImpls.hpp index 2a670d6d..613a41d5 100644 --- a/src/sfizz/SfzFilterImpls.hpp +++ b/src/sfizz/SfzFilterImpls.hpp @@ -40,59 +40,59 @@ protected: #pragma GCC diagnostic ignored "-Wunused-parameter" #endif -#include "gen/filters/sfzApf1p.cxx" -#include "gen/filters/sfzBpf1p.cxx" -#include "gen/filters/sfzBpf2p.cxx" -#include "gen/filters/sfzBpf4p.cxx" -#include "gen/filters/sfzBpf6p.cxx" -#include "gen/filters/sfzBrf1p.cxx" -#include "gen/filters/sfzBrf2p.cxx" -#include "gen/filters/sfzHpf1p.cxx" -#include "gen/filters/sfzHpf2p.cxx" -#include "gen/filters/sfzHpf4p.cxx" -#include "gen/filters/sfzHpf6p.cxx" -#include "gen/filters/sfzLpf1p.cxx" -#include "gen/filters/sfzLpf2p.cxx" -#include "gen/filters/sfzLpf4p.cxx" -#include "gen/filters/sfzLpf6p.cxx" -#include "gen/filters/sfzPink.cxx" -#include "gen/filters/sfzLpf2pSv.cxx" -#include "gen/filters/sfzHpf2pSv.cxx" -#include "gen/filters/sfzBpf2pSv.cxx" -#include "gen/filters/sfzBrf2pSv.cxx" -#include "gen/filters/sfzLsh.cxx" -#include "gen/filters/sfzHsh.cxx" -#include "gen/filters/sfzPeq.cxx" -#include "gen/filters/sfzEqPeak.cxx" -#include "gen/filters/sfzEqLshelf.cxx" -#include "gen/filters/sfzEqHshelf.cxx" +#include "gen/filters/sfzApf1p.hxx" +#include "gen/filters/sfzBpf1p.hxx" +#include "gen/filters/sfzBpf2p.hxx" +#include "gen/filters/sfzBpf4p.hxx" +#include "gen/filters/sfzBpf6p.hxx" +#include "gen/filters/sfzBrf1p.hxx" +#include "gen/filters/sfzBrf2p.hxx" +#include "gen/filters/sfzHpf1p.hxx" +#include "gen/filters/sfzHpf2p.hxx" +#include "gen/filters/sfzHpf4p.hxx" +#include "gen/filters/sfzHpf6p.hxx" +#include "gen/filters/sfzLpf1p.hxx" +#include "gen/filters/sfzLpf2p.hxx" +#include "gen/filters/sfzLpf4p.hxx" +#include "gen/filters/sfzLpf6p.hxx" +#include "gen/filters/sfzPink.hxx" +#include "gen/filters/sfzLpf2pSv.hxx" +#include "gen/filters/sfzHpf2pSv.hxx" +#include "gen/filters/sfzBpf2pSv.hxx" +#include "gen/filters/sfzBrf2pSv.hxx" +#include "gen/filters/sfzLsh.hxx" +#include "gen/filters/sfzHsh.hxx" +#include "gen/filters/sfzPeq.hxx" +#include "gen/filters/sfzEqPeak.hxx" +#include "gen/filters/sfzEqLshelf.hxx" +#include "gen/filters/sfzEqHshelf.hxx" -#include "gen/filters/sfz2chApf1p.cxx" -#include "gen/filters/sfz2chBpf1p.cxx" -#include "gen/filters/sfz2chBpf2p.cxx" -#include "gen/filters/sfz2chBpf4p.cxx" -#include "gen/filters/sfz2chBpf6p.cxx" -#include "gen/filters/sfz2chBrf1p.cxx" -#include "gen/filters/sfz2chBrf2p.cxx" -#include "gen/filters/sfz2chHpf1p.cxx" -#include "gen/filters/sfz2chHpf2p.cxx" -#include "gen/filters/sfz2chHpf4p.cxx" -#include "gen/filters/sfz2chHpf6p.cxx" -#include "gen/filters/sfz2chLpf1p.cxx" -#include "gen/filters/sfz2chLpf2p.cxx" -#include "gen/filters/sfz2chLpf4p.cxx" -#include "gen/filters/sfz2chLpf6p.cxx" -#include "gen/filters/sfz2chPink.cxx" -#include "gen/filters/sfz2chLpf2pSv.cxx" -#include "gen/filters/sfz2chHpf2pSv.cxx" -#include "gen/filters/sfz2chBpf2pSv.cxx" -#include "gen/filters/sfz2chBrf2pSv.cxx" -#include "gen/filters/sfz2chLsh.cxx" -#include "gen/filters/sfz2chHsh.cxx" -#include "gen/filters/sfz2chPeq.cxx" -#include "gen/filters/sfz2chEqPeak.cxx" -#include "gen/filters/sfz2chEqLshelf.cxx" -#include "gen/filters/sfz2chEqHshelf.cxx" +#include "gen/filters/sfz2chApf1p.hxx" +#include "gen/filters/sfz2chBpf1p.hxx" +#include "gen/filters/sfz2chBpf2p.hxx" +#include "gen/filters/sfz2chBpf4p.hxx" +#include "gen/filters/sfz2chBpf6p.hxx" +#include "gen/filters/sfz2chBrf1p.hxx" +#include "gen/filters/sfz2chBrf2p.hxx" +#include "gen/filters/sfz2chHpf1p.hxx" +#include "gen/filters/sfz2chHpf2p.hxx" +#include "gen/filters/sfz2chHpf4p.hxx" +#include "gen/filters/sfz2chHpf6p.hxx" +#include "gen/filters/sfz2chLpf1p.hxx" +#include "gen/filters/sfz2chLpf2p.hxx" +#include "gen/filters/sfz2chLpf4p.hxx" +#include "gen/filters/sfz2chLpf6p.hxx" +#include "gen/filters/sfz2chPink.hxx" +#include "gen/filters/sfz2chLpf2pSv.hxx" +#include "gen/filters/sfz2chHpf2pSv.hxx" +#include "gen/filters/sfz2chBpf2pSv.hxx" +#include "gen/filters/sfz2chBrf2pSv.hxx" +#include "gen/filters/sfz2chLsh.hxx" +#include "gen/filters/sfz2chHsh.hxx" +#include "gen/filters/sfz2chPeq.hxx" +#include "gen/filters/sfz2chEqPeak.hxx" +#include "gen/filters/sfz2chEqLshelf.hxx" +#include "gen/filters/sfz2chEqHshelf.hxx" #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index e5a0c2e5..f2608531 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -25,7 +25,7 @@ static constexpr int _oversampling = 2; #define FAUST_UIMACROS 1 -#include "gen/compressor.cxx" +#include "gen/compressor.hxx" namespace sfz { namespace fx { diff --git a/src/sfizz/effects/Disto.cpp b/src/sfizz/effects/Disto.cpp index 0ee5534e..ed9d3487 100644 --- a/src/sfizz/effects/Disto.cpp +++ b/src/sfizz/effects/Disto.cpp @@ -28,7 +28,7 @@ static constexpr int _oversampling = 8; #define FAUST_UIMACROS 1 -#include "gen/disto_stage.cxx" +#include "gen/disto_stage.hxx" namespace sfz { namespace fx { diff --git a/src/sfizz/effects/Fverb.cpp b/src/sfizz/effects/Fverb.cpp index c8ab7938..f5161533 100644 --- a/src/sfizz/effects/Fverb.cpp +++ b/src/sfizz/effects/Fverb.cpp @@ -12,7 +12,7 @@ #include #include #define FAUST_UIMACROS 1 -#include "gen/fverb.cxx" +#include "gen/fverb.hxx" /** Note(jpc): implementation status diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index b97ffd4a..bfe8fdfc 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -28,7 +28,7 @@ static constexpr int _oversampling = 2; #define FAUST_UIMACROS 1 -#include "gen/gate.cxx" +#include "gen/gate.hxx" namespace sfz { namespace fx { diff --git a/src/sfizz/effects/Limiter.cpp b/src/sfizz/effects/Limiter.cpp index 4560ebbd..eb5f1c3c 100644 --- a/src/sfizz/effects/Limiter.cpp +++ b/src/sfizz/effects/Limiter.cpp @@ -16,7 +16,7 @@ #include "absl/memory/memory.h" static constexpr int _oversampling = 2; -#include "gen/limiter.cpp" +#include "gen/limiter.hxx" namespace sfz { namespace fx { diff --git a/src/sfizz/effects/gen/compressor.cxx b/src/sfizz/effects/gen/compressor.hxx similarity index 100% rename from src/sfizz/effects/gen/compressor.cxx rename to src/sfizz/effects/gen/compressor.hxx diff --git a/src/sfizz/effects/gen/disto_stage.cxx b/src/sfizz/effects/gen/disto_stage.hxx similarity index 100% rename from src/sfizz/effects/gen/disto_stage.cxx rename to src/sfizz/effects/gen/disto_stage.hxx diff --git a/src/sfizz/effects/gen/fverb.cxx b/src/sfizz/effects/gen/fverb.hxx similarity index 100% rename from src/sfizz/effects/gen/fverb.cxx rename to src/sfizz/effects/gen/fverb.hxx diff --git a/src/sfizz/effects/gen/gate.cxx b/src/sfizz/effects/gen/gate.hxx similarity index 100% rename from src/sfizz/effects/gen/gate.cxx rename to src/sfizz/effects/gen/gate.hxx diff --git a/src/sfizz/effects/gen/limiter.cpp b/src/sfizz/effects/gen/limiter.hxx similarity index 100% rename from src/sfizz/effects/gen/limiter.cpp rename to src/sfizz/effects/gen/limiter.hxx diff --git a/src/sfizz/gen/filters/sfz2chApf1p.cxx b/src/sfizz/gen/filters/sfz2chApf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chApf1p.cxx rename to src/sfizz/gen/filters/sfz2chApf1p.hxx diff --git a/src/sfizz/gen/filters/sfz2chBpf1p.cxx b/src/sfizz/gen/filters/sfz2chBpf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chBpf1p.cxx rename to src/sfizz/gen/filters/sfz2chBpf1p.hxx diff --git a/src/sfizz/gen/filters/sfz2chBpf2p.cxx b/src/sfizz/gen/filters/sfz2chBpf2p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chBpf2p.cxx rename to src/sfizz/gen/filters/sfz2chBpf2p.hxx diff --git a/src/sfizz/gen/filters/sfz2chBpf2pSv.cxx b/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chBpf2pSv.cxx rename to src/sfizz/gen/filters/sfz2chBpf2pSv.hxx diff --git a/src/sfizz/gen/filters/sfz2chBpf4p.cxx b/src/sfizz/gen/filters/sfz2chBpf4p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chBpf4p.cxx rename to src/sfizz/gen/filters/sfz2chBpf4p.hxx diff --git a/src/sfizz/gen/filters/sfz2chBpf6p.cxx b/src/sfizz/gen/filters/sfz2chBpf6p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chBpf6p.cxx rename to src/sfizz/gen/filters/sfz2chBpf6p.hxx diff --git a/src/sfizz/gen/filters/sfz2chBrf1p.cxx b/src/sfizz/gen/filters/sfz2chBrf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chBrf1p.cxx rename to src/sfizz/gen/filters/sfz2chBrf1p.hxx diff --git a/src/sfizz/gen/filters/sfz2chBrf2p.cxx b/src/sfizz/gen/filters/sfz2chBrf2p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chBrf2p.cxx rename to src/sfizz/gen/filters/sfz2chBrf2p.hxx diff --git a/src/sfizz/gen/filters/sfz2chBrf2pSv.cxx b/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chBrf2pSv.cxx rename to src/sfizz/gen/filters/sfz2chBrf2pSv.hxx diff --git a/src/sfizz/gen/filters/sfz2chEqHshelf.cxx b/src/sfizz/gen/filters/sfz2chEqHshelf.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chEqHshelf.cxx rename to src/sfizz/gen/filters/sfz2chEqHshelf.hxx diff --git a/src/sfizz/gen/filters/sfz2chEqLshelf.cxx b/src/sfizz/gen/filters/sfz2chEqLshelf.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chEqLshelf.cxx rename to src/sfizz/gen/filters/sfz2chEqLshelf.hxx diff --git a/src/sfizz/gen/filters/sfz2chEqPeak.cxx b/src/sfizz/gen/filters/sfz2chEqPeak.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chEqPeak.cxx rename to src/sfizz/gen/filters/sfz2chEqPeak.hxx diff --git a/src/sfizz/gen/filters/sfz2chHpf1p.cxx b/src/sfizz/gen/filters/sfz2chHpf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chHpf1p.cxx rename to src/sfizz/gen/filters/sfz2chHpf1p.hxx diff --git a/src/sfizz/gen/filters/sfz2chHpf2p.cxx b/src/sfizz/gen/filters/sfz2chHpf2p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chHpf2p.cxx rename to src/sfizz/gen/filters/sfz2chHpf2p.hxx diff --git a/src/sfizz/gen/filters/sfz2chHpf2pSv.cxx b/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chHpf2pSv.cxx rename to src/sfizz/gen/filters/sfz2chHpf2pSv.hxx diff --git a/src/sfizz/gen/filters/sfz2chHpf4p.cxx b/src/sfizz/gen/filters/sfz2chHpf4p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chHpf4p.cxx rename to src/sfizz/gen/filters/sfz2chHpf4p.hxx diff --git a/src/sfizz/gen/filters/sfz2chHpf6p.cxx b/src/sfizz/gen/filters/sfz2chHpf6p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chHpf6p.cxx rename to src/sfizz/gen/filters/sfz2chHpf6p.hxx diff --git a/src/sfizz/gen/filters/sfz2chHsh.cxx b/src/sfizz/gen/filters/sfz2chHsh.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chHsh.cxx rename to src/sfizz/gen/filters/sfz2chHsh.hxx diff --git a/src/sfizz/gen/filters/sfz2chLpf1p.cxx b/src/sfizz/gen/filters/sfz2chLpf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chLpf1p.cxx rename to src/sfizz/gen/filters/sfz2chLpf1p.hxx diff --git a/src/sfizz/gen/filters/sfz2chLpf2p.cxx b/src/sfizz/gen/filters/sfz2chLpf2p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chLpf2p.cxx rename to src/sfizz/gen/filters/sfz2chLpf2p.hxx diff --git a/src/sfizz/gen/filters/sfz2chLpf2pSv.cxx b/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chLpf2pSv.cxx rename to src/sfizz/gen/filters/sfz2chLpf2pSv.hxx diff --git a/src/sfizz/gen/filters/sfz2chLpf4p.cxx b/src/sfizz/gen/filters/sfz2chLpf4p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chLpf4p.cxx rename to src/sfizz/gen/filters/sfz2chLpf4p.hxx diff --git a/src/sfizz/gen/filters/sfz2chLpf6p.cxx b/src/sfizz/gen/filters/sfz2chLpf6p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chLpf6p.cxx rename to src/sfizz/gen/filters/sfz2chLpf6p.hxx diff --git a/src/sfizz/gen/filters/sfz2chLsh.cxx b/src/sfizz/gen/filters/sfz2chLsh.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chLsh.cxx rename to src/sfizz/gen/filters/sfz2chLsh.hxx diff --git a/src/sfizz/gen/filters/sfz2chPeq.cxx b/src/sfizz/gen/filters/sfz2chPeq.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chPeq.cxx rename to src/sfizz/gen/filters/sfz2chPeq.hxx diff --git a/src/sfizz/gen/filters/sfz2chPink.cxx b/src/sfizz/gen/filters/sfz2chPink.hxx similarity index 100% rename from src/sfizz/gen/filters/sfz2chPink.cxx rename to src/sfizz/gen/filters/sfz2chPink.hxx diff --git a/src/sfizz/gen/filters/sfzApf1p.cxx b/src/sfizz/gen/filters/sfzApf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzApf1p.cxx rename to src/sfizz/gen/filters/sfzApf1p.hxx diff --git a/src/sfizz/gen/filters/sfzBpf1p.cxx b/src/sfizz/gen/filters/sfzBpf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzBpf1p.cxx rename to src/sfizz/gen/filters/sfzBpf1p.hxx diff --git a/src/sfizz/gen/filters/sfzBpf2p.cxx b/src/sfizz/gen/filters/sfzBpf2p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzBpf2p.cxx rename to src/sfizz/gen/filters/sfzBpf2p.hxx diff --git a/src/sfizz/gen/filters/sfzBpf2pSv.cxx b/src/sfizz/gen/filters/sfzBpf2pSv.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzBpf2pSv.cxx rename to src/sfizz/gen/filters/sfzBpf2pSv.hxx diff --git a/src/sfizz/gen/filters/sfzBpf4p.cxx b/src/sfizz/gen/filters/sfzBpf4p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzBpf4p.cxx rename to src/sfizz/gen/filters/sfzBpf4p.hxx diff --git a/src/sfizz/gen/filters/sfzBpf6p.cxx b/src/sfizz/gen/filters/sfzBpf6p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzBpf6p.cxx rename to src/sfizz/gen/filters/sfzBpf6p.hxx diff --git a/src/sfizz/gen/filters/sfzBrf1p.cxx b/src/sfizz/gen/filters/sfzBrf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzBrf1p.cxx rename to src/sfizz/gen/filters/sfzBrf1p.hxx diff --git a/src/sfizz/gen/filters/sfzBrf2p.cxx b/src/sfizz/gen/filters/sfzBrf2p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzBrf2p.cxx rename to src/sfizz/gen/filters/sfzBrf2p.hxx diff --git a/src/sfizz/gen/filters/sfzBrf2pSv.cxx b/src/sfizz/gen/filters/sfzBrf2pSv.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzBrf2pSv.cxx rename to src/sfizz/gen/filters/sfzBrf2pSv.hxx diff --git a/src/sfizz/gen/filters/sfzEqHshelf.cxx b/src/sfizz/gen/filters/sfzEqHshelf.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzEqHshelf.cxx rename to src/sfizz/gen/filters/sfzEqHshelf.hxx diff --git a/src/sfizz/gen/filters/sfzEqLshelf.cxx b/src/sfizz/gen/filters/sfzEqLshelf.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzEqLshelf.cxx rename to src/sfizz/gen/filters/sfzEqLshelf.hxx diff --git a/src/sfizz/gen/filters/sfzEqPeak.cxx b/src/sfizz/gen/filters/sfzEqPeak.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzEqPeak.cxx rename to src/sfizz/gen/filters/sfzEqPeak.hxx diff --git a/src/sfizz/gen/filters/sfzHpf1p.cxx b/src/sfizz/gen/filters/sfzHpf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzHpf1p.cxx rename to src/sfizz/gen/filters/sfzHpf1p.hxx diff --git a/src/sfizz/gen/filters/sfzHpf2p.cxx b/src/sfizz/gen/filters/sfzHpf2p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzHpf2p.cxx rename to src/sfizz/gen/filters/sfzHpf2p.hxx diff --git a/src/sfizz/gen/filters/sfzHpf2pSv.cxx b/src/sfizz/gen/filters/sfzHpf2pSv.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzHpf2pSv.cxx rename to src/sfizz/gen/filters/sfzHpf2pSv.hxx diff --git a/src/sfizz/gen/filters/sfzHpf4p.cxx b/src/sfizz/gen/filters/sfzHpf4p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzHpf4p.cxx rename to src/sfizz/gen/filters/sfzHpf4p.hxx diff --git a/src/sfizz/gen/filters/sfzHpf6p.cxx b/src/sfizz/gen/filters/sfzHpf6p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzHpf6p.cxx rename to src/sfizz/gen/filters/sfzHpf6p.hxx diff --git a/src/sfizz/gen/filters/sfzHsh.cxx b/src/sfizz/gen/filters/sfzHsh.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzHsh.cxx rename to src/sfizz/gen/filters/sfzHsh.hxx diff --git a/src/sfizz/gen/filters/sfzLpf1p.cxx b/src/sfizz/gen/filters/sfzLpf1p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzLpf1p.cxx rename to src/sfizz/gen/filters/sfzLpf1p.hxx diff --git a/src/sfizz/gen/filters/sfzLpf2p.cxx b/src/sfizz/gen/filters/sfzLpf2p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzLpf2p.cxx rename to src/sfizz/gen/filters/sfzLpf2p.hxx diff --git a/src/sfizz/gen/filters/sfzLpf2pSv.cxx b/src/sfizz/gen/filters/sfzLpf2pSv.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzLpf2pSv.cxx rename to src/sfizz/gen/filters/sfzLpf2pSv.hxx diff --git a/src/sfizz/gen/filters/sfzLpf4p.cxx b/src/sfizz/gen/filters/sfzLpf4p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzLpf4p.cxx rename to src/sfizz/gen/filters/sfzLpf4p.hxx diff --git a/src/sfizz/gen/filters/sfzLpf6p.cxx b/src/sfizz/gen/filters/sfzLpf6p.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzLpf6p.cxx rename to src/sfizz/gen/filters/sfzLpf6p.hxx diff --git a/src/sfizz/gen/filters/sfzLsh.cxx b/src/sfizz/gen/filters/sfzLsh.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzLsh.cxx rename to src/sfizz/gen/filters/sfzLsh.hxx diff --git a/src/sfizz/gen/filters/sfzPeq.cxx b/src/sfizz/gen/filters/sfzPeq.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzPeq.cxx rename to src/sfizz/gen/filters/sfzPeq.hxx diff --git a/src/sfizz/gen/filters/sfzPink.cxx b/src/sfizz/gen/filters/sfzPink.hxx similarity index 100% rename from src/sfizz/gen/filters/sfzPink.cxx rename to src/sfizz/gen/filters/sfzPink.hxx From 9bb633e50dfba47580db76794a57432bd7afff6e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 24 Feb 2021 23:54:32 +0100 Subject: [PATCH 325/668] Add the faust helpers for cmake --- CMakeLists.txt | 1 + cmake/SfizzFaust.cmake | 72 +++++++ scripts/faustwrap.d | 393 +++++++++++++++++++++++++++++++++++++ src/sfizz/dsp/platform.lib | 18 ++ 4 files changed, 484 insertions(+) create mode 100644 cmake/SfizzFaust.cmake create mode 100755 scripts/faustwrap.d create mode 100644 src/sfizz/dsp/platform.lib diff --git a/CMakeLists.txt b/CMakeLists.txt index dce2d0da..c4b982fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ option_ex (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds" OFF) include (SfizzConfig) include (SfizzDeps) +include (SfizzFaust) # Don't use IPO in non Release builds include (CheckIPO) diff --git a/cmake/SfizzFaust.cmake b/cmake/SfizzFaust.cmake new file mode 100644 index 00000000..a69ee115 --- /dev/null +++ b/cmake/SfizzFaust.cmake @@ -0,0 +1,72 @@ +include(CMakeParseArguments) + +option(SFIZZ_RECOMPILE_FAUST "Recompile faust sources" OFF) + +if(SFIZZ_RECOMPILE_FAUST) + find_program(RDMD "rdmd") + if(NOT RDMD) + message(FATAL_ERROR "rdmd is missing, it is required for regenerating faust sources.") + endif() +endif() + +function(add_faust_command INPUT OUTPUT) + set(_options ONE_SAMPLE DOUBLE IN_PLACE VECTORIZE MATH_APPROXIMATION) + set(_one_args PROCESS_NAME CLASS_NAME SUPERCLASS_NAME) + set(_multi_args IMPORT_DIRS) + cmake_parse_arguments(_FAUST "${_options}" "${_one_args}" "${_multi_args}" ${ARGN}) + if(NOT SFIZZ_RECOMPILE_FAUST) + return() + endif() + if(NOT RDMD) + return() + endif() + if(NOT INPUT) + message(FATAL_ERROR "No input file given.") + endif() + if(NOT OUTPUT) + message(FATAL_ERROR "No output file given.") + endif() + set(_cmd "${RDMD}" "${PROJECT_SOURCE_DIR}/scripts/faustwrap.d") + if(NOT IS_ABSOLUTE "${INPUT}") + set(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}") + endif() + if(NOT IS_ABSOLUTE "${OUTPUT}") + set(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/${OUTPUT}") + endif() + get_filename_component(_output_dir "${OUTPUT}" DIRECTORY) + file(MAKE_DIRECTORY "${_output_dir}") + list(APPEND _cmd "-o" "${OUTPUT}" "${INPUT}") + if(_FAUST_ONE_SAMPLE) + list(APPEND _cmd "--os") + endif() + if(_FAUST_DOUBLE) + list(APPEND _cmd "--double") + endif() + if(_FAUST_IN_PLACE) + list(APPEND _cmd "--inpl") + endif() + if(_FAUST_VECTORIZE) + list(APPEND _cmd "--vec") + endif() + if(_FAUST_MATH_APPROXIMATION) + list(APPEND _cmd "--mapp") + endif() + if(_FAUST_PROCESS_NAME) + list(APPEND _cmd "--pn" "${_FAUST_PROCESS_NAME}") + endif() + if(_FAUST_CLASS_NAME) + list(APPEND _cmd "--cn" "${_FAUST_CLASS_NAME}") + endif() + if(_FAUST_SUPERCLASS_NAME) + list(APPEND _cmd "--scn" "${_FAUST_SUPERCLASS_NAME}") + endif() + if (_FAUST_IMPORT_DIRS) + foreach(_dir IN LISTS _FAUST_IMPORT_DIRS) + if(NOT IS_ABSOLUTE "${_dir}") + set(_dir "${CMAKE_CURRENT_SOURCE_DIR}/${_dir}") + endif() + list(APPEND _cmd "--import-dir" "${_dir}") + endforeach() + endif() + add_custom_command(OUTPUT "${OUTPUT}" COMMAND ${_cmd} DEPENDS "${INPUT}") +endfunction() diff --git a/scripts/faustwrap.d b/scripts/faustwrap.d new file mode 100755 index 00000000..aad1e47d --- /dev/null +++ b/scripts/faustwrap.d @@ -0,0 +1,393 @@ +#!/usr/bin/env rdmd + +import std.conv; +import std.algorithm; +import std.getopt; +import std.process; +import std.regex; +import std.uni; +import std.ascii; +import std.string; +import std.array; +import std.stdio; +import core.stdc.stdlib; + +enum string prologue = `#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif +`; + +enum string epilogue = ` +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS +`; + +void main(string[] args) +{ + struct Opts { + string outputPath; + string className = "mydsp"; + string superclassName = null; + bool oneSample = false; + bool doublePrecision = false; + bool inPlace = false; + bool vectorize = false; + bool mathApproximation = false; + string processName = null; + string[] importDirs; + } + + Opts opts; + + auto optInfo = getopt(args, + "out|o", "Output path", &opts.outputPath, + "cn", "Class name", &opts.className, + "scn", "Superclass name", &opts.superclassName, + "os", "One sample", &opts.oneSample, + "double", "Double precision", &opts.doublePrecision, + "inpl", "In-place", &opts.inPlace, + "vec", "Vectorization", &opts.vectorize, + "mapp", "Math approximation", &opts.mathApproximation, + "pn", "Process name", &opts.processName, + "import-dir|I", "Import directory", &opts.importDirs); + + if (optInfo.helpWanted) + { + defaultGetoptPrinter("MyFaust", optInfo.options); + return; + } + + if (args.length != 2) + { + writeln("You must indicate exactly 1 input file."); + exit(1); + } + + string[] cmd = [getFaust()]; + cmd ~= "-cn"; + cmd ~= opts.className; + if (opts.superclassName) + { + cmd ~= "-scn"; + cmd ~= opts.superclassName; + } + if (opts.oneSample) + cmd ~= "-os"; + if (opts.doublePrecision) + cmd ~= "-double"; + if (opts.inPlace) + cmd ~= "-inpl"; + if (opts.vectorize) + cmd ~= "-vec"; + if (opts.mathApproximation) + cmd ~= "-mapp"; + if (opts.processName) + { + cmd ~= "-pn"; + cmd ~= opts.processName; + } + foreach (string dir; opts.importDirs) + { + cmd ~= "-I"; + cmd ~= dir; + } + cmd ~= args[1]; + + auto result = execute(cmd, null, Config.stderrPassThrough|Config.suppressConsole); + if (result.status != 0) + exit(1); + + string code = result.output; + Parameter[] params = findParameters(code); + + code = removeVirtualKeyword(code); + foreach (string method; ["metadata", "getInputRate", "getOutputRate", "clone", "buildUserInterface"]) + code = removeMethod(code, method); + foreach (string method; ["getNumInputs", "getNumOutputs"]) + code = makeMethodStaticConstexpr(code, method); + if (!opts.superclassName) + code = removeSuperclass(code); + code = makePointerArgsConst(code, opts.oneSample); + code = addParameters(code, params); + + foreach (string method; ["compute", "classInit", "instanceConstants", "instanceResetUserInterface", "instanceClear", "init", "instanceInit"]) + code = addMethodStartEnd(code, method); + code = addClassStartEnd(code); + + File outFile = stdout; + if (opts.outputPath) + outFile = File(opts.outputPath, "w"); + outFile.writef("%s%s%s", prologue, code, epilogue); + outFile.flush(); +} + +final class Parameter +{ + string name; + string var; + bool readonly; +}; + +Parameter[] findParameters(string code) +{ + Parameter[] params; + + auto expr = regex(`->add(Button|CheckButton|VerticalSlider|HorizontalSlider|NumEntry|HorizontalBargraph|VerticalBargraph)\("([^"]*)", &([a-zA-Z0-9_]+)`); + + foreach (string line; code.lineSplitter) + { + auto match = line.matchFirst(expr); + if (match) + { + Parameter param = new Parameter; + param.name = match[2]; + param.var = match[3]; + param.readonly = ["HorizontalBargraph", "VerticalBargraph"].canFind(match[1]); + params ~= param; + } + } + + return params; +} + +string removeVirtualKeyword(string code) +{ + auto expr = regex(`\bvirtual\s*\b`); + return code.replaceAll(expr, ""); +} + +string removeMethod(string code, string method) +{ + string[] newLines; + newLines.reserve(1024); + + auto expr = regex(`^(\s*).*\b` ~ method.escaper.to!string ~ `\s*\(.*\{\s*$`); + + bool inMethod = false; + string eom = null; + + foreach (string line; code.lineSplitter) + { + if (inMethod) + { + if (line.stripRight == eom) + inMethod = false; + } + else + { + auto match = line.matchFirst(expr); + if (match) + { + inMethod = true; + eom = match[1] ~ '}'; + } + else + newLines ~= line; + } + } + + return newLines.join('\n'); +} + +string makeMethodStaticConstexpr(string code, string method) +{ + string[] newLines; + newLines.reserve(1024); + + auto expr = regex(`^(\s*)(.*\b` ~ method.escaper.to!string ~ `\s*\(.*\{\s*)$`); + + foreach (string line; code.lineSplitter) + { + auto match = line.matchFirst(expr); + if (match) + newLines ~= match[1] ~ "static constexpr " ~ match[2]; + else + newLines ~= line; + } + + return newLines.join('\n'); +} + +string removeSuperclass(string code) +{ + auto expr = regex(`\s*:\s*public\s+dsp\s*`); + return code.replaceFirst(expr, " "); +} + +string makePointerArgsConst(string code, bool oneSample) +{ + if (!oneSample) + { + auto expr = regex(`\bvoid\s+compute\s*\(\s*([^,)]+)\s*,\s*([^,)]+)\s*,\s*([^,)]+)\s*\)`); + auto match = code.matchFirst(expr); + + string arg1 = match[1]; + string arg2 = match[2]; + string arg3 = match[3]; + + auto exprArg = regex(`^FAUSTFLOAT\s*\*\s*\*`); + arg2 = arg2.replaceFirst(exprArg, "FAUSTFLOAT const* const*"); + arg3 = arg3.replaceFirst(exprArg, "FAUSTFLOAT* const*"); + + ulong start = match[0].ptr - code.ptr; + ulong end = start + match[0].length; + code = format("%svoid compute(%s, %s, %s)%s", code[0..start], arg1, arg2, arg3, code[end..$]); + + // + auto exprStmt = regex(`FAUSTFLOAT\s*\*\s*(input\d+)`); + code = code.replaceAll(exprStmt, "FAUSTFLOAT const* $1"); + } + else + { + auto expr = regex(`\bvoid\s+compute\s*\(\s*([^,)]+)\s*,\s*([^,)]+)\s*,\s*([^,)]+)\s*,\s*([^,)]+)\s*\)`); + auto match = code.matchFirst(expr); + + string arg1 = match[1]; + string arg2 = match[2]; + string arg3 = match[3]; + string arg4 = match[4]; + + auto exprArg = regex(`^(FAUSTFLOAT|int)\s*\*`); + arg1 = arg1.replaceFirst(exprArg, "$1 const*"); + arg3 = arg3.replaceFirst(exprArg, "$1 const*"); + arg4 = arg4.replaceFirst(exprArg, "$1 const*"); + + ulong start = match[0].ptr - code.ptr; + ulong end = start + match[0].length; + code = format("%svoid compute(%s, %s, %s, %s)%s", code[0..start], arg1, arg2, arg3, arg4, code[end..$]); + } + + return code; +} + +string addParameters(string code, Parameter[] params) +{ + string[] addedLines; + + foreach (Parameter param; params) + { + string camelName = param.name.camelify; + addedLines ~= ""; + addedLines ~= format(` FAUSTFLOAT get%s() const { return %s; }`, camelName, param.var); + if (!param.readonly) + addedLines ~= format(` void set%s(FAUSTFLOAT value) { %s = value; }`, camelName, param.var); + } + + return addToClass(code, addedLines.join('\n')); +} + +string addMethodStartEnd(string code, string method) +{ + string[] newLines; + newLines.reserve(1024); + + auto expr = regex(`^(\s*).*\b` ~ method.escaper.to!string ~ `\s*\(.*\{\s*$`); + + bool inMethod = false; + string eom = null; + + foreach (string line; code.lineSplitter) + { + if (inMethod) + { + if (line.stripRight == eom) + { + newLines ~= "\t\t//[End:" ~ method ~ "]"; + inMethod = false; + } + newLines ~= line; + } + else + { + newLines ~= line; + auto match = line.matchFirst(expr); + if (match) + { + inMethod = true; + eom = match[1] ~ '}'; + newLines ~= "\t\t//[Begin:" ~ method ~ "]"; + } + } + } + + return newLines.join('\n'); +} + +string addClassStartEnd(string code) +{ + { + auto expr = regex(`^class\b.*$`, "m"); + auto match = code.matchFirst(expr); + ulong start = match[0].ptr - code.ptr; + ulong end = start + match[0].length; + code = code[0..start] ~ "\n//[Before:class]\n" ~ match[0] ~ "\n\t//[Begin:class]\n" ~ code[end..$]; + } + + { + auto expr = regex(`^\};`, "m"); + auto match = code.matchLast(expr); + ulong start = match[0].ptr - code.ptr; + ulong end = start + match[0].length; + code = code[0..start] ~ "\n\t//[End:class]\n" ~ match[0] ~ "\n//[After:class]\n" ~ code[end..$]; + } + + return code; +} + +string addToClass(string code, string addend) +{ + if (addend.empty) + return code; + + auto expr = regex(`^\};`, "m"); + auto match = code.matchLast(expr); + ulong index = match[0].ptr - code.ptr; + return code[0..index] ~ addend ~ '\n' ~ code[index..$]; +} + +string camelify(string name) +{ + dchar[] result; + result.reserve(name.length); + + bool isIdentifierChar(dchar ch) + { + return std.ascii.isAlphaNum(ch) || ch == '_'; + } + + dchar[] temp = name.to!(dchar[]); + + foreach (ref dchar uniChar; temp) + { + uniChar = [uniChar].normalize!NFD[0]; + if (!isIdentifierChar(uniChar)) + uniChar = ' '; + } + + foreach (dchar[] part; temp.split(' ')) + { + if (!part.empty) + part[0] = std.uni.toUpper(part[0]); + result ~= part; + } + + return result.to!string; +} + +Captures!S matchLast(S, R)(S input, R expr) +{ + Captures!S last; + foreach (Captures!S current; input.matchAll(expr)) + last = current; + return last; +} + +string getFaust() +{ + char *env = getenv("FAUST"); + return env ? env.to!string : "faust"; +} diff --git a/src/sfizz/dsp/platform.lib b/src/sfizz/dsp/platform.lib new file mode 100644 index 00000000..9cd53a3f --- /dev/null +++ b/src/sfizz/dsp/platform.lib @@ -0,0 +1,18 @@ +//----------------------------------------------------------------------------- +// A version of platform.lib which does not limit the sample rate. +// This allows use of high oversampling factors. +//----------------------------------------------------------------------------- + +declare name "sfizz Generic Platform Library"; +declare license "BSD-2-Clause"; + +//---------------------------------`(pl.)SR`----------------------------------- +// Current sampling rate (between 1Hz and 192000Hz). Constant during +// program execution. +//----------------------------------------------------------------------------- +SR = fconstant(int fSamplingFreq, ); + +//---------------------------------`(pl.)tablesize`---------------------------- +// Oscillator table size +//----------------------------------------------------------------------------- +tablesize = 1 << 16; From cd43cac59b67fee68205fd0e721f2b2a28459880 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 00:01:56 +0100 Subject: [PATCH 326/668] Faust filters automatically generated --- src/CMakeLists.txt | 30 ++++++++++++++++++++++++++++++ src/sfizz/SfzFilterImpls.hpp | 20 ++++++++++---------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ee7dbc3b..cc19c67f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -310,6 +310,36 @@ endif() # Generic library alias add_library(sfizz::sfizz ALIAS sfizz_static) +# Preserve generated files (Faust) +set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE) + +# Faust filters +foreach(filter_type + Lpf1p Lpf2p Lpf4p Lpf6p Hpf1p Hpf2p Hpf4p Hpf6p + Bpf1p Bpf2p Bpf4p Bpf6p Apf1p Brf1p Brf2p + Pink Lpf2pSv Hpf2pSv Bpf2pSv Brf2pSv + Lsh Hsh Peq EqPeak EqLshelf EqHshelf) + add_faust_command( + "sfizz/dsp/filters/sfz_filters.dsp" + "sfizz/gen/filters/sfz${filter_type}.hxx" + DOUBLE IN_PLACE + PROCESS_NAME "sfz${filter_type}" + CLASS_NAME "faust${filter_type}" + SUPERCLASS_NAME "sfzFilterDsp" + IMPORT_DIRS "sfizz/dsp") + add_faust_command( + "sfizz/dsp/filters/sfz_filters.dsp" + "sfizz/gen/filters/sfz2ch${filter_type}.hxx" + DOUBLE IN_PLACE + PROCESS_NAME "sfz2ch${filter_type}" + CLASS_NAME "faust2ch${filter_type}" + SUPERCLASS_NAME "sfzFilterDsp" + IMPORT_DIRS "sfizz/dsp") + target_sources(sfizz_internal PRIVATE + "sfizz/gen/filters/sfz${filter_type}.hxx" + "sfizz/gen/filters/sfz2ch${filter_type}.hxx") +endforeach() + # Windows installer if(WIN32) include(VSTConfig) diff --git a/src/sfizz/SfzFilterImpls.hpp b/src/sfizz/SfzFilterImpls.hpp index 613a41d5..72bb0fb8 100644 --- a/src/sfizz/SfzFilterImpls.hpp +++ b/src/sfizz/SfzFilterImpls.hpp @@ -16,7 +16,7 @@ public: virtual void init(int) = 0; virtual void instanceClear() = 0; - virtual void compute(int, float **, float **) = 0; + virtual void compute(int, const float *const *, float *const *) = 0; virtual void configureStandard(float, float, float) {} virtual void configureEq(float, float, float) {} @@ -105,8 +105,8 @@ protected: template struct sfzFilter : public F { void configureStandard(float cutoff, float q, float pksh) override { - F::fCutoff = cutoff; - F::fQ = q; + this->setCutoff(cutoff); + this->setResonance(q); (void)pksh; } }; @@ -118,7 +118,7 @@ template struct sfzFilter : public F { template struct sfzFilterNoQ : public F { void configureStandard(float cutoff, float q, float pksh) override { - F::fCutoff = cutoff; + this->setCutoff(cutoff); (void)q; (void)pksh; } @@ -144,9 +144,9 @@ template struct sfzFilterNoCutoff : public F { template struct sfzFilterPkSh : public F { void configureStandard(float cutoff, float q, float pksh) override { - F::fCutoff = cutoff; - F::fQ = q; - F::fPkShGain = pksh; + this->setCutoff(cutoff); + this->setResonance(q); + this->setPeakShelfGain(pksh); } }; @@ -157,9 +157,9 @@ template struct sfzFilterPkSh : public F { template struct sfzFilterEq : public F { void configureEq(float cutoff, float bw, float pksh) override { - F::fCutoff = cutoff; - F::fBandwidth = bw; - F::fPkShGain = pksh; + this->setCutoff(cutoff); + this->setBandwidth(bw); + this->setPeakShelfGain(pksh); } }; From 5c5c4342970cb3a3179fec307ac170931215d9fa Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 00:16:24 +0100 Subject: [PATCH 327/668] Update fx with faust helpers, change oversampling strategy --- src/CMakeLists.txt | 38 +++++++++++++++++++++++++++ src/sfizz/effects/Compressor.cpp | 29 ++++++++------------ src/sfizz/effects/Disto.cpp | 17 ++++-------- src/sfizz/effects/Fverb.cpp | 30 +++++++++------------ src/sfizz/effects/Gate.cpp | 29 ++++++++------------ src/sfizz/effects/Limiter.cpp | 6 ++--- src/sfizz/effects/dsp/compressor.dsp | 5 ++-- src/sfizz/effects/dsp/disto_stage.dsp | 4 +-- src/sfizz/effects/dsp/gate.dsp | 7 +++-- src/sfizz/effects/dsp/limiter.dsp | 5 ++-- 10 files changed, 88 insertions(+), 82 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc19c67f..7be3fd64 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -340,6 +340,44 @@ foreach(filter_type "sfizz/gen/filters/sfz2ch${filter_type}.hxx") endforeach() +# Faust effects +add_faust_command( + "sfizz/effects/dsp/compressor.dsp" + "sfizz/effects/gen/compressor.hxx" + IN_PLACE + CLASS_NAME "faustCompressor" + IMPORT_DIRS "sfizz/dsp") +add_faust_command( + "sfizz/effects/dsp/disto_stage.dsp" + "sfizz/effects/gen/disto_stage.hxx" + IN_PLACE + CLASS_NAME "faustDisto" + IMPORT_DIRS "sfizz/dsp") +add_faust_command( + "sfizz/effects/dsp/fverb.dsp" + "sfizz/effects/gen/fverb.hxx" + IN_PLACE + CLASS_NAME "faustFverb" + IMPORT_DIRS "sfizz/dsp") +add_faust_command( + "sfizz/effects/dsp/gate.dsp" + "sfizz/effects/gen/gate.hxx" + IN_PLACE + CLASS_NAME "faustGate" + IMPORT_DIRS "sfizz/dsp") +add_faust_command( + "sfizz/effects/dsp/limiter.dsp" + "sfizz/effects/gen/limiter.hxx" + IN_PLACE + CLASS_NAME "faustLimiter" + IMPORT_DIRS "sfizz/dsp") +target_sources(sfizz_internal PRIVATE + "sfizz/effects/gen/compressor.hxx" + "sfizz/effects/gen/disto_stage.hxx" + "sfizz/effects/gen/fverb.hxx" + "sfizz/effects/gen/gate.hxx" + "sfizz/effects/gen/limiter.hxx") + # Windows installer if(WIN32) include(VSTConfig) diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index f2608531..0cd528dc 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -17,6 +17,7 @@ */ #include "Compressor.h" +#include "gen/compressor.hxx" #include "Opcode.h" #include "AudioSpan.h" #include "MathHelpers.h" @@ -24,8 +25,6 @@ #include "absl/memory/memory.h" static constexpr int _oversampling = 2; -#define FAUST_UIMACROS 1 -#include "gen/compressor.hxx" namespace sfz { namespace fx { @@ -38,12 +37,6 @@ namespace fx { AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; hiir::Downsampler2x<12> _downsampler2x[EffectChannels]; hiir::Upsampler2x<12> _upsampler2x[EffectChannels]; - - #define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \ - float get_##ident(size_t i) const noexcept { return _compressor[i].var; } \ - void set_##ident(size_t i, float value) noexcept { _compressor[i].var = value; } - FAUST_LIST_ACTIVES(DEFINE_SET_GET); - #undef DEFINE_SET_GET }; Compressor::Compressor() @@ -62,8 +55,8 @@ namespace fx { { Impl& impl = *_impl; for (faustCompressor& comp : impl._compressor) { - comp.classInit(sampleRate); - comp.instanceConstants(sampleRate); + comp.classInit(_oversampling * sampleRate); + comp.instanceConstants(_oversampling * sampleRate); } for (unsigned c = 0; c < EffectChannels; ++c) { @@ -164,29 +157,29 @@ namespace fx { case hash("comp_attack"): { auto value = opc.read(Default::compAttack); - for (size_t c = 0; c < 2; ++c) - impl.set_Attack(c, value); + for (faustCompressor& comp : impl._compressor) + comp.setAttack(value); } break; case hash("comp_release"): { auto value = opc.read(Default::compRelease); - for (size_t c = 0; c < 2; ++c) - impl.set_Release(c, value); + for (faustCompressor& comp : impl._compressor) + comp.setRelease(value); } break; case hash("comp_threshold"): { auto value = opc.read(Default::compThreshold); - for (size_t c = 0; c < 2; ++c) - impl.set_Threshold(c, value); + for (faustCompressor& comp : impl._compressor) + comp.setThreshold(value); } break; case hash("comp_ratio"): { auto value = opc.read(Default::compRatio); - for (size_t c = 0; c < 2; ++c) - impl.set_Ratio(c, value); + for (faustCompressor& comp : impl._compressor) + comp.setRatio(value); } break; case hash("comp_gain"): diff --git a/src/sfizz/effects/Disto.cpp b/src/sfizz/effects/Disto.cpp index ed9d3487..05ba158c 100644 --- a/src/sfizz/effects/Disto.cpp +++ b/src/sfizz/effects/Disto.cpp @@ -19,6 +19,7 @@ */ #include "Disto.h" +#include "gen/disto_stage.hxx" #include "Opcode.h" #include "Config.h" #include "MathHelpers.h" @@ -27,8 +28,6 @@ #include static constexpr int _oversampling = 8; -#define FAUST_UIMACROS 1 -#include "gen/disto_stage.hxx" namespace sfz { namespace fx { @@ -56,12 +55,6 @@ struct Disto::Impl { float mk = 21.0f + _tone * 1.08f; return 440.0f * std::exp2((mk - 69.0f) * (1.0f / 12.0f)); } - - #define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \ - float get_##ident(size_t c, size_t s) const noexcept { return _stages[c][s].var; } \ - void set_##ident(size_t c, size_t s, float value) noexcept { _stages[c][s].var = value; } - FAUST_LIST_ACTIVES(DEFINE_SET_GET); - #undef DEFINE_SET_GET }; Disto::Disto() @@ -71,7 +64,7 @@ Disto::Disto() for (unsigned c = 0; c < EffectChannels; ++c) { for (faustDisto& stage : impl._stages[c]) - stage.init(config::defaultSampleRate); + stage.init(_oversampling * config::defaultSampleRate); } } @@ -86,8 +79,8 @@ void Disto::setSampleRate(double sampleRate) for (unsigned c = 0; c < EffectChannels; ++c) { for (faustDisto& stage : impl._stages[c]) { - stage.classInit(sampleRate); - stage.instanceConstants(sampleRate); + stage.classInit(_oversampling * sampleRate); + stage.instanceConstants(_oversampling * sampleRate); } } } @@ -150,7 +143,7 @@ void Disto::process(const float* const inputs[], float* const outputs[], unsigne absl::Span stageInOut = upsamplerOut; for (unsigned s = 0, numStages = impl._numStages; s < numStages; ++s) { // set depth parameter (TODO modulation) - impl.set_Depth(c, s, depth); + impl._stages[c][s].setDepth(depth); // float *faustIn[] = { stageInOut.data() }; float *faustOut[] = { stageInOut.data() }; diff --git a/src/sfizz/effects/Fverb.cpp b/src/sfizz/effects/Fverb.cpp index f5161533..804e12a3 100644 --- a/src/sfizz/effects/Fverb.cpp +++ b/src/sfizz/effects/Fverb.cpp @@ -5,14 +5,13 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Fverb.h" +#include "gen/fverb.hxx" #include "Opcode.h" #include "Config.h" #include "MathHelpers.h" #include #include #include -#define FAUST_UIMACROS 1 -#include "gen/fverb.hxx" /** Note(jpc): implementation status @@ -40,12 +39,6 @@ namespace fx { struct Fverb::Impl { faustFverb dsp; - #define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \ - float get_##ident() const noexcept { return dsp.var; } \ - void set_##ident(float value) noexcept { dsp.var = value; } - FAUST_LIST_ACTIVES(DEFINE_SET_GET); - #undef DEFINE_SET_GET - struct Profile { float tailDensity; // % float decayAtMaxSize; // % @@ -240,17 +233,18 @@ namespace fx { const float decayMin = decayMax * 0.5f; Impl& impl = *reverb->impl_; - impl.set_Predelay(predelay * 1e3); - impl.set_Tail_density(profile->tailDensity); - impl.set_Decay(decayMax * size * 0.01f + decayMin * (1.0f - size * 0.01f)); - impl.set_Modulator_frequency(profile->modulationFrequency); - impl.set_Modulator_depth(profile->modulationDepth); - impl.set_Dry(profile->dry * dry * 0.01f); - impl.set_Wet(profile->wet * wet * 0.01f); - impl.set_Input_amount(input); - impl.set_Input_low_pass_cutoff(Impl::lpfCutoff(tone)); + faustFverb& dsp = impl.dsp; + dsp.setPredelay(predelay * 1e3); + dsp.setTailDensity(profile->tailDensity); + dsp.setDecay(decayMax * size * 0.01f + decayMin * (1.0f - size * 0.01f)); + dsp.setModulatorFrequency(profile->modulationFrequency); + dsp.setModulatorDepth(profile->modulationDepth); + dsp.setDry(profile->dry * dry * 0.01f); + dsp.setWet(profile->wet * wet * 0.01f); + dsp.setInputAmount(input); + dsp.setInputLowPassCutoff(Impl::lpfCutoff(tone)); // NOTE(jpc): damp formula not well calibrated, but sounds ok-ish - impl.set_Damping(Impl::lpfCutoff(100 - 0.5 * damp)); + dsp.setDamping(Impl::lpfCutoff(100 - 0.5 * damp)); return fx; } diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index bfe8fdfc..e8852dfb 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -20,6 +20,7 @@ */ #include "Gate.h" +#include "gen/gate.hxx" #include "Opcode.h" #include "AudioSpan.h" #include "MathHelpers.h" @@ -27,8 +28,6 @@ #include "absl/memory/memory.h" static constexpr int _oversampling = 2; -#define FAUST_UIMACROS 1 -#include "gen/gate.hxx" namespace sfz { namespace fx { @@ -41,12 +40,6 @@ namespace fx { AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; hiir::Downsampler2x<12> _downsampler2x[EffectChannels]; hiir::Upsampler2x<12> _upsampler2x[EffectChannels]; - - #define DEFINE_SET_GET(type, ident, name, var, def, min, max, step) \ - float get_##ident(size_t i) const noexcept { return _gate[i].var; } \ - void set_##ident(size_t i, float value) noexcept { _gate[i].var = value; } - FAUST_LIST_ACTIVES(DEFINE_SET_GET); - #undef DEFINE_SET_GET }; Gate::Gate() @@ -65,8 +58,8 @@ namespace fx { { Impl& impl = *_impl; for (faustGate& gate : impl._gate) { - gate.classInit(sampleRate); - gate.instanceConstants(sampleRate); + gate.classInit(_oversampling * sampleRate); + gate.instanceConstants(_oversampling * sampleRate); } for (unsigned c = 0; c < EffectChannels; ++c) { @@ -167,29 +160,29 @@ namespace fx { case hash("gate_attack"): { auto value = opc.read(Default::gateAttack); - for (size_t c = 0; c < 2; ++c) - impl.set_Attack(c, value); + for (faustGate& gate : impl._gate) + gate.setAttack(value); } break; case hash("gate_hold"): { auto value = opc.read(Default::gateHold); - for (size_t c = 0; c < 2; ++c) - impl.set_Hold(c, value); + for (faustGate& gate : impl._gate) + gate.setHold(value); } break; case hash("gate_release"): { auto value = opc.read(Default::gateRelease); - for (size_t c = 0; c < 2; ++c) - impl.set_Release(c, value); + for (faustGate& gate : impl._gate) + gate.setRelease(value); } break; case hash("gate_threshold"): { auto value = opc.read(Default::gateThreshold); - for (size_t c = 0; c < 2; ++c) - impl.set_Threshold(c, value); + for (faustGate& gate : impl._gate) + gate.setThreshold(value); } break; case hash("gate_stlink"): diff --git a/src/sfizz/effects/Limiter.cpp b/src/sfizz/effects/Limiter.cpp index eb5f1c3c..8c13ca62 100644 --- a/src/sfizz/effects/Limiter.cpp +++ b/src/sfizz/effects/Limiter.cpp @@ -11,12 +11,12 @@ */ #include "Limiter.h" +#include "gen/limiter.hxx" #include "Opcode.h" #include "AudioSpan.h" #include "absl/memory/memory.h" static constexpr int _oversampling = 2; -#include "gen/limiter.hxx" namespace sfz { namespace fx { @@ -33,8 +33,8 @@ namespace fx { void Limiter::setSampleRate(double sampleRate) { - _limiter->classInit(sampleRate); - _limiter->instanceConstants(sampleRate); + _limiter->classInit(_oversampling * sampleRate); + _limiter->instanceConstants(_oversampling * sampleRate); for (unsigned c = 0; c < EffectChannels; ++c) { _downsampler2x[c].set_coefs(OSCoeffs2x); diff --git a/src/sfizz/effects/dsp/compressor.dsp b/src/sfizz/effects/dsp/compressor.dsp index 6675e7c1..acec90dd 100644 --- a/src/sfizz/effects/dsp/compressor.dsp +++ b/src/sfizz/effects/dsp/compressor.dsp @@ -3,9 +3,8 @@ import("stdfaust.lib"); cgain = co.compression_gain_mono(ratio, thresh, att, rel) with { ratio = hslider("[1] Ratio", 1.0, 1.0, 20.0, 0.01); thresh = hslider("[2] Threshold [unit:dB]", 0.0, -60.0, 0.0, 0.01); - over = fconstant(int _oversampling, ); - att = hslider("[3] Attack [unit:s]", 0.0, 0.0, 0.5, 1e-3) : *(over); - rel = hslider("[4] Release [unit:s]", 0.0, 0.0, 5.0, 1e-3) : *(over); + att = hslider("[3] Attack [unit:s]", 0.0, 0.0, 0.5, 1e-3); + rel = hslider("[4] Release [unit:s]", 0.0, 0.0, 5.0, 1e-3); }; process = cgain; diff --git a/src/sfizz/effects/dsp/disto_stage.dsp b/src/sfizz/effects/dsp/disto_stage.dsp index f05a54fa..f2494745 100644 --- a/src/sfizz/effects/dsp/disto_stage.dsp +++ b/src/sfizz/effects/dsp/disto_stage.dsp @@ -1,14 +1,12 @@ import("stdfaust.lib"); disto_stage(depth, x) = shs*hh(x)+(1.0-shs)*lh(x) : fi.dcblockerat(5.0) with { - over = fconstant(int _oversampling, ); - // sigmoid parameters a = depth*0.2+2.0; b = 2.0; // smooth hysteresis transition - shs = hs : si.smooth(ba.tau2pole(10e-3*over)); + shs = hs : si.smooth(ba.tau2pole(10e-3)); // the low and high hysteresis lh(x) = sig(a*x)*b; diff --git a/src/sfizz/effects/dsp/gate.dsp b/src/sfizz/effects/dsp/gate.dsp index 7bac7f27..bbb303f3 100644 --- a/src/sfizz/effects/dsp/gate.dsp +++ b/src/sfizz/effects/dsp/gate.dsp @@ -2,10 +2,9 @@ import("stdfaust.lib"); ggain = ef.gate_gain_mono(thresh, att, hold, rel) with { thresh = hslider("[1] Threshold [unit:dB]", 0.0, -60.0, 0.0, 0.01); - over = fconstant(int _oversampling, ); - att = hslider("[2] Attack [unit:s]", 0.0, 0.0, 10.0, 1e-3) : *(over); - hold = hslider("[3] Hold [unit:s]", 0.0, 0.0, 10.0, 1e-3) : *(over); - rel = hslider("[4] Release [unit:s]", 0.0, 0.0, 5.0, 1e-3) : *(over); + att = hslider("[2] Attack [unit:s]", 0.0, 0.0, 10.0, 1e-3); + hold = hslider("[3] Hold [unit:s]", 0.0, 0.0, 10.0, 1e-3); + rel = hslider("[4] Release [unit:s]", 0.0, 0.0, 5.0, 1e-3); }; process = ggain; diff --git a/src/sfizz/effects/dsp/limiter.dsp b/src/sfizz/effects/dsp/limiter.dsp index cbb14b26..e8ed03d9 100644 --- a/src/sfizz/effects/dsp/limiter.dsp +++ b/src/sfizz/effects/dsp/limiter.dsp @@ -1,9 +1,8 @@ import("stdfaust.lib"); limiter(x) = gain*x with { - att = 0.0008 * over; - rel = 0.5 * over; - over = fconstant(int _oversampling, ); + att = 0.0008; + rel = 0.5; peak = x : an.amp_follower_ud(att, rel); gain = ba.if(peak>1.0, 1.0/peak, 1.0) : si.smooth(ba.tau2pole(0.5*att)); }; From acf8b9f15a5846fe6d9c71e9b0d6490f66438a63 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 00:24:07 +0100 Subject: [PATCH 328/668] Delete old faust scripts --- scripts/generate_compressor.sh | 54 -------------------------- scripts/generate_disto.sh | 54 -------------------------- scripts/generate_filters.sh | 70 ---------------------------------- scripts/generate_fverb.sh | 54 -------------------------- scripts/generate_gate.sh | 54 -------------------------- 5 files changed, 286 deletions(-) delete mode 100755 scripts/generate_compressor.sh delete mode 100755 scripts/generate_disto.sh delete mode 100755 scripts/generate_filters.sh delete mode 100755 scripts/generate_fverb.sh delete mode 100755 scripts/generate_gate.sh diff --git a/scripts/generate_compressor.sh b/scripts/generate_compressor.sh deleted file mode 100755 index 7d799a5e..00000000 --- a/scripts/generate_compressor.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -set -e - -if ! test -d "src"; then - echo "Please run this in the project root directory." - exit 1 -fi - -# Note: needs faust >= 2.27.1 for UI macros -FAUSTARGS="-uim -inpl" - -# support GNU sed only, use gsed on a Mac -test -z "$SED" && SED=sed - -faustgen() { - mkdir -p src/sfizz/effects/gen - local outfile=src/sfizz/effects/gen/compressor.cxx - - local code=`faust $FAUSTARGS -cn faustCompressor src/sfizz/effects/dsp/compressor.dsp` - - # suppress some faust-specific stuff we don't care - echo "$code" \ - | fgrep -v -- '->declare(' \ - | fgrep -v -- '->openHorizontalBox(' \ - | fgrep -v -- '->openVerticalBox(' \ - | fgrep -v -- '->closeBox(' \ - | fgrep -v -- '->addHorizontalSlider(' \ - | fgrep -v -- '->addVerticalSlider(' \ - > "$outfile" - - # remove metadata - $SED -r -i 's/void[ \t]+metadata[ \t]*\(Meta[ \t]*\*[ \t]*[a-zA-Z0-9_]+\)/void metadata()/' "$outfile" - - # remove UI - $SED -r -i 's/void[ \t]+buildUserInterface[ \t]*\(UI[ \t]*\*[ \t]*[a-zA-Z0-9_]+\)/void buildUserInterface()/' "$outfile" - - # remove inheritance - $SED -r -i 's/:[ \t]*public[ \t]+dsp\b\s*//' "$outfile" - - # remove virtual - $SED -r -i 's/\bvirtual\b\s*//' "$outfile" - - # remove undesired UIM - $SED -r -i '/^[ \t]*#define[ \t]+FAUST_(FILE_NAME|CLASS_NAME|INPUTS|OUTPUTS|ACTIVES|PASSIVES)/d' "$outfile" - $SED -r -i '/^[ \t]*FAUST_ADD.*/d' "$outfile" - - # direct access to parameter variables - $SED -r -i 's/\bprivate:/public:/' "$outfile" - - # remove trailing whitespace - $SED -r -i 's/[ \t]+$//' "$outfile" -} - -faustgen diff --git a/scripts/generate_disto.sh b/scripts/generate_disto.sh deleted file mode 100755 index 095cb147..00000000 --- a/scripts/generate_disto.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -set -e - -if ! test -d "src"; then - echo "Please run this in the project root directory." - exit 1 -fi - -# Note: needs faust >= 2.27.1 for UI macros -FAUSTARGS="-uim -inpl" - -# support GNU sed only, use gsed on a Mac -test -z "$SED" && SED=sed - -faustgen() { - mkdir -p src/sfizz/effects/gen - local outfile=src/sfizz/effects/gen/disto_stage.cxx - - local code=`faust $FAUSTARGS -cn faustDisto src/sfizz/effects/dsp/disto_stage.dsp` - - # suppress some faust-specific stuff we don't care - echo "$code" \ - | fgrep -v -- '->declare(' \ - | fgrep -v -- '->openHorizontalBox(' \ - | fgrep -v -- '->openVerticalBox(' \ - | fgrep -v -- '->closeBox(' \ - | fgrep -v -- '->addHorizontalSlider(' \ - | fgrep -v -- '->addVerticalSlider(' \ - > "$outfile" - - # remove metadata - $SED -r -i 's/void[ \t]+metadata[ \t]*\(Meta[ \t]*\*[ \t]*[a-zA-Z0-9_]+\)/void metadata()/' "$outfile" - - # remove UI - $SED -r -i 's/void[ \t]+buildUserInterface[ \t]*\(UI[ \t]*\*[ \t]*[a-zA-Z0-9_]+\)/void buildUserInterface()/' "$outfile" - - # remove inheritance - $SED -r -i 's/:[ \t]*public[ \t]+dsp\b\s*//' "$outfile" - - # remove virtual - $SED -r -i 's/\bvirtual\b\s*//' "$outfile" - - # remove undesired UIM - $SED -r -i '/^[ \t]*#define[ \t]+FAUST_(FILE_NAME|CLASS_NAME|INPUTS|OUTPUTS|ACTIVES|PASSIVES)/d' "$outfile" - $SED -r -i '/^[ \t]*FAUST_ADD.*/d' "$outfile" - - # direct access to parameter variables - $SED -r -i 's/\bprivate:/public:/' "$outfile" - - # remove trailing whitespace - $SED -r -i 's/[ \t]+$//' "$outfile" -} - -faustgen diff --git a/scripts/generate_filters.sh b/scripts/generate_filters.sh deleted file mode 100755 index dd1ef713..00000000 --- a/scripts/generate_filters.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/sh -set -e - -if ! test -d "src"; then - echo "Please run this in the project root directory." - exit 1 -fi - -FAUSTARGS="-double -inpl" - -# support GNU sed only, use gsed on a Mac -test -z "$SED" && SED=sed - -faustgen() { - mkdir -p src/sfizz/gen/filters - local outfile=src/sfizz/gen/filters/sfz"$1".cxx - - local code=`faust $FAUSTARGS -pn sfz"$1" -cn faust"$1" -scn sfzFilterDsp src/sfizz/dsp/filters/sfz_filters.dsp` - - # find variable names of our controls - local cutoffVar=`echo "$code" | $SED -r 's%.*\("Cutoff", &[ \t]*([a-zA-Z0-9_]+).*%\1%;t;d'` - local resoVar=`echo "$code" | $SED -r 's%.*\("Resonance", &[ \t]*([a-zA-Z0-9_]+).*%\1%;t;d'` - local pkshVar=`echo "$code" | $SED -r 's%.*\("Peak/shelf gain", &[ \t]*([a-zA-Z0-9_]+).*%\1%;t;d'` - local bwVar=`echo "$code" | $SED -r 's%.*\("Bandwidth", &[ \t]*([a-zA-Z0-9_]+).*%\1%;t;d'` - - # suppress some faust-specific stuff we don't care - echo "$code" \ - | fgrep -v -- '->declare(' \ - | fgrep -v -- '->openHorizontalBox(' \ - | fgrep -v -- '->openVerticalBox(' \ - | fgrep -v -- '->closeBox(' \ - | fgrep -v -- '->addHorizontalSlider(' \ - | fgrep -v -- '->addVerticalSlider(' \ - > "$outfile" - - # direct access to parameter variables - $SED -r -i 's/\bprivate:/public:/' "$outfile" - - # rename the variables for us to access more easily - if test ! -z "$cutoffVar"; then - $SED -r -i 's/\b'"$cutoffVar"'\b/fCutoff/' "$outfile" - fi - if test ! -z "$resoVar"; then - $SED -r -i 's/\b'"$resoVar"'\b/fQ/' "$outfile" - fi - if test ! -z "$pkshVar"; then - $SED -r -i 's/\b'"$pkshVar"'\b/fPkShGain/' "$outfile" - fi - if test ! -z "$bwVar"; then - $SED -r -i 's/\b'"$bwVar"'\b/fBandwidth/' "$outfile" - fi - - # remove trailing whitespace - $SED -r -i 's/[ \t]+$//' "$outfile" -} - -for f in \ - Lpf1p Lpf2p Lpf4p Lpf6p \ - Hpf1p Hpf2p Hpf4p Hpf6p \ - Bpf1p Bpf2p Bpf4p Bpf6p \ - Apf1p \ - Brf1p Brf2p \ - Lsh Hsh Peq \ - Pink \ - Lpf2pSv Hpf2pSv Bpf2pSv Brf2pSv \ - EqPeak EqLshelf EqHshelf -do - faustgen "$f" - faustgen "2ch$f" -done diff --git a/scripts/generate_fverb.sh b/scripts/generate_fverb.sh deleted file mode 100755 index 7c997e2b..00000000 --- a/scripts/generate_fverb.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -set -e - -if ! test -d "src"; then - echo "Please run this in the project root directory." - exit 1 -fi - -# Note: needs faust >= 2.27.1 for UI macros -FAUSTARGS="-uim -inpl" - -# support GNU sed only, use gsed on a Mac -test -z "$SED" && SED=sed - -faustgen() { - mkdir -p src/sfizz/effects/gen - local outfile=src/sfizz/effects/gen/fverb.cxx - - local code=`faust $FAUSTARGS -cn faustFverb src/sfizz/effects/dsp/fverb.dsp` - - # suppress some faust-specific stuff we don't care - echo "$code" \ - | fgrep -v -- '->declare(' \ - | fgrep -v -- '->openHorizontalBox(' \ - | fgrep -v -- '->openVerticalBox(' \ - | fgrep -v -- '->closeBox(' \ - | fgrep -v -- '->addHorizontalSlider(' \ - | fgrep -v -- '->addVerticalSlider(' \ - > "$outfile" - - # remove metadata - $SED -r -i 's/void[ \t]+metadata[ \t]*\(Meta[ \t]*\*[ \t]*[a-zA-Z0-9_]+\)/void metadata()/' "$outfile" - - # remove UI - $SED -r -i 's/void[ \t]+buildUserInterface[ \t]*\(UI[ \t]*\*[ \t]*[a-zA-Z0-9_]+\)/void buildUserInterface()/' "$outfile" - - # remove inheritance - $SED -r -i 's/:[ \t]*public[ \t]+dsp\b\s*//' "$outfile" - - # remove virtual - $SED -r -i 's/\bvirtual\b\s*//' "$outfile" - - # remove undesired UIM - $SED -r -i '/^[ \t]*#define[ \t]+FAUST_(FILE_NAME|CLASS_NAME|INPUTS|OUTPUTS|ACTIVES|PASSIVES)/d' "$outfile" - $SED -r -i '/^[ \t]*FAUST_ADD.*/d' "$outfile" - - # direct access to parameter variables - $SED -r -i 's/\bprivate:/public:/' "$outfile" - - # remove trailing whitespace - $SED -r -i 's/[ \t]+$//' "$outfile" -} - -faustgen diff --git a/scripts/generate_gate.sh b/scripts/generate_gate.sh deleted file mode 100755 index 6cb32422..00000000 --- a/scripts/generate_gate.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -set -e - -if ! test -d "src"; then - echo "Please run this in the project root directory." - exit 1 -fi - -# Note: needs faust >= 2.27.1 for UI macros -FAUSTARGS="-uim -inpl" - -# support GNU sed only, use gsed on a Mac -test -z "$SED" && SED=sed - -faustgen() { - mkdir -p src/sfizz/effects/gen - local outfile=src/sfizz/effects/gen/gate.cxx - - local code=`faust $FAUSTARGS -cn faustGate src/sfizz/effects/dsp/gate.dsp` - - # suppress some faust-specific stuff we don't care - echo "$code" \ - | fgrep -v -- '->declare(' \ - | fgrep -v -- '->openHorizontalBox(' \ - | fgrep -v -- '->openVerticalBox(' \ - | fgrep -v -- '->closeBox(' \ - | fgrep -v -- '->addHorizontalSlider(' \ - | fgrep -v -- '->addVerticalSlider(' \ - > "$outfile" - - # remove metadata - $SED -r -i 's/void[ \t]+metadata[ \t]*\(Meta[ \t]*\*[ \t]*[a-zA-Z0-9_]+\)/void metadata()/' "$outfile" - - # remove UI - $SED -r -i 's/void[ \t]+buildUserInterface[ \t]*\(UI[ \t]*\*[ \t]*[a-zA-Z0-9_]+\)/void buildUserInterface()/' "$outfile" - - # remove inheritance - $SED -r -i 's/:[ \t]*public[ \t]+dsp\b\s*//' "$outfile" - - # remove virtual - $SED -r -i 's/\bvirtual\b\s*//' "$outfile" - - # remove undesired UIM - $SED -r -i '/^[ \t]*#define[ \t]+FAUST_(FILE_NAME|CLASS_NAME|INPUTS|OUTPUTS|ACTIVES|PASSIVES)/d' "$outfile" - $SED -r -i '/^[ \t]*FAUST_ADD.*/d' "$outfile" - - # direct access to parameter variables - $SED -r -i 's/\bprivate:/public:/' "$outfile" - - # remove trailing whitespace - $SED -r -i 's/[ \t]+$//' "$outfile" -} - -faustgen From 58c7c38f2e1a4c0c912115032c5e4a9275beee48 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 00:27:21 +0100 Subject: [PATCH 329/668] Add regenerated faust source --- src/sfizz/effects/gen/compressor.hxx | 166 +++-- src/sfizz/effects/gen/disto_stage.hxx | 149 ++--- src/sfizz/effects/gen/fverb.hxx | 797 ++++++++++++----------- src/sfizz/effects/gen/gate.hxx | 155 ++--- src/sfizz/effects/gen/limiter.hxx | 252 ++++--- src/sfizz/gen/filters/sfz2chApf1p.hxx | 151 ++--- src/sfizz/gen/filters/sfz2chBpf1p.hxx | 151 ++--- src/sfizz/gen/filters/sfz2chBpf2p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chBpf2pSv.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chBpf4p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chBpf6p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chBrf1p.hxx | 151 ++--- src/sfizz/gen/filters/sfz2chBrf2p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chBrf2pSv.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chEqHshelf.hxx | 165 +++-- src/sfizz/gen/filters/sfz2chEqLshelf.hxx | 165 +++-- src/sfizz/gen/filters/sfz2chEqPeak.hxx | 163 +++-- src/sfizz/gen/filters/sfz2chHpf1p.hxx | 151 ++--- src/sfizz/gen/filters/sfz2chHpf2p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chHpf2pSv.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chHpf4p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chHpf6p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chHsh.hxx | 173 +++-- src/sfizz/gen/filters/sfz2chLpf1p.hxx | 151 ++--- src/sfizz/gen/filters/sfz2chLpf2p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chLpf2pSv.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chLpf4p.hxx | 152 +++-- src/sfizz/gen/filters/sfz2chLpf6p.hxx | 176 +++-- src/sfizz/gen/filters/sfz2chLsh.hxx | 175 +++-- src/sfizz/gen/filters/sfz2chPeq.hxx | 163 +++-- src/sfizz/gen/filters/sfz2chPink.hxx | 132 ++-- src/sfizz/gen/filters/sfzApf1p.hxx | 141 ++-- src/sfizz/gen/filters/sfzBpf1p.hxx | 141 ++-- src/sfizz/gen/filters/sfzBpf2p.hxx | 142 ++-- src/sfizz/gen/filters/sfzBpf2pSv.hxx | 142 ++-- src/sfizz/gen/filters/sfzBpf4p.hxx | 142 ++-- src/sfizz/gen/filters/sfzBpf6p.hxx | 142 ++-- src/sfizz/gen/filters/sfzBrf1p.hxx | 141 ++-- src/sfizz/gen/filters/sfzBrf2p.hxx | 142 ++-- src/sfizz/gen/filters/sfzBrf2pSv.hxx | 142 ++-- src/sfizz/gen/filters/sfzEqHshelf.hxx | 155 ++--- src/sfizz/gen/filters/sfzEqLshelf.hxx | 155 ++--- src/sfizz/gen/filters/sfzEqPeak.hxx | 153 ++--- src/sfizz/gen/filters/sfzHpf1p.hxx | 141 ++-- src/sfizz/gen/filters/sfzHpf2p.hxx | 142 ++-- src/sfizz/gen/filters/sfzHpf2pSv.hxx | 142 ++-- src/sfizz/gen/filters/sfzHpf4p.hxx | 142 ++-- src/sfizz/gen/filters/sfzHpf6p.hxx | 142 ++-- src/sfizz/gen/filters/sfzHsh.hxx | 163 ++--- src/sfizz/gen/filters/sfzLpf1p.hxx | 141 ++-- src/sfizz/gen/filters/sfzLpf2p.hxx | 142 ++-- src/sfizz/gen/filters/sfzLpf2pSv.hxx | 142 ++-- src/sfizz/gen/filters/sfzLpf4p.hxx | 142 ++-- src/sfizz/gen/filters/sfzLpf6p.hxx | 142 ++-- src/sfizz/gen/filters/sfzLsh.hxx | 165 ++--- src/sfizz/gen/filters/sfzPeq.hxx | 153 ++--- src/sfizz/gen/filters/sfzPink.hxx | 122 ++-- 57 files changed, 4606 insertions(+), 4715 deletions(-) diff --git a/src/sfizz/effects/gen/compressor.hxx b/src/sfizz/effects/gen/compressor.hxx index ba19b870..39456bab 100644 --- a/src/sfizz/effects/gen/compressor.hxx +++ b/src/sfizz/effects/gen/compressor.hxx @@ -1,7 +1,11 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ name: "compressor" -Code generated with Faust 2.27.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -scal -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -scal -ftz 0 ------------------------------------------------------------ */ #ifndef __faustCompressor_H__ @@ -9,97 +13,73 @@ Compilation options: -lang cpp -inpl -scal -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustCompressor #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustCompressor { + //[Begin:class] - public: - - float fConst0; - float fConst1; + + private: + FAUSTFLOAT fHslider0; int fSampleRate; - float fConst2; + float fConst0; FAUSTFLOAT fHslider1; FAUSTFLOAT fHslider2; float fRec2[2]; float fRec1[2]; FAUSTFLOAT fHslider3; float fRec0[2]; - + public: + - void metadata() { - } - - int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { - (void)sample_rate; + //[Begin:classInit] + //[End:classInit] } - + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = float(_oversampling); - fConst1 = (0.5f * fConst0); - fConst2 = (1.0f / std::min(192000.0f, std::max(1.0f, float(fSampleRate)))); + fConst0 = (1.0f / float(fSampleRate)); + //[End:instanceConstants] } - + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] fHslider0 = FAUSTFLOAT(0.0f); fHslider1 = FAUSTFLOAT(1.0f); fHslider2 = FAUSTFLOAT(0.0f); fHslider3 = FAUSTFLOAT(0.0f); + //[End:instanceResetUserInterface] } - + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0f; } @@ -109,73 +89,81 @@ class faustCompressor { for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec0[l2] = 0.0f; } + //[End:instanceClear] } - + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - faustCompressor* clone() { - return new faustCompressor(); - } - + + int getSampleRate() { return fSampleRate; } - - void buildUserInterface() { - } - - void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; float fSlow0 = float(fHslider0); - float fSlow1 = (fConst1 * fSlow0); + float fSlow1 = (0.5f * fSlow0); int iSlow2 = (std::fabs(fSlow1) < 1.1920929e-07f); - float fSlow3 = (iSlow2 ? 0.0f : std::exp((0.0f - (fConst2 / (iSlow2 ? 1.0f : fSlow1))))); - float fSlow4 = ((1.0f / std::max(1.00000001e-07f, float(fHslider1))) + -1.0f); - float fSlow5 = (fConst0 * fSlow0); - int iSlow6 = (std::fabs(fSlow5) < 1.1920929e-07f); - float fSlow7 = (iSlow6 ? 0.0f : std::exp((0.0f - (fConst2 / (iSlow6 ? 1.0f : fSlow5))))); - float fSlow8 = (fConst0 * float(fHslider2)); - int iSlow9 = (std::fabs(fSlow8) < 1.1920929e-07f); - float fSlow10 = (iSlow9 ? 0.0f : std::exp((0.0f - (fConst2 / (iSlow9 ? 1.0f : fSlow8))))); - float fSlow11 = float(fHslider3); - float fSlow12 = (1.0f - fSlow3); + float fSlow3 = (iSlow2 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow2 ? 1.0f : fSlow1))))); + float fSlow4 = ((1.0f / std::max(1.1920929e-07f, float(fHslider1))) + -1.0f); + int iSlow5 = (std::fabs(fSlow0) < 1.1920929e-07f); + float fSlow6 = (iSlow5 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow5 ? 1.0f : fSlow0))))); + float fSlow7 = float(fHslider2); + int iSlow8 = (std::fabs(fSlow7) < 1.1920929e-07f); + float fSlow9 = (iSlow8 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow8 ? 1.0f : fSlow7))))); + float fSlow10 = float(fHslider3); + float fSlow11 = (1.0f - fSlow3); for (int i = 0; (i < count); i = (i + 1)) { float fTemp0 = float(input0[i]); float fTemp1 = std::fabs(fTemp0); - float fTemp2 = ((fRec1[1] > fTemp1) ? fSlow10 : fSlow7); + float fTemp2 = ((fRec1[1] > fTemp1) ? fSlow9 : fSlow6); fRec2[0] = ((fRec2[1] * fTemp2) + (fTemp1 * (1.0f - fTemp2))); fRec1[0] = fRec2[0]; - fRec0[0] = ((fRec0[1] * fSlow3) + (fSlow4 * (std::max(((20.0f * std::log10(fRec1[0])) - fSlow11), 0.0f) * fSlow12))); + fRec0[0] = ((fSlow3 * fRec0[1]) + (fSlow4 * (std::max(((20.0f * std::log10(fRec1[0])) - fSlow10), 0.0f) * fSlow11))); output0[i] = FAUSTFLOAT(std::pow(10.0f, (0.0500000007f * fRec0[0]))); fRec2[1] = fRec2[0]; fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getRatio() const { return fHslider1; } + void setRatio(FAUSTFLOAT value) { fHslider1 = value; } + + FAUSTFLOAT getThreshold() const { return fHslider3; } + void setThreshold(FAUSTFLOAT value) { fHslider3 = value; } + + FAUSTFLOAT getAttack() const { return fHslider0; } + void setAttack(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getRelease() const { return fHslider2; } + void setRelease(FAUSTFLOAT value) { fHslider2 = value; } + + //[End:class] }; +//[After:class] -#ifdef FAUST_UIMACROS - - - - #define FAUST_LIST_ACTIVES(p) \ - p(HORIZONTALSLIDER, Ratio, "Ratio", fHslider1, 1.0f, 1.0f, 20.0f, 0.01f) \ - p(HORIZONTALSLIDER, Threshold, "Threshold", fHslider3, 0.0f, -60.0f, 0.0f, 0.01f) \ - p(HORIZONTALSLIDER, Attack, "Attack", fHslider0, 0.0f, 0.0f, 0.5f, 0.001f) \ - p(HORIZONTALSLIDER, Release, "Release", fHslider2, 0.0f, 0.0f, 5.0f, 0.001f) \ - - #define FAUST_LIST_PASSIVES(p) \ #endif - +#if defined(__GNUC__) +#pragma GCC diagnostic pop #endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/effects/gen/disto_stage.hxx b/src/sfizz/effects/gen/disto_stage.hxx index e630bd68..1c16e2fb 100644 --- a/src/sfizz/effects/gen/disto_stage.hxx +++ b/src/sfizz/effects/gen/disto_stage.hxx @@ -1,7 +1,11 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ name: "disto_stage" -Code generated with Faust 2.27.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -scal -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -scal -ftz 0 ------------------------------------------------------------ */ #ifndef __faustDisto_H__ @@ -9,20 +13,24 @@ Compilation options: -lang cpp -inpl -scal -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include + +//[Before:class] class faustDistoSIG0 { + //[Begin:class] - public: - + + private: + int iRec3[2]; - + public: - + int getNumInputsfaustDistoSIG0() { return 0; } @@ -53,14 +61,13 @@ class faustDistoSIG0 { } return rate; } - + void instanceInitfaustDistoSIG0(int sample_rate) { - (void)sample_rate; for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { iRec3[l3] = 0; } } - + void fillfaustDistoSIG0(int count, float* table) { for (int i = 0; (i < count); i = (i + 1)) { iRec3[0] = (iRec3[1] + 1); @@ -77,19 +84,19 @@ static void deletefaustDistoSIG0(faustDistoSIG0* dsp) { delete dsp; } static float ftbl0faustDistoSIG0[256]; -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustDisto #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif class faustDisto { - - public: - + + private: + float fVec0[2]; int fSampleRate; float fConst0; @@ -97,79 +104,52 @@ class faustDisto { float fConst2; float fConst3; float fConst4; - int iConst5; - float fConst6; + float fConst5; int iRec2[2]; - float fConst7; float fRec1[2]; FAUSTFLOAT fHslider0; float fVec1[2]; float fRec0[2]; - + public: + - void metadata() { - } - - int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] faustDistoSIG0* sig0 = newfaustDistoSIG0(); sig0->instanceInitfaustDistoSIG0(sample_rate); sig0->fillfaustDistoSIG0(256, ftbl0faustDistoSIG0); deletefaustDistoSIG0(sig0); + //[End:classInit] } - + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0f, std::max(1.0f, float(fSampleRate))); + fConst0 = float(fSampleRate); fConst1 = (15.707963f / fConst0); fConst2 = (1.0f / (fConst1 + 1.0f)); fConst3 = (1.0f - fConst1); - fConst4 = (0.00999999978f * float(_oversampling)); - iConst5 = (std::fabs(fConst4) < 1.1920929e-07f); - fConst6 = (iConst5 ? 0.0f : std::exp((0.0f - ((1.0f / fConst0) / (iConst5 ? 1.0f : fConst4))))); - fConst7 = (1.0f - fConst6); + fConst4 = std::exp((0.0f - (100.0f / fConst0))); + fConst5 = (1.0f - fConst4); + //[End:instanceConstants] } - + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] fHslider0 = FAUSTFLOAT(100.0f); + //[End:instanceResetUserInterface] } - + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fVec0[l0] = 0.0f; } @@ -185,38 +165,39 @@ class faustDisto { for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { fRec0[l5] = 0.0f; } + //[End:instanceClear] } - + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - faustDisto* clone() { - return new faustDisto(); - } - + + int getSampleRate() { return fSampleRate; } - - void buildUserInterface() { - } - - void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; float fSlow0 = ((0.200000003f * float(fHslider0)) + 2.0f); for (int i = 0; (i < count); i = (i + 1)) { float fTemp0 = float(input0[i]); fVec0[0] = fTemp0; iRec2[0] = (((fTemp0 < fVec0[1]) & (fTemp0 < -0.25f)) ? 1 : (((fTemp0 > fVec0[1]) & (fTemp0 > 0.25f)) ? 0 : iRec2[1])); - fRec1[0] = ((fRec1[1] * fConst6) + (float(iRec2[0]) * fConst7)); + fRec1[0] = ((fConst4 * fRec1[1]) + (fConst5 * float(iRec2[0]))); float fTemp2 = std::max(0.0f, (12.75f * ((fSlow0 * fTemp0) + 10.0f))); int iTemp3 = int(fTemp2); float fTemp4 = ftbl0faustDistoSIG0[std::min(255, iTemp3)]; @@ -231,19 +212,21 @@ class faustDisto { fVec1[1] = fVec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getDepth() const { return fHslider0; } + void setDepth(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] -#ifdef FAUST_UIMACROS - - - - #define FAUST_LIST_ACTIVES(p) \ - p(HORIZONTALSLIDER, Depth, "Depth", fHslider0, 100.0f, 0.0f, 100.0f, 0.01f) \ - - #define FAUST_LIST_PASSIVES(p) \ #endif - +#if defined(__GNUC__) +#pragma GCC diagnostic pop #endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/effects/gen/fverb.hxx b/src/sfizz/effects/gen/fverb.hxx index 849c2485..cda9c189 100644 --- a/src/sfizz/effects/gen/fverb.hxx +++ b/src/sfizz/effects/gen/fverb.hxx @@ -1,10 +1,14 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "fverb" version: "0.5" -Code generated with Faust 2.27.1 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -scal -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -scal -ftz 0 ------------------------------------------------------------ */ #ifndef __faustFverb_H__ @@ -12,20 +16,24 @@ Compilation options: -lang cpp -inpl -scal -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include + +//[Before:class] class faustFverbSIG0 { + //[Begin:class] + + private: + + int iRec36[2]; + public: - - int iRec19[2]; - - public: - + int getNumInputsfaustFverbSIG0() { return 0; } @@ -56,19 +64,18 @@ class faustFverbSIG0 { } return rate; } - + void instanceInitfaustFverbSIG0(int sample_rate) { - (void)sample_rate; - for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { - iRec19[l4] = 0; + for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) { + iRec36[l23] = 0; } } - + void fillfaustFverbSIG0(int count, float* table) { for (int i = 0; (i < count); i = (i + 1)) { - iRec19[0] = (iRec19[1] + 1); - table[i] = std::sin((9.58738019e-05f * float((iRec19[0] + -1)))); - iRec19[1] = iRec19[0]; + iRec36[0] = (iRec36[1] + 1); + table[i] = std::sin((9.58738019e-05f * float((iRec36[0] + -1)))); + iRec36[1] = iRec36[0]; } } @@ -79,114 +86,114 @@ static void deletefaustFverbSIG0(faustFverbSIG0* dsp) { delete dsp; } static float ftbl0faustFverbSIG0[65536]; -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustFverb #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif class faustFverb { - - public: - + + private: + FAUSTFLOAT fHslider0; float fRec0[2]; FAUSTFLOAT fHslider1; float fRec1[2]; FAUSTFLOAT fHslider2; float fRec10[2]; - int fSampleRate; - float fConst0; FAUSTFLOAT fHslider3; - float fRec18[2]; - float fConst1; - FAUSTFLOAT fHslider4; - float fRec21[2]; - float fRec20[2]; - float fConst2; - float fConst3; - float fRec14[2]; - float fRec15[2]; - int iRec16[2]; - int iRec17[2]; - FAUSTFLOAT fHslider5; - float fRec32[2]; + float fRec24[2]; int IOTA; float fVec0[131072]; - FAUSTFLOAT fHslider6; - float fRec33[2]; - FAUSTFLOAT fHslider7; - float fRec34[2]; - float fRec31[2]; - FAUSTFLOAT fHslider8; - float fRec35[2]; - float fRec30[2]; - FAUSTFLOAT fHslider9; - float fRec36[2]; - float fVec1[1024]; - int iConst4; - float fRec28[2]; - float fVec2[1024]; - int iConst5; + int fSampleRate; + float fConst0; + FAUSTFLOAT fHslider4; + float fRec25[2]; + float fConst1; + FAUSTFLOAT fHslider5; float fRec26[2]; - FAUSTFLOAT fHslider10; - float fRec37[2]; - float fVec3[4096]; - int iConst6; - float fRec24[2]; - float fVec4[2048]; - int iConst7; + float fRec23[2]; + FAUSTFLOAT fHslider6; + float fRec27[2]; float fRec22[2]; - int iConst8; + FAUSTFLOAT fHslider7; + float fRec28[2]; + float fVec1[131072]; + int iConst2; + float fRec20[2]; + float fVec2[131072]; + int iConst3; + float fRec18[2]; + FAUSTFLOAT fHslider8; + float fRec29[2]; + float fVec3[131072]; + int iConst4; + float fRec16[2]; + float fVec4[131072]; + int iConst5; + float fRec14[2]; + int iConst6; + FAUSTFLOAT fHslider9; + float fRec30[2]; + float fVec5[131072]; + FAUSTFLOAT fHslider10; + float fRec35[2]; FAUSTFLOAT fHslider11; float fRec38[2]; - float fVec5[131072]; + float fRec37[2]; + float fConst7; + float fConst8; + float fRec31[2]; + float fRec32[2]; + int iRec33[2]; + int iRec34[2]; float fRec12[2]; - float fVec6[32768]; + float fVec6[131072]; int iConst9; FAUSTFLOAT fHslider12; float fRec39[2]; float fRec11[2]; - float fVec7[32768]; + float fVec7[131072]; int iConst10; float fRec8[2]; - float fRec2[32768]; - float fRec3[16384]; - float fRec4[32768]; - float fRec45[2]; - float fRec46[2]; - int iRec47[2]; - int iRec48[2]; + float fRec2[131072]; + float fRec3[131072]; + float fRec4[131072]; float fVec8[131072]; - float fRec58[2]; - float fRec57[2]; - float fVec9[1024]; - int iConst11; - float fRec55[2]; - float fVec10[1024]; - int iConst12; + float fRec54[2]; float fRec53[2]; - float fVec11[4096]; - int iConst13; + float fVec9[131072]; + int iConst11; float fRec51[2]; - float fVec12[2048]; - int iConst14; + float fVec10[131072]; + int iConst12; float fRec49[2]; + float fVec11[131072]; + int iConst13; + float fRec47[2]; + float fVec12[131072]; + int iConst14; + float fRec45[2]; int iConst15; float fVec13[131072]; + float fRec55[2]; + float fRec56[2]; + int iRec57[2]; + int iRec58[2]; float fRec43[2]; - float fVec14[32768]; + float fVec14[131072]; int iConst16; float fRec42[2]; - float fVec15[16384]; + float fVec15[131072]; int iConst17; float fRec40[2]; - float fRec5[32768]; - float fRec6[8192]; - float fRec7[32768]; + float fRec5[131072]; + float fRec6[131072]; + float fRec7[131072]; int iConst18; int iConst19; int iConst20; @@ -201,73 +208,38 @@ class faustFverb { int iConst29; int iConst30; int iConst31; - + public: + - void metadata() { - } - - int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] faustFverbSIG0* sig0 = newfaustFverbSIG0(); sig0->instanceInitfaustFverbSIG0(sample_rate); sig0->fillfaustFverbSIG0(65536, ftbl0faustFverbSIG0); deletefaustFverbSIG0(sig0); + //[End:classInit] } - + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0f, std::max(1.0f, float(fSampleRate))); + fConst0 = float(fSampleRate); fConst1 = (1.0f / fConst0); - fConst2 = (1.0f / float(int((0.00999999978f * fConst0)))); - fConst3 = (0.0f - fConst2); - iConst4 = std::min(65536, std::max(0, (int((0.00462820474f * fConst0)) + -1))); - iConst5 = std::min(65536, std::max(0, (int((0.00370316859f * fConst0)) + -1))); - iConst6 = std::min(65536, std::max(0, (int((0.013116831f * fConst0)) + -1))); - iConst7 = std::min(65536, std::max(0, (int((0.00902825873f * fConst0)) + -1))); - iConst8 = (std::min(65536, std::max(0, int((0.106280029f * fConst0)))) + 1); + iConst2 = std::min(65536, std::max(0, (int((0.00462820474f * fConst0)) + -1))); + iConst3 = std::min(65536, std::max(0, (int((0.00370316859f * fConst0)) + -1))); + iConst4 = std::min(65536, std::max(0, (int((0.013116831f * fConst0)) + -1))); + iConst5 = std::min(65536, std::max(0, (int((0.00902825873f * fConst0)) + -1))); + iConst6 = (std::min(65536, std::max(0, int((0.106280029f * fConst0)))) + 1); + fConst7 = (1.0f / float(int((0.00999999978f * fConst0)))); + fConst8 = (0.0f - fConst7); iConst9 = std::min(65536, std::max(0, int((0.141695514f * fConst0)))); iConst10 = std::min(65536, std::max(0, (int((0.0892443135f * fConst0)) + -1))); iConst11 = std::min(65536, std::max(0, (int((0.00491448538f * fConst0)) + -1))); @@ -291,25 +263,29 @@ class faustFverb { iConst29 = std::min(65536, std::max(0, int((0.070931755f * fConst0)))); iConst30 = std::min(65536, std::max(0, int((0.0112563418f * fConst0)))); iConst31 = std::min(65536, std::max(0, int((0.00406572362f * fConst0)))); + //[End:instanceConstants] } - + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] fHslider0 = FAUSTFLOAT(100.0f); fHslider1 = FAUSTFLOAT(50.0f); fHslider2 = FAUSTFLOAT(50.0f); - fHslider3 = FAUSTFLOAT(0.5f); - fHslider4 = FAUSTFLOAT(1.0f); - fHslider5 = FAUSTFLOAT(100.0f); - fHslider6 = FAUSTFLOAT(0.0f); - fHslider7 = FAUSTFLOAT(10000.0f); - fHslider8 = FAUSTFLOAT(100.0f); - fHslider9 = FAUSTFLOAT(75.0f); - fHslider10 = FAUSTFLOAT(62.5f); - fHslider11 = FAUSTFLOAT(70.0f); + fHslider3 = FAUSTFLOAT(100.0f); + fHslider4 = FAUSTFLOAT(0.0f); + fHslider5 = FAUSTFLOAT(10000.0f); + fHslider6 = FAUSTFLOAT(100.0f); + fHslider7 = FAUSTFLOAT(75.0f); + fHslider8 = FAUSTFLOAT(62.5f); + fHslider9 = FAUSTFLOAT(70.0f); + fHslider10 = FAUSTFLOAT(0.5f); + fHslider11 = FAUSTFLOAT(1.0f); fHslider12 = FAUSTFLOAT(5500.0f); + //[End:instanceResetUserInterface] } - + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec0[l0] = 0.0f; } @@ -320,88 +296,88 @@ class faustFverb { fRec10[l2] = 0.0f; } for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { - fRec18[l3] = 0.0f; - } - for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { - fRec21[l5] = 0.0f; - } - for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { - fRec20[l6] = 0.0f; - } - for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) { - fRec14[l7] = 0.0f; - } - for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { - fRec15[l8] = 0.0f; - } - for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { - iRec16[l9] = 0; - } - for (int l10 = 0; (l10 < 2); l10 = (l10 + 1)) { - iRec17[l10] = 0; - } - for (int l11 = 0; (l11 < 2); l11 = (l11 + 1)) { - fRec32[l11] = 0.0f; + fRec24[l3] = 0.0f; } IOTA = 0; - for (int l12 = 0; (l12 < 131072); l12 = (l12 + 1)) { - fVec0[l12] = 0.0f; + for (int l4 = 0; (l4 < 131072); l4 = (l4 + 1)) { + fVec0[l4] = 0.0f; } - for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { - fRec33[l13] = 0.0f; + for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { + fRec25[l5] = 0.0f; + } + for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { + fRec26[l6] = 0.0f; + } + for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) { + fRec23[l7] = 0.0f; + } + for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { + fRec27[l8] = 0.0f; + } + for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { + fRec22[l9] = 0.0f; + } + for (int l10 = 0; (l10 < 2); l10 = (l10 + 1)) { + fRec28[l10] = 0.0f; + } + for (int l11 = 0; (l11 < 131072); l11 = (l11 + 1)) { + fVec1[l11] = 0.0f; + } + for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) { + fRec20[l12] = 0.0f; + } + for (int l13 = 0; (l13 < 131072); l13 = (l13 + 1)) { + fVec2[l13] = 0.0f; } for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { - fRec34[l14] = 0.0f; + fRec18[l14] = 0.0f; } for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) { - fRec31[l15] = 0.0f; + fRec29[l15] = 0.0f; } - for (int l16 = 0; (l16 < 2); l16 = (l16 + 1)) { - fRec35[l16] = 0.0f; + for (int l16 = 0; (l16 < 131072); l16 = (l16 + 1)) { + fVec3[l16] = 0.0f; } for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) { - fRec30[l17] = 0.0f; + fRec16[l17] = 0.0f; } - for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) { - fRec36[l18] = 0.0f; + for (int l18 = 0; (l18 < 131072); l18 = (l18 + 1)) { + fVec4[l18] = 0.0f; } - for (int l19 = 0; (l19 < 1024); l19 = (l19 + 1)) { - fVec1[l19] = 0.0f; + for (int l19 = 0; (l19 < 2); l19 = (l19 + 1)) { + fRec14[l19] = 0.0f; } for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) { - fRec28[l20] = 0.0f; + fRec30[l20] = 0.0f; } - for (int l21 = 0; (l21 < 1024); l21 = (l21 + 1)) { - fVec2[l21] = 0.0f; + for (int l21 = 0; (l21 < 131072); l21 = (l21 + 1)) { + fVec5[l21] = 0.0f; } for (int l22 = 0; (l22 < 2); l22 = (l22 + 1)) { - fRec26[l22] = 0.0f; + fRec35[l22] = 0.0f; } - for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) { - fRec37[l23] = 0.0f; - } - for (int l24 = 0; (l24 < 4096); l24 = (l24 + 1)) { - fVec3[l24] = 0.0f; + for (int l24 = 0; (l24 < 2); l24 = (l24 + 1)) { + fRec38[l24] = 0.0f; } for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) { - fRec24[l25] = 0.0f; + fRec37[l25] = 0.0f; } - for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) { - fVec4[l26] = 0.0f; + for (int l26 = 0; (l26 < 2); l26 = (l26 + 1)) { + fRec31[l26] = 0.0f; } for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) { - fRec22[l27] = 0.0f; + fRec32[l27] = 0.0f; } for (int l28 = 0; (l28 < 2); l28 = (l28 + 1)) { - fRec38[l28] = 0.0f; + iRec33[l28] = 0; } - for (int l29 = 0; (l29 < 131072); l29 = (l29 + 1)) { - fVec5[l29] = 0.0f; + for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) { + iRec34[l29] = 0; } for (int l30 = 0; (l30 < 2); l30 = (l30 + 1)) { fRec12[l30] = 0.0f; } - for (int l31 = 0; (l31 < 32768); l31 = (l31 + 1)) { + for (int l31 = 0; (l31 < 131072); l31 = (l31 + 1)) { fVec6[l31] = 0.0f; } for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) { @@ -410,133 +386,134 @@ class faustFverb { for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) { fRec11[l33] = 0.0f; } - for (int l34 = 0; (l34 < 32768); l34 = (l34 + 1)) { + for (int l34 = 0; (l34 < 131072); l34 = (l34 + 1)) { fVec7[l34] = 0.0f; } for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) { fRec8[l35] = 0.0f; } - for (int l36 = 0; (l36 < 32768); l36 = (l36 + 1)) { + for (int l36 = 0; (l36 < 131072); l36 = (l36 + 1)) { fRec2[l36] = 0.0f; } - for (int l37 = 0; (l37 < 16384); l37 = (l37 + 1)) { + for (int l37 = 0; (l37 < 131072); l37 = (l37 + 1)) { fRec3[l37] = 0.0f; } - for (int l38 = 0; (l38 < 32768); l38 = (l38 + 1)) { + for (int l38 = 0; (l38 < 131072); l38 = (l38 + 1)) { fRec4[l38] = 0.0f; } - for (int l39 = 0; (l39 < 2); l39 = (l39 + 1)) { - fRec45[l39] = 0.0f; + for (int l39 = 0; (l39 < 131072); l39 = (l39 + 1)) { + fVec8[l39] = 0.0f; } for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) { - fRec46[l40] = 0.0f; + fRec54[l40] = 0.0f; } for (int l41 = 0; (l41 < 2); l41 = (l41 + 1)) { - iRec47[l41] = 0; + fRec53[l41] = 0.0f; } - for (int l42 = 0; (l42 < 2); l42 = (l42 + 1)) { - iRec48[l42] = 0; + for (int l42 = 0; (l42 < 131072); l42 = (l42 + 1)) { + fVec9[l42] = 0.0f; } - for (int l43 = 0; (l43 < 131072); l43 = (l43 + 1)) { - fVec8[l43] = 0.0f; + for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) { + fRec51[l43] = 0.0f; } - for (int l44 = 0; (l44 < 2); l44 = (l44 + 1)) { - fRec58[l44] = 0.0f; + for (int l44 = 0; (l44 < 131072); l44 = (l44 + 1)) { + fVec10[l44] = 0.0f; } for (int l45 = 0; (l45 < 2); l45 = (l45 + 1)) { - fRec57[l45] = 0.0f; + fRec49[l45] = 0.0f; } - for (int l46 = 0; (l46 < 1024); l46 = (l46 + 1)) { - fVec9[l46] = 0.0f; + for (int l46 = 0; (l46 < 131072); l46 = (l46 + 1)) { + fVec11[l46] = 0.0f; } for (int l47 = 0; (l47 < 2); l47 = (l47 + 1)) { - fRec55[l47] = 0.0f; + fRec47[l47] = 0.0f; } - for (int l48 = 0; (l48 < 1024); l48 = (l48 + 1)) { - fVec10[l48] = 0.0f; + for (int l48 = 0; (l48 < 131072); l48 = (l48 + 1)) { + fVec12[l48] = 0.0f; } for (int l49 = 0; (l49 < 2); l49 = (l49 + 1)) { - fRec53[l49] = 0.0f; + fRec45[l49] = 0.0f; } - for (int l50 = 0; (l50 < 4096); l50 = (l50 + 1)) { - fVec11[l50] = 0.0f; + for (int l50 = 0; (l50 < 131072); l50 = (l50 + 1)) { + fVec13[l50] = 0.0f; } for (int l51 = 0; (l51 < 2); l51 = (l51 + 1)) { - fRec51[l51] = 0.0f; + fRec55[l51] = 0.0f; } - for (int l52 = 0; (l52 < 2048); l52 = (l52 + 1)) { - fVec12[l52] = 0.0f; + for (int l52 = 0; (l52 < 2); l52 = (l52 + 1)) { + fRec56[l52] = 0.0f; } for (int l53 = 0; (l53 < 2); l53 = (l53 + 1)) { - fRec49[l53] = 0.0f; + iRec57[l53] = 0; } - for (int l54 = 0; (l54 < 131072); l54 = (l54 + 1)) { - fVec13[l54] = 0.0f; + for (int l54 = 0; (l54 < 2); l54 = (l54 + 1)) { + iRec58[l54] = 0; } for (int l55 = 0; (l55 < 2); l55 = (l55 + 1)) { fRec43[l55] = 0.0f; } - for (int l56 = 0; (l56 < 32768); l56 = (l56 + 1)) { + for (int l56 = 0; (l56 < 131072); l56 = (l56 + 1)) { fVec14[l56] = 0.0f; } for (int l57 = 0; (l57 < 2); l57 = (l57 + 1)) { fRec42[l57] = 0.0f; } - for (int l58 = 0; (l58 < 16384); l58 = (l58 + 1)) { + for (int l58 = 0; (l58 < 131072); l58 = (l58 + 1)) { fVec15[l58] = 0.0f; } for (int l59 = 0; (l59 < 2); l59 = (l59 + 1)) { fRec40[l59] = 0.0f; } - for (int l60 = 0; (l60 < 32768); l60 = (l60 + 1)) { + for (int l60 = 0; (l60 < 131072); l60 = (l60 + 1)) { fRec5[l60] = 0.0f; } - for (int l61 = 0; (l61 < 8192); l61 = (l61 + 1)) { + for (int l61 = 0; (l61 < 131072); l61 = (l61 + 1)) { fRec6[l61] = 0.0f; } - for (int l62 = 0; (l62 < 32768); l62 = (l62 + 1)) { + for (int l62 = 0; (l62 < 131072); l62 = (l62 + 1)) { fRec7[l62] = 0.0f; } + //[End:instanceClear] } - + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - faustFverb* clone() { - return new faustFverb(); - } - + + int getSampleRate() { return fSampleRate; } - - void buildUserInterface() { - } - - void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; float fSlow0 = (9.99999975e-06f * float(fHslider0)); float fSlow1 = (9.99999975e-06f * float(fHslider1)); float fSlow2 = (9.99999975e-06f * float(fHslider2)); - float fSlow3 = (9.99999997e-07f * float(fHslider3)); - float fSlow4 = (0.00100000005f * float(fHslider4)); - float fSlow5 = (9.99999975e-06f * float(fHslider5)); - float fSlow6 = (9.99999997e-07f * float(fHslider6)); - float fSlow7 = (0.00100000005f * std::exp((fConst1 * (0.0f - (6.28318548f * float(fHslider7)))))); - float fSlow8 = (0.00100000005f * std::exp((fConst1 * (0.0f - (6.28318548f * float(fHslider8)))))); + float fSlow3 = (9.99999975e-06f * float(fHslider3)); + float fSlow4 = (9.99999997e-07f * float(fHslider4)); + float fSlow5 = (0.00100000005f * std::exp((fConst1 * (0.0f - (6.28318548f * float(fHslider5)))))); + float fSlow6 = (0.00100000005f * std::exp((fConst1 * (0.0f - (6.28318548f * float(fHslider6)))))); + float fSlow7 = (9.99999975e-06f * float(fHslider7)); + float fSlow8 = (9.99999975e-06f * float(fHslider8)); float fSlow9 = (9.99999975e-06f * float(fHslider9)); - float fSlow10 = (9.99999975e-06f * float(fHslider10)); - float fSlow11 = (9.99999975e-06f * float(fHslider11)); + float fSlow10 = (9.99999997e-07f * float(fHslider10)); + float fSlow11 = (0.00100000005f * float(fHslider11)); float fSlow12 = (0.00100000005f * std::exp((fConst1 * (0.0f - (6.28318548f * float(fHslider12)))))); for (int i = 0; (i < count); i = (i + 1)) { float fTemp0 = float(input0[i]); @@ -545,170 +522,198 @@ class faustFverb { fRec1[0] = (fSlow1 + (0.999000013f * fRec1[1])); fRec10[0] = (fSlow2 + (0.999000013f * fRec10[1])); float fTemp2 = std::min(0.5f, std::max(0.25f, (fRec10[0] + 0.150000006f))); - fRec18[0] = (fSlow3 + (0.999000013f * fRec18[1])); - fRec21[0] = (fSlow4 + (0.999000013f * fRec21[1])); - float fTemp3 = (fRec20[1] + (fConst1 * fRec21[0])); - fRec20[0] = (fTemp3 - float(int(fTemp3))); - int iTemp4 = (int((fConst0 * ((fRec18[0] * ftbl0faustFverbSIG0[int((65536.0f * (fRec20[0] + (0.25f - float(int((fRec20[0] + 0.25f)))))))]) + 0.0305097271f))) + -1); - float fTemp5 = ((fRec14[1] != 0.0f) ? (((fRec15[1] > 0.0f) & (fRec15[1] < 1.0f)) ? fRec14[1] : 0.0f) : (((fRec15[1] == 0.0f) & (iTemp4 != iRec16[1])) ? fConst2 : (((fRec15[1] == 1.0f) & (iTemp4 != iRec17[1])) ? fConst3 : 0.0f))); - fRec14[0] = fTemp5; - fRec15[0] = std::max(0.0f, std::min(1.0f, (fRec15[1] + fTemp5))); - iRec16[0] = (((fRec15[1] >= 1.0f) & (iRec17[1] != iTemp4)) ? iTemp4 : iRec16[1]); - iRec17[0] = (((fRec15[1] <= 0.0f) & (iRec16[1] != iTemp4)) ? iTemp4 : iRec17[1]); - fRec32[0] = (fSlow5 + (0.999000013f * fRec32[1])); - fVec0[(IOTA & 131071)] = (fTemp1 * fRec32[0]); - fRec33[0] = (fSlow6 + (0.999000013f * fRec33[1])); - int iTemp6 = std::min(65536, std::max(0, int((fConst0 * fRec33[0])))); - fRec34[0] = (fSlow7 + (0.999000013f * fRec34[1])); - fRec31[0] = (fVec0[((IOTA - iTemp6) & 131071)] + (fRec34[0] * fRec31[1])); - float fTemp7 = (1.0f - fRec34[0]); - fRec35[0] = (fSlow8 + (0.999000013f * fRec35[1])); - fRec30[0] = ((fRec31[0] * fTemp7) + (fRec35[0] * fRec30[1])); - float fTemp8 = (fRec35[0] + 1.0f); - float fTemp9 = (0.0f - (0.5f * fTemp8)); - fRec36[0] = (fSlow9 + (0.999000013f * fRec36[1])); - float fTemp10 = (((0.5f * (fRec30[0] * fTemp8)) + (fRec30[1] * fTemp9)) - (fRec36[0] * fRec28[1])); - fVec1[(IOTA & 1023)] = fTemp10; - fRec28[0] = fVec1[((IOTA - iConst4) & 1023)]; - float fRec29 = (fRec36[0] * fTemp10); - float fTemp11 = ((fRec29 + fRec28[1]) - (fRec36[0] * fRec26[1])); - fVec2[(IOTA & 1023)] = fTemp11; - fRec26[0] = fVec2[((IOTA - iConst5) & 1023)]; - float fRec27 = (fRec36[0] * fTemp11); - fRec37[0] = (fSlow10 + (0.999000013f * fRec37[1])); - float fTemp12 = ((fRec27 + fRec26[1]) - (fRec37[0] * fRec24[1])); - fVec3[(IOTA & 4095)] = fTemp12; - fRec24[0] = fVec3[((IOTA - iConst6) & 4095)]; - float fRec25 = (fRec37[0] * fTemp12); - float fTemp13 = ((fRec25 + fRec24[1]) - (fRec37[0] * fRec22[1])); - fVec4[(IOTA & 2047)] = fTemp13; - fRec22[0] = fVec4[((IOTA - iConst7) & 2047)]; - float fRec23 = (fRec37[0] * fTemp13); + fRec24[0] = (fSlow3 + (0.999000013f * fRec24[1])); + fVec0[(IOTA & 131071)] = (fTemp1 * fRec24[0]); + fRec25[0] = (fSlow4 + (0.999000013f * fRec25[1])); + int iTemp3 = std::min(65536, std::max(0, int((fConst0 * fRec25[0])))); + fRec26[0] = (fSlow5 + (0.999000013f * fRec26[1])); + fRec23[0] = (fVec0[((IOTA - iTemp3) & 131071)] + (fRec26[0] * fRec23[1])); + float fTemp4 = (1.0f - fRec26[0]); + fRec27[0] = (fSlow6 + (0.999000013f * fRec27[1])); + fRec22[0] = ((fRec23[0] * fTemp4) + (fRec27[0] * fRec22[1])); + float fTemp5 = (fRec27[0] + 1.0f); + float fTemp6 = (0.0f - (0.5f * fTemp5)); + fRec28[0] = (fSlow7 + (0.999000013f * fRec28[1])); + float fTemp7 = (((0.5f * (fRec22[0] * fTemp5)) + (fRec22[1] * fTemp6)) - (fRec28[0] * fRec20[1])); + fVec1[(IOTA & 131071)] = fTemp7; + fRec20[0] = fVec1[((IOTA - iConst2) & 131071)]; + float fRec21 = (fRec28[0] * fTemp7); + float fTemp8 = ((fRec21 + fRec20[1]) - (fRec28[0] * fRec18[1])); + fVec2[(IOTA & 131071)] = fTemp8; + fRec18[0] = fVec2[((IOTA - iConst3) & 131071)]; + float fRec19 = (fRec28[0] * fTemp8); + fRec29[0] = (fSlow8 + (0.999000013f * fRec29[1])); + float fTemp9 = ((fRec19 + fRec18[1]) - (fRec29[0] * fRec16[1])); + fVec3[(IOTA & 131071)] = fTemp9; + fRec16[0] = fVec3[((IOTA - iConst4) & 131071)]; + float fRec17 = (fRec29[0] * fTemp9); + float fTemp10 = ((fRec17 + fRec16[1]) - (fRec29[0] * fRec14[1])); + fVec4[(IOTA & 131071)] = fTemp10; + fRec14[0] = fVec4[((IOTA - iConst5) & 131071)]; + float fRec15 = (fRec29[0] * fTemp10); + fRec30[0] = (fSlow9 + (0.999000013f * fRec30[1])); + float fTemp11 = (fRec14[1] + ((fRec10[0] * fRec5[((IOTA - iConst6) & 131071)]) + (fRec15 + (fRec30[0] * fRec12[1])))); + fVec5[(IOTA & 131071)] = fTemp11; + fRec35[0] = (fSlow10 + (0.999000013f * fRec35[1])); fRec38[0] = (fSlow11 + (0.999000013f * fRec38[1])); - float fTemp14 = (fRec22[1] + ((fRec10[0] * fRec5[((IOTA - iConst8) & 32767)]) + (fRec23 + (fRec38[0] * fRec12[1])))); - fVec5[(IOTA & 131071)] = fTemp14; - fRec12[0] = (((1.0f - fRec15[0]) * fVec5[((IOTA - std::min(65536, std::max(0, iRec16[0]))) & 131071)]) + (fRec15[0] * fVec5[((IOTA - std::min(65536, std::max(0, iRec17[0]))) & 131071)])); - float fRec13 = (0.0f - (fRec38[0] * fTemp14)); - float fTemp15 = (fRec13 + fRec12[1]); - fVec6[(IOTA & 32767)] = fTemp15; + float fTemp12 = (fRec37[1] + (fConst1 * fRec38[0])); + fRec37[0] = (fTemp12 - float(int(fTemp12))); + int iTemp13 = (int((fConst0 * ((fRec35[0] * ftbl0faustFverbSIG0[int((65536.0f * (fRec37[0] + (0.25f - float(int((fRec37[0] + 0.25f)))))))]) + 0.0305097271f))) + -1); + float fTemp14 = ((fRec31[1] != 0.0f) ? (((fRec32[1] > 0.0f) & (fRec32[1] < 1.0f)) ? fRec31[1] : 0.0f) : (((fRec32[1] == 0.0f) & (iTemp13 != iRec33[1])) ? fConst7 : (((fRec32[1] == 1.0f) & (iTemp13 != iRec34[1])) ? fConst8 : 0.0f))); + fRec31[0] = fTemp14; + fRec32[0] = std::max(0.0f, std::min(1.0f, (fRec32[1] + fTemp14))); + iRec33[0] = (((fRec32[1] >= 1.0f) & (iRec34[1] != iTemp13)) ? iTemp13 : iRec33[1]); + iRec34[0] = (((fRec32[1] <= 0.0f) & (iRec33[1] != iTemp13)) ? iTemp13 : iRec34[1]); + float fTemp15 = fVec5[((IOTA - std::min(65536, std::max(0, iRec33[0]))) & 131071)]; + fRec12[0] = (fTemp15 + (fRec32[0] * (fVec5[((IOTA - std::min(65536, std::max(0, iRec34[0]))) & 131071)] - fTemp15))); + float fRec13 = (0.0f - (fRec30[0] * fTemp11)); + float fTemp16 = (fRec13 + fRec12[1]); + fVec6[(IOTA & 131071)] = fTemp16; fRec39[0] = (fSlow12 + (0.999000013f * fRec39[1])); - fRec11[0] = (fVec6[((IOTA - iConst9) & 32767)] + (fRec39[0] * fRec11[1])); - float fTemp16 = (1.0f - fRec39[0]); - float fTemp17 = ((fTemp2 * fRec8[1]) + ((fRec10[0] * fRec11[0]) * fTemp16)); - fVec7[(IOTA & 32767)] = fTemp17; - fRec8[0] = fVec7[((IOTA - iConst10) & 32767)]; - float fRec9 = (0.0f - (fTemp2 * fTemp17)); - fRec2[(IOTA & 32767)] = (fRec9 + fRec8[1]); - fRec3[(IOTA & 16383)] = (fRec11[0] * fTemp16); - fRec4[(IOTA & 32767)] = fTemp15; - int iTemp18 = (int((fConst0 * ((fRec18[0] * ftbl0faustFverbSIG0[int((65536.0f * fRec20[0]))]) + 0.025603978f))) + -1); - float fTemp19 = ((fRec45[1] != 0.0f) ? (((fRec46[1] > 0.0f) & (fRec46[1] < 1.0f)) ? fRec45[1] : 0.0f) : (((fRec46[1] == 0.0f) & (iTemp18 != iRec47[1])) ? fConst2 : (((fRec46[1] == 1.0f) & (iTemp18 != iRec48[1])) ? fConst3 : 0.0f))); - fRec45[0] = fTemp19; - fRec46[0] = std::max(0.0f, std::min(1.0f, (fRec46[1] + fTemp19))); - iRec47[0] = (((fRec46[1] >= 1.0f) & (iRec48[1] != iTemp18)) ? iTemp18 : iRec47[1]); - iRec48[0] = (((fRec46[1] <= 0.0f) & (iRec47[1] != iTemp18)) ? iTemp18 : iRec48[1]); - fVec8[(IOTA & 131071)] = (fTemp0 * fRec32[0]); - fRec58[0] = (fVec8[((IOTA - iTemp6) & 131071)] + (fRec34[0] * fRec58[1])); - fRec57[0] = ((fTemp7 * fRec58[0]) + (fRec35[0] * fRec57[1])); - float fTemp20 = (((0.5f * (fRec57[0] * fTemp8)) + (fTemp9 * fRec57[1])) - (fRec36[0] * fRec55[1])); - fVec9[(IOTA & 1023)] = fTemp20; - fRec55[0] = fVec9[((IOTA - iConst11) & 1023)]; - float fRec56 = (fRec36[0] * fTemp20); - float fTemp21 = ((fRec56 + fRec55[1]) - (fRec36[0] * fRec53[1])); - fVec10[(IOTA & 1023)] = fTemp21; - fRec53[0] = fVec10[((IOTA - iConst12) & 1023)]; - float fRec54 = (fRec36[0] * fTemp21); - float fTemp22 = ((fRec54 + fRec53[1]) - (fRec37[0] * fRec51[1])); - fVec11[(IOTA & 4095)] = fTemp22; - fRec51[0] = fVec11[((IOTA - iConst13) & 4095)]; - float fRec52 = (fRec37[0] * fTemp22); - float fTemp23 = ((fRec52 + fRec51[1]) - (fRec37[0] * fRec49[1])); - fVec12[(IOTA & 2047)] = fTemp23; - fRec49[0] = fVec12[((IOTA - iConst14) & 2047)]; - float fRec50 = (fRec37[0] * fTemp23); - float fTemp24 = (fRec49[1] + ((fRec10[0] * fRec2[((IOTA - iConst15) & 32767)]) + (fRec50 + (fRec38[0] * fRec43[1])))); - fVec13[(IOTA & 131071)] = fTemp24; - fRec43[0] = (((1.0f - fRec46[0]) * fVec13[((IOTA - std::min(65536, std::max(0, iRec47[0]))) & 131071)]) + (fRec46[0] * fVec13[((IOTA - std::min(65536, std::max(0, iRec48[0]))) & 131071)])); - float fRec44 = (0.0f - (fRec38[0] * fTemp24)); - float fTemp25 = (fRec44 + fRec43[1]); - fVec14[(IOTA & 32767)] = fTemp25; - fRec42[0] = (fVec14[((IOTA - iConst16) & 32767)] + (fRec39[0] * fRec42[1])); - float fTemp26 = ((fTemp2 * fRec40[1]) + ((fRec10[0] * fTemp16) * fRec42[0])); - fVec15[(IOTA & 16383)] = fTemp26; - fRec40[0] = fVec15[((IOTA - iConst17) & 16383)]; - float fRec41 = (0.0f - (fTemp2 * fTemp26)); - fRec5[(IOTA & 32767)] = (fRec41 + fRec40[1]); - fRec6[(IOTA & 8191)] = (fTemp16 * fRec42[0]); - fRec7[(IOTA & 32767)] = fTemp25; - output0[i] = FAUSTFLOAT(((fTemp0 * fRec0[0]) + (0.600000024f * (fRec1[0] * (((fRec4[((IOTA - iConst18) & 32767)] + fRec4[((IOTA - iConst19) & 32767)]) + fRec2[((IOTA - iConst20) & 32767)]) - (((fRec3[((IOTA - iConst21) & 16383)] + fRec7[((IOTA - iConst22) & 32767)]) + fRec6[((IOTA - iConst23) & 8191)]) + fRec5[((IOTA - iConst24) & 32767)])))))); - output1[i] = FAUSTFLOAT(((fTemp1 * fRec0[0]) + (0.600000024f * (fRec1[0] * (((fRec7[((IOTA - iConst25) & 32767)] + fRec7[((IOTA - iConst26) & 32767)]) + fRec5[((IOTA - iConst27) & 32767)]) - (((fRec6[((IOTA - iConst28) & 8191)] + fRec4[((IOTA - iConst29) & 32767)]) + fRec3[((IOTA - iConst30) & 16383)]) + fRec2[((IOTA - iConst31) & 32767)])))))); + fRec11[0] = (fVec6[((IOTA - iConst9) & 131071)] + (fRec39[0] * fRec11[1])); + float fTemp17 = (1.0f - fRec39[0]); + float fTemp18 = ((fTemp2 * fRec8[1]) + ((fRec10[0] * fRec11[0]) * fTemp17)); + fVec7[(IOTA & 131071)] = fTemp18; + fRec8[0] = fVec7[((IOTA - iConst10) & 131071)]; + float fRec9 = (0.0f - (fTemp2 * fTemp18)); + fRec2[(IOTA & 131071)] = (fRec9 + fRec8[1]); + fRec3[(IOTA & 131071)] = (fRec11[0] * fTemp17); + fRec4[(IOTA & 131071)] = fTemp16; + fVec8[(IOTA & 131071)] = (fTemp0 * fRec24[0]); + fRec54[0] = (fVec8[((IOTA - iTemp3) & 131071)] + (fRec26[0] * fRec54[1])); + fRec53[0] = ((fTemp4 * fRec54[0]) + (fRec27[0] * fRec53[1])); + float fTemp19 = (((0.5f * (fRec53[0] * fTemp5)) + (fTemp6 * fRec53[1])) - (fRec28[0] * fRec51[1])); + fVec9[(IOTA & 131071)] = fTemp19; + fRec51[0] = fVec9[((IOTA - iConst11) & 131071)]; + float fRec52 = (fRec28[0] * fTemp19); + float fTemp20 = ((fRec52 + fRec51[1]) - (fRec28[0] * fRec49[1])); + fVec10[(IOTA & 131071)] = fTemp20; + fRec49[0] = fVec10[((IOTA - iConst12) & 131071)]; + float fRec50 = (fRec28[0] * fTemp20); + float fTemp21 = ((fRec50 + fRec49[1]) - (fRec29[0] * fRec47[1])); + fVec11[(IOTA & 131071)] = fTemp21; + fRec47[0] = fVec11[((IOTA - iConst13) & 131071)]; + float fRec48 = (fRec29[0] * fTemp21); + float fTemp22 = ((fRec48 + fRec47[1]) - (fRec29[0] * fRec45[1])); + fVec12[(IOTA & 131071)] = fTemp22; + fRec45[0] = fVec12[((IOTA - iConst14) & 131071)]; + float fRec46 = (fRec29[0] * fTemp22); + float fTemp23 = (fRec45[1] + ((fRec10[0] * fRec2[((IOTA - iConst15) & 131071)]) + (fRec46 + (fRec30[0] * fRec43[1])))); + fVec13[(IOTA & 131071)] = fTemp23; + int iTemp24 = (int((fConst0 * ((fRec35[0] * ftbl0faustFverbSIG0[int((65536.0f * fRec37[0]))]) + 0.025603978f))) + -1); + float fTemp25 = ((fRec55[1] != 0.0f) ? (((fRec56[1] > 0.0f) & (fRec56[1] < 1.0f)) ? fRec55[1] : 0.0f) : (((fRec56[1] == 0.0f) & (iTemp24 != iRec57[1])) ? fConst7 : (((fRec56[1] == 1.0f) & (iTemp24 != iRec58[1])) ? fConst8 : 0.0f))); + fRec55[0] = fTemp25; + fRec56[0] = std::max(0.0f, std::min(1.0f, (fRec56[1] + fTemp25))); + iRec57[0] = (((fRec56[1] >= 1.0f) & (iRec58[1] != iTemp24)) ? iTemp24 : iRec57[1]); + iRec58[0] = (((fRec56[1] <= 0.0f) & (iRec57[1] != iTemp24)) ? iTemp24 : iRec58[1]); + float fTemp26 = fVec13[((IOTA - std::min(65536, std::max(0, iRec57[0]))) & 131071)]; + fRec43[0] = (fTemp26 + (fRec56[0] * (fVec13[((IOTA - std::min(65536, std::max(0, iRec58[0]))) & 131071)] - fTemp26))); + float fRec44 = (0.0f - (fRec30[0] * fTemp23)); + float fTemp27 = (fRec44 + fRec43[1]); + fVec14[(IOTA & 131071)] = fTemp27; + fRec42[0] = (fVec14[((IOTA - iConst16) & 131071)] + (fRec39[0] * fRec42[1])); + float fTemp28 = ((fTemp2 * fRec40[1]) + ((fRec10[0] * fTemp17) * fRec42[0])); + fVec15[(IOTA & 131071)] = fTemp28; + fRec40[0] = fVec15[((IOTA - iConst17) & 131071)]; + float fRec41 = (0.0f - (fTemp2 * fTemp28)); + fRec5[(IOTA & 131071)] = (fRec41 + fRec40[1]); + fRec6[(IOTA & 131071)] = (fTemp17 * fRec42[0]); + fRec7[(IOTA & 131071)] = fTemp27; + output0[i] = FAUSTFLOAT(((fTemp0 * fRec0[0]) + (0.600000024f * (fRec1[0] * (((fRec4[((IOTA - iConst18) & 131071)] + fRec4[((IOTA - iConst19) & 131071)]) + fRec2[((IOTA - iConst20) & 131071)]) - (((fRec3[((IOTA - iConst21) & 131071)] + fRec7[((IOTA - iConst22) & 131071)]) + fRec6[((IOTA - iConst23) & 131071)]) + fRec5[((IOTA - iConst24) & 131071)])))))); + output1[i] = FAUSTFLOAT(((fTemp1 * fRec0[0]) + (0.600000024f * (fRec1[0] * (((fRec7[((IOTA - iConst25) & 131071)] + fRec7[((IOTA - iConst26) & 131071)]) + fRec5[((IOTA - iConst27) & 131071)]) - (((fRec6[((IOTA - iConst28) & 131071)] + fRec4[((IOTA - iConst29) & 131071)]) + fRec3[((IOTA - iConst30) & 131071)]) + fRec2[((IOTA - iConst31) & 131071)])))))); fRec0[1] = fRec0[0]; fRec1[1] = fRec1[0]; fRec10[1] = fRec10[0]; - fRec18[1] = fRec18[0]; - fRec21[1] = fRec21[0]; - fRec20[1] = fRec20[0]; - fRec14[1] = fRec14[0]; - fRec15[1] = fRec15[0]; - iRec16[1] = iRec16[0]; - iRec17[1] = iRec17[0]; - fRec32[1] = fRec32[0]; - IOTA = (IOTA + 1); - fRec33[1] = fRec33[0]; - fRec34[1] = fRec34[0]; - fRec31[1] = fRec31[0]; - fRec35[1] = fRec35[0]; - fRec30[1] = fRec30[0]; - fRec36[1] = fRec36[0]; - fRec28[1] = fRec28[0]; - fRec26[1] = fRec26[0]; - fRec37[1] = fRec37[0]; fRec24[1] = fRec24[0]; + IOTA = (IOTA + 1); + fRec25[1] = fRec25[0]; + fRec26[1] = fRec26[0]; + fRec23[1] = fRec23[0]; + fRec27[1] = fRec27[0]; fRec22[1] = fRec22[0]; + fRec28[1] = fRec28[0]; + fRec20[1] = fRec20[0]; + fRec18[1] = fRec18[0]; + fRec29[1] = fRec29[0]; + fRec16[1] = fRec16[0]; + fRec14[1] = fRec14[0]; + fRec30[1] = fRec30[0]; + fRec35[1] = fRec35[0]; fRec38[1] = fRec38[0]; + fRec37[1] = fRec37[0]; + fRec31[1] = fRec31[0]; + fRec32[1] = fRec32[0]; + iRec33[1] = iRec33[0]; + iRec34[1] = iRec34[0]; fRec12[1] = fRec12[0]; fRec39[1] = fRec39[0]; fRec11[1] = fRec11[0]; fRec8[1] = fRec8[0]; - fRec45[1] = fRec45[0]; - fRec46[1] = fRec46[0]; - iRec47[1] = iRec47[0]; - iRec48[1] = iRec48[0]; - fRec58[1] = fRec58[0]; - fRec57[1] = fRec57[0]; - fRec55[1] = fRec55[0]; + fRec54[1] = fRec54[0]; fRec53[1] = fRec53[0]; fRec51[1] = fRec51[0]; fRec49[1] = fRec49[0]; + fRec47[1] = fRec47[0]; + fRec45[1] = fRec45[0]; + fRec55[1] = fRec55[0]; + fRec56[1] = fRec56[0]; + iRec57[1] = iRec57[0]; + iRec58[1] = iRec58[0]; fRec43[1] = fRec43[0]; fRec42[1] = fRec42[0]; fRec40[1] = fRec40[0]; } + //[End:compute] } + + FAUSTFLOAT getPredelay() const { return fHslider4; } + void setPredelay(FAUSTFLOAT value) { fHslider4 = value; } + + FAUSTFLOAT getInputAmount() const { return fHslider3; } + void setInputAmount(FAUSTFLOAT value) { fHslider3 = value; } + + FAUSTFLOAT getInputLowPassCutoff() const { return fHslider5; } + void setInputLowPassCutoff(FAUSTFLOAT value) { fHslider5 = value; } + + FAUSTFLOAT getInputHighPassCutoff() const { return fHslider6; } + void setInputHighPassCutoff(FAUSTFLOAT value) { fHslider6 = value; } + + FAUSTFLOAT getInputDiffusion1() const { return fHslider7; } + void setInputDiffusion1(FAUSTFLOAT value) { fHslider7 = value; } + + FAUSTFLOAT getInputDiffusion2() const { return fHslider8; } + void setInputDiffusion2(FAUSTFLOAT value) { fHslider8 = value; } + + FAUSTFLOAT getTailDensity() const { return fHslider9; } + void setTailDensity(FAUSTFLOAT value) { fHslider9 = value; } + + FAUSTFLOAT getDecay() const { return fHslider2; } + void setDecay(FAUSTFLOAT value) { fHslider2 = value; } + + FAUSTFLOAT getDamping() const { return fHslider12; } + void setDamping(FAUSTFLOAT value) { fHslider12 = value; } + + FAUSTFLOAT getModulatorFrequency() const { return fHslider11; } + void setModulatorFrequency(FAUSTFLOAT value) { fHslider11 = value; } + + FAUSTFLOAT getModulatorDepth() const { return fHslider10; } + void setModulatorDepth(FAUSTFLOAT value) { fHslider10 = value; } + + FAUSTFLOAT getDry() const { return fHslider0; } + void setDry(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getWet() const { return fHslider1; } + void setWet(FAUSTFLOAT value) { fHslider1 = value; } + + //[End:class] }; +//[After:class] -#ifdef FAUST_UIMACROS - - - - #define FAUST_LIST_ACTIVES(p) \ - p(HORIZONTALSLIDER, Predelay, "Predelay", fHslider6, 0.0f, 0.0f, 300.0f, 1.0f) \ - p(HORIZONTALSLIDER, Input_amount, "Input amount", fHslider5, 100.0f, 0.0f, 100.0f, 0.01f) \ - p(HORIZONTALSLIDER, Input_low_pass_cutoff, "Input low pass cutoff", fHslider7, 10000.0f, 1.0f, 20000.0f, 1.0f) \ - p(HORIZONTALSLIDER, Input_high_pass_cutoff, "Input high pass cutoff", fHslider8, 100.0f, 1.0f, 1000.0f, 1.0f) \ - p(HORIZONTALSLIDER, Input_diffusion_1, "Input diffusion 1", fHslider9, 75.0f, 0.0f, 100.0f, 0.01f) \ - p(HORIZONTALSLIDER, Input_diffusion_2, "Input diffusion 2", fHslider10, 62.5f, 0.0f, 100.0f, 0.01f) \ - p(HORIZONTALSLIDER, Tail_density, "Tail density", fHslider11, 70.0f, 0.0f, 100.0f, 0.01f) \ - p(HORIZONTALSLIDER, Decay, "Decay", fHslider2, 50.0f, 0.0f, 100.0f, 0.01f) \ - p(HORIZONTALSLIDER, Damping, "Damping", fHslider12, 5500.0f, 10.0f, 20000.0f, 1.0f) \ - p(HORIZONTALSLIDER, Modulator_frequency, "Modulator frequency", fHslider4, 1.0f, 0.01f, 4.0f, 0.01f) \ - p(HORIZONTALSLIDER, Modulator_depth, "Modulator depth", fHslider3, 0.5f, 0.0f, 10.0f, 0.10000000000000001f) \ - p(HORIZONTALSLIDER, Dry, "Dry", fHslider0, 100.0f, 0.0f, 100.0f, 0.01f) \ - p(HORIZONTALSLIDER, Wet, "Wet", fHslider1, 50.0f, 0.0f, 100.0f, 0.01f) \ - - #define FAUST_LIST_PASSIVES(p) \ #endif - +#if defined(__GNUC__) +#pragma GCC diagnostic pop #endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/effects/gen/gate.hxx b/src/sfizz/effects/gen/gate.hxx index 93da987b..f1da8235 100644 --- a/src/sfizz/effects/gen/gate.hxx +++ b/src/sfizz/effects/gen/gate.hxx @@ -1,7 +1,11 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ name: "gate" -Code generated with Faust 2.27.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -scal -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -scal -ftz 0 ------------------------------------------------------------ */ #ifndef __faustGate_H__ @@ -9,101 +13,77 @@ Compilation options: -lang cpp -inpl -scal -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustGate #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustGate { + //[Begin:class] - public: - - float fConst0; + + private: + FAUSTFLOAT fHslider0; FAUSTFLOAT fHslider1; int fSampleRate; + float fConst0; float fConst1; - float fConst2; float fRec3[2]; FAUSTFLOAT fHslider2; int iVec0[2]; - float fConst3; FAUSTFLOAT fHslider3; int iRec4[2]; float fRec1[2]; float fRec0[2]; - + public: + - void metadata() { - } - - int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { - (void)sample_rate; + //[Begin:classInit] + //[End:classInit] } - + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = float(_oversampling); - fConst1 = std::min(192000.0f, std::max(1.0f, float(fSampleRate))); - fConst2 = (1.0f / fConst1); - fConst3 = (fConst1 * fConst0); + fConst0 = float(fSampleRate); + fConst1 = (1.0f / fConst0); + //[End:instanceConstants] } - + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] fHslider0 = FAUSTFLOAT(0.0f); fHslider1 = FAUSTFLOAT(0.0f); fHslider2 = FAUSTFLOAT(0.0f); fHslider3 = FAUSTFLOAT(0.0f); + //[End:instanceResetUserInterface] } - + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec3[l0] = 0.0f; } @@ -119,44 +99,45 @@ class faustGate { for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec0[l4] = 0.0f; } + //[End:instanceClear] } - + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - faustGate* clone() { - return new faustGate(); - } - + + int getSampleRate() { return fSampleRate; } - - void buildUserInterface() { - } - - void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - float fSlow0 = (fConst0 * float(fHslider0)); - float fSlow1 = (fConst0 * float(fHslider1)); + float fSlow0 = float(fHslider0); + float fSlow1 = float(fHslider1); float fSlow2 = std::min(fSlow0, fSlow1); int iSlow3 = (std::fabs(fSlow2) < 1.1920929e-07f); - float fSlow4 = (iSlow3 ? 0.0f : std::exp((0.0f - (fConst2 / (iSlow3 ? 1.0f : fSlow2))))); + float fSlow4 = (iSlow3 ? 0.0f : std::exp((0.0f - (fConst1 / (iSlow3 ? 1.0f : fSlow2))))); float fSlow5 = (1.0f - fSlow4); float fSlow6 = std::pow(10.0f, (0.0500000007f * float(fHslider2))); - int iSlow7 = int((fConst3 * float(fHslider3))); + int iSlow7 = int((fConst0 * float(fHslider3))); int iSlow8 = (std::fabs(fSlow0) < 1.1920929e-07f); - float fSlow9 = (iSlow8 ? 0.0f : std::exp((0.0f - (fConst2 / (iSlow8 ? 1.0f : fSlow0))))); + float fSlow9 = (iSlow8 ? 0.0f : std::exp((0.0f - (fConst1 / (iSlow8 ? 1.0f : fSlow0))))); int iSlow10 = (std::fabs(fSlow1) < 1.1920929e-07f); - float fSlow11 = (iSlow10 ? 0.0f : std::exp((0.0f - (fConst2 / (iSlow10 ? 1.0f : fSlow1))))); + float fSlow11 = (iSlow10 ? 0.0f : std::exp((0.0f - (fConst1 / (iSlow10 ? 1.0f : fSlow1))))); for (int i = 0; (i < count); i = (i + 1)) { float fTemp0 = float(input0[i]); fRec3[0] = ((fRec3[1] * fSlow4) + (std::fabs(fTemp0) * fSlow5)); @@ -175,22 +156,30 @@ class faustGate { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getThreshold() const { return fHslider2; } + void setThreshold(FAUSTFLOAT value) { fHslider2 = value; } + + FAUSTFLOAT getAttack() const { return fHslider0; } + void setAttack(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getHold() const { return fHslider3; } + void setHold(FAUSTFLOAT value) { fHslider3 = value; } + + FAUSTFLOAT getRelease() const { return fHslider1; } + void setRelease(FAUSTFLOAT value) { fHslider1 = value; } + + //[End:class] }; +//[After:class] -#ifdef FAUST_UIMACROS - - - - #define FAUST_LIST_ACTIVES(p) \ - p(HORIZONTALSLIDER, Threshold, "Threshold", fHslider2, 0.0f, -60.0f, 0.0f, 0.01f) \ - p(HORIZONTALSLIDER, Attack, "Attack", fHslider0, 0.0f, 0.0f, 10.0f, 0.001f) \ - p(HORIZONTALSLIDER, Hold, "Hold", fHslider3, 0.0f, 0.0f, 10.0f, 0.001f) \ - p(HORIZONTALSLIDER, Release, "Release", fHslider1, 0.0f, 0.0f, 5.0f, 0.001f) \ - - #define FAUST_LIST_PASSIVES(p) \ #endif - +#if defined(__GNUC__) +#pragma GCC diagnostic pop #endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/effects/gen/limiter.hxx b/src/sfizz/effects/gen/limiter.hxx index 420f6728..0963f670 100644 --- a/src/sfizz/effects/gen/limiter.hxx +++ b/src/sfizz/effects/gen/limiter.hxx @@ -1,135 +1,171 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ name: "limiter" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -scal -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -scal -ftz 0 ------------------------------------------------------------ */ -#ifndef __faustLimiter_H__ -#define __faustLimiter_H__ +#ifndef __faustLimiter_H__ +#define __faustLimiter_H__ #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS + +#ifndef FAUSTCLASS #define FAUSTCLASS faustLimiter #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustLimiter { + //[Begin:class] -private: - int fSampleRate; - float fConst0; - float fConst1; - float fConst2; - float fConst3; - float fConst4; - float fConst5; - float fConst6; - float fRec2[2]; - float fRec1[2]; - float fRec0[2]; - float fRec5[2]; - float fRec4[2]; - float fRec3[2]; + + private: + + int fSampleRate; + float fConst0; + float fConst1; + float fConst2; + float fConst3; + float fConst4; + float fConst5; + float fConst6; + float fRec2[2]; + float fRec1[2]; + float fRec0[2]; + float fRec5[2]; + float fRec4[2]; + float fRec3[2]; + + public: + -public: - static void classInit(int sample_rate) - { - (void)sample_rate; - } + static constexpr int getNumInputs() { + return 2; + } + static constexpr int getNumOutputs() { + return 2; + } + + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] + } + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] + fSampleRate = sample_rate; + fConst0 = float(fSampleRate); + fConst1 = std::exp((0.0f - (2500.0f / fConst0))); + fConst2 = (1.0f - fConst1); + fConst3 = std::exp((0.0f - (1250.0f / fConst0))); + fConst4 = (1.0f - fConst3); + fConst5 = std::exp((0.0f - (2.0f / fConst0))); + fConst6 = (1.0f - fConst5); + //[End:instanceConstants] + } + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + //[End:instanceResetUserInterface] + } + + void instanceClear() { + //[Begin:instanceClear] + for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { + fRec2[l0] = 0.0f; + } + for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { + fRec1[l1] = 0.0f; + } + for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { + fRec0[l2] = 0.0f; + } + for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { + fRec5[l3] = 0.0f; + } + for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { + fRec4[l4] = 0.0f; + } + for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { + fRec3[l5] = 0.0f; + } + //[End:instanceClear] + } + + void init(int sample_rate) { + //[Begin:init] + classInit(sample_rate); + instanceInit(sample_rate); + //[End:init] + } + void instanceInit(int sample_rate) { + //[Begin:instanceInit] + instanceConstants(sample_rate); + instanceResetUserInterface(); + instanceClear(); + //[End:instanceInit] + } + + + int getSampleRate() { + return fSampleRate; + } + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; + FAUSTFLOAT* output0 = outputs[0]; + FAUSTFLOAT* output1 = outputs[1]; + for (int i = 0; (i < count); i = (i + 1)) { + float fTemp0 = float(input0[i]); + float fTemp1 = float(input1[i]); + float fTemp2 = std::fabs(fTemp0); + fRec2[0] = std::max(fTemp2, ((fConst5 * fRec2[1]) + (fConst6 * fTemp2))); + fRec1[0] = ((fConst3 * fRec1[1]) + (fConst4 * fRec2[0])); + fRec0[0] = ((fConst1 * fRec0[1]) + (fConst2 * ((fRec1[0] > 1.0f) ? (1.0f / fRec1[0]) : 1.0f))); + output0[i] = FAUSTFLOAT((fTemp0 * fRec0[0])); + float fTemp3 = std::fabs(fTemp1); + fRec5[0] = std::max(fTemp3, ((fConst5 * fRec5[1]) + (fConst6 * fTemp3))); + fRec4[0] = ((fConst3 * fRec4[1]) + (fConst4 * fRec5[0])); + fRec3[0] = ((fConst1 * fRec3[1]) + (fConst2 * ((fRec4[0] > 1.0f) ? (1.0f / fRec4[0]) : 1.0f))); + output1[i] = FAUSTFLOAT((fTemp1 * fRec3[0])); + fRec2[1] = fRec2[0]; + fRec1[1] = fRec1[0]; + fRec0[1] = fRec0[0]; + fRec5[1] = fRec5[0]; + fRec4[1] = fRec4[0]; + fRec3[1] = fRec3[0]; + } + //[End:compute] + } - void instanceConstants(int sample_rate) - { - fSampleRate = sample_rate; - fConst0 = (std::min(192000.0f, std::max(1.0f, float(fSampleRate))) * float(_oversampling)); - fConst1 = std::exp((0.0f - (2500.0f / fConst0))); - fConst2 = (1.0f - fConst1); - fConst3 = std::exp((0.0f - (1250.0f / fConst0))); - fConst4 = (1.0f - fConst3); - fConst5 = std::exp((0.0f - (2.0f / fConst0))); - fConst6 = (1.0f - fConst5); - } - void instanceResetUserInterface() - { - } - - void instanceClear() - { - for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { - fRec2[l0] = 0.0f; - } - for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { - fRec1[l1] = 0.0f; - } - for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { - fRec0[l2] = 0.0f; - } - for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { - fRec5[l3] = 0.0f; - } - for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { - fRec4[l4] = 0.0f; - } - for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { - fRec3[l5] = 0.0f; - } - } - - void init(int sample_rate) - { - classInit(sample_rate); - instanceInit(sample_rate); - } - void instanceInit(int sample_rate) - { - instanceConstants(sample_rate); - instanceResetUserInterface(); - instanceClear(); - } - - int getSampleRate() - { - return fSampleRate; - } - - void compute(int count, const FAUSTFLOAT* const* inputs, FAUSTFLOAT* const* outputs) - { - const FAUSTFLOAT* input0 = inputs[0]; - const FAUSTFLOAT* input1 = inputs[1]; - FAUSTFLOAT* output0 = outputs[0]; - FAUSTFLOAT* output1 = outputs[1]; - for (int i = 0; (i < count); i = (i + 1)) { - float fTemp0 = float(input0[i]); - float fTemp1 = float(input1[i]); - float fTemp2 = std::fabs(fTemp0); - fRec2[0] = std::max(fTemp2, ((fConst5 * fRec2[1]) + (fConst6 * fTemp2))); - fRec1[0] = ((fConst3 * fRec1[1]) + (fConst4 * fRec2[0])); - fRec0[0] = ((fConst1 * fRec0[1]) + (fConst2 * ((fRec1[0] > 1.0f) ? (1.0f / fRec1[0]) : 1.0f))); - output0[i] = FAUSTFLOAT((fTemp0 * fRec0[0])); - float fTemp3 = std::fabs(fTemp1); - fRec5[0] = std::max(fTemp3, ((fConst5 * fRec5[1]) + (fConst6 * fTemp3))); - fRec4[0] = ((fConst3 * fRec4[1]) + (fConst4 * fRec5[0])); - fRec3[0] = ((fConst1 * fRec3[1]) + (fConst2 * ((fRec4[0] > 1.0f) ? (1.0f / fRec4[0]) : 1.0f))); - output1[i] = FAUSTFLOAT((fTemp1 * fRec3[0])); - fRec2[1] = fRec2[0]; - fRec1[1] = fRec1[0]; - fRec0[1] = fRec0[0]; - fRec5[1] = fRec5[0]; - fRec4[1] = fRec4[0]; - fRec3[1] = fRec3[0]; - } - } + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chApf1p.hxx b/src/sfizz/gen/filters/sfz2chApf1p.hxx index 08c62853..33ccbcfe 100644 --- a/src/sfizz/gen/filters/sfz2chApf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chApf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chApf1p_H__ @@ -11,98 +15,71 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chApf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chApf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec1[2]; double fRec0[2]; double fRec2[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (6.2831853071795862 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec1[l0] = 0.0; } @@ -112,40 +89,41 @@ class faust2chApf1p : public sfzFilterDsp { for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec2[l2] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chApf1p* clone() { - return new faust2chApf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (((fConst1 * double(fCutoff)) + -1.0) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (((fConst2 * double(fHslider0)) + -1.0) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); - fRec1[0] = (fSlow1 + (fSlow0 * fRec1[1])); + fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); fRec0[0] = (fTemp0 - (fRec1[0] * fRec0[1])); output0[i] = FAUSTFLOAT((fRec0[1] + (fRec1[0] * fRec0[0]))); fRec2[0] = (fTemp1 - (fRec1[0] * fRec2[1])); @@ -154,8 +132,21 @@ class faust2chApf1p : public sfzFilterDsp { fRec0[1] = fRec0[0]; fRec2[1] = fRec2[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chBpf1p.hxx b/src/sfizz/gen/filters/sfz2chBpf1p.hxx index 9aa4ab02..6145ed42 100644 --- a/src/sfizz/gen/filters/sfz2chBpf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chBpf1p_H__ @@ -11,100 +15,73 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chBpf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chBpf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec2[2]; double fRec1[2]; double fRec0[2]; double fRec4[2]; double fRec3[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (1.0 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (1.0 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -120,40 +97,41 @@ class faust2chBpf1p : public sfzFilterDsp { for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec3[l4] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chBpf1p* clone() { - return new faust2chBpf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (std::exp((fConst1 * (0.0 - (6.2831853071795862 * double(fCutoff))))) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); - fRec2[0] = (fSlow1 + (fSlow0 * fRec2[1])); + fRec2[0] = ((fSlow0 * fRec2[1]) + fSlow1); fRec1[0] = (fTemp0 + (fRec2[0] * fRec1[1])); double fTemp2 = (1.0 - fRec2[0]); fRec0[0] = ((fRec1[0] * fTemp2) + (fRec2[0] * fRec0[1])); @@ -169,8 +147,21 @@ class faust2chBpf1p : public sfzFilterDsp { fRec4[1] = fRec4[0]; fRec3[1] = fRec3[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chBpf2p.hxx b/src/sfizz/gen/filters/sfz2chBpf2p.hxx index 011f0d3d..4ebc2083 100644 --- a/src/sfizz/gen/filters/sfz2chBpf2p.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf2p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chBpf2p_H__ @@ -11,34 +15,38 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chBpf2p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chBpf2p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fRec2[2]; double fVec0[2]; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec3[2]; double fRec4[2]; double fVec1[2]; @@ -52,71 +60,40 @@ class faust2chBpf2p : public sfzFilterDsp { double fVec5[2]; double fRec8[2]; double fRec7[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -162,38 +139,39 @@ class faust2chBpf2p : public sfzFilterDsp { for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec7[l14] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chBpf2p* clone() { - return new faust2chBpf2p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); @@ -238,8 +216,24 @@ class faust2chBpf2p : public sfzFilterDsp { fRec8[1] = fRec8[0]; fRec7[1] = fRec7[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx b/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx index f85094dd..2719a4d8 100644 --- a/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chBpf2pSv_H__ @@ -11,104 +15,77 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chBpf2pSv #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chBpf2pSv : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; double fRec3[2]; - FAUSTFLOAT fQ; + FAUSTFLOAT fVslider0; double fRec4[2]; double fRec5[2]; double fRec1[2]; double fRec2[2]; double fRec7[2]; double fRec8[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (3.1415926535897931 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec3[l0] = 0.0; } @@ -130,38 +107,39 @@ class faust2chBpf2pSv : public sfzFilterDsp { for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { fRec8[l6] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chBpf2pSv* clone() { - return new faust2chBpf2pSv(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fCutoff))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); @@ -194,8 +172,24 @@ class faust2chBpf2pSv : public sfzFilterDsp { fRec7[1] = fRec7[0]; fRec8[1] = fRec8[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chBpf4p.hxx b/src/sfizz/gen/filters/sfz2chBpf4p.hxx index cf9d5cb5..84fe9ac1 100644 --- a/src/sfizz/gen/filters/sfz2chBpf4p.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf4p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chBpf4p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chBpf4p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chBpf4p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fRec5[2]; double fVec0[2]; @@ -62,71 +70,40 @@ class faust2chBpf4p : public sfzFilterDsp { double fVec11[2]; double fRec10[2]; double fRec9[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -202,38 +179,39 @@ class faust2chBpf4p : public sfzFilterDsp { for (int l24 = 0; (l24 < 2); l24 = (l24 + 1)) { fRec9[l24] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chBpf4p* clone() { - return new faust2chBpf4p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); @@ -298,8 +276,24 @@ class faust2chBpf4p : public sfzFilterDsp { fRec10[1] = fRec10[0]; fRec9[1] = fRec9[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chBpf6p.hxx b/src/sfizz/gen/filters/sfz2chBpf6p.hxx index 2e8808c6..473690f6 100644 --- a/src/sfizz/gen/filters/sfz2chBpf6p.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf6p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chBpf6p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chBpf6p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chBpf6p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fRec7[2]; double fVec0[2]; @@ -72,71 +80,40 @@ class faust2chBpf6p : public sfzFilterDsp { double fVec17[2]; double fRec12[2]; double fRec11[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -242,38 +219,39 @@ class faust2chBpf6p : public sfzFilterDsp { for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) { fRec11[l34] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chBpf6p* clone() { - return new faust2chBpf6p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); @@ -358,8 +336,24 @@ class faust2chBpf6p : public sfzFilterDsp { fRec12[1] = fRec12[0]; fRec11[1] = fRec11[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chBrf1p.hxx b/src/sfizz/gen/filters/sfz2chBrf1p.hxx index 99b3bd51..4817a6fc 100644 --- a/src/sfizz/gen/filters/sfz2chBrf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chBrf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chBrf1p_H__ @@ -11,100 +15,73 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chBrf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chBrf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec2[2]; double fRec1[2]; double fRec0[2]; double fRec4[2]; double fRec3[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (6.2831853071795862 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -120,40 +97,41 @@ class faust2chBrf1p : public sfzFilterDsp { for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec3[l4] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chBrf1p* clone() { - return new faust2chBrf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (((fConst1 * double(fCutoff)) + -1.0) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (((fConst2 * double(fHslider0)) + -1.0) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); - fRec2[0] = (fSlow1 + (fSlow0 * fRec2[1])); + fRec2[0] = ((fSlow0 * fRec2[1]) + fSlow1); fRec1[0] = (fTemp0 - (fRec2[0] * fRec1[1])); fRec0[0] = (fRec1[1] + (fRec2[0] * (fRec1[0] - fRec0[1]))); output0[i] = FAUSTFLOAT((fTemp0 + (fRec0[1] + (fRec2[0] * fRec0[0])))); @@ -166,8 +144,21 @@ class faust2chBrf1p : public sfzFilterDsp { fRec4[1] = fRec4[0]; fRec3[1] = fRec3[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chBrf2p.hxx b/src/sfizz/gen/filters/sfz2chBrf2p.hxx index 91e28d07..2c4a25af 100644 --- a/src/sfizz/gen/filters/sfz2chBrf2p.hxx +++ b/src/sfizz/gen/filters/sfz2chBrf2p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chBrf2p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chBrf2p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chBrf2p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -50,71 +58,40 @@ class faust2chBrf2p : public sfzFilterDsp { double fVec5[2]; double fRec6[2]; double fRec5[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -154,37 +131,38 @@ class faust2chBrf2p : public sfzFilterDsp { for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) { fRec5[l12] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chBrf2p* clone() { - return new faust2chBrf2p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); - double fSlow2 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow2 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = (1.0 - fSlow0); double fSlow5 = (((0.0 - (2.0 * std::cos(fSlow1))) / fSlow3) * fSlow4); @@ -224,8 +202,24 @@ class faust2chBrf2p : public sfzFilterDsp { fRec6[1] = fRec6[0]; fRec5[1] = fRec5[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx b/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx index 773f7fd7..020f13b0 100644 --- a/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx +++ b/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chBrf2pSv_H__ @@ -11,104 +15,77 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chBrf2pSv #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chBrf2pSv : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; double fRec5[2]; - FAUSTFLOAT fQ; + FAUSTFLOAT fVslider0; double fRec4[2]; double fRec6[2]; double fRec2[2]; double fRec3[2]; double fRec9[2]; double fRec10[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (3.1415926535897931 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec5[l0] = 0.0; } @@ -130,38 +107,39 @@ class faust2chBrf2pSv : public sfzFilterDsp { for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { fRec10[l6] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chBrf2pSv* clone() { - return new faust2chBrf2pSv(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fCutoff))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); @@ -196,8 +174,24 @@ class faust2chBrf2pSv : public sfzFilterDsp { fRec9[1] = fRec9[0]; fRec10[1] = fRec10[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chEqHshelf.hxx b/src/sfizz/gen/filters/sfz2chEqHshelf.hxx index 85c9ea93..62447f2b 100644 --- a/src/sfizz/gen/filters/sfz2chEqHshelf.hxx +++ b/src/sfizz/gen/filters/sfz2chEqHshelf.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chEqHshelf_H__ @@ -11,7 +15,7 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include @@ -21,26 +25,30 @@ static double faust2chEqHshelf_faustpower2_f(double value) { return (value * value); } -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chEqHshelf #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chEqHshelf : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider0; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fBandwidth; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -56,72 +64,41 @@ class faust2chEqHshelf : public sfzFilterDsp { double fVec5[2]; double fRec8[2]; double fRec7[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fPkShGain = FAUSTFLOAT(0.0); - fCutoff = FAUSTFLOAT(440.0); - fBandwidth = FAUSTFLOAT(1.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fVslider0 = FAUSTFLOAT(0.0); + fHslider0 = FAUSTFLOAT(440.0); + fVslider1 = FAUSTFLOAT(1.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -167,44 +144,45 @@ class faust2chEqHshelf : public sfzFilterDsp { for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec7[l14] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chEqHshelf* clone() { - return new faust2chEqHshelf(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); - double fSlow2 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow3 = std::cos(fSlow2); - double fSlow4 = (fSlow3 * (fSlow1 + 1.0)); + double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = (faust2chEqHshelf_faustpower2_f(fSlow1) + 1.0); double fSlow6 = (fSlow1 + -1.0); double fSlow7 = faust2chEqHshelf_faustpower2_f(fSlow6); - double fSlow8 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, (1.0 / std::sqrt((((fSlow1 + (1.0 / fSlow1)) * ((1.0 / std::min(((fSlow5 / fSlow7) + -0.01), std::max(0.01, ((double(fBandwidth) * fSlow5) / fSlow7)))) + -1.0)) + 2.0))))); - double fSlow9 = (fSlow3 * fSlow6); + double fSlow8 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, (1.0 / std::sqrt((((fSlow1 + (1.0 / fSlow1)) * ((1.0 / std::min(((fSlow5 / fSlow7) + -0.01), std::max(0.01, ((double(fVslider1) * fSlow5) / fSlow7)))) + -1.0)) + 2.0))))); + double fSlow9 = (fSlow6 * fSlow3); double fSlow10 = ((fSlow1 + fSlow8) + (1.0 - fSlow9)); double fSlow11 = (1.0 - fSlow0); double fSlow12 = ((((0.0 - (2.0 * fSlow1)) * ((fSlow1 + fSlow4) + -1.0)) / fSlow10) * fSlow11); @@ -249,8 +227,27 @@ class faust2chEqHshelf : public sfzFilterDsp { fRec8[1] = fRec8[0]; fRec7[1] = fRec7[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + FAUSTFLOAT getBandwidth() const { return fVslider1; } + void setBandwidth(FAUSTFLOAT value) { fVslider1 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chEqLshelf.hxx b/src/sfizz/gen/filters/sfz2chEqLshelf.hxx index 42569770..5859b454 100644 --- a/src/sfizz/gen/filters/sfz2chEqLshelf.hxx +++ b/src/sfizz/gen/filters/sfz2chEqLshelf.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chEqLshelf_H__ @@ -11,7 +15,7 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include @@ -21,26 +25,30 @@ static double faust2chEqLshelf_faustpower2_f(double value) { return (value * value); } -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chEqLshelf #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chEqLshelf : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider0; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fBandwidth; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -56,72 +64,41 @@ class faust2chEqLshelf : public sfzFilterDsp { double fVec5[2]; double fRec8[2]; double fRec7[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fPkShGain = FAUSTFLOAT(0.0); - fCutoff = FAUSTFLOAT(440.0); - fBandwidth = FAUSTFLOAT(1.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fVslider0 = FAUSTFLOAT(0.0); + fHslider0 = FAUSTFLOAT(440.0); + fVslider1 = FAUSTFLOAT(1.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -167,44 +144,45 @@ class faust2chEqLshelf : public sfzFilterDsp { for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec7[l14] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chEqLshelf* clone() { - return new faust2chEqLshelf(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); - double fSlow2 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow3 = std::cos(fSlow2); - double fSlow4 = (fSlow3 * (fSlow1 + 1.0)); + double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = (fSlow1 + -1.0); - double fSlow6 = (fSlow3 * fSlow5); + double fSlow6 = (fSlow5 * fSlow3); double fSlow7 = (faust2chEqLshelf_faustpower2_f(fSlow1) + 1.0); double fSlow8 = faust2chEqLshelf_faustpower2_f(fSlow5); - double fSlow9 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, (1.0 / std::sqrt((((fSlow1 + (1.0 / fSlow1)) * ((1.0 / std::min(((fSlow7 / fSlow8) + -0.01), std::max(0.01, ((double(fBandwidth) * fSlow7) / fSlow8)))) + -1.0)) + 2.0))))); + double fSlow9 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, (1.0 / std::sqrt((((fSlow1 + (1.0 / fSlow1)) * ((1.0 / std::min(((fSlow7 / fSlow8) + -0.01), std::max(0.01, ((double(fVslider1) * fSlow7) / fSlow8)))) + -1.0)) + 2.0))))); double fSlow10 = (fSlow6 + fSlow9); double fSlow11 = ((fSlow1 + fSlow10) + 1.0); double fSlow12 = (1.0 - fSlow0); @@ -249,8 +227,27 @@ class faust2chEqLshelf : public sfzFilterDsp { fRec8[1] = fRec8[0]; fRec7[1] = fRec7[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + FAUSTFLOAT getBandwidth() const { return fVslider1; } + void setBandwidth(FAUSTFLOAT value) { fVslider1 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chEqPeak.hxx b/src/sfizz/gen/filters/sfz2chEqPeak.hxx index 9a3e28a3..1849c94f 100644 --- a/src/sfizz/gen/filters/sfz2chEqPeak.hxx +++ b/src/sfizz/gen/filters/sfz2chEqPeak.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chEqPeak_H__ @@ -11,7 +15,7 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif /* link with : "" */ #include @@ -19,27 +23,31 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chEqPeak #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chEqPeak : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fConst3; - FAUSTFLOAT fBandwidth; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -54,73 +62,42 @@ class faust2chEqPeak : public sfzFilterDsp { double fVec5[2]; double fRec7[2]; double fRec6[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); fConst3 = (2.1775860903036022 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fBandwidth = FAUSTFLOAT(1.0); - fPkShGain = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + fVslider1 = FAUSTFLOAT(1.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -163,45 +140,46 @@ class faust2chEqPeak : public sfzFilterDsp { for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { fRec6[l13] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chEqPeak* clone() { - return new faust2chEqPeak(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::max(0.0, double(fCutoff)); + double fSlow1 = std::max(0.0, double(fHslider0)); double fSlow2 = (fConst2 * fSlow1); double fSlow3 = std::sin(fSlow2); - double fSlow4 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * double(fBandwidth)) / fSlow3))))))); - double fSlow5 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); + double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * double(fVslider1)) / fSlow3))))))); double fSlow6 = (0.5 * (fSlow3 / (fSlow4 * fSlow5))); double fSlow7 = (fSlow6 + 1.0); double fSlow8 = (1.0 - fSlow0); double fSlow9 = (((0.0 - (2.0 * std::cos(fSlow2))) / fSlow7) * fSlow8); - double fSlow10 = (0.5 * ((fSlow3 * fSlow5) / fSlow4)); + double fSlow10 = (0.5 * ((fSlow4 * fSlow3) / fSlow5)); double fSlow11 = (((fSlow10 + 1.0) / fSlow7) * fSlow8); double fSlow12 = (((1.0 - fSlow10) / fSlow7) * fSlow8); double fSlow13 = (((1.0 - fSlow6) / fSlow7) * fSlow8); @@ -239,8 +217,27 @@ class faust2chEqPeak : public sfzFilterDsp { fRec7[1] = fRec7[0]; fRec6[1] = fRec6[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + FAUSTFLOAT getBandwidth() const { return fVslider1; } + void setBandwidth(FAUSTFLOAT value) { fVslider1 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chHpf1p.hxx b/src/sfizz/gen/filters/sfz2chHpf1p.hxx index 9040783f..57ca9c51 100644 --- a/src/sfizz/gen/filters/sfz2chHpf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chHpf1p_H__ @@ -11,98 +15,71 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chHpf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chHpf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec1[2]; double fRec0[2]; double fRec2[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (1.0 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (1.0 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec1[l0] = 0.0; } @@ -112,40 +89,41 @@ class faust2chHpf1p : public sfzFilterDsp { for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec2[l2] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chHpf1p* clone() { - return new faust2chHpf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (std::exp((fConst1 * (0.0 - (6.2831853071795862 * double(fCutoff))))) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); - fRec1[0] = (fSlow1 + (fSlow0 * fRec1[1])); + fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); fRec0[0] = (fTemp0 + (fRec1[0] * fRec0[1])); double fTemp2 = (fRec1[0] + 1.0); double fTemp3 = (0.0 - (0.5 * fTemp2)); @@ -156,8 +134,21 @@ class faust2chHpf1p : public sfzFilterDsp { fRec0[1] = fRec0[0]; fRec2[1] = fRec2[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chHpf2p.hxx b/src/sfizz/gen/filters/sfz2chHpf2p.hxx index 0906a3b1..99967081 100644 --- a/src/sfizz/gen/filters/sfz2chHpf2p.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf2p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chHpf2p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chHpf2p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chHpf2p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -51,71 +59,40 @@ class faust2chHpf2p : public sfzFilterDsp { double fVec5[2]; double fRec7[2]; double fRec6[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -158,38 +135,39 @@ class faust2chHpf2p : public sfzFilterDsp { for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { fRec6[l13] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chHpf2p* clone() { - return new faust2chHpf2p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); @@ -232,8 +210,24 @@ class faust2chHpf2p : public sfzFilterDsp { fRec7[1] = fRec7[0]; fRec6[1] = fRec6[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx b/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx index 4089b324..6ff0bb53 100644 --- a/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chHpf2pSv_H__ @@ -11,104 +15,77 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chHpf2pSv #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chHpf2pSv : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; double fRec4[2]; - FAUSTFLOAT fQ; + FAUSTFLOAT fVslider0; double fRec3[2]; double fRec5[2]; double fRec1[2]; double fRec2[2]; double fRec7[2]; double fRec8[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (3.1415926535897931 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec4[l0] = 0.0; } @@ -130,38 +107,39 @@ class faust2chHpf2pSv : public sfzFilterDsp { for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { fRec8[l6] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chHpf2pSv* clone() { - return new faust2chHpf2pSv(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fCutoff))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); @@ -194,8 +172,24 @@ class faust2chHpf2pSv : public sfzFilterDsp { fRec7[1] = fRec7[0]; fRec8[1] = fRec8[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chHpf4p.hxx b/src/sfizz/gen/filters/sfz2chHpf4p.hxx index 87cf14ee..d6e829be 100644 --- a/src/sfizz/gen/filters/sfz2chHpf4p.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf4p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chHpf4p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chHpf4p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chHpf4p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fVec0[2]; double fRec5[2]; @@ -61,71 +69,40 @@ class faust2chHpf4p : public sfzFilterDsp { double fVec11[2]; double fRec9[2]; double fRec8[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -198,38 +175,39 @@ class faust2chHpf4p : public sfzFilterDsp { for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) { fRec8[l23] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chHpf4p* clone() { - return new faust2chHpf4p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); @@ -294,8 +272,24 @@ class faust2chHpf4p : public sfzFilterDsp { fRec9[1] = fRec9[0]; fRec8[1] = fRec8[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chHpf6p.hxx b/src/sfizz/gen/filters/sfz2chHpf6p.hxx index dcdd4ffb..b2fdbd97 100644 --- a/src/sfizz/gen/filters/sfz2chHpf6p.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf6p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chHpf6p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chHpf6p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chHpf6p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fVec0[2]; double fRec7[2]; @@ -71,71 +79,40 @@ class faust2chHpf6p : public sfzFilterDsp { double fVec17[2]; double fRec11[2]; double fRec10[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -238,38 +215,39 @@ class faust2chHpf6p : public sfzFilterDsp { for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) { fRec10[l33] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chHpf6p* clone() { - return new faust2chHpf6p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); @@ -356,8 +334,24 @@ class faust2chHpf6p : public sfzFilterDsp { fRec11[1] = fRec11[0]; fRec10[1] = fRec10[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chHsh.hxx b/src/sfizz/gen/filters/sfz2chHsh.hxx index f58b9574..7f7240d1 100644 --- a/src/sfizz/gen/filters/sfz2chHsh.hxx +++ b/src/sfizz/gen/filters/sfz2chHsh.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chHsh_H__ @@ -11,33 +15,37 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chHsh #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chHsh : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider0; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -53,72 +61,41 @@ class faust2chHsh : public sfzFilterDsp { double fVec5[2]; double fRec8[2]; double fRec7[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fPkShGain = FAUSTFLOAT(0.0); - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fVslider0 = FAUSTFLOAT(0.0); + fHslider0 = FAUSTFLOAT(440.0); + fVslider1 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -164,48 +141,49 @@ class faust2chHsh : public sfzFilterDsp { for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec7[l14] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chHsh* clone() { - return new faust2chHsh(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); - double fSlow2 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow3 = std::cos(fSlow2); - double fSlow4 = (fSlow3 * (fSlow1 + 1.0)); - double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ))))); - double fSlow6 = (fSlow3 * (fSlow1 + -1.0)); + double fSlow4 = ((fSlow1 + 1.0) * fSlow3); + double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider1))))); + double fSlow6 = ((fSlow1 + -1.0) * fSlow3); double fSlow7 = ((fSlow1 + fSlow5) + (1.0 - fSlow6)); double fSlow8 = (1.0 - fSlow0); double fSlow9 = ((((0.0 - (2.0 * fSlow1)) * ((fSlow1 + fSlow4) + -1.0)) / fSlow7) * fSlow8); - double fSlow10 = (fSlow1 + fSlow6); - double fSlow11 = (((fSlow1 * ((fSlow5 + fSlow10) + 1.0)) / fSlow7) * fSlow8); - double fSlow12 = (((fSlow1 * (fSlow10 + (1.0 - fSlow5))) / fSlow7) * fSlow8); - double fSlow13 = (((fSlow1 + (1.0 - (fSlow5 + fSlow6))) / fSlow7) * fSlow8); + double fSlow10 = (fSlow6 + fSlow5); + double fSlow11 = (((fSlow1 * ((fSlow1 + fSlow10) + 1.0)) / fSlow7) * fSlow8); + double fSlow12 = (((fSlow1 * ((fSlow1 + fSlow6) + (1.0 - fSlow5))) / fSlow7) * fSlow8); + double fSlow13 = (((fSlow1 + (1.0 - fSlow10)) / fSlow7) * fSlow8); double fSlow14 = ((2.0 * ((fSlow1 + (-1.0 - fSlow4)) / fSlow7)) * fSlow8); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); @@ -243,8 +221,27 @@ class faust2chHsh : public sfzFilterDsp { fRec8[1] = fRec8[0]; fRec7[1] = fRec7[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider1; } + void setResonance(FAUSTFLOAT value) { fVslider1 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chLpf1p.hxx b/src/sfizz/gen/filters/sfz2chLpf1p.hxx index a11d4fa6..83819344 100644 --- a/src/sfizz/gen/filters/sfz2chLpf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chLpf1p_H__ @@ -11,98 +15,71 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chLpf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chLpf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec1[2]; double fRec0[2]; double fRec2[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (1.0 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (1.0 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec1[l0] = 0.0; } @@ -112,40 +89,41 @@ class faust2chLpf1p : public sfzFilterDsp { for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec2[l2] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chLpf1p* clone() { - return new faust2chLpf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (std::exp((fConst1 * (0.0 - (6.2831853071795862 * double(fCutoff))))) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); - fRec1[0] = (fSlow1 + (fSlow0 * fRec1[1])); + fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); fRec0[0] = (fTemp0 + (fRec1[0] * fRec0[1])); double fTemp2 = (1.0 - fRec1[0]); output0[i] = FAUSTFLOAT((fRec0[0] * fTemp2)); @@ -155,8 +133,21 @@ class faust2chLpf1p : public sfzFilterDsp { fRec0[1] = fRec0[0]; fRec2[1] = fRec2[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chLpf2p.hxx b/src/sfizz/gen/filters/sfz2chLpf2p.hxx index 9b6d4dc1..b120b92a 100644 --- a/src/sfizz/gen/filters/sfz2chLpf2p.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf2p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chLpf2p_H__ @@ -11,31 +15,35 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chLpf2p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chLpf2p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fConst2; double fRec2[2]; double fVec0[2]; @@ -51,71 +59,40 @@ class faust2chLpf2p : public sfzFilterDsp { double fVec5[2]; double fRec7[2]; double fRec6[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = (6.2831853071795862 / fConst0); fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -158,37 +135,38 @@ class faust2chLpf2p : public sfzFilterDsp { for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { fRec6[l13] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chLpf2p* clone() { - return new faust2chLpf2p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fConst1 * std::max(0.0, double(fCutoff))); + double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); @@ -233,8 +211,24 @@ class faust2chLpf2p : public sfzFilterDsp { fRec7[1] = fRec7[0]; fRec6[1] = fRec6[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx b/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx index 2bc4fe1a..75c2243b 100644 --- a/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chLpf2pSv_H__ @@ -11,104 +15,77 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chLpf2pSv #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chLpf2pSv : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; double fRec3[2]; - FAUSTFLOAT fQ; + FAUSTFLOAT fVslider0; double fRec4[2]; double fRec5[2]; double fRec1[2]; double fRec2[2]; double fRec7[2]; double fRec8[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (3.1415926535897931 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec3[l0] = 0.0; } @@ -130,38 +107,39 @@ class faust2chLpf2pSv : public sfzFilterDsp { for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) { fRec8[l6] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chLpf2pSv* clone() { - return new faust2chLpf2pSv(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fCutoff))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); @@ -194,8 +172,24 @@ class faust2chLpf2pSv : public sfzFilterDsp { fRec7[1] = fRec7[0]; fRec8[1] = fRec8[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chLpf4p.hxx b/src/sfizz/gen/filters/sfz2chLpf4p.hxx index f0a22427..448704b2 100644 --- a/src/sfizz/gen/filters/sfz2chLpf4p.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf4p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chLpf4p_H__ @@ -11,31 +15,35 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chLpf4p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chLpf4p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fConst2; double fRec2[2]; double fVec0[2]; @@ -61,71 +69,40 @@ class faust2chLpf4p : public sfzFilterDsp { double fVec11[2]; double fRec9[2]; double fRec8[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = (6.2831853071795862 / fConst0); fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -198,37 +175,38 @@ class faust2chLpf4p : public sfzFilterDsp { for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) { fRec8[l23] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chLpf4p* clone() { - return new faust2chLpf4p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fConst1 * std::max(0.0, double(fCutoff))); + double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); @@ -295,8 +273,24 @@ class faust2chLpf4p : public sfzFilterDsp { fRec9[1] = fRec9[0]; fRec8[1] = fRec8[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chLpf6p.hxx b/src/sfizz/gen/filters/sfz2chLpf6p.hxx index c09feb80..0d3ce7f2 100644 --- a/src/sfizz/gen/filters/sfz2chLpf6p.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf6p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chLpf6p_H__ @@ -11,37 +15,41 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chLpf6p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chLpf6p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fConst2; double fRec2[2]; - double fVec0[2]; double fRec7[2]; - double fVec1[2]; + double fVec0[2]; double fRec8[2]; + double fVec1[2]; double fVec2[2]; double fRec9[2]; double fRec6[2]; @@ -71,85 +79,54 @@ class faust2chLpf6p : public sfzFilterDsp { double fVec17[2]; double fRec11[2]; double fRec10[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = (6.2831853071795862 / fConst0); fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { - fVec0[l1] = 0.0; + fRec7[l1] = 0.0; } for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { - fRec7[l2] = 0.0; + fVec0[l2] = 0.0; } for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { - fVec1[l3] = 0.0; + fRec8[l3] = 0.0; } for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { - fRec8[l4] = 0.0; + fVec1[l4] = 0.0; } for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { fVec2[l5] = 0.0; @@ -238,37 +215,38 @@ class faust2chLpf6p : public sfzFilterDsp { for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) { fRec10[l33] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chLpf6p* clone() { - return new faust2chLpf6p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fConst1 * std::max(0.0, double(fCutoff))); + double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); @@ -281,14 +259,14 @@ class faust2chLpf6p : public sfzFilterDsp { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); fRec2[0] = (fSlow7 + (fSlow5 * fRec2[1])); - fVec0[0] = (fTemp0 * fRec2[0]); fRec7[0] = ((fSlow5 * fRec7[1]) + fSlow8); double fTemp2 = (fTemp0 * fRec7[0]); - fVec1[0] = fTemp2; + fVec0[0] = fTemp2; fRec8[0] = ((fSlow5 * fRec8[1]) + fSlow9); - fVec2[0] = (fVec1[1] - (fRec8[0] * fRec5[1])); + fVec1[0] = (fVec0[1] - (fRec8[0] * fRec5[1])); + fVec2[0] = (fTemp0 * fRec2[0]); fRec9[0] = ((fSlow5 * fRec9[1]) + fSlow10); - fRec6[0] = ((fVec0[1] + (fTemp2 + fVec2[1])) - (fRec9[0] * fRec6[1])); + fRec6[0] = ((fVec1[1] + (fTemp2 + fVec2[1])) - (fRec9[0] * fRec6[1])); fRec5[0] = fRec6[0]; fVec3[0] = (fRec2[0] * fRec5[0]); double fTemp3 = (fRec7[0] * fRec5[0]); @@ -323,10 +301,10 @@ class faust2chLpf6p : public sfzFilterDsp { fRec10[0] = fRec11[0]; output1[i] = FAUSTFLOAT(fRec10[0]); fRec2[1] = fRec2[0]; - fVec0[1] = fVec0[0]; fRec7[1] = fRec7[0]; - fVec1[1] = fVec1[0]; + fVec0[1] = fVec0[0]; fRec8[1] = fRec8[0]; + fVec1[1] = fVec1[0]; fVec2[1] = fVec2[0]; fRec9[1] = fRec9[0]; fRec6[1] = fRec6[0]; @@ -357,8 +335,24 @@ class faust2chLpf6p : public sfzFilterDsp { fRec11[1] = fRec11[0]; fRec10[1] = fRec10[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chLsh.hxx b/src/sfizz/gen/filters/sfz2chLsh.hxx index ba8105de..41d5f8a3 100644 --- a/src/sfizz/gen/filters/sfz2chLsh.hxx +++ b/src/sfizz/gen/filters/sfz2chLsh.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chLsh_H__ @@ -11,33 +15,37 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chLsh #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chLsh : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider0; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -53,72 +61,41 @@ class faust2chLsh : public sfzFilterDsp { double fVec5[2]; double fRec8[2]; double fRec7[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fPkShGain = FAUSTFLOAT(0.0); - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fVslider0 = FAUSTFLOAT(0.0); + fHslider0 = FAUSTFLOAT(440.0); + fVslider1 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -164,48 +141,49 @@ class faust2chLsh : public sfzFilterDsp { for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec7[l14] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chLsh* clone() { - return new faust2chLsh(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); - double fSlow2 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow3 = std::cos(fSlow2); - double fSlow4 = (fSlow3 * (fSlow1 + 1.0)); - double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ))))); - double fSlow6 = (fSlow3 * (fSlow1 + -1.0)); - double fSlow7 = (fSlow1 + fSlow6); - double fSlow8 = ((fSlow5 + fSlow7) + 1.0); + double fSlow4 = ((fSlow1 + 1.0) * fSlow3); + double fSlow5 = ((fSlow1 + -1.0) * fSlow3); + double fSlow6 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider1))))); + double fSlow7 = (fSlow5 + fSlow6); + double fSlow8 = ((fSlow1 + fSlow7) + 1.0); double fSlow9 = (1.0 - fSlow0); double fSlow10 = ((2.0 * ((fSlow1 * (fSlow1 + (-1.0 - fSlow4))) / fSlow8)) * fSlow9); - double fSlow11 = (((fSlow1 * ((fSlow1 + fSlow5) + (1.0 - fSlow6))) / fSlow8) * fSlow9); - double fSlow12 = (((fSlow1 * (fSlow1 + (1.0 - (fSlow5 + fSlow6)))) / fSlow8) * fSlow9); - double fSlow13 = (((fSlow7 + (1.0 - fSlow5)) / fSlow8) * fSlow9); + double fSlow11 = (((fSlow1 * ((fSlow1 + fSlow6) + (1.0 - fSlow5))) / fSlow8) * fSlow9); + double fSlow12 = (((fSlow1 * (fSlow1 + (1.0 - fSlow7))) / fSlow8) * fSlow9); + double fSlow13 = ((((fSlow1 + fSlow5) + (1.0 - fSlow6)) / fSlow8) * fSlow9); double fSlow14 = (((0.0 - (2.0 * ((fSlow1 + fSlow4) + -1.0))) / fSlow8) * fSlow9); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); @@ -243,8 +221,27 @@ class faust2chLsh : public sfzFilterDsp { fRec8[1] = fRec8[0]; fRec7[1] = fRec7[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider1; } + void setResonance(FAUSTFLOAT value) { fVslider1 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chPeq.hxx b/src/sfizz/gen/filters/sfz2chPeq.hxx index 482b2933..c23009d1 100644 --- a/src/sfizz/gen/filters/sfz2chPeq.hxx +++ b/src/sfizz/gen/filters/sfz2chPeq.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chPeq_H__ @@ -11,33 +15,37 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chPeq #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chPeq : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -52,72 +60,41 @@ class faust2chPeq : public sfzFilterDsp { double fVec5[2]; double fRec7[2]; double fRec6[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); - fPkShGain = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + fVslider1 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -160,44 +137,45 @@ class faust2chPeq : public sfzFilterDsp { for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { fRec6[l13] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chPeq* clone() { - return new faust2chPeq(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))); - double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider1))); double fSlow5 = (0.5 * (fSlow2 / (fSlow3 * fSlow4))); double fSlow6 = (fSlow5 + 1.0); double fSlow7 = (1.0 - fSlow0); double fSlow8 = (((0.0 - (2.0 * std::cos(fSlow1))) / fSlow6) * fSlow7); - double fSlow9 = (0.5 * ((fSlow2 * fSlow4) / fSlow3)); + double fSlow9 = (0.5 * ((fSlow4 * fSlow2) / fSlow3)); double fSlow10 = (((fSlow9 + 1.0) / fSlow6) * fSlow7); double fSlow11 = (((1.0 - fSlow9) / fSlow6) * fSlow7); double fSlow12 = (((1.0 - fSlow5) / fSlow6) * fSlow7); @@ -235,8 +213,27 @@ class faust2chPeq : public sfzFilterDsp { fRec7[1] = fRec7[0]; fRec6[1] = fRec6[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider1; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider1 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfz2chPink.hxx b/src/sfizz/gen/filters/sfz2chPink.hxx index c04cbcec..f1aca819 100644 --- a/src/sfizz/gen/filters/sfz2chPink.hxx +++ b/src/sfizz/gen/filters/sfz2chPink.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faust2chPink_H__ @@ -11,120 +15,94 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faust2chPink #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faust2chPink : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + double fRec0[4]; double fRec1[4]; int fSampleRate; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 2; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 2; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - case 1: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 4); l0 = (l0 + 1)) { fRec0[l0] = 0.0; } for (int l1 = 0; (l1 < 4); l1 = (l1 + 1)) { fRec1[l1] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faust2chPink* clone() { - return new faust2chPink(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; - FAUSTFLOAT* input1 = inputs[1]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; + FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; for (int i = 0; (i < count); i = (i + 1)) { @@ -141,8 +119,18 @@ class faust2chPink : public sfzFilterDsp { fRec1[j1] = fRec1[(j1 - 1)]; } } + //[End:compute] } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzApf1p.hxx b/src/sfizz/gen/filters/sfzApf1p.hxx index 950129a6..2e674295 100644 --- a/src/sfizz/gen/filters/sfzApf1p.hxx +++ b/src/sfizz/gen/filters/sfzApf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustApf1p_H__ @@ -11,133 +15,128 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustApf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustApf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (6.2831853071795862 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec1[l0] = 0.0; } for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { fRec0[l1] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustApf1p* clone() { - return new faustApf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (((fConst1 * double(fCutoff)) + -1.0) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (((fConst2 * double(fHslider0)) + -1.0) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); - fRec1[0] = (fSlow1 + (fSlow0 * fRec1[1])); + fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); fRec0[0] = (fTemp0 - (fRec1[0] * fRec0[1])); output0[i] = FAUSTFLOAT((fRec0[1] + (fRec1[0] * fRec0[0]))); fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzBpf1p.hxx b/src/sfizz/gen/filters/sfzBpf1p.hxx index 0273c976..e714e436 100644 --- a/src/sfizz/gen/filters/sfzBpf1p.hxx +++ b/src/sfizz/gen/filters/sfzBpf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustBpf1p_H__ @@ -11,90 +15,71 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustBpf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustBpf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec2[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (1.0 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (1.0 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -104,37 +89,38 @@ class faustBpf1p : public sfzFilterDsp { for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec0[l2] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustBpf1p* clone() { - return new faustBpf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (std::exp((fConst1 * (0.0 - (6.2831853071795862 * double(fCutoff))))) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); - fRec2[0] = (fSlow1 + (fSlow0 * fRec2[1])); + fRec2[0] = ((fSlow0 * fRec2[1]) + fSlow1); fRec1[0] = (fTemp0 + (fRec2[0] * fRec1[1])); fRec0[0] = ((fRec1[0] * (1.0 - fRec2[0])) + (fRec2[0] * fRec0[1])); double fTemp1 = (fRec2[0] + 1.0); @@ -143,8 +129,21 @@ class faustBpf1p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzBpf2p.hxx b/src/sfizz/gen/filters/sfzBpf2p.hxx index 5068871c..fea43873 100644 --- a/src/sfizz/gen/filters/sfzBpf2p.hxx +++ b/src/sfizz/gen/filters/sfzBpf2p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustBpf2p_H__ @@ -11,34 +15,38 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustBpf2p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustBpf2p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fRec2[2]; double fVec0[2]; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec3[2]; double fRec4[2]; double fVec1[2]; @@ -47,63 +55,40 @@ class faustBpf2p : public sfzFilterDsp { double fRec6[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -134,36 +119,37 @@ class faustBpf2p : public sfzFilterDsp { for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec0[l9] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustBpf2p* clone() { - return new faustBpf2p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); @@ -196,8 +182,24 @@ class faustBpf2p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzBpf2pSv.hxx b/src/sfizz/gen/filters/sfzBpf2pSv.hxx index 8a81bb74..19389f89 100644 --- a/src/sfizz/gen/filters/sfzBpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfzBpf2pSv.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustBpf2pSv_H__ @@ -11,94 +15,75 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustBpf2pSv #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustBpf2pSv : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; double fRec3[2]; - FAUSTFLOAT fQ; + FAUSTFLOAT fVslider0; double fRec4[2]; double fRec5[2]; double fRec1[2]; double fRec2[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (3.1415926535897931 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec3[l0] = 0.0; } @@ -114,36 +99,37 @@ class faustBpf2pSv : public sfzFilterDsp { for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec2[l4] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustBpf2pSv* clone() { - return new faustBpf2pSv(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fCutoff))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec3[0] = ((fSlow0 * fRec3[1]) + fSlow2); @@ -164,8 +150,24 @@ class faustBpf2pSv : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec2[1] = fRec2[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzBpf4p.hxx b/src/sfizz/gen/filters/sfzBpf4p.hxx index 33af5534..1342d920 100644 --- a/src/sfizz/gen/filters/sfzBpf4p.hxx +++ b/src/sfizz/gen/filters/sfzBpf4p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustBpf4p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustBpf4p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustBpf4p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fRec5[2]; double fVec0[2]; @@ -52,63 +60,40 @@ class faustBpf4p : public sfzFilterDsp { double fVec5[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -154,36 +139,37 @@ class faustBpf4p : public sfzFilterDsp { for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) { fRec0[l14] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustBpf4p* clone() { - return new faustBpf4p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); @@ -226,8 +212,24 @@ class faustBpf4p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzBpf6p.hxx b/src/sfizz/gen/filters/sfzBpf6p.hxx index 0888d48b..f595a458 100644 --- a/src/sfizz/gen/filters/sfzBpf6p.hxx +++ b/src/sfizz/gen/filters/sfzBpf6p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustBpf6p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustBpf6p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustBpf6p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fRec7[2]; double fVec0[2]; @@ -57,63 +65,40 @@ class faustBpf6p : public sfzFilterDsp { double fVec8[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -174,36 +159,37 @@ class faustBpf6p : public sfzFilterDsp { for (int l19 = 0; (l19 < 2); l19 = (l19 + 1)) { fRec0[l19] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustBpf6p* clone() { - return new faustBpf6p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); @@ -256,8 +242,24 @@ class faustBpf6p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzBrf1p.hxx b/src/sfizz/gen/filters/sfzBrf1p.hxx index 88eaa643..4630be05 100644 --- a/src/sfizz/gen/filters/sfzBrf1p.hxx +++ b/src/sfizz/gen/filters/sfzBrf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustBrf1p_H__ @@ -11,90 +15,71 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustBrf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustBrf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec2[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (6.2831853071795862 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -104,37 +89,38 @@ class faustBrf1p : public sfzFilterDsp { for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { fRec0[l2] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustBrf1p* clone() { - return new faustBrf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (((fConst1 * double(fCutoff)) + -1.0) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (((fConst2 * double(fHslider0)) + -1.0) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); - fRec2[0] = (fSlow1 + (fSlow0 * fRec2[1])); + fRec2[0] = ((fSlow0 * fRec2[1]) + fSlow1); fRec1[0] = (fTemp0 - (fRec2[0] * fRec1[1])); fRec0[0] = (fRec1[1] + (fRec2[0] * (fRec1[0] - fRec0[1]))); output0[i] = FAUSTFLOAT((fTemp0 + (fRec0[1] + (fRec2[0] * fRec0[0])))); @@ -142,8 +128,21 @@ class faustBrf1p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzBrf2p.hxx b/src/sfizz/gen/filters/sfzBrf2p.hxx index 70838f48..8e0635d1 100644 --- a/src/sfizz/gen/filters/sfzBrf2p.hxx +++ b/src/sfizz/gen/filters/sfzBrf2p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustBrf2p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustBrf2p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustBrf2p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -45,63 +53,40 @@ class faustBrf2p : public sfzFilterDsp { double fVec2[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -126,35 +111,36 @@ class faustBrf2p : public sfzFilterDsp { for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) { fRec0[l7] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustBrf2p* clone() { - return new faustBrf2p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); - double fSlow2 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow2 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = (1.0 - fSlow0); double fSlow5 = (((0.0 - (2.0 * std::cos(fSlow1))) / fSlow3) * fSlow4); @@ -181,8 +167,24 @@ class faustBrf2p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzBrf2pSv.hxx b/src/sfizz/gen/filters/sfzBrf2pSv.hxx index dc10acf0..70ccbdc6 100644 --- a/src/sfizz/gen/filters/sfzBrf2pSv.hxx +++ b/src/sfizz/gen/filters/sfzBrf2pSv.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustBrf2pSv_H__ @@ -11,94 +15,75 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustBrf2pSv #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustBrf2pSv : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; double fRec5[2]; - FAUSTFLOAT fQ; + FAUSTFLOAT fVslider0; double fRec4[2]; double fRec6[2]; double fRec2[2]; double fRec3[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (3.1415926535897931 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec5[l0] = 0.0; } @@ -114,36 +99,37 @@ class faustBrf2pSv : public sfzFilterDsp { for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec3[l4] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustBrf2pSv* clone() { - return new faustBrf2pSv(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fCutoff))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec5[0] = ((fSlow0 * fRec5[1]) + fSlow2); @@ -165,8 +151,24 @@ class faustBrf2pSv : public sfzFilterDsp { fRec2[1] = fRec2[0]; fRec3[1] = fRec3[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzEqHshelf.hxx b/src/sfizz/gen/filters/sfzEqHshelf.hxx index 43d9ac0a..e09cd941 100644 --- a/src/sfizz/gen/filters/sfzEqHshelf.hxx +++ b/src/sfizz/gen/filters/sfzEqHshelf.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustEqHshelf_H__ @@ -11,7 +15,7 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include @@ -21,26 +25,30 @@ static double faustEqHshelf_faustpower2_f(double value) { return (value * value); } -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustEqHshelf #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustEqHshelf : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider0; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fBandwidth; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -51,64 +59,41 @@ class faustEqHshelf : public sfzFilterDsp { double fRec6[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fPkShGain = FAUSTFLOAT(0.0); - fCutoff = FAUSTFLOAT(440.0); - fBandwidth = FAUSTFLOAT(1.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fVslider0 = FAUSTFLOAT(0.0); + fHslider0 = FAUSTFLOAT(440.0); + fVslider1 = FAUSTFLOAT(1.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -139,42 +124,43 @@ class faustEqHshelf : public sfzFilterDsp { for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec0[l9] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustEqHshelf* clone() { - return new faustEqHshelf(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); - double fSlow2 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow3 = std::cos(fSlow2); - double fSlow4 = (fSlow3 * (fSlow1 + 1.0)); + double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = (faustEqHshelf_faustpower2_f(fSlow1) + 1.0); double fSlow6 = (fSlow1 + -1.0); double fSlow7 = faustEqHshelf_faustpower2_f(fSlow6); - double fSlow8 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, (1.0 / std::sqrt((((fSlow1 + (1.0 / fSlow1)) * ((1.0 / std::min(((fSlow5 / fSlow7) + -0.01), std::max(0.01, ((double(fBandwidth) * fSlow5) / fSlow7)))) + -1.0)) + 2.0))))); - double fSlow9 = (fSlow3 * fSlow6); + double fSlow8 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, (1.0 / std::sqrt((((fSlow1 + (1.0 / fSlow1)) * ((1.0 / std::min(((fSlow5 / fSlow7) + -0.01), std::max(0.01, ((double(fVslider1) * fSlow5) / fSlow7)))) + -1.0)) + 2.0))))); + double fSlow9 = (fSlow6 * fSlow3); double fSlow10 = ((fSlow1 + fSlow8) + (1.0 - fSlow9)); double fSlow11 = (1.0 - fSlow0); double fSlow12 = ((((0.0 - (2.0 * fSlow1)) * ((fSlow1 + fSlow4) + -1.0)) / fSlow10) * fSlow11); @@ -207,8 +193,27 @@ class faustEqHshelf : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + FAUSTFLOAT getBandwidth() const { return fVslider1; } + void setBandwidth(FAUSTFLOAT value) { fVslider1 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzEqLshelf.hxx b/src/sfizz/gen/filters/sfzEqLshelf.hxx index 89b93bb9..ac938e6b 100644 --- a/src/sfizz/gen/filters/sfzEqLshelf.hxx +++ b/src/sfizz/gen/filters/sfzEqLshelf.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustEqLshelf_H__ @@ -11,7 +15,7 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include @@ -21,26 +25,30 @@ static double faustEqLshelf_faustpower2_f(double value) { return (value * value); } -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustEqLshelf #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustEqLshelf : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider0; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fBandwidth; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -51,64 +59,41 @@ class faustEqLshelf : public sfzFilterDsp { double fRec6[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fPkShGain = FAUSTFLOAT(0.0); - fCutoff = FAUSTFLOAT(440.0); - fBandwidth = FAUSTFLOAT(1.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fVslider0 = FAUSTFLOAT(0.0); + fHslider0 = FAUSTFLOAT(440.0); + fVslider1 = FAUSTFLOAT(1.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -139,42 +124,43 @@ class faustEqLshelf : public sfzFilterDsp { for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec0[l9] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustEqLshelf* clone() { - return new faustEqLshelf(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); - double fSlow2 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow3 = std::cos(fSlow2); - double fSlow4 = (fSlow3 * (fSlow1 + 1.0)); + double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = (fSlow1 + -1.0); - double fSlow6 = (fSlow3 * fSlow5); + double fSlow6 = (fSlow5 * fSlow3); double fSlow7 = (faustEqLshelf_faustpower2_f(fSlow1) + 1.0); double fSlow8 = faustEqLshelf_faustpower2_f(fSlow5); - double fSlow9 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, (1.0 / std::sqrt((((fSlow1 + (1.0 / fSlow1)) * ((1.0 / std::min(((fSlow7 / fSlow8) + -0.01), std::max(0.01, ((double(fBandwidth) * fSlow7) / fSlow8)))) + -1.0)) + 2.0))))); + double fSlow9 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, (1.0 / std::sqrt((((fSlow1 + (1.0 / fSlow1)) * ((1.0 / std::min(((fSlow7 / fSlow8) + -0.01), std::max(0.01, ((double(fVslider1) * fSlow7) / fSlow8)))) + -1.0)) + 2.0))))); double fSlow10 = (fSlow6 + fSlow9); double fSlow11 = ((fSlow1 + fSlow10) + 1.0); double fSlow12 = (1.0 - fSlow0); @@ -207,8 +193,27 @@ class faustEqLshelf : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + FAUSTFLOAT getBandwidth() const { return fVslider1; } + void setBandwidth(FAUSTFLOAT value) { fVslider1 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzEqPeak.hxx b/src/sfizz/gen/filters/sfzEqPeak.hxx index fb16a2d4..2d6f26e5 100644 --- a/src/sfizz/gen/filters/sfzEqPeak.hxx +++ b/src/sfizz/gen/filters/sfzEqPeak.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustEqPeak_H__ @@ -11,7 +15,7 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif /* link with : "" */ #include @@ -19,27 +23,31 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustEqPeak #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustEqPeak : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fConst3; - FAUSTFLOAT fBandwidth; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -49,65 +57,42 @@ class faustEqPeak : public sfzFilterDsp { double fVec2[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); fConst3 = (2.1775860903036022 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fBandwidth = FAUSTFLOAT(1.0); - fPkShGain = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + fVslider1 = FAUSTFLOAT(1.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -135,43 +120,44 @@ class faustEqPeak : public sfzFilterDsp { for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { fRec0[l8] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustEqPeak* clone() { - return new faustEqPeak(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::max(0.0, double(fCutoff)); + double fSlow1 = std::max(0.0, double(fHslider0)); double fSlow2 = (fConst2 * fSlow1); double fSlow3 = std::sin(fSlow2); - double fSlow4 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * double(fBandwidth)) / fSlow3))))))); - double fSlow5 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); + double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * double(fVslider1)) / fSlow3))))))); double fSlow6 = (0.5 * (fSlow3 / (fSlow4 * fSlow5))); double fSlow7 = (fSlow6 + 1.0); double fSlow8 = (1.0 - fSlow0); double fSlow9 = (((0.0 - (2.0 * std::cos(fSlow2))) / fSlow7) * fSlow8); - double fSlow10 = (0.5 * ((fSlow3 * fSlow5) / fSlow4)); + double fSlow10 = (0.5 * ((fSlow4 * fSlow3) / fSlow5)); double fSlow11 = (((fSlow10 + 1.0) / fSlow7) * fSlow8); double fSlow12 = (((1.0 - fSlow10) / fSlow7) * fSlow8); double fSlow13 = (((1.0 - fSlow6) / fSlow7) * fSlow8); @@ -197,8 +183,27 @@ class faustEqPeak : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + FAUSTFLOAT getBandwidth() const { return fVslider1; } + void setBandwidth(FAUSTFLOAT value) { fVslider1 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzHpf1p.hxx b/src/sfizz/gen/filters/sfzHpf1p.hxx index 4e0cf748..dce88d8d 100644 --- a/src/sfizz/gen/filters/sfzHpf1p.hxx +++ b/src/sfizz/gen/filters/sfzHpf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustHpf1p_H__ @@ -11,134 +15,129 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustHpf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustHpf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (1.0 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (1.0 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec1[l0] = 0.0; } for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { fRec0[l1] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustHpf1p* clone() { - return new faustHpf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (std::exp((fConst1 * (0.0 - (6.2831853071795862 * double(fCutoff))))) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); - fRec1[0] = (fSlow1 + (fSlow0 * fRec1[1])); + fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); fRec0[0] = (fTemp0 + (fRec1[0] * fRec0[1])); double fTemp1 = (fRec1[0] + 1.0); output0[i] = FAUSTFLOAT(((0.5 * (fRec0[0] * fTemp1)) + (fRec0[1] * (0.0 - (0.5 * fTemp1))))); fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzHpf2p.hxx b/src/sfizz/gen/filters/sfzHpf2p.hxx index bfca60e8..3b065b2e 100644 --- a/src/sfizz/gen/filters/sfzHpf2p.hxx +++ b/src/sfizz/gen/filters/sfzHpf2p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustHpf2p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustHpf2p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustHpf2p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -46,63 +54,40 @@ class faustHpf2p : public sfzFilterDsp { double fRec5[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -130,36 +115,37 @@ class faustHpf2p : public sfzFilterDsp { for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { fRec0[l8] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustHpf2p* clone() { - return new faustHpf2p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); @@ -189,8 +175,24 @@ class faustHpf2p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzHpf2pSv.hxx b/src/sfizz/gen/filters/sfzHpf2pSv.hxx index 12fa8259..65e1008f 100644 --- a/src/sfizz/gen/filters/sfzHpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfzHpf2pSv.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustHpf2pSv_H__ @@ -11,94 +15,75 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustHpf2pSv #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustHpf2pSv : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; double fRec4[2]; - FAUSTFLOAT fQ; + FAUSTFLOAT fVslider0; double fRec3[2]; double fRec5[2]; double fRec1[2]; double fRec2[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (3.1415926535897931 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec4[l0] = 0.0; } @@ -114,36 +99,37 @@ class faustHpf2pSv : public sfzFilterDsp { for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec2[l4] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustHpf2pSv* clone() { - return new faustHpf2pSv(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fCutoff))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec4[0] = ((fSlow0 * fRec4[1]) + fSlow2); @@ -164,8 +150,24 @@ class faustHpf2pSv : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec2[1] = fRec2[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzHpf4p.hxx b/src/sfizz/gen/filters/sfzHpf4p.hxx index 6ae2cf55..0a4e8660 100644 --- a/src/sfizz/gen/filters/sfzHpf4p.hxx +++ b/src/sfizz/gen/filters/sfzHpf4p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustHpf4p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustHpf4p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustHpf4p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fVec0[2]; double fRec5[2]; @@ -51,63 +59,40 @@ class faustHpf4p : public sfzFilterDsp { double fVec5[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -150,36 +135,37 @@ class faustHpf4p : public sfzFilterDsp { for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { fRec0[l13] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustHpf4p* clone() { - return new faustHpf4p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); @@ -220,8 +206,24 @@ class faustHpf4p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzHpf6p.hxx b/src/sfizz/gen/filters/sfzHpf6p.hxx index 32a72cd6..8c66173e 100644 --- a/src/sfizz/gen/filters/sfzHpf6p.hxx +++ b/src/sfizz/gen/filters/sfzHpf6p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustHpf6p_H__ @@ -11,32 +15,36 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustHpf6p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustHpf6p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fRec2[2]; double fVec0[2]; double fRec7[2]; @@ -56,63 +64,40 @@ class faustHpf6p : public sfzFilterDsp { double fVec8[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -170,36 +155,37 @@ class faustHpf6p : public sfzFilterDsp { for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) { fRec0[l18] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustHpf6p* clone() { - return new faustHpf6p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); @@ -251,8 +237,24 @@ class faustHpf6p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzHsh.hxx b/src/sfizz/gen/filters/sfzHsh.hxx index 6934d8f5..5570875b 100644 --- a/src/sfizz/gen/filters/sfzHsh.hxx +++ b/src/sfizz/gen/filters/sfzHsh.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustHsh_H__ @@ -11,33 +15,37 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustHsh #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustHsh : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider0; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -48,64 +56,41 @@ class faustHsh : public sfzFilterDsp { double fRec6[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fPkShGain = FAUSTFLOAT(0.0); - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fVslider0 = FAUSTFLOAT(0.0); + fHslider0 = FAUSTFLOAT(440.0); + fVslider1 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -136,46 +121,47 @@ class faustHsh : public sfzFilterDsp { for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec0[l9] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustHsh* clone() { - return new faustHsh(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); - double fSlow2 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow3 = std::cos(fSlow2); - double fSlow4 = (fSlow3 * (fSlow1 + 1.0)); - double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ))))); - double fSlow6 = (fSlow3 * (fSlow1 + -1.0)); + double fSlow4 = ((fSlow1 + 1.0) * fSlow3); + double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider1))))); + double fSlow6 = ((fSlow1 + -1.0) * fSlow3); double fSlow7 = ((fSlow1 + fSlow5) + (1.0 - fSlow6)); double fSlow8 = (1.0 - fSlow0); double fSlow9 = ((((0.0 - (2.0 * fSlow1)) * ((fSlow1 + fSlow4) + -1.0)) / fSlow7) * fSlow8); - double fSlow10 = (fSlow1 + fSlow6); - double fSlow11 = (((fSlow1 * ((fSlow5 + fSlow10) + 1.0)) / fSlow7) * fSlow8); - double fSlow12 = (((fSlow1 * (fSlow10 + (1.0 - fSlow5))) / fSlow7) * fSlow8); - double fSlow13 = (((fSlow1 + (1.0 - (fSlow5 + fSlow6))) / fSlow7) * fSlow8); + double fSlow10 = (fSlow6 + fSlow5); + double fSlow11 = (((fSlow1 * ((fSlow1 + fSlow10) + 1.0)) / fSlow7) * fSlow8); + double fSlow12 = (((fSlow1 * ((fSlow1 + fSlow6) + (1.0 - fSlow5))) / fSlow7) * fSlow8); + double fSlow13 = (((fSlow1 + (1.0 - fSlow10)) / fSlow7) * fSlow8); double fSlow14 = ((2.0 * ((fSlow1 + (-1.0 - fSlow4)) / fSlow7)) * fSlow8); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); @@ -201,8 +187,27 @@ class faustHsh : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider1; } + void setResonance(FAUSTFLOAT value) { fVslider1 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzLpf1p.hxx b/src/sfizz/gen/filters/sfzLpf1p.hxx index fb9093cc..bbec0a8a 100644 --- a/src/sfizz/gen/filters/sfzLpf1p.hxx +++ b/src/sfizz/gen/filters/sfzLpf1p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustLpf1p_H__ @@ -11,133 +15,128 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustLpf1p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustLpf1p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; double fConst2; + FAUSTFLOAT fHslider0; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); - fConst1 = (1.0 / fConst0); - fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + fConst0 = double(fSampleRate); + fConst1 = std::exp((0.0 - (1000.0 / fConst0))); + fConst2 = (1.0 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec1[l0] = 0.0; } for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { fRec0[l1] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustLpf1p* clone() { - return new faustLpf1p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fSmoothEnable ? fConst2 : 0.0); - double fSlow1 = (std::exp((fConst1 * (0.0 - (6.2831853071795862 * double(fCutoff))))) * (1.0 - fSlow0)); + double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); - fRec1[0] = (fSlow1 + (fSlow0 * fRec1[1])); + fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); fRec0[0] = (fTemp0 + (fRec1[0] * fRec0[1])); output0[i] = FAUSTFLOAT((fRec0[0] * (1.0 - fRec1[0]))); fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzLpf2p.hxx b/src/sfizz/gen/filters/sfzLpf2p.hxx index 7f2044a2..105fd66f 100644 --- a/src/sfizz/gen/filters/sfzLpf2p.hxx +++ b/src/sfizz/gen/filters/sfzLpf2p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustLpf2p_H__ @@ -11,31 +15,35 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustLpf2p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustLpf2p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fConst2; double fRec2[2]; double fVec0[2]; @@ -46,63 +54,40 @@ class faustLpf2p : public sfzFilterDsp { double fRec5[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = (6.2831853071795862 / fConst0); fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -130,35 +115,36 @@ class faustLpf2p : public sfzFilterDsp { for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { fRec0[l8] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustLpf2p* clone() { - return new faustLpf2p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fConst1 * std::max(0.0, double(fCutoff))); + double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); @@ -190,8 +176,24 @@ class faustLpf2p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzLpf2pSv.hxx b/src/sfizz/gen/filters/sfzLpf2pSv.hxx index d70bcafc..a1af4a96 100644 --- a/src/sfizz/gen/filters/sfzLpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfzLpf2pSv.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustLpf2pSv_H__ @@ -11,94 +15,75 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustLpf2pSv #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustLpf2pSv : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; + FAUSTFLOAT fHslider0; double fRec3[2]; - FAUSTFLOAT fQ; + FAUSTFLOAT fVslider0; double fRec4[2]; double fRec5[2]; double fRec1[2]; double fRec2[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (3.1415926535897931 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec3[l0] = 0.0; } @@ -114,36 +99,37 @@ class faustLpf2pSv : public sfzFilterDsp { for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { fRec2[l4] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustLpf2pSv* clone() { - return new faustLpf2pSv(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fCutoff))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fQ)))); + double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec3[0] = ((fSlow0 * fRec3[1]) + fSlow2); @@ -164,8 +150,24 @@ class faustLpf2pSv : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec2[1] = fRec2[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzLpf4p.hxx b/src/sfizz/gen/filters/sfzLpf4p.hxx index 087bac79..f7fe60f9 100644 --- a/src/sfizz/gen/filters/sfzLpf4p.hxx +++ b/src/sfizz/gen/filters/sfzLpf4p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustLpf4p_H__ @@ -11,31 +15,35 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustLpf4p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustLpf4p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fConst2; double fRec2[2]; double fVec0[2]; @@ -51,63 +59,40 @@ class faustLpf4p : public sfzFilterDsp { double fVec5[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = (6.2831853071795862 / fConst0); fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -150,35 +135,36 @@ class faustLpf4p : public sfzFilterDsp { for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) { fRec0[l13] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustLpf4p* clone() { - return new faustLpf4p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fConst1 * std::max(0.0, double(fCutoff))); + double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); @@ -221,8 +207,24 @@ class faustLpf4p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzLpf6p.hxx b/src/sfizz/gen/filters/sfzLpf6p.hxx index a0c1dd24..263f1683 100644 --- a/src/sfizz/gen/filters/sfzLpf6p.hxx +++ b/src/sfizz/gen/filters/sfzLpf6p.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustLpf6p_H__ @@ -11,31 +15,35 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustLpf6p #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustLpf6p : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; double fConst2; double fRec2[2]; double fVec0[2]; @@ -56,63 +64,40 @@ class faustLpf6p : public sfzFilterDsp { double fVec8[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = (6.2831853071795862 / fConst0); fConst2 = std::exp((0.0 - (1000.0 / fConst0))); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -170,35 +155,36 @@ class faustLpf6p : public sfzFilterDsp { for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) { fRec0[l18] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustLpf6p* clone() { - return new faustLpf6p(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fConst1 * std::max(0.0, double(fCutoff))); + double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); @@ -252,8 +238,24 @@ class faustLpf6p : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzLsh.hxx b/src/sfizz/gen/filters/sfzLsh.hxx index 8ff05ae5..55d27bbc 100644 --- a/src/sfizz/gen/filters/sfzLsh.hxx +++ b/src/sfizz/gen/filters/sfzLsh.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustLsh_H__ @@ -11,33 +15,37 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustLsh #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustLsh : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fVslider0; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -48,64 +56,41 @@ class faustLsh : public sfzFilterDsp { double fRec6[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fPkShGain = FAUSTFLOAT(0.0); - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fVslider0 = FAUSTFLOAT(0.0); + fHslider0 = FAUSTFLOAT(440.0); + fVslider1 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -136,46 +121,47 @@ class faustLsh : public sfzFilterDsp { for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) { fRec0[l9] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustLsh* clone() { - return new faustLsh(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); - double fSlow2 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); + double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow3 = std::cos(fSlow2); - double fSlow4 = (fSlow3 * (fSlow1 + 1.0)); - double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ))))); - double fSlow6 = (fSlow3 * (fSlow1 + -1.0)); - double fSlow7 = (fSlow1 + fSlow6); - double fSlow8 = ((fSlow5 + fSlow7) + 1.0); + double fSlow4 = ((fSlow1 + 1.0) * fSlow3); + double fSlow5 = ((fSlow1 + -1.0) * fSlow3); + double fSlow6 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider1))))); + double fSlow7 = (fSlow5 + fSlow6); + double fSlow8 = ((fSlow1 + fSlow7) + 1.0); double fSlow9 = (1.0 - fSlow0); double fSlow10 = ((2.0 * ((fSlow1 * (fSlow1 + (-1.0 - fSlow4))) / fSlow8)) * fSlow9); - double fSlow11 = (((fSlow1 * ((fSlow1 + fSlow5) + (1.0 - fSlow6))) / fSlow8) * fSlow9); - double fSlow12 = (((fSlow1 * (fSlow1 + (1.0 - (fSlow5 + fSlow6)))) / fSlow8) * fSlow9); - double fSlow13 = (((fSlow7 + (1.0 - fSlow5)) / fSlow8) * fSlow9); + double fSlow11 = (((fSlow1 * ((fSlow1 + fSlow6) + (1.0 - fSlow5))) / fSlow8) * fSlow9); + double fSlow12 = (((fSlow1 * (fSlow1 + (1.0 - fSlow7))) / fSlow8) * fSlow9); + double fSlow13 = ((((fSlow1 + fSlow5) + (1.0 - fSlow6)) / fSlow8) * fSlow9); double fSlow14 = (((0.0 - (2.0 * ((fSlow1 + fSlow4) + -1.0))) / fSlow8) * fSlow9); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); @@ -201,8 +187,27 @@ class faustLsh : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider1; } + void setResonance(FAUSTFLOAT value) { fVslider1 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider0; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider0 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzPeq.hxx b/src/sfizz/gen/filters/sfzPeq.hxx index 0603c45f..a0e6eee5 100644 --- a/src/sfizz/gen/filters/sfzPeq.hxx +++ b/src/sfizz/gen/filters/sfzPeq.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustPeq_H__ @@ -11,33 +15,37 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustPeq #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustPeq : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + int fSampleRate; double fConst0; double fConst1; double fConst2; - FAUSTFLOAT fCutoff; - FAUSTFLOAT fQ; - FAUSTFLOAT fPkShGain; + FAUSTFLOAT fHslider0; + FAUSTFLOAT fVslider0; + FAUSTFLOAT fVslider1; double fRec2[2]; double fVec0[2]; double fRec3[2]; @@ -47,64 +55,41 @@ class faustPeq : public sfzFilterDsp { double fVec2[2]; double fRec1[2]; double fRec0[2]; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; - fConst0 = std::min(192000.0, std::max(1.0, double(fSampleRate))); + fConst0 = double(fSampleRate); fConst1 = std::exp((0.0 - (1000.0 / fConst0))); fConst2 = (6.2831853071795862 / fConst0); + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { - fCutoff = FAUSTFLOAT(440.0); - fQ = FAUSTFLOAT(0.0); - fPkShGain = FAUSTFLOAT(0.0); + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + fHslider0 = FAUSTFLOAT(440.0); + fVslider0 = FAUSTFLOAT(0.0); + fVslider1 = FAUSTFLOAT(0.0); + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { fRec2[l0] = 0.0; } @@ -132,42 +117,43 @@ class faustPeq : public sfzFilterDsp { for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) { fRec0[l8] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustPeq* clone() { - return new faustPeq(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fCutoff))); + double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fQ)))); - double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fPkShGain))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider1))); double fSlow5 = (0.5 * (fSlow2 / (fSlow3 * fSlow4))); double fSlow6 = (fSlow5 + 1.0); double fSlow7 = (1.0 - fSlow0); double fSlow8 = (((0.0 - (2.0 * std::cos(fSlow1))) / fSlow6) * fSlow7); - double fSlow9 = (0.5 * ((fSlow2 * fSlow4) / fSlow3)); + double fSlow9 = (0.5 * ((fSlow4 * fSlow2) / fSlow3)); double fSlow10 = (((fSlow9 + 1.0) / fSlow6) * fSlow7); double fSlow11 = (((1.0 - fSlow9) / fSlow6) * fSlow7); double fSlow12 = (((1.0 - fSlow5) / fSlow6) * fSlow7); @@ -193,8 +179,27 @@ class faustPeq : public sfzFilterDsp { fRec1[1] = fRec1[0]; fRec0[1] = fRec0[0]; } + //[End:compute] } + + FAUSTFLOAT getCutoff() const { return fHslider0; } + void setCutoff(FAUSTFLOAT value) { fHslider0 = value; } + + FAUSTFLOAT getResonance() const { return fVslider0; } + void setResonance(FAUSTFLOAT value) { fVslider0 = value; } + + FAUSTFLOAT getPeakShelfGain() const { return fVslider1; } + void setPeakShelfGain(FAUSTFLOAT value) { fVslider1 = value; } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS diff --git a/src/sfizz/gen/filters/sfzPink.hxx b/src/sfizz/gen/filters/sfzPink.hxx index 31b1f1c5..58205df2 100644 --- a/src/sfizz/gen/filters/sfzPink.hxx +++ b/src/sfizz/gen/filters/sfzPink.hxx @@ -1,9 +1,13 @@ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif /* ------------------------------------------------------------ author: "Jean Pierre Cimalando" license: "BSD-2-Clause" name: "sfz_filters" -Code generated with Faust 2.20.2 (https://faust.grame.fr) -Compilation options: -lang cpp -inpl -double -ftz 0 +Code generated with Faust 2.30.5 (https://faust.grame.fr) +Compilation options: -lang cpp -inpl -es 1 -double -ftz 0 ------------------------------------------------------------ */ #ifndef __faustPink_H__ @@ -11,107 +15,89 @@ Compilation options: -lang cpp -inpl -double -ftz 0 #ifndef FAUSTFLOAT #define FAUSTFLOAT float -#endif +#endif #include #include -#ifndef FAUSTCLASS +#ifndef FAUSTCLASS #define FAUSTCLASS faustPink #endif -#ifdef __APPLE__ +#ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif + +//[Before:class] class faustPink : public sfzFilterDsp { + //[Begin:class] - public: - + + private: + double fRec0[4]; int fSampleRate; - + public: + - void metadata(Meta* m) { - } - - virtual int getNumInputs() { + static constexpr int getNumInputs() { return 1; } - virtual int getNumOutputs() { + static constexpr int getNumOutputs() { return 1; } - virtual int getInputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - virtual int getOutputRate(int channel) { - int rate; - switch ((channel)) { - case 0: { - rate = 1; - break; - } - default: { - rate = -1; - break; - } - } - return rate; - } - + static void classInit(int sample_rate) { + //[Begin:classInit] + //[End:classInit] } - - virtual void instanceConstants(int sample_rate) { + + void instanceConstants(int sample_rate) { + //[Begin:instanceConstants] fSampleRate = sample_rate; + //[End:instanceConstants] } - - virtual void instanceResetUserInterface() { + + void instanceResetUserInterface() { + //[Begin:instanceResetUserInterface] + //[End:instanceResetUserInterface] } - - virtual void instanceClear() { + + void instanceClear() { + //[Begin:instanceClear] for (int l0 = 0; (l0 < 4); l0 = (l0 + 1)) { fRec0[l0] = 0.0; } + //[End:instanceClear] } - - virtual void init(int sample_rate) { + + void init(int sample_rate) { + //[Begin:init] classInit(sample_rate); instanceInit(sample_rate); + //[End:init] } - virtual void instanceInit(int sample_rate) { + void instanceInit(int sample_rate) { + //[Begin:instanceInit] instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); + //[End:instanceInit] } - - virtual faustPink* clone() { - return new faustPink(); - } - - virtual int getSampleRate() { + + + int getSampleRate() { return fSampleRate; } - - virtual void buildUserInterface(UI* ui_interface) { - } - - virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { - FAUSTFLOAT* input0 = inputs[0]; + + + void compute(int count, FAUSTFLOAT const* const* inputs, FAUSTFLOAT* const* outputs) { + //[Begin:compute] + FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); @@ -121,8 +107,18 @@ class faustPink : public sfzFilterDsp { fRec0[j0] = fRec0[(j0 - 1)]; } } + //[End:compute] } + + //[End:class] }; +//[After:class] + #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#undef FAUSTFLOAT +#undef FAUSTCLASS From dc16470dda8d0738a6f57678e7f579fa3a3ee5c3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 01:24:10 +0100 Subject: [PATCH 330/668] Fix fverb parameters corrupted in opcode spec work --- src/sfizz/Defaults.cpp | 1 + src/sfizz/Defaults.h | 1 + src/sfizz/effects/Fverb.cpp | 12 ++++++------ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 7a53d54d..792983ff 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -131,6 +131,7 @@ extern const OpcodeSpec sampleQuality { 1, Range(1, 10), 0 }; extern const OpcodeSpec octaveOffset { 0, Range(-10, 10), 0 }; extern const OpcodeSpec noteOffset { 0, Range(-127, 127), 0 }; extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec effectPercent { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec apanWaveform { 0, Range(0, std::numeric_limits::max()), 0 }; extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), 0 }; extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), kWrapPhase }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 289b8d7d..f778e09e 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -250,6 +250,7 @@ namespace Default extern const OpcodeSpec octaveOffset; extern const OpcodeSpec noteOffset; extern const OpcodeSpec effect; + extern const OpcodeSpec effectPercent; extern const OpcodeSpec apanWaveform; extern const OpcodeSpec apanFrequency; extern const OpcodeSpec apanPhase; diff --git a/src/sfizz/effects/Fverb.cpp b/src/sfizz/effects/Fverb.cpp index 804e12a3..5d0bb14f 100644 --- a/src/sfizz/effects/Fverb.cpp +++ b/src/sfizz/effects/Fverb.cpp @@ -173,9 +173,9 @@ namespace fx { std::unique_ptr fx { reverb }; const Impl::Profile* profile = &Impl::largeHall; - float dry { Default::effect }; - float wet { Default::effect }; - float input { Default::effect }; + float dry { Default::effectPercent }; + float wet { Default::effectPercent }; + float input { Default::effectPercent }; float size { Default::fverbSize }; float predelay { Default::fverbPredelay }; float tone { Default::fverbTone }; @@ -205,13 +205,13 @@ namespace fx { break; case hash("reverb_dry"): - dry = opc.read(Default::effect); + dry = opc.read(Default::effectPercent); break; case hash("reverb_wet"): - wet = opc.read(Default::effect); + wet = opc.read(Default::effectPercent); break; case hash("reverb_input"): - input = opc.read(Default::effect); + input = opc.read(Default::effectPercent); break; case hash("reverb_size"): size = opc.read(Default::fverbSize); From 81f54f98f2555078b12deee46f6bd5eae3fa8bb5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 01:26:12 +0100 Subject: [PATCH 331/668] Fix strings parameters corrupted in opcode spec work --- src/sfizz/effects/Strings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index 2ef50f7c..070496ec 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -116,7 +116,7 @@ namespace fx { auto outputR = absl::MakeSpan(outputs[1], nframes); absl::Span wet = _tempBuffer.getSpan(2).first(nframes); - sfz::fill(wet, 0.01f *_wet); // TOD strings_wet_oncc modulation... + sfz::fill(wet, _wet); // TOD strings_wet_oncc modulation... sfz::copy(inputL, outputL); sfz::copy(inputR, outputR); From 988d7926b533b8c839e14aecf8f2c4ff54d7cbd1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 01:48:18 +0100 Subject: [PATCH 332/668] Clear the disto after Fs change --- src/sfizz/effects/Disto.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sfizz/effects/Disto.cpp b/src/sfizz/effects/Disto.cpp index 05ba158c..13eeaa52 100644 --- a/src/sfizz/effects/Disto.cpp +++ b/src/sfizz/effects/Disto.cpp @@ -83,6 +83,8 @@ void Disto::setSampleRate(double sampleRate) stage.instanceConstants(_oversampling * sampleRate); } } + + clear(); } void Disto::setSamplesPerBlock(int samplesPerBlock) From c6c53a41e57a495e126bb3de999f5ec006c6e121 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 02:06:56 +0100 Subject: [PATCH 333/668] Adjust disto DC cutoff to account for oversampling --- src/sfizz/effects/dsp/disto_stage.dsp | 2 +- src/sfizz/effects/gen/disto_stage.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sfizz/effects/dsp/disto_stage.dsp b/src/sfizz/effects/dsp/disto_stage.dsp index f2494745..ec4a8383 100644 --- a/src/sfizz/effects/dsp/disto_stage.dsp +++ b/src/sfizz/effects/dsp/disto_stage.dsp @@ -1,6 +1,6 @@ import("stdfaust.lib"); -disto_stage(depth, x) = shs*hh(x)+(1.0-shs)*lh(x) : fi.dcblockerat(5.0) with { +disto_stage(depth, x) = shs*hh(x)+(1.0-shs)*lh(x) : fi.dcblockerat(40.0) with { // sigmoid parameters a = depth*0.2+2.0; b = 2.0; diff --git a/src/sfizz/effects/gen/disto_stage.hxx b/src/sfizz/effects/gen/disto_stage.hxx index 1c16e2fb..ee112e87 100644 --- a/src/sfizz/effects/gen/disto_stage.hxx +++ b/src/sfizz/effects/gen/disto_stage.hxx @@ -134,7 +134,7 @@ class faustDisto { //[Begin:instanceConstants] fSampleRate = sample_rate; fConst0 = float(fSampleRate); - fConst1 = (15.707963f / fConst0); + fConst1 = (125.663704f / fConst0); fConst2 = (1.0f / (fConst1 + 1.0f)); fConst3 = (1.0f - fConst1); fConst4 = std::exp((0.0f - (100.0f / fConst0))); From 9f78edf533071c5c8d162506189c8fc26736121a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 06:22:22 +0100 Subject: [PATCH 334/668] Delayed launch of "new file" dialog --- plugins/editor/src/editor/Editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 9dad19ba..e8fb16c3 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -1460,7 +1460,7 @@ void Editor::Impl::valueChanged(CControl* ctl) if (value != 1) break; - createNewSfzFile(); + Call::later([this]() { createNewSfzFile(); }); break; case kTagOpenSfzFolder: From ddefffea0e3b8d8f327e5fab75169a8f7aabaddb Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 08:59:13 +0100 Subject: [PATCH 335/668] Prevent window input while file dialog is open --- plugins/editor/CMakeLists.txt | 2 + plugins/editor/src/editor/Editor.cpp | 30 ++++++++++++-- plugins/editor/src/editor/GUIHelpers.cpp | 53 ++++++++++++++++++++++++ plugins/editor/src/editor/GUIHelpers.h | 30 ++++++++++++++ 4 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 plugins/editor/src/editor/GUIHelpers.cpp create mode 100644 plugins/editor/src/editor/GUIHelpers.h diff --git a/plugins/editor/CMakeLists.txt b/plugins/editor/CMakeLists.txt index d2153d32..f7c8904e 100644 --- a/plugins/editor/CMakeLists.txt +++ b/plugins/editor/CMakeLists.txt @@ -34,6 +34,8 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/EditorController.h src/editor/GUIComponents.h src/editor/GUIComponents.cpp + src/editor/GUIHelpers.h + src/editor/GUIHelpers.cpp src/editor/GUIPiano.h src/editor/GUIPiano.cpp src/editor/ColorHelpers.h diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index e8fb16c3..72013cca 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -8,6 +8,7 @@ #include "EditorController.h" #include "EditIds.h" #include "GUIComponents.h" +#include "GUIHelpers.h" #include "GUIPiano.h" #include "NativeHelpers.h" #include "BitArray.h" @@ -40,6 +41,7 @@ const int Editor::viewHeight { 475 }; struct Editor::Impl : EditorController::Receiver, IControlListener { EditorController* ctrl_ = nullptr; CFrame* frame_ = nullptr; + SharedPointer frameDisabler_; SharedPointer mainView_; std::string currentSfzFile_; @@ -227,6 +229,8 @@ void Editor::open(CFrame& frame) impl.frame_ = &frame; frame.addView(impl.mainView_.get()); + impl.frameDisabler_ = makeOwned(&frame); + impl.memQueryTimer_ = makeOwned([this](CVSTGUITimer*) { impl_->sendQueuedOSC("/mem/buffers", "", nullptr); }, 1000, true); @@ -245,6 +249,8 @@ void Editor::close() impl.memQueryTimer_ = nullptr; + impl.frameDisabler_ = nullptr; + if (impl.frame_) { impl.frame_->removeView(impl.mainView_.get(), false); impl.frame_ = nullptr; @@ -966,7 +972,11 @@ void Editor::Impl::chooseSfzFile() if (!initialDir.empty()) fs->setInitialDirectory(initialDir.c_str()); - if (fs->runModal()) { + frameDisabler_->disable(); + bool runOk = fs->runModal(); + frameDisabler_->enable(); + + if (runOk) { UTF8StringPtr file = fs->getSelectedFile(0); if (file) changeSfzFile(file); @@ -996,7 +1006,11 @@ void Editor::Impl::createNewSfzFile() if (!initialDir.empty()) fs->setInitialDirectory(initialDir.c_str()); - if (fs->runModal()) { + frameDisabler_->disable(); + bool runOk = fs->runModal(); + frameDisabler_->enable(); + + if (runOk) { UTF8StringPtr file = fs->getSelectedFile(0); std::string fileStr; if (file && !absl::EndsWithIgnoreCase(file, ".sfz")) { @@ -1084,7 +1098,11 @@ void Editor::Impl::chooseScalaFile() if (!initialDir.empty()) fs->setInitialDirectory(initialDir.c_str()); - if (fs->runModal()) { + frameDisabler_->disable(); + bool runOk = fs->runModal(); + frameDisabler_->enable(); + + if (runOk) { UTF8StringPtr file = fs->getSelectedFile(0); if (file) changeScalaFile(file); @@ -1105,7 +1123,11 @@ void Editor::Impl::chooseUserFilesDir() fs->setTitle("Set user files directory"); - if (fs->runModal()) { + frameDisabler_->disable(); + bool runOk = fs->runModal(); + frameDisabler_->enable(); + + if (runOk) { UTF8StringPtr dir = fs->getSelectedFile(0); if (dir) { userFilesDir_ = std::string(dir); diff --git a/plugins/editor/src/editor/GUIHelpers.cpp b/plugins/editor/src/editor/GUIHelpers.cpp new file mode 100644 index 00000000..b5da7443 --- /dev/null +++ b/plugins/editor/src/editor/GUIHelpers.cpp @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "GUIHelpers.h" + +class SFrameDisabler::KeyAndMouseHook : public CBaseObject, + public IKeyboardHook, + public IMouseObserver { +public: + void setEnabled(bool value) { enabled_ = value; } + +protected: + int32_t onKeyDown(const VstKeyCode&, CFrame*) { return enabled_ ? -1 : 1; } + int32_t onKeyUp(const VstKeyCode&, CFrame*) { return enabled_ ? -1 : 1; } + void onMouseEntered(CView*, CFrame*) {} + void onMouseExited(CView*, CFrame*) {} + CMouseEventResult onMouseMoved(CFrame*, const CPoint&, const CButtonState&) { return enabled_ ? kMouseEventNotHandled : kMouseEventHandled; } + CMouseEventResult onMouseDown(CFrame*, const CPoint&, const CButtonState&) { return enabled_ ? kMouseEventNotHandled : kMouseEventHandled; } + +private: + bool enabled_ = true; +}; + +SFrameDisabler::SFrameDisabler(CFrame* frame) + : frame_(frame), hook_(makeOwned()) +{ + frame->registerKeyboardHook(hook_); + frame->registerMouseObserver(hook_); + + delayedEnabler_ = makeOwned( + [this](CVSTGUITimer* t) { hook_->setEnabled(true); t->stop(); }, + 1, false); +} + +SFrameDisabler::~SFrameDisabler() +{ + frame_->unregisterKeyboardHook(hook_); + frame_->unregisterMouseObserver(hook_); +} + +void SFrameDisabler::enable() +{ + delayedEnabler_->start(); +} + +void SFrameDisabler::disable() +{ + hook_->setEnabled(false); + delayedEnabler_->stop(); +} diff --git a/plugins/editor/src/editor/GUIHelpers.h b/plugins/editor/src/editor/GUIHelpers.h new file mode 100644 index 00000000..86f43df7 --- /dev/null +++ b/plugins/editor/src/editor/GUIHelpers.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "utility/vstgui_before.h" +#include +#include +#include "utility/vstgui_after.h" + +using namespace VSTGUI; + +class SFrameDisabler : public CBaseObject { +public: + explicit SFrameDisabler(CFrame* frame); + ~SFrameDisabler(); + + void enable(); + void disable(); + +private: + class KeyAndMouseHook; + +private: + CFrame* frame_ = nullptr; + SharedPointer hook_; + SharedPointer delayedEnabler_; +}; From 291aa3d16b43475ba416008b2037d6a9b0980ad3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 09:22:24 +0100 Subject: [PATCH 336/668] Rename keyswitch things for disambiguation --- plugins/editor/src/editor/Editor.cpp | 8 ++++---- src/sfizz/Synth.cpp | 6 +++--- src/sfizz/SynthMessaging.cpp | 4 ++-- src/sfizz/SynthPrivate.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 72013cca..cceefe7a 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -237,7 +237,7 @@ void Editor::open(CFrame& frame) // request the whole Key and CC information impl.sendQueuedOSC("/key/slots", "", nullptr); - impl.sendQueuedOSC("/sw/slots", "", nullptr); + impl.sendQueuedOSC("/sw/last/slots", "", nullptr); impl.sendQueuedOSC("/cc/slots", "", nullptr); } @@ -268,7 +268,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) // request the whole Key and CC information sendQueuedOSC("/key/slots", "", nullptr); - sendQueuedOSC("/sw/slots", "", nullptr); + sendQueuedOSC("/sw/last/slots", "", nullptr); sendQueuedOSC("/cc/slots", "", nullptr); } break; @@ -430,7 +430,7 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi updateKeyUsed(key, used); } } - else if (Messages::matchOSC("/sw/slots", path, indices) && !strcmp(sig, "b")) { + else if (Messages::matchOSC("/sw/last/slots", path, indices) && !strcmp(sig, "b")) { size_t numBits = 8 * args[0].b->size; ConstBitSpan bits { args[0].b->data, numBits }; for (unsigned key = 0; key < 128; ++key) { @@ -1033,7 +1033,7 @@ void Editor::Impl::changeSfzFile(const std::string& filePath) // request the whole Key and CC information sendQueuedOSC("/key/slots", "", nullptr); - sendQueuedOSC("/sw/slots", "", nullptr); + sendQueuedOSC("/sw/last/slots", "", nullptr); sendQueuedOSC("/cc/slots", "", nullptr); } diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 5edb5e1e..3ca0beab 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -250,7 +250,7 @@ void Synth::Impl::clear() changedCCsThisCycle_.clear(); keyLabels_.clear(); keySlots_.clear(); - swSlots_.clear(); + swLastSlots_.clear(); keyswitchLabels_.clear(); globalOpcodes_.clear(); masterOpcodes_.clear(); @@ -749,13 +749,13 @@ void Synth::Impl::finalizeSfzLoad() // cache the set of keyswitches assigned for (const RegionPtr& regionPtr : regions_) { if (absl::optional sw = regionPtr->lastKeyswitch) { - swSlots_.set(*sw); + swLastSlots_.set(*sw); } else if (absl::optional> swRange = regionPtr->lastKeyswitchRange) { unsigned loKey = swRange->getStart(); unsigned hiKey = swRange->getEnd(); for (unsigned key = loKey; key <= hiKey; ++key) - swSlots_.set(key); + swLastSlots_.set(key); } } } diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index f8451d4f..6dd2d9eb 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -46,8 +46,8 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co //---------------------------------------------------------------------- - MATCH("/sw/slots", "") { - const BitArray<128>& switches = impl.swSlots_; + MATCH("/sw/last/slots", "") { + const BitArray<128>& switches = impl.swLastSlots_; sfizz_blob_t blob { switches.data(), static_cast(switches.byte_size()) }; client.receive<'b'>(delay, path, &blob); } break; diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 5c8b4479..da41a89f 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -217,7 +217,7 @@ struct Synth::Impl final: public Parser::Listener { std::map ccLabelsMap_; std::vector keyLabels_; BitArray<128> keySlots_; - BitArray<128> swSlots_; + BitArray<128> swLastSlots_; std::vector keyswitchLabels_; // Set as sw_default if present in the file From 49fa74628664bca5cf7818dbdfa3ce51f0f02ba4 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 09:50:17 +0100 Subject: [PATCH 337/668] Keyswitch label and value messaging --- src/sfizz/Synth.cpp | 44 +++++++++++++++++++++++++++++++++--- src/sfizz/SynthMessaging.cpp | 14 ++++++++++++ src/sfizz/SynthPrivate.h | 5 ++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 3ca0beab..f292875d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -241,6 +241,7 @@ void Synth::Impl::clear() numGroups_ = 0; numMasters_ = 0; currentSwitch_ = absl::nullopt; + currentSwitchChanged_ = true; defaultPath_ = ""; resources_.midiState.reset(); resources_.filePool.clear(); @@ -251,7 +252,7 @@ void Synth::Impl::clear() keyLabels_.clear(); keySlots_.clear(); swLastSlots_.clear(); - keyswitchLabels_.clear(); + clearKeyswitchLabels(); globalOpcodes_.clear(); masterOpcodes_.clear(); groupOpcodes_.clear(); @@ -623,7 +624,7 @@ void Synth::Impl::finalizeSfzLoad() region->keySwitched = (*currentSwitch_ == *region->lastKeyswitch); if (region->keyswitchLabel) - insertPairUniquely(keyswitchLabels_, *region->lastKeyswitch, *region->keyswitchLabel); + setKeyswitchLabel(*region->lastKeyswitch, *region->keyswitchLabel); } if (region->lastKeyswitchRange) { @@ -633,7 +634,7 @@ void Synth::Impl::finalizeSfzLoad() if (region->keyswitchLabel) { for (uint8_t note = range.getStart(), end = range.getEnd(); note <= end; note++) - insertPairUniquely(keyswitchLabels_, note, *region->keyswitchLabel); + setKeyswitchLabel(note, *region->keyswitchLabel); } } @@ -758,6 +759,8 @@ void Synth::Impl::finalizeSfzLoad() swLastSlots_.set(key); } } + // resend current keyswitch + currentSwitchChanged_ = true; } bool Synth::loadScalaFile(const fs::path& path) @@ -985,6 +988,16 @@ void Synth::renderBlock(AudioSpan buffer) noexcept broadcaster.receive<'b'>(numFrames - 1, "/cc/changed", &blob); } impl.changedCCsThisCycle_.clear(); + // Send the changed keyswitch + if (impl.currentSwitchChanged_) { + if (broadcaster.canReceive()) { + int32_t value = -1; + if (impl.currentSwitch_) + value = *impl.currentSwitch_; + broadcaster.receive<'i'>(numFrames - 1, "/sw/last/current", value); + } + impl.currentSwitchChanged_ = false; + } { // Clear events and advance midi time ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; @@ -1081,6 +1094,7 @@ void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noex region->keySwitched = false; } currentSwitch_ = noteNumber; + currentSwitchChanged_ = true; } for (auto& region : lastKeyswitchLists_[noteNumber]) @@ -1869,12 +1883,36 @@ void Synth::Impl::setCCLabel(int ccNumber, std::string name) } } +const std::string* Synth::Impl::getKeyswitchLabel(int swNumber) +{ + auto it = keyswitchLabelsMap_.find(swNumber); + return (it == keyswitchLabelsMap_.end()) ? nullptr : &keyswitchLabels_[it->second].second; +} + +void Synth::Impl::setKeyswitchLabel(int swNumber, std::string name) +{ + auto it = keyswitchLabelsMap_.find(swNumber); + if (it != keyswitchLabelsMap_.end()) + keyswitchLabels_[it->second].second = std::move(name); + else { + size_t index = keyswitchLabels_.size(); + keyswitchLabels_.emplace_back(swNumber, std::move(name)); + keyswitchLabelsMap_[swNumber] = index; + } +} + void Synth::Impl::clearCCLabels() { ccLabels_.clear(); ccLabelsMap_.clear(); } +void Synth::Impl::clearKeyswitchLabels() +{ + keyswitchLabels_.clear(); + keyswitchLabelsMap_.clear(); +} + Parser& Synth::getParser() noexcept { Impl& impl = *impl_; diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 6dd2d9eb..67407e3c 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -52,6 +52,20 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'b'>(delay, path, &blob); } break; + MATCH("/sw/last/current", "") { + int32_t value = -1; + if (impl.currentSwitch_) + value = *impl.currentSwitch_; + client.receive<'i'>(delay, path, value); + } break; + + MATCH("/sw/last/&/label", "") { + if (indices[0] >= 128) + break; + const std::string* label = impl.getKeyswitchLabel(indices[0]); + client.receive<'s'>(delay, path, label ? label->c_str() : ""); + } break; + //---------------------------------------------------------------------- MATCH("/cc/slots", "") { diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index da41a89f..bb69fdc7 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -184,6 +184,9 @@ struct Synth::Impl final: public Parser::Listener { const std::string* getCCLabel(int ccNumber); void setCCLabel(int ccNumber, std::string name); void clearCCLabels(); + const std::string* getKeyswitchLabel(int swNumber); + void setKeyswitchLabel(int swNumber, std::string name); + void clearKeyswitchLabels(); /** * @brief Perform a CC event @@ -219,9 +222,11 @@ struct Synth::Impl final: public Parser::Listener { BitArray<128> keySlots_; BitArray<128> swLastSlots_; std::vector keyswitchLabels_; + std::map keyswitchLabelsMap_; // Set as sw_default if present in the file absl::optional currentSwitch_; + bool currentSwitchChanged_ = true; std::vector unknownOpcodes_; using RegionViewVector = std::vector; using VoiceViewVector = std::vector; From a39e1f8e2e869a4e86cdf46d17aff10271f90c95 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 25 Feb 2021 10:09:22 +0100 Subject: [PATCH 338/668] Keyswitch name display --- plugins/editor/layout/main.fl | 8 +-- plugins/editor/src/editor/Editor.cpp | 63 +++++++++++++++++++++++ plugins/editor/src/editor/layout/main.hpp | 3 +- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 588466f1..86ef24ca 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -60,9 +60,9 @@ widget_class mainView {open xywh {195 11 250 31} labelsize 20 align 20 class ClickableLabel } - Fl_Box {} { - label {Key switch:} - xywh {195 44 250 30} labelsize 20 align 20 + Fl_Box keyswitchLabel_ { + label {Key switch:} selected + xywh {195 44 360 30} labelsize 20 align 20 class Label } Fl_Box {} { @@ -221,7 +221,7 @@ widget_class mainView {open class LogicalGroup } { Fl_Group {} { - label Engine open selected + label Engine open xywh {305 135 195 100} box ROUNDED_BOX labelsize 12 align 17 class TitleGroup } { diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index cceefe7a..9a9c77cb 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,10 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { std::string userFilesDir_; std::string fallbackFilesDir_; + int currentKeyswitch_ = -1; + std::unordered_map keyswitchNames_; + std::string keyswitchLabelPrefix_; + SharedPointer memQueryTimer_; enum { @@ -102,6 +107,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { CTextLabel* tuningFrequencyLabel_ = nullptr; CControl *stretchedTuningSlider_ = nullptr; CTextLabel* stretchedTuningLabel_ = nullptr; + CTextLabel* keyswitchLabel_ = nullptr; STitleContainer* userFilesGroup_ = nullptr; STextButton* userFilesDirButton_ = nullptr; @@ -170,12 +176,17 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void updateTuningFrequencyLabel(float tuningFrequency); void updateStretchedTuningLabel(float stretchedTuning); + absl::string_view getCurrentKeyswitchName() const; + void updateKeyswitchNameLabel(); + void updateKeyUsed(unsigned key, bool used); void updateKeyswitchUsed(unsigned key, bool used); void updateCCUsed(unsigned cc, bool used); void updateCCValue(unsigned cc, float value); void updateCCDefaultValue(unsigned cc, float value); void updateCCLabel(unsigned cc, const char* label); + void updateSWLastCurrent(int sw); + void updateSWLastLabel(unsigned sw, const char* label); void updateMemoryUsed(uint64_t mem); // edition of CC by UI @@ -436,7 +447,13 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi for (unsigned key = 0; key < 128; ++key) { bool used = key < numBits && bits.test(key); updateKeyswitchUsed(key, used); + if (used) { + char pathBuf[256]; + sprintf(pathBuf, "/sw/last/%u/label", key); + sendQueuedOSC(pathBuf, "", nullptr); + } } + sendQueuedOSC("/sw/last/current", "", nullptr); } else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) { size_t numBits = 8 * args[0].b->size; @@ -476,6 +493,12 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi else if (Messages::matchOSC("/cc&/label", path, indices) && !strcmp(sig, "s")) { updateCCLabel(indices[0], args[0].s); } + else if (Messages::matchOSC("/sw/last/current", path, indices) && !strcmp(sig, "i")) { + updateSWLastCurrent(args[0].i); + } + else if (Messages::matchOSC("/sw/last/&/label", path, indices) && !strcmp(sig, "s")) { + updateSWLastLabel(indices[0], args[0].s); + } else if (Messages::matchOSC("/mem/buffers", path, indices) && !strcmp(sig, "h")) { updateMemoryUsed(args[0].h); } @@ -808,6 +831,10 @@ void Editor::Impl::createFrameContents() mainView_ = owned(mainView); } + /// + if (keyswitchLabel_) + keyswitchLabelPrefix_ = std::string(keyswitchLabel_->getText()) + ' '; + /// SharedPointer fileDropTarget = owned(new SFileDropTarget); @@ -1347,6 +1374,27 @@ void Editor::Impl::updateStretchedTuningLabel(float stretchedTuning) label->setText(text); } +absl::string_view Editor::Impl::getCurrentKeyswitchName() const +{ + int sw = currentKeyswitch_; + if (sw == -1) + return {}; + + auto it = keyswitchNames_.find(static_cast(sw)); + if (it == keyswitchNames_.end()) + return {}; + + return it->second; +} + +void Editor::Impl::updateKeyswitchNameLabel() +{ + if (CTextLabel* label = keyswitchLabel_) { + std::string name { getCurrentKeyswitchName() }; + label->setText((keyswitchLabelPrefix_ + name).c_str()); + } +} + void Editor::Impl::updateKeyUsed(unsigned key, bool used) { if (SPiano* piano = piano_) @@ -1383,6 +1431,21 @@ void Editor::Impl::updateCCLabel(unsigned cc, const char* label) panel->setControlLabelText(cc, label); } +void Editor::Impl::updateSWLastCurrent(int sw) +{ + if (currentKeyswitch_ == sw) + return; + currentKeyswitch_ = sw; + updateKeyswitchNameLabel(); +} + +void Editor::Impl::updateSWLastLabel(unsigned sw, const char* label) +{ + keyswitchNames_[sw].assign(label); + if ((unsigned)currentKeyswitch_ == sw) + updateKeyswitchNameLabel(); +} + void Editor::Impl::updateMemoryUsed(uint64_t mem) { if (CTextLabel* label = memoryLabel_) { diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index e53cdeff..3a124a18 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -25,7 +25,8 @@ view__8->addView(view__10); auto* const view__11 = createClickableLabel(CRect(10, 6, 260, 37), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20); sfzFileLabel_ = view__11; view__8->addView(view__11); -auto* const view__12 = createLabel(CRect(10, 39, 260, 69), -1, "Key switch:", kLeftText, 20); +auto* const view__12 = createLabel(CRect(10, 39, 370, 69), -1, "Key switch:", kLeftText, 20); +keyswitchLabel_ = view__12; view__8->addView(view__12); auto* const view__13 = createLabel(CRect(10, 71, 70, 96), -1, "Voices:", kRightText, 12); view__8->addView(view__13); From 9cd68008a93bc77048f1282ae980d976913356c5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 26 Feb 2021 05:52:20 +0100 Subject: [PATCH 339/668] Switch to upstream SIMDe --- .gitmodules | 2 +- external/simde | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 92f842e7..7850d1b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -41,4 +41,4 @@ shallow = true [submodule "external/simde"] path = external/simde - url = https://github.com/sfztools/simde.git + url = https://github.com/simd-everywhere/simde.git diff --git a/external/simde b/external/simde index 0ba9d8fd..5c2f423b 160000 --- a/external/simde +++ b/external/simde @@ -1 +1 @@ -Subproject commit 0ba9d8fdc0569e5a887dc42c6ddfa2a27a9f6867 +Subproject commit 5c2f423b41c06228e4be0cce0010a252297da4e7 From 097feedc957932e510c43657ec7d4332f596e932 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 26 Feb 2021 22:25:14 +0100 Subject: [PATCH 340/668] Fix the memory corruption in LV2 --- plugins/lv2/sfizz.cpp | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 61d6c581..01ab0224 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -406,16 +406,14 @@ sfizz_lv2_parse_sample_rate(sfizz_plugin_t* self, const LV2_Options_Option* opt) } static void -sfizz_lv2_get_default_sfz_path(LV2_Handle instance, char *path, size_t size) +sfizz_lv2_get_default_sfz_path(sfizz_plugin_t *self, char *path, size_t size) { - sfizz_plugin_t *self = (sfizz_plugin_t *)instance; snprintf(path, size, "%s/%s", self->bundle_path, DEFAULT_SFZ_FILE); } static void -sfizz_lv2_get_default_scala_path(LV2_Handle instance, char *path, size_t size) +sfizz_lv2_get_default_scala_path(sfizz_plugin_t *self, char *path, size_t size) { - sfizz_plugin_t *self = (sfizz_plugin_t *)instance; snprintf(path, size, "%s/%s", self->bundle_path, DEFAULT_SCALA_FILE); } @@ -471,8 +469,6 @@ instantiate(const LV2_Descriptor *descriptor, if (!self) return NULL; - LV2_Handle instance = (LV2_Handle)self; - strncpy(self->bundle_path, bundle_path, MAX_BUNDLE_PATH_SIZE); self->bundle_path[MAX_BUNDLE_PATH_SIZE - 1] = '\0'; @@ -609,8 +605,8 @@ instantiate(const LV2_Descriptor *descriptor, sfizz_set_broadcast_callback(self->synth, &sfizz_lv2_receive_message, self); sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message); - sfizz_lv2_get_default_sfz_path(instance, self->sfz_file_path, MAX_PATH_SIZE); - sfizz_lv2_get_default_scala_path(instance, self->scala_file_path, MAX_PATH_SIZE); + sfizz_lv2_get_default_sfz_path(self, self->sfz_file_path, MAX_PATH_SIZE); + sfizz_lv2_get_default_scala_path(self, self->scala_file_path, MAX_PATH_SIZE); sfizz_load_file(self->synth, self->sfz_file_path); sfizz_load_scala_file(self->synth, self->scala_file_path); @@ -1175,14 +1171,12 @@ sfizz_lv2_update_file_info(sfizz_plugin_t* self, const char *file_path) } static bool -sfizz_lv2_load_file(LV2_Handle instance, const char *file_path) +sfizz_lv2_load_file(sfizz_plugin_t *self, const char *file_path) { - sfizz_plugin_t *self = (sfizz_plugin_t *)instance; - char buf[MAX_PATH_SIZE]; if (file_path[0] == '\0') { - sfizz_lv2_get_default_sfz_path(instance, buf, MAX_PATH_SIZE); + sfizz_lv2_get_default_sfz_path(self, buf, MAX_PATH_SIZE); file_path = buf; } @@ -1192,14 +1186,12 @@ sfizz_lv2_load_file(LV2_Handle instance, const char *file_path) } static bool -sfizz_lv2_load_scala_file(LV2_Handle instance, const char *file_path) +sfizz_lv2_load_scala_file(sfizz_plugin_t *self, const char *file_path) { - sfizz_plugin_t *self = (sfizz_plugin_t *)instance; - char buf[MAX_PATH_SIZE]; if (file_path[0] == '\0') { - sfizz_lv2_get_default_scala_path(instance, buf, MAX_PATH_SIZE); + sfizz_lv2_get_default_scala_path(self, buf, MAX_PATH_SIZE); file_path = buf; } @@ -1231,8 +1223,8 @@ restore(LV2_Handle instance, } // Set default values - sfizz_lv2_get_default_sfz_path(instance, self->sfz_file_path, MAX_PATH_SIZE); - sfizz_lv2_get_default_scala_path(instance, self->scala_file_path, MAX_PATH_SIZE); + sfizz_lv2_get_default_sfz_path(self, self->sfz_file_path, MAX_PATH_SIZE); + sfizz_lv2_get_default_scala_path(self, self->scala_file_path, MAX_PATH_SIZE); self->num_voices = DEFAULT_VOICES; self->preload_size = DEFAULT_PRELOAD; self->oversampling = DEFAULT_OVERSAMPLING; @@ -1312,7 +1304,7 @@ restore(LV2_Handle instance, // Load an empty file to remove the default sine, and then the new file. sfizz_load_string(self->synth, "empty.sfz", ""); self->check_modification = false; - if (sfizz_lv2_load_file(instance, self->sfz_file_path)) + if (sfizz_lv2_load_file(self, self->sfz_file_path)) { lv2_log_note(&self->logger, "[sfizz] Restoring the file %s\n", self->sfz_file_path); @@ -1324,7 +1316,7 @@ restore(LV2_Handle instance, "[sfizz] Error while restoring the file %s\n", self->sfz_file_path); } - if (sfizz_lv2_load_scala_file(self->synth, self->scala_file_path)) + if (sfizz_lv2_load_scala_file(self, self->scala_file_path)) { lv2_log_note(&self->logger, "[sfizz] Restoring the scale %s\n", self->scala_file_path); From aa56a81d255f68e4f50f2f01c9ff090789b1c26c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 26 Feb 2021 23:46:01 +0100 Subject: [PATCH 341/668] Update vstgui with pango fonts for x11 --- .github/workflows/build.yml | 1 + plugins/editor/cmake/Vstgui.cmake | 3 +++ plugins/editor/external/vstgui4 | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 933351a2..eb226383 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,6 +47,7 @@ jobs: libjack-jackd2-dev \ libsndfile1-dev \ libcairo2-dev \ + libpango1.0-dev \ libfontconfig1-dev \ libx11-xcb-dev \ libxcb-util-dev \ diff --git a/plugins/editor/cmake/Vstgui.cmake b/plugins/editor/cmake/Vstgui.cmake index 41cafa99..8c0d4ca5 100644 --- a/plugins/editor/cmake/Vstgui.cmake +++ b/plugins/editor/cmake/Vstgui.cmake @@ -161,6 +161,7 @@ else() pkg_check_modules(LIBXKB_COMMON REQUIRED xkbcommon) pkg_check_modules(LIBXKB_COMMON_X11 REQUIRED xkbcommon-x11) pkg_check_modules(CAIRO REQUIRED cairo) + pkg_check_modules(PANGO REQUIRED pangocairo pangoft2) pkg_check_modules(FONTCONFIG REQUIRED fontconfig) pkg_check_modules(GLIB REQUIRED glib-2.0) target_include_directories(sfizz_vstgui PRIVATE @@ -174,6 +175,7 @@ else() ${LIBXKB_COMMON_INCLUDE_DIRS} ${LIBXKB_COMMON_X11_INCLUDE_DIRS} ${CAIRO_INCLUDE_DIRS} + ${PANGO_INCLUDE_DIRS} ${FONTCONFIG_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS}) target_link_libraries(sfizz_vstgui PRIVATE @@ -187,6 +189,7 @@ else() ${LIBXKB_COMMON_LIBRARIES} ${LIBXKB_COMMON_X11_LIBRARIES} ${CAIRO_LIBRARIES} + ${PANGO_LIBRARIES} ${FONTCONFIG_LIBRARIES} ${GLIB_LIBRARIES}) find_library(DL_LIBRARY "dl") diff --git a/plugins/editor/external/vstgui4 b/plugins/editor/external/vstgui4 index 055cbcc9..8b0ef947 160000 --- a/plugins/editor/external/vstgui4 +++ b/plugins/editor/external/vstgui4 @@ -1 +1 @@ -Subproject commit 055cbcc9ae858f0b07d5d86c205a1111e2fba7a4 +Subproject commit 8b0ef947402eaf56ee77f5077204ba71eba37c4b From 974c6a03761b02040184d7badb04b2f63a1e1a47 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 27 Feb 2021 00:23:39 +0100 Subject: [PATCH 342/668] Update vstgui for pango < 1.44 compatibility --- plugins/editor/external/vstgui4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/editor/external/vstgui4 b/plugins/editor/external/vstgui4 index 8b0ef947..5224bc0f 160000 --- a/plugins/editor/external/vstgui4 +++ b/plugins/editor/external/vstgui4 @@ -1 +1 @@ -Subproject commit 8b0ef947402eaf56ee77f5077204ba71eba37c4b +Subproject commit 5224bc0fe074f068e33cd5088817793d5f32e17c From 7dc8423188569d8f0c959b46cf5a46226059b457 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 27 Feb 2021 08:07:06 +0100 Subject: [PATCH 343/668] Realign things vertically --- plugins/editor/layout/main.fl | 28 +++++++++++------------ plugins/editor/src/editor/layout/main.hpp | 24 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 86ef24ca..80132b24 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -57,59 +57,59 @@ widget_class mainView {open Fl_Box sfzFileLabel_ { label {DefaultInstrument.sfz} comment {tag=kTagLoadSfzFile} - xywh {195 11 250 31} labelsize 20 align 20 + xywh {195 13 250 30} labelsize 20 align 20 class ClickableLabel } Fl_Box keyswitchLabel_ { - label {Key switch:} selected - xywh {195 44 360 30} labelsize 20 align 20 + label {Key switch:} + xywh {195 45 360 30} labelsize 20 align 20 class Label } Fl_Box {} { label {Voices:} - xywh {195 76 60 25} labelsize 12 align 24 + xywh {195 78 60 25} labelsize 12 align 24 class Label } Fl_Button {} { - comment {tag=kTagPreviousSfzFile} - xywh {480 14 25 25} labelsize 24 + comment {tag=kTagPreviousSfzFile} selected + xywh {480 18 25 25} labelsize 24 class PreviousFileButton } Fl_Button {} { comment {tag=kTagNextSfzFile} - xywh {505 14 25 25} labelsize 24 + xywh {505 18 25 25} labelsize 24 class NextFileButton } Fl_Button fileOperationsMenu_ { comment {tag=kTagFileOperations} - xywh {530 14 25 25} labelsize 24 + xywh {530 18 25 25} labelsize 24 class ChevronDropDown } Fl_Box infoVoicesLabel_ { - xywh {260 76 40 25} labelsize 12 align 16 + xywh {260 78 40 25} labelsize 12 align 16 class Label } Fl_Box {} { label {Max:} - xywh {315 76 40 25} labelsize 12 align 24 + xywh {315 78 40 25} labelsize 12 align 24 class Label } Fl_Box numVoicesLabel_ { - xywh {360 76 35 25} labelsize 12 align 16 + xywh {360 78 35 25} labelsize 12 align 16 class Label } Fl_Box {} { label {Memory:} - xywh {425 76 60 25} labelsize 12 align 24 + xywh {425 78 60 25} labelsize 12 align 24 class Label } Fl_Box memoryLabel_ { - xywh {490 76 60 25} labelsize 12 align 16 + xywh {490 78 60 25} labelsize 12 align 16 class Label } Fl_Button numVoicesSlider_ { comment {tag=kTagSetNumVoices} - xywh {395 80 20 20} labelsize 16 + xywh {395 82 20 20} labelsize 16 class ChevronValueDropDown } } diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index 3a124a18..e1f8905e 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -22,35 +22,35 @@ auto* const view__9 = createHLine(CRect(10, 36, 370, 41), -1, "", kCenterText, 1 view__8->addView(view__9); auto* const view__10 = createHLine(CRect(10, 68, 370, 73), -1, "", kCenterText, 14); view__8->addView(view__10); -auto* const view__11 = createClickableLabel(CRect(10, 6, 260, 37), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20); +auto* const view__11 = createClickableLabel(CRect(10, 8, 260, 38), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20); sfzFileLabel_ = view__11; view__8->addView(view__11); -auto* const view__12 = createLabel(CRect(10, 39, 370, 69), -1, "Key switch:", kLeftText, 20); +auto* const view__12 = createLabel(CRect(10, 40, 370, 70), -1, "Key switch:", kLeftText, 20); keyswitchLabel_ = view__12; view__8->addView(view__12); -auto* const view__13 = createLabel(CRect(10, 71, 70, 96), -1, "Voices:", kRightText, 12); +auto* const view__13 = createLabel(CRect(10, 73, 70, 98), -1, "Voices:", kRightText, 12); view__8->addView(view__13); -auto* const view__14 = createPreviousFileButton(CRect(295, 9, 320, 34), kTagPreviousSfzFile, "", kCenterText, 24); +auto* const view__14 = createPreviousFileButton(CRect(295, 13, 320, 38), kTagPreviousSfzFile, "", kCenterText, 24); view__8->addView(view__14); -auto* const view__15 = createNextFileButton(CRect(320, 9, 345, 34), kTagNextSfzFile, "", kCenterText, 24); +auto* const view__15 = createNextFileButton(CRect(320, 13, 345, 38), kTagNextSfzFile, "", kCenterText, 24); view__8->addView(view__15); -auto* const view__16 = createChevronDropDown(CRect(345, 9, 370, 34), kTagFileOperations, "", kCenterText, 24); +auto* const view__16 = createChevronDropDown(CRect(345, 13, 370, 38), kTagFileOperations, "", kCenterText, 24); fileOperationsMenu_ = view__16; view__8->addView(view__16); -auto* const view__17 = createLabel(CRect(75, 71, 115, 96), -1, "", kCenterText, 12); +auto* const view__17 = createLabel(CRect(75, 73, 115, 98), -1, "", kCenterText, 12); infoVoicesLabel_ = view__17; view__8->addView(view__17); -auto* const view__18 = createLabel(CRect(130, 71, 170, 96), -1, "Max:", kRightText, 12); +auto* const view__18 = createLabel(CRect(130, 73, 170, 98), -1, "Max:", kRightText, 12); view__8->addView(view__18); -auto* const view__19 = createLabel(CRect(175, 71, 210, 96), -1, "", kCenterText, 12); +auto* const view__19 = createLabel(CRect(175, 73, 210, 98), -1, "", kCenterText, 12); numVoicesLabel_ = view__19; view__8->addView(view__19); -auto* const view__20 = createLabel(CRect(240, 71, 300, 96), -1, "Memory:", kRightText, 12); +auto* const view__20 = createLabel(CRect(240, 73, 300, 98), -1, "Memory:", kRightText, 12); view__8->addView(view__20); -auto* const view__21 = createLabel(CRect(305, 71, 365, 96), -1, "", kCenterText, 12); +auto* const view__21 = createLabel(CRect(305, 73, 365, 98), -1, "", kCenterText, 12); memoryLabel_ = view__21; view__8->addView(view__21); -auto* const view__22 = createChevronValueDropDown(CRect(210, 75, 230, 95), kTagSetNumVoices, "", kCenterText, 16); +auto* const view__22 = createChevronValueDropDown(CRect(210, 77, 230, 97), kTagSetNumVoices, "", kCenterText, 16); numVoicesSlider_ = view__22; view__8->addView(view__22); auto* const view__23 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14); From 7db931bfd2b1e4d09baf5104c6207bb00c17cf95 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 27 Feb 2021 09:45:03 +0100 Subject: [PATCH 344/668] Keyswitch badge with the key name --- plugins/editor/layout/main.fl | 14 +- plugins/editor/src/editor/Editor.cpp | 76 ++++++- plugins/editor/src/editor/layout/main.hpp | 257 +++++++++++----------- 3 files changed, 209 insertions(+), 138 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 80132b24..f472a88b 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -61,17 +61,25 @@ widget_class mainView {open class ClickableLabel } Fl_Box keyswitchLabel_ { - label {Key switch:} - xywh {195 45 360 30} labelsize 20 align 20 + xywh {265 45 290 30} labelsize 20 align 20 class Label } + Fl_Box keyswitchBadge_ { + xywh {195 47 60 26} box THIN_UP_BOX labelsize 20 + class Badge + } + Fl_Box keyswitchInactiveLabel_ { + label {No key switch} selected + xywh {195 45 360 30} labelsize 20 align 20 hide + class InactiveLabel + } Fl_Box {} { label {Voices:} xywh {195 78 60 25} labelsize 12 align 24 class Label } Fl_Button {} { - comment {tag=kTagPreviousSfzFile} selected + comment {tag=kTagPreviousSfzFile} xywh {480 18 25 25} labelsize 24 class PreviousFileButton } diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 9a9c77cb..51049ac1 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -52,7 +52,6 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { int currentKeyswitch_ = -1; std::unordered_map keyswitchNames_; - std::string keyswitchLabelPrefix_; SharedPointer memQueryTimer_; @@ -108,6 +107,8 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { CControl *stretchedTuningSlider_ = nullptr; CTextLabel* stretchedTuningLabel_ = nullptr; CTextLabel* keyswitchLabel_ = nullptr; + CTextLabel* keyswitchInactiveLabel_ = nullptr; + CTextLabel* keyswitchBadge_ = nullptr; STitleContainer* userFilesGroup_ = nullptr; STextButton* userFilesDirButton_ = nullptr; @@ -204,6 +205,18 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { void enterOrLeaveEdit(CControl* ctl, bool enter); void controlBeginEdit(CControl* ctl) override; void controlEndEdit(CControl* ctl) override; + + // Misc + static std::string getUnicodeNoteName(unsigned key) + { + const char* keyNames[12] = { + u8"C", u8"C♯", u8"D", u8"D♯", u8"E", + u8"F", u8"F♯", u8"G", u8"G♯", u8"A", u8"A♯", u8"B", + }; + int octave = static_cast(key / 12) - 1; + const char* keyName = keyNames[key % 12]; + return std::string(keyName) + ' ' + std::to_string(octave); + } }; Editor::Editor(EditorController& ctrl) @@ -592,8 +605,8 @@ void Editor::Impl::createFrameContents() darkTheme.titleBoxBackground = { 0xba, 0xbd, 0xb6 }; darkTheme.icon = darkTheme.text; darkTheme.iconHighlight = { 0xfd, 0x98, 0x00 }; - darkTheme.valueText = { 0x2e, 0x34, 0x36 }; - darkTheme.valueBackground = { 0xff, 0xff, 0xff }; + darkTheme.valueText = { 0x00, 0x00, 0x00 }; + darkTheme.valueBackground = { 0x9a, 0x9a, 0x9a }; darkTheme.knobActiveTrackColor = { 0x00, 0xb6, 0x2a }; darkTheme.knobInactiveTrackColor = { 0x60, 0x60, 0x60 }; darkTheme.knobLineIndicatorColor = { 0xff, 0xff, 0xff }; @@ -636,6 +649,16 @@ void Editor::Impl::createFrameContents() lbl->setFont(font); return lbl; }; + auto createInactiveLabel = [&theme](const CRect& bounds, int, const char* label, CHoriTxtAlign align, int fontsize) { + CTextLabel* lbl = new CTextLabel(bounds, label); + lbl->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + lbl->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + lbl->setFontColor(theme->inactiveText); + lbl->setHoriAlign(align); + auto font = makeOwned("Roboto", fontsize); + lbl->setFont(font); + return lbl; + }; auto createHLine = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { int y = static_cast(0.5 * (bounds.top + bounds.bottom)); CRect lineBounds(bounds.left, y, bounds.right, y + 1); @@ -663,6 +686,18 @@ void Editor::Impl::createFrameContents() lbl->setFont(font); return lbl; }; + auto createBadge = [&theme](const CRect& bounds, int, const char* label, CHoriTxtAlign align, int fontsize) { + CTextLabel* lbl = new CTextLabel(bounds, label); + lbl->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + lbl->setBackColor(theme->valueBackground); + lbl->setFontColor(theme->valueText); + lbl->setHoriAlign(align); + lbl->setStyle(CParamDisplay::kRoundRectStyle); + lbl->setRoundRectRadius(5.0); + auto font = makeOwned("Roboto", fontsize); + lbl->setFont(font); + return lbl; + }; auto createVMeter = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { // TODO the volume meter... CViewContainer* container = new CViewContainer(bounds); @@ -831,10 +866,6 @@ void Editor::Impl::createFrameContents() mainView_ = owned(mainView); } - /// - if (keyswitchLabel_) - keyswitchLabelPrefix_ = std::string(keyswitchLabel_->getText()) + ' '; - /// SharedPointer fileDropTarget = owned(new SFileDropTarget); @@ -973,6 +1004,8 @@ void Editor::Impl::createFrameContents() }; } + updateKeyswitchNameLabel(); + /// CViewContainer* panel; activePanel_ = 0; @@ -1389,9 +1422,32 @@ absl::string_view Editor::Impl::getCurrentKeyswitchName() const void Editor::Impl::updateKeyswitchNameLabel() { - if (CTextLabel* label = keyswitchLabel_) { - std::string name { getCurrentKeyswitchName() }; - label->setText((keyswitchLabelPrefix_ + name).c_str()); + CTextLabel* label = keyswitchLabel_; + CTextLabel* badge = keyswitchBadge_; + CTextLabel* inactiveLabel = keyswitchInactiveLabel_; + + int sw = currentKeyswitch_; + const std::string name { getCurrentKeyswitchName() }; + + if (sw == -1) { + if (badge) + badge->setVisible(false); + if (label) + label->setVisible(false); + if (inactiveLabel) + inactiveLabel->setVisible(true); + } + else { + if (badge) { + badge->setText(getUnicodeNoteName(sw)); + badge->setVisible(true); + } + if (label) { + label->setText(name.c_str()); + label->setVisible(true); + } + if (inactiveLabel) + inactiveLabel->setVisible(false); } } diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index e1f8905e..f997c035 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -25,142 +25,149 @@ view__8->addView(view__10); auto* const view__11 = createClickableLabel(CRect(10, 8, 260, 38), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20); sfzFileLabel_ = view__11; view__8->addView(view__11); -auto* const view__12 = createLabel(CRect(10, 40, 370, 70), -1, "Key switch:", kLeftText, 20); +auto* const view__12 = createLabel(CRect(80, 40, 370, 70), -1, "", kLeftText, 20); keyswitchLabel_ = view__12; view__8->addView(view__12); -auto* const view__13 = createLabel(CRect(10, 73, 70, 98), -1, "Voices:", kRightText, 12); +auto* const view__13 = createBadge(CRect(10, 42, 70, 68), -1, "", kCenterText, 20); +keyswitchBadge_ = view__13; view__8->addView(view__13); -auto* const view__14 = createPreviousFileButton(CRect(295, 13, 320, 38), kTagPreviousSfzFile, "", kCenterText, 24); +auto* const view__14 = createInactiveLabel(CRect(10, 40, 370, 70), -1, "No key switch", kLeftText, 20); +keyswitchInactiveLabel_ = view__14; view__8->addView(view__14); -auto* const view__15 = createNextFileButton(CRect(320, 13, 345, 38), kTagNextSfzFile, "", kCenterText, 24); +view__14->setVisible(false); +auto* const view__15 = createLabel(CRect(10, 73, 70, 98), -1, "Voices:", kRightText, 12); view__8->addView(view__15); -auto* const view__16 = createChevronDropDown(CRect(345, 13, 370, 38), kTagFileOperations, "", kCenterText, 24); -fileOperationsMenu_ = view__16; +auto* const view__16 = createPreviousFileButton(CRect(295, 13, 320, 38), kTagPreviousSfzFile, "", kCenterText, 24); view__8->addView(view__16); -auto* const view__17 = createLabel(CRect(75, 73, 115, 98), -1, "", kCenterText, 12); -infoVoicesLabel_ = view__17; +auto* const view__17 = createNextFileButton(CRect(320, 13, 345, 38), kTagNextSfzFile, "", kCenterText, 24); view__8->addView(view__17); -auto* const view__18 = createLabel(CRect(130, 73, 170, 98), -1, "Max:", kRightText, 12); +auto* const view__18 = createChevronDropDown(CRect(345, 13, 370, 38), kTagFileOperations, "", kCenterText, 24); +fileOperationsMenu_ = view__18; view__8->addView(view__18); -auto* const view__19 = createLabel(CRect(175, 73, 210, 98), -1, "", kCenterText, 12); -numVoicesLabel_ = view__19; +auto* const view__19 = createLabel(CRect(75, 73, 115, 98), -1, "", kCenterText, 12); +infoVoicesLabel_ = view__19; view__8->addView(view__19); -auto* const view__20 = createLabel(CRect(240, 73, 300, 98), -1, "Memory:", kRightText, 12); +auto* const view__20 = createLabel(CRect(130, 73, 170, 98), -1, "Max:", kRightText, 12); view__8->addView(view__20); -auto* const view__21 = createLabel(CRect(305, 73, 365, 98), -1, "", kCenterText, 12); -memoryLabel_ = view__21; +auto* const view__21 = createLabel(CRect(175, 73, 210, 98), -1, "", kCenterText, 12); +numVoicesLabel_ = view__21; view__8->addView(view__21); -auto* const view__22 = createChevronValueDropDown(CRect(210, 77, 230, 97), kTagSetNumVoices, "", kCenterText, 16); -numVoicesSlider_ = view__22; +auto* const view__22 = createLabel(CRect(240, 73, 300, 98), -1, "Memory:", kRightText, 12); view__8->addView(view__22); -auto* const view__23 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14); -view__2->addView(view__23); -auto* const view__24 = createKnob48(CRect(45, 15, 93, 63), -1, "", kCenterText, 14); -view__23->addView(view__24); -view__24->setVisible(false); -auto* const view__25 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12); -view__23->addView(view__25); -view__25->setVisible(false); -auto* const view__26 = createStyledKnob(CRect(110, 15, 158, 63), kTagSetVolume, "", kCenterText, 14); -volumeSlider_ = view__26; -view__23->addView(view__26); -auto* const view__27 = createValueLabel(CRect(105, 65, 165, 87), -1, "0.0 dB", kCenterText, 12); -volumeLabel_ = view__27; -view__23->addView(view__27); -auto* const view__28 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); -view__23->addView(view__28); +auto* const view__23 = createLabel(CRect(305, 73, 365, 98), -1, "", kCenterText, 12); +memoryLabel_ = view__23; +view__8->addView(view__23); +auto* const view__24 = createChevronValueDropDown(CRect(210, 77, 230, 97), kTagSetNumVoices, "", kCenterText, 16); +numVoicesSlider_ = view__24; +view__8->addView(view__24); +auto* const view__25 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14); +view__2->addView(view__25); +auto* const view__26 = createKnob48(CRect(45, 15, 93, 63), -1, "", kCenterText, 14); +view__25->addView(view__26); +view__26->setVisible(false); +auto* const view__27 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12); +view__25->addView(view__27); +view__27->setVisible(false); +auto* const view__28 = createStyledKnob(CRect(110, 15, 158, 63), kTagSetVolume, "", kCenterText, 14); +volumeSlider_ = view__28; +view__25->addView(view__28); +auto* const view__29 = createValueLabel(CRect(105, 65, 165, 87), -1, "0.0 dB", kCenterText, 12); +volumeLabel_ = view__29; +view__25->addView(view__29); +auto* const view__30 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); +view__25->addView(view__30); enterTheme(defaultTheme); -auto* const view__29 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); -subPanels_[kPanelGeneral] = view__29; -view__0->addView(view__29); -view__29->setVisible(false); -auto* const view__30 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); -view__29->addView(view__30); -auto* const view__31 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); -view__30->addView(view__31); -auto* const view__32 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14); -view__30->addView(view__32); -auto* const view__33 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14); -view__30->addView(view__33); -auto* const view__34 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14); -view__30->addView(view__34); -auto* const view__35 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14); -view__30->addView(view__35); -auto* const view__36 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14); -infoCurvesLabel_ = view__36; -view__30->addView(view__36); -auto* const view__37 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14); -infoMastersLabel_ = view__37; -view__30->addView(view__37); -auto* const view__38 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14); -infoGroupsLabel_ = view__38; -view__30->addView(view__38); -auto* const view__39 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14); -infoRegionsLabel_ = view__39; -view__30->addView(view__39); -auto* const view__40 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14); -infoSamplesLabel_ = view__40; -view__30->addView(view__40); -auto* const view__41 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); -subPanels_[kPanelControls] = view__41; -view__0->addView(view__41); -view__41->setVisible(false); -auto* const view__42 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); -view__41->addView(view__42); -auto* const view__43 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); -controlsPanel_ = view__43; -view__42->addView(view__43); -auto* const view__44 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); -subPanels_[kPanelSettings] = view__44; -view__0->addView(view__44); -auto* const view__45 = createTitleGroup(CRect(300, 26, 495, 126), -1, "Engine", kCenterText, 12); +auto* const view__31 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); +subPanels_[kPanelGeneral] = view__31; +view__0->addView(view__31); +view__31->setVisible(false); +auto* const view__32 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14); +view__31->addView(view__32); +auto* const view__33 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14); +view__32->addView(view__33); +auto* const view__34 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14); +view__32->addView(view__34); +auto* const view__35 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14); +view__32->addView(view__35); +auto* const view__36 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14); +view__32->addView(view__36); +auto* const view__37 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14); +view__32->addView(view__37); +auto* const view__38 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14); +infoCurvesLabel_ = view__38; +view__32->addView(view__38); +auto* const view__39 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14); +infoMastersLabel_ = view__39; +view__32->addView(view__39); +auto* const view__40 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14); +infoGroupsLabel_ = view__40; +view__32->addView(view__40); +auto* const view__41 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14); +infoRegionsLabel_ = view__41; +view__32->addView(view__41); +auto* const view__42 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14); +infoSamplesLabel_ = view__42; +view__32->addView(view__42); +auto* const view__43 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14); +subPanels_[kPanelControls] = view__43; +view__0->addView(view__43); +view__43->setVisible(false); +auto* const view__44 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); +view__43->addView(view__44); +auto* const view__45 = createControlsPanel(CRect(0, 0, 790, 285), -1, "", kCenterText, 14); +controlsPanel_ = view__45; view__44->addView(view__45); -auto* const view__46 = createValueMenu(CRect(25, 60, 85, 85), kTagSetOversampling, "", kCenterText, 12); -oversamplingSlider_ = view__46; -view__45->addView(view__46); -auto* const view__47 = createValueLabel(CRect(15, 20, 95, 45), -1, "Oversampling", kCenterText, 12); -view__45->addView(view__47); -auto* const view__48 = createValueLabel(CRect(100, 20, 180, 45), -1, "Preload size", kCenterText, 12); -view__45->addView(view__48); -auto* const view__49 = createValueMenu(CRect(110, 60, 170, 85), kTagSetPreloadSize, "", kCenterText, 12); -preloadSizeSlider_ = view__49; -view__45->addView(view__49); -auto* const view__50 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); -view__44->addView(view__50); -auto* const view__51 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); -view__50->addView(view__51); -auto* const view__52 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); -tuningFrequencySlider_ = view__52; -view__50->addView(view__52); -auto* const view__53 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); -view__50->addView(view__53); -auto* const view__54 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); -stretchedTuningSlider_ = view__54; -view__50->addView(view__54); -auto* const view__55 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); -view__50->addView(view__55); -auto* const view__56 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); -view__50->addView(view__56); -auto* const view__57 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); -scalaFileButton_ = view__57; -view__50->addView(view__57); -auto* const view__58 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); -scalaRootKeySlider_ = view__58; -view__50->addView(view__58); -auto* const view__59 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); -scalaRootOctaveSlider_ = view__59; -view__50->addView(view__59); -auto* const view__60 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); -scalaResetButton_ = view__60; -view__50->addView(view__60); -auto* const view__61 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); -userFilesGroup_ = view__61; -view__44->addView(view__61); -auto* const view__62 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); -view__61->addView(view__62); -auto* const view__63 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); -userFilesDirButton_ = view__63; -view__61->addView(view__63); -auto* const view__64 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); -piano_ = view__64; -view__0->addView(view__64); +auto* const view__46 = createLogicalGroup(CRect(5, 109, 795, 425), -1, "", kCenterText, 14); +subPanels_[kPanelSettings] = view__46; +view__0->addView(view__46); +auto* const view__47 = createTitleGroup(CRect(300, 26, 495, 126), -1, "Engine", kCenterText, 12); +view__46->addView(view__47); +auto* const view__48 = createValueMenu(CRect(25, 60, 85, 85), kTagSetOversampling, "", kCenterText, 12); +oversamplingSlider_ = view__48; +view__47->addView(view__48); +auto* const view__49 = createValueLabel(CRect(15, 20, 95, 45), -1, "Oversampling", kCenterText, 12); +view__47->addView(view__49); +auto* const view__50 = createValueLabel(CRect(100, 20, 180, 45), -1, "Preload size", kCenterText, 12); +view__47->addView(view__50); +auto* const view__51 = createValueMenu(CRect(110, 60, 170, 85), kTagSetPreloadSize, "", kCenterText, 12); +preloadSizeSlider_ = view__51; +view__47->addView(view__51); +auto* const view__52 = createTitleGroup(CRect(170, 161, 585, 261), -1, "Tuning", kCenterText, 12); +view__46->addView(view__52); +auto* const view__53 = createValueLabel(CRect(155, 20, 235, 45), -1, "Root key", kCenterText, 12); +view__52->addView(view__53); +auto* const view__54 = createValueMenu(CRect(250, 60, 310, 85), kTagSetTuningFrequency, "", kCenterText, 12); +tuningFrequencySlider_ = view__54; +view__52->addView(view__54); +auto* const view__55 = createValueLabel(CRect(240, 20, 320, 45), -1, "Frequency", kCenterText, 12); +view__52->addView(view__55); +auto* const view__56 = createStyledKnob(CRect(340, 45, 388, 93), kTagSetStretchedTuning, "", kCenterText, 14); +stretchedTuningSlider_ = view__56; +view__52->addView(view__56); +auto* const view__57 = createValueLabel(CRect(325, 20, 405, 45), -1, "Stretch", kCenterText, 12); +view__52->addView(view__57); +auto* const view__58 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12); +view__52->addView(view__58); +auto* const view__59 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12); +scalaFileButton_ = view__59; +view__52->addView(view__59); +auto* const view__60 = createValueMenu(CRect(165, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12); +scalaRootKeySlider_ = view__60; +view__52->addView(view__60); +auto* const view__61 = createValueMenu(CRect(200, 60, 230, 85), kTagSetScalaRootKey, "", kCenterText, 12); +scalaRootOctaveSlider_ = view__61; +view__52->addView(view__61); +auto* const view__62 = createResetSomethingButton(CRect(120, 60, 145, 85), kTagResetScalaFile, "", kCenterText, 12); +scalaResetButton_ = view__62; +view__52->addView(view__62); +auto* const view__63 = createTitleGroup(CRect(615, 161, 754, 261), -1, "Files", kCenterText, 12); +userFilesGroup_ = view__63; +view__46->addView(view__63); +auto* const view__64 = createValueLabel(CRect(20, 20, 120, 45), -1, "User SFZ folder", kCenterText, 12); +view__63->addView(view__64); +auto* const view__65 = createValueButton(CRect(20, 60, 120, 85), kTagChooseUserFilesDir, "DefaultPath", kCenterText, 12); +userFilesDirButton_ = view__65; +view__63->addView(view__65); +auto* const view__66 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12); +piano_ = view__66; +view__0->addView(view__66); From 8241eff3313eb104a640eca1e66dfd5e2d058162 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 27 Feb 2021 10:04:47 +0100 Subject: [PATCH 345/668] Vertically realign the buttons --- plugins/editor/layout/main.fl | 14 +++++++------- plugins/editor/src/editor/layout/main.hpp | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index f472a88b..ba35eb56 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -25,18 +25,18 @@ widget_class mainView {open class SfizzMainButton } Fl_Button {} { - comment {tag=kTagFirstChangePanel+kPanelGeneral} - xywh {49 73 25 25} labelsize 24 + comment {tag=kTagFirstChangePanel+kPanelGeneral} selected + xywh {49 77 25 25} labelsize 24 class HomeButton } Fl_Button {} { - comment {tag=kTagFirstChangePanel+kPanelControls} - xywh {81 73 25 25} labelsize 24 + comment {tag=kTagFirstChangePanel+kPanelControls} selected + xywh {81 77 25 25} labelsize 24 class CCButton } Fl_Button {} { - comment {tag=kTagFirstChangePanel+kPanelSettings} - xywh {112 73 25 25} labelsize 24 + comment {tag=kTagFirstChangePanel+kPanelSettings} selected + xywh {112 77 25 25} labelsize 24 class SettingsButton } } @@ -69,7 +69,7 @@ widget_class mainView {open class Badge } Fl_Box keyswitchInactiveLabel_ { - label {No key switch} selected + label {No key switch} xywh {195 45 360 30} labelsize 20 align 20 hide class InactiveLabel } diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index f997c035..c5d7c57b 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -10,11 +10,11 @@ auto* const view__3 = createRoundedGroup(CRect(5, 4, 180, 105), -1, "", kCenterT view__2->addView(view__3); auto* const view__4 = createSfizzMainButton(CRect(30, 5, 150, 65), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 14); view__3->addView(view__4); -auto* const view__5 = createHomeButton(CRect(44, 69, 69, 94), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 24); +auto* const view__5 = createHomeButton(CRect(44, 73, 69, 98), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 24); view__3->addView(view__5); -auto* const view__6 = createCCButton(CRect(76, 69, 101, 94), kTagFirstChangePanel+kPanelControls, "", kCenterText, 24); +auto* const view__6 = createCCButton(CRect(76, 73, 101, 98), kTagFirstChangePanel+kPanelControls, "", kCenterText, 24); view__3->addView(view__6); -auto* const view__7 = createSettingsButton(CRect(107, 69, 132, 94), kTagFirstChangePanel+kPanelSettings, "", kCenterText, 24); +auto* const view__7 = createSettingsButton(CRect(107, 73, 132, 98), kTagFirstChangePanel+kPanelSettings, "", kCenterText, 24); view__3->addView(view__7); auto* const view__8 = createRoundedGroup(CRect(185, 5, 565, 105), -1, "", kCenterText, 14); view__2->addView(view__8); From c88e55190ff6770938b395aad5d971eb06a017fd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 27 Feb 2021 11:14:28 +0100 Subject: [PATCH 346/668] Update vstgui --- plugins/editor/external/vstgui4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/editor/external/vstgui4 b/plugins/editor/external/vstgui4 index 5224bc0f..289f8717 160000 --- a/plugins/editor/external/vstgui4 +++ b/plugins/editor/external/vstgui4 @@ -1 +1 @@ -Subproject commit 5224bc0fe074f068e33cd5088817793d5f32e17c +Subproject commit 289f8717e6c7653397d4a099fe7c1a2ded42eb44 From 8e122e3a369d9f6940f411ebb05bd0a3acbf1d78 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 27 Feb 2021 13:22:52 +0100 Subject: [PATCH 347/668] Icons in filled style --- plugins/editor/CMakeLists.txt | 1 + plugins/editor/layout/main.fl | 6 +++--- .../Fonts/sfizz-fluentui-system-f20.ttf | Bin 0 -> 229796 bytes plugins/editor/src/editor/Editor.cpp | 10 +++++----- plugins/editor/src/editor/layout/main.hpp | 6 +++--- scripts/generate_ui_fonts.sh | 10 ++++++---- scripts/innosetup.iss.in | 1 + 7 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 plugins/editor/resources/Fonts/sfizz-fluentui-system-f20.ttf diff --git a/plugins/editor/CMakeLists.txt b/plugins/editor/CMakeLists.txt index f7c8904e..bfc5cc1e 100644 --- a/plugins/editor/CMakeLists.txt +++ b/plugins/editor/CMakeLists.txt @@ -14,6 +14,7 @@ set(EDITOR_RESOURCES knob48.png knob48@2x.png Fonts/sfizz-fluentui-system-r20.ttf + Fonts/sfizz-fluentui-system-f20.ttf Fonts/Roboto-Regular.ttf PARENT_SCOPE) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index ba35eb56..74582ec2 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -26,17 +26,17 @@ widget_class mainView {open } Fl_Button {} { comment {tag=kTagFirstChangePanel+kPanelGeneral} selected - xywh {49 77 25 25} labelsize 24 + xywh {36 73 32 32} labelsize 30 class HomeButton } Fl_Button {} { comment {tag=kTagFirstChangePanel+kPanelControls} selected - xywh {81 77 25 25} labelsize 24 + xywh {76 73 32 32} labelsize 30 class CCButton } Fl_Button {} { comment {tag=kTagFirstChangePanel+kPanelSettings} selected - xywh {112 77 25 25} labelsize 24 + xywh {116 73 32 32} labelsize 30 class SettingsButton } } diff --git a/plugins/editor/resources/Fonts/sfizz-fluentui-system-f20.ttf b/plugins/editor/resources/Fonts/sfizz-fluentui-system-f20.ttf new file mode 100644 index 0000000000000000000000000000000000000000..691a6dacc596e615c065d6ed11b518774a6d4e10 GIT binary patch literal 229796 zcmdqK37k~b(KlRm&h5T^yL)<{joGJXWd>%S0S1_1SOnQdKmxJ|I7U=dRD{u>f{LON zg9Z`zF>ygeMMcGkMvV(eG(lq`k3mHw2ICT z`>9i>s!p9ccZi87jaHDR&M{-AOzUZ7&=DSzTME+P7QRtJi z=65ePuHoYlKM3gy&z^tQsbl+%RHQo>5viLNpL70_OYdJiob*(KXy8R8eFJ=R+6|li}+o{@V zpdDi9LS9QQw9BJv5wh61^9m{_U{I0EveVg@(BVhw{Ql@JTCs=rE$G{ZBU*s=Ag&*v z8_*#@-PB24fKEJ3CJ(M{_FI=7*F~!k(go- z^4Cf2G{XK#Ju~f+1mlAFzj77sf|U;TqLfv%0->q$WE7_WSxXM*pO(67lhNV#30 zrVilfM(X6V`D{E(=pwYb0>2_axBcwAJ0mCklzvqJy7BDvcWUx3VG<+13d|pA#l84V z!u=XM=e?k%RLj5X-hwtxqS^MmaB$)DaWdNGU{Yp|jD~})BGftw&)pcQE?Q%^dj#m| zCcCB!>H1^PuQM_q&wLt*Q3P*vLprob*ko_g=d-t%&Kd zTOt^jbb>``pZx5;fd0BMucV$eb_(fRs^ku|WnwaC2gYd$-C@VdZ0W%qb?}h73Y~T$ z{WAQ{Laj13&de3OI6ZOFI`zx!aB#MsM%txyP$gyHX}w)%2aUnKp0*})OBvUKHjW3) zPD-|aIMPnQvyAg9^h|yq0R*3uk-HnEIT*Yb&z->R$@opMOO$>(^FmrxZ{tnEoHh!! zQ_q4qDdq4_%Br9%Z5k3v6wbKA{;dKR6YB4=-)ihKgg%_o1hZ4=Va&MHzmx40XWM0u zLoEmJ)(wuh6 zI5^`kyt|WzBV`*E;wkkmc_c>alU7W#pDMu3KEnG)HYb+w^K1@OVW*W=IKPwa)J|(9 ze~ND&`<{xIess`$@S3~rc1T&PFfzLlDziu0;?EXf`U6=>qYx%|6_|iL zOX+m`E^jj5oKUCT&e+L#PoaD0?>rBqD!rAllzVD?MkJr6@*}(lB(IZ@>*yt(w-F*b zQZ5;uXK}9wWf&CMGh)w_J+t?nfn$%d!#+IXXKs}_srRI>7Hx%T=)Lq_q*T!WN+8rC42AOd-vW4 z_CB%qslAC0sy?Xw;EWHx-q*5kmgIo~rwbMCChG3}R~RoWEG#I@mw>{e-eA$x>XUB| z;r^ToscZDv#!1G~R2t(s*BBz#EpCrlVXimdM!57(p-(PylL`IGA}{&K58XLHK?+fr zA{3<|MpV8B_ot}ZzevY1} z7w8xCBE3wnfTn&)zoK8$tMnTE20H6bTlf1Ny-B~Pw`dpr7rjk?#7ujK-lg|2Z12-v z$i02^C+L)aru~@lf1!`*6Z(`sqrZZ${f$1SFX&79JN<+HNeAg)^cDS^zNSNzpl_f& zGb`3?u#4SnvWG49vXA|o#sLm-m?IqHbk5*R&f;wD$2pwKd7RG$T*yUS%yBN^QZD0i zuH^n)#nn832XZ|(a3eQyGq>;{9?V0ym51^$9?ost&Lg;kNAf5h&13jD9?RqScplFa zcp^{Y$=t~&@D!fP)A&T5!87?Jp2f3y4$tM2c^=Q_1$+v3@u~cMK8+Xh>3jyC$&2_b zXg%lfVm_D8-a`q&o}Wcd@J9^xAPr*C-?AO{1g5u-_7^%y?h^UJ9b^Irad_wk?jL;f@G=a2X={4syRpYdP$ z0RN4@;4k^_{15&oALM`WSNw1Onh$Y;zfq)EDW#R6T*|FXtb#1%RX*icX)2(Cn0sLr zQBf6B=_*5Isw|bQ`l%e1tMXL7Do};0NENHNDp94XOqHt&RjK-`DpjopsDY|R)u{&6 zq?%QW8l(oRA*xjkRm0S9)u!6j2-TrRs!?jR8l#R=W7Rlyyc(}2sEKNlnyfn232KU( zs-~$E)pYeeHABr*C#hL#j+(1ZR`b++wLqPsy40!a`|32cP@S&MP-m(|>MV7(I!7&5 z=c@D6`D%%}KrL0vRJXcNU8H`XmaB`^CF)YOLakJnsms+BYL&WDU8Pp5tJO8?TD3;~ zP+h04S2w61t99x|wO-w%HmIA`E$UWvyShW&se061>L==_>TY$9x>wz&Hmdv8CiQ^Y ztR7SksfX1T^@w^@J*Kv*$JG<+NwrNqrGBQKR@>Dx>RI)3^_+TM{Xy+g|E1nme^k5G zJL+Bap4y|{S9{e5YM=U(`cVB@?N=YEzo?JZC+bu6nfj|bpgvb$s4vyu)j!lf)j{Y;j= zZqx00gznHI^(Z}BkI~2Jv3i_7UXRzE`UE{iPu0`(iF&&Jo}Q^s(zEnzJx9;gC+m57 zzFweD(WmO~>(lf?eY!qFpQ#t=v-H{e9KBedtIyNt>m~XEy;LvL-TFd(k^X^Rt}oV? z=u7nqy;5JMFV|P-Rr*SOm0qo{*4OB3^&0&{eVzW1UaPOyH|QVhb^1oVUf-lQ=$rK| z`c{3LzFps;@6C-N8hXO(;M~udXs)YZ`Kd$hxHcyh<;Q*rnlW1 z>Wv1Y(P%Q7jTU2&F_;EGOBqem>3h(TmfD)eg>(`9fG(y>u-;usm(k^P1vI%U>4#Wn z{g~E4!@G$#(0#NS>+P554;#yotB-GyE+7oOki3{JE-C z^{P?LRzFf})oto6^*5cX^K^wCu4m{j{g8f7|HE(_ej{uY7==Xa1|-!0hDHIIf8@VZ ztU9b(V zfQ=B~Lwdgl2F7-x0IXnv4MaiM7DFg6^fgiVMWP67fzeLb_+}HO!;Y7Z@-vVx;}fFH zX#kX)H43nqC>wQVF99H5zZrmiL^&ugw~#0gW#sK7%13ws$}dFPLc|rJ{-T9|H;IZ- zZhR=EhzDm^DA9eP>o2Uw9RiWJKMMMJ-H()z#i_-x6 ziE03~+lcDc08man%BV-$2IOf#cw+^io2Uu-nh@8#1b{ZTp!~rhzyYEmV*veaW z=u;QUJQZ#DKHg7@0X7pY#Ph;Wh)zd2XP}%j@O>cO?oa^AK5q-r`HP8`%pke|buUFbmVQaJ4B_2)?(QbKu#@N_ly}jaL_b(fv>feT zjx-lSsL_g{wT8q5bA0+xQ>iqFeqIElnZbTXD zX8?8)-GuO)Q14Bj5N#MsbaO4>Hlkay07!ES+Ih>@M7N?nw=M_V4M6#~4Fb#td`)!w zVxl`ri0)hnKpXG!0Co`l1nGXdk?3x~J*$cCod(!Ubl*CnjmW$4Hlq8{&P`*99*6-} z5N)mipq&pQ%|qQp4=*IzvW@7GgG7&RAbJe-JcjzVqTP=p?c<1h0{wh47qFjb8`3{j z4S1F4XIBtCjr32W&h1%%eMHZo&S#$^`uPN~9NeFOk?0pF=S8G{3F%+jL-g`SqE~SL zWjE2U(9U0>J-=Q;^eWz8yBqK&(Qk3ziTmrd0F?8_45Hr^0_FjB5WU$5=pp(&^8J1v z(I2J(5dIdz-`Yy_Uqb;Kh~7s2w^tMWaSL_~koO(HyJLyo1MJyI^nQ$JFWUS8+O}^Y z(VuYt5Mdvp>_1ln(7r#fA=)p1dOq4i^p{b9bwnTI{_#PgPjdnLi9UOi=&uuq4)_76 z`)_v>eU3Dr?BJ>Ec-c)Lr5yF2!?c4{_OM;_}_Z6{xQgbyOZ8?vFb9qr9qGz#8J}YQQJN0~Qkx z%mpkbu0`59q-|V8+`ON-1!WAX0PG|l{3`K~p~ORxei+gZ13rc!d^qxfpK=@8)E)z% zoggs*h4&W2Jxs`0O}mQg?P-H#K*lzJhlHfksmOm?A@M@gaXQkTISPPs7NPt_2Z_(x4ETij zY@|D90$?5S;uQdtb1up|4{bQV7VskRlHJ4?>?B@_xMjWk}o0v%2+-Ku$uVd z5CCZ}!TTj!h%e0r;J#uB-~jQ;{lu4d6JLRHR-ufm8i`lW20TZ6^*q2q;%jif7Vtxq zaUJsg$OAy0wOIhP`T7{3hxmpS#6KqDb$-B50OD>$S?iJSrfI|*mJ{Ec3qbfS&k^5x z1>jBM+cps2j`-WrmOJJFz9zmCee6N_PYMA`h<`c(u#@<1wEdn@fZfFRb_39d`%uot zMa1_b@1}O*2WkOpi8qf0p!^3>FHA@L5aJ&$1gs$5avSj@sP8cYu#ot1+#g37PvHIp z>UgpOunSw8oy1R}{GTE3(?f~3ZzX=_Zoom}XS)E~h<}cJ&!Mj8HWNROu;=#>|6&l} zRpJ+s{v|&EZFqSC@hc_7J4O-zauM;bUL^i?F7d0lzlJ)0gEYTwC*D~I*h&04^1snT z{JTcL4&pas0Ob3+w+qiOdhy$+>yKT;yQdMqQwvxN_>%bD6~yng6N3-( z`v}{+n;3kM_mvR;se<@J5AmN7zaMe?_Yi-CxW6<4@ci)_;!n`VPtea#*Aah)=g-it zzoMSMqTU1D#DALrKs}!${0sEqi-W{pzDWG{dBp!1OZ?9)0P-IM{3`^Q2G~jb)gt1r zhXQURJ~Rq|G7=kzziEdaKLfCb6fXh1NlHxvYyf;sNtpKQbCj-ss?N(6)ps9Ar)CiDvGqR zyGf-F1so)mf#=Lo0F;}#l~fiWyPZ@&gykS@?ix~g8%cqOs{FNpJ){cfkt!+ypzLBi z$5)doA;4{}s%asqW|Y~2vRY8*Afy?zkJJ#<*^2O1gbi&ZH4J%%O#mQn z_&mTaQf=r%8_H-$SsjB&jYOTJLVy=Zjb1})4C*}&~w3^gp)Nw*50BNVj0H|jg(x149)O6H69pT^mlGKb1q-HJwY$tUR?kC|6 zom4?5RkIO4=QdJvXOKF%9e_5>TT5y_;^yxnwE*v@ApDe_q`G#HIu+?o{hHMG*O5AH z0;z?FTZp*R(T+2a=M0p6Ci-$F(kwz%S6@Nun#H89MLX9Z?uU(} zuA2e)gw$F;sq5#Fx?vFjd4G)ik9Uw-_bMsqr)qr`shd#WO{nAM5UE=x0PuY4I#RbG z{PqgKbENJ7+==?{+)1hjY3?GxascWF|5ZPY0alQ@yOGpA(@5Qm`+aEB#u8HZdjOx1 z+O&t%1IWJ_^*?xk)I?8HqJW^X1l6oBZpFkZ?wgZrU8`3@n z_}Nxc+YJE9dj|QQolWZJqewkh0oX?BdE|Ma8nBtvFOcsgl>gG#q+UkaSCDtdbEJNW zI(|if8Ki#QN$NL%-=gf-LxAn1ez%$w_^Emm?fE_O{GprFTc~GOJ76cNw~_Xb(*Wq# z?u7uPgHEa5*-h$QqdfTS_eSBzic7( z@pGg;?IQJA7OB4q+)e7hSOCKRhW7jo<$VtL0`PYOaFEnL_mlcp1z-iKuTa-l+e!U< z6aZy@y@AxB<)jiwo4A71H)}}KSimQw`2cCPnzSAS*iYKk2o(Hf z3es5nYyULTXnd6RT>1L+vbPTxs7<5kjGS){W|NcUS#I(HQ5 zya}Z9YXQhpu#R*g(ie3Co&%u%IO5_<04TRK23SZM{7;vCLb`l5U?1s<)qvfkD^XA7 z7SjFE#{RbfkiV(|un=;g9}#_`($Pzk20p@6GxSl@pik=`al3X8eN-zv(j!`eT@w7L z>4uzn6b7PC>l?xi;qr!Xyx$w!?zlsxANsf-zmL)sVfPHS+np#ej`!lS#^(Brn5zgE zcNK?Y?&7jx98Z^fQ#dZs{76SlO-D`Q3I5U_iTF1~vLY3LO?XkYh^XoK9$phak;uy~ zlPk|f071|1pi^MweU~5z*bHFvL&|IAXmdtp4mW2MaD!8Aaaj#(cUd|2tJD$yqChkn zm@?Yk+l}%H6)(TR@nq> zVVBje*N1(o@1d8m02dGB#^GF_;c}bqAiMLqxuvnCxuvN>W(u2YDKs|q)EM?}*t2`F$+1{wz z@-l1fiDm}fX+dvUBg#PHfCt-7R=7TvRS@tk@db{TqTiCstXV#E6gbCDD#mvscKN8Z z$sWK~ZjwRHOJUm{Tt08N4ApLoRPV$3Bil$J)+c-Xky-Bdf|<6-7yghKk3XoDm{Zl*k;URN zMa7vJ?w|@_Z?TO{H=5Z9`pvXEV4_{pK5fr(K_X`Li>9Z(-fjAPt+k<8zx$R4D&y%c z|Aob^Y&1pPM&?I>cR4#=5etp@MvW3uIkX*DHQH@fxLEl|WH)%4dm^4-X+~>*fB%wh z!^jCm+@9Kru0mCKoUb}D5~OAGfx|qS@NPfc!HV46e9_lQlJQ%w!-X*$50R+SH@c=ezwOx0)f>^AaZ| z>s1~zF=osu$re3fw~zl;TeZL)^1Bahl_U5PREbu}X zW@Z(3(Z|t=z(s>p3|!=4s6b_c2pK>@gbOqubDP36L0>KQ9O(OAnh{jsnPqLNIm4Bi zkL~Ch3_cJz;AQuq;|I-Icteej1P<*t-F~mT#<-r}^aj%`J<=QWd-b7>_6;uxQajUv zy2FZr)5z`6X&shMi&^&dzLMHnb*B+1>xsFdv1qy9c=U0PFYGr?nt<)EkiUMIi~V6ATQf~92oU;FNel|CS8_VKaR2-Snf<~YyeAK&n)ceu#ovoF;t+KVX zGBLKYwJSRw&*p7%-I^Kh3}+s7IdIgw{i+tFvZJUk86L%18j;YDVGkmG`Na@gUp7ahT+`OWDCv|^C}k^ z+0u|1Pj6^BilsU4;QvBNNTWL4m90v(R=N`_s)p;V1c!d#6=fpc!fEf(y z0`ML%vDqU>zHc)y2zi9Aw^Fj1+fY;^|NpBudcWsNXU^atis#8{qmU zR|R|){64&R>5@kVZ^LsRT`~$9fHqQ^WWi3iWuPZ0M=Zbt+c4A=a={hGw8Oa#LCSG)&c_{88J9IDatilMuwl0bsW}`b38kp!n?u-^& zLlNa9qq#h(3pJOSK&nWF^tzbnyv60kO=XR3f^8u|TP(Un|CM=J1$Km+=@ucd>2E5jDLOiUXLUkx)t&B;n_cdKi)Ah?9tb&_SiIOU{2rHy zH#c*@@1)aSm)l_W`dIC(Df$7*jMv9e#nhsjnxd(_uRkcN`A4TV4Z}pyZgz)U12Lrs zLgaQTSDM#t;1Q+z(o%^GsNV*wG;CQIee}p|c(Y9g=KAQ7Alrs$+*u2>DYF1RTf@0V zwc^?`3`nTq_&|nARl{Wvv<1qHLrVaS19Ne#4*F`63x_B++@YvTt;?IKT+tA^7S1y~ zerCVN7*Y?#2#iMgB3cJcl`(FRVfjIUzswtQGJKG>JL;;Vx+WGH+KO1(qh77QSsYp- z9wSdm(NfxT77&q^CZ#A}*eF{LghoNXKhc(~?cg^Lf1T~{`YXb2Zjm$FWRijq+PFv` z)%!bmpFLR;x%Q3sbu}D+d_!WNTraTc-n{ytMk@k9| z0}SOeXq3>n>B#m5WLbzQ2W>lF7P(1YR$i9RcAuo5k^>@ddNkKN)r5+gbl&nUcP-7ew#U5dy*b{I7E)GS;#F_QkUGaZP2RJuRVU5Adg=5)SZ4&z zx#{7HmpW-5zvj~yv<4AofXmnz$W! zH6bf9R8}=Zu|#nm5?5@^tMvBdRaWLDX5$+DC40AeckJ*!J9LxR+v9Sn?R}Hm`M}wG zyp?&#SeeIn=T(l`P2lznij zlm^i^MbOc@WI6C1DQuza%=evH@p#tMtm5LV9ek-T0FIMbY0F5yG~xfB#j!70;?%78 z$iwPCR~KhZlZtQ|*++g#I8xeqI{I)F@Q{>lWkI_r1rJFr@58R7RFf5b5>GOkHWt*z zG4-Mt@-!F~{2sZyDay;CopMzki5pYT?VS)3_|I8~)gzIkI7wvl$0B$z&q1BwKTvtK zETqcgHBf0~HCDq-;6($K%hA(pEzZ{Pgtn48U1=sT?93dQNTL#<44bFnJ(IWSN#1DK z%ae5=pp96Rb&iT=V-efW@Mc9+;+?wqDzR#GQTv=X{-WIyA|_mm}s?0YO?WM27HUj%eDogpJ3QnrE519 zG%ZbSFyq0N26@r|);3&ax@^AgXnRmLASUBjiYlAC%R<3a$Hnc|nTZ=rFPd2w=PUnH zXS|7Veo|noJp#db_*-1=$N+fh8uR?AO^s+ ztaJ_k;wQeLC!Sbwt{6xoDi_y!#NV(m60t0Qx+^Ws=gY`g@x&8MPmF7lB2dmzZHYRR zFBJ*FiSPI7G5$@z@-rj1A>@kvm)O+7p0zhy-tb|>ml3h0F4f8PoJ<#(X{!a2hPS+t13Sfq7Ivf1rv#xf9_ zhB^6XSy>UQ$I1eLF3*aWO!H=?xz$f9TH6-CeU^mvSP~zx&U*Wj<0sU+-RW6U&xfdI zL9!lM4GXT1Sy_1*TRwMMmUmi7{HV(EbJS1FtaP`#e!}sW99`MswpOXO8TbeWr8`vDRgtXtrlkRr!)~EE|}5XaW4LSKx#NmD)l}CAo>M!rRI?)S%3a zlpcg?9_Q+6e8Zu?dkO#(Ek!)+Fhn4p#PjS$Pw{vv&a`8ESHG=Q~$EX)6PDeYC`|W2$2d6*_DEZ`OI56DQe@#fnqZW9m@3R~k&N^Qr&-~7 zzEkYm*fX#V3gsG;6Dk(uy=b^LfvTP_tTedLrdeND44l0j&W^lnWkq?;H{`|AUqL=w z*G}4gp;zw(SCiaZwBW5s10O zZ2R_xFRYe%GGz5+!o3}S<1YJrfZO$eWl8w5$eM5(5=H#Ds8N!0;W9}qk(2;yfy;Pkn?!iHY@Q>wM<_j*D-d2S zkQgH6<4L{7?vI!%?IB2NTp*5=CIE5})Y}FGm;|90kd+(r&TN9t5=*->Ee6@n=LBN0 zK;uk{J#a_y&J4j#AA&lu7_n(h2sSm8keTSJ1gH!|=0;~qw=8RBV;TxVC9>L?fh4ww zw=

&5g}Srb<>9h^iT=aHe3(3tQ;nR@hBBx-y&YapoQ;O|HQSIpO{e+1nO6mq;7% zEK%a5hoC?7ugK=g3+!zS{`f8-B@CP+yAlh9ZSV$>XzCg;kg@jrHh;riIHwSBgZLZ) z2+k~0%C3JX>fdSC50QY?jM$9q`rX25lFMS*3ITyPw=^~+MQu^Ny4P;RP}H-~k)c9F zXpTlLB1%E2N3>$MQ>)d(hIR*BMyfTa7P=o!pyE`}cHm(IPGZ^|z+rWb&CvoLrfmHe z^IeqV2GNddaO^2L3(a^+_9MV8SQ4Iw8M}kmIzx@?ojNB+d$YrsM3XHj!Z_E&!op%P zqhCLpzD2E@>@BkmnrMUmZV@1WS91NE^nz)1)QD{z=17jRc*Q%Y%YkiTJ|gv4&x{~cx~x&T7~T@ zyOsz4n{D&-#m?c*Mx(a?QEX*LzzJ;iRZY^tpcXYhCr8wF>E$GEav9)-e8MSn>^IDW zMHWt_sYN_&dzjb?WGfRBi$l8ye8Ayr!pk-#dD_y13#<=}kN>??!qo)rVK<_M0oqK` zSc+JrS?bBOlJY|4jYGGXH+|{W{15XcNwcs2Kb|)X%iS{6f4|850T7P%>?n0uU6T6j zxpS0k_r9Kz?XP>o*(+>)KnJWZJfaR@TD}al%X~PzXO68p@WK?oOPQ+_f!I{QU!%nZLFq3aUoAxY|mufvPfrEwy5AWq+X4$2hknQ&~eemUA0 z=rgG-wWvNbEAtpCH+rAWmzpv2L^BXGs{^q>wHXVT*9E-1%^L`K6JxyzJLJT^Y1GFi zG9X>`W=XWUS~4dN!~)2F(0)1bhy;+&qiGDz>%9%@#RzZ;hz#3WgcTC(`l5Xa-N~EK zT`R)|=9rX3hCp0PD)hw8g_jVGv4CgC7W!@q&!x~w52M$Sfr9puK6vKzVJY1_n6mh&ZpL-jZ{gaKqDbM3^Owet*mrX~z?f2(;{k zLK_C8QU%U99z>gK=r~!Gle3Ec7KI$slnOpv;!sm+4Ut^OmX~Raju7@y{mbOSh}DIW z=o0n54m4V4U0An5=yye(1a(;w9pSZypRL~b5AF1jKD{NV8OKU@p;K_5gnb^9wI=TU zcCBK}R5;!JtQw_Gfqp1fB3mDXxDkQ_CwCpi0KpnmS&DQbiRXnpwhCQsO_JN4cUo!z zC?x^S4mXArx5;p;ozfvLq``_*>V5-tk51JMUDV$7LfuW_ChX6PaKOmO8U*sAS@z)% zz)LCYlM7F`tUK@2I9ZIEx5|C1wldTLNbn6X-9U9%h?|8-q_Q$R782nmDWz`4*NjHv ztnME1(t<`Fz|s(N3oA7!=IC_FrN>e7K*K7qXyEcGRt=Bws&KZIcxpu2`44tn6v+<9 z0$XH2RqmWhYtHh@#6GNol!x;MKX`fCkTaG_+?GHr$)6N>?J1Bi&tPRRL+}ly(3#4; z+OACaq^c`sZ`r;Ebzuco07IH>Boc<;Hf3>%ta0cw4sU?+sFwOXMP=u7T94Mrs0h-# z&l+PF08G`Ixt#+}INzv~g6wka5}jeJ zo7m#%=d96;hC0q&zs0R+>NJ89G}^zy^x=j!Z`1U&l^wr&wttf@l~bL_ZL2 zc1#ptOpfj@!VKwa0+o;oD>xpeu^c94`joTvEMDB?h{qY_w3BBEt(zq#7F zP_R0CXjT7_-$I|%FjR2GkPB;IFS`al4-^&MSr$S^kcPbk!CYyS)okYGWsY)jzYNp; zFpr4Vv25QZTMba&np3TP%lPi4$>1ZDk%uq#3W=V2z5N{wkw;FwCD;|f5uU^1rnjmi z8sh@XlW|jh+sMDLYai8H`>3N@m$)(2#2aty+itZI1ZFJl)21Vv{8&?}5 zFJHFIxc=0%a5&9-@xx1ef z=i$ADQh0#DkB`Jr5nTqt3vK%X^pPW1$1)gLgUPC|-Yw29@bu)bcWnUn;imZX*kM(I z3^AEzMOsGmv`%Slox+*LnVH3E-3GX(M*ORuetOm9tE&;8G_BUfmyB98QWCaaAPFGy_H7t2l(JKOh&@i&VUi6I)3-f)g=!$<8o~KNK}qc+UJ9=|*!N}eXS=!Z z2jWl}9zJ90Q1j1&O*0r#T^>)DZ5$f>XE9|aRvLz?a%=7K9{MmX=H+TQU5=_7I7$tM zRVV~@k6V{Y3*t6p{xu73QHh`HfZG#G<2uvP2bS9Ytq&*L*{k7T!E7(ru#+P?lMtQb z&7E04nT3Ni;q#kbkFwJwJ*m_4}Tt|zkcd5nGv%{lhwZGKD zUfzWsi22cKh1Cr+re{pzZW&jeH44+!TIz$EaZmCwnSf`*B?9g00sdCNKUj23f^f4< z`A6G4wApuESJt%v@MSd zmrKec{)0C=Xm|r@#Mdb6RX-2h5erh1}VZQ^W4r^vqEni@fQBBOlq~qh-G=a zY2$W|8|fa9%rs4w$|pilWO|HDZ|5wgS)nzDU%$a?+IQyb!xv0YH4Yx7ysT3@q2g3f zURE5yXo<$v>xNzqEi37oCvHHF3-oX-TQf82;k(|)3;R{u`LWPnpFbeq751~cvaPHw zDx0M1l6TLyQuKOhuR^+);Znt`iYKh>XAk_-v*kOSt zF%Vy-ip-PZ98LbBj)%_kcO;&|9u>Y;b=*Mfgyl8%_G5A_u=I=}X_r4ZIPrl;MYAl< ztz16Gsze|A?5*H@hRm>x%&5qo8s}t4Q`qKPVoJf+c6v=I*-%Wp6Q^m>EfExE&g7;rweQk?CJZ3B==93 zblq+@`f&=@Fygn^9|H#l3toWz6!DK|Ibch$yc^ou*VXE)jFIgkra}WcW=^Z;aJ+g;SX;c>h0|VMn5|!b^Zjax02-1 z6KF#--Z z6nktweEsc6>#*bB6t)p*+a}t$zEu^t9o&LUwz4gVWJ4zMwY?Tz<}7a?a6#l6S6Ms2A?DsuvW|$BA{NeHAg8@r9Z)u_N;y0DD z8RbAWj=+wJ_=q^RD_oN*MAD%bRkuX3%nb_RLbG)?eagzQ4G)uYOl)6pBx!_6467g6 z-h-0}1X&}tS7dQ)yHtS|zdtRnT2&5cuP#WeD5!2906(HzcV!kc7i7AU_jh)g3@3`@ zwPPB#(%|5ly1{Gp$}~&81IJMh{0J8pR#g@9+5v4IIFBY)7GxSDGmBI~hD&bsZZ*=x zHvLGqdeZhAgsLs>gFE0EFWd`8VC@a&^$*ZDh3&J7xLfp*H|x9B)Z=|N;v?Cf4+8!3f_8G)yn1Y# z*ZmZO^slpbBb>#FE#A$t@@9zpVpF$dWTtc`Tb4)@us>^S?3qyC>jbl+xEBb1MI1tb zKr2)2tE&v=6cptc`GvEJPATCu^N7~+3#YF?{q*%wP^h@D_Bs%X1FJjLhx&^1YP?)H zJ-@Ip@%?y7+&rQ~S4aV;zmW1(O*#*Xr>YyX(q;36*T9p6vcv~$8Ss0QH48+BO>D=T z&~_yk@)E^0Y3&kPbc`|fT1IH=$PoDCBtv?As=t*6xjq^>U$<6P48g7)wkSCoz;#If ziowcxoX?#j(_%PpFftI8>&PbqG3>@YX}>-B%i5xBzs&&po^{x`+oTI(vi4}_&rZXJBefZB575^&ZWMRE0XP6vHcelFn zKRv{}B8a7k+dafgm&NPJvcfqz!<|^nJ!Q?!Wr=yX4h(vEu0$k$;#KEnV@Z?kNl#cquaCA6F>~(N+Bfk{$w^Up$JF&Biuqs&D{L$X>I8iMuDR=)8pzCv!C-#Ad&x@O3fp_Q#%jYs>v6-QkTi2FP)&iRa? zQ--W*t;GLSlCD%dSg*4lm$S1`+tWpuLW{G8wFOW^k=wBfz~G%ey0%|dk`&8$zJJP? z+S)O->YCco{=}U^q(Z7$gX>1u){e$BLfQD*FxG%O!Q(}~i+#a%*l{}2tK8b%K^H+6 zEw%v~CLHmR2YKv(%Taq%TV}Ycs0NyueQ#@Of6o(8UQbqu=0M2H?q=nYMgOAdWBn?e zSyO})kU0A&Ps%@b`abrC0<7cN9R zwX#N)dvx)wl{k5YuBz!rSF)qBb&}t+L;AJ@7Pr22I_FoNaz#ZD5{cvdkL;Nrs~t_x z%Nz^H<Q+dsdEhCK2iOxAs|#*mRB(V!X=(QEH#9C-ZG^|*sT614?9{^49G+&1erF$L zkTmvbeR0i_R9I!SF|WK8x*E7$P=#HlQPWcH{sziAl=i$xKZSE}w~LV@;)IqY3WjFm{#A?ND)2fY)sir>O3vbG78uJ z;&Pl9W3M;n%`O{O+BVm4c>%8Zrefwv}<1=vPs{`%14b;!8_>8Ot}X^i~9LC=y2d%GM&w6AF2(qSneKD}Ay2 zj_@h|A^oSCURD9Q@B^m*qez9<%u7$hgYQ#szybl?0@>-ZVjw{m6u0-I{%|D!!Hj;8 zpdWe7E*-EhkYTsOMtwPK)aka@xvjkm3w7p80T;D2H^F1iRt7LVit|PGvVD9v-(Q^A zQS9e}x=_40ac^-vRHs%zY~%m4*%@tZ8QJS+=MNc@KRYR>yFpJIfjK$1ZIhF|VLgnC zMAs;Grf-9sq{D2)7eBC;x4(SR_o=x>Evgu-<@*+gcFMK6-0b8m1a*dtuCT7Kubs{1 zybUqX6Y$<8*BwZ506|?boS8CW&b14H$+pRN4CFg4>3C0mcf(Z_7jr3&*@_kQupR8x z#C{_rIKZ{nZhNi{d;9{(ukp3}4{E2ELc(;(O*Vz%D2Ia>J+{SQi_Pl22FIyR@*+iCd8~ z7n{%++xXvv)}++k5}^aESz6Ltcv5*t-E6U?X3zG*B6oA3Qf0us)WaU5eFXTR2dj;Y zj^m~{4u$vF?l&JD$A83h&@{XoRR)*?)MO|d2`*XuP*71@+{ z<*EtSU@?>Wf8SNDz-7w5mxI5eARg372QK@w8%aDi#hYyFHK*fq9Kd9{I7kV~&r+w` zmb*)W{n6Hl_O)~35JI^BnB#`klpWX6KZq`=KODMAtbY%#4u>%_kL#Gh~m_k+YrIWQjGF@8XsI(=w=Gw~^}*fxGZJNQyh za@~|IGbjqK;H*_`BLb*0wGRp|+G|%h!0kmfnc>9Z%rGw(K9#rvC!E`4#m{FOK6^R(jZg9WOcpv)IO$ z);IEMf7qWbC#WmMm)_$~9Kw;ZOXIZxU!oM=2TzF^CxJs}JoEB7b1t95_l(DuuBRFM zwEoZHwYBj?sW%vi!j@he=NFJ*&gH;!s%K~@73eXBI4WC{&f%cqOt?VCY^=hA z;P7M9s$)0lw-ptIGYjQ%*MJ`l7&U*Cb5++I-LC7S?a@$3E|-;-DwR`So}<2BsyMg2 zJXgtg2~zDfVW$`gN=bSNd^h@%-%XNzahOu^0jxGgC+rn{4cnV?d`?z8D=VHz9J}pY zjZaYJmF89%o@msl^hT{p_$hmgs@&3ieqM5By?=B!ekEhk*gpM5Pkxg>G@u{-vQ0Ru`;E0v2f;T0PZ*VxE)P<5d0j0}f&9o?zhv&vVMXUAgM zxMkt{ZoOk6v?Jdf`tDXb(@&;kdPJ^x{|-v|O7?ovgRQo|`M2pqiM{bY+vs>8>Gy8- zX-5%kea)bY@%E1Tcee-5YYk9&VO@t!5Zj0ly!hE#vF+Q9V2N&Sse)BC6LGM$x8U%S z`#W0w$BIVR7&uHUaT_5u*)^m?rJ1Ja#vV70A{jonNB;1NY5MeeqdfH`E+cJK`C!ik zBjEaW7oP}^u5KUbOY@}-Y_A!+tfee!;Ttg8ik7w1R~JSt*&wo_h1F$4gOIJ2_Bv9f8tt91N7j!m&#UF1H?@Wi4z_xxNV8ub{9_|WW+jwaL>LWzIa zvu@NVd(N>}WQw-s*h=V@8ggJ@0Mf-1o)Dm)ddMFc|d%|1c|vK0y_PX+##QfFfu6lLSVz1>xNW^Le+zRgl`T>%MWdoYs}AI|DdWc15L;%s=DZs=KgNKzoOZ5 ziP~8j2$V_!&!Mj*rE=RDD{`ZWYvr9Uh~_40i(Nin33z+}dS(%Hy4T?QoQuJRO&uBrMts$n%x})4|Mnt((CyC0< zxNr{b`JRkV2VB*&z42GycV18XXd^?8t0wsyJ z&fKtQ(S}hTkH%ltF-&|X=D2WLhHl1R%PKcoO;=v<$#j3%@Z;UpoE^$HF5;=mHOA%k zASu4%WUALVVEVOAoRgQYRBXp69^?(WJ)GE=_*1{EpjWxP!9=6-1VUIAe2G1pFXD;6 zZ#Wax@*pcLUwaB$u1sGjFyHcctZ*o_B9@i&NXX|O5ehpYYr{EN%Tq61F+90kNC-Mg z$>419nfq?853Ra)=D^bdqXpVYdIALbyZ8;8g=RxsIDCD`EFR-7@HFHI0xN@N(YM*p z_1Nn=4ZBEzQTGK@+6+ATv8FwO7f!-ow)qdOj5f*#yTsgXe<9NpfhtTpbt^+Bd3mN}ehW&-Luee{pXBz!f#3LG)k;YYN;r!gXp;&w=PV;#K6TU;jUCQh- zF!2HrpN~E6U{3Ljd)M|rAz-fBx(@jBnZV>kcpDFKhSHJ~#6cCL16_`?D=DK-rbu~V@R_yWD zX1LuMwSG^rsUAJLS7-WFjx}UTAmlDDcZUK~u-a4p%N@%y?lH2nS`)7vyBqt?nKbE~Nj$Nr2x{?z#r5^Y zMN^MzYnRPmY`=yH_MTVhh&dqMTV+i>Fh^!pwq|&D?(}9jyK{#QVq5d3n@pb{^SpzG z+uxJTqC(_8d|b=P9d2xbn%Z3N3bQRmk}LcnIsO-3@aN3I+FnHyUD<7-|HH)dd|R*$#G1t6tym|?`Rqp9&s}5_^x#7K>v{NYRm$cp!S=ed zkLlQLtCh`-&B?p!EU2!Yn0RMWb#=irVjR8z?*)l{a=ieC-XX==*~Qrx+X_5StS-nO zT-MQ1HaNean%Ba}oLyb8UXtRH4Ws0GdyOEyZ&bfEF;zL!vHgfPBtO`@zYXdbotH4z6_}?Nx z&gA0eirVWZRaF=8Q`)Dd0hCWq18BdR3Q&HHId}*?K=<7()rX`{OQO2j?)Swu4tT9i zEfq~|Q-+xi3XW9>oYn0LdeIY1^OiaYin@+O5Zm)%JH`^5k;$D_H@^KS{{I+5F)~8H z0@CesHe$KPk(z9wOq)m9Ai z4IY;atF64i)81b~`?q_3;}LrW{yww)E#Pe19+KM0M!iQ+jcSUgbC$h@i7jhqH?_5L z=#Cz>PLz_a)=C&??Mr8;(5IZQm2byvhfN|MS_$DZQAZUimM7Wv$S~6znzW-^Cna9e zVKu2hs`S>wALMNXwZZdk*S%ek6s^MTTd@KfA`e5_3b>wNbupSHYE%2N|&e05x{;k?$xN z_LSvGgty{rA;5PBY+LW*OqP6yvKIJuuq|zoc_F588PMMM=#it*feRlkNh+19N>W)WNvD!ZHAy;Y(hJ>mXhNrjUZ6#c*bK-b-O@S@&DOZk zEFvPvh>bdc+u(x2$m;Tq8Am@`bR2bB#bv$$#%n}n9A)U^cR$a2PF1Bl-5~S-*Z=+3 z^+D(C=hVAC@3Y>|!vxSIyJ-7x?fl4(QhB(CiPQ3_-E?QsMqH9lJwjI>f%h27G1gR- z-<97+mf0|ks3!8T0iJ19p}T3-QKO1^jrFN0x<=*Kz0OCRLE{mp`KQ0Agw62Ck9HxE zpIoa)4f9_h6n@(mc0S??IRDo9&;{?Wgq!{ps(f^<`LYzd;qNC}j3|DAd;&;Ef2ipa z8fTW223;^JjA?{{M_s1Q(Ev0MsUhqE$qm%ihsHs-VaQQ4)rbkE9d#^$WY@ldL4c8K zor|3a+W;5u?-_}u3pg0>i5;LRaUj++j#Ge_?zn!(@otUu`0)(9Myb15JcuP@o|AhE zX?C@q?HOl<+IWvTO&6wj?3h08&EAtecpX39gbcrTG|jWWbSz|uUTJu}^`onzu)(so3+^|9ZxRiYmD-ZyQZ>9-+ zGr07wZ0TM6;Pd?8Ex*YDoFy9q1KWf&U|%J0HYH44p95%`>gn*-ys%WYB3=OLQ-9*JKtAw%BGh80T0)8c;-7qUc6MU8LtNW241w(r z2u*r%wj2M;zjwRu3k?s4B3!)p9^BV4Jlx@D0j_kA|KoL0`2d&EJEx*=&O_Gi`phMA z&;7*HR#6=up7tc>aY%~lD6!Z?t`LkR)KcmOEL7r6h> zxFID1Pk1=t*vhxOH9XWHNtBOw{+~P^xxbG(TDXTM15BSD0~@zteibt!`@?L>JnRWR zT*|tGozs5$AzR>0%-4A6{9E-tW)zy`!lX0=rkw6PK0-Y(x^Q0yzxdF7s_*Tj>Zd* zjo;3Rd#9&GOR=>pYOe4EAEbvK#B*PbcC{8K$d2sU&B+gV^Bj#V^=|o&J3t!=SMWQm z+v>(zxg0je)yNYv({wib41fxto)Gae(yA&Tn~6Tg$y$V}qCyaN$)}I)BuDK#jp1st zSU~t@v7jwt8S+jI#8EsmJ8M2GZgo57^=_!VUiP^Ty2yIct(A_&zNPtK z^V!W`x@G#!kg^ELkT$b>_5i(5JYyh`K}?Jm%rAiK07zDSOKd2NP8iNT#z8O~U?m#2 zduI7R^HcVxeCCTUpgkzw>jA_xyV;YlfH>5drp;)L`KF6Nk8IASU;x69P28h)P7r&V zbq>d|+SZBHF-uC7{8Z40R^a5ARFmnbQ{phYQNhV?8r~PY;`QwH&xS7Zju*OP8!i9? zD#UsG5UfYg@g3YW7JG=F09YsXlyxMMQpfT!YLi&E@Va6#m)Bg+_xAF03nDq-xnKht zo~=;x(5vkjNSc?yB~#Xab-sQGKEqYB?b+055IP;QqY}+lHXs@wAjq~?ti51@D656? zD8aUd8lM~428x3@HG8?Q_(klQG2~qe6W$A-VSu0^diZ|cKL%S zeUVrDqxvV2H-OUsbtF(4MvrqWS92f0ZFIcnq`ao(wRbmcgLJsn-KoBUr zD~@x_3@h*%2venW6a?oJF`LV{>$_T_>pz712FaF3@ROq=Y z+pkG|4BoBZJH`kL9`pzXgt(Qhv_IRKx@LO?zOZP`qb#ozF0l)oE1qAn{eWn08?H%` zh&xA$1qkZU0Oy7i$2tDp7C$h+VE#5h~}U%sLJZ+vJxuXq9P*R*y=}{mKHf>1?%i6 zjfKi(As?^{C%$R*<>&clpDAcQPd28vySE{4MVr^*^A5sBQtx5ttEjw3uI4Izao!W& z5DEkic;b0?xUnr?X)K<=w;pr*xMT5Mh>zjO7;NDbaJVlQgm(pTSixyu%OCl>fmKuy{{yCbdw2qOr>X;#DwsYa{Ch<^B zew4>qqkmrTZ{4s8jZ?&MBlQM_K?#x^|E>b~3EcopOB{?c*lBpffDjR5%||0kQ*p6- zWmh;DiT14Sjz)svC-kk$yLRSc(R?hC35PS`4=hE;hw_kfnPYU{;oRgb|9g_ zrH+GGH1H37LV7lpbBlPa1|;h`9k4%aPjp)Rm>`y{sf^EHtj)8%?=fCO`pKqrf;9v_ z4z-aFkuQioZdgAorD&Ew|c7Cl-(}N*L5U=i-hTVW^Q@5{eAT?5%^}(Q#^HF{3Hc*?q@dtfz09W?IHQLfjunGP zy1_b*dK46)2?{Q?n&&FD^%D}$D7ZRnMsY9{I3KypUL(zQV)NLh?h7`UFPDWwjmrsM z5Rd#~)0o)VRyLpAZ~^=`>*JF&k^ST~Ymd+b^)!U(s719Y43oX@$X}Mn08Q6MT4O2h zp9=fom~}1<)QtXR^2z%}K)Q{9=8-r#@&GyGsUdndIdFx=yJ)12mtAzD@`zu%!9X-R zHsTUoNvH7=&n0_}CN8&+P+%IyXq_9gEQ1tANFh*UsUq5la$2jOd>}tiUYqsyjC-EI zSbUOmA;!RsFYCXdKk4%qE>Me}be)o2TOP=d_q4atpqs_O8l1kXke)6U3eo14T)H40 zvAHnvg|*A4)|Dc8_8pJou~!y*ZWO7diA|(JQ;Z|%JtkQNhFT)^#4R0v&G{Bg!@<}} zEGf|-Q2)FkKlv=f5*zaOW!rm?w+t!e&~CREPsbA>kI&^#z_mC8S00x?8P4^W8rDk1 z7m**=@z!vAtt3&AYC!SPG<*gvK@-O`Ui!qbi@H!u(hq2vUP}SHYiVWgn9TH`PAdl{ zmss5`M(G3e;9AXa8F&Y8cl2a9AC_leC58-_KZiKU2Ouja*>~!=J;HfSMq#!^lM`+Q zS@bDD8LWsC+4kTlLzoF<_U|f=)+m}i-)y!|E;Ij_N;%=7lN)zwfwq9=8qdKs&bidZ zJ(=!Iru*3L`Cw{wO3$REr;sBfSFYfZsf@nV#m&8KZM|*B@-)b4a=eje^V$aW5{A`L zc4z9IV=JW??d6U(M|3iPTv|~_(pN6~l8$H@nUyAwse8-lPN4PY2j z=)L=tiJ@p- zL!Wxfa`h#QM~9~!n8+bxC~UZX;G<=T)}oLv)?x@x*a@>CwE^X9CE1en{mV%!VM`WB zD%S_JZY;4J|4wrWl~8sq7^ZA6t7>gA(7>Ov4a9O(hf_M?3W|GqS$bi-XHRP+Ef9M&HmE+N&a5)et zhlir^a*PP#WlT8_^Ri-ImG}_V^g{`!^oR7a*IP!D5pELkKz8m=m2>TwH5d8T5TnBG zCo6zB2N0aNp-wARbm9nOGT;KmT*Z~#&k{4lLz2} z+U^T@yMT6%bgV#O|4YP6(Ji$j`cdZtNjGs!xf}Hojr@SpKP+DN8+8s?<8A&@1AhrM z4&1lmi-Un#zs>6`mU<$bl(Gwa4+X|roW$AG;3`N)JTg0bpnhw7MP2`>>amsm9ex4( z(mMPa1E;|I6PZv!q(R$Y-@`Hq7c&sQ1cgH@ z011OaVQ^wo48uWu04m5<8qy6riGjuZv6X;w!BI?~9M2lDq2a-b%NNX@obE9^hA*=9 zn~$9r3+v{6a7Lu2hoEbT<=@u3g#Y()gX%~&L_oHvVCVz&$A^by(bLtP28+}7wfC`9(m>BdA0&57-oN|OR zH^zOzA#h2tA)n4@POUYuF{&lj$1_xzbiR2wa@LvA^2_pupkLkq6gKR(ecuWQ+>R4} zNFFxy?&j4AL?R7bw#@HnPpoS0GrWdBvh~n+&WlAK)bHakoW-Z)-du2#Z7)XXxy`nYy(L62bShT zE_1qlD%k2VLMOx9xFzmz?C5JNre$-m@A9FuM^8$)Co1x>V9fO)Vu1K9&$fGz9JRS^ zA~q0Sr|YeQcq#2|?`~P24)nOYPTRcwUDdP6zk6#_S$aOXRz!-40K__u{=*Uec5IYVK9Vd@^SqMtJ@1 z`&LsqVPAyjK zd*>@sn`&jaD$nMuTA~GGyu7O=n`tFNBbpwCZSzgAK@B!hmH`X^C{{r{cyNO{a*`J~ z>9TeRis3Mgpec+RJoBSe!~+Zim^1R}p=8UA?nn%)YAoWuu_ZZ_&I2yVH|z1tQsmHV zbJ4ML*}$(thDZZ~0bT}4pZTvw=vM>Fb~=j9vv3t)`EU>0!<3B`s}g{S7He0K@ojY2 zmfyN8iAWso45d~Ph=Q^>tWJhIZ-Uf({f?(0hR?5+hjIkG@D#5vE1_r29VDUp`cd3l zI}chr%R16S98Gf)h^C-;=sDkhZ;O7%D>us~KD&u|-eVO?2?nvzF38X5J(%&ONDRGL;s zWsAB!jTCMp#SwH5R+viH1d>IJRN^C* z(V>ybvg!!L&t>EWPErxQrjnt+YE}gOPLdCKGL~Eh-v>>TUUl);=SRFa*s&)JE9#T)BXZwSUc9c_8HL3beLIzuVlNYu+Ia=dHbLG_Hr*qCV9PFX zmvg&8i*9-&9kOfMrVci5%d64TchXa0XS#3z&+ML~XWn?zJdS~BgX6JHD&7>*rINiK zM;lXiib3!?^G(;I9PI$U4!I7)>lk5_Do_6<{gu=2q+q84ac1PUM= zLRRwe_~$-gLg@D@|kIHMK5L=@T^?+;71N!NaXsO@h&Wg*FsT zOE=UdiA2||JVR*ReXqIAmTnmB?b+Vm)YT*UN{licJ{TVc?{^LRxvG5YO&C9rE*1GF z7D~aVEI#KcWGxSL|CnTbpxP%($Kh!>hf^(t`8ixO{+T>^N?D27LPSwQ`s5HBKYj%TAQ<>xv)gR}LG z1@A%KK-*Wz_nJORw6ifD4OCX`p^|>-8C)>GM%J&MyQ=$gw4&~n|-telI6Y){3 zLZ74N7aRSUXN~Iw5bGMV)S(u&(o?=`Iw3xW1d7WULsC|FXMX;^cqS944awn0end(H z*+tvh@kl0a-bPP}i{qJNf42!FHpd3qTp3Ujwc}2*JAsE{nv4gI`~4#?sZXn)k)P&* z9r*{|-Crvn(H0$i(MiAye*h7$6zxRb(oLP<7r>tpTS$@rDk2CR8)RmGSg+gNi}hZw-Jsz^{)5A0F;+TXkB4mHPN#2Zdkvb9%;U<>)O?nd1zvY7=B}%q zf2TpgFIw_&G(+Loq7m{PhVDW44fu4`PjgLVi+K!I2o-a19&@ltoTqG|jD%bh=NpPY ztT%!nqYv!~iDAb4HVm+At6`PMVh6bjsqiZ+&tCaXmHYIKDROA=`6+(O?e>r6Md=6X z4($Twn>dt9ehNWh7v4Fp9J2vGMV{}*W;hR%hX2d?X{Gibtgz2RN-s^8WVY*vHCSX= z33e+qjDO+yvW3P^@JBIj?e;L>@waJlo&ID?W5 zxr8%CVW5RT5J@99=Rso?CXue{BwB8wLGL=8jprn+w|NZv5Yn6=p0(PFZmlDK@9>4A- z<25&)dD)4+Ouwc|;B-8+L~D|N%tnqMi^DqxiUCGaqeLr+`z=<0cgAZ9$P*l1$Kkn- zoS?Nsg|D{%wAGH=U;z;wT8mSN&3niTm^L#DbVM5kxt7;DG_TvC-R7vS2nP0l8sL6XCSx^CrI;59rQlR5x6%fZy$nbs@AT zDr83{nQd0^GRTFz`@X`4bCO=4mI|*}HZ*#k_zI_iM_za>9UdPje+`IBF}Kt0)g3N( z$Q8^oH-Y$N*^=u{Ma^fK``Lfr?)6jYYtL9-9vF+Hk-I5@dTT)RS;_I!G2mFhE2K$f zi9)TZ6QIi>mm3@12^JG}XJKa+Vsc0aS#xHzTwJX5QQJ4Izr`B^4eIRLDkSR!^qEoC zZ_v3#nF`p&LH3+t0sq3^6XaI|nl1EO%Ma zV(d>nXK%eCv+D^AZtKurs5R{lOvd}R)76$y+V7>Ih8p5 zbIWRR+co5j5NxM9TPSb6Yx}upJiVwtNITZl1ikB`N+6qh!g8WubFw|)s0AC_{H`zF z^*l3lF4c_xhNNCyom#DVw{Be#@E#(z^N`p4JogWNtc2T@Iv5Q zp_l}6mC~AmZ%c}_xS4V!m}k42T?gF~`43(cH&MbDT=6`FZkyKpDUY0`1ZfAg8tCINuH7~*J*fb00afLo#{6|R{520DLZ9#i zCP5Qv<;|d%iH#=_f>kRB>Z_S}T81vnLo_9+I*Xs*gN+9fwk z50aAcV7ib^I?Z1raf>WW4X$>yi`$NIu$pK_6+T(UwAoD zRfl61)TdYo$ypp@OkPGTq&Z1jG4uW*OdZ5J#*O=pU`#$%yYrQ7>B;vG0rv?vaW4*~ z0MRtt@6teqFXRO3Xz${DHbCMaX!`mOA@I=V-3u~q{{B%)YjY4I^tRd?~1whgFG3#b{P#R z`92NBHhbpvyxUJ5>2dXHSZL;13;Drq3=eGQBVQpbH#Q?>8+@ z4FzD@(&9QDU1x41(TDu0L-hL*wnvb?0MZ7n{73!X(Vye;*Za3N8*3A=HrpEJtqyN! z$ZrGiD3exZqno9}`@V(ut+x{y{mpsTUvK`G%4+l|jUl@qbk?|AZ|gboUFv|!TP>6M zu6N3a{{!FnfYgutJME7=T+ayf+4&o8xDS85wRDQqb{^r837LQnq=pM9ylfQ`TiJAl z-#&<3rxaJ8hEId?<7H2m46U`{0ue(j$^=GjfHe2P1r;O$JqX_nEXqtaBxLSk@frBH zVB+@A4(1SLb}DiyU6C$it_19cXr~+LJ($|^5IkB6>GO?hhxt8mE5H-dg$dW+`6A|} zh4g>sBO74)n&sRGqQrq}3R{UVP+Dnrfl}4h2mC5QS%IB}`(?EPKu@6N$cmhzR0rlq zXzPJ1<(hTgc3B?v`yE5_$CWO#m6C0UUv^c@7a{@R_4K&BVTTC)s@-YG%&*W;Xp^g( zu3_JlPDamb>a@o#Aw#pl2}?LZU4bd1VN6CV8c)e;6n|(M0!r<2iu-*z-_N0B(A?5< zN@gxo8H=5s_qtnK-QM#?+S=CQwt3RePdb09aG_HVhjlp8+~mU>Ip1;z!hKH3WGZhc z#NtkO>lv+X=Sd@NoA8d$T>gub#QQHOOgi-NU|4q$6ae^=X-g(Inj)~*T!d?+5`a(* z_Y#Kwf?}le6-5CEU@*DDu?qmOm1;plA7`;N7_43*qw8>#I2v^u5P-v$1d85-2F3g? z<$4hxuzB%Uk_KA9f4XGS?+*!i*|?XI(7=>B&$(d|<5xJ;Ew>CoYp#61uj%kwmvmy~)PW1s%#Ej$K?2zlb;C z7bgjpjeixo6m}mjs2!8zVJyL_6!iiWG;-Sk);z`^9wm!A<-MtD4B;Eau_PmTu?s8+ z=pOnXfEp;HDz?X;DjA`S(+4lji9lc?(t4O@YE46=4-GjXzZq`lga!k&kQ2xnDDRn- zKv9#kG8l3V`=pZ|@`d#YuXjS14@44F>wj}QjC5*w&=4J1Vo%}wi+UBv~{!@2i(RjRDbm1jkQj^ z_<+M13Tn%4Uj`+i({Vs=E}e9e>e=T`3dLd}^QlDQsQ!J~e99GsdHAA>5TX)viIu*E zYp(_Wb+D<3*iePxyAmiJ(0nxXIfb6rlx9TS8oHV0Aay@TuX1PN6Y_d0#&Clq3m&X= zLQ)jnfeTH8_Or3y4{W%g?b^jXElNm}P3p~_al~ZN!Pur37M<~ZIKDvWrH$Ru=F1ms zsP-@FTpyBmd)*;TAi0zRMBg+Src6`T$r$eYF0$32Xcxi?`x9tYRC#Alo+Es^jbRf|l ze%R7$6Lbw)fpoqQ_r=E|8AF=_qfAX1a!ff}!_GZ?jZV3jh>Zp-&bP!$b+Vv#>OQ(s z9*Tx^Jk(9y+KpEeu#xMCaBf$6YTOdf;2m6FAh!M~^*(>@V67Kve$E10p7IHGf|EFz za=6u6z^Vy!PAGX70cp}8RW&7J46}n+PLW_81GolRMltg?*DStiR~LnNvp25KMlRUU zobup|tM|EGo09tZ&~^K@^E(H}HhqCp8y~1mWV@PXJIdeQ?3nHB*>HiO-Jxn`KD%kG zw_uzPQPSs;=eKU!)vJ;y&)FoK=da3_WP3%N!ZloSm1rz^v7r{#9My;fO)_9K)^3TF zgarZGY^l}aPV-r!&g{Tlzk2LSW45buTMB$@w_sPMQO<gu@n%>&_SWJqS|+MUu3ksa%v_WSUpLi(bVaO zPM;#7e{yvoojJ9Vt)AI2+}3kOTBOeCZ5!_B{%Z=%;6|L6cLn*G_G-9qV5j|>{hgit zeUWPW$cBt}xTB|eQ%^SAb4GJ_$1vQ0VEsY!9f0Jdc=r9!W!(+AqMLpFP`?IF0ho+k z0U2wP;1mI;?8J~xCME?X&|2cEyo|xmCi|zLUH^RBilJ5aJyD^?WTF|YGC zOJ0?Cuk1I!MrdeaqBJSR2cwS6ikTG|N5mP6=z6T@yxzF3M`HSMu0uXkIczBJ8gYy? zmTe;$u=vE(N6s^}(bG;FHE*CTk}F(&?y09=dOH3gP)*5@gh_Tc>{ifY*1mv#0_g)^ zj!-TQ-j5pm(k0H3-<9V#zKt*`Vv`Hxm5#=ttlid?LGts%GA1S-INzl$pPgNPW4kWG zrC>OGy@U4H`n8bY;WK5uw2e)Y9EGk0@?XN?gV@U^F0*IXw;M% z@hzG^i*h4M@3i+{Aq|o1cz3li}Xr^mMQ{oOH&f^Ruc;&VS(iiS65iK5ESE z+exjmZ5w(AK>&OveuoCnPe+#reGYor;R`O0PUoo?UjO=k+J;~O>dWohNYSu;8{R@* z_-)&vl;OH4?7_QX-EW7yZHe?2^TWDVm_!vzzA4~WUM31c_>V*rnJYpY;{I~(4;LmBZge1OIOgZ4fook`>mIR!=e7r-I+jt1dr*1 zs`R6goIa+K0+jmxwQIi8+ zDVflU)3;w!Zc|mdYKaPnrsI0EQ`Oqa*K9w1g;mGvm#B*Qehw>I(w!Z)+6_(1<%_`8 zE25tW1?d!uID}A%QAJTwM84q#-c{+s@KUJI>LLdn!E=?WXGOhYZ=E^S^;Q@``0l^1 zyLa>3wsyCyI(^%UmI#Qil$zJm9P>nUttHXc(Une|^7#f7p*uLbFwa-`P~O|`=$-f_ zU~eYd;)CrK1S2|P9>1R?OJo^E?$)-p(bDMPnQ!OEr+B-K-`~T>vwV#D_OV~?AE0R> z?~_f?BVUgC0@8d6GPSa?foUt|QDIo+iKVfZd^X@=oRV%4^pd1;){@05z*8sD9L!I? z%doW0@bkxmWYwc(4lWzjBn=ue{F7y`=$!2<%oke3czJj{?*Zzy2*e!4mfx^j$2!C# zfDg$gUYAT>mYPm&PNgn$d(U}UGd6?J!?V}-I&a>4*|am_bbDN_#mQo;%M(f7?kG|&G4AF^c_J!b)} z{u0a+_WZ4~?oj!+kU&R`EWs%*i=$l{TV^zgk=D>SY_K?{ohu`8sN!<88YA+T4S?-`EfS1jCcnWpgO)joxE9f z-%SDMr0a4iu64UE)3q^b{@X9}`ECl=bjnYI#t@n%k1dG|SqKgR7`vPlAm4G|e`}3Sle|GUTM-0Q&ssN||u8%wWZ3t`dGRzb;Ay`+)eptE1 z7lsQ*ogX4h*|~HcNzP?gI-gI^(S;8XC@mk!$MPw&m9B|j0(rK6LYM3tsXWR;d@R}b zAArX?^tB*N9Ck|TGTW%wCq&4f!!+nyv7%3WhPIDv@#ub!|E!5V;p>~2=rdpJgYy;D zYbEp%e?s(bfwD`p;g+$1!7hQ9Z~VCJz*Gf6JT9a)Dd2eJLZmfpdR^J^H}E3K|{PKuV!xe@+mx=@Tv-i{lVHicrLtK9y$&ljt``WF^OXq z9?lEh*Y!=jt#Qf_HV?P^I<)&C$dJIP7MS(S&5@!fM^1}|b%iGncM7vcqY&Uq(>wYL zo5swi+-~Rc5{0LY_uTO2SRYW$`hj3^Xvg$J9aZB;W1B=_U=OFrJ~fa?_uvSZ< z-JdhA;opN9OEMY;L1M~L0gE}Pcb#BJKgmO|`WZDxKT|~-W`dR{#|roZ!OC-@DXKD$sADD5&23{H>+wxEewte@^ojK6(G6 zkM2KtcL~qAW{^1H&hoAva!(nXqg3s4W8|39vuo1?oPh_SEU4=Xi-e&B8DQ8FSK4Z3 z78IQeoq=|ng1RvMbz;bX7DN2nXmL~U3-16WdduAbW^*R)y#i8V4uDF-4j|J|23!Zw%7lP`YNB83_IuKdz2zhQCjIPu}2n3|^5jMtmfN$#} z+V2)XpeG##p;EACOU=KBNKc(tqSZlu-TdCLTa-|JGjW(4dJeNc{N{KDt|lu7%ufxh zTq!?fe$PFOhaxG7tMF$36g_m<9}fEu>ZkLgv|DkV*;6-95@-dmP?j3inXAw}blIB#4a6NF{;hxCFM zwBbtOA<+I)oeF`X8;y?caGvTDPg$3dyb20YAkpLEMSFmI=W|_ps*`+I6xy!Zk~53* z)Jt7HN{PGZe(erWNR;ot9TS;^Ms=hKjTt5SW=mM;C|jar9Wit+i7K>gw8{Wl$yN_9 z@`^toU1a6r_{cpfLNk=ere$xhOlK3Jx7F}YT*P*>dU$c9|Od2%9@?l!z$qdOf+ zoY&|V56_Be~+R{Ol@k)Esbe zgXV;t3nlG(kg7^hlhqOHiM9EPA3X-pqp2rSAu^r{0gCtgnBqEw@ z@EwR#7)pa#R<1_)x8|z0>#m^3;Y`Z7!|4hbuI!jwLWO&xo9WV&mPq@}c0`WfA#Namu#EZB+L)f7oh9sWJAUO3A$;w~6D6YwpPpQq()DB=}G^75+=Z^8r>A|78tx7yW$?Ue(Yer#boC`{%u8_w$7q21>_(%qpEVvAzvQ<;4W#;{$A<xK1+twR$sG!>)sDBo1Ote_} zGg2F`fy8wQvPazg+FF^G9@U!4oq}gAd@ypPutUp{uH(;bZFb10ePc?z>ee^EPkvR7 z{R-p3!#nf$ymP(EZg4fe^k?)5ds~TE08Uf;qXdA#8>9f{iKP1NgdKAqzpFl@)_Kwi z9%6sKT2?bwD1)IS#UDu=lyw}ls*Sq&wqbwIw+?&&(Yi28a2l{CIu>KOVxOrW`J$?N!DxrsEbx!lGHA#v=Czf^<=4 zQgk;{H5h-H+CjpI0!5RagHV=4JU_^x0dXRa)tDDk8>&dNYD^M`_y#%rWJ*wtB5$(* zg*qkKy{kKU3K>mtR%W24GCk0f(cuS_`JdW#&Dn>u&DTl4|BU{r&~*;rW9!$2R`x%} zp)60;9EHd$2rpTmpbzG9_$1P?AOwwmtvllsU!hO8b{+XId0i-U9RO_qxU!$V?ubMj z^h5nCH>((lsQ@hwfko}M96n)tn{ICUAleOrg55qOn4)>meD%g5mYuAQ$26>M^W@P8 zN=1w@cx2FgMY+aB0k2uDO#(iap4vInwsGWwKKjbyHm*0Qfk;blLu<0X)#Bz~ldEoA zUomn_fRLcEqgl6(AI>pZv#$|}%Prq{DxS?f%y%B^Z!ku1N+&Y%TyxAJ z?&YzviaXK#<-lsWs^LQZC0v-sV=sx88i?j@@-=T*HF8FNs5RM|ZXe3`rk^7(#`bhevX##6OZV*W%rvLk zP{Q2CD*5%y$A>)pK{etQ?Q1fP2Q@up9Ly)f`$P1M$~Ij&Fy%&TE(?t z>QHVg0!l1a3Y>g*kZGM^MZ|TFZ&<2Ps-+c?SYunb;no`$ulupb%Wd(M&!&5+&05AI zXp>9CwXRhou9-JQ?O3_uz_AU~J^^P>_T}c1muPxVR8E(RQC1zZ8w* zG_Ojxpg~8`+JiKYNY{TR_?oA&3VO+x3QLwBcpG}Sv#Wv)R6ye00Fgr20}w2b6YFPw zAeWT<^4prW`|WS<*kj(gTlc?H?A&AC@7I+d-Rbak{to2S8-extVdi297%bN?MMPN;{S*+} zF#D$JCvbWZak!}B>s>|omatYMD-NY1%O;_lYE2}&2Pc=|sPR;MxvR~iBTC!j2*gHv zfP+&7WQy0ZT8OoLu+r1oGaB~ka2auUGTmp672qkv_&FX3rF@VKw2qnIiMPm9Y?`-D zfwvX67ZZ>?xTagbPsMtPc3=NGhV+Bo@Qx8bL-MG zk!baX{XhWn`vbf`sdoY?i5&5i5kGTybwC0C`2Bu9sPvv`{_Xwlj-=sD_4tI_)tSIi zug`(GGK)AG(m#^t>w09aYlIs~p)-6fed`JMQDB^1iyL8$M*XEN-KXl1xno^d9q8GOh z83@ja_@4CjHD8Pa`MKB7+L6c>cX!&`T=MO>-`$h;rb}WDg-EtwQ{C{ACmoW|z6J~3 zZT3}6pQeSTweV&7M__?Ko0}j$kZg6NB@%A&xAAD}Pg^55MMehX|1jSlsl-2$h_%XP zX%%Oz?0{DzBCiwtbWM+FU`UgqpLk^cl8)F3J9jf!%uyuXJ}92a4K~Le#)7XSA6o#I zE`}F8{=nO&T&?L~-tevcOL;Z;_h(Z@jGzU-5on7%1WrDc8~pu(2kFhX`dmSg@_T=? z%qzVZ21FZ9XS?KgfJ4&>-0r3*DufwJPIV|okv)L8JT{SxQ&D(Lgjn%bpl+`u1JBGQ zC_~kb85K$t^L`~q8QY3F(k}z;BiJ~Edggb#Hi;*sNWTr(AWTlBb z$>2!X^r!zwHIL5BTr`s%9?oJnGuoV5`C&tkr^G-k*+Bc&h%iP)T3fBt{Zzh zE;i&>%y)VC@nxMGH+C-LPk7GzJ;GOYbA!hbFYqh$b|xEl1jLsDDbJJD2Q1ycy-qRZ z?Z`v7p@Qb1S|uxlpm<~zEBE5XANtV6t7>s`$qya=5cm-rYbOM>S%tL2GmeG*@Q6MN zkCb>g7ba&v;Oj`g4WJ`TU%)5L{;jY=?PCO--!Z5#Aa=I70V(V-_lUuMT^AeFIGAtR z1zfYoEL^>&4yDIJ`{v4Bi;sz0XTAKQ0MxCvmI{ilZ6!!8-~}Jf{&cbg)RIr}_S3wj zF=u0iE1bDS_(2J*yBJtJ2XI^?Qunis=sz2_z`(DIs_SXou-KZ);rJjO9?X&4H_fqU zKY=eazVTM@q)Sy>GRyGBQ6 zD$kE^NT)|%3gUT*gJ@& z;wx=^FcoQ6%EwFDBfph_Z0ULPy|^G)KAXoQ=6lJl;kz^z1?s2re}d}=mq3#qJR8q= z+Q%AZKC!Pv0lJW+8>q;=F4wB?c+WuFUOua4-X_O-lktfzxdm+grg3p;I@>c|n35Ww z4vcv{yvv1V=@m0mp4&0nZM5si0OQKQVk3c0muE3m@9j`b@8 zi{v=gfH%T6xQ|;K>=;%av@ZSj~2UfcC73+JTZ57|I~RQ?cWqk?kD*-@Ll?mZo2^V{UhJxvRFU$P^~<8RXgyrEf-MVyZK%(&;1aET`9 z+uFQ(4D%|C7-!($T5JC>322x{l_<}tTv(LOW@oHlAqL~OzXg7h`4RaTXU4j^f69FQ z23&bq+>4v$5dp=P(%aD(qkQbg%|VI9-7;svl!vJc(-wFbCytY`1gw|E5qU0=29vj^ zak6Dpm@+Wm12~Q#{^Vo!ZE>(`bRp>ZA+0|@^lU;#-Cxq7X!YC~@LU0rFW`Bbr(tfx z{#?rf&h}l~6ooc`Wthm;*+0mZzLPEWP-H{>kXD_iO4&nL&9KEW4lt+4jzh87X>hq) z$v2kT5HdSPW1S4DJnCe2CUG9O)Df{1Brwx$Sk2JtxDIOtJpoRaqRg$kbVT8A_NQ6e z2Xjkrf)dHQOWAPFj^6X;!r9U^h#Osk#0ymswz)9rpdM^Ee!l*QI7lzkd(Ycn68o;q zmaO2uGHB`;Xla=RXWo?Y@|f6R8IQW#^eeAa51`4X5nF;+#t~&mAK-DZ4SuhGC;uIE zr-b|xh*P!VVpK~&WTGXbsG&Xt`G{(dlDoSkFLyawJA#HA&cotOXHGdjq2!-oZJ^C; z8_ z3{lm=I8#4Cc@3=IkYl;LHfgjww;=?ROHSO$NEAHzi9G}*M*8rG_z{7yT^Kxf&3%MK z*&6H{+_rDU?m|WDX{8JI{Y|51Ap8X3H)ugRS>A%`n#)z}&CJ`_WPiVU2)fj}qWiX< zH8ofeAHm6xdFzS14eMTnx`_!|4GrNO!qj!Ca;QG}Vcem4MsVDe9FisTx}w5 zBVF%Zeo{|c0ytB`sX1H@4KC4oG||>`((=iHxF~dvL<3$#cnfI++>uZOWL*HE#vh1{ z6|y3%IeWyHh^j?Wm`)XW^MDVL0519#eafXrJidXERi};SGUuGU%Hs}2d)(ofd^Fa1 zhF9;6hTZPfE6#0hbGVkxh*c7F3yBo)wPFS1T=nz!;axWj3Px*j-oOG(Wyc@!q}1gr zU~(8my($SH+|VfRqD%zw7zAxxMSxcZp)v_02B>Pm=SnyE&Zb+MK7gKN<`H~V zZT?Z0+Np@@huo9IYhexIHHwHZ)JY3J6_JflR9K5dHylFuh1>Wh)-4($Rr);E zSBlQZ%C5|n7IP_H#v0LCah=9%(S{95FKh2lb5%Oksxk&n9o+dCbiaSz3sG%~nbNnj zOOO09RzLfz()!w;|Iy=?0yzqvV-DAiX!%SpXs0bZD=d3EQ#wm2+;|XS0K;mZvjGcC zI3_w9w8$B56l;B>8EX{xSrEYc=p`t8Znf>s(JN};9Wf|bfES{y%jT8!V_B#_BOilJ z=?FmFv6BgZY#w_8*~JbhyR>UKqnkiNK6Z=o=4pDO>0)`F{2bQE#!R4AOq894jkP7^ zM5|N>qcr5}r=i8C7HWb0uyr>kbnZ!RU&18F^d78Vs2?4DQEudCALs4c__@Ok$L7lo zCt`2IiFF5Rwwk^_%Tl}@@kM@8HO+rbUMtp*sFI+2Oh^Gov1kvei#Z8f{IG>A`1%v!tNMQ%NoL}aR_&rN?OPmokXnCd(6`2wxh?2l<8Hf+kIf!Narhdy%h%YK?Q496 z;2_$1K-80^D`9E?VM+N!s$fry!+~p;K}!aFK8a`QI3@90w=DX06xJ4uuueS0`HeM${We! zJ_@-JF}c{lJ`j|UE-B0t>P3}tCm>OB!^9?NZm|Rj=?s{UxHs zb-GXdW0Q>~knAGnkeutmVN6l<5;%-O@~}pOKwDTt(R$YJlOEseUWbk5#~zzS=QWfq zto%zpV84Lh7UJTj{o-?oM~7;V^%}GWft-s=*z6vaZzq1!9H6cB{4|~?JHZA!Yb#2d&mP>hl#6DF7HB7-}TKZArFEP<@o0LNcNd&H=NB+ADt zPbFOIuSs$6c3v-T55s3I4t%Pghtl9XLykN6@*N$c5)N8UvkeEs9nRY?b?kLh?ip=0 zs251#YF9Is6JRUtbvKLevU5T#pdEyb3v_{KbS8|u`KWWaA8RMxwh9$ ziE#{VmHBgg1>X{Fh=DdVN>H=cjd%;{Yuitkq-oMpDa|FX>3S}V`s1)mUQOyj6JiX~${(hY+!;*`Y;e_YP zOT^;hUitazu>2^8pi#t`d37!BOst@*n-_1?#koa~W)r%&<(MZIz4#m=+-e^_`UpX7 zs3g$3E|L$)hnQ;uFJZf46YpfRq*x2Vd=meJ_3*SCQu&MMqZj2<^+Wm4Q5URxXkPT2 z?Y|VJ2ss+61fIrzl-zSfzKRubYa#uR4Q6%tiBE(9_3==;V1A02GIFN&JQ1Q$EAZ0Y zh<_%mmpF7E1w?n&zllt%CeoK+ulsT4^hT_&@>q4>h7Zdxomb#0rFD*Q5c*^YlH8au<0CjlI zNil3-pNaKl9Fad>XepYXYbj2hwRKNI zCQ`=kecgLzXAcsZ{tL9Jb@fAV`3oljsz$?;@MByPgSkEQ7B=18-O2DCdLA3pg={to zUuY2it8)$YP~OgDolmxr3%WH98EArh)!9yyq(Fux}{ z!=miWbhNqpk~F&;&#hYCyt&&+VIMx%vQcNVgU)8@Y&FhmRV<_r;haUQ#3PDA zJw;_c&`m@FfK;$Yh*C0an&WfGURp3;W+C#Cbm5^-JmFg%PMT-;jE9qR<9{yQYGVF9 z1`Is#cNRm3xN@Qefcj7nuS?MZ^M@A@1N`R=cSjgG3Yhtaif?pntYEn%#DAC|5Tq#1;Rzq$Q4SH3Dy;CVGe)@K=qw1HYW0 z7L**?nn^3FPpx?NqEvxjhN0bAn|o1cgey&FfJc5)!>F|;9@((e*tB%IwF$<9RL#9% z=&5xksGeOg^UqfYDB4( za25Yr8)I$PirzSg)Dk#r1@6wezD)LL0OqI|99m1f%wK`m1(m=rqrEHOFo_2x?v!|e zDzRCJy;)2KTiiczT;D`F7dGQ$jf*DdUENY zy?JLoRVHQ%8;oHa@9$5r7gM&AIatOp|5>eQ>BqnX>A;6#0g7NTh9EOkM}|g=Lu$@J z$)Yt>ptDTj(G4|Fk0F|JpmhDS`$tZ3S#CV4dnOushcGJD8dT@Qk!PG%(fSX@ z7oS$Zm(q}_Ndn5|WOJ?~qeq|1Wjw8p+L)KZjRs-?qy~rx2WZ0atgCNiD+3AB=1(-a z`AmF_UumbUc%)7M%%|$dYRpm2nx8;_Lm3U%Hd;AGPe9#)fU9N+m;tiBE7w@%if_#p z;-rYjB6fkA$%4fF3my*E__B^^O#DL4qY;dUVhM;2|BM67rL;APFq16%hS%e#=hd+C zSR<3Jh$Kz3vg;0v&EJH``e9GCd+cdO^NeJ*55p&su-z2TUuXAoDDyCRjja%*XXOY< zXk82GPhde6w}R(~x^*Yk&vc>N=lX=TUK77>=QG0xsLFO2u+{w*-%0MdG+vadH=^2x z2au!T_ytf>`lGI^ANDhi6CJ#hhYrv=~{I$$=M-LSY8m7rbmQi9rpvhyk zg6~x$|4hs-xujUjlf%+Q!7K|$h$xWyk~SqCbxo9ZSM7!7QngV3_EaPLwVr)F7hqo_ z#wUMbMPDXl3na`1tT^?8p08z_{**OvfPQf_%&`pG6R6wK#_2;EQIeqgB)R8fF+c7J zGCfg8G4`;igwP0t&$#5K-peG$Ef8cQ{T(>wfO1sYIHo-)8%3&J(R3wjzc;GZOCq)e zdUnhT@EkR=%UO3wLgmOk;6lSaj0hA615XUB{q!tLw2(CMBrh{{`vBj;c$DZ5!inLB ztp}5FCBZ!u!H{ua&&CkYKQW4#+P*NE= z(-lMDvd@3%mps(SbYN6i*G&Mv5CC7hp&tWUTRn=Ym zjeE#_Z^JyfT6jW!0Wf&APf_ng+!@-XoVXSc&a$;{ri(FmmUe03n3xdXv`HmRq9aeZ z{D6>3Mbr*mN*TdBT>e-3@WmtA%kFEM@R_~p-7ng1Ykw-m$qfp4X zwufG0Jr7Sz98g@psw<3puez4DTu1A~|6BF^3hH@ALp_)Me^O5ab95TEblX3WawKn{ z$YzyaT1hqtRR2m;dZs&p?1fK=GWzQ9~!JI66ufT?n zJa1d#uDMJ+9f%cM%}ZO0Ktdz6w~E|}i5pmmVDSJF!qNZ4`O(0B3fS2nh#qM;{{PvW z{TSwKsd3JlJ6`>0RyvA?u}rk7_rDlU#llWD&CY933Q{vWUB4w|zKH2Ag7 z+5gk)X%Y=?sOM{?!T-H_l3#zfrCaN5Dnl#E-rsfLZLs|#4SX<+>L~Y zNB(wFOW)pCo!%iW;_vxN1le_17yOQB;z#f}lJG<}@q=sj9OjrAEC)M@s`5o7b zjbu2uGo18$_Lhd`c85O;HQcj!c%>A>4^emFnqzeSH z$$y3PJkYD>yfze%_MIBjkB|(gg1t{Fjpt#!41Fs8DJD~GadBdTl&QZ|w;S#; z|F;Am^nYp1pU>-x|4VC_zkStw?SGHf)aS6$d-h=#FOsn_50|tA+I~{SJPEnvH^^>y zP*{^QJFHLD3d9_Scd~`>V-15RGvAVK@5NM&1_QBxH^fq&@Z+GbHa(A3kp2l$NFe@n zDev||DvT#W9-qsffIJ)mX1vRv4CnfZmn|ZukMgw)0?&YaV3-eso)Q8m3sz1T%4+ll zZhb{dBpHRnBr4=gKqiAKlZY9dGB^N}P=R$Kz#wAmo=<)N(9)Av{|lu43VNb?oCru9 zfJ;H83_I%DNgm{2qfbaA5AYDd-c1m(LOjgILM)4o(|^O*}>5# zE>m{^z39^B$>%}c(Msku*PmVP>6zL#)zecJUurm!Taah{$`XA`eTqKnA-4yYEQ#wV z0lRrs-*Io>b@ue&X|eJ43dIUk+Q(z34NjlE#5K@#JAV47hybzL3JzhFFnSwap(8*$ zqNE38xWNh>jv;By3GYEMAGha9u|o0X^v1DQe~mVAplWV6z`mN@^U@{Ibj|KQv7t3u z($pQz(~LYGXaYL#Gr!u!zKV1PnsO4oHZUWhOBX-0-GD|kQt7~PZZ;BQexCqfE+^O4igQ{8-&mB zX|AJOmxVljtAHs5(i zOvJR*+h^YJu6Mm*#)5_>mNm1o|bI%~YGpTf9+l@eLsNA>Mp6B9+%II5LO=2MKfAXd^i zp=O*X-fm;lX`HJoV8vf8qd49gc(o8!a#cgfXqnxjK>d^C1=X;Zmzhua!p27ky}G0$ z1;@#Uvsy;a-&1Hm=kadyOGN*E-~B&ncUAY9v=iSopY%IriSVmG8VcxQdNR8urx)(Y z=UC&mhtzJoLHVZ94;0^5f-n5_O$VC3h%v|deVbmn`Ut)QzG{k^VaU;Xlyzlf5Rl#& zo>LM99)x@jcP^Y(I{{x#mBQ$=a^}$~k$q!@29WNm?fV!Vms#EN{sOrRLQM{ZsO|mb zWOr8&xm*!ho0jmY0ECA_0wF|m2sw>7EZp;iecz}3D!70DZ{pqrPOhp<8}D=Ot$T0X z+V`ri>ZPi>tExM_R`rr}cha3s(n&}NO*R5q*qRU~fFMDFvIIgH1_K5a1W^o#Aw<-1 z1VLpOc6&Z`CMqguP#8o(M<;GGjLP-@yyx88U7a+@$ISQpljhdl?^)h+&bvOZgrLRm zA~TIZ2}5!BkUuPP-SyI;)n%VHd#g_iudYP^QiXT7d`GP0q? z8*4`SZRls|lTIprT9dKrVo|P+#KCj{ReM&?axbLTEA*U&b?9v~}gYdM#E zJ(-_?`W0->%pd;ZaC>UF{gL+J0RbfQ3PRiJa>+-MIb?9$lA^~`dq|)3i?`ZL+m)`Z zp*-G#DCK*}&6>{ntpk3~Yo-#KG_5!M&#(*M7vSHGg;)dl z$32Mh3w52~-YOWxz*hGOT_I(`9K5A7q-6OkEAXEz=OoIx0exH#%Mw82C2vUOgAXFQ zRxirQOcW5wpR&DK7pZsc=n#t8M4CoB6y#;L#SEOcY9p0z#{_LxEIlKT2TaIwi1Rgk zUc}1iUT?rKbRFdB@kE0mASJ(uDviI-eLq8C0f!U|u>0NTFMr+RKd|Fp;hSY>K5xL| z(U1bk>oX7}Vgv#a5%1+-{`iCs2{3pt^O5xyty&C``6Uq&Ei60(Bga6J9t%+_T_}Hx zNkJW@&2Nc_9xh8j!Lq;`{h9nxI ze2oMXUyB#wwQK3sUcN>lKjqol>%9M+_L>dqO6vu3`nzqSC$I#8uKV{(T=o3|SDmku zF-MH816T3x+9<(A_JEm~>rAoX!`E{7(a+XSK}BW zMY80?GSSRo2lCPcjk*Fo8n+hnSrShwf4mZI&g3bbPUILvu8%91h2-o&KY{y$VvbPh z$IqUUZZaDYkc>#C^FyKbtjqc-`5JxKx~Tdk)~k3c?7Tmn8XyzTli>-sSJ8ZeFFT0PHit-1Jr zr)LOmk^r}{C8TGhx$K{>6gm~G(KBF(C!a&7Lf$Q>wn$UOvY%IIVGo49;p@@rGv!0z=+}|rs2XNZ2Rd?h=xYL_V zdfAHUW!*W4^3lBGl#gNt<{V$bnVg4%qJ1pnYgGxSIS%%M08Lmdwhsx`x4LZ8C9+OG z&fGcMd~jjS`~HViC-O<~cmiAq5XE%~C=QQoP+J~h$CyBYC*F_b^}rn`eIgc$|9jdq z>jEylGp$6SEQ}~f+iOOmwcQ4D`Ro0&U+6AnGNsJ_Jvl1LTHu>%$xI;J6LkgZke92r zR!wrAOxHmrTIZ+J!Aw#!(zQx*w-Yz#^m(=hqLIC>7JDnU7Xx`xQ^WxrgnJ=>!R^!W zVIiM9id8_=MQn;0#T^N|jqa}3c_5~b>iCNVxL$v^;K{6yzr_Wy`0_IZ4vQq|wF|{r>6OQB6Bv&oqHA_a zT`NO_#o}d;ABoxHtlQvJrq^xZPc^-6S8=;SsGR17ap)}DVzG7@6v64f+XefsRuULn zv0A@Ci}mlZSSM7Lp_MKd&}oA>~Bw_3{&yP`!^23>?;(OIc||DNX6X0B{Au3M!(3Q#`<5=cfux zEaDqafoGsZ)UmzOvhSR8Y$oL_q2>a=2nuk4{*NsrV%J+^;9*R zS-tv)5-0A3 zEKmY%LMRjRq*I9MzmA6ZYEU$|Uu zEg1`Ssr9-WpqmoG95ah4A zQYr`eBhh4MFu=yxJp0w_*K-~UE^KcG#H7dD$d#}e4@TX(;xf%Nnk8h+>2B4u#)d%1 z?N>N}LKPqKOCo-Naku71Y@DWqg3(5Fq!&47g5_YS18r5UV@6DNwR+js#TMCj?>a_} zysL3@qf{jGi|?vZ7>9f=wkw;J8e zaKKJ-y;b?0NDGjV$pMJ3bz%#eMW1X&Nk|I_6(BE@Nk{Y$cs?h%l5i0z0|&$4eaozo zw(^NoP{*bLvO^3u0@so)IAwgN4;73BQT~;#KA&$R&@S0$p%pq-Gvwt`Yh?XSWd8Yr z*g9xRkDPkPMxSr++!H->48<2S=6hGoV}z7x{d2W;$$1BVoUTn-6v`I z+n<9uEQq{jL9H=@<%`TIeoB=?{1LdL{vH}HSmVF~BIJ~KV2!-*`=CIu=P7|Ygc&ZD z@9x5^S0w-E{)&yFBLIvN@$OiBoDw)7@xyYDhEUoG9n+HD6$b24Vlv#Nt40v#R8{k! z%TynC1z}WT3Nns&UeSs4;{o5n~qg$TxqDU193T$EB+N zpjzjRQ{ZOYTc-y7DozG<6DJ<=1U0XhSOG;f-I)v~PVs7&=0jFuuFQCf zY%v-Bw%pX>Jf-G<5iMyjzfC7hU#J9FydO`8_a=wre{$xrujm@F01_y8AH*(i45 zyGnL|Y;LN9#GpAKhS?F=?1ZC=^_nqN0k&OS6Sw`X2m(QyRMQoG6J90`T_L(ee6>-2 zyBz&E7irr4T1exMg>ktYvL1n@m4y$5yThNtwGb|9_}2L~D}ZzG zJy;#+TMn-{6?lk`BCLdzhI%%J$al)(uwmG+{&QrLB7`9JQ@`KJu%Ghp0WHaDAKs*F z7}nX7LREOdRc7FyuRxWsZcooagv>ZKqMV$2d1mJIYHQ)S6u%r;S#L{+dg}Nwb_Q<`1A#Ip5G|*i%_B|_M{mY78cck9Mlzm}S)|&T{4I~03Fa6y01pElwLn&`!xZ!=5;9i-V^qUoe02wM zZC$SGkTuRd8?r{wr|e)~d^_NaWbVQp0WZH)+{`B?L{_aGAd0EjBlrto4RyRcG5=x3 zAoC2>1m-Skar_UgHu4!j6B9B9``BnFV(Ckb?FukSDY{;1Z_IWuoFlI%9FsQ`PX^zI z%ed+Np@iBnryUpG5BuZ$f=QmmR|&71auj_VJVi6j$WGRSX~ZL-i21Q>p|>SuH|F4k zfIYH7Sy4Rwy?g_)4WEk)Tu+5!`o?;aA+oSy#D1kEhm5 z0%vvu_(4!QBx+GA3?u;uOACjCuyn2Xdg2Q|p8DXExBt_Q)vI@`X5-=;7wwyR@l_o- zy&C=DkfJ zmrqq4!})gl#v{TV`F1Sf$ORR~;;d?+uTRVs1bZ4(bOSGa_awV~Td4+35M4OYiS%E((Pm^}H~1&FK8tY(0ObhX#bF z?r$4r?q`e!J68)xESi zRP&c`kXhqJT^DZ#oK02tQ|NK^;io+`+^9&ETkb-U=pcj-Xdg~y#>(}*!5&XQ_5$n% zGkVSMxytL8ud25)#nT1h>Fm_JKGmHwI&-7jV1FtyD!jLvMA%665zXNS=5X>K`Nx`g z&1#_RURiTf&Eqw%)cj7YnbO2YTbcrCMi+`doSyj|$vA2*bk9)%JR_i$&g25Mjvw z7ng~|@I5?&96m&Gvh+?J@NEK9ETTjS%=Nf|!~=>YEwCE^PmK6ziAf0M4&#}kTtk(Z z;q&N9sIIk;am8jmYyFep4ps~bWvfiEBQk;gA|)~y{u)^Z2U<(>I2*K1p`XrzR%i0F zY)7d*`0Xg@p#+y1>;NJ*z}ER9P#jT8ymO|Y1{cBG>d@2?GQ6}kK!-UX;T|6bvSTqL zO5j(#Zo@;_$1*Lvm==ZeBVViTWvz5d;th-H4G^<{TGP{IiAKzx#CYA)I?z|r_OuLQ zUn?#2aU%o2UGkd3Hi8q(l?l5v;gm~Ms_#+m5GSTV4kyk=H5TELOe=^$FVLQ8 z)83;~w0BR<*K2-I^OKtYsQIt|zv++o0YzAt1uaR6mTGno8c`I5=*y7+zdS+YL`y{b zVv18hUbI>{1SqIjvu!W^$IxA)eg6L~{aL?VL;dJ3^a_tmbhjH+6b!Y3%nE(t93^rx z(7SYUK-~TMG|~P;CIXtAoTfahU8Jr1e@1|VEehX-@Ano&ayFt-cmftRxSIAA1c`y> zK~*?I$pYlf)l@qfr2^hjO?U#D54=WJXu=wVI%Ikm zaJupU;mv&!x=n|eQivj30c9|$P(lMe(bwa2GSIaXP!0A|2DJm1Zdm?vF)05&>X+GE z`@D;87DMuxu^F4hWumo>)w!l{Yq*KudEl1^`b`dNVp*<8^{u#c*C9G7x_&6*?++12yoSo=%(*WPhkVzc@=oUXZY19e**uC*J8b-8|Cy3t?+ywj6{n>1+Khsn@mQH5p(#kd$ zn9cu?YR+|bH`TV9nTFk&6yv5g>`NE;#rJ17Wuu6kNHv!mq7kfcrrT3)POXN&W_Lc{ zU6=5BxEj@$mFwLBAZX)Z0EmcKah9UnOT8%?+Wv32-Bz2P-=1$ZNGv*k~I#8ns3 z;#n|&u53*H;>6IUdN??Fv!_m}`?8;4C@{B+4I;*7*@bMe6Mb|L{JN7@#9^Az5tzI{ z=~*GsRPVE2P!6UCMTRDkugQ8q?B7dU3%Rk7xk(kGDkN?p$J#%{ODu%G_(lG27*j)# z6}Ag*;!`zW1cgxa0eCzLOd+EHj4v=zqs@u$6S*YN=#X$UB&ZO93erpiIhJxtOx<$K z6Rzr47Aa>CJUEH_v>y<*2}nz}c!Ia}^cCbC_%zs4!Sy5Ug;Oj$;RX9$8frRC4K$l9 zk~TXbp8^a#7?|t!xjdna=1!)yhH$_gtKB)6i7IWH=|;AQ6ws816?WU-T;JK1)b&JK z59S*-H5GC$tzI)ywOTW{?PriSMf3TLq^~{^=PaCwSuc1^->GwY{5+J7^U!eL1>W~= z`C3FA1#es8k3|0?%sf87&#$NP+E6$IZJXz+B_1W1@${azY0#VYYu*#tEtzsCRPSlb zn&~KWx3&jUSyvJILVs+uX<)9m*6a4pAMQRq+v2^Dh5aWkaQi%IH>Dr*t={IlEB z(1JJV-b_5s)0xeEL-T#~%(CT6jSQGvHC5|V-T7QQa6Ka|f$Ee_IPH9x8$!O_7i{iE zI`0EF`{HWIzvFtwFvlvfjN20mB)z&n?X8PN{O-+KpOJ|xMvF^rLKmeCa>AutG?b_4 zPIzea60##Od?ANps;K^zG6Uge(_G^G_9QCgNJeZaQ0XwW5UYoTDlfyZOaI$Hw7coy zhmrV#Ju80roql&)8z~&+_QvU5=fn}~>E6Qig=ag7Qi zd_Tcwl0T=GmtbD(n_iE0@x_|Q%aRCHg;BT5@W#yh?>8~+a?C@c{0aUXbZx-Raisk$ z%`B)30xZO=m~h@Xhppio4EP@0Z#^tgyL;dZemZ+2=yQMYgKl52kALgUgGMx<-+!0n z|9GkghslihD_`+ufU_*|RSu%1b<6_+lsy6Iy+de}db2UtTl~*Z0tvD-RZ&E$h4v$` zzws^phZita7n1}usTuYX-vHFXUM853ZH9cr> zG%WdJ!+wu>nWKG%Sp;GPOGIo#E=}9y)PeI0pxCdl`@I3q=H43cyOBBE*T~txS~@d9 zzEYoLSHd!Dgk3EAcR3{l?gyStS85IZ?z8xdVUKb!?NzMPeZjEuOB}H+L2gYd)>CE# z=#a>gxfTf>7(K@3`}vj+P+tzz4Dg@vpTSEQA$$>$NX;?Y+2!S=)1oTK4NW=AC|Nu| z4>{iPd*r**g{<6yb3c52x&}L~pM=yP|E>ai`kNnv!VAAgjyMH;=oXyO!yffMl>17S z8w|qNkO80mBz_Iz2nmHrv>i5jjDr4#X({eUL$Sv1#B24+xtVy>`b@AXXPBc=2&_>*)nD%$naBAXHX z-NRs2Xn=JR34o8rN2M@2h|b62MP8v$BcliaI*}ga!Vwz+-IWc1l`U`|+!Qu1M+$gm zeUt3#ao69RrU;2ivpzlobmKp+k;eQrWX$K+!As-KAM!996gDH-yc_r5hQ~H48rWm& z3{z)Y-FVqyF5F52ZqqLJTA}QoI()YOxASp z8~JY_i$OC_ig}vTu)%krn8!rd&+hVgCjI_9@AUh>n(|Ki{QQ@iHlf$+t5#vN`ImUx z#d?4}6wnGG9?Y#)lJ2FBNyal*s_xAvy`@q2R)xZ$%r;XD)GmTDvzcg5<^K z=n(-Cb_5L1UgU0IZIcwdN*kHnVKp5t09GepyLMuNDIw4vk2`mPxCo~VidoFzab)HY zBLuntbdUq+2StS#0=yEd0Pt5i z&=H7x7DEc{L#j;ZDWropLkYp@I0gJ~fku3UN=X685!W}Vobix)=4XHuL^CbH1<4)j z>!RrJbD)y5eF9*NEujiri?HX;Ii{$B-*t}lT=jF}1#AaZ%VpQ9x?Ub|eTyicJbVO% z7$Eq3J6%OVb~9B-Rtf|KrJvNLiQg^ULJ*zb18-p#|qmeV8L46`IfZ~P{ z<*~gjgWss#U787td-3=<|3qoER%#i%`yABZJ{@SdiBM^*yc2+}$p>ZSs}OPFBRXE= z^hvOW&@13A<@8FkPD&vNGf1*Ld-p&u4INiM{M%;f3fA;=bLYV7#EG+X$tMR^XP$1h z9+;&Y+)rm#5457{v-QTGR}XYHKb>JCRb4=J7#DO^2mXmrQO`#YkfZ|I5V|?i!r6zm zOgk+F;F6#xAq6;eSdmTdptYjm>fZKX0mZtC@%&Gfp776Ub z5JnL^mmqS*LRhVl-G-N373tN_Tn zp@v%hM}}MDpWCFRLz>mCyZBCy9AI z4^Qt?rf2pdbz~wB-!$?^7nw7N%bs7iP}rSK&Tu_ zdpo?fus@H7!=Wz_IUm0)utLX60*`%M(<#0$4^DzsE zwW>qlwBsds5eyqM59K^8*R=xrV7%rGw1Bgw$_2z(NHSP!h=G!Az$?gxM>B-I3Q|Cg zy~Ye7+R@pksSr+QXhD0)!6WP?0M=C@%S5dQoK`sV?@HrQd&!&uOoQ94SF6^|?LmG% zVHsk~QtG7wM#UO~g|_?_??&s8t2==)b{zQzynL%<%5) ztwJXw`2cc$B%xQr0{wu51U&i)5qA|oT!bdURQG1O&w3dqv2nM1To_=M zF4g&25$kqu+--W!ImctV<6gFH%hjw5OI=CDABL~m)Px`vrwpHc+cMD5Ab~~b89-38 zmtpVJ*U3OP?w-92aJR9)PIki*%HXQG6l37C{JWwIZQwH2feMak2`D6sx@7Ml5`fnM z&ozY)(v&MIq((`k(MZVash|~Y+DE2#VRxZ*AOTzJwP-pRv~O-u6KJ|?_11J(S7F>V z$3=?m=maT>CZcYRTq3DfUEaNQtGqcIO5#5JB}3djed|9$)kH0Q^2xHL*G7(Bb=AL) zxijuDqzO;DL(n&c+{p+pM%Y?$r}YQs5%*dT{6~Zv$KDD`P~jtY692B`=Fr&Wg zUO1!b&ZBml@WYW~YyaX^)`6Lo5|yv6WypPQpm280PhCn*GJ zH$s?|g~%pO1L6W}I_*jW8tn^th0stXc4{BHBBZqEY30ebiPbnBrUSsCdJh9}6T3rL zs`OpFl_hySMaomO28#ExYG-C%lDg{(1B6&6{_#4ogETxvks}4gB8`~CQ-j;i!{#YO#HgSK zECaov0&G#>V@XPl<60lB*krZMvj~Dl0w!(p6BDm*8f9BXH?<)8e-&(`ceM}abYz2F zWd=N*!|m+%@Vyt4-L0>HtHVhxAZ<%)6nwVw+np}NPOP5V1Y<_ zekI#N6lC3l>%8<VnacUVJJgUigT3Ide%Z zi1indq{Mo44YHf872&u@Q?dqewM2)+-;vMIVT=}JWoRalIpX9osv%0FmQ&r{i*}>M z-64ZsmV`)rl%(XLA!5vrwhT^+t=JqDXmPk)vd^(c?3)H9mh=Q@jB?5cp~YMP%L+*v zL|`CzM-POri|GcW4^53d05CSC&7C9>Vj*k=PUCdZsGx{jzLQ{nCdh2%vo5-R%F;L? zQ{^#}Oy%|gU4&C0?nELzJjB}Y7_Nz9So~yqy$NAEXZvtM?#e6jA-cbscZvuKoDlUA z)1adjAT0oV1<=sogpfEF=3Wt-4ACG47DHB(yjT{%Vpzb;XD8T&!O-4i;5f-&f+GEU zihNtkd_J#5v&QA`Y2}g8u6&oG1k@(zC{06!&NB&LgHl5}WP}XZ4{j0eg8PB!j4ZA2 z0fu)lZTZ0k?Yi|~$3g|aY$bm8FR7HrinXq?>QlJK@8R`|C)kL!0$07HMmk zEMph0`Hxz^!p_t&ZfckmbClF0lBemQh|!xS2%%|l#&5H*j|=HbI^t2g!$X7kP+@Dw zcFJb{`!jFYy~UUm+i&N|JKXwD=)wVC3vFH5HjxV3EAW5jh#UCjH=McU21RWCDBQ_! zf_9zEt9}lMTYDd_5N1F+o4XLVK8jpyKY>O)0=;B`GA%QJYB3#VrTzp$D`~e-OceXU zJ7B3Q6e)`fn5%wLXkkT=Tga=BBlS`tW=e_lMYSB0PxU%e@TNHJj`}?7cD|tz3 z+1KXPek0VC53{SqJUl8UoL6Z=T7+HxY|@npJnxPyP2K*D6BOP%xlmQE@qgbJU4n=8 z&lFm|5z2Lkl9*}4Box51gZ`Ck?PIXF=%_KV;n+G(cQz)q3F>Anot$=VB0^Ym_|v zbqzsNNgV+wT0PRO3j;OE<(l%vq_u!7^2^Y^0w(}uCJPpdP!V-OheU+PsVb_&Qp`Y>SU`x5aenpvZIH6x8 z36$sAHtRLq{osT2T#{`YY{{l^Zz!>UzxYXKk!`7j$#e)%cLHpENK3%cn8wf9VveMo z7G0A6nwozF--QgN&U`G6Q7bwYv!XbGo|th1zm_!Uw~=G)!?gD?ahS>h-2l3C=+=Ka zb)CTx_60h^W{>Shi#%{_AI?C5ZC`Y9#-ZIA_=ZWL+b7K(nifqBe1)8_S0pM6Fl~XT zX~L%QiM2%7ai@z%wm6%?7*^;8W=P+o3<9o}?8wYf7AviFJC-1>%06Eob6w7PaJYR< z`^e}Bw!>k@cSh^<3|R%p#lxknDAd&zR_M}uIpW%_D6!g0+eSv(R;-}yrI{G#yW=o- zRPkh4NPZ)jtpuS$@}v2wIHP#dvR2expqJSzrQ4Z7uS&F!^!S~^oqhpKZlCUKWuEw) zS!&YZr2o8Xq%F}iUBGP@zzOp8j*jN$V{0-ui&?~3!@cmvsDtjb7xLN(&`oVbKL{f> zI7reoW#O0ry%WYDS-Zi!H=~cxMVJV25la%(R_GkM9@X=hZXn^|PMj4!7WAq-c>8(^ zd&UddpG?H5L`%^`*bh_I2kW;liugkw#d_X@7_3Fx>p8Lvskgx=)%qqjx8Z=@qiH|Y zv@Lih6mTowH-q6sTf`sr?5*Ga%aLsjuDy7asXZ-o60ulfPJT{c!KvX?Q>hY~-`SK3 zpSs{^S5I53zq`^>iinLo+}ho}wfl&CfSxr|O`Y@cWO&Vhi3g>Bm=o(12C~}-xWiMB zzh`^Rjv8{lw`VS$*jHk;(dn{*-eI5(9o)Wux_EJIWZUd{1vDgy2LT>M9x& z3lQN&Tnu*Xkf;XUXL{=UgS--HS@bsz?B%x$gSrQ(YM%^f>?^!|EW8D-w(Kh!;;9Tb zU$Wwo^c{hc_IP`k-%-1L%se|g z`KF0l@~tFmyvJ_IWqdwba$lrTG}fmTmbP2#r~C!kTA$Wp)L6=jORO>3T(0*2q}Ix1 zhgev!;wweMKw_8m7i7x?KaQ5$4o^s;z+5)#aT+JyE*mGihMFdR{-9_Zw&V)5%_Y{? z1RMUac+&)4=NJ4pIOhFml#$dGmb%7x6b6CtW7f$r!*!TyfsYh8gv zs;)1{c_rL3f1=UlLPp-T>EbGoU0H#`_>%#sjc?WtFur8j#dQib=o2jwZj)c*pq~r+ zdr#DVz#kn&z413H4lZ2-FRbjTE8L*Q@JW59`-N<-n916d)=(cs1ES)6iVDJ>iT@nIrorXrl;P zh+fC8mc7xLRukxgr4s!6bG5uBk5kD zkljQcD-6UnEDLa+;CPmX>!LGm=xWmoHz9yfH)6)ko$qVyVz2G%Jr9x6EOx^gT=(2G zx_K0T43dxle0>PjYp+>KWT!dj}7HFgM?SD3%Be3@chLw0LeVa|yfmjIOpT zyKYkSh;A4+XFaW5xouq`z-E>gnoadDkB)8`9la-%N>#dBH#BE+mF`HXC5JMq$@7-@ zcdowtbic9we4pl?f4ZxAIZRx#Z79bUMdOx$-nSUq&Q0LHr2VT78eYLgL1Q$OGKb9lJppY*`1Z(I6^uvT7QBO4jU)bNAHW()y39$lXHAD z?1-M&CpcRKh>2A*NeN1y##o0|ersxaPkl7ht+~x#o2J$sr1wrn>o47tj0QH0VBis5 zy@0752pFN`ND5vpoX1LPAP|_HuBPJ~oxE$)vz8;qJF}R53?t|?&*$i3s@j#ckxpSh zZ73y#y({eQ$DU-{?5pB}vzh%Y#RTnyF7qICnG1z(XroyFkx>xv*C>+M6a?sZL8u{U z6BilzNH0VxOl%-LB4-~?gNLOJZtcTmDJk?8gkaNGb{41bF~_jxzdzeKp6xWvSOnPo zo!O|@*k#OmaxV-V_n3yTmo2+7LoF z>~nMjSpvl|I$J*AJd3&0R@n4cWP5~_`>`?;l3_56VtnFpV+?-H<9KDPrQ!b140~? zZ;?tNxsUdo&Pk|aU24bL4lUOdr%A0E$8-x@fXp;VEhOE0NR>*|1&?YHh~PG^RcTZU z`6h?g!A16-(N4qwdcGXZ@=WtR%^99u3i=Y-H<@i{sPoH-j`5DfQZkIQZM3!iECf&5 za05?wj^0rlZ>uX7>)PVAY#$UnDQg)GJ%&`Y+0LCnAvUHHlg$$Wxb! z^bUtYo$aAea z(JG8RsDwyw2zV)bj~AK&1B!(w5sQlpWYECUEgD|{gbHj>pov1;2(BASgG3!vju^(h zgA_44hw+OEj@Md1+lzt-^XW#w7k(J?zyqRN{vfchM+qqKBUe(j+zprVRJt+w^^^jq zNX7$7O3QXAN=H^hE;*hEy43p`lweS4;Ge~-@1a+-E$zb(n+CA@6oA3%%BK|KG?l>t zAg|!`T?!llqeRZsXN(;U{c|EEVqe7sV?e` zn#-3r#9aQKhGpqa|M1jR{^7$^i$7Ax(jRH>Fmck>n?BV5qKr4;HRi3$&oMHMsluoH;D5QP=GK$N(z zUm?3MITBEfpvda4h?+r~*K!@`RQk0ojWHK-jVmsxM0>5qYG+@^yeshILA0q%8EYYZ%|e5b%S?SSb-#BD*wqukKnO zX!0mr*M0pBdepBsKxgCEO_ahPAPCh49r3@*a2~(#{`(O&TnVOu+*q$al;7AfFXL`q zk~z6))dUIg!><>hQ869D2!M=$rU9A++o{Klygv-5 z2-cKh;bd0zhsqIOiXRkiGbRf+k2_E$}vKg9^g~SLM>?oY<1N?%4bj7qXl;htLtkzN45(QPBiAMI!+N zyvyT;6&@IFvXt<>AkYp2e5{`JMS3D(mTIaEC-sOACecpV4q%@tfoFMx-w(YG@*(y2 z3X>(6@a~wvPolmc-46cc3(YPZG-C-BoEE$}`$>-(r?8y;`eNI!XMZFbYC!d z>sM$UIpWn0pflWxdY>yP^ncQ(S)_HY9?l`tY@OhhB%3sY{bRkrf*EKP!scxUesSP7 zVSi~IIF-K$T$k5d2O|DS=#nVv3Cbnx4z#|$@eVQG*ND6e1K?2X;Y;fbSTvh4oB6RK z<^=dH3Dp6aR7EgWvG+bC94Mw2(V$#|90Y4(_<($DXaKoAR zrHjZf=Z|J7(YXdjC)Oe4$;~{ex)b}hhU;AG(9=_YB@uT+^XEyRvu}gWf;dP(@h7Jc6c&xk zb|#bMeOt?aG~&jeD(CFuJCe!DxwlmQY#49$+_DwDtw76u8h;hGfD}-!$(ko+N{EG+ zXvHQ^7-@j%P$=8XFeR432J;*!SV<861aaVkV92Qj6B4<8N{t7uvd{K@w6`e{xUMDK zAL<kEuT7J5VJu^$=Hm8Y%MlSbuQvUA+z)eEN?8Et)w z9{4*tars=#KwEozo6hd&jPdxAs~cH%qT}qQ-rlqoKN1e4w`H{2b-w5koqhhn9VT-R zz>?~obESuSKYNNF`XhYmDkzoXkTo%NJz$?;(BPQ-a zVyJB9YF)OIy+nC(*hn(^UuJ|d-R`8T*jTrBW|5m~PNLxX01|W4xAxau2fw(3STTH% z;c1OS^YrTCQ(4%fF(>d{@Ubmf4*^uEu*eYh6yX{XBG({J5U)>{=M(clC&1P9B`V_gxa;h)Q|>s^ zf5P6+-*G0O0KzGt`55>9U~lN&?c2wU(^XF(;8FLhCiFpmQ>EYa`)E5RuT0oi_`mAn z6?oApp|CH+!rq|oe7xlcd)>y#CJ)6!9LoIZH?2DJR(j#J;tK7FZ=kM($wBhoVd@)@ z8gW(jm@D9ybcW&>%Rf2fu}6+Xg=e_%1r~eJBcTrd_%q?O^)u=ic$Xn(F72_}bod#J z6!gnP%^LU}`~_O4Hfd*iyN@Km+(LqMFx(TpZ_Uv1M{~)EWFEl!9)BKtx%A78#kp6X zI!=}$}vEC%Z&H*Cw1GLA+@`=aNzTvf}Ud{Fi?)LB3+Qxs~d6Z~^>Oj0x zh~kJOmQEE5+V29>4b}s0j}Dy9>9PLU%jsOw%Aj2ALzGftPd7{y`XT_M@Nb4fk0tWf zSDhkUMlnTux@mP@r0c@xU={qR4g-N{3%)1i1wqf69#6o>QmElEM++I7wz$Uz5TuLr zkDOxgkD~bO;5$jTI&P;}JhEDVcdB%;ef{hGtD@;S^^38J`NE;)l|g@H)9!5Yir5x* zArjtmof&G_4Hh#HOw={^6oH?`a!KJ5*L7O43&{%t`o&P1M)mZhGQn_*FTj;tx9|fzqbC)CIz?BS z`aEWLzS*t&km&~uG}-$c{e%ZAM>E9%Q7RxIO_P@}5wI?NPX)(XabSToTS{V>?vx*- zvu^A09ORNc<+1ql@GX5lK2~ORLfBs{J(|z*7|L@IC9Lw=v9k4eq49g6(Dxb(Y@|H4 zQ)m`kVtt_bf?}I#P5%pYt2yDw%=5gIO`Ac5pjbaKWVTgc{j zXi#B~D?hJou&!yS{kh_QynQ(Ma}_kF{ybDd?)jkg@06tAd@ej)+SUoD80%?~Mc`PR zH)-NvbCrJ!2LDYl*{LJ#^ww7ZoT9!`+i)0p=-WyYVsLB{uhWE$`&o%N=b**SG?WnD zH}Pc$`5SgjN++cI733p%Y-CEGv$A8x>7QQO^Kn|)&~Y&6!`ViP{!ZsMk(7&jp?Ac3 zNex}<%pzB#*o;r5?KZ@8M4Q8+U#*KK(ScLF&d!z!p5Ofdj=n!=D4?VHL3+u4+GNBd zlo1ktlj3L7Sb2XnJxmH(u)g%1ragy9o+?_MWJ^iny#ju1u*1@>MI22B#6v5UF{c^m{F3jvZ>ZwcXzG{@G~B_mhbOc zytu17&z=(Xa0zU|gG~_(uf&tfiOH8~yGaGyt`FNN-(y=HmRP1woCr zm5!s8I^khuS&C^AK~;^}5I7(57q6lKr$77b{zPAb3MhA!(CZM7&>x~Dw=y|aK8lVz z6rCGA6#qarnan2kA8ITdEi@i7l9%TD9$ax=iMhu6co$`)q0`YQu0M$T64~nx#p8#J zqowm!JlL1Fey8hw%g|RlYgQtU)j{~(OWl+jLo<|K7bY#@%8>OA18 z4XZ=Zfc8XuJzkj`()IXrT2^_&FkL-9t}9QPb-?;(3A|#R+Z)w3)djg<{az;PW+V8_ zj45q;jt#@7qEC31AXL7qNu5|` zJlLIgF<;-fi~U8p2VXv#t3w8`hVA%%SiL*3AfeqY>i8?6JLB^jyNw5zZNucatWVcZ zQE?HsA>&F0l@QOyc~liI!W$+e>YWPRhLo=wU{~#?EJKcmLbThSj*DbwKsQN11l3*{ z0OY{R!da816&hc*bHbe3dTUpG?a!hOrrY)NV6YV{Is2sWU!1f6EX8)U5APEs?>HvR zVZq=lFsbS;OrC64eYzFP{=>r6(E17<`1NqRA%+{x7vtbHN#7p9$RLl*r6d_3Dw~`R zNb{g|VuWKNbjkK6dlQxpXGuYO>(DRcVBzhnIO%;InaEl6?%Ac#L83X;;d$~c&%+p`g-$Ftj=r<*ToK*=Al#|T-$i4uBD~!5XltSbD40f!r%$&J{{pNKA+2_xD;RT zE2)(GghpCV8c(>{<8cABAm9SLICr}dnn?bB8b9lYq0kS_y4WAnEQXI*o6KmmHWX^9 zWB1mz(-0iB?ya0g(jN^#>!g{ zBeCkt*@zE>0P8{8`<$AWSBVqlHB~|O+ndS+<{?PLCFI%~;lOG-`MPj8`q%^eU zx-Hi2CEAULOQo*FDOoqm?zm(cqd2?an_<>(NfL{y^#GdfB{{y}c{@?yB#0XG;ZN zKuh{=w7z1t!Bz{!v@TjtQx8hLo+t z7LH!(*L(UaPLcRWLC+=YcF5dU#M{qv`5;ilS%DcYzsukUClEZ02;+(U-}XezTRm>K zr;#|Ws`iWEJKcg3XqAzsGih5RTop36L&S$nQvt2as4(x6aFN#I@|TJ5NdP#&E0=wf zcs%QI+OiRVMvlvS=m#-RGSY&z!Fot{U_n;M!{yBrl}5BaYfi`a@tPFAP_HTE-jC-j%3&@QB+TR&&6BN=?H|g!cb7n~%P47}2rv2GTT7hj>_@sin5gj?b5fdq<&SIfS zu-fr5OYVAP*RDTkXwG!l;x z4cZ1i>-khDlnS4l3PTGcx7JhQ;3w6m{vr zJ78Ss76s$0=lO?8r~9UiCi$XukIccqwuoQ9a7Y$dS<#)eZ*RxM`IFyb`%74^mP%Ax zzqAee3DuTxaK{WJAov!-T%HoqEA!#n{uB#@;g3(7ONGNSFvX7f+j-oX>Koqtwa%A9 z1x)Yvk4ek;7$8cJJQZJEs&mmFPW%qxz|OZ3_csI8`~q+$S7Jt`nMKYuSmMOoLexok z7g94$oIYq&^il)Mq6y!omz>^sD|&UVJHLeI0j7W=r|`r3sBvCU67>n?1<_8k_sfr_ zdnfXc*tdT77F{B{>NWvwCN{hvJAu^u2&3IJuz^hIZ^| zhYy845k})qD;!Jf&iQH*T><5v&;a_c%tWJ^$Yo;NR8?($IcoNFY6)5nPr@cU`&N=9(HCTgvcOFTrd^Zalx!0 z7DuecaFheF2>KEHi9=EL>P1$4tPZgE%RmdKzD_-zW5`!{GC&ieE*3bvRLWTVX&BjI zib1#n=mf5V(EB3Qjm&iem6>$$zLk>1`1q}VgX_3$g3K|Lm*+W{{PFPfNDB)e0NT1g zDq7`UG2ku|+X->edR4qzevLhe+eKC%`F^~UrIG9h5e7iP$Jc4ALdl8?e{(BzgJFIv zJOc2r^(wymy8JBtydHFm_rh!7`s2nl`^ePm?GoY%a6HxYbo^ZUwv?592UO;?y7TMw z#<9P%Qz3Ir5#&vx{dS7&SKop-dpeA>p_B@L>DF2W^0*3YM4SxY*dEWtdetup*)Y&Tbi{@{!UJDtNU>Fs60tO zGR{Zxt5UzP0^G)|2;Z^nOy;Xuh+3GJ1Vb%Y!NP3l-WX5PAW51!+d~9VJz$V*7!sBw z*2{VgTXt%R*e^ho;Br1yeHR#5x>S~zh~28X6^y2MK1J^;O}`qliq$ydPH|1XDV3*o zp7tFl|FZeuGdII;d}qz|HFx5wt@?pM#YQ9~u!480eJ3*)eEU@hx^ zyNHKVBX#h{F`JQXCsjL?Mj9uk2v|dv!5Xt{1ydVa3`kaH?G53)&+w+beQDiDrmgQG z0eoFVuT2?Rvf2IkiS?QZyg@A-(pn0>l*jb7ciQ^p>mx26&jh)i&}viegEKY$Gpzyr zg*r16aThuOYiK;sgTv<9&vf?(x?8j78D3 zSyw;-Yki%~=E`BhQuO&Cv<6*fZAy!PtRaW3!QA#Oom|quxba)%G$pF6edoZ(ALP<5Md;6D#%m#mlzrhSG>-XwWGYJ4jGRcH0 ziG(`_PoY_E2&=~9doDFJu3l!Em#MX9BJImM4xf~{E{&%#)ll2*sJWOw!2cd|Pa0nC z@T8*V5i5Z!-rqdqC1x1k@pM> z7EM0jp}H_vqgN1DE{!O0_O)xq*ce-|0i%Ay0_=@l6E2goG0Gp?v-DY9(WSeGj*HJO z-4lNEjUzP490385Zssz~zl2NH2L7Ksc#-tdHs6warA#~@A@!Cs3qnK&QwQ0p8H_57 zz464JkDN4bBeI(TRK6!1S+T9*NadQ1_a?H}Y#g7z4jxv}cN2Qd)jq@x_cg3(rGuXK z?w(HLy(fMo-e4`AKfdvrY~tRH*HqR6>QsA<-gH&ahw_cqoWWm#9!&a-*ANG2+vbJb zVNchB4<$Lo1)MwdQ=zEPy4Dwen4H*0X~WFv-QMkpCteV3a&6b*^vfTui&JG)!%ppW*Wk9G;26GAVWp=T6qL?;*QDU2jMO9Km>DIz{R0Sz8k={Ex=S6t2T^Fy zP>`P#BHnT`s}>?62U&jw0GNERxdYnUoNnHD z7Gq|+%k!wm)eGhnep7T4CBQl-;Bw{R{F7yOoVCR5Hin9>&Q4e76891sE7ShT9!TvK z;e9x3&B=|IR6i8sAzOgdJ`yA#r^Sg}$f|&HPPqs`BRy*?T?7)o$Zn_;v5&vKpqn}( zkc=j>nq|m)Zc`;UU*ga5-;oZHoB=2c zA%*;s=O+*ji7mqPN0X%Z2PdPSv;vZt`Bc}E@{oUVU~}2}eMhL)mu%e3I81)|dL+y8 zx?A}#J%w~<4i0-KcfD3F2iFGL$8w7!{Yak$0HOu)Y)5^(4s!T-4e>#{ASL>+LQ9)| z5Acj7LO7x``@xC8`kMf7DnzRS35mAGcedaDY%dKB^=)s8mzx2@gi&*}R36)3VvmfK z|131F=O4G-X)PnAob_d)cs>8Pt#u*n!T6gva%7@BHZHCsuh21n_Z%53^J7oi_w1zy zWnYZ5EBImd2qYY2hwLN0qEOzBhXDvi%D*=s^|G7AYv_KO!yXiEXX8y*KciJWPw2K% z3*6IJ{Vu$5>b=u@;V@q>zVT(T-771D?-BOhUNL9N?{yLu`8)Y0>Fk{%M4TO*d?#gj z%Q9XiO7~;29g<~yRvcK**(Ij-kv@hE7`G>bzCjq!=-9G5e6^&|?HpI~Q`a4#e8&A1 zYDap3)HXvUl;vHcTQ-asgZ5bWetc1Ou z5Et-!V(*wkam%&SS7cwTglxA9W2RT|K=3kP2*WFOVInFzRic%vSyp-0D$(`CF_ntI z$Su}IzcdWYoY}inK{QKm) z*(tM;%$CuXe8`LOY(p%TGqPO3@uAR5xK(h(AlA4Kk{*l~ z@XHgjA<^2zXvg1ojJ9UufxizR61q_67@eGPB(C$79i!N38t}4Ox()ZP810y(6V}hB zPvA|Xa(-J=^FjD$+~)8=QoBG}FyhMkrR}F`I3BBgV88H%{2rI}x1uHas4oOsee*Fn z^6nN#*6HHt>mi>9u9#u3H^g3~eJ+~ww_+=f?fLIx7y!F5=2{?2t|9Dz2pO5dE<&Qi zf+>5hZPH+#F>$n}+UcU1bjaoWwyHLKju3M)Rp z+?{ft^qxz`-LlusO%rKaH(HUEpz}wHPbyt=z z={8g2ZlmM!MPpZX;8C0$zvMk9xl{KFzbCQ>o(TV5$}t!RHc|(;)*6Ul(g-JQwV)QE zO3-HjBiG-{CQrQL3 zM;*A%C@nhW6n1M0Ijut>^?K0^-peodq5(a7p=*j* zkAL^O?2)kdT3r7by`9}FWRJ^gR`L76*ZRqpUW3UGkw2XZR;akmX>j%4)$M1+<|kaM z=dZr^fJpVl58wOR>h{xP$Ui+kwEDGs_m7=DHg-0iSD`K50-ug=gL|bc7$ayClIkn4 zT#JOUQ5^MB=n=HPSQ_CeEb0yUKc|2=ggs8U96`BYvpZ~^;bR_v^_}vO^~?tg?!7zQ z4L;+{8&#yVQZHF;oZ21j1+s8&q`Mt%8m>ZZZJ`zc9G;+$t^dd=0PTafCDLT?xOYRy zquzKXaw{3DFHxaSWx?UrrpRo);{sBu^ zEHoDj0ZsxkW%VzdyIu}*aI3lAM#w?-Y;JGRG%;=2OoI`+5ZTsAsNiOeYn zJNE2M?8lwsl|$>+{Bph4u`L$6((hUKBKLSW-S6Q@!LBYGr8kj#*}{di74KaL*Hnd5 z*(t~0DvZ%~4hvETbWc4sdS4y*&O z%uc$~7%Rum8Y?%ZFIoNl+dZR~1f6_-@Aud=u>6~=*MY~jF8_Em(LHuqc`SIzsOR?Y zuf8NrW!ewBG09HSuYuMhLH5-KPm2F=e0U(+;5uA5woHtbrVZ7lzY~U3SX;;W;juD& z9sV8WN#qxN9sQ zQvG&oc6+0tP&u18$FsB#ZULfIP0^ZP&IORP)2B?_)5m!r8ID(0cqVlB0vGt=QH+%z zqm2!C5;kJY(=4cgQJ~;VD4a;r0H5V&E(~!fn+2NzMYtH~B2X3Mic%lj|GJS(8LKMS zSI(KUGBmPs#JZ)i>C7c9OA{M+0}f#K#>CQ=C1*BGK6wKobF8N^K;{G$Ga6R>%^n{T z^Dv(`e3OUY8d^O!x|$d!y|J&i;+ zF7O5;$Sp%yf!&bCw$>msq+5)mA|v^bGP==LFqeWU7A7h5m9TbEXJLiz2d{;}h6$l; z8=9#ha63Yr#dfxbn&}=fIOtBW>u>pbb}!4t+lJ%Tk5{M^cABCM>`Zn(xfCo*FhHg7 z|9f4D?TL8Y73=?%f`C^zT~g3%3jfbMvMxC0#LUa=RqMt0a9f<^SIzpkefJw`a(gnq zAnpn;vcLZprCaoNZ=rsmSQNq;-UUfH2C8!0OhQo9MbJ#HX7X=3JlJ9_YXQ=oX?~|L zPqm(~o>1o%*neBE5S}2b`!eF#=2r@jK3ah9E#`#L8VBd6Q^fgCamW4d(DS@MMr&6r zN~|F~UaJZNJNcg^ip$%msz0(|!>Lz4K4+M-g^GtS*5AhhG|S$oxp1dZ@WyW7g}|>uOJv&KK900jFMCJ@AJ= z;0E0IhnrmrXR*$_{?U&%l@+wD!&3*qBMyQ)5>n?>w_zr5!HDZnH>NO{kL_T*qDu%E z7#j|Qn{7Vs3?CO!$nZHusPHapS2A}Sh)yIV1SDuf!n%oVk@i|(WrDic7VDm4&+tbP zY;3=weYl)UzKk)`&;~=W8F(3{wELvhRU|5$sM-hZkW5W&{9R~kQt)D_X%>x(kOr}s zD43Q52$dyK(G{&)UwRW2QZ1J&0FsxjeBO%Bz8dz1{`9AiC-N#%pn-&MZyAJ^Uj-A2 zd1xnE`DlH4|BCbY`VW|4_l_M#7=d0-asCn!^-G*-801WjDGSW9N)Ssxc$W!~n;0;Z&))AzWL}$uy3( zF8OGo^0?sxko#cEA8yt(>s1tbvc9}?1xcLb?@BoMhrvS;Y6=`JnLTdgnpQPzDo%ue zM#Le-EFom|@WYg0f<1KH@aBs}CW%E*5X$Jr5?}rl5=xlnF+<)uMP#c$Pz10qpiCSx zru*@rm{(vbi}X_e*bNjxgMsoAt_Ua*%PI+em8`a(T7voQR-snfMzhW96V_{DP_S+F ztc}{?=0BiC*vdksQuwI#kLRtJEZ1AFVPw&KHtjzLdog5AAyqr$gBA(QDlntbKdj~S zueYbS+a4n5JuNoFPp*XcJ*L145kVR|x27ON+g|C_SM3>x06)%Dgf@jt*uO$P1l}Vm z+AE?wK-1*=dKhskq%T;Ho+EY~i?bcAftgN-!BU-T`wt|L!q{#t$(&$rvB&jWQ~=Yo z=&*j#1=ML%JL9p4^!ghsZ*cLGvz^CRihoFSB77yQAH*AuCOv`g2=70rDWg$@uFPIn z>hrg%r=tKtMUPdEy!(1G(lJZid~B!pm%Zc4UQZh98PCf19C^o8Mx7@FZzf|8Ne4LH zPv9<~0FtxsjLxh$?$i|P(ZD5e1Uc#8Fg~o!XPvGB=2X?0d>6D~>dnNbCRLLHXSP4a z5w_3!zle1Z%h?zExe@j7b#RcO|M*(&=65D*^U0UNArPnR@elape-_jF)$JoP*b1mPt+pRzK+ z2=77+e{-L!YkIZmqPdKH91eu0^$qJAW*9zEY{ce~`r#G$nR`6pPk%b>xkvkV_HQ(K z{~P;^%Y}iD_B;vph&NytOk=)=9Q8F6Gb&mr_b;eEU7`Irol6-je+PUn1Y-+QoOzXiuyMGpBW|epeOyfr?#!`C&z$}?Thdu zwav}7XWpvs?5tk}t;wagxx9gUA9Z_zCcHU|0>lB|ZF|-2{Hy#?fy+Q0 zn=muN(vC$7i?7F6#rCmPv!}!G_%YwaD*YQ_p5Yrw7RSBdN9Yo$2p%sVpdMUUBK)Yu zSX#(jkga3jq3Y2)Vi<|9L*qzfIH#AP&m{&Hn@?!GFD0^Y1>5kn5Q60)Y1#hyw8`ly5-l zf1!wwJPS&3F^_))Cfnav;BZURyq=l>LVRj32?a|?8|qqE?eJ?JcPgm3J+%|zU=MlB zEHM9jV5`R;Xl~zCaHgWn+4HfnW$C*5hLuPNv=~up@#dP%4XvrgZI@I>0{nxTLq#N3 ztj2If1DV>A3*IveyL3f$IVmToGwILP^*Z4fG-jT015dc#?QZOF@leV&)Ex*7k8Qec z9wI-YH8qQC2abiS>-)IjYp98!?;X&F&L~v^e|{K#Q{ZW#!3J+s?f}ee;ji=#`U=W! z_2QkSYyEj5v$Dh3o#XT-t*z80yA0Rk(09 z72ee7@SFP`h8{`Gj~l6|Vq~|s^?;#F_S81l_8@tHKRupZsfVk>5nn3O>~->|7t(`B zM2aq2=sJZcN$Ry~f39~eHDKEobS0LIXpPfV?Qd9q4He$FR9EgsNSCI?Q*I?#<8E#A z_&Pclu4+oSv|ub+insdp{Vs>*57cmnGwQ`W+z#xI7x~X2Gr?*g9Fj2oXyhtBF5Hqt zMwGt(Fs2@HyZs{^<4-t^h2KRdvm*)UrzXgWdzF_r4J@ir#K%?=gNVJPVhFbRzJ)cq z+ku3(@rb7eo>r0iMS;L_8j_nDlmMIyQbFzx)~^axZ=v4VRf9$z302n)z}eA!E!UrP zBFrfj0S^;R*0BbZ4rlwS)u@V$vks?u(oKG4x;q%lG%Tl%-Lz77sBplK)i{0Cp~n8p zsTX$*YGTc$_2LNDi@SxLr;04Zm0Hm_$gPk+z^frZF!vL-RcIkUjqN;wDPwK4<#$6f zNo93(eTCm;e&4=`u}rxyhT#YLGw9<7u&&=w^?snoeyHkRd<$Bi#Q#0rU3$Oh@qVql zBo}+qL(>27MIy(%IA-_&>k)HW&yb!H|L3~9`gQX1i$|@hEXk#()D?$f8FZo$8(_0w zL>bU7T4`+3Rcb6*OH6@91`iH~{Uo0t*N(0@0|>o_&xFGp=)JKw;DwhM(*y8E73fV2 z2@%PfYX0loN6vZx5!~VtNZ0g0c<|s9o*C`ToF-a~4SW85{w%Nw{&zGA?=<{$FbFgw z1$hg=p(vUb4r>stAe$?|Hwqd$?%;~iedaIb+&%YRz|xDmVOPVwdUPeb)%vy0%;5e_ zoDDC@;41j-?3J+bSgF5!n#oyGKv{sql_6RSe;WaI;- z#+r6F|CG^CYi_S?aE&&$PxLiZYju(7XubMBvBpv@7S>80sTSTY&|O$O5{x~h#sYk~ z{3Xgr4(SisUr1-r2v!L>KViDFc%|{r1r`)aE0xs=#7|yx1ku2s=+1T~*d>~IBkQW| zb1F8kG+xX!Us6Ialu<}dBnw9EpAffH$Fto9CE#OsZ*tbA-EPo^B~?rK>-=?aoWp2m zJz1gQYleSh=Y*D9>W?v6guEi$UP#eR1B-47I7k;Kt}&g3US2Z1EZ4Gh(b_eOOO3*U zSr{oia_W&sc6YTQjg#BcH~7advn$tib+7H_ufP1q8?L#ebmj6DSEM~;AH8Q}(V~&v zkKq1*!P#(LcY+iMlF z5u%r9)ff78QXA0M5}k%GNgojI?zC7@yfi!-qLEI_P|1h#RB-{qvDbe9o2!=%b~e=I zdoOui_d~wAo3_{FUAXd|)4tI{?qiA zNfFZh^b&S>#kJS2AWmt+0b>pA*BA#j(4K^Upjs@UKwhcaC7kDOU>9wwx&~$VJhkL7 z7b8?V!b&L+TmdcP60rc>3pxqm((v?x2_2e!8IghqL|f(Lfa!v!A%+^gORuoi$l-@# zK9KflT4#+T5_0*&NbR4)h!~U>ZT|)%=<*+`ZBD0~+3CstpF&wOIqw&+hY7zX>4QcX zlN61J2z*fI%0&qHo6!ssV8|hN{(Z@|-PwL=jh5z!3~J=R?=i@KACa!Bc^9SMtNbV3 zx^5IKG8-dBozT`1T-7Y9=;@gm$z-3iWo^>wNp4X${_tv;H`7&@W8EV=P7`IpwZ+r0 z6v(7A3y}|)r?4T1KV%*TXN?>1wh+)jvxq)o5`oQ=Mr+XxDBxAqKn)Ci2svmLZ1&;E zd(|H`YuauG89fAnx*s*ZUq2lv90boT^rS0fE)^W z15W+$_7$TJJU&9tE9Up-wM5eam)C_DdA}=~^1FTBXiaq#C|RzSd3YmR=8c1zkK(Ic zfyg~XQj!5lw4J__9KDbghFAvWWHF?&vyvsv{nm4HTKCIS5IM{gbO7dvsKs_98x^Ur z!L>-67=BY+5z~d=Ap^6Tg)$wgo`q-brywn}fDXw+W^Q+h59L+R*6wrTo>8vp9Qu9;s1=Z%&f(ms|6#tvs$C+QLGyxahmbdg z9IYZlnq|=KL+)+}oS-}qHRC~PbtYXsnQrc>K!iI$fyXe2Zys!J9&CORVa83c?6T*n z4435T>QHR$pm{$M;juq$9umR36n`S)N8}?f;_2qW9$8rv)q!&4ni2J!1dml0MpE5a z2#!%o)rZ-Y{L}28@aB|BsjMHiQF^4d7;v6Jn8XYHj4b1Y{u$a7*w^M23ijWf;)v!Y z*#=1GOg0Ou6aLgTIza3KuB&B?fEi)r|MQA1w}AqV*xmu+VjNr4tFYx&``8bm)3V!d zSx0OWG%c32RI)!4oho{!`5v+3DX}wq#O{0II<;Q~j@u&8m7j`e=2naW()2)$1ByXr ztU1}d;O_)&2Gkg0{eiOpglYPxLmkEML;5PiP|Q!UJ(LWpK{KyxEb*W#lU3Qratq8A zMSoCXZr7`u2R8rxrh!d2^=tqf*`w+LCyKAeOfi3s`|%u$&(AIJ@b|ki2mFp2r07&W zQGIpwC-HCB=44Zt+B^xp)GNqa8UT8C6I#3&Z$jCZ2;J4rQ;LsD<4zbR08L&#F4%?W zDSDCe6D0dHWXUw9^|));rTP-?#wmk+H{?NvN%ApTN89r8>`^FWUOnfTBr-xg5lA}s zITfu*PefHcx!tu*I<;;UJIfjO`Z;$X=O_3w((Mx-1jYIZbhjR{?i0D|gxMG>3ou0j z?3C>{fI8^W)NeF)RQrEa?6|F?SnL>^*T$cAJ8^}t@Gop$8VG6Y%va~-8yfPv^9^v< zz&x<&t&Co$H4=mn?n{#1g6bh6piFYXFvw*Clov);EEl#nRbGs?d@nnU(CkYOxZ4Ey zc$@pcr6RU(Zpr13+;GDqH~ixXhuE|%o>?)0~S$TX?u-IZVBbQ%mN58EDJ?Tk)688HL zEP&0BJ{L=WR2J@|7$wCAUKMi3C=b(8tLefw4BdsR@CwUm1x3%J*oqY+7ee}91etYm z3b_zErt@7!y~w(|>bssGur6+Q_trQZ$$*b5-@Uil?`!8+k9k8~+si({LHdlg`b(G2 zk0_xCoFZ0q?|staPI`n(i7Nu^Xias57Jg#>M8**gI~|3M6VD$jq!R(f2!|csXgGnK zMYXIZ;4*>^^Dk=RZl-wqlW-=f`OrMoS>KP<#P4og7^~Y_TknSB1*>Wc6kC7?poLr; zd$VBxhUS`GVb$fzq||S7hvrBm!mXtZE<+EyrbkMl4RtNKf(sD9u54{htR7yz3Umf1 z_zln*1SK|zv>aACcLT;5UTFflndf`$McZZvUN{wqg}s`!{S#Np?KpwlwqnQD`ha()K2e}KNfMs0Vz)f{-Yk%|X^8tzdHi2jT5Rx7`UUDfFzy;#o{N& z+I%GD7RFBp*;Z+F1gU|p!?ykA%12Oc7G|x&;I{L*nbm9z99}$`8*DKbHVZ-oSky((6ol0XD+XzN34Kk|DZ~hV8(l#D zI;wY!DMxWY@MzDfPW8*a5O1l~_;C~*RmM8>qjZH}&dis59_`Cs?IA7QLcSU{J|WqC z37x;ZvR};dtCP(T_`F2>Dq05@h)hM(EQjs$7<(g|Z%-VqY>C}1`DgZJ&~_EReiRe=W6-%Y#@_((`)A8BBmt9zM>D0=L$4vu;Ez>tCa-}v(@Ez5 z!za`(H12puS@TxMzE$?NN&*xM>?Ju~RUXc~h6No9H0}KS4I5H~!`x}ELU|F6E7OO- zZWih3={xa!5u{?eXdTcMm!EWZnW~Ihc6%@hW#JUfM+7MeooWQ`tXV&><}Y zlHt`C?;YrFu;75()?w0SEzlf4R_NYy0kkb_4Do(?Mu@UZUCb657h&z&y8L zZjkMo-G*$}paP(0bHCRJ==1xkK3MffRiC=}_X_6_-UDGBQodlVe1d19xbQTCOA(R@ zgBK{1z(!01gcl1M5g$?zlPN%1!DJE2H!3LKO(gQdltR$Q^HGZH#}%JXNk>}hqY8KU z+=|2DsO#*ibAWPicCGy}&5`ap2Tv*R_3-t|CtB;GKo<0RI6cAs%)YZcW4`bz`U#y! zJKu#!%UcXKYSsv4nZ^yThG5tRHA++l&6=`jPqYzbXyrKhs-%?0xB?hMad&R_+tcUS z7+K1yxd1+o&;>y12NAYpeYq!%nvnM^2SqWK5{W#(|A5cA5dWhJMHEqWmY4?PL;nCT zc8|y)n@dJ;3iLYSZe|Qa?r?lk>d>G_W2+VAE=7T7)C&>hi$bO+xdpJq=X1$>z&@Qy z=BQ}qT;``qJbIgre3Oos!`w2V{nlHwB+~V~}j2D`y%4?FpgWIe|D=RIm zRwz}U;Oma=BNGX2E}>U~`gg2cQlfSb!#-}kl|1Cf;qA7Yo??gLH%5kbFo6kd4_00v zb`GF+q&Kt=z{gRX#CQ4kAfu4SIs#GrG=1q+NKGU5Bw38IoDe{;C&3uDNqbMSFP?#3 zEUxGD9zNvo_<8aJ#Nypja|4Cu?62n01oGZIYwh<~*J!uDT8SiZ|1;QomOWGR41Wa& zA44$DQT%(*<5zKJ?Z8XUE##+;o3CFP87Z>j_?4^29lT!z;fERwBzH zicupbmy{`p)FLX5^!+6FlS<8URS+Mn2SNk7eF;GbGDo@@eLB%+zSTD|0R&GVv^i9i z{K%OIIe&DVZsfP&yg6;YMGqhx5s!*{9eoo>2X4tkDQ@|^GCQrb&4s#;uOTlKDSWk%*IdtKnwp|aO+@*)YE*D=E# z3>A?>8?2%9tw`5Se)XhlZ%1y;S+Dw523%MXB84T0oJz1-Kv&k+sphgwb`iQDBYR~w z^Op?*^E`R`!DCR=xk#$F-Z4l({|kVtPP5lktJ6;L>lL=8GS zrwr7q)B$}RENTO-`;xiV0dYiLOoqogL3)wa0ltw;YHj2CNG{o;kGEN8Eks`{&y%?k zeH{Jtc-4r=wc~-;o5(yOGPFP{EN8Od{WacOZ}rw(^1|0dwMPSY2K1*44?q4a7Dkfj z*)`2WnvUYA$CzX1BCKhN1%+=`Y5c$nOe>QJ@|q zGFl2P?M3M*`G{d9s>k+nf%pVhuksot4haj&JcxD4hH`?h*z-8GZUo8`zfHPyW04y} z2FKa^=&s5ePg2czprTN$csX(a;8imiHyaU`nS^wVXnFCL)VuVy#M1{e=-nX(%RgQL z8)1{64Lgh)$yE)@uelo#8#A35%0xemENeUIH>agV4#Vgz1Tc8amtc+ncLLr5mIeH_ z0^5|7VMEBcyBj5fHKI)hz|=G2u|#JdcR~NolSx?S zn4-fkNNLygl*T;K09TVBID8q#X-fbuDL1viE?&^1eq#!Vg6m)_=Wi5h_O{gx*43q3 z_STqRE~weW8UXtSyF!^nEEy3Qw3y59gHlipMB_<-0S3mKTtUU_%8W!Js#@(?cp%&O zO3Nc;nR>858BnGSsvn~NoPOI-Me5vh`%UT3P|rb}r7-ONXl2KBcfGTYYa}fK9x;k?7JRsA~*%cCLf%6XZ^CF#Q?>&tEnt&bP2cV5{p(z0+B4R-hPIxKtilm7z#=`Kn zwMMwEl0q5iI`sbR8n5%IVDQ^Wib6Xlq)*T1bk}k0UgB(F&^2#jo-4RePw^Lq9j>Qv z8#395oy$SIsrhZM`*<%+iQbpy-H;pa?jFzG;1PZaGDfllIc_a!CxEktF^kan5*(wf zBg@}~BBj9_fTlxelt;uWK%mQob5RjMNXIzB4JFueQ3Kse_-RyF!fFams3?y3w%5aj znnLFKP)@}zgX8ddN?yOdj?<+Uzw>n`a4?@~ar*I>z=_{!U-LMp#q-v=tmfPjwz5V3 z*!A@A>$*qvJ5ld%MAh~soph~?tEJNRlH?vifa^l<|?f*(hyo$BVd0rk2J zjXj3vU_qs)pg3QmIRQ$xMB^G_W#J$iRB{Bth$g?&HV2{9M*H)6%+KXVY^8)|fMetM z%;4o>=QQ~gCHg|6pF69ee)|p1(_(Wsy<;%GcTPKV*NY8zAi%ZC_(5dnv;nH&Co=GrazA1SClwfah#~QXQ$sa zNIn3AF8;qp+y6lIVDl8w3p@#Oi(20Pcv>W-u=Kzb^Bq8pM4R;d276Yy%tMc!!NNy| zhmsX!Xv5k76*Ekr#?c^2@EBf#h3~*MTK{9&F`0|GzBh>RQqzRlx+u%N=01&5i@~>hRbkJ%;c)VBbTenfbXD zcnHs~VC&t!qDT}gc%#*@J-h<>8#Z(6t!&X7uOr^Fe9m{$8VrZM0mH(cKT4d>QOlCT z669l$0TWHOe~O`e1u>Mhh}97J7Q}FrgOT1s%1l_vFgiQg*@7v1KGS*A-`<4Z0CTl< zgW=2~v8?%%J!{wQS<5~sV@Qypcz9%Tas(_2GH8!Y6nb34&GoQ@;2tFKu;NB+tQ_(~ zNWdaaxLdPwOHn!n5uK)4LRoFd6eGH!%r;34Mz5W(t!&(tFgQ(`)>4c#w!Vj2`+31Y zRR*xl7mfY3Z24gkA9pRQy`rzX)eub=K>~B0ViTh29~Q3x9bpmj|F4lBcvk*j0{P%h zyag?DSj!u%ecxI8m~{@D6^-#U8(?r02jn3BC(U8L0M@J2T>u6_B#J!L!tzRMkhnCT zqd!#P2Mn;!-ubLs8imrVo0v3N4WzsI81P+7%>P8{r0&H-Vtc&e*!-r?{i@ps&sulx z(>VY_F)&^TEI>(J+nOu@1Sxju{{Y8X6h8)xWf1P{+E#XpNXXnFw!aedO8ipS-J)a} zO{pRYyP6gWmP*h;X^<1y3d|(bkEFXsbqt7_)&-t%`;Gvpw;G%v`S}*T9-li?ew;A8 zn?x)thBDV=lA~>qY1>AbBX}&CTRP(HNaed+)uF(yXLkic)ew1(1-tU84)4fP);G3g zY-|g=P40f%)KuHlKE~Ksds9;*%$kwz4S{&7eSJ8Xh>ULAHX2C;!}maOm}y+lo{9%H zu*LMa^+#))0ZrI!Z2S;r>P8Fydv;cU$so%gZAptEw=`1`fR8PqZ_zeKPIc0wxTk<) zaP(QI(TLTd$<*H?hbJ=o(BO;dd0ZyTqOFax_wOK{{>$0G*y3!W(NWMGK3}X}W6LKI z0P{;p32sVcnPX&qDy2EhN2Z2`rUuy)Q-gz3L$-S0V$t@c(KZA@6*GzKu|RNMK~?ok ztiO~+7|l2;8k{n+iTbdAK#xR&fnT6bQHU-2l5!i#_-C4%gp1Jy|A(^8&Oy3F%uw_R zI;u=#GDXdrm<2fWQitgM=o)n3ZzPrYj(Dq|%~F+w)*%RolX4rSPJM%R{1rhT{z}k_ z=?a4KKO&5FQEKgAXXEj2&`$6NLju1eC^A%%CzB+>g{%`)wly@5Z2X$&@HKaD+Xf`cl?c}#$S=&M9m`w0 zgNHVb^tEgyfOd~^Wpv~Iyl6AKYuksnZG$tT^iOT#Kf`(v0FAB(hrf}!f$x|6@>w};Y%iO&ywRAJ6uV}za&1|YVlFb&xV2Io6Ck73ukl4u@v^j z7sY+&E8Hgh*sQU10BhzG@b_pCImwp5n~T=}O7$WpRSuQ{nvpb~NaKj247g8W?*Z+` z1mzugN_3XpRra3!yFbp?4$NDlME#D%aE0PP7VlWdBYu^AZMQ$p*mzeQsa5$8FDaES zDG`}zNA|l%N88&0#_$ig?Ww`FEBlS70x|9n8c#X%8Rtm5{z;tT+9x~5otXyrQ(E}d z-sQc$%WLqE{Rg@u=gJe11L{QN=|UkVLE@F~C?<*JgAIuw2N6fUR=)AvH?}E@{bKgs zCbt)JZxEfZa!0hdh1eyTQOVgp0&9gdv6ix6>ZTKS7iZ7+*bFr(6$Z@kxuP{AMZT46^XpqHJzDl{ar}n1u2qUgOaTWQC)@H?}tuY=Ho+3 zG3s98q-cU#a6fU2>9r)X9#T_4_@L}#Hv9XLZ-jYN{rt*c8#^!^i1QYT?==5|wk^?s zI_;dAGGD&?s;lna##YAC`jJd>XChr!*Sania5N)ZtsVBsnga=5%&?Dw7+-a_;K%KC zDkk$C+P~OOYdA=W_5MH-7W^*?0gEUCPDpV`ixgZ(dh_;U76hcL*cDGA=^1*7Jr-1; z9tk)Q@>)JJUzdF+`Q8QdSFN1SWe+yZy-_~G4$E$x#T6k;`!wY^w0~IXscf*#RnZFD zO{v|9&UaFS$>=D=Tb<=a8=C%LwY8J~FENLoAj8Hvk^1}<(FF5%c3U%@3&hlX{CvOw z;``6?0Pm=+ak$ub_fi-F)+1t>gs_373#R)EwKe?i+WPf(*jC78K(`fZg>JL0Vl3E8 ztw41y!#P8HHY0lHhn*R_H~DeVnMr^gytkTQ51IhZw@+ig7M%{$uGNpbMJMj|&|SC} zLeoAC<8l@&B@W-wezFC~SwaFX&7GK7wqwP(6_y^URf;1D9I&Bz0m&jYcJ?%~ri#?5 zOHKkp2S4g?2IGrlCkiftV-Zfu6CCDY7{5eBv`G7bY(@krO>uUk z+#b3o*e*>^0Nub_o#^l-0&2vlsl9JyTN^tT)RI0&G;4$oEU!&E0&XBsB>dHm_G+Xk zVT}md3Y!0DaaM+o7=WP1FanW=_&i)%m>;OEYa1%SyMgJhhSfh$IHQh$tJbSD#8l>w z)K%9wbKz>Wz&dP(>+JdUw&OrM%bMSNp>a@w)pLO%0C|`62m++%>~>(DUwl03#Ko0! zkc&A}2D!aZlP-kPa)I_;2$F?pJ?S!KOamc#6WWm+td{b?UOeD^BX~9)UIr9QKc7TL z+R+Nb9!usR=H-%Gg;d6VD3zJRU4f#?lvu5U5iuQuWGBSAWR5w6{Pt}WQ{uj{s3+l2 zTlE}Z%;}ukRoRbW_$W1_%;EqQVIY*`T?I6suu1C#>?3Db9BB$AeIzJA%3sO8`3%p- zPbYJq`y9Mxles5dWtxc8(;|uGH?NJ==8|`Bc|WP0Zr-j@8!GiIHp=;IE9O$|3y42< zOKjQ#um1ChJ?GHpzdu*tIjcQ>!EY`@Y?vjHX%e&$MD92SUzE$GQ4s2qjTPp`dH!{k!~;tof;x((LOYq><0M)J}6dgdI>tm zh@sl+A~;P!l0w z!0ASCLdbF4hE^4u-DoUjU4)hG2ohUDOhV2OqzoiAoZyfu<_Y;7FGb7CqY+ahk3h#9 zB?%yVmPJL;`&DK84Q__ZjfilyEjwh_$yJQi!?8wpU9<+dHELj>Sse<^3kJpD-G;?w zwT3@J;5jA0cPdZILpc^!W7Q1}h|*h)3I>=M*XD0M^d$bF776TBd5U>PI-+m!{}Q>3 z$^V#gX+sr6f+^Mjcz=+9suN-|l~6`roI7UM*oyAwH#apmW3}{XnTCc8esOtE51kbX zI5zj&3+-(G|EB4Nn{Q~Mre&|%c~utoZs>Wuht3Ok7I5~D_L6IV2E@$VS+xR~tUnaF z4}kW;5xv9-qyipJSfc1mglFW@c%Xg6Q@uU~xoDzli?1n%Se>3$kKKE8UGW|8oEBc}|ar6olAfj=fD zxsP1S<(3p>=-~t^lAbO{?!| z9s(}1LwLq^Hdr0M`eIL4ig$P`!uhrJmW_yot?)j&_?rrEcOj4ok1P=N z5<~=iD_tzplqKV0?|KsyfiVS9SF7?w>FhV#4drCD7IUogkSmq4 zE^e^uM3$V6lS%UUmuoih64K9-G(N;lR1TXSc(4oEfTS7l6d>EVObIV5Z?Z>Q4{M|0 zbCfpI!tsPQ>>DJDncqjIvRv{c7Vcb<8yG(?(RpQx*Ctx65MC*t9KD)k3<7vlAm|*A%n0`EdGCpso!Qz`Z>e#!y=si-3HOKRc&?W`*a;5f?oL2 ztcEWQ+2P=$WPKakL21sn;VJ4=nZWJYvXN}A4bH5`M8=<}cOmNiG3;+))LZtQ#TSOF z46z{`$`!y$v&C>`*^Q~Pk>IpI-v0JbTU|0)*M_+;1Ala?Lq^sj;_vLSWBc^mN?d!- zMUaO;uI`Qc;Hj}lm{b=FmSk=S%b9-{+zl9<@*hS)C0%c%QTvYQjZ7LH13MxlbGQOY z3|*Uu&-tF0BV=2j1}cm`^)>`#w^P3pUj07TUL6gAK7OcbjQ^aU5;mMcjM_a_A4A^& z+@vCTRDYOIA>cF*r7<62Av@$y_i^|cK*$A{6*jdvnZ`BS9UoOByU)jxdrr!PgUcNRbH7FoP;?)*Nuw^tiNu z8?h9sE8>iVV?bq7C(gQC@kRp3ORU1^#_va4%qMC~&Ss;&mTf?*%x3{QA7l=sE(Q7% z%v9{pLYnH1r?TB$zL2V^A^6fdp_K{)iN7-dPbaT08q*Z+G#rkgQ)MngRbgk-%o9#c zbA+6lL(Ak65ueW0NJv#ZvZh8CZV%vgaX-ATw5X`dA3b%N2P8Le)Y3PFsIX9n2`yN8o|P;m zQw158X(^A&9g$*$Xk)|ft7~no`<(zborbx*wT>H<+wvuOBQlHUI1+Ay3=6^GR77Q1qZ{NvDWO3xTm86ad^apnFHT zfbQ+&6(jDsfdO)TSz$!=6}mr~UZIC|WreN>g37=EY+nH{+A}vq@Q%Sj@}F6$<1gwv zFrhP5nE)!J->VD`8b~RuAiU85Tl7NyZ-UmRp^3Wu-2Rj!RB|`HdCEwO*j`Fo5d(3` zqi^Aggl!)H3NCP^;ysS76Eg=}|BpNgjYYyKhl&K|VZi!%;u;S}(f}iNu!!nD^H*mT zc+YxZ?)#qkm7IDI?zX_z=IHKf)iiIw(dA8Q@A6!HzlG=*%1ID}j|q9ZV(tn@XcC46 zWRhBfXjUuL*8TmWup|gNlPjChDM=9 zi^FXd!CS)rIG@uCdaQ>}LYxjI%*c`=J50Jvb9ZqGOTbO-S}myUkCKjZV*O>varuw{ zN!VoTJBu^%;89h*M$_)ZK`?%L^ClYGgq3g;{{{brK#&!%d!(|IFc3O|yaZkaQm`KP zj>P^Z?n!;g;G;^+xb>r{kKU%MuCKr&_T`i({x`7^?^=iP6_;k*hD)~^F=dn+M3+}V z4<_qJF3Ye4UA54tC`}MN!{x82dVzGKK+X8*p%+P1}@{8@Z^&_etIVzNp5s*)z8v=50xtJxl* zP<}w`toj4ZTajq-4u|9Wx{JRTxujL)y^4c=!&-jzYucvEb5_7 z)Yr59)CoU3nq{yw*S;Mh1`vY~?Sh#W%j!`C`p0{sFmIH4pb^QH*anL9Te`#fs6YpL z)VX7+aE)8G!)O&Ht;UXJzIf8}9Out@lHTVSdrkyVUf@pQQ75bWbM~Bf_Bm?5#Ppz; zahcPP_*D|1#9HK-drUJ`=yKUr6QvSjhUzBz`Vc_0opvSuMk#Nm@}*Lq{Vab&U*7yn zaXg=nkI>+O_XA^zT&ruDq=&Heko`9hDTK^N0} zoTk!&=|u+ibi9GL5(dGrZL{uss}=gURe|h=&g&Nx^!W`!|>H2 zuW^di)wE*CW4u^hvuoky2M@CL>ICB9y)K_)pgI9({OUxvJe}8@OtOyKA_Z4I?t#R9`3)bQZEVQ}y>+^`uErQxdhjbBnuiDDNsfw)fY%$aPJ8F!1lI9OK$HHSKMmeL z3|!YFW_5-#?Lt=r`lG`kq`)ZKpWf4-i{}udl($2zQ@O5c@Q|77-ItdTN;b;xv95c z43S1Vf%^?tacSU0hl>7F#5o3Go^(4Af}a_d8XjoJhMFTJK~)4Ii_kiRp7P@`+YL3( zBy+e;JTlWf1ZPZ=?(9yWuB6y(G4;y)fsI>c&B1VQfst>Z%JM?`EW@AOI?w$0lFd8s zH@n#NwC7RtcVGDmbA82pY4Z~EvFqpEzjHJ7?Il$&gC1T1dYHkek%2$p0tN5U zuaa9FWd;@TKvet>iG_(<68IB4wktQ5!(X|OFD+lATTbUjbJO@|7b3Hu9j8q6H;#Em zm}xy2wM*f#bRBRFZUq`K&3MadFU&Rf?!a0l`07YQE1^c&HO|H8;H=XV7&aw?#n0t%)734W{3Y8NZnKF^Q zV6iNoz3=Hv7jMs~)7Y{0jP}df2bNCz6rVB;XbFR3nw)j`%hvP1#FZ}Q;QYF|c41FSR=N(OQ)?ev30;pB_LtC1hyy0F*~ zsaE3tcs4?lEKL|y%uNf;WT~`t7;?s*&1GGA#LL-CU(THpp{m^ zsEYQL5&zhP5NzCQhd>_?cIb!9X=tP~jY8^oYT5D(F#lCh1GaXknMe@Lvsh3?<_JAI zNCho%ge&W6Z99zMI>w}oSLX0JY=!iES=F|x0~m$5e!wnbB+~SLnV^efu{v42a&+aBZx<7yo&b`PEtf?0jMW>nyjwU93$Cx9SyT}P=~VLwmj08|8BOefP0%-$4Y&9`n@y%4YL;oK|bU6Kkp11KpV>< z#4qf8ihi;g7iGP;#r(C%aW+#~tN5Ms(kAHsccy(f$b0qzrEeFPRM0V8!7mQgB{PtZD%KNPTg zo$QFi<#9(eRyou_Jo4IDOQ=b_d|!DUB;LwpRj0pT1QfM%6oy=ePZgv%}$5kukQ8( zP9U|h8nC{<)08#fl%zgSHVi#GsuXgA{GJR9@Mua6$vQ9T(;l3 zLdAN;u_i~U;45r=0J`TMMD0QS_&LF+tj8gd&%U&-Mv}Ta7W^sYNe2h>eK=iwoPApy z_hNfD5Cm-A=3qrRU!RSG@*(=5&7JV60GSqaFl0e7N_6EWS%%>w_(#$i%XjPr?OO(J zW9Pel&n&2;cwvq5>>!R%c=Cuc+ez?ZzSi%m6SiJD_Sfivovb$OG)){G{19{8i9N3s z+UD~>&0VlphS3w#se0PFToLN4excw#H@z78$^rfQYWPV=TVDZOi>+ZNO@ZL9X>@=& z6s)zt@UhN-ZD<>{vZPqQMwkNcPv(e!CXgE94Gr2`XWuWgf?O!oWoRC|UvS2x^vB;8 zX)1)gG!1#_$H3c&K$6Ak54}IuQETwomcw&W%t^+dGzw@Mv0KzaoI-*DpD+!)c^;)a z8E1aw(lfei8u3?Ocln{v_(s0(kV_xLB9g^QGN`*eTix!h9{wPK+vBk_|4j=F`xdQ2 z=FdpwaqAA<39ty1wir%*hu^iv>0AT!N}6M~Z)ebo)P_`3ZYnSdWWTD^vK+({yB~A< z1&;T@7YQzEp!DWT(2hP2-w5;j)Uh^aU3ny|urd*k`Q~a;m%^2)3B0%HSu0@C+L2s( zsH#@v5GHI3`1Mhmz;nzBNV|`zGVAG}tHV1;4TQ3{!<(DlGo+V3{ikJd; zfGk@|crX-AuxuG^>1^pTZa9%U3WM-Y8j082M&j2uJ@BPZUB-JyFS|7p3~YYD{G@%q zg$#3ndQ}G-@wxvTbw&J-pocIXY`txb%%efN0Mb$rys6Yy(A)yn7m>yu+7s8va&(ciwN#vB2CIa^ z`sA}cR}m`GK2ToIzP<^56;zK)dv%;cvAD0MnTO2BW{*AcD%;oB;@s}1dN9l zDfB?sR}71;(!qyh{X8l~P8*~d*X-99{y?*@pA%h1q9t{iMqrzO_WK4Le*hcwP|AM; zlskU&cE?>ToqH{pW_LM!xy|jPQ5?iaRkJuhV z4Rv7xA$lJmosQwQaGkv6!;ZV6(YqXOrjEADx+4+!L+ztPx+67g8=jMuQ8g7&<*4BX zf9fIBR)wsmcAo_>n@jLon-Ao=#fYt&Lho&@dJm|vJ(|H*ijvfBd<0sHmzw1~cn~sjMd$uRC5Hm*G z55~V0^=A|ETKlN!nZ|!d_U=7G+rE4>v!|3#?%9(B((W4&NwSIUuK2XU=LVbU%sE0KWPO?H_ z>tH+I$!MW9W^Rru=_*d+0K*?>NEj<}P)NO*X%rGCMmDBmpi}=M+=*zzH^x#MM@}RP z#_yVkko>~FAZRMtB%g$wlS1E1do5MyhwTCMNfI7N7J@eQ*a`%Ip}^eE`1Q$LI(fXY zV`}eIN8_^)vsd{$R&sk$CHI-p}{BpW;&?_qo|7AlVM zzOcghr7LbH2UrMn7X%rCcoB}R!$kce+3$yefbYUF!NGcyM6 ziFg492Sc6)iizCyc$~@-7?5$cR12`r#It&&w%y2t95HnOU?T0=T1TQ5x%D*V1|1>! zN>`%B%iG~^G>{liYuWBUHm`B3X|ly4X5W2O)1K6V>d}@|(3zh1fx%9IHFpN$@k}Cd z0=1$a!8)ouovg`e zZJHA{(|HLe56lBrJ5erS_6L9ijW|iugsM;;TlDUna(4CFp_a@ElH1JPv^|k& zN&Nl`;1ce89cd=pF*`4f6{Ibx;<|FVCi1L|v@xmC%sFl~2Hl^^stt$Mk%m zD_6+p$SzA>BhYMM*yI^(K(RP1LVW_&5SKKa?f$obKi!%LIpC$YDpBKir8c~{{?Y?c zhYH>=#2sEGQr*&AYSUOUK2|%rDvT5vjICd~x~MuL*H5f|W|cBx{zT`|-r>+vJ?Y=# zP86Q5Z%);OXLV-Asy+4X zFd_jmskwJ>ST~B>n_G(^gN-=dH{{c;Ukb$amQW!%ZX`q16*6uRG4^#7BLry-9}@Z- z`}3CifoTh-2OSo}%g3cL1aT!tmlQwTo!gNU(R2IuN$ZB#MhHa^SGvs~kd*aoWOZ&m zF6`SU9NJIQ{Iuo39Qap?@S|UqA}VAk%Hbh?A8bP&!yCVirGQohVmg3Jhon?eV1fMC zB;1_+nZ$y4C$KNb<2KXDt`UMC3^K5?kdRGcpG2mMFGys}FJ?MVl28sOXm(11*qNU{ zc@msC`ea|#1aw`;tLlLw)Q2o}HWnehxo8?x#6kfm+eJ*iRJIE)hky%3J4-6**2S39 z$j011Q_cb{Q6Pl{KuFDI`?twA`CRluQd=gknu*Eb6Cygz>2<9%f{ByC?)S&rvqM$EktMa9t0v%};ZC@o< zjwzQPp6&3g1cz+7kNNntUPzcv4^E|Gm_?K9MI^5jPp~h-hE`6ZQh`w{v4?u+@tCxsqw4I9dZd_BGtV_oY*@%9pQ(%@ld z?Q8|aL0n3bP#Eh&>Cg(Q#5lkJs6qkt zniWg!hwq#)X8;LI41p1B=VA2|u8)IpvLfIcvfD|Lt}ILXT~l;1K1d*81GsALKBtJk zfFVLP)=}*T&U(Oa-g?dx>?R?zSNxLstFwO^U4}8Wq3T8cJiiO;EA`o|9?H@}HHhrT zq#*MVe67_hNJ`5wr^y9W_*aPajk;n(JDlSM8?V;mV zVGegJ>bssTy1tLUfNyomp>{7?)U7&BAsk_(4S($LY#DAiaOjZ0sgVAdZs^bwkU5*+ z^ENJ{|7LybD7gtJ41f%Qsf#w&Q9_GGGQIT_`Y9q%7zoMtP8u)^Sv?NR3mTuVaKdBT z9jfDCFt~li%inLGV%L6zb3WZ}dUMW?^1XneXWS^HY9cBk!3wEelgk{A8=f5?+CVSQVrP++~p=ynDUocew_Aqh?r3y2XAJp_0 z+&6E*ccAt|VPL=xZ8=52(ScAyYOcM#)jiE+u3Fydii|gtU?_p)7Oa6G`oh zE%->O(xSn=eQfi;T%Z#IpNZW`lnz$NRhY;y*(bD|oXxXS2w#h$3*@_O=V z0OTh-xOpEG6v<1jb>@X@Ufwyq#6SoW6%MVQn5W}-W~}`X39^UU1%0yDdp~Sw76vcg zw~{>dz%DF#3`txB=iMMVau9S&7YtHmdj$wa1Z)G{-eYyO=ot_xqG*<;cQ=LBr3hx% zj>2K2N*4j=27vL*x3B>hDNA0mZ$e3KF3LQy5|y`FA?sA{TeFo@O?G8;yRctg&z}ZA z5vG_S=;^Rr5u_44VkM>$UQ&o^|MlGM?T;gTBj!{dA6mZoc2+BbH~I0~H!mN0+?haN zhps%{e*1HaMI5N0VVgk%p5@=f+FlJzJ)rxFsv$Yj5F*2X9n}mLl6qHk4Il0Mj9~zz z=`-USrtiIX<|D5N9TJdl@TuAV*)aYY;hU~}rtc#&_ulIhTC0rTwU@@zUXpJ~zLNO! z^gX5AKIdBsbsA z*F_i^)^kU_9tkQs!gq}$z@oe;1M}P+ZHD5B8sko8z>Mi5{fVtxqV~O$)?K7A7yWI* zaI@!_^c%8sajn9blNy1djf`RgB9+gj9#62X0Qe(8P8=gN+$J?Zxt={fEv&-qM`CAQ zH|Ol*A6p;LL5WkI}sl>)z&v)o>%GS<&%J9QCd%ogjVHNgQotwY%Dg;BM z^S?8{t02N&F~8?f4PE~y4{XyaHx$;vy{F)D3biT5*`$cI`2)06Z6y85-}MVu5v)(= z|8={Yt*K{oO{HGDS=D``>u)jMx^Ua>6V{q>q9;NcZsNbQTIUn(5~(9=lCl4KCDe=uR@4Jvep_f z7(^m022Uc4@EZhcBpA~Bdy%Kh?-~zixk;^F?-l8?$NhR{wU(L7wtn_T&{hBB*AZ)R zHFVa#@xK!O29?;7J>ZI_pdXa8k3I{1l~Vugnn+7p4yaK=2n7RxX3{2K!Yrj3d%7XU{$t!6TUipdm3NYRC42LJ;TxlK` z>!`33O21b>IPX3}xh1KPhDup$NJcPP4n;;ZWJ4$aPmoUqnt}Pu9#!!9uQ)qO`3S7s z1b^oUIU1L_RHHY<1I}g3oB z^Ds!eG@hUQZ8E8IX@0W1XA3K;@=ck)IOXV3^>!LUMkY|pfbc(>ED zG5|K2`4n$%S%@nyo4@I)#(z3=R{A*vJV;92`W#i>?WtT3a9Oe2y3f`cFvBEF69 zY#LDd3i^!P?b~p`*gm*+-JaXoso7GxczVyewS(J@0~{%jqbz8(82LR~4y6^%dw3DHE> z&!6>s`LnKS?%Fx+PI3SK>zql-3Lk{VxEv)5OFE)ytw+YNZ{T0_2b3=&_*+@WJR9Bq zzz6R%*m|EA??LfzGN(`@&Pc>UlpWY*G+gkd&R&r#9f-oAwfy?EL-{SL%2+`-xuzP6n++{DGkApG7FmoVfk5fM` z7ua1`U`>+~0y)INjL^|#AQK|i{>)o)ZxzZr;GnXR9(i;ZEv~duA5#e`nQ2crQ!Xmo z#kOH>p9Utnc{`qwmTgqWZk0J8&D&9}&;mB4HFhg*ku;L}=0RuzR=_e=)o9U0D43<_ zi}#^L4WclyCpJp5Q|AVDHGN7NcNBL>ObJdq zF-qB6=Fi1Tw;Yf!2pDQK*2*b&V20g7x=Skyd|JJwMfQpL^RI26F8+!VC?Vt+93((o zDfRMCMPDO7(m&phGZul{6yCasuKfe57bnna{y|m}6cTa}7m6svebYq_QbVbk91hwj z{1<|wdElo87oF|+NA$ffBIY{fa=uOIs?O2uRS|K9_bUln5FLNN?dF~DJW@^VhutR+Ud2Dh*i;a&i zxK}}MBmoj7h)=Ug(%UksH^P%-xK%g5-!>}URI0-&YYV60%yRXUB!@pK#Bs-s@NvPd zHyUxLV!$T)Bzp=a-@{XQ`g_9d<$HJvPvd0w6C|fU;Y>Q|)|9d20Z~jqSQ(REbi}|7I}m;C}hX;HsVtu&kRY5GamD= z#I1As1l0a~eFE*aG;au{HYHX*=XWX9Q7i;*FBCiP@0vd&6H>Si8Ezn;P3d*Qb~K53 z`U7ZsNH0Pf3Hd$pScl1&f~ZOR`}X&REr{@$)(CBB3m+l)#lr~U@*46{vLNq zV0_OLc;Age#Iu_9WbyXReV5mPkXVCaQa^K2pnNY7h~MV#Ew4Y4eQdo=J=%7b2G05# zvw~`+s^;s65^y7J9JGsb^)sM(GboPuPY55+S=*i;GR+onYm&Py>xaUUA4Bj2QV4*P zBX??xLqiYQKaL9&uL2H@RH;Q<4zj)$eLP4%rCwlVQMNA_@k0VBvF&VXCj8KfqA z5Z@ubv4S{tjM#u?$!kccRRKk7zUqtTHB zGKWaT{ulyvivnvd3wV{qS1w+Boj@5K2$Y2z#5OK99>2Z1L4_c)UadfGCBtzu|R5Oh(4m zprLm)q^?ahG^DOcx2z1h-NBXkQs_Mu{6EH{+-jGbg^(Uz`W1xzw{I9 zKYO!hNQ-)6F^|(3cZ2M_g*Wpi5RwFtgn0aqf=Op6VDNCl@cLb!-6Z@au}OsZOUW>E zeR6u|{daEn1bD=A^Jmw8;?n)kd09T;<(i?!<1Pd=DECC;o~Y)BdO|K4Sc?TnvzS0pkRfthv=xFE z3rKo}bg!fBFK0WrBBwpR&gi9MrO|)6j>3S3%YjAZP$Qczl*U#J3VMKXFvHkz_GLKp zU3<~kq009lTO4@cckv$QKoY-Q<8?%wUsmhzxzrYiPn}lZLCbG(svB!nJlCS)fy(${ zxA0yY6Z91633M^^;x-c`mR`(7JMl{Bf=h8B&uTX8*DgP(uiJC$bHpo6)l(LvBDC>| zTc5f0)@N`6_hCw>)`Sb#8nB!;HS7G1J?r#?muvesTz2bA#9pnfr^kzi@t^eAt*n*q zYa%R~=4P_C%HyUcAY@6uZhH*%QNGo8+536~@)FiJxQ1ZR>9M!#{O`s8BHKJ~^3MLr z_?NTqpy&U*Is4`KHD~`KF8B&5$JM}+v<$690#T9`ER`8#sPfsIOvIub-VVa7 z4Z3;Ggnu?2mFZq7R#_fJ(`;-><*B@7(Jq?S_sD5IXnsDL#Kjch+7l6CoI?s z>Ua`~&P~rQUFu&7dOSf7+dey?k)R6Jx&sh(!agQub-VNYiPsN{+5Qlo_XN3RxS*jj%6)Qp5Hai^ii+ zFcf8h@M0igsE-u6*jxF@J1_qBh^fuhk1Ec~OC;VoG^5|)yGN{GQ;A?O5wrse{zTfQ zF4P5SpAt+Y+Z{k;({yaTo~#2dkkeunbfcbN!uH=k4x3;Mb|K0?RmmkGRKJTc13@?NZkoe5CMYqW zxG1waUgzq@<`vi0ZmI}e|9xlU4if)%q$qF6c7dfJ#_T>3b3k^?IxDAv&Dl}wC>9FJ zO`45%gVncdFtMd8D5SxPx?zVe(%d&!T#Ng`oQ=J0V@YQH5dSCsB=Fl1AthA=#4qNe zL&BYwaBiW40jmVf0Q}p?XA7?V*cKW=zDW-QkO9paK5LbC2k@HyY(e}|raFWQe!O=v*En+#tbdQM3CC#kgq=^jTsK1f4g zz~fQO-#OHy(6be}0%b*CV^b;<&ub0A##A5%2tQp_-BG8{sRjZn!1|b`8GaQG(oAu9 z!B&P`wXt~6s~K*?6ZPdB&DAZ1#r%uufwid~1&{#)G&%>}S+@hf!m0SNm`hE@BOXKZsBTSh=?MM|hdCI0{1R84T=lAe8hVAa!9wqbm?T15vT?8S)P+!*2pthw4hdTcf8Y$~AiW{sEL+d|@{zNTMKVhE;?mL5vj5B5 zn*i8V)%W9b?tbsv_xI*)^WK}8H#3=idzmHMB!m!1G9)o1Bm}`hwh$r`iA8pym91&P z2&R>&FbP6s5tUlBh^Wz8jg%@-u!yxqenL~qudPU~|IhcFd*6FAnS@CF|6p?8-S0Wy z^F815-M?A?f^)X-8XRlYb!+{(>5*nRa1x^$?HSY9N!IqXY50|C==uIeY0lx+i||OU zI3Gm?a;FSz`*Tk?E%Sr04FwBeHm%Hjy6S;s^hh+r*l8Iaj-p3&xMo+o8+WG{1+Pi?`tKe<4qv6_yPd9wA;TsJ@>K~^D4g1-n+{hk1OE9URaLp>d^P`K}JVSU97 z{iMIWo^KU?=37XR`)4TPZjerK0&fw@+yJv{`}2cP!d5lakZrxDJx%W|qGWR{fEbm! z7hdmth+6VC2s)|Dg+3b!bP|gTkgH+U^%OiO)x}-acBOb{-WZ>!*{?&%xd6@kCED${ z#PU8=_op45eBDRHn|Yr}e5X~T_GYmwV%LR!*hIB7%Cl0PXXGjE1YM~GWKBUFB1WUC zjKN9=8Ijm1=ux>YZUAYoc)9Ooa5-QfLuK!z*S>%~&b1>euw{SkhBH(8Xedx{-!5eQ zpW3wxN)~p32vT%{7I(nSpKiy7^M5WaNFj!@4_Hikks9wK)H;|?04^~tyLpPp)p=AVq554(bKb{S6YPR9Idw9b@ItwLvk+K zRR+Bo#CSnYo)SNo@q^1N+2H(6iihrBr4>nCQq((IdT`>brh$Q`^|TT4q{vGW=F&WQ zYR6_yKnxs;+#F3j1v40Ju5;BDrT`K(OGW8JwF$xQ0{(r1eKuVtN}9Y4w3>aH5{7KE zpEdP;6$rTMIu(BqjVt?f=|lC1+j&Yky&IHuxVxNYtJCEpFK`;X&TmyzZ~%BnSx+wj z@(CG-XzN~RLVFNph$x&oP2fC+SYeDB31d{#4LhX*24089Lv_TtdW!~?oZ2|w>ze+Z zfgEamWm)7l8mc>uz#BAl_A9-k6a9Qp`B2(N5L5H9jp;K;>OG^pi5DbvM(%U1!zZ=Q z!)T=w*c3aqi9xe>;DL<`d&_5#Bz;DvpNH@8b9e|_K-QBX2$5Bo^GJKLpkP4i^BBx%?W{=ymKQ@{{~%y-m_KjLXy{y10{B6? zyze5;;#z2~=7URL4WE$))OW;+>MmDY=Lw)f;6d(7?0{Ka1Zy7VHPx!93=?RHcA=(D zg2+S#9Guod$+vNUM48;7c-!d%rP#Vse^YE(#0*6(Yqa2xteFf43Zot~8ZyF3C~;4= z5=}j<7ra$t4NKQnT9ckQXM8vlLZ4k5bOf`)@q-2Q>y|}E zOC>T8x-bx{C463mrq`il)M+?u(L!3gk)$y^C-flIOK}9cKoA^*vIyGl$z4Q^X~Rr@ zqOF~0S4!32gj@=AZ@;)CU0X`k-7123_&Z2ybKctqN7|+t_wj4uJ)HJS4S(72kn|VQ z=aGYvvOb`tPK9*gf#wu;C%bRuIM)td6^mQaxt@vH8BER6lD9*V_H>6VN66?dPm zJjCvAjwqM&96QyWw@YF5d48(8BWSSjC-pevgIrn(q`9GKQi({&2TR3(c$x!RqhM2` zMJCQ^RP}6vpPb_yyD@J3%Ht2(-9f+SS1aIkzFse^oPKS3sb1K;Y0tNB886J+zIS_T zq4LF#tjiR=NHgj!X4o}`{eQjLtQU!~KDg=b&DWf*x2)a1b9#E`g=>tK_ushrZqF^} zp1HJjaOtY;+gB~_FE8D2ZtuFW?$&ZFNh?$`R&MPcgS~NrbxJ>D|G;BhUA&==xu{Z* z_C_)h?p##HjudB)_@hz(1lEYm1m7dNPO&(rKnMR5aP#wceso035I=!v)iUO&<9xy= zU<T#U?Ww=}JjLLfzO}T(a18Nr_=967@`so_H3<;bB_JRt8@82mvF!jnXndN;qdS@%Fb`U&duc(xB;-mfc0 zP;WoGQx6&n`j2+Am!+Tb{!@FYwxz?2615nPvzL1#do|+%nj#k%+TI8VvIQq?JqCW}7JEXv1s~r6$`+c?6>(m>8 zpC5p{_YL%6A=Xs##}T|7Xe3AkjU-XVcmh~SE}8)e<|A^!fgAt_98!0X3K8y85<>AS zLpj`q;Z~ z#-#)HQ18z}cvbhKv7UPiv*-JW4a>Fj44ULem-N`Cb)A4w$KpN?H_BhoP5-s;wi#0 zYUfWeCRxOT4slvdswd*Vz+TUoHM~hGEN)PH%P==d*D!%R%g=NDLAvLxwQ^&jg(9~Gd< zd_CDc{J~8$w>I72WsgY7bQa#~$*ez8iAw%#QZpLUa#A|R`5U-Ofqg#}vUBerQ7-7r zugiDdNIvjx{+9&$NGlPfYD{_L6^4F->w1O<**nkO1)~Gc19T(VE07uV&bzkJ-i8#<5*q1HCdDJ=3K_A$h@oI$LW`EM%3&4` zS0eONL78nG%2QG%q8(u3a@@AsLW*H%+`vwjrB6XqS4lK4_Un<%#NFLZtMh^Ibobqz z7Y!s2?Jf7NOy|P$-Y~6vN84W3dD=kX3wz6`S9|ivkL_E~KXs5-lUu4IQf-4H3=862YXc9Kf}BizyWLW+ z{EPQYG)#z4X6+u#oP1Fizx58?eNNmba;UxB~& zQEkTfR}C>I*k(PiZ~9)q^6oB5DgP(sYc}7*%NEx?K{e*W9>&PBMD zqRgWUlAs(-4U=*MVset89=)(YXGmW%WM2%2v^{clbr)BjaqoejOASK+ z?TE2;tBWD_!C+Khs!73^KB0H((V&dqSWwc~hp|}-FBRJ24|j+y@SS);mu|G7$F$fS zhj1j~a-v*;<>qtmMm`KJ@R{7TkF1ft@@_;#mhGN(4`0>zS(<;M2FH)#BUzxDBW^zP zx#$=sA!GnhcR=1DHu`0v5XWX~4x;w?hd?mdkKS3N1dtlWX}|P+QI%u!=o}<2`49-U zebGB89s;Kxrynz6Mv;T>3Nt-a;ZW001Z-zda=4uk;9jy{>ENK_uygC>(i+ggYr|sw zb60|6P+q%TOp1?dl~o0TOwTgZXI2Vow_CC7*zMjk2qm}tfvLeecxF- zO1}=xeFJl^5i1C4J=W%3t<{1YsDjghIgxWkSl&T)seUzaMacHexguyyNL-^On-=f7 z**A+0vr~|7G}EVR{;VI~?3rj7tWh*D*U1~&ve~vwZSKvY&M#yWnvu;A8S$fzD~m5w~YfVZ^UG6jP~U>LI>$Tv*!X zdfqK<%Pu9Kzf;B))ZcQEvrzOl%QHg+}^PsB2Xh7#!Zxw?Yh4ium zP}i4aBtQz`U&|2kI^q{OvPp&dm;vpl4U?GHcnpm2J`}##h5x8*#xCgz>i;-0{qiJX zY`5V>JT95a>?e2GukLEwwQJul;Q#uDtEKzl=i$alHc(P+q8w$Jvq^FAK~#xn7z*wL zNg!oio0#%%xk{oCA6pJA3gvc^Hid(Gr%&Sa##T>2)rrr|49U) zs2!vSB2StjBzYu98XlN4JOs6r03*O$?@rDa1PYs2vkQ93IGnZcanM?N|6T2D;45XJ_F%a-YrWUQa^itL;D`Cr{ zoN9Sn&gc&{`vVs?%SZ=eNglra_u(@eVTX$Q0YytlXF~)v~WU6qG}y?VNZSwYzUx8NVr@c4I$-ujVuG?%maN0D?O+f$a{n)EZT`Q~#gUH$OY z@9&&1ZH)Ttt2&*aJKRDyTO#7FlilFE`<#;o)8#syDHqr1a=!Yw! zZ9JRC1q2zQA$#9}^uFR^$ z05i@fm50dg!af7Qz3YeGLk}okW3*uu{(}Dsjpr)l?)+%Obq${Y9yVZ|#?nN9!bl1S z!2n1BwCTV)iYJ7%3VakIG(i_>u;)>U9-xC0g-`~r;?6SZu`2_PhmNp!iN^qbj?Q?5 z{IihT)8QnDAD~z9Tt`44B%dYI6ZCO3+wm}NuM9sAm#i)LholIb@z0AG#LX0lNXLFJ z0u{F+pb+Pi+1|8~PN+uwq;h{7lfxb#uR;C`@$5QO5U#%~v8>$RE{Bi2e8X91-Eh_l z-)KiV(Vt0t!av5Yo;Q|TALxy!%9-)8j(j6au`B3n^nCr-af~bwTRdTz?MJ9&SPGTB zYB23>YR~*`@gMSvLd{nf5XN*L#FN~-t1an!gt$PU+vBZbCx=>^-f?C{ERy`Y`Ei$ zKjsI>EJ&9wyyCN;<#UhX{{IMTIqDM6=7IN8T@rUUwKvoUE@oTM$gDH|ilc;Nxh+kOSUK|aqR-gda$0vhfo9It(HIcptyaSF>~C&hH3 z@Yz>hMDBCs^p_4yVWE7M+>k`X7u-VeTC5i|{`B4q{AMNrmFk;?^E`2INJ)=>m^Fge zqmLwnot#by8b}hEkcfl^9X2!yPK(Ff=IrT50>@IQP+GH~+A1v3Jou}rQ05NSfF^fp zu5>|2tZVdwHOohakigW_zlVB&w!et62zsOBW6f(6aqs3_&QNvHF9qv;8}C<)N07}w zs%J-a$&DYxY6E^6Y#GV$6#e7&;NIkQn}>SFzU+W>30EgP$fMv0KkzvR#yvxuuS?$R zwDicoaAn0qqN}7duECvRv1mM@$pJQsRFTy|jljbPoHd{geu~R)6+Q+0?BG~CYNzor zezJY+pwpfy`<;ocU8S|7tV6Fz+uFydHSh2dUpz%XJM!zT6HIBY==M)W*Ot0CPcOzk z0gYEX?1!f|porlN3;^jRJMYZF&p_Kj`Y&=>B+;@?i2h_)rvAKIevw4_C^f1lsG1uBFpXfsXwM%Vf;b71=h z4_KWPkJ9r~bblzc1rLI${C7>;qN)y#pD3)c-f$}8B^H5r`m9frH%SbJU0s{o`)s_xl>c6ITV)e|sK7d=+tl1QaAAjiNgVs>EO zC)hwFhT@<2hw1;XE>!~oQx`ajs%p#7Ht&j_QQ;7JEg^ zwAx~kwzd`hzGO6p$d9%*D{8g10sq{#>wqq|tCHHYbuhyDBjSfT<6~YD3Tc|_uq+_u90^;ctNgtxMA!kjLuR!8eLR5N8-HMkH+ zbd=JlaQfv|;A)u_x&1A+yJIw8f;Dmn714RbjQ)^D;y1#x@`b-HwpUhK^cC&|LYI@vA&Bt1|3~d4_8n!JT{n`H_@i;!B7- zNyZF)arakIQSo!bk~H{f3*{9Ts_McKYsRDeCBPT6N&|IB;bC~KG$IRKD|DBA;5`NZ zj~FA0GvZU03ROCXLtx+`O4N?gSLpz9-i){HYa7QP^zOsXKK28ovEh3dtK>Kx;6G6C zgY>&^-$8nUcJK)0*>dqihqT-Sm{UCus_C_!BJW*UqVg{DPX`6Ud=;(6Fi2Fmy3;j#8zyHL_~-(l$H z0QvRUMEM!;81A}9-|=Ie$v}VD;Ji14FR38KG4WwkIw4XWp^ssK*^QUex9nHjP-kka z{Y8B7FurxG)Jq?*Up?Hm?;w457ag+2*aMDDKu)IoVJ50a5MR@RksXI;)Omzs;>|>( zN<*ajAgxpdfL8jQPjjoww2{2hVe2)NCGGk+un4W!O_6b+t`m=JV zGgSVWeO4;?;Dfz>u(3v~X49f(0*vDwGCRLe`S+kxnHo*{G(sCF&_ThL!W?+eL#3j$ zAD>n=){!N|0L^|{yy>gQq*o?rb))nm;ZR(=&+~g!szj>3B-Z znB~;@K|G~iANPli3mx+NIR(^rdDN4Q@0dk@YdL`PdRBfcCP((;gbHyV zxPxa1*uS%ww6CQyBbQ9uuLDEbW&1%8`lqKk7QQ}x30lm)8xkqSDWAjlv|Jw6YDq>42J86LsJlY$2^ zU<>d`Q0M2dItQ%VG5GW``o`@dH$10;>=$U6-*a34{{8)kx_OSS(Wj4}~Spn&00jvGf zz!i4QblqqHeE?3%7wwLfkLTv6S=l4 zN;lQM)?p?UvBSbFWTj#Bm$|n0_*_&!@{>srvJaG|;P+gR0?yaQ^{Bqi#CotFWc3_lTH@XCzgvd6jp)Q!l`#S1hw@)yR@8bbJ$|BH zt(!G2Zd5xv$K08_v$ejGG}gpx$n`roTsNbloLe5i5(@T9xWB|JoDK_0NV{MTG5$1~ zWW*zSO}w>ZCMJzwe8!{;?7#g<7pdL($EhaTjw#qQ2NqZ7B&Of=bUn=WKVLUL*`Lmh z#K)Bjpz-9g09V15s8TIf8(^o*DL!d93!rTP3CY;d!9<|4fpM7QZ>iu6E%;4{+~fvU zA8}A89$e)z^XwWyW&|^D@1C|leH1fqpM4_C{2xx#0P5HA;B|6AJ#AGfn4RkxBB6oM z0I!ci&`}Aw1^F$_7-xGc=k#x%zMb>_M_#Y7{O)+}oJ)Ri)~Xq8s*?*^#KH^V4LmLE zR4tf{A(S)%ezsP)co5>U0V$qgup-eFYeSY{&;(g66_JOa1cwl^JR`J6c*}CXK0@DP z^YM2%Ts(OC=zC%04{=e#5jY@Va9Lw3L=H##_&+sy!+xfY2+u8V06s#8@do(f5gsLc zI&!*gZa5ctPqw4#JooM65gb5H9>T$eS6H&)=7&uE2;u-H^C%9Ibjj0iwgl1S_;#F- zv>=^~Jh__IomQg()Qg9a6#lLOHJa|F*r$Mri+Xn>E?P1!hUI|a*P@NRCN6%vCSm+H z#eQTzc}#hNG59pX1u>E|{gL5_5=g`hM1nLbNhB^zHqxbN!VH9mql!NnH8efds3xTw z>jV&9;;h`$mfRQm7QgGIcI0=R4M?pj3eeyud& zYYEyf7@BVaRG63@5GJgZ^n*7MO(2`8n>%+7n`w(!18LDO&9Ir01CCRt*)f?uNhVW~ z2Oh}?MXZs?^WFm7C0U=lv2kZ1uFMn`e-2{=#t_-zXP{~WDpQRh=bZE*RCk4T>uvF~ zr%>^}J+>~>Oy~AA4f&+E^^w)$P>R*=quZyNbL+<5_VzdNho_1eg~@B@S5NT%pVM$Q zVq1O;9a)M-A7-IM6hTOQxGQYfbv9&Qf4b0(ih2K?oJf2pnPi^iecaX}9b&Az@SS1; zSCZdJOeC3=+{Mi{fWapl7D-n_SJes}JCk4l5J2HXzA(bw1oM;sQISQ$EbbJeW71Z= zVqp2G3z#Ku8Q>wTwPY5FMN9B?V1Ke$dcUTYT6L-2EUF)j6ii9?ru893RZl_XyuQ*> zvvBaXNEj|IJMP)hn(}K}%fmOE73?sY)l|p4RJ&>QNtM;wI%LnV7B;JQ7LnXi4u{l8 zA)&S*p)=~4Hl;!l>CW}jw@vkT`83vCUbADzn#BXi?JSR;JT-dOl9ncN$>?oD7-|6q zn1xpNvLzh8_cpvAF!*~8gA;~8q8+q>^|H3siKPV1=5ASv2C7yPn&EJ9bWwkp25|iI6ug>4 zz|V4uh^s$@xy{L&OW9q-f$PR7{1$KbYV-X(f;OY#`NwA-O7L&M-xI>eg!JeX>qhzG znqg_9j3Cfx*DP9mY`LK=BJ5Y(`qLF;W+hCjDFym-a;~n2c9saQEA;C{ks$j7rGUz$(6z!~^-h}tzJ#CtH zZr%Q*_Jn|f-Q+q^)ZW5hM{`iG){rBQRr2g4o#>@}P02G9^Tg1)f~n{rh$coF%&b#9 zE>6-qM4NiRR6#_349<1;KGj+DkuMmL5)?AQmwRcFGA(J^hw{BQ>tTI`eASUf)e z2wg&&|1I35`t0h}C!M?YTTA#A;d0HiPf~7@{fsgwqyE4;;sB(Vkl@IENYOr&i@D~5 zSbSl;g3}V!B=~#o%sqxgCP;vCC(oYK%1>R!eZ4>YNlK2gAAy&6A9xIcor1bKQ;7N9 z3wucfTGc_|l;a=gXD!@;Ckny9v)5RJ&^9(d9M@=-)EYb6IinM(ZPlMi z*7Df=)yd3u`_aA%ax+x=e4T^KmrOCU-8gCANm`|>ri*Dc!@f`U+|JO(3p>eJJHF9g zSUPW%sydIJR~jw%to5{1T3R|L{GLF-1N(s7@FHrMEaUz%l=}m=9P(-eMMb+%j}$0e zrVT;{oU@g2R>?4Aw&d7M%OcmwurJ0lr~s0Qhf?7$fPA(AvD(IsCWLA<8Mwggr_Ht$ z@hYh{^JxTcjKVW%^cQ`L;bC;@;=aN?rQU}djZzNA3XFG;E?$*Tx-w+CIdT_mGhIsb1cNQ^Jwa`+2B~~;d zSDl(mDM3rorDUK{>1qrIRMrwTS*ShV=?m)At9PhZoAU|vxkN!i0^fEYICabZ1sQ>! z=Ls^|pOpQ68Huc$Cx4klTD+i@^U2L|6#(gnO9s61R=Azc-Q zbeR1LgTvBBxK{F76*m>h+0(1s1ZPjLQoIQp_Yzwjk)FWuQeJ+-Uc;R^9j{FG2=1b5 z{4pObQ5d6|-MRZc#J^zFc=ZmqE5a3k`_azsM4q7&uC4i)@h|dXav+WR(Zd^6GkO!! zGx(IkjWhbOD(V`Yj~)NwW0%%}p*b%cQ;z}x`NQmkZ{9}Oax#3ja19YAv!gqyz}oNX z)(7hM*_Ei{I8Id)%4I69z)q#;D%(q2_Ez0Kazu{P4Y&q+&lz&zoG#s5_m#RY-cR)|s8PJkDg%n+OCPZ1;@NiV()N$8|wGJ5=I>0V@UY&iT89{wpJM>BjM(+2ZnmzX1u ziJu4f4fd4v6^pCZSq5 zLAsrH@@bw2c0cc_H(%n5^?tGP@D*)8-|`doE!^qqAe`;0Z{hE)w=EKMNQ$q_9l__u zx=|fvSBP?D`gc25U;pwP&X_antHjPwzD)b4?|x=xVN81$kKyzPW95yj#YmJ7KCSsKyH=EunPoCvp7=MK;i^vE0!+k zl<6s$2q+NAePS14D|Q!p%D#A^H5~XH35qw2tfZg*QB_7!OlO_un4ILuJ%!*VSZ@w|S=gb)y$_erXWeGy9~@p%gW&ND51az!cxmjB9BIGhUI zioI}(b#dAHfY+n@>_~@4&&T~<`xN>Rm)FIVdhheyp^h}gUEfky+CKh#fAB>j0<^JT z<9NOA_nz-Wqex${5j;*Bx;4@Vtppxa*(%IvB8~9OcTIgNsSGjUfetO2bJoo>lh7dw za0@~l0t8e^h+2184Y7oTJKx`F-$c#EvHbv3Y}#j?ai9I){OrwKfLE_-lYBmK?8B1Z zcbjB+)sVED58chla5Rb`KWth2cUQWABN1aUbwi&_F_kE~=Jo!$?DJ}ja9U~jaKqoA zPU=0FujCVcGCU=~zY~j3Lg6rUUL2!&%w}Q$!JcHS(#yb4^fW#I)6o#BhRg_ztVD+U zBW0a+B2{opQ`=x~d#PD6tVDBw2ZqCt(cXg^K4&F79w1?3tD-cqQ~q4>Boa#g@gg$6 zTgp8~N9WR0zUeih1MMySs$vF_>`3zPfba;Dx?8n7@bZtNN1=$Hafh!8=(-R+ z#cDKTtV#Dlt1|#Wu?0i{G{=veg&}jwNCN29x_8iA*wIaznX8XC-e2US{aY3ggNQ<-F6U@^S0t zh=47j2H&4Gcim3&k!V{V7H{1pl1+TdXHV0IFNz5W#34MSoz(D!1^1$_#s2}O-u%^eL z^$!h3xb0FTEs_zl!&d-}l$VRxD;f1xSw~Pk!l>k6K$mZgEWYlJpx2*BW`~zZ(MCBE zYi*8)71>+)r*+}*?gP7h%|Xv3JCA6@y^Rr^OCl89MzMHJ*Dt!*fWg3E7c9IF(MGo= z{r<@%5RD^xTPl-{7up*m74`wceq~*_KSZz6HP!w+sk|9p)K67jhz^L{%TI7Qov2@h z>XGocY=;(Lj+3g2Gx>EMc@*kXJ@4|`aS@Wn`4x(D{s$hE(dGNcs2_zxBiOuHJr|AE z&TgQD)*p*m`i&ISaicEX#u>FcxK7pnzd~!fi=X=v-MR5E{V1W!b(U1~MGdHypwF~tG8g2L-Z^=0J@JG0&I65KXmmJuT)yM@;z3hgz%qidPnW2Gti-U(W zQv@vcsJ0glAGb-~quMhD{$?G#;xBHvqTz;yKjmXbqHP^y#6H%6InP&tiJ9^L$35)j zFxYMMcFOxgb6IB)g_a&RzcbN|<;-xE$yoDL!k zkf*_=lZ%g9k*n0Po>Ho=mb9?WR?0)aTaUp#n8##51msEcKJ2D zLWM~51Isa4B7qVls1K020k#%iETAq)Q6-|zxZRQKxlS3kt6-8&lPAfLGU?b|vi5qR z;(jnoW)}Oe+KgR_nMkNjyP8lS)>L+}saa3l$sf2=-2cty6>K$bfc0il*lDtSOtSp_ zY+b~Dma58nPd}ZPuVtO-W8S=C6Z(He!^K!f?uYMKFZlKipsAFeECzcLIK38hx@9;5 zu@w2?k@*Oth#n&78wzv|9^^{a6Uaw}O!WK)U>)7SHSGKbaQYSYe62n9vylkv^xQmG z;{hZ9xw2T?2dY983aF+T|WkV0VPASuW4>(2kY*shbZnqW@l(?h`-te zKe`uy3uCZLUjZy8!!&nwI~p4h*X-KyA;TaUn%i}54igW;`GS&>b4b*q1}sug^l%ZV zW<%qNhNM+|WRHb0_Jiw3)?i&2D34oFKJHX_{!jTc$bTqFH8^bJShFo_+HbR*@P} zc$G|XlW34fnIvmo)_%r4iJ2fyeU^1bX3mG}H?iGeFQyWnn1pj7p2cgjcY0X|)~@y9 zyotx@EPK$~xQpXg-Tb_KMKk(AxN?Q`WllGS;mw0c`1-y`C8{Lc#BBxnE+BcoL2I#(2`2 zFKdh$9?LY;FS3B&(lrH6Q_sv(48!!9ru4(fdwwnjgXMH8AW8lNTf8tG4EDF`KAkj&<{(M*f}WF3@pbPov(2g$Np}e z(qTQnzy84)zT1?WL-c`k;KZj6Mcig0_@!#fqQDpDyik`+F7Ic%$=S)?(ZBp4@e9Zx z;iPSfk~1DR%}55_a+o$uX`>sWhv{0-dzjx&r}%n!5bNQOIp5U>A4byY&ful$y$Rr4 zHe-DNlK{2vjN8c@1LTn$K!{YkQZ@)|jHs{cWWjwh;CbQtOFS!XKiba!TO!1c^9Fa* zAde0ZFV}s7Xwxe0?|TToD-rk=A+J;zv=qu^nx&Llu@XTdMb%9rEaY=atXNZKkSiD& z8UCq5-wf}*rpWDiHJzOQC3*1K2 ziV$HsJhlhee|G3!P^@HJ8T^}y-fomGZc;EgmF?Kye7F4{*@etpxm!9Awd34qv1d;- zviVG}WyHO3rH%ZW-DCfHJyX9&^GwCc^aObA`>{@q!gg^{!zCDXlP-fReWmeOZ$PE_q`NB{x>A_)oaX6C+;lE4<_P1T~M-Z;! zL*U9sWXnVaNkhrqkX7)M-?aX|t4lfn?=Ehxy9!kv)L2sY76Tp~Jdd44n(GBn1wt9P z)zJLq@}fnpZGIg!AI-^lEZ)|ZfL6BLx&pEP1Ae~_8{`j6-DenR=-Ra&R01~t>|-Az z7?KT$e9X5&=89mgKOI%SKZNr&`DqwYPK0R#l*>EErwtV|N2N{t6QMrj`v;X{O`F8`V_LTDoSUQo;MK8pD*-iOko~l&a+P_ zsDlhEAWhNrV!}d&h@+YE5h`T{@ddt#l4_127tQhCT>rgWVL}S1e6H3>Pj$Oh`a^zJ zR6lbL`ZEX3sV7OZ0prpiK~P>g7R>=mfIA?$cZ%LS;&JwX zhTe=AC8R861GN0YSFtKQR43FTq`blmLX)dk7w{V0Bt!6Q;DS$v1Sb87s;Zi*GXAAP z8=okxBbJP!)w=zbOa1B^axg62%p@5|s@kWBkzGs^9p|PAo7;e z=s(VX9(zpiu%a)|qAw+iRKQyBt}O)><>eT_9$|)8X(~7O!T>}a=HAIbXO7$KvN;?7 zYWt!Uc%36D3H>?%f3X)at!G$mq$@O6ZW_b6#)Lsn@mF>-vSA3MMXBpK(~sC_cMjGN;xHPqwQ2#1*a^BGz$Or#5hH z-%M}9O;wLWTI(Iz>OHlu%&lv}`HlNezI*#V@$T*W?a}RXbH_gc&yI!$!PSvoTITaX z=peykpdLNM6yfc6-6I!q@NhCj2hyK&SlEQ*_+!K?P>w=cXDEJ%DxIE+Skjr2mlNnf zG9}OKUG<-y<)b>ML*Q^fo^kc(12h;y%&bb3&v5F1!6Q-uQduRNKNk`w+UY*Q6`_2X z*#%XR(-kf6^scRuOvlyrx2`OTw>lE4>6(8`@O0Zz|KUrhzcdLO%f$_U(eQl3TTEq0 zJxJ9Bpp&A>$1SO#JCs$3Q{6b|jYw83)Acg=nZBVx#Ncs41O<5$v4(XTEjUE!1JM4= z$^B4{TZe2B+d~`-w0L!7u9wSQJO+yhT`S6qQ87Zt+^eIZ#~>8E?Nv%aAzzS#xTc=E zfrp$&Ayv~SDj+CaWW#gwyBAW+Mh@HKRCST7RpQ-x~fP_S9CLAnLdrQY^s^d zH0p(T#PXmP@CI-Z<)pAl0|JgplDP#=PMH)dKtG(=7j&IepT?iRPA`kR^D)1BOMM|kgXJNODw%amb~F9;@4#Sp&%2>tBs~6(V?WGSkwK% zd7cCubE2w@QY{{z3W2l~@@TpQ_6O{smGDLzsYFjCn96h^MoFNTMyTZxBU~7ACB&-^ehO0Cwy@RcaCh2H+C>j9q z1g{;4b!VGmvK&s#OGJGB9KPT|eRo-R5GONk;d-07u84< z=qYp)`Z&353h|Aq0fhke!C!u~;Ue%92e?=0T11a;YXIXJA+AstVK!KOhOp{T)G1Gm zFf<4p8X8vNRK*?DOBCu@87K=z5_k)j8w5N%>oS~_j&VP3@iV-rGW$)BCUb>QtdxUL z9}ff~p@6TD3I)ULutEVrFmQ|C2O6^`!k6`scf}6N(0y9apMvcoh@3_$|TrN zW}arrL+gE-devZgBUE<|aJ{_Y9O+Ba*THY*!EIiMi2R#`jsX+>n9j5+hdYmMItJJ){W&Ry zow3`)KX`4L}^^A4frB0r7M9+u|u9riDUvu*tm``1*a5RMkJ zje%g?Phj^qB}0Kw)*JO1x>q+0)uXE?Z8Lzls;YZ1iM+8$Y@k^-OiT5rtRL0C8cr6~ zxRU2H%lS4-c^W+Jom-Whfrtnnm)72jH1@66( z{AIHUzR{sXVtap23jFB3M%vs=D&=Lj8>xu=2cyW5FANXgdg4^_mj|)%Y&KG1bLkf? zDM$`V62|SIbggtP^tZ@f#=xcPCF1{RxvYR=2R=bwad&8Ou3cvr^k*j+3Dt`l)1G7& znPS(D{mS{RyCh{kws~+VNyUqL`^N*gY3ypgZLd2|JoQfSZa)U^7DHPW!E=h_scMd; zB9zCxJp;$G1W{O|X3 zUD27D^f0@i5O@%alGqZXX0x*lWbL@sFm5%I5#ucOJ8w7&t2Vj5wzUZjlJY@RVdMQ- z#ru=szEkMWv07fQ(Gm(cFj-i<=IA`e?ZlcsRPAl8-{dnmM+fX@=IDWhEL^p&b6nYu zSj0yWi&%E_4#Wu`i(vyVDX0<2#GL&UOdIDrDW^kaSh|x&Wuo!4C2LOU87Oj&B3UXe zSlHj&>G9e7=qgiIUYOG5Xi5)HjxHMP!i5huE?){OO)^~UKBcz|O+Az!j!@co@P@`fD*M<|rW8zB2M=1QpkzM9kL+hp zgwGOv{3QDL0xY)F$9L&SFK3uB9FFp#Rdy)xET9mer1MU+BmYz1{VFi-MtXf+`pohA zp@R`8e$jrjzVB5?d@1Qm<*1JoE42~)UVt($&sJ&?&OtySD|9Uw7AN3V46;VivC=4) z(a8CaM78zMv2<6yQ<*1ov8&j8Yja)>KUR~$*ju>mnJr@{om6?BM@V_koIJ0)yS&80 z5%{D*#47w4@sDw620q@f8}ioy@JV1~9o;ZeShzyd5MuO?D<<`k;-@+we?fG0wH!+9iXlVhV`H+>+!t8AP;%4&OaVbft!I8 zlS*g3DcvV~)Qo<<361^Lre|35N?tu|gnYic3|R^U4VlE4)*jS%0yCS5m-3N>B^!Z& zti~cyFrJDTh||Lbp9y)*K8HtHV1kQaPZ5EEeJL0AMrqJj#k|Mkvvd z2z&iGJ)jvz&RlA-o_o3fJ==kUZEDCmN^dEcsPowpwmN$g*52HE*N+}6L8O08QXH-P} z8F1KzdV5(Ba(nd(6$h~IqO9+tCP2sob7m;yvHyp*yTt}vu6tfuR=ay_4TqfY$a7qR z0K=K>I;vG_-PfIJ(B$Kex`8uVGFAKL%e4DAZDxG^qagkGb3e?-Z`QXf4kX-MDlPm= z92$sGrmu>9q~jJvW~g)QFX&SO0QJD&wHKT=E_nBE&mN8cm;FB8x9i(+Y?#+~e+JZN z_xuF#P$gS4W#)xA&I_4~oQzb+(>WU&oYj(#3-}6eN3osJicNJx)Lg~W`e76ES=0(T z#A8T18X8C!OZ=|;iR728yK*3$Kgg2>eHgd&Ot61zjI|W!$&viT(tJFT|9Czk&nvb-BZs^W+ZsBhN2LEG zdu9vOIfd^E-%xrDti(JB5l%yB3Te^UeMXZr!h7pKy&4MJLvvJ`zrsrUZ(8+ox~%$*o|c%eXP_k<_bilN^cg99 zAXkt!R6ezOeQbf=ky&0|>Nh>@t50oSln?R#3V+3opi8_?0=L)Wv!q5ON+~i{(EM}u zL9L`iUW2lj7~Vwa$e~c8b|m$N5>hWR@c_;!su@ZoLiGm(Um;H)qPj$s@r+cS+~z=l zb&{Wv=22)HH127HRA~L|NZyN^voW8?DtPkIsQvxuXe{rUagGheMy0>WdkU7v7t3lo z^X74r{ddu5-8oM_HX4O78Tk#DHY}B1l3wCI15~Bql!i^vqQ;Be9MMrMo+ZY}5XuN|cu85VbD62l29r_E4kA^Z^thvw6H=IvEJB!8MR6#mZ_3?`P~;^eD}5kVYvBtO?jzoc;N&9#zF32 ztdr|cdW9Cnsynz?E+MsI%92a4CpRL=f@H`=D{Yy`uvWA(uT($z6)gOHRFF>Y^GBB8 zlj6IPj9Idx*qCg^Hj08yLUA~y(6_xX*P*84sj^k6DrqE<4MZq#et?gP+KJ+~)(#V` z+9*CHKHK0$1lOqab?FWGM`Tgiqr!94pV@E$bYFi0&TfB0Lo+YY3R8kezgZbZYBY|? z0(npDzztF_i|}GF4VVP21Jxs>1gbj{*DzV}9gfJv#d>IqdwQAmrn_S^j48*dE9WW3xoQkH_(!xMp-@{O;?)8;nA*k-2VvblM)`J0wP zzR>dSn@JBT&&~~oIwGM^xIGk}YYz%i71s^jui*}bKk}t*0k4eDc_@VsJ}7&vlqqi` zdar_i`+)QduD{IitYbo}FoW!QfKBoalTeU!Ht&oc`Bn0x00O58t*c9Y} zmM&r}{n|9rSg~fBt^wNoRBkmu(831&YI^uDcyspft@KgcJN?>(*Hre%rq5@}dlYk< zR6q?1LsIG2(4}<&%R((xtTb?p)p#EOAc(ZB z3UawBAjSh(iGV+-I`aoPuAF+d@EweUF?A50i*2pa@6&PV=0dO3SHz~*ehdHzga%7` zIj;7rDy4XmWZ4^0K2ta3esA<6ReJP00XV-TJ$D?yvCgi7y0p~W z)ub&g_OVsdJAsd_@NkrZaMx)L!$lL}-|P}CpiIB^bs6~*0OC6}*)U`?q%zd`ZL4M; zLaHT}KJgJCJSSZFI>w+8+S#+

!3;7J~OYIM7fTa;$2S(Bz4w0(DHeeyN&7iqeZg zyUtA{SW}A7?>ojkUTXdK!#F8hGPQYQa!P7seS-k;Tg5&AC}OfRfI8^gPC}mUCXK7` z;b6oVGQJ_Z+;>k1+CbBtVPv*kI8V(6rKWa6W8vx7_Vdw(gDKEfe8s@%N2&TK<`t!> zK#I9v{T_fN`XOrZP_6PVL@um?RS6sf`JItp5=}AWXa@ht%2`Z92;oCq(N!J>cLVU3 z-(_}QB3(!+?bfwz8{awI+i@cf*doji)91y;V{9ClzjHeJ#!rredD2gge2P--t?THW z-Z{Rl?M58fS9UjH`aYzXUSnf)dguIsH|{*%BnGySf5&0i&U?9!7SA{-=pQ07oS5Uo zY%xMDChRA%W#@2CSn5R>1^y0mmKU#qyhk-ke+=DB7V&n8@WWL!qFR$56O^h@%OPb-fGWFr!RU*1V(6fS?dyvztjyl~h)!_bs)sf8~+>rZOS zFE?S%0!2Rw#_UK0#iZAs_Bik{9kh&)Vt*~2fFavgNhu0W<=3?$7Th#_{;~>};)p7h zJ<)IzUNEBQYSOEmX$3HY&eVFdU2SR<=1Ey<^TQ9&h?v_)hu~qNLbLcC>8H{S;B7BJ zB*b+Mw*V$^z6V?B#x2al(lVT&X+U0r6dx>9VSoyOKr44s5b(ytQaWu0 zyg_N9q4hM8sosj^6gjFHO}&LuQ-@M4B1@$rjrc-P^DS5GKQ@-Htb`4)IU!c*=^V4H zaC&4@D5M(6(LqnbW8A*D#RE%XZ?3~*sj0~04S3Y1MU}O2U4=f|KU7MDLV@u_P*u7Xj6@X~!SMXvfUe}@!QoWvcfH}DCnHHc zrTj^;F0ZUK29kQH5k;Jn_nBEU7cTS9DyL{6s5a%06-UzFP$Yz8fl#m$zOBv6V2WX)W#(zXt0~l0|7UJv7>6cx75VQV!9Ca-5l6)ljB~lzfc;)1 z(d=WxiHKmjd7KSreMr$GgYrPf3C0>}|A}@~c-}1PmDC}RkC{#t_VIDI&idFmNhlUeQ1j!pCa1ysU<11rW7gWxEjTEeI1o>1Q6XLkgXik5$ODoG1-S{G*zWQ| zuZobD7{UjdA|PNd(g4^zZ+YADrA{{Q&So!EqK2h}=B&IAr6LTiov@v<81Ycds$Rsy)bv4a{2ANFV^XNcs+qX}8f>83- zuKb~V7f+-#CAR#;uKMpL$b+r=T`@Q={*6i1&(Js=rcLeT?!d6cg&w>T{Jxu~p7{L| z*>0-UMuqy;ovB060bn26GhnhpiJy@J$w`uex&cnHG}t5EnJ3r<94$Uk4U)j}3-HkiT7iLK(?=MW@$NqS- zn`U*kOCRwk)PQgKCr%6ZG=@y8Jyq;$%{B%xjym|rb|fTwBHa8BjtJH><;8k(0DN41(tw6}l66EDWA>Up0jss0i z$$RmPkp!#cF~^%JCs+BRvV#BcLr2Y=FKSB~6rd^RRBSXey(|p{3|@{x9|+sj>4XVy zNv7sx>1$+RJ=be|J}iaIPlYAad6J=?3x^F$l36Gg3xPT1$0po8V@!(PZ6dAi=MC@b z)eqcoL$_(#|Bjdy#b-5nLSELVD5}!agRly%r$*gNy3O#3C#N^;61nqdhgSr`92TYiJhDqC7qg>?ja;K>t>*Fz*m@nFfKzBeg>U& zjU3P#?yRh2BuVIm*z|}jh#_jzaB?^Vg{qs;u>=Jh9l6!$r;uO!seEU^Do9DAQu=kN zVkD)475K`p)9q@Caf&d-$pcHN?NXR62}yqQ*QUP_RA4Dvy%ZGT$3!nUS=|;T>h>Tf zbZ%lyE5IVEc4@J*vv?^ILcJca*!_jZOC{NUmb8DV6m40jEM3}ISUx$40kh9Fj8w`n zt`bQwm)DU9E|a^pYp8aMLmLI>2bxeB<^V#yCu6MrFd1#JX}i>4D)}#!GWM(7jGM&v z+%3LP#QtG4=-Z0r2&<6DOSKnLf`RIPsRpW@M)l7};6aWIRh5{IDq<*@)-Xf)>+Ln0om~s%*_-Oi-!(zg%U|qjZcsIk z$d6wrOJ6SED)Qn(cU9Ho5sLikD1iF#mp946jhWiBmaT4WpZCmy?i~wHb1p-4^ouUS z&$o26KCS{GVwqFzf2{ON3|^8U(F_5`erhP+eh zdMPFbEh6RbvIix_lNKQu)RGs}7wPSr=dcIcV+bzS+{&tnnr z`(EB=bg->`u37%O)2j6Fv0O9kUCkGGrKlgnL~C;&e1|nr{9a>ko%oP8;*~_hsZoQ; zc=*P=R|miB#F8vOWJ1`#{F2#9y?dPd!%Rrm`=Xa4ubkCYKF?evu(fuJUVj*hIAYmb zj9IU7U$M=s0l71b@>DSi)o5ZgGrb4&TVOMTYJ=TaX0b7I(~Z5w zo?Q7$;lLHU?tS%ps>TK;KO#=W&6~%osfG?7#~8jci7^X5KIAGE80a&~)vNLo+NcRO zY91$DRsd0RqS54Bv~1gyS1)3Z#RZY!&=DpqDR9!1+UF*$Bk-drSa68?y?(s9P&qs) z(_A?`Qfk)qBbb~xZr;StnyRCiyIexR-D_5V{AS{X1AZFC2wqWLJ=R{BHdZ~UFl}04 zQuWxh0yHth#sL)%LKj~WSu`sUQLi~_JXseTrNdOi(SsRN@q|jpKI_Gzs41>B`Mwra zUGc>##F{=R`G~c!=Uttvyvlqm-)pv4RpzeFSJ#N~nrcinh|h`f5?TgReyRV|VJ0BP zY2#H3lO9^sYp+j6(okrOvSaI{wsU=P$(lVkn(oKO%1JOuurDRs8ybp-9P(nro@*-e z3-V^lfVes7d7=9?tyEclvQ(M1eqx#aR$NZ+0>x%tFM1^PeiLS-G&W%VDeO+D9uT-B z3ebT-24?Q*G^i%9>1K@~3uENUcVI2?lA$64e{`2-JPB*k;TYYnri*pgz)-Ny+viVe zsi~4RljJTvF9-T)^Y8~PA9BvlbyJK+9oI!CzdnJsd zdsMcILD`-;-m8ieJ)1s2FA8}@&BmUZ3QeNpT*>&RL$gF=yr2Wh3 z6Td0HH1QLHB#THO0hTd-+P zpB?x2zOE15(iE6d)q#ktV~L{~OXs35Lwtgmmx zkD`a19o0cbPxu@xF73%0e!I##YJkMQ7HC6 zKLUf75M{nm9emqukpwy(3ao!%{2moW5~m zbj|kK7BqGkNW`ziuXbG^8f*0S_-Dg@U!UJ6PSE$>7XM_bE90@`dxV%I>NIvnD8`|) z$xm*(w_k}R@kNcbI=-Fl_}zqSw(FWkbnnbBFNFL)Gxo3Ghq6UJiZNajLjjYJ3y4#1 ztg*?OH>5C?nnvZHEPd=ry1ru4r2LhqDXk)5=lIr5GK>83uox!l`1Hr6Q~>nbmf zPGM#usxMR+*J8ZOtixxxFn)6L;SX~n;*?j=*(9oOW-9YKjQ=s3Lc>KoZaiDyh9di2 zkMU26#`BD88QurpAtc1_Fuuq*RYW!#oHV~;HzG|a7eOq}F$%iObmaX0Jz6nmtJsv) z1^D(hR2NLZc32_AUnL^{HZ<3@mJq$CSXtC1yZo2UD;GK%VKU-Nsw3?2tnZEMwuRAd zXH-Rq*_f45H>p3EU1~vhw~(zuPpLtOx~dWyTiINLHU08Mw9d_?&Z#?Bj=IZoh%^B0 zJ*sj{u8ppY1nm`VC-mFuOjIOzKE%_&&FeDlljq~ibSS?y7(vWME0g&)#sE*fXmw5w z&zm<~zTIqP&Y8KWzNTj3+Ij>znl@V9+!kUf%L8P7+4$T;=i=Y^w+E-mh2t1*%8g8^ z9&R7lLwX1zZ+vdw8qJ3^E4m}fLV5=?CG7KN$YiD&f!yuDwCn~NZ;~;<#9w-5B9*zy zOcECR^7h)rbX|+MMD6?j(?QMfyuAhsxv^@k`*m%!{Rj{6QErQFeL*ghuSLY2-F9<_ zX3kOL<%{yQxdk~LZQFQ&k9dlFqBELuSwdVbv--ms6=!1xTI$K!G^N4%|5idZ5}S(u z&y5ZYj1DZv;NPk@x2&EK36>qvu6!60c%h-;QKU66T93s3@1-^pwIbS%HHXfCQ;FY+mWXGikQB+#Y7`xH)C<6JcOLT{s&#k1`hogdcV82ktgU%crl#e%uc^*_M&)Z& z7iL=L#Z34g)kF(RW5L$iOGF7yN41#bV0ITGjoPLeNFzGHR$QCn-odM)i?1!#l=dD0 z{F$1Lc|F5ZyHcS>_93}i-HG^P@lKh$le|gfZ3ebjlea%e@^%Jl`Zt!R@q30f$n=&> zRw8SocEE%#dELx1Z{F&kI$rNAszC-}EGyg7gqTA6x3nSb+iO34R3`o)8++%M_8!JF zmu5;`-(76h?X&Ggl?`}`w^po^pGBKhgP!e7)O!cO()ey@9A?&{vHwobMGMIy9vsf# z&BC)A12$L)IVu_O{O*gCyD5=gVOt{Z=iw=vjGqG5U8kJp=}8~(pT2vo^L^9hKDw!S ze8!3eZSAGCdoNyJeit6RRIRYBtP(e4UzdS1?G%I~t$ZZmq5J|$MJBg!-#z#9_M0=5 zt1YUmxA>sF=XvAf<72P!-A%7?-WwMe*VW}!zGXPC<(z}of3z14X_ZB&3})9J-AT3V z#r+(jM+~*tluy%{np!=*ke}IIEc9elRc)rPSUJ5fmtT|bd5!OmevR|F#0PzS#bVfm zO^l8T&v?)xcP;p#L-E5ugNo9?iKHhQs!KHj|V9)T})3={;-s#76 z_aW}kRhztJUAnnAHnqF98^sy@tR>Mp-#1~r+VlnYzzD;^IREC?2LIGbziI4GXxQI0 z(j_=IHsl-NyEN-n`SCg=@Ajboo?G7e>ro0Ep_^QZxS!|Y9qoEM7^=s6Hz4*#`l2}i zqzD-)Q@up&_rU|RYWDp3vpdE$7Us+dYdq_v_qQa;u3p_kV6*(u{65 z4_1?%_+a}*r_6)JD&d<~*oLEKMJ73PXnL?Q&ay*|e)*;qL+Hdy!M&N^ZDv5cPX4~? z&A(<_vuU>yk!Bob$O!AzCBho$-D8rCMn`7-p19E|EsYu-Ir|NjmEX&T-uabt(cp^8 znHWIpF1F~l+0H^VKKNtiJzWi*`#g-K%z{M`p5|%Y6U~#3`ZyRG*}d#=UPs>qD(wdR?db?x=hIeA|6ZZX=25kaLUzR~hWBa?##1_pB4 z=p@(~@s+iat;(!xdS0RvbiraZx=SmdhV^QVi|2RKyb^72NpwFKMB8l>j^i_*o2W*` zI$?B8bURM8H6b|pPh7RTepq^yerWDDgobz!Mj20oS7NHq@DAV5oxeFcXH3-F3;h+`yZGI{JT<|F6?3{RbKQ@7t_5mQ%0SqV1Y%wi%5Z zv<(x&8p_v{#7<5#L9_nP2!2Mf&NgvQCrgTS6h){+mdNd3b1u7i~47# zA3lIM2YZ3CLosvk3^QvG#VoSFMK;iAa$nM=$)rP8p2fx`n(<+5r?Buuf$k7nm7o0A z`f=ZGX^2bWzIx?1Rc|I!8FyR|KY{%RiQdFfm#<%c`Finl)BTTn5anXhkEqqhOz2;T z9i;*~8tCanzkV!{yscIb7fR7)p%G`kj&_xmalgcD#flRyTfhD?zf?epG5sVsTPH^k zyylPA?2?T6n9Go_Mh}VYsAiqic{pd*61@gx4p_y*j#H**ld*~BU8mf>XgJIa_Bmb# z85$2aHDsqnvp`H)suteu%yt0LvJTe_|o1(uXahEZSLw}l%rU{*w z{0(7sGw!s*y-^q21n|Q`x>3WjcEQ>O3)XhVA9nVeVF$Ajcc+Ktck~-~1G9lkLBH`U z=+BCwc#jYJC12uf`PpEwsszV%Sd2>&L}*=EJF>_A2OY687_3Gd2KX?^QZ4)~q$*Yo zIQy?zDKASCdfeQ}g4kQh+{dHwP4&mSwPVeoj)h(z+VE4|* zsyMBDesWDiQ*BE=50@w0Tb0DTEt$(TRX3u|iTN<`f?Cn;yUAOus5fTJ$Yd40s@Udg ziy5L9p-tXU&p!@B8NXw^V3?`n5zt?16z|MA<{6_%T6r-dwfx5GcjT9DF~2dJ3ozVy zy!lYR0tfXCi`TDT+z>^ufS<>cvgZx-$zT3KoUx0dauAJSnR;Ry^1*>VR8f&k!k`To zg%l%I(0pR6*i0PH7O>QqL4M=F@b3)L_f?7Pz~ZW6?&v7<7cH$S6&7YwwRE`9-j*q} z)sNK8Z!Qi0JCn7TgW@y0xws`Oi*?yGSY9FfT%^lQ9?po~);d+cxUJ_k4cZdg^ji2V zd?ohhK`Wb%6B_Re? zb=8+PO4HtG_+ws!dU0b#3%qs~fvzY*KoU8$JF?5bW@=&sG@1A_$rlL3i5^Y#g^79o zug_;qt%!mqKhe?{&3>tCIHLTw!|NyIS{pJDw&r33Mwbg8xB@WbmTM-luwoA-5` z%i5=xT1vUfj;1hdZZGBWVOq!H&oy-*@JpdoU)|MJU2kGvmO2|pHXBI;9moS!aUJsD zZQ^;@rp#K66La7{d(cJy-Q#TiuWlP<_|LfSA#n!o8zX}gBEIf+*Xe7>{`*W_@H*L4 zA;eJ?*NA(CMlEcjxJNHnY>i)uO0yIF$)1WH`GmX(*Y!Yy8AGW$5o7M7Fs6fYMPx7 zk4>4D&+E+cC$68|h_cs~pVT<}oVT4byP-bchBDdQvgEtp6PF-?4OjHTS8;N-Nw0!@ z1Qb}+oEMW@rWBjIs#;5kzFOTSrnFW!FU3UE*4ARp#hrasldB4qoy|`5KxHPgOtf~D z+G{eU$&JG!Bf|}CrA%#Gsk>!=&qEFi=zLqE@w|F?=b$-)M`mLW9J5U2WE{|z#Gh=krcrZ5f!!19F;}h{sKa?7bANRuB6TSnnrej(E9x>Nj-@UG^_l0V+XF9f_i3I#S&SD z{?!V?_JiJK>fBCK+eWh@`=aV(FH@yNli8u@qJ+43S~OriHO3r>Sw?1{vKjtak%wJm zz=!@dJq@f41(~SYwOIpO}V4j#PNuRGJm(ce$aT1h*{8e&wy{2S--3fk;&TO zv@E<;MIs?gY)f9kQWW^x6WxMu>fqv*8_V zhWpd_M<{S&M|Q|T82J^;Pd(&R{I6{7UAHbPil^RCegtR5%;!%%e-Tcag4sV_eu)Kh zOLgVYe%a;t)7x4(e_gnux>6L&k7O}EJ^K9l;i6t-MLeEu)`H)Lp3tBfr%G3X0S0g( zZD>Y4hYnHXkBJr3QHCv3n4#`rYr^cKWr~i>1|W2Q6qhkZTo&8l!4Pyi27>Mof zFE$kW`}-RU#s0?n{{BT)RZ9bc{m{?x0rcn$ce~v?5pG7Ijv#}Bp*go4bj=wUd--q1 zvAcZtz}TahxFKeYuIwE=VsF!Ljqr|g@zKHFm7`(?W^R;U+8f^8yULM?qiHM>Mk1gh z<-p2D&n0q_Pv(lD{*68NlYL09%dXDYqGK%dSB^ zWoYH--=_xIt{KLVvegvkttXp{uQ5}mqx*>UQp5SKrv|--<*_LI5MG6AYIM9Hygs8( zMSo3YWaeeywQZR@C{_*4>FOvi>S+8}sWy}S+TdLALPr+@Zm26WnVH>~Tp(GNwwHg>xJPqarbP_pkCTsOb({IJl&@-OU36Tr{GBFU-?UGw z2qw4fyDs8_bM_mcwRK17;cc6-dJJMBF;mW=9yj*T@F~B7L00|p-|E!3Igs;Bqw$v5 zBWBnP+MBcEwR&fr>c4hN?9CGA(@BU$vJE8|qc&*2;SgXtQ^tB_cru~8Fl|3BR7q(< z6=7WWT<7n%pFg-YUK4KX*nWqe|76Rg1;%G)0i1E-1G(+|L-!lo8m&>7Q(FhmzrAnb z*U@!&+^9_PKA`9Pi~C@~Hfg^)T`^~;N!D!sIl&~1nR$N)RO~IjfcFQFlY)%&T(l;B z>;ki`{11^S3dA8Q{|fVe+Yy~e$m`0_l%GKaKT#C3ij&Pom|1U-C2p-S^B%7>vf!d( z%me5eAioe6V7j;!QT(1R6rMI={eJkvqI`El@hL?2d&)%j!)NpRCn~;*zTMI0_y4r! zsCdc*6~3*2e^`(18adnSaE$*r4_gNQR9D=LCyM{HVIFvVETAV|kQ__sW;Z6sssfV) zlVe@cEY3@gGZnRBM{=Bn zIC;}?$97vo!`-9ZuW_IF#_|WPL6Zq@-m@Qwr`m+PS|2@YH|}W|Z^AsI`P*Glap19= zPFsKS#_r+ak)h$?VVp6qXfuAW85wpgCV%2?R&U(Ae)EQ7*WwTyM}J=V5}ptRJN~q5 zt1;$;g$NW}iOfQHuwjb=*eZ!iQHAQWM%0Qrcvseo2GJ;*1m@$3Rxw$$iFQnmG|v0o zqDM>-y<)1ECZ>x%(JuyI|CuRfi9zU|)#U^o@*ep&LZxv^VE#gdZ zmN;9SBi<(7F3uI_iSxxf#5=_W;zIE*@ow=R@m}#h@qY0E@j-EsxL8~wE)^dV9~PI1 z%f&~;N5vK5W8&lDN^zC=gt%H| z9r0c9J#oMIzIZ_VK>SerNIWQhEPf(>DjpIKi$}!I#G~Rd@woW8ctZR_{8Id{_?7sz z_>K6jcv3tio)*uD--&0%@5LX)AH{RxdGROlg7~xei}#u9B;Cp?sHow|tL$FCsC#Uw%M-P+lZ2mY2v&<%i^lF#{5aOUyh?sTUM;VY*UC@IPsvZq&&ccKR(U;ojyJ$F>T~i&d6T?ZeqP>! z7?5AUx(>HtjndoY9df(;vfLr>gjdd8@~iS|@^1Nc`3-rGyjOlxeoKB^?nFH4`{Z}z zcQH@oeysNiuQ6E6ek321KbAj19GHjX!&njEXYfwO9CyU;ctZX{{t|K5ekFe`eK8%S5yU7_&|Iv zWkOG8RZbz|gDR?$s#H~~TES&b)u~CUUNxvj)uftLi)vMqRhw#89ja4xsczMyrl?*u zRZUaVRiElt18Rnvsb;A`HKb;%VKt&Gg}$zGm8X0as8EfnF*UCCPh&ogqrVdv}s3X-; z>MiPMb&Oi8j#cZ_aq4)rUY(#$R2$SuYNI+?ouW=vo78D)vpQY9Rh^->s58}B>TGq6 zdYgK?I#->i&R6eH?^GA43)Q>SyVZNtd)52Y`_%{32h~ODVs(kSRDDQ&SY4(rS07Oy zRadBwsgJ8G)m7>f>S}e3x>kKseM)^=eMViUwyNvZHg$vgtood~QQf3&R-ae5s9OWAt_>Ou8m^%M0|^^kg4J)(Z59#xO2$JNi(6Y3Z0m+F7juhg&AZ`5zq zljL2PQ^|C6fS9ArI=94gY znhD5oV8pzrf`(7GM#KRUN`7Q-K3j!i*D7Eb(?P29lBF@>2BSlr|4ci zRZr8?bss#D2lNa*Q_s?adPvXK!+Jzp+SZPCwWoa@=unU9F+HyL(0l5=^c+1`@2%(Q z`FbCO16rsT>3#Knda+)j_t#7HGQC`{&@1%;dX-+S57Y()Eo3kdZRvBpQ2CIoAhaVvp!wFRiB}^=ri?M`fPoU zew%)~K3AWo&)4tJ@6;FQ3-!D7yY+kYd-ePD`}GI(2lYkzVtt9eRDVc+SYM_u*B{Xz z)mP|`>5uCx^;P;4`f7cRzE*!ye@cH^e@0)Yx9aQlHhqKstp1$7QQxF*)}Pn6=v(y{ z^cVGQ`b+wDeFr9keOd3&cj~X`yYyG}*Yw@`>-rn|9(}L=rv8@xw%)1#N8hKvqra=a zr|;L_*AM6)=pX7I=?C?X^-uIq^+Wn${fPdVepElEAJ;$EPv~FhU+VwWztX?fztO+d zPwJ=i)A||xJN>Nwz5av#qkc|5um7Z9(0|r{(SOx{(|^}5>VN2$^vk-eU&&NpEg+du z8I71!Su9GK&lEDnOes^DsmfGmYBIH%y3C|ZeWoGPm}$y1XIe6?naP>9Onasy)0yeY zbZ2@pQ!>4oshMe+>6yMve`X*vBQrBID>IlG%FNCTXGRbP(9Sp+H{)geOppmPquJv& zoO#OeBk|6Pcf;|{j(1MHbK{*C@BDZd#JeyTOBqh~Bgx)M_I9#&lD(Vky=3nv`ykmT z@~lLjmB_Oac~&CNO5|CIJS&lBCGxC9o|VY66M1$b&ramoi99=zXD9OPM4p|@1xoJ5|J$a4~TP9o1qUM8EeEd0ryVOXPWpJTH;wCGxyPo}b9`6M23j&rjs}i9A1%=O^;~ zM4q3>^AmYNA}>hf1&O>MkryQLf<#`B$O{sAK_V|mRk5KXm zC67?DMadQ=Ta;{3vPH=jC0mqiQL;tJ7A4!1Y*VsL$u=e1lx$P7P02PT+mvimvO~!Z zB|DVtP_jeG4kbI3>`<~p$qpsElCA*aDQnE+M9wmE}>`}5u z$sQ$pl{D_;$pIw?lpIiUK*<3m2b3I8 zazM!eC5Mz8QgTSiAti^D98z*f$sr|&luQP#;Y6}EoJdADKc>kVP9$5yiDYXyk!%eo zlC9xHvNfDYwuX~?w#cAG1}!pZkwJ?LT4c~7gBBUI$e=|AEi!14L5mDpWY8jm78$h2 zphX5PGH8)Oiws(1&?18t8MMftMFuT0XpupS3|eH+B7+tgw8)@E1}!pZkwJ?LT4c~7 zgBBUI$e=|AEi!14L5mDpWY8jm78$h2phX5PGH8)Oiws(15GK*2w2(oI3}WP!U$JbE zL5mDpWY8jm78$h2Afn$Ua>$@X1}!pZkwJ?LT4c~7gBBUI$e=|AEi!14L5mDpWY8jm z78$h2phX5PGH8)Oiws(1&?18t8MMiuO$Kc;Xp=#k4BBMSCWAH^w8@}N25mBElR=vd z+GNlsgEkqo$)HUJZ8B(+L7NQPWY8vqHW{?ZpiKs0y^mid#$kAnlnt8<+GNlsgEkqo z$)HUJZ8B(+L7NQPWY8vqHW{?ZpiKsCGH8=Qn+)1y&?bX68MMiuO$Kc;Xp=#k3?jyG z^2lV+CWAH^w8@}N25mBElR=vd+GNlsgEkqo$)HUJZMK6p8MMiuO$Kc;Xp=#k4BBMS zCWAH^w8@}N25mBElR=vd+GNlsgEkqo$)HUJZ8B(+L7NQPWY8vqHW{?ZpiKr54JpZa zGH8=Qn+!T+&>@2k8Fa{?Lk1l(=#W8&3_4`cA%hMXbjYAX1|2f!kU@tGI%LoxgAN&V z$e=?89Wv;UL5B=FWY8gl4jFXFpu=|1A%hMXbjYAX1|2f!kU@tGI%LoxgAN&V$e=?8 z9Wv;UL5B=FWY8gl4jFXFphE^7GU$*&hYUJo&>@2k8Fa{?Lk1l(=#W8&3_4`cA%k!Q zjY||plzEWQ?T|r-48p5~*CchFLk1l(h(LkKHDnM&tUN=>WDs5k{ECvvphE^7GU$*& zhYUJo&>@2k8Fa{?Lk1l(=#W8&3_4`cA%hMXbjYAX1|2f!kU@tGI%Lo#gDx3#$)HOH zT{7sBL6;1=WY8spE*W&mpi2f_GU$>)mkhdO&?SQ|8Fa~@O9ovs=#oK~47y~{C4(** zbjhGg23<1fl0laYx@6ELgDx3#$)HOHT{7sBL6;1=WY8spE*W&mpi2f_GKhuS)mkhdO&?SQ| z8Fa~@O9ovs=#oK~47y~{C4(**bjhGg23<1fl0lCQdSuWegB}_5$e>3CJu>K#L5~c2 zWY8mn9vSq=phpHhGU$;(j|_Tb&?AE$8T81YM+QAI=#fE>40>eHBZKhtj9;Zk20b$9 zkwK3P!h40>eHBZD3p^vEFMS|zEo9rVbcM+QAI z=#fE>40>b`OOz#Y$RMK9@(go>40>eHBZD3p^vIw`20b$9kwK3PdSuX}F6xm%j|_Tb z5VQA_`yqoK8T7~?oOF2&@0kpGWY8mn9vSq=phpHhGU$;(j|_Tb&?AE$8T81YM+QAI z=#fE>40>eHBZD3p^vIw`27NNK5=#xR84EkiyCxbp2^vR%427NNK5=#xR83}Pv^L=GAB z$)L}6&?kdF8T84ZPX^)8n8+c6J{d%;X@13fCWAg1^vR%427NNK5=#xR84EkiyCxbp2^vR%427NN-~$Y4MQ12Pzp!GH_~WH2Cu0T~R)U_b@~G8mA-fD8s?Fd%~g84So^Kn4Rc z7?8n$3-~$Y4MQ12Pzp!GH_~WH2Cu0T~R) zU_b@~G8mA-fD8s?Fd%~g84So^Kn4Rc7?8n$3-~*bW9{Fd%~g84So^Kn4Rc7?8n$3-~ z$Y4MQ12Pzp!GH_~WH2Cu0T~R)U_b@~G8mA-fD8s?FeHN^84Sr_NCrbP7?Qz|42EPd zB!eLt49Q?f217C!lEIJ+hGZ}#gCQ9V$zVtZLoyhW!H^7wWH2OyAsGzGU`Pf-G8mG< zkPL=oFeHN^84Sr_NCrbP7?Qz|42EPdB!eLt49Q?f217C!lEIJ+hGZ}#gCQ9V$zVtZ zLoyhW!H^7wWH2OyAsGzGU`Pf-G8mG=0nueRE;ihT0X&P>thMT70rfGO-8eW=)m!{#RX?STGUYdrNrs1V&cxf75nuedI z;iqZ%X&Qc-hM%V4r)l_U8h)CFpQhobX#{ZO#~<;^E0G6!(3;4}A0l7E; literal 0 HcmV?d00001 diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 51049ac1..76e08b71 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -603,7 +603,7 @@ void Editor::Impl::createFrameContents() darkTheme.highlightedText = { 0xfd, 0x98, 0x00 }; darkTheme.titleBoxText = { 0x00, 0x00, 0x00 }; darkTheme.titleBoxBackground = { 0xba, 0xbd, 0xb6 }; - darkTheme.icon = darkTheme.text; + darkTheme.icon = { 0xb2, 0xb2, 0xb2 }; darkTheme.iconHighlight = { 0xfd, 0x98, 0x00 }; darkTheme.valueText = { 0x00, 0x00, 0x00 }; darkTheme.valueBackground = { 0x9a, 0x9a, 0x9a }; @@ -757,7 +757,7 @@ void Editor::Impl::createFrameContents() }; auto createGlyphButton = [this, &theme](UTF8StringPtr glyph, const CRect& bounds, int tag, int fontsize) { STextButton* btn = new STextButton(bounds, this, tag, glyph); - btn->setFont(makeOwned("Sfizz Fluent System R20", fontsize)); + btn->setFont(makeOwned("Sfizz Fluent System F20", fontsize)); btn->setTextColor(theme->icon); btn->setHoverColor(theme->iconHighlight); btn->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); @@ -792,7 +792,7 @@ void Editor::Impl::createFrameContents() }; auto createResetSomethingButton = [&createValueButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) { STextButton* btn = createValueButton(bounds, tag, u8"\ue13a", kCenterText, fontsize); - btn->setFont(makeOwned("Sfizz Fluent System R20", fontsize)); + btn->setFont(makeOwned("Sfizz Fluent System F20", fontsize)); return btn; }; auto createPiano = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int fontsize) { @@ -804,7 +804,7 @@ void Editor::Impl::createFrameContents() auto createChevronDropDown = [this, &theme](const CRect& bounds, int, const char*, CHoriTxtAlign, int fontsize) { SActionMenu* menu = new SActionMenu(bounds, this); menu->setTitle(u8"\ue0d7"); - menu->setFont(makeOwned("Sfizz Fluent System R20", fontsize)); + menu->setFont(makeOwned("Sfizz Fluent System F20", fontsize)); menu->setFontColor(theme->icon); menu->setHoverColor(theme->iconHighlight); menu->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); @@ -817,7 +817,7 @@ void Editor::Impl::createFrameContents() result = u8"\ue0d7"; return true; }); - menu->setFont(makeOwned("Sfizz Fluent System R20", fontsize)); + menu->setFont(makeOwned("Sfizz Fluent System F20", fontsize)); menu->setFontColor(theme->icon); menu->setHoverColor(theme->iconHighlight); menu->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index c5d7c57b..626d093e 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -10,11 +10,11 @@ auto* const view__3 = createRoundedGroup(CRect(5, 4, 180, 105), -1, "", kCenterT view__2->addView(view__3); auto* const view__4 = createSfizzMainButton(CRect(30, 5, 150, 65), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 14); view__3->addView(view__4); -auto* const view__5 = createHomeButton(CRect(44, 73, 69, 98), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 24); +auto* const view__5 = createHomeButton(CRect(31, 69, 63, 101), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 30); view__3->addView(view__5); -auto* const view__6 = createCCButton(CRect(76, 73, 101, 98), kTagFirstChangePanel+kPanelControls, "", kCenterText, 24); +auto* const view__6 = createCCButton(CRect(71, 69, 103, 101), kTagFirstChangePanel+kPanelControls, "", kCenterText, 30); view__3->addView(view__6); -auto* const view__7 = createSettingsButton(CRect(107, 73, 132, 98), kTagFirstChangePanel+kPanelSettings, "", kCenterText, 24); +auto* const view__7 = createSettingsButton(CRect(111, 69, 143, 101), kTagFirstChangePanel+kPanelSettings, "", kCenterText, 30); view__3->addView(view__7); auto* const view__8 = createRoundedGroup(CRect(185, 5, 565, 105), -1, "", kCenterText, 14); view__2->addView(view__8); diff --git a/scripts/generate_ui_fonts.sh b/scripts/generate_ui_fonts.sh index 8b0f48f2..9cb1555c 100755 --- a/scripts/generate_ui_fonts.sh +++ b/scripts/generate_ui_fonts.sh @@ -7,17 +7,19 @@ if ! test -d "src"; then fi root="`pwd`" -fonts="$root/editor/resources/Fonts" +fonts="$root/plugins/editor/resources/Fonts" -if test ! -d editor/external/fluentui-system-icons; then - cd editor/external +if test ! -d plugins/editor/external/fluentui-system-icons; then + cd plugins/editor/external git clone https://github.com/sfztools/fluentui-system-icons.git cd fluentui-system-icons else - cd editor/external/fluentui-system-icons + cd plugins/editor/external/fluentui-system-icons git checkout master git pull origin master fi ./generate_icons_font.py -s regular -w 20 -n 'Sfizz Fluent System R20' \ -o "$fonts/sfizz-fluentui-system-r20.ttf" +./generate_icons_font.py -s filled -w 20 -n 'Sfizz Fluent System F20' \ + -o "$fonts/sfizz-fluentui-system-f20.ttf" diff --git a/scripts/innosetup.iss.in b/scripts/innosetup.iss.in index 3586f7d3..70dc76d8 100644 --- a/scripts/innosetup.iss.in +++ b/scripts/innosetup.iss.in @@ -63,6 +63,7 @@ Source: "sfizz.vst3\Plugin.ico"; Components: vst3; DestDir: "{commoncf}\VST3\sfi Source: "sfizz.vst3\gpl-3.0.txt"; Components: main; DestDir: "{app}" ; Note(sfizz): OS older than Windows 10 require UI fonts to be installed system-wide Source: "sfizz.vst3\Contents\Resources\Fonts\sfizz-fluentui-system-r20.ttf"; DestDir: "{fonts}"; FontInstall: "Sfizz Fluent System R20"; Flags: uninsneveruninstall; OnlyBelowVersion: 6.4 +Source: "sfizz.vst3\Contents\Resources\Fonts\sfizz-fluentui-system-f20.ttf"; DestDir: "{fonts}"; FontInstall: "Sfizz Fluent System F20"; Flags: uninsneveruninstall; OnlyBelowVersion: 6.4 Source: "sfizz.vst3\Contents\Resources\Fonts\Roboto-Regular.ttf"; DestDir: "{fonts}"; FontInstall: "Roboto Regular"; Flags: uninsneveruninstall; OnlyBelowVersion: 6.4 ;Source: "setup\vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall ; NOTE: Don't use "Flags: ignoreversion" on any shared system files From 5fe2be5facdf61569461e2d9f8551713a3215e7c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 27 Feb 2021 13:37:03 +0100 Subject: [PATCH 348/668] Editor logo in shaded style --- plugins/editor/CMakeLists.txt | 2 ++ plugins/editor/layout/main.fl | 10 +++++----- plugins/editor/resources/logo_text_shaded.png | Bin 0 -> 2471 bytes plugins/editor/resources/logo_text_shaded@2x.png | Bin 0 -> 4726 bytes plugins/editor/src/editor/Editor.cpp | 6 +++--- 5 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 plugins/editor/resources/logo_text_shaded.png create mode 100644 plugins/editor/resources/logo_text_shaded@2x.png diff --git a/plugins/editor/CMakeLists.txt b/plugins/editor/CMakeLists.txt index bfc5cc1e..387f4704 100644 --- a/plugins/editor/CMakeLists.txt +++ b/plugins/editor/CMakeLists.txt @@ -5,8 +5,10 @@ set(EDITOR_RESOURCES logo.png logo_text.png logo_text_white.png + logo_text_shaded.png logo_text@2x.png logo_text_white@2x.png + logo_text_shaded@2x.png background.png background@2x.png icon_white.png diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 74582ec2..d1e5a1ab 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -20,22 +20,22 @@ widget_class mainView {open class RoundedGroup } { Fl_Box {} { - comment {tag=kTagFirstChangePanel+kPanelGeneral} - image {../resources/logo_text_white.png} xywh {35 9 120 60} + comment {tag=kTagFirstChangePanel+kPanelGeneral} selected + image {../resources/logo_text_shaded.png} xywh {35 9 120 60} class SfizzMainButton } Fl_Button {} { - comment {tag=kTagFirstChangePanel+kPanelGeneral} selected + comment {tag=kTagFirstChangePanel+kPanelGeneral} xywh {36 73 32 32} labelsize 30 class HomeButton } Fl_Button {} { - comment {tag=kTagFirstChangePanel+kPanelControls} selected + comment {tag=kTagFirstChangePanel+kPanelControls} xywh {76 73 32 32} labelsize 30 class CCButton } Fl_Button {} { - comment {tag=kTagFirstChangePanel+kPanelSettings} selected + comment {tag=kTagFirstChangePanel+kPanelSettings} xywh {116 73 32 32} labelsize 30 class SettingsButton } diff --git a/plugins/editor/resources/logo_text_shaded.png b/plugins/editor/resources/logo_text_shaded.png new file mode 100644 index 0000000000000000000000000000000000000000..e4198b1ccf3640a5aac223e32de00cb9e9e67ca7 GIT binary patch literal 2471 zcmV;Y30U@tP)ilo&W#<8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H101$LV zSaeirbZlh+b7pCJdLV3XXK#(|1=aun0338hSad;kbZBpK090>cX<>7EASZQhW??5F zOJQDZyGB7eQEig4LF*c4qr?mh809bTI zSad^gaCvfRXJ~W)LqjkiP<3K#X=5NnZ*5^|ZXiTuWNBkzbZKvHAZT=Sa5^t9V{&C- zbZK^FV{dJ3Z*FrgZ*pfZaCKsAX=7w>ZDDC{FM4HiZ!a+}FfYdAz4-tD2xv(}K~!ko zWL1!2kZScI_d@?2nHT^{1{a#>eESXqpMAT;dqlHL6k*n7`Cce%UgUd=zd zobMm@{J!sZe&5}5?>Xl#BGGr=UYI$75H|@uFX6^G?3%lXm~JJmz)`&^T2Y zw-uJm^@{^ye-RTOGdA0Mnz}II3~vrT`VGhKiUS(4$u6@@I}sXpDE=p|zvI`&-DkLQ zl|DM5<7?u9LYwQ+^@M*VoJ`!|v#ayzu+u=n zdFFAE|F>ju3Q*`2Eryn=_%Be9FABqF`_6(3sh|5;>E}15?UtOCC?vHKy`=J7p(I)I z!TF8u%M81vgi4$eaN*n^h_hj3N~jC+<=D8Z=w3cJAH+N^h3Jxl@j{lS?@c$P11I{^ zk|mowUZmF;=DBCQ+Z6|-kJH?=PniC6tA~*}k#+#-ltOgr7tw&y&6$QwARrAdUAiT6 zgn|v@jG|r&S(Ul;>Ql$`Gmdmhgz04*93=^^@S-Gs_t2&uU=3x4>U%*S3ondJ_ zp_M(Qv%f&uZn3gid1a%(7?vr8=wvR#+3Fmik$pXPn|v8lh$1BC&73nigE^3Um0fy{ zmQi^|cBY$3j$);Fe{NDvs#la^ImhJaHp$&f&}HN}Fy+pSM5zt;#jg+}u+F){Y=~3o}aYcK*uT6s)>4^IZkIE&zoo z#SeuqWck~X-YH*6D*S?-X6HxpALD`qjRE=b0(9>&x`NBp%q=`v2o#zhWaTbAjPy5& z1#CiGDEK+=5kA0Fb^H$;g)bG@kaAc~pSu4~xsGpLijbmfNas+5Gl6$60>UoghLtyv`WUf@Q;2Kgc{x{M`R&R#`Bnu>E?!`K zDa3fe>r{YXFHR_XOwgOkV3h-@-zBkCrHGr)uWXe9tL`)Yb*T<8y5e$i04rEhQ34o7 zN@7Yj@J(F2g;AFMl*BISr@5tH^2uI$kjY-Gax2?QEBkfH3{qN@tKGutP34p2;D(0s zJ?fR@)D<5h#gvBdYDX2yS!b!zwFVS3Wx_4&H zc5Gxr`3l~4pR4^J(pj~9AHCWQbqTr=9k@YfT;|TKdkc#bx23vKnp?Nu8?XKa-5ARH zt?qfgcJ+_y+L?MT?G&_~s9#Id_EF4ZHScifPHVj5Dm#1%36kwj9a%l|;!A z^phy|A@R~l5!d5vXx^%yMy$a$-Uo&H$Mj~Tb2NuN)Qj7zp)Ek8m9-&kevygjw~+F* zv?6wr2gVaE7R0f)@INR7v=lRyG>aedO?Cb9c4s?K*oQ~jcA$QTF_^UfX`iCmSNCup zLjv0>P(ElEa8PLb9MhFS0P$gN$TNDG^M*effX3AbJkk+`BHg5-3@C~S{FN!mG(kn@kjmDY zdQjvrX`Jg(h->D!98a6>VdHd})C9y*cW!<{`{BMW*hX4V`q z26sB?*mdIepz~{#N68V5;Hbh2x~S*8d6h6-Cx~w7ZU8Ub>HQhI$nLF7w3oR3yU|T^ zdyaENBY0Lp0~r>m1CcqXN8CHn3j}DopLH*?cQ=ZT1L3eYu%g#NvwQx$Fm8?@R^V0- zZCIcV=4E}M=6yFiZUQH!`ilB~$7SMX65Hr^fjU}Ql zx?kF_wCF62mNHAW<=_3`Jsw~4STq)(kWSpKE$s`X!S!1+9_NFh5PG*SOxG9s5F3(P z!?%FKK9T>o{&jbN#=skk!0_GhL7*}4gGFF?_}~yw_(rrC+CA+(ppd%=?Ao3jwU2@e zBcJ%8LF)$i9{zdk?6*MSzHN;^expq`z4bNM3JO8ClQy7XE%ZmbVG}TqZ^qS=B@@Hc zr#Z~nHu|CAsY_Gf0nvVFcjhcX<>7EASZQhW??5F zOJQDZyGB7eQEig4LF*c4qr?mh809bTI zSad^gaCvfRXJ~W)LqjkiP<3K#X=5NnZ*5^|ZXiTuWNBkzbZKvHAZT=Sa5^t9V{&C- zbZK^FV{dJ3Z*FrgZ*pfZaCKsAX=7w>ZDDC{FM4HiZ!a+}FfYdAz4-tD5jROhK~#9! z?Ol6(6y>>2AORFPV37(Um#Re+%drP9)oKwv9uI0u>9Mt*1C%32Ku@i<3TU;kfe>fH$tWetGO(Q#RM9M`@*B~u3$C#j9cuw z#dQSPs`uCed2|Th&P^eDJsqc2i`?qmKoFjr%IB8DzNP!W zihkR=y|dghkAWcM8y)P|ac%4N2hnjG$FWb`K^Q!KF_q8bW6rIQijLd1y{kQR9>9SC zk35gF9{%oOo(Uf19)rjhYH&2#gHLeseJ*-#+taH^Phi2A=NZqRN}P-i=T6=mJdb!@ zGTQE4V@9uVR>nzqY!^MZVR*0g(t804mG@fqZ*8wFp4nc8+uL0^G1r9iBn#th_^c3J zw`GI~Bg z6(RFPucswW9{dUryd*kfC-GJCNnl{q|8CJ4d$~yJIt2`rioV!Me7*cMAP5khv6DFc z#@B#AT+FkZJ@|{i0TW+~r&#t90rGEviIa;(XY8fHjRC+whv^9WoO>=oP@3_Q>s z92&IM+G&a4_fgJwgf}>-5#hbTQiYb+i230PqPK^l9t7`Uu_SzDXhi6E2v~)oVE^F9 zt!S`6#umCxXnXzd4w+!`2D2>lhiI)FwIx6sOi>SSuzYsdpF?$_AP9z#^pF?XO%HoJ zw1W(DAcV&_Oiv@GGKt80IUDSa<%F@^s1vRw zS(%9@+F*Km;ie4^TN9y;079tdGCkr7F&zlkaDN9!WFT3Fpam>jlXHLxq`?t;DC$AP z)CLDFIHNuT#P9{X<cE*K?gpRHA~|imwk8F%!4&n38yp!a1r8XZnx$u@ZjlF~ z_D1fG+%5e?>Lv}9=1RNq?PY7&Esxy9sl*q@xY`@G7|ls!{qSjt)@BT(!O}ex^+5Vv zgQGV^0UM-svOh&EW1Zz%DccbhDea${A*X7Jo=Nuau)+LbF((MvBsstj!p* zQ&@xP=|%NL{_s1~b7X*`U-q%W$%4tuyP|(1inF<-AgseTd~m zvwkR~>*X7SK^BYG8C8-x7x8V0P`#*M$aJWpLH4WfWFCzM6jx=uo}HC1k3JEtiw4=l zTw6t7WKpvQBiwgf%KWh`*%P!TcV%xz8_+ttV^`78^LLIeU~$HKYGd}v0YQJvS}PVN zmPdcey+!mNq7N8Do`~v4nr_F0e7Biu3K8B>`5Zd!mH$BAgN{Uhb~7EtXkSzhE{ZRc4LV3aQY#+j0O=lD#^W-XEqs1#Ev^{Hc)HRdP9Fyh_}Hqw=N>@R zAxDSi970az z65_BCB*3|7O6`3nVH8!=#p5TYiN%S)MAB9pH8>1YkAGPBHDcl@!dyhU{-n>a`X^C; zZUGIyQkNuZaK)te*h&mf0tDTOPurrwN#%(4fbcWV4)5jIjO)3Luyj;CR%%P>f5L$f&DD?9LAhnB+4>4fIzGUjL0;_hU+&}nbR?^wE_Ot#0sc zlye(_&wLKTJCQ`-g)TYIW{;v(k7oUZMti|AJ0ABw>zozWHY#VuM>zvIzzYV2Tw&FZ zTjZR?_^kiHOkuu`FgFr7Dg0i}CESJczo#@6bb!V6%T}L?Dpu#7QvgqlC=T(z`cvd0 zOk={YA{9%q8gpZXPZZ{6u#8_ur@c8F72~L$F7L;Jh;yILjmy>N0xwkMJjzq$Cc;u9 z+?L!|vHBDe!MulAMy^)eL!-UQWw}~hQSpBy=pWAu%5>AHwo;)7ZF~a zke5uP&do1n8ShCt?N$C)z5&xKxK%{w*V@2Qxv?OmV7LIxqNl*3+1SExG+XdYF3c(z zV)7Q23E?dG8_QTP)KR(1I)6<;AF5|i{?dVFlq@d#tgxdH%)p{K-@*zcvsd`KRna3@ zO$A{B7%wobyyEwT*L6XTF&8bj?#!b&j%9=y zKxJW}=$VocRBya!ql2vj954D_1RSMirtV6PqFFx`UR9|Y;q9@KYah$_G%6|!3nhz7 zF5`+N`yHkyE(VkWhKpt%ekn~vvJ9$)g1@c%R({MLS z6KLQ5$Ql)kRM%91z|3Wd>JpN3iNOB*W2~A|E3Q^m%T!u)WM+>})<)SOTu;?fvB+Wi zqRh1n5NNnhUCInd&N<=Ll<&Z*Dc{TgG_ouY9T${QT39H5rECJ#)2aT=VLGGY>2g3Y z%$f5%mQzOHw|px+FlN;YyzTZzM+N2TIw}hb<*UlOSrm6UOmC_K@QU$^4XR8N?>4|)4-ER22>Jw+@rFC z$y?RVlVeR~A6g$&QCe82IF0L7RuErUu;$=W1qiNlaBU0h(Pt1RgVhD-dzm{l$<#|%#5lE;UlSf5v_&Si^Z$LQ4Xl4 zw6IY1MD-x5XQ}VCu;t;O&A zs(rd{1RagOmde5cIM&6m_?Js)VWDxYdO{6%Frf~ud5q7um0J4GTw`2s=D2lEeE`d; zCt#ski7<~hTX-8^{bKcHd_47s=zROuf5PIQwr(jY328kT!BDSI@2EHXdqpr?y}iE4 zB=M(uuwxqeN6?Hw8Y9f?DL+EtC^_nId9McTMasHB-pHOdl2hAgJD|d4^%533eK}!e)H>QHoV9I*n z(DFsgSPKwER+ZTY#9Q64%q9XWtgRIY^MIvyUbKV|_QC|r2GiAR`Sv@w^{G}>D-gpe zORn8olaNe(m*6)CD4be#2y=8X~{}OTcI_Wj!z*;M&Ws?Je!V3pd*%+F#*we_{IzD33&VgEfay=2tAPEQIIS z`GV14%6fng^P%=Vnn+EJW?Td8Xzy>&={Tf$5qLlEqj?|YdyBvxysCWz6Xwq8r+mOy zWBKHuF`22Wn?qNxeS?{M3_5<)v01ZI^Op{H&0jnGJN!FOb+~taKKVbdT@~;X6O$~! zMCTd@G3+Bc3p#;;Av!mai(&Hs$1A;8z!aSqMQ7|JuCBTY2m(cC>?FG0)B+P-ABoP` zOM^e}0t7FM&e%y@lU@TRv`a*1>?E#NUk3)XqA&K+-g|D0-v9=ZMQ7|JZvMwjKyXlW z#!jNgvj>>C`KsuQeN1x9>ecjuDQ@XH?h?JRi|E~Q3lOA>&e+HP>(p1<2Tb(u61|xj z4V*n79e$Ag@BLo=fI!!~Nc3(-#K7AFFre*YdE0FNzRABL7z`Gjn;HAB<6!k5+=gQC z-@)kCyWtgsvO9k>g<){L=-rHnpF$bR&<5&drDzd0huq;4{&=84{y~qrewq=fO#IZbroT%VWSBjc}jn+)Qb3_BilF z11uMPn=vu=tiEyrcpw?X$&DFy73`$nr|;5(1?ZgEA^J5ln>+{JHYf}R1F%4E$b(%l zS9EG-xA}h94t|gYm7sya$!nobsG9tjJG>ztmTez@2aXZy6e2ec-v9sr07*qoM6N<$ Ef@g2{CIA2c literal 0 HcmV?d00001 diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 76e08b71..e721a0ee 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -558,7 +558,7 @@ void Editor::Impl::createFrameContents() { CViewContainer* mainView; - SharedPointer iconWhite = owned(new CBitmap("logo_text_white.png")); + SharedPointer iconShaded = owned(new CBitmap("logo_text_shaded.png")); SharedPointer background = owned(new CBitmap("background.png")); SharedPointer knob48 = owned(new CBitmap("knob48.png")); SharedPointer logoText = owned(new CBitmap("logo_text.png")); @@ -636,8 +636,8 @@ void Editor::Impl::createFrameContents() box->setTitleFont(font); return box; }; - auto createSfizzMainButton = [this, &iconWhite](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int) { - return new CKickButton(bounds, this, tag, iconWhite); + auto createSfizzMainButton = [this, &iconShaded](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int) { + return new CKickButton(bounds, this, tag, iconShaded); }; auto createLabel = [&theme](const CRect& bounds, int, const char* label, CHoriTxtAlign align, int fontsize) { CTextLabel* lbl = new CTextLabel(bounds, label); From c03a5dc63507933d77a70591bfee58a7e2696b29 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 28 Feb 2021 07:32:16 +0100 Subject: [PATCH 349/668] Labeled CC knobs --- plugins/editor/layout/main.fl | 4 +- plugins/editor/src/editor/Editor.cpp | 8 + plugins/editor/src/editor/GUIComponents.cpp | 207 +++++++++++++++----- plugins/editor/src/editor/GUIComponents.h | 51 ++++- 4 files changed, 213 insertions(+), 57 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index d1e5a1ab..b6d7510c 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -20,7 +20,7 @@ widget_class mainView {open class RoundedGroup } { Fl_Box {} { - comment {tag=kTagFirstChangePanel+kPanelGeneral} selected + comment {tag=kTagFirstChangePanel+kPanelGeneral} image {../resources/logo_text_shaded.png} xywh {35 9 120 60} class SfizzMainButton } @@ -121,7 +121,7 @@ widget_class mainView {open class ChevronValueDropDown } } - Fl_Group {} {open + Fl_Group {} {open selected xywh {570 5 225 100} box ROUNDED_BOX class RoundedGroup } { diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index e721a0ee..09b0d31b 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -824,6 +824,14 @@ void Editor::Impl::createFrameContents() menu->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); return menu; }; + auto createKnobCCBox = [this, &theme](const CRect& bounds, int tag, const char* label, CHoriTxtAlign, int) { + SKnobCCBox* box = new SKnobCCBox(bounds, this, tag); + box->setNameLabelText(label); + box->setNameLabelFontColor(theme->text); + box->setKnobFontColor(theme->text); + box->setKnobLineIndicatorColor(theme->knobLineIndicatorColor); + return box; + }; auto createBackground = [&background](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { CViewContainer* container = new CViewContainer(bounds); container->setBackground(background); diff --git a/plugins/editor/src/editor/GUIComponents.cpp b/plugins/editor/src/editor/GUIComponents.cpp index c0025af0..73f7c302 100644 --- a/plugins/editor/src/editor/GUIComponents.cpp +++ b/plugins/editor/src/editor/GUIComponents.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "GUIComponents.h" +#include "ColorHelpers.h" #include #include @@ -488,10 +489,32 @@ void SStyledKnob::setLineIndicatorColor(const CColor& color) invalid(); } +void SStyledKnob::setFont(CFontRef font) +{ + if (font_ == font) + return; + font_ = font; + invalid(); +} + +void SStyledKnob::setFontColor(CColor fontColor) +{ + if (fontColor_ == fontColor) + return; + fontColor_ = fontColor; + invalid(); +} + +void SStyledKnob::setValueToStringFunction(ValueToStringFunction func) +{ + valueToStringFunction_ = std::move(func); + invalid(); +} + void SStyledKnob::draw(CDrawContext* dc) { const CCoord lineWidth = 4.0; - const CCoord indicatorLineLength = 10.0; + const CCoord indicatorLineLength = 8.0; const CCoord angleSpread = 250.0; const CCoord angle1 = 270.0 - 0.5 * angleSpread; const CCoord angle2 = 270.0 + 0.5 * angleSpread; @@ -546,6 +569,106 @@ void SStyledKnob::draw(CDrawContext* dc) dc->setLineStyle(kLineSolid); dc->drawLine(p1, p2); } + + if (valueToStringFunction_ && fontColor_.alpha > 0) { + std::string text; + if (valueToStringFunction_(getValue(), text)) { + dc->setFont(font_); + dc->setFontColor(fontColor_); + dc->drawString(text.c_str(), bounds); + } + } +} + +/// +SKnobCCBox::SKnobCCBox(const CRect& size, IControlListener* listener, int32_t tag) + : CViewContainer(size), + label_(makeOwned(CRect())), + knob_(makeOwned(CRect(), listener, tag)), + ccLabel_(makeOwned(CRect())) +{ + setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); + + label_->setText("Parameter"); + label_->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label_->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label_->setFontColor(CColor(0x00, 0x00, 0x00, 0xff)); + + knob_->setLineIndicatorColor(CColor(0x00, 0x00, 0x00, 0xff)); + + ccLabel_->setText("CC 1"); + ccLabel_->setStyle(CParamDisplay::kRoundRectStyle); + ccLabel_->setRoundRectRadius(5.0); + ccLabel_->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + ccLabel_->setFontColor(CColor(0xff, 0xff, 0xff)); + + addView(label_); + label_->remember(); + addView(knob_); + knob_->remember(); + addView(ccLabel_); + ccLabel_->remember(); + + updateViewColors(); + updateViewSizes(); +} + +void SKnobCCBox::setHue(float hue) +{ + hue_ = hue; + updateViewColors(); +} + +void SKnobCCBox::setNameLabelFont(CFontRef font) +{ + label_->setFont(font); + updateViewSizes(); +} + +void SKnobCCBox::setCCLabelFont(CFontRef font) +{ + ccLabel_->setFont(font); + updateViewSizes(); +} + +void SKnobCCBox::updateViewSizes() +{ + const CRect size = getViewSize(); + const CCoord ypad = 4.0; + + const CFontRef nameFont = ccLabel_->getFont(); + const CFontRef ccFont = ccLabel_->getFont(); + + nameLabelSize_ = CRect(0.0, 0.0, size.getWidth(), nameFont->getSize() + 2 * ypad); + ccLabelSize_ = CRect(0.0, size.bottom - ccFont->getSize() - 2 * ypad, size.getWidth(), size.bottom); + knobSize_ = CRect(0.0, nameLabelSize_.bottom, size.getWidth(), ccLabelSize_.top); + + // remove knob side areas + CCoord side = std::max(0.0, knobSize_.getWidth() - knobSize_.getHeight()); + knobSize_.extend(-0.5 * side, 0.0); + + // + label_->setViewSize(nameLabelSize_); + knob_->setViewSize(knobSize_); + ccLabel_->setViewSize(ccLabelSize_); + + invalid(); +} + +void SKnobCCBox::updateViewColors() +{ + const float knobLuma = 0.4; + const float ccLuma = 0.25; + + SColorHCY knobActiveTrackColor { hue_, 1.0, knobLuma }; + SColorHCY knobInactiveTrackColor { 0.0, 0.0, knobLuma }; + knob_->setActiveTrackColor(knobActiveTrackColor.toColor()); + knob_->setInactiveTrackColor(knobInactiveTrackColor.toColor()); + + SColorHCY ccLabelColor { hue_, 1.0, ccLuma }; + ccLabel_->setBackColor(ccLabelColor.toColor()); + + invalid(); } /// @@ -579,7 +702,8 @@ void SControlsPanel::setControlUsed(uint32_t index, bool used) std::string SControlsPanel::getDefaultLabelText(uint32_t index) { - return "CC " + std::to_string(index); + (void)index; + return {}; } SControlsPanel::ControlSlot* SControlsPanel::getSlot(uint32_t index) @@ -602,42 +726,15 @@ SControlsPanel::ControlSlot* SControlsPanel::getOrCreateSlot(uint32_t index) slot = new ControlSlot; slots_[index].reset(slot); - // create controls etc... - CCoord knobWidth = 48.0; - CCoord knobHeight = knobWidth; - CCoord labelWidth = 96.0; - CCoord labelHeight = 24.0; - CCoord verticalPadding = 0.0; - - CCoord totalWidth = std::max(knobWidth, labelWidth); - CCoord knobX = (totalWidth - knobWidth) / 2.0; - CCoord labelX = (totalWidth - labelWidth) / 2.0; - - CRect knobBounds(knobX, 0.0, knobX + knobWidth, knobHeight); - CRect labelBounds(labelX, knobHeight + verticalPadding, labelX + labelWidth, knobHeight + verticalPadding + labelHeight); - CRect boxBounds = CRect(knobBounds).unite(labelBounds); - - SharedPointer knob = owned(new SStyledKnob(knobBounds, listener_.get(), index)); - SharedPointer label = owned(new CTextLabel(labelBounds)); - SharedPointer box = owned(new CViewContainer(boxBounds)); - - box->addView(knob); - knob->remember(); - box->addView(label); - label->remember(); - - box->setBackgroundColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setStyle(CTextLabel::kRoundRectStyle); - label->setRoundRectRadius(5.0); - label->setBackColor(CColor(0x2e, 0x34, 0x36)); - label->setText(getDefaultLabelText(index)); - knob->setActiveTrackColor(CColor(0x00, 0xb6, 0x2a)); - knob->setInactiveTrackColor(CColor(0x30, 0x30, 0x30)); - knob->setLineIndicatorColor(CColor(0x00, 0x00, 0x00)); - - slot->knob = knob; - slot->label = label; + CRect boxSize { 0.0, 0.0, 120.0, 90.0 }; + SharedPointer box = makeOwned(boxSize, listener_.get(), index); slot->box = box; + slot->box->setCCLabelText(("CC " + std::to_string(index)).c_str()); + + slot->box->setValueToStringFunction([](float value, std::string& text) -> bool { + text = std::to_string(std::lround(value * 127)); + return true; + }); return slot; } @@ -645,27 +742,27 @@ SControlsPanel::ControlSlot* SControlsPanel::getOrCreateSlot(uint32_t index) void SControlsPanel::setControlValue(uint32_t index, float value) { ControlSlot* slot = getOrCreateSlot(index); - CControl* knob = slot->knob; - knob->setValue(value); - knob->invalid(); + SKnobCCBox* box = slot->box; + box->getControl()->setValue(value); + box->invalid(); } void SControlsPanel::setControlDefaultValue(uint32_t index, float value) { ControlSlot* slot = getOrCreateSlot(index); - CControl* knob = slot->knob; - knob->setDefaultValue(value); + SKnobCCBox* box = slot->box; + box->getControl()->setDefaultValue(value); } void SControlsPanel::setControlLabelText(uint32_t index, UTF8StringPtr text) { ControlSlot* slot = getOrCreateSlot(index); - CTextLabel* label = slot->label; + SKnobCCBox* box = slot->box; if (text && text[0] != '\0') - label->setText(text); + box->setNameLabelText(text); else - label->setText(getDefaultLabelText(index).c_str()); - label->invalid(); + box->setNameLabelText(getDefaultLabelText(index).c_str()); + box->invalid(); } void SControlsPanel::recalculateSubViews() @@ -693,8 +790,10 @@ void SControlsPanel::updateLayout() CCoord itemOffsetX {}; int numColumns {}; - const CCoord horizontalPadding = 24.0; - const CCoord verticalPadding = 18.0; + const CCoord horizontalPadding = 4.0; + CCoord verticalPadding = 4.0; + CCoord interRowPadding = {}; + CCoord interColumnPadding = 8.0; int currentRow = 0; int currentColumn = 0; @@ -713,16 +812,20 @@ void SControlsPanel::updateLayout() itemHeight = box->getHeight(); isFirstSlot = false; numColumns = int((viewBounds.getWidth() - horizontalPadding) / - (itemWidth + horizontalPadding)); + (itemWidth + interColumnPadding)); numColumns = std::max(1, numColumns); itemOffsetX = (viewBounds.getWidth() - horizontalPadding - - numColumns * (itemWidth + horizontalPadding)) / 2.0; + numColumns * (itemWidth + interColumnPadding)) / 2.0; + + int maxRowsShown = int((viewBounds.getHeight() - 2 * verticalPadding) / itemHeight); + if (maxRowsShown > 1) + interRowPadding = (viewBounds.getHeight() - 2 * verticalPadding - itemHeight * maxRowsShown) / (maxRowsShown - 1); } CRect itemBounds = box->getViewSize(); itemBounds.moveTo( - itemOffsetX + horizontalPadding + currentColumn * (horizontalPadding + itemWidth), - verticalPadding + currentRow * (verticalPadding + itemHeight)); + itemOffsetX + horizontalPadding + currentColumn * (interColumnPadding + itemWidth), + verticalPadding + currentRow * (interRowPadding + itemHeight)); box->setViewSize(itemBounds); diff --git a/plugins/editor/src/editor/GUIComponents.h b/plugins/editor/src/editor/GUIComponents.h index b7de29ff..a890b3ed 100644 --- a/plugins/editor/src/editor/GUIComponents.h +++ b/plugins/editor/src/editor/GUIComponents.h @@ -215,6 +215,14 @@ public: const CColor& getLineIndicatorColor() const { return lineIndicatorColor_; } void setLineIndicatorColor(const CColor& color); + void setFont(CFontRef font); + CFontRef getFont() const { return font_; } + void setFontColor(CColor fontColor); + CColor getFontColor() const { return fontColor_; } + + using ValueToStringFunction = std::function; + void setValueToStringFunction(ValueToStringFunction func); + CLASS_METHODS(SStyledKnob, CKnobBase) protected: void draw(CDrawContext* dc) override; @@ -223,6 +231,45 @@ private: CColor activeTrackColor_; CColor inactiveTrackColor_; CColor lineIndicatorColor_; + + SharedPointer font_ = kNormalFont; + CColor fontColor_ { 0x00, 0x00, 0x00 }; + + ValueToStringFunction valueToStringFunction_; +}; + +/// +class SKnobCCBox : public CViewContainer { +public: + SKnobCCBox(const CRect& size, IControlListener* listener, int32_t tag); + void setHue(float hue); + SStyledKnob* getControl() const { return knob_; } + + void setNameLabelText(const UTF8String& name) { label_->setText(name); } + void setNameLabelFont(CFontRef font); + void setNameLabelFontColor(CColor color) { label_->setFontColor(color); } + void setCCLabelText(const UTF8String& name) { ccLabel_->setText(name); } + void setCCLabelFont(CFontRef font); + void setCCLabelFontColor(CColor color) { ccLabel_->setFontColor(color); } + void setKnobLineIndicatorColor(CColor color) { knob_->setLineIndicatorColor(color); } + void setKnobFont(CFontRef font) { knob_->setFont(font); } + void setKnobFontColor(CColor color) { knob_->setFontColor(color); } + + using ValueToStringFunction = SStyledKnob::ValueToStringFunction; + void setValueToStringFunction(ValueToStringFunction f) { knob_->setValueToStringFunction(std::move(f)); } + +private: + void updateViewSizes(); + void updateViewColors(); + +private: + SharedPointer label_; + SharedPointer knob_; + SharedPointer ccLabel_; + CRect nameLabelSize_; + CRect knobSize_; + CRect ccLabelSize_; + float hue_ = 0.35; }; /// @@ -253,9 +300,7 @@ private: private: struct ControlSlot { bool used = false; - SharedPointer knob; - SharedPointer label; - SharedPointer box; + SharedPointer box; }; class ControlSlotListener : public IControlListener { From 119bd7a2229bd7a5fd0763d5cefc49d3a6f332e7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 28 Feb 2021 10:13:36 +0100 Subject: [PATCH 350/668] Add null check for view --- plugins/editor/src/editor/Editor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 09b0d31b..4a539451 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -144,6 +144,8 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { template void adjustMinMaxToEditRange(Control* c, EditId id) { + if (!c) + return; const EditRange er = EditRange::get(id); c->setMin(er.min); c->setMax(er.max); From b71d56fc2ed2c87adcec90130fcdfefdda44531b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 28 Feb 2021 10:24:35 +0100 Subject: [PATCH 351/668] Fix a mistake in SKnobCCBox implementation --- plugins/editor/src/editor/GUIComponents.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/editor/src/editor/GUIComponents.cpp b/plugins/editor/src/editor/GUIComponents.cpp index 73f7c302..d8b02acc 100644 --- a/plugins/editor/src/editor/GUIComponents.cpp +++ b/plugins/editor/src/editor/GUIComponents.cpp @@ -636,11 +636,11 @@ void SKnobCCBox::updateViewSizes() const CRect size = getViewSize(); const CCoord ypad = 4.0; - const CFontRef nameFont = ccLabel_->getFont(); + const CFontRef nameFont = label_->getFont(); const CFontRef ccFont = ccLabel_->getFont(); nameLabelSize_ = CRect(0.0, 0.0, size.getWidth(), nameFont->getSize() + 2 * ypad); - ccLabelSize_ = CRect(0.0, size.bottom - ccFont->getSize() - 2 * ypad, size.getWidth(), size.bottom); + ccLabelSize_ = CRect(0.0, size.getHeight() - ccFont->getSize() - 2 * ypad, size.getWidth(), size.getHeight()); knobSize_ = CRect(0.0, nameLabelSize_.bottom, size.getWidth(), ccLabelSize_.top); // remove knob side areas From 73ab9f48584d0a134acd7fd02218f633e80a76de Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 28 Feb 2021 11:11:15 +0100 Subject: [PATCH 352/668] Volume and Pan knobs at top-right corner --- plugins/editor/layout/main.fl | 26 +++++----- plugins/editor/src/editor/Editor.cpp | 57 +++++++++++++++++++-- plugins/editor/src/editor/GUIComponents.cpp | 7 ++- plugins/editor/src/editor/layout/main.hpp | 10 ++-- 4 files changed, 77 insertions(+), 23 deletions(-) diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index b6d7510c..9c077163 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -3,7 +3,7 @@ version 1.0305 header_name {.h} code_name {.cxx} widget_class mainView {open - xywh {571 362 800 475} type Double + xywh {659 319 800 475} type Double class LogicalGroup visible } { Fl_Box {} { @@ -121,7 +121,7 @@ widget_class mainView {open class ChevronValueDropDown } } - Fl_Group {} {open selected + Fl_Group {} {open xywh {570 5 225 100} box ROUNDED_BOX class RoundedGroup } { @@ -134,20 +134,22 @@ widget_class mainView {open xywh {610 70 60 5} labelsize 12 hide class ValueLabel } - Fl_Dial volumeSlider_ { - comment {tag=kTagSetVolume} - xywh {680 20 48 48} value 0.5 - class StyledKnob - } - Fl_Box volumeLabel_ { - label {0.0 dB} - xywh {675 70 60 22} labelsize 12 - class ValueLabel - } Fl_Box {} { xywh {745 20 35 55} box BORDER_BOX class VMeter } + Fl_Box volumeCCKnob_ { + label Volume + comment {tag=kTagSetCCVolume} selected + xywh {580 10 70 90} box BORDER_BOX labelsize 12 align 17 + class KnobCCBox + } + Fl_Box panCCKnob_ { + label Pan + comment {tag=kTagSetCCPan} + xywh {655 10 70 90} box BORDER_BOX labelsize 12 align 17 + class KnobCCBox + } } } Fl_Group {subPanels_[kPanelGeneral]} { diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 4a539451..9f6407ef 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -73,7 +73,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { kTagPreviousSfzFile, kTagNextSfzFile, kTagFileOperations, - kTagSetVolume, + kTagSetMainVolume, kTagSetNumVoices, kTagSetOversampling, kTagSetPreloadSize, @@ -82,6 +82,8 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { kTagSetScalaRootKey, kTagSetTuningFrequency, kTagSetStretchedTuning, + kTagSetCCVolume, + kTagSetCCPan, kTagChooseUserFilesDir, kTagFirstChangePanel, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, @@ -128,6 +130,18 @@ struct Editor::Impl : EditorController::Receiver, IControlListener { SControlsPanel* controlsPanel_ = nullptr; + SKnobCCBox* volumeCCKnob_ = nullptr; + SKnobCCBox* panCCKnob_ = nullptr; + + CControl* getSecondaryCCControl(unsigned cc) + { + switch (cc) { + case 7: return volumeCCKnob_ ? volumeCCKnob_->getControl() : nullptr; + case 10: return panCCKnob_ ? panCCKnob_->getControl() : nullptr; + default: return nullptr; + } + } + void uiReceiveValue(EditId id, const EditValue& v) override; void uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) override; @@ -826,12 +840,19 @@ void Editor::Impl::createFrameContents() menu->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); return menu; }; - auto createKnobCCBox = [this, &theme](const CRect& bounds, int tag, const char* label, CHoriTxtAlign, int) { + auto createKnobCCBox = [this, &theme](const CRect& bounds, int tag, const char* label, CHoriTxtAlign, int fontsize) { SKnobCCBox* box = new SKnobCCBox(bounds, this, tag); + auto font = makeOwned("Roboto", fontsize); box->setNameLabelText(label); + box->setNameLabelFont(font); box->setNameLabelFontColor(theme->text); + box->setKnobFont(font); box->setKnobFontColor(theme->text); box->setKnobLineIndicatorColor(theme->knobLineIndicatorColor); + box->setValueToStringFunction([](float value, std::string& text) -> bool { + text = std::to_string(std::lround(value * 127)); + return true; + }); return box; }; auto createBackground = [&background](const CRect& bounds, int, const char*, CHoriTxtAlign, int) { @@ -1005,6 +1026,7 @@ void Editor::Impl::createFrameContents() if (SControlsPanel* panel = controlsPanel_) { panel->ValueChangeFunction = [this](uint32_t cc, float value) { performCCValueChange(cc, value); + updateCCValue(cc, value); }; panel->BeginEditFunction = [this](uint32_t cc) { performCCBeginEdit(cc); @@ -1014,6 +1036,15 @@ void Editor::Impl::createFrameContents() }; } + if (SKnobCCBox* box = volumeCCKnob_) { + unsigned ccNumber = 7; + box->setCCLabelText(("CC " + std::to_string(ccNumber)).c_str()); + } + if (SKnobCCBox* box = panCCKnob_) { + unsigned ccNumber = 10; + box->setCCLabelText(("CC " + std::to_string(ccNumber)).c_str()); + } + updateKeyswitchNameLabel(); /// @@ -1483,12 +1514,18 @@ void Editor::Impl::updateCCValue(unsigned cc, float value) { if (SControlsPanel* panel = controlsPanel_) panel->setControlValue(cc, value); + + if (CControl* other = getSecondaryCCControl(cc)) + other->setValue(value); } void Editor::Impl::updateCCDefaultValue(unsigned cc, float value) { if (SControlsPanel* panel = controlsPanel_) panel->setControlDefaultValue(cc, value); + + if (CControl* other = getSecondaryCCControl(cc)) + other->setDefaultValue(value); } void Editor::Impl::updateCCLabel(unsigned cc, const char* label) @@ -1652,11 +1689,21 @@ void Editor::Impl::valueChanged(CControl* ctl) changeScalaFile(std::string()); break; - case kTagSetVolume: + case kTagSetMainVolume: ctrl.uiSendValue(EditId::Volume, value); updateVolumeLabel(value); break; + case kTagSetCCVolume: + performCCValueChange(7, value); + updateCCValue(7, value); + break; + + case kTagSetCCPan: + performCCValueChange(10, value); + updateCCValue(10, value); + break; + case kTagSetNumVoices: ctrl.uiSendValue(EditId::Polyphony, value); updateNumVoicesLabel(static_cast(value)); @@ -1717,13 +1764,15 @@ void Editor::Impl::enterOrLeaveEdit(CControl* ctl, bool enter) EditId id; switch (tag) { - case kTagSetVolume: id = EditId::Volume; break; + case kTagSetMainVolume: id = EditId::Volume; break; case kTagSetNumVoices: id = EditId::Polyphony; break; case kTagSetOversampling: id = EditId::Oversampling; break; case kTagSetPreloadSize: id = EditId::PreloadSize; break; case kTagSetScalaRootKey: id = EditId::ScalaRootKey; break; case kTagSetTuningFrequency: id = EditId::TuningFrequency; break; case kTagSetStretchedTuning: id = EditId::StretchTuning; break; + case kTagSetCCVolume: id = editIdForCC(7); break; + case kTagSetCCPan: id = editIdForCC(10); break; default: return; } diff --git a/plugins/editor/src/editor/GUIComponents.cpp b/plugins/editor/src/editor/GUIComponents.cpp index d8b02acc..294a5703 100644 --- a/plugins/editor/src/editor/GUIComponents.cpp +++ b/plugins/editor/src/editor/GUIComponents.cpp @@ -743,8 +743,11 @@ void SControlsPanel::setControlValue(uint32_t index, float value) { ControlSlot* slot = getOrCreateSlot(index); SKnobCCBox* box = slot->box; - box->getControl()->setValue(value); - box->invalid(); + auto* control = box->getControl(); + float oldValue = control->getValue(); + control->setValue(value); + if (control->getValue() != oldValue) + box->invalid(); } void SControlsPanel::setControlDefaultValue(uint32_t index, float value) diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index 626d093e..96557324 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -68,13 +68,13 @@ view__26->setVisible(false); auto* const view__27 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12); view__25->addView(view__27); view__27->setVisible(false); -auto* const view__28 = createStyledKnob(CRect(110, 15, 158, 63), kTagSetVolume, "", kCenterText, 14); -volumeSlider_ = view__28; +auto* const view__28 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); view__25->addView(view__28); -auto* const view__29 = createValueLabel(CRect(105, 65, 165, 87), -1, "0.0 dB", kCenterText, 12); -volumeLabel_ = view__29; +auto* const view__29 = createKnobCCBox(CRect(10, 5, 80, 95), kTagSetCCVolume, "Volume", kCenterText, 12); +volumeCCKnob_ = view__29; view__25->addView(view__29); -auto* const view__30 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14); +auto* const view__30 = createKnobCCBox(CRect(85, 5, 155, 95), kTagSetCCPan, "Pan", kCenterText, 12); +panCCKnob_ = view__30; view__25->addView(view__30); enterTheme(defaultTheme); auto* const view__31 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14); From bb593277f65bb7c42fb91e34d52478c8035fe0df Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Mar 2021 06:59:29 +0100 Subject: [PATCH 353/668] Invalidate the secondary CC knob on value changed --- plugins/editor/src/editor/Editor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 9f6407ef..71ae9d20 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -1515,8 +1515,10 @@ void Editor::Impl::updateCCValue(unsigned cc, float value) if (SControlsPanel* panel = controlsPanel_) panel->setControlValue(cc, value); - if (CControl* other = getSecondaryCCControl(cc)) + if (CControl* other = getSecondaryCCControl(cc)) { other->setValue(value); + other->invalid(); + } } void Editor::Impl::updateCCDefaultValue(unsigned cc, float value) From e3b77b0417fb599c12b1b470a09f4a4baab3fa5c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 1 Mar 2021 06:17:58 +0100 Subject: [PATCH 354/668] vst: eliminate some string comparisons --- plugins/vst/SfizzVstProcessor.cpp | 36 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/plugins/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp index 609de2f8..d2d308f3 100644 --- a/plugins/vst/SfizzVstProcessor.cpp +++ b/plugins/vst/SfizzVstProcessor.cpp @@ -33,6 +33,14 @@ enum { static const char* kRingIdMidi = "Mid"; static const char* kRingIdOsc = "Osc"; +static const char* kMsgIdSetNumVoices = "SetNumVoices"; +static const char* kMsgIdSetOversampling = "SetOversampling"; +static const char* kMsgIdSetPreloadSize = "SetPreloadSize"; +static const char* kMsgIdCheckShouldReload = "CheckShouldReload"; +static const char* kMsgIdNotifyPlayState = "NotifyPlayState"; +static const char* kMsgIdReceiveMessage = "ReceiveMessage"; +static const char* kMsgIdNoteEvents = "NoteEvents"; + SfizzVstProcessor::SfizzVstProcessor() : _fifoToWorker(64 * 1024), _fifoMessageFromUi(64 * 1024), _oscTemp(new uint8_t[kOscTempSize]) @@ -265,7 +273,7 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) _fileChangeCounter += numFrames; if (_fileChangeCounter > _fileChangePeriod) { _fileChangeCounter %= _fileChangePeriod; - if (writeWorkerMessage("CheckShouldReload", nullptr, 0)) + if (writeWorkerMessage(kMsgIdCheckShouldReload, nullptr, 0)) _semaToWorker.post(); } @@ -279,7 +287,7 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) playState.regions = synth.getNumRegions(); playState.preloadedSamples = synth.getNumPreloadedSamples(); playState.activeVoices = synth.getNumActiveVoices(); - if (writeWorkerMessage("NotifyPlayState", &playState, sizeof(playState))) + if (writeWorkerMessage(kMsgIdNotifyPlayState, &playState, sizeof(playState))) _semaToWorker.post(); } @@ -294,7 +302,7 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) _noteEventsCurrentCycle[key] = -1.0f; } if (numNoteEvents > 0) { - if (writeWorkerMessage("NoteEvents", noteEvents, numNoteEvents * sizeof(noteEvents[0]))) + if (writeWorkerMessage(kMsgIdNoteEvents, noteEvents, numNoteEvents * sizeof(noteEvents[0]))) _semaToWorker.post(); } @@ -349,7 +357,7 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { int32 data = static_cast(range.denormalize(value)); _state.numVoices = data; - if (writeWorkerMessage("SetNumVoices", &data, sizeof(data))) + if (writeWorkerMessage(kMsgIdSetNumVoices, &data, sizeof(data))) _semaToWorker.post(); } break; @@ -357,7 +365,7 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { int32 data = static_cast(range.denormalize(value)); _state.oversamplingLog2 = data; - if (writeWorkerMessage("SetOversampling", &data, sizeof(data))) + if (writeWorkerMessage(kMsgIdSetOversampling, &data, sizeof(data))) _semaToWorker.post(); } break; @@ -365,7 +373,7 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { int32 data = static_cast(range.denormalize(value)); _state.preloadSize = data; - if (writeWorkerMessage("SetPreloadSize", &data, sizeof(data))) + if (writeWorkerMessage(kMsgIdSetPreloadSize, &data, sizeof(data))) _semaToWorker.post(); } break; @@ -606,7 +614,7 @@ void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char* uint8_t* oscTemp = _oscTemp.get(); uint32 oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args); if (oscSize <= kOscTempSize) { - if (writeWorkerMessage("ReceiveMessage", oscTemp, oscSize)) + if (writeWorkerMessage(kMsgIdReceiveMessage, oscTemp, oscSize)) _semaToWorker.post(); } } @@ -635,22 +643,22 @@ void SfizzVstProcessor::doBackgroundWork() const char* id = msg->type; - if (!std::strcmp(id, "SetNumVoices")) { + if (id == kMsgIdSetNumVoices) { int32 value = *msg->payload(); std::lock_guard lock(_processMutex); _synth->setNumVoices(value); } - else if (!std::strcmp(id, "SetOversampling")) { + else if (id == kMsgIdSetOversampling) { int32 value = *msg->payload(); std::lock_guard lock(_processMutex); _synth->setOversamplingFactor(1 << value); } - else if (!std::strcmp(id, "SetPreloadSize")) { + else if (id == kMsgIdSetPreloadSize) { int32 value = *msg->payload(); std::lock_guard lock(_processMutex); _synth->setPreloadSize(value); } - else if (!std::strcmp(id, "CheckShouldReload")) { + else if (id == kMsgIdCheckShouldReload) { if (_synth->shouldReloadFile()) { fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n"); std::lock_guard lock(_processMutex); @@ -667,20 +675,20 @@ void SfizzVstProcessor::doBackgroundWork() _synth->loadScalaFile(_state.scalaFile); } } - else if (!std::strcmp(id, "NotifyPlayState")) { + else if (id == kMsgIdNotifyPlayState) { SfizzPlayState playState = *msg->payload(); Steinberg::OPtr notification { allocateMessage() }; notification->setMessageID("NotifiedPlayState"); notification->getAttributes()->setBinary("PlayState", &playState, sizeof(playState)); sendMessage(notification); } - else if (!std::strcmp(id, "ReceiveMessage")) { + else if (id == kMsgIdReceiveMessage) { Steinberg::OPtr notification { allocateMessage() }; notification->setMessageID("ReceivedMessage"); notification->getAttributes()->setBinary("Message", msg->payload(), msg->size); sendMessage(notification); } - else if (!std::strcmp(id, "NoteEvents")) { + else if (id == kMsgIdNoteEvents) { Steinberg::OPtr notification { allocateMessage() }; notification->setMessageID("NoteEvents"); notification->getAttributes()->setBinary("Events", msg->payload(), msg->size); From 29d8723601c5fe0556063691ce029931507c9974 Mon Sep 17 00:00:00 2001 From: redtide Date: Tue, 2 Mar 2021 17:10:03 +0100 Subject: [PATCH 355/668] Removed erroneous comment --- src/sfizz/VoiceManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/VoiceManager.cpp b/src/sfizz/VoiceManager.cpp index d6a73cc2..eb663fd6 100644 --- a/src/sfizz/VoiceManager.cpp +++ b/src/sfizz/VoiceManager.cpp @@ -114,7 +114,7 @@ void VoiceManager::clear() void VoiceManager::setStealingAlgorithm(StealingAlgorithm algorithm) { switch(algorithm){ - case StealingAlgorithm::First: // fallthrough + case StealingAlgorithm::First: for (auto& voice : list_) voice.disablePowerFollower(); From f2a79723a7039d2da8b7af865fd3b697df7b7a25 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Tue, 23 Feb 2021 12:25:25 +0100 Subject: [PATCH 356/668] Add support for count --- src/sfizz/Defaults.cpp | 3 ++- src/sfizz/Defaults.h | 1 + src/sfizz/Region.cpp | 6 +++++- src/sfizz/Region.h | 3 ++- src/sfizz/SynthMessaging.cpp | 3 ++- src/sfizz/Voice.cpp | 41 +++++++++++++++++++++++++++++++----- tests/RegionValuesT.cpp | 2 -- 7 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 792983ff..b30272dc 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -12,9 +12,10 @@ extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), 0 extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, uint32_t_max), kEnforceLowerBound }; -extern const OpcodeSpec sampleCount { 1, Range(1, uint32_t_max), 0 }; +extern const OpcodeSpec sampleCount { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopStart { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopEnd { uint32_t_max, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopCount { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), 0 }; extern const OpcodeSpec oscillator { OscillatorEnabled::Auto, Range(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 }; extern const OpcodeSpec oscillatorPhase { 0.0f, Range(-1000.0f, 1000.0f), 0 }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index f778e09e..2290052b 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -134,6 +134,7 @@ namespace Default extern const OpcodeSpec sampleCount; extern const OpcodeSpec loopStart; extern const OpcodeSpec loopEnd; + extern const OpcodeSpec loopCount; extern const OpcodeSpec loopCrossfade; extern const OpcodeSpec oscillatorPhase; extern const OpcodeSpec oscillator; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 4fed8896..88948362 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -122,7 +122,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) sampleEnd = opcode.read(Default::sampleEnd); break; case hash("count"): - sampleCount = opcode.read(Default::sampleCount); + sampleCount = opcode.readOptional(Default::sampleCount); + loopMode = LoopMode::one_shot; break; case hash("loop_mode"): // also loopmode loopMode = opcode.readOptional(Default::loopMode); @@ -130,6 +131,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("loop_end"): // also loopend loopRange.setEnd(opcode.read(Default::loopEnd)); break; + case hash("loop_count"): + loopCount = opcode.readOptional(Default::loopCount); + break; case hash("loop_start"): // also loopstart loopRange.setStart(opcode.read(Default::loopStart)); break; diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 98dda576..bb72cfd4 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -326,9 +326,10 @@ struct Region { int64_t offsetRandom { Default::offsetRandom }; // offset_random CCMap offsetCC { Default::offsetMod }; uint32_t sampleEnd { Default::sampleEnd }; // end - uint32_t sampleCount { Default::sampleCount }; // count + absl::optional sampleCount {}; // count absl::optional loopMode {}; // loopmode Range loopRange { Default::loopStart, Default::loopEnd }; //loopstart and loopend + absl::optional loopCount {}; // count float loopCrossfade { Default::loopCrossfade }; // loop_crossfade // Wavetable oscillator diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 67407e3c..0c73a454 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -186,7 +186,8 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/count", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'h'>(delay, path, region.sampleCount); + if (region.sampleCount) + client.receive<'h'>(delay, path, *region.sampleCount); } break; MATCH("/region&/loop_range", "") { diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 20e84be0..4d76c6f7 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -192,6 +192,9 @@ struct Voice::Impl int sourcePosition_ { 0 }; int initialDelay_ { 0 }; int age_ { 0 }; + uint32_t count_ { 1 }; + int sampleSize_ { 0 }; + struct { int start { 0 }; int end { 0 }; @@ -199,6 +202,7 @@ struct Voice::Impl int xfSize { 0 }; int xfOutStart { 0 }; int xfInStart { 0 }; + uint32_t restarts { 0 }; } loop_; FileDataHolder currentPromise_; @@ -416,6 +420,7 @@ void Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe impl.triggerDelay_ = delay; impl.initialDelay_ = delay + static_cast(region->getDelay() * impl.sampleRate_); impl.baseFrequency_ = impl.resources_.tuning.getFrequencyOfKey(impl.triggerEvent_.number); + impl.sampleSize_ = region->trueSampleEnd(impl.resources_.filePool.getOversamplingFactor()) - impl.sourcePosition_ - 1; impl.bendStepFactor_ = centsFactor(region->bendStep); impl.bendSmoother_.setSmoothing(region->bendSmooth, impl.sampleRate_); impl.bendSmoother_.reset(centsFactor(region->getBendInCents(impl.resources_.midiState.getPitchBend()))); @@ -924,12 +929,22 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept if (isLooping) { int oldIndex {}; int oldPartitionType {}; + int blockRestarts { 0 }; for (unsigned i = 0; i < numSamples; ++i) { - int index = (*indices)[i]; - - // wrap indices post loop-entry around the loop segment - int wrappedIndex = (index <= loop.end) ? index : - (loop.start + (index - loop.start) % loop.size); + int index = (*indices)[i] - loop.size * blockRestarts; + int wrappedIndex = index; + // wrap indices post loop-entry around the loop segment and increment the counter if necessary + if (index > loop.end) { + if (region_->loopCount && loop_.restarts >= *region_->loopCount) { + wrappedIndex = loop.end; + egAmplitude_.setReleaseTime(0.0f); + egAmplitude_.startRelease(i); + } else { + wrappedIndex -= loop.size; + blockRestarts += 1; + loop_.restarts += 1; + } + } (*indices)[i] = wrappedIndex; // identify the partition this index is in @@ -956,7 +971,12 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept int(source.getNumFrames())) - 1; + int blockRestarts { 0 }; + for (unsigned i = 0; i < numSamples; ++i) { + ASSERT((*indices)[i] - sampleSize_ * blockRestarts >= 0); + (*indices)[i] -= sampleSize_ * blockRestarts; + if ((*indices)[i] >= sampleEnd) { #ifndef NDEBUG // Check for underflow @@ -967,6 +987,14 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept << " for sample " << *region_->sampleId); } #endif + if (region_->sampleCount && count_ < *region_->sampleCount) { + (*indices)[i] -= sampleSize_; + ASSERT((*indices)[i] >= 0); + blockRestarts += 1; + count_ += 1; + continue; + } + if (!region_->flexAmpEG) { egAmplitude_.setReleaseTime(0.0f); egAmplitude_.startRelease(i); @@ -975,6 +1003,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept // TODO(jpc): Flex AmpEG flexEGs_[*region_->flexAmpEG]->release(i); } + fill(indices->subspan(i), sampleEnd); fill(coeffs->subspan(i), 1.0f); break; @@ -1416,6 +1445,7 @@ void Voice::reset() noexcept impl.currentPromise_.reset(); impl.sourcePosition_ = 0; impl.age_ = 0; + impl.count_ = 1; impl.floatPositionOffset_ = 0.0f; impl.noteIsOff_ = false; @@ -1440,6 +1470,7 @@ void Voice::Impl::resetLoopInformation() noexcept loop_.xfSize = 0; loop_.xfOutStart = 0; loop_.xfInStart = 0; + loop_.restarts = 0; } void Voice::Impl::updateLoopInformation() noexcept diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index 24467ea3..e321d558 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -237,9 +237,7 @@ TEST_CASE("[Values] Count") synth.dispatchMessage(client, 0, "/region1/count", "", nullptr); synth.dispatchMessage(client, 0, "/region2/count", "", nullptr); std::vector expected { - "/region0/count,h : { 1 }", "/region1/count,h : { 2 }", - "/region2/count,h : { 1 }", }; REQUIRE(messageList == expected); } From 4a3c1f36e5d50af839d859d84f5fc55ca5264b40 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Fri, 5 Mar 2021 00:21:35 +0100 Subject: [PATCH 357/668] Handle the different types of looping --- src/sfizz/Voice.cpp | 226 +++++++++++++++++++++++++++----------------- src/sfizz/Voice.h | 1 - 2 files changed, 139 insertions(+), 88 deletions(-) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 4d76c6f7..7b009771 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -171,6 +171,30 @@ struct Voice::Impl */ void updateLoopInformation() noexcept; + /** + * @brief Check whether the voice is released + * + * @return true + * @return false + */ + bool released() const noexcept; + + /** + * @brief Release the voice after a given delay + * + * @param delay + */ + void release(int delay) noexcept; + + /** + * @brief Off the voice (steal). This will respect the off mode of the region + * and set the envelopes if necessary. + * + * @param delay + * @param fast whether to apply a fast release regardless of the off mode + */ + void off(int delay, bool fast = false) noexcept; + const NumericId id_; StateListener* stateListener_ = nullptr; @@ -450,29 +474,39 @@ bool Voice::isFree() const noexcept void Voice::release(int delay) noexcept { Impl& impl = *impl_; - if (impl.state_ != State::playing) + impl.release(delay); +} + +void Voice::Impl::release(int delay) noexcept +{ + if (state_ != State::playing) return; - if (!impl.region_->flexAmpEG) { - if (impl.egAmplitude_.getRemainingDelay() > delay) - impl.switchState(State::cleanMeUp); + if (!region_->flexAmpEG) { + if (egAmplitude_.getRemainingDelay() > delay) + switchState(State::cleanMeUp); } else { - if (impl.flexEGs_[*impl.region_->flexAmpEG]->getRemainingDelay() > static_cast(delay)) - impl.switchState(State::cleanMeUp); + if (flexEGs_[*region_->flexAmpEG]->getRemainingDelay() > static_cast(delay)) + switchState(State::cleanMeUp); } - impl.resources_.modMatrix.releaseVoice(impl.id_, impl.region_->getId(), delay); + resources_.modMatrix.releaseVoice(id_, region_->getId(), delay); } void Voice::off(int delay, bool fast) noexcept { Impl& impl = *impl_; - if (!impl.region_->flexAmpEG) { - if (impl.region_->offMode == OffMode::fast || fast) { - impl.egAmplitude_.setReleaseTime(Default::offTime); - } else if (impl.region_->offMode == OffMode::time) { - impl.egAmplitude_.setReleaseTime(impl.region_->offTime); + impl.off(delay, fast); +} + +void Voice::Impl::off(int delay, bool fast) noexcept +{ + if (!region_->flexAmpEG) { + if (region_->offMode == OffMode::fast || fast) { + egAmplitude_.setReleaseTime(Default::offTime); + } else if (region_->offMode == OffMode::time) { + egAmplitude_.setReleaseTime(region_->offTime); } } else { @@ -884,8 +918,9 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept // calculate loop characteristics const auto loop = this->loop_; - const bool isLooping = region_->shouldLoop() - && (static_cast(loop.end) < source.getNumFrames()); + const bool hasLoopSamples = static_cast(loop.end) < source.getNumFrames(); + const bool loopContinuous = hasLoopSamples && (region_->loopMode == LoopMode::loop_continuous); + const bool loopSustain = hasLoopSamples && (region_->loopMode == LoopMode::loop_sustain) && !released(); /* loop start loop end @@ -907,13 +942,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept enum PartitionType { kPartitionNormal, kPartitionLoopXfade }; SpanHolder> partitionBuffers[2]; - if (!isLooping) { - static const int starts[1] = { 0 }; - static const int types[1] = { kPartitionNormal }; - partitionStarts = absl::MakeSpan(const_cast(starts), 1); - partitionTypes = absl::MakeSpan(const_cast(types), 1); - numPartitions = 1; - } else { + if (loopSustain || loopContinuous) { for (auto& buf : partitionBuffers) { buf = resources_.bufferPool.getIndexBuffer(numSamples); if (!buf) @@ -923,87 +952,104 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept partitionTypes = *partitionBuffers[1]; // Note: partitions will be alternance of Normal/Xfade // computed along with index processing below + } else { + static const int starts[1] = { 0 }; + static const int types[1] = { kPartitionNormal }; + partitionStarts = absl::MakeSpan(const_cast(starts), 1); + partitionTypes = absl::MakeSpan(const_cast(types), 1); + numPartitions = 1; } - // index preprocessing for loops - if (isLooping) { - int oldIndex {}; - int oldPartitionType {}; - int blockRestarts { 0 }; - for (unsigned i = 0; i < numSamples; ++i) { - int index = (*indices)[i] - loop.size * blockRestarts; - int wrappedIndex = index; - // wrap indices post loop-entry around the loop segment and increment the counter if necessary - if (index > loop.end) { - if (region_->loopCount && loop_.restarts >= *region_->loopCount) { - wrappedIndex = loop.end; - egAmplitude_.setReleaseTime(0.0f); - egAmplitude_.startRelease(i); - } else { - wrappedIndex -= loop.size; - blockRestarts += 1; - loop_.restarts += 1; - } - } - (*indices)[i] = wrappedIndex; - - // identify the partition this index is in - bool xfading = wrappedIndex >= loop.start && wrappedIndex >= loop.xfOutStart; - int partitionType = xfading ? kPartitionLoopXfade : kPartitionNormal; - // if looping or entering a different type, start a new partition - bool start = i == 0 || wrappedIndex < oldIndex || partitionType != oldPartitionType; - if (start) { - partitionStarts[numPartitions] = i; - partitionTypes[numPartitions] = partitionType; - ++numPartitions; - } - - oldIndex = wrappedIndex; - oldPartitionType = partitionType; - } - } - // index preprocessing for one-shots - else { - // cut short the voice at the instant of reaching end of sample - const auto sampleEnd = min( + const auto sampleEnd = min( int(region_->trueSampleEnd(resources_.filePool.getOversamplingFactor())), int(currentPromise_->information.end), int(source.getNumFrames())) - 1; - int blockRestarts { 0 }; + int blockRestarts { 0 }; + int oldIndex {}; + int oldPartitionType {}; + + const auto addPartitionIfNecessary = [&] (unsigned blockIndex, int wrappedIndex, bool wrapped) { + const bool xfading = wrappedIndex >= loop.start && wrappedIndex >= loop.xfOutStart; + const int partitionType = xfading ? kPartitionLoopXfade : kPartitionNormal; + + // if looping or entering a different type, start a new partition + bool start = blockIndex == 0 || wrapped || partitionType != oldPartitionType; + if (start) { + partitionStarts[numPartitions] = blockIndex; + partitionTypes[numPartitions] = partitionType; + ++numPartitions; + } + + oldIndex = wrappedIndex; + oldPartitionType = partitionType; + }; + + if (loopContinuous) { for (unsigned i = 0; i < numSamples; ++i) { - ASSERT((*indices)[i] - sampleSize_ * blockRestarts >= 0); + int wrappedIndex = (*indices)[i] - loop.size * blockRestarts; + if (wrappedIndex > loop.end) { + wrappedIndex -= loop.size; + blockRestarts += 1; + loop_.restarts += 1; + } + (*indices)[i] = wrappedIndex; + const bool wrapped = wrappedIndex < oldIndex; + addPartitionIfNecessary(i, wrappedIndex, wrapped); + + // Release if we reached the loop count + if (wrapped && region_->loopCount && loop_.restarts >= *region_->loopCount && !released()) { + release(i); + } + } + } else if (loopSustain) { + unsigned i = 0; + while (i < numSamples) { + int wrappedIndex = (*indices)[i] - loop.size * blockRestarts; + if (wrappedIndex > loop.end) { + wrappedIndex -= loop.size; + blockRestarts += 1; + loop_.restarts += 1; + } + (*indices)[i] = wrappedIndex; + const bool wrapped = wrappedIndex < oldIndex; + + // identify the partition this index is in + addPartitionIfNecessary(i, wrappedIndex, wrapped); + + i++; + + // Release if we reached the loop count and break + if (wrapped && region_->loopCount && loop_.restarts >= *region_->loopCount) { + release(i - 1); + break; + } + } + + while (i < numSamples) { // In case we released within the block, continue as if it were a one-shot + (*indices)[i] -= loop.size * blockRestarts; + if ((*indices)[i] >= sampleEnd) { + fill(indices->subspan(i), sampleEnd); + fill(coeffs->subspan(i), 1.0f); + break; + } + i++; + } + } else { // One shots and loop_sustain that have ended + for (unsigned i = 0; i < numSamples; ++i) { (*indices)[i] -= sampleSize_ * blockRestarts; if ((*indices)[i] >= sampleEnd) { -#ifndef NDEBUG - // Check for underflow - if (source.getNumFrames() - 1 < currentPromise_->information.end) { - DBG("[sfizz] Underflow: source available samples " - << source.getNumFrames() << "/" - << currentPromise_->information.end - << " for sample " << *region_->sampleId); - } -#endif if (region_->sampleCount && count_ < *region_->sampleCount) { (*indices)[i] -= sampleSize_; - ASSERT((*indices)[i] >= 0); blockRestarts += 1; count_ += 1; continue; } - if (!region_->flexAmpEG) { - egAmplitude_.setReleaseTime(0.0f); - egAmplitude_.startRelease(i); - } - else { - // TODO(jpc): Flex AmpEG - flexEGs_[*region_->flexAmpEG]->release(i); - } - + release(i); fill(indices->subspan(i), sampleEnd); fill(coeffs->subspan(i), 1.0f); break; @@ -1421,6 +1467,14 @@ void Voice::Impl::fillWithGenerator(AudioSpan buffer) noexcept #endif } +bool Voice::Impl::released() const noexcept +{ + if (!region_->flexAmpEG) + return egAmplitude_.isReleased(); + else + return flexEGs_[*region_->flexAmpEG]->isReleased(); +} + bool Voice::checkOffGroup(const Region* other, int delay, int noteNumber) noexcept { Impl& impl = *impl_; @@ -1528,10 +1582,8 @@ bool Voice::releasedOrFree() const noexcept Impl& impl = *impl_; if (impl.state_ != State::playing) return true; - if (!impl.region_->flexAmpEG) - return impl.egAmplitude_.isReleased(); - else - return impl.flexEGs_[*impl.region_->flexAmpEG]->isReleased(); + + return impl.released(); } void Voice::setMaxFiltersPerVoice(size_t numFilters) diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index b6a07d38..34885cbb 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -309,7 +309,6 @@ public: * @brief Release the voice after a given delay * * @param delay - * @param fastRelease whether to do a normal release or cut the voice abruptly */ void release(int delay) noexcept; From a98e909eebffc4127f8c099fb4cc4a1361a0554d Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Fri, 5 Mar 2021 13:02:03 +0100 Subject: [PATCH 358/668] Tweaks --- src/sfizz/Region.cpp | 2 +- src/sfizz/Voice.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 88948362..6283cbf4 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1661,7 +1661,7 @@ uint32_t sfz::Region::trueSampleEnd(Oversampling factor) const noexcept if (sampleEnd <= 0) return 0; - return min(static_cast(sampleEnd), loopRange.getEnd()) * static_cast(factor); + return static_cast(sampleEnd) * static_cast(factor); } uint32_t sfz::Region::loopStart(Oversampling factor) const noexcept diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 7b009771..d3b04c2f 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -987,7 +987,6 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept }; if (loopContinuous) { - for (unsigned i = 0; i < numSamples; ++i) { int wrappedIndex = (*indices)[i] - loop.size * blockRestarts; if (wrappedIndex > loop.end) { @@ -1000,9 +999,8 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept addPartitionIfNecessary(i, wrappedIndex, wrapped); // Release if we reached the loop count - if (wrapped && region_->loopCount && loop_.restarts >= *region_->loopCount && !released()) { + if (wrapped && region_->loopCount && loop_.restarts >= *region_->loopCount && !released()) release(i); - } } } else if (loopSustain) { unsigned i = 0; @@ -1037,19 +1035,21 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept } i++; } - } else { // One shots and loop_sustain that have ended + } else { // One shots and loop_sustain that have released or ended for (unsigned i = 0; i < numSamples; ++i) { (*indices)[i] -= sampleSize_ * blockRestarts; if ((*indices)[i] >= sampleEnd) { - if (region_->sampleCount && count_ < *region_->sampleCount) { + if (region_->sampleCount && count_ < *region_->sampleCount && !region_->shouldLoop()) { (*indices)[i] -= sampleSize_; blockRestarts += 1; count_ += 1; continue; } - release(i); + if (!released()) + release(i); + fill(indices->subspan(i), sampleEnd); fill(coeffs->subspan(i), 1.0f); break; From 5d8eda74285f4ce999469a76c61e17b9bd63d695 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Fri, 5 Mar 2021 13:03:52 +0100 Subject: [PATCH 359/668] Better messaging --- src/sfizz/SynthMessaging.cpp | 10 ++++++++++ tests/RegionValuesT.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 0c73a454..3b4b18bf 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -188,6 +188,8 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co GET_REGION_OR_BREAK(indices[0]) if (region.sampleCount) client.receive<'h'>(delay, path, *region.sampleCount); + else + client.receive<'N'>(delay, path, {}); } break; MATCH("/region&/loop_range", "") { @@ -226,6 +228,14 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'f'>(delay, path, region.loopCrossfade); } break; + MATCH("/region&/loop_count", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.loopCount) + client.receive<'h'>(delay, path, *region.loopCount); + else + client.receive<'N'>(delay, path, {}); + } break; + MATCH("/region&/group", "") { GET_REGION_OR_BREAK(indices[0]) client.receive<'h'>(delay, path, region.group); diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index e321d558..91df9ba0 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -237,7 +237,9 @@ TEST_CASE("[Values] Count") synth.dispatchMessage(client, 0, "/region1/count", "", nullptr); synth.dispatchMessage(client, 0, "/region2/count", "", nullptr); std::vector expected { + "/region0/count,N : { }", "/region1/count,h : { 2 }", + "/region2/count,N : { }", }; REQUIRE(messageList == expected); } @@ -348,6 +350,29 @@ TEST_CASE("[Values] Loop crossfade") REQUIRE(messageList == expected); } +TEST_CASE("[Values] Loop count") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav loop_count=2 + sample=kick.wav loop_count=-1 + )"); + synth.dispatchMessage(client, 0, "/region0/loop_count", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/loop_count", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/loop_count", "", nullptr); + std::vector expected { + "/region0/loop_count,N : { }", + "/region1/loop_count,h : { 2 }", + "/region2/loop_count,N : { }", + }; + REQUIRE(messageList == expected); +} + + TEST_CASE("[Values] Group") { Synth synth; From da57f36a0f595a9b744a54a80a1d529a02336fdd Mon Sep 17 00:00:00 2001 From: redtide Date: Fri, 5 Mar 2021 21:22:19 +0100 Subject: [PATCH 360/668] GH Actions: restored official Archlinux image --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb226383..716e3b67 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -137,7 +137,7 @@ jobs: build_for_mingw32: runs-on: ubuntu-18.04 container: - image: ghcr.io/sfztools/archlinux + image: archlinux steps: - name: Set install name run: | @@ -201,7 +201,7 @@ jobs: build_for_mingw64: runs-on: ubuntu-18.04 container: - image: ghcr.io/sfztools/archlinux + image: archlinux steps: - name: Set install name run: | From 194ceb2592a6c8a7e8e4300f29c2e3cfd0a89f4d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 08:54:27 +0100 Subject: [PATCH 361/668] P-impl the VK to facilitate color editing --- plugins/editor/src/editor/GUIPiano.cpp | 173 ++++++++++++++++--------- plugins/editor/src/editor/GUIPiano.h | 31 +---- 2 files changed, 119 insertions(+), 85 deletions(-) diff --git a/plugins/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp index 0aa16586..9a8b5844 100644 --- a/plugins/editor/src/editor/GUIPiano.cpp +++ b/plugins/editor/src/editor/GUIPiano.cpp @@ -17,73 +17,123 @@ static constexpr CCoord keyoffs[12] = {0, 0.6, 1, 1.8, 2, 3, 3.55, 4, 4.7, 5, 5.85, 6}; static constexpr bool black[12] = {0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0}; +struct SPiano::Impl { + unsigned octs_ {}; + std::vector keyval_; + std::bitset<128> keyUsed_; + std::bitset<128> keyswitchUsed_; + unsigned mousePressedKey_ = ~0u; + + CCoord innerPaddingX_ = 4.0; + CCoord innerPaddingY_ = 4.0; + CCoord spacingY_ = 4.0; + + CColor backgroundFill_ { 0xca, 0xca, 0xca, 0xff }; + float backgroundRadius_ = 5.0; + + float keyUsedHue_ = 0.55; + float keySwitchHue_ = 0.0; + float whiteKeyLuma_ = 0.9; + float blackKeyLuma_ = 0.5; + float keyLumaPressDelta_ = 0.2; + + CColor outline_ { 0x00, 0x00, 0x00, 0xff }; + CColor shadeOutline_ { 0x80, 0x80, 0x80, 0xff }; + CColor labelStroke_ { 0x63, 0x63, 0x63, 0xff }; + + mutable Dimensions dim_; + SharedPointer font_; +}; + SPiano::SPiano(CRect bounds) - : CView(bounds) + : CView(bounds), impl_(new Impl) { setNumOctaves(10); } +CFontRef SPiano::getFont() const +{ + const Impl& impl = *impl_; + return impl.font_; +} + void SPiano::setFont(CFontRef font) { - font_ = font; + Impl& impl = *impl_; + impl.font_ = font; getDimensions(true); invalid(); } +unsigned SPiano::getNumOctaves() const +{ + const Impl& impl = *impl_; + return impl.octs_; +} + void SPiano::setNumOctaves(unsigned octs) { - keyval_.resize(octs * 12); - octs_ = std::max(1u, octs); + Impl& impl = *impl_; + impl.keyval_.resize(octs * 12); + impl.octs_ = std::max(1u, octs); getDimensions(true); invalid(); } void SPiano::setKeyUsed(unsigned key, bool used) { + Impl& impl = *impl_; + if (key >= 128) return; - if (keyUsed_.test(key) == used) + if (impl.keyUsed_.test(key) == used) return; - keyUsed_.set(key, used); + impl.keyUsed_.set(key, used); invalid(); } void SPiano::setKeyswitchUsed(unsigned key, bool used) { + Impl& impl = *impl_; + if (key >= 128) return; - if (keyswitchUsed_.test(key) == used) + if (impl.keyswitchUsed_.test(key) == used) return; - keyswitchUsed_.set(key, used); + impl.keyswitchUsed_.set(key, used); invalid(); } void SPiano::setKeyValue(unsigned key, float value) { + Impl& impl = *impl_; + if (key >= 128) return; value = std::max(0.0f, std::min(1.0f, value)); - if (keyval_[key] == value) + if (impl.keyval_[key] == value) return; - keyval_[key] = value; + impl.keyval_[key] = value; invalid(); } SPiano::KeyRole SPiano::getKeyRole(unsigned key) { + Impl& impl = *impl_; + if (key >= 128) return KeyRole::Unused; - if (keyUsed_.test(key)) + if (impl.keyUsed_.test(key)) return KeyRole::Note; - if (keyswitchUsed_.test(key)) + if (impl.keyswitchUsed_.test(key)) return KeyRole::Switch; return KeyRole::Unused; @@ -91,17 +141,18 @@ SPiano::KeyRole SPiano::getKeyRole(unsigned key) void SPiano::draw(CDrawContext* dc) { + Impl& impl = *impl_; const Dimensions dim = getDimensions(false); - const unsigned octs = octs_; + const unsigned octs = impl.octs_; const unsigned keyCount = octs * 12; - const bool allKeysUsed = keyUsed_.all(); + const bool allKeysUsed = impl.keyUsed_.all(); dc->setDrawMode(kAntiAliasing); - if (backgroundFill_.alpha > 0) { + if (impl.backgroundFill_.alpha > 0) { SharedPointer path; path = owned(dc->createGraphicsPath()); - path->addRoundRect(dim.bounds, backgroundRadius_); + path->addRoundRect(dim.bounds, impl.backgroundRadius_); dc->setFillColor(CColor(0xca, 0xca, 0xca)); dc->drawGraphicsPath(path, CDrawContext::kPathFilled); } @@ -110,26 +161,26 @@ void SPiano::draw(CDrawContext* dc) if (!black[key % 12]) { CRect rect = keyRect(key); - SColorHCY hcy(0.0, 1.0, whiteKeyLuma_); + SColorHCY hcy(0.0, 1.0, impl.whiteKeyLuma_); switch (getKeyRole(key)) { case KeyRole::Note: if (allKeysUsed) goto whiteKeyDefault; - hcy.h = keyUsedHue_; + hcy.h = impl.keyUsedHue_; break; case KeyRole::Switch: - hcy.h = keySwitchHue_; + hcy.h = impl.keySwitchHue_; break; default: whiteKeyDefault: hcy.y = 1.0; - if (keyval_[key]) + if (impl.keyval_[key]) hcy.c = 0.0; break; } - if (keyval_[key]) - hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_); + if (impl.keyval_[key]) + hcy.y = std::max(0.0f, hcy.y - impl.keyLumaPressDelta_); CColor keycolor = hcy.toColor(); dc->setFillColor(keycolor); @@ -137,7 +188,7 @@ void SPiano::draw(CDrawContext* dc) } } - dc->setFrameColor(outline_); + dc->setFrameColor(impl.outline_); dc->drawLine(dim.keyBounds.getTopLeft(), dim.keyBounds.getBottomLeft()); for (unsigned key = 0; key < keyCount; ++key) { if (!black[key % 12]) { @@ -150,62 +201,63 @@ void SPiano::draw(CDrawContext* dc) if (black[key % 12]) { CRect rect = keyRect(key); - SColorHCY hcy(0.0, 1.0, blackKeyLuma_); + SColorHCY hcy(0.0, 1.0, impl.blackKeyLuma_); switch (getKeyRole(key)) { case KeyRole::Note: if (allKeysUsed) goto blackKeyDefault; - hcy.h = keyUsedHue_; + hcy.h = impl.keyUsedHue_; break; case KeyRole::Switch: - hcy.h = keySwitchHue_; + hcy.h = impl.keySwitchHue_; break; default: blackKeyDefault: hcy.c = 0.0; break; } - if (keyval_[key]) - hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_); + if (impl.keyval_[key]) + hcy.y = std::max(0.0f, hcy.y - impl.keyLumaPressDelta_); CColor keycolor = hcy.toColor(); dc->setFillColor(keycolor); dc->drawRect(rect, kDrawFilled); - dc->setFrameColor(outline_); + dc->setFrameColor(impl.outline_); dc->drawRect(rect); } } - if (const CFontRef& font = font_) { + if (const CFontRef& font = impl.font_) { for (unsigned o = 0; o < octs; ++o) { CRect rect = keyRect(o * 12); CRect textRect( rect.left, dim.labelBounds.top, rect.right, dim.labelBounds.bottom); dc->setFont(font); - dc->setFontColor(labelStroke_); + dc->setFontColor(impl.labelStroke_); std::string text = std::to_string(static_cast(o) - 1); dc->drawString(text.c_str(), textRect, kCenterText); } } { - dc->setFrameColor(outline_); + dc->setFrameColor(impl.outline_); dc->drawLine(dim.keyBounds.getTopLeft(), dim.keyBounds.getTopRight()); - dc->setFrameColor(shadeOutline_); + dc->setFrameColor(impl.shadeOutline_); dc->drawLine(dim.keyBounds.getBottomLeft(), dim.keyBounds.getBottomRight()); } - dc->setFrameColor(outline_); + dc->setFrameColor(impl.outline_); } CMouseEventResult SPiano::onMouseDown(CPoint& where, const CButtonState& buttons) { + Impl& impl = *impl_; unsigned key = keyAtPos(where); if (key != ~0u) { - keyval_[key] = 1; - mousePressedKey_ = key; + impl.keyval_[key] = 1; + impl.mousePressedKey_ = key; if (onKeyPressed) onKeyPressed(key, mousePressVelocity(key, where.y)); invalid(); @@ -216,12 +268,13 @@ CMouseEventResult SPiano::onMouseDown(CPoint& where, const CButtonState& buttons CMouseEventResult SPiano::onMouseUp(CPoint& where, const CButtonState& buttons) { - unsigned key = mousePressedKey_; + Impl& impl = *impl_; + unsigned key = impl.mousePressedKey_; if (key != ~0u) { - keyval_[key] = 0; + impl.keyval_[key] = 0; if (onKeyReleased) onKeyReleased(key, mousePressVelocity(key, where.y)); - mousePressedKey_ = ~0u; + impl.mousePressedKey_ = ~0u; invalid(); return kMouseEventHandled; } @@ -230,16 +283,17 @@ CMouseEventResult SPiano::onMouseUp(CPoint& where, const CButtonState& buttons) CMouseEventResult SPiano::onMouseMoved(CPoint& where, const CButtonState& buttons) { - if (mousePressedKey_ != ~0u) { + Impl& impl = *impl_; + if (impl.mousePressedKey_ != ~0u) { unsigned key = keyAtPos(where); - if (mousePressedKey_ != key) { - keyval_[mousePressedKey_] = 0; + if (impl.mousePressedKey_ != key) { + impl.keyval_[impl.mousePressedKey_] = 0; if (onKeyReleased) - onKeyReleased(mousePressedKey_, mousePressVelocity(key, where.y)); + onKeyReleased(impl.mousePressedKey_, mousePressVelocity(key, where.y)); // mousePressedKey_ = ~0u; if (key != ~0u) { - keyval_[key] = 1; - mousePressedKey_ = key; + impl.keyval_[key] = 1; + impl.mousePressedKey_ = key; if (onKeyPressed) onKeyPressed(key, mousePressVelocity(key, where.y)); } @@ -252,33 +306,35 @@ CMouseEventResult SPiano::onMouseMoved(CPoint& where, const CButtonState& button const SPiano::Dimensions& SPiano::getDimensions(bool forceUpdate) const { - if (!forceUpdate && dim_.bounds == getViewSize()) - return dim_; + const Impl& impl = *impl_; + + if (!forceUpdate && impl.dim_.bounds == getViewSize()) + return impl.dim_; Dimensions dim; dim.bounds = getViewSize(); dim.paddedBounds = CRect(dim.bounds) - .extend(-2 * innerPaddingX_, -2 * innerPaddingY_); + .extend(-2 * impl.innerPaddingX_, -2 * impl.innerPaddingY_); CCoord keyHeight = std::floor(dim.paddedBounds.getHeight()); - CCoord fontHeight = font_ ? font_->getSize() : 0.0; - keyHeight -= spacingY_ + fontHeight; + CCoord fontHeight = impl.font_ ? impl.font_->getSize() : 0.0; + keyHeight -= impl.spacingY_ + fontHeight; dim.keyBounds = CRect(dim.paddedBounds) .setHeight(keyHeight); dim.keyWidth = static_cast( - dim.paddedBounds.getWidth() / octs_ / 7.0); - dim.keyBounds.setWidth(dim.keyWidth * octs_ * 7.0); + dim.paddedBounds.getWidth() / impl.octs_ / 7.0); + dim.keyBounds.setWidth(dim.keyWidth * impl.octs_ * 7.0); dim.keyBounds.offset( std::floor(0.5 * (dim.paddedBounds.getWidth() - dim.keyBounds.getWidth())), 0.0); - if (!font_) + if (!impl.font_) dim.labelBounds = CRect(); else dim.labelBounds = CRect( - dim.keyBounds.left, dim.keyBounds.bottom + spacingY_, - dim.keyBounds.right, dim.keyBounds.bottom + spacingY_ + fontHeight); + dim.keyBounds.left, dim.keyBounds.bottom + impl.spacingY_, + dim.keyBounds.right, dim.keyBounds.bottom + impl.spacingY_ + fontHeight); - dim_ = dim; - return dim_; + impl.dim_ = dim; + return impl.dim_; } CRect SPiano::keyRect(const Dimensions& dim, unsigned key) @@ -302,7 +358,8 @@ CRect SPiano::keyRect(unsigned key) const unsigned SPiano::keyAtPos(CPoint pos) const { - const unsigned octs = octs_; + const Impl& impl = *impl_; + const unsigned octs = impl.octs_; for (unsigned key = 0; key < octs * 12; ++key) { if (black[key % 12]) { diff --git a/plugins/editor/src/editor/GUIPiano.h b/plugins/editor/src/editor/GUIPiano.h index b01603c0..d7e57fae 100644 --- a/plugins/editor/src/editor/GUIPiano.h +++ b/plugins/editor/src/editor/GUIPiano.h @@ -19,10 +19,10 @@ class SPiano : public CView { public: explicit SPiano(CRect bounds); - CFontRef getFont() const { return font_; } + CFontRef getFont() const; void setFont(CFontRef font); - unsigned getNumOctaves() const { return octs_; } + unsigned getNumOctaves() const; void setNumOctaves(unsigned octs); void setKeyUsed(unsigned key, bool used); @@ -63,29 +63,6 @@ private: float mousePressVelocity(unsigned key, CCoord posY); private: - unsigned octs_ {}; - std::vector keyval_; - std::bitset<128> keyUsed_; - std::bitset<128> keyswitchUsed_; - unsigned mousePressedKey_ = ~0u; - - CCoord innerPaddingX_ = 4.0; - CCoord innerPaddingY_ = 4.0; - CCoord spacingY_ = 4.0; - - CColor backgroundFill_ { 0xca, 0xca, 0xca, 0xff }; - float backgroundRadius_ = 5.0; - - float keyUsedHue_ = 0.55; - float keySwitchHue_ = 0.0; - float whiteKeyLuma_ = 0.9; - float blackKeyLuma_ = 0.5; - float keyLumaPressDelta_ = 0.2; - - CColor outline_ { 0x00, 0x00, 0x00, 0xff }; - CColor shadeOutline_ { 0x80, 0x80, 0x80, 0xff }; - CColor labelStroke_ { 0x63, 0x63, 0x63, 0xff }; - - mutable Dimensions dim_; - SharedPointer font_; + struct Impl; + std::unique_ptr impl_; }; From 1b515a1b3365f9a92b63e7a3c4e7a04ee0574e2b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 08:56:35 +0100 Subject: [PATCH 362/668] Separate B/W key chroma and have these as variables --- plugins/editor/src/editor/GUIPiano.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp index 9a8b5844..bc3ecfbb 100644 --- a/plugins/editor/src/editor/GUIPiano.cpp +++ b/plugins/editor/src/editor/GUIPiano.cpp @@ -33,6 +33,8 @@ struct SPiano::Impl { float keyUsedHue_ = 0.55; float keySwitchHue_ = 0.0; + float whiteKeyChroma_ = 1.0; + float blackKeyChroma_ = 1.0; float whiteKeyLuma_ = 0.9; float blackKeyLuma_ = 0.5; float keyLumaPressDelta_ = 0.2; @@ -161,7 +163,7 @@ void SPiano::draw(CDrawContext* dc) if (!black[key % 12]) { CRect rect = keyRect(key); - SColorHCY hcy(0.0, 1.0, impl.whiteKeyLuma_); + SColorHCY hcy(0.0, impl.whiteKeyChroma_, impl.whiteKeyLuma_); switch (getKeyRole(key)) { case KeyRole::Note: @@ -201,7 +203,7 @@ void SPiano::draw(CDrawContext* dc) if (black[key % 12]) { CRect rect = keyRect(key); - SColorHCY hcy(0.0, 1.0, impl.blackKeyLuma_); + SColorHCY hcy(0.0, impl.blackKeyChroma_, impl.blackKeyLuma_); switch (getKeyRole(key)) { case KeyRole::Note: From 4a91d5c724c966c44164b8bead8932cfbd1ded33 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 08:57:56 +0100 Subject: [PATCH 363/668] Make the black key lighten on click --- plugins/editor/src/editor/GUIPiano.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp index bc3ecfbb..c056f56d 100644 --- a/plugins/editor/src/editor/GUIPiano.cpp +++ b/plugins/editor/src/editor/GUIPiano.cpp @@ -220,7 +220,7 @@ void SPiano::draw(CDrawContext* dc) } if (impl.keyval_[key]) - hcy.y = std::max(0.0f, hcy.y - impl.keyLumaPressDelta_); + hcy.y = std::min(1.0f, hcy.y + impl.keyLumaPressDelta_); CColor keycolor = hcy.toColor(); dc->setFillColor(keycolor); From 857cc25c5781b28f6201aed727402301fd50d345 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 09:08:22 +0100 Subject: [PATCH 364/668] Make luma and chroma adjustments --- plugins/editor/src/editor/GUIPiano.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/editor/src/editor/GUIPiano.cpp b/plugins/editor/src/editor/GUIPiano.cpp index c056f56d..ef82e5de 100644 --- a/plugins/editor/src/editor/GUIPiano.cpp +++ b/plugins/editor/src/editor/GUIPiano.cpp @@ -33,10 +33,10 @@ struct SPiano::Impl { float keyUsedHue_ = 0.55; float keySwitchHue_ = 0.0; - float whiteKeyChroma_ = 1.0; - float blackKeyChroma_ = 1.0; + float whiteKeyChroma_ = 0.9; + float blackKeyChroma_ = 0.75; float whiteKeyLuma_ = 0.9; - float blackKeyLuma_ = 0.5; + float blackKeyLuma_ = 0.35; float keyLumaPressDelta_ = 0.2; CColor outline_ { 0x00, 0x00, 0x00, 0xff }; From 625cf2a93b32d4372a6e48c1f3bcb7c9e7ba1c87 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 17:21:37 +0100 Subject: [PATCH 365/668] Add import utilities for foreign instruments --- plugins/CMakeLists.txt | 9 +- plugins/common/plugin/ForeignInstrument.cpp | 39 +++++++++ plugins/common/plugin/ForeignInstrument.h | 83 +++++++++++++++++++ .../plugin/foreign_instruments/AudioFile.cpp | 63 ++++++++++++++ .../plugin/foreign_instruments/AudioFile.h | 30 +++++++ 5 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 plugins/common/plugin/ForeignInstrument.cpp create mode 100644 plugins/common/plugin/ForeignInstrument.h create mode 100644 plugins/common/plugin/foreign_instruments/AudioFile.cpp create mode 100644 plugins/common/plugin/foreign_instruments/AudioFile.h diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index a2105364..f69bbe0f 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,10 +1,15 @@ add_library(plugins-common STATIC EXCLUDE_FROM_ALL "common/plugin/MessageUtils.h" - "common/plugin/MessageUtils.cpp") + "common/plugin/MessageUtils.cpp" + "common/plugin/ForeignInstrument.h" + "common/plugin/ForeignInstrument.cpp" + "common/plugin/foreign_instruments/AudioFile.h" + "common/plugin/foreign_instruments/AudioFile.cpp") target_include_directories(plugins-common PUBLIC "common") target_link_libraries(plugins-common PUBLIC sfizz::spin_mutex - PUBLIC absl::strings) + PUBLIC sfizz::filesystem absl::strings + PRIVATE sfizz::pugixml absl::memory) add_library(sfizz::plugins-common ALIAS plugins-common) if((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST) diff --git a/plugins/common/plugin/ForeignInstrument.cpp b/plugins/common/plugin/ForeignInstrument.cpp new file mode 100644 index 00000000..0508010e --- /dev/null +++ b/plugins/common/plugin/ForeignInstrument.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "ForeignInstrument.h" +#include "foreign_instruments/AudioFile.h" + +namespace sfz { + +InstrumentFormatRegistry::InstrumentFormatRegistry() + : formats_ { + &AudioFileInstrumentFormat::getInstance(), + } +{ +} + +InstrumentFormatRegistry& InstrumentFormatRegistry::getInstance() +{ + static InstrumentFormatRegistry registry; + return registry; +} + +const InstrumentFormat* InstrumentFormatRegistry::getMatchingFormat(const fs::path& path) const +{ + const InstrumentFormat* resultFormat = nullptr; + + for (const InstrumentFormat* currentFormat : formats_) { + if (currentFormat->matchesFilePath(path)) { + resultFormat = currentFormat; + break; + } + } + + return resultFormat; +} + +} // namespace sfz diff --git a/plugins/common/plugin/ForeignInstrument.h b/plugins/common/plugin/ForeignInstrument.h new file mode 100644 index 00000000..c48185fb --- /dev/null +++ b/plugins/common/plugin/ForeignInstrument.h @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include +#include +#include + +namespace sfz { + +class InstrumentFormat; +class InstrumentImporter; + +/** + * Registry of known non-SFZ instrument formats + */ +class InstrumentFormatRegistry { +private: + InstrumentFormatRegistry(); + +public: + /** + * @brief Get the single instance of the registry + */ + static InstrumentFormatRegistry& getInstance(); + + /** + * @brief Get a format which is able to handle a file which goes by the + * given path name, or null otherwise. + */ + const InstrumentFormat* getMatchingFormat(const fs::path& path) const; + +private: + std::vector formats_; +}; + +/** + * Description of a non-SFZ instrument format + */ +class InstrumentFormat { +public: + virtual ~InstrumentFormat() {} + + /** + * @brief Get the name of the instrument format + */ + virtual const char* name() const noexcept = 0; + + /** + * @brief Checks whether this importer matches files of the given path + * + * This should check for a pattern like such as a file extension, but not + * examine the contents of the file itself. + */ + virtual bool matchesFilePath(const fs::path& path) const = 0; + + /** + * @brief Create a new importer for instrument files of this format + */ + virtual std::unique_ptr createImporter() const = 0; +}; + +/** + * Importer of non-SFZ instruments + */ +class InstrumentImporter { +public: + /** + * @brief Get the format that this importer converts from + */ + virtual const InstrumentFormat* getFormat() const noexcept = 0; + + /** + * @brief Process the file and convert to an equivalent SFZ string + */ + virtual std::string convertToSfz(const fs::path& path) const = 0; +}; + +} // namespace sfz diff --git a/plugins/common/plugin/foreign_instruments/AudioFile.cpp b/plugins/common/plugin/foreign_instruments/AudioFile.cpp new file mode 100644 index 00000000..4fa897ea --- /dev/null +++ b/plugins/common/plugin/foreign_instruments/AudioFile.cpp @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "AudioFile.h" +#include +#include +#include +#include +#include + +namespace sfz { + +static const char* kRecognizedAudioExtensions[] = { + ".wav", ".flac", ".ogg", ".mp3", ".aif", ".aiff", ".aifc", +}; + +/// +AudioFileInstrumentFormat& AudioFileInstrumentFormat::getInstance() +{ + static AudioFileInstrumentFormat format; + return format; +} + +const char* AudioFileInstrumentFormat::name() const noexcept +{ + return "Audio file"; +} + +bool AudioFileInstrumentFormat::matchesFilePath(const fs::path& path) const +{ + const std::string ext = path.extension().u8string(); + + for (absl::string_view knownExt : kRecognizedAudioExtensions) { + if (absl::EqualsIgnoreCase(ext, knownExt)) + return true; + } + + return false; +} + +std::unique_ptr AudioFileInstrumentFormat::createImporter() const +{ + return absl::make_unique(); +} + +/// +std::string AudioFileInstrumentImporter::convertToSfz(const fs::path& path) const +{ + std::ostringstream os; + os.imbue(std::locale::classic()); + os << "sample=" << path.filename().u8string(); + return os.str(); +} + +const InstrumentFormat* AudioFileInstrumentImporter::getFormat() const noexcept +{ + return &AudioFileInstrumentFormat::getInstance(); +} + +} // namespace sfz diff --git a/plugins/common/plugin/foreign_instruments/AudioFile.h b/plugins/common/plugin/foreign_instruments/AudioFile.h new file mode 100644 index 00000000..09345152 --- /dev/null +++ b/plugins/common/plugin/foreign_instruments/AudioFile.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "../ForeignInstrument.h" + +namespace sfz { + +class AudioFileInstrumentFormat : public InstrumentFormat { +private: + AudioFileInstrumentFormat() noexcept = default; + +public: + static AudioFileInstrumentFormat& getInstance(); + const char* name() const noexcept override; + bool matchesFilePath(const fs::path& path) const override; + std::unique_ptr createImporter() const override; +}; + +/// +class AudioFileInstrumentImporter : public InstrumentImporter { +public: + std::string convertToSfz(const fs::path& path) const override; + const InstrumentFormat* getFormat() const noexcept override; +}; + +} // namespace sfz From 37b5c3b1bc8682b4a6e4c402a4d3e9798653fc08 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 17:40:05 +0100 Subject: [PATCH 366/668] Add importer support in plugins --- plugins/editor/src/editor/Editor.cpp | 9 +++++++++ plugins/lv2/sfizz.cpp | 21 ++++++++++++++++++++- plugins/vst/SfizzVstProcessor.cpp | 15 +++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 71ae9d20..9a6568c5 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -1069,6 +1069,15 @@ void Editor::Impl::chooseSfzFile() fs->setTitle("Load SFZ file"); fs->setDefaultExtension(CFileExtension("SFZ", "sfz")); + // also add extensions of importable files + fs->addFileExtension(CFileExtension("WAV", "wav")); + fs->addFileExtension(CFileExtension("FLAC", "flac")); + fs->addFileExtension(CFileExtension("OGG", "ogg")); + fs->addFileExtension(CFileExtension("MP3", "mp3")); + fs->addFileExtension(CFileExtension("AIF", "aif")); + fs->addFileExtension(CFileExtension("AIFF", "aiff")); + fs->addFileExtension(CFileExtension("AIFC", "aifc")); + std::string initialDir = getFileChooserInitialDir(currentSfzFile_); if (!initialDir.empty()) fs->setInitialDirectory(initialDir.c_str()); diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 01ab0224..16084aa5 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -34,6 +34,8 @@ #include "sfizz_lv2.h" +#include "plugin/ForeignInstrument.h" + #include #include #include @@ -1173,6 +1175,8 @@ sfizz_lv2_update_file_info(sfizz_plugin_t* self, const char *file_path) static bool sfizz_lv2_load_file(sfizz_plugin_t *self, const char *file_path) { + bool status; + char buf[MAX_PATH_SIZE]; if (file_path[0] == '\0') { @@ -1180,7 +1184,22 @@ sfizz_lv2_load_file(sfizz_plugin_t *self, const char *file_path) file_path = buf; } - bool status = sfizz_load_file(self->synth, file_path); + // bool status = sfizz_load_file(self->synth, file_path); + + /// + const sfz::InstrumentFormatRegistry& formatRegistry = sfz::InstrumentFormatRegistry::getInstance(); + const sfz::InstrumentFormat* format = formatRegistry.getMatchingFormat(file_path); + + if (!format) + status = sfizz_load_file(self->synth, file_path); + else { + auto importer = format->createImporter(); + std::string virtual_path = std::string(file_path) + ".sfz"; + std::string sfz_text = importer->convertToSfz(file_path); + status = sfizz_load_string(self->synth, virtual_path.c_str(), sfz_text.c_str()); + } + + /// sfizz_lv2_update_file_info(self, file_path); return status; } diff --git a/plugins/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp index d2d308f3..3701d13f 100644 --- a/plugins/vst/SfizzVstProcessor.cpp +++ b/plugins/vst/SfizzVstProcessor.cpp @@ -9,6 +9,7 @@ #include "SfizzVstState.h" #include "SfizzVstParameters.h" #include "SfizzFileScan.h" +#include "plugin/ForeignInstrument.h" #include "base/source/fstreamer.h" #include "pluginterfaces/vst/ivstevents.h" #include "pluginterfaces/vst/ivstparameterchanges.h" @@ -621,8 +622,18 @@ void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char* void SfizzVstProcessor::loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath) { - if (!filePath.empty()) - synth.loadSfzFile(filePath); + if (!filePath.empty()) { + const sfz::InstrumentFormatRegistry& formatRegistry = sfz::InstrumentFormatRegistry::getInstance(); + const sfz::InstrumentFormat* format = formatRegistry.getMatchingFormat(filePath); + if (!format) + synth.loadSfzFile(filePath); + else { + auto importer = format->createImporter(); + std::string virtualPath = filePath + ".sfz"; + std::string sfzText = importer->convertToSfz(filePath); + synth.loadSfzString(virtualPath, sfzText); + } + } else synth.loadSfzString("default.sfz", defaultSfzText); } From 5803630c0dec82720c5337ef13f256b7eef1b609 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 17:58:06 +0100 Subject: [PATCH 367/668] Eliminate a leftover comment --- plugins/lv2/sfizz.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/lv2/sfizz.cpp b/plugins/lv2/sfizz.cpp index 16084aa5..a1467ec2 100644 --- a/plugins/lv2/sfizz.cpp +++ b/plugins/lv2/sfizz.cpp @@ -1184,8 +1184,6 @@ sfizz_lv2_load_file(sfizz_plugin_t *self, const char *file_path) file_path = buf; } - // bool status = sfizz_load_file(self->synth, file_path); - /// const sfz::InstrumentFormatRegistry& formatRegistry = sfz::InstrumentFormatRegistry::getInstance(); const sfz::InstrumentFormat* format = formatRegistry.getMatchingFormat(file_path); From 9e362a5507961a42b9f06902df677fe10ff8d8bd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 18:08:27 +0100 Subject: [PATCH 368/668] Ensure to not set vst libs to a lower standard --- plugins/editor/cmake/Vstgui.cmake | 4 +++- plugins/vst/cmake/Vst3.cmake | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/editor/cmake/Vstgui.cmake b/plugins/editor/cmake/Vstgui.cmake index 8c0d4ca5..51d1c26f 100644 --- a/plugins/editor/cmake/Vstgui.cmake +++ b/plugins/editor/cmake/Vstgui.cmake @@ -208,7 +208,9 @@ endif() if(CMAKE_SYSTEM_NAME STREQUAL "Windows") # higher C++ requirement on Windows - set_property(TARGET sfizz_vstgui PROPERTY CXX_STANDARD 14) + if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 14) + set_property(TARGET sfizz_vstgui PROPERTY CXX_STANDARD 14) + endif() # Windows 10 RS2 DDI for custom fonts target_compile_definitions(sfizz_vstgui PRIVATE "NTDDI_VERSION=0x0A000003") # disable custom fonts while dwrite3 API is unavailable in MinGW diff --git a/plugins/vst/cmake/Vst3.cmake b/plugins/vst/cmake/Vst3.cmake index 449467ce..eceaaf17 100644 --- a/plugins/vst/cmake/Vst3.cmake +++ b/plugins/vst/cmake/Vst3.cmake @@ -36,7 +36,9 @@ function(plugin_add_vst3sdk NAME) "${VST3SDK_BASEDIR}/public.sdk/source/common/threadchecker_win32.cpp" "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstgui_win32_bundle_support.cpp" "${VST3SDK_BASEDIR}/public.sdk/source/main/dllmain.cpp") - set_property(TARGET "${NAME}" PROPERTY CXX_STANDARD 14) + if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 14) + set_property(TARGET "${NAME}" PROPERTY CXX_STANDARD 14) + endif() elseif(APPLE) target_sources("${NAME}" PRIVATE "${VST3SDK_BASEDIR}/public.sdk/source/main/macmain.cpp") From 0b27ef38458c4216fc3db92af48df5abadef8aaa Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 7 Mar 2021 18:12:33 +0100 Subject: [PATCH 369/668] Fix new MinGW problems after raising c++ standard --- plugins/vst/SfizzFileScan.cpp | 3 +++ plugins/vst/SfizzSettings.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/plugins/vst/SfizzFileScan.cpp b/plugins/vst/SfizzFileScan.cpp index 1dd313f6..f6ec9ee1 100644 --- a/plugins/vst/SfizzFileScan.cpp +++ b/plugins/vst/SfizzFileScan.cpp @@ -11,6 +11,9 @@ #include #include #include +#if defined(_WIN32) +#include +#endif // wait at least this much before refreshing the file rescan // it permits to not repeat the operation many times if many searches are diff --git a/plugins/vst/SfizzSettings.cpp b/plugins/vst/SfizzSettings.cpp index 9560d16d..b089cecf 100644 --- a/plugins/vst/SfizzSettings.cpp +++ b/plugins/vst/SfizzSettings.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "SfizzSettings.h" +#include #include std::string SfizzSettings::load_or(const char* key, absl::string_view defaultValue) From f1d4dfb823222e3500fd429d7082642007eb0793 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 7 Mar 2021 18:37:38 +0100 Subject: [PATCH 370/668] Fine tune the looping behavior --- src/sfizz/Voice.cpp | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index d3b04c2f..b3d86310 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -918,9 +918,13 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept // calculate loop characteristics const auto loop = this->loop_; + + // Looping logic const bool hasLoopSamples = static_cast(loop.end) < source.getNumFrames(); - const bool loopContinuous = hasLoopSamples && (region_->loopMode == LoopMode::loop_continuous); - const bool loopSustain = hasLoopSamples && (region_->loopMode == LoopMode::loop_sustain) && !released(); + const bool loopCountReached = region_->loopCount && loop_.restarts >= *region_->loopCount; + const bool loopContinuous = (region_->loopMode == LoopMode::loop_continuous); + const bool loopSustain = (region_->loopMode == LoopMode::loop_sustain) && !released(); + const bool shouldLoop = hasLoopSamples && (loopSustain || loopContinuous) && !loopCountReached; /* loop start loop end @@ -942,7 +946,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept enum PartitionType { kPartitionNormal, kPartitionLoopXfade }; SpanHolder> partitionBuffers[2]; - if (loopSustain || loopContinuous) { + if (shouldLoop) { for (auto& buf : partitionBuffers) { buf = resources_.bufferPool.getIndexBuffer(numSamples); if (!buf) @@ -986,23 +990,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept oldPartitionType = partitionType; }; - if (loopContinuous) { - for (unsigned i = 0; i < numSamples; ++i) { - int wrappedIndex = (*indices)[i] - loop.size * blockRestarts; - if (wrappedIndex > loop.end) { - wrappedIndex -= loop.size; - blockRestarts += 1; - loop_.restarts += 1; - } - (*indices)[i] = wrappedIndex; - const bool wrapped = wrappedIndex < oldIndex; - addPartitionIfNecessary(i, wrappedIndex, wrapped); - - // Release if we reached the loop count - if (wrapped && region_->loopCount && loop_.restarts >= *region_->loopCount && !released()) - release(i); - } - } else if (loopSustain) { + if (shouldLoop) { unsigned i = 0; while (i < numSamples) { int wrappedIndex = (*indices)[i] - loop.size * blockRestarts; @@ -1016,14 +1004,11 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept // identify the partition this index is in addPartitionIfNecessary(i, wrappedIndex, wrapped); - i++; - // Release if we reached the loop count and break - if (wrapped && region_->loopCount && loop_.restarts >= *region_->loopCount) { - release(i - 1); + // Break if we reached the loop count + if (wrapped && region_->loopCount && loop_.restarts >= *region_->loopCount) break; - } } while (i < numSamples) { // In case we released within the block, continue as if it were a one-shot @@ -1035,7 +1020,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept } i++; } - } else { // One shots and loop_sustain that have released or ended + } else { // One shots and loops that have released (for loop sustain) or ended (with loop counts) for (unsigned i = 0; i < numSamples; ++i) { (*indices)[i] -= sampleSize_ * blockRestarts; @@ -1048,7 +1033,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept } if (!released()) - release(i); + off(i, true); fill(indices->subspan(i), sampleEnd); fill(coeffs->subspan(i), 1.0f); From 89b09d298503b8d6fae06cc7ae5ca8c42177ca37 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Mon, 8 Mar 2021 16:24:12 +0100 Subject: [PATCH 371/668] Update src/sfizz/Voice.cpp --- src/sfizz/Voice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index b3d86310..e5fc2ddf 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1015,7 +1015,7 @@ void Voice::Impl::fillWithData(AudioSpan buffer) noexcept (*indices)[i] -= loop.size * blockRestarts; if ((*indices)[i] >= sampleEnd) { fill(indices->subspan(i), sampleEnd); - fill(coeffs->subspan(i), 1.0f); + fill(coeffs->subspan(i), 0x1.fffffep-1); break; } i++; From 3edf948949bc5958552191d9de6b7f86829aac5c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Mar 2021 16:43:45 +0100 Subject: [PATCH 372/668] Ensure to initialize the PlayState structure --- plugins/vst/SfizzVstProcessor.cpp | 2 +- plugins/vst/SfizzVstUpdates.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/vst/SfizzVstProcessor.cpp b/plugins/vst/SfizzVstProcessor.cpp index 3701d13f..93519ee6 100644 --- a/plugins/vst/SfizzVstProcessor.cpp +++ b/plugins/vst/SfizzVstProcessor.cpp @@ -281,7 +281,7 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) _playStateChangeCounter += numFrames; if (_playStateChangeCounter > _playStateChangePeriod) { _playStateChangeCounter %= _playStateChangePeriod; - SfizzPlayState playState; + SfizzPlayState playState {}; playState.curves = synth.getNumCurves(); playState.masters = synth.getNumMasters(); playState.groups = synth.getNumGroups(); diff --git a/plugins/vst/SfizzVstUpdates.h b/plugins/vst/SfizzVstUpdates.h index 0fbd8d3a..145e39df 100644 --- a/plugins/vst/SfizzVstUpdates.h +++ b/plugins/vst/SfizzVstUpdates.h @@ -158,6 +158,6 @@ public: OBJ_METHODS(PlayStateUpdate, FObject) private: - SfizzPlayState state_; + SfizzPlayState state_ {}; mutable std::mutex mutex_; }; From d9e230c7e6f36258c417970e23f6e86a95e9c472 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 8 Mar 2021 18:05:29 +0100 Subject: [PATCH 373/668] Deduplicate LFO code in core/fx --- src/CMakeLists.txt | 4 +-- src/sfizz/Defaults.cpp | 2 +- src/sfizz/Defaults.h | 15 ++-------- .../{effects/CommonLFO.h => LFOCommon.h} | 29 ++++++++++--------- .../{effects/CommonLFO.hpp => LFOCommon.hpp} | 20 ++++++------- src/sfizz/effects/Apan.cpp | 24 +++++++-------- src/sfizz/effects/Apan.h | 4 +-- 7 files changed, 43 insertions(+), 55 deletions(-) rename src/sfizz/{effects/CommonLFO.h => LFOCommon.h} (59%) rename src/sfizz/{effects/CommonLFO.hpp => LFOCommon.hpp} (70%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7be3fd64..709c6990 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,8 +44,6 @@ set(SFIZZ_HEADERS sfizz/effects/impl/ResonantStringAVX.h sfizz/effects/impl/ResonantStringSSE.h sfizz/effects/Apan.h - sfizz/effects/CommonLFO.h - sfizz/effects/CommonLFO.hpp sfizz/effects/Compressor.h sfizz/effects/Disto.h sfizz/effects/Eq.h @@ -75,6 +73,8 @@ set(SFIZZ_HEADERS sfizz/Interpolators.hpp sfizz/Logger.h sfizz/LFO.h + sfizz/LFOCommon.h + sfizz/LFOCommon.hpp sfizz/LFODescription.h sfizz/MathHelpers.h sfizz/Metronome.h diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 792983ff..2efac0e3 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -132,7 +132,7 @@ extern const OpcodeSpec octaveOffset { 0, Range(-10, 10), 0 }; extern const OpcodeSpec noteOffset { 0, Range(-127, 127), 0 }; extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; extern const OpcodeSpec effectPercent { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec apanWaveform { 0, Range(0, std::numeric_limits::max()), 0 }; +extern const OpcodeSpec apanWaveform { LFOWave::Triangle, Range(LFOWave::Triangle, LFOWave::Saw), 0 }; extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), 0 }; extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), kWrapPhase }; extern const OpcodeSpec apanLevel { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index f778e09e..7252a1e9 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -31,6 +31,7 @@ #include "Config.h" #include "SfzFilter.h" #include "SfzHelpers.h" +#include "LFOCommon.h" #include "MathHelpers.h" @@ -44,18 +45,6 @@ enum class VelocityOverride { current = 0, previous }; enum class CrossfadeCurve { gain = 0, power }; enum class SelfMask { mask = 0, dontMask }; enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; -enum class LFOWave : int { - Triangle, - Sine, - Pulse75, - Square, - Pulse25, - Pulse12_5, - Ramp, - Saw, - // ARIA extra - RandomSH = 12, -}; enum OpcodeFlags : int { kCanBeNote = 1, @@ -251,7 +240,7 @@ namespace Default extern const OpcodeSpec noteOffset; extern const OpcodeSpec effect; extern const OpcodeSpec effectPercent; - extern const OpcodeSpec apanWaveform; + extern const OpcodeSpec apanWaveform; extern const OpcodeSpec apanFrequency; extern const OpcodeSpec apanPhase; extern const OpcodeSpec apanLevel; diff --git a/src/sfizz/effects/CommonLFO.h b/src/sfizz/LFOCommon.h similarity index 59% rename from src/sfizz/effects/CommonLFO.h rename to src/sfizz/LFOCommon.h index 3129e1c5..a6d915c6 100644 --- a/src/sfizz/effects/CommonLFO.h +++ b/src/sfizz/LFOCommon.h @@ -7,24 +7,25 @@ #pragma once namespace sfz { -namespace fx { -namespace lfo { -enum Wave { - kTriangle, - kSine, - kPulse75, - kSquare, - kPulse25, - kPulse12_5, - kRamp, - kSaw, +enum class LFOWave : int { + Triangle, + Sine, + Pulse75, + Square, + Pulse25, + Pulse12_5, + Ramp, + Saw, + // ARIA extra + RandomSH = 12, }; -template float evaluateAtPhase(float phase); +namespace lfo { + +template float evaluateAtPhase(float phase); } // namespace lfo -} // namespace fx } // namespace sfz -#include "CommonLFO.hpp" +#include "LFOCommon.hpp" diff --git a/src/sfizz/effects/CommonLFO.hpp b/src/sfizz/LFOCommon.hpp similarity index 70% rename from src/sfizz/effects/CommonLFO.hpp rename to src/sfizz/LFOCommon.hpp index d43c0e88..2a5daa45 100644 --- a/src/sfizz/effects/CommonLFO.hpp +++ b/src/sfizz/LFOCommon.hpp @@ -4,11 +4,10 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "CommonLFO.h" +#include "LFOCommon.h" #include namespace sfz { -namespace fx { namespace lfo { // Pulse and Square levels @@ -16,7 +15,7 @@ namespace lfo { static constexpr float hiPulse = 1.0f; template <> - inline float evaluateAtPhase(float phase) + inline float evaluateAtPhase(float phase) { float y = -4 * phase + 2; y = (phase < 0.25f) ? (4 * phase) : y; @@ -25,48 +24,47 @@ namespace lfo { } template <> - inline float evaluateAtPhase(float phase) + inline float evaluateAtPhase(float phase) { float x = phase + phase - 1; return -4 * x * (1 - std::fabs(x)); } template <> - inline float evaluateAtPhase(float phase) + inline float evaluateAtPhase(float phase) { return (phase < 0.75f) ? hiPulse : loPulse; } template <> - inline float evaluateAtPhase(float phase) + inline float evaluateAtPhase(float phase) { return (phase < 0.5f) ? hiPulse : loPulse; } template <> - inline float evaluateAtPhase(float phase) + inline float evaluateAtPhase(float phase) { return (phase < 0.25f) ? hiPulse : loPulse; } template <> - inline float evaluateAtPhase(float phase) + inline float evaluateAtPhase(float phase) { return (phase < 0.125f) ? hiPulse : loPulse; } template <> - inline float evaluateAtPhase(float phase) + inline float evaluateAtPhase(float phase) { return 2 * phase - 1; } template <> - inline float evaluateAtPhase(float phase) + inline float evaluateAtPhase(float phase) { return 1 - 2 * phase; } } // namespace lfo -} // namespace fx } // namespace sfz diff --git a/src/sfizz/effects/Apan.cpp b/src/sfizz/effects/Apan.cpp index d100361f..92dbb22e 100644 --- a/src/sfizz/effects/Apan.cpp +++ b/src/sfizz/effects/Apan.cpp @@ -22,7 +22,7 @@ #include "Apan.h" #include "Macros.h" -#include "CommonLFO.h" +#include "LFOCommon.h" #include "Opcode.h" #include #include @@ -107,22 +107,22 @@ namespace fx { void Apan::computeLfos(float* left, float* right, unsigned nframes) { switch (_lfoWave) { - #define CASE(X) case lfo::X: \ - computeLfos(left, right, nframes); break; + #define CASE(X) case X: \ + computeLfos(left, right, nframes); break; default: - CASE(kTriangle) - CASE(kSine) - CASE(kPulse75) - CASE(kSquare) - CASE(kPulse25) - CASE(kPulse12_5) - CASE(kRamp) - CASE(kSaw) + CASE(LFOWave::Triangle) + CASE(LFOWave::Sine) + CASE(LFOWave::Pulse75) + CASE(LFOWave::Square) + CASE(LFOWave::Pulse25) + CASE(LFOWave::Pulse12_5) + CASE(LFOWave::Ramp) + CASE(LFOWave::Saw) #undef CASE } } - template void Apan::computeLfos(float* left, float* right, unsigned nframes) + template void Apan::computeLfos(float* left, float* right, unsigned nframes) { float samplePeriod = _samplePeriod; float frequency = _lfoFrequency; diff --git a/src/sfizz/effects/Apan.h b/src/sfizz/effects/Apan.h index 9e30c144..43f0127c 100644 --- a/src/sfizz/effects/Apan.h +++ b/src/sfizz/effects/Apan.h @@ -44,7 +44,7 @@ namespace fx { private: void computeLfos(float* left, float* right, unsigned nframes); - template void computeLfos(float* left, float* right, unsigned nframes); + template void computeLfos(float* left, float* right, unsigned nframes); private: float _samplePeriod { 0.0f }; @@ -55,7 +55,7 @@ namespace fx { float _dry { Default::apanLevel }; float _wet { Default::apanLevel }; float _depth { Default::apanLevel }; - int _lfoWave { Default::apanWaveform }; + LFOWave _lfoWave { Default::apanWaveform }; float _lfoFrequency { Default::apanFrequency }; float _lfoPhaseOffset { Default::apanPhase }; From c23d9b5f5bad67619fdf529efc00b48c55f81da2 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 9 Mar 2021 10:00:13 +0100 Subject: [PATCH 374/668] Update the sample rate of Flex EG --- src/sfizz/Voice.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 20e84be0..33d2d5eb 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -551,6 +551,9 @@ void Voice::setSampleRate(float sampleRate) noexcept for (WavetableOscillator& osc : impl.waveOscillators_) osc.init(sampleRate); + for (auto& eg : impl.flexEGs_) + eg->setSampleRate(sampleRate); + for (auto& lfo : impl.lfos_) lfo->setSampleRate(sampleRate); From eef101766e3ce6e0243a785bd38cbdaf2657c55c Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 9 Mar 2021 19:12:44 +0100 Subject: [PATCH 375/668] Update vstgui for file dialog filters --- plugins/editor/external/vstgui4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/editor/external/vstgui4 b/plugins/editor/external/vstgui4 index 289f8717..f4fe0d0b 160000 --- a/plugins/editor/external/vstgui4 +++ b/plugins/editor/external/vstgui4 @@ -1 +1 @@ -Subproject commit 289f8717e6c7653397d4a099fe7c1a2ded42eb44 +Subproject commit f4fe0d0b1e53443342ba732a0e715ce5c96b49df From ec85b2e16917d2638c91a1198c396f30277e197f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 10 Mar 2021 09:37:10 +0100 Subject: [PATCH 376/668] Add feature check for MinGW dwrite3 support --- plugins/editor/cmake/Vstgui.cmake | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/plugins/editor/cmake/Vstgui.cmake b/plugins/editor/cmake/Vstgui.cmake index 51d1c26f..32380b81 100644 --- a/plugins/editor/cmake/Vstgui.cmake +++ b/plugins/editor/cmake/Vstgui.cmake @@ -213,9 +213,23 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") endif() # Windows 10 RS2 DDI for custom fonts target_compile_definitions(sfizz_vstgui PRIVATE "NTDDI_VERSION=0x0A000003") - # disable custom fonts while dwrite3 API is unavailable in MinGW + # disable custom fonts if dwrite3 API is unavailable in MinGW if(MINGW) - target_compile_definitions(sfizz_vstgui PRIVATE "VSTGUI_WIN32_CUSTOMFONT_SUPPORT=0") + check_cxx_source_compiles(" +#include +#include +HRESULT FeatureCheck(IDWriteFontSet* self, const WCHAR* name, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontSet** fontset) +{ + return self->GetMatchingFonts(name, weight, stretch, style, fontset); +} +int main() +{ + return 0; +}" SFIZZ_MINGW_SUPPORTS_DWRITE3) + if(NOT SFIZZ_MINGW_SUPPORTS_DWRITE3) + message(WARNING "This version of MinGW does not support DirectWrite 3. Custom font support is disabled.") + target_compile_definitions(sfizz_vstgui PRIVATE "VSTGUI_WIN32_CUSTOMFONT_SUPPORT=0") + endif() endif() endif() From 5a6a1bbfcd8059c49d04545145a78787a089914f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 10 Mar 2021 10:18:11 +0100 Subject: [PATCH 377/668] Workaround for MinGW CI to build custom font support --- .github/workflows/build.yml | 10 + scripts/mingw_dwrite_3.h | 12280 ++++++++++++++++++++++++++++++++++ 2 files changed, 12290 insertions(+) create mode 100644 scripts/mingw_dwrite_3.h diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 716e3b67..cfd21976 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,6 +161,11 @@ jobs: - uses: actions/checkout@v2 with: submodules: recursive + - name: Fix MinGW headers + shell: bash + run: | + cp -vf "$GITHUB_WORKSPACE"/scripts/mingw_dwrite_3.h \ + /usr/i686-w64-mingw32/include/dwrite_3.h - name: Fix VST sources shell: bash # need to convert some includes to lower case (as of VST 3.7.1) @@ -225,6 +230,11 @@ jobs: - uses: actions/checkout@v2 with: submodules: recursive + - name: Fix MinGW headers + shell: bash + run: | + cp -vf "$GITHUB_WORKSPACE"/scripts/mingw_dwrite_3.h \ + /usr/x86_64-w64-mingw32/include/dwrite_3.h - name: Fix VST sources shell: bash # need to convert some includes to lower case (as of VST 3.7.1) diff --git a/scripts/mingw_dwrite_3.h b/scripts/mingw_dwrite_3.h new file mode 100644 index 00000000..d8e109b4 --- /dev/null +++ b/scripts/mingw_dwrite_3.h @@ -0,0 +1,12280 @@ +/* A substitution header for MinGW-w64 8.0.0, manually edited, + which allows to build Vstgui custom font support. */ + +/*** Autogenerated by WIDL 5.16 from include/dwrite_3.idl - Do not edit ***/ + +#ifdef _WIN32 +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif +#include +#include +#endif + +#ifndef COM_NO_WINDOWS_H +#include +#include +#endif + +#ifndef __dwrite_3_h__ +#define __dwrite_3_h__ + +/* Forward declarations */ + +#ifndef __IDWriteFontDownloadListener_FWD_DEFINED__ +#define __IDWriteFontDownloadListener_FWD_DEFINED__ +typedef interface IDWriteFontDownloadListener IDWriteFontDownloadListener; +#ifdef __cplusplus +interface IDWriteFontDownloadListener; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontDownloadQueue_FWD_DEFINED__ +#define __IDWriteFontDownloadQueue_FWD_DEFINED__ +typedef interface IDWriteFontDownloadQueue IDWriteFontDownloadQueue; +#ifdef __cplusplus +interface IDWriteFontDownloadQueue; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteRenderingParams3_FWD_DEFINED__ +#define __IDWriteRenderingParams3_FWD_DEFINED__ +typedef interface IDWriteRenderingParams3 IDWriteRenderingParams3; +#ifdef __cplusplus +interface IDWriteRenderingParams3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteStringList_FWD_DEFINED__ +#define __IDWriteStringList_FWD_DEFINED__ +typedef interface IDWriteStringList IDWriteStringList; +#ifdef __cplusplus +interface IDWriteStringList; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontSet_FWD_DEFINED__ +#define __IDWriteFontSet_FWD_DEFINED__ +typedef interface IDWriteFontSet IDWriteFontSet; +#ifdef __cplusplus +interface IDWriteFontSet; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontResource_FWD_DEFINED__ +#define __IDWriteFontResource_FWD_DEFINED__ +typedef interface IDWriteFontResource IDWriteFontResource; +#ifdef __cplusplus +interface IDWriteFontResource; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontSet1_FWD_DEFINED__ +#define __IDWriteFontSet1_FWD_DEFINED__ +typedef interface IDWriteFontSet1 IDWriteFontSet1; +#ifdef __cplusplus +interface IDWriteFontSet1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFont3_FWD_DEFINED__ +#define __IDWriteFont3_FWD_DEFINED__ +typedef interface IDWriteFont3 IDWriteFont3; +#ifdef __cplusplus +interface IDWriteFont3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFamily1_FWD_DEFINED__ +#define __IDWriteFontFamily1_FWD_DEFINED__ +typedef interface IDWriteFontFamily1 IDWriteFontFamily1; +#ifdef __cplusplus +interface IDWriteFontFamily1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFamily2_FWD_DEFINED__ +#define __IDWriteFontFamily2_FWD_DEFINED__ +typedef interface IDWriteFontFamily2 IDWriteFontFamily2; +#ifdef __cplusplus +interface IDWriteFontFamily2; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontCollection1_FWD_DEFINED__ +#define __IDWriteFontCollection1_FWD_DEFINED__ +typedef interface IDWriteFontCollection1 IDWriteFontCollection1; +#ifdef __cplusplus +interface IDWriteFontCollection1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontCollection2_FWD_DEFINED__ +#define __IDWriteFontCollection2_FWD_DEFINED__ +typedef interface IDWriteFontCollection2 IDWriteFontCollection2; +#ifdef __cplusplus +interface IDWriteFontCollection2; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontCollection3_FWD_DEFINED__ +#define __IDWriteFontCollection3_FWD_DEFINED__ +typedef interface IDWriteFontCollection3 IDWriteFontCollection3; +#ifdef __cplusplus +interface IDWriteFontCollection3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFaceReference_FWD_DEFINED__ +#define __IDWriteFontFaceReference_FWD_DEFINED__ +typedef interface IDWriteFontFaceReference IDWriteFontFaceReference; +#ifdef __cplusplus +interface IDWriteFontFaceReference; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFaceReference1_FWD_DEFINED__ +#define __IDWriteFontFaceReference1_FWD_DEFINED__ +typedef interface IDWriteFontFaceReference1 IDWriteFontFaceReference1; +#ifdef __cplusplus +interface IDWriteFontFaceReference1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontList1_FWD_DEFINED__ +#define __IDWriteFontList1_FWD_DEFINED__ +typedef interface IDWriteFontList1 IDWriteFontList1; +#ifdef __cplusplus +interface IDWriteFontList1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontList2_FWD_DEFINED__ +#define __IDWriteFontList2_FWD_DEFINED__ +typedef interface IDWriteFontList2 IDWriteFontList2; +#ifdef __cplusplus +interface IDWriteFontList2; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontSet2_FWD_DEFINED__ +#define __IDWriteFontSet2_FWD_DEFINED__ +typedef interface IDWriteFontSet2 IDWriteFontSet2; +#ifdef __cplusplus +interface IDWriteFontSet2; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontSet3_FWD_DEFINED__ +#define __IDWriteFontSet3_FWD_DEFINED__ +typedef interface IDWriteFontSet3 IDWriteFontSet3; +#ifdef __cplusplus +interface IDWriteFontSet3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFace3_FWD_DEFINED__ +#define __IDWriteFontFace3_FWD_DEFINED__ +typedef interface IDWriteFontFace3 IDWriteFontFace3; +#ifdef __cplusplus +interface IDWriteFontFace3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteTextFormat2_FWD_DEFINED__ +#define __IDWriteTextFormat2_FWD_DEFINED__ +typedef interface IDWriteTextFormat2 IDWriteTextFormat2; +#ifdef __cplusplus +interface IDWriteTextFormat2; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteTextFormat3_FWD_DEFINED__ +#define __IDWriteTextFormat3_FWD_DEFINED__ +typedef interface IDWriteTextFormat3 IDWriteTextFormat3; +#ifdef __cplusplus +interface IDWriteTextFormat3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteTextLayout3_FWD_DEFINED__ +#define __IDWriteTextLayout3_FWD_DEFINED__ +typedef interface IDWriteTextLayout3 IDWriteTextLayout3; +#ifdef __cplusplus +interface IDWriteTextLayout3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteTextLayout4_FWD_DEFINED__ +#define __IDWriteTextLayout4_FWD_DEFINED__ +typedef interface IDWriteTextLayout4 IDWriteTextLayout4; +#ifdef __cplusplus +interface IDWriteTextLayout4; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFallback1_FWD_DEFINED__ +#define __IDWriteFontFallback1_FWD_DEFINED__ +typedef interface IDWriteFontFallback1 IDWriteFontFallback1; +#ifdef __cplusplus +interface IDWriteFontFallback1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteGdiInterop1_FWD_DEFINED__ +#define __IDWriteGdiInterop1_FWD_DEFINED__ +typedef interface IDWriteGdiInterop1 IDWriteGdiInterop1; +#ifdef __cplusplus +interface IDWriteGdiInterop1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontSetBuilder_FWD_DEFINED__ +#define __IDWriteFontSetBuilder_FWD_DEFINED__ +typedef interface IDWriteFontSetBuilder IDWriteFontSetBuilder; +#ifdef __cplusplus +interface IDWriteFontSetBuilder; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontSetBuilder1_FWD_DEFINED__ +#define __IDWriteFontSetBuilder1_FWD_DEFINED__ +typedef interface IDWriteFontSetBuilder1 IDWriteFontSetBuilder1; +#ifdef __cplusplus +interface IDWriteFontSetBuilder1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontSetBuilder2_FWD_DEFINED__ +#define __IDWriteFontSetBuilder2_FWD_DEFINED__ +typedef interface IDWriteFontSetBuilder2 IDWriteFontSetBuilder2; +#ifdef __cplusplus +interface IDWriteFontSetBuilder2; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFactory3_FWD_DEFINED__ +#define __IDWriteFactory3_FWD_DEFINED__ +typedef interface IDWriteFactory3 IDWriteFactory3; +#ifdef __cplusplus +interface IDWriteFactory3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFace4_FWD_DEFINED__ +#define __IDWriteFontFace4_FWD_DEFINED__ +typedef interface IDWriteFontFace4 IDWriteFontFace4; +#ifdef __cplusplus +interface IDWriteFontFace4; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFace5_FWD_DEFINED__ +#define __IDWriteFontFace5_FWD_DEFINED__ +typedef interface IDWriteFontFace5 IDWriteFontFace5; +#ifdef __cplusplus +interface IDWriteFontFace5; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteColorGlyphRunEnumerator1_FWD_DEFINED__ +#define __IDWriteColorGlyphRunEnumerator1_FWD_DEFINED__ +typedef interface IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1; +#ifdef __cplusplus +interface IDWriteColorGlyphRunEnumerator1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFactory4_FWD_DEFINED__ +#define __IDWriteFactory4_FWD_DEFINED__ +typedef interface IDWriteFactory4 IDWriteFactory4; +#ifdef __cplusplus +interface IDWriteFactory4; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteAsyncResult_FWD_DEFINED__ +#define __IDWriteAsyncResult_FWD_DEFINED__ +typedef interface IDWriteAsyncResult IDWriteAsyncResult; +#ifdef __cplusplus +interface IDWriteAsyncResult; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteRemoteFontFileStream_FWD_DEFINED__ +#define __IDWriteRemoteFontFileStream_FWD_DEFINED__ +typedef interface IDWriteRemoteFontFileStream IDWriteRemoteFontFileStream; +#ifdef __cplusplus +interface IDWriteRemoteFontFileStream; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteRemoteFontFileLoader_FWD_DEFINED__ +#define __IDWriteRemoteFontFileLoader_FWD_DEFINED__ +typedef interface IDWriteRemoteFontFileLoader IDWriteRemoteFontFileLoader; +#ifdef __cplusplus +interface IDWriteRemoteFontFileLoader; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteInMemoryFontFileLoader_FWD_DEFINED__ +#define __IDWriteInMemoryFontFileLoader_FWD_DEFINED__ +typedef interface IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader; +#ifdef __cplusplus +interface IDWriteInMemoryFontFileLoader; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFactory5_FWD_DEFINED__ +#define __IDWriteFactory5_FWD_DEFINED__ +typedef interface IDWriteFactory5 IDWriteFactory5; +#ifdef __cplusplus +interface IDWriteFactory5; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFactory6_FWD_DEFINED__ +#define __IDWriteFactory6_FWD_DEFINED__ +typedef interface IDWriteFactory6 IDWriteFactory6; +#ifdef __cplusplus +interface IDWriteFactory6; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFactory7_FWD_DEFINED__ +#define __IDWriteFactory7_FWD_DEFINED__ +typedef interface IDWriteFactory7 IDWriteFactory7; +#ifdef __cplusplus +interface IDWriteFactory7; +#endif /* __cplusplus */ +#endif + +/* Headers for imported files */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __IDWriteFontFaceReference_FWD_DEFINED__ +#define __IDWriteFontFaceReference_FWD_DEFINED__ +typedef interface IDWriteFontFaceReference IDWriteFontFaceReference; +#ifdef __cplusplus +interface IDWriteFontFaceReference; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFaceReference1_FWD_DEFINED__ +#define __IDWriteFontFaceReference1_FWD_DEFINED__ +typedef interface IDWriteFontFaceReference1 IDWriteFontFaceReference1; +#ifdef __cplusplus +interface IDWriteFontFaceReference1; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFace3_FWD_DEFINED__ +#define __IDWriteFontFace3_FWD_DEFINED__ +typedef interface IDWriteFontFace3 IDWriteFontFace3; +#ifdef __cplusplus +interface IDWriteFontFace3; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontSet_FWD_DEFINED__ +#define __IDWriteFontSet_FWD_DEFINED__ +typedef interface IDWriteFontSet IDWriteFontSet; +#ifdef __cplusplus +interface IDWriteFontSet; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontDownloadQueue_FWD_DEFINED__ +#define __IDWriteFontDownloadQueue_FWD_DEFINED__ +typedef interface IDWriteFontDownloadQueue IDWriteFontDownloadQueue; +#ifdef __cplusplus +interface IDWriteFontDownloadQueue; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontFace5_FWD_DEFINED__ +#define __IDWriteFontFace5_FWD_DEFINED__ +typedef interface IDWriteFontFace5 IDWriteFontFace5; +#ifdef __cplusplus +interface IDWriteFontFace5; +#endif /* __cplusplus */ +#endif + +#ifndef __IDWriteFontList2_FWD_DEFINED__ +#define __IDWriteFontList2_FWD_DEFINED__ +typedef interface IDWriteFontList2 IDWriteFontList2; +#ifdef __cplusplus +interface IDWriteFontList2; +#endif /* __cplusplus */ +#endif + +#ifndef _WINGDI_ +typedef struct FONTSIGNATURE FONTSIGNATURE; +#endif /* _WINGDI_ */ +typedef enum DWRITE_LOCALITY { + DWRITE_LOCALITY_REMOTE = 0, + DWRITE_LOCALITY_PARTIAL = 1, + DWRITE_LOCALITY_LOCAL = 2 +} DWRITE_LOCALITY; +typedef enum DWRITE_RENDERING_MODE1 { + DWRITE_RENDERING_MODE1_DEFAULT = 0, + DWRITE_RENDERING_MODE1_ALIASED = 1, + DWRITE_RENDERING_MODE1_GDI_CLASSIC = 2, + DWRITE_RENDERING_MODE1_GDI_NATURAL = 3, + DWRITE_RENDERING_MODE1_NATURAL = 4, + DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC = 5, + DWRITE_RENDERING_MODE1_OUTLINE = 6, + DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED = 7 +} DWRITE_RENDERING_MODE1; +typedef enum DWRITE_FONT_PROPERTY_ID { + DWRITE_FONT_PROPERTY_ID_NONE = 0, + DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME = 1, + DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME = 2, + DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME = 3, + DWRITE_FONT_PROPERTY_ID_FULL_NAME = 4, + DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME = 5, + DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME = 6, + DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG = 7, + DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG = 8, + DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG = 9, + DWRITE_FONT_PROPERTY_ID_WEIGHT = 10, + DWRITE_FONT_PROPERTY_ID_STRETCH = 11, + DWRITE_FONT_PROPERTY_ID_STYLE = 12, + DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME = 13, + DWRITE_FONT_PROPERTY_ID_TOTAL = DWRITE_FONT_PROPERTY_ID_STYLE + 1, + DWRITE_FONT_PROPERTY_ID_TOTAL_RS3 = DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME + 1, + DWRITE_FONT_PROPERTY_ID_FAMILY_NAME = DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME, + DWRITE_FONT_PROPERTY_ID_PREFERRED_FAMILY_NAME = DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME, + DWRITE_FONT_PROPERTY_ID_FACE_NAME = DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME +} DWRITE_FONT_PROPERTY_ID; +typedef struct DWRITE_FONT_PROPERTY { + DWRITE_FONT_PROPERTY_ID propertyId; + const WCHAR *propertyValue; + const WCHAR *localeName; +} DWRITE_FONT_PROPERTY; +typedef enum DWRITE_FONT_AXIS_TAG { + DWRITE_FONT_AXIS_TAG_WEIGHT = 0x74686777, + DWRITE_FONT_AXIS_TAG_WIDTH = 0x68746477, + DWRITE_FONT_AXIS_TAG_SLANT = 0x746e6c73, + DWRITE_FONT_AXIS_TAG_OPTICAL_SIZE = 0x7a73706f, + DWRITE_FONT_AXIS_TAG_ITALIC = 0x6c617469 +} DWRITE_FONT_AXIS_TAG; +typedef enum DWRITE_FONT_SOURCE_TYPE { + DWRITE_FONT_SOURCE_TYPE_UNKNOWN = 0, + DWRITE_FONT_SOURCE_TYPE_PER_MACHINE = 1, + DWRITE_FONT_SOURCE_TYPE_PER_USER = 2, + DWRITE_FONT_SOURCE_TYPE_APPX_PACKAGE = 3, + DWRITE_FONT_SOURCE_TYPE_REMOTE_FONT_PROVIDER = 4 +} DWRITE_FONT_SOURCE_TYPE; +typedef struct DWRITE_FONT_AXIS_VALUE { + DWRITE_FONT_AXIS_TAG axisTag; + FLOAT value; +} DWRITE_FONT_AXIS_VALUE; +typedef struct DWRITE_FONT_AXIS_RANGE { + DWRITE_FONT_AXIS_TAG axisTag; + FLOAT minValue; + FLOAT maxValue; +} DWRITE_FONT_AXIS_RANGE; +typedef enum DWRITE_AUTOMATIC_FONT_AXES { + DWRITE_AUTOMATIC_FONT_AXES_NONE = 0, + DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE = 1 +} DWRITE_AUTOMATIC_FONT_AXES; +typedef enum DWRITE_FONT_AXIS_ATTRIBUTES { + DWRITE_FONT_AXIS_ATTRIBUTES_NONE = 0, + DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE = 1, + DWRITE_FONT_AXIS_ATTRIBUTES_HIDDEN = 2 +} DWRITE_FONT_AXIS_ATTRIBUTES; +typedef enum DWRITE_FONT_FAMILY_MODEL { + DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC = 0, + DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE = 1 +} DWRITE_FONT_FAMILY_MODEL; +/***************************************************************************** + * IDWriteFontDownloadListener interface + */ +#ifndef __IDWriteFontDownloadListener_INTERFACE_DEFINED__ +#define __IDWriteFontDownloadListener_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontDownloadListener, 0xb06fe5b9, 0x43ec, 0x4393, 0x88,0x1b, 0xdb,0xe4,0xdc,0x72,0xfd,0xa7); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("b06fe5b9-43ec-4393-881b-dbe4dc72fda7") +IDWriteFontDownloadListener : public IUnknown +{ + virtual void STDMETHODCALLTYPE DownloadCompleted( + IDWriteFontDownloadQueue *queue, + IUnknown *context, + HRESULT result) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontDownloadListener, 0xb06fe5b9, 0x43ec, 0x4393, 0x88,0x1b, 0xdb,0xe4,0xdc,0x72,0xfd,0xa7) +#endif +#else +typedef struct IDWriteFontDownloadListenerVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontDownloadListener *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontDownloadListener *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontDownloadListener *This); + + /*** IDWriteFontDownloadListener methods ***/ + void (STDMETHODCALLTYPE *DownloadCompleted)( + IDWriteFontDownloadListener *This, + IDWriteFontDownloadQueue *queue, + IUnknown *context, + HRESULT result); + + END_INTERFACE +} IDWriteFontDownloadListenerVtbl; + +interface IDWriteFontDownloadListener { + CONST_VTBL IDWriteFontDownloadListenerVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontDownloadListener_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontDownloadListener_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontDownloadListener_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontDownloadListener methods ***/ +#define IDWriteFontDownloadListener_DownloadCompleted(This,queue,context,result) (This)->lpVtbl->DownloadCompleted(This,queue,context,result) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontDownloadListener_QueryInterface(IDWriteFontDownloadListener* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontDownloadListener_AddRef(IDWriteFontDownloadListener* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontDownloadListener_Release(IDWriteFontDownloadListener* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontDownloadListener methods ***/ +static FORCEINLINE void IDWriteFontDownloadListener_DownloadCompleted(IDWriteFontDownloadListener* This,IDWriteFontDownloadQueue *queue,IUnknown *context,HRESULT result) { + This->lpVtbl->DownloadCompleted(This,queue,context,result); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontDownloadListener_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontDownloadQueue interface + */ +#ifndef __IDWriteFontDownloadQueue_INTERFACE_DEFINED__ +#define __IDWriteFontDownloadQueue_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontDownloadQueue, 0xb71e6052, 0x5aea, 0x4fa3, 0x83,0x2e, 0xf6,0x0d,0x43,0x1f,0x7e,0x91); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("b71e6052-5aea-4fa3-832e-f60d431f7e91") +IDWriteFontDownloadQueue : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE AddListener( + IDWriteFontDownloadListener *listener, + UINT32 *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE RemoveListener( + UINT32 token) = 0; + + virtual WINBOOL STDMETHODCALLTYPE IsEmpty( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginDownload( + IUnknown *context) = 0; + + virtual HRESULT STDMETHODCALLTYPE CancelDownload( + ) = 0; + + virtual UINT64 STDMETHODCALLTYPE GetGenerationCount( + ) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontDownloadQueue, 0xb71e6052, 0x5aea, 0x4fa3, 0x83,0x2e, 0xf6,0x0d,0x43,0x1f,0x7e,0x91) +#endif +#else +typedef struct IDWriteFontDownloadQueueVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontDownloadQueue *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontDownloadQueue *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontDownloadQueue *This); + + /*** IDWriteFontDownloadQueue methods ***/ + HRESULT (STDMETHODCALLTYPE *AddListener)( + IDWriteFontDownloadQueue *This, + IDWriteFontDownloadListener *listener, + UINT32 *token); + + HRESULT (STDMETHODCALLTYPE *RemoveListener)( + IDWriteFontDownloadQueue *This, + UINT32 token); + + WINBOOL (STDMETHODCALLTYPE *IsEmpty)( + IDWriteFontDownloadQueue *This); + + HRESULT (STDMETHODCALLTYPE *BeginDownload)( + IDWriteFontDownloadQueue *This, + IUnknown *context); + + HRESULT (STDMETHODCALLTYPE *CancelDownload)( + IDWriteFontDownloadQueue *This); + + UINT64 (STDMETHODCALLTYPE *GetGenerationCount)( + IDWriteFontDownloadQueue *This); + + END_INTERFACE +} IDWriteFontDownloadQueueVtbl; + +interface IDWriteFontDownloadQueue { + CONST_VTBL IDWriteFontDownloadQueueVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontDownloadQueue_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontDownloadQueue_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontDownloadQueue_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontDownloadQueue methods ***/ +#define IDWriteFontDownloadQueue_AddListener(This,listener,token) (This)->lpVtbl->AddListener(This,listener,token) +#define IDWriteFontDownloadQueue_RemoveListener(This,token) (This)->lpVtbl->RemoveListener(This,token) +#define IDWriteFontDownloadQueue_IsEmpty(This) (This)->lpVtbl->IsEmpty(This) +#define IDWriteFontDownloadQueue_BeginDownload(This,context) (This)->lpVtbl->BeginDownload(This,context) +#define IDWriteFontDownloadQueue_CancelDownload(This) (This)->lpVtbl->CancelDownload(This) +#define IDWriteFontDownloadQueue_GetGenerationCount(This) (This)->lpVtbl->GetGenerationCount(This) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontDownloadQueue_QueryInterface(IDWriteFontDownloadQueue* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontDownloadQueue_AddRef(IDWriteFontDownloadQueue* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontDownloadQueue_Release(IDWriteFontDownloadQueue* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontDownloadQueue methods ***/ +static FORCEINLINE HRESULT IDWriteFontDownloadQueue_AddListener(IDWriteFontDownloadQueue* This,IDWriteFontDownloadListener *listener,UINT32 *token) { + return This->lpVtbl->AddListener(This,listener,token); +} +static FORCEINLINE HRESULT IDWriteFontDownloadQueue_RemoveListener(IDWriteFontDownloadQueue* This,UINT32 token) { + return This->lpVtbl->RemoveListener(This,token); +} +static FORCEINLINE WINBOOL IDWriteFontDownloadQueue_IsEmpty(IDWriteFontDownloadQueue* This) { + return This->lpVtbl->IsEmpty(This); +} +static FORCEINLINE HRESULT IDWriteFontDownloadQueue_BeginDownload(IDWriteFontDownloadQueue* This,IUnknown *context) { + return This->lpVtbl->BeginDownload(This,context); +} +static FORCEINLINE HRESULT IDWriteFontDownloadQueue_CancelDownload(IDWriteFontDownloadQueue* This) { + return This->lpVtbl->CancelDownload(This); +} +static FORCEINLINE UINT64 IDWriteFontDownloadQueue_GetGenerationCount(IDWriteFontDownloadQueue* This) { + return This->lpVtbl->GetGenerationCount(This); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontDownloadQueue_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteRenderingParams3 interface + */ +#ifndef __IDWriteRenderingParams3_INTERFACE_DEFINED__ +#define __IDWriteRenderingParams3_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteRenderingParams3, 0xb7924baa, 0x391b, 0x412a, 0x8c,0x5c, 0xe4,0x4c,0xc2,0xd8,0x67,0xdc); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("b7924baa-391b-412a-8c5c-e44cc2d867dc") +IDWriteRenderingParams3 : public IDWriteRenderingParams2 +{ + virtual DWRITE_RENDERING_MODE1 STDMETHODCALLTYPE GetRenderingMode1( + ) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteRenderingParams3, 0xb7924baa, 0x391b, 0x412a, 0x8c,0x5c, 0xe4,0x4c,0xc2,0xd8,0x67,0xdc) +#endif +#else +typedef struct IDWriteRenderingParams3Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteRenderingParams3 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteRenderingParams3 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteRenderingParams3 *This); + + /*** IDWriteRenderingParams methods ***/ + FLOAT (STDMETHODCALLTYPE *GetGamma)( + IDWriteRenderingParams3 *This); + + FLOAT (STDMETHODCALLTYPE *GetEnhancedContrast)( + IDWriteRenderingParams3 *This); + + FLOAT (STDMETHODCALLTYPE *GetClearTypeLevel)( + IDWriteRenderingParams3 *This); + + DWRITE_PIXEL_GEOMETRY (STDMETHODCALLTYPE *GetPixelGeometry)( + IDWriteRenderingParams3 *This); + + DWRITE_RENDERING_MODE (STDMETHODCALLTYPE *GetRenderingMode)( + IDWriteRenderingParams3 *This); + + /*** IDWriteRenderingParams1 methods ***/ + FLOAT (STDMETHODCALLTYPE *GetGrayscaleEnhancedContrast)( + IDWriteRenderingParams3 *This); + + /*** IDWriteRenderingParams2 methods ***/ + DWRITE_GRID_FIT_MODE (STDMETHODCALLTYPE *GetGridFitMode)( + IDWriteRenderingParams3 *This); + + /*** IDWriteRenderingParams3 methods ***/ + DWRITE_RENDERING_MODE1 (STDMETHODCALLTYPE *GetRenderingMode1)( + IDWriteRenderingParams3 *This); + + END_INTERFACE +} IDWriteRenderingParams3Vtbl; + +interface IDWriteRenderingParams3 { + CONST_VTBL IDWriteRenderingParams3Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteRenderingParams3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteRenderingParams3_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteRenderingParams3_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteRenderingParams methods ***/ +#define IDWriteRenderingParams3_GetGamma(This) (This)->lpVtbl->GetGamma(This) +#define IDWriteRenderingParams3_GetEnhancedContrast(This) (This)->lpVtbl->GetEnhancedContrast(This) +#define IDWriteRenderingParams3_GetClearTypeLevel(This) (This)->lpVtbl->GetClearTypeLevel(This) +#define IDWriteRenderingParams3_GetPixelGeometry(This) (This)->lpVtbl->GetPixelGeometry(This) +#define IDWriteRenderingParams3_GetRenderingMode(This) (This)->lpVtbl->GetRenderingMode(This) +/*** IDWriteRenderingParams1 methods ***/ +#define IDWriteRenderingParams3_GetGrayscaleEnhancedContrast(This) (This)->lpVtbl->GetGrayscaleEnhancedContrast(This) +/*** IDWriteRenderingParams2 methods ***/ +#define IDWriteRenderingParams3_GetGridFitMode(This) (This)->lpVtbl->GetGridFitMode(This) +/*** IDWriteRenderingParams3 methods ***/ +#define IDWriteRenderingParams3_GetRenderingMode1(This) (This)->lpVtbl->GetRenderingMode1(This) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteRenderingParams3_QueryInterface(IDWriteRenderingParams3* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteRenderingParams3_AddRef(IDWriteRenderingParams3* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteRenderingParams3_Release(IDWriteRenderingParams3* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteRenderingParams methods ***/ +static FORCEINLINE FLOAT IDWriteRenderingParams3_GetGamma(IDWriteRenderingParams3* This) { + return This->lpVtbl->GetGamma(This); +} +static FORCEINLINE FLOAT IDWriteRenderingParams3_GetEnhancedContrast(IDWriteRenderingParams3* This) { + return This->lpVtbl->GetEnhancedContrast(This); +} +static FORCEINLINE FLOAT IDWriteRenderingParams3_GetClearTypeLevel(IDWriteRenderingParams3* This) { + return This->lpVtbl->GetClearTypeLevel(This); +} +static FORCEINLINE DWRITE_PIXEL_GEOMETRY IDWriteRenderingParams3_GetPixelGeometry(IDWriteRenderingParams3* This) { + return This->lpVtbl->GetPixelGeometry(This); +} +static FORCEINLINE DWRITE_RENDERING_MODE IDWriteRenderingParams3_GetRenderingMode(IDWriteRenderingParams3* This) { + return This->lpVtbl->GetRenderingMode(This); +} +/*** IDWriteRenderingParams1 methods ***/ +static FORCEINLINE FLOAT IDWriteRenderingParams3_GetGrayscaleEnhancedContrast(IDWriteRenderingParams3* This) { + return This->lpVtbl->GetGrayscaleEnhancedContrast(This); +} +/*** IDWriteRenderingParams2 methods ***/ +static FORCEINLINE DWRITE_GRID_FIT_MODE IDWriteRenderingParams3_GetGridFitMode(IDWriteRenderingParams3* This) { + return This->lpVtbl->GetGridFitMode(This); +} +/*** IDWriteRenderingParams3 methods ***/ +static FORCEINLINE DWRITE_RENDERING_MODE1 IDWriteRenderingParams3_GetRenderingMode1(IDWriteRenderingParams3* This) { + return This->lpVtbl->GetRenderingMode1(This); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteRenderingParams3_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteStringList interface + */ +#ifndef __IDWriteStringList_INTERFACE_DEFINED__ +#define __IDWriteStringList_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteStringList, 0xcfee3140, 0x1257, 0x47ca, 0x8b,0x85, 0x31,0xbf,0xcf,0x3f,0x2d,0x0e); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("cfee3140-1257-47ca-8b85-31bfcf3f2d0e") +IDWriteStringList : public IUnknown +{ + virtual UINT32 STDMETHODCALLTYPE GetCount( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetLocaleNameLength( + UINT32 index, + UINT32 *length) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetLocaleName( + UINT32 index, + WCHAR *name, + UINT32 size) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetStringLength( + UINT32 index, + UINT32 *length) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + UINT32 index, + WCHAR *string, + UINT32 size) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteStringList, 0xcfee3140, 0x1257, 0x47ca, 0x8b,0x85, 0x31,0xbf,0xcf,0x3f,0x2d,0x0e) +#endif +#else +typedef struct IDWriteStringListVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteStringList *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteStringList *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteStringList *This); + + /*** IDWriteStringList methods ***/ + UINT32 (STDMETHODCALLTYPE *GetCount)( + IDWriteStringList *This); + + HRESULT (STDMETHODCALLTYPE *GetLocaleNameLength)( + IDWriteStringList *This, + UINT32 index, + UINT32 *length); + + HRESULT (STDMETHODCALLTYPE *GetLocaleName)( + IDWriteStringList *This, + UINT32 index, + WCHAR *name, + UINT32 size); + + HRESULT (STDMETHODCALLTYPE *GetStringLength)( + IDWriteStringList *This, + UINT32 index, + UINT32 *length); + + HRESULT (STDMETHODCALLTYPE *GetString)( + IDWriteStringList *This, + UINT32 index, + WCHAR *string, + UINT32 size); + + END_INTERFACE +} IDWriteStringListVtbl; + +interface IDWriteStringList { + CONST_VTBL IDWriteStringListVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteStringList_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteStringList_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteStringList_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteStringList methods ***/ +#define IDWriteStringList_GetCount(This) (This)->lpVtbl->GetCount(This) +#define IDWriteStringList_GetLocaleNameLength(This,index,length) (This)->lpVtbl->GetLocaleNameLength(This,index,length) +#define IDWriteStringList_GetLocaleName(This,index,name,size) (This)->lpVtbl->GetLocaleName(This,index,name,size) +#define IDWriteStringList_GetStringLength(This,index,length) (This)->lpVtbl->GetStringLength(This,index,length) +#define IDWriteStringList_GetString(This,index,string,size) (This)->lpVtbl->GetString(This,index,string,size) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteStringList_QueryInterface(IDWriteStringList* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteStringList_AddRef(IDWriteStringList* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteStringList_Release(IDWriteStringList* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteStringList methods ***/ +static FORCEINLINE UINT32 IDWriteStringList_GetCount(IDWriteStringList* This) { + return This->lpVtbl->GetCount(This); +} +static FORCEINLINE HRESULT IDWriteStringList_GetLocaleNameLength(IDWriteStringList* This,UINT32 index,UINT32 *length) { + return This->lpVtbl->GetLocaleNameLength(This,index,length); +} +static FORCEINLINE HRESULT IDWriteStringList_GetLocaleName(IDWriteStringList* This,UINT32 index,WCHAR *name,UINT32 size) { + return This->lpVtbl->GetLocaleName(This,index,name,size); +} +static FORCEINLINE HRESULT IDWriteStringList_GetStringLength(IDWriteStringList* This,UINT32 index,UINT32 *length) { + return This->lpVtbl->GetStringLength(This,index,length); +} +static FORCEINLINE HRESULT IDWriteStringList_GetString(IDWriteStringList* This,UINT32 index,WCHAR *string,UINT32 size) { + return This->lpVtbl->GetString(This,index,string,size); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteStringList_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontSet interface + */ +#ifndef __IDWriteFontSet_INTERFACE_DEFINED__ +#define __IDWriteFontSet_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontSet, 0x53585141, 0xd9f8, 0x4095, 0x83,0x21, 0xd7,0x3c,0xf6,0xbd,0x11,0x6b); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("53585141-d9f8-4095-8321-d73cf6bd116b") +IDWriteFontSet : public IUnknown +{ + virtual UINT32 STDMETHODCALLTYPE GetFontCount( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontFaceReference( + UINT32 index, + IDWriteFontFaceReference **reference) = 0; + + virtual HRESULT STDMETHODCALLTYPE FindFontFaceReference( + IDWriteFontFaceReference *reference, + UINT32 *index, + WINBOOL *exists) = 0; + + virtual HRESULT STDMETHODCALLTYPE FindFontFace( + IDWriteFontFace *fontface, + UINT32 *index, + WINBOOL *exists) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyValues( + DWRITE_FONT_PROPERTY_ID id, + IDWriteStringList **values) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyValues( + DWRITE_FONT_PROPERTY_ID id, + const WCHAR *preferred_locales, + IDWriteStringList **values) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyValues( + UINT32 index, + DWRITE_FONT_PROPERTY_ID id, + WINBOOL *exists, + IDWriteLocalizedStrings **values) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyOccurrenceCount( + const DWRITE_FONT_PROPERTY *property, + UINT32 *count) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetMatchingFonts( + const WCHAR *family, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFontSet **fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetMatchingFonts( + const DWRITE_FONT_PROPERTY *props, + UINT32 count, + IDWriteFontSet **fontset) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontSet, 0x53585141, 0xd9f8, 0x4095, 0x83,0x21, 0xd7,0x3c,0xf6,0xbd,0x11,0x6b) +#endif +#else +typedef struct IDWriteFontSetVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontSet *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontSet *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontSet *This); + + /*** IDWriteFontSet methods ***/ + UINT32 (STDMETHODCALLTYPE *GetFontCount)( + IDWriteFontSet *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontSet *This, + UINT32 index, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *FindFontFaceReference)( + IDWriteFontSet *This, + IDWriteFontFaceReference *reference, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *FindFontFace)( + IDWriteFontSet *This, + IDWriteFontFace *fontface, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues__)( + IDWriteFontSet *This, + DWRITE_FONT_PROPERTY_ID id, + IDWriteStringList **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues_)( + IDWriteFontSet *This, + DWRITE_FONT_PROPERTY_ID id, + const WCHAR *preferred_locales, + IDWriteStringList **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues)( + IDWriteFontSet *This, + UINT32 index, + DWRITE_FONT_PROPERTY_ID id, + WINBOOL *exists, + IDWriteLocalizedStrings **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyOccurrenceCount)( + IDWriteFontSet *This, + const DWRITE_FONT_PROPERTY *property, + UINT32 *count); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts_)( + IDWriteFontSet *This, + const WCHAR *family, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts)( + IDWriteFontSet *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 count, + IDWriteFontSet **fontset); + + END_INTERFACE +} IDWriteFontSetVtbl; + +interface IDWriteFontSet { + CONST_VTBL IDWriteFontSetVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontSet_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontSet_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontSet_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontSet methods ***/ +#define IDWriteFontSet_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +#define IDWriteFontSet_GetFontFaceReference(This,index,reference) (This)->lpVtbl->GetFontFaceReference(This,index,reference) +#define IDWriteFontSet_FindFontFaceReference(This,reference,index,exists) (This)->lpVtbl->FindFontFaceReference(This,reference,index,exists) +#define IDWriteFontSet_FindFontFace(This,fontface,index,exists) (This)->lpVtbl->FindFontFace(This,fontface,index,exists) +#define IDWriteFontSet_GetPropertyValues__(This,id,values) (This)->lpVtbl->GetPropertyValues__(This,id,values) +#define IDWriteFontSet_GetPropertyValues_(This,id,preferred_locales,values) (This)->lpVtbl->GetPropertyValues_(This,id,preferred_locales,values) +#define IDWriteFontSet_GetPropertyValues(This,index,id,exists,values) (This)->lpVtbl->GetPropertyValues(This,index,id,exists,values) +#define IDWriteFontSet_GetPropertyOccurrenceCount(This,property,count) (This)->lpVtbl->GetPropertyOccurrenceCount(This,property,count) +#define IDWriteFontSet_GetMatchingFonts_(This,family,weight,stretch,style,fontset) (This)->lpVtbl->GetMatchingFonts_(This,family,weight,stretch,style,fontset) +#define IDWriteFontSet_GetMatchingFonts(This,props,count,fontset) (This)->lpVtbl->GetMatchingFonts(This,props,count,fontset) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontSet_QueryInterface(IDWriteFontSet* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontSet_AddRef(IDWriteFontSet* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontSet_Release(IDWriteFontSet* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontSet methods ***/ +static FORCEINLINE UINT32 IDWriteFontSet_GetFontCount(IDWriteFontSet* This) { + return This->lpVtbl->GetFontCount(This); +} +static FORCEINLINE HRESULT IDWriteFontSet_GetFontFaceReference(IDWriteFontSet* This,UINT32 index,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,index,reference); +} +static FORCEINLINE HRESULT IDWriteFontSet_FindFontFaceReference(IDWriteFontSet* This,IDWriteFontFaceReference *reference,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFontFaceReference(This,reference,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontSet_FindFontFace(IDWriteFontSet* This,IDWriteFontFace *fontface,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFontFace(This,fontface,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontSet_GetPropertyValues__(IDWriteFontSet* This,DWRITE_FONT_PROPERTY_ID id,IDWriteStringList **values) { + return This->lpVtbl->GetPropertyValues__(This,id,values); +} +static FORCEINLINE HRESULT IDWriteFontSet_GetPropertyValues_(IDWriteFontSet* This,DWRITE_FONT_PROPERTY_ID id,const WCHAR *preferred_locales,IDWriteStringList **values) { + return This->lpVtbl->GetPropertyValues_(This,id,preferred_locales,values); +} +static FORCEINLINE HRESULT IDWriteFontSet_GetPropertyValues(IDWriteFontSet* This,UINT32 index,DWRITE_FONT_PROPERTY_ID id,WINBOOL *exists,IDWriteLocalizedStrings **values) { + return This->lpVtbl->GetPropertyValues(This,index,id,exists,values); +} +static FORCEINLINE HRESULT IDWriteFontSet_GetPropertyOccurrenceCount(IDWriteFontSet* This,const DWRITE_FONT_PROPERTY *property,UINT32 *count) { + return This->lpVtbl->GetPropertyOccurrenceCount(This,property,count); +} +static FORCEINLINE HRESULT IDWriteFontSet_GetMatchingFonts_(IDWriteFontSet* This,const WCHAR *family,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFontSet **fontset) { + return This->lpVtbl->GetMatchingFonts_(This,family,weight,stretch,style,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet_GetMatchingFonts(IDWriteFontSet* This,const DWRITE_FONT_PROPERTY *props,UINT32 count,IDWriteFontSet **fontset) { + return This->lpVtbl->GetMatchingFonts(This,props,count,fontset); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontSet_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontResource interface + */ +#ifndef __IDWriteFontResource_INTERFACE_DEFINED__ +#define __IDWriteFontResource_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontResource, 0x1f803a76, 0x6871, 0x48e8, 0x98,0x7f, 0xb9,0x75,0x55,0x1c,0x50,0xf2); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("1f803a76-6871-48e8-987f-b975551c50f2") +IDWriteFontResource : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE GetFontFile( + IDWriteFontFile **fontfile) = 0; + + virtual UINT32 STDMETHODCALLTYPE GetFontFaceIndex( + ) = 0; + + virtual UINT32 STDMETHODCALLTYPE GetFontAxisCount( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDefaultFontAxisValues( + const DWRITE_FONT_AXIS_VALUE *values, + UINT32 num_values) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontAxisRanges( + const DWRITE_FONT_AXIS_RANGE *ranges, + UINT32 num_ranges) = 0; + + virtual DWRITE_FONT_AXIS_ATTRIBUTES STDMETHODCALLTYPE GetFontAxisAttributes( + UINT32 axis) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAxisNames( + UINT32 axis, + IDWriteLocalizedStrings **names) = 0; + + virtual UINT32 STDMETHODCALLTYPE GetAxisValueNameCount( + UINT32 axis) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAxisValueNames( + UINT32 axis, + UINT32 axis_value, + DWRITE_FONT_AXIS_RANGE *axis_range, + IDWriteLocalizedStrings **names) = 0; + + virtual WINBOOL STDMETHODCALLTYPE HasVariations( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontFace( + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontFace5 **fontface) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontFaceReference( + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontFaceReference1 **reference) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontResource, 0x1f803a76, 0x6871, 0x48e8, 0x98,0x7f, 0xb9,0x75,0x55,0x1c,0x50,0xf2) +#endif +#else +typedef struct IDWriteFontResourceVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontResource *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontResource *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontResource *This); + + /*** IDWriteFontResource methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontFile)( + IDWriteFontResource *This, + IDWriteFontFile **fontfile); + + UINT32 (STDMETHODCALLTYPE *GetFontFaceIndex)( + IDWriteFontResource *This); + + UINT32 (STDMETHODCALLTYPE *GetFontAxisCount)( + IDWriteFontResource *This); + + HRESULT (STDMETHODCALLTYPE *GetDefaultFontAxisValues)( + IDWriteFontResource *This, + const DWRITE_FONT_AXIS_VALUE *values, + UINT32 num_values); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisRanges)( + IDWriteFontResource *This, + const DWRITE_FONT_AXIS_RANGE *ranges, + UINT32 num_ranges); + + DWRITE_FONT_AXIS_ATTRIBUTES (STDMETHODCALLTYPE *GetFontAxisAttributes)( + IDWriteFontResource *This, + UINT32 axis); + + HRESULT (STDMETHODCALLTYPE *GetAxisNames)( + IDWriteFontResource *This, + UINT32 axis, + IDWriteLocalizedStrings **names); + + UINT32 (STDMETHODCALLTYPE *GetAxisValueNameCount)( + IDWriteFontResource *This, + UINT32 axis); + + HRESULT (STDMETHODCALLTYPE *GetAxisValueNames)( + IDWriteFontResource *This, + UINT32 axis, + UINT32 axis_value, + DWRITE_FONT_AXIS_RANGE *axis_range, + IDWriteLocalizedStrings **names); + + WINBOOL (STDMETHODCALLTYPE *HasVariations)( + IDWriteFontResource *This); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFontResource *This, + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontFace5 **fontface); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference)( + IDWriteFontResource *This, + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontFaceReference1 **reference); + + END_INTERFACE +} IDWriteFontResourceVtbl; + +interface IDWriteFontResource { + CONST_VTBL IDWriteFontResourceVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontResource_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontResource_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontResource_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontResource methods ***/ +#define IDWriteFontResource_GetFontFile(This,fontfile) (This)->lpVtbl->GetFontFile(This,fontfile) +#define IDWriteFontResource_GetFontFaceIndex(This) (This)->lpVtbl->GetFontFaceIndex(This) +#define IDWriteFontResource_GetFontAxisCount(This) (This)->lpVtbl->GetFontAxisCount(This) +#define IDWriteFontResource_GetDefaultFontAxisValues(This,values,num_values) (This)->lpVtbl->GetDefaultFontAxisValues(This,values,num_values) +#define IDWriteFontResource_GetFontAxisRanges(This,ranges,num_ranges) (This)->lpVtbl->GetFontAxisRanges(This,ranges,num_ranges) +#define IDWriteFontResource_GetFontAxisAttributes(This,axis) (This)->lpVtbl->GetFontAxisAttributes(This,axis) +#define IDWriteFontResource_GetAxisNames(This,axis,names) (This)->lpVtbl->GetAxisNames(This,axis,names) +#define IDWriteFontResource_GetAxisValueNameCount(This,axis) (This)->lpVtbl->GetAxisValueNameCount(This,axis) +#define IDWriteFontResource_GetAxisValueNames(This,axis,axis_value,axis_range,names) (This)->lpVtbl->GetAxisValueNames(This,axis,axis_value,axis_range,names) +#define IDWriteFontResource_HasVariations(This) (This)->lpVtbl->HasVariations(This) +#define IDWriteFontResource_CreateFontFace(This,simulations,axis_values,num_values,fontface) (This)->lpVtbl->CreateFontFace(This,simulations,axis_values,num_values,fontface) +#define IDWriteFontResource_CreateFontFaceReference(This,simulations,axis_values,num_values,reference) (This)->lpVtbl->CreateFontFaceReference(This,simulations,axis_values,num_values,reference) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontResource_QueryInterface(IDWriteFontResource* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontResource_AddRef(IDWriteFontResource* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontResource_Release(IDWriteFontResource* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontResource methods ***/ +static FORCEINLINE HRESULT IDWriteFontResource_GetFontFile(IDWriteFontResource* This,IDWriteFontFile **fontfile) { + return This->lpVtbl->GetFontFile(This,fontfile); +} +static FORCEINLINE UINT32 IDWriteFontResource_GetFontFaceIndex(IDWriteFontResource* This) { + return This->lpVtbl->GetFontFaceIndex(This); +} +static FORCEINLINE UINT32 IDWriteFontResource_GetFontAxisCount(IDWriteFontResource* This) { + return This->lpVtbl->GetFontAxisCount(This); +} +static FORCEINLINE HRESULT IDWriteFontResource_GetDefaultFontAxisValues(IDWriteFontResource* This,const DWRITE_FONT_AXIS_VALUE *values,UINT32 num_values) { + return This->lpVtbl->GetDefaultFontAxisValues(This,values,num_values); +} +static FORCEINLINE HRESULT IDWriteFontResource_GetFontAxisRanges(IDWriteFontResource* This,const DWRITE_FONT_AXIS_RANGE *ranges,UINT32 num_ranges) { + return This->lpVtbl->GetFontAxisRanges(This,ranges,num_ranges); +} +static FORCEINLINE DWRITE_FONT_AXIS_ATTRIBUTES IDWriteFontResource_GetFontAxisAttributes(IDWriteFontResource* This,UINT32 axis) { + return This->lpVtbl->GetFontAxisAttributes(This,axis); +} +static FORCEINLINE HRESULT IDWriteFontResource_GetAxisNames(IDWriteFontResource* This,UINT32 axis,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetAxisNames(This,axis,names); +} +static FORCEINLINE UINT32 IDWriteFontResource_GetAxisValueNameCount(IDWriteFontResource* This,UINT32 axis) { + return This->lpVtbl->GetAxisValueNameCount(This,axis); +} +static FORCEINLINE HRESULT IDWriteFontResource_GetAxisValueNames(IDWriteFontResource* This,UINT32 axis,UINT32 axis_value,DWRITE_FONT_AXIS_RANGE *axis_range,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetAxisValueNames(This,axis,axis_value,axis_range,names); +} +static FORCEINLINE WINBOOL IDWriteFontResource_HasVariations(IDWriteFontResource* This) { + return This->lpVtbl->HasVariations(This); +} +static FORCEINLINE HRESULT IDWriteFontResource_CreateFontFace(IDWriteFontResource* This,DWRITE_FONT_SIMULATIONS simulations,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,IDWriteFontFace5 **fontface) { + return This->lpVtbl->CreateFontFace(This,simulations,axis_values,num_values,fontface); +} +static FORCEINLINE HRESULT IDWriteFontResource_CreateFontFaceReference(IDWriteFontResource* This,DWRITE_FONT_SIMULATIONS simulations,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,IDWriteFontFaceReference1 **reference) { + return This->lpVtbl->CreateFontFaceReference(This,simulations,axis_values,num_values,reference); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontResource_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontSet1 interface + */ +#ifndef __IDWriteFontSet1_INTERFACE_DEFINED__ +#define __IDWriteFontSet1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontSet1, 0x7e9fda85, 0x6c92, 0x4053, 0xbc,0x47, 0x7a,0xe3,0x53,0x0d,0xb4,0xd3); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("7e9fda85-6c92-4053-bc47-7ae3530db4d3") +IDWriteFontSet1 : public IDWriteFontSet +{ + virtual HRESULT STDMETHODCALLTYPE GetMatchingFonts( + const DWRITE_FONT_PROPERTY *property, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontSet1 **fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFirstFontResources( + IDWriteFontSet1 **fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFilteredFonts( + const UINT32 *indices, + UINT32 num_indices, + IDWriteFontSet1 **fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFilteredFonts( + const DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + WINBOOL select_any_range, + IDWriteFontSet1 **fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFilteredFonts( + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties, + WINBOOL select_any_property, + IDWriteFontSet1 **fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFilteredFontIndices( + const DWRITE_FONT_AXIS_RANGE *ranges, + UINT32 num_ranges, + WINBOOL select_any_range, + UINT32 *indices, + UINT32 num_indices, + UINT32 *actual_num_indices) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFilteredFontIndices( + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties, + WINBOOL select_any_range, + UINT32 *indices, + UINT32 num_indices, + UINT32 *actual_num_indices) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontAxisRanges( + UINT32 font_index, + DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + UINT32 *actual_num_ranges) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontAxisRanges( + DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + UINT32 *actual_num_ranges) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontFaceReference( + UINT32 index, + IDWriteFontFaceReference1 **reference) = 0; + + using IDWriteFontSet::GetFontFaceReference; + + virtual HRESULT STDMETHODCALLTYPE CreateFontResource( + UINT32 index, + IDWriteFontResource **resource) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontFace( + UINT32 index, + IDWriteFontFace5 **fontface) = 0; + + virtual DWRITE_LOCALITY STDMETHODCALLTYPE GetFontLocality( + UINT32 index) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontSet1, 0x7e9fda85, 0x6c92, 0x4053, 0xbc,0x47, 0x7a,0xe3,0x53,0x0d,0xb4,0xd3) +#endif +#else +typedef struct IDWriteFontSet1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontSet1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontSet1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontSet1 *This); + + /*** IDWriteFontSet methods ***/ + UINT32 (STDMETHODCALLTYPE *GetFontCount)( + IDWriteFontSet1 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontSet1 *This, + UINT32 index, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *FindFontFaceReference)( + IDWriteFontSet1 *This, + IDWriteFontFaceReference *reference, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *FindFontFace)( + IDWriteFontSet1 *This, + IDWriteFontFace *fontface, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues__)( + IDWriteFontSet1 *This, + DWRITE_FONT_PROPERTY_ID id, + IDWriteStringList **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues_)( + IDWriteFontSet1 *This, + DWRITE_FONT_PROPERTY_ID id, + const WCHAR *preferred_locales, + IDWriteStringList **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues)( + IDWriteFontSet1 *This, + UINT32 index, + DWRITE_FONT_PROPERTY_ID id, + WINBOOL *exists, + IDWriteLocalizedStrings **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyOccurrenceCount)( + IDWriteFontSet1 *This, + const DWRITE_FONT_PROPERTY *property, + UINT32 *count); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts_)( + IDWriteFontSet1 *This, + const WCHAR *family, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts)( + IDWriteFontSet1 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 count, + IDWriteFontSet **fontset); + + /*** IDWriteFontSet1 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFontSet1_GetMatchingFonts)( + IDWriteFontSet1 *This, + const DWRITE_FONT_PROPERTY *property, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFirstFontResources)( + IDWriteFontSet1 *This, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts__)( + IDWriteFontSet1 *This, + const UINT32 *indices, + UINT32 num_indices, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts_)( + IDWriteFontSet1 *This, + const DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + WINBOOL select_any_range, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts)( + IDWriteFontSet1 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties, + WINBOOL select_any_property, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFontIndices_)( + IDWriteFontSet1 *This, + const DWRITE_FONT_AXIS_RANGE *ranges, + UINT32 num_ranges, + WINBOOL select_any_range, + UINT32 *indices, + UINT32 num_indices, + UINT32 *actual_num_indices); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFontIndices)( + IDWriteFontSet1 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties, + WINBOOL select_any_range, + UINT32 *indices, + UINT32 num_indices, + UINT32 *actual_num_indices); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisRanges_)( + IDWriteFontSet1 *This, + UINT32 font_index, + DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + UINT32 *actual_num_ranges); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisRanges)( + IDWriteFontSet1 *This, + DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + UINT32 *actual_num_ranges); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontSet1_GetFontFaceReference)( + IDWriteFontSet1 *This, + UINT32 index, + IDWriteFontFaceReference1 **reference); + + HRESULT (STDMETHODCALLTYPE *CreateFontResource)( + IDWriteFontSet1 *This, + UINT32 index, + IDWriteFontResource **resource); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFontSet1 *This, + UINT32 index, + IDWriteFontFace5 **fontface); + + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetFontLocality)( + IDWriteFontSet1 *This, + UINT32 index); + + END_INTERFACE +} IDWriteFontSet1Vtbl; + +interface IDWriteFontSet1 { + CONST_VTBL IDWriteFontSet1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontSet1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontSet1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontSet1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontSet methods ***/ +#define IDWriteFontSet1_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +#define IDWriteFontSet1_FindFontFaceReference(This,reference,index,exists) (This)->lpVtbl->FindFontFaceReference(This,reference,index,exists) +#define IDWriteFontSet1_FindFontFace(This,fontface,index,exists) (This)->lpVtbl->FindFontFace(This,fontface,index,exists) +#define IDWriteFontSet1_GetPropertyValues__(This,id,values) (This)->lpVtbl->GetPropertyValues__(This,id,values) +#define IDWriteFontSet1_GetPropertyValues_(This,id,preferred_locales,values) (This)->lpVtbl->GetPropertyValues_(This,id,preferred_locales,values) +#define IDWriteFontSet1_GetPropertyValues(This,index,id,exists,values) (This)->lpVtbl->GetPropertyValues(This,index,id,exists,values) +#define IDWriteFontSet1_GetPropertyOccurrenceCount(This,property,count) (This)->lpVtbl->GetPropertyOccurrenceCount(This,property,count) +#define IDWriteFontSet1_GetMatchingFonts_(This,family,weight,stretch,style,fontset) (This)->lpVtbl->GetMatchingFonts_(This,family,weight,stretch,style,fontset) +/*** IDWriteFontSet1 methods ***/ +#define IDWriteFontSet1_GetMatchingFonts(This,property,axis_values,num_values,fontset) (This)->lpVtbl->IDWriteFontSet1_GetMatchingFonts(This,property,axis_values,num_values,fontset) +#define IDWriteFontSet1_GetFirstFontResources(This,fontset) (This)->lpVtbl->GetFirstFontResources(This,fontset) +#define IDWriteFontSet1_GetFilteredFonts__(This,indices,num_indices,fontset) (This)->lpVtbl->GetFilteredFonts__(This,indices,num_indices,fontset) +#define IDWriteFontSet1_GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset) (This)->lpVtbl->GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset) +#define IDWriteFontSet1_GetFilteredFonts(This,props,num_properties,select_any_property,fontset) (This)->lpVtbl->GetFilteredFonts(This,props,num_properties,select_any_property,fontset) +#define IDWriteFontSet1_GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices) (This)->lpVtbl->GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices) +#define IDWriteFontSet1_GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices) (This)->lpVtbl->GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices) +#define IDWriteFontSet1_GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges) (This)->lpVtbl->GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges) +#define IDWriteFontSet1_GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges) (This)->lpVtbl->GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges) +#define IDWriteFontSet1_GetFontFaceReference(This,index,reference) (This)->lpVtbl->IDWriteFontSet1_GetFontFaceReference(This,index,reference) +#define IDWriteFontSet1_CreateFontResource(This,index,resource) (This)->lpVtbl->CreateFontResource(This,index,resource) +#define IDWriteFontSet1_CreateFontFace(This,index,fontface) (This)->lpVtbl->CreateFontFace(This,index,fontface) +#define IDWriteFontSet1_GetFontLocality(This,index) (This)->lpVtbl->GetFontLocality(This,index) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontSet1_QueryInterface(IDWriteFontSet1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontSet1_AddRef(IDWriteFontSet1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontSet1_Release(IDWriteFontSet1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontSet methods ***/ +static FORCEINLINE UINT32 IDWriteFontSet1_GetFontCount(IDWriteFontSet1* This) { + return This->lpVtbl->GetFontCount(This); +} +static FORCEINLINE HRESULT IDWriteFontSet1_FindFontFaceReference(IDWriteFontSet1* This,IDWriteFontFaceReference *reference,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFontFaceReference(This,reference,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontSet1_FindFontFace(IDWriteFontSet1* This,IDWriteFontFace *fontface,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFontFace(This,fontface,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetPropertyValues__(IDWriteFontSet1* This,DWRITE_FONT_PROPERTY_ID id,IDWriteStringList **values) { + return This->lpVtbl->GetPropertyValues__(This,id,values); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetPropertyValues_(IDWriteFontSet1* This,DWRITE_FONT_PROPERTY_ID id,const WCHAR *preferred_locales,IDWriteStringList **values) { + return This->lpVtbl->GetPropertyValues_(This,id,preferred_locales,values); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetPropertyValues(IDWriteFontSet1* This,UINT32 index,DWRITE_FONT_PROPERTY_ID id,WINBOOL *exists,IDWriteLocalizedStrings **values) { + return This->lpVtbl->GetPropertyValues(This,index,id,exists,values); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetPropertyOccurrenceCount(IDWriteFontSet1* This,const DWRITE_FONT_PROPERTY *property,UINT32 *count) { + return This->lpVtbl->GetPropertyOccurrenceCount(This,property,count); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetMatchingFonts_(IDWriteFontSet1* This,const WCHAR *family,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFontSet **fontset) { + return This->lpVtbl->GetMatchingFonts_(This,family,weight,stretch,style,fontset); +} +/*** IDWriteFontSet1 methods ***/ +static FORCEINLINE HRESULT IDWriteFontSet1_GetMatchingFonts(IDWriteFontSet1* This,const DWRITE_FONT_PROPERTY *property,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,IDWriteFontSet1 **fontset) { + return This->lpVtbl->IDWriteFontSet1_GetMatchingFonts(This,property,axis_values,num_values,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFirstFontResources(IDWriteFontSet1* This,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFirstFontResources(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFilteredFonts__(IDWriteFontSet1* This,const UINT32 *indices,UINT32 num_indices,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts__(This,indices,num_indices,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFilteredFonts_(IDWriteFontSet1* This,const DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,WINBOOL select_any_range,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFilteredFonts(IDWriteFontSet1* This,const DWRITE_FONT_PROPERTY *props,UINT32 num_properties,WINBOOL select_any_property,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts(This,props,num_properties,select_any_property,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFilteredFontIndices_(IDWriteFontSet1* This,const DWRITE_FONT_AXIS_RANGE *ranges,UINT32 num_ranges,WINBOOL select_any_range,UINT32 *indices,UINT32 num_indices,UINT32 *actual_num_indices) { + return This->lpVtbl->GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFilteredFontIndices(IDWriteFontSet1* This,const DWRITE_FONT_PROPERTY *props,UINT32 num_properties,WINBOOL select_any_range,UINT32 *indices,UINT32 num_indices,UINT32 *actual_num_indices) { + return This->lpVtbl->GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFontAxisRanges_(IDWriteFontSet1* This,UINT32 font_index,DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,UINT32 *actual_num_ranges) { + return This->lpVtbl->GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFontAxisRanges(IDWriteFontSet1* This,DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,UINT32 *actual_num_ranges) { + return This->lpVtbl->GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges); +} +static FORCEINLINE HRESULT IDWriteFontSet1_GetFontFaceReference(IDWriteFontSet1* This,UINT32 index,IDWriteFontFaceReference1 **reference) { + return This->lpVtbl->IDWriteFontSet1_GetFontFaceReference(This,index,reference); +} +static FORCEINLINE HRESULT IDWriteFontSet1_CreateFontResource(IDWriteFontSet1* This,UINT32 index,IDWriteFontResource **resource) { + return This->lpVtbl->CreateFontResource(This,index,resource); +} +static FORCEINLINE HRESULT IDWriteFontSet1_CreateFontFace(IDWriteFontSet1* This,UINT32 index,IDWriteFontFace5 **fontface) { + return This->lpVtbl->CreateFontFace(This,index,fontface); +} +static FORCEINLINE DWRITE_LOCALITY IDWriteFontSet1_GetFontLocality(IDWriteFontSet1* This,UINT32 index) { + return This->lpVtbl->GetFontLocality(This,index); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontSet1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFont3 interface + */ +#ifndef __IDWriteFont3_INTERFACE_DEFINED__ +#define __IDWriteFont3_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFont3, 0x29748ed6, 0x8c9c, 0x4a6a, 0xbe,0x0b, 0xd9,0x12,0xe8,0x53,0x89,0x44); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("29748ed6-8c9c-4a6a-be0b-d912e8538944") +IDWriteFont3 : public IDWriteFont2 +{ + virtual HRESULT STDMETHODCALLTYPE CreateFontFace( + IDWriteFontFace3 **fontface) = 0; + + using IDWriteFont::CreateFontFace; + + virtual WINBOOL STDMETHODCALLTYPE Equals( + IDWriteFont *font) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontFaceReference( + IDWriteFontFaceReference **reference) = 0; + + virtual WINBOOL STDMETHODCALLTYPE HasCharacter( + UINT32 character) = 0; + + using IDWriteFont::HasCharacter; + + virtual DWRITE_LOCALITY STDMETHODCALLTYPE GetLocality( + ) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFont3, 0x29748ed6, 0x8c9c, 0x4a6a, 0xbe,0x0b, 0xd9,0x12,0xe8,0x53,0x89,0x44) +#endif +#else +typedef struct IDWriteFont3Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFont3 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFont3 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFont3 *This); + + /*** IDWriteFont methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontFamily)( + IDWriteFont3 *This, + IDWriteFontFamily **family); + + DWRITE_FONT_WEIGHT (STDMETHODCALLTYPE *GetWeight)( + IDWriteFont3 *This); + + DWRITE_FONT_STRETCH (STDMETHODCALLTYPE *GetStretch)( + IDWriteFont3 *This); + + DWRITE_FONT_STYLE (STDMETHODCALLTYPE *GetStyle)( + IDWriteFont3 *This); + + WINBOOL (STDMETHODCALLTYPE *IsSymbolFont)( + IDWriteFont3 *This); + + HRESULT (STDMETHODCALLTYPE *GetFaceNames)( + IDWriteFont3 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetInformationalStrings)( + IDWriteFont3 *This, + DWRITE_INFORMATIONAL_STRING_ID stringid, + IDWriteLocalizedStrings **strings, + WINBOOL *exists); + + DWRITE_FONT_SIMULATIONS (STDMETHODCALLTYPE *GetSimulations)( + IDWriteFont3 *This); + + void (STDMETHODCALLTYPE *GetMetrics)( + IDWriteFont3 *This, + DWRITE_FONT_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *HasCharacter)( + IDWriteFont3 *This, + UINT32 value, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFont3 *This, + IDWriteFontFace **face); + + /*** IDWriteFont1 methods ***/ + void (STDMETHODCALLTYPE *IDWriteFont1_GetMetrics)( + IDWriteFont3 *This, + DWRITE_FONT_METRICS1 *metrics); + + void (STDMETHODCALLTYPE *GetPanose)( + IDWriteFont3 *This, + DWRITE_PANOSE *panose); + + HRESULT (STDMETHODCALLTYPE *GetUnicodeRanges)( + IDWriteFont3 *This, + UINT32 max_count, + DWRITE_UNICODE_RANGE *ranges, + UINT32 *count); + + WINBOOL (STDMETHODCALLTYPE *IsMonospacedFont)( + IDWriteFont3 *This); + + /*** IDWriteFont2 methods ***/ + WINBOOL (STDMETHODCALLTYPE *IsColorFont)( + IDWriteFont3 *This); + + /*** IDWriteFont3 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFont3_CreateFontFace)( + IDWriteFont3 *This, + IDWriteFontFace3 **fontface); + + WINBOOL (STDMETHODCALLTYPE *Equals)( + IDWriteFont3 *This, + IDWriteFont *font); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFont3 *This, + IDWriteFontFaceReference **reference); + + WINBOOL (STDMETHODCALLTYPE *IDWriteFont3_HasCharacter)( + IDWriteFont3 *This, + UINT32 character); + + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetLocality)( + IDWriteFont3 *This); + + END_INTERFACE +} IDWriteFont3Vtbl; + +interface IDWriteFont3 { + CONST_VTBL IDWriteFont3Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFont3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFont3_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFont3_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFont methods ***/ +#define IDWriteFont3_GetFontFamily(This,family) (This)->lpVtbl->GetFontFamily(This,family) +#define IDWriteFont3_GetWeight(This) (This)->lpVtbl->GetWeight(This) +#define IDWriteFont3_GetStretch(This) (This)->lpVtbl->GetStretch(This) +#define IDWriteFont3_GetStyle(This) (This)->lpVtbl->GetStyle(This) +#define IDWriteFont3_IsSymbolFont(This) (This)->lpVtbl->IsSymbolFont(This) +#define IDWriteFont3_GetFaceNames(This,names) (This)->lpVtbl->GetFaceNames(This,names) +#define IDWriteFont3_GetInformationalStrings(This,stringid,strings,exists) (This)->lpVtbl->GetInformationalStrings(This,stringid,strings,exists) +#define IDWriteFont3_GetSimulations(This) (This)->lpVtbl->GetSimulations(This) +/*** IDWriteFont1 methods ***/ +#define IDWriteFont3_GetMetrics(This,metrics) (This)->lpVtbl->IDWriteFont1_GetMetrics(This,metrics) +#define IDWriteFont3_GetPanose(This,panose) (This)->lpVtbl->GetPanose(This,panose) +#define IDWriteFont3_GetUnicodeRanges(This,max_count,ranges,count) (This)->lpVtbl->GetUnicodeRanges(This,max_count,ranges,count) +#define IDWriteFont3_IsMonospacedFont(This) (This)->lpVtbl->IsMonospacedFont(This) +/*** IDWriteFont2 methods ***/ +#define IDWriteFont3_IsColorFont(This) (This)->lpVtbl->IsColorFont(This) +/*** IDWriteFont3 methods ***/ +#define IDWriteFont3_CreateFontFace(This,fontface) (This)->lpVtbl->IDWriteFont3_CreateFontFace(This,fontface) +#define IDWriteFont3_Equals(This,font) (This)->lpVtbl->Equals(This,font) +#define IDWriteFont3_GetFontFaceReference(This,reference) (This)->lpVtbl->GetFontFaceReference(This,reference) +#define IDWriteFont3_HasCharacter(This,character) (This)->lpVtbl->IDWriteFont3_HasCharacter(This,character) +#define IDWriteFont3_GetLocality(This) (This)->lpVtbl->GetLocality(This) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFont3_QueryInterface(IDWriteFont3* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFont3_AddRef(IDWriteFont3* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFont3_Release(IDWriteFont3* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFont methods ***/ +static FORCEINLINE HRESULT IDWriteFont3_GetFontFamily(IDWriteFont3* This,IDWriteFontFamily **family) { + return This->lpVtbl->GetFontFamily(This,family); +} +static FORCEINLINE DWRITE_FONT_WEIGHT IDWriteFont3_GetWeight(IDWriteFont3* This) { + return This->lpVtbl->GetWeight(This); +} +static FORCEINLINE DWRITE_FONT_STRETCH IDWriteFont3_GetStretch(IDWriteFont3* This) { + return This->lpVtbl->GetStretch(This); +} +static FORCEINLINE DWRITE_FONT_STYLE IDWriteFont3_GetStyle(IDWriteFont3* This) { + return This->lpVtbl->GetStyle(This); +} +static FORCEINLINE WINBOOL IDWriteFont3_IsSymbolFont(IDWriteFont3* This) { + return This->lpVtbl->IsSymbolFont(This); +} +static FORCEINLINE HRESULT IDWriteFont3_GetFaceNames(IDWriteFont3* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFaceNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFont3_GetInformationalStrings(IDWriteFont3* This,DWRITE_INFORMATIONAL_STRING_ID stringid,IDWriteLocalizedStrings **strings,WINBOOL *exists) { + return This->lpVtbl->GetInformationalStrings(This,stringid,strings,exists); +} +static FORCEINLINE DWRITE_FONT_SIMULATIONS IDWriteFont3_GetSimulations(IDWriteFont3* This) { + return This->lpVtbl->GetSimulations(This); +} +/*** IDWriteFont1 methods ***/ +static FORCEINLINE void IDWriteFont3_GetMetrics(IDWriteFont3* This,DWRITE_FONT_METRICS1 *metrics) { + This->lpVtbl->IDWriteFont1_GetMetrics(This,metrics); +} +static FORCEINLINE void IDWriteFont3_GetPanose(IDWriteFont3* This,DWRITE_PANOSE *panose) { + This->lpVtbl->GetPanose(This,panose); +} +static FORCEINLINE HRESULT IDWriteFont3_GetUnicodeRanges(IDWriteFont3* This,UINT32 max_count,DWRITE_UNICODE_RANGE *ranges,UINT32 *count) { + return This->lpVtbl->GetUnicodeRanges(This,max_count,ranges,count); +} +static FORCEINLINE WINBOOL IDWriteFont3_IsMonospacedFont(IDWriteFont3* This) { + return This->lpVtbl->IsMonospacedFont(This); +} +/*** IDWriteFont2 methods ***/ +static FORCEINLINE WINBOOL IDWriteFont3_IsColorFont(IDWriteFont3* This) { + return This->lpVtbl->IsColorFont(This); +} +/*** IDWriteFont3 methods ***/ +static FORCEINLINE HRESULT IDWriteFont3_CreateFontFace(IDWriteFont3* This,IDWriteFontFace3 **fontface) { + return This->lpVtbl->IDWriteFont3_CreateFontFace(This,fontface); +} +static FORCEINLINE WINBOOL IDWriteFont3_Equals(IDWriteFont3* This,IDWriteFont *font) { + return This->lpVtbl->Equals(This,font); +} +static FORCEINLINE HRESULT IDWriteFont3_GetFontFaceReference(IDWriteFont3* This,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,reference); +} +static FORCEINLINE WINBOOL IDWriteFont3_HasCharacter(IDWriteFont3* This,UINT32 character) { + return This->lpVtbl->IDWriteFont3_HasCharacter(This,character); +} +static FORCEINLINE DWRITE_LOCALITY IDWriteFont3_GetLocality(IDWriteFont3* This) { + return This->lpVtbl->GetLocality(This); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFont3_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontFamily1 interface + */ +#ifndef __IDWriteFontFamily1_INTERFACE_DEFINED__ +#define __IDWriteFontFamily1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontFamily1, 0xda20d8ef, 0x812a, 0x4c43, 0x98,0x02, 0x62,0xec,0x4a,0xbd,0x7a,0xdf); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("da20d8ef-812a-4c43-9802-62ec4abd7adf") +IDWriteFontFamily1 : public IDWriteFontFamily +{ + virtual DWRITE_LOCALITY STDMETHODCALLTYPE GetFontLocality( + UINT32 index) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFont( + UINT32 index, + IDWriteFont3 **font) = 0; + + using IDWriteFontFamily::GetFont; + + virtual HRESULT STDMETHODCALLTYPE GetFontFaceReference( + UINT32 index, + IDWriteFontFaceReference **reference) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontFamily1, 0xda20d8ef, 0x812a, 0x4c43, 0x98,0x02, 0x62,0xec,0x4a,0xbd,0x7a,0xdf) +#endif +#else +typedef struct IDWriteFontFamily1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontFamily1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontFamily1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontFamily1 *This); + + /*** IDWriteFontList methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontCollection)( + IDWriteFontFamily1 *This, + IDWriteFontCollection **collection); + + UINT32 (STDMETHODCALLTYPE *GetFontCount)( + IDWriteFontFamily1 *This); + + HRESULT (STDMETHODCALLTYPE *GetFont)( + IDWriteFontFamily1 *This, + UINT32 index, + IDWriteFont **font); + + /*** IDWriteFontFamily methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFamilyNames)( + IDWriteFontFamily1 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetFirstMatchingFont)( + IDWriteFontFamily1 *This, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFont **font); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts)( + IDWriteFontFamily1 *This, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFontList **fonts); + + /*** IDWriteFontFamily1 methods ***/ + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetFontLocality)( + IDWriteFontFamily1 *This, + UINT32 index); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFamily1_GetFont)( + IDWriteFontFamily1 *This, + UINT32 index, + IDWriteFont3 **font); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontFamily1 *This, + UINT32 index, + IDWriteFontFaceReference **reference); + + END_INTERFACE +} IDWriteFontFamily1Vtbl; + +interface IDWriteFontFamily1 { + CONST_VTBL IDWriteFontFamily1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontFamily1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFamily1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFamily1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontList methods ***/ +#define IDWriteFontFamily1_GetFontCollection(This,collection) (This)->lpVtbl->GetFontCollection(This,collection) +#define IDWriteFontFamily1_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +/*** IDWriteFontFamily methods ***/ +#define IDWriteFontFamily1_GetFamilyNames(This,names) (This)->lpVtbl->GetFamilyNames(This,names) +#define IDWriteFontFamily1_GetFirstMatchingFont(This,weight,stretch,style,font) (This)->lpVtbl->GetFirstMatchingFont(This,weight,stretch,style,font) +#define IDWriteFontFamily1_GetMatchingFonts(This,weight,stretch,style,fonts) (This)->lpVtbl->GetMatchingFonts(This,weight,stretch,style,fonts) +/*** IDWriteFontFamily1 methods ***/ +#define IDWriteFontFamily1_GetFontLocality(This,index) (This)->lpVtbl->GetFontLocality(This,index) +#define IDWriteFontFamily1_GetFont(This,index,font) (This)->lpVtbl->IDWriteFontFamily1_GetFont(This,index,font) +#define IDWriteFontFamily1_GetFontFaceReference(This,index,reference) (This)->lpVtbl->GetFontFaceReference(This,index,reference) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontFamily1_QueryInterface(IDWriteFontFamily1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontFamily1_AddRef(IDWriteFontFamily1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontFamily1_Release(IDWriteFontFamily1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontList methods ***/ +static FORCEINLINE HRESULT IDWriteFontFamily1_GetFontCollection(IDWriteFontFamily1* This,IDWriteFontCollection **collection) { + return This->lpVtbl->GetFontCollection(This,collection); +} +static FORCEINLINE UINT32 IDWriteFontFamily1_GetFontCount(IDWriteFontFamily1* This) { + return This->lpVtbl->GetFontCount(This); +} +/*** IDWriteFontFamily methods ***/ +static FORCEINLINE HRESULT IDWriteFontFamily1_GetFamilyNames(IDWriteFontFamily1* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFamilyNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFontFamily1_GetFirstMatchingFont(IDWriteFontFamily1* This,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFont **font) { + return This->lpVtbl->GetFirstMatchingFont(This,weight,stretch,style,font); +} +static FORCEINLINE HRESULT IDWriteFontFamily1_GetMatchingFonts(IDWriteFontFamily1* This,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFontList **fonts) { + return This->lpVtbl->GetMatchingFonts(This,weight,stretch,style,fonts); +} +/*** IDWriteFontFamily1 methods ***/ +static FORCEINLINE DWRITE_LOCALITY IDWriteFontFamily1_GetFontLocality(IDWriteFontFamily1* This,UINT32 index) { + return This->lpVtbl->GetFontLocality(This,index); +} +static FORCEINLINE HRESULT IDWriteFontFamily1_GetFont(IDWriteFontFamily1* This,UINT32 index,IDWriteFont3 **font) { + return This->lpVtbl->IDWriteFontFamily1_GetFont(This,index,font); +} +static FORCEINLINE HRESULT IDWriteFontFamily1_GetFontFaceReference(IDWriteFontFamily1* This,UINT32 index,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,index,reference); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontFamily1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontFamily2 interface + */ +#ifndef __IDWriteFontFamily2_INTERFACE_DEFINED__ +#define __IDWriteFontFamily2_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontFamily2, 0x3ed49e77, 0xa398, 0x4261, 0xb9,0xcf, 0xc1,0x26,0xc2,0x13,0x1e,0xf3); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("3ed49e77-a398-4261-b9cf-c126c2131ef3") +IDWriteFontFamily2 : public IDWriteFontFamily1 +{ + virtual HRESULT STDMETHODCALLTYPE GetMatchingFonts( + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontList2 **fontlist) = 0; + + using IDWriteFontFamily::GetMatchingFonts; + + virtual HRESULT STDMETHODCALLTYPE GetFontSet( + IDWriteFontSet1 **fontset) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontFamily2, 0x3ed49e77, 0xa398, 0x4261, 0xb9,0xcf, 0xc1,0x26,0xc2,0x13,0x1e,0xf3) +#endif +#else +typedef struct IDWriteFontFamily2Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontFamily2 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontFamily2 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontFamily2 *This); + + /*** IDWriteFontList methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontCollection)( + IDWriteFontFamily2 *This, + IDWriteFontCollection **collection); + + UINT32 (STDMETHODCALLTYPE *GetFontCount)( + IDWriteFontFamily2 *This); + + HRESULT (STDMETHODCALLTYPE *GetFont)( + IDWriteFontFamily2 *This, + UINT32 index, + IDWriteFont **font); + + /*** IDWriteFontFamily methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFamilyNames)( + IDWriteFontFamily2 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetFirstMatchingFont)( + IDWriteFontFamily2 *This, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFont **font); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts)( + IDWriteFontFamily2 *This, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFontList **fonts); + + /*** IDWriteFontFamily1 methods ***/ + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetFontLocality)( + IDWriteFontFamily2 *This, + UINT32 index); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFamily1_GetFont)( + IDWriteFontFamily2 *This, + UINT32 index, + IDWriteFont3 **font); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontFamily2 *This, + UINT32 index, + IDWriteFontFaceReference **reference); + + /*** IDWriteFontFamily2 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFontFamily2_GetMatchingFonts)( + IDWriteFontFamily2 *This, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontList2 **fontlist); + + HRESULT (STDMETHODCALLTYPE *GetFontSet)( + IDWriteFontFamily2 *This, + IDWriteFontSet1 **fontset); + + END_INTERFACE +} IDWriteFontFamily2Vtbl; + +interface IDWriteFontFamily2 { + CONST_VTBL IDWriteFontFamily2Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontFamily2_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFamily2_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFamily2_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontList methods ***/ +#define IDWriteFontFamily2_GetFontCollection(This,collection) (This)->lpVtbl->GetFontCollection(This,collection) +#define IDWriteFontFamily2_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +/*** IDWriteFontFamily methods ***/ +#define IDWriteFontFamily2_GetFamilyNames(This,names) (This)->lpVtbl->GetFamilyNames(This,names) +#define IDWriteFontFamily2_GetFirstMatchingFont(This,weight,stretch,style,font) (This)->lpVtbl->GetFirstMatchingFont(This,weight,stretch,style,font) +/*** IDWriteFontFamily1 methods ***/ +#define IDWriteFontFamily2_GetFontLocality(This,index) (This)->lpVtbl->GetFontLocality(This,index) +#define IDWriteFontFamily2_GetFont(This,index,font) (This)->lpVtbl->IDWriteFontFamily1_GetFont(This,index,font) +#define IDWriteFontFamily2_GetFontFaceReference(This,index,reference) (This)->lpVtbl->GetFontFaceReference(This,index,reference) +/*** IDWriteFontFamily2 methods ***/ +#define IDWriteFontFamily2_GetMatchingFonts(This,axis_values,num_values,fontlist) (This)->lpVtbl->IDWriteFontFamily2_GetMatchingFonts(This,axis_values,num_values,fontlist) +#define IDWriteFontFamily2_GetFontSet(This,fontset) (This)->lpVtbl->GetFontSet(This,fontset) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontFamily2_QueryInterface(IDWriteFontFamily2* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontFamily2_AddRef(IDWriteFontFamily2* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontFamily2_Release(IDWriteFontFamily2* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontList methods ***/ +static FORCEINLINE HRESULT IDWriteFontFamily2_GetFontCollection(IDWriteFontFamily2* This,IDWriteFontCollection **collection) { + return This->lpVtbl->GetFontCollection(This,collection); +} +static FORCEINLINE UINT32 IDWriteFontFamily2_GetFontCount(IDWriteFontFamily2* This) { + return This->lpVtbl->GetFontCount(This); +} +/*** IDWriteFontFamily methods ***/ +static FORCEINLINE HRESULT IDWriteFontFamily2_GetFamilyNames(IDWriteFontFamily2* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFamilyNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFontFamily2_GetFirstMatchingFont(IDWriteFontFamily2* This,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFont **font) { + return This->lpVtbl->GetFirstMatchingFont(This,weight,stretch,style,font); +} +/*** IDWriteFontFamily1 methods ***/ +static FORCEINLINE DWRITE_LOCALITY IDWriteFontFamily2_GetFontLocality(IDWriteFontFamily2* This,UINT32 index) { + return This->lpVtbl->GetFontLocality(This,index); +} +static FORCEINLINE HRESULT IDWriteFontFamily2_GetFont(IDWriteFontFamily2* This,UINT32 index,IDWriteFont3 **font) { + return This->lpVtbl->IDWriteFontFamily1_GetFont(This,index,font); +} +static FORCEINLINE HRESULT IDWriteFontFamily2_GetFontFaceReference(IDWriteFontFamily2* This,UINT32 index,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,index,reference); +} +/*** IDWriteFontFamily2 methods ***/ +static FORCEINLINE HRESULT IDWriteFontFamily2_GetMatchingFonts(IDWriteFontFamily2* This,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,IDWriteFontList2 **fontlist) { + return This->lpVtbl->IDWriteFontFamily2_GetMatchingFonts(This,axis_values,num_values,fontlist); +} +static FORCEINLINE HRESULT IDWriteFontFamily2_GetFontSet(IDWriteFontFamily2* This,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFontSet(This,fontset); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontFamily2_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontCollection1 interface + */ +#ifndef __IDWriteFontCollection1_INTERFACE_DEFINED__ +#define __IDWriteFontCollection1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontCollection1, 0x53585141, 0xd9f8, 0x4095, 0x83,0x21, 0xd7,0x3c,0xf6,0xbd,0x11,0x6c); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("53585141-d9f8-4095-8321-d73cf6bd116c") +IDWriteFontCollection1 : public IDWriteFontCollection +{ + virtual HRESULT STDMETHODCALLTYPE GetFontSet( + IDWriteFontSet **fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontFamily( + UINT32 index, + IDWriteFontFamily1 **family) = 0; + + using IDWriteFontCollection::GetFontFamily; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontCollection1, 0x53585141, 0xd9f8, 0x4095, 0x83,0x21, 0xd7,0x3c,0xf6,0xbd,0x11,0x6c) +#endif +#else +typedef struct IDWriteFontCollection1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontCollection1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontCollection1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontCollection1 *This); + + /*** IDWriteFontCollection methods ***/ + UINT32 (STDMETHODCALLTYPE *GetFontFamilyCount)( + IDWriteFontCollection1 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFamily)( + IDWriteFontCollection1 *This, + UINT32 index, + IDWriteFontFamily **family); + + HRESULT (STDMETHODCALLTYPE *FindFamilyName)( + IDWriteFontCollection1 *This, + const WCHAR *name, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *GetFontFromFontFace)( + IDWriteFontCollection1 *This, + IDWriteFontFace *face, + IDWriteFont **font); + + /*** IDWriteFontCollection1 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontSet)( + IDWriteFontCollection1 *This, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontCollection1_GetFontFamily)( + IDWriteFontCollection1 *This, + UINT32 index, + IDWriteFontFamily1 **family); + + END_INTERFACE +} IDWriteFontCollection1Vtbl; + +interface IDWriteFontCollection1 { + CONST_VTBL IDWriteFontCollection1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontCollection1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontCollection1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontCollection1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontCollection methods ***/ +#define IDWriteFontCollection1_GetFontFamilyCount(This) (This)->lpVtbl->GetFontFamilyCount(This) +#define IDWriteFontCollection1_FindFamilyName(This,name,index,exists) (This)->lpVtbl->FindFamilyName(This,name,index,exists) +#define IDWriteFontCollection1_GetFontFromFontFace(This,face,font) (This)->lpVtbl->GetFontFromFontFace(This,face,font) +/*** IDWriteFontCollection1 methods ***/ +#define IDWriteFontCollection1_GetFontSet(This,fontset) (This)->lpVtbl->GetFontSet(This,fontset) +#define IDWriteFontCollection1_GetFontFamily(This,index,family) (This)->lpVtbl->IDWriteFontCollection1_GetFontFamily(This,index,family) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontCollection1_QueryInterface(IDWriteFontCollection1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontCollection1_AddRef(IDWriteFontCollection1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontCollection1_Release(IDWriteFontCollection1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontCollection methods ***/ +static FORCEINLINE UINT32 IDWriteFontCollection1_GetFontFamilyCount(IDWriteFontCollection1* This) { + return This->lpVtbl->GetFontFamilyCount(This); +} +static FORCEINLINE HRESULT IDWriteFontCollection1_FindFamilyName(IDWriteFontCollection1* This,const WCHAR *name,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFamilyName(This,name,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontCollection1_GetFontFromFontFace(IDWriteFontCollection1* This,IDWriteFontFace *face,IDWriteFont **font) { + return This->lpVtbl->GetFontFromFontFace(This,face,font); +} +/*** IDWriteFontCollection1 methods ***/ +static FORCEINLINE HRESULT IDWriteFontCollection1_GetFontSet(IDWriteFontCollection1* This,IDWriteFontSet **fontset) { + return This->lpVtbl->GetFontSet(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFontCollection1_GetFontFamily(IDWriteFontCollection1* This,UINT32 index,IDWriteFontFamily1 **family) { + return This->lpVtbl->IDWriteFontCollection1_GetFontFamily(This,index,family); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontCollection1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontCollection2 interface + */ +#ifndef __IDWriteFontCollection2_INTERFACE_DEFINED__ +#define __IDWriteFontCollection2_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontCollection2, 0x514039c6, 0x4617, 0x4064, 0xbf,0x8b, 0x92,0xea,0x83,0xe5,0x06,0xe0); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("514039c6-4617-4064-bf8b-92ea83e506e0") +IDWriteFontCollection2 : public IDWriteFontCollection1 +{ + virtual HRESULT STDMETHODCALLTYPE GetFontFamily( + UINT32 index, + IDWriteFontFamily2 **family) = 0; + + using IDWriteFontCollection::GetFontFamily; + using IDWriteFontCollection1::GetFontFamily; + + virtual HRESULT STDMETHODCALLTYPE GetMatchingFonts( + const WCHAR *familyname, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontList2 **fontlist) = 0; + + virtual DWRITE_FONT_FAMILY_MODEL STDMETHODCALLTYPE GetFontFamilyModel( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontSet( + IDWriteFontSet1 **fontset) = 0; + + using IDWriteFontCollection1::GetFontSet; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontCollection2, 0x514039c6, 0x4617, 0x4064, 0xbf,0x8b, 0x92,0xea,0x83,0xe5,0x06,0xe0) +#endif +#else +typedef struct IDWriteFontCollection2Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontCollection2 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontCollection2 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontCollection2 *This); + + /*** IDWriteFontCollection methods ***/ + UINT32 (STDMETHODCALLTYPE *GetFontFamilyCount)( + IDWriteFontCollection2 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFamily)( + IDWriteFontCollection2 *This, + UINT32 index, + IDWriteFontFamily **family); + + HRESULT (STDMETHODCALLTYPE *FindFamilyName)( + IDWriteFontCollection2 *This, + const WCHAR *name, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *GetFontFromFontFace)( + IDWriteFontCollection2 *This, + IDWriteFontFace *face, + IDWriteFont **font); + + /*** IDWriteFontCollection1 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontSet)( + IDWriteFontCollection2 *This, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontCollection1_GetFontFamily)( + IDWriteFontCollection2 *This, + UINT32 index, + IDWriteFontFamily1 **family); + + /*** IDWriteFontCollection2 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFontCollection2_GetFontFamily)( + IDWriteFontCollection2 *This, + UINT32 index, + IDWriteFontFamily2 **family); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts)( + IDWriteFontCollection2 *This, + const WCHAR *familyname, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontList2 **fontlist); + + DWRITE_FONT_FAMILY_MODEL (STDMETHODCALLTYPE *GetFontFamilyModel)( + IDWriteFontCollection2 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontCollection2_GetFontSet)( + IDWriteFontCollection2 *This, + IDWriteFontSet1 **fontset); + + END_INTERFACE +} IDWriteFontCollection2Vtbl; + +interface IDWriteFontCollection2 { + CONST_VTBL IDWriteFontCollection2Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontCollection2_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontCollection2_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontCollection2_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontCollection methods ***/ +#define IDWriteFontCollection2_GetFontFamilyCount(This) (This)->lpVtbl->GetFontFamilyCount(This) +#define IDWriteFontCollection2_FindFamilyName(This,name,index,exists) (This)->lpVtbl->FindFamilyName(This,name,index,exists) +#define IDWriteFontCollection2_GetFontFromFontFace(This,face,font) (This)->lpVtbl->GetFontFromFontFace(This,face,font) +/*** IDWriteFontCollection1 methods ***/ +/*** IDWriteFontCollection2 methods ***/ +#define IDWriteFontCollection2_GetFontFamily(This,index,family) (This)->lpVtbl->IDWriteFontCollection2_GetFontFamily(This,index,family) +#define IDWriteFontCollection2_GetMatchingFonts(This,familyname,axis_values,num_values,fontlist) (This)->lpVtbl->GetMatchingFonts(This,familyname,axis_values,num_values,fontlist) +#define IDWriteFontCollection2_GetFontFamilyModel(This) (This)->lpVtbl->GetFontFamilyModel(This) +#define IDWriteFontCollection2_GetFontSet(This,fontset) (This)->lpVtbl->IDWriteFontCollection2_GetFontSet(This,fontset) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontCollection2_QueryInterface(IDWriteFontCollection2* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontCollection2_AddRef(IDWriteFontCollection2* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontCollection2_Release(IDWriteFontCollection2* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontCollection methods ***/ +static FORCEINLINE UINT32 IDWriteFontCollection2_GetFontFamilyCount(IDWriteFontCollection2* This) { + return This->lpVtbl->GetFontFamilyCount(This); +} +static FORCEINLINE HRESULT IDWriteFontCollection2_FindFamilyName(IDWriteFontCollection2* This,const WCHAR *name,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFamilyName(This,name,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontCollection2_GetFontFromFontFace(IDWriteFontCollection2* This,IDWriteFontFace *face,IDWriteFont **font) { + return This->lpVtbl->GetFontFromFontFace(This,face,font); +} +/*** IDWriteFontCollection1 methods ***/ +/*** IDWriteFontCollection2 methods ***/ +static FORCEINLINE HRESULT IDWriteFontCollection2_GetFontFamily(IDWriteFontCollection2* This,UINT32 index,IDWriteFontFamily2 **family) { + return This->lpVtbl->IDWriteFontCollection2_GetFontFamily(This,index,family); +} +static FORCEINLINE HRESULT IDWriteFontCollection2_GetMatchingFonts(IDWriteFontCollection2* This,const WCHAR *familyname,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,IDWriteFontList2 **fontlist) { + return This->lpVtbl->GetMatchingFonts(This,familyname,axis_values,num_values,fontlist); +} +static FORCEINLINE DWRITE_FONT_FAMILY_MODEL IDWriteFontCollection2_GetFontFamilyModel(IDWriteFontCollection2* This) { + return This->lpVtbl->GetFontFamilyModel(This); +} +static FORCEINLINE HRESULT IDWriteFontCollection2_GetFontSet(IDWriteFontCollection2* This,IDWriteFontSet1 **fontset) { + return This->lpVtbl->IDWriteFontCollection2_GetFontSet(This,fontset); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontCollection2_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontCollection3 interface + */ +#ifndef __IDWriteFontCollection3_INTERFACE_DEFINED__ +#define __IDWriteFontCollection3_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontCollection3, 0xa4d055a6, 0xf9e3, 0x4e25, 0x93,0xb7, 0x9e,0x30,0x9f,0x3a,0xf8,0xe9); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("a4d055a6-f9e3-4e25-93b7-9e309f3af8e9") +IDWriteFontCollection3 : public IDWriteFontCollection2 +{ + virtual HANDLE STDMETHODCALLTYPE GetExpirationEvent( + ) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontCollection3, 0xa4d055a6, 0xf9e3, 0x4e25, 0x93,0xb7, 0x9e,0x30,0x9f,0x3a,0xf8,0xe9) +#endif +#else +typedef struct IDWriteFontCollection3Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontCollection3 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontCollection3 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontCollection3 *This); + + /*** IDWriteFontCollection methods ***/ + UINT32 (STDMETHODCALLTYPE *GetFontFamilyCount)( + IDWriteFontCollection3 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFamily)( + IDWriteFontCollection3 *This, + UINT32 index, + IDWriteFontFamily **family); + + HRESULT (STDMETHODCALLTYPE *FindFamilyName)( + IDWriteFontCollection3 *This, + const WCHAR *name, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *GetFontFromFontFace)( + IDWriteFontCollection3 *This, + IDWriteFontFace *face, + IDWriteFont **font); + + /*** IDWriteFontCollection1 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontSet)( + IDWriteFontCollection3 *This, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontCollection1_GetFontFamily)( + IDWriteFontCollection3 *This, + UINT32 index, + IDWriteFontFamily1 **family); + + /*** IDWriteFontCollection2 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFontCollection2_GetFontFamily)( + IDWriteFontCollection3 *This, + UINT32 index, + IDWriteFontFamily2 **family); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts)( + IDWriteFontCollection3 *This, + const WCHAR *familyname, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontList2 **fontlist); + + DWRITE_FONT_FAMILY_MODEL (STDMETHODCALLTYPE *GetFontFamilyModel)( + IDWriteFontCollection3 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontCollection2_GetFontSet)( + IDWriteFontCollection3 *This, + IDWriteFontSet1 **fontset); + + /*** IDWriteFontCollection3 methods ***/ + HANDLE (STDMETHODCALLTYPE *GetExpirationEvent)( + IDWriteFontCollection3 *This); + + END_INTERFACE +} IDWriteFontCollection3Vtbl; + +interface IDWriteFontCollection3 { + CONST_VTBL IDWriteFontCollection3Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontCollection3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontCollection3_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontCollection3_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontCollection methods ***/ +#define IDWriteFontCollection3_GetFontFamilyCount(This) (This)->lpVtbl->GetFontFamilyCount(This) +#define IDWriteFontCollection3_FindFamilyName(This,name,index,exists) (This)->lpVtbl->FindFamilyName(This,name,index,exists) +#define IDWriteFontCollection3_GetFontFromFontFace(This,face,font) (This)->lpVtbl->GetFontFromFontFace(This,face,font) +/*** IDWriteFontCollection1 methods ***/ +/*** IDWriteFontCollection2 methods ***/ +#define IDWriteFontCollection3_GetFontFamily(This,index,family) (This)->lpVtbl->IDWriteFontCollection2_GetFontFamily(This,index,family) +#define IDWriteFontCollection3_GetMatchingFonts(This,familyname,axis_values,num_values,fontlist) (This)->lpVtbl->GetMatchingFonts(This,familyname,axis_values,num_values,fontlist) +#define IDWriteFontCollection3_GetFontFamilyModel(This) (This)->lpVtbl->GetFontFamilyModel(This) +#define IDWriteFontCollection3_GetFontSet(This,fontset) (This)->lpVtbl->IDWriteFontCollection2_GetFontSet(This,fontset) +/*** IDWriteFontCollection3 methods ***/ +#define IDWriteFontCollection3_GetExpirationEvent(This) (This)->lpVtbl->GetExpirationEvent(This) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontCollection3_QueryInterface(IDWriteFontCollection3* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontCollection3_AddRef(IDWriteFontCollection3* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontCollection3_Release(IDWriteFontCollection3* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontCollection methods ***/ +static FORCEINLINE UINT32 IDWriteFontCollection3_GetFontFamilyCount(IDWriteFontCollection3* This) { + return This->lpVtbl->GetFontFamilyCount(This); +} +static FORCEINLINE HRESULT IDWriteFontCollection3_FindFamilyName(IDWriteFontCollection3* This,const WCHAR *name,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFamilyName(This,name,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontCollection3_GetFontFromFontFace(IDWriteFontCollection3* This,IDWriteFontFace *face,IDWriteFont **font) { + return This->lpVtbl->GetFontFromFontFace(This,face,font); +} +/*** IDWriteFontCollection1 methods ***/ +/*** IDWriteFontCollection2 methods ***/ +static FORCEINLINE HRESULT IDWriteFontCollection3_GetFontFamily(IDWriteFontCollection3* This,UINT32 index,IDWriteFontFamily2 **family) { + return This->lpVtbl->IDWriteFontCollection2_GetFontFamily(This,index,family); +} +static FORCEINLINE HRESULT IDWriteFontCollection3_GetMatchingFonts(IDWriteFontCollection3* This,const WCHAR *familyname,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,IDWriteFontList2 **fontlist) { + return This->lpVtbl->GetMatchingFonts(This,familyname,axis_values,num_values,fontlist); +} +static FORCEINLINE DWRITE_FONT_FAMILY_MODEL IDWriteFontCollection3_GetFontFamilyModel(IDWriteFontCollection3* This) { + return This->lpVtbl->GetFontFamilyModel(This); +} +static FORCEINLINE HRESULT IDWriteFontCollection3_GetFontSet(IDWriteFontCollection3* This,IDWriteFontSet1 **fontset) { + return This->lpVtbl->IDWriteFontCollection2_GetFontSet(This,fontset); +} +/*** IDWriteFontCollection3 methods ***/ +static FORCEINLINE HANDLE IDWriteFontCollection3_GetExpirationEvent(IDWriteFontCollection3* This) { + return This->lpVtbl->GetExpirationEvent(This); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontCollection3_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontFaceReference interface + */ +#ifndef __IDWriteFontFaceReference_INTERFACE_DEFINED__ +#define __IDWriteFontFaceReference_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontFaceReference, 0x5e7fa7ca, 0xdde3, 0x424c, 0x89,0xf0, 0x9f,0xcd,0x6f,0xed,0x58,0xcd); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("5e7fa7ca-dde3-424c-89f0-9fcd6fed58cd") +IDWriteFontFaceReference : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE CreateFontFace( + IDWriteFontFace3 **fontface) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontFaceWithSimulations( + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFace3 **fontface) = 0; + + virtual WINBOOL STDMETHODCALLTYPE Equals( + IDWriteFontFaceReference *reference) = 0; + + virtual UINT32 STDMETHODCALLTYPE GetFontFaceIndex( + ) = 0; + + virtual DWRITE_FONT_SIMULATIONS STDMETHODCALLTYPE GetSimulations( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontFile( + IDWriteFontFile **fontfile) = 0; + + virtual UINT64 STDMETHODCALLTYPE GetLocalFileSize( + ) = 0; + + virtual UINT64 STDMETHODCALLTYPE GetFileSize( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFileTime( + FILETIME *writetime) = 0; + + virtual DWRITE_LOCALITY STDMETHODCALLTYPE GetLocality( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnqueueFontDownloadRequest( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnqueueCharacterDownloadRequest( + const WCHAR *chars, + UINT32 count) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnqueueGlyphDownloadRequest( + const UINT16 *glyphs, + UINT32 count) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnqueueFileFragmentDownloadRequest( + UINT64 offset, + UINT64 size) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontFaceReference, 0x5e7fa7ca, 0xdde3, 0x424c, 0x89,0xf0, 0x9f,0xcd,0x6f,0xed,0x58,0xcd) +#endif +#else +typedef struct IDWriteFontFaceReferenceVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontFaceReference *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontFaceReference *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontFaceReference *This); + + /*** IDWriteFontFaceReference methods ***/ + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFontFaceReference *This, + IDWriteFontFace3 **fontface); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceWithSimulations)( + IDWriteFontFaceReference *This, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFace3 **fontface); + + WINBOOL (STDMETHODCALLTYPE *Equals)( + IDWriteFontFaceReference *This, + IDWriteFontFaceReference *reference); + + UINT32 (STDMETHODCALLTYPE *GetFontFaceIndex)( + IDWriteFontFaceReference *This); + + DWRITE_FONT_SIMULATIONS (STDMETHODCALLTYPE *GetSimulations)( + IDWriteFontFaceReference *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFile)( + IDWriteFontFaceReference *This, + IDWriteFontFile **fontfile); + + UINT64 (STDMETHODCALLTYPE *GetLocalFileSize)( + IDWriteFontFaceReference *This); + + UINT64 (STDMETHODCALLTYPE *GetFileSize)( + IDWriteFontFaceReference *This); + + HRESULT (STDMETHODCALLTYPE *GetFileTime)( + IDWriteFontFaceReference *This, + FILETIME *writetime); + + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetLocality)( + IDWriteFontFaceReference *This); + + HRESULT (STDMETHODCALLTYPE *EnqueueFontDownloadRequest)( + IDWriteFontFaceReference *This); + + HRESULT (STDMETHODCALLTYPE *EnqueueCharacterDownloadRequest)( + IDWriteFontFaceReference *This, + const WCHAR *chars, + UINT32 count); + + HRESULT (STDMETHODCALLTYPE *EnqueueGlyphDownloadRequest)( + IDWriteFontFaceReference *This, + const UINT16 *glyphs, + UINT32 count); + + HRESULT (STDMETHODCALLTYPE *EnqueueFileFragmentDownloadRequest)( + IDWriteFontFaceReference *This, + UINT64 offset, + UINT64 size); + + END_INTERFACE +} IDWriteFontFaceReferenceVtbl; + +interface IDWriteFontFaceReference { + CONST_VTBL IDWriteFontFaceReferenceVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontFaceReference_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFaceReference_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFaceReference_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFaceReference methods ***/ +#define IDWriteFontFaceReference_CreateFontFace(This,fontface) (This)->lpVtbl->CreateFontFace(This,fontface) +#define IDWriteFontFaceReference_CreateFontFaceWithSimulations(This,simulations,fontface) (This)->lpVtbl->CreateFontFaceWithSimulations(This,simulations,fontface) +#define IDWriteFontFaceReference_Equals(This,reference) (This)->lpVtbl->Equals(This,reference) +#define IDWriteFontFaceReference_GetFontFaceIndex(This) (This)->lpVtbl->GetFontFaceIndex(This) +#define IDWriteFontFaceReference_GetSimulations(This) (This)->lpVtbl->GetSimulations(This) +#define IDWriteFontFaceReference_GetFontFile(This,fontfile) (This)->lpVtbl->GetFontFile(This,fontfile) +#define IDWriteFontFaceReference_GetLocalFileSize(This) (This)->lpVtbl->GetLocalFileSize(This) +#define IDWriteFontFaceReference_GetFileSize(This) (This)->lpVtbl->GetFileSize(This) +#define IDWriteFontFaceReference_GetFileTime(This,writetime) (This)->lpVtbl->GetFileTime(This,writetime) +#define IDWriteFontFaceReference_GetLocality(This) (This)->lpVtbl->GetLocality(This) +#define IDWriteFontFaceReference_EnqueueFontDownloadRequest(This) (This)->lpVtbl->EnqueueFontDownloadRequest(This) +#define IDWriteFontFaceReference_EnqueueCharacterDownloadRequest(This,chars,count) (This)->lpVtbl->EnqueueCharacterDownloadRequest(This,chars,count) +#define IDWriteFontFaceReference_EnqueueGlyphDownloadRequest(This,glyphs,count) (This)->lpVtbl->EnqueueGlyphDownloadRequest(This,glyphs,count) +#define IDWriteFontFaceReference_EnqueueFileFragmentDownloadRequest(This,offset,size) (This)->lpVtbl->EnqueueFileFragmentDownloadRequest(This,offset,size) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontFaceReference_QueryInterface(IDWriteFontFaceReference* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontFaceReference_AddRef(IDWriteFontFaceReference* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontFaceReference_Release(IDWriteFontFaceReference* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFaceReference methods ***/ +static FORCEINLINE HRESULT IDWriteFontFaceReference_CreateFontFace(IDWriteFontFaceReference* This,IDWriteFontFace3 **fontface) { + return This->lpVtbl->CreateFontFace(This,fontface); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference_CreateFontFaceWithSimulations(IDWriteFontFaceReference* This,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFace3 **fontface) { + return This->lpVtbl->CreateFontFaceWithSimulations(This,simulations,fontface); +} +static FORCEINLINE WINBOOL IDWriteFontFaceReference_Equals(IDWriteFontFaceReference* This,IDWriteFontFaceReference *reference) { + return This->lpVtbl->Equals(This,reference); +} +static FORCEINLINE UINT32 IDWriteFontFaceReference_GetFontFaceIndex(IDWriteFontFaceReference* This) { + return This->lpVtbl->GetFontFaceIndex(This); +} +static FORCEINLINE DWRITE_FONT_SIMULATIONS IDWriteFontFaceReference_GetSimulations(IDWriteFontFaceReference* This) { + return This->lpVtbl->GetSimulations(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference_GetFontFile(IDWriteFontFaceReference* This,IDWriteFontFile **fontfile) { + return This->lpVtbl->GetFontFile(This,fontfile); +} +static FORCEINLINE UINT64 IDWriteFontFaceReference_GetLocalFileSize(IDWriteFontFaceReference* This) { + return This->lpVtbl->GetLocalFileSize(This); +} +static FORCEINLINE UINT64 IDWriteFontFaceReference_GetFileSize(IDWriteFontFaceReference* This) { + return This->lpVtbl->GetFileSize(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference_GetFileTime(IDWriteFontFaceReference* This,FILETIME *writetime) { + return This->lpVtbl->GetFileTime(This,writetime); +} +static FORCEINLINE DWRITE_LOCALITY IDWriteFontFaceReference_GetLocality(IDWriteFontFaceReference* This) { + return This->lpVtbl->GetLocality(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference_EnqueueFontDownloadRequest(IDWriteFontFaceReference* This) { + return This->lpVtbl->EnqueueFontDownloadRequest(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference* This,const WCHAR *chars,UINT32 count) { + return This->lpVtbl->EnqueueCharacterDownloadRequest(This,chars,count); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference* This,const UINT16 *glyphs,UINT32 count) { + return This->lpVtbl->EnqueueGlyphDownloadRequest(This,glyphs,count); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference* This,UINT64 offset,UINT64 size) { + return This->lpVtbl->EnqueueFileFragmentDownloadRequest(This,offset,size); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontFaceReference_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontFaceReference1 interface + */ +#ifndef __IDWriteFontFaceReference1_INTERFACE_DEFINED__ +#define __IDWriteFontFaceReference1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontFaceReference1, 0xc081fe77, 0x2fd1, 0x41ac, 0xa5,0xa3, 0x34,0x98,0x3c,0x4b,0xa6,0x1a); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("c081fe77-2fd1-41ac-a5a3-34983c4ba61a") +IDWriteFontFaceReference1 : public IDWriteFontFaceReference +{ + virtual HRESULT STDMETHODCALLTYPE CreateFontFace( + IDWriteFontFace5 **fontface) = 0; + + using IDWriteFontFaceReference::CreateFontFace; + + virtual UINT32 STDMETHODCALLTYPE GetFontAxisValueCount( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontAxisValues( + DWRITE_FONT_AXIS_VALUE *values, + UINT32 num_values) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontFaceReference1, 0xc081fe77, 0x2fd1, 0x41ac, 0xa5,0xa3, 0x34,0x98,0x3c,0x4b,0xa6,0x1a) +#endif +#else +typedef struct IDWriteFontFaceReference1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontFaceReference1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontFaceReference1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontFaceReference1 *This); + + /*** IDWriteFontFaceReference methods ***/ + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFontFaceReference1 *This, + IDWriteFontFace3 **fontface); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceWithSimulations)( + IDWriteFontFaceReference1 *This, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFace3 **fontface); + + WINBOOL (STDMETHODCALLTYPE *Equals)( + IDWriteFontFaceReference1 *This, + IDWriteFontFaceReference *reference); + + UINT32 (STDMETHODCALLTYPE *GetFontFaceIndex)( + IDWriteFontFaceReference1 *This); + + DWRITE_FONT_SIMULATIONS (STDMETHODCALLTYPE *GetSimulations)( + IDWriteFontFaceReference1 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFile)( + IDWriteFontFaceReference1 *This, + IDWriteFontFile **fontfile); + + UINT64 (STDMETHODCALLTYPE *GetLocalFileSize)( + IDWriteFontFaceReference1 *This); + + UINT64 (STDMETHODCALLTYPE *GetFileSize)( + IDWriteFontFaceReference1 *This); + + HRESULT (STDMETHODCALLTYPE *GetFileTime)( + IDWriteFontFaceReference1 *This, + FILETIME *writetime); + + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetLocality)( + IDWriteFontFaceReference1 *This); + + HRESULT (STDMETHODCALLTYPE *EnqueueFontDownloadRequest)( + IDWriteFontFaceReference1 *This); + + HRESULT (STDMETHODCALLTYPE *EnqueueCharacterDownloadRequest)( + IDWriteFontFaceReference1 *This, + const WCHAR *chars, + UINT32 count); + + HRESULT (STDMETHODCALLTYPE *EnqueueGlyphDownloadRequest)( + IDWriteFontFaceReference1 *This, + const UINT16 *glyphs, + UINT32 count); + + HRESULT (STDMETHODCALLTYPE *EnqueueFileFragmentDownloadRequest)( + IDWriteFontFaceReference1 *This, + UINT64 offset, + UINT64 size); + + /*** IDWriteFontFaceReference1 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFontFaceReference1_CreateFontFace)( + IDWriteFontFaceReference1 *This, + IDWriteFontFace5 **fontface); + + UINT32 (STDMETHODCALLTYPE *GetFontAxisValueCount)( + IDWriteFontFaceReference1 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisValues)( + IDWriteFontFaceReference1 *This, + DWRITE_FONT_AXIS_VALUE *values, + UINT32 num_values); + + END_INTERFACE +} IDWriteFontFaceReference1Vtbl; + +interface IDWriteFontFaceReference1 { + CONST_VTBL IDWriteFontFaceReference1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontFaceReference1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFaceReference1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFaceReference1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFaceReference methods ***/ +#define IDWriteFontFaceReference1_CreateFontFaceWithSimulations(This,simulations,fontface) (This)->lpVtbl->CreateFontFaceWithSimulations(This,simulations,fontface) +#define IDWriteFontFaceReference1_Equals(This,reference) (This)->lpVtbl->Equals(This,reference) +#define IDWriteFontFaceReference1_GetFontFaceIndex(This) (This)->lpVtbl->GetFontFaceIndex(This) +#define IDWriteFontFaceReference1_GetSimulations(This) (This)->lpVtbl->GetSimulations(This) +#define IDWriteFontFaceReference1_GetFontFile(This,fontfile) (This)->lpVtbl->GetFontFile(This,fontfile) +#define IDWriteFontFaceReference1_GetLocalFileSize(This) (This)->lpVtbl->GetLocalFileSize(This) +#define IDWriteFontFaceReference1_GetFileSize(This) (This)->lpVtbl->GetFileSize(This) +#define IDWriteFontFaceReference1_GetFileTime(This,writetime) (This)->lpVtbl->GetFileTime(This,writetime) +#define IDWriteFontFaceReference1_GetLocality(This) (This)->lpVtbl->GetLocality(This) +#define IDWriteFontFaceReference1_EnqueueFontDownloadRequest(This) (This)->lpVtbl->EnqueueFontDownloadRequest(This) +#define IDWriteFontFaceReference1_EnqueueCharacterDownloadRequest(This,chars,count) (This)->lpVtbl->EnqueueCharacterDownloadRequest(This,chars,count) +#define IDWriteFontFaceReference1_EnqueueGlyphDownloadRequest(This,glyphs,count) (This)->lpVtbl->EnqueueGlyphDownloadRequest(This,glyphs,count) +#define IDWriteFontFaceReference1_EnqueueFileFragmentDownloadRequest(This,offset,size) (This)->lpVtbl->EnqueueFileFragmentDownloadRequest(This,offset,size) +/*** IDWriteFontFaceReference1 methods ***/ +#define IDWriteFontFaceReference1_CreateFontFace(This,fontface) (This)->lpVtbl->IDWriteFontFaceReference1_CreateFontFace(This,fontface) +#define IDWriteFontFaceReference1_GetFontAxisValueCount(This) (This)->lpVtbl->GetFontAxisValueCount(This) +#define IDWriteFontFaceReference1_GetFontAxisValues(This,values,num_values) (This)->lpVtbl->GetFontAxisValues(This,values,num_values) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontFaceReference1_QueryInterface(IDWriteFontFaceReference1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontFaceReference1_AddRef(IDWriteFontFaceReference1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontFaceReference1_Release(IDWriteFontFaceReference1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFaceReference methods ***/ +static FORCEINLINE HRESULT IDWriteFontFaceReference1_CreateFontFaceWithSimulations(IDWriteFontFaceReference1* This,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFace3 **fontface) { + return This->lpVtbl->CreateFontFaceWithSimulations(This,simulations,fontface); +} +static FORCEINLINE WINBOOL IDWriteFontFaceReference1_Equals(IDWriteFontFaceReference1* This,IDWriteFontFaceReference *reference) { + return This->lpVtbl->Equals(This,reference); +} +static FORCEINLINE UINT32 IDWriteFontFaceReference1_GetFontFaceIndex(IDWriteFontFaceReference1* This) { + return This->lpVtbl->GetFontFaceIndex(This); +} +static FORCEINLINE DWRITE_FONT_SIMULATIONS IDWriteFontFaceReference1_GetSimulations(IDWriteFontFaceReference1* This) { + return This->lpVtbl->GetSimulations(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference1_GetFontFile(IDWriteFontFaceReference1* This,IDWriteFontFile **fontfile) { + return This->lpVtbl->GetFontFile(This,fontfile); +} +static FORCEINLINE UINT64 IDWriteFontFaceReference1_GetLocalFileSize(IDWriteFontFaceReference1* This) { + return This->lpVtbl->GetLocalFileSize(This); +} +static FORCEINLINE UINT64 IDWriteFontFaceReference1_GetFileSize(IDWriteFontFaceReference1* This) { + return This->lpVtbl->GetFileSize(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference1_GetFileTime(IDWriteFontFaceReference1* This,FILETIME *writetime) { + return This->lpVtbl->GetFileTime(This,writetime); +} +static FORCEINLINE DWRITE_LOCALITY IDWriteFontFaceReference1_GetLocality(IDWriteFontFaceReference1* This) { + return This->lpVtbl->GetLocality(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference1_EnqueueFontDownloadRequest(IDWriteFontFaceReference1* This) { + return This->lpVtbl->EnqueueFontDownloadRequest(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference1_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1* This,const WCHAR *chars,UINT32 count) { + return This->lpVtbl->EnqueueCharacterDownloadRequest(This,chars,count); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference1_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1* This,const UINT16 *glyphs,UINT32 count) { + return This->lpVtbl->EnqueueGlyphDownloadRequest(This,glyphs,count); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference1_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1* This,UINT64 offset,UINT64 size) { + return This->lpVtbl->EnqueueFileFragmentDownloadRequest(This,offset,size); +} +/*** IDWriteFontFaceReference1 methods ***/ +static FORCEINLINE HRESULT IDWriteFontFaceReference1_CreateFontFace(IDWriteFontFaceReference1* This,IDWriteFontFace5 **fontface) { + return This->lpVtbl->IDWriteFontFaceReference1_CreateFontFace(This,fontface); +} +static FORCEINLINE UINT32 IDWriteFontFaceReference1_GetFontAxisValueCount(IDWriteFontFaceReference1* This) { + return This->lpVtbl->GetFontAxisValueCount(This); +} +static FORCEINLINE HRESULT IDWriteFontFaceReference1_GetFontAxisValues(IDWriteFontFaceReference1* This,DWRITE_FONT_AXIS_VALUE *values,UINT32 num_values) { + return This->lpVtbl->GetFontAxisValues(This,values,num_values); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontFaceReference1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontList1 interface + */ +#ifndef __IDWriteFontList1_INTERFACE_DEFINED__ +#define __IDWriteFontList1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontList1, 0xda20d8ef, 0x812a, 0x4c43, 0x98,0x02, 0x62,0xec,0x4a,0xbd,0x7a,0xde); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("da20d8ef-812a-4c43-9802-62ec4abd7ade") +IDWriteFontList1 : public IDWriteFontList +{ + virtual DWRITE_LOCALITY STDMETHODCALLTYPE GetFontLocality( + UINT32 index) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFont( + UINT32 index, + IDWriteFont3 **font) = 0; + + using IDWriteFontList::GetFont; + + virtual HRESULT STDMETHODCALLTYPE GetFontFaceReference( + UINT32 index, + IDWriteFontFaceReference **reference) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontList1, 0xda20d8ef, 0x812a, 0x4c43, 0x98,0x02, 0x62,0xec,0x4a,0xbd,0x7a,0xde) +#endif +#else +typedef struct IDWriteFontList1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontList1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontList1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontList1 *This); + + /*** IDWriteFontList methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontCollection)( + IDWriteFontList1 *This, + IDWriteFontCollection **collection); + + UINT32 (STDMETHODCALLTYPE *GetFontCount)( + IDWriteFontList1 *This); + + HRESULT (STDMETHODCALLTYPE *GetFont)( + IDWriteFontList1 *This, + UINT32 index, + IDWriteFont **font); + + /*** IDWriteFontList1 methods ***/ + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetFontLocality)( + IDWriteFontList1 *This, + UINT32 index); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontList1_GetFont)( + IDWriteFontList1 *This, + UINT32 index, + IDWriteFont3 **font); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontList1 *This, + UINT32 index, + IDWriteFontFaceReference **reference); + + END_INTERFACE +} IDWriteFontList1Vtbl; + +interface IDWriteFontList1 { + CONST_VTBL IDWriteFontList1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontList1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontList1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontList1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontList methods ***/ +#define IDWriteFontList1_GetFontCollection(This,collection) (This)->lpVtbl->GetFontCollection(This,collection) +#define IDWriteFontList1_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +/*** IDWriteFontList1 methods ***/ +#define IDWriteFontList1_GetFontLocality(This,index) (This)->lpVtbl->GetFontLocality(This,index) +#define IDWriteFontList1_GetFont(This,index,font) (This)->lpVtbl->IDWriteFontList1_GetFont(This,index,font) +#define IDWriteFontList1_GetFontFaceReference(This,index,reference) (This)->lpVtbl->GetFontFaceReference(This,index,reference) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontList1_QueryInterface(IDWriteFontList1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontList1_AddRef(IDWriteFontList1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontList1_Release(IDWriteFontList1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontList methods ***/ +static FORCEINLINE HRESULT IDWriteFontList1_GetFontCollection(IDWriteFontList1* This,IDWriteFontCollection **collection) { + return This->lpVtbl->GetFontCollection(This,collection); +} +static FORCEINLINE UINT32 IDWriteFontList1_GetFontCount(IDWriteFontList1* This) { + return This->lpVtbl->GetFontCount(This); +} +/*** IDWriteFontList1 methods ***/ +static FORCEINLINE DWRITE_LOCALITY IDWriteFontList1_GetFontLocality(IDWriteFontList1* This,UINT32 index) { + return This->lpVtbl->GetFontLocality(This,index); +} +static FORCEINLINE HRESULT IDWriteFontList1_GetFont(IDWriteFontList1* This,UINT32 index,IDWriteFont3 **font) { + return This->lpVtbl->IDWriteFontList1_GetFont(This,index,font); +} +static FORCEINLINE HRESULT IDWriteFontList1_GetFontFaceReference(IDWriteFontList1* This,UINT32 index,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,index,reference); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontList1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontList2 interface + */ +#ifndef __IDWriteFontList2_INTERFACE_DEFINED__ +#define __IDWriteFontList2_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontList2, 0xc0763a34, 0x77af, 0x445a, 0xb7,0x35, 0x08,0xc3,0x7b,0x0a,0x5b,0xf5); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("c0763a34-77af-445a-b735-08c37b0a5bf5") +IDWriteFontList2 : public IDWriteFontList1 +{ + virtual HRESULT STDMETHODCALLTYPE GetFontSet( + IDWriteFontSet1 **fontset) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontList2, 0xc0763a34, 0x77af, 0x445a, 0xb7,0x35, 0x08,0xc3,0x7b,0x0a,0x5b,0xf5) +#endif +#else +typedef struct IDWriteFontList2Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontList2 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontList2 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontList2 *This); + + /*** IDWriteFontList methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontCollection)( + IDWriteFontList2 *This, + IDWriteFontCollection **collection); + + UINT32 (STDMETHODCALLTYPE *GetFontCount)( + IDWriteFontList2 *This); + + HRESULT (STDMETHODCALLTYPE *GetFont)( + IDWriteFontList2 *This, + UINT32 index, + IDWriteFont **font); + + /*** IDWriteFontList1 methods ***/ + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetFontLocality)( + IDWriteFontList2 *This, + UINT32 index); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontList1_GetFont)( + IDWriteFontList2 *This, + UINT32 index, + IDWriteFont3 **font); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontList2 *This, + UINT32 index, + IDWriteFontFaceReference **reference); + + /*** IDWriteFontList2 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontSet)( + IDWriteFontList2 *This, + IDWriteFontSet1 **fontset); + + END_INTERFACE +} IDWriteFontList2Vtbl; + +interface IDWriteFontList2 { + CONST_VTBL IDWriteFontList2Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontList2_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontList2_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontList2_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontList methods ***/ +#define IDWriteFontList2_GetFontCollection(This,collection) (This)->lpVtbl->GetFontCollection(This,collection) +#define IDWriteFontList2_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +/*** IDWriteFontList1 methods ***/ +#define IDWriteFontList2_GetFontLocality(This,index) (This)->lpVtbl->GetFontLocality(This,index) +#define IDWriteFontList2_GetFont(This,index,font) (This)->lpVtbl->IDWriteFontList1_GetFont(This,index,font) +#define IDWriteFontList2_GetFontFaceReference(This,index,reference) (This)->lpVtbl->GetFontFaceReference(This,index,reference) +/*** IDWriteFontList2 methods ***/ +#define IDWriteFontList2_GetFontSet(This,fontset) (This)->lpVtbl->GetFontSet(This,fontset) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontList2_QueryInterface(IDWriteFontList2* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontList2_AddRef(IDWriteFontList2* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontList2_Release(IDWriteFontList2* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontList methods ***/ +static FORCEINLINE HRESULT IDWriteFontList2_GetFontCollection(IDWriteFontList2* This,IDWriteFontCollection **collection) { + return This->lpVtbl->GetFontCollection(This,collection); +} +static FORCEINLINE UINT32 IDWriteFontList2_GetFontCount(IDWriteFontList2* This) { + return This->lpVtbl->GetFontCount(This); +} +/*** IDWriteFontList1 methods ***/ +static FORCEINLINE DWRITE_LOCALITY IDWriteFontList2_GetFontLocality(IDWriteFontList2* This,UINT32 index) { + return This->lpVtbl->GetFontLocality(This,index); +} +static FORCEINLINE HRESULT IDWriteFontList2_GetFont(IDWriteFontList2* This,UINT32 index,IDWriteFont3 **font) { + return This->lpVtbl->IDWriteFontList1_GetFont(This,index,font); +} +static FORCEINLINE HRESULT IDWriteFontList2_GetFontFaceReference(IDWriteFontList2* This,UINT32 index,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,index,reference); +} +/*** IDWriteFontList2 methods ***/ +static FORCEINLINE HRESULT IDWriteFontList2_GetFontSet(IDWriteFontList2* This,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFontSet(This,fontset); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontList2_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontSet2 interface + */ +#ifndef __IDWriteFontSet2_INTERFACE_DEFINED__ +#define __IDWriteFontSet2_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontSet2, 0xdc7ead19, 0xe54c, 0x43af, 0xb2,0xda, 0x4e,0x2b,0x79,0xba,0x3f,0x7f); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("dc7ead19-e54c-43af-b2da-4e2b79ba3f7f") +IDWriteFontSet2 : public IDWriteFontSet1 +{ + virtual HANDLE STDMETHODCALLTYPE GetExpirationEvent( + ) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontSet2, 0xdc7ead19, 0xe54c, 0x43af, 0xb2,0xda, 0x4e,0x2b,0x79,0xba,0x3f,0x7f) +#endif +#else +typedef struct IDWriteFontSet2Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontSet2 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontSet2 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontSet2 *This); + + /*** IDWriteFontSet methods ***/ + UINT32 (STDMETHODCALLTYPE *GetFontCount)( + IDWriteFontSet2 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontSet2 *This, + UINT32 index, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *FindFontFaceReference)( + IDWriteFontSet2 *This, + IDWriteFontFaceReference *reference, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *FindFontFace)( + IDWriteFontSet2 *This, + IDWriteFontFace *fontface, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues__)( + IDWriteFontSet2 *This, + DWRITE_FONT_PROPERTY_ID id, + IDWriteStringList **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues_)( + IDWriteFontSet2 *This, + DWRITE_FONT_PROPERTY_ID id, + const WCHAR *preferred_locales, + IDWriteStringList **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues)( + IDWriteFontSet2 *This, + UINT32 index, + DWRITE_FONT_PROPERTY_ID id, + WINBOOL *exists, + IDWriteLocalizedStrings **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyOccurrenceCount)( + IDWriteFontSet2 *This, + const DWRITE_FONT_PROPERTY *property, + UINT32 *count); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts_)( + IDWriteFontSet2 *This, + const WCHAR *family, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts)( + IDWriteFontSet2 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 count, + IDWriteFontSet **fontset); + + /*** IDWriteFontSet1 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFontSet1_GetMatchingFonts)( + IDWriteFontSet2 *This, + const DWRITE_FONT_PROPERTY *property, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFirstFontResources)( + IDWriteFontSet2 *This, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts__)( + IDWriteFontSet2 *This, + const UINT32 *indices, + UINT32 num_indices, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts_)( + IDWriteFontSet2 *This, + const DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + WINBOOL select_any_range, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts)( + IDWriteFontSet2 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties, + WINBOOL select_any_property, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFontIndices_)( + IDWriteFontSet2 *This, + const DWRITE_FONT_AXIS_RANGE *ranges, + UINT32 num_ranges, + WINBOOL select_any_range, + UINT32 *indices, + UINT32 num_indices, + UINT32 *actual_num_indices); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFontIndices)( + IDWriteFontSet2 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties, + WINBOOL select_any_range, + UINT32 *indices, + UINT32 num_indices, + UINT32 *actual_num_indices); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisRanges_)( + IDWriteFontSet2 *This, + UINT32 font_index, + DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + UINT32 *actual_num_ranges); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisRanges)( + IDWriteFontSet2 *This, + DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + UINT32 *actual_num_ranges); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontSet1_GetFontFaceReference)( + IDWriteFontSet2 *This, + UINT32 index, + IDWriteFontFaceReference1 **reference); + + HRESULT (STDMETHODCALLTYPE *CreateFontResource)( + IDWriteFontSet2 *This, + UINT32 index, + IDWriteFontResource **resource); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFontSet2 *This, + UINT32 index, + IDWriteFontFace5 **fontface); + + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetFontLocality)( + IDWriteFontSet2 *This, + UINT32 index); + + /*** IDWriteFontSet2 methods ***/ + HANDLE (STDMETHODCALLTYPE *GetExpirationEvent)( + IDWriteFontSet2 *This); + + END_INTERFACE +} IDWriteFontSet2Vtbl; + +interface IDWriteFontSet2 { + CONST_VTBL IDWriteFontSet2Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontSet2_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontSet2_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontSet2_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontSet methods ***/ +#define IDWriteFontSet2_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +#define IDWriteFontSet2_FindFontFaceReference(This,reference,index,exists) (This)->lpVtbl->FindFontFaceReference(This,reference,index,exists) +#define IDWriteFontSet2_FindFontFace(This,fontface,index,exists) (This)->lpVtbl->FindFontFace(This,fontface,index,exists) +#define IDWriteFontSet2_GetPropertyValues__(This,id,values) (This)->lpVtbl->GetPropertyValues__(This,id,values) +#define IDWriteFontSet2_GetPropertyValues_(This,id,preferred_locales,values) (This)->lpVtbl->GetPropertyValues_(This,id,preferred_locales,values) +#define IDWriteFontSet2_GetPropertyValues(This,index,id,exists,values) (This)->lpVtbl->GetPropertyValues(This,index,id,exists,values) +#define IDWriteFontSet2_GetPropertyOccurrenceCount(This,property,count) (This)->lpVtbl->GetPropertyOccurrenceCount(This,property,count) +#define IDWriteFontSet2_GetMatchingFonts_(This,family,weight,stretch,style,fontset) (This)->lpVtbl->GetMatchingFonts_(This,family,weight,stretch,style,fontset) +/*** IDWriteFontSet1 methods ***/ +#define IDWriteFontSet2_GetMatchingFonts(This,property,axis_values,num_values,fontset) (This)->lpVtbl->IDWriteFontSet1_GetMatchingFonts(This,property,axis_values,num_values,fontset) +#define IDWriteFontSet2_GetFirstFontResources(This,fontset) (This)->lpVtbl->GetFirstFontResources(This,fontset) +#define IDWriteFontSet2_GetFilteredFonts__(This,indices,num_indices,fontset) (This)->lpVtbl->GetFilteredFonts__(This,indices,num_indices,fontset) +#define IDWriteFontSet2_GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset) (This)->lpVtbl->GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset) +#define IDWriteFontSet2_GetFilteredFonts(This,props,num_properties,select_any_property,fontset) (This)->lpVtbl->GetFilteredFonts(This,props,num_properties,select_any_property,fontset) +#define IDWriteFontSet2_GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices) (This)->lpVtbl->GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices) +#define IDWriteFontSet2_GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices) (This)->lpVtbl->GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices) +#define IDWriteFontSet2_GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges) (This)->lpVtbl->GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges) +#define IDWriteFontSet2_GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges) (This)->lpVtbl->GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges) +#define IDWriteFontSet2_GetFontFaceReference(This,index,reference) (This)->lpVtbl->IDWriteFontSet1_GetFontFaceReference(This,index,reference) +#define IDWriteFontSet2_CreateFontResource(This,index,resource) (This)->lpVtbl->CreateFontResource(This,index,resource) +#define IDWriteFontSet2_CreateFontFace(This,index,fontface) (This)->lpVtbl->CreateFontFace(This,index,fontface) +#define IDWriteFontSet2_GetFontLocality(This,index) (This)->lpVtbl->GetFontLocality(This,index) +/*** IDWriteFontSet2 methods ***/ +#define IDWriteFontSet2_GetExpirationEvent(This) (This)->lpVtbl->GetExpirationEvent(This) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontSet2_QueryInterface(IDWriteFontSet2* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontSet2_AddRef(IDWriteFontSet2* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontSet2_Release(IDWriteFontSet2* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontSet methods ***/ +static FORCEINLINE UINT32 IDWriteFontSet2_GetFontCount(IDWriteFontSet2* This) { + return This->lpVtbl->GetFontCount(This); +} +static FORCEINLINE HRESULT IDWriteFontSet2_FindFontFaceReference(IDWriteFontSet2* This,IDWriteFontFaceReference *reference,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFontFaceReference(This,reference,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontSet2_FindFontFace(IDWriteFontSet2* This,IDWriteFontFace *fontface,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFontFace(This,fontface,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetPropertyValues__(IDWriteFontSet2* This,DWRITE_FONT_PROPERTY_ID id,IDWriteStringList **values) { + return This->lpVtbl->GetPropertyValues__(This,id,values); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetPropertyValues_(IDWriteFontSet2* This,DWRITE_FONT_PROPERTY_ID id,const WCHAR *preferred_locales,IDWriteStringList **values) { + return This->lpVtbl->GetPropertyValues_(This,id,preferred_locales,values); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetPropertyValues(IDWriteFontSet2* This,UINT32 index,DWRITE_FONT_PROPERTY_ID id,WINBOOL *exists,IDWriteLocalizedStrings **values) { + return This->lpVtbl->GetPropertyValues(This,index,id,exists,values); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetPropertyOccurrenceCount(IDWriteFontSet2* This,const DWRITE_FONT_PROPERTY *property,UINT32 *count) { + return This->lpVtbl->GetPropertyOccurrenceCount(This,property,count); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetMatchingFonts_(IDWriteFontSet2* This,const WCHAR *family,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFontSet **fontset) { + return This->lpVtbl->GetMatchingFonts_(This,family,weight,stretch,style,fontset); +} +/*** IDWriteFontSet1 methods ***/ +static FORCEINLINE HRESULT IDWriteFontSet2_GetMatchingFonts(IDWriteFontSet2* This,const DWRITE_FONT_PROPERTY *property,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,IDWriteFontSet1 **fontset) { + return This->lpVtbl->IDWriteFontSet1_GetMatchingFonts(This,property,axis_values,num_values,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFirstFontResources(IDWriteFontSet2* This,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFirstFontResources(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFilteredFonts__(IDWriteFontSet2* This,const UINT32 *indices,UINT32 num_indices,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts__(This,indices,num_indices,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFilteredFonts_(IDWriteFontSet2* This,const DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,WINBOOL select_any_range,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFilteredFonts(IDWriteFontSet2* This,const DWRITE_FONT_PROPERTY *props,UINT32 num_properties,WINBOOL select_any_property,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts(This,props,num_properties,select_any_property,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFilteredFontIndices_(IDWriteFontSet2* This,const DWRITE_FONT_AXIS_RANGE *ranges,UINT32 num_ranges,WINBOOL select_any_range,UINT32 *indices,UINT32 num_indices,UINT32 *actual_num_indices) { + return This->lpVtbl->GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFilteredFontIndices(IDWriteFontSet2* This,const DWRITE_FONT_PROPERTY *props,UINT32 num_properties,WINBOOL select_any_range,UINT32 *indices,UINT32 num_indices,UINT32 *actual_num_indices) { + return This->lpVtbl->GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFontAxisRanges_(IDWriteFontSet2* This,UINT32 font_index,DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,UINT32 *actual_num_ranges) { + return This->lpVtbl->GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFontAxisRanges(IDWriteFontSet2* This,DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,UINT32 *actual_num_ranges) { + return This->lpVtbl->GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges); +} +static FORCEINLINE HRESULT IDWriteFontSet2_GetFontFaceReference(IDWriteFontSet2* This,UINT32 index,IDWriteFontFaceReference1 **reference) { + return This->lpVtbl->IDWriteFontSet1_GetFontFaceReference(This,index,reference); +} +static FORCEINLINE HRESULT IDWriteFontSet2_CreateFontResource(IDWriteFontSet2* This,UINT32 index,IDWriteFontResource **resource) { + return This->lpVtbl->CreateFontResource(This,index,resource); +} +static FORCEINLINE HRESULT IDWriteFontSet2_CreateFontFace(IDWriteFontSet2* This,UINT32 index,IDWriteFontFace5 **fontface) { + return This->lpVtbl->CreateFontFace(This,index,fontface); +} +static FORCEINLINE DWRITE_LOCALITY IDWriteFontSet2_GetFontLocality(IDWriteFontSet2* This,UINT32 index) { + return This->lpVtbl->GetFontLocality(This,index); +} +/*** IDWriteFontSet2 methods ***/ +static FORCEINLINE HANDLE IDWriteFontSet2_GetExpirationEvent(IDWriteFontSet2* This) { + return This->lpVtbl->GetExpirationEvent(This); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontSet2_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontSet3 interface + */ +#ifndef __IDWriteFontSet3_INTERFACE_DEFINED__ +#define __IDWriteFontSet3_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontSet3, 0x7c073ef2, 0xa7f4, 0x4045, 0x8c,0x32, 0x8a,0xb8,0xae,0x64,0x0f,0x90); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("7c073ef2-a7f4-4045-8c32-8ab8ae640f90") +IDWriteFontSet3 : public IDWriteFontSet2 +{ + virtual DWRITE_FONT_SOURCE_TYPE STDMETHODCALLTYPE GetFontSourceType( + UINT32 index) = 0; + + virtual UINT32 STDMETHODCALLTYPE GetFontSourceNameLength( + UINT32 index) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontSourceName( + UINT32 index, + WCHAR *buffer, + UINT32 buffer_size) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontSet3, 0x7c073ef2, 0xa7f4, 0x4045, 0x8c,0x32, 0x8a,0xb8,0xae,0x64,0x0f,0x90) +#endif +#else +typedef struct IDWriteFontSet3Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontSet3 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontSet3 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontSet3 *This); + + /*** IDWriteFontSet methods ***/ + UINT32 (STDMETHODCALLTYPE *GetFontCount)( + IDWriteFontSet3 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontSet3 *This, + UINT32 index, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *FindFontFaceReference)( + IDWriteFontSet3 *This, + IDWriteFontFaceReference *reference, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *FindFontFace)( + IDWriteFontSet3 *This, + IDWriteFontFace *fontface, + UINT32 *index, + WINBOOL *exists); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues__)( + IDWriteFontSet3 *This, + DWRITE_FONT_PROPERTY_ID id, + IDWriteStringList **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues_)( + IDWriteFontSet3 *This, + DWRITE_FONT_PROPERTY_ID id, + const WCHAR *preferred_locales, + IDWriteStringList **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyValues)( + IDWriteFontSet3 *This, + UINT32 index, + DWRITE_FONT_PROPERTY_ID id, + WINBOOL *exists, + IDWriteLocalizedStrings **values); + + HRESULT (STDMETHODCALLTYPE *GetPropertyOccurrenceCount)( + IDWriteFontSet3 *This, + const DWRITE_FONT_PROPERTY *property, + UINT32 *count); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts_)( + IDWriteFontSet3 *This, + const WCHAR *family, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STRETCH stretch, + DWRITE_FONT_STYLE style, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFonts)( + IDWriteFontSet3 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 count, + IDWriteFontSet **fontset); + + /*** IDWriteFontSet1 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFontSet1_GetMatchingFonts)( + IDWriteFontSet3 *This, + const DWRITE_FONT_PROPERTY *property, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFirstFontResources)( + IDWriteFontSet3 *This, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts__)( + IDWriteFontSet3 *This, + const UINT32 *indices, + UINT32 num_indices, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts_)( + IDWriteFontSet3 *This, + const DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + WINBOOL select_any_range, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFonts)( + IDWriteFontSet3 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties, + WINBOOL select_any_property, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFontIndices_)( + IDWriteFontSet3 *This, + const DWRITE_FONT_AXIS_RANGE *ranges, + UINT32 num_ranges, + WINBOOL select_any_range, + UINT32 *indices, + UINT32 num_indices, + UINT32 *actual_num_indices); + + HRESULT (STDMETHODCALLTYPE *GetFilteredFontIndices)( + IDWriteFontSet3 *This, + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties, + WINBOOL select_any_range, + UINT32 *indices, + UINT32 num_indices, + UINT32 *actual_num_indices); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisRanges_)( + IDWriteFontSet3 *This, + UINT32 font_index, + DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + UINT32 *actual_num_ranges); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisRanges)( + IDWriteFontSet3 *This, + DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + UINT32 *actual_num_ranges); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontSet1_GetFontFaceReference)( + IDWriteFontSet3 *This, + UINT32 index, + IDWriteFontFaceReference1 **reference); + + HRESULT (STDMETHODCALLTYPE *CreateFontResource)( + IDWriteFontSet3 *This, + UINT32 index, + IDWriteFontResource **resource); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFontSet3 *This, + UINT32 index, + IDWriteFontFace5 **fontface); + + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetFontLocality)( + IDWriteFontSet3 *This, + UINT32 index); + + /*** IDWriteFontSet2 methods ***/ + HANDLE (STDMETHODCALLTYPE *GetExpirationEvent)( + IDWriteFontSet3 *This); + + /*** IDWriteFontSet3 methods ***/ + DWRITE_FONT_SOURCE_TYPE (STDMETHODCALLTYPE *GetFontSourceType)( + IDWriteFontSet3 *This, + UINT32 index); + + UINT32 (STDMETHODCALLTYPE *GetFontSourceNameLength)( + IDWriteFontSet3 *This, + UINT32 index); + + HRESULT (STDMETHODCALLTYPE *GetFontSourceName)( + IDWriteFontSet3 *This, + UINT32 index, + WCHAR *buffer, + UINT32 buffer_size); + + END_INTERFACE +} IDWriteFontSet3Vtbl; + +interface IDWriteFontSet3 { + CONST_VTBL IDWriteFontSet3Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontSet3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontSet3_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontSet3_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontSet methods ***/ +#define IDWriteFontSet3_GetFontCount(This) (This)->lpVtbl->GetFontCount(This) +#define IDWriteFontSet3_FindFontFaceReference(This,reference,index,exists) (This)->lpVtbl->FindFontFaceReference(This,reference,index,exists) +#define IDWriteFontSet3_FindFontFace(This,fontface,index,exists) (This)->lpVtbl->FindFontFace(This,fontface,index,exists) +#define IDWriteFontSet3_GetPropertyValues__(This,id,values) (This)->lpVtbl->GetPropertyValues__(This,id,values) +#define IDWriteFontSet3_GetPropertyValues_(This,id,preferred_locales,values) (This)->lpVtbl->GetPropertyValues_(This,id,preferred_locales,values) +#define IDWriteFontSet3_GetPropertyValues(This,index,id,exists,values) (This)->lpVtbl->GetPropertyValues(This,index,id,exists,values) +#define IDWriteFontSet3_GetPropertyOccurrenceCount(This,property,count) (This)->lpVtbl->GetPropertyOccurrenceCount(This,property,count) +#define IDWriteFontSet3_GetMatchingFonts_(This,family,weight,stretch,style,fontset) (This)->lpVtbl->GetMatchingFonts_(This,family,weight,stretch,style,fontset) +/*** IDWriteFontSet1 methods ***/ +#define IDWriteFontSet3_GetMatchingFonts(This,property,axis_values,num_values,fontset) (This)->lpVtbl->IDWriteFontSet1_GetMatchingFonts(This,property,axis_values,num_values,fontset) +#define IDWriteFontSet3_GetFirstFontResources(This,fontset) (This)->lpVtbl->GetFirstFontResources(This,fontset) +#define IDWriteFontSet3_GetFilteredFonts__(This,indices,num_indices,fontset) (This)->lpVtbl->GetFilteredFonts__(This,indices,num_indices,fontset) +#define IDWriteFontSet3_GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset) (This)->lpVtbl->GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset) +#define IDWriteFontSet3_GetFilteredFonts(This,props,num_properties,select_any_property,fontset) (This)->lpVtbl->GetFilteredFonts(This,props,num_properties,select_any_property,fontset) +#define IDWriteFontSet3_GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices) (This)->lpVtbl->GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices) +#define IDWriteFontSet3_GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices) (This)->lpVtbl->GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices) +#define IDWriteFontSet3_GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges) (This)->lpVtbl->GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges) +#define IDWriteFontSet3_GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges) (This)->lpVtbl->GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges) +#define IDWriteFontSet3_GetFontFaceReference(This,index,reference) (This)->lpVtbl->IDWriteFontSet1_GetFontFaceReference(This,index,reference) +#define IDWriteFontSet3_CreateFontResource(This,index,resource) (This)->lpVtbl->CreateFontResource(This,index,resource) +#define IDWriteFontSet3_CreateFontFace(This,index,fontface) (This)->lpVtbl->CreateFontFace(This,index,fontface) +#define IDWriteFontSet3_GetFontLocality(This,index) (This)->lpVtbl->GetFontLocality(This,index) +/*** IDWriteFontSet2 methods ***/ +#define IDWriteFontSet3_GetExpirationEvent(This) (This)->lpVtbl->GetExpirationEvent(This) +/*** IDWriteFontSet3 methods ***/ +#define IDWriteFontSet3_GetFontSourceType(This,index) (This)->lpVtbl->GetFontSourceType(This,index) +#define IDWriteFontSet3_GetFontSourceNameLength(This,index) (This)->lpVtbl->GetFontSourceNameLength(This,index) +#define IDWriteFontSet3_GetFontSourceName(This,index,buffer,buffer_size) (This)->lpVtbl->GetFontSourceName(This,index,buffer,buffer_size) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontSet3_QueryInterface(IDWriteFontSet3* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontSet3_AddRef(IDWriteFontSet3* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontSet3_Release(IDWriteFontSet3* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontSet methods ***/ +static FORCEINLINE UINT32 IDWriteFontSet3_GetFontCount(IDWriteFontSet3* This) { + return This->lpVtbl->GetFontCount(This); +} +static FORCEINLINE HRESULT IDWriteFontSet3_FindFontFaceReference(IDWriteFontSet3* This,IDWriteFontFaceReference *reference,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFontFaceReference(This,reference,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontSet3_FindFontFace(IDWriteFontSet3* This,IDWriteFontFace *fontface,UINT32 *index,WINBOOL *exists) { + return This->lpVtbl->FindFontFace(This,fontface,index,exists); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetPropertyValues__(IDWriteFontSet3* This,DWRITE_FONT_PROPERTY_ID id,IDWriteStringList **values) { + return This->lpVtbl->GetPropertyValues__(This,id,values); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetPropertyValues_(IDWriteFontSet3* This,DWRITE_FONT_PROPERTY_ID id,const WCHAR *preferred_locales,IDWriteStringList **values) { + return This->lpVtbl->GetPropertyValues_(This,id,preferred_locales,values); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetPropertyValues(IDWriteFontSet3* This,UINT32 index,DWRITE_FONT_PROPERTY_ID id,WINBOOL *exists,IDWriteLocalizedStrings **values) { + return This->lpVtbl->GetPropertyValues(This,index,id,exists,values); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetPropertyOccurrenceCount(IDWriteFontSet3* This,const DWRITE_FONT_PROPERTY *property,UINT32 *count) { + return This->lpVtbl->GetPropertyOccurrenceCount(This,property,count); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetMatchingFonts_(IDWriteFontSet3* This,const WCHAR *family,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFontSet **fontset) { + return This->lpVtbl->GetMatchingFonts_(This,family,weight,stretch,style,fontset); +} +/*** IDWriteFontSet1 methods ***/ +static FORCEINLINE HRESULT IDWriteFontSet3_GetMatchingFonts(IDWriteFontSet3* This,const DWRITE_FONT_PROPERTY *property,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,IDWriteFontSet1 **fontset) { + return This->lpVtbl->IDWriteFontSet1_GetMatchingFonts(This,property,axis_values,num_values,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFirstFontResources(IDWriteFontSet3* This,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFirstFontResources(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFilteredFonts__(IDWriteFontSet3* This,const UINT32 *indices,UINT32 num_indices,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts__(This,indices,num_indices,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFilteredFonts_(IDWriteFontSet3* This,const DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,WINBOOL select_any_range,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts_(This,axis_ranges,num_ranges,select_any_range,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFilteredFonts(IDWriteFontSet3* This,const DWRITE_FONT_PROPERTY *props,UINT32 num_properties,WINBOOL select_any_property,IDWriteFontSet1 **fontset) { + return This->lpVtbl->GetFilteredFonts(This,props,num_properties,select_any_property,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFilteredFontIndices_(IDWriteFontSet3* This,const DWRITE_FONT_AXIS_RANGE *ranges,UINT32 num_ranges,WINBOOL select_any_range,UINT32 *indices,UINT32 num_indices,UINT32 *actual_num_indices) { + return This->lpVtbl->GetFilteredFontIndices_(This,ranges,num_ranges,select_any_range,indices,num_indices,actual_num_indices); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFilteredFontIndices(IDWriteFontSet3* This,const DWRITE_FONT_PROPERTY *props,UINT32 num_properties,WINBOOL select_any_range,UINT32 *indices,UINT32 num_indices,UINT32 *actual_num_indices) { + return This->lpVtbl->GetFilteredFontIndices(This,props,num_properties,select_any_range,indices,num_indices,actual_num_indices); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFontAxisRanges_(IDWriteFontSet3* This,UINT32 font_index,DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,UINT32 *actual_num_ranges) { + return This->lpVtbl->GetFontAxisRanges_(This,font_index,axis_ranges,num_ranges,actual_num_ranges); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFontAxisRanges(IDWriteFontSet3* This,DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,UINT32 *actual_num_ranges) { + return This->lpVtbl->GetFontAxisRanges(This,axis_ranges,num_ranges,actual_num_ranges); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFontFaceReference(IDWriteFontSet3* This,UINT32 index,IDWriteFontFaceReference1 **reference) { + return This->lpVtbl->IDWriteFontSet1_GetFontFaceReference(This,index,reference); +} +static FORCEINLINE HRESULT IDWriteFontSet3_CreateFontResource(IDWriteFontSet3* This,UINT32 index,IDWriteFontResource **resource) { + return This->lpVtbl->CreateFontResource(This,index,resource); +} +static FORCEINLINE HRESULT IDWriteFontSet3_CreateFontFace(IDWriteFontSet3* This,UINT32 index,IDWriteFontFace5 **fontface) { + return This->lpVtbl->CreateFontFace(This,index,fontface); +} +static FORCEINLINE DWRITE_LOCALITY IDWriteFontSet3_GetFontLocality(IDWriteFontSet3* This,UINT32 index) { + return This->lpVtbl->GetFontLocality(This,index); +} +/*** IDWriteFontSet2 methods ***/ +static FORCEINLINE HANDLE IDWriteFontSet3_GetExpirationEvent(IDWriteFontSet3* This) { + return This->lpVtbl->GetExpirationEvent(This); +} +/*** IDWriteFontSet3 methods ***/ +static FORCEINLINE DWRITE_FONT_SOURCE_TYPE IDWriteFontSet3_GetFontSourceType(IDWriteFontSet3* This,UINT32 index) { + return This->lpVtbl->GetFontSourceType(This,index); +} +static FORCEINLINE UINT32 IDWriteFontSet3_GetFontSourceNameLength(IDWriteFontSet3* This,UINT32 index) { + return This->lpVtbl->GetFontSourceNameLength(This,index); +} +static FORCEINLINE HRESULT IDWriteFontSet3_GetFontSourceName(IDWriteFontSet3* This,UINT32 index,WCHAR *buffer,UINT32 buffer_size) { + return This->lpVtbl->GetFontSourceName(This,index,buffer,buffer_size); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontSet3_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontFace3 interface + */ +#ifndef __IDWriteFontFace3_INTERFACE_DEFINED__ +#define __IDWriteFontFace3_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontFace3, 0xd37d7598, 0x09be, 0x4222, 0xa2,0x36, 0x20,0x81,0x34,0x1c,0xc1,0xf2); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("d37d7598-09be-4222-a236-2081341cc1f2") +IDWriteFontFace3 : public IDWriteFontFace2 +{ + virtual HRESULT STDMETHODCALLTYPE GetFontFaceReference( + IDWriteFontFaceReference **reference) = 0; + + virtual void STDMETHODCALLTYPE GetPanose( + DWRITE_PANOSE *panose) = 0; + + virtual DWRITE_FONT_WEIGHT STDMETHODCALLTYPE GetWeight( + ) = 0; + + virtual DWRITE_FONT_STRETCH STDMETHODCALLTYPE GetStretch( + ) = 0; + + virtual DWRITE_FONT_STYLE STDMETHODCALLTYPE GetStyle( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFamilyNames( + IDWriteLocalizedStrings **names) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFaceNames( + IDWriteLocalizedStrings **names) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInformationalStrings( + DWRITE_INFORMATIONAL_STRING_ID stringid, + IDWriteLocalizedStrings **strings, + WINBOOL *exists) = 0; + + virtual WINBOOL STDMETHODCALLTYPE HasCharacter( + UINT32 character) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetRecommendedRenderingMode( + FLOAT emsize, + FLOAT dpi_x, + FLOAT dpi_y, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuring_mode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE1 *rendering_mode, + DWRITE_GRID_FIT_MODE *gridfit_mode) = 0; + + virtual WINBOOL STDMETHODCALLTYPE IsCharacterLocal( + UINT32 character) = 0; + + virtual WINBOOL STDMETHODCALLTYPE IsGlyphLocal( + UINT16 glyph) = 0; + + virtual HRESULT STDMETHODCALLTYPE AreCharactersLocal( + const WCHAR *characters, + UINT32 count, + WINBOOL enqueue_if_not, + WINBOOL *are_local) = 0; + + virtual HRESULT STDMETHODCALLTYPE AreGlyphsLocal( + const UINT16 *glyphs, + UINT32 count, + WINBOOL enqueue_if_not, + WINBOOL *are_local) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontFace3, 0xd37d7598, 0x09be, 0x4222, 0xa2,0x36, 0x20,0x81,0x34,0x1c,0xc1,0xf2) +#endif +#else +typedef struct IDWriteFontFace3Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontFace3 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontFace3 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontFace3 *This); + + /*** IDWriteFontFace methods ***/ + DWRITE_FONT_FACE_TYPE (STDMETHODCALLTYPE *GetType)( + IDWriteFontFace3 *This); + + HRESULT (STDMETHODCALLTYPE *GetFiles)( + IDWriteFontFace3 *This, + UINT32 *number_of_files, + IDWriteFontFile **fontfiles); + + UINT32 (STDMETHODCALLTYPE *GetIndex)( + IDWriteFontFace3 *This); + + DWRITE_FONT_SIMULATIONS (STDMETHODCALLTYPE *GetSimulations)( + IDWriteFontFace3 *This); + + WINBOOL (STDMETHODCALLTYPE *IsSymbolFont)( + IDWriteFontFace3 *This); + + void (STDMETHODCALLTYPE *GetMetrics)( + IDWriteFontFace3 *This, + DWRITE_FONT_METRICS *metrics); + + UINT16 (STDMETHODCALLTYPE *GetGlyphCount)( + IDWriteFontFace3 *This); + + HRESULT (STDMETHODCALLTYPE *GetDesignGlyphMetrics)( + IDWriteFontFace3 *This, + const UINT16 *glyph_indices, + UINT32 glyph_count, + DWRITE_GLYPH_METRICS *metrics, + WINBOOL is_sideways); + + HRESULT (STDMETHODCALLTYPE *GetGlyphIndices)( + IDWriteFontFace3 *This, + const UINT32 *codepoints, + UINT32 count, + UINT16 *glyph_indices); + + HRESULT (STDMETHODCALLTYPE *TryGetFontTable)( + IDWriteFontFace3 *This, + UINT32 table_tag, + const void **table_data, + UINT32 *table_size, + void **context, + WINBOOL *exists); + + void (STDMETHODCALLTYPE *ReleaseFontTable)( + IDWriteFontFace3 *This, + void *table_context); + + HRESULT (STDMETHODCALLTYPE *GetGlyphRunOutline)( + IDWriteFontFace3 *This, + FLOAT emSize, + const UINT16 *glyph_indices, + const FLOAT *glyph_advances, + const DWRITE_GLYPH_OFFSET *glyph_offsets, + UINT32 glyph_count, + WINBOOL is_sideways, + WINBOOL is_rtl, + IDWriteGeometrySink *geometrysink); + + HRESULT (STDMETHODCALLTYPE *GetRecommendedRenderingMode)( + IDWriteFontFace3 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + DWRITE_MEASURING_MODE mode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE *rendering_mode); + + using IDWriteFontFace2::GetRecommendedRenderingMode; + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleMetrics)( + IDWriteFontFace3 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_FONT_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleGlyphMetrics)( + IDWriteFontFace3 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + const UINT16 *glyph_indices, + UINT32 glyph_count, + DWRITE_GLYPH_METRICS *metrics, + WINBOOL is_sideways); + + /*** IDWriteFontFace1 methods ***/ + void (STDMETHODCALLTYPE *IDWriteFontFace1_GetMetrics)( + IDWriteFontFace3 *This, + DWRITE_FONT_METRICS1 *metrics); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace1_GetGdiCompatibleMetrics)( + IDWriteFontFace3 *This, + FLOAT em_size, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_FONT_METRICS1 *metrics); + + void (STDMETHODCALLTYPE *GetCaretMetrics)( + IDWriteFontFace3 *This, + DWRITE_CARET_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *GetUnicodeRanges)( + IDWriteFontFace3 *This, + UINT32 max_count, + DWRITE_UNICODE_RANGE *ranges, + UINT32 *count); + + WINBOOL (STDMETHODCALLTYPE *IsMonospacedFont)( + IDWriteFontFace3 *This); + + HRESULT (STDMETHODCALLTYPE *GetDesignGlyphAdvances)( + IDWriteFontFace3 *This, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *advances, + WINBOOL is_sideways); + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleGlyphAdvances)( + IDWriteFontFace3 *This, + FLOAT em_size, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + WINBOOL is_sideways, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *advances); + + HRESULT (STDMETHODCALLTYPE *GetKerningPairAdjustments)( + IDWriteFontFace3 *This, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *adjustments); + + WINBOOL (STDMETHODCALLTYPE *HasKerningPairs)( + IDWriteFontFace3 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace1_GetRecommendedRenderingMode)( + IDWriteFontFace3 *This, + FLOAT font_emsize, + FLOAT dpiX, + FLOAT dpiY, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_RENDERING_MODE *rendering_mode); + + HRESULT (STDMETHODCALLTYPE *GetVerticalGlyphVariants)( + IDWriteFontFace3 *This, + UINT32 glyph_count, + const UINT16 *nominal_indices, + UINT16 *vertical_indices); + + WINBOOL (STDMETHODCALLTYPE *HasVerticalGlyphVariants)( + IDWriteFontFace3 *This); + + /*** IDWriteFontFace2 methods ***/ + WINBOOL (STDMETHODCALLTYPE *IsColorFont)( + IDWriteFontFace3 *This); + + UINT32 (STDMETHODCALLTYPE *GetColorPaletteCount)( + IDWriteFontFace3 *This); + + UINT32 (STDMETHODCALLTYPE *GetPaletteEntryCount)( + IDWriteFontFace3 *This); + + HRESULT (STDMETHODCALLTYPE *GetPaletteEntries)( + IDWriteFontFace3 *This, + UINT32 palette_index, + UINT32 first_entry_index, + UINT32 entry_count, + DWRITE_COLOR_F *entries); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace2_GetRecommendedRenderingMode)( + IDWriteFontFace3 *This, + FLOAT fontEmSize, + FLOAT dpiX, + FLOAT dpiY, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuringmode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE *renderingmode, + DWRITE_GRID_FIT_MODE *gridfitmode); + + /*** IDWriteFontFace3 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontFace3 *This, + IDWriteFontFaceReference **reference); + + void (STDMETHODCALLTYPE *GetPanose)( + IDWriteFontFace3 *This, + DWRITE_PANOSE *panose); + + DWRITE_FONT_WEIGHT (STDMETHODCALLTYPE *GetWeight)( + IDWriteFontFace3 *This); + + DWRITE_FONT_STRETCH (STDMETHODCALLTYPE *GetStretch)( + IDWriteFontFace3 *This); + + DWRITE_FONT_STYLE (STDMETHODCALLTYPE *GetStyle)( + IDWriteFontFace3 *This); + + HRESULT (STDMETHODCALLTYPE *GetFamilyNames)( + IDWriteFontFace3 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetFaceNames)( + IDWriteFontFace3 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetInformationalStrings)( + IDWriteFontFace3 *This, + DWRITE_INFORMATIONAL_STRING_ID stringid, + IDWriteLocalizedStrings **strings, + WINBOOL *exists); + + WINBOOL (STDMETHODCALLTYPE *HasCharacter)( + IDWriteFontFace3 *This, + UINT32 character); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace3_GetRecommendedRenderingMode)( + IDWriteFontFace3 *This, + FLOAT emsize, + FLOAT dpi_x, + FLOAT dpi_y, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuring_mode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE1 *rendering_mode, + DWRITE_GRID_FIT_MODE *gridfit_mode); + + WINBOOL (STDMETHODCALLTYPE *IsCharacterLocal)( + IDWriteFontFace3 *This, + UINT32 character); + + WINBOOL (STDMETHODCALLTYPE *IsGlyphLocal)( + IDWriteFontFace3 *This, + UINT16 glyph); + + HRESULT (STDMETHODCALLTYPE *AreCharactersLocal)( + IDWriteFontFace3 *This, + const WCHAR *characters, + UINT32 count, + WINBOOL enqueue_if_not, + WINBOOL *are_local); + + HRESULT (STDMETHODCALLTYPE *AreGlyphsLocal)( + IDWriteFontFace3 *This, + const UINT16 *glyphs, + UINT32 count, + WINBOOL enqueue_if_not, + WINBOOL *are_local); + + END_INTERFACE +} IDWriteFontFace3Vtbl; + +interface IDWriteFontFace3 { + CONST_VTBL IDWriteFontFace3Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontFace3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFace3_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFace3_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFace methods ***/ +#define IDWriteFontFace3_GetType(This) (This)->lpVtbl->GetType(This) +#define IDWriteFontFace3_GetFiles(This,number_of_files,fontfiles) (This)->lpVtbl->GetFiles(This,number_of_files,fontfiles) +#define IDWriteFontFace3_GetIndex(This) (This)->lpVtbl->GetIndex(This) +#define IDWriteFontFace3_GetSimulations(This) (This)->lpVtbl->GetSimulations(This) +#define IDWriteFontFace3_IsSymbolFont(This) (This)->lpVtbl->IsSymbolFont(This) +#define IDWriteFontFace3_GetGlyphCount(This) (This)->lpVtbl->GetGlyphCount(This) +#define IDWriteFontFace3_GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways) (This)->lpVtbl->GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways) +#define IDWriteFontFace3_GetGlyphIndices(This,codepoints,count,glyph_indices) (This)->lpVtbl->GetGlyphIndices(This,codepoints,count,glyph_indices) +#define IDWriteFontFace3_TryGetFontTable(This,table_tag,table_data,table_size,context,exists) (This)->lpVtbl->TryGetFontTable(This,table_tag,table_data,table_size,context,exists) +#define IDWriteFontFace3_ReleaseFontTable(This,table_context) (This)->lpVtbl->ReleaseFontTable(This,table_context) +#define IDWriteFontFace3_GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink) (This)->lpVtbl->GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink) +#define IDWriteFontFace3_GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways) (This)->lpVtbl->GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways) +/*** IDWriteFontFace1 methods ***/ +#define IDWriteFontFace3_GetMetrics(This,metrics) (This)->lpVtbl->IDWriteFontFace1_GetMetrics(This,metrics) +#define IDWriteFontFace3_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics) (This)->lpVtbl->IDWriteFontFace1_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics) +#define IDWriteFontFace3_GetCaretMetrics(This,metrics) (This)->lpVtbl->GetCaretMetrics(This,metrics) +#define IDWriteFontFace3_GetUnicodeRanges(This,max_count,ranges,count) (This)->lpVtbl->GetUnicodeRanges(This,max_count,ranges,count) +#define IDWriteFontFace3_IsMonospacedFont(This) (This)->lpVtbl->IsMonospacedFont(This) +#define IDWriteFontFace3_GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways) (This)->lpVtbl->GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways) +#define IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances) (This)->lpVtbl->GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances) +#define IDWriteFontFace3_GetKerningPairAdjustments(This,glyph_count,indices,adjustments) (This)->lpVtbl->GetKerningPairAdjustments(This,glyph_count,indices,adjustments) +#define IDWriteFontFace3_HasKerningPairs(This) (This)->lpVtbl->HasKerningPairs(This) +#define IDWriteFontFace3_GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices) (This)->lpVtbl->GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices) +#define IDWriteFontFace3_HasVerticalGlyphVariants(This) (This)->lpVtbl->HasVerticalGlyphVariants(This) +/*** IDWriteFontFace2 methods ***/ +#define IDWriteFontFace3_IsColorFont(This) (This)->lpVtbl->IsColorFont(This) +#define IDWriteFontFace3_GetColorPaletteCount(This) (This)->lpVtbl->GetColorPaletteCount(This) +#define IDWriteFontFace3_GetPaletteEntryCount(This) (This)->lpVtbl->GetPaletteEntryCount(This) +#define IDWriteFontFace3_GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries) (This)->lpVtbl->GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries) +/*** IDWriteFontFace3 methods ***/ +#define IDWriteFontFace3_GetFontFaceReference(This,reference) (This)->lpVtbl->GetFontFaceReference(This,reference) +#define IDWriteFontFace3_GetPanose(This,panose) (This)->lpVtbl->GetPanose(This,panose) +#define IDWriteFontFace3_GetWeight(This) (This)->lpVtbl->GetWeight(This) +#define IDWriteFontFace3_GetStretch(This) (This)->lpVtbl->GetStretch(This) +#define IDWriteFontFace3_GetStyle(This) (This)->lpVtbl->GetStyle(This) +#define IDWriteFontFace3_GetFamilyNames(This,names) (This)->lpVtbl->GetFamilyNames(This,names) +#define IDWriteFontFace3_GetFaceNames(This,names) (This)->lpVtbl->GetFaceNames(This,names) +#define IDWriteFontFace3_GetInformationalStrings(This,stringid,strings,exists) (This)->lpVtbl->GetInformationalStrings(This,stringid,strings,exists) +#define IDWriteFontFace3_HasCharacter(This,character) (This)->lpVtbl->HasCharacter(This,character) +#define IDWriteFontFace3_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode) (This)->lpVtbl->IDWriteFontFace3_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode) +#define IDWriteFontFace3_IsCharacterLocal(This,character) (This)->lpVtbl->IsCharacterLocal(This,character) +#define IDWriteFontFace3_IsGlyphLocal(This,glyph) (This)->lpVtbl->IsGlyphLocal(This,glyph) +#define IDWriteFontFace3_AreCharactersLocal(This,characters,count,enqueue_if_not,are_local) (This)->lpVtbl->AreCharactersLocal(This,characters,count,enqueue_if_not,are_local) +#define IDWriteFontFace3_AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local) (This)->lpVtbl->AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontFace3_QueryInterface(IDWriteFontFace3* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontFace3_AddRef(IDWriteFontFace3* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontFace3_Release(IDWriteFontFace3* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFace methods ***/ +static FORCEINLINE DWRITE_FONT_FACE_TYPE IDWriteFontFace3_GetType(IDWriteFontFace3* This) { + return This->lpVtbl->GetType(This); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetFiles(IDWriteFontFace3* This,UINT32 *number_of_files,IDWriteFontFile **fontfiles) { + return This->lpVtbl->GetFiles(This,number_of_files,fontfiles); +} +static FORCEINLINE UINT32 IDWriteFontFace3_GetIndex(IDWriteFontFace3* This) { + return This->lpVtbl->GetIndex(This); +} +static FORCEINLINE DWRITE_FONT_SIMULATIONS IDWriteFontFace3_GetSimulations(IDWriteFontFace3* This) { + return This->lpVtbl->GetSimulations(This); +} +static FORCEINLINE WINBOOL IDWriteFontFace3_IsSymbolFont(IDWriteFontFace3* This) { + return This->lpVtbl->IsSymbolFont(This); +} +static FORCEINLINE UINT16 IDWriteFontFace3_GetGlyphCount(IDWriteFontFace3* This) { + return This->lpVtbl->GetGlyphCount(This); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetDesignGlyphMetrics(IDWriteFontFace3* This,const UINT16 *glyph_indices,UINT32 glyph_count,DWRITE_GLYPH_METRICS *metrics,WINBOOL is_sideways) { + return This->lpVtbl->GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetGlyphIndices(IDWriteFontFace3* This,const UINT32 *codepoints,UINT32 count,UINT16 *glyph_indices) { + return This->lpVtbl->GetGlyphIndices(This,codepoints,count,glyph_indices); +} +static FORCEINLINE HRESULT IDWriteFontFace3_TryGetFontTable(IDWriteFontFace3* This,UINT32 table_tag,const void **table_data,UINT32 *table_size,void **context,WINBOOL *exists) { + return This->lpVtbl->TryGetFontTable(This,table_tag,table_data,table_size,context,exists); +} +static FORCEINLINE void IDWriteFontFace3_ReleaseFontTable(IDWriteFontFace3* This,void *table_context) { + This->lpVtbl->ReleaseFontTable(This,table_context); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetGlyphRunOutline(IDWriteFontFace3* This,FLOAT emSize,const UINT16 *glyph_indices,const FLOAT *glyph_advances,const DWRITE_GLYPH_OFFSET *glyph_offsets,UINT32 glyph_count,WINBOOL is_sideways,WINBOOL is_rtl,IDWriteGeometrySink *geometrysink) { + return This->lpVtbl->GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetGdiCompatibleGlyphMetrics(IDWriteFontFace3* This,FLOAT emSize,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,const UINT16 *glyph_indices,UINT32 glyph_count,DWRITE_GLYPH_METRICS *metrics,WINBOOL is_sideways) { + return This->lpVtbl->GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways); +} +/*** IDWriteFontFace1 methods ***/ +static FORCEINLINE void IDWriteFontFace3_GetMetrics(IDWriteFontFace3* This,DWRITE_FONT_METRICS1 *metrics) { + This->lpVtbl->IDWriteFontFace1_GetMetrics(This,metrics); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetGdiCompatibleMetrics(IDWriteFontFace3* This,FLOAT em_size,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,DWRITE_FONT_METRICS1 *metrics) { + return This->lpVtbl->IDWriteFontFace1_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics); +} +static FORCEINLINE void IDWriteFontFace3_GetCaretMetrics(IDWriteFontFace3* This,DWRITE_CARET_METRICS *metrics) { + This->lpVtbl->GetCaretMetrics(This,metrics); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetUnicodeRanges(IDWriteFontFace3* This,UINT32 max_count,DWRITE_UNICODE_RANGE *ranges,UINT32 *count) { + return This->lpVtbl->GetUnicodeRanges(This,max_count,ranges,count); +} +static FORCEINLINE WINBOOL IDWriteFontFace3_IsMonospacedFont(IDWriteFontFace3* This) { + return This->lpVtbl->IsMonospacedFont(This); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetDesignGlyphAdvances(IDWriteFontFace3* This,UINT32 glyph_count,const UINT16 *indices,INT32 *advances,WINBOOL is_sideways) { + return This->lpVtbl->GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(IDWriteFontFace3* This,FLOAT em_size,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,WINBOOL is_sideways,UINT32 glyph_count,const UINT16 *indices,INT32 *advances) { + return This->lpVtbl->GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetKerningPairAdjustments(IDWriteFontFace3* This,UINT32 glyph_count,const UINT16 *indices,INT32 *adjustments) { + return This->lpVtbl->GetKerningPairAdjustments(This,glyph_count,indices,adjustments); +} +static FORCEINLINE WINBOOL IDWriteFontFace3_HasKerningPairs(IDWriteFontFace3* This) { + return This->lpVtbl->HasKerningPairs(This); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetVerticalGlyphVariants(IDWriteFontFace3* This,UINT32 glyph_count,const UINT16 *nominal_indices,UINT16 *vertical_indices) { + return This->lpVtbl->GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices); +} +static FORCEINLINE WINBOOL IDWriteFontFace3_HasVerticalGlyphVariants(IDWriteFontFace3* This) { + return This->lpVtbl->HasVerticalGlyphVariants(This); +} +/*** IDWriteFontFace2 methods ***/ +static FORCEINLINE WINBOOL IDWriteFontFace3_IsColorFont(IDWriteFontFace3* This) { + return This->lpVtbl->IsColorFont(This); +} +static FORCEINLINE UINT32 IDWriteFontFace3_GetColorPaletteCount(IDWriteFontFace3* This) { + return This->lpVtbl->GetColorPaletteCount(This); +} +static FORCEINLINE UINT32 IDWriteFontFace3_GetPaletteEntryCount(IDWriteFontFace3* This) { + return This->lpVtbl->GetPaletteEntryCount(This); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetPaletteEntries(IDWriteFontFace3* This,UINT32 palette_index,UINT32 first_entry_index,UINT32 entry_count,DWRITE_COLOR_F *entries) { + return This->lpVtbl->GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries); +} +/*** IDWriteFontFace3 methods ***/ +static FORCEINLINE HRESULT IDWriteFontFace3_GetFontFaceReference(IDWriteFontFace3* This,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,reference); +} +static FORCEINLINE void IDWriteFontFace3_GetPanose(IDWriteFontFace3* This,DWRITE_PANOSE *panose) { + This->lpVtbl->GetPanose(This,panose); +} +static FORCEINLINE DWRITE_FONT_WEIGHT IDWriteFontFace3_GetWeight(IDWriteFontFace3* This) { + return This->lpVtbl->GetWeight(This); +} +static FORCEINLINE DWRITE_FONT_STRETCH IDWriteFontFace3_GetStretch(IDWriteFontFace3* This) { + return This->lpVtbl->GetStretch(This); +} +static FORCEINLINE DWRITE_FONT_STYLE IDWriteFontFace3_GetStyle(IDWriteFontFace3* This) { + return This->lpVtbl->GetStyle(This); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetFamilyNames(IDWriteFontFace3* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFamilyNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetFaceNames(IDWriteFontFace3* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFaceNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetInformationalStrings(IDWriteFontFace3* This,DWRITE_INFORMATIONAL_STRING_ID stringid,IDWriteLocalizedStrings **strings,WINBOOL *exists) { + return This->lpVtbl->GetInformationalStrings(This,stringid,strings,exists); +} +static FORCEINLINE WINBOOL IDWriteFontFace3_HasCharacter(IDWriteFontFace3* This,UINT32 character) { + return This->lpVtbl->HasCharacter(This,character); +} +static FORCEINLINE HRESULT IDWriteFontFace3_GetRecommendedRenderingMode(IDWriteFontFace3* This,FLOAT emsize,FLOAT dpi_x,FLOAT dpi_y,const DWRITE_MATRIX *transform,WINBOOL is_sideways,DWRITE_OUTLINE_THRESHOLD threshold,DWRITE_MEASURING_MODE measuring_mode,IDWriteRenderingParams *params,DWRITE_RENDERING_MODE1 *rendering_mode,DWRITE_GRID_FIT_MODE *gridfit_mode) { + return This->lpVtbl->IDWriteFontFace3_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode); +} +static FORCEINLINE WINBOOL IDWriteFontFace3_IsCharacterLocal(IDWriteFontFace3* This,UINT32 character) { + return This->lpVtbl->IsCharacterLocal(This,character); +} +static FORCEINLINE WINBOOL IDWriteFontFace3_IsGlyphLocal(IDWriteFontFace3* This,UINT16 glyph) { + return This->lpVtbl->IsGlyphLocal(This,glyph); +} +static FORCEINLINE HRESULT IDWriteFontFace3_AreCharactersLocal(IDWriteFontFace3* This,const WCHAR *characters,UINT32 count,WINBOOL enqueue_if_not,WINBOOL *are_local) { + return This->lpVtbl->AreCharactersLocal(This,characters,count,enqueue_if_not,are_local); +} +static FORCEINLINE HRESULT IDWriteFontFace3_AreGlyphsLocal(IDWriteFontFace3* This,const UINT16 *glyphs,UINT32 count,WINBOOL enqueue_if_not,WINBOOL *are_local) { + return This->lpVtbl->AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontFace3_INTERFACE_DEFINED__ */ + +typedef struct DWRITE_LINE_METRICS1 { + UINT32 length; + UINT32 trailingWhitespaceLength; + UINT32 newlineLength; + FLOAT height; + FLOAT baseline; + WINBOOL isTrimmed; + FLOAT leadingBefore; + FLOAT leadingAfter; +} DWRITE_LINE_METRICS1; +typedef enum DWRITE_FONT_LINE_GAP_USAGE { + DWRITE_FONT_LINE_GAP_USAGE_DEFAULT = 0, + DWRITE_FONT_LINE_GAP_USAGE_DISABLED = 1, + DWRITE_FONT_LINE_GAP_USAGE_ENABLED = 2 +} DWRITE_FONT_LINE_GAP_USAGE; +typedef struct DWRITE_LINE_SPACING { + DWRITE_LINE_SPACING_METHOD method; + FLOAT height; + FLOAT baseline; + FLOAT leadingBefore; + DWRITE_FONT_LINE_GAP_USAGE fontLineGapUsage; +} DWRITE_LINE_SPACING; +/***************************************************************************** + * IDWriteTextFormat2 interface + */ +#ifndef __IDWriteTextFormat2_INTERFACE_DEFINED__ +#define __IDWriteTextFormat2_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteTextFormat2, 0xf67e0edd, 0x9e3d, 0x4ecc, 0x8c,0x32, 0x41,0x83,0x25,0x3d,0xfe,0x70); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("f67e0edd-9e3d-4ecc-8c32-4183253dfe70") +IDWriteTextFormat2 : public IDWriteTextFormat1 +{ + virtual HRESULT STDMETHODCALLTYPE SetLineSpacing( + const DWRITE_LINE_SPACING *spacing) = 0; + + using IDWriteTextFormat1::SetLineSpacing; + + virtual HRESULT STDMETHODCALLTYPE GetLineSpacing( + DWRITE_LINE_SPACING *spacing) = 0; + + using IDWriteTextFormat1::GetLineSpacing; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteTextFormat2, 0xf67e0edd, 0x9e3d, 0x4ecc, 0x8c,0x32, 0x41,0x83,0x25,0x3d,0xfe,0x70) +#endif +#else +typedef struct IDWriteTextFormat2Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteTextFormat2 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteTextFormat2 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteTextFormat2 *This); + + /*** IDWriteTextFormat methods ***/ + HRESULT (STDMETHODCALLTYPE *SetTextAlignment)( + IDWriteTextFormat2 *This, + DWRITE_TEXT_ALIGNMENT alignment); + + HRESULT (STDMETHODCALLTYPE *SetParagraphAlignment)( + IDWriteTextFormat2 *This, + DWRITE_PARAGRAPH_ALIGNMENT alignment); + + HRESULT (STDMETHODCALLTYPE *SetWordWrapping)( + IDWriteTextFormat2 *This, + DWRITE_WORD_WRAPPING wrapping); + + HRESULT (STDMETHODCALLTYPE *SetReadingDirection)( + IDWriteTextFormat2 *This, + DWRITE_READING_DIRECTION direction); + + HRESULT (STDMETHODCALLTYPE *SetFlowDirection)( + IDWriteTextFormat2 *This, + DWRITE_FLOW_DIRECTION direction); + + HRESULT (STDMETHODCALLTYPE *SetIncrementalTabStop)( + IDWriteTextFormat2 *This, + FLOAT tabstop); + + HRESULT (STDMETHODCALLTYPE *SetTrimming)( + IDWriteTextFormat2 *This, + const DWRITE_TRIMMING *trimming, + IDWriteInlineObject *trimming_sign); + + HRESULT (STDMETHODCALLTYPE *SetLineSpacing)( + IDWriteTextFormat2 *This, + DWRITE_LINE_SPACING_METHOD spacing, + FLOAT line_spacing, + FLOAT baseline); + + DWRITE_TEXT_ALIGNMENT (STDMETHODCALLTYPE *GetTextAlignment)( + IDWriteTextFormat2 *This); + + DWRITE_PARAGRAPH_ALIGNMENT (STDMETHODCALLTYPE *GetParagraphAlignment)( + IDWriteTextFormat2 *This); + + DWRITE_WORD_WRAPPING (STDMETHODCALLTYPE *GetWordWrapping)( + IDWriteTextFormat2 *This); + + DWRITE_READING_DIRECTION (STDMETHODCALLTYPE *GetReadingDirection)( + IDWriteTextFormat2 *This); + + DWRITE_FLOW_DIRECTION (STDMETHODCALLTYPE *GetFlowDirection)( + IDWriteTextFormat2 *This); + + FLOAT (STDMETHODCALLTYPE *GetIncrementalTabStop)( + IDWriteTextFormat2 *This); + + HRESULT (STDMETHODCALLTYPE *GetTrimming)( + IDWriteTextFormat2 *This, + DWRITE_TRIMMING *options, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *GetLineSpacing)( + IDWriteTextFormat2 *This, + DWRITE_LINE_SPACING_METHOD *method, + FLOAT *spacing, + FLOAT *baseline); + + HRESULT (STDMETHODCALLTYPE *GetFontCollection)( + IDWriteTextFormat2 *This, + IDWriteFontCollection **collection); + + UINT32 (STDMETHODCALLTYPE *GetFontFamilyNameLength)( + IDWriteTextFormat2 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFamilyName)( + IDWriteTextFormat2 *This, + WCHAR *name, + UINT32 size); + + DWRITE_FONT_WEIGHT (STDMETHODCALLTYPE *GetFontWeight)( + IDWriteTextFormat2 *This); + + DWRITE_FONT_STYLE (STDMETHODCALLTYPE *GetFontStyle)( + IDWriteTextFormat2 *This); + + DWRITE_FONT_STRETCH (STDMETHODCALLTYPE *GetFontStretch)( + IDWriteTextFormat2 *This); + + FLOAT (STDMETHODCALLTYPE *GetFontSize)( + IDWriteTextFormat2 *This); + + UINT32 (STDMETHODCALLTYPE *GetLocaleNameLength)( + IDWriteTextFormat2 *This); + + HRESULT (STDMETHODCALLTYPE *GetLocaleName)( + IDWriteTextFormat2 *This, + WCHAR *name, + UINT32 size); + + /*** IDWriteTextFormat1 methods ***/ + HRESULT (STDMETHODCALLTYPE *SetVerticalGlyphOrientation)( + IDWriteTextFormat2 *This, + DWRITE_VERTICAL_GLYPH_ORIENTATION orientation); + + DWRITE_VERTICAL_GLYPH_ORIENTATION (STDMETHODCALLTYPE *GetVerticalGlyphOrientation)( + IDWriteTextFormat2 *This); + + HRESULT (STDMETHODCALLTYPE *SetLastLineWrapping)( + IDWriteTextFormat2 *This, + WINBOOL lastline_wrapping_enabled); + + WINBOOL (STDMETHODCALLTYPE *GetLastLineWrapping)( + IDWriteTextFormat2 *This); + + HRESULT (STDMETHODCALLTYPE *SetOpticalAlignment)( + IDWriteTextFormat2 *This, + DWRITE_OPTICAL_ALIGNMENT alignment); + + DWRITE_OPTICAL_ALIGNMENT (STDMETHODCALLTYPE *GetOpticalAlignment)( + IDWriteTextFormat2 *This); + + HRESULT (STDMETHODCALLTYPE *SetFontFallback)( + IDWriteTextFormat2 *This, + IDWriteFontFallback *fallback); + + HRESULT (STDMETHODCALLTYPE *GetFontFallback)( + IDWriteTextFormat2 *This, + IDWriteFontFallback **fallback); + + /*** IDWriteTextFormat2 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteTextFormat2_SetLineSpacing)( + IDWriteTextFormat2 *This, + const DWRITE_LINE_SPACING *spacing); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextFormat2_GetLineSpacing)( + IDWriteTextFormat2 *This, + DWRITE_LINE_SPACING *spacing); + + END_INTERFACE +} IDWriteTextFormat2Vtbl; + +interface IDWriteTextFormat2 { + CONST_VTBL IDWriteTextFormat2Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteTextFormat2_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteTextFormat2_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteTextFormat2_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteTextFormat methods ***/ +#define IDWriteTextFormat2_SetTextAlignment(This,alignment) (This)->lpVtbl->SetTextAlignment(This,alignment) +#define IDWriteTextFormat2_SetParagraphAlignment(This,alignment) (This)->lpVtbl->SetParagraphAlignment(This,alignment) +#define IDWriteTextFormat2_SetWordWrapping(This,wrapping) (This)->lpVtbl->SetWordWrapping(This,wrapping) +#define IDWriteTextFormat2_SetReadingDirection(This,direction) (This)->lpVtbl->SetReadingDirection(This,direction) +#define IDWriteTextFormat2_SetFlowDirection(This,direction) (This)->lpVtbl->SetFlowDirection(This,direction) +#define IDWriteTextFormat2_SetIncrementalTabStop(This,tabstop) (This)->lpVtbl->SetIncrementalTabStop(This,tabstop) +#define IDWriteTextFormat2_SetTrimming(This,trimming,trimming_sign) (This)->lpVtbl->SetTrimming(This,trimming,trimming_sign) +#define IDWriteTextFormat2_GetTextAlignment(This) (This)->lpVtbl->GetTextAlignment(This) +#define IDWriteTextFormat2_GetParagraphAlignment(This) (This)->lpVtbl->GetParagraphAlignment(This) +#define IDWriteTextFormat2_GetWordWrapping(This) (This)->lpVtbl->GetWordWrapping(This) +#define IDWriteTextFormat2_GetReadingDirection(This) (This)->lpVtbl->GetReadingDirection(This) +#define IDWriteTextFormat2_GetFlowDirection(This) (This)->lpVtbl->GetFlowDirection(This) +#define IDWriteTextFormat2_GetIncrementalTabStop(This) (This)->lpVtbl->GetIncrementalTabStop(This) +#define IDWriteTextFormat2_GetTrimming(This,options,trimming_sign) (This)->lpVtbl->GetTrimming(This,options,trimming_sign) +#define IDWriteTextFormat2_GetFontCollection(This,collection) (This)->lpVtbl->GetFontCollection(This,collection) +#define IDWriteTextFormat2_GetFontFamilyNameLength(This) (This)->lpVtbl->GetFontFamilyNameLength(This) +#define IDWriteTextFormat2_GetFontFamilyName(This,name,size) (This)->lpVtbl->GetFontFamilyName(This,name,size) +#define IDWriteTextFormat2_GetFontWeight(This) (This)->lpVtbl->GetFontWeight(This) +#define IDWriteTextFormat2_GetFontStyle(This) (This)->lpVtbl->GetFontStyle(This) +#define IDWriteTextFormat2_GetFontStretch(This) (This)->lpVtbl->GetFontStretch(This) +#define IDWriteTextFormat2_GetFontSize(This) (This)->lpVtbl->GetFontSize(This) +#define IDWriteTextFormat2_GetLocaleNameLength(This) (This)->lpVtbl->GetLocaleNameLength(This) +#define IDWriteTextFormat2_GetLocaleName(This,name,size) (This)->lpVtbl->GetLocaleName(This,name,size) +/*** IDWriteTextFormat1 methods ***/ +#define IDWriteTextFormat2_SetVerticalGlyphOrientation(This,orientation) (This)->lpVtbl->SetVerticalGlyphOrientation(This,orientation) +#define IDWriteTextFormat2_GetVerticalGlyphOrientation(This) (This)->lpVtbl->GetVerticalGlyphOrientation(This) +#define IDWriteTextFormat2_SetLastLineWrapping(This,lastline_wrapping_enabled) (This)->lpVtbl->SetLastLineWrapping(This,lastline_wrapping_enabled) +#define IDWriteTextFormat2_GetLastLineWrapping(This) (This)->lpVtbl->GetLastLineWrapping(This) +#define IDWriteTextFormat2_SetOpticalAlignment(This,alignment) (This)->lpVtbl->SetOpticalAlignment(This,alignment) +#define IDWriteTextFormat2_GetOpticalAlignment(This) (This)->lpVtbl->GetOpticalAlignment(This) +#define IDWriteTextFormat2_SetFontFallback(This,fallback) (This)->lpVtbl->SetFontFallback(This,fallback) +#define IDWriteTextFormat2_GetFontFallback(This,fallback) (This)->lpVtbl->GetFontFallback(This,fallback) +/*** IDWriteTextFormat2 methods ***/ +#define IDWriteTextFormat2_SetLineSpacing(This,spacing) (This)->lpVtbl->IDWriteTextFormat2_SetLineSpacing(This,spacing) +#define IDWriteTextFormat2_GetLineSpacing(This,spacing) (This)->lpVtbl->IDWriteTextFormat2_GetLineSpacing(This,spacing) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat2_QueryInterface(IDWriteTextFormat2* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteTextFormat2_AddRef(IDWriteTextFormat2* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteTextFormat2_Release(IDWriteTextFormat2* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteTextFormat methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat2_SetTextAlignment(IDWriteTextFormat2* This,DWRITE_TEXT_ALIGNMENT alignment) { + return This->lpVtbl->SetTextAlignment(This,alignment); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetParagraphAlignment(IDWriteTextFormat2* This,DWRITE_PARAGRAPH_ALIGNMENT alignment) { + return This->lpVtbl->SetParagraphAlignment(This,alignment); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetWordWrapping(IDWriteTextFormat2* This,DWRITE_WORD_WRAPPING wrapping) { + return This->lpVtbl->SetWordWrapping(This,wrapping); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetReadingDirection(IDWriteTextFormat2* This,DWRITE_READING_DIRECTION direction) { + return This->lpVtbl->SetReadingDirection(This,direction); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetFlowDirection(IDWriteTextFormat2* This,DWRITE_FLOW_DIRECTION direction) { + return This->lpVtbl->SetFlowDirection(This,direction); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetIncrementalTabStop(IDWriteTextFormat2* This,FLOAT tabstop) { + return This->lpVtbl->SetIncrementalTabStop(This,tabstop); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetTrimming(IDWriteTextFormat2* This,const DWRITE_TRIMMING *trimming,IDWriteInlineObject *trimming_sign) { + return This->lpVtbl->SetTrimming(This,trimming,trimming_sign); +} +static FORCEINLINE DWRITE_TEXT_ALIGNMENT IDWriteTextFormat2_GetTextAlignment(IDWriteTextFormat2* This) { + return This->lpVtbl->GetTextAlignment(This); +} +static FORCEINLINE DWRITE_PARAGRAPH_ALIGNMENT IDWriteTextFormat2_GetParagraphAlignment(IDWriteTextFormat2* This) { + return This->lpVtbl->GetParagraphAlignment(This); +} +static FORCEINLINE DWRITE_WORD_WRAPPING IDWriteTextFormat2_GetWordWrapping(IDWriteTextFormat2* This) { + return This->lpVtbl->GetWordWrapping(This); +} +static FORCEINLINE DWRITE_READING_DIRECTION IDWriteTextFormat2_GetReadingDirection(IDWriteTextFormat2* This) { + return This->lpVtbl->GetReadingDirection(This); +} +static FORCEINLINE DWRITE_FLOW_DIRECTION IDWriteTextFormat2_GetFlowDirection(IDWriteTextFormat2* This) { + return This->lpVtbl->GetFlowDirection(This); +} +static FORCEINLINE FLOAT IDWriteTextFormat2_GetIncrementalTabStop(IDWriteTextFormat2* This) { + return This->lpVtbl->GetIncrementalTabStop(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_GetTrimming(IDWriteTextFormat2* This,DWRITE_TRIMMING *options,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->GetTrimming(This,options,trimming_sign); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_GetFontCollection(IDWriteTextFormat2* This,IDWriteFontCollection **collection) { + return This->lpVtbl->GetFontCollection(This,collection); +} +static FORCEINLINE UINT32 IDWriteTextFormat2_GetFontFamilyNameLength(IDWriteTextFormat2* This) { + return This->lpVtbl->GetFontFamilyNameLength(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_GetFontFamilyName(IDWriteTextFormat2* This,WCHAR *name,UINT32 size) { + return This->lpVtbl->GetFontFamilyName(This,name,size); +} +static FORCEINLINE DWRITE_FONT_WEIGHT IDWriteTextFormat2_GetFontWeight(IDWriteTextFormat2* This) { + return This->lpVtbl->GetFontWeight(This); +} +static FORCEINLINE DWRITE_FONT_STYLE IDWriteTextFormat2_GetFontStyle(IDWriteTextFormat2* This) { + return This->lpVtbl->GetFontStyle(This); +} +static FORCEINLINE DWRITE_FONT_STRETCH IDWriteTextFormat2_GetFontStretch(IDWriteTextFormat2* This) { + return This->lpVtbl->GetFontStretch(This); +} +static FORCEINLINE FLOAT IDWriteTextFormat2_GetFontSize(IDWriteTextFormat2* This) { + return This->lpVtbl->GetFontSize(This); +} +static FORCEINLINE UINT32 IDWriteTextFormat2_GetLocaleNameLength(IDWriteTextFormat2* This) { + return This->lpVtbl->GetLocaleNameLength(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_GetLocaleName(IDWriteTextFormat2* This,WCHAR *name,UINT32 size) { + return This->lpVtbl->GetLocaleName(This,name,size); +} +/*** IDWriteTextFormat1 methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat2_SetVerticalGlyphOrientation(IDWriteTextFormat2* This,DWRITE_VERTICAL_GLYPH_ORIENTATION orientation) { + return This->lpVtbl->SetVerticalGlyphOrientation(This,orientation); +} +static FORCEINLINE DWRITE_VERTICAL_GLYPH_ORIENTATION IDWriteTextFormat2_GetVerticalGlyphOrientation(IDWriteTextFormat2* This) { + return This->lpVtbl->GetVerticalGlyphOrientation(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetLastLineWrapping(IDWriteTextFormat2* This,WINBOOL lastline_wrapping_enabled) { + return This->lpVtbl->SetLastLineWrapping(This,lastline_wrapping_enabled); +} +static FORCEINLINE WINBOOL IDWriteTextFormat2_GetLastLineWrapping(IDWriteTextFormat2* This) { + return This->lpVtbl->GetLastLineWrapping(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetOpticalAlignment(IDWriteTextFormat2* This,DWRITE_OPTICAL_ALIGNMENT alignment) { + return This->lpVtbl->SetOpticalAlignment(This,alignment); +} +static FORCEINLINE DWRITE_OPTICAL_ALIGNMENT IDWriteTextFormat2_GetOpticalAlignment(IDWriteTextFormat2* This) { + return This->lpVtbl->GetOpticalAlignment(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_SetFontFallback(IDWriteTextFormat2* This,IDWriteFontFallback *fallback) { + return This->lpVtbl->SetFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_GetFontFallback(IDWriteTextFormat2* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetFontFallback(This,fallback); +} +/*** IDWriteTextFormat2 methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat2_SetLineSpacing(IDWriteTextFormat2* This,const DWRITE_LINE_SPACING *spacing) { + return This->lpVtbl->IDWriteTextFormat2_SetLineSpacing(This,spacing); +} +static FORCEINLINE HRESULT IDWriteTextFormat2_GetLineSpacing(IDWriteTextFormat2* This,DWRITE_LINE_SPACING *spacing) { + return This->lpVtbl->IDWriteTextFormat2_GetLineSpacing(This,spacing); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteTextFormat2_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteTextFormat3 interface + */ +#ifndef __IDWriteTextFormat3_INTERFACE_DEFINED__ +#define __IDWriteTextFormat3_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteTextFormat3, 0x6d3b5641, 0xe550, 0x430d, 0xa8,0x5b, 0xb7,0xbf,0x48,0xa9,0x34,0x27); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("6d3b5641-e550-430d-a85b-b7bf48a93427") +IDWriteTextFormat3 : public IDWriteTextFormat2 +{ + virtual HRESULT STDMETHODCALLTYPE SetFontAxisValues( + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values) = 0; + + virtual UINT32 STDMETHODCALLTYPE GetFontAxisValueCount( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontAxisValues( + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values) = 0; + + virtual DWRITE_AUTOMATIC_FONT_AXES STDMETHODCALLTYPE GetAutomaticFontAxes( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAutomaticFontAxes( + DWRITE_AUTOMATIC_FONT_AXES axes) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteTextFormat3, 0x6d3b5641, 0xe550, 0x430d, 0xa8,0x5b, 0xb7,0xbf,0x48,0xa9,0x34,0x27) +#endif +#else +typedef struct IDWriteTextFormat3Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteTextFormat3 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteTextFormat3 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteTextFormat3 *This); + + /*** IDWriteTextFormat methods ***/ + HRESULT (STDMETHODCALLTYPE *SetTextAlignment)( + IDWriteTextFormat3 *This, + DWRITE_TEXT_ALIGNMENT alignment); + + HRESULT (STDMETHODCALLTYPE *SetParagraphAlignment)( + IDWriteTextFormat3 *This, + DWRITE_PARAGRAPH_ALIGNMENT alignment); + + HRESULT (STDMETHODCALLTYPE *SetWordWrapping)( + IDWriteTextFormat3 *This, + DWRITE_WORD_WRAPPING wrapping); + + HRESULT (STDMETHODCALLTYPE *SetReadingDirection)( + IDWriteTextFormat3 *This, + DWRITE_READING_DIRECTION direction); + + HRESULT (STDMETHODCALLTYPE *SetFlowDirection)( + IDWriteTextFormat3 *This, + DWRITE_FLOW_DIRECTION direction); + + HRESULT (STDMETHODCALLTYPE *SetIncrementalTabStop)( + IDWriteTextFormat3 *This, + FLOAT tabstop); + + HRESULT (STDMETHODCALLTYPE *SetTrimming)( + IDWriteTextFormat3 *This, + const DWRITE_TRIMMING *trimming, + IDWriteInlineObject *trimming_sign); + + HRESULT (STDMETHODCALLTYPE *SetLineSpacing)( + IDWriteTextFormat3 *This, + DWRITE_LINE_SPACING_METHOD spacing, + FLOAT line_spacing, + FLOAT baseline); + + DWRITE_TEXT_ALIGNMENT (STDMETHODCALLTYPE *GetTextAlignment)( + IDWriteTextFormat3 *This); + + DWRITE_PARAGRAPH_ALIGNMENT (STDMETHODCALLTYPE *GetParagraphAlignment)( + IDWriteTextFormat3 *This); + + DWRITE_WORD_WRAPPING (STDMETHODCALLTYPE *GetWordWrapping)( + IDWriteTextFormat3 *This); + + DWRITE_READING_DIRECTION (STDMETHODCALLTYPE *GetReadingDirection)( + IDWriteTextFormat3 *This); + + DWRITE_FLOW_DIRECTION (STDMETHODCALLTYPE *GetFlowDirection)( + IDWriteTextFormat3 *This); + + FLOAT (STDMETHODCALLTYPE *GetIncrementalTabStop)( + IDWriteTextFormat3 *This); + + HRESULT (STDMETHODCALLTYPE *GetTrimming)( + IDWriteTextFormat3 *This, + DWRITE_TRIMMING *options, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *GetLineSpacing)( + IDWriteTextFormat3 *This, + DWRITE_LINE_SPACING_METHOD *method, + FLOAT *spacing, + FLOAT *baseline); + + HRESULT (STDMETHODCALLTYPE *GetFontCollection)( + IDWriteTextFormat3 *This, + IDWriteFontCollection **collection); + + UINT32 (STDMETHODCALLTYPE *GetFontFamilyNameLength)( + IDWriteTextFormat3 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFamilyName)( + IDWriteTextFormat3 *This, + WCHAR *name, + UINT32 size); + + DWRITE_FONT_WEIGHT (STDMETHODCALLTYPE *GetFontWeight)( + IDWriteTextFormat3 *This); + + DWRITE_FONT_STYLE (STDMETHODCALLTYPE *GetFontStyle)( + IDWriteTextFormat3 *This); + + DWRITE_FONT_STRETCH (STDMETHODCALLTYPE *GetFontStretch)( + IDWriteTextFormat3 *This); + + FLOAT (STDMETHODCALLTYPE *GetFontSize)( + IDWriteTextFormat3 *This); + + UINT32 (STDMETHODCALLTYPE *GetLocaleNameLength)( + IDWriteTextFormat3 *This); + + HRESULT (STDMETHODCALLTYPE *GetLocaleName)( + IDWriteTextFormat3 *This, + WCHAR *name, + UINT32 size); + + /*** IDWriteTextFormat1 methods ***/ + HRESULT (STDMETHODCALLTYPE *SetVerticalGlyphOrientation)( + IDWriteTextFormat3 *This, + DWRITE_VERTICAL_GLYPH_ORIENTATION orientation); + + DWRITE_VERTICAL_GLYPH_ORIENTATION (STDMETHODCALLTYPE *GetVerticalGlyphOrientation)( + IDWriteTextFormat3 *This); + + HRESULT (STDMETHODCALLTYPE *SetLastLineWrapping)( + IDWriteTextFormat3 *This, + WINBOOL lastline_wrapping_enabled); + + WINBOOL (STDMETHODCALLTYPE *GetLastLineWrapping)( + IDWriteTextFormat3 *This); + + HRESULT (STDMETHODCALLTYPE *SetOpticalAlignment)( + IDWriteTextFormat3 *This, + DWRITE_OPTICAL_ALIGNMENT alignment); + + DWRITE_OPTICAL_ALIGNMENT (STDMETHODCALLTYPE *GetOpticalAlignment)( + IDWriteTextFormat3 *This); + + HRESULT (STDMETHODCALLTYPE *SetFontFallback)( + IDWriteTextFormat3 *This, + IDWriteFontFallback *fallback); + + HRESULT (STDMETHODCALLTYPE *GetFontFallback)( + IDWriteTextFormat3 *This, + IDWriteFontFallback **fallback); + + /*** IDWriteTextFormat2 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteTextFormat2_SetLineSpacing)( + IDWriteTextFormat3 *This, + const DWRITE_LINE_SPACING *spacing); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextFormat2_GetLineSpacing)( + IDWriteTextFormat3 *This, + DWRITE_LINE_SPACING *spacing); + + /*** IDWriteTextFormat3 methods ***/ + HRESULT (STDMETHODCALLTYPE *SetFontAxisValues)( + IDWriteTextFormat3 *This, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values); + + UINT32 (STDMETHODCALLTYPE *GetFontAxisValueCount)( + IDWriteTextFormat3 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisValues)( + IDWriteTextFormat3 *This, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values); + + DWRITE_AUTOMATIC_FONT_AXES (STDMETHODCALLTYPE *GetAutomaticFontAxes)( + IDWriteTextFormat3 *This); + + HRESULT (STDMETHODCALLTYPE *SetAutomaticFontAxes)( + IDWriteTextFormat3 *This, + DWRITE_AUTOMATIC_FONT_AXES axes); + + END_INTERFACE +} IDWriteTextFormat3Vtbl; + +interface IDWriteTextFormat3 { + CONST_VTBL IDWriteTextFormat3Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteTextFormat3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteTextFormat3_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteTextFormat3_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteTextFormat methods ***/ +#define IDWriteTextFormat3_SetTextAlignment(This,alignment) (This)->lpVtbl->SetTextAlignment(This,alignment) +#define IDWriteTextFormat3_SetParagraphAlignment(This,alignment) (This)->lpVtbl->SetParagraphAlignment(This,alignment) +#define IDWriteTextFormat3_SetWordWrapping(This,wrapping) (This)->lpVtbl->SetWordWrapping(This,wrapping) +#define IDWriteTextFormat3_SetReadingDirection(This,direction) (This)->lpVtbl->SetReadingDirection(This,direction) +#define IDWriteTextFormat3_SetFlowDirection(This,direction) (This)->lpVtbl->SetFlowDirection(This,direction) +#define IDWriteTextFormat3_SetIncrementalTabStop(This,tabstop) (This)->lpVtbl->SetIncrementalTabStop(This,tabstop) +#define IDWriteTextFormat3_SetTrimming(This,trimming,trimming_sign) (This)->lpVtbl->SetTrimming(This,trimming,trimming_sign) +#define IDWriteTextFormat3_GetTextAlignment(This) (This)->lpVtbl->GetTextAlignment(This) +#define IDWriteTextFormat3_GetParagraphAlignment(This) (This)->lpVtbl->GetParagraphAlignment(This) +#define IDWriteTextFormat3_GetWordWrapping(This) (This)->lpVtbl->GetWordWrapping(This) +#define IDWriteTextFormat3_GetReadingDirection(This) (This)->lpVtbl->GetReadingDirection(This) +#define IDWriteTextFormat3_GetFlowDirection(This) (This)->lpVtbl->GetFlowDirection(This) +#define IDWriteTextFormat3_GetIncrementalTabStop(This) (This)->lpVtbl->GetIncrementalTabStop(This) +#define IDWriteTextFormat3_GetTrimming(This,options,trimming_sign) (This)->lpVtbl->GetTrimming(This,options,trimming_sign) +#define IDWriteTextFormat3_GetFontCollection(This,collection) (This)->lpVtbl->GetFontCollection(This,collection) +#define IDWriteTextFormat3_GetFontFamilyNameLength(This) (This)->lpVtbl->GetFontFamilyNameLength(This) +#define IDWriteTextFormat3_GetFontFamilyName(This,name,size) (This)->lpVtbl->GetFontFamilyName(This,name,size) +#define IDWriteTextFormat3_GetFontWeight(This) (This)->lpVtbl->GetFontWeight(This) +#define IDWriteTextFormat3_GetFontStyle(This) (This)->lpVtbl->GetFontStyle(This) +#define IDWriteTextFormat3_GetFontStretch(This) (This)->lpVtbl->GetFontStretch(This) +#define IDWriteTextFormat3_GetFontSize(This) (This)->lpVtbl->GetFontSize(This) +#define IDWriteTextFormat3_GetLocaleNameLength(This) (This)->lpVtbl->GetLocaleNameLength(This) +#define IDWriteTextFormat3_GetLocaleName(This,name,size) (This)->lpVtbl->GetLocaleName(This,name,size) +/*** IDWriteTextFormat1 methods ***/ +#define IDWriteTextFormat3_SetVerticalGlyphOrientation(This,orientation) (This)->lpVtbl->SetVerticalGlyphOrientation(This,orientation) +#define IDWriteTextFormat3_GetVerticalGlyphOrientation(This) (This)->lpVtbl->GetVerticalGlyphOrientation(This) +#define IDWriteTextFormat3_SetLastLineWrapping(This,lastline_wrapping_enabled) (This)->lpVtbl->SetLastLineWrapping(This,lastline_wrapping_enabled) +#define IDWriteTextFormat3_GetLastLineWrapping(This) (This)->lpVtbl->GetLastLineWrapping(This) +#define IDWriteTextFormat3_SetOpticalAlignment(This,alignment) (This)->lpVtbl->SetOpticalAlignment(This,alignment) +#define IDWriteTextFormat3_GetOpticalAlignment(This) (This)->lpVtbl->GetOpticalAlignment(This) +#define IDWriteTextFormat3_SetFontFallback(This,fallback) (This)->lpVtbl->SetFontFallback(This,fallback) +#define IDWriteTextFormat3_GetFontFallback(This,fallback) (This)->lpVtbl->GetFontFallback(This,fallback) +/*** IDWriteTextFormat2 methods ***/ +#define IDWriteTextFormat3_SetLineSpacing(This,spacing) (This)->lpVtbl->IDWriteTextFormat2_SetLineSpacing(This,spacing) +#define IDWriteTextFormat3_GetLineSpacing(This,spacing) (This)->lpVtbl->IDWriteTextFormat2_GetLineSpacing(This,spacing) +/*** IDWriteTextFormat3 methods ***/ +#define IDWriteTextFormat3_SetFontAxisValues(This,axis_values,num_values) (This)->lpVtbl->SetFontAxisValues(This,axis_values,num_values) +#define IDWriteTextFormat3_GetFontAxisValueCount(This) (This)->lpVtbl->GetFontAxisValueCount(This) +#define IDWriteTextFormat3_GetFontAxisValues(This,axis_values,num_values) (This)->lpVtbl->GetFontAxisValues(This,axis_values,num_values) +#define IDWriteTextFormat3_GetAutomaticFontAxes(This) (This)->lpVtbl->GetAutomaticFontAxes(This) +#define IDWriteTextFormat3_SetAutomaticFontAxes(This,axes) (This)->lpVtbl->SetAutomaticFontAxes(This,axes) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat3_QueryInterface(IDWriteTextFormat3* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteTextFormat3_AddRef(IDWriteTextFormat3* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteTextFormat3_Release(IDWriteTextFormat3* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteTextFormat methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat3_SetTextAlignment(IDWriteTextFormat3* This,DWRITE_TEXT_ALIGNMENT alignment) { + return This->lpVtbl->SetTextAlignment(This,alignment); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetParagraphAlignment(IDWriteTextFormat3* This,DWRITE_PARAGRAPH_ALIGNMENT alignment) { + return This->lpVtbl->SetParagraphAlignment(This,alignment); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetWordWrapping(IDWriteTextFormat3* This,DWRITE_WORD_WRAPPING wrapping) { + return This->lpVtbl->SetWordWrapping(This,wrapping); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetReadingDirection(IDWriteTextFormat3* This,DWRITE_READING_DIRECTION direction) { + return This->lpVtbl->SetReadingDirection(This,direction); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetFlowDirection(IDWriteTextFormat3* This,DWRITE_FLOW_DIRECTION direction) { + return This->lpVtbl->SetFlowDirection(This,direction); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetIncrementalTabStop(IDWriteTextFormat3* This,FLOAT tabstop) { + return This->lpVtbl->SetIncrementalTabStop(This,tabstop); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetTrimming(IDWriteTextFormat3* This,const DWRITE_TRIMMING *trimming,IDWriteInlineObject *trimming_sign) { + return This->lpVtbl->SetTrimming(This,trimming,trimming_sign); +} +static FORCEINLINE DWRITE_TEXT_ALIGNMENT IDWriteTextFormat3_GetTextAlignment(IDWriteTextFormat3* This) { + return This->lpVtbl->GetTextAlignment(This); +} +static FORCEINLINE DWRITE_PARAGRAPH_ALIGNMENT IDWriteTextFormat3_GetParagraphAlignment(IDWriteTextFormat3* This) { + return This->lpVtbl->GetParagraphAlignment(This); +} +static FORCEINLINE DWRITE_WORD_WRAPPING IDWriteTextFormat3_GetWordWrapping(IDWriteTextFormat3* This) { + return This->lpVtbl->GetWordWrapping(This); +} +static FORCEINLINE DWRITE_READING_DIRECTION IDWriteTextFormat3_GetReadingDirection(IDWriteTextFormat3* This) { + return This->lpVtbl->GetReadingDirection(This); +} +static FORCEINLINE DWRITE_FLOW_DIRECTION IDWriteTextFormat3_GetFlowDirection(IDWriteTextFormat3* This) { + return This->lpVtbl->GetFlowDirection(This); +} +static FORCEINLINE FLOAT IDWriteTextFormat3_GetIncrementalTabStop(IDWriteTextFormat3* This) { + return This->lpVtbl->GetIncrementalTabStop(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_GetTrimming(IDWriteTextFormat3* This,DWRITE_TRIMMING *options,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->GetTrimming(This,options,trimming_sign); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_GetFontCollection(IDWriteTextFormat3* This,IDWriteFontCollection **collection) { + return This->lpVtbl->GetFontCollection(This,collection); +} +static FORCEINLINE UINT32 IDWriteTextFormat3_GetFontFamilyNameLength(IDWriteTextFormat3* This) { + return This->lpVtbl->GetFontFamilyNameLength(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_GetFontFamilyName(IDWriteTextFormat3* This,WCHAR *name,UINT32 size) { + return This->lpVtbl->GetFontFamilyName(This,name,size); +} +static FORCEINLINE DWRITE_FONT_WEIGHT IDWriteTextFormat3_GetFontWeight(IDWriteTextFormat3* This) { + return This->lpVtbl->GetFontWeight(This); +} +static FORCEINLINE DWRITE_FONT_STYLE IDWriteTextFormat3_GetFontStyle(IDWriteTextFormat3* This) { + return This->lpVtbl->GetFontStyle(This); +} +static FORCEINLINE DWRITE_FONT_STRETCH IDWriteTextFormat3_GetFontStretch(IDWriteTextFormat3* This) { + return This->lpVtbl->GetFontStretch(This); +} +static FORCEINLINE FLOAT IDWriteTextFormat3_GetFontSize(IDWriteTextFormat3* This) { + return This->lpVtbl->GetFontSize(This); +} +static FORCEINLINE UINT32 IDWriteTextFormat3_GetLocaleNameLength(IDWriteTextFormat3* This) { + return This->lpVtbl->GetLocaleNameLength(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_GetLocaleName(IDWriteTextFormat3* This,WCHAR *name,UINT32 size) { + return This->lpVtbl->GetLocaleName(This,name,size); +} +/*** IDWriteTextFormat1 methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat3_SetVerticalGlyphOrientation(IDWriteTextFormat3* This,DWRITE_VERTICAL_GLYPH_ORIENTATION orientation) { + return This->lpVtbl->SetVerticalGlyphOrientation(This,orientation); +} +static FORCEINLINE DWRITE_VERTICAL_GLYPH_ORIENTATION IDWriteTextFormat3_GetVerticalGlyphOrientation(IDWriteTextFormat3* This) { + return This->lpVtbl->GetVerticalGlyphOrientation(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetLastLineWrapping(IDWriteTextFormat3* This,WINBOOL lastline_wrapping_enabled) { + return This->lpVtbl->SetLastLineWrapping(This,lastline_wrapping_enabled); +} +static FORCEINLINE WINBOOL IDWriteTextFormat3_GetLastLineWrapping(IDWriteTextFormat3* This) { + return This->lpVtbl->GetLastLineWrapping(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetOpticalAlignment(IDWriteTextFormat3* This,DWRITE_OPTICAL_ALIGNMENT alignment) { + return This->lpVtbl->SetOpticalAlignment(This,alignment); +} +static FORCEINLINE DWRITE_OPTICAL_ALIGNMENT IDWriteTextFormat3_GetOpticalAlignment(IDWriteTextFormat3* This) { + return This->lpVtbl->GetOpticalAlignment(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetFontFallback(IDWriteTextFormat3* This,IDWriteFontFallback *fallback) { + return This->lpVtbl->SetFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_GetFontFallback(IDWriteTextFormat3* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetFontFallback(This,fallback); +} +/*** IDWriteTextFormat2 methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat3_SetLineSpacing(IDWriteTextFormat3* This,const DWRITE_LINE_SPACING *spacing) { + return This->lpVtbl->IDWriteTextFormat2_SetLineSpacing(This,spacing); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_GetLineSpacing(IDWriteTextFormat3* This,DWRITE_LINE_SPACING *spacing) { + return This->lpVtbl->IDWriteTextFormat2_GetLineSpacing(This,spacing); +} +/*** IDWriteTextFormat3 methods ***/ +static FORCEINLINE HRESULT IDWriteTextFormat3_SetFontAxisValues(IDWriteTextFormat3* This,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values) { + return This->lpVtbl->SetFontAxisValues(This,axis_values,num_values); +} +static FORCEINLINE UINT32 IDWriteTextFormat3_GetFontAxisValueCount(IDWriteTextFormat3* This) { + return This->lpVtbl->GetFontAxisValueCount(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_GetFontAxisValues(IDWriteTextFormat3* This,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values) { + return This->lpVtbl->GetFontAxisValues(This,axis_values,num_values); +} +static FORCEINLINE DWRITE_AUTOMATIC_FONT_AXES IDWriteTextFormat3_GetAutomaticFontAxes(IDWriteTextFormat3* This) { + return This->lpVtbl->GetAutomaticFontAxes(This); +} +static FORCEINLINE HRESULT IDWriteTextFormat3_SetAutomaticFontAxes(IDWriteTextFormat3* This,DWRITE_AUTOMATIC_FONT_AXES axes) { + return This->lpVtbl->SetAutomaticFontAxes(This,axes); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteTextFormat3_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteTextLayout3 interface + */ +#ifndef __IDWriteTextLayout3_INTERFACE_DEFINED__ +#define __IDWriteTextLayout3_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteTextLayout3, 0x07ddcd52, 0x020e, 0x4de8, 0xac,0x33, 0x6c,0x95,0x3d,0x83,0xf9,0x2d); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("07ddcd52-020e-4de8-ac33-6c953d83f92d") +IDWriteTextLayout3 : public IDWriteTextLayout2 +{ + virtual HRESULT STDMETHODCALLTYPE InvalidateLayout( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetLineSpacing( + const DWRITE_LINE_SPACING *spacing) = 0; + + using IDWriteTextLayout2::SetLineSpacing; + + virtual HRESULT STDMETHODCALLTYPE GetLineSpacing( + DWRITE_LINE_SPACING *spacing) = 0; + + using IDWriteTextLayout2::GetLineSpacing; + + virtual HRESULT STDMETHODCALLTYPE GetLineMetrics( + DWRITE_LINE_METRICS1 *metrics, + UINT32 max_count, + UINT32 *count) = 0; + + using IDWriteTextLayout2::GetLineMetrics; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteTextLayout3, 0x07ddcd52, 0x020e, 0x4de8, 0xac,0x33, 0x6c,0x95,0x3d,0x83,0xf9,0x2d) +#endif +#else +typedef struct IDWriteTextLayout3Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteTextLayout3 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteTextLayout3 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteTextLayout3 *This); + + /*** IDWriteTextFormat methods ***/ + HRESULT (STDMETHODCALLTYPE *SetTextAlignment)( + IDWriteTextLayout3 *This, + DWRITE_TEXT_ALIGNMENT alignment); + + HRESULT (STDMETHODCALLTYPE *SetParagraphAlignment)( + IDWriteTextLayout3 *This, + DWRITE_PARAGRAPH_ALIGNMENT alignment); + + HRESULT (STDMETHODCALLTYPE *SetWordWrapping)( + IDWriteTextLayout3 *This, + DWRITE_WORD_WRAPPING wrapping); + + HRESULT (STDMETHODCALLTYPE *SetReadingDirection)( + IDWriteTextLayout3 *This, + DWRITE_READING_DIRECTION direction); + + HRESULT (STDMETHODCALLTYPE *SetFlowDirection)( + IDWriteTextLayout3 *This, + DWRITE_FLOW_DIRECTION direction); + + HRESULT (STDMETHODCALLTYPE *SetIncrementalTabStop)( + IDWriteTextLayout3 *This, + FLOAT tabstop); + + HRESULT (STDMETHODCALLTYPE *SetTrimming)( + IDWriteTextLayout3 *This, + const DWRITE_TRIMMING *trimming, + IDWriteInlineObject *trimming_sign); + + HRESULT (STDMETHODCALLTYPE *SetLineSpacing)( + IDWriteTextLayout3 *This, + DWRITE_LINE_SPACING_METHOD spacing, + FLOAT line_spacing, + FLOAT baseline); + + DWRITE_TEXT_ALIGNMENT (STDMETHODCALLTYPE *GetTextAlignment)( + IDWriteTextLayout3 *This); + + DWRITE_PARAGRAPH_ALIGNMENT (STDMETHODCALLTYPE *GetParagraphAlignment)( + IDWriteTextLayout3 *This); + + DWRITE_WORD_WRAPPING (STDMETHODCALLTYPE *GetWordWrapping)( + IDWriteTextLayout3 *This); + + DWRITE_READING_DIRECTION (STDMETHODCALLTYPE *GetReadingDirection)( + IDWriteTextLayout3 *This); + + DWRITE_FLOW_DIRECTION (STDMETHODCALLTYPE *GetFlowDirection)( + IDWriteTextLayout3 *This); + + FLOAT (STDMETHODCALLTYPE *GetIncrementalTabStop)( + IDWriteTextLayout3 *This); + + HRESULT (STDMETHODCALLTYPE *GetTrimming)( + IDWriteTextLayout3 *This, + DWRITE_TRIMMING *options, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *GetLineSpacing)( + IDWriteTextLayout3 *This, + DWRITE_LINE_SPACING_METHOD *method, + FLOAT *spacing, + FLOAT *baseline); + + HRESULT (STDMETHODCALLTYPE *GetFontCollection)( + IDWriteTextLayout3 *This, + IDWriteFontCollection **collection); + + UINT32 (STDMETHODCALLTYPE *GetFontFamilyNameLength)( + IDWriteTextLayout3 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFamilyName)( + IDWriteTextLayout3 *This, + WCHAR *name, + UINT32 size); + + DWRITE_FONT_WEIGHT (STDMETHODCALLTYPE *GetFontWeight)( + IDWriteTextLayout3 *This); + + DWRITE_FONT_STYLE (STDMETHODCALLTYPE *GetFontStyle)( + IDWriteTextLayout3 *This); + + DWRITE_FONT_STRETCH (STDMETHODCALLTYPE *GetFontStretch)( + IDWriteTextLayout3 *This); + + FLOAT (STDMETHODCALLTYPE *GetFontSize)( + IDWriteTextLayout3 *This); + + UINT32 (STDMETHODCALLTYPE *GetLocaleNameLength)( + IDWriteTextLayout3 *This); + + HRESULT (STDMETHODCALLTYPE *GetLocaleName)( + IDWriteTextLayout3 *This, + WCHAR *name, + UINT32 size); + + /*** IDWriteTextLayout methods ***/ + HRESULT (STDMETHODCALLTYPE *SetMaxWidth)( + IDWriteTextLayout3 *This, + FLOAT maxWidth); + + HRESULT (STDMETHODCALLTYPE *SetMaxHeight)( + IDWriteTextLayout3 *This, + FLOAT maxHeight); + + HRESULT (STDMETHODCALLTYPE *SetFontCollection)( + IDWriteTextLayout3 *This, + IDWriteFontCollection *collection, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontFamilyName)( + IDWriteTextLayout3 *This, + const WCHAR *name, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontWeight)( + IDWriteTextLayout3 *This, + DWRITE_FONT_WEIGHT weight, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontStyle)( + IDWriteTextLayout3 *This, + DWRITE_FONT_STYLE style, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontStretch)( + IDWriteTextLayout3 *This, + DWRITE_FONT_STRETCH stretch, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontSize)( + IDWriteTextLayout3 *This, + FLOAT size, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetUnderline)( + IDWriteTextLayout3 *This, + WINBOOL underline, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetStrikethrough)( + IDWriteTextLayout3 *This, + WINBOOL strikethrough, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetDrawingEffect)( + IDWriteTextLayout3 *This, + IUnknown *effect, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetInlineObject)( + IDWriteTextLayout3 *This, + IDWriteInlineObject *object, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetTypography)( + IDWriteTextLayout3 *This, + IDWriteTypography *typography, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetLocaleName)( + IDWriteTextLayout3 *This, + const WCHAR *locale, + DWRITE_TEXT_RANGE range); + + FLOAT (STDMETHODCALLTYPE *GetMaxWidth)( + IDWriteTextLayout3 *This); + + FLOAT (STDMETHODCALLTYPE *GetMaxHeight)( + IDWriteTextLayout3 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontCollection)( + IDWriteTextLayout3 *This, + UINT32 pos, + IDWriteFontCollection **collection, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontFamilyNameLength)( + IDWriteTextLayout3 *This, + UINT32 pos, + UINT32 *len, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontFamilyName)( + IDWriteTextLayout3 *This, + UINT32 position, + WCHAR *name, + UINT32 name_size, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontWeight)( + IDWriteTextLayout3 *This, + UINT32 position, + DWRITE_FONT_WEIGHT *weight, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontStyle)( + IDWriteTextLayout3 *This, + UINT32 currentPosition, + DWRITE_FONT_STYLE *style, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontStretch)( + IDWriteTextLayout3 *This, + UINT32 position, + DWRITE_FONT_STRETCH *stretch, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontSize)( + IDWriteTextLayout3 *This, + UINT32 position, + FLOAT *size, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetUnderline)( + IDWriteTextLayout3 *This, + UINT32 position, + WINBOOL *has_underline, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetStrikethrough)( + IDWriteTextLayout3 *This, + UINT32 position, + WINBOOL *has_strikethrough, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetDrawingEffect)( + IDWriteTextLayout3 *This, + UINT32 position, + IUnknown **effect, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetInlineObject)( + IDWriteTextLayout3 *This, + UINT32 position, + IDWriteInlineObject **object, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetTypography)( + IDWriteTextLayout3 *This, + UINT32 position, + IDWriteTypography **typography, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetLocaleNameLength)( + IDWriteTextLayout3 *This, + UINT32 position, + UINT32 *length, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetLocaleName)( + IDWriteTextLayout3 *This, + UINT32 position, + WCHAR *name, + UINT32 name_size, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *Draw)( + IDWriteTextLayout3 *This, + void *context, + IDWriteTextRenderer *renderer, + FLOAT originX, + FLOAT originY); + + HRESULT (STDMETHODCALLTYPE *GetLineMetrics)( + IDWriteTextLayout3 *This, + DWRITE_LINE_METRICS *metrics, + UINT32 max_count, + UINT32 *actual_count); + + HRESULT (STDMETHODCALLTYPE *GetMetrics)( + IDWriteTextLayout3 *This, + DWRITE_TEXT_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *GetOverhangMetrics)( + IDWriteTextLayout3 *This, + DWRITE_OVERHANG_METRICS *overhangs); + + HRESULT (STDMETHODCALLTYPE *GetClusterMetrics)( + IDWriteTextLayout3 *This, + DWRITE_CLUSTER_METRICS *metrics, + UINT32 max_count, + UINT32 *act_count); + + HRESULT (STDMETHODCALLTYPE *DetermineMinWidth)( + IDWriteTextLayout3 *This, + FLOAT *min_width); + + HRESULT (STDMETHODCALLTYPE *HitTestPoint)( + IDWriteTextLayout3 *This, + FLOAT pointX, + FLOAT pointY, + WINBOOL *is_trailinghit, + WINBOOL *is_inside, + DWRITE_HIT_TEST_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *HitTestTextPosition)( + IDWriteTextLayout3 *This, + UINT32 textPosition, + WINBOOL is_trailinghit, + FLOAT *pointX, + FLOAT *pointY, + DWRITE_HIT_TEST_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *HitTestTextRange)( + IDWriteTextLayout3 *This, + UINT32 textPosition, + UINT32 textLength, + FLOAT originX, + FLOAT originY, + DWRITE_HIT_TEST_METRICS *metrics, + UINT32 max_metricscount, + UINT32 *actual_metricscount); + + /*** IDWriteTextLayout1 methods ***/ + HRESULT (STDMETHODCALLTYPE *SetPairKerning)( + IDWriteTextLayout3 *This, + WINBOOL is_pairkerning_enabled, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *GetPairKerning)( + IDWriteTextLayout3 *This, + UINT32 position, + WINBOOL *is_pairkerning_enabled, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *SetCharacterSpacing)( + IDWriteTextLayout3 *This, + FLOAT leading_spacing, + FLOAT trailing_spacing, + FLOAT minimum_advance_width, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *GetCharacterSpacing)( + IDWriteTextLayout3 *This, + UINT32 position, + FLOAT *leading_spacing, + FLOAT *trailing_spacing, + FLOAT *minimum_advance_width, + DWRITE_TEXT_RANGE *range); + + /*** IDWriteTextLayout2 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout2_GetMetrics)( + IDWriteTextLayout3 *This, + DWRITE_TEXT_METRICS1 *metrics); + + HRESULT (STDMETHODCALLTYPE *SetVerticalGlyphOrientation)( + IDWriteTextLayout3 *This, + DWRITE_VERTICAL_GLYPH_ORIENTATION orientation); + + DWRITE_VERTICAL_GLYPH_ORIENTATION (STDMETHODCALLTYPE *GetVerticalGlyphOrientation)( + IDWriteTextLayout3 *This); + + HRESULT (STDMETHODCALLTYPE *SetLastLineWrapping)( + IDWriteTextLayout3 *This, + WINBOOL lastline_wrapping_enabled); + + WINBOOL (STDMETHODCALLTYPE *GetLastLineWrapping)( + IDWriteTextLayout3 *This); + + HRESULT (STDMETHODCALLTYPE *SetOpticalAlignment)( + IDWriteTextLayout3 *This, + DWRITE_OPTICAL_ALIGNMENT alignment); + + DWRITE_OPTICAL_ALIGNMENT (STDMETHODCALLTYPE *GetOpticalAlignment)( + IDWriteTextLayout3 *This); + + HRESULT (STDMETHODCALLTYPE *SetFontFallback)( + IDWriteTextLayout3 *This, + IDWriteFontFallback *fallback); + + HRESULT (STDMETHODCALLTYPE *GetFontFallback)( + IDWriteTextLayout3 *This, + IDWriteFontFallback **fallback); + + /*** IDWriteTextLayout3 methods ***/ + HRESULT (STDMETHODCALLTYPE *InvalidateLayout)( + IDWriteTextLayout3 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout3_SetLineSpacing)( + IDWriteTextLayout3 *This, + const DWRITE_LINE_SPACING *spacing); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout3_GetLineSpacing)( + IDWriteTextLayout3 *This, + DWRITE_LINE_SPACING *spacing); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout3_GetLineMetrics)( + IDWriteTextLayout3 *This, + DWRITE_LINE_METRICS1 *metrics, + UINT32 max_count, + UINT32 *count); + + END_INTERFACE +} IDWriteTextLayout3Vtbl; + +interface IDWriteTextLayout3 { + CONST_VTBL IDWriteTextLayout3Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteTextLayout3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteTextLayout3_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteTextLayout3_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteTextFormat methods ***/ +#define IDWriteTextLayout3_SetTextAlignment(This,alignment) (This)->lpVtbl->SetTextAlignment(This,alignment) +#define IDWriteTextLayout3_SetParagraphAlignment(This,alignment) (This)->lpVtbl->SetParagraphAlignment(This,alignment) +#define IDWriteTextLayout3_SetWordWrapping(This,wrapping) (This)->lpVtbl->SetWordWrapping(This,wrapping) +#define IDWriteTextLayout3_SetReadingDirection(This,direction) (This)->lpVtbl->SetReadingDirection(This,direction) +#define IDWriteTextLayout3_SetFlowDirection(This,direction) (This)->lpVtbl->SetFlowDirection(This,direction) +#define IDWriteTextLayout3_SetIncrementalTabStop(This,tabstop) (This)->lpVtbl->SetIncrementalTabStop(This,tabstop) +#define IDWriteTextLayout3_SetTrimming(This,trimming,trimming_sign) (This)->lpVtbl->SetTrimming(This,trimming,trimming_sign) +#define IDWriteTextLayout3_GetTextAlignment(This) (This)->lpVtbl->GetTextAlignment(This) +#define IDWriteTextLayout3_GetParagraphAlignment(This) (This)->lpVtbl->GetParagraphAlignment(This) +#define IDWriteTextLayout3_GetWordWrapping(This) (This)->lpVtbl->GetWordWrapping(This) +#define IDWriteTextLayout3_GetReadingDirection(This) (This)->lpVtbl->GetReadingDirection(This) +#define IDWriteTextLayout3_GetFlowDirection(This) (This)->lpVtbl->GetFlowDirection(This) +#define IDWriteTextLayout3_GetIncrementalTabStop(This) (This)->lpVtbl->GetIncrementalTabStop(This) +#define IDWriteTextLayout3_GetTrimming(This,options,trimming_sign) (This)->lpVtbl->GetTrimming(This,options,trimming_sign) +/*** IDWriteTextLayout methods ***/ +#define IDWriteTextLayout3_SetMaxWidth(This,maxWidth) (This)->lpVtbl->SetMaxWidth(This,maxWidth) +#define IDWriteTextLayout3_SetMaxHeight(This,maxHeight) (This)->lpVtbl->SetMaxHeight(This,maxHeight) +#define IDWriteTextLayout3_SetFontCollection(This,collection,range) (This)->lpVtbl->SetFontCollection(This,collection,range) +#define IDWriteTextLayout3_SetFontFamilyName(This,name,range) (This)->lpVtbl->SetFontFamilyName(This,name,range) +#define IDWriteTextLayout3_SetFontWeight(This,weight,range) (This)->lpVtbl->SetFontWeight(This,weight,range) +#define IDWriteTextLayout3_SetFontStyle(This,style,range) (This)->lpVtbl->SetFontStyle(This,style,range) +#define IDWriteTextLayout3_SetFontStretch(This,stretch,range) (This)->lpVtbl->SetFontStretch(This,stretch,range) +#define IDWriteTextLayout3_SetFontSize(This,size,range) (This)->lpVtbl->SetFontSize(This,size,range) +#define IDWriteTextLayout3_SetUnderline(This,underline,range) (This)->lpVtbl->SetUnderline(This,underline,range) +#define IDWriteTextLayout3_SetStrikethrough(This,strikethrough,range) (This)->lpVtbl->SetStrikethrough(This,strikethrough,range) +#define IDWriteTextLayout3_SetDrawingEffect(This,effect,range) (This)->lpVtbl->SetDrawingEffect(This,effect,range) +#define IDWriteTextLayout3_SetInlineObject(This,object,range) (This)->lpVtbl->SetInlineObject(This,object,range) +#define IDWriteTextLayout3_SetTypography(This,typography,range) (This)->lpVtbl->SetTypography(This,typography,range) +#define IDWriteTextLayout3_SetLocaleName(This,locale,range) (This)->lpVtbl->SetLocaleName(This,locale,range) +#define IDWriteTextLayout3_GetMaxWidth(This) (This)->lpVtbl->GetMaxWidth(This) +#define IDWriteTextLayout3_GetMaxHeight(This) (This)->lpVtbl->GetMaxHeight(This) +#define IDWriteTextLayout3_GetFontCollection(This,pos,collection,range) (This)->lpVtbl->IDWriteTextLayout_GetFontCollection(This,pos,collection,range) +#define IDWriteTextLayout3_GetFontFamilyNameLength(This,pos,len,range) (This)->lpVtbl->IDWriteTextLayout_GetFontFamilyNameLength(This,pos,len,range) +#define IDWriteTextLayout3_GetFontFamilyName(This,position,name,name_size,range) (This)->lpVtbl->IDWriteTextLayout_GetFontFamilyName(This,position,name,name_size,range) +#define IDWriteTextLayout3_GetFontWeight(This,position,weight,range) (This)->lpVtbl->IDWriteTextLayout_GetFontWeight(This,position,weight,range) +#define IDWriteTextLayout3_GetFontStyle(This,currentPosition,style,range) (This)->lpVtbl->IDWriteTextLayout_GetFontStyle(This,currentPosition,style,range) +#define IDWriteTextLayout3_GetFontStretch(This,position,stretch,range) (This)->lpVtbl->IDWriteTextLayout_GetFontStretch(This,position,stretch,range) +#define IDWriteTextLayout3_GetFontSize(This,position,size,range) (This)->lpVtbl->IDWriteTextLayout_GetFontSize(This,position,size,range) +#define IDWriteTextLayout3_GetUnderline(This,position,has_underline,range) (This)->lpVtbl->GetUnderline(This,position,has_underline,range) +#define IDWriteTextLayout3_GetStrikethrough(This,position,has_strikethrough,range) (This)->lpVtbl->GetStrikethrough(This,position,has_strikethrough,range) +#define IDWriteTextLayout3_GetDrawingEffect(This,position,effect,range) (This)->lpVtbl->GetDrawingEffect(This,position,effect,range) +#define IDWriteTextLayout3_GetInlineObject(This,position,object,range) (This)->lpVtbl->GetInlineObject(This,position,object,range) +#define IDWriteTextLayout3_GetTypography(This,position,typography,range) (This)->lpVtbl->GetTypography(This,position,typography,range) +#define IDWriteTextLayout3_GetLocaleNameLength(This,position,length,range) (This)->lpVtbl->IDWriteTextLayout_GetLocaleNameLength(This,position,length,range) +#define IDWriteTextLayout3_GetLocaleName(This,position,name,name_size,range) (This)->lpVtbl->IDWriteTextLayout_GetLocaleName(This,position,name,name_size,range) +#define IDWriteTextLayout3_Draw(This,context,renderer,originX,originY) (This)->lpVtbl->Draw(This,context,renderer,originX,originY) +#define IDWriteTextLayout3_GetOverhangMetrics(This,overhangs) (This)->lpVtbl->GetOverhangMetrics(This,overhangs) +#define IDWriteTextLayout3_GetClusterMetrics(This,metrics,max_count,act_count) (This)->lpVtbl->GetClusterMetrics(This,metrics,max_count,act_count) +#define IDWriteTextLayout3_DetermineMinWidth(This,min_width) (This)->lpVtbl->DetermineMinWidth(This,min_width) +#define IDWriteTextLayout3_HitTestPoint(This,pointX,pointY,is_trailinghit,is_inside,metrics) (This)->lpVtbl->HitTestPoint(This,pointX,pointY,is_trailinghit,is_inside,metrics) +#define IDWriteTextLayout3_HitTestTextPosition(This,textPosition,is_trailinghit,pointX,pointY,metrics) (This)->lpVtbl->HitTestTextPosition(This,textPosition,is_trailinghit,pointX,pointY,metrics) +#define IDWriteTextLayout3_HitTestTextRange(This,textPosition,textLength,originX,originY,metrics,max_metricscount,actual_metricscount) (This)->lpVtbl->HitTestTextRange(This,textPosition,textLength,originX,originY,metrics,max_metricscount,actual_metricscount) +/*** IDWriteTextLayout1 methods ***/ +#define IDWriteTextLayout3_SetPairKerning(This,is_pairkerning_enabled,range) (This)->lpVtbl->SetPairKerning(This,is_pairkerning_enabled,range) +#define IDWriteTextLayout3_GetPairKerning(This,position,is_pairkerning_enabled,range) (This)->lpVtbl->GetPairKerning(This,position,is_pairkerning_enabled,range) +#define IDWriteTextLayout3_SetCharacterSpacing(This,leading_spacing,trailing_spacing,minimum_advance_width,range) (This)->lpVtbl->SetCharacterSpacing(This,leading_spacing,trailing_spacing,minimum_advance_width,range) +#define IDWriteTextLayout3_GetCharacterSpacing(This,position,leading_spacing,trailing_spacing,minimum_advance_width,range) (This)->lpVtbl->GetCharacterSpacing(This,position,leading_spacing,trailing_spacing,minimum_advance_width,range) +/*** IDWriteTextLayout2 methods ***/ +#define IDWriteTextLayout3_GetMetrics(This,metrics) (This)->lpVtbl->IDWriteTextLayout2_GetMetrics(This,metrics) +#define IDWriteTextLayout3_SetVerticalGlyphOrientation(This,orientation) (This)->lpVtbl->SetVerticalGlyphOrientation(This,orientation) +#define IDWriteTextLayout3_GetVerticalGlyphOrientation(This) (This)->lpVtbl->GetVerticalGlyphOrientation(This) +#define IDWriteTextLayout3_SetLastLineWrapping(This,lastline_wrapping_enabled) (This)->lpVtbl->SetLastLineWrapping(This,lastline_wrapping_enabled) +#define IDWriteTextLayout3_GetLastLineWrapping(This) (This)->lpVtbl->GetLastLineWrapping(This) +#define IDWriteTextLayout3_SetOpticalAlignment(This,alignment) (This)->lpVtbl->SetOpticalAlignment(This,alignment) +#define IDWriteTextLayout3_GetOpticalAlignment(This) (This)->lpVtbl->GetOpticalAlignment(This) +#define IDWriteTextLayout3_SetFontFallback(This,fallback) (This)->lpVtbl->SetFontFallback(This,fallback) +#define IDWriteTextLayout3_GetFontFallback(This,fallback) (This)->lpVtbl->GetFontFallback(This,fallback) +/*** IDWriteTextLayout3 methods ***/ +#define IDWriteTextLayout3_InvalidateLayout(This) (This)->lpVtbl->InvalidateLayout(This) +#define IDWriteTextLayout3_SetLineSpacing(This,spacing) (This)->lpVtbl->IDWriteTextLayout3_SetLineSpacing(This,spacing) +#define IDWriteTextLayout3_GetLineSpacing(This,spacing) (This)->lpVtbl->IDWriteTextLayout3_GetLineSpacing(This,spacing) +#define IDWriteTextLayout3_GetLineMetrics(This,metrics,max_count,count) (This)->lpVtbl->IDWriteTextLayout3_GetLineMetrics(This,metrics,max_count,count) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout3_QueryInterface(IDWriteTextLayout3* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteTextLayout3_AddRef(IDWriteTextLayout3* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteTextLayout3_Release(IDWriteTextLayout3* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteTextFormat methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout3_SetTextAlignment(IDWriteTextLayout3* This,DWRITE_TEXT_ALIGNMENT alignment) { + return This->lpVtbl->SetTextAlignment(This,alignment); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetParagraphAlignment(IDWriteTextLayout3* This,DWRITE_PARAGRAPH_ALIGNMENT alignment) { + return This->lpVtbl->SetParagraphAlignment(This,alignment); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetWordWrapping(IDWriteTextLayout3* This,DWRITE_WORD_WRAPPING wrapping) { + return This->lpVtbl->SetWordWrapping(This,wrapping); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetReadingDirection(IDWriteTextLayout3* This,DWRITE_READING_DIRECTION direction) { + return This->lpVtbl->SetReadingDirection(This,direction); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetFlowDirection(IDWriteTextLayout3* This,DWRITE_FLOW_DIRECTION direction) { + return This->lpVtbl->SetFlowDirection(This,direction); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetIncrementalTabStop(IDWriteTextLayout3* This,FLOAT tabstop) { + return This->lpVtbl->SetIncrementalTabStop(This,tabstop); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetTrimming(IDWriteTextLayout3* This,const DWRITE_TRIMMING *trimming,IDWriteInlineObject *trimming_sign) { + return This->lpVtbl->SetTrimming(This,trimming,trimming_sign); +} +static FORCEINLINE DWRITE_TEXT_ALIGNMENT IDWriteTextLayout3_GetTextAlignment(IDWriteTextLayout3* This) { + return This->lpVtbl->GetTextAlignment(This); +} +static FORCEINLINE DWRITE_PARAGRAPH_ALIGNMENT IDWriteTextLayout3_GetParagraphAlignment(IDWriteTextLayout3* This) { + return This->lpVtbl->GetParagraphAlignment(This); +} +static FORCEINLINE DWRITE_WORD_WRAPPING IDWriteTextLayout3_GetWordWrapping(IDWriteTextLayout3* This) { + return This->lpVtbl->GetWordWrapping(This); +} +static FORCEINLINE DWRITE_READING_DIRECTION IDWriteTextLayout3_GetReadingDirection(IDWriteTextLayout3* This) { + return This->lpVtbl->GetReadingDirection(This); +} +static FORCEINLINE DWRITE_FLOW_DIRECTION IDWriteTextLayout3_GetFlowDirection(IDWriteTextLayout3* This) { + return This->lpVtbl->GetFlowDirection(This); +} +static FORCEINLINE FLOAT IDWriteTextLayout3_GetIncrementalTabStop(IDWriteTextLayout3* This) { + return This->lpVtbl->GetIncrementalTabStop(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetTrimming(IDWriteTextLayout3* This,DWRITE_TRIMMING *options,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->GetTrimming(This,options,trimming_sign); +} +/*** IDWriteTextLayout methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout3_SetMaxWidth(IDWriteTextLayout3* This,FLOAT maxWidth) { + return This->lpVtbl->SetMaxWidth(This,maxWidth); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetMaxHeight(IDWriteTextLayout3* This,FLOAT maxHeight) { + return This->lpVtbl->SetMaxHeight(This,maxHeight); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetFontCollection(IDWriteTextLayout3* This,IDWriteFontCollection *collection,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontCollection(This,collection,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetFontFamilyName(IDWriteTextLayout3* This,const WCHAR *name,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontFamilyName(This,name,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetFontWeight(IDWriteTextLayout3* This,DWRITE_FONT_WEIGHT weight,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontWeight(This,weight,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetFontStyle(IDWriteTextLayout3* This,DWRITE_FONT_STYLE style,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontStyle(This,style,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetFontStretch(IDWriteTextLayout3* This,DWRITE_FONT_STRETCH stretch,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontStretch(This,stretch,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetFontSize(IDWriteTextLayout3* This,FLOAT size,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontSize(This,size,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetUnderline(IDWriteTextLayout3* This,WINBOOL underline,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetUnderline(This,underline,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetStrikethrough(IDWriteTextLayout3* This,WINBOOL strikethrough,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetStrikethrough(This,strikethrough,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetDrawingEffect(IDWriteTextLayout3* This,IUnknown *effect,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetDrawingEffect(This,effect,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetInlineObject(IDWriteTextLayout3* This,IDWriteInlineObject *object,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetInlineObject(This,object,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetTypography(IDWriteTextLayout3* This,IDWriteTypography *typography,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetTypography(This,typography,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetLocaleName(IDWriteTextLayout3* This,const WCHAR *locale,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetLocaleName(This,locale,range); +} +static FORCEINLINE FLOAT IDWriteTextLayout3_GetMaxWidth(IDWriteTextLayout3* This) { + return This->lpVtbl->GetMaxWidth(This); +} +static FORCEINLINE FLOAT IDWriteTextLayout3_GetMaxHeight(IDWriteTextLayout3* This) { + return This->lpVtbl->GetMaxHeight(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetFontCollection(IDWriteTextLayout3* This,UINT32 pos,IDWriteFontCollection **collection,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontCollection(This,pos,collection,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetFontFamilyNameLength(IDWriteTextLayout3* This,UINT32 pos,UINT32 *len,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontFamilyNameLength(This,pos,len,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetFontFamilyName(IDWriteTextLayout3* This,UINT32 position,WCHAR *name,UINT32 name_size,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontFamilyName(This,position,name,name_size,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetFontWeight(IDWriteTextLayout3* This,UINT32 position,DWRITE_FONT_WEIGHT *weight,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontWeight(This,position,weight,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetFontStyle(IDWriteTextLayout3* This,UINT32 currentPosition,DWRITE_FONT_STYLE *style,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontStyle(This,currentPosition,style,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetFontStretch(IDWriteTextLayout3* This,UINT32 position,DWRITE_FONT_STRETCH *stretch,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontStretch(This,position,stretch,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetFontSize(IDWriteTextLayout3* This,UINT32 position,FLOAT *size,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontSize(This,position,size,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetUnderline(IDWriteTextLayout3* This,UINT32 position,WINBOOL *has_underline,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetUnderline(This,position,has_underline,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetStrikethrough(IDWriteTextLayout3* This,UINT32 position,WINBOOL *has_strikethrough,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetStrikethrough(This,position,has_strikethrough,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetDrawingEffect(IDWriteTextLayout3* This,UINT32 position,IUnknown **effect,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetDrawingEffect(This,position,effect,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetInlineObject(IDWriteTextLayout3* This,UINT32 position,IDWriteInlineObject **object,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetInlineObject(This,position,object,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetTypography(IDWriteTextLayout3* This,UINT32 position,IDWriteTypography **typography,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetTypography(This,position,typography,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetLocaleNameLength(IDWriteTextLayout3* This,UINT32 position,UINT32 *length,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetLocaleNameLength(This,position,length,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetLocaleName(IDWriteTextLayout3* This,UINT32 position,WCHAR *name,UINT32 name_size,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetLocaleName(This,position,name,name_size,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_Draw(IDWriteTextLayout3* This,void *context,IDWriteTextRenderer *renderer,FLOAT originX,FLOAT originY) { + return This->lpVtbl->Draw(This,context,renderer,originX,originY); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetOverhangMetrics(IDWriteTextLayout3* This,DWRITE_OVERHANG_METRICS *overhangs) { + return This->lpVtbl->GetOverhangMetrics(This,overhangs); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetClusterMetrics(IDWriteTextLayout3* This,DWRITE_CLUSTER_METRICS *metrics,UINT32 max_count,UINT32 *act_count) { + return This->lpVtbl->GetClusterMetrics(This,metrics,max_count,act_count); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_DetermineMinWidth(IDWriteTextLayout3* This,FLOAT *min_width) { + return This->lpVtbl->DetermineMinWidth(This,min_width); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_HitTestPoint(IDWriteTextLayout3* This,FLOAT pointX,FLOAT pointY,WINBOOL *is_trailinghit,WINBOOL *is_inside,DWRITE_HIT_TEST_METRICS *metrics) { + return This->lpVtbl->HitTestPoint(This,pointX,pointY,is_trailinghit,is_inside,metrics); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_HitTestTextPosition(IDWriteTextLayout3* This,UINT32 textPosition,WINBOOL is_trailinghit,FLOAT *pointX,FLOAT *pointY,DWRITE_HIT_TEST_METRICS *metrics) { + return This->lpVtbl->HitTestTextPosition(This,textPosition,is_trailinghit,pointX,pointY,metrics); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_HitTestTextRange(IDWriteTextLayout3* This,UINT32 textPosition,UINT32 textLength,FLOAT originX,FLOAT originY,DWRITE_HIT_TEST_METRICS *metrics,UINT32 max_metricscount,UINT32 *actual_metricscount) { + return This->lpVtbl->HitTestTextRange(This,textPosition,textLength,originX,originY,metrics,max_metricscount,actual_metricscount); +} +/*** IDWriteTextLayout1 methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout3_SetPairKerning(IDWriteTextLayout3* This,WINBOOL is_pairkerning_enabled,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetPairKerning(This,is_pairkerning_enabled,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetPairKerning(IDWriteTextLayout3* This,UINT32 position,WINBOOL *is_pairkerning_enabled,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetPairKerning(This,position,is_pairkerning_enabled,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetCharacterSpacing(IDWriteTextLayout3* This,FLOAT leading_spacing,FLOAT trailing_spacing,FLOAT minimum_advance_width,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetCharacterSpacing(This,leading_spacing,trailing_spacing,minimum_advance_width,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetCharacterSpacing(IDWriteTextLayout3* This,UINT32 position,FLOAT *leading_spacing,FLOAT *trailing_spacing,FLOAT *minimum_advance_width,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetCharacterSpacing(This,position,leading_spacing,trailing_spacing,minimum_advance_width,range); +} +/*** IDWriteTextLayout2 methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout3_GetMetrics(IDWriteTextLayout3* This,DWRITE_TEXT_METRICS1 *metrics) { + return This->lpVtbl->IDWriteTextLayout2_GetMetrics(This,metrics); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetVerticalGlyphOrientation(IDWriteTextLayout3* This,DWRITE_VERTICAL_GLYPH_ORIENTATION orientation) { + return This->lpVtbl->SetVerticalGlyphOrientation(This,orientation); +} +static FORCEINLINE DWRITE_VERTICAL_GLYPH_ORIENTATION IDWriteTextLayout3_GetVerticalGlyphOrientation(IDWriteTextLayout3* This) { + return This->lpVtbl->GetVerticalGlyphOrientation(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetLastLineWrapping(IDWriteTextLayout3* This,WINBOOL lastline_wrapping_enabled) { + return This->lpVtbl->SetLastLineWrapping(This,lastline_wrapping_enabled); +} +static FORCEINLINE WINBOOL IDWriteTextLayout3_GetLastLineWrapping(IDWriteTextLayout3* This) { + return This->lpVtbl->GetLastLineWrapping(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetOpticalAlignment(IDWriteTextLayout3* This,DWRITE_OPTICAL_ALIGNMENT alignment) { + return This->lpVtbl->SetOpticalAlignment(This,alignment); +} +static FORCEINLINE DWRITE_OPTICAL_ALIGNMENT IDWriteTextLayout3_GetOpticalAlignment(IDWriteTextLayout3* This) { + return This->lpVtbl->GetOpticalAlignment(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetFontFallback(IDWriteTextLayout3* This,IDWriteFontFallback *fallback) { + return This->lpVtbl->SetFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetFontFallback(IDWriteTextLayout3* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetFontFallback(This,fallback); +} +/*** IDWriteTextLayout3 methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout3_InvalidateLayout(IDWriteTextLayout3* This) { + return This->lpVtbl->InvalidateLayout(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_SetLineSpacing(IDWriteTextLayout3* This,const DWRITE_LINE_SPACING *spacing) { + return This->lpVtbl->IDWriteTextLayout3_SetLineSpacing(This,spacing); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetLineSpacing(IDWriteTextLayout3* This,DWRITE_LINE_SPACING *spacing) { + return This->lpVtbl->IDWriteTextLayout3_GetLineSpacing(This,spacing); +} +static FORCEINLINE HRESULT IDWriteTextLayout3_GetLineMetrics(IDWriteTextLayout3* This,DWRITE_LINE_METRICS1 *metrics,UINT32 max_count,UINT32 *count) { + return This->lpVtbl->IDWriteTextLayout3_GetLineMetrics(This,metrics,max_count,count); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteTextLayout3_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteTextLayout4 interface + */ +#ifndef __IDWriteTextLayout4_INTERFACE_DEFINED__ +#define __IDWriteTextLayout4_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteTextLayout4, 0x05a9bf42, 0x223f, 0x4441, 0xb5,0xfb, 0x82,0x63,0x68,0x5f,0x55,0xe9); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("05a9bf42-223f-4441-b5fb-8263685f55e9") +IDWriteTextLayout4 : public IDWriteTextLayout3 +{ + virtual HRESULT STDMETHODCALLTYPE SetFontAxisValues( + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + DWRITE_TEXT_RANGE range) = 0; + + virtual UINT32 STDMETHODCALLTYPE GetFontAxisValueCount( + UINT32 pos) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontAxisValues( + UINT32 pos, + DWRITE_FONT_AXIS_VALUE *values, + UINT32 num_values, + DWRITE_TEXT_RANGE *range) = 0; + + virtual DWRITE_AUTOMATIC_FONT_AXES STDMETHODCALLTYPE GetAutomaticFontAxes( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAutomaticFontAxes( + DWRITE_AUTOMATIC_FONT_AXES axes) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteTextLayout4, 0x05a9bf42, 0x223f, 0x4441, 0xb5,0xfb, 0x82,0x63,0x68,0x5f,0x55,0xe9) +#endif +#else +typedef struct IDWriteTextLayout4Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteTextLayout4 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteTextLayout4 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteTextLayout4 *This); + + /*** IDWriteTextFormat methods ***/ + HRESULT (STDMETHODCALLTYPE *SetTextAlignment)( + IDWriteTextLayout4 *This, + DWRITE_TEXT_ALIGNMENT alignment); + + HRESULT (STDMETHODCALLTYPE *SetParagraphAlignment)( + IDWriteTextLayout4 *This, + DWRITE_PARAGRAPH_ALIGNMENT alignment); + + HRESULT (STDMETHODCALLTYPE *SetWordWrapping)( + IDWriteTextLayout4 *This, + DWRITE_WORD_WRAPPING wrapping); + + HRESULT (STDMETHODCALLTYPE *SetReadingDirection)( + IDWriteTextLayout4 *This, + DWRITE_READING_DIRECTION direction); + + HRESULT (STDMETHODCALLTYPE *SetFlowDirection)( + IDWriteTextLayout4 *This, + DWRITE_FLOW_DIRECTION direction); + + HRESULT (STDMETHODCALLTYPE *SetIncrementalTabStop)( + IDWriteTextLayout4 *This, + FLOAT tabstop); + + HRESULT (STDMETHODCALLTYPE *SetTrimming)( + IDWriteTextLayout4 *This, + const DWRITE_TRIMMING *trimming, + IDWriteInlineObject *trimming_sign); + + HRESULT (STDMETHODCALLTYPE *SetLineSpacing)( + IDWriteTextLayout4 *This, + DWRITE_LINE_SPACING_METHOD spacing, + FLOAT line_spacing, + FLOAT baseline); + + DWRITE_TEXT_ALIGNMENT (STDMETHODCALLTYPE *GetTextAlignment)( + IDWriteTextLayout4 *This); + + DWRITE_PARAGRAPH_ALIGNMENT (STDMETHODCALLTYPE *GetParagraphAlignment)( + IDWriteTextLayout4 *This); + + DWRITE_WORD_WRAPPING (STDMETHODCALLTYPE *GetWordWrapping)( + IDWriteTextLayout4 *This); + + DWRITE_READING_DIRECTION (STDMETHODCALLTYPE *GetReadingDirection)( + IDWriteTextLayout4 *This); + + DWRITE_FLOW_DIRECTION (STDMETHODCALLTYPE *GetFlowDirection)( + IDWriteTextLayout4 *This); + + FLOAT (STDMETHODCALLTYPE *GetIncrementalTabStop)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *GetTrimming)( + IDWriteTextLayout4 *This, + DWRITE_TRIMMING *options, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *GetLineSpacing)( + IDWriteTextLayout4 *This, + DWRITE_LINE_SPACING_METHOD *method, + FLOAT *spacing, + FLOAT *baseline); + + HRESULT (STDMETHODCALLTYPE *GetFontCollection)( + IDWriteTextLayout4 *This, + IDWriteFontCollection **collection); + + UINT32 (STDMETHODCALLTYPE *GetFontFamilyNameLength)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontFamilyName)( + IDWriteTextLayout4 *This, + WCHAR *name, + UINT32 size); + + DWRITE_FONT_WEIGHT (STDMETHODCALLTYPE *GetFontWeight)( + IDWriteTextLayout4 *This); + + DWRITE_FONT_STYLE (STDMETHODCALLTYPE *GetFontStyle)( + IDWriteTextLayout4 *This); + + DWRITE_FONT_STRETCH (STDMETHODCALLTYPE *GetFontStretch)( + IDWriteTextLayout4 *This); + + FLOAT (STDMETHODCALLTYPE *GetFontSize)( + IDWriteTextLayout4 *This); + + UINT32 (STDMETHODCALLTYPE *GetLocaleNameLength)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *GetLocaleName)( + IDWriteTextLayout4 *This, + WCHAR *name, + UINT32 size); + + /*** IDWriteTextLayout methods ***/ + HRESULT (STDMETHODCALLTYPE *SetMaxWidth)( + IDWriteTextLayout4 *This, + FLOAT maxWidth); + + HRESULT (STDMETHODCALLTYPE *SetMaxHeight)( + IDWriteTextLayout4 *This, + FLOAT maxHeight); + + HRESULT (STDMETHODCALLTYPE *SetFontCollection)( + IDWriteTextLayout4 *This, + IDWriteFontCollection *collection, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontFamilyName)( + IDWriteTextLayout4 *This, + const WCHAR *name, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontWeight)( + IDWriteTextLayout4 *This, + DWRITE_FONT_WEIGHT weight, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontStyle)( + IDWriteTextLayout4 *This, + DWRITE_FONT_STYLE style, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontStretch)( + IDWriteTextLayout4 *This, + DWRITE_FONT_STRETCH stretch, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetFontSize)( + IDWriteTextLayout4 *This, + FLOAT size, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetUnderline)( + IDWriteTextLayout4 *This, + WINBOOL underline, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetStrikethrough)( + IDWriteTextLayout4 *This, + WINBOOL strikethrough, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetDrawingEffect)( + IDWriteTextLayout4 *This, + IUnknown *effect, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetInlineObject)( + IDWriteTextLayout4 *This, + IDWriteInlineObject *object, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetTypography)( + IDWriteTextLayout4 *This, + IDWriteTypography *typography, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *SetLocaleName)( + IDWriteTextLayout4 *This, + const WCHAR *locale, + DWRITE_TEXT_RANGE range); + + FLOAT (STDMETHODCALLTYPE *GetMaxWidth)( + IDWriteTextLayout4 *This); + + FLOAT (STDMETHODCALLTYPE *GetMaxHeight)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontCollection)( + IDWriteTextLayout4 *This, + UINT32 pos, + IDWriteFontCollection **collection, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontFamilyNameLength)( + IDWriteTextLayout4 *This, + UINT32 pos, + UINT32 *len, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontFamilyName)( + IDWriteTextLayout4 *This, + UINT32 position, + WCHAR *name, + UINT32 name_size, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontWeight)( + IDWriteTextLayout4 *This, + UINT32 position, + DWRITE_FONT_WEIGHT *weight, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontStyle)( + IDWriteTextLayout4 *This, + UINT32 currentPosition, + DWRITE_FONT_STYLE *style, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontStretch)( + IDWriteTextLayout4 *This, + UINT32 position, + DWRITE_FONT_STRETCH *stretch, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetFontSize)( + IDWriteTextLayout4 *This, + UINT32 position, + FLOAT *size, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetUnderline)( + IDWriteTextLayout4 *This, + UINT32 position, + WINBOOL *has_underline, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetStrikethrough)( + IDWriteTextLayout4 *This, + UINT32 position, + WINBOOL *has_strikethrough, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetDrawingEffect)( + IDWriteTextLayout4 *This, + UINT32 position, + IUnknown **effect, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetInlineObject)( + IDWriteTextLayout4 *This, + UINT32 position, + IDWriteInlineObject **object, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *GetTypography)( + IDWriteTextLayout4 *This, + UINT32 position, + IDWriteTypography **typography, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetLocaleNameLength)( + IDWriteTextLayout4 *This, + UINT32 position, + UINT32 *length, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout_GetLocaleName)( + IDWriteTextLayout4 *This, + UINT32 position, + WCHAR *name, + UINT32 name_size, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *Draw)( + IDWriteTextLayout4 *This, + void *context, + IDWriteTextRenderer *renderer, + FLOAT originX, + FLOAT originY); + + HRESULT (STDMETHODCALLTYPE *GetLineMetrics)( + IDWriteTextLayout4 *This, + DWRITE_LINE_METRICS *metrics, + UINT32 max_count, + UINT32 *actual_count); + + HRESULT (STDMETHODCALLTYPE *GetMetrics)( + IDWriteTextLayout4 *This, + DWRITE_TEXT_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *GetOverhangMetrics)( + IDWriteTextLayout4 *This, + DWRITE_OVERHANG_METRICS *overhangs); + + HRESULT (STDMETHODCALLTYPE *GetClusterMetrics)( + IDWriteTextLayout4 *This, + DWRITE_CLUSTER_METRICS *metrics, + UINT32 max_count, + UINT32 *act_count); + + HRESULT (STDMETHODCALLTYPE *DetermineMinWidth)( + IDWriteTextLayout4 *This, + FLOAT *min_width); + + HRESULT (STDMETHODCALLTYPE *HitTestPoint)( + IDWriteTextLayout4 *This, + FLOAT pointX, + FLOAT pointY, + WINBOOL *is_trailinghit, + WINBOOL *is_inside, + DWRITE_HIT_TEST_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *HitTestTextPosition)( + IDWriteTextLayout4 *This, + UINT32 textPosition, + WINBOOL is_trailinghit, + FLOAT *pointX, + FLOAT *pointY, + DWRITE_HIT_TEST_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *HitTestTextRange)( + IDWriteTextLayout4 *This, + UINT32 textPosition, + UINT32 textLength, + FLOAT originX, + FLOAT originY, + DWRITE_HIT_TEST_METRICS *metrics, + UINT32 max_metricscount, + UINT32 *actual_metricscount); + + /*** IDWriteTextLayout1 methods ***/ + HRESULT (STDMETHODCALLTYPE *SetPairKerning)( + IDWriteTextLayout4 *This, + WINBOOL is_pairkerning_enabled, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *GetPairKerning)( + IDWriteTextLayout4 *This, + UINT32 position, + WINBOOL *is_pairkerning_enabled, + DWRITE_TEXT_RANGE *range); + + HRESULT (STDMETHODCALLTYPE *SetCharacterSpacing)( + IDWriteTextLayout4 *This, + FLOAT leading_spacing, + FLOAT trailing_spacing, + FLOAT minimum_advance_width, + DWRITE_TEXT_RANGE range); + + HRESULT (STDMETHODCALLTYPE *GetCharacterSpacing)( + IDWriteTextLayout4 *This, + UINT32 position, + FLOAT *leading_spacing, + FLOAT *trailing_spacing, + FLOAT *minimum_advance_width, + DWRITE_TEXT_RANGE *range); + + /*** IDWriteTextLayout2 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout2_GetMetrics)( + IDWriteTextLayout4 *This, + DWRITE_TEXT_METRICS1 *metrics); + + HRESULT (STDMETHODCALLTYPE *SetVerticalGlyphOrientation)( + IDWriteTextLayout4 *This, + DWRITE_VERTICAL_GLYPH_ORIENTATION orientation); + + DWRITE_VERTICAL_GLYPH_ORIENTATION (STDMETHODCALLTYPE *GetVerticalGlyphOrientation)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *SetLastLineWrapping)( + IDWriteTextLayout4 *This, + WINBOOL lastline_wrapping_enabled); + + WINBOOL (STDMETHODCALLTYPE *GetLastLineWrapping)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *SetOpticalAlignment)( + IDWriteTextLayout4 *This, + DWRITE_OPTICAL_ALIGNMENT alignment); + + DWRITE_OPTICAL_ALIGNMENT (STDMETHODCALLTYPE *GetOpticalAlignment)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *SetFontFallback)( + IDWriteTextLayout4 *This, + IDWriteFontFallback *fallback); + + HRESULT (STDMETHODCALLTYPE *GetFontFallback)( + IDWriteTextLayout4 *This, + IDWriteFontFallback **fallback); + + /*** IDWriteTextLayout3 methods ***/ + HRESULT (STDMETHODCALLTYPE *InvalidateLayout)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout3_SetLineSpacing)( + IDWriteTextLayout4 *This, + const DWRITE_LINE_SPACING *spacing); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout3_GetLineSpacing)( + IDWriteTextLayout4 *This, + DWRITE_LINE_SPACING *spacing); + + HRESULT (STDMETHODCALLTYPE *IDWriteTextLayout3_GetLineMetrics)( + IDWriteTextLayout4 *This, + DWRITE_LINE_METRICS1 *metrics, + UINT32 max_count, + UINT32 *count); + + /*** IDWriteTextLayout4 methods ***/ + HRESULT (STDMETHODCALLTYPE *SetFontAxisValues)( + IDWriteTextLayout4 *This, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + DWRITE_TEXT_RANGE range); + + UINT32 (STDMETHODCALLTYPE *GetFontAxisValueCount)( + IDWriteTextLayout4 *This, + UINT32 pos); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisValues)( + IDWriteTextLayout4 *This, + UINT32 pos, + DWRITE_FONT_AXIS_VALUE *values, + UINT32 num_values, + DWRITE_TEXT_RANGE *range); + + DWRITE_AUTOMATIC_FONT_AXES (STDMETHODCALLTYPE *GetAutomaticFontAxes)( + IDWriteTextLayout4 *This); + + HRESULT (STDMETHODCALLTYPE *SetAutomaticFontAxes)( + IDWriteTextLayout4 *This, + DWRITE_AUTOMATIC_FONT_AXES axes); + + END_INTERFACE +} IDWriteTextLayout4Vtbl; + +interface IDWriteTextLayout4 { + CONST_VTBL IDWriteTextLayout4Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteTextLayout4_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteTextLayout4_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteTextLayout4_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteTextFormat methods ***/ +#define IDWriteTextLayout4_SetTextAlignment(This,alignment) (This)->lpVtbl->SetTextAlignment(This,alignment) +#define IDWriteTextLayout4_SetParagraphAlignment(This,alignment) (This)->lpVtbl->SetParagraphAlignment(This,alignment) +#define IDWriteTextLayout4_SetWordWrapping(This,wrapping) (This)->lpVtbl->SetWordWrapping(This,wrapping) +#define IDWriteTextLayout4_SetReadingDirection(This,direction) (This)->lpVtbl->SetReadingDirection(This,direction) +#define IDWriteTextLayout4_SetFlowDirection(This,direction) (This)->lpVtbl->SetFlowDirection(This,direction) +#define IDWriteTextLayout4_SetIncrementalTabStop(This,tabstop) (This)->lpVtbl->SetIncrementalTabStop(This,tabstop) +#define IDWriteTextLayout4_SetTrimming(This,trimming,trimming_sign) (This)->lpVtbl->SetTrimming(This,trimming,trimming_sign) +#define IDWriteTextLayout4_GetTextAlignment(This) (This)->lpVtbl->GetTextAlignment(This) +#define IDWriteTextLayout4_GetParagraphAlignment(This) (This)->lpVtbl->GetParagraphAlignment(This) +#define IDWriteTextLayout4_GetWordWrapping(This) (This)->lpVtbl->GetWordWrapping(This) +#define IDWriteTextLayout4_GetReadingDirection(This) (This)->lpVtbl->GetReadingDirection(This) +#define IDWriteTextLayout4_GetFlowDirection(This) (This)->lpVtbl->GetFlowDirection(This) +#define IDWriteTextLayout4_GetIncrementalTabStop(This) (This)->lpVtbl->GetIncrementalTabStop(This) +#define IDWriteTextLayout4_GetTrimming(This,options,trimming_sign) (This)->lpVtbl->GetTrimming(This,options,trimming_sign) +/*** IDWriteTextLayout methods ***/ +#define IDWriteTextLayout4_SetMaxWidth(This,maxWidth) (This)->lpVtbl->SetMaxWidth(This,maxWidth) +#define IDWriteTextLayout4_SetMaxHeight(This,maxHeight) (This)->lpVtbl->SetMaxHeight(This,maxHeight) +#define IDWriteTextLayout4_SetFontCollection(This,collection,range) (This)->lpVtbl->SetFontCollection(This,collection,range) +#define IDWriteTextLayout4_SetFontFamilyName(This,name,range) (This)->lpVtbl->SetFontFamilyName(This,name,range) +#define IDWriteTextLayout4_SetFontWeight(This,weight,range) (This)->lpVtbl->SetFontWeight(This,weight,range) +#define IDWriteTextLayout4_SetFontStyle(This,style,range) (This)->lpVtbl->SetFontStyle(This,style,range) +#define IDWriteTextLayout4_SetFontStretch(This,stretch,range) (This)->lpVtbl->SetFontStretch(This,stretch,range) +#define IDWriteTextLayout4_SetFontSize(This,size,range) (This)->lpVtbl->SetFontSize(This,size,range) +#define IDWriteTextLayout4_SetUnderline(This,underline,range) (This)->lpVtbl->SetUnderline(This,underline,range) +#define IDWriteTextLayout4_SetStrikethrough(This,strikethrough,range) (This)->lpVtbl->SetStrikethrough(This,strikethrough,range) +#define IDWriteTextLayout4_SetDrawingEffect(This,effect,range) (This)->lpVtbl->SetDrawingEffect(This,effect,range) +#define IDWriteTextLayout4_SetInlineObject(This,object,range) (This)->lpVtbl->SetInlineObject(This,object,range) +#define IDWriteTextLayout4_SetTypography(This,typography,range) (This)->lpVtbl->SetTypography(This,typography,range) +#define IDWriteTextLayout4_SetLocaleName(This,locale,range) (This)->lpVtbl->SetLocaleName(This,locale,range) +#define IDWriteTextLayout4_GetMaxWidth(This) (This)->lpVtbl->GetMaxWidth(This) +#define IDWriteTextLayout4_GetMaxHeight(This) (This)->lpVtbl->GetMaxHeight(This) +#define IDWriteTextLayout4_GetFontCollection(This,pos,collection,range) (This)->lpVtbl->IDWriteTextLayout_GetFontCollection(This,pos,collection,range) +#define IDWriteTextLayout4_GetFontFamilyNameLength(This,pos,len,range) (This)->lpVtbl->IDWriteTextLayout_GetFontFamilyNameLength(This,pos,len,range) +#define IDWriteTextLayout4_GetFontFamilyName(This,position,name,name_size,range) (This)->lpVtbl->IDWriteTextLayout_GetFontFamilyName(This,position,name,name_size,range) +#define IDWriteTextLayout4_GetFontWeight(This,position,weight,range) (This)->lpVtbl->IDWriteTextLayout_GetFontWeight(This,position,weight,range) +#define IDWriteTextLayout4_GetFontStyle(This,currentPosition,style,range) (This)->lpVtbl->IDWriteTextLayout_GetFontStyle(This,currentPosition,style,range) +#define IDWriteTextLayout4_GetFontStretch(This,position,stretch,range) (This)->lpVtbl->IDWriteTextLayout_GetFontStretch(This,position,stretch,range) +#define IDWriteTextLayout4_GetFontSize(This,position,size,range) (This)->lpVtbl->IDWriteTextLayout_GetFontSize(This,position,size,range) +#define IDWriteTextLayout4_GetUnderline(This,position,has_underline,range) (This)->lpVtbl->GetUnderline(This,position,has_underline,range) +#define IDWriteTextLayout4_GetStrikethrough(This,position,has_strikethrough,range) (This)->lpVtbl->GetStrikethrough(This,position,has_strikethrough,range) +#define IDWriteTextLayout4_GetDrawingEffect(This,position,effect,range) (This)->lpVtbl->GetDrawingEffect(This,position,effect,range) +#define IDWriteTextLayout4_GetInlineObject(This,position,object,range) (This)->lpVtbl->GetInlineObject(This,position,object,range) +#define IDWriteTextLayout4_GetTypography(This,position,typography,range) (This)->lpVtbl->GetTypography(This,position,typography,range) +#define IDWriteTextLayout4_GetLocaleNameLength(This,position,length,range) (This)->lpVtbl->IDWriteTextLayout_GetLocaleNameLength(This,position,length,range) +#define IDWriteTextLayout4_GetLocaleName(This,position,name,name_size,range) (This)->lpVtbl->IDWriteTextLayout_GetLocaleName(This,position,name,name_size,range) +#define IDWriteTextLayout4_Draw(This,context,renderer,originX,originY) (This)->lpVtbl->Draw(This,context,renderer,originX,originY) +#define IDWriteTextLayout4_GetOverhangMetrics(This,overhangs) (This)->lpVtbl->GetOverhangMetrics(This,overhangs) +#define IDWriteTextLayout4_GetClusterMetrics(This,metrics,max_count,act_count) (This)->lpVtbl->GetClusterMetrics(This,metrics,max_count,act_count) +#define IDWriteTextLayout4_DetermineMinWidth(This,min_width) (This)->lpVtbl->DetermineMinWidth(This,min_width) +#define IDWriteTextLayout4_HitTestPoint(This,pointX,pointY,is_trailinghit,is_inside,metrics) (This)->lpVtbl->HitTestPoint(This,pointX,pointY,is_trailinghit,is_inside,metrics) +#define IDWriteTextLayout4_HitTestTextPosition(This,textPosition,is_trailinghit,pointX,pointY,metrics) (This)->lpVtbl->HitTestTextPosition(This,textPosition,is_trailinghit,pointX,pointY,metrics) +#define IDWriteTextLayout4_HitTestTextRange(This,textPosition,textLength,originX,originY,metrics,max_metricscount,actual_metricscount) (This)->lpVtbl->HitTestTextRange(This,textPosition,textLength,originX,originY,metrics,max_metricscount,actual_metricscount) +/*** IDWriteTextLayout1 methods ***/ +#define IDWriteTextLayout4_SetPairKerning(This,is_pairkerning_enabled,range) (This)->lpVtbl->SetPairKerning(This,is_pairkerning_enabled,range) +#define IDWriteTextLayout4_GetPairKerning(This,position,is_pairkerning_enabled,range) (This)->lpVtbl->GetPairKerning(This,position,is_pairkerning_enabled,range) +#define IDWriteTextLayout4_SetCharacterSpacing(This,leading_spacing,trailing_spacing,minimum_advance_width,range) (This)->lpVtbl->SetCharacterSpacing(This,leading_spacing,trailing_spacing,minimum_advance_width,range) +#define IDWriteTextLayout4_GetCharacterSpacing(This,position,leading_spacing,trailing_spacing,minimum_advance_width,range) (This)->lpVtbl->GetCharacterSpacing(This,position,leading_spacing,trailing_spacing,minimum_advance_width,range) +/*** IDWriteTextLayout2 methods ***/ +#define IDWriteTextLayout4_GetMetrics(This,metrics) (This)->lpVtbl->IDWriteTextLayout2_GetMetrics(This,metrics) +#define IDWriteTextLayout4_SetVerticalGlyphOrientation(This,orientation) (This)->lpVtbl->SetVerticalGlyphOrientation(This,orientation) +#define IDWriteTextLayout4_GetVerticalGlyphOrientation(This) (This)->lpVtbl->GetVerticalGlyphOrientation(This) +#define IDWriteTextLayout4_SetLastLineWrapping(This,lastline_wrapping_enabled) (This)->lpVtbl->SetLastLineWrapping(This,lastline_wrapping_enabled) +#define IDWriteTextLayout4_GetLastLineWrapping(This) (This)->lpVtbl->GetLastLineWrapping(This) +#define IDWriteTextLayout4_SetOpticalAlignment(This,alignment) (This)->lpVtbl->SetOpticalAlignment(This,alignment) +#define IDWriteTextLayout4_GetOpticalAlignment(This) (This)->lpVtbl->GetOpticalAlignment(This) +#define IDWriteTextLayout4_SetFontFallback(This,fallback) (This)->lpVtbl->SetFontFallback(This,fallback) +#define IDWriteTextLayout4_GetFontFallback(This,fallback) (This)->lpVtbl->GetFontFallback(This,fallback) +/*** IDWriteTextLayout3 methods ***/ +#define IDWriteTextLayout4_InvalidateLayout(This) (This)->lpVtbl->InvalidateLayout(This) +#define IDWriteTextLayout4_SetLineSpacing(This,spacing) (This)->lpVtbl->IDWriteTextLayout3_SetLineSpacing(This,spacing) +#define IDWriteTextLayout4_GetLineSpacing(This,spacing) (This)->lpVtbl->IDWriteTextLayout3_GetLineSpacing(This,spacing) +#define IDWriteTextLayout4_GetLineMetrics(This,metrics,max_count,count) (This)->lpVtbl->IDWriteTextLayout3_GetLineMetrics(This,metrics,max_count,count) +/*** IDWriteTextLayout4 methods ***/ +#define IDWriteTextLayout4_SetFontAxisValues(This,axis_values,num_values,range) (This)->lpVtbl->SetFontAxisValues(This,axis_values,num_values,range) +#define IDWriteTextLayout4_GetFontAxisValueCount(This,pos) (This)->lpVtbl->GetFontAxisValueCount(This,pos) +#define IDWriteTextLayout4_GetFontAxisValues(This,pos,values,num_values,range) (This)->lpVtbl->GetFontAxisValues(This,pos,values,num_values,range) +#define IDWriteTextLayout4_GetAutomaticFontAxes(This) (This)->lpVtbl->GetAutomaticFontAxes(This) +#define IDWriteTextLayout4_SetAutomaticFontAxes(This,axes) (This)->lpVtbl->SetAutomaticFontAxes(This,axes) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout4_QueryInterface(IDWriteTextLayout4* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteTextLayout4_AddRef(IDWriteTextLayout4* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteTextLayout4_Release(IDWriteTextLayout4* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteTextFormat methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout4_SetTextAlignment(IDWriteTextLayout4* This,DWRITE_TEXT_ALIGNMENT alignment) { + return This->lpVtbl->SetTextAlignment(This,alignment); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetParagraphAlignment(IDWriteTextLayout4* This,DWRITE_PARAGRAPH_ALIGNMENT alignment) { + return This->lpVtbl->SetParagraphAlignment(This,alignment); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetWordWrapping(IDWriteTextLayout4* This,DWRITE_WORD_WRAPPING wrapping) { + return This->lpVtbl->SetWordWrapping(This,wrapping); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetReadingDirection(IDWriteTextLayout4* This,DWRITE_READING_DIRECTION direction) { + return This->lpVtbl->SetReadingDirection(This,direction); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFlowDirection(IDWriteTextLayout4* This,DWRITE_FLOW_DIRECTION direction) { + return This->lpVtbl->SetFlowDirection(This,direction); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetIncrementalTabStop(IDWriteTextLayout4* This,FLOAT tabstop) { + return This->lpVtbl->SetIncrementalTabStop(This,tabstop); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetTrimming(IDWriteTextLayout4* This,const DWRITE_TRIMMING *trimming,IDWriteInlineObject *trimming_sign) { + return This->lpVtbl->SetTrimming(This,trimming,trimming_sign); +} +static FORCEINLINE DWRITE_TEXT_ALIGNMENT IDWriteTextLayout4_GetTextAlignment(IDWriteTextLayout4* This) { + return This->lpVtbl->GetTextAlignment(This); +} +static FORCEINLINE DWRITE_PARAGRAPH_ALIGNMENT IDWriteTextLayout4_GetParagraphAlignment(IDWriteTextLayout4* This) { + return This->lpVtbl->GetParagraphAlignment(This); +} +static FORCEINLINE DWRITE_WORD_WRAPPING IDWriteTextLayout4_GetWordWrapping(IDWriteTextLayout4* This) { + return This->lpVtbl->GetWordWrapping(This); +} +static FORCEINLINE DWRITE_READING_DIRECTION IDWriteTextLayout4_GetReadingDirection(IDWriteTextLayout4* This) { + return This->lpVtbl->GetReadingDirection(This); +} +static FORCEINLINE DWRITE_FLOW_DIRECTION IDWriteTextLayout4_GetFlowDirection(IDWriteTextLayout4* This) { + return This->lpVtbl->GetFlowDirection(This); +} +static FORCEINLINE FLOAT IDWriteTextLayout4_GetIncrementalTabStop(IDWriteTextLayout4* This) { + return This->lpVtbl->GetIncrementalTabStop(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetTrimming(IDWriteTextLayout4* This,DWRITE_TRIMMING *options,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->GetTrimming(This,options,trimming_sign); +} +/*** IDWriteTextLayout methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout4_SetMaxWidth(IDWriteTextLayout4* This,FLOAT maxWidth) { + return This->lpVtbl->SetMaxWidth(This,maxWidth); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetMaxHeight(IDWriteTextLayout4* This,FLOAT maxHeight) { + return This->lpVtbl->SetMaxHeight(This,maxHeight); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFontCollection(IDWriteTextLayout4* This,IDWriteFontCollection *collection,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontCollection(This,collection,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFontFamilyName(IDWriteTextLayout4* This,const WCHAR *name,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontFamilyName(This,name,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFontWeight(IDWriteTextLayout4* This,DWRITE_FONT_WEIGHT weight,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontWeight(This,weight,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFontStyle(IDWriteTextLayout4* This,DWRITE_FONT_STYLE style,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontStyle(This,style,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFontStretch(IDWriteTextLayout4* This,DWRITE_FONT_STRETCH stretch,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontStretch(This,stretch,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFontSize(IDWriteTextLayout4* This,FLOAT size,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontSize(This,size,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetUnderline(IDWriteTextLayout4* This,WINBOOL underline,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetUnderline(This,underline,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetStrikethrough(IDWriteTextLayout4* This,WINBOOL strikethrough,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetStrikethrough(This,strikethrough,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetDrawingEffect(IDWriteTextLayout4* This,IUnknown *effect,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetDrawingEffect(This,effect,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetInlineObject(IDWriteTextLayout4* This,IDWriteInlineObject *object,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetInlineObject(This,object,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetTypography(IDWriteTextLayout4* This,IDWriteTypography *typography,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetTypography(This,typography,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetLocaleName(IDWriteTextLayout4* This,const WCHAR *locale,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetLocaleName(This,locale,range); +} +static FORCEINLINE FLOAT IDWriteTextLayout4_GetMaxWidth(IDWriteTextLayout4* This) { + return This->lpVtbl->GetMaxWidth(This); +} +static FORCEINLINE FLOAT IDWriteTextLayout4_GetMaxHeight(IDWriteTextLayout4* This) { + return This->lpVtbl->GetMaxHeight(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontCollection(IDWriteTextLayout4* This,UINT32 pos,IDWriteFontCollection **collection,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontCollection(This,pos,collection,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontFamilyNameLength(IDWriteTextLayout4* This,UINT32 pos,UINT32 *len,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontFamilyNameLength(This,pos,len,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontFamilyName(IDWriteTextLayout4* This,UINT32 position,WCHAR *name,UINT32 name_size,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontFamilyName(This,position,name,name_size,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontWeight(IDWriteTextLayout4* This,UINT32 position,DWRITE_FONT_WEIGHT *weight,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontWeight(This,position,weight,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontStyle(IDWriteTextLayout4* This,UINT32 currentPosition,DWRITE_FONT_STYLE *style,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontStyle(This,currentPosition,style,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontStretch(IDWriteTextLayout4* This,UINT32 position,DWRITE_FONT_STRETCH *stretch,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontStretch(This,position,stretch,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontSize(IDWriteTextLayout4* This,UINT32 position,FLOAT *size,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetFontSize(This,position,size,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetUnderline(IDWriteTextLayout4* This,UINT32 position,WINBOOL *has_underline,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetUnderline(This,position,has_underline,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetStrikethrough(IDWriteTextLayout4* This,UINT32 position,WINBOOL *has_strikethrough,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetStrikethrough(This,position,has_strikethrough,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetDrawingEffect(IDWriteTextLayout4* This,UINT32 position,IUnknown **effect,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetDrawingEffect(This,position,effect,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetInlineObject(IDWriteTextLayout4* This,UINT32 position,IDWriteInlineObject **object,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetInlineObject(This,position,object,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetTypography(IDWriteTextLayout4* This,UINT32 position,IDWriteTypography **typography,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetTypography(This,position,typography,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetLocaleNameLength(IDWriteTextLayout4* This,UINT32 position,UINT32 *length,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetLocaleNameLength(This,position,length,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetLocaleName(IDWriteTextLayout4* This,UINT32 position,WCHAR *name,UINT32 name_size,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->IDWriteTextLayout_GetLocaleName(This,position,name,name_size,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_Draw(IDWriteTextLayout4* This,void *context,IDWriteTextRenderer *renderer,FLOAT originX,FLOAT originY) { + return This->lpVtbl->Draw(This,context,renderer,originX,originY); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetOverhangMetrics(IDWriteTextLayout4* This,DWRITE_OVERHANG_METRICS *overhangs) { + return This->lpVtbl->GetOverhangMetrics(This,overhangs); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetClusterMetrics(IDWriteTextLayout4* This,DWRITE_CLUSTER_METRICS *metrics,UINT32 max_count,UINT32 *act_count) { + return This->lpVtbl->GetClusterMetrics(This,metrics,max_count,act_count); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_DetermineMinWidth(IDWriteTextLayout4* This,FLOAT *min_width) { + return This->lpVtbl->DetermineMinWidth(This,min_width); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_HitTestPoint(IDWriteTextLayout4* This,FLOAT pointX,FLOAT pointY,WINBOOL *is_trailinghit,WINBOOL *is_inside,DWRITE_HIT_TEST_METRICS *metrics) { + return This->lpVtbl->HitTestPoint(This,pointX,pointY,is_trailinghit,is_inside,metrics); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_HitTestTextPosition(IDWriteTextLayout4* This,UINT32 textPosition,WINBOOL is_trailinghit,FLOAT *pointX,FLOAT *pointY,DWRITE_HIT_TEST_METRICS *metrics) { + return This->lpVtbl->HitTestTextPosition(This,textPosition,is_trailinghit,pointX,pointY,metrics); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_HitTestTextRange(IDWriteTextLayout4* This,UINT32 textPosition,UINT32 textLength,FLOAT originX,FLOAT originY,DWRITE_HIT_TEST_METRICS *metrics,UINT32 max_metricscount,UINT32 *actual_metricscount) { + return This->lpVtbl->HitTestTextRange(This,textPosition,textLength,originX,originY,metrics,max_metricscount,actual_metricscount); +} +/*** IDWriteTextLayout1 methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout4_SetPairKerning(IDWriteTextLayout4* This,WINBOOL is_pairkerning_enabled,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetPairKerning(This,is_pairkerning_enabled,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetPairKerning(IDWriteTextLayout4* This,UINT32 position,WINBOOL *is_pairkerning_enabled,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetPairKerning(This,position,is_pairkerning_enabled,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetCharacterSpacing(IDWriteTextLayout4* This,FLOAT leading_spacing,FLOAT trailing_spacing,FLOAT minimum_advance_width,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetCharacterSpacing(This,leading_spacing,trailing_spacing,minimum_advance_width,range); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetCharacterSpacing(IDWriteTextLayout4* This,UINT32 position,FLOAT *leading_spacing,FLOAT *trailing_spacing,FLOAT *minimum_advance_width,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetCharacterSpacing(This,position,leading_spacing,trailing_spacing,minimum_advance_width,range); +} +/*** IDWriteTextLayout2 methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout4_GetMetrics(IDWriteTextLayout4* This,DWRITE_TEXT_METRICS1 *metrics) { + return This->lpVtbl->IDWriteTextLayout2_GetMetrics(This,metrics); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetVerticalGlyphOrientation(IDWriteTextLayout4* This,DWRITE_VERTICAL_GLYPH_ORIENTATION orientation) { + return This->lpVtbl->SetVerticalGlyphOrientation(This,orientation); +} +static FORCEINLINE DWRITE_VERTICAL_GLYPH_ORIENTATION IDWriteTextLayout4_GetVerticalGlyphOrientation(IDWriteTextLayout4* This) { + return This->lpVtbl->GetVerticalGlyphOrientation(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetLastLineWrapping(IDWriteTextLayout4* This,WINBOOL lastline_wrapping_enabled) { + return This->lpVtbl->SetLastLineWrapping(This,lastline_wrapping_enabled); +} +static FORCEINLINE WINBOOL IDWriteTextLayout4_GetLastLineWrapping(IDWriteTextLayout4* This) { + return This->lpVtbl->GetLastLineWrapping(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetOpticalAlignment(IDWriteTextLayout4* This,DWRITE_OPTICAL_ALIGNMENT alignment) { + return This->lpVtbl->SetOpticalAlignment(This,alignment); +} +static FORCEINLINE DWRITE_OPTICAL_ALIGNMENT IDWriteTextLayout4_GetOpticalAlignment(IDWriteTextLayout4* This) { + return This->lpVtbl->GetOpticalAlignment(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFontFallback(IDWriteTextLayout4* This,IDWriteFontFallback *fallback) { + return This->lpVtbl->SetFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontFallback(IDWriteTextLayout4* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetFontFallback(This,fallback); +} +/*** IDWriteTextLayout3 methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout4_InvalidateLayout(IDWriteTextLayout4* This) { + return This->lpVtbl->InvalidateLayout(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetLineSpacing(IDWriteTextLayout4* This,const DWRITE_LINE_SPACING *spacing) { + return This->lpVtbl->IDWriteTextLayout3_SetLineSpacing(This,spacing); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetLineSpacing(IDWriteTextLayout4* This,DWRITE_LINE_SPACING *spacing) { + return This->lpVtbl->IDWriteTextLayout3_GetLineSpacing(This,spacing); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetLineMetrics(IDWriteTextLayout4* This,DWRITE_LINE_METRICS1 *metrics,UINT32 max_count,UINT32 *count) { + return This->lpVtbl->IDWriteTextLayout3_GetLineMetrics(This,metrics,max_count,count); +} +/*** IDWriteTextLayout4 methods ***/ +static FORCEINLINE HRESULT IDWriteTextLayout4_SetFontAxisValues(IDWriteTextLayout4* This,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,DWRITE_TEXT_RANGE range) { + return This->lpVtbl->SetFontAxisValues(This,axis_values,num_values,range); +} +static FORCEINLINE UINT32 IDWriteTextLayout4_GetFontAxisValueCount(IDWriteTextLayout4* This,UINT32 pos) { + return This->lpVtbl->GetFontAxisValueCount(This,pos); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_GetFontAxisValues(IDWriteTextLayout4* This,UINT32 pos,DWRITE_FONT_AXIS_VALUE *values,UINT32 num_values,DWRITE_TEXT_RANGE *range) { + return This->lpVtbl->GetFontAxisValues(This,pos,values,num_values,range); +} +static FORCEINLINE DWRITE_AUTOMATIC_FONT_AXES IDWriteTextLayout4_GetAutomaticFontAxes(IDWriteTextLayout4* This) { + return This->lpVtbl->GetAutomaticFontAxes(This); +} +static FORCEINLINE HRESULT IDWriteTextLayout4_SetAutomaticFontAxes(IDWriteTextLayout4* This,DWRITE_AUTOMATIC_FONT_AXES axes) { + return This->lpVtbl->SetAutomaticFontAxes(This,axes); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteTextLayout4_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontFallback1 interface + */ +#ifndef __IDWriteFontFallback1_INTERFACE_DEFINED__ +#define __IDWriteFontFallback1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontFallback1, 0x2397599d, 0xdd0d, 0x4681, 0xbd,0x6a, 0xf4,0xf3,0x1e,0xaa,0xde,0x77); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("2397599d-dd0d-4681-bd6a-f4f31eaade77") +IDWriteFontFallback1 : public IDWriteFontFallback +{ + virtual HRESULT STDMETHODCALLTYPE MapCharacters( + IDWriteTextAnalysisSource *source, + UINT32 pos, + UINT32 length, + IDWriteFontCollection *base_collection, + const WCHAR *familyname, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + UINT32 *mapped_length, + FLOAT *scale, + IDWriteFontFace5 **fontface) = 0; + + using IDWriteFontFallback::MapCharacters; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontFallback1, 0x2397599d, 0xdd0d, 0x4681, 0xbd,0x6a, 0xf4,0xf3,0x1e,0xaa,0xde,0x77) +#endif +#else +typedef struct IDWriteFontFallback1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontFallback1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontFallback1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontFallback1 *This); + + /*** IDWriteFontFallback methods ***/ + HRESULT (STDMETHODCALLTYPE *MapCharacters)( + IDWriteFontFallback1 *This, + IDWriteTextAnalysisSource *source, + UINT32 position, + UINT32 length, + IDWriteFontCollection *basecollection, + const WCHAR *baseFamilyName, + DWRITE_FONT_WEIGHT baseWeight, + DWRITE_FONT_STYLE baseStyle, + DWRITE_FONT_STRETCH baseStretch, + UINT32 *mappedLength, + IDWriteFont **mappedFont, + FLOAT *scale); + + /*** IDWriteFontFallback1 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFontFallback1_MapCharacters)( + IDWriteFontFallback1 *This, + IDWriteTextAnalysisSource *source, + UINT32 pos, + UINT32 length, + IDWriteFontCollection *base_collection, + const WCHAR *familyname, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + UINT32 *mapped_length, + FLOAT *scale, + IDWriteFontFace5 **fontface); + + END_INTERFACE +} IDWriteFontFallback1Vtbl; + +interface IDWriteFontFallback1 { + CONST_VTBL IDWriteFontFallback1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontFallback1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFallback1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFallback1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFallback methods ***/ +/*** IDWriteFontFallback1 methods ***/ +#define IDWriteFontFallback1_MapCharacters(This,source,pos,length,base_collection,familyname,axis_values,num_values,mapped_length,scale,fontface) (This)->lpVtbl->IDWriteFontFallback1_MapCharacters(This,source,pos,length,base_collection,familyname,axis_values,num_values,mapped_length,scale,fontface) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontFallback1_QueryInterface(IDWriteFontFallback1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontFallback1_AddRef(IDWriteFontFallback1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontFallback1_Release(IDWriteFontFallback1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFallback methods ***/ +/*** IDWriteFontFallback1 methods ***/ +static FORCEINLINE HRESULT IDWriteFontFallback1_MapCharacters(IDWriteFontFallback1* This,IDWriteTextAnalysisSource *source,UINT32 pos,UINT32 length,IDWriteFontCollection *base_collection,const WCHAR *familyname,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,UINT32 *mapped_length,FLOAT *scale,IDWriteFontFace5 **fontface) { + return This->lpVtbl->IDWriteFontFallback1_MapCharacters(This,source,pos,length,base_collection,familyname,axis_values,num_values,mapped_length,scale,fontface); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontFallback1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteGdiInterop1 interface + */ +#ifndef __IDWriteGdiInterop1_INTERFACE_DEFINED__ +#define __IDWriteGdiInterop1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteGdiInterop1, 0x4556be70, 0x3abd, 0x4f70, 0x90,0xbe, 0x42,0x17,0x80,0xa6,0xf5,0x15); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("4556be70-3abd-4f70-90be-421780a6f515") +IDWriteGdiInterop1 : public IDWriteGdiInterop +{ + virtual HRESULT STDMETHODCALLTYPE CreateFontFromLOGFONT( + const LOGFONTW *logfont, + IDWriteFontCollection *collection, + IDWriteFont **font) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontSignature( + IDWriteFontFace *fontface, + FONTSIGNATURE *fontsig) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontSignature( + IDWriteFont *font, + FONTSIGNATURE *fontsig) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetMatchingFontsByLOGFONT( + const LOGFONTW *logfont, + IDWriteFontSet *fontset, + IDWriteFontSet **subset) = 0; + + using IDWriteGdiInterop::CreateFontFromLOGFONT; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteGdiInterop1, 0x4556be70, 0x3abd, 0x4f70, 0x90,0xbe, 0x42,0x17,0x80,0xa6,0xf5,0x15) +#endif +#else +typedef struct IDWriteGdiInterop1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteGdiInterop1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteGdiInterop1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteGdiInterop1 *This); + + /*** IDWriteGdiInterop methods ***/ + HRESULT (STDMETHODCALLTYPE *CreateFontFromLOGFONT)( + IDWriteGdiInterop1 *This, + const LOGFONTW *logfont, + IDWriteFont **font); + + HRESULT (STDMETHODCALLTYPE *ConvertFontToLOGFONT)( + IDWriteGdiInterop1 *This, + IDWriteFont *font, + LOGFONTW *logfont, + WINBOOL *is_systemfont); + + HRESULT (STDMETHODCALLTYPE *ConvertFontFaceToLOGFONT)( + IDWriteGdiInterop1 *This, + IDWriteFontFace *font, + LOGFONTW *logfont); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceFromHdc)( + IDWriteGdiInterop1 *This, + HDC hdc, + IDWriteFontFace **fontface); + + HRESULT (STDMETHODCALLTYPE *CreateBitmapRenderTarget)( + IDWriteGdiInterop1 *This, + HDC hdc, + UINT32 width, + UINT32 height, + IDWriteBitmapRenderTarget **target); + + /*** IDWriteGdiInterop1 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteGdiInterop1_CreateFontFromLOGFONT)( + IDWriteGdiInterop1 *This, + const LOGFONTW *logfont, + IDWriteFontCollection *collection, + IDWriteFont **font); + + HRESULT (STDMETHODCALLTYPE *GetFontSignature_)( + IDWriteGdiInterop1 *This, + IDWriteFontFace *fontface, + FONTSIGNATURE *fontsig); + + HRESULT (STDMETHODCALLTYPE *GetFontSignature)( + IDWriteGdiInterop1 *This, + IDWriteFont *font, + FONTSIGNATURE *fontsig); + + HRESULT (STDMETHODCALLTYPE *GetMatchingFontsByLOGFONT)( + IDWriteGdiInterop1 *This, + const LOGFONTW *logfont, + IDWriteFontSet *fontset, + IDWriteFontSet **subset); + + END_INTERFACE +} IDWriteGdiInterop1Vtbl; + +interface IDWriteGdiInterop1 { + CONST_VTBL IDWriteGdiInterop1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteGdiInterop1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteGdiInterop1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteGdiInterop1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteGdiInterop methods ***/ +#define IDWriteGdiInterop1_ConvertFontToLOGFONT(This,font,logfont,is_systemfont) (This)->lpVtbl->ConvertFontToLOGFONT(This,font,logfont,is_systemfont) +#define IDWriteGdiInterop1_ConvertFontFaceToLOGFONT(This,font,logfont) (This)->lpVtbl->ConvertFontFaceToLOGFONT(This,font,logfont) +#define IDWriteGdiInterop1_CreateFontFaceFromHdc(This,hdc,fontface) (This)->lpVtbl->CreateFontFaceFromHdc(This,hdc,fontface) +#define IDWriteGdiInterop1_CreateBitmapRenderTarget(This,hdc,width,height,target) (This)->lpVtbl->CreateBitmapRenderTarget(This,hdc,width,height,target) +/*** IDWriteGdiInterop1 methods ***/ +#define IDWriteGdiInterop1_CreateFontFromLOGFONT(This,logfont,collection,font) (This)->lpVtbl->IDWriteGdiInterop1_CreateFontFromLOGFONT(This,logfont,collection,font) +#define IDWriteGdiInterop1_GetFontSignature_(This,fontface,fontsig) (This)->lpVtbl->GetFontSignature_(This,fontface,fontsig) +#define IDWriteGdiInterop1_GetFontSignature(This,font,fontsig) (This)->lpVtbl->GetFontSignature(This,font,fontsig) +#define IDWriteGdiInterop1_GetMatchingFontsByLOGFONT(This,logfont,fontset,subset) (This)->lpVtbl->GetMatchingFontsByLOGFONT(This,logfont,fontset,subset) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteGdiInterop1_QueryInterface(IDWriteGdiInterop1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteGdiInterop1_AddRef(IDWriteGdiInterop1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteGdiInterop1_Release(IDWriteGdiInterop1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteGdiInterop methods ***/ +static FORCEINLINE HRESULT IDWriteGdiInterop1_ConvertFontToLOGFONT(IDWriteGdiInterop1* This,IDWriteFont *font,LOGFONTW *logfont,WINBOOL *is_systemfont) { + return This->lpVtbl->ConvertFontToLOGFONT(This,font,logfont,is_systemfont); +} +static FORCEINLINE HRESULT IDWriteGdiInterop1_ConvertFontFaceToLOGFONT(IDWriteGdiInterop1* This,IDWriteFontFace *font,LOGFONTW *logfont) { + return This->lpVtbl->ConvertFontFaceToLOGFONT(This,font,logfont); +} +static FORCEINLINE HRESULT IDWriteGdiInterop1_CreateFontFaceFromHdc(IDWriteGdiInterop1* This,HDC hdc,IDWriteFontFace **fontface) { + return This->lpVtbl->CreateFontFaceFromHdc(This,hdc,fontface); +} +static FORCEINLINE HRESULT IDWriteGdiInterop1_CreateBitmapRenderTarget(IDWriteGdiInterop1* This,HDC hdc,UINT32 width,UINT32 height,IDWriteBitmapRenderTarget **target) { + return This->lpVtbl->CreateBitmapRenderTarget(This,hdc,width,height,target); +} +/*** IDWriteGdiInterop1 methods ***/ +static FORCEINLINE HRESULT IDWriteGdiInterop1_CreateFontFromLOGFONT(IDWriteGdiInterop1* This,const LOGFONTW *logfont,IDWriteFontCollection *collection,IDWriteFont **font) { + return This->lpVtbl->IDWriteGdiInterop1_CreateFontFromLOGFONT(This,logfont,collection,font); +} +static FORCEINLINE HRESULT IDWriteGdiInterop1_GetFontSignature_(IDWriteGdiInterop1* This,IDWriteFontFace *fontface,FONTSIGNATURE *fontsig) { + return This->lpVtbl->GetFontSignature_(This,fontface,fontsig); +} +static FORCEINLINE HRESULT IDWriteGdiInterop1_GetFontSignature(IDWriteGdiInterop1* This,IDWriteFont *font,FONTSIGNATURE *fontsig) { + return This->lpVtbl->GetFontSignature(This,font,fontsig); +} +static FORCEINLINE HRESULT IDWriteGdiInterop1_GetMatchingFontsByLOGFONT(IDWriteGdiInterop1* This,const LOGFONTW *logfont,IDWriteFontSet *fontset,IDWriteFontSet **subset) { + return This->lpVtbl->GetMatchingFontsByLOGFONT(This,logfont,fontset,subset); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteGdiInterop1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontSetBuilder interface + */ +#ifndef __IDWriteFontSetBuilder_INTERFACE_DEFINED__ +#define __IDWriteFontSetBuilder_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontSetBuilder, 0x2f642afe, 0x9c68, 0x4f40, 0xb8,0xbe, 0x45,0x74,0x01,0xaf,0xcb,0x3d); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("2f642afe-9c68-4f40-b8be-457401afcb3d") +IDWriteFontSetBuilder : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE AddFontFaceReference( + IDWriteFontFaceReference *ref, + const DWRITE_FONT_PROPERTY *props, + UINT32 prop_count) = 0; + + virtual HRESULT STDMETHODCALLTYPE AddFontFaceReference( + IDWriteFontFaceReference *ref) = 0; + + virtual HRESULT STDMETHODCALLTYPE AddFontSet( + IDWriteFontSet *fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontSet( + IDWriteFontSet **fontset) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontSetBuilder, 0x2f642afe, 0x9c68, 0x4f40, 0xb8,0xbe, 0x45,0x74,0x01,0xaf,0xcb,0x3d) +#endif +#else +typedef struct IDWriteFontSetBuilderVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontSetBuilder *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontSetBuilder *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontSetBuilder *This); + + /*** IDWriteFontSetBuilder methods ***/ + HRESULT (STDMETHODCALLTYPE *AddFontFaceReference_)( + IDWriteFontSetBuilder *This, + IDWriteFontFaceReference *ref, + const DWRITE_FONT_PROPERTY *props, + UINT32 prop_count); + + HRESULT (STDMETHODCALLTYPE *AddFontFaceReference)( + IDWriteFontSetBuilder *This, + IDWriteFontFaceReference *ref); + + HRESULT (STDMETHODCALLTYPE *AddFontSet)( + IDWriteFontSetBuilder *This, + IDWriteFontSet *fontset); + + HRESULT (STDMETHODCALLTYPE *CreateFontSet)( + IDWriteFontSetBuilder *This, + IDWriteFontSet **fontset); + + END_INTERFACE +} IDWriteFontSetBuilderVtbl; + +interface IDWriteFontSetBuilder { + CONST_VTBL IDWriteFontSetBuilderVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontSetBuilder_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontSetBuilder_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontSetBuilder_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontSetBuilder methods ***/ +#define IDWriteFontSetBuilder_AddFontFaceReference_(This,ref,props,prop_count) (This)->lpVtbl->AddFontFaceReference_(This,ref,props,prop_count) +#define IDWriteFontSetBuilder_AddFontFaceReference(This,ref) (This)->lpVtbl->AddFontFaceReference(This,ref) +#define IDWriteFontSetBuilder_AddFontSet(This,fontset) (This)->lpVtbl->AddFontSet(This,fontset) +#define IDWriteFontSetBuilder_CreateFontSet(This,fontset) (This)->lpVtbl->CreateFontSet(This,fontset) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontSetBuilder_QueryInterface(IDWriteFontSetBuilder* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontSetBuilder_AddRef(IDWriteFontSetBuilder* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontSetBuilder_Release(IDWriteFontSetBuilder* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontSetBuilder methods ***/ +static FORCEINLINE HRESULT IDWriteFontSetBuilder_AddFontFaceReference_(IDWriteFontSetBuilder* This,IDWriteFontFaceReference *ref,const DWRITE_FONT_PROPERTY *props,UINT32 prop_count) { + return This->lpVtbl->AddFontFaceReference_(This,ref,props,prop_count); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder_AddFontFaceReference(IDWriteFontSetBuilder* This,IDWriteFontFaceReference *ref) { + return This->lpVtbl->AddFontFaceReference(This,ref); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder_AddFontSet(IDWriteFontSetBuilder* This,IDWriteFontSet *fontset) { + return This->lpVtbl->AddFontSet(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder_CreateFontSet(IDWriteFontSetBuilder* This,IDWriteFontSet **fontset) { + return This->lpVtbl->CreateFontSet(This,fontset); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontSetBuilder_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontSetBuilder1 interface + */ +#ifndef __IDWriteFontSetBuilder1_INTERFACE_DEFINED__ +#define __IDWriteFontSetBuilder1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontSetBuilder1, 0x3ff7715f, 0x3cdc, 0x4dc6, 0x9b,0x72, 0xec,0x56,0x21,0xdc,0xca,0xfd); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("3ff7715f-3cdc-4dc6-9b72-ec5621dccafd") +IDWriteFontSetBuilder1 : public IDWriteFontSetBuilder +{ + virtual HRESULT STDMETHODCALLTYPE AddFontFile( + IDWriteFontFile *file) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontSetBuilder1, 0x3ff7715f, 0x3cdc, 0x4dc6, 0x9b,0x72, 0xec,0x56,0x21,0xdc,0xca,0xfd) +#endif +#else +typedef struct IDWriteFontSetBuilder1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontSetBuilder1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontSetBuilder1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontSetBuilder1 *This); + + /*** IDWriteFontSetBuilder methods ***/ + HRESULT (STDMETHODCALLTYPE *AddFontFaceReference_)( + IDWriteFontSetBuilder1 *This, + IDWriteFontFaceReference *ref, + const DWRITE_FONT_PROPERTY *props, + UINT32 prop_count); + + HRESULT (STDMETHODCALLTYPE *AddFontFaceReference)( + IDWriteFontSetBuilder1 *This, + IDWriteFontFaceReference *ref); + + HRESULT (STDMETHODCALLTYPE *AddFontSet)( + IDWriteFontSetBuilder1 *This, + IDWriteFontSet *fontset); + + HRESULT (STDMETHODCALLTYPE *CreateFontSet)( + IDWriteFontSetBuilder1 *This, + IDWriteFontSet **fontset); + + /*** IDWriteFontSetBuilder1 methods ***/ + HRESULT (STDMETHODCALLTYPE *AddFontFile)( + IDWriteFontSetBuilder1 *This, + IDWriteFontFile *file); + + END_INTERFACE +} IDWriteFontSetBuilder1Vtbl; + +interface IDWriteFontSetBuilder1 { + CONST_VTBL IDWriteFontSetBuilder1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontSetBuilder1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontSetBuilder1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontSetBuilder1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontSetBuilder methods ***/ +#define IDWriteFontSetBuilder1_AddFontFaceReference_(This,ref,props,prop_count) (This)->lpVtbl->AddFontFaceReference_(This,ref,props,prop_count) +#define IDWriteFontSetBuilder1_AddFontFaceReference(This,ref) (This)->lpVtbl->AddFontFaceReference(This,ref) +#define IDWriteFontSetBuilder1_AddFontSet(This,fontset) (This)->lpVtbl->AddFontSet(This,fontset) +#define IDWriteFontSetBuilder1_CreateFontSet(This,fontset) (This)->lpVtbl->CreateFontSet(This,fontset) +/*** IDWriteFontSetBuilder1 methods ***/ +#define IDWriteFontSetBuilder1_AddFontFile(This,file) (This)->lpVtbl->AddFontFile(This,file) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontSetBuilder1_QueryInterface(IDWriteFontSetBuilder1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontSetBuilder1_AddRef(IDWriteFontSetBuilder1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontSetBuilder1_Release(IDWriteFontSetBuilder1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontSetBuilder methods ***/ +static FORCEINLINE HRESULT IDWriteFontSetBuilder1_AddFontFaceReference_(IDWriteFontSetBuilder1* This,IDWriteFontFaceReference *ref,const DWRITE_FONT_PROPERTY *props,UINT32 prop_count) { + return This->lpVtbl->AddFontFaceReference_(This,ref,props,prop_count); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder1_AddFontFaceReference(IDWriteFontSetBuilder1* This,IDWriteFontFaceReference *ref) { + return This->lpVtbl->AddFontFaceReference(This,ref); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder1_AddFontSet(IDWriteFontSetBuilder1* This,IDWriteFontSet *fontset) { + return This->lpVtbl->AddFontSet(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder1_CreateFontSet(IDWriteFontSetBuilder1* This,IDWriteFontSet **fontset) { + return This->lpVtbl->CreateFontSet(This,fontset); +} +/*** IDWriteFontSetBuilder1 methods ***/ +static FORCEINLINE HRESULT IDWriteFontSetBuilder1_AddFontFile(IDWriteFontSetBuilder1* This,IDWriteFontFile *file) { + return This->lpVtbl->AddFontFile(This,file); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontSetBuilder1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontSetBuilder2 interface + */ +#ifndef __IDWriteFontSetBuilder2_INTERFACE_DEFINED__ +#define __IDWriteFontSetBuilder2_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontSetBuilder2, 0xee5ba612, 0xb131, 0x463c, 0x8f,0x4f, 0x31,0x89,0xb9,0x40,0x1e,0x45); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("ee5ba612-b131-463c-8f4f-3189b9401e45") +IDWriteFontSetBuilder2 : public IDWriteFontSetBuilder1 +{ + virtual HRESULT STDMETHODCALLTYPE AddFont( + IDWriteFontFile *fontfile, + UINT32 face_index, + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + const DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties) = 0; + + virtual HRESULT STDMETHODCALLTYPE AddFontFile( + const WCHAR *filepath) = 0; + + using IDWriteFontSetBuilder1::AddFontFile; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontSetBuilder2, 0xee5ba612, 0xb131, 0x463c, 0x8f,0x4f, 0x31,0x89,0xb9,0x40,0x1e,0x45) +#endif +#else +typedef struct IDWriteFontSetBuilder2Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontSetBuilder2 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontSetBuilder2 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontSetBuilder2 *This); + + /*** IDWriteFontSetBuilder methods ***/ + HRESULT (STDMETHODCALLTYPE *AddFontFaceReference_)( + IDWriteFontSetBuilder2 *This, + IDWriteFontFaceReference *ref, + const DWRITE_FONT_PROPERTY *props, + UINT32 prop_count); + + HRESULT (STDMETHODCALLTYPE *AddFontFaceReference)( + IDWriteFontSetBuilder2 *This, + IDWriteFontFaceReference *ref); + + HRESULT (STDMETHODCALLTYPE *AddFontSet)( + IDWriteFontSetBuilder2 *This, + IDWriteFontSet *fontset); + + HRESULT (STDMETHODCALLTYPE *CreateFontSet)( + IDWriteFontSetBuilder2 *This, + IDWriteFontSet **fontset); + + /*** IDWriteFontSetBuilder1 methods ***/ + HRESULT (STDMETHODCALLTYPE *AddFontFile)( + IDWriteFontSetBuilder2 *This, + IDWriteFontFile *file); + + /*** IDWriteFontSetBuilder2 methods ***/ + HRESULT (STDMETHODCALLTYPE *AddFont)( + IDWriteFontSetBuilder2 *This, + IDWriteFontFile *fontfile, + UINT32 face_index, + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_values, + const DWRITE_FONT_AXIS_RANGE *axis_ranges, + UINT32 num_ranges, + const DWRITE_FONT_PROPERTY *props, + UINT32 num_properties); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontSetBuilder2_AddFontFile)( + IDWriteFontSetBuilder2 *This, + const WCHAR *filepath); + + END_INTERFACE +} IDWriteFontSetBuilder2Vtbl; + +interface IDWriteFontSetBuilder2 { + CONST_VTBL IDWriteFontSetBuilder2Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontSetBuilder2_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontSetBuilder2_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontSetBuilder2_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontSetBuilder methods ***/ +#define IDWriteFontSetBuilder2_AddFontFaceReference_(This,ref,props,prop_count) (This)->lpVtbl->AddFontFaceReference_(This,ref,props,prop_count) +#define IDWriteFontSetBuilder2_AddFontFaceReference(This,ref) (This)->lpVtbl->AddFontFaceReference(This,ref) +#define IDWriteFontSetBuilder2_AddFontSet(This,fontset) (This)->lpVtbl->AddFontSet(This,fontset) +#define IDWriteFontSetBuilder2_CreateFontSet(This,fontset) (This)->lpVtbl->CreateFontSet(This,fontset) +/*** IDWriteFontSetBuilder1 methods ***/ +/*** IDWriteFontSetBuilder2 methods ***/ +#define IDWriteFontSetBuilder2_AddFont(This,fontfile,face_index,simulations,axis_values,num_values,axis_ranges,num_ranges,props,num_properties) (This)->lpVtbl->AddFont(This,fontfile,face_index,simulations,axis_values,num_values,axis_ranges,num_ranges,props,num_properties) +#define IDWriteFontSetBuilder2_AddFontFile(This,filepath) (This)->lpVtbl->IDWriteFontSetBuilder2_AddFontFile(This,filepath) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontSetBuilder2_QueryInterface(IDWriteFontSetBuilder2* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontSetBuilder2_AddRef(IDWriteFontSetBuilder2* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontSetBuilder2_Release(IDWriteFontSetBuilder2* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontSetBuilder methods ***/ +static FORCEINLINE HRESULT IDWriteFontSetBuilder2_AddFontFaceReference_(IDWriteFontSetBuilder2* This,IDWriteFontFaceReference *ref,const DWRITE_FONT_PROPERTY *props,UINT32 prop_count) { + return This->lpVtbl->AddFontFaceReference_(This,ref,props,prop_count); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder2_AddFontFaceReference(IDWriteFontSetBuilder2* This,IDWriteFontFaceReference *ref) { + return This->lpVtbl->AddFontFaceReference(This,ref); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder2_AddFontSet(IDWriteFontSetBuilder2* This,IDWriteFontSet *fontset) { + return This->lpVtbl->AddFontSet(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder2_CreateFontSet(IDWriteFontSetBuilder2* This,IDWriteFontSet **fontset) { + return This->lpVtbl->CreateFontSet(This,fontset); +} +/*** IDWriteFontSetBuilder1 methods ***/ +/*** IDWriteFontSetBuilder2 methods ***/ +static FORCEINLINE HRESULT IDWriteFontSetBuilder2_AddFont(IDWriteFontSetBuilder2* This,IDWriteFontFile *fontfile,UINT32 face_index,DWRITE_FONT_SIMULATIONS simulations,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_values,const DWRITE_FONT_AXIS_RANGE *axis_ranges,UINT32 num_ranges,const DWRITE_FONT_PROPERTY *props,UINT32 num_properties) { + return This->lpVtbl->AddFont(This,fontfile,face_index,simulations,axis_values,num_values,axis_ranges,num_ranges,props,num_properties); +} +static FORCEINLINE HRESULT IDWriteFontSetBuilder2_AddFontFile(IDWriteFontSetBuilder2* This,const WCHAR *filepath) { + return This->lpVtbl->IDWriteFontSetBuilder2_AddFontFile(This,filepath); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontSetBuilder2_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFactory3 interface + */ +#ifndef __IDWriteFactory3_INTERFACE_DEFINED__ +#define __IDWriteFactory3_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFactory3, 0x9a1b41c3, 0xd3bb, 0x466a, 0x87,0xfc, 0xfe,0x67,0x55,0x6a,0x3b,0x65); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("9a1b41c3-d3bb-466a-87fc-fe67556a3b65") +IDWriteFactory3 : public IDWriteFactory2 +{ + virtual HRESULT STDMETHODCALLTYPE CreateGlyphRunAnalysis( + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + DWRITE_TEXT_ANTIALIAS_MODE antialias_mode, + FLOAT origin_x, + FLOAT origin_y, + IDWriteGlyphRunAnalysis **analysis) = 0; + + using IDWriteFactory::CreateGlyphRunAnalysis; + using IDWriteFactory2::CreateGlyphRunAnalysis; + + virtual HRESULT STDMETHODCALLTYPE CreateCustomRenderingParams( + FLOAT gamma, + FLOAT enhanced_contrast, + FLOAT grayscale_enhanced_contrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY pixel_geometry, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + IDWriteRenderingParams3 **params) = 0; + + using IDWriteFactory::CreateCustomRenderingParams; + using IDWriteFactory1::CreateCustomRenderingParams; + using IDWriteFactory2::CreateCustomRenderingParams; + + virtual HRESULT STDMETHODCALLTYPE CreateFontFaceReference( + IDWriteFontFile *file, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontFaceReference( + const WCHAR *path, + const FILETIME *writetime, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSystemFontSet( + IDWriteFontSet **fontset) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontSetBuilder( + IDWriteFontSetBuilder **builder) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontCollectionFromFontSet( + IDWriteFontSet *fontset, + IDWriteFontCollection1 **collection) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSystemFontCollection( + WINBOOL include_downloadable, + IDWriteFontCollection1 **collection, + WINBOOL check_for_updates) = 0; + + using IDWriteFactory::GetSystemFontCollection; + + virtual HRESULT STDMETHODCALLTYPE GetFontDownloadQueue( + IDWriteFontDownloadQueue **queue) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFactory3, 0x9a1b41c3, 0xd3bb, 0x466a, 0x87,0xfc, 0xfe,0x67,0x55,0x6a,0x3b,0x65) +#endif +#else +typedef struct IDWriteFactory3Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFactory3 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFactory3 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFactory3 *This); + + /*** IDWriteFactory methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontCollection)( + IDWriteFactory3 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontCollection)( + IDWriteFactory3 *This, + IDWriteFontCollectionLoader *loader, + const void *key, + UINT32 key_size, + IDWriteFontCollection **collection); + + HRESULT (STDMETHODCALLTYPE *RegisterFontCollectionLoader)( + IDWriteFactory3 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontCollectionLoader)( + IDWriteFactory3 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateFontFileReference)( + IDWriteFactory3 *This, + const WCHAR *path, + const FILETIME *writetime, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontFileReference)( + IDWriteFactory3 *This, + const void *reference_key, + UINT32 key_size, + IDWriteFontFileLoader *loader, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFactory3 *This, + DWRITE_FONT_FACE_TYPE facetype, + UINT32 files_number, + IDWriteFontFile *const *font_files, + UINT32 index, + DWRITE_FONT_SIMULATIONS sim_flags, + IDWriteFontFace **font_face); + + HRESULT (STDMETHODCALLTYPE *CreateRenderingParams)( + IDWriteFactory3 *This, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateMonitorRenderingParams)( + IDWriteFactory3 *This, + HMONITOR monitor, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateCustomRenderingParams)( + IDWriteFactory3 *This, + FLOAT gamma, + FLOAT enhancedContrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *RegisterFontFileLoader)( + IDWriteFactory3 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontFileLoader)( + IDWriteFactory3 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateTextFormat)( + IDWriteFactory3 *This, + const WCHAR *family_name, + IDWriteFontCollection *collection, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STYLE style, + DWRITE_FONT_STRETCH stretch, + FLOAT size, + const WCHAR *locale, + IDWriteTextFormat **format); + + HRESULT (STDMETHODCALLTYPE *CreateTypography)( + IDWriteFactory3 *This, + IDWriteTypography **typography); + + HRESULT (STDMETHODCALLTYPE *GetGdiInterop)( + IDWriteFactory3 *This, + IDWriteGdiInterop **gdi_interop); + + HRESULT (STDMETHODCALLTYPE *CreateTextLayout)( + IDWriteFactory3 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT max_width, + FLOAT max_height, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateGdiCompatibleTextLayout)( + IDWriteFactory3 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT layout_width, + FLOAT layout_height, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateEllipsisTrimmingSign)( + IDWriteFactory3 *This, + IDWriteTextFormat *format, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *CreateTextAnalyzer)( + IDWriteFactory3 *This, + IDWriteTextAnalyzer **analyzer); + + HRESULT (STDMETHODCALLTYPE *CreateNumberSubstitution)( + IDWriteFactory3 *This, + DWRITE_NUMBER_SUBSTITUTION_METHOD method, + const WCHAR *locale, + WINBOOL ignore_user_override, + IDWriteNumberSubstitution **substitution); + + HRESULT (STDMETHODCALLTYPE *CreateGlyphRunAnalysis)( + IDWriteFactory3 *This, + const DWRITE_GLYPH_RUN *glyph_run, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + FLOAT baseline_x, + FLOAT baseline_y, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory1 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetEudcFontCollection)( + IDWriteFactory3 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory1_CreateCustomRenderingParams)( + IDWriteFactory3 *This, + FLOAT gamma, + FLOAT enhcontrast, + FLOAT enhcontrast_grayscale, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams1 **params); + + /*** IDWriteFactory2 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontFallback)( + IDWriteFactory3 *This, + IDWriteFontFallback **fallback); + + HRESULT (STDMETHODCALLTYPE *CreateFontFallbackBuilder)( + IDWriteFactory3 *This, + IDWriteFontFallbackBuilder **fallbackbuilder); + + HRESULT (STDMETHODCALLTYPE *TranslateColorGlyphRun)( + IDWriteFactory3 *This, + FLOAT originX, + FLOAT originY, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, + DWRITE_MEASURING_MODE mode, + const DWRITE_MATRIX *transform, + UINT32 palette_index, + IDWriteColorGlyphRunEnumerator **colorlayers); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateCustomRenderingParams)( + IDWriteFactory3 *This, + FLOAT gamma, + FLOAT contrast, + FLOAT grayscalecontrast, + FLOAT cleartypeLevel, + DWRITE_PIXEL_GEOMETRY pixelGeometry, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_GRID_FIT_MODE gridFitMode, + IDWriteRenderingParams2 **params); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateGlyphRunAnalysis)( + IDWriteFactory3 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GRID_FIT_MODE gridFitMode, + DWRITE_TEXT_ANTIALIAS_MODE antialiasMode, + FLOAT originX, + FLOAT originY, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory3 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateGlyphRunAnalysis)( + IDWriteFactory3 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + DWRITE_TEXT_ANTIALIAS_MODE antialias_mode, + FLOAT origin_x, + FLOAT origin_y, + IDWriteGlyphRunAnalysis **analysis); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateCustomRenderingParams)( + IDWriteFactory3 *This, + FLOAT gamma, + FLOAT enhanced_contrast, + FLOAT grayscale_enhanced_contrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY pixel_geometry, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + IDWriteRenderingParams3 **params); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference_)( + IDWriteFactory3 *This, + IDWriteFontFile *file, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference)( + IDWriteFactory3 *This, + const WCHAR *path, + const FILETIME *writetime, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *GetSystemFontSet)( + IDWriteFactory3 *This, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *CreateFontSetBuilder)( + IDWriteFactory3 *This, + IDWriteFontSetBuilder **builder); + + HRESULT (STDMETHODCALLTYPE *CreateFontCollectionFromFontSet)( + IDWriteFactory3 *This, + IDWriteFontSet *fontset, + IDWriteFontCollection1 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_GetSystemFontCollection)( + IDWriteFactory3 *This, + WINBOOL include_downloadable, + IDWriteFontCollection1 **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *GetFontDownloadQueue)( + IDWriteFactory3 *This, + IDWriteFontDownloadQueue **queue); + + END_INTERFACE +} IDWriteFactory3Vtbl; + +interface IDWriteFactory3 { + CONST_VTBL IDWriteFactory3Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFactory3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFactory3_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFactory3_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFactory methods ***/ +#define IDWriteFactory3_CreateCustomFontCollection(This,loader,key,key_size,collection) (This)->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection) +#define IDWriteFactory3_RegisterFontCollectionLoader(This,loader) (This)->lpVtbl->RegisterFontCollectionLoader(This,loader) +#define IDWriteFactory3_UnregisterFontCollectionLoader(This,loader) (This)->lpVtbl->UnregisterFontCollectionLoader(This,loader) +#define IDWriteFactory3_CreateFontFileReference(This,path,writetime,font_file) (This)->lpVtbl->CreateFontFileReference(This,path,writetime,font_file) +#define IDWriteFactory3_CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) (This)->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) +#define IDWriteFactory3_CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) (This)->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) +#define IDWriteFactory3_CreateRenderingParams(This,params) (This)->lpVtbl->CreateRenderingParams(This,params) +#define IDWriteFactory3_CreateMonitorRenderingParams(This,monitor,params) (This)->lpVtbl->CreateMonitorRenderingParams(This,monitor,params) +#define IDWriteFactory3_RegisterFontFileLoader(This,loader) (This)->lpVtbl->RegisterFontFileLoader(This,loader) +#define IDWriteFactory3_UnregisterFontFileLoader(This,loader) (This)->lpVtbl->UnregisterFontFileLoader(This,loader) +#define IDWriteFactory3_CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format) (This)->lpVtbl->CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format) +#define IDWriteFactory3_CreateTypography(This,typography) (This)->lpVtbl->CreateTypography(This,typography) +#define IDWriteFactory3_GetGdiInterop(This,gdi_interop) (This)->lpVtbl->GetGdiInterop(This,gdi_interop) +#define IDWriteFactory3_CreateTextLayout(This,string,len,format,max_width,max_height,layout) (This)->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout) +#define IDWriteFactory3_CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) (This)->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) +#define IDWriteFactory3_CreateEllipsisTrimmingSign(This,format,trimming_sign) (This)->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign) +#define IDWriteFactory3_CreateTextAnalyzer(This,analyzer) (This)->lpVtbl->CreateTextAnalyzer(This,analyzer) +#define IDWriteFactory3_CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) (This)->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) +/*** IDWriteFactory1 methods ***/ +#define IDWriteFactory3_GetEudcFontCollection(This,collection,check_for_updates) (This)->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates) +/*** IDWriteFactory2 methods ***/ +#define IDWriteFactory3_GetSystemFontFallback(This,fallback) (This)->lpVtbl->GetSystemFontFallback(This,fallback) +#define IDWriteFactory3_CreateFontFallbackBuilder(This,fallbackbuilder) (This)->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder) +#define IDWriteFactory3_TranslateColorGlyphRun(This,originX,originY,run,rundescr,mode,transform,palette_index,colorlayers) (This)->lpVtbl->TranslateColorGlyphRun(This,originX,originY,run,rundescr,mode,transform,palette_index,colorlayers) +/*** IDWriteFactory3 methods ***/ +#define IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) (This)->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) +#define IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) (This)->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) +#define IDWriteFactory3_CreateFontFaceReference_(This,file,index,simulations,reference) (This)->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference) +#define IDWriteFactory3_CreateFontFaceReference(This,path,writetime,index,simulations,reference) (This)->lpVtbl->CreateFontFaceReference(This,path,writetime,index,simulations,reference) +#define IDWriteFactory3_GetSystemFontSet(This,fontset) (This)->lpVtbl->GetSystemFontSet(This,fontset) +#define IDWriteFactory3_CreateFontSetBuilder(This,builder) (This)->lpVtbl->CreateFontSetBuilder(This,builder) +#define IDWriteFactory3_CreateFontCollectionFromFontSet(This,fontset,collection) (This)->lpVtbl->CreateFontCollectionFromFontSet(This,fontset,collection) +#define IDWriteFactory3_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates) (This)->lpVtbl->IDWriteFactory3_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates) +#define IDWriteFactory3_GetFontDownloadQueue(This,queue) (This)->lpVtbl->GetFontDownloadQueue(This,queue) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFactory3_QueryInterface(IDWriteFactory3* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFactory3_AddRef(IDWriteFactory3* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFactory3_Release(IDWriteFactory3* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFactory methods ***/ +static FORCEINLINE HRESULT IDWriteFactory3_CreateCustomFontCollection(IDWriteFactory3* This,IDWriteFontCollectionLoader *loader,const void *key,UINT32 key_size,IDWriteFontCollection **collection) { + return This->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection); +} +static FORCEINLINE HRESULT IDWriteFactory3_RegisterFontCollectionLoader(IDWriteFactory3* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->RegisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory3_UnregisterFontCollectionLoader(IDWriteFactory3* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->UnregisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateFontFileReference(IDWriteFactory3* This,const WCHAR *path,const FILETIME *writetime,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateFontFileReference(This,path,writetime,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateCustomFontFileReference(IDWriteFactory3* This,const void *reference_key,UINT32 key_size,IDWriteFontFileLoader *loader,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateFontFace(IDWriteFactory3* This,DWRITE_FONT_FACE_TYPE facetype,UINT32 files_number,IDWriteFontFile *const *font_files,UINT32 index,DWRITE_FONT_SIMULATIONS sim_flags,IDWriteFontFace **font_face) { + return This->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateRenderingParams(IDWriteFactory3* This,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateRenderingParams(This,params); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateMonitorRenderingParams(IDWriteFactory3* This,HMONITOR monitor,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateMonitorRenderingParams(This,monitor,params); +} +static FORCEINLINE HRESULT IDWriteFactory3_RegisterFontFileLoader(IDWriteFactory3* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->RegisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory3_UnregisterFontFileLoader(IDWriteFactory3* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->UnregisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateTextFormat(IDWriteFactory3* This,const WCHAR *family_name,IDWriteFontCollection *collection,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STYLE style,DWRITE_FONT_STRETCH stretch,FLOAT size,const WCHAR *locale,IDWriteTextFormat **format) { + return This->lpVtbl->CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateTypography(IDWriteFactory3* This,IDWriteTypography **typography) { + return This->lpVtbl->CreateTypography(This,typography); +} +static FORCEINLINE HRESULT IDWriteFactory3_GetGdiInterop(IDWriteFactory3* This,IDWriteGdiInterop **gdi_interop) { + return This->lpVtbl->GetGdiInterop(This,gdi_interop); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateTextLayout(IDWriteFactory3* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT max_width,FLOAT max_height,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateGdiCompatibleTextLayout(IDWriteFactory3* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT layout_width,FLOAT layout_height,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateEllipsisTrimmingSign(IDWriteFactory3* This,IDWriteTextFormat *format,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateTextAnalyzer(IDWriteFactory3* This,IDWriteTextAnalyzer **analyzer) { + return This->lpVtbl->CreateTextAnalyzer(This,analyzer); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateNumberSubstitution(IDWriteFactory3* This,DWRITE_NUMBER_SUBSTITUTION_METHOD method,const WCHAR *locale,WINBOOL ignore_user_override,IDWriteNumberSubstitution **substitution) { + return This->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution); +} +/*** IDWriteFactory1 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory3_GetEudcFontCollection(IDWriteFactory3* This,IDWriteFontCollection **collection,WINBOOL check_for_updates) { + return This->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates); +} +/*** IDWriteFactory2 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory3_GetSystemFontFallback(IDWriteFactory3* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetSystemFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateFontFallbackBuilder(IDWriteFactory3* This,IDWriteFontFallbackBuilder **fallbackbuilder) { + return This->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder); +} +static FORCEINLINE HRESULT IDWriteFactory3_TranslateColorGlyphRun(IDWriteFactory3* This,FLOAT originX,FLOAT originY,const DWRITE_GLYPH_RUN *run,const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,DWRITE_MEASURING_MODE mode,const DWRITE_MATRIX *transform,UINT32 palette_index,IDWriteColorGlyphRunEnumerator **colorlayers) { + return This->lpVtbl->TranslateColorGlyphRun(This,originX,originY,run,rundescr,mode,transform,palette_index,colorlayers); +} +/*** IDWriteFactory3 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory3_CreateGlyphRunAnalysis(IDWriteFactory3* This,const DWRITE_GLYPH_RUN *run,const DWRITE_MATRIX *transform,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_MEASURING_MODE measuring_mode,DWRITE_GRID_FIT_MODE gridfit_mode,DWRITE_TEXT_ANTIALIAS_MODE antialias_mode,FLOAT origin_x,FLOAT origin_y,IDWriteGlyphRunAnalysis **analysis) { + return This->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateCustomRenderingParams(IDWriteFactory3* This,FLOAT gamma,FLOAT enhanced_contrast,FLOAT grayscale_enhanced_contrast,FLOAT cleartype_level,DWRITE_PIXEL_GEOMETRY pixel_geometry,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_GRID_FIT_MODE gridfit_mode,IDWriteRenderingParams3 **params) { + return This->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateFontFaceReference_(IDWriteFactory3* This,IDWriteFontFile *file,UINT32 index,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFaceReference **reference) { + return This->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateFontFaceReference(IDWriteFactory3* This,const WCHAR *path,const FILETIME *writetime,UINT32 index,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFaceReference **reference) { + return This->lpVtbl->CreateFontFaceReference(This,path,writetime,index,simulations,reference); +} +static FORCEINLINE HRESULT IDWriteFactory3_GetSystemFontSet(IDWriteFactory3* This,IDWriteFontSet **fontset) { + return This->lpVtbl->GetSystemFontSet(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateFontSetBuilder(IDWriteFactory3* This,IDWriteFontSetBuilder **builder) { + return This->lpVtbl->CreateFontSetBuilder(This,builder); +} +static FORCEINLINE HRESULT IDWriteFactory3_CreateFontCollectionFromFontSet(IDWriteFactory3* This,IDWriteFontSet *fontset,IDWriteFontCollection1 **collection) { + return This->lpVtbl->CreateFontCollectionFromFontSet(This,fontset,collection); +} +static FORCEINLINE HRESULT IDWriteFactory3_GetSystemFontCollection(IDWriteFactory3* This,WINBOOL include_downloadable,IDWriteFontCollection1 **collection,WINBOOL check_for_updates) { + return This->lpVtbl->IDWriteFactory3_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates); +} +static FORCEINLINE HRESULT IDWriteFactory3_GetFontDownloadQueue(IDWriteFactory3* This,IDWriteFontDownloadQueue **queue) { + return This->lpVtbl->GetFontDownloadQueue(This,queue); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFactory3_INTERFACE_DEFINED__ */ + +typedef struct DWRITE_GLYPH_IMAGE_DATA { + const void *imageData; + UINT32 imageDataSize; + UINT32 uniqueDataId; + UINT32 pixelsPerEm; + D2D1_SIZE_U pixelSize; + D2D1_POINT_2L horizontalLeftOrigin; + D2D1_POINT_2L horizontalRightOrigin; + D2D1_POINT_2L verticalTopOrigin; + D2D1_POINT_2L verticalBottomOrigin; +} DWRITE_GLYPH_IMAGE_DATA; +/***************************************************************************** + * IDWriteFontFace4 interface + */ +#ifndef __IDWriteFontFace4_INTERFACE_DEFINED__ +#define __IDWriteFontFace4_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontFace4, 0x27f2a904, 0x4eb8, 0x441d, 0x96,0x78, 0x05,0x63,0xf5,0x3e,0x3e,0x2f); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("27f2a904-4eb8-441d-9678-0563f53e3e2f") +IDWriteFontFace4 : public IDWriteFontFace3 +{ + virtual HRESULT STDMETHODCALLTYPE GetGlyphImageFormats( + UINT16 glyph, + UINT32 ppem_first, + UINT32 ppem_last, + DWRITE_GLYPH_IMAGE_FORMATS *formats) = 0; + + virtual DWRITE_GLYPH_IMAGE_FORMATS STDMETHODCALLTYPE GetGlyphImageFormats( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetGlyphImageData( + UINT16 glyph, + UINT32 ppem, + DWRITE_GLYPH_IMAGE_FORMATS format, + DWRITE_GLYPH_IMAGE_DATA *data, + void **context) = 0; + + virtual void STDMETHODCALLTYPE ReleaseGlyphImageData( + void *context) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontFace4, 0x27f2a904, 0x4eb8, 0x441d, 0x96,0x78, 0x05,0x63,0xf5,0x3e,0x3e,0x2f) +#endif +#else +typedef struct IDWriteFontFace4Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontFace4 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontFace4 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontFace4 *This); + + /*** IDWriteFontFace methods ***/ + DWRITE_FONT_FACE_TYPE (STDMETHODCALLTYPE *GetType)( + IDWriteFontFace4 *This); + + HRESULT (STDMETHODCALLTYPE *GetFiles)( + IDWriteFontFace4 *This, + UINT32 *number_of_files, + IDWriteFontFile **fontfiles); + + UINT32 (STDMETHODCALLTYPE *GetIndex)( + IDWriteFontFace4 *This); + + DWRITE_FONT_SIMULATIONS (STDMETHODCALLTYPE *GetSimulations)( + IDWriteFontFace4 *This); + + WINBOOL (STDMETHODCALLTYPE *IsSymbolFont)( + IDWriteFontFace4 *This); + + void (STDMETHODCALLTYPE *GetMetrics)( + IDWriteFontFace4 *This, + DWRITE_FONT_METRICS *metrics); + + UINT16 (STDMETHODCALLTYPE *GetGlyphCount)( + IDWriteFontFace4 *This); + + HRESULT (STDMETHODCALLTYPE *GetDesignGlyphMetrics)( + IDWriteFontFace4 *This, + const UINT16 *glyph_indices, + UINT32 glyph_count, + DWRITE_GLYPH_METRICS *metrics, + WINBOOL is_sideways); + + HRESULT (STDMETHODCALLTYPE *GetGlyphIndices)( + IDWriteFontFace4 *This, + const UINT32 *codepoints, + UINT32 count, + UINT16 *glyph_indices); + + HRESULT (STDMETHODCALLTYPE *TryGetFontTable)( + IDWriteFontFace4 *This, + UINT32 table_tag, + const void **table_data, + UINT32 *table_size, + void **context, + WINBOOL *exists); + + void (STDMETHODCALLTYPE *ReleaseFontTable)( + IDWriteFontFace4 *This, + void *table_context); + + HRESULT (STDMETHODCALLTYPE *GetGlyphRunOutline)( + IDWriteFontFace4 *This, + FLOAT emSize, + const UINT16 *glyph_indices, + const FLOAT *glyph_advances, + const DWRITE_GLYPH_OFFSET *glyph_offsets, + UINT32 glyph_count, + WINBOOL is_sideways, + WINBOOL is_rtl, + IDWriteGeometrySink *geometrysink); + + HRESULT (STDMETHODCALLTYPE *GetRecommendedRenderingMode)( + IDWriteFontFace4 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + DWRITE_MEASURING_MODE mode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE *rendering_mode); + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleMetrics)( + IDWriteFontFace4 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_FONT_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleGlyphMetrics)( + IDWriteFontFace4 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + const UINT16 *glyph_indices, + UINT32 glyph_count, + DWRITE_GLYPH_METRICS *metrics, + WINBOOL is_sideways); + + /*** IDWriteFontFace1 methods ***/ + void (STDMETHODCALLTYPE *IDWriteFontFace1_GetMetrics)( + IDWriteFontFace4 *This, + DWRITE_FONT_METRICS1 *metrics); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace1_GetGdiCompatibleMetrics)( + IDWriteFontFace4 *This, + FLOAT em_size, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_FONT_METRICS1 *metrics); + + void (STDMETHODCALLTYPE *GetCaretMetrics)( + IDWriteFontFace4 *This, + DWRITE_CARET_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *GetUnicodeRanges)( + IDWriteFontFace4 *This, + UINT32 max_count, + DWRITE_UNICODE_RANGE *ranges, + UINT32 *count); + + WINBOOL (STDMETHODCALLTYPE *IsMonospacedFont)( + IDWriteFontFace4 *This); + + HRESULT (STDMETHODCALLTYPE *GetDesignGlyphAdvances)( + IDWriteFontFace4 *This, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *advances, + WINBOOL is_sideways); + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleGlyphAdvances)( + IDWriteFontFace4 *This, + FLOAT em_size, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + WINBOOL is_sideways, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *advances); + + HRESULT (STDMETHODCALLTYPE *GetKerningPairAdjustments)( + IDWriteFontFace4 *This, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *adjustments); + + WINBOOL (STDMETHODCALLTYPE *HasKerningPairs)( + IDWriteFontFace4 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace1_GetRecommendedRenderingMode)( + IDWriteFontFace4 *This, + FLOAT font_emsize, + FLOAT dpiX, + FLOAT dpiY, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_RENDERING_MODE *rendering_mode); + + HRESULT (STDMETHODCALLTYPE *GetVerticalGlyphVariants)( + IDWriteFontFace4 *This, + UINT32 glyph_count, + const UINT16 *nominal_indices, + UINT16 *vertical_indices); + + WINBOOL (STDMETHODCALLTYPE *HasVerticalGlyphVariants)( + IDWriteFontFace4 *This); + + /*** IDWriteFontFace2 methods ***/ + WINBOOL (STDMETHODCALLTYPE *IsColorFont)( + IDWriteFontFace4 *This); + + UINT32 (STDMETHODCALLTYPE *GetColorPaletteCount)( + IDWriteFontFace4 *This); + + UINT32 (STDMETHODCALLTYPE *GetPaletteEntryCount)( + IDWriteFontFace4 *This); + + HRESULT (STDMETHODCALLTYPE *GetPaletteEntries)( + IDWriteFontFace4 *This, + UINT32 palette_index, + UINT32 first_entry_index, + UINT32 entry_count, + DWRITE_COLOR_F *entries); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace2_GetRecommendedRenderingMode)( + IDWriteFontFace4 *This, + FLOAT fontEmSize, + FLOAT dpiX, + FLOAT dpiY, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuringmode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE *renderingmode, + DWRITE_GRID_FIT_MODE *gridfitmode); + + /*** IDWriteFontFace3 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontFace4 *This, + IDWriteFontFaceReference **reference); + + void (STDMETHODCALLTYPE *GetPanose)( + IDWriteFontFace4 *This, + DWRITE_PANOSE *panose); + + DWRITE_FONT_WEIGHT (STDMETHODCALLTYPE *GetWeight)( + IDWriteFontFace4 *This); + + DWRITE_FONT_STRETCH (STDMETHODCALLTYPE *GetStretch)( + IDWriteFontFace4 *This); + + DWRITE_FONT_STYLE (STDMETHODCALLTYPE *GetStyle)( + IDWriteFontFace4 *This); + + HRESULT (STDMETHODCALLTYPE *GetFamilyNames)( + IDWriteFontFace4 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetFaceNames)( + IDWriteFontFace4 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetInformationalStrings)( + IDWriteFontFace4 *This, + DWRITE_INFORMATIONAL_STRING_ID stringid, + IDWriteLocalizedStrings **strings, + WINBOOL *exists); + + WINBOOL (STDMETHODCALLTYPE *HasCharacter)( + IDWriteFontFace4 *This, + UINT32 character); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace3_GetRecommendedRenderingMode)( + IDWriteFontFace4 *This, + FLOAT emsize, + FLOAT dpi_x, + FLOAT dpi_y, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuring_mode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE1 *rendering_mode, + DWRITE_GRID_FIT_MODE *gridfit_mode); + + WINBOOL (STDMETHODCALLTYPE *IsCharacterLocal)( + IDWriteFontFace4 *This, + UINT32 character); + + WINBOOL (STDMETHODCALLTYPE *IsGlyphLocal)( + IDWriteFontFace4 *This, + UINT16 glyph); + + HRESULT (STDMETHODCALLTYPE *AreCharactersLocal)( + IDWriteFontFace4 *This, + const WCHAR *characters, + UINT32 count, + WINBOOL enqueue_if_not, + WINBOOL *are_local); + + HRESULT (STDMETHODCALLTYPE *AreGlyphsLocal)( + IDWriteFontFace4 *This, + const UINT16 *glyphs, + UINT32 count, + WINBOOL enqueue_if_not, + WINBOOL *are_local); + + /*** IDWriteFontFace4 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetGlyphImageFormats_)( + IDWriteFontFace4 *This, + UINT16 glyph, + UINT32 ppem_first, + UINT32 ppem_last, + DWRITE_GLYPH_IMAGE_FORMATS *formats); + + DWRITE_GLYPH_IMAGE_FORMATS (STDMETHODCALLTYPE *GetGlyphImageFormats)( + IDWriteFontFace4 *This); + + HRESULT (STDMETHODCALLTYPE *GetGlyphImageData)( + IDWriteFontFace4 *This, + UINT16 glyph, + UINT32 ppem, + DWRITE_GLYPH_IMAGE_FORMATS format, + DWRITE_GLYPH_IMAGE_DATA *data, + void **context); + + void (STDMETHODCALLTYPE *ReleaseGlyphImageData)( + IDWriteFontFace4 *This, + void *context); + + END_INTERFACE +} IDWriteFontFace4Vtbl; + +interface IDWriteFontFace4 { + CONST_VTBL IDWriteFontFace4Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontFace4_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFace4_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFace4_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFace methods ***/ +#define IDWriteFontFace4_GetType(This) (This)->lpVtbl->GetType(This) +#define IDWriteFontFace4_GetFiles(This,number_of_files,fontfiles) (This)->lpVtbl->GetFiles(This,number_of_files,fontfiles) +#define IDWriteFontFace4_GetIndex(This) (This)->lpVtbl->GetIndex(This) +#define IDWriteFontFace4_GetSimulations(This) (This)->lpVtbl->GetSimulations(This) +#define IDWriteFontFace4_IsSymbolFont(This) (This)->lpVtbl->IsSymbolFont(This) +#define IDWriteFontFace4_GetGlyphCount(This) (This)->lpVtbl->GetGlyphCount(This) +#define IDWriteFontFace4_GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways) (This)->lpVtbl->GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways) +#define IDWriteFontFace4_GetGlyphIndices(This,codepoints,count,glyph_indices) (This)->lpVtbl->GetGlyphIndices(This,codepoints,count,glyph_indices) +#define IDWriteFontFace4_TryGetFontTable(This,table_tag,table_data,table_size,context,exists) (This)->lpVtbl->TryGetFontTable(This,table_tag,table_data,table_size,context,exists) +#define IDWriteFontFace4_ReleaseFontTable(This,table_context) (This)->lpVtbl->ReleaseFontTable(This,table_context) +#define IDWriteFontFace4_GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink) (This)->lpVtbl->GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink) +#define IDWriteFontFace4_GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways) (This)->lpVtbl->GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways) +/*** IDWriteFontFace1 methods ***/ +#define IDWriteFontFace4_GetMetrics(This,metrics) (This)->lpVtbl->IDWriteFontFace1_GetMetrics(This,metrics) +#define IDWriteFontFace4_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics) (This)->lpVtbl->IDWriteFontFace1_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics) +#define IDWriteFontFace4_GetCaretMetrics(This,metrics) (This)->lpVtbl->GetCaretMetrics(This,metrics) +#define IDWriteFontFace4_GetUnicodeRanges(This,max_count,ranges,count) (This)->lpVtbl->GetUnicodeRanges(This,max_count,ranges,count) +#define IDWriteFontFace4_IsMonospacedFont(This) (This)->lpVtbl->IsMonospacedFont(This) +#define IDWriteFontFace4_GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways) (This)->lpVtbl->GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways) +#define IDWriteFontFace4_GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances) (This)->lpVtbl->GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances) +#define IDWriteFontFace4_GetKerningPairAdjustments(This,glyph_count,indices,adjustments) (This)->lpVtbl->GetKerningPairAdjustments(This,glyph_count,indices,adjustments) +#define IDWriteFontFace4_HasKerningPairs(This) (This)->lpVtbl->HasKerningPairs(This) +#define IDWriteFontFace4_GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices) (This)->lpVtbl->GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices) +#define IDWriteFontFace4_HasVerticalGlyphVariants(This) (This)->lpVtbl->HasVerticalGlyphVariants(This) +/*** IDWriteFontFace2 methods ***/ +#define IDWriteFontFace4_IsColorFont(This) (This)->lpVtbl->IsColorFont(This) +#define IDWriteFontFace4_GetColorPaletteCount(This) (This)->lpVtbl->GetColorPaletteCount(This) +#define IDWriteFontFace4_GetPaletteEntryCount(This) (This)->lpVtbl->GetPaletteEntryCount(This) +#define IDWriteFontFace4_GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries) (This)->lpVtbl->GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries) +/*** IDWriteFontFace3 methods ***/ +#define IDWriteFontFace4_GetFontFaceReference(This,reference) (This)->lpVtbl->GetFontFaceReference(This,reference) +#define IDWriteFontFace4_GetPanose(This,panose) (This)->lpVtbl->GetPanose(This,panose) +#define IDWriteFontFace4_GetWeight(This) (This)->lpVtbl->GetWeight(This) +#define IDWriteFontFace4_GetStretch(This) (This)->lpVtbl->GetStretch(This) +#define IDWriteFontFace4_GetStyle(This) (This)->lpVtbl->GetStyle(This) +#define IDWriteFontFace4_GetFamilyNames(This,names) (This)->lpVtbl->GetFamilyNames(This,names) +#define IDWriteFontFace4_GetFaceNames(This,names) (This)->lpVtbl->GetFaceNames(This,names) +#define IDWriteFontFace4_GetInformationalStrings(This,stringid,strings,exists) (This)->lpVtbl->GetInformationalStrings(This,stringid,strings,exists) +#define IDWriteFontFace4_HasCharacter(This,character) (This)->lpVtbl->HasCharacter(This,character) +#define IDWriteFontFace4_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode) (This)->lpVtbl->IDWriteFontFace3_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode) +#define IDWriteFontFace4_IsCharacterLocal(This,character) (This)->lpVtbl->IsCharacterLocal(This,character) +#define IDWriteFontFace4_IsGlyphLocal(This,glyph) (This)->lpVtbl->IsGlyphLocal(This,glyph) +#define IDWriteFontFace4_AreCharactersLocal(This,characters,count,enqueue_if_not,are_local) (This)->lpVtbl->AreCharactersLocal(This,characters,count,enqueue_if_not,are_local) +#define IDWriteFontFace4_AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local) (This)->lpVtbl->AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local) +/*** IDWriteFontFace4 methods ***/ +#define IDWriteFontFace4_GetGlyphImageFormats_(This,glyph,ppem_first,ppem_last,formats) (This)->lpVtbl->GetGlyphImageFormats_(This,glyph,ppem_first,ppem_last,formats) +#define IDWriteFontFace4_GetGlyphImageFormats(This) (This)->lpVtbl->GetGlyphImageFormats(This) +#define IDWriteFontFace4_GetGlyphImageData(This,glyph,ppem,format,data,context) (This)->lpVtbl->GetGlyphImageData(This,glyph,ppem,format,data,context) +#define IDWriteFontFace4_ReleaseGlyphImageData(This,context) (This)->lpVtbl->ReleaseGlyphImageData(This,context) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontFace4_QueryInterface(IDWriteFontFace4* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontFace4_AddRef(IDWriteFontFace4* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontFace4_Release(IDWriteFontFace4* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFace methods ***/ +static FORCEINLINE DWRITE_FONT_FACE_TYPE IDWriteFontFace4_GetType(IDWriteFontFace4* This) { + return This->lpVtbl->GetType(This); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetFiles(IDWriteFontFace4* This,UINT32 *number_of_files,IDWriteFontFile **fontfiles) { + return This->lpVtbl->GetFiles(This,number_of_files,fontfiles); +} +static FORCEINLINE UINT32 IDWriteFontFace4_GetIndex(IDWriteFontFace4* This) { + return This->lpVtbl->GetIndex(This); +} +static FORCEINLINE DWRITE_FONT_SIMULATIONS IDWriteFontFace4_GetSimulations(IDWriteFontFace4* This) { + return This->lpVtbl->GetSimulations(This); +} +static FORCEINLINE WINBOOL IDWriteFontFace4_IsSymbolFont(IDWriteFontFace4* This) { + return This->lpVtbl->IsSymbolFont(This); +} +static FORCEINLINE UINT16 IDWriteFontFace4_GetGlyphCount(IDWriteFontFace4* This) { + return This->lpVtbl->GetGlyphCount(This); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetDesignGlyphMetrics(IDWriteFontFace4* This,const UINT16 *glyph_indices,UINT32 glyph_count,DWRITE_GLYPH_METRICS *metrics,WINBOOL is_sideways) { + return This->lpVtbl->GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetGlyphIndices(IDWriteFontFace4* This,const UINT32 *codepoints,UINT32 count,UINT16 *glyph_indices) { + return This->lpVtbl->GetGlyphIndices(This,codepoints,count,glyph_indices); +} +static FORCEINLINE HRESULT IDWriteFontFace4_TryGetFontTable(IDWriteFontFace4* This,UINT32 table_tag,const void **table_data,UINT32 *table_size,void **context,WINBOOL *exists) { + return This->lpVtbl->TryGetFontTable(This,table_tag,table_data,table_size,context,exists); +} +static FORCEINLINE void IDWriteFontFace4_ReleaseFontTable(IDWriteFontFace4* This,void *table_context) { + This->lpVtbl->ReleaseFontTable(This,table_context); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetGlyphRunOutline(IDWriteFontFace4* This,FLOAT emSize,const UINT16 *glyph_indices,const FLOAT *glyph_advances,const DWRITE_GLYPH_OFFSET *glyph_offsets,UINT32 glyph_count,WINBOOL is_sideways,WINBOOL is_rtl,IDWriteGeometrySink *geometrysink) { + return This->lpVtbl->GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetGdiCompatibleGlyphMetrics(IDWriteFontFace4* This,FLOAT emSize,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,const UINT16 *glyph_indices,UINT32 glyph_count,DWRITE_GLYPH_METRICS *metrics,WINBOOL is_sideways) { + return This->lpVtbl->GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways); +} +/*** IDWriteFontFace1 methods ***/ +static FORCEINLINE void IDWriteFontFace4_GetMetrics(IDWriteFontFace4* This,DWRITE_FONT_METRICS1 *metrics) { + This->lpVtbl->IDWriteFontFace1_GetMetrics(This,metrics); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetGdiCompatibleMetrics(IDWriteFontFace4* This,FLOAT em_size,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,DWRITE_FONT_METRICS1 *metrics) { + return This->lpVtbl->IDWriteFontFace1_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics); +} +static FORCEINLINE void IDWriteFontFace4_GetCaretMetrics(IDWriteFontFace4* This,DWRITE_CARET_METRICS *metrics) { + This->lpVtbl->GetCaretMetrics(This,metrics); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetUnicodeRanges(IDWriteFontFace4* This,UINT32 max_count,DWRITE_UNICODE_RANGE *ranges,UINT32 *count) { + return This->lpVtbl->GetUnicodeRanges(This,max_count,ranges,count); +} +static FORCEINLINE WINBOOL IDWriteFontFace4_IsMonospacedFont(IDWriteFontFace4* This) { + return This->lpVtbl->IsMonospacedFont(This); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetDesignGlyphAdvances(IDWriteFontFace4* This,UINT32 glyph_count,const UINT16 *indices,INT32 *advances,WINBOOL is_sideways) { + return This->lpVtbl->GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetGdiCompatibleGlyphAdvances(IDWriteFontFace4* This,FLOAT em_size,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,WINBOOL is_sideways,UINT32 glyph_count,const UINT16 *indices,INT32 *advances) { + return This->lpVtbl->GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetKerningPairAdjustments(IDWriteFontFace4* This,UINT32 glyph_count,const UINT16 *indices,INT32 *adjustments) { + return This->lpVtbl->GetKerningPairAdjustments(This,glyph_count,indices,adjustments); +} +static FORCEINLINE WINBOOL IDWriteFontFace4_HasKerningPairs(IDWriteFontFace4* This) { + return This->lpVtbl->HasKerningPairs(This); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetVerticalGlyphVariants(IDWriteFontFace4* This,UINT32 glyph_count,const UINT16 *nominal_indices,UINT16 *vertical_indices) { + return This->lpVtbl->GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices); +} +static FORCEINLINE WINBOOL IDWriteFontFace4_HasVerticalGlyphVariants(IDWriteFontFace4* This) { + return This->lpVtbl->HasVerticalGlyphVariants(This); +} +/*** IDWriteFontFace2 methods ***/ +static FORCEINLINE WINBOOL IDWriteFontFace4_IsColorFont(IDWriteFontFace4* This) { + return This->lpVtbl->IsColorFont(This); +} +static FORCEINLINE UINT32 IDWriteFontFace4_GetColorPaletteCount(IDWriteFontFace4* This) { + return This->lpVtbl->GetColorPaletteCount(This); +} +static FORCEINLINE UINT32 IDWriteFontFace4_GetPaletteEntryCount(IDWriteFontFace4* This) { + return This->lpVtbl->GetPaletteEntryCount(This); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetPaletteEntries(IDWriteFontFace4* This,UINT32 palette_index,UINT32 first_entry_index,UINT32 entry_count,DWRITE_COLOR_F *entries) { + return This->lpVtbl->GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries); +} +/*** IDWriteFontFace3 methods ***/ +static FORCEINLINE HRESULT IDWriteFontFace4_GetFontFaceReference(IDWriteFontFace4* This,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,reference); +} +static FORCEINLINE void IDWriteFontFace4_GetPanose(IDWriteFontFace4* This,DWRITE_PANOSE *panose) { + This->lpVtbl->GetPanose(This,panose); +} +static FORCEINLINE DWRITE_FONT_WEIGHT IDWriteFontFace4_GetWeight(IDWriteFontFace4* This) { + return This->lpVtbl->GetWeight(This); +} +static FORCEINLINE DWRITE_FONT_STRETCH IDWriteFontFace4_GetStretch(IDWriteFontFace4* This) { + return This->lpVtbl->GetStretch(This); +} +static FORCEINLINE DWRITE_FONT_STYLE IDWriteFontFace4_GetStyle(IDWriteFontFace4* This) { + return This->lpVtbl->GetStyle(This); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetFamilyNames(IDWriteFontFace4* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFamilyNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetFaceNames(IDWriteFontFace4* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFaceNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetInformationalStrings(IDWriteFontFace4* This,DWRITE_INFORMATIONAL_STRING_ID stringid,IDWriteLocalizedStrings **strings,WINBOOL *exists) { + return This->lpVtbl->GetInformationalStrings(This,stringid,strings,exists); +} +static FORCEINLINE WINBOOL IDWriteFontFace4_HasCharacter(IDWriteFontFace4* This,UINT32 character) { + return This->lpVtbl->HasCharacter(This,character); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetRecommendedRenderingMode(IDWriteFontFace4* This,FLOAT emsize,FLOAT dpi_x,FLOAT dpi_y,const DWRITE_MATRIX *transform,WINBOOL is_sideways,DWRITE_OUTLINE_THRESHOLD threshold,DWRITE_MEASURING_MODE measuring_mode,IDWriteRenderingParams *params,DWRITE_RENDERING_MODE1 *rendering_mode,DWRITE_GRID_FIT_MODE *gridfit_mode) { + return This->lpVtbl->IDWriteFontFace3_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode); +} +static FORCEINLINE WINBOOL IDWriteFontFace4_IsCharacterLocal(IDWriteFontFace4* This,UINT32 character) { + return This->lpVtbl->IsCharacterLocal(This,character); +} +static FORCEINLINE WINBOOL IDWriteFontFace4_IsGlyphLocal(IDWriteFontFace4* This,UINT16 glyph) { + return This->lpVtbl->IsGlyphLocal(This,glyph); +} +static FORCEINLINE HRESULT IDWriteFontFace4_AreCharactersLocal(IDWriteFontFace4* This,const WCHAR *characters,UINT32 count,WINBOOL enqueue_if_not,WINBOOL *are_local) { + return This->lpVtbl->AreCharactersLocal(This,characters,count,enqueue_if_not,are_local); +} +static FORCEINLINE HRESULT IDWriteFontFace4_AreGlyphsLocal(IDWriteFontFace4* This,const UINT16 *glyphs,UINT32 count,WINBOOL enqueue_if_not,WINBOOL *are_local) { + return This->lpVtbl->AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local); +} +/*** IDWriteFontFace4 methods ***/ +static FORCEINLINE HRESULT IDWriteFontFace4_GetGlyphImageFormats_(IDWriteFontFace4* This,UINT16 glyph,UINT32 ppem_first,UINT32 ppem_last,DWRITE_GLYPH_IMAGE_FORMATS *formats) { + return This->lpVtbl->GetGlyphImageFormats_(This,glyph,ppem_first,ppem_last,formats); +} +static FORCEINLINE DWRITE_GLYPH_IMAGE_FORMATS IDWriteFontFace4_GetGlyphImageFormats(IDWriteFontFace4* This) { + return This->lpVtbl->GetGlyphImageFormats(This); +} +static FORCEINLINE HRESULT IDWriteFontFace4_GetGlyphImageData(IDWriteFontFace4* This,UINT16 glyph,UINT32 ppem,DWRITE_GLYPH_IMAGE_FORMATS format,DWRITE_GLYPH_IMAGE_DATA *data,void **context) { + return This->lpVtbl->GetGlyphImageData(This,glyph,ppem,format,data,context); +} +static FORCEINLINE void IDWriteFontFace4_ReleaseGlyphImageData(IDWriteFontFace4* This,void *context) { + This->lpVtbl->ReleaseGlyphImageData(This,context); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontFace4_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFontFace5 interface + */ +#ifndef __IDWriteFontFace5_INTERFACE_DEFINED__ +#define __IDWriteFontFace5_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFontFace5, 0x98eff3a5, 0xb667, 0x479a, 0xb1,0x45, 0xe2,0xfa,0x5b,0x9f,0xdc,0x29); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("98eff3a5-b667-479a-b145-e2fa5b9fdc29") +IDWriteFontFace5 : public IDWriteFontFace4 +{ + virtual UINT32 STDMETHODCALLTYPE GetFontAxisValueCount( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontAxisValues( + DWRITE_FONT_AXIS_VALUE *values, + UINT32 value_count) = 0; + + virtual WINBOOL STDMETHODCALLTYPE HasVariations( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFontResource( + IDWriteFontResource **resource) = 0; + + virtual WINBOOL STDMETHODCALLTYPE Equals( + IDWriteFontFace *fontface) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFontFace5, 0x98eff3a5, 0xb667, 0x479a, 0xb1,0x45, 0xe2,0xfa,0x5b,0x9f,0xdc,0x29) +#endif +#else +typedef struct IDWriteFontFace5Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFontFace5 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFontFace5 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFontFace5 *This); + + /*** IDWriteFontFace methods ***/ + DWRITE_FONT_FACE_TYPE (STDMETHODCALLTYPE *GetType)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *GetFiles)( + IDWriteFontFace5 *This, + UINT32 *number_of_files, + IDWriteFontFile **fontfiles); + + UINT32 (STDMETHODCALLTYPE *GetIndex)( + IDWriteFontFace5 *This); + + DWRITE_FONT_SIMULATIONS (STDMETHODCALLTYPE *GetSimulations)( + IDWriteFontFace5 *This); + + WINBOOL (STDMETHODCALLTYPE *IsSymbolFont)( + IDWriteFontFace5 *This); + + void (STDMETHODCALLTYPE *GetMetrics)( + IDWriteFontFace5 *This, + DWRITE_FONT_METRICS *metrics); + + UINT16 (STDMETHODCALLTYPE *GetGlyphCount)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *GetDesignGlyphMetrics)( + IDWriteFontFace5 *This, + const UINT16 *glyph_indices, + UINT32 glyph_count, + DWRITE_GLYPH_METRICS *metrics, + WINBOOL is_sideways); + + HRESULT (STDMETHODCALLTYPE *GetGlyphIndices)( + IDWriteFontFace5 *This, + const UINT32 *codepoints, + UINT32 count, + UINT16 *glyph_indices); + + HRESULT (STDMETHODCALLTYPE *TryGetFontTable)( + IDWriteFontFace5 *This, + UINT32 table_tag, + const void **table_data, + UINT32 *table_size, + void **context, + WINBOOL *exists); + + void (STDMETHODCALLTYPE *ReleaseFontTable)( + IDWriteFontFace5 *This, + void *table_context); + + HRESULT (STDMETHODCALLTYPE *GetGlyphRunOutline)( + IDWriteFontFace5 *This, + FLOAT emSize, + const UINT16 *glyph_indices, + const FLOAT *glyph_advances, + const DWRITE_GLYPH_OFFSET *glyph_offsets, + UINT32 glyph_count, + WINBOOL is_sideways, + WINBOOL is_rtl, + IDWriteGeometrySink *geometrysink); + + HRESULT (STDMETHODCALLTYPE *GetRecommendedRenderingMode)( + IDWriteFontFace5 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + DWRITE_MEASURING_MODE mode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE *rendering_mode); + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleMetrics)( + IDWriteFontFace5 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_FONT_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleGlyphMetrics)( + IDWriteFontFace5 *This, + FLOAT emSize, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + const UINT16 *glyph_indices, + UINT32 glyph_count, + DWRITE_GLYPH_METRICS *metrics, + WINBOOL is_sideways); + + /*** IDWriteFontFace1 methods ***/ + void (STDMETHODCALLTYPE *IDWriteFontFace1_GetMetrics)( + IDWriteFontFace5 *This, + DWRITE_FONT_METRICS1 *metrics); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace1_GetGdiCompatibleMetrics)( + IDWriteFontFace5 *This, + FLOAT em_size, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_FONT_METRICS1 *metrics); + + void (STDMETHODCALLTYPE *GetCaretMetrics)( + IDWriteFontFace5 *This, + DWRITE_CARET_METRICS *metrics); + + HRESULT (STDMETHODCALLTYPE *GetUnicodeRanges)( + IDWriteFontFace5 *This, + UINT32 max_count, + DWRITE_UNICODE_RANGE *ranges, + UINT32 *count); + + WINBOOL (STDMETHODCALLTYPE *IsMonospacedFont)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *GetDesignGlyphAdvances)( + IDWriteFontFace5 *This, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *advances, + WINBOOL is_sideways); + + HRESULT (STDMETHODCALLTYPE *GetGdiCompatibleGlyphAdvances)( + IDWriteFontFace5 *This, + FLOAT em_size, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + WINBOOL is_sideways, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *advances); + + HRESULT (STDMETHODCALLTYPE *GetKerningPairAdjustments)( + IDWriteFontFace5 *This, + UINT32 glyph_count, + const UINT16 *indices, + INT32 *adjustments); + + WINBOOL (STDMETHODCALLTYPE *HasKerningPairs)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace1_GetRecommendedRenderingMode)( + IDWriteFontFace5 *This, + FLOAT font_emsize, + FLOAT dpiX, + FLOAT dpiY, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_RENDERING_MODE *rendering_mode); + + HRESULT (STDMETHODCALLTYPE *GetVerticalGlyphVariants)( + IDWriteFontFace5 *This, + UINT32 glyph_count, + const UINT16 *nominal_indices, + UINT16 *vertical_indices); + + WINBOOL (STDMETHODCALLTYPE *HasVerticalGlyphVariants)( + IDWriteFontFace5 *This); + + /*** IDWriteFontFace2 methods ***/ + WINBOOL (STDMETHODCALLTYPE *IsColorFont)( + IDWriteFontFace5 *This); + + UINT32 (STDMETHODCALLTYPE *GetColorPaletteCount)( + IDWriteFontFace5 *This); + + UINT32 (STDMETHODCALLTYPE *GetPaletteEntryCount)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *GetPaletteEntries)( + IDWriteFontFace5 *This, + UINT32 palette_index, + UINT32 first_entry_index, + UINT32 entry_count, + DWRITE_COLOR_F *entries); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace2_GetRecommendedRenderingMode)( + IDWriteFontFace5 *This, + FLOAT fontEmSize, + FLOAT dpiX, + FLOAT dpiY, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuringmode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE *renderingmode, + DWRITE_GRID_FIT_MODE *gridfitmode); + + /*** IDWriteFontFace3 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetFontFaceReference)( + IDWriteFontFace5 *This, + IDWriteFontFaceReference **reference); + + void (STDMETHODCALLTYPE *GetPanose)( + IDWriteFontFace5 *This, + DWRITE_PANOSE *panose); + + DWRITE_FONT_WEIGHT (STDMETHODCALLTYPE *GetWeight)( + IDWriteFontFace5 *This); + + DWRITE_FONT_STRETCH (STDMETHODCALLTYPE *GetStretch)( + IDWriteFontFace5 *This); + + DWRITE_FONT_STYLE (STDMETHODCALLTYPE *GetStyle)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *GetFamilyNames)( + IDWriteFontFace5 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetFaceNames)( + IDWriteFontFace5 *This, + IDWriteLocalizedStrings **names); + + HRESULT (STDMETHODCALLTYPE *GetInformationalStrings)( + IDWriteFontFace5 *This, + DWRITE_INFORMATIONAL_STRING_ID stringid, + IDWriteLocalizedStrings **strings, + WINBOOL *exists); + + WINBOOL (STDMETHODCALLTYPE *HasCharacter)( + IDWriteFontFace5 *This, + UINT32 character); + + HRESULT (STDMETHODCALLTYPE *IDWriteFontFace3_GetRecommendedRenderingMode)( + IDWriteFontFace5 *This, + FLOAT emsize, + FLOAT dpi_x, + FLOAT dpi_y, + const DWRITE_MATRIX *transform, + WINBOOL is_sideways, + DWRITE_OUTLINE_THRESHOLD threshold, + DWRITE_MEASURING_MODE measuring_mode, + IDWriteRenderingParams *params, + DWRITE_RENDERING_MODE1 *rendering_mode, + DWRITE_GRID_FIT_MODE *gridfit_mode); + + WINBOOL (STDMETHODCALLTYPE *IsCharacterLocal)( + IDWriteFontFace5 *This, + UINT32 character); + + WINBOOL (STDMETHODCALLTYPE *IsGlyphLocal)( + IDWriteFontFace5 *This, + UINT16 glyph); + + HRESULT (STDMETHODCALLTYPE *AreCharactersLocal)( + IDWriteFontFace5 *This, + const WCHAR *characters, + UINT32 count, + WINBOOL enqueue_if_not, + WINBOOL *are_local); + + HRESULT (STDMETHODCALLTYPE *AreGlyphsLocal)( + IDWriteFontFace5 *This, + const UINT16 *glyphs, + UINT32 count, + WINBOOL enqueue_if_not, + WINBOOL *are_local); + + /*** IDWriteFontFace4 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetGlyphImageFormats_)( + IDWriteFontFace5 *This, + UINT16 glyph, + UINT32 ppem_first, + UINT32 ppem_last, + DWRITE_GLYPH_IMAGE_FORMATS *formats); + + DWRITE_GLYPH_IMAGE_FORMATS (STDMETHODCALLTYPE *GetGlyphImageFormats)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *GetGlyphImageData)( + IDWriteFontFace5 *This, + UINT16 glyph, + UINT32 ppem, + DWRITE_GLYPH_IMAGE_FORMATS format, + DWRITE_GLYPH_IMAGE_DATA *data, + void **context); + + void (STDMETHODCALLTYPE *ReleaseGlyphImageData)( + IDWriteFontFace5 *This, + void *context); + + /*** IDWriteFontFace5 methods ***/ + UINT32 (STDMETHODCALLTYPE *GetFontAxisValueCount)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontAxisValues)( + IDWriteFontFace5 *This, + DWRITE_FONT_AXIS_VALUE *values, + UINT32 value_count); + + WINBOOL (STDMETHODCALLTYPE *HasVariations)( + IDWriteFontFace5 *This); + + HRESULT (STDMETHODCALLTYPE *GetFontResource)( + IDWriteFontFace5 *This, + IDWriteFontResource **resource); + + WINBOOL (STDMETHODCALLTYPE *Equals)( + IDWriteFontFace5 *This, + IDWriteFontFace *fontface); + + END_INTERFACE +} IDWriteFontFace5Vtbl; + +interface IDWriteFontFace5 { + CONST_VTBL IDWriteFontFace5Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFontFace5_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFontFace5_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFontFace5_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFace methods ***/ +#define IDWriteFontFace5_GetType(This) (This)->lpVtbl->GetType(This) +#define IDWriteFontFace5_GetFiles(This,number_of_files,fontfiles) (This)->lpVtbl->GetFiles(This,number_of_files,fontfiles) +#define IDWriteFontFace5_GetIndex(This) (This)->lpVtbl->GetIndex(This) +#define IDWriteFontFace5_GetSimulations(This) (This)->lpVtbl->GetSimulations(This) +#define IDWriteFontFace5_IsSymbolFont(This) (This)->lpVtbl->IsSymbolFont(This) +#define IDWriteFontFace5_GetGlyphCount(This) (This)->lpVtbl->GetGlyphCount(This) +#define IDWriteFontFace5_GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways) (This)->lpVtbl->GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways) +#define IDWriteFontFace5_GetGlyphIndices(This,codepoints,count,glyph_indices) (This)->lpVtbl->GetGlyphIndices(This,codepoints,count,glyph_indices) +#define IDWriteFontFace5_TryGetFontTable(This,table_tag,table_data,table_size,context,exists) (This)->lpVtbl->TryGetFontTable(This,table_tag,table_data,table_size,context,exists) +#define IDWriteFontFace5_ReleaseFontTable(This,table_context) (This)->lpVtbl->ReleaseFontTable(This,table_context) +#define IDWriteFontFace5_GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink) (This)->lpVtbl->GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink) +#define IDWriteFontFace5_GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways) (This)->lpVtbl->GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways) +/*** IDWriteFontFace1 methods ***/ +#define IDWriteFontFace5_GetMetrics(This,metrics) (This)->lpVtbl->IDWriteFontFace1_GetMetrics(This,metrics) +#define IDWriteFontFace5_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics) (This)->lpVtbl->IDWriteFontFace1_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics) +#define IDWriteFontFace5_GetCaretMetrics(This,metrics) (This)->lpVtbl->GetCaretMetrics(This,metrics) +#define IDWriteFontFace5_GetUnicodeRanges(This,max_count,ranges,count) (This)->lpVtbl->GetUnicodeRanges(This,max_count,ranges,count) +#define IDWriteFontFace5_IsMonospacedFont(This) (This)->lpVtbl->IsMonospacedFont(This) +#define IDWriteFontFace5_GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways) (This)->lpVtbl->GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways) +#define IDWriteFontFace5_GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances) (This)->lpVtbl->GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances) +#define IDWriteFontFace5_GetKerningPairAdjustments(This,glyph_count,indices,adjustments) (This)->lpVtbl->GetKerningPairAdjustments(This,glyph_count,indices,adjustments) +#define IDWriteFontFace5_HasKerningPairs(This) (This)->lpVtbl->HasKerningPairs(This) +#define IDWriteFontFace5_GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices) (This)->lpVtbl->GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices) +#define IDWriteFontFace5_HasVerticalGlyphVariants(This) (This)->lpVtbl->HasVerticalGlyphVariants(This) +/*** IDWriteFontFace2 methods ***/ +#define IDWriteFontFace5_IsColorFont(This) (This)->lpVtbl->IsColorFont(This) +#define IDWriteFontFace5_GetColorPaletteCount(This) (This)->lpVtbl->GetColorPaletteCount(This) +#define IDWriteFontFace5_GetPaletteEntryCount(This) (This)->lpVtbl->GetPaletteEntryCount(This) +#define IDWriteFontFace5_GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries) (This)->lpVtbl->GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries) +/*** IDWriteFontFace3 methods ***/ +#define IDWriteFontFace5_GetFontFaceReference(This,reference) (This)->lpVtbl->GetFontFaceReference(This,reference) +#define IDWriteFontFace5_GetPanose(This,panose) (This)->lpVtbl->GetPanose(This,panose) +#define IDWriteFontFace5_GetWeight(This) (This)->lpVtbl->GetWeight(This) +#define IDWriteFontFace5_GetStretch(This) (This)->lpVtbl->GetStretch(This) +#define IDWriteFontFace5_GetStyle(This) (This)->lpVtbl->GetStyle(This) +#define IDWriteFontFace5_GetFamilyNames(This,names) (This)->lpVtbl->GetFamilyNames(This,names) +#define IDWriteFontFace5_GetFaceNames(This,names) (This)->lpVtbl->GetFaceNames(This,names) +#define IDWriteFontFace5_GetInformationalStrings(This,stringid,strings,exists) (This)->lpVtbl->GetInformationalStrings(This,stringid,strings,exists) +#define IDWriteFontFace5_HasCharacter(This,character) (This)->lpVtbl->HasCharacter(This,character) +#define IDWriteFontFace5_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode) (This)->lpVtbl->IDWriteFontFace3_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode) +#define IDWriteFontFace5_IsCharacterLocal(This,character) (This)->lpVtbl->IsCharacterLocal(This,character) +#define IDWriteFontFace5_IsGlyphLocal(This,glyph) (This)->lpVtbl->IsGlyphLocal(This,glyph) +#define IDWriteFontFace5_AreCharactersLocal(This,characters,count,enqueue_if_not,are_local) (This)->lpVtbl->AreCharactersLocal(This,characters,count,enqueue_if_not,are_local) +#define IDWriteFontFace5_AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local) (This)->lpVtbl->AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local) +/*** IDWriteFontFace4 methods ***/ +#define IDWriteFontFace5_GetGlyphImageFormats_(This,glyph,ppem_first,ppem_last,formats) (This)->lpVtbl->GetGlyphImageFormats_(This,glyph,ppem_first,ppem_last,formats) +#define IDWriteFontFace5_GetGlyphImageFormats(This) (This)->lpVtbl->GetGlyphImageFormats(This) +#define IDWriteFontFace5_GetGlyphImageData(This,glyph,ppem,format,data,context) (This)->lpVtbl->GetGlyphImageData(This,glyph,ppem,format,data,context) +#define IDWriteFontFace5_ReleaseGlyphImageData(This,context) (This)->lpVtbl->ReleaseGlyphImageData(This,context) +/*** IDWriteFontFace5 methods ***/ +#define IDWriteFontFace5_GetFontAxisValueCount(This) (This)->lpVtbl->GetFontAxisValueCount(This) +#define IDWriteFontFace5_GetFontAxisValues(This,values,value_count) (This)->lpVtbl->GetFontAxisValues(This,values,value_count) +#define IDWriteFontFace5_HasVariations(This) (This)->lpVtbl->HasVariations(This) +#define IDWriteFontFace5_GetFontResource(This,resource) (This)->lpVtbl->GetFontResource(This,resource) +#define IDWriteFontFace5_Equals(This,fontface) (This)->lpVtbl->Equals(This,fontface) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFontFace5_QueryInterface(IDWriteFontFace5* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFontFace5_AddRef(IDWriteFontFace5* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFontFace5_Release(IDWriteFontFace5* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFace methods ***/ +static FORCEINLINE DWRITE_FONT_FACE_TYPE IDWriteFontFace5_GetType(IDWriteFontFace5* This) { + return This->lpVtbl->GetType(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetFiles(IDWriteFontFace5* This,UINT32 *number_of_files,IDWriteFontFile **fontfiles) { + return This->lpVtbl->GetFiles(This,number_of_files,fontfiles); +} +static FORCEINLINE UINT32 IDWriteFontFace5_GetIndex(IDWriteFontFace5* This) { + return This->lpVtbl->GetIndex(This); +} +static FORCEINLINE DWRITE_FONT_SIMULATIONS IDWriteFontFace5_GetSimulations(IDWriteFontFace5* This) { + return This->lpVtbl->GetSimulations(This); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_IsSymbolFont(IDWriteFontFace5* This) { + return This->lpVtbl->IsSymbolFont(This); +} +static FORCEINLINE UINT16 IDWriteFontFace5_GetGlyphCount(IDWriteFontFace5* This) { + return This->lpVtbl->GetGlyphCount(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetDesignGlyphMetrics(IDWriteFontFace5* This,const UINT16 *glyph_indices,UINT32 glyph_count,DWRITE_GLYPH_METRICS *metrics,WINBOOL is_sideways) { + return This->lpVtbl->GetDesignGlyphMetrics(This,glyph_indices,glyph_count,metrics,is_sideways); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetGlyphIndices(IDWriteFontFace5* This,const UINT32 *codepoints,UINT32 count,UINT16 *glyph_indices) { + return This->lpVtbl->GetGlyphIndices(This,codepoints,count,glyph_indices); +} +static FORCEINLINE HRESULT IDWriteFontFace5_TryGetFontTable(IDWriteFontFace5* This,UINT32 table_tag,const void **table_data,UINT32 *table_size,void **context,WINBOOL *exists) { + return This->lpVtbl->TryGetFontTable(This,table_tag,table_data,table_size,context,exists); +} +static FORCEINLINE void IDWriteFontFace5_ReleaseFontTable(IDWriteFontFace5* This,void *table_context) { + This->lpVtbl->ReleaseFontTable(This,table_context); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetGlyphRunOutline(IDWriteFontFace5* This,FLOAT emSize,const UINT16 *glyph_indices,const FLOAT *glyph_advances,const DWRITE_GLYPH_OFFSET *glyph_offsets,UINT32 glyph_count,WINBOOL is_sideways,WINBOOL is_rtl,IDWriteGeometrySink *geometrysink) { + return This->lpVtbl->GetGlyphRunOutline(This,emSize,glyph_indices,glyph_advances,glyph_offsets,glyph_count,is_sideways,is_rtl,geometrysink); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5* This,FLOAT emSize,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,const UINT16 *glyph_indices,UINT32 glyph_count,DWRITE_GLYPH_METRICS *metrics,WINBOOL is_sideways) { + return This->lpVtbl->GetGdiCompatibleGlyphMetrics(This,emSize,pixels_per_dip,transform,use_gdi_natural,glyph_indices,glyph_count,metrics,is_sideways); +} +/*** IDWriteFontFace1 methods ***/ +static FORCEINLINE void IDWriteFontFace5_GetMetrics(IDWriteFontFace5* This,DWRITE_FONT_METRICS1 *metrics) { + This->lpVtbl->IDWriteFontFace1_GetMetrics(This,metrics); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetGdiCompatibleMetrics(IDWriteFontFace5* This,FLOAT em_size,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,DWRITE_FONT_METRICS1 *metrics) { + return This->lpVtbl->IDWriteFontFace1_GetGdiCompatibleMetrics(This,em_size,pixels_per_dip,transform,metrics); +} +static FORCEINLINE void IDWriteFontFace5_GetCaretMetrics(IDWriteFontFace5* This,DWRITE_CARET_METRICS *metrics) { + This->lpVtbl->GetCaretMetrics(This,metrics); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetUnicodeRanges(IDWriteFontFace5* This,UINT32 max_count,DWRITE_UNICODE_RANGE *ranges,UINT32 *count) { + return This->lpVtbl->GetUnicodeRanges(This,max_count,ranges,count); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_IsMonospacedFont(IDWriteFontFace5* This) { + return This->lpVtbl->IsMonospacedFont(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetDesignGlyphAdvances(IDWriteFontFace5* This,UINT32 glyph_count,const UINT16 *indices,INT32 *advances,WINBOOL is_sideways) { + return This->lpVtbl->GetDesignGlyphAdvances(This,glyph_count,indices,advances,is_sideways); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5* This,FLOAT em_size,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,WINBOOL is_sideways,UINT32 glyph_count,const UINT16 *indices,INT32 *advances) { + return This->lpVtbl->GetGdiCompatibleGlyphAdvances(This,em_size,pixels_per_dip,transform,use_gdi_natural,is_sideways,glyph_count,indices,advances); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetKerningPairAdjustments(IDWriteFontFace5* This,UINT32 glyph_count,const UINT16 *indices,INT32 *adjustments) { + return This->lpVtbl->GetKerningPairAdjustments(This,glyph_count,indices,adjustments); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_HasKerningPairs(IDWriteFontFace5* This) { + return This->lpVtbl->HasKerningPairs(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetVerticalGlyphVariants(IDWriteFontFace5* This,UINT32 glyph_count,const UINT16 *nominal_indices,UINT16 *vertical_indices) { + return This->lpVtbl->GetVerticalGlyphVariants(This,glyph_count,nominal_indices,vertical_indices); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_HasVerticalGlyphVariants(IDWriteFontFace5* This) { + return This->lpVtbl->HasVerticalGlyphVariants(This); +} +/*** IDWriteFontFace2 methods ***/ +static FORCEINLINE WINBOOL IDWriteFontFace5_IsColorFont(IDWriteFontFace5* This) { + return This->lpVtbl->IsColorFont(This); +} +static FORCEINLINE UINT32 IDWriteFontFace5_GetColorPaletteCount(IDWriteFontFace5* This) { + return This->lpVtbl->GetColorPaletteCount(This); +} +static FORCEINLINE UINT32 IDWriteFontFace5_GetPaletteEntryCount(IDWriteFontFace5* This) { + return This->lpVtbl->GetPaletteEntryCount(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetPaletteEntries(IDWriteFontFace5* This,UINT32 palette_index,UINT32 first_entry_index,UINT32 entry_count,DWRITE_COLOR_F *entries) { + return This->lpVtbl->GetPaletteEntries(This,palette_index,first_entry_index,entry_count,entries); +} +/*** IDWriteFontFace3 methods ***/ +static FORCEINLINE HRESULT IDWriteFontFace5_GetFontFaceReference(IDWriteFontFace5* This,IDWriteFontFaceReference **reference) { + return This->lpVtbl->GetFontFaceReference(This,reference); +} +static FORCEINLINE void IDWriteFontFace5_GetPanose(IDWriteFontFace5* This,DWRITE_PANOSE *panose) { + This->lpVtbl->GetPanose(This,panose); +} +static FORCEINLINE DWRITE_FONT_WEIGHT IDWriteFontFace5_GetWeight(IDWriteFontFace5* This) { + return This->lpVtbl->GetWeight(This); +} +static FORCEINLINE DWRITE_FONT_STRETCH IDWriteFontFace5_GetStretch(IDWriteFontFace5* This) { + return This->lpVtbl->GetStretch(This); +} +static FORCEINLINE DWRITE_FONT_STYLE IDWriteFontFace5_GetStyle(IDWriteFontFace5* This) { + return This->lpVtbl->GetStyle(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetFamilyNames(IDWriteFontFace5* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFamilyNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetFaceNames(IDWriteFontFace5* This,IDWriteLocalizedStrings **names) { + return This->lpVtbl->GetFaceNames(This,names); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetInformationalStrings(IDWriteFontFace5* This,DWRITE_INFORMATIONAL_STRING_ID stringid,IDWriteLocalizedStrings **strings,WINBOOL *exists) { + return This->lpVtbl->GetInformationalStrings(This,stringid,strings,exists); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_HasCharacter(IDWriteFontFace5* This,UINT32 character) { + return This->lpVtbl->HasCharacter(This,character); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetRecommendedRenderingMode(IDWriteFontFace5* This,FLOAT emsize,FLOAT dpi_x,FLOAT dpi_y,const DWRITE_MATRIX *transform,WINBOOL is_sideways,DWRITE_OUTLINE_THRESHOLD threshold,DWRITE_MEASURING_MODE measuring_mode,IDWriteRenderingParams *params,DWRITE_RENDERING_MODE1 *rendering_mode,DWRITE_GRID_FIT_MODE *gridfit_mode) { + return This->lpVtbl->IDWriteFontFace3_GetRecommendedRenderingMode(This,emsize,dpi_x,dpi_y,transform,is_sideways,threshold,measuring_mode,params,rendering_mode,gridfit_mode); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_IsCharacterLocal(IDWriteFontFace5* This,UINT32 character) { + return This->lpVtbl->IsCharacterLocal(This,character); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_IsGlyphLocal(IDWriteFontFace5* This,UINT16 glyph) { + return This->lpVtbl->IsGlyphLocal(This,glyph); +} +static FORCEINLINE HRESULT IDWriteFontFace5_AreCharactersLocal(IDWriteFontFace5* This,const WCHAR *characters,UINT32 count,WINBOOL enqueue_if_not,WINBOOL *are_local) { + return This->lpVtbl->AreCharactersLocal(This,characters,count,enqueue_if_not,are_local); +} +static FORCEINLINE HRESULT IDWriteFontFace5_AreGlyphsLocal(IDWriteFontFace5* This,const UINT16 *glyphs,UINT32 count,WINBOOL enqueue_if_not,WINBOOL *are_local) { + return This->lpVtbl->AreGlyphsLocal(This,glyphs,count,enqueue_if_not,are_local); +} +/*** IDWriteFontFace4 methods ***/ +static FORCEINLINE HRESULT IDWriteFontFace5_GetGlyphImageFormats_(IDWriteFontFace5* This,UINT16 glyph,UINT32 ppem_first,UINT32 ppem_last,DWRITE_GLYPH_IMAGE_FORMATS *formats) { + return This->lpVtbl->GetGlyphImageFormats_(This,glyph,ppem_first,ppem_last,formats); +} +static FORCEINLINE DWRITE_GLYPH_IMAGE_FORMATS IDWriteFontFace5_GetGlyphImageFormats(IDWriteFontFace5* This) { + return This->lpVtbl->GetGlyphImageFormats(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetGlyphImageData(IDWriteFontFace5* This,UINT16 glyph,UINT32 ppem,DWRITE_GLYPH_IMAGE_FORMATS format,DWRITE_GLYPH_IMAGE_DATA *data,void **context) { + return This->lpVtbl->GetGlyphImageData(This,glyph,ppem,format,data,context); +} +static FORCEINLINE void IDWriteFontFace5_ReleaseGlyphImageData(IDWriteFontFace5* This,void *context) { + This->lpVtbl->ReleaseGlyphImageData(This,context); +} +/*** IDWriteFontFace5 methods ***/ +static FORCEINLINE UINT32 IDWriteFontFace5_GetFontAxisValueCount(IDWriteFontFace5* This) { + return This->lpVtbl->GetFontAxisValueCount(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetFontAxisValues(IDWriteFontFace5* This,DWRITE_FONT_AXIS_VALUE *values,UINT32 value_count) { + return This->lpVtbl->GetFontAxisValues(This,values,value_count); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_HasVariations(IDWriteFontFace5* This) { + return This->lpVtbl->HasVariations(This); +} +static FORCEINLINE HRESULT IDWriteFontFace5_GetFontResource(IDWriteFontFace5* This,IDWriteFontResource **resource) { + return This->lpVtbl->GetFontResource(This,resource); +} +static FORCEINLINE WINBOOL IDWriteFontFace5_Equals(IDWriteFontFace5* This,IDWriteFontFace *fontface) { + return This->lpVtbl->Equals(This,fontface); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFontFace5_INTERFACE_DEFINED__ */ + +typedef struct DWRITE_COLOR_GLYPH_RUN1 { + DWRITE_GLYPH_RUN glyphRun; + DWRITE_GLYPH_RUN_DESCRIPTION *glyphRunDescription; + FLOAT baselineOriginX; + FLOAT baselineOriginY; + DWRITE_COLOR_F runColor; + UINT16 paletteIndex; + DWRITE_GLYPH_IMAGE_FORMATS glyphImageFormat; + DWRITE_MEASURING_MODE measuringMode; +} DWRITE_COLOR_GLYPH_RUN1; +/***************************************************************************** + * IDWriteColorGlyphRunEnumerator1 interface + */ +#ifndef __IDWriteColorGlyphRunEnumerator1_INTERFACE_DEFINED__ +#define __IDWriteColorGlyphRunEnumerator1_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteColorGlyphRunEnumerator1, 0x7c5f86da, 0xc7a1, 0x4f05, 0xb8,0xe1, 0x55,0xa1,0x79,0xfe,0x5a,0x35); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("7c5f86da-c7a1-4f05-b8e1-55a179fe5a35") +IDWriteColorGlyphRunEnumerator1 : public IDWriteColorGlyphRunEnumerator +{ + virtual HRESULT STDMETHODCALLTYPE GetCurrentRun( + const DWRITE_COLOR_GLYPH_RUN1 **run) = 0; + + using IDWriteColorGlyphRunEnumerator::GetCurrentRun; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteColorGlyphRunEnumerator1, 0x7c5f86da, 0xc7a1, 0x4f05, 0xb8,0xe1, 0x55,0xa1,0x79,0xfe,0x5a,0x35) +#endif +#else +typedef struct IDWriteColorGlyphRunEnumerator1Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteColorGlyphRunEnumerator1 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteColorGlyphRunEnumerator1 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteColorGlyphRunEnumerator1 *This); + + /*** IDWriteColorGlyphRunEnumerator methods ***/ + HRESULT (STDMETHODCALLTYPE *MoveNext)( + IDWriteColorGlyphRunEnumerator1 *This, + WINBOOL *hasRun); + + HRESULT (STDMETHODCALLTYPE *GetCurrentRun)( + IDWriteColorGlyphRunEnumerator1 *This, + const DWRITE_COLOR_GLYPH_RUN **run); + + /*** IDWriteColorGlyphRunEnumerator1 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteColorGlyphRunEnumerator1_GetCurrentRun)( + IDWriteColorGlyphRunEnumerator1 *This, + const DWRITE_COLOR_GLYPH_RUN1 **run); + + END_INTERFACE +} IDWriteColorGlyphRunEnumerator1Vtbl; + +interface IDWriteColorGlyphRunEnumerator1 { + CONST_VTBL IDWriteColorGlyphRunEnumerator1Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteColorGlyphRunEnumerator1_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteColorGlyphRunEnumerator1_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteColorGlyphRunEnumerator1_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteColorGlyphRunEnumerator methods ***/ +#define IDWriteColorGlyphRunEnumerator1_MoveNext(This,hasRun) (This)->lpVtbl->MoveNext(This,hasRun) +/*** IDWriteColorGlyphRunEnumerator1 methods ***/ +#define IDWriteColorGlyphRunEnumerator1_GetCurrentRun(This,run) (This)->lpVtbl->IDWriteColorGlyphRunEnumerator1_GetCurrentRun(This,run) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteColorGlyphRunEnumerator1_QueryInterface(IDWriteColorGlyphRunEnumerator1* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteColorGlyphRunEnumerator1_AddRef(IDWriteColorGlyphRunEnumerator1* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteColorGlyphRunEnumerator1_Release(IDWriteColorGlyphRunEnumerator1* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteColorGlyphRunEnumerator methods ***/ +static FORCEINLINE HRESULT IDWriteColorGlyphRunEnumerator1_MoveNext(IDWriteColorGlyphRunEnumerator1* This,WINBOOL *hasRun) { + return This->lpVtbl->MoveNext(This,hasRun); +} +/*** IDWriteColorGlyphRunEnumerator1 methods ***/ +static FORCEINLINE HRESULT IDWriteColorGlyphRunEnumerator1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1* This,const DWRITE_COLOR_GLYPH_RUN1 **run) { + return This->lpVtbl->IDWriteColorGlyphRunEnumerator1_GetCurrentRun(This,run); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteColorGlyphRunEnumerator1_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFactory4 interface + */ +#ifndef __IDWriteFactory4_INTERFACE_DEFINED__ +#define __IDWriteFactory4_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFactory4, 0x4b0b5bd3, 0x0797, 0x4549, 0x8a,0xc5, 0xfe,0x91,0x5c,0xc5,0x38,0x56); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("4b0b5bd3-0797-4549-8ac5-fe915cc53856") +IDWriteFactory4 : public IDWriteFactory3 +{ + virtual HRESULT STDMETHODCALLTYPE TranslateColorGlyphRun( + D2D1_POINT_2F baseline_origin, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc, + DWRITE_GLYPH_IMAGE_FORMATS desired_formats, + DWRITE_MEASURING_MODE measuring_mode, + const DWRITE_MATRIX *transform, + UINT32 palette, + IDWriteColorGlyphRunEnumerator1 **layers) = 0; + + using IDWriteFactory2::TranslateColorGlyphRun; + + virtual HRESULT STDMETHODCALLTYPE ComputeGlyphOrigins( + const DWRITE_GLYPH_RUN *run, + D2D1_POINT_2F baseline_origin, + D2D1_POINT_2F *origins) = 0; + + virtual HRESULT STDMETHODCALLTYPE ComputeGlyphOrigins( + const DWRITE_GLYPH_RUN *run, + DWRITE_MEASURING_MODE measuring_mode, + D2D1_POINT_2F baseline_origin, + const DWRITE_MATRIX *transform, + D2D1_POINT_2F *origins) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFactory4, 0x4b0b5bd3, 0x0797, 0x4549, 0x8a,0xc5, 0xfe,0x91,0x5c,0xc5,0x38,0x56) +#endif +#else +typedef struct IDWriteFactory4Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFactory4 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFactory4 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFactory4 *This); + + /*** IDWriteFactory methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontCollection)( + IDWriteFactory4 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontCollection)( + IDWriteFactory4 *This, + IDWriteFontCollectionLoader *loader, + const void *key, + UINT32 key_size, + IDWriteFontCollection **collection); + + HRESULT (STDMETHODCALLTYPE *RegisterFontCollectionLoader)( + IDWriteFactory4 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontCollectionLoader)( + IDWriteFactory4 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateFontFileReference)( + IDWriteFactory4 *This, + const WCHAR *path, + const FILETIME *writetime, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontFileReference)( + IDWriteFactory4 *This, + const void *reference_key, + UINT32 key_size, + IDWriteFontFileLoader *loader, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFactory4 *This, + DWRITE_FONT_FACE_TYPE facetype, + UINT32 files_number, + IDWriteFontFile *const *font_files, + UINT32 index, + DWRITE_FONT_SIMULATIONS sim_flags, + IDWriteFontFace **font_face); + + HRESULT (STDMETHODCALLTYPE *CreateRenderingParams)( + IDWriteFactory4 *This, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateMonitorRenderingParams)( + IDWriteFactory4 *This, + HMONITOR monitor, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateCustomRenderingParams)( + IDWriteFactory4 *This, + FLOAT gamma, + FLOAT enhancedContrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *RegisterFontFileLoader)( + IDWriteFactory4 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontFileLoader)( + IDWriteFactory4 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateTextFormat)( + IDWriteFactory4 *This, + const WCHAR *family_name, + IDWriteFontCollection *collection, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STYLE style, + DWRITE_FONT_STRETCH stretch, + FLOAT size, + const WCHAR *locale, + IDWriteTextFormat **format); + + HRESULT (STDMETHODCALLTYPE *CreateTypography)( + IDWriteFactory4 *This, + IDWriteTypography **typography); + + HRESULT (STDMETHODCALLTYPE *GetGdiInterop)( + IDWriteFactory4 *This, + IDWriteGdiInterop **gdi_interop); + + HRESULT (STDMETHODCALLTYPE *CreateTextLayout)( + IDWriteFactory4 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT max_width, + FLOAT max_height, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateGdiCompatibleTextLayout)( + IDWriteFactory4 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT layout_width, + FLOAT layout_height, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateEllipsisTrimmingSign)( + IDWriteFactory4 *This, + IDWriteTextFormat *format, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *CreateTextAnalyzer)( + IDWriteFactory4 *This, + IDWriteTextAnalyzer **analyzer); + + HRESULT (STDMETHODCALLTYPE *CreateNumberSubstitution)( + IDWriteFactory4 *This, + DWRITE_NUMBER_SUBSTITUTION_METHOD method, + const WCHAR *locale, + WINBOOL ignore_user_override, + IDWriteNumberSubstitution **substitution); + + HRESULT (STDMETHODCALLTYPE *CreateGlyphRunAnalysis)( + IDWriteFactory4 *This, + const DWRITE_GLYPH_RUN *glyph_run, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + FLOAT baseline_x, + FLOAT baseline_y, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory1 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetEudcFontCollection)( + IDWriteFactory4 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory1_CreateCustomRenderingParams)( + IDWriteFactory4 *This, + FLOAT gamma, + FLOAT enhcontrast, + FLOAT enhcontrast_grayscale, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams1 **params); + + /*** IDWriteFactory2 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontFallback)( + IDWriteFactory4 *This, + IDWriteFontFallback **fallback); + + HRESULT (STDMETHODCALLTYPE *CreateFontFallbackBuilder)( + IDWriteFactory4 *This, + IDWriteFontFallbackBuilder **fallbackbuilder); + + HRESULT (STDMETHODCALLTYPE *TranslateColorGlyphRun)( + IDWriteFactory4 *This, + FLOAT originX, + FLOAT originY, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, + DWRITE_MEASURING_MODE mode, + const DWRITE_MATRIX *transform, + UINT32 palette_index, + IDWriteColorGlyphRunEnumerator **colorlayers); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateCustomRenderingParams)( + IDWriteFactory4 *This, + FLOAT gamma, + FLOAT contrast, + FLOAT grayscalecontrast, + FLOAT cleartypeLevel, + DWRITE_PIXEL_GEOMETRY pixelGeometry, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_GRID_FIT_MODE gridFitMode, + IDWriteRenderingParams2 **params); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateGlyphRunAnalysis)( + IDWriteFactory4 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GRID_FIT_MODE gridFitMode, + DWRITE_TEXT_ANTIALIAS_MODE antialiasMode, + FLOAT originX, + FLOAT originY, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory3 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateGlyphRunAnalysis)( + IDWriteFactory4 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + DWRITE_TEXT_ANTIALIAS_MODE antialias_mode, + FLOAT origin_x, + FLOAT origin_y, + IDWriteGlyphRunAnalysis **analysis); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateCustomRenderingParams)( + IDWriteFactory4 *This, + FLOAT gamma, + FLOAT enhanced_contrast, + FLOAT grayscale_enhanced_contrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY pixel_geometry, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + IDWriteRenderingParams3 **params); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference_)( + IDWriteFactory4 *This, + IDWriteFontFile *file, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference)( + IDWriteFactory4 *This, + const WCHAR *path, + const FILETIME *writetime, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *GetSystemFontSet)( + IDWriteFactory4 *This, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *CreateFontSetBuilder)( + IDWriteFactory4 *This, + IDWriteFontSetBuilder **builder); + + HRESULT (STDMETHODCALLTYPE *CreateFontCollectionFromFontSet)( + IDWriteFactory4 *This, + IDWriteFontSet *fontset, + IDWriteFontCollection1 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_GetSystemFontCollection)( + IDWriteFactory4 *This, + WINBOOL include_downloadable, + IDWriteFontCollection1 **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *GetFontDownloadQueue)( + IDWriteFactory4 *This, + IDWriteFontDownloadQueue **queue); + + /*** IDWriteFactory4 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory4_TranslateColorGlyphRun)( + IDWriteFactory4 *This, + D2D1_POINT_2F baseline_origin, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc, + DWRITE_GLYPH_IMAGE_FORMATS desired_formats, + DWRITE_MEASURING_MODE measuring_mode, + const DWRITE_MATRIX *transform, + UINT32 palette, + IDWriteColorGlyphRunEnumerator1 **layers); + + HRESULT (STDMETHODCALLTYPE *ComputeGlyphOrigins_)( + IDWriteFactory4 *This, + const DWRITE_GLYPH_RUN *run, + D2D1_POINT_2F baseline_origin, + D2D1_POINT_2F *origins); + + HRESULT (STDMETHODCALLTYPE *ComputeGlyphOrigins)( + IDWriteFactory4 *This, + const DWRITE_GLYPH_RUN *run, + DWRITE_MEASURING_MODE measuring_mode, + D2D1_POINT_2F baseline_origin, + const DWRITE_MATRIX *transform, + D2D1_POINT_2F *origins); + + END_INTERFACE +} IDWriteFactory4Vtbl; + +interface IDWriteFactory4 { + CONST_VTBL IDWriteFactory4Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFactory4_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFactory4_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFactory4_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFactory methods ***/ +#define IDWriteFactory4_CreateCustomFontCollection(This,loader,key,key_size,collection) (This)->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection) +#define IDWriteFactory4_RegisterFontCollectionLoader(This,loader) (This)->lpVtbl->RegisterFontCollectionLoader(This,loader) +#define IDWriteFactory4_UnregisterFontCollectionLoader(This,loader) (This)->lpVtbl->UnregisterFontCollectionLoader(This,loader) +#define IDWriteFactory4_CreateFontFileReference(This,path,writetime,font_file) (This)->lpVtbl->CreateFontFileReference(This,path,writetime,font_file) +#define IDWriteFactory4_CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) (This)->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) +#define IDWriteFactory4_CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) (This)->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) +#define IDWriteFactory4_CreateRenderingParams(This,params) (This)->lpVtbl->CreateRenderingParams(This,params) +#define IDWriteFactory4_CreateMonitorRenderingParams(This,monitor,params) (This)->lpVtbl->CreateMonitorRenderingParams(This,monitor,params) +#define IDWriteFactory4_RegisterFontFileLoader(This,loader) (This)->lpVtbl->RegisterFontFileLoader(This,loader) +#define IDWriteFactory4_UnregisterFontFileLoader(This,loader) (This)->lpVtbl->UnregisterFontFileLoader(This,loader) +#define IDWriteFactory4_CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format) (This)->lpVtbl->CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format) +#define IDWriteFactory4_CreateTypography(This,typography) (This)->lpVtbl->CreateTypography(This,typography) +#define IDWriteFactory4_GetGdiInterop(This,gdi_interop) (This)->lpVtbl->GetGdiInterop(This,gdi_interop) +#define IDWriteFactory4_CreateTextLayout(This,string,len,format,max_width,max_height,layout) (This)->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout) +#define IDWriteFactory4_CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) (This)->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) +#define IDWriteFactory4_CreateEllipsisTrimmingSign(This,format,trimming_sign) (This)->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign) +#define IDWriteFactory4_CreateTextAnalyzer(This,analyzer) (This)->lpVtbl->CreateTextAnalyzer(This,analyzer) +#define IDWriteFactory4_CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) (This)->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) +/*** IDWriteFactory1 methods ***/ +#define IDWriteFactory4_GetEudcFontCollection(This,collection,check_for_updates) (This)->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates) +/*** IDWriteFactory2 methods ***/ +#define IDWriteFactory4_GetSystemFontFallback(This,fallback) (This)->lpVtbl->GetSystemFontFallback(This,fallback) +#define IDWriteFactory4_CreateFontFallbackBuilder(This,fallbackbuilder) (This)->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder) +/*** IDWriteFactory3 methods ***/ +#define IDWriteFactory4_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) (This)->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) +#define IDWriteFactory4_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) (This)->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) +#define IDWriteFactory4_CreateFontFaceReference_(This,file,index,simulations,reference) (This)->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference) +#define IDWriteFactory4_CreateFontFaceReference(This,path,writetime,index,simulations,reference) (This)->lpVtbl->CreateFontFaceReference(This,path,writetime,index,simulations,reference) +#define IDWriteFactory4_GetSystemFontSet(This,fontset) (This)->lpVtbl->GetSystemFontSet(This,fontset) +#define IDWriteFactory4_CreateFontSetBuilder(This,builder) (This)->lpVtbl->CreateFontSetBuilder(This,builder) +#define IDWriteFactory4_CreateFontCollectionFromFontSet(This,fontset,collection) (This)->lpVtbl->CreateFontCollectionFromFontSet(This,fontset,collection) +#define IDWriteFactory4_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates) (This)->lpVtbl->IDWriteFactory3_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates) +#define IDWriteFactory4_GetFontDownloadQueue(This,queue) (This)->lpVtbl->GetFontDownloadQueue(This,queue) +/*** IDWriteFactory4 methods ***/ +#define IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers) (This)->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers) +#define IDWriteFactory4_ComputeGlyphOrigins_(This,run,baseline_origin,origins) (This)->lpVtbl->ComputeGlyphOrigins_(This,run,baseline_origin,origins) +#define IDWriteFactory4_ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins) (This)->lpVtbl->ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFactory4_QueryInterface(IDWriteFactory4* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFactory4_AddRef(IDWriteFactory4* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFactory4_Release(IDWriteFactory4* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFactory methods ***/ +static FORCEINLINE HRESULT IDWriteFactory4_CreateCustomFontCollection(IDWriteFactory4* This,IDWriteFontCollectionLoader *loader,const void *key,UINT32 key_size,IDWriteFontCollection **collection) { + return This->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection); +} +static FORCEINLINE HRESULT IDWriteFactory4_RegisterFontCollectionLoader(IDWriteFactory4* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->RegisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory4_UnregisterFontCollectionLoader(IDWriteFactory4* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->UnregisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateFontFileReference(IDWriteFactory4* This,const WCHAR *path,const FILETIME *writetime,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateFontFileReference(This,path,writetime,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateCustomFontFileReference(IDWriteFactory4* This,const void *reference_key,UINT32 key_size,IDWriteFontFileLoader *loader,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateFontFace(IDWriteFactory4* This,DWRITE_FONT_FACE_TYPE facetype,UINT32 files_number,IDWriteFontFile *const *font_files,UINT32 index,DWRITE_FONT_SIMULATIONS sim_flags,IDWriteFontFace **font_face) { + return This->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateRenderingParams(IDWriteFactory4* This,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateRenderingParams(This,params); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateMonitorRenderingParams(IDWriteFactory4* This,HMONITOR monitor,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateMonitorRenderingParams(This,monitor,params); +} +static FORCEINLINE HRESULT IDWriteFactory4_RegisterFontFileLoader(IDWriteFactory4* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->RegisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory4_UnregisterFontFileLoader(IDWriteFactory4* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->UnregisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateTextFormat(IDWriteFactory4* This,const WCHAR *family_name,IDWriteFontCollection *collection,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STYLE style,DWRITE_FONT_STRETCH stretch,FLOAT size,const WCHAR *locale,IDWriteTextFormat **format) { + return This->lpVtbl->CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateTypography(IDWriteFactory4* This,IDWriteTypography **typography) { + return This->lpVtbl->CreateTypography(This,typography); +} +static FORCEINLINE HRESULT IDWriteFactory4_GetGdiInterop(IDWriteFactory4* This,IDWriteGdiInterop **gdi_interop) { + return This->lpVtbl->GetGdiInterop(This,gdi_interop); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateTextLayout(IDWriteFactory4* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT max_width,FLOAT max_height,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateGdiCompatibleTextLayout(IDWriteFactory4* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT layout_width,FLOAT layout_height,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateEllipsisTrimmingSign(IDWriteFactory4* This,IDWriteTextFormat *format,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateTextAnalyzer(IDWriteFactory4* This,IDWriteTextAnalyzer **analyzer) { + return This->lpVtbl->CreateTextAnalyzer(This,analyzer); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateNumberSubstitution(IDWriteFactory4* This,DWRITE_NUMBER_SUBSTITUTION_METHOD method,const WCHAR *locale,WINBOOL ignore_user_override,IDWriteNumberSubstitution **substitution) { + return This->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution); +} +/*** IDWriteFactory1 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory4_GetEudcFontCollection(IDWriteFactory4* This,IDWriteFontCollection **collection,WINBOOL check_for_updates) { + return This->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates); +} +/*** IDWriteFactory2 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory4_GetSystemFontFallback(IDWriteFactory4* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetSystemFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateFontFallbackBuilder(IDWriteFactory4* This,IDWriteFontFallbackBuilder **fallbackbuilder) { + return This->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder); +} +/*** IDWriteFactory3 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory4_CreateGlyphRunAnalysis(IDWriteFactory4* This,const DWRITE_GLYPH_RUN *run,const DWRITE_MATRIX *transform,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_MEASURING_MODE measuring_mode,DWRITE_GRID_FIT_MODE gridfit_mode,DWRITE_TEXT_ANTIALIAS_MODE antialias_mode,FLOAT origin_x,FLOAT origin_y,IDWriteGlyphRunAnalysis **analysis) { + return This->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateCustomRenderingParams(IDWriteFactory4* This,FLOAT gamma,FLOAT enhanced_contrast,FLOAT grayscale_enhanced_contrast,FLOAT cleartype_level,DWRITE_PIXEL_GEOMETRY pixel_geometry,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_GRID_FIT_MODE gridfit_mode,IDWriteRenderingParams3 **params) { + return This->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateFontFaceReference_(IDWriteFactory4* This,IDWriteFontFile *file,UINT32 index,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFaceReference **reference) { + return This->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateFontFaceReference(IDWriteFactory4* This,const WCHAR *path,const FILETIME *writetime,UINT32 index,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFaceReference **reference) { + return This->lpVtbl->CreateFontFaceReference(This,path,writetime,index,simulations,reference); +} +static FORCEINLINE HRESULT IDWriteFactory4_GetSystemFontSet(IDWriteFactory4* This,IDWriteFontSet **fontset) { + return This->lpVtbl->GetSystemFontSet(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateFontSetBuilder(IDWriteFactory4* This,IDWriteFontSetBuilder **builder) { + return This->lpVtbl->CreateFontSetBuilder(This,builder); +} +static FORCEINLINE HRESULT IDWriteFactory4_CreateFontCollectionFromFontSet(IDWriteFactory4* This,IDWriteFontSet *fontset,IDWriteFontCollection1 **collection) { + return This->lpVtbl->CreateFontCollectionFromFontSet(This,fontset,collection); +} +static FORCEINLINE HRESULT IDWriteFactory4_GetSystemFontCollection(IDWriteFactory4* This,WINBOOL include_downloadable,IDWriteFontCollection1 **collection,WINBOOL check_for_updates) { + return This->lpVtbl->IDWriteFactory3_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates); +} +static FORCEINLINE HRESULT IDWriteFactory4_GetFontDownloadQueue(IDWriteFactory4* This,IDWriteFontDownloadQueue **queue) { + return This->lpVtbl->GetFontDownloadQueue(This,queue); +} +/*** IDWriteFactory4 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory4_TranslateColorGlyphRun(IDWriteFactory4* This,D2D1_POINT_2F baseline_origin,const DWRITE_GLYPH_RUN *run,const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc,DWRITE_GLYPH_IMAGE_FORMATS desired_formats,DWRITE_MEASURING_MODE measuring_mode,const DWRITE_MATRIX *transform,UINT32 palette,IDWriteColorGlyphRunEnumerator1 **layers) { + return This->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers); +} +static FORCEINLINE HRESULT IDWriteFactory4_ComputeGlyphOrigins_(IDWriteFactory4* This,const DWRITE_GLYPH_RUN *run,D2D1_POINT_2F baseline_origin,D2D1_POINT_2F *origins) { + return This->lpVtbl->ComputeGlyphOrigins_(This,run,baseline_origin,origins); +} +static FORCEINLINE HRESULT IDWriteFactory4_ComputeGlyphOrigins(IDWriteFactory4* This,const DWRITE_GLYPH_RUN *run,DWRITE_MEASURING_MODE measuring_mode,D2D1_POINT_2F baseline_origin,const DWRITE_MATRIX *transform,D2D1_POINT_2F *origins) { + return This->lpVtbl->ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFactory4_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteAsyncResult interface + */ +#ifndef __IDWriteAsyncResult_INTERFACE_DEFINED__ +#define __IDWriteAsyncResult_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteAsyncResult, 0xce25f8fd, 0x863b, 0x4d13, 0x96,0x51, 0xc1,0xf8,0x8d,0xc7,0x3f,0xe2); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("ce25f8fd-863b-4d13-9651-c1f88dc73fe2") +IDWriteAsyncResult : public IUnknown +{ + virtual HANDLE STDMETHODCALLTYPE GetWaitHandle( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetResult( + ) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteAsyncResult, 0xce25f8fd, 0x863b, 0x4d13, 0x96,0x51, 0xc1,0xf8,0x8d,0xc7,0x3f,0xe2) +#endif +#else +typedef struct IDWriteAsyncResultVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteAsyncResult *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteAsyncResult *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteAsyncResult *This); + + /*** IDWriteAsyncResult methods ***/ + HANDLE (STDMETHODCALLTYPE *GetWaitHandle)( + IDWriteAsyncResult *This); + + HRESULT (STDMETHODCALLTYPE *GetResult)( + IDWriteAsyncResult *This); + + END_INTERFACE +} IDWriteAsyncResultVtbl; + +interface IDWriteAsyncResult { + CONST_VTBL IDWriteAsyncResultVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteAsyncResult_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteAsyncResult_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteAsyncResult_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteAsyncResult methods ***/ +#define IDWriteAsyncResult_GetWaitHandle(This) (This)->lpVtbl->GetWaitHandle(This) +#define IDWriteAsyncResult_GetResult(This) (This)->lpVtbl->GetResult(This) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteAsyncResult_QueryInterface(IDWriteAsyncResult* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteAsyncResult_AddRef(IDWriteAsyncResult* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteAsyncResult_Release(IDWriteAsyncResult* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteAsyncResult methods ***/ +static FORCEINLINE HANDLE IDWriteAsyncResult_GetWaitHandle(IDWriteAsyncResult* This) { + return This->lpVtbl->GetWaitHandle(This); +} +static FORCEINLINE HRESULT IDWriteAsyncResult_GetResult(IDWriteAsyncResult* This) { + return This->lpVtbl->GetResult(This); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteAsyncResult_INTERFACE_DEFINED__ */ + +typedef struct DWRITE_FILE_FRAGMENT { + UINT64 fileOffset; + UINT64 fragmentSize; +} DWRITE_FILE_FRAGMENT; +/***************************************************************************** + * IDWriteRemoteFontFileStream interface + */ +#ifndef __IDWriteRemoteFontFileStream_INTERFACE_DEFINED__ +#define __IDWriteRemoteFontFileStream_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteRemoteFontFileStream, 0x4db3757a, 0x2c72, 0x4ed9, 0xb2,0xb6, 0x1a,0xba,0xbe,0x1a,0xff,0x9c); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("4db3757a-2c72-4ed9-b2b6-1ababe1aff9c") +IDWriteRemoteFontFileStream : public IDWriteFontFileStream +{ + virtual HRESULT STDMETHODCALLTYPE GetLocalFileSize( + UINT64 *size) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFileFragmentLocality( + UINT64 offset, + UINT64 size, + WINBOOL *is_local, + UINT64 *partial_size) = 0; + + virtual DWRITE_LOCALITY STDMETHODCALLTYPE GetLocality( + ) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginDownload( + const GUID *operation_id, + const DWRITE_FILE_FRAGMENT *fragments, + UINT32 fragment_count, + IDWriteAsyncResult **async_result) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteRemoteFontFileStream, 0x4db3757a, 0x2c72, 0x4ed9, 0xb2,0xb6, 0x1a,0xba,0xbe,0x1a,0xff,0x9c) +#endif +#else +typedef struct IDWriteRemoteFontFileStreamVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteRemoteFontFileStream *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteRemoteFontFileStream *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteRemoteFontFileStream *This); + + /*** IDWriteFontFileStream methods ***/ + HRESULT (STDMETHODCALLTYPE *ReadFileFragment)( + IDWriteRemoteFontFileStream *This, + const void **fragment_start, + UINT64 offset, + UINT64 fragment_size, + void **fragment_context); + + void (STDMETHODCALLTYPE *ReleaseFileFragment)( + IDWriteRemoteFontFileStream *This, + void *fragment_context); + + HRESULT (STDMETHODCALLTYPE *GetFileSize)( + IDWriteRemoteFontFileStream *This, + UINT64 *size); + + HRESULT (STDMETHODCALLTYPE *GetLastWriteTime)( + IDWriteRemoteFontFileStream *This, + UINT64 *last_writetime); + + /*** IDWriteRemoteFontFileStream methods ***/ + HRESULT (STDMETHODCALLTYPE *GetLocalFileSize)( + IDWriteRemoteFontFileStream *This, + UINT64 *size); + + HRESULT (STDMETHODCALLTYPE *GetFileFragmentLocality)( + IDWriteRemoteFontFileStream *This, + UINT64 offset, + UINT64 size, + WINBOOL *is_local, + UINT64 *partial_size); + + DWRITE_LOCALITY (STDMETHODCALLTYPE *GetLocality)( + IDWriteRemoteFontFileStream *This); + + HRESULT (STDMETHODCALLTYPE *BeginDownload)( + IDWriteRemoteFontFileStream *This, + const GUID *operation_id, + const DWRITE_FILE_FRAGMENT *fragments, + UINT32 fragment_count, + IDWriteAsyncResult **async_result); + + END_INTERFACE +} IDWriteRemoteFontFileStreamVtbl; + +interface IDWriteRemoteFontFileStream { + CONST_VTBL IDWriteRemoteFontFileStreamVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteRemoteFontFileStream_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteRemoteFontFileStream_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteRemoteFontFileStream_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFileStream methods ***/ +#define IDWriteRemoteFontFileStream_ReadFileFragment(This,fragment_start,offset,fragment_size,fragment_context) (This)->lpVtbl->ReadFileFragment(This,fragment_start,offset,fragment_size,fragment_context) +#define IDWriteRemoteFontFileStream_ReleaseFileFragment(This,fragment_context) (This)->lpVtbl->ReleaseFileFragment(This,fragment_context) +#define IDWriteRemoteFontFileStream_GetFileSize(This,size) (This)->lpVtbl->GetFileSize(This,size) +#define IDWriteRemoteFontFileStream_GetLastWriteTime(This,last_writetime) (This)->lpVtbl->GetLastWriteTime(This,last_writetime) +/*** IDWriteRemoteFontFileStream methods ***/ +#define IDWriteRemoteFontFileStream_GetLocalFileSize(This,size) (This)->lpVtbl->GetLocalFileSize(This,size) +#define IDWriteRemoteFontFileStream_GetFileFragmentLocality(This,offset,size,is_local,partial_size) (This)->lpVtbl->GetFileFragmentLocality(This,offset,size,is_local,partial_size) +#define IDWriteRemoteFontFileStream_GetLocality(This) (This)->lpVtbl->GetLocality(This) +#define IDWriteRemoteFontFileStream_BeginDownload(This,operation_id,fragments,fragment_count,async_result) (This)->lpVtbl->BeginDownload(This,operation_id,fragments,fragment_count,async_result) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteRemoteFontFileStream_QueryInterface(IDWriteRemoteFontFileStream* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteRemoteFontFileStream_AddRef(IDWriteRemoteFontFileStream* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteRemoteFontFileStream_Release(IDWriteRemoteFontFileStream* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFileStream methods ***/ +static FORCEINLINE HRESULT IDWriteRemoteFontFileStream_ReadFileFragment(IDWriteRemoteFontFileStream* This,const void **fragment_start,UINT64 offset,UINT64 fragment_size,void **fragment_context) { + return This->lpVtbl->ReadFileFragment(This,fragment_start,offset,fragment_size,fragment_context); +} +static FORCEINLINE void IDWriteRemoteFontFileStream_ReleaseFileFragment(IDWriteRemoteFontFileStream* This,void *fragment_context) { + This->lpVtbl->ReleaseFileFragment(This,fragment_context); +} +static FORCEINLINE HRESULT IDWriteRemoteFontFileStream_GetFileSize(IDWriteRemoteFontFileStream* This,UINT64 *size) { + return This->lpVtbl->GetFileSize(This,size); +} +static FORCEINLINE HRESULT IDWriteRemoteFontFileStream_GetLastWriteTime(IDWriteRemoteFontFileStream* This,UINT64 *last_writetime) { + return This->lpVtbl->GetLastWriteTime(This,last_writetime); +} +/*** IDWriteRemoteFontFileStream methods ***/ +static FORCEINLINE HRESULT IDWriteRemoteFontFileStream_GetLocalFileSize(IDWriteRemoteFontFileStream* This,UINT64 *size) { + return This->lpVtbl->GetLocalFileSize(This,size); +} +static FORCEINLINE HRESULT IDWriteRemoteFontFileStream_GetFileFragmentLocality(IDWriteRemoteFontFileStream* This,UINT64 offset,UINT64 size,WINBOOL *is_local,UINT64 *partial_size) { + return This->lpVtbl->GetFileFragmentLocality(This,offset,size,is_local,partial_size); +} +static FORCEINLINE DWRITE_LOCALITY IDWriteRemoteFontFileStream_GetLocality(IDWriteRemoteFontFileStream* This) { + return This->lpVtbl->GetLocality(This); +} +static FORCEINLINE HRESULT IDWriteRemoteFontFileStream_BeginDownload(IDWriteRemoteFontFileStream* This,const GUID *operation_id,const DWRITE_FILE_FRAGMENT *fragments,UINT32 fragment_count,IDWriteAsyncResult **async_result) { + return This->lpVtbl->BeginDownload(This,operation_id,fragments,fragment_count,async_result); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteRemoteFontFileStream_INTERFACE_DEFINED__ */ + +typedef enum DWRITE_CONTAINER_TYPE { + DWRITE_CONTAINER_TYPE_UNKNOWN = 0, + DWRITE_CONTAINER_TYPE_WOFF = 1, + DWRITE_CONTAINER_TYPE_WOFF2 = 2 +} DWRITE_CONTAINER_TYPE; +/***************************************************************************** + * IDWriteRemoteFontFileLoader interface + */ +#ifndef __IDWriteRemoteFontFileLoader_INTERFACE_DEFINED__ +#define __IDWriteRemoteFontFileLoader_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteRemoteFontFileLoader, 0x68648c83, 0x6ede, 0x46c0, 0xab,0x46, 0x20,0x08,0x3a,0x88,0x7f,0xde); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("68648c83-6ede-46c0-ab46-20083a887fde") +IDWriteRemoteFontFileLoader : public IDWriteFontFileLoader +{ + virtual HRESULT STDMETHODCALLTYPE CreateRemoteStreamFromKey( + const void *key, + UINT32 key_size, + IDWriteRemoteFontFileStream **stream) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetLocalityFromKey( + const void *key, + UINT32 key_size, + DWRITE_LOCALITY *locality) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateFontFileReferenceFromUrl( + IDWriteFactory *factory, + const WCHAR *base_url, + const WCHAR *file_url, + IDWriteFontFile **fontfile) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteRemoteFontFileLoader, 0x68648c83, 0x6ede, 0x46c0, 0xab,0x46, 0x20,0x08,0x3a,0x88,0x7f,0xde) +#endif +#else +typedef struct IDWriteRemoteFontFileLoaderVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteRemoteFontFileLoader *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteRemoteFontFileLoader *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteRemoteFontFileLoader *This); + + /*** IDWriteFontFileLoader methods ***/ + HRESULT (STDMETHODCALLTYPE *CreateStreamFromKey)( + IDWriteRemoteFontFileLoader *This, + const void *key, + UINT32 key_size, + IDWriteFontFileStream **stream); + + /*** IDWriteRemoteFontFileLoader methods ***/ + HRESULT (STDMETHODCALLTYPE *CreateRemoteStreamFromKey)( + IDWriteRemoteFontFileLoader *This, + const void *key, + UINT32 key_size, + IDWriteRemoteFontFileStream **stream); + + HRESULT (STDMETHODCALLTYPE *GetLocalityFromKey)( + IDWriteRemoteFontFileLoader *This, + const void *key, + UINT32 key_size, + DWRITE_LOCALITY *locality); + + HRESULT (STDMETHODCALLTYPE *CreateFontFileReferenceFromUrl)( + IDWriteRemoteFontFileLoader *This, + IDWriteFactory *factory, + const WCHAR *base_url, + const WCHAR *file_url, + IDWriteFontFile **fontfile); + + END_INTERFACE +} IDWriteRemoteFontFileLoaderVtbl; + +interface IDWriteRemoteFontFileLoader { + CONST_VTBL IDWriteRemoteFontFileLoaderVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteRemoteFontFileLoader_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteRemoteFontFileLoader_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteRemoteFontFileLoader_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFileLoader methods ***/ +#define IDWriteRemoteFontFileLoader_CreateStreamFromKey(This,key,key_size,stream) (This)->lpVtbl->CreateStreamFromKey(This,key,key_size,stream) +/*** IDWriteRemoteFontFileLoader methods ***/ +#define IDWriteRemoteFontFileLoader_CreateRemoteStreamFromKey(This,key,key_size,stream) (This)->lpVtbl->CreateRemoteStreamFromKey(This,key,key_size,stream) +#define IDWriteRemoteFontFileLoader_GetLocalityFromKey(This,key,key_size,locality) (This)->lpVtbl->GetLocalityFromKey(This,key,key_size,locality) +#define IDWriteRemoteFontFileLoader_CreateFontFileReferenceFromUrl(This,factory,base_url,file_url,fontfile) (This)->lpVtbl->CreateFontFileReferenceFromUrl(This,factory,base_url,file_url,fontfile) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteRemoteFontFileLoader_QueryInterface(IDWriteRemoteFontFileLoader* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteRemoteFontFileLoader_AddRef(IDWriteRemoteFontFileLoader* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteRemoteFontFileLoader_Release(IDWriteRemoteFontFileLoader* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFileLoader methods ***/ +static FORCEINLINE HRESULT IDWriteRemoteFontFileLoader_CreateStreamFromKey(IDWriteRemoteFontFileLoader* This,const void *key,UINT32 key_size,IDWriteFontFileStream **stream) { + return This->lpVtbl->CreateStreamFromKey(This,key,key_size,stream); +} +/*** IDWriteRemoteFontFileLoader methods ***/ +static FORCEINLINE HRESULT IDWriteRemoteFontFileLoader_CreateRemoteStreamFromKey(IDWriteRemoteFontFileLoader* This,const void *key,UINT32 key_size,IDWriteRemoteFontFileStream **stream) { + return This->lpVtbl->CreateRemoteStreamFromKey(This,key,key_size,stream); +} +static FORCEINLINE HRESULT IDWriteRemoteFontFileLoader_GetLocalityFromKey(IDWriteRemoteFontFileLoader* This,const void *key,UINT32 key_size,DWRITE_LOCALITY *locality) { + return This->lpVtbl->GetLocalityFromKey(This,key,key_size,locality); +} +static FORCEINLINE HRESULT IDWriteRemoteFontFileLoader_CreateFontFileReferenceFromUrl(IDWriteRemoteFontFileLoader* This,IDWriteFactory *factory,const WCHAR *base_url,const WCHAR *file_url,IDWriteFontFile **fontfile) { + return This->lpVtbl->CreateFontFileReferenceFromUrl(This,factory,base_url,file_url,fontfile); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteRemoteFontFileLoader_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteInMemoryFontFileLoader interface + */ +#ifndef __IDWriteInMemoryFontFileLoader_INTERFACE_DEFINED__ +#define __IDWriteInMemoryFontFileLoader_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteInMemoryFontFileLoader, 0xdc102f47, 0xa12d, 0x4b1c, 0x82,0x2d, 0x9e,0x11,0x7e,0x33,0x04,0x3f); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("dc102f47-a12d-4b1c-822d-9e117e33043f") +IDWriteInMemoryFontFileLoader : public IDWriteFontFileLoader +{ + virtual HRESULT STDMETHODCALLTYPE CreateInMemoryFontFileReference( + IDWriteFactory *factory, + const void *data, + UINT32 data_size, + IUnknown *owner, + IDWriteFontFile **fontfile) = 0; + + virtual UINT32 STDMETHODCALLTYPE GetFileCount( + ) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteInMemoryFontFileLoader, 0xdc102f47, 0xa12d, 0x4b1c, 0x82,0x2d, 0x9e,0x11,0x7e,0x33,0x04,0x3f) +#endif +#else +typedef struct IDWriteInMemoryFontFileLoaderVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteInMemoryFontFileLoader *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteInMemoryFontFileLoader *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteInMemoryFontFileLoader *This); + + /*** IDWriteFontFileLoader methods ***/ + HRESULT (STDMETHODCALLTYPE *CreateStreamFromKey)( + IDWriteInMemoryFontFileLoader *This, + const void *key, + UINT32 key_size, + IDWriteFontFileStream **stream); + + /*** IDWriteInMemoryFontFileLoader methods ***/ + HRESULT (STDMETHODCALLTYPE *CreateInMemoryFontFileReference)( + IDWriteInMemoryFontFileLoader *This, + IDWriteFactory *factory, + const void *data, + UINT32 data_size, + IUnknown *owner, + IDWriteFontFile **fontfile); + + UINT32 (STDMETHODCALLTYPE *GetFileCount)( + IDWriteInMemoryFontFileLoader *This); + + END_INTERFACE +} IDWriteInMemoryFontFileLoaderVtbl; + +interface IDWriteInMemoryFontFileLoader { + CONST_VTBL IDWriteInMemoryFontFileLoaderVtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteInMemoryFontFileLoader_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteInMemoryFontFileLoader_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteInMemoryFontFileLoader_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFontFileLoader methods ***/ +#define IDWriteInMemoryFontFileLoader_CreateStreamFromKey(This,key,key_size,stream) (This)->lpVtbl->CreateStreamFromKey(This,key,key_size,stream) +/*** IDWriteInMemoryFontFileLoader methods ***/ +#define IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(This,factory,data,data_size,owner,fontfile) (This)->lpVtbl->CreateInMemoryFontFileReference(This,factory,data,data_size,owner,fontfile) +#define IDWriteInMemoryFontFileLoader_GetFileCount(This) (This)->lpVtbl->GetFileCount(This) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteInMemoryFontFileLoader_QueryInterface(IDWriteInMemoryFontFileLoader* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteInMemoryFontFileLoader_AddRef(IDWriteInMemoryFontFileLoader* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteInMemoryFontFileLoader_Release(IDWriteInMemoryFontFileLoader* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFontFileLoader methods ***/ +static FORCEINLINE HRESULT IDWriteInMemoryFontFileLoader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader* This,const void *key,UINT32 key_size,IDWriteFontFileStream **stream) { + return This->lpVtbl->CreateStreamFromKey(This,key,key_size,stream); +} +/*** IDWriteInMemoryFontFileLoader methods ***/ +static FORCEINLINE HRESULT IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader* This,IDWriteFactory *factory,const void *data,UINT32 data_size,IUnknown *owner,IDWriteFontFile **fontfile) { + return This->lpVtbl->CreateInMemoryFontFileReference(This,factory,data,data_size,owner,fontfile); +} +static FORCEINLINE UINT32 IDWriteInMemoryFontFileLoader_GetFileCount(IDWriteInMemoryFontFileLoader* This) { + return This->lpVtbl->GetFileCount(This); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteInMemoryFontFileLoader_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFactory5 interface + */ +#ifndef __IDWriteFactory5_INTERFACE_DEFINED__ +#define __IDWriteFactory5_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFactory5, 0x958db99a, 0xbe2a, 0x4f09, 0xaf,0x7d, 0x65,0x18,0x98,0x03,0xd1,0xd3); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("958db99a-be2a-4f09-af7d-65189803d1d3") +IDWriteFactory5 : public IDWriteFactory4 +{ + virtual HRESULT STDMETHODCALLTYPE CreateFontSetBuilder( + IDWriteFontSetBuilder1 **fontset_builder) = 0; + + using IDWriteFactory3::CreateFontSetBuilder; + + virtual HRESULT STDMETHODCALLTYPE CreateInMemoryFontFileLoader( + IDWriteInMemoryFontFileLoader **loader) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateHttpFontFileLoader( + const WCHAR *referrer_url, + const WCHAR *extra_headers, + IDWriteRemoteFontFileLoader **loader) = 0; + + virtual DWRITE_CONTAINER_TYPE STDMETHODCALLTYPE AnalyzeContainerType( + const void *data, + UINT32 data_size) = 0; + + virtual HRESULT STDMETHODCALLTYPE UnpackFontFile( + DWRITE_CONTAINER_TYPE container_type, + const void *data, + UINT32 data_size, + IDWriteFontFileStream **stream) = 0; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFactory5, 0x958db99a, 0xbe2a, 0x4f09, 0xaf,0x7d, 0x65,0x18,0x98,0x03,0xd1,0xd3) +#endif +#else +typedef struct IDWriteFactory5Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFactory5 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFactory5 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFactory5 *This); + + /*** IDWriteFactory methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontCollection)( + IDWriteFactory5 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontCollection)( + IDWriteFactory5 *This, + IDWriteFontCollectionLoader *loader, + const void *key, + UINT32 key_size, + IDWriteFontCollection **collection); + + HRESULT (STDMETHODCALLTYPE *RegisterFontCollectionLoader)( + IDWriteFactory5 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontCollectionLoader)( + IDWriteFactory5 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateFontFileReference)( + IDWriteFactory5 *This, + const WCHAR *path, + const FILETIME *writetime, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontFileReference)( + IDWriteFactory5 *This, + const void *reference_key, + UINT32 key_size, + IDWriteFontFileLoader *loader, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFactory5 *This, + DWRITE_FONT_FACE_TYPE facetype, + UINT32 files_number, + IDWriteFontFile *const *font_files, + UINT32 index, + DWRITE_FONT_SIMULATIONS sim_flags, + IDWriteFontFace **font_face); + + HRESULT (STDMETHODCALLTYPE *CreateRenderingParams)( + IDWriteFactory5 *This, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateMonitorRenderingParams)( + IDWriteFactory5 *This, + HMONITOR monitor, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateCustomRenderingParams)( + IDWriteFactory5 *This, + FLOAT gamma, + FLOAT enhancedContrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *RegisterFontFileLoader)( + IDWriteFactory5 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontFileLoader)( + IDWriteFactory5 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateTextFormat)( + IDWriteFactory5 *This, + const WCHAR *family_name, + IDWriteFontCollection *collection, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STYLE style, + DWRITE_FONT_STRETCH stretch, + FLOAT size, + const WCHAR *locale, + IDWriteTextFormat **format); + + HRESULT (STDMETHODCALLTYPE *CreateTypography)( + IDWriteFactory5 *This, + IDWriteTypography **typography); + + HRESULT (STDMETHODCALLTYPE *GetGdiInterop)( + IDWriteFactory5 *This, + IDWriteGdiInterop **gdi_interop); + + HRESULT (STDMETHODCALLTYPE *CreateTextLayout)( + IDWriteFactory5 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT max_width, + FLOAT max_height, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateGdiCompatibleTextLayout)( + IDWriteFactory5 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT layout_width, + FLOAT layout_height, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateEllipsisTrimmingSign)( + IDWriteFactory5 *This, + IDWriteTextFormat *format, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *CreateTextAnalyzer)( + IDWriteFactory5 *This, + IDWriteTextAnalyzer **analyzer); + + HRESULT (STDMETHODCALLTYPE *CreateNumberSubstitution)( + IDWriteFactory5 *This, + DWRITE_NUMBER_SUBSTITUTION_METHOD method, + const WCHAR *locale, + WINBOOL ignore_user_override, + IDWriteNumberSubstitution **substitution); + + HRESULT (STDMETHODCALLTYPE *CreateGlyphRunAnalysis)( + IDWriteFactory5 *This, + const DWRITE_GLYPH_RUN *glyph_run, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + FLOAT baseline_x, + FLOAT baseline_y, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory1 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetEudcFontCollection)( + IDWriteFactory5 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory1_CreateCustomRenderingParams)( + IDWriteFactory5 *This, + FLOAT gamma, + FLOAT enhcontrast, + FLOAT enhcontrast_grayscale, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams1 **params); + + /*** IDWriteFactory2 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontFallback)( + IDWriteFactory5 *This, + IDWriteFontFallback **fallback); + + HRESULT (STDMETHODCALLTYPE *CreateFontFallbackBuilder)( + IDWriteFactory5 *This, + IDWriteFontFallbackBuilder **fallbackbuilder); + + HRESULT (STDMETHODCALLTYPE *TranslateColorGlyphRun)( + IDWriteFactory5 *This, + FLOAT originX, + FLOAT originY, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, + DWRITE_MEASURING_MODE mode, + const DWRITE_MATRIX *transform, + UINT32 palette_index, + IDWriteColorGlyphRunEnumerator **colorlayers); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateCustomRenderingParams)( + IDWriteFactory5 *This, + FLOAT gamma, + FLOAT contrast, + FLOAT grayscalecontrast, + FLOAT cleartypeLevel, + DWRITE_PIXEL_GEOMETRY pixelGeometry, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_GRID_FIT_MODE gridFitMode, + IDWriteRenderingParams2 **params); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateGlyphRunAnalysis)( + IDWriteFactory5 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GRID_FIT_MODE gridFitMode, + DWRITE_TEXT_ANTIALIAS_MODE antialiasMode, + FLOAT originX, + FLOAT originY, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory3 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateGlyphRunAnalysis)( + IDWriteFactory5 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + DWRITE_TEXT_ANTIALIAS_MODE antialias_mode, + FLOAT origin_x, + FLOAT origin_y, + IDWriteGlyphRunAnalysis **analysis); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateCustomRenderingParams)( + IDWriteFactory5 *This, + FLOAT gamma, + FLOAT enhanced_contrast, + FLOAT grayscale_enhanced_contrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY pixel_geometry, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + IDWriteRenderingParams3 **params); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference_)( + IDWriteFactory5 *This, + IDWriteFontFile *file, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference)( + IDWriteFactory5 *This, + const WCHAR *path, + const FILETIME *writetime, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *GetSystemFontSet)( + IDWriteFactory5 *This, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *CreateFontSetBuilder)( + IDWriteFactory5 *This, + IDWriteFontSetBuilder **builder); + + HRESULT (STDMETHODCALLTYPE *CreateFontCollectionFromFontSet)( + IDWriteFactory5 *This, + IDWriteFontSet *fontset, + IDWriteFontCollection1 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_GetSystemFontCollection)( + IDWriteFactory5 *This, + WINBOOL include_downloadable, + IDWriteFontCollection1 **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *GetFontDownloadQueue)( + IDWriteFactory5 *This, + IDWriteFontDownloadQueue **queue); + + /*** IDWriteFactory4 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory4_TranslateColorGlyphRun)( + IDWriteFactory5 *This, + D2D1_POINT_2F baseline_origin, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc, + DWRITE_GLYPH_IMAGE_FORMATS desired_formats, + DWRITE_MEASURING_MODE measuring_mode, + const DWRITE_MATRIX *transform, + UINT32 palette, + IDWriteColorGlyphRunEnumerator1 **layers); + + HRESULT (STDMETHODCALLTYPE *ComputeGlyphOrigins_)( + IDWriteFactory5 *This, + const DWRITE_GLYPH_RUN *run, + D2D1_POINT_2F baseline_origin, + D2D1_POINT_2F *origins); + + HRESULT (STDMETHODCALLTYPE *ComputeGlyphOrigins)( + IDWriteFactory5 *This, + const DWRITE_GLYPH_RUN *run, + DWRITE_MEASURING_MODE measuring_mode, + D2D1_POINT_2F baseline_origin, + const DWRITE_MATRIX *transform, + D2D1_POINT_2F *origins); + + /*** IDWriteFactory5 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory5_CreateFontSetBuilder)( + IDWriteFactory5 *This, + IDWriteFontSetBuilder1 **fontset_builder); + + HRESULT (STDMETHODCALLTYPE *CreateInMemoryFontFileLoader)( + IDWriteFactory5 *This, + IDWriteInMemoryFontFileLoader **loader); + + HRESULT (STDMETHODCALLTYPE *CreateHttpFontFileLoader)( + IDWriteFactory5 *This, + const WCHAR *referrer_url, + const WCHAR *extra_headers, + IDWriteRemoteFontFileLoader **loader); + + DWRITE_CONTAINER_TYPE (STDMETHODCALLTYPE *AnalyzeContainerType)( + IDWriteFactory5 *This, + const void *data, + UINT32 data_size); + + HRESULT (STDMETHODCALLTYPE *UnpackFontFile)( + IDWriteFactory5 *This, + DWRITE_CONTAINER_TYPE container_type, + const void *data, + UINT32 data_size, + IDWriteFontFileStream **stream); + + END_INTERFACE +} IDWriteFactory5Vtbl; + +interface IDWriteFactory5 { + CONST_VTBL IDWriteFactory5Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFactory5_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFactory5_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFactory5_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFactory methods ***/ +#define IDWriteFactory5_CreateCustomFontCollection(This,loader,key,key_size,collection) (This)->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection) +#define IDWriteFactory5_RegisterFontCollectionLoader(This,loader) (This)->lpVtbl->RegisterFontCollectionLoader(This,loader) +#define IDWriteFactory5_UnregisterFontCollectionLoader(This,loader) (This)->lpVtbl->UnregisterFontCollectionLoader(This,loader) +#define IDWriteFactory5_CreateFontFileReference(This,path,writetime,font_file) (This)->lpVtbl->CreateFontFileReference(This,path,writetime,font_file) +#define IDWriteFactory5_CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) (This)->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) +#define IDWriteFactory5_CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) (This)->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) +#define IDWriteFactory5_CreateRenderingParams(This,params) (This)->lpVtbl->CreateRenderingParams(This,params) +#define IDWriteFactory5_CreateMonitorRenderingParams(This,monitor,params) (This)->lpVtbl->CreateMonitorRenderingParams(This,monitor,params) +#define IDWriteFactory5_RegisterFontFileLoader(This,loader) (This)->lpVtbl->RegisterFontFileLoader(This,loader) +#define IDWriteFactory5_UnregisterFontFileLoader(This,loader) (This)->lpVtbl->UnregisterFontFileLoader(This,loader) +#define IDWriteFactory5_CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format) (This)->lpVtbl->CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format) +#define IDWriteFactory5_CreateTypography(This,typography) (This)->lpVtbl->CreateTypography(This,typography) +#define IDWriteFactory5_GetGdiInterop(This,gdi_interop) (This)->lpVtbl->GetGdiInterop(This,gdi_interop) +#define IDWriteFactory5_CreateTextLayout(This,string,len,format,max_width,max_height,layout) (This)->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout) +#define IDWriteFactory5_CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) (This)->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) +#define IDWriteFactory5_CreateEllipsisTrimmingSign(This,format,trimming_sign) (This)->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign) +#define IDWriteFactory5_CreateTextAnalyzer(This,analyzer) (This)->lpVtbl->CreateTextAnalyzer(This,analyzer) +#define IDWriteFactory5_CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) (This)->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) +/*** IDWriteFactory1 methods ***/ +#define IDWriteFactory5_GetEudcFontCollection(This,collection,check_for_updates) (This)->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates) +/*** IDWriteFactory2 methods ***/ +#define IDWriteFactory5_GetSystemFontFallback(This,fallback) (This)->lpVtbl->GetSystemFontFallback(This,fallback) +#define IDWriteFactory5_CreateFontFallbackBuilder(This,fallbackbuilder) (This)->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder) +/*** IDWriteFactory3 methods ***/ +#define IDWriteFactory5_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) (This)->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) +#define IDWriteFactory5_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) (This)->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) +#define IDWriteFactory5_CreateFontFaceReference_(This,file,index,simulations,reference) (This)->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference) +#define IDWriteFactory5_CreateFontFaceReference(This,path,writetime,index,simulations,reference) (This)->lpVtbl->CreateFontFaceReference(This,path,writetime,index,simulations,reference) +#define IDWriteFactory5_GetSystemFontSet(This,fontset) (This)->lpVtbl->GetSystemFontSet(This,fontset) +#define IDWriteFactory5_CreateFontCollectionFromFontSet(This,fontset,collection) (This)->lpVtbl->CreateFontCollectionFromFontSet(This,fontset,collection) +#define IDWriteFactory5_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates) (This)->lpVtbl->IDWriteFactory3_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates) +#define IDWriteFactory5_GetFontDownloadQueue(This,queue) (This)->lpVtbl->GetFontDownloadQueue(This,queue) +/*** IDWriteFactory4 methods ***/ +#define IDWriteFactory5_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers) (This)->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers) +#define IDWriteFactory5_ComputeGlyphOrigins_(This,run,baseline_origin,origins) (This)->lpVtbl->ComputeGlyphOrigins_(This,run,baseline_origin,origins) +#define IDWriteFactory5_ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins) (This)->lpVtbl->ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins) +/*** IDWriteFactory5 methods ***/ +#define IDWriteFactory5_CreateFontSetBuilder(This,fontset_builder) (This)->lpVtbl->IDWriteFactory5_CreateFontSetBuilder(This,fontset_builder) +#define IDWriteFactory5_CreateInMemoryFontFileLoader(This,loader) (This)->lpVtbl->CreateInMemoryFontFileLoader(This,loader) +#define IDWriteFactory5_CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader) (This)->lpVtbl->CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader) +#define IDWriteFactory5_AnalyzeContainerType(This,data,data_size) (This)->lpVtbl->AnalyzeContainerType(This,data,data_size) +#define IDWriteFactory5_UnpackFontFile(This,container_type,data,data_size,stream) (This)->lpVtbl->UnpackFontFile(This,container_type,data,data_size,stream) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFactory5_QueryInterface(IDWriteFactory5* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFactory5_AddRef(IDWriteFactory5* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFactory5_Release(IDWriteFactory5* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFactory methods ***/ +static FORCEINLINE HRESULT IDWriteFactory5_CreateCustomFontCollection(IDWriteFactory5* This,IDWriteFontCollectionLoader *loader,const void *key,UINT32 key_size,IDWriteFontCollection **collection) { + return This->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection); +} +static FORCEINLINE HRESULT IDWriteFactory5_RegisterFontCollectionLoader(IDWriteFactory5* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->RegisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory5_UnregisterFontCollectionLoader(IDWriteFactory5* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->UnregisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateFontFileReference(IDWriteFactory5* This,const WCHAR *path,const FILETIME *writetime,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateFontFileReference(This,path,writetime,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateCustomFontFileReference(IDWriteFactory5* This,const void *reference_key,UINT32 key_size,IDWriteFontFileLoader *loader,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateFontFace(IDWriteFactory5* This,DWRITE_FONT_FACE_TYPE facetype,UINT32 files_number,IDWriteFontFile *const *font_files,UINT32 index,DWRITE_FONT_SIMULATIONS sim_flags,IDWriteFontFace **font_face) { + return This->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateRenderingParams(IDWriteFactory5* This,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateRenderingParams(This,params); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateMonitorRenderingParams(IDWriteFactory5* This,HMONITOR monitor,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateMonitorRenderingParams(This,monitor,params); +} +static FORCEINLINE HRESULT IDWriteFactory5_RegisterFontFileLoader(IDWriteFactory5* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->RegisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory5_UnregisterFontFileLoader(IDWriteFactory5* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->UnregisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateTextFormat(IDWriteFactory5* This,const WCHAR *family_name,IDWriteFontCollection *collection,DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STYLE style,DWRITE_FONT_STRETCH stretch,FLOAT size,const WCHAR *locale,IDWriteTextFormat **format) { + return This->lpVtbl->CreateTextFormat(This,family_name,collection,weight,style,stretch,size,locale,format); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateTypography(IDWriteFactory5* This,IDWriteTypography **typography) { + return This->lpVtbl->CreateTypography(This,typography); +} +static FORCEINLINE HRESULT IDWriteFactory5_GetGdiInterop(IDWriteFactory5* This,IDWriteGdiInterop **gdi_interop) { + return This->lpVtbl->GetGdiInterop(This,gdi_interop); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateTextLayout(IDWriteFactory5* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT max_width,FLOAT max_height,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateGdiCompatibleTextLayout(IDWriteFactory5* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT layout_width,FLOAT layout_height,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateEllipsisTrimmingSign(IDWriteFactory5* This,IDWriteTextFormat *format,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateTextAnalyzer(IDWriteFactory5* This,IDWriteTextAnalyzer **analyzer) { + return This->lpVtbl->CreateTextAnalyzer(This,analyzer); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateNumberSubstitution(IDWriteFactory5* This,DWRITE_NUMBER_SUBSTITUTION_METHOD method,const WCHAR *locale,WINBOOL ignore_user_override,IDWriteNumberSubstitution **substitution) { + return This->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution); +} +/*** IDWriteFactory1 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory5_GetEudcFontCollection(IDWriteFactory5* This,IDWriteFontCollection **collection,WINBOOL check_for_updates) { + return This->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates); +} +/*** IDWriteFactory2 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory5_GetSystemFontFallback(IDWriteFactory5* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetSystemFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateFontFallbackBuilder(IDWriteFactory5* This,IDWriteFontFallbackBuilder **fallbackbuilder) { + return This->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder); +} +/*** IDWriteFactory3 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory5_CreateGlyphRunAnalysis(IDWriteFactory5* This,const DWRITE_GLYPH_RUN *run,const DWRITE_MATRIX *transform,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_MEASURING_MODE measuring_mode,DWRITE_GRID_FIT_MODE gridfit_mode,DWRITE_TEXT_ANTIALIAS_MODE antialias_mode,FLOAT origin_x,FLOAT origin_y,IDWriteGlyphRunAnalysis **analysis) { + return This->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateCustomRenderingParams(IDWriteFactory5* This,FLOAT gamma,FLOAT enhanced_contrast,FLOAT grayscale_enhanced_contrast,FLOAT cleartype_level,DWRITE_PIXEL_GEOMETRY pixel_geometry,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_GRID_FIT_MODE gridfit_mode,IDWriteRenderingParams3 **params) { + return This->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateFontFaceReference_(IDWriteFactory5* This,IDWriteFontFile *file,UINT32 index,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFaceReference **reference) { + return This->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateFontFaceReference(IDWriteFactory5* This,const WCHAR *path,const FILETIME *writetime,UINT32 index,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFaceReference **reference) { + return This->lpVtbl->CreateFontFaceReference(This,path,writetime,index,simulations,reference); +} +static FORCEINLINE HRESULT IDWriteFactory5_GetSystemFontSet(IDWriteFactory5* This,IDWriteFontSet **fontset) { + return This->lpVtbl->GetSystemFontSet(This,fontset); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateFontCollectionFromFontSet(IDWriteFactory5* This,IDWriteFontSet *fontset,IDWriteFontCollection1 **collection) { + return This->lpVtbl->CreateFontCollectionFromFontSet(This,fontset,collection); +} +static FORCEINLINE HRESULT IDWriteFactory5_GetSystemFontCollection(IDWriteFactory5* This,WINBOOL include_downloadable,IDWriteFontCollection1 **collection,WINBOOL check_for_updates) { + return This->lpVtbl->IDWriteFactory3_GetSystemFontCollection(This,include_downloadable,collection,check_for_updates); +} +static FORCEINLINE HRESULT IDWriteFactory5_GetFontDownloadQueue(IDWriteFactory5* This,IDWriteFontDownloadQueue **queue) { + return This->lpVtbl->GetFontDownloadQueue(This,queue); +} +/*** IDWriteFactory4 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory5_TranslateColorGlyphRun(IDWriteFactory5* This,D2D1_POINT_2F baseline_origin,const DWRITE_GLYPH_RUN *run,const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc,DWRITE_GLYPH_IMAGE_FORMATS desired_formats,DWRITE_MEASURING_MODE measuring_mode,const DWRITE_MATRIX *transform,UINT32 palette,IDWriteColorGlyphRunEnumerator1 **layers) { + return This->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers); +} +static FORCEINLINE HRESULT IDWriteFactory5_ComputeGlyphOrigins_(IDWriteFactory5* This,const DWRITE_GLYPH_RUN *run,D2D1_POINT_2F baseline_origin,D2D1_POINT_2F *origins) { + return This->lpVtbl->ComputeGlyphOrigins_(This,run,baseline_origin,origins); +} +static FORCEINLINE HRESULT IDWriteFactory5_ComputeGlyphOrigins(IDWriteFactory5* This,const DWRITE_GLYPH_RUN *run,DWRITE_MEASURING_MODE measuring_mode,D2D1_POINT_2F baseline_origin,const DWRITE_MATRIX *transform,D2D1_POINT_2F *origins) { + return This->lpVtbl->ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins); +} +/*** IDWriteFactory5 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory5_CreateFontSetBuilder(IDWriteFactory5* This,IDWriteFontSetBuilder1 **fontset_builder) { + return This->lpVtbl->IDWriteFactory5_CreateFontSetBuilder(This,fontset_builder); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateInMemoryFontFileLoader(IDWriteFactory5* This,IDWriteInMemoryFontFileLoader **loader) { + return This->lpVtbl->CreateInMemoryFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory5_CreateHttpFontFileLoader(IDWriteFactory5* This,const WCHAR *referrer_url,const WCHAR *extra_headers,IDWriteRemoteFontFileLoader **loader) { + return This->lpVtbl->CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader); +} +static FORCEINLINE DWRITE_CONTAINER_TYPE IDWriteFactory5_AnalyzeContainerType(IDWriteFactory5* This,const void *data,UINT32 data_size) { + return This->lpVtbl->AnalyzeContainerType(This,data,data_size); +} +static FORCEINLINE HRESULT IDWriteFactory5_UnpackFontFile(IDWriteFactory5* This,DWRITE_CONTAINER_TYPE container_type,const void *data,UINT32 data_size,IDWriteFontFileStream **stream) { + return This->lpVtbl->UnpackFontFile(This,container_type,data,data_size,stream); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFactory5_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFactory6 interface + */ +#ifndef __IDWriteFactory6_INTERFACE_DEFINED__ +#define __IDWriteFactory6_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFactory6, 0xf3744d80, 0x21f7, 0x42eb, 0xb3,0x5d, 0x99,0x5b,0xc7,0x2f,0xc2,0x23); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("f3744d80-21f7-42eb-b35d-995bc72fc223") +IDWriteFactory6 : public IDWriteFactory5 +{ + virtual HRESULT STDMETHODCALLTYPE CreateFontFaceReference( + IDWriteFontFile *file, + UINT32 face_index, + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_axis, + IDWriteFontFaceReference1 **face_ref) = 0; + + using IDWriteFactory5::CreateFontFaceReference; + + virtual HRESULT STDMETHODCALLTYPE CreateFontResource( + IDWriteFontFile *file, + UINT32 face_index, + IDWriteFontResource **resource) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSystemFontSet( + WINBOOL include_downloadable, + IDWriteFontSet1 **fontset) = 0; + + using IDWriteFactory3::GetSystemFontSet; + + virtual HRESULT STDMETHODCALLTYPE GetSystemFontCollection( + WINBOOL include_downloadable, + DWRITE_FONT_FAMILY_MODEL family_model, + IDWriteFontCollection2 **collection) = 0; + + using IDWriteFactory3::GetSystemFontCollection; + + virtual HRESULT STDMETHODCALLTYPE CreateFontCollectionFromFontSet( + IDWriteFontSet *fontset, + DWRITE_FONT_FAMILY_MODEL family_model, + IDWriteFontCollection2 **collection) = 0; + + using IDWriteFactory5::CreateFontCollectionFromFontSet; + + virtual HRESULT STDMETHODCALLTYPE CreateFontSetBuilder( + IDWriteFontSetBuilder2 **builder) = 0; + + using IDWriteFactory3::CreateFontSetBuilder; + using IDWriteFactory5::CreateFontSetBuilder; + + virtual HRESULT STDMETHODCALLTYPE CreateTextFormat( + const WCHAR *familyname, + IDWriteFontCollection *collection, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_axis, + FLOAT fontsize, + const WCHAR *localename, + IDWriteTextFormat3 **format) = 0; + + using IDWriteFactory::CreateTextFormat; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFactory6, 0xf3744d80, 0x21f7, 0x42eb, 0xb3,0x5d, 0x99,0x5b,0xc7,0x2f,0xc2,0x23) +#endif +#else +typedef struct IDWriteFactory6Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFactory6 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFactory6 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFactory6 *This); + + /*** IDWriteFactory methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontCollection)( + IDWriteFactory6 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontCollection)( + IDWriteFactory6 *This, + IDWriteFontCollectionLoader *loader, + const void *key, + UINT32 key_size, + IDWriteFontCollection **collection); + + HRESULT (STDMETHODCALLTYPE *RegisterFontCollectionLoader)( + IDWriteFactory6 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontCollectionLoader)( + IDWriteFactory6 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateFontFileReference)( + IDWriteFactory6 *This, + const WCHAR *path, + const FILETIME *writetime, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontFileReference)( + IDWriteFactory6 *This, + const void *reference_key, + UINT32 key_size, + IDWriteFontFileLoader *loader, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFactory6 *This, + DWRITE_FONT_FACE_TYPE facetype, + UINT32 files_number, + IDWriteFontFile *const *font_files, + UINT32 index, + DWRITE_FONT_SIMULATIONS sim_flags, + IDWriteFontFace **font_face); + + HRESULT (STDMETHODCALLTYPE *CreateRenderingParams)( + IDWriteFactory6 *This, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateMonitorRenderingParams)( + IDWriteFactory6 *This, + HMONITOR monitor, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateCustomRenderingParams)( + IDWriteFactory6 *This, + FLOAT gamma, + FLOAT enhancedContrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *RegisterFontFileLoader)( + IDWriteFactory6 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontFileLoader)( + IDWriteFactory6 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateTextFormat)( + IDWriteFactory6 *This, + const WCHAR *family_name, + IDWriteFontCollection *collection, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STYLE style, + DWRITE_FONT_STRETCH stretch, + FLOAT size, + const WCHAR *locale, + IDWriteTextFormat **format); + + HRESULT (STDMETHODCALLTYPE *CreateTypography)( + IDWriteFactory6 *This, + IDWriteTypography **typography); + + HRESULT (STDMETHODCALLTYPE *GetGdiInterop)( + IDWriteFactory6 *This, + IDWriteGdiInterop **gdi_interop); + + HRESULT (STDMETHODCALLTYPE *CreateTextLayout)( + IDWriteFactory6 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT max_width, + FLOAT max_height, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateGdiCompatibleTextLayout)( + IDWriteFactory6 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT layout_width, + FLOAT layout_height, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateEllipsisTrimmingSign)( + IDWriteFactory6 *This, + IDWriteTextFormat *format, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *CreateTextAnalyzer)( + IDWriteFactory6 *This, + IDWriteTextAnalyzer **analyzer); + + HRESULT (STDMETHODCALLTYPE *CreateNumberSubstitution)( + IDWriteFactory6 *This, + DWRITE_NUMBER_SUBSTITUTION_METHOD method, + const WCHAR *locale, + WINBOOL ignore_user_override, + IDWriteNumberSubstitution **substitution); + + HRESULT (STDMETHODCALLTYPE *CreateGlyphRunAnalysis)( + IDWriteFactory6 *This, + const DWRITE_GLYPH_RUN *glyph_run, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + FLOAT baseline_x, + FLOAT baseline_y, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory1 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetEudcFontCollection)( + IDWriteFactory6 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory1_CreateCustomRenderingParams)( + IDWriteFactory6 *This, + FLOAT gamma, + FLOAT enhcontrast, + FLOAT enhcontrast_grayscale, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams1 **params); + + /*** IDWriteFactory2 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontFallback)( + IDWriteFactory6 *This, + IDWriteFontFallback **fallback); + + HRESULT (STDMETHODCALLTYPE *CreateFontFallbackBuilder)( + IDWriteFactory6 *This, + IDWriteFontFallbackBuilder **fallbackbuilder); + + HRESULT (STDMETHODCALLTYPE *TranslateColorGlyphRun)( + IDWriteFactory6 *This, + FLOAT originX, + FLOAT originY, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, + DWRITE_MEASURING_MODE mode, + const DWRITE_MATRIX *transform, + UINT32 palette_index, + IDWriteColorGlyphRunEnumerator **colorlayers); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateCustomRenderingParams)( + IDWriteFactory6 *This, + FLOAT gamma, + FLOAT contrast, + FLOAT grayscalecontrast, + FLOAT cleartypeLevel, + DWRITE_PIXEL_GEOMETRY pixelGeometry, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_GRID_FIT_MODE gridFitMode, + IDWriteRenderingParams2 **params); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateGlyphRunAnalysis)( + IDWriteFactory6 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GRID_FIT_MODE gridFitMode, + DWRITE_TEXT_ANTIALIAS_MODE antialiasMode, + FLOAT originX, + FLOAT originY, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory3 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateGlyphRunAnalysis)( + IDWriteFactory6 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + DWRITE_TEXT_ANTIALIAS_MODE antialias_mode, + FLOAT origin_x, + FLOAT origin_y, + IDWriteGlyphRunAnalysis **analysis); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateCustomRenderingParams)( + IDWriteFactory6 *This, + FLOAT gamma, + FLOAT enhanced_contrast, + FLOAT grayscale_enhanced_contrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY pixel_geometry, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + IDWriteRenderingParams3 **params); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference_)( + IDWriteFactory6 *This, + IDWriteFontFile *file, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference)( + IDWriteFactory6 *This, + const WCHAR *path, + const FILETIME *writetime, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *GetSystemFontSet)( + IDWriteFactory6 *This, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *CreateFontSetBuilder)( + IDWriteFactory6 *This, + IDWriteFontSetBuilder **builder); + + HRESULT (STDMETHODCALLTYPE *CreateFontCollectionFromFontSet)( + IDWriteFactory6 *This, + IDWriteFontSet *fontset, + IDWriteFontCollection1 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_GetSystemFontCollection)( + IDWriteFactory6 *This, + WINBOOL include_downloadable, + IDWriteFontCollection1 **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *GetFontDownloadQueue)( + IDWriteFactory6 *This, + IDWriteFontDownloadQueue **queue); + + /*** IDWriteFactory4 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory4_TranslateColorGlyphRun)( + IDWriteFactory6 *This, + D2D1_POINT_2F baseline_origin, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc, + DWRITE_GLYPH_IMAGE_FORMATS desired_formats, + DWRITE_MEASURING_MODE measuring_mode, + const DWRITE_MATRIX *transform, + UINT32 palette, + IDWriteColorGlyphRunEnumerator1 **layers); + + HRESULT (STDMETHODCALLTYPE *ComputeGlyphOrigins_)( + IDWriteFactory6 *This, + const DWRITE_GLYPH_RUN *run, + D2D1_POINT_2F baseline_origin, + D2D1_POINT_2F *origins); + + HRESULT (STDMETHODCALLTYPE *ComputeGlyphOrigins)( + IDWriteFactory6 *This, + const DWRITE_GLYPH_RUN *run, + DWRITE_MEASURING_MODE measuring_mode, + D2D1_POINT_2F baseline_origin, + const DWRITE_MATRIX *transform, + D2D1_POINT_2F *origins); + + /*** IDWriteFactory5 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory5_CreateFontSetBuilder)( + IDWriteFactory6 *This, + IDWriteFontSetBuilder1 **fontset_builder); + + HRESULT (STDMETHODCALLTYPE *CreateInMemoryFontFileLoader)( + IDWriteFactory6 *This, + IDWriteInMemoryFontFileLoader **loader); + + HRESULT (STDMETHODCALLTYPE *CreateHttpFontFileLoader)( + IDWriteFactory6 *This, + const WCHAR *referrer_url, + const WCHAR *extra_headers, + IDWriteRemoteFontFileLoader **loader); + + DWRITE_CONTAINER_TYPE (STDMETHODCALLTYPE *AnalyzeContainerType)( + IDWriteFactory6 *This, + const void *data, + UINT32 data_size); + + HRESULT (STDMETHODCALLTYPE *UnpackFontFile)( + IDWriteFactory6 *This, + DWRITE_CONTAINER_TYPE container_type, + const void *data, + UINT32 data_size, + IDWriteFontFileStream **stream); + + /*** IDWriteFactory6 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_CreateFontFaceReference)( + IDWriteFactory6 *This, + IDWriteFontFile *file, + UINT32 face_index, + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_axis, + IDWriteFontFaceReference1 **face_ref); + + HRESULT (STDMETHODCALLTYPE *CreateFontResource)( + IDWriteFactory6 *This, + IDWriteFontFile *file, + UINT32 face_index, + IDWriteFontResource **resource); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_GetSystemFontSet)( + IDWriteFactory6 *This, + WINBOOL include_downloadable, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_GetSystemFontCollection)( + IDWriteFactory6 *This, + WINBOOL include_downloadable, + DWRITE_FONT_FAMILY_MODEL family_model, + IDWriteFontCollection2 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_CreateFontCollectionFromFontSet)( + IDWriteFactory6 *This, + IDWriteFontSet *fontset, + DWRITE_FONT_FAMILY_MODEL family_model, + IDWriteFontCollection2 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_CreateFontSetBuilder)( + IDWriteFactory6 *This, + IDWriteFontSetBuilder2 **builder); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_CreateTextFormat)( + IDWriteFactory6 *This, + const WCHAR *familyname, + IDWriteFontCollection *collection, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_axis, + FLOAT fontsize, + const WCHAR *localename, + IDWriteTextFormat3 **format); + + END_INTERFACE +} IDWriteFactory6Vtbl; + +interface IDWriteFactory6 { + CONST_VTBL IDWriteFactory6Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFactory6_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFactory6_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFactory6_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFactory methods ***/ +#define IDWriteFactory6_CreateCustomFontCollection(This,loader,key,key_size,collection) (This)->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection) +#define IDWriteFactory6_RegisterFontCollectionLoader(This,loader) (This)->lpVtbl->RegisterFontCollectionLoader(This,loader) +#define IDWriteFactory6_UnregisterFontCollectionLoader(This,loader) (This)->lpVtbl->UnregisterFontCollectionLoader(This,loader) +#define IDWriteFactory6_CreateFontFileReference(This,path,writetime,font_file) (This)->lpVtbl->CreateFontFileReference(This,path,writetime,font_file) +#define IDWriteFactory6_CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) (This)->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) +#define IDWriteFactory6_CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) (This)->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) +#define IDWriteFactory6_CreateRenderingParams(This,params) (This)->lpVtbl->CreateRenderingParams(This,params) +#define IDWriteFactory6_CreateMonitorRenderingParams(This,monitor,params) (This)->lpVtbl->CreateMonitorRenderingParams(This,monitor,params) +#define IDWriteFactory6_RegisterFontFileLoader(This,loader) (This)->lpVtbl->RegisterFontFileLoader(This,loader) +#define IDWriteFactory6_UnregisterFontFileLoader(This,loader) (This)->lpVtbl->UnregisterFontFileLoader(This,loader) +#define IDWriteFactory6_CreateTypography(This,typography) (This)->lpVtbl->CreateTypography(This,typography) +#define IDWriteFactory6_GetGdiInterop(This,gdi_interop) (This)->lpVtbl->GetGdiInterop(This,gdi_interop) +#define IDWriteFactory6_CreateTextLayout(This,string,len,format,max_width,max_height,layout) (This)->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout) +#define IDWriteFactory6_CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) (This)->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) +#define IDWriteFactory6_CreateEllipsisTrimmingSign(This,format,trimming_sign) (This)->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign) +#define IDWriteFactory6_CreateTextAnalyzer(This,analyzer) (This)->lpVtbl->CreateTextAnalyzer(This,analyzer) +#define IDWriteFactory6_CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) (This)->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) +/*** IDWriteFactory1 methods ***/ +#define IDWriteFactory6_GetEudcFontCollection(This,collection,check_for_updates) (This)->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates) +/*** IDWriteFactory2 methods ***/ +#define IDWriteFactory6_GetSystemFontFallback(This,fallback) (This)->lpVtbl->GetSystemFontFallback(This,fallback) +#define IDWriteFactory6_CreateFontFallbackBuilder(This,fallbackbuilder) (This)->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder) +/*** IDWriteFactory3 methods ***/ +#define IDWriteFactory6_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) (This)->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) +#define IDWriteFactory6_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) (This)->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) +#define IDWriteFactory6_CreateFontFaceReference_(This,file,index,simulations,reference) (This)->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference) +#define IDWriteFactory6_GetFontDownloadQueue(This,queue) (This)->lpVtbl->GetFontDownloadQueue(This,queue) +/*** IDWriteFactory4 methods ***/ +#define IDWriteFactory6_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers) (This)->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers) +#define IDWriteFactory6_ComputeGlyphOrigins_(This,run,baseline_origin,origins) (This)->lpVtbl->ComputeGlyphOrigins_(This,run,baseline_origin,origins) +#define IDWriteFactory6_ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins) (This)->lpVtbl->ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins) +/*** IDWriteFactory5 methods ***/ +#define IDWriteFactory6_CreateInMemoryFontFileLoader(This,loader) (This)->lpVtbl->CreateInMemoryFontFileLoader(This,loader) +#define IDWriteFactory6_CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader) (This)->lpVtbl->CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader) +#define IDWriteFactory6_AnalyzeContainerType(This,data,data_size) (This)->lpVtbl->AnalyzeContainerType(This,data,data_size) +#define IDWriteFactory6_UnpackFontFile(This,container_type,data,data_size,stream) (This)->lpVtbl->UnpackFontFile(This,container_type,data,data_size,stream) +/*** IDWriteFactory6 methods ***/ +#define IDWriteFactory6_CreateFontFaceReference(This,file,face_index,simulations,axis_values,num_axis,face_ref) (This)->lpVtbl->IDWriteFactory6_CreateFontFaceReference(This,file,face_index,simulations,axis_values,num_axis,face_ref) +#define IDWriteFactory6_CreateFontResource(This,file,face_index,resource) (This)->lpVtbl->CreateFontResource(This,file,face_index,resource) +#define IDWriteFactory6_GetSystemFontSet(This,include_downloadable,fontset) (This)->lpVtbl->IDWriteFactory6_GetSystemFontSet(This,include_downloadable,fontset) +#define IDWriteFactory6_GetSystemFontCollection(This,include_downloadable,family_model,collection) (This)->lpVtbl->IDWriteFactory6_GetSystemFontCollection(This,include_downloadable,family_model,collection) +#define IDWriteFactory6_CreateFontCollectionFromFontSet(This,fontset,family_model,collection) (This)->lpVtbl->IDWriteFactory6_CreateFontCollectionFromFontSet(This,fontset,family_model,collection) +#define IDWriteFactory6_CreateFontSetBuilder(This,builder) (This)->lpVtbl->IDWriteFactory6_CreateFontSetBuilder(This,builder) +#define IDWriteFactory6_CreateTextFormat(This,familyname,collection,axis_values,num_axis,fontsize,localename,format) (This)->lpVtbl->IDWriteFactory6_CreateTextFormat(This,familyname,collection,axis_values,num_axis,fontsize,localename,format) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFactory6_QueryInterface(IDWriteFactory6* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFactory6_AddRef(IDWriteFactory6* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFactory6_Release(IDWriteFactory6* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFactory methods ***/ +static FORCEINLINE HRESULT IDWriteFactory6_CreateCustomFontCollection(IDWriteFactory6* This,IDWriteFontCollectionLoader *loader,const void *key,UINT32 key_size,IDWriteFontCollection **collection) { + return This->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection); +} +static FORCEINLINE HRESULT IDWriteFactory6_RegisterFontCollectionLoader(IDWriteFactory6* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->RegisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory6_UnregisterFontCollectionLoader(IDWriteFactory6* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->UnregisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateFontFileReference(IDWriteFactory6* This,const WCHAR *path,const FILETIME *writetime,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateFontFileReference(This,path,writetime,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateCustomFontFileReference(IDWriteFactory6* This,const void *reference_key,UINT32 key_size,IDWriteFontFileLoader *loader,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateFontFace(IDWriteFactory6* This,DWRITE_FONT_FACE_TYPE facetype,UINT32 files_number,IDWriteFontFile *const *font_files,UINT32 index,DWRITE_FONT_SIMULATIONS sim_flags,IDWriteFontFace **font_face) { + return This->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateRenderingParams(IDWriteFactory6* This,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateRenderingParams(This,params); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateMonitorRenderingParams(IDWriteFactory6* This,HMONITOR monitor,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateMonitorRenderingParams(This,monitor,params); +} +static FORCEINLINE HRESULT IDWriteFactory6_RegisterFontFileLoader(IDWriteFactory6* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->RegisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory6_UnregisterFontFileLoader(IDWriteFactory6* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->UnregisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateTypography(IDWriteFactory6* This,IDWriteTypography **typography) { + return This->lpVtbl->CreateTypography(This,typography); +} +static FORCEINLINE HRESULT IDWriteFactory6_GetGdiInterop(IDWriteFactory6* This,IDWriteGdiInterop **gdi_interop) { + return This->lpVtbl->GetGdiInterop(This,gdi_interop); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateTextLayout(IDWriteFactory6* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT max_width,FLOAT max_height,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateGdiCompatibleTextLayout(IDWriteFactory6* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT layout_width,FLOAT layout_height,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateEllipsisTrimmingSign(IDWriteFactory6* This,IDWriteTextFormat *format,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateTextAnalyzer(IDWriteFactory6* This,IDWriteTextAnalyzer **analyzer) { + return This->lpVtbl->CreateTextAnalyzer(This,analyzer); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateNumberSubstitution(IDWriteFactory6* This,DWRITE_NUMBER_SUBSTITUTION_METHOD method,const WCHAR *locale,WINBOOL ignore_user_override,IDWriteNumberSubstitution **substitution) { + return This->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution); +} +/*** IDWriteFactory1 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory6_GetEudcFontCollection(IDWriteFactory6* This,IDWriteFontCollection **collection,WINBOOL check_for_updates) { + return This->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates); +} +/*** IDWriteFactory2 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory6_GetSystemFontFallback(IDWriteFactory6* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetSystemFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateFontFallbackBuilder(IDWriteFactory6* This,IDWriteFontFallbackBuilder **fallbackbuilder) { + return This->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder); +} +/*** IDWriteFactory3 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory6_CreateGlyphRunAnalysis(IDWriteFactory6* This,const DWRITE_GLYPH_RUN *run,const DWRITE_MATRIX *transform,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_MEASURING_MODE measuring_mode,DWRITE_GRID_FIT_MODE gridfit_mode,DWRITE_TEXT_ANTIALIAS_MODE antialias_mode,FLOAT origin_x,FLOAT origin_y,IDWriteGlyphRunAnalysis **analysis) { + return This->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateCustomRenderingParams(IDWriteFactory6* This,FLOAT gamma,FLOAT enhanced_contrast,FLOAT grayscale_enhanced_contrast,FLOAT cleartype_level,DWRITE_PIXEL_GEOMETRY pixel_geometry,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_GRID_FIT_MODE gridfit_mode,IDWriteRenderingParams3 **params) { + return This->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateFontFaceReference_(IDWriteFactory6* This,IDWriteFontFile *file,UINT32 index,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFaceReference **reference) { + return This->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference); +} +static FORCEINLINE HRESULT IDWriteFactory6_GetFontDownloadQueue(IDWriteFactory6* This,IDWriteFontDownloadQueue **queue) { + return This->lpVtbl->GetFontDownloadQueue(This,queue); +} +/*** IDWriteFactory4 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory6_TranslateColorGlyphRun(IDWriteFactory6* This,D2D1_POINT_2F baseline_origin,const DWRITE_GLYPH_RUN *run,const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc,DWRITE_GLYPH_IMAGE_FORMATS desired_formats,DWRITE_MEASURING_MODE measuring_mode,const DWRITE_MATRIX *transform,UINT32 palette,IDWriteColorGlyphRunEnumerator1 **layers) { + return This->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers); +} +static FORCEINLINE HRESULT IDWriteFactory6_ComputeGlyphOrigins_(IDWriteFactory6* This,const DWRITE_GLYPH_RUN *run,D2D1_POINT_2F baseline_origin,D2D1_POINT_2F *origins) { + return This->lpVtbl->ComputeGlyphOrigins_(This,run,baseline_origin,origins); +} +static FORCEINLINE HRESULT IDWriteFactory6_ComputeGlyphOrigins(IDWriteFactory6* This,const DWRITE_GLYPH_RUN *run,DWRITE_MEASURING_MODE measuring_mode,D2D1_POINT_2F baseline_origin,const DWRITE_MATRIX *transform,D2D1_POINT_2F *origins) { + return This->lpVtbl->ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins); +} +/*** IDWriteFactory5 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory6_CreateInMemoryFontFileLoader(IDWriteFactory6* This,IDWriteInMemoryFontFileLoader **loader) { + return This->lpVtbl->CreateInMemoryFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateHttpFontFileLoader(IDWriteFactory6* This,const WCHAR *referrer_url,const WCHAR *extra_headers,IDWriteRemoteFontFileLoader **loader) { + return This->lpVtbl->CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader); +} +static FORCEINLINE DWRITE_CONTAINER_TYPE IDWriteFactory6_AnalyzeContainerType(IDWriteFactory6* This,const void *data,UINT32 data_size) { + return This->lpVtbl->AnalyzeContainerType(This,data,data_size); +} +static FORCEINLINE HRESULT IDWriteFactory6_UnpackFontFile(IDWriteFactory6* This,DWRITE_CONTAINER_TYPE container_type,const void *data,UINT32 data_size,IDWriteFontFileStream **stream) { + return This->lpVtbl->UnpackFontFile(This,container_type,data,data_size,stream); +} +/*** IDWriteFactory6 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory6_CreateFontFaceReference(IDWriteFactory6* This,IDWriteFontFile *file,UINT32 face_index,DWRITE_FONT_SIMULATIONS simulations,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_axis,IDWriteFontFaceReference1 **face_ref) { + return This->lpVtbl->IDWriteFactory6_CreateFontFaceReference(This,file,face_index,simulations,axis_values,num_axis,face_ref); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateFontResource(IDWriteFactory6* This,IDWriteFontFile *file,UINT32 face_index,IDWriteFontResource **resource) { + return This->lpVtbl->CreateFontResource(This,file,face_index,resource); +} +static FORCEINLINE HRESULT IDWriteFactory6_GetSystemFontSet(IDWriteFactory6* This,WINBOOL include_downloadable,IDWriteFontSet1 **fontset) { + return This->lpVtbl->IDWriteFactory6_GetSystemFontSet(This,include_downloadable,fontset); +} +static FORCEINLINE HRESULT IDWriteFactory6_GetSystemFontCollection(IDWriteFactory6* This,WINBOOL include_downloadable,DWRITE_FONT_FAMILY_MODEL family_model,IDWriteFontCollection2 **collection) { + return This->lpVtbl->IDWriteFactory6_GetSystemFontCollection(This,include_downloadable,family_model,collection); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateFontCollectionFromFontSet(IDWriteFactory6* This,IDWriteFontSet *fontset,DWRITE_FONT_FAMILY_MODEL family_model,IDWriteFontCollection2 **collection) { + return This->lpVtbl->IDWriteFactory6_CreateFontCollectionFromFontSet(This,fontset,family_model,collection); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateFontSetBuilder(IDWriteFactory6* This,IDWriteFontSetBuilder2 **builder) { + return This->lpVtbl->IDWriteFactory6_CreateFontSetBuilder(This,builder); +} +static FORCEINLINE HRESULT IDWriteFactory6_CreateTextFormat(IDWriteFactory6* This,const WCHAR *familyname,IDWriteFontCollection *collection,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_axis,FLOAT fontsize,const WCHAR *localename,IDWriteTextFormat3 **format) { + return This->lpVtbl->IDWriteFactory6_CreateTextFormat(This,familyname,collection,axis_values,num_axis,fontsize,localename,format); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFactory6_INTERFACE_DEFINED__ */ + +/***************************************************************************** + * IDWriteFactory7 interface + */ +#ifndef __IDWriteFactory7_INTERFACE_DEFINED__ +#define __IDWriteFactory7_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IDWriteFactory7, 0x35d0e0b3, 0x9076, 0x4d2e, 0xa0,0x16, 0xa9,0x1b,0x56,0x8a,0x06,0xb4); +#if defined(__cplusplus) && !defined(CINTERFACE) +MIDL_INTERFACE("35d0e0b3-9076-4d2e-a016-a91b568a06b4") +IDWriteFactory7 : public IDWriteFactory6 +{ + virtual HRESULT STDMETHODCALLTYPE GetSystemFontSet( + WINBOOL include_downloadable, + IDWriteFontSet2 **fontset) = 0; + + using IDWriteFactory6::GetSystemFontSet; + + virtual HRESULT STDMETHODCALLTYPE GetSystemFontCollection( + WINBOOL include_downloadable, + DWRITE_FONT_FAMILY_MODEL family_model, + IDWriteFontCollection3 **collection) = 0; + + using IDWriteFactory6::GetSystemFontCollection; + +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFactory7, 0x35d0e0b3, 0x9076, 0x4d2e, 0xa0,0x16, 0xa9,0x1b,0x56,0x8a,0x06,0xb4) +#endif +#else +typedef struct IDWriteFactory7Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IDWriteFactory7 *This, + REFIID riid, + void **ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IDWriteFactory7 *This); + + ULONG (STDMETHODCALLTYPE *Release)( + IDWriteFactory7 *This); + + /*** IDWriteFactory methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontCollection)( + IDWriteFactory7 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontCollection)( + IDWriteFactory7 *This, + IDWriteFontCollectionLoader *loader, + const void *key, + UINT32 key_size, + IDWriteFontCollection **collection); + + HRESULT (STDMETHODCALLTYPE *RegisterFontCollectionLoader)( + IDWriteFactory7 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontCollectionLoader)( + IDWriteFactory7 *This, + IDWriteFontCollectionLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateFontFileReference)( + IDWriteFactory7 *This, + const WCHAR *path, + const FILETIME *writetime, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateCustomFontFileReference)( + IDWriteFactory7 *This, + const void *reference_key, + UINT32 key_size, + IDWriteFontFileLoader *loader, + IDWriteFontFile **font_file); + + HRESULT (STDMETHODCALLTYPE *CreateFontFace)( + IDWriteFactory7 *This, + DWRITE_FONT_FACE_TYPE facetype, + UINT32 files_number, + IDWriteFontFile *const *font_files, + UINT32 index, + DWRITE_FONT_SIMULATIONS sim_flags, + IDWriteFontFace **font_face); + + HRESULT (STDMETHODCALLTYPE *CreateRenderingParams)( + IDWriteFactory7 *This, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateMonitorRenderingParams)( + IDWriteFactory7 *This, + HMONITOR monitor, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *CreateCustomRenderingParams)( + IDWriteFactory7 *This, + FLOAT gamma, + FLOAT enhancedContrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams **params); + + HRESULT (STDMETHODCALLTYPE *RegisterFontFileLoader)( + IDWriteFactory7 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *UnregisterFontFileLoader)( + IDWriteFactory7 *This, + IDWriteFontFileLoader *loader); + + HRESULT (STDMETHODCALLTYPE *CreateTextFormat)( + IDWriteFactory7 *This, + const WCHAR *family_name, + IDWriteFontCollection *collection, + DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STYLE style, + DWRITE_FONT_STRETCH stretch, + FLOAT size, + const WCHAR *locale, + IDWriteTextFormat **format); + + HRESULT (STDMETHODCALLTYPE *CreateTypography)( + IDWriteFactory7 *This, + IDWriteTypography **typography); + + HRESULT (STDMETHODCALLTYPE *GetGdiInterop)( + IDWriteFactory7 *This, + IDWriteGdiInterop **gdi_interop); + + HRESULT (STDMETHODCALLTYPE *CreateTextLayout)( + IDWriteFactory7 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT max_width, + FLOAT max_height, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateGdiCompatibleTextLayout)( + IDWriteFactory7 *This, + const WCHAR *string, + UINT32 len, + IDWriteTextFormat *format, + FLOAT layout_width, + FLOAT layout_height, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + WINBOOL use_gdi_natural, + IDWriteTextLayout **layout); + + HRESULT (STDMETHODCALLTYPE *CreateEllipsisTrimmingSign)( + IDWriteFactory7 *This, + IDWriteTextFormat *format, + IDWriteInlineObject **trimming_sign); + + HRESULT (STDMETHODCALLTYPE *CreateTextAnalyzer)( + IDWriteFactory7 *This, + IDWriteTextAnalyzer **analyzer); + + HRESULT (STDMETHODCALLTYPE *CreateNumberSubstitution)( + IDWriteFactory7 *This, + DWRITE_NUMBER_SUBSTITUTION_METHOD method, + const WCHAR *locale, + WINBOOL ignore_user_override, + IDWriteNumberSubstitution **substitution); + + HRESULT (STDMETHODCALLTYPE *CreateGlyphRunAnalysis)( + IDWriteFactory7 *This, + const DWRITE_GLYPH_RUN *glyph_run, + FLOAT pixels_per_dip, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + FLOAT baseline_x, + FLOAT baseline_y, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory1 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetEudcFontCollection)( + IDWriteFactory7 *This, + IDWriteFontCollection **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory1_CreateCustomRenderingParams)( + IDWriteFactory7 *This, + FLOAT gamma, + FLOAT enhcontrast, + FLOAT enhcontrast_grayscale, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY geometry, + DWRITE_RENDERING_MODE mode, + IDWriteRenderingParams1 **params); + + /*** IDWriteFactory2 methods ***/ + HRESULT (STDMETHODCALLTYPE *GetSystemFontFallback)( + IDWriteFactory7 *This, + IDWriteFontFallback **fallback); + + HRESULT (STDMETHODCALLTYPE *CreateFontFallbackBuilder)( + IDWriteFactory7 *This, + IDWriteFontFallbackBuilder **fallbackbuilder); + + HRESULT (STDMETHODCALLTYPE *TranslateColorGlyphRun)( + IDWriteFactory7 *This, + FLOAT originX, + FLOAT originY, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, + DWRITE_MEASURING_MODE mode, + const DWRITE_MATRIX *transform, + UINT32 palette_index, + IDWriteColorGlyphRunEnumerator **colorlayers); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateCustomRenderingParams)( + IDWriteFactory7 *This, + FLOAT gamma, + FLOAT contrast, + FLOAT grayscalecontrast, + FLOAT cleartypeLevel, + DWRITE_PIXEL_GEOMETRY pixelGeometry, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_GRID_FIT_MODE gridFitMode, + IDWriteRenderingParams2 **params); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory2_CreateGlyphRunAnalysis)( + IDWriteFactory7 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE renderingMode, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GRID_FIT_MODE gridFitMode, + DWRITE_TEXT_ANTIALIAS_MODE antialiasMode, + FLOAT originX, + FLOAT originY, + IDWriteGlyphRunAnalysis **analysis); + + /*** IDWriteFactory3 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateGlyphRunAnalysis)( + IDWriteFactory7 *This, + const DWRITE_GLYPH_RUN *run, + const DWRITE_MATRIX *transform, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_MEASURING_MODE measuring_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + DWRITE_TEXT_ANTIALIAS_MODE antialias_mode, + FLOAT origin_x, + FLOAT origin_y, + IDWriteGlyphRunAnalysis **analysis); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_CreateCustomRenderingParams)( + IDWriteFactory7 *This, + FLOAT gamma, + FLOAT enhanced_contrast, + FLOAT grayscale_enhanced_contrast, + FLOAT cleartype_level, + DWRITE_PIXEL_GEOMETRY pixel_geometry, + DWRITE_RENDERING_MODE1 rendering_mode, + DWRITE_GRID_FIT_MODE gridfit_mode, + IDWriteRenderingParams3 **params); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference_)( + IDWriteFactory7 *This, + IDWriteFontFile *file, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *CreateFontFaceReference)( + IDWriteFactory7 *This, + const WCHAR *path, + const FILETIME *writetime, + UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, + IDWriteFontFaceReference **reference); + + HRESULT (STDMETHODCALLTYPE *GetSystemFontSet)( + IDWriteFactory7 *This, + IDWriteFontSet **fontset); + + HRESULT (STDMETHODCALLTYPE *CreateFontSetBuilder)( + IDWriteFactory7 *This, + IDWriteFontSetBuilder **builder); + + HRESULT (STDMETHODCALLTYPE *CreateFontCollectionFromFontSet)( + IDWriteFactory7 *This, + IDWriteFontSet *fontset, + IDWriteFontCollection1 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory3_GetSystemFontCollection)( + IDWriteFactory7 *This, + WINBOOL include_downloadable, + IDWriteFontCollection1 **collection, + WINBOOL check_for_updates); + + HRESULT (STDMETHODCALLTYPE *GetFontDownloadQueue)( + IDWriteFactory7 *This, + IDWriteFontDownloadQueue **queue); + + /*** IDWriteFactory4 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory4_TranslateColorGlyphRun)( + IDWriteFactory7 *This, + D2D1_POINT_2F baseline_origin, + const DWRITE_GLYPH_RUN *run, + const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc, + DWRITE_GLYPH_IMAGE_FORMATS desired_formats, + DWRITE_MEASURING_MODE measuring_mode, + const DWRITE_MATRIX *transform, + UINT32 palette, + IDWriteColorGlyphRunEnumerator1 **layers); + + HRESULT (STDMETHODCALLTYPE *ComputeGlyphOrigins_)( + IDWriteFactory7 *This, + const DWRITE_GLYPH_RUN *run, + D2D1_POINT_2F baseline_origin, + D2D1_POINT_2F *origins); + + HRESULT (STDMETHODCALLTYPE *ComputeGlyphOrigins)( + IDWriteFactory7 *This, + const DWRITE_GLYPH_RUN *run, + DWRITE_MEASURING_MODE measuring_mode, + D2D1_POINT_2F baseline_origin, + const DWRITE_MATRIX *transform, + D2D1_POINT_2F *origins); + + /*** IDWriteFactory5 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory5_CreateFontSetBuilder)( + IDWriteFactory7 *This, + IDWriteFontSetBuilder1 **fontset_builder); + + HRESULT (STDMETHODCALLTYPE *CreateInMemoryFontFileLoader)( + IDWriteFactory7 *This, + IDWriteInMemoryFontFileLoader **loader); + + HRESULT (STDMETHODCALLTYPE *CreateHttpFontFileLoader)( + IDWriteFactory7 *This, + const WCHAR *referrer_url, + const WCHAR *extra_headers, + IDWriteRemoteFontFileLoader **loader); + + DWRITE_CONTAINER_TYPE (STDMETHODCALLTYPE *AnalyzeContainerType)( + IDWriteFactory7 *This, + const void *data, + UINT32 data_size); + + HRESULT (STDMETHODCALLTYPE *UnpackFontFile)( + IDWriteFactory7 *This, + DWRITE_CONTAINER_TYPE container_type, + const void *data, + UINT32 data_size, + IDWriteFontFileStream **stream); + + /*** IDWriteFactory6 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_CreateFontFaceReference)( + IDWriteFactory7 *This, + IDWriteFontFile *file, + UINT32 face_index, + DWRITE_FONT_SIMULATIONS simulations, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_axis, + IDWriteFontFaceReference1 **face_ref); + + HRESULT (STDMETHODCALLTYPE *CreateFontResource)( + IDWriteFactory7 *This, + IDWriteFontFile *file, + UINT32 face_index, + IDWriteFontResource **resource); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_GetSystemFontSet)( + IDWriteFactory7 *This, + WINBOOL include_downloadable, + IDWriteFontSet1 **fontset); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_GetSystemFontCollection)( + IDWriteFactory7 *This, + WINBOOL include_downloadable, + DWRITE_FONT_FAMILY_MODEL family_model, + IDWriteFontCollection2 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_CreateFontCollectionFromFontSet)( + IDWriteFactory7 *This, + IDWriteFontSet *fontset, + DWRITE_FONT_FAMILY_MODEL family_model, + IDWriteFontCollection2 **collection); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_CreateFontSetBuilder)( + IDWriteFactory7 *This, + IDWriteFontSetBuilder2 **builder); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory6_CreateTextFormat)( + IDWriteFactory7 *This, + const WCHAR *familyname, + IDWriteFontCollection *collection, + const DWRITE_FONT_AXIS_VALUE *axis_values, + UINT32 num_axis, + FLOAT fontsize, + const WCHAR *localename, + IDWriteTextFormat3 **format); + + /*** IDWriteFactory7 methods ***/ + HRESULT (STDMETHODCALLTYPE *IDWriteFactory7_GetSystemFontSet)( + IDWriteFactory7 *This, + WINBOOL include_downloadable, + IDWriteFontSet2 **fontset); + + HRESULT (STDMETHODCALLTYPE *IDWriteFactory7_GetSystemFontCollection)( + IDWriteFactory7 *This, + WINBOOL include_downloadable, + DWRITE_FONT_FAMILY_MODEL family_model, + IDWriteFontCollection3 **collection); + + END_INTERFACE +} IDWriteFactory7Vtbl; + +interface IDWriteFactory7 { + CONST_VTBL IDWriteFactory7Vtbl* lpVtbl; +}; + +#ifdef COBJMACROS +#ifndef WIDL_C_INLINE_WRAPPERS +/*** IUnknown methods ***/ +#define IDWriteFactory7_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject) +#define IDWriteFactory7_AddRef(This) (This)->lpVtbl->AddRef(This) +#define IDWriteFactory7_Release(This) (This)->lpVtbl->Release(This) +/*** IDWriteFactory methods ***/ +#define IDWriteFactory7_CreateCustomFontCollection(This,loader,key,key_size,collection) (This)->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection) +#define IDWriteFactory7_RegisterFontCollectionLoader(This,loader) (This)->lpVtbl->RegisterFontCollectionLoader(This,loader) +#define IDWriteFactory7_UnregisterFontCollectionLoader(This,loader) (This)->lpVtbl->UnregisterFontCollectionLoader(This,loader) +#define IDWriteFactory7_CreateFontFileReference(This,path,writetime,font_file) (This)->lpVtbl->CreateFontFileReference(This,path,writetime,font_file) +#define IDWriteFactory7_CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) (This)->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file) +#define IDWriteFactory7_CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) (This)->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face) +#define IDWriteFactory7_CreateRenderingParams(This,params) (This)->lpVtbl->CreateRenderingParams(This,params) +#define IDWriteFactory7_CreateMonitorRenderingParams(This,monitor,params) (This)->lpVtbl->CreateMonitorRenderingParams(This,monitor,params) +#define IDWriteFactory7_RegisterFontFileLoader(This,loader) (This)->lpVtbl->RegisterFontFileLoader(This,loader) +#define IDWriteFactory7_UnregisterFontFileLoader(This,loader) (This)->lpVtbl->UnregisterFontFileLoader(This,loader) +#define IDWriteFactory7_CreateTypography(This,typography) (This)->lpVtbl->CreateTypography(This,typography) +#define IDWriteFactory7_GetGdiInterop(This,gdi_interop) (This)->lpVtbl->GetGdiInterop(This,gdi_interop) +#define IDWriteFactory7_CreateTextLayout(This,string,len,format,max_width,max_height,layout) (This)->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout) +#define IDWriteFactory7_CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) (This)->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout) +#define IDWriteFactory7_CreateEllipsisTrimmingSign(This,format,trimming_sign) (This)->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign) +#define IDWriteFactory7_CreateTextAnalyzer(This,analyzer) (This)->lpVtbl->CreateTextAnalyzer(This,analyzer) +#define IDWriteFactory7_CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) (This)->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution) +/*** IDWriteFactory1 methods ***/ +#define IDWriteFactory7_GetEudcFontCollection(This,collection,check_for_updates) (This)->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates) +/*** IDWriteFactory2 methods ***/ +#define IDWriteFactory7_GetSystemFontFallback(This,fallback) (This)->lpVtbl->GetSystemFontFallback(This,fallback) +#define IDWriteFactory7_CreateFontFallbackBuilder(This,fallbackbuilder) (This)->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder) +/*** IDWriteFactory3 methods ***/ +#define IDWriteFactory7_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) (This)->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis) +#define IDWriteFactory7_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) (This)->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params) +#define IDWriteFactory7_CreateFontFaceReference_(This,file,index,simulations,reference) (This)->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference) +#define IDWriteFactory7_GetFontDownloadQueue(This,queue) (This)->lpVtbl->GetFontDownloadQueue(This,queue) +/*** IDWriteFactory4 methods ***/ +#define IDWriteFactory7_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers) (This)->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers) +#define IDWriteFactory7_ComputeGlyphOrigins_(This,run,baseline_origin,origins) (This)->lpVtbl->ComputeGlyphOrigins_(This,run,baseline_origin,origins) +#define IDWriteFactory7_ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins) (This)->lpVtbl->ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins) +/*** IDWriteFactory5 methods ***/ +#define IDWriteFactory7_CreateInMemoryFontFileLoader(This,loader) (This)->lpVtbl->CreateInMemoryFontFileLoader(This,loader) +#define IDWriteFactory7_CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader) (This)->lpVtbl->CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader) +#define IDWriteFactory7_AnalyzeContainerType(This,data,data_size) (This)->lpVtbl->AnalyzeContainerType(This,data,data_size) +#define IDWriteFactory7_UnpackFontFile(This,container_type,data,data_size,stream) (This)->lpVtbl->UnpackFontFile(This,container_type,data,data_size,stream) +/*** IDWriteFactory6 methods ***/ +#define IDWriteFactory7_CreateFontFaceReference(This,file,face_index,simulations,axis_values,num_axis,face_ref) (This)->lpVtbl->IDWriteFactory6_CreateFontFaceReference(This,file,face_index,simulations,axis_values,num_axis,face_ref) +#define IDWriteFactory7_CreateFontResource(This,file,face_index,resource) (This)->lpVtbl->CreateFontResource(This,file,face_index,resource) +#define IDWriteFactory7_CreateFontCollectionFromFontSet(This,fontset,family_model,collection) (This)->lpVtbl->IDWriteFactory6_CreateFontCollectionFromFontSet(This,fontset,family_model,collection) +#define IDWriteFactory7_CreateFontSetBuilder(This,builder) (This)->lpVtbl->IDWriteFactory6_CreateFontSetBuilder(This,builder) +#define IDWriteFactory7_CreateTextFormat(This,familyname,collection,axis_values,num_axis,fontsize,localename,format) (This)->lpVtbl->IDWriteFactory6_CreateTextFormat(This,familyname,collection,axis_values,num_axis,fontsize,localename,format) +/*** IDWriteFactory7 methods ***/ +#define IDWriteFactory7_GetSystemFontSet(This,include_downloadable,fontset) (This)->lpVtbl->IDWriteFactory7_GetSystemFontSet(This,include_downloadable,fontset) +#define IDWriteFactory7_GetSystemFontCollection(This,include_downloadable,family_model,collection) (This)->lpVtbl->IDWriteFactory7_GetSystemFontCollection(This,include_downloadable,family_model,collection) +#else +/*** IUnknown methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_QueryInterface(IDWriteFactory7* This,REFIID riid,void **ppvObject) { + return This->lpVtbl->QueryInterface(This,riid,ppvObject); +} +static FORCEINLINE ULONG IDWriteFactory7_AddRef(IDWriteFactory7* This) { + return This->lpVtbl->AddRef(This); +} +static FORCEINLINE ULONG IDWriteFactory7_Release(IDWriteFactory7* This) { + return This->lpVtbl->Release(This); +} +/*** IDWriteFactory methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_CreateCustomFontCollection(IDWriteFactory7* This,IDWriteFontCollectionLoader *loader,const void *key,UINT32 key_size,IDWriteFontCollection **collection) { + return This->lpVtbl->CreateCustomFontCollection(This,loader,key,key_size,collection); +} +static FORCEINLINE HRESULT IDWriteFactory7_RegisterFontCollectionLoader(IDWriteFactory7* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->RegisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory7_UnregisterFontCollectionLoader(IDWriteFactory7* This,IDWriteFontCollectionLoader *loader) { + return This->lpVtbl->UnregisterFontCollectionLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateFontFileReference(IDWriteFactory7* This,const WCHAR *path,const FILETIME *writetime,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateFontFileReference(This,path,writetime,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateCustomFontFileReference(IDWriteFactory7* This,const void *reference_key,UINT32 key_size,IDWriteFontFileLoader *loader,IDWriteFontFile **font_file) { + return This->lpVtbl->CreateCustomFontFileReference(This,reference_key,key_size,loader,font_file); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateFontFace(IDWriteFactory7* This,DWRITE_FONT_FACE_TYPE facetype,UINT32 files_number,IDWriteFontFile *const *font_files,UINT32 index,DWRITE_FONT_SIMULATIONS sim_flags,IDWriteFontFace **font_face) { + return This->lpVtbl->CreateFontFace(This,facetype,files_number,font_files,index,sim_flags,font_face); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateRenderingParams(IDWriteFactory7* This,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateRenderingParams(This,params); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateMonitorRenderingParams(IDWriteFactory7* This,HMONITOR monitor,IDWriteRenderingParams **params) { + return This->lpVtbl->CreateMonitorRenderingParams(This,monitor,params); +} +static FORCEINLINE HRESULT IDWriteFactory7_RegisterFontFileLoader(IDWriteFactory7* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->RegisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory7_UnregisterFontFileLoader(IDWriteFactory7* This,IDWriteFontFileLoader *loader) { + return This->lpVtbl->UnregisterFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateTypography(IDWriteFactory7* This,IDWriteTypography **typography) { + return This->lpVtbl->CreateTypography(This,typography); +} +static FORCEINLINE HRESULT IDWriteFactory7_GetGdiInterop(IDWriteFactory7* This,IDWriteGdiInterop **gdi_interop) { + return This->lpVtbl->GetGdiInterop(This,gdi_interop); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateTextLayout(IDWriteFactory7* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT max_width,FLOAT max_height,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateTextLayout(This,string,len,format,max_width,max_height,layout); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateGdiCompatibleTextLayout(IDWriteFactory7* This,const WCHAR *string,UINT32 len,IDWriteTextFormat *format,FLOAT layout_width,FLOAT layout_height,FLOAT pixels_per_dip,const DWRITE_MATRIX *transform,WINBOOL use_gdi_natural,IDWriteTextLayout **layout) { + return This->lpVtbl->CreateGdiCompatibleTextLayout(This,string,len,format,layout_width,layout_height,pixels_per_dip,transform,use_gdi_natural,layout); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateEllipsisTrimmingSign(IDWriteFactory7* This,IDWriteTextFormat *format,IDWriteInlineObject **trimming_sign) { + return This->lpVtbl->CreateEllipsisTrimmingSign(This,format,trimming_sign); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateTextAnalyzer(IDWriteFactory7* This,IDWriteTextAnalyzer **analyzer) { + return This->lpVtbl->CreateTextAnalyzer(This,analyzer); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateNumberSubstitution(IDWriteFactory7* This,DWRITE_NUMBER_SUBSTITUTION_METHOD method,const WCHAR *locale,WINBOOL ignore_user_override,IDWriteNumberSubstitution **substitution) { + return This->lpVtbl->CreateNumberSubstitution(This,method,locale,ignore_user_override,substitution); +} +/*** IDWriteFactory1 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_GetEudcFontCollection(IDWriteFactory7* This,IDWriteFontCollection **collection,WINBOOL check_for_updates) { + return This->lpVtbl->GetEudcFontCollection(This,collection,check_for_updates); +} +/*** IDWriteFactory2 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_GetSystemFontFallback(IDWriteFactory7* This,IDWriteFontFallback **fallback) { + return This->lpVtbl->GetSystemFontFallback(This,fallback); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateFontFallbackBuilder(IDWriteFactory7* This,IDWriteFontFallbackBuilder **fallbackbuilder) { + return This->lpVtbl->CreateFontFallbackBuilder(This,fallbackbuilder); +} +/*** IDWriteFactory3 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_CreateGlyphRunAnalysis(IDWriteFactory7* This,const DWRITE_GLYPH_RUN *run,const DWRITE_MATRIX *transform,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_MEASURING_MODE measuring_mode,DWRITE_GRID_FIT_MODE gridfit_mode,DWRITE_TEXT_ANTIALIAS_MODE antialias_mode,FLOAT origin_x,FLOAT origin_y,IDWriteGlyphRunAnalysis **analysis) { + return This->lpVtbl->IDWriteFactory3_CreateGlyphRunAnalysis(This,run,transform,rendering_mode,measuring_mode,gridfit_mode,antialias_mode,origin_x,origin_y,analysis); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateCustomRenderingParams(IDWriteFactory7* This,FLOAT gamma,FLOAT enhanced_contrast,FLOAT grayscale_enhanced_contrast,FLOAT cleartype_level,DWRITE_PIXEL_GEOMETRY pixel_geometry,DWRITE_RENDERING_MODE1 rendering_mode,DWRITE_GRID_FIT_MODE gridfit_mode,IDWriteRenderingParams3 **params) { + return This->lpVtbl->IDWriteFactory3_CreateCustomRenderingParams(This,gamma,enhanced_contrast,grayscale_enhanced_contrast,cleartype_level,pixel_geometry,rendering_mode,gridfit_mode,params); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateFontFaceReference_(IDWriteFactory7* This,IDWriteFontFile *file,UINT32 index,DWRITE_FONT_SIMULATIONS simulations,IDWriteFontFaceReference **reference) { + return This->lpVtbl->CreateFontFaceReference_(This,file,index,simulations,reference); +} +static FORCEINLINE HRESULT IDWriteFactory7_GetFontDownloadQueue(IDWriteFactory7* This,IDWriteFontDownloadQueue **queue) { + return This->lpVtbl->GetFontDownloadQueue(This,queue); +} +/*** IDWriteFactory4 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_TranslateColorGlyphRun(IDWriteFactory7* This,D2D1_POINT_2F baseline_origin,const DWRITE_GLYPH_RUN *run,const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc,DWRITE_GLYPH_IMAGE_FORMATS desired_formats,DWRITE_MEASURING_MODE measuring_mode,const DWRITE_MATRIX *transform,UINT32 palette,IDWriteColorGlyphRunEnumerator1 **layers) { + return This->lpVtbl->IDWriteFactory4_TranslateColorGlyphRun(This,baseline_origin,run,run_desc,desired_formats,measuring_mode,transform,palette,layers); +} +static FORCEINLINE HRESULT IDWriteFactory7_ComputeGlyphOrigins_(IDWriteFactory7* This,const DWRITE_GLYPH_RUN *run,D2D1_POINT_2F baseline_origin,D2D1_POINT_2F *origins) { + return This->lpVtbl->ComputeGlyphOrigins_(This,run,baseline_origin,origins); +} +static FORCEINLINE HRESULT IDWriteFactory7_ComputeGlyphOrigins(IDWriteFactory7* This,const DWRITE_GLYPH_RUN *run,DWRITE_MEASURING_MODE measuring_mode,D2D1_POINT_2F baseline_origin,const DWRITE_MATRIX *transform,D2D1_POINT_2F *origins) { + return This->lpVtbl->ComputeGlyphOrigins(This,run,measuring_mode,baseline_origin,transform,origins); +} +/*** IDWriteFactory5 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_CreateInMemoryFontFileLoader(IDWriteFactory7* This,IDWriteInMemoryFontFileLoader **loader) { + return This->lpVtbl->CreateInMemoryFontFileLoader(This,loader); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateHttpFontFileLoader(IDWriteFactory7* This,const WCHAR *referrer_url,const WCHAR *extra_headers,IDWriteRemoteFontFileLoader **loader) { + return This->lpVtbl->CreateHttpFontFileLoader(This,referrer_url,extra_headers,loader); +} +static FORCEINLINE DWRITE_CONTAINER_TYPE IDWriteFactory7_AnalyzeContainerType(IDWriteFactory7* This,const void *data,UINT32 data_size) { + return This->lpVtbl->AnalyzeContainerType(This,data,data_size); +} +static FORCEINLINE HRESULT IDWriteFactory7_UnpackFontFile(IDWriteFactory7* This,DWRITE_CONTAINER_TYPE container_type,const void *data,UINT32 data_size,IDWriteFontFileStream **stream) { + return This->lpVtbl->UnpackFontFile(This,container_type,data,data_size,stream); +} +/*** IDWriteFactory6 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_CreateFontFaceReference(IDWriteFactory7* This,IDWriteFontFile *file,UINT32 face_index,DWRITE_FONT_SIMULATIONS simulations,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_axis,IDWriteFontFaceReference1 **face_ref) { + return This->lpVtbl->IDWriteFactory6_CreateFontFaceReference(This,file,face_index,simulations,axis_values,num_axis,face_ref); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateFontResource(IDWriteFactory7* This,IDWriteFontFile *file,UINT32 face_index,IDWriteFontResource **resource) { + return This->lpVtbl->CreateFontResource(This,file,face_index,resource); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateFontCollectionFromFontSet(IDWriteFactory7* This,IDWriteFontSet *fontset,DWRITE_FONT_FAMILY_MODEL family_model,IDWriteFontCollection2 **collection) { + return This->lpVtbl->IDWriteFactory6_CreateFontCollectionFromFontSet(This,fontset,family_model,collection); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateFontSetBuilder(IDWriteFactory7* This,IDWriteFontSetBuilder2 **builder) { + return This->lpVtbl->IDWriteFactory6_CreateFontSetBuilder(This,builder); +} +static FORCEINLINE HRESULT IDWriteFactory7_CreateTextFormat(IDWriteFactory7* This,const WCHAR *familyname,IDWriteFontCollection *collection,const DWRITE_FONT_AXIS_VALUE *axis_values,UINT32 num_axis,FLOAT fontsize,const WCHAR *localename,IDWriteTextFormat3 **format) { + return This->lpVtbl->IDWriteFactory6_CreateTextFormat(This,familyname,collection,axis_values,num_axis,fontsize,localename,format); +} +/*** IDWriteFactory7 methods ***/ +static FORCEINLINE HRESULT IDWriteFactory7_GetSystemFontSet(IDWriteFactory7* This,WINBOOL include_downloadable,IDWriteFontSet2 **fontset) { + return This->lpVtbl->IDWriteFactory7_GetSystemFontSet(This,include_downloadable,fontset); +} +static FORCEINLINE HRESULT IDWriteFactory7_GetSystemFontCollection(IDWriteFactory7* This,WINBOOL include_downloadable,DWRITE_FONT_FAMILY_MODEL family_model,IDWriteFontCollection3 **collection) { + return This->lpVtbl->IDWriteFactory7_GetSystemFontCollection(This,include_downloadable,family_model,collection); +} +#endif +#endif + +#endif + + +#endif /* __IDWriteFactory7_INTERFACE_DEFINED__ */ + +/* Begin additional prototypes for all interfaces */ + + +/* End additional prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __dwrite_3_h__ */ From ec506edbbc1e0b075806420f6f62c31cfa9dd82b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 10 Mar 2021 11:49:50 +0100 Subject: [PATCH 378/668] Add flag BUILD_SHARED_LIBS=OFF --- .github/workflows/build.yml | 12 ++++++++---- scripts/appveyor/before_build.cmd | 1 + scripts/appveyor/before_build.sh | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfd21976..85f104fb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,7 +72,8 @@ jobs: -DSFIZZ_SHARED=OFF \ -DSFIZZ_STATIC_DEPENDENCIES=OFF \ -DSFIZZ_LV2=ON \ - -DCMAKE_CXX_STANDARD=17 + -DCMAKE_CXX_STANDARD=17 \ + -DBUILD_SHARED_LIBS=OFF - name: Build shell: bash working-directory: ${{runner.workspace}}/build @@ -118,7 +119,8 @@ jobs: run: | mod-plugin-builder /usr/local/bin/cmake "$GITHUB_WORKSPACE" \ -DSFIZZ_SYSTEM_PROCESSOR=armv7-a \ - -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_VST=OFF -DSFIZZ_LV2_UI=OFF + -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_VST=OFF -DSFIZZ_LV2_UI=OFF \ + -DBUILD_SHARED_LIBS=OFF - name: Build shell: bash working-directory: ${{runner.workspace}}/build @@ -187,7 +189,8 @@ jobs: -DSFIZZ_JACK=OFF \ -DSFIZZ_VST=ON \ -DSFIZZ_STATIC_DEPENDENCIES=ON \ - -DCMAKE_CXX_STANDARD=17 + -DCMAKE_CXX_STANDARD=17 \ + -DBUILD_SHARED_LIBS=OFF - name: Build shell: bash working-directory: ${{runner.workspace}}/build @@ -256,7 +259,8 @@ jobs: -DSFIZZ_JACK=OFF \ -DSFIZZ_VST=ON \ -DSFIZZ_STATIC_DEPENDENCIES=ON \ - -DCMAKE_CXX_STANDARD=17 + -DCMAKE_CXX_STANDARD=17 \ + -DBUILD_SHARED_LIBS=OFF - name: Build shell: bash working-directory: ${{runner.workspace}}/build diff --git a/scripts/appveyor/before_build.cmd b/scripts/appveyor/before_build.cmd index 0b7804cd..8742946c 100644 --- a/scripts/appveyor/before_build.cmd +++ b/scripts/appveyor/before_build.cmd @@ -11,5 +11,6 @@ cmake .. -G"Visual Studio 16 2019" -A"%RELEASE_ARCH%"^ -DSFIZZ_LV2=ON^ -DSFIZZ_VST=ON^ -DCMAKE_BUILD_TYPE=Release^ + -DBUILD_SHARED_LIBS=OFF^ -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET%^ -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake diff --git a/scripts/appveyor/before_build.sh b/scripts/appveyor/before_build.sh index 213ab8a3..48e2e70a 100644 --- a/scripts/appveyor/before_build.sh +++ b/scripts/appveyor/before_build.sh @@ -10,6 +10,7 @@ cmake -DCMAKE_BUILD_TYPE=Release \ -DSFIZZ_SHARED=OFF \ -DSFIZZ_TESTS=ON \ -DCMAKE_CXX_STANDARD=14 \ + -DBUILD_SHARED_LIBS=OFF \ -DLV2PLUGIN_INSTALL_DIR=/ \ -DVSTPLUGIN_INSTALL_DIR=/ \ -DAUPLUGIN_INSTALL_DIR=/ \ From 982116a050933878a0e7320523101ca3ce010650 Mon Sep 17 00:00:00 2001 From: redtide Date: Wed, 10 Mar 2021 12:16:15 +0100 Subject: [PATCH 379/668] Don't use VSTGUI::CNewFileSelector::setDefaultExtension This fixes a wrong file extension filter in the file dialog under Windows. It seems that the last added extension is selected as default one due to some wrong selection index. So use the All Files filter as workaround. --- plugins/editor/src/editor/Editor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 9a6568c5..fba6c418 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -1067,7 +1067,7 @@ void Editor::Impl::chooseSfzFile() SharedPointer fs = owned(CNewFileSelector::create(frame_)); fs->setTitle("Load SFZ file"); - fs->setDefaultExtension(CFileExtension("SFZ", "sfz")); + fs->addFileExtension(CFileExtension("SFZ", "sfz")); // also add extensions of importable files fs->addFileExtension(CFileExtension("WAV", "wav")); @@ -1110,7 +1110,7 @@ void Editor::Impl::createNewSfzFile() SharedPointer fs = owned(CNewFileSelector::create(frame_, CNewFileSelector::kSelectSaveFile)); fs->setTitle("Create SFZ file"); - fs->setDefaultExtension(CFileExtension("SFZ", "sfz")); + fs->addFileExtension(CFileExtension("SFZ", "sfz")); std::string initialDir = getFileChooserInitialDir(currentSfzFile_); if (!initialDir.empty()) @@ -1202,7 +1202,7 @@ void Editor::Impl::chooseScalaFile() SharedPointer fs = owned(CNewFileSelector::create(frame_)); fs->setTitle("Load Scala file"); - fs->setDefaultExtension(CFileExtension("SCL", "scl")); + fs->addFileExtension(CFileExtension("SCL", "scl")); std::string initialDir = getFileChooserInitialDir(currentScalaFile_); if (!initialDir.empty()) From 97c9411f8d5fc41905bc3f3c2641894838f4fe60 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 9 Mar 2021 18:43:59 +0100 Subject: [PATCH 380/668] Refactor the opcode handling for LFO and EG --- src/sfizz/Opcode.cpp | 22 + src/sfizz/Opcode.h | 6 + src/sfizz/Region.cpp | 942 ++++++++++++++++++------------------------- src/sfizz/Region.h | 16 + 4 files changed, 444 insertions(+), 542 deletions(-) diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 47fbb98f..79ac2eac 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -53,6 +53,28 @@ static absl::string_view extractBackInteger(absl::string_view opcodeName) return opcodeName.substr(i); } +std::string Opcode::getLetterOnlyName() const +{ + absl::string_view name { this->name }; + + std::string letterOnlyName; + letterOnlyName.reserve(name.size()); + + bool charWasDigit = false; + for (unsigned char c : name) { + bool charIsDigit = absl::ascii_isdigit(c); + + if (!charIsDigit) + letterOnlyName.push_back(c); + else if (!charWasDigit) + letterOnlyName.push_back('&'); + + charWasDigit = charIsDigit; + } + + return letterOnlyName; +} + std::string Opcode::getDerivedName(OpcodeCategory newCategory, unsigned number) const { std::string derivedName(name); diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index ad4d4acc..0982a678 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -82,6 +82,12 @@ struct Opcode { */ Opcode cleanUp(OpcodeScope scope) const; + /** + * @brief Calculate a letter-only name, replacing any digit sequence with + * in the opcode name with a single ampersand character. + */ + std::string getLetterOnlyName() const; + /* * @brief Get the derived opcode name to convert it to another category. * diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 6283cbf4..453e432f 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -14,6 +14,7 @@ #include "modulations/ModId.h" #include "absl/strings/str_replace.h" #include "absl/strings/str_cat.h" +#include "absl/strings/match.h" #include "absl/algorithm/container.h" #include #include @@ -45,32 +46,18 @@ sfz::Region::Region(int regionNumber, const MidiState& midiState, absl::string_v amplitudeEG.release = Default::egRelease; } +// Helper for ccN processing +#define case_any_ccN(x) \ + case hash(x "_oncc&"): \ + case hash(x "_curvecc&"): \ + case hash(x "_stepcc&"): \ + case hash(x "_smoothcc&") + bool sfz::Region::parseOpcode(const Opcode& rawOpcode) { const Opcode opcode = rawOpcode.cleanUp(kOpcodeScopeRegion); switch (opcode.lettersOnlyHash) { - // Helper for ccN processing - #define case_any_ccN(x) \ - case hash(x "_oncc&"): \ - case hash(x "_curvecc&"): \ - case hash(x "_stepcc&"): \ - case hash(x "_smoothcc&") - - #define LFO_EG_filter_EQ_target(sourceKey, targetKey, spec) \ - { \ - const auto number = opcode.parameters.front(); \ - if (number == 0) \ - return false; \ - \ - const auto index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; \ - if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \ - return false; \ - \ - const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \ - const ModKey target = ModKey::createNXYZ(targetKey, id, index); \ - getOrCreateConnection(source, target).sourceDepth = opcode.read(spec); \ - } // Sound source: sample playback case hash("sample"): @@ -747,523 +734,6 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) bendSmooth = opcode.read(Default::smoothCC); break; - // Modulation: LFO - case hash("lfo&_freq"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - lfos[lfoNumber - 1].freq = opcode.read(Default::lfoFreq); - } - break; - case_any_ccN("lfo&_freq"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - processGenericCc(opcode, Default::lfoFreqMod, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber - 1)); - } - break; - case hash("lfo&_beats"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - lfos[lfoNumber - 1].beats = opcode.read(Default::lfoBeats); - } - break; - case_any_ccN("lfo&_beats"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - processGenericCc(opcode, Default::lfoBeatsMod, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber - 1)); - } - break; - case hash("lfo&_phase"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - lfos[lfoNumber - 1].phase0 = opcode.read(Default::lfoPhase); - } - break; - case hash("lfo&_delay"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - lfos[lfoNumber - 1].delay = opcode.read(Default::lfoDelay); - } - break; - case hash("lfo&_fade"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - lfos[lfoNumber - 1].fade = opcode.read(Default::lfoFade); - } - break; - case hash("lfo&_count"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - lfos[lfoNumber - 1].count = opcode.read(Default::lfoCount); - } - break; - case hash("lfo&_steps"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - if (!lfos[lfoNumber - 1].seq) - lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); - lfos[lfoNumber - 1].seq->steps.resize(opcode.read(Default::lfoSteps)); - } - break; - case hash("lfo&_step&"): - { - const auto lfoNumber = opcode.parameters.front(); - const auto stepNumber = opcode.parameters[1]; - if (lfoNumber == 0 || stepNumber == 0 || stepNumber > config::maxLFOSteps) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - if (!lfos[lfoNumber - 1].seq) - lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); - if (!extendIfNecessary(lfos[lfoNumber - 1].seq->steps, stepNumber, Default::numLFOSteps)) - return false; - lfos[lfoNumber - 1].seq->steps[stepNumber - 1] = opcode.read(Default::lfoStepX); - } - break; - case hash("lfo&_wave&"): // also lfo&_wave - { - const auto lfoNumber = opcode.parameters.front(); - const auto subNumber = opcode.parameters[1]; - if (lfoNumber == 0 || subNumber == 0 || subNumber > config::maxLFOSubs) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].wave = opcode.read(Default::lfoWave); - } - break; - case hash("lfo&_offset&"): // also lfo&_offset - { - const auto lfoNumber = opcode.parameters.front(); - const auto subNumber = opcode.parameters[1]; - if (lfoNumber == 0 || subNumber == 0 || subNumber > config::maxLFOSubs) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].offset = opcode.read(Default::lfoOffset); - } - break; - case hash("lfo&_ratio&"): // also lfo&_ratio - { - const auto lfoNumber = opcode.parameters.front(); - const auto subNumber = opcode.parameters[1]; - if (lfoNumber == 0 || subNumber == 0 || subNumber > config::maxLFOSubs) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].ratio = opcode.read(Default::lfoRatio); - } - break; - case hash("lfo&_scale&"): // also lfo&_scale - { - const auto lfoNumber = opcode.parameters.front(); - const auto subNumber = opcode.parameters[1]; - if (lfoNumber == 0 || subNumber == 0 || subNumber > config::maxLFOSubs) - return false; - if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) - return false; - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].scale = opcode.read(Default::lfoScale); - } - break; - - // Modulation: LFO (targets) - case hash("lfo&_amplitude"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::amplitudeMod); - } - break; - case hash("lfo&_pan"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pan, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::panMod); - } - break; - case hash("lfo&_width"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Width, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::widthMod); - } - break; - case hash("lfo&_position"): // sfizz extension - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Position, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::positionMod); - } - break; - case hash("lfo&_pitch"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::pitchMod); - } - break; - case hash("lfo&_volume"): - { - const auto lfoNumber = opcode.parameters.front(); - if (lfoNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Volume, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::volumeMod); - } - break; - case hash("lfo&_cutoff&"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffMod); - break; - case hash("lfo&_resonance&"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceMod); - break; - case hash("lfo&_fil&gain"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainMod); - break; - case hash("lfo&_eq&gain"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainMod); - break; - case hash("lfo&_eq&freq"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyMod); - break; - case hash("lfo&_eq&bw"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthMod); - break; - - // Modulation: Flex EG (targets) - case hash("eg&_amplitude"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::amplitudeMod); - } - break; - case hash("eg&_pan"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pan, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::panMod); - } - break; - case hash("eg&_width"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Width, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::widthMod); - } - break; - case hash("eg&_position"): // sfizz extension - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Position, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::positionMod); - } - break; - case hash("eg&_pitch"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::pitchMod); - } - break; - case hash("eg&_volume"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Volume, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::volumeMod); - } - break; - case hash("eg&_cutoff&"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffMod); - break; - case hash("eg&_resonance&"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceMod); - break; - case hash("eg&_fil&gain"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainMod); - break; - case hash("eg&_eq&gain"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainMod); - break; - case hash("eg&_eq&freq"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyMod); - break; - case hash("eg&_eq&bw"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthMod); - break; - - case hash("eg&_ampeg"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) - return false; - auto ampeg = opcode.read(Default::flexEGAmpeg); - FlexEGDescription& desc = flexEGs[egNumber - 1]; - if (desc.ampeg != ampeg) { - desc.ampeg = ampeg; - flexAmpEG = absl::nullopt; - for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) { - if (flexEGs[i].ampeg) - flexAmpEG = static_cast(i); - } - } - break; - } - - // Amplitude Envelope - case hash("ampeg_attack"): - case hash("ampeg_decay"): - case hash("ampeg_delay"): - case hash("ampeg_hold"): - case hash("ampeg_release"): - case hash("ampeg_start"): - case hash("ampeg_sustain"): - case hash("ampeg_veltoattack"): // also ampeg_vel2attack - case hash("ampeg_veltodecay"): // also ampeg_vel2decay - case hash("ampeg_veltodelay"): // also ampeg_vel2delay - case hash("ampeg_veltohold"): // also ampeg_vel2hold - case hash("ampeg_veltorelease"): // also ampeg_vel2release - case hash("ampeg_veltosustain"): // also ampeg_vel2sustain - case hash("ampeg_attack_oncc&"): // also ampeg_attackcc& - case hash("ampeg_decay_oncc&"): // also ampeg_decaycc& - case hash("ampeg_delay_oncc&"): // also ampeg_delaycc& - case hash("ampeg_hold_oncc&"): // also ampeg_holdcc& - case hash("ampeg_release_oncc&"): // also ampeg_releasecc& - case hash("ampeg_start_oncc&"): // also ampeg_startcc& - case hash("ampeg_sustain_oncc&"): // also ampeg_sustaincc& - parseEGOpcode(opcode, amplitudeEG); - break; - - case hash("pitcheg_attack"): - case hash("pitcheg_decay"): - case hash("pitcheg_delay"): - case hash("pitcheg_hold"): - case hash("pitcheg_release"): - case hash("pitcheg_start"): - case hash("pitcheg_sustain"): - case hash("pitcheg_veltoattack"): // also pitcheg_vel2attack - case hash("pitcheg_veltodecay"): // also pitcheg_vel2decay - case hash("pitcheg_veltodelay"): // also pitcheg_vel2delay - case hash("pitcheg_veltohold"): // also pitcheg_vel2hold - case hash("pitcheg_veltorelease"): // also pitcheg_vel2release - case hash("pitcheg_veltosustain"): // also pitcheg_vel2sustain - case hash("pitcheg_attack_oncc&"): // also pitcheg_attackcc& - case hash("pitcheg_decay_oncc&"): // also pitcheg_decaycc& - case hash("pitcheg_delay_oncc&"): // also pitcheg_delaycc& - case hash("pitcheg_hold_oncc&"): // also pitcheg_holdcc& - case hash("pitcheg_release_oncc&"): // also pitcheg_releasecc& - case hash("pitcheg_start_oncc&"): // also pitcheg_startcc& - case hash("pitcheg_sustain_oncc&"): // also pitcheg_sustaincc& - if (parseEGOpcode(opcode, pitchEG)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::PitchEG, id), - ModKey::createNXYZ(ModId::Pitch, id)); - break; - - case hash("fileg_attack"): - case hash("fileg_decay"): - case hash("fileg_delay"): - case hash("fileg_hold"): - case hash("fileg_release"): - case hash("fileg_start"): - case hash("fileg_sustain"): - case hash("fileg_veltoattack"): // also fileg_vel2attack - case hash("fileg_veltodecay"): // also fileg_vel2decay - case hash("fileg_veltodelay"): // also fileg_vel2delay - case hash("fileg_veltohold"): // also fileg_vel2hold - case hash("fileg_veltorelease"): // also fileg_vel2release - case hash("fileg_veltosustain"): // also fileg_vel2sustain - case hash("fileg_attack_oncc&"): // also fileg_attackcc& - case hash("fileg_decay_oncc&"): // also fileg_decaycc& - case hash("fileg_delay_oncc&"): // also fileg_delaycc& - case hash("fileg_hold_oncc&"): // also fileg_holdcc& - case hash("fileg_release_oncc&"): // also fileg_releasecc& - case hash("fileg_start_oncc&"): // also fileg_startcc& - case hash("fileg_sustain_oncc&"): // also fileg_sustaincc& - if (parseEGOpcode(opcode, filterEG)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)); - break; - - case hash("pitcheg_depth"): - getOrCreateConnection( - ModKey::createNXYZ(ModId::PitchEG, id), - ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = opcode.read(Default::egDepth); - break; - case hash("fileg_depth"): - getOrCreateConnection( - ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = opcode.read(Default::egDepth); - break; - - case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth - getOrCreateConnection( - ModKey::createNXYZ(ModId::PitchEG, id), - ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = opcode.read(Default::egVel2Depth); - break; - case hash("fileg_veltodepth"): // also fileg_vel2depth - getOrCreateConnection( - ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = opcode.read(Default::egVel2Depth); - break; - - // Flex envelopes - case hash("eg&_dynamic"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) - return false; - auto& eg = flexEGs[egNumber - 1]; - eg.dynamic = opcode.read(Default::flexEGDynamic); - } - break; - case hash("eg&_sustain"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) - return false; - auto& eg = flexEGs[egNumber - 1]; - eg.sustain = opcode.read(Default::flexEGSustain); - } - break; - case hash("eg&_time&"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) - return false; - auto& eg = flexEGs[egNumber - 1]; - const auto pointNumber = opcode.parameters[1]; - if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) - return false; - eg.points[pointNumber].time = opcode.read(Default::flexEGPointTime); - } - break; - case hash("eg&_level&"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) - return false; - auto& eg = flexEGs[egNumber - 1]; - const auto pointNumber = opcode.parameters[1]; - if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) - return false; - eg.points[pointNumber].level = opcode.read(Default::flexEGPointLevel); - } - break; - case hash("eg&_shape&"): - { - const auto egNumber = opcode.parameters.front(); - if (egNumber == 0) - return false; - if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) - return false; - auto& eg = flexEGs[egNumber - 1]; - const auto pointNumber = opcode.parameters[1]; - if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) - return false; - eg.points[pointNumber].setShape(opcode.read(Default::flexEGPointShape)); - } - break; - case hash("effect&"): { const auto effectNumber = opcode.parameters.back(); @@ -1284,11 +754,49 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("ampeg_depth"): case hash("ampeg_veltodepth"): // also ampeg_vel2depth break; - default: - return false; - #undef case_any_ccN - #undef LFO_EG_filter_EQ_target + default: { + // Amplitude Envelope + if (absl::StartsWith(opcode.name, "ampeg_")) { + if (parseEGOpcode(opcode, amplitudeEG)) + return true; + } + // Pitch Envelope + if (absl::StartsWith(opcode.name, "pitcheg_")) { + if (parseEGOpcode(opcode, pitchEG)) { + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchEG, id), + ModKey::createNXYZ(ModId::Pitch, id)); + return true; + } + } + // Filter Envelope + if (absl::StartsWith(opcode.name, "fileg_")) { + if (parseEGOpcode(opcode, filterEG)) { + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilEG, id), + ModKey::createNXYZ(ModId::FilCutoff, id)); + return true; + } + } + + // + const std::string letterOnlyName = opcode.getLetterOnlyName(); + + // Modulation: LFO + if (absl::StartsWith(letterOnlyName, "lfo&_")) { + if (parseLFOOpcodeV2(opcode)) + return true; + } + // Modulation: Flex EG + if (absl::StartsWith(letterOnlyName, "eg&_")) { + if (parseEGOpcodeV2(opcode)) + return true; + } + + return false; + } + } return true; @@ -1390,6 +898,29 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) eg.ccSustain[opcode.parameters.back()] = opcode.read(Default::egPercentMod); break; + + case hash("pitcheg_depth"): + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchEG, id), + ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = opcode.read(Default::egDepth); + break; + case hash("fileg_depth"): + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilEG, id), + ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = opcode.read(Default::egDepth); + break; + + case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchEG, id), + ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = opcode.read(Default::egVel2Depth); + break; + case hash("fileg_veltodepth"): // also fileg_vel2depth + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilEG, id), + ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = opcode.read(Default::egVel2Depth); + break; + default: return false; } @@ -1412,6 +943,333 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, absl::optional float* { + const unsigned stepNumber1Based = opcode.parameters[1]; + if (stepNumber1Based <= 0 || stepNumber1Based > config::maxLFOSteps) + return nullptr; + if (!lfo.seq) + lfo.seq = LFODescription::StepSequence(); + if (!extendIfNecessary(lfo.seq->steps, stepNumber1Based, Default::numLFOSteps)) + return nullptr; + return &lfo.seq->steps[stepNumber1Based - 1]; + }; + auto getOrCreateLFOSub = [&opcode, &lfo]() -> LFODescription::Sub* { + const unsigned subNumber1Based = opcode.parameters[1]; + if (subNumber1Based <= 0 || subNumber1Based > config::maxLFOSubs) + return nullptr; + if (!extendIfNecessary(lfo.sub, subNumber1Based, Default::numLFOSubs)) + return nullptr; + return &lfo.sub[subNumber1Based - 1]; + }; + auto LFO_EG_filter_EQ_target = [this, &opcode, lfoNumber](ModId sourceId, ModId targetId, const OpcodeSpec& spec) -> bool { + const unsigned index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; + if (!extendIfNecessary(filters, index + 1, Default::numFilters)) + return false; + const ModKey source = ModKey::createNXYZ(sourceId, id, lfoNumber); + const ModKey target = ModKey::createNXYZ(targetId, id, index); + getOrCreateConnection(source, target).sourceDepth = opcode.read(spec); + return true; + }; + + // + switch (opcode.lettersOnlyHash) { + + // Modulation: LFO + case hash("lfo&_freq"): + lfo.freq = opcode.read(Default::lfoFreq); + break; + case_any_ccN("lfo&_freq"): + processGenericCc(opcode, Default::lfoFreqMod, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber)); + break; + case hash("lfo&_beats"): + lfo.beats = opcode.read(Default::lfoBeats); + break; + case_any_ccN("lfo&_beats"): + processGenericCc(opcode, Default::lfoBeatsMod, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber)); + break; + case hash("lfo&_phase"): + lfo.phase0 = opcode.read(Default::lfoPhase); + break; + case hash("lfo&_delay"): + lfo.delay = opcode.read(Default::lfoDelay); + break; + case hash("lfo&_fade"): + lfo.fade = opcode.read(Default::lfoFade); + break; + case hash("lfo&_count"): + lfo.count = opcode.read(Default::lfoCount); + break; + case hash("lfo&_steps"): + if (!lfo.seq) + lfo.seq = LFODescription::StepSequence(); + lfo.seq->steps.resize(opcode.read(Default::lfoSteps)); + break; + case hash("lfo&_step&"): + if (float* step = getOrCreateLFOStep()) + *step = opcode.read(Default::lfoStepX); + else + return false; + break; + case hash("lfo&_wave&"): // also lfo&_wave + if (LFODescription::Sub* sub = getOrCreateLFOSub()) + sub->wave = opcode.read(Default::lfoWave); + else + return false; + break; + case hash("lfo&_offset&"): // also lfo&_offset + if (LFODescription::Sub* sub = getOrCreateLFOSub()) + sub->offset = opcode.read(Default::lfoOffset); + else + return false; + break; + case hash("lfo&_ratio&"): // also lfo&_ratio + if (LFODescription::Sub* sub = getOrCreateLFOSub()) + sub->ratio = opcode.read(Default::lfoRatio); + else + return false; + break; + case hash("lfo&_scale&"): // also lfo&_scale + if (LFODescription::Sub* sub = getOrCreateLFOSub()) + sub->scale = opcode.read(Default::lfoScale); + else + return false; + break; + + // Modulation: LFO (targets) + case hash("lfo&_amplitude"): + { + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); + const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::amplitudeMod); + } + break; + case hash("lfo&_pan"): + { + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); + const ModKey target = ModKey::createNXYZ(ModId::Pan, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::panMod); + } + break; + case hash("lfo&_width"): + { + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); + const ModKey target = ModKey::createNXYZ(ModId::Width, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::widthMod); + } + break; + case hash("lfo&_position"): // sfizz extension + { + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); + const ModKey target = ModKey::createNXYZ(ModId::Position, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::positionMod); + } + break; + case hash("lfo&_pitch"): + { + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); + const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::pitchMod); + } + break; + case hash("lfo&_volume"): + { + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); + const ModKey target = ModKey::createNXYZ(ModId::Volume, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::volumeMod); + } + break; + + case hash("lfo&_cutoff&"): + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffMod); + break; + case hash("lfo&_resonance&"): + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceMod); + break; + case hash("lfo&_fil&gain"): + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainMod); + break; + case hash("lfo&_eq&gain"): + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainMod); + break; + case hash("lfo&_eq&freq"): + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyMod); + break; + case hash("lfo&_eq&bw"): + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthMod); + break; + + default: + return false; + } + + return true; +} + +bool sfz::Region::parseEGOpcodeV2(const Opcode& opcode) +{ + const unsigned egNumber1Based = opcode.parameters.front(); + if (egNumber1Based <= 0) + return false; + if (!extendIfNecessary(flexEGs, egNumber1Based, Default::numFlexEGs)) + return false; + + const unsigned egNumber = egNumber1Based - 1; + FlexEGDescription& eg = flexEGs[egNumber]; + + // + auto getOrCreateEGPoint = [&opcode, &eg]() -> FlexEGPoint* { + const auto pointNumber = opcode.parameters[1]; + if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) + return nullptr; + return &eg.points[pointNumber]; + }; + auto LFO_EG_filter_EQ_target = [this, &opcode, egNumber](ModId sourceId, ModId targetId, const OpcodeSpec& spec) -> bool { + const unsigned index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; + if (!extendIfNecessary(filters, index + 1, Default::numFilters)) + return false; + const ModKey source = ModKey::createNXYZ(sourceId, id, egNumber); + const ModKey target = ModKey::createNXYZ(targetId, id, index); + getOrCreateConnection(source, target).sourceDepth = opcode.read(spec); + return true; + }; + + // + switch (opcode.lettersOnlyHash) { + + // Flex envelopes + case hash("eg&_dynamic"): + eg.dynamic = opcode.read(Default::flexEGDynamic); + break; + case hash("eg&_sustain"): + eg.sustain = opcode.read(Default::flexEGSustain); + break; + case hash("eg&_time&"): + if (FlexEGPoint* point = getOrCreateEGPoint()) + point->time = opcode.read(Default::flexEGPointTime); + else + return false; + break; + case hash("eg&_level&"): + if (FlexEGPoint* point = getOrCreateEGPoint()) + point->level = opcode.read(Default::flexEGPointLevel); + else + return false; + break; + case hash("eg&_shape&"): + if (FlexEGPoint* point = getOrCreateEGPoint()) + point->setShape(opcode.read(Default::flexEGPointShape)); + else + return false; + break; + + // Modulation: Flex EG (targets) + case hash("eg&_amplitude"): + { + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); + const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::amplitudeMod); + } + break; + case hash("eg&_pan"): + { + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); + const ModKey target = ModKey::createNXYZ(ModId::Pan, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::panMod); + } + break; + case hash("eg&_width"): + { + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); + const ModKey target = ModKey::createNXYZ(ModId::Width, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::widthMod); + } + break; + case hash("eg&_position"): // sfizz extension + { + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); + const ModKey target = ModKey::createNXYZ(ModId::Position, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::positionMod); + } + break; + case hash("eg&_pitch"): + { + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); + const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::pitchMod); + } + break; + case hash("eg&_volume"): + { + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); + const ModKey target = ModKey::createNXYZ(ModId::Volume, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::volumeMod); + } + break; + case hash("eg&_cutoff&"): + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffMod); + break; + case hash("eg&_resonance&"): + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceMod); + break; + case hash("eg&_fil&gain"): + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainMod); + break; + case hash("eg&_eq&gain"): + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainMod); + break; + case hash("eg&_eq&freq"): + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyMod); + break; + case hash("eg&_eq&bw"): + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthMod); + break; + + case hash("eg&_ampeg"): + { + auto ampeg = opcode.read(Default::flexEGAmpeg); + if (eg.ampeg != ampeg) { + eg.ampeg = ampeg; + flexAmpEG = absl::nullopt; + for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) { + if (flexEGs[i].ampeg) + flexAmpEG = static_cast(i); + } + } + break; + } + + default: + return false; + } + + return true; +} + bool sfz::Region::processGenericCc(const Opcode& opcode, OpcodeSpec spec, const ModKey& target) { if (!opcode.isAnyCcN()) diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index bb72cfd4..5330ee84 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -266,6 +266,22 @@ struct Region { * @return false */ bool parseEGOpcode(const Opcode& opcode, absl::optional& eg); + /** + * @brief Parse a opcode which is specific to a particular SFZv2 LFO: lfoN. + * + * @param opcode + * @return true if the opcode was properly read and stored. + * @return false + */ + bool parseLFOOpcodeV2(const Opcode& opcode); + /** + * @brief Parse a opcode which is specific to a particular SFZv2 EG: egN. + * + * @param opcode + * @return true if the opcode was properly read and stored. + * @return false + */ + bool parseEGOpcodeV2(const Opcode& opcode); /** * @brief Process a generic CC opcode, and fill the modulation parameters. * From dfd777fd3e039eb318e71e2670e5aa7c63b9cd55 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 10 Mar 2021 14:18:09 +0100 Subject: [PATCH 381/668] Move LFO modulation keys into the description --- demos/PlotLFO.cpp | 3 +-- src/sfizz/LFO.cpp | 32 +++++++++------------------ src/sfizz/LFO.h | 7 ++---- src/sfizz/LFODescription.h | 5 +++++ src/sfizz/Region.cpp | 4 ++++ src/sfizz/Voice.cpp | 3 +-- src/sfizz/modulations/sources/LFO.cpp | 2 +- tests/LFOT.cpp | 3 +-- 8 files changed, 26 insertions(+), 33 deletions(-) diff --git a/demos/PlotLFO.cpp b/demos/PlotLFO.cpp index 680ee721..57e94f51 100644 --- a/demos/PlotLFO.cpp +++ b/demos/PlotLFO.cpp @@ -116,8 +116,7 @@ int main(int argc, char* argv[]) std::vector> lfos(numLfos); for (size_t l = 0; l < numLfos; ++l) { - const NumericId id { static_cast(l) }; - sfz::LFO* lfo = new sfz::LFO(id, bufferPool); + sfz::LFO* lfo = new sfz::LFO(bufferPool); lfos[l].reset(lfo); lfo->setSampleRate(sampleRate); lfo->configure(&desc[l]); diff --git a/src/sfizz/LFO.cpp b/src/sfizz/LFO.cpp index 053ef1b1..24aa8d6e 100644 --- a/src/sfizz/LFO.cpp +++ b/src/sfizz/LFO.cpp @@ -21,9 +21,8 @@ namespace sfz { struct LFO::Impl { - explicit Impl(NumericId id, BufferPool& bufferPool, BeatClock* beatClock, ModMatrix* modMatrix) - : id_(id), - bufferPool_(bufferPool), + explicit Impl(BufferPool& bufferPool, BeatClock* beatClock, ModMatrix* modMatrix) + : bufferPool_(bufferPool), beatClock_(beatClock), modMatrix_(modMatrix), sampleRate_(config::defaultSampleRate), @@ -31,7 +30,6 @@ struct LFO::Impl { { } - NumericId id_; BufferPool& bufferPool_; BeatClock* beatClock_ = nullptr; ModMatrix* modMatrix_ = nullptr; @@ -48,8 +46,8 @@ struct LFO::Impl { std::array sampleHoldState_ {{}}; }; -LFO::LFO(NumericId id, BufferPool& bufferPool, BeatClock* beatClock, ModMatrix* modMatrix) - : impl_(new Impl(id, bufferPool, beatClock, modMatrix)) +LFO::LFO(BufferPool& bufferPool, BeatClock* beatClock, ModMatrix* modMatrix) + : impl_(new Impl(bufferPool, beatClock, modMatrix)) { } @@ -57,11 +55,6 @@ LFO::~LFO() { } -NumericId LFO::getId() const noexcept -{ - return impl_->id_; -} - void LFO::setSampleRate(double sampleRate) { impl_->sampleRate_ = sampleRate; @@ -221,7 +214,7 @@ void LFO::processSteps(absl::Span out, const float* phaseIn) } } -void LFO::process(absl::Span out, NumericId regionId) +void LFO::process(absl::Span out) { Impl& impl = *impl_; const LFODescription& desc = *impl.desc_; @@ -252,13 +245,13 @@ void LFO::process(absl::Span out, NumericId regionId) absl::Span phases = *phasesTemp; if (desc.seq) { - generatePhase(0, phases, regionId); + generatePhase(0, phases); processSteps(out, phases.data()); ++subno; } for (; subno < countSubs; ++subno) { - generatePhase(subno, phases, regionId); + generatePhase(subno, phases); switch (desc.sub[subno].wave) { case LFOWave::Triangle: processWave(subno, out, phases.data()); @@ -315,13 +308,12 @@ void LFO::processFadeIn(absl::Span out) impl.fadePosition_ = fadePosition; } -void LFO::generatePhase(unsigned nth, absl::Span phases, NumericId regionId) +void LFO::generatePhase(unsigned nth, absl::Span phases) { Impl& impl = *impl_; BufferPool& bufferPool = impl.bufferPool_; BeatClock* beatClock = impl.beatClock_; ModMatrix* modMatrix = impl.modMatrix_; - const NumericId id { impl.id_ }; const LFODescription& desc = *impl.desc_; const LFODescription::Sub& sub = desc.sub[nth]; const float samplePeriod = 1.0f / impl.sampleRate_; @@ -337,13 +329,11 @@ void LFO::generatePhase(unsigned nth, absl::Span phases, NumericIdgetModulationByKey(beatsKey); - freqMod = modMatrix->getModulationByKey(freqKey); + beatsMod = modMatrix->getModulationByKey(desc.beatsKey); + freqMod = modMatrix->getModulationByKey(desc.freqKey); } if (beatClock && beatClock->isPlaying() && beats > 0) { diff --git a/src/sfizz/LFO.h b/src/sfizz/LFO.h index caac1c27..ab2f415b 100644 --- a/src/sfizz/LFO.h +++ b/src/sfizz/LFO.h @@ -55,14 +55,11 @@ struct LFODescription; class LFO { public: explicit LFO( - NumericId id, BufferPool& bufferPool, BeatClock* beatClock = nullptr, ModMatrix* modMatrix = nullptr); ~LFO(); - NumericId getId() const noexcept; - /** Sets the sample rate. */ @@ -85,7 +82,7 @@ public: TODO(jpc) frequency modulations */ - void process(absl::Span out, NumericId regionId = {}); + void process(absl::Span out); private: /** @@ -123,7 +120,7 @@ private: /** Generate the phase of the N-th generator */ - void generatePhase(unsigned nth, absl::Span phases, NumericId regionId); + void generatePhase(unsigned nth, absl::Span phases); private: struct Impl; diff --git a/src/sfizz/LFODescription.h b/src/sfizz/LFODescription.h index 82859779..a4abfa62 100644 --- a/src/sfizz/LFODescription.h +++ b/src/sfizz/LFODescription.h @@ -6,6 +6,7 @@ #pragma once #include "Defaults.h" +#include "modulations/ModKey.h" #include #include @@ -32,6 +33,10 @@ struct LFODescription { }; absl::optional seq; std::vector sub; + + // modulations + ModKey beatsKey; + ModKey freqKey; }; } // namespace sfz diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 453e432f..feb7cb4a 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -955,6 +955,10 @@ bool sfz::Region::parseLFOOpcodeV2(const Opcode& opcode) const unsigned lfoNumber = lfoNumber1Based - 1; LFODescription& lfo = lfos[lfoNumber]; + // + lfo.beatsKey = ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber); + lfo.freqKey = ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber); + // auto getOrCreateLFOStep = [&opcode, &lfo]() -> float* { const unsigned stepNumber1Based = opcode.parameters[1]; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index e6a67170..dbffda04 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -1604,8 +1604,7 @@ void Voice::setMaxLFOsPerVoice(size_t numLFOs) impl.lfos_.resize(numLFOs); for (size_t i = 0; i < numLFOs; ++i) { - const NumericId id { static_cast(i) }; - auto lfo = absl::make_unique(id, resources.bufferPool, &resources.beatClock, &resources.modMatrix); + auto lfo = absl::make_unique(resources.bufferPool, &resources.beatClock, &resources.modMatrix); lfo->setSampleRate(impl.sampleRate_); impl.lfos_[i] = std::move(lfo); } diff --git a/src/sfizz/modulations/sources/LFO.cpp b/src/sfizz/modulations/sources/LFO.cpp index 206f0ca1..a485833d 100644 --- a/src/sfizz/modulations/sources/LFO.cpp +++ b/src/sfizz/modulations/sources/LFO.cpp @@ -59,7 +59,7 @@ void LFOSource::generate(const ModKey& sourceKey, NumericId voiceId, absl } LFO* lfo = voice->getLFO(lfoIndex); - lfo->process(buffer, region->getId()); + lfo->process(buffer); } } // namespace sfz diff --git a/tests/LFOT.cpp b/tests/LFOT.cpp index 26bd0fb1..486a8cc6 100644 --- a/tests/LFOT.cpp +++ b/tests/LFOT.cpp @@ -28,8 +28,7 @@ static bool computeLFO(DataPoints& dp, const fs::path& sfzPath, double sampleRat std::vector> lfos(numLfos); for (size_t l = 0; l < numLfos; ++l) { - const NumericId id { static_cast(l) }; - sfz::LFO* lfo = new sfz::LFO(id, resources.bufferPool); + sfz::LFO* lfo = new sfz::LFO(resources.bufferPool); lfos[l].reset(lfo); lfo->setSampleRate(sampleRate); lfo->configure(&desc[l]); From 3957668d0fc1040edfce2f15509e8401d0652f45 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 10 Mar 2021 14:44:50 +0100 Subject: [PATCH 382/668] Add modulation key for v1 LFOs --- src/sfizz/modulations/ModId.cpp | 6 ++++++ src/sfizz/modulations/ModId.h | 3 +++ src/sfizz/modulations/ModKey.cpp | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/src/sfizz/modulations/ModId.cpp b/src/sfizz/modulations/ModId.cpp index 374b0887..5bc66bc8 100644 --- a/src/sfizz/modulations/ModId.cpp +++ b/src/sfizz/modulations/ModId.cpp @@ -30,6 +30,12 @@ int ModIds::flags(ModId id) noexcept return kModIsPerVoice; case ModId::LFO: return kModIsPerVoice; + case ModId::AmpLFO: + return kModIsPerVoice; + case ModId::PitchLFO: + return kModIsPerVoice; + case ModId::FilLFO: + return kModIsPerVoice; case ModId::AmpEG: return kModIsPerVoice; case ModId::PitchEG: diff --git a/src/sfizz/modulations/ModId.h b/src/sfizz/modulations/ModId.h index 055dacdc..648ed8c7 100644 --- a/src/sfizz/modulations/ModId.h +++ b/src/sfizz/modulations/ModId.h @@ -23,6 +23,9 @@ enum class ModId : int { Controller = _SourcesStart, Envelope, LFO, + AmpLFO, + PitchLFO, + FilLFO, AmpEG, PitchEG, FilEG, diff --git a/src/sfizz/modulations/ModKey.cpp b/src/sfizz/modulations/ModKey.cpp index 1cb95991..4b61552c 100644 --- a/src/sfizz/modulations/ModKey.cpp +++ b/src/sfizz/modulations/ModKey.cpp @@ -99,6 +99,12 @@ std::string ModKey::toString() const return absl::StrCat("EG ", 1 + params_.N, " {", region_.number(), "}"); case ModId::LFO: return absl::StrCat("LFO ", 1 + params_.N, " {", region_.number(), "}"); + case ModId::AmpLFO: + return absl::StrCat("AmplitudeLFO {", region_.number(), "}"); + case ModId::PitchLFO: + return absl::StrCat("PitchLFO {", region_.number(), "}"); + case ModId::FilLFO: + return absl::StrCat("FilterLFO {", region_.number(), "}"); case ModId::AmpEG: return absl::StrCat("AmplitudeEG {", region_.number(), "}"); case ModId::PitchEG: From ef1a548d9883187abafdfbf684b5823107b92c9b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 10 Mar 2021 14:49:29 +0100 Subject: [PATCH 383/668] Add v1 LFOs in voices --- src/sfizz/Voice.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++ src/sfizz/Voice.h | 31 +++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index dbffda04..34b98c8d 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -241,6 +241,10 @@ struct Voice::Impl std::vector> lfos_; std::vector> flexEGs_; + std::unique_ptr lfoAmplitude_; + std::unique_ptr lfoPitch_; + std::unique_ptr lfoFilter_; + ADSREnvelope egAmplitude_; std::unique_ptr egPitch_; std::unique_ptr egFilter_; @@ -595,6 +599,12 @@ void Voice::setSampleRate(float sampleRate) noexcept for (auto& lfo : impl.lfos_) lfo->setSampleRate(sampleRate); + if (auto* lfo = impl.lfoAmplitude_.get()) + lfo->setSampleRate(sampleRate); + if (auto* lfo = impl.lfoPitch_.get()) + lfo->setSampleRate(sampleRate); + if (auto* lfo = impl.lfoFilter_.get()) + lfo->setSampleRate(sampleRate); for (auto& filter : impl.filters_) filter.setSampleRate(sampleRate); @@ -1640,6 +1650,45 @@ void Voice::setFilterEGEnabledPerVoice(bool haveFilterEG) impl.egFilter_.reset(); } +void Voice::setAmplitudeLFOEnabledPerVoice(bool haveAmplitudeLFO) +{ + Impl& impl = *impl_; + Resources& res = impl.resources_; + if (haveAmplitudeLFO) { + LFO* lfo = new LFO(res.bufferPool, &res.beatClock, &res.modMatrix); + impl.lfoAmplitude_.reset(lfo); + lfo->setSampleRate(impl.sampleRate_); + } + else + impl.lfoAmplitude_.reset(); +} + +void Voice::setPitchLFOEnabledPerVoice(bool havePitchLFO) +{ + Impl& impl = *impl_; + Resources& res = impl.resources_; + if (havePitchLFO) { + LFO* lfo = new LFO(res.bufferPool, &res.beatClock, &res.modMatrix); + impl.lfoPitch_.reset(lfo); + lfo->setSampleRate(impl.sampleRate_); + } + else + impl.lfoPitch_.reset(); +} + +void Voice::setFilterLFOEnabledPerVoice(bool haveFilterLFO) +{ + Impl& impl = *impl_; + Resources& res = impl.resources_; + if (haveFilterLFO) { + LFO* lfo = new LFO(res.bufferPool, &res.beatClock, &res.modMatrix); + impl.lfoFilter_.reset(lfo); + lfo->setSampleRate(impl.sampleRate_); + } + else + impl.lfoFilter_.reset(); +} + void Voice::Impl::setupOscillatorUnison() { const int m = region_->oscillatorMulti; @@ -1855,6 +1904,24 @@ Duration Voice::getLastPanningDuration() const noexcept return impl.panningDuration_; } +LFO* Voice::getAmplitudeLFO() +{ + Impl& impl = *impl_; + return impl.lfoAmplitude_.get(); +} + +LFO* Voice::getPitchLFO() +{ + Impl& impl = *impl_; + return impl.lfoPitch_.get(); +} + +LFO* Voice::getFilterLFO() +{ + Impl& impl = *impl_; + return impl.lfoFilter_.get(); +} + ADSREnvelope* Voice::getAmplitudeEG() { Impl& impl = *impl_; diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 34885cbb..595bf1c1 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -305,6 +305,24 @@ public: * @param haveFilterEG */ void setFilterEGEnabledPerVoice(bool haveFilterEG); + /** + * @brief Set whether SFZv1 amplitude LFO is enabled on this voice + * + * @param haveAmplitudeLFO + */ + void setAmplitudeLFOEnabledPerVoice(bool haveAmplitudeLFO); + /** + * @brief Set whether SFZv1 pitch LFO is enabled on this voice + * + * @param havePitchLFO + */ + void setPitchLFOEnabledPerVoice(bool havePitchLFO); + /** + * @brief Set whether SFZv1 filter LFO is enabled on this voice + * + * @param haveFilterLFO + */ + void setFilterLFOEnabledPerVoice(bool haveFilterLFO); /** * @brief Release the voice after a given delay * @@ -333,6 +351,19 @@ public: Duration getLastFilterDuration() const noexcept; Duration getLastPanningDuration() const noexcept; + /** + * @brief Get the SFZv1 amplitude LFO, if existing + */ + LFO* getAmplitudeLFO(); + /** + * @brief Get the SFZv1 pitch LFO, if existing + */ + LFO* getPitchLFO(); + /** + * @brief Get the SFZv1 filter LFO, if existing + */ + LFO* getFilterLFO(); + /** * @brief Get the SFZv1 amplitude EG, if existing */ From 7f2daa24e79d5ecbd7dbb1e0adc56400846bd08d Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 10 Mar 2021 15:07:14 +0100 Subject: [PATCH 384/668] Implement the LFOs v1 --- src/sfizz/Defaults.cpp | 3 + src/sfizz/Defaults.h | 3 + src/sfizz/Region.cpp | 131 ++++++++++++++++++++++++++ src/sfizz/Region.h | 23 +++++ src/sfizz/Synth.cpp | 15 +++ src/sfizz/SynthPrivate.h | 3 + src/sfizz/modulations/ModId.cpp | 6 ++ src/sfizz/modulations/ModId.h | 3 + src/sfizz/modulations/ModKey.cpp | 6 ++ src/sfizz/modulations/sources/LFO.cpp | 60 ++++++++++-- 10 files changed, 245 insertions(+), 8 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index a1ca1d14..7d9a5459 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -101,6 +101,9 @@ extern const OpcodeSpec pitchMod { 0.0f, Range(-2400.0f, 2400.0f), extern const OpcodeSpec bendUp { 200.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec bendDown { -200.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), 0 }; +extern const OpcodeSpec ampLFODepth { 0.0f, Range(-10.0f, 10.0f), 0 }; +extern const OpcodeSpec pitchLFODepth { 0.0f, Range(-1200.0f, 1200.0f), 0 }; +extern const OpcodeSpec filLFODepth { 0.0f, Range(-1200.0f, 1200.0f), 0 }; extern const OpcodeSpec lfoFreq { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec lfoFreqMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec lfoBeats { 0.0f, Range(0.0f, 1000.0f), 0 }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 83d8658c..adc14cd6 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -209,6 +209,9 @@ namespace Default extern const OpcodeSpec bendUp; extern const OpcodeSpec bendDown; extern const OpcodeSpec bendStep; + extern const OpcodeSpec ampLFODepth; + extern const OpcodeSpec pitchLFODepth; + extern const OpcodeSpec filLFODepth; extern const OpcodeSpec lfoFreq; extern const OpcodeSpec lfoFreqMod; extern const OpcodeSpec lfoBeats; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index feb7cb4a..c866a96a 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -780,6 +780,34 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } } + // Amplitude LFO + if (absl::StartsWith(opcode.name, "amplfo_")) { + if (parseLFOOpcode(opcode, amplitudeLFO)) { + getOrCreateConnection( + ModKey::createNXYZ(ModId::AmpLFO, id), + ModKey::createNXYZ(ModId::Volume, id)); + return true; + } + } + // Pitch LFO + if (absl::StartsWith(opcode.name, "pitchlfo_")) { + if (parseLFOOpcode(opcode, pitchLFO)) { + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchLFO, id), + ModKey::createNXYZ(ModId::Pitch, id)); + return true; + } + } + // Filter LFO + if (absl::StartsWith(opcode.name, "fillfo_")) { + if (parseLFOOpcode(opcode, filterLFO)) { + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilLFO, id), + ModKey::createNXYZ(ModId::FilCutoff, id)); + return true; + } + } + // const std::string letterOnlyName = opcode.getLetterOnlyName(); @@ -802,6 +830,109 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return true; } +bool sfz::Region::parseLFOOpcode(const Opcode& opcode, LFODescription& lfo) +{ + #define case_any_lfo(param) \ + case hash("amplfo_" param): \ + case hash("pitchlfo_" param): \ + case hash("fillfo_" param) \ + + #define case_any_lfo_any_ccN(param) \ + case_any_ccN("amplfo_" param): \ + case_any_ccN("pitchlfo_" param): \ + case_any_ccN("fillfo_" param) \ + + // + ModKey sourceKey; + ModKey targetKey; + OpcodeSpec depthSpec; + + if (absl::StartsWith(opcode.name, "amplfo_")) { + sourceKey = ModKey::createNXYZ(ModId::AmpLFO, id); + targetKey = ModKey::createNXYZ(ModId::Volume, id); + lfo.freqKey = ModKey::createNXYZ(ModId::AmpLFOFrequency, id); + depthSpec = Default::ampLFODepth; + } + else if (absl::StartsWith(opcode.name, "pitchlfo_")) { + sourceKey = ModKey::createNXYZ(ModId::PitchLFO, id); + targetKey = ModKey::createNXYZ(ModId::Pitch, id); + lfo.freqKey = ModKey::createNXYZ(ModId::PitchLFOFrequency, id); + depthSpec = Default::pitchLFODepth; + } + else if (absl::StartsWith(opcode.name, "fillfo_")) { + sourceKey = ModKey::createNXYZ(ModId::FilLFO, id); + targetKey = ModKey::createNXYZ(ModId::FilCutoff, id); + lfo.freqKey = ModKey::createNXYZ(ModId::FilLFOFrequency, id); + depthSpec = Default::filLFODepth; + } + else { + ASSERTFALSE; + return false; + } + + // + switch (opcode.lettersOnlyHash) { + + case_any_lfo("delay"): + lfo.delay = opcode.read(Default::lfoDelay); + break; + case_any_lfo("depth"): + getOrCreateConnection(sourceKey, targetKey).sourceDepth = opcode.read(depthSpec); + break; + case_any_lfo_any_ccN("depth"): // also depthcc& + // TODO(jpc) LFO v1 + break; + case_any_lfo("depthchanaft"): + // TODO(jpc) LFO v1 + break; + case_any_lfo("depthpolyaft"): + // TODO(jpc) LFO v1 + break; + case_any_lfo("fade"): + lfo.fade = opcode.read(Default::lfoFade); + break; + case_any_lfo("freq"): + lfo.freq = opcode.read(Default::lfoFreq); + break; + case_any_lfo_any_ccN("freq"): // also freqcc& + processGenericCc(opcode, Default::lfoFreqMod, lfo.freqKey); + break; + case_any_lfo("freqchanaft"): + // TODO(jpc) LFO v1 + break; + case_any_lfo("freqpolyaft"): + // TODO(jpc) LFO v1 + break; + + // sfizz extension + case_any_lfo("wave"): + lfo.sub[0].wave = opcode.read(Default::lfoWave); + break; + + default: + return false; + } + + #undef case_any_lfo + + return true; +} + +bool sfz::Region::parseLFOOpcode(const Opcode& opcode, absl::optional& lfo) +{ + bool create = lfo == absl::nullopt; + if (create) { + lfo = LFODescription(); + lfo->sub[0].wave = LFOWave::Sine; // the LFO v1 default + } + + bool parsed = parseLFOOpcode(opcode, *lfo); + if (!parsed && create) + lfo = absl::nullopt; + + return parsed; +} + bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) { #define case_any_eg(param) \ diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 5330ee84..fd983db3 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -246,6 +246,26 @@ struct Region { * @return false */ bool parseOpcode(const Opcode& opcode); + /** + * @brief Parse a opcode which is specific to a particular SFZv1 LFO: + * amplfo, pitchlfo, fillfo. + * + * @param opcode + * @param lfo + * @return true if the opcode was properly read and stored. + * @return false + */ + bool parseLFOOpcode(const Opcode& opcode, LFODescription& lfo); + /** + * @brief Parse a opcode which is specific to a particular SFZv1 LFO: + * amplfo, pitchlfo, fillfo. + * + * @param opcode + * @param lfo + * @return true if the opcode was properly read and stored. + * @return false + */ + bool parseLFOOpcode(const Opcode& opcode, absl::optional& lfo); /** * @brief Parse a opcode which is specific to a particular SFZv1 EG: * ampeg, pitcheg, fileg. @@ -457,6 +477,9 @@ struct Region { // LFOs std::vector lfos; + absl::optional amplitudeLFO; + absl::optional pitchLFO; + absl::optional filterLFO; bool hasStereoSample { false }; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index f292875d..c99bcaf6 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -551,6 +551,9 @@ void Synth::Impl::finalizeSfzLoad() size_t maxFlexEGs { 0 }; bool havePitchEG { false }; bool haveFilterEG { false }; + bool haveAmplitudeLFO { false }; + bool havePitchLFO { false }; + bool haveFilterLFO { false }; FlexEGs::clearUnusedCurves(); @@ -683,6 +686,9 @@ void Synth::Impl::finalizeSfzLoad() maxFlexEGs = max(maxFlexEGs, region->flexEGs.size()); havePitchEG = havePitchEG || region->pitchEG != absl::nullopt; haveFilterEG = haveFilterEG || region->filterEG != absl::nullopt; + haveAmplitudeLFO = haveAmplitudeLFO || region->amplitudeLFO != absl::nullopt; + havePitchLFO = havePitchLFO || region->pitchLFO != absl::nullopt; + haveFilterLFO = haveFilterLFO || region->filterLFO != absl::nullopt; ++currentRegionIndex; } @@ -731,6 +737,9 @@ void Synth::Impl::finalizeSfzLoad() settingsPerVoice_.maxFlexEGs = maxFlexEGs; settingsPerVoice_.havePitchEG = havePitchEG; settingsPerVoice_.haveFilterEG = haveFilterEG; + settingsPerVoice_.haveAmplitudeLFO = haveAmplitudeLFO; + settingsPerVoice_.havePitchLFO = havePitchLFO; + settingsPerVoice_.haveFilterLFO = haveFilterLFO; applySettingsPerVoice(); @@ -1579,6 +1588,9 @@ void Synth::Impl::applySettingsPerVoice() voice.setMaxFlexEGsPerVoice(settingsPerVoice_.maxFlexEGs); voice.setPitchEGEnabledPerVoice(settingsPerVoice_.havePitchEG); voice.setFilterEGEnabledPerVoice(settingsPerVoice_.haveFilterEG); + voice.setAmplitudeLFOEnabledPerVoice(settingsPerVoice_.haveAmplitudeLFO); + voice.setPitchLFOEnabledPerVoice(settingsPerVoice_.havePitchLFO); + voice.setFilterLFOEnabledPerVoice(settingsPerVoice_.haveFilterLFO); } } @@ -1605,6 +1617,9 @@ void Synth::Impl::setupModMatrix() case ModId::Controller: gen = genController_.get(); break; + case ModId::AmpLFO: + case ModId::PitchLFO: + case ModId::FilLFO: case ModId::LFO: gen = genLFO_.get(); break; diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index bb69fdc7..af694fa0 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -283,6 +283,9 @@ struct Synth::Impl final: public Parser::Listener { size_t maxFlexEGs { 0 }; bool havePitchEG { false }; bool haveFilterEG { false }; + bool haveAmplitudeLFO { false }; + bool havePitchLFO { false }; + bool haveFilterLFO { false }; } settingsPerVoice_; Duration dispatchDuration_ { 0 }; diff --git a/src/sfizz/modulations/ModId.cpp b/src/sfizz/modulations/ModId.cpp index 5bc66bc8..5d01ae7b 100644 --- a/src/sfizz/modulations/ModId.cpp +++ b/src/sfizz/modulations/ModId.cpp @@ -76,6 +76,12 @@ int ModIds::flags(ModId id) noexcept return kModIsPerVoice|kModIsAdditive; case ModId::OscillatorModDepth: return kModIsPerVoice|kModIsPercentMultiplicative; + case ModId::AmpLFOFrequency: + return kModIsPerVoice|kModIsAdditive; + case ModId::PitchLFOFrequency: + return kModIsPerVoice|kModIsAdditive; + case ModId::FilLFOFrequency: + return kModIsPerVoice|kModIsAdditive; case ModId::LFOFrequency: return kModIsPerVoice|kModIsAdditive; case ModId::LFOBeats: diff --git a/src/sfizz/modulations/ModId.h b/src/sfizz/modulations/ModId.h index 648ed8c7..a7374083 100644 --- a/src/sfizz/modulations/ModId.h +++ b/src/sfizz/modulations/ModId.h @@ -53,6 +53,9 @@ enum class ModId : int { EqBandwidth, OscillatorDetune, OscillatorModDepth, + AmpLFOFrequency, + PitchLFOFrequency, + FilLFOFrequency, LFOFrequency, LFOBeats, diff --git a/src/sfizz/modulations/ModKey.cpp b/src/sfizz/modulations/ModKey.cpp index 4b61552c..55d9cee5 100644 --- a/src/sfizz/modulations/ModKey.cpp +++ b/src/sfizz/modulations/ModKey.cpp @@ -144,6 +144,12 @@ std::string ModKey::toString() const return absl::StrCat("OscillatorDetune {", region_.number(), ", N=", 1 + params_.N, "}"); case ModId::OscillatorModDepth: return absl::StrCat("OscillatorModDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::AmpLFOFrequency: + return absl::StrCat("AmplitudeLFOFrequency {", region_.number(), "}"); + case ModId::PitchLFOFrequency: + return absl::StrCat("PitchLFOFrequency {", region_.number(), "}"); + case ModId::FilLFOFrequency: + return absl::StrCat("FilterLFOFrequency {", region_.number(), "}"); case ModId::LFOFrequency: return absl::StrCat("LFOFrequency {", region_.number(), ", N=", 1 + params_.N, "}"); case ModId::LFOBeats: diff --git a/src/sfizz/modulations/sources/LFO.cpp b/src/sfizz/modulations/sources/LFO.cpp index a485833d..aabd5f70 100644 --- a/src/sfizz/modulations/sources/LFO.cpp +++ b/src/sfizz/modulations/sources/LFO.cpp @@ -21,8 +21,6 @@ LFOSource::LFOSource(VoiceManager& manager) void LFOSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { - unsigned lfoIndex = sourceKey.parameters().N; - Voice* voice = voiceManager_.getVoiceById(voiceId); if (!voice) { ASSERTFALSE; @@ -30,13 +28,39 @@ void LFOSource::init(const ModKey& sourceKey, NumericId voiceId, unsigned } const Region* region = voice->getRegion(); - if (lfoIndex >= region->lfos.size()) { + LFO* lfo = nullptr; + const LFODescription* desc = nullptr; + + switch (sourceKey.id()) { + case ModId::AmpLFO: + lfo = voice->getAmplitudeLFO(); + desc = &*region->amplitudeLFO; + break; + case ModId::PitchLFO: + lfo = voice->getPitchLFO(); + desc = &*region->pitchLFO; + break; + case ModId::FilLFO: + lfo = voice->getFilterLFO(); + desc = &*region->filterLFO; + break; + case ModId::LFO: + { + unsigned lfoIndex = sourceKey.parameters().N; + if (lfoIndex >= region->lfos.size()) { + ASSERTFALSE; + return; + } + lfo = voice->getLFO(lfoIndex); + desc = ®ion->lfos[lfoIndex]; + } + break; + default: ASSERTFALSE; return; } - LFO* lfo = voice->getLFO(lfoIndex); - lfo->configure(®ion->lfos[lfoIndex]); + lfo->configure(desc); lfo->start(delay); } @@ -52,13 +76,33 @@ void LFOSource::generate(const ModKey& sourceKey, NumericId voiceId, absl } const Region* region = voice->getRegion(); - if (lfoIndex >= region->lfos.size()) { + LFO* lfo = nullptr; + + switch (sourceKey.id()) { + case ModId::AmpLFO: + lfo = voice->getAmplitudeLFO(); + break; + case ModId::PitchLFO: + lfo = voice->getPitchLFO(); + break; + case ModId::FilLFO: + lfo = voice->getFilterLFO(); + break; + case ModId::LFO: + { + if (lfoIndex >= region->lfos.size()) { + ASSERTFALSE; + fill(buffer, 0.0f); + return; + } + lfo = voice->getLFO(lfoIndex); + } + break; + default: ASSERTFALSE; - fill(buffer, 0.0f); return; } - LFO* lfo = voice->getLFO(lfoIndex); lfo->process(buffer); } From de7c125c54c499c2a5f3bf31bb72bbd57f6fe5f3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 11 Mar 2021 08:11:07 +0100 Subject: [PATCH 385/668] Add connections unit test --- tests/ModulationsT.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/ModulationsT.cpp b/tests/ModulationsT.cpp index 72c38cb6..516a34ae 100644 --- a/tests/ModulationsT.cpp +++ b/tests/ModulationsT.cpp @@ -354,3 +354,20 @@ TEST_CASE("[Modulations] Aftertouch connections") R"("ChannelAftertouch" -> "FilterCutoff {1, N=2}")", }, 2)); } + +TEST_CASE("[Modulations] LFO v1 connections") +{ + sfz::Synth synth; + synth.loadSfzString("/modulation.sfz", R"( + sample=*sine amplfo_freq=1.0 + sample=*sine pitchlfo_freq=1.0 + sample=*sine fillfo_freq=1.0 + )"); + + const std::string graph = synth.getResources().modMatrix.toDotGraph(); + REQUIRE(graph == createDefaultGraph({ + R"("AmplitudeLFO {0}" -> "Volume {0}")", + R"("PitchLFO {1}" -> "Pitch {1}")", + R"("FilterLFO {2}" -> "FilterCutoff {2, N=1}")", + }, 3)); +} From 48cc74b2a3ce7be7d11a5dec9507922904f2bb7e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 11 Mar 2021 11:45:51 +0100 Subject: [PATCH 386/668] Always force vendor abseil to be built statically --- .github/workflows/build.yml | 12 ++++-------- cmake/SfizzDeps.cmake | 6 +++++- scripts/appveyor/before_build.cmd | 1 - scripts/appveyor/before_build.sh | 1 - 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 85f104fb..cfd21976 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,8 +72,7 @@ jobs: -DSFIZZ_SHARED=OFF \ -DSFIZZ_STATIC_DEPENDENCIES=OFF \ -DSFIZZ_LV2=ON \ - -DCMAKE_CXX_STANDARD=17 \ - -DBUILD_SHARED_LIBS=OFF + -DCMAKE_CXX_STANDARD=17 - name: Build shell: bash working-directory: ${{runner.workspace}}/build @@ -119,8 +118,7 @@ jobs: run: | mod-plugin-builder /usr/local/bin/cmake "$GITHUB_WORKSPACE" \ -DSFIZZ_SYSTEM_PROCESSOR=armv7-a \ - -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_VST=OFF -DSFIZZ_LV2_UI=OFF \ - -DBUILD_SHARED_LIBS=OFF + -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_VST=OFF -DSFIZZ_LV2_UI=OFF - name: Build shell: bash working-directory: ${{runner.workspace}}/build @@ -189,8 +187,7 @@ jobs: -DSFIZZ_JACK=OFF \ -DSFIZZ_VST=ON \ -DSFIZZ_STATIC_DEPENDENCIES=ON \ - -DCMAKE_CXX_STANDARD=17 \ - -DBUILD_SHARED_LIBS=OFF + -DCMAKE_CXX_STANDARD=17 - name: Build shell: bash working-directory: ${{runner.workspace}}/build @@ -259,8 +256,7 @@ jobs: -DSFIZZ_JACK=OFF \ -DSFIZZ_VST=ON \ -DSFIZZ_STATIC_DEPENDENCIES=ON \ - -DCMAKE_CXX_STANDARD=17 \ - -DBUILD_SHARED_LIBS=OFF + -DCMAKE_CXX_STANDARD=17 - name: Build shell: bash working-directory: ${{runner.workspace}}/build diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index dc39f499..664286c1 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -39,7 +39,11 @@ endif() if(SFIZZ_USE_SYSTEM_ABSEIL) find_package(absl REQUIRED) else() - add_subdirectory("external/abseil-cpp" EXCLUDE_FROM_ALL) + function(sfizz_add_vendor_abseil) + set(BUILD_SHARED_LIBS OFF) # only changed at local scope + add_subdirectory("external/abseil-cpp" EXCLUDE_FROM_ALL) + endfunction() + sfizz_add_vendor_abseil() endif() # The jsl utility library for C++ diff --git a/scripts/appveyor/before_build.cmd b/scripts/appveyor/before_build.cmd index 8742946c..0b7804cd 100644 --- a/scripts/appveyor/before_build.cmd +++ b/scripts/appveyor/before_build.cmd @@ -11,6 +11,5 @@ cmake .. -G"Visual Studio 16 2019" -A"%RELEASE_ARCH%"^ -DSFIZZ_LV2=ON^ -DSFIZZ_VST=ON^ -DCMAKE_BUILD_TYPE=Release^ - -DBUILD_SHARED_LIBS=OFF^ -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET%^ -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake diff --git a/scripts/appveyor/before_build.sh b/scripts/appveyor/before_build.sh index 48e2e70a..213ab8a3 100644 --- a/scripts/appveyor/before_build.sh +++ b/scripts/appveyor/before_build.sh @@ -10,7 +10,6 @@ cmake -DCMAKE_BUILD_TYPE=Release \ -DSFIZZ_SHARED=OFF \ -DSFIZZ_TESTS=ON \ -DCMAKE_CXX_STANDARD=14 \ - -DBUILD_SHARED_LIBS=OFF \ -DLV2PLUGIN_INSTALL_DIR=/ \ -DVSTPLUGIN_INSTALL_DIR=/ \ -DAUPLUGIN_INSTALL_DIR=/ \ From 9a2f91f5ef101a92c4a916cefd9f817ead63a160 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 12 Mar 2021 15:12:19 +0100 Subject: [PATCH 387/668] Safeguard against EQ bandwidth low values --- src/sfizz/dsp/filters/sfz_filters.dsp | 2 +- src/sfizz/gen/filters/sfz2chEqPeak.hxx | 2 +- src/sfizz/gen/filters/sfzEqPeak.hxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sfizz/dsp/filters/sfz_filters.dsp b/src/sfizz/dsp/filters/sfz_filters.dsp index 1f47ce04..8efb07a1 100644 --- a/src/sfizz/dsp/filters/sfz_filters.dsp +++ b/src/sfizz/dsp/filters/sfz_filters.dsp @@ -94,7 +94,7 @@ sfzPeq = fm.rbjPeakingEqSmooth(smoothCoefs,cutoff,pkShGain,Q); // the SFZ equalizer band sfzEqPeak = fm.rbjPeakingEqSmooth(smoothCoefs,cutoff,pkShGain,Q) with { - Q = 1./(2.*ma.sinh(0.5*log(2)*bandwidth*w0/sin(w0))); + Q = 1./(2.*ma.sinh(0.5*log(2)*max(1e-3, bandwidth)*w0/sin(w0))); w0 = 2*ma.PI*max(0,cutoff)/ma.SR; }; diff --git a/src/sfizz/gen/filters/sfz2chEqPeak.hxx b/src/sfizz/gen/filters/sfz2chEqPeak.hxx index 1849c94f..cac02e65 100644 --- a/src/sfizz/gen/filters/sfz2chEqPeak.hxx +++ b/src/sfizz/gen/filters/sfz2chEqPeak.hxx @@ -174,7 +174,7 @@ class faust2chEqPeak : public sfzFilterDsp { double fSlow2 = (fConst2 * fSlow1); double fSlow3 = std::sin(fSlow2); double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * double(fVslider1)) / fSlow3))))))); + double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * std::max(0.001, double(fVslider1))) / fSlow3))))))); double fSlow6 = (0.5 * (fSlow3 / (fSlow4 * fSlow5))); double fSlow7 = (fSlow6 + 1.0); double fSlow8 = (1.0 - fSlow0); diff --git a/src/sfizz/gen/filters/sfzEqPeak.hxx b/src/sfizz/gen/filters/sfzEqPeak.hxx index 2d6f26e5..251815b8 100644 --- a/src/sfizz/gen/filters/sfzEqPeak.hxx +++ b/src/sfizz/gen/filters/sfzEqPeak.hxx @@ -152,7 +152,7 @@ class faustEqPeak : public sfzFilterDsp { double fSlow2 = (fConst2 * fSlow1); double fSlow3 = std::sin(fSlow2); double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * double(fVslider1)) / fSlow3))))))); + double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * std::max(0.001, double(fVslider1))) / fSlow3))))))); double fSlow6 = (0.5 * (fSlow3 / (fSlow4 * fSlow5))); double fSlow7 = (fSlow6 + 1.0); double fSlow8 = (1.0 - fSlow0); From 7d1bf23b005f14dfe744b9bfaa1dd0bdec0c3b4a Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 12 Mar 2021 15:55:11 +0100 Subject: [PATCH 388/668] Simplify the notation for opcode spec --- src/sfizz/Defaults.cpp | 342 +++++++++++++++++++++-------------------- src/sfizz/Defaults.h | 34 ++-- 2 files changed, 194 insertions(+), 182 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 7d9a5459..10375e86 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -4,172 +4,184 @@ namespace sfz { namespace Default { constexpr auto uint32_t_max = std::numeric_limits::max(); +constexpr auto float_max = std::numeric_limits::max(); -extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec delayMod { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, uint32_t_max), kEnforceLowerBound }; -extern const OpcodeSpec sampleCount { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec loopStart { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec loopEnd { uint32_t_max, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec loopCount { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), 0 }; -extern const OpcodeSpec oscillator { OscillatorEnabled::Auto, Range(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 }; -extern const OpcodeSpec oscillatorPhase { 0.0f, Range(-1000.0f, 1000.0f), 0 }; -extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), 0 }; -extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), 0 }; -extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; -extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; -extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), 0 }; -extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec polyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; -extern const OpcodeSpec notePolyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; -extern const OpcodeSpec key { 60, Range(0, 127), kCanBeNote }; -extern const OpcodeSpec loKey { 0, Range(0, 127), kCanBeNote }; -extern const OpcodeSpec hiKey { 127, Range(0, 127), kCanBeNote }; -extern const OpcodeSpec loCC { 0, Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec hiCC { 127, Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec loVel { 0, Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec hiVel { 127, Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec loChannelAftertouch { 0, Range(0, 127), 0 }; -extern const OpcodeSpec hiChannelAftertouch { 127, Range(0, 127), 0 }; -extern const OpcodeSpec loBend { -8192, Range(-8192.0f, 8192.0f), kNormalizeBend }; -extern const OpcodeSpec hiBend { 8192, Range(-8192.0f, 8192.0f), kNormalizeBend }; -extern const OpcodeSpec loNormalized { 0.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec hiNormalized { 1.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec loBipolar { -1.0f, Range(-1.0f, 1.0f), 0 }; -extern const OpcodeSpec hiBipolar { 1.0f, Range(-1.0f, 1.0f), 0 }; -extern const OpcodeSpec ccNumber { 0, Range(0, config::numCCs), 0 }; -extern const OpcodeSpec smoothCC { 0, Range(0, 100), 0 }; -extern const OpcodeSpec curveCC { 0, Range(0, 255), 0 }; -extern const OpcodeSpec sustainCC { 64, Range(0, 127), 0 }; -extern const OpcodeSpec sustainThreshold { 1.0f, Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; -extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; -extern const OpcodeSpec loBPM { 0.0f, Range(0.0f, 500.0f), 0 }; -extern const OpcodeSpec hiBPM { 500.0f, Range(0.0f, 500.0f), 0 }; -extern const OpcodeSpec sequence { 1, Range(1, 100), 0 }; -extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; -extern const OpcodeSpec volumeMod { 0.0f, Range(-144.0f, 48.0f), 0 }; -extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 10000.0f), kNormalizePercent }; -extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), 0 }; -extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec crossfadeIn { 0.0f, Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec crossfadeOut { 127.0f, Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), 0 }; -extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), 0 }; -extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; -extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), 0 }; -extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceUpperBound }; -extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), 0 }; -extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), 0 }; -extern const OpcodeSpec filterGain { 0.0f, Range(-96.0f, 96.0f), 0 }; -extern const OpcodeSpec filterGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; -extern const OpcodeSpec filterRandom { 0.0f, Range(0.0f, 12000.0f), 0 }; -extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), 0 }; -extern const OpcodeSpec filterVeltrack { 0, Range(-12000, 12000), 0 }; -extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), 0 }; -extern const OpcodeSpec eqBandwidthMod { 0.0f, Range(-4.0f, 4.0f), 0 }; -extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 20000.0f), kEnforceUpperBound }; -extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-20000.0f, 20000.0f), 0 }; -extern const OpcodeSpec eqGain { 0.0f, Range(-96.0f, 96.0f), 0 }; -extern const OpcodeSpec eqGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; -extern const OpcodeSpec eqVel2Frequency { 0.0f, Range(-30000.0f, 30000.0f), 0 }; -extern const OpcodeSpec eqVel2Gain { 0.0f, Range(-96.0f, 96.0f), 0 }; -extern const OpcodeSpec pitchKeytrack { 100, Range(-1200, 1200), 0 }; -extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), 0 }; -extern const OpcodeSpec pitchVeltrack { 0, Range(-12000, 12000), 0 }; -extern const OpcodeSpec transpose { 0, Range(-127, 127), 0 }; -extern const OpcodeSpec pitch { 0.0f, Range(-2400.0f, 2400.0f), 0 }; -extern const OpcodeSpec pitchMod { 0.0f, Range(-2400.0f, 2400.0f), 0 }; -extern const OpcodeSpec bendUp { 200.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec bendDown { -200.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), 0 }; -extern const OpcodeSpec ampLFODepth { 0.0f, Range(-10.0f, 10.0f), 0 }; -extern const OpcodeSpec pitchLFODepth { 0.0f, Range(-1200.0f, 1200.0f), 0 }; -extern const OpcodeSpec filLFODepth { 0.0f, Range(-1200.0f, 1200.0f), 0 }; -extern const OpcodeSpec lfoFreq { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec lfoFreqMod { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec lfoBeats { 0.0f, Range(0.0f, 1000.0f), 0 }; -extern const OpcodeSpec lfoBeatsMod { 0.0f, Range(-1000.0f, 1000.0f), 0 }; -extern const OpcodeSpec lfoPhase { 0.0f, Range(0.0f, 1.0f), kWrapPhase }; -extern const OpcodeSpec lfoDelay { 0.0f, Range(0.0f, 30.0f), 0 }; -extern const OpcodeSpec lfoFade { 0.0f, Range(0.0f, 30.0f), 0 }; -extern const OpcodeSpec lfoCount { 0, Range(0, 1000), 0 }; -extern const OpcodeSpec lfoSteps { 0, Range(0, static_cast(config::maxLFOSteps)), 0 }; -extern const OpcodeSpec lfoStepX { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec lfoWave { LFOWave::Triangle, Range(LFOWave::Triangle, LFOWave::RandomSH), 0 }; -extern const OpcodeSpec lfoOffset { 0.0f, Range(-1.0f, 1.0f), 0 }; -extern const OpcodeSpec lfoRatio { 1.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec lfoScale { 1.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec egTime { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec egRelease { 0.001f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec egTimeMod { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec egPercentMod { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec egDepth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec egVel2Depth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec flexEGAmpeg { false, Range(0, 1), 0 }; -extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), 0 }; -extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), 0 }; -extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec flexEGPointLevel { 0.0f, Range(-1.0f, 1.0f), 0 }; -extern const OpcodeSpec flexEGPointShape { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec sampleQuality { 1, Range(1, 10), 0 }; -extern const OpcodeSpec octaveOffset { 0, Range(-10, 10), 0 }; -extern const OpcodeSpec noteOffset { 0, Range(-127, 127), 0 }; -extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec effectPercent { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec apanWaveform { LFOWave::Triangle, Range(LFOWave::Triangle, LFOWave::Saw), 0 }; -extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), 0 }; -extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), kWrapPhase }; -extern const OpcodeSpec apanLevel { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec distoTone { 100.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), 0 }; -extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), 0 }; -extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), 0 }; -extern const OpcodeSpec compSTLink { false, Range(0, 1), 0 }; -extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; -extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), 0 }; -extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), kDb2Mag }; -extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), 0 }; -extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec gateSTLink { false, Range(0, 1), 0 }; -extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), 0 }; -extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), 0 }; -extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), 0 }; -extern const OpcodeSpec gateThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; -extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), 0 }; -extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), 0 }; -extern const OpcodeSpec trigger { Trigger::attack, Range(Trigger::attack, Trigger::release_key), 0}; -extern const OpcodeSpec crossfadeCurve { CrossfadeCurve::power, Range(CrossfadeCurve::gain, CrossfadeCurve::power), 0}; -extern const OpcodeSpec offMode { OffMode::fast, Range(OffMode::fast, OffMode::time), 0}; -extern const OpcodeSpec loopMode { LoopMode::no_loop, Range(LoopMode::no_loop, LoopMode::loop_sustain), 0}; -extern const OpcodeSpec velocityOverride { VelocityOverride::current, Range(VelocityOverride::current, VelocityOverride::previous), 0}; -extern const OpcodeSpec selfMask { SelfMask::mask, Range(SelfMask::mask, SelfMask::dontMask), 0}; -extern const OpcodeSpec filter { FilterType::kFilterNone, Range(FilterType::kFilterNone, FilterType::kFilterPeq), 0}; -extern const OpcodeSpec eq { EqType::kEqNone, Range(EqType::kEqNone, EqType::kEqHighShelf), 0}; +using FloatSpec = const OpcodeSpec; +using Int8Spec = const OpcodeSpec; +using Int16Spec = const OpcodeSpec; +using Int32Spec = const OpcodeSpec; +using Int64Spec = const OpcodeSpec; +using UInt8Spec = const OpcodeSpec; +using UInt16Spec = const OpcodeSpec; +using UInt32Spec = const OpcodeSpec; +using BoolSpec = const OpcodeSpec; +template using ESpec = const OpcodeSpec; + +FloatSpec delay { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec delayRandom { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec delayMod { 0.0f, {0.0f, 100.0f}, 0 }; +Int64Spec offset { 0, {0, uint32_t_max}, 0 }; +Int64Spec offsetMod { 0, {0, uint32_t_max}, 0 }; +Int64Spec offsetRandom { 0, {0, uint32_t_max}, 0 }; +UInt32Spec sampleEnd { uint32_t_max, {0, uint32_t_max}, kEnforceLowerBound }; +UInt32Spec sampleCount { 0, {0, uint32_t_max}, 0 }; +UInt32Spec loopStart { 0, {0, uint32_t_max}, 0 }; +UInt32Spec loopEnd { uint32_t_max, {0, uint32_t_max}, 0 }; +UInt32Spec loopCount { 0, {0, uint32_t_max}, 0 }; +FloatSpec loopCrossfade { 1e-3, {1e-3, 1.0f}, 0 }; +ESpec oscillator { OscillatorEnabled::Auto, {OscillatorEnabled::Auto, OscillatorEnabled::On}, 0 }; +FloatSpec oscillatorPhase { 0.0f, {-1000.0f, 1000.0f}, 0 }; +Int32Spec oscillatorMode { 0, {0, 2}, 0 }; +Int32Spec oscillatorMulti { 1, {1, config::oscillatorsPerVoice}, 0 }; +FloatSpec oscillatorDetune { 0.0f, {-12000.0f, 12000.0f}, 0 }; +FloatSpec oscillatorDetuneMod { 0.0f, {-12000.0f, 12000.0f}, 0 }; +FloatSpec oscillatorModDepth { 0.0f, {0.0f, 10000.0f}, kNormalizePercent }; +FloatSpec oscillatorModDepthMod { 0.0f, {0.0f, 10000.0f}, kNormalizePercent }; +Int32Spec oscillatorQuality { 1, {0, 3}, 0 }; +UInt32Spec group { 0, {0, uint32_t_max}, 0 }; +FloatSpec offTime { 6e-3f, {0.0f, 100.0f}, 0 }; +UInt32Spec polyphony { config::maxVoices, {0, config::maxVoices}, 0 }; +UInt32Spec notePolyphony { config::maxVoices, {0, config::maxVoices}, 0 }; +UInt8Spec key { 60, {0, 127}, kCanBeNote }; +UInt8Spec loKey { 0, {0, 127}, kCanBeNote }; +UInt8Spec hiKey { 127, {0, 127}, kCanBeNote }; +FloatSpec loCC { 0, {0.0f, 127.0f}, kNormalizeMidi }; +FloatSpec hiCC { 127, {0.0f, 127.0f}, kNormalizeMidi }; +FloatSpec loVel { 0, {0.0f, 127.0f}, kNormalizeMidi }; +FloatSpec hiVel { 127, {0.0f, 127.0f}, kNormalizeMidi }; +UInt8Spec loChannelAftertouch { 0, {0, 127}, 0 }; +UInt8Spec hiChannelAftertouch { 127, {0, 127}, 0 }; +FloatSpec loBend { -8192, {-8192.0f, 8192.0f}, kNormalizeBend }; +FloatSpec hiBend { 8192, {-8192.0f, 8192.0f}, kNormalizeBend }; +FloatSpec loNormalized { 0.0f, {0.0f, 1.0f}, 0 }; +FloatSpec hiNormalized { 1.0f, {0.0f, 1.0f}, 0 }; +FloatSpec loBipolar { -1.0f, {-1.0f, 1.0f}, 0 }; +FloatSpec hiBipolar { 1.0f, {-1.0f, 1.0f}, 0 }; +UInt16Spec ccNumber { 0, {0, config::numCCs}, 0 }; +UInt8Spec smoothCC { 0, {0, 100}, 0 }; +UInt8Spec curveCC { 0, {0, 255}, 0 }; +UInt8Spec sustainCC { 64, {0, 127}, 0 }; +FloatSpec sustainThreshold { 1.0f, {0.0f, 127.0f}, kNormalizeMidi }; +BoolSpec checkSustain { true, {0, 1}, 0 }; +BoolSpec checkSostenuto { true, {0, 1}, 0 }; +FloatSpec loBPM { 0.0f, {0.0f, 500.0f}, 0 }; +FloatSpec hiBPM { 500.0f, {0.0f, 500.0f}, 0 }; +UInt8Spec sequence { 1, {1, 100}, 0 }; +FloatSpec volume { 0.0f, {-144.0f, 48.0f}, 0 }; +FloatSpec volumeMod { 0.0f, {-144.0f, 48.0f}, 0 }; +FloatSpec amplitude { 100.0f, {0.0f, 10000.0f}, kNormalizePercent }; +FloatSpec amplitudeMod { 0.0f, {0.0f, 10000.0f}, 0 }; +FloatSpec pan { 0.0f, {-100.0f, 100.0f}, kNormalizePercent }; +FloatSpec panMod { 0.0f, {-200.0f, 200.0f}, 0 }; +FloatSpec position { 0.0f, {-100.0f, 100.0f}, kNormalizePercent }; +FloatSpec positionMod { 0.0f, {-200.0f, 200.0f}, 0 }; +FloatSpec width { 100.0f, {-100.0f, 100.0f}, kNormalizePercent }; +FloatSpec widthMod { 0.0f, {-200.0f, 200.0f}, 0 }; +FloatSpec crossfadeIn { 0.0f, {0.0f, 127.0f}, kNormalizeMidi }; +FloatSpec crossfadeInNorm { 0.0f, {0.0f, 1.0f}, 0 }; +FloatSpec crossfadeOut { 127.0f, {0.0f, 127.0f}, kNormalizeMidi }; +FloatSpec crossfadeOutNorm { 1.0f, {0.0f, 1.0f}, 0 }; +FloatSpec ampKeytrack { 0.0f, {-96.0f, 12.0f}, 0 }; +FloatSpec ampVeltrack { 100.0f, {-100.0f, 100.0f}, kNormalizePercent }; +FloatSpec ampVelcurve { 0.0f, {0.0f, 1.0f}, 0 }; +FloatSpec ampRandom { 0.0f, {0.0f, 24.0f}, 0 }; +BoolSpec rtDead { false, {false, true}, 0 }; +FloatSpec rtDecay { 0.0f, {0.0f, 200.0f}, 0 }; +FloatSpec filterCutoff { 0.0f, {0.0f, 20000.0f}, kEnforceUpperBound }; +FloatSpec filterCutoffMod { 0.0f, {-12000.0f, 12000.0f}, 0 }; +FloatSpec filterResonance { 0.0f, {0.0f, 96.0f}, 0 }; +FloatSpec filterResonanceMod { 0.0f, {0.0f, 96.0f}, 0 }; +FloatSpec filterGain { 0.0f, {-96.0f, 96.0f}, 0 }; +FloatSpec filterGainMod { 0.0f, {-96.0f, 96.0f}, 0 }; +FloatSpec filterRandom { 0.0f, {0.0f, 12000.0f}, 0 }; +Int32Spec filterKeytrack { 0, {0, 1200}, 0 }; +Int32Spec filterVeltrack { 0, {-12000, 12000}, 0 }; +FloatSpec eqBandwidth { 1.0f, {0.001f, 4.0f}, 0 }; +FloatSpec eqBandwidthMod { 0.0f, {-4.0f, 4.0f}, 0 }; +FloatSpec eqFrequency { 0.0f, {0.0f, 20000.0f}, kEnforceUpperBound }; +FloatSpec eqFrequencyMod { 0.0f, {-20000.0f, 20000.0f}, 0 }; +FloatSpec eqGain { 0.0f, {-96.0f, 96.0f}, 0 }; +FloatSpec eqGainMod { 0.0f, {-96.0f, 96.0f}, 0 }; +FloatSpec eqVel2Frequency { 0.0f, {-30000.0f, 30000.0f}, 0 }; +FloatSpec eqVel2Gain { 0.0f, {-96.0f, 96.0f}, 0 }; +Int32Spec pitchKeytrack { 100, {-1200, 1200}, 0 }; +FloatSpec pitchRandom { 0.0f, {0.0f, 12000.0f}, 0 }; +Int32Spec pitchVeltrack { 0, {-12000, 12000}, 0 }; +Int32Spec transpose { 0, {-127, 127}, 0 }; +FloatSpec pitch { 0.0f, {-2400.0f, 2400.0f}, 0 }; +FloatSpec pitchMod { 0.0f, {-2400.0f, 2400.0f}, 0 }; +FloatSpec bendUp { 200.0f, {-12000.0f, 12000.0f}, 0 }; +FloatSpec bendDown { -200.0f, {-12000.0f, 12000.0f}, 0 }; +FloatSpec bendStep { 1.0f, {1.0f, 1200.0f}, 0 }; +FloatSpec ampLFODepth { 0.0f, {-10.0f, 10.0f}, 0 }; +FloatSpec pitchLFODepth { 0.0f, {-1200.0f, 1200.0f}, 0 }; +FloatSpec filLFODepth { 0.0f, {-1200.0f, 1200.0f}, 0 }; +FloatSpec lfoFreq { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec lfoFreqMod { 0.0f, {-100.0f, 100.0f}, 0 }; +FloatSpec lfoBeats { 0.0f, {0.0f, 1000.0f}, 0 }; +FloatSpec lfoBeatsMod { 0.0f, {-1000.0f, 1000.0f}, 0 }; +FloatSpec lfoPhase { 0.0f, {0.0f, 1.0f}, kWrapPhase }; +FloatSpec lfoDelay { 0.0f, {0.0f, 30.0f}, 0 }; +FloatSpec lfoFade { 0.0f, {0.0f, 30.0f}, 0 }; +UInt32Spec lfoCount { 0, {0, 1000}, 0 }; +UInt32Spec lfoSteps { 0, {0, static_cast(config::maxLFOSteps)}, 0 }; +FloatSpec lfoStepX { 0.0f, {-100.0f, 100.0f}, kNormalizePercent }; +ESpec lfoWave { LFOWave::Triangle, {LFOWave::Triangle, LFOWave::RandomSH}, 0 }; +FloatSpec lfoOffset { 0.0f, {-1.0f, 1.0f}, 0 }; +FloatSpec lfoRatio { 1.0f, {0.0f, 100.0f}, 0 }; +FloatSpec lfoScale { 1.0f, {0.0f, 1.0f}, 0 }; +FloatSpec egTime { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec egRelease { 0.001f, {0.0f, 100.0f}, 0 }; +FloatSpec egTimeMod { 0.0f, {-100.0f, 100.0f}, 0 }; +FloatSpec egPercent { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec egPercentMod { 0.0f, {-100.0f, 100.0f}, 0 }; +FloatSpec egDepth { 0.0f, {-12000.0f, 12000.0f}, 0 }; +FloatSpec egVel2Depth { 0.0f, {-12000.0f, 12000.0f}, 0 }; +BoolSpec flexEGAmpeg { false, {0, 1}, 0 }; +Int32Spec flexEGDynamic { 0, {0, 1}, 0 }; +Int32Spec flexEGSustain { 0, {0, 100}, 0 }; +FloatSpec flexEGPointTime { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec flexEGPointLevel { 0.0f, {-1.0f, 1.0f}, 0 }; +FloatSpec flexEGPointShape { 0.0f, {-100.0f, 100.0f}, 0 }; +Int32Spec sampleQuality { 1, {1, 10}, 0 }; +Int32Spec octaveOffset { 0, {-10, 10}, 0 }; +Int32Spec noteOffset { 0, {-127, 127}, 0 }; +FloatSpec effect { 0.0f, {0.0f, 100.0f}, kNormalizePercent }; +FloatSpec effectPercent { 0.0f, {0.0f, 100.0f}, 0 }; +ESpec apanWaveform { LFOWave::Triangle, {LFOWave::Triangle, LFOWave::Saw}, 0 }; +FloatSpec apanFrequency { 0.0f, {0.0f, float_max}, 0 }; +FloatSpec apanPhase { 0.5f, {0.0f, 1.0f}, kWrapPhase }; +FloatSpec apanLevel { 0.0f, {0.0f, 100.0f}, kNormalizePercent }; +FloatSpec distoTone { 100.0f, {0.0f, 100.0f}, 0 }; +FloatSpec distoDepth { 0.0f, {0.0f, 100.0f}, 0 }; +UInt32Spec distoStages { 1, {1, maxDistoStages}, 0 }; +FloatSpec compAttack { 0.005f, {0.0f, 10.0f}, 0 }; +FloatSpec compRelease { 0.05f, {0.0f, 10.0f}, 0 }; +BoolSpec compSTLink { false, {0, 1}, 0 }; +FloatSpec compThreshold { 0.0f, {-100.0f, 0.0f}, 0 }; +FloatSpec compRatio { 1.0f, {1.0f, 50.0f}, 0 }; +FloatSpec compGain { 0.0f, {-100.0f, 100.0f}, kDb2Mag }; +FloatSpec fverbSize { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec fverbPredelay { 0.0f, {0.0f, 10.0f}, 0 }; +FloatSpec fverbTone { 100.0f, {0.0f, 100.0f}, 0 }; +FloatSpec fverbDamp { 0.0f, {0.0f, 100.0f}, 0 }; +BoolSpec gateSTLink { false, {0, 1}, 0 }; +FloatSpec gateAttack { 0.005f, {0.0f, 10.0f}, 0 }; +FloatSpec gateRelease { 0.05f, {0.0f, 10.0f}, 0 }; +FloatSpec gateHold { 0.0f, {0.0f, 10.0f}, 0 }; +FloatSpec gateThreshold { 0.0f, {-100.0f, 0.0f}, 0 }; +FloatSpec lofiBitred { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec lofiDecim { 0.0f, {0.0f, 100.0f}, 0 }; +FloatSpec rectify { 0.0f, {0.0f, 100.0f}, 0 }; +UInt32Spec stringsNumber { maxStrings, {0, maxStrings}, 0 }; +ESpec trigger { Trigger::attack, {Trigger::attack, Trigger::release_key}, 0}; +ESpec crossfadeCurve { CrossfadeCurve::power, {CrossfadeCurve::gain, CrossfadeCurve::power}, 0}; +ESpec offMode { OffMode::fast, {OffMode::fast, OffMode::time}, 0}; +ESpec loopMode { LoopMode::no_loop, {LoopMode::no_loop, LoopMode::loop_sustain}, 0}; +ESpec velocityOverride { VelocityOverride::current, {VelocityOverride::current, VelocityOverride::previous}, 0}; +ESpec selfMask { SelfMask::mask, {SelfMask::mask, SelfMask::dontMask}, 0}; +ESpec filter { FilterType::kFilterNone, {FilterType::kFilterNone, FilterType::kFilterPeq}, 0}; +ESpec eq { EqType::kEqNone, {EqType::kEqNone, EqType::kEqHighShelf}, 0}; } // namespace Default } // namespace sfz diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index adc14cd6..bf33f5b0 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -127,13 +127,13 @@ namespace Default extern const OpcodeSpec loopCrossfade; extern const OpcodeSpec oscillatorPhase; extern const OpcodeSpec oscillator; - extern const OpcodeSpec oscillatorMode; - extern const OpcodeSpec oscillatorMulti; + extern const OpcodeSpec oscillatorMode; + extern const OpcodeSpec oscillatorMulti; extern const OpcodeSpec oscillatorDetune; extern const OpcodeSpec oscillatorDetuneMod; extern const OpcodeSpec oscillatorModDepth; extern const OpcodeSpec oscillatorModDepthMod; - extern const OpcodeSpec oscillatorQuality; + extern const OpcodeSpec oscillatorQuality; extern const OpcodeSpec group; extern const OpcodeSpec offTime; extern const OpcodeSpec polyphony; @@ -190,8 +190,8 @@ namespace Default extern const OpcodeSpec filterGain; extern const OpcodeSpec filterGainMod; extern const OpcodeSpec filterRandom; - extern const OpcodeSpec filterKeytrack; - extern const OpcodeSpec filterVeltrack; + extern const OpcodeSpec filterKeytrack; + extern const OpcodeSpec filterVeltrack; extern const OpcodeSpec eqBandwidth; extern const OpcodeSpec eqBandwidthMod; extern const OpcodeSpec eqFrequency; @@ -200,10 +200,10 @@ namespace Default extern const OpcodeSpec eqGainMod; extern const OpcodeSpec eqVel2Frequency; extern const OpcodeSpec eqVel2Gain; - extern const OpcodeSpec pitchKeytrack; + extern const OpcodeSpec pitchKeytrack; extern const OpcodeSpec pitchRandom; - extern const OpcodeSpec pitchVeltrack; - extern const OpcodeSpec transpose; + extern const OpcodeSpec pitchVeltrack; + extern const OpcodeSpec transpose; extern const OpcodeSpec pitch; extern const OpcodeSpec pitchMod; extern const OpcodeSpec bendUp; @@ -219,8 +219,8 @@ namespace Default extern const OpcodeSpec lfoPhase; extern const OpcodeSpec lfoDelay; extern const OpcodeSpec lfoFade; - extern const OpcodeSpec lfoCount; - extern const OpcodeSpec lfoSteps; + extern const OpcodeSpec lfoCount; + extern const OpcodeSpec lfoSteps; extern const OpcodeSpec lfoStepX; extern const OpcodeSpec lfoWave; extern const OpcodeSpec lfoOffset; @@ -234,14 +234,14 @@ namespace Default extern const OpcodeSpec egDepth; extern const OpcodeSpec egVel2Depth; extern const OpcodeSpec flexEGAmpeg; - extern const OpcodeSpec flexEGDynamic; - extern const OpcodeSpec flexEGSustain; + extern const OpcodeSpec flexEGDynamic; + extern const OpcodeSpec flexEGSustain; extern const OpcodeSpec flexEGPointTime; extern const OpcodeSpec flexEGPointLevel; extern const OpcodeSpec flexEGPointShape; - extern const OpcodeSpec sampleQuality; - extern const OpcodeSpec octaveOffset; - extern const OpcodeSpec noteOffset; + extern const OpcodeSpec sampleQuality; + extern const OpcodeSpec octaveOffset; + extern const OpcodeSpec noteOffset; extern const OpcodeSpec effect; extern const OpcodeSpec effectPercent; extern const OpcodeSpec apanWaveform; @@ -250,7 +250,7 @@ namespace Default extern const OpcodeSpec apanLevel; extern const OpcodeSpec distoTone; extern const OpcodeSpec distoDepth; - extern const OpcodeSpec distoStages; + extern const OpcodeSpec distoStages; extern const OpcodeSpec compAttack; extern const OpcodeSpec compRelease; extern const OpcodeSpec compThreshold; @@ -269,7 +269,7 @@ namespace Default extern const OpcodeSpec lofiBitred; extern const OpcodeSpec lofiDecim; extern const OpcodeSpec rectify; - extern const OpcodeSpec stringsNumber; + extern const OpcodeSpec stringsNumber; extern const OpcodeSpec trigger; extern const OpcodeSpec offMode; extern const OpcodeSpec loopMode; From c60bb048574a4cb706ff399f3efd86c58fa01763 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 12 Mar 2021 17:20:56 +0100 Subject: [PATCH 389/668] Limit filter parameters to prevent over-modulation --- src/sfizz/dsp/filters/sfz_filters.dsp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sfizz/dsp/filters/sfz_filters.dsp b/src/sfizz/dsp/filters/sfz_filters.dsp index 8efb07a1..72da6362 100644 --- a/src/sfizz/dsp/filters/sfz_filters.dsp +++ b/src/sfizz/dsp/filters/sfz_filters.dsp @@ -94,19 +94,17 @@ sfzPeq = fm.rbjPeakingEqSmooth(smoothCoefs,cutoff,pkShGain,Q); // the SFZ equalizer band sfzEqPeak = fm.rbjPeakingEqSmooth(smoothCoefs,cutoff,pkShGain,Q) with { - Q = 1./(2.*ma.sinh(0.5*log(2)*max(1e-3, bandwidth)*w0/sin(w0))); - w0 = 2*ma.PI*max(0,cutoff)/ma.SR; + Q = 1./(2.*ma.sinh(0.5*log(2)*bandwidth*w0/sin(w0))); + w0 = 2*ma.PI*cutoff/ma.SR; }; // the SFZ low-shelf with EQ controls sfzEqLshelf = fm.rbjLowShelfSmooth(smoothCoefs,cutoff,pkShGain,Q) with { - slope = bandwidth; // in this case eqN_bw meaning is not bandwith but slope Q = sfzGetQFromSlope(slope); }; // the SFZ high-shelf with EQ controls sfzEqHshelf = fm.rbjHighShelfSmooth(smoothCoefs,cutoff,pkShGain,Q) with { - slope = bandwidth; // in this case eqN_bw meaning is not bandwith but slope Q = sfzGetQFromSlope(slope); }; @@ -155,10 +153,12 @@ sfz2chEqHshelf = par(i,2,sfzEqHshelf); //============================================================================== // Filter parameters -cutoff = hslider("[01] Cutoff [unit:Hz] [scale:log]", 440.0, 50.0, 10000.0, 1.0); -Q = vslider("[02] Resonance [unit:dB]", 0.0, 0.0, 40.0, 0.1) : ba.db2linear; -pkShGain = vslider("[03] Peak/shelf gain [unit:dB]", 0.0, 0.0, 40.0, 0.1); -bandwidth = vslider("[04] Bandwidth [unit:octave]", 1.0, 0.1, 10.0, 0.01); +cutoff = hslider("[01] Cutoff [unit:Hz] [scale:log]", 440.0, 50.0, 10000.0, 1.0) : max(1.0) : min(20000.0); +Q = vslider("[02] Resonance [unit:dB]", 0.0, 0.0, 40.0, 0.1) : max(0.0) : min(60.0) : ba.db2linear; +pkShGain = vslider("[03] Peak/shelf gain [unit:dB]", 0.0, 0.0, 40.0, 0.1) : max(-120.0) : min(60.0); +bandwidthOrSlope = vslider("[04] Bandwidth [unit:octave]", 1.0, 0.1, 10.0, 0.01); +bandwidth = bandwidthOrSlope : max(1e-2) : min(12.0); +slope = bandwidthOrSlope; // limited further down in code // smoothing function to prevent fast changes of filter coefficients // The basic si.smoo is a bit longish and creates strange modulation sounds From 9431faa77fc014812be90d27aeb10d593a064269 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 12 Mar 2021 17:21:13 +0100 Subject: [PATCH 390/668] Regenerate filters faust code --- src/sfizz/gen/filters/sfz2chApf1p.hxx | 2 +- src/sfizz/gen/filters/sfz2chBpf1p.hxx | 2 +- src/sfizz/gen/filters/sfz2chBpf2p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chBpf2pSv.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chBpf4p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chBpf6p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chBrf1p.hxx | 2 +- src/sfizz/gen/filters/sfz2chBrf2p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chBrf2pSv.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chEqHshelf.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chEqLshelf.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chEqPeak.hxx | 8 +++---- src/sfizz/gen/filters/sfz2chHpf1p.hxx | 2 +- src/sfizz/gen/filters/sfz2chHpf2p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chHpf2pSv.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chHpf4p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chHpf6p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chHsh.hxx | 6 ++--- src/sfizz/gen/filters/sfz2chLpf1p.hxx | 2 +- src/sfizz/gen/filters/sfz2chLpf2p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chLpf2pSv.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chLpf4p.hxx | 4 ++-- src/sfizz/gen/filters/sfz2chLpf6p.hxx | 28 ++++++++++++------------ src/sfizz/gen/filters/sfz2chLsh.hxx | 6 ++--- src/sfizz/gen/filters/sfz2chPeq.hxx | 6 ++--- src/sfizz/gen/filters/sfzApf1p.hxx | 2 +- src/sfizz/gen/filters/sfzBpf1p.hxx | 2 +- src/sfizz/gen/filters/sfzBpf2p.hxx | 4 ++-- src/sfizz/gen/filters/sfzBpf2pSv.hxx | 4 ++-- src/sfizz/gen/filters/sfzBpf4p.hxx | 4 ++-- src/sfizz/gen/filters/sfzBpf6p.hxx | 4 ++-- src/sfizz/gen/filters/sfzBrf1p.hxx | 2 +- src/sfizz/gen/filters/sfzBrf2p.hxx | 4 ++-- src/sfizz/gen/filters/sfzBrf2pSv.hxx | 4 ++-- src/sfizz/gen/filters/sfzEqHshelf.hxx | 4 ++-- src/sfizz/gen/filters/sfzEqLshelf.hxx | 4 ++-- src/sfizz/gen/filters/sfzEqPeak.hxx | 8 +++---- src/sfizz/gen/filters/sfzHpf1p.hxx | 2 +- src/sfizz/gen/filters/sfzHpf2p.hxx | 4 ++-- src/sfizz/gen/filters/sfzHpf2pSv.hxx | 4 ++-- src/sfizz/gen/filters/sfzHpf4p.hxx | 4 ++-- src/sfizz/gen/filters/sfzHpf6p.hxx | 4 ++-- src/sfizz/gen/filters/sfzHsh.hxx | 6 ++--- src/sfizz/gen/filters/sfzLpf1p.hxx | 2 +- src/sfizz/gen/filters/sfzLpf2p.hxx | 4 ++-- src/sfizz/gen/filters/sfzLpf2pSv.hxx | 4 ++-- src/sfizz/gen/filters/sfzLpf4p.hxx | 4 ++-- src/sfizz/gen/filters/sfzLpf6p.hxx | 4 ++-- src/sfizz/gen/filters/sfzLsh.hxx | 6 ++--- src/sfizz/gen/filters/sfzPeq.hxx | 6 ++--- 50 files changed, 112 insertions(+), 112 deletions(-) diff --git a/src/sfizz/gen/filters/sfz2chApf1p.hxx b/src/sfizz/gen/filters/sfz2chApf1p.hxx index 33ccbcfe..6e7aef00 100644 --- a/src/sfizz/gen/filters/sfz2chApf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chApf1p.hxx @@ -119,7 +119,7 @@ class faust2chApf1p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (((fConst2 * double(fHslider0)) + -1.0) * (1.0 - fSlow0)); + double fSlow1 = (((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0)))) + -1.0) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chBpf1p.hxx b/src/sfizz/gen/filters/sfz2chBpf1p.hxx index 6145ed42..6243be67 100644 --- a/src/sfizz/gen/filters/sfz2chBpf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf1p.hxx @@ -127,7 +127,7 @@ class faust2chBpf1p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * std::min(20000.0, std::max(1.0, double(fHslider0))))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chBpf2p.hxx b/src/sfizz/gen/filters/sfz2chBpf2p.hxx index 4ebc2083..5c591b9e 100644 --- a/src/sfizz/gen/filters/sfz2chBpf2p.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf2p.hxx @@ -169,9 +169,9 @@ class faust2chBpf2p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); diff --git a/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx b/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx index 2719a4d8..398dfec1 100644 --- a/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf2pSv.hxx @@ -138,8 +138,8 @@ class faust2chBpf2pSv : public sfzFilterDsp { FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow2 = (std::tan((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0))))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chBpf4p.hxx b/src/sfizz/gen/filters/sfz2chBpf4p.hxx index 84fe9ac1..cb7113d0 100644 --- a/src/sfizz/gen/filters/sfz2chBpf4p.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf4p.hxx @@ -209,9 +209,9 @@ class faust2chBpf4p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); diff --git a/src/sfizz/gen/filters/sfz2chBpf6p.hxx b/src/sfizz/gen/filters/sfz2chBpf6p.hxx index 473690f6..78495246 100644 --- a/src/sfizz/gen/filters/sfz2chBpf6p.hxx +++ b/src/sfizz/gen/filters/sfz2chBpf6p.hxx @@ -249,9 +249,9 @@ class faust2chBpf6p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); diff --git a/src/sfizz/gen/filters/sfz2chBrf1p.hxx b/src/sfizz/gen/filters/sfz2chBrf1p.hxx index 4817a6fc..b1bec565 100644 --- a/src/sfizz/gen/filters/sfz2chBrf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chBrf1p.hxx @@ -127,7 +127,7 @@ class faust2chBrf1p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (((fConst2 * double(fHslider0)) + -1.0) * (1.0 - fSlow0)); + double fSlow1 = (((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0)))) + -1.0) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chBrf2p.hxx b/src/sfizz/gen/filters/sfz2chBrf2p.hxx index 2c4a25af..b802972f 100644 --- a/src/sfizz/gen/filters/sfz2chBrf2p.hxx +++ b/src/sfizz/gen/filters/sfz2chBrf2p.hxx @@ -161,8 +161,8 @@ class faust2chBrf2p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); - double fSlow2 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); + double fSlow2 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = (1.0 - fSlow0); double fSlow5 = (((0.0 - (2.0 * std::cos(fSlow1))) / fSlow3) * fSlow4); diff --git a/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx b/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx index 020f13b0..c9b75ee2 100644 --- a/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx +++ b/src/sfizz/gen/filters/sfz2chBrf2pSv.hxx @@ -138,8 +138,8 @@ class faust2chBrf2pSv : public sfzFilterDsp { FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow2 = (std::tan((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0))))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chEqHshelf.hxx b/src/sfizz/gen/filters/sfz2chEqHshelf.hxx index 62447f2b..fc2a9c74 100644 --- a/src/sfizz/gen/filters/sfz2chEqHshelf.hxx +++ b/src/sfizz/gen/filters/sfz2chEqHshelf.hxx @@ -174,8 +174,8 @@ class faust2chEqHshelf : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow2 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow3 = std::cos(fSlow2); double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = (faust2chEqHshelf_faustpower2_f(fSlow1) + 1.0); diff --git a/src/sfizz/gen/filters/sfz2chEqLshelf.hxx b/src/sfizz/gen/filters/sfz2chEqLshelf.hxx index 5859b454..f07d9038 100644 --- a/src/sfizz/gen/filters/sfz2chEqLshelf.hxx +++ b/src/sfizz/gen/filters/sfz2chEqLshelf.hxx @@ -174,8 +174,8 @@ class faust2chEqLshelf : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow2 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow3 = std::cos(fSlow2); double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = (fSlow1 + -1.0); diff --git a/src/sfizz/gen/filters/sfz2chEqPeak.hxx b/src/sfizz/gen/filters/sfz2chEqPeak.hxx index cac02e65..87b552cf 100644 --- a/src/sfizz/gen/filters/sfz2chEqPeak.hxx +++ b/src/sfizz/gen/filters/sfz2chEqPeak.hxx @@ -170,11 +170,11 @@ class faust2chEqPeak : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::max(0.0, double(fHslider0)); - double fSlow2 = (fConst2 * fSlow1); + double fSlow1 = std::min(20000.0, std::max(1.0, double(fHslider0))); + double fSlow2 = (fConst2 * std::max(0.0, fSlow1)); double fSlow3 = std::sin(fSlow2); - double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * std::max(0.001, double(fVslider1))) / fSlow3))))))); + double fSlow4 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * std::min(12.0, std::max(0.01, double(fVslider1)))) / std::sin((fConst2 * fSlow1))))))))); double fSlow6 = (0.5 * (fSlow3 / (fSlow4 * fSlow5))); double fSlow7 = (fSlow6 + 1.0); double fSlow8 = (1.0 - fSlow0); diff --git a/src/sfizz/gen/filters/sfz2chHpf1p.hxx b/src/sfizz/gen/filters/sfz2chHpf1p.hxx index 57ca9c51..a0a054e2 100644 --- a/src/sfizz/gen/filters/sfz2chHpf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf1p.hxx @@ -119,7 +119,7 @@ class faust2chHpf1p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * std::min(20000.0, std::max(1.0, double(fHslider0))))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chHpf2p.hxx b/src/sfizz/gen/filters/sfz2chHpf2p.hxx index 99967081..49059293 100644 --- a/src/sfizz/gen/filters/sfz2chHpf2p.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf2p.hxx @@ -165,9 +165,9 @@ class faust2chHpf2p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); diff --git a/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx b/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx index 6ff0bb53..6631a898 100644 --- a/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf2pSv.hxx @@ -138,8 +138,8 @@ class faust2chHpf2pSv : public sfzFilterDsp { FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow2 = (std::tan((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0))))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chHpf4p.hxx b/src/sfizz/gen/filters/sfz2chHpf4p.hxx index d6e829be..85ddb785 100644 --- a/src/sfizz/gen/filters/sfz2chHpf4p.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf4p.hxx @@ -205,9 +205,9 @@ class faust2chHpf4p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); diff --git a/src/sfizz/gen/filters/sfz2chHpf6p.hxx b/src/sfizz/gen/filters/sfz2chHpf6p.hxx index b2fdbd97..4c848e81 100644 --- a/src/sfizz/gen/filters/sfz2chHpf6p.hxx +++ b/src/sfizz/gen/filters/sfz2chHpf6p.hxx @@ -245,9 +245,9 @@ class faust2chHpf6p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); diff --git a/src/sfizz/gen/filters/sfz2chHsh.hxx b/src/sfizz/gen/filters/sfz2chHsh.hxx index 7f7240d1..7bb9fde3 100644 --- a/src/sfizz/gen/filters/sfz2chHsh.hxx +++ b/src/sfizz/gen/filters/sfz2chHsh.hxx @@ -171,11 +171,11 @@ class faust2chHsh : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow2 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow3 = std::cos(fSlow2); double fSlow4 = ((fSlow1 + 1.0) * fSlow3); - double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider1))))); + double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider1))))))); double fSlow6 = ((fSlow1 + -1.0) * fSlow3); double fSlow7 = ((fSlow1 + fSlow5) + (1.0 - fSlow6)); double fSlow8 = (1.0 - fSlow0); diff --git a/src/sfizz/gen/filters/sfz2chLpf1p.hxx b/src/sfizz/gen/filters/sfz2chLpf1p.hxx index 83819344..8567bcaf 100644 --- a/src/sfizz/gen/filters/sfz2chLpf1p.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf1p.hxx @@ -119,7 +119,7 @@ class faust2chLpf1p : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * std::min(20000.0, std::max(1.0, double(fHslider0))))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chLpf2p.hxx b/src/sfizz/gen/filters/sfz2chLpf2p.hxx index b120b92a..1ee9a6f8 100644 --- a/src/sfizz/gen/filters/sfz2chLpf2p.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf2p.hxx @@ -164,9 +164,9 @@ class faust2chLpf2p : public sfzFilterDsp { FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); + double fSlow0 = (fConst1 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); diff --git a/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx b/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx index 75c2243b..6c42c4ed 100644 --- a/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf2pSv.hxx @@ -138,8 +138,8 @@ class faust2chLpf2pSv : public sfzFilterDsp { FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow2 = (std::tan((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0))))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); diff --git a/src/sfizz/gen/filters/sfz2chLpf4p.hxx b/src/sfizz/gen/filters/sfz2chLpf4p.hxx index 448704b2..7fabed76 100644 --- a/src/sfizz/gen/filters/sfz2chLpf4p.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf4p.hxx @@ -204,9 +204,9 @@ class faust2chLpf4p : public sfzFilterDsp { FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); + double fSlow0 = (fConst1 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); diff --git a/src/sfizz/gen/filters/sfz2chLpf6p.hxx b/src/sfizz/gen/filters/sfz2chLpf6p.hxx index 0d3ce7f2..b2ce9fca 100644 --- a/src/sfizz/gen/filters/sfz2chLpf6p.hxx +++ b/src/sfizz/gen/filters/sfz2chLpf6p.hxx @@ -46,10 +46,10 @@ class faust2chLpf6p : public sfzFilterDsp { FAUSTFLOAT fVslider0; double fConst2; double fRec2[2]; - double fRec7[2]; double fVec0[2]; - double fRec8[2]; + double fRec7[2]; double fVec1[2]; + double fRec8[2]; double fVec2[2]; double fRec9[2]; double fRec6[2]; @@ -117,16 +117,16 @@ class faust2chLpf6p : public sfzFilterDsp { fRec2[l0] = 0.0; } for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { - fRec7[l1] = 0.0; + fVec0[l1] = 0.0; } for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) { - fVec0[l2] = 0.0; + fRec7[l2] = 0.0; } for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) { - fRec8[l3] = 0.0; + fVec1[l3] = 0.0; } for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) { - fVec1[l4] = 0.0; + fRec8[l4] = 0.0; } for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) { fVec2[l5] = 0.0; @@ -244,9 +244,9 @@ class faust2chLpf6p : public sfzFilterDsp { FAUSTFLOAT const* input1 = inputs[1]; FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; - double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); + double fSlow0 = (fConst1 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); @@ -259,14 +259,14 @@ class faust2chLpf6p : public sfzFilterDsp { double fTemp0 = double(input0[i]); double fTemp1 = double(input1[i]); fRec2[0] = (fSlow7 + (fSlow5 * fRec2[1])); + fVec0[0] = (fTemp0 * fRec2[0]); fRec7[0] = ((fSlow5 * fRec7[1]) + fSlow8); double fTemp2 = (fTemp0 * fRec7[0]); - fVec0[0] = fTemp2; + fVec1[0] = fTemp2; fRec8[0] = ((fSlow5 * fRec8[1]) + fSlow9); - fVec1[0] = (fVec0[1] - (fRec8[0] * fRec5[1])); - fVec2[0] = (fTemp0 * fRec2[0]); + fVec2[0] = (fVec1[1] - (fRec8[0] * fRec5[1])); fRec9[0] = ((fSlow5 * fRec9[1]) + fSlow10); - fRec6[0] = ((fVec1[1] + (fTemp2 + fVec2[1])) - (fRec9[0] * fRec6[1])); + fRec6[0] = ((fVec0[1] + (fTemp2 + fVec2[1])) - (fRec9[0] * fRec6[1])); fRec5[0] = fRec6[0]; fVec3[0] = (fRec2[0] * fRec5[0]); double fTemp3 = (fRec7[0] * fRec5[0]); @@ -301,10 +301,10 @@ class faust2chLpf6p : public sfzFilterDsp { fRec10[0] = fRec11[0]; output1[i] = FAUSTFLOAT(fRec10[0]); fRec2[1] = fRec2[0]; - fRec7[1] = fRec7[0]; fVec0[1] = fVec0[0]; - fRec8[1] = fRec8[0]; + fRec7[1] = fRec7[0]; fVec1[1] = fVec1[0]; + fRec8[1] = fRec8[0]; fVec2[1] = fVec2[0]; fRec9[1] = fRec9[0]; fRec6[1] = fRec6[0]; diff --git a/src/sfizz/gen/filters/sfz2chLsh.hxx b/src/sfizz/gen/filters/sfz2chLsh.hxx index 41d5f8a3..b3ec808f 100644 --- a/src/sfizz/gen/filters/sfz2chLsh.hxx +++ b/src/sfizz/gen/filters/sfz2chLsh.hxx @@ -171,12 +171,12 @@ class faust2chLsh : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow2 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow3 = std::cos(fSlow2); double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = ((fSlow1 + -1.0) * fSlow3); - double fSlow6 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider1))))); + double fSlow6 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider1))))))); double fSlow7 = (fSlow5 + fSlow6); double fSlow8 = ((fSlow1 + fSlow7) + 1.0); double fSlow9 = (1.0 - fSlow0); diff --git a/src/sfizz/gen/filters/sfz2chPeq.hxx b/src/sfizz/gen/filters/sfz2chPeq.hxx index c23009d1..6126a8fd 100644 --- a/src/sfizz/gen/filters/sfz2chPeq.hxx +++ b/src/sfizz/gen/filters/sfz2chPeq.hxx @@ -167,10 +167,10 @@ class faust2chPeq : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; FAUSTFLOAT* output1 = outputs[1]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); - double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider1))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); + double fSlow4 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider1))))); double fSlow5 = (0.5 * (fSlow2 / (fSlow3 * fSlow4))); double fSlow6 = (fSlow5 + 1.0); double fSlow7 = (1.0 - fSlow0); diff --git a/src/sfizz/gen/filters/sfzApf1p.hxx b/src/sfizz/gen/filters/sfzApf1p.hxx index 2e674295..4e473e63 100644 --- a/src/sfizz/gen/filters/sfzApf1p.hxx +++ b/src/sfizz/gen/filters/sfzApf1p.hxx @@ -113,7 +113,7 @@ class faustApf1p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (((fConst2 * double(fHslider0)) + -1.0) * (1.0 - fSlow0)); + double fSlow1 = (((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0)))) + -1.0) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); diff --git a/src/sfizz/gen/filters/sfzBpf1p.hxx b/src/sfizz/gen/filters/sfzBpf1p.hxx index e714e436..7013d92f 100644 --- a/src/sfizz/gen/filters/sfzBpf1p.hxx +++ b/src/sfizz/gen/filters/sfzBpf1p.hxx @@ -117,7 +117,7 @@ class faustBpf1p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * std::min(20000.0, std::max(1.0, double(fHslider0))))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec2[0] = ((fSlow0 * fRec2[1]) + fSlow1); diff --git a/src/sfizz/gen/filters/sfzBpf2p.hxx b/src/sfizz/gen/filters/sfzBpf2p.hxx index fea43873..9a0c61dc 100644 --- a/src/sfizz/gen/filters/sfzBpf2p.hxx +++ b/src/sfizz/gen/filters/sfzBpf2p.hxx @@ -147,9 +147,9 @@ class faustBpf2p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); diff --git a/src/sfizz/gen/filters/sfzBpf2pSv.hxx b/src/sfizz/gen/filters/sfzBpf2pSv.hxx index 19389f89..19b66dec 100644 --- a/src/sfizz/gen/filters/sfzBpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfzBpf2pSv.hxx @@ -128,8 +128,8 @@ class faustBpf2pSv : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow2 = (std::tan((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0))))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec3[0] = ((fSlow0 * fRec3[1]) + fSlow2); diff --git a/src/sfizz/gen/filters/sfzBpf4p.hxx b/src/sfizz/gen/filters/sfzBpf4p.hxx index 1342d920..e51efc1b 100644 --- a/src/sfizz/gen/filters/sfzBpf4p.hxx +++ b/src/sfizz/gen/filters/sfzBpf4p.hxx @@ -167,9 +167,9 @@ class faustBpf4p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); diff --git a/src/sfizz/gen/filters/sfzBpf6p.hxx b/src/sfizz/gen/filters/sfzBpf6p.hxx index f595a458..98fc4b1e 100644 --- a/src/sfizz/gen/filters/sfzBpf6p.hxx +++ b/src/sfizz/gen/filters/sfzBpf6p.hxx @@ -187,9 +187,9 @@ class faustBpf6p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); double fSlow4 = (0.5 * (fSlow2 / fSlow3)); double fSlow5 = (fSlow4 + 1.0); double fSlow6 = (0.5 * (fSlow2 / (fSlow3 * fSlow5))); diff --git a/src/sfizz/gen/filters/sfzBrf1p.hxx b/src/sfizz/gen/filters/sfzBrf1p.hxx index 4630be05..ed5d662c 100644 --- a/src/sfizz/gen/filters/sfzBrf1p.hxx +++ b/src/sfizz/gen/filters/sfzBrf1p.hxx @@ -117,7 +117,7 @@ class faustBrf1p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (((fConst2 * double(fHslider0)) + -1.0) * (1.0 - fSlow0)); + double fSlow1 = (((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0)))) + -1.0) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec2[0] = ((fSlow0 * fRec2[1]) + fSlow1); diff --git a/src/sfizz/gen/filters/sfzBrf2p.hxx b/src/sfizz/gen/filters/sfzBrf2p.hxx index 8e0635d1..210366e5 100644 --- a/src/sfizz/gen/filters/sfzBrf2p.hxx +++ b/src/sfizz/gen/filters/sfzBrf2p.hxx @@ -139,8 +139,8 @@ class faustBrf2p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); - double fSlow2 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); + double fSlow2 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = (1.0 - fSlow0); double fSlow5 = (((0.0 - (2.0 * std::cos(fSlow1))) / fSlow3) * fSlow4); diff --git a/src/sfizz/gen/filters/sfzBrf2pSv.hxx b/src/sfizz/gen/filters/sfzBrf2pSv.hxx index 70ccbdc6..4a50a451 100644 --- a/src/sfizz/gen/filters/sfzBrf2pSv.hxx +++ b/src/sfizz/gen/filters/sfzBrf2pSv.hxx @@ -128,8 +128,8 @@ class faustBrf2pSv : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow2 = (std::tan((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0))))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec5[0] = ((fSlow0 * fRec5[1]) + fSlow2); diff --git a/src/sfizz/gen/filters/sfzEqHshelf.hxx b/src/sfizz/gen/filters/sfzEqHshelf.hxx index e09cd941..8ec67785 100644 --- a/src/sfizz/gen/filters/sfzEqHshelf.hxx +++ b/src/sfizz/gen/filters/sfzEqHshelf.hxx @@ -152,8 +152,8 @@ class faustEqHshelf : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow2 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow3 = std::cos(fSlow2); double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = (faustEqHshelf_faustpower2_f(fSlow1) + 1.0); diff --git a/src/sfizz/gen/filters/sfzEqLshelf.hxx b/src/sfizz/gen/filters/sfzEqLshelf.hxx index ac938e6b..33f6e8de 100644 --- a/src/sfizz/gen/filters/sfzEqLshelf.hxx +++ b/src/sfizz/gen/filters/sfzEqLshelf.hxx @@ -152,8 +152,8 @@ class faustEqLshelf : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow2 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow3 = std::cos(fSlow2); double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = (fSlow1 + -1.0); diff --git a/src/sfizz/gen/filters/sfzEqPeak.hxx b/src/sfizz/gen/filters/sfzEqPeak.hxx index 251815b8..44eeb706 100644 --- a/src/sfizz/gen/filters/sfzEqPeak.hxx +++ b/src/sfizz/gen/filters/sfzEqPeak.hxx @@ -148,11 +148,11 @@ class faustEqPeak : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::max(0.0, double(fHslider0)); - double fSlow2 = (fConst2 * fSlow1); + double fSlow1 = std::min(20000.0, std::max(1.0, double(fHslider0))); + double fSlow2 = (fConst2 * std::max(0.0, fSlow1)); double fSlow3 = std::sin(fSlow2); - double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * std::max(0.001, double(fVslider1))) / fSlow3))))))); + double fSlow4 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow5 = std::max(0.001, (0.5 / double(sinh(double((fConst3 * ((fSlow1 * std::min(12.0, std::max(0.01, double(fVslider1)))) / std::sin((fConst2 * fSlow1))))))))); double fSlow6 = (0.5 * (fSlow3 / (fSlow4 * fSlow5))); double fSlow7 = (fSlow6 + 1.0); double fSlow8 = (1.0 - fSlow0); diff --git a/src/sfizz/gen/filters/sfzHpf1p.hxx b/src/sfizz/gen/filters/sfzHpf1p.hxx index dce88d8d..b96ec816 100644 --- a/src/sfizz/gen/filters/sfzHpf1p.hxx +++ b/src/sfizz/gen/filters/sfzHpf1p.hxx @@ -113,7 +113,7 @@ class faustHpf1p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * std::min(20000.0, std::max(1.0, double(fHslider0))))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); diff --git a/src/sfizz/gen/filters/sfzHpf2p.hxx b/src/sfizz/gen/filters/sfzHpf2p.hxx index 3b065b2e..9934aabf 100644 --- a/src/sfizz/gen/filters/sfzHpf2p.hxx +++ b/src/sfizz/gen/filters/sfzHpf2p.hxx @@ -143,9 +143,9 @@ class faustHpf2p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); diff --git a/src/sfizz/gen/filters/sfzHpf2pSv.hxx b/src/sfizz/gen/filters/sfzHpf2pSv.hxx index 65e1008f..2dc0420a 100644 --- a/src/sfizz/gen/filters/sfzHpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfzHpf2pSv.hxx @@ -128,8 +128,8 @@ class faustHpf2pSv : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow2 = (std::tan((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0))))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec4[0] = ((fSlow0 * fRec4[1]) + fSlow2); diff --git a/src/sfizz/gen/filters/sfzHpf4p.hxx b/src/sfizz/gen/filters/sfzHpf4p.hxx index 0a4e8660..1ffeed51 100644 --- a/src/sfizz/gen/filters/sfzHpf4p.hxx +++ b/src/sfizz/gen/filters/sfzHpf4p.hxx @@ -163,9 +163,9 @@ class faustHpf4p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); diff --git a/src/sfizz/gen/filters/sfzHpf6p.hxx b/src/sfizz/gen/filters/sfzHpf6p.hxx index 8c66173e..ab376387 100644 --- a/src/sfizz/gen/filters/sfzHpf6p.hxx +++ b/src/sfizz/gen/filters/sfzHpf6p.hxx @@ -183,9 +183,9 @@ class faustHpf6p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::cos(fSlow1); - double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow3 = (0.5 * (std::sin(fSlow1) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow4 = (fSlow3 + 1.0); double fSlow5 = (1.0 - fSlow0); double fSlow6 = (((-1.0 - fSlow2) / fSlow4) * fSlow5); diff --git a/src/sfizz/gen/filters/sfzHsh.hxx b/src/sfizz/gen/filters/sfzHsh.hxx index 5570875b..fc80a946 100644 --- a/src/sfizz/gen/filters/sfzHsh.hxx +++ b/src/sfizz/gen/filters/sfzHsh.hxx @@ -149,11 +149,11 @@ class faustHsh : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow2 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow3 = std::cos(fSlow2); double fSlow4 = ((fSlow1 + 1.0) * fSlow3); - double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider1))))); + double fSlow5 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider1))))))); double fSlow6 = ((fSlow1 + -1.0) * fSlow3); double fSlow7 = ((fSlow1 + fSlow5) + (1.0 - fSlow6)); double fSlow8 = (1.0 - fSlow0); diff --git a/src/sfizz/gen/filters/sfzLpf1p.hxx b/src/sfizz/gen/filters/sfzLpf1p.hxx index bbec0a8a..7c6d95c9 100644 --- a/src/sfizz/gen/filters/sfzLpf1p.hxx +++ b/src/sfizz/gen/filters/sfzLpf1p.hxx @@ -113,7 +113,7 @@ class faustLpf1p : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * double(fHslider0))))) * (1.0 - fSlow0)); + double fSlow1 = (std::exp((fConst2 * (0.0 - (6.2831853071795862 * std::min(20000.0, std::max(1.0, double(fHslider0))))))) * (1.0 - fSlow0)); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow1); diff --git a/src/sfizz/gen/filters/sfzLpf2p.hxx b/src/sfizz/gen/filters/sfzLpf2p.hxx index 105fd66f..43880467 100644 --- a/src/sfizz/gen/filters/sfzLpf2p.hxx +++ b/src/sfizz/gen/filters/sfzLpf2p.hxx @@ -142,9 +142,9 @@ class faustLpf2p : public sfzFilterDsp { //[Begin:compute] FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); + double fSlow0 = (fConst1 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); diff --git a/src/sfizz/gen/filters/sfzLpf2pSv.hxx b/src/sfizz/gen/filters/sfzLpf2pSv.hxx index a1af4a96..f303bb73 100644 --- a/src/sfizz/gen/filters/sfzLpf2pSv.hxx +++ b/src/sfizz/gen/filters/sfzLpf2pSv.hxx @@ -128,8 +128,8 @@ class faustLpf2pSv : public sfzFilterDsp { FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); double fSlow1 = (1.0 - fSlow0); - double fSlow2 = (std::tan((fConst2 * double(fHslider0))) * fSlow1); - double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); + double fSlow2 = (std::tan((fConst2 * std::min(20000.0, std::max(1.0, double(fHslider0))))) * fSlow1); + double fSlow3 = (1.0 / std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); for (int i = 0; (i < count); i = (i + 1)) { double fTemp0 = double(input0[i]); fRec3[0] = ((fSlow0 * fRec3[1]) + fSlow2); diff --git a/src/sfizz/gen/filters/sfzLpf4p.hxx b/src/sfizz/gen/filters/sfzLpf4p.hxx index f7fe60f9..d0435d56 100644 --- a/src/sfizz/gen/filters/sfzLpf4p.hxx +++ b/src/sfizz/gen/filters/sfzLpf4p.hxx @@ -162,9 +162,9 @@ class faustLpf4p : public sfzFilterDsp { //[Begin:compute] FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); + double fSlow0 = (fConst1 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); diff --git a/src/sfizz/gen/filters/sfzLpf6p.hxx b/src/sfizz/gen/filters/sfzLpf6p.hxx index 263f1683..95f70228 100644 --- a/src/sfizz/gen/filters/sfzLpf6p.hxx +++ b/src/sfizz/gen/filters/sfzLpf6p.hxx @@ -182,9 +182,9 @@ class faustLpf6p : public sfzFilterDsp { //[Begin:compute] FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; - double fSlow0 = (fConst1 * std::max(0.0, double(fHslider0))); + double fSlow0 = (fConst1 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow1 = std::cos(fSlow0); - double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))))); + double fSlow2 = (0.5 * (std::sin(fSlow0) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))))); double fSlow3 = (fSlow2 + 1.0); double fSlow4 = ((1.0 - fSlow1) / fSlow3); double fSlow5 = (fSmoothEnable ? fConst2 : 0.0); diff --git a/src/sfizz/gen/filters/sfzLsh.hxx b/src/sfizz/gen/filters/sfzLsh.hxx index 55d27bbc..b614b558 100644 --- a/src/sfizz/gen/filters/sfzLsh.hxx +++ b/src/sfizz/gen/filters/sfzLsh.hxx @@ -149,12 +149,12 @@ class faustLsh : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = std::pow(10.0, (0.025000000000000001 * double(fVslider0))); - double fSlow2 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider0))))); + double fSlow2 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow3 = std::cos(fSlow2); double fSlow4 = ((fSlow1 + 1.0) * fSlow3); double fSlow5 = ((fSlow1 + -1.0) * fSlow3); - double fSlow6 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider1))))); + double fSlow6 = ((std::sqrt(fSlow1) * std::sin(fSlow2)) / std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider1))))))); double fSlow7 = (fSlow5 + fSlow6); double fSlow8 = ((fSlow1 + fSlow7) + 1.0); double fSlow9 = (1.0 - fSlow0); diff --git a/src/sfizz/gen/filters/sfzPeq.hxx b/src/sfizz/gen/filters/sfzPeq.hxx index a0e6eee5..50ce2084 100644 --- a/src/sfizz/gen/filters/sfzPeq.hxx +++ b/src/sfizz/gen/filters/sfzPeq.hxx @@ -145,10 +145,10 @@ class faustPeq : public sfzFilterDsp { FAUSTFLOAT const* input0 = inputs[0]; FAUSTFLOAT* output0 = outputs[0]; double fSlow0 = (fSmoothEnable ? fConst1 : 0.0); - double fSlow1 = (fConst2 * std::max(0.0, double(fHslider0))); + double fSlow1 = (fConst2 * std::max(0.0, std::min(20000.0, std::max(1.0, double(fHslider0))))); double fSlow2 = std::sin(fSlow1); - double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * double(fVslider0)))); - double fSlow4 = std::pow(10.0, (0.025000000000000001 * double(fVslider1))); + double fSlow3 = std::max(0.001, std::pow(10.0, (0.050000000000000003 * std::min(60.0, std::max(0.0, double(fVslider0)))))); + double fSlow4 = std::pow(10.0, (0.025000000000000001 * std::min(60.0, std::max(-120.0, double(fVslider1))))); double fSlow5 = (0.5 * (fSlow2 / (fSlow3 * fSlow4))); double fSlow6 = (fSlow5 + 1.0); double fSlow7 = (1.0 - fSlow0); From a8f65f5327311daa7c7f4142020c06fd9fb32a56 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 12 Mar 2021 17:31:05 +0100 Subject: [PATCH 391/668] Fix the build of PlotLFO demo --- demos/PlotLFO.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/demos/PlotLFO.cpp b/demos/PlotLFO.cpp index 57e94f51..af8cabff 100644 --- a/demos/PlotLFO.cpp +++ b/demos/PlotLFO.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #ifdef _WIN32 #define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 From 75ca9b7d82155f63085afcfbb07a94ea49516df7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 13 Mar 2021 12:37:41 +0100 Subject: [PATCH 392/668] Linear smoother --- benchmarks/BM_smoothers.cpp | 22 +++---- src/sfizz/Smoothers.cpp | 128 ++++++++++++++++++++++++++++++++++-- src/sfizz/Smoothers.h | 51 +++++++++++++- 3 files changed, 184 insertions(+), 17 deletions(-) diff --git a/benchmarks/BM_smoothers.cpp b/benchmarks/BM_smoothers.cpp index caca19b8..b9755be7 100644 --- a/benchmarks/BM_smoothers.cpp +++ b/benchmarks/BM_smoothers.cpp @@ -34,24 +34,24 @@ public: std::vector output; }; -BENCHMARK_DEFINE_F(SmootherFixture, Linear) (benchmark::State& state) +BENCHMARK_DEFINE_F(SmootherFixture, OnePole) (benchmark::State& state) { - sfz::Smoother smoother; + sfz::OnePoleSmoother smoother; smoother.setSmoothing(10, sfz::config::defaultSampleRate); for (auto _ : state) { smoother.process(input, absl::MakeSpan(output)); } } -// BENCHMARK_DEFINE_F(SmootherFixture, Multiplicative)(benchmark::State& state) { -// sfz::MultiplicativeSmoother smoother; -// smoother.setSmoothing(10, sfz::config::defaultSampleRate); -// for (auto _ : state) -// { -// smoother.process(input, absl::MakeSpan(output)); -// } -// } +BENCHMARK_DEFINE_F(SmootherFixture, Linear) (benchmark::State& state) +{ + sfz::LinearSmoother smoother; + smoother.setSmoothing(10, sfz::config::defaultSampleRate); + for (auto _ : state) { + smoother.process(input, absl::MakeSpan(output)); + } +} +BENCHMARK_REGISTER_F(SmootherFixture, OnePole)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); BENCHMARK_REGISTER_F(SmootherFixture, Linear)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); -// BENCHMARK_REGISTER_F(SmootherFixture, Multiplicative)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); BENCHMARK_MAIN(); diff --git a/src/sfizz/Smoothers.cpp b/src/sfizz/Smoothers.cpp index c2f6e2fb..189249c2 100644 --- a/src/sfizz/Smoothers.cpp +++ b/src/sfizz/Smoothers.cpp @@ -9,14 +9,15 @@ #include "MathHelpers.h" #include "SfzHelpers.h" #include "SIMDHelpers.h" +#include namespace sfz { -Smoother::Smoother() +OnePoleSmoother::OnePoleSmoother() { } -void Smoother::setSmoothing(uint8_t smoothValue, float sampleRate) +void OnePoleSmoother::setSmoothing(uint8_t smoothValue, float sampleRate) { smoothing = (smoothValue > 0); if (smoothing) { @@ -24,12 +25,12 @@ void Smoother::setSmoothing(uint8_t smoothValue, float sampleRate) } } -void Smoother::reset(float value) +void OnePoleSmoother::reset(float value) { filter.reset(value); } -void Smoother::process(absl::Span input, absl::Span output, bool canShortcut) +void OnePoleSmoother::process(absl::Span input, absl::Span output, bool canShortcut) { CHECK_SPAN_SIZES(input, output); if (input.size() == 0) @@ -53,4 +54,123 @@ void Smoother::process(absl::Span input, absl::Span output, } } +/// +LinearSmoother::LinearSmoother() +{ +} + +void LinearSmoother::setSmoothing(uint8_t smoothValue, float sampleRate) +{ + const float smoothTime = 1e-3f * smoothValue; + smoothFrames_ = static_cast(smoothTime * sampleRate); +} + +void LinearSmoother::reset(float value) +{ + current_ = value; + target_ = value; + step_ = 0.0; + framesToTarget_ = 0; +} + +void LinearSmoother::process(absl::Span input, absl::Span output, bool canShortcut) +{ + CHECK_SPAN_SIZES(input, output); + + uint32_t i = 0; + const uint32_t count = static_cast(input.size()); + if (count == 0) + return; + + float current = current_; + float target = target_; + + if (canShortcut && current == target && current == input.front()) { + if (input.data() != output.data()) + copy(input, output); + reset(input.back()); + return; + } + + float step = step_; + int32_t framesToTarget = framesToTarget_; + const int32_t smoothFrames = smoothFrames_; + + for (; i + 15 < count; i += 16) { + const float nextTarget = input[i + 15]; + if (target != nextTarget) { + target = nextTarget; + //framesToTarget = (framesToTarget > 0) ? framesToTarget : smoothFrames; + framesToTarget = smoothFrames; + step = (target - current) / max(1, framesToTarget); + } + const simde__m128 targetX4 = simde_mm_set1_ps(target); + if (target > current) { + simde__m128 stepX4 = simde_mm_set1_ps(step); + simde__m128 tmp1X4 = simde_mm_mul_ps(stepX4, simde_mm_setr_ps(1.0f, 2.0f, 3.0f, 4.0f)); + simde__m128 tmp2X4 = simde_mm_shuffle_ps(tmp1X4, tmp1X4, SIMDE_MM_SHUFFLE(3, 3, 3, 3)); + simde__m128 current1X4 = simde_mm_add_ps(simde_mm_set1_ps(current), tmp1X4); + simde_mm_storeu_ps(&output[i], simde_mm_min_ps(current1X4, targetX4)); + simde__m128 current2X4 = simde_mm_add_ps(current1X4, tmp2X4); + simde_mm_storeu_ps(&output[i + 4], simde_mm_min_ps(current2X4, targetX4)); + simde__m128 current3X4 = simde_mm_add_ps(current2X4, tmp2X4); + simde_mm_storeu_ps(&output[i + 8], simde_mm_min_ps(current3X4, targetX4)); + simde__m128 current4X4 = simde_mm_add_ps(current3X4, tmp2X4); + simde__m128 limited4X4 = simde_mm_min_ps(current4X4, targetX4); + simde_mm_storeu_ps(&output[i + 12], limited4X4); + current = simde_mm_cvtss_f32(simde_mm_shuffle_ps(limited4X4, limited4X4, SIMDE_MM_SHUFFLE(3, 3, 3, 3))); + } + else if (target < current) { + simde__m128 stepX4 = simde_mm_set1_ps(step); + simde__m128 tmp1X4 = simde_mm_mul_ps(stepX4, simde_mm_setr_ps(1.0f, 2.0f, 3.0f, 4.0f)); + simde__m128 tmp2X4 = simde_mm_shuffle_ps(tmp1X4, tmp1X4, SIMDE_MM_SHUFFLE(3, 3, 3, 3)); + simde__m128 current1X4 = simde_mm_add_ps(simde_mm_set1_ps(current), tmp1X4); + simde_mm_storeu_ps(&output[i], simde_mm_max_ps(current1X4, targetX4)); + simde__m128 current2X4 = simde_mm_add_ps(current1X4, tmp2X4); + simde_mm_storeu_ps(&output[i + 4], simde_mm_max_ps(current2X4, targetX4)); + simde__m128 current3X4 = simde_mm_add_ps(current2X4, tmp2X4); + simde_mm_storeu_ps(&output[i + 8], simde_mm_max_ps(current3X4, targetX4)); + simde__m128 current4X4 = simde_mm_add_ps(current3X4, tmp2X4); + simde__m128 limited4X4 = simde_mm_max_ps(current4X4, targetX4); + simde_mm_storeu_ps(&output[i + 12], limited4X4); + current = simde_mm_cvtss_f32(simde_mm_shuffle_ps(limited4X4, limited4X4, SIMDE_MM_SHUFFLE(3, 3, 3, 3))); + } + else { + simde_mm_storeu_ps(&output[i], targetX4); + simde_mm_storeu_ps(&output[i + 4], targetX4); + simde_mm_storeu_ps(&output[i + 8], targetX4); + simde_mm_storeu_ps(&output[i + 12], targetX4); + } + framesToTarget -= 16; + } + + if (i < count) { + const float nextTarget = input[count - 1]; + if (target != nextTarget) { + target = nextTarget; + //framesToTarget = (framesToTarget > 0) ? framesToTarget : smoothFrames; + framesToTarget = smoothFrames; + step = (target - current) / max(1, framesToTarget); + } + if (target > current) { + for (; i < count; ++i) + output[i] = current = min(target, current + step); + } + else if (target < current) { + for (; i < count; ++i) + output[i] = current = max(target, current + step); + } + else { + for (; i < count; ++i) + output[i] = target; + } + framesToTarget -= count; + } + + current_ = current; + target_ = target; + step_ = step; + framesToTarget_ = max(0, framesToTarget); +} + } diff --git a/src/sfizz/Smoothers.h b/src/sfizz/Smoothers.h index 50f99821..1d64c9d4 100644 --- a/src/sfizz/Smoothers.h +++ b/src/sfizz/Smoothers.h @@ -14,9 +14,9 @@ namespace sfz { * @brief Wrapper class for a one pole filter smoother * */ -class Smoother { +class OnePoleSmoother { public: - Smoother(); + OnePoleSmoother(); /** * @brief Set the filter cutoff based on the sfz smoothing value * and the sample rate. @@ -49,4 +49,51 @@ private: OnePoleFilter filter {}; }; +/** + * @brief Linear smoother + * + */ +class LinearSmoother { +public: + LinearSmoother(); + /** + * @brief Set the filter cutoff based on the sfz smoothing value + * and the sample rate. + * + * @param smoothValue + * @param sampleRate + */ + void setSmoothing(uint8_t smoothValue, float sampleRate); + /** + * @brief Reset the filter state to a given value + * + * @param value + */ + void reset(float value = 0.0f); + /** + * @brief Process a span of data. Input and output can refer to the same + * memory. + * + * @param input + * @param output + * @param canShortcut whether we can have a fast path if the filter is within + * a reasonable range around the first value of the input + * span. + */ + void process(absl::Span input, absl::Span output, bool canShortcut = false); + + float current() const { return current_; } +private: + float current_ = 0.0; + float target_ = 0.0; + float step_ = 0.0; + int32_t framesToTarget_ = 0; + int32_t smoothFrames_ = 0; +}; + +/** + * @brief Default smoother + */ +using Smoother = LinearSmoother; + } From 6c84d58ad842fdb30bbcbe424a27fcdf04e5b3ba Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 13 Mar 2021 14:19:19 +0100 Subject: [PATCH 393/668] Remove unused variable --- src/sfizz/Smoothers.cpp | 20 ++++++++++---------- src/sfizz/Smoothers.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sfizz/Smoothers.cpp b/src/sfizz/Smoothers.cpp index 189249c2..9dcd8023 100644 --- a/src/sfizz/Smoothers.cpp +++ b/src/sfizz/Smoothers.cpp @@ -70,7 +70,7 @@ void LinearSmoother::reset(float value) current_ = value; target_ = value; step_ = 0.0; - framesToTarget_ = 0; + //framesToTarget_ = 0; } void LinearSmoother::process(absl::Span input, absl::Span output, bool canShortcut) @@ -93,7 +93,7 @@ void LinearSmoother::process(absl::Span input, absl::Span ou } float step = step_; - int32_t framesToTarget = framesToTarget_; + // int32_t framesToTarget = framesToTarget_; const int32_t smoothFrames = smoothFrames_; for (; i + 15 < count; i += 16) { @@ -101,8 +101,8 @@ void LinearSmoother::process(absl::Span input, absl::Span ou if (target != nextTarget) { target = nextTarget; //framesToTarget = (framesToTarget > 0) ? framesToTarget : smoothFrames; - framesToTarget = smoothFrames; - step = (target - current) / max(1, framesToTarget); + //step = (target - current) / max(1, framesToTarget); + step = (target - current) / max(1, smoothFrames); } const simde__m128 targetX4 = simde_mm_set1_ps(target); if (target > current) { @@ -141,16 +141,16 @@ void LinearSmoother::process(absl::Span input, absl::Span ou simde_mm_storeu_ps(&output[i + 8], targetX4); simde_mm_storeu_ps(&output[i + 12], targetX4); } - framesToTarget -= 16; + //framesToTarget -= 16; } if (i < count) { const float nextTarget = input[count - 1]; if (target != nextTarget) { target = nextTarget; - //framesToTarget = (framesToTarget > 0) ? framesToTarget : smoothFrames; - framesToTarget = smoothFrames; - step = (target - current) / max(1, framesToTarget); + // framesToTarget = (framesToTarget > 0) ? framesToTarget : smoothFrames; + // step = (target - current) / max(1, framesToTarget); + step = (target - current) / max(1, smoothFrames); } if (target > current) { for (; i < count; ++i) @@ -164,13 +164,13 @@ void LinearSmoother::process(absl::Span input, absl::Span ou for (; i < count; ++i) output[i] = target; } - framesToTarget -= count; + //framesToTarget -= count; } current_ = current; target_ = target; step_ = step; - framesToTarget_ = max(0, framesToTarget); + //framesToTarget_ = max(0, framesToTarget); } } diff --git a/src/sfizz/Smoothers.h b/src/sfizz/Smoothers.h index 1d64c9d4..e62190eb 100644 --- a/src/sfizz/Smoothers.h +++ b/src/sfizz/Smoothers.h @@ -87,7 +87,7 @@ private: float current_ = 0.0; float target_ = 0.0; float step_ = 0.0; - int32_t framesToTarget_ = 0; + //int32_t framesToTarget_ = 0; int32_t smoothFrames_ = 0; }; From 65ac71a2aa41eb341ac3d2901d5229326c3cd500 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 17 Mar 2021 11:44:14 +0100 Subject: [PATCH 394/668] Add and remove timers only when a frame is active --- plugins/editor/src/editor/Editor.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index fba6c418..b11c9e4c 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -245,11 +245,6 @@ Editor::Editor(EditorController& ctrl) ctrl.decorate(&impl); impl.createFrameContents(); - - uint32_t oscSendInterval = 1; // milliseconds - impl.oscSendQueueTimer_ = makeOwned( - [this](CVSTGUITimer* timer) { impl_->tickOSCQueue(timer); }, - oscSendInterval, false); } Editor::~Editor() @@ -275,6 +270,11 @@ void Editor::open(CFrame& frame) impl_->sendQueuedOSC("/mem/buffers", "", nullptr); }, 1000, true); + uint32_t oscSendInterval = 1; // milliseconds + impl.oscSendQueueTimer_ = makeOwned( + [this](CVSTGUITimer* timer) { impl_->tickOSCQueue(timer); }, + oscSendInterval, false); + // request the whole Key and CC information impl.sendQueuedOSC("/key/slots", "", nullptr); impl.sendQueuedOSC("/sw/last/slots", "", nullptr); @@ -286,6 +286,7 @@ void Editor::close() Impl& impl = *impl_; impl.clearQueuedOSC(); + impl.oscSendQueueTimer_ = nullptr; impl.memQueryTimer_ = nullptr; From fe2fc4501416e8a70c662cc695b9e751364bc0ad Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 18 Mar 2021 00:41:37 +0100 Subject: [PATCH 395/668] Update catch2 --- tests/catch2/Catch.cmake | 206 ++ tests/catch2/CatchAddTests.cmake | 132 ++ tests/catch2/LICENSE.txt | 23 + tests/catch2/catch.hpp | 2482 ++++++++++++++------- tests/catch2/catch_reporter_sonarqube.hpp | 181 ++ tests/catch2/catch_reporter_tap.hpp | 23 +- tests/catch2/catch_reporter_teamcity.hpp | 3 +- 7 files changed, 2199 insertions(+), 851 deletions(-) create mode 100644 tests/catch2/Catch.cmake create mode 100644 tests/catch2/CatchAddTests.cmake create mode 100644 tests/catch2/LICENSE.txt create mode 100644 tests/catch2/catch_reporter_sonarqube.hpp diff --git a/tests/catch2/Catch.cmake b/tests/catch2/Catch.cmake new file mode 100644 index 00000000..a3885162 --- /dev/null +++ b/tests/catch2/Catch.cmake @@ -0,0 +1,206 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +Catch +----- + +This module defines a function to help use the Catch test framework. + +The :command:`catch_discover_tests` discovers tests by asking the compiled test +executable to enumerate its tests. This does not require CMake to be re-run +when tests change. However, it may not work in a cross-compiling environment, +and setting test properties is less convenient. + +This command is intended to replace use of :command:`add_test` to register +tests, and will create a separate CTest test for each Catch test case. Note +that this is in some cases less efficient, as common set-up and tear-down logic +cannot be shared by multiple test cases executing in the same instance. +However, it provides more fine-grained pass/fail information to CTest, which is +usually considered as more beneficial. By default, the CTest test name is the +same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``. + +.. command:: catch_discover_tests + + Automatically add tests with CTest by querying the compiled test executable + for available tests:: + + catch_discover_tests(target + [TEST_SPEC arg1...] + [EXTRA_ARGS arg1...] + [WORKING_DIRECTORY dir] + [TEST_PREFIX prefix] + [TEST_SUFFIX suffix] + [PROPERTIES name1 value1...] + [TEST_LIST var] + [REPORTER reporter] + [OUTPUT_DIR dir] + [OUTPUT_PREFIX prefix} + [OUTPUT_SUFFIX suffix] + ) + + ``catch_discover_tests`` sets up a post-build command on the test executable + that generates the list of tests by parsing the output from running the test + with the ``--list-test-names-only`` argument. This ensures that the full + list of tests is obtained. Since test discovery occurs at build time, it is + not necessary to re-run CMake when the list of tests changes. + However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set + in order to function in a cross-compiling environment. + + Additionally, setting properties on tests is somewhat less convenient, since + the tests are not available at CMake time. Additional test properties may be + assigned to the set of tests as a whole using the ``PROPERTIES`` option. If + more fine-grained test control is needed, custom content may be provided + through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES` + directory property. The set of discovered tests is made accessible to such a + script via the ``_TESTS`` variable. + + The options are: + + ``target`` + Specifies the Catch executable, which must be a known CMake executable + target. CMake will substitute the location of the built executable when + running the test. + + ``TEST_SPEC arg1...`` + Specifies test cases, wildcarded test cases, tags and tag expressions to + pass to the Catch executable with the ``--list-test-names-only`` argument. + + ``EXTRA_ARGS arg1...`` + Any extra arguments to pass on the command line to each test case. + + ``WORKING_DIRECTORY dir`` + Specifies the directory in which to run the discovered test cases. If this + option is not provided, the current binary directory is used. + + ``TEST_PREFIX prefix`` + Specifies a ``prefix`` to be prepended to the name of each discovered test + case. This can be useful when the same test executable is being used in + multiple calls to ``catch_discover_tests()`` but with different + ``TEST_SPEC`` or ``EXTRA_ARGS``. + + ``TEST_SUFFIX suffix`` + Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of + every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may + be specified. + + ``PROPERTIES name1 value1...`` + Specifies additional properties to be set on all tests discovered by this + invocation of ``catch_discover_tests``. + + ``TEST_LIST var`` + Make the list of tests available in the variable ``var``, rather than the + default ``_TESTS``. This can be useful when the same test + executable is being used in multiple calls to ``catch_discover_tests()``. + Note that this variable is only available in CTest. + + ``REPORTER reporter`` + Use the specified reporter when running the test case. The reporter will + be passed to the Catch executable as ``--reporter reporter``. + + ``OUTPUT_DIR dir`` + If specified, the parameter is passed along as + ``--out dir/`` to Catch executable. The actual file name is the + same as the test name. This should be used instead of + ``EXTRA_ARGS --out foo`` to avoid race conditions writing the result output + when using parallel test execution. + + ``OUTPUT_PREFIX prefix`` + May be used in conjunction with ``OUTPUT_DIR``. + If specified, ``prefix`` is added to each output file name, like so + ``--out dir/prefix``. + + ``OUTPUT_SUFFIX suffix`` + May be used in conjunction with ``OUTPUT_DIR``. + If specified, ``suffix`` is added to each output file name, like so + ``--out dir/suffix``. This can be used to add a file extension to + the output e.g. ".xml". + +#]=======================================================================] + +#------------------------------------------------------------------------------ +function(catch_discover_tests TARGET) + cmake_parse_arguments( + "" + "" + "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX" + "TEST_SPEC;EXTRA_ARGS;PROPERTIES" + ${ARGN} + ) + + if(NOT _WORKING_DIRECTORY) + set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() + if(NOT _TEST_LIST) + set(_TEST_LIST ${TARGET}_TESTS) + endif() + + ## Generate a unique name based on the extra arguments + string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}") + string(SUBSTRING ${args_hash} 0 7 args_hash) + + # Define rule to generate test list for aforementioned test executable + set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake") + set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake") + get_property(crosscompiling_emulator + TARGET ${TARGET} + PROPERTY CROSSCOMPILING_EMULATOR + ) + add_custom_command( + TARGET ${TARGET} POST_BUILD + BYPRODUCTS "${ctest_tests_file}" + COMMAND "${CMAKE_COMMAND}" + -D "TEST_TARGET=${TARGET}" + -D "TEST_EXECUTABLE=$" + -D "TEST_EXECUTOR=${crosscompiling_emulator}" + -D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}" + -D "TEST_SPEC=${_TEST_SPEC}" + -D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}" + -D "TEST_PROPERTIES=${_PROPERTIES}" + -D "TEST_PREFIX=${_TEST_PREFIX}" + -D "TEST_SUFFIX=${_TEST_SUFFIX}" + -D "TEST_LIST=${_TEST_LIST}" + -D "TEST_REPORTER=${_REPORTER}" + -D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}" + -D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}" + -D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}" + -D "CTEST_FILE=${ctest_tests_file}" + -P "${_CATCH_DISCOVER_TESTS_SCRIPT}" + VERBATIM + ) + + file(WRITE "${ctest_include_file}" + "if(EXISTS \"${ctest_tests_file}\")\n" + " include(\"${ctest_tests_file}\")\n" + "else()\n" + " add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n" + "endif()\n" + ) + + if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + # Add discovered tests to directory TEST_INCLUDE_FILES + set_property(DIRECTORY + APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}" + ) + else() + # Add discovered tests as directory TEST_INCLUDE_FILE if possible + get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET) + if (NOT ${test_include_file_set}) + set_property(DIRECTORY + PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}" + ) + else() + message(FATAL_ERROR + "Cannot set more than one TEST_INCLUDE_FILE" + ) + endif() + endif() + +endfunction() + +############################################################################### + +set(_CATCH_DISCOVER_TESTS_SCRIPT + ${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake + CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file" +) diff --git a/tests/catch2/CatchAddTests.cmake b/tests/catch2/CatchAddTests.cmake new file mode 100644 index 00000000..18286b71 --- /dev/null +++ b/tests/catch2/CatchAddTests.cmake @@ -0,0 +1,132 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +set(prefix "${TEST_PREFIX}") +set(suffix "${TEST_SUFFIX}") +set(spec ${TEST_SPEC}) +set(extra_args ${TEST_EXTRA_ARGS}) +set(properties ${TEST_PROPERTIES}) +set(reporter ${TEST_REPORTER}) +set(output_dir ${TEST_OUTPUT_DIR}) +set(output_prefix ${TEST_OUTPUT_PREFIX}) +set(output_suffix ${TEST_OUTPUT_SUFFIX}) +set(script) +set(suite) +set(tests) + +function(add_command NAME) + set(_args "") + foreach(_arg ${ARGN}) + if(_arg MATCHES "[^-./:a-zA-Z0-9_]") + set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument + else() + set(_args "${_args} ${_arg}") + endif() + endforeach() + set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE) +endfunction() + +# Run test executable to get list of available tests +if(NOT EXISTS "${TEST_EXECUTABLE}") + message(FATAL_ERROR + "Specified test executable '${TEST_EXECUTABLE}' does not exist" + ) +endif() +execute_process( + COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only + OUTPUT_VARIABLE output + RESULT_VARIABLE result + WORKING_DIRECTORY "${TEST_WORKING_DIR}" +) +# Catch --list-test-names-only reports the number of tests, so 0 is... surprising +if(${result} EQUAL 0) + message(WARNING + "Test executable '${TEST_EXECUTABLE}' contains no tests!\n" + ) +elseif(${result} LESS 0) + message(FATAL_ERROR + "Error running test executable '${TEST_EXECUTABLE}':\n" + " Result: ${result}\n" + " Output: ${output}\n" + ) +endif() + +string(REPLACE "\n" ";" output "${output}") + +# Run test executable to get list of available reporters +execute_process( + COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-reporters + OUTPUT_VARIABLE reporters_output + RESULT_VARIABLE reporters_result + WORKING_DIRECTORY "${TEST_WORKING_DIR}" +) +if(${reporters_result} EQUAL 0) + message(WARNING + "Test executable '${TEST_EXECUTABLE}' contains no reporters!\n" + ) +elseif(${reporters_result} LESS 0) + message(FATAL_ERROR + "Error running test executable '${TEST_EXECUTABLE}':\n" + " Result: ${reporters_result}\n" + " Output: ${reporters_output}\n" + ) +endif() +string(FIND "${reporters_output}" "${reporter}" reporter_is_valid) +if(reporter AND ${reporter_is_valid} EQUAL -1) + message(FATAL_ERROR + "\"${reporter}\" is not a valid reporter!\n" + ) +endif() + +# Prepare reporter +if(reporter) + set(reporter_arg "--reporter ${reporter}") +endif() + +# Prepare output dir +if(output_dir AND NOT IS_ABSOLUTE ${output_dir}) + set(output_dir "${TEST_WORKING_DIR}/${output_dir}") + if(NOT EXISTS ${output_dir}) + file(MAKE_DIRECTORY ${output_dir}) + endif() +endif() + +# Parse output +foreach(line ${output}) + set(test ${line}) + # Escape characters in test case names that would be parsed by Catch2 + set(test_name ${test}) + foreach(char , [ ]) + string(REPLACE ${char} "\\${char}" test_name ${test_name}) + endforeach(char) + # ...add output dir + if(output_dir) + string(REGEX REPLACE "[^A-Za-z0-9_]" "_" test_name_clean ${test_name}) + set(output_dir_arg "--out ${output_dir}/${output_prefix}${test_name_clean}${output_suffix}") + endif() + + # ...and add to script + add_command(add_test + "${prefix}${test}${suffix}" + ${TEST_EXECUTOR} + "${TEST_EXECUTABLE}" + "${test_name}" + ${extra_args} + "${reporter_arg}" + "${output_dir_arg}" + ) + add_command(set_tests_properties + "${prefix}${test}${suffix}" + PROPERTIES + WORKING_DIRECTORY "${TEST_WORKING_DIR}" + ${properties} + ) + list(APPEND tests "${prefix}${test}${suffix}") +endforeach() + +# Create a list of all discovered tests, which users may use to e.g. set +# properties on the tests +add_command(set ${TEST_LIST} ${tests}) + +# Write CTest script +file(WRITE "${CTEST_FILE}" "${script}") diff --git a/tests/catch2/LICENSE.txt b/tests/catch2/LICENSE.txt new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/tests/catch2/LICENSE.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/tests/catch2/catch.hpp b/tests/catch2/catch.hpp index 5feb2a4b..0384171a 100644 --- a/tests/catch2/catch.hpp +++ b/tests/catch2/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.9.2 - * Generated: 2019-08-08 13:35:12.279703 + * Catch v2.13.4 + * Generated: 2020-12-29 14:48:00.116107 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,8 +14,8 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 9 -#define CATCH_VERSION_PATCH 2 +#define CATCH_VERSION_MINOR 13 +#define CATCH_VERSION_PATCH 4 #ifdef __clang__ # pragma clang system_header @@ -132,36 +132,51 @@ namespace Catch { #endif -#if defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + #endif -#ifdef __clang__ +#if defined(__clang__) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) && !defined(__CUDACC__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ @@ -186,6 +201,7 @@ namespace Catch { // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE #endif //////////////////////////////////////////////////////////////////////////////// @@ -219,11 +235,10 @@ namespace Catch { //////////////////////////////////////////////////////////////////////////////// // Visual C++ -#ifdef _MSC_VER +#if defined(_MSC_VER) -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) // Universal Windows platform does not support SEH // Or console colours (or console at all...) @@ -236,9 +251,12 @@ namespace Catch { // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif +# if !defined(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ + #endif // _MSC_VER #if defined(_REENTRANT) || defined(_MSC_VER) @@ -286,49 +304,46 @@ namespace Catch { #define CATCH_CONFIG_COLOUR_NONE #endif -//////////////////////////////////////////////////////////////////////////////// -// Check if string_view is available and usable -// The check is split apart to work around v140 (VS2015) preprocessor issue... -#if defined(__has_include) -#if __has_include() && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW -#endif +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif -//////////////////////////////////////////////////////////////////////////////// -// Check if optional is available and usable +// Various stdlib support checks that require __has_include #if defined(__has_include) -# if __has_include() && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL -# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif -//////////////////////////////////////////////////////////////////////////////// -// Check if byte is available and usable -#if defined(__has_include) -# if __has_include() && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_BYTE -# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -//////////////////////////////////////////////////////////////////////////////// -// Check if variant is available and usable -#if defined(__has_include) -# if __has_include() && defined(CATCH_CPP17_OR_GREATER) -# if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 -# include -# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) -# define CATCH_CONFIG_NO_CPP17_VARIANT -# else -# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT -# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) -# else -# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT -# endif // defined(__clang__) && (__clang_major__ < 8) -# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # include + # if __cpp_lib_byte > 0 + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER @@ -353,10 +368,6 @@ namespace Catch { # define CATCH_CONFIG_CPP17_OPTIONAL #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) # define CATCH_CONFIG_CPP17_STRING_VIEW #endif @@ -389,21 +400,49 @@ namespace Catch { # define CATCH_CONFIG_USE_ASYNC #endif +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) @@ -468,7 +507,7 @@ namespace Catch { SourceLineInfo( SourceLineInfo&& ) noexcept = default; SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - bool empty() const noexcept; + bool empty() const noexcept { return file[0] == '\0'; } bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; @@ -509,9 +548,10 @@ namespace Catch { } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h @@ -551,53 +591,30 @@ namespace Catch { #include #include #include +#include namespace Catch { /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. + /// it may not be null terminated. class StringRef { public: using size_type = std::size_t; + using const_iterator = const char*; private: - friend struct StringRefTestAccess; - - char const* m_start; - size_type m_size; - - char* m_data = nullptr; - - void takeOwnership(); - static constexpr char const* const s_empty = ""; - public: // construction/ assignment - StringRef() noexcept - : StringRef( s_empty, 0 ) - {} + char const* m_start = s_empty; + size_type m_size = 0; - StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } + public: // construction + constexpr StringRef() noexcept = default; StringRef( char const* rawChars ) noexcept; - StringRef( char const* rawChars, size_type size ) noexcept + constexpr StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} @@ -607,101 +624,64 @@ namespace Catch { m_size( stdString.size() ) {} - ~StringRef() noexcept { - delete[] m_data; + explicit operator std::string() const { + return std::string(m_start, m_size); } - auto operator = ( StringRef const &other ) noexcept -> StringRef& { - delete[] m_data; - m_data = nullptr; - m_start = other.m_start; - m_size = other.m_size; - return *this; - } - - operator std::string() const; - - void swap( StringRef& other ) noexcept; - public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } - auto operator[] ( size_type index ) const noexcept -> char; + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } public: // named queries - auto empty() const noexcept -> bool { + constexpr auto empty() const noexcept -> bool { return m_size == 0; } - auto size() const noexcept -> size_type { + constexpr auto size() const noexcept -> size_type { return m_size; } - auto numberOfCharacters() const noexcept -> size_type; + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception auto c_str() const -> char const*; public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; - // Returns the current start pointer. - // Note that the pointer can change when if the StringRef is a substring - auto currentData() const noexcept -> char const*; + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } }; - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } - } // namespace Catch -inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { return Catch::StringRef( rawChars, size ); } // end catch_stringref.h -// start catch_type_traits.hpp - - -#include - -namespace Catch{ - -#ifdef CATCH_CPP17_OR_GREATER - template - inline constexpr auto is_unique = std::true_type{}; - - template - inline constexpr auto is_unique = std::bool_constant< - (!std::is_same_v && ...) && is_unique - >{}; -#else - -template -struct is_unique : std::true_type{}; - -template -struct is_unique : std::integral_constant -::value - && is_unique::value - && is_unique::value ->{}; - -#endif -} - -// end catch_type_traits.hpp // start catch_preprocessor.hpp @@ -786,7 +766,7 @@ struct is_unique : std::integral_constant #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) @@ -798,35 +778,49 @@ struct is_unique : std::integral_constant template struct TypeList {};\ template\ constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ \ - template class L1, typename...E1, template class L2, typename...E2> \ - constexpr auto append(L1, L2) noexcept -> L1 { return {}; }\ + template \ + struct append { using type = T; };\ template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - constexpr auto append(L1, L2, Rest...) noexcept -> decltype(append(L1{}, Rest{}...)) { return {}; }\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ template< template class L1, typename...E1, typename...Rest>\ - constexpr auto append(L1, TypeList, Rest...) noexcept -> L1 { return {}; }\ + struct append, TypeList, Rest...> { using type = L1; };\ \ template< template class Container, template class List, typename...elems>\ - constexpr auto rewrap(List) noexcept -> TypeList> { return {}; }\ + struct rewrap, List> { using type = TypeList>; };\ template< template class Container, template class List, class...Elems, typename...Elements>\ - constexpr auto rewrap(List,Elements...) noexcept -> decltype(append(TypeList>{}, rewrap(Elements{}...))) { return {}; }\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ \ template