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 <cmath>
21 #include <drumstick/alsaclient.h>
22 #include <drumstick/alsaevent.h>
23 #include <drumstick/alsaqueue.h>
24 #include <drumstick/alsatimer.h>
25 
26 /**
27  * @file alsaqueue.cpp
28  * Implementation of classes managing ALSA Sequencer queues
29  */
30 
31 namespace drumstick {
32 namespace ALSA {
33 
34 /**
35  * This is the value for the base skew used in ALSA. It is not possible
36  * to assign an arbitrary value (ALSA version <= 1.0.20).
37  */
38 const unsigned int SKEW_BASE = 0x10000;
39 
40 /**
41  * @addtogroup ALSAQueue
42  * @{
43  *
44  * ALSA events can be delivered to the output ports at scheduled times using the
45  * queues. There is a small amount of available queues in the system, so this is
46  * a limited resource. Queues are also used to time-stamp incoming events.
47  *
48  * Classes:
49  *
50  * QueueInfo holds several properties about the queue object.
51  *
52  * QueueStatus is used to retrieve the status of the queue object.
53  *
54  * QueueTempo holds properties to get and set the tempo in the queue object.
55  *
56  * QueueTimer holds properties about the Timer used in the queue object.
57  *
58  * MidiQueue represents the queue object.
59  *
60  * @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_queue.html
61  * @}
62  */
63 
64 /**
65  * Default constructor
66  */
QueueInfo()67 QueueInfo::QueueInfo()
68 {
69     snd_seq_queue_info_malloc(&m_Info);
70 }
71 
72 /**
73  * Constructor.
74  * @param other ALSA queue info object pointer
75  */
QueueInfo(snd_seq_queue_info_t * other)76 QueueInfo::QueueInfo(snd_seq_queue_info_t* other)
77 {
78     snd_seq_queue_info_malloc(&m_Info);
79     snd_seq_queue_info_copy(m_Info, other);
80 }
81 
82 /**
83  * Copy constructor.
84  * @param other An existing QueueInfo object reference.
85  */
QueueInfo(const QueueInfo & other)86 QueueInfo::QueueInfo(const QueueInfo& other)
87 {
88     snd_seq_queue_info_malloc(&m_Info);
89     snd_seq_queue_info_copy(m_Info, other.m_Info);
90 }
91 
92 /**
93  * Destructor
94  */
~QueueInfo()95 QueueInfo::~QueueInfo()
96 {
97     snd_seq_queue_info_free(m_Info);
98 }
99 
100 /**
101  * Copy the current object and return the copy.
102  * @return The pointer to the new object.
103  */
clone()104 QueueInfo* QueueInfo::clone()
105 {
106     return new QueueInfo(m_Info);
107 }
108 
109 /**
110  * Assignment operator.
111  * @param other An existing QueueInfo object reference.
112  * @return This object.
113  */
operator =(const QueueInfo & other)114 QueueInfo& QueueInfo::operator=(const QueueInfo& other)
115 {
116     if (this == &other)
117         return *this;
118     snd_seq_queue_info_copy(m_Info, other.m_Info);
119     return *this;
120 }
121 
122 /**
123  * Gets the queue's numeric identifier.
124  * @return The numeric identifier.
125  */
getId()126 int QueueInfo::getId()
127 {
128     return snd_seq_queue_info_get_queue(m_Info);
129 }
130 
131 /**
132  * Gets the queue name
133  * @return The queue name.
134  */
getName()135 QString QueueInfo::getName()
136 {
137     return QString(snd_seq_queue_info_get_name(m_Info));
138 }
139 
140 /**
141  * Gets the owner's client id of the queue.
142  * @return the owner's client id.
143  */
getOwner()144 int QueueInfo::getOwner()
145 {
146     return snd_seq_queue_info_get_owner(m_Info);
147 }
148 
149 /**
150  * Returns the locking status of the queue
151  * @return The locking status.
152  */
isLocked()153 bool QueueInfo::isLocked()
154 {
155     return (snd_seq_queue_info_get_locked(m_Info) != 0);
156 }
157 
158 /**
159  * Gets the flags of the queue.
160  * @return The flags of the queue.
161  */
getFlags()162 unsigned int QueueInfo::getFlags()
163 {
164     return snd_seq_queue_info_get_flags(m_Info);
165 }
166 
167 /**
168  * Sets the queue name
169  * @param value The queue name
170  */
setName(QString value)171 void QueueInfo::setName(QString value)
172 {
173     snd_seq_queue_info_set_name(m_Info, value.toLocal8Bit().data());
174 }
175 
176 /**
177  * Sets the client ID of the owner
178  * @param value The client ID of the owner
179  */
setOwner(int value)180 void QueueInfo::setOwner(int value)
181 {
182     snd_seq_queue_info_set_owner(m_Info, value);
183 }
184 
185 /**
186  * Sets the bit flags of the queue
187  * @param value The bit flags
188  */
setFlags(unsigned int value)189 void QueueInfo::setFlags(unsigned int value)
190 {
191     snd_seq_queue_info_set_flags(m_Info, value);
192 }
193 
194 /**
195  * Sets the locked status of the queue
196  * @param locked The locked status
197  */
setLocked(bool locked)198 void QueueInfo::setLocked(bool locked)
199 {
200     snd_seq_queue_info_set_locked(m_Info, locked ? 1 : 0);
201 }
202 
203 /**
204  * Gets the size of the ALSA queue info object.
205  * @return The size of the ALSA object.
206  */
getInfoSize() const207 int QueueInfo::getInfoSize() const
208 {
209     return snd_seq_queue_info_sizeof();
210 }
211 
212 
213 /**
214  * Default constructor
215  */
QueueStatus()216 QueueStatus::QueueStatus()
217 {
218     snd_seq_queue_status_malloc(&m_Info);
219 }
220 
221 /**
222  * Constructor
223  * @param other ALSA queue status object pointer
224  */
QueueStatus(snd_seq_queue_status_t * other)225 QueueStatus::QueueStatus(snd_seq_queue_status_t* other)
226 {
227     snd_seq_queue_status_malloc(&m_Info);
228     snd_seq_queue_status_copy(m_Info, other);
229 }
230 
231 /**
232  * Copy constructor
233  * @param other An existing QueueStatus object reference
234  */
QueueStatus(const QueueStatus & other)235 QueueStatus::QueueStatus(const QueueStatus& other)
236 {
237     snd_seq_queue_status_malloc(&m_Info);
238     snd_seq_queue_status_copy(m_Info, other.m_Info);
239 }
240 
241 /**
242  * Destructor
243  */
~QueueStatus()244 QueueStatus::~QueueStatus()
245 {
246     snd_seq_queue_status_free(m_Info);
247 }
248 
249 /**
250  * Copy the current object and return the copy
251  * @return The pointer to the new object
252  */
clone()253 QueueStatus* QueueStatus::clone()
254 {
255     return new QueueStatus(m_Info);
256 }
257 
258 /**
259  * Assignment operator
260  * @param other An existing QueueStatus object reference
261  * @return This object
262  */
operator =(const QueueStatus & other)263 QueueStatus& QueueStatus::operator=(const QueueStatus& other)
264 {
265     if (this == &other)
266         return *this;
267     snd_seq_queue_status_copy(m_Info, other.m_Info);
268     return *this;
269 }
270 
271 /**
272  * Gets the queue's numeric identifier
273  * @return The queue's numeric identifier.
274  */
getId()275 int QueueStatus::getId()
276 {
277     return snd_seq_queue_status_get_queue(m_Info);
278 }
279 
280 /**
281  * Gets the number of queued events
282  * @return The number of queued events
283  */
getEvents()284 int QueueStatus::getEvents()
285 {
286     return snd_seq_queue_status_get_events(m_Info);
287 }
288 
289 /**
290  * Gets the real time (secods and nanoseconds) of the queue
291  * @return The queue's real time.
292  */
getRealtime()293 const snd_seq_real_time_t* QueueStatus::getRealtime()
294 {
295     return snd_seq_queue_status_get_real_time(m_Info);
296 }
297 
298 /**
299  * Gets the running status bits
300  * @return The running status bits
301  */
getStatusBits()302 unsigned int QueueStatus::getStatusBits()
303 {
304     return snd_seq_queue_status_get_status(m_Info);
305 }
306 
307 /**
308  * Gets the musical time (ticks) of the queue
309  * @return The musical time
310  */
getTickTime()311 snd_seq_tick_time_t QueueStatus::getTickTime()
312 {
313     return snd_seq_queue_status_get_tick_time(m_Info);
314 }
315 
316 /**
317  * Gets the size of the ALSA status object
318  * @return The size of the ALSA object
319  */
getInfoSize() const320 int QueueStatus::getInfoSize() const
321 {
322     return snd_seq_queue_status_sizeof();
323 }
324 
325 /**
326  * Gets the queue's running state
327  * @return True if the queue is running
328  */
isRunning()329 bool QueueStatus::isRunning()
330 {
331     return (snd_seq_queue_status_get_status(m_Info) != 0);
332 }
333 
334 /**
335  * Gets the clock time in seconds of the queue
336  * @return The queue time in seconds
337  */
getClockTime()338 double QueueStatus::getClockTime()
339 {
340     const snd_seq_real_time_t* time = snd_seq_queue_status_get_real_time(m_Info);
341     return (time->tv_sec * 1.0) + (time->tv_nsec * 1.0e-9);
342 }
343 
344 /**
345  * Default constructor
346  */
QueueTempo()347 QueueTempo::QueueTempo()
348 {
349     snd_seq_queue_tempo_malloc(&m_Info);
350 }
351 
352 /**
353  * Constructor
354  * @param other An ALSA queue tempo object pointer
355  */
QueueTempo(snd_seq_queue_tempo_t * other)356 QueueTempo::QueueTempo(snd_seq_queue_tempo_t* other)
357 {
358     snd_seq_queue_tempo_malloc(&m_Info);
359     snd_seq_queue_tempo_copy(m_Info, other);
360 }
361 
362 /**
363  * Copy constructor
364  * @param other An existing QueueTempo object reference
365  */
QueueTempo(const QueueTempo & other)366 QueueTempo::QueueTempo(const QueueTempo& other)
367 {
368     snd_seq_queue_tempo_malloc(&m_Info);
369     snd_seq_queue_tempo_copy(m_Info, other.m_Info);
370 }
371 
372 /**
373  * Destructor
374  */
~QueueTempo()375 QueueTempo::~QueueTempo()
376 {
377     snd_seq_queue_tempo_free(m_Info);
378 }
379 
380 /**
381  * Copy the current object returning the copied object
382  * @return The pointer to the new object
383  */
clone()384 QueueTempo* QueueTempo::clone()
385 {
386     return new QueueTempo(m_Info);
387 }
388 
389 /**
390  * Assignment operator
391  * @param other An existing QueueTempo object reference
392  * @return This object
393  */
operator =(const QueueTempo & other)394 QueueTempo& QueueTempo::operator=(const QueueTempo& other)
395 {
396     if (this == &other)
397         return *this;
398     snd_seq_queue_tempo_copy(m_Info, other.m_Info);
399     return *this;
400 }
401 
402 /**
403  * Gets the queue's numeric identifier
404  * @return The queue's numeric identifier
405  */
getId()406 int QueueTempo::getId()
407 {
408     return snd_seq_queue_tempo_get_queue(m_Info);
409 }
410 
411 /**
412  * Gets the PPQ (parts per quarter note) resolution of the queue
413  * @return The PPQ (parts per quarter note) resolution
414  */
getPPQ()415 int QueueTempo::getPPQ()
416 {
417     return snd_seq_queue_tempo_get_ppq(m_Info);
418 }
419 
420 /**
421  * Gets the tempo skew numerator. The real skew factor is the quotient of this
422  * value divided by the skew base.
423  * @return The tempo skew numerator.
424  * @see getSkewBase(), setSkewValue(), setTempoFactor()
425  */
getSkewValue()426 unsigned int QueueTempo::getSkewValue()
427 {
428     return snd_seq_queue_tempo_get_skew(m_Info);
429 }
430 
431 /**
432  * Gets the tempo skew base. The real skew factor is the quotient of the skew
433  * value divided by the skew base.
434  * @return The tempo skew base.
435  * @see getSkewValue(), setSkewValue(), setTempoFactor()
436  */
getSkewBase()437 unsigned int QueueTempo::getSkewBase()
438 {
439     return snd_seq_queue_tempo_get_skew_base(m_Info);
440 }
441 
442 /**
443  * Gets the queue's tempo in microseconds per beat.
444  * @return The queue's tempo in microseconds per beat.
445  */
getTempo()446 unsigned int QueueTempo::getTempo()
447 {
448     return snd_seq_queue_tempo_get_tempo(m_Info);
449 }
450 
451 /**
452  * Sets the queue resolution in parts per quarter note.
453  * @param value The queue resolution in PPQ.
454  */
setPPQ(int value)455 void QueueTempo::setPPQ(int value)
456 {
457     snd_seq_queue_tempo_set_ppq(m_Info, value);
458 }
459 
460 /**
461  * Sets the tempo skew numerator. The real skew factor is the quotient of this
462  * value divided by the skew base.
463  * @param value The tempo skew numerator.
464  * @see getSkewBase(), getSkewValue(), setTempoFactor()
465  */
setSkewValue(unsigned int value)466 void QueueTempo::setSkewValue(unsigned int value)
467 {
468     snd_seq_queue_tempo_set_skew(m_Info, value);
469 }
470 
471 /**
472  * Sets the tempo skew base. The real skew factor is the quotient of the skew
473  * value divided by the skew base.
474  * @bug Protected because ALSA only accepts as argument a constant SKEW_BASE
475  * @param value The tempo skew base.
476  * @see getSkewBase(), getSkewValue(), setTempoFactor()
477  */
setSkewBase(unsigned int value)478 void QueueTempo::setSkewBase(unsigned int value)
479 {
480     snd_seq_queue_tempo_set_skew_base(m_Info, value);
481 }
482 
483 /**
484  * Sets the queue tempo in microseconds per beat
485  * @param value The tempo in microseconds per beat
486  */
setTempo(unsigned int value)487 void QueueTempo::setTempo(unsigned int value)
488 {
489     snd_seq_queue_tempo_set_tempo(m_Info, value);
490 }
491 
492 /**
493  * Gets the queue's nominal BPM tempo (in beats per minute)
494  * @return The queue's nominal BPM tempo (in beats per minute)
495  */
getNominalBPM()496 float QueueTempo::getNominalBPM()
497 {
498     int itempo = getTempo();
499     if (itempo != 0)
500         return 6.0e7f / itempo;
501     return 0.0f;
502 }
503 
504 /**
505  * Gets the queue's real BPM tempo in beats per minute. The result is equal to
506  * the nominal BPM tempo multiplied by the skew factor.
507  * @return
508  */
getRealBPM()509 float QueueTempo::getRealBPM()
510 {
511     float tempo = getNominalBPM();
512     return tempo * getSkewValue() / SKEW_BASE;
513 }
514 
515 /**
516  * Sets the queue's tempo skew factor
517  * @param value The tempo skew factor.
518  */
setTempoFactor(float value)519 void QueueTempo::setTempoFactor(float value)
520 {
521     setSkewValue(floor(SKEW_BASE * value));
522     setSkewBase(SKEW_BASE);
523 }
524 
525 /**
526  * Sets the queue's nominal tempo in BPM (beats per minute).
527  * @param value The nominal tempo in BPM (beats per minute).
528  */
setNominalBPM(float value)529 void QueueTempo::setNominalBPM(float value)
530 {
531     setTempo(floor(6.0e7f / value));
532 }
533 
534 /**
535  * Gets the size of the ALSA queue tempo object
536  * @return The size of the ALSA object
537  */
getInfoSize() const538 int QueueTempo::getInfoSize() const
539 {
540     return snd_seq_queue_tempo_sizeof();
541 }
542 
543 /**
544  * Default constructor
545  */
QueueTimer()546 QueueTimer::QueueTimer()
547 {
548     snd_seq_queue_timer_malloc(&m_Info);
549 }
550 
551 /**
552  * Constructor
553  * @param other An ALSA queue timer object pointer
554  */
QueueTimer(snd_seq_queue_timer_t * other)555 QueueTimer::QueueTimer(snd_seq_queue_timer_t* other)
556 {
557     snd_seq_queue_timer_malloc(&m_Info);
558     snd_seq_queue_timer_copy(m_Info, other);
559 }
560 
561 /**
562  * Copy constructor
563  * @param other An existing QueueTimer object reference
564  */
QueueTimer(const QueueTimer & other)565 QueueTimer::QueueTimer(const QueueTimer& other)
566 {
567     snd_seq_queue_timer_malloc(&m_Info);
568     snd_seq_queue_timer_copy(m_Info, other.m_Info);
569 }
570 
571 /**
572  * Destructor
573  */
~QueueTimer()574 QueueTimer::~QueueTimer()
575 {
576     snd_seq_queue_timer_free(m_Info);
577 }
578 
579 /**
580  * Copy the current object and return the copy
581  * @return The pointer to the new object
582  */
clone()583 QueueTimer* QueueTimer::clone()
584 {
585     return new QueueTimer(m_Info);
586 }
587 
588 /**
589  * Assignment operator
590  * @param other An existing QueueTimer object reference
591  * @return This object
592  */
operator =(const QueueTimer & other)593 QueueTimer& QueueTimer::operator=(const QueueTimer& other)
594 {
595     if (this == &other)
596         return *this;
597     snd_seq_queue_timer_copy(m_Info, other.m_Info);
598     return *this;
599 }
600 
601 /**
602  * The queue's numeric identifier
603  * @return The queue's numeric identifier
604  */
getQueueId()605 int QueueTimer::getQueueId()
606 {
607     return snd_seq_queue_timer_get_queue(m_Info);
608 }
609 
610 /**
611  * Gets the timer type.
612  *
613  * The timer type can be one of the following constants:
614  * <ul>
615  * <li>SND_SEQ_TIMER_ALSA: ALSA timer</li>
616  * <li>SND_SEQ_TIMER_MIDI_CLOCK: MIDI Clock (CLOCK event)</li>
617  * <li>SND_SEQ_TIMER_MIDI_TICK: MIDI Timer Tick (TICK event)</li>
618  * </ul>
619  * @return the timer type.
620  * @see setType()
621  */
getType()622 snd_seq_queue_timer_type_t QueueTimer::getType()
623 {
624     return snd_seq_queue_timer_get_type(m_Info);
625 }
626 
627 /**
628  * Gets the timer identifier record
629  * @return The timer identifier record pointer
630  */
getId()631 const snd_timer_id_t* QueueTimer::getId()
632 {
633     return snd_seq_queue_timer_get_id(m_Info);
634 }
635 
636 /**
637  * Gets the timer resolution
638  * @return The timer resolution
639  */
getResolution()640 unsigned int QueueTimer::getResolution()
641 {
642     return snd_seq_queue_timer_get_resolution(m_Info);
643 }
644 
645 /**
646  * Sets the timer type.
647  * The timer type can be one of the following constants:
648  * <ul>
649  * <li>SND_SEQ_TIMER_ALSA: ALSA timer</li>
650  * <li>SND_SEQ_TIMER_MIDI_CLOCK: MIDI Clock (CLOCK event)</li>
651  * <li>SND_SEQ_TIMER_MIDI_TICK: MIDI Timer Tick (TICK event)</li>
652  * </ul>
653  * @param value The timer type
654  * @see getType()
655  */
setType(snd_seq_queue_timer_type_t value)656 void QueueTimer::setType(snd_seq_queue_timer_type_t value)
657 {
658     snd_seq_queue_timer_set_type(m_Info, value);
659 }
660 
661 /**
662  * Sets the timer identifier record
663  * @param value The timer identifier record pointer
664  */
setId(snd_timer_id_t * value)665 void QueueTimer::setId(snd_timer_id_t* value)
666 {
667     snd_seq_queue_timer_set_id(m_Info, value);
668 }
669 
670 /**
671  * Sets the timer identifier
672  * @param id Timer identifier object
673  * @since 0.3.0
674  */
setId(const TimerId & id)675 void QueueTimer::setId(const TimerId& id)
676 {
677     setId(id.m_Info);
678 }
679 
680 /**
681  * Sets the timer resolution
682  * @param value The timer resolution
683  */
setResolution(unsigned int value)684 void QueueTimer::setResolution(unsigned int value)
685 {
686     snd_seq_queue_timer_set_resolution(m_Info, value);
687 }
688 
689 /**
690  * Gets the size of the ALSA queue timer object
691  * @return The size of the ALSA object
692  */
getInfoSize() const693 int QueueTimer::getInfoSize() const
694 {
695     return snd_seq_queue_timer_sizeof();
696 }
697 
698 /**
699  * Constructor
700  * @param seq An existing MidiClient instance
701  * @param parent An optional parent object
702  */
MidiQueue(MidiClient * seq,QObject * parent)703 MidiQueue::MidiQueue(MidiClient* seq, QObject* parent)
704     : QObject(parent)
705 {
706     m_MidiClient = seq;
707     m_Id = DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_alloc_queue(m_MidiClient->getHandle()));
708     m_allocated = !(m_Id < 0);
709 }
710 
711 /**
712  * Constructor
713  * @param seq An existing MidiClient instance
714  * @param info A QueueInfo object reference
715  * @param parent An optional parent object
716  */
MidiQueue(MidiClient * seq,const QueueInfo & info,QObject * parent)717 MidiQueue::MidiQueue(MidiClient* seq, const QueueInfo& info, QObject* parent)
718     : QObject(parent)
719 {
720     m_MidiClient = seq;
721     m_Info = info;
722     m_Id = DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_create_queue(m_MidiClient->getHandle(), m_Info.m_Info));
723     m_allocated = !(m_Id < 0);
724 }
725 
726 /**
727  * Constructor
728  * @param seq An existing MidiClient instance
729  * @param name The name for the new queue
730  * @param parent An optional parent object
731  */
MidiQueue(MidiClient * seq,const QString name,QObject * parent)732 MidiQueue::MidiQueue(MidiClient* seq, const QString name, QObject* parent)
733     : QObject(parent)
734 {
735     m_MidiClient = seq;
736     m_Id = DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_alloc_named_queue(m_MidiClient->getHandle(), name.toLocal8Bit().data()));
737     m_allocated = !(m_Id < 0);
738 }
739 
740 /**
741  * Constructor.
742  *
743  * Note: this constructor doesn't allocate a new queue, it uses an existing one.
744  * @param seq An existing MidiClient instance
745  * @param queue_id An existing queue numeric identifier
746  * @param parent An optional parent object
747  */
MidiQueue(MidiClient * seq,const int queue_id,QObject * parent)748 MidiQueue::MidiQueue(MidiClient* seq, const int queue_id, QObject* parent)
749     : QObject(parent)
750 {
751     m_MidiClient = seq;
752     m_Id = queue_id;
753     m_allocated = false;
754 }
755 
756 /**
757  * Destructor
758  */
~MidiQueue()759 MidiQueue::~MidiQueue()
760 {
761     if ( m_allocated && (m_MidiClient->getHandle() != nullptr) )
762     {
763         DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_free_queue(m_MidiClient->getHandle(), m_Id));
764     }
765 }
766 
767 /**
768  * Gets a QueueInfo object reference
769  * @return A QueueInfo object reference
770  */
getInfo()771 QueueInfo& MidiQueue::getInfo()
772 {
773     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_info(m_MidiClient->getHandle(), m_Id, m_Info.m_Info));
774     return m_Info;
775 }
776 
777 /**
778  * Gets a QueueStatus object reference
779  * @return A QueueStatus object reference
780  */
getStatus()781 QueueStatus& MidiQueue::getStatus()
782 {
783     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_status(m_MidiClient->getHandle(), m_Id, m_Status.m_Info));
784     return m_Status;
785 }
786 
787 /**
788  * Gets a QueueTempo object reference
789  * @return A QueueTempo object reference
790  */
getTempo()791 QueueTempo& MidiQueue::getTempo()
792 {
793     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_tempo(m_MidiClient->getHandle(), m_Id, m_Tempo.m_Info));
794     return m_Tempo;
795 }
796 
797 /**
798  * Gets a QueueTimer object reference
799  * @return A QueueTimer object reference
800  */
getTimer()801 QueueTimer& MidiQueue::getTimer()
802 {
803     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_timer(m_MidiClient->getHandle(), m_Id, m_Timer.m_Info));
804     return m_Timer;
805 }
806 
807 /**
808  * Applies a QueueInfo object to the queue
809  * @param value A QueueInfo object reference
810  */
setInfo(const QueueInfo & value)811 void MidiQueue::setInfo(const QueueInfo& value)
812 {
813     m_Info = value;
814     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_queue_info(m_MidiClient->getHandle(), m_Id, m_Info.m_Info));
815 }
816 
817 /**
818  * Applies a QueueTempo object to the queue
819  * @param value A QueueTempo object reference
820  */
setTempo(const QueueTempo & value)821 void MidiQueue::setTempo(const QueueTempo& value)
822 {
823     m_Tempo = value;
824     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_queue_tempo(m_MidiClient->getHandle(), m_Id, m_Tempo.m_Info));
825 }
826 
827 /**
828  * Applies q QueueTimer object to the queue
829  * @param value A QueueTimer object reference
830  */
setTimer(const QueueTimer & value)831 void MidiQueue::setTimer(const QueueTimer& value)
832 {
833     m_Timer = value;
834     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_queue_timer(m_MidiClient->getHandle(), m_Id, m_Timer.m_Info));
835 }
836 
837 /**
838  * Gets the queue usage flag.
839  *
840  * @return 1 = client is allowed to access the queue, 0 = not allowed.
841  */
getUsage()842 int MidiQueue::getUsage()
843 {
844     return DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_usage(m_MidiClient->getHandle(), m_Id));
845 }
846 
847 /**
848  * Sets the queue usage flag.
849  *
850  * @param used 1 = client is allowed to access the queue, 0 = not allowed.
851  */
setUsage(int used)852 void MidiQueue::setUsage(int used)
853 {
854     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_queue_usage(m_MidiClient->getHandle(), m_Id, used));
855 }
856 
857 /**
858  * Start the queue.
859  *
860  * This method should start running the queue from the initial position.
861  */
start()862 void MidiQueue::start()
863 {
864     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_start_queue(m_MidiClient->getHandle(), m_Id, nullptr));
865     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drain_output(m_MidiClient->getHandle()));
866 }
867 
868 /**
869  * Stop the queue.
870  *
871  * This method should stop running the queue.
872  */
stop()873 void MidiQueue::stop()
874 {
875     if (m_MidiClient != nullptr && m_MidiClient->getHandle() != nullptr) {
876         DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_stop_queue(m_MidiClient->getHandle(), m_Id, nullptr));
877         DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drain_output(m_MidiClient->getHandle()));
878     }
879 }
880 
881 /**
882  * Start the queue without resetting the last position.
883  *
884  * This method should start running the queue from the last position set.
885  */
continueRunning()886 void MidiQueue::continueRunning()
887 {
888     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_continue_queue(m_MidiClient->getHandle(), m_Id, nullptr));
889     DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drain_output(m_MidiClient->getHandle()));
890 }
891 
892 /**
893  * Clear the queue, dropping any scheduled events.
894  */
clear()895 void MidiQueue::clear()
896 {
897     if (m_MidiClient != nullptr && m_MidiClient->getHandle() != nullptr)
898         snd_seq_drop_output(m_MidiClient->getHandle());
899 }
900 
901 /**
902  * Sets the queue position in musical time (ticks).
903  * @param pos Musical time in ticks.
904  */
setTickPosition(snd_seq_tick_time_t pos)905 void MidiQueue::setTickPosition(snd_seq_tick_time_t pos)
906 {
907     SystemEvent event(SND_SEQ_EVENT_SETPOS_TICK);
908     snd_seq_ev_set_queue_pos_tick(event.getHandle(), m_Id, pos);
909     event.setDirect();
910     m_MidiClient->outputDirect(&event);
911 }
912 
913 /**
914  * Sets the queue position in real time (clock) units: seconds and nanoseconds.
915  * @param pos Real time (clock) position in seconds/nanoseconds.
916  */
setRealTimePosition(snd_seq_real_time_t * pos)917 void MidiQueue::setRealTimePosition(snd_seq_real_time_t* pos)
918 {
919     SystemEvent event(SND_SEQ_EVENT_SETPOS_TIME);
920     snd_seq_ev_set_queue_pos_real(event.getHandle(), m_Id, pos);
921     event.setDirect();
922     m_MidiClient->outputDirect(&event);
923 }
924 
925 } // namespace ALSA
926 } // namespace drumstick
927 
928