smflite

annotate src/smf_decode.c @ 0:4264abea8b06

smf-lite initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 26 Jan 2012 11:25:11 +0200
parents
children
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