From d460bb34755ea2343eef444c85cc572f8e176e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Nusser?= Date: Mon, 12 Oct 2015 18:04:52 +0200 Subject: [PATCH 1/6] Include "Transform..." into MIDI region menu. Everything has already been done except the including. --- gtk2_ardour/ardour.menus.in | 2 ++ gtk2_ardour/editor_selection.cc | 1 + 2 files changed, 3 insertions(+) diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index f997347a7b..03192470bc 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -313,6 +313,7 @@ + @@ -649,6 +650,7 @@ + diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 85ec795e40..3a6277ecec 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -1241,6 +1241,7 @@ Editor::sensitize_the_right_region_actions () _region_actions->get_action("quantize-region")->set_sensitive (false); _region_actions->get_action("legatize-region")->set_sensitive (false); _region_actions->get_action("remove-overlap")->set_sensitive (false); + _region_actions->get_action("transform-region")->set_sensitive (false); _region_actions->get_action("fork-region")->set_sensitive (false); _region_actions->get_action("insert-patch-change-context")->set_sensitive (false); _region_actions->get_action("insert-patch-change")->set_sensitive (false); From bc83699e44ddaff9318dad95038def3ed20f42f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Nusser?= Date: Thu, 15 Oct 2015 15:24:46 +0200 Subject: [PATCH 2/6] Fix tiny memory leak. --- gtk2_ardour/editor_ops.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 5796b95868..bfd7b14492 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -5341,14 +5341,14 @@ Editor::transform_regions (const RegionSelection& rs) return; } - TransformDialog* td = new TransformDialog(); + TransformDialog td; - td->present(); - const int r = td->run(); - td->hide(); + td.present(); + const int r = td.run(); + td.hide(); if (r == Gtk::RESPONSE_OK) { - Transform transform(td->get()); + Transform transform(td.get()); apply_midi_note_edit_op(transform, rs); } } From 66f18914b21837b0d4087d1d5dfff3d654cc3ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Nusser?= Date: Thu, 15 Oct 2015 15:36:17 +0200 Subject: [PATCH 3/6] Split transpose in MidiModel into two functions. --- libs/ardour/ardour/midi_model.h | 1 + libs/ardour/midi_model.cc | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index b2e018ca3b..80ae71f206 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -287,6 +287,7 @@ public: boost::shared_ptr control_factory(const Evoral::Parameter& id); void insert_silence_at_start (TimeType); + void transpose (NoteDiffCommand *, const NotePtr, int); void transpose (TimeType, TimeType, int); std::set& active_notes() { return _active_notes; } diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index fd08428a68..5997c5b548 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -1983,6 +1983,20 @@ MidiModel::insert_silence_at_start (TimeType t) } } +void +MidiModel::transpose (NoteDiffCommand* c, const NotePtr note_ptr, int semitones) +{ + int new_note = note_ptr->note() + semitones; + + if (new_note < 0) { + new_note = 0; + } else if (new_note > 127) { + new_note = 127; + } + + c->change (note_ptr, NoteDiffCommand::NoteNumber, (uint8_t) new_note); +} + /** Transpose notes in a time range by a given number of semitones. Notes * will be clamped at 0 and 127 if the transposition would make them exceed * that range. @@ -2007,16 +2021,7 @@ MidiModel::transpose (TimeType from, TimeType to, int semitones) } else if ((*i)->time() >= from) { - int new_note = (*i)->note() + semitones; - - if (new_note < 0) { - new_note = 0; - } else if (new_note > 127) { - new_note = 127; - } - - c->change (*i, NoteDiffCommand::NoteNumber, (uint8_t) new_note); - + transpose (c, *i, semitones); } } From bd02a7f817e0be2c4b8f8ec9c86c21ebb2417da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Nusser?= Date: Thu, 15 Oct 2015 15:41:11 +0200 Subject: [PATCH 4/6] Add Transpose class that can be used by apply_midi_note_edit_op. --- libs/ardour/ardour/transpose.h | 48 +++++++++++++++++++++++++++++++++ libs/ardour/transpose.cc | 49 ++++++++++++++++++++++++++++++++++ libs/ardour/wscript | 1 + 3 files changed, 98 insertions(+) create mode 100644 libs/ardour/ardour/transpose.h create mode 100644 libs/ardour/transpose.cc diff --git a/libs/ardour/ardour/transpose.h b/libs/ardour/ardour/transpose.h new file mode 100644 index 0000000000..17f83283f9 --- /dev/null +++ b/libs/ardour/ardour/transpose.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2015 Paul Davis + Author: André Nusser + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_transpose_h__ +#define __ardour_transpose_h__ + +#include "ardour/libardour_visibility.h" +#include "ardour/midi_model.h" +#include "ardour/midi_operator.h" + +namespace ARDOUR { + +class LIBARDOUR_API Transpose : public MidiOperator { +public: + typedef Evoral::Sequence::NotePtr NotePtr; + typedef Evoral::Sequence::Notes Notes; + + Transpose (int semitones); + + Command* operator() (boost::shared_ptr model, + Evoral::Beats position, + std::vector& seqs); + + std::string name () const { return std::string ("transpose"); } + +private: + int _semitones; +}; + +} /* namespace */ + +#endif /* __ardour_transpose_h__ */ diff --git a/libs/ardour/transpose.cc b/libs/ardour/transpose.cc new file mode 100644 index 0000000000..ca0b7abf4e --- /dev/null +++ b/libs/ardour/transpose.cc @@ -0,0 +1,49 @@ +/* + Copyright (C) 2015 Paul Davis + Author: André Nusser + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "ardour/transpose.h" + +namespace ARDOUR { + +Transpose::Transpose(int semitones) + : _semitones(semitones) +{} + +Command* +Transpose::operator()(boost::shared_ptr model, + Evoral::Beats position, + std::vector& seqs) +{ + typedef MidiModel::NoteDiffCommand Command; + + Command* cmd = new Command(model, name()); + + for (std::vector::iterator s = seqs.begin(); s != seqs.end(); ++s) { + for (Notes::const_iterator i = (*s).begin(); i != (*s).end(); ++i) { + + const NotePtr note = *i; + + model->transpose (cmd, *i, _semitones); + } + } + + return cmd; +} + +} // namespace ARDOUR diff --git a/libs/ardour/wscript b/libs/ardour/wscript index af5b266987..dccdd30345 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -216,6 +216,7 @@ libardour_sources = [ 'track.cc', 'transient_detector.cc', 'transform.cc', + 'transpose.cc', 'unknown_processor.cc', 'user_bundle.cc', 'utils.cc', From e807fe2b289be7736cd33df6fdc4b50ef4a4c099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Nusser?= Date: Thu, 15 Oct 2015 15:44:09 +0200 Subject: [PATCH 5/6] Introduce "Transpose..." also in the context menu of selected notes. --- gtk2_ardour/editor.cc | 2 ++ gtk2_ardour/editor.h | 4 ++-- gtk2_ardour/editor_ops.cc | 49 ++++++++++++++++++++------------------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 9ed69351d5..538203644f 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -5959,6 +5959,8 @@ Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event) sigc::mem_fun(mrv, &MidiRegionView::delete_selection))); items.push_back(MenuElem(_("Edit..."), sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv))); + items.push_back(MenuElem(_("Transpose..."), + sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs))); items.push_back(MenuElem(_("Legatize"), sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false))); items.push_back(MenuElem(_("Quantize..."), diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index f558355bb0..be018d6b9b 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1258,6 +1258,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void legatize_regions (const RegionSelection& rs, bool shrink_only); void transform_region (); void transform_regions (const RegionSelection& rs); + void transpose_region (); + void transpose_regions (const RegionSelection& rs); void insert_patch_change (bool from_context); void fork_region (); @@ -2029,8 +2031,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD int pitch_shift (RegionSelection&, float cents); void pitch_shift_region (); - void transpose_region (); - /* editor-mixer strip */ MixerStrip *current_mixer_strip; diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index bfd7b14492..2d718284d2 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -57,6 +57,7 @@ #include "ardour/session_playlists.h" #include "ardour/strip_silence.h" #include "ardour/transient_detector.h" +#include "ardour/transpose.h" #include "canvas/canvas.h" @@ -5353,6 +5354,30 @@ Editor::transform_regions (const RegionSelection& rs) } } +void +Editor::transpose_region () +{ + if (_session) { + transpose_regions(get_regions_from_selection_and_entered ()); + } +} + +void +Editor::transpose_regions (const RegionSelection& rs) +{ + if (rs.n_midi_regions() == 0) { + return; + } + + TransposeDialog d; + int const r = d.run (); + + if (r == RESPONSE_ACCEPT) { + Transpose transpose(d.semitones ()); + apply_midi_note_edit_op (transpose, rs); + } +} + void Editor::insert_patch_change (bool from_context) { @@ -6425,30 +6450,6 @@ Editor::pitch_shift_region () pitch_shift (audio_rs, 1.2); } -void -Editor::transpose_region () -{ - RegionSelection rs = get_regions_from_selection_and_entered (); - - list midi_region_views; - for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { - MidiRegionView* mrv = dynamic_cast (*i); - if (mrv) { - midi_region_views.push_back (mrv); - } - } - - TransposeDialog d; - int const r = d.run (); - if (r != RESPONSE_ACCEPT) { - return; - } - - for (list::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) { - (*i)->midi_region()->transpose (d.semitones ()); - } -} - void Editor::set_tempo_from_region () { From a958770abd3e73d3465f914e06b45a1dca80d778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Nusser?= Date: Thu, 15 Oct 2015 15:49:41 +0200 Subject: [PATCH 6/6] Remove all the now unused functions in the MidiModel class. --- libs/ardour/ardour/midi_model.h | 1 - libs/ardour/ardour/midi_region.h | 1 - libs/ardour/midi_model.cc | 31 ------------------------------- libs/ardour/midi_region.cc | 8 -------- 4 files changed, 41 deletions(-) diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index 80ae71f206..21c67c2b32 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -288,7 +288,6 @@ public: void insert_silence_at_start (TimeType); void transpose (NoteDiffCommand *, const NotePtr, int); - void transpose (TimeType, TimeType, int); std::set& active_notes() { return _active_notes; } diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index 87e89c695b..250a58aa70 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -101,7 +101,6 @@ class LIBARDOUR_API MidiRegion : public Region boost::shared_ptr model() const; void fix_negative_start (); - void transpose (int); protected: diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 5997c5b548..d9f6e802cf 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -1997,37 +1997,6 @@ MidiModel::transpose (NoteDiffCommand* c, const NotePtr note_ptr, int semitones) c->change (note_ptr, NoteDiffCommand::NoteNumber, (uint8_t) new_note); } -/** Transpose notes in a time range by a given number of semitones. Notes - * will be clamped at 0 and 127 if the transposition would make them exceed - * that range. - * - * @param from Start time. - * @param end End time. - * @param semitones Number of semitones to transpose by (+ve is higher, -ve is lower). - */ -void -MidiModel::transpose (TimeType from, TimeType to, int semitones) -{ - boost::shared_ptr s = midi_source (); - - NoteDiffCommand* c = new_note_diff_command (_("transpose")); - - for (Notes::iterator i = notes().begin(); i != notes().end(); ++i) { - - if ((*i)->time() >= to) { - - /* finished */ - break; - - } else if ((*i)->time() >= from) { - - transpose (c, *i, semitones); - } - } - - apply_command (s->session (), c); -} - void MidiModel::control_list_marked_dirty () { diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 3e4a656ebe..56472e4ba8 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -458,14 +458,6 @@ MidiRegion::fix_negative_start () _start_beats = Evoral::Beats(); } -/** Transpose the notes in this region by a given number of semitones */ -void -MidiRegion::transpose (int semitones) -{ - BeatsFramesConverter c (_session.tempo_map(), _start); - model()->transpose (c.from (_start), c.from (_start + _length), semitones); -} - void MidiRegion::set_start_internal (framecnt_t s) {