Merge with 2.0-ongoing R2943.
[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<AudioRegion> region)
64 {
65         SourceList nsrcs;
66         nframes_t done;
67         int ret = -1;
68         const nframes_t bufsize = 256;
69         gain_t* gain_buffer = 0;
70         Sample** buffers = 0;
71         char suffix[32];
72         string new_name;
73         string::size_type at;
74         nframes_t pos = 0;
75         int avail = 0;
76
77         double this_time_fraction = tsr.time_fraction * region->stretch ();
78         double this_pitch_fraction = tsr.pitch_fraction * region->shift ();
79
80         RubberBandStretcher stretcher (session.frame_rate(), region->n_channels(),
81                                        (RubberBandStretcher::Options) tsr.opts,
82                                        this_time_fraction, this_pitch_fraction);
83         
84         stretcher.setExpectedInputDuration(region->length());
85         stretcher.setDebugLevel(1);
86
87         tsr.progress = 0.0f;
88         tsr.done = false;
89
90         uint32_t channels = region->n_channels();
91         nframes_t duration = region->length();
92
93         /* the name doesn't need to be super-precise, but allow for 2 fractional
94            digits just to disambiguate close but not identical FX
95         */
96
97         if (this_time_fraction == 1.0) {
98                 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (this_pitch_fraction * 100.0f));
99         } else if (this_pitch_fraction == 1.0) {
100                 snprintf (suffix, sizeof (suffix), "@%d", (int) floor (this_time_fraction * 100.0f));
101         } else {
102                 snprintf (suffix, sizeof (suffix), "@%d-%d", 
103                           (int) floor (this_time_fraction * 100.0f),
104                           (int) floor (this_pitch_fraction * 100.0f));
105         }
106
107         /* create new sources */
108
109         if (make_new_sources (region, nsrcs, suffix)) {
110                 goto out;
111         }
112
113         gain_buffer = new gain_t[bufsize];
114         buffers = new float *[channels];
115
116         for (uint32_t i = 0; i < channels; ++i) {
117                 buffers[i] = new float[bufsize];
118         }
119
120         /* we read from the master (original) sources for the region,
121            not the ones currently in use, in case it's already been
122            subject to timefx.  */
123
124         /* study first, process afterwards. */
125
126         pos = 0;
127         avail = 0;
128         done = 0;
129
130         try { 
131                 while (pos < duration && !tsr.cancel) {
132                         
133                         nframes_t this_read = 0;
134                         
135                         for (uint32_t i = 0; i < channels; ++i) {
136                                 
137                                 this_read = 0;
138                                 nframes_t this_time;
139                                 
140                                 this_time = min(bufsize, duration - pos);
141                                 
142                                 this_read = region->master_read_at
143                                         (buffers[i],
144                                          buffers[i],
145                                          gain_buffer,
146                                          pos + region->position(),
147                                          this_time,
148                                          i);
149                                 
150                                 if (this_read != this_time) {
151                                         error << string_compose
152                                                 (_("tempoize: error reading data from %1"),
153                                                  nsrcs[i]->name()) << endmsg;
154                                         goto out;
155                                 }
156                         }
157                         
158                         pos += this_read;
159                         done += this_read;
160
161                         tsr.progress = ((float) done / duration) * 0.25;
162
163                         stretcher.study(buffers, this_read, pos == duration);
164                 }
165                 
166                 done = 0;
167                 pos = 0;
168
169                 while (pos < duration && !tsr.cancel) {
170                         
171                         nframes_t this_read = 0;
172                         
173                         for (uint32_t i = 0; i < channels; ++i) {
174                                 
175                                 this_read = 0;
176                                 nframes_t this_time;
177                                 
178                                 this_time = min(bufsize, duration - pos);
179                                 
180                                 this_read = region->master_read_at
181                                         (buffers[i],
182                                          buffers[i],
183                                          gain_buffer,
184                                          pos + region->position(),
185                                          this_time,
186                                          i);
187                                 
188                                 if (this_read != this_time) {
189                                         error << string_compose
190                                                 (_("tempoize: error reading data from %1"),
191                                                  nsrcs[i]->name()) << endmsg;
192                                         goto out;
193                                 }
194                         }
195
196                         pos += this_read;
197                         done += this_read;
198
199                         tsr.progress = 0.25 + ((float) done / duration) * 0.75;
200
201                         stretcher.process(buffers, this_read, pos == duration);
202
203                         int avail = 0;
204
205                         while ((avail = stretcher.available()) > 0) {
206
207                                 this_read = min(bufsize, uint32_t(avail));
208
209                                 stretcher.retrieve(buffers, this_read);
210                         
211                                 for (uint32_t i = 0; i < nsrcs.size(); ++i) {
212
213                                         if (nsrcs[i]->write(buffers[i], this_read) !=
214                                             this_read) {
215                                                 error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
216                                                 goto out;
217                                         }
218                                 }
219                         }
220                 }
221
222                 while ((avail = stretcher.available()) >= 0) {
223
224                         uint32_t this_read = min(bufsize, uint32_t(avail));
225
226                         stretcher.retrieve(buffers, this_read);
227
228                         for (uint32_t i = 0; i < nsrcs.size(); ++i) {
229
230                                 if (nsrcs[i]->write(buffers[i], this_read) !=
231                                     this_read) {
232                                         error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
233                                         goto out;
234                                 }
235                         }
236                 }
237
238         } catch (runtime_error& err) {
239                 error << _("timefx code failure. please notify ardour-developers.") << endmsg;
240                 error << err.what() << endmsg;
241                 goto out;
242         }
243
244         new_name = region->name();
245         at = new_name.find ('@');
246
247         // remove any existing stretch indicator
248
249         if (at != string::npos && at > 2) {
250                 new_name = new_name.substr (0, at - 1);
251         }
252
253         new_name += suffix;
254
255         ret = finish (region, nsrcs, new_name);
256
257         /* now reset ancestral data for each new region */
258
259         for (vector<boost::shared_ptr<AudioRegion> >::iterator x = results.begin(); x != results.end(); ++x) {
260                 nframes64_t astart = (*x)->ancestral_start();
261                 nframes64_t alength = (*x)->ancestral_length();
262                 nframes_t start;
263                 nframes_t length;
264
265                 // note: this_time_fraction is a ratio of original length. 1.0 = no change, 
266                 // 0.5 is half as long, 2.0 is twice as long, etc.
267                 
268                 float stretch = (*x)->stretch() * (tsr.time_fraction/100.0);
269                 float shift = (*x)->shift() * tsr.pitch_fraction;
270
271                 start = (nframes_t) floor (astart + ((astart - (*x)->start()) / stretch));
272                 length = (nframes_t) floor (alength / stretch);
273
274                 (*x)->set_ancestral_data (start, length, stretch, shift);
275         }
276
277   out:
278
279         if (gain_buffer) {
280                 delete [] gain_buffer;
281         }
282
283         if (buffers) {
284                 for (uint32_t i = 0; i < channels; ++i) {
285                         delete buffers[i];
286                 }
287                 delete [] buffers;
288         }
289
290         if (ret || tsr.cancel) {
291                 for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
292                         (*si)->mark_for_remove ();
293                 }
294         }
295         
296         tsr.done = true;
297
298         return ret;
299 }
300
301
302
303
304