13
0

various changes to get MIDI clip recording to display the post-capture region

This commit is contained in:
Paul Davis 2024-10-22 14:41:40 -06:00
parent aa2fb8c1d4
commit e11caf2dea
7 changed files with 143 additions and 119 deletions

View File

@ -494,20 +494,6 @@ MidiCueEditor::idle_data_captured ()
return false;
}
void
MidiCueEditor::set_box (std::shared_ptr<ARDOUR::TriggerBox> b)
{
capture_connections.drop_connections ();
idle_update_queued.store (0);
if (b) {
b->Captured.connect (capture_connections, invalidator (*this), std::bind (&MidiCueEditor::data_captured, this, _1), gui_context());
/* Don't bind a shared_ptr<TriggerBox> within the lambda */
TriggerBox* tb (b.get());
b->RecEnableChanged.connect (capture_connections, invalidator (*this), [&, tb]() { box_rec_enable_change (*tb); }, gui_context());
}
}
void
MidiCueEditor::box_rec_enable_change (ARDOUR::TriggerBox const & b)
{
@ -528,61 +514,6 @@ MidiCueEditor::trigger_rec_enable_change (ARDOUR::Trigger const & t)
}
}
void
MidiCueEditor::set_track (std::shared_ptr<ARDOUR::MidiTrack> t)
{
_track = t;
view->set_track (t);
_update_connection.disconnect ();
capture_connections.drop_connections ();
if (t) {
set_box (t->triggerbox());
_update_connection = Timers::rapid_connect (sigc::mem_fun (*this, &MidiCueEditor::maybe_update));
_track->DropReferences.connect (track_connection, invalidator (*this), std::bind (&MidiCueEditor::set_track, this, nullptr), gui_context());
} else {
set_box (nullptr);
}
}
void
MidiCueEditor::set_region (std::shared_ptr<ARDOUR::MidiRegion> r)
{
if (!r) {
view->set_region (nullptr);
return;
}
view->set_region (r);
/* Compute zoom level to show entire source plus some margin if possible */
Temporal::timecnt_t duration = Temporal::timecnt_t (r->midi_source()->length().beats());
bool provided = false;
std::shared_ptr<Temporal::TempoMap> map;
std::shared_ptr<SMFSource> smf (std::dynamic_pointer_cast<SMFSource> (r->midi_source()));
if (smf) {
map = smf->tempo_map (provided);
}
if (!provided) {
map.reset (new Temporal::TempoMap (Temporal::Tempo (120, 4), Temporal::Meter (4, 4)));
}
{
EditingContext::TempoMapScope tms (*this, map);
double width = bg->width();
samplecnt_t samples = duration.samples();
samplecnt_t spp = floor (samples / width);
reset_zoom (spp);
}
}
bool
MidiCueEditor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
{
@ -1761,3 +1692,98 @@ MidiCueEditor::selectable_owners()
return std::list<SelectableOwner*> ();
}
void
MidiCueEditor::trigger_prop_change (PBD::PropertyChange const & what_changed)
{
if (what_changed.contains (Properties::region)) {
std::shared_ptr<MidiRegion> mr = std::dynamic_pointer_cast<MidiRegion> (ref.trigger()->the_region());
if (mr) {
set_region (mr);
}
}
}
void
MidiCueEditor::set (TriggerReference & tref)
{
_update_connection.disconnect ();
object_connections.drop_connections ();
ref = tref;
idle_update_queued.store (0);
ref.box()->Captured.connect (object_connections, invalidator (*this), std::bind (&MidiCueEditor::data_captured, this, _1), gui_context());
/* Don't bind a shared_ptr<TriggerBox> within the lambda */
TriggerBox* tb (ref.box().get());
tb->RecEnableChanged.connect (object_connections, invalidator (*this), [&, tb]() { box_rec_enable_change (*tb); }, gui_context());
Stripable* st = dynamic_cast<Stripable*> (ref.box()->owner());
assert (st);
_track = std::dynamic_pointer_cast<MidiTrack> (st->shared_from_this());
assert (_track);
view->set_track (_track);
_update_connection = Timers::rapid_connect (sigc::mem_fun (*this, &MidiCueEditor::maybe_update));
_track->DropReferences.connect (object_connections, invalidator (*this), std::bind (&MidiCueEditor::unset, this), gui_context());
ref.trigger()->PropertyChanged.connect (object_connections, invalidator (*this), std::bind (&MidiCueEditor::trigger_prop_change, this, _1), gui_context());
if (ref.trigger()->the_region()) {
std::shared_ptr<MidiRegion> mr = std::dynamic_pointer_cast<MidiRegion> (ref.trigger()->the_region());
if (mr) {
set_region (mr);
}
}
}
void
MidiCueEditor::unset ()
{
_update_connection.disconnect();
object_connections.drop_connections ();
_track.reset ();
view->set_region (nullptr);
ref = TriggerReference ();
}
void
MidiCueEditor::set_region (std::shared_ptr<ARDOUR::MidiRegion> r)
{
if (!r) {
view->set_region (nullptr);
return;
}
view->set_region (r);
/* Compute zoom level to show entire source plus some margin if possible */
Temporal::timecnt_t duration = Temporal::timecnt_t (r->midi_source()->length().beats());
std::cerr << "new region: " << duration << std::endl;
bool provided = false;
std::shared_ptr<Temporal::TempoMap> map;
std::shared_ptr<SMFSource> smf (std::dynamic_pointer_cast<SMFSource> (r->midi_source()));
if (smf) {
map = smf->tempo_map (provided);
}
if (!provided) {
map.reset (new Temporal::TempoMap (Temporal::Tempo (120, 4), Temporal::Meter (4, 4)));
}
{
EditingContext::TempoMapScope tms (*this, map);
double width = bg->width();
samplecnt_t samples = duration.samples();
std::cerr << "new spp from " << samples << " / " << width << std::endl;
samplecnt_t spp = floor (samples / width);
reset_zoom (spp);
}
}

