![]() |
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_FFTCHANNEL_H 00040 #define PLONK_FFTCHANNEL_H 00041 00042 #include "../channel/plonk_ChannelInternalCore.h" 00043 #include "../plonk_GraphForwardDeclarations.h" 00044 00046 //template<class SampleType> 00047 //class FFTChannelInternal 00048 //: public ProxyOwnerChannelInternal<SampleType, ChannelInternalCore::Data> 00049 //{ 00050 //public: 00051 // typedef ChannelInternalCore::Data Data; 00052 // typedef ChannelBase<SampleType> ChannelType; 00053 // typedef ObjectArray<ChannelType> ChannelArrayType; 00054 // typedef FFTChannelInternal<SampleType> FFTInternal; 00055 // typedef ProxyOwnerChannelInternal<SampleType,Data> Internal; 00056 // typedef UnitBase<SampleType> UnitType; 00057 // typedef InputDictionary Inputs; 00058 // typedef NumericalArray<SampleType> Buffer; 00059 // typedef FFTEngineBase<SampleType> FFTEngineType; 00060 // 00061 // enum OutputIndices { RealOutput, ImagOutput, NumOutputs }; 00062 // 00063 // FFTChannelInternal (Inputs const& inputs, 00064 // Data const& data, 00065 // BlockSize const& blockSize, 00066 // SampleRate const& sampleRate, 00067 // ChannelArrayType& channels) throw() 00068 // : Internal (NumOutputs, inputs, data, blockSize, sampleRate, channels) 00069 // { 00070 // } 00071 // 00072 // Text getName() const throw() 00073 // { 00074 // return "FFT"; 00075 // } 00076 // 00077 // IntArray getInputKeys() const throw() 00078 // { 00079 // const IntArray keys (IOKey::Generic); 00080 // return keys; 00081 // } 00082 // 00083 // void initChannel (const int channel) throw() 00084 // { 00085 // if ((channel % this->getNumChannels()) == 0) 00086 // { 00087 // const UnitType& input = this->getInputAsUnit (IOKey::Generic); 00088 // 00089 // this->setBlockSize (input.getBlockSize (0)); 00090 // this->setSampleRate (input.getSampleRate (0)); 00091 // this->setOverlap (input.getOverlap (0)); 00092 // 00093 // this->fft = FFTEngineType (input.getBlockSize (0)); 00094 // } 00095 // 00096 // this->initProxyValue (channel, SampleType (0)); // not really applicable with an FFT output 00097 // } 00098 // 00099 // void process (ProcessInfo& info, const int channel) throw() 00100 // { 00101 // /* Be careful optimising this with the new NumericalArray vector stuff */ 00102 // 00103 // UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic)); 00104 // const Buffer& inputBuffer (inputUnit.process (info, channel)); 00105 // const SampleType* const inputSamples = inputBuffer.getArray(); 00106 // 00107 // SampleType* const realOutputSamples = this->getOutputSamples (RealOutput); 00108 // SampleType* const imagOutputSamples = this->getOutputSamples (ImagOutput); 00109 // const int outputBufferLength = this->getOutputBuffer (0).length(); 00110 // 00111 // plonk_assert (outputBufferLength == inputBuffer.length()); 00112 // 00113 // if (outputBufferLength != this->fft.length()) 00114 // this->fft = FFTEngineType (outputBufferLength); 00115 // 00116 // // transform 00117 // this->fft.forward (realOutputSamples, inputSamples); 00118 // 00119 // imagOutputSamples[0] = SampleType (0); 00120 // 00121 // int i, j; 00122 // 00123 // // unpack, assuming samples that should be zero are already zero.. (as they should be). 00124 // for (i = this->fft.halfLength() + 1, j = 1; i < outputBufferLength; ++i, ++j) 00125 // { 00126 // imagOutputSamples[j] = realOutputSamples[i]; 00127 // realOutputSamples[i] = SampleType (0); 00128 // } 00129 // } 00130 // 00131 //private: 00132 // FFTEngineType fft; 00133 //}; 00134 // 00135 // 00136 // 00138 // 00140 // Takes a time domain real signal as its input and outputs frequency domain data in real/imaginary format. 00141 // 00142 // Each input channel generates two output channels. The even number channel is the real data and 00143 // the odd numbered channel contains the imaginary data. (The IFFTUnit expects the data in this format.) 00144 // 00145 // @par Factory functions: 00146 // - ar (input) 00147 // 00148 // @par Inputs: 00149 // - input: (unit, multi) the input unit 00150 // 00151 // 00152 // @ingroup ConverterUnits FFTUnits */ 00153 //template<class SampleType> 00154 //class FFTUnit 00155 //{ 00156 //public: 00157 // typedef FFTChannelInternal<SampleType> FFTInternal; 00158 // typedef typename FFTInternal::Data Data; 00159 // typedef UnitBase<SampleType> UnitType; 00160 // typedef InputDictionary Inputs; 00161 // 00162 // static inline UnitInfos getInfo() throw() 00163 // { 00164 // return UnitInfo ("FFT", "Transforms time domain to frequency domain data.", 00165 // 00166 // // output 00167 // 2, 00168 // IOKey::Real, Measure::Real, IOInfo::NoDefault, IOLimit::None, 00169 // IOKey::Imaginary, Measure::Imaginary, IOInfo::NoDefault, IOLimit::None, 00170 // IOKey::End, 00171 // 00172 // // inputs 00173 // IOKey::Generic, Measure::None, 00174 // IOKey::End); 00175 // } 00176 // 00177 // /** FFTs a signal. */ 00178 // static inline UnitType ar (UnitType const& input) throw() 00179 // { 00180 // // re: full templating - could say that FFT/IFTT are only supported with float (and eventually double)? 00181 // 00182 // const int numInputChannels = input.getNumChannels(); 00183 // UnitType result (UnitType::emptyWithAllocatedSize (numInputChannels * 2)); 00184 // Data data = { -1.0, -1.0 }; 00185 // 00186 // for (int i = 0; i < numInputChannels; ++i) 00187 // { 00188 // Inputs inputs; 00189 // inputs.put (IOKey::Generic, input[i]); 00190 // 00191 // result.add (UnitType::template proxiesFromInputs<FFTInternal> (inputs, 00192 // data, 00193 // BlockSize::noPreference(), 00194 // SampleRate::noPreference())); 00195 // } 00196 // 00197 // return result; 00198 // } 00199 //}; 00200 00202 template<class SampleType> 00203 class FFTChannelInternal 00204 : public ChannelInternal<SampleType, ChannelInternalCore::Data> 00205 { 00206 public: 00207 typedef ChannelInternalCore::Data Data; 00208 typedef ChannelBase<SampleType> ChannelType; 00209 typedef ObjectArray<ChannelType> ChannelArrayType; 00210 typedef FFTChannelInternal<SampleType> FFTInternal; 00211 typedef ChannelInternal<SampleType,Data> Internal; 00212 typedef ChannelInternalBase<SampleType> InternalBase; 00213 typedef UnitBase<SampleType> UnitType; 00214 typedef InputDictionary Inputs; 00215 typedef NumericalArray<SampleType> Buffer; 00216 typedef FFTEngineBase<SampleType> FFTEngineType; 00217 00218 FFTChannelInternal (Inputs const& inputs, 00219 Data const& data, 00220 BlockSize const& blockSize, 00221 SampleRate const& sampleRate) throw() 00222 : Internal (inputs, data, blockSize, sampleRate) 00223 { 00224 } 00225 00226 Text getName() const throw() 00227 { 00228 return "FFT"; 00229 } 00230 00231 IntArray getInputKeys() const throw() 00232 { 00233 const IntArray keys (IOKey::Generic); 00234 return keys; 00235 } 00236 00237 InternalBase* getChannel (const int index) throw() 00238 { 00239 const Inputs channelInputs = this->getInputs().getChannel (index); 00240 return new FFTInternal (channelInputs, 00241 this->getState(), 00242 this->getBlockSize(), 00243 this->getSampleRate()); 00244 } 00245 00246 void initChannel (const int channel) throw() 00247 { 00248 const UnitType& input = this->getInputAsUnit (IOKey::Generic); 00249 00250 this->setBlockSize (input.getBlockSize (channel)); 00251 this->setSampleRate (input.getSampleRate (channel)); 00252 this->setOverlap (input.getOverlap (channel)); 00253 this->fft = FFTEngineType (input.getBlockSize (channel)); 00254 00255 this->initValue (SampleType (0)); // not really applicable with an FFT output 00256 } 00257 00258 void process (ProcessInfo& info, const int channel) throw() 00259 { 00260 /* Be careful optimising this with the new NumericalArray vector stuff */ 00261 00262 UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic)); 00263 const Buffer& inputBuffer (inputUnit.process (info, channel)); 00264 const SampleType* const inputSamples = inputBuffer.getArray(); 00265 00266 SampleType* const outputSamples = this->getOutputSamples(); 00267 const int outputBufferLength = this->getOutputBuffer().length(); 00268 00269 plonk_assert (outputBufferLength == inputBuffer.length()); 00270 00271 if (outputBufferLength != this->fft.length()) 00272 this->fft = FFTEngineType (outputBufferLength); 00273 00274 // transform 00275 this->fft.forward (outputSamples, inputSamples); 00276 } 00277 00278 private: 00279 FFTEngineType fft; 00280 }; 00281 00282 00283 00284 //------------------------------------------------------------------------------ 00285 00300 template<class SampleType> 00301 class FFTUnit 00302 { 00303 public: 00304 typedef FFTChannelInternal<SampleType> FFTInternal; 00305 typedef typename FFTInternal::Data Data; 00306 typedef UnitBase<SampleType> UnitType; 00307 typedef InputDictionary Inputs; 00308 00309 static inline UnitInfos getInfo() throw() 00310 { 00311 return UnitInfo ("FFT", "Transforms time domain to frequency domain data.", 00312 00313 // output 00314 ChannelCount::VariableChannelCount, 00315 IOKey::FFTPacked, Measure::FFTPacked, IOInfo::NoDefault, IOLimit::None, 00316 IOKey::End, 00317 00318 // inputs 00319 IOKey::Generic, Measure::None, 00320 IOKey::End); 00321 } 00322 00324 static inline UnitType ar (UnitType const& input) throw() 00325 { 00326 // re: full templating - could say that FFT/IFFT are only supported with float (and eventually double)? 00327 00328 Inputs inputs; 00329 inputs.put (IOKey::Generic, input); 00330 00331 Data data = { -1.0, -1.0 }; 00332 00333 return UnitType::template createFromInputs<FFTInternal> (inputs, 00334 data, 00335 BlockSize::noPreference(), 00336 SampleRate::noPreference()); 00337 } 00338 }; 00339 00340 00341 typedef FFTUnit<PLONK_TYPE_DEFAULT> FFT; 00342 00343 #endif // PLONK_FFTCHANNEL_H 00344 00345