diff options
author | 2013-01-11 07:32:46 +0000 | |
---|---|---|
committer | 2013-01-11 07:32:46 +0000 | |
commit | 0e19f641d3186cdbf51f8ca857e2b07ab95779c2 (patch) | |
tree | 234109de1123b13f217494af4b3f8efad346d5cc /src/lib/portmidi/pmlinuxalsa.c | |
parent | 111157ca09a9ff60fe4a9ba49173c315e94314fa (diff) |
Cleanups and version bumpmame0148
Diffstat (limited to 'src/lib/portmidi/pmlinuxalsa.c')
-rw-r--r-- | src/lib/portmidi/pmlinuxalsa.c | 1224 |
1 files changed, 612 insertions, 612 deletions
diff --git a/src/lib/portmidi/pmlinuxalsa.c b/src/lib/portmidi/pmlinuxalsa.c index 1e69ea00e60..8d565deaac9 100644 --- a/src/lib/portmidi/pmlinuxalsa.c +++ b/src/lib/portmidi/pmlinuxalsa.c @@ -1,11 +1,11 @@ /* * pmlinuxalsa.c -- system specific definitions - * + * * written by: * Roger Dannenberg (port to Alsa 0.9.x) * Clemens Ladisch (provided code examples and invaluable consulting) * Jason Cohen, Rico Colon, Matt Filippone (Alsa 0.5.x implementation) - */ + */ #include "stdlib.h" #include "portmidi.h" @@ -49,17 +49,17 @@ typedef UINT32 FPTR; extern pm_fns_node pm_linuxalsa_in_dictionary; extern pm_fns_node pm_linuxalsa_out_dictionary; -static snd_seq_t *seq = NULL; // all input comes here, - // output queue allocated on seq +static snd_seq_t *seq = NULL; // all input comes here, + // output queue allocated on seq static int queue, queue_used; /* one for all ports, reference counted */ typedef struct alsa_descriptor_struct { - int client; - int port; - int this_port; - int in_sysex; - snd_midi_event_t *parser; - int error; /* host error code */ + int client; + int port; + int this_port; + int in_sysex; + snd_midi_event_t *parser; + int error; /* host error code */ } alsa_descriptor_node, *alsa_descriptor_type; @@ -67,324 +67,324 @@ typedef struct alsa_descriptor_struct { /**/ static void get_alsa_error_text(char *msg, int len, int err) { - int errlen = strlen(snd_strerror(err)); - if (errlen < len) { - strcpy(msg, snd_strerror(err)); - } else if (len > 20) { - sprintf(msg, "Alsa error %d", err); - } else if (len > 4) { - strcpy(msg, "Alsa"); - } else { - msg[0] = 0; - } + int errlen = strlen(snd_strerror(err)); + if (errlen < len) { + strcpy(msg, snd_strerror(err)); + } else if (len > 20) { + sprintf(msg, "Alsa error %d", err); + } else if (len > 4) { + strcpy(msg, "Alsa"); + } else { + msg[0] = 0; + } } /* queue is shared by both input and output, reference counted */ static PmError alsa_use_queue(void) { - if (queue_used == 0) { - snd_seq_queue_tempo_t *tempo; - - queue = snd_seq_alloc_queue(seq); - if (queue < 0) { - pm_hosterror = queue; - return pmHostError; - } - snd_seq_queue_tempo_alloca(&tempo); - snd_seq_queue_tempo_set_tempo(tempo, 480000); - snd_seq_queue_tempo_set_ppq(tempo, 480); - pm_hosterror = snd_seq_set_queue_tempo(seq, queue, tempo); - if (pm_hosterror < 0) - return pmHostError; - - snd_seq_start_queue(seq, queue, NULL); - snd_seq_drain_output(seq); - } - ++queue_used; - return pmNoError; + if (queue_used == 0) { + snd_seq_queue_tempo_t *tempo; + + queue = snd_seq_alloc_queue(seq); + if (queue < 0) { + pm_hosterror = queue; + return pmHostError; + } + snd_seq_queue_tempo_alloca(&tempo); + snd_seq_queue_tempo_set_tempo(tempo, 480000); + snd_seq_queue_tempo_set_ppq(tempo, 480); + pm_hosterror = snd_seq_set_queue_tempo(seq, queue, tempo); + if (pm_hosterror < 0) + return pmHostError; + + snd_seq_start_queue(seq, queue, NULL); + snd_seq_drain_output(seq); + } + ++queue_used; + return pmNoError; } static void alsa_unuse_queue(void) { - if (--queue_used == 0) { - snd_seq_stop_queue(seq, queue, NULL); - snd_seq_drain_output(seq); - snd_seq_free_queue(seq, queue); - VERBOSE printf("queue freed\n"); - } + if (--queue_used == 0) { + snd_seq_stop_queue(seq, queue, NULL); + snd_seq_drain_output(seq); + snd_seq_free_queue(seq, queue); + VERBOSE printf("queue freed\n"); + } } /* midi_message_length -- how many bytes in a message? */ static int midi_message_length(PmMessage message) { - message &= 0xff; - if (message < 0x80) { - return 0; - } else if (message < 0xf0) { - static const int length[] = {3, 3, 3, 3, 2, 2, 3}; - return length[(message - 0x80) >> 4]; - } else { - static const int length[] = { - -1, 2, 3, 2, 0, 0, 1, -1, 1, 0, 1, 1, 1, 0, 1, 1}; - return length[message - 0xf0]; - } + message &= 0xff; + if (message < 0x80) { + return 0; + } else if (message < 0xf0) { + static const int length[] = {3, 3, 3, 3, 2, 2, 3}; + return length[(message - 0x80) >> 4]; + } else { + static const int length[] = { + -1, 2, 3, 2, 0, 0, 1, -1, 1, 0, 1, 1, 1, 0, 1, 1}; + return length[message - 0xf0]; + } } -static PmError alsa_out_open(PmInternal *midi, void *driverInfo) +static PmError alsa_out_open(PmInternal *midi, void *driverInfo) { - void *client_port = descriptors[midi->device_id].descriptor; - alsa_descriptor_type desc = (alsa_descriptor_type) - pm_alloc(sizeof(alsa_descriptor_node)); - snd_seq_port_info_t *info; - int err; - - if (!desc) return pmInsufficientMemory; - - snd_seq_port_info_alloca(&info); - snd_seq_port_info_set_port(info, midi->device_id); - snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE | - SND_SEQ_PORT_CAP_READ); - snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC | - SND_SEQ_PORT_TYPE_APPLICATION); - snd_seq_port_info_set_port_specified(info, 1); - err = snd_seq_create_port(seq, info); - if (err < 0) goto free_desc; - - /* fill in fields of desc, which is passed to pm_write routines */ - midi->descriptor = desc; - desc->client = GET_DESCRIPTOR_CLIENT(client_port); - desc->port = GET_DESCRIPTOR_PORT(client_port); - desc->this_port = midi->device_id; - desc->in_sysex = 0; - - desc->error = 0; - - err = snd_midi_event_new(PM_DEFAULT_SYSEX_BUFFER_SIZE, &desc->parser); - if (err < 0) goto free_this_port; - - if (midi->latency > 0) { /* must delay output using a queue */ - err = alsa_use_queue(); - if (err < 0) goto free_parser; - - err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port); - if (err < 0) goto unuse_queue; /* clean up and return on error */ - } else { - err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port); - if (err < 0) goto free_parser; /* clean up and return on error */ - } - return pmNoError; - - unuse_queue: - alsa_unuse_queue(); - free_parser: - snd_midi_event_free(desc->parser); - free_this_port: - snd_seq_delete_port(seq, desc->this_port); - free_desc: - pm_free(desc); - pm_hosterror = err; - if (err < 0) { - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err); - } - return pmHostError; + void *client_port = descriptors[midi->device_id].descriptor; + alsa_descriptor_type desc = (alsa_descriptor_type) + pm_alloc(sizeof(alsa_descriptor_node)); + snd_seq_port_info_t *info; + int err; + + if (!desc) return pmInsufficientMemory; + + snd_seq_port_info_alloca(&info); + snd_seq_port_info_set_port(info, midi->device_id); + snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE | + SND_SEQ_PORT_CAP_READ); + snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC | + SND_SEQ_PORT_TYPE_APPLICATION); + snd_seq_port_info_set_port_specified(info, 1); + err = snd_seq_create_port(seq, info); + if (err < 0) goto free_desc; + + /* fill in fields of desc, which is passed to pm_write routines */ + midi->descriptor = desc; + desc->client = GET_DESCRIPTOR_CLIENT(client_port); + desc->port = GET_DESCRIPTOR_PORT(client_port); + desc->this_port = midi->device_id; + desc->in_sysex = 0; + + desc->error = 0; + + err = snd_midi_event_new(PM_DEFAULT_SYSEX_BUFFER_SIZE, &desc->parser); + if (err < 0) goto free_this_port; + + if (midi->latency > 0) { /* must delay output using a queue */ + err = alsa_use_queue(); + if (err < 0) goto free_parser; + + err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port); + if (err < 0) goto unuse_queue; /* clean up and return on error */ + } else { + err = snd_seq_connect_to(seq, desc->this_port, desc->client, desc->port); + if (err < 0) goto free_parser; /* clean up and return on error */ + } + return pmNoError; + + unuse_queue: + alsa_unuse_queue(); + free_parser: + snd_midi_event_free(desc->parser); + free_this_port: + snd_seq_delete_port(seq, desc->this_port); + free_desc: + pm_free(desc); + pm_hosterror = err; + if (err < 0) { + get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err); + } + return pmHostError; } - -static PmError alsa_write_byte(PmInternal *midi, unsigned char byte, - PmTimestamp timestamp) + +static PmError alsa_write_byte(PmInternal *midi, unsigned char byte, + PmTimestamp timestamp) { - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - snd_seq_event_t ev; - int err; - - snd_seq_ev_clear(&ev); - if (snd_midi_event_encode_byte(desc->parser, byte, &ev) == 1) { - snd_seq_ev_set_dest(&ev, desc->client, desc->port); - snd_seq_ev_set_source(&ev, desc->this_port); - if (midi->latency > 0) { - /* compute relative time of event = timestamp - now + latency */ - PmTimestamp now = (midi->time_proc ? - midi->time_proc(midi->time_info) : - Pt_Time()); - int when = timestamp; - /* if timestamp is zero, send immediately */ - /* otherwise compute time delay and use delay if positive */ - if (when == 0) when = now; - when = (when - now) + midi->latency; - if (when < 0) when = 0; - VERBOSE printf("timestamp %d now %d latency %d, ", - (int) timestamp, (int) now, midi->latency); - VERBOSE printf("scheduling event after %d\n", when); - /* message is sent in relative ticks, where 1 tick = 1 ms */ - snd_seq_ev_schedule_tick(&ev, queue, 1, when); - /* NOTE: for cases where the user does not supply a time function, - we could optimize the code by not starting Pt_Time and using - the alsa tick time instead. I didn't do this because it would - entail changing the queue management to start the queue tick - count when PortMidi is initialized and keep it running until - PortMidi is terminated. (This should be simple, but it's not - how the code works now.) -RBD */ - } else { /* send event out without queueing */ - VERBOSE printf("direct\n"); - /* ev.queue = SND_SEQ_QUEUE_DIRECT; - ev.dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS; */ - snd_seq_ev_set_direct(&ev); - } - VERBOSE printf("sending event\n"); - err = snd_seq_event_output(seq, &ev); - if (err < 0) { - desc->error = err; - return pmHostError; - } - } - return pmNoError; + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + snd_seq_event_t ev; + int err; + + snd_seq_ev_clear(&ev); + if (snd_midi_event_encode_byte(desc->parser, byte, &ev) == 1) { + snd_seq_ev_set_dest(&ev, desc->client, desc->port); + snd_seq_ev_set_source(&ev, desc->this_port); + if (midi->latency > 0) { + /* compute relative time of event = timestamp - now + latency */ + PmTimestamp now = (midi->time_proc ? + midi->time_proc(midi->time_info) : + Pt_Time()); + int when = timestamp; + /* if timestamp is zero, send immediately */ + /* otherwise compute time delay and use delay if positive */ + if (when == 0) when = now; + when = (when - now) + midi->latency; + if (when < 0) when = 0; + VERBOSE printf("timestamp %d now %d latency %d, ", + (int) timestamp, (int) now, midi->latency); + VERBOSE printf("scheduling event after %d\n", when); + /* message is sent in relative ticks, where 1 tick = 1 ms */ + snd_seq_ev_schedule_tick(&ev, queue, 1, when); + /* NOTE: for cases where the user does not supply a time function, + we could optimize the code by not starting Pt_Time and using + the alsa tick time instead. I didn't do this because it would + entail changing the queue management to start the queue tick + count when PortMidi is initialized and keep it running until + PortMidi is terminated. (This should be simple, but it's not + how the code works now.) -RBD */ + } else { /* send event out without queueing */ + VERBOSE printf("direct\n"); + /* ev.queue = SND_SEQ_QUEUE_DIRECT; + ev.dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS; */ + snd_seq_ev_set_direct(&ev); + } + VERBOSE printf("sending event\n"); + err = snd_seq_event_output(seq, &ev); + if (err < 0) { + desc->error = err; + return pmHostError; + } + } + return pmNoError; } static PmError alsa_out_close(PmInternal *midi) { - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - if (!desc) return pmBadPtr; - - if ((pm_hosterror = snd_seq_disconnect_to(seq, desc->this_port, - desc->client, desc->port))) { - // if there's an error, try to delete the port anyway, but don't - // change the pm_hosterror value so we retain the first error - snd_seq_delete_port(seq, desc->this_port); - } else { // if there's no error, delete the port and retain any error - pm_hosterror = snd_seq_delete_port(seq, desc->this_port); - } - if (midi->latency > 0) alsa_unuse_queue(); - snd_midi_event_free(desc->parser); - midi->descriptor = NULL; /* destroy the pointer to signify "closed" */ - pm_free(desc); - if (pm_hosterror) { - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, - pm_hosterror); - return pmHostError; - } - return pmNoError; + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + if (!desc) return pmBadPtr; + + if ((pm_hosterror = snd_seq_disconnect_to(seq, desc->this_port, + desc->client, desc->port))) { + // if there's an error, try to delete the port anyway, but don't + // change the pm_hosterror value so we retain the first error + snd_seq_delete_port(seq, desc->this_port); + } else { // if there's no error, delete the port and retain any error + pm_hosterror = snd_seq_delete_port(seq, desc->this_port); + } + if (midi->latency > 0) alsa_unuse_queue(); + snd_midi_event_free(desc->parser); + midi->descriptor = NULL; /* destroy the pointer to signify "closed" */ + pm_free(desc); + if (pm_hosterror) { + get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, + pm_hosterror); + return pmHostError; + } + return pmNoError; } static PmError alsa_in_open(PmInternal *midi, void *driverInfo) { - void *client_port = descriptors[midi->device_id].descriptor; - alsa_descriptor_type desc = (alsa_descriptor_type) - pm_alloc(sizeof(alsa_descriptor_node)); - snd_seq_port_info_t *info; - snd_seq_port_subscribe_t *sub; - snd_seq_addr_t addr; - int err; - - if (!desc) return pmInsufficientMemory; - - err = alsa_use_queue(); - if (err < 0) goto free_desc; - - snd_seq_port_info_alloca(&info); - snd_seq_port_info_set_port(info, midi->device_id); - snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE | - SND_SEQ_PORT_CAP_READ); - snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC | - SND_SEQ_PORT_TYPE_APPLICATION); - snd_seq_port_info_set_port_specified(info, 1); - err = snd_seq_create_port(seq, info); - if (err < 0) goto free_queue; - - /* fill in fields of desc, which is passed to pm_write routines */ - midi->descriptor = desc; - desc->client = GET_DESCRIPTOR_CLIENT(client_port); - desc->port = GET_DESCRIPTOR_PORT(client_port); - desc->this_port = midi->device_id; - desc->in_sysex = 0; - - desc->error = 0; - - VERBOSE printf("snd_seq_connect_from: %d %d %d\n", - desc->this_port, desc->client, desc->port); - snd_seq_port_subscribe_alloca(&sub); - addr.client = snd_seq_client_id(seq); - addr.port = desc->this_port; - snd_seq_port_subscribe_set_dest(sub, &addr); - addr.client = desc->client; - addr.port = desc->port; - snd_seq_port_subscribe_set_sender(sub, &addr); - snd_seq_port_subscribe_set_time_update(sub, 1); - /* this doesn't seem to work: messages come in with real timestamps */ - snd_seq_port_subscribe_set_time_real(sub, 0); - err = snd_seq_subscribe_port(seq, sub); - /* err = - snd_seq_connect_from(seq, desc->this_port, desc->client, desc->port); */ - if (err < 0) goto free_this_port; /* clean up and return on error */ - return pmNoError; - - free_this_port: - snd_seq_delete_port(seq, desc->this_port); - free_queue: - alsa_unuse_queue(); - free_desc: - pm_free(desc); - pm_hosterror = err; - if (err < 0) { - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err); - } - return pmHostError; + void *client_port = descriptors[midi->device_id].descriptor; + alsa_descriptor_type desc = (alsa_descriptor_type) + pm_alloc(sizeof(alsa_descriptor_node)); + snd_seq_port_info_t *info; + snd_seq_port_subscribe_t *sub; + snd_seq_addr_t addr; + int err; + + if (!desc) return pmInsufficientMemory; + + err = alsa_use_queue(); + if (err < 0) goto free_desc; + + snd_seq_port_info_alloca(&info); + snd_seq_port_info_set_port(info, midi->device_id); + snd_seq_port_info_set_capability(info, SND_SEQ_PORT_CAP_WRITE | + SND_SEQ_PORT_CAP_READ); + snd_seq_port_info_set_type(info, SND_SEQ_PORT_TYPE_MIDI_GENERIC | + SND_SEQ_PORT_TYPE_APPLICATION); + snd_seq_port_info_set_port_specified(info, 1); + err = snd_seq_create_port(seq, info); + if (err < 0) goto free_queue; + + /* fill in fields of desc, which is passed to pm_write routines */ + midi->descriptor = desc; + desc->client = GET_DESCRIPTOR_CLIENT(client_port); + desc->port = GET_DESCRIPTOR_PORT(client_port); + desc->this_port = midi->device_id; + desc->in_sysex = 0; + + desc->error = 0; + + VERBOSE printf("snd_seq_connect_from: %d %d %d\n", + desc->this_port, desc->client, desc->port); + snd_seq_port_subscribe_alloca(&sub); + addr.client = snd_seq_client_id(seq); + addr.port = desc->this_port; + snd_seq_port_subscribe_set_dest(sub, &addr); + addr.client = desc->client; + addr.port = desc->port; + snd_seq_port_subscribe_set_sender(sub, &addr); + snd_seq_port_subscribe_set_time_update(sub, 1); + /* this doesn't seem to work: messages come in with real timestamps */ + snd_seq_port_subscribe_set_time_real(sub, 0); + err = snd_seq_subscribe_port(seq, sub); + /* err = + snd_seq_connect_from(seq, desc->this_port, desc->client, desc->port); */ + if (err < 0) goto free_this_port; /* clean up and return on error */ + return pmNoError; + + free_this_port: + snd_seq_delete_port(seq, desc->this_port); + free_queue: + alsa_unuse_queue(); + free_desc: + pm_free(desc); + pm_hosterror = err; + if (err < 0) { + get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err); + } + return pmHostError; } static PmError alsa_in_close(PmInternal *midi) { - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - if (!desc) return pmBadPtr; - if ((pm_hosterror = snd_seq_disconnect_from(seq, desc->this_port, - desc->client, desc->port))) { - snd_seq_delete_port(seq, desc->this_port); /* try to close port */ - } else { - pm_hosterror = snd_seq_delete_port(seq, desc->this_port); - } - alsa_unuse_queue(); - pm_free(desc); - if (pm_hosterror) { - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, - pm_hosterror); - return pmHostError; - } - return pmNoError; + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + if (!desc) return pmBadPtr; + if ((pm_hosterror = snd_seq_disconnect_from(seq, desc->this_port, + desc->client, desc->port))) { + snd_seq_delete_port(seq, desc->this_port); /* try to close port */ + } else { + pm_hosterror = snd_seq_delete_port(seq, desc->this_port); + } + alsa_unuse_queue(); + pm_free(desc); + if (pm_hosterror) { + get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, + pm_hosterror); + return pmHostError; + } + return pmNoError; } - + static PmError alsa_abort(PmInternal *midi) { - /* NOTE: ALSA documentation is vague. This is supposed to - * remove any pending output messages. If you can test and - * confirm this code is correct, please update this comment. -RBD - */ - /* Unfortunately, I can't even compile it -- my ALSA version - * does not implement snd_seq_remove_events_t, so this does - * not compile. I'll try again, but it looks like I'll need to - * upgrade my entire Linux OS -RBD - */ - /* - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - snd_seq_remove_events_t info; - snd_seq_addr_t addr; - addr.client = desc->client; - addr.port = desc->port; - snd_seq_remove_events_set_dest(&info, &addr); - snd_seq_remove_events_set_condition(&info, SND_SEQ_REMOVE_DEST); - pm_hosterror = snd_seq_remove_events(seq, &info); - if (pm_hosterror) { - get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, - pm_hosterror); - return pmHostError; - } - */ - printf("WARNING: alsa_abort not implemented\n"); - return pmNoError; + /* NOTE: ALSA documentation is vague. This is supposed to + * remove any pending output messages. If you can test and + * confirm this code is correct, please update this comment. -RBD + */ + /* Unfortunately, I can't even compile it -- my ALSA version + * does not implement snd_seq_remove_events_t, so this does + * not compile. I'll try again, but it looks like I'll need to + * upgrade my entire Linux OS -RBD + */ + /* + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + snd_seq_remove_events_t info; + snd_seq_addr_t addr; + addr.client = desc->client; + addr.port = desc->port; + snd_seq_remove_events_set_dest(&info, &addr); + snd_seq_remove_events_set_condition(&info, SND_SEQ_REMOVE_DEST); + pm_hosterror = snd_seq_remove_events(seq, &info); + if (pm_hosterror) { + get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, + pm_hosterror); + return pmHostError; + } + */ + printf("WARNING: alsa_abort not implemented\n"); + return pmNoError; } @@ -392,396 +392,396 @@ static PmError alsa_abort(PmInternal *midi) This is old code here temporarily for reference static PmError alsa_write(PmInternal *midi, PmEvent *buffer, int32_t length) { - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - int i, bytes; - unsigned char byte; - PmMessage msg; - - desc->error = 0; - for (; length > 0; length--, buffer++) { - VERBOSE printf("message 0x%x\n", buffer->message); - if (Pm_MessageStatus(buffer->message) == MIDI_SYSEX) - desc->in_sysex = TRUE; - if (desc->in_sysex) { - msg = buffer->message; - for (i = 0; i < 4; i++) { - byte = msg; /* extract next byte to send */ - alsa_write_byte(midi, byte, buffer->timestamp); - if (byte == MIDI_EOX) { - desc->in_sysex = FALSE; - break; - } - if (desc->error < 0) break; - msg >>= 8; /* shift next byte into position */ - } - } else { - bytes = midi_message_length(buffer->message); - msg = buffer->message; - for (i = 0; i < bytes; i++) { - byte = msg; /* extract next byte to send */ - VERBOSE printf("sending 0x%x\n", byte); - alsa_write_byte(midi, byte, buffer->timestamp); - if (desc->error < 0) break; - msg >>= 8; /* shift next byte into position */ - } - } - } - if (desc->error < 0) return pmHostError; - - VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq); - desc->error = snd_seq_drain_output(seq); - if (desc->error < 0) return pmHostError; - - desc->error = pmNoError; - return pmNoError; + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + int i, bytes; + unsigned char byte; + PmMessage msg; + + desc->error = 0; + for (; length > 0; length--, buffer++) { + VERBOSE printf("message 0x%x\n", buffer->message); + if (Pm_MessageStatus(buffer->message) == MIDI_SYSEX) + desc->in_sysex = TRUE; + if (desc->in_sysex) { + msg = buffer->message; + for (i = 0; i < 4; i++) { + byte = msg; /* extract next byte to send */ + alsa_write_byte(midi, byte, buffer->timestamp); + if (byte == MIDI_EOX) { + desc->in_sysex = FALSE; + break; + } + if (desc->error < 0) break; + msg >>= 8; /* shift next byte into position */ + } + } else { + bytes = midi_message_length(buffer->message); + msg = buffer->message; + for (i = 0; i < bytes; i++) { + byte = msg; /* extract next byte to send */ + VERBOSE printf("sending 0x%x\n", byte); + alsa_write_byte(midi, byte, buffer->timestamp); + if (desc->error < 0) break; + msg >>= 8; /* shift next byte into position */ + } + } + } + if (desc->error < 0) return pmHostError; + + VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq); + desc->error = snd_seq_drain_output(seq); + if (desc->error < 0) return pmHostError; + + desc->error = pmNoError; + return pmNoError; } #endif static PmError alsa_write_flush(PmInternal *midi, PmTimestamp timestamp) { - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int)(FPTR) seq); - desc->error = snd_seq_drain_output(seq); - if (desc->error < 0) return pmHostError; + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int)(FPTR) seq); + desc->error = snd_seq_drain_output(seq); + if (desc->error < 0) return pmHostError; - desc->error = pmNoError; - return pmNoError; + desc->error = pmNoError; + return pmNoError; } static PmError alsa_write_short(PmInternal *midi, PmEvent *event) { - int bytes = midi_message_length(event->message); - PmMessage msg = event->message; - int i; - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - for (i = 0; i < bytes; i++) { - unsigned char byte = msg; - VERBOSE printf("sending 0x%x\n", byte); - alsa_write_byte(midi, byte, event->timestamp); - if (desc->error < 0) break; - msg >>= 8; /* shift next byte into position */ - } - if (desc->error < 0) return pmHostError; - desc->error = pmNoError; - return pmNoError; + int bytes = midi_message_length(event->message); + PmMessage msg = event->message; + int i; + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + for (i = 0; i < bytes; i++) { + unsigned char byte = msg; + VERBOSE printf("sending 0x%x\n", byte); + alsa_write_byte(midi, byte, event->timestamp); + if (desc->error < 0) break; + msg >>= 8; /* shift next byte into position */ + } + if (desc->error < 0) return pmHostError; + desc->error = pmNoError; + return pmNoError; } /* alsa_sysex -- implements begin_sysex and end_sysex */ PmError alsa_sysex(PmInternal *midi, PmTimestamp timestamp) { - return pmNoError; + return pmNoError; } static PmTimestamp alsa_synchronize(PmInternal *midi) { - return 0; /* linux implementation does not use this synchronize function */ - /* Apparently, Alsa data is relative to the time you send it, and there - is no reference. If this is true, this is a serious shortcoming of - Alsa. If not true, then PortMidi has a serious shortcoming -- it - should be scheduling relative to Alsa's time reference. */ + return 0; /* linux implementation does not use this synchronize function */ + /* Apparently, Alsa data is relative to the time you send it, and there + is no reference. If this is true, this is a serious shortcoming of + Alsa. If not true, then PortMidi has a serious shortcoming -- it + should be scheduling relative to Alsa's time reference. */ } static void handle_event(snd_seq_event_t *ev) { - int device_id = ev->dest.port; - PmInternal *midi = descriptors[device_id].internalDescriptor; - PmEvent pm_ev; - PmTimeProcPtr time_proc = midi->time_proc; - PmTimestamp timestamp; - - /* time stamp should be in ticks, using our queue where 1 tick = 1ms */ - assert((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_TICK); - - /* if no time_proc, just return "native" ticks (ms) */ - if (time_proc == NULL) { - timestamp = ev->time.tick; - } else { /* translate time to time_proc basis */ - snd_seq_queue_status_t *queue_status; - snd_seq_queue_status_alloca(&queue_status); - snd_seq_get_queue_status(seq, queue, queue_status); - /* return (now - alsa_now) + alsa_timestamp */ - timestamp = (*time_proc)(midi->time_info) + ev->time.tick - - snd_seq_queue_status_get_tick_time(queue_status); - } - pm_ev.timestamp = timestamp; - switch (ev->type) { - case SND_SEQ_EVENT_NOTEON: - pm_ev.message = Pm_Message(0x90 | ev->data.note.channel, - ev->data.note.note & 0x7f, - ev->data.note.velocity & 0x7f); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_NOTEOFF: - pm_ev.message = Pm_Message(0x80 | ev->data.note.channel, - ev->data.note.note & 0x7f, - ev->data.note.velocity & 0x7f); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_KEYPRESS: - pm_ev.message = Pm_Message(0xa0 | ev->data.note.channel, - ev->data.note.note & 0x7f, - ev->data.note.velocity & 0x7f); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_CONTROLLER: - pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, - ev->data.control.param & 0x7f, - ev->data.control.value & 0x7f); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_PGMCHANGE: - pm_ev.message = Pm_Message(0xc0 | ev->data.note.channel, - ev->data.control.value & 0x7f, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_CHANPRESS: - pm_ev.message = Pm_Message(0xd0 | ev->data.note.channel, - ev->data.control.value & 0x7f, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_PITCHBEND: - pm_ev.message = Pm_Message(0xe0 | ev->data.note.channel, - (ev->data.control.value + 0x2000) & 0x7f, - ((ev->data.control.value + 0x2000) >> 7) & 0x7f); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_CONTROL14: - if (ev->data.control.param < 0x20) { - pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, - ev->data.control.param, - (ev->data.control.value >> 7) & 0x7f); - pm_read_short(midi, &pm_ev); - pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, - ev->data.control.param + 0x20, - ev->data.control.value & 0x7f); - pm_read_short(midi, &pm_ev); - } else { - pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, - ev->data.control.param & 0x7f, - ev->data.control.value & 0x7f); - - pm_read_short(midi, &pm_ev); - } - break; - case SND_SEQ_EVENT_SONGPOS: - pm_ev.message = Pm_Message(0xf2, - ev->data.control.value & 0x7f, - (ev->data.control.value >> 7) & 0x7f); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_SONGSEL: - pm_ev.message = Pm_Message(0xf3, - ev->data.control.value & 0x7f, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_QFRAME: - pm_ev.message = Pm_Message(0xf1, - ev->data.control.value & 0x7f, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_START: - pm_ev.message = Pm_Message(0xfa, 0, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_CONTINUE: - pm_ev.message = Pm_Message(0xfb, 0, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_STOP: - pm_ev.message = Pm_Message(0xfc, 0, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_CLOCK: - pm_ev.message = Pm_Message(0xf8, 0, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_TUNE_REQUEST: - pm_ev.message = Pm_Message(0xf6, 0, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_RESET: - pm_ev.message = Pm_Message(0xff, 0, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_SENSING: - pm_ev.message = Pm_Message(0xfe, 0, 0); - pm_read_short(midi, &pm_ev); - break; - case SND_SEQ_EVENT_SYSEX: { - const BYTE *ptr = (const BYTE *) ev->data.ext.ptr; - /* assume there is one sysex byte to process */ - pm_read_bytes(midi, ptr, ev->data.ext.len, timestamp); - break; - } - } + int device_id = ev->dest.port; + PmInternal *midi = descriptors[device_id].internalDescriptor; + PmEvent pm_ev; + PmTimeProcPtr time_proc = midi->time_proc; + PmTimestamp timestamp; + + /* time stamp should be in ticks, using our queue where 1 tick = 1ms */ + assert((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_TICK); + + /* if no time_proc, just return "native" ticks (ms) */ + if (time_proc == NULL) { + timestamp = ev->time.tick; + } else { /* translate time to time_proc basis */ + snd_seq_queue_status_t *queue_status; + snd_seq_queue_status_alloca(&queue_status); + snd_seq_get_queue_status(seq, queue, queue_status); + /* return (now - alsa_now) + alsa_timestamp */ + timestamp = (*time_proc)(midi->time_info) + ev->time.tick - + snd_seq_queue_status_get_tick_time(queue_status); + } + pm_ev.timestamp = timestamp; + switch (ev->type) { + case SND_SEQ_EVENT_NOTEON: + pm_ev.message = Pm_Message(0x90 | ev->data.note.channel, + ev->data.note.note & 0x7f, + ev->data.note.velocity & 0x7f); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_NOTEOFF: + pm_ev.message = Pm_Message(0x80 | ev->data.note.channel, + ev->data.note.note & 0x7f, + ev->data.note.velocity & 0x7f); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_KEYPRESS: + pm_ev.message = Pm_Message(0xa0 | ev->data.note.channel, + ev->data.note.note & 0x7f, + ev->data.note.velocity & 0x7f); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_CONTROLLER: + pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, + ev->data.control.param & 0x7f, + ev->data.control.value & 0x7f); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_PGMCHANGE: + pm_ev.message = Pm_Message(0xc0 | ev->data.note.channel, + ev->data.control.value & 0x7f, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_CHANPRESS: + pm_ev.message = Pm_Message(0xd0 | ev->data.note.channel, + ev->data.control.value & 0x7f, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_PITCHBEND: + pm_ev.message = Pm_Message(0xe0 | ev->data.note.channel, + (ev->data.control.value + 0x2000) & 0x7f, + ((ev->data.control.value + 0x2000) >> 7) & 0x7f); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_CONTROL14: + if (ev->data.control.param < 0x20) { + pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, + ev->data.control.param, + (ev->data.control.value >> 7) & 0x7f); + pm_read_short(midi, &pm_ev); + pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, + ev->data.control.param + 0x20, + ev->data.control.value & 0x7f); + pm_read_short(midi, &pm_ev); + } else { + pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel, + ev->data.control.param & 0x7f, + ev->data.control.value & 0x7f); + + pm_read_short(midi, &pm_ev); + } + break; + case SND_SEQ_EVENT_SONGPOS: + pm_ev.message = Pm_Message(0xf2, + ev->data.control.value & 0x7f, + (ev->data.control.value >> 7) & 0x7f); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_SONGSEL: + pm_ev.message = Pm_Message(0xf3, + ev->data.control.value & 0x7f, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_QFRAME: + pm_ev.message = Pm_Message(0xf1, + ev->data.control.value & 0x7f, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_START: + pm_ev.message = Pm_Message(0xfa, 0, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_CONTINUE: + pm_ev.message = Pm_Message(0xfb, 0, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_STOP: + pm_ev.message = Pm_Message(0xfc, 0, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_CLOCK: + pm_ev.message = Pm_Message(0xf8, 0, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_TUNE_REQUEST: + pm_ev.message = Pm_Message(0xf6, 0, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_RESET: + pm_ev.message = Pm_Message(0xff, 0, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_SENSING: + pm_ev.message = Pm_Message(0xfe, 0, 0); + pm_read_short(midi, &pm_ev); + break; + case SND_SEQ_EVENT_SYSEX: { + const BYTE *ptr = (const BYTE *) ev->data.ext.ptr; + /* assume there is one sysex byte to process */ + pm_read_bytes(midi, ptr, ev->data.ext.len, timestamp); + break; + } + } } static PmError alsa_poll(PmInternal *midi) { - snd_seq_event_t *ev; - /* expensive check for input data, gets data from device: */ - while (snd_seq_event_input_pending(seq, TRUE) > 0) { - /* cheap check on local input buffer */ - while (snd_seq_event_input_pending(seq, FALSE) > 0) { - /* check for and ignore errors, e.g. input overflow */ - /* note: if there's overflow, this should be reported - * all the way through to client. Since input from all - * devices is merged, we need to find all input devices - * and set all to the overflow state. - * NOTE: this assumes every input is ALSA based. - */ - int rslt = snd_seq_event_input(seq, &ev); - if (rslt >= 0) { - handle_event(ev); - } else if (rslt == -ENOSPC) { - int i; - for (i = 0; i < pm_descriptor_index; i++) { - if (descriptors[i].pub.input) { - PmInternal *midi = (PmInternal *) - descriptors[i].internalDescriptor; - /* careful, device may not be open! */ - if (midi) Pm_SetOverflow(midi->queue); - } - } - } - } - } - return pmNoError; + snd_seq_event_t *ev; + /* expensive check for input data, gets data from device: */ + while (snd_seq_event_input_pending(seq, TRUE) > 0) { + /* cheap check on local input buffer */ + while (snd_seq_event_input_pending(seq, FALSE) > 0) { + /* check for and ignore errors, e.g. input overflow */ + /* note: if there's overflow, this should be reported + * all the way through to client. Since input from all + * devices is merged, we need to find all input devices + * and set all to the overflow state. + * NOTE: this assumes every input is ALSA based. + */ + int rslt = snd_seq_event_input(seq, &ev); + if (rslt >= 0) { + handle_event(ev); + } else if (rslt == -ENOSPC) { + int i; + for (i = 0; i < pm_descriptor_index; i++) { + if (descriptors[i].pub.input) { + PmInternal *midi = (PmInternal *) + descriptors[i].internalDescriptor; + /* careful, device may not be open! */ + if (midi) Pm_SetOverflow(midi->queue); + } + } + } + } + } + return pmNoError; } static unsigned int alsa_has_host_error(PmInternal *midi) { - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - return desc->error; + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + return desc->error; } static void alsa_get_host_error(PmInternal *midi, char *msg, unsigned int len) { - alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; - int err = (pm_hosterror || desc->error); - get_alsa_error_text(msg, len, err); + alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor; + int err = (pm_hosterror || desc->error); + get_alsa_error_text(msg, len, err); } pm_fns_node pm_linuxalsa_in_dictionary = { - none_write_short, - none_sysex, - none_sysex, - none_write_byte, - none_write_short, - none_write_flush, - alsa_synchronize, - alsa_in_open, - alsa_abort, - alsa_in_close, - alsa_poll, - alsa_has_host_error, - alsa_get_host_error + none_write_short, + none_sysex, + none_sysex, + none_write_byte, + none_write_short, + none_write_flush, + alsa_synchronize, + alsa_in_open, + alsa_abort, + alsa_in_close, + alsa_poll, + alsa_has_host_error, + alsa_get_host_error }; pm_fns_node pm_linuxalsa_out_dictionary = { - alsa_write_short, - alsa_sysex, - alsa_sysex, - alsa_write_byte, - alsa_write_short, /* short realtime message */ - alsa_write_flush, - alsa_synchronize, - alsa_out_open, - alsa_abort, - alsa_out_close, - none_poll, - alsa_has_host_error, - alsa_get_host_error + alsa_write_short, + alsa_sysex, + alsa_sysex, + alsa_write_byte, + alsa_write_short, /* short realtime message */ + alsa_write_flush, + alsa_synchronize, + alsa_out_open, + alsa_abort, + alsa_out_close, + none_poll, + alsa_has_host_error, + alsa_get_host_error }; -/* pm_strdup -- copy a string to the heap. Use this rather than strdup so - * that we call pm_alloc, not malloc. This allows portmidi to avoid +/* pm_strdup -- copy a string to the heap. Use this rather than strdup so + * that we call pm_alloc, not malloc. This allows portmidi to avoid * malloc which might cause priority inversion. Probably ALSA is going * to call malloc anyway, so this extra work here may be pointless. */ char *pm_strdup(const char *s) { - int len = strlen(s); - char *dup = (char *) pm_alloc(len + 1); - strcpy(dup, s); - return dup; + int len = strlen(s); + char *dup = (char *) pm_alloc(len + 1); + strcpy(dup, s); + return dup; } PmError pm_linuxalsa_init( void ) { - int err; - snd_seq_client_info_t *cinfo; - snd_seq_port_info_t *pinfo; - unsigned int caps; - - /* Previously, the last parameter was SND_SEQ_NONBLOCK, but this - * would cause messages to be dropped if the ALSA buffer fills up. - * The correct behavior is for writes to block until there is - * room to send all the data. The client should normally allocate - * a large enough buffer to avoid blocking on output. - * Now that blocking is enabled, the seq_event_input() will block - * if there is no input data. This is not what we want, so must - * call seq_event_input_pending() to avoid blocking. - */ - err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0); - if (err < 0) return err; - - snd_seq_client_info_alloca(&cinfo); - snd_seq_port_info_alloca(&pinfo); - - snd_seq_client_info_set_client(cinfo, -1); - while (snd_seq_query_next_client(seq, cinfo) == 0) { - snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); - snd_seq_port_info_set_port(pinfo, -1); - while (snd_seq_query_next_port(seq, pinfo) == 0) { - if (snd_seq_port_info_get_client(pinfo) == SND_SEQ_CLIENT_SYSTEM) - continue; /* ignore Timer and Announce ports on client 0 */ - caps = snd_seq_port_info_get_capability(pinfo); - if (!(caps & (SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE))) - continue; /* ignore if you cannot read or write port */ - if (caps & SND_SEQ_PORT_CAP_SUBS_WRITE) { - if (pm_default_output_device_id == -1) - pm_default_output_device_id = pm_descriptor_index; - pm_add_device((char *)"ALSA", - pm_strdup(snd_seq_port_info_get_name(pinfo)), - FALSE, - MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo), - snd_seq_port_info_get_port(pinfo)), - &pm_linuxalsa_out_dictionary); - } - if (caps & SND_SEQ_PORT_CAP_SUBS_READ) { - if (pm_default_input_device_id == -1) - pm_default_input_device_id = pm_descriptor_index; - pm_add_device((char *)"ALSA", - pm_strdup(snd_seq_port_info_get_name(pinfo)), - TRUE, - MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo), - snd_seq_port_info_get_port(pinfo)), - &pm_linuxalsa_in_dictionary); - } - } - } - return pmNoError; + int err; + snd_seq_client_info_t *cinfo; + snd_seq_port_info_t *pinfo; + unsigned int caps; + + /* Previously, the last parameter was SND_SEQ_NONBLOCK, but this + * would cause messages to be dropped if the ALSA buffer fills up. + * The correct behavior is for writes to block until there is + * room to send all the data. The client should normally allocate + * a large enough buffer to avoid blocking on output. + * Now that blocking is enabled, the seq_event_input() will block + * if there is no input data. This is not what we want, so must + * call seq_event_input_pending() to avoid blocking. + */ + err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0); + if (err < 0) return err; + + snd_seq_client_info_alloca(&cinfo); + snd_seq_port_info_alloca(&pinfo); + + snd_seq_client_info_set_client(cinfo, -1); + while (snd_seq_query_next_client(seq, cinfo) == 0) { + snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); + snd_seq_port_info_set_port(pinfo, -1); + while (snd_seq_query_next_port(seq, pinfo) == 0) { + if (snd_seq_port_info_get_client(pinfo) == SND_SEQ_CLIENT_SYSTEM) + continue; /* ignore Timer and Announce ports on client 0 */ + caps = snd_seq_port_info_get_capability(pinfo); + if (!(caps & (SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE))) + continue; /* ignore if you cannot read or write port */ + if (caps & SND_SEQ_PORT_CAP_SUBS_WRITE) { + if (pm_default_output_device_id == -1) + pm_default_output_device_id = pm_descriptor_index; + pm_add_device((char *)"ALSA", + pm_strdup(snd_seq_port_info_get_name(pinfo)), + FALSE, + MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo), + snd_seq_port_info_get_port(pinfo)), + &pm_linuxalsa_out_dictionary); + } + if (caps & SND_SEQ_PORT_CAP_SUBS_READ) { + if (pm_default_input_device_id == -1) + pm_default_input_device_id = pm_descriptor_index; + pm_add_device((char *)"ALSA", + pm_strdup(snd_seq_port_info_get_name(pinfo)), + TRUE, + MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo), + snd_seq_port_info_get_port(pinfo)), + &pm_linuxalsa_in_dictionary); + } + } + } + return pmNoError; } - + void pm_linuxalsa_term(void) { - if (seq) { - snd_seq_close(seq); - pm_free(descriptors); - descriptors = NULL; - pm_descriptor_index = 0; - pm_descriptor_max = 0; - } + if (seq) { + snd_seq_close(seq); + pm_free(descriptors); + descriptors = NULL; + pm_descriptor_index = 0; + pm_descriptor_max = 0; + } } |