drumstick
1.0.2
|
00001 /* 00002 MIDI Sequencer C++ library 00003 Copyright (C) 2006-2015, Pedro Lopez-Cabanillas <plcl@users.sf.net> 00004 00005 This library is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or 00008 (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License along 00016 with this program; if not, write to the Free Software Foundation, Inc., 00017 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "alsaclient.h" 00021 #include "alsaqueue.h" 00022 #include "alsaevent.h" 00023 #include <QFile> 00024 #include <QRegExp> 00025 #include <QThread> 00026 #include <QReadLocker> 00027 #include <QWriteLocker> 00028 #if defined(RTKIT_SUPPORT) 00029 #include <QDBusConnection> 00030 #include <QDBusInterface> 00031 #include <sys/types.h> 00032 #include <sys/syscall.h> 00033 #include <sys/resource.h> 00034 #endif 00035 #include <pthread.h> 00036 00037 #ifndef RLIMIT_RTTIME 00038 #define RLIMIT_RTTIME 15 00039 #endif 00040 00041 #ifndef SCHED_RESET_ON_FORK 00042 #define SCHED_RESET_ON_FORK 0x40000000 00043 #endif 00044 00045 #ifndef DEFAULT_INPUT_TIMEOUT 00046 #define DEFAULT_INPUT_TIMEOUT 500 00047 #endif 00048 00066 namespace drumstick { 00067 00329 class MidiClient::SequencerInputThread: public QThread 00330 { 00331 public: 00332 SequencerInputThread(MidiClient *seq, int timeout) 00333 : QThread(), 00334 m_MidiClient(seq), 00335 m_Wait(timeout), 00336 m_Stopped(false), 00337 m_RealTime(true) {} 00338 virtual ~SequencerInputThread() {} 00339 virtual void run(); 00340 bool stopped(); 00341 void stop(); 00342 void setRealtimePriority(); 00343 00344 MidiClient *m_MidiClient; 00345 int m_Wait; 00346 bool m_Stopped; 00347 bool m_RealTime; 00348 QReadWriteLock m_mutex; 00349 }; 00350 00351 class MidiClient::MidiClientPrivate 00352 { 00353 public: 00354 MidiClientPrivate() : 00355 m_eventsEnabled(false), 00356 m_BlockMode(false), 00357 m_NeedRefreshClientList(true), 00358 m_OpenMode(SND_SEQ_OPEN_DUPLEX), 00359 m_DeviceName("default"), 00360 m_SeqHandle(0), 00361 m_Thread(0), 00362 m_Queue(0), 00363 m_handler(0) 00364 { } 00365 00366 bool m_eventsEnabled; 00367 bool m_BlockMode; 00368 bool m_NeedRefreshClientList; 00369 int m_OpenMode; 00370 QString m_DeviceName; 00371 snd_seq_t* m_SeqHandle; 00372 QPointer<SequencerInputThread> m_Thread; 00373 QPointer<MidiQueue> m_Queue; 00374 SequencerEventHandler* m_handler; 00375 00376 ClientInfo m_Info; 00377 ClientInfoList m_ClientList; 00378 MidiPortList m_Ports; 00379 PortInfoList m_OutputsAvail; 00380 PortInfoList m_InputsAvail; 00381 QObjectList m_listeners; 00382 SystemInfo m_sysInfo; 00383 PoolInfo m_poolInfo; 00384 }; 00385 00401 MidiClient::MidiClient( QObject* parent ) : 00402 QObject(parent), 00403 d(new MidiClientPrivate) 00404 { } 00405 00411 MidiClient::~MidiClient() 00412 { 00413 stopSequencerInput(); 00414 detachAllPorts(); 00415 if (d->m_Queue != 0) 00416 delete d->m_Queue; 00417 close(); 00418 freeClients(); 00419 if (d->m_Thread != 0) 00420 delete d->m_Thread; 00421 delete d; 00422 } 00423 00424 00428 snd_seq_t* 00429 MidiClient::getHandle() 00430 { 00431 return d->m_SeqHandle; 00432 } 00433 00437 bool MidiClient::isOpened() 00438 { 00439 return (d->m_SeqHandle != NULL); 00440 } 00441 00445 QString MidiClient::getDeviceName() 00446 { 00447 return d->m_DeviceName; 00448 } 00449 00453 int MidiClient::getOpenMode() 00454 { 00455 return d->m_OpenMode; 00456 } 00457 00461 bool MidiClient::getBlockMode() 00462 { 00463 return d->m_BlockMode; 00464 } 00465 00469 bool MidiClient::getEventsEnabled() const 00470 { 00471 return d->m_eventsEnabled; 00472 } 00473 00477 void MidiClient::setHandler(SequencerEventHandler* handler) 00478 { 00479 d->m_handler = handler; 00480 } 00481 00482 00491 void MidiClient::setRealTimeInput(bool enable) 00492 { 00493 if (d->m_Thread == 0) { 00494 d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT); 00495 d->m_Thread->m_RealTime = enable; 00496 } 00497 } 00498 00504 bool MidiClient::realTimeInputEnabled() 00505 { 00506 if (d->m_Thread == 0) 00507 return true; 00508 return d->m_Thread->m_RealTime; 00509 } 00510 00531 void 00532 MidiClient::open( const QString deviceName, 00533 const int openMode, 00534 const bool blockMode) 00535 { 00536 CHECK_ERROR( snd_seq_open( &d->m_SeqHandle, deviceName.toLocal8Bit().data(), 00537 openMode, blockMode ? 0 : SND_SEQ_NONBLOCK ) ); 00538 CHECK_WARNING( snd_seq_get_client_info( d->m_SeqHandle, d->m_Info.m_Info ) ); 00539 d->m_DeviceName = deviceName; 00540 d->m_OpenMode = openMode; 00541 d->m_BlockMode = blockMode; 00542 } 00543 00564 void 00565 MidiClient::open( snd_config_t* conf, 00566 const QString deviceName, 00567 const int openMode, 00568 const bool blockMode ) 00569 { 00570 CHECK_ERROR( snd_seq_open_lconf( &d->m_SeqHandle, 00571 deviceName.toLocal8Bit().data(), 00572 openMode, 00573 blockMode ? 0 : SND_SEQ_NONBLOCK, 00574 conf )); 00575 CHECK_WARNING( snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info)); 00576 d->m_DeviceName = deviceName; 00577 d->m_OpenMode = openMode; 00578 d->m_BlockMode = blockMode; 00579 } 00580 00588 void 00589 MidiClient::close() 00590 { 00591 if (d->m_SeqHandle != NULL) { 00592 stopSequencerInput(); 00593 CHECK_WARNING(snd_seq_close(d->m_SeqHandle)); 00594 d->m_SeqHandle = NULL; 00595 } 00596 } 00597 00606 size_t 00607 MidiClient::getOutputBufferSize() 00608 { 00609 return snd_seq_get_output_buffer_size(d->m_SeqHandle); 00610 } 00611 00620 void 00621 MidiClient::setOutputBufferSize(size_t newSize) 00622 { 00623 if (getOutputBufferSize() != newSize) { 00624 CHECK_WARNING(snd_seq_set_output_buffer_size(d->m_SeqHandle, newSize)); 00625 } 00626 } 00627 00636 size_t 00637 MidiClient::getInputBufferSize() 00638 { 00639 return snd_seq_get_input_buffer_size(d->m_SeqHandle); 00640 } 00641 00650 void 00651 MidiClient::setInputBufferSize(size_t newSize) 00652 { 00653 if (getInputBufferSize() != newSize) { 00654 CHECK_WARNING(snd_seq_set_input_buffer_size(d->m_SeqHandle, newSize)); 00655 } 00656 } 00657 00667 void 00668 MidiClient::setBlockMode(bool newValue) 00669 { 00670 if (d->m_BlockMode != newValue) 00671 { 00672 d->m_BlockMode = newValue; 00673 if (d->m_SeqHandle != NULL) 00674 { 00675 CHECK_WARNING(snd_seq_nonblock(d->m_SeqHandle, d->m_BlockMode ? 0 : 1)); 00676 } 00677 } 00678 } 00679 00688 int 00689 MidiClient::getClientId() 00690 { 00691 return CHECK_WARNING(snd_seq_client_id(d->m_SeqHandle)); 00692 } 00693 00698 snd_seq_type_t 00699 MidiClient::getSequencerType() 00700 { 00701 return snd_seq_type(d->m_SeqHandle); 00702 } 00703 00724 void 00725 MidiClient::doEvents() 00726 { 00727 do { 00728 int err = 0; 00729 snd_seq_event_t* evp = NULL; 00730 SequencerEvent* event = NULL; 00731 err = snd_seq_event_input(d->m_SeqHandle, &evp); 00732 if ((err >= 0) && (evp != NULL)) { 00733 switch (evp->type) { 00734 00735 case SND_SEQ_EVENT_NOTE: 00736 event = new NoteEvent(evp); 00737 break; 00738 00739 case SND_SEQ_EVENT_NOTEON: 00740 event = new NoteOnEvent(evp); 00741 break; 00742 00743 case SND_SEQ_EVENT_NOTEOFF: 00744 event = new NoteOffEvent(evp); 00745 break; 00746 00747 case SND_SEQ_EVENT_KEYPRESS: 00748 event = new KeyPressEvent(evp); 00749 break; 00750 00751 case SND_SEQ_EVENT_CONTROLLER: 00752 case SND_SEQ_EVENT_CONTROL14: 00753 case SND_SEQ_EVENT_REGPARAM: 00754 case SND_SEQ_EVENT_NONREGPARAM: 00755 event = new ControllerEvent(evp); 00756 break; 00757 00758 case SND_SEQ_EVENT_PGMCHANGE: 00759 event = new ProgramChangeEvent(evp); 00760 break; 00761 00762 case SND_SEQ_EVENT_CHANPRESS: 00763 event = new ChanPressEvent(evp); 00764 break; 00765 00766 case SND_SEQ_EVENT_PITCHBEND: 00767 event = new PitchBendEvent(evp); 00768 break; 00769 00770 case SND_SEQ_EVENT_SYSEX: 00771 event = new SysExEvent(evp); 00772 break; 00773 00774 case SND_SEQ_EVENT_PORT_SUBSCRIBED: 00775 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: 00776 event = new SubscriptionEvent(evp); 00777 break; 00778 00779 case SND_SEQ_EVENT_PORT_CHANGE: 00780 case SND_SEQ_EVENT_PORT_EXIT: 00781 case SND_SEQ_EVENT_PORT_START: 00782 event = new PortEvent(evp); 00783 d->m_NeedRefreshClientList = true; 00784 break; 00785 00786 case SND_SEQ_EVENT_CLIENT_CHANGE: 00787 case SND_SEQ_EVENT_CLIENT_EXIT: 00788 case SND_SEQ_EVENT_CLIENT_START: 00789 event = new ClientEvent(evp); 00790 d->m_NeedRefreshClientList = true; 00791 break; 00792 00793 case SND_SEQ_EVENT_SONGPOS: 00794 case SND_SEQ_EVENT_SONGSEL: 00795 case SND_SEQ_EVENT_QFRAME: 00796 case SND_SEQ_EVENT_TIMESIGN: 00797 case SND_SEQ_EVENT_KEYSIGN: 00798 event = new ValueEvent(evp); 00799 break; 00800 00801 case SND_SEQ_EVENT_SETPOS_TICK: 00802 case SND_SEQ_EVENT_SETPOS_TIME: 00803 case SND_SEQ_EVENT_QUEUE_SKEW: 00804 event = new QueueControlEvent(evp); 00805 break; 00806 00807 case SND_SEQ_EVENT_TEMPO: 00808 event = new TempoEvent(evp); 00809 break; 00810 00811 default: 00812 event = new SequencerEvent(evp); 00813 break; 00814 } 00815 // first, process the callback (if any) 00816 if (d->m_handler != NULL) { 00817 d->m_handler->handleSequencerEvent(event->clone()); 00818 } else { 00819 // second, process the event listeners 00820 if (d->m_eventsEnabled) { 00821 QObjectList::Iterator it; 00822 for(it=d->m_listeners.begin(); it!=d->m_listeners.end(); ++it) { 00823 QObject* sub = (*it); 00824 QCoreApplication::postEvent(sub, event->clone()); 00825 } 00826 } else { 00827 // finally, process signals 00828 emit eventReceived(event->clone()); 00829 } 00830 } 00831 delete event; 00832 } 00833 } 00834 while (snd_seq_event_input_pending(d->m_SeqHandle, 0) > 0); 00835 } 00836 00840 void 00841 MidiClient::startSequencerInput() 00842 { 00843 if (d->m_Thread == 0) { 00844 d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT); 00845 } 00846 d->m_Thread->start( d->m_Thread->m_RealTime ? 00847 QThread::TimeCriticalPriority : QThread::InheritPriority ); 00848 } 00849 00853 void 00854 MidiClient::stopSequencerInput() 00855 { 00856 int counter = 0; 00857 if (d->m_Thread != 0) { 00858 if (d->m_Thread->isRunning()) { 00859 d->m_Thread->stop(); 00860 while (!d->m_Thread->wait(500) && (counter < 10)) { 00861 counter++; 00862 } 00863 if (!d->m_Thread->isFinished()) { 00864 d->m_Thread->terminate(); 00865 } 00866 } 00867 delete d->m_Thread; 00868 } 00869 } 00870 00874 void 00875 MidiClient::readClients() 00876 { 00877 ClientInfo cInfo; 00878 freeClients(); 00879 cInfo.setClient(-1); 00880 while (snd_seq_query_next_client(d->m_SeqHandle, cInfo.m_Info) >= 0) { 00881 cInfo.readPorts(this); 00882 d->m_ClientList.append(cInfo); 00883 } 00884 d->m_NeedRefreshClientList = false; 00885 } 00886 00890 void 00891 MidiClient::freeClients() 00892 { 00893 d->m_ClientList.clear(); 00894 } 00895 00900 ClientInfoList 00901 MidiClient::getAvailableClients() 00902 { 00903 if (d->m_NeedRefreshClientList) 00904 readClients(); 00905 ClientInfoList lst = d->m_ClientList; // copy 00906 return lst; 00907 } 00908 00913 ClientInfo& 00914 MidiClient::getThisClientInfo() 00915 { 00916 snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info); 00917 return d->m_Info; 00918 } 00919 00927 void 00928 MidiClient::setThisClientInfo(const ClientInfo& val) 00929 { 00930 d->m_Info = val; 00931 snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info); 00932 } 00933 00937 void 00938 MidiClient::applyClientInfo() 00939 { 00940 if (d->m_SeqHandle != NULL) { 00941 snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info); 00942 } 00943 } 00944 00949 QString 00950 MidiClient::getClientName() 00951 { 00952 return d->m_Info.getName(); 00953 } 00954 00960 QString 00961 MidiClient::getClientName(const int clientId) 00962 { 00963 ClientInfoList::Iterator it; 00964 if (d->m_NeedRefreshClientList) 00965 readClients(); 00966 for (it = d->m_ClientList.begin(); it != d->m_ClientList.end(); ++it) { 00967 if ((*it).getClientId() == clientId) { 00968 return (*it).getName(); 00969 } 00970 } 00971 return QString(); 00972 } 00973 00978 void 00979 MidiClient::setClientName(QString const& newName) 00980 { 00981 if (newName != d->m_Info.getName()) { 00982 d->m_Info.setName(newName); 00983 applyClientInfo(); 00984 } 00985 } 00986 00991 MidiPortList 00992 MidiClient::getMidiPorts() const 00993 { 00994 return d->m_Ports; 00995 } 00996 01001 MidiPort* 01002 MidiClient::createPort() 01003 { 01004 MidiPort* port = new MidiPort(this); 01005 port->attach(this); 01006 return port; 01007 } 01008 01013 void 01014 MidiClient::portAttach(MidiPort* port) 01015 { 01016 if (d->m_SeqHandle != NULL) { 01017 CHECK_ERROR(snd_seq_create_port(d->m_SeqHandle, port->m_Info.m_Info)); 01018 d->m_Ports.push_back(port); 01019 } 01020 } 01021 01026 void 01027 MidiClient::portDetach(MidiPort* port) 01028 { 01029 if (d->m_SeqHandle != NULL) { 01030 if(port->getPortInfo()->getClient() == getClientId()) 01031 { 01032 return; 01033 } 01034 CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, port->getPortInfo()->getPort())); 01035 port->setMidiClient(NULL); 01036 01037 MidiPortList::iterator it; 01038 for(it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it) 01039 { 01040 if ((*it)->getPortInfo()->getPort() == port->getPortInfo()->getPort()) 01041 { 01042 d->m_Ports.erase(it); 01043 break; 01044 } 01045 } 01046 } 01047 } 01048 01052 void MidiClient::detachAllPorts() 01053 { 01054 if (d->m_SeqHandle != NULL) { 01055 MidiPortList::iterator it; 01056 for (it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it) { 01057 CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, (*it)->getPortInfo()->getPort())); 01058 (*it)->setMidiClient(NULL); 01059 d->m_Ports.erase(it); 01060 } 01061 } 01062 } 01063 01068 void 01069 MidiClient::addEventFilter(int evtype) 01070 { 01071 snd_seq_set_client_event_filter(d->m_SeqHandle, evtype); 01072 } 01073 01079 bool 01080 MidiClient::getBroadcastFilter() 01081 { 01082 return d->m_Info.getBroadcastFilter(); 01083 } 01084 01090 void 01091 MidiClient::setBroadcastFilter(bool newValue) 01092 { 01093 d->m_Info.setBroadcastFilter(newValue); 01094 applyClientInfo(); 01095 } 01096 01102 bool 01103 MidiClient::getErrorBounce() 01104 { 01105 return d->m_Info.getErrorBounce(); 01106 } 01107 01113 void 01114 MidiClient::setErrorBounce(bool newValue) 01115 { 01116 d->m_Info.setErrorBounce(newValue); 01117 applyClientInfo(); 01118 } 01119 01131 void 01132 MidiClient::output(SequencerEvent* ev, bool async, int timeout) 01133 { 01134 int npfds; 01135 pollfd* pfds; 01136 if (async) { 01137 CHECK_WARNING(snd_seq_event_output(d->m_SeqHandle, ev->getHandle())); 01138 } else { 01139 npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT); 01140 pfds = (pollfd*) alloca(npfds * sizeof(pollfd)); 01141 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT); 01142 while (snd_seq_event_output(d->m_SeqHandle, ev->getHandle()) < 0) 01143 { 01144 poll(pfds, npfds, timeout); 01145 } 01146 } 01147 } 01148 01160 void MidiClient::outputDirect(SequencerEvent* ev, bool async, int timeout) 01161 { 01162 int npfds; 01163 pollfd* pfds; 01164 if (async) { 01165 CHECK_WARNING(snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle())); 01166 } else { 01167 npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT); 01168 pfds = (pollfd*) alloca(npfds * sizeof(pollfd)); 01169 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT); 01170 while (snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()) < 0) 01171 { 01172 poll(pfds, npfds, timeout); 01173 } 01174 } 01175 } 01176 01185 void 01186 MidiClient::outputBuffer(SequencerEvent* ev) 01187 { 01188 CHECK_WARNING(snd_seq_event_output_buffer(d->m_SeqHandle, ev->getHandle())); 01189 } 01190 01202 void MidiClient::drainOutput(bool async, int timeout) 01203 { 01204 int npfds; 01205 pollfd* pfds; 01206 if (async) { 01207 CHECK_WARNING(snd_seq_drain_output(d->m_SeqHandle)); 01208 } else { 01209 npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT); 01210 pfds = (pollfd*) alloca(npfds * sizeof(pollfd)); 01211 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT); 01212 while (snd_seq_drain_output(d->m_SeqHandle) < 0) 01213 { 01214 poll(pfds, npfds, timeout); 01215 } 01216 } 01217 } 01218 01224 void 01225 MidiClient::synchronizeOutput() 01226 { 01227 snd_seq_sync_output_queue(d->m_SeqHandle); 01228 } 01229 01235 MidiQueue* 01236 MidiClient::getQueue() 01237 { 01238 if (d->m_Queue == NULL) { 01239 createQueue(); 01240 } 01241 return d->m_Queue; 01242 } 01243 01248 MidiQueue* 01249 MidiClient::createQueue() 01250 { 01251 if (d->m_Queue != NULL) { 01252 delete d->m_Queue; 01253 } 01254 d->m_Queue = new MidiQueue(this, this); 01255 return d->m_Queue; 01256 } 01257 01264 MidiQueue* 01265 MidiClient::createQueue(QString const& queueName ) 01266 { 01267 if (d->m_Queue != NULL) { 01268 delete d->m_Queue; 01269 } 01270 d->m_Queue = new MidiQueue(this, queueName, this); 01271 return d->m_Queue; 01272 } 01273 01281 MidiQueue* 01282 MidiClient::useQueue(int queue_id) 01283 { 01284 if (d->m_Queue != NULL) { 01285 delete d->m_Queue; 01286 } 01287 d->m_Queue = new MidiQueue(this, queue_id, this); 01288 return d->m_Queue; 01289 } 01290 01298 MidiQueue* 01299 MidiClient::useQueue(const QString& name) 01300 { 01301 if (d->m_Queue != NULL) { 01302 delete d->m_Queue; 01303 } 01304 int queue_id = getQueueId(name); 01305 if ( queue_id >= 0) { 01306 d->m_Queue = new MidiQueue(this, queue_id, this); 01307 } 01308 return d->m_Queue; 01309 } 01310 01317 MidiQueue* 01318 MidiClient::useQueue(MidiQueue* queue) 01319 { 01320 if (d->m_Queue != NULL) { 01321 delete d->m_Queue; 01322 } 01323 queue->setParent(this); 01324 d->m_Queue = queue; 01325 return d->m_Queue; 01326 } 01327 01332 QList<int> 01333 MidiClient::getAvailableQueues() 01334 { 01335 int q, err, max; 01336 QList<int> queues; 01337 snd_seq_queue_info_t* qinfo; 01338 snd_seq_queue_info_alloca(&qinfo); 01339 max = getSystemInfo().getMaxQueues(); 01340 for ( q = 0; q < max; ++q ) { 01341 err = snd_seq_get_queue_info(d->m_SeqHandle, q, qinfo); 01342 if (err == 0) { 01343 queues.append(q); 01344 } 01345 } 01346 return queues; 01347 } 01348 01356 PortInfoList 01357 MidiClient::filterPorts(unsigned int filter) 01358 { 01359 PortInfoList result; 01360 ClientInfoList::ConstIterator itc; 01361 PortInfoList::ConstIterator itp; 01362 01363 if (d->m_NeedRefreshClientList) 01364 readClients(); 01365 01366 for (itc = d->m_ClientList.constBegin(); itc != d->m_ClientList.constEnd(); ++itc) { 01367 ClientInfo ci = (*itc); 01368 if ((ci.getClientId() == SND_SEQ_CLIENT_SYSTEM) || 01369 (ci.getClientId() == d->m_Info.getClientId())) 01370 continue; 01371 PortInfoList lstPorts = ci.getPorts(); 01372 for(itp = lstPorts.constBegin(); itp != lstPorts.constEnd(); ++itp) { 01373 PortInfo pi = (*itp); 01374 unsigned int cap = pi.getCapability(); 01375 if ( ((filter & cap) != 0) && 01376 ((SND_SEQ_PORT_CAP_NO_EXPORT & cap) == 0) ) { 01377 result.append(pi); 01378 } 01379 } 01380 } 01381 return result; 01382 } 01383 01387 void 01388 MidiClient::updateAvailablePorts() 01389 { 01390 d->m_InputsAvail.clear(); 01391 d->m_OutputsAvail.clear(); 01392 d->m_InputsAvail = filterPorts( SND_SEQ_PORT_CAP_READ | 01393 SND_SEQ_PORT_CAP_SUBS_READ ); 01394 d->m_OutputsAvail = filterPorts( SND_SEQ_PORT_CAP_WRITE | 01395 SND_SEQ_PORT_CAP_SUBS_WRITE ); 01396 } 01397 01402 PortInfoList 01403 MidiClient::getAvailableInputs() 01404 { 01405 d->m_NeedRefreshClientList = true; 01406 updateAvailablePorts(); 01407 return d->m_InputsAvail; 01408 } 01409 01414 PortInfoList 01415 MidiClient::getAvailableOutputs() 01416 { 01417 d->m_NeedRefreshClientList = true; 01418 updateAvailablePorts(); 01419 return d->m_OutputsAvail; 01420 } 01421 01428 void 01429 MidiClient::addListener(QObject* listener) 01430 { 01431 d->m_listeners.append(listener); 01432 } 01433 01439 void 01440 MidiClient::removeListener(QObject* listener) 01441 { 01442 d->m_listeners.removeAll(listener); 01443 } 01444 01451 void 01452 MidiClient::setEventsEnabled(bool bEnabled) 01453 { 01454 if (bEnabled != d->m_eventsEnabled) { 01455 d->m_eventsEnabled = bEnabled; 01456 } 01457 } 01458 01463 SystemInfo& 01464 MidiClient::getSystemInfo() 01465 { 01466 snd_seq_system_info(d->m_SeqHandle, d->m_sysInfo.m_Info); 01467 return d->m_sysInfo; 01468 } 01469 01474 PoolInfo& 01475 MidiClient::getPoolInfo() 01476 { 01477 snd_seq_get_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info); 01478 return d->m_poolInfo; 01479 } 01480 01485 void 01486 MidiClient::setPoolInfo(const PoolInfo& info) 01487 { 01488 d->m_poolInfo = info; 01489 CHECK_WARNING(snd_seq_set_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info)); 01490 } 01491 01496 void 01497 MidiClient::resetPoolInput() 01498 { 01499 CHECK_WARNING(snd_seq_reset_pool_input(d->m_SeqHandle)); 01500 } 01501 01506 void 01507 MidiClient::resetPoolOutput() 01508 { 01509 CHECK_WARNING(snd_seq_reset_pool_output(d->m_SeqHandle)); 01510 } 01511 01516 void 01517 MidiClient::setPoolInput(int size) 01518 { 01519 CHECK_WARNING(snd_seq_set_client_pool_input(d->m_SeqHandle, size)); 01520 } 01521 01526 void 01527 MidiClient::setPoolOutput(int size) 01528 { 01529 CHECK_WARNING(snd_seq_set_client_pool_output(d->m_SeqHandle, size)); 01530 } 01531 01536 void 01537 MidiClient::setPoolOutputRoom(int size) 01538 { 01539 CHECK_WARNING(snd_seq_set_client_pool_output_room(d->m_SeqHandle, size)); 01540 } 01541 01546 void 01547 MidiClient::dropInput() 01548 { 01549 CHECK_WARNING(snd_seq_drop_input(d->m_SeqHandle)); 01550 } 01551 01556 void 01557 MidiClient::dropInputBuffer() 01558 { 01559 CHECK_WARNING(snd_seq_drop_input_buffer(d->m_SeqHandle)); 01560 } 01561 01569 void 01570 MidiClient::dropOutput() 01571 { 01572 CHECK_WARNING(snd_seq_drop_output(d->m_SeqHandle)); 01573 } 01574 01582 void 01583 MidiClient::dropOutputBuffer() 01584 { 01585 CHECK_WARNING(snd_seq_drop_output_buffer(d->m_SeqHandle)); 01586 } 01587 01594 void 01595 MidiClient::removeEvents(const RemoveEvents* spec) 01596 { 01597 CHECK_WARNING(snd_seq_remove_events(d->m_SeqHandle, spec->m_Info)); 01598 } 01599 01604 SequencerEvent* 01605 MidiClient::extractOutput() 01606 { 01607 snd_seq_event_t* ev; 01608 if (CHECK_WARNING(snd_seq_extract_output(d->m_SeqHandle, &ev) == 0)) { 01609 return new SequencerEvent(ev); 01610 } 01611 return NULL; 01612 } 01613 01619 int 01620 MidiClient::outputPending() 01621 { 01622 return snd_seq_event_output_pending(d->m_SeqHandle); 01623 } 01624 01638 int 01639 MidiClient::inputPending(bool fetch) 01640 { 01641 return snd_seq_event_input_pending(d->m_SeqHandle, fetch ? 1 : 0); 01642 } 01643 01650 int 01651 MidiClient::getQueueId(const QString& name) 01652 { 01653 return snd_seq_query_named_queue(d->m_SeqHandle, name.toLocal8Bit().data()); 01654 } 01655 01661 int 01662 MidiClient::getPollDescriptorsCount(short events) 01663 { 01664 return snd_seq_poll_descriptors_count(d->m_SeqHandle, events); 01665 } 01666 01680 int 01681 MidiClient::pollDescriptors( struct pollfd *pfds, unsigned int space, 01682 short events ) 01683 { 01684 return snd_seq_poll_descriptors(d->m_SeqHandle, pfds, space, events); 01685 } 01686 01693 unsigned short 01694 MidiClient::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds) 01695 { 01696 unsigned short revents; 01697 CHECK_WARNING( snd_seq_poll_descriptors_revents( d->m_SeqHandle, 01698 pfds, nfds, 01699 &revents )); 01700 return revents; 01701 } 01702 01707 const char * 01708 MidiClient::_getDeviceName() 01709 { 01710 return snd_seq_name(d->m_SeqHandle); 01711 } 01712 01717 void 01718 MidiClient::_setClientName(const char *name) 01719 { 01720 CHECK_WARNING(snd_seq_set_client_name(d->m_SeqHandle, name)); 01721 } 01722 01730 int 01731 MidiClient::createSimplePort( const char *name, 01732 unsigned int caps, 01733 unsigned int type ) 01734 { 01735 return CHECK_WARNING( snd_seq_create_simple_port( d->m_SeqHandle, 01736 name, caps, type )); 01737 } 01738 01743 void 01744 MidiClient::deleteSimplePort(int port) 01745 { 01746 CHECK_WARNING( snd_seq_delete_simple_port( d->m_SeqHandle, port )); 01747 } 01748 01755 void 01756 MidiClient::connectFrom(int myport, int client, int port) 01757 { 01758 CHECK_WARNING( snd_seq_connect_from(d->m_SeqHandle, myport, client, port )); 01759 } 01760 01767 void 01768 MidiClient::connectTo(int myport, int client, int port) 01769 { 01770 CHECK_WARNING( snd_seq_connect_to(d->m_SeqHandle, myport, client, port )); 01771 } 01772 01779 void 01780 MidiClient::disconnectFrom(int myport, int client, int port) 01781 { 01782 CHECK_WARNING( snd_seq_disconnect_from(d->m_SeqHandle, myport, client, port )); 01783 } 01784 01791 void 01792 MidiClient::disconnectTo(int myport, int client, int port) 01793 { 01794 CHECK_WARNING( snd_seq_disconnect_to(d->m_SeqHandle, myport, client, port )); 01795 } 01796 01808 bool 01809 MidiClient::parseAddress( const QString& straddr, snd_seq_addr& addr ) 01810 { 01811 bool ok(false); 01812 QString testClient, testPort; 01813 ClientInfoList::ConstIterator cit; 01814 int pos = straddr.indexOf(':'); 01815 if (pos > -1) { 01816 testClient = straddr.left(pos); 01817 testPort = straddr.mid(pos+1); 01818 } else { 01819 testClient = straddr; 01820 testPort = '0'; 01821 } 01822 addr.client = testClient.toInt(&ok); 01823 if (ok) 01824 addr.port = testPort.toInt(&ok); 01825 if (!ok) { 01826 if (d->m_NeedRefreshClientList) 01827 readClients(); 01828 for ( cit = d->m_ClientList.constBegin(); 01829 cit != d->m_ClientList.constEnd(); ++cit ) { 01830 ClientInfo ci = *cit; 01831 if (testClient.compare(ci.getName(), Qt::CaseInsensitive) == 0) { 01832 addr.client = ci.getClientId(); 01833 addr.port = testPort.toInt(&ok); 01834 return ok; 01835 } 01836 } 01837 } 01838 return ok; 01839 } 01840 01845 bool 01846 MidiClient::SequencerInputThread::stopped() 01847 { 01848 QReadLocker locker(&m_mutex); 01849 return m_Stopped; 01850 } 01851 01855 void 01856 MidiClient::SequencerInputThread::stop() 01857 { 01858 QWriteLocker locker(&m_mutex); 01859 m_Stopped = true; 01860 } 01861 01862 #if defined(RTKIT_SUPPORT) 01863 static pid_t _gettid(void) { 01864 return (pid_t) ::syscall(SYS_gettid); 01865 } 01866 #endif 01867 01868 void 01869 MidiClient::SequencerInputThread::setRealtimePriority() 01870 { 01871 struct sched_param p; 01872 int rt, policy = SCHED_RR | SCHED_RESET_ON_FORK; 01873 quint32 priority = 6; 01874 #if defined(RTKIT_SUPPORT) 01875 bool ok; 01876 quint32 max_prio; 01877 quint64 thread; 01878 struct rlimit old_limit, new_limit; 01879 long long max_rttime; 01880 #endif 01881 01882 ::memset(&p, 0, sizeof(p)); 01883 p.sched_priority = priority; 01884 rt = ::pthread_setschedparam(::pthread_self(), policy, &p); 01885 if (rt != 0) { 01886 #if defined(RTKIT_SUPPORT) 01887 const QString rtkit_service = 01888 QLatin1String("org.freedesktop.RealtimeKit1"); 01889 const QString rtkit_path = 01890 QLatin1String("/org/freedesktop/RealtimeKit1"); 01891 const QString rtkit_iface = rtkit_service; 01892 thread = _gettid(); 01893 QDBusConnection bus = QDBusConnection::systemBus(); 01894 QDBusInterface realtimeKit(rtkit_service, rtkit_path, rtkit_iface, bus); 01895 QVariant maxRTPrio = realtimeKit.property("MaxRealtimePriority"); 01896 max_prio = maxRTPrio.toUInt(&ok); 01897 if (!ok) { 01898 qWarning() << "invalid property RealtimeKit.MaxRealtimePriority"; 01899 return; 01900 } 01901 if (priority > max_prio) 01902 priority = max_prio; 01903 QVariant maxRTNSec = realtimeKit.property("RTTimeNSecMax"); 01904 max_rttime = maxRTNSec.toLongLong(&ok); 01905 if (!ok || max_rttime < 0) { 01906 qWarning() << "invalid property RealtimeKit.RTTimeNSecMax"; 01907 return; 01908 } 01909 new_limit.rlim_cur = new_limit.rlim_max = max_rttime; 01910 rt = ::getrlimit(RLIMIT_RTTIME, &old_limit); 01911 if (rt < 0) { 01912 qWarning() << "getrlimit() failed. err=" << rt << ::strerror(rt); 01913 return; 01914 } 01915 rt = ::setrlimit(RLIMIT_RTTIME, &new_limit); 01916 if ( rt < 0) { 01917 qWarning() << "setrlimit() failed, err=" << rt << ::strerror(rt); 01918 return; 01919 } 01920 QDBusMessage reply = realtimeKit.call("MakeThreadRealtime", thread, priority); 01921 if (reply.type() == QDBusMessage::ErrorMessage ) 01922 qWarning() << "error returned by RealtimeKit.MakeThreadRealtime:" 01923 << reply.errorMessage(); 01924 #else 01925 qWarning() << "pthread_setschedparam() failed, err=" 01926 << rt << ::strerror(rt); 01927 #endif 01928 } 01929 } 01930 01934 void 01935 MidiClient::SequencerInputThread::run() 01936 { 01937 unsigned long npfd; 01938 pollfd* pfd; 01939 if ( priority() == TimeCriticalPriority ) 01940 setRealtimePriority(); 01941 01942 if (m_MidiClient != NULL) { 01943 npfd = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLIN); 01944 pfd = (pollfd *) alloca(npfd * sizeof(pollfd)); 01945 try 01946 { 01947 snd_seq_poll_descriptors(m_MidiClient->getHandle(), pfd, npfd, POLLIN); 01948 while (!stopped() && (m_MidiClient != NULL)) 01949 { 01950 int rt = poll(pfd, npfd, m_Wait); 01951 if (rt > 0) { 01952 m_MidiClient->doEvents(); 01953 } 01954 } 01955 } 01956 catch (...) 01957 { 01958 qWarning() << "exception in input thread"; 01959 } 01960 } 01961 } 01962 01966 ClientInfo::ClientInfo() 01967 { 01968 snd_seq_client_info_malloc(&m_Info); 01969 } 01970 01975 ClientInfo::ClientInfo(const ClientInfo& other) 01976 { 01977 snd_seq_client_info_malloc(&m_Info); 01978 snd_seq_client_info_copy(m_Info, other.m_Info); 01979 m_Ports = other.m_Ports; 01980 } 01981 01986 ClientInfo::ClientInfo(snd_seq_client_info_t* other) 01987 { 01988 snd_seq_client_info_malloc(&m_Info); 01989 snd_seq_client_info_copy(m_Info, other); 01990 } 01991 01997 ClientInfo::ClientInfo(MidiClient* seq, int id) 01998 { 01999 snd_seq_client_info_malloc(&m_Info); 02000 snd_seq_get_any_client_info(seq->getHandle(), id, m_Info); 02001 } 02002 02006 ClientInfo::~ClientInfo() 02007 { 02008 freePorts(); 02009 snd_seq_client_info_free(m_Info); 02010 } 02011 02016 ClientInfo* 02017 ClientInfo::clone() 02018 { 02019 return new ClientInfo(m_Info); 02020 } 02021 02027 ClientInfo& 02028 ClientInfo::operator=(const ClientInfo& other) 02029 { 02030 snd_seq_client_info_copy(m_Info, other.m_Info); 02031 m_Ports = other.m_Ports; 02032 return *this; 02033 } 02034 02039 int 02040 ClientInfo::getClientId() 02041 { 02042 return snd_seq_client_info_get_client(m_Info); 02043 } 02044 02049 snd_seq_client_type_t 02050 ClientInfo::getClientType() 02051 { 02052 return snd_seq_client_info_get_type(m_Info); 02053 } 02054 02059 QString 02060 ClientInfo::getName() 02061 { 02062 return QString(snd_seq_client_info_get_name(m_Info)); 02063 } 02064 02069 bool 02070 ClientInfo::getBroadcastFilter() 02071 { 02072 return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0); 02073 } 02074 02079 bool 02080 ClientInfo::getErrorBounce() 02081 { 02082 return (snd_seq_client_info_get_error_bounce(m_Info) != 0); 02083 } 02084 02090 const unsigned char* 02091 ClientInfo::getEventFilter() 02092 { 02093 return snd_seq_client_info_get_event_filter(m_Info); 02094 } 02095 02100 int 02101 ClientInfo::getNumPorts() 02102 { 02103 return snd_seq_client_info_get_num_ports(m_Info); 02104 } 02105 02110 int 02111 ClientInfo::getEventLost() 02112 { 02113 return snd_seq_client_info_get_event_lost(m_Info); 02114 } 02115 02120 void 02121 ClientInfo::setClient(int client) 02122 { 02123 snd_seq_client_info_set_client(m_Info, client); 02124 } 02125 02130 void 02131 ClientInfo::setName(QString name) 02132 { 02133 snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data()); 02134 } 02135 02140 void 02141 ClientInfo::setBroadcastFilter(bool val) 02142 { 02143 snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0); 02144 } 02145 02150 void 02151 ClientInfo::setErrorBounce(bool val) 02152 { 02153 snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0); 02154 } 02155 02161 void 02162 ClientInfo::setEventFilter(unsigned char *filter) 02163 { 02164 snd_seq_client_info_set_event_filter(m_Info, filter); 02165 } 02166 02171 void 02172 ClientInfo::readPorts(MidiClient* seq) 02173 { 02174 PortInfo info; 02175 freePorts(); 02176 info.setClient(getClientId()); 02177 info.setClientName(getName()); 02178 info.setPort(-1); 02179 while (snd_seq_query_next_port(seq->getHandle(), info.m_Info) >= 0) { 02180 info.readSubscribers(seq); 02181 m_Ports.append(info); 02182 } 02183 } 02184 02188 void 02189 ClientInfo::freePorts() 02190 { 02191 m_Ports.clear(); 02192 } 02193 02198 PortInfoList 02199 ClientInfo::getPorts() const 02200 { 02201 PortInfoList lst = m_Ports; // copy 02202 return lst; 02203 } 02204 02209 int 02210 ClientInfo::getSizeOfInfo() const 02211 { 02212 return snd_seq_client_info_sizeof(); 02213 } 02214 02215 #if SND_LIB_VERSION > 0x010010 02216 02221 void 02222 ClientInfo::addFilter(int eventType) 02223 { 02224 snd_seq_client_info_event_filter_add(m_Info, eventType); 02225 } 02226 02232 bool 02233 ClientInfo::isFiltered(int eventType) 02234 { 02235 return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0); 02236 } 02237 02241 void 02242 ClientInfo::clearFilter() 02243 { 02244 snd_seq_client_info_event_filter_clear(m_Info); 02245 } 02246 02251 void 02252 ClientInfo::removeFilter(int eventType) 02253 { 02254 snd_seq_client_info_event_filter_del(m_Info, eventType); 02255 } 02256 #endif 02257 02261 SystemInfo::SystemInfo() 02262 { 02263 snd_seq_system_info_malloc(&m_Info); 02264 } 02265 02270 SystemInfo::SystemInfo(const SystemInfo& other) 02271 { 02272 snd_seq_system_info_malloc(&m_Info); 02273 snd_seq_system_info_copy(m_Info, other.m_Info); 02274 } 02275 02280 SystemInfo::SystemInfo(snd_seq_system_info_t* other) 02281 { 02282 snd_seq_system_info_malloc(&m_Info); 02283 snd_seq_system_info_copy(m_Info, other); 02284 } 02285 02290 SystemInfo::SystemInfo(MidiClient* seq) 02291 { 02292 snd_seq_system_info_malloc(&m_Info); 02293 snd_seq_system_info(seq->getHandle(), m_Info); 02294 } 02295 02299 SystemInfo::~SystemInfo() 02300 { 02301 snd_seq_system_info_free(m_Info); 02302 } 02303 02308 SystemInfo* 02309 SystemInfo::clone() 02310 { 02311 return new SystemInfo(m_Info); 02312 } 02313 02319 SystemInfo& 02320 SystemInfo::operator=(const SystemInfo& other) 02321 { 02322 snd_seq_system_info_copy(m_Info, other.m_Info); 02323 return *this; 02324 } 02325 02330 int SystemInfo::getMaxClients() 02331 { 02332 return snd_seq_system_info_get_clients(m_Info); 02333 } 02334 02339 int SystemInfo::getMaxPorts() 02340 { 02341 return snd_seq_system_info_get_ports(m_Info); 02342 } 02343 02348 int SystemInfo::getMaxQueues() 02349 { 02350 return snd_seq_system_info_get_queues(m_Info); 02351 } 02352 02357 int SystemInfo::getMaxChannels() 02358 { 02359 return snd_seq_system_info_get_channels(m_Info); 02360 } 02361 02366 int SystemInfo::getCurrentQueues() 02367 { 02368 return snd_seq_system_info_get_cur_queues(m_Info); 02369 } 02370 02375 int SystemInfo::getCurrentClients() 02376 { 02377 return snd_seq_system_info_get_cur_clients(m_Info); 02378 } 02379 02384 int SystemInfo::getSizeOfInfo() const 02385 { 02386 return snd_seq_system_info_sizeof(); 02387 } 02388 02392 PoolInfo::PoolInfo() 02393 { 02394 snd_seq_client_pool_malloc(&m_Info); 02395 } 02396 02401 PoolInfo::PoolInfo(const PoolInfo& other) 02402 { 02403 snd_seq_client_pool_malloc(&m_Info); 02404 snd_seq_client_pool_copy(m_Info, other.m_Info); 02405 } 02406 02411 PoolInfo::PoolInfo(snd_seq_client_pool_t* other) 02412 { 02413 snd_seq_client_pool_malloc(&m_Info); 02414 snd_seq_client_pool_copy(m_Info, other); 02415 } 02416 02421 PoolInfo::PoolInfo(MidiClient* seq) 02422 { 02423 snd_seq_client_pool_malloc(&m_Info); 02424 snd_seq_get_client_pool(seq->getHandle(), m_Info); 02425 } 02426 02430 PoolInfo::~PoolInfo() 02431 { 02432 snd_seq_client_pool_free(m_Info); 02433 } 02434 02439 PoolInfo* 02440 PoolInfo::clone() 02441 { 02442 return new PoolInfo(m_Info); 02443 } 02444 02450 PoolInfo& PoolInfo::operator=(const PoolInfo& other) 02451 { 02452 snd_seq_client_pool_copy(m_Info, other.m_Info); 02453 return *this; 02454 } 02455 02460 int 02461 PoolInfo::getClientId() 02462 { 02463 return snd_seq_client_pool_get_client(m_Info); 02464 } 02465 02470 int 02471 PoolInfo::getInputFree() 02472 { 02473 return snd_seq_client_pool_get_input_free(m_Info); 02474 } 02475 02480 int 02481 PoolInfo::getInputPool() 02482 { 02483 return snd_seq_client_pool_get_input_pool(m_Info); 02484 } 02485 02490 int 02491 PoolInfo::getOutputFree() 02492 { 02493 return snd_seq_client_pool_get_output_free(m_Info); 02494 } 02495 02500 int 02501 PoolInfo::getOutputPool() 02502 { 02503 return snd_seq_client_pool_get_output_pool(m_Info); 02504 } 02505 02511 int 02512 PoolInfo::getOutputRoom() 02513 { 02514 return snd_seq_client_pool_get_output_room(m_Info); 02515 } 02516 02521 void 02522 PoolInfo::setInputPool(int size) 02523 { 02524 snd_seq_client_pool_set_input_pool(m_Info, size); 02525 } 02526 02531 void 02532 PoolInfo::setOutputPool(int size) 02533 { 02534 snd_seq_client_pool_set_output_pool(m_Info, size); 02535 } 02536 02543 void 02544 PoolInfo::setOutputRoom(int size) 02545 { 02546 snd_seq_client_pool_set_output_room(m_Info, size); 02547 } 02548 02553 int 02554 PoolInfo::getSizeOfInfo() const 02555 { 02556 return snd_seq_client_pool_sizeof(); 02557 } 02558 02559 #if SND_LIB_VERSION > 0x010004 02560 02565 QString 02566 getRuntimeALSALibraryVersion() 02567 { 02568 return QString(snd_asoundlib_version()); 02569 } 02570 02576 int 02577 getRuntimeALSALibraryNumber() 02578 { 02579 QRegExp rx("(\\d+)"); 02580 QString str = getRuntimeALSALibraryVersion(); 02581 bool ok; 02582 int pos = 0, result = 0, j = 0; 02583 while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) { 02584 int v = rx.cap(1).toInt(&ok); 02585 if (ok) { 02586 result <<= 8; 02587 result += v; 02588 } 02589 pos += rx.matchedLength(); 02590 j++; 02591 } 02592 return result; 02593 } 02594 #endif // SND_LIB_VERSION > 0x010004 02595 02601 QString 02602 getRuntimeALSADriverVersion() 02603 { 02604 QRegExp rx(".*Driver Version.*([\\d\\.]+).*"); 02605 QString s; 02606 QFile f("/proc/asound/version"); 02607 if (f.open(QFile::ReadOnly)) { 02608 QTextStream str(&f); 02609 if (rx.exactMatch(str.readLine().trimmed())) 02610 s = rx.cap(1); 02611 } 02612 return s; 02613 } 02614 02620 int 02621 getRuntimeALSADriverNumber() 02622 { 02623 QRegExp rx("(\\d+)"); 02624 QString str = getRuntimeALSADriverVersion(); 02625 bool ok; 02626 int pos = 0, result = 0, j = 0; 02627 while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) { 02628 int v = rx.cap(1).toInt(&ok); 02629 if (ok) { 02630 result <<= 8; 02631 result += v; 02632 } 02633 pos += rx.matchedLength(); 02634 j++; 02635 } 02636 return result; 02637 } 02638 02639 } /* namespace drumstick */