1 1.34 rillig /* $NetBSD: midiplay.c,v 1.34 2021/11/27 22:16:41 rillig Exp $ */ 2 1.1 augustss 3 1.1 augustss /* 4 1.16 augustss * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. 5 1.1 augustss * All rights reserved. 6 1.1 augustss * 7 1.8 augustss * This code is derived from software contributed to The NetBSD Foundation 8 1.20 salo * by Lennart Augustsson (augustss (at) NetBSD.org). 9 1.1 augustss * 10 1.1 augustss * Redistribution and use in source and binary forms, with or without 11 1.1 augustss * modification, are permitted provided that the following conditions 12 1.1 augustss * are met: 13 1.1 augustss * 1. Redistributions of source code must retain the above copyright 14 1.1 augustss * notice, this list of conditions and the following disclaimer. 15 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 augustss * notice, this list of conditions and the following disclaimer in the 17 1.1 augustss * documentation and/or other materials provided with the distribution. 18 1.1 augustss * 19 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 augustss * POSSIBILITY OF SUCH DAMAGE. 30 1.1 augustss */ 31 1.19 agc #include <sys/cdefs.h> 32 1.19 agc 33 1.19 agc #ifndef lint 34 1.34 rillig __RCSID("$NetBSD: midiplay.c,v 1.34 2021/11/27 22:16:41 rillig Exp $"); 35 1.19 agc #endif 36 1.19 agc 37 1.1 augustss 38 1.1 augustss #include <stdio.h> 39 1.1 augustss #include <stdlib.h> 40 1.1 augustss #include <fcntl.h> 41 1.1 augustss #include <err.h> 42 1.29 jmcneill #include <errno.h> 43 1.29 jmcneill #include <limits.h> 44 1.1 augustss #include <unistd.h> 45 1.1 augustss #include <string.h> 46 1.1 augustss #include <sys/types.h> 47 1.1 augustss #include <sys/stat.h> 48 1.1 augustss #include <sys/ioctl.h> 49 1.1 augustss #include <sys/midiio.h> 50 1.1 augustss 51 1.1 augustss #define DEVMUSIC "/dev/music" 52 1.1 augustss 53 1.1 augustss struct track { 54 1.23 chap struct track *indirect; /* for fast swaps in heap code */ 55 1.1 augustss u_char *start, *end; 56 1.23 chap u_long delta; 57 1.1 augustss u_char status; 58 1.1 augustss }; 59 1.1 augustss 60 1.1 augustss #define MIDI_META 0xff 61 1.1 augustss 62 1.1 augustss #define META_SEQNO 0x00 63 1.1 augustss #define META_TEXT 0x01 64 1.1 augustss #define META_COPYRIGHT 0x02 65 1.1 augustss #define META_TRACK 0x03 66 1.1 augustss #define META_INSTRUMENT 0x04 67 1.1 augustss #define META_LYRIC 0x05 68 1.1 augustss #define META_MARKER 0x06 69 1.1 augustss #define META_CUE 0x07 70 1.1 augustss #define META_CHPREFIX 0x20 71 1.1 augustss #define META_EOT 0x2f 72 1.1 augustss #define META_SET_TEMPO 0x51 73 1.1 augustss #define META_KEY 0x59 74 1.1 augustss #define META_SMPTE 0x54 75 1.1 augustss #define META_TIMESIGN 0x58 76 1.1 augustss 77 1.28 christos static const char *metanames[] = { 78 1.28 christos "", "Text", "Copyright", "Track", "Instrument", 79 1.1 augustss "Lyric", "Marker", "Cue", 80 1.1 augustss }; 81 1.1 augustss 82 1.28 christos static int midi_lengths[] = { 2, 2, 2, 2, 1, 1, 2, 0 }; 83 1.1 augustss /* Number of bytes in a MIDI command */ 84 1.1 augustss #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7]) 85 1.1 augustss 86 1.28 christos #define SEQ_MK_SYSEX0(_dev,...) \ 87 1.28 christos SEQ_MK_EVENT(sysex, 0x94, .device=(_dev), .buffer={__VA_ARGS__}) 88 1.28 christos 89 1.28 christos 90 1.28 christos static void usage(void); 91 1.28 christos static void send_event(seq_event_t *); 92 1.28 christos static void dometa(u_int, u_char *, u_int); 93 1.28 christos #if 0 94 1.28 christos static void midireset(void); 95 1.28 christos #endif 96 1.28 christos static void send_sysex(u_char *, u_int); 97 1.28 christos static u_long getvar(struct track *); 98 1.28 christos static u_long getlen(struct track *); 99 1.28 christos static void playfile(FILE *, const char *); 100 1.28 christos static void playdata(u_char *, u_int, const char *); 101 1.28 christos 102 1.28 christos static void Heapify(struct track *, int, int); 103 1.28 christos static void BuildHeap(struct track *, int); 104 1.28 christos static int ShrinkHeap(struct track *, int); 105 1.23 chap 106 1.23 chap /* 107 1.23 chap * This sample plays at an apparent tempo of 120 bpm when the BASETEMPO is 150 108 1.23 chap * bpm, because the quavers are 5 divisions (4 on 1 off) rather than 4 total. 109 1.23 chap */ 110 1.28 christos #define P(c) 1, 0x90, c, 0x7f, 4, 0x80, c, 0 111 1.28 christos #define PL(c) 1, 0x90, c, 0x7f, 8, 0x80, c, 0 112 1.1 augustss #define C 0x3c 113 1.1 augustss #define D 0x3e 114 1.1 augustss #define E 0x40 115 1.1 augustss #define F 0x41 116 1.1 augustss 117 1.28 christos static u_char sample[] = { 118 1.28 christos 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 8, 119 1.28 christos 'M', 'T', 'r', 'k', 0, 0, 0, 4+13*8, 120 1.28 christos P(C), P(C), P(C), P(E), P(D), P(D), P(D), 121 1.1 augustss P(F), P(E), P(E), P(D), P(D), PL(C), 122 1.1 augustss 0, 0xff, 0x2f, 0 123 1.1 augustss }; 124 1.1 augustss #undef P 125 1.1 augustss #undef PL 126 1.1 augustss #undef C 127 1.1 augustss #undef D 128 1.1 augustss #undef E 129 1.1 augustss #undef F 130 1.1 augustss 131 1.31 mrg static u_char silence_sample[] = { 132 1.31 mrg 'M', 'T', 'h', 'd', 0, 0, 0, 6, 0, 1, 0, 1, 0, 8, 133 1.31 mrg 'M', 'T', 'r', 'k', 0, 0, 0, 8, 134 1.31 mrg 0, 0xb0, 0x78, 0x00, 135 1.31 mrg 0, 0xff, 0x2f, 0 136 1.31 mrg }; 137 1.31 mrg 138 1.1 augustss #define MARK_HEADER "MThd" 139 1.1 augustss #define MARK_TRACK "MTrk" 140 1.1 augustss #define MARK_LEN 4 141 1.1 augustss 142 1.18 augustss #define RMID_SIG "RIFF" 143 1.18 augustss #define RMID_MIDI_ID "RMID" 144 1.18 augustss #define RMID_DATA_ID "data" 145 1.18 augustss 146 1.1 augustss #define SIZE_LEN 4 147 1.1 augustss #define HEADER_LEN 6 148 1.1 augustss 149 1.1 augustss #define GET8(p) ((p)[0]) 150 1.1 augustss #define GET16(p) (((p)[0] << 8) | (p)[1]) 151 1.1 augustss #define GET24(p) (((p)[0] << 16) | ((p)[1] << 8) | (p)[2]) 152 1.1 augustss #define GET32(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3]) 153 1.18 augustss #define GET32_LE(p) (((p)[3] << 24) | ((p)[2] << 16) | ((p)[1] << 8) | (p)[0]) 154 1.1 augustss 155 1.28 christos static void __attribute__((__noreturn__)) 156 1.16 augustss usage(void) 157 1.1 augustss { 158 1.32 wiz fprintf(stderr, "usage: %s [-lmqsvx] [-d devno] [-f file] " 159 1.32 wiz "[-p pgm] [-t tempo] [file ...]\n", 160 1.12 cgd getprogname()); 161 1.1 augustss exit(1); 162 1.1 augustss } 163 1.1 augustss 164 1.28 christos static int showmeta = 0; 165 1.28 christos static int verbose = 0; 166 1.23 chap #define BASETEMPO 400000 /* us/beat(=24 clks or qn) (150 bpm) */ 167 1.28 christos static u_int tempo_set = 0; 168 1.28 christos static u_int tempo_abs = 0; 169 1.28 christos static u_int ttempo = 100; 170 1.28 christos static int unit = 0; 171 1.28 christos static int play = 1; 172 1.28 christos static int fd = -1; 173 1.28 christos static int sameprogram = 0; 174 1.28 christos static int insysex = 0; 175 1.28 christos static int svsysex = 0; /* number of sysex bytes saved internally */ 176 1.1 augustss 177 1.28 christos static void 178 1.23 chap send_event(seq_event_t *ev) 179 1.1 augustss { 180 1.3 augustss /* 181 1.3 augustss printf("%02x %02x %02x %02x %02x %02x %02x %02x\n", 182 1.28 christos ev->arr[0], ev->arr[1], ev->arr[2], ev->arr[3], 183 1.3 augustss ev->arr[4], ev->arr[5], ev->arr[6], ev->arr[7]); 184 1.3 augustss */ 185 1.3 augustss if (play) 186 1.3 augustss write(fd, ev, sizeof *ev); 187 1.1 augustss } 188 1.1 augustss 189 1.28 christos static u_long 190 1.16 augustss getvar(struct track *tp) 191 1.1 augustss { 192 1.1 augustss u_long r, c; 193 1.1 augustss 194 1.1 augustss r = 0; 195 1.1 augustss do { 196 1.1 augustss c = *tp->start++; 197 1.1 augustss r = (r << 7) | (c & 0x7f); 198 1.1 augustss } while ((c & 0x80) && tp->start < tp->end); 199 1.23 chap return r; 200 1.23 chap } 201 1.23 chap 202 1.28 christos static u_long 203 1.23 chap getlen(struct track *tp) 204 1.23 chap { 205 1.23 chap u_long len; 206 1.23 chap len = getvar(tp); 207 1.23 chap if (tp->start + len > tp->end) 208 1.23 chap errx(1, "bogus item length exceeds remaining track size"); 209 1.23 chap return len; 210 1.1 augustss } 211 1.1 augustss 212 1.28 christos static void 213 1.16 augustss dometa(u_int meta, u_char *p, u_int len) 214 1.1 augustss { 215 1.23 chap static char const * const keys[] = { 216 1.23 chap "Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F", 217 1.23 chap "C", 218 1.23 chap "G", "D", "A", "E", "B", "F#", "C#", 219 1.23 chap "G#", "D#", "A#" /* for minors */ 220 1.23 chap }; 221 1.23 chap seq_event_t ev; 222 1.23 chap uint32_t usperbeat; 223 1.28 christos 224 1.1 augustss switch (meta) { 225 1.1 augustss case META_TEXT: 226 1.1 augustss case META_COPYRIGHT: 227 1.1 augustss case META_TRACK: 228 1.1 augustss case META_INSTRUMENT: 229 1.1 augustss case META_LYRIC: 230 1.1 augustss case META_MARKER: 231 1.1 augustss case META_CUE: 232 1.1 augustss if (showmeta) { 233 1.1 augustss printf("%s: ", metanames[meta]); 234 1.1 augustss fwrite(p, len, 1, stdout); 235 1.1 augustss printf("\n"); 236 1.1 augustss } 237 1.1 augustss break; 238 1.1 augustss case META_SET_TEMPO: 239 1.23 chap usperbeat = GET24(p); 240 1.23 chap ev = SEQ_MK_TIMING(TEMPO, 241 1.23 chap .bpm=(60000000. / usperbeat) * (ttempo / 100.) + 0.5); 242 1.1 augustss if (showmeta) 243 1.23 chap printf("Tempo: %u us/'beat'(24 midiclks)" 244 1.23 chap " at %u%%; adjusted bpm = %u\n", 245 1.23 chap usperbeat, ttempo, ev.t_TEMPO.bpm); 246 1.23 chap if (tempo_abs) 247 1.23 chap warnx("tempo event ignored" 248 1.23 chap " in absolute-timed MIDI file"); 249 1.23 chap else { 250 1.23 chap send_event(&ev); 251 1.23 chap if (!tempo_set) { 252 1.23 chap tempo_set = 1; 253 1.23 chap send_event(&SEQ_MK_TIMING(START)); 254 1.23 chap } 255 1.23 chap } 256 1.1 augustss break; 257 1.1 augustss case META_TIMESIGN: 258 1.23 chap ev = SEQ_MK_TIMING(TIMESIG, 259 1.23 chap .numerator=p[0], .lg2denom=p[1], 260 1.23 chap .clks_per_click=p[2], .dsq_per_24clks=p[3]); 261 1.1 augustss if (showmeta) { 262 1.23 chap printf("Time signature: %d/%d." 263 1.23 chap " Click every %d midiclk%s" 264 1.23 chap " (24 midiclks = %d 32nd note%s)\n", 265 1.23 chap ev.t_TIMESIG.numerator, 266 1.23 chap 1 << ev.t_TIMESIG.lg2denom, 267 1.23 chap ev.t_TIMESIG.clks_per_click, 268 1.23 chap 1 == ev.t_TIMESIG.clks_per_click ? "" : "s", 269 1.23 chap ev.t_TIMESIG.dsq_per_24clks, 270 1.23 chap 1 == ev.t_TIMESIG.dsq_per_24clks ? "" : "s"); 271 1.1 augustss } 272 1.23 chap /* send_event(&ev); not implemented in sequencer */ 273 1.1 augustss break; 274 1.1 augustss case META_KEY: 275 1.1 augustss if (showmeta) 276 1.23 chap printf("Key: %s %s\n", 277 1.23 chap keys[((char)p[0]) + p[1] ? 10 : 7], 278 1.1 augustss p[1] ? "minor" : "major"); 279 1.1 augustss break; 280 1.1 augustss default: 281 1.1 augustss break; 282 1.1 augustss } 283 1.1 augustss } 284 1.1 augustss 285 1.28 christos #if 0 286 1.28 christos static void 287 1.16 augustss midireset(void) 288 1.1 augustss { 289 1.1 augustss /* General MIDI reset sequence */ 290 1.28 christos send_event(&SEQ_MK_SYSEX0(unit, 0x7e, 0x7f, 0x09, 0x01, 0xf7, 0xff)); 291 1.6 augustss } 292 1.28 christos #endif 293 1.6 augustss 294 1.6 augustss #define SYSEX_CHUNK 6 295 1.28 christos static void 296 1.16 augustss send_sysex(u_char *p, u_int l) 297 1.6 augustss { 298 1.23 chap seq_event_t event; 299 1.23 chap static u_char bf[6]; 300 1.28 christos 301 1.28 christos if (0 == l) { 302 1.23 chap warnx("zero-length system-exclusive event"); 303 1.23 chap return; 304 1.23 chap } 305 1.28 christos 306 1.23 chap /* 307 1.23 chap * This block is needed only to handle the possibility that a sysex 308 1.23 chap * message is broken into multiple events in a MIDI file that do not 309 1.23 chap * have length six; the /dev/music sequencer assumes a sysex message is 310 1.23 chap * finished with the first SYSEX event carrying fewer than six bytes, 311 1.23 chap * even if the last is not MIDI_SYSEX_END. So, we need to be careful 312 1.23 chap * not to send a short sysex event until we have seen the end byte. 313 1.23 chap * Instead, save some straggling bytes in bf, and send when we have a 314 1.23 chap * full six (or an end byte). Note bf/saved/insysex should be per- 315 1.23 chap * device, if we supported output to more than one device at a time. 316 1.23 chap */ 317 1.28 christos if (svsysex > 0) { 318 1.28 christos if (l > sizeof bf - svsysex) { 319 1.23 chap memcpy(bf + svsysex, p, sizeof bf - svsysex); 320 1.23 chap l -= sizeof bf - svsysex; 321 1.23 chap p += sizeof bf - svsysex; 322 1.28 christos send_event(&SEQ_MK_SYSEX0(unit, 323 1.28 christos bf[0], bf[1], bf[2], bf[3], bf[4], bf[5])); 324 1.23 chap svsysex = 0; 325 1.23 chap } else { 326 1.23 chap memcpy(bf + svsysex, p, l); 327 1.23 chap svsysex += l; 328 1.23 chap p += l; 329 1.28 christos if (MIDI_SYSEX_END == bf[svsysex-1]) { 330 1.23 chap event = SEQ_MK_SYSEX(unit); 331 1.23 chap memcpy(event.sysex.buffer, bf, svsysex); 332 1.23 chap send_event(&event); 333 1.23 chap svsysex = insysex = 0; 334 1.23 chap } else 335 1.23 chap insysex = 1; 336 1.23 chap return; 337 1.23 chap } 338 1.23 chap } 339 1.28 christos 340 1.23 chap /* 341 1.23 chap * l > 0. May as well test now whether we will be left 'insysex' 342 1.23 chap * after processing this event. 343 1.28 christos */ 344 1.28 christos insysex = (MIDI_SYSEX_END != p[l-1]); 345 1.28 christos 346 1.23 chap /* 347 1.23 chap * If not for multi-event sysexes and chunk-size weirdness, this 348 1.23 chap * function could pretty much start here. :) 349 1.23 chap */ 350 1.28 christos while (l >= SYSEX_CHUNK) { 351 1.28 christos send_event(&SEQ_MK_SYSEX0(unit, p[0], p[1], p[2], p[3], p[4], p[5])); 352 1.23 chap p += SYSEX_CHUNK; 353 1.23 chap l -= SYSEX_CHUNK; 354 1.23 chap } 355 1.28 christos if (l > 0) { 356 1.28 christos if (insysex) { 357 1.23 chap memcpy(bf, p, l); 358 1.23 chap svsysex = l; 359 1.23 chap } else { /* a <6 byte chunk is ok if it's REALLY the end */ 360 1.23 chap event = SEQ_MK_SYSEX(unit); 361 1.23 chap memcpy(event.sysex.buffer, p, l); 362 1.23 chap send_event(&event); 363 1.23 chap } 364 1.23 chap } 365 1.1 augustss } 366 1.1 augustss 367 1.28 christos static void 368 1.27 lukem playfile(FILE *f, const char *name) 369 1.1 augustss { 370 1.21 itojun u_char *buf, *nbuf; 371 1.1 augustss u_int tot, n, size, nread; 372 1.1 augustss 373 1.28 christos /* 374 1.1 augustss * We need to read the whole file into memory for easy processing. 375 1.1 augustss * Using mmap() would be nice, but some file systems do not support 376 1.1 augustss * it, nor does reading from e.g. a pipe. The latter also precludes 377 1.1 augustss * finding out the file size without reading it. 378 1.1 augustss */ 379 1.1 augustss size = 1000; 380 1.1 augustss buf = malloc(size); 381 1.1 augustss if (buf == 0) 382 1.17 itojun errx(1, "malloc() failed"); 383 1.1 augustss nread = size; 384 1.1 augustss tot = 0; 385 1.1 augustss for (;;) { 386 1.1 augustss n = fread(buf + tot, 1, nread, f); 387 1.1 augustss tot += n; 388 1.1 augustss if (n < nread) 389 1.1 augustss break; 390 1.1 augustss /* There must be more to read. */ 391 1.1 augustss nread = size; 392 1.21 itojun nbuf = realloc(buf, size * 2); 393 1.21 itojun if (nbuf == NULL) 394 1.21 itojun errx(1, "realloc() failed"); 395 1.21 itojun buf = nbuf; 396 1.1 augustss size *= 2; 397 1.1 augustss } 398 1.1 augustss playdata(buf, tot, name); 399 1.1 augustss free(buf); 400 1.1 augustss } 401 1.1 augustss 402 1.28 christos static void 403 1.27 lukem playdata(u_char *buf, u_int tot, const char *name) 404 1.1 augustss { 405 1.23 chap int format, ntrks, divfmt, ticks, t; 406 1.1 augustss u_int len, mlen, status, chan; 407 1.1 augustss u_char *p, *end, byte, meta, *msg; 408 1.29 jmcneill struct synth_info info; 409 1.1 augustss struct track *tracks; 410 1.1 augustss struct track *tp; 411 1.1 augustss 412 1.29 jmcneill /* verify that the requested midi unit exists */ 413 1.29 jmcneill info.device = unit; 414 1.30 mrg if (play && ioctl(fd, SEQUENCER_INFO, &info) < 0) 415 1.29 jmcneill err(1, "ioctl(SEQUENCER_INFO) failed"); 416 1.29 jmcneill 417 1.1 augustss end = buf + tot; 418 1.31 mrg if (verbose) { 419 1.31 mrg printf("Playing %s (%d bytes)", name, tot); 420 1.31 mrg if (play) 421 1.31 mrg printf(" on %s (unit %d)...", info.name, info.device); 422 1.31 mrg puts("\n"); 423 1.31 mrg } 424 1.1 augustss 425 1.18 augustss if (tot < MARK_LEN + 4) { 426 1.18 augustss warnx("Not a MIDI file, too short"); 427 1.18 augustss return; 428 1.18 augustss } 429 1.18 augustss 430 1.18 augustss if (memcmp(buf, RMID_SIG, MARK_LEN) == 0) { 431 1.18 augustss u_char *eod; 432 1.18 augustss /* Detected a RMID file, let's just check if it's 433 1.18 augustss * a MIDI file */ 434 1.27 lukem if ((u_int)GET32_LE(buf + MARK_LEN) != tot - 8) { 435 1.18 augustss warnx("Not a RMID file, bad header"); 436 1.18 augustss return; 437 1.18 augustss } 438 1.18 augustss 439 1.18 augustss buf += MARK_LEN + 4; 440 1.18 augustss if (memcmp(buf, RMID_MIDI_ID, MARK_LEN) != 0) { 441 1.18 augustss warnx("Not a RMID file, bad ID"); 442 1.18 augustss return; 443 1.18 augustss } 444 1.18 augustss 445 1.18 augustss /* Now look for the 'data' chunk, which contains 446 1.18 augustss * MIDI data */ 447 1.18 augustss buf += MARK_LEN; 448 1.18 augustss 449 1.18 augustss /* Test against end-8 since we must have at least 8 bytes 450 1.18 augustss * left to read */ 451 1.18 augustss while(buf < end-8 && memcmp(buf, RMID_DATA_ID, MARK_LEN)) 452 1.18 augustss buf += GET32_LE(buf+4) + 8; /* MARK_LEN + 4 */ 453 1.18 augustss 454 1.18 augustss if (buf >= end-8) { 455 1.18 augustss warnx("Not a valid RMID file, no data chunk"); 456 1.18 augustss return; 457 1.18 augustss } 458 1.18 augustss 459 1.18 augustss buf += MARK_LEN; /* "data" */ 460 1.18 augustss eod = buf + 4 + GET32_LE(buf); 461 1.18 augustss if (eod >= end) { 462 1.18 augustss warnx("Not a valid RMID file, bad data chunk size"); 463 1.18 augustss return; 464 1.18 augustss } 465 1.18 augustss 466 1.18 augustss end = eod; 467 1.18 augustss buf += 4; 468 1.18 augustss } 469 1.18 augustss 470 1.1 augustss if (memcmp(buf, MARK_HEADER, MARK_LEN) != 0) { 471 1.17 itojun warnx("Not a MIDI file, missing header"); 472 1.1 augustss return; 473 1.1 augustss } 474 1.18 augustss 475 1.1 augustss if (GET32(buf + MARK_LEN) != HEADER_LEN) { 476 1.17 itojun warnx("Not a MIDI file, bad header"); 477 1.1 augustss return; 478 1.1 augustss } 479 1.1 augustss format = GET16(buf + MARK_LEN + SIZE_LEN); 480 1.1 augustss ntrks = GET16(buf + MARK_LEN + SIZE_LEN + 2); 481 1.1 augustss divfmt = GET8(buf + MARK_LEN + SIZE_LEN + 4); 482 1.1 augustss ticks = GET8(buf + MARK_LEN + SIZE_LEN + 5); 483 1.1 augustss p = buf + MARK_LEN + SIZE_LEN + HEADER_LEN; 484 1.23 chap /* 485 1.23 chap * Set the timebase (or timebase and tempo, for absolute-timed files). 486 1.23 chap * PORTABILITY: some sequencers actually check the timebase against 487 1.23 chap * available timing sources and may adjust it accordingly (storing a 488 1.23 chap * new value in the ioctl arg) which would require us to compensate 489 1.23 chap * somehow. That possibility is ignored for now, as NetBSD's sequencer 490 1.23 chap * currently synthesizes all timebases, for better or worse, from the 491 1.23 chap * system clock. 492 1.23 chap * 493 1.23 chap * For a non-absolute file, if timebase is set to the file's divisions 494 1.23 chap * value, and tempo set in the obvious way, then the timing deltas in 495 1.23 chap * the MTrks require no scaling. A downside to this approach is that 496 1.23 chap * the sequencer API wants tempo in (integer) beats per minute, which 497 1.23 chap * limits how finely tempo can be specified. That might be got around 498 1.23 chap * in some cases by frobbing tempo and timebase more obscurely, but this 499 1.23 chap * player is meant to be simple and clear. 500 1.23 chap */ 501 1.30 mrg if (!play) 502 1.30 mrg /* do nothing */; 503 1.30 mrg else if ((divfmt & 0x80) == 0) { 504 1.1 augustss ticks |= divfmt << 8; 505 1.23 chap if (ioctl(fd, SEQUENCER_TMR_TIMEBASE, &(int){ticks}) < 0) 506 1.23 chap err(1, "SEQUENCER_TMR_TIMEBASE"); 507 1.23 chap } else { 508 1.23 chap tempo_abs = tempo_set = 1; 509 1.23 chap divfmt = -(int8_t)divfmt; 510 1.23 chap /* 511 1.23 chap * divfmt is frames per second; multiplying by 60 to set tempo 512 1.23 chap * in frames per minute could exceed sequencer's (arbitrary) 513 1.23 chap * tempo limits, so factor 60 as 12*5, set tempo in frames per 514 1.23 chap * 12 seconds, and account for the 5 in timebase. 515 1.23 chap */ 516 1.23 chap send_event(&SEQ_MK_TIMING(TEMPO, 517 1.23 chap .bpm=(12*divfmt) * (ttempo/100.) + 0.5)); 518 1.23 chap if (ioctl(fd, SEQUENCER_TMR_TIMEBASE, &(int){5*ticks}) < 0) 519 1.23 chap err(1, "SEQUENCER_TMR_TIMEBASE"); 520 1.23 chap } 521 1.1 augustss if (verbose > 1) 522 1.23 chap printf(tempo_abs ? 523 1.23 chap "format=%d ntrks=%d abs fps=%u subdivs=%u\n" : 524 1.23 chap "format=%d ntrks=%d divisions=%u\n", 525 1.23 chap format, ntrks, tempo_abs ? divfmt : ticks, ticks); 526 1.1 augustss if (format != 0 && format != 1) { 527 1.17 itojun warnx("Cannot play MIDI file of type %d", format); 528 1.1 augustss return; 529 1.1 augustss } 530 1.1 augustss if (ntrks == 0) 531 1.1 augustss return; 532 1.1 augustss tracks = malloc(ntrks * sizeof(struct track)); 533 1.1 augustss if (tracks == NULL) 534 1.17 itojun errx(1, "malloc() tracks failed"); 535 1.28 christos for (t = 0; t < ntrks;) { 536 1.1 augustss if (p >= end - MARK_LEN - SIZE_LEN) { 537 1.17 itojun warnx("Cannot find track %d", t); 538 1.6 augustss goto ret; 539 1.1 augustss } 540 1.1 augustss len = GET32(p + MARK_LEN); 541 1.1 augustss if (len > 1000000) { /* a safe guard */ 542 1.17 itojun warnx("Crazy track length"); 543 1.6 augustss goto ret; 544 1.1 augustss } 545 1.1 augustss if (memcmp(p, MARK_TRACK, MARK_LEN) == 0) { 546 1.1 augustss tracks[t].start = p + MARK_LEN + SIZE_LEN; 547 1.1 augustss tracks[t].end = tracks[t].start + len; 548 1.23 chap tracks[t].delta = getvar(&tracks[t]); 549 1.23 chap tracks[t].indirect = &tracks[t]; /* -> self for now */ 550 1.1 augustss t++; 551 1.1 augustss } 552 1.1 augustss p += MARK_LEN + SIZE_LEN + len; 553 1.1 augustss } 554 1.1 augustss 555 1.23 chap /* 556 1.23 chap * Force every channel to the same patch if requested by the user. 557 1.1 augustss */ 558 1.11 augustss if (sameprogram) { 559 1.11 augustss for(t = 0; t < 16; t++) { 560 1.23 chap send_event(&SEQ_MK_CHN(PGM_CHANGE, .device=unit, 561 1.23 chap .channel=t, .program=sameprogram-1)); 562 1.10 augustss } 563 1.10 augustss } 564 1.28 christos /* 565 1.23 chap * Play MIDI events by selecting the track with the lowest 566 1.23 chap * delta. Execute the event, update the delta and repeat. 567 1.23 chap * 568 1.23 chap * The ticks variable is the number of ticks that make up a beat 569 1.23 chap * (beat: 24 MIDI clocks always, a quarter note by usual convention) 570 1.23 chap * and is used as a reference value for the delays between 571 1.1 augustss * the MIDI events. 572 1.1 augustss */ 573 1.23 chap BuildHeap(tracks, ntrks); /* tracks[0].indirect is always next */ 574 1.1 augustss for (;;) { 575 1.23 chap tp = tracks[0].indirect; 576 1.23 chap if ((verbose > 2 && tp->delta > 0) || verbose > 3) { 577 1.25 he printf("DELAY %4ld TRACK %2td%s", 578 1.25 he tp->delta, tp - tracks, verbose>3?" ":"\n"); 579 1.1 augustss fflush(stdout); 580 1.1 augustss } 581 1.23 chap if (tp->delta > 0) { 582 1.23 chap if (!tempo_set) { 583 1.23 chap if (verbose || showmeta) 584 1.23 chap printf("No initial tempo;" 585 1.23 chap " defaulting:\n"); 586 1.23 chap dometa(META_SET_TEMPO, (u_char[]){ 587 1.23 chap BASETEMPO >> 16, 588 1.23 chap (BASETEMPO >> 8) & 0xff, 589 1.23 chap BASETEMPO & 0xff}, 590 1.23 chap 3); 591 1.1 augustss } 592 1.23 chap send_event(&SEQ_MK_TIMING(WAIT_REL, 593 1.23 chap .divisions=tp->delta)); 594 1.1 augustss } 595 1.1 augustss byte = *tp->start++; 596 1.1 augustss if (byte == MIDI_META) { 597 1.1 augustss meta = *tp->start++; 598 1.23 chap mlen = getlen(tp); 599 1.23 chap if (verbose > 3) 600 1.1 augustss printf("META %02x (%d)\n", meta, mlen); 601 1.1 augustss dometa(meta, tp->start, mlen); 602 1.1 augustss tp->start += mlen; 603 1.1 augustss } else { 604 1.1 augustss if (MIDI_IS_STATUS(byte)) 605 1.1 augustss tp->status = byte; 606 1.4 augustss else 607 1.4 augustss tp->start--; 608 1.1 augustss mlen = MIDI_LENGTH(tp->status); 609 1.3 augustss msg = tp->start; 610 1.23 chap if (verbose > 3) { 611 1.3 augustss if (mlen == 1) 612 1.3 augustss printf("MIDI %02x (%d) %02x\n", 613 1.3 augustss tp->status, mlen, msg[0]); 614 1.28 christos else 615 1.3 augustss printf("MIDI %02x (%d) %02x %02x\n", 616 1.3 augustss tp->status, mlen, msg[0], msg[1]); 617 1.3 augustss } 618 1.23 chap if (insysex && tp->status != MIDI_SYSEX_END) { 619 1.23 chap warnx("incomplete system exclusive message" 620 1.23 chap " aborted"); 621 1.23 chap svsysex = insysex = 0; 622 1.23 chap } 623 1.1 augustss status = MIDI_GET_STATUS(tp->status); 624 1.1 augustss chan = MIDI_GET_CHAN(tp->status); 625 1.1 augustss switch (status) { 626 1.1 augustss case MIDI_NOTEOFF: 627 1.23 chap send_event(&SEQ_MK_CHN(NOTEOFF, .device=unit, 628 1.23 chap .channel=chan, .key=msg[0], .velocity=msg[1])); 629 1.23 chap break; 630 1.1 augustss case MIDI_NOTEON: 631 1.23 chap send_event(&SEQ_MK_CHN(NOTEON, .device=unit, 632 1.23 chap .channel=chan, .key=msg[0], .velocity=msg[1])); 633 1.23 chap break; 634 1.1 augustss case MIDI_KEY_PRESSURE: 635 1.23 chap send_event(&SEQ_MK_CHN(KEY_PRESSURE, 636 1.23 chap .device=unit, .channel=chan, 637 1.23 chap .key=msg[0], .pressure=msg[1])); 638 1.1 augustss break; 639 1.1 augustss case MIDI_CTL_CHANGE: 640 1.23 chap send_event(&SEQ_MK_CHN(CTL_CHANGE, 641 1.23 chap .device=unit, .channel=chan, 642 1.23 chap .controller=msg[0], .value=msg[1])); 643 1.1 augustss break; 644 1.1 augustss case MIDI_PGM_CHANGE: 645 1.23 chap if (!sameprogram) 646 1.23 chap send_event(&SEQ_MK_CHN(PGM_CHANGE, 647 1.23 chap .device=unit, .channel=chan, 648 1.23 chap .program=msg[0])); 649 1.23 chap break; 650 1.1 augustss case MIDI_CHN_PRESSURE: 651 1.23 chap send_event(&SEQ_MK_CHN(CHN_PRESSURE, 652 1.23 chap .device=unit, .channel=chan, .pressure=msg[0])); 653 1.1 augustss break; 654 1.1 augustss case MIDI_PITCH_BEND: 655 1.23 chap send_event(&SEQ_MK_CHN(PITCH_BEND, 656 1.23 chap .device=unit, .channel=chan, 657 1.23 chap .value=(msg[0] & 0x7f) | ((msg[1] & 0x7f)<<7))); 658 1.1 augustss break; 659 1.6 augustss case MIDI_SYSTEM_PREFIX: 660 1.23 chap mlen = getlen(tp); 661 1.23 chap if (tp->status == MIDI_SYSEX_START) { 662 1.6 augustss send_sysex(tp->start, mlen); 663 1.23 chap break; 664 1.23 chap } else if (tp->status == MIDI_SYSEX_END) { 665 1.23 chap /* SMF uses SYSEX_END as CONTINUATION/ESCAPE */ 666 1.23 chap if (insysex) { /* CONTINUATION */ 667 1.23 chap send_sysex(tp->start, mlen); 668 1.23 chap } else { /* ESCAPE */ 669 1.28 christos for (; mlen > 0 ; -- mlen) { 670 1.23 chap send_event( 671 1.23 chap &SEQ_MK_EVENT(putc, 672 1.23 chap SEQOLD_MIDIPUTC, 673 1.23 chap .device=unit, 674 1.23 chap .byte=*(tp->start++) 675 1.28 christos )); 676 1.23 chap } 677 1.23 chap } 678 1.23 chap break; 679 1.23 chap } 680 1.33 mrg /* Sorry, can't do this yet */ 681 1.33 mrg /* FALLTHROUGH */ 682 1.3 augustss default: 683 1.3 augustss if (verbose) 684 1.3 augustss printf("MIDI event 0x%02x ignored\n", 685 1.3 augustss tp->status); 686 1.1 augustss } 687 1.1 augustss tp->start += mlen; 688 1.1 augustss } 689 1.23 chap if (tp->start >= tp->end) { 690 1.23 chap ntrks = ShrinkHeap(tracks, ntrks); /* track gone */ 691 1.23 chap if (0 == ntrks) 692 1.23 chap break; 693 1.23 chap } else 694 1.23 chap tp->delta = getvar(tp); 695 1.23 chap Heapify(tracks, ntrks, 0); 696 1.1 augustss } 697 1.30 mrg if (play && ioctl(fd, SEQUENCER_SYNC, 0) < 0) 698 1.6 augustss err(1, "SEQUENCER_SYNC"); 699 1.1 augustss 700 1.6 augustss ret: 701 1.1 augustss free(tracks); 702 1.1 augustss } 703 1.1 augustss 704 1.29 jmcneill static int 705 1.29 jmcneill parse_unit(const char *sunit) 706 1.29 jmcneill { 707 1.29 jmcneill const char *osunit = sunit; 708 1.29 jmcneill long n; 709 1.29 jmcneill char *ep; 710 1.29 jmcneill 711 1.29 jmcneill if (strncmp(sunit, "midi", strlen("midi")) == 0) 712 1.29 jmcneill sunit += strlen("midi"); 713 1.29 jmcneill 714 1.29 jmcneill errno = 0; 715 1.29 jmcneill n = strtol(sunit, &ep, 10); 716 1.29 jmcneill if (n < 0 || n > INT_MAX || *ep != '\0' || 717 1.29 jmcneill (errno == ERANGE && 718 1.29 jmcneill (n == LONG_MAX || n == LONG_MIN))) 719 1.29 jmcneill errx(1, "bad midi unit -- %s", osunit); 720 1.29 jmcneill 721 1.29 jmcneill return (int)n; 722 1.29 jmcneill } 723 1.29 jmcneill 724 1.1 augustss int 725 1.16 augustss main(int argc, char **argv) 726 1.1 augustss { 727 1.1 augustss int ch; 728 1.1 augustss int listdevs = 0; 729 1.1 augustss int example = 0; 730 1.31 mrg int silence = 0; 731 1.1 augustss int nmidi; 732 1.16 augustss const char *file = DEVMUSIC; 733 1.16 augustss const char *sunit; 734 1.1 augustss struct synth_info info; 735 1.1 augustss FILE *f; 736 1.16 augustss 737 1.16 augustss if ((sunit = getenv("MIDIUNIT"))) 738 1.29 jmcneill unit = parse_unit(sunit); 739 1.1 augustss 740 1.31 mrg while ((ch = getopt(argc, argv, "?d:f:lmp:qst:vx")) != -1) { 741 1.1 augustss switch(ch) { 742 1.1 augustss case 'd': 743 1.29 jmcneill unit = parse_unit(optarg); 744 1.1 augustss break; 745 1.1 augustss case 'f': 746 1.1 augustss file = optarg; 747 1.1 augustss break; 748 1.1 augustss case 'l': 749 1.1 augustss listdevs++; 750 1.1 augustss break; 751 1.1 augustss case 'm': 752 1.1 augustss showmeta++; 753 1.10 augustss break; 754 1.10 augustss case 'p': 755 1.10 augustss sameprogram = atoi(optarg); 756 1.3 augustss break; 757 1.3 augustss case 'q': 758 1.3 augustss play = 0; 759 1.1 augustss break; 760 1.31 mrg case 's': 761 1.31 mrg silence++; 762 1.31 mrg break; 763 1.1 augustss case 't': 764 1.2 augustss ttempo = atoi(optarg); 765 1.1 augustss break; 766 1.1 augustss case 'v': 767 1.1 augustss verbose++; 768 1.1 augustss break; 769 1.1 augustss case 'x': 770 1.1 augustss example++; 771 1.1 augustss break; 772 1.1 augustss case '?': 773 1.1 augustss default: 774 1.1 augustss usage(); 775 1.1 augustss } 776 1.1 augustss } 777 1.1 augustss argc -= optind; 778 1.1 augustss argv += optind; 779 1.28 christos 780 1.15 augustss if (!play) 781 1.15 augustss goto output; 782 1.15 augustss 783 1.1 augustss fd = open(file, O_WRONLY); 784 1.1 augustss if (fd < 0) 785 1.1 augustss err(1, "%s", file); 786 1.1 augustss if (ioctl(fd, SEQUENCER_NRMIDIS, &nmidi) < 0) 787 1.1 augustss err(1, "ioctl(SEQUENCER_NRMIDIS) failed, "); 788 1.1 augustss if (nmidi == 0) 789 1.17 itojun errx(1, "Sorry, no MIDI devices available"); 790 1.1 augustss if (listdevs) { 791 1.1 augustss for (info.device = 0; info.device < nmidi; info.device++) { 792 1.1 augustss if (ioctl(fd, SEQUENCER_INFO, &info) < 0) 793 1.1 augustss err(1, "ioctl(SEQUENCER_INFO) failed, "); 794 1.1 augustss printf("%d: %s\n", info.device, info.name); 795 1.1 augustss } 796 1.1 augustss exit(0); 797 1.1 augustss } 798 1.9 augustss 799 1.15 augustss output: 800 1.1 augustss if (example) 801 1.9 augustss while (example--) 802 1.9 augustss playdata(sample, sizeof sample, "<Gubben Noa>"); 803 1.31 mrg else if (silence) 804 1.31 mrg while (silence--) 805 1.31 mrg playdata(silence_sample, sizeof silence_sample, 806 1.31 mrg "<Silence>"); 807 1.1 augustss else if (argc == 0) 808 1.1 augustss playfile(stdin, "<stdin>"); 809 1.1 augustss else 810 1.1 augustss while (argc--) { 811 1.1 augustss f = fopen(*argv, "r"); 812 1.1 augustss if (f == NULL) 813 1.1 augustss err(1, "%s", *argv); 814 1.1 augustss else { 815 1.1 augustss playfile(f, *argv); 816 1.1 augustss fclose(f); 817 1.1 augustss } 818 1.1 augustss argv++; 819 1.1 augustss } 820 1.1 augustss 821 1.1 augustss exit(0); 822 1.1 augustss } 823 1.23 chap 824 1.23 chap /* 825 1.23 chap * relative-time priority queue (min-heap). Properties: 826 1.23 chap * 1. The delta time at a node is relative to the node's parent's time. 827 1.23 chap * 2. When an event is dequeued from a track, the delta time of the new head 828 1.23 chap * event is relative to the time of the event just dequeued. 829 1.23 chap * Therefore: 830 1.23 chap * 3. After dequeueing the head event from the track at heap root, the next 831 1.23 chap * event's time is directly comparable to the root's children. 832 1.23 chap * These properties allow the heap to be maintained with delta times throughout. 833 1.23 chap * Insert is also implementable, but not needed: all the tracks are present 834 1.23 chap * at first; they just go away as they end. 835 1.23 chap */ 836 1.23 chap 837 1.28 christos #define PARENT(i) ((i - 1) >> 1) 838 1.28 christos #define LEFT(i) ((i << 1) + 1) 839 1.28 christos #define RIGHT(i) ((i + 1) << 1) 840 1.23 chap #define DTIME(i) (t[i].indirect->delta) 841 1.28 christos #define SWAP(i, j) do { \ 842 1.23 chap struct track *_t = t[i].indirect; \ 843 1.23 chap t[i].indirect = t[j].indirect; \ 844 1.23 chap t[j].indirect = _t; \ 845 1.34 rillig } while (0) 846 1.23 chap 847 1.28 christos static void 848 1.23 chap Heapify(struct track *t, int ntrks, int node) 849 1.23 chap { 850 1.23 chap int lc, rc, mn; 851 1.28 christos 852 1.23 chap lc = LEFT(node); 853 1.23 chap rc = RIGHT(node); 854 1.28 christos 855 1.23 chap if (rc >= ntrks) { /* no right child */ 856 1.23 chap if (lc >= ntrks) /* node is a leaf */ 857 1.23 chap return; 858 1.23 chap if (DTIME(node) > DTIME(lc)) 859 1.28 christos SWAP(node, lc); 860 1.23 chap DTIME(lc) -= DTIME(node); 861 1.23 chap return; /* no rc ==> lc is a leaf */ 862 1.23 chap } 863 1.23 chap 864 1.23 chap mn = lc; 865 1.23 chap if (DTIME(lc) > DTIME(rc)) 866 1.23 chap mn = rc; 867 1.23 chap if (DTIME(node) <= DTIME(mn)) { 868 1.23 chap DTIME(rc) -= DTIME(node); 869 1.23 chap DTIME(lc) -= DTIME(node); 870 1.23 chap return; 871 1.23 chap } 872 1.28 christos 873 1.28 christos SWAP(node, mn); 874 1.23 chap DTIME(rc) -= DTIME(node); 875 1.23 chap DTIME(lc) -= DTIME(node); 876 1.23 chap Heapify(t, ntrks, mn); /* gcc groks tail recursion */ 877 1.23 chap } 878 1.23 chap 879 1.28 christos static void 880 1.23 chap BuildHeap(struct track *t, int ntrks) 881 1.23 chap { 882 1.23 chap int node; 883 1.28 christos 884 1.28 christos for (node = PARENT(ntrks - 1); node --> 0;) 885 1.23 chap Heapify(t, ntrks, node); 886 1.23 chap } 887 1.23 chap 888 1.23 chap /* 889 1.23 chap * Make the heap 1 item smaller by discarding the track at the root. Move the 890 1.23 chap * rightmost bottom-level leaf to the root and decrement ntrks. It remains to 891 1.23 chap * run Heapify, which the caller is expected to do. Returns the new ntrks. 892 1.23 chap */ 893 1.28 christos static int 894 1.23 chap ShrinkHeap(struct track *t, int ntrks) 895 1.23 chap { 896 1.23 chap int ancest; 897 1.28 christos 898 1.28 christos --ntrks; 899 1.28 christos for (ancest = PARENT(ntrks); ancest > 0; ancest = PARENT(ancest)) 900 1.23 chap DTIME(ntrks) += DTIME(ancest); 901 1.23 chap t[0].indirect = t[ntrks].indirect; 902 1.23 chap return ntrks; 903 1.23 chap } 904