Jack2 1.9.12

JackALSARawMidiPort.cpp
1 /*
2 Copyright (C) 2011 Devin Anderson
3
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.
8
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.
13
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.
17
18 */
19
20 #include <cassert>
21 #include <stdexcept>
22 #include <string>
23
24 #include "JackALSARawMidiPort.h"
25 #include "JackALSARawMidiUtil.h"
26 #include "JackError.h"
27
28 using Jack::JackALSARawMidiPort;
29
30 JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
31 size_t index, unsigned short io_mask)
32 {
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 *alias_suffix;
40 const char *error_message;
41 snd_rawmidi_t **in;
42 const char *name_prefix;
43 snd_rawmidi_t **out;
44 if (snd_rawmidi_info_get_stream(info) == SND_RAWMIDI_STREAM_OUTPUT) {
45 alias_suffix = "out";
46 in = 0;
47 name_prefix = "system:midi_playback_";
48 out = &rawmidi;
49 } else {
50 alias_suffix = "in";
51 in = &rawmidi;
52 name_prefix = "system:midi_capture_";
53 out = 0;
54 }
55 const char *func;
56 int code = snd_rawmidi_open(in, out, device_id, SND_RAWMIDI_NONBLOCK);
57 if (code) {
58 error_message = snd_strerror(code);
59 func = "snd_rawmidi_open";
60 goto handle_error;
61 }
62 snd_rawmidi_params_t *params;
63 code = snd_rawmidi_params_malloc(&params);
64 if (code) {
65 error_message = snd_strerror(code);
66 func = "snd_rawmidi_params_malloc";
67 goto close;
68 }
69 code = snd_rawmidi_params_current(rawmidi, params);
70 if (code) {
71 error_message = snd_strerror(code);
72 func = "snd_rawmidi_params_current";
73 goto free_params;
74 }
75 code = snd_rawmidi_params_set_avail_min(rawmidi, params, 1);
76 if (code) {
77 error_message = snd_strerror(code);
78 func = "snd_rawmidi_params_set_avail_min";
79 goto free_params;
80 }
81
82 // Minimum buffer size allowed by ALSA
83 code = snd_rawmidi_params_set_buffer_size(rawmidi, params, 32);
84 if (code) {
85 error_message = snd_strerror(code);
86 func = "snd_rawmidi_params_set_buffer_size";
87 goto free_params;
88 }
89
90 code = snd_rawmidi_params_set_no_active_sensing(rawmidi, params, 1);
91 if (code) {
92 error_message = snd_strerror(code);
93 func = "snd_rawmidi_params_set_no_active_sensing";
94 goto free_params;
95 }
96 code = snd_rawmidi_params(rawmidi, params);
97 if (code) {
98 error_message = snd_strerror(code);
99 func = "snd_rawmidi_params";
100 goto free_params;
101 }
102 snd_rawmidi_params_free(params);
103 alsa_poll_fd_count = snd_rawmidi_poll_descriptors_count(rawmidi);
104 if (! alsa_poll_fd_count) {
105 error_message = "returned '0' count for poll descriptors";
106 func = "snd_rawmidi_poll_descriptors_count";
107 goto close;
108 }
109 try {
110 CreateNonBlockingPipe(fds);
111 } catch (std::exception e) {
112 error_message = e.what();
113 func = "CreateNonBlockingPipe";
114 goto close;
115 }
116 snprintf(alias, sizeof(alias), "system:%d-%d %s %d %s", card + 1,
117 device + 1, snd_rawmidi_info_get_name(info), subdevice + 1,
118 alias_suffix);
119 snprintf(name, sizeof(name), "%s%zu", name_prefix, index + 1);
120 this->io_mask = io_mask;
121 return;
122 free_params:
123 snd_rawmidi_params_free(params);
124 close:
125 snd_rawmidi_close(rawmidi);
126 handle_error:
127 throw std::runtime_error(std::string(func) + ": " + error_message);
128 }
129
130 JackALSARawMidiPort::~JackALSARawMidiPort()
131 {
132 DestroyNonBlockingPipe(fds);
133 if (rawmidi) {
134 int code = snd_rawmidi_close(rawmidi);
135 if (code) {
136 jack_error("JackALSARawMidiPort::~JackALSARawMidiPort - "
137 "snd_rawmidi_close: %s", snd_strerror(code));
138 }
139 rawmidi = 0;
140 }
141 }
142
143 const char *
144 JackALSARawMidiPort::GetAlias()
145 {
146 return alias;
147 }
148
149 int
150 JackALSARawMidiPort::GetIOPollEvent()
151 {
152 unsigned short events;
153 int code = snd_rawmidi_poll_descriptors_revents(rawmidi, alsa_poll_fds,
154 alsa_poll_fd_count,
155 &events);
156 if (code) {
157 jack_error("JackALSARawMidiPort::GetIOPollEvents - "
158 "snd_rawmidi_poll_descriptors_revents: %s",
159 snd_strerror(code));
160 return -1;
161 }
162 if (events & POLLNVAL) {
163 jack_error("JackALSARawMidiPort::GetIOPollEvents - the file "
164 "descriptor is invalid.");
165 return -1;
166 }
167 if (events & POLLERR) {
168 jack_error("JackALSARawMidiPort::GetIOPollEvents - an error has "
169 "occurred on the device or stream.");
170 return -1;
171 }
172 return (events & io_mask) ? 1 : 0;
173 }
174
175 const char *
176 JackALSARawMidiPort::GetName()
177 {
178 return name;
179 }
180
181 int
182 JackALSARawMidiPort::GetPollDescriptorCount()
183 {
184 return alsa_poll_fd_count + 1;
185 }
186
187 int
188 JackALSARawMidiPort::GetQueuePollEvent()
189 {
190 unsigned short events = queue_poll_fd->revents;
191 if (events & POLLNVAL) {
192 jack_error("JackALSARawMidiPort::GetQueuePollEvents - the file "
193 "descriptor is invalid.");
194 return -1;
195 }
196 if (events & POLLERR) {
197 jack_error("JackALSARawMidiPort::GetQueuePollEvents - an error has "
198 "occurred on the device or stream.");
199 return -1;
200 }
201 int event = events & POLLIN ? 1 : 0;
202 if (event) {
203 char c;
204 ssize_t result = read(fds[0], &c, 1);
205 assert(result);
206 if (result < 0) {
207 jack_error("JackALSARawMidiPort::GetQueuePollEvents - error "
208 "reading a byte from the pipe file descriptor: %s",
209 strerror(errno));
210 return -1;
211 }
212 }
213 return event;
214 }
215
216 void
217 JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd)
218 {
219 alsa_poll_fds = poll_fd + 1;
220 assert(snd_rawmidi_poll_descriptors(rawmidi, alsa_poll_fds,
221 alsa_poll_fd_count) ==
222 alsa_poll_fd_count);
223 queue_poll_fd = poll_fd;
224 queue_poll_fd->events = POLLERR | POLLIN | POLLNVAL;
225 queue_poll_fd->fd = fds[0];
226 SetIOEventsEnabled(true);
227 }
228
229 void
230 JackALSARawMidiPort::SetIOEventsEnabled(bool enabled)
231 {
232 unsigned short mask = POLLNVAL | POLLERR | (enabled ? io_mask : 0);
233 for (int i = 0; i < alsa_poll_fd_count; i++) {
234 (alsa_poll_fds + i)->events = mask;
235 }
236 }
237
238 bool
239 JackALSARawMidiPort::TriggerQueueEvent()
240 {
241 char c;
242 ssize_t result = write(fds[1], &c, 1);
243 assert(result <= 1);
244 switch (result) {
245 case 1:
246 return true;
247 case 0:
248 jack_error("JackALSARawMidiPort::TriggerQueueEvent - error writing a "
249 "byte to the pipe file descriptor: %s", strerror(errno));
250 break;
251 default:
252 jack_error("JackALSARawMidiPort::TriggerQueueEvent - couldn't write a "
253 "byte to the pipe file descriptor.");
254 }
255 return false;
256 }
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
Jack::JackALSARawMidiPort
Definition: JackALSARawMidiPort.h:30