#include "ardour/debug.h"
#include "ardour/midi_buffer.h"
#include "ardour/midi_port.h"
+#include "ardour/session.h"
using namespace std;
using namespace ARDOUR;
MidiPort::~MidiPort()
{
+ if (_shadow_port) {
+ AudioEngine::instance()->unregister_port (_shadow_port);
+ _shadow_port.reset ();
+ }
+
delete _buffer;
}
MidiBuffer& mb (get_midi_buffer (nframes));
/* dump incoming MIDI to parser */
-
+
for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
uint8_t* buf = (*b).buffer();
-
+
_self_parser.set_timestamp (now + (*b).time());
-
+
uint32_t limit = (*b).size();
-
+
for (size_t n = 0; n < limit; ++n) {
_self_parser.scanner (buf[n]);
}
}
}
+
+ if (inbound_midi_filter) {
+ MidiBuffer& mb (get_midi_buffer (nframes));
+ inbound_midi_filter (mb, mb);
+ }
+
+ if (_shadow_port) {
+ MidiBuffer& mb (get_midi_buffer (nframes));
+ if (shadow_midi_filter (mb, _shadow_port->get_midi_buffer (nframes))) {
+ _shadow_port->flush_buffers (nframes);
+ }
+ }
+
}
Buffer&
*/
for (pframes_t i = 0; i < event_count; ++i) {
-
+
pframes_t timestamp;
size_t size;
uint8_t* buf;
-
+
port_engine.midi_event_get (timestamp, size, &buf, buffer, i);
-
+
if (buf[0] == 0xfe) {
/* throw away active sensing */
continue;
buf[0] = 0x80 | (buf[0] & 0x0F); /* note off */
buf[2] = 0x40; /* default velocity */
}
-
+
/* check that the event is in the acceptable time range */
-
+
if ((timestamp >= (_global_port_buffer_offset + _port_buffer_offset)) &&
(timestamp < (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
_buffer->push_back (timestamp, size, buf);
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
- if (port_engine.midi_event_put (port_buffer, 0, ev, 3) != 0) {
+ if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) {
cerr << "failed to deliver ALL NOTES OFF on channel " << (int)channel << " on port " << name() << endl;
}
}
if (sends_output ()) {
void* port_buffer = 0;
-
+
if (_resolve_required) {
port_buffer = port_engine.get_buffer (_port_handle, nframes);
/* resolve all notes at the start of the buffer */
- resolve_notes (port_buffer, 0);
+ resolve_notes (port_buffer, _global_port_buffer_offset);
_resolve_required = false;
}
-
+
if (_buffer->empty()) {
return;
}
for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
- const Evoral::MIDIEvent<MidiBuffer::TimeType> ev (*i, false);
+ const Evoral::Event<MidiBuffer::TimeType> ev (*i, false);
if (sends_output() && _trace_on) {
uint8_t const * const buf = ev.buffer();
- const framepos_t now = AudioEngine::instance()->sample_time_at_cycle_start();
+ const framepos_t now = AudioEngine::instance()->sample_time_at_cycle_start();
_self_parser.set_timestamp (now + ev.time());
-
+
uint32_t limit = ev.size();
-
+
for (size_t n = 0; n < limit; ++n) {
_self_parser.scanner (buf[n]);
}
#ifndef NDEBUG
if (DEBUG_ENABLED (DEBUG::MidiIO)) {
+ const Session* s = AudioEngine::instance()->session();
+ const framepos_t now = (s ? s->transport_frame() : 0);
DEBUG_STR_DECL(a);
- DEBUG_STR_APPEND(a, string_compose ("MidiPort %1 pop event @ %2 sz %3 ", _buffer, ev.time(), ev.size()));
+ DEBUG_STR_APPEND(a, string_compose ("MidiPort %8 %1 pop event @ %2 (global %4, within %5 gpbo %6 pbo %7 sz %3 ", _buffer, ev.time(), ev.size(),
+ now + ev.time(), nframes, _global_port_buffer_offset, _port_buffer_offset, name()));
for (size_t i=0; i < ev.size(); ++i) {
DEBUG_STR_APPEND(a,hex);
DEBUG_STR_APPEND(a,"0x");
{
_trace_on = yn;
}
+
+int
+MidiPort::add_shadow_port (string const & name, MidiFilter mf)
+{
+ if (!ARDOUR::Port::receives_input()) {
+ return -1;
+ }
+
+ if (_shadow_port) {
+ return -2;
+ }
+
+ shadow_midi_filter = mf;
+
+ if (!(_shadow_port = boost::dynamic_pointer_cast<MidiPort> (AudioEngine::instance()->register_output_port (DataType::MIDI, name, false, PortFlags (Shadow|IsTerminal))))) {
+ return -3;
+ }
+
+ /* forward on our port latency to the shadow port.
+
+ XXX: need to capture latency changes and forward them too.
+ */
+
+ LatencyRange latency = private_latency_range (false);
+ _shadow_port->set_private_latency_range (latency, false);
+
+ return 0;
+}