summaryrefslogtreecommitdiff
path: root/controller/libs/midi.c
diff options
context:
space:
mode:
Diffstat (limited to 'controller/libs/midi.c')
-rw-r--r--controller/libs/midi.c826
1 files changed, 0 insertions, 826 deletions
diff --git a/controller/libs/midi.c b/controller/libs/midi.c
deleted file mode 100644
index b718818..0000000
--- a/controller/libs/midi.c
+++ /dev/null
@@ -1,826 +0,0 @@
- // This file is written to be read side-along with the MIDI 1.0 spec.
-// Note the tables at its very end, with /absolutely no direct allusion in the text/.
-
-#include "midi.h"
-
-#ifdef RUNNING_STATUS
-uint8_t last_status = 0x00;
-#endif
-
-// Helper functions
-#define MAX_DATA_BYTE 0b01111111
-static inline void MIDI_bare_send(uint8_t status) {
-#ifdef DEBUG
- if (status <= MAX_DATA_BYTE) {
- while(true); // Illegal status.
- }
-#endif
-
- pfns->uart_write(status);
-
-}
-
-static inline void MIDI_single_send(uint8_t status, uint8_t byte) {
-#ifdef DEBUG
- if (status <= MAX_DATA_BYTE || byte > MAX_DATA_BYTE) {
- while(true); // Illegal status or data byte.
- }
-#endif
-
-#ifdef RUNNING_STATUS
- if (status != last_status) {
- pfns->uart_write(status);
- last_status = status;
- }
-#else
- pfns->uart_write(status);
-#endif
- pfns->uart_write(byte);
-}
-
-static inline void MIDI_send(uint8_t status, uint8_t byte1, uint8_t byte2) {
-#ifdef DEBUG
- if (status <= MAX_DATA_BYTE || byte1 > MAX_DATA_BYTE || byte2 > MAX_DATA_BYTE) {
- while(true); // Illegal status or data byte.
- }
-#endif
-
-#ifdef RUNNING_STATUS
- if (status != last_status) {
- pfns->uart_write(status);
- last_status = status;
- }
-#else
- pfns->uart_write(status);
-#endif
- pfns->uart_write(byte1);
- pfns->uart_write(byte2);
-}
-
-
-#define MAX_NON_UNIVERSAL_ID (MAX_DATA_BYTE - 2)
-#define SYSEX_STATUS 0xf0
-#define EOX_STATUS 0xf7
-void sysex(uint16_t manufacturer_id, uint8_t* contents, size_t contents_len) {
-#ifdef DEBUG
- if (manufacturer_id == 0 || (manufacturer_id >> 8) > MAX_DATA_BYTE || (manufacturer_id & 0x00ff) > MAX_DATA_BYTE) {
- while(true); // Invalid ID.
- }
-
- // Pretty inefficient to iterate contents twice, but prevents writing partial SysEx messages to the bus.
- for (int i = 0; i < contents_len, i++) {
- if (contents[i] > MAX_DATA_BYTE) {
- while(true);
- }
- }
-#endif
-
- if ((manufacturer_id >> 8) != 0) {
- pfns->uart_write(SYSEX_STATUS);
- pfns->uart_write(0x00);
- pfns->uart_write(manufacturer_id >> 8);
- pfns->uart_write(manufacturer_id & 0x00ff);
- } else {
- if (manufacturer_id > MAX_NON_UNIVERSAL_ID) {
- while(true); // Used universal sysex ID.
- }
-
- pfns->uart_write(manufacturer_id);
- }
-
- for (int i = 0; i < message.contents_len; i++) {
- pfns->uart_write(message.contents[i]);
- }
-
- pfns->uart_write(EOX_STATUS);
-}
-
-#define NON_REAL_TIME_ID 0x7e
-#define REAL_TIME_ID 0x7f
-void universal_nonrealtime(uint8_t device_id, uint16_t sub_id, uint8_t *contents, size_t contents_len) {
-#ifdef DEBUG
- if ((sub_id >> 8) > MAX_DATA_BYTE || (sub_id & 0x00ff) > MAX_DATA_BYTE) {
- while(true);
- }
-
- for (int i = 0; i < contents_len; i++) {
- if (contents[i] > MAX_DATA_BYTE) {
- while(true);
- }
- }
-#endif
-
- pfns->uart_write(SYSEX_STATUS);
- pfns->uart_write(REAL_TIME_ID);
- pfns->uart_write(sub_id >> 8);
- pfns->uart_write(sub_id & 0x00ff);
-
- for (int i = 0; i < message.contents_len; i++) {
- pfns->uart_write(message.contents[i]);
- }
-
- pfns->uart_write(EOX_STATUS);
-}
-
-void universal_realtime(uint8_t device_id, uint16_t sub_id, uint8_t *contents, size_t contents_len) {
-#ifdef DEBUG
- if ((sub_id >> 8) > MAX_DATA_BYTE || (sub_id & 0x00ff) > MAX_DATA_BYTE) {
- while(true);
- }
-
- for (int i = 0; i < contents_len; i++) {
- if (contents[i] > MAX_DATA_BYTE) {
- while(true);
- }
- }
-#endif
-
- pfns->uart_write(SYSEX_STATUS);
- pfns->uart_write(NON_REAL_TIME_ID);
- pfns->uart_write(sub_id >> 8);
- pfns->uart_write(sub_id & 0x00ff);
-
- for (int i = 0; i < message.contents_len; i++) {
- pfns->uart_write(message.contents[i]);
- }
-
- pfns->uart_write(EOX_STATUS);
-}
-// Channel voice messages.
-
-#define MAX_CHANNEL 0x0f
-#define NOTE_OFF_MASK 0x80
-#define NOTE_ON_MASK 0x90
-#define POLY_KEY_PRESSURE_MASK 0xa0
-#define CONTROL_CHANGE_MASK 0xb0
-#define PROGRAM_CHANGE_MASK 0xc0
-#define AFTERTOUCH_MASK 0xd0
-#define PITCH_BEND_MASK 0xe0
-
-#define MIDDLE_VELOCITY 0x40
-
-#ifdef KEY_ON_VELOCITY
-void note_on(uint8_t channel, uint8_t note, uint8_t velocity) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE || velocity > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_send(NOTE_ON_MASK | channel, note, velocity);
-
-}
-
-#else
-
-void note_on(uint8_t channel, uint8_t note) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_send(NOTE_ON_MASK | channel, note, MIDDLE_VELOCITY);
-
-}
-
-
-#endif
-
-#ifdef RELEASE_VELOCITY
-
-void note_off(uint8_t channel, uint8_t note, uint8_t velocity) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE || velocity > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_send(NOTE_OFF_MASK | channel, note, velocity);
-
-}
-
-#else
-
-void note_off(uint8_t channel, uint8_t note) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
-#ifdef ACTUAL_OFF_MESSAGE
- MIDI_send(NOTE_OFF_MASK | channel, note, MIDDLE_VELOCITY);
-#else
- MIDI_send(NOTE_ON_MASK | channel, note, 0);
-#endif
-
-}
-
-#endif
-
-#define MAX_CONTROLLER 119
-void control_change(uint8_t channel, uint8_t controller_number, uint8_t control_value) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || controller_number > MAX_CONTROLLER_NUMBER || control_value > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, controller_number, control_value);
-
-}
-
-void program_change(uint8_t channel, uint8_t program_number) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || program_number > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_single_send(PROGRAM_CHANGE_MASK | channel, program_number);
-
-}
-
-void aftertouch(uint8_t channel, uint8_t pressure_value) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || pressure_value > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_single_send(AFTERTOUCH_MASK | channel, pressure_value);
-
-}
-
-void pitch_bend_change(uint8_t channel, uint16_t pressure_value) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || pressure_value > (MAX_DATA_BYTE << 8) | MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_single_send(PITCH_BEND_CHANGE_MASK | channel, pressure_value);
-
-}
-
-
-
-// Channel mode messages.
-
-#define SOUND_OFF_MODE (MAX_CONTROLLER + 1)
-#define RESET_ALL_MODE (MAX_CONTROLLER + 2)
-#define LOCAL_CONTROL_MODE (MAX_CONTROLLER + 3)
-#define NOTES_OFF_MODE (MAX_CONTROLLER + 4)
-#define OMNI_OFF_MODE (MAX_CONTROLLER + 5)
-#define OMNI_ON_MODE (MAX_CONTROLLER + 6)
-#define MONO_ON_MODE (MAX_CONTROLLER + 7)
-#define POLY_ON_MODE (MAX_CONTROLLER + 8)
-
-void all_sound_off(uint8_t channel) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, SOUND_OFF_MODE, 0);
-
-}
-
-void reset_all_controllers(uint8_t channel) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, RESET_ALL_MODE, 0);
-
-}
-
-void local_control_on(uint8_t channel) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, LOCAL_CONTROL_MODE, MAX_DATA_BYTE);
-
-}
-
-void local_control_off(uint8_t channel) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, LOCAL_CONTROL_MODE, 0);
-
-}
-
-void all_notes_off(uint8_t channel) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, NOTES_OFF_MODE, 0)
-
-}
-
-void omni_on(uint8_t channel) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, OMNI_ON_MODE, 0);
-
-}
-
-void omni_off(uint8_t channel) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, OMNI_OFF_MODE, 0);
-
-}
-
-#define RECEIVER_CHANNEL_COUNT 0
-void mono_on(uint8_t channel, uint8_t channel_count) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL || channel_count > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, MONO_ON_MODE, channel_count);
-
-}
-
-void poly_on(uint8_t channel) {
-#ifdef DEBUG
- if (channel > MAX_CHANNEL) {
- while(true);
- }
-#endif
-
- MIDI_send(CONTROL_CHANGE_MASK | channel, POLY_ON_MODE, 0);
-
-}
-
-
-// System common messages.
-// Not implemented:
-// - MTC Quarter Frame
-// EOX is automatically sent in the functions that send exclusives.
-
-#define MTC_QUARTER_FRAME_STATUS 0xf1
-#define SONG_POSITION_POINTER_STATUS 0xf2
-// Undefined.
-#define SONG_SELECT_STATUS 0xf3
-#define TUNE_REQUEST_STATUS 0xf6
-
-void song_position_pointer(uint16_t position) {
-#ifdef DEBUG
- if (position & 0x0ff > MAX_DATA_BYTE || position >> 8 > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_send(SONG_POSITION_POINTER_STATUS, position & 0x00ff, position >> 8);
-
-}
-
-void song_select(uint8_t song) {
-#ifdef DEBUG
- if (song > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- MIDI_single_send(SONG_SELECT_STATUS, song);
-
-}
-
-void tune_request() {
- MIDI_bare_send(TUNE_REQUEST_STATUS);
-}
-
-
-
-// System real time messages.
-// Not implemented:
-// - Timing Clock,
-// - Start,
-// - Continue,
-// - Stop,
-// - Active Sensing.
-
-#define TIMING_CLOCK_STATUS 0xf8
-// Undefined.
-#define START_STATUS 0xfa
-#define CONTINUE_STATUS 0xfb
-#define STOP_STATUS 0xfc
-// Undefined.
-#define ACTIVE_SENSING_STATUS 0xfe
-#define SYSTEM_RESET_STATUS 0xff
-void timing_clock() {
- MIDI_bare_send(TIMING_CLOCK_STATUS);
-}
-
-void srt_start() {
- MIDI_bare_send(START_STATUS);
-}
-
-void srt_continue() {
- MIDI_bare_send(CONTINUE_STATUS);
-}
-
-void srt_stop() {
- MIDI_bare_send(STOP_STATUS);
-}
-
-void active_sensing() {
- MIDI_bare_send(ACTIVE_SENSING_STATUS);
-}
-
-void MIDI_reset() {
- MIDI_bare_send(SYSTEM_RESET_STATUS);
-}
-
-
-// Universal system exclusive messages.
-
-
-// Only implement MIDI Tuning Standard universals and general information.
-
-
-#define TUNING_STANDARD_SUBID 0x08
-#define BULK_DUMP_REQUEST_SUBID 0x00
-void bulk_tuning_dump_request(uint8_t device_id, uint8_t program) {
-#ifdef DEBUG
- if (program > MAX_DATA_BYTE || device_id > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- uint8_t contents[] = {program};
-
- universal_nonrealtime(device_id, TUNING_STANDARD_SUBID, BULK_DUMP_REQUEST_SUBID, contents, 1);
-
-}
-
-
-#define BULK_DUMP_REPLY_SUBID 0x01
-void bulk_tuning_dump(uint8_t device_id, uint8_t program, char* name, uint8_t* tuning_data) {
-#ifdef DEBUG
- if (device_id > MAX_DATA_BYTE || program > MAX_DATA_BYTE) {
- while(true);
- }
-#endif
-
- uint8_t *contents = malloc(1 + TUNING_NAME_LENGTH + TUNING_LENGTH + 1);
- contents[0] = program;
- memcpy(contents + 1, name, TUNING_NAME_LENGTH);
- memcpy(contents + 1 + TUNING_NAME_LENGTH, tuning_data, TUNING_LENGTH);
-
- // I hate this freaking "standard"...what TF do I checksum???
- uint8_t checksum = NON_REAL_TIME_ID ^ device_id ^ TUNING_STANDARD_SUBID ^ BULK_DUMP_REPLY_SUBID ^ program;
- for (int i = 0; i < TUNING_LENGTH; i++) {
- checksum ^= tuning_data[i];
- }
-
- contents[1 + TUNING_NAME_LENGTH + DEVICE_KEY_COUNT] = checksum;
-
- universal_nonrealtime(device_id, TUNING_STANDARD_SUBID, BULK_DUMP_REPLY_SUBID, contents,
- 1 + TUNING_NAME_LENGTH + TUNING_LENGTH + 1);
-
- free(contents);
-
-}
-
-#define NOTE_CHANGE_SUBID 0x02
-void single_note_tuning_change(uint8_t device_id, uint8_t program, uint8_t *note_tuning_data, uint8_t keys_changed) {
-#ifdef DEBUG
- if (device_id > MAX_DATA_BYTE || program > MAX_DATA_BYTE || keys_changed > DEVICE_KEY_COUNT) {
- while(true);
- }
-#endif
-
- uint8_t *contents = malloc(2 + NOTE_TUNING_BYTES_PER_KEY * keys_changed);
- contents[0] = program;
- contents[1] = keys_changed;
- memcpy(contents + 2, note_tuning_data, NOTE_TUNING_BYTES_PER_KEY * keys_changed);
-
- universal_realtime(device_id, TUNING_STANDARD_SUBID, NOTE_CHANGE_SUBID, contents,
- 2 + NOTE_TUNING_BYTES_PER_KEY * keys_changed);
-
- free(contents);
-
-}
-
-// TODO: tuning banks.
-
-
-// Parsing.
-// Stream parsing.
-typedef struct {
- uint8_t status;
- bool first_byte;
- uint8_t byte0;
- bool send_eox;
- uint8_t *stack;
- uint8_t top;
- size_t size;
-} ParserMemory;
-
-#define WAITING_FOR_STATUS 0x00
-ParserMemory memory = {.status = WAITING_FOR_STATUS,
- .first_byte = false,
- .byte0 = 0x00,
- .send_eox = false,
- .stack = malloc(128),
- .top = 0,
- .size = 128};
-
-static inline void push(uint8_t val) {
- if (memory->top == memory->size - 1) {
- memory->stack = realloc(memory->stack, memory->size + 128);
- }
-
- memory->stack[memory->top + 1] = val;
- ++memory->top;
-}
-
-static inline uint8_t pop() {
- if (memory->size - memory->top > 128) {
- memory->stack = realloc(memory->stack, memory->size - 128);
- }
-
- --memory->top;
- return memory->stack[memory->top + 1];
-}
-
-static inline void reset() {
- memory->stack = realloc(memory->stack, 128);
- memory->size = 128;
- memory->top = 0;
- memory->status = WAITING_FOR_STATUS;
-}
-
-static inline void second_byte() {
- memory->first_data_byte = false;
- memory->byte0 = byte;
-}
-
-#define channel (memory->status & 0x0f)
-
-
-// Memory should be large enough to handle the largest message that's expected to be processed automatically here.
-void parse_midi_stream(uint8_t byte) {
- switch (byte) {
- // Status byte.
- case NOTE_OFF_MASK ... (PITCH_BEND_MASK + MAX_CHANNEL):
- memory->status = byte;
- break;
-
- case MTC_QUARTER_FRAME_STATUS ... SONG_SELECT_STATUS:
- memory->status = byte;
- break;
- case TUNE_REQUEST_STATUS:
- pfns->tune_request_handler();
- memory->status = WAITING_FOR_STATUS;
- break;
-
- case TIMING_CLOCK_STATUS:
- pfns->timing_clock_handler();
- break;
- case START_STATUS:
- pfns->start_handler();
- break;
- case CONTINUE_STATUS:
- pfns->continue_handler();
- break;
- case STOP_STATUS:
- pfns->stop_handler();
- break;
- case ACTIVE_SENSING_STATUS:
- pfns->active_sensing_handler();
- break;
- case SYSTEM_RESET_STATUS:
- pfns->system_reset_handler();
- break;
- case SYSEX_STATUS:
- memory->status = byte;
- break;
- case EOX_STATUS:
- if (memory->send_eox) {
- pfns->end_of_sysex_handler();
- memory->send_eox = false;
- }
- reset();
- break;
-
- // Data byte.
- case 0x00 ... MAX_DATA_BYTE:
- switch (memory->status) {
- case WAITING_FOR_STATUS:
- break;
-
- case NOTE_OFF_MASK ... (NOTE_OFF_MASK + MAX_CHANNEL):
- if (memory->first_data_byte)
- second_byte();
- else {
- pfns->note_off_handler(channel, memory->byte0, byte);
- memory->first_data_byte = true;
- }
- break;
- case NOTE_ON_MASK ... (NOTE_ON_MASK + MAX_CHANNEL):
- if (memory->first_data_byte)
- second_byte();
- else {
- pfns->note_on_handler(channel, memory->byte0, byte);
- memory->first_data_byte = true;
- }
- break;
- case POLY_KEY_PRESSURE_MASK ... (POLY_KEY_PRESSURE_MASK + MAX_CHANNEL):
- if (memory->first_data_byte)
- second_byte();
- else {
- pfns->poly_key_handler(channel, memory->byte0, byte);
- memory->first_data_byte = true;
- }
- break;
- case CONTROL_CHANGE_MASK ... (CONTROL_CHANGE_MASK + MAX_CHANNEL):
- if (memory->first_data_byte):
- second_byte();
- else {
- switch (memory->byte0) {
- case 0x00 ... MAX_CONTROLLER:
- pfns->control_change_handler(channel);
- break;
- case SOUND_OFF_MODE:
- pfns->all_sound_off_handler(channel);
- break;
- case RESET_ALL_MODE:
- pfns->reset_all_controllers_handler(channel);
- break;
- case LOCAL_CONTROL_MODE:
- pfns->local_control_handler(channel);
- break;
- case NOTES_OFF_MODE:
- pfns->all_notes_off_handler(channel);
- break;
- case OMNI_OFF_MODE:
- pfns->omni_off_handler(channel);
- break;
- case OMNI_ON_MODE:
- pfns->omni_on_handler(channel);
- break;
- case MONO_ON_MODE:
- pfns->mono_on_handler(channel, byte);
- break;
- case POLY_ON_MODE:
- pfns->poly_on_handler(channel);
- break;
- default:
- while(true); // Should be unreachable.
- }
- memory->first_data_byte = true;
- }
- break;
- case PROGRAM_CHANGE_MASK ... (PROGRAM_CHANGE_MASK + MAX_CHANNEL):
- pfns->program_change_handler(channel, byte);
- break;
- case AFTERTOUCH_MASK ... (AFTERTOUCH_MASK + MAX_CHANNEL):
- pfns->aftertouch_handler(channel, byte);
- break;
- case PITCH_BEND_MASK ... (PITCH_BEND_MASK + MAX_CHANNEL):
- pfns->pitch_bend_change_handler(channel, byte);
- break;
-
-
- case MTC_QUARTER_FRAME_STATUS:
- if (memory->first_data_byte)
- second_byte();
- else {
- pfns->mtc_quarter_frame_handler(memory->byte0, byte);
- memory->first_data_byte = true;
- }
- break;
- case SONG_POSITION_POINTER_STATUS:
- if (memory->first_data_byte)
- second_byte();
- else {
- pfns->song_position_pointer_handler(memory->byte0, byte);
- memory->first_data_byte = true;
- }
- break;
- case SONG_SELECT_STATUS:
- song_select_handler(byte);
- break;
-
- case SYSEX_STATUS:
- if (memory->first_data_byte) {
- reset(); // In case last sysex got interrupted by a status.
- if (byte <= MAX_NON_UNIVERSAL_ID)
- pfns->sysex_collector(byte);
- second_byte();
- } else
- switch (memory->byte0) {
- case UNIVERSAL_NONREALTIME_SUBID:
- push();
- if (memory->top > 2) {
- uint8_t device_id = memory->stack[0];
- uint8_t subid1 = memory->stack[1];
- uint8_t subid2 = memory->stack[2];
- switch (subid1) {
- case TUNING_STANDARD_SUBID:
- switch (subid2) {
- case BULK_DUMP_REQUEST_SUBID:
- pfns->bulk_tuning_dump_request_handler(device_id, byte);
- reset();
- break;
- case BULK_DUMP_REPLY_SUBID:
- if (memory->top == 4 + TUNING_NAME_LENGTH + TUNING_LENGTH - 1) {
- uint8_t tuning_program = memory->stack[3];
- uint8_t checksum = NON_REAL_TIME_ID ^ device_id ^ TUNING_STANDARD_SUBID \
- ^ BULK_DUMP_REPLY_SUBID ^ tuning_program;
- for (int i = 0; i < TUNING_LENGTH; i++) {
- checksum ^= memory->stack[4 + TUNING_NAME_LENGTH - 1 + i];
- }
-
- if (memory->stack[memory->top] == checksum) {
- pfns->bulk_tuning_dump_handler(memory->stack[0], memory->stack[3], memory->stack + 4,
- memory->stack + 4 + TUNING_NAME_LENGTH);
- }
-
- reset();
- }
- default:
- while(true); // Unrecognized tuning standard subid2.
- }
- break;
- default:
- if (!pfns->unimplemented_universal_sysex_collector(byte)) {
- reset();
- } else {
- push();
- }
- break;
- }
- }
- break;
-
- case UNIVERSAL_REALTIME_SUBID:
- push();
- if (memory->top > 2) {
- uint8_t device_id = memory->stack[0];
- uint8_t subid1 = memory->stack[1];
- uint8_t subid2 = memory->stack[2];
- switch (subid1) {
- case TUNING_STANDARD_SUBID:
- switch (subid2) {
- case NOTE_CHANGE_SUBID:
- uint8_t program_number = memory->stack[3];
- uint8_t change_count = memory->stack[4];
- if (memory->top >= 4 && memory->top == 4 + change_count + 1 - 1) {
- pfns->single_note_tuning_change_handler(device_id, program_number, change_count, memory->stack + 5);
- reset();
- }
- break;
- default:
- while(true); // Unrecognized tuning standard message.
- }
- break;
- default:
- break;
- }
- }
- break;
- default:
- if (!pfns->sysex_collector(byte)) {
- reset();
- } else {
- push();
- }
- break;
- }
- default:
- while(true); // Unhandled status got set, somehow.
- }
- break;
-
- default:
- while(true); // Unrecognized status byte.
- }
-}