pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_Table.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_TABLE_H
00040 #define PLONK_TABLE_H
00041 
00042 #include "../channel/plonk_ChannelInternalCore.h"
00043 #include "../plonk_GraphForwardDeclarations.h"
00044 
00045 template<class SampleType> class TableChannelInternal;
00046 
00047 PLONK_CHANNELDATA_DECLARE(TableChannelInternal,SampleType)
00048 {    
00049     typedef typename TypeUtility<SampleType>::IndexType FrequencyType;
00050 
00051     ChannelInternalCore::Data base;
00052     FrequencyType currentPosition;
00053 };      
00054 
00055 //------------------------------------------------------------------------------
00056 
00058 template<class SampleType>
00059 class TableChannelInternal 
00060 :   public ChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(TableChannelInternal,SampleType)>
00061 {
00062 public:
00063     typedef PLONK_CHANNELDATA_NAME(TableChannelInternal,SampleType)     Data;
00064     typedef ChannelBase<SampleType>                                     ChannelType;
00065     typedef TableChannelInternal<SampleType>                            TableInternal;
00066     typedef ChannelInternal<SampleType,Data>                            Internal;
00067     typedef ChannelInternalBase<SampleType>                             InternalBase;
00068     typedef UnitBase<SampleType>                                        UnitType;
00069     typedef InputDictionary                                             Inputs;
00070     typedef NumericalArray<SampleType>                                  Buffer;
00071     typedef WavetableBase<SampleType>                                   WavetableType;
00072     
00073     typedef typename TypeUtility<SampleType>::IndexType         FrequencyType;
00074     typedef UnitBase<FrequencyType>                             FrequencyUnitType;
00075     typedef NumericalArray<FrequencyType>                       FrequencyBufferType;
00076     typedef InterpLinear<SampleType,FrequencyType>              InterpType;
00077 
00078 
00079     TableChannelInternal (Inputs const& inputs, 
00080                           Data const& data, 
00081                           BlockSize const& blockSize,
00082                           SampleRate const& sampleRate) throw()
00083     :   Internal (inputs, data, blockSize, sampleRate)
00084     {
00085     }
00086             
00087     Text getName() const throw()
00088     {
00089         return "Table";
00090     }       
00091     
00092     IntArray getInputKeys() const throw()
00093     {
00094         const IntArray keys (IOKey::Wavetable, 
00095                              IOKey::Frequency);
00096         return keys;
00097     }    
00098     
00099     InternalBase* getChannel (const int index) throw()
00100     {
00101         const Inputs channelInputs = this->getInputs().getChannel (index);
00102         return new TableInternal (channelInputs, 
00103                                   this->getState(), 
00104                                   this->getBlockSize(), 
00105                                   this->getSampleRate());
00106     }
00107     
00108     void initChannel (const int channel) throw()
00109     {        
00110         const FrequencyUnitType& frequencyUnit = ChannelInternalCore::getInputAs<FrequencyUnitType> (IOKey::Frequency);
00111         
00112         this->setBlockSize (BlockSize::decide (frequencyUnit.getBlockSize (channel),
00113                                                this->getBlockSize()));
00114         this->setSampleRate (SampleRate::decide (frequencyUnit.getSampleRate (channel),
00115                                                  this->getSampleRate()));
00116         
00117         this->setOverlap (frequencyUnit.getOverlap (channel));
00118         
00119         this->initValue (this->getState().currentPosition);
00120     }    
00121     
00122     void process (ProcessInfo& info, const int channel) throw()
00123     {        
00124         Data& data = this->getState();
00125         const double sampleDuration = data.base.sampleDuration;
00126 
00127         FrequencyUnitType& frequencyUnit = ChannelInternalCore::getInputAs<FrequencyUnitType> (IOKey::Frequency);
00128         const FrequencyBufferType& frequencyBuffer (frequencyUnit.process (info, channel));
00129         
00130         SampleType* const outputSamples = this->getOutputSamples();
00131         const int outputBufferLength = this->getOutputBuffer().length();
00132         
00133         const FrequencyType* const frequencySamples = frequencyBuffer.getArray();
00134         const int frequencyBufferLength = frequencyBuffer.length();
00135         
00136         const WavetableType& table (this->getInputAsWavetable (IOKey::Wavetable));
00137         const SampleType* const tableSamples = table.getArray();
00138         const FrequencyType tableLength = FrequencyType (table.length());
00139         const FrequencyType table0 (0);
00140         const FrequencyType tableLengthOverSampleRate = FrequencyType (tableLength * sampleDuration); 
00141         
00142         FrequencyType currentPosition = data.currentPosition;
00143         int i;
00144         
00145         if (frequencyBufferLength == outputBufferLength)
00146         {
00147             for (i = 0; i < outputBufferLength; ++i) 
00148             {
00149                 outputSamples[i] = InterpType::lookup (tableSamples, currentPosition);
00150                 currentPosition += frequencySamples[i] * tableLengthOverSampleRate;
00151                 
00152                 if (currentPosition >= tableLength)
00153                     currentPosition -= tableLength;
00154                 else if (currentPosition < table0)      
00155                     currentPosition += tableLength;                
00156             }                    
00157         }
00158         else if (frequencyBufferLength == 1)
00159         {
00160             const FrequencyType valueIncrement (frequencySamples[0] * tableLengthOverSampleRate);
00161             
00162             if (valueIncrement > table0)
00163             {
00164                 for (i = 0; i < outputBufferLength; ++i) 
00165                 {
00166                     outputSamples[i] = InterpType::lookup (tableSamples, currentPosition);
00167                     currentPosition += valueIncrement;
00168                     
00169                     if (currentPosition >= tableLength)
00170                         currentPosition -= tableLength;
00171                 }            
00172             }
00173             else
00174             {
00175                 for (i = 0; i < outputBufferLength; ++i) 
00176                 {
00177                     outputSamples[i] = InterpType::lookup (tableSamples, currentPosition);
00178                     currentPosition += valueIncrement;
00179                     
00180                     if (currentPosition < table0)       
00181                         currentPosition += tableLength;                
00182                 }            
00183             }
00184         }
00185         else
00186         {
00187             double frequencyPosition = 0.0;
00188             const double frequencyIncrement = double (frequencyBufferLength) / double (outputBufferLength);
00189             
00190             for (i = 0; i < outputBufferLength; ++i) 
00191             {
00192                 outputSamples[i] = InterpType::lookup (tableSamples, currentPosition);
00193                 currentPosition += frequencySamples[int (frequencyPosition)] * tableLengthOverSampleRate;
00194                 
00195                 if (currentPosition >= tableLength)
00196                     currentPosition -= tableLength;
00197                 else if (currentPosition < table0)      
00198                     currentPosition += tableLength;                
00199                 
00200                 frequencyPosition += frequencyIncrement;
00201             }        
00202         }
00203         
00204         data.currentPosition = currentPosition;
00205     }
00206 };
00207 
00208 //------------------------------------------------------------------------------
00209 
00210 #ifdef PLONK_USEPLINK
00211 
00212 template<>
00213 class TableChannelInternal<float> :   public ChannelInternal<float, TableProcessStateF>
00214 {
00215 public:
00216     typedef TableProcessStateF              Data;
00217     typedef ChannelBase<float>              ChannelType;
00218     typedef TableChannelInternal<float>     TableInternal;
00219     typedef ChannelInternal<float,Data>     Internal;
00220     typedef ChannelInternalBase<float>      InternalBase;
00221     typedef UnitBase<float>                 UnitType;
00222     typedef InputDictionary                 Inputs;
00223     typedef NumericalArray<float>           Buffer;
00224     typedef WavetableBase<float>            WavetableType;
00225     
00226     typedef float                           FrequencyType;
00227     typedef UnitBase<float>                 FrequencyUnitType;
00228     typedef NumericalArray<float>           FrequencyBufferType;
00229     
00230     enum Outputs { Output, NumOutputs };
00231     enum InputIndices  { Frequency, NumInputs };
00232     enum Buffers { OutputBuffer, FrequencyBuffer, TableBuffer, NumBuffers };
00233     
00234     typedef PlinkProcess<NumBuffers>        Process;
00235     
00236     TableChannelInternal (Inputs const& inputs, 
00237                           Data const& data, 
00238                           BlockSize const& blockSize,
00239                           SampleRate const& sampleRate) throw()
00240     :   Internal (inputs, data, blockSize, sampleRate)
00241     {
00242         plonk_staticassert (NumBuffers == (NumInputs + NumOutputs + 1));
00243         plonk_assert (Bits::isPowerOf2 (this->getInputAsWavetable (IOKey::Wavetable).length())); // wavetable must be a power of 2 length for Plink
00244         
00245         Process::init (&p, this, NumOutputs, NumInputs);
00246     }
00247     
00248     Text getName() const throw()
00249     {
00250         return "Table";
00251     }       
00252     
00253     IntArray getInputKeys() const throw()
00254     {
00255         const IntArray keys (IOKey::Wavetable, 
00256                              IOKey::Frequency);
00257         return keys;
00258     }    
00259     
00260     InternalBase* getChannel (const int index) throw()
00261     {
00262         const Inputs channelInputs = this->getInputs().getChannel (index);
00263         return new TableInternal (channelInputs, 
00264                                   this->getState(), 
00265                                   this->getBlockSize(), 
00266                                   this->getSampleRate());
00267     }
00268     
00269     void initChannel (const int channel) throw()
00270     {        
00271         const FrequencyUnitType& frequencyUnit = ChannelInternalCore::getInputAs<FrequencyUnitType> (IOKey::Frequency);
00272         
00273         this->setBlockSize (BlockSize::decide (frequencyUnit.getBlockSize (channel),
00274                                                this->getBlockSize()));
00275         this->setSampleRate (SampleRate::decide (frequencyUnit.getSampleRate (channel),
00276                                                  this->getSampleRate()));
00277         
00278         this->setOverlap (frequencyUnit.getOverlap (channel));
00279         
00280         this->initValue (this->getState().currentPosition);
00281     }    
00282     
00283     void process (ProcessInfo& info, const int channel) throw()
00284     {                
00285         FrequencyUnitType& frequencyUnit = ChannelInternalCore::getInputAs<FrequencyUnitType> (IOKey::Frequency);
00286         const FrequencyBufferType& frequencyBuffer (frequencyUnit.process (info, channel));
00287         const WavetableType& table (this->getInputAsWavetable (IOKey::Wavetable));
00288 
00289         p.buffers[0].bufferSize = this->getOutputBuffer().length();
00290         p.buffers[0].buffer     = this->getOutputSamples();
00291         p.buffers[1].bufferSize = frequencyBuffer.length();
00292         p.buffers[1].buffer     = frequencyBuffer.getArray();
00293         p.buffers[2].bufferSize = table.length();
00294         p.buffers[2].buffer     = table.getArray();
00295         
00296         plink_TableProcessF (&p, &this->getState());
00297     }
00298     
00299 private:
00300     Process p;
00301 };    
00302 
00303 #endif // PLONK_USEPLINK
00304 
00305 //------------------------------------------------------------------------------
00306 
00307 
00324 template<class SampleType>
00325 class TableUnit
00326 {
00327 public:    
00328     typedef TableChannelInternal<SampleType>        TableInternal;
00329     typedef typename TableInternal::Data            Data;
00330     typedef ChannelBase<SampleType>                 ChannelType;
00331     typedef ChannelInternal<SampleType,Data>        Internal;
00332     typedef UnitBase<SampleType>                    UnitType;
00333     typedef InputDictionary                         Inputs;
00334     typedef WavetableBase<SampleType>               WavetableType;
00335     
00336     typedef typename TableInternal::FrequencyType         FrequencyType;
00337     typedef typename TableInternal::FrequencyUnitType     FrequencyUnitType;
00338     typedef typename TableInternal::FrequencyBufferType   FrequencyBufferType;
00339     
00340     static inline UnitInfos getInfo() throw()
00341     {
00342         const double blockSize = (double)BlockSize::getDefault().getValue();
00343         const double sampleRate = SampleRate::getDefault().getValue();
00344         
00345         return UnitInfo ("Table", "A wavetable oscillator.",
00346                          
00347                          // output
00348                          ChannelCount::VariableChannelCount, 
00349                          IOKey::Generic,    Measure::None,      0.0,        IOLimit::None,
00350                          IOKey::End,
00351                          
00352                          // inputs
00353                          IOKey::Wavetable,  Measure::None,
00354                          IOKey::Frequency,  Measure::Hertz,     440.0,      IOLimit::Clipped,   Measure::SampleRateRatio,   0.0, 0.5,
00355                          IOKey::Multiply,   Measure::Factor,    1.0,        IOLimit::None,
00356                          IOKey::Add,        Measure::None,      0.0,        IOLimit::None,
00357                          IOKey::BlockSize,  Measure::Samples,   blockSize,  IOLimit::Minimum,   Measure::Samples,           1.0,
00358                          IOKey::SampleRate, Measure::Hertz,     sampleRate, IOLimit::Minimum,   Measure::Hertz,             0.0,
00359                          IOKey::End);
00360     }
00361     
00363     static UnitType ar (WavetableType const& table, 
00364                         FrequencyUnitType const& frequency = FrequencyType (440), 
00365                         UnitType const& mul = SampleType (1),
00366                         UnitType const& add = SampleType (0),
00367                         BlockSize const& preferredBlockSize = BlockSize::getDefault(),
00368                         SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw()
00369     {             
00370         Inputs inputs;
00371         inputs.put (IOKey::Wavetable, table);
00372         inputs.put (IOKey::Frequency, frequency);
00373         inputs.put (IOKey::Multiply, mul);
00374         inputs.put (IOKey::Add, add);
00375                         
00376         Data data;
00377         Memory::zero (data);
00378         data.base.sampleRate = -1.0;
00379         data.base.sampleDuration = -1.0;
00380         
00381         return UnitType::template createFromInputs<TableInternal> (inputs, 
00382                                                                    data, 
00383                                                                    preferredBlockSize, 
00384                                                                    preferredSampleRate);
00385     }
00386     
00388     static UnitType kr (WavetableType const& table,
00389                         FrequencyUnitType const& frequency, 
00390                         UnitType const& mul = SampleType (1),
00391                         UnitType const& add = SampleType (0)) throw()
00392     {
00393         return ar (table, frequency, mul, add, 
00394                    BlockSize::getControlRateBlockSize(), 
00395                    SampleRate::getControlRate());
00396     }        
00397 };
00398 
00399 typedef TableUnit<PLONK_TYPE_DEFAULT> Table;
00400 
00401 //------------------------------------------------------------------------------
00402 
00418 template<class SampleType>
00419 class SineUnit
00420 {
00421 public:    
00422     typedef TableChannelInternal<SampleType>        TableInternal;
00423     typedef typename TableInternal::Data            Data;
00424     typedef ChannelBase<SampleType>                 ChannelType;
00425     typedef ChannelInternal<SampleType,Data>        Internal;
00426     typedef UnitBase<SampleType>                    UnitType;
00427     typedef InputDictionary                         Inputs;
00428     typedef WavetableBase<SampleType>               WavetableType;
00429     typedef TableUnit<SampleType>                   TableType;
00430     
00431     typedef typename TableInternal::FrequencyType         FrequencyType;
00432     typedef typename TableInternal::FrequencyUnitType     FrequencyUnitType;
00433     typedef typename TableInternal::FrequencyBufferType   FrequencyBufferType;
00434 
00435     static inline UnitInfos getInfo() throw()
00436     {
00437         const double blockSize = (double)BlockSize::getDefault().getValue();
00438         const double sampleRate = SampleRate::getDefault().getValue();
00439         
00440         return UnitInfo ("Sine", "A wavetable-based sine oscillator.",
00441                          
00442                          // output
00443                          ChannelCount::VariableChannelCount, 
00444                          IOKey::Generic,    Measure::None,      0.0,        IOLimit::None,
00445                          IOKey::End,
00446                          
00447                          // inputs
00448                          IOKey::Frequency,  Measure::Hertz,     440.0,      IOLimit::Clipped,   Measure::SampleRateRatio,  -0.5, 0.5,
00449                          IOKey::Multiply,   Measure::Factor,    1.0,        IOLimit::None,
00450                          IOKey::Add,        Measure::None,      0.0,        IOLimit::None,
00451                          IOKey::BlockSize,  Measure::Samples,   blockSize,  IOLimit::Minimum,   Measure::Samples,           1.0,
00452                          IOKey::SampleRate, Measure::Hertz,     sampleRate, IOLimit::Minimum,   Measure::Hertz,             0.0,
00453                          IOKey::End);
00454     }
00455     
00457     static UnitType ar (FrequencyUnitType const& frequency = FrequencyType (440), 
00458                         UnitType const& mul = SampleType (1),
00459                         UnitType const& add = SampleType (0),
00460                         BlockSize const& preferredBlockSize = BlockSize::getDefault(),
00461                         SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw()
00462     {     
00463         return TableType::ar (WavetableType::sine8192(), frequency, mul, add, preferredBlockSize, preferredSampleRate);
00464     }
00465     
00467     static UnitType kr (FrequencyUnitType const& frequency, 
00468                         UnitType const& mul = SampleType (1),
00469                         UnitType const& add = SampleType (0)) throw()
00470     {
00471         return TableType::kr (WavetableType::sine8192(), frequency, mul, add);
00472     }        
00473 };
00474 
00475 typedef SineUnit<PLONK_TYPE_DEFAULT> Sine;
00476 
00493 template<class SampleType>
00494 class HarmonicSawUnit
00495 {
00496 public:    
00497     typedef TableChannelInternal<SampleType>        TableInternal;
00498     typedef typename TableInternal::Data            Data;
00499     typedef ChannelBase<SampleType>                 ChannelType;
00500     typedef ChannelInternal<SampleType,Data>        Internal;
00501     typedef UnitBase<SampleType>                    UnitType;
00502     typedef InputDictionary                         Inputs;
00503     typedef WavetableBase<SampleType>               WavetableType;
00504     typedef TableUnit<SampleType>                   TableType;
00505     typedef NumericalArray<SampleType>              WeightsType;
00506     
00507     typedef typename TableInternal::FrequencyType         FrequencyType;
00508     typedef typename TableInternal::FrequencyUnitType     FrequencyUnitType;
00509     typedef typename TableInternal::FrequencyBufferType   FrequencyBufferType;
00510 
00511     static inline UnitInfos getInfo() throw()
00512     {
00513         const double blockSize = (double)BlockSize::getDefault().getValue();
00514         const double sampleRate = SampleRate::getDefault().getValue();
00515         
00516         return UnitInfo ("HarmonicSaw", "A wavetable-based sawtooth oscillator.",
00517                          
00518                          // output
00519                          ChannelCount::VariableChannelCount, 
00520                          IOKey::Generic,        Measure::None,      0.0,        IOLimit::None,
00521                          IOKey::End,
00522                          
00523                          // inputs
00524                          IOKey::Frequency,      Measure::Hertz,     440.0,      IOLimit::Clipped,   Measure::SampleRateRatio,   0.0, 0.5,
00525                          IOKey::Multiply,       Measure::Factor,    1.0,        IOLimit::None,
00526                          IOKey::Add,            Measure::None,      0.0,        IOLimit::None,
00527                          IOKey::HarmonicCount,  Measure::Count,     21,         IOLimit::Minimum,   Measure::Count,             1,
00528                          IOKey::BlockSize,      Measure::Samples,   blockSize,  IOLimit::Minimum,   Measure::Samples,           1.0,
00529                          IOKey::SampleRate,     Measure::Hertz,     sampleRate, IOLimit::Minimum,   Measure::Hertz,             0.0,
00530                          IOKey::End);
00531     }
00532     
00534     static UnitType ar (FrequencyUnitType const& frequency = FrequencyType (440), 
00535                         UnitType const& mul = SampleType (1),
00536                         UnitType const& add = SampleType (0),
00537                         const int numHarmonics = 21,
00538                         BlockSize const& preferredBlockSize = BlockSize::getDefault(),
00539                         SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw()
00540     {          
00541         const WavetableType table = (numHarmonics == 21) ? WavetableType::harmonicSaw() : WavetableType::harmonicSaw (8192, numHarmonics);
00542         return TableType::ar (table, frequency, mul, add, preferredBlockSize, preferredSampleRate);
00543     }
00544     
00546     static UnitType kr (FrequencyUnitType const& frequency, 
00547                         UnitType const& mul = SampleType (1),
00548                         UnitType const& add = SampleType (0),
00549                         const int numHarmonics = 21) throw()
00550     {
00551         const WavetableType table = (numHarmonics == 21) ? WavetableType::harmonicSaw() : WavetableType::harmonicSaw (8192, numHarmonics);
00552         return TableType::kr (table, frequency, mul, add);
00553     }        
00554 };
00555 
00556 typedef HarmonicSawUnit<PLONK_TYPE_DEFAULT> HarmonicSaw;
00557 
00558 
00575 template<class SampleType>
00576 class HarmonicSquareUnit
00577 {
00578 public:    
00579     typedef TableChannelInternal<SampleType>        TableInternal;
00580     typedef typename TableInternal::Data            Data;
00581     typedef ChannelBase<SampleType>                 ChannelType;
00582     typedef ChannelInternal<SampleType,Data>        Internal;
00583     typedef UnitBase<SampleType>                    UnitType;
00584     typedef InputDictionary                         Inputs;
00585     typedef WavetableBase<SampleType>               WavetableType;
00586     typedef TableUnit<SampleType>                   TableType;
00587     typedef NumericalArray<SampleType>              WeightsType;
00588     
00589     typedef typename TableInternal::FrequencyType         FrequencyType;
00590     typedef typename TableInternal::FrequencyUnitType     FrequencyUnitType;
00591     typedef typename TableInternal::FrequencyBufferType   FrequencyBufferType;
00592 
00593     static inline UnitInfos getInfo() throw()
00594     {
00595         const double blockSize = (double)BlockSize::getDefault().getValue();
00596         const double sampleRate = SampleRate::getDefault().getValue();
00597         
00598         return UnitInfo ("HarmonicSquare", "A wavetable-based square wave oscillator.",
00599                          
00600                          // output
00601                          ChannelCount::VariableChannelCount, 
00602                          IOKey::Generic,        Measure::None,      0.0,        IOLimit::None,
00603                          IOKey::End,
00604                          
00605                          // inputs
00606                          IOKey::Frequency,      Measure::Hertz,     440.0,      IOLimit::Clipped,   Measure::SampleRateRatio,   0.0, 0.5,
00607                          IOKey::Multiply,       Measure::Factor,    1.0,        IOLimit::None,
00608                          IOKey::Add,            Measure::None,      0.0,        IOLimit::None,
00609                          IOKey::HarmonicCount,  Measure::Count,     21,         IOLimit::Minimum,   Measure::Count,             1,
00610                          IOKey::BlockSize,      Measure::Samples,   blockSize,  IOLimit::Minimum,   Measure::Samples,           1.0,
00611                          IOKey::SampleRate,     Measure::Hertz,     sampleRate, IOLimit::Minimum,   Measure::Hertz,             0.0,
00612                          IOKey::End);
00613     }
00614     
00616     static UnitType ar (FrequencyUnitType const& frequency = FrequencyType (440), 
00617                         UnitType const& mul = SampleType (1),
00618                         UnitType const& add = SampleType (0),
00619                         const int numHarmonics = 21,
00620                         BlockSize const& preferredBlockSize = BlockSize::getDefault(),
00621                         SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw()
00622     {            
00623         const WavetableType table = (numHarmonics == 21) ? WavetableType::harmonicSquare() : WavetableType::harmonicSquare (8192, numHarmonics);
00624         return TableType::ar (table, frequency, mul, add, preferredBlockSize, preferredSampleRate);
00625     }
00626     
00628     static UnitType kr (FrequencyUnitType const& frequency, 
00629                         UnitType const& mul = SampleType (1),
00630                         UnitType const& add = SampleType (0),
00631                         const int numHarmonics = 21) throw()
00632     {
00633         const WavetableType table = (numHarmonics == 21) ? WavetableType::harmonicSquare() : WavetableType::harmonicSquare (8192, numHarmonics);
00634         return TableType::kr (table, frequency, mul, add);
00635     }        
00636 };
00637 
00638 typedef HarmonicSquareUnit<PLONK_TYPE_DEFAULT> HarmonicSquare;
00639 
00656 template<class SampleType>
00657 class HarmonicTriUnit
00658 {
00659 public:
00660     typedef TableChannelInternal<SampleType>        TableInternal;
00661     typedef typename TableInternal::Data            Data;
00662     typedef ChannelBase<SampleType>                 ChannelType;
00663     typedef ChannelInternal<SampleType,Data>        Internal;
00664     typedef UnitBase<SampleType>                    UnitType;
00665     typedef InputDictionary                         Inputs;
00666     typedef WavetableBase<SampleType>               WavetableType;
00667     typedef TableUnit<SampleType>                   TableType;
00668     typedef NumericalArray<SampleType>              WeightsType;
00669     
00670     typedef typename TableInternal::FrequencyType         FrequencyType;
00671     typedef typename TableInternal::FrequencyUnitType     FrequencyUnitType;
00672     typedef typename TableInternal::FrequencyBufferType   FrequencyBufferType;
00673     
00674     static inline UnitInfos getInfo() throw()
00675     {
00676         const double blockSize = (double)BlockSize::getDefault().getValue();
00677         const double sampleRate = SampleRate::getDefault().getValue();
00678         
00679         return UnitInfo ("HarmonicTri", "A wavetable-based triangle wave oscillator.",
00680                          
00681                          // output
00682                          ChannelCount::VariableChannelCount,
00683                          IOKey::Generic,        Measure::None,      0.0,        IOLimit::None,
00684                          IOKey::End,
00685                          
00686                          // inputs
00687                          IOKey::Frequency,      Measure::Hertz,     440.0,      IOLimit::Clipped,   Measure::SampleRateRatio,   0.0, 0.5,
00688                          IOKey::Multiply,       Measure::Factor,    1.0,        IOLimit::None,
00689                          IOKey::Add,            Measure::None,      0.0,        IOLimit::None,
00690                          IOKey::HarmonicCount,  Measure::Count,     21,         IOLimit::Minimum,   Measure::Count,             1,
00691                          IOKey::BlockSize,      Measure::Samples,   blockSize,  IOLimit::Minimum,   Measure::Samples,           1.0,
00692                          IOKey::SampleRate,     Measure::Hertz,     sampleRate, IOLimit::Minimum,   Measure::Hertz,             0.0,
00693                          IOKey::End);
00694     }
00695     
00697     static UnitType ar (FrequencyUnitType const& frequency = FrequencyType (440),
00698                         UnitType const& mul = SampleType (1),
00699                         UnitType const& add = SampleType (0),
00700                         const int numHarmonics = 21,
00701                         BlockSize const& preferredBlockSize = BlockSize::getDefault(),
00702                         SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw()
00703     {
00704         const WavetableType table = (numHarmonics == 21) ? WavetableType::harmonicTri() : WavetableType::harmonicTri (8192, numHarmonics);
00705         return TableType::ar (table, frequency, mul, add, preferredBlockSize, preferredSampleRate);
00706     }
00707     
00709     static UnitType kr (FrequencyUnitType const& frequency,
00710                         UnitType const& mul = SampleType (1),
00711                         UnitType const& add = SampleType (0),
00712                         const int numHarmonics = 21) throw()
00713     {
00714         const WavetableType table = (numHarmonics == 21) ? WavetableType::harmonicTri() : WavetableType::harmonicTri (8192, numHarmonics);
00715         return TableType::kr (table, frequency, mul, add);
00716     }        
00717 };
00718 
00719 typedef HarmonicTriUnit<PLONK_TYPE_DEFAULT> HarmonicTri;
00720 
00721 #endif // PLONK_TABLE_H
00722 
 All Classes Functions Typedefs Enumerations Enumerator Properties