summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/ardour-sae.bindings.in4
-rw-r--r--gtk2_ardour/ardour-sae.menus4
-rw-r--r--gtk2_ardour/ardour_ui.cc2
-rw-r--r--gtk2_ardour/editor.cc2
-rw-r--r--gtk2_ardour/editor.h32
-rw-r--r--gtk2_ardour/editor_actions.cc5
-rw-r--r--gtk2_ardour/editor_keyboard.cc11
-rw-r--r--gtk2_ardour/editor_mouse.cc2
-rw-r--r--gtk2_ardour/editor_ops.cc24
-rw-r--r--gtk2_ardour/editor_timefx.cc205
-rw-r--r--libs/ardour/SConscript6
-rw-r--r--libs/ardour/ardour/pitch.h62
-rw-r--r--libs/ardour/ardour/region.h4
-rw-r--r--libs/ardour/ardour/stretch.h37
-rw-r--r--libs/ardour/ardour/types.h7
-rw-r--r--libs/ardour/rb_effect.cc (renamed from libs/ardour/rb_pitch.cc)68
-rw-r--r--libs/ardour/region.cc14
-rw-r--r--libs/ardour/st_pitch.cc56
-rw-r--r--libs/ardour/st_stretch.cc6
19 files changed, 424 insertions, 127 deletions
diff --git a/gtk2_ardour/ardour-sae.bindings.in b/gtk2_ardour/ardour-sae.bindings.in
index 2449abd00e..78af95aa15 100644
--- a/gtk2_ardour/ardour-sae.bindings.in
+++ b/gtk2_ardour/ardour-sae.bindings.in
@@ -66,7 +66,7 @@
(gtk_accel_path "<Actions>/Editor/jump-backward-to-mark" "<%PRIMARY%>KP_Left")
; (gtk_accel_path "<Actions>/Main/AudioFileFormatData" "")
; (gtk_accel_path "<Actions>/options/MeterFalloffFastest" "")
-; (gtk_accel_path "<Actions>/Editor/audition-at-mouse" "w")
+(gtk_accel_path "<Actions>/Editor/audition-region" "w")
(gtk_accel_path "<Actions>/Transport/Forward" "<%PRIMARY%>rightarrow")
; (gtk_accel_path "<Actions>/Snap/snap-to-smpte-seconds" "")
; (gtk_accel_path "<Actions>/Snap/snap-to-smpte-frame" "")
@@ -340,5 +340,5 @@
(gtk_accel_path "<Actions>/Editor/loop-region" "<%PRIMARY%>bracketright")
(gtk_accel_path "<Actions>/Editor/toggle-zoom" "o")
(gtk_accel_path "<Actions>/Editor/zoom-to-region" "y")
-
+(gtk_accel_path "<Actions>/Editor/pitch-shift-region" "F5")
diff --git a/gtk2_ardour/ardour-sae.menus b/gtk2_ardour/ardour-sae.menus
index 62d3447920..fa5c45914f 100644
--- a/gtk2_ardour/ardour-sae.menus
+++ b/gtk2_ardour/ardour-sae.menus
@@ -106,7 +106,7 @@
<menuitem action='edit-to-playhead'/>
</menu>
<menu name='KeyMouse Actions' action='KeyMouse Actions'>
- <menuitem action='audition-at-mouse'/>
+ <menuitem action='audition-region'/>
<menuitem action='brush-at-mouse'/>
<menuitem action='mute-unmute-region'/>
<separator/>
@@ -148,6 +148,8 @@
<menuitem action='trim-back'/>
<menuitem action='trim-region-to-loop'/>
<menuitem action='trim-region-to-punch'/>
+ <separator/>
+ <menuitem action='pitch-shift-region'/>
</menu>
<menu name='View' action = 'View'>
<menuitem action='ToggleMaximalEditor'/>
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index 44562f3ec0..033cc5ed3c 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -2028,6 +2028,8 @@ ARDOUR_UI::get_session_parameters (Glib::ustring predetermined_path, bool have_e
new_session_dialog->show();
new_session_dialog->present ();
response = new_session_dialog->run ();
+
+ loading_dialog->hide ();
_session_is_new = false;
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index e3b5796045..ba824512df 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -302,7 +302,7 @@ Editor::Editor ()
entered_marker = 0;
clear_entered_track = false;
_new_regionviews_show_envelope = false;
- current_timestretch = 0;
+ current_timefx = 0;
in_edit_group_row_change = false;
last_canvas_frame = 0;
playhead_cursor = 0;
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 63a19e0d3e..30cfed686d 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -1290,7 +1290,6 @@ class Editor : public PublicEditor
void kbd_driver (sigc::slot<void,GdkEvent*>, bool use_track_canvas = true, bool use_time_canvas = true, bool can_select = true);
void kbd_mute_unmute_region ();
void kbd_brush ();
- void kbd_audition ();
void kbd_do_brush (GdkEvent*);
void kbd_do_audition (GdkEvent*);
@@ -1806,9 +1805,16 @@ class Editor : public PublicEditor
void start_time_fx (ArdourCanvas::Item*, GdkEvent*);
void end_time_fx (ArdourCanvas::Item*, GdkEvent*);
- struct TimeStretchDialog : public ArdourDialog {
- ARDOUR::TimeStretchRequest request;
+ struct TimeFXDialog : public ArdourDialog {
+ 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;
RegionSelection regions;
Gtk::ProgressBar progress_bar;
Gtk::ToggleButton quick_button;
@@ -1819,24 +1825,28 @@ class Editor : public PublicEditor
Gtk::VBox packer;
int status;
- TimeStretchDialog (Editor& e);
+ TimeFXDialog (Editor& e, bool for_pitch);
gint update_progress ();
sigc::connection first_cancel;
sigc::connection first_delete;
- void cancel_timestretch_in_progress ();
- gint delete_timestretch_in_progress (GdkEventAny*);
+ void cancel_in_progress ();
+ gint delete_in_progress (GdkEventAny*);
};
/* "whats mine is yours" */
- friend class TimeStretchDialog;
+ friend class TimeFXDialog;
- TimeStretchDialog* current_timestretch;
+ TimeFXDialog* current_timefx;
- static void* timestretch_thread (void *arg);
- int run_timestretch (RegionSelection&, float fraction);
- void do_timestretch (TimeStretchDialog&);
+ static void* timefx_thread (void *arg);
+ void do_timefx (TimeFXDialog&);
+
+ int time_stretch (RegionSelection&, float fraction);
+ int pitch_shift (RegionSelection&, float cents);
+ void pitch_shift_regions ();
+ int time_fx (RegionSelection&, float val, bool pitching);
/* editor-mixer strip */
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index 487d354a0a..2d2e91600c 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -267,6 +267,9 @@ Editor::register_actions ()
ActionManager::session_sensitive_actions.push_back (act);
+ act = ActionManager::register_action (editor_actions, "pitch-shift-region", _("Transpose"), mem_fun(*this, &Editor::pitch_shift_regions));
+ ActionManager::session_sensitive_actions.push_back (act);
+
act = ActionManager::register_action (editor_actions, "set-fade-in-length", _("Set Fade In Length"), bind (mem_fun(*this, &Editor::set_fade_length), true));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "toggle-fade-in-active", _("Toggle Fade In Active"), bind (mem_fun(*this, &Editor::toggle_fade_active), true));
@@ -290,7 +293,7 @@ Editor::register_actions ()
act = ActionManager::register_action (editor_actions, "align-regions-sync-relative", _("Align Regions Sync Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint));
ActionManager::session_sensitive_actions.push_back (act);
- act = ActionManager::register_action (editor_actions, "audition-at-mouse", _("Audition at Mouse"), mem_fun(*this, &Editor::kbd_audition));
+ act = ActionManager::register_action (editor_actions, "audition-region", _("Audition Region"), mem_fun(*this, &Editor::audition_selected_region));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "brush-at-mouse", _("Brush at Mouse"), mem_fun(*this, &Editor::kbd_brush));
ActionManager::session_sensitive_actions.push_back (act);
diff --git a/gtk2_ardour/editor_keyboard.cc b/gtk2_ardour/editor_keyboard.cc
index 7f2b892fc6..4a5d55d879 100644
--- a/gtk2_ardour/editor_keyboard.cc
+++ b/gtk2_ardour/editor_keyboard.cc
@@ -102,14 +102,3 @@ Editor::kbd_brush ()
kbd_driver (mem_fun(*this, &Editor::kbd_do_brush), true, true, false);
}
-void
-Editor::kbd_do_audition (GdkEvent *ignored)
-{
- audition_selected_region ();
-}
-
-void
-Editor::kbd_audition ()
-{
- kbd_driver (mem_fun(*this, &Editor::kbd_do_audition), true, false, true);
-}
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc
index f6e3301164..f65325c2de 100644
--- a/gtk2_ardour/editor_mouse.cc
+++ b/gtk2_ardour/editor_mouse.cc
@@ -5166,7 +5166,7 @@ Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
begin_reversible_command (_("timestretch"));
- if (run_timestretch (selection->regions, percentage) == 0) {
+ if (time_stretch (selection->regions, percentage) == 0) {
session->commit_reversible_command ();
}
}
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index 5edd0e15c4..6814dda081 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -2258,9 +2258,15 @@ Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Ro
void
Editor::audition_selected_region ()
{
- if (!selection->regions.empty()) {
- RegionView* rv = *(selection->regions.begin());
- session->audition_region (rv->region());
+ ensure_entered_region_selected (true);
+
+ if (selection->regions.empty()) {
+ return;
+ }
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ session->audition_region ((*i)->region());
+ /* XXX need to check if user requested stop between each one, but how? */
}
}
@@ -4600,3 +4606,15 @@ Editor::set_punch_from_edit_range ()
set_punch_range (start, end, _("set punch range from edit range"));
}
+void
+Editor::pitch_shift_regions ()
+{
+ ensure_entered_region_selected (true);
+
+ if (selection->regions.empty()) {
+ return;
+ }
+
+ pitch_shift (selection->regions, 1.2);
+}
+
diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc
index df0a73c965..b87c80b38e 100644
--- a/gtk2_ardour/editor_timefx.cc
+++ b/gtk2_ardour/editor_timefx.cc
@@ -40,6 +40,7 @@
#include <ardour/audioregion.h>
#include <ardour/audio_diskstream.h>
#include <ardour/stretch.h>
+#include <ardour/pitch.h>
#include "i18n.h"
@@ -49,50 +50,88 @@ using namespace sigc;
using namespace Gtk;
using namespace Gtkmm2ext;
-Editor::TimeStretchDialog::TimeStretchDialog (Editor& e)
- : ArdourDialog ("time stretch dialog"),
+Editor::TimeFXDialog::TimeFXDialog (Editor& e, bool pitch)
+ : ArdourDialog (X_("time fx dialog")),
editor (e),
+ pitching (pitch),
+ pitch_octave_adjustment (0.0, 0.0, 4.0, 1, 2.0),
+ pitch_semitone_adjustment (0.0, 0.0, 12.0, 1.0, 4.0),
+ pitch_cent_adjustment (0.0, 0.0, 150.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"))
{
set_modal (true);
set_position (Gtk::WIN_POS_MOUSE);
- set_name (N_("TimeStretchDialog"));
+ set_name (N_("TimeFXDialog"));
WindowTitle title(Glib::get_application_name());
- title += _("Timestretch");
+ if (pitching) {
+ title += _("Pitch Shift");
+ } else {
+ title += _("Time Stretch");
+ }
set_title(title.get_string());
+ cancel_button = add_button (_("Cancel"), Gtk::RESPONSE_CANCEL);
+
get_vbox()->set_spacing (5);
- get_vbox()->set_border_width (5);
- get_vbox()->pack_start (upper_button_box);
+ get_vbox()->set_border_width (12);
+ get_vbox()->pack_start (upper_button_box, false, false);
get_vbox()->pack_start (progress_bar);
- upper_button_box.set_homogeneous (true);
- upper_button_box.set_spacing (5);
- upper_button_box.set_border_width (5);
- upper_button_box.pack_start (quick_button, true, true);
- upper_button_box.pack_start (antialias_button, true, true);
+ if (pitching) {
- action_button = add_button (_("Stretch/Shrink it"), Gtk::RESPONSE_ACCEPT);
- cancel_button = add_button (_("Cancel"), Gtk::RESPONSE_CANCEL);
+ upper_button_box.set_spacing (5);
+ upper_button_box.set_border_width (5);
+
+ Gtk::Label* l;
+
+ l = manage (new Label (_("Octaves")));
+ upper_button_box.pack_start (*l, false, false);
+ upper_button_box.pack_start (pitch_octave_spinner, false, false);
+
+ l = manage (new Label (_("Semitones (12TET)")));
+ upper_button_box.pack_start (*l, false, false);
+ upper_button_box.pack_start (pitch_semitone_spinner, false, false);
+
+ l = manage (new Label (_("Cents")));
+ upper_button_box.pack_start (*l, false, false);
+ upper_button_box.pack_start (pitch_cent_spinner, false, false);
+
+ pitch_cent_spinner.set_digits (1);
+
+ add_button (_("Shift"), Gtk::RESPONSE_ACCEPT);
- quick_button.set_name (N_("TimeStretchButton"));
- antialias_button.set_name (N_("TimeStretchButton"));
- progress_bar.set_name (N_("TimeStretchProgress"));
+ } else {
+
+ upper_button_box.set_homogeneous (true);
+ upper_button_box.set_spacing (5);
+ upper_button_box.set_border_width (5);
+ upper_button_box.pack_start (quick_button, true, true);
+ upper_button_box.pack_start (antialias_button, true, true);
+
+ add_button (_("Stretch/Shrink"), Gtk::RESPONSE_ACCEPT);
+ }
+
+ quick_button.set_name (N_("TimeFXButton"));
+ antialias_button.set_name (N_("TimeFXButton"));
+ progress_bar.set_name (N_("TimeFXProgress"));
show_all_children ();
}
gint
-Editor::TimeStretchDialog::update_progress ()
+Editor::TimeFXDialog::update_progress ()
{
progress_bar.set_fraction (request.progress);
return !request.done;
}
void
-Editor::TimeStretchDialog::cancel_timestretch_in_progress ()
+Editor::TimeFXDialog::cancel_in_progress ()
{
status = -2;
request.cancel = true;
@@ -100,7 +139,7 @@ Editor::TimeStretchDialog::cancel_timestretch_in_progress ()
}
gint
-Editor::TimeStretchDialog::delete_timestretch_in_progress (GdkEventAny* ev)
+Editor::TimeFXDialog::delete_in_progress (GdkEventAny* ev)
{
status = -2;
request.cancel = true;
@@ -109,63 +148,109 @@ Editor::TimeStretchDialog::delete_timestretch_in_progress (GdkEventAny* ev)
}
int
-Editor::run_timestretch (RegionSelection& regions, float fraction)
+Editor::time_stretch (RegionSelection& regions, float fraction)
+{
+ return time_fx (regions, fraction, false);
+}
+
+int
+Editor::pitch_shift (RegionSelection& regions, float fraction)
{
- if (current_timestretch == 0) {
- current_timestretch = new TimeStretchDialog (*this);
+ return time_fx (regions, fraction, true);
+}
+
+int
+Editor::time_fx (RegionSelection& regions, float val, bool pitching)
+{
+ if (current_timefx != 0) {
+ delete current_timefx;
}
- current_timestretch->progress_bar.set_fraction (0.0f);
+ current_timefx = new TimeFXDialog (*this, pitching);
+
+ current_timefx->progress_bar.set_fraction (0.0f);
- switch (current_timestretch->run ()) {
+ switch (current_timefx->run ()) {
case RESPONSE_ACCEPT:
break;
default:
- current_timestretch->hide ();
+ current_timefx->hide ();
return 1;
}
- current_timestretch->status = 0;
- current_timestretch->regions = regions;
- current_timestretch->request.fraction = fraction;
- current_timestretch->request.quick_seek = current_timestretch->quick_button.get_active();
- current_timestretch->request.antialias = !current_timestretch->antialias_button.get_active();
- current_timestretch->request.progress = 0.0f;
- current_timestretch->request.done = false;
- current_timestretch->request.cancel = false;
+ current_timefx->status = 0;
+ current_timefx->regions = regions;
+
+ if (pitching) {
+
+ float cents = current_timefx->pitch_octave_adjustment.get_value() * 1200.0;
+ 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;
+ }
+
+ // we now have the pitch shift in cents. divide by 1200 to get octaves
+ // then multiply by 2.0 because 1 octave == doubling the frequency
+
+ cents /= 1200.0;
+ cents /= 2.0;
+
+ // add 1.0 to convert to RB scale
+
+ cents += 1.0;
+
+ current_timefx->request.time_fraction = 1.0;
+ current_timefx->request.pitch_fraction = cents;
+
+ } else {
+
+ current_timefx->request.time_fraction = val;
+ current_timefx->request.pitch_fraction = 1.0;
+
+ }
+
+ current_timefx->request.quick_seek = current_timefx->quick_button.get_active();
+ current_timefx->request.antialias = !current_timefx->antialias_button.get_active();
+ current_timefx->request.progress = 0.0f;
+ current_timefx->request.done = false;
+ current_timefx->request.cancel = false;
/* re-connect the cancel button and delete events */
- current_timestretch->first_cancel.disconnect();
- current_timestretch->first_delete.disconnect();
+ current_timefx->first_cancel.disconnect();
+ current_timefx->first_delete.disconnect();
- current_timestretch->first_cancel = current_timestretch->cancel_button->signal_clicked().connect
- (mem_fun (current_timestretch, &TimeStretchDialog::cancel_timestretch_in_progress));
- current_timestretch->first_delete = current_timestretch->signal_delete_event().connect
- (mem_fun (current_timestretch, &TimeStretchDialog::delete_timestretch_in_progress));
-
- if (pthread_create_and_store ("timestretch", &current_timestretch->request.thread, 0, timestretch_thread, current_timestretch)) {
- current_timestretch->hide ();
- error << _("timestretch cannot be started - thread creation error") << endmsg;
+ current_timefx->first_cancel = current_timefx->cancel_button->signal_clicked().connect
+ (mem_fun (current_timefx, &TimeFXDialog::cancel_in_progress));
+ current_timefx->first_delete = current_timefx->signal_delete_event().connect
+ (mem_fun (current_timefx, &TimeFXDialog::delete_in_progress));
+
+ if (pthread_create_and_store ("timefx", &current_timefx->request.thread, 0, timefx_thread, current_timefx)) {
+ current_timefx->hide ();
+ error << _("timefx cannot be started - thread creation error") << endmsg;
return -1;
}
- pthread_detach (current_timestretch->request.thread);
+ pthread_detach (current_timefx->request.thread);
- sigc::connection c = Glib::signal_timeout().connect (mem_fun (current_timestretch, &TimeStretchDialog::update_progress), 100);
+ sigc::connection c = Glib::signal_timeout().connect (mem_fun (current_timefx, &TimeFXDialog::update_progress), 100);
- while (!current_timestretch->request.done) {
+ while (!current_timefx->request.done) {
gtk_main_iteration ();
}
c.disconnect ();
- current_timestretch->hide ();
- return current_timestretch->status;
+ current_timefx->hide ();
+ return current_timefx->status;
}
void
-Editor::do_timestretch (TimeStretchDialog& dialog)
+Editor::do_timefx (TimeFXDialog& dialog)
{
Track* t;
boost::shared_ptr<Playlist> playlist;
@@ -205,16 +290,23 @@ Editor::do_timestretch (TimeStretchDialog& dialog)
return;
}
- Stretch stretch (*session, dialog.request);
+ AudioFilter* fx;
+
+ if (dialog.pitching) {
+ fx = new Pitch (*session, dialog.request);
+ } else {
+ fx = new Stretch (*session, dialog.request);
+ }
- if (stretch.run (region)) {
+ if (fx->run (region)) {
dialog.status = -1;
dialog.request.done = true;
+ delete fx;
return;
}
- if (!stretch.results.empty()) {
- new_region = stretch.results.front();
+ if (!fx->results.empty()) {
+ new_region = fx->results.front();
XMLNode &before = playlist->get_state();
playlist->replace_region (region, new_region, region->position());
@@ -223,6 +315,7 @@ Editor::do_timestretch (TimeStretchDialog& dialog)
}
i = tmp;
+ delete fx;
}
dialog.status = 0;
@@ -230,15 +323,15 @@ Editor::do_timestretch (TimeStretchDialog& dialog)
}
void*
-Editor::timestretch_thread (void *arg)
+Editor::timefx_thread (void *arg)
{
PBD::ThreadCreated (pthread_self(), X_("TimeFX"));
- TimeStretchDialog* tsd = static_cast<TimeStretchDialog*>(arg);
+ TimeFXDialog* tsd = static_cast<TimeFXDialog*>(arg);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
- tsd->editor.do_timestretch (*tsd);
+ tsd->editor.do_timefx (*tsd);
return 0;
}
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index d29f4a0b10..5f33eb01f8 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -267,10 +267,10 @@ ardour.Merge ([
if ardour['RUBBERBAND']:
ardour.Merge ([ libraries['rubberband'], libraries['vamp'], libraries['fftw3f'] ])
- timefx_sources += [ 'rb_stretch.cc' ]
+ timefx_sources += [ 'rb_effect.cc' ]
else:
ardour.Merge ([ libraries['soundtouch'] ])
- timefx_sources += [ 'st_stretch.cc' ]
+ timefx_sources += [ 'st_stretch.cc', 'st_pitch.cc' ]
if ardour['LIBLO']:
ardour.Merge ([ libraries['lo'] ])
@@ -326,6 +326,6 @@ env.Alias('version', ardour.VersionBuild(['version.cc', 'ardour/version.h'], [])
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'i18n.h', 'gettext.h' ] +
[ 'sse_functions_xmm.cc', 'sse_functions.s', 'sse_functions_64bit.s' ] +
- [ 'rb_stretch.cc', 'st_stretch.cc' ] +
+ [ 'rb_effect.cc', 'st_stretch.cc', 'st_pitch.cc' ] +
ardour_files + osc_files + vst_files + coreaudio_files + audiounit_files +
glob.glob('po/*.po') + glob.glob('ardour/*.h')))
diff --git a/libs/ardour/ardour/pitch.h b/libs/ardour/ardour/pitch.h
new file mode 100644
index 0000000000..785a429625
--- /dev/null
+++ b/libs/ardour/ardour/pitch.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2007 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 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_pitch_h__
+#define __ardour_pitch_h__
+
+#include <ardour/audiofilter.h>
+
+namespace ARDOUR {
+ class AudioRegion;
+}
+
+#ifdef USE_RUBBERBAND
+
+#include <ardour/rb_effect.h>
+
+namespace ARDOUR {
+
+class Pitch : public RBEffect {
+ public:
+ Pitch (ARDOUR::Session&, TimeFXRequest&);
+ ~Pitch () {}
+};
+
+} /* namespace */
+
+# else
+
+namespace ARDOUR {
+
+class Pitch : public AudioFilter {
+ public:
+ Pitch (ARDOUR::Session&, TimeFXRequest&);
+ ~Pitch () {}
+
+ int run (boost::shared_ptr<ARDOUR::AudioRegion>);
+
+ private:
+ TimeFXRequest& tsr;
+};
+
+} /* namespace */
+
+#endif
+
+#endif /* __ardour_pitch_h__ */
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 8acbc8b39b..3aae8c4767 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -98,8 +98,9 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
nframes64_t ancestral_start () const { return _ancestral_start; }
nframes64_t ancestral_length () const { return _ancestral_length; }
float stretch() const { return _stretch; }
+ float shift() const { return _shift; }
- void set_ancestral_data (nframes64_t start, nframes64_t length, float stretch);
+ void set_ancestral_data (nframes64_t start, nframes64_t length, float stretch, float shift);
nframes_t sync_offset(int& dir) const;
nframes_t sync_position() const;
@@ -235,6 +236,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
nframes64_t _ancestral_start;
nframes64_t _ancestral_length;
float _stretch;
+ float _shift;
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/stretch.h b/libs/ardour/ardour/stretch.h
index 6b5c2957e1..0ec926916c 100644
--- a/libs/ardour/ardour/stretch.h
+++ b/libs/ardour/ardour/stretch.h
@@ -22,36 +22,45 @@
#include <ardour/audiofilter.h>
-#ifndef USE_RUBBERBAND
-#include <soundtouch/SoundTouch.h>
-#endif
-
namespace ARDOUR {
+ class AudioRegion;
+}
-class AudioRegion;
+#ifdef USE_RUBBERBAND
-struct TimeStretchRequest : public InterThreadInfo {
- float fraction;
- bool quick_seek;
- bool antialias;
+#include <ardour/rb_effect.h>
+
+namespace ARDOUR {
+
+class Stretch : public RBEffect {
+ public:
+ Stretch (ARDOUR::Session&, TimeFXRequest&);
+ ~Stretch() {}
};
+} /* namespace */
+
+#else
+
+#include <soundtouch/SoundTouch.h>
+
+namespace ARDOUR {
+
class Stretch : public AudioFilter {
public:
- Stretch (ARDOUR::Session&, TimeStretchRequest&);
+ Stretch (ARDOUR::Session&, TimeFXRequest&);
~Stretch ();
int run (boost::shared_ptr<ARDOUR::AudioRegion>);
private:
- TimeStretchRequest& tsr;
+ TimeFXRequest& tsr;
-#ifndef USE_RUBBERBAND
soundtouch::SoundTouch st;
-#endif
-
};
} /* namespace */
+#endif
+
#endif /* __ardour_stretch_h__ */
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index a8c6414798..2426b223dc 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -369,6 +369,13 @@ namespace ARDOUR {
SrcFastest
};
+ struct TimeFXRequest : public InterThreadInfo {
+ float time_fraction;
+ float pitch_fraction;
+ bool quick_seek;
+ bool antialias;
+ };
+
} // namespace ARDOUR
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
diff --git a/libs/ardour/rb_pitch.cc b/libs/ardour/rb_effect.cc
index e3c90346b8..ccd8317c71 100644
--- a/libs/ardour/rb_pitch.cc
+++ b/libs/ardour/rb_effect.cc
@@ -24,6 +24,7 @@
#include <rubberband/RubberBandStretcher.h>
#include <ardour/types.h>
+#include <ardour/stretch.h>
#include <ardour/pitch.h>
#include <ardour/audiofilesource.h>
#include <ardour/session.h>
@@ -37,6 +38,16 @@ using namespace PBD;
using namespace RubberBand;
Pitch::Pitch (Session& s, TimeFXRequest& req)
+ : RBEffect (s, req)
+{
+}
+
+Stretch::Stretch (Session& s, TimeFXRequest& req)
+ : RBEffect (s, req)
+{
+}
+
+RBEffect::RBEffect (Session& s, TimeFXRequest& req)
: AudioFilter (s)
, tsr (req)
@@ -44,12 +55,12 @@ Pitch::Pitch (Session& s, TimeFXRequest& req)
tsr.progress = 0.0f;
}
-Pitch::~Pitch ()
+RBEffect::~RBEffect ()
{
}
int
-Pitch::run (boost::shared_ptr<AudioRegion> region)
+RBEffect::run (boost::shared_ptr<AudioRegion> region)
{
SourceList nsrcs;
nframes_t done;
@@ -63,12 +74,12 @@ Pitch::run (boost::shared_ptr<AudioRegion> region)
nframes_t pos = 0;
int avail = 0;
- RubberBandStretcher pitcher (session.frame_rate(), region->n_channels(),
- RubberBandStretcher::DefaultOptions,
- 1.0, tsr.fraction);
+ RubberBandStretcher stretcher (session.frame_rate(), region->n_channels(),
+ RubberBandStretcher::DefaultOptions,
+ tsr.time_fraction, tsr.pitch_fraction);
- pitcher.setExpectedInputDuration(region->length());
- pitcher.setDebugLevel(1);
+ stretcher.setExpectedInputDuration(region->length());
+ stretcher.setDebugLevel(1);
tsr.progress = 0.0f;
tsr.done = false;
@@ -77,10 +88,18 @@ Pitch::run (boost::shared_ptr<AudioRegion> region)
nframes_t duration = region->length();
/* the name doesn't need to be super-precise, but allow for 2 fractional
- digits just to disambiguate close but not identical stretches.
+ digits just to disambiguate close but not identical FX
*/
-
- snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.fraction * 100.0f));
+
+ if (tsr.time_fraction == 1.0) {
+ snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.pitch_fraction * 100.0f));
+ } else if (tsr.pitch_fraction == 1.0) {
+ snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.time_fraction * 100.0f));
+ } else {
+ snprintf (suffix, sizeof (suffix), "@%d-%d",
+ (int) floor (tsr.time_fraction * 100.0f),
+ (int) floor (tsr.pitch_fraction * 100.0f));
+ }
/* create new sources */
@@ -138,7 +157,7 @@ Pitch::run (boost::shared_ptr<AudioRegion> region)
tsr.progress = ((float) done / duration) * 0.75;
- pitcher.study(buffers, this_read, pos == duration);
+ stretcher.study(buffers, this_read, pos == duration);
}
done = 0;
@@ -176,15 +195,15 @@ Pitch::run (boost::shared_ptr<AudioRegion> region)
tsr.progress = 0.75 + ((float) done / duration) * 0.25;
- pitcher.process(buffers, this_read, pos == duration);
+ stretcher.process(buffers, this_read, pos == duration);
int avail = 0;
- while ((avail = pitcher.available()) > 0) {
+ while ((avail = stretcher.available()) > 0) {
this_read = min(bufsize, uint32_t(avail));
- pitcher.retrieve(buffers, this_read);
+ stretcher.retrieve(buffers, this_read);
for (uint32_t i = 0; i < nsrcs.size(); ++i) {
@@ -197,11 +216,11 @@ Pitch::run (boost::shared_ptr<AudioRegion> region)
}
}
- while ((avail = pitcher.available()) >= 0) {
+ while ((avail = stretcher.available()) >= 0) {
uint32_t this_read = min(bufsize, uint32_t(avail));
- pitcher.retrieve(buffers, this_read);
+ stretcher.retrieve(buffers, this_read);
for (uint32_t i = 0; i < nsrcs.size(); ++i) {
@@ -240,9 +259,17 @@ Pitch::run (boost::shared_ptr<AudioRegion> region)
nframes_t start;
nframes_t length;
- float shift = (*x)->shift() * (tsr.fraction/100.0);
+ // note: tsr.time_fraction is a percentage of original length. 100 = no change,
+ // 50 is half as long, 200 is twice as long, etc.
+
+
+ float stretch = (*x)->stretch() * (tsr.time_fraction/100.0);
+ float shift = (*x)->shift() * tsr.pitch_fraction;
+
+ start = (nframes_t) floor (astart + ((astart - (*x)->start()) / stretch));
+ length = (nframes_t) floor (alength / stretch);
- (*x)->set_ancestral_data ((*x)->ancestral_start(), (*x)->ancestral_length(), (*x)->stretch(), shift);
+ (*x)->set_ancestral_data (start, length, stretch, shift);
}
out:
@@ -268,3 +295,8 @@ Pitch::run (boost::shared_ptr<AudioRegion> region)
return ret;
}
+
+
+
+
+
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index e824eebaf0..8705228d1c 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -65,6 +65,7 @@ Region::Region (nframes_t start, nframes_t length, const string& name, layer_t l
_ancestral_start = start;
_ancestral_length = length;
_stretch = 1.0;
+ _shift = 1.0;
_last_position = 0;
_position = 0;
_layer = layer;
@@ -92,6 +93,7 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
_ancestral_start = other->_ancestral_start + offset;
_ancestral_length = length;
_stretch = 1.0;
+ _shift = 1.0;
_name = name;
_last_position = 0;
_position = 0;
@@ -125,6 +127,7 @@ Region::Region (boost::shared_ptr<const Region> other)
_ancestral_start = _start;
_ancestral_length = _length;
_stretch = 1.0;
+ _shift = 1.0;
_name = other->_name;
_last_position = other->_position;
_position = other->_position;
@@ -365,11 +368,12 @@ Region::nudge_position (nframes64_t n, void *src)
}
void
-Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st)
+Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
{
_ancestral_length = l;
_ancestral_start = s;
_stretch = st;
+ _shift = sh;
}
void
@@ -795,6 +799,8 @@ Region::state (bool full_state)
node->add_property ("ancestral-length", buf);
snprintf (buf, sizeof (buf), "%.12g", _stretch);
node->add_property ("stretch", buf);
+ snprintf (buf, sizeof (buf), "%.12g", _shift);
+ node->add_property ("shift", buf);
switch (_first_edit) {
case EditChangesNothing:
@@ -924,6 +930,12 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
_stretch = 1.0;
}
+ if ((prop = node.property ("shift")) != 0) {
+ _shift = atof (prop->value());
+ } else {
+ _shift = 1.0;
+ }
+
/* note: derived classes set flags */
if (_extra_xml) {
diff --git a/libs/ardour/st_pitch.cc b/libs/ardour/st_pitch.cc
new file mode 100644
index 0000000000..8626d0f619
--- /dev/null
+++ b/libs/ardour/st_pitch.cc
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2004-2007 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 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 <algorithm>
+#include <cmath>
+
+#include <pbd/error.h>
+
+#include <ardour/types.h>
+#include <ardour/pitch.h>
+#include <ardour/audiofilesource.h>
+#include <ardour/session.h>
+#include <ardour/audioregion.h>
+
+#include "i18n.h"
+
+using namespace std;
+using namespace ARDOUR;
+using namespace PBD;
+
+Pitch::Pitch (Session& s, TimeFXRequest& req)
+ : AudioFilter (s)
+ , tsr (req)
+
+{
+ tsr.progress = 0.0f;
+}
+
+Pitch::~Pitch ()
+{
+}
+
+int
+Pitch::run (boost::shared_ptr<AudioRegion> region)
+{
+ tsr.progress = 1.0f;
+ tsr.done = true;
+
+ return 1;
+}
diff --git a/libs/ardour/st_stretch.cc b/libs/ardour/st_stretch.cc
index 4cabfa79df..3c804e5549 100644
--- a/libs/ardour/st_stretch.cc
+++ b/libs/ardour/st_stretch.cc
@@ -35,7 +35,7 @@ using namespace ARDOUR;
using namespace PBD;
using namespace soundtouch;
-Stretch::Stretch (Session& s, TimeStretchRequest& req)
+Stretch::Stretch (Session& s, TimeFXRequest& req)
: AudioFilter (s)
, tsr (req)
{
@@ -45,7 +45,7 @@ Stretch::Stretch (Session& s, TimeStretchRequest& req)
of opposite sign to the length change.
*/
- percentage = -tsr.fraction;
+ percentage = -tsr.time_fraction;
st.setSampleRate (s.frame_rate());
st.setChannels (1);
@@ -185,7 +185,7 @@ Stretch::run (boost::shared_ptr<AudioRegion> region)
start = (nframes_t) floor (astart + ((astart - (*x)->start()) / stretch));
length = (nframes_t) floor (alength / stretch);
- (*x)->set_ancestral_data (start, length, stretch);
+ (*x)->set_ancestral_data (start, length, stretch, (*x)->shift());
}
out: