diff --git a/app.cpp b/app.cpp
new file mode 100644
index 0000000..390d2e9
--- /dev/null
+++ b/app.cpp
@@ -0,0 +1,575 @@
+/*
+ * Copyright (c) 2026 Marcel Licence
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
+ * der GNU General Public License, wie von der Free Software Foundation,
+ * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
+ * veröffentlichten Version, weiter verteilen und/oder modifizieren.
+ *
+ * Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
+ * OHNE JEDE GEWÄHR,; sogar ohne die implizite
+ * Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
+ * Siehe die GNU General Public License für weitere Einzelheiten.
+ *
+ * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
+ * Programm erhalten haben. Wenn nicht, siehe .
+ */
+
+/**
+ * @file app.cpp
+ * @author Marcel Licence
+ * @date 26.11.2021
+ *
+ * @brief This is the main project file to test the ML_SynthLibrary (multi saw module)
+ * It should be compatible with the Raspberry Pi Pico and all other RP2040 platforms
+ *
+ * @see https://youtu.be/kcf597op8o4
+ */
+
+
+#ifdef __CDT_PARSER__
+#include
+#endif
+
+
+#include "config.h"
+
+#include "app.h"
+
+
+#include
+#include
+
+
+/*
+ * Library can be found on https://github.com/marcel-licence/ML_SynthTools
+ */
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef ARP_MODULE_ENABLED
+#include
+#endif
+
+#ifdef REVERB_ENABLED
+#include
+#endif
+#ifdef MAX_DELAY_Q
+#include
+#endif
+#ifdef OLED_OSC_DISP_ENABLED
+#include
+#endif
+
+
+/* centralized modules */
+#define ML_SYNTH_INLINE_DECLARATION
+#include
+#undef ML_SYNTH_INLINE_DECLARATION
+
+
+#if (defined ARDUINO_GENERIC_F407VGTX) || (defined ARDUINO_DISCO_F407VG)
+#include /* todo remove, just for scanning */
+#endif
+
+
+char shortName[] = "ML_MultiSaw";
+
+float static_sine[WAVEFORM_CNT];
+float *sine = static_sine;
+
+
+struct filterCoeffQ16T mainFiltC;
+struct filterProcQ16T mainFiltL;
+struct filterProcQ16T mainFiltR;
+
+
+void App_Setup(void)
+{
+ for (int i = 0; i < WAVEFORM_CNT; i++)
+ {
+ float val = (float)sin(i * 2.0 * PI / WAVEFORM_CNT);
+ sine[i] = val;
+ }
+
+ Filter_Init(&mainFiltL, &mainFiltC);
+ Filter_Init(&mainFiltR, &mainFiltC);
+
+ /*
+ * this code runs once
+ */
+#ifdef MIDI_USB_ENABLED
+ Midi_Usb_Setup();
+#endif
+
+#ifdef BLINK_LED_PIN
+ Blink_Setup();
+ Blink_Fast(3);
+#endif
+
+#ifdef ARDUINO_DAISY_SEED
+ DaisySeed_Setup();
+#endif
+
+ delay(2500);
+
+#ifdef SWAP_SERIAL
+ /* only one hw serial use this for ESP */
+ Serial.begin(115200);
+ delay(500);
+#else
+ Serial.begin(SERIAL_BAUDRATE);
+#endif
+
+ Serial.println();
+
+
+ Serial.printf("Loading data\n");
+
+
+ Serial.printf("Multi Saw Synth Example\n");
+
+
+#ifdef ESP8266
+ Midi_Setup();
+#endif
+
+ Serial.printf("Initialize Audio Interface\n");
+ Audio_Setup();
+
+#ifdef TEENSYDUINO
+ Teensy_Setup();
+#else
+
+#ifdef ARDUINO_SEEED_XIAO_M0
+ pinMode(7, INPUT_PULLUP);
+ Midi_Setup();
+ pinMode(LED_BUILTIN, OUTPUT);
+#else
+
+#ifndef ESP8266 /* otherwise it will break audio output */
+ Midi_Setup();
+#endif
+#endif
+
+#endif
+
+
+#ifdef REVERB_ENABLED
+ /*
+ * Initialize reverb
+ * The buffer shall be static to ensure that
+ * the memory will be exclusive available for the reverb module
+ */
+
+ static float *revBuffer = (float *)malloc(sizeof(float) * REV_BUFF_SIZE);
+ Reverb_Setup(revBuffer);
+#endif
+
+#ifdef MAX_DELAY_Q
+ /*
+ * Prepare a buffer which can be used for the delay
+ */
+#ifdef ESP32
+ static int16_t *delBuffer1 = (int16_t *)malloc(sizeof(int16_t) * MAX_DELAY);
+ static int16_t *delBuffer2 = (int16_t *)malloc(sizeof(int16_t) * MAX_DELAY);
+#else
+ static int16_t delBuffer1[MAX_DELAY];
+ static int16_t delBuffer2[MAX_DELAY];
+#endif
+ DelayQ_Init2(delBuffer1, delBuffer2, MAX_DELAY_Q);
+#endif
+
+#ifdef MIDI_BLE_ENABLED
+ midi_ble_setup();
+#endif
+
+#ifdef USB_HOST_ENABLED
+ Usb_Host_Midi_setup();
+#endif
+
+#ifdef ESP32
+ Serial.printf("ESP.getFreeHeap() %d\n", ESP.getFreeHeap());
+ Serial.printf("ESP.getMinFreeHeap() %d\n", ESP.getMinFreeHeap());
+ Serial.printf("ESP.getHeapSize() %d\n", ESP.getHeapSize());
+ Serial.printf("ESP.getMaxAllocHeap() %d\n", ESP.getMaxAllocHeap());
+
+ /* PSRAM will be fully used by the looper */
+ Serial.printf("Total PSRAM: %d\n", ESP.getPsramSize());
+ Serial.printf("Free PSRAM: %d\n", ESP.getFreePsram());
+#endif
+
+#if (defined OLED_OSC_DISP_ENABLED) && (defined TEENSYDUINO)
+ ScopeOled_Setup();
+#endif
+
+#ifdef USB_HOST_ENABLED
+ Usb_Host_Midi_setup();
+#endif
+
+#ifdef ARP_MODULE_ENABLED
+ Arp_Init(1750); /* some quick tempo */
+ Arp_SelectSequence(1, 1);
+ Arp_Active();
+#endif
+
+ Slicer_SetType(0, 0);
+ Slicer_SetDecay(0, 127);
+ Slicer_SetDepth(0, 0);
+
+ Serial.printf("Wait for multi saw module to be initialized\n");
+ MultiSawSynth_Init(SAMPLE_RATE);
+ Serial.printf("Multi saw module ready\n");
+ MultiSawSynth_SetDetune(32);
+ MultiSawSynth_SetCount(127);
+
+#ifdef NOTE_ON_AFTER_SETUP
+ App_NoteOn(0, 64, 127);
+#endif
+
+
+#ifdef MIDI_STREAM_PLAYER_ENABLED
+ MidiStreamPlayer_Init();
+
+ char midiFile[] = "/song.mid";
+ MidiStreamPlayer_PlayMidiFile_fromLittleFS(midiFile, 1);
+#endif
+
+#ifdef ADC_ENABLED
+ AdcSetup();
+#endif
+}
+
+#ifdef ESP32
+void App_Setup1(void)
+{
+ /*
+ * init your stuff for core0 here
+ */
+
+#ifdef OLED_OSC_DISP_ENABLED
+ ScopeOled_Setup();
+#endif
+#ifdef MIDI_VIA_USB_ENABLED
+ UsbMidi_Setup();
+#endif
+}
+
+void App_Loop1(void)
+{
+ /*
+ * put your loop stuff for core0 here
+ */
+#ifdef MIDI_VIA_USB_ENABLED
+ UsbMidi_Loop();
+#endif
+
+#ifdef OLED_OSC_DISP_ENABLED
+ ScopeOled_Process();
+#endif
+}
+#endif /* ESP32 */
+
+void loop_1Hz()
+{
+#ifdef CYCLE_MODULE_ENABLED
+ CyclePrint();
+#endif
+#ifdef BLINK_LED_PIN
+ Blink_Process();
+#endif
+}
+
+
+void App_Loop(void)
+{
+ static int loop_cnt_1hz = 0; /*!< counter to allow 1Hz loop cycle */
+
+#ifdef SAMPLE_BUFFER_SIZE
+ loop_cnt_1hz += SAMPLE_BUFFER_SIZE;
+#else
+ loop_cnt_1hz += 1; /* in case only one sample will be processed per loop cycle */
+#endif
+ if (loop_cnt_1hz >= SAMPLE_RATE)
+ {
+ loop_cnt_1hz -= SAMPLE_RATE;
+ loop_1Hz();
+ }
+
+#ifdef ADC_ENABLED
+ AdcCheck();
+#endif
+
+#ifdef ARP_MODULE_ENABLED
+ Arp_Process(1);
+#endif
+
+ /*
+ * MIDI processing
+ */
+ Midi_Process();
+
+#ifdef MIDI_VIA_USB_ENABLED
+ UsbMidi_ProcessSync();
+#endif
+#ifdef MIDI_STREAM_PLAYER_ENABLED
+ MidiStreamPlayer_Tick(SAMPLE_BUFFER_SIZE);
+#endif
+
+#ifdef MIDI_BLE_ENABLED
+ midi_ble_loop();
+#endif
+
+#ifdef USB_HOST_ENABLED
+ Usb_Host_Midi_loop();
+#endif
+
+#ifdef MIDI_USB_ENABLED
+ Midi_Usb_Loop();
+#endif
+
+ /*
+ * And finally the audio stuff
+ */
+ Q1_14 left[SAMPLE_BUFFER_SIZE];
+ Q1_14 right[SAMPLE_BUFFER_SIZE];
+
+ memset(left, 0, sizeof(left));
+ memset(right, 0, sizeof(left));
+
+ MultiSawSynth_Process(left, right, SAMPLE_BUFFER_SIZE);
+
+ Filter_Process_Buffer(left, &mainFiltL, SAMPLE_BUFFER_SIZE);
+ Filter_Process_Buffer(right, &mainFiltR, SAMPLE_BUFFER_SIZE);
+
+ Slicer_Process(left, right, SAMPLE_BUFFER_SIZE);
+
+#ifdef MAX_DELAY_Q
+ DelayQ_Process_Buff(&left[0].s16, &right[0].s16, &left[0].s16, &right[0].s16, SAMPLE_BUFFER_SIZE);
+#endif
+
+ /*
+ * Output the audio
+ */
+ Audio_Output(left, right);
+}
+
+void App_NoteOn(uint8_t ch, uint8_t note, uint8_t vel)
+{
+#ifdef ARP_MODULE_ENABLED
+ Arp_NoteOn(ch, note, vel);
+#else
+ MultiSawSynth_NoteOn(ch, note, vel);
+#endif
+}
+
+void App_NoteOff(uint8_t ch, uint8_t note)
+{
+#ifdef ARP_MODULE_ENABLED
+ Arp_NoteOff(ch, note);
+#else
+ MultiSawSynth_NoteOff(ch, note);
+#endif
+}
+
+void App_NoteSetPitch(uint8_t ch, uint8_t note, uint32_t pitch)
+{
+ MultiSawSynth_NoteSetPitch(ch, note, pitch);
+}
+
+void App_NoteSetVolume(uint8_t ch, uint8_t note, uint16_t volume)
+{
+ MultiSawSynth_NoteSetVolume(ch, note, volume);
+}
+
+void App_PitchBend(uint8_t ch, uint16_t bend)
+{
+ MultiSawSynth_PitchBend(ch, bend);
+}
+
+void App_ModulationWheel(uint8_t ch, uint8_t value)
+{
+ /* not implemented yet */
+}
+
+/*
+ * MIDI via USB Host Module
+ */
+#ifdef MIDI_VIA_USB_ENABLED
+void App_UsbMidiShortMsgReceived(uint8_t *msg)
+{
+#ifdef MIDI_TX2_PIN
+ Midi_SendShortMessage(msg);
+#endif
+ Midi_HandleShortMsg(msg, 8);
+}
+#endif
+
+/*
+ * MIDI callbacks
+ */
+void App_ButtonA(uint8_t setting, uint8_t value)
+{
+ if (value > 0)
+ {
+ MultiSawSynth_SetProfile(setting);
+ }
+}
+
+void App_ButtonCh(uint8_t setting, uint8_t value)
+{
+ if (value > 0)
+ {
+ MultiSawSynth_SetCurrentCh(setting);
+ }
+}
+
+void App_ButtonSlicer(uint8_t setting, uint8_t value)
+{
+ if (value > 0)
+ {
+ Slicer_SetType(0, setting);
+ }
+}
+
+void App_SliderSawCtrl(uint8_t id, uint8_t value)
+{
+ switch (id)
+ {
+ case 0:
+ MultiSawSynth_SetDetune(value);
+ break;
+ case 1:
+ MultiSawSynth_SetCount(value);
+ break;
+ case 2:
+ MultiSawSynth_SetProfile(value);
+ break;
+ case 3:
+ {
+ if (value < 30)
+ {
+ value = 30;
+ }
+ if (value > 126)
+ {
+ value = 126;
+ }
+ float c = value;
+ c *= 1.0f / 127.0f;
+ Filter_Calculate(c, 0.5f, &mainFiltC);
+ }
+ break;
+ }
+}
+
+/*
+ * Arp Callbacks
+ */
+void Arp_Cb_NoteOn(uint8_t ch, uint8_t note, float vel)
+{
+ MultiSawSynth_NoteOn(ch, note, vel);
+}
+
+void Arp_Cb_NoteOff(uint8_t ch, uint8_t note)
+{
+ MultiSawSynth_NoteOff(ch, note);
+}
+
+void Arp_Status_ValueChangedInt(const char *msg, int value)
+{
+ // Status_ValueChangedInt(msg, value);
+}
+
+void Arp_Status_LogMessage(const char *msg)
+{
+ //Status_LogMessage(msg);
+}
+
+void Arp_Status_ValueChangedFloat(const char *msg, float value)
+{
+ // Status_ValueChangedFloat(msg, value);
+}
+
+void Arp_Cb_Step(uint8_t step)
+{
+ /* ignore */
+}
+
+#if defined(I2C_SCL) && defined(I2C_SDA)
+void ScanI2C(void)
+{
+#ifdef ARDUINO_GENERIC_F407VGTX
+ Wire.setSDA(I2C_SDA);
+ Wire.setSCL(I2C_SCL);
+ Wire.begin();//I2C_SDA, I2C_SCL);
+#else
+ Wire.begin();
+#endif
+
+ byte address;
+ int nDevices;
+
+ Serial.println("Scanning...");
+
+ nDevices = 0;
+ for (address = 1; address < 127; address++)
+ {
+ byte r_error;
+ // The i2c_scanner uses the return value of
+ // the Write.endTransmisstion to see if
+ // a device did acknowledge to the address.
+ Wire.beginTransmission(address);
+ r_error = Wire.endTransmission();
+
+ if (r_error == 0)
+ {
+ Serial.print("I2C device found at address 0x");
+ if (address < 16)
+ {
+ Serial.print("0");
+ }
+ Serial.print(address, HEX);
+ Serial.println(" !");
+
+ nDevices++;
+ }
+ else if (r_error == 4)
+ {
+ Serial.print("Unknown error at address 0x");
+ if (address < 16)
+ {
+ Serial.print("0");
+ }
+ Serial.println(address, HEX);
+ }
+ }
+ if (nDevices == 0)
+ {
+ Serial.println("No I2C devices found\n");
+ }
+ else
+ {
+ Serial.println("done\n");
+ }
+}
+#endif /* (defined ARDUINO_GENERIC_F407VGTX) || (defined ARDUINO_DISCO_F407VG) */
+
diff --git a/app.h b/app.h
new file mode 100644
index 0000000..28aaf3d
--- /dev/null
+++ b/app.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2026 Marcel Licence
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
+ * der GNU General Public License, wie von der Free Software Foundation,
+ * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
+ * veröffentlichten Version, weiter verteilen und/oder modifizieren.
+ *
+ * Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
+ * OHNE JEDE GEWÄHR,; sogar ohne die implizite
+ * Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
+ * Siehe die GNU General Public License für weitere Einzelheiten.
+ *
+ * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
+ * Programm erhalten haben. Wenn nicht, siehe .
+ */
+
+/**
+ * @file app.h
+ * @author Marcel Licence
+ * @date 18.03.2026
+ *
+ * @brief Declarations of the app
+ */
+
+
+#ifndef APP_H_
+#define APP_H_
+
+
+#include "config.h"
+
+#include
+
+
+void App_Setup(void);
+void App_Loop(void);
+
+void App_Setup1(void);
+void App_Loop1(void);
+
+
+void App_ButtonA(uint8_t setting, uint8_t value);
+void App_ButtonCh(uint8_t setting, uint8_t value);
+void App_ButtonSlicer(uint8_t setting, uint8_t value);
+void App_SliderSawCtrl(uint8_t id, uint8_t value);
+void App_NoteOn(uint8_t ch, uint8_t note, uint8_t vel);
+void App_NoteOff(uint8_t ch, uint8_t note);
+void App_PitchBend(uint8_t ch, uint16_t bend);
+void App_ModulationWheel(uint8_t ch, uint8_t value);
+
+
+#endif /* APP_H_ */
diff --git a/ml_inline.ino b/ml_inline.ino
index 1fecd6c..16ac6e5 100644
--- a/ml_inline.ino
+++ b/ml_inline.ino
@@ -1,4 +1,46 @@
+/*
+ * Copyright (c) 2026 Marcel Licence
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
+ * der GNU General Public License, wie von der Free Software Foundation,
+ * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
+ * veröffentlichten Version, weiter verteilen und/oder modifizieren.
+ *
+ * Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
+ * OHNE JEDE GEWÄHR,; sogar ohne die implizite
+ * Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
+ * Siehe die GNU General Public License für weitere Einzelheiten.
+ *
+ * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
+ * Programm erhalten haben. Wenn nicht, siehe .
+ */
+
+
+#include "config.h"
+
+
+#define ML_SYNTH_INLINE_DECLARATION
+#include
+#undef ML_SYNTH_INLINE_DECLARATION
#define ML_SYNTH_INLINE_DEFINITION
#include
+#ifdef OLED_OSC_DISP_ENABLED
+#define ML_SCOPE_OLED
+#include
+#endif
#undef ML_SYNTH_INLINE_DEFINITION
+
diff --git a/ml_synth_multi_saw_example.ino b/ml_synth_multi_saw_example.ino
index 0d337db..7988ce4 100644
--- a/ml_synth_multi_saw_example.ino
+++ b/ml_synth_multi_saw_example.ino
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024 Marcel Licence
+ * Copyright (c) 2026 Marcel Licence
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,279 +31,92 @@
/**
* @file ml_synth_multi_saw_example.ino
* @author Marcel Licence
- * @date 26.11.2021
+ * @date 18.03.2026
*
- * @brief This is the main project file to test the ML_SynthLibrary (multi saw module)
- * It should be compatible with the Raspberry Pi Pico and all other RP2040 platforms
- *
- * @see https://youtu.be/kcf597op8o4
+ * @brief This is the main project file which handles the app startup and loop calls
+ * You will find the main code in app.cpp
*/
-#ifdef __CDT_PARSER__
-#include
-#endif
-
-
-#include "config.h"
+#include "app.h"
-#include
-#include
-
-
-/*
- * Library can be found on https://github.com/marcel-licence/ML_SynthTools
- */
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#ifdef ARP_MODULE_ENABLED
-#include
+#if (defined ESP32) && (SOC_CPU_CORES_NUM > 1)
+void Core0TaskInit(void);
+void Core0Task(void *parameter);
#endif
-#ifdef REVERB_ENABLED
-#include
-#endif
-#ifdef MAX_DELAY_Q
-#include
-#endif
-#ifdef OLED_OSC_DISP_ENABLED
-#include
+#ifdef ARDUINO_RP2040
+volatile bool g_setup_done = false;
#endif
-/* centralized modules */
-#define ML_SYNTH_INLINE_DECLARATION
-#include
-#undef ML_SYNTH_INLINE_DECLARATION
-
-
-#if (defined ARDUINO_GENERIC_F407VGTX) || (defined ARDUINO_DISCO_F407VG)
-#include /* todo remove, just for scanning */
-#endif
-
-
-char shortName[] = "ML_MultiSaw";
-
-float static_sine[WAVEFORM_CNT];
-float *sine = static_sine;
-
-
-struct filterCoeffQ16T mainFiltC;
-struct filterProcQ16T mainFiltL;
-struct filterProcQ16T mainFiltR;
-
-
void setup()
{
- for (int i = 0; i < WAVEFORM_CNT; i++)
- {
- float val = (float)sin(i * 2.0 * PI / WAVEFORM_CNT);
- sine[i] = val;
- }
-
- Filter_Init(&mainFiltL, &mainFiltC);
- Filter_Init(&mainFiltR, &mainFiltC);
-
- /*
- * this code runs once
- */
-#ifdef MIDI_USB_ENABLED
- Midi_Usb_Setup();
-#endif
-
-#ifdef BLINK_LED_PIN
- Blink_Setup();
- Blink_Fast(3);
-#endif
-
-#ifdef ARDUINO_DAISY_SEED
- DaisySeed_Setup();
-#endif
-
- delay(2500);
-
-#ifdef SWAP_SERIAL
- /* only one hw serial use this for ESP */
Serial.begin(115200);
- delay(500);
-#else
- Serial.begin(SERIAL_BAUDRATE);
-#endif
-
- Serial.println();
-
-
- Serial.printf("Loading data\n");
-
-
- Serial.printf("Multi Saw Synth Example\n");
-
-
-#ifdef ESP8266
- Midi_Setup();
-#endif
-
- Serial.printf("Initialize Audio Interface\n");
- Audio_Setup();
-
-#ifdef TEENSYDUINO
- Teensy_Setup();
-#else
-
-#ifdef ARDUINO_SEEED_XIAO_M0
- pinMode(7, INPUT_PULLUP);
- Midi_Setup();
- pinMode(LED_BUILTIN, OUTPUT);
-#else
-
-#ifndef ESP8266 /* otherwise it will break audio output */
- Midi_Setup();
-#endif
-#endif
-
-#endif
-
-
-#ifdef REVERB_ENABLED
- /*
- * Initialize reverb
- * The buffer shall be static to ensure that
- * the memory will be exclusive available for the reverb module
- */
-
- static float *revBuffer = (float *)malloc(sizeof(float) * REV_BUFF_SIZE);
- Reverb_Setup(revBuffer);
-#endif
-
-#ifdef MAX_DELAY_Q
- /*
- * Prepare a buffer which can be used for the delay
- */
-#ifdef ESP32
- static int16_t *delBuffer1 = (int16_t *)malloc(sizeof(int16_t) * MAX_DELAY);
- static int16_t *delBuffer2 = (int16_t *)malloc(sizeof(int16_t) * MAX_DELAY);
-#else
- static int16_t delBuffer1[MAX_DELAY];
- static int16_t delBuffer2[MAX_DELAY];
-#endif
- DelayQ_Init2(delBuffer1, delBuffer2, MAX_DELAY_Q);
-#endif
-
-#ifdef MIDI_BLE_ENABLED
- midi_ble_setup();
-#endif
-
-#ifdef USB_HOST_ENABLED
- Usb_Host_Midi_setup();
-#endif
-
-#ifdef ESP32
- Serial.printf("ESP.getFreeHeap() %d\n", ESP.getFreeHeap());
- Serial.printf("ESP.getMinFreeHeap() %d\n", ESP.getMinFreeHeap());
- Serial.printf("ESP.getHeapSize() %d\n", ESP.getHeapSize());
- Serial.printf("ESP.getMaxAllocHeap() %d\n", ESP.getMaxAllocHeap());
-
- /* PSRAM will be fully used by the looper */
- Serial.printf("Total PSRAM: %d\n", ESP.getPsramSize());
- Serial.printf("Free PSRAM: %d\n", ESP.getFreePsram());
-#endif
-
-#if (defined OLED_OSC_DISP_ENABLED) && (defined TEENSYDUINO)
- ScopeOled_Setup();
-#endif
+ App_Setup();
-#ifdef USB_HOST_ENABLED
- Usb_Host_Midi_setup();
+#ifdef ARDUINO_RP2040
+ g_setup_done = true;
#endif
-#ifdef ARP_MODULE_ENABLED
- Arp_Init(1750); /* some quick tempo */
- Arp_SelectSequence(1, 1);
- Arp_Active();
+#if (defined ESP32) && (SOC_CPU_CORES_NUM > 1)
+ Core0TaskInit();
#endif
+}
- Slicer_SetType(0, 0);
- Slicer_SetDecay(0, 127);
- Slicer_SetDepth(0, 0);
-
- Serial.printf("Wait for multi saw module to be initialized\n");
- MultiSawSynth_Init(SAMPLE_RATE);
- Serial.printf("Multi saw module ready\n");
- MultiSawSynth_SetDetune(32);
- MultiSawSynth_SetCount(127);
-
-#ifdef NOTE_ON_AFTER_SETUP
- App_NoteOn(0, 64, 127);
-#endif
+void loop()
+{
+ App_Loop();
+}
+#ifdef ARDUINO_RP2040
-#ifdef MIDI_STREAM_PLAYER_ENABLED
- MidiStreamPlayer_Init();
+void wait_until_setup_finished(void)
+{
+ while (!g_setup_done)
+ {
+ delay(1);
+ }
+}
- char midiFile[] = "/song.mid";
- MidiStreamPlayer_PlayMidiFile_fromLittleFS(midiFile, 1);
-#endif
+void setup1()
+{
+ wait_until_setup_finished();
+ App_Setup1();
+}
-#if (defined MIDI_VIA_USB_ENABLED) || (defined OLED_OSC_DISP_ENABLED)
-#ifdef ESP32
- Core0TaskInit();
-#else
- //#error only supported by ESP32 platform
-#endif
+void loop1()
+{
+ App_Loop1();
+}
#endif
-#ifdef ADC_ENABLED
- AdcSetup();
-#endif
-}
-#ifdef ESP32
+#if (defined ESP32) && (SOC_CPU_CORES_NUM > 1)
/*
* Core 0
*/
/* this is used to add a task to core 0 */
TaskHandle_t Core0TaskHnd;
-inline
-void Core0TaskInit()
+void Core0TaskInit(void)
{
/* we need a second task for the terminal output */
- xTaskCreatePinnedToCore(Core0Task, "CoreTask0", 8000, NULL, 999, &Core0TaskHnd, 0);
+ xTaskCreatePinnedToCore(Core0Task, "CoreTask0", 8000, NULL, 4, &Core0TaskHnd, 0);
}
-void Core0TaskSetup()
+void Core0TaskSetup(void)
{
/*
* init your stuff for core0 here
*/
-
-#ifdef OLED_OSC_DISP_ENABLED
- ScopeOled_Setup();
-#endif
-#ifdef MIDI_VIA_USB_ENABLED
- UsbMidi_Setup();
-#endif
+ App_Setup1();
}
-void Core0TaskLoop()
+void Core0TaskLoop(void)
{
- /*
- * put your loop stuff for core0 here
- */
-#ifdef MIDI_VIA_USB_ENABLED
- UsbMidi_Loop();
-#endif
-
-#ifdef OLED_OSC_DISP_ENABLED
- ScopeOled_Process();
-#endif
+ App_Loop1();
}
void Core0Task(void *parameter)
@@ -319,290 +132,4 @@ void Core0Task(void *parameter)
yield();
}
}
-#endif /* ESP32 */
-
-void loop_1Hz()
-{
-#ifdef CYCLE_MODULE_ENABLED
- CyclePrint();
-#endif
-#ifdef BLINK_LED_PIN
- Blink_Process();
-#endif
-}
-
-
-void loop()
-{
- static int loop_cnt_1hz = 0; /*!< counter to allow 1Hz loop cycle */
-
-#ifdef SAMPLE_BUFFER_SIZE
- loop_cnt_1hz += SAMPLE_BUFFER_SIZE;
-#else
- loop_cnt_1hz += 1; /* in case only one sample will be processed per loop cycle */
-#endif
- if (loop_cnt_1hz >= SAMPLE_RATE)
- {
- loop_cnt_1hz -= SAMPLE_RATE;
- loop_1Hz();
- }
-
-#ifdef ADC_ENABLED
- AdcCheck();
-#endif
-
-#ifdef ARP_MODULE_ENABLED
- Arp_Process(1);
-#endif
-
- /*
- * MIDI processing
- */
- Midi_Process();
-
-#ifdef MIDI_VIA_USB_ENABLED
- UsbMidi_ProcessSync();
-#endif
-#ifdef MIDI_STREAM_PLAYER_ENABLED
- MidiStreamPlayer_Tick(SAMPLE_BUFFER_SIZE);
-#endif
-
-#ifdef MIDI_BLE_ENABLED
- midi_ble_loop();
-#endif
-
-#ifdef USB_HOST_ENABLED
- Usb_Host_Midi_loop();
-#endif
-
-#ifdef MIDI_USB_ENABLED
- Midi_Usb_Loop();
-#endif
-
- /*
- * And finally the audio stuff
- */
- Q1_14 left[SAMPLE_BUFFER_SIZE];
- Q1_14 right[SAMPLE_BUFFER_SIZE];
-
- memset(left, 0, sizeof(left));
- memset(right, 0, sizeof(left));
-
- MultiSawSynth_Process(left, right, SAMPLE_BUFFER_SIZE);
-
- Filter_Process_Buffer(left, &mainFiltL, SAMPLE_BUFFER_SIZE);
- Filter_Process_Buffer(right, &mainFiltR, SAMPLE_BUFFER_SIZE);
-
- Slicer_Process(left, right, SAMPLE_BUFFER_SIZE);
-
-#ifdef MAX_DELAY_Q
- DelayQ_Process_Buff(&left[0].s16, &right[0].s16, &left[0].s16, &right[0].s16, SAMPLE_BUFFER_SIZE);
-#endif
-
- /*
- * Output the audio
- */
- Audio_Output(left, right);
-}
-
-void App_NoteOn(uint8_t ch, uint8_t note, uint8_t vel)
-{
-#ifdef ARP_MODULE_ENABLED
- Arp_NoteOn(ch, note, vel);
-#else
- MultiSawSynth_NoteOn(ch, note, vel);
-#endif
-}
-
-void App_NoteOff(uint8_t ch, uint8_t note)
-{
-#ifdef ARP_MODULE_ENABLED
- Arp_NoteOff(ch, note);
-#else
- MultiSawSynth_NoteOff(ch, note);
-#endif
-}
-
-void App_NoteSetPitch(uint8_t ch, uint8_t note, uint32_t pitch)
-{
- MultiSawSynth_NoteSetPitch(ch, note, pitch);
-}
-
-void App_NoteSetVolume(uint8_t ch, uint8_t note, uint16_t volume)
-{
- MultiSawSynth_NoteSetVolume(ch, note, volume);
-}
-
-void App_PitchBend(uint8_t ch, uint16_t bend)
-{
- MultiSawSynth_PitchBend(ch, bend);
-}
-
-void App_ModulationWheel(uint8_t ch, uint8_t value)
-{
- /* not implemented yet */
-}
-
-/*
- * MIDI via USB Host Module
- */
-#ifdef MIDI_VIA_USB_ENABLED
-void App_UsbMidiShortMsgReceived(uint8_t *msg)
-{
-#ifdef MIDI_TX2_PIN
- Midi_SendShortMessage(msg);
-#endif
- Midi_HandleShortMsg(msg, 8);
-}
-#endif
-
-/*
- * MIDI callbacks
- */
-inline void App_ButtonA(uint8_t setting, uint8_t value)
-{
- if (value > 0)
- {
- MultiSawSynth_SetProfile(setting);
- }
-}
-
-inline void App_ButtonCh(uint8_t setting, uint8_t value)
-{
- if (value > 0)
- {
- MultiSawSynth_SetCurrentCh(setting);
- }
-}
-
-inline void App_ButtonSlicer(uint8_t setting, uint8_t value)
-{
- if (value > 0)
- {
- Slicer_SetType(0, setting);
- }
-}
-
-inline void App_SliderSawCtrl(uint8_t id, uint8_t value)
-{
- switch (id)
- {
- case 0:
- MultiSawSynth_SetDetune(value);
- break;
- case 1:
- MultiSawSynth_SetCount(value);
- break;
- case 2:
- MultiSawSynth_SetProfile(value);
- break;
- case 3:
- {
- if (value < 30)
- {
- value = 30;
- }
- if (value > 126)
- {
- value = 126;
- }
- float c = value;
- c *= 1.0f / 127.0f;
- Filter_Calculate(c, 0.5f, &mainFiltC);
- }
- break;
- }
-}
-
-/*
- * Arp Callbacks
- */
-void Arp_Cb_NoteOn(uint8_t ch, uint8_t note, float vel)
-{
- MultiSawSynth_NoteOn(ch, note, vel);
-}
-
-void Arp_Cb_NoteOff(uint8_t ch, uint8_t note)
-{
- MultiSawSynth_NoteOff(ch, note);
-}
-
-void Arp_Status_ValueChangedInt(const char *msg, int value)
-{
- // Status_ValueChangedInt(msg, value);
-}
-
-void Arp_Status_LogMessage(const char *msg)
-{
- //Status_LogMessage(msg);
-}
-
-void Arp_Status_ValueChangedFloat(const char *msg, float value)
-{
- // Status_ValueChangedFloat(msg, value);
-}
-
-void Arp_Cb_Step(uint8_t step)
-{
- /* ignore */
-}
-
-#if defined(I2C_SCL) && defined(I2C_SDA)
-void ScanI2C(void)
-{
-#ifdef ARDUINO_GENERIC_F407VGTX
- Wire.setSDA(I2C_SDA);
- Wire.setSCL(I2C_SCL);
- Wire.begin();//I2C_SDA, I2C_SCL);
-#else
- Wire.begin();
#endif
-
- byte address;
- int nDevices;
-
- Serial.println("Scanning...");
-
- nDevices = 0;
- for (address = 1; address < 127; address++)
- {
- byte r_error;
- // The i2c_scanner uses the return value of
- // the Write.endTransmisstion to see if
- // a device did acknowledge to the address.
- Wire.beginTransmission(address);
- r_error = Wire.endTransmission();
-
- if (r_error == 0)
- {
- Serial.print("I2C device found at address 0x");
- if (address < 16)
- {
- Serial.print("0");
- }
- Serial.print(address, HEX);
- Serial.println(" !");
-
- nDevices++;
- }
- else if (r_error == 4)
- {
- Serial.print("Unknown error at address 0x");
- if (address < 16)
- {
- Serial.print("0");
- }
- Serial.println(address, HEX);
- }
- }
- if (nDevices == 0)
- {
- Serial.println("No I2C devices found\n");
- }
- else
- {
- Serial.println("done\n");
- }
-}
-#endif /* (defined ARDUINO_GENERIC_F407VGTX) || (defined ARDUINO_DISCO_F407VG) */
-
diff --git a/z_config.ino b/z_config.ino
index 9a35be4..7eb5e81 100644
--- a/z_config.ino
+++ b/z_config.ino
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Marcel Licence
+ * Copyright (c) 2026 Marcel Licence
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,6 +47,16 @@
#endif
+#include "config.h"
+#include "app.h"
+
+
+#ifdef REVERB_ENABLED
+#include
+#endif
+#include
+
+
#ifdef AUDIO_KIT_BUTTON_ANALOG
audioKitButtonCb audioKitButtonCallback = NULL;
#endif