From bf8b3fd11166e717708587ce0bbca7cc305d4907 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 11 Aug 2020 17:06:09 +0200 Subject: [PATCH] Support multi-level volumes --- src/sfizz/Region.cpp | 32 +++++++++++++++++++++++++++++++- src/sfizz/Region.h | 7 +++++++ tests/RegionT.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index c8aee196..4487354b 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -539,6 +539,27 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("rt_decay"): setValueFromOpcode(opcode, rtDecay, Default::rtDecayRange); break; + case hash("global_amplitude"): + if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + globalAmplitude = normalizePercents(*value); + break; + case hash("master_amplitude"): + if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + masterAmplitude = normalizePercents(*value); + break; + case hash("group_amplitude"): + if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + groupAmplitude = normalizePercents(*value); + break; + case hash("global_volume"): + setValueFromOpcode(opcode, globalVolume, Default::volumeRange); + break; + case hash("master_volume"): + setValueFromOpcode(opcode, masterVolume, Default::volumeRange); + break; + case hash("group_volume"): + setValueFromOpcode(opcode, groupVolume, Default::volumeRange); + break; // Performance parameters: filters case hash("cutoff&"): // also cutoff @@ -1165,6 +1186,9 @@ float sfz::Region::getBaseVolumedB(int noteNumber) const noexcept { fast_real_distribution volumeDistribution { -ampRandom, ampRandom }; auto baseVolumedB = volume + volumeDistribution(Random::randomGenerator); + baseVolumedB += globalVolume; + baseVolumedB += masterVolume; + baseVolumedB += groupVolume; if (trigger == SfzTrigger::release || trigger == SfzTrigger::release_key) baseVolumedB -= rtDecay * midiState.getNoteDuration(noteNumber); return baseVolumedB; @@ -1172,7 +1196,13 @@ float sfz::Region::getBaseVolumedB(int noteNumber) const noexcept float sfz::Region::getBaseGain() const noexcept { - return amplitude; + float baseGain = amplitude; + + baseGain *= globalAmplitude; + baseGain *= masterAmplitude; + baseGain *= groupAmplitude; + + return baseGain; } float sfz::Region::getPhase() const noexcept diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 72c29ad9..9376d236 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -345,6 +345,13 @@ struct Region { CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN float rtDecay { Default::rtDecay }; // rt_decay + float globalAmplitude { 1.0 }; // global_amplitude + float masterAmplitude { 1.0 }; // master_amplitude + float groupAmplitude { 1.0 }; // group_amplitude + float globalVolume { 0.0 }; // global_volume + float masterVolume { 0.0 }; // master_volume + float groupVolume { 0.0 }; // group_volume + // Filters and EQs std::vector equalizers; std::vector filters; diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index 481e8628..051a4fe5 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -882,6 +882,46 @@ TEST_CASE("[Region] Parsing opcodes") 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.0_a); + } + } + SECTION("pitch_keycenter") { REQUIRE(region.pitchKeycenter == 60);