ref: a7eedc627b937332dc96ae338b6373555a0cd2e5
parent: fe679cd98d991aa2a306a4147d8e41c97e909702
author: spiricom <jeff@snyderphonics.com>
date: Mon May 18 08:20:29 EDT 2020
added tSimplePoly
binary files a/.DS_Store b/.DS_Store differ
binary files a/LEAF/.DS_Store b/LEAF/.DS_Store differ
--- a/LEAF/Inc/leaf-midi.h
+++ b/LEAF/Inc/leaf-midi.h
@@ -362,6 +362,134 @@
/*! @} */
//==============================================================================
+
+
+ // 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
+ {
+ tStack stack;
+
+ int numVoices;
+ int maxNumVoices;
+ int** voices;
+
+ int notes[128][2];
+ } _tSimplePoly;
+
+ typedef _tSimplePoly* tSimplePoly;
+
+ //! Initialize a tPoly to the default LEAF mempool.
+ /*!
+ @param poly A pointer to the tPoly to be initialized.
+ @param maxNumVoices The maximum number of voices this tPoly can handle at once.
+ */
+ void tSimplePoly_init (tSimplePoly* const poly, int maxNumVoices);
+
+
+ //! Free a tPoly from the default LEAF mempool.
+ /*!
+ @param poly A pointer to the tPoly to be freed.
+ */
+ void tSimplePoly_free (tSimplePoly* const poly);
+
+
+ //! Initialize a tPoly to a specified mempool.
+ /*!
+ @param poly A pointer to the tPoly to be initialized.
+ @param pool A pointer to the tMempool to which the tPoly should be initialized.
+ */
+ void tSimplePoly_initToPool (tSimplePoly* const poly, int maxNumVoices, tMempool* const pool);
+
+
+ //! Free a tPoly from a specified mempool.
+ /*!
+ @param poly A pointer to the tPoly to be freed.
+ @param pool A pointer to the tMempool from which the tPoly should be freed.
+ */
+ void tSimplePoly_freeFromPool (tSimplePoly* const poly, tMempool* const pool);
+
+ //! Add a note with a given velocity to the poly handler.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @param note The MIDI note number to add.
+ @param vel The MIDI velocity of the note to add.
+ @return The voice that will play the note.
+ */
+ int tSimplePoly_noteOn (tSimplePoly* const poly, int note, uint8_t vel);
+
+
+ //! Remove a note from the poly handler.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @param note The MIDI note number to remove.
+ @return The voice that was playing the removed note.
+ */
+ int tSimplePoly_noteOff (tSimplePoly* const poly, uint8_t note);
+
+
+ //! Set the number of voices available to play notes.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @param numVoices The new number of available voices. Cannot be greater than the max number voices given in tPoly_init().
+ */
+ void tSimplePoly_setNumVoices (tSimplePoly* const poly, uint8_t numVoices);
+
+ //! Set whether pitch glide over note changes in voices is active.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @param isActive Whether pitch glide should be active or not.
+ */
+
+ //! Get the current number of voices available to play notes.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @return The current number of voices available to play notes.
+ */
+ int tSimplePoly_getNumVoices (tSimplePoly* const poly);
+
+ //! Get the number of voices currently playing notes.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @return The number of voices currently playing notes.
+ */
+ int tSimplePoly_getNumActiveVoices (tSimplePoly* const poly);
+
+ //! Get the current MIDI note number of a given voice.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @param voice The voice to get the MIDI note number of.
+ @return The MIDI note number of the given voice.
+ */
+
+ int tSimplePoly_getPitch (tSimplePoly* const poly, uint8_t voice);
+
+ //! Get the current MIDI velocity of a given voice.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @param voice The voice to get the MIDI velocity of.
+ @return The current MIDI velocity of the given voice.
+ */
+ int tSimplePoly_getVelocity (tSimplePoly* const poly, uint8_t voice);
+
+
+ //! Get the current play state of a given voice.
+ /*!
+ @param poly A pointer to the relevant tPoly.
+ @param voice The voice to get the state of.
+ @return The current play state of the given voice.
+ */
+ int tSimplePoly_isOn (tSimplePoly* const poly, uint8_t voice);
+
+ /*! @} */
+ //==============================================================================
#ifdef __cplusplus
}
--- a/LEAF/Src/leaf-effects.c
+++ b/LEAF/Src/leaf-effects.c
@@ -1374,7 +1374,7 @@
{
_tRetune* r = *rt;
- return r->inputPeriod;
+ return (r->inputPeriod * leaf.invSampleRate);
}
float tRetune_getInputFreq(tRetune* const rt)
@@ -1381,7 +1381,7 @@
{
_tRetune* r = *rt;
- return 1.0f/r->inputPeriod;
+ return 1.0f/(r->inputPeriod * leaf.invSampleRate);
}
//============================================================================================================
--- a/LEAF/Src/leaf-midi.c
+++ b/LEAF/Src/leaf-midi.c
@@ -679,3 +679,198 @@
_tPoly* poly = *polyh;
return (poly->voices[voice][0] > 0) ? 1 : 0;
}
+
+
+
+//tSimplePoly = more efficient implementation without ramps and glide
+
+
+// SIMPLE POLY
+void tSimplePoly_init(tSimplePoly* const polyh, int maxNumVoices)
+{
+ tSimplePoly_initToPool(polyh, maxNumVoices, &leaf.mempool);
+}
+
+void tSimplePoly_free(tSimplePoly* const polyh)
+{
+ tSimplePoly_freeFromPool(polyh, &leaf.mempool);
+}
+
+void tSimplePoly_initToPool (tSimplePoly* const polyh, int maxNumVoices, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tSimplePoly* poly = *polyh = (_tSimplePoly*) mpool_alloc(sizeof(_tSimplePoly), m);
+
+ poly->numVoices = maxNumVoices;
+ poly->maxNumVoices = maxNumVoices;
+
+ for (int i = 0; i < 128; i++)
+ {
+ poly->notes[i][0] = -1;
+ poly->notes[i][1] = 0;
+ }
+
+ poly->voices = (int**) mpool_alloc(sizeof(int*) * poly->maxNumVoices, m);
+
+ for (int i = 0; i < poly->maxNumVoices; ++i)
+ {
+ poly->voices[i] = (int*) mpool_alloc(sizeof(int) * 3, m);
+ poly->voices[i][0] = -1;
+ }
+ tStack_initToPool(&poly->stack, mp);
+
+}
+
+void tSimplePoly_freeFromPool (tSimplePoly* const polyh, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tSimplePoly* poly = *polyh;
+
+ for (int i = 0; i < poly->maxNumVoices; i++)
+ {
+ mpool_free(poly->voices[i], m);
+ }
+ tStack_freeFromPool(&poly->stack, mp);
+ mpool_free(poly->voices, m);
+ mpool_free(poly, m);
+}
+
+int tSimplePoly_noteOn(tSimplePoly* const polyh, int note, uint8_t vel)
+{
+ _tSimplePoly* poly = *polyh;
+ int whichVoice, whichNote, oldNote, alteredVoice;
+ // if not in keymap or already on stack, dont do anything. else, add that note.
+ 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
+ {
+
+ found = OTRUE;
+
+ poly->voices[i][0] = note;
+ poly->voices[i][1] = vel;
+ poly->notes[note][0] = i;
+
+ poly->voices[i][2] = note; // voices[i][2] is the output midi note, (avoiding the -1 when a voice is inactive)
+
+ alteredVoice = i;
+ break;
+ }
+ }
+
+ if (!found) //steal
+ {
+ for (int j = tStack_getSize(&poly->stack) - 1; j >= 0; j--)
+ {
+ whichNote = tStack_get(&poly->stack, j);
+ whichVoice = poly->notes[whichNote][0];
+ if (whichVoice >= 0)
+ {
+ 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[note][0] = whichVoice;
+ poly->notes[note][1] = vel;
+
+ poly->voices[whichVoice][2] = note;
+
+ alteredVoice = whichVoice;
+
+ break;
+ }
+ }
+ }
+ return alteredVoice;
+ }
+}
+
+
+
+
+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++)
+ {
+ if (poly->voices[i][0] == note)
+ {
+ poly->voices[i][0] = -1;
+ poly->voices[i][1] = 0;
+ deactivatedVoice = i;
+ break;
+ }
+ }
+
+ //grab old notes off the stack if there are notes waiting to replace the free voice
+ if (deactivatedVoice >= 0)
+ {
+ 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)
+ {
+ 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_setNumVoices(tSimplePoly* const polyh, uint8_t numVoices)
+{
+ _tSimplePoly* poly = *polyh;
+ poly->numVoices = (numVoices > poly->maxNumVoices) ? poly->maxNumVoices : numVoices;
+}
+
+
+int tSimplePoly_getNumVoices(tSimplePoly* const polyh)
+{
+ _tSimplePoly* poly = *polyh;
+ return poly->numVoices;
+}
+
+int tSimplePoly_getNumActiveVoices(tSimplePoly* const polyh)
+{
+ _tSimplePoly* poly = *polyh;
+ return LEAF_clip(0, tStack_getSize(&poly->stack), poly->numVoices);
+}
+
+
+int tSimplePoly_getPitch(tSimplePoly* const polyh, uint8_t voice)
+{
+ _tSimplePoly* poly = *polyh;
+ return poly->voices[voice][2];
+}
+
+int tSimplePoly_getVelocity(tSimplePoly* const polyh, uint8_t voice)
+{
+ _tSimplePoly* poly = *polyh;
+ return poly->voices[voice][1];
+}
+
+int tSimplePoly_isOn(tSimplePoly* const polyh, uint8_t voice)
+{
+ _tSimplePoly* poly = *polyh;
+ return (poly->voices[voice][0] > 0) ? 1 : 0;
+}