![]() |
pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
|
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