Missing the delayed release logic for sostenuto
This commit is contained in:
parent
0a065a392c
commit
ed09e30fcf
3 changed files with 98 additions and 30 deletions
|
|
@ -1155,7 +1155,6 @@ void Synth::Impl::startDelayedReleaseVoices(Region* region, int delay, SisterVoi
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& note: region->delayedReleases) {
|
for (auto& note: region->delayedReleases) {
|
||||||
// FIXME: we really need to have some form of common method to find and start voices...
|
|
||||||
const TriggerEvent noteOffEvent { TriggerEventType::NoteOff, note.first, note.second };
|
const TriggerEvent noteOffEvent { TriggerEventType::NoteOff, note.first, note.second };
|
||||||
startVoice(region, delay, noteOffEvent, ring);
|
startVoice(region, delay, noteOffEvent, ring);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,8 @@ struct Voice::Impl
|
||||||
|
|
||||||
State state_ { State::idle };
|
State state_ { State::idle };
|
||||||
bool noteIsOff_ { false };
|
bool noteIsOff_ { false };
|
||||||
|
enum class SustainState { Up, Sustaining };
|
||||||
|
SustainState sustainState_ { SustainState::Up };
|
||||||
enum class SostenutoState { Up, Sustaining, PreviouslyDown };
|
enum class SostenutoState { Up, Sustaining, PreviouslyDown };
|
||||||
SostenutoState sostenutoState_ { SostenutoState::Up };
|
SostenutoState sostenutoState_ { SostenutoState::Up };
|
||||||
|
|
||||||
|
|
@ -461,6 +463,13 @@ bool Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe
|
||||||
impl.resources_.modMatrix.initVoice(impl.id_, region->getId(), impl.initialDelay_);
|
impl.resources_.modMatrix.initVoice(impl.id_, region->getId(), impl.initialDelay_);
|
||||||
impl.saveModulationTargets(region);
|
impl.saveModulationTargets(region);
|
||||||
|
|
||||||
|
if (region->checkSustain) {
|
||||||
|
const bool sustainPressed =
|
||||||
|
impl.resources_.midiState.getCCValue(region->sustainCC) >= region->sustainThreshold;
|
||||||
|
impl.sustainState_ =
|
||||||
|
sustainPressed ? Impl::SustainState::Sustaining : Impl::SustainState::Up;
|
||||||
|
}
|
||||||
|
|
||||||
if (region->checkSostenuto) {
|
if (region->checkSostenuto) {
|
||||||
const bool sostenutoPressed =
|
const bool sostenutoPressed =
|
||||||
impl.resources_.midiState.getCCValue(region->sostenutoCC) >= region->sostenutoThreshold;
|
impl.resources_.midiState.getCCValue(region->sostenutoCC) >= region->sostenutoThreshold;
|
||||||
|
|
@ -552,12 +561,13 @@ void Voice::registerNoteOff(int delay, int noteNumber, float velocity) noexcept
|
||||||
if (impl.region_->loopMode == LoopMode::one_shot)
|
if (impl.region_->loopMode == LoopMode::one_shot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!impl.region_->checkSustain
|
const bool sustainPedalReleaseCondition = !impl.region_->checkSustain
|
||||||
|| impl.resources_.midiState.getCCValue(impl.region_->sustainCC) < impl.region_->sustainThreshold)
|
|| impl.sustainState_ != Impl::SustainState::Sustaining;
|
||||||
release(delay);
|
|
||||||
|
|
||||||
if (!impl.region_->checkSostenuto
|
const bool sostenutoPedalReleaseCondition = !impl.region_->checkSostenuto
|
||||||
|| impl.sostenutoState_ != Impl::SostenutoState::Sustaining)
|
|| impl.sostenutoState_ != Impl::SostenutoState::Sustaining;
|
||||||
|
|
||||||
|
if (sustainPedalReleaseCondition && sostenutoPedalReleaseCondition)
|
||||||
release(delay);
|
release(delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -572,24 +582,30 @@ void Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
|
||||||
if (impl.state_ != State::playing)
|
if (impl.state_ != State::playing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (impl.region_->checkSustain
|
if (impl.region_->checkSustain && (ccNumber == impl.region_->sostenutoCC)) {
|
||||||
&& impl.noteIsOff_
|
|
||||||
&& ccNumber == impl.region_->sustainCC
|
|
||||||
&& ccValue < impl.region_->sustainThreshold)
|
|
||||||
release(delay);
|
|
||||||
|
|
||||||
if (impl.region_->checkSostenuto
|
|
||||||
&& ccNumber == impl.region_->sostenutoCC) {
|
|
||||||
if (ccValue < impl.region_->sostenutoThreshold) {
|
if (ccValue < impl.region_->sostenutoThreshold) {
|
||||||
impl.sostenutoState_ = Impl::SostenutoState::Up;
|
impl.sostenutoState_ = Impl::SostenutoState::Up;
|
||||||
} else {
|
} else if (impl.sostenutoState_ == Impl::SostenutoState::Up) {
|
||||||
if (impl.sostenutoState_ == Impl::SostenutoState::Up)
|
|
||||||
impl.sostenutoState_ = Impl::SostenutoState::Sustaining;
|
impl.sostenutoState_ = Impl::SostenutoState::Sustaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (impl.sostenutoState_ != Impl::SostenutoState::Sustaining && impl.noteIsOff_)
|
|
||||||
release(delay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (impl.region_->checkSostenuto && (ccNumber == impl.region_->sustainCC)) {
|
||||||
|
if (ccValue < impl.region_->sustainThreshold) {
|
||||||
|
impl.sustainState_ = Impl::SustainState::Up;
|
||||||
|
} else {
|
||||||
|
impl.sustainState_ = Impl::SustainState::Sustaining;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool sustainPedalReleaseCondition = !impl.region_->checkSustain
|
||||||
|
|| (impl.noteIsOff_ && (impl.sustainState_ != Impl::SustainState::Sustaining));
|
||||||
|
|
||||||
|
const bool sostenutoPedalReleaseCondition = !impl.region_->checkSostenuto
|
||||||
|
|| (impl.noteIsOff_ && (impl.sostenutoState_ != Impl::SostenutoState::Sustaining));
|
||||||
|
|
||||||
|
if (sostenutoPedalReleaseCondition && sustainPedalReleaseCondition)
|
||||||
|
release(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::registerPitchWheel(int delay, float pitch) noexcept
|
void Voice::registerPitchWheel(int delay, float pitch) noexcept
|
||||||
|
|
|
||||||
|
|
@ -840,10 +840,10 @@ TEST_CASE("[Synth] Release (Different sostenuto CC)")
|
||||||
<region> key=62 sample=*sine trigger=release
|
<region> key=62 sample=*sine trigger=release
|
||||||
)");
|
)");
|
||||||
synth.noteOn(0, 62, 85);
|
synth.noteOn(0, 62, 85);
|
||||||
synth.cc(0, 54, 127);
|
synth.cc(1, 54, 127);
|
||||||
synth.noteOff(0, 62, 85);
|
synth.noteOff(2, 62, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices() == 1 );
|
REQUIRE( synth.getNumActiveVoices() == 1 );
|
||||||
synth.cc(0, 54, 0);
|
synth.cc(3, 54, 0);
|
||||||
REQUIRE( synth.getNumActiveVoices() == 2 );
|
REQUIRE( synth.getNumActiveVoices() == 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -881,6 +881,59 @@ TEST_CASE("[Synth] Sustain threshold")
|
||||||
REQUIRE( synth.getNumActiveVoices() == 5 );
|
REQUIRE( synth.getNumActiveVoices() == 5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[Synth] Sustain")
|
||||||
|
{
|
||||||
|
sfz::Synth synth;
|
||||||
|
synth.loadSfzString(fs::current_path() / "tests/TestFiles/sostenuto.sfz", R"(
|
||||||
|
<region> sample=*sine
|
||||||
|
)");
|
||||||
|
|
||||||
|
SECTION("1 note")
|
||||||
|
{
|
||||||
|
synth.noteOn(0, 62, 85);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 1 );
|
||||||
|
synth.cc(1, 64, 1);
|
||||||
|
synth.noteOff(2, 62, 85);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 1 );
|
||||||
|
synth.cc(3, 64, 0);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("2 notes")
|
||||||
|
{
|
||||||
|
synth.noteOn(0, 62, 85);
|
||||||
|
synth.noteOn(0, 64, 85);
|
||||||
|
synth.cc(1, 64, 1);
|
||||||
|
synth.noteOff(2, 62, 85);
|
||||||
|
synth.noteOff(2, 64, 85);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 2 );
|
||||||
|
synth.cc(3, 64, 0);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("1 note after the pedal is depressed")
|
||||||
|
{
|
||||||
|
synth.cc(0, 64, 1);
|
||||||
|
synth.noteOn(1, 62, 85);
|
||||||
|
synth.noteOff(2, 62, 85);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 1 );
|
||||||
|
synth.cc(3, 64, 0);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("2 notes, 1 after the pedal is depressed")
|
||||||
|
{
|
||||||
|
synth.noteOn(0, 62, 85);
|
||||||
|
synth.cc(1, 64, 1);
|
||||||
|
synth.noteOn(2, 64, 85);
|
||||||
|
synth.noteOff(3, 62, 85);
|
||||||
|
synth.noteOff(3, 64, 85);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 2 );
|
||||||
|
synth.cc(4, 64, 0);
|
||||||
|
REQUIRE( numPlayingVoices(synth) == 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("[Synth] Sostenuto")
|
TEST_CASE("[Synth] Sostenuto")
|
||||||
{
|
{
|
||||||
sfz::Synth synth;
|
sfz::Synth synth;
|
||||||
|
|
@ -893,9 +946,9 @@ TEST_CASE("[Synth] Sostenuto")
|
||||||
synth.noteOn(0, 62, 85);
|
synth.noteOn(0, 62, 85);
|
||||||
synth.cc(1, 66, 1);
|
synth.cc(1, 66, 1);
|
||||||
synth.noteOff(2, 62, 85);
|
synth.noteOff(2, 62, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices() == 1 );
|
REQUIRE( numPlayingVoices(synth) == 1 );
|
||||||
synth.cc(3, 66, 0);
|
synth.cc(3, 66, 0);
|
||||||
REQUIRE( synth.getNumActiveVoices() == 0 );
|
REQUIRE( numPlayingVoices(synth) == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("2 notes")
|
SECTION("2 notes")
|
||||||
|
|
@ -905,9 +958,9 @@ TEST_CASE("[Synth] Sostenuto")
|
||||||
synth.cc(1, 66, 1);
|
synth.cc(1, 66, 1);
|
||||||
synth.noteOff(2, 62, 85);
|
synth.noteOff(2, 62, 85);
|
||||||
synth.noteOff(2, 64, 85);
|
synth.noteOff(2, 64, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices() == 2 );
|
REQUIRE( numPlayingVoices(synth) == 2 );
|
||||||
synth.cc(3, 66, 0);
|
synth.cc(3, 66, 0);
|
||||||
REQUIRE( synth.getNumActiveVoices() == 0 );
|
REQUIRE( numPlayingVoices(synth) == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("1 note but after the pedal is depressed")
|
SECTION("1 note but after the pedal is depressed")
|
||||||
|
|
@ -915,7 +968,7 @@ TEST_CASE("[Synth] Sostenuto")
|
||||||
synth.cc(0, 66, 1);
|
synth.cc(0, 66, 1);
|
||||||
synth.noteOn(1, 62, 85);
|
synth.noteOn(1, 62, 85);
|
||||||
synth.noteOff(2, 62, 85);
|
synth.noteOff(2, 62, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices() == 0 );
|
REQUIRE( numPlayingVoices(synth) == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("2 notes, 1 after the pedal is depressed")
|
SECTION("2 notes, 1 after the pedal is depressed")
|
||||||
|
|
@ -925,7 +978,7 @@ TEST_CASE("[Synth] Sostenuto")
|
||||||
synth.noteOn(2, 64, 85);
|
synth.noteOn(2, 64, 85);
|
||||||
synth.noteOff(3, 62, 85);
|
synth.noteOff(3, 62, 85);
|
||||||
synth.noteOff(3, 64, 85);
|
synth.noteOff(3, 64, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices() == 1 );
|
REQUIRE( numPlayingVoices(synth) == 1 );
|
||||||
REQUIRE( getActiveVoices(synth)[0]->getTriggerEvent().number == 62 );
|
REQUIRE( getActiveVoices(synth)[0]->getTriggerEvent().number == 62 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue