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;
77 const framecnt_t bufsize = 256;
78 gain_t* gain_buffer = 0;
85 boost::shared_ptr<AudioRegion> result;
87 cerr << "RBEffect: source region: position = " << region->position()
88 << ", start = " << region->start()
89 << ", length = " << region->length()
90 << ", ancestral_start = " << region->ancestral_start()
91 << ", ancestral_length = " << region->ancestral_length()
92 << ", stretch " << region->stretch()
93 << ", shift " << region->shift() << endl;
96 We have two cases to consider:
98 1. The region has not been stretched before.
100 In this case, we just want to read region->length() frames
101 from region->start().
103 We will create a new region of region->length() *
104 tsr.time_fraction frames. The new region will have its
105 start set to 0 (because it has a new audio file that begins
106 at the start of the stretched area) and its ancestral_start
107 set to region->start() (so that we know where to begin
108 reading if we want to stretch it again).
110 2. The region has been stretched before.
112 The region starts at region->start() frames into its
113 (possibly previously stretched) source file. But we don't
114 want to read from its source file; we want to read from the
115 file it was originally stretched from.
117 The region's source begins at region->ancestral_start()
118 frames into its master source file. Thus, we need to start
119 reading at region->ancestral_start() + (region->start() /
120 region->stretch()) frames into the master source. This
121 value will also become the ancestral_start for the new
124 We cannot use region->ancestral_length() to establish how
125 many frames to read, because it won't be up to date if the
126 region has been trimmed since it was last stretched. We
127 must read region->length() / region->stretch() frames and
128 stretch them by tsr.time_fraction * region->stretch(), for
129 a new region of region->length() * tsr.time_fraction
132 Case 1 is of course a special case of 2, where
133 region->ancestral_start() == 0 and region->stretch() == 1.
135 When we ask to read from a region, we supply a position on
136 the global timeline. The read function calculates the
137 offset into the source as (position - region->position()) +
138 region->start(). This calculation is used regardless of
139 whether we are reading from a master or
140 previously-stretched region. In order to read from a point
141 n frames into the master source, we need to provide n -
142 region->start() + region->position() as our position
143 argument to master_read_at().
145 Note that region->ancestral_length() is not used.
147 I hope this is clear.
150 double stretch = region->stretch() * tsr.time_fraction;
151 double shift = region->shift() * tsr.pitch_fraction;
153 framecnt_t read_start = region->ancestral_start() +
154 framecnt_t(region->start() / (double)region->stretch());
156 framecnt_t read_duration =
157 framecnt_t(region->length() / (double)region->stretch());
159 uint32_t channels = region->n_channels();
161 RubberBandStretcher stretcher
162 (session.frame_rate(), channels,
163 (RubberBandStretcher::Options) tsr.opts, stretch, shift);
165 progress->set_progress (0);
168 stretcher.setExpectedInputDuration(read_duration);
169 stretcher.setDebugLevel(1);
171 /* the name doesn't need to be super-precise, but allow for 2 fractional
172 digits just to disambiguate close but not identical FX
175 if (stretch == 1.0) {
176 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (shift * 100.0f));
177 } else if (shift == 1.0) {
178 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (stretch * 100.0f));
180 snprintf (suffix, sizeof (suffix), "@%d-%d",
181 (int) floor (stretch * 100.0f),
182 (int) floor (shift * 100.0f));
185 /* create new sources */
187 if (make_new_sources (region, nsrcs, suffix)) {
191 gain_buffer = new gain_t[bufsize];
192 buffers = new float *[channels];
194 for (uint32_t i = 0; i < channels; ++i) {
195 buffers[i] = new float[bufsize];
198 /* we read from the master (original) sources for the region,
199 not the ones currently in use, in case it's already been
200 subject to timefx. */
202 /* study first, process afterwards. */
209 while (pos < read_duration && !tsr.cancel) {
211 framecnt_t this_read = 0;
213 for (uint32_t i = 0; i < channels; ++i) {
217 framepos_t this_time;
218 this_time = min(bufsize, read_duration - pos);
220 framepos_t this_position;
221 this_position = read_start + pos -
222 region->start() + region->position();
224 this_read = region->master_read_at
232 if (this_read != this_time) {
233 error << string_compose
234 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
235 region->name(), this_position, this_time, this_read) << endmsg;
243 progress->set_progress (((float) done / read_duration) * 0.25);
245 stretcher.study(buffers, this_read, pos == read_duration);
251 while (pos < read_duration && !tsr.cancel) {
253 framecnt_t this_read = 0;
255 for (uint32_t i = 0; i < channels; ++i) {
258 framepos_t this_time;
259 this_time = min(bufsize, read_duration - pos);
261 framepos_t this_position;
262 this_position = read_start + pos -
263 region->start() + region->position();
265 this_read = region->master_read_at
273 if (this_read != this_time) {
274 error << string_compose
275 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
276 region->name(), pos + region->position(), this_time, this_read) << endmsg;
284 progress->set_progress (0.25 + ((float) done / read_duration) * 0.75);
286 stretcher.process(buffers, this_read, pos == read_duration);
288 framecnt_t avail = 0;
290 while ((avail = stretcher.available()) > 0) {
292 this_read = min (bufsize, avail);
294 stretcher.retrieve(buffers, this_read);
296 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
298 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
303 if (asrc->write(buffers[i], this_read) != this_read) {
304 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
311 while ((avail = stretcher.available()) >= 0) {
313 framecnt_t this_read = min (bufsize, avail);
315 stretcher.retrieve(buffers, this_read);
317 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
319 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
324 if (asrc->write(buffers[i], this_read) !=
326 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
332 } catch (runtime_error& err) {
333 error << string_compose (_("programming error: %1"), X_("timefx code failure")) << endmsg;
334 error << err.what() << endmsg;
338 new_name = region->name();
339 at = new_name.find ('@');
341 // remove any existing stretch indicator
343 if (at != string::npos && at > 2) {
344 new_name = new_name.substr (0, at - 1);
349 ret = finish (region, nsrcs, new_name);
351 /* now reset ancestral data for each new region */
353 for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
355 (*x)->set_ancestral_data (read_start,
359 (*x)->set_master_sources (region->master_sources());
360 /* multiply the old (possibly previously stretched) region length by the extra
361 stretch this time around to get its new length
363 (*x)->set_length ((*x)->length() * tsr.time_fraction);
366 /* stretch region gain envelope */
367 /* XXX: assuming we've only processed one input region into one result here */
369 if (tsr.time_fraction != 1) {
370 result = boost::dynamic_pointer_cast<AudioRegion> (results.front());
372 result->envelope()->x_scale (tsr.time_fraction);
377 delete [] gain_buffer;
380 for (uint32_t i = 0; i < channels; ++i) {
386 if (ret || tsr.cancel) {
387 for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
388 (*si)->mark_for_remove ();