int main(int argc, char **argv) { int i; char *connect_client = NULL; int connect_port = -1; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--prefix") == 0) { if (++i == argc) usage(argv[0]); prefix = argv[i]; } else if (strcmp(argv[i], "--timeout") == 0) { if (++i == argc) usage(argv[0]); timeout = atoi(argv[i]); } else if (strcmp(argv[i], "--confirmation") == 0) { if (++i == argc) usage(argv[0]); confirmation_command_pattern = argv[i]; } else if (strcmp(argv[i], "--connect") == 0) { if (++i == argc) usage(argv[0]); connect_client = argv[i]; if (++i == argc) usage(argv[0]); connect_port = atoi(argv[i]); } else { usage(argv[0]); } } { snd_seq_t *seq; int port; if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_INPUT, 0) < 0) { fprintf(stderr, "Cannot open the ALSA sequencer.\n"); exit(1); } snd_seq_set_client_name(seq, "Brainstorm"); port = snd_seq_create_simple_port(seq, "Brainstorm recording port", SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); if ((connect_client != NULL) && (connect_port >= 0)) { int connect_client_id = -1; { snd_seq_client_info_t *client_info; snd_seq_client_info_malloc(&client_info); while (snd_seq_query_next_client(seq, client_info) == 0) { if (strcmp(snd_seq_client_info_get_name(client_info), connect_client) == 0) { connect_client_id = snd_seq_client_info_get_client(client_info); break; } } snd_seq_client_info_free(client_info); } if (connect_client_id < 0) connect_client_id = atoi(connect_client); snd_seq_connect_from(seq, port, connect_client_id, connect_port); } signal(SIGALRM, alarm_handler); { snd_seq_event_t *event; while (snd_seq_event_input(seq, &event) >= 0) { switch (event->type) { case SND_SEQ_EVENT_NOTEOFF: { alarm(timeout); create_midi_file_for_first_event(); MidiFileTrack_createNoteOffEvent(track, get_tick(), event->data.note.channel, event->data.note.note, event->data.note.velocity); break; } case SND_SEQ_EVENT_NOTEON: { alarm(timeout); create_midi_file_for_first_event(); MidiFileTrack_createNoteOnEvent(track, get_tick(), event->data.note.channel, event->data.note.note, event->data.note.velocity); break; } case SND_SEQ_EVENT_KEYPRESS: { alarm(timeout); create_midi_file_for_first_event(); MidiFileTrack_createKeyPressureEvent(track, get_tick(), event->data.note.channel, event->data.note.note, event->data.note.velocity); break; } case SND_SEQ_EVENT_CONTROLLER: { alarm(timeout); create_midi_file_for_first_event(); MidiFileTrack_createControlChangeEvent(track, get_tick(), event->data.control.channel, event->data.control.param, event->data.control.value); break; } case SND_SEQ_EVENT_PGMCHANGE: { alarm(timeout); create_midi_file_for_first_event(); MidiFileTrack_createProgramChangeEvent(track, get_tick(), event->data.control.channel, event->data.control.value); break; } case SND_SEQ_EVENT_CHANPRESS: { alarm(timeout); create_midi_file_for_first_event(); MidiFileTrack_createChannelPressureEvent(track, get_tick(), event->data.control.channel, event->data.control.value); break; } case SND_SEQ_EVENT_PITCHBEND: { alarm(timeout); create_midi_file_for_first_event(); MidiFileTrack_createPitchWheelEvent(track, get_tick(), event->data.control.channel, event->data.control.value); break; } default: { /* I'm ignoring the pseudoevents which ALSA provides as convenience features (SND_SEQ_EVENT_NOTE, SND_SEQ_EVENT_CONTROL14, SND_SEQ_EVENT_NONREGPARAM, and SND_SEQ_EVENT_REGPARAM). Hopefully I can find some way to convince ALSA to normalize them into true MIDI events. */ break; } } } } } return 0; }
int MidiDriver_ALSA::open() { if (_isOpen) return MERR_ALREADY_OPEN; _isOpen = true; if (my_snd_seq_open(&seq_handle) < 0) { error("Can't open sequencer"); return -1; } my_client = snd_seq_client_id(seq_handle); if (snd_seq_set_client_name(seq_handle, "SCUMMVM") < 0) { error("Can't set sequencer client name"); } snd_seq_set_client_group(seq_handle, "input"); // According to http://www.alsa-project.org/~tiwai/alsa-subs.html // you can set read or write capabilities to allow other clients to // read or write the port. I don't think we need that, unless maybe // to be able to record the sound, but I can't get that to work even // with those capabilities. my_port = snd_seq_create_simple_port(seq_handle, "SCUMMVM port 0", 0, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); if (my_port < 0) { snd_seq_close(seq_handle); error("Can't create port"); return -1; } if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) { // Subscribe to MIDI port. Prefer one that doesn't already have // any connections, unless we've forced a port number already. if (seq_port == -1) { snd_seq_client_info_t *cinfo; snd_seq_port_info_t *pinfo; snd_seq_client_info_alloca(&cinfo); snd_seq_port_info_alloca(&pinfo); snd_seq_get_any_client_info(seq_handle, seq_client, cinfo); int first_port = -1; int found_port = -1; snd_seq_port_info_set_client(pinfo, seq_client); snd_seq_port_info_set_port(pinfo, -1); while (found_port == -1 && snd_seq_query_next_port(seq_handle, pinfo) >= 0) { if (check_permission(pinfo)) { if (first_port == -1) first_port = snd_seq_port_info_get_port(pinfo); if (found_port == -1 && snd_seq_port_info_get_write_use(pinfo) == 0) found_port = snd_seq_port_info_get_port(pinfo); } } if (found_port == -1) { // Should we abort here? For now, use the first // available port. seq_port = first_port; warning("MidiDriver_ALSA: All ports on client %d (%s) are already in use", seq_client, snd_seq_client_info_get_name(cinfo)); } else { seq_port = found_port; } } if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) { error("Can't subscribe to MIDI port (%d:%d) see README for help", seq_client, seq_port); } } printf("Connected to Alsa sequencer client [%d:%d]\n", seq_client, seq_port); printf("ALSA client initialised [%d:0]\n", my_client); return 0; }
static GstStateChangeReturn gst_amidisrc_change_state (GstElement * element, GstStateChange transition ) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstaMIDISrc *src = GST_AMIDISRC (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: // TODO: Open our listen alsa ports // 1. Open sequencer // 2. If we have a client and port, connect to them printf("***Here: %s:%d\n",__FILE__,__LINE__); if ((snd_seq_open(&src->a_seq, src->device, SND_SEQ_OPEN_INPUT, 0)) < 0) return GST_STATE_CHANGE_FAILURE; if( src->a_seq == NULL ) return GST_STATE_CHANGE_FAILURE; snd_seq_set_client_name(src->a_seq, "gstreamer"); if ((src->a_port = snd_seq_create_simple_port(src->a_seq, "In", SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) { return GST_STATE_CHANGE_FAILURE; } src->a_queue = snd_seq_alloc_queue(src->a_seq); if( src->a_queue < 0 ) return GST_STATE_CHANGE_FAILURE; // Only connect if we have positive client/port if( src->client >= 0 && src->port >= 0 ) { if( snd_seq_connect_to(src->a_seq, src->a_port, src->client, src->port) < 0 ) return GST_STATE_CHANGE_FAILURE; } break; case GST_STATE_CHANGE_READY_TO_PAUSED: return GST_STATE_CHANGE_NO_PREROLL; break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_READY_TO_NULL: // TODO: close our listening alsa ports // disconnect from midi port printf("***Here: %s:%d\n",__FILE__,__LINE__); if( src->a_queue >= 0 ){ if( snd_seq_free_queue( src->a_seq, src->a_queue ) < 0 ) return GST_STATE_CHANGE_FAILURE; } if( src->a_port >= 0 && src->a_seq != NULL){ if( snd_seq_delete_simple_port(src->a_seq,src->a_port) < 0 ){ return GST_STATE_CHANGE_FAILURE; } } if( snd_seq_close( src->a_seq ) < 0 ) return GST_STATE_CHANGE_FAILURE; break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: return GST_STATE_CHANGE_NO_PREROLL; break; default: break; } return ret; }