/*
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
*/
#include <iostream>
+#include <vector>
#include <glibmm/timer.h>
using namespace std;
using namespace PBD;
-namespace Evoral {
- template class EventRingBuffer<MIDI::timestamp_t>;
-}
-
pthread_t AsyncMIDIPort::_process_thread;
#define port_engine AudioEngine::instance()->port_engine()
, 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)
- , xthread (true)
+ , _xthread (true)
{
}
{
}
+void
+AsyncMIDIPort::set_timer (boost::function<MIDI::framecnt_t (void)>& f)
+{
+ timer = f;
+ have_timer = true;
+}
+
void
AsyncMIDIPort::flush_output_fifo (MIDI::pframes_t nframes)
{
RingBuffer< Evoral::Event<double> >::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<double>* 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<double>* 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
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());
}
-
+
if (!mb.empty()) {
- xthread.wakeup ();
+ _xthread.wakeup ();
}
}
-
}
void
* 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<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
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();
}
}
/* 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]);
Glib::Threads::Mutex::Lock lm (output_fifo_lock);
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
-
+
output_fifo.get_write_vector (&vec);
if (vec.len[0] + vec.len[1] < 1) {
}
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 {
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;
if (!ARDOUR::Port::receives_input()) {
return 0;
}
-
+
timestamp_t time;
Evoral::EventType type;
uint32_t size;
- MIDI::byte buffer[input_fifo.capacity()];
+ vector<MIDI::byte> buffer(input_fifo.capacity());
- while (input_fifo.read (&time, &type, &size, buffer)) {
+ while (input_fifo.read (&time, &type, &size, &buffer[0])) {
_parser->set_timestamp (time);
for (uint32_t i = 0; i < size; ++i) {
_parser->scanner (buffer[i]);