diff --git a/app.cpp b/app.cpp
new file mode 100644
index 0000000..c2e007b
--- /dev/null
+++ b/app.cpp
@@ -0,0 +1,508 @@
+/*
+ * 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 ml_synth_basic_example.ino
+ * @author Marcel Licence
+ * @date 17.12.2021
+ *
+ * @brief This is the main project file
+ *
+ * The project is shown in this video: @see https://youtu.be/WJGOIgaY-1s
+ */
+
+
+#ifdef __CDT_PARSER__
+#include
+#endif
+
+
+#include "config.h"
+
+
+#include "app.h"
+
+#include
+
+
+#ifdef ESP32
+#include
+#endif
+
+/* requires the ML_SynthTools library: https://github.com/marcel-licence/ML_SynthTools */
+#include
+#ifdef REVERB_ENABLED
+#include
+#endif
+#include
+#ifdef OLED_OSC_DISP_ENABLED
+#include
+#endif
+
+#include
+
+//#include
+
+
+#define ML_SYNTH_INLINE_DECLARATION
+#include
+#undef ML_SYNTH_INLINE_DECLARATION
+
+
+const char shortName[] = "ML_BasicSynth";
+
+
+void App_Setup(void)
+{
+ /*
+ * this code runs once
+ */
+
+#ifdef BLINK_LED_PIN
+ Blink_Setup();
+ Blink_Fast(1);
+#endif
+
+#ifdef ARDUINO_DAISY_SEED
+ DaisySeed_Setup();
+#endif
+
+ delay(1500);
+
+ Serial.begin(115200);
+ delay(1500);
+
+
+ Serial.printf("ml_synth_basic_example Copyright (C) 2024 Marcel Licence\n");
+ Serial.printf("This program comes with ABSOLUTELY NO WARRANTY;\n");
+ Serial.printf("This is free software, and you are welcome to redistribute it\n");
+ Serial.printf("under certain conditions; \n");
+
+ Serial.printf("Initialize Synth Module\n");
+ delay(1000);
+ Synth_Init();
+
+#ifdef REVERB_ENABLED
+ /*
+ * Initialize reverb
+ * The buffer shall be static to ensure that
+ * the memory will be exclusive available for the reverb module
+ */
+#ifdef REVERB_STATIC
+ static float revBuffer[REV_BUFF_SIZE];
+#else
+ static float *revBuffer = (float *)malloc(sizeof(float) * REV_BUFF_SIZE);
+#endif
+ Reverb_Setup(revBuffer);
+#endif
+
+#ifdef MAX_DELAY
+ /*
+ * Prepare a buffer which can be used for the delay
+ */
+#ifdef DELAY_STATIC
+ static int16_t delBuffer1[MAX_DELAY];
+ static int16_t delBuffer2[MAX_DELAY];
+#else
+ static int16_t *delBuffer1 = (int16_t *)malloc(sizeof(int16_t) * MAX_DELAY);
+ static int16_t *delBuffer2 = (int16_t *)malloc(sizeof(int16_t) * MAX_DELAY);
+#endif
+ Delay_Init2(delBuffer1, delBuffer2, MAX_DELAY);
+#endif
+
+ Serial.printf("Initialize Audio Interface\n");
+#ifdef ML_BOARD_SETUP
+ Board_Setup();
+#else
+ Audio_Setup();
+
+ Serial.printf("Initialize Midi Module\n");
+ /*
+ * setup midi module / rx port
+ */
+ Midi_Setup();
+#endif
+
+ Arp_Init(24 * 4); /* slowest tempo one step per bar */
+
+#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());
+#endif
+
+ Serial.printf("Firmware started successfully\n");
+
+#ifdef MIDI_BLE_ENABLED
+ midi_ble_setup();
+#endif
+
+#ifdef MIDI_USB_ENABLED
+ Midi_Usb_Setup();
+#endif
+
+#ifdef NOTE_ON_AFTER_SETUP /* activate this line to get a tone on startup to test the DAC */
+ Synth_NoteOn(0, 64, 1.0f);
+#endif
+}
+
+#ifdef ESP32
+void App_Setup1(void)
+{
+ /*
+ * init your stuff for core0 here
+ */
+
+#ifdef OLED_OSC_DISP_ENABLED
+ ScopeOled_Setup();
+#endif
+
+#ifdef _ADC_TO_MIDI_ENABLED
+ AdcMul_Init();
+#endif
+
+#ifdef MIDI_VIA_USB_ENABLED
+ UsbMidi_Setup();
+#endif
+
+#ifdef PRESSURE_SENSOR_ENABLED
+ PressureSetup();
+#endif
+}
+
+void App_Loop1(void)
+{
+ /*
+ * put your loop stuff for core0 here
+ */
+#ifdef _ADC_TO_MIDI_ENABLED
+#ifdef MIDI_VIA_USB_ENABLED
+ static uint8_t adc_prescaler = 0;
+ adc_prescaler++;
+ if (adc_prescaler > 15) /* use prescaler when USB is active because it is very time consuming */
+#endif /* MIDI_VIA_USB_ENABLED */
+ {
+ adc_prescaler = 0;
+ AdcMul_Process();
+ }
+#endif /* ADC_TO_MIDI_ENABLED */
+#ifdef MIDI_VIA_USB_ENABLED
+ UsbMidi_Loop();
+#endif
+
+#ifdef _MCP23_MODULE_ENABLED
+ MCP23_Loop();
+#endif
+
+#ifdef OLED_OSC_DISP_ENABLED
+ ScopeOled_Process();
+#endif
+
+#ifdef PRESSURE_SENSOR_ENABLED
+ PressureLoop();
+#endif
+}
+#endif /* ESP32 */
+
+static uint32_t midi_sync = 0;
+
+void Midi_SyncRecvd(void)
+{
+ midi_sync += 1;
+}
+
+void Synth_RealTimeMsg(uint8_t msg)
+{
+#ifndef MIDI_SYNC_MASTER
+ switch (msg)
+ {
+ case 0xfa: /* start */
+ Arp_Reset();
+ break;
+ case 0xf8: /* Timing Clock */
+ Midi_SyncRecvd();
+ break;
+ }
+#endif
+}
+
+#ifdef MIDI_SYNC_MASTER
+
+#define MIDI_PPQ 24
+#define SAMPLES_PER_MIN (SAMPLE_RATE*60)
+
+static float midi_tempo = 120.0f;
+
+void MidiSyncMasterLoop(void)
+{
+ static float midiDiv = 0;
+ midiDiv += SAMPLE_BUFFER_SIZE;
+ if (midiDiv >= (SAMPLES_PER_MIN) / (MIDI_PPQ * midi_tempo))
+ {
+ midiDiv -= (SAMPLES_PER_MIN) / (MIDI_PPQ * midi_tempo);
+ Midi_SyncRecvd();
+ }
+}
+
+void Synth_SetMidiMasterTempo(uint8_t unused __attribute__((unused)), float val)
+{
+ midi_tempo = 60.0f + val * (240.0f - 60.0f);
+}
+
+#endif
+
+void Synth_SongPosition(uint16_t pos)
+{
+ Serial.printf("Songpos: %d\n", pos);
+ if (pos == 0)
+ {
+ Arp_Reset();
+ }
+}
+
+void Synth_SongPosReset(uint8_t unused __attribute__((unused)), float var)
+{
+ if (var > 0)
+ {
+ Synth_SongPosition(0);
+ }
+}
+
+/*
+ * use this if something should happen every second
+ * - you can drive a blinking LED for example
+ */
+inline void Loop_1Hz(void)
+{
+#ifdef BLINK_LED_PIN
+ Blink_Process();
+#endif
+}
+
+
+/*
+ * our main loop
+ * - all is done in a blocking context
+ * - do not block the loop otherwise you will get problems with your audio
+ */
+static float left[SAMPLE_BUFFER_SIZE];
+static float right[SAMPLE_BUFFER_SIZE];
+#ifdef REVERB_ENABLED
+static float mono[SAMPLE_BUFFER_SIZE];
+#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_1Hz();
+ loop_cnt_1hz = 0;
+ }
+
+#ifdef MIDI_SYNC_MASTER
+ MidiSyncMasterLoop();
+#endif
+
+#ifdef ARP_MODULE_ENABLED
+ Arp_Process(midi_sync);
+ midi_sync = 0;
+#endif
+
+ /*
+ * MIDI processing
+ */
+ Midi_Process();
+#ifdef MIDI_VIA_USB_ENABLED
+ UsbMidi_ProcessSync();
+#endif
+
+#ifdef MIDI_BLE_ENABLED
+ midi_ble_loop();
+#endif
+
+#ifdef MIDI_USB_ENABLED
+ Midi_Usb_Loop();
+#endif
+
+ /* zero buffer, otherwise you can pass trough an input signal */
+ memset(left, 0, sizeof(left));
+ memset(right, 0, sizeof(right));
+
+#ifdef AUDIO_PASS_THROUGH
+ Audio_Input(left, right);
+#endif
+
+ /*
+ * Process synthesizer core
+ */
+ Synth_Process(left, right, SAMPLE_BUFFER_SIZE);
+
+#ifdef MAX_DELAY
+ /*
+ * process delay line
+ */
+ Delay_Process_Buff2(left, right, SAMPLE_BUFFER_SIZE);
+#endif
+
+ /*
+ * add some mono reverb
+ */
+#ifdef REVERB_ENABLED
+ for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
+ {
+ mono[i] = 0.5f * (left[i] + right[i]);
+ }
+ Reverb_Process(mono, SAMPLE_BUFFER_SIZE);
+ for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
+ {
+ left[i] += mono[i];
+ right[i] += mono[i];
+ }
+#endif
+
+ /*
+ * Output the audio
+ */
+ Audio_Output(left, right);
+
+#ifdef OLED_OSC_DISP_ENABLED
+ ScopeOled_AddSamples(left, right, SAMPLE_BUFFER_SIZE);
+#endif
+}
+
+/*
+ * Callbacks
+ */
+void Arp_Cb_NoteOn(uint8_t ch, uint8_t note, float vel)
+{
+ Synth_NoteOn(ch, note, vel);
+}
+
+void Arp_Cb_NoteOff(uint8_t ch, uint8_t note)
+{
+ Synth_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 */
+}
+
+/*
+ * MIDI via USB Host Module
+ */
+#ifdef MIDI_VIA_USB_ENABLED
+void App_UsbMidiShortMsgReceived(uint8_t *msg)
+{
+ Midi_SendShortMessage(msg);
+ Midi_HandleShortMsg(msg, 8);
+}
+#endif
+
+/*
+ * Test functions
+ */
+#if defined(I2C_SCL) && defined (I2C_SDA) && (!defined ARDUINO_DISCO_F407VG)
+void ScanI2C(void)
+{
+
+ Wire.begin(I2C_SDA, I2C_SCL);
+
+ 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
+
diff --git a/app.h b/app.h
new file mode 100644
index 0000000..7d579d4
--- /dev/null
+++ b/app.h
@@ -0,0 +1,62 @@
+/*
+ * 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 08.03.2026
+ *
+ * @brief Declarations of the app
+ */
+
+
+#ifndef APP_H_
+#define APP_H_
+
+
+#include
+
+
+void App_Setup(void);
+void App_Loop(void);
+
+void App_Setup1(void);
+void App_Loop1(void);
+
+
+void Synth_Init(void);
+void Synth_SongPosition(uint16_t pos);
+void Synth_RealTimeMsg(uint8_t msg);
+void Synth_Process(float *left, float *right, uint32_t len);
+void Synth_NoteOn(uint8_t ch, uint8_t note, float vel __attribute__((unused)));
+void Synth_NoteOff(uint8_t ch, uint8_t note);
+
+
+#endif /* APP_H_ */
diff --git a/easySynth.ino b/easySynth.ino
index 781d7ec..88c3259 100644
--- a/easySynth.ino
+++ b/easySynth.ino
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 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
@@ -42,6 +42,9 @@
#endif
+#include "config.h"
+
+
#include
#include
#include
@@ -276,7 +279,7 @@ uint32_t voc_act = 0;
static float justOne = 1.0f;
-void Synth_Init()
+void Synth_Init(void)
{
#ifdef ESP32
randomSeed(34547379);
@@ -507,7 +510,7 @@ float GetModulation(uint8_t ch)
const float postGain = 1.0f / ((float)MAX_POLY_OSC);
//[[gnu::noinline, gnu::optimize ("fast-math")]]
-inline void Synth_Process(float *left, float *right, uint32_t len)
+void Synth_Process(float *left, float *right, uint32_t len)
{
/*
* update pitch bending / modulation
@@ -665,7 +668,7 @@ static struct notePlayerT *getFreeVoice(void)
return NULL;
}
-inline void Synth_NoteOn(uint8_t ch, uint8_t note, float vel __attribute__((unused)))
+void Synth_NoteOn(uint8_t ch, uint8_t note, float vel __attribute__((unused)))
{
struct notePlayerT *voice = getFreeVoice();
struct oscillatorT *osc = getFreeOsc();
@@ -802,7 +805,7 @@ inline void Synth_NoteOn(uint8_t ch, uint8_t note, float vel __attribute__((unus
Filter_Process(&voice->lastSample[1][0], &voice->filterR);
}
-inline void Synth_NoteOff(uint8_t ch, uint8_t note)
+void Synth_NoteOff(uint8_t ch, uint8_t note)
{
for (uint32_t j = 0; j < chCfg[ch].noteCnt; j++)
{
diff --git a/ml_inline.ino b/ml_inline.ino
index 1fecd6c..a410647 100644
--- a/ml_inline.ino
+++ b/ml_inline.ino
@@ -1,4 +1,54 @@
+/*
+ * 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 ml_inline.ino
+ * @author Marcel Licence
+ *
+ * @brief This file inlines library functions
+ * @see https://github.com/marcel-licence/ML_SynthTools
+ */
+
+
+#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_basic_example.ino b/ml_synth_basic_example.ino
index 070492f..93509ed 100644
--- a/ml_synth_basic_example.ino
+++ b/ml_synth_basic_example.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
@@ -29,513 +29,107 @@
*/
/**
- * @file ml_synth_basic_example.ino
+ * @file ml_synth_organ_example.ino
* @author Marcel Licence
- * @date 17.12.2021
+ * @date 21.03.2026
*
- * @brief This is the main project file
- *
- * The project is shown in this video: @see https://youtu.be/WJGOIgaY-1s
+ * @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
-
-
-#ifdef ESP32
-#include
+#if (defined ESP32) && (SOC_CPU_CORES_NUM > 1)
+void Core0TaskInit(void);
+void Core0Task(void *parameter);
#endif
-/* requires the ML_SynthTools library: https://github.com/marcel-licence/ML_SynthTools */
-#include
-#ifdef REVERB_ENABLED
-#include
-#endif
-#include
-#ifdef OLED_OSC_DISP_ENABLED
-#include
+#ifdef ARDUINO_RP2040
+volatile bool g_setup_done = false;
#endif
-#include
-
-//#include
-
-
-#define ML_SYNTH_INLINE_DECLARATION
-#include
-#undef ML_SYNTH_INLINE_DECLARATION
-
-
-const char shortName[] = "ML_BasicSynth";
-
void setup()
{
- /*
- * this code runs once
- */
-
-#ifdef BLINK_LED_PIN
- Blink_Setup();
- Blink_Fast(1);
-#endif
-
-#ifdef ARDUINO_DAISY_SEED
- DaisySeed_Setup();
-#endif
-
- delay(1500);
-
Serial.begin(115200);
- delay(1500);
-
-
- Serial.printf("ml_synth_basic_example Copyright (C) 2024 Marcel Licence\n");
- Serial.printf("This program comes with ABSOLUTELY NO WARRANTY;\n");
- Serial.printf("This is free software, and you are welcome to redistribute it\n");
- Serial.printf("under certain conditions; \n");
-
- Serial.printf("Initialize Synth Module\n");
- delay(1000);
- Synth_Init();
-
-#ifdef REVERB_ENABLED
- /*
- * Initialize reverb
- * The buffer shall be static to ensure that
- * the memory will be exclusive available for the reverb module
- */
-#ifdef REVERB_STATIC
- static float revBuffer[REV_BUFF_SIZE];
-#else
- static float *revBuffer = (float *)malloc(sizeof(float) * REV_BUFF_SIZE);
-#endif
- Reverb_Setup(revBuffer);
-#endif
-
-#ifdef MAX_DELAY
- /*
- * Prepare a buffer which can be used for the delay
- */
-#ifdef DELAY_STATIC
- static int16_t delBuffer1[MAX_DELAY];
- static int16_t delBuffer2[MAX_DELAY];
-#else
- static int16_t *delBuffer1 = (int16_t *)malloc(sizeof(int16_t) * MAX_DELAY);
- static int16_t *delBuffer2 = (int16_t *)malloc(sizeof(int16_t) * MAX_DELAY);
-#endif
- Delay_Init2(delBuffer1, delBuffer2, MAX_DELAY);
-#endif
-
- Serial.printf("Initialize Audio Interface\n");
-#ifdef ML_BOARD_SETUP
- Board_Setup();
-#else
- Audio_Setup();
-
- Serial.printf("Initialize Midi Module\n");
- /*
- * setup midi module / rx port
- */
- Midi_Setup();
-#endif
+ App_Setup();
- Arp_Init(24 * 4); /* slowest tempo one step per bar */
-
-#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());
-#endif
-
- Serial.printf("Firmware started successfully\n");
-
-#ifdef MIDI_BLE_ENABLED
- midi_ble_setup();
+#ifdef ARDUINO_RP2040
+ g_setup_done = true;
#endif
-#ifdef MIDI_USB_ENABLED
- Midi_Usb_Setup();
-#endif
-
-#ifdef NOTE_ON_AFTER_SETUP /* activate this line to get a tone on startup to test the DAC */
- Synth_NoteOn(0, 64, 1.0f);
-#endif
-
-#if (defined ADC_TO_MIDI_ENABLED) || (defined MIDI_VIA_USB_ENABLED) || (defined OLED_OSC_DISP_ENABLED)
-#ifdef ESP32
+#if (defined ESP32) && (SOC_CPU_CORES_NUM > 1)
Core0TaskInit();
-#else
-#error only supported by ESP32 platform
-#endif
#endif
}
-#ifdef ESP32
-/*
- * Core 0
- */
-/* this is used to add a task to core 0 */
-TaskHandle_t Core0TaskHnd;
-
-inline
-void Core0TaskInit()
-{
- /* we need a second task for the terminal output */
- xTaskCreatePinnedToCore(Core0Task, "CoreTask0", 8000, NULL, 999, &Core0TaskHnd, 0);
-}
-
-void Core0TaskSetup()
+void loop()
{
- /*
- * init your stuff for core0 here
- */
-
-#ifdef OLED_OSC_DISP_ENABLED
- ScopeOled_Setup();
-#endif
-
-#ifdef _ADC_TO_MIDI_ENABLED
- AdcMul_Init();
-#endif
-
-#ifdef MIDI_VIA_USB_ENABLED
- UsbMidi_Setup();
-#endif
-
-#ifdef PRESSURE_SENSOR_ENABLED
- PressureSetup();
-#endif
+ App_Loop();
}
-void Core0TaskLoop()
-{
- /*
- * put your loop stuff for core0 here
- */
-#ifdef _ADC_TO_MIDI_ENABLED
-#ifdef MIDI_VIA_USB_ENABLED
- static uint8_t adc_prescaler = 0;
- adc_prescaler++;
- if (adc_prescaler > 15) /* use prescaler when USB is active because it is very time consuming */
-#endif /* MIDI_VIA_USB_ENABLED */
- {
- adc_prescaler = 0;
- AdcMul_Process();
- }
-#endif /* ADC_TO_MIDI_ENABLED */
-#ifdef MIDI_VIA_USB_ENABLED
- UsbMidi_Loop();
-#endif
-
-#ifdef _MCP23_MODULE_ENABLED
- MCP23_Loop();
-#endif
-
-#ifdef OLED_OSC_DISP_ENABLED
- ScopeOled_Process();
-#endif
+#ifdef ARDUINO_RP2040
-#ifdef PRESSURE_SENSOR_ENABLED
- PressureLoop();
-#endif
-}
-
-void Core0Task(void *parameter)
+void wait_until_setup_finished(void)
{
- Core0TaskSetup();
-
- while (true)
+ while (!g_setup_done)
{
- Core0TaskLoop();
-
- /* this seems necessary to trigger the watchdog */
delay(1);
- yield();
}
}
-#endif /* ESP32 */
-static uint32_t midi_sync = 0;
-
-void Midi_SyncRecvd(void)
+void setup1()
{
- midi_sync += 1;
+ wait_until_setup_finished();
+ App_Setup1();
}
-void Synth_RealTimeMsg(uint8_t msg)
+void loop1()
{
-#ifndef MIDI_SYNC_MASTER
- switch (msg)
- {
- case 0xfa: /* start */
- Arp_Reset();
- break;
- case 0xf8: /* Timing Clock */
- Midi_SyncRecvd();
- break;
- }
-#endif
+ App_Loop1();
}
-
-#ifdef MIDI_SYNC_MASTER
-
-#define MIDI_PPQ 24
-#define SAMPLES_PER_MIN (SAMPLE_RATE*60)
-
-static float midi_tempo = 120.0f;
-
-void MidiSyncMasterLoop(void)
-{
- static float midiDiv = 0;
- midiDiv += SAMPLE_BUFFER_SIZE;
- if (midiDiv >= (SAMPLES_PER_MIN) / (MIDI_PPQ * midi_tempo))
- {
- midiDiv -= (SAMPLES_PER_MIN) / (MIDI_PPQ * midi_tempo);
- Midi_SyncRecvd();
- }
-}
-
-void Synth_SetMidiMasterTempo(uint8_t unused __attribute__((unused)), float val)
-{
- midi_tempo = 60.0f + val * (240.0f - 60.0f);
-}
-
#endif
-void Synth_SongPosition(uint16_t pos)
-{
- Serial.printf("Songpos: %d\n", pos);
- if (pos == 0)
- {
- Arp_Reset();
- }
-}
-
-void Synth_SongPosReset(uint8_t unused __attribute__((unused)), float var)
-{
- if (var > 0)
- {
- Synth_SongPosition(0);
- }
-}
+#if (defined ESP32) && (SOC_CPU_CORES_NUM > 1)
/*
- * use this if something should happen every second
- * - you can drive a blinking LED for example
+ * Core 0
*/
-inline void Loop_1Hz(void)
+/* this is used to add a task to core 0 */
+TaskHandle_t Core0TaskHnd;
+
+void Core0TaskInit(void)
{
-#ifdef BLINK_LED_PIN
- Blink_Process();
-#endif
+ /* we need a second task for the terminal output */
+ xTaskCreatePinnedToCore(Core0Task, "CoreTask0", 8000, NULL, 4, &Core0TaskHnd, 0);
}
-
-/*
- * our main loop
- * - all is done in a blocking context
- * - do not block the loop otherwise you will get problems with your audio
- */
-static float left[SAMPLE_BUFFER_SIZE];
-static float right[SAMPLE_BUFFER_SIZE];
-#ifdef REVERB_ENABLED
-static float mono[SAMPLE_BUFFER_SIZE];
-#endif
-
-void loop()
+void Core0TaskSetup(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_1Hz();
- loop_cnt_1hz = 0;
- }
-
-#ifdef MIDI_SYNC_MASTER
- MidiSyncMasterLoop();
-#endif
-
-#ifdef ARP_MODULE_ENABLED
- Arp_Process(midi_sync);
- midi_sync = 0;
-#endif
-
- /*
- * MIDI processing
- */
- Midi_Process();
-#ifdef MIDI_VIA_USB_ENABLED
- UsbMidi_ProcessSync();
-#endif
-
-#ifdef MIDI_BLE_ENABLED
- midi_ble_loop();
-#endif
-
-#ifdef MIDI_USB_ENABLED
- Midi_Usb_Loop();
-#endif
-
- /* zero buffer, otherwise you can pass trough an input signal */
- memset(left, 0, sizeof(left));
- memset(right, 0, sizeof(right));
-
-#ifdef AUDIO_PASS_THROUGH
- Audio_Input(left, right);
-#endif
-
/*
- * Process synthesizer core
- */
- Synth_Process(left, right, SAMPLE_BUFFER_SIZE);
-
-#ifdef MAX_DELAY
- /*
- * process delay line
- */
- Delay_Process_Buff2(left, right, SAMPLE_BUFFER_SIZE);
-#endif
-
- /*
- * add some mono reverb
- */
-#ifdef REVERB_ENABLED
- for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
- {
- mono[i] = 0.5f * (left[i] + right[i]);
- }
- Reverb_Process(mono, SAMPLE_BUFFER_SIZE);
- for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
- {
- left[i] += mono[i];
- right[i] += mono[i];
- }
-#endif
-
- /*
- * Output the audio
+ * init your stuff for core0 here
*/
- Audio_Output(left, right);
-
-#ifdef OLED_OSC_DISP_ENABLED
- ScopeOled_AddSamples(left, right, SAMPLE_BUFFER_SIZE);
-#endif
-}
-
-/*
- * Callbacks
- */
-void Arp_Cb_NoteOn(uint8_t ch, uint8_t note, float vel)
-{
- Synth_NoteOn(ch, note, vel);
+ App_Setup1();
}
-void Arp_Cb_NoteOff(uint8_t ch, uint8_t note)
+void Core0TaskLoop(void)
{
- Synth_NoteOff(ch, note);
+ App_Loop1();
}
-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 */
-}
-
-/*
- * MIDI via USB Host Module
- */
-#ifdef MIDI_VIA_USB_ENABLED
-void App_UsbMidiShortMsgReceived(uint8_t *msg)
-{
- Midi_SendShortMessage(msg);
- Midi_HandleShortMsg(msg, 8);
-}
-#endif
-
-/*
- * Test functions
- */
-#if defined(I2C_SCL) && defined (I2C_SDA) && (!defined ARDUINO_DISCO_F407VG)
-void ScanI2C(void)
+void Core0Task(void *parameter)
{
+ Core0TaskSetup();
- Wire.begin(I2C_SDA, I2C_SCL);
-
- byte address;
- int nDevices;
-
- Serial.println("Scanning...");
-
- nDevices = 0;
- for (address = 1; address < 127; address++)
+ while (true)
{
- 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(" !");
+ Core0TaskLoop();
- 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");
+ /* this seems necessary to trigger the watchdog */
+ delay(1);
+ yield();
}
}
#endif
-
diff --git a/z_config.ino b/z_config.ino
index 676141b..6d0e56c 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,20 @@
#endif
+#include "config.h"
+#include "app.h"
+#include
+#ifdef REVERB_ENABLED
+#include
+#endif
+#include
+
+
+#define ML_SYNTH_INLINE_DECLARATION
+#include
+#undef ML_SYNTH_INLINE_DECLARATION
+
+
#ifdef AUDIO_KIT_BUTTON_ANALOG
audioKitButtonCb audioKitButtonCallback = App_ButtonCb;
#endif