History

replaced multiple booleans in ADSR4 with single state variable, and added some functions to tSimplePoly to allow handling of release envelopes

spiricom committed 6 years ago

Commit 6dcc4ae1 parent 64d544f4 files · +325 −235Browse files

Unified · Split

4 files
  1. LEAF/Inc/leaf-envelopes.h +5 −3
  2. LEAF/Inc/leaf-midi.h +16 −8
  3. LEAF/Src/leaf-envelopes.c +178 −202
  4. LEAF/Src/leaf-midi.c +126 −22
LEAF/Inc/leaf-envelopes.h+5−3
@@ -239,8 +239,10 @@ extern "C" { · 238 unmodified lines
239239
240240 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
241241
242− /* ADSR 4*/
243− typedef struct _tADSR4
242+ //ADSR4
243+
244+
245+ typedef struct _tADSR4
244246 {
245247 const float *exp_buff;
246248 uint32_t buff_size;
@@ -250,7 +252,7 @@ extern "C" { · 3 unmodified lines
250252
251253 float attackInc, decayInc, releaseInc, rampInc;
252254
253− oBool inAttack, inDecay, inSustain, inRelease, inRamp;
255+ uint32_t whichStage;
254256
255257 float sustain, gain, rampPeak, releasePeak;
256258
LEAF/Inc/leaf-midi.h+16−8
@@ -364,14 +364,6 @@ extern "C" { · 363 unmodified lines
364364 //==============================================================================
365365
366366
367− // simplified version of poly for more efficiency when we don't need ramps and pitch glide
368− /*!
369− * @defgroup tpoly tPoly
370− * @ingroup midi
371− * @brief An object for polyphonic handling.
372− * @{
373− */
374−
375367 /* tPoly */
376368 typedef struct _tSimplePoly
377369 {
@@ -380,6 +372,8 @@ extern "C" { · 2 unmodified lines
380372 int numVoices;
381373 int maxNumVoices;
382374 int** voices;
375+ int stealing_on;
376+ int recover_stolen;
383377
384378 int notes[128][2];
385379 } _tSimplePoly;
@@ -435,6 +429,15 @@ extern "C" { · 49 unmodified lines
435429 int tSimplePoly_noteOff (tSimplePoly* const poly, uint8_t note);
436430
437431
432+
433+ void tSimplePoly_deactivateVoice(tSimplePoly* const polyh, uint8_t voice);
434+
435+ int tSimplePoly_markPendingNoteOff(tSimplePoly* const polyh, uint8_t note);
436+
437+
438+ //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
439+ int tSimplePoly_findVoiceAssignedToNote(tSimplePoly* const polyh, uint8_t note);
440+
438441 //! Set the number of voices available to play notes.
439442 /*!
440443 @param poly A pointer to the relevant tPoly.
@@ -471,6 +474,11 @@ extern "C" { · 30 unmodified lines
471474
472475 int tSimplePoly_getPitch (tSimplePoly* const poly, uint8_t voice);
473476
477+
478+ //this one returns negative one if the voice is inactive
479+ int tSimplePoly_getPitchAndCheckActive(tSimplePoly* const polyh, uint8_t voice);
480+
481+
474482 //! Get the current MIDI velocity of a given voice.
475483 /*!
476484 @param poly A pointer to the relevant tPoly.
LEAF/Src/leaf-envelopes.c+178−202
@@ -850,7 +850,7 @@ float tADSR3_tick(tADSR3* const adsrenv) · 849 unmodified lines
850850 // use this if the size of the big ADSR tables is too much.
851851 void tADSR4_init (tADSR4* const adsrenv, float attack, float decay, float sustain, float release, float* expBuffer, int bufferSize)
852852 {
853− tADSR4_initToPool (adsrenv, attack, decay, sustain, release, expBuffer, bufferSize, &leaf.mempool);
853+ tADSR4_initToPool (adsrenv, attack, decay, sustain, release, expBuffer, bufferSize, &leaf.mempool);
854854 }
855855
856856 void tADSR4_free(tADSR4* const adsrenv)
@@ -887,11 +887,7 @@ void tADSR4_initToPool (tADSR4* const adsrenv, float attack, float decay, · 30 unmodified lines
887887
888888 adsr->next = 0.0f;
889889
890− adsr->inRamp = OFALSE;
891− adsr->inAttack = OFALSE;
892− adsr->inDecay = OFALSE;
893− adsr->inSustain = OFALSE;
894− adsr->inRelease = OFALSE;
890+ adsr->whichStage = env_idle;
895891
896892 adsr->sustain = sustain;
897893
@@ -916,7 +912,7 @@ void tADSR4_setAttack(tADSR4* const adsrenv, float attack) · 18 unmodified lines
916912
917913 if (attack < 0.0f)
918914 {
919− attack = 0.0f;
915+ attack = 0.0f;
920916 }
921917
922918 adsr->attackInc = adsr->bufferSizeDividedBySampleRateInMs / attack;
@@ -928,7 +924,7 @@ void tADSR4_setDecay(tADSR4* const adsrenv, float decay) · 5 unmodified lines
928924
929925 if (decay < 0.0f)
930926 {
931− decay = 0.0f;
927+ decay = 0.0f;
932928 }
933929 adsr->decayInc = adsr->bufferSizeDividedBySampleRateInMs / decay;
934930 }
@@ -948,7 +944,7 @@ void tADSR4_setRelease(tADSR4* const adsrenv, float release) · 13 unmodified lines
948944
949945 if (release < 0.0f)
950946 {
951− release = 0.0f;
947+ release = 0.0f;
952948 }
953949 adsr->releaseInc = adsr->bufferSizeDividedBySampleRateInMs / release;
954950 }
@@ -966,23 +962,20 @@ void tADSR4_on(tADSR4* const adsrenv, float velocity) · 11 unmodified lines
966962 {
967963 _tADSR4* adsr = *adsrenv;
968964
969− if ((adsr->inAttack || adsr->inDecay) || (adsr->inSustain || adsr->inRelease)) // In case ADSR retriggered while it is still happening.
965+ if (adsr->whichStage != env_idle) // In case ADSR retriggered while it is still happening.
970966 {
971967 adsr->rampPhase = 0;
972− adsr->inRamp = OTRUE;
968+ adsr->whichStage = env_ramp;
973969 adsr->rampPeak = adsr->next;
974970 }
975971 else // Normal start.
976972 {
977− adsr->inAttack = OTRUE;
973+ adsr->whichStage = env_attack;
978974 }
979975
980976 adsr->attackPhase = 0;
981977 adsr->decayPhase = 0;
982978 adsr->releasePhase = 0;
983− adsr->inDecay = OFALSE;
984− adsr->inSustain = OFALSE;
985− adsr->inRelease = OFALSE;
986979 adsr->gain = velocity;
987980 }
988981
@@ -990,146 +983,139 @@ void tADSR4_off(tADSR4* const adsrenv) · 1 unmodified line
990983 {
991984 _tADSR4* adsr = *adsrenv;
992985
993− if (adsr->inRelease) return;
994−
995− adsr->inAttack = OFALSE;
996− adsr->inDecay = OFALSE;
997− adsr->inSustain = OFALSE;
998− adsr->inRelease = OTRUE;
999−
1000− adsr->releasePeak = adsr->next;
986+ if (adsr->whichStage == env_idle)
987+ {
988+ return;
989+ }
990+ else
991+ {
992+ adsr->whichStage = env_release;
993+ adsr->releasePeak = adsr->next;
994+ }
1001995 }
1002996
1003997 float tADSR4_tick(tADSR4* const adsrenv)
1004998 {
1005999 _tADSR4* adsr = *adsrenv;
10061000
1007−
1008− if (adsr->inRamp)
1001+ switch (adsr->whichStage)
10091002 {
1010− if (adsr->rampPhase > adsr->buff_sizeMinusOne)
1011− {
1012− adsr->inRamp = OFALSE;
1013− adsr->inAttack = OTRUE;
1014− adsr->next = 0.0f;
1015− }
1016− else
1017− {
1018− uint32_t intPart = (uint32_t)adsr->rampPhase;
1019− float floatPart = adsr->rampPhase - intPart;
1020− float secondValue;
1021− if (adsr->rampPhase + 1.0f > adsr->buff_sizeMinusOne)
1022− {
1023− secondValue = 0.0f;
1024− }
1025− else
1026− {
1027− secondValue = adsr->exp_buff[(uint32_t)((adsr->rampPhase)+1)];
1028− }
1029− adsr->next = adsr->rampPeak * LEAF_interpolation_linear(adsr->exp_buff[(uint32_t)(adsr->rampPhase)], secondValue, floatPart);
1030− }
1003+ case env_ramp:
1004+ if (adsr->rampPhase > adsr->buff_sizeMinusOne)
1005+ {
1006+ adsr->whichStage = env_attack;
1007+ adsr->next = 0.0f;
1008+ }
1009+ else
1010+ {
1011+ uint32_t intPart = (uint32_t)adsr->rampPhase;
1012+ float floatPart = adsr->rampPhase - intPart;
1013+ float secondValue;
1014+ if (adsr->rampPhase + 1.0f > adsr->buff_sizeMinusOne)
1015+ {
1016+ secondValue = 0.0f;
1017+ }
1018+ else
1019+ {
1020+ secondValue = adsr->exp_buff[(uint32_t)((adsr->rampPhase)+1)];
1021+ }
1022+ adsr->next = adsr->rampPeak * LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart);
1023+ }
10311024
1032− adsr->rampPhase += adsr->rampInc;
1033− }
1025+ adsr->rampPhase += adsr->rampInc;
1026+ break;
10341027
1035− if (adsr->inAttack)
1036− {
10371028
1038− // If attack done, time to turn around.
1039− if (adsr->attackPhase > adsr->buff_sizeMinusOne)
1040− {
1041− adsr->inDecay = OTRUE;
1042− adsr->inAttack = OFALSE;
1043− adsr->next = adsr->gain;
1044− }
1045− else
1046− {
1047− // do interpolation !
1048− uint32_t intPart = (uint32_t)adsr->attackPhase;
1049− float floatPart = adsr->attackPhase - intPart;
1050− float secondValue;
1051− if (adsr->attackPhase + 1.0f > adsr->buff_sizeMinusOne)
1052− {
1053− secondValue = 0.0f;
1054− }
1055− else
1056− {
1057− secondValue = adsr->exp_buff[(uint32_t)((adsr->attackPhase)+1)];
1058− }
1059−
1060− 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
1061− }
1029+ case env_attack:
10621030
1063− // Increment ADSR attack.
1064− adsr->attackPhase += adsr->attackInc;
1031+ // If attack done, time to turn around.
1032+ if (adsr->attackPhase > adsr->buff_sizeMinusOne)
1033+ {
1034+ adsr->whichStage = env_decay;
1035+ adsr->next = adsr->gain;
1036+ }
1037+ else
1038+ {
1039+ // do interpolation !
1040+ uint32_t intPart = (uint32_t)adsr->attackPhase;
1041+ float floatPart = adsr->attackPhase - intPart;
1042+ float secondValue;
1043+ if (adsr->attackPhase + 1.0f > adsr->buff_sizeMinusOne)
1044+ {
1045+ secondValue = 0.0f;
1046+ }
1047+ else
1048+ {
1049+ secondValue = adsr->exp_buff[(uint32_t)((adsr->attackPhase)+1)];
1050+ }
1051+
1052+ 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
1053+ }
10651054
1066− }
1055+ // Increment ADSR attack.
1056+ adsr->attackPhase += adsr->attackInc;
1057+ break;
10671058
1068− if (adsr->inDecay)
1069− {
1059+ case env_decay:
10701060
1071− // If decay done, sustain.
1072− if (adsr->decayPhase > adsr->buff_sizeMinusOne)
1073− {
1074− adsr->inDecay = OFALSE;
1075− adsr->inSustain = OTRUE;
1076− adsr->next = adsr->gain * adsr->sustain;
1077− }
1061+ // If decay done, sustain.
1062+ if (adsr->decayPhase > adsr->buff_sizeMinusOne)
1063+ {
1064+ adsr->whichStage = env_sustain;
1065+ adsr->next = adsr->gain * adsr->sustain;
1066+ }
10781067
1079− else
1080− {
1081− uint32_t intPart = (uint32_t)adsr->decayPhase;
1082− float floatPart = adsr->decayPhase - intPart;
1083− float secondValue;
1084− if (adsr->decayPhase + 1.0f > adsr->buff_sizeMinusOne)
1085− {
1086− secondValue = 0.0f;
1087− }
1088− else
1089− {
1090− secondValue = adsr->exp_buff[(uint32_t)((adsr->decayPhase)+1)];
1091− }
1092− float interpValue = (LEAF_interpolation_linear(adsr->exp_buff[(uint32_t)(adsr->decayPhase)], secondValue, floatPart));
1093− adsr->next = (adsr->gain * (adsr->sustain + (interpValue * (1.0f - adsr->sustain)))) * adsr->leakFactor; // do interpolation !
1094− }
1068+ else
1069+ {
1070+ uint32_t intPart = (uint32_t)adsr->decayPhase;
1071+ float floatPart = adsr->decayPhase - intPart;
1072+ float secondValue;
1073+ if (adsr->decayPhase + 1.0f > adsr->buff_sizeMinusOne)
1074+ {
1075+ secondValue = 0.0f;
1076+ }
1077+ else
1078+ {
1079+ secondValue = adsr->exp_buff[(uint32_t)((adsr->decayPhase)+1)];
1080+ }
1081+ float interpValue = (LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart));
1082+ adsr->next = (adsr->gain * (adsr->sustain + (interpValue * (1.0f - adsr->sustain)))) * adsr->leakFactor; // do interpolation !
1083+ }
10951084
1096− // Increment ADSR decay.
1097− adsr->decayPhase += adsr->decayInc;
1098− }
1085+ // Increment ADSR decay.
1086+ adsr->decayPhase += adsr->decayInc;
1087+ break;
10991088
1100− if (adsr->inSustain)
1101− {
1102− adsr->next = adsr->next * adsr->leakFactor;
1103− }
1089+ case env_sustain:
1090+ adsr->next = adsr->next * adsr->leakFactor;
1091+ break;
11041092
1105− if (adsr->inRelease)
1106− {
1107− // If release done, finish.
1108− if (adsr->releasePhase > adsr->buff_sizeMinusOne)
1109− {
1110− adsr->inRelease = OFALSE;
1111− adsr->next = 0.0f;
1112− }
1113− else {
1114− uint32_t intPart = (uint32_t)adsr->releasePhase;
1115− float floatPart = adsr->releasePhase - intPart;
1116− float secondValue;
1117− if (adsr->releasePhase + 1.0f > adsr->buff_sizeMinusOne)
1118− {
1119− secondValue = 0.0f;
1120− }
1121− else
1122− {
1123− secondValue = adsr->exp_buff[(uint32_t)((adsr->releasePhase)+1)];
1124− }
1125− adsr->next = adsr->releasePeak * (LEAF_interpolation_linear(adsr->exp_buff[(uint32_t)(adsr->releasePhase)], secondValue, floatPart)); // do interpolation !
1126− }
1093+ case env_release:
1094+ // If release done, finish.
1095+ if (adsr->releasePhase > adsr->buff_sizeMinusOne)
1096+ {
1097+ adsr->whichStage = env_idle;
1098+ adsr->next = 0.0f;
1099+ }
1100+ else {
1101+ uint32_t intPart = (uint32_t)adsr->releasePhase;
1102+ float floatPart = adsr->releasePhase - intPart;
1103+ float secondValue;
1104+ if (adsr->releasePhase + 1.0f > adsr->buff_sizeMinusOne)
1105+ {
1106+ secondValue = 0.0f;
1107+ }
1108+ else
1109+ {
1110+ secondValue = adsr->exp_buff[(uint32_t)((adsr->releasePhase)+1)];
1111+ }
1112+ adsr->next = adsr->releasePeak * (LEAF_interpolation_linear(adsr->exp_buff[intPart], secondValue, floatPart)); // do interpolation !
1113+ }
11271114
1128− // Increment envelope release;
1129− adsr->releasePhase += adsr->releaseInc;
1115+ // Increment envelope release;
1116+ adsr->releasePhase += adsr->releaseInc;
1117+ break;
11301118 }
1131−
1132−
11331119 return adsr->next;
11341120 }
11351121
@@ -1137,87 +1123,77 @@ float tADSR4_tickNoInterp(tADSR4* const adsrenv) · 1 unmodified line
11371123 {
11381124 _tADSR4* adsr = *adsrenv;
11391125
1140−
1141− if (adsr->inRamp)
1126+ switch (adsr->whichStage)
11421127 {
1143− if (adsr->rampPhase > adsr->buff_sizeMinusOne)
1144− {
1145− adsr->inRamp = OFALSE;
1146− adsr->inAttack = OTRUE;
1147− adsr->next = 0.0f;
1148− }
1149− else
1150− {
1151− adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)(adsr->rampPhase)];
1152− }
1153−
1154− adsr->rampPhase += adsr->rampInc;
1155− }
1128+ case env_ramp:
1129+ if (adsr->rampPhase > adsr->buff_sizeMinusOne)
1130+ {
1131+ adsr->whichStage = env_attack;
1132+ adsr->next = 0.0f;
1133+ }
1134+ else
1135+ {
1136+ adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase];
1137+ }
11561138
1157− if (adsr->inAttack)
1158− {
1139+ adsr->rampPhase += adsr->rampInc;
1140+ break;
11591141
1160− // If attack done, time to turn around.
1161− if (adsr->attackPhase > adsr->buff_sizeMinusOne)
1162− {
1163− adsr->inDecay = OTRUE;
1164− adsr->inAttack = OFALSE;
1165− adsr->next = adsr->gain;
1166− }
1167− else
1168− {
1169− // do interpolation !
1170− adsr->next = adsr->gain * (1.0f - adsr->exp_buff[(uint32_t)(adsr->attackPhase)]); // inverted and backwards to get proper rising exponential shape/perception
1171− }
11721142
1173− // Increment ADSR attack.
1174− adsr->attackPhase += adsr->attackInc;
1143+ case env_attack:
11751144
1176− }
1145+ // If attack done, time to turn around.
1146+ if (adsr->attackPhase > adsr->buff_sizeMinusOne)
1147+ {
1148+ adsr->whichStage = env_decay;
1149+ adsr->next = adsr->gain;
1150+ }
1151+ else
1152+ {
1153+ adsr->next = adsr->gain * (1.0f - adsr->exp_buff[(uint32_t)adsr->attackPhase]); // inverted and backwards to get proper rising exponential shape/perception
1154+ }
11771155
1178− if (adsr->inDecay)
1179− {
1156+ // Increment ADSR attack.
1157+ adsr->attackPhase += adsr->attackInc;
1158+ break;
11801159
1181− // If decay done, sustain.
1182− if (adsr->decayPhase > adsr->buff_sizeMinusOne)
1183− {
1184− adsr->inDecay = OFALSE;
1185− adsr->inSustain = OTRUE;
1186− adsr->next = adsr->gain * adsr->sustain;
1187− }
1160+ case env_decay:
11881161
1189− else
1190− {
1191− adsr->next = (adsr->gain * (adsr->sustain + ((adsr->exp_buff[(uint32_t)(adsr->decayPhase)]) * (1.0f - adsr->sustain)))) * adsr->leakFactor; // do interpolation !
1192− }
1162+ // If decay done, sustain.
1163+ if (adsr->decayPhase > adsr->buff_sizeMinusOne)
1164+ {
1165+ adsr->whichStage = env_sustain;
1166+ adsr->next = adsr->gain * adsr->sustain;
1167+ }
11931168
1194− // Increment ADSR decay.
1195− adsr->decayPhase += adsr->decayInc;
1196− }
1169+ else
1170+ {
1171+ adsr->next = (adsr->gain * (adsr->sustain + (adsr->exp_buff[(uint32_t)adsr->decayPhase] * (1.0f - adsr->sustain)))) * adsr->leakFactor;
1172+ }
11971173
1198− if (adsr->inSustain)
1199− {
1200− adsr->next = adsr->next * adsr->leakFactor;
1201− }
1174+ // Increment ADSR decay.
1175+ adsr->decayPhase += adsr->decayInc;
1176+ break;
12021177
1203− if (adsr->inRelease)
1204− {
1205− // If release done, finish.
1206− if (adsr->releasePhase > adsr->buff_sizeMinusOne)
1207− {
1208− adsr->inRelease = OFALSE;
1209− adsr->next = 0.0f;
1210− }
1211− else {
1178+ case env_sustain:
1179+ adsr->next = adsr->next * adsr->leakFactor;
1180+ break;
12121181
1213− adsr->next = adsr->releasePeak * (adsr->exp_buff[(uint32_t)(adsr->releasePhase)]); // do interpolation !
1214− }
1182+ case env_release:
1183+ // If release done, finish.
1184+ if (adsr->releasePhase > adsr->buff_sizeMinusOne)
1185+ {
1186+ adsr->whichStage = env_idle;
1187+ adsr->next = 0.0f;
1188+ }
1189+ else {
1190+ adsr->next = adsr->releasePeak * adsr->exp_buff[(uint32_t)adsr->releasePhase];
1191+ }
12151192
1216− // Increment envelope release;
1217− adsr->releasePhase += adsr->releaseInc;
1193+ // Increment envelope release;
1194+ adsr->releasePhase += adsr->releaseInc;
1195+ break;
12181196 }
1219−
1220−
12211197 return adsr->next;
12221198 }
12231199
LEAF/Src/leaf-midi.c+126−22
@@ -682,7 +682,8 @@ int tPoly_isOn(tPoly* const polyh, uint8_t voice) · 681 unmodified lines
682682
683683
684684
685−//tSimplePoly = more efficient implementation without ramps and glide
685+
686+//tSimplePoly = much more efficient implementation without ramps and glide
686687
687688
688689 // SIMPLE POLY
@@ -709,7 +710,8 @@ void tSimplePoly_initToPool (tSimplePoly* const polyh, int maxNumV · 20 unmodified lines
709710 poly->notes[i][0] = -1;
710711 poly->notes[i][1] = 0;
711712 }
712−
713+ poly->stealing_on = 1;
714+ poly->recover_stolen = 1;
713715 poly->voices = (int**) mpool_alloc(sizeof(int*) * poly->maxNumVoices, m);
714716
715717 for (int i = 0; i < poly->maxNumVoices; ++i)
@@ -743,13 +745,11 @@ int tSimplePoly_noteOn(tSimplePoly* const polyh, int note, uint8_t vel) · 27 unmodified lines
743745 if (tStack_contains(&poly->stack, note) >= 0) return -1;
744746 else
745747 {
746− tStack_add(&poly->stack, note);
747−
748748 alteredVoice = -1;
749749 oBool found = OFALSE;
750750 for (int i = 0; i < poly->numVoices; i++)
751751 {
752− if (poly->voices[i][0] < 0) // if inactive voice, give this note to voice
752+ if (poly->voices[i][0] == -1) // if inactive voice, give this note to voice
753753 {
754754
755755 found = OTRUE;
@@ -757,15 +757,37 @@ int tSimplePoly_noteOn(tSimplePoly* const polyh, int note, uint8_t vel) · 1 unmodified line
757757 poly->voices[i][0] = note;
758758 poly->voices[i][1] = vel;
759759 poly->notes[note][0] = i;
760−
760+ poly->notes[note][1] = vel;
761761 poly->voices[i][2] = note; // voices[i][2] is the output midi note, (avoiding the -1 when a voice is inactive)
762762
763763 alteredVoice = i;
764+ tStack_add(&poly->stack, note);
764765 break;
765766 }
766767 }
768+ if (!found)
769+ {
770+ //second preference is grabbing one that is in release phase but not finished sounding yet
771+ for (int i = 0 ; i < poly->numVoices; i++)
772+ {
773+ if (poly->voices[i][0] == -2) // if voice is released but still sounding, take over this voice
774+ {
767775
768− if (!found) //steal
776+ found = OTRUE;
777+
778+ poly->voices[i][0] = note;
779+ poly->voices[i][1] = vel;
780+ poly->notes[note][0] = i;
781+ poly->notes[note][1] = vel;
782+ poly->voices[i][2] = note; // voices[i][2] is the output midi note, (avoiding the -1 when a voice is inactive)
783+
784+ alteredVoice = i;
785+ tStack_add(&poly->stack, note);
786+ break;
787+ }
788+ }
789+ }
790+ if ((!found) && (poly->stealing_on)) //steal
769791 {
770792 for (int j = tStack_getSize(&poly->stack) - 1; j >= 0; j--)
771793 {
@@ -776,14 +798,14 @@ int tSimplePoly_noteOn(tSimplePoly* const polyh, int note, uint8_t vel) · 4 unmodified lines
776798 oldNote = poly->voices[whichVoice][0];
777799 poly->voices[whichVoice][0] = note;
778800 poly->voices[whichVoice][1] = vel;
779− poly->notes[oldNote][0] = -1; //mark the stolen voice as inactive (in the second dimension of the notes array)
801+ poly->notes[oldNote][0] = -3; //mark the stolen voice as stolen (in the second dimension of the notes array)
780802 poly->notes[note][0] = whichVoice;
781803 poly->notes[note][1] = vel;
782804
783805 poly->voices[whichVoice][2] = note;
784806
785807 alteredVoice = whichVoice;
786−
808+ tStack_add(&poly->stack, note);
787809 break;
788810 }
789811 }
@@ -794,17 +816,14 @@ int tSimplePoly_noteOn(tSimplePoly* const polyh, int note, uint8_t vel) · 4 unmodified lines
794816
795817
796818
797−
798819 int tSimplePoly_noteOff(tSimplePoly* const polyh, uint8_t note)
799820 {
800821 _tSimplePoly* poly = *polyh;
801822 int16_t noteToTest = -1;
802823
803−
804824 tStack_remove(&poly->stack, note);
805825 poly->notes[note][0] = -1;
806826
807−
808827 int deactivatedVoice = -1;
809828 for (int i = 0; i < poly->maxNumVoices; i++)
810829 {
@@ -817,22 +836,100 @@ int tSimplePoly_noteOff(tSimplePoly* const polyh, uint8_t note) · 6 unmodified lines
817836 }
818837 }
819838
820− //grab old notes off the stack if there are notes waiting to replace the free voice
821− if (deactivatedVoice >= 0)
839+ if (poly->recover_stolen)
822840 {
823− for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
841+ //grab old notes off the stack if there are notes waiting to replace the free voice
842+ if (deactivatedVoice >= 0)
824843 {
825− noteToTest = tStack_get(&poly->stack, j);
844+ for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
845+ {
846+ noteToTest = tStack_get(&poly->stack, j);
826847
827− if (poly->notes[noteToTest][0] < 0) //if there is a stolen note waiting (marked inactive but on the stack)
848+ if (poly->notes[noteToTest][0] == -3) //if there is a stolen note waiting (marked inactive but on the stack)
849+ {
850+ poly->voices[deactivatedVoice][0] = noteToTest; //set the newly free voice to use the old stolen note
851+ poly->voices[deactivatedVoice][1] = poly->notes[noteToTest][1]; // set the velocity of the voice to be the velocity of that note
852+ poly->voices[deactivatedVoice][2] = noteToTest;
853+ poly->notes[noteToTest][0] = deactivatedVoice; //mark that it is no longer stolen and is now active
854+ return -1;
855+ }
856+ }
857+ }
858+ }
859+ return deactivatedVoice;
860+}
861+
862+
863+void tSimplePoly_deactivateVoice(tSimplePoly* const polyh, uint8_t voice)
864+{
865+ _tSimplePoly* poly = *polyh;
866+
867+ if (poly->voices[voice][0] == -2) //only do this if the voice is waiting for deactivation (not already reassigned while waiting)
868+ {
869+ poly->voices[voice][0] = -1;
870+ poly->voices[voice][1] = 0;
871+ if (poly->recover_stolen)
872+ {
873+ //grab old notes off the stack if there are notes waiting to replace the free voice
874+ for (int j = 0; j < tStack_getSize(&poly->stack); ++j)
828875 {
829− poly->voices[deactivatedVoice][0] = noteToTest; //set the newly free voice to use the old stolen note
830− poly->voices[deactivatedVoice][1] = poly->notes[noteToTest][1]; // set the velocity of the voice to be the velocity of that note
831− poly->voices[deactivatedVoice][2] = noteToTest;
832− poly->notes[noteToTest][0] = deactivatedVoice; //mark that it is no longer stolen and is now active
833− return -1;
876+ noteToTest = tStack_get(&poly->stack, j);
877+
878+ if (poly->notes[noteToTest][0] == -3) //if there is a stolen note waiting (marked inactive but on the stack)
879+ {
880+ poly->voices[voice][0] = noteToTest; //set the newly free voice to use the old stolen note
881+ poly->voices[voice][1] = poly->notes[noteToTest][1]; // set the velocity of the voice to be the velocity of that note
882+ poly->voices[voice][2] = noteToTest;
883+ poly->notes[noteToTest][0] = voice; //mark that it is no longer stolen and is now active
884+ }
885+ }
886+ }
887+ }
888+}
889+
890+int tSimplePoly_findVoiceAssignedToNote(tSimplePoly* const polyh, uint8_t note)
891+{
892+ _tSimplePoly* poly = *polyh;
893+
894+
895+ int voiceWithThatNote = -1;
896+ for (int i = 0; i < poly->maxNumVoices; i++)
897+ {
898+ if (poly->voices[i][0] == note)
899+ {
900+ voiceWithThatNote = i;
901+ break;
902+ }
903+ }
904+ return voiceWithThatNote;
905+}
906+
907+
908+int tSimplePoly_markPendingNoteOff(tSimplePoly* const polyh, uint8_t note)
909+{
910+ _tSimplePoly* poly = *polyh;
911+ int deactivatedVoice = -1;
912+
913+ if (tStack_remove(&poly->stack, note))
914+
915+ {
916+
917+ poly->notes[note][0] = -2;
918+
919+
920+
921+ for (int i = 0; i < poly->maxNumVoices; i++)
922+ {
923+ if (poly->voices[i][0] == note)
924+ {
925+ poly->voices[i][0] = -2;
926+ poly->voices[i][1] = 0;
927+ deactivatedVoice = i;
928+ break;
834929 }
835930 }
931+
932+
836933 }
837934 return deactivatedVoice;
838935 }
@@ -863,6 +960,13 @@ int tSimplePoly_getPitch(tSimplePoly* const polyh, uint8_t voice) · 24 unmodified lines
863960 return poly->voices[voice][2];
864961 }
865962
963+//this one returns negative one if the voice is inactive
964+int tSimplePoly_getPitchAndCheckActive(tSimplePoly* const polyh, uint8_t voice)
965+{
966+ _tSimplePoly* poly = *polyh;
967+ return poly->voices[voice][0];
968+}
969+
866970 int tSimplePoly_getVelocity(tSimplePoly* const polyh, uint8_t voice)
867971 {
868972 _tSimplePoly* poly = *polyh;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t