-
-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathmidi_comm.h
More file actions
207 lines (184 loc) · 6.04 KB
/
midi_comm.h
File metadata and controls
207 lines (184 loc) · 6.04 KB
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 LIB_MIDI_COMM_H
#define LIB_MIDI_COMM_H 1
#include <stdarg.h> // Include this header for va_start, va_end, etc.
#include <stdio.h> // Include for vsnprintf
uint32_t send_buffer_as_sysex(char* buffer, uint32_t bufsize) {
uint8_t sysex_data[bufsize + 2]; // +2 for SysEx start and end bytes
sysex_data[0] = 0xF0; // Start of SysEx
for (uint32_t i = 0; i < bufsize; i++) {
sysex_data[i + 1] = buffer[i]; // Copy buffer into SysEx data
}
sysex_data[bufsize + 1] = 0xF7; // End of SysEx
return tud_midi_n_stream_write(0, 0, sysex_data, sizeof(sysex_data));
}
uint32_t send_text_as_sysex(const char* text) {
uint32_t text_length = strlen(text); // Get the length of the text
uint8_t sysex_data[text_length + 2]; // +2 for SysEx start and end bytes
sysex_data[0] = 0xF0; // Start of SysEx
for (uint32_t i = 0; i < text_length; i++) {
sysex_data[i + 1] = text[i]; // Copy text into SysEx data
}
sysex_data[text_length + 1] = 0xF7; // End of SysEx
// Call the stream write function with the SysEx message
return tud_midi_n_stream_write(0, 0, sysex_data, sizeof(sysex_data));
}
void send_midi_clock() {
// Ensure TinyUSB stack is initialized and ready
if (tud_ready()) {
// Construct the MIDI message
// MIDI Timing Clock message format: 0xF8
uint8_t midi_message[1];
midi_message[0] = 0xF8; // Timing Clock command
// Send the MIDI message
tud_midi_n_stream_write(0, 0, midi_message, sizeof(midi_message));
}
}
void send_midi_start() {
// Ensure TinyUSB stack is initialized and ready
if (tud_ready()) {
// Construct the MIDI message
// MIDI Start message format: 0xFA
uint8_t midi_message[1];
midi_message[0] = 0xFA; // Start command
// Send the MIDI message
tud_midi_n_stream_write(0, 0, midi_message, sizeof(midi_message));
}
}
void send_midi_stop() {
// Ensure TinyUSB stack is initialized and ready
if (tud_ready()) {
// Construct the MIDI message
// MIDI Stop message format: 0xFC
uint8_t midi_message[1];
midi_message[0] = 0xFC; // Stop command
// Send the MIDI message
tud_midi_n_stream_write(0, 0, midi_message, sizeof(midi_message));
}
}
void send_midi_note_on(uint8_t note, uint8_t velocity) {
// Ensure TinyUSB stack is initialized and ready
if (tud_ready()) {
// MIDI cable number 0, Note On event, channel 1
uint8_t channel = 0; // MIDI channels are 0-15
// Construct the MIDI message
// MIDI Note On message format: 0x9n, where n is the channel number
uint8_t midi_message[3];
midi_message[0] = 0x90 | channel; // Note On command with channel
midi_message[1] = note; // MIDI note number
midi_message[2] = velocity; // Note velocity
// Send the MIDI message
tud_midi_n_stream_write(0, 0, midi_message, sizeof(midi_message));
}
}
int printf_sysex(const char* format, ...) {
if (!tud_ready()) {
return 0;
}
va_list args;
va_start(args, format);
int text_length = vsnprintf(NULL, 0, format, args);
va_end(args);
char text[text_length + 1]; // +1 for null terminator
va_start(args, format);
vsnprintf(text, text_length + 1, format, args);
va_end(args);
return send_text_as_sysex(text);
}
typedef void (*midi_comm_callback)(uint8_t, uint8_t, uint8_t, uint8_t);
void midi_comm_task(midi_comm_callback callback, callback_int_int midi_note_on,
callback_int midi_note_off, callback_void midi_start,
callback_void midi_continue, callback_void midi_stop,
callback_void midi_timing,
callback_uint8_uint8_uint8 midi_control_change) {
uint8_t midi_buffer[3];
midi_buffer[0] = 0;
midi_buffer[1] = 0;
midi_buffer[2] = 0;
uint32_t bytes_read = 0;
if (tud_midi_n_available(0, 0)) {
bytes_read = tud_midi_n_stream_read(0, 0, midi_buffer, 3);
} else {
return;
}
if (bytes_read == 0) {
return;
}
if (midi_buffer[0] == 0xf8) {
// timing received
usb_midi_present = true;
if (midi_timing != NULL) {
midi_timing();
}
return;
} else if (midi_buffer[0] == 0xfa) {
// start received
usb_midi_present = true;
if (midi_start != NULL) {
midi_start();
}
return;
} else if (midi_buffer[0] == 0xfb) {
// continue received
usb_midi_present = true;
if (midi_continue != NULL) {
midi_continue();
}
return;
} else if (midi_buffer[0] == 0xfc) {
// stop received
usb_midi_present = true;
if (midi_stop != NULL) {
midi_stop();
}
return;
} else if (midi_buffer[0] == 0xB0 && bytes_read > 1) {
uint8_t channel = midi_buffer[0] & 0xf;
// CONTROL CHANGE
midi_control_change(channel, midi_buffer[1], midi_buffer[2]);
return;
} else if (midi_buffer[0] == 0x80 && bytes_read > 1) {
// note off received
usb_midi_present = true;
if (midi_note_off != NULL) {
midi_note_off(midi_buffer[1]);
}
return;
} else if (midi_buffer[0] == 0x90 && bytes_read > 2) {
// note on received
usb_midi_present = true;
if (midi_note_on != NULL) {
if (bytes_read == 3) {
// TODO: for some reason this is not working
midi_note_on(midi_buffer[1], midi_buffer[2]);
} else {
midi_note_on(midi_buffer[1], 0);
}
}
return;
}
// for (int i = 0; i < bytes_read; i++) {
// printf_sysex("[midi_comm_task] midi_buffer[%d]: %x\n", i,
// midi_buffer[i]);
// }
if (bytes_read == 3) {
usb_midi_present = true;
// Extract the status byte and MIDI channel
uint8_t status = midi_buffer[0] & 0xF0;
uint8_t channel = midi_buffer[0] & 0x0F;
// Extract the note number and velocity
uint8_t note = midi_buffer[1];
uint8_t velocity = midi_buffer[2];
if (status == 176 && channel == 0 && note == 0) {
send_text_as_sysex("command=reset");
sleep_ms(10);
reset_usb_boot(0, 0);
} else if (status == 176 && channel == 0 && note == 1) {
send_text_as_sysex("version=v7.1.1");
}
if (callback != NULL) {
callback(status, channel, note, velocity);
}
}
}
#define printf printf_sysex
#endif