rev |
line source |
nuclear@0
|
1 /*-
|
nuclear@0
|
2 * Copyright (c) 2007, 2008 Edward Tomasz NapieraĆa <trasz@FreeBSD.org>
|
nuclear@0
|
3 * All rights reserved.
|
nuclear@0
|
4 *
|
nuclear@0
|
5 * Redistribution and use in source and binary forms, with or without
|
nuclear@0
|
6 * modification, are permitted provided that the following conditions
|
nuclear@0
|
7 * are met:
|
nuclear@0
|
8 * 1. Redistributions of source code must retain the above copyright
|
nuclear@0
|
9 * notice, this list of conditions and the following disclaimer.
|
nuclear@0
|
10 * 2. Redistributions in binary form must reproduce the above copyright
|
nuclear@0
|
11 * notice, this list of conditions and the following disclaimer in the
|
nuclear@0
|
12 * documentation and/or other materials provided with the distribution.
|
nuclear@0
|
13 *
|
nuclear@0
|
14 * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE
|
nuclear@0
|
15 * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
nuclear@0
|
16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
nuclear@0
|
17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
nuclear@0
|
18 * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
nuclear@0
|
20 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
nuclear@0
|
21 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
nuclear@0
|
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
nuclear@0
|
23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
nuclear@0
|
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
25 *
|
nuclear@0
|
26 */
|
nuclear@0
|
27
|
nuclear@0
|
28 /**
|
nuclear@0
|
29 * \file
|
nuclear@0
|
30 *
|
nuclear@0
|
31 * Event decoding routines.
|
nuclear@0
|
32 *
|
nuclear@0
|
33 */
|
nuclear@0
|
34
|
nuclear@0
|
35 #include <stdlib.h>
|
nuclear@0
|
36 #include <string.h>
|
nuclear@0
|
37 #include <assert.h>
|
nuclear@0
|
38 #include <math.h>
|
nuclear@0
|
39 #include <errno.h>
|
nuclear@0
|
40 #ifdef __MINGW32__
|
nuclear@0
|
41 #include <windows.h>
|
nuclear@0
|
42 #else /* ! __MINGW32__ */
|
nuclear@0
|
43 #include <arpa/inet.h>
|
nuclear@0
|
44 #endif /* ! __MINGW32__ */
|
nuclear@0
|
45 #include <stdint.h>
|
nuclear@0
|
46 #include "smf.h"
|
nuclear@0
|
47 #include "smf_private.h"
|
nuclear@0
|
48
|
nuclear@0
|
49 #define BUFFER_SIZE 1024
|
nuclear@0
|
50
|
nuclear@0
|
51 /**
|
nuclear@0
|
52 * \return Nonzero if event is metaevent. You should never send metaevents;
|
nuclear@0
|
53 * they are not really MIDI messages. They carry information like track title,
|
nuclear@0
|
54 * time signature etc.
|
nuclear@0
|
55 */
|
nuclear@0
|
56 int
|
nuclear@0
|
57 smf_event_is_metadata(const smf_event_t *event)
|
nuclear@0
|
58 {
|
nuclear@0
|
59 assert(event->midi_buffer);
|
nuclear@0
|
60 assert(event->midi_buffer_length > 0);
|
nuclear@0
|
61
|
nuclear@0
|
62 if (event->midi_buffer[0] == 0xFF)
|
nuclear@0
|
63 return (1);
|
nuclear@0
|
64
|
nuclear@0
|
65 return (0);
|
nuclear@0
|
66 }
|
nuclear@0
|
67
|
nuclear@0
|
68 /**
|
nuclear@0
|
69 * \return Nonzero if event is System Realtime.
|
nuclear@0
|
70 */
|
nuclear@0
|
71 int
|
nuclear@0
|
72 smf_event_is_system_realtime(const smf_event_t *event)
|
nuclear@0
|
73 {
|
nuclear@0
|
74 assert(event->midi_buffer);
|
nuclear@0
|
75 assert(event->midi_buffer_length > 0);
|
nuclear@0
|
76
|
nuclear@0
|
77 if (smf_event_is_metadata(event))
|
nuclear@0
|
78 return (0);
|
nuclear@0
|
79
|
nuclear@0
|
80 if (event->midi_buffer[0] >= 0xF8)
|
nuclear@0
|
81 return (1);
|
nuclear@0
|
82
|
nuclear@0
|
83 return (0);
|
nuclear@0
|
84 }
|
nuclear@0
|
85
|
nuclear@0
|
86 /**
|
nuclear@0
|
87 * \return Nonzero if event is System Common.
|
nuclear@0
|
88 */
|
nuclear@0
|
89 int
|
nuclear@0
|
90 smf_event_is_system_common(const smf_event_t *event)
|
nuclear@0
|
91 {
|
nuclear@0
|
92 assert(event->midi_buffer);
|
nuclear@0
|
93 assert(event->midi_buffer_length > 0);
|
nuclear@0
|
94
|
nuclear@0
|
95 if (event->midi_buffer[0] >= 0xF0 && event->midi_buffer[0] <= 0xF7)
|
nuclear@0
|
96 return (1);
|
nuclear@0
|
97
|
nuclear@0
|
98 return (0);
|
nuclear@0
|
99 }
|
nuclear@0
|
100 /**
|
nuclear@0
|
101 * \return Nonzero if event is SysEx message.
|
nuclear@0
|
102 */
|
nuclear@0
|
103 int
|
nuclear@0
|
104 smf_event_is_sysex(const smf_event_t *event)
|
nuclear@0
|
105 {
|
nuclear@0
|
106 assert(event->midi_buffer);
|
nuclear@0
|
107 assert(event->midi_buffer_length > 0);
|
nuclear@0
|
108
|
nuclear@0
|
109 if (event->midi_buffer[0] == 0xF0)
|
nuclear@0
|
110 return (1);
|
nuclear@0
|
111
|
nuclear@0
|
112 return (0);
|
nuclear@0
|
113 }
|
nuclear@0
|
114
|
nuclear@0
|
115 static char *
|
nuclear@0
|
116 smf_event_decode_textual(const smf_event_t *event, const char *name)
|
nuclear@0
|
117 {
|
nuclear@0
|
118 int off = 0;
|
nuclear@0
|
119 char *buf, *extracted;
|
nuclear@0
|
120
|
nuclear@0
|
121 buf = malloc(BUFFER_SIZE);
|
nuclear@0
|
122 if (buf == NULL) {
|
nuclear@0
|
123 fg_critical("smf_event_decode_textual: malloc failed.");
|
nuclear@0
|
124 return (NULL);
|
nuclear@0
|
125 }
|
nuclear@0
|
126
|
nuclear@0
|
127 extracted = smf_event_extract_text(event);
|
nuclear@0
|
128 if (extracted == NULL) {
|
nuclear@0
|
129 free(buf);
|
nuclear@0
|
130 return (NULL);
|
nuclear@0
|
131 }
|
nuclear@0
|
132
|
nuclear@0
|
133 snprintf(buf + off, BUFFER_SIZE - off, "%s: %s", name, extracted);
|
nuclear@0
|
134
|
nuclear@0
|
135 return (buf);
|
nuclear@0
|
136 }
|
nuclear@0
|
137
|
nuclear@0
|
138 static char *
|
nuclear@0
|
139 smf_event_decode_metadata(const smf_event_t *event)
|
nuclear@0
|
140 {
|
nuclear@0
|
141 int off = 0, mspqn, flats, isminor;
|
nuclear@0
|
142 char *buf;
|
nuclear@0
|
143
|
nuclear@0
|
144 static const char *const major_keys[] = {"Fb", "Cb", "Gb", "Db", "Ab",
|
nuclear@0
|
145 "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#"};
|
nuclear@0
|
146
|
nuclear@0
|
147 static const char *const minor_keys[] = {"Dbm", "Abm", "Ebm", "Bbm", "Fm",
|
nuclear@0
|
148 "Cm", "Gm", "Dm", "Am", "Em", "Bm", "F#m", "C#m", "G#m", "D#m", "A#m", "E#m"};
|
nuclear@0
|
149
|
nuclear@0
|
150 assert(smf_event_is_metadata(event));
|
nuclear@0
|
151
|
nuclear@0
|
152 switch (event->midi_buffer[1]) {
|
nuclear@0
|
153 case 0x01:
|
nuclear@0
|
154 return (smf_event_decode_textual(event, "Text"));
|
nuclear@0
|
155
|
nuclear@0
|
156 case 0x02:
|
nuclear@0
|
157 return (smf_event_decode_textual(event, "Copyright"));
|
nuclear@0
|
158
|
nuclear@0
|
159 case 0x03:
|
nuclear@0
|
160 return (smf_event_decode_textual(event, "Sequence/Track Name"));
|
nuclear@0
|
161
|
nuclear@0
|
162 case 0x04:
|
nuclear@0
|
163 return (smf_event_decode_textual(event, "Instrument"));
|
nuclear@0
|
164
|
nuclear@0
|
165 case 0x05:
|
nuclear@0
|
166 return (smf_event_decode_textual(event, "Lyric"));
|
nuclear@0
|
167
|
nuclear@0
|
168 case 0x06:
|
nuclear@0
|
169 return (smf_event_decode_textual(event, "Marker"));
|
nuclear@0
|
170
|
nuclear@0
|
171 case 0x07:
|
nuclear@0
|
172 return (smf_event_decode_textual(event, "Cue Point"));
|
nuclear@0
|
173
|
nuclear@0
|
174 case 0x08:
|
nuclear@0
|
175 return (smf_event_decode_textual(event, "Program Name"));
|
nuclear@0
|
176
|
nuclear@0
|
177 case 0x09:
|
nuclear@0
|
178 return (smf_event_decode_textual(event, "Device (Port) Name"));
|
nuclear@0
|
179
|
nuclear@0
|
180 default:
|
nuclear@0
|
181 break;
|
nuclear@0
|
182 }
|
nuclear@0
|
183
|
nuclear@0
|
184 buf = malloc(BUFFER_SIZE);
|
nuclear@0
|
185 if (buf == NULL) {
|
nuclear@0
|
186 fg_critical("smf_event_decode_metadata: malloc failed.");
|
nuclear@0
|
187 return (NULL);
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 switch (event->midi_buffer[1]) {
|
nuclear@0
|
191 case 0x00:
|
nuclear@0
|
192 off += snprintf(buf + off, BUFFER_SIZE - off, "Sequence number");
|
nuclear@0
|
193 break;
|
nuclear@0
|
194
|
nuclear@0
|
195 /* http://music.columbia.edu/pipermail/music-dsp/2004-August/061196.html */
|
nuclear@0
|
196 case 0x20:
|
nuclear@0
|
197 if (event->midi_buffer_length < 4) {
|
nuclear@0
|
198 fg_critical("smf_event_decode_metadata: truncated MIDI message.");
|
nuclear@0
|
199 goto error;
|
nuclear@0
|
200 }
|
nuclear@0
|
201
|
nuclear@0
|
202 off += snprintf(buf + off, BUFFER_SIZE - off, "Channel Prefix: %d", event->midi_buffer[3]);
|
nuclear@0
|
203 break;
|
nuclear@0
|
204
|
nuclear@0
|
205 case 0x21:
|
nuclear@0
|
206 if (event->midi_buffer_length < 4) {
|
nuclear@0
|
207 fg_critical("smf_event_decode_metadata: truncated MIDI message.");
|
nuclear@0
|
208 goto error;
|
nuclear@0
|
209 }
|
nuclear@0
|
210
|
nuclear@0
|
211 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Port: %d", event->midi_buffer[3]);
|
nuclear@0
|
212 break;
|
nuclear@0
|
213
|
nuclear@0
|
214 case 0x2F:
|
nuclear@0
|
215 off += snprintf(buf + off, BUFFER_SIZE - off, "End Of Track");
|
nuclear@0
|
216 break;
|
nuclear@0
|
217
|
nuclear@0
|
218 case 0x51:
|
nuclear@0
|
219 if (event->midi_buffer_length < 6) {
|
nuclear@0
|
220 fg_critical("smf_event_decode_metadata: truncated MIDI message.");
|
nuclear@0
|
221 goto error;
|
nuclear@0
|
222 }
|
nuclear@0
|
223
|
nuclear@0
|
224 mspqn = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5];
|
nuclear@0
|
225
|
nuclear@0
|
226 off += snprintf(buf + off, BUFFER_SIZE - off, "Tempo: %d microseconds per quarter note, %.2f BPM",
|
nuclear@0
|
227 mspqn, 60000000.0 / (double)mspqn);
|
nuclear@0
|
228 break;
|
nuclear@0
|
229
|
nuclear@0
|
230 case 0x54:
|
nuclear@0
|
231 off += snprintf(buf + off, BUFFER_SIZE - off, "SMPTE Offset");
|
nuclear@0
|
232 break;
|
nuclear@0
|
233
|
nuclear@0
|
234 case 0x58:
|
nuclear@0
|
235 if (event->midi_buffer_length < 7) {
|
nuclear@0
|
236 fg_critical("smf_event_decode_metadata: truncated MIDI message.");
|
nuclear@0
|
237 goto error;
|
nuclear@0
|
238 }
|
nuclear@0
|
239
|
nuclear@0
|
240 off += snprintf(buf + off, BUFFER_SIZE - off,
|
nuclear@0
|
241 "Time Signature: %d/%d, %d clocks per click, %d notated 32nd notes per quarter note",
|
nuclear@0
|
242 event->midi_buffer[3], (int)pow(2, event->midi_buffer[4]), event->midi_buffer[5],
|
nuclear@0
|
243 event->midi_buffer[6]);
|
nuclear@0
|
244 break;
|
nuclear@0
|
245
|
nuclear@0
|
246 case 0x59:
|
nuclear@0
|
247 if (event->midi_buffer_length < 5) {
|
nuclear@0
|
248 fg_critical("smf_event_decode_metadata: truncated MIDI message.");
|
nuclear@0
|
249 goto error;
|
nuclear@0
|
250 }
|
nuclear@0
|
251
|
nuclear@0
|
252 flats = event->midi_buffer[3];
|
nuclear@0
|
253 isminor = event->midi_buffer[4];
|
nuclear@0
|
254
|
nuclear@0
|
255 if (isminor != 0 && isminor != 1) {
|
nuclear@0
|
256 fg_critical("smf_event_decode_metadata: last byte of the Key Signature event has invalid value %d.", isminor);
|
nuclear@0
|
257 goto error;
|
nuclear@0
|
258 }
|
nuclear@0
|
259
|
nuclear@0
|
260 off += snprintf(buf + off, BUFFER_SIZE - off, "Key Signature: ");
|
nuclear@0
|
261
|
nuclear@0
|
262 if (flats > 8 && flats < 248) {
|
nuclear@0
|
263 off += snprintf(buf + off, BUFFER_SIZE - off, "%d %s, %s key", abs((int8_t)flats),
|
nuclear@0
|
264 flats > 127 ? "flats" : "sharps", isminor ? "minor" : "major");
|
nuclear@0
|
265 } else {
|
nuclear@0
|
266 int i = (flats - 248) & 255;
|
nuclear@0
|
267
|
nuclear@0
|
268 assert(i >= 0 && i < sizeof(minor_keys) / sizeof(*minor_keys));
|
nuclear@0
|
269 assert(i >= 0 && i < sizeof(major_keys) / sizeof(*major_keys));
|
nuclear@0
|
270
|
nuclear@0
|
271 if (isminor)
|
nuclear@0
|
272 off += snprintf(buf + off, BUFFER_SIZE - off, "%s", minor_keys[i]);
|
nuclear@0
|
273 else
|
nuclear@0
|
274 off += snprintf(buf + off, BUFFER_SIZE - off, "%s", major_keys[i]);
|
nuclear@0
|
275 }
|
nuclear@0
|
276
|
nuclear@0
|
277 break;
|
nuclear@0
|
278
|
nuclear@0
|
279 case 0x7F:
|
nuclear@0
|
280 off += snprintf(buf + off, BUFFER_SIZE - off, "Proprietary (aka Sequencer) Event, length %d",
|
nuclear@0
|
281 event->midi_buffer_length);
|
nuclear@0
|
282 break;
|
nuclear@0
|
283
|
nuclear@0
|
284 default:
|
nuclear@0
|
285 goto error;
|
nuclear@0
|
286 }
|
nuclear@0
|
287
|
nuclear@0
|
288 return (buf);
|
nuclear@0
|
289
|
nuclear@0
|
290 error:
|
nuclear@0
|
291 free(buf);
|
nuclear@0
|
292
|
nuclear@0
|
293 return (NULL);
|
nuclear@0
|
294 }
|
nuclear@0
|
295
|
nuclear@0
|
296 static char *
|
nuclear@0
|
297 smf_event_decode_system_realtime(const smf_event_t *event)
|
nuclear@0
|
298 {
|
nuclear@0
|
299 int off = 0;
|
nuclear@0
|
300 char *buf;
|
nuclear@0
|
301
|
nuclear@0
|
302 assert(smf_event_is_system_realtime(event));
|
nuclear@0
|
303
|
nuclear@0
|
304 if (event->midi_buffer_length != 1) {
|
nuclear@0
|
305 fg_critical("smf_event_decode_system_realtime: event length is not 1.");
|
nuclear@0
|
306 return (NULL);
|
nuclear@0
|
307 }
|
nuclear@0
|
308
|
nuclear@0
|
309 buf = malloc(BUFFER_SIZE);
|
nuclear@0
|
310 if (buf == NULL) {
|
nuclear@0
|
311 fg_critical("smf_event_decode_system_realtime: malloc failed.");
|
nuclear@0
|
312 return (NULL);
|
nuclear@0
|
313 }
|
nuclear@0
|
314
|
nuclear@0
|
315 switch (event->midi_buffer[0]) {
|
nuclear@0
|
316 case 0xF8:
|
nuclear@0
|
317 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Clock (realtime)");
|
nuclear@0
|
318 break;
|
nuclear@0
|
319
|
nuclear@0
|
320 case 0xF9:
|
nuclear@0
|
321 off += snprintf(buf + off, BUFFER_SIZE - off, "Tick (realtime)");
|
nuclear@0
|
322 break;
|
nuclear@0
|
323
|
nuclear@0
|
324 case 0xFA:
|
nuclear@0
|
325 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Start (realtime)");
|
nuclear@0
|
326 break;
|
nuclear@0
|
327
|
nuclear@0
|
328 case 0xFB:
|
nuclear@0
|
329 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Continue (realtime)");
|
nuclear@0
|
330 break;
|
nuclear@0
|
331
|
nuclear@0
|
332 case 0xFC:
|
nuclear@0
|
333 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Stop (realtime)");
|
nuclear@0
|
334 break;
|
nuclear@0
|
335
|
nuclear@0
|
336 case 0xFE:
|
nuclear@0
|
337 off += snprintf(buf + off, BUFFER_SIZE - off, "Active Sense (realtime)");
|
nuclear@0
|
338 break;
|
nuclear@0
|
339
|
nuclear@0
|
340 default:
|
nuclear@0
|
341 free(buf);
|
nuclear@0
|
342 return (NULL);
|
nuclear@0
|
343 }
|
nuclear@0
|
344
|
nuclear@0
|
345 return (buf);
|
nuclear@0
|
346 }
|
nuclear@0
|
347
|
nuclear@0
|
348 static char *
|
nuclear@0
|
349 smf_event_decode_sysex(const smf_event_t *event)
|
nuclear@0
|
350 {
|
nuclear@0
|
351 int off = 0;
|
nuclear@0
|
352 char *buf, manufacturer, subid, subid2;
|
nuclear@0
|
353
|
nuclear@0
|
354 assert(smf_event_is_sysex(event));
|
nuclear@0
|
355
|
nuclear@0
|
356 if (event->midi_buffer_length < 5) {
|
nuclear@0
|
357 fg_critical("smf_event_decode_sysex: truncated MIDI message.");
|
nuclear@0
|
358 return (NULL);
|
nuclear@0
|
359 }
|
nuclear@0
|
360
|
nuclear@0
|
361 buf = malloc(BUFFER_SIZE);
|
nuclear@0
|
362 if (buf == NULL) {
|
nuclear@0
|
363 fg_critical("smf_event_decode_sysex: malloc failed.");
|
nuclear@0
|
364 return (NULL);
|
nuclear@0
|
365 }
|
nuclear@0
|
366
|
nuclear@0
|
367 manufacturer = event->midi_buffer[1];
|
nuclear@0
|
368
|
nuclear@0
|
369 if (manufacturer == 0x7F) {
|
nuclear@0
|
370 off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, realtime, channel %d", event->midi_buffer[2]);
|
nuclear@0
|
371 } else if (manufacturer == 0x7E) {
|
nuclear@0
|
372 off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, non-realtime, channel %d", event->midi_buffer[2]);
|
nuclear@0
|
373 } else {
|
nuclear@0
|
374 off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, manufacturer 0x%x", manufacturer);
|
nuclear@0
|
375
|
nuclear@0
|
376 return (buf);
|
nuclear@0
|
377 }
|
nuclear@0
|
378
|
nuclear@0
|
379 subid = event->midi_buffer[3];
|
nuclear@0
|
380 subid2 = event->midi_buffer[4];
|
nuclear@0
|
381
|
nuclear@0
|
382 if (subid == 0x01)
|
nuclear@0
|
383 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Header");
|
nuclear@0
|
384
|
nuclear@0
|
385 else if (subid == 0x02)
|
nuclear@0
|
386 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Data Packet");
|
nuclear@0
|
387
|
nuclear@0
|
388 else if (subid == 0x03)
|
nuclear@0
|
389 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Request");
|
nuclear@0
|
390
|
nuclear@0
|
391 else if (subid == 0x04 && subid2 == 0x01)
|
nuclear@0
|
392 off += snprintf(buf + off, BUFFER_SIZE - off, ", Master Volume");
|
nuclear@0
|
393
|
nuclear@0
|
394 else if (subid == 0x05 && subid2 == 0x01)
|
nuclear@0
|
395 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Loop Point Retransmit");
|
nuclear@0
|
396
|
nuclear@0
|
397 else if (subid == 0x05 && subid2 == 0x02)
|
nuclear@0
|
398 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Loop Point Request");
|
nuclear@0
|
399
|
nuclear@0
|
400 else if (subid == 0x06 && subid2 == 0x01)
|
nuclear@0
|
401 off += snprintf(buf + off, BUFFER_SIZE - off, ", Identity Request");
|
nuclear@0
|
402
|
nuclear@0
|
403 else if (subid == 0x06 && subid2 == 0x02)
|
nuclear@0
|
404 off += snprintf(buf + off, BUFFER_SIZE - off, ", Identity Reply");
|
nuclear@0
|
405
|
nuclear@0
|
406 else if (subid == 0x08 && subid2 == 0x00)
|
nuclear@0
|
407 off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump Request");
|
nuclear@0
|
408
|
nuclear@0
|
409 else if (subid == 0x08 && subid2 == 0x01)
|
nuclear@0
|
410 off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump");
|
nuclear@0
|
411
|
nuclear@0
|
412 else if (subid == 0x08 && subid2 == 0x02)
|
nuclear@0
|
413 off += snprintf(buf + off, BUFFER_SIZE - off, ", Single Note Tuning Change");
|
nuclear@0
|
414
|
nuclear@0
|
415 else if (subid == 0x08 && subid2 == 0x03)
|
nuclear@0
|
416 off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump Request (Bank)");
|
nuclear@0
|
417
|
nuclear@0
|
418 else if (subid == 0x08 && subid2 == 0x04)
|
nuclear@0
|
419 off += snprintf(buf + off, BUFFER_SIZE - off, ", Key Based Tuning Dump");
|
nuclear@0
|
420
|
nuclear@0
|
421 else if (subid == 0x08 && subid2 == 0x05)
|
nuclear@0
|
422 off += snprintf(buf + off, BUFFER_SIZE - off, ", Scale/Octave Tuning Dump, 1 byte format");
|
nuclear@0
|
423
|
nuclear@0
|
424 else if (subid == 0x08 && subid2 == 0x06)
|
nuclear@0
|
425 off += snprintf(buf + off, BUFFER_SIZE - off, ", Scale/Octave Tuning Dump, 2 byte format");
|
nuclear@0
|
426
|
nuclear@0
|
427 else if (subid == 0x08 && subid2 == 0x07)
|
nuclear@0
|
428 off += snprintf(buf + off, BUFFER_SIZE - off, ", Single Note Tuning Change (Bank)");
|
nuclear@0
|
429
|
nuclear@0
|
430 else if (subid == 0x09)
|
nuclear@0
|
431 off += snprintf(buf + off, BUFFER_SIZE - off, ", General MIDI %s", subid2 == 0 ? "disable" : "enable");
|
nuclear@0
|
432
|
nuclear@0
|
433 else if (subid == 0x7C)
|
nuclear@0
|
434 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Wait");
|
nuclear@0
|
435
|
nuclear@0
|
436 else if (subid == 0x7D)
|
nuclear@0
|
437 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Cancel");
|
nuclear@0
|
438
|
nuclear@0
|
439 else if (subid == 0x7E)
|
nuclear@0
|
440 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump NAK");
|
nuclear@0
|
441
|
nuclear@0
|
442 else if (subid == 0x7F)
|
nuclear@0
|
443 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump ACK");
|
nuclear@0
|
444
|
nuclear@0
|
445 else
|
nuclear@0
|
446 off += snprintf(buf + off, BUFFER_SIZE - off, ", Unknown");
|
nuclear@0
|
447
|
nuclear@0
|
448 return (buf);
|
nuclear@0
|
449 }
|
nuclear@0
|
450
|
nuclear@0
|
451 static char *
|
nuclear@0
|
452 smf_event_decode_system_common(const smf_event_t *event)
|
nuclear@0
|
453 {
|
nuclear@0
|
454 int off = 0;
|
nuclear@0
|
455 char *buf;
|
nuclear@0
|
456
|
nuclear@0
|
457 assert(smf_event_is_system_common(event));
|
nuclear@0
|
458
|
nuclear@0
|
459 if (smf_event_is_sysex(event))
|
nuclear@0
|
460 return (smf_event_decode_sysex(event));
|
nuclear@0
|
461
|
nuclear@0
|
462 buf = malloc(BUFFER_SIZE);
|
nuclear@0
|
463 if (buf == NULL) {
|
nuclear@0
|
464 fg_critical("smf_event_decode_system_realtime: malloc failed.");
|
nuclear@0
|
465 return (NULL);
|
nuclear@0
|
466 }
|
nuclear@0
|
467
|
nuclear@0
|
468 switch (event->midi_buffer[0]) {
|
nuclear@0
|
469 case 0xF1:
|
nuclear@0
|
470 off += snprintf(buf + off, BUFFER_SIZE - off, "MTC Quarter Frame");
|
nuclear@0
|
471 break;
|
nuclear@0
|
472
|
nuclear@0
|
473 case 0xF2:
|
nuclear@0
|
474 off += snprintf(buf + off, BUFFER_SIZE - off, "Song Position Pointer");
|
nuclear@0
|
475 break;
|
nuclear@0
|
476
|
nuclear@0
|
477 case 0xF3:
|
nuclear@0
|
478 off += snprintf(buf + off, BUFFER_SIZE - off, "Song Select");
|
nuclear@0
|
479 break;
|
nuclear@0
|
480
|
nuclear@0
|
481 case 0xF6:
|
nuclear@0
|
482 off += snprintf(buf + off, BUFFER_SIZE - off, "Tune Request");
|
nuclear@0
|
483 break;
|
nuclear@0
|
484
|
nuclear@0
|
485 default:
|
nuclear@0
|
486 free(buf);
|
nuclear@0
|
487 return (NULL);
|
nuclear@0
|
488 }
|
nuclear@0
|
489
|
nuclear@0
|
490 return (buf);
|
nuclear@0
|
491 }
|
nuclear@0
|
492
|
nuclear@0
|
493 static void
|
nuclear@0
|
494 note_from_int(char *buf, int note_number)
|
nuclear@0
|
495 {
|
nuclear@0
|
496 int note, octave;
|
nuclear@0
|
497 char *names[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
|
nuclear@0
|
498
|
nuclear@0
|
499 octave = note_number / 12 - 1;
|
nuclear@0
|
500 note = note_number % 12;
|
nuclear@0
|
501
|
nuclear@0
|
502 sprintf(buf, "%s%d", names[note], octave);
|
nuclear@0
|
503 }
|
nuclear@0
|
504
|
nuclear@0
|
505 /**
|
nuclear@0
|
506 * \return Textual representation of the event given, or NULL, if event is unknown.
|
nuclear@0
|
507 * Returned string looks like this:
|
nuclear@0
|
508 *
|
nuclear@0
|
509 * Note On, channel 1, note F#3, velocity 0
|
nuclear@0
|
510 *
|
nuclear@0
|
511 * You should free the returned string afterwards, using free(3).
|
nuclear@0
|
512 */
|
nuclear@0
|
513 char *
|
nuclear@0
|
514 smf_event_decode(const smf_event_t *event)
|
nuclear@0
|
515 {
|
nuclear@0
|
516 int off = 0, channel;
|
nuclear@0
|
517 char *buf, note[5];
|
nuclear@0
|
518
|
nuclear@0
|
519 if (smf_event_is_metadata(event))
|
nuclear@0
|
520 return (smf_event_decode_metadata(event));
|
nuclear@0
|
521
|
nuclear@0
|
522 if (smf_event_is_system_realtime(event))
|
nuclear@0
|
523 return (smf_event_decode_system_realtime(event));
|
nuclear@0
|
524
|
nuclear@0
|
525 if (smf_event_is_system_common(event))
|
nuclear@0
|
526 return (smf_event_decode_system_common(event));
|
nuclear@0
|
527
|
nuclear@0
|
528 if (!smf_event_length_is_valid(event)) {
|
nuclear@0
|
529 fg_critical("smf_event_decode: incorrect MIDI message length.");
|
nuclear@0
|
530 return (NULL);
|
nuclear@0
|
531 }
|
nuclear@0
|
532
|
nuclear@0
|
533 buf = malloc(BUFFER_SIZE);
|
nuclear@0
|
534 if (buf == NULL) {
|
nuclear@0
|
535 fg_critical("smf_event_decode: malloc failed.");
|
nuclear@0
|
536 return (NULL);
|
nuclear@0
|
537 }
|
nuclear@0
|
538
|
nuclear@0
|
539 /* + 1, because user-visible channels used to be in range <1-16>. */
|
nuclear@0
|
540 channel = (event->midi_buffer[0] & 0x0F) + 1;
|
nuclear@0
|
541
|
nuclear@0
|
542 switch (event->midi_buffer[0] & 0xF0) {
|
nuclear@0
|
543 case 0x80:
|
nuclear@0
|
544 note_from_int(note, event->midi_buffer[1]);
|
nuclear@0
|
545 off += snprintf(buf + off, BUFFER_SIZE - off, "Note Off, channel %d, note %s, velocity %d",
|
nuclear@0
|
546 channel, note, event->midi_buffer[2]);
|
nuclear@0
|
547 break;
|
nuclear@0
|
548
|
nuclear@0
|
549 case 0x90:
|
nuclear@0
|
550 note_from_int(note, event->midi_buffer[1]);
|
nuclear@0
|
551 off += snprintf(buf + off, BUFFER_SIZE - off, "Note On, channel %d, note %s, velocity %d",
|
nuclear@0
|
552 channel, note, event->midi_buffer[2]);
|
nuclear@0
|
553 break;
|
nuclear@0
|
554
|
nuclear@0
|
555 case 0xA0:
|
nuclear@0
|
556 note_from_int(note, event->midi_buffer[1]);
|
nuclear@0
|
557 off += snprintf(buf + off, BUFFER_SIZE - off, "Aftertouch, channel %d, note %s, pressure %d",
|
nuclear@0
|
558 channel, note, event->midi_buffer[2]);
|
nuclear@0
|
559 break;
|
nuclear@0
|
560
|
nuclear@0
|
561 case 0xB0:
|
nuclear@0
|
562 off += snprintf(buf + off, BUFFER_SIZE - off, "Controller, channel %d, controller %d, value %d",
|
nuclear@0
|
563 channel, event->midi_buffer[1], event->midi_buffer[2]);
|
nuclear@0
|
564 break;
|
nuclear@0
|
565
|
nuclear@0
|
566 case 0xC0:
|
nuclear@0
|
567 off += snprintf(buf + off, BUFFER_SIZE - off, "Program Change, channel %d, controller %d",
|
nuclear@0
|
568 channel, event->midi_buffer[1]);
|
nuclear@0
|
569 break;
|
nuclear@0
|
570
|
nuclear@0
|
571 case 0xD0:
|
nuclear@0
|
572 off += snprintf(buf + off, BUFFER_SIZE - off, "Channel Pressure, channel %d, pressure %d",
|
nuclear@0
|
573 channel, event->midi_buffer[1]);
|
nuclear@0
|
574 break;
|
nuclear@0
|
575
|
nuclear@0
|
576 case 0xE0:
|
nuclear@0
|
577 off += snprintf(buf + off, BUFFER_SIZE - off, "Pitch Wheel, channel %d, value %d",
|
nuclear@0
|
578 channel, ((int)event->midi_buffer[2] << 7) | (int)event->midi_buffer[2]);
|
nuclear@0
|
579 break;
|
nuclear@0
|
580
|
nuclear@0
|
581 default:
|
nuclear@0
|
582 free(buf);
|
nuclear@0
|
583 return (NULL);
|
nuclear@0
|
584 }
|
nuclear@0
|
585
|
nuclear@0
|
586 return (buf);
|
nuclear@0
|
587 }
|
nuclear@0
|
588
|
nuclear@0
|
589 /**
|
nuclear@0
|
590 * \return Textual representation of the data extracted from MThd header, or NULL, if something goes wrong.
|
nuclear@0
|
591 * Returned string looks like this:
|
nuclear@0
|
592 *
|
nuclear@0
|
593 * format: 1 (several simultaneous tracks); number of tracks: 4; division: 192 PPQN.
|
nuclear@0
|
594 *
|
nuclear@0
|
595 * You should free the returned string afterwards, using free(3).
|
nuclear@0
|
596 */
|
nuclear@0
|
597 char *
|
nuclear@0
|
598 smf_decode(const smf_t *smf)
|
nuclear@0
|
599 {
|
nuclear@0
|
600 int off = 0;
|
nuclear@0
|
601 char *buf;
|
nuclear@0
|
602
|
nuclear@0
|
603 buf = malloc(BUFFER_SIZE);
|
nuclear@0
|
604 if (buf == NULL) {
|
nuclear@0
|
605 fg_critical("smf_event_decode: malloc failed.");
|
nuclear@0
|
606 return (NULL);
|
nuclear@0
|
607 }
|
nuclear@0
|
608
|
nuclear@0
|
609 off += snprintf(buf + off, BUFFER_SIZE - off, "format: %d ", smf->format);
|
nuclear@0
|
610
|
nuclear@0
|
611 switch (smf->format) {
|
nuclear@0
|
612 case 0:
|
nuclear@0
|
613 off += snprintf(buf + off, BUFFER_SIZE - off, "(single track)");
|
nuclear@0
|
614 break;
|
nuclear@0
|
615
|
nuclear@0
|
616 case 1:
|
nuclear@0
|
617 off += snprintf(buf + off, BUFFER_SIZE - off, "(several simultaneous tracks)");
|
nuclear@0
|
618 break;
|
nuclear@0
|
619
|
nuclear@0
|
620 case 2:
|
nuclear@0
|
621 off += snprintf(buf + off, BUFFER_SIZE - off, "(several independent tracks)");
|
nuclear@0
|
622 break;
|
nuclear@0
|
623
|
nuclear@0
|
624 default:
|
nuclear@0
|
625 off += snprintf(buf + off, BUFFER_SIZE - off, "(INVALID FORMAT)");
|
nuclear@0
|
626 break;
|
nuclear@0
|
627 }
|
nuclear@0
|
628
|
nuclear@0
|
629 off += snprintf(buf + off, BUFFER_SIZE - off, "; number of tracks: %d", smf->number_of_tracks);
|
nuclear@0
|
630
|
nuclear@0
|
631 if (smf->ppqn != 0)
|
nuclear@0
|
632 off += snprintf(buf + off, BUFFER_SIZE - off, "; division: %d PPQN", smf->ppqn);
|
nuclear@0
|
633 else
|
nuclear@0
|
634 off += snprintf(buf + off, BUFFER_SIZE - off, "; division: %d FPS, %d resolution", smf->frames_per_second, smf->resolution);
|
nuclear@0
|
635
|
nuclear@0
|
636 return (buf);
|
nuclear@0
|
637 }
|
nuclear@0
|
638
|