try not thinning when loading old-school automation lists
[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/audioregion.h"
27 #include "ardour/audiosource.h"
28 #include "ardour/pitch.h"
29 #include "ardour/progress.h"
30 #include "ardour/session.h"
31 #include "ardour/stretch.h"
32 #include "ardour/types.h"
33
34 #include "i18n.h"
35
36 using namespace std;
37 using namespace ARDOUR;
38 using namespace PBD;
39 using namespace RubberBand;
40
41 Pitch::Pitch (Session& s, TimeFXRequest& req)
42         : RBEffect (s, req)
43 {
44 }
45
46 RBStretch::RBStretch (Session& s, TimeFXRequest& req)
47         : RBEffect (s, req)
48 {
49 }
50
51 RBEffect::RBEffect (Session& s, TimeFXRequest& req)
52         : Filter (s)
53         , tsr (req)
54
55 {
56
57 }
58
59 RBEffect::~RBEffect ()
60 {
61 }
62
63 int
64 RBEffect::run (boost::shared_ptr<Region> r, Progress* progress)
65 {
66         boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
67
68         if (!region) {
69                 error << "RBEffect::run() passed a non-audio region! WTF?" << endmsg;
70                 return -1;
71         }
72
73         SourceList nsrcs;
74         framecnt_t done;
75         int ret = -1;
76         const framecnt_t bufsize = 256;
77         gain_t* gain_buffer = 0;
78         Sample** buffers = 0;
79         char suffix[32];
80         string new_name;
81         string::size_type at;
82         framepos_t pos = 0;
83         framecnt_t avail = 0;
84         boost::shared_ptr<AudioRegion> result;
85
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;
93
94         /*
95            We have two cases to consider:
96
97            1. The region has not been stretched before.
98
99            In this case, we just want to read region->length() frames
100            from region->start().
101
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).
108
109            2. The region has been stretched before.
110
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.
115
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
121            region.
122
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
129            frames.
130
131            Case 1 is of course a special case of 2, where
132            region->ancestral_start() == 0 and region->stretch() == 1.
133
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().
143
144            Note that region->ancestral_length() is not used.
145
146            I hope this is clear.
147         */
148
149         double stretch = region->stretch() * tsr.time_fraction;
150         double shift = region->shift() * tsr.pitch_fraction;
151
152         framecnt_t read_start = region->ancestral_start() +
153                 framecnt_t(region->start() / (double)region->stretch());
154
155         framecnt_t read_duration =
156                 framecnt_t(region->length() / (double)region->stretch());
157
158         uint32_t channels = region->n_channels();
159
160         RubberBandStretcher stretcher
161                 (session.frame_rate(), channels,
162                  (RubberBandStretcher::Options) tsr.opts, stretch, shift);
163
164         progress->set_progress (0);
165         tsr.done = false;
166
167         stretcher.setExpectedInputDuration(read_duration);
168         stretcher.setDebugLevel(1);
169
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
172         */
173
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));
178         } else {
179                 snprintf (suffix, sizeof (suffix), "@%d-%d",
180                           (int) floor (stretch * 100.0f),
181                           (int) floor (shift * 100.0f));
182         }
183
184         /* create new sources */
185
186         if (make_new_sources (region, nsrcs, suffix)) {
187                 goto out;
188         }
189
190         gain_buffer = new gain_t[bufsize];
191         buffers = new float *[channels];
192
193         for (uint32_t i = 0; i < channels; ++i) {
194                 buffers[i] = new float[bufsize];
195         }
196
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.  */
200
201         /* study first, process afterwards. */
202
203         pos = 0;
204         avail = 0;
205         done = 0;
206
207         try {
208                 while (pos < read_duration && !tsr.cancel) {
209
210                         framecnt_t this_read = 0;
211
212                         for (uint32_t i = 0; i < channels; ++i) {
213
214                                 this_read = 0;
215
216                                 framepos_t this_time;
217                                 this_time = min(bufsize, read_duration - pos);
218
219                                 framepos_t this_position;
220                                 this_position = read_start + pos -
221                                         region->start() + region->position();
222
223                                 this_read = region->master_read_at
224                                         (buffers[i],
225                                          buffers[i],
226                                          gain_buffer,
227                                          this_position,
228                                          this_time,
229                                          i);
230
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;
235                                         goto out;
236                                 }
237                         }
238
239                         pos += this_read;
240                         done += this_read;
241
242                         progress->set_progress (((float) done / read_duration) * 0.25);
243
244                         stretcher.study(buffers, this_read, pos == read_duration);
245                 }
246
247                 done = 0;
248                 pos = 0;
249
250                 while (pos < read_duration && !tsr.cancel) {
251
252                         framecnt_t this_read = 0;
253
254                         for (uint32_t i = 0; i < channels; ++i) {
255
256                                 this_read = 0;
257                                 framepos_t this_time;
258                                 this_time = min(bufsize, read_duration - pos);
259
260                                 framepos_t this_position;
261                                 this_position = read_start + pos -
262                                         region->start() + region->position();
263
264                                 this_read = region->master_read_at
265                                         (buffers[i],
266                                          buffers[i],
267                                          gain_buffer,
268                                          this_position,
269                                          this_time,
270                                          i);
271
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;
276                                         goto out;
277                                 }
278                         }
279
280                         pos += this_read;
281                         done += this_read;
282
283                         progress->set_progress (0.25 + ((float) done / read_duration) * 0.75);
284
285                         stretcher.process(buffers, this_read, pos == read_duration);
286
287                         framecnt_t avail = 0;
288
289                         while ((avail = stretcher.available()) > 0) {
290
291                                 this_read = min (bufsize, avail);
292
293                                 stretcher.retrieve(buffers, this_read);
294
295                                 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
296
297                                         boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
298                                         if (!asrc) {
299                                                 continue;
300                                         }
301
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;
304                                                 goto out;
305                                         }
306                                 }
307                         }
308                 }
309
310                 while ((avail = stretcher.available()) >= 0) {
311
312                         framecnt_t this_read = min (bufsize, avail);
313
314                         stretcher.retrieve(buffers, this_read);
315
316                         for (uint32_t i = 0; i < nsrcs.size(); ++i) {
317
318                                 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
319                                 if (!asrc) {
320                                         continue;
321                                 }
322
323                                 if (asrc->write(buffers[i], this_read) !=
324                                     this_read) {
325                                         error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
326                                         goto out;
327                                 }
328                         }
329                 }
330
331         } catch (runtime_error& err) {
332                 error << _("timefx code failure. please notify ardour-developers.") << endmsg;
333                 error << err.what() << endmsg;
334                 goto out;
335         }
336
337         new_name = region->name();
338         at = new_name.find ('@');
339
340         // remove any existing stretch indicator
341
342         if (at != string::npos && at > 2) {
343                 new_name = new_name.substr (0, at - 1);
344         }
345
346         new_name += suffix;
347
348         ret = finish (region, nsrcs, new_name);
349
350         /* now reset ancestral data for each new region */
351
352         for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
353
354                 (*x)->set_ancestral_data (read_start,
355                                           read_duration,
356                                           stretch,
357                                           shift);
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
361                 */
362                 (*x)->set_length ((*x)->length() * tsr.time_fraction);
363         }
364
365         /* stretch region gain envelope */
366         /* XXX: assuming we've only processed one input region into one result here */
367
368         if (tsr.time_fraction != 1) {
369                 result = boost::dynamic_pointer_cast<AudioRegion> (results.front());
370                 assert (result);
371                 result->envelope()->x_scale (tsr.time_fraction);
372         }
373
374   out:
375
376         delete [] gain_buffer;
377
378         if (buffers) {
379                 for (uint32_t i = 0; i < channels; ++i) {
380                         delete buffers[i];
381                 }
382                 delete [] buffers;
383         }
384
385         if (ret || tsr.cancel) {
386                 for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
387                         (*si)->mark_for_remove ();
388                 }
389         }
390
391         tsr.done = true;
392
393         return ret;
394 }
395
396
397
398
399