2 Copyright (C) 2004-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <rubberband/RubberBandStretcher.h>
25 #include "pbd/error.h"
27 #include "ardour/audioregion.h"
28 #include "ardour/audiosource.h"
29 #include "ardour/pitch.h"
30 #include "ardour/progress.h"
31 #include "ardour/session.h"
32 #include "ardour/stretch.h"
33 #include "ardour/types.h"
38 using namespace ARDOUR;
40 using namespace RubberBand;
42 Pitch::Pitch (Session& s, TimeFXRequest& req)
47 RBStretch::RBStretch (Session& s, TimeFXRequest& req)
52 RBEffect::RBEffect (Session& s, TimeFXRequest& req)
60 RBEffect::~RBEffect ()
65 RBEffect::run (boost::shared_ptr<Region> r, Progress* progress)
67 boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
70 error << "RBEffect::run() passed a non-audio region! WTF?" << endmsg;
76 const framecnt_t bufsize = 256;
77 gain_t* gain_buffer = 0;
82 boost::shared_ptr<AudioRegion> result;
84 cerr << "RBEffect: source region: position = " << region->position()
85 << ", start = " << region->start()
86 << ", length = " << region->length()
87 << ", ancestral_start = " << region->ancestral_start()
88 << ", ancestral_length = " << region->ancestral_length()
89 << ", stretch " << region->stretch()
90 << ", shift " << region->shift() << endl;
93 We have two cases to consider:
95 1. The region has not been stretched before.
97 In this case, we just want to read region->length() frames
100 We will create a new region of region->length() *
101 tsr.time_fraction frames. The new region will have its
102 start set to 0 (because it has a new audio file that begins
103 at the start of the stretched area) and its ancestral_start
104 set to region->start() (so that we know where to begin
105 reading if we want to stretch it again).
107 2. The region has been stretched before.
109 The region starts at region->start() frames into its
110 (possibly previously stretched) source file. But we don't
111 want to read from its source file; we want to read from the
112 file it was originally stretched from.
114 The region's source begins at region->ancestral_start()
115 frames into its master source file. Thus, we need to start
116 reading at region->ancestral_start() + (region->start() /
117 region->stretch()) frames into the master source. This
118 value will also become the ancestral_start for the new
121 We cannot use region->ancestral_length() to establish how
122 many frames to read, because it won't be up to date if the
123 region has been trimmed since it was last stretched. We
124 must read region->length() / region->stretch() frames and
125 stretch them by tsr.time_fraction * region->stretch(), for
126 a new region of region->length() * tsr.time_fraction
129 Case 1 is of course a special case of 2, where
130 region->ancestral_start() == 0 and region->stretch() == 1.
132 When we ask to read from a region, we supply a position on
133 the global timeline. The read function calculates the
134 offset into the source as (position - region->position()) +
135 region->start(). This calculation is used regardless of
136 whether we are reading from a master or
137 previously-stretched region. In order to read from a point
138 n frames into the master source, we need to provide n -
139 region->start() + region->position() as our position
140 argument to master_read_at().
142 Note that region->ancestral_length() is not used.
144 I hope this is clear.
147 double stretch = region->stretch() * tsr.time_fraction;
148 double shift = region->shift() * tsr.pitch_fraction;
150 framecnt_t read_start = region->ancestral_start() +
151 framecnt_t(region->start() / (double)region->stretch());
153 framecnt_t read_duration =
154 framecnt_t(region->length() / (double)region->stretch());
156 uint32_t channels = region->n_channels();
158 RubberBandStretcher stretcher
159 (session.frame_rate(), channels,
160 (RubberBandStretcher::Options) tsr.opts, stretch, shift);
162 progress->set_progress (0);
165 stretcher.setExpectedInputDuration(read_duration);
166 stretcher.setDebugLevel(1);
168 /* the name doesn't need to be super-precise, but allow for 2 fractional
169 digits just to disambiguate close but not identical FX
172 if (stretch == 1.0) {
173 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (shift * 100.0f));
174 } else if (shift == 1.0) {
175 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (stretch * 100.0f));
177 snprintf (suffix, sizeof (suffix), "@%d-%d",
178 (int) floor (stretch * 100.0f),
179 (int) floor (shift * 100.0f));
182 /* create new sources */
185 framecnt_t avail = 0;
188 if (make_new_sources (region, nsrcs, suffix)) {
192 gain_buffer = new gain_t[bufsize];
193 buffers = new float *[channels];
195 for (uint32_t i = 0; i < channels; ++i) {
196 buffers[i] = new float[bufsize];
199 /* we read from the master (original) sources for the region,
200 not the ones currently in use, in case it's already been
201 subject to timefx. */
203 /* study first, process afterwards. */
206 while (pos < read_duration && !tsr.cancel) {
208 framecnt_t this_read = 0;
210 for (uint32_t i = 0; i < channels; ++i) {
212 framepos_t this_time;
213 this_time = min(bufsize, read_duration - pos);
215 framepos_t this_position;
216 this_position = read_start + pos -
217 region->start() + region->position();
219 this_read = region->master_read_at
227 if (this_read != this_time) {
228 error << string_compose
229 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
230 region->name(), this_position, this_time, this_read) << endmsg;
238 progress->set_progress (((float) done / read_duration) * 0.25);
240 stretcher.study(buffers, this_read, pos == read_duration);
246 while (pos < read_duration && !tsr.cancel) {
248 framecnt_t this_read = 0;
250 for (uint32_t i = 0; i < channels; ++i) {
252 framepos_t this_time;
253 this_time = min(bufsize, read_duration - pos);
255 framepos_t this_position;
256 this_position = read_start + pos -
257 region->start() + region->position();
259 this_read = region->master_read_at
267 if (this_read != this_time) {
268 error << string_compose
269 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
270 region->name(), pos + region->position(), this_time, this_read) << endmsg;
278 progress->set_progress (0.25 + ((float) done / read_duration) * 0.75);
280 stretcher.process(buffers, this_read, pos == read_duration);
282 framecnt_t avail = 0;
284 while ((avail = stretcher.available()) > 0) {
286 this_read = min (bufsize, avail);
288 stretcher.retrieve(buffers, this_read);
290 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
292 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
297 if (asrc->write(buffers[i], this_read) != this_read) {
298 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
305 while ((avail = stretcher.available()) >= 0) {
307 framecnt_t this_read = min (bufsize, avail);
309 stretcher.retrieve(buffers, this_read);
311 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
313 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
318 if (asrc->write(buffers[i], this_read) !=
320 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
326 } catch (runtime_error& err) {
327 error << string_compose (_("programming error: %1"), X_("timefx code failure")) << endmsg;
328 error << err.what() << endmsg;
332 new_name = region->name();
333 at = new_name.find ('@');
335 // remove any existing stretch indicator
337 if (at != string::npos && at > 2) {
338 new_name = new_name.substr (0, at - 1);
343 ret = finish (region, nsrcs, new_name);
345 /* now reset ancestral data for each new region */
347 for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
349 (*x)->set_ancestral_data (read_start,
353 (*x)->set_master_sources (region->master_sources());
354 /* multiply the old (possibly previously stretched) region length by the extra
355 stretch this time around to get its new length. this is a non-music based edit atm.
357 (*x)->set_length ((*x)->length() * tsr.time_fraction, 0);
360 /* stretch region gain envelope */
361 /* XXX: assuming we've only processed one input region into one result here */
363 if (tsr.time_fraction != 1) {
364 result = boost::dynamic_pointer_cast<AudioRegion> (results.front());
366 result->envelope()->x_scale (tsr.time_fraction);
371 delete [] gain_buffer;
374 for (uint32_t i = 0; i < channels; ++i) {
375 delete [] buffers[i];
380 if (ret || tsr.cancel) {
381 for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
382 (*si)->mark_for_remove ();