#ifndef MIDI_H #define MIDI_H #include #include #include // Configuration. #define DEBUG 0 // If defined, enable input safety checking (e.g. too large data bytes, bad ID numbers, etc). // These checks have some performance downside. /* #define RUNNING_STATUS 0 // If defined, the MIDI instrument stores a transmit status and uses running statuses whenever possible .*/ #define KEY_ON_VELOCITY 0 // If defined, the MIDI instrument sends velocities with Note On messages. #undef RELEASE_VELOCITY // If defined, the MIDI instrument sends Note Off messages with velocities. // Otherwise, sends Note On velocity 0 or Note Off velocity 0 according to ACTUAL_OFF_MESSAGE. #undef ACTUAL_OFF_MESSAGE // If defined, the MIDI instrument sends true Note Off messages. // Otherwise sends Note On velocity 0 (so as to exploit running status). #undef EXPORT_CONTROLLERS // If defined, export constants useful for controller messages. // Device info. Modify to suit your use-case. #define DEVICE_MANUFACTURER 0x7d #define DEVICE_FAMILY 0x00'00 #define DEVICE_MODEL_NUMBER 0x00'00 #define SOFTWARE_REVISION 0x00'00'00'00 // Consumers must specify typedef struct { void (*uart_write)(uint8_t); // Blocking, single-byte UART transmit function. // Channel voice handlers. void (*note_on_handler)(uint8_t, uint8_t, uint8_t); void (*note_off_handler)(uint8_t, uint8_t, uint8_t); void (*poly_key_handler)(uint8_t, uint8_t, uint8_t); void (*control_change_handler)(uint8_t, uint8_t, uint8_t); void (*program_change_handler)(uint8_t, uint8_t); void (*aftertouch_handler)(uint8_t, uint8_t); void (*pitch_bend_change_handler)(uint8_t, uint8_t); // Channel mode handlers. void (*all_sound_off_handler)(uint8_t); void (*reset_all_controllers_handler)(uint8_t); void (*local_control_handler)(uint8_t, uint8_t); void (*all_notes_off_handler)(uint8_t); void (*omni_on_handler)(uint8_t); void (*omni_off_handler)(uint8_t); void (*mono_on_handler)(uint8_t, uint8_t); void (*poly_on_handler)(uint8_t); // System common handlers. void (*mtc_quarter_frame_handler)(uint8_t, uint8_t); void (*song_position_pointer_handler)(uint8_t, uint8_t); void (*song_select_handler)(uint8_t); void (*tune_request_handler)(); // System real time handlers. void (*timing_clock_handler)(); void (*start_handler)(); void (*continue_handler)(); void (*stop_handler)(); void (*active_sensing_handler)(); void (*system_reset_handler)(); // System Exclusive handlers. bool (*sysex_collector)(uint8_t); // Feeds most recent byte system exclusive byte (status and eox excluded, ID included) // to client, returning false whenever the client determines sysex can be safely discarded. // Client is expected to maintain parsing state externally, // including resetting correctly after aborted parses. // Client also should not abort the parse before the first post-manufacturer-ID byte. void (*end_of_sysex_handler)(); // Sent only when client // Universal System Exclusive handlers. void (*bulk_tuning_dump_request_handler)(uint8_t, uint8_t); void (*bulk_tuning_dump_handler)(uint8_t, uint8_t, char*, uint8_t*); void (*single_note_tuning_change_handler)(uint8_t, uint8_t, uint8_t, uint8_t*); // TODO: more. bool (*unimplemented_universal_sysex_collector)(uint8_t); // Same as above. Parsing ends with end_of_sysex_handler. } ConsumerBehavior; typedef struct { uint8_t status; bool first_byte; uint8_t byte0; bool send_eox; uint8_t *stack; size_t top; size_t size; } ParserMemory; void midi_init(ConsumerBehavior new_pfns); // System exclusive sends. void sysex(uint16_t manufacturer_id, uint8_t* contents, size_t contents_len); void universal_nonrealtime(uint8_t device_id, uint16_t sub_id, uint8_t* contents, size_t contents_len); void universal_realtime(uint8_t device_id, uint16_t sub_id, uint8_t* contents, size_t contents_len); // Channel voice sends. #ifdef KEY_ON_VELOCITY void note_on(uint8_t channel, uint8_t note, uint8_t velocity); #else void note_on(uint8_t channel, uint8_t note); #endif #ifdef RELEASE_VELOCITY void note_off(uint8_t channel, uint8_t note, uint8_t velocity); #else void note_off(uint8_t channel, uint8_t note); #endif void control_change(uint8_t channel, uint8_t controller_number, uint8_t control_value); void program_change(uint8_t channel, uint8_t program_number); void aftertouch(uint8_t channel, uint8_t pressure_value); void pitch_bend_change(uint8_t channel, uint16_t pressure_value); // Channel mode sends. void all_sound_off(uint8_t channel); void reset_all_controllers(uint8_t channel); void local_control_on(uint8_t channel); void local_control_off(uint8_t channel); void all_notes_off(uint8_t channel); void omni_on(uint8_t channel); void omni_off(uint8_t channel); void mono_on(uint8_t channel, uint8_t channel_count); void poly_on(uint8_t channel); // System Common sends. // MTC Quarter Frame unimplemented. void song_position_pointer(uint16_t position); void song_select(uint8_t song); void tune_request(); // System Real Time sends. void timing_clock(); void srt_start(); void srt_continue(); void srt_stop(); void active_sensing(); void MIDI_reset(); // Universal SysEx. // Only implement MTS; consumers can do their own parsing via unimplemented_universal_sysex_collector. // MIDI Tuning Standard sends. void bulk_tuning_dump_request(uint8_t device_id, uint8_t program); void bulk_tuning_dump(uint8_t device_id, uint8_t program, char* name, uint8_t* tuning_data); void single_note_tuning_change(uint8_t device_id, uint8_t program, uint8_t *note_tuning_data, uint8_t keys_changed); // Feed bytes to this in the UART interrupt handler. void parse_midi_stream(uint8_t byte); // Public constants; magic numbers useful for consumers. #define ALL_CALL_DEVICE_ID 0x7f #define DEVICE_KEY_COUNT 128 #define TUNING_LENGTH (3 * DEVICE_KEY_COUNT) #define TUNING_NAME_LENGTH 16 #define NOTE_TUNING_BYTES_PER_KEY 4 #ifdef EXPORT_CONTROLLERS // Controller constants. typedef enum Controller { BANK_SELECT = 0, MODULATION_WHEEL = 1, BREATH_CONTROLLER = 2, // Undefined FOOT_CONTROLLER = 4, PORTAMENTO_TIME = 5, DATA_ENTRY_MSB = 6, CHANNEL_VOLUME = 7, BALANCE = 8, // Undefined PAN = 10, EXPRESSION = 11, EFFECT1 = 12, EFFECT2 = 13, // Undefined GP1 = 16, GP2 = 17, GP3 = 18, GP4 = 19, DAMPER_PEDAL = 64, PORTAMENTO_TOGGLE = 65, SOSTENUTO = 66, SOFT_PEDAL = 67, LEGATO_FOOTSWITCH = 68, HOLD2 = 69, SC1_SOUND_VARIATION = 70, SC2_TIMBRE = 71, SC3_RELEASE_TIME = 72, SC4_ATTACK_TIME = 73, SC5_BRIGHTNESS = 74, SC6 = 75, SC7 = 76, SC8 = 77, SC9 = 78, SC10 = 79, GP5 = 80, GP6 = 81, GP7 = 82, GP8 = 83, PORTAMENTO_CONTROL = 84, // Undefined EFFECTS_DEPTH1 = 91, EFFECTS_DEPTH2 = 92, EFFECTS_DEPTH3 = 93, EFFECTS_DEPTH4 = 94, EFFECTS_DEPTH5 = 95, DATA_INCREMENT = 96, DATA_DECREMENT = 97, NONREGISTERED_LSB = 98, NONREGISTERED_MSB = 99, REGISTERED_LSB = 100, REGISTERED_MSB = 101, // undefined 102-119 // reserved for channel mode 120-127 }; typedef enum RegisteredParams { PITCH_BEND_SENSITIVITY = 0, FINE_TUNING = 1, COARSE_TUNING = 2, TUNING_PROGRAM_SELECT = 3, TUNING_BANK_SELECT = 4 }; #endif #endif