X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fasync_midi_port.cc;h=f7147676b0b5286775e92546af9982be42e8d065;hb=5b9822ab98074c29b7eba219c81265dde678429b;hp=21b59dec00241bacfaa3a9b11acba2fb19fb932d;hpb=152935e736eaf06f85bc7f5cb27337a62d95edd4;p=ardour.git diff --git a/libs/ardour/async_midi_port.cc b/libs/ardour/async_midi_port.cc index 21b59dec00..f7147676b0 100644 --- a/libs/ardour/async_midi_port.cc +++ b/libs/ardour/async_midi_port.cc @@ -1,6 +1,6 @@ /* Copyright (C) 1998 Paul Barton-Davis - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -37,10 +37,6 @@ using namespace ARDOUR; using namespace std; using namespace PBD; -namespace Evoral { - template class EventRingBuffer; -} - pthread_t AsyncMIDIPort::_process_thread; #define port_engine AudioEngine::instance()->port_engine() @@ -50,12 +46,11 @@ AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags) , MIDI::Port (name, MIDI::Port::Flags (0)) , _currently_in_cycle (false) , _last_write_timestamp (0) + , _flush_at_cycle_start (false) , have_timer (false) - , output_fifo (512) + , output_fifo (2048) , input_fifo (1024) -#ifndef PLATFORM_WINDOWS - , xthread (true) -#endif + , _xthread (true) { } @@ -64,7 +59,7 @@ AsyncMIDIPort::~AsyncMIDIPort () } void -AsyncMIDIPort::set_timer (boost::function& f) +AsyncMIDIPort::set_timer (boost::function& f) { timer = f; have_timer = true; @@ -74,31 +69,43 @@ void AsyncMIDIPort::flush_output_fifo (MIDI::pframes_t nframes) { RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0 } }; - size_t written; + size_t written = 0; output_fifo.get_read_vector (&vec); MidiBuffer& mb (get_midi_buffer (nframes)); - + if (vec.len[0]) { Evoral::Event* evp = vec.buf[0]; - + + assert (evp->size()); + assert (evp->buffer()); + for (size_t n = 0; n < vec.len[0]; ++n, ++evp) { - mb.push_back (evp->time(), evp->size(), evp->buffer()); + if (mb.push_back (evp->time(), evp->size(), evp->buffer())) { + written++; + } } } - + if (vec.len[1]) { Evoral::Event* evp = vec.buf[1]; + assert (evp->size()); + assert (evp->buffer()); + for (size_t n = 0; n < vec.len[1]; ++n, ++evp) { - mb.push_back (evp->time(), evp->size(), evp->buffer()); + if (mb.push_back (evp->time(), evp->size(), evp->buffer())) { + written++; + } } } - - if ((written = vec.len[0] + vec.len[1]) != 0) { - output_fifo.increment_read_idx (written); - } + + /* do this "atomically" after we're done pushing events into the + * MidiBuffer + */ + + output_fifo.increment_read_idx (written); } void @@ -113,8 +120,11 @@ AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes) if (ARDOUR::Port::sends_output()) { flush_output_fifo (nframes); - } - + if (_flush_at_cycle_start) { + flush_buffers (nframes); + } + } + /* copy incoming data from the port buffer into the input FIFO and if necessary wakeup the reader */ @@ -122,7 +132,7 @@ AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes) if (ARDOUR::Port::receives_input()) { MidiBuffer& mb (get_midi_buffer (nframes)); framecnt_t when; - + if (have_timer) { when = timer (); } else { @@ -133,21 +143,20 @@ AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes) if (!have_timer) { when += (*b).time(); } - input_fifo.write (when, (Evoral::EventType) 0, (*b).size(), (*b).buffer()); + input_fifo.write (when, Evoral::NO_EVENT, (*b).size(), (*b).buffer()); } -#ifndef PLATFORM_WINDOWS if (!mb.empty()) { - xthread.wakeup (); + _xthread.wakeup (); } -#endif + } } void AsyncMIDIPort::cycle_end (MIDI::pframes_t nframes) { - if (ARDOUR::Port::sends_output()) { + if (ARDOUR::Port::sends_output() && !_flush_at_cycle_start) { /* move any additional data from output FIFO into the port buffer. */ @@ -164,7 +173,7 @@ AsyncMIDIPort::cycle_end (MIDI::pframes_t nframes) * Cannot be called from a processing thread. */ void -AsyncMIDIPort::drain (int check_interval_usecs) +AsyncMIDIPort::drain (int check_interval_usecs, int total_usecs_to_wait) { RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0} }; @@ -179,12 +188,16 @@ AsyncMIDIPort::drain (int check_interval_usecs) return; } - while (1) { + microseconds_t now = get_microseconds (); + microseconds_t end = now + total_usecs_to_wait; + + while (now < end) { output_fifo.get_write_vector (&vec); if (vec.len[0] + vec.len[1] >= output_fifo.bufsize() - 1) { break; } Glib::usleep (check_interval_usecs); + now = get_microseconds(); } } @@ -202,7 +215,7 @@ AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t t /* this is the best estimate of "when" this MIDI data is being * delivered */ - + _parser->set_timestamp (AudioEngine::instance()->sample_time() + timestamp); for (size_t n = 0; n < msglen; ++n) { _parser->scanner (msg[n]); @@ -210,7 +223,7 @@ AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t t Glib::Threads::Mutex::Lock lm (output_fifo_lock); RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0} }; - + output_fifo.get_write_vector (&vec); if (vec.len[0] + vec.len[1] < 1) { @@ -219,19 +232,28 @@ AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t t } if (vec.len[0]) { - if (!vec.buf[0]->owns_buffer()) { - vec.buf[0]->set_buffer (0, 0, true); - } + /* force each event inside the ringbuffer to own its + own buffer, but let that be null and of zero size + initially. When ::set() is called, the buffer will + be allocated to hold a *copy* of the data we're + storing, and then that buffer will be used over and + over, occasionally being upwardly resized as + necessary. + */ + if (!vec.buf[0]->owns_buffer()) { + vec.buf[0]->set_buffer (0, 0, true); + } vec.buf[0]->set (msg, msglen, timestamp); } else { - if (!vec.buf[1]->owns_buffer()) { - vec.buf[1]->set_buffer (0, 0, true); - } + /* see comment in previous branch of if() statement */ + if (!vec.buf[1]->owns_buffer()) { + vec.buf[1]->set_buffer (0, 0, true); + } vec.buf[1]->set (msg, msglen, timestamp); } output_fifo.increment_write_idx (1); - + ret = msglen; } else { @@ -257,11 +279,11 @@ AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t t if (_currently_in_cycle) { MidiBuffer& mb (get_midi_buffer (_cycle_nframes)); - + if (timestamp == 0) { timestamp = _last_write_timestamp; - } - + } + if (mb.push_back (timestamp, msglen, msg)) { ret = msglen; _last_write_timestamp = timestamp; @@ -287,7 +309,7 @@ AsyncMIDIPort::read (MIDI::byte *, size_t) if (!ARDOUR::Port::receives_input()) { return 0; } - + timestamp_t time; Evoral::EventType type; uint32_t size;