zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 8da7b0075eeb8f3aef698db8f46e5fc1f14d4bd6
parent 24f490d2c05cf8e9c85061c7da5fc90c08581ddb
Author: friedolino78 <34608315+friedolino78@users.noreply.github.com>
Date:   Thu, 26 Aug 2021 00:20:37 +0200

add latch mode (#132)

* add latch mode

* fix KitTest (sustain bit)

Co-authored-by: Friedolino <mkirchn@freenet.de>
Diffstat:
Msrc/Containers/NotePool.cpp | 29++++++++++++++++++++++++-----
Msrc/Containers/NotePool.h | 5+++++
Msrc/Misc/Part.cpp | 25+++++++++++++++++++++----
Msrc/Misc/Part.h | 1+
Msrc/Tests/KitTest.cpp | 2+-
5 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/src/Containers/NotePool.cpp b/src/Containers/NotePool.cpp @@ -16,8 +16,8 @@ #include <cassert> #include <iostream> -#define SUSTAIN_BIT 0x04 -#define NOTE_MASK 0x03 +#define SUSTAIN_BIT 0x08 +#define NOTE_MASK 0x07 namespace zyn { @@ -25,7 +25,8 @@ enum NoteStatus { KEY_OFF = 0x00, KEY_PLAYING = 0x01, KEY_RELEASED_AND_SUSTAINED = 0x02, - KEY_RELEASED = 0x03 + KEY_RELEASED = 0x03, + KEY_LATCHED = 0x04 }; @@ -41,6 +42,11 @@ bool NotePool::NoteDescriptor::playing(void) const return (status&NOTE_MASK) == KEY_PLAYING; } +bool NotePool::NoteDescriptor::latched(void) const +{ + return (status&NOTE_MASK) == KEY_LATCHED; +} + bool NotePool::NoteDescriptor::sustained(void) const { return (status&NOTE_MASK) == KEY_RELEASED_AND_SUSTAINED; @@ -259,7 +265,7 @@ int NotePool::getRunningNotes(void) const int running_count = 0; for(auto &desc:activeDesc()) { - if(desc.playing() == false && desc.sustained() == false) + if(desc.playing() == false && desc.sustained() == false && desc.latched() == false) continue; if(running[desc.note] != false) continue; @@ -304,7 +310,7 @@ void NotePool::enforceKeyLimit(int limit) void NotePool::releasePlayingNotes(void) { for(auto &d:activeDesc()) { - if(d.playing() || d.sustained()) { + if(d.playing() || d.sustained() || d.latched()) { d.setStatus(KEY_RELEASED); for(auto s:activeNotes(d)) s.note->releasekey(); @@ -319,6 +325,19 @@ void NotePool::release(NoteDescriptor &d) s.note->releasekey(); } +void NotePool::latch(NoteDescriptor &d) +{ + d.setStatus(KEY_LATCHED); +} + +void NotePool::releaseLatched() +{ + for(auto &desc:activeDesc()) + if(desc.latched()) + for(auto s:activeNotes(desc)) + s.note->releasekey(); +} + void NotePool::killAllNotes(void) { for(auto &d:activeDesc()) diff --git a/src/Containers/NotePool.h b/src/Containers/NotePool.h @@ -44,6 +44,7 @@ class NotePool bool off(void) const; bool sustained(void) const; bool released(void) const; + bool latched(void) const; //status transitions void setStatus(uint8_t s); @@ -125,6 +126,8 @@ class NotePool void applyLegato(note_t note, const LegatoParams &par); void makeUnsustainable(note_t note); + + void releaseLatched(); bool full(void) const; bool synthFull(int sdesc_count) const; @@ -137,6 +140,8 @@ class NotePool void releasePlayingNotes(void); void releaseNote(note_t note); void release(NoteDescriptor &d); + void latch(NoteDescriptor &d); + void killAllNotes(void); void killNote(note_t note); diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -116,13 +116,15 @@ static const Ports partPorts = { {"captureMax:", rDoc("Capture maximum valid note"), NULL, [](const char *, RtData &r) {Part *p = (Part*)r.obj; p->Pmaxkey = p->lastnote;}}, - {"polyType::c:i", rProp(parameter) rOptions(Polyphonic, Monophonic, Legato) + {"polyType::c:i", rProp(parameter) rOptions(Polyphonic, Monophonic, Legato, Latch) rDoc("Synthesis polyphony type\n" "Polyphonic - Each note is played independently\n" "Monophonic - A single note is played at a time with" " envelopes resetting between notes\n" "Legato - A single note is played at a time without" " envelopes resetting between notes\n" + "Latch - Notes are released when a new one is hit " + " after key release\n" ), NULL, [](const char *msg, RtData &d) { @@ -143,12 +145,19 @@ static const Ports partPorts = { if(i == 0) { p->Ppolymode = 1; p->Plegatomode = 0; + p->Platchmode = 0; } else if(i==1) { p->Ppolymode = 0; p->Plegatomode = 0; - } else { + p->Platchmode = 0; + } else if(i==2) { p->Ppolymode = 0; p->Plegatomode = 1; + p->Platchmode = 0; + } else { + p->Ppolymode = 1; + p->Plegatomode = 0; + p->Platchmode = 1; } d.broadcast(d.loc, "i", get_polytype()); } @@ -550,6 +559,10 @@ bool Part::NoteOnInternal(note_t note, if(Ppolymode) notePool.makeUnsustainable(note); + + // in latch mode release latched notes before creating the new one + if(Platchmode) + notePool.releaseLatched(); //Create New Notes for(uint8_t i = 0; i < NUM_KIT_ITEMS; ++i) { @@ -603,7 +616,10 @@ void Part::NoteOff(note_t note) //release the key for(auto &desc:notePool.activeDesc()) { if(desc.note != note || !desc.playing()) continue; - if(!ctl.sustain.sustain) { //the sustain pedal is not pushed + // if latch is on we ignore noteoff, but set the state to lateched + if(Platchmode) { + notePool.latch(desc); + } else if(!ctl.sustain.sustain) { //the sustain pedal is not pushed if((isMonoMode() || isLegatoMode()) && !monomemEmpty()) MonoMemRenote();//Play most recent still active note else @@ -612,8 +628,9 @@ void Part::NoteOff(note_t note) //release the key else { //the sustain pedal is pushed if(desc.canSustain()) desc.doSustain(); - else + else { notePool.release(desc); + } } } } diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -147,6 +147,7 @@ class Part bool Ppolymode; //Part mode - 0=monophonic , 1=polyphonic bool Plegatomode; // 0=normal, 1=legato + bool Platchmode; // 0=normal, 1=latch unsigned char Pkeylimit; //how many keys are allowed to be played same time (0=off), the older will be released char *Pname; //name of the instrument diff --git a/src/Tests/KitTest.cpp b/src/Tests/KitTest.cpp @@ -30,7 +30,7 @@ using namespace zyn; SYNTH_T *synth; int dummy=0; -#define SUSTAIN_BIT 0x04 +#define SUSTAIN_BIT 0x08 enum PrivateNoteStatus { KEY_OFF = 0x00, KEY_PLAYING = 0x01,