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>
26 #include <drumstick/alsaclient.h>
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 
68 namespace drumstick { namespace ALSA {
69 
188 {
189 public:
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 
209 class MidiClient::MidiClientPrivate
210 {
211 public:
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 {
274  detachAllPorts();
275  delete d->m_Queue;
276  close();
277  freeClients();
278  delete d->m_Thread;
279 }
280 
285 snd_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 
394 void
395 MidiClient::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 
427 void
428 MidiClient::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 
451 void
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 
469 size_t
471 {
472  return snd_seq_get_output_buffer_size(d->m_SeqHandle);
473 }
474 
483 void
485 {
486  if (getOutputBufferSize() != newSize) {
487  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_output_buffer_size(d->m_SeqHandle, newSize));
488  }
489 }
490 
499 size_t
501 {
502  return snd_seq_get_input_buffer_size(d->m_SeqHandle);
503 }
504 
513 void
515 {
516  if (getInputBufferSize() != newSize) {
517  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_input_buffer_size(d->m_SeqHandle, newSize));
518  }
519 }
520 
530 void
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 
551 int
553 {
554  return DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_client_id(d->m_SeqHandle));
555 }
556 
561 snd_seq_type_t
563 {
564  return snd_seq_type(d->m_SeqHandle);
565 }
566 
587 void
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 
703 void
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 
716 void
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 
737 void
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 
753 void
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 
776 ClientInfo&
778 {
779  snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info);
780  return d->m_Info;
781 }
782 
790 void
792 {
793  d->m_Info = val;
794  snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
795 }
796 
800 void
802 {
803  if (d->m_SeqHandle != nullptr) {
804  snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
805  }
806 }
807 
812 QString
814 {
815  return d->m_Info.getName();
816 }
817 
823 QString
824 MidiClient::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 
841 void
842 MidiClient::setClientName(QString const& newName)
843 {
844  if (newName != d->m_Info.getName()) {
845  d->m_Info.setName(newName);
846  applyClientInfo();
847  }
848 }
849 
856 {
857  return d->m_Ports;
858 }
859 
864 MidiPort*
866 {
867  MidiPort* port = new MidiPort(this);
868  port->attach(this);
869  return port;
870 }
871 
876 void
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 
889 void
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 
932 void
934 {
935  snd_seq_set_client_event_filter(d->m_SeqHandle, evtype);
936 }
937 
943 bool
945 {
946  return d->m_Info.getBroadcastFilter();
947 }
948 
954 void
956 {
957  d->m_Info.setBroadcastFilter(newValue);
958  applyClientInfo();
959 }
960 
966 bool
968 {
969  return d->m_Info.getErrorBounce();
970 }
971 
977 void
979 {
980  d->m_Info.setErrorBounce(newValue);
981  applyClientInfo();
982 }
983 
995 void
996 MidiClient::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 
1024 void 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 
1048 void
1050 {
1051  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_event_output_buffer(d->m_SeqHandle, ev->getHandle()));
1052 }
1053 
1065 void 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 
1086 void
1088 {
1089  snd_seq_sync_output_queue(d->m_SeqHandle);
1090 }
1091 
1097 MidiQueue*
1099 {
1100  if (d->m_Queue == nullptr) {
1101  createQueue();
1102  }
1103  return d->m_Queue;
1104 }
1105 
1110 MidiQueue*
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 
1126 MidiQueue*
1127 MidiClient::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 
1143 MidiQueue*
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 
1160 MidiQueue*
1161 MidiClient::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 
1179 MidiQueue*
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 
1194 QList<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 
1219 MidiClient::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 
1249 void
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 
1290 void
1292 {
1293  d->m_listeners.append(listener);
1294 }
1295 
1301 void
1303 {
1304  d->m_listeners.removeAll(listener);
1305 }
1306 
1313 void
1315 {
1316  if (bEnabled != d->m_eventsEnabled) {
1317  d->m_eventsEnabled = bEnabled;
1318  }
1319 }
1320 
1325 SystemInfo&
1327 {
1328  snd_seq_system_info(d->m_SeqHandle, d->m_sysInfo.m_Info);
1329  return d->m_sysInfo;
1330 }
1331 
1336 PoolInfo&
1338 {
1339  snd_seq_get_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info);
1340  return d->m_poolInfo;
1341 }
1342 
1347 void
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 
1358 void
1360 {
1361  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_reset_pool_input(d->m_SeqHandle));
1362 }
1363 
1368 void
1370 {
1371  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_reset_pool_output(d->m_SeqHandle));
1372 }
1373 
1378 void
1380 {
1381  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_input(d->m_SeqHandle, size));
1382 }
1383 
1388 void
1390 {
1391  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_output(d->m_SeqHandle, size));
1392 }
1393 
1398 void
1400 {
1401  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_output_room(d->m_SeqHandle, size));
1402 }
1403 
1408 void
1410 {
1411  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_input(d->m_SeqHandle));
1412 }
1413 
1418 void
1420 {
1421  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_input_buffer(d->m_SeqHandle));
1422 }
1423 
1431 void
1433 {
1434  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_output(d->m_SeqHandle));
1435 }
1436 
1444 void
1446 {
1447  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_output_buffer(d->m_SeqHandle));
1448 }
1449 
1456 void
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 
1481 int
1483 {
1484  return snd_seq_event_output_pending(d->m_SeqHandle);
1485 }
1486 
1500 int
1502 {
1503  return snd_seq_event_input_pending(d->m_SeqHandle, fetch ? 1 : 0);
1504 }
1505 
1512 int
1513 MidiClient::getQueueId(const QString& name)
1514 {
1515  return snd_seq_query_named_queue(d->m_SeqHandle, name.toLocal8Bit().data());
1516 }
1517 
1523 int
1525 {
1526  return snd_seq_poll_descriptors_count(d->m_SeqHandle, events);
1527 }
1528 
1542 int
1543 MidiClient::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 
1555 unsigned short
1556 MidiClient::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 
1569 const char *
1571 {
1572  return snd_seq_name(d->m_SeqHandle);
1573 }
1574 
1579 void
1581 {
1582  DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_name(d->m_SeqHandle, name));
1583 }
1584 
1592 int
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 
1605 void
1607 {
1608  DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_delete_simple_port( d->m_SeqHandle, port ));
1609 }
1610 
1617 void
1618 MidiClient::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 
1629 void
1630 MidiClient::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 
1641 void
1642 MidiClient::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 
1653 void
1654 MidiClient::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 
1670 bool
1671 MidiClient::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 
1707 bool
1709 {
1710  QReadLocker locker(&m_mutex);
1711  return m_Stopped;
1712 }
1713 
1717 void
1719 {
1720  QWriteLocker locker(&m_mutex);
1721  m_Stopped = true;
1722 }
1723 
1724 #if defined(RTKIT_SUPPORT)
1725 static pid_t _gettid() {
1726  return (pid_t) ::syscall(SYS_gettid);
1727 }
1728 #endif
1729 
1730 void
1731 MidiClient::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 
1796 void
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 
1847 ClientInfo::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 
1877 ClientInfo*
1879 {
1880  return new ClientInfo(m_Info);
1881 }
1882 
1888 ClientInfo&
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 
1902 int
1904 {
1905  return snd_seq_client_info_get_client(m_Info);
1906 }
1907 
1912 snd_seq_client_type_t
1914 {
1915  return snd_seq_client_info_get_type(m_Info);
1916 }
1917 
1922 QString
1924 {
1925  return QString(snd_seq_client_info_get_name(m_Info));
1926 }
1927 
1932 bool
1934 {
1935  return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0);
1936 }
1937 
1942 bool
1944 {
1945  return (snd_seq_client_info_get_error_bounce(m_Info) != 0);
1946 }
1947 
1953 const unsigned char*
1955 {
1956  return snd_seq_client_info_get_event_filter(m_Info);
1957 }
1958 
1963 int
1965 {
1966  return snd_seq_client_info_get_num_ports(m_Info);
1967 }
1968 
1973 int
1975 {
1976  return snd_seq_client_info_get_event_lost(m_Info);
1977 }
1978 
1983 void
1985 {
1986  snd_seq_client_info_set_client(m_Info, client);
1987 }
1988 
1993 void
1994 ClientInfo::setName(QString name)
1995 {
1996  snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data());
1997 }
1998 
2003 void
2005 {
2006  snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0);
2007 }
2008 
2013 void
2015 {
2016  snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0);
2017 }
2018 
2024 void
2025 ClientInfo::setEventFilter(unsigned char *filter)
2026 {
2027  snd_seq_client_info_set_event_filter(m_Info, filter);
2028 }
2029 
2034 void
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 
2051 void
2053 {
2054  m_Ports.clear();
2055 }
2056 
2063 {
2064  PortInfoList lst = m_Ports; // copy
2065  return lst;
2066 }
2067 
2072 int
2074 {
2075  return snd_seq_client_info_sizeof();
2076 }
2077 
2078 #if SND_LIB_VERSION > 0x010010
2084 void
2085 ClientInfo::addFilter(int eventType)
2086 {
2087  snd_seq_client_info_event_filter_add(m_Info, eventType);
2088 }
2089 
2095 bool
2096 ClientInfo::isFiltered(int eventType)
2097 {
2098  return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0);
2099 }
2100 
2104 void
2105 ClientInfo::clearFilter()
2106 {
2107  snd_seq_client_info_event_filter_clear(m_Info);
2108 }
2109 
2114 void
2115 ClientInfo::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 
2143 SystemInfo::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 
2171 SystemInfo*
2173 {
2174  return new SystemInfo(m_Info);
2175 }
2176 
2182 SystemInfo&
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 
2276 PoolInfo::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 
2304 PoolInfo*
2306 {
2307  return new PoolInfo(m_Info);
2308 }
2309 
2315 PoolInfo&
2317 {
2318  if (this == &other)
2319  return *this;
2320  snd_seq_client_pool_copy(m_Info, other.m_Info);
2321  return *this;
2322 }
2323 
2328 int
2330 {
2331  return snd_seq_client_pool_get_client(m_Info);
2332 }
2333 
2338 int
2340 {
2341  return snd_seq_client_pool_get_input_free(m_Info);
2342 }
2343 
2348 int
2350 {
2351  return snd_seq_client_pool_get_input_pool(m_Info);
2352 }
2353 
2358 int
2360 {
2361  return snd_seq_client_pool_get_output_free(m_Info);
2362 }
2363 
2368 int
2370 {
2371  return snd_seq_client_pool_get_output_pool(m_Info);
2372 }
2373 
2379 int
2381 {
2382  return snd_seq_client_pool_get_output_room(m_Info);
2383 }
2384 
2389 void
2391 {
2392  snd_seq_client_pool_set_input_pool(m_Info, size);
2393 }
2394 
2399 void
2401 {
2402  snd_seq_client_pool_set_output_pool(m_Info, size);
2403 }
2404 
2411 void
2413 {
2414  snd_seq_client_pool_set_output_room(m_Info, size);
2415 }
2416 
2421 int
2423 {
2424  return snd_seq_client_pool_sizeof();
2425 }
2426 
2427 #if SND_LIB_VERSION > 0x010004
2433 QString
2434 getRuntimeALSALibraryVersion()
2435 {
2436  return QString(snd_asoundlib_version());
2437 }
2438 
2444 int
2445 getRuntimeALSALibraryNumber()
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 
2470 QString
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 
2492 int
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