From 7c944687c91fe05cc0f9ffda704f4e783a68c2d2 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 10 Oct 2024 22:18:09 -0600 Subject: [PATCH] preparations for clip data display (MIDI) while recording --- libs/ardour/ardour/triggerbox.h | 19 ++++++++--- libs/ardour/triggerbox.cc | 58 +++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/libs/ardour/ardour/triggerbox.h b/libs/ardour/ardour/triggerbox.h index 4e09919e97..0b2cf048f8 100644 --- a/libs/ardour/ardour/triggerbox.h +++ b/libs/ardour/ardour/triggerbox.h @@ -45,6 +45,7 @@ #include "evoral/PatchChange.h" #include "evoral/SMF.h" +#include "ardour/event_ring_buffer.h" #include "ardour/midi_model.h" #include "ardour/midi_state_tracker.h" #include "ardour/processor.h" @@ -777,8 +778,10 @@ struct SlotArmInfo { ~SlotArmInfo(); Trigger& slot; - Temporal::timepos_t start; - Temporal::timepos_t end; + Temporal::Beats start_beats; + samplepos_t start_samples; + Temporal::Beats end_beats; + samplepos_t end_samples; RTMidiBufferBeats* midi_buf; AudioTrigger::AudioData audio_buf; RubberBand::RubberBandStretcher* stretcher; @@ -931,8 +934,12 @@ class LIBARDOUR_API TriggerBox : public Processor, public std::enable_shared_fro void send_property_change (PBD::PropertyChange pc); static PBD::Signal2 TriggerBoxPropertyChange; + std::shared_ptr get_gui_feed_buffer () const; + void dump (std::ostream &) const; + PBD::Signal0 Captured; + private: struct Requests { std::atomic stop_all; @@ -966,8 +973,6 @@ class LIBARDOUR_API TriggerBox : public Processor, public std::enable_shared_fro void maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes); void finish_recording (BufferSet& bufs); void set_armed (SlotArmInfo*); - SlotArmInfo* capture_info() const { return _arm_info; } - PBD::Signal0 Captured; /* These four are accessed (read/write) only from process() context */ @@ -1025,6 +1030,12 @@ class LIBARDOUR_API TriggerBox : public Processor, public std::enable_shared_fro PBD::ScopedConnection stop_all_connection; std::atomic _arm_info; + /** A buffer that we use to put newly-arrived MIDI data in for + * the GUI to read (so that it can update itself). + */ + mutable EventRingBuffer _gui_feed_fifo; + mutable Glib::Threads::Mutex _gui_feed_reset_mutex; + typedef std::map,std::pair > CustomMidiMap; static CustomMidiMap _custom_midi_map; diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index 19cc94c81d..30433c25cc 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -3417,8 +3418,8 @@ Trigger::make_property_quarks () SlotArmInfo::SlotArmInfo (Trigger& s) : slot (s) - , start (0) - , end (0) + , start_samples (0) + , end_samples (0) , midi_buf (nullptr) , stretcher (nullptr) { @@ -3498,6 +3499,7 @@ TriggerBox::TriggerBox (Session& s, DataType dt) , _record_state (Disabled) , requests (1024) , _arm_info (nullptr) + , _gui_feed_fifo (std::min (64000, std::max (s.sample_rate() / 10, 2 * AudioEngine::instance()->raw_buffer_size (DataType::MIDI)))) { set_display_to_user (false); @@ -3549,7 +3551,8 @@ TriggerBox::arm_from_another_thread (Trigger& slot, samplepos_t now, uint32_t ch slot.compute_quantized_transition (now, now_beats, std::numeric_limits::max(), t_bbt, t_beats, t_samples, tmap, slot.quantization()); - ai->start = t_samples; + ai->start_samples = t_samples; + ai->start_beats = t_beats; _arm_info = ai; } @@ -3583,7 +3586,7 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_ bool reached_end = false; if (!ai->slot.armed()) { - if (!ai->end) { + if (!ai->end_samples) { /* disarmed: compute end */ Beats start_b; Beats end_b; @@ -3595,7 +3598,8 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_ ai->slot.compute_quantized_transition (start_sample, now_beats, std::numeric_limits::max(), t_bbt, t_beats, t_samples, tmap, ai->slot.quantization()); - ai->end = t_samples; + ai->end_samples = t_samples; + ai->end_beats = t_beats; return; } } @@ -3609,25 +3613,25 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_ return; } - if (ai->end.samples() != 0 && (start_sample > ai->end.samples())) { + if (ai->end_samples != 0 && (start_sample > ai->end_samples)) { return; } - if (start_sample < ai->start.samples() && end_sample < ai->start.samples() ) { + if (start_sample < ai->start_samples && end_sample < ai->start_samples) { /* Have not yet reached the start of capture */ return; } - if (ai->start.samples() >= start_sample && ai->start.samples() < end_sample) { + if (ai->start_samples >= start_sample && ai->start_samples < end_sample) { /* Let's get going */ - offset = ai->start.samples() - start_sample; + offset = ai->start_samples - start_sample; nframes -= offset; _record_state = Recording; } - if ((ai->end.samples() != 0) && (start_sample <= ai->end.samples() && ai->end.samples() < end_sample)) { + if ((ai->end_samples != 0) && (start_sample <= ai->end_samples && ai->end_samples < end_sample)) { /* we're going to stop */ - nframes -= (end_sample - ai->end.samples()); + nframes -= (end_sample - ai->end_samples); reached_end = true; } @@ -3678,9 +3682,16 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_ } if (!skip_event && (!filter || !filter->filter(ev.buffer(), ev.size()))) { - const samplepos_t event_time (start_sample + ev.time() - ai->start.samples()); - if (!ai->end || (event_time < ai->end.samples())) { - ai->midi_buf->write (tmap->quarters_at_sample (event_time), ev.event_type(), ev.size(), ev.buffer()); + const samplepos_t event_time (start_sample + ev.time()); + if (!ai->end_samples || (event_time < ai->end_samples)) { + /* First write (to an * * RTMidiBufferBeats) uses beat time. + * Second write (to a FIFO) uses sample time. + * + * Both are relative to where we + * started capturing. + */ + ai->midi_buf->write (tmap->quarters_at_sample (event_time) - ai->start_beats, ev.event_type(), ev.size(), ev.buffer()); + _gui_feed_fifo.write (event_time - ai->start_samples, Evoral::MIDI_EVENT, ev.size(), ev.buffer()); send_signal = true; } } @@ -3688,6 +3699,7 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_ } if (send_signal) { + std::cerr << "SEND CAPTURED\n"; Captured(); /* EMIT SIGNAL */ } @@ -5699,3 +5711,21 @@ TriggerBoxThread::build_midi_source (MIDITrigger* t) t->set_region_in_worker_thread_from_capture (copy); } + +std::shared_ptr +TriggerBox::get_gui_feed_buffer () const +{ + Glib::Threads::Mutex::Lock lm (_gui_feed_reset_mutex); + std::shared_ptr b (new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI))); + + std::vector buffer (_gui_feed_fifo.capacity()); + samplepos_t time; + Evoral::EventType type; + uint32_t size; + + while (_gui_feed_fifo.read (&time, &type, &size, &buffer[0])) { + b->push_back (time, type, size, &buffer[0]); + } + + return b; +}