X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fasync_midi_port.cc;h=bbcc0aab85e7e086d9a081e6d062e15df18bda2a;hb=4ddb6b74f5c0fe445b49e9abb5527afecc60dd8b;hp=bd583328c30f1781a768d3268f27c1053bb64265;hpb=1745340c67d66d8dd92e5b3a377e935ed5eea973;p=ardour.git diff --git a/libs/ardour/async_midi_port.cc b/libs/ardour/async_midi_port.cc index bd583328c3..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() @@ -50,11 +46,10 @@ AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags) , MIDI::Port (name, MIDI::Port::Flags (0)) , _currently_in_cycle (false) , _last_write_timestamp (0) - , output_fifo (512) + , have_timer (false) + , output_fifo (2048) , input_fifo (1024) -#ifndef PLATFORM_WINDOWS - , xthread (true) -#endif + , _xthread (true) { } @@ -62,35 +57,54 @@ AsyncMIDIPort::~AsyncMIDIPort () { } +void +AsyncMIDIPort::set_timer (boost::function& f) +{ + timer = f; + have_timer = true; +} + 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 @@ -105,25 +119,32 @@ 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 */ if (ARDOUR::Port::receives_input()) { MidiBuffer& mb (get_midi_buffer (nframes)); - pframes_t when = AudioEngine::instance()->sample_time_at_cycle_start(); + framecnt_t when; + + if (have_timer) { + when = timer (); + } else { + when = AudioEngine::instance()->sample_time_at_cycle_start(); + } for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) { + if (!have_timer) { + when += (*b).time(); + } input_fifo.write (when, (Evoral::EventType) 0, (*b).size(), (*b).buffer()); } -#ifndef PLATFORM_WINDOWS if (!mb.empty()) { - xthread.wakeup (); + _xthread.wakeup (); } -#endif } } @@ -147,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} }; @@ -162,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(); } } @@ -185,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]); @@ -193,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) { @@ -202,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 { @@ -240,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; @@ -270,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;