fix crash when copy'ing latent plugins
[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 <rubberband/RubberBandStretcher.h>
24
25 #include "pbd/error.h"
26
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"
34
35 #include "pbd/i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace PBD;
40 using namespace RubberBand;
41
42 Pitch::Pitch (Session& s, TimeFXRequest& req)
43         : RBEffect (s, req)
44 {
45 }
46
47 RBStretch::RBStretch (Session& s, TimeFXRequest& req)
48         : RBEffect (s, req)
49 {
50 }
51
52 RBEffect::RBEffect (Session& s, TimeFXRequest& req)
53         : Filter (s)
54         , tsr (req)
55
56 {
57
58 }
59
60 RBEffect::~RBEffect ()
61 {
62 }
63
64 int
65 RBEffect::run (boost::shared_ptr<Region> r, Progress* progress)
66 {
67         boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
68
69         if (!region) {
70                 error << "RBEffect::run() passed a non-audio region! WTF?" << endmsg;
71                 return -1;
72         }
73
74         SourceList nsrcs;
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         boost::shared_ptr<AudioRegion> result;
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         framecnt_t read_start = region->ancestral_start() +
151                 framecnt_t(region->start() / (double)region->stretch());
152
153         framecnt_t read_duration =
154                 framecnt_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         progress->set_progress (0);
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         framepos_t pos   = 0;
185         framecnt_t avail = 0;
186         framecnt_t done  = 0;
187
188         if (make_new_sources (region, nsrcs, suffix)) {
189                 goto out;
190         }
191
192         gain_buffer = new gain_t[bufsize];
193         buffers = new float *[channels];
194
195         for (uint32_t i = 0; i < channels; ++i) {
196                 buffers[i] = new float[bufsize];
197         }
198
199         /* we read from the master (original) sources for the region,
200            not the ones currently in use, in case it's already been
201            subject to timefx.  */
202
203         /* study first, process afterwards. */
204
205         try {
206                 while (pos < read_duration && !tsr.cancel) {
207
208                         framecnt_t this_read = 0;
209
210                         for (uint32_t i = 0; i < channels; ++i) {
211
212                                 framepos_t this_time;
213                                 this_time = min(bufsize, read_duration - pos);
214
215                                 framepos_t this_position;
216                                 this_position = read_start + pos -
217                                         region->start() + region->position();
218
219                                 this_read = region->master_read_at
220                                         (buffers[i],
221                                          buffers[i],
222                                          gain_buffer,
223                                          this_position,
224                                          this_time,
225                                          i);
226
227                                 if (this_read != this_time) {
228                                         error << string_compose
229                                                 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
230                                                  region->name(), this_position, this_time, this_read) << endmsg;
231                                         goto out;
232                                 }
233                         }
234
235                         pos += this_read;
236                         done += this_read;
237
238                         progress->set_progress (((float) done / read_duration) * 0.25);
239
240                         stretcher.study(buffers, this_read, pos == read_duration);
241                 }
242
243                 done = 0;
244                 pos = 0;
245
246                 while (pos < read_duration && !tsr.cancel) {
247
248                         framecnt_t this_read = 0;
249
250                         for (uint32_t i = 0; i < channels; ++i) {
251
252                                 framepos_t this_time;
253                                 this_time = min(bufsize, read_duration - pos);
254
255                                 framepos_t this_position;
256                                 this_position = read_start + pos -
257                                         region->start() + region->position();
258
259                                 this_read = region->master_read_at
260                                         (buffers[i],
261                                          buffers[i],
262                                          gain_buffer,
263                                          this_position,
264                                          this_time,
265                                          i);
266
267                                 if (this_read != this_time) {
268                                         error << string_compose
269                                                 (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
270                                                  region->name(), pos + region->position(), this_time, this_read) << endmsg;
271                                         goto out;
272                                 }
273                         }
274
275                         pos += this_read;
276                         done += this_read;
277
278                         progress->set_progress (0.25 + ((float) done / read_duration) * 0.75);
279
280                         stretcher.process(buffers, this_read, pos == read_duration);
281
282                         framecnt_t avail = 0;
283
284                         while ((avail = stretcher.available()) > 0) {
285
286                                 this_read = min (bufsize, avail);
287
288                                 stretcher.retrieve(buffers, this_read);
289
290                                 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
291
292                                         boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
293                                         if (!asrc) {
294                                                 continue;
295                                         }
296
297                                         if (asrc->write(buffers[i], this_read) != this_read) {
298                                                 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
299                                                 goto out;
300                                         }
301                                 }
302                         }
303                 }
304
305                 while ((avail = stretcher.available()) >= 0) {
306
307                         framecnt_t this_read = min (bufsize, avail);
308
309                         stretcher.retrieve(buffers, this_read);
310
311                         for (uint32_t i = 0; i < nsrcs.size(); ++i) {
312
313                                 boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
314                                 if (!asrc) {
315                                         continue;
316                                 }
317
318                                 if (asrc->write(buffers[i], this_read) !=
319                                     this_read) {
320                                         error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
321                                         goto out;
322                                 }
323                         }
324                 }
325
326         } catch (runtime_error& err) {
327                 error << string_compose (_("programming error: %1"), X_("timefx code failure")) << endmsg;
328                 error << err.what() << endmsg;
329                 goto out;
330         }
331
332         new_name = region->name();
333         at = new_name.find ('@');
334
335         // remove any existing stretch indicator
336
337         if (at != string::npos && at > 2) {
338                 new_name = new_name.substr (0, at - 1);
339         }
340
341         new_name += suffix;
342
343         ret = finish (region, nsrcs, new_name);
344
345         /* now reset ancestral data for each new region */
346
347         for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
348
349                 (*x)->set_ancestral_data (read_start,
350                                           read_duration,
351                                           stretch,
352                                           shift);
353                 (*x)->set_master_sources (region->master_sources());
354                 /* multiply the old (possibly previously stretched) region length by the extra
355                    stretch this time around to get its new length. this is a non-music based edit atm.
356                 */
357                 (*x)->set_length ((*x)->length() * tsr.time_fraction, 0);
358         }
359
360         /* stretch region gain envelope */
361         /* XXX: assuming we've only processed one input region into one result here */
362
363         if (tsr.time_fraction != 1) {
364                 result = boost::dynamic_pointer_cast<AudioRegion> (results.front());
365                 assert (result);
366                 result->envelope()->x_scale (tsr.time_fraction);
367         }
368
369   out:
370
371         delete [] gain_buffer;
372
373         if (buffers) {
374                 for (uint32_t i = 0; i < channels; ++i) {
375                         delete buffers[i];
376                 }
377                 delete [] buffers;
378         }
379
380         if (ret || tsr.cancel) {
381                 for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
382                         (*si)->mark_for_remove ();
383                 }
384         }
385
386         return ret;
387 }
388
389
390
391
392