![]() |
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_FILTERCOEFFS3PARAM_H 00040 #define PLONK_FILTERCOEFFS3PARAM_H 00041 00042 #include "../channel/plonk_ChannelInternalCore.h" 00043 #include "plonk_FilterForwardDeclarations.h" 00044 00045 00046 00048 template<class ShapeType> 00049 class FilterCoeffs3ParamChannelInternal 00050 : public ProxyOwnerChannelInternal<typename ShapeType::SampleDataType, 00051 typename ShapeType::Data> 00052 { 00053 public: 00054 typedef typename ShapeType::SampleDataType SampleType; 00055 typedef typename ShapeType::Data Data; 00056 typedef typename ShapeType::FormType FormType; 00057 00058 typedef ChannelBase<SampleType> ChannelType; 00059 typedef ObjectArray<ChannelType> ChannelArrayType; 00060 00061 typedef ProxyOwnerChannelInternal<SampleType,Data> Internal; 00062 typedef UnitBase<SampleType> UnitType; 00063 typedef InputDictionary Inputs; 00064 typedef NumericalArray<SampleType> Buffer; 00065 00066 FilterCoeffs3ParamChannelInternal (Inputs const& inputs, 00067 Data const& data, 00068 BlockSize const& blockSize, 00069 SampleRate const& sampleRate, 00070 ChannelArrayType& channels) throw() 00071 : Internal (FormType::NumCoeffs, inputs, data, blockSize, sampleRate, channels), 00072 inputKeys (ShapeType::getInputKeys()) 00073 { 00074 plonk_assert (ShapeType::NumParams == 3); 00075 00076 SampleRate& filterSampleRate = this->getInputAsSampleRate (IOKey::FilterSampleRate); 00077 filterSampleRate.addReceiver (this); 00078 00079 updateFilterSampleRateInData(); 00080 } 00081 00082 ~FilterCoeffs3ParamChannelInternal() 00083 { 00084 SampleRate& filterSampleRate = this->getInputAsSampleRate (IOKey::FilterSampleRate); 00085 filterSampleRate.removeReceiver (this); 00086 } 00087 00088 Text getName() const throw() 00089 { 00090 return "Filter Coeffs 3 Param (" + ShapeType::getFormName() + " / " + ShapeType::getShapeName() + ")"; 00091 } 00092 00093 IntArray getInputKeys() const throw() 00094 { 00095 return inputKeys; 00096 } 00097 00098 void initChannel (const int channel) throw() 00099 { 00100 plonk_assert (ShapeType::NumParams == 3); 00101 00102 UnitType& param0Unit = this->getInputAsUnit (inputKeys.atUnchecked (0)); 00103 UnitType& param1Unit = this->getInputAsUnit (inputKeys.atUnchecked (1)); 00104 UnitType& param2Unit = this->getInputAsUnit (inputKeys.atUnchecked (2)); 00105 00106 plonk_assert (param0Unit.getOverlap (0) == Math<DoubleVariable>::get1()); 00107 plonk_assert (param1Unit.getOverlap (0) == Math<DoubleVariable>::get1()); 00108 plonk_assert (param2Unit.getOverlap (0) == Math<DoubleVariable>::get1()); 00109 00110 if ((channel % this->getNumChannels()) == 0) 00111 { 00112 this->setBlockSize (BlockSize::decide (param0Unit.getBlockSize (0), 00113 this->getBlockSize())); 00114 this->setSampleRate (SampleRate::decide (param0Unit.getSampleRate (0), 00115 this->getSampleRate())); 00116 00117 Data& data = this->getState(); 00118 data.params[0] = param0Unit.getValue (0); 00119 data.params[1] = param1Unit.getValue (0); 00120 data.params[2] = param2Unit.getValue (0); 00121 00122 ShapeType::calculate (data); 00123 00124 for (int i = 0; i < FormType::NumCoeffs; ++i) 00125 this->initProxyValue (i, data.coeffs[i]); 00126 } 00127 } 00128 00129 void changed (DoubleVariable::Sender const& source, Text const& message, Dynamic const& payload) throw() 00130 { 00131 SampleRate sampleRateSource = static_cast<SampleRate> (source); 00132 00133 if (sampleRateSource == this->getInputAsSampleRate (IOKey::FilterSampleRate)) 00134 { 00135 this->updateFilterSampleRateInData(); 00136 return; 00137 } 00138 00139 Internal::changed (source, message, payload); // process others 00140 } 00141 00142 void updateFilterSampleRateInData() throw() 00143 { 00144 const SampleRate& filterSampleRate = this->getInputAsSampleRate (IOKey::FilterSampleRate); 00145 Data& data = this->getState(); 00146 00147 data.filterSampleRate = filterSampleRate.getValue(); 00148 data.filterSampleDuration = 1.0 / data.filterSampleRate; 00149 } 00150 00151 void process (ProcessInfo& info, const int /*channel*/) throw() 00152 { 00153 int i, j; 00154 00155 Data& data = this->getState(); 00156 00157 const int outputBufferLength = this->getOutputBuffer (0).length(); 00158 00159 UnitType& param0Unit = this->getInputAsUnit (inputKeys.atUnchecked (0)); 00160 UnitType& param1Unit = this->getInputAsUnit (inputKeys.atUnchecked (1)); 00161 UnitType& param2Unit = this->getInputAsUnit (inputKeys.atUnchecked (2)); 00162 00163 const Buffer& param0Buffer (param0Unit.process (info, 0)); 00164 const Buffer& param1Buffer (param1Unit.process (info, 0)); 00165 const Buffer& param2Buffer (param2Unit.process (info, 0)); 00166 const SampleType* const param0Samples = param0Buffer.getArray(); 00167 const SampleType* const param1Samples = param1Buffer.getArray(); 00168 const SampleType* const param2Samples = param2Buffer.getArray(); 00169 00170 const int param0BufferLength = param0Buffer.length(); 00171 const int param1BufferLength = param1Buffer.length(); 00172 const int param2BufferLength = param2Buffer.length(); 00173 00174 if (outputBufferLength == param0BufferLength) 00175 { 00176 if ((outputBufferLength == param1BufferLength) && 00177 (outputBufferLength == param2BufferLength)) 00178 { 00179 // NNN 00180 for (i = 0; i < outputBufferLength; ++i) 00181 { 00182 data.params[0] = param0Samples[i]; 00183 data.params[1] = param1Samples[i]; 00184 data.params[2] = param2Samples[i]; 00185 00186 ShapeType::calculate (data); 00187 00188 for (j = 0; j < FormType::NumCoeffs; ++j) 00189 this->getOutputSamples (j) [i] = data.coeffs[j]; 00190 } 00191 } 00192 else if (param1BufferLength == 1) 00193 { 00194 if (outputBufferLength == param2BufferLength) 00195 { 00196 // N1N 00197 data.params[1] = param1Samples[0]; 00198 00199 for (i = 0; i < outputBufferLength; ++i) 00200 { 00201 data.params[0] = param0Samples[i]; 00202 data.params[2] = param2Samples[i]; 00203 00204 ShapeType::calculate (data); 00205 00206 for (j = 0; j < FormType::NumCoeffs; ++j) 00207 this->getOutputSamples (j) [i] = data.coeffs[j]; 00208 } 00209 } 00210 else if (param2BufferLength == 1) 00211 { 00212 // N11 00213 data.params[1] = param1Samples[0]; 00214 data.params[2] = param2Samples[0]; 00215 00216 for (i = 0; i < outputBufferLength; ++i) 00217 { 00218 data.params[0] = param0Samples[i]; 00219 00220 ShapeType::calculate (data); 00221 00222 for (j = 0; j < FormType::NumCoeffs; ++j) 00223 this->getOutputSamples (j) [i] = data.coeffs[j]; 00224 } 00225 } 00226 else goto fallback; // Nnn 00227 } 00228 else if (param2BufferLength == 1) 00229 { 00230 if (outputBufferLength == param1BufferLength) 00231 { 00232 // NN1 00233 data.params[2] = param2Samples[0]; 00234 00235 for (i = 0; i < outputBufferLength; ++i) 00236 { 00237 data.params[0] = param0Samples[i]; 00238 data.params[1] = param1Samples[i]; 00239 00240 ShapeType::calculate (data); 00241 00242 for (j = 0; j < FormType::NumCoeffs; ++j) 00243 this->getOutputSamples (j) [i] = data.coeffs[j]; 00244 } 00245 } 00246 else goto fallback; // Nn1 00247 } 00248 else goto fallback; //? 00249 } 00250 else if (param0BufferLength == 1) 00251 { 00252 if ((outputBufferLength == param1BufferLength) && 00253 (outputBufferLength == param2BufferLength)) 00254 { 00255 // 1NN 00256 data.params[0] = param0Samples[0]; 00257 00258 for (i = 0; i < outputBufferLength; ++i) 00259 { 00260 data.params[1] = param1Samples[i]; 00261 data.params[2] = param2Samples[i]; 00262 00263 ShapeType::calculate (data); 00264 00265 for (j = 0; j < FormType::NumCoeffs; ++j) 00266 this->getOutputSamples (j) [i] = data.coeffs[j]; 00267 } 00268 } 00269 else if (param1BufferLength == 1) 00270 { 00271 if (param2BufferLength == outputBufferLength) 00272 { 00273 // 11N 00274 data.params[0] = param0Samples[0]; 00275 data.params[1] = param1Samples[0]; 00276 00277 for (i = 0; i < outputBufferLength; ++i) 00278 { 00279 data.params[2] = param2Samples[i]; 00280 00281 ShapeType::calculate (data); 00282 00283 for (j = 0; j < FormType::NumCoeffs; ++j) 00284 this->getOutputSamples (j) [i] = data.coeffs[j]; 00285 } 00286 } 00287 else if (param2BufferLength == 1) 00288 { 00289 // 111 00290 data.params[0] = param0Samples[0]; 00291 data.params[1] = param1Samples[0]; 00292 data.params[2] = param2Samples[0]; 00293 00294 ShapeType::calculate (data); 00295 00296 for (i = 0; i < outputBufferLength; ++i) 00297 { 00298 for (j = 0; j < FormType::NumCoeffs; ++j) 00299 this->getOutputSamples (j) [i] = data.coeffs[j]; 00300 } 00301 } 00302 else goto fallback; // 11n 00303 } 00304 else if (param2BufferLength == 1) 00305 { 00306 if (param1BufferLength == outputBufferLength) 00307 { 00308 // 1N1 00309 data.params[0] = param0Samples[0]; 00310 data.params[2] = param2Samples[0]; 00311 00312 for (i = 0; i < outputBufferLength; ++i) 00313 { 00314 data.params[1] = param1Samples[i]; 00315 00316 ShapeType::calculate (data); 00317 00318 for (j = 0; j < FormType::NumCoeffs; ++j) 00319 this->getOutputSamples (j) [i] = data.coeffs[j]; 00320 } 00321 } 00322 goto fallback; // 1n1 00323 } 00324 else goto fallback; // 1nn 00325 } 00326 else goto fallback; // nnn 00327 00328 return; 00329 00330 fallback: 00331 { 00332 double param0Position = 0.0; 00333 const double param0Increment = double (param0BufferLength) / double (outputBufferLength); 00334 double param1Position = 0.0; 00335 const double param1Increment = double (param1BufferLength) / double (outputBufferLength); 00336 double param2Position = 0.0; 00337 const double param2Increment = double (param2BufferLength) / double (outputBufferLength); 00338 00339 for (i = 0; i < outputBufferLength; ++i) 00340 { 00341 data.params[0] = param0Samples[int (param0Position)]; 00342 data.params[1] = param1Samples[int (param1Position)]; 00343 data.params[2] = param2Samples[int (param2Position)]; 00344 00345 ShapeType::calculate (data); 00346 00347 for (j = 0; j < FormType::NumCoeffs; ++j) 00348 this->getOutputSamples (j) [i] = data.coeffs[j]; 00349 00350 param0Position += param0Increment; 00351 param1Position += param1Increment; 00352 param2Position += param2Increment; 00353 } 00354 } 00355 } 00356 00357 private: 00358 IntArray inputKeys; 00359 }; 00360 00361 00362 00363 00364 00367 template<class ShapeType> 00368 class FilterCoeffs3ParamUnit 00369 { 00370 public: 00371 typedef typename ShapeType::SampleDataType SampleType; 00372 typedef typename ShapeType::Data Data; 00373 typedef typename ShapeType::FormType FormType; 00374 00375 typedef FilterCoeffs3ParamChannelInternal<ShapeType> FilterCoeffsInternal; 00376 typedef ChannelBase<SampleType> ChannelType; 00377 typedef ChannelInternal<SampleType,Data> Internal; 00378 typedef UnitBase<SampleType> UnitType; 00379 typedef InputDictionary Inputs; 00380 00381 static inline UnitInfos getInfo() throw() 00382 { 00383 const double sampleRate = SampleRate::getDefault().getValue(); 00384 00385 return UnitInfo ("Filter Coeffs 3 Param", "Filter coefficients generator for an IIR filter using three control parameters.", 00386 00387 // output 00388 FormType::NumCoeffs, 00389 IOKey::Coeffs, Measure::Coeffs, 0.0, IOLimit::None, 00390 IOKey::End, 00391 00392 // inputs 00393 IOKey::Generic, Measure::Unknown, IOInfo::NoDefault, IOLimit::None, 00394 IOKey::Generic, Measure::Unknown, IOInfo::NoDefault, IOLimit::None, 00395 IOKey::Generic, Measure::Unknown, IOInfo::NoDefault, IOLimit::None, 00396 IOKey::FilterSampleRate, Measure::Hertz, sampleRate, IOLimit::Minimum, Measure::Hertz, 0.0, 00397 IOKey::BlockSize, Measure::Samples, 0.0, IOLimit::Minimum, Measure::Samples, 1.0, 00398 IOKey::SampleRate, Measure::Hertz, -1.0, IOLimit::Minimum, Measure::Hertz, 0.0, 00399 IOKey::End); 00400 } 00401 00402 00405 static UnitType ar (UnitType const& param0, 00406 UnitType const& param1, 00407 UnitType const& param2, 00408 SampleRates const filterSampleRates = SampleRate::getDefault(), 00409 BlockSize const& preferredBlockSize = BlockSize::noPreference(), 00410 SampleRate const& preferredSampleRate = SampleRate::noPreference()) throw() 00411 { 00412 const IntArray inputKeys = ShapeType::getInputKeys(); 00413 00414 plonk_assert (inputKeys.length() == 3); 00415 00416 const int numInputChannels = plonk::max (param0.getNumChannels(), param1.getNumChannels(), param2.getNumChannels()); 00417 const int numSampleRates = filterSampleRates.length(); 00418 const int numChannels = filterSampleRates.areAllEqual() ? numInputChannels : plonk::max (numInputChannels, numSampleRates); 00419 UnitType result (UnitType::emptyWithAllocatedSize (numChannels * FormType::NumCoeffs)); 00420 00421 Data data; 00422 Memory::zero (data); 00423 data.base.sampleRate = -1.0; 00424 data.base.sampleDuration = -1.0; 00425 00426 for (int i = 0; i < numChannels; ++i) 00427 { 00428 Inputs inputs; 00429 inputs.put (inputKeys.atUnchecked (0), param0[i]); 00430 inputs.put (inputKeys.atUnchecked (1), param1[i]); 00431 inputs.put (inputKeys.atUnchecked (2), param2[i]); 00432 inputs.put (IOKey::FilterSampleRate, filterSampleRates.wrapAt (i)); 00433 00434 result.add (UnitType::template proxiesFromInputs<FilterCoeffsInternal> (inputs, 00435 data, 00436 preferredBlockSize, 00437 preferredSampleRate)); 00438 } 00439 00440 return result; 00441 } 00442 }; 00443 00444 00445 00446 00447 #endif // PLONK_FILTERCOEFFS3PARAM_H 00448