From d3c2f2f3cfdb2b207accefc54f7f4efbebe275c1 Mon Sep 17 00:00:00 2001
From: moon2 <moon2protonmail@protonmail.com>
Date: Thu, 22 Jun 2023 22:42:05 +0200
Subject: [PATCH] bl00mbox: new synth backend split off from audio.c

---
 README.md                                     |   2 -
 components/badge23/CMakeLists.txt             |   2 +-
 components/badge23/audio.c                    | 129 +++--------
 components/badge23/espan.c                    |   3 +
 components/badge23/include/badge23/audio.h    |  18 +-
 components/badge23/include/badge23/synth.h    |  42 ----
 components/badge23/synth.c                    | 195 -----------------
 components/bl00mbox/CMakeLists.txt            |  10 +
 components/bl00mbox/README.md                 |   7 +
 components/bl00mbox/bl00mbox.c                | 118 ++++++++++
 .../bl00mbox/buds/tinysynth/tinysynth.c       | 207 ++++++++++++++++++
 .../bl00mbox/buds/tinysynth/tinysynth.h       |  71 ++++++
 components/bl00mbox/idf_component.yml         |   7 +
 components/bl00mbox/include/bl00mbox.h        |  10 +
 components/bl00mbox/include/bud_registry.h    |  11 +
 components/bl00mbox/include/radspa.h          |  28 +++
 components/st3m/CMakeLists.txt                |   1 +
 python_payload/apps/demo_sparabo.py           |   6 +-
 python_payload/apps/flow3r/menu_crazysynth.py |   6 +-
 python_payload/apps/flow3r/menu_tinysynth.py  |   6 +-
 python_payload/apps/harmonic_demo.py          |  36 ++-
 python_payload/apps/melodic_demo.py           |   7 +-
 usermodule/micropython.cmake                  |   2 +-
 usermodule/{mp_synth.c => mp_bl00mbox.c}      |  85 ++++---
 usermodule/mp_hardware.c                      |  27 ---
 25 files changed, 614 insertions(+), 422 deletions(-)
 delete mode 100644 components/badge23/include/badge23/synth.h
 delete mode 100644 components/badge23/synth.c
 create mode 100644 components/bl00mbox/CMakeLists.txt
 create mode 100644 components/bl00mbox/README.md
 create mode 100644 components/bl00mbox/bl00mbox.c
 create mode 100644 components/bl00mbox/buds/tinysynth/tinysynth.c
 create mode 100644 components/bl00mbox/buds/tinysynth/tinysynth.h
 create mode 100644 components/bl00mbox/idf_component.yml
 create mode 100644 components/bl00mbox/include/bl00mbox.h
 create mode 100644 components/bl00mbox/include/bud_registry.h
 create mode 100644 components/bl00mbox/include/radspa.h
 rename usermodule/{mp_synth.c => mp_bl00mbox.c} (58%)

diff --git a/README.md b/README.md
index a79656fd01..be712ef99d 100644
--- a/README.md
+++ b/README.md
@@ -144,8 +144,6 @@ C entry point, called by^: `os_app_main()` in components/badge23/espan.c
 
 Register new C files for compilation: add to components/badge23/CMakelists.txt
 
-Change output volume in the `set_global_vol_dB(int8_t)` call; -90 for mute
-
 ### Debugging
 
 The badge is currently configured to run in HW USB UART/JTAG mode (vs. using TinyUSB and 'software' CDC/whatever using the generic OTG peripheral).
