This commit is contained in:
Paul Ferrand 2020-11-08 23:59:28 +01:00 committed by Jean Pierre Cimalando
parent 31103d11a2
commit 171a5e5083
14 changed files with 4390 additions and 1946 deletions

View file

@ -144,9 +144,9 @@ public:
#ifndef NDEBUG #ifndef NDEBUG
~BufferPool() ~BufferPool()
{ {
DBG("Max buffers used: " << maxBuffersUsed); // DBG("Max buffers used: " << maxBuffersUsed);
DBG("Max index buffers used: " << maxIndexBuffersUsed); // DBG("Max index buffers used: " << maxIndexBuffersUsed);
DBG("Max stereo buffers used: " << maxStereoBuffersUsed); // DBG("Max stereo buffers used: " << maxStereoBuffersUsed);
} }
#endif #endif

View file

@ -9,6 +9,7 @@
#include "SfzHelpers.h" #include "SfzHelpers.h"
#include <vector> #include <vector>
#include <absl/algorithm/container.h> #include <absl/algorithm/container.h>
#include <absl/types/optional.h>
namespace sfz { 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<ValueType> get(int index) const noexcept
{
auto it = absl::c_lower_bound(container, index, CCDataComparator<ValueType> {});
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 * @brief Get the value at index or emplace a new one if not present
* *

View file

@ -207,8 +207,8 @@ namespace Default
constexpr Range<int> pitchVeltrackRange { -12000, 12000 }; constexpr Range<int> pitchVeltrackRange { -12000, 12000 };
constexpr int transpose { 0 }; constexpr int transpose { 0 };
constexpr Range<int> transposeRange { -127, 127 }; constexpr Range<int> transposeRange { -127, 127 };
constexpr int tune { 0 }; constexpr float tune { 0 };
constexpr Range<int> tuneRange { -12000, 12000 }; // ±100 in SFZv1, more in ARIA constexpr Range<float> tuneRange { -12000, 12000 }; // ±100 in SFZv1, more in ARIA
constexpr Range<float> tuneCCRange { -12000, 12000 }; constexpr Range<float> tuneCCRange { -12000, 12000 };
constexpr Range<int> bendBoundRange { -12000, 12000 }; constexpr Range<int> bendBoundRange { -12000, 12000 };
constexpr Range<int> bendStepRange { 1, 1200 }; constexpr Range<int> bendStepRange { 1, 1200 };

View file

@ -27,8 +27,6 @@ public:
private: private:
template <char Tag> template <char Tag>
sfizz_arg_t make_arg(OscDecayedType<Tag> value); sfizz_arg_t make_arg(OscDecayedType<Tag> value);
private:
void* data_ = nullptr; void* data_ = nullptr;
sfizz_receive_t* receive_ = nullptr; sfizz_receive_t* receive_ = nullptr;
}; };

View file

@ -56,7 +56,7 @@ inline void Client::receive(int delay, const char* path, OscDecayedType<Sig>...
typedef struct Nothing {} type; \ typedef struct Nothing {} type; \
typedef type decayed_type; \ typedef type decayed_type; \
static inline sfizz_arg_t make_arg(decayed_type v) { \ 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; \
} \ } \
} }

View file

@ -1936,3 +1936,31 @@ bool sfz::Region::disabled() const noexcept
{ {
return (sampleEnd == 0); return (sampleEnd == 0);
} }
absl::optional<float> 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::ModKey::Parameters> 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 {};
}

View file

