From 60055a0d6ab0ce7abd65daeb52cef96cf2c4244f Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 21 Feb 2016 16:28:44 -0500 Subject: first steps in providing more precise control over timestretching --- gtk2_ardour/dark.colors | 4 ++ gtk2_ardour/editor_timefx.cc | 71 ++++++++----------------- gtk2_ardour/time_fx_dialog.cc | 103 +++++++++++++++++++++++++++++------- gtk2_ardour/time_fx_dialog.h | 120 ++++++++++++++++++++++++------------------ 4 files changed, 180 insertions(+), 118 deletions(-) (limited to 'gtk2_ardour') diff --git a/gtk2_ardour/dark.colors b/gtk2_ardour/dark.colors index acfe6130cd..1b6545b386 100644 --- a/gtk2_ardour/dark.colors +++ b/gtk2_ardour/dark.colors @@ -430,6 +430,10 @@ + + + + diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc index d78340df65..932ca71b0e 100644 --- a/gtk2_ardour/editor_timefx.cc +++ b/gtk2_ardour/editor_timefx.cc @@ -29,6 +29,13 @@ #include "pbd/memento_command.h" #include "pbd/stateful_diff_command.h" +#include "ardour/audioregion.h" +#include "ardour/midi_stretch.h" +#include "ardour/pitch.h" +#include "ardour/region.h" +#include "ardour/session.h" +#include "ardour/stretch.h" + #include #include "audio_region_view.h" @@ -37,13 +44,6 @@ #include "region_selection.h" #include "time_fx_dialog.h" -#include "ardour/audioregion.h" -#include "ardour/midi_stretch.h" -#include "ardour/pitch.h" -#include "ardour/region.h" -#include "ardour/session.h" -#include "ardour/stretch.h" - #ifdef USE_RUBBERBAND #include using namespace RubberBand; @@ -146,22 +146,18 @@ Editor::pitch_shift (RegionSelection& regions, float fraction) int Editor::time_fx (RegionList& regions, float val, bool pitching) { - delete current_timefx; - current_timefx = new TimeFXDialog (*this, pitching); - current_timefx->regions = regions; - - /* See if we have any audio regions on our list */ - RegionList::iterator i = regions.begin (); - while (i != regions.end() && boost::dynamic_pointer_cast (*i) == 0) { - ++i; - } - - if (i == regions.end ()) { - /* No audio regions; we can just do the timefx without a dialogue */ - do_timefx (); + if (regions.empty()) { return 0; } + const framecnt_t oldlen = (framecnt_t) (regions.front()->length()); + const framecnt_t newlen = (framecnt_t) (regions.front()->length() * val); + const framecnt_t pos = regions.front()->position (); + + delete current_timefx; + current_timefx = new TimeFXDialog (*this, pitching, oldlen, newlen, pos); + current_timefx->regions = regions; + switch (current_timefx->run ()) { case RESPONSE_ACCEPT: break; @@ -171,34 +167,14 @@ Editor::time_fx (RegionList& regions, float val, bool pitching) } current_timefx->status = 0; + current_timefx->request.time_fraction = current_timefx->get_time_fraction (); + current_timefx->request.pitch_fraction = current_timefx->get_pitch_fraction (); - if (pitching) { - - float cents = current_timefx->pitch_octave_adjustment.get_value() * 1200.0; - float pitch_fraction; - cents += current_timefx->pitch_semitone_adjustment.get_value() * 100.0; - cents += current_timefx->pitch_cent_adjustment.get_value(); - - if (cents == 0.0) { - // user didn't change anything - current_timefx->hide (); - return 0; - } - - // one octave == 1200 cents - // adding one octave doubles the frequency - // ratio is 2^^octaves - - pitch_fraction = pow(2, cents/1200); - - current_timefx->request.time_fraction = 1.0; - current_timefx->request.pitch_fraction = pitch_fraction; - - } else { - - current_timefx->request.time_fraction = val; - current_timefx->request.pitch_fraction = 1.0; - + if (current_timefx->request.time_fraction == 1.0 && + current_timefx->request.pitch_fraction == 1.0) { + /* nothing to do */ + current_timefx->hide (); + return 0; } #ifdef USE_RUBBERBAND @@ -413,4 +389,3 @@ Editor::timefx_thread (void *arg) #endif return 0; } - diff --git a/gtk2_ardour/time_fx_dialog.cc b/gtk2_ardour/time_fx_dialog.cc index 7efabc93ed..e16ba92504 100644 --- a/gtk2_ardour/time_fx_dialog.cc +++ b/gtk2_ardour/time_fx_dialog.cc @@ -17,7 +17,6 @@ */ -#include "time_fx_dialog.h" #include #include @@ -31,10 +30,12 @@ #include +#include "audio_clock.h" #include "editor.h" #include "audio_time_axis.h" #include "audio_region_view.h" #include "region_selection.h" +#include "time_fx_dialog.h" #ifdef USE_RUBBERBAND #include @@ -49,21 +50,27 @@ using namespace PBD; using namespace Gtk; using namespace Gtkmm2ext; -TimeFXDialog::TimeFXDialog (Editor& e, bool pitch) +TimeFXDialog::TimeFXDialog (Editor& e, bool pitch, framecnt_t oldlen, framecnt_t new_length, framepos_t position) : ArdourDialog (X_("time fx dialog")) , editor (e) , pitching (pitch) + , quick_button (_("Quick but Ugly")) + , antialias_button (_("Skip Anti-aliasing")) + , stretch_opts_label (_("Contents:")) + , precise_button (_("Minimize time distortion")) + , preserve_formants_button(_("Preserve Formants")) + , original_length (oldlen) , pitch_octave_adjustment (0.0, -4.0, 4.0, 1, 2.0) , pitch_semitone_adjustment (0.0, -12.0, 12.0, 1.0, 4.0) , pitch_cent_adjustment (0.0, -499.0, 500.0, 5.0, 15.0) , pitch_octave_spinner (pitch_octave_adjustment) , pitch_semitone_spinner (pitch_semitone_adjustment) , pitch_cent_spinner (pitch_cent_adjustment) - , quick_button (_("Quick but Ugly")) - , antialias_button (_("Skip Anti-aliasing")) - , stretch_opts_label (_("Contents:")) - , precise_button (_("Minimize time distortion")) - , preserve_formants_button(_("Preserve Formants")) + , percent_adjustment (100.0, -1000.0, 1000.0, 1.0, 10.0) + , duration_clock (0) + , duration_chosen (_("Duration")) + , choice_group (duration_chosen.get_group()) + , percent_chosen (choice_group, _("Percent")) { set_modal (true); set_skip_taskbar_hint (true); @@ -123,31 +130,55 @@ TimeFXDialog::TimeFXDialog (Editor& e, bool pitch) upper_button_box.pack_start (*table, false, true); } else { - Table* table = manage (new Table (2, 3, false)); + Table* table = manage (new Table (4, 2, false)); + int row = 0; + table->set_row_spacings (6); - table->set_col_spacing (1, 6); - l = manage (new Label ("", Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false )); - l->set_padding (8, 0); - table->attach (*l, 0, 1, 0, 2, Gtk::FILL, Gtk::FILL, 0, 0); + table->set_col_spacings (6); #ifdef USE_RUBBERBAND vector strings; + duration_clock = manage (new AudioClock (X_("stretch"), true, "stretch", true, false, true, false, true)); + duration_clock->set_session (e.session()); + duration_clock->set (new_length, true); + duration_clock->set_mode (AudioClock::BBT); + duration_clock->set_bbt_reference (position); + + Gtk::Alignment* clock_align = manage (new Gtk::Alignment); + clock_align->add (*duration_clock); + clock_align->set (0.0, 0.5, 0.0, 1.0); + + Gtk::RadioButtonGroup group; + table->attach (duration_chosen, 0, 1, row, row+1, Gtk::FILL, Gtk::FILL, 0, 0); + table->attach (*clock_align, 1, 2, row, row+1, Gtk::AttachOptions (Gtk::EXPAND|Gtk::FILL), Gtk::FILL, 0, 0); + row++; + + const double fract = ((double) new_length) / original_length; + /* note the *100.0 to convert fract into a percentage */ + percent_adjustment.set_value (fract*100.0); + Gtk::SpinButton* spinner = manage (new Gtk::SpinButton (percent_adjustment, 1.0, 3)); + + table->attach (percent_chosen, 0, 1, row, row+1, Gtk::FILL, Gtk::FILL, 0, 0); + table->attach (*spinner, 1, 2, row, row+1, Gtk::FILL, Gtk::FILL, 0, 0); + row++; - table->attach (stretch_opts_label, 1, 2, 0, 1, Gtk::FILL, Gtk::EXPAND, 0, 0); + table->attach (stretch_opts_label, 0, 1, row, row+1, Gtk::FILL, Gtk::EXPAND, 0, 0); set_popdown_strings (stretch_opts_selector, editor.rb_opt_strings); /* set default */ stretch_opts_selector.set_active_text (editor.rb_opt_strings[editor.rb_current_opt]); - table->attach (stretch_opts_selector, 2, 3, 0, 1, Gtk::FILL, Gtk::EXPAND & Gtk::FILL, 0, 0); - - table->attach (precise_button, 1, 3, 1, 2, Gtk::FILL, Gtk::EXPAND, 0, 0); + table->attach (stretch_opts_selector, 1, 2, row, row+1, Gtk::FILL, Gtk::EXPAND & Gtk::FILL, 0, 0); + row++; + table->attach (precise_button, 0, 2, row, row+1, Gtk::FILL, Gtk::EXPAND, 0, 0); + row++; #else quick_button.set_name (N_("TimeFXButton")); - table->attach (quick_button, 1, 3, 0, 1, Gtk::FILL, Gtk::EXPAND, 0, 0); + table->attach (quick_button, 1, 3, row, row+1, Gtk::FILL, Gtk::EXPAND, 0, 0); + row++; antialias_button.set_name (N_("TimeFXButton")); - table->attach (antialias_button, 1, 3, 1, 2, Gtk::FILL, Gtk::EXPAND, 0, 0); + table->attach (antialias_button, 1, 3, row, row+1, Gtk::FILL, Gtk::EXPAND, 0, 0); #endif @@ -199,3 +230,39 @@ TimeFXDialog::delete_in_progress (GdkEventAny*) return TRUE; } +float +TimeFXDialog::get_time_fraction () const +{ + if (pitching) { + return 1.0; + } + + if (duration_chosen.get_active()) { + return duration_clock->current_duration () / original_length; + } + + return percent_adjustment.get_value() / 100.0; +} + +float +TimeFXDialog::get_pitch_fraction () const +{ + if (!pitching) { + return 1.0; + } + + float cents = pitch_octave_adjustment.get_value() * 1200.0; + + cents += pitch_semitone_adjustment.get_value() * 100.0; + cents += pitch_cent_adjustment.get_value(); + + if (cents == 0.0) { + return 1.0; + } + + // one octave == 1200 cents + // adding one octave doubles the frequency + // ratio is 2^^octaves + + return pow(2, cents/1200); +} diff --git a/gtk2_ardour/time_fx_dialog.h b/gtk2_ardour/time_fx_dialog.h index a7e4a7ab10..c2616b6d2b 100644 --- a/gtk2_ardour/time_fx_dialog.h +++ b/gtk2_ardour/time_fx_dialog.h @@ -1,26 +1,32 @@ /* - Copyright (C) 2000-2009 Paul Davis + Copyright (C) 2000-2009 Paul Davis - 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 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. + 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. + 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_time_fx_dialog_h__ #define __ardour_time_fx_dialog_h__ -#include +#include +#include +#include +#include +#include +#include +#include #include "ardour/timefx_request.h" @@ -28,48 +34,58 @@ #include "progress_reporter.h" class Editor; +class AudioClock; class TimeFXDialog : public ArdourDialog, public ProgressReporter { -public: - ARDOUR::TimeFXRequest request; - Editor& editor; - bool pitching; - Gtk::Adjustment pitch_octave_adjustment; - Gtk::Adjustment pitch_semitone_adjustment; - Gtk::Adjustment pitch_cent_adjustment; - Gtk::SpinButton pitch_octave_spinner; - Gtk::SpinButton pitch_semitone_spinner; - Gtk::SpinButton pitch_cent_spinner; - Gtk::ProgressBar progress_bar; - ARDOUR::RegionList regions; - - /* SoundTouch */ - Gtk::CheckButton quick_button; - Gtk::CheckButton antialias_button; - Gtk::VBox upper_button_box; - - /* RubberBand */ - Gtk::ComboBoxText stretch_opts_selector; - Gtk::Label stretch_opts_label; - Gtk::CheckButton precise_button; - Gtk::CheckButton preserve_formants_button; - - Gtk::Button* cancel_button; - Gtk::Button* action_button; - Gtk::VBox packer; - int status; - - TimeFXDialog (Editor& e, bool for_pitch); - - sigc::connection first_cancel; - sigc::connection first_delete; - void cancel_in_progress (); - gint delete_in_progress (GdkEventAny*); - -private: - - void update_progress_gui (float); + public: + /* We need a position so that BBT mode in the clock can function */ + TimeFXDialog (Editor& e, bool for_pitch, ARDOUR::framecnt_t old_length, ARDOUR::framecnt_t new_length, ARDOUR::framepos_t position); + + ARDOUR::TimeFXRequest request; + Editor& editor; + bool pitching; + Gtk::ProgressBar progress_bar; + ARDOUR::RegionList regions; + + /* SoundTouch */ + Gtk::CheckButton quick_button; + Gtk::CheckButton antialias_button; + Gtk::VBox upper_button_box; + + /* RubberBand */ + Gtk::ComboBoxText stretch_opts_selector; + Gtk::Label stretch_opts_label; + Gtk::CheckButton precise_button; + Gtk::CheckButton preserve_formants_button; + + Gtk::Button* cancel_button; + Gtk::Button* action_button; + Gtk::VBox packer; + int status; + + sigc::connection first_cancel; + sigc::connection first_delete; + void cancel_in_progress (); + gint delete_in_progress (GdkEventAny*); + + float get_time_fraction () const; + float get_pitch_fraction () const; + + private: + ARDOUR::framecnt_t original_length; + Gtk::Adjustment pitch_octave_adjustment; + Gtk::Adjustment pitch_semitone_adjustment; + Gtk::Adjustment pitch_cent_adjustment; + Gtk::SpinButton pitch_octave_spinner; + Gtk::SpinButton pitch_semitone_spinner; + Gtk::SpinButton pitch_cent_spinner; + Gtk::Adjustment percent_adjustment; + AudioClock* duration_clock; + Gtk::RadioButton duration_chosen; + Gtk::RadioButtonGroup choice_group; + Gtk::RadioButton percent_chosen; + void update_progress_gui (float); }; #endif /* __ardour_time_fx_dialog_h__ */ -- cgit v1.2.3