00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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 }