1 /* $NetBSD: midirecord.c,v 1.13 2023/05/09 20:42:19 mrg Exp $ */
2
3 /*
4 * Copyright (c) 2014, 2015, 2017 Matthew R. Green
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * midirecord(1), similar to audiorecord(1).
31 */
32
33 #include <sys/cdefs.h>
34
35 #ifndef lint
36 __RCSID("$NetBSD: midirecord.c,v 1.13 2023/05/09 20:42:19 mrg Exp $");
37 #endif
38
39 #include <sys/param.h>
40 #include <sys/midiio.h>
41 #include <sys/ioctl.h>
42 #include <sys/time.h>
43 #include <sys/uio.h>
44
45 #include <err.h>
46 #include <errno.h>
47 #include <ctype.h>
48 #include <fcntl.h>
49 #include <paths.h>
50 #include <signal.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <util.h>
56 #include <stdbool.h>
57
58 #include "libaudio.h"
59
60 static const char *midi_device;
61 static unsigned *filt_devnos = NULL;
62 static unsigned *filt_chans = NULL;
63 static unsigned num_filt_devnos, num_filt_chans;
64 static char *raw_output;
65 static int midifd;
66 static int aflag, qflag, oflag;
67 static bool debug = false;
68 int verbose;
69 static int outfd, rawfd = -1;
70 static ssize_t data_size;
71 static struct timeval record_time;
72 static struct timeval start_time;
73 static int tempo = 120;
74 static unsigned round_beats = 1;
75 static unsigned notes_per_beat = 24;
76 static bool ignore_timer_fail = false;
77 static bool stdout_mode = false;
78
79 static void debug_log(const char *, size_t, const char *, ...)
80 __printflike(3, 4);
81 static size_t midi_event_local_to_output(seq_event_t, u_char *, size_t);
82 static size_t midi_event_timer_wait_abs_to_output(seq_event_t, u_char *,
83 size_t);
84 static size_t midi_event_timer_to_output(seq_event_t, u_char *, size_t);
85 static size_t midi_event_chn_common_to_output(seq_event_t, u_char *, size_t);
86 static size_t midi_event_chn_voice_to_output(seq_event_t, u_char *, size_t);
87 static size_t midi_event_sysex_to_output(seq_event_t, u_char *, size_t);
88 static size_t midi_event_fullsize_to_output(seq_event_t, u_char *, size_t);
89 static size_t midi_event_to_output(seq_event_t, u_char *, size_t);
90 static int timeleft(struct timeval *, struct timeval *);
91 static bool filter_array(unsigned, unsigned *, size_t);
92 static bool filter_dev(unsigned);
93 static bool filter_chan(unsigned);
94 static bool filter_devchan(unsigned, unsigned);
95 static void parse_ints(const char *, unsigned **, unsigned *, const char *);
96 static void cleanup(int) __dead;
97 static void rewrite_header(void);
98 static void write_midi_header(void);
99 static void write_midi_trailer(void);
100 static void usage(void) __dead;
101
102 #define PATH_DEV_MUSIC "/dev/music"
103
104 int
main(int argc,char * argv[])105 main(int argc, char *argv[])
106 {
107 u_char *buffer;
108 size_t bufsize = 0;
109 int ch, no_time_limit = 1;
110
111 while ((ch = getopt(argc, argv, "aB:c:Dd:f:hn:oqr:t:T:V")) != -1) {
112 switch (ch) {
113 case 'a':
114 aflag++;
115 break;
116 case 'B':
117 bufsize = strsuftoll("read buffer size", optarg,
118 1, UINT_MAX);
119 break;
120 case 'c':
121 parse_ints(optarg, &filt_chans, &num_filt_chans,
122 "channels");
123 break;
124 case 'D':
125 debug = true;
126 break;
127 case 'd':
128 parse_ints(optarg, &filt_devnos, &num_filt_devnos,
129 "devices");
130 break;
131 case 'f':
132 midi_device = optarg;
133 ignore_timer_fail = true;
134 break;
135 case 'n':
136 decode_uint(optarg, ¬es_per_beat);
137 break;
138 case 'o':
139 oflag++; /* time stamp starts at proc start */
140 break;
141 case 'q':
142 qflag++;
143 break;
144 case 'r':
145 raw_output = optarg;
146 break;
147 case 'R':
148 decode_uint(optarg, &round_beats);
149 if (round_beats == 0)
150 errx(1, "-R <round_beats> must be a positive integer");
151 break;
152 case 't':
153 no_time_limit = 0;
154 decode_time(optarg, &record_time);
155 break;
156 case 'T':
157 decode_int(optarg, &tempo);
158 break;
159 case 'V':
160 verbose++;
161 break;
162 /* case 'h': */
163 default:
164 usage();
165 /* NOTREACHED */
166 }
167 }
168 argc -= optind;
169 argv += optind;
170
171 if (argc != 1)
172 usage();
173
174 /*
175 * work out the buffer size to use, and allocate it. don't allow it
176 * to be too small.
177 */
178 if (bufsize < 32)
179 bufsize = 32 * 1024;
180 buffer = malloc(bufsize);
181 if (buffer == NULL)
182 err(1, "couldn't malloc buffer of %d size", (int)bufsize);
183
184 /*
185 * open the music device
186 */
187 if (midi_device == NULL && (midi_device = getenv("MIDIDEVICE")) == NULL)
188 midi_device = PATH_DEV_MUSIC;
189 midifd = open(midi_device, O_RDONLY);
190 if (midifd < 0)
191 err(1, "failed to open %s", midi_device);
192
193 /* open the output file */
194 if (argv[0][0] != '-' || argv[0][1] != '\0') {
195 int mode = O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY;
196
197 outfd = open(*argv, mode, 0666);
198 if (outfd < 0)
199 err(1, "could not open %s", *argv);
200 } else {
201 stdout_mode = true;
202 outfd = STDOUT_FILENO;
203 }
204
205 /* open the raw output file */
206 if (raw_output) {
207 int mode = O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY;
208
209 rawfd = open(raw_output, mode, 0666);
210 if (rawfd < 0)
211 err(1, "could not open %s", raw_output);
212 }
213
214 /* start the midi timer */
215 if (ioctl(midifd, SEQUENCER_TMR_START, NULL) < 0) {
216 if (ignore_timer_fail)
217 warn("failed to start midi timer");
218 else
219 err(1, "failed to start midi timer");
220 }
221
222 /* set the timebase */
223 if (ioctl(midifd, SEQUENCER_TMR_TIMEBASE, ¬es_per_beat) < 0) {
224 if (ignore_timer_fail)
225 warn("SEQUENCER_TMR_TIMEBASE: notes_per_beat %d",
226 notes_per_beat);
227 else
228 err(1, "SEQUENCER_TMR_TIMEBASE: notes_per_beat %d",
229 notes_per_beat);
230 }
231
232 /* set the tempo */
233 if (ioctl(midifd, SEQUENCER_TMR_TEMPO, &tempo) < 0) {
234 if (ignore_timer_fail)
235 warn("SEQUENCER_TMR_TIMEBASE: tempo %d", tempo);
236 else
237 err(1, "SEQUENCER_TMR_TIMEBASE: tempo %d", tempo);
238 }
239
240 signal(SIGINT, cleanup);
241
242 data_size = 0;
243
244 if (verbose)
245 fprintf(stderr, "tempo=%d notes_per_beat=%u\n",
246 tempo, notes_per_beat);
247
248 if (!no_time_limit && verbose)
249 fprintf(stderr, "recording for %lu seconds, %lu microseconds\n",
250 (u_long)record_time.tv_sec, (u_long)record_time.tv_usec);
251
252 /* Create a midi header. */
253 write_midi_header();
254
255 (void)gettimeofday(&start_time, NULL);
256 while (no_time_limit || timeleft(&start_time, &record_time)) {
257 seq_event_t e;
258 size_t wrsize;
259 size_t rdsize;
260
261 rdsize = (size_t)read(midifd, &e, sizeof e);
262 if (rdsize == 0)
263 break;
264
265 if (rdsize != sizeof e)
266 err(1, "read failed");
267
268 if (rawfd != -1 && write(rawfd, &e, sizeof e) != sizeof e)
269 err(1, "write to raw file failed");
270
271 /* convert 'e' into something useful for output */
272 wrsize = midi_event_to_output(e, buffer, bufsize);
273
274 if (wrsize) {
275 if ((size_t)write(outfd, buffer, wrsize) != wrsize)
276 err(1, "write failed");
277 data_size += wrsize;
278 }
279 }
280 cleanup(0);
281 }
282
283 static void
debug_log(const char * file,size_t line,const char * fmt,...)284 debug_log(const char *file, size_t line, const char *fmt, ...)
285 {
286 va_list ap;
287
288 if (!debug)
289 return;
290 fprintf(stderr, "%s:%zu: ", file, line);
291 va_start(ap, fmt);
292 vfprintf(stderr, fmt, ap);
293 va_end(ap);
294 fprintf(stderr, "\n");
295 }
296
297 #define LOG(fmt...) \
298 debug_log(__func__, __LINE__, fmt)
299
300
301 /*
302 * handle a SEQ_LOCAL event. NetBSD /dev/music doesn't generate these.
303 */
304 static size_t
midi_event_local_to_output(seq_event_t e,u_char * buffer,size_t bufsize)305 midi_event_local_to_output(seq_event_t e, u_char *buffer, size_t bufsize)
306 {
307 size_t size = 0;
308
309 LOG("UNHANDLED SEQ_LOCAL");
310
311 return size;
312 }
313
314 /*
315 * convert a midi absolute time event to a variable length delay
316 */
317 static size_t
midi_event_timer_wait_abs_to_output(seq_event_t e,u_char * buffer,size_t bufsize)318 midi_event_timer_wait_abs_to_output(
319 seq_event_t e,
320 u_char *buffer,
321 size_t bufsize)
322 {
323 static unsigned prev_div;
324 static int prev_leftover;
325 unsigned cur_div;
326 unsigned val = 0, xdiv;
327 int vallen = 0, i;
328
329 if (bufsize < 4) {
330 warnx("too small bufsize: %zu", bufsize);
331 return 0;
332 }
333
334 if (prev_div == 0 && !oflag)
335 prev_div = e.t_WAIT_ABS.divisions;
336 cur_div = e.t_WAIT_ABS.divisions;
337
338 xdiv = cur_div - prev_div + prev_leftover;
339 if (round_beats != 1) {
340 // round to closest
341 prev_leftover = xdiv % round_beats;
342 xdiv -= prev_leftover;
343 if (verbose)
344 fprintf(stderr, "adjusted beat value to %x (leftover = %d)\n",
345 xdiv, prev_leftover);
346 }
347 if (xdiv) {
348 while (xdiv) {
349 uint32_t extra = val ? 0x80 : 0;
350
351 val <<= 8;
352 val |= (xdiv & 0x7f) | extra;
353 xdiv >>= 7;
354 vallen++;
355 }
356 } else
357 vallen = 1;
358
359 for (i = 0; i < vallen; i++) {
360 buffer[i] = val & 0xff;
361 val >>= 8;
362 }
363 for (; i < 4; i++)
364 buffer[i] = 0;
365 LOG("TMR_WAIT_ABS: new div %x (cur %x prev %x): bufval (len=%u): "
366 "%02x:%02x:%02x:%02x",
367 cur_div - prev_div, cur_div, prev_div,
368 vallen, buffer[0], buffer[1], buffer[2], buffer[3]);
369
370 prev_div = cur_div;
371
372 return vallen;
373 }
374
375 /*
376 * handle a SEQ_TIMING event.
377 */
378 static size_t
midi_event_timer_to_output(seq_event_t e,u_char * buffer,size_t bufsize)379 midi_event_timer_to_output(seq_event_t e, u_char *buffer, size_t bufsize)
380 {
381 size_t size = 0;
382
383 LOG("SEQ_TIMING");
384 switch (e.timing.op) {
385 case TMR_WAIT_REL:
386 /* NetBSD /dev/music doesn't generate these. */
387 LOG("UNHANDLED TMR_WAIT_REL: divisions: %x", e.t_WAIT_REL.divisions);
388 break;
389
390 case TMR_WAIT_ABS:
391 size = midi_event_timer_wait_abs_to_output(e, buffer, bufsize);
392 break;
393
394 case TMR_STOP:
395 case TMR_START:
396 case TMR_CONTINUE:
397 case TMR_TEMPO:
398 case TMR_ECHO:
399 case TMR_CLOCK:
400 case TMR_SPP:
401 case TMR_TIMESIG:
402 /* NetBSD /dev/music doesn't generate these. */
403 LOG("UNHANDLED timer op: %x", e.timing.op);
404 break;
405
406 default:
407 LOG("unknown timer op: %x", e.timing.op);
408 break;
409 }
410
411 return size;
412 }
413
414 /*
415 * handle a SEQ_CHN_COMMON event.
416 */
417 static size_t
midi_event_chn_common_to_output(seq_event_t e,u_char * buffer,size_t bufsize)418 midi_event_chn_common_to_output(seq_event_t e, u_char *buffer, size_t bufsize)
419 {
420 size_t size = 0;
421
422 LOG("SEQ_CHN_COMMON");
423
424 if (bufsize < 3) {
425 warnx("too small bufsize: %zu", bufsize);
426 return 0;
427 }
428
429 if (e.common.channel >= 16) {
430 warnx("invalid channel: %u", e.common.channel);
431 return 0;
432 }
433
434 if (filter_devchan(e.common.device, e.common.channel))
435 return 0;
436
437 switch (e.common.op) {
438 case MIDI_CTL_CHANGE:
439 buffer[0] = MIDI_CTL_CHANGE | e.c_CTL_CHANGE.channel;
440 buffer[1] = e.c_CTL_CHANGE.controller;
441 buffer[2] = e.c_CTL_CHANGE.value;
442 LOG("MIDI_CTL_CHANGE: channel %x ctrl %x val %x",
443 e.c_CTL_CHANGE.channel, e.c_CTL_CHANGE.controller,
444 e.c_CTL_CHANGE.value);
445 size = 3;
446 break;
447
448 case MIDI_PGM_CHANGE:
449 buffer[0] = MIDI_PGM_CHANGE | e.c_PGM_CHANGE.channel;
450 buffer[1] = e.c_PGM_CHANGE.program;
451 LOG("MIDI_PGM_CHANGE: channel %x program %x",
452 e.c_PGM_CHANGE.channel, e.c_PGM_CHANGE.program);
453 size = 2;
454 break;
455
456 case MIDI_CHN_PRESSURE:
457 buffer[0] = MIDI_CHN_PRESSURE | e.c_CHN_PRESSURE.channel;
458 buffer[1] = e.c_CHN_PRESSURE.pressure;
459 LOG("MIDI_CHN_PRESSURE: channel %x pressure %x",
460 e.c_CHN_PRESSURE.channel, e.c_CHN_PRESSURE.pressure);
461 size = 2;
462 break;
463
464 case MIDI_PITCH_BEND:
465 buffer[0] = MIDI_PITCH_BEND | e.c_PITCH_BEND.channel;
466 /* 14 bits split over 2 data bytes, lsb first */
467 buffer[1] = e.c_PITCH_BEND.value & 0x7f;
468 buffer[2] = (e.c_PITCH_BEND.value >> 7) & 0x7f;
469 LOG("MIDI_PITCH_BEND: channel %x val %x",
470 e.c_PITCH_BEND.channel, e.c_PITCH_BEND.value);
471 size = 3;
472 break;
473
474 default:
475 LOG("unknown common op: %x", e.voice.op);
476 break;
477 }
478
479 return size;
480 }
481
482 /*
483 * handle a SEQ_CHN_VOICE event.
484 */
485 static size_t
midi_event_chn_voice_to_output(seq_event_t e,u_char * buffer,size_t bufsize)486 midi_event_chn_voice_to_output(seq_event_t e, u_char *buffer, size_t bufsize)
487 {
488 size_t size = 0;
489
490 LOG("SEQ_CHN_VOICE");
491
492 if (bufsize < 3) {
493 warnx("too small bufsize: %zu", bufsize);
494 return 0;
495 }
496
497 if (e.common.channel >= 16) {
498 warnx("invalid channel: %u", e.common.channel);
499 return 0;
500 }
501
502 if (filter_devchan(e.voice.device, e.voice.channel))
503 return 0;
504
505 switch (e.voice.op) {
506 case MIDI_NOTEOFF:
507 buffer[0] = MIDI_NOTEOFF | e.c_NOTEOFF.channel;
508 buffer[1] = e.c_NOTEOFF.key;
509 buffer[2] = e.c_NOTEOFF.velocity;
510
511 LOG("MIDI_NOTEOFF: channel %x key %x velocity %x",
512 e.c_NOTEOFF.channel, e.c_NOTEOFF.key, e.c_NOTEOFF.velocity);
513 size = 3;
514 break;
515
516 case MIDI_NOTEON:
517 buffer[0] = MIDI_NOTEON | e.c_NOTEON.channel;
518 buffer[1] = e.c_NOTEON.key;
519 buffer[2] = e.c_NOTEON.velocity;
520
521 LOG("MIDI_NOTEON: channel %x key %x velocity %x",
522 e.c_NOTEON.channel, e.c_NOTEON.key, e.c_NOTEON.velocity);
523 size = 3;
524 break;
525
526 case MIDI_KEY_PRESSURE:
527 buffer[0] = MIDI_KEY_PRESSURE | e.c_KEY_PRESSURE.channel;
528 buffer[1] = e.c_KEY_PRESSURE.key;
529 buffer[2] = e.c_KEY_PRESSURE.pressure;
530
531 LOG("MIDI_KEY_PRESSURE: channel %x key %x pressure %x",
532 e.c_KEY_PRESSURE.channel, e.c_KEY_PRESSURE.key,
533 e.c_KEY_PRESSURE.pressure);
534 size = 3;
535 break;
536
537 default:
538 LOG("unknown voice op: %x", e.voice.op);
539 break;
540 }
541
542 return size;
543 }
544
545 /*
546 * handle a SEQ_SYSEX event. NetBSD /dev/music doesn't generate these.
547 */
548 static size_t
midi_event_sysex_to_output(seq_event_t e,u_char * buffer,size_t bufsize)549 midi_event_sysex_to_output(seq_event_t e, u_char *buffer, size_t bufsize)
550 {
551 size_t size = 0;
552
553 LOG("UNHANDLED SEQ_SYSEX");
554
555 return size;
556 }
557
558 /*
559 * handle a SEQ_FULLSIZE event. NetBSD /dev/music doesn't generate these.
560 */
561 static size_t
midi_event_fullsize_to_output(seq_event_t e,u_char * buffer,size_t bufsize)562 midi_event_fullsize_to_output(seq_event_t e, u_char *buffer, size_t bufsize)
563 {
564 size_t size = 0;
565
566 LOG("UNHANDLED SEQ_FULLSIZE");
567
568 return size;
569 }
570
571 /*
572 * main handler for MIDI events.
573 */
574 static size_t
midi_event_to_output(seq_event_t e,u_char * buffer,size_t bufsize)575 midi_event_to_output(seq_event_t e, u_char *buffer, size_t bufsize)
576 {
577 size_t size = 0;
578
579 LOG("event: %02x:%02x:%02x:%02x %02x:%02x:%02x:%02x (%zu valid)",
580 e.tag,
581 e.unknown.byte[0], e.unknown.byte[1],
582 e.unknown.byte[2], e.unknown.byte[3],
583 e.unknown.byte[4], e.unknown.byte[5],
584 e.unknown.byte[6], bufsize);
585
586 switch (e.tag) {
587 case SEQ_LOCAL:
588 size = midi_event_local_to_output(e, buffer, bufsize);
589 break;
590
591 case SEQ_TIMING:
592 size = midi_event_timer_to_output(e, buffer, bufsize);
593 break;
594
595 case SEQ_CHN_COMMON:
596 size = midi_event_chn_common_to_output(e, buffer, bufsize);
597 break;
598
599 case SEQ_CHN_VOICE:
600 size = midi_event_chn_voice_to_output(e, buffer, bufsize);
601 break;
602
603 case SEQ_SYSEX:
604 size = midi_event_sysex_to_output(e, buffer, bufsize);
605 break;
606
607 case SEQ_FULLSIZE:
608 size = midi_event_fullsize_to_output(e, buffer, bufsize);
609 break;
610
611 default:
612 errx(1, "don't understand midi tag %x", e.tag);
613 }
614
615 return size;
616 }
617
618 static bool
filter_array(unsigned val,unsigned * array,size_t arraylen)619 filter_array(unsigned val, unsigned *array, size_t arraylen)
620 {
621
622 if (array == NULL)
623 return false;
624
625 for (; arraylen; arraylen--)
626 if (array[arraylen - 1] == val)
627 return false;
628
629 return true;
630 }
631
632 static bool
filter_dev(unsigned device)633 filter_dev(unsigned device)
634 {
635
636 if (filter_array(device, filt_devnos, num_filt_devnos))
637 return true;
638
639 return false;
640 }
641
642 static bool
filter_chan(unsigned channel)643 filter_chan(unsigned channel)
644 {
645
646 if (filter_array(channel, filt_chans, num_filt_chans))
647 return true;
648
649 return false;
650 }
651
652 static bool
filter_devchan(unsigned device,unsigned channel)653 filter_devchan(unsigned device, unsigned channel)
654 {
655
656 if (filter_dev(device) || filter_chan(channel))
657 return true;
658
659 return false;
660 }
661
662 static int
timeleft(struct timeval * start_tvp,struct timeval * record_tvp)663 timeleft(struct timeval *start_tvp, struct timeval *record_tvp)
664 {
665 struct timeval now, diff;
666
667 (void)gettimeofday(&now, NULL);
668 timersub(&now, start_tvp, &diff);
669 timersub(record_tvp, &diff, &now);
670
671 return (now.tv_sec > 0 || (now.tv_sec == 0 && now.tv_usec > 0));
672 }
673
674 static void
parse_ints(const char * str,unsigned ** arrayp,unsigned * sizep,const char * msg)675 parse_ints(const char *str, unsigned **arrayp, unsigned *sizep, const char *msg)
676 {
677 unsigned count = 1, u, longest = 0, c = 0;
678 unsigned *ip;
679 const char *s, *os;
680 char *num_buf;
681
682 /*
683 * count all the comma separated values, and figre out
684 * the longest one.
685 */
686 for (s = str; *s; s++) {
687 c++;
688 if (*s == ',') {
689 count++;
690 if (c > longest)
691 longest = c;
692 c = 0;
693 }
694 }
695 *sizep = count;
696
697 num_buf = malloc(longest + 1);
698 ip = malloc(sizeof(*ip) * count);
699 if (!ip || !num_buf)
700 errx(1, "malloc failed");
701
702 for (count = 0, s = os = str, u = 0; *s; s++) {
703 if (*s == ',') {
704 num_buf[u] = '\0';
705 decode_uint(num_buf, &ip[count++]);
706 os = s + 1;
707 u = 0;
708 } else
709 num_buf[u++] = *s;
710 }
711 num_buf[u] = '\0';
712 decode_uint(num_buf, &ip[count++]);
713 *arrayp = ip;
714
715 if (verbose) {
716 fprintf(stderr, "Filtering %s in:", msg);
717 for (size_t i = 0; i < *sizep; i++)
718 fprintf(stderr, " %u", ip[i]);
719 fprintf(stderr, "\n");
720 }
721
722 free(num_buf);
723 }
724
725 static void
cleanup(int signo)726 cleanup(int signo)
727 {
728
729 write_midi_trailer();
730 rewrite_header();
731
732 if (ioctl(midifd, SEQUENCER_TMR_STOP, NULL) < 0) {
733 if (ignore_timer_fail)
734 warn("failed to stop midi timer");
735 else
736 err(1, "failed to stop midi timer");
737 }
738
739 if (close(outfd) != 0)
740 warn("couldn't close output");
741 if (close(midifd) != 0)
742 warn("couldn't close midi device");
743 if (signo != 0)
744 (void)raise_default_signal(signo);
745
746 exit(0);
747 }
748
749 static void
rewrite_header(void)750 rewrite_header(void)
751 {
752
753 /* can't do this here! */
754 if (stdout_mode)
755 return;
756
757 if (lseek(outfd, (off_t)0, SEEK_SET) == (off_t)-1)
758 err(1, "could not seek to start of file for header rewrite");
759 write_midi_header();
760 }
761
762 #define BYTE1(x) ((x) & 0xff)
763 #define BYTE2(x) (((x) >> 8) & 0xff)
764 #define BYTE3(x) (((x) >> 16) & 0xff)
765 #define BYTE4(x) (((x) >> 24) & 0xff)
766
767 static void
write_midi_header(void)768 write_midi_header(void)
769 {
770 unsigned char header[] = {
771 'M', 'T', 'h', 'd',
772 0, 0, 0, 6,
773 0, 1,
774 0, 0, /* ntracks */
775 0, 0, /* notes per beat */
776 };
777 /* XXX only support one track so far */
778 unsigned ntracks = 1;
779 unsigned char track[] = {
780 'M', 'T', 'r', 'k',
781 0, 0, 0, 0,
782 };
783 unsigned char bpm[] = {
784 0, 0xff, 0x51, 0x3,
785 0, 0, 0, /* inverse tempo */
786 };
787 unsigned total_size = data_size + sizeof header + sizeof track + sizeof bpm;
788
789 header[10] = BYTE2(ntracks);
790 header[11] = BYTE1(ntracks);
791 header[12] = BYTE2(notes_per_beat);
792 header[13] = BYTE1(notes_per_beat);
793
794 track[4] = BYTE4(total_size);
795 track[5] = BYTE3(total_size);
796 track[6] = BYTE2(total_size);
797 track[7] = BYTE1(total_size);
798
799 #define TEMPO_INV(x) (60000000UL / (x))
800 bpm[4] = BYTE3(TEMPO_INV(tempo));
801 bpm[5] = BYTE2(TEMPO_INV(tempo));
802 bpm[6] = BYTE1(TEMPO_INV(tempo));
803
804 if (write(outfd, header, sizeof header) != sizeof header)
805 err(1, "write of header failed");
806 if (write(outfd, track, sizeof track) != sizeof track)
807 err(1, "write of track header failed");
808 if (write(outfd, bpm, sizeof bpm) != sizeof bpm)
809 err(1, "write of bpm header failed");
810
811 LOG("wrote header: ntracks=%u notes_per_beat=%u tempo=%d total_size=%u",
812 ntracks, notes_per_beat, tempo, total_size);
813 }
814
815 static void
write_midi_trailer(void)816 write_midi_trailer(void)
817 {
818 unsigned char trailer[] = {
819 0, 0xff, 0x2f, 0,
820 };
821
822 if (write(outfd, trailer, sizeof trailer) != sizeof trailer)
823 err(1, "write of trailer failed");
824 }
825
826 static void
usage(void)827 usage(void)
828 {
829
830 fprintf(stderr, "Usage: %s [-aDfhqV] [options] {outfile|-}\n",
831 getprogname());
832 fprintf(stderr, "Options:\n"
833 "\t-B buffer size\n"
834 "\t-c channels\n"
835 "\t-d devices\n"
836 "\t-f sequencerdev\n"
837 "\t-n notesperbeat\n"
838 "\t-r raw_output\n"
839 "\t-T tempo\n"
840 "\t-t recording time\n");
841 exit(EXIT_FAILURE);
842 }
843