drumstick 2.10.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-2024, 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
33
56
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) {
78 m_Queue = m_MidiClient->getQueue();
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);
119 ev.setDestination(m_MidiClient->getClientId(), m_PortId);
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) {
160 m_MidiClient->synchronizeOutput();
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);
180 m_Queue->continueRunning();
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
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.
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.
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.
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.
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.
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: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.
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: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.
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.
Drumstick ALSA library wrapper.
Drumstick common.
Sequencer output thread.