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 "pbd/error.h"
24 #include "rubberband/RubberBandStretcher.h"
26 #include "ardour/types.h"
27 #include "ardour/stretch.h"
28 #include "ardour/pitch.h"
29 #include "ardour/audiofilesource.h"
30 #include "ardour/session.h"
31 #include "ardour/audioregion.h"
32 #include "ardour/progress.h"
37 using namespace ARDOUR;
39 using namespace RubberBand;
41 Pitch::Pitch (Session& s, TimeFXRequest& req)
46 RBStretch::RBStretch (Session& s, TimeFXRequest& req)
51 RBEffect::RBEffect (Session& s, TimeFXRequest& req)
59 RBEffect::~RBEffect ()
64 RBEffect::run (boost::shared_ptr<Region> r, Progress* progress)
66 boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
69 error << "RBEffect::run() passed a non-audio region! WTF?" << endmsg;
76 const framecnt_t bufsize = 256;
77 gain_t* gain_buffer = 0;
84 boost::shared_ptr<AudioRegion> result;
86 cerr << "RBEffect: source region: position = " << region->position()
87 << ", start = " << region->start()
88 << ", length = " << region->length()
89 << ", ancestral_start = " << region->ancestral_start()
90 << ", ancestral_length = " << region->ancestral_length()
91 << ", stretch " << region->stretch()
92 << ", shift " << region->shift() << endl;
95 We have two cases to consider:
97 1. The region has not been stretched before.
99 In this case, we just want to read region->length() frames
100 from region->start().
102 We will create a new region of region->length() *
103 tsr.time_fraction frames. The new region will have its
104 start set to 0 (because it has a new audio file that begins
105 at the start of the stretched area) and its ancestral_start
106 set to region->start() (so that we know where to begin
107 reading if we want to stretch it again).
109 2. The region has been stretched before.
111 The region starts at region->start() frames into its
112 (possibly previously stretched) source file. But we don't
113 want to read from its source file; we want to read from the
114 file it was originally stretched from.
116 The region's source begins at region->ancestral_start()
117 frames into its master source file. Thus, we need to start
118 reading at region->ancestral_start() + (region->start() /
119 region->stretch()) frames into the master source. This
120 value will also become the ancestral_start for the new
123 We cannot use region->ancestral_length() to establish how
124 many frames to read, because it won't be up to date if the
125 region has been trimmed since it was last stretched. We
126 must read region->length() / region->stretch() frames and
127 stretch them by tsr.time_fraction * region->stretch(), for
128 a new region of region->length() * tsr.time_fraction
131 Case 1 is of course a special case of 2, where
132 region->ancestral_start() == 0 and region->stretch() == 1.
134 When we ask to read from a region, we supply a position on
135 the global timeline. The read function calculates the
136 offset into the source as (position - region->position()) +
137 region->start(). This calculation is used regardless of
138 whether we are reading from a master or
139 previously-stretched region. In order to read from a point
140 n frames into the master source, we need to provide n -
141 region->start() + region->position() as our position
142 argument to master_read_at().
144 Note that region->ancestral_length() is not used.
146 I hope this is clear.
149 double stretch = region->stretch() * tsr.time_fraction;
150 double shift = region->shift() * tsr.pitch_fraction;
152 framecnt_t read_start = region->ancestral_start() +
153 framecnt_t(region->start() / (double)region->stretch());
155 framecnt_t read_duration =
156 framecnt_t(region->length() / (double)region->stretch());
158 uint32_t channels = region->n_channels();
160 RubberBandStretcher stretcher
161 (session.frame_rate(), channels,
162 (RubberBandStretcher::Options) tsr.opts, stretch, shift);
164 progress->set_progress (0);
167 stretcher.setExpectedInputDuration(read_duration);
168 stretcher.setDebugLevel(1);
170 /* the name doesn't need to be super-precise, but allow for 2 fractional
171 digits just to disambiguate close but not identical FX
174 if (stretch == 1.0) {
175 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (shift * 100.0f));
176 } else if (shift == 1.0) {
177 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (stretch * 100.0f));
179 snprintf (suffix, sizeof (suffix), "@%d-%d",
180 (int) floor (stretch * 100.0f),
181 (int) floor (shift * 100.0f));
184 /* create new sources */
186 if (make_new_sources (region, nsrcs, suffix)) {
190 gain_buffer = new gain_t[bufsize];
191 buffers = new float *[channels];
193 for (uint32_t i = 0; i < channels; ++i) {
194 buffers[i] = new float[bufsize];
197 /* we read from the master (original) sources for the region,
198 not the ones currently in use, in case it's already been
199 subject to timefx. */
201 /* study first, process afterwards. */
208 while (pos < read_duration && !tsr.cancel) {
210 framecnt_t this_read = 0;
212 for (uint32_t i = 0; i < channels; ++i) {
216 framepos_t this_time;
217 this_time = min(bufsize, read_duration - pos);
219 framepos_t this_position;
220 this_position = read_start + pos -
221 region->start() + region->position();
223 this_read = region->master_read_at
231 if (this_read != this_time) {
232 error << string_compose
233 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
234 region->name(), this_position, this_time, this_read) << endmsg;
242 progress->set_progress (((float) done / read_duration) * 0.25);
244 stretcher.study(buffers, this_read, pos == read_duration);
250 while (pos < read_duration && !tsr.cancel) {
252 framecnt_t this_read = 0;
254 for (uint32_t i = 0; i < channels; ++i) {
257 framepos_t this_time;
258 this_time = min(bufsize, read_duration - pos);
260 framepos_t this_position;
261 this_position = read_start + pos -
262 region->start() + region->position();
264 this_read = region->master_read_at
272 if (this_read != this_time) {
273 error << string_compose
274 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
275 region->name(), pos + region->position(), this_time, this_read) << endmsg;
283 progress->set_progress (0.25 + ((float) done / read_duration) * 0.75);
285 stretcher.process(buffers, this_read, pos == read_duration);
287 framecnt_t avail = 0;
289 while ((avail = stretcher.available()) > 0) {
291 this_read = min (bufsize, avail);
293 stretcher.retrieve(buffers, this_read);
295 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
297 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
302 if (asrc->write(buffers[i], this_read) != this_read) {
303 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
310 while ((avail = stretcher.available()) >= 0) {
312 framecnt_t this_read = min (bufsize, avail);
314 stretcher.retrieve(buffers, this_read);
316 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
318 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
323 if (asrc->write(buffers[i], this_read) !=
325 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
331 } catch (runtime_error& err) {
332 error << _("timefx code failure. please notify ardour-developers.") << endmsg;
333 error << err.what() << endmsg;
337 new_name = region->name();
338 at = new_name.find ('@');
340 // remove any existing stretch indicator
342 if (at != string::npos && at > 2) {
343 new_name = new_name.substr (0, at - 1);
348 ret = finish (region, nsrcs, new_name);
350 /* now reset ancestral data for each new region */
352 for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
354 (*x)->set_ancestral_data (read_start,
358 (*x)->set_master_sources (region->master_sources());
359 /* multiply the old (possibly previously stretched) region length by the extra
360 stretch this time around to get its new length
362 (*x)->set_length ((*x)->length() * tsr.time_fraction);
365 /* stretch region gain envelope */
366 /* XXX: assuming we've only processed one input region into one result here */
368 if (tsr.time_fraction != 1) {
369 result = boost::dynamic_pointer_cast<AudioRegion> (results.front());
371 result->envelope()->x_scale (tsr.time_fraction);
376 delete [] gain_buffer;
379 for (uint32_t i = 0; i < channels; ++i) {
385 if (ret || tsr.cancel) {
386 for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
387 (*si)->mark_for_remove ();