Changed the legato logic
The midistate now counts the active notes instead of it being per-region
This commit is contained in:
parent
2dbc870f9a
commit
0d0cf64405
6 changed files with 40 additions and 10 deletions
|
|
@ -14,7 +14,21 @@ void sfz::MidiState::noteOnEvent(int noteNumber, uint8_t velocity) noexcept
|
||||||
if (noteNumber >= 0 && noteNumber < 128) {
|
if (noteNumber >= 0 && noteNumber < 128) {
|
||||||
lastNoteVelocities[noteNumber] = velocity;
|
lastNoteVelocities[noteNumber] = velocity;
|
||||||
noteOnTimes[noteNumber] = std::chrono::steady_clock::now();
|
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
|
float sfz::MidiState::getNoteDuration(int noteNumber) const
|
||||||
|
|
@ -78,6 +92,7 @@ void sfz::MidiState::reset() noexcept
|
||||||
ccValue = 0;
|
ccValue = 0;
|
||||||
|
|
||||||
pitchBend = 0;
|
pitchBend = 0;
|
||||||
|
activeNotes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfz::MidiState::resetAllControllers() noexcept
|
void sfz::MidiState::resetAllControllers() noexcept
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,16 @@ public:
|
||||||
*/
|
*/
|
||||||
void noteOnEvent(int noteNumber, uint8_t velocity) noexcept;
|
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
|
* @brief Register a note off and get the note duration
|
||||||
*
|
*
|
||||||
|
|
@ -91,6 +101,7 @@ private:
|
||||||
template<class T>
|
template<class T>
|
||||||
using MidiNoteArray = std::array<T, 128>;
|
using MidiNoteArray = std::array<T, 128>;
|
||||||
using NoteOnTime = std::chrono::steady_clock::time_point;
|
using NoteOnTime = std::chrono::steady_clock::time_point;
|
||||||
|
int activeNotes { 0 };
|
||||||
/**
|
/**
|
||||||
* @brief Stores the note on times.
|
* @brief Stores the note on times.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -523,9 +523,6 @@ bool sfz::Region::registerNoteOn(int noteNumber, uint8_t velocity, float randVal
|
||||||
|
|
||||||
const bool keyOk = keyRange.containsWithEnd(noteNumber);
|
const bool keyOk = keyRange.containsWithEnd(noteNumber);
|
||||||
if (keyOk) {
|
if (keyOk) {
|
||||||
// Update the number of notes playing for the region
|
|
||||||
activeNotesInRange++;
|
|
||||||
|
|
||||||
// Sequence activation
|
// Sequence activation
|
||||||
sequenceCounter += 1;
|
sequenceCounter += 1;
|
||||||
if ((sequenceCounter % sequenceLength) == sequencePosition - 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 velOk = velocityRange.containsWithEnd(velocity);
|
||||||
const bool randOk = randRange.contains(randValue) || (randValue == 1.0f && randRange.getEnd() == 1.0f);
|
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 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);
|
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);
|
const bool keyOk = keyRange.containsWithEnd(noteNumber);
|
||||||
|
|
||||||
// Update the number of notes playing for the region
|
|
||||||
if (keyOk)
|
|
||||||
activeNotesInRange--;
|
|
||||||
|
|
||||||
if (!isSwitchedOn())
|
if (!isSwitchedOn())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,6 @@ private:
|
||||||
bool triggerOnCC { false };
|
bool triggerOnCC { false };
|
||||||
absl::string_view defaultPath { "" };
|
absl::string_view defaultPath { "" };
|
||||||
|
|
||||||
int activeNotesInRange { -1 };
|
|
||||||
int sequenceCounter { 0 };
|
int sequenceCounter { 0 };
|
||||||
|
|
||||||
std::uniform_real_distribution<float> volumeDistribution { -sfz::Default::ampRandom, sfz::Default::ampRandom };
|
std::uniform_real_distribution<float> volumeDistribution { -sfz::Default::ampRandom, sfz::Default::ampRandom };
|
||||||
|
|
|
||||||
|
|
@ -417,6 +417,8 @@ void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity [[maybe_unu
|
||||||
ASSERT(noteNumber < 128);
|
ASSERT(noteNumber < 128);
|
||||||
ASSERT(noteNumber >= 0);
|
ASSERT(noteNumber >= 0);
|
||||||
|
|
||||||
|
midiState.noteOffEvent(noteNumber, velocity);
|
||||||
|
|
||||||
AtomicGuard callbackGuard { inCallback };
|
AtomicGuard callbackGuard { inCallback };
|
||||||
if (!canEnterCallback)
|
if (!canEnterCallback)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -152,10 +152,15 @@ TEST_CASE("Legato triggers", "Region triggers")
|
||||||
region.parseOpcode({ "lokey", "40" });
|
region.parseOpcode({ "lokey", "40" });
|
||||||
region.parseOpcode({ "hikey", "50" });
|
region.parseOpcode({ "hikey", "50" });
|
||||||
region.parseOpcode({ "trigger", "first" });
|
region.parseOpcode({ "trigger", "first" });
|
||||||
|
midiState.noteOnEvent(40, 64);
|
||||||
REQUIRE(region.registerNoteOn(40, 64, 0.5f));
|
REQUIRE(region.registerNoteOn(40, 64, 0.5f));
|
||||||
|
midiState.noteOnEvent(41, 64);
|
||||||
REQUIRE(!region.registerNoteOn(41, 64, 0.5f));
|
REQUIRE(!region.registerNoteOn(41, 64, 0.5f));
|
||||||
|
midiState.noteOffEvent(40, 0);
|
||||||
region.registerNoteOff(40, 0, 0.5f);
|
region.registerNoteOff(40, 0, 0.5f);
|
||||||
|
midiState.noteOffEvent(41, 0);
|
||||||
region.registerNoteOff(41, 0, 0.5f);
|
region.registerNoteOff(41, 0, 0.5f);
|
||||||
|
midiState.noteOnEvent(42, 64);
|
||||||
REQUIRE(region.registerNoteOn(42, 64, 0.5f));
|
REQUIRE(region.registerNoteOn(42, 64, 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,10 +169,15 @@ TEST_CASE("Legato triggers", "Region triggers")
|
||||||
region.parseOpcode({ "lokey", "40" });
|
region.parseOpcode({ "lokey", "40" });
|
||||||
region.parseOpcode({ "hikey", "50" });
|
region.parseOpcode({ "hikey", "50" });
|
||||||
region.parseOpcode({ "trigger", "legato" });
|
region.parseOpcode({ "trigger", "legato" });
|
||||||
|
midiState.noteOnEvent(40, 64);
|
||||||
REQUIRE(!region.registerNoteOn(40, 64, 0.5f));
|
REQUIRE(!region.registerNoteOn(40, 64, 0.5f));
|
||||||
|
midiState.noteOnEvent(41, 64);
|
||||||
REQUIRE(region.registerNoteOn(41, 64, 0.5f));
|
REQUIRE(region.registerNoteOn(41, 64, 0.5f));
|
||||||
|
midiState.noteOffEvent(40, 64);
|
||||||
region.registerNoteOff(40, 0, 0.5f);
|
region.registerNoteOff(40, 0, 0.5f);
|
||||||
|
midiState.noteOffEvent(41, 64);
|
||||||
region.registerNoteOff(41, 0, 0.5f);
|
region.registerNoteOff(41, 0, 0.5f);
|
||||||
|
midiState.noteOnEvent(42, 64);
|
||||||
REQUIRE(!region.registerNoteOn(42, 64, 0.5f));
|
REQUIRE(!region.registerNoteOn(42, 64, 0.5f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue