pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_BinaryOpChannel.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_BINARYOPCHANNEL_H
00040 #define PLONK_BINARYOPCHANNEL_H
00041 
00042 #include "../../maths/plonk_InlineBinaryOps.h"
00043 #include "../channel/plonk_ChannelInternalCore.h"
00044 #include "../plonk_GraphForwardDeclarations.h"
00045 
00046 template<class SampleType>
00047 class BinaryOpUtility
00048 {
00049 private:
00050     typedef SampleType (*Function)(SampleType const&,SampleType const&);
00051     typedef typename BinaryOpFunctionsHelper<SampleType>::BinaryOpFunctionsType BinaryOpFunctionsType;    
00052     
00053     BinaryOpUtility() throw()
00054     {
00055         names.put (&BinaryOpFunctionsType::addop,                   "add");
00056         names.put (&BinaryOpFunctionsType::subop,                   "subtract");
00057         names.put (&BinaryOpFunctionsType::mulop,                   "multiply");
00058         names.put (&BinaryOpFunctionsType::divop,                   "divide");
00059         names.put (&BinaryOpFunctionsType::modop,                   "modulo");
00060         names.put (&BinaryOpFunctionsType::isEqualTo,               "==");
00061         names.put (&BinaryOpFunctionsType::isNotEqualTo,            "=");
00062         names.put (&BinaryOpFunctionsType::isGreaterThan,           ">");
00063         names.put (&BinaryOpFunctionsType::isGreaterThanOrEqualTo,  ">=");
00064         names.put (&BinaryOpFunctionsType::isLessThan,              "<");
00065         names.put (&BinaryOpFunctionsType::isLessThanOrEqualTo,     "<=");
00066         names.put (&BinaryOpFunctionsType::hypot,                   "hypot");
00067         names.put (&BinaryOpFunctionsType::pow,                     "pow");
00068         names.put (&BinaryOpFunctionsType::atan2,                   "atan2");
00069         names.put (&BinaryOpFunctionsType::min,                     "min");
00070         names.put (&BinaryOpFunctionsType::max,                     "max");
00071         names.put (&BinaryOpFunctionsType::sumsqr,                  "sumsqr");
00072         names.put (&BinaryOpFunctionsType::difsqr,                  "difsqr");
00073         names.put (&BinaryOpFunctionsType::sqrsum,                  "sqrsum");
00074         names.put (&BinaryOpFunctionsType::sqrdif,                  "sqrdif");
00075         names.put (&BinaryOpFunctionsType::absdif,                  "absdif");
00076         names.put (&BinaryOpFunctionsType::thresh,                  "thresh");
00077         names.put (&BinaryOpFunctionsType::round,                   "round");
00078         names.put (&BinaryOpFunctionsType::trunc,                   "trunc");
00079         names.put (&BinaryOpFunctionsType::clip2,                   "clip2");
00080         names.put (&BinaryOpFunctionsType::decayFeedback,           "decayFeedback");
00081     }
00082     
00083 public:
00084     inline Text getName (Function function) const throw()
00085     {
00086         return names[function];
00087     }
00088     
00089     inline void add (Function function, Text const& name) throw()
00090     {
00091         names.put (function, name);
00092     }    
00093     
00094     static BinaryOpUtility& global() throw()
00095     {
00096         static BinaryOpUtility util;
00097         return util;
00098     }
00099     
00100 private:
00101     Dictionary<Text, Function> names;
00102 };
00103 
00104 
00105 //------------------------------------------------------------------------------
00106 
00107 
00109 template<class SampleType, PLONK_BINARYOPFUNCTION(SampleType, op)>
00110 class BinaryOpChannelInternal 
00111 :   public ChannelInternal<SampleType, ChannelInternalCore::Data>
00112 {
00113 public:
00114     typedef typename ChannelInternalCore::Data      Data;
00115     typedef typename BinaryOpFunctionsHelper<SampleType>::BinaryOpFunctionsType BinaryOpFunctionsType;
00116 
00117     typedef ChannelBase<SampleType>                 ChannelType;
00118     typedef BinaryOpChannelInternal<SampleType,op>  BinaryOpInternal;
00119     typedef ChannelInternal<SampleType,Data>        Internal;
00120     typedef ChannelInternalBase<SampleType>         InternalBase;
00121     typedef UnitBase<SampleType>                    UnitType;
00122     typedef InputDictionary                         Inputs;
00123     typedef NumericalArray<SampleType>              Buffer;
00124     typedef BinaryOpUtility<SampleType>             UtilityType;
00125         
00126 
00127     BinaryOpChannelInternal (Inputs const& inputs, 
00128                              Data const& data, 
00129                              BlockSize const& blockSize,
00130                              SampleRate const& sampleRate) throw()
00131     :   Internal (inputs, data, blockSize, sampleRate)
00132     {
00133     }
00134     
00135     Text getName() const throw()
00136     {
00137         Text variant = UtilityType::global().getName (op);
00138         
00139         if (variant.length() < 1)
00140             variant = "unknown type";
00141         
00142         return "Binary Operator (" + variant + ")";
00143     }    
00144     
00145     IntArray getInputKeys() const throw()
00146     {
00147         const IntArray keys (IOKey::LeftOperand,
00148                              IOKey::RightOperand);
00149         return keys;
00150     }
00151     
00152     
00153     InternalBase* getChannel (const int index) throw()
00154     {
00155         const Inputs channelInputs = this->getInputs().getChannel (index);
00156         return new BinaryOpInternal (channelInputs, 
00157                                      this->getState(), 
00158                                      this->getBlockSize(), 
00159                                      this->getSampleRate());
00160     }        
00161     
00162     void initChannel(const int channel) throw()
00163     {
00164         const UnitType& leftUnit = this->getInputAsUnit (IOKey::LeftOperand);
00165         const SampleType leftValue = leftUnit.getValue (channel);
00166         const UnitType& rightUnit = this->getInputAsUnit (IOKey::RightOperand);
00167         const SampleType rightValue = rightUnit.getValue (channel);
00168 
00169         this->setBlockSize (BlockSize::decide (leftUnit.getBlockSize (channel).selectMax (rightUnit.getBlockSize (channel)),
00170                                                this->getBlockSize()));
00171         this->setSampleRate (SampleRate::decide (leftUnit.getSampleRate (channel).selectMax (rightUnit.getSampleRate (channel)),
00172                                                  this->getSampleRate()));                        
00173             
00174         const DoubleVariable leftOverlap = leftUnit.getOverlap (channel);
00175         const DoubleVariable rightOverlap = rightUnit.getOverlap (channel);
00176 
00177         if (leftOverlap == rightOverlap)
00178             this->setOverlap (leftOverlap);
00179         else if (leftUnit.isConstant (channel))
00180             this->setOverlap (rightOverlap);
00181         else if (rightUnit.isConstant (channel))
00182             this->setOverlap (leftOverlap);
00183         else
00184             plonk_assertfalse;
00185         
00186         this->initValue (op (leftValue, rightValue));
00187     }    
00188     
00189     void process (ProcessInfo& info, const int channel) throw()
00190     {
00191         UnitType& leftUnit (this->getInputAsUnit (IOKey::LeftOperand));
00192         UnitType& rightUnit (this->getInputAsUnit (IOKey::RightOperand));
00193         
00194         const Buffer& leftBuffer (leftUnit.process (info, channel));
00195         const Buffer& rightBuffer (rightUnit.process (info, channel));
00196         
00197         SampleType* const outputSamples = this->getOutputSamples();
00198         const int outputBufferLength = this->getOutputBuffer().length();
00199         
00200         const SampleType* const leftSamples = leftBuffer.getArray();
00201         const int leftBufferLength = leftBuffer.length();
00202         const SampleType* const rightSamples = rightBuffer.getArray();
00203         const int rightBufferLength = rightBuffer.length();
00204 
00205         int i;
00206         
00207         if ((leftBufferLength == outputBufferLength) && (rightBufferLength == outputBufferLength))
00208         {
00209             NumericalArrayBinaryOp<SampleType,op>::calcNN (outputSamples, leftSamples, rightSamples, outputBufferLength);
00210         }
00211         else if (rightBufferLength == outputBufferLength)
00212         {
00213             if (leftBufferLength == 1)
00214             {
00215                 NumericalArrayBinaryOp<SampleType,op>::calc1N (outputSamples, leftSamples[0], rightSamples, outputBufferLength);
00216             }
00217             else
00218             {
00219                 double leftPosition = 0.0;
00220                 const double leftIncrement = double (leftBufferLength) / double (outputBufferLength);
00221                 
00222                 for (i = 0; i < outputBufferLength; ++i) 
00223                 {
00224                     outputSamples[i] = op (leftSamples[int (leftPosition)],
00225                                            rightSamples[i]);
00226                     
00227                     leftPosition += leftIncrement;
00228                 }                     
00229             }
00230         }
00231         else if (leftBufferLength == outputBufferLength)
00232         {
00233             if (rightBufferLength == 1)
00234             {
00235                 NumericalArrayBinaryOp<SampleType,op>::calcN1 (outputSamples, leftSamples, rightSamples[0], outputBufferLength);
00236             }
00237             else
00238             {
00239                 double rightPosition = 0.0;
00240                 const double rightIncrement = double (rightBufferLength) / double (outputBufferLength);
00241 
00242                 for (i = 0; i < outputBufferLength; ++i) 
00243                 {
00244                     outputSamples[i] = op (leftSamples[i],
00245                                            rightSamples[int (rightPosition)]);
00246                     
00247                     rightPosition += rightIncrement;
00248                 }                     
00249             }
00250         }
00251         else
00252         {
00253             double leftPosition = 0.0;
00254             const double leftIncrement = double (leftBufferLength) / double (outputBufferLength);
00255             
00256             double rightPosition = 0.0;
00257             const double rightIncrement = double (rightBufferLength) / double (outputBufferLength);
00258             
00259             for (i = 0; i < outputBufferLength; ++i) 
00260             {
00261                 outputSamples[i] = op (leftSamples[int (leftPosition)],
00262                                        rightSamples[int (rightPosition)]);
00263                 
00264                 leftPosition += leftIncrement;
00265                 rightPosition += rightIncrement;
00266             }     
00267         }
00268     }
00269 };
00270 
00271 
00272 #endif // PLONK_BINARYOPCHANNEL_H
 All Classes Functions Typedefs Enumerations Enumerator Properties