Changed the legato logic

The midistate now counts the active notes instead of it
being per-region
This commit is contained in:
Paul Ferrand 2019-12-30 00:10:20 +01:00
parent 2dbc870f9a
commit 0d0cf64405
6 changed files with 40 additions and 10 deletions

View file

@ -14,7 +14,21 @@ void sfz::MidiState::noteOnEvent(int noteNumber, uint8_t velocity) noexcept
if (noteNumber >= 0 && noteNumber < 128) {
lastNoteVelocities[noteNumber] = velocity;
noteOnTimes[noteNumber] = std::chrono::steady_clock::now();
activeNotes++;
}
}
void sfz::MidiState::noteOffEvent(int noteNumber, uint8_t velocity [[maybe_unused]]) noexcept
{
ASSERT(noteNumber >= 0 && noteNumber <= 127);
ASSERT(velocity >= 0 && velocity <= 127);
if (noteNumber >= 0 && noteNumber < 128) {
activeNotes--;
ASSERT(activeNotes >= 0);
}
}
float sfz::MidiState::getNoteDuration(int noteNumber) const
@ -78,6 +92,7 @@ void sfz::MidiState::reset() noexcept
ccValue = 0;
pitchBend = 0;
activeNotes = 0;
}
void sfz::MidiState::resetAllControllers() noexcept

View file

@ -23,6 +23,16 @@ public:
*/
void noteOnEvent(int noteNumber, uint8_t velocity) noexcept;
/**
* @brief Update the state after a note off event
*
* @param noteNumber
* @param velocity
*/
void noteOffEvent(int noteNumber, uint8_t velocity) noexcept;
int getActiveNotes() const noexcept { return activeNotes; }
/**
* @brief Register a note off and get the note duration
*
@ -91,6 +101,7 @@ private:
template<class T>
using MidiNoteArray = std::array<T, 128>;
using NoteOnTime = std::chrono::steady_clock::time_point;
int activeNotes { 0 };
/**
* @brief Stores the note on times.
*

View file

@ -523,9 +523,6 @@ bool sfz::Region::registerNoteOn(int noteNumber, uint8_t velocity, float randVal
const bool keyOk = keyRange.containsWithEnd(noteNumber);
if (keyOk) {
// Update the number of notes playing for the region
activeNotesInRange++;
// Sequence activation
sequenceCounter += 1;
if ((sequenceCounter % sequenceLength) == sequencePosition - 1)
@ -552,9 +549,9 @@ bool sfz::Region::registerNoteOn(int noteNumber, uint8_t velocity, float randVal
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 && activeNotesInRange == 0);
const bool firstLegatoNote = (trigger == SfzTrigger::first && midiState.getActiveNotes() == 1);
const bool attackTrigger = (trigger == SfzTrigger::attack);
const bool notFirstLegatoNote = (trigger == SfzTrigger::legato && activeNotesInRange > 0);
const bool notFirstLegatoNote = (trigger == SfzTrigger::legato && midiState.getActiveNotes() > 1);
return keyOk && velOk && randOk && (attackTrigger || firstLegatoNote || notFirstLegatoNote);
}
@ -571,10 +568,6 @@ bool sfz::Region::registerNoteOff(int noteNumber, uint8_t velocity [[maybe_unuse
const bool keyOk = keyRange.containsWithEnd(noteNumber);
// Update the number of notes playing for the region
if (keyOk)
activeNotesInRange--;
if (!isSwitchedOn())
return false;

View file

@ -319,7 +319,6 @@ private:
bool triggerOnCC { false };
absl::string_view defaultPath { "" };
int activeNotesInRange { -1 };
int sequenceCounter { 0 };
std::uniform_real_distribution<float> volumeDistribution { -sfz::Default::ampRandom, sfz::Default::ampRandom };

View file

@ -417,6 +417,8 @@ void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity [[maybe_unu
ASSERT(noteNumber < 128);
ASSERT(noteNumber >= 0);
midiState.noteOffEvent(noteNumber, velocity);
AtomicGuard callbackGuard { inCallback };
if (!canEnterCallback)
return;

View file

@ -152,10 +152,15 @@ TEST_CASE("Legato triggers", "Region triggers")
region.parseOpcode({ "lokey", "40" });
region.parseOpcode({ "hikey", "50" });
region.parseOpcode({ "trigger", "first" });
midiState.noteOnEvent(40, 64);
REQUIRE(region.registerNoteOn(40, 64, 0.5f));
midiState.noteOnEvent(41, 64);
REQUIRE(!region.registerNoteOn(41, 64, 0.5f));
midiState.noteOffEvent(40, 0);
region.registerNoteOff(40, 0, 0.5f);
midiState.noteOffEvent(41, 0);
region.registerNoteOff(41, 0, 0.5f);
midiState.noteOnEvent(42, 64);
REQUIRE(region.registerNoteOn(42, 64, 0.5f));
}
@ -164,10 +169,15 @@ TEST_CASE("Legato triggers", "Region triggers")
region.parseOpcode({ "lokey", "40" });
region.parseOpcode({ "hikey", "50" });
region.parseOpcode({ "trigger", "legato" });
midiState.noteOnEvent(40, 64);
REQUIRE(!region.registerNoteOn(40, 64, 0.5f));
midiState.noteOnEvent(41, 64);
REQUIRE(region.registerNoteOn(41, 64, 0.5f));
midiState.noteOffEvent(40, 64);
region.registerNoteOff(40, 0, 0.5f);
midiState.noteOffEvent(41, 64);
region.registerNoteOff(41, 0, 0.5f);
midiState.noteOnEvent(42, 64);
REQUIRE(!region.registerNoteOn(42, 64, 0.5f));
}
}