Nsound  0.9.4
FFTransform.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //
3 // $Id: FFTransform.cc 874 2014-09-08 02:21:29Z weegreenblobbie $
4 //
5 // Copyright (c) 2007-Present 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/FFTransform.h>
32 #include <Nsound/Generator.h>
33 #include <Nsound/Plotter.h>
34 
35 #include <cmath>
36 
37 using namespace Nsound;
38 
39 //-----------------------------------------------------------------------------
41 FFTransform(const float64 & sample_rate)
42  :
43  sample_rate_(static_cast<uint32>(sample_rate)),
44  type_(RECTANGULAR)
45 {
46 }
47 
48 Buffer
50 fft(const Buffer & time_domain) const
51 {
52  int32 N = roundUp2(time_domain.getLength());
53 
54  FFTChunkVector v = fft(time_domain, N);
55 
56  if(v.size() >= 1)
57  {
58  // Calculate the magnitude of the frequency domain.
59  Buffer f_domain = v[0].getMagnitude();
60 
61  // Resample so to return exacly sample_rate / 2 samples.
62  float64 sr_2 = sample_rate_ / 2.0;
63 
64  float64 factor = static_cast<float64>(f_domain.getLength()) / sr_2;
65 
66  // Simple down sample.
67  return f_domain.getSpeedUp(factor);
68  }
69 
70  return time_domain;
71 }
72 
75 fft(const Buffer & input, int32 n_order, int32 n_overlap) const
76 {
77  const int32 N = roundUp2(n_order);
78 
79  const int32 input_length = input.getLength();
80 
81  FFTChunkVector vec;
82 
83  Generator gen(1);
84 
85  Buffer fft_window = gen.drawWindow(N, type_);
86 
87  for(int32 n = 0; n < input_length; n += (N - n_overlap))
88  {
89  // Create an FFTChunk to operate on.
90  FFTChunk chunk(N, sample_rate_, input.getLength());
91 
92  // Grab N samples from the input buffer
93 
94  Buffer sub_signal = input.subbuffer(n,N);
95 
96  // Apply window
97  int32 sub_length = sub_signal.getLength();
98  if(sub_length == N)
99  {
100  sub_signal *= fft_window;
101  }
102  else
103  {
104  sub_signal *= gen.drawWindow(sub_length, type_);
105  }
106 
107  (*chunk.real_) = sub_signal;
108 
109  int32 chunk_size = chunk.real_->getLength();
110 
111  // If there is less than N samples, pad with zeros
112  for(int32 i = 0; i < N - chunk_size; ++i)
113  {
114  (*chunk.real_) << 0.0;
115  }
116 
117  // Zero out the imaginary side.
118  (*chunk.imag_) = gen.silence(N);
119 
120  fft(*chunk.real_, *chunk.imag_, N);
121 
122  vec.push_back(chunk);
123  }
124 
125  return vec;
126 }
127 
128 void
130 fft(Buffer & real, Buffer & img, const int32 N) const
131 {
132  const float64 pi = M_PI;
133  const int32 n_minus_1 = N - 1;
134  const int32 n_devide_2 = N / 2;
135  const int32 m = static_cast<uint32>(
136  std::log10(static_cast<float64>(N)) / std::log10(2.0) + 0.5);
137 
138  int32 j = n_devide_2;
139 
140  // Bit reversal sorting.
141  for(int32 i = 1; i <= N - 2 ; ++i)
142  {
143  if(i < j)
144  {
145  float64 temp_real = real[j];
146  float64 temp_img = img[j];
147 
148  real[j] = real[i];
149  img[j] = img[i];
150 
151  real[i] = temp_real;
152  img[i] = temp_img;
153  }
154 
155  int32 k = n_devide_2;
156 
157  while(k <= j)
158  {
159  j -= k;
160  k /= 2;
161  }
162  j += k;
163  }
164 
165  // Loop for each fft stage.
166  for(int32 l = 1; l <= m; ++l)
167  {
168  int32 le = static_cast<int32>(std::pow(2.0, l) + 0.5);
169  int32 le2 = le / 2;
170 
171  float64 ur = 1.0;
172  float64 ui = 0.0;
173 
174  // Calculate sine and cosine values.
175  float64 sr = std::cos(pi / static_cast<float64>(le2));
176  float64 si = -1.0 * std::sin(pi / static_cast<float64>(le2));
177 
178  // Loop for each sub DFT.
179  for(j = 1; j <= le2; ++j)
180  {
181  int32 j_minus_1 = j - 1;
182 
183  // Loop for each butterfly.
184  for(int32 i = j_minus_1; i <= n_minus_1; i += le)
185  {
186  int32 ip = i + le2;
187 
188  // Butterfly calculation.
189  float64 temp_real = ur * real[ip] - ui * img[ip];
190  float64 temp_img = ui * real[ip] + ur * img[ip];
191 
192  real[ip] = real[i] - temp_real;
193  img[ip] = img[i] - temp_img;
194 
195  real[i] += temp_real;
196  img[i] += temp_img;
197  }
198  float64 temp = ur;
199  ur = temp * sr - ui * si;
200  ui = temp * si + ui * sr;
201  }
202  }
203 }
204 
205 Buffer
207 ifft(const FFTChunkVector & vec) const
208 {
209  Buffer output;
210 
211  FFTChunkVector::const_iterator itor = vec.begin();
212  FFTChunkVector::const_iterator end = vec.end();
213 
214  const uint32 N = roundUp2(itor->real_->getLength() - 2);
215  const float64 f_N = static_cast<float64>(N);
216 
217  while(itor != end)
218  {
219  FFTChunk chunk(*itor);
220 
221  if(chunk.isPolar()) chunk.toCartesian();
222 
223  // Change the sign of img.
224  *chunk.imag_ *= -1.0;
225 
226  // Perform the forwared fft
227  fft(*chunk.real_, *chunk.imag_, N);
228 
229  *chunk.real_ = chunk.real_->subbuffer(0, itor->getOriginalSize());
230 
231  // Divide the real by N.
232  *chunk.real_ /= f_N;
233 
234  // Change the sign of img. But the img is never used again so don't
235  // bother.
236 //~ img *= -1.0;
237 
238  output << *chunk.real_;
239 
240  ++itor;
241  }
242 
243  return output;
244 }
245 
246 Buffer
248 ifft(const Buffer & frequency_domain) const
249 {
250  int32 N = roundUp2(frequency_domain.getLength());
251 
252  FFTChunk chunk(N, sample_rate_);
253 
254  *chunk.real_ << frequency_domain;
255 
256  for(uint32 i = 0; i < 2 * (N - frequency_domain.getLength()); ++i)
257  {
258  *chunk.real_ << 0.0;
259  }
260 
261  *chunk.real_ << frequency_domain.getReverse();
262 
263  *chunk.imag_ = 0.0 * *chunk.real_;
264 
265  FFTChunkVector vec;
266 
267  vec.push_back(chunk);
268 
269  return ifft(vec).subbuffer(0, frequency_domain.getLength());
270 }
271 
272 int32
275 {
276  raw = static_cast<int32>(::fabs(static_cast<float64>(raw - 1)));
277 
278  int32 n;
279 
280  n = 1;
281  while(raw)
282  {
283  n <<= 1; // Multiply n by 2
284  raw >>= 1; // Divide raw by 2
285  }
286 
287  return n;
288 }
289 
290 void
293 {
294  type_ = type;
295 }
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
FFTransform(const float64 &sample_rate)
Definition: FFTransform.cc:41
Results of performing an FFT are stored in this class.
Definition: FFTChunk.h:49
Buffer ifft(const FFTChunkVector &input) const
Peforms an inverse FFT on each FFTChunk and concatenates the output.
Definition: FFTransform.cc:207
void toCartesian()
convertes the magnitude & phase to cartesian form: real & imaginary
Definition: FFTChunk.cc:340
#define M_PI
Definition: Nsound.h:121
Buffer * imag_
Definition: FFTChunk.h:106
Buffer drawWindow(const float64 &duration, WindowType type) const
Draws a window of the specified type.
Definition: Generator.cc:702
double float64
Definition: Nsound.h:146
void setWindow(WindowType type)
A window is multiplied by the input prior to performing the transform, this help reduce artifacts nea...
Definition: FFTransform.cc:292
static int32 roundUp2(int32 raw)
Returns nearest power of 2 >= raw.
Definition: FFTransform.cc:274
uint32 getLength() const
Returns the number of samples in the Buffer.
Definition: Buffer.h:587
Buffer silence(const float64 &duration) const
This method generates silence.
Definition: Generator.cc:1310
uint32 sample_rate_
Samples per second.
Definition: FFTransform.h:220
iterator begin()
Retruns the itreator at the start of the Buffer.
Definition: Buffer.h:285
Buffer * real_
Definition: FFTChunk.h:105
A Buffer for storing audio samples.
Definition: Buffer.h:60
signed int int32
Definition: Nsound.h:142
Buffer fft(const Buffer &time_domain) const
Transforms the time_domain signal and calculates the FFT.
Definition: FFTransform.cc:50
Buffer getReverse() const
Reverses the samples in a copy of this Buffer.
Definition: Buffer.h:1558
boolean isPolar() const
Definition: FFTChunk.h:78
std::vector< FFTChunk > FFTChunkVector
Definition: FFTChunk.h:119
WindowType
Definition: WindowType.h:39
A class the provides draw utilities and a wavetable oscillator.
Definition: Generator.h:50
float64 sr
Definition: example3.cc:24