drumstick 0.5.0
playthread.cpp
Go to the documentation of this file.
1/*
2 MIDI Sequencer C++ library
3 Copyright (C) 2006-2010, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#include "playthread.h"
21#include "alsaclient.h"
22#include "alsaqueue.h"
23#include <QReadLocker>
24#include <QWriteLocker>
25
31namespace drumstick {
32
56const int TIMEOUT = 100;
57
64 : QThread(),
65 m_MidiClient(seq),
66 m_Queue(0),
67 m_PortId(portId),
68 m_Stopped(false),
69 m_QueueId(0),
70 m_npfds(0),
71 m_pfds(0)
72{
73 if (m_MidiClient != NULL) {
75 m_QueueId = m_Queue->getId();
76 }
77}
78
84bool
86{
87 QReadLocker locker(&m_mutex);
88 return m_Stopped;
89}
90
94void
96{
97 QWriteLocker locker(&m_mutex);
98 m_Stopped = true;
99 locker.unlock();
100 while (isRunning())
101 wait(TIMEOUT);
102}
103
108void
110{
111 if (!stopRequested() && m_MidiClient != NULL) {
112 SystemEvent ev(SND_SEQ_EVENT_ECHO);
115 ev.scheduleTick(m_QueueId, tick, false);
116 sendSongEvent(&ev);
117 }
118}
119
124void
126{
127 if (m_MidiClient != NULL) {
128 while (!stopRequested() &&
129 (snd_seq_event_output_direct(m_MidiClient->getHandle(), ev->getHandle()) < 0))
130 poll(m_pfds, m_npfds, TIMEOUT);
131 }
132}
133
137void
139{
140 if (m_MidiClient != NULL) {
141 while (!stopRequested() &&
142 (snd_seq_drain_output(m_MidiClient->getHandle()) < 0))
143 poll(m_pfds, m_npfds, TIMEOUT);
144 }
145}
146
150void
152{
153 if (!stopRequested() && m_MidiClient != NULL) {
154 QueueStatus status = m_Queue->getStatus();
155 while (!stopRequested() && (status.getEvents() > 0)) {
156 usleep(TIMEOUT);
157 status = m_Queue->getStatus();
158 }
159 }
160}
161
166{
167 unsigned int last_tick;
168 if (m_MidiClient != NULL) {
169 try {
170 m_npfds = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLOUT);
171 m_pfds = (pollfd*) alloca(m_npfds * sizeof(pollfd));
172 snd_seq_poll_descriptors(m_MidiClient->getHandle(), m_pfds, m_npfds, POLLOUT);
173 last_tick = getInitialPosition();
174 if (last_tick == 0) {
175 m_Queue->start();
176 } else {
177 m_Queue->setTickPosition(last_tick);
179 }
180 while (!stopRequested() && hasNext()) {
182 if (getEchoResolution() > 0) {
183 while (!stopRequested() && (last_tick < ev->getTick())) {
184 last_tick += getEchoResolution();
185 sendEchoEvent(last_tick);
186 }
187 }
189 sendSongEvent(ev);
190 }
191 if (stopRequested()) {
192 m_Queue->clear();
193 emit stopped();
194 } else {
195 drainOutput();
196 syncOutput();
197 if (stopRequested())
198 emit stopped();
199 else
200 emit finished();
201 }
202 m_Queue->stop();
203 } catch (...) {
204 qWarning("exception in output thread");
205 }
206 m_npfds = 0;
207 m_pfds = 0;
208 }
209}
210
215void SequencerOutputThread::start( Priority priority )
216{
217 QWriteLocker locker(&m_mutex);
218 m_Stopped = false;
219 QThread::start( priority );
220}
221
222} /* namespace drumstick */
223
Classes managing ALSA Sequencer clients.
Classes managing ALSA Sequencer queues.
The QThread class provides platform-independent threads.
Client management.
Definition: alsaclient.h:199
MidiQueue * getQueue()
Get the MidiQueue instance associated to this client.
snd_seq_t * getHandle()
Returns the sequencer handler managed by ALSA.
Definition: alsaclient.h:235
int getClientId()
Gets the client ID.
Definition: alsaclient.cpp:602
void setTickPosition(snd_seq_tick_time_t pos)
Sets the queue position in musical time (ticks).
Definition: alsaqueue.cpp:890
void continueRunning()
Start the queue without resetting the last position.
Definition: alsaqueue.cpp:871
QueueStatus & getStatus()
Gets a QueueStatus object reference.
Definition: alsaqueue.cpp:766
void start()
Start the queue.
Definition: alsaqueue.cpp:847
void stop()
Stop the queue.
Definition: alsaqueue.cpp:858
void clear()
Clear the queue, dropping any scheduled events.
Definition: alsaqueue.cpp:880
Queue status container.
Definition: alsaqueue.h:81
int getEvents()
Gets the number of queued events.
Definition: alsaqueue.cpp:273
Base class for the event's hierarchy.
Definition: alsaevent.h:54
static bool isConnectionChange(const SequencerEvent *event)
Checks if the event's type is of type connection change.
Definition: alsaevent.cpp:184
snd_seq_event_t * getHandle()
Gets the handle of the event.
Definition: alsaevent.h:123
void scheduleTick(const int queue, const int tick, const bool relative)
Sets the event to be scheduled in musical time (ticks) units.
Definition: alsaevent.cpp:279
void setDestination(const unsigned char client, const unsigned char port)
Sets the client:port destination of the event.
Definition: alsaevent.cpp:233
void setSource(const unsigned char port)
Sets the event's source port ID.
Definition: alsaevent.cpp:243
virtual SequencerEvent * nextEvent()=0
Gets the next event in the sequence.
virtual void run()
Thread process loop.
Definition: playthread.cpp:165
virtual unsigned int getInitialPosition()
Gets the initial position in ticks of the sequence.
Definition: playthread.h:58
virtual void sendEchoEvent(int tick)
Sends an echo event, with the same PortId as sender and destination.
Definition: playthread.cpp:109
SequencerOutputThread(MidiClient *seq, int portId)
Constructor.
Definition: playthread.cpp:63
virtual void syncOutput()
Waits until the ALSA output queue is empty (all the events have been played.)
Definition: playthread.cpp:151
int m_QueueId
MidiQueue numeric identifier.
Definition: playthread.h:112
MidiClient * m_MidiClient
MidiClient instance pointer.
Definition: playthread.h:108
bool m_Stopped
Stopped status.
Definition: playthread.h:111
virtual void stop()
Stops playing the current sequence.
Definition: playthread.cpp:95
virtual void sendSongEvent(SequencerEvent *ev)
Sends a SequencerEvent.
Definition: playthread.cpp:125
virtual void drainOutput()
Flush the ALSA output buffer.
Definition: playthread.cpp:138
pollfd * m_pfds
Array of pollfd pointers.
Definition: playthread.h:114
QReadWriteLock m_mutex
Mutex object used for synchronization.
Definition: playthread.h:115
MidiQueue * m_Queue
MidiQueue instance pointer.
Definition: playthread.h:109
virtual bool hasNext()=0
Check if there is one more event in the sequence.
virtual unsigned int getEchoResolution()
Gets the echo event resolution in ticks.
Definition: playthread.h:65
void stopped()
Signal emitted when the play-back has stopped.
int m_npfds
Number of pollfd pointers.
Definition: playthread.h:113
int m_PortId
MidiPort numeric identifier.
Definition: playthread.h:110
void start(Priority priority=InheritPriority)
Starts the playback thread.
Definition: playthread.cpp:215
virtual bool stopRequested()
Checks if stop has been requested.
Definition: playthread.cpp:85
void finished()
Signal emitted when the sequence play-back has finished.
Generic event.
Definition: alsaevent.h:439
Sequencer output thread.