From 4a016f366a2d39f6d901c8105b9dbba258d2475f Mon Sep 17 00:00:00 2001 From: carlh Date: Wed, 6 Apr 2011 02:04:37 +0000 Subject: [PATCH] Differentiate between pitch-shift (for audio) and transpose (for MIDI). Fixes #3940. git-svn-id: http://subversion.ardour.org/svn/ardour2/ardour2/branches/3.0@9299 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardour.menus.in | 2 ++ gtk2_ardour/editor.h | 2 ++ gtk2_ardour/editor_actions.cc | 7 +++-- gtk2_ardour/editor_ops.cc | 36 +++++++++++++++++++++-- gtk2_ardour/editor_selection.cc | 2 ++ gtk2_ardour/time_fx_dialog.cc | 4 +-- gtk2_ardour/transpose_dialog.cc | 63 ++++++++++++++++++++++++++++++++++++++++ gtk2_ardour/transpose_dialog.h | 41 ++++++++++++++++++++++++++ gtk2_ardour/wscript | 1 + libs/ardour/ardour/midi_model.h | 1 + libs/ardour/ardour/midi_region.h | 1 + libs/ardour/midi_model.cc | 40 +++++++++++++++++++++++++ libs/ardour/midi_region.cc | 8 +++++ 13 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 gtk2_ardour/transpose_dialog.cc create mode 100644 gtk2_ardour/transpose_dialog.h diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index db5a78eab..7e6c16a50 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -234,6 +234,7 @@ + @@ -584,6 +585,7 @@ + diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index aefe9ac64..6ac031945 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1816,6 +1816,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void pitch_shift_region (); int time_fx (RegionSelection&, float val, bool pitching); + void transpose_region (); + /* editor-mixer strip */ MixerStrip *current_mixer_strip; diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 0c10267b7..7f3d6db14 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -1250,8 +1250,11 @@ Editor::register_region_actions () /* Cut selected region gain */ reg_sens (_region_actions, "cut-region-gain", _("Cut Gain"), sigc::bind (sigc::mem_fun(*this, &Editor::adjust_region_gain), false)); - /* Open the pitch shift dialogue for the selected regions */ - reg_sens (_region_actions, "pitch-shift-region", _("Pitch Shift"), sigc::mem_fun (*this, &Editor::pitch_shift_region)); + /* Open the pitch shift dialogue for any selected audio regions */ + reg_sens (_region_actions, "pitch-shift-region", _("Pitch Shift..."), sigc::mem_fun (*this, &Editor::pitch_shift_region)); + + /* Open the transpose dialogue for any selected MIDI regions */ + reg_sens (_region_actions, "transpose-region", _("Transpose..."), sigc::mem_fun (*this, &Editor::transpose_region)); /* Toggle selected region opacity */ toggle_reg_sens (_region_actions, "toggle-opaque-region", _("Opaque"), sigc::mem_fun (*this, &Editor::toggle_opaque_region)); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index dac504bf2..b88cd3cf4 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -87,6 +87,7 @@ #include "editor_cursors.h" #include "mouse_cursors.h" #include "patch_change_dialog.h" +#include "transpose_dialog.h" #include "i18n.h" @@ -5344,11 +5345,42 @@ Editor::pitch_shift_region () { RegionSelection rs = get_regions_from_selection_and_entered (); - if (rs.empty()) { + RegionSelection audio_rs; + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { + if (dynamic_cast (*i)) { + audio_rs.push_back (*i); + } + } + + if (audio_rs.empty()) { return; } - pitch_shift (rs, 1.2); + 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 diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 72c115738..7998a4bfa 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -1072,6 +1072,7 @@ Editor::sensitize_the_right_region_actions () _region_actions->get_action("show-region-list-editor")->set_sensitive (false); _region_actions->get_action("quantize-region")->set_sensitive (false); _region_actions->get_action("fork-region")->set_sensitive (false); + _region_actions->get_action("transpose-region")->set_sensitive (false); } if (_edit_point == EditAtMouse) { @@ -1102,6 +1103,7 @@ Editor::sensitize_the_right_region_actions () _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false); _region_actions->get_action("toggle-region-gain-envelope-visible")->set_sensitive (false); _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false); + _region_actions->get_action("pitch-shift-region")->set_sensitive (false); } diff --git a/gtk2_ardour/time_fx_dialog.cc b/gtk2_ardour/time_fx_dialog.cc index f16676883..1884a54af 100644 --- a/gtk2_ardour/time_fx_dialog.cc +++ b/gtk2_ardour/time_fx_dialog.cc @@ -81,9 +81,9 @@ TimeFXDialog::TimeFXDialog (Editor& e, bool pitch) set_name (N_("TimeFXDialog")); if (pitching) { - set_title (_("Pitch Shift")); + set_title (_("Pitch Shift Audio")); } else { - set_title (_("Time Stretch")); + set_title (_("Time Stretch Audio")); } cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); diff --git a/gtk2_ardour/transpose_dialog.cc b/gtk2_ardour/transpose_dialog.cc new file mode 100644 index 000000000..6a3c5bf11 --- /dev/null +++ b/gtk2_ardour/transpose_dialog.cc @@ -0,0 +1,63 @@ +/* + Copyright (C) 2011 Paul Davis + Author: Carl Hetherington + + 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 +#include +#include +#include "transpose_dialog.h" + +using namespace Gtk; + +TransposeDialog::TransposeDialog () + : ArdourDialog (_("Transpose MIDI")) + , _octaves_adjustment (0.0, -4.0, 4.0, 1, 2.0) + , _semitones_adjustment (0.0, -12.0, 12.0, 1.0, 4.0) + , _octaves_spinner (_octaves_adjustment) + , _semitones_spinner (_semitones_adjustment) +{ + Table* t = manage (new Table (2, 2)); + t->set_row_spacings (6); + t->set_col_spacings (6); + + int r = 0; + Label* l = manage (new Label (_("Octaves:"), ALIGN_LEFT, ALIGN_CENTER, false)); + t->attach (*l, 0, 1, r, r + 1, FILL, EXPAND, 0, 0); + t->attach (_octaves_spinner, 1, 2, r, r + 1, FILL, EXPAND & FILL, 0, 0); + ++r; + + l = manage (new Label (_("Semitones:"), ALIGN_LEFT, ALIGN_CENTER, false)); + t->attach (*l, 0, 1, r, r + 1, FILL, EXPAND, 0, 0); + t->attach (_semitones_spinner, 1, 2, r, r + 1, FILL, EXPAND & FILL, 0, 0); + ++r; + + get_vbox()->set_spacing (6); + get_vbox()->pack_start (*t, false, false); + + add_button (Stock::CANCEL, RESPONSE_CANCEL); + add_button (_("Transpose"), RESPONSE_ACCEPT); + + show_all_children (); +} + +int +TransposeDialog::semitones () const +{ + return _octaves_spinner.get_value () * 12 + _semitones_spinner.get_value (); +} diff --git a/gtk2_ardour/transpose_dialog.h b/gtk2_ardour/transpose_dialog.h new file mode 100644 index 000000000..b2f41cec6 --- /dev/null +++ b/gtk2_ardour/transpose_dialog.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2011 Paul Davis + Author: Carl Hetherington + + 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 +#include "ardour_dialog.h" + +/** A dialog box to select a transposition to apply to a MIDI region. + * It asks for octaves and semitones, with the transposition being + * the sum of the two. + */ + +class TransposeDialog : public ArdourDialog +{ +public: + TransposeDialog (); + + int semitones () const; + +private: + Gtk::Adjustment _octaves_adjustment; + Gtk::Adjustment _semitones_adjustment; + Gtk::SpinButton _octaves_spinner; + Gtk::SpinButton _semitones_spinner; +}; diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 84c5fe76d..a3c0936bd 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -219,6 +219,7 @@ gtk2_ardour_sources = [ 'time_selection.cc', 'track_selection.cc', 'track_view_list.cc', + 'transpose_dialog.cc', 'ui_config.cc', 'utils.cc', 'version.cc', diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index 23e4b9de5..e32d31d2a 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -261,6 +261,7 @@ public: boost::shared_ptr control_factory(const Evoral::Parameter& id); void insert_silence_at_start (TimeType); + void transpose (TimeType, TimeType, int); protected: int resolve_overlaps_unlocked (const NotePtr, void* arg = 0); diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index 016536b8b..bb9f011ec 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -109,6 +109,7 @@ class MidiRegion : public Region boost::shared_ptr model() const { return midi_source()->model(); } void fix_negative_start (); + void transpose (int); protected: diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 1691380c9..e1a955d43 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -1899,3 +1899,43 @@ MidiModel::insert_silence_at_start (TimeType t) apply_command_as_subcommand (s->session(), c); } } + +/** 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) { + + 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); + + } + } + + apply_command (s->session (), c); +} diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index f4058377b..f8640e019 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -378,3 +378,11 @@ MidiRegion::fix_negative_start () model()->insert_silence_at_start (c.from (-_start)); _start = 0; } + +/** 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); +} -- 2.11.4.GIT