![]() |
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_MULADDCHANNEL_H 00040 #define PLONK_MULADDCHANNEL_H 00041 00042 #include "../../maths/plonk_InlineBinaryOps.h" 00043 #include "../channel/plonk_ChannelInternalCore.h" 00044 #include "../plonk_GraphForwardDeclarations.h" 00045 00047 template<class SampleType> 00048 class MulAddChannelInternal 00049 : public ChannelInternal<SampleType, ChannelInternalCore::Data> 00050 { 00051 public: 00052 typedef typename ChannelInternalCore::Data Data; 00053 00054 typedef ChannelBase<SampleType> ChannelType; 00055 typedef MulAddChannelInternal<SampleType> MulAddInternal; 00056 typedef ChannelInternal<SampleType,Data> Internal; 00057 typedef ChannelInternalBase<SampleType> InternalBase; 00058 typedef UnitBase<SampleType> UnitType; 00059 typedef InputDictionary Inputs; 00060 typedef NumericalArray<SampleType> Buffer; 00061 00062 MulAddChannelInternal (Inputs const& inputs, 00063 Data const& data, 00064 BlockSize const& blockSize, 00065 SampleRate const& sampleRate) throw() 00066 : Internal (inputs, data, blockSize, sampleRate) 00067 { 00068 } 00069 00070 Text getName() const throw() 00071 { 00072 return "MulAdd"; 00073 } 00074 00075 IntArray getInputKeys() const throw() 00076 { 00077 const IntArray keys (IOKey::Generic, 00078 IOKey::Multiply, 00079 IOKey::Add); 00080 return keys; 00081 } 00082 00083 00084 InternalBase* getChannel (const int index) throw() 00085 { 00086 const Inputs channelInputs = this->getInputs().getChannel (index); 00087 return new MulAddChannelInternal (channelInputs, 00088 this->getState(), 00089 this->getBlockSize(), 00090 this->getSampleRate()); 00091 } 00092 00093 void initChannel(const int channel) throw() 00094 { 00095 UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic)); 00096 const SampleType inputValue = inputUnit.getValue (channel); 00097 UnitType& multiplyUnit (this->getInputAsUnit (IOKey::Multiply)); 00098 const SampleType multiplyValue = multiplyUnit.getValue (channel); 00099 UnitType& addUnit (this->getInputAsUnit (IOKey::Add)); 00100 const SampleType addValue = addUnit.getValue (channel); 00101 00102 00103 const BlockSize tempBlockSize = inputUnit.getBlockSize (channel) 00104 .selectMax (multiplyUnit.getBlockSize (channel)) 00105 .selectMax (addUnit.getBlockSize (channel)); 00106 const SampleRate tempSampleRate = inputUnit.getSampleRate (channel) 00107 .selectMax (multiplyUnit.getSampleRate (channel)) 00108 .selectMax (addUnit.getSampleRate (channel)); 00109 00110 this->setBlockSize (BlockSize::decide (tempBlockSize, this->getBlockSize())); 00111 this->setSampleRate (SampleRate::decide (tempSampleRate, this->getSampleRate())); 00112 00113 const DoubleVariable inputOverlap = inputUnit.getOverlap (channel); 00114 const DoubleVariable multiplyOverlap = multiplyUnit.getOverlap (channel); 00115 const DoubleVariable addOverlap = addUnit.getOverlap (channel); 00116 00117 if ((inputOverlap == multiplyOverlap) && (inputOverlap == addOverlap)) 00118 this->setOverlap (inputOverlap); 00119 else if ((inputUnit.isConstant (channel)) && (multiplyUnit.isConstant (channel))) 00120 this->setOverlap (addOverlap); 00121 else if ((inputUnit.isConstant (channel)) && (addUnit.isConstant (channel))) 00122 this->setOverlap (multiplyOverlap); 00123 else if ((addUnit.isConstant (channel)) && (multiplyUnit.isConstant (channel))) 00124 this->setOverlap (inputOverlap); 00125 else 00126 plonk_assertfalse; 00127 00128 this->initValue (inputValue * multiplyValue + addValue); 00129 } 00130 00131 void process (ProcessInfo& info, const int channel) throw() 00132 { 00133 UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic)); 00134 UnitType& multiplyUnit (this->getInputAsUnit (IOKey::Multiply)); 00135 UnitType& addUnit (this->getInputAsUnit (IOKey::Add)); 00136 00137 const Buffer& inputBuffer (inputUnit.process (info, channel)); 00138 const Buffer& multiplyBuffer (multiplyUnit.process (info, channel)); 00139 const Buffer& addBuffer (addUnit.process (info, channel)); 00140 00141 SampleType* const outputSamples = this->getOutputSamples(); 00142 const int outputBufferLength = this->getOutputBuffer().length(); 00143 00144 const SampleType* const inputSamples = inputBuffer.getArray(); 00145 const int inputBufferLength = inputBuffer.length(); 00146 const SampleType* const multiplySamples = multiplyBuffer.getArray(); 00147 const int multiplyBufferLength = multiplyBuffer.length(); 00148 const SampleType* const addSamples = addBuffer.getArray(); 00149 const int addBufferLength = addBuffer.length(); 00150 00151 int i; 00152 00153 if ((inputBufferLength == outputBufferLength) && 00154 (multiplyBufferLength == outputBufferLength) && 00155 (addBufferLength == outputBufferLength)) 00156 { 00157 // NNNN 00158 for (i = 0; i < outputBufferLength; ++i) 00159 outputSamples[i] = inputSamples[i] * multiplySamples[i] + addSamples[i]; 00160 } 00161 else if ((inputBufferLength == outputBufferLength) && 00162 (multiplyBufferLength == 1) && 00163 (addBufferLength == 1)) 00164 { 00165 // NN11 00166 const SampleType multiplyValue (multiplyBuffer[0]); 00167 const SampleType addValue (addBuffer[0]); 00168 00169 for (i = 0; i < outputBufferLength; ++i) 00170 outputSamples[i] = inputSamples[i] * multiplyValue + addValue; 00171 00172 } 00173 else if ((inputBufferLength == outputBufferLength) && 00174 (multiplyBufferLength == outputBufferLength) && 00175 (addBufferLength == 1)) 00176 { 00177 // NNN1 00178 const SampleType addValue (addBuffer[0]); 00179 00180 for (i = 0; i < outputBufferLength; ++i) 00181 outputSamples[i] = inputSamples[i] * multiplySamples[i] + addValue; 00182 } 00183 else if ((inputBufferLength == outputBufferLength) && 00184 (multiplyBufferLength == 1) && 00185 (addBufferLength == outputBufferLength)) 00186 { 00187 // NN1N 00188 const SampleType multiplyValue (multiplyBuffer[0]); 00189 00190 for (i = 0; i < outputBufferLength; ++i) 00191 outputSamples[i] = inputSamples[i] * multiplyValue + addSamples[i]; 00192 } 00193 else goto fallback; 00194 00195 return; 00196 00197 fallback: 00198 { 00199 double inputPosition = 0.0; 00200 const double inputIncrement = double (inputBufferLength) / double (outputBufferLength); 00201 double multiplyPosition = 0.0; 00202 const double multiplyIncrement = double (multiplyBufferLength) / double (outputBufferLength); 00203 double addPosition = 0.0; 00204 const double addIncrement = double (addBufferLength) / double (outputBufferLength); 00205 00206 for (i = 0; i < outputBufferLength; ++i) 00207 { 00208 outputSamples[i] = inputSamples[int (inputPosition)] * 00209 multiplySamples[int (multiplyPosition)] + 00210 addSamples[int (addPosition)]; 00211 00212 inputPosition += inputIncrement; 00213 multiplyPosition += multiplyIncrement; 00214 addPosition += addIncrement; 00215 } 00216 } 00217 } 00218 }; 00219 00220 //------------------------------------------------------------------------------ 00221 00222 #ifdef PLONK_USEPLINK 00223 00224 template<> 00225 class MulAddChannelInternal<float> 00226 : public ChannelInternal<float, ChannelInternalCore::Data> 00227 { 00228 public: 00229 typedef ChannelInternalCore::Data Data; 00230 typedef ChannelBase<float> ChannelType; 00231 typedef MulAddChannelInternal<float> MulAddInternal; 00232 typedef ChannelInternal<float,Data> Internal; 00233 typedef ChannelInternalBase<float> InternalBase; 00234 typedef UnitBase<float> UnitType; 00235 typedef InputDictionary Inputs; 00236 typedef NumericalArray<float> Buffer; 00237 00238 enum Outputs { Output, NumOutputs }; 00239 enum InputIndices { Input, Multiply, Add, NumInputs }; 00240 enum Buffers { OutputBuffer, InputBuffer, MultiplyBuffer, AddBuffer, NumBuffers }; 00241 00242 typedef PlinkProcess<NumBuffers> Process; 00243 00244 MulAddChannelInternal (Inputs const& inputs, 00245 Data const& data, 00246 BlockSize const& blockSize, 00247 SampleRate const& sampleRate) throw() 00248 : Internal (inputs, data, blockSize, sampleRate) 00249 { 00250 plonk_staticassert (NumBuffers == (NumInputs + NumOutputs)); 00251 Process::init (&p, this, NumOutputs, NumInputs); 00252 } 00253 00254 Text getName() const throw() 00255 { 00256 return "MulAdd"; 00257 } 00258 00259 IntArray getInputKeys() const throw() 00260 { 00261 const IntArray keys (IOKey::Generic, 00262 IOKey::Multiply, 00263 IOKey::Add); 00264 return keys; 00265 } 00266 00267 00268 InternalBase* getChannel (const int index) throw() 00269 { 00270 const Inputs channelInputs = this->getInputs().getChannel (index); 00271 return new MulAddChannelInternal (channelInputs, 00272 this->getState(), 00273 this->getBlockSize(), 00274 this->getSampleRate()); 00275 } 00276 00277 void initChannel(const int channel) throw() 00278 { 00279 UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic)); 00280 const float inputValue = inputUnit.getValue (channel); 00281 UnitType& multiplyUnit (this->getInputAsUnit (IOKey::Multiply)); 00282 const float multiplyValue = multiplyUnit.getValue (channel); 00283 UnitType& addUnit (this->getInputAsUnit (IOKey::Add)); 00284 const float addValue = addUnit.getValue (channel); 00285 00286 const BlockSize tempBlockSize = inputUnit.getBlockSize (channel) 00287 .selectMax (multiplyUnit.getBlockSize (channel)) 00288 .selectMax (addUnit.getBlockSize (channel)); 00289 const SampleRate tempSampleRate = inputUnit.getSampleRate (channel) 00290 .selectMax (multiplyUnit.getSampleRate (channel)) 00291 .selectMax (addUnit.getSampleRate (channel)); 00292 00293 this->setBlockSize (BlockSize::decide (tempBlockSize, this->getBlockSize())); 00294 this->setSampleRate (SampleRate::decide (tempSampleRate, this->getSampleRate())); 00295 00296 const DoubleVariable inputOverlap = inputUnit.getOverlap (channel); 00297 const DoubleVariable multiplyOverlap = multiplyUnit.getOverlap (channel); 00298 const DoubleVariable addOverlap = addUnit.getOverlap (channel); 00299 00300 if ((inputOverlap == multiplyOverlap) && (inputOverlap == addOverlap)) 00301 this->setOverlap (inputOverlap); 00302 else if ((inputUnit.isConstant (channel)) && (multiplyUnit.isConstant (channel))) 00303 this->setOverlap (addOverlap); 00304 else if ((inputUnit.isConstant (channel)) && (addUnit.isConstant (channel))) 00305 this->setOverlap (multiplyOverlap); 00306 else if ((addUnit.isConstant (channel)) && (multiplyUnit.isConstant (channel))) 00307 this->setOverlap (inputOverlap); 00308 else 00309 plonk_assertfalse; 00310 00311 this->initValue (inputValue * multiplyValue + addValue); 00312 } 00313 00314 void process (ProcessInfo& info, const int channel) throw() 00315 { 00316 UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic)); 00317 UnitType& multiplyUnit (this->getInputAsUnit (IOKey::Multiply)); 00318 UnitType& addUnit (this->getInputAsUnit (IOKey::Add)); 00319 00320 const Buffer& inputBuffer (inputUnit.process (info, channel)); 00321 const Buffer& multiplyBuffer (multiplyUnit.process (info, channel)); 00322 const Buffer& addBuffer (addUnit.process (info, channel)); 00323 00324 p.buffers[0].bufferSize = this->getOutputBuffer().length();; 00325 p.buffers[0].buffer = this->getOutputSamples(); 00326 p.buffers[1].bufferSize = inputBuffer.length(); 00327 p.buffers[1].buffer = inputBuffer.getArray(); 00328 p.buffers[2].bufferSize = multiplyBuffer.length(); 00329 p.buffers[2].buffer = multiplyBuffer.getArray(); 00330 p.buffers[3].bufferSize = addBuffer.length(); 00331 p.buffers[3].buffer = addBuffer.getArray(); 00332 00333 plink_MulAddProcessF (&p, 0); 00334 } 00335 00336 private: 00337 Process p; 00338 }; 00339 00340 #endif // PLONK_USEPLINK 00341 00342 //------------------------------------------------------------------------------ 00343 00344 template<class SampleType> 00345 class MulAddUnit 00346 { 00347 public: 00348 typedef MulAddChannelInternal<SampleType> MulAddInternal; 00349 typedef typename MulAddInternal::Data Data; 00350 typedef InputDictionary Inputs; 00351 typedef ChannelBase<SampleType> ChannelType; 00352 typedef ChannelInternal<SampleType,Data> Internal; 00353 typedef ChannelInternalBase<SampleType> ChannelInternalType; 00354 typedef UnitBase<SampleType> UnitType; 00355 00357 static UnitType ar (UnitType const& input, 00358 UnitType const& mul, 00359 UnitType const& add, 00360 BlockSize const& preferredBlockSize = BlockSize::getDefault(), 00361 SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw() 00362 { 00363 Inputs inputs; 00364 inputs.put (IOKey::Generic, input); 00365 inputs.put (IOKey::Multiply, mul); 00366 inputs.put (IOKey::Add, add); 00367 00368 Data data = { -1.0, -1.0 }; 00369 00370 const int numChannels = inputs.getMaxNumChannels(); 00371 UnitType result (UnitType::withSize (numChannels)); 00372 00373 for (int i = 0; i < numChannels; ++i) 00374 { 00375 ChannelInternalType* internal = new MulAddInternal (inputs, 00376 data, 00377 preferredBlockSize, 00378 preferredSampleRate); 00379 internal->initChannel (i); 00380 result.put (i, ChannelType (internal)); 00381 } 00382 00383 return result; 00384 } 00385 00387 static inline UnitType kr (UnitType const& input, 00388 UnitType const& mul, 00389 UnitType const& add) throw() 00390 { 00391 return ar (input, mul, add, 00392 BlockSize::getControlRateBlockSize(), 00393 SampleRate::getControlRate()); 00394 } 00395 00396 }; 00397 00398 typedef MulAddUnit<PLONK_TYPE_DEFAULT> MulAdd; 00399 00400 00401 00402 #endif // PLONK_MULADDCHANNEL_H