ardour
st_stretch.cc
Go to the documentation of this file.
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 
25 #include "ardour/types.h"
26 #include "ardour/stretch.h"
27 #include "ardour/audiofilesource.h"
28 #include "ardour/session.h"
29 #include "ardour/audioregion.h"
30 
31 #include "i18n.h"
32 
33 using namespace std;
34 using namespace ARDOUR;
35 using namespace PBD;
36 using namespace soundtouch;
37 
38 STStretch::STStretch (Session& s, TimeFXRequest& req)
39  : Filter (s)
40  , tsr (req)
41 {
42  float percentage;
43 
44  /* the soundtouch code wants a *tempo* change percentage, which is
45  of opposite sign to the length change.
46  */
47 
48  percentage = -tsr.time_fraction;
49 
50  st.setSampleRate (s.frame_rate());
51  st.setChannels (1);
52  st.setTempoChange (percentage);
53  st.setPitchSemiTones (0);
54  st.setRateChange (0);
55 
56  st.setSetting(SETTING_USE_QUICKSEEK, tsr.quick_seek);
57  st.setSetting(SETTING_USE_AA_FILTER, tsr.antialias);
58 
59 }
60 
62 {
63 }
64 
65 int
67 {
68  SourceList nsrcs;
69  framecnt_t total_frames;
70  framecnt_t done;
71  int ret = -1;
72  const framecnt_t bufsize = 16384;
73  gain_t *gain_buffer = 0;
74  Sample *buffer = 0;
75  char suffix[32];
76  string new_name;
77  string::size_type at;
78 
79  progress->set_progress (0);
80  tsr.done = false;
81 
83 
84  total_frames = region->length() * region->n_channels();
85  done = 0;
86 
87  /* the name doesn't need to be super-precise, but allow for 2 fractional
88  digits just to disambiguate close but not identical stretches.
89  */
90 
91  snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.time_fraction * 100.0f));
92 
93  /* create new sources */
94 
95  if (make_new_sources (region, nsrcs, suffix)) {
96  goto out;
97  }
98 
99  gain_buffer = new gain_t[bufsize];
100  buffer = new Sample[bufsize];
101 
102  // soundtouch throws runtime_error on error
103 
104  try {
105  for (uint32_t i = 0; i < nsrcs.size(); ++i) {
106 
109 
110  framepos_t pos = 0;
111  framecnt_t this_read = 0;
112 
113  st.clear();
114 
115  while (!tsr.cancel && pos < region->length()) {
116  framecnt_t this_time;
117 
118  this_time = min (bufsize, region->length() - pos);
119 
120  /* 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 
125  if ((this_read = region->master_read_at (buffer, buffer, gain_buffer, pos + region->position(), this_time)) != this_time) {
126  error << string_compose (_("tempoize: error reading data from %1"), asrc->name()) << endmsg;
127  goto out;
128  }
129 
130  pos += this_read;
131  done += this_read;
132 
133  progress->set_progress ((float) done / total_frames);
134 
135  st.putSamples (buffer, this_read);
136 
137  while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && !tsr.cancel) {
138  if (asrc->write (buffer, this_read) != this_read) {
139  error << string_compose (_("error writing tempo-adjusted data to %1"), asrc->name()) << endmsg;
140  goto out;
141  }
142  }
143  }
144 
145  if (!tsr.cancel) {
146  st.flush ();
147  }
148 
149  while (!tsr.cancel && (this_read = st.receiveSamples (buffer, bufsize)) > 0) {
150  if (asrc->write (buffer, this_read) != this_read) {
151  error << string_compose (_("error writing tempo-adjusted data to %1"), asrc->name()) << endmsg;
152  goto out;
153  }
154  }
155  }
156 
157  } catch (runtime_error& err) {
158  error << _("timefx code failure. please notify ardour-developers.") << endmsg;
159  error << err.what() << endmsg;
160  goto out;
161  }
162 
163  new_name = region->name();
164  at = new_name.find ('@');
165 
166  // remove any existing stretch indicator
167 
168  if (at != string::npos && at > 2) {
169  new_name = new_name.substr (0, at - 1);
170  }
171 
172  new_name += suffix;
173 
174  ret = finish (region, nsrcs, new_name);
175 
176  /* now reset ancestral data for each new region */
177 
178  for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
179  framepos_t astart = (*x)->ancestral_start();
180  framepos_t alength = (*x)->ancestral_length();
183 
184  // note: tsr.fraction is a percentage of original length. 100 = no change,
185  // 50 is half as long, 200 is twice as long, etc.
186 
187  float stretch = (*x)->stretch() * (tsr.time_fraction/100.0);
188 
189  start = (framepos_t) floor (astart + ((astart - (*x)->start()) / stretch));
190  length = (framecnt_t) floor (alength / stretch);
191 
192  (*x)->set_ancestral_data (start, length, stretch, (*x)->shift());
193  }
194 
195  out:
196 
197  delete [] gain_buffer;
198  delete [] buffer;
199 
200  if (ret || tsr.cancel) {
201  for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
202  (*si)->mark_for_remove ();
203  }
204  }
205 
206  return ret;
207 }
int make_new_sources(boost::shared_ptr< ARDOUR::Region >, ARDOUR::SourceList &, std::string suffix="")
Definition: filter.cc:42
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
int run(boost::shared_ptr< ARDOUR::Region >)
Definition: st_stretch.cc:66
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
float gain_t
Definition: types.h:58
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
framecnt_t frame_rate() const
Definition: session.h:365
LIBARDOUR_API PBD::PropertyDescriptor< float > stretch
Definition: region.cc:70
#define _(Text)
Definition: i18n.h:11
int64_t framecnt_t
Definition: types.h:76
float Sample
Definition: types.h:54
void set_progress(float)
Definition: progress.cc:59
Definition: amp.h:29
int64_t framepos_t
Definition: types.h:66
virtual framecnt_t master_read_at(Sample *buf, Sample *mixdown_buf, float *gain_buf, framepos_t position, framecnt_t cnt, uint32_t chan_n=0) const
Definition: audioregion.cc:453
framepos_t position() const
Definition: region.h:112
std::vector< boost::shared_ptr< ARDOUR::Region > > results
Definition: filter.h:41
uint32_t n_channels() const
Definition: region.h:259
std::string name() const
Definition: debug.h:30
virtual framecnt_t write(Sample *src, framecnt_t cnt)
Definition: audiosource.cc:321
soundtouch::SoundTouch st
Definition: stretch.h:60
TimeFXRequest & tsr
Definition: stretch.h:58
framecnt_t length() const
Definition: region.h:114
int finish(boost::shared_ptr< ARDOUR::Region >, ARDOUR::SourceList &, std::string region_name="")
Definition: filter.cc:88
std::vector< boost::shared_ptr< Source > > SourceList
Definition: types.h:520
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64