Nsound  0.9.4
Stretcher.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //
3 // $Id: Stretcher.cc 878 2014-11-23 04:51:23Z weegreenblobbie $
4 //
5 // Nsound is a C++ library and Python module for audio synthesis featuring
6 // dynamic digital filters. Nsound lets you easily shape waveforms and write
7 // to disk or plot them. Nsound aims to be as powerful as Csound but easy to
8 // use.
9 //
10 // Copyright (c) 2008 to Present Nick Hilton
11 //
12 // weegreenblobbie_yahoo_com (replace '_' with '@' and '.')
13 //
14 //-----------------------------------------------------------------------------
15 
16 //-----------------------------------------------------------------------------
17 //
18 // This program is free software; you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation; either version 2 of the License, or
21 // (at your option) any later version.
22 //
23 // This program is distributed in the hope that it will be useful,
24 // but WITHOUT ANY WARRANTY; without even the implied warranty of
25 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 // GNU Library General Public License for more details.
27 //
28 // You should have received a copy of the GNU General Public License
29 // along with this program; if not, write to the Free Software
30 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 //
32 //-----------------------------------------------------------------------------
33 
34 #include <Nsound/AudioStream.h>
35 #include <Nsound/Buffer.h>
36 #include <Nsound/Sine.h>
37 #include <Nsound/Stretcher.h>
38 
39 #include <cstdio>
40 #include <algorithm>
41 #include <cmath>
42 #include <cstdlib>
43 #include <deque>
44 #include <set>
45 
46 using namespace Nsound;
47 
48 using std::cerr;
49 using std::cout;
50 using std::endl;
51 
52 //-----------------------------------------------------------------------------
55  const float64 & sample_rate,
56  const float64 & window_size_seconds,
57  const float64 & max_delta_window)
58  :
59  frames_(NULL),
60  sample_rate_(sample_rate),
61  window_(NULL),
62  window_length_(0),
63  max_delta_(0),
64  show_progress_(false)
65 {
66  frames_ = new Buffer(1024);
67  window_ = new Buffer(1024);
68 
69  Sine sin(sample_rate);
70  *window_ = sin.drawWindowHanning(window_size_seconds);
72  max_delta_ = uint32(float64(window_length_) * max_delta_window);
73 }
74 
75 //-----------------------------------------------------------------------------
77 Stretcher(const Stretcher & copy)
78  :
79  frames_(NULL),
80  sample_rate_(copy.sample_rate_),
81  window_(NULL),
82  window_length_(copy.window_length_),
83  max_delta_(copy.max_delta_),
84  show_progress_(copy.show_progress_)
85 {
86  frames_ = new Buffer(1024);
88 
89  *this = copy;
90 }
91 
92 //-----------------------------------------------------------------------------
95 {
96  delete frames_;
97  delete window_;
98 }
99 
100 //-----------------------------------------------------------------------------
101 Stretcher &
103 operator=(const Stretcher & rhs)
104 {
105  if(this == & rhs) return *this;
106 
109  max_delta_ = rhs.max_delta_;
110  *frames_ = *rhs.frames_;
111  *window_ = *rhs.window_;
113 
114  return *this;
115 }
116 
117 void
119 analyize(const Buffer & input, const float64 & f)
120 {
121  Buffer factor(1);
122  factor << f;
123 
124  analyize(input, factor);
125 }
126 
127 void
129 analyize(const Buffer & input, const Buffer & factor)
130 {
131  // Always calculate time shift.
132 
133  Buffer::const_circular_iterator ifactor = factor.cbegin();
134 
135  uint32 tau = static_cast<uint32>(window_length_ / 2.0 / ::fabs(*ifactor));
136 
137  uint32 input_length = input.getLength();
138 
139  *frames_ = Buffer(256);
140 
141  uint32 i = 0;
142  while(i < input_length - window_length_)
143  {
144  *frames_ << i;
145  i += tau;
146 
147  ifactor += tau;
148 
149  tau = static_cast<uint32>(window_length_ / 2.0 / ::fabs(*ifactor));
150  }
151 
152  uint32 n_frames = frames_->getLength();
153 
154  uint32 mod_frames = n_frames / 100;
155 
156  if(n_frames < 100) mod_frames = n_frames;
157 
158  if(show_progress_)
159  {
160  #ifdef NSOUND_CUDA
161 
162  printf("Using CUDA\n");
163 
164  #else
165 
166  #ifdef NSOUND_OPENMP
167  #pragma omp parallel
168  {
169  if(0 == omp_get_thread_num())
170  {
171  printf("Using OpenMP with %d threads\n",
172  omp_get_num_threads());
173  fflush(stdout);
174  }
175  }
176  #endif
177 
178  #endif
179 
180  printf("Analyizing %3.0f%%", 0.0);
181  fflush(stdout);
182  }
183 
184  for(uint32 j = 0; j < n_frames-1; ++j)
185  {
186  if(show_progress_ && j % mod_frames == 0)
187  {
188  printf("\b\b\b\b");
189  printf("%3.0f%%", 100.0 * float64(j) / float64(n_frames));
190  fflush(stdout);
191  }
192 
193  (*frames_)[j] = searchForBestMatch(
194  input,
195  uint32((*frames_)[j]),
196  uint32((*frames_)[j+1]));
197  }
198 
199  if(show_progress_)
200  {
201  printf("\b\b\b\b");
202  printf("%3.0f%%\n", 100.0);
203  fflush(stdout);
204  }
205 }
206 
207 uint32
210  const Buffer & input,
211  uint32 source_index,
212  uint32 search_index) const
213 {
214  // Nick's original score function
215  #if 1
216  Buffer b_source = input.subbuffer(source_index, window_length_);
217 
218  uint32 t = 0;
219  float64 min_score = 1.0e100;
220 
221  #ifdef NSOUND_OPENMP
222  #pragma omp parallel for shared(t, min_score)
223  #endif
224  for(uint32 i = 0; i < max_delta_; ++i)
225  {
226  Buffer b_test = input.subbuffer(search_index + i, window_length_)
227  - b_source;
228 
229  b_test *= b_test;
230 
231  float64 score = b_test.getSum();
232 
233  if(score < min_score)
234  {
235  min_score = score;
236  t = i;
237  }
238  }
239  #endif
240 
241  #if 0
242  // Maximizing fft phase information.
243 
244  FFTransform transform(100.0); // Sample rate here won't be used.
245 
246  Buffer b_source = input.subbuffer(source_index, window_length_);
247 
248  FFTChunkVector vec = transform.fft(b_source, window_length_);
249 
250  Buffer source_fft = vec[0].getPhase();
251 
252  uint32 t = 0;
253  float64 min_score = 1.0e100;
254  for(uint32 i = 0; i < max_delta_; ++i)
255  {
256  Buffer b_test = input.subbuffer(search_index + i, window_length_);
257 
258  FFTChunkVector vec = transform.fft(b_test, window_length_);
259 
260  Buffer test_fft = vec[0].getPhase();
261 
262  Buffer delta = source_fft - test_fft;
263 
264  delta *= delta;
265 
266  float64 score = delta.getSum();
267 
268  if(score < min_score)
269  {
270  min_score = score;
271  t = i;
272  }
273  }
274  #endif
275 
276  return t + search_index;
277 }
278 
279 Buffer
281 overlapAdd(const Buffer & input) const
282 {
283  Sine sin(sample_rate_);
284 
285  float64 half_window_seconds = (window_length_ / 2) / sample_rate_;
286 
287  uint32 half_length = window_length_ / 2;
288 
289  Buffer window_start = sin.drawLine(half_window_seconds, 1.0, 1.0)
290  << window_->subbuffer(half_length, half_length);
291 
292  Buffer window_finish = window_start.getReverse();
293 
294  Buffer output = input.subbuffer(0, window_length_) * (*window_);
295 
296  uint32 n_frames = frames_->getLength();
297 
298  uint32 mod_frames = n_frames / 100;
299 
300  if(n_frames < 100) mod_frames = n_frames;
301 
302  if(show_progress_)
303  {
304  printf("Creating output %3.0f%%", 0.0);
305  fflush(stdout);
306  }
307 
308  for(uint32 i = 1; i < n_frames; ++i)
309  {
310  if(show_progress_ && i % mod_frames == 0)
311  {
312  printf("\b\b\b\b");
313  printf("%3.0f%%", 100.0 * float64(i) / float64(n_frames));
314  fflush(stdout);
315  }
316 
317  uint32 frame = uint32((*frames_)[i]);
318 
319  Buffer next_window = input.subbuffer(frame, window_length_)
320  * (*window_);
321 
322  // overlap & add
323  output.add(next_window, i * half_length);
324  }
325 
326  if(show_progress_)
327  {
328  printf("\b\b\b\b");
329  printf("%3.0f%%\n", 100.0);
330  fflush(stdout);
331  }
332 
333  return output;
334 }
335 
338 pitchShift(const AudioStream & x, const float64 & factor)
339 {
340  // Prepare for time shift.
341  analyize(x.getMono()[0], factor);
342 
344 
345  for(uint32 i = 0; i < x.getNChannels(); ++i)
346  {
347  y[i] = overlapAdd(x[i]);
348  }
349 
350  return y.getResample(1.0/factor);
351 }
352 
355 pitchShift(const AudioStream & x, const Buffer & factor)
356 {
357  // Prepare for time shift.
358  analyize(x.getMono()[0], factor);
359 
361 
362  for(uint32 i = 0; i < x.getNChannels(); ++i)
363  {
364  y[i] = overlapAdd(x[i]);
365  }
366 
367  return y.getSpeedUp(factor);
368 }
369 
370 Buffer
372 pitchShift(const Buffer & x, const float64 & factor)
373 {
374  // Prepare for time shift.
375  analyize(x, factor);
376 
377  Buffer stretched = overlapAdd(x);
378 
379  return stretched.getResample(1.0/factor);
380 }
381 
382 Buffer
384 pitchShift(const Buffer & x, const Buffer & factor)
385 {
386  // Prepare for time shift.
387  analyize(x, factor);
388 
389  Buffer stretched = overlapAdd(x);
390 
391  return stretched.getSpeedUp(factor);
392 }
393 
396 timeShift(const AudioStream & x, const float64 & factor)
397 {
398  // Prepare for time shift.
399  analyize(x.getMono()[0], factor);
400 
402 
403  for(uint32 i = 0; i < x.getNChannels(); ++i)
404  {
405  y[i] = overlapAdd(x[i]);
406  }
407 
408  return y;
409 }
410 
413 timeShift(const AudioStream & x, const Buffer & factor)
414 {
415  // Prepare for time shift.
416  analyize(x.getMono()[0], factor);
417 
419 
420  for(uint32 i = 0; i < x.getNChannels(); ++i)
421  {
422  y[i] = overlapAdd(x[i]);
423  }
424 
425  return y;
426 }
427 
428 Buffer
430 timeShift(const Buffer & x, const float64 & factor)
431 {
432  // Prepare for time shift.
433  analyize(x, factor);
434 
435  Buffer stretched = overlapAdd(x);
436 
437  return stretched;
438 }
439 
440 Buffer
442 timeShift(const Buffer & x, const Buffer & factor)
443 {
444  // Prepare for time shift.
445  analyize(x, factor);
446 
447  Buffer stretched = overlapAdd(x);
448 
449  return stretched;
450 }
451 
Buffer subbuffer(uint32 start_index, uint32 n_samples=0) const
Slice the Buffer.
Definition: Buffer.cc:2073
unsigned int uint32
Definition: Nsound.h:153
Buffer getSpeedUp(float64 step_size) const
Resamples a copy of this Buffer by the step_size, no interpolation.
Definition: Buffer.h:1707
float64 getSampleRate() const
Returns the sample rate of the stream.
Definition: AudioStream.h:217
Buffer * window_
Definition: Stretcher.h:119
AudioStream pitchShift(const AudioStream &x, const float64 &factor)
Definition: Stretcher.cc:338
uint32 searchForBestMatch(const Buffer &input, uint32 source_index, uint32 search_index) const
Definition: Stretcher.cc:209
Stretcher & operator=(const Stretcher &rhs)
Assignment.
Definition: Stretcher.cc:103
double float64
Definition: Nsound.h:146
Buffer overlapAdd(const Buffer &input) const
Definition: Stretcher.cc:281
circular_iterator cbegin()
Retruns the itreator at the start of the Buffer.
Definition: Buffer.h:318
virtual ~Stretcher()
Destructor.
Definition: Stretcher.cc:94
uint32 window_length_
Definition: Stretcher.h:120
Buffer drawWindowHanning(const float64 &duration) const
Draws a Hanning window.
Definition: Generator.cc:819
uint32 getLength() const
Returns the number of samples in the Buffer.
Definition: Buffer.h:587
uint32 getNChannels(void) const
Returns the number of audio channels in the stream.
Definition: AudioStream.h:212
Buffer * frames_
Definition: Stretcher.h:117
boolean show_progress_
Definition: Stretcher.h:122
A Class that performes the Fast Fouier Transfrom on a Buffer.
Definition: FFTransform.h:57
AudioStream timeShift(const AudioStream &x, const float64 &factor)
Definition: Stretcher.cc:396
float64 getSum() const
Returns the sum of all samples.
Definition: Buffer.cc:1118
A Buffer for storing audio samples.
Definition: Buffer.h:60
float64 sample_rate_
Definition: Stretcher.h:118
Buffer fft(const Buffer &time_domain) const
Transforms the time_domain signal and calculates the FFT.
Definition: FFTransform.cc:50
Buffer getResample(float64 factor, const uint32 N=10, float64 beta=5.0) const
Resamples a copy of this Buffer using discrete-time resampling.
Definition: Buffer.cc:1607
AudioStream getMono() const
Collapses all channels into one Buffer making it mono.
Definition: AudioStream.cc:265
void analyize(const Buffer &input, const float64 &factor)
Definition: Stretcher.cc:119
Stretcher(const float64 &sample_rate, const float64 &window_size_seconds=0.08, const float64 &max_delta_window=0.25)
Default Constructor.
Definition: Stretcher.cc:54
Buffer drawLine(const float64 &duration, const float64 &amplitude_start, const float64 &amplitude_finish) const
This method draws a linear line beteween 2 points.
Definition: Generator.cc:464
void add(const Buffer &buffer, uint32 offset=0, uint32 n_samples=0)
This method adds buffer to *this.
Definition: Buffer.cc:225
Buffer getReverse() const
Reverses the samples in a copy of this Buffer.
Definition: Buffer.h:1558
std::vector< FFTChunk > FFTChunkVector
Definition: FFTChunk.h:119
DOXME.
Definition: Sine.h:43