commit 934f9657083cc7fc67c3ffad0bb913389e542f0e
parent d8121bf92692e4eaa51104eb03b6bb38baa7fa20
Author: fundamental <mark.d.mccurry@gmail.com>
Date: Fri, 3 Jul 2015 16:26:40 -0400
Rewrite Part's Note Pool Implementation
Makes Part::NoteOn massively more readable
- Currently ignores key limits
- Doesn't have too many notes case tested
Diffstat:
14 files changed, 1008 insertions(+), 724 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -347,6 +347,7 @@ add_subdirectory(Nio)
add_library(zynaddsubfx_core STATIC
../tlsf/tlsf.c
+ Containers/NotePool.cpp
${zynaddsubfx_dsp_SRCS}
${zynaddsubfx_effect_SRCS}
${zynaddsubfx_misc_SRCS}
diff --git a/src/Containers/NotePool.cpp b/src/Containers/NotePool.cpp
@@ -0,0 +1,283 @@
+#include "NotePool.h"
+//XXX eliminate dependence on Part.h
+#include "../Misc/Part.h"
+#include "../Misc/Allocator.h"
+#include "../Synth/SynthNote.h"
+#include <cstring>
+#include <cassert>
+
+NotePool::NotePool(void)
+{
+ memset(ndesc, 0, sizeof(ndesc));
+ memset(sdesc, 0, sizeof(ndesc));
+}
+NotePool::activeNotesIter NotePool::activeNotes(NoteDescriptor &n)
+{
+ const int off_d1 = &n-ndesc;
+ int off_d2 = 0;
+ assert(off_d1 <= POLYPHONY);
+ for(int i=0; i<off_d1; ++i)
+ off_d2 += ndesc[i].size;
+ return NotePool::activeNotesIter{sdesc+off_d2,sdesc+off_d2+n.size};
+}
+
+bool NotePool::NoteDescriptor::operator==(NoteDescriptor nd)
+{
+ return age == nd.age && note == nd.note && sendto == nd.sendto && size == nd.size && status == nd.status;
+}
+
+//return either the first unused descriptor or the last valid descriptor which
+//matches note/sendto
+static int getMergeableDescriptor(uint8_t note, uint8_t sendto, bool legato,
+ NotePool::NoteDescriptor *ndesc)
+{
+ int desc_id = 0;
+ for(int i=0; i<POLYPHONY; ++i, ++desc_id)
+ if(ndesc[desc_id].status == Part::KEY_OFF)
+ break;
+
+ //Out of free descriptors
+ if(ndesc[desc_id].status != Part::KEY_OFF)
+ return -1;
+
+ if(desc_id != 0) {
+ auto &nd = ndesc[desc_id-1];
+ if(nd.age == 0 && nd.note == note && nd.sendto == sendto
+ && nd.status == Part::KEY_PLAYING && nd.legatoMirror == legato)
+ return desc_id-1;
+ }
+ return desc_id;
+}
+
+NotePool::activeDescIter NotePool::activeDesc(void)
+{
+ cleanup();
+ return activeDescIter{*this};
+}
+
+NotePool::constActiveDescIter NotePool::activeDesc(void) const
+{
+ const_cast<NotePool*>(this)->cleanup();
+ return constActiveDescIter{*this};
+}
+
+void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato)
+{
+ //Get first free note descriptor
+ int desc_id = getMergeableDescriptor(note, sendto, legato, ndesc);
+ assert(desc_id != -1);
+
+ ndesc[desc_id].note = note;
+ ndesc[desc_id].sendto = sendto;
+ ndesc[desc_id].size += 1;
+ ndesc[desc_id].status = Part::KEY_PLAYING;
+ ndesc[desc_id].legatoMirror = legato;
+
+ //Get first free synth descriptor
+ int sdesc_id = 0;
+ while(sdesc[sdesc_id].note)
+ sdesc_id++;
+ sdesc[sdesc_id] = desc;
+};
+
+void NotePool::upgradeToLegato(void)
+{
+ for(auto &d:activeDesc())
+ if(d.status == Part::KEY_PLAYING)
+ for(auto &s:activeNotes(d))
+ insertLegatoNote(d.note, d.sendto, s);
+}
+
+void NotePool::insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc)
+{
+ assert(desc.note);
+ desc.note = desc.note->cloneLegato();
+ insertNote(note, sendto, desc, true);
+};
+
+//There should only be one pair of notes which are still playing
+void NotePool::applyLegato(LegatoParams &par)
+{
+ for(auto &desc:activeDesc()) {
+ desc.note = par.midinote;
+ for(auto &synth:activeNotes(desc))
+ synth.note->legatonote(par);
+ }
+};
+
+//Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
+bool NotePool::existsRunningNote(void) const
+{
+ printf("runing note # =%d\n", getRunningNotes());
+ return getRunningNotes();
+}
+
+int NotePool::getRunningNotes(void) const
+{
+ bool running[256] = {0};
+ for(auto &desc:activeDesc()) {
+ printf("note!(%d)\n", desc.note);
+ running[desc.note] = true;
+ }
+
+ int running_count = 0;
+ for(int i=0; i<256; ++i)
+ running_count += running[i];
+
+ return running_count;
+}
+int NotePool::enforceKeyLimit(int limit) const
+{
+ //{
+ //int oldestnotepos = -1;
+ //if(notecount > keylimit) //find out the oldest note
+ // for(int i = 0; i < POLYPHONY; ++i) {
+ // int maxtime = 0;
+ // if(((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED)) && (partnote[i].time > maxtime)) {
+ // maxtime = partnote[i].time;
+ // oldestnotepos = i;
+ // }
+ // }
+ //if(oldestnotepos != -1)
+ // ReleaseNotePos(oldestnotepos);
+ //}
+ printf("Unimplemented enforceKeyLimit()\n");
+ return -1;
+}
+
+void NotePool::releasePlayingNotes(void)
+{
+ for(auto &d:activeDesc()) {
+ if(d.status == Part::KEY_PLAYING) {
+ d.status = Part::KEY_RELEASED;
+ for(auto s:activeNotes(d))
+ s.note->releasekey();
+ }
+ }
+}
+
+void NotePool::release(NoteDescriptor &d)
+{
+ d.status = Part::KEY_RELEASED;
+ for(auto s:activeNotes(d))
+ s.note->releasekey();
+}
+
+void NotePool::killAllNotes(void)
+{
+ for(auto &d:activeDesc())
+ kill(d);
+}
+
+void NotePool::killNote(uint8_t note)
+{
+ for(auto &d:activeDesc()) {
+ if(d.note == note)
+ kill(d);
+ }
+}
+
+void NotePool::kill(NoteDescriptor &d)
+{
+ d.status = Part::KEY_OFF;
+ for(auto &s:activeNotes(d))
+ kill(s);
+}
+
+void NotePool::kill(SynthDescriptor &s)
+{
+ printf("Kill synth...\n");
+ s.note->memory.dealloc(s.note);
+ needs_cleaning = true;
+}
+
+const char *getStatus(int status_bits)
+{
+ switch(status_bits)
+ {
+ case 0: return "OFF ";
+ case 1: return "PLAY";
+ case 2: return "SUST";
+ case 3: return "RELA";
+ default: return "INVD";
+ }
+}
+
+void NotePool::cleanup(void)
+{
+ if(!needs_cleaning)
+ return;
+ needs_cleaning = false;
+ int new_length[POLYPHONY] = {0};
+ int cur_length[POLYPHONY] = {0};
+ printf("Cleanup Start\n");
+ dump();
+
+ //Identify the current length of all segments
+ //and the lengths discarding invalid entries
+
+ int last_valid_desc = 0;
+ for(int i=0; i<POLYPHONY; ++i)
+ if(ndesc[i].status != Part::KEY_OFF)
+ last_valid_desc = i;
+
+ //Find the real numbers of allocated notes
+ {
+ int cum_old = 0;
+
+ for(int i=0; i<=last_valid_desc; ++i) {
+ cur_length[i] = ndesc[i].size;
+ for(int j=0; j<ndesc[i].size; ++j)
+ new_length[i] += (bool)sdesc[cum_old++].note;
+ }
+ }
+
+
+ //Move the note descriptors
+ {
+ int cum_new = 0;
+ for(int i=0; i<=last_valid_desc; ++i) {
+ ndesc[i].size = new_length[i];
+ if(new_length[i] != 0)
+ ndesc[cum_new++] = ndesc[i];
+ else
+ ndesc[i].status = Part::KEY_OFF;
+ }
+ memset(ndesc+cum_new, 0, sizeof(*ndesc)*(POLYPHONY-cum_new));
+ }
+
+ //Move the synth descriptors
+ {
+ int total_notes=0;
+ for(int i=0; i<=last_valid_desc; ++i)
+ total_notes+=cur_length[i];
+
+ int cum_new = 0;
+ for(int i=0; i<total_notes; ++i)
+ if(sdesc[i].note)
+ sdesc[cum_new++] = sdesc[i];
+ memset(sdesc+cum_new, 0, sizeof(*sdesc)*(POLYPHONY*EXPECTED_USAGE-cum_new));
+ }
+ printf("Cleanup Done\n");
+ dump();
+}
+
+void NotePool::dump(void)
+{
+ printf("NotePool::dump<\n");
+ const char *format =
+ " Note %d:%d age(%d) note(%d) sendto(%d) status(%s) legato(%d) type(%d) kit(%d) ptr(%p)\n";
+ int note_id=0;
+ int descriptor_id=0;
+ for(auto &d:activeDesc()) {
+ descriptor_id += 1;
+ for(auto &s:activeNotes(d)) {
+ note_id += 1;
+ printf(format,
+ note_id, descriptor_id,
+ d.age, d.note, d.sendto,
+ getStatus(d.status), d.legatoMirror, s.type, s.kit, s.note);
+ }
+ }
+ printf(">NotePool::dump\n");
+}
diff --git a/src/Containers/NotePool.h b/src/Containers/NotePool.h
@@ -0,0 +1,113 @@
+#pragma once
+#include <stdint.h>
+#include <functional>
+#include "../globals.h"
+
+//Expected upper bound of synths given that max polyphony is hit
+#define EXPECTED_USAGE 3
+
+class LegatoParams;
+class NotePool
+{
+ public:
+ typedef uint8_t note_t;
+ //Currently this wastes a ton of bits due ot the legatoMirror flag
+ struct NoteDescriptor {
+ //acceptable overlap after 2 minutes
+ //run time at 48kHz 8 samples per buffer
+ //19 bit minimum
+ uint32_t age;
+ uint8_t note;
+ uint8_t sendto;
+ //max of 16 kit elms and 3 kit items per
+ uint8_t size;
+ uint8_t status;
+ bool legatoMirror;
+ bool operator==(NoteDescriptor);
+ };
+
+ //To be pedantic this wastes 2 or 6 bytes per descriptor
+ //depending on 32bit/64bit alignment rules
+ struct SynthDescriptor {
+ SynthNote *note;
+ uint8_t type;
+ uint8_t kit;
+ };
+
+
+ //Pool of notes
+ NoteDescriptor ndesc[POLYPHONY];
+ SynthDescriptor sdesc[POLYPHONY*EXPECTED_USAGE];
+ bool needs_cleaning;
+
+
+ //Iterators
+ struct activeNotesIter {
+ SynthDescriptor *begin() {return _b;};
+ SynthDescriptor *end() {return _e;};
+ SynthDescriptor *_b;
+ SynthDescriptor *_e;
+ };
+
+ struct activeDescIter {
+ activeDescIter(NotePool &_np):np(_np)
+ {
+ int off=0;
+ for(int i=0; i<POLYPHONY; ++i, ++off)
+ if(np.ndesc[i].status == 0)
+ break;
+ _end = np.ndesc+off;
+ }
+ NoteDescriptor *begin() {return np.ndesc;};
+ NoteDescriptor *end() { return _end; };
+ NoteDescriptor *_end;
+ NotePool &np;
+ };
+
+ struct constActiveDescIter {
+ constActiveDescIter(const NotePool &_np):np(_np)
+ {
+ int off=0;
+ for(int i=0; i<POLYPHONY; ++i, ++off)
+ if(np.ndesc[i].status == 0)
+ break;
+ _end = np.ndesc+off;
+ }
+ const NoteDescriptor *begin() const {return np.ndesc;};
+ const NoteDescriptor *end() const { return _end; };
+ const NoteDescriptor *_end;
+ const NotePool &np;
+ };
+
+ activeNotesIter activeNotes(NoteDescriptor &n);
+
+ activeDescIter activeDesc(void);
+ constActiveDescIter activeDesc(void) const;
+
+ NotePool(void);
+
+ //Operations
+ void insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato=false);
+ void insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc);
+
+ void upgradeToLegato(void);
+ void applyLegato(LegatoParams &par);
+
+ //Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
+ bool existsRunningNote(void) const;
+ int getRunningNotes(void) const;
+ int enforceKeyLimit(int limit) const;
+
+ void releasePlayingNotes(void);
+ void releaseNote(note_t note);
+ void release(NoteDescriptor &d);
+
+ void killAllNotes(void);
+ void killNote(note_t note);
+ void kill(NoteDescriptor &d);
+ void kill(SynthDescriptor &s);
+
+ void cleanup(void);
+
+ void dump(void);
+};
diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp
@@ -186,13 +186,18 @@ const Ports &Part::Kit::ports = kitPorts;
const Ports &Part::ports = partPorts;
Part::Part(Allocator &alloc, const SYNTH_T &synth_, Microtonal *microtonal_, FFTwrapper *fft_)
- :ctl(synth_), memory(alloc), synth(synth_)
+ :
+ Pdrummode(false),
+ Ppolymode(true),
+ Plegatomode(false),
+ partoutl(new float[synth_.buffersize]),
+ partoutr(new float[synth_.buffersize]),
+ ctl(synth_),
+ lastlegatomodevalid(false),
+ microtonal(microtonal_), fft(fft_),
+ memory(alloc),
+ synth(synth_)
{
- microtonal = microtonal_;
- fft = fft_;
- partoutl = new float [synth.buffersize];
- partoutr = new float [synth.buffersize];
-
monomemClear();
for(int n = 0; n < NUM_KIT_ITEMS; ++n) {
@@ -209,6 +214,7 @@ Part::Part(Allocator &alloc, const SYNTH_T &synth_, Microtonal *microtonal_, FFT
partefx[nefx] = new EffectMgr(memory, synth, 1);
Pefxbypass[nefx] = false;
}
+ assert(partefx[0]);
for(int n = 0; n < NUM_PART_EFX + 1; ++n) {
partfxinputl[n] = new float [synth.buffersize];
@@ -218,28 +224,15 @@ Part::Part(Allocator &alloc, const SYNTH_T &synth_, Microtonal *microtonal_, FFT
killallnotes = false;
oldfreq = -1.0f;
-
- for(int i = 0; i < POLYPHONY; ++i) {
- partnote[i].status = KEY_OFF;
- partnote[i].note = -1;
- partnote[i].itemsplaying = 0;
- for(int j = 0; j < NUM_KIT_ITEMS; ++j) {
- partnote[i].kititem[j].adnote = NULL;
- partnote[i].kititem[j].subnote = NULL;
- partnote[i].kititem[j].padnote = NULL;
- }
- partnote[i].time = 0;
- }
cleanup();
Pname = new char[PART_MAX_NAME_LEN];
oldvolumel = oldvolumer = 0.5f;
lastnote = -1;
- lastpos = 0; // lastpos will store previously used NoteOn(...)'s pos.
- lastlegatomodevalid = false; // To store previous legatomodevalid value.
defaults();
+ assert(partefx[0]);
}
void Part::cloneTraits(Part &p) const
@@ -326,8 +319,7 @@ void Part::defaultsinstrument()
*/
void Part::cleanup(bool final_)
{
- for(int k = 0; k < POLYPHONY; ++k)
- KillNotePos(k);
+ notePool.killAllNotes();
for(int i = 0; i < synth.buffersize; ++i) {
partoutl[i] = final_ ? 0.0f : denormalkillbuf[i];
partoutr[i] = final_ ? 0.0f : denormalkillbuf[i];
@@ -380,297 +372,92 @@ void Part::NoteOn(unsigned char note,
unsigned char velocity,
int masterkeyshift)
{
- // Legato and MonoMem used vars:
- int posb = POLYPHONY - 1; // Just a dummy initial value.
- bool legatomodevalid = false; //true when legato mode is determined applicable.
- bool doinglegato = false; // true when we determined we do a legato note.
- bool ismonofirstnote = false; /*(In Mono/Legato) true when we determined
- no other notes are held down or sustained.*/
- int lastnotecopy = lastnote; //Useful after lastnote has been changed.
+ //Verify Basic Mode and sanity
+ const bool isRunningNote = notePool.existsRunningNote();
+ const bool doingLegato = isRunningNote && isLegatoMode() &&
+ lastlegatomodevalid;
if(!Pnoteon || !inRange(note, Pminkey, Pmaxkey))
return;
+ verifyKeyMode();
assert_kit_sanity(kit);
- // MonoMem stuff:
- if(!Ppolymode) { // If Poly is off
- monomemPush(note); // Add note to the list.
- monomem[note].velocity = velocity; // Store this note's velocity.
- monomem[note].mkeyshift = masterkeyshift; /* Store masterkeyshift too*/
- if((partnote[lastpos].status != KEY_PLAYING)
- && (partnote[lastpos].status != KEY_RELEASED_AND_SUSTAINED))
- ismonofirstnote = true; // No other keys are held or sustained.
+ //Preserve Note Stack
+ if(isMonoMode() || isLegatoMode()) {
+ monomemPush(note);
+ monomem[note].velocity = velocity;
+ monomem[note].mkeyshift = masterkeyshift;
+
} else if(!monomemEmpty())
monomemClear();
- lastnote = note;
-
- int pos = -1;
- for(int i = 0; i < POLYPHONY; ++i)
- if(partnote[i].status == KEY_OFF) {
- pos = i;
- break;
- }
-
- if(Plegatomode && !Pdrummode) {
- if(Ppolymode) {
- fprintf(
- stderr,
- "ZynAddSubFX WARNING: Poly and Legato modes are both On, that should not happen ! ... Disabling Legato mode ! - (Part.cpp::NoteOn(..))\n");
- Plegatomode = 0;
- }
- else {
- // Legato mode is on and applicable.
- legatomodevalid = true;
- if(!ismonofirstnote && lastlegatomodevalid) {
- // At least one other key is held or sustained, and the
- // previous note was played while in valid legato mode.
- doinglegato = true; // So we'll do a legato note.
- pos = lastpos; // A legato note uses same pos as previous..
- posb = lastposb; // .. same goes for posb.
- }
- else {
- // Legato mode is valid, but this is only a first note.
- for(int i = 0; i < POLYPHONY; ++i)
- if((partnote[i].status == KEY_PLAYING)
- || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED))
- ReleaseNotePos(i);
-
- // Set posb
- posb = (pos + 1) % POLYPHONY; //We really want it (if the following fails)
- for(int i = 0; i < POLYPHONY; ++i)
- if((partnote[i].status == KEY_OFF) && (pos != i)) {
- posb = i;
- break;
- }
- }
- lastposb = posb; // Keep a trace of used posb
- }
- }
- else // Legato mode is either off or non-applicable.
- if(!Ppolymode) { //if the mode is 'mono' turn off all other notes
- for(int i = 0; i < POLYPHONY; ++i)
- if(partnote[i].status == KEY_PLAYING)
- ReleaseNotePos(i);
- ReleaseSustainedKeys();
- }
- lastlegatomodevalid = legatomodevalid;
-
- if(pos == -1)
- fprintf(stderr,
- "%s",
- "NOTES TOO MANY (> POLYPHONY) - (Part.cpp::NoteOn(..))\n");
- else {
- //start the note
- partnote[pos].status = KEY_PLAYING;
- partnote[pos].note = note;
- if(legatomodevalid) {
- partnote[posb].status = KEY_PLAYING;
- partnote[posb].note = note;
- }
-
- //this computes the velocity sensing of the part
- float vel = VelF(velocity / 127.0f, Pvelsns);
-
- //compute the velocity offset
- vel = limit(vel + (Pveloffs - 64.0f) / 64.0f, 0.0f, 1.0f);
-
- //compute the keyshift
- int partkeyshift = (int)Pkeyshift - 64;
- int keyshift = masterkeyshift + partkeyshift;
-
- //initialise note frequency
- float notebasefreq;
- if(Pdrummode == 0) {
- notebasefreq = microtonal->getnotefreq(note, keyshift);
- if(notebasefreq < 0.0f)
- return;//the key is no mapped
- }
- else
- notebasefreq = 440.0f * powf(2.0f, (note - 69.0f) / 12.0f);
-
- //Portamento
- if(oldfreq < 1.0f)
- oldfreq = notebasefreq;//this is only the first note is played
-
- // For Mono/Legato: Force Portamento Off on first
- // notes. That means it is required that the previous note is
- // still held down or sustained for the Portamento to activate
- // (that's like Legato).
- bool portamento = false;
- if(Ppolymode || !ismonofirstnote)
- // I added a third argument to the
- // ctl.initportamento(...) function to be able
- // to tell it if we're doing a legato note.
- portamento = ctl.initportamento(oldfreq, notebasefreq, doinglegato);
-
- if(portamento)
- ctl.portamento.noteusing = pos;
- oldfreq = notebasefreq;
-
- lastpos = pos; // Keep a trace of used pos.
-
- if(doinglegato) {
- // Do Legato note
- if(Pkitmode == 0) { // "normal mode" legato note
-
- auto note1 = partnote[pos].kititem[0];
- auto note2 = partnote[posb].kititem[0];
- LegatoParams pars = {notebasefreq, vel, portamento, note, true};
- if(kit[0].Padenabled && note1.adnote && note2.adnote) {
- note1.adnote->legatonote(pars);
- note2.adnote->legatonote(pars);
- }
-
- if(kit[0].Psubenabled && note1.subnote && note2.subnote) {
- note1.subnote->legatonote(pars);
- note2.subnote->legatonote(pars);
- }
-
- if(kit[0].Ppadenabled && note1.padnote && note2.padnote) {
- note1.padnote->legatonote(pars);
- note2.padnote->legatonote(pars);
- }
- }
- else { // "kit mode" legato note
- int ci = 0;
- for(int item = 0; item < NUM_KIT_ITEMS; ++item) {
-
- //Make sure the key is valid and not across multiple ranges
- if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey)
- || !inRange((unsigned char)lastnotecopy, kit[item].Pminkey, kit[item].Pmaxkey))
- continue;
-
- auto note1 = partnote[pos].kititem[ci];
- auto note2 = partnote[posb].kititem[ci];
- LegatoParams pars = {notebasefreq, vel, portamento, note, true};
- note1.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX);
- note2.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX);
-
- if(kit[item].Padenabled && kit[item].adpars && note1.adnote && note2.adnote) {
- note1.adnote->legatonote(pars);
- note2.adnote->legatonote(pars);
- }
- if(kit[item].Psubenabled && kit[item].subpars && note1.subnote && note2.subnote) {
- note1.subnote->legatonote(pars);
- note2.subnote->legatonote(pars);
- }
- if(kit[item].Ppadenabled && kit[item].padpars && note1.padnote && note2.padnote) {
- note1.padnote->legatonote(pars);
- note2.padnote->legatonote(pars);
- }
-
- if(kit[item].adpars || kit[item].subpars || kit[item].padpars) {
- ci++;
- if((kit[item].Padenabled || kit[item].Psubenabled || kit[item].Ppadenabled) && (Pkitmode == 2))
- break;
- }
- }
- if(ci == 0) {
- // No legato were performed at all, so pretend nothing happened:
- monomemPop(monomemBack()); // Remove last note from the list.
- lastnote = lastnotecopy; // Set lastnote back to previous value.
- }
- }
- return; // Ok, Legato note done, return.
- }
-
- partnote[pos].itemsplaying = 0;
- if(legatomodevalid)
- partnote[posb].itemsplaying = 0;
-
- if(Pkitmode == 0) { //init the notes for the "normal mode"
- partnote[pos].kititem[0].sendtoparteffect = 0;
- SynthParams pars{memory, ctl, synth, notebasefreq, vel, (bool) portamento, note, false};
-
- if(kit[0].Padenabled)
- partnote[pos].kititem[0].adnote =
- memory.alloc<ADnote>(kit[0].adpars, pars);
- if(kit[0].Psubenabled)
- partnote[pos].kititem[0].subnote =
- memory.alloc<SUBnote>(kit[0].subpars, pars);
- if(kit[0].Ppadenabled)
- partnote[pos].kititem[0].padnote =
- memory.alloc<PADnote>(kit[0].padpars, pars);
-
-
- if(kit[0].Padenabled || kit[0].Psubenabled || kit[0].Ppadenabled)
- partnote[pos].itemsplaying++;
-
- // Spawn another note (but silent) if legatomodevalid==true
- if(legatomodevalid) {
- partnote[posb].kititem[0].sendtoparteffect = 0;
- pars.quiet = true;
-
- if(kit[0].Padenabled)
- partnote[posb].kititem[0].adnote =
- memory.alloc<ADnote>(kit[0].adpars, pars);
- if(kit[0].Psubenabled)
- partnote[posb].kititem[0].subnote =
- memory.alloc<SUBnote>(kit[0].subpars, pars);
- if(kit[0].Ppadenabled)
- partnote[posb].kititem[0].padnote =
- memory.alloc<PADnote>(kit[0].padpars, pars);
-
- if(kit[0].Padenabled || kit[0].Psubenabled || kit[0].Ppadenabled)
- partnote[posb].itemsplaying++;
- }
- }
- else //init the notes for the "kit mode"
- for(int item = 0; item < NUM_KIT_ITEMS; ++item) {
- if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey))
- continue;
+ //Mono/Legato Release old notes
+ if(isMonoMode() || (isLegatoMode() && !doingLegato))
+ notePool.releasePlayingNotes();
- int ci = partnote[pos].itemsplaying; //ci=current item
- auto ¬e1 = partnote[pos].kititem[ci];
+ lastlegatomodevalid = isLegatoMode();
- //if this parameter is 127 for "unprocessed"
- note1.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX);
+ //Compute Note Parameters
+ const float vel = getVelocity(velocity, Pvelsns, Pveloffs);
+ const int partkeyshift = (int)Pkeyshift - 64;
+ const int keyshift = masterkeyshift + partkeyshift;
+ const float notebasefreq = getBaseFreq(note, keyshift);
- SynthParams pars{memory, ctl, synth, notebasefreq, vel, (bool) portamento, note, false};
-
- if(kit[item].adpars && kit[item].Padenabled)
- note1.adnote =
- memory.alloc<ADnote>(kit[item].adpars, pars);
-
- if(kit[item].subpars && kit[item].Psubenabled)
- note1.subnote =
- memory.alloc<SUBnote>(kit[item].subpars, pars);
-
- if(kit[item].padpars && kit[item].Ppadenabled)
- note1.padnote =
- memory.alloc<PADnote>(kit[item].padpars, pars);
-
- // Spawn another note (but silent) if legatomodevalid==true
- if(legatomodevalid) {
- auto ¬e2 = partnote[posb].kititem[ci];
- note2.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX);
+ if(notebasefreq < 0)
+ return;
- pars.quiet = true;
- if(kit[item].adpars && kit[item].Padenabled)
- note2.adnote =
- memory.alloc<ADnote>(kit[item].adpars, pars);
- if(kit[item].subpars && kit[item].Psubenabled)
- note2.subnote =
- memory.alloc<SUBnote>(kit[item].subpars, pars);
- if(kit[item].padpars && kit[item].Ppadenabled)
- note2.padnote =
- memory.alloc<PADnote>(kit[item].padpars, pars);
+ //Portamento
+ lastnote = note;
+ if(oldfreq < 1.0f)
+ oldfreq = notebasefreq;//this is only the first note is played
+
+ // For Mono/Legato: Force Portamento Off on first
+ // notes. That means it is required that the previous note is
+ // still held down or sustained for the Portamento to activate
+ // (that's like Legato).
+ bool portamento = false;
+ if(Ppolymode || isRunningNote)
+ portamento = ctl.initportamento(oldfreq, notebasefreq, doingLegato);
+
+ oldfreq = notebasefreq;
+
+ //Adjust Existing Notes
+ if(doingLegato) {
+ LegatoParams pars = {notebasefreq, vel, portamento, note, true};
+ notePool.applyLegato(pars);
+ return;
+ }
- if(kit[item].adpars || kit[item].subpars || kit[item].padpars)
- partnote[posb].itemsplaying++;
- }
+ //Create New Notes
+ for(uint8_t i = 0; i < NUM_KIT_ITEMS; ++i) {
+ auto &item = kit[i];
+ if(Pkitmode != 0 && !item.validNote(note))
+ continue;
- if(kit[item].adpars || kit[item].subpars) {
- partnote[pos].itemsplaying++;
- if((kit[item].Padenabled || kit[item].Psubenabled || kit[item].Ppadenabled) && (Pkitmode == 2))
- break;
- }
- }
+ SynthParams pars{memory, ctl, synth, notebasefreq, vel,
+ portamento, note, false};
+ const int sendto = Pkitmode ? item.sendto() : 0;
+
+ if(item.Padenabled)
+ notePool.insertNote(note, sendto,
+ {memory.alloc<ADnote>(kit[0].adpars, pars), 0, i});
+ if(item.Psubenabled)
+ notePool.insertNote(note, sendto,
+ {memory.alloc<SUBnote>(kit[0].subpars, pars), 1, i});
+ if(item.Ppadenabled)
+ notePool.insertNote(note, sendto,
+ {memory.alloc<PADnote>(kit[0].padpars, pars), 2, i});
+
+ //Partial Kit Use
+ if(isNonKit() || (isSingleKit() && item.active()))
+ break;
}
- //this only release the keys if there is maximum number of keys allowed
+ if(isLegatoMode())
+ notePool.upgradeToLegato();
+
+ //Enforce the key limit
setkeylimit(Pkeylimit);
}
@@ -683,17 +470,18 @@ void Part::NoteOff(unsigned char note) //release the key
if(!monomemEmpty())
monomemPop(note);
- for(int i = POLYPHONY - 1; i >= 0; i--) //first note in, is first out if there are same note multiple times
- if((partnote[i].status == KEY_PLAYING) && (partnote[i].note == note)) {
- if(!ctl.sustain.sustain) { //the sustain pedal is not pushed
- if(!Ppolymode && !monomemEmpty())
- MonoMemRenote();//Play most recent still active note
- else
- ReleaseNotePos(i);
- }
- else //the sustain pedal is pushed
- partnote[i].status = KEY_RELEASED_AND_SUSTAINED;
+ for(auto &desc:notePool.activeDesc()) {
+ if(desc.note != note)
+ continue;
+ if(!ctl.sustain.sustain) { //the sustain pedal is not pushed
+ if((isMonoMode() || isLegatoMode()) && !monomemEmpty())
+ MonoMemRenote();//Play most recent still active note
+ else
+ notePool.release(desc);
}
+ else //the sustain pedal is pushed
+ desc.status = KEY_RELEASED_AND_SUSTAINED;
+ }
}
void Part::PolyphonicAftertouch(unsigned char note,
@@ -709,36 +497,12 @@ void Part::PolyphonicAftertouch(unsigned char note,
if(!Ppolymode) // if Poly is off
monomem[note].velocity = velocity; // Store this note's velocity.
-
- for(int i = 0; i < POLYPHONY; ++i)
- if((partnote[i].note == note) && (partnote[i].status == KEY_PLAYING)) {
- /* update velocity */
- // compute the velocity offset
- float vel = VelF(velocity / 127.0f, Pvelsns) + (Pveloffs - 64.0f) / 64.0f;
- vel = limit(vel, 0.0f, 1.0f);
-
- if(!Pkitmode) { // "normal mode"
- if(kit[0].Padenabled && partnote[i].kititem[0].adnote)
- partnote[i].kititem[0].adnote->setVelocity(vel);
- if(kit[0].Psubenabled && partnote[i].kititem[0].subnote)
- partnote[i].kititem[0].subnote->setVelocity(vel);
- if(kit[0].Ppadenabled && partnote[i].kititem[0].padnote)
- partnote[i].kititem[0].padnote->setVelocity(vel);
- }
- else // "kit mode"
- for(int item = 0; item < NUM_KIT_ITEMS; ++item) {
- if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey))
- continue;
-
- if(kit[item].Padenabled && partnote[i].kititem[item].adnote)
- partnote[i].kititem[item].adnote->setVelocity(vel);
- if(kit[item].Psubenabled && partnote[i].kititem[item].subnote)
- partnote[i].kititem[item].subnote->setVelocity(vel);
- if(kit[item].Ppadenabled && partnote[i].kititem[item].padnote)
- partnote[i].kititem[item].padnote->setVelocity(vel);
- }
- }
-
+ const float vel = getVelocity(velocity, Pvelsns, Pveloffs);
+ for(auto &d:notePool.activeDesc()) {
+ if(d.note == note && d.status == KEY_PLAYING)
+ for(auto &s:notePool.activeNotes(d))
+ s.note->setVelocity(vel);
+ }
}
/*
@@ -839,13 +603,14 @@ void Part::SetController(unsigned int type, int par)
void Part::ReleaseSustainedKeys()
{
// Let's call MonoMemRenote() on some conditions:
- if(Ppolymode == 0 && !monomemEmpty())
+ if((isMonoMode() || isLegatoMode()) && !monomemEmpty())
if(monomemBack() != lastnote) // Sustain controller manipulation would cause repeated same note respawn without this check.
MonoMemRenote(); // To play most recent still held note.
- for(int i = 0; i < POLYPHONY; ++i)
- if(partnote[i].status == KEY_RELEASED_AND_SUSTAINED)
- ReleaseNotePos(i);
+ for(auto &d:notePool.activeDesc())
+ if(d.status == KEY_RELEASED_AND_SUSTAINED)
+ for(auto &s:notePool.activeNotes(d))
+ s.note->releasekey();
}
/*
@@ -854,10 +619,10 @@ void Part::ReleaseSustainedKeys()
void Part::ReleaseAllKeys()
{
- for(int i = 0; i < POLYPHONY; ++i)
- if((partnote[i].status != KEY_RELEASED)
- && (partnote[i].status != KEY_OFF)) //thanks to Frank Neumann
- ReleaseNotePos(i);
+ for(auto &d:notePool.activeDesc())
+ if(d.status != KEY_RELEASED)
+ for(auto &s:notePool.activeNotes(d))
+ s.note->releasekey();
}
// Call NoteOn(...) with the most recent still held key as new note
@@ -866,50 +631,36 @@ void Part::MonoMemRenote()
{
unsigned char mmrtempnote = monomemBack(); // Last list element.
monomemPop(mmrtempnote); // We remove it, will be added again in NoteOn(...).
- if(Pnoteon == 0)
- ReleaseNotePos(lastpos);
- else
- NoteOn(mmrtempnote, monomem[mmrtempnote].velocity,
- monomem[mmrtempnote].mkeyshift);
+ NoteOn(mmrtempnote, monomem[mmrtempnote].velocity,
+ monomem[mmrtempnote].mkeyshift);
}
-/*
- * Release note at position
- */
-void Part::ReleaseNotePos(int pos)
+float Part::getBaseFreq(int note, int keyshift) const
{
- for(int j = 0; j < NUM_KIT_ITEMS; ++j) {
- if(partnote[pos].kititem[j].adnote)
- partnote[pos].kititem[j].adnote->releasekey();
+ if(Pdrummode)
+ return 440.0f * powf(2.0f, (note - 69.0f) / 12.0f);
+ else
+ return microtonal->getnotefreq(note, keyshift);
+}
- if(partnote[pos].kititem[j].subnote)
- partnote[pos].kititem[j].subnote->releasekey();
+float Part::getVelocity(uint8_t velocity, uint8_t velocity_sense,
+ uint8_t velocity_offset) const
+{
+ //compute sense function
+ const float vel = VelF(velocity / 127.0f, velocity_sense);
- if(partnote[pos].kititem[j].padnote)
- partnote[pos].kititem[j].padnote->releasekey();
- }
- partnote[pos].status = KEY_RELEASED;
+ //compute the velocity offset
+ return limit(vel + (velocity_offset - 64.0f) / 64.0f, 0.0f, 1.0f);
}
-
-/*
- * Kill note at position
- */
-void Part::KillNotePos(int pos)
+void Part::verifyKeyMode(void)
{
- partnote[pos].status = KEY_OFF;
- partnote[pos].note = -1;
- partnote[pos].time = 0;
- partnote[pos].itemsplaying = 0;
-
- for(int j = 0; j < NUM_KIT_ITEMS; ++j) {
- memory.dealloc(partnote[pos].kititem[j].adnote);
- memory.dealloc(partnote[pos].kititem[j].subnote);
- memory.dealloc(partnote[pos].kititem[j].padnote);
- }
- if(pos == ctl.portamento.noteusing) {
- ctl.portamento.noteusing = -1;
- ctl.portamento.used = 0;
+ if(Plegatomode && !Pdrummode && Ppolymode) {
+ fprintf(stderr,
+ "WARNING: Poly & Legato modes are On, that shouldn't happen\n"
+ "Disabling Legato mode...\n"
+ "(Part.cpp::NoteOn(..))\n");
+ Plegatomode = 0;
}
}
@@ -917,32 +668,15 @@ void Part::KillNotePos(int pos)
/*
* Set Part's key limit
*/
-void Part::setkeylimit(unsigned char Pkeylimit)
+void Part::setkeylimit(unsigned char Pkeylimit_)
{
- this->Pkeylimit = Pkeylimit;
+ Pkeylimit = Pkeylimit_;
int keylimit = Pkeylimit;
if(keylimit == 0)
keylimit = POLYPHONY - 5;
- //release old keys if the number of notes>keylimit
- if(Ppolymode != 0) {
- int notecount = 0;
- for(int i = 0; i < POLYPHONY; ++i)
- if((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED))
- notecount++;
-
- int oldestnotepos = -1;
- if(notecount > keylimit) //find out the oldest note
- for(int i = 0; i < POLYPHONY; ++i) {
- int maxtime = 0;
- if(((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED)) && (partnote[i].time > maxtime)) {
- maxtime = partnote[i].time;
- oldestnotepos = i;
- }
- }
- if(oldestnotepos != -1)
- ReleaseNotePos(oldestnotepos);
- }
+ if(notePool.getRunningNotes() > keylimit)
+ notePool.enforceKeyLimit(keylimit);
}
@@ -954,65 +688,35 @@ void Part::AllNotesOff()
killallnotes = true;
}
-void Part::RunNote(unsigned int k)
+/*
+ * Compute Part samples and store them in the partoutl[] and partoutr[]
+ */
+void Part::ComputePartSmps()
{
- unsigned noteplay = 0;
- for(int item = 0; item < partnote[k].itemsplaying; ++item) {
- int sendcurrenttofx = partnote[k].kititem[item].sendtoparteffect;
-
- for(unsigned type = 0; type < 3; ++type) {
- //Select a note
- SynthNote **note = NULL;
- if(type == 0)
- note = &partnote[k].kititem[item].adnote;
- else if(type == 1)
- note = &partnote[k].kititem[item].subnote;
- else if(type == 2)
- note = &partnote[k].kititem[item].padnote;
-
- //Process if it exists
- if(!(*note))
- continue;
- noteplay++;
+ assert(partefx[0]);
+ for(unsigned nefx = 0; nefx < NUM_PART_EFX + 1; ++nefx) {
+ memset(partfxinputl[nefx], 0, synth.bufferbytes);
+ memset(partfxinputr[nefx], 0, synth.bufferbytes);
+ }
+ for(auto &d:notePool.activeDesc()) {
+ d.age++;
+ for(auto &s:notePool.activeNotes(d)) {
float tmpoutr[synth.buffersize];
float tmpoutl[synth.buffersize];
- (*note)->noteout(&tmpoutl[0], &tmpoutr[0]);
+ auto ¬e = *s.note;
+ note.noteout(&tmpoutl[0], &tmpoutr[0]);
- if((*note)->finished())
- memory.dealloc(*note);
for(int i = 0; i < synth.buffersize; ++i) { //add the note to part(mix)
- partfxinputl[sendcurrenttofx][i] += tmpoutl[i];
- partfxinputr[sendcurrenttofx][i] += tmpoutr[i];
+ partfxinputl[d.sendto][i] += tmpoutl[i];
+ partfxinputr[d.sendto][i] += tmpoutr[i];
}
- }
- }
-
- //Kill note if there is no synth on that note
- if(!noteplay)
- KillNotePos(k);
-}
-/*
- * Compute Part samples and store them in the partoutl[] and partoutr[]
- */
-void Part::ComputePartSmps()
-{
- for(unsigned nefx = 0; nefx < NUM_PART_EFX + 1; ++nefx)
- for(int i = 0; i < synth.buffersize; ++i) {
- partfxinputl[nefx][i] = 0.0f;
- partfxinputr[nefx][i] = 0.0f;
+ if(note.finished())
+ notePool.kill(s);
}
-
- for(unsigned k = 0; k < POLYPHONY; ++k) {
- if(partnote[k].status == KEY_OFF)
- continue;
- partnote[k].time++;
- //get the sampledata of the note and kill it if it's finished
- RunNote(k);
}
-
//Apply part's effects and mix them
for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx) {
if(!Pefxbypass[nefx]) {
@@ -1040,8 +744,7 @@ void Part::ComputePartSmps()
partoutl[i] *= tmp;
partoutr[i] *= tmp;
}
- for(int k = 0; k < POLYPHONY; ++k)
- KillNotePos(k);
+ notePool.killAllNotes();
killallnotes = false;
for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx)
partefx[nefx]->cleanup();
@@ -1087,9 +790,7 @@ void Part::setkititemstatus(unsigned kititem, bool Penabled_)
delete kkit.padpars;
kkit.Pname[0] = '\0';
- //Reset notes s.t. stale buffers will not get read
- for(int k = 0; k < POLYPHONY; ++k)
- KillNotePos(k);
+ notePool.killAllNotes();
}
else {
//All parameters must be NULL in this case
@@ -1247,8 +948,7 @@ void Part::kill_rt(void)
{
for(int i=0; i<NUM_PART_EFX; ++i)
partefx[i]->kill();
- for(int k = 0; k < POLYPHONY; ++k)
- KillNotePos(k);
+ notePool.killAllNotes();
}
void Part::monomemPush(char note)
@@ -1414,3 +1114,19 @@ void Part::getfromXML(XMLwrapper *xml)
xml->exitbranch();
}
}
+
+bool Part::Kit::active(void) const
+{
+ return Padenabled || Psubenabled || Ppadenabled;
+}
+
+uint8_t Part::Kit::sendto(void) const
+{
+ return limit((int)Psendtoparteffect, 0, NUM_PART_EFX);
+
+}
+
+bool Part::Kit::validNote(char note) const
+{
+ return !Pmuted && inRange((uint8_t)note, Pminkey, Pmaxkey);
+}
diff --git a/src/Misc/Part.h b/src/Misc/Part.h
@@ -27,6 +27,7 @@
#include "../globals.h"
#include "../Params/Controller.h"
+#include "../Containers/NotePool.h"
#include <functional>
@@ -94,6 +95,10 @@ class Part
SUBnoteParameters *subpars;
PADnoteParameters *padpars;
+ bool active(void) const;
+ uint8_t sendto(void) const;
+ bool validNote(char note) const;
+
const static rtosc::Ports &ports;
} kit[NUM_KIT_ITEMS];
@@ -155,25 +160,22 @@ class Part
const static rtosc::Ports &ports;
private:
- void RunNote(unsigned k);
- void KillNotePos(int pos);
- void ReleaseNotePos(int pos);
void MonoMemRenote(); // MonoMem stuff.
+ float getBaseFreq(int note, int keyshift) const;
+ float getVelocity(uint8_t velocity, uint8_t velocity_sense,
+ uint8_t velocity_offset) const;
+ void verifyKeyMode(void);
+ bool isPolyMode(void) const {return Ppolymode;}
+ bool isMonoMode(void) const {return !Ppolymode && !Plegatomode;};
+ bool isLegatoMode(void) const {return Plegatomode && !Pdrummode;}
+ bool isNonKit(void) const {return Pkitmode == 0;}
+ bool isMultiKit(void) const {return Pkitmode == 1;}
+ bool isSingleKit(void) const {return Pkitmode == 2;}
- int killallnotes; //is set to 1 if I want to kill all notes
-
- struct PartNotes {
- NoteStatus status;
- int note; //if there is no note playing, the "note"=-1
- int itemsplaying;
- struct {
- SynthNote *adnote, *subnote, *padnote;
- int sendtoparteffect;
- } kititem[NUM_KIT_ITEMS];
- int time;
- };
+ bool killallnotes;
+
+ NotePool notePool;
- int lastpos, lastposb; // To keep track of previously used pos and posb.
bool lastlegatomodevalid; // To keep track of previous legatomodevalid.
// MonoMem stuff
@@ -193,8 +195,6 @@ class Part
store the velocity and masterkeyshift values of a given note (the list only store note values).
For example 'monomem[note].velocity' would be the velocity value of the note 'note'.*/
- PartNotes partnote[POLYPHONY];
-
float oldfreq; //this is used for portamento
Microtonal *microtonal;
FFTwrapper *fft;
diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp
@@ -397,6 +397,13 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars)
initparameters();
}
+SynthNote *ADnote::cloneLegato(void)
+{
+ SynthParams sp{memory, ctl, synth, legato.param.freq, velocity,
+ (bool)portamento, legato.param.midinote, true};
+ return memory.alloc<ADnote>(&pars, sp);
+}
+
// ADlegatonote: This function is (mostly) a copy of ADnote(...) and
// initparameters() stuck together with some lines removed so that it
// only alter the already playing note (to perform legato). It is
diff --git a/src/Synth/ADnote.h b/src/Synth/ADnote.h
@@ -53,6 +53,8 @@ class ADnote:public SynthNote
int noteout(float *outl, float *outr);
void releasekey();
int finished() const;
+
+ virtual SynthNote *cloneLegato(void) override;
private:
/**Changes the frequency of an oscillator.
diff --git a/src/Synth/PADnote.cpp b/src/Synth/PADnote.cpp
@@ -28,7 +28,7 @@
#include "../Params/FilterParams.h"
#include "../Misc/Util.h"
-PADnote::PADnote(PADnoteParameters *parameters,
+PADnote::PADnote(const PADnoteParameters *parameters,
SynthParams pars)
:SynthNote(pars), pars(*parameters)
{
@@ -166,6 +166,13 @@ void PADnote::setup(float freq,
}
}
+SynthNote *PADnote::cloneLegato(void)
+{
+ SynthParams sp{memory, ctl, synth, legato.param.freq, velocity,
+ (bool)portamento, legato.param.midinote, true};
+ return memory.alloc<PADnote>(&pars, sp);
+}
+
void PADnote::legatonote(LegatoParams pars)
{
// Manage legato stuff
diff --git a/src/Synth/PADnote.h b/src/Synth/PADnote.h
@@ -30,9 +30,10 @@
class PADnote:public SynthNote
{
public:
- PADnote(PADnoteParameters *parameters, SynthParams pars);
+ PADnote(const PADnoteParameters *parameters, SynthParams pars);
~PADnote();
+ SynthNote *cloneLegato(void);
void legatonote(LegatoParams pars);
int noteout(float *outl, float *outr);
diff --git a/src/Synth/SUBnote.cpp b/src/Synth/SUBnote.cpp
@@ -33,7 +33,7 @@
#include "../Misc/Util.h"
#include "../Misc/Allocator.h"
-SUBnote::SUBnote(SUBnoteParameters *parameters, SynthParams &spars)
+SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars)
:SynthNote(spars), pars(*parameters)
{
NoteEnabled = ON;
@@ -46,6 +46,7 @@ void SUBnote::setup(float freq,
int midinote,
bool legato)
{
+ this->velocity = velocity;
portamento = portamento_;
NoteEnabled = ON;
volume = powf(0.1f, 3.0f * (1.0f - pars.PVolume / 96.0f)); //-60 dB .. 0 dB
@@ -210,6 +211,13 @@ void SUBnote::setup(float freq,
oldamplitude = newamplitude;
}
+SynthNote *SUBnote::cloneLegato(void)
+{
+ SynthParams sp{memory, ctl, synth, legato.param.freq, velocity,
+ (bool)portamento, legato.param.midinote, true};
+ return memory.alloc<SUBnote>(&pars, sp);
+}
+
void SUBnote::legatonote(LegatoParams pars)
{
// Manage legato stuff
diff --git a/src/Synth/SUBnote.h b/src/Synth/SUBnote.h
@@ -30,9 +30,10 @@
class SUBnote:public SynthNote
{
public:
- SUBnote(SUBnoteParameters *parameters, SynthParams &pars);
+ SUBnote(const SUBnoteParameters *parameters, SynthParams &pars);
~SUBnote();
+ SynthNote *cloneLegato(void);
void legatonote(LegatoParams pars);
int noteout(float *outl, float *outr); //note output,return 0 if the note is finished
@@ -100,6 +101,7 @@ class SUBnote:public SynthNote
int oldpitchwheel, oldbandwidth;
float globalfiltercenterq;
+ float velocity;
};
#endif
diff --git a/src/Synth/SynthNote.cpp b/src/Synth/SynthNote.cpp
@@ -3,9 +3,9 @@
#include <cstring>
SynthNote::SynthNote(SynthParams &pars)
- :legato(pars.synth, pars.frequency, pars.velocity, pars.portamento,
- pars.note, pars.quiet),
- memory(pars.memory), ctl(pars.ctl), synth(pars.synth)
+ :memory(pars.memory),
+ legato(pars.synth, pars.frequency, pars.velocity, pars.portamento,
+ pars.note, pars.quiet), ctl(pars.ctl), synth(pars.synth)
{}
SynthNote::Legato::Legato(const SYNTH_T &synth_, float freq, float vel, int port,
diff --git a/src/Synth/SynthNote.h b/src/Synth/SynthNote.h
@@ -28,7 +28,7 @@ class Controller;
struct SynthParams
{
Allocator &memory; //Memory Allocator for the Note to use
- Controller &ctl;
+ const Controller &ctl;
const SYNTH_T &synth;
float frequency; //Note base frequency
float velocity; //Velocity of the Note
@@ -65,8 +65,14 @@ class SynthNote
virtual int finished() const = 0;
virtual void legatonote(LegatoParams pars) = 0;
+
+ virtual SynthNote *cloneLegato(void) = 0;
+
/* For polyphonic aftertouch needed */
void setVelocity(float velocity_);
+
+ //Realtime Safe Memory Allocator For notes
+ class Allocator &memory;
protected:
// Legato transitions
class Legato
@@ -87,6 +93,7 @@ class SynthNote
int length;
float m, step;
} fade;
+ public:
struct { // Note parameters
float freq, vel;
bool portamento;
@@ -103,8 +110,6 @@ class SynthNote
void setDecounter(int decounter_) {decounter = decounter_; }
} legato;
- //Realtime Safe Memory Allocator For notes
- class Allocator &memory;
const Controller &ctl;
const SYNTH_T &synth;
};
diff --git a/src/Tests/KitTest.h b/src/Tests/KitTest.h
@@ -52,22 +52,32 @@ class KitTest:public CxxTest::TestSuite
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[0].note, 64);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=64,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
}
void testNoKitYesLegatoNoMono() {
@@ -75,26 +85,44 @@ class KitTest:public CxxTest::TestSuite
part->Plegatomode = true;
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[0].note, 65);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].adnote->legato.silent, true);
-
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr);
+ if(part->notePool.sdesc[1].note)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, true);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0)
}
void testNoKitNoLegatoYesMono() {
@@ -102,26 +130,44 @@ class KitTest:public CxxTest::TestSuite
part->Plegatomode = false;
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_RELEASED);
- TS_ASSERT_EQUALS(part->partnote[0].note, 64);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=64,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_RELEASED,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0)
}
//Normal Kit
@@ -136,34 +182,58 @@ class KitTest:public CxxTest::TestSuite
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[0].note, 64);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+ part->notePool.dump();
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=64,
+ .sendto=0,
+ .size=2,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=2,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 1)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[2].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[3].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].kit, 1)
+
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].kit, 0)
}
void testYesKitYesLegatoNoMono() {
@@ -177,38 +247,59 @@ class KitTest:public CxxTest::TestSuite
part->Plegatomode = true;
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[0].note, 65);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].adnote->legato.silent, true);
-
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+
+ part->notePool.dump();
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=2,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=2,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 1)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[2].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].note->legato.silent, true);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[3].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].note->legato.silent, true);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].kit, 1)
+
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].kit, 0)
}
void testYesKitNoLegatoYesMono() {
@@ -222,38 +313,59 @@ class KitTest:public CxxTest::TestSuite
part->Plegatomode = false;
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_RELEASED);
- TS_ASSERT_EQUALS(part->partnote[0].note, 64);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+
+ part->notePool.dump();
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=64,
+ .sendto=0,
+ .size=2,
+ .status=Part::KEY_RELEASED,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=2,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 1)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[2].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[3].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[3].kit, 1)
+
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[4].kit, 0)
}
//Single Kit
@@ -267,34 +379,48 @@ class KitTest:public CxxTest::TestSuite
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[0].note, 64);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+ part->notePool.dump();
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=64,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0)
+
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[2].kit, 0)
}
void testSingleKitYesLegatoNoMono() {
@@ -308,38 +434,44 @@ class KitTest:public CxxTest::TestSuite
part->Plegatomode = true;
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[0].note, 65);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].adnote->legato.silent, true);
-
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr);
+ if(part->notePool.sdesc[1].note)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, true);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0)
}
void testSingleKitNoLegatoYesMono() {
@@ -353,38 +485,45 @@ class KitTest:public CxxTest::TestSuite
part->Plegatomode = false;
part->NoteOn(64, 127, 0);
part->NoteOn(65, 127, 0);
- TS_ASSERT_EQUALS(part->partnote[0].status, Part::KEY_RELEASED);
- TS_ASSERT_EQUALS(part->partnote[0].note, 64);
- TS_ASSERT_EQUALS(part->partnote[0].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[0].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[0].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[1].status, Part::KEY_PLAYING);
- TS_ASSERT_EQUALS(part->partnote[1].note, 65);
- TS_ASSERT_EQUALS(part->partnote[1].time, 0);
- TS_ASSERT_DIFFERS(part->partnote[1].kititem[0].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[1].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].adnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[2].subnote, nullptr);
- TS_ASSERT_EQUALS(part->partnote[1].kititem[0].adnote->legato.silent, false);
-
-
- TS_ASSERT_EQUALS(part->partnote[2].status, Part::KEY_OFF);
- TS_ASSERT_EQUALS(part->partnote[2].note, -1);
+
+
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[0],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=64,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_RELEASED,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[1],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=65,
+ .sendto=0,
+ .size=1,
+ .status=Part::KEY_PLAYING,
+ .legatoMirror=false}));
+
+ TS_ASSERT_EQUALS(part->notePool.ndesc[2],
+ (NotePool::NoteDescriptor{
+ .age=0,
+ .note=0,
+ .sendto=0,
+ .size=0,
+ .status=0,
+ .legatoMirror=false}));
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[0].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[0].kit, 0)
+
+ TS_ASSERT_DIFFERS(part->notePool.sdesc[1].note, nullptr);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].note->legato.silent, false);
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].type, 0)
+ TS_ASSERT_EQUALS(part->notePool.sdesc[1].kit, 0)
}
void tearDown() {