pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_SchmidtChannel.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_SCHMIDTCHANNEL_H
00040 #define PLONK_SCHMIDTCHANNEL_H
00041 
00042 #include "../channel/plonk_ChannelInternalCore.h"
00043 #include "../plonk_GraphForwardDeclarations.h"
00044 
00045 template<class SampleType> class SchmidtChannelInternal;
00046 
00047 PLONK_CHANNELDATA_DECLARE(SchmidtChannelInternal,SampleType)
00048 {
00049     ChannelInternalCore::Data base;
00050     SampleType currentState;
00051 };
00052 
00054 template<class SampleType>
00055 class SchmidtChannelInternal 
00056 :   public ChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(SchmidtChannelInternal,SampleType)>
00057 {
00058 public:
00059     typedef PLONK_CHANNELDATA_NAME(SchmidtChannelInternal,SampleType)   Data;
00060     typedef ChannelBase<SampleType>                                     ChannelType;
00061     typedef SchmidtChannelInternal<SampleType>                          SchmidtInternal;
00062     typedef ChannelInternal<SampleType,Data>                            Internal;
00063     typedef ChannelInternalBase<SampleType>                             InternalBase;
00064     typedef UnitBase<SampleType>                                        UnitType;
00065     typedef InputDictionary                                             Inputs;
00066     typedef NumericalArray<SampleType>                                  Buffer;
00067             
00068     SchmidtChannelInternal (Inputs const& inputs, 
00069                             Data const& data,
00070                             BlockSize const& blockSize,
00071                             SampleRate const& sampleRate) throw()
00072     :   Internal (inputs, data, blockSize, sampleRate)
00073     {
00074     }
00075     
00076     Text getName() const throw()
00077     {
00078         return "Schmidt";
00079     }        
00080     
00081     IntArray getInputKeys() const throw()
00082     {
00083         const IntArray keys (IOKey::Generic, IOKey::Minimum, IOKey::Maximum);
00084         return keys;
00085     }
00086     
00087     InternalBase* getChannel (const int index) throw()
00088     {
00089         const Inputs channelInputs = this->getInputs().getChannel (index);
00090         return new SchmidtInternal (channelInputs, 
00091                                     this->getState(), 
00092                                     this->getBlockSize(),
00093                                     this->getSampleRate());
00094     }    
00095     
00096     void initChannel (const int channel) throw()
00097     {        
00098         const UnitType& input = this->getInputAsUnit (IOKey::Generic);
00099 
00100         this->setBlockSize (BlockSize::decide (input.getBlockSize (channel),
00101                                                this->getBlockSize()));
00102         this->setSampleRate (SampleRate::decide (input.getSampleRate (channel),
00103                                                  this->getSampleRate()));
00104         this->setOverlap (input.getOverlap (channel));
00105     
00106         this->initValue (0);
00107     }    
00108         
00109     void process (ProcessInfo& info, const int channel) throw()
00110     {
00111         Data& data = this->getState();
00112         
00113         UnitType& inputUnit (this->getInputAsUnit (IOKey::Generic));
00114         const Buffer& inputBuffer (inputUnit.process (info, channel));
00115         const SampleType* inputSamples = inputBuffer.getArray();
00116         const int inputBufferLength = inputBuffer.length();
00117 
00118         UnitType& minimumUnit (this->getInputAsUnit (IOKey::Minimum));
00119         const Buffer& minimumBuffer (minimumUnit.process (info, channel));
00120         const SampleType* minimumSamples = minimumBuffer.getArray();
00121         const int minimumBufferLength = minimumBuffer.length();
00122 
00123         UnitType& maximumUnit (this->getInputAsUnit (IOKey::Maximum));
00124         const Buffer& maximumBuffer (maximumUnit.process (info, channel));
00125         const SampleType* maximumSamples = maximumBuffer.getArray();
00126         const int maximumBufferLength = maximumBuffer.length();
00127 
00128         SampleType* outputSamples = this->getOutputSamples();
00129         const int outputBufferLength = this->getOutputBuffer().length();
00130         
00131         const SampleType sampleZero = Math<SampleType>::get0();
00132         const SampleType sampleOne = Math<SampleType>::get1();
00133         SampleType currentState = data.currentState;
00134         
00135         int i = 0;
00136         
00137         if (inputBufferLength == outputBufferLength)
00138         {
00139             if ((inputBufferLength == minimumBufferLength) &&
00140                 (inputBufferLength == maximumBufferLength))
00141             {
00142                 for (i = 0; i < outputBufferLength; ++i)
00143                 {
00144                     if (currentState == sampleZero)
00145                     {
00146                         if (inputSamples[i] > maximumSamples[i])
00147                             currentState = sampleOne;
00148                     }
00149                     else
00150                     {
00151                         if (inputSamples[i] < minimumSamples[i])
00152                             currentState = sampleZero;
00153                     }
00154 
00155                     outputSamples[i] = currentState;
00156                 }
00157             }
00158             else if ((minimumBufferLength == 1) &&
00159                      (maximumBufferLength == 1))
00160             {
00161                 const SampleType minimum = minimumSamples[0];
00162                 const SampleType maximum = maximumSamples[0];
00163                 
00164                 for (i = 0; i < outputBufferLength; ++i)
00165                 {
00166                     if (currentState == sampleZero)
00167                     {
00168                         if (inputSamples[i] > maximum)
00169                             currentState = sampleOne;
00170                     }
00171                     else
00172                     {
00173                         if (inputSamples[i] < minimum)
00174                             currentState = sampleZero;
00175                     }
00176                     
00177                     outputSamples[i] = currentState;
00178                 }
00179             }
00180         }
00181         else if (i == 0) // none of the other routines executed..
00182         {
00183             double inputPosition = 0.0;
00184             const double inputIncrement = double (inputBufferLength) / double (outputBufferLength);
00185             double minimumPosition = 0.0;
00186             const double minimumIncrement = double (minimumBufferLength) / double (outputBufferLength);
00187             double maximumPosition = 0.0;
00188             const double maximumIncrement = double (maximumBufferLength) / double (outputBufferLength);
00189    
00190             for (i = 0; i < outputBufferLength; ++i)
00191             {
00192                 if (currentState == sampleZero)
00193                 {
00194                     if (inputSamples[int (inputPosition)] > maximumSamples[int (maximumPosition)])
00195                         currentState = sampleOne;
00196                 }
00197                 else
00198                 {
00199                     if (inputSamples[int (inputPosition)] < minimumSamples[int (minimumPosition)])
00200                         currentState = sampleZero;
00201                 }
00202                 
00203                 outputSamples[i] = currentState;
00204                 
00205                 inputPosition += inputIncrement;
00206                 minimumPosition += minimumIncrement;
00207                 maximumPosition += maximumIncrement;
00208             }
00209         }
00210                             
00211                         
00212         data.currentState = currentState;
00213     }
00214 };
00215 
00216 //------------------------------------------------------------------------------
00217 
00232 template<class SampleType>
00233 class SchmidtUnit
00234 {
00235 public:    
00236     typedef SchmidtChannelInternal<SampleType>      SchmidtInternal;
00237     typedef typename SchmidtInternal::Data          Data;
00238     typedef ChannelBase<SampleType>                 ChannelType;
00239     typedef ChannelInternal<SampleType,Data>        Internal;
00240     typedef UnitBase<SampleType>                    UnitType;
00241     typedef InputDictionary                         Inputs;    
00242     
00243     static inline UnitInfos getInfo() throw()
00244     {
00245         const double blockSize = (double)BlockSize::getDefault().getValue();
00246         const double sampleRate = SampleRate::getDefault().getValue();
00247 
00248         return UnitInfo ("Schmidt", "Trigger with hysteresis.",
00249                          
00250                          // output
00251                          ChannelCount::VariableChannelCount, 
00252                          IOKey::Generic,    Measure::None,     IOInfo::NoDefault,   IOLimit::None,      IOKey::End,
00253 
00254                          // inputs
00255                          IOKey::Generic,    Measure::None,     IOInfo::NoDefault,   IOLimit::None,
00256                          IOKey::Minimum,    Measure::None,     IOInfo::NoDefault,   IOLimit::None,
00257                          IOKey::Maximum,    Measure::None,     IOInfo::NoDefault,   IOLimit::None,
00258                          IOKey::BlockSize,  Measure::Samples,  blockSize,           IOLimit::Minimum,   Measure::Samples,   1.0,
00259                          IOKey::SampleRate, Measure::Hertz,    sampleRate,          IOLimit::Minimum,   Measure::Hertz,     0.0,
00260                          IOKey::End);
00261     }    
00262     
00264     static UnitType ar (UnitType const& input,
00265                         UnitType const& minimum,
00266                         UnitType const& maximum,
00267                         BlockSize const& preferredBlockSize = BlockSize::getDefault(),
00268                         SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw()
00269     {                                
00270         Inputs inputs;
00271         inputs.put (IOKey::Generic, input);
00272         inputs.put (IOKey::Minimum, minimum);
00273         inputs.put (IOKey::Maximum, maximum);
00274         
00275         Data data = { { -1.0, -1.0 }, 0 };
00276                 
00277         return UnitType::template createFromInputs<SchmidtInternal> (inputs, 
00278                                                                      data,
00279                                                                      preferredBlockSize,
00280                                                                      preferredSampleRate);
00281     }
00282     
00283     static inline UnitType kr (UnitType const& input,
00284                                UnitType const& minimum,
00285                                UnitType const& maximum) throw()
00286     {
00287         return ar (input, minimum, maximum,
00288                    BlockSize::getControlRateBlockSize(), 
00289                    SampleRate::getControlRate());
00290     }
00291     
00292 };
00293 
00294 typedef SchmidtUnit<PLONK_TYPE_DEFAULT> Schmidt;
00295 
00296 
00297 
00298 #endif // PLONK_SCHMIDTCHANNEL_H
00299 
00300 
 All Classes Functions Typedefs Enumerations Enumerator Properties