From 449aab3c465bbbf66d221fac3d7ea559f1720357 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 2 Jun 2008 21:41:35 +0000 Subject: rollback to 3428, before the mysterious removal of libs/* at 3431/3432 git-svn-id: svn://localhost/ardour2/branches/3.0@3435 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/rb_effect.cc | 298 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 libs/ardour/rb_effect.cc (limited to 'libs/ardour/rb_effect.cc') diff --git a/libs/ardour/rb_effect.cc b/libs/ardour/rb_effect.cc new file mode 100644 index 0000000000..4daf5cb33a --- /dev/null +++ b/libs/ardour/rb_effect.cc @@ -0,0 +1,298 @@ +/* + 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 +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "i18n.h" + +using namespace std; +using namespace ARDOUR; +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) + : Filter (s) + , tsr (req) + +{ + tsr.progress = 0.0f; +} + +RBEffect::~RBEffect () +{ +} + +int +RBEffect::run (boost::shared_ptr region) +{ + SourceList nsrcs; + nframes_t done; + int ret = -1; + const nframes_t bufsize = 256; + gain_t* gain_buffer = 0; + Sample** buffers = 0; + char suffix[32]; + string new_name; + string::size_type at; + nframes_t pos = 0; + int avail = 0; + + // note: this_time_fraction is a ratio of original length. 1.0 = no change, + // 0.5 is half as long, 2.0 is twice as long, etc. + + double this_time_fraction = tsr.time_fraction * region->stretch (); + double this_pitch_fraction = tsr.pitch_fraction * region->shift (); + + RubberBandStretcher stretcher (session.frame_rate(), region->n_channels(), + (RubberBandStretcher::Options) tsr.opts, + this_time_fraction, this_pitch_fraction); + + tsr.progress = 0.0f; + tsr.done = false; + + uint32_t channels = region->n_channels(); + nframes_t duration = region->ancestral_length(); + + stretcher.setExpectedInputDuration(duration); + stretcher.setDebugLevel(1); + + /* the name doesn't need to be super-precise, but allow for 2 fractional + digits just to disambiguate close but not identical FX + */ + + if (this_time_fraction == 1.0) { + snprintf (suffix, sizeof (suffix), "@%d", (int) floor (this_pitch_fraction * 100.0f)); + } else if (this_pitch_fraction == 1.0) { + snprintf (suffix, sizeof (suffix), "@%d", (int) floor (this_time_fraction * 100.0f)); + } else { + snprintf (suffix, sizeof (suffix), "@%d-%d", + (int) floor (this_time_fraction * 100.0f), + (int) floor (this_pitch_fraction * 100.0f)); + } + + /* create new sources */ + + if (make_new_sources (region, nsrcs, suffix)) { + goto out; + } + + gain_buffer = new gain_t[bufsize]; + buffers = new float *[channels]; + + for (uint32_t i = 0; i < channels; ++i) { + buffers[i] = new float[bufsize]; + } + + /* we read from the master (original) sources for the region, + not the ones currently in use, in case it's already been + subject to timefx. */ + + /* study first, process afterwards. */ + + pos = 0; + avail = 0; + done = 0; + + try { + while (pos < duration && !tsr.cancel) { + + nframes_t this_read = 0; + + for (uint32_t i = 0; i < channels; ++i) { + + this_read = 0; + nframes_t this_time; + + this_time = min(bufsize, duration - pos); + + this_read = region->master_read_at + (buffers[i], + buffers[i], + gain_buffer, + pos + region->position(), + this_time, + i); + + if (this_read != this_time) { + error << string_compose + (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"), + region->name(), pos + region->position(), this_time, this_read) << endmsg; + goto out; + } + } + + pos += this_read; + done += this_read; + + tsr.progress = ((float) done / duration) * 0.25; + + stretcher.study(buffers, this_read, pos == duration); + } + + done = 0; + pos = 0; + + while (pos < duration && !tsr.cancel) { + + nframes_t this_read = 0; + + for (uint32_t i = 0; i < channels; ++i) { + + this_read = 0; + nframes_t this_time; + + this_time = min(bufsize, duration - pos); + + this_read = region->master_read_at + (buffers[i], + buffers[i], + gain_buffer, + pos + region->position(), + this_time, + i); + + if (this_read != this_time) { + error << string_compose + (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"), + region->name(), pos + region->position(), this_time, this_read) << endmsg; + goto out; + } + } + + pos += this_read; + done += this_read; + + tsr.progress = 0.25 + ((float) done / duration) * 0.75; + + stretcher.process(buffers, this_read, pos == duration); + + int avail = 0; + + while ((avail = stretcher.available()) > 0) { + + this_read = min(bufsize, uint32_t(avail)); + + stretcher.retrieve(buffers, this_read); + + for (uint32_t i = 0; i < nsrcs.size(); ++i) { + + if (nsrcs[i]->write(buffers[i], this_read) != + this_read) { + error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg; + goto out; + } + } + } + } + + while ((avail = stretcher.available()) >= 0) { + + uint32_t this_read = min(bufsize, uint32_t(avail)); + + stretcher.retrieve(buffers, this_read); + + for (uint32_t i = 0; i < nsrcs.size(); ++i) { + + if (nsrcs[i]->write(buffers[i], 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 >::iterator x = results.begin(); x != results.end(); ++x) { + + (*x)->set_ancestral_data (region->ancestral_start(), + region->ancestral_length(), + this_time_fraction, + this_pitch_fraction ); + (*x)->set_master_sources (region->get_master_sources()); + } + + out: + + if (gain_buffer) { + delete [] gain_buffer; + } + + if (buffers) { + for (uint32_t i = 0; i < channels; ++i) { + delete buffers[i]; + } + delete [] buffers; + } + + if (ret || tsr.cancel) { + for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) { + (*si)->mark_for_remove (); + } + } + + tsr.done = true; + + return ret; +} + + + + + -- cgit v1.2.3