Nsound  0.9.4
FFTChunk.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //
3 // $Id: FFTChunk.cc 874 2014-09-08 02:21:29Z weegreenblobbie $
4 //
5 // Copyright (c) 2008 Nick Hilton
6 //
7 // weegreenblobbie_yahoo_com (replace '_' with '@' and '.')
8 //
9 //-----------------------------------------------------------------------------
10 
11 //-----------------------------------------------------------------------------
12 //
13 // This program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation; either version 2 of the License, or
16 // (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU Library General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 //
27 //-----------------------------------------------------------------------------
28 
29 #include <Nsound/Buffer.h>
30 #include <Nsound/FFTChunk.h>
31 #include <Nsound/Generator.h>
32 #include <Nsound/Plotter.h>
33 
34 #include <iostream>
35 #include <sstream>
36 
37 using namespace Nsound;
38 
39 using std::cout;
40 using std::cerr;
41 using std::endl;
42 using std::flush;
43 
44 //-----------------------------------------------------------------------------
46 FFTChunk(uint32 size, uint32 sample_rate, uint32 original_size)
47  :
48  real_(NULL),
49  imag_(NULL),
50  sample_rate_(sample_rate),
51  original_size_(original_size),
52  is_polar_(false)
53 {
54  real_ = new Buffer(size);
55  imag_ = new Buffer(size);
56 
57  if(original_size_ == 0)
58  {
59  original_size_ = size;
60  }
61 }
62 
63 //-----------------------------------------------------------------------------
65 FFTChunk(const FFTChunk & copy)
66  :
67  real_(new Buffer(copy.real_->getLength())),
68  imag_(new Buffer(copy.real_->getLength())),
69  sample_rate_(copy.sample_rate_),
70  original_size_(copy.original_size_),
71  is_polar_(copy.is_polar_)
72 {
73  // Call operator =
74  *this = copy;
75 }
76 
77 //-----------------------------------------------------------------------------
80 {
81  delete real_;
82  delete imag_;
83 }
84 
85 Buffer
87 getImaginary() const
88 {
89  if(!is_polar_)
90  {
91  return imag_->subbuffer(0, imag_->getLength() / 2);
92  }
93 
94  Buffer out;
95 
96  uint32 n_samples = real_->getLength();
97 
98  for(uint32 i = 0; i < n_samples / 2; ++i)
99  {
100  // mag * sin(phase)
101  out << (*real_)[i] * std::sin((*imag_)[i]);
102  }
103 
104  return out;
105 }
106 
107 Buffer
110 {
111  // Create the x axis based on Hz.
112 
113  uint32 chunk_size = real_->getLength();
114 
115  uint32 n_samples = chunk_size / 2 + 1;
116 
117  float64 x_step = static_cast<float64>(sample_rate_)
118  / static_cast<float64>(chunk_size);
119 
120  Generator gen(1);
121 
122  return gen.drawLine(n_samples, 0.0, x_step * n_samples);
123 }
124 
125 Buffer
127 getReal() const
128 {
129  if(!is_polar_)
130  {
131  return real_->subbuffer(0, real_->getLength() / 2);
132  }
133 
134  uint32 n_samples = real_->getLength();
135 
136  Buffer out(n_samples / 2);
137 
138  for(uint32 i = 0; i < n_samples / 2; ++i)
139  {
140  // mag * cos(phase)
141  out << (*real_)[i] * std::cos((*imag_)[i]);
142  }
143 
144  return out;
145 }
146 
147 Buffer
150 {
151  uint32 n_samples = real_->getLength();
152 
153  if(is_polar_)
154  {
155  return real_->subbuffer(0, n_samples / 2 + 1);
156  }
157 
158  float64 x = 0.0;
159  float64 y = 0.0;
160 
161  Buffer out(n_samples / 2 + 1);
162 
163  for(uint32 i = 0; i < n_samples / 2 + 1; ++i)
164  {
165  x = (*real_)[i];
166  y = (*imag_)[i];
167  out << std::sqrt(x*x + y*y);
168  }
169 
170  return out;
171 }
172 
173 Buffer
175 getPhase() const
176 {
177  if(is_polar_)
178  {
179  return imag_->subbuffer(0, imag_->getLength() / 2 + 1);
180  }
181 
182  uint32 n_samples = real_->getLength();
183 
184  float64 r = 0.0;
185  float64 i = 0.0;
186  float64 phase = 0.0;
187 
188  Buffer out(n_samples / 2 + 1);
189 
190  for(uint32 j = 0; j < n_samples / 2 + 1; ++j)
191  {
192  r = (*real_)[j];
193  i = (*imag_)[j];
194 
195  //if(r == 0.0) r = 1e-20;
196 
197  phase = std::atan(i/r);
198 
199  if(r < 0.0)
200  {
201  if(i < 0.0) phase -= M_PI;
202  else phase += M_PI;
203  }
204 
205  out << phase;
206  }
207 
208  return out;
209 }
210 
211 //-----------------------------------------------------------------------------
212 FFTChunk &
214 operator=(const FFTChunk & rhs)
215 {
216  if(this == &rhs)
217  {
218  return *this;
219  }
220 
221  *real_ = *rhs.real_;
222  *imag_ = *rhs.imag_;
225  is_polar_ = rhs.is_polar_;
226 
227  return *this;
228 }
229 
230 void
233  const std::string & title,
234  boolean dB,
235  boolean show_phase) const
236 {
237  //~ // Create the x axis based on Hz.
238  //~
239  //~ uint32 chunk_size = real_->getLength();
240 
241  uint32 n_samples = real_->getLength() / 2 + 1;
242 
243  //~
244  //~ float64 x_step = (1.0 / (static_cast<float64>(chunk_size) / 2.0))
245  //~ * (static_cast<float64>(sample_rate_) / 2.0);
246  //~
247  //~ Buffer x;
248  //~
249  //~ float64 tx = 0.0;
250  //~
251  //~ for(uint32 i = 0; i < n_samples; ++i)
252  //~ {
253  //~ x << tx;
254  //~ tx += x_step;
255  //~ }
256 
257  Buffer x = getFrequencyAxis();
258 
259  // Calculate the magnitude for the signal:
260  //
261  // magnitude = sqrt(x*x + y*y);
262  //
263  Buffer magnitude = getMagnitude();
264 
265  Plotter pylab;
266 
267  pylab.figure();
268 
269  if(show_phase)
270  {
271  pylab.subplot(2, 1, 1);
272  }
273 
274  if(title.length() <= 0)
275  {
276  pylab.title("Magnitude");
277  }
278  else
279  {
280  pylab.title(title);
281  }
282 
283  if(dB)
284  {
285  magnitude.dB();
286  pylab.ylabel("Magnitude dB");
287  }
288  else
289  {
290  pylab.ylabel("Magnitude");
291  }
292 
293  pylab.plot(x,magnitude.subbuffer(0,n_samples));
294 
295  if(show_phase)
296  {
297  Buffer phase = getPhase().subbuffer(0,n_samples);
298 
299  pylab.subplot(2, 1, 2);
300  pylab.title("Phase");
301  pylab.plot(x,phase);
302  pylab.ylabel("Phase Radians");
303  }
304 
305  pylab.xlabel("Frequency Hz");
306 }
307 
308 void
310 setCartesian(const Buffer & real, const Buffer & img)
311 {
312  Buffer zeros = 0.0 * real;
313 
314  *real_ = 2.0 * real;
315  *real_ << zeros;
316 
317  *imag_ = 2.0 * img;
318  *imag_ << zeros;
319 
320  is_polar_ = false;
321 }
322 
323 void
325 setPolar(const Buffer & mag, const Buffer & phase)
326 {
327  Buffer zeros = 0.0 * mag;
328 
329  *real_ = 2.0 * mag;
330  *real_ << zeros;
331 
332  *imag_ = 2.0 * phase;
333  *imag_ << zeros;
334 
335  is_polar_ = true;
336 }
337 
338 void
341 {
342  if(!is_polar_) return;
343 
344  uint32 n_samples = real_->getLength();
345 
346  float64 m = 0.0;
347  float64 p = 0.0;
348 
349  for(uint32 j = 0; j < n_samples; ++j)
350  {
351  m = (*real_)[j];
352  p = (*imag_)[j];
353  (*real_)[j] = m * std::cos(p);
354  (*imag_)[j] = m * std::sin(p);
355  }
356 
357  is_polar_ = false;
358 }
359 
360 void
363 {
364  if(is_polar_) return;
365 
366  uint32 n_samples = real_->getLength();
367 
368  float64 r = 0.0;
369  float64 i = 0.0;
370 
371  for(uint32 j = 0; j < n_samples; ++j)
372  {
373  r = (*real_)[j];
374  i = (*imag_)[j];
375 
376  (*real_)[j] = std::sqrt(r*r + i*i);
377  (*imag_)[j] = std::atan(i / r);
378 
379  if(i < 0.0 && r < 0.0) (*imag_)[j] -= M_PI;
380  if(i >= 0.0 && r < 0.0) (*imag_)[j] += M_PI;
381  }
382 
383  is_polar_ = true;
384 }
385 
386 //~///////////////////////////////////////////////////////////////////////////////
387 //~FFTChunk
388 //~FFTChunkVector::
389 //~getMean() const
390 //~{
391 //~ FFTChunk chunk;
392 
393 //~ uint32 n_chunks = this->size();
394 
395 //~ if(n_chunks == 0) return chunk;
396 
397 //~ chunk = (*this)[0];
398 
399 //~ for(uint32 i = 1; i < n_chunks; ++i)
400 //~ {
401 //~ *chunk.real_ += *(*this)[i].real_;
402 //~ *chunk.imag_ += *(*this)[i].imag_;
403 //~ }
404 
405 //~ float64 n = static_cast<float64>(n_chunks);
406 
407 //~ *chunk.real_ /= n;
408 //~ *chunk.imag_ /= n;
409 
410 //~ return chunk;
411 //~}
412 
413 //~///////////////////////////////////////////////////////////////////////////////
414 //~FFTChunk
415 //~FFTChunkVector::
416 //~getMax() const
417 //~{
418 //~ FFTChunk chunk;
419 
420 //~ uint32 n_chunks = this->size();
421 
422 //~ if(n_chunks == 0) return chunk;
423 
424 //~ chunk = (*this)[0];
425 
426 //~ for(uint32 i = 1; i < n_chunks; ++i)
427 //~ {
428 //~ Buffer mag1 = chunk.getMagnitude();
429 //~ Buffer mag2 = (*this)[i].getMagnitude();
430 
431 //~ for(uint32 j = 0; j < mag1.getLength(); ++j)
432 //~ {
433 //~ if(mag2[j] > mag1[j])
434 //~ {
435 //~ (*chunk.real_)[j] = (*(*this)[i].real_)[j];
436 //~ (*chunk.imag_)[j] = (*(*this)[i].imag_)[j];
437 //~ }
438 //~ }
439 //~ }
440 
441 //~ return chunk;
442 //~}
443 
444 //~///////////////////////////////////////////////////////////////////////////////
445 //~FFTChunk
446 //~FFTChunkVector::
447 //~getMin() const
448 //~{
449 //~ FFTChunk chunk;
450 
451 //~ uint32 n_chunks = this->size();
452 
453 //~ if(n_chunks == 0) return chunk;
454 
455 //~ chunk = (*this)[0];
456 
457 //~ for(uint32 i = 1; i < n_chunks; ++i)
458 //~ {
459 //~ Buffer mag1 = chunk.getMagnitude();
460 //~ Buffer mag2 = (*this)[i].getMagnitude();
461 
462 //~ for(uint32 j = 0; j < mag1.getLength(); ++j)
463 //~ {
464 //~ if(mag2[j] < mag1[j])
465 //~ {
466 //~ (*chunk.real_)[j] = (*(*this)[i].real_)[j];
467 //~ (*chunk.imag_)[j] = (*(*this)[i].imag_)[j];
468 //~ }
469 //~ }
470 //~ }
471 
472 //~ return chunk;
473 //~}
474 
Buffer subbuffer(uint32 start_index, uint32 n_samples=0) const
Slice the Buffer.
Definition: Buffer.cc:2073
unsigned int uint32
Definition: Nsound.h:153
void xlabel(const std::string &label, const std::string &kwargs="")
Add a label x axis.
Definition: Plotter.cc:1154
Buffer getFrequencyAxis() const
Definition: FFTChunk.cc:109
Buffer getImaginary() const
Definition: FFTChunk.cc:87
void dB()
Modifies the Buffer so each sample is converted to dB, 20 * log10(sample).
Definition: Buffer.cc:567
FFTChunk & operator=(const FFTChunk &rhs)
Definition: FFTChunk.cc:214
Results of performing an FFT are stored in this class.
Definition: FFTChunk.h:49
void plot(const Buffer &y, const std::string &fmt="", const std::string &kwargs="")
Plots the Buffer on the current figure.
Definition: Plotter.cc:765
void toCartesian()
convertes the magnitude & phase to cartesian form: real & imaginary
Definition: FFTChunk.cc:340
#define M_PI
Definition: Nsound.h:121
void figure(const std::string &kwargs="") const
Creates a new figure window to plot in.
Definition: Plotter.cc:455
void title(const std::string &title, const std::string &kwargs="")
Add a title to the plot at the top and centered.
Definition: Plotter.cc:1127
Buffer getReal() const
Definition: FFTChunk.cc:127
Buffer * imag_
Definition: FFTChunk.h:106
void plot(const std::string &title="", boolean dB=true, boolean show_phase=false) const
Definition: FFTChunk.cc:232
double float64
Definition: Nsound.h:146
void setPolar(const Buffer &magnitude, const Buffer &phase)
Sets up an FFTChunk to use the provided magnitude & phase.
Definition: FFTChunk.cc:325
void toPolar()
convertes the real & imaginary unit to plor form: magnitude & phase
Definition: FFTChunk.cc:362
uint32 getLength() const
Returns the number of samples in the Buffer.
Definition: Buffer.h:587
Buffer getMagnitude() const
Definition: FFTChunk.cc:149
Axes subplot(const uint32 n_rows, const uint32 n_cols, const uint32 n, const std::string &kwargs="", Axes *sharex=NULL, Axes *sharey=NULL)
Creates a figure in a subplot, subplot(A, B, C, **kwargs)
Definition: Plotter.cc:1031
Buffer getPhase() const
Definition: FFTChunk.cc:175
uint32 original_size_
Definition: FFTChunk.h:113
boolean is_polar_
Definition: FFTChunk.h:114
uint32 sample_rate_
Definition: FFTChunk.h:108
void ylabel(const std::string &label, const std::string &kwargs="")
Add a label y axis.
Definition: Plotter.cc:1180
FFTChunk(uint32 size=32, uint32 sample_rate=44100, uint32 original_size=0)
Definition: FFTChunk.cc:46
Buffer * real_
Definition: FFTChunk.h:105
A Buffer for storing audio samples.
Definition: Buffer.h:60
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 setCartesian(const Buffer &real, const Buffer &imaginary)
Sets up an FFTChunk to use the provided real & imaginary.
Definition: FFTChunk.cc:310
A class the provides draw utilities and a wavetable oscillator.
Definition: Generator.h:50