From eb0dded0954782768834e1d3a494f45cc4a118a1 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 30 Sep 2017 23:16:04 +0200 Subject: Immediate-event/out-of-band injection update & tweak clearing buffers Immediate events are used for MIDI-Panic and to inject GUI generated events e.g. patch-changes, note-events from the track-header (scroomer-keyboard) and patch-change audition. Current behavior: - snapshot copy immediate events from ringbuffer into a buffer at the beginning of each the cycle. - Inject immediate events into input-buffer directly after reading the input - process "normally" - pass immediate event-buffer to disk-writer, so it can skip them (don't write immediate events to disk) - if the Route is not monitoring input: clear buffer before disk-reader and re-inject (original) immediate events after the disk-reader - immediate events process normally and are also sent to outputs. --- libs/ardour/ardour/midi_track.h | 21 ++++++++++------ libs/ardour/ardour/route.h | 4 ++- libs/ardour/midi_track.cc | 55 ++++++++++++++++++++++++----------------- libs/ardour/route.cc | 33 +++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 34 deletions(-) (limited to 'libs') diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index dfd5a42d13..93856282c4 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -126,6 +126,8 @@ public: MonitorState monitoring_state () const; + MidiBuffer const& immediate_event_buffer () const { return _immediate_event_buffer; } + void set_input_active (bool); bool input_active () const; PBD::Signal0 InputActiveChanged; @@ -136,16 +138,19 @@ protected: void act_on_mute (); void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition); + void snapshot_out_of_band_data (samplecnt_t nframes); + void write_out_of_band_data (BufferSet& bufs, samplecnt_t /* nframes */) const; + + private: MidiRingBuffer _immediate_events; + MidiBuffer _immediate_event_buffer; MidiRingBuffer _step_edit_ring_buffer; - NoteMode _note_mode; - bool _step_editing; - bool _input_active; - MidiChannelFilter _playback_filter; - MidiChannelFilter _capture_filter; - - void write_out_of_band_data (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, samplecnt_t nframes); + NoteMode _note_mode; + bool _step_editing; + bool _input_active; + MidiChannelFilter _playback_filter; + MidiChannelFilter _capture_filter; void set_state_part_two (); void set_state_part_three (); @@ -157,7 +162,7 @@ private: void map_input_active (bool); /** Update automation controls to reflect any changes in buffers. */ - void update_controls (const BufferSet& bufs); + void update_controls (BufferSet const& bufs); void restore_controls (); }; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 1437fd79ed..830ef4bab3 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -597,7 +597,9 @@ protected: virtual int no_roll_unlocked (pframes_t nframes, samplepos_t start_sample, samplepos_t end_sample, bool session_state_changing); - virtual void write_out_of_band_data (BufferSet& /* bufs */, samplepos_t /* start_sample */, samplepos_t /* end_sample */, samplecnt_t /* nframes */) {} + virtual void snapshot_out_of_band_data (samplecnt_t /* nframes */) {} + virtual void write_out_of_band_data (BufferSet&, samplecnt_t /* nframes */) const {} + virtual void update_controls (BufferSet const&) {} void process_output_buffers (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 2e5fd2a0b4..20faa80bc8 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -73,6 +73,7 @@ using namespace PBD; MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode) : Track (sess, name, PresentationInfo::MidiTrack, mode, DataType::MIDI) , _immediate_events(6096) // FIXME: size? + , _immediate_event_buffer(6096) , _step_edit_ring_buffer(64) // FIXME: size? , _note_mode (Sustained) , _step_editing (false) @@ -303,16 +304,19 @@ MidiTrack::restore_controls () } void -MidiTrack::update_controls(const BufferSet& bufs) +MidiTrack::update_controls (BufferSet const& bufs) { const MidiBuffer& buf = bufs.get_midi(0); for (MidiBuffer::const_iterator e = buf.begin(); e != buf.end(); ++e) { - const Evoral::Event& ev = *e; + const Evoral::Event& ev = *e; const Evoral::Parameter param = midi_parameter(ev.buffer(), ev.size()); const boost::shared_ptr control = automation_control (param); if (control) { - control->set_double(ev.value(), _session.transport_sample(), false); - control->Changed (false, Controllable::NoGroup); + double old = control->get_double (false, 0); + control->set_double (ev.value(), 0, false); + if (old != ev.value()) { + control->Changed (false, Controllable::NoGroup); + } } } } @@ -416,30 +420,35 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (samplecnt_t nframes) } void -MidiTrack::write_out_of_band_data (BufferSet& bufs, samplepos_t /*start*/, samplepos_t /*end*/, samplecnt_t nframes) +MidiTrack::snapshot_out_of_band_data (samplecnt_t nframes) { - MidiBuffer& buf (bufs.get_midi (0)); - - update_controls (bufs); + _immediate_event_buffer.clear (); + if (0 == _immediate_events.read_space()) { + return; + } - // Append immediate events + assert (nframes > 0); - if (_immediate_events.read_space()) { + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 has %2 of immediate events to deliver\n", + name(), _immediate_events.read_space())); - DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 has %2 of immediate events to deliver\n", - name(), _immediate_events.read_space())); + /* write as many of the immediate events as we can, but give "true" as + * the last argument ("stop on overflow in destination") so that we'll + * ship the rest out next time. + * + * the Port::port_offset() + (nframes-1) argument puts all these events at the last + * possible position of the output buffer, so that we do not + * violate monotonicity when writing. Port::port_offset() will + * be non-zero if we're in a split process cycle. + */ + _immediate_events.read (_immediate_event_buffer, 0, 1, Port::port_offset() + nframes - 1, true); +} - /* write as many of the immediate events as we can, but give "true" as - * the last argument ("stop on overflow in destination") so that we'll - * ship the rest out next time. - * - * the Port::port_offset() + (nframes-1) argument puts all these events at the last - * possible position of the output buffer, so that we do not - * violate monotonicity when writing. Port::port_offset() will - * be non-zero if we're in a split process cycle. - */ - _immediate_events.read (buf, 0, 1, Port::port_offset() + nframes - 1, true); - } +void +MidiTrack::write_out_of_band_data (BufferSet& bufs, samplecnt_t nframes) const +{ + MidiBuffer& buf (bufs.get_midi (0)); + buf.merge_from (_immediate_event_buffer, nframes); } int diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 0f8c892b24..236f2d7c0c 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -402,7 +402,8 @@ Route::process_output_buffers (BufferSet& bufs, * Also during remaining_latency_preroll, transport_rolling () is false, but * we may need to monitor disk instead. */ - bool silence = _have_internal_generator ? false : (monitoring_state () == MonitoringSilence); + MonitorState ms = monitoring_state (); + bool silence = _have_internal_generator ? false : (ms == MonitoringSilence); _main_outs->no_outs_cuz_we_no_monitor (silence); @@ -524,6 +525,24 @@ Route::process_output_buffers (BufferSet& bufs, /* input->latency() + */ latency, /* output->latency() + */ playback_latency); } + bool re_inject_oob_data = false; + if ((*i) == _disk_reader) { + /* Well now, we've made it past the disk-writer and to the disk-reader. + * Time to decide what to do about monitoring. + * + * Even when not doing MonitoringDisk, we need to run the processors, + * so that it advances its internal buffers (IFF run_disk_reader is true). + * + */ + if (ms == MonitoringDisk || ms == MonitoringSilence) { + /* this will clear out-of-band data, too (e.g. MIDI-PC, Panic etc. + * OOB data is written at the end of the cycle (nframes - 1), + * and jack does not re-order events, so we push them back later */ + re_inject_oob_data = true; + bufs.silence (nframes, 0); + } + } + double pspeed = speed; if ((!run_disk_reader && (*i) == _disk_reader) || (!run_disk_writer && (*i) == _disk_writer)) { /* run with speed 0, no-roll */ @@ -531,6 +550,7 @@ Route::process_output_buffers (BufferSet& bufs, } (*i)->run (bufs, start_sample - latency, end_sample - latency, pspeed, nframes, *i != _processors.back()); + bufs.set_count ((*i)->output_streams()); /* Note: plugin latency may change. While the plugin does inform the session via @@ -542,6 +562,11 @@ Route::process_output_buffers (BufferSet& bufs, if ((*i)->active ()) { latency += (*i)->signal_latency (); } + + if (re_inject_oob_data) { + write_out_of_band_data (bufs, nframes); + } + #if 0 if ((*i) == _delayline) { latency += _delayline->get_delay (); @@ -701,14 +726,18 @@ Route::run_route (samplepos_t start_sample, samplepos_t end_sample, pframes_t nf bufs.silence (nframes, 0); } + snapshot_out_of_band_data (nframes); /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */ - write_out_of_band_data (bufs, start_sample, end_sample, nframes); + write_out_of_band_data (bufs, nframes); /* run processor chain */ process_output_buffers (bufs, start_sample, end_sample, nframes, declick, gain_automation_ok, run_disk_reader); + /* map events (e.g. MIDI-CC) back to control-parameters */ + update_controls (bufs); + flush_processor_buffers_locked (nframes); } -- cgit v1.2.3