shithub: leaf

Download patch

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;
+}