drumstick
0.5.0
|
00001 /* 00002 MIDI Sequencer C++ library 00003 Copyright (C) 2006-2010, 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 00366 MidiClient::MidiClient( QObject* parent ) : 00367 QObject(parent), 00368 m_eventsEnabled(false), 00369 m_BlockMode(false), 00370 m_NeedRefreshClientList(true), 00371 m_OpenMode(SND_SEQ_OPEN_DUPLEX), 00372 m_DeviceName("default"), 00373 m_SeqHandle(NULL), 00374 m_Thread(NULL), 00375 m_Queue(NULL), 00376 m_handler(NULL) 00377 { } 00378 00384 MidiClient::~MidiClient() 00385 { 00386 stopSequencerInput(); 00387 detachAllPorts(); 00388 if (m_Queue != NULL) 00389 delete m_Queue; 00390 close(); 00391 freeClients(); 00392 if (m_Thread != NULL) 00393 delete m_Thread; 00394 } 00395 00404 void MidiClient::setRealTimeInput(bool enable) 00405 { 00406 if (m_Thread == 0) { 00407 m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT); 00408 m_Thread->m_RealTime = enable; 00409 } 00410 } 00411 00417 bool MidiClient::realTimeInputEnabled() 00418 { 00419 if (m_Thread == 0) 00420 return true; 00421 return m_Thread->m_RealTime; 00422 } 00423 00444 void 00445 MidiClient::open( const QString deviceName, 00446 const int openMode, 00447 const bool blockMode) 00448 { 00449 CHECK_ERROR( snd_seq_open( &m_SeqHandle, deviceName.toLocal8Bit().data(), 00450 openMode, blockMode ? 0 : SND_SEQ_NONBLOCK ) ); 00451 CHECK_WARNING( snd_seq_get_client_info( m_SeqHandle, m_Info.m_Info ) ); 00452 m_DeviceName = deviceName; 00453 m_OpenMode = openMode; 00454 m_BlockMode = blockMode; 00455 } 00456 00477 void 00478 MidiClient::open( snd_config_t* conf, 00479 const QString deviceName, 00480 const int openMode, 00481 const bool blockMode ) 00482 { 00483 CHECK_ERROR( snd_seq_open_lconf( &m_SeqHandle, 00484 deviceName.toLocal8Bit().data(), 00485 openMode, 00486 blockMode ? 0 : SND_SEQ_NONBLOCK, 00487 conf )); 00488 CHECK_WARNING( snd_seq_get_client_info(m_SeqHandle, m_Info.m_Info)); 00489 m_DeviceName = deviceName; 00490 m_OpenMode = openMode; 00491 m_BlockMode = blockMode; 00492 } 00493 00501 void 00502 MidiClient::close() 00503 { 00504 if (m_SeqHandle != NULL) { 00505 stopSequencerInput(); 00506 CHECK_WARNING(snd_seq_close(m_SeqHandle)); 00507 m_SeqHandle = NULL; 00508 } 00509 } 00510 00519 size_t 00520 MidiClient::getOutputBufferSize() 00521 { 00522 return snd_seq_get_output_buffer_size(m_SeqHandle); 00523 } 00524 00533 void 00534 MidiClient::setOutputBufferSize(size_t newSize) 00535 { 00536 if (getOutputBufferSize() != newSize) { 00537 CHECK_WARNING(snd_seq_set_output_buffer_size(m_SeqHandle, newSize)); 00538 } 00539 } 00540 00549 size_t 00550 MidiClient::getInputBufferSize() 00551 { 00552 return snd_seq_get_input_buffer_size(m_SeqHandle); 00553 } 00554 00563 void 00564 MidiClient::setInputBufferSize(size_t newSize) 00565 { 00566 if (getInputBufferSize() != newSize) { 00567 CHECK_WARNING(snd_seq_set_input_buffer_size(m_SeqHandle, newSize)); 00568 } 00569 } 00570 00580 void 00581 MidiClient::setBlockMode(bool newValue) 00582 { 00583 if (m_BlockMode != newValue) 00584 { 00585 m_BlockMode = newValue; 00586 if (m_SeqHandle != NULL) 00587 { 00588 CHECK_WARNING(snd_seq_nonblock(m_SeqHandle, m_BlockMode ? 0 : 1)); 00589 } 00590 } 00591 } 00592 00601 int 00602 MidiClient::getClientId() 00603 { 00604 return CHECK_WARNING(snd_seq_client_id(m_SeqHandle)); 00605 } 00606 00611 snd_seq_type_t 00612 MidiClient::getSequencerType() 00613 { 00614 return snd_seq_type(m_SeqHandle); 00615 } 00616 00637 void 00638 MidiClient::doEvents() 00639 { 00640 do { 00641 int err = 0; 00642 snd_seq_event_t* evp = NULL; 00643 SequencerEvent* event = NULL; 00644 err = snd_seq_event_input(m_SeqHandle, &evp); 00645 if ((err >= 0) && (evp != NULL)) { 00646 switch (evp->type) { 00647 00648 case SND_SEQ_EVENT_NOTE: 00649 event = new NoteEvent(evp); 00650 break; 00651 00652 case SND_SEQ_EVENT_NOTEON: 00653 event = new NoteOnEvent(evp); 00654 break; 00655 00656 case SND_SEQ_EVENT_NOTEOFF: 00657 event = new NoteOffEvent(evp); 00658 break; 00659 00660 case SND_SEQ_EVENT_KEYPRESS: 00661 event = new KeyPressEvent(evp); 00662 break; 00663 00664 case SND_SEQ_EVENT_CONTROLLER: 00665 case SND_SEQ_EVENT_CONTROL14: 00666 case SND_SEQ_EVENT_REGPARAM: 00667 case SND_SEQ_EVENT_NONREGPARAM: 00668 event = new ControllerEvent(evp); 00669 break; 00670 00671 case SND_SEQ_EVENT_PGMCHANGE: 00672 event = new ProgramChangeEvent(evp); 00673 break; 00674 00675 case SND_SEQ_EVENT_CHANPRESS: 00676 event = new ChanPressEvent(evp); 00677 break; 00678 00679 case SND_SEQ_EVENT_PITCHBEND: 00680 event = new PitchBendEvent(evp); 00681 break; 00682 00683 case SND_SEQ_EVENT_SYSEX: 00684 event = new SysExEvent(evp); 00685 break; 00686 00687 case SND_SEQ_EVENT_PORT_SUBSCRIBED: 00688 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: 00689 event = new SubscriptionEvent(evp); 00690 break; 00691 00692 case SND_SEQ_EVENT_PORT_CHANGE: 00693 case SND_SEQ_EVENT_PORT_EXIT: 00694 case SND_SEQ_EVENT_PORT_START: 00695 event = new PortEvent(evp); 00696 m_NeedRefreshClientList = true; 00697 break; 00698 00699 case SND_SEQ_EVENT_CLIENT_CHANGE: 00700 case SND_SEQ_EVENT_CLIENT_EXIT: 00701 case SND_SEQ_EVENT_CLIENT_START: 00702 event = new ClientEvent(evp); 00703 m_NeedRefreshClientList = true; 00704 break; 00705 00706 case SND_SEQ_EVENT_SONGPOS: 00707 case SND_SEQ_EVENT_SONGSEL: 00708 case SND_SEQ_EVENT_QFRAME: 00709 case SND_SEQ_EVENT_TIMESIGN: 00710 case SND_SEQ_EVENT_KEYSIGN: 00711 event = new ValueEvent(evp); 00712 break; 00713 00714 case SND_SEQ_EVENT_SETPOS_TICK: 00715 case SND_SEQ_EVENT_SETPOS_TIME: 00716 case SND_SEQ_EVENT_QUEUE_SKEW: 00717 event = new QueueControlEvent(evp); 00718 break; 00719 00720 case SND_SEQ_EVENT_TEMPO: 00721 event = new TempoEvent(evp); 00722 break; 00723 00724 default: 00725 event = new SequencerEvent(evp); 00726 break; 00727 } 00728 // first, process the callback (if any) 00729 if (m_handler != NULL) { 00730 m_handler->handleSequencerEvent(event->clone()); 00731 } else { 00732 // second, process the event listeners 00733 if (m_eventsEnabled) { 00734 QObjectList::Iterator it; 00735 for(it=m_listeners.begin(); it!=m_listeners.end(); ++it) { 00736 QObject* sub = (*it); 00737 QApplication::postEvent(sub, event->clone()); 00738 } 00739 } else { 00740 // finally, process signals 00741 emit eventReceived(event->clone()); 00742 } 00743 } 00744 delete event; 00745 } 00746 } 00747 while (snd_seq_event_input_pending(m_SeqHandle, 0) > 0); 00748 } 00749 00753 void 00754 MidiClient::startSequencerInput() 00755 { 00756 if (m_Thread == 0) { 00757 m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT); 00758 } 00759 m_Thread->start( m_Thread->m_RealTime ? 00760 QThread::TimeCriticalPriority : QThread::InheritPriority ); 00761 } 00762 00766 void 00767 MidiClient::stopSequencerInput() 00768 { 00769 int counter = 0; 00770 if (m_Thread != 0) { 00771 if (m_Thread->isRunning()) { 00772 m_Thread->stop(); 00773 while (!m_Thread->wait(500) && (counter < 10)) { 00774 counter++; 00775 } 00776 if (!m_Thread->isFinished()) { 00777 m_Thread->terminate(); 00778 } 00779 } 00780 delete m_Thread; 00781 } 00782 } 00783 00787 void 00788 MidiClient::readClients() 00789 { 00790 ClientInfo cInfo; 00791 freeClients(); 00792 cInfo.setClient(-1); 00793 while (snd_seq_query_next_client(m_SeqHandle, cInfo.m_Info) >= 0) { 00794 cInfo.readPorts(this); 00795 m_ClientList.append(cInfo); 00796 } 00797 m_NeedRefreshClientList = false; 00798 } 00799 00803 void 00804 MidiClient::freeClients() 00805 { 00806 m_ClientList.clear(); 00807 } 00808 00813 ClientInfoList 00814 MidiClient::getAvailableClients() 00815 { 00816 if (m_NeedRefreshClientList) 00817 readClients(); 00818 ClientInfoList lst = m_ClientList; // copy 00819 return lst; 00820 } 00821 00826 ClientInfo& 00827 MidiClient::getThisClientInfo() 00828 { 00829 snd_seq_get_client_info(m_SeqHandle, m_Info.m_Info); 00830 return m_Info; 00831 } 00832 00840 void 00841 MidiClient::setThisClientInfo(const ClientInfo& val) 00842 { 00843 m_Info = val; 00844 snd_seq_set_client_info(m_SeqHandle, m_Info.m_Info); 00845 } 00846 00850 void 00851 MidiClient::applyClientInfo() 00852 { 00853 if (m_SeqHandle != NULL) { 00854 snd_seq_set_client_info(m_SeqHandle, m_Info.m_Info); 00855 } 00856 } 00857 00862 QString 00863 MidiClient::getClientName() 00864 { 00865 return m_Info.getName(); 00866 } 00867 00873 QString 00874 MidiClient::getClientName(const int clientId) 00875 { 00876 ClientInfoList::Iterator it; 00877 if (m_NeedRefreshClientList) 00878 readClients(); 00879 for (it = m_ClientList.begin(); it != m_ClientList.end(); ++it) { 00880 if ((*it).getClientId() == clientId) { 00881 return (*it).getName(); 00882 } 00883 } 00884 return QString(); 00885 } 00886 00891 void 00892 MidiClient::setClientName(QString const& newName) 00893 { 00894 if (newName != m_Info.getName()) { 00895 m_Info.setName(newName); 00896 applyClientInfo(); 00897 } 00898 } 00899 00904 MidiPortList 00905 MidiClient::getMidiPorts() const 00906 { 00907 return m_Ports; 00908 } 00909 00914 MidiPort* 00915 MidiClient::createPort() 00916 { 00917 MidiPort* port = new MidiPort(this); 00918 port->attach(this); 00919 return port; 00920 } 00921 00926 void 00927 MidiClient::portAttach(MidiPort* port) 00928 { 00929 if (m_SeqHandle != NULL) { 00930 CHECK_ERROR(snd_seq_create_port(m_SeqHandle, port->m_Info.m_Info)); 00931 m_Ports.push_back(port); 00932 } 00933 } 00934 00939 void 00940 MidiClient::portDetach(MidiPort* port) 00941 { 00942 if (m_SeqHandle != NULL) { 00943 if(port->getPortInfo()->getClient() == getClientId()) 00944 { 00945 return; 00946 } 00947 CHECK_ERROR(snd_seq_delete_port(m_SeqHandle, port->getPortInfo()->getPort())); 00948 port->setMidiClient(NULL); 00949 00950 MidiPortList::iterator it; 00951 for(it = m_Ports.begin(); it != m_Ports.end(); ++it) 00952 { 00953 if ((*it)->getPortInfo()->getPort() == port->getPortInfo()->getPort()) 00954 { 00955 m_Ports.erase(it); 00956 break; 00957 } 00958 } 00959 } 00960 } 00961 00965 void MidiClient::detachAllPorts() 00966 { 00967 if (m_SeqHandle != NULL) { 00968 MidiPortList::iterator it; 00969 for (it = m_Ports.begin(); it != m_Ports.end(); ++it) { 00970 CHECK_ERROR(snd_seq_delete_port(m_SeqHandle, (*it)->getPortInfo()->getPort())); 00971 (*it)->setMidiClient(NULL); 00972 m_Ports.erase(it); 00973 } 00974 } 00975 } 00976 00981 void 00982 MidiClient::addEventFilter(int evtype) 00983 { 00984 snd_seq_set_client_event_filter(m_SeqHandle, evtype); 00985 } 00986 00992 bool 00993 MidiClient::getBroadcastFilter() 00994 { 00995 return m_Info.getBroadcastFilter(); 00996 } 00997 01003 void 01004 MidiClient::setBroadcastFilter(bool newValue) 01005 { 01006 m_Info.setBroadcastFilter(newValue); 01007 applyClientInfo(); 01008 } 01009 01015 bool 01016 MidiClient::getErrorBounce() 01017 { 01018 return m_Info.getErrorBounce(); 01019 } 01020 01026 void 01027 MidiClient::setErrorBounce(bool newValue) 01028 { 01029 m_Info.setErrorBounce(newValue); 01030 applyClientInfo(); 01031 } 01032 01044 void 01045 MidiClient::output(SequencerEvent* ev, bool async, int timeout) 01046 { 01047 int npfds; 01048 pollfd* pfds; 01049 if (async) { 01050 CHECK_WARNING(snd_seq_event_output(m_SeqHandle, ev->getHandle())); 01051 } else { 01052 npfds = snd_seq_poll_descriptors_count(m_SeqHandle, POLLOUT); 01053 pfds = (pollfd*) alloca(npfds * sizeof(pollfd)); 01054 snd_seq_poll_descriptors(m_SeqHandle, pfds, npfds, POLLOUT); 01055 while (snd_seq_event_output(m_SeqHandle, ev->getHandle()) < 0) 01056 { 01057 poll(pfds, npfds, timeout); 01058 } 01059 } 01060 } 01061 01073 void MidiClient::outputDirect(SequencerEvent* ev, bool async, int timeout) 01074 { 01075 int npfds; 01076 pollfd* pfds; 01077 if (async) { 01078 CHECK_WARNING(snd_seq_event_output_direct(m_SeqHandle, ev->getHandle())); 01079 } else { 01080 npfds = snd_seq_poll_descriptors_count(m_SeqHandle, POLLOUT); 01081 pfds = (pollfd*) alloca(npfds * sizeof(pollfd)); 01082 snd_seq_poll_descriptors(m_SeqHandle, pfds, npfds, POLLOUT); 01083 while (snd_seq_event_output_direct(m_SeqHandle, ev->getHandle()) < 0) 01084 { 01085 poll(pfds, npfds, timeout); 01086 } 01087 } 01088 } 01089 01098 void 01099 MidiClient::outputBuffer(SequencerEvent* ev) 01100 { 01101 CHECK_WARNING(snd_seq_event_output_buffer(m_SeqHandle, ev->getHandle())); 01102 } 01103 01115 void MidiClient::drainOutput(bool async, int timeout) 01116 { 01117 int npfds; 01118 pollfd* pfds; 01119 if (async) { 01120 CHECK_WARNING(snd_seq_drain_output(m_SeqHandle)); 01121 } else { 01122 npfds = snd_seq_poll_descriptors_count(m_SeqHandle, POLLOUT); 01123 pfds = (pollfd*) alloca(npfds * sizeof(pollfd)); 01124 snd_seq_poll_descriptors(m_SeqHandle, pfds, npfds, POLLOUT); 01125 while (snd_seq_drain_output(m_SeqHandle) < 0) 01126 { 01127 poll(pfds, npfds, timeout); 01128 } 01129 } 01130 } 01131 01137 void 01138 MidiClient::synchronizeOutput() 01139 { 01140 snd_seq_sync_output_queue(m_SeqHandle); 01141 } 01142 01148 MidiQueue* 01149 MidiClient::getQueue() 01150 { 01151 if (m_Queue == NULL) { 01152 createQueue(); 01153 } 01154 return m_Queue; 01155 } 01156 01161 MidiQueue* 01162 MidiClient::createQueue() 01163 { 01164 if (m_Queue != NULL) { 01165 delete m_Queue; 01166 } 01167 m_Queue = new MidiQueue(this, this); 01168 return m_Queue; 01169 } 01170 01177 MidiQueue* 01178 MidiClient::createQueue(QString const& queueName ) 01179 { 01180 if (m_Queue != NULL) { 01181 delete m_Queue; 01182 } 01183 m_Queue = new MidiQueue(this, queueName, this); 01184 return m_Queue; 01185 } 01186 01194 MidiQueue* 01195 MidiClient::useQueue(int queue_id) 01196 { 01197 if (m_Queue != NULL) { 01198 delete m_Queue; 01199 } 01200 m_Queue = new MidiQueue(this, queue_id, this); 01201 return m_Queue; 01202 } 01203 01211 MidiQueue* 01212 MidiClient::useQueue(const QString& name) 01213 { 01214 if (m_Queue != NULL) { 01215 delete m_Queue; 01216 } 01217 int queue_id = getQueueId(name); 01218 if ( queue_id >= 0) { 01219 m_Queue = new MidiQueue(this, queue_id, this); 01220 } 01221 return m_Queue; 01222 } 01223 01230 MidiQueue* 01231 MidiClient::useQueue(MidiQueue* queue) 01232 { 01233 if (m_Queue != NULL) { 01234 delete m_Queue; 01235 } 01236 queue->setParent(this); 01237 m_Queue = queue; 01238 return m_Queue; 01239 } 01240 01245 QList<int> 01246 MidiClient::getAvailableQueues() 01247 { 01248 int q, err, max; 01249 QList<int> queues; 01250 snd_seq_queue_info_t* qinfo; 01251 snd_seq_queue_info_alloca(&qinfo); 01252 max = getSystemInfo().getMaxQueues(); 01253 for ( q = 0; q < max; ++q ) { 01254 err = snd_seq_get_queue_info(m_SeqHandle, q, qinfo); 01255 if (err == 0) { 01256 queues.append(q); 01257 } 01258 } 01259 return queues; 01260 } 01261 01269 PortInfoList 01270 MidiClient::filterPorts(unsigned int filter) 01271 { 01272 PortInfoList result; 01273 ClientInfoList::ConstIterator itc; 01274 PortInfoList::ConstIterator itp; 01275 01276 if (m_NeedRefreshClientList) 01277 readClients(); 01278 01279 for (itc = m_ClientList.constBegin(); itc != m_ClientList.constEnd(); ++itc) { 01280 ClientInfo ci = (*itc); 01281 if ((ci.getClientId() == SND_SEQ_CLIENT_SYSTEM) || 01282 (ci.getClientId() == m_Info.getClientId())) 01283 continue; 01284 PortInfoList lstPorts = ci.getPorts(); 01285 for(itp = lstPorts.constBegin(); itp != lstPorts.constEnd(); ++itp) { 01286 PortInfo pi = (*itp); 01287 unsigned int cap = pi.getCapability(); 01288 if ( ((filter & cap) != 0) && 01289 ((SND_SEQ_PORT_CAP_NO_EXPORT & cap) == 0) ) { 01290 result.append(pi); 01291 } 01292 } 01293 } 01294 return result; 01295 } 01296 01300 void 01301 MidiClient::updateAvailablePorts() 01302 { 01303 m_InputsAvail.clear(); 01304 m_OutputsAvail.clear(); 01305 m_InputsAvail = filterPorts( SND_SEQ_PORT_CAP_READ | 01306 SND_SEQ_PORT_CAP_SUBS_READ ); 01307 m_OutputsAvail = filterPorts( SND_SEQ_PORT_CAP_WRITE | 01308 SND_SEQ_PORT_CAP_SUBS_WRITE ); 01309 } 01310 01315 PortInfoList 01316 MidiClient::getAvailableInputs() 01317 { 01318 m_NeedRefreshClientList = true; 01319 updateAvailablePorts(); 01320 return m_InputsAvail; 01321 } 01322 01327 PortInfoList 01328 MidiClient::getAvailableOutputs() 01329 { 01330 m_NeedRefreshClientList = true; 01331 updateAvailablePorts(); 01332 return m_OutputsAvail; 01333 } 01334 01341 void 01342 MidiClient::addListener(QObject* listener) 01343 { 01344 m_listeners.append(listener); 01345 } 01346 01352 void 01353 MidiClient::removeListener(QObject* listener) 01354 { 01355 m_listeners.removeAll(listener); 01356 } 01357 01364 void 01365 MidiClient::setEventsEnabled(bool bEnabled) 01366 { 01367 if (bEnabled != m_eventsEnabled) { 01368 m_eventsEnabled = bEnabled; 01369 } 01370 } 01371 01376 SystemInfo& 01377 MidiClient::getSystemInfo() 01378 { 01379 snd_seq_system_info(m_SeqHandle, m_sysInfo.m_Info); 01380 return m_sysInfo; 01381 } 01382 01387 PoolInfo& 01388 MidiClient::getPoolInfo() 01389 { 01390 snd_seq_get_client_pool(m_SeqHandle, m_poolInfo.m_Info); 01391 return m_poolInfo; 01392 } 01393 01398 void 01399 MidiClient::setPoolInfo(const PoolInfo& info) 01400 { 01401 m_poolInfo = info; 01402 CHECK_WARNING(snd_seq_set_client_pool(m_SeqHandle, m_poolInfo.m_Info)); 01403 } 01404 01409 void 01410 MidiClient::resetPoolInput() 01411 { 01412 CHECK_WARNING(snd_seq_reset_pool_input(m_SeqHandle)); 01413 } 01414 01419 void 01420 MidiClient::resetPoolOutput() 01421 { 01422 CHECK_WARNING(snd_seq_reset_pool_output(m_SeqHandle)); 01423 } 01424 01429 void 01430 MidiClient::setPoolInput(int size) 01431 { 01432 CHECK_WARNING(snd_seq_set_client_pool_input(m_SeqHandle, size)); 01433 } 01434 01439 void 01440 MidiClient::setPoolOutput(int size) 01441 { 01442 CHECK_WARNING(snd_seq_set_client_pool_output(m_SeqHandle, size)); 01443 } 01444 01449 void 01450 MidiClient::setPoolOutputRoom(int size) 01451 { 01452 CHECK_WARNING(snd_seq_set_client_pool_output_room(m_SeqHandle, size)); 01453 } 01454 01459 void 01460 MidiClient::dropInput() 01461 { 01462 CHECK_WARNING(snd_seq_drop_input(m_SeqHandle)); 01463 } 01464 01469 void 01470 MidiClient::dropInputBuffer() 01471 { 01472 CHECK_WARNING(snd_seq_drop_input_buffer(m_SeqHandle)); 01473 } 01474 01482 void 01483 MidiClient::dropOutput() 01484 { 01485 CHECK_WARNING(snd_seq_drop_output(m_SeqHandle)); 01486 } 01487 01495 void 01496 MidiClient::dropOutputBuffer() 01497 { 01498 CHECK_WARNING(snd_seq_drop_output_buffer(m_SeqHandle)); 01499 } 01500 01507 void 01508 MidiClient::removeEvents(const RemoveEvents* spec) 01509 { 01510 CHECK_WARNING(snd_seq_remove_events(m_SeqHandle, spec->m_Info)); 01511 } 01512 01517 SequencerEvent* 01518 MidiClient::extractOutput() 01519 { 01520 snd_seq_event_t* ev; 01521 if (CHECK_WARNING(snd_seq_extract_output(m_SeqHandle, &ev) == 0)) { 01522 return new SequencerEvent(ev); 01523 } 01524 return NULL; 01525 } 01526 01532 int 01533 MidiClient::outputPending() 01534 { 01535 return snd_seq_event_output_pending(m_SeqHandle); 01536 } 01537 01551 int 01552 MidiClient::inputPending(bool fetch) 01553 { 01554 return snd_seq_event_input_pending(m_SeqHandle, fetch ? 1 : 0); 01555 } 01556 01563 int 01564 MidiClient::getQueueId(const QString& name) 01565 { 01566 return snd_seq_query_named_queue(m_SeqHandle, name.toLocal8Bit().data()); 01567 } 01568 01574 int 01575 MidiClient::getPollDescriptorsCount(short events) 01576 { 01577 return snd_seq_poll_descriptors_count(m_SeqHandle, events); 01578 } 01579 01593 int 01594 MidiClient::pollDescriptors( struct pollfd *pfds, unsigned int space, 01595 short events ) 01596 { 01597 return snd_seq_poll_descriptors(m_SeqHandle, pfds, space, events); 01598 } 01599 01606 unsigned short 01607 MidiClient::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds) 01608 { 01609 unsigned short revents; 01610 CHECK_WARNING( snd_seq_poll_descriptors_revents( m_SeqHandle, 01611 pfds, nfds, 01612 &revents )); 01613 return revents; 01614 } 01615 01620 const char * 01621 MidiClient::_getDeviceName() 01622 { 01623 return snd_seq_name(m_SeqHandle); 01624 } 01625 01630 void 01631 MidiClient::_setClientName(const char *name) 01632 { 01633 CHECK_WARNING(snd_seq_set_client_name(m_SeqHandle, name)); 01634 } 01635 01643 int 01644 MidiClient::createSimplePort( const char *name, 01645 unsigned int caps, 01646 unsigned int type ) 01647 { 01648 return CHECK_WARNING( snd_seq_create_simple_port( m_SeqHandle, 01649 name, caps, type )); 01650 } 01651 01656 void 01657 MidiClient::deleteSimplePort(int port) 01658 { 01659 CHECK_WARNING( snd_seq_delete_simple_port( m_SeqHandle, port )); 01660 } 01661 01668 void 01669 MidiClient::connectFrom(int myport, int client, int port) 01670 { 01671 CHECK_WARNING( snd_seq_connect_from(m_SeqHandle, myport, client, port )); 01672 } 01673 01680 void 01681 MidiClient::connectTo(int myport, int client, int port) 01682 { 01683 CHECK_WARNING( snd_seq_connect_to(m_SeqHandle, myport, client, port )); 01684 } 01685 01692 void 01693 MidiClient::disconnectFrom(int myport, int client, int port) 01694 { 01695 CHECK_WARNING( snd_seq_disconnect_from(m_SeqHandle, myport, client, port )); 01696 } 01697 01704 void 01705 MidiClient::disconnectTo(int myport, int client, int port) 01706 { 01707 CHECK_WARNING( snd_seq_disconnect_to(m_SeqHandle, myport, client, port )); 01708 } 01709 01721 bool 01722 MidiClient::parseAddress( const QString& straddr, snd_seq_addr& addr ) 01723 { 01724 bool ok(false); 01725 QString testClient, testPort; 01726 ClientInfoList::ConstIterator cit; 01727 int pos = straddr.indexOf(':'); 01728 if (pos > -1) { 01729 testClient = straddr.left(pos); 01730 testPort = straddr.mid(pos+1); 01731 } else { 01732 testClient = straddr; 01733 testPort = '0'; 01734 } 01735 addr.client = testClient.toInt(&ok); 01736 if (ok) 01737 addr.port = testPort.toInt(&ok); 01738 if (!ok) { 01739 if (m_NeedRefreshClientList) 01740 readClients(); 01741 for ( cit = m_ClientList.constBegin(); 01742 cit != m_ClientList.constEnd(); ++cit ) { 01743 ClientInfo ci = *cit; 01744 if (testClient.compare(ci.getName(), Qt::CaseInsensitive) == 0) { 01745 addr.client = ci.getClientId(); 01746 addr.port = testPort.toInt(&ok); 01747 return ok; 01748 } 01749 } 01750 } 01751 return ok; 01752 } 01753 01758 bool 01759 MidiClient::SequencerInputThread::stopped() 01760 { 01761 QReadLocker locker(&m_mutex); 01762 return m_Stopped; 01763 } 01764 01768 void 01769 MidiClient::SequencerInputThread::stop() 01770 { 01771 QWriteLocker locker(&m_mutex); 01772 m_Stopped = true; 01773 } 01774 01775 #if defined(RTKIT_SUPPORT) 01776 static pid_t _gettid(void) { 01777 return (pid_t) ::syscall(SYS_gettid); 01778 } 01779 #endif 01780 01781 void 01782 MidiClient::SequencerInputThread::setRealtimePriority() 01783 { 01784 struct sched_param p; 01785 int rt, policy = SCHED_RR | SCHED_RESET_ON_FORK; 01786 quint32 priority = 6; 01787 #if defined(RTKIT_SUPPORT) 01788 bool ok; 01789 quint32 max_prio; 01790 quint64 thread; 01791 struct rlimit old_limit, new_limit; 01792 long long max_rttime; 01793 #endif 01794 01795 ::memset(&p, 0, sizeof(p)); 01796 p.sched_priority = priority; 01797 rt = ::pthread_setschedparam(::pthread_self(), policy, &p); 01798 if (rt != 0) { 01799 #if defined(RTKIT_SUPPORT) 01800 const QString rtkit_service = 01801 QLatin1String("org.freedesktop.RealtimeKit1"); 01802 const QString rtkit_path = 01803 QLatin1String("/org/freedesktop/RealtimeKit1"); 01804 const QString rtkit_iface = rtkit_service; 01805 thread = _gettid(); 01806 QDBusConnection bus = QDBusConnection::systemBus(); 01807 QDBusInterface realtimeKit(rtkit_service, rtkit_path, rtkit_iface, bus); 01808 QVariant maxRTPrio = realtimeKit.property("MaxRealtimePriority"); 01809 max_prio = maxRTPrio.toUInt(&ok); 01810 if (!ok) { 01811 qWarning() << "invalid property RealtimeKit.MaxRealtimePriority"; 01812 return; 01813 } 01814 if (priority > max_prio) 01815 priority = max_prio; 01816 QVariant maxRTNSec = realtimeKit.property("RTTimeNSecMax"); 01817 max_rttime = maxRTNSec.toLongLong(&ok); 01818 if (!ok || max_rttime < 0) { 01819 qWarning() << "invalid property RealtimeKit.RTTimeNSecMax"; 01820 return; 01821 } 01822 new_limit.rlim_cur = new_limit.rlim_max = max_rttime; 01823 rt = ::getrlimit(RLIMIT_RTTIME, &old_limit); 01824 if (rt < 0) { 01825 qWarning() << "getrlimit() failed. err=" << rt << ::strerror(rt); 01826 return; 01827 } 01828 rt = ::setrlimit(RLIMIT_RTTIME, &new_limit); 01829 if ( rt < 0) { 01830 qWarning() << "setrlimit() failed, err=" << rt << ::strerror(rt); 01831 return; 01832 } 01833 QDBusMessage reply = realtimeKit.call("MakeThreadRealtime", thread, priority); 01834 if (reply.type() == QDBusMessage::ErrorMessage ) 01835 qWarning() << "error returned by RealtimeKit.MakeThreadRealtime:" 01836 << reply.errorMessage(); 01837 #else 01838 qWarning() << "pthread_setschedparam() failed, err=" 01839 << rt << ::strerror(rt); 01840 #endif 01841 } 01842 } 01843 01847 void 01848 MidiClient::SequencerInputThread::run() 01849 { 01850 unsigned long npfd; 01851 pollfd* pfd; 01852 if ( priority() == TimeCriticalPriority ) 01853 setRealtimePriority(); 01854 01855 if (m_MidiClient != NULL) { 01856 npfd = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLIN); 01857 pfd = (pollfd *) alloca(npfd * sizeof(pollfd)); 01858 try 01859 { 01860 snd_seq_poll_descriptors(m_MidiClient->getHandle(), pfd, npfd, POLLIN); 01861 while (!stopped() && (m_MidiClient != NULL)) 01862 { 01863 int rt = poll(pfd, npfd, m_Wait); 01864 if (rt > 0) { 01865 m_MidiClient->doEvents(); 01866 } 01867 } 01868 } 01869 catch (...) 01870 { 01871 qWarning() << "exception in input thread"; 01872 } 01873 } 01874 } 01875 01879 ClientInfo::ClientInfo() 01880 { 01881 snd_seq_client_info_malloc(&m_Info); 01882 } 01883 01888 ClientInfo::ClientInfo(const ClientInfo& other) 01889 { 01890 snd_seq_client_info_malloc(&m_Info); 01891 snd_seq_client_info_copy(m_Info, other.m_Info); 01892 m_Ports = other.m_Ports; 01893 } 01894 01899 ClientInfo::ClientInfo(snd_seq_client_info_t* other) 01900 { 01901 snd_seq_client_info_malloc(&m_Info); 01902 snd_seq_client_info_copy(m_Info, other); 01903 } 01904 01910 ClientInfo::ClientInfo(MidiClient* seq, int id) 01911 { 01912 snd_seq_client_info_malloc(&m_Info); 01913 snd_seq_get_any_client_info(seq->getHandle(), id, m_Info); 01914 } 01915 01919 ClientInfo::~ClientInfo() 01920 { 01921 freePorts(); 01922 snd_seq_client_info_free(m_Info); 01923 } 01924 01929 ClientInfo* 01930 ClientInfo::clone() 01931 { 01932 return new ClientInfo(m_Info); 01933 } 01934 01940 ClientInfo& 01941 ClientInfo::operator=(const ClientInfo& other) 01942 { 01943 snd_seq_client_info_copy(m_Info, other.m_Info); 01944 m_Ports = other.m_Ports; 01945 return *this; 01946 } 01947 01952 int 01953 ClientInfo::getClientId() 01954 { 01955 return snd_seq_client_info_get_client(m_Info); 01956 } 01957 01962 snd_seq_client_type_t 01963 ClientInfo::getClientType() 01964 { 01965 return snd_seq_client_info_get_type(m_Info); 01966 } 01967 01972 QString 01973 ClientInfo::getName() 01974 { 01975 return QString(snd_seq_client_info_get_name(m_Info)); 01976 } 01977 01982 bool 01983 ClientInfo::getBroadcastFilter() 01984 { 01985 return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0); 01986 } 01987 01992 bool 01993 ClientInfo::getErrorBounce() 01994 { 01995 return (snd_seq_client_info_get_error_bounce(m_Info) != 0); 01996 } 01997 02003 const unsigned char* 02004 ClientInfo::getEventFilter() 02005 { 02006 return snd_seq_client_info_get_event_filter(m_Info); 02007 } 02008 02013 int 02014 ClientInfo::getNumPorts() 02015 { 02016 return snd_seq_client_info_get_num_ports(m_Info); 02017 } 02018 02023 int 02024 ClientInfo::getEventLost() 02025 { 02026 return snd_seq_client_info_get_event_lost(m_Info); 02027 } 02028 02033 void 02034 ClientInfo::setClient(int client) 02035 { 02036 snd_seq_client_info_set_client(m_Info, client); 02037 } 02038 02043 void 02044 ClientInfo::setName(QString name) 02045 { 02046 snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data()); 02047 } 02048 02053 void 02054 ClientInfo::setBroadcastFilter(bool val) 02055 { 02056 snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0); 02057 } 02058 02063 void 02064 ClientInfo::setErrorBounce(bool val) 02065 { 02066 snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0); 02067 } 02068 02074 void 02075 ClientInfo::setEventFilter(unsigned char *filter) 02076 { 02077 snd_seq_client_info_set_event_filter(m_Info, filter); 02078 } 02079 02084 void 02085 ClientInfo::readPorts(MidiClient* seq) 02086 { 02087 PortInfo info; 02088 freePorts(); 02089 info.setClient(getClientId()); 02090 info.setClientName(getName()); 02091 info.setPort(-1); 02092 while (snd_seq_query_next_port(seq->getHandle(), info.m_Info) >= 0) { 02093 info.readSubscribers(seq); 02094 m_Ports.append(info); 02095 } 02096 } 02097 02101 void 02102 ClientInfo::freePorts() 02103 { 02104 m_Ports.clear(); 02105 } 02106 02111 PortInfoList 02112 ClientInfo::getPorts() const 02113 { 02114 PortInfoList lst = m_Ports; // copy 02115 return lst; 02116 } 02117 02122 int 02123 ClientInfo::getSizeOfInfo() const 02124 { 02125 return snd_seq_client_info_sizeof(); 02126 } 02127 02128 #if SND_LIB_VERSION > 0x010010 02129 02134 void 02135 ClientInfo::addFilter(int eventType) 02136 { 02137 snd_seq_client_info_event_filter_add(m_Info, eventType); 02138 } 02139 02145 bool 02146 ClientInfo::isFiltered(int eventType) 02147 { 02148 return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0); 02149 } 02150 02154 void 02155 ClientInfo::clearFilter() 02156 { 02157 snd_seq_client_info_event_filter_clear(m_Info); 02158 } 02159 02164 void 02165 ClientInfo::removeFilter(int eventType) 02166 { 02167 snd_seq_client_info_event_filter_del(m_Info, eventType); 02168 } 02169 #endif 02170 02174 SystemInfo::SystemInfo() 02175 { 02176 snd_seq_system_info_malloc(&m_Info); 02177 } 02178 02183 SystemInfo::SystemInfo(const SystemInfo& other) 02184 { 02185 snd_seq_system_info_malloc(&m_Info); 02186 snd_seq_system_info_copy(m_Info, other.m_Info); 02187 } 02188 02193 SystemInfo::SystemInfo(snd_seq_system_info_t* other) 02194 { 02195 snd_seq_system_info_malloc(&m_Info); 02196 snd_seq_system_info_copy(m_Info, other); 02197 } 02198 02203 SystemInfo::SystemInfo(MidiClient* seq) 02204 { 02205 snd_seq_system_info_malloc(&m_Info); 02206 snd_seq_system_info(seq->getHandle(), m_Info); 02207 } 02208 02212 SystemInfo::~SystemInfo() 02213 { 02214 snd_seq_system_info_free(m_Info); 02215 } 02216 02221 SystemInfo* 02222 SystemInfo::clone() 02223 { 02224 return new SystemInfo(m_Info); 02225 } 02226 02232 SystemInfo& 02233 SystemInfo::operator=(const SystemInfo& other) 02234 { 02235 snd_seq_system_info_copy(m_Info, other.m_Info); 02236 return *this; 02237 } 02238 02243 int SystemInfo::getMaxClients() 02244 { 02245 return snd_seq_system_info_get_clients(m_Info); 02246 } 02247 02252 int SystemInfo::getMaxPorts() 02253 { 02254 return snd_seq_system_info_get_ports(m_Info); 02255 } 02256 02261 int SystemInfo::getMaxQueues() 02262 { 02263 return snd_seq_system_info_get_queues(m_Info); 02264 } 02265 02270 int SystemInfo::getMaxChannels() 02271 { 02272 return snd_seq_system_info_get_channels(m_Info); 02273 } 02274 02279 int SystemInfo::getCurrentQueues() 02280 { 02281 return snd_seq_system_info_get_cur_queues(m_Info); 02282 } 02283 02288 int SystemInfo::getCurrentClients() 02289 { 02290 return snd_seq_system_info_get_cur_clients(m_Info); 02291 } 02292 02297 int SystemInfo::getSizeOfInfo() const 02298 { 02299 return snd_seq_system_info_sizeof(); 02300 } 02301 02305 PoolInfo::PoolInfo() 02306 { 02307 snd_seq_client_pool_malloc(&m_Info); 02308 } 02309 02314 PoolInfo::PoolInfo(const PoolInfo& other) 02315 { 02316 snd_seq_client_pool_malloc(&m_Info); 02317 snd_seq_client_pool_copy(m_Info, other.m_Info); 02318 } 02319 02324 PoolInfo::PoolInfo(snd_seq_client_pool_t* other) 02325 { 02326 snd_seq_client_pool_malloc(&m_Info); 02327 snd_seq_client_pool_copy(m_Info, other); 02328 } 02329 02334 PoolInfo::PoolInfo(MidiClient* seq) 02335 { 02336 snd_seq_client_pool_malloc(&m_Info); 02337 snd_seq_get_client_pool(seq->getHandle(), m_Info); 02338 } 02339 02343 PoolInfo::~PoolInfo() 02344 { 02345 snd_seq_client_pool_free(m_Info); 02346 } 02347 02352 PoolInfo* 02353 PoolInfo::clone() 02354 { 02355 return new PoolInfo(m_Info); 02356 } 02357 02363 PoolInfo& PoolInfo::operator=(const PoolInfo& other) 02364 { 02365 snd_seq_client_pool_copy(m_Info, other.m_Info); 02366 return *this; 02367 } 02368 02373 int 02374 PoolInfo::getClientId() 02375 { 02376 return snd_seq_client_pool_get_client(m_Info); 02377 } 02378 02383 int 02384 PoolInfo::getInputFree() 02385 { 02386 return snd_seq_client_pool_get_input_free(m_Info); 02387 } 02388 02393 int 02394 PoolInfo::getInputPool() 02395 { 02396 return snd_seq_client_pool_get_input_pool(m_Info); 02397 } 02398 02403 int 02404 PoolInfo::getOutputFree() 02405 { 02406 return snd_seq_client_pool_get_output_free(m_Info); 02407 } 02408 02413 int 02414 PoolInfo::getOutputPool() 02415 { 02416 return snd_seq_client_pool_get_output_pool(m_Info); 02417 } 02418 02424 int 02425 PoolInfo::getOutputRoom() 02426 { 02427 return snd_seq_client_pool_get_output_room(m_Info); 02428 } 02429 02434 void 02435 PoolInfo::setInputPool(int size) 02436 { 02437 snd_seq_client_pool_set_input_pool(m_Info, size); 02438 } 02439 02444 void 02445 PoolInfo::setOutputPool(int size) 02446 { 02447 snd_seq_client_pool_set_output_pool(m_Info, size); 02448 } 02449 02456 void 02457 PoolInfo::setOutputRoom(int size) 02458 { 02459 snd_seq_client_pool_set_output_room(m_Info, size); 02460 } 02461 02466 int 02467 PoolInfo::getSizeOfInfo() const 02468 { 02469 return snd_seq_client_pool_sizeof(); 02470 } 02471 02472 #if SND_LIB_VERSION > 0x010004 02473 02478 QString 02479 getRuntimeALSALibraryVersion() 02480 { 02481 return QString(snd_asoundlib_version()); 02482 } 02483 02489 int 02490 getRuntimeALSALibraryNumber() 02491 { 02492 QRegExp rx("(\\d+)"); 02493 QString str = getRuntimeALSALibraryVersion(); 02494 bool ok; 02495 int pos = 0, result = 0, j = 0; 02496 while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) { 02497 int v = rx.cap(1).toInt(&ok); 02498 if (ok) { 02499 result <<= 8; 02500 result += v; 02501 } 02502 pos += rx.matchedLength(); 02503 j++; 02504 } 02505 return result; 02506 } 02507 #endif // SND_LIB_VERSION > 0x010004 02508 02514 QString 02515 getRuntimeALSADriverVersion() 02516 { 02517 QRegExp rx(".*Driver Version ([\\d\\.]+).*"); 02518 QString s; 02519 QFile f("/proc/asound/version"); 02520 if (f.open(QFile::ReadOnly)) { 02521 QTextStream str(&f); 02522 if (rx.exactMatch(str.readLine().trimmed())) 02523 s = rx.cap(1); 02524 } 02525 return s; 02526 } 02527 02533 int 02534 getRuntimeALSADriverNumber() 02535 { 02536 QRegExp rx("(\\d+)"); 02537 QString str = getRuntimeALSADriverVersion(); 02538 bool ok; 02539 int pos = 0, result = 0, j = 0; 02540 while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) { 02541 int v = rx.cap(1).toInt(&ok); 02542 if (ok) { 02543 result <<= 8; 02544 result += v; 02545 } 02546 pos += rx.matchedLength(); 02547 j++; 02548 } 02549 return result; 02550 } 02551 02552 } /* namespace drumstick */