diff --git a/gtk2_ardour/ardour.keys.in b/gtk2_ardour/ardour.keys.in index f53032e785..ba208d9a73 100644 --- a/gtk2_ardour/ardour.keys.in +++ b/gtk2_ardour/ardour.keys.in @@ -482,6 +482,8 @@ This mode provides many different operations on both regions and control points, @notes|Notes/increase-velocity-fine-smush| <@PRIMARY@><@SECONDARY@><@TERTIARY@>Up|Increase Note Velocity (+1) allow mushing @notes|Notes/decrease-velocity-fine-smush| <@PRIMARY@><@SECONDARY@><@TERTIARY@>Down|Increase Note Velocity (+1) allow mushing +@notes|Notes/quantize-selected-notes|q|Quantize Selected Notes + @notes|Notes/delete| Backspace|Delete Note Selection @notes|Notes/alt-delete| Delete|Delete Note Selection @notes|Main/Escape|Clear selection diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index cf37bf50a7..e0f6d22caf 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1357,6 +1357,8 @@ private: void normalize_region (); void adjust_region_gain (bool up); void reset_region_gain (); + ARDOUR::Quantize get_quantize_op (bool force_dialog, bool& did_show_dialog); + void apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs); void quantize_region (); void quantize_regions (const RegionSelection& rs); void legatize_region (bool shrink_only); @@ -2266,7 +2268,6 @@ private: void apply_filter (ARDOUR::Filter&, std::string cmd, ProgressReporter* progress = 0); Command* apply_midi_note_edit_op_to_region (ARDOUR::MidiOperator& op, MidiRegionView& mrv); - void apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs); /* plugin setup */ int plugin_setup (boost::shared_ptr, boost::shared_ptr, ARDOUR::Route::PluginSetupOptions); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index c9f1377ac3..63e48e17e7 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -876,6 +876,8 @@ Editor::register_midi_actions (Bindings* midi_bindings) ActionManager::register_action (_midi_actions, X_("edit-channels"), _("Edit Note Channels"), sigc::bind (sigc::mem_fun (*this, &Editor::midi_action), &MidiRegionView::channel_edit)); ActionManager::register_action (_midi_actions, X_("edit-velocities"), _("Edit Note Velocities"), sigc::bind (sigc::mem_fun (*this, &Editor::midi_action), &MidiRegionView::velocity_edit)); + ActionManager::register_action (_midi_actions, X_("quantize-selected-notes"), _("Quantize Selected Notes"), sigc::bind (sigc::mem_fun (*this, &Editor::midi_action), &MidiRegionView::quantize_selected_notes)); + ActionManager::set_sensitive (_midi_actions, false); } diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 4ecf926eb3..1ae35f3392 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -5827,6 +5827,10 @@ Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv Evoral::Sequence::Notes selected; mrv.selection_as_notelist (selected, true); + if (selected.empty()) { + return 0; + } + vector::Notes> v; v.push_back (selected); @@ -6009,32 +6013,52 @@ Editor::quantize_regions (const RegionSelection& rs) return; } + bool ignored; + Quantize quant = get_quantize_op (true, ignored); + + if (!quant.empty()) { + apply_midi_note_edit_op (quant, rs); + } +} + +Quantize +Editor::get_quantize_op (bool force_dialog, bool& did_show_dialog) +{ + did_show_dialog = false; + if (!quantize_dialog) { quantize_dialog = new QuantizeDialog (*this); + force_dialog = true; } if (quantize_dialog->get_mapped()) { /* in progress already */ - return; + return Quantize (false, false, Temporal::Beats(), Temporal::Beats(), 0., 0., Temporal::Beats()); } - quantize_dialog->present (); - const int r = quantize_dialog->run (); - quantize_dialog->hide (); + int r = Gtk::RESPONSE_OK; + + if (force_dialog) { + quantize_dialog->present (); + r = quantize_dialog->run (); + quantize_dialog->hide (); + did_show_dialog = true; + } if (r == Gtk::RESPONSE_OK) { - Quantize quant (quantize_dialog->snap_start(), - quantize_dialog->snap_end(), - quantize_dialog->start_grid_size(), - quantize_dialog->end_grid_size(), - quantize_dialog->strength(), - quantize_dialog->swing(), - quantize_dialog->threshold()); - - apply_midi_note_edit_op (quant, rs); + return Quantize (quantize_dialog->snap_start(), + quantize_dialog->snap_end(), + quantize_dialog->start_grid_size(), + quantize_dialog->end_grid_size(), + quantize_dialog->strength(), + quantize_dialog->swing(), + quantize_dialog->threshold()); } + + return Quantize (false, false, Temporal::Beats(), Temporal::Beats(), 0., 0., Temporal::Beats()); } + void Editor::legatize_region (bool shrink_only) { diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 618a0f0faa..f9291b89c1 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -47,6 +47,7 @@ #include "ardour/midi_source.h" #include "ardour/midi_track.h" #include "ardour/operations.h" +#include "ardour/quantize.h" #include "ardour/session.h" #include "evoral/Parameter.h" @@ -4578,3 +4579,25 @@ MidiRegionView::note_to_y(uint8_t note) const { return contents_height() - (note + 1 - _current_range_min) * note_height() + 1; } + +void +MidiRegionView::quantize_selected_notes () +{ + RegionSelection rs; + rs.push_back (this); + + bool did_show_dialog; + Quantize quant = trackview.editor().get_quantize_op (false, did_show_dialog); + bool success; + + if (!did_show_dialog) { + /* use global grid */ + quant.set_start_grid (trackview.editor().get_grid_type_as_beats (success, midi_region()->source_position())); + if (!success) { + return; + } + quant.set_end_grid (quant.start_grid()); + } + + trackview.editor().apply_midi_note_edit_op (quant, rs); +} diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index b309c82754..323dab196e 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -392,6 +392,8 @@ public: void nudge_notes_earlier () { nudge_notes (false, false); } void nudge_notes_earlier_fine () { nudge_notes (false, true); } + void quantize_selected_notes (); + private: friend class MidiRubberbandSelectDrag; diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 6c876abb20..32754c195f 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -72,6 +72,7 @@ namespace ARDOUR { class Trimmable; class Movable; class Stripable; + class MidiOperator; } namespace Gtk { @@ -554,6 +555,9 @@ public: virtual void queue_redisplay_track_views () = 0; + virtual ARDOUR::Quantize get_quantize_op (bool force_dialog, bool& did_show_dialog) = 0; + virtual void apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs) = 0; + /// Singleton instance, set up by Editor::Editor() static PublicEditor* _instance; diff --git a/libs/ardour/ardour/quantize.h b/libs/ardour/ardour/quantize.h index 24417b356d..272ed51807 100644 --- a/libs/ardour/ardour/quantize.h +++ b/libs/ardour/ardour/quantize.h @@ -37,6 +37,12 @@ public: Temporal::Beats position, std::vector::Notes>&); std::string name() const { return std::string ("quantize"); } + bool empty() const { return !_snap_start && !_snap_end; } + + Temporal::Beats start_grid() const { return _start_grid; } + Temporal::Beats end_grid() const { return _end_grid; } + void set_start_grid (Temporal::Beats const &); + void set_end_grid (Temporal::Beats const &); private: bool _snap_start; diff --git a/libs/ardour/quantize.cc b/libs/ardour/quantize.cc index 1058c55acc..6c64070754 100644 --- a/libs/ardour/quantize.cc +++ b/libs/ardour/quantize.cc @@ -162,6 +162,7 @@ Quantize::operator () (boost::shared_ptr model, if (_snap_start) { /* this is here because Beats intentionally does not have operator* (double) */ delta = Temporal::Beats::ticks (llrintf (delta.to_ticks()) * _strength); + std::cerr << "new start " << (*i)->time() + delta << " shift was " << delta << std::endl; cmd->change ((*i), MidiModel::NoteDiffCommand::StartTime, (*i)->time() + delta); } } @@ -185,3 +186,15 @@ Quantize::operator () (boost::shared_ptr model, return cmd; } + +void +Quantize::set_start_grid (Temporal::Beats const & sg) +{ + _start_grid = sg; +} + +void +Quantize::set_end_grid (Temporal::Beats const & eg) +{ + _end_grid = eg; +}