![]() |
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_MIXERS_H 00040 #define PLONK_MIXERS_H 00041 00042 #include "../channel/plonk_ChannelInternalCore.h" 00043 #include "../plonk_GraphForwardDeclarations.h" 00044 00045 template<class SampleType> class ChannelMixerChannelInternal; 00046 00047 PLONK_CHANNELDATA_DECLARE(ChannelMixerChannelInternal,SampleType) 00048 { 00049 ChannelInternalCore::Data base; 00050 bool allowAutoDelete:1; 00051 }; 00052 00053 00055 template<class SampleType> 00056 class ChannelMixerChannelInternal 00057 : public ChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(ChannelMixerChannelInternal,SampleType)> 00058 { 00059 public: 00060 typedef PLONK_CHANNELDATA_NAME(ChannelMixerChannelInternal,SampleType) Data; 00061 typedef typename BinaryOpFunctionsHelper<SampleType>::BinaryOpFunctionsType BinaryOpFunctionsType; 00062 typedef ChannelBase<SampleType> ChannelType; 00063 typedef ChannelMixerChannelInternal<SampleType> ChannelMixerInternal; 00064 typedef ChannelInternal<SampleType,Data> Internal; 00065 typedef ChannelInternalBase<SampleType> InternalBase; 00066 typedef UnitBase<SampleType> UnitType; 00067 typedef InputDictionary Inputs; 00068 typedef NumericalArray<SampleType> Buffer; 00069 00070 ChannelMixerChannelInternal (Inputs const& inputs, 00071 Data const& data, 00072 BlockSize const& blockSize, 00073 SampleRate const& sampleRate) throw() 00074 : Internal (inputs, data, blockSize, sampleRate) 00075 { 00076 } 00077 00078 Text getName() const throw() 00079 { 00080 return "Channel Mixer"; 00081 } 00082 00083 IntArray getInputKeys() const throw() 00084 { 00085 const IntArray keys (IOKey::Generic); 00086 return keys; 00087 } 00088 00089 InternalBase* getChannel (const int /*index*/) throw() 00090 { 00091 return this; 00092 } 00093 00094 void initChannel (const int /*channel*/) throw() 00095 { 00096 const UnitType& input = this->getInputAsUnit (IOKey::Generic); 00097 00098 this->setBlockSize (BlockSize::decide (input.getMaxBlockSize(), 00099 this->getBlockSize())); 00100 this->setSampleRate (SampleRate::decide (input.getMaxSampleRate(), 00101 this->getSampleRate())); 00102 00103 const int numChannels = input.getNumChannels(); 00104 SampleType value (0); 00105 00106 for (int i = 0; i < numChannels; ++i) 00107 value += input.getValue (i); 00108 00109 this->initValue (value); 00110 } 00111 00112 void process (ProcessInfo& info, const int /*channel*/) throw() 00113 { 00114 int i; 00115 00116 this->getOutputBuffer().zero(); 00117 SampleType* const outputSamples = this->getOutputSamples(); 00118 const int outputBufferLength = this->getOutputBuffer().length(); 00119 00120 UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic)); 00121 00122 const int numChannels = inputUnit.getNumChannels(); 00123 00124 for (int channel = 0; channel < numChannels; ++channel) 00125 { 00126 plonk_assert (inputUnit.getOverlap (channel) == Math<DoubleVariable>::get1()); 00127 00128 const Buffer& inputBuffer (inputUnit.process (info, channel)); 00129 const SampleType* const inputSamples = inputBuffer.getArray(); 00130 const int inputBufferLength = inputBuffer.length(); 00131 00132 if (inputBufferLength == outputBufferLength) 00133 { 00134 NumericalArrayBinaryOp<SampleType,BinaryOpFunctionsType::addop>::calcNN (outputSamples, outputSamples, inputSamples, outputBufferLength); 00135 } 00136 else if (inputBufferLength == 1) 00137 { 00138 NumericalArrayBinaryOp<SampleType,BinaryOpFunctionsType::addop>::calcN1 (outputSamples, outputSamples, inputSamples[0], outputBufferLength); 00139 } 00140 else 00141 { 00142 double inputPosition = 0.0; 00143 const double inputIncrement = double (inputBufferLength) / double (outputBufferLength); 00144 00145 for (i = 0; i < outputBufferLength; ++i) 00146 { 00147 outputSamples[i] += inputSamples[int (inputPosition)]; 00148 inputPosition += inputIncrement; 00149 } 00150 } 00151 } 00152 00153 const Data& data = this->getState(); 00154 00155 if (data.allowAutoDelete == false) 00156 info.resetShouldDelete(); 00157 } 00158 }; 00159 00160 //------------------------------------------------------------------------------ 00161 00162 template<class SampleType> class UnitMixerChannelInternal; 00163 00164 PLONK_CHANNELDATA_DECLARE(UnitMixerChannelInternal,SampleType) 00165 { 00166 ChannelInternalCore::Data base; 00167 int preferredNumChannels; 00168 bool allowAutoDelete:1; 00169 bool purgeExpiredUnits:1; 00170 }; 00171 00172 00174 template<class SampleType> 00175 class UnitMixerChannelInternal 00176 : public ProxyOwnerChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(UnitMixerChannelInternal,SampleType)> 00177 { 00178 public: 00179 typedef PLONK_CHANNELDATA_NAME(UnitMixerChannelInternal,SampleType) Data; 00180 typedef typename BinaryOpFunctionsHelper<SampleType>::BinaryOpFunctionsType BinaryOpFunctionsType; 00181 typedef ChannelBase<SampleType> ChannelType; 00182 typedef ObjectArray<ChannelType> ChannelArrayType; 00183 typedef ProxyOwnerChannelInternal<SampleType,Data> Internal; 00184 typedef UnitBase<SampleType> UnitType; 00185 typedef InputDictionary Inputs; 00186 typedef NumericalArray<SampleType> Buffer; 00187 typedef NumericalArray2D<ChannelType,UnitType> UnitsType; 00188 00189 UnitMixerChannelInternal (Inputs const& inputs, 00190 Data const& data, 00191 BlockSize const& blockSize, 00192 SampleRate const& sampleRate, 00193 ChannelArrayType& channels) throw() 00194 : Internal (data.preferredNumChannels > 0 ? data.preferredNumChannels : inputs.getMaxNumChannels(), 00195 inputs, data, blockSize, sampleRate, channels) 00196 { 00197 } 00198 00199 Text getName() const throw() 00200 { 00201 return "Unit Mixer"; 00202 } 00203 00204 IntArray getInputKeys() const throw() 00205 { 00206 const IntArray keys (IOKey::Units); 00207 return keys; 00208 } 00209 00210 void initChannel (const int channel) throw() 00211 { 00212 if ((channel % this->getNumChannels()) == 0) 00213 { 00214 // should look at the initial array in case no preference was given really... 00215 this->setBlockSize (BlockSize::decide (BlockSize::getDefault(), 00216 this->getBlockSize())); 00217 this->setSampleRate (SampleRate::decide (SampleRate::getDefault(), 00218 this->getSampleRate())); 00219 } 00220 00221 const Units& units = this->getInputAsUnits (IOKey::Units); 00222 00223 const int numUnits = units.length(); 00224 SampleType value (0); 00225 00226 for (int i = 0; i < numUnits; ++i) 00227 value += units.atUnchecked (i).getValue (channel); 00228 00229 this->initProxyValue (channel, value); 00230 } 00231 00232 void process (ProcessInfo& info, const int /*channel*/) throw() 00233 { 00234 const Data& data = this->getState(); 00235 00236 int i, channel, unit; 00237 00238 UnitsType& units = this->getInputAsUnits (IOKey::Units); 00239 00240 if (data.purgeExpiredUnits) 00241 { 00242 // remove nulls... 00243 for (unit = units.length(); --unit >= 0;) 00244 if (units.atUnchecked (unit).shouldBeDeletedNow (info)) 00245 units.remove (unit); 00246 } 00247 00248 const int numChannels = this->getNumChannels(); 00249 const int numUnits = units.length(); 00250 00251 // ..and process. 00252 for (channel = 0; channel < numChannels; ++channel) 00253 { 00254 Buffer outputBuffer = this->getOutputBuffer (channel); 00255 outputBuffer.zero(); 00256 SampleType* const outputSamples = outputBuffer.getArray(); 00257 const int outputBufferLength = outputBuffer.length(); 00258 00259 for (unit = 0; unit < numUnits; ++unit) 00260 { 00261 UnitType& inputUnit (units.atUnchecked (unit)); 00262 00263 if (!inputUnit.wrapAt (channel).shouldBeDeletedNow (info.getTimeStamp())) 00264 { 00265 plonk_assert (inputUnit.getOverlap (channel) == Math<DoubleVariable>::get1()); 00266 00267 const Buffer inputBuffer (inputUnit.process (info, channel)); 00268 const SampleType* const inputSamples = inputBuffer.getArray(); 00269 const int inputBufferLength = inputBuffer.length(); 00270 00271 if (inputBufferLength == outputBufferLength) 00272 { 00273 NumericalArrayBinaryOp<SampleType,BinaryOpFunctionsType::addop>::calcNN (outputSamples, outputSamples, inputSamples, outputBufferLength); 00274 } 00275 else if (inputBufferLength == 1) 00276 { 00277 NumericalArrayBinaryOp<SampleType,BinaryOpFunctionsType::addop>::calcN1 (outputSamples, outputSamples, inputSamples[0], outputBufferLength); 00278 } 00279 else 00280 { 00281 double inputPosition = 0.0; 00282 const double inputIncrement = double (inputBufferLength) / double (outputBufferLength); 00283 00284 for (i = 0; i < outputBufferLength; ++i) 00285 { 00286 outputSamples[i] += inputSamples[int (inputPosition)]; 00287 inputPosition += inputIncrement; 00288 } 00289 } 00290 00291 if (data.allowAutoDelete == false) 00292 info.resetShouldDelete(); 00293 } 00294 } 00295 } 00296 } 00297 }; 00298 00299 //------------------------------------------------------------------------------ 00300 00301 template<class SampleType> class QueueMixerChannelInternal; 00302 00303 PLONK_CHANNELDATA_DECLARE(QueueMixerChannelInternal,SampleType) 00304 { 00305 ChannelInternalCore::Data base; 00306 int preferredNumChannels; 00307 bool allowAutoDelete:1; 00308 bool purgeExpiredUnits:1; 00309 }; 00310 00311 00313 template<class SampleType> 00314 class QueueMixerChannelInternal 00315 : public ProxyOwnerChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(QueueMixerChannelInternal,SampleType)> 00316 { 00317 public: 00318 typedef PLONK_CHANNELDATA_NAME(QueueMixerChannelInternal,SampleType) Data; 00319 typedef typename BinaryOpFunctionsHelper<SampleType>::BinaryOpFunctionsType BinaryOpFunctionsType; 00320 typedef ChannelBase<SampleType> ChannelType; 00321 typedef ObjectArray<ChannelType> ChannelArrayType; 00322 typedef ProxyOwnerChannelInternal<SampleType,Data> Internal; 00323 typedef UnitBase<SampleType> UnitType; 00324 typedef InputDictionary Inputs; 00325 typedef NumericalArray<SampleType> Buffer; 00326 typedef NumericalArray2D<ChannelType,UnitType> UnitsType; 00327 typedef LockFreeQueue<UnitType> QueueType; 00328 00329 QueueMixerChannelInternal (Inputs const& inputs, 00330 Data const& data, 00331 BlockSize const& blockSize, 00332 SampleRate const& sampleRate, 00333 ChannelArrayType& channels) throw() 00334 : Internal (data.preferredNumChannels > 0 ? data.preferredNumChannels : inputs.getMaxNumChannels(), 00335 inputs, data, blockSize, sampleRate, channels) 00336 { 00337 } 00338 00339 Text getName() const throw() 00340 { 00341 return "Queue Mixer"; 00342 } 00343 00344 IntArray getInputKeys() const throw() 00345 { 00346 const IntArray keys (IOKey::UnitQueue); 00347 return keys; 00348 } 00349 00350 static inline const UnitType& getDummy() throw() 00351 { 00352 // dummy is a marker so we know we've done the whole queue up to the poiunt that we add this dummy marker 00353 static UnitType dummy (0); 00354 return dummy; 00355 } 00356 00357 void initChannel (const int channel) throw() 00358 { 00359 if ((channel % this->getNumChannels()) == 0) 00360 { 00361 // should look at the initial array in case no preference was given really... 00362 this->setBlockSize (BlockSize::decide (BlockSize::getDefault(), 00363 this->getBlockSize())); 00364 this->setSampleRate (SampleRate::decide (SampleRate::getDefault(), 00365 this->getSampleRate())); 00366 } 00367 00368 QueueType& queue = this->getInputAsUnitQueue (IOKey::UnitQueue); 00369 SampleType value (0); 00370 00371 if (queue.length() > 0) 00372 { 00373 UnitType inputUnit; 00374 queue.push (getDummy()); 00375 00376 while ((inputUnit = queue.pop()) != getDummy()) 00377 { 00378 value += inputUnit.getValue (channel); 00379 queue.push (inputUnit); 00380 } 00381 } 00382 00383 this->initProxyValue (channel, value); 00384 } 00385 00386 void process (ProcessInfo& info, const int /*channel*/) throw() 00387 { 00388 const Data& data = this->getState(); 00389 00390 QueueType& queue = this->getInputAsUnitQueue (IOKey::UnitQueue); 00391 00392 const int numChannels = this->getNumChannels(); 00393 int i, channel; 00394 00395 for (channel = 0; channel < numChannels; ++channel) 00396 this->getOutputBuffer (channel).zero(); 00397 00398 if (queue.length() > 0) 00399 { 00400 UnitType inputUnit; 00401 queue.push (getDummy()); 00402 00403 while ((inputUnit = queue.pop()) != getDummy()) 00404 { 00405 if (!inputUnit.shouldBeDeletedNow (info)) 00406 { 00407 plonk_assert (inputUnit.getOverlap (channel) == Math<DoubleVariable>::get1()); 00408 00409 for (channel = 0; channel < numChannels; ++channel) 00410 { 00411 const Buffer& inputBuffer (inputUnit.process (info, channel)); 00412 const SampleType* const inputSamples = inputBuffer.getArray(); 00413 const int inputBufferLength = inputBuffer.length(); 00414 00415 Buffer& outputBuffer = this->getOutputBuffer (channel); 00416 SampleType* const outputSamples = outputBuffer.getArray(); 00417 const int outputBufferLength = outputBuffer.length(); 00418 00419 if (inputBufferLength == outputBufferLength) 00420 { 00421 NumericalArrayBinaryOp<SampleType,BinaryOpFunctionsType::addop>::calcNN (outputSamples, outputSamples, inputSamples, outputBufferLength); 00422 } 00423 else if (inputBufferLength == 1) 00424 { 00425 NumericalArrayBinaryOp<SampleType,BinaryOpFunctionsType::addop>::calcN1 (outputSamples, outputSamples, inputSamples[0], outputBufferLength); 00426 } 00427 else 00428 { 00429 double inputPosition = 0.0; 00430 const double inputIncrement = double (inputBufferLength) / double (outputBufferLength); 00431 00432 for (i = 0; i < outputBufferLength; ++i) 00433 { 00434 outputSamples[i] += inputSamples[int (inputPosition)]; 00435 inputPosition += inputIncrement; 00436 } 00437 } 00438 00439 if (data.allowAutoDelete == false) 00440 info.resetShouldDelete(); 00441 } 00442 00443 queue.push (inputUnit); 00444 } 00445 else if (!data.purgeExpiredUnits) 00446 { 00447 queue.push (inputUnit); 00448 } 00449 } 00450 } 00451 } 00452 }; 00453 00454 //------------------------------------------------------------------------------ 00455 00456 #ifdef PLONK_USEPLINK 00457 #include "plonk_BinaryOpPlink.h" 00458 #include "plonk_UnaryOpPlink.h" 00459 00460 template<> 00461 class ChannelMixerChannelInternal<float> 00462 : public ChannelInternal<float, PLONK_CHANNELDATA_NAME(ChannelMixerChannelInternal,float)> 00463 { 00464 public: 00465 typedef PLONK_CHANNELDATA_NAME(ChannelMixerChannelInternal,float) Data; 00466 typedef ChannelBase<float> ChannelType; 00467 typedef ChannelMixerChannelInternal<float> ChannelMixerInternal; 00468 typedef ChannelInternal<float,Data> Internal; 00469 typedef ChannelInternalBase<float> InternalBase; 00470 typedef UnitBase<float> UnitType; 00471 typedef InputDictionary Inputs; 00472 typedef NumericalArray<float> Buffer; 00473 00474 typedef BinaryOpFunctionsHelper<float>::BinaryOpFunctionsType BinaryOpFunctionsType; 00475 typedef UnaryOpFunctionsHelper<float>::UnaryOpFunctionsType UnaryOpFunctionsType; 00476 00477 typedef BinaryOpChannelInternal<float,BinaryOpFunctionsType::addop> BinaryOpChannel; 00478 typedef BinaryOpChannel::Process Process; 00479 typedef UnaryOpChannelInternal<float,UnaryOpFunctionsType::move> UnaryOpChannel; 00480 typedef UnaryOpChannel::Process UnaryProcess; 00481 00482 ChannelMixerChannelInternal (Inputs const& inputs, 00483 Data const& data, 00484 BlockSize const& blockSize, 00485 SampleRate const& sampleRate) throw() 00486 : Internal (inputs, data, blockSize, sampleRate) 00487 { 00488 plonk_staticassert (BinaryOpChannel::NumBuffers == (BinaryOpChannel::NumInputs + BinaryOpChannel::NumOutputs)); 00489 Process::init (&p, this, BinaryOpChannel::NumOutputs, BinaryOpChannel::NumInputs); 00490 } 00491 00492 Text getName() const throw() 00493 { 00494 return "Channel Mixer"; 00495 } 00496 00497 IntArray getInputKeys() const throw() 00498 { 00499 const IntArray keys (IOKey::Generic); 00500 return keys; 00501 } 00502 00503 InternalBase* getChannel (const int /*index*/) throw() 00504 { 00505 return this; 00506 } 00507 00508 void initChannel (const int /*channel*/) throw() 00509 { 00510 const UnitType& input = this->getInputAsUnit (IOKey::Generic); 00511 00512 this->setBlockSize (BlockSize::decide (input.getMaxBlockSize(), 00513 this->getBlockSize())); 00514 this->setSampleRate (SampleRate::decide (input.getMaxSampleRate(), 00515 this->getSampleRate())); 00516 00517 const int numChannels = input.getNumChannels(); 00518 float value = 0.f; 00519 00520 for (int i = 0; i < numChannels; ++i) 00521 value += input.getValue (i); 00522 00523 this->initValue (value); 00524 } 00525 00526 void process (ProcessInfo& info, const int /*channel*/) throw() 00527 { 00528 float* const outputSamples = this->getOutputSamples(); 00529 const int outputBufferLength = this->getOutputBuffer().length(); 00530 pl_VectorClearF_N (outputSamples, outputBufferLength); 00531 00532 UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic)); 00533 const int numChannels = inputUnit.getNumChannels(); 00534 00535 p.buffers[0].bufferSize = outputBufferLength; 00536 p.buffers[0].buffer = outputSamples; 00537 00538 // channel 0 00539 { 00540 plonk_assert (inputUnit.getOverlap (0) == Math<DoubleVariable>::get1()); 00541 00542 const Buffer& inputBuffer (inputUnit.process (info, 0)); 00543 const float* const inputSamples = inputBuffer.getArray(); 00544 const int inputBufferLength = inputBuffer.length(); 00545 00546 if (outputBufferLength == inputBufferLength) 00547 { 00548 pl_VectorMoveF_NN (outputSamples, inputSamples, outputBufferLength); 00549 } 00550 else 00551 { 00552 p.buffers[1].bufferSize = inputBuffer.length(); 00553 p.buffers[1].buffer = inputBuffer.getArray(); 00554 plink_UnaryOpProcessMoveF_Nn (reinterpret_cast<UnaryProcess*>(&p), 0); 00555 } 00556 } 00557 00558 p.buffers[1].bufferSize = outputBufferLength; 00559 p.buffers[1].buffer = outputSamples; 00560 00561 // channels 1+ 00562 for (int channel = 1; channel < numChannels; ++channel) 00563 { 00564 plonk_assert (inputUnit.getOverlap (channel) == Math<DoubleVariable>::get1()); 00565 00566 const Buffer& inputBuffer (inputUnit.process (info, channel)); 00567 const float* const inputSamples = inputBuffer.getArray(); 00568 const int inputBufferLength = inputBuffer.length(); 00569 00570 if (outputBufferLength == inputBufferLength) 00571 { 00572 pl_VectorAddF_NNN (outputSamples, outputSamples, inputSamples, outputBufferLength); 00573 } 00574 else 00575 { 00576 p.buffers[2].bufferSize = inputBuffer.length(); 00577 p.buffers[2].buffer = inputBuffer.getArray(); 00578 plink_BinaryOpProcessAddF_NNn (&p, 0); 00579 } 00580 } 00581 00582 const Data& data = this->getState(); 00583 00584 if (data.allowAutoDelete == false) 00585 info.resetShouldDelete(); 00586 } 00587 00588 private: 00589 Process p; 00590 }; 00591 00592 00593 template<> 00594 class UnitMixerChannelInternal<float> 00595 : public ProxyOwnerChannelInternal<float, PLONK_CHANNELDATA_NAME(UnitMixerChannelInternal,float)> 00596 { 00597 public: 00598 typedef PLONK_CHANNELDATA_NAME(UnitMixerChannelInternal,float) Data; 00599 typedef ChannelBase<float> ChannelType; 00600 typedef ObjectArray<ChannelType> ChannelArrayType; 00601 typedef ProxyOwnerChannelInternal<float,Data> Internal; 00602 typedef UnitBase<float> UnitType; 00603 typedef InputDictionary Inputs; 00604 typedef NumericalArray<float> Buffer; 00605 typedef NumericalArray2D<ChannelType,UnitType> UnitsType; 00606 typedef BinaryOpFunctionsHelper<float>::BinaryOpFunctionsType BinaryOpFunctionsType; 00607 00608 typedef BinaryOpChannelInternal<float,BinaryOpFunctionsType::addop> BinaryOpChannel; 00609 typedef BinaryOpChannel::Process Process; 00610 00611 UnitMixerChannelInternal (Inputs const& inputs, 00612 Data const& data, 00613 BlockSize const& blockSize, 00614 SampleRate const& sampleRate, 00615 ChannelArrayType& channels) throw() 00616 : Internal (data.preferredNumChannels > 0 ? data.preferredNumChannels : inputs.getMaxNumChannels(), 00617 inputs, data, blockSize, sampleRate, channels) 00618 { 00619 plonk_staticassert (BinaryOpChannel::NumBuffers == (BinaryOpChannel::NumInputs + BinaryOpChannel::NumOutputs)); 00620 Process::init (&p, this, BinaryOpChannel::NumOutputs, BinaryOpChannel::NumInputs); 00621 } 00622 00623 Text getName() const throw() 00624 { 00625 return "Unit Mixer"; 00626 } 00627 00628 IntArray getInputKeys() const throw() 00629 { 00630 const IntArray keys (IOKey::Units); 00631 return keys; 00632 } 00633 00634 void initChannel (const int channel) throw() 00635 { 00636 if ((channel % this->getNumChannels()) == 0) 00637 { 00638 // should look at the initial array in case no preference was given really... 00639 this->setBlockSize (BlockSize::decide (BlockSize::getDefault(), 00640 this->getBlockSize())); 00641 this->setSampleRate (SampleRate::decide (SampleRate::getDefault(), 00642 this->getSampleRate())); 00643 } 00644 00645 const Units& units = this->getInputAsUnits (IOKey::Units); 00646 00647 const int numUnits = units.length(); 00648 float value (0.f); 00649 00650 for (int i = 0; i < numUnits; ++i) 00651 value += units.atUnchecked (i).getValue (channel); 00652 00653 this->initProxyValue (channel, value); 00654 } 00655 00656 void process (ProcessInfo& info, const int /*channel*/) throw() 00657 { 00658 int channel, unit; 00659 const Data& data = this->getState(); 00660 UnitsType& units = this->getInputAsUnits (IOKey::Units); 00661 00662 if (data.purgeExpiredUnits) 00663 { 00664 // remove nulls... 00665 for (unit = units.length(); --unit >= 0;) 00666 if (units.atUnchecked (unit).shouldBeDeletedNow (info)) 00667 units.remove (unit); 00668 } 00669 00670 const int numChannels = this->getNumChannels(); 00671 const int numUnits = units.length(); 00672 00673 // ..and process. 00674 for (channel = 0; channel < numChannels; ++channel) 00675 { 00676 Buffer outputBuffer = this->getOutputBuffer (channel); 00677 float* const outputSamples = outputBuffer.getArray(); 00678 const int outputBufferLength = outputBuffer.length(); 00679 pl_VectorClearF_N (outputSamples, outputBufferLength); 00680 00681 p.buffers[0].bufferSize = outputBufferLength; 00682 p.buffers[0].buffer = outputSamples; 00683 p.buffers[1].bufferSize = outputBufferLength; 00684 p.buffers[1].buffer = outputSamples; 00685 00686 for (unit = 0; unit < numUnits; ++unit) 00687 { 00688 UnitType& inputUnit (units.atUnchecked (unit)); 00689 00690 if (!inputUnit.wrapAt (channel).shouldBeDeletedNow (info.getTimeStamp())) 00691 { 00692 plonk_assert (inputUnit.getOverlap (channel) == Math<DoubleVariable>::get1()); 00693 00694 const Buffer inputBuffer (inputUnit.process (info, channel)); 00695 const float* const inputSamples = inputBuffer.getArray(); 00696 const int inputBufferLength = inputBuffer.length(); 00697 00698 if (outputBufferLength == inputBufferLength) 00699 { 00700 pl_VectorAddF_NNN (outputSamples, outputSamples, inputSamples, outputBufferLength); 00701 } 00702 else 00703 { 00704 p.buffers[2].bufferSize = inputBuffer.length(); 00705 p.buffers[2].buffer = inputBuffer.getArray(); 00706 plink_BinaryOpProcessAddF_NNn (&p, 0); 00707 } 00708 00709 if (data.allowAutoDelete == false) 00710 info.resetShouldDelete(); 00711 } 00712 } 00713 } 00714 } 00715 00716 private: 00717 Process p; 00718 }; 00719 00720 00721 00722 #endif //PLONK_USEPLINK 00723 00724 00725 //------------------------------------------------------------------------------ 00726 00747 template<class SampleType> 00748 class MixerUnit 00749 { 00750 public: 00751 typedef ChannelMixerChannelInternal<SampleType> ChannelMixerInternal; 00752 typedef UnitMixerChannelInternal<SampleType> UnitMixerInternal; 00753 typedef QueueMixerChannelInternal<SampleType> QueueMixerInternal; 00754 typedef ChannelBase<SampleType> ChannelType; 00755 typedef UnitBase<SampleType> UnitType; 00756 typedef NumericalArray2D<ChannelType,UnitType> UnitsType; 00757 typedef InputDictionary Inputs; 00758 typedef LockFreeQueue<UnitType> QueueType; 00759 00760 static inline UnitInfos getInfo() throw() 00761 { 00762 const double blockSize = (double)BlockSize::getDefault().getValue(); 00763 const double sampleRate = SampleRate::getDefault().getValue(); 00764 00765 return UnitInfos (UnitInfo ("Channel Mixer", "Mixes all channels in an input unit down to a single channel.", 00766 00767 // output 00768 1, 00769 IOKey::Generic, Measure::None, IOInfo::NoDefault, IOLimit::None, IOKey::End, 00770 00771 // inputs 00772 IOKey::Generic, Measure::None, IOInfo::NoDefault, IOLimit::None, 00773 IOKey::AutoDeleteFlag, Measure::Bool, IOInfo::True, IOLimit::None, 00774 IOKey::Multiply, Measure::Factor, 1.0, IOLimit::None, 00775 IOKey::Add, Measure::None, 0.0, IOLimit::None, 00776 IOKey::BlockSize, Measure::Samples, blockSize, IOLimit::Minimum, Measure::Samples, 1.0, 00777 IOKey::SampleRate, Measure::Hertz, sampleRate, IOLimit::Minimum, Measure::Hertz, 0.0, 00778 IOKey::End), 00779 00780 UnitInfo ("Unit Mixer", "Mixes a queue of units down to a multichannel unit.", 00781 00782 // output 00783 ChannelCount::VariableChannelCount, 00784 IOKey::Generic, Measure::None, IOInfo::NoDefault, IOLimit::None, IOKey::End, 00785 00786 // inputs 00787 IOKey::UnitQueue, Measure::None, 00788 IOKey::AutoDeleteFlag, Measure::Bool, IOInfo::True, IOLimit::None, 00789 IOKey::Multiply, Measure::Factor, 1.0, IOLimit::None, 00790 IOKey::Add, Measure::None, 0.0, IOLimit::None, 00791 IOKey::BlockSize, Measure::Samples, blockSize, IOLimit::Minimum, Measure::Samples, 1.0, 00792 IOKey::SampleRate, Measure::Hertz, sampleRate, IOLimit::Minimum, Measure::Hertz, 0.0, 00793 IOKey::End), 00794 00795 UnitInfo ("Queue Mixer", "Mixes multichannel units down to a multichannel unit.", 00796 00797 // output 00798 ChannelCount::VariableChannelCount, 00799 IOKey::Generic, Measure::None, IOInfo::NoDefault, IOLimit::None, IOKey::End, 00800 00801 // inputs 00802 IOKey::Units, Measure::None, 00803 IOKey::AutoDeleteFlag, Measure::Bool, IOInfo::True, IOLimit::None, 00804 IOKey::PurgeExpiredUnitsFlag, Measure::Bool, IOInfo::True, IOLimit::None, 00805 IOKey::PreferredNumChannels, Measure::Count, 0.0, IOLimit::None, 00806 IOKey::Multiply, Measure::Factor, 1.0, IOLimit::None, 00807 IOKey::Add, Measure::None, 0.0, IOLimit::None, 00808 IOKey::BlockSize, Measure::Samples, blockSize, IOLimit::Minimum, Measure::Samples, 1.0, 00809 IOKey::SampleRate, Measure::Hertz, sampleRate, IOLimit::Minimum, Measure::Hertz, 0.0, 00810 IOKey::End)); 00811 } 00812 00813 00815 static UnitType ar (UnitType const& input, 00816 const bool allowAutoDelete = true, 00817 UnitType const& mul = SampleType (1), 00818 UnitType const& add = SampleType (0), 00819 BlockSize const& preferredBlockSize = BlockSize::getDefault(), 00820 SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw() 00821 { 00822 typedef PLONK_CHANNELDATA_NAME(ChannelMixerChannelInternal,SampleType) Data; 00823 00824 Inputs inputs; 00825 inputs.put (IOKey::Generic, input); 00826 inputs.put (IOKey::Multiply, mul); 00827 inputs.put (IOKey::Add, add); 00828 00829 Data data = { { -1.0, -1.0 }, allowAutoDelete }; 00830 00831 return UnitType::template createFromInputs<ChannelMixerInternal> (inputs, 00832 data, 00833 preferredBlockSize, 00834 preferredSampleRate); 00835 } 00836 00838 static UnitType ar (UnitsType const& array, 00839 const bool allowAutoDelete = true, 00840 const bool purgeExpiredUnits = true, 00841 const int preferredNumChannels = 0, 00842 UnitType const& mul = SampleType (1), 00843 UnitType const& add = SampleType (0), 00844 BlockSize const& preferredBlockSize = BlockSize::getDefault(), 00845 SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw() 00846 { 00847 typedef PLONK_CHANNELDATA_NAME(UnitMixerChannelInternal,SampleType) Data; 00848 00849 Inputs inputs; 00850 inputs.put (IOKey::Units, array); 00851 inputs.put (IOKey::Multiply, mul); 00852 inputs.put (IOKey::Add, add); 00853 00854 Data data = { { -1.0, -1.0 }, preferredNumChannels, allowAutoDelete, purgeExpiredUnits }; 00855 00856 return UnitType::template proxiesFromInputs<UnitMixerInternal> (inputs, 00857 data, 00858 preferredBlockSize, 00859 preferredSampleRate); 00860 } 00861 00863 static UnitType ar (QueueType const& queue, 00864 const bool allowAutoDelete = true, 00865 const bool purgeExpiredUnits = true, 00866 const int preferredNumChannels = 0, 00867 UnitType const& mul = SampleType (1), 00868 UnitType const& add = SampleType (0), 00869 BlockSize const& preferredBlockSize = BlockSize::getDefault(), 00870 SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw() 00871 { 00872 typedef PLONK_CHANNELDATA_NAME(QueueMixerChannelInternal,SampleType) Data; 00873 00874 Inputs inputs; 00875 inputs.put (IOKey::UnitQueue, queue); 00876 inputs.put (IOKey::Multiply, mul); 00877 inputs.put (IOKey::Add, add); 00878 00879 Data data = { { -1.0, -1.0 }, preferredNumChannels, allowAutoDelete, purgeExpiredUnits }; 00880 00881 return UnitType::template proxiesFromInputs<QueueMixerInternal> (inputs, 00882 data, 00883 preferredBlockSize, 00884 preferredSampleRate); 00885 } 00886 00887 }; 00888 00889 typedef MixerUnit<PLONK_TYPE_DEFAULT> Mixer; 00890 00891 #endif // PLONK_MIXERS_H