X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_port.cc;h=9a7d3eeb27fdfee4a716671d35fcd7b1583e9780;hb=1db2be2fef7a70f5200bcd96a701f612bbd7ec52;hp=75fd269cdee989f4e64fc28a1ccf863e4d242370;hpb=665f3bea5a7b145636b6d85bb3623013e38f1819;p=ardour.git diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index 75fd269cde..9a7d3eeb27 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -21,6 +21,7 @@ #include "ardour/midi_port.h" #include "ardour/data_type.h" +#include "ardour/audioengine.h" using namespace ARDOUR; using namespace std; @@ -28,9 +29,10 @@ using namespace std; MidiPort::MidiPort (const std::string& name, Flags flags) : Port (name, DataType::MIDI, flags) , _has_been_mixed_down (false) - , _resolve_in_process (false) + , _resolve_required (false) + , _input_active (true) { - _buffer = new MidiBuffer (raw_buffer_size(0)); + _buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI)); } MidiPort::~MidiPort() @@ -41,7 +43,10 @@ MidiPort::~MidiPort() void MidiPort::cycle_start (pframes_t nframes) { + Port::cycle_start (nframes); + _buffer->clear (); + assert (_buffer->size () == 0); if (sends_output ()) { @@ -50,7 +55,7 @@ MidiPort::cycle_start (pframes_t nframes) } MidiBuffer & -MidiPort::get_midi_buffer (framecnt_t nframes) +MidiPort::get_midi_buffer (pframes_t nframes) { if (_has_been_mixed_down) { return *_buffer; @@ -58,35 +63,42 @@ MidiPort::get_midi_buffer (framecnt_t nframes) if (receives_input ()) { - void* jack_buffer = jack_port_get_buffer (_jack_port, nframes); - const pframes_t event_count = jack_midi_get_event_count(jack_buffer); - - assert (event_count < _buffer->capacity()); - - /* suck all relevant MIDI events from the JACK MIDI port buffer - into our MidiBuffer - */ - - for (pframes_t i = 0; i < event_count; ++i) { - - jack_midi_event_t ev; - - jack_midi_event_get (&ev, jack_buffer, i); - - if (ev.buffer[0] == 0xfe) { - /* throw away active sensing */ - continue; - } - - if (ev.time >= _port_offset && ev.time < (_port_offset + nframes)) { - _buffer->push_back (ev); - } else { - cerr << "Dropping incoming MIDI at time " << ev.time << "; offset=" << _port_offset << " limit=" << (_port_offset + nframes) << "\n"; - } - } - - if (nframes) { - _has_been_mixed_down = true; + if (_input_active) { + + void* jack_buffer = jack_port_get_buffer (_jack_port, nframes); + const pframes_t event_count = jack_midi_get_event_count (jack_buffer); + + assert (event_count < _buffer->capacity()); + + /* suck all relevant MIDI events from the JACK MIDI port buffer + into our MidiBuffer + */ + + for (pframes_t i = 0; i < event_count; ++i) { + + jack_midi_event_t ev; + + jack_midi_event_get (&ev, jack_buffer, i); + + if (ev.buffer[0] == 0xfe) { + /* throw away active sensing */ + continue; + } + + /* check that the event is in the acceptable time range */ + + if ((ev.time >= (_global_port_buffer_offset + _port_buffer_offset)) && + (ev.time < (_global_port_buffer_offset + _port_buffer_offset + nframes))) { + _buffer->push_back (ev); + } else { + cerr << "Dropping incoming MIDI at time " << ev.time << "; offset=" + << _global_port_buffer_offset << " limit=" + << (_global_port_buffer_offset + _port_buffer_offset + nframes) << "\n"; + } + } + + } else { + _buffer->silence (nframes); } } else { @@ -114,38 +126,64 @@ MidiPort::cycle_split () } void -MidiPort::flush_buffers (pframes_t nframes, framepos_t time) +MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when) { - if (sends_output ()) { + for (uint8_t channel = 0; channel <= 0xF; channel++) { - void* jack_buffer = jack_port_get_buffer (_jack_port, nframes); + uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 }; - // Feed the data through the MidiStateTracker - bool did_loop; + /* we need to send all notes off AND turn the + * sustain/damper pedal off to handle synths + * that prioritize sustain over AllNotesOff + */ - _midi_state_tracker.track (_buffer->begin(), _buffer->end(), did_loop); + if (jack_midi_event_write (jack_buffer, when, ev, 3) != 0) { + cerr << "failed to deliver sustain-zero on channel " << channel << " on port " << name() << endl; + } + + ev[1] = MIDI_CTL_ALL_NOTES_OFF; - if (did_loop || _resolve_in_process) { - /* add necessary note offs */ - _midi_state_tracker.resolve_notes (*_buffer, time); + if (jack_midi_event_write (jack_buffer, 0, ev, 3) != 0) { + cerr << "failed to deliver ALL NOTES OFF on channel " << channel << " on port " << name() << endl; } + } +} - _resolve_in_process = false; +void +MidiPort::flush_buffers (pframes_t nframes) +{ + if (sends_output ()) { + + void* jack_buffer = jack_port_get_buffer (_jack_port, nframes); + + if (_resolve_required) { + /* resolve all notes at the start of the buffer */ + resolve_notes (jack_buffer, 0); + _resolve_required = false; + } for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) { - const Evoral::Event& ev = *i; + + const Evoral::MIDIEvent ev (*i, false); // event times are in frames, relative to cycle start - assert (ev.time() < (nframes + _port_offset)); + assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset)); - if (ev.time() >= _port_offset) { + if (ev.event_type() == LoopEventType) { + resolve_notes (jack_buffer, ev.time()); + continue; + } + + if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) { if (jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size()) != 0) { - cerr << "write failed, drop flushed note off on the floor, time " << ev.time() << " > " << _port_offset << endl; - } - } else { - cerr << "drop flushed event on the floor, time " << ev.time() << " < " << _port_offset << endl; - } + cerr << "write failed, drop flushed note off on the floor, time " + << 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; + } } } } @@ -153,12 +191,25 @@ MidiPort::flush_buffers (pframes_t nframes, framepos_t time) void MidiPort::transport_stopped () { - _resolve_in_process = true; + _resolve_required = true; +} + +void +MidiPort::realtime_locate () +{ + _resolve_required = true; } -size_t -MidiPort::raw_buffer_size (pframes_t nframes) const +void +MidiPort::reset () { - return jack_midi_max_event_size (jack_port_get_buffer (_jack_port, nframes)); + Port::reset (); + delete _buffer; + _buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI)); } +void +MidiPort::set_input_active (bool yn) +{ + _input_active = yn; +}