summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2007-11-01 15:28:42 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2007-11-01 15:28:42 +0000
commitcb534fd536125fc0a1654f51d077424a58fda06e (patch)
treee745902b79e49b751cf3a738085b413e66a8208b
parent33cde64ba350219e5642dc0ad05d532e9fa51c83 (diff)
new ancestral data handling for regions; new Stretch AudioFilter replaces session member function; fix for "+" in XML node name; fix up async peak build flag in SourceFactory
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2583 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/ardour_ui.cc4
-rw-r--r--gtk2_ardour/ardour_ui_ed.cc3
-rw-r--r--gtk2_ardour/editor.h3
-rw-r--r--gtk2_ardour/editor_timefx.cc51
-rw-r--r--gtk2_ardour/route_time_axis.cc2
-rw-r--r--libs/ardour/SConscript2
-rw-r--r--libs/ardour/ardour/audiofilter.h4
-rw-r--r--libs/ardour/ardour/audioregion.h3
-rw-r--r--libs/ardour/ardour/region.h23
-rw-r--r--libs/ardour/ardour/session.h15
-rw-r--r--libs/ardour/ardour/stretch.h51
-rw-r--r--libs/ardour/audio_diskstream.cc2
-rw-r--r--libs/ardour/audiofilter.cc27
-rw-r--r--libs/ardour/audioregion.cc17
-rw-r--r--libs/ardour/region.cc43
-rw-r--r--libs/ardour/session.cc11
-rw-r--r--libs/ardour/session_state.cc30
-rw-r--r--libs/ardour/session_timefx.cc236
-rw-r--r--libs/ardour/source_factory.cc48
-rw-r--r--libs/ardour/stretch.cc210
20 files changed, 447 insertions, 338 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index 2eed08ab6f..4e40f2a907 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -3126,8 +3126,4 @@ ARDOUR_UI::setup_profile ()
}
}
-void
-ARDOUR_UI::audioengine_setup ()
-{
-}
diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc
index 4ee6ccc2fc..0143f3c60e 100644
--- a/gtk2_ardour/ardour_ui_ed.cc
+++ b/gtk2_ardour/ardour_ui_ed.cc
@@ -159,9 +159,6 @@ ARDOUR_UI::install_actions ()
ActionManager::register_action (jack_actions, X_("JACK"), _("JACK"));
ActionManager::register_action (jack_actions, X_("Latency"), _("Latency"));
- /* not sensitive to the presence or absence of JACK */
- act = ActionManager::register_action (jack_actions, X_("AudioEngineSetup"), _("Setup"), mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::audioengine_setup));
-
act = ActionManager::register_action (jack_actions, X_("JACKReconnect"), _("Reconnect"), mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::reconnect_to_jack));
ActionManager::jack_opposite_sensitive_actions.push_back (act);
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 4cfb1b0fda..4dba9d3fb4 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -45,6 +45,7 @@
#include <pbd/stateful.h>
#include <ardour/session.h>
+#include <ardour/stretch.h>
#include <ardour/tempo.h>
#include <ardour/location.h>
#include <ardour/audioregion.h>
@@ -1744,7 +1745,7 @@ class Editor : public PublicEditor
void end_time_fx (ArdourCanvas::Item*, GdkEvent*);
struct TimeStretchDialog : public ArdourDialog {
- ARDOUR::Session::TimeStretchRequest request;
+ ARDOUR::TimeStretchRequest request;
Editor& editor;
RegionSelection regions;
Gtk::ProgressBar progress_bar;
diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc
index 2efdc03f8f..df0a73c965 100644
--- a/gtk2_ardour/editor_timefx.cc
+++ b/gtk2_ardour/editor_timefx.cc
@@ -39,6 +39,7 @@
#include <ardour/audio_track.h>
#include <ardour/audioregion.h>
#include <ardour/audio_diskstream.h>
+#include <ardour/stretch.h>
#include "i18n.h"
@@ -87,29 +88,29 @@ gint
Editor::TimeStretchDialog::update_progress ()
{
progress_bar.set_fraction (request.progress);
- return request.running;
+ return !request.done;
}
void
Editor::TimeStretchDialog::cancel_timestretch_in_progress ()
{
status = -2;
- request.running = false;
+ request.cancel = true;
+ first_cancel.disconnect();
}
gint
Editor::TimeStretchDialog::delete_timestretch_in_progress (GdkEventAny* ev)
{
status = -2;
- request.running = false;
+ request.cancel = true;
+ first_delete.disconnect();
return TRUE;
}
int
Editor::run_timestretch (RegionSelection& regions, float fraction)
{
- pthread_t thread;
-
if (current_timestretch == 0) {
current_timestretch = new TimeStretchDialog (*this);
}
@@ -130,27 +131,30 @@ Editor::run_timestretch (RegionSelection& regions, float 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.running = true;
+ current_timestretch->request.done = false;
+ current_timestretch->request.cancel = false;
/* re-connect the cancel button and delete events */
current_timestretch->first_cancel.disconnect();
current_timestretch->first_delete.disconnect();
- current_timestretch->cancel_button->signal_clicked().connect (mem_fun (current_timestretch, &TimeStretchDialog::cancel_timestretch_in_progress));
- current_timestretch->signal_delete_event().connect (mem_fun (current_timestretch, &TimeStretchDialog::delete_timestretch_in_progress));
+ 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", &thread, 0, timestretch_thread, current_timestretch)) {
+ 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;
return -1;
}
- pthread_detach (thread);
+ pthread_detach (current_timestretch->request.thread);
sigc::connection c = Glib::signal_timeout().connect (mem_fun (current_timestretch, &TimeStretchDialog::update_progress), 100);
- while (current_timestretch->request.running) {
+ while (!current_timestretch->request.done) {
gtk_main_iteration ();
}
@@ -195,31 +199,34 @@ Editor::do_timestretch (TimeStretchDialog& dialog)
continue;
}
- dialog.request.region = region;
-
- if (!dialog.request.running) {
+ if (dialog.request.cancel) {
/* we were cancelled */
dialog.status = 1;
return;
}
- if ((new_region = session->tempoize_region (dialog.request)) == 0) {
+ Stretch stretch (*session, dialog.request);
+
+ if (stretch.run (region)) {
dialog.status = -1;
- dialog.request.running = false;
+ dialog.request.done = true;
return;
}
- XMLNode &before = playlist->get_state();
- playlist->replace_region (region, new_region, region->position());
- XMLNode &after = playlist->get_state();
- session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
+ if (!stretch.results.empty()) {
+ new_region = stretch.results.front();
+
+ XMLNode &before = playlist->get_state();
+ playlist->replace_region (region, new_region, region->position());
+ XMLNode &after = playlist->get_state();
+ session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
+ }
i = tmp;
}
dialog.status = 0;
- dialog.request.running = false;
- dialog.request.region.reset ();
+ dialog.request.done = true;
}
void*
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 93419b813c..13fa435b16 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -1490,7 +1490,7 @@ static string
legalize_for_xml_node (string str)
{
string::size_type pos;
- string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:";
+ string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:";
string legal;
legal = str;
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index dfa7396bcc..224fcc8656 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -86,13 +86,13 @@ session_midi.cc
session_process.cc
session_state.cc
session_time.cc
-session_timefx.cc
session_transport.cc
silentfilesource.cc
sndfile_helpers.cc
sndfilesource.cc
source.cc
source_factory.cc
+stretch.cc
tempo.cc
utils.cc
version.cc
diff --git a/libs/ardour/ardour/audiofilter.h b/libs/ardour/ardour/audiofilter.h
index 6b60544942..18751a2bde 100644
--- a/libs/ardour/ardour/audiofilter.h
+++ b/libs/ardour/ardour/audiofilter.h
@@ -41,8 +41,8 @@ class AudioFilter {
protected:
ARDOUR::Session& session;
- int make_new_sources (boost::shared_ptr<ARDOUR::AudioRegion>, ARDOUR::SourceList&);
- int finish (boost::shared_ptr<ARDOUR::AudioRegion>, ARDOUR::SourceList&);
+ int make_new_sources (boost::shared_ptr<ARDOUR::AudioRegion>, ARDOUR::SourceList&, std::string suffix = "");
+ int finish (boost::shared_ptr<ARDOUR::AudioRegion>, ARDOUR::SourceList&, std::string region_name = "");
};
} /* namespace */
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index a450d90008..ff32199771 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -67,7 +67,8 @@ class AudioRegion : public Region
uint32_t n_channels() const { return sources.size(); }
vector<string> master_source_names();
-
+ void set_master_sources (SourceList&);
+
bool envelope_active () const { return _flags & Region::EnvelopeActive; }
bool fade_in_active () const { return _flags & Region::FadeIn; }
bool fade_out_active () const { return _flags & Region::FadeOut; }
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 0002356f41..16242a2f42 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -88,8 +88,14 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
nframes_t position () const { return _position; }
nframes_t start () const { return _start; }
nframes_t length() const { return _length; }
- layer_t layer () const { return _layer; }
-
+ layer_t layer () const { return _layer; }
+
+ nframes64_t ancestral_start () const { return _ancestral_start; }
+ nframes64_t ancestral_length () const { return _ancestral_length; }
+ float stretch() const { return _stretch; }
+
+ void set_ancestral_data (nframes64_t start, nframes64_t length, float stretch);
+
nframes_t sync_offset(int& dir) const;
nframes_t sync_position() const;
@@ -205,11 +211,11 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
virtual void recompute_at_end () = 0;
- nframes_t _start;
- nframes_t _length;
- nframes_t _position;
- Flag _flags;
- nframes_t _sync_position;
+ nframes_t _start;
+ nframes_t _length;
+ nframes_t _position;
+ Flag _flags;
+ nframes_t _sync_position;
layer_t _layer;
string _name;
mutable RegionEditState _first_edit;
@@ -219,6 +225,9 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
mutable uint32_t _read_data_count; // modified in read()
Change pending_changed;
uint64_t _last_layer_op; // timestamp
+ nframes64_t _ancestral_start;
+ nframes64_t _ancestral_length;
+ float _stretch;
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 0097080c9d..b1a1254009 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -845,21 +845,6 @@ class Session : public PBD::StatefulDestructible
boost::shared_ptr<IO> click_io() { return _click_io; }
- /* tempo FX */
-
- struct TimeStretchRequest {
- boost::shared_ptr<ARDOUR::AudioRegion> region;
- float fraction; /* session: read ; GUI: write */
- float progress; /* session: write ; GUI: read */
- bool running; /* read/write */
- bool quick_seek; /* GUI: write */
- bool antialias; /* GUI: write */
-
- TimeStretchRequest () {}
- };
-
- boost::shared_ptr<AudioRegion> tempoize_region (TimeStretchRequest&);
-
/* disk, buffer loads */
uint32_t playback_load ();
diff --git a/libs/ardour/ardour/stretch.h b/libs/ardour/ardour/stretch.h
new file mode 100644
index 0000000000..02cc930ee5
--- /dev/null
+++ b/libs/ardour/ardour/stretch.h
@@ -0,0 +1,51 @@
+/*
+ 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_stretch_h__
+#define __ardour_stretch_h__
+
+#include <ardour/audiofilter.h>
+#include <soundtouch/SoundTouch.h>
+
+namespace ARDOUR {
+
+class AudioRegion;
+
+struct TimeStretchRequest : public InterThreadInfo {
+ float fraction;
+ bool quick_seek;
+ bool antialias;
+};
+
+class Stretch : public AudioFilter {
+ public:
+ Stretch (ARDOUR::Session&, TimeStretchRequest&);
+ ~Stretch ();
+
+ int run (boost::shared_ptr<ARDOUR::AudioRegion>);
+
+ private:
+ TimeStretchRequest& tsr;
+ soundtouch::SoundTouch st;
+
+};
+
+} /* namespace */
+
+#endif /* __ardour_stretch_h__ */
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index f7e982b502..6642cee369 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -792,7 +792,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
chaninfo->current_playback_buffer = chaninfo->speed_buffer;
}
- playback_distance = i;
+ playback_distance = i; // + 1;
last_phase = (phase & 0xFFFFFF);
} else {
diff --git a/libs/ardour/audiofilter.cc b/libs/ardour/audiofilter.cc
index fb4e5af1ae..ee38bff89c 100644
--- a/libs/ardour/audiofilter.cc
+++ b/libs/ardour/audiofilter.cc
@@ -34,13 +34,26 @@ using namespace ARDOUR;
using namespace PBD;
int
-AudioFilter::make_new_sources (boost::shared_ptr<AudioRegion> region, SourceList& nsrcs)
+AudioFilter::make_new_sources (boost::shared_ptr<AudioRegion> region, SourceList& nsrcs, string suffix)
{
vector<string> names = region->master_source_names();
for (uint32_t i = 0; i < region->n_channels(); ++i) {
- string path = session.path_from_region_name (PBD::basename_nosuffix (names[i]), string (""));
+ string name = PBD::basename_nosuffix (names[i]);
+
+ /* remove any existing version of suffix by assuming it starts
+ with some kind of "special" character.
+ */
+
+ if (!suffix.empty()) {
+ string::size_type pos = name.find (suffix[0]);
+ if (pos != string::npos && pos > 2) {
+ name = name.substr (0, pos - 1);
+ }
+ }
+
+ string path = session.path_from_region_name (name, suffix);
if (path.length() == 0) {
error << string_compose (_("audiofilter: error creating name for new audio file based on %1"), region->name())
@@ -63,10 +76,8 @@ AudioFilter::make_new_sources (boost::shared_ptr<AudioRegion> region, SourceList
}
int
-AudioFilter::finish (boost::shared_ptr<AudioRegion> region, SourceList& nsrcs)
+AudioFilter::finish (boost::shared_ptr<AudioRegion> region, SourceList& nsrcs, string region_name)
{
- string region_name;
-
/* update headers on new sources */
time_t xnow;
@@ -91,9 +102,11 @@ AudioFilter::finish (boost::shared_ptr<AudioRegion> region, SourceList& nsrcs)
/* create a new region */
- region_name = session.new_region_name (region->name());
+ if (region_name.empty()) {
+ region_name = session.new_region_name (region->name());
+ }
results.clear ();
- results.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (nsrcs, 0, region->length(), region_name, 0,
+ results.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (nsrcs, 0, nsrcs.front()->length(), region_name, 0,
Region::Flag (Region::WholeFile|Region::DefaultFlags))));
return 0;
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 0a141ee3fa..4a82303cdb 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -32,6 +32,7 @@
#include <pbd/xml++.h>
#include <pbd/stacktrace.h>
#include <pbd/enumwriter.h>
+#include <pbd/convert.h>
#include <ardour/audioregion.h>
#include <ardour/session.h>
@@ -47,6 +48,7 @@
using namespace std;
using namespace ARDOUR;
+using namespace PBD;
/* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
@@ -92,7 +94,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
/* basic AudioRegion constructor */
sources.push_back (src);
- master_sources.push_back (src);
+ master_sources.push_back (src);
src->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
@@ -167,6 +169,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
(*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
}
master_sources.push_back (*i);
+
}
/* return to default fades if the existing ones are too long */
@@ -678,6 +681,12 @@ AudioRegion::state (bool full)
child->add_property ("default", "yes");
}
+ for (uint32_t n=0; n < master_sources.size(); ++n) {
+ snprintf (buf2, sizeof(buf2), "master-source-%d", n);
+ master_sources[n]->id().print (buf, sizeof (buf));
+ node.add_property (buf2, buf);
+ }
+
if (full && _extra_xml) {
node.add_child_copy (*_extra_xml);
}
@@ -1113,6 +1122,12 @@ AudioRegion::master_source_names ()
return names;
}
+void
+AudioRegion::set_master_sources (SourceList& srcs)
+{
+ master_sources = srcs;
+}
+
bool
AudioRegion::source_equivalent (boost::shared_ptr<const Region> o) const
{
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 7e131eab51..cd91772a3b 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -61,6 +61,9 @@ Region::Region (nframes_t start, nframes_t length, const string& name, layer_t l
_start = start;
_sync_position = _start;
_length = length;
+ _ancestral_start = start;
+ _ancestral_length = length;
+ _stretch = 1.0;
_position = 0;
_layer = layer;
_read_data_count = 0;
@@ -83,6 +86,9 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
_sync_position = _start;
}
_length = length;
+ _ancestral_start = other->_ancestral_start + offset;
+ _ancestral_length = length;
+ _stretch = 1.0;
_name = name;
_position = 0;
_layer = layer;
@@ -111,6 +117,9 @@ Region::Region (boost::shared_ptr<const Region> other)
_start = other->_start;
_sync_position = other->_sync_position;
_length = other->_length;
+ _ancestral_start = _start;
+ _ancestral_length = _length;
+ _stretch = 1.0;
_name = other->_name;
_position = other->_position;
_layer = other->_layer;
@@ -340,6 +349,14 @@ Region::nudge_position (long n, void *src)
}
void
+Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st)
+{
+ _ancestral_length = l;
+ _ancestral_start = s;
+ _stretch = st;
+}
+
+void
Region::set_start (nframes_t pos, void *src)
{
if (_flags & Locked) {
@@ -748,6 +765,12 @@ Region::state (bool full_state)
node->add_property ("length", buf);
snprintf (buf, sizeof (buf), "%u", _position);
node->add_property ("position", buf);
+ snprintf (buf, sizeof (buf), "%lu", _ancestral_start);
+ node->add_property ("ancestral-start", buf);
+ snprintf (buf, sizeof (buf), "%lu", _ancestral_length);
+ node->add_property ("ancestral-length", buf);
+ snprintf (buf, sizeof (buf), "%.12g", _stretch);
+ node->add_property ("stretch", buf);
switch (_first_edit) {
case EditChangesNothing:
@@ -854,6 +877,26 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
/* XXX FIRST EDIT !!! */
+ /* these 3 properties never change as a result of any editing */
+
+ if ((prop = node.property ("ancestral-start")) != 0) {
+ _ancestral_start = atoi (prop->value());
+ } else {
+ _ancestral_start = _start;
+ }
+
+ if ((prop = node.property ("ancestral-length")) != 0) {
+ _ancestral_length = atoi (prop->value());
+ } else {
+ _ancestral_length = _length;
+ }
+
+ if ((prop = node.property ("stretch")) != 0) {
+ _stretch = atof (prop->value());
+ } else {
+ _stretch = 1.0;
+ }
+
/* note: derived classes set flags */
if (_extra_xml) {
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 2ecf3ccae7..1dc682d4e9 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -2097,14 +2097,14 @@ Session::remove_route (shared_ptr<Route> route)
find_current_end ();
- update_latency_compensation (false, false);
- set_dirty();
-
// We need to disconnect the routes inputs and outputs
route->disconnect_inputs (0);
route->disconnect_outputs (0);
+ update_latency_compensation (false, false);
+ set_dirty();
+
/* get rid of it from the dead wood collection in the route list manager */
/* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
@@ -2113,8 +2113,13 @@ Session::remove_route (shared_ptr<Route> route)
/* try to cause everyone to drop their references */
+ cerr << "pre drop, Route now has " << route.use_count() << " refs\n";
+ cerr << "sig has " << route->GoingAway.size() << endl;
+
route->drop_references ();
+ cerr << "route dangling refs = " << route.use_count() << endl;
+
/* save the new state of the world */
if (save_state (_current_snapshot_name)) {
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index f704bbad5f..e1afae1443 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -1398,6 +1398,7 @@ Session::XMLRegionFactory (const XMLNode& node, bool full)
boost::shared_ptr<Source> source;
boost::shared_ptr<AudioSource> as;
SourceList sources;
+ SourceList master_sources;
uint32_t nchans = 1;
char buf[128];
@@ -1458,7 +1459,27 @@ Session::XMLRegionFactory (const XMLNode& node, bool full)
sources.push_back (as);
}
}
-
+
+ for (uint32_t n=1; n < nchans; ++n) {
+ snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
+ if ((prop = node.property (buf)) != 0) {
+
+ PBD::ID id2 (prop->value());
+
+ if ((source = source_by_id (id2)) == 0) {
+ error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
+ return boost::shared_ptr<AudioRegion>();
+ }
+
+ as = boost::dynamic_pointer_cast<AudioSource>(source);
+ if (!as) {
+ error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
+ return boost::shared_ptr<AudioRegion>();
+ }
+ master_sources.push_back (as);
+ }
+ }
+
try {
boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
@@ -1473,6 +1494,13 @@ Session::XMLRegionFactory (const XMLNode& node, bool full)
}
}
+ if (!master_sources.empty()) {
+ if (master_sources.size() == nchans) {
+ error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
+ } else {
+ region->set_master_sources (master_sources);
+ }
+ }
return region;
diff --git a/libs/ardour/session_timefx.cc b/libs/ardour/session_timefx.cc
deleted file mode 100644
index e2cd6f6543..0000000000
--- a/libs/ardour/session_timefx.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- Copyright (C) 2003 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 <cerrno>
-#include <stdexcept>
-
-#include <pbd/basename.h>
-
-#include <soundtouch/SoundTouch.h>
-
-#include <ardour/session.h>
-#include <ardour/audioregion.h>
-#include <ardour/sndfilesource.h>
-#include <ardour/region_factory.h>
-#include <ardour/source_factory.h>
-
-#include "i18n.h"
-
-using namespace std;
-using namespace ARDOUR;
-using namespace PBD;
-using namespace soundtouch;
-
-boost::shared_ptr<AudioRegion>
-Session::tempoize_region (TimeStretchRequest& tsr)
-{
- SourceList sources;
- SourceList::iterator it;
- boost::shared_ptr<AudioRegion> r;
- SoundTouch st;
- string region_name;
- string ident = X_("-TIMEFX-");
- float percentage;
- nframes_t total_frames;
- nframes_t done;
- int c;
- char buf[64];
- string::size_type len;
-
- /* the soundtouch code wants a *tempo* change percentage, which is
- of opposite sign to the length change.
- */
-
- percentage = -tsr.fraction;
-
- st.setSampleRate (frame_rate());
- st.setChannels (1);
- st.setTempoChange (percentage);
- st.setPitchSemiTones (0);
- st.setRateChange (0);
-
- st.setSetting(SETTING_USE_QUICKSEEK, tsr.quick_seek);
- st.setSetting(SETTING_USE_AA_FILTER, tsr.antialias);
-
- vector<string> names = tsr.region->master_source_names();
-
- tsr.progress = 0.0f;
- total_frames = tsr.region->length() * tsr.region->n_channels();
- done = 0;
-
- for (uint32_t i = 0; i < tsr.region->n_channels(); ++i) {
-
- string rstr;
- string::size_type existing_ident;
-
- if ((existing_ident = names[i].find (ident)) != string::npos) {
- rstr = names[i].substr (0, existing_ident);
- } else {
- rstr = names[i];
- }
-
- string path = path_from_region_name (PBD::basename_nosuffix (rstr), ident);
-
- if (path.length() == 0) {
- error << string_compose (_("tempoize: error creating name for new audio file based on %1"), tsr.region->name())
- << endmsg;
- goto out;
- }
-
- try {
- sources.push_back (boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (*this, path, false, frame_rate())));
- sources.back()->prepare_for_peakfile_writes ();
-
- } catch (failed_constructor& err) {
- error << string_compose (_("tempoize: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg;
- goto out;
- }
- }
-
- try {
- const nframes_t bufsize = 16384;
-
- for (uint32_t i = 0; i < sources.size(); ++i) {
- gain_t gain_buffer[bufsize];
- Sample buffer[bufsize];
- nframes_t pos = 0;
- nframes_t this_read = 0;
-
- st.clear();
- while (tsr.running && pos < tsr.region->length()) {
- nframes_t this_time;
-
- this_time = min (bufsize, tsr.region->length() - pos);
-
- /* read from the master (original) sources for the region,
- not the ones currently in use, in case it's already been
- subject to timefx. */
-
- if ((this_read = tsr.region->master_read_at (buffer, buffer, gain_buffer, pos + tsr.region->position(), this_time)) != this_time) {
- error << string_compose (_("tempoize: error reading data from %1"), sources[i]->name()) << endmsg;
- goto out;
- }
-
- pos += this_read;
- done += this_read;
-
- tsr.progress = (float) done / total_frames;
-
- st.putSamples (buffer, this_read);
-
- while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && tsr.running) {
- if (sources[i]->write (buffer, this_read) != this_read) {
- error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
- goto out;
- }
- }
- }
-
- if (tsr.running) {
- st.flush ();
- }
-
- while (tsr.running && (this_read = st.receiveSamples (buffer, bufsize)) > 0) {
- if (sources[i]->write (buffer, this_read) != this_read) {
- error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
- goto out;
- }
- }
- }
- } catch (runtime_error& err) {
- error << _("timefx code failure. please notify ardour-developers.") << endmsg;
- error << err.what() << endmsg;
- goto out;
- }
-
- time_t now;
- struct tm* xnow;
- time (&now);
- xnow = localtime (&now);
-
- for (it = sources.begin(); it != sources.end(); ++it) {
- boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*it);
- boost::shared_ptr<AudioSource> as = boost::dynamic_pointer_cast<AudioSource>(*it);
-
- if (as) {
- as->done_with_peakfile_writes ();
- }
-
- if (afs) {
- afs->update_header (tsr.region->position(), *xnow, now);
- }
- }
-
- len = tsr.region->name().length();
-
- while (--len) {
- if (!isdigit (tsr.region->name()[len])) {
- break;
- }
- }
-
- if (len == 0) {
-
- region_name = tsr.region->name() + ".t000";
-
- } else {
-
- if (tsr.region->name()[len] == 't') {
- c = atoi (tsr.region->name().substr(len+1));
-
- snprintf (buf, sizeof (buf), "t%03d", ++c);
- region_name = tsr.region->name().substr (0, len) + buf;
-
- } else {
-
- /* not sure what this is, just tack the suffix on to it */
-
- region_name = tsr.region->name() + ".t000";
- }
-
- }
-
- r = (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, 0, sources.front()->length(), region_name,
- 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile))));
-
- out:
-
- if (sources.size()) {
-
- /* if we failed to complete for any reason, mark the new file
- for deletion.
- */
-
- if ((!r || !tsr.running)) {
- for (it = sources.begin(); it != sources.end(); ++it) {
- (*it)->mark_for_remove ();
- }
- }
-
- sources.clear ();
- }
-
- /* if the process was cancelled, delete the region */
-
- if (!tsr.running) {
- r.reset ();
- }
-
- return r;
-}
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index ddd2f8e95e..cee0173387 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -126,10 +126,8 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
{
try {
boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
- if (!defer_peaks) {
- if (setup_peakfile (ret, false)) {
- return boost::shared_ptr<Source>();
- }
+ if (setup_peakfile (ret, defer_peaks)) {
+ return boost::shared_ptr<Source>();
}
SourceCreated (ret);
return ret;
@@ -141,10 +139,8 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
/* this is allowed to throw */
boost::shared_ptr<Source> ret (new SndFileSource (s, node));
- if (!defer_peaks) {
- if (setup_peakfile (ret, false)) {
- return boost::shared_ptr<Source>();
- }
+ if (setup_peakfile (ret, defer_peaks)) {
+ return boost::shared_ptr<Source>();
}
SourceCreated (ret);
return ret;
@@ -162,10 +158,8 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
boost::shared_ptr<Source> ret (new SndFileSource (s, node));
- if (!defer_peaks) {
- if (setup_peakfile (ret, false)) {
- return boost::shared_ptr<Source>();
- }
+ if (setup_peakfile (ret, defer_peaks)) {
+ return boost::shared_ptr<Source>();
}
SourceCreated (ret);
@@ -182,10 +176,8 @@ SourceFactory::createReadable (Session& s, string path, int chn, AudioFileSource
try {
boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags));
- if (!defer_peaks) {
- if (setup_peakfile (ret, false)) {
- return boost::shared_ptr<Source>();
- }
+ if (setup_peakfile (ret, defer_peaks)) {
+ return boost::shared_ptr<Source>();
}
if (announce) {
SourceCreated (ret);
@@ -198,10 +190,8 @@ SourceFactory::createReadable (Session& s, string path, int chn, AudioFileSource
/* this is allowed to throw */
boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
- if (!defer_peaks) {
- if (setup_peakfile (ret, false)) {
- return boost::shared_ptr<Source>();
- }
+ if (setup_peakfile (ret, defer_peaks)) {
+ return boost::shared_ptr<Source>();
}
if (announce) {
SourceCreated (ret);
@@ -212,10 +202,8 @@ SourceFactory::createReadable (Session& s, string path, int chn, AudioFileSource
} else {
boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
- if (!defer_peaks) {
- if (setup_peakfile (ret, false)) {
- return boost::shared_ptr<Source>();
- }
+ if (setup_peakfile (ret, defer_peaks)) {
+ return boost::shared_ptr<Source>();
}
if (announce) {
SourceCreated (ret);
@@ -233,10 +221,8 @@ SourceFactory::createReadable (Session& s, string path, int chn, AudioFileSource
{
boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
- if (!defer_peaks) {
- if (setup_peakfile (ret, false)) {
- return boost::shared_ptr<Source>();
- }
+ if (setup_peakfile (ret, defer_peaks)) {
+ return boost::shared_ptr<Source>();
}
if (announce) {
@@ -261,10 +247,8 @@ SourceFactory::createWritable (Session& s, std::string path, bool destructive, n
(destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) :
SndFileSource::default_writable_flags)));
- if (!defer_peaks) {
- if (setup_peakfile (ret, false)) {
- return boost::shared_ptr<Source>();
- }
+ if (setup_peakfile (ret, defer_peaks)) {
+ return boost::shared_ptr<Source>();
}
if (announce) {
diff --git a/libs/ardour/stretch.cc b/libs/ardour/stretch.cc
new file mode 100644
index 0000000000..4cabfa79df
--- /dev/null
+++ b/libs/ardour/stretch.cc
@@ -0,0 +1,210 @@
+/*
+ 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/stretch.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;
+using namespace soundtouch;
+
+Stretch::Stretch (Session& s, TimeStretchRequest& req)
+ : AudioFilter (s)
+ , tsr (req)
+{
+ float percentage;
+
+ /* the soundtouch code wants a *tempo* change percentage, which is
+ of opposite sign to the length change.
+ */
+
+ percentage = -tsr.fraction;
+
+ st.setSampleRate (s.frame_rate());
+ st.setChannels (1);
+ st.setTempoChange (percentage);
+ st.setPitchSemiTones (0);
+ st.setRateChange (0);
+
+ st.setSetting(SETTING_USE_QUICKSEEK, tsr.quick_seek);
+ st.setSetting(SETTING_USE_AA_FILTER, tsr.antialias);
+
+ tsr.progress = 0.0f;
+}
+
+Stretch::~Stretch ()
+{
+}
+
+int
+Stretch::run (boost::shared_ptr<AudioRegion> region)
+{
+ SourceList nsrcs;
+ nframes_t total_frames;
+ nframes_t done;
+ int ret = -1;
+ const nframes_t bufsize = 16384;
+ gain_t *gain_buffer = 0;
+ Sample *buffer = 0;
+ char suffix[32];
+ string new_name;
+ string::size_type at;
+
+ tsr.progress = 0.0f;
+ tsr.done = false;
+
+ total_frames = region->length() * region->n_channels();
+ done = 0;
+
+ /* the name doesn't need to be super-precise, but allow for 2 fractional
+ digits just to disambiguate close but not identical stretches.
+ */
+
+ snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.fraction * 100.0f));
+
+ /* create new sources */
+
+ if (make_new_sources (region, nsrcs, suffix)) {
+ goto out;
+ }
+
+ gain_buffer = new gain_t[bufsize];
+ buffer = new Sample[bufsize];
+
+ // soundtouch throws runtime_error on error
+
+ try {
+ for (uint32_t i = 0; i < nsrcs.size(); ++i) {
+
+ nframes_t pos = 0;
+ nframes_t this_read = 0;
+
+ st.clear();
+
+ while (!tsr.cancel && pos < region->length()) {
+ nframes_t this_time;
+
+ this_time = min (bufsize, region->length() - pos);
+
+ /* read from the master (original) sources for the region,
+ not the ones currently in use, in case it's already been
+ subject to timefx.
+ */
+
+ if ((this_read = region->master_read_at (buffer, buffer, gain_buffer, pos + region->position(), this_time)) != this_time) {
+ error << string_compose (_("tempoize: error reading data from %1"), nsrcs[i]->name()) << endmsg;
+ goto out;
+ }
+
+ pos += this_read;
+ done += this_read;
+
+ tsr.progress = (float) done / total_frames;
+
+ st.putSamples (buffer, this_read);
+
+ while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && !tsr.cancel) {
+ if (nsrcs[i]->write (buffer, this_read) != this_read) {
+ error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
+ goto out;
+ }
+ }
+ }
+
+ if (!tsr.cancel) {
+ st.flush ();
+ }
+
+ while (!tsr.cancel && (this_read = st.receiveSamples (buffer, bufsize)) > 0) {
+ if (nsrcs[i]->write (buffer, this_read) != this_read) {
+ error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
+ goto out;
+ }
+ }
+ }
+
+ } catch (runtime_error& err) {
+ error << _("timefx code failure. please notify ardour-developers.") << endmsg;
+ error << err.what() << endmsg;
+ goto out;
+ }
+
+ new_name = region->name();
+ at = new_name.find ('@');
+
+ // remove any existing stretch indicator
+
+ if (at != string::npos && at > 2) {
+ new_name = new_name.substr (0, at - 1);
+ }
+
+ new_name += suffix;
+
+ ret = finish (region, nsrcs, new_name);
+
+ /* now reset ancestral data for each new region */
+
+ for (vector<boost::shared_ptr<AudioRegion> >::iterator x = results.begin(); x != results.end(); ++x) {
+ nframes64_t astart = (*x)->ancestral_start();
+ nframes64_t alength = (*x)->ancestral_length();
+ nframes_t start;
+ nframes_t length;
+
+ // note: tsr.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.fraction/100.0);
+
+ start = (nframes_t) floor (astart + ((astart - (*x)->start()) / stretch));
+ length = (nframes_t) floor (alength / stretch);
+
+ (*x)->set_ancestral_data (start, length, stretch);
+ }
+
+ out:
+
+ if (gain_buffer) {
+ delete [] gain_buffer;
+ }
+
+ if (buffer) {
+ delete [] buffer;
+ }
+
+ if (ret || tsr.cancel) {
+ for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
+ (*si)->mark_for_remove ();
+ }
+ }
+
+ tsr.done = true;
+
+ return ret;
+}