diff --git a/Digital-Synth-PRA32-U/Digital-Synth-PRA32-U.ino b/Digital-Synth-PRA32-U/Digital-Synth-PRA32-U.ino index 31998dc..2e14429 100644 --- a/Digital-Synth-PRA32-U/Digital-Synth-PRA32-U.ino +++ b/Digital-Synth-PRA32-U/Digital-Synth-PRA32-U.ino @@ -2,6 +2,8 @@ * Digital Synth PRA32-U */ +#define PRA32_U_VERSION "v2.3.1 " + //#define PRA32_U_USE_DEBUG_PRINT // Serial1 #define PRA32_U_USE_USB_MIDI // Select USB Stack: "Adafruit TinyUSB" in the Arduino IDE "Tools" menu @@ -16,13 +18,14 @@ #define PRA32_U_MIDI_CH (0) // 0-based -// for Pimoroni Pico Audio Pack [PIM544] +// for Pimoroni Pico Audio Pack (PIM544) #define PRA32_U_I2S_DAC_MUTE_OFF_PIN (22) #define PRA32_U_I2S_DATA_PIN (9) //#define PRA32_U_I2S_MCLK_PIN (0) //#define PRA32_U_I2S_MCLK_MULT (0) #define PRA32_U_I2S_BCLK_PIN (10) // LRCLK Pin is PRA32_U_I2S_BCLK_PIN + 1 #define PRA32_U_I2S_SWAP_BCLK_AND_LRCLK_PINS (false) +#define PRA32_U_I2S_SWAP_LEFT_AND_RIGHT (false) #define PRA32_U_I2S_BUFFERS (4) #define PRA32_U_I2S_BUFFER_WORDS (64) @@ -33,19 +36,50 @@ #define PRA32_U_PWM_AUDIO_L_PIN (28) #define PRA32_U_PWM_AUDIO_R_PIN (27) -//#define PRA32_U_USE_PWM_AUDIO_DITHERING_INSTEAD_OF_ERROR_DIFFUSION - #define PRA32_U_USE_2_CORES_FOR_SIGNAL_PROCESSING #define PRA32_U_USE_EMULATED_EEPROM //////////////////////////////////////////////////////////////// +//#define PRA32_U_USE_CONTROL_PANEL // Experimental + +#define PRA32_U_USE_CONTROL_PANEL_KEY_INPUT // Use tactile switches +#define PRA32_U_KEY_INPUT_ACTIVE_LEVEL (HIGH) +#define PRA32_U_KEY_INPUT_PREV_KEY_PIN (16) +#define PRA32_U_KEY_INPUT_NEXT_KEY_PIN (18) +#define PRA32_U_KEY_INPUT_PLAY_KEY_PIN (20) +#define PRA32_U_KEY_ANTI_CHATTERING_WAIT (15) + +#define PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT // Use ADC0, ADC1, and ADC2 +#define PRA32_U_ANALOG_INPUT_REVERSED (true) +#define PRA32_U_ANALOG_INPUT_CORRECTION (-504) +#define PRA32_U_ANALOG_INPUT_THRESHOLD (504) +#define PRA32_U_ANALOG_INPUT_DENOMINATOR (504) + +#define PRA32_U_USE_CONTROL_PANEL_OLED_DISPLAY // Use SSD1306 monochrome 128x64 OLED +#define PRA32_U_OLED_DISPLAY_I2C (i2c1) +#define PRA32_U_OLED_DISPLAY_I2C_SDA_PIN (6) +#define PRA32_U_OLED_DISPLAY_I2C_SCL_PIN (7) +#define PRA32_U_OLED_DISPLAY_I2C_ADDRESS (0x3C) +#define PRA32_U_OLED_DISPLAY_CONTRAST (0xFF) +#define PRA32_U_OLED_DISPLAY_ROTATION (true) + +//////////////////////////////////////////////////////////////// + +#include "hardware/adc.h" + +#if defined(PRA32_U_USE_CONTROL_PANEL) +extern void PRA32_U_ControlPanel_on_control_change(uint8_t control_number); +#endif // defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + #include "pra32-u-common.h" #include "pra32-u-synth.h" PRA32_U_Synth g_synth; +#include "pra32-u-control-panel.h" + #include #if defined(PRA32_U_USE_USB_MIDI) #include @@ -66,17 +100,65 @@ PWMAudio g_pwm_r(PRA32_U_PWM_AUDIO_R_PIN); #include I2S g_i2s_output(OUTPUT); +static volatile uint32_t s_debug_measurement_elapsed0_us = 0; +static volatile uint32_t s_debug_measurement_max0_us = 0; +static volatile uint32_t s_debug_measurement_elapsed1_us = 0; +static volatile uint32_t s_debug_measurement_max1_us = 0; + void handleNoteOn(byte channel, byte pitch, byte velocity); void handleNoteOff(byte channel, byte pitch, byte velocity); void handleControlChange(byte channel, byte number, byte value); void handleHandleProgramChange(byte channel, byte number); void handleHandlePitchBend(byte channel, int bend); +void writeProgramsToFlashAndEndSketch(); void __not_in_flash_func(setup1)() { + PRA32_U_ControlPanel_setup(); + +#if defined(PRA32_U_USE_DEBUG_PRINT) + Serial1.setTX(0); + Serial1.setRX(1); + Serial1.begin(115200); +#endif // defined(PRA32_U_USE_DEBUG_PRINT) } void __not_in_flash_func(loop1)() { - g_synth.secondary_core_process(); + boolean processed = g_synth.secondary_core_process(); + if (processed) { + static uint32_t s_loop_counter = 0; + s_loop_counter++; + if (s_loop_counter >= 16 * 400) { + s_loop_counter = 0; + } + + PRA32_U_ControlPanel_update_analog_inputs(s_loop_counter); + PRA32_U_ControlPanel_update_display_buffer(s_loop_counter); + PRA32_U_ControlPanel_update_display(s_loop_counter); + +#if defined(PRA32_U_USE_DEBUG_PRINT) + switch (s_loop_counter) { + case 1 * 400: + Serial1.print("\e[1;1H\e[K"); + Serial1.print(s_debug_measurement_elapsed1_us); + break; + case 2 * 400: + Serial1.print("\e[2;1H\e[K"); + Serial1.print(s_debug_measurement_max1_us); + break; + case 3 * 400: + Serial1.print("\e[4;1H\e[K"); + Serial1.print(s_debug_measurement_elapsed0_us); + break; + case 4 * 400: + Serial1.print("\e[5;1H\e[K"); + Serial1.print(s_debug_measurement_max0_us); + break; + default: + PRA32_U_ControlPanel_debug_print(s_loop_counter); + break; + } +#endif // defined(PRA32_U_USE_DEBUG_PRINT) + } } void __not_in_flash_func(setup)() { @@ -142,12 +224,6 @@ void __not_in_flash_func(setup)() { Serial2.begin(PRA32_U_UART_MIDI_SPEED); #endif // defined(PRA32_U_USE_UART_MIDI) -#if defined(PRA32_U_USE_DEBUG_PRINT) - Serial1.setTX(0); - Serial1.setRX(1); - Serial1.begin(115200); -#endif // defined(PRA32_U_USE_DEBUG_PRINT) - #if defined(ARDUINO_RASPBERRY_PI_PICO) pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); @@ -167,6 +243,10 @@ void __not_in_flash_func(setup)() { #endif // defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) g_synth.initialize(); + + PRA32_U_ControlPanel_initialize_parameters(); + + delay(100); } void __not_in_flash_func(loop)() { @@ -185,6 +265,8 @@ void __not_in_flash_func(loop)() { #endif } + PRA32_U_ControlPanel_update_control(); + #if defined(PRA32_U_USE_DEBUG_PRINT) uint32_t debug_measurement_start1_us = micros(); #endif // defined(PRA32_U_USE_DEBUG_PRINT) @@ -214,42 +296,29 @@ void __not_in_flash_func(loop)() { } #else // defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) for (uint32_t i = 0; i < PRA32_U_I2S_BUFFER_WORDS; i++) { - g_i2s_output.write16(left_buffer[i], right_buffer[i]); + if (PRA32_U_I2S_SWAP_LEFT_AND_RIGHT) { + g_i2s_output.write16(right_buffer[i], left_buffer[i]); + } else { + g_i2s_output.write16(left_buffer[i], right_buffer[i]); + } } #endif // defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) #if defined(PRA32_U_USE_DEBUG_PRINT) - static uint32_t s_debug_measurement_max0_us = 0; - uint32_t debug_measurement_elapsed0_us = debug_measurement_end_us - debug_measurement_start0_us; - s_debug_measurement_max0_us += (debug_measurement_elapsed0_us > s_debug_measurement_max0_us) * - (debug_measurement_elapsed0_us - s_debug_measurement_max0_us); - - static uint32_t s_debug_measurement_max1_us = 0; - uint32_t debug_measurement_elapsed1_us = debug_measurement_end_us - debug_measurement_start1_us; - s_debug_measurement_max1_us += (debug_measurement_elapsed1_us > s_debug_measurement_max1_us) * - (debug_measurement_elapsed1_us - s_debug_measurement_max1_us); - - static uint32_t s_debug_loop_counter = 0; - if (++s_debug_loop_counter == 4000) { - s_debug_loop_counter = 0; - - Serial1.println(debug_measurement_elapsed1_us); - Serial1.println(s_debug_measurement_max1_us); - Serial1.println(debug_measurement_elapsed0_us); - Serial1.println(s_debug_measurement_max0_us); - Serial1.println(); - } + s_debug_measurement_elapsed0_us = debug_measurement_end_us - debug_measurement_start0_us; + s_debug_measurement_max0_us += (s_debug_measurement_elapsed0_us > s_debug_measurement_max0_us) * + (s_debug_measurement_elapsed0_us - s_debug_measurement_max0_us); + + s_debug_measurement_elapsed1_us = debug_measurement_end_us - debug_measurement_start1_us; + s_debug_measurement_max1_us += (s_debug_measurement_elapsed1_us > s_debug_measurement_max1_us) * + (s_debug_measurement_elapsed1_us - s_debug_measurement_max1_us); #endif // defined(PRA32_U_USE_DEBUG_PRINT) } void __not_in_flash_func(handleNoteOn)(byte channel, byte pitch, byte velocity) { if ((channel - 1) == PRA32_U_MIDI_CH) { - if (velocity > 0) { - g_synth.note_on(pitch, velocity); - } else { - g_synth.note_off(pitch); - } + g_synth.note_on(pitch, velocity); } } diff --git a/Digital-Synth-PRA32-U/pra32-u-control-panel-font-table.h b/Digital-Synth-PRA32-U/pra32-u-control-panel-font-table.h new file mode 100644 index 0000000..fee7c14 --- /dev/null +++ b/Digital-Synth-PRA32-U/pra32-u-control-panel-font-table.h @@ -0,0 +1,772 @@ +#pragma once + +uint8_t g_control_panel_font_table[128][6] = { + 0b01111111, + 0b01111111, + 0b01111111, + 0b01111111, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01111111, + 0b01111111, + 0b01111111, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b00010100, + 0b01111111, + 0b00010100, + 0b01111111, + 0b00010100, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b00100010, + 0b01111111, + 0b00100010, + 0b01111111, + 0b00100010, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b00000000, + 0b00011100, + 0b00100010, + 0b01000001, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01000001, + 0b00100010, + 0b00011100, + 0b00000000, + 0b00000000, + 0b00100010, + 0b00010100, + 0b01111111, + 0b00010100, + 0b00100010, + 0b00000000, + 0b00001000, + 0b00001000, + 0b00111110, + 0b00001000, + 0b00001000, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00001000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00110000, + 0b00110000, + 0b00000000, + 0b00000000, + 0b00100000, + 0b00010000, + 0b00001000, + 0b00000100, + 0b00000010, + 0b00000000, + 0b00111110, + 0b01000001, + 0b01000001, + 0b01000001, + 0b00111110, + 0b00000000, + 0b00000000, + 0b01000010, + 0b01111111, + 0b01000000, + 0b00000000, + 0b00000000, + 0b01000010, + 0b01100001, + 0b01010001, + 0b01001001, + 0b01000110, + 0b00000000, + 0b00100010, + 0b01000001, + 0b01001001, + 0b01001001, + 0b00110110, + 0b00000000, + 0b00011000, + 0b00010100, + 0b00010010, + 0b01111111, + 0b00010000, + 0b00000000, + 0b00100111, + 0b01000101, + 0b01000101, + 0b01000101, + 0b00111001, + 0b00000000, + 0b00111100, + 0b01001010, + 0b01001001, + 0b01001001, + 0b00110000, + 0b00000000, + 0b00000011, + 0b00000001, + 0b01110001, + 0b00001101, + 0b00000011, + 0b00000000, + 0b00110110, + 0b01001001, + 0b01001001, + 0b01001001, + 0b00110110, + 0b00000000, + 0b00000110, + 0b01001001, + 0b01001001, + 0b00101001, + 0b00011110, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00110110, + 0b00110110, + 0b00000000, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b00001000, + 0b00010100, + 0b00100010, + 0b01000001, + 0b00000000, + 0b00000000, + 0b00010100, + 0b00010100, + 0b00010100, + 0b00010100, + 0b00010100, + 0b00000000, + 0b00000000, + 0b01000001, + 0b00100010, + 0b00010100, + 0b00001000, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01111111, + 0b01111111, + 0b01111111, + 0b01111111, + 0b00000000, + 0b01111110, + 0b00010001, + 0b00010001, + 0b00010001, + 0b01111110, + 0b00000000, + 0b01111111, + 0b01001001, + 0b01001001, + 0b01001001, + 0b00110110, + 0b00000000, + 0b00111110, + 0b01000001, + 0b01000001, + 0b01000001, + 0b00100010, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b00100010, + 0b00011100, + 0b00000000, + 0b01111111, + 0b01001001, + 0b01001001, + 0b01001001, + 0b01000001, + 0b00000000, + 0b01111111, + 0b00001001, + 0b00001001, + 0b00001001, + 0b00000001, + 0b00000000, + 0b00111110, + 0b01000001, + 0b01001001, + 0b01001001, + 0b00111010, + 0b00000000, + 0b01111111, + 0b00001000, + 0b00001000, + 0b00001000, + 0b01111111, + 0b00000000, + 0b00000000, + 0b01000001, + 0b01111111, + 0b01000001, + 0b00000000, + 0b00000000, + 0b00100000, + 0b01000000, + 0b01000001, + 0b00111111, + 0b00000001, + 0b00000000, + 0b01111111, + 0b00001000, + 0b00010100, + 0b00100010, + 0b01000001, + 0b00000000, + 0b01111111, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b00000000, + 0b01111111, + 0b00000010, + 0b00001100, + 0b00000010, + 0b01111111, + 0b00000000, + 0b01111111, + 0b00000100, + 0b00001000, + 0b00010000, + 0b01111111, + 0b00000000, + 0b00111110, + 0b01000001, + 0b01000001, + 0b01000001, + 0b00111110, + 0b00000000, + 0b01111111, + 0b00001001, + 0b00001001, + 0b00001001, + 0b00000110, + 0b00000000, + 0b00111110, + 0b01000001, + 0b01010001, + 0b00100001, + 0b01011110, + 0b00000000, + 0b01111111, + 0b00001001, + 0b00011001, + 0b00101001, + 0b01000110, + 0b00000000, + 0b00100110, + 0b01001001, + 0b01001001, + 0b01001001, + 0b00110010, + 0b00000000, + 0b00000001, + 0b00000001, + 0b01111111, + 0b00000001, + 0b00000001, + 0b00000000, + 0b00111111, + 0b01000000, + 0b01000000, + 0b01000000, + 0b00111111, + 0b00000000, + 0b00011111, + 0b00100000, + 0b01000000, + 0b00100000, + 0b00011111, + 0b00000000, + 0b00111111, + 0b01000000, + 0b00111100, + 0b01000000, + 0b00111111, + 0b00000000, + 0b01100011, + 0b00010100, + 0b00001000, + 0b00010100, + 0b01100011, + 0b00000000, + 0b00000011, + 0b00000100, + 0b01111000, + 0b00000100, + 0b00000011, + 0b00000000, + 0b01100001, + 0b01010001, + 0b01001001, + 0b01000101, + 0b01000011, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01111111, + 0b01111111, + 0b01111111, + 0b01111111, + 0b00000000, + 0b00100000, + 0b01010100, + 0b01010100, + 0b01010100, + 0b01111000, + 0b00000000, + 0b01111111, + 0b00101000, + 0b01000100, + 0b01000100, + 0b00111000, + 0b00000000, + 0b00111000, + 0b01000100, + 0b01000100, + 0b01000100, + 0b00101000, + 0b00000000, + 0b00111000, + 0b01000100, + 0b01000100, + 0b00101000, + 0b01111111, + 0b00000000, + 0b00111000, + 0b01010100, + 0b01010100, + 0b01010100, + 0b00011000, + 0b00000000, + 0b00001000, + 0b00001000, + 0b01111110, + 0b00001001, + 0b00001001, + 0b00000000, + 0b00001000, + 0b01010100, + 0b01010100, + 0b01010100, + 0b00111100, + 0b00000000, + 0b01111111, + 0b00001000, + 0b00000100, + 0b00000100, + 0b01111000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01111101, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00100000, + 0b01000000, + 0b01000100, + 0b00111101, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01111111, + 0b00010000, + 0b00101000, + 0b01000100, + 0b00000000, + 0b00000000, + 0b01000001, + 0b01111111, + 0b01000000, + 0b00000000, + 0b00000000, + 0b01111100, + 0b00000100, + 0b01111000, + 0b00000100, + 0b01111000, + 0b00000000, + 0b01111100, + 0b00001000, + 0b00000100, + 0b00000100, + 0b01111000, + 0b00000000, + 0b00111000, + 0b01000100, + 0b01000100, + 0b01000100, + 0b00111000, + 0b00000000, + 0b01111100, + 0b00010100, + 0b00010100, + 0b00010100, + 0b00001000, + 0b00000000, + 0b00001000, + 0b00010100, + 0b00010100, + 0b00010100, + 0b01111100, + 0b00000000, + 0b01111100, + 0b00001000, + 0b00000100, + 0b00000100, + 0b00001000, + 0b00000000, + 0b01001000, + 0b01010100, + 0b01010100, + 0b01010100, + 0b00100100, + 0b00000000, + 0b00000100, + 0b00000100, + 0b00111111, + 0b01000100, + 0b01000100, + 0b00000000, + 0b00111100, + 0b01000000, + 0b01000000, + 0b00100000, + 0b01111100, + 0b00000000, + 0b00011100, + 0b00100000, + 0b01000000, + 0b00100000, + 0b00011100, + 0b00000000, + 0b00111100, + 0b01000000, + 0b00111000, + 0b01000000, + 0b00111100, + 0b00000000, + 0b01000100, + 0b00101000, + 0b00010000, + 0b00101000, + 0b01000100, + 0b00000000, + 0b00001100, + 0b01010000, + 0b01010000, + 0b01010000, + 0b00111100, + 0b00000000, + 0b01000100, + 0b01100100, + 0b01010100, + 0b01001100, + 0b01000100, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, + 0b01111111, + 0b01000001, + 0b01000001, + 0b01000001, + 0b01111111, + 0b00000000, +}; diff --git a/Digital-Synth-PRA32-U/pra32-u-control-panel-page-table.h b/Digital-Synth-PRA32-U/pra32-u-control-panel-page-table.h new file mode 100644 index 0000000..5640457 --- /dev/null +++ b/Digital-Synth-PRA32-U/pra32-u-control-panel-page-table.h @@ -0,0 +1,102 @@ +#pragma once + +const uint8_t PANEL_PITCH = 128 + 0; +const uint8_t PANEL_SCALE = 128 + 1; +const uint8_t PANEL_TRANSPOSE = 128 + 2; +const uint8_t PANEL_VELOCITY = 128 + 3; + +const uint8_t PC_BY_PANEL_0 = 128 + 64; +const uint8_t PC_BY_PANEL_1 = 128 + 65; +const uint8_t PC_BY_PANEL_2 = 128 + 66; +const uint8_t PC_BY_PANEL_3 = 128 + 67; +const uint8_t PC_BY_PANEL_4 = 128 + 68; +const uint8_t PC_BY_PANEL_5 = 128 + 69; +const uint8_t PC_BY_PANEL_6 = 128 + 70; +const uint8_t PC_BY_PANEL_7 = 128 + 71; + +const uint8_t PC_BY_PANEL_8 = 128 + 72; +const uint8_t PC_BY_PANEL_9 = 128 + 73; +const uint8_t PC_BY_PANEL_10 = 128 + 74; +const uint8_t PC_BY_PANEL_11 = 128 + 75; +const uint8_t PC_BY_PANEL_12 = 128 + 76; +const uint8_t PC_BY_PANEL_13 = 128 + 77; +const uint8_t PC_BY_PANEL_14 = 128 + 78; +const uint8_t PC_BY_PANEL_15 = 128 + 79; + +const uint8_t WR_BY_PANEL_0 = 128 + 80; // Invalid +const uint8_t WR_BY_PANEL_1 = 128 + 81; // Invalid +const uint8_t WR_BY_PANEL_2 = 128 + 82; // Invalid +const uint8_t WR_BY_PANEL_3 = 128 + 83; // Invalid +const uint8_t WR_BY_PANEL_4 = 128 + 84; // Invalid +const uint8_t WR_BY_PANEL_5 = 128 + 85; // Invalid +const uint8_t WR_BY_PANEL_6 = 128 + 86; // Invalid +const uint8_t WR_BY_PANEL_7 = 128 + 87; // Invalid + +const uint8_t WR_BY_PANEL_8 = 128 + 88; +const uint8_t WR_BY_PANEL_9 = 128 + 89; +const uint8_t WR_BY_PANEL_10 = 128 + 90; +const uint8_t WR_BY_PANEL_11 = 128 + 91; +const uint8_t WR_BY_PANEL_12 = 128 + 92; +const uint8_t WR_BY_PANEL_13 = 128 + 93; +const uint8_t WR_BY_PANEL_14 = 128 + 94; +const uint8_t WR_BY_PANEL_15 = 128 + 95; + +const uint8_t PAGE_INDEX_DEFAULT = 7; + +struct PRA32_U_ControlPanelPage { + char page_name_line_0 [10 + 1]; + char page_name_line_1 [10 + 1]; + char control_target_a_name_line_0[10 + 1]; + char control_target_a_name_line_1[10 + 1]; + uint8_t control_target_a; + char control_target_b_name_line_0[10 + 1]; + char control_target_b_name_line_1[10 + 1]; + uint8_t control_target_b; + char control_target_c_name_line_0[10 + 1]; + char control_target_c_name_line_1[10 + 1]; + uint8_t control_target_c; +} g_control_panel_page_table[] = { + { "Page= 0 ", "Info ", "PRA32-U ", "with Panel", 0xFF , " ",PRA32_U_VERSION, 0xFF , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 1 ", "Voice a ", "Voice ", "Mode ", VOICE_MODE , " ", " ", 0xFF , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 2 ", "Voice b ", "Portamento", " ", PORTAMENTO , "Pitch ", "Bend Range", P_BEND_RANGE , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 3 ", "Osc a ", "Osc 1 ", "Wave ", OSC_1_WAVE , "Mixer ", "Noise/Sub ", MIXER_SUB_OSC , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 4 ", "Osc b ", "Osc 1 ", "Shape ", OSC_1_SHAPE , "Osc 1 ", "Morph ", OSC_1_MORPH , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 5 ", "Osc c ", "Osc 2 ", "Wave ", OSC_2_WAVE , "Mixer ", "Osc Mix ", MIXER_OSC_MIX , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 6 ", "Osc d ", "Osc 2 ", "Coarse ", OSC_2_COARSE , "Osc 2 ", "Pitch ", OSC_2_PITCH , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 7 ", "Filter a ", "Filter ", "Cutoff ", FILTER_CUTOFF , "Filter ", "Resonance ", FILTER_RESO , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 8 ", "Filter b ", "Filter ", "EG Amt ", FILTER_EG_AMT , "Filter ", "Key Track ", FILTER_KEY_TRK , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page= 9 ", "Filter c ", " ", " ", 0xFF , "Filter ", "Mode ", FILTER_MODE , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=10 ", "EG a ", "EG ", "Attack ", EG_ATTACK , "EG ", "Decay ", EG_DECAY , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=11 ", "EG b ", "EG ", "Sustain ", EG_SUSTAIN , "EG ", "Release ", EG_RELEASE , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=12 ", "EG c ", "EG ", "Amp Mod ", EG_AMP_MOD , "Release ", "= Decay ", REL_EQ_DECAY , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=13 ", "EG d ", "EG ", "Osc Amt ", EG_OSC_AMT , "EG ", "Osc Dst ", EG_OSC_DST , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=14 ", "EG e ", " ", " ", 0xFF , "EG ", "Velo Sens ", EG_VEL_SENS , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=15 ", "Amp a ", "Amp ", "Attack ", AMP_ATTACK , "Amp ", "Decay ", AMP_DECAY , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=16 ", "Amp c ", "Amp ", "Sustain ", AMP_SUSTAIN , "Amp ", "Release ", AMP_RELEASE , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=17 ", "Amp b ", "Amp ", "Gain ", AMP_GAIN , "Amp ", "Velo Sens ", AMP_VEL_SENS , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=18 ", "LFO a ", "LFO ", "Wave ", LFO_WAVE , "LFO ", "Fade Time ", LFO_FADE_TIME , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=19 ", "LFO b ", "LFO ", "Rate ", LFO_RATE , "LFO ", "Depth ", LFO_DEPTH , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=20 ", "LFO c ", "LFO ", "Osc Amt ", LFO_OSC_AMT , "LFO ", "Osc Dst ", LFO_OSC_DST , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=21 ", "LFO d ", "LFO ", "Filter Amt", LFO_FILTER_AMT , " ", " ", 0xFF , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=22 ", "Breath ", "Breath ", "Filter Amt", BTH_FILTER_AMT , "Breath ", "Amp Mod ", BTH_AMP_MOD , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=23 ", "Chorus a ", "Chorus ", "Mix ", CHORUS_MIX , " ", " ", 0xFF , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=24 ", "Chorus b ", "Chorus ", "Rate ", CHORUS_RATE , "Chorus ", "Depth ", CHORUS_DEPTH , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=25 ", "Delay a ", "Delay ", "Feedback ", DELAY_FEEDBACK , "Delay ", "Time ", DELAY_TIME , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=26 ", "Delay b ", "Delay ", "Mode ", DELAY_MODE , " ", " ", 0xFF , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=27 ", "Write a ", "Write ", "Program 8", WR_BY_PANEL_8 , "Write ", "Program 9", WR_BY_PANEL_9 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=28 ", "Write b ", "Write ", "Program 10", WR_BY_PANEL_10 , "Write ", "Program 11", WR_BY_PANEL_11 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=29 ", "Write c ", "Write ", "Program 12", WR_BY_PANEL_12 , "Write ", "Program 13", WR_BY_PANEL_13 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=30 ", "Write d ", "Write ", "Program 14", WR_BY_PANEL_14 , "Write ", "Program 15", WR_BY_PANEL_15 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=31 ", "Read a ", "Read ", "Program 0", PC_BY_PANEL_0 , "Read ", "Program 1", PC_BY_PANEL_1 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=32 ", "Read b ", "Read ", "Program 2", PC_BY_PANEL_2 , "Read ", "Program 3", PC_BY_PANEL_3 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=33 ", "Read c ", "Read ", "Program 4", PC_BY_PANEL_4 , "Read ", "Program 5", PC_BY_PANEL_5 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=34 ", "Read d ", "Read ", "Program 6", PC_BY_PANEL_6 , "Read ", "Program 7", PC_BY_PANEL_7 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=35 ", "Read e ", "Read ", "Program 8", PC_BY_PANEL_8 , "Read ", "Program 9", PC_BY_PANEL_9 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=36 ", "Read f ", "Read ", "Program 10", PC_BY_PANEL_10 , "Read ", "Program 11", PC_BY_PANEL_11 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=37 ", "Read g ", "Read ", "Program 12", PC_BY_PANEL_12 , "Read ", "Program 13", PC_BY_PANEL_13 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=38 ", "Read h ", "Read ", "Program 14", PC_BY_PANEL_14 , "Read ", "Program 15", PC_BY_PANEL_15 , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=39 ", "Panel a ", "Modulation", " ", MODULATION , " ", " ", 0xFF , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=40 ", "Panel b ", "Breath ", "Controller", BTH_CONTROLLER , "Sustain ", "Pedal ", SUSTAIN_PEDAL , "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=41 ", "Panel c ", "Panel ", "Scale ", PANEL_SCALE , "Panel ", "Transpose ", PANEL_TRANSPOSE, "Panel ", "Pitch ", PANEL_PITCH , }, + { "Page=42 ", "Panel b ", "Panel ", "Velocity ", PANEL_VELOCITY , " ", " ", 0xFF , "Panel ", "Pitch ", PANEL_PITCH , }, +}; diff --git a/Digital-Synth-PRA32-U/pra32-u-control-panel.h b/Digital-Synth-PRA32-U/pra32-u-control-panel.h new file mode 100644 index 0000000..ddd7c52 --- /dev/null +++ b/Digital-Synth-PRA32-U/pra32-u-control-panel.h @@ -0,0 +1,961 @@ +#pragma once + +#include "pra32-u-common.h" +#include "pra32-u-control-panel-font-table.h" +#include "pra32-u-control-panel-page-table.h" + +#include "hardware/i2c.h" + +#include +#include + + + +#define NUMBER_OF_PAGES (sizeof(g_control_panel_page_table) / sizeof(g_control_panel_page_table[0])) + +static volatile uint32_t s_current_page_index = PAGE_INDEX_DEFAULT; + +static volatile int32_t s_adc_current_value[3]; +static volatile uint8_t s_adc_control_value[3]; +static volatile uint8_t s_adc_control_target[3] = { 0xFF, 0xFF, 0xFF }; +static volatile boolean s_adc_control_catched[3]; + +#if defined(PRA32_U_USE_CONTROL_PANEL) +static uint32_t s_prev_key_current_value; +static uint32_t s_next_key_current_value; +#endif // defined(PRA32_U_USE_CONTROL_PANEL) +static uint32_t s_play_key_current_value; + +static volatile uint8_t s_panel_play_note_number = 60; +static volatile uint8_t s_panel_playing_note_number = 0xFF; +static volatile uint8_t s_reserved_note_off = 0xFF; +static volatile uint8_t s_reserved_note_on = 0xFF; + +static volatile uint32_t s_display_draw_counter = 0; + +static char s_display_buffer[8][21 + 1] = { + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", +}; + + +static INLINE void PRA32_U_ControlPanel_update_page() { + PRA32_U_ControlPanelPage& current_page = g_control_panel_page_table[s_current_page_index]; + + std::memset(&s_display_buffer[3], ' ', 21); + std::memset(&s_display_buffer[7], ' ', 21); + + std::memcpy(&s_display_buffer[1][ 0], current_page.page_name_line_0 , 10); + std::memcpy(&s_display_buffer[2][ 0], current_page.page_name_line_1 , 10); + + std::memcpy(&s_display_buffer[5][ 0], current_page.control_target_a_name_line_0, 10); + std::memcpy(&s_display_buffer[6][ 0], current_page.control_target_a_name_line_1, 10); + s_adc_control_target[0] = current_page.control_target_a; + + std::memcpy(&s_display_buffer[5][11], current_page.control_target_b_name_line_0, 10); + std::memcpy(&s_display_buffer[6][11], current_page.control_target_b_name_line_1, 10); + s_adc_control_target[1] = current_page.control_target_b; + + std::memcpy(&s_display_buffer[1][11], current_page.control_target_c_name_line_0, 10); + std::memcpy(&s_display_buffer[2][11], current_page.control_target_c_name_line_1, 10); + s_adc_control_target[2] = current_page.control_target_c; + + s_display_draw_counter = 0; +} + +static INLINE uint8_t PRA32_U_ControlPanel_adc_control_value_candidate(uint32_t adc_number) { + volatile int32_t adc_control_value_candidate; + +#if defined(PRA32_U_ANALOG_INPUT_REVERSED) + adc_control_value_candidate = (127 - (s_adc_current_value[adc_number] / PRA32_U_ANALOG_INPUT_DENOMINATOR)); +#else // defined(PRA32_U_ANALOG_INPUT_REVERSED) + adc_control_value_candidate = (s_adc_current_value[adc_number] / PRA32_U_ANALOG_INPUT_DENOMINATOR); +#endif // defined(PRA32_U_ANALOG_INPUT_REVERSED) + + if (adc_control_value_candidate > 127) { + adc_control_value_candidate = 127; + } + + if (adc_control_value_candidate < 0) { + adc_control_value_candidate = 0; + } + + return adc_control_value_candidate; +} + +static INLINE boolean PRA32_U_ControlPanel_process_reserved_note_off_on() { + if (s_reserved_note_on <= 127) { + uint8_t velocity = g_synth.current_controller_value(PANEL_VELOCITY); + if (velocity == 0) { + velocity = 1; + } + + g_synth.note_on(s_reserved_note_on, velocity); + s_panel_playing_note_number = s_reserved_note_on; + s_reserved_note_on = 0xFF; + return true; + } + + if (s_reserved_note_off <= 127) { + g_synth.note_off(s_reserved_note_off); + if (s_panel_playing_note_number == s_reserved_note_off) { + s_panel_playing_note_number = 0xFF; + } + s_reserved_note_off = 0xFF; + return true; + } + + return false; +} + +static INLINE void PRA32_U_ControlPanel_update_pitch() { + int32_t new_note_number = g_synth.current_controller_value(PANEL_PITCH); + + uint32_t index_scale = ((g_synth.current_controller_value(PANEL_SCALE) * 4) + 127) / 254; + if (index_scale == 2) { + const uint8_t ary_major[53] = + { 48, 48, 48, 48, 48, 50, 50, 50, 50, 52, 52, 52, 53, 53, 53, + 55, 55, 55, 55, 57, 57, 57, 57, 59, 59, 59, 60, + 60, 60, 62, 62, 62, 62, 64, 64, 64, 65, 65, 65, + 67, 67, 67, 67, 69, 69, 69, 69, 71, 71, 71, 72, 72, 72 }; + uint32_t index_pitch = (((g_synth.current_controller_value(PANEL_PITCH) + 3) * 2) + 1) / 5; + new_note_number = ary_major[index_pitch]; + } else if (index_scale == 1) { + const uint8_t ary_pentatonic[53] = + { 48, 48, 48, 48, 48, 50, 50, 50, 50, 52, 52, 52, 52, 52, 55, + 55, 55, 55, 55, 57, 57, 57, 57, 57, 60, 60, 60, + 60, 60, 62, 62, 62, 62, 64, 64, 64, 64, 64, 67, + 67, 67, 67, 67, 69, 69, 69, 69, 69, 72, 72, 72, 72, 72 }; + + uint32_t index_pitch = (((g_synth.current_controller_value(PANEL_PITCH) + 3) * 2) + 1) / 5; + new_note_number = ary_pentatonic[index_pitch]; + } + + new_note_number += g_synth.current_controller_value(PANEL_TRANSPOSE) - 64; + if (new_note_number < 0) { + new_note_number = 0; + } else if (new_note_number > 127) { + new_note_number = 127; + } + + bool panel_play_note_number_changed = false; + if (s_panel_play_note_number != new_note_number) { + s_panel_play_note_number = new_note_number; + panel_play_note_number_changed = true; + } + + if (s_play_key_current_value == 1) { + if (panel_play_note_number_changed) { + s_reserved_note_off = s_panel_playing_note_number; + s_reserved_note_on = s_panel_play_note_number; + PRA32_U_ControlPanel_process_reserved_note_off_on(); + } + } +} + +static INLINE boolean PRA32_U_ControlPanel_update_control_adc(uint32_t adc_number) { + uint8_t adc_control_value_candidate = PRA32_U_ControlPanel_adc_control_value_candidate(adc_number); + + if (s_adc_control_value[adc_number] != adc_control_value_candidate) { + uint8_t s_adc_control_value_old = s_adc_control_value[adc_number]; + s_adc_control_value[adc_number] = adc_control_value_candidate; + + uint8_t current_controller_value = s_adc_control_value[adc_number]; + if (s_adc_control_target[adc_number] < 128 + 64) { + current_controller_value = g_synth.current_controller_value(s_adc_control_target[adc_number]); + } + + if ((s_adc_control_value_old <= current_controller_value) && + (s_adc_control_value[adc_number] >= current_controller_value)) { + s_adc_control_catched[adc_number] = true; + } + + if ((s_adc_control_value_old >= current_controller_value) && + (s_adc_control_value[adc_number] <= current_controller_value)) { + s_adc_control_catched[adc_number] = true; + } + + if ((s_adc_control_target[adc_number] == PANEL_PITCH) || + (s_adc_control_target[adc_number] == PANEL_SCALE) || + (s_adc_control_target[adc_number] == PANEL_TRANSPOSE)) { + if (s_adc_control_catched[adc_number]) { + g_synth.control_change(s_adc_control_target[adc_number], s_adc_control_value[adc_number]); + PRA32_U_ControlPanel_update_pitch(); + } + } else if (s_adc_control_target[adc_number] < 128 + 64) { + if (s_adc_control_catched[adc_number]) { + g_synth.control_change(s_adc_control_target[adc_number], s_adc_control_value[adc_number]); + } + } else if ((s_adc_control_target[adc_number] >= PC_BY_PANEL_0) && (s_adc_control_target[adc_number] <= PC_BY_PANEL_15)) { + if ((s_adc_control_value_old < 64) && (s_adc_control_value[adc_number] >= 64)) { + g_synth.program_change(s_adc_control_target[adc_number] - PC_BY_PANEL_0); + } + } else if ((s_adc_control_target[adc_number] >= WR_BY_PANEL_0) && (s_adc_control_target[adc_number] <= WR_BY_PANEL_15)) { + static boolean s_ready_to_write[PROGRAM_NUMBER_MAX + 1] = {}; + + uint8_t program_number_to_write = s_adc_control_target[adc_number] - WR_BY_PANEL_0; + + if (s_adc_control_value[adc_number] == 0) { + s_ready_to_write[program_number_to_write] = true; + } else if (s_ready_to_write[program_number_to_write] && (s_adc_control_value[adc_number] == 127)) { + g_synth.write_parameters_to_program(program_number_to_write); + s_ready_to_write[program_number_to_write] = false; + } + } + + return true; + } + + return false; +} + +static INLINE void PRA32_U_ControlPanel_set_draw_position(uint8_t x, uint8_t y) { + uint8_t commands[] = {0x00, static_cast(0xB0 + y), + static_cast(0x10 + ((x * 6) >> 4)), + static_cast(0x00 + ((x * 6) & 0x0F))}; + i2c_write_blocking(PRA32_U_OLED_DISPLAY_I2C, PRA32_U_OLED_DISPLAY_I2C_ADDRESS, commands, sizeof(commands), false); +} + +static INLINE void PRA32_U_ControlPanel_draw_character(uint8_t c) { + uint8_t data[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + std::memcpy(&data[1], g_control_panel_font_table[c], 6); + i2c_write_blocking(PRA32_U_OLED_DISPLAY_I2C, PRA32_U_OLED_DISPLAY_I2C_ADDRESS, data, sizeof(data), false); +} + +static INLINE boolean PRA32_U_ControlPanel_calc_value_display(uint8_t control_target, uint8_t controller_value, char value_display_text[5]) +{ + boolean result = false; + + switch (control_target) { + case OSC_2_COARSE : + case OSC_2_PITCH : + case FILTER_EG_AMT : + case EG_OSC_AMT : + case LFO_OSC_AMT : + case LFO_FILTER_AMT : + case BTH_FILTER_AMT : + case PANEL_TRANSPOSE : + { + std::sprintf(value_display_text, "%+3d", static_cast(controller_value) - 64); + result = true; + } + break; + case MIXER_SUB_OSC : + { + std::sprintf(value_display_text, "%+3d", static_cast(controller_value) - 64); + + if (controller_value < 55) { + value_display_text[0] = 'N'; + } else if (controller_value < 64) { + value_display_text[1] = 'N'; + } else if (controller_value < 74) { + value_display_text[1] = 'S'; + } else { + value_display_text[0] = 'S'; + } + + result = true; + } + break; + case OSC_1_WAVE : + { + char ary[6][5] = {"Saw","Sin"," -","Tri"," -","Pls"}; + uint32_t index = ((controller_value * 10) + 127) / 254; + if (controller_value < 6) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case OSC_2_WAVE : + { + char ary[6][5] = {"Saw","Sin"," -","Tri","Nos","Sqr"}; + uint32_t index = ((controller_value * 10) + 127) / 254; + if (controller_value < 6) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case FILTER_KEY_TRK : + { + char ary[3][5] = {"0.0","0.5","1.0"}; + uint32_t index = ((controller_value * 4) + 127) / 254; + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case EG_OSC_DST : + case LFO_OSC_DST : + { + char ary[3][5] = {" P"," 2P"," 1S"}; + uint32_t index = ((controller_value * 4) + 127) / 254; + if (controller_value < 3) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case VOICE_MODE : + { + char ary[6][5] = {"Pol","Par"," -","Mon"," LP","Lgt"}; + uint32_t index = ((controller_value * 10) + 127) / 254; + if (controller_value < 6) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case LFO_WAVE : + { + char ary[6][5] = {"Tri","Sin"," -","Saw"," SH","Sqr"}; + uint32_t index = ((controller_value * 10) + 127) / 254; + if (controller_value < 6) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case FILTER_MODE : + { + char ary[2][5] = {" LP"," HP"}; + uint32_t index = ((controller_value * 2) + 127) / 254; + if (controller_value < 2) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case EG_AMP_MOD : + case REL_EQ_DECAY : + case SUSTAIN_PEDAL : + { + char ary[2][5] = {"Off"," On"}; + uint32_t index = ((controller_value * 2) + 127) / 254; + if (controller_value < 2) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case BTH_AMP_MOD : + { + char ary[3][5] = {"Off","Qad","Lin"}; + uint32_t index = ((controller_value * 4) + 127) / 254; + if (controller_value < 3) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case DELAY_MODE : + { + char ary[2][5] = {" S"," P"}; + uint32_t index = ((controller_value * 2) + 127) / 254; + if (controller_value < 2) { index = controller_value; } + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + case PC_BY_PANEL_0 : + case PC_BY_PANEL_1 : + case PC_BY_PANEL_2 : + case PC_BY_PANEL_3 : + case PC_BY_PANEL_4 : + case PC_BY_PANEL_5 : + case PC_BY_PANEL_6 : + case PC_BY_PANEL_7 : + case PC_BY_PANEL_8 : + case PC_BY_PANEL_9 : + case PC_BY_PANEL_10 : + case PC_BY_PANEL_11 : + case PC_BY_PANEL_12 : + case PC_BY_PANEL_13 : + case PC_BY_PANEL_14 : + case PC_BY_PANEL_15 : + { + if (controller_value < 64) { + value_display_text[0] = 'R'; + value_display_text[1] = 'd'; + value_display_text[2] = 'y'; + } else { + value_display_text[0] = 'E'; + value_display_text[1] = 'x'; + value_display_text[2] = 'e'; + } + + result = true; + } + break; + case WR_BY_PANEL_0 : + case WR_BY_PANEL_1 : + case WR_BY_PANEL_2 : + case WR_BY_PANEL_3 : + case WR_BY_PANEL_4 : + case WR_BY_PANEL_5 : + case WR_BY_PANEL_6 : + case WR_BY_PANEL_7 : + case WR_BY_PANEL_8 : + case WR_BY_PANEL_9 : + case WR_BY_PANEL_10 : + case WR_BY_PANEL_11 : + case WR_BY_PANEL_12 : + case WR_BY_PANEL_13 : + case WR_BY_PANEL_14 : + case WR_BY_PANEL_15 : + { + if (controller_value == 0) { + value_display_text[0] = 'R'; + value_display_text[1] = 'd'; + value_display_text[2] = 'y'; + } else if (controller_value == 127) { + value_display_text[0] = 'E'; + value_display_text[1] = 'x'; + value_display_text[2] = 'e'; + } else { + value_display_text[0] = ' '; + value_display_text[1] = ' '; + value_display_text[2] = '-'; + } + + result = true; + } + break; + case PANEL_PITCH : + { + uint32_t index_scale = ((g_synth.current_controller_value(PANEL_SCALE) * 4) + 127) / 254; + if (index_scale == 0) { + char ary[12][5] = { " C", "C#", " D", "D#", " E", " F", "F#", " G", "G#", " A", "A#", " B" }; + + uint32_t quotient = controller_value / 12; + uint32_t remainder = controller_value % 12; + + value_display_text[0] = ary[remainder][0]; + value_display_text[1] = ary[remainder][1]; + + if (quotient == 0) { + value_display_text[2] = '-'; + } else { + value_display_text[2] = '0' + quotient - 1; + } + } else if (index_scale == 2) { + char ary_major[53][5] = + { " C3", " C3", " C3", " C3", " C3", " D3", " D3", " D3", " D3", " E3", " E3", " E3", " F3", " F3", " F3", + " G3", " G3", " G3", " G3", " A3", " A3", " A3", " A3", " B3", " B3", " B3", " C4", + " C4", " C4", " D4", " D4", " D4", " D4", " E4", " E4", " E4", " F4", " F4", " F4", + " G4", " G4", " G4", " G4", " A4", " A4", " A4", " A4", " B4", " B4", " B4", " C5", " C5", " C5" }; + uint32_t index = (((g_synth.current_controller_value(PANEL_PITCH) + 3) * 2) + 1) / 5; + std::strcpy(value_display_text, ary_major[index]); + } else if (index_scale == 1) { + char ary_pentatonic[53][5] = + { " C3", " C3", " C3", " C3", " C3", " D3", " D3", " D3", " D3", " E3", " E3", " E3", " E3", " E3", " G3", + " G3", " G3", " G3", " G3", " A3", " A3", " A3", " A3", " A3", " C4", " C4", " C4", + " C4", " C4", " D4", " D4", " D4", " D4", " E4", " E4", " E4", " E4", " E4", " G4", + " G4", " G4", " G4", " G4", " A4", " A4", " A4", " A4", " A4", " C4", " C5", " C5", " C5", " C5" }; + uint32_t index = (((g_synth.current_controller_value(PANEL_PITCH) + 3) * 2) + 1) / 5; + std::strcpy(value_display_text, ary_pentatonic[index]); + } + + result = true; + } + break; + case PANEL_SCALE : + { + char ary[3][5] = {"Ful","Pen","Maj"}; + uint32_t index = ((controller_value * 4) + 127) / 254; + std::strcpy(value_display_text, ary[index]); + result = true; + } + break; + } + + return result; +} + + + +INLINE void PRA32_U_ControlPanel_setup() { +#if defined(PRA32_U_USE_CONTROL_PANEL) + PRA32_U_ControlPanel_update_page(); + +#if defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + adc_init(); + adc_gpio_init(26); + adc_gpio_init(27); + adc_gpio_init(28); +#endif // defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + +#if defined(PRA32_U_USE_CONTROL_PANEL_OLED_DISPLAY) + i2c_init(PRA32_U_OLED_DISPLAY_I2C, 400 * 1000); + i2c_set_slave_mode(PRA32_U_OLED_DISPLAY_I2C, false, 0); + gpio_set_function(PRA32_U_OLED_DISPLAY_I2C_SDA_PIN, GPIO_FUNC_I2C); + gpio_pull_up(PRA32_U_OLED_DISPLAY_I2C_SDA_PIN); + gpio_set_function(PRA32_U_OLED_DISPLAY_I2C_SCL_PIN, GPIO_FUNC_I2C); + gpio_pull_up(PRA32_U_OLED_DISPLAY_I2C_SCL_PIN); + + uint8_t commands_init_0[] = {0x00, 0x81, PRA32_U_OLED_DISPLAY_CONTRAST, 0xA0, 0xC0, 0x8D, 0x14}; + if (PRA32_U_OLED_DISPLAY_ROTATION) { + commands_init_0[3] = 0xA1; + commands_init_0[4] = 0xC8; + } + + i2c_write_blocking(PRA32_U_OLED_DISPLAY_I2C, PRA32_U_OLED_DISPLAY_I2C_ADDRESS, commands_init_0, sizeof(commands_init_0), false); + + for (uint8_t y = 0; y <= 7; ++y) { + for (uint8_t x = 0; x <= 20; ++x) { + PRA32_U_ControlPanel_set_draw_position(x, y); + PRA32_U_ControlPanel_draw_character(s_display_buffer[y][x]); + } + + uint8_t commands[] = {0x00, static_cast(0xB0 + y), 0x17, 0x0E}; + i2c_write_blocking(PRA32_U_OLED_DISPLAY_I2C, PRA32_U_OLED_DISPLAY_I2C_ADDRESS, commands, sizeof(commands), false); + + uint8_t data[] = {0x40, 0x00, 0x00}; + i2c_write_blocking(PRA32_U_OLED_DISPLAY_I2C, PRA32_U_OLED_DISPLAY_I2C_ADDRESS, data, sizeof(data), false); + } + + uint8_t commands_init_1[] = {0x00, 0xAF}; + i2c_write_blocking(PRA32_U_OLED_DISPLAY_I2C, PRA32_U_OLED_DISPLAY_I2C_ADDRESS, commands_init_1, sizeof(commands_init_1), false); +#endif // defined(PRA32_U_USE_CONTROL_PANEL_OLED_DISPLAY) + +#endif // defined(PRA32_U_USE_CONTROL_PANEL) +} + +INLINE void PRA32_U_ControlPanel_initialize_parameters() { +#if defined(PRA32_U_USE_CONTROL_PANEL) + g_synth.control_change(PANEL_PITCH , 64 ); + g_synth.control_change(PANEL_SCALE , 127); + g_synth.control_change(PANEL_TRANSPOSE , 64 ); + g_synth.control_change(PANEL_VELOCITY , 100); +#endif // defined(PRA32_U_USE_CONTROL_PANEL) +} + +INLINE void PRA32_U_ControlPanel_update_analog_inputs(uint32_t loop_counter) { + static_cast(loop_counter); + +#if defined(PRA32_U_USE_CONTROL_PANEL) + +#if defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + static int32_t s_adc_total_value = 0; + switch (loop_counter & 0x3F) { + case 0x10: + adc_select_input(0); + s_adc_total_value = PRA32_U_ANALOG_INPUT_CORRECTION; + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x14: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x18: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x1C: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + if (s_adc_current_value[0] >= s_adc_total_value + PRA32_U_ANALOG_INPUT_THRESHOLD) { + s_adc_current_value[0] = s_adc_total_value; + } else if (s_adc_current_value[0] + PRA32_U_ANALOG_INPUT_THRESHOLD <= s_adc_total_value ) { + s_adc_current_value[0] = s_adc_total_value; + } + break; + case 0x20: + adc_select_input(1); + s_adc_total_value = PRA32_U_ANALOG_INPUT_CORRECTION; + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x24: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x28: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x2C: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + if (s_adc_current_value[1] >= s_adc_total_value + PRA32_U_ANALOG_INPUT_THRESHOLD) { + s_adc_current_value[1] = s_adc_total_value; + } else if (s_adc_current_value[1] + PRA32_U_ANALOG_INPUT_THRESHOLD <= s_adc_total_value ) { + s_adc_current_value[1] = s_adc_total_value; + } + break; + case 0x30: + adc_select_input(2); + s_adc_total_value = PRA32_U_ANALOG_INPUT_CORRECTION; + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x34: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x38: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + break; + case 0x3C: + s_adc_total_value += adc_read() + adc_read() + adc_read() + adc_read(); + if (s_adc_current_value[2] >= s_adc_total_value + PRA32_U_ANALOG_INPUT_THRESHOLD) { + s_adc_current_value[2] = s_adc_total_value; + } else if (s_adc_current_value[2] + PRA32_U_ANALOG_INPUT_THRESHOLD <= s_adc_total_value ) { + s_adc_current_value[2] = s_adc_total_value; + } + break; + } +#endif // defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + +#endif // defined(PRA32_U_USE_CONTROL_PANEL) +} + +INLINE void PRA32_U_ControlPanel_update_control() { +#if defined(PRA32_U_USE_CONTROL_PANEL) + static uint32_t s_initialize_counter = 0; + if (s_initialize_counter < 75) { + ++s_initialize_counter; +#if defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + s_adc_control_value[0] = PRA32_U_ControlPanel_adc_control_value_candidate(0); + s_adc_control_value[1] = PRA32_U_ControlPanel_adc_control_value_candidate(1); + s_adc_control_value[2] = PRA32_U_ControlPanel_adc_control_value_candidate(2); +#endif // defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + return; + } + + boolean processed = PRA32_U_ControlPanel_process_reserved_note_off_on(); + if (processed) { + return; + } + +#if defined(PRA32_U_USE_CONTROL_PANEL_KEY_INPUT) + static uint32_t s_prev_key_value_changed_time; + static uint32_t s_next_key_value_changed_time; + static uint32_t s_play_key_value_changed_time; + + static uint32_t s_key_inpuy_counter = 0; + ++s_key_inpuy_counter; + +#if defined(PRA32_U_KEY_INPUT_PREV_KEY_PIN) + if (s_key_inpuy_counter - s_prev_key_value_changed_time >= PRA32_U_KEY_ANTI_CHATTERING_WAIT) { + uint32_t value = digitalRead(PRA32_U_KEY_INPUT_PREV_KEY_PIN) == PRA32_U_KEY_INPUT_ACTIVE_LEVEL; + if (s_prev_key_current_value != value) { + s_prev_key_current_value = value; + s_prev_key_value_changed_time = s_key_inpuy_counter; + + if (s_prev_key_current_value == 0) { + // Prev key released + if (s_current_page_index == 0) { + s_current_page_index = NUMBER_OF_PAGES - 1; + } else { + --s_current_page_index; + } + + PRA32_U_ControlPanel_update_page(); + + s_adc_control_catched[0] = false; + s_adc_control_catched[1] = false; + s_adc_control_catched[2] = false; + } + return; + } + } +#endif // defined(PRA32_U_KEY_INPUT_PREV_KEY_PIN) + +#if defined(PRA32_U_KEY_INPUT_NEXT_KEY_PIN) + if (s_key_inpuy_counter - s_next_key_value_changed_time >= PRA32_U_KEY_ANTI_CHATTERING_WAIT) { + uint32_t value = digitalRead(PRA32_U_KEY_INPUT_NEXT_KEY_PIN) == PRA32_U_KEY_INPUT_ACTIVE_LEVEL; + if (s_next_key_current_value != value) { + s_next_key_current_value = value; + s_next_key_value_changed_time = s_key_inpuy_counter; + + if (s_next_key_current_value == 0) { + // Next key released + if (s_current_page_index == NUMBER_OF_PAGES - 1) { + s_current_page_index = 0; + } else { + ++s_current_page_index; + } + + PRA32_U_ControlPanel_update_page(); + + s_adc_control_catched[0] = false; + s_adc_control_catched[1] = false; + s_adc_control_catched[2] = false; + } + return; + } + } +#endif // defined(PRA32_U_KEY_INPUT_NEXT_KEY_PIN) + +#if defined(PRA32_U_KEY_INPUT_PLAY_KEY_PIN) + if (s_key_inpuy_counter - s_play_key_value_changed_time >= PRA32_U_KEY_ANTI_CHATTERING_WAIT) { + uint32_t value = digitalRead(PRA32_U_KEY_INPUT_PLAY_KEY_PIN) == PRA32_U_KEY_INPUT_ACTIVE_LEVEL; + if (s_play_key_current_value != value) { + s_play_key_current_value = value; + s_play_key_value_changed_time = s_key_inpuy_counter; + + if (s_play_key_current_value == 1) { + // Play key pressed + s_reserved_note_on = s_panel_play_note_number; + } else { + // Play key released + s_reserved_note_off = s_panel_playing_note_number; + } + + PRA32_U_ControlPanel_process_reserved_note_off_on(); + return; + } + } +#endif // defined(PRA32_U_KEY_INPUT_PLAY_KEY_PIN) + +#endif // defined(PRA32_U_USE_CONTROL_PANEL_KEY_INPUT) + +#if defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + static uint32_t s_adc_number_to_check = 0; + + boolean updated = PRA32_U_ControlPanel_update_control_adc(s_adc_number_to_check); + s_adc_number_to_check = (s_adc_number_to_check + 1) % 3; + + if (updated == false) { + updated = PRA32_U_ControlPanel_update_control_adc(s_adc_number_to_check); + s_adc_number_to_check = (s_adc_number_to_check + 1) % 3; + + if (updated == false) { + updated = PRA32_U_ControlPanel_update_control_adc(s_adc_number_to_check); + s_adc_number_to_check = (s_adc_number_to_check + 1) % 3; + } + } +#endif // defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + +#endif // defined(PRA32_U_USE_CONTROL_PANEL) +} + +INLINE void PRA32_U_ControlPanel_update_display_buffer(uint32_t loop_counter) { + static_cast(loop_counter); + +#if defined(PRA32_U_USE_CONTROL_PANEL) + if ((loop_counter & 0x7F) == 0x00) { + char buff[6]; + + uint8_t adc_control_target_0 = s_adc_control_target[0]; + if (adc_control_target_0 < 0xFF) { + uint8_t adc_control_value = s_adc_control_value[0]; + uint8_t current_controller_value = adc_control_value; + if (adc_control_target_0 < 128 + 64) { + current_controller_value = g_synth.current_controller_value(adc_control_target_0); + } + + s_display_buffer[7][ 0] = 'A'; + if (adc_control_value < current_controller_value) { + s_display_buffer[7][ 1] = '<'; + } else if (adc_control_value > current_controller_value) { + s_display_buffer[7][ 1] = '>'; + } else { + s_display_buffer[7][ 1] = '='; + } + + std::sprintf(buff, "%3u", current_controller_value); + s_display_buffer[7][ 2] = buff[0]; + s_display_buffer[7][ 3] = buff[1]; + s_display_buffer[7][ 4] = buff[2]; + + char value_display_text[5] = {}; + boolean exists = PRA32_U_ControlPanel_calc_value_display(adc_control_target_0, current_controller_value, value_display_text); + if (exists) { + s_display_buffer[7][ 5] = '['; + s_display_buffer[7][ 6] = value_display_text[0]; + s_display_buffer[7][ 7] = value_display_text[1]; + s_display_buffer[7][ 8] = value_display_text[2]; + s_display_buffer[7][ 9] = ']'; + } + } + + uint8_t adc_control_target_1 = s_adc_control_target[1]; + if (adc_control_target_1 < 0xFF) { + uint8_t adc_control_value = s_adc_control_value[1]; + uint8_t current_controller_value = adc_control_value; + if (adc_control_target_1 < 128 + 64) { + current_controller_value = g_synth.current_controller_value(adc_control_target_1); + } + + s_display_buffer[7][11] = 'B'; + if (adc_control_value < current_controller_value) { + s_display_buffer[7][12] = '<'; + } else if (adc_control_value > current_controller_value) { + s_display_buffer[7][12] = '>'; + } else { + s_display_buffer[7][12] = '='; + } + + std::sprintf(buff, "%3u", current_controller_value); + s_display_buffer[7][13] = buff[0]; + s_display_buffer[7][14] = buff[1]; + s_display_buffer[7][15] = buff[2]; + + char value_display_text[5] = {}; + boolean exists = PRA32_U_ControlPanel_calc_value_display(adc_control_target_1, current_controller_value, value_display_text); + if (exists) { + s_display_buffer[7][16] = '['; + s_display_buffer[7][17] = value_display_text[0]; + s_display_buffer[7][18] = value_display_text[1]; + s_display_buffer[7][19] = value_display_text[2]; + s_display_buffer[7][20] = ']'; + } + } + + uint8_t adc_control_target_2 = s_adc_control_target[2]; + if (adc_control_target_2 < 0xFF) { + uint8_t adc_control_value = s_adc_control_value[2]; + uint8_t current_controller_value = adc_control_value; + if (adc_control_target_2 < 128+64) { + current_controller_value = g_synth.current_controller_value(adc_control_target_2); + } + + s_display_buffer[3][11] = 'C'; + if (adc_control_value < current_controller_value) { + s_display_buffer[3][12] = '<'; + } else if (adc_control_value > current_controller_value) { + s_display_buffer[3][12] = '>'; + } else { + s_display_buffer[3][12] = '='; + } + + std::sprintf(buff, "%3u", current_controller_value); + s_display_buffer[3][13] = buff[0]; + s_display_buffer[3][14] = buff[1]; + s_display_buffer[3][15] = buff[2]; + + char value_display_text[5] = {}; + boolean exists = PRA32_U_ControlPanel_calc_value_display(adc_control_target_2, current_controller_value, value_display_text); + if (exists) { + s_display_buffer[3][16] = '['; + s_display_buffer[3][17] = value_display_text[0]; + s_display_buffer[3][18] = value_display_text[1]; + s_display_buffer[3][19] = value_display_text[2]; + s_display_buffer[3][20] = ']'; + } + } + } +#endif // defined(PRA32_U_USE_CONTROL_PANEL) +} + +INLINE void PRA32_U_ControlPanel_update_display(uint32_t loop_counter) { + static_cast(loop_counter); + +#if defined(PRA32_U_USE_CONTROL_PANEL) + +#if defined(PRA32_U_USE_CONTROL_PANEL_OLED_DISPLAY) + static uint32_t s_display_draw_position_x = 0; + static uint32_t s_display_draw_position_y = 0; + + if ((loop_counter & 0x7F) == 0x40) { + uint32_t display_draw_counter = s_display_draw_counter; + + s_display_draw_counter++; + if (s_display_draw_counter == 8 * 21) { + s_display_draw_counter = (6 * 21) + 11; + } + + switch (display_draw_counter / 21) { + case 0: + s_display_draw_position_y = 1; + break; + case 1: + s_display_draw_position_y = 2; + break; + case 2: + s_display_draw_position_y = 3; + break; + case 3: + s_display_draw_position_y = 5; + break; + case 4: + s_display_draw_position_y = 6; + break; + case 5: + s_display_draw_position_y = 7; + break; + case 6: + s_display_draw_position_y = 3; + break; + case 7: + s_display_draw_position_y = 7; + break; + } + + s_display_draw_position_x = display_draw_counter % 21; + + PRA32_U_ControlPanel_set_draw_position(s_display_draw_position_x, s_display_draw_position_y); + } else if ((loop_counter & 0x7F) == 0x00) { + PRA32_U_ControlPanel_draw_character(s_display_buffer[s_display_draw_position_y][s_display_draw_position_x]); + } +#endif // defined(PRA32_U_USE_CONTROL_PANEL_OLED_DISPLAY) + +#endif // defined(PRA32_U_USE_CONTROL_PANEL) +} + +void PRA32_U_ControlPanel_on_control_change(uint8_t control_number) +{ + static_cast(control_number); + +#if defined(PRA32_U_USE_CONTROL_PANEL) + if (s_adc_control_target[0] == control_number) { + s_adc_control_catched[0] = false; + } + + if (s_adc_control_target[1] == control_number) { + s_adc_control_catched[1] = false; + } + + if (s_adc_control_target[2] == control_number) { + s_adc_control_catched[2] = false; + } +#endif // defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) +} + +INLINE void PRA32_U_ControlPanel_debug_print(uint32_t loop_counter) { + static_cast(loop_counter); + +#if defined(PRA32_U_USE_DEBUG_PRINT) +#if defined(PRA32_U_USE_CONTROL_PANEL) + switch (loop_counter) { + case 5 * 400: + Serial1.print("\e[7;1H\e[K"); + Serial1.print(static_cast(s_display_buffer[0])); + break; + case 6 * 400: + Serial1.print("\e[8;1H\e[K"); + Serial1.print(static_cast(s_display_buffer[1])); + break; + case 7 * 400: + Serial1.print("\e[9;1H\e[K"); + Serial1.print(static_cast(s_display_buffer[2])); + break; + case 8 * 400: + Serial1.print("\e[10;1H\e[K"); + Serial1.print(static_cast(s_display_buffer[3])); + break; + case 9 * 400: + Serial1.print("\e[11;1H\e[K"); + Serial1.print(static_cast(s_display_buffer[4])); + break; + case 10 * 400: + Serial1.print("\e[12;1H\e[K"); + Serial1.print(static_cast(s_display_buffer[5])); + break; + case 11 * 400: + Serial1.print("\e[13;1H\e[K"); + Serial1.print(static_cast(s_display_buffer[6])); + break; + case 12 * 400: + Serial1.print("\e[14;1H\e[K"); + Serial1.print(static_cast(s_display_buffer[7])); + break; +#if defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + case 13 * 400: + Serial1.print("\e[16;1H\e[K"); + Serial1.print(s_adc_current_value[0]); + break; + case 14 * 400: + Serial1.print("\e[17;1H\e[K"); + Serial1.print(s_adc_current_value[1]); + break; + case 15 * 400: + Serial1.print("\e[18;1H\e[K"); + Serial1.print(s_adc_current_value[2]); + break; +#endif // defined(PRA32_U_USE_CONTROL_PANEL_ANALOG_INPUT) + } +#endif // defined(PRA32_U_USE_CONTROL_PANEL) +#endif // defined(PRA32_U_USE_DEBUG_PRINT) +} diff --git a/Digital-Synth-PRA32-U/pra32-u-program-table.h b/Digital-Synth-PRA32-U/pra32-u-program-table.h index 4f5f354..a7cdc24 100644 --- a/Digital-Synth-PRA32-U/pra32-u-program-table.h +++ b/Digital-Synth-PRA32-U/pra32-u-program-table.h @@ -1,6 +1,6 @@ #pragma once -const uint8_t PROGRAM_NUMBER_DEFAULT = 0; +const uint8_t PROGRAM_NUMBER_DEFAULT = 8; // Preset #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 #10 #11 #12 #13 #14 #15 const uint8_t g_preset_table_OSC_1_WAVE [] = {127, 127, 127, 127, 127, 127, 127, 0 , 127, 127, 127, 127, 127, 127, 127, 0 }; diff --git a/Digital-Synth-PRA32-U/pra32-u-synth.h b/Digital-Synth-PRA32-U/pra32-u-synth.h index 683e46a..8841cbd 100644 --- a/Digital-Synth-PRA32-U/pra32-u-synth.h +++ b/Digital-Synth-PRA32-U/pra32-u-synth.h @@ -13,6 +13,8 @@ #if defined(ARDUINO_ARCH_RP2040) #include +#include +extern I2S g_i2s_output; #endif // defined(ARDUINO_ARCH_RP2040) #include @@ -123,7 +125,7 @@ class PRA32_U_Synth { uint8_t m_program_number_to_write; uint8_t m_wr_prog_to_flash_cc_value; uint8_t m_sp_prog_chg_cc_values[8]; - uint8_t m_current_controller_value_table[128]; + uint8_t m_current_controller_value_table[128 + 128]; uint8_t m_program_table[128][PROGRAM_NUMBER_MAX + 1]; volatile int32_t m_secondary_core_processing_argument; @@ -268,9 +270,9 @@ class PRA32_U_Synth { #if defined(ARDUINO_ARCH_RP2040) #if defined(PRA32_U_USE_EMULATED_EEPROM) -#if defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) && !defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) EEPROM.begin(2048); +#if !defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) for (uint32_t program_number = (PRESET_PROGRAM_NUMBER_MAX + 1); program_number <= PROGRAM_NUMBER_MAX; ++program_number) { if ((EEPROM.read(program_number * 128) == 'U') && (EEPROM.read(program_number * 128 + 1) == program_number)) { for (uint32_t i = 0; i < sizeof(s_program_table_parameters) / sizeof(s_program_table_parameters[0]); ++i) { @@ -279,14 +281,18 @@ class PRA32_U_Synth { } } } -#endif // defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) && !defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) +#endif // !defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) #endif // defined(PRA32_U_USE_EMULATED_EEPROM) #endif // defined(ARDUINO_ARCH_RP2040) program_change(PROGRAM_NUMBER_DEFAULT); } - INLINE void note_on(uint8_t note_number, uint8_t velocity) { + INLINE uint8_t current_controller_value(uint8_t control_number) { + return m_current_controller_value_table[control_number]; + } + + /* INLINE */ void note_on(uint8_t note_number, uint8_t velocity) { if (m_note_on_total_count == 255) { return; } @@ -446,7 +452,7 @@ class PRA32_U_Synth { } } - INLINE void note_off(uint8_t note_number) { + /* INLINE */ void note_off(uint8_t note_number) { if (m_note_on_total_count == 0) { return; } @@ -559,7 +565,7 @@ class PRA32_U_Synth { } } - void all_sound_off() { + void all_notes_off() { m_sustain_pedal = false; m_note_on_number[0] = NOTE_NUMBER_INVALID; m_note_on_number[1] = NOTE_NUMBER_INVALID; @@ -586,18 +592,24 @@ class PRA32_U_Synth { m_eg[5].note_off(); m_eg[6].note_off(); m_eg[7].note_off(); + + control_change(SUSTAIN_PEDAL , 0 ); } INLINE void reset_all_controllers() { pitch_bend(0, 64); - set_modulation(0); - set_breath_controller(0); - set_sustain_pedal(0); + control_change(MODULATION , 0 ); + control_change(BTH_CONTROLLER , 0 ); + control_change(SUSTAIN_PEDAL , 0 ); } - INLINE void control_change(uint8_t control_number, uint8_t controller_value) { + /* INLINE */ void control_change(uint8_t control_number, uint8_t controller_value) { m_current_controller_value_table[control_number] = controller_value; +#if defined(PRA32_U_USE_CONTROL_PANEL) + PRA32_U_ControlPanel_on_control_change(control_number); +#endif // defined(PRA32_U_USE_CONTROL_PANEL) + switch (control_number) { case MODULATION : m_lfo.set_lfo_depth<1>(controller_value); @@ -828,11 +840,11 @@ class PRA32_U_Synth { case OMNI_MODE_ON : case MONO_MODE_ON : case POLY_MODE_ON : - all_sound_off(); // Strictly speaking, this is a violation of MIDI 1.0 Specification... + all_notes_off(); // Strictly speaking, this is a violation of MIDI 1.0 Specification... break; case ALL_SOUND_OFF : - all_sound_off(); + all_notes_off(); break; case RESET_ALL_CTRLS: @@ -848,35 +860,8 @@ class PRA32_U_Synth { uint8_t old_value = m_wr_prog_to_flash_cc_value; m_wr_prog_to_flash_cc_value = controller_value; - if (m_program_number_to_write >= (PRESET_PROGRAM_NUMBER_MAX + 1)) { - if ((old_value == 0) && (controller_value >= 1)) { - for (uint32_t i = 0; i < sizeof(s_program_table_parameters) / sizeof(s_program_table_parameters[0]); ++i) { - uint32_t control_number = s_program_table_parameters[i]; - m_program_table[control_number][m_program_number_to_write] = m_current_controller_value_table[control_number]; - } - -#if defined(ARDUINO_ARCH_RP2040) -#if defined(PRA32_U_USE_EMULATED_EEPROM) -#if defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) && !defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) - // To avoid noise, the data will not be written to the flash - // if PRA32_U_I2S_DAC_MUTE_OFF_PIN is not defined or PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S is defined - for (uint32_t i = 0; i < sizeof(s_program_table_parameters) / sizeof(s_program_table_parameters[0]); ++i) { - uint32_t control_number = s_program_table_parameters[i]; - EEPROM.write(m_program_number_to_write * 128 + control_number, m_current_controller_value_table[control_number]); - } - - EEPROM.write(m_program_number_to_write * 128, 'U'); - EEPROM.write(m_program_number_to_write * 128 + 1, m_program_number_to_write); - - digitalWrite(PRA32_U_I2S_DAC_MUTE_OFF_PIN, LOW); - - EEPROM.commit(); - - digitalWrite(PRA32_U_I2S_DAC_MUTE_OFF_PIN, HIGH); -#endif // defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) && !defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) -#endif // defined(PRA32_U_USE_EMULATED_EEPROM) -#endif // defined(ARDUINO_ARCH_RP2040) - } + if ((old_value == 0) && (m_wr_prog_to_flash_cc_value >= 1)) { + write_parameters_to_program(m_program_number_to_write); } } break; @@ -902,7 +887,7 @@ class PRA32_U_Synth { } } - INLINE void pitch_bend(uint8_t lsb, uint8_t msb) { + /* INLINE */ void pitch_bend(uint8_t lsb, uint8_t msb) { int16_t pitch_bend = ((static_cast(msb) << 8) >> 1) + lsb - 8192; m_osc.set_pitch_bend(pitch_bend); } @@ -918,6 +903,48 @@ class PRA32_U_Synth { } } + /* INLINE */ void write_parameters_to_program(uint8_t program_number_to_write) { + if (program_number_to_write < (PRESET_PROGRAM_NUMBER_MAX + 1)) { + return; + } + + for (uint32_t i = 0; i < sizeof(s_program_table_parameters) / sizeof(s_program_table_parameters[0]); ++i) { + uint32_t control_number = s_program_table_parameters[i]; + m_program_table[control_number][program_number_to_write] = m_current_controller_value_table[control_number]; + } + +#if defined(ARDUINO_ARCH_RP2040) +#if defined(PRA32_U_USE_EMULATED_EEPROM) + for (uint32_t i = 0; i < sizeof(s_program_table_parameters) / sizeof(s_program_table_parameters[0]); ++i) { + uint32_t control_number = s_program_table_parameters[i]; + EEPROM.write(program_number_to_write * 128 + control_number, m_current_controller_value_table[control_number]); + } + + EEPROM.write(program_number_to_write * 128, 'U'); + EEPROM.write(program_number_to_write * 128 + 1, program_number_to_write); + +#if !defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) + // To avoid noise, the data will not be written to the flash + // if PRA32_U_I2S_DAC_MUTE_OFF_PIN is not defined or PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S is defined + +#if defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) + digitalWrite(PRA32_U_I2S_DAC_MUTE_OFF_PIN, LOW); +#else // defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) + g_i2s_output.end(); +#endif // defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) + + EEPROM.commit(); + +#if defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) + digitalWrite(PRA32_U_I2S_DAC_MUTE_OFF_PIN, HIGH); +#else // defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) + g_i2s_output.begin(); +#endif // defined(PRA32_U_I2S_DAC_MUTE_OFF_PIN) +#endif +#endif // defined(PRA32_U_USE_EMULATED_EEPROM) +#endif // defined(ARDUINO_ARCH_RP2040) + } + INLINE int16_t process(int16_t& right_level) { ++m_count; @@ -1045,6 +1072,11 @@ class PRA32_U_Synth { voice_mixer_output = amp_output[0]; } else { +#if defined(PRA32_U_USE_2_CORES_FOR_SIGNAL_PROCESSING) + m_secondary_core_processing_argument = 0; + m_secondary_core_processing_request = 1; +#endif // defined(PRA32_U_USE_2_CORES_FOR_SIGNAL_PROCESSING) + osc_output[0] = m_osc.process<0>(noise_int15); int16_t osc_mixer_output = osc_output[0] << 1; @@ -1052,6 +1084,17 @@ class PRA32_U_Synth { amp_output [0] = m_amp [0].process(filter_output[0]); voice_mixer_output = amp_output[0]; + +#if defined(PRA32_U_USE_2_CORES_FOR_SIGNAL_PROCESSING) + // Wait + for (volatile uint32_t i = 0; i < 30; ++i) { + ; + } + + while (m_secondary_core_processing_request) { + ; + } +#endif // defined(PRA32_U_USE_2_CORES_FOR_SIGNAL_PROCESSING) } int16_t chorus_fx_output_r; @@ -1093,7 +1136,9 @@ class PRA32_U_Synth { #endif // defined(PRA32_U_USE_PWM_AUDIO_INSTEAD_OF_I2S) } - INLINE void secondary_core_process() { + INLINE boolean secondary_core_process() { + boolean processed = false; + #if defined(PRA32_U_USE_2_CORES_FOR_SIGNAL_PROCESSING) if (m_secondary_core_processing_request == 1) { int16_t noise_int15 = static_cast(m_secondary_core_processing_argument); @@ -1117,11 +1162,16 @@ class PRA32_U_Synth { osc_output[3] = m_osc.process<3>(noise_int15); m_secondary_core_processing_result = osc_output[2] + osc_output[3]; + } else { + m_secondary_core_processing_result = 0; } m_secondary_core_processing_request = 0; + processed = true; } #endif // defined(PRA32_U_USE_2_CORES_FOR_SIGNAL_PROCESSING) + + return processed; } private: @@ -1184,7 +1234,7 @@ class PRA32_U_Synth { #endif if (m_voice_mode != new_voice_mode) { m_voice_mode = new_voice_mode; - all_sound_off(); + all_notes_off(); m_osc.set_gate_enabled(m_voice_mode == VOICE_PARAPHONIC); } } diff --git a/PRA32-U-Change-History.md b/PRA32-U-Change-History.md index a36a2d4..7896ffc 100644 --- a/PRA32-U-Change-History.md +++ b/PRA32-U-Change-History.md @@ -1,5 +1,17 @@ ## Digital Synth PRA32-U Change History +- v2.3.1 (2024-04-21): + - Abolish the option to write user programs to the flash when using PWM audio due to performance problem uncovered + - Tested with Arduino-Pico version 3.7.2 +- v2.3.0 (2024-04-21): + - Allow user programs to be written to the flash when using I2S DAC without mute-off pin + - Add the option to write user programs to the flash when using PWM audio (for Raspberry Pi Pico/H/W/WH) + - Add the option PRA32_U_I2S_SWAP_LEFT_AND_RIGHT + - Add the option PRA32-U with Panel, Prototype 1 (experimental) + - Change the default program #0 to #8 + - Use core 1 for Debug Print + - Other changes + - Tested with Arduino-Pico version 3.7.2 - v2.2.2 (2024-02-10): - Fix a bug that the parameters are not written to the flash when using I2S DAC, even if PRA32_U_I2S_DAC_MUTE_OFF_PIN is defined - Tested with Arduino-Pico version 3.7.0 diff --git a/PRA32-U-MIDI-Implementation-Chart.md b/PRA32-U-MIDI-Implementation-Chart.md index 6671b77..1fddaf2 100644 --- a/PRA32-U-MIDI-Implementation-Chart.md +++ b/PRA32-U-MIDI-Implementation-Chart.md @@ -1,6 +1,6 @@ ``` - [Polyphonic/Paraphonic Synthesizer] Date: 2024-02-10 - Model: Digital Synth PRA32-U MIDI Implementation Chart Version: 2.2.2 + [Polyphonic/Paraphonic Synthesizer] Date: 2024-04-21 + Model: Digital Synth PRA32-U MIDI Implementation Chart Version: 2.3.1 +-------------------------------+---------------+---------------+-------------------------------------+ | Function... | Transmitted | Recognized | Remarks | +-------------------------------+---------------+---------------+-------------------------------------+ @@ -88,11 +88,18 @@ | | | | | | 87 | x | o | Program Number to Write to $$$$ | | 106 | x | o | Write Parameters to Program $$$$ | -| 112-119 | | | Program Change #8-15 by CC | +| 112 | | | Program Change #8 by CC | +| 113 | | | Program Change #9 by CC | +| 114 | | | Program Change #10 by CC | +| 115 | | | Program Change #11 by CC | +| 116 | | | Program Change #12 by CC | +| 117 | | | Program Change #13 by CC | +| 118 | | | Program Change #14 by CC | +| 119 | | | Program Change #15 by CC | | 111 | x | x | [Reserved] | +-------------------------------+---------------+---------------+-------------------------------------+ | Program | x | o | | -| Change : True # | ************* | 0-15 | Default 0 | +| Change : True # | ************* | 0-15 | Default 8 | +-------------------------------+---------------+---------------+-------------------------------------+ | System Exclusive | x | x | | +-------------------------------+---------------+---------------+-------------------------------------+ diff --git a/PRA32-U-Parameter-Guide.md b/PRA32-U-Parameter-Guide.md index 10ef168..815e2ba 100644 --- a/PRA32-U-Parameter-Guide.md +++ b/PRA32-U-Parameter-Guide.md @@ -1,6 +1,6 @@ -# Digital Synth PRA32-U Parameter Guide v2.2.2 +# Digital Synth PRA32-U Parameter Guide v2.3.1 -- 2024-02-10 ISGK Instruments +- 2024-04-21 ISGK Instruments - ## Control Change Parameters diff --git a/README.md b/README.md index d682f4e..14a396c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Digital Synth PRA32-U v2.2.2 +# Digital Synth PRA32-U v2.3.1 -- 2024-02-10 ISGK Instruments +- 2024-04-21 ISGK Instruments - @@ -14,7 +14,7 @@ - An **I2S DAC** hardware (e.g. Pimoroni Pico Audio Pack) is required - PWM Audio can also be used instead of I2S (PWM Audio does not require an I2S DAC hardware) - Prebuilt UF2 files ("bin") - - "Digital-Synth-PRA32-U-2.2.2-Pimoroni-Pico-Audio-Pack.uf2" is for Raspberry Pi Pico and Pimoroni Pico Audio Pack + - "Digital-Synth-PRA32-U-2.3.1-Pimoroni-Pico-Audio-Pack.uf2" is for Raspberry Pi Pico and Pimoroni Pico Audio Pack ## [Change History](/PRA32-U-Change-History.md) @@ -27,8 +27,8 @@ - Info: - Please install Arduino-Pico = **Raspberry Pi Pico/RP2040** (by Earle F. Philhower, III) core - Additional Board Manager URL: - - This sketch is tested with version **3.7.0**: - - Arduino-Pico version 3.7.0 includes Adafruit TinyUSB Library version 2.3.0 + - This sketch is tested with version **3.7.2**: + - Arduino-Pico version 3.7.2 includes Adafruit TinyUSB Library version 2.3.0 - Info: - Please install Arduino **MIDI Library** (by Francois Best, lathoub) - This sketch is tested with version **5.0.2**: @@ -48,14 +48,18 @@ #### UART MIDI (Optional) - UART MIDI can also be used + - Noise caused by USB communication can be avoided - Uncomment out `//#define PRA32_U_USE_UART_MIDI` in "Digital-Synth-PRA32-U.ino" and modify `PRA32_U_UART_MIDI_SPEED`, `PRA32_U_UART_MIDI_TX_PIN`, and `PRA32_U_UART_MIDI_RX_PIN` -- Speed: 31250 bps (default, for DIN/TRS MIDI) or 38400 bps -- GP4 and GP5 pins are used by UART1 TX and UART1 RX by default + - Speed: 31250 bps (default, for DIN/TRS MIDI) or 38400 bps (for PC) + - GP4 and GP5 pins are used by UART1 TX and UART1 RX by default - DIN/TRS MIDI is available by using (and modifying) Adafruit MIDI FeatherWing Kit, for example - Adafruit [MIDI FeatherWing Kit](https://www.adafruit.com/product/4740) - 木下研究所 [MIDI-UARTインターフェースさん キット](https://www.switch-science.com/products/8117) (Shipping to Japan only) - necobit電子 [MIDI Unit for GROVE](https://necobit.com/denshi/grove-midi-unit/) (Shipping to Japan only) +- We recommend using [Hairless MIDI<->Serial Bridge](https://projectgus.github.io/hairless-midiserial/) on PC + - On Windows, We recommend using [loopMIDI](https://www.tobias-erichsen.de/software/loopmidi.html) (virtual loopback MIDI cable) + - On Mac, a virtual MIDI bus (port) can be created by using the IAC bus ### Audio (Output) @@ -65,9 +69,8 @@ - Use an I2S DAC (e.g. Texas Instruments PCM5100A and Cirrus Logic CS4344), Sampling Rate: 48 kHz, Bit Depth: 16 bit - NOTE: The RP2040 system clock (sysclk) changes to overclocked 147.6 MHz by I2S Audio Library setSysClk() - Modify `PRA32_U_I2S_DAC_MUTE_OFF_PIN`, `PRA32_U_I2S_DATA_PIN`, `PRA32_U_I2S_MCLK_PIN`, `PRA32_U_I2S_MCLK_MULT`, - `PRA32_U_I2S_BCLK_PIN`, and `PRA32_U_I2S_SWAP_BCLK_AND_LRCLK_PINS` + `PRA32_U_I2S_BCLK_PIN`, `PRA32_U_I2S_SWAP_BCLK_AND_LRCLK_PINS`, and `PRA32_U_I2S_SWAP_LEFT_AND_RIGHT` in "Digital-Synth-PRA32-U.ino" to match the hardware configuration - - NOTE: To avoid noise, the parameters will not be written to the flash if `PRA32_U_I2S_DAC_MUTE_OFF_PIN` is not defined - The default setting is for Pimoroni [Pico Audio Pack](https://shop.pimoroni.com/products/pico-audio-pack) (PIM544) ``` #define PRA32_U_I2S_DAC_MUTE_OFF_PIN (22) @@ -76,18 +79,9 @@ //#define PRA32_U_I2S_MCLK_MULT (0) #define PRA32_U_I2S_BCLK_PIN (10) // LRCLK Pin is PRA32_U_I2S_BCLK_PIN + 1 #define PRA32_U_I2S_SWAP_BCLK_AND_LRCLK_PINS (false) +#define PRA32_U_I2S_SWAP_LEFT_AND_RIGHT (false) ``` - The following is setting is for [Pimoroni Pico VGA Demo Base](https://shop.pimoroni.com/products/pimoroni-pico-vga-demo-base) (PIM553) - and [Pimoroni Pico DV Demo Base](https://shop.pimoroni.com/products/pimoroni-pico-dv-demo-base) (PIM588) -``` -//#define PRA32_U_I2S_DAC_MUTE_OFF_PIN (0) -#define PRA32_U_I2S_DATA_PIN (26) -//#define PRA32_U_I2S_MCLK_PIN (0) -//#define PRA32_U_I2S_MCLK_MULT (0) -#define PRA32_U_I2S_BCLK_PIN (27) // LRCLK Pin is is PRA32_U_I2S_BCLK_PIN + 1 -#define PRA32_U_I2S_SWAP_BCLK_AND_LRCLK_PINS (false) -``` -- The following is setting is for Waveshare Pico-Audio Initial Version (WAVESHARE-20167) ``` //#define PRA32_U_I2S_DAC_MUTE_OFF_PIN (0) #define PRA32_U_I2S_DATA_PIN (26) @@ -95,6 +89,7 @@ //#define PRA32_U_I2S_MCLK_MULT (0) #define PRA32_U_I2S_BCLK_PIN (27) // LRCLK Pin is is PRA32_U_I2S_BCLK_PIN + 1 #define PRA32_U_I2S_SWAP_BCLK_AND_LRCLK_PINS (false) +#define PRA32_U_I2S_SWAP_LEFT_AND_RIGHT (false) ``` - The following is setting is for [Waveshare Pico-Audio](https://www.waveshare.com/wiki/Pico-Audio) Rev2.1 Version (WAVESHARE-20167) ``` @@ -104,6 +99,7 @@ #define PRA32_U_I2S_MCLK_MULT (256) #define PRA32_U_I2S_BCLK_PIN (27) // LRCLK Pin is is PRA32_U_I2S_BCLK_PIN + 1 #define PRA32_U_I2S_SWAP_BCLK_AND_LRCLK_PINS (true) +#define PRA32_U_I2S_SWAP_LEFT_AND_RIGHT (true) ``` @@ -149,7 +145,7 @@ - When not using PRA32-U CTRL - PRA32-U can also be controlled by MIDI without using PRA32-U CTRL - Refer to "PRA32-U-MIDI-Implementation-Chart.txt" for the supported functions - - The default program is #0 + - The default program is #8 - Programs #0-15 can be modified by editing "pra32-u-program-table.h" - PRA32-U CTRL functions related to parameter writing - Write: Write the current parameters to PRA32-U (Program #8-15 and the flash) @@ -254,15 +250,43 @@ graph LR - This image was created with Fritzing. +## PRA32-U with Panel, Prototype 1 (Experimental) (Optional) + +![PRA32-U with Panel, Prototype 1](./pra32-u-with-panel-prototype-1.jpg) + +- Uncomment out `//#define PRA32_U_USE_CONTROL_PANEL` in "Digital-Synth-PRA32-U.ino" and modify options +- This option requires 3 tactile switches, 3 ADCs, and SSD1306 compatible monochrome 128x64 OLED Display + - Tested with Seeed Studio's Grove Shield for Pi Pico, Buttons, Rotary Angle Sensors, and a OLED Display 0.96 inch +- Inputs + - SW0: Prev Key + - SW1: Next Key + - SW2: Play Key (play notes) + - ADC0: Parameter A + - ADC1: Parameter B + - ADC2: Parameter C +- Panel Parameters + - Panel Pitch + - Panel Scale [Ful|Pen|Maj] + - Full = Chromatic, 10 + 7/12 octaves + - Major Pentatonic, 2 octaves + - Major, 2 octaves + - Panel Transpose [-|+] + - Panel Velocity +- Other Operations + - Write Program 8-15: Change the value from 0 [Rdy] to 127 [Exe] + - Read Program 1-7, 8-15: Change the value from 0-63 [Rdy] to 64-127 [Exe] +- NOTE: Specifications may change significantly in the future + + ## License ![CC0](http://i.creativecommons.org/p/zero/1.0/88x31.png) -**Digital Synth PRA32-U v2.2.2 by ISGK Instruments (Ryo Ishigaki)** +**Digital Synth PRA32-U v2.3.1 by ISGK Instruments (Ryo Ishigaki)** To the extent possible under law, ISGK Instruments (Ryo Ishigaki) has waived all copyright and related or neighboring rights -to Digital Synth PRA32-U v2.2.2. +to Digital Synth PRA32-U v2.3.1. You should have received a copy of the CC0 legalcode along with this work. If not, see . diff --git a/bin/Digital-Synth-PRA32-U-2.2.2-Pimoroni-Pico-Audio-Pack.uf2 b/bin/Digital-Synth-PRA32-U-2.2.2-Pimoroni-Pico-Audio-Pack.uf2 deleted file mode 100644 index 0af2334..0000000 Binary files a/bin/Digital-Synth-PRA32-U-2.2.2-Pimoroni-Pico-Audio-Pack.uf2 and /dev/null differ diff --git a/bin/Digital-Synth-PRA32-U-2.3.1-Pimoroni-Pico-Audio-Pack.uf2 b/bin/Digital-Synth-PRA32-U-2.3.1-Pimoroni-Pico-Audio-Pack.uf2 new file mode 100644 index 0000000..e86ed7a Binary files /dev/null and b/bin/Digital-Synth-PRA32-U-2.3.1-Pimoroni-Pico-Audio-Pack.uf2 differ diff --git a/pra32-u-ctrl.html b/pra32-u-ctrl.html index f29343c..b861c56 100644 --- a/pra32-u-ctrl.html +++ b/pra32-u-ctrl.html @@ -41,7 +41,7 @@ }