diff --git a/components/badge23/CMakeLists.txt b/components/badge23/CMakeLists.txt
index 23ad0f3837..adeb53cd8e 100644
--- a/components/badge23/CMakeLists.txt
+++ b/components/badge23/CMakeLists.txt
@@ -5,7 +5,6 @@ idf_component_register(
         captouch.c
         espan.c
         leds.c
-        synth.c
         spio.c
     INCLUDE_DIRS
         include
@@ -13,4 +12,5 @@ idf_component_register(
         flow3r_bsp
         st3m
         espressif__led_strip
+        bl00mbox
 )
diff --git a/components/badge23/audio.c b/components/badge23/audio.c
index e63f8acead..c94a650423 100644
--- a/components/badge23/audio.c
+++ b/components/badge23/audio.c
@@ -1,5 +1,4 @@
 #include "badge23/audio.h"
-#include "badge23/synth.h" 
 #include "badge23/lock.h"
 
 #include "st3m_scope.h"
@@ -580,85 +579,18 @@ void audio_update_jacksense(){
 #endif
 }
 
-typedef struct _audio_source_t{
-    void * render_data;
-    float (* render_function)(void *);
-    uint16_t index;
-    struct _audio_source_t * next;
-} audio_source_t;
-
-static audio_source_t * _audio_sources = NULL;
-
-uint16_t add_audio_source(void * render_data, void * render_function){
-    //construct audio source struct
-    audio_source_t * src = malloc(sizeof(audio_source_t));
-    if(src == NULL) return;
-    src->render_data = render_data;
-    src->render_function = render_function;
-    src->next = NULL;
-    src->index = 0;
-
-    //handle empty list special case
-    if(_audio_sources == NULL){
-        _audio_sources = src;
-        return 0; //only nonempty lists from here on out!
-    }
-
-    //searching for lowest unused index
-    audio_source_t * index_source = _audio_sources;
-    while(1){
-        if(src->index == (index_source->index)){
-            src->index++; //someone else has index already, try next
-            index_source = _audio_sources; //start whole list for new index
-        } else {
-            index_source = index_source->next;
-        }
-        if(index_source == NULL){ //traversed the entire list
-            break;
-        }
-    }
 
-    audio_source_t * audio_source = _audio_sources;
-    //append new source to linked list
-    while(audio_source != NULL){
-        if(audio_source->next == NULL){
-            audio_source->next = src;
-            break;
-        } else {
-        audio_source = audio_source->next;
-        }
+void audio_player_function_dummy(int16_t * rx, int16_t * tx, uint16_t len){
+    for(uint16_t i = 0; i < len; i++){
+        tx[i] = 0;
     }
-    return src->index;
 }
 
-void remove_audio_source(uint16_t index){
-    audio_source_t * audio_source = _audio_sources;
-    audio_source_t * start_gap = NULL;
-
-    while(audio_source != NULL){
-        if(index == audio_source->index){
-            if(start_gap == NULL){
-                _audio_sources = audio_source->next;
-            } else {
-                start_gap->next = audio_source->next;
-            }
-            vTaskDelay(20 / portTICK_PERIOD_MS); //give other tasks time to stop using
-            free(audio_source); //terrible hack tbh
-            break;
-        }
-        start_gap = audio_source;
-        audio_source = audio_source->next;
-    }
-}
+static audio_player_function_type audio_player_function = audio_player_function_dummy;
 
-uint16_t count_audio_sources(){
-    uint16_t ret = 0;
-    audio_source_t * audio_source = _audio_sources;
-    while(audio_source != NULL){
-        audio_source = audio_source->next;
-        ret++;
-    }
-    return ret;
+void audio_set_player_function(audio_player_function_type fun){
+    // ...wonder how unsafe this is
+    audio_player_function = fun;
 }
 
 static void _audio_init(void) {
@@ -669,6 +601,10 @@ static void _audio_init(void) {
     audio_update_jacksense();
     TaskHandle_t handle;
     xTaskCreate(&audio_player_task, "Audio player", 3000, NULL, configMAX_PRIORITIES - 1, &handle);
+    audio_player_function = audio_player_function_dummy;
+}
+
+static void _audio_deinit(void){
 }
 
 float audio_input_thru_set_volume_dB(float vol_dB){
@@ -690,47 +626,36 @@ static void audio_player_task(void* arg) {
     size_t count;
 
     while(true) {
+        count = 0;
 
-        for(int i = 0; i < (DMA_BUFFER_SIZE * 2); i += 2){
-            float acc = 0;
-            int32_t sample = 0;
-            audio_source_t * audio_source = _audio_sources;
-            while(audio_source != NULL){
-                acc += (*(audio_source->render_function))(audio_source->render_data);
-                audio_source = audio_source->next;
-            }
-            st3m_scope_write((int16_t) (1600. * acc));
+#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P6)
+        count = 0;
+        i2s_read(I2S_PORT, buffer_rx, sizeof(buffer_rx), &count, 1000);
+        if (count != sizeof(buffer_rx)) {
+            printf("i2s_read_bytes: count (%d) != length (%d)\n", count, sizeof(buffer_rx));
+            abort();
+        }
+#endif
 
-            acc /= 10;
+        (* audio_player_function)(buffer_rx, buffer_tx, DMA_BUFFER_SIZE*2);
+
+        for(int i = 0; i < (DMA_BUFFER_SIZE * 2); i += 2){
+            int32_t acc = buffer_tx[i];
 
-            sample += 32767 * acc;
-            sample = (sample * software_volume) >> 15;
+            acc = (acc * software_volume) >> 15;
 
-            if(sample > 32767) sample = 32767;
-            if(sample < -32767) sample = -32767;
-            buffer_tx[i] = sample;
-            buffer_tx[i+1] = sample;
             if(!input_thru_mute){
-                buffer_tx[i] += (((int32_t) buffer_rx[i]) * input_thru_vol_int) >> 15;
-                buffer_tx[i+1] += (((int32_t) buffer_rx[i+1]) * input_thru_vol_int) >> 15;
+                acc += (((int32_t) buffer_rx[i]) * input_thru_vol_int) >> 15;
             }
+            buffer_tx[i] = acc;
         }
 
-        count = 0;
         i2s_write(I2S_PORT, buffer_tx, sizeof(buffer_tx), &count, 1000);
         if (count != sizeof(buffer_tx)) {
             printf("i2s_write_bytes: count (%d) != length (%d)\n", count, sizeof(buffer_tx));
             abort();
         }
 
-#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P6)
-        count = 0;
-        i2s_read(I2S_PORT, buffer_rx, sizeof(buffer_rx), &count, 1000);
-        if (count != sizeof(buffer_rx)) {
-            printf("i2s_read_bytes: count (%d) != length (%d)\n", count, sizeof(buffer_rx));
-            abort();
-        }
-#endif
     }
 }
 
diff --git a/components/badge23/espan.c b/components/badge23/espan.c
index 5e51f36001..a261ca19b8 100644
--- a/components/badge23/espan.c
+++ b/components/badge23/espan.c
@@ -8,6 +8,8 @@
 #include "st3m_gfx.h"
 #include "st3m_fs.h"
 
+#include "bl00mbox.h"
+
 #include "esp_log.h"
 #include "driver/i2c.h"
 #include "driver/spi_master.h"
@@ -93,6 +95,7 @@ void badge23_main(void)
     init_buttons();
     captouch_init();
     spio_badge_link_disable(255);
+    audio_set_player_function(bl00mbox_player_function);
 
     captouch_force_calibration();
 
diff --git a/components/badge23/include/badge23/audio.h b/components/badge23/include/badge23/audio.h
index 06f52ee282..18dd2d9928 100644
--- a/components/badge23/include/badge23/audio.h
+++ b/components/badge23/include/badge23/audio.h
@@ -2,23 +2,31 @@
 #include <stdint.h>
 #include <stdbool.h>
 
-#define SAMPLE_RATE 16000
+#define SAMPLE_RATE 48000
 
 #define AUDIO_INPUT_SOURCE_NONE 0
 #define AUDIO_INPUT_SOURCE_LINE_IN 1
 #define AUDIO_INPUT_SOURCE_HEADSET_MIC 2
 #define AUDIO_INPUT_SOURCE_ONBOARD_MIC 3
 
+typedef void (* audio_player_function_type)(int16_t * tx, int16_t * rx, uint16_t len);
+
+/* The default audio task takes a function of prototype &audio_player_function_type,
+ * loops it and sets software volume/adds software thru. tx is the stereo zipped l/r
+ *output, rx is the stereo zipped input, each buffer the size of len.
+ */
+void audio_set_player_function(audio_player_function_type fun);
+
+/* Dummy for audio_set_player_function that just writes zeros to the output. Default state.
+ */
+void audio_player_function_dummy(int16_t * rx, int16_t * tx, uint16_t len);
+
 /* Initializes I2S bus, the audio task and required data structures.
  * Expects an initialized I2C bus, will fail ungracefully otherwise (TODO).
  * Requires the I2C lock.
  */
 void audio_init();
 
-uint16_t count_audio_sources();
-uint16_t add_audio_source(void * render_data, void * render_function);
-void remove_audio_source(uint16_t index);
-
 /* Polls hardware to check if headphones, headset or line in are plugged
  * into the 3.5mm jacks. If it detects a plug in the headphone jack, speakers
  * are automatically muted. There is no override for this at this moment.
diff --git a/components/badge23/include/badge23/synth.h b/components/badge23/include/badge23/synth.h
deleted file mode 100644
index cd52e28bd8..0000000000
--- a/components/badge23/include/badge23/synth.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#pragma once
-#include <stdint.h>
-#include <stdio.h>
-
-#define TRAD_OSC_DECAY_STEP          0.01
-#define TRAD_OSC_ATTACK_STEP          0.01
-#define TRAD_OSC_MIN_ATTACK_ENV          0.01
-#define TRAD_OSC_ATTACK_POP_BLOCK          16
-typedef struct {
-    //user variables
-    float       freq;           //in hertz, negative frequencies for linFM allowed
-    float       bend;
-    float       vol;            //output volume
-    float       env;
-    uint8_t     env_phase;      //0: off, 1: attack, 2: hold, 3: decay
-    uint8_t     skip_hold;
-    float       gate;           //below what volume the oscillator stops and returns 0
-    uint16_t    decay_steps;    //after how many sample rate steps the volume reduces
-                                //by factor TRAD_OSC_DECAY_STEP, set 0 for no decay
-    uint16_t    attack_steps;
-    uint8_t     waveform;       //0: sine, 1: fast sine, 2: tri, 3: saw,
-                                //4: square, 5: 33% pulse, 6: 25% pulse
-
-    //internal data storage, not for user access
-    float       counter;        //state of central sawtooth oscillator, [-1..1] typ.
-    uint16_t    env_counter;
-    int8_t      overflow_event; //set to -1 when counter underflows (below -1),
-                                //set to +1 when counter overflows (above 1)
-                                //not reset or used by anything so far
-    uint8_t     undersampling_counter;
-    uint16_t    noise_reg;
-} trad_osc_t;
-
-float run_trad_osc(trad_osc_t * osc);
-void trad_osc_set_freq_semitone(trad_osc_t * osc, float bend);
-void trad_osc_set_freq_Hz(trad_osc_t * osc, float freq);
-void trad_osc_set_waveform(trad_osc_t * osc, uint8_t waveform);
-void trad_osc_set_attack(trad_osc_t * osc, uint16_t attack);
-void trad_osc_set_decay(trad_osc_t * osc, uint16_t decay);
-void trad_env_stop(trad_osc_t * osc);
-void trad_env_fullstop(trad_osc_t * osc);
-void trad_env_start(trad_osc_t * osc);
diff --git a/components/badge23/synth.c b/components/badge23/synth.c
deleted file mode 100644
index a3ba968ece..0000000000
--- a/components/badge23/synth.c
+++ /dev/null
@@ -1,195 +0,0 @@
-#include "badge23/synth.h"
-#include "badge23/audio.h"
-#include <math.h>
-
-#define SYNTH_UNDERSAMPLING 1
-#define SYNTH_SAMPLE_RATE ((SAMPLE_RATE)/(SYNTH_UNDERSAMPLING))
-
-float waveshaper(uint8_t shape, float in);
-float nes_noise(uint16_t * reg, uint8_t mode, uint8_t run);
-
-void run_trad_env(trad_osc_t * osc){
-    switch(osc->env_phase){
-        case 0:
-            osc->env = 0; osc->counter = 0; osc->env_counter = 0;
-            break;
-        case 1:
-            if(osc->attack_steps){
-                if(osc->env == 0){
-                    osc->env = (TRAD_OSC_MIN_ATTACK_ENV);
-                } else {
-                    osc->env_counter++;
-                    if(osc->env_counter > osc->attack_steps){
-                        osc->env *= (1. + (TRAD_OSC_ATTACK_STEP));
-                        osc->env_counter = 0;
-                    }
-                }
-            } else {
-                osc->env += osc->vol/TRAD_OSC_ATTACK_POP_BLOCK;
-            }
-            if(osc->env > osc->vol){
-                osc->env_phase = 2;
-                osc->env = osc->vol;
-            }
-            break;
-        case 2:
-            osc->env = osc->vol;
-            osc->env_counter = 0;
-            if(osc->skip_hold) osc->env_phase = 3;
-            break;
-        case 3:
-            if(osc->decay_steps){
-                osc->env_counter++;
-                if(osc->env_counter > osc->decay_steps){
-                    osc->env *= (1. - (TRAD_OSC_DECAY_STEP));
-                    osc->env_counter = 0;
-                }
-                if(osc->env < osc->gate){
-                    osc->env_phase = 0; osc->env = 0; osc->counter = 0;
-                }
-            } else {
-                osc->env_phase = 0; osc->env = 0; osc->counter = 0;
-            }
-            break;
-    }
-}
-
-float run_trad_osc(trad_osc_t * osc){
-    static float ret = 0;
-    //osc->undersampling_counter = (osc->undersampling_counter+1) % SYNTH_UNDERSAMPLING;
-    //if(osc->undersampling_counter) return ret;
-
-    run_trad_env(osc);
-    if(!osc->env_phase) return 0;
-
-    //run core sawtooth
-    float freq = osc->freq * osc->bend;
-    if(freq > 10000) freq = 10000;
-    if(freq < -10000) freq = -10000;
-    if(freq != freq) freq = 0;
-    osc->counter += 2. * freq / ((float)(SYNTH_SAMPLE_RATE));
-    if(osc->counter != osc->counter){
-        printf("trad_osc counter is NaN");
-        abort();
-    }
-    while(osc->counter > 1.){
-        osc->counter -= 2.;
-        osc->overflow_event = 1;
-    }
-    while(osc->counter < -1.){
-        osc->counter += 2.;
-        osc->overflow_event = -1;
-    }
-
-    if(osc->waveform >= 7){
-        ret = nes_noise(&(osc->noise_reg), osc->waveform == 7, osc->overflow_event);
-        osc->overflow_event = 0;
-    } else {
-        //apply waveshaper
-        ret = waveshaper(osc->waveform, osc->counter);
-    }
-
-    //apply volume
-    ret *= osc->env;
-    return ret;
-}
-
-float nes_noise(uint16_t * reg, uint8_t mode, uint8_t run){
-    if(run) {
-        uint8_t fb = *reg;
-        if(mode){
-            fb = fb>>6;
-        } else {
-            fb = fb>>1;
-        }
-        fb = (fb ^ (*reg)) & 1;
-        *reg = (*reg >> 1);
-        *reg = (*reg) | (((uint16_t) fb) << 14);
-    }
-    return ((float) ((*reg) & 1)) * 2 - 1;
-}
-
-float waveshaper(uint8_t shape, float in){
-    //expects sawtooth input in [-1..1] range
-    switch(shape){
-        case 0: // TODO: implement proper sine
-            in = sin(in * 3.1415);
-            break;
-        case 1: //fast sine
-            in = waveshaper(2, in);
-            if(in > 0.){
-                in = 1. - in;
-                in *= in;
-                in = 1. - in;
-            } else {
-                in = 1. + in;
-                in *= in;
-                in = in - 1.;
-            }
-            break;
-        case 2: //triangle
-            in += 0.5;
-            if(in > 1.0) in -= 2;
-            if(in > 0.) in = -in;
-            in = (2. * in) + 1.;
-            break;
-        case 3: //sawtooth
-            break;
-        case 4: //square
-            if(in > 0){
-                in = 1.;
-            } else {
-                in = -1.;
-            }
-            break;
-        case 5: //33% pulse
-            if(in > 0.33){
-                in = 1.;
-            } else {
-                in = -1.;
-            }
-            break;
-        case 6: //25% pulse
-            if(in > 0.5){
-                in = 1.;
-            } else {
-                in = -1.;
-            }
-            break;
-    }
-    return in;
-}
-
-#define NAT_LOG_SEMITONE 0.05776226504666215
-
-void trad_osc_set_freq_semitone(trad_osc_t * osc, float bend){
-    osc->freq = 440. * exp(bend * NAT_LOG_SEMITONE);
-}
-
-void trad_osc_set_freq_Hz(trad_osc_t * osc, float freq){
-    osc->freq = freq;
-}
-
-void trad_osc_set_waveform(trad_osc_t * osc, uint8_t waveform){
-    osc->waveform = waveform;
-}
-
-void trad_osc_set_attack(trad_osc_t * osc, uint16_t attack){
-    osc->attack_steps = attack;
-}
-
-void trad_osc_set_decay(trad_osc_t * osc, uint16_t decay){
-    osc->decay_steps = decay;
-}
-
-void trad_env_stop(trad_osc_t * osc){
-    if(osc->env_phase) osc->env_phase = 3; 
-}
-
-void trad_env_fullstop(trad_osc_t * osc){
-    osc->env_phase = 0; //stop and skip decay phase
-}
-
-void trad_env_start(trad_osc_t * osc){
-    osc->env_phase = 1; //put into attack phase;
-}
diff --git a/components/bl00mbox/CMakeLists.txt b/components/bl00mbox/CMakeLists.txt
new file mode 100644
index 0000000000..d8322693d6
--- /dev/null
+++ b/components/bl00mbox/CMakeLists.txt
@@ -0,0 +1,10 @@
+idf_component_register(
+    SRCS
+        bl00mbox.c
+        buds/tinysynth/tinysynth.c
+    INCLUDE_DIRS
+        include
+        buds/tinysynth
+    REQUIRES
+        badge23
+)
diff --git a/components/bl00mbox/README.md b/components/bl00mbox/README.md
new file mode 100644
index 0000000000..9e4c8e90ab
--- /dev/null
+++ b/components/bl00mbox/README.md
@@ -0,0 +1,7 @@
+Welcome to bl00mbox!
+
+Plugins are called buds and provided in the radspa (wip) file format.
+To add your own plugin to the compiler add the .c files and also the
+directory of the .h files to ./CMakeLists.txt/.
+
+
diff --git a/components/bl00mbox/bl00mbox.c b/components/bl00mbox/bl00mbox.c
new file mode 100644
index 0000000000..9f03f12b8b
--- /dev/null
+++ b/components/bl00mbox/bl00mbox.c
@@ -0,0 +1,118 @@
+#include "badge23/audio.h"
+#include "st3m_scope.h"
+#include <freertos/FreeRTOS.h>
+#include <freertos/task.h>
+#include <freertos/queue.h>
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+typedef struct _audio_source_t{
+    void * render_data;
+    int16_t (* render_function)(void *);
+    uint16_t index;
+    struct _audio_source_t * next;
+} audio_source_t;
+
+static audio_source_t * _audio_sources = NULL;
+
+uint16_t bl00mbox_source_add(void * render_data, void * render_function){
+    //construct audio source struct
+    audio_source_t * src = malloc(sizeof(audio_source_t));
+    if(src == NULL) return;
+    src->render_data = render_data;
+    src->render_function = render_function;
+    src->next = NULL;
+    src->index = 0;
+
+    //handle empty list special case
+    if(_audio_sources == NULL){
+        _audio_sources = src;
+        return 0; //only nonempty lists from here on out!
+    }
+
+    //searching for lowest unused index
+    audio_source_t * index_source = _audio_sources;
+    while(1){
+        if(src->index == (index_source->index)){
+            src->index++; //someone else has index already, try next
+            index_source = _audio_sources; //start whole list for new index
+        } else {
+            index_source = index_source->next;
+        }
+        if(index_source == NULL){ //traversed the entire list
+            break;
+        }
+    }
+
+    audio_source_t * audio_source = _audio_sources;
+    //append new source to linked list
+    while(audio_source != NULL){
+        if(audio_source->next == NULL){
+            audio_source->next = src;
+            break;
+        } else {
+        audio_source = audio_source->next;
+        }
+    }
+    return src->index;
+}
+
+void bl00mbox_source_remove(uint16_t index){
+    audio_source_t * audio_source = _audio_sources;
+    audio_source_t * start_gap = NULL;
+
+    while(audio_source != NULL){
+        if(index == audio_source->index){
+            if(start_gap == NULL){
+                _audio_sources = audio_source->next;
+            } else {
+                start_gap->next = audio_source->next;
+            }
+            vTaskDelay(20 / portTICK_PERIOD_MS); //give other tasks time to stop using
+            free(audio_source); //terrible hack tbh
+            break;
+        }
+        start_gap = audio_source;
+        audio_source = audio_source->next;
+    }
+}
+
+uint16_t bl00mbox_sources_count(){
+    uint16_t ret = 0;
+    audio_source_t * audio_source = _audio_sources;
+    while(audio_source != NULL){
+        audio_source = audio_source->next;
+        ret++;
+    }
+    return ret;
+}
+
+void bl00mbox_player_function(int16_t * rx, int16_t * tx, uint16_t len){
+    int32_t acc[len];
+    memset(acc, 0, len * sizeof(float));
+    audio_source_t * audio_source = _audio_sources;
+    while(audio_source != NULL){
+        for(uint16_t i = 0; i < len; i += 2){
+            acc[i] += (*(audio_source->render_function))(audio_source->render_data);
+        }
+        audio_source = audio_source->next;
+    }
+
+    for(uint16_t i = 0; i < len; i += 2){
+        
+        st3m_scope_write((acc[i])>>4);
+
+        acc[i] = acc[i]>>3;
+
+        if(acc[i] > 32767) acc[i] = 32767;
+        if(acc[i] < -32767) acc[i] = -32767;
+        tx[i] = acc[i];
+        tx[i+1] = acc[i];
+    }
+}
+
+void bl00mbox_init(){
+    audio_set_player_function(bl00mbox_player_function);
+}
diff --git a/components/bl00mbox/buds/tinysynth/tinysynth.c b/components/bl00mbox/buds/tinysynth/tinysynth.c
new file mode 100644
index 0000000000..1b1482c904
--- /dev/null
+++ b/components/bl00mbox/buds/tinysynth/tinysynth.c
@@ -0,0 +1,207 @@
+#include "tinysynth.h"
+#include <math.h>
+
+#define SYNTH_UNDERSAMPLING 1
+#define SYNTH_SAMPLE_RATE ((SAMPLE_RATE)/(SYNTH_UNDERSAMPLING))
+
+int16_t waveshaper(uint8_t shape, int16_t in);
+int16_t nes_noise(uint16_t * reg, uint8_t mode, uint8_t run);
+
+int16_t run_trad_env(trad_env_t * env){
+    uint32_t tmp;
+    switch(env->env_phase){
+        case TRAD_ENV_PHASE_OFF:
+            env->env_counter = 0;;
+            break;
+        case TRAD_ENV_PHASE_ATTACK:
+            tmp = env->env_counter + env->attack;
+            if(tmp < env->env_counter){ // overflow
+                tmp = ~((uint32_t) 0); // max out
+                env->env_phase = TRAD_ENV_PHASE_DECAY;
+                printf("decay \n");
+            }
+            env->env_counter = tmp;
+            break;
+        case TRAD_ENV_PHASE_DECAY:
+            tmp = env->env_counter - env->decay;
+            if(tmp > env->env_counter){ // underflow
+                tmp = 0; //bottom out
+            }
+            env->env_counter = tmp;
+
+            if(env->env_counter <= env->sustain){
+                env->env_counter = env->sustain;
+                env->env_phase = TRAD_ENV_PHASE_SUSTAIN;
+                printf("sustain \n");
+            }
+            break;
+        case TRAD_ENV_PHASE_SUSTAIN:
+            if(env->sustain == 0) env->env_phase = TRAD_ENV_PHASE_OFF;
+            env->env_counter = env->sustain;
+            break;
+        case TRAD_ENV_PHASE_RELEASE:
+            tmp = env->env_counter - env->release;
+            if(tmp > env->env_counter){ // underflow
+                tmp = 0; //bottom out
+                env->env_phase = TRAD_ENV_PHASE_OFF;
+            }
+            env->env_counter = tmp;
+            break;
+    }
+    return env->env_counter >> 17;
+}
+
+int16_t run_trad_osc(trad_osc_t * osc){
+    osc->undersampling_counter = (osc->undersampling_counter+1) % SYNTH_UNDERSAMPLING;
+    if(osc->undersampling_counter) return osc->prev_output;
+
+    int32_t ret; //lil bit buffer for operations
+
+    int32_t env = run_trad_env(&(osc->env));
+    if(osc->env.env_phase == TRAD_ENV_PHASE_OFF){
+        osc->counter = ((uint64_t) 1) << 63;
+        return 0;
+    }
+
+    //run core sawtooth
+    //uint64_t incr = osc->freq * osc->bend;
+    uint64_t incr = osc->freq;
+    osc->counter += incr;
+
+    osc->overflow_event = osc->counter_prev > osc->counter; //no neg f linfm for now
+    osc->counter_prev = osc->counter;
+
+    if(osc->waveform >= 7){
+        ret = nes_noise(&(osc->noise_reg), osc->waveform == 7, osc->overflow_event);
+    } else {
+        //apply waveshaper
+        int32_t tmp = (osc->counter) >> (33+16);
+        tmp *= 2;
+        tmp -= 32767;
+        ret = waveshaper(osc->waveform, tmp);
+    }
+
+    //apply volume
+    ret = (ret * env)>>15;
+    ret = (ret * osc->vol)>>15;
+    osc->prev_output = ret;
+    return ret;
+}
+
+int16_t nes_noise(uint16_t * reg, uint8_t mode, uint8_t run){
+    if(run) {
+        uint8_t fb = *reg;
+        if(mode){
+            fb = fb>>6;
+        } else {
+            fb = fb>>1;
+        }
+        fb = (fb ^ (*reg)) & 1;
+        *reg = (*reg >> 1);
+        *reg = (*reg) | (((uint16_t) fb) << 14);
+    }
+    return ((int16_t) (((*reg) & 1))*2 - 1) * 32767;
+}
+
+int16_t fake_square(int16_t triangle, int16_t pwm, int16_t gain){
+    //max gain (1<<14)-1
+    int32_t tmp = triangle;
+    tmp += pwm;
+    tmp *= gain;
+    if(tmp > 32767) tmp = 32767;
+    if(tmp < -32767) tmp = -32767;
+    return tmp;
+}
+
+int16_t waveshaper(uint8_t shape, int16_t in){
+    int32_t tmp = 0;
+    switch(shape){
+        case TRAD_OSC_WAVE_SINE: // TODO: implement proper sine
+        case TRAD_OSC_WAVE_FAKE_SINE:
+            tmp = waveshaper(TRAD_OSC_WAVE_TRI, in);
+            if(tmp > 0.){
+                tmp = 32767 - tmp;
+                tmp = (tmp*tmp)>>15;
+                tmp = 32767. - tmp;
+            } else {
+                tmp = 32767 + tmp;
+                tmp = (tmp*tmp)>>15;
+                tmp = tmp - 32767.;
+            }
+            break;
+        case TRAD_OSC_WAVE_TRI:
+            tmp = in;
+            tmp += 16384;
+            if(tmp > 32767) tmp -= 65535;
+            if(tmp > 0) tmp = -tmp;
+            tmp = (2 * tmp) + 32767;
+            break;
+        case TRAD_OSC_WAVE_SAW:
+            tmp = in;
+            break;
+        case TRAD_OSC_WAVE_SQUARE:
+            tmp = waveshaper(TRAD_OSC_WAVE_TRI, in);
+            tmp = fake_square(tmp, 0, 100);
+            break;
+        case TRAD_OSC_WAVE_PULSE:
+            tmp = waveshaper(TRAD_OSC_WAVE_TRI, in);
+            tmp = fake_square(tmp, 12269, 100);
+            break;
+        case TRAD_OSC_WAVE_BLIP:
+            tmp = waveshaper(TRAD_OSC_WAVE_TRI, in);
+            tmp = fake_square(tmp, 20384, 100);
+            break;
+    }
+    if(tmp > 32767) tmp = 32767;
+    if(tmp < -32767) tmp = -32767;
+    return tmp;
+}
+
+#define NAT_LOG_SEMITONE 0.05776226504666215
+
+void trad_osc_set_freq_semitone(trad_osc_t * osc, float tone){
+    trad_osc_set_freq_Hz(osc, 440. * exp(tone * NAT_LOG_SEMITONE));
+}
+
+void trad_osc_set_freq_Hz(trad_osc_t * osc, float freq){
+    osc->freq = (freq/(SYNTH_SAMPLE_RATE)) * (~((uint64_t) 0));
+    printf("freq: %llu \n" , osc->freq);
+}
+
+void trad_osc_set_waveform(trad_osc_t * osc, uint8_t waveform){
+    osc->waveform = waveform;
+}
+
+void trad_osc_set_attack_ms(trad_osc_t * osc, float ms){
+    osc->env.attack = (1000./ms/(SYNTH_SAMPLE_RATE)) * (~((uint32_t) 0)) ;
+    printf("atk: %u \n" , osc->env.attack);
+}
+
+void trad_osc_set_decay_ms(trad_osc_t * osc, float ms){
+    osc->env.decay = (1000./ms/(SYNTH_SAMPLE_RATE)) * ((~((uint32_t) 0)) - osc->env.sustain);
+}
+
+void trad_osc_set_sustain(trad_osc_t * osc, float sus){
+    osc->env.sustain = (~((uint32_t) 0)) * sus;
+}
+
+void trad_osc_set_release_ms(trad_osc_t * osc, float ms){
+    osc->env.release = (1000./ms/(SYNTH_SAMPLE_RATE)) * osc->env.sustain;
+}
+
+void trad_env_stop(trad_osc_t * osc){
+    if(osc->env.env_phase != TRAD_ENV_PHASE_OFF) osc->env.env_phase = TRAD_ENV_PHASE_RELEASE; 
+}
+
+void trad_env_fullstop(trad_osc_t * osc){
+    osc->env.env_phase = TRAD_ENV_PHASE_OFF; //stop and skip decay phase
+}
+
+void trad_env_start(trad_osc_t * osc){
+    osc->env.env_phase = TRAD_ENV_PHASE_ATTACK; //put into attack phase;
+}
+
+void trad_osc_set_vol(trad_osc_t * osc, float volume){
+    osc->vol = 32767 * volume;
+}
+
diff --git a/components/bl00mbox/buds/tinysynth/tinysynth.h b/components/bl00mbox/buds/tinysynth/tinysynth.h
new file mode 100644
index 0000000000..aed43e16db
--- /dev/null
+++ b/components/bl00mbox/buds/tinysynth/tinysynth.h
@@ -0,0 +1,71 @@
+#pragma once
+#include <stdint.h>
+#include <stdio.h>
+
+//#include "radspa.h"
+//#include "bl00mbox.h"
+
+#define SAMPLE_RATE 48000
+
+#define TRAD_OSC_DECAY_STEP          0.01
+#define TRAD_OSC_ATTACK_POP_BLOCK          16
+
+#define TRAD_ENV_PHASE_OFF 0
+#define TRAD_ENV_PHASE_ATTACK 1
+#define TRAD_ENV_PHASE_DECAY 2
+#define TRAD_ENV_PHASE_SUSTAIN 3
+#define TRAD_ENV_PHASE_RELEASE 4
+
+#define TRAD_OSC_WAVE_SINE 0
+#define TRAD_OSC_WAVE_FAKE_SINE 1
+#define TRAD_OSC_WAVE_TRI 2
+#define TRAD_OSC_WAVE_SAW 3
+#define TRAD_OSC_WAVE_SQUARE 4
+#define TRAD_OSC_WAVE_PULSE 5
+#define TRAD_OSC_WAVE_BLIP 6
+
+
+typedef struct {
+    uint32_t    env_counter;
+    uint32_t    attack;
+    uint32_t    decay;
+    uint32_t    sustain;
+    uint32_t    release;
+    uint8_t     env_phase;
+    uint8_t     skip_hold;
+} trad_env_t;
+
+typedef struct {
+    //user variables
+
+    //internal data storage, not for user access
+    uint64_t    freq;           //in hertz, negative frequencies for linFM allowed
+    uint64_t    bend;
+    uint32_t    vol;            //output volume
+    uint8_t     waveform;       //0: sine, 1: fast sine, 2: tri, 3: saw,
+                                //4: square, 5: 33% pulse, 6: 25% pulse
+
+    uint64_t    counter;     //state of central sawtooth oscillator.
+    uint64_t    counter_prev;     //previous state of central sawtooth oscillator.
+    int8_t      overflow_event; //set to -1 when counter underflows (below -1),
+                                //set to +1 when counter overflows (above 1)
+                                //not reset or used by anything so far
+    uint8_t     undersampling_counter;
+    int16_t       prev_output;           // for undersampling
+    uint16_t    noise_reg;
+    trad_env_t env;
+} trad_osc_t;
+
+int16_t run_trad_osc(trad_osc_t * osc);
+void trad_osc_set_freq_semitone(trad_osc_t * osc, float bend);
+void trad_osc_set_freq_Hz(trad_osc_t * osc, float freq);
+void trad_osc_set_waveform(trad_osc_t * osc, uint8_t waveform);
+void trad_osc_set_attack_ms(trad_osc_t * osc, float ms);
+void trad_osc_set_decay_ms(trad_osc_t * osc, float ms);
+void trad_osc_set_sustain(trad_osc_t * osc, float sus);
+void trad_osc_set_release_ms(trad_osc_t * osc, float ms);
+void trad_env_stop(trad_osc_t * osc);
+void trad_env_fullstop(trad_osc_t * osc);
+void trad_env_start(trad_osc_t * osc);
+
+void trad_osc_set_vol(trad_osc_t * osc, float volume);
diff --git a/components/bl00mbox/idf_component.yml b/components/bl00mbox/idf_component.yml
new file mode 100644
index 0000000000..aaa441830b
--- /dev/null
+++ b/components/bl00mbox/idf_component.yml
@@ -0,0 +1,7 @@
+version: "0.0.0"
+description: synth/sampler/sequencer for flow3r project
+
+dependencies:
+  # Required IDF version
+  idf:
+    version: ">=4.4"
diff --git a/components/bl00mbox/include/bl00mbox.h b/components/bl00mbox/include/bl00mbox.h
new file mode 100644
index 0000000000..6d8cd0e76d
--- /dev/null
+++ b/components/bl00mbox/include/bl00mbox.h
@@ -0,0 +1,10 @@
+#pragma once
+#include <stdint.h>
+#include <stdbool.h>
+
+#define SAMPLE_RATE 48000
+
+uint16_t bl00mbox_sources_count();
+uint16_t bl00mbox_source_add(void * render_data, void * render_function);
+void bl00mbox_source_remove(uint16_t index);
+void bl00mbox_player_function(int16_t * rx, int16_t * tx, uint16_t len);
diff --git a/components/bl00mbox/include/bud_registry.h b/components/bl00mbox/include/bud_registry.h
new file mode 100644
index 0000000000..5f1d5ec486
--- /dev/null
+++ b/components/bl00mbox/include/bud_registry.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#define BUD_ENTRIES 1
+
+#include "tinysynth.h"
+
+bud_t
+
+bud_t buds[BUD_ENTRIES] = {
+    tinysynth_bud
+}
diff --git a/components/bl00mbox/include/radspa.h b/components/bl00mbox/include/radspa.h
new file mode 100644
index 0000000000..a505435288
--- /dev/null
+++ b/components/bl00mbox/include/radspa.h
@@ -0,0 +1,28 @@
+#pragma once
+
+// realtime audio developer's simple plugin api
+// written from scratch but largely inspired by
+// faint memories of the excellent ladspa api
+
+#define RADSPA_SIGNAL_INPUT 0
+#define RADSPA_SIGNAL_TYPE_OUTPUT 1
+#define RADSPA_SIGNAL_EVENT_TRIGGER 2
+
+#define RADSPA_SIGNAL_HINT_LIN 0
+#define RADSPA_SIGNAL_HINT_LOG 1
+
+#if 0
+typedef struct _radspa_signal_t(){
+    uint16_t type;
+    uint16_t hints;
+    char name[32];
+    _radspa_signal_t * next; //linked list
+} radspa_signal_t;
+
+typedef struct _radspa_t(){
+    radspa_signal_t * signals;
+    
+
+} radspa_t;
+
+#endif
diff --git a/components/st3m/CMakeLists.txt b/components/st3m/CMakeLists.txt
index f3f94c980c..cae3d3c522 100644
--- a/components/st3m/CMakeLists.txt
+++ b/components/st3m/CMakeLists.txt
@@ -9,6 +9,7 @@ idf_component_register(
         .
     REQUIRES
         flow3r_bsp
+        bl00mbox
         ctx
         fatfs
 )
diff --git a/python_payload/apps/demo_sparabo.py b/python_payload/apps/demo_sparabo.py
index bf9b365e88..fcf6648bb4 100644
--- a/python_payload/apps/demo_sparabo.py
+++ b/python_payload/apps/demo_sparabo.py
@@ -4,7 +4,7 @@ import math
 # badge23
 from st3m import event, application, ui
 from st3m.system import hardware, audio
-from synth import tinysynth
+from bl00mbox import tinysynth
 
 popcorn = [9, 7, 9, 5, 0, 5, -3, 999]
 
@@ -17,8 +17,8 @@ class AppSparabo(application.Application):
 
         audio.set_volume_dB(0)
 
-        self.synth = tinysynth(440, 1)
-        self.synth.decay(25)
+        self.synth = tinysynth(440)
+        self.synth.decay_ms(250)
 
         print("here")
         self.sequencer = event.Sequence(bpm=160, steps=8, action=self.on_step, loop=True)
diff --git a/python_payload/apps/flow3r/menu_crazysynth.py b/python_payload/apps/flow3r/menu_crazysynth.py
index 63e557fb37..58a75f2155 100644
--- a/python_payload/apps/flow3r/menu_crazysynth.py
+++ b/python_payload/apps/flow3r/menu_crazysynth.py
@@ -1,9 +1,11 @@
-from synth import tinysynth
+from bl00mbox import tinysynth
 
 from st3m import menu, event, control, ui
 from st3m.system import hardware, audio
 
-synths = [tinysynth(440, 0), tinysynth(440, 0), tinysynth(440, 0)]
+synths = [tinysynth(440), tinysynth(440), tinysynth(440)]
+for s in synths:
+    s.sustain(1)
 # synth = tinysynth(440,0)
 
 
diff --git a/python_payload/apps/flow3r/menu_tinysynth.py b/python_payload/apps/flow3r/menu_tinysynth.py
index ddf7346f9e..1e725d2e76 100644
--- a/python_payload/apps/flow3r/menu_tinysynth.py
+++ b/python_payload/apps/flow3r/menu_tinysynth.py
@@ -1,10 +1,10 @@
-from synth import tinysynth
+from bl00mbox import tinysynth
 
 from st3m import menu, event, control, ui
 from st3m.system import hardware, audio
 
-synth = tinysynth(440, 0)
-
+synth = tinysynth(440)
+synth.sustain(1)
 
 def set_play(value):
     print("set_controls_overlay")
diff --git a/python_payload/apps/harmonic_demo.py b/python_payload/apps/harmonic_demo.py
index 86a4601607..d8c361a2fe 100644
--- a/python_payload/apps/harmonic_demo.py
+++ b/python_payload/apps/harmonic_demo.py
@@ -1,4 +1,4 @@
-from synth import tinysynth
+from bl00mbox import tinysynth
 from hardware import *
 import leds
 
@@ -21,11 +21,27 @@ class HarmonicApp(Application):
         self.chord_index = None
         self.chord = None
         self.synths = [
-            tinysynth(440, 1) for i in range(5)
+            tinysynth(440) for i in range(15)
         ]
-        for synth in self.synths:
-            synth.decay(100)
-            synth.waveform(1)
+        for i, synth in enumerate(self.synths):
+            synth.decay_ms(100)
+            synth.sustain(0.5)
+            if(i<5):
+                synth.waveform(1)
+                synth.volume(0.5)
+                synth.release_ms(1200)
+            elif(i<10):
+                synth.waveform(1)
+                synth.attack_ms(300)
+                synth.volume(0.1)
+                synth.sustain(0.9)
+                synth.release_ms(2400)
+            else:
+                synth.waveform(1)
+                synth.attack_ms(500)
+                synth.volume(0.03)
+                synth.sustain(0.9)
+                synth.release_ms(800)
         self._set_chord(3)
 
     def _set_chord(self, i):
@@ -59,8 +75,18 @@ class HarmonicApp(Application):
                 else:
                     k = int(i / 2)
                     self.synths[k].tone(self.chord[k])
+                    self.synths[k+5].tone(12+self.chord[k])
+                    self.synths[k+10].tone(7+self.chord[k])
                     self.synths[k].start()
+                    self.synths[k+5].start()
+                    self.synths[k+10].start()
                     self.color_intensity = 1.0
+            else:
+                if (1+i) % 2:
+                    k = int(i / 2)
+                    self.synths[k].stop()
+                    self.synths[k+5].stop()
+                    self.synths[k+10].stop()
 
 
 app = HarmonicApp("harmonic")
diff --git a/python_payload/apps/melodic_demo.py b/python_payload/apps/melodic_demo.py
index 9b8d4788d5..7b37378bc0 100644
--- a/python_payload/apps/melodic_demo.py
+++ b/python_payload/apps/melodic_demo.py
@@ -1,4 +1,4 @@
-from synth import tinysynth
+from bl00mbox import tinysynth
 from hardware import *
 import leds
 
@@ -64,10 +64,9 @@ def run():
 def init():
     global synths
     for i in range(1):
-        synths += [tinysynth(440, 1)]
+        synths += [tinysynth(440)]
     for synth in synths:
-        synth.decay(100)
-        synth.waveform(1)
+        synth.decay_ms(100)
 
 
 def foreground():
diff --git a/usermodule/micropython.cmake b/usermodule/micropython.cmake
index 54beadee0f..20723a93c7 100644
--- a/usermodule/micropython.cmake
+++ b/usermodule/micropython.cmake
@@ -8,8 +8,8 @@ target_sources(usermod_badge23 INTERFACE
     ${CMAKE_CURRENT_LIST_DIR}/mp_hardware.c
     ${CMAKE_CURRENT_LIST_DIR}/mp_leds.c
     ${CMAKE_CURRENT_LIST_DIR}/mp_audio.c
+    ${CMAKE_CURRENT_LIST_DIR}/mp_bl00mbox.c
     ${CMAKE_CURRENT_LIST_DIR}/mp_badge_link.c
-    ${CMAKE_CURRENT_LIST_DIR}/mp_synth.c
     ${CMAKE_CURRENT_LIST_DIR}/mp_kernel.c
     ${CMAKE_CURRENT_LIST_DIR}/mp_uctx.c
 )
diff --git a/usermodule/mp_synth.c b/usermodule/mp_bl00mbox.c
similarity index 58%
rename from usermodule/mp_synth.c
rename to usermodule/mp_bl00mbox.c
index 9e83278533..9b492e4d2c 100644
--- a/usermodule/mp_synth.c
+++ b/usermodule/mp_bl00mbox.c
@@ -1,8 +1,9 @@
 #include <stdio.h>
 #include "py/runtime.h"
 #include "py/obj.h"
-#include "badge23/synth.h"
-#include "badge23/audio.h"
+// sorry ;w;
+#include "badge23/../../../bl00mbox/include/bl00mbox.h"
+#include "badge23/../../../bl00mbox/buds/tinysynth/tinysynth.h"
 
 #if !MICROPY_ENABLE_FINALISER
 #error "BADGE23_SYNTH requires MICROPY_ENABLE_FINALISER"
@@ -25,21 +26,21 @@ STATIC void tinysynth_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
 }
 
 STATIC mp_obj_t tinysynth_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
-    mp_arg_check_num(n_args, n_kw, 2, 2, true);
+    mp_arg_check_num(n_args, n_kw, 1, 1, true);
     synth_tinysynth_obj_t *self = m_new_obj_with_finaliser(synth_tinysynth_obj_t);
     self->base.type = &synth_tinysynth_type;
-    self->osc.decay_steps = 50;
-    self->osc.attack_steps = 3;
-    self->osc.vol = 1.;
-    self->osc.gate = 0.01;
-    self->osc.freq = mp_obj_get_float(args[0]);
-    self->osc.counter = 0;
+
+    self->osc.vol = 32767;
     self->osc.bend = 1;
     self->osc.noise_reg = 1;
-    self->osc.waveform = 1;
-    self->osc.skip_hold = mp_obj_get_int(args[1]);
-    //set_extra_synth(&(self->osc));
-    self->source_index = add_audio_source(&(self->osc), run_trad_osc);
+    self->osc.waveform = TRAD_OSC_WAVE_TRI;
+
+    trad_osc_set_freq_Hz(&(self->osc), mp_obj_get_float(args[0]));
+    trad_osc_set_attack_ms(&(self->osc), 20);
+    trad_osc_set_decay_ms(&(self->osc), 500);
+    trad_osc_set_sustain(&(self->osc), 0);
+    trad_osc_set_release_ms(&(self->osc), 500);
+    self->source_index = bl00mbox_source_add(&(self->osc), run_trad_osc);
 
     return MP_OBJ_FROM_PTR(self);
 }
@@ -80,23 +81,44 @@ STATIC mp_obj_t tinysynth_waveform(mp_obj_t self_in, mp_obj_t waveform) {
 }
 MP_DEFINE_CONST_FUN_OBJ_2(tinysynth_waveform_obj, tinysynth_waveform);
 
-STATIC mp_obj_t tinysynth_attack(mp_obj_t self_in, mp_obj_t attack) {
+STATIC mp_obj_t tinysynth_attack_ms(mp_obj_t self_in, mp_obj_t attack_ms) {
+    synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    trad_osc_set_attack_ms(&(self->osc), mp_obj_get_float(attack_ms));
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(tinysynth_attack_ms_obj, tinysynth_attack_ms);
+
+STATIC mp_obj_t tinysynth_decay_ms(mp_obj_t self_in, mp_obj_t decay_ms) {
+    synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    trad_osc_set_decay_ms(&(self->osc), mp_obj_get_int(decay_ms));
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(tinysynth_decay_ms_obj, tinysynth_decay_ms);
+
+STATIC mp_obj_t tinysynth_release_ms(mp_obj_t self_in, mp_obj_t release_ms) {
+    synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    trad_osc_set_release_ms(&(self->osc), mp_obj_get_int(release_ms));
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(tinysynth_release_ms_obj, tinysynth_release_ms);
+
+STATIC mp_obj_t tinysynth_sustain(mp_obj_t self_in, mp_obj_t sus) {
     synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
-    trad_osc_set_attack(&(self->osc), mp_obj_get_int(attack));
+    trad_osc_set_sustain(&(self->osc), mp_obj_get_float(sus));
     return mp_const_none;
 }
-MP_DEFINE_CONST_FUN_OBJ_2(tinysynth_attack_obj, tinysynth_attack);
+MP_DEFINE_CONST_FUN_OBJ_2(tinysynth_sustain_obj, tinysynth_sustain);
 
-STATIC mp_obj_t tinysynth_decay(mp_obj_t self_in, mp_obj_t decay) {
+STATIC mp_obj_t tinysynth_volume(mp_obj_t self_in, mp_obj_t vol) {
     synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
-    trad_osc_set_decay(&(self->osc), mp_obj_get_int(decay));
+    trad_osc_set_vol(&(self->osc), mp_obj_get_float(vol));
     return mp_const_none;
 }
-MP_DEFINE_CONST_FUN_OBJ_2(tinysynth_decay_obj, tinysynth_decay);
+MP_DEFINE_CONST_FUN_OBJ_2(tinysynth_volume_obj, tinysynth_volume);
 
 STATIC mp_obj_t tinysynth_deinit(mp_obj_t self_in) {
     synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
-    remove_audio_source(self->source_index);
+    bl00mbox_source_remove(self->source_index);
     return mp_const_none;
 }
 
@@ -108,8 +130,11 @@ STATIC const mp_rom_map_elem_t tinysynth_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&tinysynth_freq_obj) },
     { MP_ROM_QSTR(MP_QSTR_tone), MP_ROM_PTR(&tinysynth_tone_obj) },
     { MP_ROM_QSTR(MP_QSTR_waveform), MP_ROM_PTR(&tinysynth_waveform_obj) },
-    { MP_ROM_QSTR(MP_QSTR_attack), MP_ROM_PTR(&tinysynth_attack_obj) },
-    { MP_ROM_QSTR(MP_QSTR_decay), MP_ROM_PTR(&tinysynth_decay_obj) },
+    { MP_ROM_QSTR(MP_QSTR_attack_ms), MP_ROM_PTR(&tinysynth_attack_ms_obj) },
+    { MP_ROM_QSTR(MP_QSTR_decay_ms), MP_ROM_PTR(&tinysynth_decay_ms_obj) },
+    { MP_ROM_QSTR(MP_QSTR_volume), MP_ROM_PTR(&tinysynth_sustain_obj) },
+    { MP_ROM_QSTR(MP_QSTR_sustain), MP_ROM_PTR(&tinysynth_sustain_obj) },
+    { MP_ROM_QSTR(MP_QSTR_release_ms), MP_ROM_PTR(&tinysynth_release_ms_obj) },
     { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&tinysynth_deinit_obj) },
 };
 
@@ -118,26 +143,26 @@ STATIC MP_DEFINE_CONST_DICT(tinysynth_locals_dict, tinysynth_locals_dict_table);
 
 MP_DEFINE_CONST_OBJ_TYPE(
     synth_tinysynth_type,
-    MP_QSTR_synth,
+    MP_QSTR_bl00mbox,
     MP_TYPE_FLAG_NONE,
     make_new, tinysynth_make_new,
     print, tinysynth_print,
     locals_dict, &tinysynth_locals_dict
     );    
 
-STATIC const mp_map_elem_t synth_globals_table[] = {
-    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_synth) },
+STATIC const mp_map_elem_t bl00mbox_globals_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_bl00mbox) },
     { MP_OBJ_NEW_QSTR(MP_QSTR_tinysynth), (mp_obj_t)&synth_tinysynth_type },
 };
 
 STATIC MP_DEFINE_CONST_DICT (
-    mp_module_synth_globals,
-    synth_globals_table
+    mp_module_bl00mbox_globals,
+    bl00mbox_globals_table
 );
 
-const mp_obj_module_t synth_user_cmodule = {
+const mp_obj_module_t bl00mbox_user_cmodule = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_synth_globals,
+    .globals = (mp_obj_dict_t*)&mp_module_bl00mbox_globals,
 };
 
-MP_REGISTER_MODULE(MP_QSTR_synth, synth_user_cmodule);
+MP_REGISTER_MODULE(MP_QSTR_bl00mbox, bl00mbox_user_cmodule);
diff --git a/usermodule/mp_hardware.c b/usermodule/mp_hardware.c
index 7f40a738bb..6b34c1591a 100644
--- a/usermodule/mp_hardware.c
+++ b/usermodule/mp_hardware.c
@@ -140,30 +140,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_right_button_get_obj, mp_right_button_get);
 
 
 
-STATIC mp_obj_t mp_set_global_volume_dB(size_t n_args, const mp_obj_t *args) {
-    //TODO: DEPRECATE
-    mp_float_t d = mp_obj_get_float(args[0]);
-    audio_set_volume_dB(d);
-    return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_set_global_volume_dB_obj, 1, 2, mp_set_global_volume_dB);
-
-STATIC mp_obj_t mp_count_sources(size_t n_args, const mp_obj_t *args) {
-    uint16_t d = count_audio_sources();
-    return mp_obj_new_int(d);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_count_sources_obj, 0, 2, mp_count_sources);
-
-STATIC mp_obj_t mp_dump_all_sources(size_t n_args, const mp_obj_t *args) {
-    uint16_t d = count_audio_sources();
-    for(uint16_t i = 0; i < d; i++){
-        remove_audio_source(i);
-    }
-    return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_dump_all_sources_obj, 0, 2, mp_dump_all_sources);
-
-
 STATIC mp_obj_t mp_version(void) {
     mp_obj_t str = mp_obj_new_str(flow3r_bsp_hw_name, strlen(flow3r_bsp_hw_name));
     return str;
@@ -249,9 +225,6 @@ STATIC const mp_rom_map_elem_t mp_module_hardware_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_menu_button_set_left), MP_ROM_PTR(&mp_menu_button_set_left_obj) },
     { MP_ROM_QSTR(MP_QSTR_menu_button_get_left), MP_ROM_PTR(&mp_menu_button_get_left_obj) },
 
-    { MP_ROM_QSTR(MP_QSTR_set_global_volume_dB), MP_ROM_PTR(&mp_set_global_volume_dB_obj) },
-    { MP_ROM_QSTR(MP_QSTR_count_sources), MP_ROM_PTR(&mp_count_sources_obj) },
-    { MP_ROM_QSTR(MP_QSTR_dump_all_sources), MP_ROM_PTR(&mp_dump_all_sources_obj) },
     { MP_ROM_QSTR(MP_QSTR_display_update), MP_ROM_PTR(&mp_display_update_obj) },
     { MP_ROM_QSTR(MP_QSTR_freertos_sleep), MP_ROM_PTR(&mp_freertos_sleep_obj) },
     { MP_ROM_QSTR(MP_QSTR_display_pipe_full), MP_ROM_PTR(&mp_display_pipe_full_obj) },
-- 
GitLab