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