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.
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
);
37 snprintf(device_id
, sizeof(device_id
), "hw:%d,%d,%d", card
, device
,
39 const char* driver_name
= snd_rawmidi_info_get_name(info
);
40 const char *alias_suffix
;
41 const char *error_message
;
43 const char *port_name
;
45 if (snd_rawmidi_info_get_stream(info
) == SND_RAWMIDI_STREAM_OUTPUT
) {
48 port_name
= "playback_";
53 port_name
= "capture_";
57 int code
= snd_rawmidi_open(in
, out
, device_id
, SND_RAWMIDI_NONBLOCK
);
59 error_message
= snd_strerror(code
);
60 func
= "snd_rawmidi_open";
63 snd_rawmidi_params_t
*params
;
64 code
= snd_rawmidi_params_malloc(¶ms
);
66 error_message
= snd_strerror(code
);
67 func
= "snd_rawmidi_params_malloc";
70 code
= snd_rawmidi_params_current(rawmidi
, params
);
72 error_message
= snd_strerror(code
);
73 func
= "snd_rawmidi_params_current";
76 code
= snd_rawmidi_params_set_avail_min(rawmidi
, params
, 1);
78 error_message
= snd_strerror(code
);
79 func
= "snd_rawmidi_params_set_avail_min";
83 // Minimum buffer size allowed by ALSA
84 code
= snd_rawmidi_params_set_buffer_size(rawmidi
, params
, 32);
86 error_message
= snd_strerror(code
);
87 func
= "snd_rawmidi_params_set_buffer_size";
91 code
= snd_rawmidi_params_set_no_active_sensing(rawmidi
, params
, 1);
93 error_message
= snd_strerror(code
);
94 func
= "snd_rawmidi_params_set_no_active_sensing";
97 code
= snd_rawmidi_params(rawmidi
, params
);
99 error_message
= snd_strerror(code
);
100 func
= "snd_rawmidi_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";
111 CreateNonBlockingPipe(fds
);
112 } catch (std::exception e
) {
113 error_message
= e
.what();
114 func
= "CreateNonBlockingPipe";
117 snprintf(alias
, sizeof(alias
), "system:%d-%d %s %d %s", card
+ 1,
118 device
+ 1, driver_name
, subdevice
+ 1,
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
;
125 snd_rawmidi_params_free(params
);
127 snd_rawmidi_close(rawmidi
);
129 throw std::runtime_error(std::string(func
) + ": " + error_message
);
132 JackALSARawMidiPort::~JackALSARawMidiPort()
134 DestroyNonBlockingPipe(fds
);
136 int code
= snd_rawmidi_close(rawmidi
);
138 jack_error("JackALSARawMidiPort::~JackALSARawMidiPort - "
139 "snd_rawmidi_close: %s", snd_strerror(code
));
146 JackALSARawMidiPort::GetAlias()
152 JackALSARawMidiPort::GetIOPollEvent()
154 unsigned short events
;
155 int code
= snd_rawmidi_poll_descriptors_revents(rawmidi
, alsa_poll_fds
,
159 jack_error("JackALSARawMidiPort::GetIOPollEvents - "
160 "snd_rawmidi_poll_descriptors_revents: %s",
164 if (events
& POLLNVAL
) {
165 jack_error("JackALSARawMidiPort::GetIOPollEvents - the file "
166 "descriptor is invalid.");
169 if (events
& POLLERR
) {
170 jack_error("JackALSARawMidiPort::GetIOPollEvents - an error has "
171 "occurred on the device or stream.");
174 return (events
& io_mask
) ? 1 : 0;
178 JackALSARawMidiPort::GetName()
184 JackALSARawMidiPort::GetDeviceName()
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.");
204 if (events
& POLLERR
) {
205 jack_error("JackALSARawMidiPort::GetQueuePollEvents - an error has "
206 "occurred on the device or stream.");
209 int event
= events
& POLLIN
? 1 : 0;
212 ssize_t result
= read(fds
[0], &c
, 1);
215 jack_error("JackALSARawMidiPort::GetQueuePollEvents - error "
216 "reading a byte from the pipe file descriptor: %s",
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
) ==
231 queue_poll_fd
= poll_fd
;
232 queue_poll_fd
->events
= POLLERR
| POLLIN
| POLLNVAL
;
233 queue_poll_fd
->fd
= fds
[0];
234 SetIOEventsEnabled(true);
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
;
247 JackALSARawMidiPort::TriggerQueueEvent()
250 ssize_t result
= write(fds
[1], &c
, 1);
256 jack_error("JackALSARawMidiPort::TriggerQueueEvent - error writing a "
257 "byte to the pipe file descriptor: %s", strerror(errno
));
260 jack_error("JackALSARawMidiPort::TriggerQueueEvent - couldn't write a "
261 "byte to the pipe file descriptor.");