midiplay.c revision 1.32 1 1.32 wiz /* $NetBSD: midiplay.c,v 1.32 2018/05/03 05:14:55 wiz 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.32 wiz __RCSID("$NetBSD: midiplay.c,v 1.32 2018/05/03 05:14:55 wiz 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.23 chap /* Sorry, can't do this yet; FALLTHROUGH */
681 1.3 augustss default:
682 1.3 augustss if (verbose)
683 1.3 augustss printf("MIDI event 0x%02x ignored\n",
684 1.3 augustss tp->status);
685 1.1 augustss }
686 1.1 augustss tp->start += mlen;
687 1.1 augustss }
688 1.23 chap if (tp->start >= tp->end) {
689 1.23 chap ntrks = ShrinkHeap(tracks, ntrks); /* track gone */
690 1.23 chap if (0 == ntrks)
691 1.23 chap break;
692 1.23 chap } else
693 1.23 chap tp->delta = getvar(tp);
694 1.23 chap Heapify(tracks, ntrks, 0);
695 1.1 augustss }
696 1.30 mrg if (play && ioctl(fd, SEQUENCER_SYNC, 0) < 0)
697 1.6 augustss err(1, "SEQUENCER_SYNC");
698 1.1 augustss
699 1.6 augustss ret:
700 1.1 augustss free(tracks);
701 1.1 augustss }
702 1.1 augustss
703 1.29 jmcneill static int
704 1.29 jmcneill parse_unit(const char *sunit)
705 1.29 jmcneill {
706 1.29 jmcneill const char *osunit = sunit;
707 1.29 jmcneill long n;
708 1.29 jmcneill char *ep;
709 1.29 jmcneill
710 1.29 jmcneill if (strncmp(sunit, "midi", strlen("midi")) == 0)
711 1.29 jmcneill sunit += strlen("midi");
712 1.29 jmcneill
713 1.29 jmcneill errno = 0;
714 1.29 jmcneill n = strtol(sunit, &ep, 10);
715 1.29 jmcneill if (n < 0 || n > INT_MAX || *ep != '\0' ||
716 1.29 jmcneill (errno == ERANGE &&
717 1.29 jmcneill (n == LONG_MAX || n == LONG_MIN)))
718 1.29 jmcneill errx(1, "bad midi unit -- %s", osunit);
719 1.29 jmcneill
720 1.29 jmcneill return (int)n;
721 1.29 jmcneill }
722 1.29 jmcneill
723 1.1 augustss int
724 1.16 augustss main(int argc, char **argv)
725 1.1 augustss {
726 1.1 augustss int ch;
727 1.1 augustss int listdevs = 0;
728 1.1 augustss int example = 0;
729 1.31 mrg int silence = 0;
730 1.1 augustss int nmidi;
731 1.16 augustss const char *file = DEVMUSIC;
732 1.16 augustss const char *sunit;
733 1.1 augustss struct synth_info info;
734 1.1 augustss FILE *f;
735 1.16 augustss
736 1.16 augustss if ((sunit = getenv("MIDIUNIT")))
737 1.29 jmcneill unit = parse_unit(sunit);
738 1.1 augustss
739 1.31 mrg while ((ch = getopt(argc, argv, "?d:f:lmp:qst:vx")) != -1) {
740 1.1 augustss switch(ch) {
741 1.1 augustss case 'd':
742 1.29 jmcneill unit = parse_unit(optarg);
743 1.1 augustss break;
744 1.1 augustss case 'f':
745 1.1 augustss file = optarg;
746 1.1 augustss break;
747 1.1 augustss case 'l':
748 1.1 augustss listdevs++;
749 1.1 augustss break;
750 1.1 augustss case 'm':
751 1.1 augustss showmeta++;
752 1.10 augustss break;
753 1.10 augustss case 'p':
754 1.10 augustss sameprogram = atoi(optarg);
755 1.3 augustss break;
756 1.3 augustss case 'q':
757 1.3 augustss play = 0;
758 1.1 augustss break;
759 1.31 mrg case 's':
760 1.31 mrg silence++;
761 1.31 mrg break;
762 1.1 augustss case 't':
763 1.2 augustss ttempo = atoi(optarg);
764 1.1 augustss break;
765 1.1 augustss case 'v':
766 1.1 augustss verbose++;
767 1.1 augustss break;
768 1.1 augustss case 'x':
769 1.1 augustss example++;
770 1.1 augustss break;
771 1.1 augustss case '?':
772 1.1 augustss default:
773 1.1 augustss usage();
774 1.1 augustss }
775 1.1 augustss }
776 1.1 augustss argc -= optind;
777 1.1 augustss argv += optind;
778 1.28 christos
779 1.15 augustss if (!play)
780 1.15 augustss goto output;
781 1.15 augustss
782 1.1 augustss fd = open(file, O_WRONLY);
783 1.1 augustss if (fd < 0)
784 1.1 augustss err(1, "%s", file);
785 1.1 augustss if (ioctl(fd, SEQUENCER_NRMIDIS, &nmidi) < 0)
786 1.1 augustss err(1, "ioctl(SEQUENCER_NRMIDIS) failed, ");
787 1.1 augustss if (nmidi == 0)
788 1.17 itojun errx(1, "Sorry, no MIDI devices available");
789 1.1 augustss if (listdevs) {
790 1.1 augustss for (info.device = 0; info.device < nmidi; info.device++) {
791 1.1 augustss if (ioctl(fd, SEQUENCER_INFO, &info) < 0)
792 1.1 augustss err(1, "ioctl(SEQUENCER_INFO) failed, ");
793 1.1 augustss printf("%d: %s\n", info.device, info.name);
794 1.1 augustss }
795 1.1 augustss exit(0);
796 1.1 augustss }
797 1.9 augustss
798 1.15 augustss output:
799 1.1 augustss if (example)
800 1.9 augustss while (example--)
801 1.9 augustss playdata(sample, sizeof sample, "<Gubben Noa>");
802 1.31 mrg else if (silence)
803 1.31 mrg while (silence--)
804 1.31 mrg playdata(silence_sample, sizeof silence_sample,
805 1.31 mrg "<Silence>");
806 1.1 augustss else if (argc == 0)
807 1.1 augustss playfile(stdin, "<stdin>");
808 1.1 augustss else
809 1.1 augustss while (argc--) {
810 1.1 augustss f = fopen(*argv, "r");
811 1.1 augustss if (f == NULL)
812 1.1 augustss err(1, "%s", *argv);
813 1.1 augustss else {
814 1.1 augustss playfile(f, *argv);
815 1.1 augustss fclose(f);
816 1.1 augustss }
817 1.1 augustss argv++;
818 1.1 augustss }
819 1.1 augustss
820 1.1 augustss exit(0);
821 1.1 augustss }
822 1.23 chap
823 1.23 chap /*
824 1.23 chap * relative-time priority queue (min-heap). Properties:
825 1.23 chap * 1. The delta time at a node is relative to the node's parent's time.
826 1.23 chap * 2. When an event is dequeued from a track, the delta time of the new head
827 1.23 chap * event is relative to the time of the event just dequeued.
828 1.23 chap * Therefore:
829 1.23 chap * 3. After dequeueing the head event from the track at heap root, the next
830 1.23 chap * event's time is directly comparable to the root's children.
831 1.23 chap * These properties allow the heap to be maintained with delta times throughout.
832 1.23 chap * Insert is also implementable, but not needed: all the tracks are present
833 1.23 chap * at first; they just go away as they end.
834 1.23 chap */
835 1.23 chap
836 1.28 christos #define PARENT(i) ((i - 1) >> 1)
837 1.28 christos #define LEFT(i) ((i << 1) + 1)
838 1.28 christos #define RIGHT(i) ((i + 1) << 1)
839 1.23 chap #define DTIME(i) (t[i].indirect->delta)
840 1.28 christos #define SWAP(i, j) do { \
841 1.23 chap struct track *_t = t[i].indirect; \
842 1.23 chap t[i].indirect = t[j].indirect; \
843 1.23 chap t[j].indirect = _t; \
844 1.28 christos } while (/*CONSTCOND*/ 0)
845 1.23 chap
846 1.28 christos static void
847 1.23 chap Heapify(struct track *t, int ntrks, int node)
848 1.23 chap {
849 1.23 chap int lc, rc, mn;
850 1.28 christos
851 1.23 chap lc = LEFT(node);
852 1.23 chap rc = RIGHT(node);
853 1.28 christos
854 1.23 chap if (rc >= ntrks) { /* no right child */
855 1.23 chap if (lc >= ntrks) /* node is a leaf */
856 1.23 chap return;
857 1.23 chap if (DTIME(node) > DTIME(lc))
858 1.28 christos SWAP(node, lc);
859 1.23 chap DTIME(lc) -= DTIME(node);
860 1.23 chap return; /* no rc ==> lc is a leaf */
861 1.23 chap }
862 1.23 chap
863 1.23 chap mn = lc;
864 1.23 chap if (DTIME(lc) > DTIME(rc))
865 1.23 chap mn = rc;
866 1.23 chap if (DTIME(node) <= DTIME(mn)) {
867 1.23 chap DTIME(rc) -= DTIME(node);
868 1.23 chap DTIME(lc) -= DTIME(node);
869 1.23 chap return;
870 1.23 chap }
871 1.28 christos
872 1.28 christos SWAP(node, mn);
873 1.23 chap DTIME(rc) -= DTIME(node);
874 1.23 chap DTIME(lc) -= DTIME(node);
875 1.23 chap Heapify(t, ntrks, mn); /* gcc groks tail recursion */
876 1.23 chap }
877 1.23 chap
878 1.28 christos static void
879 1.23 chap BuildHeap(struct track *t, int ntrks)
880 1.23 chap {
881 1.23 chap int node;
882 1.28 christos
883 1.28 christos for (node = PARENT(ntrks - 1); node --> 0;)
884 1.23 chap Heapify(t, ntrks, node);
885 1.23 chap }
886 1.23 chap
887 1.23 chap /*
888 1.23 chap * Make the heap 1 item smaller by discarding the track at the root. Move the
889 1.23 chap * rightmost bottom-level leaf to the root and decrement ntrks. It remains to
890 1.23 chap * run Heapify, which the caller is expected to do. Returns the new ntrks.
891 1.23 chap */
892 1.28 christos static int
893 1.23 chap ShrinkHeap(struct track *t, int ntrks)
894 1.23 chap {
895 1.23 chap int ancest;
896 1.28 christos
897 1.28 christos --ntrks;
898 1.28 christos for (ancest = PARENT(ntrks); ancest > 0; ancest = PARENT(ancest))
899 1.23 chap DTIME(ntrks) += DTIME(ancest);
900 1.23 chap t[0].indirect = t[ntrks].indirect;
901 1.23 chap return ntrks;
902 1.23 chap }
903