![]() |
pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
|
00001 /* 00002 ------------------------------------------------------------------------------- 00003 This file is part of the Plink, Plonk, Plank libraries 00004 by Martin Robinson 00005 00006 http://code.google.com/p/pl-nk/ 00007 00008 Copyright University of the West of England, Bristol 2011-14 00009 All rights reserved. 00010 00011 Redistribution and use in source and binary forms, with or without 00012 modification, are permitted provided that the following conditions are met: 00013 00014 * Redistributions of source code must retain the above copyright 00015 notice, this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright 00017 notice, this list of conditions and the following disclaimer in the 00018 documentation and/or other materials provided with the distribution. 00019 * Neither the name of University of the West of England, Bristol nor 00020 the names of its contributors may be used to endorse or promote products 00021 derived from this software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00026 DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF THE WEST OF ENGLAND, BRISTOL BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 This software makes use of third party libraries. For more information see: 00035 doc/license.txt included in the distribution. 00036 ------------------------------------------------------------------------------- 00037 */ 00038 00039 #ifndef PLONK_IFFTCHANNEL_H 00040 #define PLONK_IFFTCHANNEL_H 00041 00042 #include "../channel/plonk_ChannelInternalCore.h" 00043 #include "../plonk_GraphForwardDeclarations.h" 00044 00046 //template<class SampleType> 00047 //class IFFTChannelInternal 00048 //: public ChannelInternal<SampleType, ChannelInternalCore::Data> 00049 //{ 00050 //public: 00051 // typedef ChannelInternalCore::Data Data; 00052 // typedef ChannelBase<SampleType> ChannelType; 00053 // typedef IFFTChannelInternal<SampleType> IFFTInternal; 00054 // typedef ChannelInternal<SampleType,Data> Internal; 00055 // typedef ChannelInternalBase<SampleType> InternalBase; 00056 // typedef UnitBase<SampleType> UnitType; 00057 // typedef InputDictionary Inputs; 00058 // typedef NumericalArray<SampleType> Buffer; 00059 // typedef FFTEngineBase<SampleType> FFTEngineType; 00060 // 00061 // IFFTChannelInternal (Inputs const& inputs, 00062 // Data const& data, 00063 // BlockSize const& blockSize, 00064 // SampleRate const& sampleRate) throw() 00065 // : Internal (inputs, data, blockSize, sampleRate) 00066 // { 00067 // } 00068 // 00069 // Text getName() const throw() 00070 // { 00071 // return "IFFT"; 00072 // } 00073 // 00074 // IntArray getInputKeys() const throw() 00075 // { 00076 // const IntArray keys (IOKey::FFT); 00077 // return keys; 00078 // } 00079 // 00080 // InternalBase* getChannel (const int /*index*/) throw() 00081 // { 00082 // return this; /// ? could create "this" with pairs but no need at the moment 00083 // } 00084 // 00085 // void initChannel (const int /*channel*/) throw() 00086 // { 00087 // const UnitType& input = this->getInputAsUnit (IOKey::FFT); 00088 // 00089 // // check for channel an channel + 1 on the input? 00090 // 00091 // this->setBlockSize (input.getBlockSize (0)); 00092 // this->setSampleRate (input.getSampleRate (0)); 00093 // this->setOverlap (input.getOverlap (0)); 00094 // 00095 // this->fft = FFTEngineType (input.getBlockSize (0)); 00096 // 00097 // this->initValue (SampleType (0)); // impossible to precalculate 00098 // } 00099 // 00100 // void process (ProcessInfo& info, const int channel) throw() 00101 // { 00102 // /* Be careful optimising this with the new NumericalArray vector stuff */ 00103 // 00104 // const int realIndex = channel * 2; 00105 // const int imagIndex = realIndex + 1; 00106 // 00107 // UnitType& inputUnit (this->getInputAsUnit (IOKey::FFT)); 00108 // const Buffer& realBuffer (inputUnit.process (info, realIndex)); 00109 // const Buffer& imagBuffer (inputUnit.process (info, imagIndex)); 00110 // 00111 // plonk_assert (realBuffer.length() == imagBuffer.length()); 00112 // 00113 // const SampleType* const realInputSamples = realBuffer.getArray(); 00114 // const SampleType* const imagInputSamples = imagBuffer.getArray(); 00115 // 00116 // SampleType* const outputSamples = this->getOutputSamples(); 00117 // const int outputBufferLength = this->getOutputBuffer().length(); 00118 // 00119 // plonk_assert (outputBufferLength == realBuffer.length()); 00120 // 00121 // if (outputBufferLength != this->fft.length()) 00122 // this->fft = FFTEngineType (outputBufferLength); 00123 // 00124 // const long halfLength = this->fft.halfLength(); 00125 // 00126 // // pack 00127 // int i, j; 00128 // 00129 // for (i = 0; i <= halfLength; ++i) 00130 // outputSamples[i] = realInputSamples[i]; 00131 // 00132 // for (j = 1; i < outputBufferLength; ++i, ++j) 00133 // outputSamples[i] = imagInputSamples[j]; 00134 // 00135 // // transform 00136 // this->fft.inverse (outputSamples, outputSamples); // in-place 00137 // } 00138 // 00139 //private: 00140 // FFTEngineType fft; 00141 //}; 00142 // 00143 // 00144 // 00146 // 00148 // Takes frequency domain signal in real/imaginary format and outputs the time domain real signal. 00149 // 00150 // Each pair of imput channels generates one output channel. The even numbered channels should conatin 00151 // the real data and the odd numbered channel should contain the imaginary data. (This is the same 00152 // output format as the FFTUnit.) 00153 // 00154 // @par Factory functions: 00155 // - ar (input) 00156 // 00157 // @par Inputs: 00158 // - input: (unit, multi, fft) the input unit in FFT format 00159 // 00160 // 00161 // @ingroup ConverterUnits FFTUnits */ 00162 //template<class SampleType> 00163 //class IFFTUnit 00164 //{ 00165 //public: 00166 // typedef IFFTChannelInternal<SampleType> IFFTInternal; 00167 // typedef typename IFFTInternal::Data Data; 00168 // typedef ChannelBase<SampleType> ChannelType; 00169 // typedef ChannelInternal<SampleType,Data> Internal; 00170 // typedef ChannelInternalBase<SampleType> InternalBase; 00171 // typedef UnitBase<SampleType> UnitType; 00172 // typedef InputDictionary Inputs; 00173 // typedef NumericalArray<SampleType> Buffer; 00174 // 00175 // static inline UnitInfos getInfo() throw() 00176 // { 00177 // return UnitInfo ("IFFT", "Transforms frequency domain data to a time domain signal.", 00178 // 00179 // // output 00180 // 1, 00181 // IOKey::Generic, Measure::None, IOInfo::NoDefault, IOLimit::None, 00182 // IOKey::End, 00183 // 00184 // // inputs 00185 // IOKey::FFT, Measure::None, 00186 // IOKey::End); 00187 // } 00188 // 00189 // /** IFFTs a signal. */ 00190 // static inline UnitType ar (UnitType const& input) throw() 00191 // { 00192 // // re: full templating - could say that FFT/IFTT are only supported with float (and eventually double)? 00193 // 00194 // plonk_assert ((input.getNumChannels() % 2) == 0); // must be real and imag pairs 00195 // 00196 // // need to put these asserts in the initChannel 00199 // 00200 // const int numOutputChannels = input.getNumChannels() / 2; 00201 // plonk_assert (numOutputChannels > 0); 00202 // 00203 // UnitType result (UnitType::emptyWithAllocatedSize (numOutputChannels)); 00204 // Data data = { -1.0, -1.0 }; 00205 // 00206 // for (int i = 0; i < numOutputChannels; ++i) 00207 // { 00208 // UnitType pair (UnitType::emptyWithAllocatedSize (2)); 00209 // pair.add (input[i * 2]); 00210 // pair.add (input[i * 2 + 1]); 00211 // 00212 // Inputs inputs; 00213 // inputs.put (IOKey::FFT, pair); 00214 // 00215 // InternalBase* internal = new IFFTInternal (inputs, 00216 // data, 00217 // BlockSize::noPreference(), 00218 // SampleRate::noPreference()); 00219 // internal->initChannel (i); 00220 // 00221 // result.add (ChannelType (internal)); 00222 // } 00223 // 00224 // return result; 00225 // 00226 // } 00227 //}; 00228 00230 template<class SampleType> 00231 class IFFTChannelInternal 00232 : public ChannelInternal<SampleType, ChannelInternalCore::Data> 00233 { 00234 public: 00235 typedef ChannelInternalCore::Data Data; 00236 typedef ChannelBase<SampleType> ChannelType; 00237 typedef IFFTChannelInternal<SampleType> IFFTInternal; 00238 typedef ChannelInternal<SampleType,Data> Internal; 00239 typedef ChannelInternalBase<SampleType> InternalBase; 00240 typedef UnitBase<SampleType> UnitType; 00241 typedef InputDictionary Inputs; 00242 typedef NumericalArray<SampleType> Buffer; 00243 typedef FFTEngineBase<SampleType> FFTEngineType; 00244 00245 IFFTChannelInternal (Inputs const& inputs, 00246 Data const& data, 00247 BlockSize const& blockSize, 00248 SampleRate const& sampleRate) throw() 00249 : Internal (inputs, data, blockSize, sampleRate) 00250 { 00251 } 00252 00253 Text getName() const throw() 00254 { 00255 return "IFFT"; 00256 } 00257 00258 IntArray getInputKeys() const throw() 00259 { 00260 const IntArray keys (IOKey::FFTPacked); 00261 return keys; 00262 } 00263 00264 InternalBase* getChannel (const int index) throw() 00265 { 00266 const Inputs channelInputs = this->getInputs().getChannel (index); 00267 return new IFFTInternal (channelInputs, 00268 this->getState(), 00269 this->getBlockSize(), 00270 this->getSampleRate()); 00271 } 00272 00273 void initChannel (const int channel) throw() 00274 { 00275 const UnitType& input = this->getInputAsUnit (IOKey::FFTPacked); 00276 00277 this->setBlockSize (input.getBlockSize (channel)); 00278 this->setSampleRate (input.getSampleRate (channel)); 00279 this->setOverlap (input.getOverlap (channel)); 00280 00281 this->fft = FFTEngineType (input.getBlockSize (channel)); 00282 00283 this->initValue (SampleType (0)); // impossible to precalculate 00284 } 00285 00286 void process (ProcessInfo& info, const int channel) throw() 00287 { 00288 /* Be careful optimising this with the new NumericalArray vector stuff */ 00289 00290 UnitType& inputUnit (this->getInputAsUnit (IOKey::FFTPacked)); 00291 const Buffer& inputBuffer (inputUnit.process (info, channel)); 00292 const SampleType* const inputSamples = inputBuffer.getArray(); 00293 00294 SampleType* const outputSamples = this->getOutputSamples(); 00295 const int outputBufferLength = this->getOutputBuffer().length(); 00296 00297 plonk_assert (outputBufferLength == inputBuffer.length()); 00298 00299 if (outputBufferLength != this->fft.length()) 00300 this->fft = FFTEngineType (outputBufferLength); 00301 00302 this->fft.inverse (outputSamples, inputSamples); // in-place 00303 } 00304 00305 private: 00306 FFTEngineType fft; 00307 }; 00308 00309 00310 00311 //------------------------------------------------------------------------------ 00312 00328 template<class SampleType> 00329 class IFFTUnit 00330 { 00331 public: 00332 typedef IFFTChannelInternal<SampleType> IFFTInternal; 00333 typedef typename IFFTInternal::Data Data; 00334 typedef ChannelBase<SampleType> ChannelType; 00335 typedef ChannelInternal<SampleType,Data> Internal; 00336 typedef ChannelInternalBase<SampleType> InternalBase; 00337 typedef UnitBase<SampleType> UnitType; 00338 typedef InputDictionary Inputs; 00339 typedef NumericalArray<SampleType> Buffer; 00340 00341 static inline UnitInfos getInfo() throw() 00342 { 00343 return UnitInfo ("IFFT", "Transforms frequency domain data to a time domain signal.", 00344 00345 // output 00346 ChannelCount::VariableChannelCount, 00347 IOKey::Generic, Measure::None, IOInfo::NoDefault, IOLimit::None, 00348 IOKey::End, 00349 00350 // inputs 00351 IOKey::FFTPacked, Measure::FFTPacked, IOInfo::NoDefault, IOLimit::None, 00352 IOKey::End); 00353 } 00354 00355 static inline UnitType ar (UnitType const& input) throw() 00356 { 00357 // re: full templating - could say that FFT/IFFT are only supported with float (and eventually double)? 00358 00359 Inputs inputs; 00360 inputs.put (IOKey::FFTPacked, input); 00361 00362 Data data = { -1.0, -1.0 }; 00363 00364 return UnitType::template createFromInputs<IFFTInternal> (inputs, 00365 data, 00366 BlockSize::noPreference(), 00367 SampleRate::noPreference()); 00368 } 00369 00370 }; 00371 00372 00373 typedef IFFTUnit<PLONK_TYPE_DEFAULT> IFFT; 00374 00375 #endif // PLONK_IFFTCHANNEL_H 00376 00377