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.
void setTickPosition(snd_seq_tick_time_t pos)
Sets the queue position in musical time (ticks).
void continueRunning()
Start the queue without resetting the last position.
QueueStatus & getStatus()
Gets a QueueStatus object reference.
void start()
Start the queue.
void stop()
Stop the queue.
void clear()
Clear the queue, dropping any scheduled events.
Queue status container.
Definition alsaqueue.h:81
int getEvents()
Gets the number of queued events.
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.
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.
void setDestination(const unsigned char client, const unsigned char port)
Sets the client:port destination of the event.
void setSource(const unsigned char port)
Sets the event's source port ID.
virtual SequencerEvent * nextEvent()=0
Gets the next event in the sequence.
virtual void run()
Thread process loop.
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.
SequencerOutputThread(MidiClient *seq, int portId)
Constructor.
virtual void syncOutput()
Waits until the ALSA output queue is empty (all the events have been played.)
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.
virtual void sendSongEvent(SequencerEvent *ev)
Sends a SequencerEvent.
virtual void drainOutput()
Flush the ALSA output buffer.
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.
virtual bool stopRequested()
Checks if stop has been requested.
void finished()
Signal emitted when the sequence play-back has finished.
Generic event.
Definition alsaevent.h:439
Sequencer output thread.