43 #include <arpa/inet.h>
49 #define BUFFER_SIZE 1024
116 smf_event_decode_textual(
const smf_event_t *event,
const char *name)
119 char *buf, *extracted;
121 buf = malloc(BUFFER_SIZE);
123 g_critical(
"smf_event_decode_textual: malloc failed.");
128 if (extracted == NULL) {
133 snprintf(buf + off, BUFFER_SIZE - off,
"%s: %s", name, extracted);
139 smf_event_decode_metadata(
const smf_event_t *event)
141 int off = 0, mspqn, flats, isminor;
144 static const char *
const major_keys[] = {
"Fb",
"Cb",
"Gb",
"Db",
"Ab",
145 "Eb",
"Bb",
"F",
"C",
"G",
"D",
"A",
"E",
"B",
"F#",
"C#",
"G#"};
147 static const char *
const minor_keys[] = {
"Dbm",
"Abm",
"Ebm",
"Bbm",
"Fm",
148 "Cm",
"Gm",
"Dm",
"Am",
"Em",
"Bm",
"F#m",
"C#m",
"G#m",
"D#m",
"A#m",
"E#m"};
154 return (smf_event_decode_textual(event,
"Text"));
157 return (smf_event_decode_textual(event,
"Copyright"));
160 return (smf_event_decode_textual(event,
"Sequence/Track Name"));
163 return (smf_event_decode_textual(event,
"Instrument"));
166 return (smf_event_decode_textual(event,
"Lyric"));
169 return (smf_event_decode_textual(event,
"Marker"));
172 return (smf_event_decode_textual(event,
"Cue Point"));
175 return (smf_event_decode_textual(event,
"Program Name"));
178 return (smf_event_decode_textual(event,
"Device (Port) Name"));
184 buf = malloc(BUFFER_SIZE);
186 g_critical(
"smf_event_decode_metadata: malloc failed.");
192 off += snprintf(buf + off, BUFFER_SIZE - off,
"Sequence number");
198 g_critical(
"smf_event_decode_metadata: truncated MIDI message.");
202 off += snprintf(buf + off, BUFFER_SIZE - off,
"Channel Prefix: %d", event->
midi_buffer[3]);
207 g_critical(
"smf_event_decode_metadata: truncated MIDI message.");
211 off += snprintf(buf + off, BUFFER_SIZE - off,
"MIDI Port: %d", event->
midi_buffer[3]);
215 off += snprintf(buf + off, BUFFER_SIZE - off,
"End Of Track");
220 g_critical(
"smf_event_decode_metadata: truncated MIDI message.");
224 mspqn = (
event->midi_buffer[3] << 16) + (event->
midi_buffer[4] << 8) +
event->midi_buffer[5];
226 off += snprintf(buf + off, BUFFER_SIZE - off,
"Tempo: %d microseconds per quarter note, %.2f BPM",
227 mspqn, 60000000.0 / (
double)mspqn);
231 off += snprintf(buf + off, BUFFER_SIZE - off,
"SMPTE Offset");
236 g_critical(
"smf_event_decode_metadata: truncated MIDI message.");
240 off += snprintf(buf + off, BUFFER_SIZE - off,
241 "Time Signature: %d/%d, %d clocks per click, %d notated 32nd notes per quarter note",
248 g_critical(
"smf_event_decode_metadata: truncated MIDI message.");
252 flats =
event->midi_buffer[3];
253 isminor =
event->midi_buffer[4];
255 if (isminor != 0 && isminor != 1) {
256 g_critical(
"smf_event_decode_metadata: last byte of the Key Signature event has invalid value %d.", isminor);
260 off += snprintf(buf + off, BUFFER_SIZE - off,
"Key Signature: ");
262 if (flats > 8 && flats < 248) {
263 off += snprintf(buf + off, BUFFER_SIZE - off,
"%d %s, %s key", abs((int8_t)flats),
264 flats > 127 ?
"flats" :
"sharps", isminor ?
"minor" :
"major");
266 int i = (flats - 248) & 255;
268 assert(i >= 0 && i <
sizeof(minor_keys) /
sizeof(*minor_keys));
269 assert(i >= 0 && i <
sizeof(major_keys) /
sizeof(*major_keys));
272 off += snprintf(buf + off, BUFFER_SIZE - off,
"%s", minor_keys[i]);
274 off += snprintf(buf + off, BUFFER_SIZE - off,
"%s", major_keys[i]);
280 off += snprintf(buf + off, BUFFER_SIZE - off,
"Proprietary (aka Sequencer) Event, length %d",
297 smf_event_decode_system_realtime(
const smf_event_t *event)
305 g_critical(
"smf_event_decode_system_realtime: event length is not 1.");
309 buf = malloc(BUFFER_SIZE);
311 g_critical(
"smf_event_decode_system_realtime: malloc failed.");
317 off += snprintf(buf + off, BUFFER_SIZE - off,
"MIDI Clock (realtime)");
321 off += snprintf(buf + off, BUFFER_SIZE - off,
"Tick (realtime)");
325 off += snprintf(buf + off, BUFFER_SIZE - off,
"MIDI Start (realtime)");
329 off += snprintf(buf + off, BUFFER_SIZE - off,
"MIDI Continue (realtime)");
333 off += snprintf(buf + off, BUFFER_SIZE - off,
"MIDI Stop (realtime)");
337 off += snprintf(buf + off, BUFFER_SIZE - off,
"Active Sense (realtime)");
352 char *buf, manufacturer, subid, subid2;
357 g_critical(
"smf_event_decode_sysex: truncated MIDI message.");
361 buf = malloc(BUFFER_SIZE);
363 g_critical(
"smf_event_decode_sysex: malloc failed.");
367 manufacturer =
event->midi_buffer[1];
369 if (manufacturer == 0x7F) {
370 off += snprintf(buf + off, BUFFER_SIZE - off,
"SysEx, realtime, channel %d", event->
midi_buffer[2]);
371 }
else if (manufacturer == 0x7E) {
372 off += snprintf(buf + off, BUFFER_SIZE - off,
"SysEx, non-realtime, channel %d", event->
midi_buffer[2]);
374 off += snprintf(buf + off, BUFFER_SIZE - off,
"SysEx, manufacturer 0x%x", manufacturer);
379 subid =
event->midi_buffer[3];
380 subid2 =
event->midi_buffer[4];
383 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump Header");
385 else if (subid == 0x02)
386 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump Data Packet");
388 else if (subid == 0x03)
389 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump Request");
391 else if (subid == 0x04 && subid2 == 0x01)
392 off += snprintf(buf + off, BUFFER_SIZE - off,
", Master Volume");
394 else if (subid == 0x05 && subid2 == 0x01)
395 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump Loop Point Retransmit");
397 else if (subid == 0x05 && subid2 == 0x02)
398 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump Loop Point Request");
400 else if (subid == 0x06 && subid2 == 0x01)
401 off += snprintf(buf + off, BUFFER_SIZE - off,
", Identity Request");
403 else if (subid == 0x06 && subid2 == 0x02)
404 off += snprintf(buf + off, BUFFER_SIZE - off,
", Identity Reply");
406 else if (subid == 0x08 && subid2 == 0x00)
407 off += snprintf(buf + off, BUFFER_SIZE - off,
", Bulk Tuning Dump Request");
409 else if (subid == 0x08 && subid2 == 0x01)
410 off += snprintf(buf + off, BUFFER_SIZE - off,
", Bulk Tuning Dump");
412 else if (subid == 0x08 && subid2 == 0x02)
413 off += snprintf(buf + off, BUFFER_SIZE - off,
", Single Note Tuning Change");
415 else if (subid == 0x08 && subid2 == 0x03)
416 off += snprintf(buf + off, BUFFER_SIZE - off,
", Bulk Tuning Dump Request (Bank)");
418 else if (subid == 0x08 && subid2 == 0x04)
419 off += snprintf(buf + off, BUFFER_SIZE - off,
", Key Based Tuning Dump");
421 else if (subid == 0x08 && subid2 == 0x05)
422 off += snprintf(buf + off, BUFFER_SIZE - off,
", Scale/Octave Tuning Dump, 1 byte format");
424 else if (subid == 0x08 && subid2 == 0x06)
425 off += snprintf(buf + off, BUFFER_SIZE - off,
", Scale/Octave Tuning Dump, 2 byte format");
427 else if (subid == 0x08 && subid2 == 0x07)
428 off += snprintf(buf + off, BUFFER_SIZE - off,
", Single Note Tuning Change (Bank)");
430 else if (subid == 0x09)
431 off += snprintf(buf + off, BUFFER_SIZE - off,
", General MIDI %s", subid2 == 0 ?
"disable" :
"enable");
433 else if (subid == 0x7C)
434 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump Wait");
436 else if (subid == 0x7D)
437 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump Cancel");
439 else if (subid == 0x7E)
440 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump NAK");
442 else if (subid == 0x7F)
443 off += snprintf(buf + off, BUFFER_SIZE - off,
", Sample Dump ACK");
446 off += snprintf(buf + off, BUFFER_SIZE - off,
", Unknown");
452 smf_event_decode_system_common(
const smf_event_t *event)
460 return (smf_event_decode_sysex(event));
462 buf = malloc(BUFFER_SIZE);
464 g_critical(
"smf_event_decode_system_realtime: malloc failed.");
470 off += snprintf(buf + off, BUFFER_SIZE - off,
"MTC Quarter Frame");
474 off += snprintf(buf + off, BUFFER_SIZE - off,
"Song Position Pointer");
478 off += snprintf(buf + off, BUFFER_SIZE - off,
"Song Select");
482 off += snprintf(buf + off, BUFFER_SIZE - off,
"Tune Request");
494 note_from_int(
char *buf,
int note_number)
497 char *names[] = {
"C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#",
"A",
"A#",
"B"};
499 octave = note_number / 12 - 1;
500 note = note_number % 12;
502 sprintf(buf,
"%s%d", names[note], octave);
516 int off = 0, channel;
520 return (smf_event_decode_metadata(event));
523 return (smf_event_decode_system_realtime(event));
526 return (smf_event_decode_system_common(event));
529 g_critical(
"smf_event_decode: incorrect MIDI message length.");
533 buf = malloc(BUFFER_SIZE);
535 g_critical(
"smf_event_decode: malloc failed.");
540 channel = (
event->midi_buffer[0] & 0x0F) + 1;
545 off += snprintf(buf + off, BUFFER_SIZE - off,
"Note Off, channel %d, note %s, velocity %d",
551 off += snprintf(buf + off, BUFFER_SIZE - off,
"Note On, channel %d, note %s, velocity %d",
557 off += snprintf(buf + off, BUFFER_SIZE - off,
"Aftertouch, channel %d, note %s, pressure %d",
562 off += snprintf(buf + off, BUFFER_SIZE - off,
"Controller, channel %d, controller %d, value %d",
567 off += snprintf(buf + off, BUFFER_SIZE - off,
"Program Change, channel %d, controller %d",
572 off += snprintf(buf + off, BUFFER_SIZE - off,
"Channel Pressure, channel %d, pressure %d",
577 off += snprintf(buf + off, BUFFER_SIZE - off,
"Pitch Wheel, channel %d, value %d",
603 buf = malloc(BUFFER_SIZE);
605 g_critical(
"smf_event_decode: malloc failed.");
609 off += snprintf(buf + off, BUFFER_SIZE - off,
"format: %d ", smf->
format);
613 off += snprintf(buf + off, BUFFER_SIZE - off,
"(single track)");
617 off += snprintf(buf + off, BUFFER_SIZE - off,
"(several simultaneous tracks)");
621 off += snprintf(buf + off, BUFFER_SIZE - off,
"(several independent tracks)");
625 off += snprintf(buf + off, BUFFER_SIZE - off,
"(INVALID FORMAT)");
629 off += snprintf(buf + off, BUFFER_SIZE - off,
"; number of tracks: %d", smf->
number_of_tracks);
632 off += snprintf(buf + off, BUFFER_SIZE - off,
"; division: %d PPQN", smf->
ppqn);
char * smf_decode(const smf_t *smf)
int smf_event_is_system_common(const smf_event_t *event)
unsigned char * midi_buffer
Pointer to the buffer containing MIDI message.
Represents a "song", that is, collection of one or more tracks.
int ppqn
These fields are extracted from "division" field of MThd header.
int smf_event_is_sysex(const smf_event_t *event)
int smf_event_is_system_realtime(const smf_event_t *event)
int smf_event_length_is_valid(const smf_event_t *event)
int midi_buffer_length
Length of the MIDI message in the buffer, in bytes.
Public interface declaration for libsmf, Standard MIDI File format library.
char * smf_event_extract_text(const smf_event_t *event) WARN_UNUSED_RESULT
Extracts text from "textual metaevents", such as Text or Lyric.
Represents a single MIDI event or metaevent.
int smf_event_is_metadata(const smf_event_t *event)
char * smf_event_decode(const smf_event_t *event)