View File

@ -72,9 +72,8 @@ class MidiCueEditor : public CueEditor
int32_t get_grid_beat_divisions (Editing::GridType gt) const { return 1; }
int32_t get_grid_music_divisions (Editing::GridType gt, uint32_t event_state) const { return 1; }
void set (ARDOUR::TriggerReference&);
void set_region (std::shared_ptr<ARDOUR::MidiRegion>);
void set_box (std::shared_ptr<ARDOUR::TriggerBox>);
void set_track (std::shared_ptr<ARDOUR::MidiTrack>);
ArdourCanvas::ScrollGroup* get_hscroll_group () const { return h_scroll_group; }
ArdourCanvas::ScrollGroup* get_cursor_scroll_group () const { return cursor_scroll_group; }
@ -140,6 +139,7 @@ class MidiCueEditor : public CueEditor
void on_samples_per_pixel_changed ();
private:
ARDOUR::TriggerReference ref;
std::shared_ptr<ARDOUR::MidiTrack> _track;
ArdourCanvas::GtkCanvasViewport* _canvas_viewport;
ArdourCanvas::GtkCanvas* _canvas;
@ -208,8 +208,11 @@ class MidiCueEditor : public CueEditor
void stop_canvas_autoscroll ();
sigc::connection _update_connection;
PBD::ScopedConnection track_connection;
PBD::ScopedConnectionList object_connections;
void maybe_update ();
void trigger_prop_change (PBD::PropertyChange const &);
void unset ();
void visual_changer (const VisualChange&);
void bindings_changed ();
@ -217,7 +220,6 @@ class MidiCueEditor : public CueEditor
void data_captured (Temporal::timecnt_t);
bool idle_data_captured ();
std::atomic<int> idle_update_queued;
PBD::ScopedConnectionList capture_connections;
Temporal::timecnt_t data_capture_duration;
};

View File

@ -95,7 +95,7 @@ MidiCueView::set_height (double h)
double automation_height = h - note_area_height - velocity_height;
event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, note_area_height));
midi_context().set_size (ArdourCanvas::COORD_MAX, note_area_height);
midi_context().set_size (midi_context().width(), note_area_height);
velocity_base->set_position (ArdourCanvas::Duple (0., note_area_height));
velocity_base->set (ArdourCanvas::Rect (0., 0., ArdourCanvas::COORD_MAX, velocity_height));

View File

