drumstick  1.1.0
alsaclient.cpp
Go to the documentation of this file.
1 /*
2  MIDI Sequencer C++ library
3  Copyright (C) 2006-2016, 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 2 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 along
16  with this program; if not, write to the Free Software Foundation, Inc.,
17  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19 
20 #include "alsaclient.h"
21 #include "alsaqueue.h"
22 #include "alsaevent.h"
23 #include <QFile>
24 #include <QRegExp>
25 #include <QThread>
26 #include <QReadLocker>
27 #include <QWriteLocker>
28 #if defined(RTKIT_SUPPORT)
29 #include <QDBusConnection>
30 #include <QDBusInterface>
31 #include <sys/types.h>
32 #include <sys/syscall.h>
33 #include <sys/resource.h>
34 #endif
35 #include <pthread.h>
36 
37 #ifndef RLIMIT_RTTIME
38 #define RLIMIT_RTTIME 15
39 #endif
40 
41 #ifndef SCHED_RESET_ON_FORK
42 #define SCHED_RESET_ON_FORK 0x40000000
43 #endif
44 
45 #ifndef DEFAULT_INPUT_TIMEOUT
46 #define DEFAULT_INPUT_TIMEOUT 500
47 #endif
48 
66 namespace drumstick {
67 
187 {
188 public:
189  SequencerInputThread(MidiClient *seq, int timeout)
190  : QThread(),
191  m_MidiClient(seq),
192  m_Wait(timeout),
193  m_Stopped(false),
194  m_RealTime(true) {}
195  virtual ~SequencerInputThread() {}
196  virtual void run();
197  bool stopped();
198  void stop();
199  void setRealtimePriority();
200 
201  MidiClient *m_MidiClient;
202  int m_Wait;
203  bool m_Stopped;
204  bool m_RealTime;
205  QReadWriteLock m_mutex;
206 };
207 
208 class MidiClient::MidiClientPrivate
209 {
210 public:
211  MidiClientPrivate() :
212  m_eventsEnabled(false),
213  m_BlockMode(false),
214  m_NeedRefreshClientList(true),
215  m_OpenMode(SND_SEQ_OPEN_DUPLEX),
216  m_DeviceName("default"),
217  m_SeqHandle(0),
218  m_Thread(0),
219  m_Queue(0),
220  m_handler(0)
221  { }
222 
223  bool m_eventsEnabled;
224  bool m_BlockMode;
225  bool m_NeedRefreshClientList;
226  int m_OpenMode;
227  QString m_DeviceName;
228  snd_seq_t* m_SeqHandle;
229  QPointer<SequencerInputThread> m_Thread;
230  QPointer<MidiQueue> m_Queue;
231  SequencerEventHandler* m_handler;
232 
233  ClientInfo m_Info;
234  ClientInfoList m_ClientList;
235  MidiPortList m_Ports;
236  PortInfoList m_OutputsAvail;
237  PortInfoList m_InputsAvail;
238  QObjectList m_listeners;
239  SystemInfo m_sysInfo;
240  PoolInfo m_poolInfo;
241 };
242 
259  QObject(parent),
260  d(new MidiClientPrivate)
261 { }
262 
269 {
271  detachAllPorts();
272  if (d->m_Queue != 0)
273  delete d->m_Queue;
274  close();
275  freeClients();
276  if (d->m_Thread != 0)
277  delete d->m_Thread;
278  delete d;
279 }
280 
281 
285 snd_seq_t*
287 {
288  return d->m_SeqHandle;
289 }
290 
295 {
296  return (d->m_SeqHandle != NULL);
297 }
298 
303 {
304  return d->m_DeviceName;
305 }
306 
311 {
312  return d->m_OpenMode;
313 }
314 
319 {
320  return d->m_BlockMode;
321 }
322 
327 {
328  return d->m_eventsEnabled;
329 }
330 
335 {
336  d->m_handler = handler;
337 }
338 
339 
349 {
350  if (d->m_Thread == 0) {
351  d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
352  d->m_Thread->m_RealTime = enable;
353  }
354 }
355 
362 {
363  if (d->m_Thread == 0)
364  return true;
365  return d->m_Thread->m_RealTime;
366 }
367 
388 void
389 MidiClient::open( const QString deviceName,
390  const int openMode,
391  const bool blockMode)
392 {
393  CHECK_ERROR( snd_seq_open( &d->m_SeqHandle, deviceName.toLocal8Bit().data(),
394  openMode, blockMode ? 0 : SND_SEQ_NONBLOCK ) );
395  CHECK_WARNING( snd_seq_get_client_info( d->m_SeqHandle, d->m_Info.m_Info ) );
396  d->m_DeviceName = deviceName;
397  d->m_OpenMode = openMode;
398  d->m_BlockMode = blockMode;
399 }
400 
421 void
422 MidiClient::open( snd_config_t* conf,
423  const QString deviceName,
424  const int openMode,
425  const bool blockMode )
426 {
427  CHECK_ERROR( snd_seq_open_lconf( &d->m_SeqHandle,
428  deviceName.toLocal8Bit().data(),
429  openMode,
430  blockMode ? 0 : SND_SEQ_NONBLOCK,
431  conf ));
432  CHECK_WARNING( snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info));
433  d->m_DeviceName = deviceName;
434  d->m_OpenMode = openMode;
435  d->m_BlockMode = blockMode;
436 }
437 
445 void
447 {
448  if (d->m_SeqHandle != NULL) {
450  CHECK_WARNING(snd_seq_close(d->m_SeqHandle));
451  d->m_SeqHandle = NULL;
452  }
453 }
454 
463 size_t
465 {
466  return snd_seq_get_output_buffer_size(d->m_SeqHandle);
467 }
468 
477 void
479 {
480  if (getOutputBufferSize() != newSize) {
481  CHECK_WARNING(snd_seq_set_output_buffer_size(d->m_SeqHandle, newSize));
482  }
483 }
484 
493 size_t
495 {
496  return snd_seq_get_input_buffer_size(d->m_SeqHandle);
497 }
498 
507 void
509 {
510  if (getInputBufferSize() != newSize) {
511  CHECK_WARNING(snd_seq_set_input_buffer_size(d->m_SeqHandle, newSize));
512  }
513 }
514 
524 void
526 {
527  if (d->m_BlockMode != newValue)
528  {
529  d->m_BlockMode = newValue;
530  if (d->m_SeqHandle != NULL)
531  {
532  CHECK_WARNING(snd_seq_nonblock(d->m_SeqHandle, d->m_BlockMode ? 0 : 1));
533  }
534  }
535 }
536 
545 int
547 {
548  return CHECK_WARNING(snd_seq_client_id(d->m_SeqHandle));
549 }
550 
555 snd_seq_type_t
557 {
558  return snd_seq_type(d->m_SeqHandle);
559 }
560 
581 void
583 {
584  do {
585  int err = 0;
586  snd_seq_event_t* evp = NULL;
587  SequencerEvent* event = NULL;
588  err = snd_seq_event_input(d->m_SeqHandle, &evp);
589  if ((err >= 0) && (evp != NULL)) {
590  switch (evp->type) {
591 
592  case SND_SEQ_EVENT_NOTE:
593  event = new NoteEvent(evp);
594  break;
595 
596  case SND_SEQ_EVENT_NOTEON:
597  event = new NoteOnEvent(evp);
598  break;
599 
600  case SND_SEQ_EVENT_NOTEOFF:
601  event = new NoteOffEvent(evp);
602  break;
603 
604  case SND_SEQ_EVENT_KEYPRESS:
605  event = new KeyPressEvent(evp);
606  break;
607 
608  case SND_SEQ_EVENT_CONTROLLER:
609  case SND_SEQ_EVENT_CONTROL14:
610  case SND_SEQ_EVENT_REGPARAM:
611  case SND_SEQ_EVENT_NONREGPARAM:
612  event = new ControllerEvent(evp);
613  break;
614 
615  case SND_SEQ_EVENT_PGMCHANGE:
616  event = new ProgramChangeEvent(evp);
617  break;
618 
619  case SND_SEQ_EVENT_CHANPRESS:
620  event = new ChanPressEvent(evp);
621  break;
622 
623  case SND_SEQ_EVENT_PITCHBEND:
624  event = new PitchBendEvent(evp);
625  break;
626 
627  case SND_SEQ_EVENT_SYSEX:
628  event = new SysExEvent(evp);
629  break;
630 
631  case SND_SEQ_EVENT_PORT_SUBSCRIBED:
632  case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
633  event = new SubscriptionEvent(evp);
634  break;
635 
636  case SND_SEQ_EVENT_PORT_CHANGE:
637  case SND_SEQ_EVENT_PORT_EXIT:
638  case SND_SEQ_EVENT_PORT_START:
639  event = new PortEvent(evp);
640  d->m_NeedRefreshClientList = true;
641  break;
642 
643  case SND_SEQ_EVENT_CLIENT_CHANGE:
644  case SND_SEQ_EVENT_CLIENT_EXIT:
645  case SND_SEQ_EVENT_CLIENT_START:
646  event = new ClientEvent(evp);
647  d->m_NeedRefreshClientList = true;
648  break;
649 
650  case SND_SEQ_EVENT_SONGPOS:
651  case SND_SEQ_EVENT_SONGSEL:
652  case SND_SEQ_EVENT_QFRAME:
653  case SND_SEQ_EVENT_TIMESIGN:
654  case SND_SEQ_EVENT_KEYSIGN:
655  event = new ValueEvent(evp);
656  break;
657 
658  case SND_SEQ_EVENT_SETPOS_TICK:
659  case SND_SEQ_EVENT_SETPOS_TIME:
660  case SND_SEQ_EVENT_QUEUE_SKEW:
661  event = new QueueControlEvent(evp);
662  break;
663 
664  case SND_SEQ_EVENT_TEMPO:
665  event = new TempoEvent(evp);
666  break;
667 
668  default:
669  event = new SequencerEvent(evp);
670  break;
671  }
672  // first, process the callback (if any)
673  if (d->m_handler != NULL) {
674  d->m_handler->handleSequencerEvent(event->clone());
675  } else {
676  // second, process the event listeners
677  if (d->m_eventsEnabled) {
678  QObjectList::Iterator it;
679  for(it=d->m_listeners.begin(); it!=d->m_listeners.end(); ++it) {
680  QObject* sub = (*it);
681  QCoreApplication::postEvent(sub, event->clone());
682  }
683  } else {
684  // finally, process signals
685  emit eventReceived(event->clone());
686  }
687  }
688  delete event;
689  }
690  }
691  while (snd_seq_event_input_pending(d->m_SeqHandle, 0) > 0);
692 }
693 
697 void
699 {
700  if (d->m_Thread == 0) {
701  d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
702  }
703  d->m_Thread->start( d->m_Thread->m_RealTime ?
704  QThread::TimeCriticalPriority : QThread::InheritPriority );
705 }
706 
710 void
712 {
713  int counter = 0;
714  if (d->m_Thread != 0) {
715  if (d->m_Thread->isRunning()) {
716  d->m_Thread->stop();
717  while (!d->m_Thread->wait(500) && (counter < 10)) {
718  counter++;
719  }
720  if (!d->m_Thread->isFinished()) {
721  d->m_Thread->terminate();
722  }
723  }
724  delete d->m_Thread;
725  }
726 }
727 
731 void
733 {
734  ClientInfo cInfo;
735  freeClients();
736  cInfo.setClient(-1);
737  while (snd_seq_query_next_client(d->m_SeqHandle, cInfo.m_Info) >= 0) {
738  cInfo.readPorts(this);
739  d->m_ClientList.append(cInfo);
740  }
741  d->m_NeedRefreshClientList = false;
742 }
743 
747 void
749 {
750  d->m_ClientList.clear();
751 }
752 
757 ClientInfoList
759 {
760  if (d->m_NeedRefreshClientList)
761  readClients();
762  ClientInfoList lst = d->m_ClientList; // copy
763  return lst;
764 }
765 
770 ClientInfo&
772 {
773  snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info);
774  return d->m_Info;
775 }
776 
784 void
786 {
787  d->m_Info = val;
788  snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
789 }
790 
794 void
796 {
797  if (d->m_SeqHandle != NULL) {
798  snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
799  }
800 }
801 
806 QString
808 {
809  return d->m_Info.getName();
810 }
811 
817 QString
818 MidiClient::getClientName(const int clientId)
819 {
820  ClientInfoList::Iterator it;
821  if (d->m_NeedRefreshClientList)
822  readClients();
823  for (it = d->m_ClientList.begin(); it != d->m_ClientList.end(); ++it) {
824  if ((*it).getClientId() == clientId) {
825  return (*it).getName();
826  }
827  }
828  return QString();
829 }
830 
835 void
836 MidiClient::setClientName(QString const& newName)
837 {
838  if (newName != d->m_Info.getName()) {
839  d->m_Info.setName(newName);
840  applyClientInfo();
841  }
842 }
843 
848 MidiPortList
850 {
851  return d->m_Ports;
852 }
853 
858 MidiPort*
860 {
861  MidiPort* port = new MidiPort(this);
862  port->attach(this);
863  return port;
864 }
865 
870 void
872 {
873  if (d->m_SeqHandle != NULL) {
874  CHECK_ERROR(snd_seq_create_port(d->m_SeqHandle, port->m_Info.m_Info));
875  d->m_Ports.push_back(port);
876  }
877 }
878 
883 void
885 {
886  if (d->m_SeqHandle != NULL) {
887  if(port->getPortInfo()->getClient() == getClientId())
888  {
889  return;
890  }
891  CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, port->getPortInfo()->getPort()));
892  port->setMidiClient(NULL);
893 
894  MidiPortList::iterator it;
895  for(it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it)
896  {
897  if ((*it)->getPortInfo()->getPort() == port->getPortInfo()->getPort())
898  {
899  d->m_Ports.erase(it);
900  break;
901  }
902  }
903  }
904 }
905 
910 {
911  if (d->m_SeqHandle != NULL) {
912  MidiPortList::iterator it;
913  for (it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it) {
914  CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, (*it)->getPortInfo()->getPort()));
915  (*it)->setMidiClient(NULL);
916  d->m_Ports.erase(it);
917  }
918  }
919 }
920 
925 void
927 {
928  snd_seq_set_client_event_filter(d->m_SeqHandle, evtype);
929 }
930 
936 bool
938 {
939  return d->m_Info.getBroadcastFilter();
940 }
941 
947 void
949 {
950  d->m_Info.setBroadcastFilter(newValue);
951  applyClientInfo();
952 }
953 
959 bool
961 {
962  return d->m_Info.getErrorBounce();
963 }
964 
970 void
972 {
973  d->m_Info.setErrorBounce(newValue);
974  applyClientInfo();
975 }
976 
988 void
989 MidiClient::output(SequencerEvent* ev, bool async, int timeout)
990 {
991  int npfds;
992  pollfd* pfds;
993  if (async) {
994  CHECK_WARNING(snd_seq_event_output(d->m_SeqHandle, ev->getHandle()));
995  } else {
996  npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
997  pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
998  snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
999  while (snd_seq_event_output(d->m_SeqHandle, ev->getHandle()) < 0)
1000  {
1001  poll(pfds, npfds, timeout);
1002  }
1003  }
1004 }
1005 
1017 void MidiClient::outputDirect(SequencerEvent* ev, bool async, int timeout)
1018 {
1019  int npfds;
1020  pollfd* pfds;
1021  if (async) {
1022  CHECK_WARNING(snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()));
1023  } else {
1024  npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
1025  pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
1026  snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
1027  while (snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()) < 0)
1028  {
1029  poll(pfds, npfds, timeout);
1030  }
1031  }
1032 }
1033 
1042 void
1044 {
1045  CHECK_WARNING(snd_seq_event_output_buffer(d->m_SeqHandle, ev->getHandle()));
1046 }
1047 
1059 void MidiClient::drainOutput(bool async, int timeout)
1060 {
1061  int npfds;
1062  pollfd* pfds;
1063  if (async) {
1064  CHECK_WARNING(snd_seq_drain_output(d->m_SeqHandle));
1065  } else {
1066  npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
1067  pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
1068  snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
1069  while (snd_seq_drain_output(d->m_SeqHandle) < 0)
1070  {
1071  poll(pfds, npfds, timeout);
1072  }
1073  }
1074 }
1075 
1081 void
1083 {
1084  snd_seq_sync_output_queue(d->m_SeqHandle);
1085 }
1086 
1092 MidiQueue*
1094 {
1095  if (d->m_Queue == NULL) {
1096  createQueue();
1097  }
1098  return d->m_Queue;
1099 }
1100 
1105 MidiQueue*
1107 {
1108  if (d->m_Queue != NULL) {
1109  delete d->m_Queue;
1110  }
1111  d->m_Queue = new MidiQueue(this, this);
1112  return d->m_Queue;
1113 }
1114 
1121 MidiQueue*
1122 MidiClient::createQueue(QString const& queueName )
1123 {
1124  if (d->m_Queue != NULL) {
1125  delete d->m_Queue;
1126  }
1127  d->m_Queue = new MidiQueue(this, queueName, this);
1128  return d->m_Queue;
1129 }
1130 
1138 MidiQueue*
1140 {
1141  if (d->m_Queue != NULL) {
1142  delete d->m_Queue;
1143  }
1144  d->m_Queue = new MidiQueue(this, queue_id, this);
1145  return d->m_Queue;
1146 }
1147 
1155 MidiQueue*
1156 MidiClient::useQueue(const QString& name)
1157 {
1158  if (d->m_Queue != NULL) {
1159  delete d->m_Queue;
1160  }
1161  int queue_id = getQueueId(name);
1162  if ( queue_id >= 0) {
1163  d->m_Queue = new MidiQueue(this, queue_id, this);
1164  }
1165  return d->m_Queue;
1166 }
1167 
1174 MidiQueue*
1176 {
1177  if (d->m_Queue != NULL) {
1178  delete d->m_Queue;
1179  }
1180  queue->setParent(this);
1181  d->m_Queue = queue;
1182  return d->m_Queue;
1183 }
1184 
1189 QList<int>
1191 {
1192  int q, err, max;
1193  QList<int> queues;
1194  snd_seq_queue_info_t* qinfo;
1195  snd_seq_queue_info_alloca(&qinfo);
1196  max = getSystemInfo().getMaxQueues();
1197  for ( q = 0; q < max; ++q ) {
1198  err = snd_seq_get_queue_info(d->m_SeqHandle, q, qinfo);
1199  if (err == 0) {
1200  queues.append(q);
1201  }
1202  }
1203  return queues;
1204 }
1205 
1213 PortInfoList
1214 MidiClient::filterPorts(unsigned int filter)
1215 {
1216  PortInfoList result;
1217  ClientInfoList::ConstIterator itc;
1218  PortInfoList::ConstIterator itp;
1219 
1220  if (d->m_NeedRefreshClientList)
1221  readClients();
1222 
1223  for (itc = d->m_ClientList.constBegin(); itc != d->m_ClientList.constEnd(); ++itc) {
1224  ClientInfo ci = (*itc);
1225  if ((ci.getClientId() == SND_SEQ_CLIENT_SYSTEM) ||
1226  (ci.getClientId() == d->m_Info.getClientId()))
1227  continue;
1228  PortInfoList lstPorts = ci.getPorts();
1229  for(itp = lstPorts.constBegin(); itp != lstPorts.constEnd(); ++itp) {
1230  PortInfo pi = (*itp);
1231  unsigned int cap = pi.getCapability();
1232  if ( ((filter & cap) != 0) &&
1233  ((SND_SEQ_PORT_CAP_NO_EXPORT & cap) == 0) ) {
1234  result.append(pi);
1235  }
1236  }
1237  }
1238  return result;
1239 }
1240 
1244 void
1246 {
1247  d->m_InputsAvail.clear();
1248  d->m_OutputsAvail.clear();
1249  d->m_InputsAvail = filterPorts( SND_SEQ_PORT_CAP_READ |
1250  SND_SEQ_PORT_CAP_SUBS_READ );
1251  d->m_OutputsAvail = filterPorts( SND_SEQ_PORT_CAP_WRITE |
1252  SND_SEQ_PORT_CAP_SUBS_WRITE );
1253 }
1254 
1259 PortInfoList
1261 {
1262  d->m_NeedRefreshClientList = true;
1264  return d->m_InputsAvail;
1265 }
1266 
1271 PortInfoList
1273 {
1274  d->m_NeedRefreshClientList = true;
1276  return d->m_OutputsAvail;
1277 }
1278 
1285 void
1287 {
1288  d->m_listeners.append(listener);
1289 }
1290 
1296 void
1298 {
1299  d->m_listeners.removeAll(listener);
1300 }
1301 
1308 void
1310 {
1311  if (bEnabled != d->m_eventsEnabled) {
1312  d->m_eventsEnabled = bEnabled;
1313  }
1314 }
1315 
1320 SystemInfo&
1322 {
1323  snd_seq_system_info(d->m_SeqHandle, d->m_sysInfo.m_Info);
1324  return d->m_sysInfo;
1325 }
1326 
1331 PoolInfo&
1333 {
1334  snd_seq_get_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info);
1335  return d->m_poolInfo;
1336 }
1337 
1342 void
1344 {
1345  d->m_poolInfo = info;
1346  CHECK_WARNING(snd_seq_set_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info));
1347 }
1348 
1353 void
1355 {
1356  CHECK_WARNING(snd_seq_reset_pool_input(d->m_SeqHandle));
1357 }
1358 
1363 void
1365 {
1366  CHECK_WARNING(snd_seq_reset_pool_output(d->m_SeqHandle));
1367 }
1368 
1373 void
1375 {
1376  CHECK_WARNING(snd_seq_set_client_pool_input(d->m_SeqHandle, size));
1377 }
1378 
1383 void
1385 {
1386  CHECK_WARNING(snd_seq_set_client_pool_output(d->m_SeqHandle, size));
1387 }
1388 
1393 void
1395 {
1396  CHECK_WARNING(snd_seq_set_client_pool_output_room(d->m_SeqHandle, size));
1397 }
1398 
1403 void
1405 {
1406  CHECK_WARNING(snd_seq_drop_input(d->m_SeqHandle));
1407 }
1408 
1413 void
1415 {
1416  CHECK_WARNING(snd_seq_drop_input_buffer(d->m_SeqHandle));
1417 }
1418 
1426 void
1428 {
1429  CHECK_WARNING(snd_seq_drop_output(d->m_SeqHandle));
1430 }
1431 
1439 void
1441 {
1442  CHECK_WARNING(snd_seq_drop_output_buffer(d->m_SeqHandle));
1443 }
1444 
1451 void
1453 {
1454  CHECK_WARNING(snd_seq_remove_events(d->m_SeqHandle, spec->m_Info));
1455 }
1456 
1463 {
1464  snd_seq_event_t* ev;
1465  if (CHECK_WARNING(snd_seq_extract_output(d->m_SeqHandle, &ev) == 0)) {
1466  return new SequencerEvent(ev);
1467  }
1468  return NULL;
1469 }
1470 
1476 int
1478 {
1479  return snd_seq_event_output_pending(d->m_SeqHandle);
1480 }
1481 
1495 int
1497 {
1498  return snd_seq_event_input_pending(d->m_SeqHandle, fetch ? 1 : 0);
1499 }
1500 
1507 int
1508 MidiClient::getQueueId(const QString& name)
1509 {
1510  return snd_seq_query_named_queue(d->m_SeqHandle, name.toLocal8Bit().data());
1511 }
1512 
1518 int
1520 {
1521  return snd_seq_poll_descriptors_count(d->m_SeqHandle, events);
1522 }
1523 
1537 int
1538 MidiClient::pollDescriptors( struct pollfd *pfds, unsigned int space,
1539  short events )
1540 {
1541  return snd_seq_poll_descriptors(d->m_SeqHandle, pfds, space, events);
1542 }
1543 
1550 unsigned short
1551 MidiClient::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds)
1552 {
1553  unsigned short revents;
1554  CHECK_WARNING( snd_seq_poll_descriptors_revents( d->m_SeqHandle,
1555  pfds, nfds,
1556  &revents ));
1557  return revents;
1558 }
1559 
1564 const char *
1566 {
1567  return snd_seq_name(d->m_SeqHandle);
1568 }
1569 
1574 void
1576 {
1577  CHECK_WARNING(snd_seq_set_client_name(d->m_SeqHandle, name));
1578 }
1579 
1587 int
1589  unsigned int caps,
1590  unsigned int type )
1591 {
1592  return CHECK_WARNING( snd_seq_create_simple_port( d->m_SeqHandle,
1593  name, caps, type ));
1594 }
1595 
1600 void
1602 {
1603  CHECK_WARNING( snd_seq_delete_simple_port( d->m_SeqHandle, port ));
1604 }
1605 
1612 void
1613 MidiClient::connectFrom(int myport, int client, int port)
1614 {
1615  CHECK_WARNING( snd_seq_connect_from(d->m_SeqHandle, myport, client, port ));
1616 }
1617 
1624 void
1625 MidiClient::connectTo(int myport, int client, int port)
1626 {
1627  CHECK_WARNING( snd_seq_connect_to(d->m_SeqHandle, myport, client, port ));
1628 }
1629 
1636 void
1637 MidiClient::disconnectFrom(int myport, int client, int port)
1638 {
1639  CHECK_WARNING( snd_seq_disconnect_from(d->m_SeqHandle, myport, client, port ));
1640 }
1641 
1648 void
1649 MidiClient::disconnectTo(int myport, int client, int port)
1650 {
1651  CHECK_WARNING( snd_seq_disconnect_to(d->m_SeqHandle, myport, client, port ));
1652 }
1653 
1665 bool
1666 MidiClient::parseAddress( const QString& straddr, snd_seq_addr& addr )
1667 {
1668  bool ok(false);
1669  QString testClient, testPort;
1670  ClientInfoList::ConstIterator cit;
1671  int pos = straddr.indexOf(':');
1672  if (pos > -1) {
1673  testClient = straddr.left(pos);
1674  testPort = straddr.mid(pos+1);
1675  } else {
1676  testClient = straddr;
1677  testPort = '0';
1678  }
1679  addr.client = testClient.toInt(&ok);
1680  if (ok)
1681  addr.port = testPort.toInt(&ok);
1682  if (!ok) {
1683  if (d->m_NeedRefreshClientList)
1684  readClients();
1685  for ( cit = d->m_ClientList.constBegin();
1686  cit != d->m_ClientList.constEnd(); ++cit ) {
1687  ClientInfo ci = *cit;
1688  if (testClient.compare(ci.getName(), Qt::CaseInsensitive) == 0) {
1689  addr.client = ci.getClientId();
1690  addr.port = testPort.toInt(&ok);
1691  return ok;
1692  }
1693  }
1694  }
1695  return ok;
1696 }
1697 
1702 bool
1704 {
1705  QReadLocker locker(&m_mutex);
1706  return m_Stopped;
1707 }
1708 
1712 void
1714 {
1715  QWriteLocker locker(&m_mutex);
1716  m_Stopped = true;
1717 }
1718 
1719 #if defined(RTKIT_SUPPORT)
1720 static pid_t _gettid(void) {
1721  return (pid_t) ::syscall(SYS_gettid);
1722 }
1723 #endif
1724 
1725 void
1726 MidiClient::SequencerInputThread::setRealtimePriority()
1727 {
1728  struct sched_param p;
1729  int rt, policy = SCHED_RR | SCHED_RESET_ON_FORK;
1730  quint32 priority = 6;
1731 #if defined(RTKIT_SUPPORT)
1732  bool ok;
1733  quint32 max_prio;
1734  quint64 thread;
1735  struct rlimit old_limit, new_limit;
1736  long long max_rttime;
1737 #endif
1738 
1739  ::memset(&p, 0, sizeof(p));
1740  p.sched_priority = priority;
1741  rt = ::pthread_setschedparam(::pthread_self(), policy, &p);
1742  if (rt != 0) {
1743 #if defined(RTKIT_SUPPORT)
1744  const QString rtkit_service =
1745  QLatin1String("org.freedesktop.RealtimeKit1");
1746  const QString rtkit_path =
1747  QLatin1String("/org/freedesktop/RealtimeKit1");
1748  const QString rtkit_iface = rtkit_service;
1749  thread = _gettid();
1750  QDBusConnection bus = QDBusConnection::systemBus();
1751  QDBusInterface realtimeKit(rtkit_service, rtkit_path, rtkit_iface, bus);
1752  QVariant maxRTPrio = realtimeKit.property("MaxRealtimePriority");
1753  max_prio = maxRTPrio.toUInt(&ok);
1754  if (!ok) {
1755  qWarning() << "invalid property RealtimeKit.MaxRealtimePriority";
1756  return;
1757  }
1758  if (priority > max_prio)
1759  priority = max_prio;
1760  QVariant maxRTNSec = realtimeKit.property("RTTimeNSecMax");
1761  max_rttime = maxRTNSec.toLongLong(&ok);
1762  if (!ok || max_rttime < 0) {
1763  qWarning() << "invalid property RealtimeKit.RTTimeNSecMax";
1764  return;
1765  }
1766  new_limit.rlim_cur = new_limit.rlim_max = max_rttime;
1767  rt = ::getrlimit(RLIMIT_RTTIME, &old_limit);
1768  if (rt < 0) {
1769  qWarning() << "getrlimit() failed. err=" << rt << ::strerror(rt);
1770  return;
1771  }
1772  rt = ::setrlimit(RLIMIT_RTTIME, &new_limit);
1773  if ( rt < 0) {
1774  qWarning() << "setrlimit() failed, err=" << rt << ::strerror(rt);
1775  return;
1776  }
1777  QDBusMessage reply = realtimeKit.call("MakeThreadRealtime", thread, priority);
1778  if (reply.type() == QDBusMessage::ErrorMessage )
1779  qWarning() << "error returned by RealtimeKit.MakeThreadRealtime:"
1780  << reply.errorMessage();
1781 #else
1782  qWarning() << "pthread_setschedparam() failed, err="
1783  << rt << ::strerror(rt);
1784 #endif
1785  }
1786 }
1787 
1791 void
1793 {
1794  unsigned long npfd;
1795  pollfd* pfd;
1796  if ( priority() == TimeCriticalPriority )
1797  setRealtimePriority();
1798 
1799  if (m_MidiClient != NULL) {
1800  npfd = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLIN);
1801  pfd = (pollfd *) alloca(npfd * sizeof(pollfd));
1802  try
1803  {
1804  snd_seq_poll_descriptors(m_MidiClient->getHandle(), pfd, npfd, POLLIN);
1805  while (!stopped() && (m_MidiClient != NULL))
1806  {
1807  int rt = poll(pfd, npfd, m_Wait);
1808  if (rt > 0) {
1809  m_MidiClient->doEvents();
1810  }
1811  }
1812  }
1813  catch (...)
1814  {
1815  qWarning() << "exception in input thread";
1816  }
1817  }
1818 }
1819 
1824 {
1825  snd_seq_client_info_malloc(&m_Info);
1826 }
1827 
1833 {
1834  snd_seq_client_info_malloc(&m_Info);
1835  snd_seq_client_info_copy(m_Info, other.m_Info);
1836  m_Ports = other.m_Ports;
1837 }
1838 
1843 ClientInfo::ClientInfo(snd_seq_client_info_t* other)
1844 {
1845  snd_seq_client_info_malloc(&m_Info);
1846  snd_seq_client_info_copy(m_Info, other);
1847 }
1848 
1855 {
1856  snd_seq_client_info_malloc(&m_Info);
1857  snd_seq_get_any_client_info(seq->getHandle(), id, m_Info);
1858 }
1859 
1864 {
1865  freePorts();
1866  snd_seq_client_info_free(m_Info);
1867 }
1868 
1873 ClientInfo*
1875 {
1876  return new ClientInfo(m_Info);
1877 }
1878 
1884 ClientInfo&
1886 {
1887  snd_seq_client_info_copy(m_Info, other.m_Info);
1888  m_Ports = other.m_Ports;
1889  return *this;
1890 }
1891 
1896 int
1898 {
1899  return snd_seq_client_info_get_client(m_Info);
1900 }
1901 
1906 snd_seq_client_type_t
1908 {
1909  return snd_seq_client_info_get_type(m_Info);
1910 }
1911 
1916 QString
1918 {
1919  return QString(snd_seq_client_info_get_name(m_Info));
1920 }
1921 
1926 bool
1928 {
1929  return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0);
1930 }
1931 
1936 bool
1938 {
1939  return (snd_seq_client_info_get_error_bounce(m_Info) != 0);
1940 }
1941 
1947 const unsigned char*
1949 {
1950  return snd_seq_client_info_get_event_filter(m_Info);
1951 }
1952 
1957 int
1959 {
1960  return snd_seq_client_info_get_num_ports(m_Info);
1961 }
1962 
1967 int
1969 {
1970  return snd_seq_client_info_get_event_lost(m_Info);
1971 }
1972 
1977 void
1979 {
1980  snd_seq_client_info_set_client(m_Info, client);
1981 }
1982 
1987 void
1988 ClientInfo::setName(QString name)
1989 {
1990  snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data());
1991 }
1992 
1997 void
1999 {
2000  snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0);
2001 }
2002 
2007 void
2009 {
2010  snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0);
2011 }
2012 
2018 void
2019 ClientInfo::setEventFilter(unsigned char *filter)
2020 {
2021  snd_seq_client_info_set_event_filter(m_Info, filter);
2022 }
2023 
2028 void
2030 {
2031  PortInfo info;
2032  freePorts();
2033  info.setClient(getClientId());
2034  info.setClientName(getName());
2035  info.setPort(-1);
2036  while (snd_seq_query_next_port(seq->getHandle(), info.m_Info) >= 0) {
2037  info.readSubscribers(seq);
2038  m_Ports.append(info);
2039  }
2040 }
2041 
2045 void
2047 {
2048  m_Ports.clear();
2049 }
2050 
2055 PortInfoList
2057 {
2058  PortInfoList lst = m_Ports; // copy
2059  return lst;
2060 }
2061 
2066 int
2068 {
2069  return snd_seq_client_info_sizeof();
2070 }
2071 
2072 #if SND_LIB_VERSION > 0x010010
2073 
2078 void
2079 ClientInfo::addFilter(int eventType)
2080 {
2081  snd_seq_client_info_event_filter_add(m_Info, eventType);
2082 }
2083 
2089 bool
2090 ClientInfo::isFiltered(int eventType)
2091 {
2092  return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0);
2093 }
2094 
2098 void
2099 ClientInfo::clearFilter()
2100 {
2101  snd_seq_client_info_event_filter_clear(m_Info);
2102 }
2103 
2108 void
2109 ClientInfo::removeFilter(int eventType)
2110 {
2111  snd_seq_client_info_event_filter_del(m_Info, eventType);
2112 }
2113 #endif
2114 
2119 {
2120  snd_seq_system_info_malloc(&m_Info);
2121 }
2122 
2128 {
2129  snd_seq_system_info_malloc(&m_Info);
2130  snd_seq_system_info_copy(m_Info, other.m_Info);
2131 }
2132 
2137 SystemInfo::SystemInfo(snd_seq_system_info_t* other)
2138 {
2139  snd_seq_system_info_malloc(&m_Info);
2140  snd_seq_system_info_copy(m_Info, other);
2141 }
2142 
2148 {
2149  snd_seq_system_info_malloc(&m_Info);
2150  snd_seq_system_info(seq->getHandle(), m_Info);
2151 }
2152 
2157 {
2158  snd_seq_system_info_free(m_Info);
2159 }
2160 
2165 SystemInfo*
2167 {
2168  return new SystemInfo(m_Info);
2169 }
2170 
2176 SystemInfo&
2178 {
2179  snd_seq_system_info_copy(m_Info, other.m_Info);
2180  return *this;
2181 }
2182 
2188 {
2189  return snd_seq_system_info_get_clients(m_Info);
2190 }
2191 
2197 {
2198  return snd_seq_system_info_get_ports(m_Info);
2199 }
2200 
2206 {
2207  return snd_seq_system_info_get_queues(m_Info);
2208 }
2209 
2215 {
2216  return snd_seq_system_info_get_channels(m_Info);
2217 }
2218 
2224 {
2225  return snd_seq_system_info_get_cur_queues(m_Info);
2226 }
2227 
2233 {
2234  return snd_seq_system_info_get_cur_clients(m_Info);
2235 }
2236 
2242 {
2243  return snd_seq_system_info_sizeof();
2244 }
2245 
2250 {
2251  snd_seq_client_pool_malloc(&m_Info);
2252 }
2253 
2259 {
2260  snd_seq_client_pool_malloc(&m_Info);
2261  snd_seq_client_pool_copy(m_Info, other.m_Info);
2262 }
2263 
2268 PoolInfo::PoolInfo(snd_seq_client_pool_t* other)
2269 {
2270  snd_seq_client_pool_malloc(&m_Info);
2271  snd_seq_client_pool_copy(m_Info, other);
2272 }
2273 
2279 {
2280  snd_seq_client_pool_malloc(&m_Info);
2281  snd_seq_get_client_pool(seq->getHandle(), m_Info);
2282 }
2283 
2288 {
2289  snd_seq_client_pool_free(m_Info);
2290 }
2291 
2296 PoolInfo*
2298 {
2299  return new PoolInfo(m_Info);
2300 }
2301 
2308 {
2309  snd_seq_client_pool_copy(m_Info, other.m_Info);
2310  return *this;
2311 }
2312 
2317 int
2319 {
2320  return snd_seq_client_pool_get_client(m_Info);
2321 }
2322 
2327 int
2329 {
2330  return snd_seq_client_pool_get_input_free(m_Info);
2331 }
2332 
2337 int
2339 {
2340  return snd_seq_client_pool_get_input_pool(m_Info);
2341 }
2342 
2347 int
2349 {
2350  return snd_seq_client_pool_get_output_free(m_Info);
2351 }
2352 
2357 int
2359 {
2360  return snd_seq_client_pool_get_output_pool(m_Info);
2361 }
2362 
2368 int
2370 {
2371  return snd_seq_client_pool_get_output_room(m_Info);
2372 }
2373 
2378 void
2380 {
2381  snd_seq_client_pool_set_input_pool(m_Info, size);
2382 }
2383 
2388 void
2390 {
2391  snd_seq_client_pool_set_output_pool(m_Info, size);
2392 }
2393 
2400 void
2402 {
2403  snd_seq_client_pool_set_output_room(m_Info, size);
2404 }
2405 
2410 int
2412 {
2413  return snd_seq_client_pool_sizeof();
2414 }
2415 
2416 #if SND_LIB_VERSION > 0x010004
2417 
2422 QString
2423 getRuntimeALSALibraryVersion()
2424 {
2425  return QString(snd_asoundlib_version());
2426 }
2427 
2433 int
2434 getRuntimeALSALibraryNumber()
2435 {
2436  QRegExp rx("(\\d+)");
2437  QString str = getRuntimeALSALibraryVersion();
2438  bool ok;
2439  int pos = 0, result = 0, j = 0;
2440  while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) {
2441  int v = rx.cap(1).toInt(&ok);
2442  if (ok) {
2443  result <<= 8;
2444  result += v;
2445  }
2446  pos += rx.matchedLength();
2447  j++;
2448  }
2449  return result;
2450 }
2451 #endif // SND_LIB_VERSION > 0x010004
2452 
2458 QString
2459 getRuntimeALSADriverVersion()
2460 {
2461  QRegExp rx(".*Driver Version.*([\\d\\.]+).*");
2462  QString s;
2463  QFile f("/proc/asound/version");
2464  if (f.open(QFile::ReadOnly)) {
2465  QTextStream str(&f);
2466  if (rx.exactMatch(str.readLine().trimmed()))
2467  s = rx.cap(1);
2468  }
2469  return s;
2470 }
2471 
2477 int
2478 getRuntimeALSADriverNumber()
2479 {
2480  QRegExp rx("(\\d+)");
2481  QString str = getRuntimeALSADriverVersion();
2482  bool ok;
2483  int pos = 0, result = 0, j = 0;
2484  while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) {
2485  int v = rx.cap(1).toInt(&ok);
2486  if (ok) {
2487  result <<= 8;
2488  result += v;
2489  }
2490  pos += rx.matchedLength();
2491  j++;
2492  }
2493  return result;
2494 }
2495 
2496 } /* namespace drumstick */