drumstick  1.1.1
playthread.cpp
Go to the documentation of this file.
1 /*
2  MIDI Sequencer C++ library
3  Copyright (C) 2006-2018, 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
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "playthread.h"
20 #include "alsaclient.h"
21 #include "alsaqueue.h"
22 #include <QReadLocker>
23 #include <QWriteLocker>
24 
30 namespace drumstick {
31 
55 const int TIMEOUT = 100;
56 
63  : QThread(),
64  m_MidiClient(seq),
65  m_Queue(0),
66  m_PortId(portId),
67  m_Stopped(false),
68  m_QueueId(0),
69  m_npfds(0),
70  m_pfds(0)
71 {
72  if (m_MidiClient != NULL) {
74  m_QueueId = m_Queue->getId();
75  }
76 }
77 
83 bool
85 {
86  QReadLocker locker(&m_mutex);
87  return m_Stopped;
88 }
89 
93 void
95 {
96  QWriteLocker locker(&m_mutex);
97  m_Stopped = true;
98  locker.unlock();
99  while (isRunning())
100  wait(TIMEOUT);
101 }
102 
107 void
109 {
110  if (!stopRequested() && m_MidiClient != NULL) {
111  SystemEvent ev(SND_SEQ_EVENT_ECHO);
112  ev.setSource(m_PortId);
114  ev.scheduleTick(m_QueueId, tick, false);
115  sendSongEvent(&ev);
116  }
117 }
118 
123 void
125 {
126  if (m_MidiClient != NULL) {
127  while (!stopRequested() &&
128  (snd_seq_event_output_direct(m_MidiClient->getHandle(), ev->getHandle()) < 0))
129  poll(m_pfds, m_npfds, TIMEOUT);
130  }
131 }
132 
136 void
138 {
139  if (m_MidiClient != NULL) {
140  while (!stopRequested() &&
141  (snd_seq_drain_output(m_MidiClient->getHandle()) < 0))
142  poll(m_pfds, m_npfds, TIMEOUT);
143  }
144 }
145 
149 void
151 {
152  if (!stopRequested() && m_MidiClient != NULL) {
153  QueueStatus status = m_Queue->getStatus();
154  while (!stopRequested() && (status.getEvents() > 0)) {
155  usleep(TIMEOUT);
156  status = m_Queue->getStatus();
157  }
158  }
159 }
160 
165 {
166  unsigned int last_tick;
167  if (m_MidiClient != NULL) {
168  try {
169  m_npfds = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLOUT);
170  m_pfds = (pollfd*) alloca(m_npfds * sizeof(pollfd));
171  snd_seq_poll_descriptors(m_MidiClient->getHandle(), m_pfds, m_npfds, POLLOUT);
172  last_tick = getInitialPosition();
173  if (last_tick == 0) {
174  m_Queue->start();
175  } else {
176  m_Queue->setTickPosition(last_tick);
178  }
179  while (!stopRequested() && hasNext()) {
180  SequencerEvent* ev = nextEvent();
181  if (getEchoResolution() > 0) {
182  while (!stopRequested() && (last_tick < ev->getTick())) {
183  last_tick += getEchoResolution();
184  sendEchoEvent(last_tick);
185  }
186  }
188  sendSongEvent(ev);
189  }
190  if (stopRequested()) {
191  m_Queue->clear();
192  emit stopped();
193  } else {
194  drainOutput();
195  syncOutput();
196  if (stopRequested())
197  emit stopped();
198  else
199  emit finished();
200  }
201  m_Queue->stop();
202  } catch (...) {
203  qWarning("exception in output thread");
204  }
205  m_npfds = 0;
206  m_pfds = 0;
207  }
208 }
209 
214 void SequencerOutputThread::start( Priority priority )
215 {
216  QWriteLocker locker(&m_mutex);
217  m_Stopped = false;
218  QThread::start( priority );
219 }
220 
221 } /* namespace drumstick */
222 
snd_seq_event_t * getHandle()
Gets the handle of the event.
Definition: alsaevent.h:122
MidiQueue * m_Queue
MidiQueue instance pointer.
Definition: playthread.h:108
void setTickPosition(snd_seq_tick_time_t pos)
Sets the queue position in musical time (ticks).
Definition: alsaqueue.cpp:889
virtual unsigned int getEchoResolution()
Gets the echo event resolution in ticks.
Definition: playthread.h:64
Classes managing ALSA Sequencer clients.
virtual void drainOutput()
Flush the ALSA output buffer.
Definition: playthread.cpp:137
void continueRunning()
Start the queue without resetting the last position.
Definition: alsaqueue.cpp:870
void clear()
Clear the queue, dropping any scheduled events.
Definition: alsaqueue.cpp:879
void start()
Start the queue.
Definition: alsaqueue.cpp:846
virtual unsigned int getInitialPosition()
Gets the initial position in ticks of the sequence.
Definition: playthread.h:57
void stop()
Stop the queue.
Definition: alsaqueue.cpp:857
snd_seq_t * getHandle()
Returns the sequencer handler managed by ALSA.
Definition: alsaclient.cpp:285
Generic event.
Definition: alsaevent.h:437
virtual SequencerEvent * nextEvent()=0
Gets the next event in the sequence.
static bool isConnectionChange(const SequencerEvent *event)
Checks if the event&#39;s type is of type connection change.
Definition: alsaevent.cpp:183
QueueStatus & getStatus()
Gets a QueueStatus object reference.
Definition: alsaqueue.cpp:765
Base class for the event&#39;s hierarchy.
Definition: alsaevent.h:52
virtual void syncOutput()
Waits until the ALSA output queue is empty (all the events have been played.)
Definition: playthread.cpp:150
int getEvents()
Gets the number of queued events.
Definition: alsaqueue.cpp:272
SequencerOutputThread(MidiClient *seq, int portId)
Constructor.
Definition: playthread.cpp:62
int m_npfds
Number of pollfd pointers.
Definition: playthread.h:112
Client management.
Definition: alsaclient.h:197
virtual void run()
Thread process loop.
Definition: playthread.cpp:164
void start(Priority priority=InheritPriority)
Starts the playback thread.
Definition: playthread.cpp:214
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
int m_QueueId
MidiQueue numeric identifier.
Definition: playthread.h:111
void setSource(const unsigned char port)
Sets the event&#39;s source port ID.
Definition: alsaevent.cpp:242
bool m_Stopped
Stopped status.
Definition: playthread.h:110
Sequencer output thread.
virtual void sendEchoEvent(int tick)
Sends an echo event, with the same PortId as sender and destination.
Definition: playthread.cpp:108
MidiQueue * getQueue()
Get the MidiQueue instance associated to this client.
pollfd * m_pfds
Array of pollfd pointers.
Definition: playthread.h:113
Queue status container.
Definition: alsaqueue.h:79
void stopped()
Signal emitted when the play-back has stopped.
virtual void stop()
Stops playing the current sequence.
Definition: playthread.cpp:94
MidiClient * m_MidiClient
MidiClient instance pointer.
Definition: playthread.h:107
virtual bool hasNext()=0
Check if there is one more event in the sequence.
Classes managing ALSA Sequencer queues.
int getClientId()
Gets the client ID.
Definition: alsaclient.cpp:545
The QThread class provides platform-independent threads.
virtual void sendSongEvent(SequencerEvent *ev)
Sends a SequencerEvent.
Definition: playthread.cpp:124
int m_PortId
MidiPort numeric identifier.
Definition: playthread.h:109
QReadWriteLock m_mutex
Mutex object used for synchronization.
Definition: playthread.h:114
void finished()
Signal emitted when the sequence play-back has finished.
virtual bool stopRequested()
Checks if stop has been requested.
Definition: playthread.cpp:84
void setDestination(const unsigned char client, const unsigned char port)
Sets the client:port destination of the event.
Definition: alsaevent.cpp:232