Nsound  0.9.4
FFTransform_UnitTest.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //
3 // $Id: FFTransform_UnitTest.cc 874 2014-09-08 02:21:29Z weegreenblobbie $
4 //
5 // Copyright (c) 2006 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/Cosine.h>
31 #include <Nsound/FFTransform.h>
32 #include <Nsound/Plotter.h>
33 #include <Nsound/Sine.h>
34 #include <Nsound/Wavefile.h>
35 
36 #include "UnitTest.h"
37 
38 #include <stdlib.h>
39 #include <iostream>
40 
41 using namespace Nsound;
42 
43 using std::cout;
44 using std::cerr;
45 using std::endl;
46 using std::flush;
47 
48 static const char * THIS_FILE = "FFTransform_UnitTest.cc";
49 
50 static const float64 GAMMA = 1.0e-11;
51 
52 void
54 {
55  cout << endl << THIS_FILE;
56 
59 
60  Cosine cos(512);
61 
62  Buffer input = cos.buzz(1.0, 8.0, 2.0, 0.0);
63 
64  FFTransform fft(512);
65 
66  FFTChunkVector vec;
67 
68  Buffer gold;
69 
70  cout << TEST_HEADER << "Testing FFTransform::fft(), ifft() ..." << flush;
71 
72  vec = fft.fft(input, 128, 0);
73 
74  if(vec.size() != 512 / 128)
75  {
76  cerr << TEST_ERROR_HEADER
77  << "Output did not match!"
78  << endl
79  << "vec.size() = " << vec.size() << " != " << 512 / 128
80  << endl;
81 
82  exit(1);
83  }
84 
85  Buffer data = fft.ifft(vec);
86 
87 //~ input.plot("input");
88 //~ data.plot("fft,ifft");
89 
90  if(data.getLength() != input.getLength())
91  {
92  cerr << TEST_ERROR_HEADER
93  << "Output did not match!"
94  << endl
95  << "result.getLength() = " << data.getLength() << " != "
96  << input.getLength()
97  << endl;
98 
99  exit(1);
100  }
101 
102  // Create gold file
103 //~ data >> "gold/FFTransform_out1.wav";
104 
105  gold = Buffer("gold/FFTransform_out1.wav");
106 
107  Buffer diff = data - gold;
108 
109  if(diff.getAbs().getMax() > GAMMA)
110  {
111  cerr << TEST_ERROR_HEADER
112  << "Output did not match gold file!"
113  << endl;
114 
115  diff.plot("input - gold");
116  data.plot("data");
117  gold.plot("gold");
118 
119  Plotter::show();
120  exit(1);
121  }
122 
123  cout << SUCCESS;
124 
125  cout << TEST_HEADER << "Testing FFTChunk::getReal(), getImaginary() ..." << flush;
126 
127  vec = fft.fft(input, 128, 0);
128 
129  Buffer real = vec[0].getReal();
130  Buffer img = vec[0].getImaginary();
131 
132  // Create gold files.
133 //~ real >> "gold/FFTransform_out2.wav";
134 //~ img >> "gold/FFTransform_out3.wav";
135 
136  gold = Buffer("gold/FFTransform_out2.wav");
137 
138  diff = real - gold;
139  diff.abs();
140  if(diff.getMax() > GAMMA)
141  {
142  cerr << TEST_ERROR_HEADER
143  << "Output did not match gold file!"
144  << endl;
145 
146  diff.plot("real - gold");
147  real.plot("real");
148  gold.plot("gold");
149 
150  Plotter::show();
151  exit(1);
152  }
153 
154  gold = Buffer("gold/FFTransform_out3.wav");
155 
156  diff = img - gold;
157  diff.abs();
158 
159  if(diff.getMax() > GAMMA)
160  {
161  cerr << TEST_ERROR_HEADER
162  << "Output did not match gold file!"
163  << endl;
164 
165  diff.plot("img - gold");
166  img.plot("img");
167  gold.plot("gold");
168 
169  Plotter::show();
170  exit(1);
171  }
172 
173  cout << SUCCESS;
174 
175  cout << TEST_HEADER << "Testing FFTChunk::getMagnitude(), getPhase() ..." << flush;
176 
177  vec = fft.fft(input, 128, 0);
178 
179  Buffer mag = vec[0].getMagnitude();
180  Buffer phase = vec[0].getPhase();
181 
182  // Create gold files.
183 //~ mag >> "gold/FFTransform_out4.wav";
184 //~ phase >> "gold/FFTransform_out5.wav";
185 
186  gold = Buffer("gold/FFTransform_out4.wav");
187 
188  diff = mag - gold;
189 
190  if(diff.getAbs().getMax() > GAMMA)
191  {
192  cerr << TEST_ERROR_HEADER
193  << "Output did not match gold file!"
194  << endl;
195 
196  diff.plot("data - gold");
197  mag.plot("data");
198  gold.plot("gold");
199 
200  Plotter::show();
201  exit(1);
202  }
203 
204  gold = Buffer("gold/FFTransform_out5.wav");
205 
206  diff = phase - gold;
207 
208  diff(diff > 2.0 * M_PI - 0.01) = 0.0;
209  diff(diff < 2.0 * M_PI - 0.01) = 0.0;
210 
211  if(diff.getAbs().getMax() > GAMMA)
212  {
213  cerr << TEST_ERROR_HEADER
214  << "Output did not match gold file!"
215  << endl;
216 
217  diff.plot("phase - gold");
218  phase.plot("phase");
219  gold.plot("gold");
220 
221  Plotter::show();
222  exit(1);
223  }
224 
225  cout << SUCCESS;
226 
227  cout << TEST_HEADER << "Testing FFTChunk::toCartesian(), toPolar() ..." << flush;
228 
229  vec[0].toPolar();
230 
231  mag = vec[0].getMagnitude();
232  phase = vec[0].getPhase();
233 
234  gold = Buffer("gold/FFTransform_out4.wav");
235 
236  diff = mag - gold;
237 
238  if(diff.getAbs().getMax() > GAMMA)
239  {
240  cerr << TEST_ERROR_HEADER
241  << "Output did not match gold file!"
242  << endl;
243 
244  diff.plot("data - gold");
245  mag.plot("data");
246  gold.plot("gold");
247 
248  Plotter::show();
249  exit(1);
250  }
251 
252  gold = Buffer("gold/FFTransform_out5.wav");
253 
254  diff = phase - gold;
255  diff.abs();
256  if(diff.getMax() > 2*M_PI)
257  {
258  cerr << TEST_ERROR_HEADER
259  << "Output did not match gold file!"
260  << endl;
261 
262  diff.plot("phase - gold");
263  phase.plot("phase");
264  gold.plot("gold");
265 
266  Plotter::show();
267  exit(1);
268  }
269 
270  cout << SUCCESS;
271 
272  cout << TEST_HEADER << "Testing FFTChunk::setCartesian(), setPolar() ..." << flush;
273 
274  vec = fft.fft(input, 512, 0);
275 
276  mag = vec[0].getMagnitude();
277  phase = vec[0].getPhase();
278 
279  FFTChunk orig(vec[0]);
280  FFTChunk chunk(512, 512);
281 
282  chunk.setPolar(mag, phase);
283 
284  vec[0] = chunk;
285 
286  data = fft.ifft(vec);
287 
288  diff = data - input;
289 
290  if(diff.getAbs().getMax() > 0.005)
291  {
292  cerr << TEST_ERROR_HEADER
293  << "Output did not match gold file!"
294  << endl;
295 
296  diff.plot("data - gold");
297  data.plot("data");
298  input.plot("gold");
299 
300  Plotter::show();
301  exit(1);
302  }
303 
304  chunk.setCartesian(orig.getReal(), orig.getImaginary());
305 
306  vec[0] = chunk;
307 
308  data = fft.ifft(vec);
309 
310  diff = data - input;
311 
312  if(diff.getAbs().getMax() > 2*GAMMA)
313  {
314  cerr << TEST_ERROR_HEADER
315  << "Output did not match gold file!"
316  << endl;
317 
318  diff.plot("data - gold");
319  data.plot("data");
320  input.plot("gold");
321 
322  Plotter::show();
323  exit(1);
324  }
325 
326  cout << SUCCESS;
327 
328  cout << TEST_HEADER << "Testing FFTChunk::getFrequencyAxis() ..." << flush;
329 
330  data = vec[0].getFrequencyAxis();
331 
332 //~ // Create gold files.
333 //~ data >> "gold/FFTransform_out6.wav";
334 
335  gold = Buffer("gold/FFTransform_out6.wav");
336 
337  diff = data - gold;
338 
339  if(diff.getAbs().getMax() > 1e-16)
340  {
341  cerr << TEST_ERROR_HEADER
342  << "Output did not match gold file!"
343  << endl;
344 
345  diff.plot("data - gold");
346  data.plot("data");
347  gold.plot("gold");
348 
349  Plotter::show();
350  exit(1);
351  }
352 
353  cout << SUCCESS << endl;
354 }
Buffer getImaginary() const
Definition: FFTChunk.cc:87
static void show()
Acutally draw the plots to the screen.
Definition: Plotter.cc:252
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
#define M_PI
Definition: Nsound.h:121
DOXME.
Definition: Cosine.h:44
void plot(const std::string &title="Buffer") const
Requires matplotlib. Creates a plot of this Buffer.
Definition: Buffer.cc:1551
#define TEST_HEADER
Definition: Test.h:45
Buffer getReal() const
Definition: FFTChunk.cc:127
static const char * THIS_FILE
Buffer getAbs() const
Modifies a copy of the Buffer by making any negative value positive.
Definition: Buffer.h:174
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
uint32 getLength() const
Returns the number of samples in the Buffer.
Definition: Buffer.h:587
#define TEST_ERROR_HEADER
Definition: Test.h:49
float64 buzz(const float64 &frequency, const float64 &n_harmonics, const float64 &delay)
Returns sample from a set of harmonics. Based on the Csound buzz opcode.
Definition: Generator.cc:260
static void setIEEEFloat(boolean flag)
Definition: Wavefile.cc:98
void abs()
Modifies the Buffer by making any negative value positive.
Definition: Buffer.cc:119
A Class that performes the Fast Fouier Transfrom on a Buffer.
Definition: FFTransform.h:57
#define SUCCESS
Definition: UnitTest.h:42
A Buffer for storing audio samples.
Definition: Buffer.h:60
Buffer fft(const Buffer &time_domain) const
Transforms the time_domain signal and calculates the FFT.
Definition: FFTransform.cc:50
static const float64 GAMMA
static void setDefaultSampleSize(uint32 size)
Definition: Wavefile.cc:79
void FFTransform_UnitTest()
float64 getMax() const
Returns the maximum sample value in the Buffer.
Definition: Buffer.cc:951
void setCartesian(const Buffer &real, const Buffer &imaginary)
Sets up an FFTChunk to use the provided real & imaginary.
Definition: FFTChunk.cc:310
std::vector< FFTChunk > FFTChunkVector
Definition: FFTChunk.h:119