X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_port.cc;h=615abede1c58e904bb2de4b991de779c4ba8191d;hb=b68a4e5cdc59ffb81c1952ac9cad63ddf0c76d06;hp=5589c6e501aea0f7ead75d7c37a90c1fdb95beaf;hpb=f0fcda204444922fc0e1261929aa6fdb84412036;p=ardour.git diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index 5589c6e501..615abede1c 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -19,12 +19,18 @@ #include #include -#include "ardour/midi_port.h" -#include "ardour/data_type.h" +#include "pbd/compose.h" +#include "pbd/debug.h" + #include "ardour/audioengine.h" +#include "ardour/data_type.h" +#include "ardour/debug.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" -using namespace ARDOUR; using namespace std; +using namespace ARDOUR; +using namespace PBD; #define port_engine AudioEngine::instance()->port_engine() @@ -33,6 +39,8 @@ MidiPort::MidiPort (const std::string& name, PortFlags flags) , _has_been_mixed_down (false) , _resolve_required (false) , _input_active (true) + , _always_parse (false) + , _trace_on (false) { _buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI)); } @@ -45,6 +53,8 @@ MidiPort::~MidiPort() void MidiPort::cycle_start (pframes_t nframes) { + framepos_t now = AudioEngine::instance()->sample_time_at_cycle_start(); + Port::cycle_start (nframes); _buffer->clear (); @@ -52,6 +62,30 @@ MidiPort::cycle_start (pframes_t nframes) if (sends_output ()) { port_engine.midi_clear (port_engine.get_buffer (_port_handle, nframes)); } + + if (_always_parse || (receives_input() && _trace_on)) { + 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]); + } + } + } +} + +Buffer& +MidiPort::get_buffer (pframes_t nframes) +{ + return get_midi_buffer (nframes); } MidiBuffer & @@ -67,11 +101,11 @@ MidiPort::get_midi_buffer (pframes_t nframes) void* buffer = port_engine.get_buffer (_port_handle, nframes); const pframes_t event_count = port_engine.get_midi_event_count (buffer); - + /* suck all relevant MIDI events from the MIDI port buffer into our MidiBuffer */ - + for (pframes_t i = 0; i < event_count; ++i) { pframes_t timestamp; @@ -83,6 +117,10 @@ MidiPort::get_midi_buffer (pframes_t nframes) if (buf[0] == 0xfe) { /* throw away active sensing */ continue; + } else if ((buf[0] & 0xF0) == 0x90 && buf[2] == 0) { + /* normalize note on with velocity 0 to proper note off */ + buf[0] = 0x80 | (buf[0] & 0x0F); /* note off */ + buf[2] = 0x40; /* default velocity */ } /* check that the event is in the acceptable time range */ @@ -137,13 +175,13 @@ MidiPort::resolve_notes (void* port_buffer, MidiBuffer::TimeType when) */ if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) { - cerr << "failed to deliver sustain-zero on channel " << channel << " on port " << name() << endl; + cerr << "failed to deliver sustain-zero on channel " << (int)channel << " on port " << name() << endl; } ev[1] = MIDI_CTL_ALL_NOTES_OFF; if (port_engine.midi_event_put (port_buffer, 0, ev, 3) != 0) { - cerr << "failed to deliver ALL NOTES OFF on channel " << channel << " on port " << name() << endl; + cerr << "failed to deliver ALL NOTES OFF on channel " << (int)channel << " on port " << name() << endl; } } } @@ -153,20 +191,60 @@ MidiPort::flush_buffers (pframes_t nframes) { if (sends_output ()) { - void* port_buffer = port_engine.get_buffer (_port_handle, nframes); + 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_required = false; + } + + if (_buffer->empty()) { + return; } + if (!port_buffer) { + port_buffer = port_engine.get_buffer (_port_handle, nframes); + } + + for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) { const Evoral::MIDIEvent 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(); + + _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]); + } + } + + // event times are in frames, relative to cycle start +#ifndef NDEBUG + if (DEBUG::MidiIO & PBD::debug_bits) { + DEBUG_STR_DECL(a); + DEBUG_STR_APPEND(a, string_compose ("MidiPort %1 pop event @ %2 sz %3 ", _buffer, ev.time(), ev.size())); + for (size_t i=0; i < ev.size(); ++i) { + DEBUG_STR_APPEND(a,hex); + DEBUG_STR_APPEND(a,"0x"); + DEBUG_STR_APPEND(a,(int)(ev.buffer()[i])); + DEBUG_STR_APPEND(a,' '); + } + DEBUG_STR_APPEND(a,'\n'); + DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str()); + } +#endif + assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset)); if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) { @@ -175,11 +253,20 @@ MidiPort::flush_buffers (pframes_t nframes) << ev.time() << " > " << _global_port_buffer_offset + _port_buffer_offset << endl; } } else { - cerr << "drop flushed event on the floor, time " << ev - << " to early for " << _global_port_buffer_offset - << " + " << _port_buffer_offset << endl; + cerr << "drop flushed event on the floor, time " << ev.time() + << " too early for " << _global_port_buffer_offset + << " + " << _port_buffer_offset; + for (size_t xx = 0; xx < ev.size(); ++xx) { + cerr << ' ' << hex << (int) ev.buffer()[xx]; + } + cerr << dec << endl; } } + + /* done.. the data has moved to the port buffer, mark it so + */ + + _buffer->clear (); } } @@ -215,3 +302,15 @@ MidiPort::set_input_active (bool yn) { _input_active = yn; } + +void +MidiPort::set_always_parse (bool yn) +{ + _always_parse = yn; +} + +void +MidiPort::set_trace_on (bool yn) +{ + _trace_on = yn; +}