13
0

triggerbox: functional handling of MIDI region editing -> trigger re-render/reload

This commit is contained in:
Paul Davis 2021-11-04 14:00:16 -06:00
parent efdd3e86c3
commit 859d43855e
2 changed files with 99 additions and 25 deletions

View File

@ -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<MidiRegion>);
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<Request*> 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 {

View File

@ -1,3 +1,4 @@
#include <algorithm>
#include <iostream>
#include <cstdlib>
@ -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<Region> 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<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion> (_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<RTMidiBuffer*> (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<MidiRegion> 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);
}