summaryrefslogtreecommitdiff
path: root/controller/inc/midi.h
blob: 819db03e2666559c414e10bf4dacc0b95667cee3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#ifndef MIDI_H
#define MIDI_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

// 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.

// 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;

extern ConsumerBehavior pfns; // Initialize this globally in your main.

// System exclusive sends.
void sysex(uint16_t manufacturer_id, bool long_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