|
- /*
- 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 <cassert>
- #include <stdexcept>
- #include <string>
-
- #include "JackALSARawMidiPort.h"
- #include "JackALSARawMidiUtil.h"
- #include "JackError.h"
-
- using Jack::JackALSARawMidiPort;
-
- JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
- size_t index, unsigned short io_mask)
- {
- int card = snd_rawmidi_info_get_card(info);
- unsigned int device = snd_rawmidi_info_get_device(info);
- unsigned int subdevice = snd_rawmidi_info_get_subdevice(info);
- char device_id[32];
- snprintf(device_id, sizeof(device_id), "hw:%d,%d,%d", card, device,
- subdevice);
- const char *alias_suffix;
- const char *error_message;
- snd_rawmidi_t **in;
- const char *name_prefix;
- snd_rawmidi_t **out;
- if (snd_rawmidi_info_get_stream(info) == SND_RAWMIDI_STREAM_OUTPUT) {
- alias_suffix = "out";
- in = 0;
- name_prefix = "system:midi_playback_";
- out = &rawmidi;
- } else {
- alias_suffix = "in";
- in = &rawmidi;
- name_prefix = "system:midi_capture_";
- out = 0;
- }
- 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;
- }
-
- // Minimum buffer size allowed by ALSA
- code = snd_rawmidi_params_set_buffer_size(rawmidi, params, 32);
- if (code) {
- error_message = snd_strerror(code);
- func = "snd_rawmidi_params_set_buffer_size";
- 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;
- }
- code = snd_rawmidi_params(rawmidi, params);
- if (code) {
- error_message = snd_strerror(code);
- func = "snd_rawmidi_params";
- goto free_params;
- }
- snd_rawmidi_params_free(params);
- alsa_poll_fd_count = snd_rawmidi_poll_descriptors_count(rawmidi);
- if (! alsa_poll_fd_count) {
- error_message = "returned '0' count for poll descriptors";
- func = "snd_rawmidi_poll_descriptors_count";
- goto close;
- }
- try {
- CreateNonBlockingPipe(fds);
- } catch (std::exception e) {
- error_message = e.what();
- func = "CreateNonBlockingPipe";
- goto close;
- }
- snprintf(alias, sizeof(alias), "system:%d-%d %s %d %s", card + 1,
- device + 1, snd_rawmidi_info_get_name(info), subdevice + 1,
- alias_suffix);
- snprintf(name, sizeof(name), "%s%zu", name_prefix, index + 1);
- this->io_mask = io_mask;
- 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()
- {
- DestroyNonBlockingPipe(fds);
- 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;
- }
-
- int
- JackALSARawMidiPort::GetIOPollEvent()
- {
- unsigned short events;
- int code = snd_rawmidi_poll_descriptors_revents(rawmidi, alsa_poll_fds,
- alsa_poll_fd_count,
- &events);
- if (code) {
- jack_error("JackALSARawMidiPort::GetIOPollEvents - "
- "snd_rawmidi_poll_descriptors_revents: %s",
- snd_strerror(code));
- return -1;
- }
- if (events & POLLNVAL) {
- jack_error("JackALSARawMidiPort::GetIOPollEvents - the file "
- "descriptor is invalid.");
- return -1;
- }
- if (events & POLLERR) {
- jack_error("JackALSARawMidiPort::GetIOPollEvents - an error has "
- "occurred on the device or stream.");
- return -1;
- }
- return (events & io_mask) ? 1 : 0;
- }
-
- const char *
- JackALSARawMidiPort::GetName()
- {
- return name;
- }
-
- int
- JackALSARawMidiPort::GetPollDescriptorCount()
- {
- return alsa_poll_fd_count + 1;
- }
-
- int
- JackALSARawMidiPort::GetQueuePollEvent()
- {
- unsigned short events = queue_poll_fd->revents;
- if (events & POLLNVAL) {
- jack_error("JackALSARawMidiPort::GetQueuePollEvents - the file "
- "descriptor is invalid.");
- return -1;
- }
- if (events & POLLERR) {
- jack_error("JackALSARawMidiPort::GetQueuePollEvents - an error has "
- "occurred on the device or stream.");
- return -1;
- }
- int event = events & POLLIN ? 1 : 0;
- if (event) {
- char c;
- ssize_t result = read(fds[0], &c, 1);
- assert(result);
- if (result < 0) {
- jack_error("JackALSARawMidiPort::GetQueuePollEvents - error "
- "reading a byte from the pipe file descriptor: %s",
- strerror(errno));
- return -1;
- }
- }
- return event;
- }
-
- void
- JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd)
- {
- alsa_poll_fds = poll_fd + 1;
- assert(snd_rawmidi_poll_descriptors(rawmidi, alsa_poll_fds,
- alsa_poll_fd_count) ==
- alsa_poll_fd_count);
- queue_poll_fd = poll_fd;
- queue_poll_fd->events = POLLERR | POLLIN | POLLNVAL;
- queue_poll_fd->fd = fds[0];
- SetIOEventsEnabled(true);
- }
-
- void
- JackALSARawMidiPort::SetIOEventsEnabled(bool enabled)
- {
- unsigned short mask = POLLNVAL | POLLERR | (enabled ? io_mask : 0);
- for (int i = 0; i < alsa_poll_fd_count; i++) {
- (alsa_poll_fds + i)->events = mask;
- }
- }
-
- bool
- JackALSARawMidiPort::TriggerQueueEvent()
- {
- char c;
- ssize_t result = write(fds[1], &c, 1);
- assert(result <= 1);
- switch (result) {
- case 1:
- return true;
- case 0:
- jack_error("JackALSARawMidiPort::TriggerQueueEvent - error writing a "
- "byte to the pipe file descriptor: %s", strerror(errno));
- break;
- default:
- jack_error("JackALSARawMidiPort::TriggerQueueEvent - couldn't write a "
- "byte to the pipe file descriptor.");
- }
- return false;
- }
|