pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_Mixers.h
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
 All Classes Functions Typedefs Enumerations Enumerator Properties