@ -303,6 +303,24 @@ struct Region {
*/ */
bool disabled() const noexcept; bool disabled() const noexcept;
/**
* @brief Extract the source depth modifier for a given cc and id.
*
* @param cc
* @param id
* @return absl::optional<float>
*/
absl::optional<float> 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<ModKey::Parameters> ccModParameters(int cc, ModId id) const noexcept;
const NumericId<Region> id; const NumericId<Region> id;
// Sound source: sample playback // Sound source: sample playback
@ -412,7 +430,7 @@ struct Region {
float pitchRandom { Default::pitchRandom }; // pitch_random float pitchRandom { Default::pitchRandom }; // pitch_random
int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack
int transpose { Default::transpose }; // transpose int transpose { Default::transpose }; // transpose
int tune { Default::tune }; // tune float tune { Default::tune }; // tune
int bendUp { Default::bendUp }; int bendUp { Default::bendUp };
int bendDown { Default::bendDown }; int bendDown { Default::bendDown };
int bendStep { Default::bendStep }; int bendStep { Default::bendStep };

View file

@ -676,7 +676,10 @@ void Synth::Impl::finalizeSfzLoad()
++currentRegionIndex; ++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); regions_.resize(currentRegionCount);
// collect all CCs used in regions, with matrix not yet connected // collect all CCs used in regions, with matrix not yet connected

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,8 @@
project(sfizz) project(sfizz)
set(SFIZZ_TEST_SOURCES set(SFIZZ_TEST_SOURCES
RegionT.cpp DirectRegionT.cpp
RegionValuesT.cpp
TestHelpers.h TestHelpers.h
TestHelpers.cpp TestHelpers.cpp
ParsingT.cpp ParsingT.cpp

112
tests/DirectRegionT.cpp Normal file
View file

@ -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 <stdexcept>
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<uint8_t, float>(6, 0.4f));
region.parseOpcode({ "amp_velcurve_127", "-1.0" });
REQUIRE(region.velocityPoints.back() == std::pair<uint8_t, float>(127, 0.0f));
region.parseOpcode({ "amp_velcurve_008", "0.3" });
REQUIRE(region.velocityPoints.back() == std::pair<uint8_t, float>(8, 0.3f));
region.parseOpcode({ "amp_velcurve_064", "0.9" });
REQUIRE(region.velocityPoints.back() == std::pair<uint8_t, float>(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<std::pair<int, float>> 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<std::pair<int, float>> 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<std::pair<int, float>> expected = {
{ 63, 0.5f }
};
REQUIRE( region.delayedReleases == expected );
}
}

File diff suppressed because it is too large Load diff

View file

@ -6,17 +6,20 @@
#include "sfizz/Defaults.h" #include "sfizz/Defaults.h"
#include "sfizz/Region.h" #include "sfizz/Region.h"
#include "sfizz/MidiState.h"
#include "sfizz/SfzHelpers.h" #include "sfizz/SfzHelpers.h"
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
#include <chrono> #include <chrono>
#include <thread> #include <thread>
using namespace Catch::literals; using namespace Catch::literals;
using namespace sfz::literals; using namespace sfz::literals;
using namespace sfz;
constexpr int numRandomTests { 64 }; constexpr int numRandomTests { 64 };
TEST_CASE("[Region] Crossfade in on key") TEST_CASE("[Region] Crossfade in on key")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfin_lokey", "1" }); region.parseOpcode({ "xfin_lokey", "1" });
region.parseOpcode({ "xfin_hikey", "3" }); region.parseOpcode({ "xfin_hikey", "3" });
@ -27,8 +30,8 @@ TEST_CASE("[Region] Crossfade in on key")
TEST_CASE("[Region] Crossfade in on key - 2") TEST_CASE("[Region] Crossfade in on key - 2")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfin_lokey", "1" }); region.parseOpcode({ "xfin_lokey", "1" });
region.parseOpcode({ "xfin_hikey", "5" }); 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") TEST_CASE("[Region] Crossfade in on key - gain")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfin_lokey", "1" }); region.parseOpcode({ "xfin_lokey", "1" });
region.parseOpcode({ "xfin_hikey", "5" }); region.parseOpcode({ "xfin_hikey", "5" });
@ -57,8 +60,8 @@ TEST_CASE("[Region] Crossfade in on key - gain")
TEST_CASE("[Region] Crossfade out on key") TEST_CASE("[Region] Crossfade out on key")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfout_lokey", "51" }); region.parseOpcode({ "xfout_lokey", "51" });
region.parseOpcode({ "xfout_hikey", "55" }); region.parseOpcode({ "xfout_hikey", "55" });
@ -73,8 +76,8 @@ TEST_CASE("[Region] Crossfade out on key")
TEST_CASE("[Region] Crossfade out on key - gain") TEST_CASE("[Region] Crossfade out on key - gain")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfout_lokey", "51" }); region.parseOpcode({ "xfout_lokey", "51" });
region.parseOpcode({ "xfout_hikey", "55" }); region.parseOpcode({ "xfout_hikey", "55" });
@ -90,8 +93,8 @@ TEST_CASE("[Region] Crossfade out on key - gain")
TEST_CASE("[Region] Crossfade in on velocity") TEST_CASE("[Region] Crossfade in on velocity")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfin_lovel", "20" }); region.parseOpcode({ "xfin_lovel", "20" });
region.parseOpcode({ "xfin_hivel", "24" }); region.parseOpcode({ "xfin_hivel", "24" });
@ -107,8 +110,8 @@ TEST_CASE("[Region] Crossfade in on velocity")
TEST_CASE("[Region] Crossfade in on vel - gain") TEST_CASE("[Region] Crossfade in on vel - gain")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfin_lovel", "20" }); region.parseOpcode({ "xfin_lovel", "20" });
region.parseOpcode({ "xfin_hivel", "24" }); region.parseOpcode({ "xfin_hivel", "24" });
@ -125,8 +128,8 @@ TEST_CASE("[Region] Crossfade in on vel - gain")
TEST_CASE("[Region] Crossfade out on vel") TEST_CASE("[Region] Crossfade out on vel")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfout_lovel", "51" }); region.parseOpcode({ "xfout_lovel", "51" });
region.parseOpcode({ "xfout_hivel", "55" }); region.parseOpcode({ "xfout_hivel", "55" });
@ -142,8 +145,8 @@ TEST_CASE("[Region] Crossfade out on vel")
TEST_CASE("[Region] Crossfade out on vel - gain") TEST_CASE("[Region] Crossfade out on vel - gain")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfout_lovel", "51" }); region.parseOpcode({ "xfout_lovel", "51" });
region.parseOpcode({ "xfout_hivel", "55" }); region.parseOpcode({ "xfout_hivel", "55" });
@ -160,8 +163,8 @@ TEST_CASE("[Region] Crossfade out on vel - gain")
TEST_CASE("[Region] Crossfade in on CC") TEST_CASE("[Region] Crossfade in on CC")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfin_locc24", "20" }); region.parseOpcode({ "xfin_locc24", "20" });
region.parseOpcode({ "xfin_hicc24", "24" }); region.parseOpcode({ "xfin_hicc24", "24" });
@ -184,8 +187,8 @@ TEST_CASE("[Region] Crossfade in on CC")
TEST_CASE("[Region] Crossfade in on CC - gain") TEST_CASE("[Region] Crossfade in on CC - gain")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfin_locc24", "20" }); region.parseOpcode({ "xfin_locc24", "20" });
region.parseOpcode({ "xfin_hicc24", "24" }); region.parseOpcode({ "xfin_hicc24", "24" });
@ -208,8 +211,8 @@ TEST_CASE("[Region] Crossfade in on CC - gain")
} }
TEST_CASE("[Region] Crossfade out on CC") TEST_CASE("[Region] Crossfade out on CC")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfout_locc24", "20" }); region.parseOpcode({ "xfout_locc24", "20" });
region.parseOpcode({ "xfout_hicc24", "24" }); region.parseOpcode({ "xfout_hicc24", "24" });
@ -232,8 +235,8 @@ TEST_CASE("[Region] Crossfade out on CC")
TEST_CASE("[Region] Crossfade out on CC - gain") TEST_CASE("[Region] Crossfade out on CC - gain")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "xfout_locc24", "20" }); region.parseOpcode({ "xfout_locc24", "20" });
region.parseOpcode({ "xfout_hicc24", "24" }); 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") TEST_CASE("[Region] Velocity bug for extreme values - veltrack at 0")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "amp_veltrack", "0" }); region.parseOpcode({ "amp_veltrack", "0" });
REQUIRE(region.getNoteGain(64, 127_norm) == 1.0_a); 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") TEST_CASE("[Region] Velocity bug for extreme values - positive veltrack")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "amp_veltrack", "100" }); region.parseOpcode({ "amp_veltrack", "100" });
REQUIRE(region.getNoteGain(64, 127_norm) == 1.0_a); 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") TEST_CASE("[Region] Velocity bug for extreme values - negative veltrack")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "amp_veltrack", "-100" }); region.parseOpcode({ "amp_veltrack", "-100" });
REQUIRE(region.getNoteGain(64, 127_norm) == Approx(0.0).margin(0.0001)); 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") TEST_CASE("[Region] rt_decay")
{ {
sfz::MidiState midiState; MidiState midiState;
midiState.setSampleRate(1000); midiState.setSampleRate(1000);
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "trigger", "release" }); region.parseOpcode({ "trigger", "release" });
region.parseOpcode({ "rt_decay", "10" }); region.parseOpcode({ "rt_decay", "10" });
midiState.noteOnEvent(0, 64, 64_norm); midiState.noteOnEvent(0, 64, 64_norm);
midiState.advanceTime(100); 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" }); region.parseOpcode({ "rt_decay", "20" });
midiState.noteOnEvent(0, 64, 64_norm); midiState.noteOnEvent(0, 64, 64_norm);
midiState.advanceTime(100); 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" }); region.parseOpcode({ "trigger", "attack" });
midiState.noteOnEvent(0, 64, 64_norm); midiState.noteOnEvent(0, 64, 64_norm);
midiState.advanceTime(100); 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") TEST_CASE("[Region] Base delay")
{ {
sfz::MidiState midiState; MidiState midiState;
sfz::Region region { 0, midiState }; Region region { 0, midiState };
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "delay", "10" }); region.parseOpcode({ "delay", "10" });
REQUIRE( region.getDelay() == 10.0f ); REQUIRE( region.getDelay() == 10.0f );
@ -322,3 +325,36 @@ TEST_CASE("[Region] Base delay")
REQUIRE( (delay >= 10.0 && delay <= 20.0) ); 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));
}

3033
tests/RegionValuesT.cpp Normal file

File diff suppressed because it is too large Load diff