805782807ae37198c1c7279efad4f5d7f2949227
[ardour.git] / libs / ardour / rb_effect.cc
1 /*
2     Copyright (C) 2004-2007 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <algorithm>
21 #include <cmath>
22
23 #include "pbd/error.h"
24 #include "rubberband/RubberBandStretcher.h"
25
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
33 #include "i18n.h"
34
35 using namespace std;
36 using namespace ARDOUR;
37 using namespace PBD;
38 using namespace RubberBand;
39
40 Pitch::Pitch (Session& s, TimeFXRequest& req)
41         : RBEffect (s, req)
42 {
43 }
44
45 RBStretch::RBStretch (Session& s, TimeFXRequest& req)
46         : RBEffect (s, req)
47 {
48 }
49
50 RBEffect::RBEffect (Session& s, TimeFXRequest& req)
51         : Filter (s)
52         , tsr (req)
53
54 {
55         tsr.progress = 0.0f;
56 }
57
58 RBEffect::~RBEffect ()
59 {
60 }
61
62 int
63 RBEffect::run (boost::shared_ptr<Region> r, Progress*)
64 {
65         boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
66
67         if (!region) {
68                 error << "RBEffect::run() passed a non-audio region! WTF?" << endmsg;
69                 return -1;
70         }
71
72         SourceList nsrcs;
73         framecnt_t done;
74         int ret = -1;
75         const framecnt_t bufsize = 256;
76         gain_t* gain_buffer = 0;
77         Sample** buffers = 0;
78         char suffix[32];
79         string new_name;
80         string::size_type at;
81         framepos_t pos = 0;
82         framecnt_t avail = 0;
83         boost::shared_ptr<AudioRegion> result;
84         
85         cerr << "RBEffect: source region: position = " << region->position()
86              << ", start = " << region->start()
87              << ", length = " << region->length()
88              << ", ancestral_start = " << region->ancestral_start()
89              << ", ancestral_length = " << region->ancestral_length()
90              << ", stretch " << region->stretch()
91              << ", shift " << region->shift() << endl;
92
93         /*
94            We have two cases to consider:
95
96            1. The region has not been stretched before.
97
98            In this case, we just want to read region->length() frames
99            from region->start().
100
101            We will create a new region of region->length() *
102            tsr.time_fraction frames.  The new region will have its
103            start set to 0 (because it has a new audio file that begins
104            at the start of the stretched area) and its ancestral_start
105            set to region->start() (so that we know where to begin
106            reading if we want to stretch it again).
107
108            2. The region has been stretched before.
109
110            The region starts at region->start() frames into its
111            (possibly previously stretched) source file.  But we don't
112            want to read from its source file; we want to read from the
113            file it was originally stretched from.
114
115            The region's source begins at region->ancestral_start()
116            frames into its master source file.  Thus, we need to start
117            reading at region->ancestral_start() + (region->start() /
118            region->stretch()) frames into the master source.  This
119            value will also become the ancestral_start for the new
120            region.
121
122            We cannot use region->ancestral_length() to establish how
123            many frames to read, because it won't be up to date if the
124            region has been trimmed since it was last stretched.  We
125            must read region->length() / region->stretch() frames and
126            stretch them by tsr.time_fraction * region->stretch(), for
127            a new region of region->length() * tsr.time_fraction
128            frames.
129
130            Case 1 is of course a special case of 2, where
131            region->ancestral_start() == 0 and region->stretch() == 1.
132
133            When we ask to read from a region, we supply a position on
134            the global timeline.  The read function calculates the
135            offset into the source as (position - region->position()) +
136            region->start().  This calculation is used regardless of
137            whether we are reading from a master or
138            previously-stretched region.  In order to read from a point
139            n frames into the master source, we need to provide n -
140            region->start() + region->position() as our position
141            argument to master_read_at().
142
143            Note that region->ancestral_length() is not used.
144
145            I hope this is clear.
146         */
147
148         double stretch = region->stretch() * tsr.time_fraction;
149         double shift = region->shift() * tsr.pitch_fraction;
150
151         framecnt_t read_start = region->ancestral_start() +
152                 framecnt_t(region->start() / (double)region->stretch());
153
154         framecnt_t read_duration =
155                 framecnt_t(region->length() / (double)region->stretch());
156
157         uint32_t channels = region->n_channels();
158
159         RubberBandStretcher stretcher
160                 (session.frame_rate(), channels,
161                  (RubberBandStretcher::Options) tsr.opts, stretch, shift);
162
163         tsr.progress = 0.0f;
164         tsr.done = false;
165
166         stretcher.setExpectedInputDuration(read_duration);
167         stretcher.setDebugLevel(1);
168
169         /* the name doesn't need to be super-precise, but allow for 2 fractional
170            digits just to disambiguate close but not identical FX
171         */
172
173         if (stretch == 1.0) {
174                 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (shift * 100.0f));
175         } else if (shift == 1.0) {
176                 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (stretch * 100.0f));
177         } else {
178                 snprintf (suffix, sizeof (suffix), "@%d-%d",
179                           (int) floor (stretch * 100.0f),
180                           (int) floor (shift * 100.0f));
181         }
182
183         /* create new sources */
184
185         if (make_new_sources (region, nsrcs, suffix)) {
186                 goto out;
187         }
188
189         gain_buffer = new gain_t[bufsize];
190         buffers = new float *[channels];
191
192         for (uint32_t i = 0; i < channels; ++i) {
193                 buffers[i] = new float[bufsize];
194         }
195
196         /* we read from the master (original) sources for the region,
197            not the ones currently in use, in case it's already been
198            subject to timefx.  */
199
200         /* study first, process afterwards. */
201
202         pos = 0;
203         avail = 0;
204         done = 0;
205
206         try {
207                 while (pos < read_duration && !tsr.cancel) {
208
209                         framecnt_t this_read = 0;
210
211                         for (uint32_t i = 0; i < channels; ++i) {
212
213                                 this_read = 0;
214
215                                 framepos_t this_time;
216                                 this_time = min(bufsize, read_duration - pos);
217
218                                 framepos_t this_position;
219                                 this_position = read_start + pos -
220                                         region->start() + region->position();
221
222                                 this_read = region->master_read_at
223                                         (buffers[i],
224                                          buffers[i],
225                                          gain_buffer,
226                                          this_position,
227                                          this_time,
228                                          i);
229
230                                 if (this_read != this_time) {
231                                         error << string_compose
232                                                 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
233                                                  region->name(), this_position, this_time, this_read) << endmsg;
234                                         goto out;
235                                 }
236                         }
237
238                         pos += this_read;
239                         done += this_read;
240
241                         tsr.progress = ((float) done / read_duration) * 0.25;
242
243                         stretcher.study(buffers, this_read, pos == read_duration);
244                 }
245
246                 done = 0;
247                 pos = 0;
248
249                 while (pos < read_duration && !tsr.cancel) {
250
251                         framecnt_t this_read = 0;
252
253                         for (uint32_t i = 0; i < channels; ++i) {
254
255                                 this_read = 0;
256                                 framepos_t this_time;
257                                 this_time = min(bufsize, read_duration - pos);
258
259                                 framepos_t this_position;
260                                 this_position = read_start + pos -
261                                         region->start() + region->position();
262
263                                 this_read = region->master_read_at
264                                         (buffers[i],
265                                          buffers[i],
266                                          gain_buffer,
267                                          this_position,
268                                          this_time,
269                                          i);
270
271                                 if (this_read != this_time) {
272                                         error << string_compose
273                                                 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
274                                                  region->name(), pos + region->position(), this_time, this_read) << endmsg;
275                                         goto out;
276                                 }
277                         }
278
279                         pos += this_read;
280                         done += this_read;
281
282                         tsr.progress = 0.25 + ((float) done / read_duration) * 0.75;
283
284                         stretcher.process(buffers, this_read, pos == read_duration);
285
286                         framecnt_t avail = 0;
287
288                         while ((avail = stretcher.available()) > 0) {
289
290                                 this_read = min (bufsize, avail);
291
292                                 stretcher.retrieve(buffers, this_read);
293
294                                 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
295
296                                         boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
297                                         if (!asrc) {
298                                                 continue;
299                                         }
300
301                                         if (asrc->write(buffers[i], this_read) != this_read) {
302                                                 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
303                                                 goto out;
304                                         }
305                                 }
306                         }
307                 }
308
309                 while ((avail = stretcher.available()) >= 0) {
310
311                         framecnt_t this_read = min (bufsize, avail);
312
313                         stretcher.retrieve(buffers, this_read);
314
315                         for (uint32_t i = 0; i < nsrcs.size(); ++i) {
316
317                                 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
318                                 if (!asrc) {
319                                         continue;
320                                 }
321
322                                 if (asrc->write(buffers[i], this_read) !=
323                                     this_read) {
324                                         error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
325                                         goto out;
326                                 }
327                         }
328                 }
329
330         } catch (runtime_error& err) {
331                 error << _("timefx code failure. please notify ardour-developers.") << endmsg;
332                 error << err.what() << endmsg;
333                 goto out;
334         }
335
336         new_name = region->name();
337         at = new_name.find ('@');
338
339         // remove any existing stretch indicator
340
341         if (at != string::npos && at > 2) {
342                 new_name = new_name.substr (0, at - 1);
343         }
344
345         new_name += suffix;
346
347         ret = finish (region, nsrcs, new_name);
348
349         /* now reset ancestral data for each new region */
350
351         for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
352
353                 (*x)->set_ancestral_data (read_start,
354                                           read_duration,
355                                           stretch,
356                                           shift);
357                 (*x)->set_master_sources (region->master_sources());
358                 (*x)->set_length( (*x)->length() * stretch, this);
359         }
360
361         /* stretch region gain envelope */
362         /* XXX: assuming we've only processed one input region into one result here */
363
364         if (tsr.time_fraction != 1) {
365                 result = boost::dynamic_pointer_cast<AudioRegion> (results.front());
366                 assert (result);
367                 result->envelope()->x_scale (tsr.time_fraction);
368         }
369
370   out:
371
372         delete [] gain_buffer;
373
374         if (buffers) {
375                 for (uint32_t i = 0; i < channels; ++i) {
376                         delete buffers[i];
377                 }
378                 delete [] buffers;
379         }
380
381         if (ret || tsr.cancel) {
382                 for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
383                         (*si)->mark_for_remove ();
384                 }
385         }
386
387         tsr.done = true;
388
389         return ret;
390 }
391
392
393
394
395