From 859d43855eae0c1bd8192029388bfbd0056f914b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 4 Nov 2021 14:00:16 -0600 Subject: [PATCH] triggerbox: functional handling of MIDI region editing -> trigger re-render/reload --- libs/ardour/ardour/triggerbox.h | 17 +++-- libs/ardour/triggerbox.cc | 107 +++++++++++++++++++++++++------- 2 files changed, 99 insertions(+), 25 deletions(-) diff --git a/libs/ardour/ardour/triggerbox.h b/libs/ardour/ardour/triggerbox.h index 12cb568a97..0becc40dee 100644 --- a/libs/ardour/ardour/triggerbox.h +++ b/libs/ardour/ardour/triggerbox.h @@ -84,6 +84,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful { virtual void set_end (timepos_t const &) = 0; virtual void set_length (timecnt_t const &) = 0; virtual void tempo_map_change () = 0; + virtual void reload (BufferSet&, void*) = 0; virtual double position_as_fraction() const = 0; @@ -237,6 +238,7 @@ class LIBARDOUR_API AudioTrigger : public Trigger { timepos_t start_offset () const { return timepos_t (_start_offset); } /* offset from start of data */ timepos_t current_length() const; /* offset from start of data */ timepos_t natural_length() const; /* offset from start of data */ + void reload (BufferSet&, void*); double position_as_fraction() const; @@ -287,6 +289,7 @@ class LIBARDOUR_API MIDITrigger : public Trigger { timepos_t end() const; /* offset from start of data */ timepos_t current_length() const; /* offset from start of data */ timepos_t natural_length() const; /* offset from start of data */ + void reload (BufferSet&, void*); double position_as_fraction() const; @@ -306,8 +309,9 @@ class LIBARDOUR_API MIDITrigger : public Trigger { private: PBD::ID data_source; - RTMidiBuffer data; + RTMidiBuffer* data; MidiStateTracker tracker; + PBD::ScopedConnection content_connection; size_t read_index; /* index into data */ samplecnt_t data_length; /* using timestamps from data */ @@ -320,6 +324,9 @@ class LIBARDOUR_API MIDITrigger : public Trigger { int load_data (boost::shared_ptr); RunResult at_end (); void compute_and_set_length (); + + void render (RTMidiBuffer&); + void re_render (); }; @@ -367,7 +374,7 @@ class LIBARDOUR_API TriggerBox : public Processor void add_midi_sidechain (std::string const & name); - void request_reload (int32_t slot); + void request_reload (int32_t slot, void*); void request_use (int32_t slot, Trigger&); enum TriggerMidiMapMode { @@ -446,6 +453,7 @@ class LIBARDOUR_API TriggerBox : public Processor union { Trigger* trigger; + void* ptr; }; union { @@ -464,9 +472,10 @@ class LIBARDOUR_API TriggerBox : public Processor typedef PBD::RingBuffer RequestBuffer; RequestBuffer requests; - void process_requests (); - void process_request (Request*); + void process_requests (BufferSet&); + void process_request (BufferSet&, Request*); + void reload (BufferSet& bufs, int32_t slot, void* ptr); }; namespace Properties { diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index 12fb2603df..138741657e 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -1,3 +1,4 @@ +#include #include #include @@ -16,6 +17,7 @@ #include "ardour/audio_buffer.h" #include "ardour/debug.h" #include "ardour/midi_buffer.h" +#include "ardour/midi_model.h" #include "ardour/midi_region.h" #include "ardour/minibpm.h" #include "ardour/port.h" @@ -946,6 +948,10 @@ AudioTrigger::run (BufferSet& bufs, pframes_t nframes, pframes_t dest_offset, bo return 0; } +void +AudioTrigger::reload (BufferSet&, void*) +{ +} /*--------------------*/ @@ -978,6 +984,7 @@ AudioTrigger::run (BufferSet& bufs, pframes_t nframes, pframes_t dest_offset, bo MIDITrigger::MIDITrigger (uint64_t n, TriggerBox& b) : Trigger (n, b) + , data (0) , read_index (0) , data_length (0) , usable_length (0) @@ -988,6 +995,7 @@ MIDITrigger::MIDITrigger (uint64_t n, TriggerBox& b) MIDITrigger::~MIDITrigger () { + drop_data (); } void @@ -1018,15 +1026,15 @@ MIDITrigger::position_as_fraction () const return 0.0; } - if (data.size() == 0) { + if (data->size() == 0) { return 0.0; } - if (read_index >= data.size()) { + if (read_index >= data->size()) { return 1.0; } - const samplepos_t l = data[read_index].timestamp; + const samplepos_t l = (*data)[read_index].timestamp; return l / (double) usable_length; } @@ -1097,7 +1105,7 @@ MIDITrigger::start_offset () const timepos_t MIDITrigger::current_pos() const { - return timepos_t (data[read_index].timestamp); + return timepos_t ((*data)[read_index].timestamp); } void @@ -1163,11 +1171,54 @@ MIDITrigger::set_region (boost::shared_ptr r) load_data (mr); set_length (mr->length()); + mr->model()->ContentsChanged.connect_same_thread (content_connection, boost::bind (&MIDITrigger::re_render, this)); + mr->PropertyChanged.connect_same_thread (content_connection, boost::bind (&MIDITrigger::re_render, this)); + PropertyChanged (ARDOUR::Properties::name); return 0; } +void +MIDITrigger::render (RTMidiBuffer& rtmb) +{ + /* this generates timestamps in session time. We want trigger-relative + * time (so the beginning of the region/trigger is zero). + */ + + boost::shared_ptr mr = boost::dynamic_pointer_cast (_region); + assert (mr); + + mr->render_range (rtmb, 0, Sustained, mr->start(), mr->length(), 0); + const sampleoffset_t shift = mr->position().samples(); + rtmb.shift (-shift); +} + +void +MIDITrigger::reload (BufferSet& bufs, void* ptr) +{ + MidiBuffer& mb (bufs.get_midi (0)); + + tracker.resolve_notes (mb, 0); + + RTMidiBuffer* rtmb = reinterpret_cast (ptr); + + std::swap (data, rtmb); + + delete rtmb; + + std::cerr << _index << " data now " << data << std::endl; +} + +void +MIDITrigger::re_render () +{ + RTMidiBuffer* new_data = new RTMidiBuffer; + std::cerr << "will re-render " << _region->name() << " into " << new_data << std::endl; + render (*new_data); + _box.request_reload (_index, new_data); +} + void MIDITrigger::tempo_map_change () { @@ -1176,7 +1227,8 @@ MIDITrigger::tempo_map_change () void MIDITrigger::drop_data () { - data.clear (); + delete data; + data = 0; } int @@ -1184,13 +1236,9 @@ MIDITrigger::load_data (boost::shared_ptr mr) { drop_data (); - /* this generates timestamps in session time. We want trigger-relative - * time (so the beginning of the region/trigger is zero). - */ + data = new RTMidiBuffer; - mr->render_range (data, 0, Sustained, mr->start(), mr->length(), 0); - const sampleoffset_t shift = mr->position().samples(); - data.shift (-shift); + render (*data); set_name (mr->name()); @@ -1223,9 +1271,9 @@ MIDITrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sam while (true) { - if (read_index < data.size()) { + if (read_index < data->size()) { - RTMidiBuffer::Item const & item (data[read_index]); + RTMidiBuffer::Item const & item ((*data)[read_index]); /* timestamps inside the RTMidiBuffer are relative to the start of the region. @@ -1235,12 +1283,12 @@ MIDITrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sam const samplepos_t effective_time = transition_samples + item.timestamp; - cerr << start_sample << " .. " << end_sample << " Item " << read_index << " @ " << item.timestamp << " + " << transition_samples << " = " << effective_time << endl; + // cerr << start_sample << " .. " << end_sample << " Item " << read_index << " @ " << item.timestamp << " + " << transition_samples << " = " << effective_time << endl; if (effective_time >= start_sample && effective_time < end_sample) { uint32_t sz; - uint8_t const * bytes = data.bytes (item, sz); + uint8_t const * bytes = data->bytes (item, sz); samplepos_t process_relative_timestamp = effective_time - start_sample; @@ -1258,7 +1306,7 @@ MIDITrigger::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sam const samplepos_t region_end = transition_samples + data_length; - if (read_index >= data.size() || (_state == Running && region_end >= start_sample && region_end <= end_sample)) { + if (read_index >= data->size() || (_state == Running && region_end >= start_sample && region_end <= end_sample)) { /* We reached the end */ @@ -1737,6 +1785,8 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp _sidechain->run (bufs, start_sample, end_sample, speed, nframes, true); } + process_requests (bufs); + process_midi_trigger_requests (bufs); if (_active_scene >= 0) { @@ -2246,10 +2296,11 @@ TriggerBox::Request::operator delete (void *ptr, size_t /*size*/) } void -TriggerBox::request_reload (int32_t slot) +TriggerBox::request_reload (int32_t slot, void* ptr) { - Request* r = new Request (Request::Use); + Request* r = new Request (Request::Reload); r->slot = slot; + r->ptr = ptr; requests.write (&r, 1); } @@ -2263,24 +2314,38 @@ TriggerBox::request_use (int32_t slot, Trigger& t) } void -TriggerBox::process_requests () +TriggerBox::process_requests (BufferSet& bufs) { Request* r; while (requests.read (&r, 1) == 1) { - process_request (r); + process_request (bufs, r); } } void -TriggerBox::process_request (Request* req) +TriggerBox::process_request (BufferSet& bufs, Request* req) { switch (req->type) { case Request::Use: + std::cerr << "Use for " << req->slot << std::endl; break; case Request::Reload: + std::cerr << "Reload for " << req->slot << std::endl; + reload (bufs, req->slot, req->ptr); break; } delete req; /* back to the pool, RT-safe */ } + +void +TriggerBox::reload (BufferSet& bufs, int32_t slot, void* ptr) +{ + if (slot >= all_triggers.size()) { + return; + } + std::cerr << "reload slot " << slot << std::endl; + all_triggers[slot]->reload (bufs, ptr); +} +