drumstick 2.9.0
C++ MIDI libraries using Qt objects, idioms, and style.
alsaclient.cpp
Go to the documentation of this file.
1/*
2 MIDI Sequencer C++ library
3 Copyright (C) 2006-2023, 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 <QCoreApplication>
21#include <QFile>
22#include <QReadLocker>
23#include <QRegularExpression>
24#include <QThread>
25#include <QWriteLocker>
27#include <drumstick/alsaevent.h>
28#include <drumstick/alsaqueue.h>
29
30#if defined(RTKIT_SUPPORT)
31#include <QDBusConnection>
32#include <QDBusInterface>
33#include <sys/resource.h>
34#include <sys/syscall.h>
35#include <sys/types.h>
36#endif
37#include <pthread.h>
38
39#ifndef RLIMIT_RTTIME
40#define RLIMIT_RTTIME 15
41#endif
42
43#ifndef SCHED_RESET_ON_FORK
44#define SCHED_RESET_ON_FORK 0x40000000
45#endif
46
47#ifndef DEFAULT_INPUT_TIMEOUT
48#define DEFAULT_INPUT_TIMEOUT 500
49#endif
50
68namespace drumstick { namespace ALSA {
69
188{
189public:
190 SequencerInputThread(MidiClient *seq, int timeout)
191 : QThread(),
192 m_MidiClient(seq),
193 m_Wait(timeout),
194 m_Stopped(false),
195 m_RealTime(true) {}
196 virtual ~SequencerInputThread() = default;
197 void run() override;
198 bool stopped();
199 void stop();
200 void setRealtimePriority();
201
202 MidiClient *m_MidiClient;
203 int m_Wait;
204 bool m_Stopped;
205 bool m_RealTime;
206 QReadWriteLock m_mutex;
207};
208
209class MidiClient::MidiClientPrivate
210{
211public:
212 MidiClientPrivate() :
213 m_eventsEnabled(false),
214 m_BlockMode(false),
215 m_NeedRefreshClientList(true),
216 m_OpenMode(SND_SEQ_OPEN_DUPLEX),
217 m_DeviceName("default"),
218 m_SeqHandle(nullptr),
219 m_Thread(nullptr),
220 m_Queue(nullptr),
221 m_handler(nullptr)
222 { }
223
224 bool m_eventsEnabled;
225 bool m_BlockMode;
226 bool m_NeedRefreshClientList;
227 int m_OpenMode;
228 QString m_DeviceName;
229 snd_seq_t* m_SeqHandle;
230 QPointer<SequencerInputThread> m_Thread;
231 QPointer<MidiQueue> m_Queue;
232 SequencerEventHandler* m_handler;
233
234 ClientInfo m_Info;
235 ClientInfoList m_ClientList;
236 MidiPortList m_Ports;
237 PortInfoList m_OutputsAvail;
238 PortInfoList m_InputsAvail;
239 QObjectList m_listeners;
240 SystemInfo m_sysInfo;
241 PoolInfo m_poolInfo;
242};
243
259 QObject(parent),
260 d(new MidiClientPrivate)
261{
262 qRegisterMetaType<drumstick::ALSA::SequencerEvent>();
263 qRegisterMetaType<drumstick::ALSA::SequencerEvent*>();
264}
265
272{
275 delete d->m_Queue;
276 close();
277 freeClients();
278 delete d->m_Thread;
279}
280
285snd_seq_t*
287{
288 return d->m_SeqHandle;
289}
290
296{
297 return !d.isNull() && (d->m_SeqHandle != nullptr);
298}
299
305{
306 return d->m_DeviceName;
307}
308
314{
315 return d->m_OpenMode;
316}
317
323{
324 return d->m_BlockMode;
325}
326
332{
333 return d->m_eventsEnabled;
334}
335
341{
342 d->m_handler = handler;
343}
344
345
355{
356 if (d->m_Thread == nullptr) {
357 d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
358 d->m_Thread->m_RealTime = enable;
359 }
360}
361
368{
369 if (d->m_Thread == nullptr)
370 return true;
371 return d->m_Thread->m_RealTime;
372}
373
394void
395MidiClient::open( const QString deviceName,
396 const int openMode,
397 const bool blockMode)
398{
399 DRUMSTICK_ALSA_CHECK_ERROR( snd_seq_open( &d->m_SeqHandle, deviceName.toLocal8Bit().data(),
400 openMode, blockMode ? 0 : SND_SEQ_NONBLOCK ) );
401 DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_get_client_info( d->m_SeqHandle, d->m_Info.m_Info ) );
402 d->m_DeviceName = deviceName;
403 d->m_OpenMode = openMode;
404 d->m_BlockMode = blockMode;
405}
406
427void
428MidiClient::open( snd_config_t* conf,
429 const QString deviceName,
430 const int openMode,
431 const bool blockMode )
432{
433 DRUMSTICK_ALSA_CHECK_ERROR( snd_seq_open_lconf( &d->m_SeqHandle,
434 deviceName.toLocal8Bit().data(),
435 openMode,
436 blockMode ? 0 : SND_SEQ_NONBLOCK,
437 conf ));
438 DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info));
439 d->m_DeviceName = deviceName;
440 d->m_OpenMode = openMode;
441 d->m_BlockMode = blockMode;
442}
443
451void
453{
454 if (d->m_SeqHandle != nullptr) {
456 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_close(d->m_SeqHandle));
457 d->m_SeqHandle = nullptr;
458 }
459}
460
469size_t
471{
472 return snd_seq_get_output_buffer_size(d->m_SeqHandle);
473}
474
483void
485{
486 if (getOutputBufferSize() != newSize) {
487 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_output_buffer_size(d->m_SeqHandle, newSize));
488 }
489}
490
499size_t
501{
502 return snd_seq_get_input_buffer_size(d->m_SeqHandle);
503}
504
513void
515{
516 if (getInputBufferSize() != newSize) {
517 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_input_buffer_size(d->m_SeqHandle, newSize));
518 }
519}
520
530void
532{
533 if (d->m_BlockMode != newValue)
534 {
535 d->m_BlockMode = newValue;
536 if (d->m_SeqHandle != nullptr)
537 {
538 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_nonblock(d->m_SeqHandle, d->m_BlockMode ? 0 : 1));
539 }
540 }
541}
542
551int
553{
554 return DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_client_id(d->m_SeqHandle));
555}
556
561snd_seq_type_t
563{
564 return snd_seq_type(d->m_SeqHandle);
565}
566
587void
589{
590 do {
591 int err = 0;
592 snd_seq_event_t* evp = nullptr;
593 SequencerEvent* event = nullptr;
594 err = snd_seq_event_input(d->m_SeqHandle, &evp);
595 if ((err >= 0) && (evp != nullptr)) {
596 switch (evp->type) {
597
598 case SND_SEQ_EVENT_NOTE:
599 event = new NoteEvent(evp);
600 break;
601
602 case SND_SEQ_EVENT_NOTEON:
603 event = new NoteOnEvent(evp);
604 break;
605
606 case SND_SEQ_EVENT_NOTEOFF:
607 event = new NoteOffEvent(evp);
608 break;
609
610 case SND_SEQ_EVENT_KEYPRESS:
611 event = new KeyPressEvent(evp);
612 break;
613
614 case SND_SEQ_EVENT_CONTROLLER:
615 case SND_SEQ_EVENT_CONTROL14:
616 case SND_SEQ_EVENT_REGPARAM:
617 case SND_SEQ_EVENT_NONREGPARAM:
618 event = new ControllerEvent(evp);
619 break;
620
621 case SND_SEQ_EVENT_PGMCHANGE:
622 event = new ProgramChangeEvent(evp);
623 break;
624
625 case SND_SEQ_EVENT_CHANPRESS:
626 event = new ChanPressEvent(evp);
627 break;
628
629 case SND_SEQ_EVENT_PITCHBEND:
630 event = new PitchBendEvent(evp);
631 break;
632
633 case SND_SEQ_EVENT_SYSEX:
634 event = new SysExEvent(evp);
635 break;
636
637 case SND_SEQ_EVENT_PORT_SUBSCRIBED:
638 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
639 event = new SubscriptionEvent(evp);
640 break;
641
642 case SND_SEQ_EVENT_PORT_CHANGE:
643 case SND_SEQ_EVENT_PORT_EXIT:
644 case SND_SEQ_EVENT_PORT_START:
645 event = new PortEvent(evp);
646 d->m_NeedRefreshClientList = true;
647 break;
648
649 case SND_SEQ_EVENT_CLIENT_CHANGE:
650 case SND_SEQ_EVENT_CLIENT_EXIT:
651 case SND_SEQ_EVENT_CLIENT_START:
652 event = new ClientEvent(evp);
653 d->m_NeedRefreshClientList = true;
654 break;
655
656 case SND_SEQ_EVENT_SONGPOS:
657 case SND_SEQ_EVENT_SONGSEL:
658 case SND_SEQ_EVENT_QFRAME:
659 case SND_SEQ_EVENT_TIMESIGN:
660 case SND_SEQ_EVENT_KEYSIGN:
661 event = new ValueEvent(evp);
662 break;
663
664 case SND_SEQ_EVENT_SETPOS_TICK:
665 case SND_SEQ_EVENT_SETPOS_TIME:
666 case SND_SEQ_EVENT_QUEUE_SKEW:
667 event = new QueueControlEvent(evp);
668 break;
669
670 case SND_SEQ_EVENT_TEMPO:
671 event = new TempoEvent(evp);
672 break;
673
674 default:
675 event = new SequencerEvent(evp);
676 break;
677 }
678 // first, process the callback (if any)
679 if (d->m_handler != nullptr) {
680 d->m_handler->handleSequencerEvent(event->clone());
681 } else {
682 // second, process the event listeners
683 if (d->m_eventsEnabled) {
684 QObjectList::Iterator it;
685 for(it=d->m_listeners.begin(); it!=d->m_listeners.end(); ++it) {
686 QObject* sub = (*it);
687 QCoreApplication::postEvent(sub, event->clone());
688 }
689 } else {
690 // finally, process signals
691 Q_EMIT eventReceived(event->clone());
692 }
693 }
694 delete event;
695 }
696 }
697 while (snd_seq_event_input_pending(d->m_SeqHandle, 0) > 0);
698}
699
703void
705{
706 if (d->m_Thread == nullptr) {
707 d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
708 }
709 d->m_Thread->start( d->m_Thread->m_RealTime ?
710 QThread::TimeCriticalPriority : QThread::InheritPriority );
711}
712
716void
718{
719 int counter = 0;
720 if (d->m_Thread != nullptr) {
721 if (d->m_Thread->isRunning()) {
722 d->m_Thread->stop();
723 while (!d->m_Thread->wait(500) && (counter < 10)) {
724 counter++;
725 }
726 if (!d->m_Thread->isFinished()) {
727 d->m_Thread->terminate();
728 }
729 }
730 delete d->m_Thread;
731 }
732}
733
737void
739{
740 ClientInfo cInfo;
741 freeClients();
742 cInfo.setClient(-1);
743 while (snd_seq_query_next_client(d->m_SeqHandle, cInfo.m_Info) >= 0) {
744 cInfo.readPorts(this);
745 d->m_ClientList.append(cInfo);
746 }
747 d->m_NeedRefreshClientList = false;
748}
749
753void
755{
756 d->m_ClientList.clear();
757}
758
765{
766 if (d->m_NeedRefreshClientList)
767 readClients();
768 ClientInfoList lst = d->m_ClientList; // copy
769 return lst;
770}
771
778{
779 snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info);
780 return d->m_Info;
781}
782
790void
792{
793 d->m_Info = val;
794 snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
795}
796
800void
802{
803 if (d->m_SeqHandle != nullptr) {
804 snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
805 }
806}
807
812QString
814{
815 return d->m_Info.getName();
816}
817
823QString
824MidiClient::getClientName(const int clientId)
825{
826 ClientInfoList::Iterator it;
827 if (d->m_NeedRefreshClientList)
828 readClients();
829 for (it = d->m_ClientList.begin(); it != d->m_ClientList.end(); ++it) {
830 if ((*it).getClientId() == clientId) {
831 return (*it).getName();
832 }
833 }
834 return QString();
835}
836
841void
842MidiClient::setClientName(QString const& newName)
843{
844 if (newName != d->m_Info.getName()) {
845 d->m_Info.setName(newName);
847 }
848}
849
856{
857 return d->m_Ports;
858}
859
866{
867 MidiPort* port = new MidiPort(this);
868 port->attach(this);
869 return port;
870}
871
876void
878{
879 if (d->m_SeqHandle != nullptr) {
880 DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_create_port(d->m_SeqHandle, port->m_Info.m_Info));
881 d->m_Ports.push_back(port);
882 }
883}
884
889void
891{
892 if (d->m_SeqHandle != nullptr) {
893 if(port->getPortInfo()->getClient() == getClientId())
894 {
895 return;
896 }
897 DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, port->getPortInfo()->getPort()));
898 port->setMidiClient(nullptr);
899
900 MidiPortList::iterator it;
901 for(it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it)
902 {
903 if ((*it)->getPortInfo()->getPort() == port->getPortInfo()->getPort())
904 {
905 d->m_Ports.erase(it);
906 break;
907 }
908 }
909 }
910}
911
916{
917 if (d->m_SeqHandle != nullptr) {
918 QMutableListIterator<MidiPort*> it(d->m_Ports);
919 while (it.hasNext()) {
920 MidiPort* p = it.next();
921 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_delete_port(d->m_SeqHandle, p->getPortInfo()->getPort()));
922 p->setMidiClient(nullptr);
923 it.remove();
924 }
925 }
926}
927
932void
934{
935 snd_seq_set_client_event_filter(d->m_SeqHandle, evtype);
936}
937
943bool
945{
946 return d->m_Info.getBroadcastFilter();
947}
948
954void
956{
957 d->m_Info.setBroadcastFilter(newValue);
959}
960
966bool
968{
969 return d->m_Info.getErrorBounce();
970}
971
977void
979{
980 d->m_Info.setErrorBounce(newValue);
982}
983
995void
996MidiClient::output(SequencerEvent* ev, bool async, int timeout)
997{
998 pollfd* pfds = nullptr;
999 if (async) {
1000 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_event_output(d->m_SeqHandle, ev->getHandle()));
1001 } else {
1002 int npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
1003 pfds = (pollfd*) calloc(npfds, sizeof(pollfd));
1004 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
1005 while (snd_seq_event_output(d->m_SeqHandle, ev->getHandle()) < 0)
1006 {
1007 poll(pfds, npfds, timeout);
1008 }
1009 free(pfds);
1010 }
1011}
1012
1024void MidiClient::outputDirect(SequencerEvent* ev, bool async, int timeout)
1025{
1026 if (async) {
1027 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()));
1028 } else {
1029 int npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
1030 pollfd* pfds = (pollfd*) calloc(npfds, sizeof(pollfd));
1031 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
1032 while (snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()) < 0)
1033 {
1034 poll(pfds, npfds, timeout);
1035 }
1036 free(pfds);
1037 }
1038}
1039
1048void
1050{
1051 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_event_output_buffer(d->m_SeqHandle, ev->getHandle()));
1052}
1053
1065void MidiClient::drainOutput(bool async, int timeout)
1066{
1067 if (async) {
1068 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drain_output(d->m_SeqHandle));
1069 } else {
1070 int npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
1071 pollfd* pfds = (pollfd*) calloc(npfds, sizeof(pollfd));
1072 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
1073 while (snd_seq_drain_output(d->m_SeqHandle) < 0)
1074 {
1075 poll(pfds, npfds, timeout);
1076 }
1077 free(pfds);
1078 }
1079}
1080
1086void
1088{
1089 snd_seq_sync_output_queue(d->m_SeqHandle);
1090}
1091
1097MidiQueue*
1099{
1100 if (d->m_Queue == nullptr) {
1101 createQueue();
1102 }
1103 return d->m_Queue;
1104}
1105
1110MidiQueue*
1112{
1113 if (d->m_Queue != nullptr) {
1114 delete d->m_Queue;
1115 }
1116 d->m_Queue = new MidiQueue(this, this);
1117 return d->m_Queue;
1118}
1119
1126MidiQueue*
1127MidiClient::createQueue(QString const& queueName )
1128{
1129 if (d->m_Queue != nullptr) {
1130 delete d->m_Queue;
1131 }
1132 d->m_Queue = new MidiQueue(this, queueName, this);
1133 return d->m_Queue;
1134}
1135
1143MidiQueue*
1145{
1146 if (d->m_Queue != nullptr) {
1147 delete d->m_Queue;
1148 }
1149 d->m_Queue = new MidiQueue(this, queue_id, this);
1150 return d->m_Queue;
1151}
1152
1160MidiQueue*
1161MidiClient::useQueue(const QString& name)
1162{
1163 if (d->m_Queue != nullptr) {
1164 delete d->m_Queue;
1165 }
1166 int queue_id = getQueueId(name);
1167 if ( queue_id >= 0) {
1168 d->m_Queue = new MidiQueue(this, queue_id, this);
1169 }
1170 return d->m_Queue;
1171}
1172
1179MidiQueue*
1181{
1182 if (d->m_Queue != nullptr) {
1183 delete d->m_Queue;
1184 }
1185 queue->setParent(this);
1186 d->m_Queue = queue;
1187 return d->m_Queue;
1188}
1189
1194QList<int>
1196{
1197 int q, err, max;
1198 QList<int> queues;
1199 snd_seq_queue_info_t* qinfo;
1200 snd_seq_queue_info_alloca(&qinfo);
1201 max = getSystemInfo().getMaxQueues();
1202 for ( q = 0; q < max; ++q ) {
1203 err = snd_seq_get_queue_info(d->m_SeqHandle, q, qinfo);
1204 if (err == 0) {
1205 queues.append(q);
1206 }
1207 }
1208 return queues;
1209}
1210
1219MidiClient::filterPorts(unsigned int filter)
1220{
1221 PortInfoList result;
1222 ClientInfoList::ConstIterator itc;
1223 PortInfoList::ConstIterator itp;
1224
1225 if (d->m_NeedRefreshClientList)
1226 readClients();
1227
1228 for (itc = d->m_ClientList.constBegin(); itc != d->m_ClientList.constEnd(); ++itc) {
1229 ClientInfo ci = (*itc);
1230 if ((ci.getClientId() == SND_SEQ_CLIENT_SYSTEM) ||
1231 (ci.getClientId() == d->m_Info.getClientId()))
1232 continue;
1233 PortInfoList lstPorts = ci.getPorts();
1234 for(itp = lstPorts.constBegin(); itp != lstPorts.constEnd(); ++itp) {
1235 PortInfo pi = (*itp);
1236 unsigned int cap = pi.getCapability();
1237 if ( ((filter & cap) != 0) &&
1238 ((SND_SEQ_PORT_CAP_NO_EXPORT & cap) == 0) ) {
1239 result.append(pi);
1240 }
1241 }
1242 }
1243 return result;
1244}
1245
1249void
1251{
1252 d->m_InputsAvail.clear();
1253 d->m_OutputsAvail.clear();
1254 d->m_InputsAvail = filterPorts( SND_SEQ_PORT_CAP_READ |
1255 SND_SEQ_PORT_CAP_SUBS_READ );
1256 d->m_OutputsAvail = filterPorts( SND_SEQ_PORT_CAP_WRITE |
1257 SND_SEQ_PORT_CAP_SUBS_WRITE );
1258}
1259
1266{
1267 d->m_NeedRefreshClientList = true;
1269 return d->m_InputsAvail;
1270}
1271
1278{
1279 d->m_NeedRefreshClientList = true;
1281 return d->m_OutputsAvail;
1282}
1283
1290void
1292{
1293 d->m_listeners.append(listener);
1294}
1295
1301void
1303{
1304 d->m_listeners.removeAll(listener);
1305}
1306
1313void
1315{
1316 if (bEnabled != d->m_eventsEnabled) {
1317 d->m_eventsEnabled = bEnabled;
1318 }
1319}
1320
1327{
1328 snd_seq_system_info(d->m_SeqHandle, d->m_sysInfo.m_Info);
1329 return d->m_sysInfo;
1330}
1331
1336PoolInfo&
1338{
1339 snd_seq_get_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info);
1340 return d->m_poolInfo;
1341}
1342
1347void
1349{
1350 d->m_poolInfo = info;
1351 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info));
1352}
1353
1358void
1360{
1361 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_reset_pool_input(d->m_SeqHandle));
1362}
1363
1368void
1370{
1371 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_reset_pool_output(d->m_SeqHandle));
1372}
1373
1378void
1380{
1381 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_input(d->m_SeqHandle, size));
1382}
1383
1388void
1390{
1391 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_output(d->m_SeqHandle, size));
1392}
1393
1398void
1400{
1401 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_output_room(d->m_SeqHandle, size));
1402}
1403
1408void
1410{
1411 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_input(d->m_SeqHandle));
1412}
1413
1418void
1420{
1421 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_input_buffer(d->m_SeqHandle));
1422}
1423
1431void
1433{
1434 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_output(d->m_SeqHandle));
1435}
1436
1444void
1446{
1447 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_output_buffer(d->m_SeqHandle));
1448}
1449
1456void
1458{
1459 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_remove_events(d->m_SeqHandle, spec->m_Info));
1460}
1461
1468{
1469 snd_seq_event_t* ev;
1470 if (DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_extract_output(d->m_SeqHandle, &ev) == 0)) {
1471 return new SequencerEvent(ev);
1472 }
1473 return nullptr;
1474}
1475
1481int
1483{
1484 return snd_seq_event_output_pending(d->m_SeqHandle);
1485}
1486
1500int
1502{
1503 return snd_seq_event_input_pending(d->m_SeqHandle, fetch ? 1 : 0);
1504}
1505
1512int
1513MidiClient::getQueueId(const QString& name)
1514{
1515 return snd_seq_query_named_queue(d->m_SeqHandle, name.toLocal8Bit().data());
1516}
1517
1523int
1525{
1526 return snd_seq_poll_descriptors_count(d->m_SeqHandle, events);
1527}
1528
1542int
1543MidiClient::pollDescriptors( struct pollfd *pfds, unsigned int space,
1544 short events )
1545{
1546 return snd_seq_poll_descriptors(d->m_SeqHandle, pfds, space, events);
1547}
1548
1555unsigned short
1556MidiClient::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds)
1557{
1558 unsigned short revents;
1559 DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_poll_descriptors_revents( d->m_SeqHandle,
1560 pfds, nfds,
1561 &revents ));
1562 return revents;
1563}
1564
1569const char *
1571{
1572 return snd_seq_name(d->m_SeqHandle);
1573}
1574
1579void
1581{
1582 DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_name(d->m_SeqHandle, name));
1583}
1584
1592int
1594 unsigned int caps,
1595 unsigned int type )
1596{
1597 return DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_create_simple_port( d->m_SeqHandle,
1598 name, caps, type ));
1599}
1600
1605void
1607{
1608 DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_delete_simple_port( d->m_SeqHandle, port ));
1609}
1610
1617void
1618MidiClient::connectFrom(int myport, int client, int port)
1619{
1620 DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_connect_from(d->m_SeqHandle, myport, client, port ));
1621}
1622
1629void
1630MidiClient::connectTo(int myport, int client, int port)
1631{
1632 DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_connect_to(d->m_SeqHandle, myport, client, port ));
1633}
1634
1641void
1642MidiClient::disconnectFrom(int myport, int client, int port)
1643{
1644 DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_disconnect_from(d->m_SeqHandle, myport, client, port ));
1645}
1646
1653void
1654MidiClient::disconnectTo(int myport, int client, int port)
1655{
1656 DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_disconnect_to(d->m_SeqHandle, myport, client, port ));
1657}
1658
1670bool
1671MidiClient::parseAddress( const QString& straddr, snd_seq_addr& addr )
1672{
1673 bool ok(false);
1674 QString testClient, testPort;
1675 ClientInfoList::ConstIterator cit;
1676 int pos = straddr.indexOf(':');
1677 if (pos > -1) {
1678 testClient = straddr.left(pos);
1679 testPort = straddr.mid(pos+1);
1680 } else {
1681 testClient = straddr;
1682 testPort = '0';
1683 }
1684 addr.client = testClient.toInt(&ok);
1685 if (ok)
1686 addr.port = testPort.toInt(&ok);
1687 if (!ok) {
1688 if (d->m_NeedRefreshClientList)
1689 readClients();
1690 for ( cit = d->m_ClientList.constBegin();
1691 cit != d->m_ClientList.constEnd(); ++cit ) {
1692 ClientInfo ci = *cit;
1693 if (testClient.compare(ci.getName(), Qt::CaseInsensitive) == 0) {
1694 addr.client = ci.getClientId();
1695 addr.port = testPort.toInt(&ok);
1696 return ok;
1697 }
1698 }
1699 }
1700 return ok;
1701}
1702
1707bool
1709{
1710 QReadLocker locker(&m_mutex);
1711 return m_Stopped;
1712}
1713
1717void
1719{
1720 QWriteLocker locker(&m_mutex);
1721 m_Stopped = true;
1722}
1723
1724#if defined(RTKIT_SUPPORT)
1725static pid_t _gettid() {
1726 return (pid_t) ::syscall(SYS_gettid);
1727}
1728#endif
1729
1730void
1731MidiClient::SequencerInputThread::setRealtimePriority()
1732{
1733 struct sched_param p;
1734 int rt, policy = SCHED_RR | SCHED_RESET_ON_FORK;
1735 quint32 priority = 6;
1736#if defined(RTKIT_SUPPORT)
1737 bool ok;
1738 quint32 max_prio;
1739 quint64 thread;
1740 struct rlimit old_limit, new_limit;
1741 long long max_rttime;
1742#endif
1743
1744 ::memset(&p, 0, sizeof(p));
1745 p.sched_priority = priority;
1746 rt = ::pthread_setschedparam(::pthread_self(), policy, &p);
1747 if (rt != 0) {
1748#if defined(RTKIT_SUPPORT)
1749 const QString rtkit_service =
1750 QStringLiteral("org.freedesktop.RealtimeKit1");
1751 const QString rtkit_path =
1752 QStringLiteral("/org/freedesktop/RealtimeKit1");
1753 const QString rtkit_iface = rtkit_service;
1754 thread = _gettid();
1755 QDBusConnection bus = QDBusConnection::systemBus();
1756 QDBusInterface realtimeKit(rtkit_service, rtkit_path, rtkit_iface, bus);
1757 QVariant maxRTPrio = realtimeKit.property("MaxRealtimePriority");
1758 max_prio = maxRTPrio.toUInt(&ok);
1759 if (!ok) {
1760 qWarning() << "invalid property RealtimeKit.MaxRealtimePriority";
1761 return;
1762 }
1763 if (priority > max_prio)
1764 priority = max_prio;
1765 QVariant maxRTNSec = realtimeKit.property("RTTimeNSecMax");
1766 max_rttime = maxRTNSec.toLongLong(&ok);
1767 if (!ok || max_rttime < 0) {
1768 qWarning() << "invalid property RealtimeKit.RTTimeNSecMax";
1769 return;
1770 }
1771 new_limit.rlim_cur = new_limit.rlim_max = max_rttime;
1772 rt = ::getrlimit(RLIMIT_RTTIME, &old_limit);
1773 if (rt < 0) {
1774 qWarning() << "getrlimit() failed. err=" << rt << ::strerror(rt);
1775 return;
1776 }
1777 rt = ::setrlimit(RLIMIT_RTTIME, &new_limit);
1778 if ( rt < 0) {
1779 qWarning() << "setrlimit() failed, err=" << rt << ::strerror(rt);
1780 return;
1781 }
1782 QDBusMessage reply = realtimeKit.call("MakeThreadRealtime", thread, priority);
1783 if (reply.type() == QDBusMessage::ErrorMessage )
1784 qWarning() << "error returned by RealtimeKit.MakeThreadRealtime:"
1785 << reply.errorMessage();
1786#endif
1787 } else {
1788 qWarning() << "pthread_setschedparam() failed, err="
1789 << rt << ::strerror(rt);
1790 }
1791}
1792
1796void
1798{
1799 if ( priority() == TimeCriticalPriority ) {
1800 setRealtimePriority();
1801 }
1802 if (m_MidiClient != nullptr) {
1803 int npfd = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLIN);
1804 pollfd* pfd = (pollfd *) calloc(npfd, sizeof(pollfd));
1805 try
1806 {
1807 snd_seq_poll_descriptors(m_MidiClient->getHandle(), pfd, npfd, POLLIN);
1808 while (!stopped() && (m_MidiClient != nullptr))
1809 {
1810 int rt = poll(pfd, npfd, m_Wait);
1811 if (rt > 0) {
1812 m_MidiClient->doEvents();
1813 }
1814 }
1815 }
1816 catch (...)
1817 {
1818 qWarning() << "exception in input thread";
1819 }
1820 free(pfd);
1821 }
1822}
1823
1828{
1829 snd_seq_client_info_malloc(&m_Info);
1830}
1831
1837{
1838 snd_seq_client_info_malloc(&m_Info);
1839 snd_seq_client_info_copy(m_Info, other.m_Info);
1840 m_Ports = other.m_Ports;
1841}
1842
1847ClientInfo::ClientInfo(snd_seq_client_info_t* other)
1848{
1849 snd_seq_client_info_malloc(&m_Info);
1850 snd_seq_client_info_copy(m_Info, other);
1851}
1852
1859{
1860 snd_seq_client_info_malloc(&m_Info);
1861 snd_seq_get_any_client_info(seq->getHandle(), id, m_Info);
1862}
1863
1868{
1869 freePorts();
1870 snd_seq_client_info_free(m_Info);
1871}
1872
1879{
1880 return new ClientInfo(m_Info);
1881}
1882
1890{
1891 if (this == &other)
1892 return *this;
1893 snd_seq_client_info_copy(m_Info, other.m_Info);
1894 m_Ports = other.m_Ports;
1895 return *this;
1896}
1897
1902int
1904{
1905 return snd_seq_client_info_get_client(m_Info);
1906}
1907
1912snd_seq_client_type_t
1914{
1915 return snd_seq_client_info_get_type(m_Info);
1916}
1917
1922QString
1924{
1925 return QString(snd_seq_client_info_get_name(m_Info));
1926}
1927
1932bool
1934{
1935 return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0);
1936}
1937
1942bool
1944{
1945 return (snd_seq_client_info_get_error_bounce(m_Info) != 0);
1946}
1947
1953const unsigned char*
1955{
1956 return snd_seq_client_info_get_event_filter(m_Info);
1957}
1958
1963int
1965{
1966 return snd_seq_client_info_get_num_ports(m_Info);
1967}
1968
1973int
1975{
1976 return snd_seq_client_info_get_event_lost(m_Info);
1977}
1978
1983void
1985{
1986 snd_seq_client_info_set_client(m_Info, client);
1987}
1988
1993void
1995{
1996 snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data());
1997}
1998
2003void
2005{
2006 snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0);
2007}
2008
2013void
2015{
2016 snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0);
2017}
2018
2024void
2025ClientInfo::setEventFilter(unsigned char *filter)
2026{
2027 snd_seq_client_info_set_event_filter(m_Info, filter);
2028}
2029
2034void
2036{
2037 PortInfo info;
2038 freePorts();
2039 info.setClient(getClientId());
2040 info.setClientName(getName());
2041 info.setPort(-1);
2042 while (snd_seq_query_next_port(seq->getHandle(), info.m_Info) >= 0) {
2043 info.readSubscribers(seq);
2044 m_Ports.append(info);
2045 }
2046}
2047
2051void
2053{
2054 m_Ports.clear();
2055}
2056
2063{
2064 PortInfoList lst = m_Ports; // copy
2065 return lst;
2066}
2067
2072int
2074{
2075 return snd_seq_client_info_sizeof();
2076}
2077
2078#if SND_LIB_VERSION > 0x010010
2084void
2085ClientInfo::addFilter(int eventType)
2086{
2087 snd_seq_client_info_event_filter_add(m_Info, eventType);
2088}
2089
2095bool
2096ClientInfo::isFiltered(int eventType)
2097{
2098 return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0);
2099}
2100
2104void
2105ClientInfo::clearFilter()
2106{
2107 snd_seq_client_info_event_filter_clear(m_Info);
2108}
2109
2114void
2115ClientInfo::removeFilter(int eventType)
2116{
2117 snd_seq_client_info_event_filter_del(m_Info, eventType);
2118}
2119#endif
2120
2125{
2126 snd_seq_system_info_malloc(&m_Info);
2127}
2128
2134{
2135 snd_seq_system_info_malloc(&m_Info);
2136 snd_seq_system_info_copy(m_Info, other.m_Info);
2137}
2138
2143SystemInfo::SystemInfo(snd_seq_system_info_t* other)
2144{
2145 snd_seq_system_info_malloc(&m_Info);
2146 snd_seq_system_info_copy(m_Info, other);
2147}
2148
2154{
2155 snd_seq_system_info_malloc(&m_Info);
2156 snd_seq_system_info(seq->getHandle(), m_Info);
2157}
2158
2163{
2164 snd_seq_system_info_free(m_Info);
2165}
2166
2173{
2174 return new SystemInfo(m_Info);
2175}
2176
2184{
2185 if (this == &other)
2186 return *this;
2187 snd_seq_system_info_copy(m_Info, other.m_Info);
2188 return *this;
2189}
2190
2196{
2197 return snd_seq_system_info_get_clients(m_Info);
2198}
2199
2205{
2206 return snd_seq_system_info_get_ports(m_Info);
2207}
2208
2214{
2215 return snd_seq_system_info_get_queues(m_Info);
2216}
2217
2223{
2224 return snd_seq_system_info_get_channels(m_Info);
2225}
2226
2232{
2233 return snd_seq_system_info_get_cur_queues(m_Info);
2234}
2235
2241{
2242 return snd_seq_system_info_get_cur_clients(m_Info);
2243}
2244
2250{
2251 return snd_seq_system_info_sizeof();
2252}
2253
2258{
2259 snd_seq_client_pool_malloc(&m_Info);
2260}
2261
2267{
2268 snd_seq_client_pool_malloc(&m_Info);
2269 snd_seq_client_pool_copy(m_Info, other.m_Info);
2270}
2271
2276PoolInfo::PoolInfo(snd_seq_client_pool_t* other)
2277{
2278 snd_seq_client_pool_malloc(&m_Info);
2279 snd_seq_client_pool_copy(m_Info, other);
2280}
2281
2287{
2288 snd_seq_client_pool_malloc(&m_Info);
2289 snd_seq_get_client_pool(seq->getHandle(), m_Info);
2290}
2291
2296{
2297 snd_seq_client_pool_free(m_Info);
2298}
2299
2304PoolInfo*
2306{
2307 return new PoolInfo(m_Info);
2308}
2309
2315PoolInfo&
2317{
2318 if (this == &other)
2319 return *this;
2320 snd_seq_client_pool_copy(m_Info, other.m_Info);
2321 return *this;
2322}
2323
2328int
2330{
2331 return snd_seq_client_pool_get_client(m_Info);
2332}
2333
2338int
2340{
2341 return snd_seq_client_pool_get_input_free(m_Info);
2342}
2343
2348int
2350{
2351 return snd_seq_client_pool_get_input_pool(m_Info);
2352}
2353
2358int
2360{
2361 return snd_seq_client_pool_get_output_free(m_Info);
2362}
2363
2368int
2370{
2371 return snd_seq_client_pool_get_output_pool(m_Info);
2372}
2373
2379int
2381{
2382 return snd_seq_client_pool_get_output_room(m_Info);
2383}
2384
2389void
2391{
2392 snd_seq_client_pool_set_input_pool(m_Info, size);
2393}
2394
2399void
2401{
2402 snd_seq_client_pool_set_output_pool(m_Info, size);
2403}
2404
2411void
2413{
2414 snd_seq_client_pool_set_output_room(m_Info, size);
2415}
2416
2421int
2423{
2424 return snd_seq_client_pool_sizeof();
2425}
2426
2427#if SND_LIB_VERSION > 0x010004
2433QString
2434getRuntimeALSALibraryVersion()
2435{
2436 return QString(snd_asoundlib_version());
2437}
2438
2444int
2445getRuntimeALSALibraryNumber()
2446{
2447 QRegularExpression rx("(\\d+)");
2448 QString str = getRuntimeALSALibraryVersion();
2449 bool ok;
2450 int result = 0, j = 0;
2451 QRegularExpressionMatchIterator i = rx.globalMatch(str);
2452 while (i.hasNext() && (j < 3)) {
2453 QRegularExpressionMatch m = i.next();
2454 int v = m.captured(1).toInt(&ok);
2455 if (ok) {
2456 result <<= 8;
2457 result += v;
2458 }
2459 j++;
2460 }
2461 return result;
2462}
2463#endif // SND_LIB_VERSION > 0x010004
2464
2470QString
2472{
2473 QRegularExpression rx("([\\d\\.]+)");
2474 QString s;
2475 QFile f("/proc/asound/version");
2476 if (f.open(QFile::ReadOnly)) {
2477 QTextStream str(&f);
2478 QString sub = str.readLine().trimmed();
2479 QRegularExpressionMatch m = rx.match(sub);
2480 if (m.hasMatch()) {
2481 s = m.captured(1);
2482 }
2483 }
2484 return s;
2485}
2486
2492int
2494{
2495 QRegularExpression rx("(\\d+)");
2496 QString str = getRuntimeALSADriverVersion();
2497 bool ok;
2498 int result = 0, j = 0;
2499 QRegularExpressionMatchIterator i = rx.globalMatch(str);
2500 while (i.hasNext() && (j < 3)) {
2501 QRegularExpressionMatch m = i.next();
2502 int v = m.captured(1).toInt(&ok);
2503 if (ok) {
2504 result <<= 8;
2505 result += v;
2506 }
2507 j++;
2508 }
2509 return result;
2510}
2511
2521{
2522 return QStringLiteral(SND_LIB_VERSION_STR);
2523}
2524
2530{
2531 return QStringLiteral(QT_STRINGIFY(VERSION));
2532}
2533
2536} // namespace ALSA
2537} // namespace drumstick
2538
Classes managing ALSA Sequencer clients.
Classes managing ALSA Sequencer events.
Classes managing ALSA Sequencer queues.
The QObject class is the base class of all Qt objects.
The QThread class provides platform-independent threads.
Event representing a MIDI channel pressure or after-touch event.
Definition: alsaevent.h:429
ALSA Event representing a change on some ALSA sequencer client on the system.
Definition: alsaevent.h:709
Client information.
Definition: alsaclient.h:71
Event representing a MIDI control change event.
Definition: alsaevent.h:325
Event representing a MIDI key pressure, or polyphonic after-touch event.
Definition: alsaevent.h:305
This class manages event input from the ALSA sequencer.
Definition: alsaclient.cpp:188
Client management.
Definition: alsaclient.h:219
void eventReceived(drumstick::ALSA::SequencerEvent *ev)
Signal emitted when an event is received.
Port management.
Definition: alsaport.h:125
void attach(MidiClient *seq)
Attach the port to a MidiClient instance.
Definition: alsaport.cpp:1121
void setMidiClient(MidiClient *seq)
Sets the MidiClient.
Definition: alsaport.cpp:624
PortInfo * getPortInfo()
Gets the PortInfo object pointer.
Definition: alsaport.cpp:595
Queue management.
Definition: alsaqueue.h:201
Class representing a note event with duration.
Definition: alsaevent.h:232
Event representing a note-off MIDI event.
Definition: alsaevent.h:285
Event representing a note-on MIDI event.
Definition: alsaevent.h:265
Event representing a MIDI bender, or pitch wheel event.
Definition: alsaevent.h:399
Sequencer Pool information.
Definition: alsaclient.h:159
ALSA Event representing a change on some ALSA sequencer port on the system.
Definition: alsaevent.h:730
Port information container.
Definition: alsaport.h:52
void readSubscribers(MidiClient *seq)
Obtains the port subscribers lists.
Definition: alsaport.cpp:444
int getClient()
Gets the client number.
Definition: alsaport.cpp:148
int getPort()
Gets the port number.
Definition: alsaport.cpp:159
void setClient(int client)
Sets the client number.
Definition: alsaport.cpp:288
unsigned int getCapability()
Gets the capabilities bitmap.
Definition: alsaport.cpp:202
void setClientName(QString name)
Sets the client name.
Definition: alsaport.cpp:486
void setPort(int port)
Set the port number.
Definition: alsaport.cpp:299
Event representing a MIDI program change event.
Definition: alsaevent.h:369
ALSA Event representing a queue control command.
Definition: alsaevent.h:542
Auxiliary class to remove events from an ALSA queue.
Definition: alsaevent.h:752
Sequencer events handler.
Definition: alsaclient.h:196
Base class for the event's hierarchy.
Definition: alsaevent.h:68
snd_seq_event_t * getHandle()
Gets the handle of the event.
Definition: alsaevent.h:135
ALSA Event representing a subscription between two ALSA clients and ports.
Definition: alsaevent.h:663
Event representing a MIDI system exclusive event.
Definition: alsaevent.h:486
System information.
Definition: alsaclient.h:128
ALSA Event representing a tempo change for an ALSA queue.
Definition: alsaevent.h:646
Generic event having a value property.
Definition: alsaevent.h:619
Error checking functions and macros.
void outputBuffer(SequencerEvent *ev)
Output an event using the library output buffer, without draining the buffer.
MidiQueue * useQueue(int queue_id)
Create a new MidiQueue instance using a queue already existing in the system, associating it to the c...
void setOutputBufferSize(size_t newSize)
Sets the size of the library output buffer for the ALSA client.
Definition: alsaclient.cpp:484
void setPoolInfo(const PoolInfo &info)
Applies (updates) the client's PoolInfo data into the system.
int getInputFree()
Gets the available size on input pool.
void setOutputRoom(int size)
Sets the output room size.
int inputPending(bool fetch)
Gets the size of the events on the input buffer.
void setBroadcastFilter(bool val)
Sets the broadcast filter.
void removeEvents(const RemoveEvents *spec)
Removes events on input/output buffers and pools.
MidiQueue * createQueue()
Create and return a new MidiQueue associated to this client.
void setBroadcastFilter(bool newValue)
Sets the broadcast filter usage of the client.
Definition: alsaclient.cpp:955
QString getDeviceName()
Returns the name of the sequencer device.
Definition: alsaclient.cpp:304
bool getEventsEnabled() const
Returns true if the events mode of delivery has been enabled.
Definition: alsaclient.cpp:331
size_t getOutputBufferSize()
Gets the size of the library output buffer for the ALSA client.
Definition: alsaclient.cpp:470
size_t getInputBufferSize()
Gets the size of the library input buffer for the ALSA client.
Definition: alsaclient.cpp:500
PoolInfo & operator=(const PoolInfo &other)
Assignment operator.
QString getDrumstickLibraryVersion()
getDrumstickLibraryVersion provides the Drumstick version as an edited QString
int getSizeOfInfo() const
Gets the size of the internal object.
int createSimplePort(const char *name, unsigned int caps, unsigned int type)
Create an ALSA sequencer port, without using MidiPort.
PortInfoList getAvailableOutputs()
Gets the available user output ports in the system.
int getMaxQueues()
Get the system's maximum number of queues.
virtual ~ClientInfo()
Destructor.
void startSequencerInput()
Starts reading events from the ALSA sequencer.
Definition: alsaclient.cpp:704
bool getErrorBounce()
Get the error-bounce usage of the client.
Definition: alsaclient.cpp:967
void readClients()
Reads the ALSA sequencer's clients list.
Definition: alsaclient.cpp:738
int getOutputRoom()
Gets the output room size.
void removeListener(QObject *listener)
Removes a QObject listener from the listeners list.
PoolInfo()
Default constructor.
int getCurrentQueues()
Get the system's current number of queues.
int pollDescriptors(struct pollfd *pfds, unsigned int space, short events)
Get poll descriptors.
MidiPortList getMidiPorts() const
Gets the list of MidiPort instances belonging to this client.
Definition: alsaclient.cpp:855
int getQueueId(const QString &name)
Gets the queue's numeric identifier corresponding to the provided name.
void _setClientName(const char *name)
Sets the client name.
bool realTimeInputEnabled()
Return the real-time priority setting for the MIDI input thread.
Definition: alsaclient.cpp:367
void disconnectTo(int myport, int client, int port)
Unsubscribe one port to another arbitrary sequencer client:port.
snd_seq_type_t getSequencerType()
Returns the type snd_seq_type_t of the given sequencer handle.
Definition: alsaclient.cpp:562
PortInfoList filterPorts(unsigned int filter)
Gets a list of the available user ports in the system, filtered by the given bitmap of desired capabi...
void addListener(QObject *listener)
Adds a QObject to the listeners list.
int getMaxPorts()
Get the system's maximum number of ports.
PortInfoList getAvailableInputs()
Gets the available user input ports in the system.
void setBlockMode(bool newValue)
Change the blocking mode of the client.
Definition: alsaclient.cpp:531
void applyClientInfo()
This internal method applies the ClientInfo data to the ALSA sequencer client.
Definition: alsaclient.cpp:801
void close()
Close the sequencer device.
Definition: alsaclient.cpp:452
int getMaxChannels()
Get the system's maximum number of channels.
void readPorts(MidiClient *seq)
Read the client ports.
void setName(QString name)
Sets the client name.
SystemInfo & getSystemInfo()
Gets a SystemInfo instance with the updated state of the system.
Q_DECL_DEPRECATED void setEventFilter(unsigned char *filter)
Sets the event filter.
snd_seq_client_type_t getClientType()
Gets the client's type.
void resetPoolOutput()
Resets the client output pool.
SystemInfo * clone()
Clone the system info object.
virtual ~SystemInfo()
Destructor.
int getRuntimeALSADriverNumber()
Gets the runtime ALSA drivers version number.
void setErrorBounce(bool val)
Sets the error bounce.
MidiClient(QObject *parent=nullptr)
Constructor.
Definition: alsaclient.cpp:258
MidiQueue * getQueue()
Get the MidiQueue instance associated to this client.
virtual ~PoolInfo()
Destructor.
SystemInfo & operator=(const SystemInfo &other)
Assignment operator.
int getInputPool()
Gets the input pool size.
QList< int > getAvailableQueues()
Get a list of the existing queues.
int getPollDescriptorsCount(short events)
Returns the number of poll descriptors.
void setClientName(QString const &newName)
Changes the public name of the ALSA sequencer client.
Definition: alsaclient.cpp:842
SequencerEvent * extractOutput()
Extracts (and removes) the first event in the output buffer.
void detachAllPorts()
Detach all the ports belonging to this client.
Definition: alsaclient.cpp:915
void setRealTimeInput(bool enabled)
Enables real-time priority for the MIDI input thread.
Definition: alsaclient.cpp:354
void resetPoolInput()
Resets the client input pool.
QList< ClientInfo > ClientInfoList
List of sequencer client information.
Definition: alsaclient.h:119
void setPoolOutput(int size)
Sets the size of the client's output pool.
void stopSequencerInput()
Stops reading events from the ALSA sequencer.
Definition: alsaclient.cpp:717
ClientInfo()
Default constructor.
bool getBroadcastFilter()
Gets the broadcast filter usage of the client.
Definition: alsaclient.cpp:944
void deleteSimplePort(int port)
Remove an ALSA sequencer port.
bool parseAddress(const QString &straddr, snd_seq_addr &result)
Parse a text address representation, returning an ALSA address record.
void setInputPool(int size)
Set the input pool size.
int getCurrentClients()
Get the system's current number of clients.
snd_seq_t * getHandle()
Returns the sequencer handler managed by ALSA.
Definition: alsaclient.cpp:286
void output(SequencerEvent *ev, bool async=false, int timeout=-1)
Output an event using the library output buffer.
Definition: alsaclient.cpp:996
int getOpenMode()
Returns the last open mode used in open()
Definition: alsaclient.cpp:313
MidiPort * createPort()
Create and attach a new MidiPort instance to this client.
Definition: alsaclient.cpp:865
void portDetach(MidiPort *port)
Detach a MidiPort instance from this client.
Definition: alsaclient.cpp:890
int getNumPorts()
Gets the client's port count.
void setClient(int client)
Sets the client identifier number.
ClientInfo & operator=(const ClientInfo &other)
Assignment operator.
const char * _getDeviceName()
Gets the internal sequencer device name.
void setThisClientInfo(const ClientInfo &val)
Sets the data supplied by the ClientInfo object into the ALSA sequencer client.
Definition: alsaclient.cpp:791
ClientInfoList getAvailableClients()
Gets the list of clients from the ALSA sequencer.
Definition: alsaclient.cpp:764
void setHandler(SequencerEventHandler *handler)
Sets a sequencer event handler enabling the callback delivery mode.
Definition: alsaclient.cpp:340
void dropOutput()
Clears the client's output buffer and and remove events in sequencer queue.
void dropInput()
Clears the client's input buffer and and remove events in sequencer queue.
QString getRuntimeALSADriverVersion()
Gets the runtime ALSA drivers version string.
QString getName()
Gets the client's name.
void setPoolInput(int size)
Sets the size of the client's input pool.
int getClientId()
Gets the client ID.
Definition: alsaclient.cpp:552
void doEvents()
Dispatch the events received from the Sequencer.
Definition: alsaclient.cpp:588
void dropInputBuffer()
Remove all events on user-space input buffer.
QString getCompiledALSALibraryVersion()
ALSA library version at build time.
QString getClientName()
Gets the client's public name.
Definition: alsaclient.cpp:813
void setPoolOutputRoom(int size)
Sets the room size of the client's output pool.
void open(const QString deviceName="default", const int openMode=SND_SEQ_OPEN_DUPLEX, const bool blockMode=false)
Open the sequencer device.
Definition: alsaclient.cpp:395
void dropOutputBuffer()
Removes all events on the library output buffer.
int getMaxClients()
Get the system's maximum number of clients.
void setErrorBounce(bool newValue)
Sets the error-bounce usage of the client.
Definition: alsaclient.cpp:978
void run() override
Main input thread process loop.
void disconnectFrom(int myport, int client, int port)
Unsubscribe one port from another arbitrary sequencer client:port.
Q_DECL_DEPRECATED const unsigned char * getEventFilter()
Gets the client's event filter.
void synchronizeOutput()
Wait until all sent events are processed.
int getEventLost()
Gets the number of lost events.
void setInputBufferSize(size_t newSize)
Sets the size of the library input buffer for the ALSA client.
Definition: alsaclient.cpp:514
SystemInfo()
Default constructor.
PortInfoList getPorts() const
Gets the ports list.
void updateAvailablePorts()
Update the internal lists of user ports.
void freeClients()
Releases the list of ALSA sequencer's clients.
Definition: alsaclient.cpp:754
unsigned short pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds)
Gets the number of returned events from poll descriptors.
void connectFrom(int myport, int client, int port)
Subscribe one port from another arbitrary sequencer client:port.
int getOutputFree()
Gets the available size on output pool.
int outputPending()
Returns the size of pending events on the output buffer.
PoolInfo * clone()
Clone the pool info obeject.
bool stopped()
Returns true or false depending on the input thread state.
ClientInfo & getThisClientInfo()
Gets the ClientInfo object holding data about this client.
Definition: alsaclient.cpp:777
PoolInfo & getPoolInfo()
Gets a PoolInfo instance with an updated state of the client memory pool.
void freePorts()
Release the ports list.
void portAttach(MidiPort *port)
Attach a MidiPort instance to this client.
Definition: alsaclient.cpp:877
void setEventsEnabled(const bool bEnabled)
Enables the notification of received SequencerEvent instances to the listeners registered with addLis...
bool getBlockMode()
Returns the last block mode used in open()
Definition: alsaclient.cpp:322
void addEventFilter(int evtype)
Add an event filter to the client.
Definition: alsaclient.cpp:933
void setOutputPool(int size)
Sets the output pool size.
void outputDirect(SequencerEvent *ev, bool async=false, int timeout=-1)
Output an event directly to the sequencer.
int getOutputPool()
Gets the output pool size.
void drainOutput(bool async=false, int timeout=-1)
Drain the library output buffer.
bool isOpened()
Returns true if the sequencer is opened.
Definition: alsaclient.cpp:295
void connectTo(int myport, int client, int port)
Subscribe one port to another arbitrary sequencer client:port.
ClientInfo * clone()
Clone the client info object.
virtual ~MidiClient()
Destructor.
Definition: alsaclient.cpp:271
#define DRUMSTICK_ALSA_CHECK_WARNING(x)
This macro calls the check warning function.
Definition: errorcheck.h:86
#define DRUMSTICK_ALSA_CHECK_ERROR(x)
This macro calls the check error function.
Definition: errorcheck.h:80
QList< MidiPort * > MidiPortList
List of Ports instances.
Definition: alsaport.h:220
QList< PortInfo > PortInfoList
List of port information objects.
Definition: alsaport.h:117
Drumstick common.
Definition: alsaclient.cpp:68