Import of jack-smf-utils 1.0.
[jack-smf-utils.git] / libsmf / smf_decode.c
blob3cd762c1a22f9a459e88b7d1c4d94c00c3422e4a
1 /*-
2 * Copyright (c) 2007, 2008 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * ALTHOUGH THIS SOFTWARE IS MADE OF WIN AND SCIENCE, IT IS PROVIDED BY THE
15 * AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18 * THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
20 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
21 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * This is Standard MIDI File format implementation, event decoding routines.
31 * For questions and comments, contact Edward Tomasz Napierala <trasz@FreeBSD.org>.
34 #include <stdlib.h>
35 #include <string.h>
36 #include <assert.h>
37 #include <math.h>
38 #include <errno.h>
39 #include <arpa/inet.h>
40 #include <stdint.h>
41 #include "smf.h"
42 #include "smf_private.h"
44 #define BUFFER_SIZE 1024
46 /**
47 * \return Nonzero if event is metaevent. You should never send metaevents;
48 * they are not really MIDI messages. They carry information like track title,
49 * time signature etc.
51 int
52 smf_event_is_metadata(const smf_event_t *event)
54 assert(event->midi_buffer);
55 assert(event->midi_buffer_length > 0);
57 if (event->midi_buffer[0] == 0xFF)
58 return 1;
60 return 0;
63 /**
64 * \return Nonzero if event is system realtime.
66 int
67 smf_event_is_system_realtime(const smf_event_t *event)
69 assert(event->midi_buffer);
70 assert(event->midi_buffer_length > 0);
72 if (smf_event_is_metadata(event))
73 return 0;
75 if (event->midi_buffer[0] >= 0xF8)
76 return 1;
78 return 0;
81 /**
82 * \return Nonzero if event is system common.
84 int
85 smf_event_is_system_common(const smf_event_t *event)
87 assert(event->midi_buffer);
88 assert(event->midi_buffer_length > 0);
90 if (event->midi_buffer[0] >= 0xF0 && event->midi_buffer[0] <= 0xF7)
91 return 1;
93 return 0;
95 /**
96 * \return Nonzero if event is SysEx message.
98 int
99 smf_event_is_sysex(const smf_event_t *event)
101 assert(event->midi_buffer);
102 assert(event->midi_buffer_length > 0);
104 if (event->midi_buffer[0] == 0xF0)
105 return 1;
107 return 0;
110 static char *
111 smf_event_decode_textual(const smf_event_t *event, const char *name)
113 int off = 0;
114 char *buf, *extracted;
116 buf = malloc(BUFFER_SIZE);
117 if (buf == NULL) {
118 g_critical("smf_event_decode_textual: malloc failed.");
119 return NULL;
122 extracted = smf_string_from_event(event);
123 if (extracted == NULL) {
124 free(buf);
125 return NULL;
128 snprintf(buf + off, BUFFER_SIZE - off, "%s: %s", name, extracted);
130 return buf;
133 static char *
134 smf_event_decode_metadata(const smf_event_t *event)
136 int off = 0, mspqn, flats, isminor;
137 char *buf;
139 static const char *const major_keys[] = {"Fb", "Cb", "Gb", "Db", "Ab",
140 "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#"};
142 static const char *const minor_keys[] = {"Dbm", "Abm", "Ebm", "Bbm", "Fm",
143 "Cm", "Gm", "Dm", "Am", "Em", "Bm", "F#m", "C#m", "G#m", "D#m", "A#m", "E#m"};
145 assert(smf_event_is_metadata(event));
147 switch (event->midi_buffer[1]) {
148 case 0x01:
149 return smf_event_decode_textual(event, "Text");
151 case 0x02:
152 return smf_event_decode_textual(event, "Copyright");
154 case 0x03:
155 return smf_event_decode_textual(event, "Sequence/Track Name");
157 case 0x04:
158 return smf_event_decode_textual(event, "Instrument");
160 case 0x05:
161 return smf_event_decode_textual(event, "Lyric");
163 case 0x06:
164 return smf_event_decode_textual(event, "Marker");
166 case 0x07:
167 return smf_event_decode_textual(event, "Cue Point");
169 case 0x08:
170 return smf_event_decode_textual(event, "Program Name");
172 case 0x09:
173 return smf_event_decode_textual(event, "Device (Port) Name");
175 default:
176 break;
179 buf = malloc(BUFFER_SIZE);
180 if (buf == NULL) {
181 g_critical("smf_event_decode_metadata: malloc failed.");
182 return NULL;
185 switch (event->midi_buffer[1]) {
186 case 0x00:
187 off += snprintf(buf + off, BUFFER_SIZE - off, "Sequence number");
188 break;
190 /* http://music.columbia.edu/pipermail/music-dsp/2004-August/061196.html */
191 case 0x20:
192 if (event->midi_buffer_length < 4) {
193 g_critical("smf_event_decode_metadata: truncated MIDI message.");
194 goto error;
197 off += snprintf(buf + off, BUFFER_SIZE - off, "Channel Prefix: %d.", event->midi_buffer[3]);
198 break;
200 case 0x21:
201 if (event->midi_buffer_length < 4) {
202 g_critical("smf_event_decode_metadata: truncated MIDI message.");
203 goto error;
206 off += snprintf(buf + off, BUFFER_SIZE - off, "Midi Port: %d.", event->midi_buffer[3]);
207 break;
209 case 0x2F:
210 off += snprintf(buf + off, BUFFER_SIZE - off, "End Of Track");
211 break;
213 case 0x51:
214 if (event->midi_buffer_length < 6) {
215 g_critical("smf_event_decode_metadata: truncated MIDI message.");
216 goto error;
219 mspqn = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5];
221 off += snprintf(buf + off, BUFFER_SIZE - off, "Tempo: %d microseconds per quarter note, %.2f BPM",
222 mspqn, 60000000.0 / (double)mspqn);
223 break;
225 case 0x54:
226 off += snprintf(buf + off, BUFFER_SIZE - off, "SMPTE Offset");
227 break;
229 case 0x58:
230 if (event->midi_buffer_length < 7) {
231 g_critical("smf_event_decode_metadata: truncated MIDI message.");
232 goto error;
235 off += snprintf(buf + off, BUFFER_SIZE - off,
236 "Time Signature: %d/%d, %d clocks per click, %d notated 32nd notes per quarter note",
237 event->midi_buffer[3], (int)pow(2, event->midi_buffer[4]), event->midi_buffer[5],
238 event->midi_buffer[6]);
239 break;
241 case 0x59:
242 if (event->midi_buffer_length < 5) {
243 g_critical("smf_event_decode_metadata: truncated MIDI message.");
244 goto error;
247 flats = event->midi_buffer[3];
248 isminor = event->midi_buffer[4];
250 if (isminor != 0 && isminor != 1) {
251 g_critical("smf_event_decode_metadata: last byte of the Key Signature event has invalid value %d.", isminor);
252 goto error;
255 off += snprintf(buf + off, BUFFER_SIZE - off, "Key Signature: ");
257 if (flats > 8 && flats < 248) {
258 off += snprintf(buf + off, BUFFER_SIZE - off, "%d %s, %s key", abs((int8_t)flats),
259 flats > 127 ? "flats" : "sharps", isminor ? "minor" : "major");
260 } else {
261 int i = (flats - 248) & 255;
263 assert(i >= 0 && i < sizeof(minor_keys) / sizeof(*minor_keys));
264 assert(i >= 0 && i < sizeof(major_keys) / sizeof(*major_keys));
266 if (isminor)
267 off += snprintf(buf + off, BUFFER_SIZE - off, "%s", minor_keys[i]);
268 else
269 off += snprintf(buf + off, BUFFER_SIZE - off, "%s", major_keys[i]);
272 break;
274 case 0x7F:
275 off += snprintf(buf + off, BUFFER_SIZE - off, "Proprietary (aka Sequencer) Event, length %d",
276 event->midi_buffer_length);
277 break;
279 default:
280 goto error;
283 return buf;
285 error:
286 free(buf);
288 return NULL;
291 static char *
292 smf_event_decode_system_realtime(const smf_event_t *event)
294 int off = 0;
295 char *buf;
297 assert(smf_event_is_system_realtime(event));
299 if (event->midi_buffer_length != 1) {
300 g_critical("smf_event_decode_system_realtime: event length is not 1.");
301 return NULL;
304 buf = malloc(BUFFER_SIZE);
305 if (buf == NULL) {
306 g_critical("smf_event_decode_system_realtime: malloc failed.");
307 return NULL;
310 switch (event->midi_buffer[0]) {
311 case 0xF8:
312 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Clock (realtime)");
313 break;
315 case 0xF9:
316 off += snprintf(buf + off, BUFFER_SIZE - off, "Tick (realtime)");
317 break;
319 case 0xFA:
320 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Start (realtime)");
321 break;
323 case 0xFB:
324 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Continue (realtime)");
325 break;
327 case 0xFC:
328 off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Stop (realtime)");
329 break;
331 case 0xFE:
332 off += snprintf(buf + off, BUFFER_SIZE - off, "Active Sense (realtime)");
333 break;
335 default:
336 free(buf);
337 return NULL;
340 return buf;
343 static char *
344 smf_event_decode_sysex(const smf_event_t *event)
346 int off = 0;
347 char *buf, manufacturer, subid, subid2;
349 assert(smf_event_is_sysex(event));
351 if (event->midi_buffer_length < 5) {
352 g_critical("smf_event_decode_sysex: truncated MIDI message.");
353 return NULL;
356 buf = malloc(BUFFER_SIZE);
357 if (buf == NULL) {
358 g_critical("smf_event_decode_sysex: malloc failed.");
359 return NULL;
362 manufacturer = event->midi_buffer[1];
364 if (manufacturer == 0x7F) {
365 off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, realtime, channel %d", event->midi_buffer[2]);
366 } else if (manufacturer == 0x7E) {
367 off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, non-realtime, channel %d", event->midi_buffer[2]);
368 } else {
369 off += snprintf(buf + off, BUFFER_SIZE - off, "SysEx, manufacturer 0x%x", manufacturer);
371 return buf;
374 subid = event->midi_buffer[3];
375 subid2 = event->midi_buffer[4];
377 if (subid == 0x01)
378 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Header");
380 else if (subid == 0x02)
381 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Data Packet");
383 else if (subid == 0x03)
384 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Request");
386 else if (subid == 0x04 && subid2 == 0x01)
387 off += snprintf(buf + off, BUFFER_SIZE - off, ", Master Volume");
389 else if (subid == 0x05 && subid2 == 0x01)
390 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Loop Point Retransmit");
392 else if (subid == 0x05 && subid2 == 0x02)
393 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Loop Point Request");
395 else if (subid == 0x06 && subid2 == 0x01)
396 off += snprintf(buf + off, BUFFER_SIZE - off, ", Identity Request");
398 else if (subid == 0x06 && subid2 == 0x02)
399 off += snprintf(buf + off, BUFFER_SIZE - off, ", Identity Reply");
401 else if (subid == 0x08 && subid2 == 0x00)
402 off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump Request");
404 else if (subid == 0x08 && subid2 == 0x01)
405 off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump");
407 else if (subid == 0x08 && subid2 == 0x02)
408 off += snprintf(buf + off, BUFFER_SIZE - off, ", Single Note Tuning Change");
410 else if (subid == 0x08 && subid2 == 0x03)
411 off += snprintf(buf + off, BUFFER_SIZE - off, ", Bulk Tuning Dump Request (Bank)");
413 else if (subid == 0x08 && subid2 == 0x04)
414 off += snprintf(buf + off, BUFFER_SIZE - off, ", Key Based Tuning Dump");
416 else if (subid == 0x08 && subid2 == 0x05)
417 off += snprintf(buf + off, BUFFER_SIZE - off, ", Scale/Octave Tuning Dump, 1 byte format");
419 else if (subid == 0x08 && subid2 == 0x06)
420 off += snprintf(buf + off, BUFFER_SIZE - off, ", Scale/Octave Tuning Dump, 2 byte format");
422 else if (subid == 0x08 && subid2 == 0x07)
423 off += snprintf(buf + off, BUFFER_SIZE - off, ", Single Note Tuning Change (Bank)");
425 else if (subid == 0x09)
426 off += snprintf(buf + off, BUFFER_SIZE - off, ", General Midi %s", subid2 == 0 ? "disable" : "enable");
428 else if (subid == 0x7C)
429 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Wait");
431 else if (subid == 0x7D)
432 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump Cancel");
434 else if (subid == 0x7E)
435 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump NAK");
437 else if (subid == 0x7F)
438 off += snprintf(buf + off, BUFFER_SIZE - off, ", Sample Dump ACK");
440 else
441 off += snprintf(buf + off, BUFFER_SIZE - off, ", Unknown");
443 return buf;
446 static char *
447 smf_event_decode_system_common(const smf_event_t *event)
449 int off = 0;
450 char *buf;
452 assert(smf_event_is_system_common(event));
454 if (smf_event_is_sysex(event))
455 return smf_event_decode_sysex(event);
457 buf = malloc(BUFFER_SIZE);
458 if (buf == NULL) {
459 g_critical("smf_event_decode_system_realtime: malloc failed.");
460 return NULL;
463 switch (event->midi_buffer[0]) {
464 case 0xF1:
465 off += snprintf(buf + off, BUFFER_SIZE - off, "MTC Quarter Frame");
466 break;
468 case 0xF2:
469 off += snprintf(buf + off, BUFFER_SIZE - off, "Song Position Pointer");
470 break;
472 case 0xF3:
473 off += snprintf(buf + off, BUFFER_SIZE - off, "Song Select");
474 break;
476 case 0xF6:
477 off += snprintf(buf + off, BUFFER_SIZE - off, "Tune Request");
478 break;
480 default:
481 free(buf);
482 return NULL;
485 return buf;
488 static void
489 note_from_int(char *buf, int note_number)
491 int note, octave;
492 char *names[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
494 octave = note_number / 12 - 1;
495 note = note_number % 12;
497 sprintf(buf, "%s%d", names[note], octave);
501 * \return Textual representation of the event given, or NULL, if event is unknown.
502 * Returned string looks like this:
503 * Note On, channel 0, note F#3, velocity 0
505 char *
506 smf_event_decode(const smf_event_t *event)
508 int off = 0;
509 char *buf, note[5];
511 if (smf_event_is_metadata(event))
512 return smf_event_decode_metadata(event);
514 if (smf_event_is_system_realtime(event))
515 return smf_event_decode_system_realtime(event);
517 if (smf_event_is_system_common(event))
518 return smf_event_decode_system_common(event);
520 if (!smf_event_length_is_valid(event)) {
521 g_critical("smf_event_decode: incorrect MIDI message length.");
522 return NULL;
525 buf = malloc(BUFFER_SIZE);
526 if (buf == NULL) {
527 g_critical("smf_event_decode: malloc failed.");
528 return NULL;
531 switch (event->midi_buffer[0] & 0xF0) {
532 case 0x80:
533 note_from_int(note, event->midi_buffer[1]);
534 off += snprintf(buf + off, BUFFER_SIZE - off, "Note Off, channel %d, note %s, velocity %d",
535 event->midi_buffer[0] & 0x0F, note, event->midi_buffer[2]);
536 break;
538 case 0x90:
539 note_from_int(note, event->midi_buffer[1]);
540 off += snprintf(buf + off, BUFFER_SIZE - off, "Note On, channel %d, note %s, velocity %d",
541 event->midi_buffer[0] & 0x0F, note, event->midi_buffer[2]);
542 break;
544 case 0xA0:
545 note_from_int(note, event->midi_buffer[1]);
546 off += snprintf(buf + off, BUFFER_SIZE - off, "Aftertouch, channel %d, note %s, pressure %d",
547 event->midi_buffer[0] & 0x0F, note, event->midi_buffer[2]);
548 break;
550 case 0xB0:
551 off += snprintf(buf + off, BUFFER_SIZE - off, "Controller, channel %d, controller %d, value %d",
552 event->midi_buffer[0] & 0x0F, event->midi_buffer[1], event->midi_buffer[2]);
553 break;
555 case 0xC0:
556 off += snprintf(buf + off, BUFFER_SIZE - off, "Program Change, channel %d, controller %d",
557 event->midi_buffer[0] & 0x0F, event->midi_buffer[1]);
558 break;
560 case 0xD0:
561 off += snprintf(buf + off, BUFFER_SIZE - off, "Channel Pressure, channel %d, pressure %d",
562 event->midi_buffer[0] & 0x0F, event->midi_buffer[1]);
563 break;
565 case 0xE0:
566 off += snprintf(buf + off, BUFFER_SIZE - off, "Pitch Wheel, channel %d, value %d",
567 event->midi_buffer[0] & 0x0F, ((int)event->midi_buffer[2] << 7) | (int)event->midi_buffer[2]);
568 break;
570 default:
571 free(buf);
572 return NULL;
575 return buf;
579 * \return Textual representation of the data extracted from MThd header, or NULL, if something goes wrong.
580 * Returned string looks like this:
581 * format: 1 (several simultaneous tracks); number of tracks: 4; division: 192 PPQN.
583 char *
584 smf_decode(const smf_t *smf)
586 int off = 0;
587 char *buf;
589 buf = malloc(BUFFER_SIZE);
590 if (buf == NULL) {
591 g_critical("smf_event_decode: malloc failed.");
592 return NULL;
595 off += snprintf(buf + off, BUFFER_SIZE - off, "format: %d ", smf->format);
597 switch (smf->format) {
598 case 0:
599 off += snprintf(buf + off, BUFFER_SIZE - off, "(single track)");
600 break;
602 case 1:
603 off += snprintf(buf + off, BUFFER_SIZE - off, "(several simultaneous tracks)");
604 break;
606 case 2:
607 off += snprintf(buf + off, BUFFER_SIZE - off, "(several independent tracks)");
608 break;
610 default:
611 off += snprintf(buf + off, BUFFER_SIZE - off, "(INVALID FORMAT)");
612 break;
615 off += snprintf(buf + off, BUFFER_SIZE - off, "; number of tracks: %d", smf->number_of_tracks);
617 if (smf->ppqn != 0)
618 off += snprintf(buf + off, BUFFER_SIZE - off, "; division: %d PPQN", smf->ppqn);
619 else
620 off += snprintf(buf + off, BUFFER_SIZE - off, "; division: %d FPS, %d resolution", smf->frames_per_second, smf->resolution);
622 return buf;