Waf building of rubberband.
[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 Stretch::Stretch (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)
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         nframes_t done;
74         int ret = -1;
75         const nframes_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         nframes_t pos = 0;
82         int avail = 0;
83
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;
91
92         /*
93            We have two cases to consider:
94           
95            1. The region has not been stretched before.
96           
97            In this case, we just want to read region->length() frames
98            from region->start().
99           
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).
106           
107            2. The region has been stretched before.
108           
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.
113            
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
119            region.
120            
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
127            frames.
128           
129            Case 1 is of course a special case of 2, where
130            region->ancestral_start() == 0 and region->stretch() == 1.
131           
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().
141           
142            Note that region->ancestral_length() is not used.
143           
144            I hope this is clear.
145         */
146
147         double stretch = region->stretch() * tsr.time_fraction;
148         double shift = region->shift() * tsr.pitch_fraction;
149
150         nframes_t read_start = region->ancestral_start() +
151                 nframes_t(region->start() / (double)region->stretch());
152
153         nframes_t read_duration =
154                 nframes_t(region->length() / (double)region->stretch());
155
156         uint32_t channels = region->n_channels();
157
158         RubberBandStretcher stretcher
159                 (session.frame_rate(), channels,
160                  (RubberBandStretcher::Options) tsr.opts, stretch, shift);
161         
162         tsr.progress = 0.0f;
163         tsr.done = false;
164
165         stretcher.setExpectedInputDuration(read_duration);
166         stretcher.setDebugLevel(1);
167
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
170         */
171
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));
176         } else {
177                 snprintf (suffix, sizeof (suffix), "@%d-%d", 
178                           (int) floor (stretch * 100.0f),
179                           (int) floor (shift * 100.0f));
180         }
181
182         /* create new sources */
183
184         if (make_new_sources (region, nsrcs, suffix)) {
185                 goto out;
186         }
187
188         gain_buffer = new gain_t[bufsize];
189         buffers = new float *[channels];
190
191         for (uint32_t i = 0; i < channels; ++i) {
192                 buffers[i] = new float[bufsize];
193         }
194
195         /* we read from the master (original) sources for the region,
196            not the ones currently in use, in case it's already been
197            subject to timefx.  */
198
199         /* study first, process afterwards. */
200
201         pos = 0;
202         avail = 0;
203         done = 0;
204
205         try { 
206                 while (pos < read_duration && !tsr.cancel) {
207                         
208                         nframes_t this_read = 0;
209
210                         for (uint32_t i = 0; i < channels; ++i) {
211                                 
212                                 this_read = 0;
213
214                                 nframes_t this_time;
215                                 this_time = min(bufsize, read_duration - pos);
216                                 
217                                 nframes_t this_position;
218                                 this_position = read_start + pos -
219                                         region->start() + region->position();
220
221                                 this_read = region->master_read_at
222                                         (buffers[i],
223                                          buffers[i],
224                                          gain_buffer,
225                                          this_position,
226                                          this_time,
227                                          i);
228                                 
229                                 if (this_read != this_time) {
230                                         error << string_compose
231                                                 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
232                                                  region->name(), this_position, this_time, this_read) << endmsg;
233                                         goto out;
234                                 }
235                         }
236                         
237                         pos += this_read;
238                         done += this_read;
239
240                         tsr.progress = ((float) done / read_duration) * 0.25;
241
242                         stretcher.study(buffers, this_read, pos == read_duration);
243                 }
244                 
245                 done = 0;
246                 pos = 0;
247
248                 while (pos < read_duration && !tsr.cancel) {
249                         
250                         nframes_t this_read = 0;
251                         
252                         for (uint32_t i = 0; i < channels; ++i) {
253                                 
254                                 this_read = 0;
255                                 nframes_t this_time;
256                                 this_time = min(bufsize, read_duration - pos);
257
258                                 nframes_t this_position;
259                                 this_position = read_start + pos -
260                                         region->start() + region->position();
261                                 
262                                 this_read = region->master_read_at
263                                         (buffers[i],
264                                          buffers[i],
265                                          gain_buffer,
266                                          this_position,
267                                          this_time,
268                                          i);
269                                 
270                                 if (this_read != this_time) {
271                                         error << string_compose
272                                                 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
273                                                  region->name(), pos + region->position(), this_time, this_read) << endmsg;
274                                         goto out;
275                                 }
276                         }
277
278                         pos += this_read;
279                         done += this_read;
280
281                         tsr.progress = 0.25 + ((float) done / read_duration) * 0.75;
282
283                         stretcher.process(buffers, this_read, pos == read_duration);
284
285                         int avail = 0;
286
287                         while ((avail = stretcher.available()) > 0) {
288
289                                 this_read = min(bufsize, uint32_t(avail));
290
291                                 stretcher.retrieve(buffers, this_read);
292                         
293                                 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
294
295                                         boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
296                                         if (!asrc) {
297                                                 continue;
298                                         }
299
300                                         if (asrc->write(buffers[i], this_read) != this_read) {
301                                                 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
302                                                 goto out;
303                                         }
304                                 }
305                         }
306                 }
307
308                 while ((avail = stretcher.available()) >= 0) {
309
310                         uint32_t this_read = min(bufsize, uint32_t(avail));
311
312                         stretcher.retrieve(buffers, this_read);
313
314                         for (uint32_t i = 0; i < nsrcs.size(); ++i) {
315
316                                 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
317                                 if (!asrc) {
318                                         continue;
319                                 }
320                                 
321                                 if (asrc->write(buffers[i], this_read) !=
322                                     this_read) {
323                                         error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
324                                         goto out;
325                                 }
326                         }
327                 }
328
329         } catch (runtime_error& err) {
330                 error << _("timefx code failure. please notify ardour-developers.") << endmsg;
331                 error << err.what() << endmsg;
332                 goto out;
333         }
334
335         new_name = region->name();
336         at = new_name.find ('@');
337
338         // remove any existing stretch indicator
339
340         if (at != string::npos && at > 2) {
341                 new_name = new_name.substr (0, at - 1);
342         }
343
344         new_name += suffix;
345
346         ret = finish (region, nsrcs, new_name);
347
348         /* now reset ancestral data for each new region */
349
350         for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
351
352                 (*x)->set_ancestral_data (read_start,
353                                           read_duration,
354                                           stretch,
355                                           shift);
356                 (*x)->set_master_sources (region->master_sources());
357         }
358
359   out:
360
361         delete [] gain_buffer;
362
363         if (buffers) {
364                 for (uint32_t i = 0; i < channels; ++i) {
365                         delete buffers[i];
366                 }
367                 delete [] buffers;
368         }
369
370         if (ret || tsr.cancel) {
371                 for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
372                         (*si)->mark_for_remove ();
373                 }
374         }
375         
376         tsr.done = true;
377
378         return ret;
379 }
380
381
382
383
384