2 * Copyright (c) 2007, 2008 Edward Tomasz NapieraĆa <trasz@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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>.
39 #include <arpa/inet.h>
42 #include "smf_private.h"
44 #define BUFFER_SIZE 1024
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,
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)
64 * \return Nonzero if event is system realtime.
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
))
75 if (event
->midi_buffer
[0] >= 0xF8)
82 * \return Nonzero if event is system common.
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)
96 * \return Nonzero if event is SysEx message.
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)
111 smf_event_decode_textual(const smf_event_t
*event
, const char *name
)
114 char *buf
, *extracted
;
116 buf
= malloc(BUFFER_SIZE
);
118 g_critical("smf_event_decode_textual: malloc failed.");
122 extracted
= smf_string_from_event(event
);
123 if (extracted
== NULL
) {
128 snprintf(buf
+ off
, BUFFER_SIZE
- off
, "%s: %s", name
, extracted
);
134 smf_event_decode_metadata(const smf_event_t
*event
)
136 int off
= 0, mspqn
, flats
, isminor
;
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]) {
149 return smf_event_decode_textual(event
, "Text");
152 return smf_event_decode_textual(event
, "Copyright");
155 return smf_event_decode_textual(event
, "Sequence/Track Name");
158 return smf_event_decode_textual(event
, "Instrument");
161 return smf_event_decode_textual(event
, "Lyric");
164 return smf_event_decode_textual(event
, "Marker");
167 return smf_event_decode_textual(event
, "Cue Point");
170 return smf_event_decode_textual(event
, "Program Name");
173 return smf_event_decode_textual(event
, "Device (Port) Name");
179 buf
= malloc(BUFFER_SIZE
);
181 g_critical("smf_event_decode_metadata: malloc failed.");
185 switch (event
->midi_buffer
[1]) {
187 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Sequence number");
190 /* http://music.columbia.edu/pipermail/music-dsp/2004-August/061196.html */
192 if (event
->midi_buffer_length
< 4) {
193 g_critical("smf_event_decode_metadata: truncated MIDI message.");
197 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Channel Prefix: %d.", event
->midi_buffer
[3]);
201 if (event
->midi_buffer_length
< 4) {
202 g_critical("smf_event_decode_metadata: truncated MIDI message.");
206 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Midi Port: %d.", event
->midi_buffer
[3]);
210 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "End Of Track");
214 if (event
->midi_buffer_length
< 6) {
215 g_critical("smf_event_decode_metadata: truncated MIDI message.");
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
);
226 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "SMPTE Offset");
230 if (event
->midi_buffer_length
< 7) {
231 g_critical("smf_event_decode_metadata: truncated MIDI message.");
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]);
242 if (event
->midi_buffer_length
< 5) {
243 g_critical("smf_event_decode_metadata: truncated MIDI message.");
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
);
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");
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
));
267 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "%s", minor_keys
[i
]);
269 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "%s", major_keys
[i
]);
275 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Proprietary (aka Sequencer) Event, length %d",
276 event
->midi_buffer_length
);
292 smf_event_decode_system_realtime(const smf_event_t
*event
)
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.");
304 buf
= malloc(BUFFER_SIZE
);
306 g_critical("smf_event_decode_system_realtime: malloc failed.");
310 switch (event
->midi_buffer
[0]) {
312 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Clock (realtime)");
316 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Tick (realtime)");
320 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Start (realtime)");
324 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Continue (realtime)");
328 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Stop (realtime)");
332 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Active Sense (realtime)");
344 smf_event_decode_sysex(const smf_event_t
*event
)
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.");
356 buf
= malloc(BUFFER_SIZE
);
358 g_critical("smf_event_decode_sysex: malloc failed.");
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]);
369 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "SysEx, manufacturer 0x%x", manufacturer
);
374 subid
= event
->midi_buffer
[3];
375 subid2
= event
->midi_buffer
[4];
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");
441 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Unknown");
447 smf_event_decode_system_common(const smf_event_t
*event
)
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
);
459 g_critical("smf_event_decode_system_realtime: malloc failed.");
463 switch (event
->midi_buffer
[0]) {
465 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MTC Quarter Frame");
469 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Song Position Pointer");
473 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Song Select");
477 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Tune Request");
489 note_from_int(char *buf
, int note_number
)
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
506 smf_event_decode(const smf_event_t
*event
)
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.");
525 buf
= malloc(BUFFER_SIZE
);
527 g_critical("smf_event_decode: malloc failed.");
531 switch (event
->midi_buffer
[0] & 0xF0) {
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]);
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]);
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]);
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]);
556 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Program Change, channel %d, controller %d",
557 event
->midi_buffer
[0] & 0x0F, event
->midi_buffer
[1]);
561 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Channel Pressure, channel %d, pressure %d",
562 event
->midi_buffer
[0] & 0x0F, event
->midi_buffer
[1]);
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]);
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.
584 smf_decode(const smf_t
*smf
)
589 buf
= malloc(BUFFER_SIZE
);
591 g_critical("smf_event_decode: malloc failed.");
595 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "format: %d ", smf
->format
);
597 switch (smf
->format
) {
599 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "(single track)");
603 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "(several simultaneous tracks)");
607 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "(several independent tracks)");
611 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "(INVALID FORMAT)");
615 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "; number of tracks: %d", smf
->number_of_tracks
);
618 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "; division: %d PPQN", smf
->ppqn
);
620 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "; division: %d FPS, %d resolution", smf
->frames_per_second
, smf
->resolution
);