/* Copyright (C) 2011 Devin Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include "JackALSARawMidiPort.h" #include "JackError.h" using Jack::JackALSARawMidiPort; JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info, size_t index) { char device_id[32]; snprintf(device_id, sizeof(device_id), "hw:%d,%d,%d", snd_rawmidi_info_get_card(info), snd_rawmidi_info_get_device(info), snd_rawmidi_info_get_subdevice(info)); const char *alias_prefix; const char *error_message; snd_rawmidi_t **in; snd_rawmidi_t **out; const char *name_suffix; if (snd_rawmidi_info_get_stream(info) == SND_RAWMIDI_STREAM_OUTPUT) { alias_prefix = "system:midi_playback_"; in = 0; name_suffix = "out"; out = &rawmidi; } else { alias_prefix = "system:midi_capture_"; in = &rawmidi; name_suffix = "in"; out = 0; } const char *device_name; const char *func; int code = snd_rawmidi_open(in, out, device_id, SND_RAWMIDI_NONBLOCK); if (code) { error_message = snd_strerror(code); func = "snd_rawmidi_open"; goto handle_error; } snd_rawmidi_params_t *params; code = snd_rawmidi_params_malloc(¶ms); if (code) { error_message = snd_strerror(code); func = "snd_rawmidi_params_malloc"; goto close; } code = snd_rawmidi_params_current(rawmidi, params); if (code) { error_message = snd_strerror(code); func = "snd_rawmidi_params_current"; goto free_params; } code = snd_rawmidi_params_set_avail_min(rawmidi, params, 1); if (code) { error_message = snd_strerror(code); func = "snd_rawmidi_params_set_avail_min"; goto free_params; } code = snd_rawmidi_params_set_no_active_sensing(rawmidi, params, 1); if (code) { error_message = snd_strerror(code); func = "snd_rawmidi_params_set_no_active_sensing"; goto free_params; } snd_rawmidi_params_free(params); num_fds = snd_rawmidi_poll_descriptors_count(rawmidi); if (! num_fds) { error_message = "returned '0' count for poll descriptors"; func = "snd_rawmidi_poll_descriptors_count"; goto close; } snprintf(alias, sizeof(alias), "%s%d", alias_prefix, index); device_name = snd_rawmidi_info_get_subdevice_name(info); if (! strlen(device_name)) { device_name = snd_rawmidi_info_get_name(info); } snprintf(name, sizeof(name), "system:%s %s", device_name, name_suffix); return; free_params: snd_rawmidi_params_free(params); close: snd_rawmidi_close(rawmidi); handle_error: throw std::runtime_error(std::string(func) + ": " + error_message); } JackALSARawMidiPort::~JackALSARawMidiPort() { if (rawmidi) { int code = snd_rawmidi_close(rawmidi); if (code) { jack_error("JackALSARawMidiPort::~JackALSARawMidiPort - " "snd_rawmidi_close: %s", snd_strerror(code)); } rawmidi = 0; } } const char * JackALSARawMidiPort::GetAlias() { return alias; } const char * JackALSARawMidiPort::GetName() { return name; } int JackALSARawMidiPort::GetPollDescriptorCount() { return num_fds; } bool JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd) { bool result = snd_rawmidi_poll_descriptors(rawmidi, poll_fd, num_fds) == num_fds; if (result) { poll_fds = poll_fd; } return result; } bool JackALSARawMidiPort::ProcessPollEvents(unsigned short *revents) { int code = snd_rawmidi_poll_descriptors_revents(rawmidi, poll_fds, num_fds, revents); if (code) { jack_error("JackALSARawMidiPort::ProcessPollEvents - " "snd_rawmidi_poll_descriptors_revents: %s", snd_strerror(code)); return false; } if ((*revents) & POLLNVAL) { jack_error("JackALSARawMidiPort::ProcessPollEvents - the file " "descriptor is invalid."); return false; } if ((*revents) & POLLERR) { jack_error("JackALSARawMidiPort::ProcessPollEvents - an error has " "occurred on the device or stream."); return false; } return true; } void JackALSARawMidiPort::SetPollEventMask(unsigned short events) { for (int i = 0; i < num_fds; i++) { (poll_fds + i)->events = events; } }