static int alsa_seqmidi_attach(alsa_midi_t *m) { alsa_seqmidi_t *self = (alsa_seqmidi_t*) m; int err; debug_log("midi: attach"); if (self->seq) return -EALREADY; if ((err = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) { error_log("failed to open alsa seq"); return err; } snd_seq_set_client_name(self->seq, self->alsa_name); self->port_id = snd_seq_create_simple_port(self->seq, "port", SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE #ifndef JACK_MIDI_DEBUG |SND_SEQ_PORT_CAP_NO_EXPORT #endif ,SND_SEQ_PORT_TYPE_APPLICATION); self->client_id = snd_seq_client_id(self->seq); self->queue = snd_seq_alloc_queue(self->seq); snd_seq_start_queue(self->seq, self->queue, 0); stream_attach(self, PORT_INPUT); stream_attach(self, PORT_OUTPUT); snd_seq_nonblock(self->seq, 1); return 0; }
/* Returned structure pointer is allocated using malloc. */ struct polls * midi_init_alsa(void) { struct polls *polls; int npfd; int synth_port, ctrlr_port; int i; if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { dprintf("Couldn't open ALSA sequencer: %s\n", snd_strerror(errno)); return NULL; } snd_seq_set_client_name(seq, "Xtor"); client = snd_seq_client_id(seq); if (client < 0) { dprintf("Can't get client_id: %d\n", client); return NULL; } dprintf("Client address %d\n", client); synth_port = snd_seq_create_simple_port(seq, "Xtor synth port", SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION); if (synth_port < 0) { dprintf("Couldn't create synth port: %s\n", snd_strerror(errno)); return NULL; } ports[SYNTH_PORT] = synth_port; ctrlr_port = snd_seq_create_simple_port(seq, "Xtor controller port", SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION); if (ctrlr_port < 0) { dprintf("Couldn't create controller port: %s\n", snd_strerror(errno)); return NULL; } ports[CTRLR_PORT] = ctrlr_port; /* Fetch poll descriptor(s) for MIDI input (normally only one) */ npfd = snd_seq_poll_descriptors_count(seq, POLLIN); polls = (struct polls *) malloc(sizeof(struct polls) + npfd * sizeof(struct pollfd)); polls->npfd = npfd; snd_seq_poll_descriptors(seq, polls->pollfds, npfd, POLLIN); snd_seq_nonblock(seq, SND_SEQ_NONBLOCK); return polls; }
void run() { const int maxEventSize = 16 * 1024; snd_midi_event_t* midiParser; if (snd_midi_event_new (maxEventSize, &midiParser) >= 0) { HeapBlock <uint8> buffer (maxEventSize); const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN); struct pollfd* const pfd = (struct pollfd*) alloca (numPfds * sizeof (struct pollfd)); snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN); while (! threadShouldExit()) { if (poll (pfd, numPfds, 500) > 0) { snd_seq_event_t* inputEvent = nullptr; snd_seq_nonblock (seqHandle, 1); do { if (snd_seq_event_input (seqHandle, &inputEvent) >= 0) { // xxx what about SYSEXes that are too big for the buffer? const int numBytes = snd_midi_event_decode (midiParser, buffer, maxEventSize, inputEvent); snd_midi_event_reset_decode (midiParser); if (numBytes > 0) { const MidiMessage message ((const uint8*) buffer, numBytes, Time::getMillisecondCounter() * 0.001); callback->handleIncomingMidiMessage (midiInput, message); } snd_seq_free_event (inputEvent); } } while (snd_seq_event_input_pending (seqHandle, 0) > 0); snd_seq_free_event (inputEvent); } } snd_midi_event_free (midiParser); } };
static int snd_rawmidi_virtual_nonblock(snd_rawmidi_t *rmidi, int nonblock) { snd_rawmidi_virtual_t *virt = rmidi->private_data; return snd_seq_nonblock(virt->handle, nonblock); }
int connect_to_alsa (struct a2j* self) { int error; void * thread_status; self->port_add = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(snd_seq_addr_t)); if (self->port_add == NULL) { goto free_self; } self->port_del = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(struct a2j_port *)); if (self->port_del == NULL) { goto free_ringbuffer_add; } if (!a2j_stream_init(self)) { goto free_ringbuffer_outbound; } if ((error = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) { a2j_error("failed to open alsa seq"); goto close_stream; } if ((error = snd_seq_set_client_name(self->seq, "midi_in")) < 0) { a2j_error("snd_seq_set_client_name() failed"); goto close_seq_client; } if ((self->port_id = snd_seq_create_simple_port( self->seq, "port", SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE #ifndef DEBUG |SND_SEQ_PORT_CAP_NO_EXPORT #endif ,SND_SEQ_PORT_TYPE_APPLICATION)) < 0) { a2j_error("snd_seq_create_simple_port() failed"); goto close_seq_client; } if ((self->client_id = snd_seq_client_id(self->seq)) < 0) { a2j_error("snd_seq_client_id() failed"); goto close_seq_client; } if ((self->queue = snd_seq_alloc_queue(self->seq)) < 0) { a2j_error("snd_seq_alloc_queue() failed"); goto close_seq_client; } snd_seq_start_queue (self->seq, self->queue, 0); a2j_stream_attach (&self->stream); if ((error = snd_seq_nonblock(self->seq, 1)) < 0) { a2j_error("snd_seq_nonblock() failed"); goto close_seq_client; } snd_seq_drop_input (self->seq); a2j_add_ports(&self->stream); if (sem_init(&self->io_semaphore, 0, 0) < 0) { a2j_error("can't create IO semaphore"); goto close_jack_client; } g_keep_alsa_walking = true; if (pthread_create(&self->alsa_io_thread, NULL, alsa_input_thread, self) < 0) { a2j_error("cannot start ALSA input thread"); goto sem_destroy; } /* wake the poll loop in the alsa input thread so initial ports are fetched */ if ((error = snd_seq_connect_from (self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE)) < 0) { a2j_error("snd_seq_connect_from() failed"); goto join_io_thread; } return 0; g_keep_alsa_walking = false; /* tell alsa threads to stop */ snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE); join_io_thread: pthread_join(self->alsa_io_thread, &thread_status); sem_destroy: sem_destroy(&self->io_semaphore); close_jack_client: if ((error = jack_client_close(self->jack_client)) < 0) { a2j_error("Cannot close jack client"); } close_seq_client: snd_seq_close(self->seq); close_stream: a2j_stream_close(self); free_ringbuffer_outbound: jack_ringbuffer_free(self->outbound_events); jack_ringbuffer_free(self->port_del); free_ringbuffer_add: jack_ringbuffer_free(self->port_add); free_self: free(self); return -1; }
void event_decoder(snd_seq_t *handle, int argc, char *argv[]) { snd_seq_event_t *ev; snd_seq_port_info_t *pinfo; snd_seq_port_subscribe_t *sub; snd_seq_addr_t addr; int client, port, queue, max, err, v1, v2; char *ptr; struct pollfd *pfds; if ((client = snd_seq_client_id(handle))<0) { fprintf(stderr, "Cannot determine client number: %s\n", snd_strerror(client)); return; } printf("Client ID = %i\n", client); if ((queue = snd_seq_alloc_queue(handle))<0) { fprintf(stderr, "Cannot allocate queue: %s\n", snd_strerror(queue)); return; } printf("Queue ID = %i\n", queue); if ((err = snd_seq_nonblock(handle, 1))<0) fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err)); snd_seq_port_info_alloca(&pinfo); snd_seq_port_info_set_name(pinfo, "Input"); snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC); snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_WRITE); /* Enable timestamping for events sent by external subscribers. */ snd_seq_port_info_set_timestamping(pinfo, 1); snd_seq_port_info_set_timestamp_real(pinfo, 1); snd_seq_port_info_set_timestamp_queue(pinfo, queue); if ((err = snd_seq_create_port(handle, pinfo)) < 0) { fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err)); return; } port = snd_seq_port_info_get_port(pinfo); event_decoder_start_timer(handle, queue, client, port); snd_seq_port_subscribe_alloca(&sub); addr.client = SND_SEQ_CLIENT_SYSTEM; addr.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE; snd_seq_port_subscribe_set_sender(sub, &addr); addr.client = client; addr.port = port; snd_seq_port_subscribe_set_dest(sub, &addr); snd_seq_port_subscribe_set_queue(sub, queue); snd_seq_port_subscribe_set_time_update(sub, 1); snd_seq_port_subscribe_set_time_real(sub, 1); if ((err = snd_seq_subscribe_port(handle, sub))<0) { fprintf(stderr, "Cannot subscribe announce port: %s\n", snd_strerror(err)); return; } addr.client = SND_SEQ_CLIENT_SYSTEM; addr.port = SND_SEQ_PORT_SYSTEM_TIMER; snd_seq_port_subscribe_set_sender(sub, &addr); if ((err = snd_seq_subscribe_port(handle, sub))<0) { fprintf(stderr, "Cannot subscribe timer port: %s\n", snd_strerror(err)); return; } for (max = 0; max < argc; max++) { ptr = argv[max]; if (!ptr) continue; snd_seq_port_subscribe_set_time_real(sub, 0); if (tolower(*ptr) == 'r') { snd_seq_port_subscribe_set_time_real(sub, 1); ptr++; } if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) { fprintf(stderr, "Wrong argument '%s'...\n", argv[max]); return; } addr.client = v1; addr.port = v2; snd_seq_port_subscribe_set_sender(sub, &addr); if ((err = snd_seq_subscribe_port(handle, sub))<0) { fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err)); return; } } max = snd_seq_poll_descriptors_count(handle, POLLIN); pfds = alloca(sizeof(*pfds) * max); while (1) { snd_seq_poll_descriptors(handle, pfds, max, POLLIN); if (poll(pfds, max, -1) < 0) break; do { if ((err = snd_seq_event_input(handle, &ev))<0) break; if (!ev) continue; decode_event(ev); snd_seq_free_event(ev); } while (err > 0); } }
int main(int argc, char *argv[]) { static const char short_options[] = "hVlp:"; static const struct option long_options[] = { {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'V'}, {"list", 0, NULL, 'l'}, {"port", 1, NULL, 'p'}, { } }; int do_list = 0; struct pollfd *pfds; int npfds; int c, err; init_seq(); while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (c) { case 'h': help(argv[0]); return 0; case 'V': version(); return 0; case 'l': do_list = 1; break; case 'p': parse_ports(optarg); break; default: help(argv[0]); return 1; } } if (optind < argc) { help(argv[0]); return 1; } if (do_list) { list_ports(); return 0; } create_port(); connect_ports(); err = snd_seq_nonblock(seq, 1); check_snd("set nonblock mode", err); if (port_count > 0) printf("Waiting for data."); else printf("Waiting for data at port %d:0.", snd_seq_client_id(seq)); printf(" Press Ctrl+C to end.\n"); printf("Source Event Ch Data\n"); signal(SIGINT, sighandler); signal(SIGTERM, sighandler); npfds = snd_seq_poll_descriptors_count(seq, POLLIN); pfds = alloca(sizeof(*pfds) * npfds); for (;;) { snd_seq_poll_descriptors(seq, pfds, npfds, POLLIN); if (poll(pfds, npfds, -1) < 0) break; do { snd_seq_event_t *event; err = snd_seq_event_input(seq, &event); if (err < 0) break; if (event) dump_event(event); } while (err > 0); fflush(stdout); if (stop) break; } snd_seq_close(seq); return 0; }