1 /*
2 MIDI Sequencer C++ library
3 Copyright (C) 2006-2021, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "errorcheck.h"
20 #include <drumstick/alsaclient.h>
21 /**
22 * @file subscription.cpp
23 * Implementation of classes managing ALSA sequencer subscriptions
24 */
25
26 /** @ingroup ALSAGroup */
27 namespace drumstick {
28 namespace ALSA {
29
30 /**
31 * @addtogroup ALSASubs
32 * @{
33 *
34 * Subscriptions are virtual MIDI cables between readable and writable ports.
35 *
36 * The ALSA sequencer readable ports are equivalent to the MIDI OUT ports in the
37 * real world. Similarly, the writable ports are equivalent to the MIDI IN ones.
38 * Subscriptions, like real MIDI cables, always involve a readable port (source)
39 * and a writable port (destination).
40 *
41 * Classes:
42 *
43 * Subscriber: This class is used to enumerate the subscribers of a given (root) port.
44 *
45 * Subscription: This class represents a connection between two ports.
46 *
47 * @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_subscribe.html
48 * @}
49 */
50
51 /**
52 * Default constructor
53 */
Subscriber()54 Subscriber::Subscriber()
55 {
56 snd_seq_query_subscribe_malloc(&m_Info);
57 }
58
59 /**
60 * Copy constructor
61 * @param other Existing Subscriber object reference
62 */
Subscriber(const Subscriber & other)63 Subscriber::Subscriber(const Subscriber& other)
64 {
65 snd_seq_query_subscribe_malloc(&m_Info);
66 snd_seq_query_subscribe_copy(m_Info, other.m_Info);
67 }
68
69 /**
70 * Constructor
71 * @param other Pointer to an ALSA query subscribe object
72 */
Subscriber(snd_seq_query_subscribe_t * other)73 Subscriber::Subscriber(snd_seq_query_subscribe_t* other)
74 {
75 snd_seq_query_subscribe_malloc(&m_Info);
76 snd_seq_query_subscribe_copy(m_Info, other);
77 }
78
79 /**
80 * Destructor
81 */
~Subscriber()82 Subscriber::~Subscriber()
83 {
84 snd_seq_query_subscribe_free(m_Info);
85 }
86
87 /**
88 * Copy the current object
89 * @return Pointer to the new object
90 */
clone()91 Subscriber* Subscriber::clone()
92 {
93 return new Subscriber(m_Info);
94 }
95
96 /**
97 * Assignment operator
98 * @param other Existing Subscriber object reference
99 * @return This object
100 */
operator =(const Subscriber & other)101 Subscriber& Subscriber::operator=(const Subscriber& other)
102 {
103 if (this == &other)
104 return *this;
105 snd_seq_query_subscribe_copy(m_Info, other.m_Info);
106 return *this;
107 }
108
109 /**
110 * Gets the subscriber's client number
111 * @return Client number
112 */
113 int
getClient()114 Subscriber::getClient()
115 {
116 return snd_seq_query_subscribe_get_client(m_Info);
117 }
118
119 /**
120 * Gets the subscriober's port number
121 * @return Port number
122 */
123 int
getPort()124 Subscriber::getPort()
125 {
126 return snd_seq_query_subscribe_get_port(m_Info);
127 }
128
129 /**
130 * Gets the subscriber's root address
131 * @return Pointer to the ALSA client/port address
132 */
133 const snd_seq_addr_t*
getRoot()134 Subscriber::getRoot()
135 {
136 return snd_seq_query_subscribe_get_root(m_Info);
137 }
138
139 /**
140 * Gets the subscription type (read or write).
141 * <ul>
142 * <li>SND_SEQ_QUERY_SUBS_READ: read subscriptions</li>
143 * <li>SND_SEQ_QUERY_SUBS_WRITE: write subscriptions</li>
144 * </ul>
145 * @return Subscription type
146 */
147 snd_seq_query_subs_type_t
getType()148 Subscriber::getType()
149 {
150 return snd_seq_query_subscribe_get_type(m_Info);
151 }
152
153 /**
154 * Gets the index of the subscriber container
155 * @return Index of the subscriber
156 */
157 int
getIndex()158 Subscriber::getIndex()
159 {
160 return snd_seq_query_subscribe_get_index(m_Info);
161 }
162
163 /**
164 * Gets the number of subscribers returned by a query operation
165 * @return Number of subscribers
166 */
167 int
getNumSubs()168 Subscriber::getNumSubs()
169 {
170 return snd_seq_query_subscribe_get_num_subs(m_Info);
171 }
172
173 /**
174 * Gets the subscriber's address
175 * @return Pointer to the ALSA address record
176 */
177 const snd_seq_addr_t*
getAddr()178 Subscriber::getAddr()
179 {
180 return snd_seq_query_subscribe_get_addr(m_Info);
181 }
182
183 /**
184 * Gets the subscriber's queue number
185 * @return Queue number
186 */
187 int
getQueue()188 Subscriber::getQueue()
189 {
190 return snd_seq_query_subscribe_get_queue(m_Info);
191 }
192
193 /**
194 * Gets the subscriber's exclusive flag
195 * @return Exclusive flag
196 */
197 bool
getExclusive()198 Subscriber::getExclusive()
199 {
200 return (snd_seq_query_subscribe_get_exclusive(m_Info) != 0);
201 }
202
203 /**
204 * Gets the susbcriber's time-update flag
205 * @return Time update flag
206 */
207 bool
getTimeUpdate()208 Subscriber::getTimeUpdate()
209 {
210 return (snd_seq_query_subscribe_get_time_update(m_Info) != 0);
211 }
212
213 /**
214 * Gets the subscriber's time real time-stamp flag
215 * @return Time real flag
216 */
217 bool
getTimeReal()218 Subscriber::getTimeReal()
219 {
220 return (snd_seq_query_subscribe_get_time_real(m_Info) != 0);
221 }
222
223 /**
224 * Sets the subscriber's client number
225 * @param client Client number
226 */
227 void
setClient(int client)228 Subscriber::setClient(int client)
229 {
230 snd_seq_query_subscribe_set_client(m_Info, client);
231 }
232
233 /**
234 * Sets the subscriber's port number
235 * @param port Port number
236 */
237 void
setPort(int port)238 Subscriber::setPort(int port)
239 {
240 snd_seq_query_subscribe_set_port(m_Info, port);
241 }
242
243 /**
244 * Sets the subscriber's root address
245 * @param addr Pointer to the root ALSA address record
246 */
247 void
setRoot(snd_seq_addr_t * addr)248 Subscriber::setRoot(snd_seq_addr_t* addr)
249 {
250 snd_seq_query_subscribe_set_root(m_Info, addr);
251 }
252
253 /**
254 * Sets the subscription type
255 * <ul>
256 * <li>SND_SEQ_QUERY_SUBS_READ: read subscriptions</li>
257 * <li>SND_SEQ_QUERY_SUBS_WRITE: write subscriptions</li>
258 * </ul>
259 * @param type Subscription type
260 */
261 void
setType(snd_seq_query_subs_type_t type)262 Subscriber::setType(snd_seq_query_subs_type_t type)
263 {
264 snd_seq_query_subscribe_set_type(m_Info, type);
265 }
266
267 /**
268 * Sets the index of the subscriber
269 * @param index Subscriber index
270 */
271 void
setIndex(int index)272 Subscriber::setIndex(int index)
273 {
274 snd_seq_query_subscribe_set_index(m_Info, index);
275 }
276
277 /**
278 * Gets the size of the ALSA query subscriber object
279 * @return Size of the ALSA object
280 */
281 int
getSizeOfInfo() const282 Subscriber::getSizeOfInfo() const
283 {
284 return snd_seq_query_subscribe_sizeof();
285 }
286
287 /**
288 * Default constructor
289 */
Subscription()290 Subscription::Subscription()
291 {
292 snd_seq_port_subscribe_malloc(&m_Info);
293 }
294
295 /**
296 * Copy constructor
297 * @param other Existing Subscription object reference
298 */
Subscription(const Subscription & other)299 Subscription::Subscription(const Subscription& other)
300 {
301 snd_seq_port_subscribe_malloc(&m_Info);
302 snd_seq_port_subscribe_copy(m_Info, other.m_Info);
303 }
304
305 /**
306 * Constructor
307 * @param other Pointer to an ALSA subscription object
308 */
Subscription(snd_seq_port_subscribe_t * other)309 Subscription::Subscription(snd_seq_port_subscribe_t* other)
310 {
311 snd_seq_port_subscribe_malloc(&m_Info);
312 snd_seq_port_subscribe_copy(m_Info, other);
313 }
314
315 /**
316 * Constructor
317 * @param seq Pointer to a MIDI Client object
318 */
Subscription(MidiClient * seq)319 Subscription::Subscription(MidiClient* seq)
320 {
321 snd_seq_port_subscribe_malloc(&m_Info);
322 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_port_subscription(seq->getHandle(), m_Info));
323 }
324
325 /**
326 * Destructor
327 * @return
328 */
~Subscription()329 Subscription::~Subscription()
330 {
331 snd_seq_port_subscribe_free(m_Info);
332 }
333
334 /**
335 * Copy the current object
336 * @return Pointer to the new object
337 */
338 Subscription*
clone()339 Subscription::clone()
340 {
341 return new Subscription(m_Info);
342 }
343
344 /**
345 * Assignment operator
346 * @param other Existing subscription object reference
347 * @return This object
348 */
349 Subscription&
operator =(const Subscription & other)350 Subscription::operator=(const Subscription& other)
351 {
352 if (this == &other)
353 return *this;
354 snd_seq_port_subscribe_copy(m_Info, other.m_Info);
355 return *this;
356 }
357
358 /**
359 * Gets the sender address of the subscription (MIDI OUT port)
360 * @return Pointer to the sender ALSA address record
361 */
362 const snd_seq_addr_t*
getSender()363 Subscription::getSender()
364 {
365 return snd_seq_port_subscribe_get_sender(m_Info);
366 }
367
368 /**
369 * Gets the destination address of the subscription (MIDI IN port)
370 * @return Pointer to the destination ALSA address record
371 */
372 const snd_seq_addr_t*
getDest()373 Subscription::getDest()
374 {
375 return snd_seq_port_subscribe_get_dest(m_Info);
376 }
377
378 /**
379 * Gets the susbcription's queue number
380 * @return Queue number
381 */
382 int
getQueue()383 Subscription::getQueue()
384 {
385 return snd_seq_port_subscribe_get_queue(m_Info);
386 }
387
388 /**
389 * Gets the subscription's exclusive flag
390 * @return Exclusive flag
391 */
392 bool
getExclusive()393 Subscription::getExclusive()
394 {
395 return (snd_seq_port_subscribe_get_exclusive(m_Info) != 0);
396 }
397
398 /**
399 * Gets the susbcription's time-update flag
400 * @return Time-update flag
401 */
402 bool
getTimeUpdate()403 Subscription::getTimeUpdate()
404 {
405 return (snd_seq_port_subscribe_get_time_update(m_Info) != 0);
406 }
407
408 /**
409 * Gets the susbcription's time-real (time-stamping) flag
410 * @return Time real flag
411 */
412 bool
getTimeReal()413 Subscription::getTimeReal()
414 {
415 return (snd_seq_port_subscribe_get_time_real(m_Info) != 0);
416 }
417
418 /**
419 * Sets the Subscription's sender (MIDI OUT) port
420 * @param addr Pointer to the sender ALSA address record
421 */
422 void
setSender(const snd_seq_addr_t * addr)423 Subscription::setSender(const snd_seq_addr_t* addr)
424 {
425 snd_seq_port_subscribe_set_sender(m_Info, addr);
426 }
427
428 /**
429 * Sets the Subscription's destination (MIDI IN) port
430 * @param addr Pointer to the destination ALSA address record
431 */
432 void
setDest(const snd_seq_addr_t * addr)433 Subscription::setDest(const snd_seq_addr_t* addr)
434 {
435 snd_seq_port_subscribe_set_dest(m_Info, addr);
436 }
437
438 /**
439 * Sets the Subscription's Queue number
440 * @param q Queue number
441 */
442 void
setQueue(int q)443 Subscription::setQueue(int q)
444 {
445 snd_seq_port_subscribe_set_queue(m_Info, q);
446 }
447
448 /**
449 * Sets the subscription's exclusive flag
450 * @param val Exclusive flag
451 */
452 void
setExclusive(bool val)453 Subscription::setExclusive(bool val)
454 {
455 snd_seq_port_subscribe_set_exclusive(m_Info, val?1:0);
456 }
457
458 /**
459 * Sets the susbcription's time-update flag
460 * @param val Time update flag
461 */
462 void
setTimeUpdate(bool val)463 Subscription::setTimeUpdate(bool val)
464 {
465 snd_seq_port_subscribe_set_time_update(m_Info, val?1:0);
466 }
467
468 /**
469 * Sets the subscription's time real (time-stamping) flag
470 * @param val Time real flag
471 */
472 void
setTimeReal(bool val)473 Subscription::setTimeReal(bool val)
474 {
475 snd_seq_port_subscribe_set_time_real(m_Info, val?1:0);
476 }
477
478 /**
479 * Sets the Subscription's sender (MIDI OUT) port
480 * @param client Client number
481 * @param port Port number
482 */
483 void
setSender(unsigned char client,unsigned char port)484 Subscription::setSender(unsigned char client, unsigned char port)
485 {
486 snd_seq_addr_t addr;
487 addr.client = client;
488 addr.port = port;
489 setSender(&addr);
490 }
491
492 /**
493 * Sets the Subscription's destination (MIDI IN) port
494 * @param client Client number
495 * @param port Port number
496 */
497 void
setDest(unsigned char client,unsigned char port)498 Subscription::setDest(unsigned char client, unsigned char port)
499 {
500 snd_seq_addr_t addr;
501 addr.client = client;
502 addr.port = port;
503 setDest(&addr);
504 }
505
506 /**
507 * Performs the subscription in the ALSA sequencer subsystem.
508 * Neither the sender nor the destination ports need to belong to the
509 * same MidiClient instance performing the subscription.
510 * @param seq MidiClient instance pointer
511 */
512 void
subscribe(MidiClient * seq)513 Subscription::subscribe(MidiClient* seq)
514 {
515 if ((m_Info == nullptr) || (seq == nullptr) || !(seq->isOpened()))
516 {
517 return;
518 }
519 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_subscribe_port(seq->getHandle(), m_Info));
520 }
521
522 /**
523 * Breaks the subscription in the ALSA sequencer subsystem.
524 * Neither the sender nor the destination ports need to belong to the
525 * same MidiClient instance breaking the subscription.
526 * @param seq MidiClient instance pointer
527 */
528 void
unsubscribe(MidiClient * seq)529 Subscription::unsubscribe(MidiClient* seq)
530 {
531 if ((m_Info == nullptr) || (seq == nullptr) || !(seq->isOpened()))
532 {
533 return;
534 }
535 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_unsubscribe_port(seq->getHandle(), m_Info));
536 }
537
538 /**
539 * Gets the size of the ALSA subscription object
540 * @return Size of the ALSA object
541 */
542 int
getSizeOfInfo() const543 Subscription::getSizeOfInfo() const
544 {
545 return snd_seq_port_subscribe_sizeof();
546 }
547
548 } // namespace ALSA
549 } // namespace drumstick
550
551