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