extend MidiModel and MIDITrigger in preparation for edit-change handling

This commit is contained in:
Paul Davis
2024-06-21 22:18:52 -06:00
parent 5da8de05ca
commit 7dee98279a
5 changed files with 59 additions and 3 deletions

View File

@@ -48,6 +48,7 @@ namespace ARDOUR {
class Session;
class MidiSource;
class MidiStateTracker;
/** This is a higher level (than MidiBuffer) model of MIDI data, with separate
* representations for notes (instead of just unassociated note on/off events)
@@ -61,6 +62,7 @@ public:
typedef Temporal::Beats TimeType;
MidiModel (MidiSource&);
MidiModel (MidiModel const & other, MidiSource&);
class LIBARDOUR_API DiffCommand : public PBD::Command {
public:
@@ -324,6 +326,8 @@ public:
void insert_silence_at_start (TimeType);
void transpose (NoteDiffCommand *, const NotePtr, int);
void track_state (timepos_t const & when, MidiStateTracker&) const;
protected:
int resolve_overlaps_unlocked (const NotePtr, void* arg = 0);

View File

@@ -580,6 +580,8 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
return midi_run<true> (bufs, start_sample, end_sample, start, end, nframes, dest_offset, bpm, quantize_offset);
}
void swap_model (std::shared_ptr<ARDOUR::MidiModel>, ARDOUR::MidiModel::DiffCommand*);
void set_start (timepos_t const &);
void set_end (timepos_t const &);
void set_legato_offset (timepos_t const &);
@@ -657,6 +659,16 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
int load_data (std::shared_ptr<MidiRegion>);
void compute_and_set_length ();
void _startup (BufferSet&, pframes_t dest_offset, Temporal::BBT_Offset const &);
struct ModelSwap {
std::shared_ptr<ARDOUR::MidiModel> model;
ARDOUR::MidiModel::DiffCommand* cmd;
ModelSwap (std::shared_ptr<ARDOUR::MidiModel> m, ARDOUR::MidiModel::DiffCommand* c)
: model (m), cmd (c) {}
};
std::atomic<ModelSwap*> model_swap;
};
class LIBARDOUR_API TriggerBoxThread

View File

@@ -66,6 +66,14 @@ MidiModel::MidiModel (MidiSource& s)
_midi_source.AutomationStateChanged.connect_same_thread (_midi_source_connections, boost::bind (&MidiModel::source_automation_state_changed, this, _1, _2));
}
MidiModel::MidiModel (MidiModel const & other, MidiSource & s)
: AutomatableSequence<TimeType> (other)
, _midi_source (s)
{
_midi_source.InterpolationChanged.connect_same_thread (_midi_source_connections, boost::bind (&MidiModel::source_interpolation_changed, this, _1, _2));
_midi_source.AutomationStateChanged.connect_same_thread (_midi_source_connections, boost::bind (&MidiModel::source_automation_state_changed, this, _1, _2));
}
MidiModel::NoteDiffCommand*
MidiModel::new_note_diff_command (const string& name)
{
@@ -1424,7 +1432,7 @@ MidiModel::find_sysex (Evoral::event_id_t sysex_id)
MidiModel::WriteLock
MidiModel::edit_lock()
{
Source::WriterLock* source_lock = 0;
Source::WriterLock* source_lock = nullptr;
/* Take source lock and invalidate iterator to release its lock on model.
* Add currently active notes to _active_notes so we can restore them
@@ -1866,3 +1874,11 @@ MidiModel::rebuild_from_mapping_stash (Temporal::Beats const & src_pos_offset)
tempo_mapping_stash.clear ();
}
void
MidiModel::track_state (timepos_t const & when, MidiStateTracker& mst) const
{
for (auto const & ev : *this) {
mst.track (ev.buffer());
}
}

View File

@@ -497,6 +497,7 @@ void
MidiSource::set_model (const WriterLock& lock, std::shared_ptr<MidiModel> m)
{
_model = m;
std::cerr << "Source " << name() << " switched to model " << _model << std::endl;
invalidate(lock);
ModelChanged (); /* EMIT SIGNAL */
}

View File

@@ -2205,6 +2205,7 @@ MIDITrigger::MIDITrigger (uint32_t n, TriggerBox& b)
, pending_rt_midibuffer (nullptr)
, old_rt_midibuffer (nullptr)
, map_change (false)
, model_swap (nullptr)
{
_channel_map.assign (16, -1);
}
@@ -2213,6 +2214,14 @@ MIDITrigger::~MIDITrigger ()
{
}
void
MIDITrigger::check_edit_swap (bool playing)
{
if (model_swap != nullptr) {
std::cerr << "EDIT!\n";
}
}
void
MIDITrigger::set_used_channels (Evoral::SMF::UsedChannels used)
{
@@ -2779,6 +2788,13 @@ MIDITrigger::tempo_map_changed ()
map_change = true;
}
void
MIDITrigger::swap_model (std::shared_ptr<ARDOUR::MidiModel> model, ARDOUR::MidiModel::DiffCommand* cmd)
{
ModelSwap* ms = new ModelSwap (model, cmd);
model_swap = ms;
}
template<bool in_process_context>
pframes_t
MIDITrigger::midi_run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
@@ -2787,12 +2803,15 @@ MIDITrigger::midi_run (BufferSet& bufs, samplepos_t start_sample, samplepos_t en
{
assert (rt_midibuffer);
MidiBuffer* mb (in_process_context? &bufs.get_midi (0) : 0);
MidiBuffer* mb (in_process_context? &bufs.get_midi (0) : nullptr);
typedef Evoral::Event<MidiModel::TimeType> MidiEvent;
const timepos_t region_start_time = _region->start();
const Temporal::Beats region_start = region_start_time.beats();
Temporal::TempoMap::SharedPtr tmap (Temporal::TempoMap::use());
std::shared_ptr<MidiRegion> mr = std::dynamic_pointer_cast<MidiRegion> (_region);
assert (mr);
last_event_samples = end_sample;
/* see if we're going to start or stop or retrigger in this run() call */
@@ -3145,7 +3164,7 @@ TriggerBox::send_property_change (PBD::PropertyChange pc)
TriggerBox::TriggerBox (Session& s, DataType dt)
: Processor (s, _("TriggerBox"), Temporal::TimeDomainProvider (Temporal::BeatTime))
, tracker (dt == DataType::MIDI ? new MidiStateTracker : 0)
, tracker (dt == DataType::MIDI ? new MidiStateTracker : nullptr)
, _data_type (dt)
, _order (-1)
, explicit_queue (64)
@@ -4830,6 +4849,10 @@ TriggerBox::process_requests (BufferSet& bufs)
{
Request* r;
for (uint64_t n = 0; n < all_triggers.size(); ++n) {
all_triggers[n]->check_edit_swap (_currently_playing == all_triggers[n]);
}
while (requests.read (&r, 1) == 1) {
process_request (bufs, r);
}