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 "playthread.h" 00021 #include "alsaclient.h" 00022 #include "alsaqueue.h" 00023 #include <QReadLocker> 00024 #include <QWriteLocker> 00025 00031 namespace drumstick { 00032 00056 const int TIMEOUT = 100; 00057 00063 SequencerOutputThread::SequencerOutputThread(MidiClient *seq, int portId) 00064 : QThread(), 00065 m_MidiClient(seq), 00066 m_Queue(0), 00067 m_PortId(portId), 00068 m_Stopped(false), 00069 m_QueueId(0), 00070 m_npfds(0), 00071 m_pfds(0) 00072 { 00073 if (m_MidiClient != NULL) { 00074 m_Queue = m_MidiClient->getQueue(); 00075 m_QueueId = m_Queue->getId(); 00076 } 00077 } 00078 00084 bool 00085 SequencerOutputThread::stopRequested() 00086 { 00087 QReadLocker locker(&m_mutex); 00088 return m_Stopped; 00089 } 00090 00094 void 00095 SequencerOutputThread::stop() 00096 { 00097 QWriteLocker locker(&m_mutex); 00098 m_Stopped = true; 00099 locker.unlock(); 00100 while (isRunning()) 00101 wait(TIMEOUT); 00102 } 00103 00108 void 00109 SequencerOutputThread::sendEchoEvent(int tick) 00110 { 00111 if (!stopRequested() && m_MidiClient != NULL) { 00112 SystemEvent ev(SND_SEQ_EVENT_ECHO); 00113 ev.setSource(m_PortId); 00114 ev.setDestination(m_MidiClient->getClientId(), m_PortId); 00115 ev.scheduleTick(m_QueueId, tick, false); 00116 sendSongEvent(&ev); 00117 } 00118 } 00119 00124 void 00125 SequencerOutputThread::sendSongEvent(SequencerEvent* ev) 00126 { 00127 if (m_MidiClient != NULL) { 00128 while (!stopRequested() && 00129 (snd_seq_event_output_direct(m_MidiClient->getHandle(), ev->getHandle()) < 0)) 00130 poll(m_pfds, m_npfds, TIMEOUT); 00131 } 00132 } 00133 00137 void 00138 SequencerOutputThread::drainOutput() 00139 { 00140 if (m_MidiClient != NULL) { 00141 while (!stopRequested() && 00142 (snd_seq_drain_output(m_MidiClient->getHandle()) < 0)) 00143 poll(m_pfds, m_npfds, TIMEOUT); 00144 } 00145 } 00146 00150 void 00151 SequencerOutputThread::syncOutput() 00152 { 00153 if (!stopRequested() && m_MidiClient != NULL) { 00154 QueueStatus status = m_Queue->getStatus(); 00155 while (!stopRequested() && (status.getEvents() > 0)) { 00156 usleep(TIMEOUT); 00157 status = m_Queue->getStatus(); 00158 } 00159 } 00160 } 00161 00165 void SequencerOutputThread::run() 00166 { 00167 unsigned int last_tick; 00168 if (m_MidiClient != NULL) { 00169 try { 00170 m_npfds = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLOUT); 00171 m_pfds = (pollfd*) alloca(m_npfds * sizeof(pollfd)); 00172 snd_seq_poll_descriptors(m_MidiClient->getHandle(), m_pfds, m_npfds, POLLOUT); 00173 last_tick = getInitialPosition(); 00174 if (last_tick == 0) { 00175 m_Queue->start(); 00176 } else { 00177 m_Queue->setTickPosition(last_tick); 00178 m_Queue->continueRunning(); 00179 } 00180 while (!stopRequested() && hasNext()) { 00181 SequencerEvent* ev = nextEvent(); 00182 if (getEchoResolution() > 0) { 00183 while (!stopRequested() && (last_tick < ev->getTick())) { 00184 last_tick += getEchoResolution(); 00185 sendEchoEvent(last_tick); 00186 } 00187 } 00188 if (!stopRequested() && !SequencerEvent::isConnectionChange(ev)) 00189 sendSongEvent(ev); 00190 } 00191 if (stopRequested()) { 00192 m_Queue->clear(); 00193 emit stopped(); 00194 } else { 00195 drainOutput(); 00196 syncOutput(); 00197 if (stopRequested()) 00198 emit stopped(); 00199 else 00200 emit finished(); 00201 } 00202 m_Queue->stop(); 00203 } catch (...) { 00204 qWarning("exception in output thread"); 00205 } 00206 m_npfds = 0; 00207 m_pfds = 0; 00208 } 00209 } 00210 00215 void SequencerOutputThread::start( Priority priority ) 00216 { 00217 QWriteLocker locker(&m_mutex); 00218 m_Stopped = false; 00219 QThread::start( priority ); 00220 } 00221 00222 } /* namespace drumstick */ 00223