From ed60865743a5d65240c9da353edb4dc20cf7009f Mon Sep 17 00:00:00 2001 From: Duncan Wilkie Date: Tue, 18 Jul 2023 11:55:03 -0500 Subject: Rename, add startup file. --- controller/libs/midi.c | 826 ------------------------------------------------- 1 file changed, 826 deletions(-) delete mode 100644 controller/libs/midi.c (limited to 'controller/libs/midi.c') 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. - } -} -- cgit v1.2.3