Jack2
1.9.10
|
00001 /* 00002 Copyright (C) 2011 Devin Anderson 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 00018 */ 00019 00020 #include <cassert> 00021 #include <stdexcept> 00022 #include <string> 00023 00024 #include "JackALSARawMidiPort.h" 00025 #include "JackALSARawMidiUtil.h" 00026 #include "JackError.h" 00027 00028 using Jack::JackALSARawMidiPort; 00029 00030 JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info, 00031 size_t index, unsigned short io_mask) 00032 { 00033 int card = snd_rawmidi_info_get_card(info); 00034 unsigned int device = snd_rawmidi_info_get_device(info); 00035 unsigned int subdevice = snd_rawmidi_info_get_subdevice(info); 00036 char device_id[32]; 00037 snprintf(device_id, sizeof(device_id), "hw:%d,%d,%d", card, device, 00038 subdevice); 00039 const char *alias_suffix; 00040 const char *error_message; 00041 snd_rawmidi_t **in; 00042 const char *name_prefix; 00043 snd_rawmidi_t **out; 00044 if (snd_rawmidi_info_get_stream(info) == SND_RAWMIDI_STREAM_OUTPUT) { 00045 alias_suffix = "out"; 00046 in = 0; 00047 name_prefix = "system:midi_playback_"; 00048 out = &rawmidi; 00049 } else { 00050 alias_suffix = "in"; 00051 in = &rawmidi; 00052 name_prefix = "system:midi_capture_"; 00053 out = 0; 00054 } 00055 const char *func; 00056 int code = snd_rawmidi_open(in, out, device_id, SND_RAWMIDI_NONBLOCK); 00057 if (code) { 00058 error_message = snd_strerror(code); 00059 func = "snd_rawmidi_open"; 00060 goto handle_error; 00061 } 00062 snd_rawmidi_params_t *params; 00063 code = snd_rawmidi_params_malloc(¶ms); 00064 if (code) { 00065 error_message = snd_strerror(code); 00066 func = "snd_rawmidi_params_malloc"; 00067 goto close; 00068 } 00069 code = snd_rawmidi_params_current(rawmidi, params); 00070 if (code) { 00071 error_message = snd_strerror(code); 00072 func = "snd_rawmidi_params_current"; 00073 goto free_params; 00074 } 00075 code = snd_rawmidi_params_set_avail_min(rawmidi, params, 1); 00076 if (code) { 00077 error_message = snd_strerror(code); 00078 func = "snd_rawmidi_params_set_avail_min"; 00079 goto free_params; 00080 } 00081 00082 // Minimum buffer size allowed by ALSA 00083 code = snd_rawmidi_params_set_buffer_size(rawmidi, params, 32); 00084 if (code) { 00085 error_message = snd_strerror(code); 00086 func = "snd_rawmidi_params_set_buffer_size"; 00087 goto free_params; 00088 } 00089 00090 code = snd_rawmidi_params_set_no_active_sensing(rawmidi, params, 1); 00091 if (code) { 00092 error_message = snd_strerror(code); 00093 func = "snd_rawmidi_params_set_no_active_sensing"; 00094 goto free_params; 00095 } 00096 code = snd_rawmidi_params(rawmidi, params); 00097 if (code) { 00098 error_message = snd_strerror(code); 00099 func = "snd_rawmidi_params"; 00100 goto free_params; 00101 } 00102 snd_rawmidi_params_free(params); 00103 alsa_poll_fd_count = snd_rawmidi_poll_descriptors_count(rawmidi); 00104 if (! alsa_poll_fd_count) { 00105 error_message = "returned '0' count for poll descriptors"; 00106 func = "snd_rawmidi_poll_descriptors_count"; 00107 goto close; 00108 } 00109 try { 00110 CreateNonBlockingPipe(fds); 00111 } catch (std::exception e) { 00112 error_message = e.what(); 00113 func = "CreateNonBlockingPipe"; 00114 goto close; 00115 } 00116 snprintf(alias, sizeof(alias), "system:%d-%d %s %d %s", card + 1, 00117 device + 1, snd_rawmidi_info_get_name(info), subdevice + 1, 00118 alias_suffix); 00119 snprintf(name, sizeof(name), "%s%zu", name_prefix, index + 1); 00120 this->io_mask = io_mask; 00121 return; 00122 free_params: 00123 snd_rawmidi_params_free(params); 00124 close: 00125 snd_rawmidi_close(rawmidi); 00126 handle_error: 00127 throw std::runtime_error(std::string(func) + ": " + error_message); 00128 } 00129 00130 JackALSARawMidiPort::~JackALSARawMidiPort() 00131 { 00132 DestroyNonBlockingPipe(fds); 00133 if (rawmidi) { 00134 int code = snd_rawmidi_close(rawmidi); 00135 if (code) { 00136 jack_error("JackALSARawMidiPort::~JackALSARawMidiPort - " 00137 "snd_rawmidi_close: %s", snd_strerror(code)); 00138 } 00139 rawmidi = 0; 00140 } 00141 } 00142 00143 const char * 00144 JackALSARawMidiPort::GetAlias() 00145 { 00146 return alias; 00147 } 00148 00149 int 00150 JackALSARawMidiPort::GetIOPollEvent() 00151 { 00152 unsigned short events; 00153 int code = snd_rawmidi_poll_descriptors_revents(rawmidi, alsa_poll_fds, 00154 alsa_poll_fd_count, 00155 &events); 00156 if (code) { 00157 jack_error("JackALSARawMidiPort::GetIOPollEvents - " 00158 "snd_rawmidi_poll_descriptors_revents: %s", 00159 snd_strerror(code)); 00160 return -1; 00161 } 00162 if (events & POLLNVAL) { 00163 jack_error("JackALSARawMidiPort::GetIOPollEvents - the file " 00164 "descriptor is invalid."); 00165 return -1; 00166 } 00167 if (events & POLLERR) { 00168 jack_error("JackALSARawMidiPort::GetIOPollEvents - an error has " 00169 "occurred on the device or stream."); 00170 return -1; 00171 } 00172 return (events & io_mask) ? 1 : 0; 00173 } 00174 00175 const char * 00176 JackALSARawMidiPort::GetName() 00177 { 00178 return name; 00179 } 00180 00181 int 00182 JackALSARawMidiPort::GetPollDescriptorCount() 00183 { 00184 return alsa_poll_fd_count + 1; 00185 } 00186 00187 int 00188 JackALSARawMidiPort::GetQueuePollEvent() 00189 { 00190 unsigned short events = queue_poll_fd->revents; 00191 if (events & POLLNVAL) { 00192 jack_error("JackALSARawMidiPort::GetQueuePollEvents - the file " 00193 "descriptor is invalid."); 00194 return -1; 00195 } 00196 if (events & POLLERR) { 00197 jack_error("JackALSARawMidiPort::GetQueuePollEvents - an error has " 00198 "occurred on the device or stream."); 00199 return -1; 00200 } 00201 int event = events & POLLIN ? 1 : 0; 00202 if (event) { 00203 char c; 00204 ssize_t result = read(fds[0], &c, 1); 00205 assert(result); 00206 if (result < 0) { 00207 jack_error("JackALSARawMidiPort::GetQueuePollEvents - error " 00208 "reading a byte from the pipe file descriptor: %s", 00209 strerror(errno)); 00210 return -1; 00211 } 00212 } 00213 return event; 00214 } 00215 00216 void 00217 JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd) 00218 { 00219 alsa_poll_fds = poll_fd + 1; 00220 assert(snd_rawmidi_poll_descriptors(rawmidi, alsa_poll_fds, 00221 alsa_poll_fd_count) == 00222 alsa_poll_fd_count); 00223 queue_poll_fd = poll_fd; 00224 queue_poll_fd->events = POLLERR | POLLIN | POLLNVAL; 00225 queue_poll_fd->fd = fds[0]; 00226 SetIOEventsEnabled(true); 00227 } 00228 00229 void 00230 JackALSARawMidiPort::SetIOEventsEnabled(bool enabled) 00231 { 00232 unsigned short mask = POLLNVAL | POLLERR | (enabled ? io_mask : 0); 00233 for (int i = 0; i < alsa_poll_fd_count; i++) { 00234 (alsa_poll_fds + i)->events = mask; 00235 } 00236 } 00237 00238 bool 00239 JackALSARawMidiPort::TriggerQueueEvent() 00240 { 00241 char c; 00242 ssize_t result = write(fds[1], &c, 1); 00243 assert(result <= 1); 00244 switch (result) { 00245 case 1: 00246 return true; 00247 case 0: 00248 jack_error("JackALSARawMidiPort::TriggerQueueEvent - error writing a " 00249 "byte to the pipe file descriptor: %s", strerror(errno)); 00250 break; 00251 default: 00252 jack_error("JackALSARawMidiPort::TriggerQueueEvent - couldn't write a " 00253 "byte to the pipe file descriptor."); 00254 } 00255 return false; 00256 }