00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 }
00223