drumstick 2.9.0
C++ MIDI libraries using Qt objects, idioms, and style.
playthread.cpp
Go to the documentation of this file.
1/*
2 MIDI Sequencer C++ library
3 Copyright (C) 2006-2023, 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 3 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
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19extern "C" {
20 #include <alsa/asoundlib.h>
21}
22
23#include <QReadLocker>
24#include <QWriteLocker>
26#include <drumstick/alsaqueue.h>
28
57namespace drumstick {
58namespace ALSA {
59
60const int TIMEOUT = 100;
61
68 : QThread(),
69 m_MidiClient(seq),
70 m_Queue(nullptr),
71 m_PortId(portId),
72 m_Stopped(false),
73 m_QueueId(0),
74 m_npfds(0),
75 m_pfds(nullptr)
76{
77 if (m_MidiClient != nullptr) {
79 m_QueueId = m_Queue->getId();
80 }
81}
82
88bool
90{
91 QReadLocker locker(&m_mutex);
92 return m_Stopped;
93}
94
98void
100{
101 QWriteLocker locker(&m_mutex);
102 m_Stopped = true;
103 locker.unlock();
104 while (isRunning()) {
105 wait(TIMEOUT);
106 }
107}
108
113void
115{
116 if (!stopRequested() && m_MidiClient != nullptr) {
117 SystemEvent ev(SND_SEQ_EVENT_ECHO);
120 ev.scheduleTick(m_QueueId, tick, false);
121 sendSongEvent(&ev);
122 }
123}
124
129void
131{
132 if (m_MidiClient != nullptr) {
133 while (!stopRequested() &&
134 (snd_seq_event_output_direct(m_MidiClient->getHandle(), ev->getHandle()) < 0)) {
135 poll(m_pfds, m_npfds, TIMEOUT);
136 }
137 }
138}
139
143void
145{
146 if (!stopRequested() && m_MidiClient != nullptr) {
147 while (!stopRequested() && (snd_seq_drain_output(m_MidiClient->getHandle()) < 0)) {
148 poll(m_pfds, m_npfds, TIMEOUT);
149 }
150 }
151}
152
156void
158{
159 if (!stopRequested() && m_MidiClient != nullptr) {
161 }
162}
163
168{
169 if (m_MidiClient != nullptr) {
170 try {
171 unsigned int last_tick;
172 m_npfds = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLOUT);
173 m_pfds = (pollfd*) calloc(m_npfds, sizeof(pollfd));
174 snd_seq_poll_descriptors(m_MidiClient->getHandle(), m_pfds, m_npfds, POLLOUT);
175 last_tick = getInitialPosition();
176 if (last_tick == 0) {
177 m_Queue->start();
178 } else {
179 m_Queue->setTickPosition(last_tick);
181 }
182 while (!stopRequested() && hasNext()) {
185 sendSongEvent(ev);
186 }
187 if (getEchoResolution() > 0) {
188 while (!stopRequested() && (last_tick < ev->getTick())) {
189 last_tick += getEchoResolution();
190 sendEchoEvent(last_tick);
191 }
192 }
193 }
194 if (stopRequested()) {
195 m_Queue->clear();
196 Q_EMIT playbackStopped();
197 } else {
198 drainOutput();
199 syncOutput();
200 if (stopRequested())
201 Q_EMIT playbackStopped();
202 else
203 Q_EMIT playbackFinished();
204 }
205 m_Queue->stop();
206 } catch (...) {
207 qWarning("exception in output thread");
208 }
209 m_npfds = 0;
210 free(m_pfds);
211 m_pfds = nullptr;
212 }
213}
214
219void SequencerOutputThread::start( Priority priority )
220{
221 QWriteLocker locker(&m_mutex);
222 m_Stopped = false;
223 QThread::start( priority );
224}
225
226} // namespace ALSA
227} // namespace drumstick
228
229
Classes managing ALSA Sequencer clients.
Classes managing ALSA Sequencer queues.
The QThread class provides platform-independent threads.
Client management.
Definition: alsaclient.h:219
void setTickPosition(snd_seq_tick_time_t pos)
Sets the queue position in musical time (ticks).
Definition: alsaqueue.cpp:905
void continueRunning()
Start the queue without resetting the last position.
Definition: alsaqueue.cpp:886
void start()
Start the queue.
Definition: alsaqueue.cpp:862
void stop()
Stop the queue.
Definition: alsaqueue.cpp:873
void clear()
Clear the queue, dropping any scheduled events.
Definition: alsaqueue.cpp:895
Base class for the event's hierarchy.
Definition: alsaevent.h:68
static bool isConnectionChange(const SequencerEvent *event)
Checks if the event's type is of type connection change.
Definition: alsaevent.cpp:183
snd_seq_event_t * getHandle()
Gets the handle of the event.
Definition: alsaevent.h:135
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:278
void setDestination(const unsigned char client, const unsigned char port)
Sets the client:port destination of the event.
Definition: alsaevent.cpp:232
void setSource(const unsigned char port)
Sets the event's source port ID.
Definition: alsaevent.cpp:242
void playbackStopped()
Signal emitted when the play-back has stopped.
virtual SequencerEvent * nextEvent()=0
Gets the next event in the sequence.
void start(QThread::Priority priority=InheritPriority)
Starts the playback thread.
Definition: playthread.cpp:219
virtual unsigned int getInitialPosition()
Gets the initial position in ticks of the sequence.
Definition: playthread.h:70
virtual void sendEchoEvent(int tick)
Sends an echo event, with the same PortId as sender and destination.
Definition: playthread.cpp:114
SequencerOutputThread(MidiClient *seq, int portId)
Constructor.
Definition: playthread.cpp:67
virtual void syncOutput()
Waits until the ALSA output queue is empty (all the events have been played.)
Definition: playthread.cpp:157
int m_QueueId
MidiQueue numeric identifier.
Definition: playthread.h:123
MidiClient * m_MidiClient
MidiClient instance pointer.
Definition: playthread.h:119
void playbackFinished()
Signal emitted when the sequence play-back has finished.
virtual void stop()
Stops playing the current sequence.
Definition: playthread.cpp:99
virtual void sendSongEvent(SequencerEvent *ev)
Sends a SequencerEvent.
Definition: playthread.cpp:130
virtual void drainOutput()
Flush the ALSA output buffer.
Definition: playthread.cpp:144
pollfd * m_pfds
Array of pollfd pointers.
Definition: playthread.h:125
QReadWriteLock m_mutex
Mutex object used for synchronization.
Definition: playthread.h:126
MidiQueue * m_Queue
MidiQueue instance pointer.
Definition: playthread.h:120
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:77
virtual void run() override
Thread process loop.
Definition: playthread.cpp:167
int m_npfds
Number of pollfd pointers.
Definition: playthread.h:124
int m_PortId
MidiPort numeric identifier.
Definition: playthread.h:121
virtual bool stopRequested()
Checks if stop has been requested.
Definition: playthread.cpp:89
MidiQueue * getQueue()
Get the MidiQueue instance associated to this client.
snd_seq_t * getHandle()
Returns the sequencer handler managed by ALSA.
Definition: alsaclient.cpp:286
int getClientId()
Gets the client ID.
Definition: alsaclient.cpp:552
void synchronizeOutput()
Wait until all sent events are processed.
Drumstick common.
Definition: alsaclient.cpp:68
Sequencer output thread.