tarina

git clone https://git.tarina.org/tarina
Log | Files | Refs | README | LICENSE

arecordmidi.c (23879B)


      1 /*
      2  * arecordmidi.c - record standard MIDI files from sequencer ports
      3  *
      4  * Copyright (c) 2004-2005 Clemens Ladisch <clemens@ladisch.de>
      5  *
      6  *
      7  *  This program is free software; you can redistribute it and/or modify
      8  *  it under the terms of the GNU General Public License as published by
      9  *  the Free Software Foundation; either version 2 of the License, or
     10  *  (at your option) any later version.
     11  *
     12  *  This program is distributed in the hope that it will be useful,
     13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  *  GNU General Public License for more details.
     16  *
     17  *  You should have received a copy of the GNU General Public License
     18  *  along with this program; if not, write to the Free Software
     19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     20  */
     21 
     22 /* TODO: sequencer queue timer selection */
     23 
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <stdarg.h>
     27 #include <string.h>
     28 #include <signal.h>
     29 #include <getopt.h>
     30 #include <sys/poll.h>
     31 #include <alsa/asoundlib.h>
     32 #include "aconfig.h"
     33 #include "version.h"
     34 
     35 #define BUFFER_SIZE 4088
     36 
     37 /* linked list of buffers, stores data as in the .mid file */
     38 struct buffer {
     39 	struct buffer *next;
     40 	unsigned char buf[BUFFER_SIZE];
     41 };
     42 
     43 struct smf_track {
     44 	int size;			/* size of entire data */
     45 	int cur_buf_size;		/* size of cur_buf */
     46 	struct buffer *cur_buf;
     47 	snd_seq_tick_time_t last_tick;	/* end of track */
     48 	unsigned char last_command;	/* used for running status */
     49 	int used;			/* anything record on this track */
     50 	struct buffer first_buf;	/* list head */
     51 };
     52 
     53 /* timing/sysex + 16 channels */
     54 #define TRACKS_PER_PORT 17
     55 
     56 /* metronome settings */
     57 /* TODO: create options for this */
     58 #define METRONOME_CHANNEL 9
     59 #define METRONOME_STRONG_NOTE 34
     60 #define METRONOME_WEAK_NOTE 33
     61 #define METRONOME_VELOCITY 100
     62 #define METRONOME_PROGRAM 0
     63 
     64 static snd_seq_t *seq;
     65 static int client;
     66 static int port_count;
     67 static snd_seq_addr_t *ports;
     68 static int queue;
     69 static int smpte_timing = 0;
     70 static int beats = 120;
     71 static int frames;
     72 static int ticks = 0;
     73 static FILE *file;
     74 static int channel_split;
     75 static int num_tracks;
     76 static struct smf_track *tracks;
     77 static volatile sig_atomic_t stop = 0;
     78 static int use_metronome = 0;
     79 static snd_seq_addr_t metronome_port;
     80 static int metronome_weak_note = METRONOME_WEAK_NOTE;
     81 static int metronome_strong_note = METRONOME_STRONG_NOTE;
     82 static int metronome_velocity = METRONOME_VELOCITY;
     83 static int metronome_program = METRONOME_PROGRAM;
     84 static int metronome_channel = METRONOME_CHANNEL;
     85 static int ts_num = 4; /* time signature: numerator */
     86 static int ts_div = 4; /* time signature: denominator */
     87 static int ts_dd = 2; /* time signature: denominator as a power of two */
     88 
     89 
     90 /* prints an error message to stderr, and dies */
     91 static void fatal(const char *msg, ...)
     92 {
     93 	va_list ap;
     94 
     95 	va_start(ap, msg);
     96 	vfprintf(stderr, msg, ap);
     97 	va_end(ap);
     98 	fputc('\n', stderr);
     99 	exit(EXIT_FAILURE);
    100 }
    101 
    102 /* memory allocation error handling */
    103 static void check_mem(void *p)
    104 {
    105 	if (!p)
    106 		fatal("Out of memory");
    107 }
    108 
    109 /* error handling for ALSA functions */
    110 static void check_snd(const char *operation, int err)
    111 {
    112 	if (err < 0)
    113 		fatal("Cannot %s - %s", operation, snd_strerror(err));
    114 }
    115 
    116 static void init_seq(void)
    117 {
    118 	int err;
    119 
    120 	/* open sequencer */
    121 	err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
    122 	check_snd("open sequencer", err);
    123 
    124 	/* find out our client's id */
    125 	client = snd_seq_client_id(seq);
    126 	check_snd("get client id", client);
    127 
    128 	/* set our client's name */
    129 	err = snd_seq_set_client_name(seq, "arecordmidi");
    130 	check_snd("set client name", err);
    131 }
    132 
    133 /* parses one or more port addresses from the string */
    134 static void parse_ports(const char *arg)
    135 {
    136 	char *buf, *s, *port_name;
    137 	int err;
    138 
    139 	/* make a copy of the string because we're going to modify it */
    140 	buf = strdup(arg);
    141 	check_mem(buf);
    142 
    143 	for (port_name = s = buf; s; port_name = s + 1) {
    144 		/* Assume that ports are separated by commas.  We don't use
    145 		 * spaces because those are valid in client names. */
    146 		s = strchr(port_name, ',');
    147 		if (s)
    148 			*s = '\0';
    149 
    150 		++port_count;
    151 		ports = realloc(ports, port_count * sizeof(snd_seq_addr_t));
    152 		check_mem(ports);
    153 
    154 		err = snd_seq_parse_address(seq, &ports[port_count - 1], port_name);
    155 		if (err < 0)
    156 			fatal("Invalid port %s - %s", port_name, snd_strerror(err));
    157 	}
    158 
    159 	free(buf);
    160 }
    161 
    162 /* parses the metronome port address */
    163 static void init_metronome(const char *arg)
    164 {
    165 	int err;
    166 
    167 	err = snd_seq_parse_address(seq, &metronome_port, arg);
    168 	if (err < 0)
    169 		fatal("Invalid port %s - %s", arg, snd_strerror(err));
    170 	use_metronome = 1;
    171 }
    172 
    173 /* parses time signature specification */
    174 static void time_signature(const char *arg)
    175 {
    176 	long x = 0;
    177 	char *sep;
    178 
    179 	x = strtol(arg, &sep, 10);
    180 	if (x < 1 || x > 64 || *sep != ':')
    181 		fatal("Invalid time signature (%s)", arg);
    182 	ts_num = x;
    183 	x = strtol(++sep, NULL, 10);
    184 	if (x < 1 || x > 64)
    185 		fatal("Invalid time signature (%s)", arg);
    186 	ts_div = x;
    187 	for (ts_dd = 0; x > 1; x /= 2)
    188 		++ts_dd;
    189 }
    190 
    191 /*
    192  * Metronome implementation
    193  */
    194 static void metronome_note(unsigned char note, unsigned int tick)
    195 {
    196 	snd_seq_event_t ev;
    197 	snd_seq_ev_clear(&ev);
    198 	snd_seq_ev_set_note(&ev, metronome_channel, note, metronome_velocity, 1);
    199 	snd_seq_ev_schedule_tick(&ev, queue, 0, tick);
    200 	snd_seq_ev_set_source(&ev, port_count);
    201 	snd_seq_ev_set_subs(&ev);
    202 	snd_seq_event_output(seq, &ev);
    203 }
    204 
    205 static void metronome_echo(unsigned int tick)
    206 {
    207 	snd_seq_event_t ev;
    208 	snd_seq_ev_clear(&ev);
    209 	ev.type = SND_SEQ_EVENT_USR0;
    210 	snd_seq_ev_schedule_tick(&ev, queue, 0, tick);
    211 	snd_seq_ev_set_source(&ev, port_count);
    212 	snd_seq_ev_set_dest(&ev, client, port_count);
    213 	snd_seq_event_output(seq, &ev);
    214 }
    215 
    216 static void metronome_pattern(unsigned int tick)
    217 {
    218 	int j, t, duration;
    219 
    220 	t = tick;
    221 	duration = ticks * 4 / ts_div;
    222 	for (j = 0; j < ts_num; j++) {
    223 		metronome_note(j ? metronome_weak_note : metronome_strong_note, t);
    224 		t += duration;
    225 	}
    226 	metronome_echo(t);
    227 	snd_seq_drain_output(seq);
    228 }
    229 
    230 static void metronome_set_program(void)
    231 {
    232 	snd_seq_event_t ev;
    233 
    234 	snd_seq_ev_clear(&ev);
    235 	snd_seq_ev_set_pgmchange(&ev, metronome_channel, metronome_program);
    236 	snd_seq_ev_set_source(&ev, port_count);
    237 	snd_seq_ev_set_subs(&ev);
    238 	snd_seq_event_output(seq, &ev);
    239 }
    240 
    241 static void init_tracks(void)
    242 {
    243 	int i;
    244 
    245 	/* MIDI RP-019 says we need at least one track per port */
    246 	num_tracks = port_count;
    247 	/* Allocate one track for each possible channel.
    248 	 * Empty tracks won't be written to the file. */
    249 	if (channel_split)
    250 		num_tracks *= TRACKS_PER_PORT;
    251 
    252 	tracks = calloc(num_tracks, sizeof(struct smf_track));
    253 	check_mem(tracks);
    254 	for (i = 0; i < num_tracks; ++i)
    255 		tracks[i].cur_buf = &tracks[i].first_buf;
    256 }
    257 
    258 static void create_queue(void)
    259 {
    260 	snd_seq_queue_tempo_t *tempo;
    261 	int err;
    262 
    263 	queue = snd_seq_alloc_named_queue(seq, "arecordmidi");
    264 	check_snd("create queue", queue);
    265 
    266 	snd_seq_queue_tempo_alloca(&tempo);
    267 	if (!smpte_timing) {
    268 		snd_seq_queue_tempo_set_tempo(tempo, 60000000 / beats);
    269 		snd_seq_queue_tempo_set_ppq(tempo, ticks);
    270 	} else {
    271 		/*
    272 		 * ALSA doesn't know about the SMPTE time divisions, so
    273 		 * we pretend to have a musical tempo with the equivalent
    274 		 * number of ticks/s.
    275 		 */
    276 		switch (frames) {
    277 		case 24:
    278 			snd_seq_queue_tempo_set_tempo(tempo, 500000);
    279 			snd_seq_queue_tempo_set_ppq(tempo, 12 * ticks);
    280 			break;
    281 		case 25:
    282 			snd_seq_queue_tempo_set_tempo(tempo, 400000);
    283 			snd_seq_queue_tempo_set_ppq(tempo, 10 * ticks);
    284 			break;
    285 		case 29:
    286 			snd_seq_queue_tempo_set_tempo(tempo, 100000000);
    287 			snd_seq_queue_tempo_set_ppq(tempo, 2997 * ticks);
    288 			break;
    289 		case 30:
    290 			snd_seq_queue_tempo_set_tempo(tempo, 500000);
    291 			snd_seq_queue_tempo_set_ppq(tempo, 15 * ticks);
    292 			break;
    293 		default:
    294 			fatal("Invalid SMPTE frames %d", frames);
    295 		}
    296 	}
    297 	err = snd_seq_set_queue_tempo(seq, queue, tempo);
    298 	if (err < 0)
    299 		fatal("Cannot set queue tempo (%u/%i)",
    300 		      snd_seq_queue_tempo_get_tempo(tempo),
    301 		      snd_seq_queue_tempo_get_ppq(tempo));
    302 }
    303 
    304 static void create_ports(void)
    305 {
    306 	snd_seq_port_info_t *pinfo;
    307 	int i, err;
    308 	char name[32];
    309 
    310 	snd_seq_port_info_alloca(&pinfo);
    311 
    312 	/* common information for all our ports */
    313 	snd_seq_port_info_set_capability(pinfo,
    314 					 SND_SEQ_PORT_CAP_WRITE |
    315 					 SND_SEQ_PORT_CAP_SUBS_WRITE);
    316 	snd_seq_port_info_set_type(pinfo,
    317 				   SND_SEQ_PORT_TYPE_MIDI_GENERIC |
    318 				   SND_SEQ_PORT_TYPE_APPLICATION);
    319 	snd_seq_port_info_set_midi_channels(pinfo, 16);
    320 
    321 	/* we want to know when the events got delivered to us */
    322 	snd_seq_port_info_set_timestamping(pinfo, 1);
    323 	snd_seq_port_info_set_timestamp_queue(pinfo, queue);
    324 
    325 	/* our port number is the same as our port index */
    326 	snd_seq_port_info_set_port_specified(pinfo, 1);
    327 	for (i = 0; i < port_count; ++i) {
    328 		snd_seq_port_info_set_port(pinfo, i);
    329 
    330 		sprintf(name, "arecordmidi port %i", i);
    331 		snd_seq_port_info_set_name(pinfo, name);
    332 
    333 		err = snd_seq_create_port(seq, pinfo);
    334 		check_snd("create port", err);
    335 	}
    336 
    337 	/* create an optional metronome port */
    338 	if (use_metronome) {
    339 		snd_seq_port_info_set_port(pinfo, port_count);
    340 		snd_seq_port_info_set_name(pinfo, "arecordmidi metronome");
    341 		snd_seq_port_info_set_capability(pinfo,
    342 						 SND_SEQ_PORT_CAP_READ |
    343 						 SND_SEQ_PORT_CAP_WRITE);
    344 		snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_APPLICATION);
    345 		snd_seq_port_info_set_midi_channels(pinfo, 0);
    346 		snd_seq_port_info_set_timestamping(pinfo, 0);
    347 		err = snd_seq_create_port(seq, pinfo);
    348 		check_snd("create metronome port", err);
    349 	}
    350 }
    351 
    352 static void connect_ports(void)
    353 {
    354 	int i, err;
    355 
    356 	for (i = 0; i < port_count; ++i) {
    357 		err = snd_seq_connect_from(seq, i, ports[i].client, ports[i].port);
    358 		if (err < 0)
    359 			fatal("Cannot connect from port %d:%d - %s",
    360 			      ports[i].client, ports[i].port, snd_strerror(err));
    361 	}
    362 
    363 	/* subscribe the metronome port */
    364 	if (use_metronome) {
    365 	        err = snd_seq_connect_to(seq, port_count, metronome_port.client, metronome_port.port);
    366 		if (err < 0)
    367 	    		fatal("Cannot connect to port %d:%d - %s",
    368 			      metronome_port.client, metronome_port.port, snd_strerror(err));
    369 	}
    370 }
    371 
    372 /* records a byte to be written to the .mid file */
    373 static void add_byte(struct smf_track *track, unsigned char byte)
    374 {
    375 	/* make sure we have enough room in the current buffer */
    376 	if (track->cur_buf_size >= BUFFER_SIZE) {
    377 		track->cur_buf->next = calloc(1, sizeof(struct buffer));
    378 		if (!track->cur_buf->next)
    379 			fatal("out of memory");
    380 		track->cur_buf = track->cur_buf->next;
    381 		track->cur_buf_size = 0;
    382 	}
    383 
    384 	track->cur_buf->buf[track->cur_buf_size++] = byte;
    385 	track->size++;
    386 }
    387 
    388 /* record a variable-length quantity */
    389 static void var_value(struct smf_track *track, int v)
    390 {
    391 	if (v >= (1 << 28))
    392 		add_byte(track, 0x80 | ((v >> 28) & 0x03));
    393 	if (v >= (1 << 21))
    394 		add_byte(track, 0x80 | ((v >> 21) & 0x7f));
    395 	if (v >= (1 << 14))
    396 		add_byte(track, 0x80 | ((v >> 14) & 0x7f));
    397 	if (v >= (1 << 7))
    398 		add_byte(track, 0x80 | ((v >> 7) & 0x7f));
    399 	add_byte(track, v & 0x7f);
    400 }
    401 
    402 /* record the delta time from the last event */
    403 static void delta_time(struct smf_track *track, const snd_seq_event_t *ev)
    404 {
    405 	int diff = ev->time.tick - track->last_tick;
    406 	if (diff < 0)
    407 		diff = 0;
    408 	var_value(track, diff);
    409 	track->last_tick = ev->time.tick;
    410 }
    411 
    412 /* record a status byte (or not if we can use running status) */
    413 static void command(struct smf_track *track, unsigned char cmd)
    414 {
    415 	if (cmd != track->last_command)
    416 		add_byte(track, cmd);
    417 	track->last_command = cmd < 0xf0 ? cmd : 0;
    418 }
    419 
    420 /* put port numbers into all tracks */
    421 static void record_port_numbers(void)
    422 {
    423 	int i;
    424 
    425 	for (i = 0; i < num_tracks; ++i) {
    426 		var_value(&tracks[i], 0);
    427 		add_byte(&tracks[i], 0xff);
    428 		add_byte(&tracks[i], 0x21);
    429 		var_value(&tracks[i], 1);
    430 		if (channel_split)
    431 			add_byte(&tracks[i], i / TRACKS_PER_PORT);
    432 		else
    433 			add_byte(&tracks[i], i);
    434 	}
    435 }
    436 
    437 static void record_event(const snd_seq_event_t *ev)
    438 {
    439 	unsigned int i;
    440 	struct smf_track *track;
    441 
    442 	/* ignore events without proper timestamps */
    443 	if (ev->queue != queue || !snd_seq_ev_is_tick(ev))
    444 		return;
    445 
    446 	/* determine which track to record to */
    447 	i = ev->dest.port;
    448 	if (i == port_count) {
    449 		if (ev->type == SND_SEQ_EVENT_USR0)
    450 			metronome_pattern(ev->time.tick);
    451 		return;
    452 	}
    453 	if (channel_split) {
    454 		i *= TRACKS_PER_PORT;
    455 		if (snd_seq_ev_is_channel_type(ev))
    456 			i += 1 + (ev->data.note.channel & 0xf);
    457 	}
    458 	if (i >= num_tracks)
    459 		return;
    460 	track = &tracks[i];
    461 
    462 	switch (ev->type) {
    463 	case SND_SEQ_EVENT_NOTEON:
    464 		delta_time(track, ev);
    465 		command(track, MIDI_CMD_NOTE_ON | (ev->data.note.channel & 0xf));
    466 		add_byte(track, ev->data.note.note & 0x7f);
    467 		add_byte(track, ev->data.note.velocity & 0x7f);
    468 		break;
    469 	case SND_SEQ_EVENT_NOTEOFF:
    470 		delta_time(track, ev);
    471 		command(track, MIDI_CMD_NOTE_OFF | (ev->data.note.channel & 0xf));
    472 		add_byte(track, ev->data.note.note & 0x7f);
    473 		add_byte(track, ev->data.note.velocity & 0x7f);
    474 		break;
    475 	case SND_SEQ_EVENT_KEYPRESS:
    476 		delta_time(track, ev);
    477 		command(track, MIDI_CMD_NOTE_PRESSURE | (ev->data.note.channel & 0xf));
    478 		add_byte(track, ev->data.note.note & 0x7f);
    479 		add_byte(track, ev->data.note.velocity & 0x7f);
    480 		break;
    481 	case SND_SEQ_EVENT_CONTROLLER:
    482 		delta_time(track, ev);
    483 		command(track, MIDI_CMD_CONTROL | (ev->data.control.channel & 0xf));
    484 		add_byte(track, ev->data.control.param & 0x7f);
    485 		add_byte(track, ev->data.control.value & 0x7f);
    486 		break;
    487 	case SND_SEQ_EVENT_PGMCHANGE:
    488 		delta_time(track, ev);
    489 		command(track, MIDI_CMD_PGM_CHANGE | (ev->data.control.channel & 0xf));
    490 		add_byte(track, ev->data.control.value & 0x7f);
    491 		break;
    492 	case SND_SEQ_EVENT_CHANPRESS:
    493 		delta_time(track, ev);
    494 		command(track, MIDI_CMD_CHANNEL_PRESSURE | (ev->data.control.channel & 0xf));
    495 		add_byte(track, ev->data.control.value & 0x7f);
    496 		break;
    497 	case SND_SEQ_EVENT_PITCHBEND:
    498 		delta_time(track, ev);
    499 		command(track, MIDI_CMD_BENDER | (ev->data.control.channel & 0xf));
    500 		add_byte(track, (ev->data.control.value + 8192) & 0x7f);
    501 		add_byte(track, ((ev->data.control.value + 8192) >> 7) & 0x7f);
    502 		break;
    503 	case SND_SEQ_EVENT_CONTROL14:
    504 		/* create two commands for MSB and LSB */
    505 		delta_time(track, ev);
    506 		command(track, MIDI_CMD_CONTROL | (ev->data.control.channel & 0xf));
    507 		add_byte(track, ev->data.control.param & 0x7f);
    508 		add_byte(track, (ev->data.control.value >> 7) & 0x7f);
    509 		if ((ev->data.control.param & 0x7f) < 0x20) {
    510 			delta_time(track, ev);
    511 			/* running status */
    512 			add_byte(track, (ev->data.control.param & 0x7f) + 0x20);
    513 			add_byte(track, ev->data.control.value & 0x7f);
    514 		}
    515 		break;
    516 	case SND_SEQ_EVENT_NONREGPARAM:
    517 		delta_time(track, ev);
    518 		command(track, MIDI_CMD_CONTROL | (ev->data.control.channel & 0xf));
    519 		add_byte(track, MIDI_CTL_NONREG_PARM_NUM_LSB);
    520 		add_byte(track, ev->data.control.param & 0x7f);
    521 		delta_time(track, ev);
    522 		add_byte(track, MIDI_CTL_NONREG_PARM_NUM_MSB);
    523 		add_byte(track, (ev->data.control.param >> 7) & 0x7f);
    524 		delta_time(track, ev);
    525 		add_byte(track, MIDI_CTL_MSB_DATA_ENTRY);
    526 		add_byte(track, (ev->data.control.value >> 7) & 0x7f);
    527 		delta_time(track, ev);
    528 		add_byte(track, MIDI_CTL_LSB_DATA_ENTRY);
    529 		add_byte(track, ev->data.control.value & 0x7f);
    530 		break;
    531 	case SND_SEQ_EVENT_REGPARAM:
    532 		delta_time(track, ev);
    533 		command(track, MIDI_CMD_CONTROL | (ev->data.control.channel & 0xf));
    534 		add_byte(track, MIDI_CTL_REGIST_PARM_NUM_LSB);
    535 		add_byte(track, ev->data.control.param & 0x7f);
    536 		delta_time(track, ev);
    537 		add_byte(track, MIDI_CTL_REGIST_PARM_NUM_MSB);
    538 		add_byte(track, (ev->data.control.param >> 7) & 0x7f);
    539 		delta_time(track, ev);
    540 		add_byte(track, MIDI_CTL_MSB_DATA_ENTRY);
    541 		add_byte(track, (ev->data.control.value >> 7) & 0x7f);
    542 		delta_time(track, ev);
    543 		add_byte(track, MIDI_CTL_LSB_DATA_ENTRY);
    544 		add_byte(track, ev->data.control.value & 0x7f);
    545 		break;
    546 #if 0	/* ignore */
    547 	case SND_SEQ_EVENT_SONGPOS:
    548 	case SND_SEQ_EVENT_SONGSEL:
    549 	case SND_SEQ_EVENT_QFRAME:
    550 	case SND_SEQ_EVENT_START:
    551 	case SND_SEQ_EVENT_CONTINUE:
    552 	case SND_SEQ_EVENT_STOP:
    553 	case SND_SEQ_EVENT_TUNE_REQUEST:
    554 	case SND_SEQ_EVENT_RESET:
    555 	case SND_SEQ_EVENT_SENSING:
    556 		break;
    557 #endif
    558 	case SND_SEQ_EVENT_SYSEX:
    559 		if (ev->data.ext.len == 0)
    560 			break;
    561 		delta_time(track, ev);
    562 		if (*(unsigned char*)ev->data.ext.ptr == 0xf0)
    563 			command(track, 0xf0), i = 1;
    564 		else
    565 			command(track, 0xf7), i = 0;
    566 		var_value(track, ev->data.ext.len - i);
    567 		for (; i < ev->data.ext.len; ++i)
    568 			add_byte(track, ((unsigned char*)ev->data.ext.ptr)[i]);
    569 		break;
    570 	default:
    571 		return;
    572 	}
    573 	track->used = 1;
    574 }
    575 
    576 static void finish_tracks(void)
    577 {
    578 	snd_seq_queue_status_t *queue_status;
    579 	int tick, i, err;
    580 
    581 	snd_seq_queue_status_alloca(&queue_status);
    582 
    583 	err = snd_seq_get_queue_status(seq, queue, queue_status);
    584 	check_snd("get queue status", err);
    585 	tick = snd_seq_queue_status_get_tick_time(queue_status);
    586 
    587 	/* make length of first track the recording length */
    588 	var_value(&tracks[0], tick - tracks[0].last_tick);
    589 	add_byte(&tracks[0], 0xff);
    590 	add_byte(&tracks[0], 0x2f);
    591 	var_value(&tracks[0], 0);
    592 
    593 	/* finish other tracks */
    594 	for (i = 1; i < num_tracks; ++i) {
    595 		var_value(&tracks[i], 0);
    596 		add_byte(&tracks[i], 0xff);
    597 		add_byte(&tracks[i], 0x2f);
    598 		var_value(&tracks[i], 0);
    599 	}
    600 }
    601 
    602 static void write_file(void)
    603 {
    604 	int used_tracks, time_division, i;
    605 	struct buffer *buf;
    606 
    607 	used_tracks = 0;
    608 	for (i = 0; i < num_tracks; ++i)
    609 		used_tracks += !!tracks[i].used;
    610 
    611 	/* header id and length */
    612 	fwrite("MThd\0\0\0\6", 1, 8, file);
    613 	/* type 0 or 1 */
    614 	fputc(0, file);
    615 	fputc(used_tracks > 1, file);
    616 	/* number of tracks */
    617 	fputc((used_tracks >> 8) & 0xff, file);
    618 	fputc(used_tracks & 0xff, file);
    619 	/* time division */
    620 	time_division = ticks;
    621 	if (smpte_timing)
    622 		time_division |= (0x100 - frames) << 8;
    623 	fputc(time_division >> 8, file);
    624 	fputc(time_division & 0xff, file);
    625 
    626 	for (i = 0; i < num_tracks; ++i) {
    627 		if (!tracks[i].used)
    628 			continue;
    629 		/* track id */
    630 		fwrite("MTrk", 1, 4, file);
    631 		/* data length */
    632 		fputc((tracks[i].size >> 24) & 0xff, file);
    633 		fputc((tracks[i].size >> 16) & 0xff, file);
    634 		fputc((tracks[i].size >> 8) & 0xff, file);
    635 		fputc(tracks[i].size & 0xff, file);
    636 		/* track contents */
    637 		for (buf = &tracks[i].first_buf; buf; buf = buf->next)
    638 			fwrite(buf->buf, 1, buf == tracks[i].cur_buf
    639 			       ? tracks[i].cur_buf_size : BUFFER_SIZE, file);
    640 	}
    641 }
    642 
    643 static void list_ports(void)
    644 {
    645 	snd_seq_client_info_t *cinfo;
    646 	snd_seq_port_info_t *pinfo;
    647 
    648 	snd_seq_client_info_alloca(&cinfo);
    649 	snd_seq_port_info_alloca(&pinfo);
    650 
    651 	puts(" Port    Client name                      Port name");
    652 
    653 	snd_seq_client_info_set_client(cinfo, -1);
    654 	while (snd_seq_query_next_client(seq, cinfo) >= 0) {
    655 		int client = snd_seq_client_info_get_client(cinfo);
    656 
    657 		if (client == SND_SEQ_CLIENT_SYSTEM)
    658 			continue; /* don't show system timer and announce ports */
    659 		snd_seq_port_info_set_client(pinfo, client);
    660 		snd_seq_port_info_set_port(pinfo, -1);
    661 		while (snd_seq_query_next_port(seq, pinfo) >= 0) {
    662 			/* port must understand MIDI messages */
    663 			if (!(snd_seq_port_info_get_type(pinfo)
    664 			      & SND_SEQ_PORT_TYPE_MIDI_GENERIC))
    665 				continue;
    666 			/* we need both READ and SUBS_READ */
    667 			if ((snd_seq_port_info_get_capability(pinfo)
    668 			     & (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ))
    669 			    != (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ))
    670 				continue;
    671 			printf("%3d:%-3d  %-32.32s %s\n",
    672 			       snd_seq_port_info_get_client(pinfo),
    673 			       snd_seq_port_info_get_port(pinfo),
    674 			       snd_seq_client_info_get_name(cinfo),
    675 			       snd_seq_port_info_get_name(pinfo));
    676 		}
    677 	}
    678 }
    679 
    680 static void help(const char *argv0)
    681 {
    682 	fprintf(stderr, "Usage: %s [options] outputfile\n"
    683 		"\nAvailable options:\n"
    684 		"  -h,--help                  this help\n"
    685 		"  -V,--version               show version\n"
    686 		"  -l,--list                  list input ports\n"
    687 		"  -p,--port=client:port,...  source port(s)\n"
    688 		"  -b,--bpm=beats             tempo in beats per minute\n"
    689 		"  -f,--fps=frames            resolution in frames per second (SMPTE)\n"
    690 		"  -t,--ticks=ticks           resolution in ticks per beat or frame\n"
    691 		"  -s,--split-channels        create a track for each channel\n"
    692 		"  -m,--metronome=client:port play a metronome signal\n"
    693 		"  -i,--timesig=nn:dd         time signature\n",
    694 		argv0);
    695 }
    696 
    697 static void version(void)
    698 {
    699 	fputs("arecordmidi version " SND_UTIL_VERSION_STR "\n", stderr);
    700 }
    701 
    702 static void sighandler(int sig)
    703 {
    704 	stop = 1;
    705 }
    706 
    707 int main(int argc, char *argv[])
    708 {
    709 	static const char short_options[] = "hVlp:b:f:t:sdm:i:";
    710 	static const struct option long_options[] = {
    711 		{"help", 0, NULL, 'h'},
    712 		{"version", 0, NULL, 'V'},
    713 		{"list", 0, NULL, 'l'},
    714 		{"port", 1, NULL, 'p'},
    715 		{"bpm", 1, NULL, 'b'},
    716 		{"fps", 1, NULL, 'f'},
    717 		{"ticks", 1, NULL, 't'},
    718 		{"split-channels", 0, NULL, 's'},
    719 		{"dump", 0, NULL, 'd'},
    720 		{"metronome", 1, NULL, 'm'},
    721 		{"timesig", 1, NULL, 'i'},
    722 		{ }
    723 	};
    724 
    725 	char *filename = NULL;
    726 	int do_list = 0;
    727 	struct pollfd *pfds;
    728 	int npfds;
    729 	int c, err;
    730 
    731 	init_seq();
    732 
    733 	while ((c = getopt_long(argc, argv, short_options,
    734 				long_options, NULL)) != -1) {
    735 		switch (c) {
    736 		case 'h':
    737 			help(argv[0]);
    738 			return 0;
    739 		case 'V':
    740 			version();
    741 			return 0;
    742 		case 'l':
    743 			do_list = 1;
    744 			break;
    745 		case 'p':
    746 			parse_ports(optarg);
    747 			break;
    748 		case 'b':
    749 			beats = atoi(optarg);
    750 			if (beats < 4 || beats > 6000)
    751 				fatal("Invalid tempo");
    752 			smpte_timing = 0;
    753 			break;
    754 		case 'f':
    755 			frames = atoi(optarg);
    756 			if (frames != 24 && frames != 25 &&
    757 			    frames != 29 && frames != 30)
    758 				fatal("Invalid number of frames/s");
    759 			smpte_timing = 1;
    760 			break;
    761 		case 't':
    762 			ticks = atoi(optarg);
    763 			if (ticks < 1 || ticks > 0x7fff)
    764 				fatal("Invalid number of ticks");
    765 			break;
    766 		case 's':
    767 			channel_split = 1;
    768 			break;
    769 		case 'd':
    770 			fputs("The --dump option isn't supported anymore, use aseqdump instead.\n", stderr);
    771 			break;
    772 		case 'm':
    773 			init_metronome(optarg);
    774 			break;
    775 		case 'i':
    776 			time_signature(optarg);
    777 			break;
    778 		default:
    779 			help(argv[0]);
    780 			return 1;
    781 		}
    782 	}
    783 
    784 	if (do_list) {
    785 		list_ports();
    786 		return 0;
    787 	}
    788 
    789 	if (port_count < 1) {
    790 		fputs("Pleast specify a source port with --port.\n", stderr);
    791 		return 1;
    792 	}
    793 
    794 	if (!ticks)
    795 		ticks = smpte_timing ? 40 : 384;
    796 	if (smpte_timing && ticks > 0xff)
    797 		ticks = 0xff;
    798 
    799 	if (optind >= argc) {
    800 		fputs("Please specify a file to record to.\n", stderr);
    801 		return 1;
    802 	}
    803 	filename = argv[optind];
    804 
    805 	init_tracks();
    806 	create_queue();
    807 	create_ports();
    808 	connect_ports();
    809 	if (port_count > 1)
    810 		record_port_numbers();
    811 
    812 	/* record tempo */
    813 	if (!smpte_timing) {
    814 		int usecs_per_quarter = 60000000 / beats;
    815 		var_value(&tracks[0], 0); /* delta time */
    816 		add_byte(&tracks[0], 0xff);
    817 		add_byte(&tracks[0], 0x51);
    818 		var_value(&tracks[0], 3);
    819 		add_byte(&tracks[0], usecs_per_quarter >> 16);
    820 		add_byte(&tracks[0], usecs_per_quarter >> 8);
    821 		add_byte(&tracks[0], usecs_per_quarter);
    822 
    823 		/* time signature */
    824 		var_value(&tracks[0], 0); /* delta time */
    825 		add_byte(&tracks[0], 0xff);
    826 		add_byte(&tracks[0], 0x58);
    827 		var_value(&tracks[0], 4);
    828 		add_byte(&tracks[0], ts_num);
    829 		add_byte(&tracks[0], ts_dd);
    830 		add_byte(&tracks[0], 24); /* MIDI clocks per metronome click */
    831 		add_byte(&tracks[0], 8); /* notated 32nd-notes per MIDI quarter note */
    832 	}
    833 	
    834 	/* always write at least one track */
    835 	tracks[0].used = 1;
    836 
    837 	file = fopen(filename, "wb");
    838 	if (!file)
    839 		fatal("Cannot open %s - %s", filename, strerror(errno));
    840 
    841 	err = snd_seq_start_queue(seq, queue, NULL);
    842 	check_snd("start queue", err);
    843 	snd_seq_drain_output(seq);
    844 
    845 	err = snd_seq_nonblock(seq, 1);
    846 	check_snd("set nonblock mode", err);
    847 	
    848 	if (use_metronome) {
    849 		metronome_set_program();
    850 		metronome_pattern(0);
    851 	}
    852 
    853 	signal(SIGINT, sighandler);
    854 	signal(SIGTERM, sighandler);
    855 
    856 	npfds = snd_seq_poll_descriptors_count(seq, POLLIN);
    857 	pfds = alloca(sizeof(*pfds) * npfds);
    858 	for (;;) {
    859 		snd_seq_poll_descriptors(seq, pfds, npfds, POLLIN);
    860 		if (poll(pfds, npfds, -1) < 0)
    861 			break;
    862 		do {
    863 			snd_seq_event_t *event;
    864 			err = snd_seq_event_input(seq, &event);
    865 			if (err < 0)
    866 				break;
    867 			if (event)
    868 				record_event(event);
    869 		} while (err > 0);
    870 		if (stop)
    871 			break;
    872 	}
    873 
    874 	finish_tracks();
    875 	write_file();
    876 
    877 	fclose(file);
    878 	snd_seq_close(seq);
    879 	return 0;
    880 }