diff options
author | Tim Mayberry <mojofunk@gmail.com> | 2015-10-28 12:58:55 +1000 |
---|---|---|
committer | Tim Mayberry <mojofunk@gmail.com> | 2016-01-14 20:41:44 +1000 |
commit | 084af96bf441c065841af6a399d4c0d3c99962d4 (patch) | |
tree | 9fbb60b5c005b730c88b2e0d468713d173f70af4 | |
parent | b93a9e26013e8143ff63fcfde1f7c714fff55be3 (diff) |
Change handling of Midi note selection to eliminate signal emission/delays.
Each MidiRegionView(MRV) is connected to the Selection::ClearMidiNoteSelection
signal that is used to notify the all MRV instances to clear their note
selection.
The MRV class also has a private static SelectionCleared signal that is used to
signal other MRV instances when their selection has been cleared. When the
Selection::ClearMidiNoteSelection signal is emitted it causes each MRV to also
emit the SelectionCleared signal. So the emission takes quadratic time.
With 1500 MRV instances emission takes about 2.2 seconds on my machine, and
some operations like track selection cause it to be emitted 3 times(another
issue).
The Selection class in the Editor knows which MRV instances have note
selections, as it is notified by MidiRegionView whenever the selection count
becomes zero or becomes non-zero. Clearing the Note selection should then just
be O(N) and direct calls can be used rather than signals.
This change removes both the signals and uses the existing references between
Selection and MRV class to control note selection. There should be no
behavioural changes in Midi note selection with this change.
-rw-r--r-- | gtk2_ardour/editor_mouse.cc | 4 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 134 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.h | 29 | ||||
-rw-r--r-- | gtk2_ardour/selection.cc | 21 | ||||
-rw-r--r-- | gtk2_ardour/selection.h | 2 |
5 files changed, 73 insertions, 117 deletions
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 7740cb9b17..a7b7059a12 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -333,12 +333,12 @@ Editor::update_time_selection_display () switch (mouse_mode) { case MouseRange: selection->clear_objects (); - selection->ClearMidiNoteSelection (); /* EMIT SIGNAL */ + selection->clear_midi_notes (); break; case MouseObject: selection->clear_time (); selection->clear_tracks (); - selection->ClearMidiNoteSelection (); /* EMIT SIGNAL */ + selection->clear_midi_notes (); break; case MouseDraw: /* Clear regions, but not time or tracks, since that diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index e9e4258b81..c62686170a 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -90,8 +90,6 @@ using namespace Editing; using namespace std; using Gtkmm2ext::Keyboard; -PBD::Signal1<void, MidiRegionView *> MidiRegionView::SelectionCleared; - #define MIDI_BP_ZERO ((Config->get_first_midi_bank_is_zero())?0:1) MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent, @@ -134,11 +132,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent, Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context()); connect_to_diskstream (); - - SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ()); - - PublicEditor& editor (trackview.editor()); - editor.get_selection().ClearMidiNoteSelection.connect (_clear_midi_selection_connection, invalidator (*this), boost::bind (&MidiRegionView::clear_midi_selection, this), gui_context ()); } MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent, @@ -183,11 +176,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent, PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys)); connect_to_diskstream (); - - SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ()); - - PublicEditor& editor (trackview.editor()); - editor.get_selection().ClearMidiNoteSelection.connect (_clear_midi_selection_connection, invalidator (*this), boost::bind (&MidiRegionView::clear_midi_selection, this), gui_context ()); } void @@ -320,11 +308,6 @@ MidiRegionView::init (bool wfd) Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context()); connect_to_diskstream (); - - SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ()); - - PublicEditor& editor (trackview.editor()); - editor.get_selection().ClearMidiNoteSelection.connect (_clear_midi_selection_connection, invalidator (*this), boost::bind (&MidiRegionView::clear_midi_selection, this), gui_context ()); } InstrumentInfo& @@ -554,7 +537,7 @@ MidiRegionView::button_release (GdkEventButton* ev) switch (editor.current_mouse_mode()) { case MouseRange: /* no motion occured - simple click */ - clear_selection (); + clear_editor_note_selection (); _mouse_changed_selection = true; break; @@ -574,7 +557,7 @@ MidiRegionView::button_release (GdkEventButton* ev) Evoral::Beats beats = get_grid_beats(editor.pixel_to_sample(event_x)); create_note_at (editor.pixel_to_sample (event_x), event_y, beats, true); } else { - clear_selection (); + clear_editor_note_selection (); } break; @@ -669,7 +652,7 @@ MidiRegionView::motion (GdkEventMotion* ev) } else if (m == MouseContent) { editor.drags()->set (new MidiRubberbandSelectDrag (dynamic_cast<Editor *> (&editor), this), (GdkEvent *) ev); if (!Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) { - clear_selection (); + clear_editor_note_selection (); _mouse_changed_selection = true; } _mouse_state = SelectRectDragging; @@ -752,7 +735,7 @@ MidiRegionView::key_press (GdkEventKey* ev) return true; } else if (ev->keyval == GDK_Escape && unmodified) { - clear_selection(); + clear_editor_note_selection (); _mouse_state = None; } else if (ev->keyval == GDK_comma || ev->keyval == GDK_period) { @@ -970,7 +953,7 @@ MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, bo start_note_diff_command(_("add note")); - clear_selection (); + clear_editor_note_selection (); note_diff_add_note (new_note, true, false); apply_diff(); @@ -979,9 +962,10 @@ MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, bo } void -MidiRegionView::clear_events (bool with_selection_signal) +MidiRegionView::clear_events () { - clear_selection (with_selection_signal); + // clear selection without signaling + clear_selection_internal (); MidiGhostRegion* gr; for (std::vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) { @@ -1008,7 +992,7 @@ MidiRegionView::display_model(boost::shared_ptr<MidiModel> model) content_connection.disconnect (); _model->ContentsChanged.connect (content_connection, invalidator (*this), boost::bind (&MidiRegionView::redisplay_model, this), gui_context()); /* Don't signal as nobody else needs to know until selection has been altered. */ - clear_events (false); + clear_events (); if (_enable_display) { redisplay_model(); @@ -1110,7 +1094,7 @@ MidiRegionView::abort_command() { delete _note_diff_command; _note_diff_command = 0; - clear_selection(); + clear_editor_note_selection(); } NoteBase* @@ -1405,10 +1389,8 @@ MidiRegionView::~MidiRegionView () end_write(); } - _selection_cleared_connection.disconnect (); - _selection.clear(); - clear_events (false); + clear_events (); delete _note_group; delete _note_diff_command; @@ -1898,7 +1880,7 @@ MidiRegionView::step_add_note (uint8_t channel, uint8_t number, uint8_t velocity start_note_diff_command (_("step add")); - clear_selection (); + clear_editor_note_selection (); note_diff_add_note (new_note, true, false); apply_diff(); @@ -2148,65 +2130,50 @@ MidiRegionView::delete_note (boost::shared_ptr<NoteType> n) } void -MidiRegionView::clear_selection_except (NoteBase* ev, bool signal) +MidiRegionView::clear_editor_note_selection () { - for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) { - if ((*i) != ev) { - Selection::iterator tmp = i; - ++tmp; + DEBUG_TRACE(DEBUG::Selection, "MRV::clear_editor_note_selection\n"); + PublicEditor& editor(trackview.editor()); + editor.get_selection().clear_midi_notes(); +} - (*i)->set_selected (false); - (*i)->hide_velocity (); - _selection.erase (i); +void +MidiRegionView::clear_selection () +{ + clear_selection_internal(); + PublicEditor& editor(trackview.editor()); + editor.get_selection().remove(this); +} - i = tmp; - } else { - ++i; - } +void +MidiRegionView::clear_selection_internal () +{ + DEBUG_TRACE(DEBUG::Selection, "MRV::clear_selection_internal\n"); + + for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { + (*i)->set_selected(false); + (*i)->hide_velocity(); } + _selection.clear(); - if (!ev && _entered) { + if (_entered) { // Clearing selection entirely, ungrab keyboard Keyboard::magic_widget_drop_focus(); _grabbed_keyboard = false; } - - /* this does not change the status of this regionview w.r.t the editor - selection. - */ - - if (signal) { - SelectionCleared (this); /* EMIT SIGNAL */ - } } void MidiRegionView::unique_select(NoteBase* ev) { - const bool selection_was_empty = _selection.empty(); - - clear_selection_except (ev); - - /* don't bother with checking to see if we should remove this - regionview from the editor selection, since we're about to add - another note, and thus put/keep this regionview in the editor - selection anyway. - */ - - if (!ev->selected()) { - add_to_selection (ev); - if (selection_was_empty && _entered) { - // Grab keyboard for moving notes with arrow keys - Keyboard::magic_widget_grab_focus(); - _grabbed_keyboard = true; - } - } + clear_editor_note_selection(); + add_to_selection(ev); } void MidiRegionView::select_all_notes () { - clear_selection (); + clear_editor_note_selection (); for (Events::iterator i = _events.begin(); i != _events.end(); ++i) { add_to_selection (*i); @@ -2216,7 +2183,7 @@ MidiRegionView::select_all_notes () void MidiRegionView::select_range (framepos_t start, framepos_t end) { - clear_selection (); + clear_editor_note_selection (); for (Events::iterator i = _events.begin(); i != _events.end(); ++i) { framepos_t t = source_beats_to_absolute_frames((*i)->note()->time()); @@ -2281,7 +2248,7 @@ MidiRegionView::select_matching_notes (uint8_t notenum, uint16_t channel_mask, b } if (!add) { - clear_selection (); + clear_editor_note_selection (); if (!extend && (low_note == high_note) && (high_note == notenum)) { /* only note previously selected is the one we are @@ -2356,11 +2323,8 @@ void MidiRegionView::note_selected (NoteBase* ev, bool add, bool extend) { if (!add) { - clear_selection_except (ev); - if (!_selection.empty()) { - PublicEditor& editor (trackview.editor()); - editor.get_selection().add (this); - } + clear_editor_note_selection(); + add_to_selection (ev); } if (!extend) { @@ -3574,7 +3538,7 @@ MidiRegionView::paste_internal (framepos_t pos, unsigned paste_count, float time duration, pos, _region->position(), pos_beats)); - clear_selection (); + clear_editor_note_selection (); for (int n = 0; n < (int) times; ++n) { @@ -4123,20 +4087,6 @@ MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, framecnt_t& grid_fr return snap_frame_to_frame (p); } -/** Called when the selection has been cleared in any MidiRegionView. - * @param rv MidiRegionView that the selection was cleared in. - */ -void -MidiRegionView::selection_cleared (MidiRegionView* rv) -{ - if (rv == this) { - return; - } - - /* Clear our selection in sympathy; but don't signal the fact */ - clear_selection (false); -} - ChannelMode MidiRegionView::get_channel_mode () const { diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index eb23a8873b..5733861d87 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -328,9 +328,12 @@ public: */ void create_note_at (framepos_t t, double y, Evoral::Beats length, bool snap_t); - void clear_selection (bool signal = true) { clear_selection_except (0, signal); } + /** An external request to clear the note selection, remove MRV from editor + * selection. + */ + void clear_selection (); - ARDOUR::InstrumentInfo& instrument_info() const; + ARDOUR::InstrumentInfo& instrument_info() const; void note_deleted (NoteBase*); @@ -349,19 +352,6 @@ private: friend class MidiRubberbandSelectDrag; friend class MidiVerticalSelectDrag; - /** Emitted when the selection has been cleared in one MidiRegionView, - * with the expectation that others will clear their selections in - * sympathy. - */ - static PBD::Signal1<void, MidiRegionView*> SelectionCleared; - PBD::ScopedConnection _selection_cleared_connection; - void selection_cleared (MidiRegionView *); - - /** this handles the case when the "external" world wants us to clear our internal selections - */ - PBD::ScopedConnection _clear_midi_selection_connection; - void clear_midi_selection () { clear_selection(); } - friend class EditNoteDialog; /** Play the NoteOn event of the given note immediately @@ -371,7 +361,13 @@ private: void start_playing_midi_note (boost::shared_ptr<NoteType> note); void start_playing_midi_chord (std::vector<boost::shared_ptr<NoteType> > notes); - void clear_events (bool with_selection_signal = true); + /** Clear the note selection of just this midi region + */ + void clear_selection_internal (); + + void clear_editor_note_selection (); + + void clear_events (); bool canvas_group_event(GdkEvent* ev); bool note_canvas_event(GdkEvent* ev); @@ -389,7 +385,6 @@ private: void trim_note(NoteBase* ev, ARDOUR::MidiModel::TimeType start_delta, ARDOUR::MidiModel::TimeType end_delta); - void clear_selection_except (NoteBase* ev, bool signal = true); void update_drag_selection (framepos_t start, framepos_t end, double y0, double y1, bool extend); void update_vertical_drag_selection (double last_y, double y, bool extend); diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index baf424669f..c1a53bd00d 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -27,6 +27,7 @@ #include "ardour/rc_configuration.h" #include "audio_region_view.h" +#include "debug.h" #include "gui_thread.h" #include "midi_cut_buffer.h" #include "region_gain_line.h" @@ -177,9 +178,18 @@ Selection::clear_midi_notes () MidiNotesChanged (); } - /* The note selection is actually stored in MidiRegionView, emit signal to - tell them to clear their selection. */ - ClearMidiNoteSelection(); /* EMIT SIGNAL */ + // clear note selections for MRV's that have note selections + // this will cause the MRV to be removed from the list + for (MidiRegionSelection::iterator i = midi_regions.begin(); + i != midi_regions.end();) { + MidiRegionSelection::iterator tmp = i; + ++tmp; + MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i); + if (mrv) { + mrv->clear_selection(); + } + i = tmp; + } } void @@ -518,6 +528,8 @@ Selection::add (RegionView* r) void Selection::add (MidiRegionView* mrv) { + DEBUG_TRACE(DEBUG::Selection, string_compose("Selection::add MRV %1\n", mrv)); + clear_time(); //enforce object/range exclusivity clear_tracks(); //enforce object/track exclusivity @@ -719,6 +731,8 @@ Selection::remove (RegionView* r) void Selection::remove (MidiRegionView* mrv) { + DEBUG_TRACE(DEBUG::Selection, string_compose("Selection::remove MRV %1\n", mrv)); + MidiRegionSelection::iterator x; if ((x = find (midi_regions.begin(), midi_regions.end(), mrv)) != midi_regions.end()) { @@ -727,7 +741,6 @@ Selection::remove (MidiRegionView* mrv) } } - void Selection::remove (uint32_t selection_id) { diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h index c28b42a443..586c2e8997 100644 --- a/gtk2_ardour/selection.h +++ b/gtk2_ardour/selection.h @@ -221,8 +221,6 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList XMLNode& get_state () const; int set_state (XMLNode const &, int); - PBD::Signal0<void> ClearMidiNoteSelection; - std::list<std::pair<PBD::ID const, std::list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > pending_midi_note_selection; private: |