| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: midirecord.c,v 1.6 2015/01/03 22:57:54 joerg Exp $ */ | | 1 | /* $NetBSD: midirecord.c,v 1.7 2015/03/01 09:56:54 mrg Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2014 Matthew R. Green | | 4 | * Copyright (c) 2014 Matthew R. Green |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -23,27 +23,27 @@ | | | @@ -23,27 +23,27 @@ |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 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 | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | /* | | 29 | /* |
30 | * midirecord(1), similar to audiorecord(1). | | 30 | * midirecord(1), similar to audiorecord(1). |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | | | 34 | |
35 | #ifndef lint | | 35 | #ifndef lint |
36 | __RCSID("$NetBSD: midirecord.c,v 1.6 2015/01/03 22:57:54 joerg Exp $"); | | 36 | __RCSID("$NetBSD: midirecord.c,v 1.7 2015/03/01 09:56:54 mrg Exp $"); |
37 | #endif | | 37 | #endif |
38 | | | 38 | |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | #include <sys/midiio.h> | | 40 | #include <sys/midiio.h> |
41 | #include <sys/ioctl.h> | | 41 | #include <sys/ioctl.h> |
42 | #include <sys/time.h> | | 42 | #include <sys/time.h> |
43 | #include <sys/uio.h> | | 43 | #include <sys/uio.h> |
44 | | | 44 | |
45 | #include <err.h> | | 45 | #include <err.h> |
46 | #include <errno.h> | | 46 | #include <errno.h> |
47 | #include <ctype.h> | | 47 | #include <ctype.h> |
48 | #include <fcntl.h> | | 48 | #include <fcntl.h> |
49 | #include <paths.h> | | 49 | #include <paths.h> |
| @@ -64,26 +64,27 @@ static unsigned *filt_chans = NULL; | | | @@ -64,26 +64,27 @@ static unsigned *filt_chans = NULL; |
64 | static unsigned num_filt_devnos, num_filt_chans; | | 64 | static unsigned num_filt_devnos, num_filt_chans; |
65 | static char *raw_output; | | 65 | static char *raw_output; |
66 | static int midifd; | | 66 | static int midifd; |
67 | static int aflag, qflag, oflag; | | 67 | static int aflag, qflag, oflag; |
68 | static bool debug = false; | | 68 | static bool debug = false; |
69 | int verbose; | | 69 | int verbose; |
70 | static int outfd, rawfd = -1; | | 70 | static int outfd, rawfd = -1; |
71 | static ssize_t data_size; | | 71 | static ssize_t data_size; |
72 | static struct timeval record_time; | | 72 | static struct timeval record_time; |
73 | static struct timeval start_time; | | 73 | static struct timeval start_time; |
74 | static int tempo = 120; | | 74 | static int tempo = 120; |
75 | static unsigned notes_per_beat = 24; | | 75 | static unsigned notes_per_beat = 24; |
76 | static bool ignore_timer_fail = false; | | 76 | static bool ignore_timer_fail = false; |
| | | 77 | static bool stdout_mode = false; |
77 | | | 78 | |
78 | static void debug_log(const char *, size_t, const char *, ...) | | 79 | static void debug_log(const char *, size_t, const char *, ...) |
79 | __printflike(3, 4); | | 80 | __printflike(3, 4); |
80 | static size_t midi_event_local_to_output(seq_event_t, u_char *, size_t); | | 81 | static size_t midi_event_local_to_output(seq_event_t, u_char *, size_t); |
81 | static size_t midi_event_timer_wait_abs_to_output(seq_event_t, u_char *, | | 82 | static size_t midi_event_timer_wait_abs_to_output(seq_event_t, u_char *, |
82 | size_t); | | 83 | size_t); |
83 | static size_t midi_event_timer_to_output(seq_event_t, u_char *, size_t); | | 84 | static size_t midi_event_timer_to_output(seq_event_t, u_char *, size_t); |
84 | static size_t midi_event_chn_common_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); |
85 | static size_t midi_event_chn_voice_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); |
86 | static size_t midi_event_sysex_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); |
87 | static size_t midi_event_fullsize_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); |
88 | static size_t midi_event_to_output(seq_event_t, u_char *, size_t); | | 89 | static size_t midi_event_to_output(seq_event_t, u_char *, size_t); |
89 | static int timeleft(struct timeval *, struct timeval *); | | 90 | static int timeleft(struct timeval *, struct timeval *); |
| @@ -181,28 +182,30 @@ main(int argc, char *argv[]) | | | @@ -181,28 +182,30 @@ main(int argc, char *argv[]) |
181 | if (midi_device == NULL && (midi_device = getenv("MIDIDEVICE")) == NULL) | | 182 | if (midi_device == NULL && (midi_device = getenv("MIDIDEVICE")) == NULL) |
182 | midi_device = PATH_DEV_MUSIC; | | 183 | midi_device = PATH_DEV_MUSIC; |
183 | midifd = open(midi_device, O_RDONLY); | | 184 | midifd = open(midi_device, O_RDONLY); |
184 | if (midifd < 0) | | 185 | if (midifd < 0) |
185 | err(1, "failed to open %s", midi_device); | | 186 | err(1, "failed to open %s", midi_device); |
186 | | | 187 | |
187 | /* open the output file */ | | 188 | /* open the output file */ |
188 | if (argv[0][0] != '-' || argv[0][1] != '\0') { | | 189 | if (argv[0][0] != '-' || argv[0][1] != '\0') { |
189 | int mode = O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY; | | 190 | int mode = O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY; |
190 | | | 191 | |
191 | outfd = open(*argv, mode, 0666); | | 192 | outfd = open(*argv, mode, 0666); |
192 | if (outfd < 0) | | 193 | if (outfd < 0) |
193 | err(1, "could not open %s", *argv); | | 194 | err(1, "could not open %s", *argv); |
194 | } else | | 195 | } else { |
| | | 196 | stdout_mode = true; |
195 | outfd = STDOUT_FILENO; | | 197 | outfd = STDOUT_FILENO; |
| | | 198 | } |
196 | | | 199 | |
197 | /* open the raw output file */ | | 200 | /* open the raw output file */ |
198 | if (raw_output) { | | 201 | if (raw_output) { |
199 | int mode = O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY; | | 202 | int mode = O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY; |
200 | | | 203 | |
201 | rawfd = open(raw_output, mode, 0666); | | 204 | rawfd = open(raw_output, mode, 0666); |
202 | if (rawfd < 0) | | 205 | if (rawfd < 0) |
203 | err(1, "could not open %s", raw_output); | | 206 | err(1, "could not open %s", raw_output); |
204 | } | | 207 | } |
205 | | | 208 | |
206 | /* start the midi timer */ | | 209 | /* start the midi timer */ |
207 | if (ioctl(midifd, SEQUENCER_TMR_START, NULL) < 0) { | | 210 | if (ioctl(midifd, SEQUENCER_TMR_START, NULL) < 0) { |
208 | if (ignore_timer_fail) | | 211 | if (ignore_timer_fail) |
| @@ -701,50 +704,50 @@ cleanup(int signo) | | | @@ -701,50 +704,50 @@ cleanup(int signo) |
701 | close(outfd); | | 704 | close(outfd); |
702 | close(midifd); | | 705 | close(midifd); |
703 | if (signo != 0) | | 706 | if (signo != 0) |
704 | (void)raise_default_signal(signo); | | 707 | (void)raise_default_signal(signo); |
705 | | | 708 | |
706 | exit(0); | | 709 | exit(0); |
707 | } | | 710 | } |
708 | | | 711 | |
709 | static void | | 712 | static void |
710 | rewrite_header(void) | | 713 | rewrite_header(void) |
711 | { | | 714 | { |
712 | | | 715 | |
713 | /* can't do this here! */ | | 716 | /* can't do this here! */ |
714 | if (outfd == STDOUT_FILENO) | | 717 | if (stdout_mode) |
715 | return; | | 718 | return; |
716 | | | 719 | |
717 | if (lseek(outfd, (off_t)0, SEEK_SET) == (off_t)-1) | | 720 | if (lseek(outfd, (off_t)0, SEEK_SET) == (off_t)-1) |
718 | err(1, "could not seek to start of file for header rewrite"); | | 721 | err(1, "could not seek to start of file for header rewrite"); |
719 | write_midi_header(); | | 722 | write_midi_header(); |
720 | } | | 723 | } |
721 | | | 724 | |
722 | #define BYTE1(x) ((x) & 0xff) | | 725 | #define BYTE1(x) ((x) & 0xff) |
723 | #define BYTE2(x) (((x) >> 8) & 0xff) | | 726 | #define BYTE2(x) (((x) >> 8) & 0xff) |
724 | #define BYTE3(x) (((x) >> 16) & 0xff) | | 727 | #define BYTE3(x) (((x) >> 16) & 0xff) |
725 | #define BYTE4(x) (((x) >> 24) & 0xff) | | 728 | #define BYTE4(x) (((x) >> 24) & 0xff) |
726 | | | 729 | |
727 | static void | | 730 | static void |
728 | write_midi_header(void) | | 731 | write_midi_header(void) |
729 | { | | 732 | { |
730 | unsigned char header[] = { | | 733 | unsigned char header[] = { |
731 | 'M', 'T', 'h', 'd', | | 734 | 'M', 'T', 'h', 'd', |
732 | 0, 0, 0, 6, | | 735 | 0, 0, 0, 6, |
733 | 0, 1, | | 736 | 0, 1, |
734 | 0, 0, /* ntracks */ | | 737 | 0, 0, /* ntracks */ |
735 | 0, 0, /* notes per beat */ | | 738 | 0, 0, /* notes per beat */ |
736 | }; | | 739 | }; |
737 | /* XXX only spport one track so far */ | | 740 | /* XXX only support one track so far */ |
738 | unsigned ntracks = 1; | | 741 | unsigned ntracks = 1; |
739 | unsigned char track[] = { | | 742 | unsigned char track[] = { |
740 | 'M', 'T', 'r', 'k', | | 743 | 'M', 'T', 'r', 'k', |
741 | 0, 0, 0, 0, | | 744 | 0, 0, 0, 0, |
742 | }; | | 745 | }; |
743 | unsigned char bpm[] = { | | 746 | unsigned char bpm[] = { |
744 | 0, 0xff, 0x51, 0x3, | | 747 | 0, 0xff, 0x51, 0x3, |
745 | 0, 0, 0, /* inverse tempo */ | | 748 | 0, 0, 0, /* inverse tempo */ |
746 | }; | | 749 | }; |
747 | unsigned total_size = data_size + sizeof header + sizeof track + sizeof bpm; | | 750 | unsigned total_size = data_size + sizeof header + sizeof track + sizeof bpm; |
748 | | | 751 | |
749 | header[10] = BYTE2(ntracks); | | 752 | header[10] = BYTE2(ntracks); |
750 | header[11] = BYTE1(ntracks); | | 753 | header[11] = BYTE1(ntracks); |