drumstick  0.5.0
alsaclient.cpp
Go to the documentation of this file.
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 */