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.
31 * Event decoding routines.
40 #include <arpa/inet.h>
43 #include "smf_private.h"
45 #define BUFFER_SIZE 1024
48 * \return Nonzero if event is metaevent. You should never send metaevents;
49 * they are not really MIDI messages. They carry information like track title,
53 smf_event_is_metadata(const smf_event_t
*event
)
55 assert(event
->midi_buffer
);
56 assert(event
->midi_buffer_length
> 0);
58 if (event
->midi_buffer
[0] == 0xFF)
65 * \return Nonzero if event is System Realtime.
68 smf_event_is_system_realtime(const smf_event_t
*event
)
70 assert(event
->midi_buffer
);
71 assert(event
->midi_buffer_length
> 0);
73 if (smf_event_is_metadata(event
))
76 if (event
->midi_buffer
[0] >= 0xF8)
83 * \return Nonzero if event is System Common.
86 smf_event_is_system_common(const smf_event_t
*event
)
88 assert(event
->midi_buffer
);
89 assert(event
->midi_buffer_length
> 0);
91 if (event
->midi_buffer
[0] >= 0xF0 && event
->midi_buffer
[0] <= 0xF7)
97 * \return Nonzero if event is SysEx message.
100 smf_event_is_sysex(const smf_event_t
*event
)
102 assert(event
->midi_buffer
);
103 assert(event
->midi_buffer_length
> 0);
105 if (event
->midi_buffer
[0] == 0xF0)
112 smf_event_decode_textual(const smf_event_t
*event
, const char *name
)
115 char *buf
, *extracted
;
117 buf
= malloc(BUFFER_SIZE
);
119 g_critical("smf_event_decode_textual: malloc failed.");
123 extracted
= smf_event_extract_text(event
);
124 if (extracted
== NULL
) {
129 snprintf(buf
+ off
, BUFFER_SIZE
- off
, "%s: %s", name
, extracted
);
135 smf_event_decode_metadata(const smf_event_t
*event
)
137 int off
= 0, mspqn
, flats
, isminor
;
140 static const char *const major_keys
[] = {"Fb", "Cb", "Gb", "Db", "Ab",
141 "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#"};
143 static const char *const minor_keys
[] = {"Dbm", "Abm", "Ebm", "Bbm", "Fm",
144 "Cm", "Gm", "Dm", "Am", "Em", "Bm", "F#m", "C#m", "G#m", "D#m", "A#m", "E#m"};
146 assert(smf_event_is_metadata(event
));
148 switch (event
->midi_buffer
[1]) {
150 return (smf_event_decode_textual(event
, "Text"));
153 return (smf_event_decode_textual(event
, "Copyright"));
156 return (smf_event_decode_textual(event
, "Sequence/Track Name"));
159 return (smf_event_decode_textual(event
, "Instrument"));
162 return (smf_event_decode_textual(event
, "Lyric"));
165 return (smf_event_decode_textual(event
, "Marker"));
168 return (smf_event_decode_textual(event
, "Cue Point"));
171 return (smf_event_decode_textual(event
, "Program Name"));
174 return (smf_event_decode_textual(event
, "Device (Port) Name"));
180 buf
= malloc(BUFFER_SIZE
);
182 g_critical("smf_event_decode_metadata: malloc failed.");
186 switch (event
->midi_buffer
[1]) {
188 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Sequence number");
191 /* http://music.columbia.edu/pipermail/music-dsp/2004-August/061196.html */
193 if (event
->midi_buffer_length
< 4) {
194 g_critical("smf_event_decode_metadata: truncated MIDI message.");
198 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Channel Prefix: %d", event
->midi_buffer
[3]);
202 if (event
->midi_buffer_length
< 4) {
203 g_critical("smf_event_decode_metadata: truncated MIDI message.");
207 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Port: %d", event
->midi_buffer
[3]);
211 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "End Of Track");
215 if (event
->midi_buffer_length
< 6) {
216 g_critical("smf_event_decode_metadata: truncated MIDI message.");
220 mspqn
= (event
->midi_buffer
[3] << 16) + (event
->midi_buffer
[4] << 8) + event
->midi_buffer
[5];
222 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Tempo: %d microseconds per quarter note, %.2f BPM",
223 mspqn
, 60000000.0 / (double)mspqn
);
227 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "SMPTE Offset");
231 if (event
->midi_buffer_length
< 7) {
232 g_critical("smf_event_decode_metadata: truncated MIDI message.");
236 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
,
237 "Time Signature: %d/%d, %d clocks per click, %d notated 32nd notes per quarter note",
238 event
->midi_buffer
[3], (int)pow(2, event
->midi_buffer
[4]), event
->midi_buffer
[5],
239 event
->midi_buffer
[6]);
243 if (event
->midi_buffer_length
< 5) {
244 g_critical("smf_event_decode_metadata: truncated MIDI message.");
248 flats
= event
->midi_buffer
[3];
249 isminor
= event
->midi_buffer
[4];
251 if (isminor
!= 0 && isminor
!= 1) {
252 g_critical("smf_event_decode_metadata: last byte of the Key Signature event has invalid value %d.", isminor
);
256 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Key Signature: ");
258 if (flats
> 8 && flats
< 248) {
259 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "%d %s, %s key", abs((int8_t)flats
),
260 flats
> 127 ? "flats" : "sharps", isminor
? "minor" : "major");
262 int i
= (flats
- 248) & 255;
264 assert(i
>= 0 && i
< sizeof(minor_keys
) / sizeof(*minor_keys
));
265 assert(i
>= 0 && i
< sizeof(major_keys
) / sizeof(*major_keys
));
268 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "%s", minor_keys
[i
]);
270 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "%s", major_keys
[i
]);
276 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Proprietary (aka Sequencer) Event, length %d",
277 event
->midi_buffer_length
);
293 smf_event_decode_system_realtime(const smf_event_t
*event
)
298 assert(smf_event_is_system_realtime(event
));
300 if (event
->midi_buffer_length
!= 1) {
301 g_critical("smf_event_decode_system_realtime: event length is not 1.");
305 buf
= malloc(BUFFER_SIZE
);
307 g_critical("smf_event_decode_system_realtime: malloc failed.");
311 switch (event
->midi_buffer
[0]) {
313 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Clock (realtime)");
317 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Tick (realtime)");
321 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Start (realtime)");
325 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Continue (realtime)");
329 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MIDI Stop (realtime)");
333 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Active Sense (realtime)");
345 smf_event_decode_sysex(const smf_event_t
*event
)
348 char *buf
, manufacturer
, subid
, subid2
;
350 assert(smf_event_is_sysex(event
));
352 if (event
->midi_buffer_length
< 5) {
353 g_critical("smf_event_decode_sysex: truncated MIDI message.");
357 buf
= malloc(BUFFER_SIZE
);
359 g_critical("smf_event_decode_sysex: malloc failed.");
363 manufacturer
= event
->midi_buffer
[1];
365 if (manufacturer
== 0x7F) {
366 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "SysEx, realtime, channel %d", event
->midi_buffer
[2]);
367 } else if (manufacturer
== 0x7E) {
368 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "SysEx, non-realtime, channel %d", event
->midi_buffer
[2]);
370 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "SysEx, manufacturer 0x%x", manufacturer
);
375 subid
= event
->midi_buffer
[3];
376 subid2
= event
->midi_buffer
[4];
379 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump Header");
381 else if (subid
== 0x02)
382 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump Data Packet");
384 else if (subid
== 0x03)
385 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump Request");
387 else if (subid
== 0x04 && subid2
== 0x01)
388 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Master Volume");
390 else if (subid
== 0x05 && subid2
== 0x01)
391 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump Loop Point Retransmit");
393 else if (subid
== 0x05 && subid2
== 0x02)
394 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump Loop Point Request");
396 else if (subid
== 0x06 && subid2
== 0x01)
397 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Identity Request");
399 else if (subid
== 0x06 && subid2
== 0x02)
400 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Identity Reply");
402 else if (subid
== 0x08 && subid2
== 0x00)
403 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Bulk Tuning Dump Request");
405 else if (subid
== 0x08 && subid2
== 0x01)
406 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Bulk Tuning Dump");
408 else if (subid
== 0x08 && subid2
== 0x02)
409 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Single Note Tuning Change");
411 else if (subid
== 0x08 && subid2
== 0x03)
412 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Bulk Tuning Dump Request (Bank)");
414 else if (subid
== 0x08 && subid2
== 0x04)
415 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Key Based Tuning Dump");
417 else if (subid
== 0x08 && subid2
== 0x05)
418 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Scale/Octave Tuning Dump, 1 byte format");
420 else if (subid
== 0x08 && subid2
== 0x06)
421 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Scale/Octave Tuning Dump, 2 byte format");
423 else if (subid
== 0x08 && subid2
== 0x07)
424 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Single Note Tuning Change (Bank)");
426 else if (subid
== 0x09)
427 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", General MIDI %s", subid2
== 0 ? "disable" : "enable");
429 else if (subid
== 0x7C)
430 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump Wait");
432 else if (subid
== 0x7D)
433 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump Cancel");
435 else if (subid
== 0x7E)
436 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump NAK");
438 else if (subid
== 0x7F)
439 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Sample Dump ACK");
442 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, ", Unknown");
448 smf_event_decode_system_common(const smf_event_t
*event
)
453 assert(smf_event_is_system_common(event
));
455 if (smf_event_is_sysex(event
))
456 return (smf_event_decode_sysex(event
));
458 buf
= malloc(BUFFER_SIZE
);
460 g_critical("smf_event_decode_system_realtime: malloc failed.");
464 switch (event
->midi_buffer
[0]) {
466 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "MTC Quarter Frame");
470 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Song Position Pointer");
474 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Song Select");
478 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Tune Request");
490 note_from_int(char *buf
, int note_number
)
493 char *names
[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
495 octave
= note_number
/ 12 - 1;
496 note
= note_number
% 12;
498 sprintf(buf
, "%s%d", names
[note
], octave
);
502 * \return Textual representation of the event given, or NULL, if event is unknown.
503 * Returned string looks like this:
505 * Note On, channel 1, note F#3, velocity 0
507 * You should free the returned string afterwards, using free(3).
510 smf_event_decode(const smf_event_t
*event
)
512 int off
= 0, channel
;
515 if (smf_event_is_metadata(event
))
516 return (smf_event_decode_metadata(event
));
518 if (smf_event_is_system_realtime(event
))
519 return (smf_event_decode_system_realtime(event
));
521 if (smf_event_is_system_common(event
))
522 return (smf_event_decode_system_common(event
));
524 if (!smf_event_length_is_valid(event
)) {
525 g_critical("smf_event_decode: incorrect MIDI message length.");
529 buf
= malloc(BUFFER_SIZE
);
531 g_critical("smf_event_decode: malloc failed.");
535 /* + 1, because user-visible channels used to be in range <1-16>. */
536 channel
= (event
->midi_buffer
[0] & 0x0F) + 1;
538 switch (event
->midi_buffer
[0] & 0xF0) {
540 note_from_int(note
, event
->midi_buffer
[1]);
541 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Note Off, channel %d, note %s, velocity %d",
542 channel
, note
, event
->midi_buffer
[2]);
546 note_from_int(note
, event
->midi_buffer
[1]);
547 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Note On, channel %d, note %s, velocity %d",
548 channel
, note
, event
->midi_buffer
[2]);
552 note_from_int(note
, event
->midi_buffer
[1]);
553 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Aftertouch, channel %d, note %s, pressure %d",
554 channel
, note
, event
->midi_buffer
[2]);
558 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Controller, channel %d, controller %d, value %d",
559 channel
, event
->midi_buffer
[1], event
->midi_buffer
[2]);
563 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Program Change, channel %d, controller %d",
564 channel
, event
->midi_buffer
[1]);
568 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Channel Pressure, channel %d, pressure %d",
569 channel
, event
->midi_buffer
[1]);
573 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "Pitch Wheel, channel %d, value %d",
574 channel
, ((int)event
->midi_buffer
[2] << 7) | (int)event
->midi_buffer
[2]);
586 * \return Textual representation of the data extracted from MThd header, or NULL, if something goes wrong.
587 * Returned string looks like this:
589 * format: 1 (several simultaneous tracks); number of tracks: 4; division: 192 PPQN.
591 * You should free the returned string afterwards, using free(3).
594 smf_decode(const smf_t
*smf
)
599 buf
= malloc(BUFFER_SIZE
);
601 g_critical("smf_event_decode: malloc failed.");
605 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "format: %d ", smf
->format
);
607 switch (smf
->format
) {
609 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "(single track)");
613 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "(several simultaneous tracks)");
617 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "(several independent tracks)");
621 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "(INVALID FORMAT)");
625 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "; number of tracks: %d", smf
->number_of_tracks
);
628 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "; division: %d PPQN", smf
->ppqn
);
630 off
+= snprintf(buf
+ off
, BUFFER_SIZE
- off
, "; division: %d FPS, %d resolution", smf
->frames_per_second
, smf
->resolution
);