From d7e85de7c2b4209d5a558eab87925f4980d6c5f2 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 13 Oct 2024 09:03:44 -0600 Subject: [PATCH] first somewhat version of show-clip-capture MIDI notes as they arrive --- gtk2_ardour/midi_cue_editor.cc | 43 +++++--- gtk2_ardour/midi_cue_editor.h | 6 +- gtk2_ardour/midi_cue_view.cc | 6 +- gtk2_ardour/midi_cue_view.h | 1 - gtk2_ardour/midi_view.cc | 181 +++++++++++++++++++++++---------- gtk2_ardour/midi_view.h | 2 + gtk2_ardour/trigger_page.cc | 17 ++-- 7 files changed, 176 insertions(+), 80 deletions(-) diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index cd8d145154..8c49310416 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -78,6 +78,8 @@ MidiCueEditor::MidiCueEditor() _toolbox.pack_start (viewport(), true, true); + view = new MidiCueView (nullptr, 0, *data_group, *this, *bg, 0xff0000ff); + _verbose_cursor = new VerboseCursor (*this); // _playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event, X_("playhead")); @@ -329,12 +331,9 @@ MidiCueEditor::canvas_allocate (Gtk::Allocation alloc) _visible_canvas_width = alloc.get_width(); _visible_canvas_height = alloc.get_height(); - if (view) { - double timebars = n_timebars * timebar_height; - view->set_height (alloc.get_height() - timebars); - } else { - bg->set_size (alloc.get_width(), alloc.get_height()); - } + double timebars = n_timebars * timebar_height; + view->set_height (alloc.get_height() - timebars); + bg->set_size (alloc.get_width(), alloc.get_height()); } timepos_t @@ -444,26 +443,42 @@ MidiCueEditor::data_captured () void MidiCueEditor::set_box (std::shared_ptr b) { - capture_connection.disconnect (); + capture_connections.drop_connections (); if (b) { - std::cerr << "Bix set to " << b->order() << std::endl; - b->Captured.connect (capture_connection, invalidator (*this), boost::bind (&MidiCueEditor::data_captured, this), gui_context()); + b->Captured.connect (capture_connections, invalidator (*this), boost::bind (&MidiCueEditor::data_captured, this), gui_context()); + /* Don't bind a shared_ptr within the lambda */ + TriggerBox* tb (b.get()); + b->RecEnableChanged.connect (capture_connections, invalidator (*this), [&, tb]() { rec_enable_change (tb); }, gui_context()); } } void -MidiCueEditor::set_region (std::shared_ptr t, uint32_t slot_index, std::shared_ptr r) +MidiCueEditor::rec_enable_change (ARDOUR::TriggerBox* b) { - delete view; - view = nullptr; + if (b->record_enabled()) { + view->begin_write(); + } else { + view->end_write (); + } +} - if (!t || !r) { +void +MidiCueEditor::set_track (std::shared_ptr t) +{ + view->set_track (t); +} + +void +MidiCueEditor::set_region (std::shared_ptr r) +{ + if (!r) { bg->set_view (nullptr); prh->set_view (nullptr); +#warning paul unset view model return; } - view = new MidiCueView (t, r, slot_index, *data_group, *this, *bg, 0xff0000ff); + view->set_region (r); bg->set_view (view); prh->set_view (view); diff --git a/gtk2_ardour/midi_cue_editor.h b/gtk2_ardour/midi_cue_editor.h index 847abd125f..a3eb970326 100644 --- a/gtk2_ardour/midi_cue_editor.h +++ b/gtk2_ardour/midi_cue_editor.h @@ -72,8 +72,9 @@ 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_region (std::shared_ptr, uint32_t slot_index, std::shared_ptr); + void set_region (std::shared_ptr); void set_box (std::shared_ptr); + void set_track (std::shared_ptr); ArdourCanvas::ScrollGroup* get_hscroll_group () const { return h_scroll_group; } ArdourCanvas::ScrollGroup* get_cursor_scroll_group () const { return cursor_scroll_group; } @@ -205,8 +206,9 @@ class MidiCueEditor : public CueEditor void visual_changer (const VisualChange&); void bindings_changed (); + void rec_enable_change (ARDOUR::TriggerBox*); void data_captured (); - PBD::ScopedConnection capture_connection; + PBD::ScopedConnectionList capture_connections; }; diff --git a/gtk2_ardour/midi_cue_view.cc b/gtk2_ardour/midi_cue_view.cc index 6366d1f014..374b39a15a 100644 --- a/gtk2_ardour/midi_cue_view.cc +++ b/gtk2_ardour/midi_cue_view.cc @@ -42,7 +42,6 @@ using namespace Gtkmm2ext; MidiCueView::MidiCueView (std::shared_ptr mt, - std::shared_ptr region, uint32_t slot_index, ArdourCanvas::Item& parent, EditingContext& ec, @@ -83,7 +82,6 @@ MidiCueView::MidiCueView (std::shared_ptr mt, } set_extensible (true); - set_region (region); Evoral::Parameter fully_qualified_param (ARDOUR::MidiCCAutomation, 0, MIDI_CTL_MSB_MODWHEEL); show_automation (fully_qualified_param); @@ -242,6 +240,10 @@ MidiCueView::show_automation (Evoral::Parameter const & param) { using namespace ARDOUR; + if (!_midi_region) { + return; + } + if (param.type() == NullAutomation) { return; } diff --git a/gtk2_ardour/midi_cue_view.h b/gtk2_ardour/midi_cue_view.h index 716d69dad4..01c8b5da12 100644 --- a/gtk2_ardour/midi_cue_view.h +++ b/gtk2_ardour/midi_cue_view.h @@ -33,7 +33,6 @@ class MidiCueView : public MidiView { public: MidiCueView (std::shared_ptr mt, - std::shared_ptr region, uint32_t slot_index, ArdourCanvas::Item& parent, EditingContext& ec, diff --git a/gtk2_ardour/midi_view.cc b/gtk2_ardour/midi_view.cc index f9758c3643..3f6ee8b300 100644 --- a/gtk2_ardour/midi_view.cc +++ b/gtk2_ardour/midi_view.cc @@ -141,7 +141,8 @@ MidiView::MidiView (std::shared_ptr mt, MidiView::MidiView (MidiView const & other) - : _editing_context (other.editing_context()) + : sigc::trackable (other) + , _editing_context (other.editing_context()) , _midi_context (other.midi_context()) , _midi_region (other.midi_region()) , _active_notes(0) @@ -190,6 +191,12 @@ MidiView::set_track (std::shared_ptr mt) if (_midi_track) { _midi_track->DropReferences.connect (track_going_away_connection, invalidator (*this), boost::bind (&MidiView::track_going_away, this), gui_context()); + + if (_midi_track->triggerbox()->record_enabled()) { + begin_write (); + } else { + end_write (); + } } } @@ -1516,6 +1523,7 @@ MidiView::apply_note_range (uint8_t min, uint8_t max, bool force) void MidiView::begin_write() { + std::cerr << "MV::begin write\n"; if (_active_notes) { delete[] _active_notes; } @@ -1531,8 +1539,9 @@ MidiView::begin_write() void MidiView::end_write() { + std::cerr << "MV::end write\n"; delete[] _active_notes; - _active_notes = 0; + _active_notes = nullptr; _marked_for_selection.clear(); _marked_for_velocity.clear(); } @@ -1593,6 +1602,9 @@ MidiView::start_playing_midi_chord (vector > notes) bool MidiView::note_in_region_time_range (const std::shared_ptr note) const { + if (!_midi_region) { + return true; + } const std::shared_ptr midi_reg = midi_region(); return (timepos_t (note->time()) >= _midi_region->start()) && (timepos_t (note->time()) < _midi_region->start() + _midi_region->length()); } @@ -1600,6 +1612,10 @@ MidiView::note_in_region_time_range (const std::shared_ptr note) const bool MidiView::note_in_region_range (const std::shared_ptr note, bool& visible) const { + if (!_midi_region) { + return true; + } + const std::shared_ptr midi_reg = midi_region(); const bool outside = !note_in_region_time_range (note); @@ -1628,63 +1644,15 @@ MidiView::update_note (NoteBase* note) void MidiView::update_sustained (Note* ev) { - const std::shared_ptr mr = midi_region(); std::shared_ptr note = ev->note(); - const timepos_t note_start (note->time()); - timepos_t note_end (note->end_time()); - - /* The note is drawn as a child item of this region view, so its - * coordinate system is relative to the region view. This means that x0 - * and x1 are pixel offsets relative to beginning of the region (view) - */ - - /* compute absolute time where the start of the source is - */ - - const timepos_t session_source_start = _midi_region->source_position(); - - /* this computes the number of samples from the start of the region of the start of the - * note. We add the source start to get to the absolute time of the - * note, then subtract the start of the region - */ - - const samplepos_t note_start_samples = _midi_region->position().distance ((note_start + session_source_start)).samples(); - - const double x0 = _editing_context.sample_to_pixel (note_start_samples); - double x1; - - const double y0 = 1 + floor(note_to_y(note->note())); - double y1; - - if (note->length() == Temporal::Beats()) { - - /* special case actual zero-length notes */ - - x1 = x0 + 1.; - - } else if (note->end_time() != std::numeric_limits::max()) { - - /* normal note */ - - const Temporal::Beats source_end ((_midi_region->start() + _midi_region->length()).beats()); - - if (!_extensible && note->end_time() > source_end) { - note_end = timepos_t (source_end); - } - - const samplepos_t note_end_samples = _midi_region->position().distance ((session_source_start + note_end)).samples(); - - x1 = std::max(1., _editing_context.sample_to_pixel (note_end_samples)); + double x0, x1, y0, y1; + if (_midi_region) { + region_update_sustained (ev, x0, x1, y0, y1); } else { - - /* nascent note currently being recorded, noteOff has not yet arrived */ - - x1 = std::max(1., _editing_context.duration_to_pixels (_midi_region->length())); + clip_capture_update_sustained (ev, x0, x1, y0, y1); } - y1 = y0 + std::max(1., floor(note_height()) - 1); - ev->set (ArdourCanvas::Rect (x0, y0, x1, y1)); ev->set_velocity (note->velocity()/127.0); @@ -1713,8 +1681,111 @@ MidiView::update_sustained (Note* ev) const uint32_t base_col = ev->base_color(); ev->set_fill_color (base_col); ev->set_outline_color (ev->calculate_outline(base_col, ev->selected())); + } +void +MidiView::clip_capture_update_sustained (Note *ev, double& x0, double& x1, double& y0, double& y1) +{ + std::shared_ptr note = ev->note(); + const timepos_t note_start (note->time()); + timepos_t note_end (note->end_time()); + + x0 = _editing_context.sample_to_pixel (note_start.samples()); + y0 = 1 + floor(note_to_y(note->note())); + + if (note->length() == Temporal::Beats()) { + + /* special case actual zero-length notes */ + + x1 = x0 + 1.; + + } else if (note->end_time() != std::numeric_limits::max()) { + + /* normal note */ + +#warning paul make this use the distance captured so far + const Temporal::Beats source_end (4,0); + + if (!_extensible && note->end_time() > source_end) { + note_end = timepos_t (source_end); + } + +#warning paul this needs to use the correct part of the tempo map, which will start at SlotArmInfo::start_samples + const samplepos_t note_end_samples = note_end.samples(); + + x1 = std::max(1., _editing_context.sample_to_pixel (note_end_samples)); + + } else { + + /* nascent note currently being recorded, noteOff has not yet arrived */ + +#warning paul make this use the distance captured so far + x1 = std::max(1., _editing_context.duration_to_pixels (timecnt_t (Temporal::Beats (1, 0)))); + } + + y1 = y0 + std::max(1., floor(note_height()) - 1); +} + +void +MidiView::region_update_sustained (Note *ev, double& x0, double& x1, double& y0, double& y1) +{ + const std::shared_ptr mr = midi_region(); + std::shared_ptr note = ev->note(); + const timepos_t note_start (note->time()); + timepos_t note_end (note->end_time()); + + /* The note is drawn as a child item of this region view, so its + * coordinate system is relative to the region view. This means that x0 + * and x1 are pixel offsets relative to beginning of the region (view) + */ + + /* compute absolute time where the start of the source is + */ + + const timepos_t session_source_start = _midi_region->source_position(); + + /* this computes the number of samples from the start of the region of the start of the + * note. We add the source start to get to the absolute time of the + * note, then subtract the start of the region + */ + + const samplepos_t note_start_samples = _midi_region->position().distance ((note_start + session_source_start)).samples(); + + x0 = _editing_context.sample_to_pixel (note_start_samples); + y0 = 1 + floor(note_to_y(note->note())); + + if (note->length() == Temporal::Beats()) { + + /* special case actual zero-length notes */ + + x1 = x0 + 1.; + + } else if (note->end_time() != std::numeric_limits::max()) { + + /* normal note */ + + const Temporal::Beats source_end ((_midi_region->start() + _midi_region->length()).beats()); + + if (!_extensible && note->end_time() > source_end) { + note_end = timepos_t (source_end); + } + + const samplepos_t note_end_samples = _midi_region->position().distance ((session_source_start + note_end)).samples(); + + x1 = std::max(1., _editing_context.sample_to_pixel (note_end_samples)); + + } else { + + /* nascent note currently being recorded, noteOff has not yet arrived */ + + x1 = std::max(1., _editing_context.duration_to_pixels (_midi_region->length())); + } + + y1 = y0 + std::max(1., floor(note_height()) - 1); +} + + void MidiView::update_hit (Hit* ev) { @@ -4220,6 +4291,8 @@ MidiView::set_step_edit_cursor_width (Temporal::Beats beats) void MidiView::clip_data_recorded () { + std::cerr << "cd recorded, mt " << _midi_track << std::endl; + if (!_midi_track) { return; } diff --git a/gtk2_ardour/midi_view.h b/gtk2_ardour/midi_view.h index 908d5c1934..f36b534d5f 100644 --- a/gtk2_ardour/midi_view.h +++ b/gtk2_ardour/midi_view.h @@ -643,6 +643,8 @@ class MidiView : public virtual sigc::trackable, public LineMerger void join_notes_on_channel (int channel); void add_split_notes (); + void region_update_sustained (Note *, double&, double&, double&, double&); + void clip_capture_update_sustained (Note *, double&, double&, double&, double&); }; diff --git a/gtk2_ardour/trigger_page.cc b/gtk2_ardour/trigger_page.cc index 167df2be2c..237349d8ee 100644 --- a/gtk2_ardour/trigger_page.cc +++ b/gtk2_ardour/trigger_page.cc @@ -387,17 +387,15 @@ TriggerPage::selection_changed () { Selection& selection (Editor::instance ().get_selection ()); + /* hide everything */ + _slot_prop_box.hide (); - _audio_trig_box.hide (); - _midi_trig_box.hide (); _midi_editor->viewport().hide (); _parameter_box.hide (); - std::cerr << "here, st = " << selection.triggers.size() << std::endl; - if (!selection.triggers.empty ()) { TriggerSelection ts = selection.triggers; TriggerEntry* entry = *ts.begin (); @@ -419,17 +417,22 @@ TriggerPage::selection_changed () _midi_editor->set_box (ref.box()); + std::shared_ptr mt = std::dynamic_pointer_cast (entry->strip().stripable()); + assert (mt); + _midi_editor->set_track (mt); + if (trigger->the_region()) { std::shared_ptr mr = std::dynamic_pointer_cast (trigger->the_region()); if (mr) { - std::shared_ptr mt = std::dynamic_pointer_cast (entry->strip().stripable()); - _midi_editor->set_region (mt, ref.slot(), mr); - _midi_editor->viewport().show (); + _midi_editor->set_region (mr); } } + + _midi_editor->viewport().show (); } + _parameter_box.show (); } }