pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_Saw.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_SAW_H
00040 #define PLONK_SAW_H
00041 
00042 #include "../channel/plonk_ChannelInternalCore.h"
00043 #include "../plonk_GraphForwardDeclarations.h"
00044 
00045 template<class SampleType> class SawChannelInternal;
00046 
00047 PLONK_CHANNELDATA_DECLARE(SawChannelInternal,SampleType)
00048 {    
00049     typedef typename TypeUtility<SampleType>::IndexType FrequencyType;
00050 
00051     ChannelInternalCore::Data base;
00052     
00053     FrequencyType currentValue;
00054     LongLong peak;
00055     LongLong peak2peak;
00056 };      
00057 
00058 PLONK_CHANNELDATA_SPECIAL(SawChannelInternal,float)
00059 {    
00060     ChannelInternalCore::Data base;
00061     
00062     float currentValue;
00063     float peak;
00064     float peak2peak;
00065 };        
00066 
00067 PLONK_CHANNELDATA_SPECIAL(SawChannelInternal,double)
00068 {    
00069     ChannelInternalCore::Data base;
00070     
00071     double currentValue;
00072     double peak;
00073     double peak2peak;
00074 };        
00075 
00076 PLONK_CHANNELDATA_SPECIAL(SawChannelInternal,short)
00077 {    
00078     typedef TypeUtility<short>::IndexType FrequencyType;
00079 
00080     ChannelInternalCore::Data base;
00081     
00082     FrequencyType currentValue;
00083     short peak;
00084     int peak2peak;
00085 };      
00086 
00087 PLONK_CHANNELDATA_SPECIAL(SawChannelInternal,int)
00088 {    
00089     typedef TypeUtility<int>::IndexType FrequencyType;
00090 
00091     ChannelInternalCore::Data base;
00092     
00093     FrequencyType currentValue;
00094     int peak;
00095     LongLong peak2peak;
00096 };        
00097 
00098 
00099 
00100 //------------------------------------------------------------------------------
00101 
00103 template<class SampleType>
00104 class SawChannelInternal 
00105 :   public ChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(SawChannelInternal,SampleType)>
00106 {
00107 public:
00108     typedef PLONK_CHANNELDATA_NAME(SawChannelInternal,SampleType)     Data;
00109     typedef InputDictionary                                     Inputs;
00110 
00111     typedef ChannelBase<SampleType>                             ChannelType;
00112     typedef SawChannelInternal<SampleType>                      SawInternal;
00113     typedef ChannelInternal<SampleType,Data>                    Internal;
00114     typedef ChannelInternalBase<SampleType>                     InternalBase;
00115     typedef UnitBase<SampleType>                                UnitType;
00116     
00117     typedef typename TypeUtility<SampleType>::IndexType         FrequencyType;
00118     typedef UnitBase<FrequencyType>                             FrequencyUnitType;
00119     typedef NumericalArray<FrequencyType>                       FrequencyBufferType;
00120 
00121     SawChannelInternal (Inputs const& inputs, 
00122                         Data const& data, 
00123                         BlockSize const& blockSize,
00124                         SampleRate const& sampleRate) throw()
00125     :   Internal (inputs, data, blockSize, sampleRate)
00126     {
00127     }
00128             
00129     Text getName() const throw()
00130     {
00131         return "Saw";
00132     }       
00133     
00134     IntArray getInputKeys() const throw()
00135     {
00136         const IntArray keys (IOKey::Frequency);
00137         return keys;
00138     }    
00139     
00140     InternalBase* getChannel (const int index) throw()
00141     {
00142         const Inputs channelInputs = this->getInputs().getChannel (index);
00143         return new SawInternal (channelInputs, 
00144                                 this->getState(), 
00145                                 this->getBlockSize(), 
00146                                 this->getSampleRate());
00147     }
00148     
00149     void initChannel (const int channel) throw()
00150     {                
00151         const FrequencyUnitType& frequencyUnit = ChannelInternalCore::getInputAs<FrequencyUnitType> (IOKey::Frequency);
00152         
00153         this->setBlockSize (BlockSize::decide (frequencyUnit.getBlockSize (channel),
00154                                                this->getBlockSize()));
00155         this->setSampleRate (SampleRate::decide (frequencyUnit.getSampleRate (channel),
00156                                                  this->getSampleRate()));
00157         
00158         this->setOverlap (frequencyUnit.getOverlap (channel));
00159         
00160         this->initValue (this->getState().currentValue);
00161     }    
00162     
00163     void process (ProcessInfo& info, const int channel) throw()
00164     {        
00165         Data& data = this->getState();
00166         const double sampleDuration = data.base.sampleDuration;
00167         const double factor = data.peak2peak * sampleDuration;
00168 
00169         FrequencyUnitType& frequencyUnit = ChannelInternalCore::getInputAs<FrequencyUnitType> (IOKey::Frequency);
00170 
00171         const FrequencyBufferType& frequencyBuffer (frequencyUnit.process (info, channel));
00172         const FrequencyType* const frequencySamples = frequencyBuffer.getArray();
00173         const int frequencyBufferLength = frequencyBuffer.length();
00174         
00175         SampleType* const outputSamples = this->getOutputSamples();
00176         const int outputBufferLength = this->getOutputBuffer().length();
00177 
00178         int i;
00179         
00180         if (frequencyBufferLength == outputBufferLength)
00181         {
00182             for (i = 0; i < outputBufferLength; ++i) 
00183             {
00184                 outputSamples[i] = SampleType (data.currentValue);
00185                 data.currentValue += frequencySamples[i] * factor;
00186                 
00187                 if (data.currentValue >= data.peak)
00188                     data.currentValue -= data.peak2peak;
00189                 else if (data.currentValue < -data.peak)        
00190                     data.currentValue += data.peak2peak;                
00191             }                    
00192         }
00193         else if (frequencyBufferLength == 1)
00194         {
00195             const FrequencyType valueIncrement (frequencySamples[0] * factor);
00196             
00197             for (i = 0; i < outputBufferLength; ++i) 
00198             {
00199                 outputSamples[i] = SampleType (data.currentValue);
00200                 data.currentValue += valueIncrement;
00201                 
00202                 if (data.currentValue >= data.peak)
00203                     data.currentValue -= data.peak2peak;
00204                 else if (data.currentValue < -data.peak)        
00205                     data.currentValue += data.peak2peak;                
00206             }                    
00207         }
00208         else
00209         {
00210             double frequencyPosition = 0.0;
00211             const double frequencyIncrement = double (frequencyBufferLength) / double (outputBufferLength);
00212                                 
00213             for (i = 0; i < outputBufferLength; ++i) 
00214             {
00215                 outputSamples[i] = SampleType (data.currentValue);
00216                 data.currentValue += frequencySamples[int (frequencyPosition)] * factor;
00217 
00218                 if (data.currentValue >= data.peak)
00219                     data.currentValue -= data.peak2peak;
00220                 else if (data.currentValue < -data.peak)        
00221                     data.currentValue += data.peak2peak;
00222 
00223                 frequencyPosition += frequencyIncrement;
00224             }        
00225         }
00226     }
00227     
00228 private:
00229 };
00230 
00231 //------------------------------------------------------------------------------
00232 
00233 #ifdef PLONK_USEPLINK
00234 
00235 template<>
00236 class SawChannelInternal<float> :   public ChannelInternal<float, SawProcessStateF>
00237 {
00238 public:
00239     typedef SawProcessStateF                Data;
00240     typedef InputDictionary                 Inputs;
00241     typedef ChannelBase<float>              ChannelType;
00242     typedef SawChannelInternal<float>       SawInternal;
00243     typedef ChannelInternal<float,Data>     Internal;
00244     typedef ChannelInternalBase<float>      InternalBase;
00245     typedef UnitBase<float>                 UnitType;
00246     
00247     typedef float                           FrequencyType;
00248     typedef UnitBase<float>                 FrequencyUnitType;
00249     typedef NumericalArray<float>           FrequencyBufferType;
00250     
00251     enum Outputs { Output, NumOutputs };
00252     enum InputIndices  { Frequency, NumInputs };
00253     enum Buffers { OutputBuffer, FrequencyBuffer, NumBuffers };
00254     
00255     typedef PlinkProcess<NumBuffers>        Process;
00256     
00257     SawChannelInternal (Inputs const& inputs, 
00258                         Data const& data, 
00259                         BlockSize const& blockSize,
00260                         SampleRate const& sampleRate) throw()
00261     :   Internal (inputs, data, blockSize, sampleRate)
00262     {
00263         plonk_staticassert (NumBuffers == (NumInputs + NumOutputs));
00264         
00265         Process::init (&p, this, NumOutputs, NumInputs);
00266     }
00267         
00268     Text getName() const throw()
00269     {
00270         return "Saw";
00271     }       
00272     
00273     IntArray getInputKeys() const throw()
00274     {
00275         const IntArray keys (IOKey::Frequency);
00276         return keys;
00277     }    
00278     
00279     InternalBase* getChannel (const int index) throw()
00280     {
00281         const Inputs channelInputs = this->getInputs().getChannel (index);
00282         return new SawInternal (channelInputs, 
00283                                 this->getState(), 
00284                                 this->getBlockSize(), 
00285                                 this->getSampleRate());
00286     }    
00287     
00288     void initChannel (const int channel) throw()
00289     {        
00290         const FrequencyUnitType& frequencyUnit = ChannelInternalCore::getInputAs<FrequencyUnitType> (IOKey::Frequency);
00291 
00292         this->setBlockSize (BlockSize::decide (frequencyUnit.getBlockSize (channel),
00293                                                this->getBlockSize()));
00294         this->setSampleRate (SampleRate::decide (frequencyUnit.getSampleRate (channel),
00295                                                  this->getSampleRate()));
00296         
00297         this->initValue (this->getState().currentValue);
00298     }        
00299     
00300     void process (ProcessInfo& info, const int channel) throw()
00301     {                
00302         FrequencyUnitType& frequencyUnit = ChannelInternalCore::getInputAs<FrequencyUnitType> (IOKey::Frequency);
00303         const FrequencyBufferType& frequencyBuffer (frequencyUnit.process (info, channel));
00304                         
00305         p.buffers[0].bufferSize = this->getOutputBuffer().length();;
00306         p.buffers[0].buffer     = this->getOutputSamples();
00307         p.buffers[1].bufferSize = frequencyBuffer.length();
00308         p.buffers[1].buffer     = frequencyBuffer.getArray();
00309         
00310         plink_SawProcessF (&p, &this->getState());
00311     }
00312   
00313 private:
00314     Process p;
00315 };
00316 
00317 #endif
00318 
00319 //------------------------------------------------------------------------------
00320 
00335 template<class SampleType>
00336 class SawUnit
00337 {
00338 public:    
00339     typedef SawChannelInternal<SampleType>          SawInternal;
00340     typedef typename SawInternal::Data              Data;
00341     typedef InputDictionary                         Inputs;
00342     typedef ChannelBase<SampleType>                 ChannelType;
00343     typedef ChannelInternal<SampleType,Data>        Internal;
00344     typedef UnitBase<SampleType>                    UnitType;
00345     
00346     typedef typename SawInternal::FrequencyType         FrequencyType;
00347     typedef typename SawInternal::FrequencyUnitType     FrequencyUnitType;
00348     typedef typename SawInternal::FrequencyBufferType   FrequencyBufferType;
00349 
00350     
00351     static inline UnitInfos getInfo() throw()
00352     {
00353         const double blockSize = (double)BlockSize::getDefault().getValue();
00354         const double sampleRate = SampleRate::getDefault().getValue();
00355         const double peak = (double)TypeUtility<SampleType>::getTypePeak(); // will be innaccurate for LongLong
00356         
00357         return UnitInfo ("Saw", "A non-band limited sawtooth wave oscillator.",
00358                          
00359                          // output
00360                          ChannelCount::VariableChannelCount, 
00361                          IOKey::Generic,    Measure::None,      0.0,        IOLimit::Clipped,   Measure::NormalisedBipolar, -peak, peak,
00362                          IOKey::End,
00363                          
00364                          // inputs
00365                          IOKey::Frequency,  Measure::Hertz,     440.0,      IOLimit::Clipped,   Measure::SampleRateRatio,  -0.5, 0.5,
00366                          IOKey::Multiply,   Measure::Factor,    1.0,        IOLimit::None,
00367                          IOKey::Add,        Measure::None,      0.0,        IOLimit::None,
00368                          IOKey::BlockSize,  Measure::Samples,   blockSize,  IOLimit::Minimum,   Measure::Samples,           1.0,
00369                          IOKey::SampleRate, Measure::Hertz,     sampleRate, IOLimit::Minimum,   Measure::Hertz,             0.0,
00370                          IOKey::End);
00371     }
00372     
00374     static UnitType ar (FrequencyUnitType const& frequency = FrequencyType (440), 
00375                         UnitType const& mul = SampleType (1),
00376                         UnitType const& add = SampleType (0),
00377                         BlockSize const& preferredBlockSize = BlockSize::getDefault(),
00378                         SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw()
00379     {                
00380         Inputs inputs;
00381         inputs.put (IOKey::Frequency, frequency);
00382         inputs.put (IOKey::Multiply, mul);
00383         inputs.put (IOKey::Add, add);
00384                 
00385         const LongLong peak = SampleType (TypeUtility<SampleType>::getTypePeak());
00386         
00387         Data data = { { -1.0, -1.0 }, 0, peak, peak * 2 };
00388         
00389         return UnitType::template createFromInputs<SawInternal> (inputs, 
00390                                                                  data, 
00391                                                                  preferredBlockSize, 
00392                                                                  preferredSampleRate);
00393     }
00394     
00396     static UnitType kr (FrequencyUnitType const& frequency, 
00397                         UnitType const& mul = SampleType (1),
00398                         UnitType const& add = SampleType (0)) throw()
00399     {
00400         return ar (frequency, mul, add, 
00401                    BlockSize::getControlRateBlockSize(), 
00402                    SampleRate::getControlRate());
00403     }        
00404 };
00405 
00406 typedef SawUnit<PLONK_TYPE_DEFAULT> Saw;
00407 
00408 
00409 
00410 
00411 #endif // PLONK_SAW_H
00412 
 All Classes Functions Typedefs Enumerations Enumerator Properties