2 Copyright (C) 1998 Paul Barton-Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <glibmm/timer.h>
26 #include "pbd/error.h"
27 #include "pbd/stacktrace.h"
29 #include "midi++/types.h"
31 #include "ardour/async_midi_port.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/midi_buffer.h"
36 using namespace ARDOUR;
40 pthread_t AsyncMIDIPort::_process_thread;
42 #define port_engine AudioEngine::instance()->port_engine()
45 filter_relax (MidiBuffer& in, MidiBuffer& out)
51 filter_copy (MidiBuffer& in, MidiBuffer& out)
58 filter_notes_only (MidiBuffer& in, MidiBuffer& out)
60 for (MidiBuffer::iterator b = in.begin(); b != in.end(); ++b) {
61 if ((*b).is_note_on() || (*b).is_note_off()) {
68 AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags)
69 : MidiPort (name, flags)
70 , MIDI::Port (name, MIDI::Port::Flags (0))
71 , _currently_in_cycle (false)
72 , _last_write_timestamp (0)
77 , inbound_midi_filter (boost::bind (filter_notes_only, _1, _2))
81 AsyncMIDIPort::~AsyncMIDIPort ()
86 AsyncMIDIPort::set_timer (boost::function<MIDI::framecnt_t (void)>& f)
93 AsyncMIDIPort::flush_output_fifo (MIDI::pframes_t nframes)
95 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
98 output_fifo.get_read_vector (&vec);
100 MidiBuffer& mb (get_midi_buffer (nframes));
103 Evoral::Event<double>* evp = vec.buf[0];
105 assert (evp->size());
106 assert (evp->buffer());
108 for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
109 if (mb.push_back (evp->time(), evp->size(), evp->buffer())) {
116 Evoral::Event<double>* evp = vec.buf[1];
118 assert (evp->size());
119 assert (evp->buffer());
121 for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
122 if (mb.push_back (evp->time(), evp->size(), evp->buffer())) {
128 /* do this "atomically" after we're done pushing events into the
132 output_fifo.increment_read_idx (written);
136 AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes)
138 _currently_in_cycle = true;
139 MidiPort::cycle_start (nframes);
141 /* dump anything waiting in the output FIFO at the start of the port
145 if (ARDOUR::Port::sends_output()) {
146 flush_output_fifo (nframes);
149 /* copy incoming data from the port buffer into the input FIFO
150 and if necessary wakeup the reader
153 if (ARDOUR::Port::receives_input()) {
154 MidiBuffer& mb (get_midi_buffer (nframes));
160 when = AudioEngine::instance()->sample_time_at_cycle_start();
163 for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
167 input_fifo.write (when, (Evoral::EventType) 0, (*b).size(), (*b).buffer());
175 inbound_midi_filter (mb, shadow_port->get_midi_buffer (nframes));
177 inbound_midi_filter (mb, mb);
183 AsyncMIDIPort::cycle_end (MIDI::pframes_t nframes)
185 if (ARDOUR::Port::sends_output()) {
186 /* move any additional data from output FIFO into the port
189 flush_output_fifo (nframes);
192 MidiPort::cycle_end (nframes);
194 _currently_in_cycle = false;
197 /** wait for the output FIFO to be emptied by successive process() callbacks.
199 * Cannot be called from a processing thread.
202 AsyncMIDIPort::drain (int check_interval_usecs, int total_usecs_to_wait)
204 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
206 if (!AudioEngine::instance()->running() || AudioEngine::instance()->session() == 0) {
207 /* no more process calls - it will never drain */
212 if (is_process_thread()) {
213 error << "Process thread called MIDI::AsyncMIDIPort::drain() - this cannot work" << endmsg;
217 microseconds_t now = get_microseconds ();
218 microseconds_t end = now + total_usecs_to_wait;
221 output_fifo.get_write_vector (&vec);
222 if (vec.len[0] + vec.len[1] >= output_fifo.bufsize() - 1) {
225 Glib::usleep (check_interval_usecs);
226 now = get_microseconds();
231 AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t timestamp)
235 if (!ARDOUR::Port::sends_output()) {
239 if (!is_process_thread()) {
241 /* this is the best estimate of "when" this MIDI data is being
245 _parser->set_timestamp (AudioEngine::instance()->sample_time() + timestamp);
246 for (size_t n = 0; n < msglen; ++n) {
247 _parser->scanner (msg[n]);
250 Glib::Threads::Mutex::Lock lm (output_fifo_lock);
251 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
253 output_fifo.get_write_vector (&vec);
255 if (vec.len[0] + vec.len[1] < 1) {
256 error << "no space in FIFO for non-process thread MIDI write" << endmsg;
261 /* force each event inside the ringbuffer to own its
262 own buffer, but let that be null and of zero size
263 initially. When ::set() is called, the buffer will
264 be allocated to hold a *copy* of the data we're
265 storing, and then that buffer will be used over and
266 over, occasionally being upwardly resized as
269 if (!vec.buf[0]->owns_buffer()) {
270 vec.buf[0]->set_buffer (0, 0, true);
272 vec.buf[0]->set (msg, msglen, timestamp);
274 /* see comment in previous branch of if() statement */
275 if (!vec.buf[1]->owns_buffer()) {
276 vec.buf[1]->set_buffer (0, 0, true);
278 vec.buf[1]->set (msg, msglen, timestamp);
281 output_fifo.increment_write_idx (1);
287 _parser->set_timestamp (AudioEngine::instance()->sample_time_at_cycle_start() + timestamp);
288 for (size_t n = 0; n < msglen; ++n) {
289 _parser->scanner (msg[n]);
292 if (timestamp >= _cycle_nframes) {
293 std::cerr << "attempting to write MIDI event of " << msglen << " MIDI::bytes at time "
294 << timestamp << " of " << _cycle_nframes
295 << " (this will not work - needs a code fix)"
299 /* This is the process thread, which makes checking
300 * _currently_in_cycle atomic and safe, since it is only
301 * set from cycle_start() and cycle_end(), also called
302 * only from the process thread.
305 if (_currently_in_cycle) {
307 MidiBuffer& mb (get_midi_buffer (_cycle_nframes));
309 if (timestamp == 0) {
310 timestamp = _last_write_timestamp;
313 if (mb.push_back (timestamp, msglen, msg)) {
315 _last_write_timestamp = timestamp;
318 cerr << "AsyncMIDIPort (" << ARDOUR::Port::name() << "): write of " << msglen << " @ " << timestamp << " failed\n" << endl;
319 PBD::stacktrace (cerr, 20);
323 cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
324 PBD::stacktrace (cerr, 20);
333 AsyncMIDIPort::read (MIDI::byte *, size_t)
335 if (!ARDOUR::Port::receives_input()) {
340 Evoral::EventType type;
342 vector<MIDI::byte> buffer(input_fifo.capacity());
344 while (input_fifo.read (&time, &type, &size, &buffer[0])) {
345 _parser->set_timestamp (time);
346 for (uint32_t i = 0; i < size; ++i) {
347 _parser->scanner (buffer[i]);
355 AsyncMIDIPort::parse (MIDI::framecnt_t)
359 /* see ::read() to realize why buf is not used */
360 read (buf, sizeof (buf));
364 AsyncMIDIPort::set_process_thread (pthread_t thr)
366 _process_thread = thr;
370 AsyncMIDIPort::is_process_thread()
372 return pthread_equal (pthread_self(), _process_thread);
376 AsyncMIDIPort::add_shadow_port (string const & name)
378 if (!ARDOUR::Port::receives_input()) {
386 /* shadow port is not async. */
388 if (!(shadow_port = boost::dynamic_pointer_cast<MidiPort> (AudioEngine::instance()->register_output_port (DataType::MIDI, name, false)))) {