Entropy Piano Tuner  1.1.3 (documentation not yet complete)
An open-source experimental software for piano tuning by entropy minimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
fftimplementation.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2015 Haye Hinrichsen, Christoph Wick
3  *
4  * This file is part of Entropy Piano Tuner.
5  *
6  * Entropy Piano Tuner is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * Entropy Piano Tuner is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * Entropy Piano Tuner. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 //=============================================================================
21 // FFTW3 implementation for fast Fourier transformations
22 //=============================================================================
23 
24 #include "fftimplementation.h"
25 
26 #include <cstring>
27 #include <iostream>
28 #include <typeinfo>
29 
30 #include "../system/eptexception.h"
31 #include "../system/log.h"
32 
33 //-----------------------------------------------------------------------------
34 // static mutex
35 //-----------------------------------------------------------------------------
36 
38 
39 
40 //-----------------------------------------------------------------------------
41 // Constructor
42 //-----------------------------------------------------------------------------
43 
47 
49  mRvec1(nullptr),
50  mRvec2(nullptr),
51  mCvec1(nullptr),
52  mCvec2(nullptr),
53  mNRC(0),
54  mNCR(0),
55  mPlanRC(nullptr),
56  mPlanCR(nullptr)
57 {
58  // Check the consistency of types defined in the adapater:
59  EptAssert (typeid(FFTRealType)==typeid(double),
60  "FFT only implemented for real data type double.");
61  EptAssert (typeid(FFTComplexType)==typeid(std::complex<double>),
62  "FFT only implemented for complex data type std::complex<double>.");
63 }
64 
65 
66 //-----------------------------------------------------------------------------
67 // Destructor
68 //-----------------------------------------------------------------------------
69 
73 
75 {
76  std::lock_guard<std::mutex> lock(mPlanMutex);
77  try
78  {
79  if (mPlanRC) fftw_destroy_plan(mPlanRC);
80  if (mPlanCR) fftw_destroy_plan(mPlanCR);
81  if (mRvec1) free(mRvec1);
82  if (mCvec2) fftw_free(mCvec2);
83  if (mCvec1) fftw_free(mCvec1);
84  if (mRvec2) free(mRvec2);
85  }
86  catch (...) LogE("fftw3_destroy_plan throwed an exception");
87 }
88 
89 
90 //-----------------------------------------------------------------------------
91 // Optimize forward transformation real -> complex
92 //-----------------------------------------------------------------------------
93 
104 
106 {
107  updatePlan(in,FFTW_PATIENT);
108 }
109 
110 
111 //-----------------------------------------------------------------------------
112 // Optimize backward transformation complex -> real
113 //-----------------------------------------------------------------------------
114 
125 
127 {
128  updatePlan(in,FFTW_MEASURE);
129 }
130 
131 
132 //-----------------------------------------------------------------------------
133 // Private function: construct a plan for transformations real->complex
134 //-----------------------------------------------------------------------------
135 
148 
150  unsigned flags)
151 {
152  // if plan still exists and input vector has the same size do nothing
153  if (mPlanRC and mRvec1 and mCvec2 and in.size()==mNRC) return
154  EptAssert(in.size()>0,"vector size has to be nonzero");
155 
156  std::lock_guard<std::mutex> lock(mPlanMutex);
157  try {
158  // delete old plan and vectors
159  if (mPlanRC) fftw_destroy_plan(mPlanRC);
160  if (mRvec1) free(mRvec1);
161  if (mCvec2) fftw_free(mCvec2);
162 
163  // allocate new vectors and create a new plan
164  mNRC = in.size();
165  mRvec1 = (double *) malloc(mNRC*sizeof(double));
166  mCvec2 = (fftw_complex*) fftw_malloc((mNRC/2+1)*sizeof(fftw_complex));
167  EptAssert(mRvec1, "May not be nullptr");
168  EptAssert(mCvec2, "May not be nullptr");
169  mPlanRC = fftw_plan_dft_r2c_1d (mNRC, mRvec1, mCvec2, flags);
170  }
171  catch (...) LogE("fftw_pplan_dft_r2c_1d throwed an exception");
172 }
173 
174 
175 //-----------------------------------------------------------------------------
176 // Private function: construct a plan for transformations complex->real
177 //-----------------------------------------------------------------------------
178 
191 
193  unsigned flags)
194 {
195  // if plan still exists and input vector has the same size do nothing
196  if (mPlanCR and mCvec1 and mRvec2 and in.size()==mNCR/2+1) return;
197  EptAssert(in.size()>0,"vector size has to be nonzero");
198 
199  std::lock_guard<std::mutex> lock(mPlanMutex);
200  try {
201  // delete old plan and vectors
202  if (mPlanCR) fftw_destroy_plan(mPlanCR);
203  if (mCvec1) fftw_free(mCvec1);
204  if (mRvec2) free(mRvec2);
205 
206  // allocate new vectors and create a new plan
207  mNCR = 2*in.size()-2;
208  mCvec1 = (fftw_complex*) fftw_malloc((mNCR/2+1)*sizeof(fftw_complex));
209  mRvec2 = (double *) malloc(mNCR*sizeof(double));
210  EptAssert(mCvec1, "May not be nullptr");
211  EptAssert(mRvec2, "May not be nullptr");
212  mPlanCR = fftw_plan_dft_c2r_1d (mNCR, mCvec1, mRvec2, flags);
213  }
214  catch (...) LogE("fftw_pplan_dft_c2r_1d throwed an exception");
215 }
216 
217 
218 //-----------------------------------------------------------------------------
219 // Calculate forward FFT real -> complex
220 //-----------------------------------------------------------------------------
221 
229 
231 {
232  EptAssert (in.size()>=1,"calling FFT with empty vector");
233  if (out.size() != in.size()/2+1) out.resize(in.size()/2+1);
234  updatePlan(in,FFTW_ESTIMATE);
235  EptAssert (in.size()==mNRC and out.size()==mNRC/2+1,"Vector consistency");
236  try {
237  std::memcpy(mRvec1,in.data(),mNRC*sizeof(double));
238  fftw_execute(mPlanRC);
239  std::memcpy(out.data(),mCvec2,(mNRC/2+1)*sizeof(fftw_complex));
240  }
241  catch (...) LogE("fftw_execute throwed an exception");
242 }
243 
244 
245 //-----------------------------------------------------------------------------
246 // Calculate backward FFT complex -> real
247 //-----------------------------------------------------------------------------
248 
256 
258 {
259  EptAssert (in.size()>=1,"calling FFT with empty vector");
260  if (out.size() != 2*in.size()-2) out.resize(2*in.size()-2);
261  updatePlan(in,FFTW_ESTIMATE);
262  EptAssert (in.size()==mNCR/2+1 and out.size()==mNCR,"Vector consistency");
263  try {
264  std::memcpy(mCvec1,in.data(),(mNCR/2+1)*sizeof(fftw_complex));
265  fftw_execute(mPlanCR);
266  std::memcpy(out.data(),mRvec2,mNCR*sizeof(double));
267  }
268  catch (...) LogE("fftw_execute throwed an exception");
269 }
fftw_complex * mCvec2
Local copy of outgoing complex data.
size_t mNRC
Size of the FFT real -> complex.
size_t mNCR
Size of the FFT complex -> real.
std::vector< FFTComplexType > FFTComplexVector
Definition: fftadapter.h:36
fftw_plan mPlanRC
Plan for FFT real -> complex.
double * mRvec1
Local copy of incoming real data.
std::complex< double > FFTComplexType
Definition: fftadapter.h:34
void updatePlan(const FFTRealVector &in, unsigned flags)
Construct a new plan for the FFT transformation if necessary.
double FFTRealType
Definition: fftadapter.h:33
~FFT_Implementation()
Destructor, deletes plans and local vector copies if existing.
#define LogE(...)
Definition: log.h:62
fftw_plan mPlanCR
Plan for FFT complex -> real.
fftw_complex * mCvec1
Local copy of incoming complex data.
#define EptAssert(a, b)
Definition: eptexception.h:47
std::vector< FFTRealType > FFTRealVector
Definition: fftadapter.h:35
double * mRvec2
Local copy of outgoing real data.
void optimize(FFTRealVector &in)
Optimize plan for the forward transfomation.
void calculateFFT(const FFTRealVector &in, FFTComplexVector &out)
Foward FFT, mapping a real vector with size N to a complex one with size N/2+1.
FFT_Implementation()
Constructor, clears member variables and checks type consistency.
static std::mutex mPlanMutex
Static mutex protecting planmaking.