CSL  6.0
FFT_Wrapper.cpp
Go to the documentation of this file.
1 //
2 // FFT_Wrapper.cpp -- wrapper class for FFTs that hides implementation details
3 // This file includes the 3 standard concrete subclasses:
4 // FFTW (assumes fftw3f),
5 // RealFFT (RealFFT code included in CSL), and
6 // KISS FFT (included, untested).
7 //
8 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
9 //
10 
11 #include "FFT_Wrapper.h"
12 #include "math.h"
13 #include <string.h> // for memcpy
14 
15 using namespace csl;
16 
17 //-------------------------------------------------------------------------------------------------//
18 
19 #ifdef USE_FFTW // the FFTW-based version
20 
21 // FFTW_Wrapper = FFTW-based concrete implementation
22 
23 FFTW_Wrapper::FFTW_Wrapper(unsigned size, CSL_FFTType type, CSL_FFTDir forward)
24  : Abst_FFT_W(size, type, forward) {
25  // allocate buffers
26  mSampBuf = (SampleBuffer) fftwf_malloc(size * sizeof(sample));
27  mSpectBuf = (fftwf_complex *) fftwf_malloc(mCSize * sizeof(fftwf_complex));
28 
29  if (mDirection == CSL_FFT_FORWARD) { // create FFT plans
30  // (int n, float *in, fftw_complex *out, unsigned flags);
31  mPlan = fftwf_plan_dft_r2c_1d(size, mSampBuf, mSpectBuf, FFTWF_FLAGS);
32  } else { // inverse FFT
33  // int n, fftw_complex *in, float *out, unsigned flags);
34  mPlan = fftwf_plan_dft_c2r_1d(size, mSpectBuf, mSampBuf, FFTWF_FLAGS);
35  }
36 // logMsg("FFTW %d", size);
37 }
38 
39 FFTW_Wrapper::~FFTW_Wrapper() {
40  fftwf_destroy_plan(mPlan);
41  fftwf_free(mSampBuf);
42  fftwf_free(mSpectBuf);
43 }
44 
45 /// run the transform
46 
47 void FFTW_Wrapper::nextBuffer(Buffer & in, Buffer & out) throw (CException) {
48 
49  if (mDirection == CSL_FFT_FORWARD) { // mDirection == CSL_FFT_FORWARD
50  // copy input into sample buffer
51  memcpy(mSampBuf, in.buffer(0), mSize * sizeof(sample));
52 // printf("\t%x - %x\n", in.buffer(0), out.buffer(0));
53 
54  fftwf_execute(mPlan); //// GO ////
55 
56  SampleBuffer ioPtr = out.buffer(0); // out buffer
57  fftwf_complex * spPtr = mSpectBuf; // spectrum ptr
58 
59  if (mType == CSL_FFT_REAL) { // real: write magnitude to mono output
60  for (unsigned j = 0; j < mCSize; j++, spPtr++)
61  *ioPtr++ = hypotf((*spPtr)[0], (*spPtr)[0]);
62 
63  } else if (mType == CSL_FFT_COMPLEX) { // copy complex ptr to output
64  memcpy(out.buffer(0), mSpectBuf + 1, (mSize * sizeof(sample)));
65 // memcpy(out.buffer(0), mSpectBuf, (mCSize * sizeof(fftwf_complex)));
66 
67  } else if (mType == CSL_FFT_MAGPHASE) { // write mag/phase to buffer[0]/[1]
68  SampleBuffer inOutPh = out.buffer(1);
69  for (unsigned j = 0; j < in.mNumFrames; j++) {
70  // fprintf(stderr, "re:%f cx:%f ", (*spPtr)[0], (*spPtr)[1]);
71  *ioPtr++ = hypotf((*spPtr)[0], (*spPtr)[1]); // write magnitude
72  spPtr++;
73  if ((*spPtr)[0] == 0.0f) {
74  if ((*spPtr)[1] >= 0.0f)
75  *inOutPh++ = CSL_PIHALF;
76  else
77  *inOutPh++ = CSL_PI + CSL_PIHALF;
78  } else {
79  *inOutPh++ = atan((*spPtr)[1] / (*spPtr)[0]); // write phase
80  }
81  }
82  }
83  } else { // mDirection == CSL_FFT_INVERSE
84  // copy data into spectrum
85  memcpy(mSpectBuf, in.buffer(0), (mCSize * sizeof(fftwf_complex)));
86 
87  fftwf_execute(mPlan); // GO
88  // copy real output
89  memcpy(out.buffer(0), mSampBuf, (mSize * sizeof(sample)));
90  }
91 }
92 
93 #endif // FFTW
94 
95 //-------------------------------------------------------------------------------------------------//
96 
97 #ifdef USE_FFTREAL // the FFTReal-based version
98 
99 // FFTR_Wrapper = FFTReal-based concrete implementation
100 
101 FFTR_Wrapper::FFTR_Wrapper(unsigned size, CSL_FFTType type, CSL_FFTDir forward)
102  : Abst_FFT_W(size, type, forward), mFFT(size) {
103  SAFE_MALLOC(mTempBuf, sample, size + 1);
104 // logMsg("FFTReal %d", size);
105 }
106 
107 FFTR_Wrapper::~FFTR_Wrapper() {
108  SAFE_FREE(mTempBuf);
109 }
110 
111 // execute = run the transform
112 
113 void FFTR_Wrapper::nextBuffer(Buffer & in, Buffer & out) throw (CException) {
114  if (mDirection == CSL_FFT_FORWARD) { // mDirection == CSL_FFT_FORWARD
115  SampleBuffer ioPtr = in.buffer(0); // set input data ptr
116 // printf("\t%x - %x\n", in.buffer(0), out.buffer(0));
117 
118  mFFT.do_fft(mTempBuf, ioPtr); // perform FFT
119 
120 // do_fft (flt_t f [], const flt_t x []) -- this is the fcn signature
121 // - x: pointer on the source array (time).
122 // - f: pointer on the destination array (frequencies).
123 // f [0...length(x)/2] = real values,
124 // f [length(x)/2+1...length(x)-1] = imaginary values of coeff 1...length(x)/2-1.
125 
126  if (mType == CSL_FFT_COMPLEX) { // raw: copy complex points to output
127  SampleComplexPtr cxPtr = (SampleComplexPtr) out.buffer(0);
128  SampleBuffer rPtr = mTempBuf;
129  SampleBuffer iPtr = mTempBuf + (mSize / 2) ; // + 1;
130  float normFactor = 1.0 / sqrt((double) mSize);
131  for (unsigned j = 0; j < mSize / 2; j++) {
132  SampleBuffer cplx = cxPtr[j];
133  cx_r(cplx) = *rPtr++ * normFactor;
134  cx_i(cplx) = *iPtr++ * normFactor;
135  }
136  } else if (mType == CSL_FFT_REAL) { // real: write magnitude to mono output
137  ioPtr = out.buffer(0); // output pointer
138  SampleBuffer rPtr = mTempBuf;
139  SampleBuffer iPtr = mTempBuf + (mSize / 2) ; // + 1;
140  for (unsigned j = 0; j < mSize / 2; j++)
141  *ioPtr++ = hypotf(*rPtr++, *iPtr++);
142  } else if (mType == CSL_FFT_MAGPHASE) { // complex: write mag/phase to buffer[0]/[1]
143  ioPtr = out.buffer(0); // output pointer
144  SampleBuffer rPtr = mTempBuf;
145  SampleBuffer iPtr = mTempBuf + (mSize / 2);
146  SampleBuffer inOutPh = out.buffer(1);
147  for (unsigned j = 0; j < mSize / 2; j++) {
148  *ioPtr++ = hypotf(*rPtr, *iPtr);
149  if (*rPtr == 0.0f) {
150  if (*iPtr >= 0.0f)
151  *inOutPh++ = CSL_PIHALF;
152  else
153  *inOutPh++ = CSL_PI + CSL_PIHALF;
154  } else {
155  *inOutPh++ = atan(*iPtr / *rPtr);
156  }
157  rPtr++;
158  iPtr++;
159  } // end of loop
160  }
161  } else { // mDirection == CSL_FFT_INVERSE
162  if (mType == CSL_FFT_COMPLEX) { // CSL_FFT_COMPLEX format
163  // copy complex spectrum to un-packed IFFT format
164  SampleComplexPtr ioPtr = (SampleComplexPtr) in.buffer(0);
165  SampleBuffer rPtr = mTempBuf; // copy data to FFTReal format
166  SampleBuffer iPtr = mTempBuf + (mSize / 2);
167 
168  for (unsigned j = 0; j < mSize / 2; j++) { // loop to unpack complex array
169  SampleBuffer cplx = ioPtr[j];
170  *rPtr++ = cx_r(cplx);
171  *iPtr++ = cx_i(cplx);
172  }
173  } else if (mType == CSL_FFT_REAL) { // real: copy real spectrum to un-packed IFFT format
174  SampleBuffer ioPtr = in.buffer(0);
175  SampleBuffer rPtr = mTempBuf; // copy data to FFTReal format
176  SampleBuffer iPtr = mTempBuf + (mSize / 2);
177 
178  for (unsigned j = 0; j < mSize / 2; j++) { // loop to unpack real array
179  *rPtr++ = *ioPtr++;
180  *iPtr++ = 0.0f;
181  }
182  }
183  SampleBuffer oPtr = out.buffer(0); // output pointer
184 
185  mFFT.do_ifft(mTempBuf, oPtr);
186 
187 // do_ifft (const flt_t f [], flt_t x [])
188 // - f: pointer on the source array (frequencies).
189 // f [0...length(x)/2] = real values,
190 // f [length(x)/2+1...length(x)] = imaginary values of coeff 1...length(x)-1.
191 // - x: pointer on the destination array (time).
192 
193  }
194 }
195 
196 #endif
197 
198 //-------------------------------------------------------------------------------------------------//
199 
200 
201 #ifdef USE_KISSFFT
202 
203 // KISSFFT_Wrapper = KISS FFT-based concrete implementation
204 
205 KISSFFT_Wrapper::KISSFFT_Wrapper(unsigned size, CSL_FFTType type, CSL_FFTDir forward)
206  : Abst_FFT_W(size, type, forward) {
207  int dir = (forward == CSL_FFT_FORWARD) ? 0 : 1;
208  mFFT = kiss_fft_alloc(size, dir, NULL, NULL);
209  SAFE_MALLOC(inBuf, SampleComplex, size);
210  SAFE_MALLOC(outBuf, SampleComplex, size);
211 }
212 
213 KISSFFT_Wrapper::~KISSFFT_Wrapper() {
214  free(mFFT);
215  kiss_fft_cleanup();
216 }
217 
218 // run the transform between in and out
219 
220 void KISSFFT_Wrapper::nextBuffer(Buffer & in, Buffer & out) throw (CException) {
221 
222  if (mDirection == CSL_FFT_FORWARD) { // mDirection == CSL_FFT_FORWARD
223  SampleBuffer ioPtr = in.buffer(0); // input data ptr
224  SampleComplexPtr cxPtr = inBuf;
225  for (int j = 0; j < mSize; j++) { // loop to pack complex array
226  *cxPtr[0] = *ioPtr++;
227  cxPtr++;
228  }
229 
230 // kiss_fft(kiss_fft_cfg cfg, const kiss_fft_cpx *fin, kiss_fft_cpx *fout)
231 // Perform an FFT on a complex input buffer.
232 // for a forward FFT,
233 // fin should be f[0] , f[1] , ... ,f[nfft-1]
234 // fout will be F[0] , F[1] , ... ,F[nfft-1]
235 // Note that each element is complex and can be accessed like f[k].r and f[k].i
236 
237  kiss_fft(mFFT, (const kiss_fft_cpx *) inBuf, (kiss_fft_cpx *) outBuf);
238 
239  ioPtr = out.buffer(0); // output pointer
240  if (mType == CSL_FFT_REAL) { // real: write magnitude to mono output
241  SampleBuffer rPtr = mTempBuf;
242  SampleBuffer iPtr = mTempBuf + (mSize / 2);
243  *ioPtr++ = *rPtr++;
244  *ioPtr++;
245  for (int j = 1; j < mSize; j++)
246  *ioPtr++ = hypotf(*rPtr++, *iPtr++);
247  } else if (mType == CSL_FFT_COMPLEX) { // raw: copy complex points to output
248  memcpy(ioPtr, outBuf, mSize * sizeof(SampleComplex));
249  }
250  } else { // mDirection == CSL_FFT_INVERSE
251 
252  kiss_fft(mFFT, (const kiss_fft_cpx *) in.buffer(0), (kiss_fft_cpx *) outBuf);
253 
254  SampleComplexPtr cxPtr = outBuf;
255  SampleBuffer ioPtr = out.buffer(0);
256  for (int j = 0; j < mSize; j++) // loop to unpack complex array
257  *ioPtr++ = cxPtr[j][0];
258  }
259 }
260 
261 #endif
sample * SampleBuffer
1-channel buffer data type, vector of (sample)
Definition: CSL_Types.h:194
CSL_FFTType
real/complex flag (determines results from forward FFT)
Definition: FFT_Wrapper.h:55
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Definition: Accessor.h:17
#define cx_i(val)
Definition: CSL_Types.h:200
#define CSL_PI
Definition: CSL_Types.h:334
#define cx_r(val)
complex # accesor macros
Definition: CSL_Types.h:199
Abstract FFT class can do forward/reverse real/complex I/O FFTs.
Definition: FFT_Wrapper.h:72
float sample
(could be changed to int, or double)
Definition: CSL_Types.h:191
static size_t size
Definition: fft_N.c:40
#define SAFE_FREE(ptr)
Definition: CGestalt.h:137
SampleComplex * SampleComplexPtr
complex pointer
Definition: CSL_Types.h:203
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
Definition: CSL_Core.h:106
CSL_FFTDir
forward/reverse flag (determines FFT direction)
Definition: FFT_Wrapper.h:63
#define CSL_PIHALF
Definition: CSL_Types.h:337
sample SampleComplex[2]
array-of-2 complex # type (like FFTW)
Definition: CSL_Types.h:198
#define SAFE_MALLOC(ptr, type, len)
Useful Macros.
Definition: CGestalt.h:103
Base class of CSL exceptions (written upper-case). Has a string message.