MIDI port pretty names (#498)
[jack2.git] / linux / alsarawmidi / JackALSARawMidiPort.cpp
blob70e1fa71e6a29b75d023fae5d96e65a6c0a77275
1 /*
2 Copyright (C) 2011 Devin Anderson
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <cassert>
21 #include <stdexcept>
22 #include <string>
24 #include "JackALSARawMidiPort.h"
25 #include "JackALSARawMidiUtil.h"
26 #include "JackError.h"
28 using Jack::JackALSARawMidiPort;
30 JackALSARawMidiPort::JackALSARawMidiPort(const char *client_name, snd_rawmidi_info_t *info,
31 size_t index, unsigned short io_mask)
33 int card = snd_rawmidi_info_get_card(info);
34 unsigned int device = snd_rawmidi_info_get_device(info);
35 unsigned int subdevice = snd_rawmidi_info_get_subdevice(info);
36 char device_id[32];
37 snprintf(device_id, sizeof(device_id), "hw:%d,%d,%d", card, device,
38 subdevice);
39 const char* driver_name = snd_rawmidi_info_get_name(info);
40 const char *alias_suffix;
41 const char *error_message;
42 snd_rawmidi_t **in;
43 const char *port_name;
44 snd_rawmidi_t **out;
45 if (snd_rawmidi_info_get_stream(info) == SND_RAWMIDI_STREAM_OUTPUT) {
46 alias_suffix = "out";
47 in = 0;
48 port_name = "playback_";
49 out = &rawmidi;
50 } else {
51 alias_suffix = "in";
52 in = &rawmidi;
53 port_name = "capture_";
54 out = 0;
56 const char *func;
57 int code = snd_rawmidi_open(in, out, device_id, SND_RAWMIDI_NONBLOCK);
58 if (code) {
59 error_message = snd_strerror(code);
60 func = "snd_rawmidi_open";
61 goto handle_error;
63 snd_rawmidi_params_t *params;
64 code = snd_rawmidi_params_malloc(&params);
65 if (code) {
66 error_message = snd_strerror(code);
67 func = "snd_rawmidi_params_malloc";
68 goto close;
70 code = snd_rawmidi_params_current(rawmidi, params);
71 if (code) {
72 error_message = snd_strerror(code);
73 func = "snd_rawmidi_params_current";
74 goto free_params;
76 code = snd_rawmidi_params_set_avail_min(rawmidi, params, 1);
77 if (code) {
78 error_message = snd_strerror(code);
79 func = "snd_rawmidi_params_set_avail_min";
80 goto free_params;
83 // Minimum buffer size allowed by ALSA
84 code = snd_rawmidi_params_set_buffer_size(rawmidi, params, 32);
85 if (code) {
86 error_message = snd_strerror(code);
87 func = "snd_rawmidi_params_set_buffer_size";
88 goto free_params;
91 code = snd_rawmidi_params_set_no_active_sensing(rawmidi, params, 1);
92 if (code) {
93 error_message = snd_strerror(code);
94 func = "snd_rawmidi_params_set_no_active_sensing";
95 goto free_params;
97 code = snd_rawmidi_params(rawmidi, params);
98 if (code) {
99 error_message = snd_strerror(code);
100 func = "snd_rawmidi_params";
101 goto free_params;
103 snd_rawmidi_params_free(params);
104 alsa_poll_fd_count = snd_rawmidi_poll_descriptors_count(rawmidi);
105 if (! alsa_poll_fd_count) {
106 error_message = "returned '0' count for poll descriptors";
107 func = "snd_rawmidi_poll_descriptors_count";
108 goto close;
110 try {
111 CreateNonBlockingPipe(fds);
112 } catch (std::exception e) {
113 error_message = e.what();
114 func = "CreateNonBlockingPipe";
115 goto close;
117 snprintf(alias, sizeof(alias), "system:%d-%d %s %d %s", card + 1,
118 device + 1, driver_name, subdevice + 1,
119 alias_suffix);
120 snprintf(name, sizeof(name), "%s:%s%zu", client_name, port_name, index + 1);
121 strncpy(device_name, driver_name, sizeof(device_name) - 1);
122 this->io_mask = io_mask;
123 return;
124 free_params:
125 snd_rawmidi_params_free(params);
126 close:
127 snd_rawmidi_close(rawmidi);
128 handle_error:
129 throw std::runtime_error(std::string(func) + ": " + error_message);
132 JackALSARawMidiPort::~JackALSARawMidiPort()
134 DestroyNonBlockingPipe(fds);
135 if (rawmidi) {
136 int code = snd_rawmidi_close(rawmidi);
137 if (code) {
138 jack_error("JackALSARawMidiPort::~JackALSARawMidiPort - "
139 "snd_rawmidi_close: %s", snd_strerror(code));
141 rawmidi = 0;
145 const char *
146 JackALSARawMidiPort::GetAlias()
148 return alias;
152 JackALSARawMidiPort::GetIOPollEvent()
154 unsigned short events;
155 int code = snd_rawmidi_poll_descriptors_revents(rawmidi, alsa_poll_fds,
156 alsa_poll_fd_count,
157 &events);
158 if (code) {
159 jack_error("JackALSARawMidiPort::GetIOPollEvents - "
160 "snd_rawmidi_poll_descriptors_revents: %s",
161 snd_strerror(code));
162 return -1;
164 if (events & POLLNVAL) {
165 jack_error("JackALSARawMidiPort::GetIOPollEvents - the file "
166 "descriptor is invalid.");
167 return -1;
169 if (events & POLLERR) {
170 jack_error("JackALSARawMidiPort::GetIOPollEvents - an error has "
171 "occurred on the device or stream.");
172 return -1;
174 return (events & io_mask) ? 1 : 0;
177 const char *
178 JackALSARawMidiPort::GetName()
180 return name;
183 const char *
184 JackALSARawMidiPort::GetDeviceName()
186 return device_name;
190 JackALSARawMidiPort::GetPollDescriptorCount()
192 return alsa_poll_fd_count + 1;
196 JackALSARawMidiPort::GetQueuePollEvent()
198 unsigned short events = queue_poll_fd->revents;
199 if (events & POLLNVAL) {
200 jack_error("JackALSARawMidiPort::GetQueuePollEvents - the file "
201 "descriptor is invalid.");
202 return -1;
204 if (events & POLLERR) {
205 jack_error("JackALSARawMidiPort::GetQueuePollEvents - an error has "
206 "occurred on the device or stream.");
207 return -1;
209 int event = events & POLLIN ? 1 : 0;
210 if (event) {
211 char c;
212 ssize_t result = read(fds[0], &c, 1);
213 assert(result);
214 if (result < 0) {
215 jack_error("JackALSARawMidiPort::GetQueuePollEvents - error "
216 "reading a byte from the pipe file descriptor: %s",
217 strerror(errno));
218 return -1;
221 return event;
224 void
225 JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd)
227 alsa_poll_fds = poll_fd + 1;
228 assert(snd_rawmidi_poll_descriptors(rawmidi, alsa_poll_fds,
229 alsa_poll_fd_count) ==
230 alsa_poll_fd_count);
231 queue_poll_fd = poll_fd;
232 queue_poll_fd->events = POLLERR | POLLIN | POLLNVAL;
233 queue_poll_fd->fd = fds[0];
234 SetIOEventsEnabled(true);
237 void
238 JackALSARawMidiPort::SetIOEventsEnabled(bool enabled)
240 unsigned short mask = POLLNVAL | POLLERR | (enabled ? io_mask : 0);
241 for (int i = 0; i < alsa_poll_fd_count; i++) {
242 (alsa_poll_fds + i)->events = mask;
246 bool
247 JackALSARawMidiPort::TriggerQueueEvent()
249 char c;
250 ssize_t result = write(fds[1], &c, 1);
251 assert(result <= 1);
252 switch (result) {
253 case 1:
254 return true;
255 case 0:
256 jack_error("JackALSARawMidiPort::TriggerQueueEvent - error writing a "
257 "byte to the pipe file descriptor: %s", strerror(errno));
258 break;
259 default:
260 jack_error("JackALSARawMidiPort::TriggerQueueEvent - couldn't write a "
261 "byte to the pipe file descriptor.");
263 return false;