From 052ef18c4a045eb4a8ad818b9ca2970ae9766e6e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 23 Sep 2024 16:14:20 -0600 Subject: [PATCH] cliprec: add processor to tracks, and get MIDITrigger prepared for capture --- libs/ardour/ardour/cliprec.h | 7 ++ libs/ardour/ardour/route.h | 2 + libs/ardour/ardour/triggerbox.h | 10 ++- libs/ardour/cliprec.cc | 25 ++++++ libs/ardour/route.cc | 16 +++- libs/ardour/track.cc | 14 +++ libs/ardour/triggerbox.cc | 151 ++++++++++++++++++-------------- 7 files changed, 156 insertions(+), 69 deletions(-) diff --git a/libs/ardour/ardour/cliprec.h b/libs/ardour/ardour/cliprec.h index 240c43c554..d98d187014 100644 --- a/libs/ardour/ardour/cliprec.h +++ b/libs/ardour/ardour/cliprec.h @@ -51,9 +51,13 @@ class LIBARDOUR_API ClipRecProcessor : public DiskIOProcessor void run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool result_required); bool can_support_io_configuration (const ChanCount& in, ChanCount& out); + std::string display_name () const; + float buffer_load () const; void adjust_buffering (); void configuration_changed (); + int seek (samplepos_t, bool) { return 0; } + int add_channel_to (std::shared_ptr, uint32_t how_many) { return 0; } void arm_from_another_thread (Trigger& slot, samplepos_t, timecnt_t const & expected_duration, uint32_t chans); void disarm(); @@ -61,6 +65,9 @@ class LIBARDOUR_API ClipRecProcessor : public DiskIOProcessor bool armed() const { return (bool) _arm_info.load(); } PBD::Signal0 ArmedChanged; + int set_state (const XMLNode&, int version); + XMLNode& state () const; + private: DataType _data_type; std::atomic _arm_info; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 2e1be45087..da47b6544f 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -72,6 +72,7 @@ namespace ARDOUR { class Amp; class BeatBox; class DelayLine; +class ClipRecProcessor; class Delivery; class DiskReader; class DiskWriter; @@ -627,6 +628,7 @@ protected: std::shared_ptr _pannable; std::shared_ptr _disk_reader; std::shared_ptr _disk_writer; + std::shared_ptr _clip_recorder; #ifdef HAVE_BEATBOX std::shared_ptr _beatbox; #endif diff --git a/libs/ardour/ardour/triggerbox.h b/libs/ardour/ardour/triggerbox.h index 2676c1f980..8e91795780 100644 --- a/libs/ardour/ardour/triggerbox.h +++ b/libs/ardour/ardour/triggerbox.h @@ -294,9 +294,9 @@ class LIBARDOUR_API Trigger : public PBD::Stateful { timepos_t current_pos() const; double position_as_fraction() const; - void captured (SlotArmInfo&); - void arm(); - void disarm (); + virtual void captured (SlotArmInfo&) {} + virtual void arm() {} + virtual void disarm () {} Temporal::BBT_Argument compute_start (Temporal::TempoMap::SharedPtr const &, samplepos_t start, samplepos_t end, Temporal::BBT_Offset const & q, samplepos_t& start_samples, bool& will_start); virtual timepos_t compute_end (Temporal::TempoMap::SharedPtr const &, Temporal::BBT_Time const &, samplepos_t, Temporal::Beats &) = 0; @@ -579,6 +579,10 @@ class LIBARDOUR_API MIDITrigger : public Trigger { MIDITrigger (uint32_t index, TriggerBox&); ~MIDITrigger (); + void captured (SlotArmInfo&); + void arm(); + void disarm (); + template pframes_t midi_run (BufferSet&, samplepos_t start_sample, samplepos_t end_sample, Temporal::Beats const & start_beats, Temporal::Beats const & end_beats, pframes_t nframes, pframes_t offset, double bpm, pframes_t& quantize_offset); diff --git a/libs/ardour/cliprec.cc b/libs/ardour/cliprec.cc index bfd8dee74d..38796531d9 100644 --- a/libs/ardour/cliprec.cc +++ b/libs/ardour/cliprec.cc @@ -43,6 +43,7 @@ ClipRecProcessor::ClipRecProcessor (Session& s, Track& t, std::string const & na : DiskIOProcessor (s, t,name, DiskIOProcessor::Recordable, tdp) , _data_type (dt) { + _display_to_user = false; } SlotArmInfo::SlotArmInfo (Trigger& s) @@ -233,3 +234,27 @@ ClipRecProcessor::configuration_changed () { /* nothing to do */ } + +XMLNode& +ClipRecProcessor::state () const +{ + XMLNode& node (DiskIOProcessor::state ()); + node.set_property (X_("type"), X_("cliprec")); + return node; +} + +int +ClipRecProcessor::set_state (const XMLNode& node, int version) +{ + if (DiskIOProcessor::set_state (node, version)) { + return -1; + } + + return 0; +} + +std::string +ClipRecProcessor::display_name () const +{ + return std::string (_("Cue Recorder")); +} diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index ca4dc2f87c..045801befa 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -59,6 +59,7 @@ #include "ardour/buffer.h" #include "ardour/buffer_set.h" #include "ardour/capturing_processor.h" +#include "ardour/cliprec.h" #include "ardour/debug.h" #include "ardour/delivery.h" #include "ardour/disk_reader.h" @@ -2803,6 +2804,9 @@ Route::set_state (const XMLNode& node, int version) DiskIOPoint diop; if (node.get_property (X_("disk-io-point"), diop)) { + if (_clip_recorder) { + _clip_recorder->set_display_to_user (diop == DiskIOCustom); + } if (_disk_writer) { _disk_writer->set_display_to_user (diop == DiskIOCustom); } @@ -3233,6 +3237,9 @@ Route::set_processor_state (const XMLNode& node, int version) } else if (prop->value() == "diskwriter" && _disk_writer) { _disk_writer->set_state (**niter, version); new_order.push_back (_disk_writer); + } else if (prop->value() == "cliprec" && _clip_recorder) { + _clip_recorder->set_state (**niter, version); + new_order.push_back (_clip_recorder); } else if (prop->value() == "triggerbox") { if (!_triggerbox) { _triggerbox.reset (new TriggerBox (_session, _default_type)); @@ -5421,7 +5428,7 @@ Route::setup_invisible_processors () /* DISK READER & WRITER (for Track objects) */ - if (_disk_reader || _disk_writer) { + if (_disk_reader || _disk_writer || _clip_recorder) { switch (_disk_io_point) { case DiskIOPreFader: if (trim != new_processors.end()) { @@ -5469,6 +5476,9 @@ Route::setup_invisible_processors () assert (writer_pos == find (new_processors.begin(), new_processors.end(), _disk_writer)); reader_pos = new_processors.insert (++writer_pos, _disk_reader); } + if (_clip_recorder) { + new_processors.insert (reader_pos, _clip_recorder); + } } /* Polarity Invert */ @@ -6088,6 +6098,10 @@ Route::set_disk_io_point (DiskIOPoint diop) display = false; } + if (_clip_recorder) { + _clip_recorder->set_display_to_user (display); + } + if (_disk_writer) { _disk_writer->set_display_to_user (display); } diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index d91c4b9a47..98762323bb 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -28,6 +28,7 @@ #include "ardour/audiofilesource.h" #include "ardour/audioplaylist.h" #include "ardour/audioregion.h" +#include "ardour/cliprec.h" #include "ardour/debug.h" #include "ardour/delivery.h" #include "ardour/disk_reader.h" @@ -89,6 +90,10 @@ Track::~Track () if (_disk_writer) { _disk_writer.reset (); } + + if (_clip_recorder) { + _clip_recorder.reset (); + } } int @@ -113,6 +118,9 @@ Track::init () _disk_writer->set_block_size (_session.get_block_size ()); _disk_writer->set_owner (this); + _clip_recorder.reset (new ClipRecProcessor (_session, *this, name(), data_type(), *this)); + _clip_recorder->set_owner (this); + /* no triggerbox for the auditioner, to avoid visual clutter in * patchbays and elsewhere (or special-case code in those places) */ @@ -989,6 +997,12 @@ Track::set_processor_state (XMLNode const& node, int version, XMLProperty const* new_order.push_back (_disk_writer); return true; } + } else if (prop->value() == "cliprec") { + if (_clip_recorder) { + _clip_recorder->set_state (node, version); + new_order.push_back (_clip_recorder); + return true; + } } error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index 273e130699..766455af00 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -1278,71 +1278,6 @@ AudioTrigger::~AudioTrigger () delete _stretcher; } -void -MIDITrigger::check_edit_swap (timepos_t const & time, bool playing, BufferSet& bufs) -{ - RTMidiBufferBeats* pending = pending_rt_midibuffer.load(); - - if (!pending) { - return; - } - - if (playing) { - MidiBuffer& mbuf (bufs.get_midi (0)); - MidiStateTracker post_edit_state; - - /* Get the new MIDI state at the current time, and resolve any - * differences with the MIDI state held by the triggerbox we're - * in. - */ - - /* note: transition_beats is the time of the most recent - * transition (e.g. loop point) - */ - - Temporal::Beats p = time.beats() - transition_beats; - - /* now determine the state at this time, which we need relative - * to the start of the loop within the data. - */ - - pending->track_state (p - loop_start, post_edit_state); - _box.tracker->resolve_diff (post_edit_state, mbuf, time.samples()); - } - - old_rt_midibuffer = rt_midibuffer.exchange (pending); - if (iter < rt_midibuffer.load()->size()) { - /* shutdown */ - } - - RTMidiBufferBeats* ort = rt_midibuffer.load (); - - first_event_index = std::numeric_limits::min(); - last_event_index = std::numeric_limits::max(); - - for (uint32_t n = 0; n < ort->size(); ++n) { - if (first_event_index == std::numeric_limits::min()) { - if ((*ort)[n].timestamp <= loop_start) { - first_event_index = n; - } else { - break; - } - } - } - - for (uint32_t n = 0; n < ort->size(); ++n) { - if (last_event_index == std::numeric_limits::max()) { - if ((*ort)[n].timestamp >= loop_end) { - last_event_index = n; /* exclusive end */ - break; - } - } - } - - pending_rt_midibuffer = nullptr; -} - - void AudioTrigger::set_stretch_mode (Trigger::StretchMode sm) { @@ -2259,6 +2194,89 @@ MIDITrigger::~MIDITrigger () { } +void +MIDITrigger::check_edit_swap (timepos_t const & time, bool playing, BufferSet& bufs) +{ + RTMidiBufferBeats* pending = pending_rt_midibuffer.load(); + + if (!pending) { + return; + } + + if (playing) { + MidiBuffer& mbuf (bufs.get_midi (0)); + MidiStateTracker post_edit_state; + + /* Get the new MIDI state at the current time, and resolve any + * differences with the MIDI state held by the triggerbox we're + * in. + */ + + /* note: transition_beats is the time of the most recent + * transition (e.g. loop point) + */ + + Temporal::Beats p = time.beats() - transition_beats; + + /* now determine the state at this time, which we need relative + * to the start of the loop within the data. + */ + + pending->track_state (p - loop_start, post_edit_state); + _box.tracker->resolve_diff (post_edit_state, mbuf, time.samples()); + } + + old_rt_midibuffer = rt_midibuffer.exchange (pending); + if (iter < rt_midibuffer.load()->size()) { + /* shutdown */ + } + + RTMidiBufferBeats* ort = rt_midibuffer.load (); + + first_event_index = std::numeric_limits::min(); + last_event_index = std::numeric_limits::max(); + + for (uint32_t n = 0; n < ort->size(); ++n) { + if (first_event_index == std::numeric_limits::min()) { + if ((*ort)[n].timestamp <= loop_start) { + first_event_index = n; + } else { + break; + } + } + } + + for (uint32_t n = 0; n < ort->size(); ++n) { + if (last_event_index == std::numeric_limits::max()) { + if ((*ort)[n].timestamp >= loop_end) { + last_event_index = n; /* exclusive end */ + break; + } + } + } + + pending_rt_midibuffer = nullptr; +} + +void +MIDITrigger::arm () +{ +} + +void +MIDITrigger::disarm () +{ +} + +void +MIDITrigger::captured (SlotArmInfo& ai) +{ + RTMidiBufferBeats* rtmb = ai.midi_buf->convert (); + /* Note: the original MIDI buffer in ai is now invalid, all data has + * been moved to rtmb. + */ +} + void MIDITrigger::set_used_channels (Evoral::SMF::UsedChannels used) { @@ -2774,6 +2792,9 @@ MIDITrigger::set_region_in_worker_thread (std::shared_ptr r) DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 loaded midi region, span is %2\n", name(), data_length)); + /* This is being used as a kind of shorthand for "everything" which is + pretty stupid + */ send_property_change (ARDOUR::Properties::name); return 0;