2 * Copyright (C) 1998-2017 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2013-2014 John Emmas <john@creativepost.co.uk>
4 * Copyright (C) 2014-2016 David Robillard <d@drobilla.net>
5 * Copyright (C) 2015-2016 Robin Gareus <robin@gareus.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <glibmm/timer.h>
27 #include "pbd/error.h"
28 #include "pbd/stacktrace.h"
30 #include "midi++/types.h"
32 #include "ardour/async_midi_port.h"
33 #include "ardour/audioengine.h"
34 #include "ardour/midi_buffer.h"
37 using namespace ARDOUR;
41 pthread_t AsyncMIDIPort::_process_thread;
43 #define port_engine AudioEngine::instance()->port_engine()
45 AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags)
46 : MidiPort (name, flags)
47 , MIDI::Port (name, MIDI::Port::Flags (0))
48 , _currently_in_cycle (false)
49 , _last_write_timestamp (0)
50 , _flush_at_cycle_start (false)
58 AsyncMIDIPort::~AsyncMIDIPort ()
63 AsyncMIDIPort::set_timer (boost::function<MIDI::samplecnt_t (void)>& f)
70 AsyncMIDIPort::flush_output_fifo (MIDI::pframes_t nframes)
72 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
75 output_fifo.get_read_vector (&vec);
77 MidiBuffer& mb (get_midi_buffer (nframes));
80 Evoral::Event<double>* evp = vec.buf[0];
83 assert (evp->buffer());
85 for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
86 if (mb.push_back (evp->time(), evp->size(), evp->buffer())) {
93 Evoral::Event<double>* evp = vec.buf[1];
96 assert (evp->buffer());
98 for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
99 if (mb.push_back (evp->time(), evp->size(), evp->buffer())) {
105 /* do this "atomically" after we're done pushing events into the
109 output_fifo.increment_read_idx (written);
113 AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes)
115 _currently_in_cycle = true;
116 MidiPort::cycle_start (nframes);
118 /* dump anything waiting in the output FIFO at the start of the port
122 if (ARDOUR::Port::sends_output()) {
123 flush_output_fifo (nframes);
124 if (_flush_at_cycle_start) {
125 flush_buffers (nframes);
129 /* copy incoming data from the port buffer into the input FIFO
130 and if necessary wakeup the reader
133 if (ARDOUR::Port::receives_input()) {
134 MidiBuffer& mb (get_midi_buffer (nframes));
140 when = AudioEngine::instance()->sample_time_at_cycle_start();
143 for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
147 input_fifo.write (when, Evoral::NO_EVENT, (*b).size(), (*b).buffer());
158 AsyncMIDIPort::cycle_end (MIDI::pframes_t nframes)
160 if (ARDOUR::Port::sends_output() && !_flush_at_cycle_start) {
161 /* move any additional data from output FIFO into the port
164 flush_output_fifo (nframes);
167 MidiPort::cycle_end (nframes);
169 _currently_in_cycle = false;
172 /** wait for the output FIFO to be emptied by successive process() callbacks.
174 * Cannot be called from a processing thread.
177 AsyncMIDIPort::drain (int check_interval_usecs, int total_usecs_to_wait)
179 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
181 if (!AudioEngine::instance()->running() || AudioEngine::instance()->session() == 0) {
182 /* no more process calls - it will never drain */
187 if (is_process_thread()) {
188 error << "Process thread called MIDI::AsyncMIDIPort::drain() - this cannot work" << endmsg;
192 microseconds_t now = get_microseconds ();
193 microseconds_t end = now + total_usecs_to_wait;
196 output_fifo.get_write_vector (&vec);
197 if (vec.len[0] + vec.len[1] >= output_fifo.bufsize() - 1) {
200 Glib::usleep (check_interval_usecs);
201 now = get_microseconds();
206 AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t timestamp)
210 if (!ARDOUR::Port::sends_output()) {
214 if (!is_process_thread()) {
216 /* this is the best estimate of "when" this MIDI data is being
220 _parser->set_timestamp (AudioEngine::instance()->sample_time() + timestamp);
221 for (size_t n = 0; n < msglen; ++n) {
222 _parser->scanner (msg[n]);
225 Glib::Threads::Mutex::Lock lm (output_fifo_lock);
226 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
228 output_fifo.get_write_vector (&vec);
230 if (vec.len[0] + vec.len[1] < 1) {
231 error << "no space in FIFO for non-process thread MIDI write" << endmsg;
236 /* force each event inside the ringbuffer to own its
237 own buffer, but let that be null and of zero size
238 initially. When ::set() is called, the buffer will
239 be allocated to hold a *copy* of the data we're
240 storing, and then that buffer will be used over and
241 over, occasionally being upwardly resized as
244 if (!vec.buf[0]->owns_buffer()) {
245 vec.buf[0]->set_buffer (0, 0, true);
247 vec.buf[0]->set (msg, msglen, timestamp);
249 /* see comment in previous branch of if() statement */
250 if (!vec.buf[1]->owns_buffer()) {
251 vec.buf[1]->set_buffer (0, 0, true);
253 vec.buf[1]->set (msg, msglen, timestamp);
256 output_fifo.increment_write_idx (1);
262 _parser->set_timestamp (AudioEngine::instance()->sample_time_at_cycle_start() + timestamp);
263 for (size_t n = 0; n < msglen; ++n) {
264 _parser->scanner (msg[n]);
267 if (timestamp >= _cycle_nframes) {
268 std::cerr << "attempting to write MIDI event of " << msglen << " MIDI::bytes at time "
269 << timestamp << " of " << _cycle_nframes
270 << " (this will not work - needs a code fix)"
274 /* This is the process thread, which makes checking
275 * _currently_in_cycle atomic and safe, since it is only
276 * set from cycle_start() and cycle_end(), also called
277 * only from the process thread.
280 if (_currently_in_cycle) {
282 MidiBuffer& mb (get_midi_buffer (_cycle_nframes));
284 if (timestamp == 0) {
285 timestamp = _last_write_timestamp;
288 if (mb.push_back (timestamp, msglen, msg)) {
290 _last_write_timestamp = timestamp;
293 cerr << "AsyncMIDIPort (" << ARDOUR::Port::name() << "): write of " << msglen << " @ " << timestamp << " failed\n" << endl;
294 PBD::stacktrace (cerr, 20);
298 cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
299 PBD::stacktrace (cerr, 20);
308 AsyncMIDIPort::read (MIDI::byte *, size_t)
310 if (!ARDOUR::Port::receives_input()) {
315 Evoral::EventType type;
317 vector<MIDI::byte> buffer(input_fifo.capacity());
319 while (input_fifo.read (&time, &type, &size, &buffer[0])) {
320 _parser->set_timestamp (time);
321 for (uint32_t i = 0; i < size; ++i) {
322 _parser->scanner (buffer[i]);
330 AsyncMIDIPort::parse (MIDI::samplecnt_t)
334 /* see ::read() to realize why buf is not used */
335 read (buf, sizeof (buf));
339 AsyncMIDIPort::set_process_thread (pthread_t thr)
341 _process_thread = thr;
345 AsyncMIDIPort::is_process_thread()
347 return pthread_equal (pthread_self(), _process_thread);