drumstick  0.5.0
alsaclient.cpp
Go to the documentation of this file.
1 /*
2  MIDI Sequencer C++ library
3  Copyright (C) 2006-2010, 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 
330 {
331 public:
332  SequencerInputThread(MidiClient *seq, int timeout)
333  : QThread(),
334  m_MidiClient(seq),
335  m_Wait(timeout),
336  m_Stopped(false),
337  m_RealTime(true) {}
338  virtual ~SequencerInputThread() {}
339  virtual void run();
340  bool stopped();
341  void stop();
342  void setRealtimePriority();
343 
344  MidiClient *m_MidiClient;
345  int m_Wait;
346  bool m_Stopped;
347  bool m_RealTime;
348  QReadWriteLock m_mutex;
349 };
350 
367  QObject(parent),
368  m_eventsEnabled(false),
369  m_BlockMode(false),
370  m_NeedRefreshClientList(true),
371  m_OpenMode(SND_SEQ_OPEN_DUPLEX),
372  m_DeviceName("default"),
373  m_SeqHandle(NULL),
374  m_Thread(NULL),
375  m_Queue(NULL),
376  m_handler(NULL)
377 { }
378 
385 {
387  detachAllPorts();
388  if (m_Queue != NULL)
389  delete m_Queue;
390  close();
391  freeClients();
392  if (m_Thread != NULL)
393  delete m_Thread;
394 }
395 
405 {
406  if (m_Thread == 0) {
407  m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
408  m_Thread->m_RealTime = enable;
409  }
410 }
411 
418 {
419  if (m_Thread == 0)
420  return true;
421  return m_Thread->m_RealTime;
422 }
423 
444 void
445 MidiClient::open( const QString deviceName,
446  const int openMode,
447  const bool blockMode)
448 {
449  CHECK_ERROR( snd_seq_open( &m_SeqHandle, deviceName.toLocal8Bit().data(),
450  openMode, blockMode ? 0 : SND_SEQ_NONBLOCK ) );
451  CHECK_WARNING( snd_seq_get_client_info( m_SeqHandle, m_Info.m_Info ) );
452  m_DeviceName = deviceName;
453  m_OpenMode = openMode;
454  m_BlockMode = blockMode;
455 }
456 
477 void
478 MidiClient::open( snd_config_t* conf,
479  const QString deviceName,
480  const int openMode,
481  const bool blockMode )
482 {
483  CHECK_ERROR( snd_seq_open_lconf( &m_SeqHandle,
484  deviceName.toLocal8Bit().data(),
485  openMode,
486  blockMode ? 0 : SND_SEQ_NONBLOCK,
487  conf ));
488  CHECK_WARNING( snd_seq_get_client_info(m_SeqHandle, m_Info.m_Info));
489  m_DeviceName = deviceName;
490  m_OpenMode = openMode;
491  m_BlockMode = blockMode;
492 }
493 
501 void
503 {
504  if (m_SeqHandle != NULL) {
506  CHECK_WARNING(snd_seq_close(m_SeqHandle));
507  m_SeqHandle = NULL;
508  }
509 }
510 
519 size_t
521 {
522  return snd_seq_get_output_buffer_size(m_SeqHandle);
523 }
524 
533 void
535 {
536  if (getOutputBufferSize() != newSize) {
537  CHECK_WARNING(snd_seq_set_output_buffer_size(m_SeqHandle, newSize));
538  }
539 }
540 
549 size_t
551 {
552  return snd_seq_get_input_buffer_size(m_SeqHandle);
553 }
554 
563 void
565 {
566  if (getInputBufferSize() != newSize) {
567  CHECK_WARNING(snd_seq_set_input_buffer_size(m_SeqHandle, newSize));
568  }
569 }
570 
580 void
582 {
583  if (m_BlockMode != newValue)
584  {
585  m_BlockMode = newValue;
586  if (m_SeqHandle != NULL)
587  {
588  CHECK_WARNING(snd_seq_nonblock(m_SeqHandle, m_BlockMode ? 0 : 1));
589  }
590  }
591 }
592 
601 int
603 {
604  return CHECK_WARNING(snd_seq_client_id(m_SeqHandle));
605 }
606 
611 snd_seq_type_t
613 {
614  return snd_seq_type(m_SeqHandle);
615 }
616 
637 void
639 {
640  do {
641  int err = 0;
642  snd_seq_event_t* evp = NULL;
643  SequencerEvent* event = NULL;
644  err = snd_seq_event_input(m_SeqHandle, &evp);
645  if ((err >= 0) && (evp != NULL)) {
646  switch (evp->type) {
647 
648  case SND_SEQ_EVENT_NOTE:
649  event = new NoteEvent(evp);
650  break;
651 
652  case SND_SEQ_EVENT_NOTEON:
653  event = new NoteOnEvent(evp);
654  break;
655 
656  case SND_SEQ_EVENT_NOTEOFF:
657  event = new NoteOffEvent(evp);
658  break;
659 
660  case SND_SEQ_EVENT_KEYPRESS:
661  event = new KeyPressEvent(evp);
662  break;
663 
664  case SND_SEQ_EVENT_CONTROLLER:
665  case SND_SEQ_EVENT_CONTROL14:
666  case SND_SEQ_EVENT_REGPARAM:
667  case SND_SEQ_EVENT_NONREGPARAM:
668  event = new ControllerEvent(evp);
669  break;
670 
671  case SND_SEQ_EVENT_PGMCHANGE:
672  event = new ProgramChangeEvent(evp);
673  break;
674 
675  case SND_SEQ_EVENT_CHANPRESS:
676  event = new ChanPressEvent(evp);
677  break;
678 
679  case SND_SEQ_EVENT_PITCHBEND:
680  event = new PitchBendEvent(evp);
681  break;
682 
683  case SND_SEQ_EVENT_SYSEX:
684  event = new SysExEvent(evp);
685  break;
686 
687  case SND_SEQ_EVENT_PORT_SUBSCRIBED:
688  case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
689  event = new SubscriptionEvent(evp);
690  break;
691 
692  case SND_SEQ_EVENT_PORT_CHANGE:
693  case SND_SEQ_EVENT_PORT_EXIT:
694  case SND_SEQ_EVENT_PORT_START:
695  event = new PortEvent(evp);
696  m_NeedRefreshClientList = true;
697  break;
698 
699  case SND_SEQ_EVENT_CLIENT_CHANGE:
700  case SND_SEQ_EVENT_CLIENT_EXIT:
701  case SND_SEQ_EVENT_CLIENT_START:
702  event = new ClientEvent(evp);
703  m_NeedRefreshClientList = true;
704  break;
705 
706  case SND_SEQ_EVENT_SONGPOS:
707  case SND_SEQ_EVENT_SONGSEL:
708  case SND_SEQ_EVENT_QFRAME:
709  case SND_SEQ_EVENT_TIMESIGN:
710  case SND_SEQ_EVENT_KEYSIGN:
711  event = new ValueEvent(evp);
712  break;
713 
714  case SND_SEQ_EVENT_SETPOS_TICK:
715  case SND_SEQ_EVENT_SETPOS_TIME:
716  case SND_SEQ_EVENT_QUEUE_SKEW:
717  event = new QueueControlEvent(evp);
718  break;
719 
720  case SND_SEQ_EVENT_TEMPO:
721  event = new TempoEvent(evp);
722  break;
723 
724  default:
725  event = new SequencerEvent(evp);
726  break;
727  }
728  // first, process the callback (if any)
729  if (m_handler != NULL) {
730  m_handler->handleSequencerEvent(event->clone());
731  } else {
732  // second, process the event listeners
733  if (m_eventsEnabled) {
734  QObjectList::Iterator it;
735  for(it=m_listeners.begin(); it!=m_listeners.end(); ++it) {
736  QObject* sub = (*it);
737  QApplication::postEvent(sub, event->clone());
738  }
739  } else {
740  // finally, process signals
741  emit eventReceived(event->clone());
742  }
743  }
744  delete event;
745  }
746  }
747  while (snd_seq_event_input_pending(m_SeqHandle, 0) > 0);
748 }
749 
753 void
755 {
756  if (m_Thread == 0) {
757  m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
758  }
759  m_Thread->start( m_Thread->m_RealTime ?
760  QThread::TimeCriticalPriority : QThread::InheritPriority );
761 }
762 
766 void
768 {
769  int counter = 0;
770  if (m_Thread != 0) {
771  if (m_Thread->isRunning()) {
772  m_Thread->stop();
773  while (!m_Thread->wait(500) && (counter < 10)) {
774  counter++;
775  }
776  if (!m_Thread->isFinished()) {
777  m_Thread->terminate();
778  }
779  }
780  delete m_Thread;
781  }
782 }
783 
787 void
789 {
790  ClientInfo cInfo;
791  freeClients();
792  cInfo.setClient(-1);
793  while (snd_seq_query_next_client(m_SeqHandle, cInfo.m_Info) >= 0) {
794  cInfo.readPorts(this);
795  m_ClientList.append(cInfo);
796  }
797  m_NeedRefreshClientList = false;
798 }
799 
803 void
805 {
806  m_ClientList.clear();
807 }
808 
813 ClientInfoList
815 {
816  if (m_NeedRefreshClientList)
817  readClients();
818  ClientInfoList lst = m_ClientList; // copy
819  return lst;
820 }
821 
826 ClientInfo&
828 {
829  snd_seq_get_client_info(m_SeqHandle, m_Info.m_Info);
830  return m_Info;
831 }
832 
840 void
842 {
843  m_Info = val;
844  snd_seq_set_client_info(m_SeqHandle, m_Info.m_Info);
845 }
846 
850 void
852 {
853  if (m_SeqHandle != NULL) {
854  snd_seq_set_client_info(m_SeqHandle, m_Info.m_Info);
855  }
856 }
857 
862 QString
864 {
865  return m_Info.getName();
866 }
867 
873 QString
874 MidiClient::getClientName(const int clientId)
875 {
876  ClientInfoList::Iterator it;
877  if (m_NeedRefreshClientList)
878  readClients();
879  for (it = m_ClientList.begin(); it != m_ClientList.end(); ++it) {
880  if ((*it).getClientId() == clientId) {
881  return (*it).getName();
882  }
883  }
884  return QString();
885 }
886 
891 void
892 MidiClient::setClientName(QString const& newName)
893 {
894  if (newName != m_Info.getName()) {
895  m_Info.setName(newName);
896  applyClientInfo();
897  }
898 }
899 
904 MidiPortList
906 {
907  return m_Ports;
908 }
909 
914 MidiPort*
916 {
917  MidiPort* port = new MidiPort(this);
918  port->attach(this);
919  return port;
920 }
921 
926 void
928 {
929  if (m_SeqHandle != NULL) {
930  CHECK_ERROR(snd_seq_create_port(m_SeqHandle, port->m_Info.m_Info));
931  m_Ports.push_back(port);
932  }
933 }
934 
939 void
941 {
942  if (m_SeqHandle != NULL) {
943  if(port->getPortInfo()->getClient() == getClientId())
944  {
945  return;
946  }
947  CHECK_ERROR(snd_seq_delete_port(m_SeqHandle, port->getPortInfo()->getPort()));
948  port->setMidiClient(NULL);
949 
950  MidiPortList::iterator it;
951  for(it = m_Ports.begin(); it != m_Ports.end(); ++it)
952  {
953  if ((*it)->getPortInfo()->getPort() == port->getPortInfo()->getPort())
954  {
955  m_Ports.erase(it);
956  break;
957  }
958  }
959  }
960 }
961 
966 {
967  if (m_SeqHandle != NULL) {
968  MidiPortList::iterator it;
969  for (it = m_Ports.begin(); it != m_Ports.end(); ++it) {
970  CHECK_ERROR(snd_seq_delete_port(m_SeqHandle, (*it)->getPortInfo()->getPort()));
971  (*it)->setMidiClient(NULL);
972  m_Ports.erase(it);
973  }
974  }
975 }
976 
981 void
983 {
984  snd_seq_set_client_event_filter(m_SeqHandle, evtype);
985 }
986 
992 bool
994 {
995  return m_Info.getBroadcastFilter();
996 }
997 
1003 void
1005 {
1006  m_Info.setBroadcastFilter(newValue);
1007  applyClientInfo();
1008 }
1009 
1015 bool
1017 {
1018  return m_Info.getErrorBounce();
1019 }
1020 
1026 void
1028 {
1029  m_Info.setErrorBounce(newValue);
1030  applyClientInfo();
1031 }
1032 
1044 void
1045 MidiClient::output(SequencerEvent* ev, bool async, int timeout)
1046 {
1047  int npfds;
1048  pollfd* pfds;
1049  if (async) {
1050  CHECK_WARNING(snd_seq_event_output(m_SeqHandle, ev->getHandle()));
1051  } else {
1052  npfds = snd_seq_poll_descriptors_count(m_SeqHandle, POLLOUT);
1053  pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
1054  snd_seq_poll_descriptors(m_SeqHandle, pfds, npfds, POLLOUT);
1055  while (snd_seq_event_output(m_SeqHandle, ev->getHandle()) < 0)
1056  {
1057  poll(pfds, npfds, timeout);
1058  }
1059  }
1060 }
1061 
1073 void MidiClient::outputDirect(SequencerEvent* ev, bool async, int timeout)
1074 {
1075  int npfds;
1076  pollfd* pfds;
1077  if (async) {
1078  CHECK_WARNING(snd_seq_event_output_direct(m_SeqHandle, ev->getHandle()));
1079  } else {
1080  npfds = snd_seq_poll_descriptors_count(m_SeqHandle, POLLOUT);
1081  pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
1082  snd_seq_poll_descriptors(m_SeqHandle, pfds, npfds, POLLOUT);
1083  while (snd_seq_event_output_direct(m_SeqHandle, ev->getHandle()) < 0)
1084  {
1085  poll(pfds, npfds, timeout);
1086  }
1087  }
1088 }
1089 
1098 void
1100 {
1101  CHECK_WARNING(snd_seq_event_output_buffer(m_SeqHandle, ev->getHandle()));
1102 }
1103 
1115 void MidiClient::drainOutput(bool async, int timeout)
1116 {
1117  int npfds;
1118  pollfd* pfds;
1119  if (async) {
1120  CHECK_WARNING(snd_seq_drain_output(m_SeqHandle));
1121  } else {
1122  npfds = snd_seq_poll_descriptors_count(m_SeqHandle, POLLOUT);
1123  pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
1124  snd_seq_poll_descriptors(m_SeqHandle, pfds, npfds, POLLOUT);
1125  while (snd_seq_drain_output(m_SeqHandle) < 0)
1126  {
1127  poll(pfds, npfds, timeout);
1128  }
1129  }
1130 }
1131 
1137 void
1139 {
1140  snd_seq_sync_output_queue(m_SeqHandle);
1141 }
1142 
1148 MidiQueue*
1150 {
1151  if (m_Queue == NULL) {
1152  createQueue();
1153  }
1154  return m_Queue;
1155 }
1156 
1161 MidiQueue*
1163 {
1164  if (m_Queue != NULL) {
1165  delete m_Queue;
1166  }
1167  m_Queue = new MidiQueue(this, this);
1168  return m_Queue;
1169 }
1170 
1177 MidiQueue*
1178 MidiClient::createQueue(QString const& queueName )
1179 {
1180  if (m_Queue != NULL) {
1181  delete m_Queue;
1182  }
1183  m_Queue = new MidiQueue(this, queueName, this);
1184  return m_Queue;
1185 }
1186 
1194 MidiQueue*
1196 {
1197  if (m_Queue != NULL) {
1198  delete m_Queue;
1199  }
1200  m_Queue = new MidiQueue(this, queue_id, this);
1201  return m_Queue;
1202 }
1203 
1211 MidiQueue*
1212 MidiClient::useQueue(const QString& name)
1213 {
1214  if (m_Queue != NULL) {
1215  delete m_Queue;
1216  }
1217  int queue_id = getQueueId(name);
1218  if ( queue_id >= 0) {
1219  m_Queue = new MidiQueue(this, queue_id, this);
1220  }
1221  return m_Queue;
1222 }
1223 
1230 MidiQueue*
1232 {
1233  if (m_Queue != NULL) {
1234  delete m_Queue;
1235  }
1236  queue->setParent(this);
1237  m_Queue = queue;
1238  return m_Queue;
1239 }
1240 
1245 QList<int>
1247 {
1248  int q, err, max;
1249  QList<int> queues;
1250  snd_seq_queue_info_t* qinfo;
1251  snd_seq_queue_info_alloca(&qinfo);
1252  max = getSystemInfo().getMaxQueues();
1253  for ( q = 0; q < max; ++q ) {
1254  err = snd_seq_get_queue_info(m_SeqHandle, q, qinfo);
1255  if (err == 0) {
1256  queues.append(q);
1257  }
1258  }
1259  return queues;
1260 }
1261 
1269 PortInfoList
1270 MidiClient::filterPorts(unsigned int filter)
1271 {
1272  PortInfoList result;
1273  ClientInfoList::ConstIterator itc;
1274  PortInfoList::ConstIterator itp;
1275 
1276  if (m_NeedRefreshClientList)
1277  readClients();
1278 
1279  for (itc = m_ClientList.constBegin(); itc != m_ClientList.constEnd(); ++itc) {
1280  ClientInfo ci = (*itc);
1281  if ((ci.getClientId() == SND_SEQ_CLIENT_SYSTEM) ||
1282  (ci.getClientId() == m_Info.getClientId()))
1283  continue;
1284  PortInfoList lstPorts = ci.getPorts();
1285  for(itp = lstPorts.constBegin(); itp != lstPorts.constEnd(); ++itp) {
1286  PortInfo pi = (*itp);
1287  unsigned int cap = pi.getCapability();
1288  if ( ((filter & cap) != 0) &&
1289  ((SND_SEQ_PORT_CAP_NO_EXPORT & cap) == 0) ) {
1290  result.append(pi);
1291  }
1292  }
1293  }
1294  return result;
1295 }
1296 
1300 void
1302 {
1303  m_InputsAvail.clear();
1304  m_OutputsAvail.clear();
1305  m_InputsAvail = filterPorts( SND_SEQ_PORT_CAP_READ |
1306  SND_SEQ_PORT_CAP_SUBS_READ );
1307  m_OutputsAvail = filterPorts( SND_SEQ_PORT_CAP_WRITE |
1308  SND_SEQ_PORT_CAP_SUBS_WRITE );
1309 }
1310 
1315 PortInfoList
1317 {
1318  m_NeedRefreshClientList = true;
1320  return m_InputsAvail;
1321 }
1322 
1327 PortInfoList
1329 {
1330  m_NeedRefreshClientList = true;
1332  return m_OutputsAvail;
1333 }
1334 
1341 void
1343 {
1344  m_listeners.append(listener);
1345 }
1346 
1352 void
1354 {
1355  m_listeners.removeAll(listener);
1356 }
1357 
1364 void
1366 {
1367  if (bEnabled != m_eventsEnabled) {
1368  m_eventsEnabled = bEnabled;
1369  }
1370 }
1371 
1376 SystemInfo&
1378 {
1379  snd_seq_system_info(m_SeqHandle, m_sysInfo.m_Info);
1380  return m_sysInfo;
1381 }
1382 
1387 PoolInfo&
1389 {
1390  snd_seq_get_client_pool(m_SeqHandle, m_poolInfo.m_Info);
1391  return m_poolInfo;
1392 }
1393 
1398 void
1400 {
1401  m_poolInfo = info;
1402  CHECK_WARNING(snd_seq_set_client_pool(m_SeqHandle, m_poolInfo.m_Info));
1403 }
1404 
1409 void
1411 {
1412  CHECK_WARNING(snd_seq_reset_pool_input(m_SeqHandle));
1413 }
1414 
1419 void
1421 {
1422  CHECK_WARNING(snd_seq_reset_pool_output(m_SeqHandle));
1423 }
1424 
1429 void
1431 {
1432  CHECK_WARNING(snd_seq_set_client_pool_input(m_SeqHandle, size));
1433 }
1434 
1439 void
1441 {
1442  CHECK_WARNING(snd_seq_set_client_pool_output(m_SeqHandle, size));
1443 }
1444 
1449 void
1451 {
1452  CHECK_WARNING(snd_seq_set_client_pool_output_room(m_SeqHandle, size));
1453 }
1454 
1459 void
1461 {
1462  CHECK_WARNING(snd_seq_drop_input(m_SeqHandle));
1463 }
1464 
1469 void
1471 {
1472  CHECK_WARNING(snd_seq_drop_input_buffer(m_SeqHandle));
1473 }
1474 
1482 void
1484 {
1485  CHECK_WARNING(snd_seq_drop_output(m_SeqHandle));
1486 }
1487 
1495 void
1497 {
1498  CHECK_WARNING(snd_seq_drop_output_buffer(m_SeqHandle));
1499 }
1500 
1507 void
1509 {
1510  CHECK_WARNING(snd_seq_remove_events(m_SeqHandle, spec->m_Info));
1511 }
1512 
1519 {
1520  snd_seq_event_t* ev;
1521  if (CHECK_WARNING(snd_seq_extract_output(m_SeqHandle, &ev) == 0)) {
1522  return new SequencerEvent(ev);
1523  }
1524  return NULL;
1525 }
1526 
1532 int
1534 {
1535  return snd_seq_event_output_pending(m_SeqHandle);
1536 }
1537 
1551 int
1553 {
1554  return snd_seq_event_input_pending(m_SeqHandle, fetch ? 1 : 0);
1555 }
1556 
1563 int
1564 MidiClient::getQueueId(const QString& name)
1565 {
1566  return snd_seq_query_named_queue(m_SeqHandle, name.toLocal8Bit().data());
1567 }
1568 
1574 int
1576 {
1577  return snd_seq_poll_descriptors_count(m_SeqHandle, events);
1578 }
1579 
1593 int
1594 MidiClient::pollDescriptors( struct pollfd *pfds, unsigned int space,
1595  short events )
1596 {
1597  return snd_seq_poll_descriptors(m_SeqHandle, pfds, space, events);
1598 }
1599 
1606 unsigned short
1607 MidiClient::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds)
1608 {
1609  unsigned short revents;
1610  CHECK_WARNING( snd_seq_poll_descriptors_revents( m_SeqHandle,
1611  pfds, nfds,
1612  &revents ));
1613  return revents;
1614 }
1615 
1620 const char *
1622 {
1623  return snd_seq_name(m_SeqHandle);
1624 }
1625 
1630 void
1632 {
1633  CHECK_WARNING(snd_seq_set_client_name(m_SeqHandle, name));
1634 }
1635 
1643 int
1645  unsigned int caps,
1646  unsigned int type )
1647 {
1648  return CHECK_WARNING( snd_seq_create_simple_port( m_SeqHandle,
1649  name, caps, type ));
1650 }
1651 
1656 void
1658 {
1659  CHECK_WARNING( snd_seq_delete_simple_port( m_SeqHandle, port ));
1660 }
1661 
1668 void
1669 MidiClient::connectFrom(int myport, int client, int port)
1670 {
1671  CHECK_WARNING( snd_seq_connect_from(m_SeqHandle, myport, client, port ));
1672 }
1673 
1680 void
1681 MidiClient::connectTo(int myport, int client, int port)
1682 {
1683  CHECK_WARNING( snd_seq_connect_to(m_SeqHandle, myport, client, port ));
1684 }
1685 
1692 void
1693 MidiClient::disconnectFrom(int myport, int client, int port)
1694 {
1695  CHECK_WARNING( snd_seq_disconnect_from(m_SeqHandle, myport, client, port ));
1696 }
1697 
1704 void
1705 MidiClient::disconnectTo(int myport, int client, int port)
1706 {
1707  CHECK_WARNING( snd_seq_disconnect_to(m_SeqHandle, myport, client, port ));
1708 }
1709 
1721 bool
1722 MidiClient::parseAddress( const QString& straddr, snd_seq_addr& addr )
1723 {
1724  bool ok(false);
1725  QString testClient, testPort;
1726  ClientInfoList::ConstIterator cit;
1727  int pos = straddr.indexOf(':');
1728  if (pos > -1) {
1729  testClient = straddr.left(pos);
1730  testPort = straddr.mid(pos+1);
1731  } else {
1732  testClient = straddr;
1733  testPort = '0';
1734  }
1735  addr.client = testClient.toInt(&ok);
1736  if (ok)
1737  addr.port = testPort.toInt(&ok);
1738  if (!ok) {
1739  if (m_NeedRefreshClientList)
1740  readClients();
1741  for ( cit = m_ClientList.constBegin();
1742  cit != m_ClientList.constEnd(); ++cit ) {
1743  ClientInfo ci = *cit;
1744  if (testClient.compare(ci.getName(), Qt::CaseInsensitive) == 0) {
1745  addr.client = ci.getClientId();
1746  addr.port = testPort.toInt(&ok);
1747  return ok;
1748  }
1749  }
1750  }
1751  return ok;
1752 }
1753 
1758 bool
1760 {
1761  QReadLocker locker(&m_mutex);
1762  return m_Stopped;
1763 }
1764 
1768 void
1770 {
1771  QWriteLocker locker(&m_mutex);
1772  m_Stopped = true;
1773 }
1774 
1775 #if defined(RTKIT_SUPPORT)
1776 static pid_t _gettid(void) {
1777  return (pid_t) ::syscall(SYS_gettid);
1778 }
1779 #endif
1780 
1781 void
1782 MidiClient::SequencerInputThread::setRealtimePriority()
1783 {
1784  struct sched_param p;
1785  int rt, policy = SCHED_RR | SCHED_RESET_ON_FORK;
1786  quint32 priority = 6;
1787 #if defined(RTKIT_SUPPORT)
1788  bool ok;
1789  quint32 max_prio;
1790  quint64 thread;
1791  struct rlimit old_limit, new_limit;
1792  long long max_rttime;
1793 #endif
1794 
1795  ::memset(&p, 0, sizeof(p));
1796  p.sched_priority = priority;
1797  rt = ::pthread_setschedparam(::pthread_self(), policy, &p);
1798  if (rt != 0) {
1799 #if defined(RTKIT_SUPPORT)
1800  const QString rtkit_service =
1801  QLatin1String("org.freedesktop.RealtimeKit1");
1802  const QString rtkit_path =
1803  QLatin1String("/org/freedesktop/RealtimeKit1");
1804  const QString rtkit_iface = rtkit_service;
1805  thread = _gettid();
1806  QDBusConnection bus = QDBusConnection::systemBus();
1807  QDBusInterface realtimeKit(rtkit_service, rtkit_path, rtkit_iface, bus);
1808  QVariant maxRTPrio = realtimeKit.property("MaxRealtimePriority");
1809  max_prio = maxRTPrio.toUInt(&ok);
1810  if (!ok) {
1811  qWarning() << "invalid property RealtimeKit.MaxRealtimePriority";
1812  return;
1813  }
1814  if (priority > max_prio)
1815  priority = max_prio;
1816  QVariant maxRTNSec = realtimeKit.property("RTTimeNSecMax");
1817  max_rttime = maxRTNSec.toLongLong(&ok);
1818  if (!ok || max_rttime < 0) {
1819  qWarning() << "invalid property RealtimeKit.RTTimeNSecMax";
1820  return;
1821  }
1822  new_limit.rlim_cur = new_limit.rlim_max = max_rttime;
1823  rt = ::getrlimit(RLIMIT_RTTIME, &old_limit);
1824  if (rt < 0) {
1825  qWarning() << "getrlimit() failed. err=" << rt << ::strerror(rt);
1826  return;
1827  }
1828  rt = ::setrlimit(RLIMIT_RTTIME, &new_limit);
1829  if ( rt < 0) {
1830  qWarning() << "setrlimit() failed, err=" << rt << ::strerror(rt);
1831  return;
1832  }
1833  QDBusMessage reply = realtimeKit.call("MakeThreadRealtime", thread, priority);
1834  if (reply.type() == QDBusMessage::ErrorMessage )
1835  qWarning() << "error returned by RealtimeKit.MakeThreadRealtime:"
1836  << reply.errorMessage();
1837 #else
1838  qWarning() << "pthread_setschedparam() failed, err="
1839  << rt << ::strerror(rt);
1840 #endif
1841  }
1842 }
1843 
1847 void
1849 {
1850  unsigned long npfd;
1851  pollfd* pfd;
1852  if ( priority() == TimeCriticalPriority )
1853  setRealtimePriority();
1854 
1855  if (m_MidiClient != NULL) {
1856  npfd = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLIN);
1857  pfd = (pollfd *) alloca(npfd * sizeof(pollfd));
1858  try
1859  {
1860  snd_seq_poll_descriptors(m_MidiClient->getHandle(), pfd, npfd, POLLIN);
1861  while (!stopped() && (m_MidiClient != NULL))
1862  {
1863  int rt = poll(pfd, npfd, m_Wait);
1864  if (rt > 0) {
1865  m_MidiClient->doEvents();
1866  }
1867  }
1868  }
1869  catch (...)
1870  {
1871  qWarning() << "exception in input thread";
1872  }
1873  }
1874 }
1875 
1880 {
1881  snd_seq_client_info_malloc(&m_Info);
1882 }
1883 
1889 {
1890  snd_seq_client_info_malloc(&m_Info);
1891  snd_seq_client_info_copy(m_Info, other.m_Info);
1892  m_Ports = other.m_Ports;
1893 }
1894 
1899 ClientInfo::ClientInfo(snd_seq_client_info_t* other)
1900 {
1901  snd_seq_client_info_malloc(&m_Info);
1902  snd_seq_client_info_copy(m_Info, other);
1903 }
1904 
1911 {
1912  snd_seq_client_info_malloc(&m_Info);
1913  snd_seq_get_any_client_info(seq->getHandle(), id, m_Info);
1914 }
1915 
1920 {
1921  freePorts();
1922  snd_seq_client_info_free(m_Info);
1923 }
1924 
1929 ClientInfo*
1931 {
1932  return new ClientInfo(m_Info);
1933 }
1934 
1940 ClientInfo&
1942 {
1943  snd_seq_client_info_copy(m_Info, other.m_Info);
1944  m_Ports = other.m_Ports;
1945  return *this;
1946 }
1947 
1952 int
1954 {
1955  return snd_seq_client_info_get_client(m_Info);
1956 }
1957 
1962 snd_seq_client_type_t
1964 {
1965  return snd_seq_client_info_get_type(m_Info);
1966 }
1967 
1972 QString
1974 {
1975  return QString(snd_seq_client_info_get_name(m_Info));
1976 }
1977 
1982 bool
1984 {
1985  return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0);
1986 }
1987 
1992 bool
1994 {
1995  return (snd_seq_client_info_get_error_bounce(m_Info) != 0);
1996 }
1997 
2003 const unsigned char*
2005 {
2006  return snd_seq_client_info_get_event_filter(m_Info);
2007 }
2008 
2013 int
2015 {
2016  return snd_seq_client_info_get_num_ports(m_Info);
2017 }
2018 
2023 int
2025 {
2026  return snd_seq_client_info_get_event_lost(m_Info);
2027 }
2028 
2033 void
2035 {
2036  snd_seq_client_info_set_client(m_Info, client);
2037 }
2038 
2043 void
2044 ClientInfo::setName(QString name)
2045 {
2046  snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data());
2047 }
2048 
2053 void
2055 {
2056  snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0);
2057 }
2058 
2063 void
2065 {
2066  snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0);
2067 }
2068 
2074 void
2075 ClientInfo::setEventFilter(unsigned char *filter)
2076 {
2077  snd_seq_client_info_set_event_filter(m_Info, filter);
2078 }
2079 
2084 void
2086 {
2087  PortInfo info;
2088  freePorts();
2089  info.setClient(getClientId());
2090  info.setClientName(getName());
2091  info.setPort(-1);
2092  while (snd_seq_query_next_port(seq->getHandle(), info.m_Info) >= 0) {
2093  info.readSubscribers(seq);
2094  m_Ports.append(info);
2095  }
2096 }
2097 
2101 void
2103 {
2104  m_Ports.clear();
2105 }
2106 
2111 PortInfoList
2113 {
2114  PortInfoList lst = m_Ports; // copy
2115  return lst;
2116 }
2117 
2122 int
2124 {
2125  return snd_seq_client_info_sizeof();
2126 }
2127 
2128 #if SND_LIB_VERSION > 0x010010
2129 
2134 void
2135 ClientInfo::addFilter(int eventType)
2136 {
2137  snd_seq_client_info_event_filter_add(m_Info, eventType);
2138 }
2139 
2145 bool
2146 ClientInfo::isFiltered(int eventType)
2147 {
2148  return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0);
2149 }
2150 
2154 void
2155 ClientInfo::clearFilter()
2156 {
2157  snd_seq_client_info_event_filter_clear(m_Info);
2158 }
2159 
2164 void
2165 ClientInfo::removeFilter(int eventType)
2166 {
2167  snd_seq_client_info_event_filter_del(m_Info, eventType);
2168 }
2169 #endif
2170 
2175 {
2176  snd_seq_system_info_malloc(&m_Info);
2177 }
2178 
2184 {
2185  snd_seq_system_info_malloc(&m_Info);
2186  snd_seq_system_info_copy(m_Info, other.m_Info);
2187 }
2188 
2193 SystemInfo::SystemInfo(snd_seq_system_info_t* other)
2194 {
2195  snd_seq_system_info_malloc(&m_Info);
2196  snd_seq_system_info_copy(m_Info, other);
2197 }
2198 
2204 {
2205  snd_seq_system_info_malloc(&m_Info);
2206  snd_seq_system_info(seq->getHandle(), m_Info);
2207 }
2208 
2213 {
2214  snd_seq_system_info_free(m_Info);
2215 }
2216 
2221 SystemInfo*
2223 {
2224  return new SystemInfo(m_Info);
2225 }
2226 
2232 SystemInfo&
2234 {
2235  snd_seq_system_info_copy(m_Info, other.m_Info);
2236  return *this;
2237 }
2238 
2244 {
2245  return snd_seq_system_info_get_clients(m_Info);
2246 }
2247 
2253 {
2254  return snd_seq_system_info_get_ports(m_Info);
2255 }
2256 
2262 {
2263  return snd_seq_system_info_get_queues(m_Info);
2264 }
2265 
2271 {
2272  return snd_seq_system_info_get_channels(m_Info);
2273 }
2274 
2280 {
2281  return snd_seq_system_info_get_cur_queues(m_Info);
2282 }
2283 
2289 {
2290  return snd_seq_system_info_get_cur_clients(m_Info);
2291 }
2292 
2298 {
2299  return snd_seq_system_info_sizeof();
2300 }
2301 
2306 {
2307  snd_seq_client_pool_malloc(&m_Info);
2308 }
2309 
2315 {
2316  snd_seq_client_pool_malloc(&m_Info);
2317  snd_seq_client_pool_copy(m_Info, other.m_Info);
2318 }
2319 
2324 PoolInfo::PoolInfo(snd_seq_client_pool_t* other)
2325 {
2326  snd_seq_client_pool_malloc(&m_Info);
2327  snd_seq_client_pool_copy(m_Info, other);
2328 }
2329 
2335 {
2336  snd_seq_client_pool_malloc(&m_Info);
2337  snd_seq_get_client_pool(seq->getHandle(), m_Info);
2338 }
2339 
2344 {
2345  snd_seq_client_pool_free(m_Info);
2346 }
2347 
2352 PoolInfo*
2354 {
2355  return new PoolInfo(m_Info);
2356 }
2357 
2364 {
2365  snd_seq_client_pool_copy(m_Info, other.m_Info);
2366  return *this;
2367 }
2368 
2373 int
2375 {
2376  return snd_seq_client_pool_get_client(m_Info);
2377 }
2378 
2383 int
2385 {
2386  return snd_seq_client_pool_get_input_free(m_Info);
2387 }
2388 
2393 int
2395 {
2396  return snd_seq_client_pool_get_input_pool(m_Info);
2397 }
2398 
2403 int
2405 {
2406  return snd_seq_client_pool_get_output_free(m_Info);
2407 }
2408 
2413 int
2415 {
2416  return snd_seq_client_pool_get_output_pool(m_Info);
2417 }
2418 
2424 int
2426 {
2427  return snd_seq_client_pool_get_output_room(m_Info);
2428 }
2429 
2434 void
2436 {
2437  snd_seq_client_pool_set_input_pool(m_Info, size);
2438 }
2439 
2444 void
2446 {
2447  snd_seq_client_pool_set_output_pool(m_Info, size);
2448 }
2449 
2456 void
2458 {
2459  snd_seq_client_pool_set_output_room(m_Info, size);
2460 }
2461 
2466 int
2468 {
2469  return snd_seq_client_pool_sizeof();
2470 }
2471 
2472 #if SND_LIB_VERSION > 0x010004
2473 
2478 QString
2479 getRuntimeALSALibraryVersion()
2480 {
2481  return QString(snd_asoundlib_version());
2482 }
2483 
2489 int
2490 getRuntimeALSALibraryNumber()
2491 {
2492  QRegExp rx("(\\d+)");
2493  QString str = getRuntimeALSALibraryVersion();
2494  bool ok;
2495  int pos = 0, result = 0, j = 0;
2496  while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) {
2497  int v = rx.cap(1).toInt(&ok);
2498  if (ok) {
2499  result <<= 8;
2500  result += v;
2501  }
2502  pos += rx.matchedLength();
2503  j++;
2504  }
2505  return result;
2506 }
2507 #endif // SND_LIB_VERSION > 0x010004
2508 
2514 QString
2515 getRuntimeALSADriverVersion()
2516 {
2517  QRegExp rx(".*Driver Version ([\\d\\.]+).*");
2518  QString s;
2519  QFile f("/proc/asound/version");
2520  if (f.open(QFile::ReadOnly)) {
2521  QTextStream str(&f);
2522  if (rx.exactMatch(str.readLine().trimmed()))
2523  s = rx.cap(1);
2524  }
2525  return s;
2526 }
2527 
2533 int
2534 getRuntimeALSADriverNumber()
2535 {
2536  QRegExp rx("(\\d+)");
2537  QString str = getRuntimeALSADriverVersion();
2538  bool ok;
2539  int pos = 0, result = 0, j = 0;
2540  while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) {
2541  int v = rx.cap(1).toInt(&ok);
2542  if (ok) {
2543  result <<= 8;
2544  result += v;
2545  }
2546  pos += rx.matchedLength();
2547  j++;
2548  }
2549  return result;
2550 }
2551 
2552 } /* namespace drumstick */