Skip to content

Commit

Permalink
Add lotimer/hitimer tests
Browse files Browse the repository at this point in the history
  • Loading branch information
paulfd committed Dec 10, 2023
1 parent 621b4c2 commit 9b38c0b
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/sfizz/SynthMessaging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,15 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
}
} break;

MATCH("/region&/use_timer_range", "") {
GET_REGION_OR_BREAK(indices[0])
if (region.useTimerRange) {
client.receive<'T'>(delay, path, {});
} else {
client.receive<'F'>(delay, path, {});
}
} break;

MATCH("/region&/count", "") {
GET_REGION_OR_BREAK(indices[0])
if (region.sampleCount)
Expand Down
124 changes: 124 additions & 0 deletions tests/RegionTriggersT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,127 @@ TEST_CASE("[Triggers] Offed voices with CC triggers do not activate release trig
synth.hdcc(10, 64, 10_norm);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "*saw" });
}

TEST_CASE("[Triggers] lotimer")
{
Synth synth;
synth.setSampleRate(48000);
synth.setSamplesPerBlock(480);
sfz::AudioBuffer<float> buffer { 2, 480 };
synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"(
<region> key=40 lotimer=0.1 sample=kick.wav loop_mode=one_shot
)");

// Advance time, t = 0.2s
for (int i = 0; i < 20; ++i)
synth.renderBlock(buffer);

synth.noteOn(0, 40, 100);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav" });

// Advance time by 0.02s and send a note off
synth.renderBlock(buffer);
synth.noteOff(0, 40, 100);
synth.renderBlock(buffer);

// t = 0.22s, not allowed to retrigger
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav" });
synth.noteOn(0, 40, 100);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav" });

// Advance time by 0.08s and send a note off
synth.renderBlock(buffer);
synth.noteOff(0, 40, 100);
for (int i = 0; i < 7; ++i)
synth.renderBlock(buffer);

// t = 0.3s, retriggering OK
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav" });
synth.noteOn(0, 40, 100);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav", "kick.wav" });
}

TEST_CASE("[Triggers] lotimer on CC")
{
Synth synth;
synth.setSampleRate(48000);
synth.setSamplesPerBlock(480);
sfz::AudioBuffer<float> buffer { 2, 480 };
synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"(
<region> start_locc4=100 start_hicc4=100 lotimer=0.1 sample=kick.wav loop_mode=one_shot
)");

// Advance time, t = 0.2s
for (int i = 0; i < 20; ++i)
synth.renderBlock(buffer);

REQUIRE(playingSamples(synth) == std::vector<std::string> { });
synth.hdcc(0, 4, 100_norm);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav" });

// Advance time by 0.02s and reset CC
synth.renderBlock(buffer);
synth.hdcc(0, 4, 0);
synth.renderBlock(buffer);

// t = 0.22s, not allowed to retrigger
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav" });
synth.hdcc(0, 4, 100_norm);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav" });

// Advance time by 0.08s and reset CC
synth.renderBlock(buffer);
synth.hdcc(0, 4, 0);
for (int i = 0; i < 7; ++i)
synth.renderBlock(buffer);

// t = 0.3s, retriggering OK
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav" });
synth.hdcc(0, 4, 100_norm);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "kick.wav", "kick.wav" });
}

TEST_CASE("[Triggers] hitimer (with group)")
{
Synth synth;
synth.setSampleRate(48000);
synth.setSamplesPerBlock(480);
sfz::AudioBuffer<float> buffer { 2, 480 };
synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"(
<region> group=1 key=40 sample=snare.wav loop_mode=one_shot
<region> group=1 key=41 hitimer=0.1 sample=kick.wav loop_mode=one_shot
)");

// Advance time to 0.1s
for (int i = 0; i < 10; ++i)
synth.renderBlock(buffer);

// Not triggering before snare
synth.noteOn(0, 41, 100);
REQUIRE(playingSamples(synth) == std::vector<std::string> { });
synth.noteOn(0, 40, 100);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "snare.wav" });

// OK to trigger now
REQUIRE(playingSamples(synth) == std::vector<std::string> { "snare.wav" });
synth.noteOn(0, 41, 100);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "snare.wav", "kick.wav" });

// Advance time
for (int i = 0; i < 5; ++i)
synth.renderBlock(buffer);

// t = 0.15s, still OK to trigger now
REQUIRE(playingSamples(synth) == std::vector<std::string> { "snare.wav", "kick.wav" });
synth.noteOn(0, 41, 100);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "snare.wav", "kick.wav", "kick.wav" });

// Advance time (it has to be 0.1s because playing the kick resets the timer)
for (int i = 0; i < 10; ++i)
synth.renderBlock(buffer);

// t = 0.25s, not triggering a new kick
REQUIRE(playingSamples(synth) == std::vector<std::string> { "snare.wav", "kick.wav", "kick.wav" });
synth.noteOn(0, 41, 100);
REQUIRE(playingSamples(synth) == std::vector<std::string> { "snare.wav", "kick.wav", "kick.wav" });
}
33 changes: 33 additions & 0 deletions tests/RegionValuesT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,39 @@ TEST_CASE("[Values] Rand range")
REQUIRE(messageList == expected);
}

TEST_CASE("[Values] Timer range")
{
Synth synth;
std::vector<std::string> messageList;
Client client(&messageList);
client.setReceiveCallback(&simpleMessageReceiver);
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav lotimer=0.2 hitimer=0.4
<region> sample=kick.wav lotimer=-0.1 hitimer=0.4
<region> sample=kick.wav lotimer=0.2 hitimer=-0.1
)");
synth.dispatchMessage(client, 0, "/region0/timer_range", "", nullptr);
synth.dispatchMessage(client, 0, "/region0/use_timer_range", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/timer_range", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/use_timer_range", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/timer_range", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/use_timer_range", "", nullptr);
synth.dispatchMessage(client, 0, "/region3/timer_range", "", nullptr);
synth.dispatchMessage(client, 0, "/region3/use_timer_range", "", nullptr);
std::vector<std::string> expected {
"/region0/timer_range,ff : { 0, 3.40282e+38 }",
"/region0/use_timer_range,F : { }",
"/region1/timer_range,ff : { 0.2, 0.4 }",
"/region1/use_timer_range,T : { }",
"/region2/timer_range,ff : { 0, 0.4 }",
"/region2/use_timer_range,T : { }",
"/region3/timer_range,ff : { 0.2, 3.40282e+38 }",
"/region3/use_timer_range,T : { }",
};
REQUIRE(messageList == expected);
}

TEST_CASE("[Values] Sequence length")
{
Synth synth;
Expand Down

0 comments on commit 9b38c0b

Please sign in to comment.