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.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 5796b95868..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"
@@ -5341,18 +5342,42 @@ 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);
}
}
+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 ()
{
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);
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
index b2e018ca3b..21c67c2b32 100644
--- a/libs/ardour/ardour/midi_model.h
+++ b/libs/ardour/ardour/midi_model.h
@@ -287,7 +287,7 @@ public:
boost::shared_ptr control_factory(const Evoral::Parameter& id);
void insert_silence_at_start (TimeType);
- void transpose (TimeType, TimeType, int);
+ void transpose (NoteDiffCommand *, const NotePtr, 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/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/midi_model.cc b/libs/ardour/midi_model.cc
index fd08428a68..d9f6e802cf 100644
--- a/libs/ardour/midi_model.cc
+++ b/libs/ardour/midi_model.cc
@@ -1983,44 +1983,18 @@ MidiModel::insert_silence_at_start (TimeType t)
}
}
-/** 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)
+MidiModel::transpose (NoteDiffCommand* c, const NotePtr note_ptr, int semitones)
{
- boost::shared_ptr s = midi_source ();
+ int new_note = note_ptr->note() + semitones;
- 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) {
-
- 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);
-
- }
+ if (new_note < 0) {
+ new_note = 0;
+ } else if (new_note > 127) {
+ new_note = 127;
}
- apply_command (s->session (), c);
+ c->change (note_ptr, NoteDiffCommand::NoteNumber, (uint8_t) new_note);
}
void
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)
{
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',