@ -236,8 +236,18 @@ MidiView::set_model (std::shared_ptr<MidiModel> m)
assert (_midi_track);
assert (_midi_region);
clear_events ();
connections_requiring_model.drop_connections ();
_model = m;
if (!_model) {
std::cerr << "no model!\n";
return;
}
std::cerr << "model set to " << _model << std::endl;
//set_height (trackview.current_height());
#warning paul pianorule needs these fixed
@ -251,8 +261,6 @@ MidiView::set_model (std::shared_ptr<MidiModel> m)
reset_width_dependent_items (_pixel_width);
*/
connections_requiring_model.drop_connections ();
_model->ContentsChanged.connect (connections_requiring_model, invalidator (*this), std::bind (&MidiView::model_changed, this), gui_context());
_midi_track->playback_filter().ChannelModeChanged.connect (connections_requiring_model, invalidator (*this),
@ -849,9 +857,8 @@ MidiView::clear_events ()
{
// clear selection without signaling or trying to change state of event objects
_selection.clear ();
clear_ghost_events ();
/* This will delete all the NoteBase* in the _events map */
_note_group->clear (true);
_events.clear();
_patch_changes.clear();
@ -863,8 +870,6 @@ void
MidiView::display_model (std::shared_ptr<MidiModel> model)
{
set_model (_model);
/* Don't signal as nobody else needs to know until selection has been altered. */
clear_events();
model_changed ();
}
@ -1099,14 +1104,16 @@ MidiView::model_changed()
return;
}
if (!_model) {
return;
}
for (_optimization_iterator = _events.begin(); _optimization_iterator != _events.end(); ++_optimization_iterator) {
_optimization_iterator->second->invalidate ();
}
/* note that _optimization_iterator now points to _events.end() */
if (!_model) {
return;
}
bool empty_when_starting = _events.empty();
_optimization_iterator = _events.begin();
MidiModel::Notes missing_notes;
@ -1588,6 +1595,7 @@ void
MidiView::end_write()
{
if (_active_notes) {
std::cerr << "active notes deleted in end_write\n";
for (unsigned i = 0; i < 128; ++i) {
delete _active_notes[i];
}

View File

@ -419,23 +419,7 @@ TriggerPage::rec_enable_changed (Trigger const * trigger)
_midi_trig_box.set_trigger (ref);
_midi_trig_box.show ();
_midi_editor->set_box (trigger->boxptr());
Stripable* st = dynamic_cast<Stripable*> (box.owner());
assert (st);
std::shared_ptr<MidiTrack> mt = std::dynamic_pointer_cast<MidiTrack> (st->shared_from_this());
assert (mt);
_midi_editor->set_track (mt);
if (trigger->the_region()) {
std::shared_ptr<MidiRegion> mr = std::dynamic_pointer_cast<MidiRegion> (trigger->the_region());
if (mr) {
_midi_editor->set_region (mr);
}
}
_midi_editor->set (ref);
_midi_editor->viewport().show ();
}
@ -475,19 +459,7 @@ TriggerPage::selection_changed ()
_midi_trig_box.set_trigger (ref);
_midi_trig_box.show ();
std::shared_ptr<MidiTrack> mt = std::dynamic_pointer_cast<MidiTrack> (entry->strip().stripable());
assert (mt);
_midi_editor->set_track (mt);
if (trigger->the_region()) {
std::shared_ptr<MidiRegion> mr = std::dynamic_pointer_cast<MidiRegion> (trigger->the_region());
if (mr) {
_midi_editor->set_region (mr);
}
}
_midi_editor->set (ref);
_midi_editor->viewport().show ();
}

View File

@ -41,6 +41,7 @@ class ViewBackground
virtual ~ViewBackground ();
virtual double height() const { return 0.; }
virtual double width() const { return 0.; }
virtual double contents_height() const { return 0.; }
/** @return y position, or -1 if hidden */

View File

@ -127,6 +127,7 @@ TriggerBox::all_trigger_props()
all.add(Properties::patch_change);
all.add(Properties::channel_map);
all.add(Properties::used_channels);
all.add(Properties::region);
return all;
}
@ -313,7 +314,6 @@ Trigger::arm ()
void
Trigger::disarm ()
{
_box.disarm ();
_armed = false;
ArmChanged(); /* EMIT SIGNAL */
TriggerArmChanged (this);
@ -1965,10 +1965,12 @@ AudioTrigger::captured (SlotArmInfo& ai, BufferSet&)
delete &ai; // XXX delete is not RT-safe
_box.queue_explict (index());
TriggerBox::worker->request_build_source (this);
_armed = false;
ArmChanged(); /* EMIT SIGNAL */
TriggerArmChanged (this);
TriggerBox::worker->request_build_source (this, timecnt_t (data.length));
}
int
@ -2438,6 +2440,7 @@ void
MIDITrigger::captured (SlotArmInfo& ai, BufferSet& bufs)
{
if (ai.midi_buf->size() == 0) {
std::cerr << "nothing recorded\n";
_armed = false;
ArmChanged(); /* EMIT SIGNAL */
delete &ai;
@ -2468,10 +2471,13 @@ MIDITrigger::captured (SlotArmInfo& ai, BufferSet& bufs)
_box.queue_explict (index());
/* Meanwhile, build a new source and region from the data now in rt_midibuffer */
TriggerBox::worker->request_build_source (this);
std::cerr << "request source ...\n";
_armed = false;
ArmChanged(); /* EMIT SIGNAL */
TriggerArmChanged (this);
TriggerBox::worker->request_build_source (this, timecnt_t (data_length));
}
void
@ -2946,6 +2952,8 @@ MIDITrigger::set_region_in_worker_thread_from_capture (std::shared_ptr<Region> r
{
assert (r);
std::cerr << "SRIWTFC " << r->name() << std::endl;
std::shared_ptr<MidiRegion> mr = std::dynamic_pointer_cast<MidiRegion> (r);
if (!mr) {
@ -2966,7 +2974,8 @@ MIDITrigger::set_region_in_worker_thread_from_capture (std::shared_ptr<Region> r
/* This is being used as a kind of shorthand for "everything" which is
pretty stupid
*/
send_property_change (ARDOUR::Properties::name);
std::cerr << "send region change\n";
send_property_change (ARDOUR::Properties::region);
return 0;
}
@ -3597,10 +3606,16 @@ TriggerBox::disarm_all ()
void
TriggerBox::finish_recording (BufferSet& bufs)
{
std::cerr << "FR!\n";
SlotArmInfo* ai = _arm_info.load();
assert (ai);
/* This transfers responsibility for the SlotArmInfo object to the
trigger
*/
ai->slot.captured (*ai, bufs);
_arm_info = nullptr;
_record_state = Disabled;
}
void