diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2011-05-30 21:37:58 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2011-05-30 21:37:58 +0000 |
commit | de9e216cb5fcc08b6c39071d7cef031673aa67da (patch) | |
tree | 696922c23551b5609277be3dbbc4b1d378ad6fc2 /libs/ardour/midi_port.cc | |
parent | 14a80c091d850045bd35c56d5d378bfdd2fbe4f9 (diff) |
(1) push a locate all the way through the processing heirarchy so that MIDI output ports can resolve any notes currently playing (2) remove MidiStateTracker from MidiPort and use a fixed set of MIDI messages (sustain-off and all-notes-off, per channel) to do note resolution (3) move note resolution caused by a LoopEvent psuedo-event to within the main MidiPort::flush_output() loop, so that we resolve (turn off) Notes that come before the loop point, rather than send them out after the note resolution messages
git-svn-id: svn://localhost/ardour2/branches/3.0@9635 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/midi_port.cc')
-rw-r--r-- | libs/ardour/midi_port.cc | 61 |
1 files changed, 48 insertions, 13 deletions
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index 39f43eeef9..77fe712c5c 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -29,7 +29,7 @@ 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) { _buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI)); } @@ -119,31 +119,60 @@ MidiPort::cycle_split () } void +MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when) +{ + uint8_t ev[3]; + + ev[2] = 0; + + for (uint8_t channel = 0; channel <= 0xF; channel++) { + ev[0] = (MIDI_CMD_CONTROL | channel); + + /* we need to send all notes off AND turn the + * sustain/damper pedal off to handle synths + * that prioritize sustain over AllNotesOff + */ + + ev[1] = MIDI_CTL_SUSTAIN; + + 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 (jack_midi_event_write (jack_buffer, 0, ev, 3) != 0) { + cerr << "failed to deliver ALL NOTES OFF on channel " << channel << " on port " << name() << endl; + } + } +} + +void MidiPort::flush_buffers (pframes_t nframes, framepos_t time) { if (sends_output ()) { void* jack_buffer = jack_port_get_buffer (_jack_port, nframes); - // Feed the data through the MidiStateTracker - bool did_loop; - - _midi_state_tracker.track (_buffer->begin(), _buffer->end(), did_loop); - - if (did_loop || _resolve_in_process) { - /* add necessary note offs */ - _midi_state_tracker.resolve_notes (*_buffer, time); + if (_resolve_required) { + /* resolve all notes at the start of the buffer */ + resolve_notes (jack_buffer, 0); + _resolve_required= false; } - _resolve_in_process = false; - for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) { - const Evoral::Event<framepos_t>& ev = *i; + + const Evoral::MIDIEvent<MidiBuffer::TimeType> ev (*i, false); // event times are in frames, relative to cycle start assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_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 " @@ -160,7 +189,13 @@ 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; } void |