ref: 6dcc4aeffb487193bb072797444d354fd7ded848
parent: 64d544f911536439cbc718aeb3d46cc6ad2732cb
author: spiricom <jeff@snyderphonics.com>
date: Tue May 26 18:22:42 EDT 2020
replaced multiple booleans in ADSR4 with single state variable, and added some functions to tSimplePoly to allow handling of release envelopes
--- a/LEAF/Inc/leaf-envelopes.h
+++ b/LEAF/Inc/leaf-envelopes.h
@@ -239,8 +239,10 @@
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
- /* ADSR 4*/
- typedef struct _tADSR4
+ //ADSR4
+
+
+ typedef struct _tADSR4
{
const float *exp_buff;
uint32_t buff_size;
@@ -250,7 +252,7 @@
float attackInc, decayInc, releaseInc, rampInc;
- oBool inAttack, inDecay, inSustain, inRelease, inRamp;
+ uint32_t whichStage;
float sustain, gain, rampPeak, releasePeak;
--- a/LEAF/Inc/leaf-midi.h
+++ b/LEAF/Inc/leaf-midi.h
@@ -364,14 +364,6 @@
//==============================================================================
- // simplified version of poly for more efficiency when we don't need ramps and pitch glide
- /*!
- * @defgroup tpoly tPoly
- * @ingroup midi
- * @brief An object for polyphonic handling.
- * @{
- */
-
/* tPoly */
typedef struct _tSimplePoly
{
@@ -380,6 +372,8 @@
int numVoices;
int maxNumVoices;
int** voices;
+ int stealing_on;
+ int recover_stolen;
int notes[128][2];
} _tSimplePoly;
@@ -435,6 +429,15 @@
int tSimplePoly_noteOff (tSimplePoly* const poly, uint8_t note);
+
+ void tSimplePoly_deactivateVoice(tSimplePoly* const polyh, uint8_t voice);
+
+ int tSimplePoly_markPendingNoteOff(tSimplePoly* const polyh, uint8_t note);
+
+
+ //find if there is a voice with that note -- useful for note offs where you want to wait to remove it from the poly until the release phase of the envelope is finished
+ int tSimplePoly_findVoiceAssignedToNote(tSimplePoly* const polyh, uint8_t note);
+
//! Set the number of voices available to play notes.
/*!
@param poly A pointer to the relevant tPoly.
@@ -470,6 +473,11 @@
*/
int tSimplePoly_getPitch (tSimplePoly* const poly, uint8_t voice);
+
+
+ //this one returns negative one if the voice is inactive
+ int tSimplePoly_getPitchAndCheckActive(tSimplePoly* const polyh, uint8_t voice);
+
//! Get the current MIDI velocity of a given voice.
/*!
--- a/LEAF/Src/leaf-envelopes.c
+++ b/LEAF/Src/leaf-envelopes.c
@@ -850,7 +850,7 @@
// use this if the size of the big ADSR tables is too much.
void tADSR4_init (tADSR4* const adsrenv, float attack, float decay, float sustain, float release, float* expBuffer, int bufferSize)
{
- tADSR4_initToPool (adsrenv, attack, decay, sustain, release, expBuffer, bufferSize, &leaf.mempool);
+ tADSR4_initToPool (adsrenv, attack, decay, sustain, release, expBuffer, bufferSize, &leaf.mempool);
}
void tADSR4_free(tADSR4* const adsrenv)
@@ -887,11 +887,7 @@
adsr->next = 0.0f;
- adsr->inRamp = OFALSE;
- adsr->inAttack = OFALSE;
- adsr->inDecay = OFALSE;
- adsr->inSustain = OFALSE;
- adsr->inRelease = OFALSE;
+ adsr->whichStage = env_idle;
adsr->sustain = sustain;
@@ -916,7 +912,7 @@
if (attack < 0.0f)
{
- attack = 0.0f;
+ attack = 0.0f;
}
adsr->attackInc = adsr->bufferSizeDividedBySampleRateInMs / attack;
@@ -928,7 +924,7 @@
if (decay < 0.0f)
{
- decay = 0.0f;
+ decay = 0.0f;
}
adsr->decayInc = adsr->bufferSizeDividedBySampleRateInMs / decay;
}
@@ -948,7 +944,7 @@
if (release < 0.0f)
{
- release = 0.0f;
+ release = 0.0f;
}
adsr->releaseInc = adsr->bufferSizeDividedBySampleRateInMs / release;
}
@@ -966,23 +962,20 @@
{
_tADSR4* adsr = *adsrenv;
- if ((adsr->inAttack || adsr->inDecay) || (adsr->inSustain || adsr->inRelease)) // In case ADSR retriggered while it is still happening.
+ if (adsr->whichStage != env_idle) // In case ADSR retriggered while it is still happening.
{
adsr->rampPhase = 0;
- adsr->inRamp = OTRUE;
+ adsr->whichStage = env_ramp;
adsr->rampPeak = adsr->next;
}
else // Normal start.
{
- adsr->inAttack = OTRUE;
+ adsr->whichStage = env_attack;
}
adsr->attackPhase = 0;
adsr->decayPhase = 0;
adsr->releasePhase = 0;
- adsr->inDecay = OFALSE;
- adsr->inSustain = OFALSE;
- adsr->inRelease = OFALSE;
adsr->gain = velocity;
}
@@ -990,14 +983,15 @@
{
_tADSR4* adsr = *adsrenv;
- if (adsr->inRelease) return;
-
- adsr->inAttack = OFALSE;
- adsr->inDecay = OFALSE;
- adsr->inSustain = OFALSE;
- adsr->inRelease = OTRUE;
-
- adsr->releasePeak = adsr->next;
+ if (adsr->whichStage == env_idle)
+ {
+ return;
+ }
+ else
+ {
+ adsr->whichStage = env_release;
+ adsr->releasePeak = adsr->next;
+ }
}
float tADSR4_tick(tADSR4* const adsrenv)
@@ -1004,132 +998,124 @@
{
_tADSR4* adsr = *adsrenv;
-
- if (adsr->inRamp)
+ switch (adsr->whichStage)
{
- if (adsr->rampPhase > adsr->buff_sizeMinusOne)
- {
- adsr->inRamp = OFALSE;
- adsr->inAttack = OTRUE;
- adsr->next = 0.0f;
- }
- else
- {
- uint32_t intPart = (uint32_t)adsr->rampPhase;
- float floatPart = adsr->rampPhase - intPart;
- float secondValue;
- if (adsr->rampPhase + 1.0f > adsr->buff_sizeMinusOne)
- {
- secondValue = 0.0f;
- }
- else
- {
- secondValue = adsr->exp_buff[(uint32_t)((adsr->rampPhase)+1)];
- }
- adsr->next = adsr->rampPeak * LEAF_interpolation_linear(adsr->exp_buff[(uint32_t)(adsr->rampPhase)], secondValue, floatPart);
- }
+ case env_ramp:
+ if (adsr->rampPhase > adsr->buff_sizeMinusOne)
+ {
+ adsr->whichStage = env_attack;
+ adsr->next = 0.0f;
+ }
+ else
+ {
+ uint32_t intPart = (uint32_t)adsr->rampPhase;
+ float floatPart = adsr->rampPhase - intPart;
+ float secondValue;
+ if (adsr->rampPhase + 1.0f > adsr->buff_sizeMinusOne)
+ {
+ secondValue = 0.0f;
+ }
+ else
+ {
+ secondValue = adsr->exp_buff[(uint32_t)((adsr->rampPhase)+1)];
+ }
+ adsr->next = adsr->rampPeak * LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart);
+ }
- adsr->rampPhase += adsr->rampInc;
- }
+ adsr->rampPhase += adsr->rampInc;
+ break;
- if (adsr->inAttack)
- {
- // If attack done, time to turn around.
- if (adsr->attackPhase > adsr->buff_sizeMinusOne)
- {
- adsr->inDecay = OTRUE;
- adsr->inAttack = OFALSE;
- adsr->next = adsr->gain;
- }
- else
- {
- // do interpolation !
- uint32_t intPart = (uint32_t)adsr->attackPhase;
- float floatPart = adsr->attackPhase - intPart;
- float secondValue;
- if (adsr->attackPhase + 1.0f > adsr->buff_sizeMinusOne)
- {
- secondValue = 0.0f;
- }
- else
- {
- secondValue = adsr->exp_buff[(uint32_t)((adsr->attackPhase)+1)];
- }
+ case env_attack:
- adsr->next = adsr->gain * (1.0f - LEAF_interpolation_linear(adsr->exp_buff[(uint32_t)(adsr->attackPhase)], secondValue, floatPart)); // inverted and backwards to get proper rising exponential shape/perception
- }
+ // If attack done, time to turn around.
+ if (adsr->attackPhase > adsr->buff_sizeMinusOne)
+ {
+ adsr->whichStage = env_decay;
+ adsr->next = adsr->gain;
+ }
+ else
+ {
+ // do interpolation !
+ uint32_t intPart = (uint32_t)adsr->attackPhase;
+ float floatPart = adsr->attackPhase - intPart;
+ float secondValue;
+ if (adsr->attackPhase + 1.0f > adsr->buff_sizeMinusOne)
+ {
+ secondValue = 0.0f;
+ }
+ else
+ {
+ secondValue = adsr->exp_buff[(uint32_t)((adsr->attackPhase)+1)];
+ }
- // Increment ADSR attack.
- adsr->attackPhase += adsr->attackInc;
+ adsr->next = adsr->gain * (1.0f - LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart)); // inverted and backwards to get proper rising exponential shape/perception
+ }
- }
+ // Increment ADSR attack.
+ adsr->attackPhase += adsr->attackInc;
+ break;
- if (adsr->inDecay)
- {
+ case env_decay:
- // If decay done, sustain.
- if (adsr->decayPhase > adsr->buff_sizeMinusOne)
- {
- adsr->inDecay = OFALSE;
- adsr->inSustain = OTRUE;
- adsr->next = adsr->gain * adsr->sustain;
- }
+ // If decay done, sustain.
+ if (adsr->decayPhase > adsr->buff_sizeMinusOne)
+ {
+ adsr->whichStage = env_sustain;
+ adsr->next = adsr->gain * adsr->sustain;
+ }
- else
- {
- uint32_t intPart = (uint32_t)adsr->decayPhase;
- float floatPart = adsr->decayPhase - intPart;
- float secondValue;
- if (adsr->decayPhase + 1.0f > adsr->buff_sizeMinusOne)
- {
- secondValue = 0.0f;
- }
- else
- {
- secondValue = adsr->exp_buff[(uint32_t)((adsr->decayPhase)+1)];
- }
- float interpValue = (LEAF_interpolation_linear(adsr->exp_buff[(uint32_t)(adsr->decayPhase)], secondValue, floatPart));
- adsr->next = (adsr->gain * (adsr->sustain + (interpValue * (1.0f - adsr->sustain)))) * adsr->leakFactor; // do interpolation !
- }
+ else
+ {
+ uint32_t intPart = (uint32_t)adsr->decayPhase;
+ float floatPart = adsr->decayPhase - intPart;
+ float secondValue;
+ if (adsr->decayPhase + 1.0f > adsr->buff_sizeMinusOne)
+ {
+ secondValue = 0.0f;
+ }
+ else
+ {
+ secondValue = adsr->exp_buff[(uint32_t)((adsr->decayPhase)+1)];
+ }
+ float interpValue = (LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart));
+ adsr->next = (adsr->gain * (adsr->sustain + (interpValue * (1.0f - adsr->sustain)))) * adsr->leakFactor; // do interpolation !
+ }
- // Increment ADSR decay.
- adsr->decayPhase += adsr->decayInc;
- }
+ // Increment ADSR decay.
+ adsr->decayPhase += adsr->decayInc;
+ break;
- if (adsr->inSustain)
- {
- adsr->next = adsr->next * adsr->leakFactor;
- }
+ case env_sustain:
+ adsr->next = adsr->next * adsr->leakFactor;
+ break;
- if (adsr->inRelease)
- {
- // If release done, finish.
- if (adsr->releasePhase > adsr->buff_sizeMinusOne)
- {
- adsr->inRelease = OFALSE;
- adsr->next = 0.0f;
- }
- else {
- uint32_t intPart = (uint32_t)adsr->releasePhase;
- float floatPart = adsr->releasePhase - intPart;
- float secondValue;
- if (adsr->releasePhase + 1.0f > adsr->buff_sizeMinusOne)
- {
- secondValue = 0.0f;
- }
- else
- {
- secondValue = adsr->exp_buff[(uint32_t)((adsr->releasePhase)+1)];
- }
- adsr->next = adsr->releasePeak * (LEAF_interpolation_linear(adsr->exp_buff[(uint32_t)(adsr->releasePhase)], secondValue, floatPart)); // do interpolation !
- }
+ case env_release:
+ // If release done, finish.
+ if (adsr->releasePhase > adsr->buff_sizeMinusOne)
+ {
+ adsr->whichStage = env_idle;
+ adsr->next = 0.0f;
+ }
+ else {
+ uint32_t intPart = (uint32_t)adsr->releasePhase;
+ float floatPart = adsr->releasePhase - intPart;
+ float secondValue;
+ if (adsr->releasePhase + 1.0f > adsr->buff_sizeMinusOne)
+ {
+ secondValue = 0.0f;
+ }
+ else
+ {
+ secondValue = adsr->exp_buff[(uint32_t)((adsr->releasePhase)+1)];
+ }
+ adsr->next = adsr->releasePeak * (LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart)); // do interpolation !
+ }
- // Increment envelope release;
- adsr->releasePhase += adsr->releaseInc;
+ // Increment envelope release;
+ adsr->releasePhase += adsr->releaseInc;
+ break;
}
-
-
return adsr->next;
}
@@ -1137,87 +1123,77 @@
{
_tADSR4* adsr = *adsrenv;
-
- if (adsr->inRamp)
+ switch (adsr->whichStage)
{
- if (adsr->rampPhase > adsr->buff_sizeMinusOne)
- {
- adsr->inRamp = OFALSE;
- adsr->inAttack = OTRUE;
- adsr->next = 0.0f;
- }
- else
- {
- adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)(adsr->rampPhase)];
- }
+ case env_ramp:
+ if (adsr->rampPhase > adsr->buff_sizeMinusOne)
+ {
+ adsr->whichStage = env_attack;
+ adsr->next = 0.0f;
+ }
+ else
+ {
+ adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase];
+ }
- adsr->rampPhase += adsr->rampInc;
- }
+ adsr->rampPhase += adsr->rampInc;
+ break;
- if (adsr->inAttack)
- {
- // If attack done, time to turn around.
- if (adsr->attackPhase > adsr->buff_sizeMinusOne)
- {
- adsr->inDecay = OTRUE;
- adsr->inAttack = OFALSE;
- adsr->next = adsr->gain;
- }
- else
- {
- // do interpolation !
- adsr->next = adsr->gain * (1.0f - adsr->exp_buff[(uint32_t)(adsr->attackPhase)]); // inverted and backwards to get proper rising exponential shape/perception
- }
+ case env_attack:
- // Increment ADSR attack.
- adsr->attackPhase += adsr->attackInc;
+ // If attack done, time to turn around.
+ if (adsr->attackPhase > adsr->buff_sizeMinusOne)
+ {
+ adsr->whichStage = env_decay;
+ adsr->next = adsr->gain;
+ }
+ else
+ {
+ adsr->next = adsr->gain * (1.0f - adsr->exp_buff[(uint32_t)adsr->attackPhase]); // inverted and backwards to get proper rising exponential shape/perception
+ }
- }
+ // Increment ADSR attack.
+ adsr->attackPhase += adsr->attackInc;
+ break;
- if (adsr->inDecay)
- {
+ case env_decay:
- // If decay done, sustain.
- if (adsr->decayPhase > adsr->buff_sizeMinusOne)
- {
- adsr->inDecay = OFALSE;
- adsr->inSustain = OTRUE;
- adsr->next = adsr->gain * adsr->sustain;
- }
+ // If decay done, sustain.
+ if (adsr->decayPhase > adsr->buff_sizeMinusOne)
+ {
+ adsr->whichStage = env_sustain;
+ adsr->next = adsr->gain * adsr->sustain;
+ }
- else
- {
- adsr->next = (adsr->gain * (adsr->sustain + ((adsr->exp_buff[(uint32_t)(adsr->decayPhase)]) * (1.0f - adsr->sustain)))) * adsr->leakFactor; // do interpolation !
- }
+ else
+ {
+ adsr->next = (adsr->gain * (adsr->sustain + (adsr->exp_buff[(uint32_t)adsr->decayPhase] * (1.0f - adsr->sustain)))) * adsr->leakFactor;
+ }
- // Increment ADSR decay.
- adsr->decayPhase += adsr->decayInc;
- }
+ // Increment ADSR decay.
+ adsr->decayPhase += adsr->decayInc;
+ break;
- if (adsr->inSustain)
- {
- adsr->next = adsr->next * adsr->leakFactor;
- }
+ case env_sustain:
+ adsr->next = adsr->next * adsr->leakFactor;
+ break;
- if (adsr->inRelease)
- {
- // If release done, finish.
- if (adsr->releasePhase > adsr->buff_sizeMinusOne)
- {
- adsr->inRelease = OFALSE;
- adsr->next = 0.0f;
- }
- else {
+ case env_release:
+ // If release done, finish.
+ if (adsr->releasePhase > adsr->buff_sizeMinusOne)
+ {
+ adsr->whichStage = env_idle;
+ adsr->next = 0.0f;
+ }
+ else {
+ adsr->next = adsr->releasePeak * adsr->exp_buff[(uint32_t)adsr->releasePhase];
+ }
- adsr->next = adsr->releasePeak * (adsr->exp_buff[(uint32_t)(adsr->releasePhase)]); // do interpolation !
- }
-
- // Increment envelope release;
- adsr->releasePhase += adsr->releaseInc;
+ // Increment envelope release;
+ adsr->releasePhase += adsr->releaseInc;
+ break;
}
-
-
return adsr->next;
}
--- a/LEAF/Src/leaf-midi.c
+++ b/LEAF/Src/leaf-midi.c
@@ -682,9 +682,10 @@
-//tSimplePoly = more efficient implementation without ramps and glide
+//tSimplePoly = much more efficient implementation without ramps and glide
+
// SIMPLE POLY
void tSimplePoly_init(tSimplePoly* const polyh, int maxNumVoices)
{
@@ -709,7 +710,8 @@
poly->notes[i][0] = -1;
poly->notes[i][1] = 0;
}
-
+ poly->stealing_on = 1;
+ poly->recover_stolen = 1;
poly->voices = (int**) mpool_alloc(sizeof(int*) * poly->maxNumVoices, m);
for (int i = 0; i < poly->maxNumVoices; ++i)
@@ -743,13 +745,11 @@
if (tStack_contains(&poly->stack, note) >= 0) return -1;
else
{
- tStack_add(&poly->stack, note);
-
alteredVoice = -1;
oBool found = OFALSE;
for (int i = 0; i < poly->numVoices; i++)
{
- if (poly->voices[i][0] < 0) // if inactive voice, give this note to voice
+ if (poly->voices[i][0] == -1) // if inactive voice, give this note to voice
{
found = OTRUE;
@@ -757,15 +757,37 @@
poly->voices[i][0] = note;
poly->voices[i][1] = vel;
poly->notes[note][0] = i;
-
+ poly->notes[note][1] = vel;
poly->voices[i][2] = note; // voices[i][2] is the output midi note, (avoiding the -1 when a voice is inactive)
alteredVoice = i;
+ tStack_add(&poly->stack, note);
break;
}
}
+ if (!found)
+ {
+ //second preference is grabbing one that is in release phase but not finished sounding yet
+ for (int i = 0 ; i < poly->numVoices; i++)
+ {
+ if (poly->voices[i][0] == -2) // if voice is released but still sounding, take over this voice
+ {
- if (!found) //steal
+ found = OTRUE;
+
+ poly->voices[i][0] = note;
+ poly->voices[i][1] = vel;
+ poly->notes[note][0] = i;
+ poly->notes[note][1] = vel;
+ poly->voices[i][2] = note; // voices[i][2] is the output midi note, (avoiding the -1 when a voice is inactive)
+
+ alteredVoice = i;
+ tStack_add(&poly->stack, note);
+ break;
+ }
+ }
+ }
+ if ((!found) && (poly->stealing_on)) //steal
{
for (int j = tStack_getSize(&poly->stack) - 1; j >= 0; j--)
{
@@ -776,7 +798,7 @@
oldNote = poly->voices[whichVoice][0];
poly->voices[whichVoice][0] = note;
poly->voices[whichVoice][1] = vel;
- poly->notes[oldNote][0] = -1; //mark the stolen voice as inactive (in the second dimension of the notes array)
+ poly->notes[oldNote][0] = -3; //mark the stolen voice as stolen (in the second dimension of the notes array)
poly->notes[note][0] = whichVoice;
poly->notes[note][1] = vel;
@@ -783,7 +805,7 @@
poly->voices[whichVoice][2] = note;
alteredVoice = whichVoice;
-
+ tStack_add(&poly->stack, note);
break;
}
}
@@ -794,17 +816,14 @@
-
int tSimplePoly_noteOff(tSimplePoly* const polyh, uint8_t note)
{
_tSimplePoly* poly = *polyh;
int16_t noteToTest = -1;
-
tStack_remove(&poly->stack, note);
poly->notes[note][0] = -1;
-
int deactivatedVoice = -1;
for (int i = 0; i < poly->maxNumVoices; i++)
{
@@ -817,23 +836,101 @@
}
}
- //grab old notes off the stack if there are notes waiting to replace the free voice
- if (deactivatedVoice >= 0)
+ if (poly->recover_stolen)
{
- for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
+ //grab old notes off the stack if there are notes waiting to replace the free voice
+ if (deactivatedVoice >= 0)
{
- noteToTest = tStack_get(&poly->stack, j);
+ for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
+ {
+ noteToTest = tStack_get(&poly->stack, j);
- if (poly->notes[noteToTest][0] < 0) //if there is a stolen note waiting (marked inactive but on the stack)
+ if (poly->notes[noteToTest][0] == -3) //if there is a stolen note waiting (marked inactive but on the stack)
+ {
+ poly->voices[deactivatedVoice][0] = noteToTest; //set the newly free voice to use the old stolen note
+ poly->voices[deactivatedVoice][1] = poly->notes[noteToTest][1]; // set the velocity of the voice to be the velocity of that note
+ poly->voices[deactivatedVoice][2] = noteToTest;
+ poly->notes[noteToTest][0] = deactivatedVoice; //mark that it is no longer stolen and is now active
+ return -1;
+ }
+ }
+ }
+ }
+ return deactivatedVoice;
+}
+
+
+void tSimplePoly_deactivateVoice(tSimplePoly* const polyh, uint8_t voice)
+{
+ _tSimplePoly* poly = *polyh;
+
+ if (poly->voices[voice][0] == -2) //only do this if the voice is waiting for deactivation (not already reassigned while waiting)
+ {
+ poly->voices[voice][0] = -1;
+ poly->voices[voice][1] = 0;
+ if (poly->recover_stolen)
+ {
+ //grab old notes off the stack if there are notes waiting to replace the free voice
+ for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
{
- poly->voices[deactivatedVoice][0] = noteToTest; //set the newly free voice to use the old stolen note
- poly->voices[deactivatedVoice][1] = poly->notes[noteToTest][1]; // set the velocity of the voice to be the velocity of that note
- poly->voices[deactivatedVoice][2] = noteToTest;
- poly->notes[noteToTest][0] = deactivatedVoice; //mark that it is no longer stolen and is now active
- return -1;
+ noteToTest = tStack_get(&poly->stack, j);
+
+ if (poly->notes[noteToTest][0] == -3) //if there is a stolen note waiting (marked inactive but on the stack)
+ {
+ poly->voices[voice][0] = noteToTest; //set the newly free voice to use the old stolen note
+ poly->voices[voice][1] = poly->notes[noteToTest][1]; // set the velocity of the voice to be the velocity of that note
+ poly->voices[voice][2] = noteToTest;
+ poly->notes[noteToTest][0] = voice; //mark that it is no longer stolen and is now active
+ }
}
}
}
+}
+
+int tSimplePoly_findVoiceAssignedToNote(tSimplePoly* const polyh, uint8_t note)
+{
+ _tSimplePoly* poly = *polyh;
+
+
+ int voiceWithThatNote = -1;
+ for (int i = 0; i < poly->maxNumVoices; i++)
+ {
+ if (poly->voices[i][0] == note)
+ {
+ voiceWithThatNote = i;
+ break;
+ }
+ }
+ return voiceWithThatNote;
+}
+
+
+int tSimplePoly_markPendingNoteOff(tSimplePoly* const polyh, uint8_t note)
+{
+ _tSimplePoly* poly = *polyh;
+ int deactivatedVoice = -1;
+
+ if (tStack_remove(&poly->stack, note))
+
+ {
+
+ poly->notes[note][0] = -2;
+
+
+
+ for (int i = 0; i < poly->maxNumVoices; i++)
+ {
+ if (poly->voices[i][0] == note)
+ {
+ poly->voices[i][0] = -2;
+ poly->voices[i][1] = 0;
+ deactivatedVoice = i;
+ break;
+ }
+ }
+
+
+ }
return deactivatedVoice;
}
@@ -861,6 +958,13 @@
{
_tSimplePoly* poly = *polyh;
return poly->voices[voice][2];
+}
+
+//this one returns negative one if the voice is inactive
+int tSimplePoly_getPitchAndCheckActive(tSimplePoly* const polyh, uint8_t voice)
+{
+ _tSimplePoly* poly = *polyh;
+ return poly->voices[voice][0];
}
int tSimplePoly_getVelocity(tSimplePoly* const polyh, uint8_t voice)