X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fasync_midi_port.cc;h=bbcc0aab85e7e086d9a081e6d062e15df18bda2a;hb=4ddb6b74f5c0fe445b49e9abb5527afecc60dd8b;hp=ce32fe2ccc4d7e28a3bd2324c4f3cd42a0b768a9;hpb=9cf2cf55f5fa18bfbeb10c1a611132103e6ddc42;p=ardour.git diff --git a/libs/ardour/async_midi_port.cc b/libs/ardour/async_midi_port.cc index ce32fe2ccc..bbcc0aab85 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() @@ -51,11 +47,9 @@ AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags) , _currently_in_cycle (false) , _last_write_timestamp (0) , have_timer (false) - , output_fifo (512) + , output_fifo (2048) , input_fifo (1024) -#ifndef PLATFORM_WINDOWS - , xthread (true) -#endif + , _xthread (true) { } @@ -74,31 +68,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 +119,8 @@ AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes) if (ARDOUR::Port::sends_output()) { flush_output_fifo (nframes); - } - + } + /* copy incoming data from the port buffer into the input FIFO and if necessary wakeup the reader */ @@ -122,7 +128,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 { @@ -136,11 +142,9 @@ AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes) input_fifo.write (when, (Evoral::EventType) 0, (*b).size(), (*b).buffer()); } -#ifndef PLATFORM_WINDOWS if (!mb.empty()) { - xthread.wakeup (); + _xthread.wakeup (); } -#endif } } @@ -164,7 +168,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 +183,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 +210,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 +218,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 +227,28 @@ AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t t } if (vec.len[0]) { - if (!vec.buf[0]->owns_buffer()) { + /* 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()) { + /* 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 +274,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 +304,7 @@ AsyncMIDIPort::read (MIDI::byte *, size_t) if (!ARDOUR::Port::receives_input()) { return 0; } - + timestamp_t time; Evoral::EventType type; uint32_t size;