![]() |
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_SIGNALPLAY_H 00040 #define PLONK_SIGNALPLAY_H 00041 00042 #include "../channel/plonk_ChannelInternalCore.h" 00043 #include "../plonk_GraphForwardDeclarations.h" 00044 00045 template<class SampleType> class SignalPlayChannelInternal; 00046 00047 PLONK_CHANNELDATA_DECLARE(SignalPlayChannelInternal,SampleType) 00048 { 00049 typedef typename TypeUtility<SampleType>::IndexType RateType; 00050 00051 ChannelInternalCore::Data base; 00052 RateType currentPosition; 00053 00054 bool done:1; 00055 bool deleteWhenDone:1; 00056 }; 00057 00058 //------------------------------------------------------------------------------ 00059 00061 template<class SampleType> 00062 class SignalPlayChannelInternal 00063 : public ChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(SignalPlayChannelInternal,SampleType)> 00064 { 00065 public: 00066 00067 typedef PLONK_CHANNELDATA_NAME(SignalPlayChannelInternal,SampleType) Data; 00068 typedef ChannelBase<SampleType> ChannelType; 00069 typedef SignalPlayChannelInternal<SampleType> SignalPlayInternal; 00070 typedef ChannelInternal<SampleType,Data> Internal; 00071 typedef ChannelInternalBase<SampleType> InternalBase; 00072 typedef UnitBase<SampleType> UnitType; 00073 typedef InputDictionary Inputs; 00074 typedef NumericalArray<SampleType> Buffer; 00075 typedef SignalBase<SampleType> SignalType; 00076 00077 typedef typename TypeUtility<SampleType>::IndexType RateType; 00078 typedef UnitBase<RateType> RateUnitType; 00079 typedef NumericalArray<RateType> RateBufferType; 00080 typedef InterpLinear<SampleType,RateType> InterpType; 00081 00082 SignalPlayChannelInternal (Inputs const& inputs, 00083 Data const& data, 00084 BlockSize const& blockSize, 00085 SampleRate const& sampleRate) throw() 00086 : Internal (inputs, data, blockSize, sampleRate) 00087 { 00088 } 00089 00090 Text getName() const throw() 00091 { 00092 return "Signal Play"; 00093 } 00094 00095 IntArray getInputKeys() const throw() 00096 { 00097 const IntArray keys (IOKey::Signal, 00098 IOKey::Rate); 00099 return keys; 00100 } 00101 00102 InternalBase* getChannel (const int index) throw() 00103 { 00104 const Inputs channelInputs = this->getInputs().getChannel (index); 00105 return new SignalPlayInternal (channelInputs, 00106 this->getState(), 00107 this->getBlockSize(), 00108 this->getSampleRate()); 00109 } 00110 00111 void initChannel (const int channel) throw() 00112 { 00113 const RateUnitType& rateUnit = ChannelInternalCore::getInputAs<RateUnitType> (IOKey::Rate); 00114 00115 this->setBlockSize (BlockSize::decide (rateUnit.getBlockSize (channel), 00116 this->getBlockSize())); 00117 this->setSampleRate (SampleRate::decide (rateUnit.getSampleRate (channel), 00118 this->getSampleRate())); 00119 00120 this->setOverlap (rateUnit.getOverlap (channel)); 00121 00122 this->initValue (0);//this->getState().currentPosition); 00123 } 00124 00125 inline bool checkPosition (ProcessInfo& info, Data& data, const int numSignalFrames, const bool loop) throw() 00126 { 00127 if (data.currentPosition >= numSignalFrames) 00128 { 00129 if (loop) 00130 { 00131 data.currentPosition -= numSignalFrames; 00132 this->update (Text::getMessageLooped(), Dynamic::getNull()); 00133 } 00134 else 00135 { 00136 data.done = true; 00137 this->update (Text::getMessageDone(), Dynamic::getNull()); 00138 } 00139 } 00140 else if (data.currentPosition < RateType (0)) 00141 { 00142 if (loop) 00143 { 00144 data.currentPosition += numSignalFrames; 00145 this->update (Text::getMessageLooped(), Dynamic::getNull()); 00146 } 00147 else 00148 { 00149 data.done = true; 00150 this->update (Text::getMessageDone(), Dynamic::getNull()); 00151 } 00152 } 00153 00154 return data.done; 00155 } 00156 00157 void process (ProcessInfo& info, const int channel) throw() 00158 { 00159 Data& data = this->getState(); 00160 00161 RateUnitType& rateUnit = ChannelInternalCore::getInputAs<RateUnitType> (IOKey::Rate); 00162 const RateBufferType& rateBuffer (rateUnit.process (info, channel)); 00163 00164 SampleType* outputSamples = this->getOutputSamples(); 00165 const int outputBufferLength = this->getOutputBuffer().length(); 00166 00167 const RateType* rateSamples = rateBuffer.getArray(); 00168 const int rateBufferLength = rateBuffer.length(); 00169 00170 UnitType& loop (this->getInputAsUnit (IOKey::Loop)); 00171 const Buffer& loopBuffer (loop.process (info, channel)); 00172 const SampleType* const loopSamples = loopBuffer.getArray(); 00173 const bool loopFlag = loopSamples[0] >= SampleType (0.5); 00174 00175 const SignalType& signal (this->getInputAsSignal (IOKey::Signal)); 00176 const SampleType* const signalSamples = signal.getSamples (channel); 00177 const unsigned int signalFrameStride = signal.getFrameStride(); 00178 const unsigned int numSignalFrames (signal.getNumFrames()); 00179 const RateType rateScale (signal.getSampleRate().getValue() * data.base.sampleDuration); 00180 00181 int numSamplesRemaining = outputBufferLength; 00182 00183 if (rateBufferLength == outputBufferLength) 00184 { 00185 while (numSamplesRemaining--) 00186 { 00187 const unsigned int sampleA (data.currentPosition); 00188 const unsigned int sampleB (sampleA + 1); 00189 const RateType frac (plonk::frac (data.currentPosition)); 00190 00191 *outputSamples++ = InterpType::interp (signalSamples[(sampleA % numSignalFrames) * signalFrameStride], 00192 signalSamples[(sampleB % numSignalFrames) * signalFrameStride], 00193 frac); 00194 00195 data.currentPosition += *rateSamples++ * rateScale; 00196 00197 if (checkPosition (info, data, numSignalFrames, loopFlag)) 00198 break; 00199 } 00200 } 00201 else if (rateBufferLength == 1) 00202 { 00203 const RateType increment = rateSamples[0] * rateScale; 00204 00205 while (numSamplesRemaining--) 00206 { 00207 const unsigned int sampleA (data.currentPosition); 00208 const unsigned int sampleB (sampleA + 1); 00209 const RateType frac (plonk::frac (data.currentPosition)); 00210 00211 *outputSamples++ = InterpType::interp (signalSamples[(sampleA % numSignalFrames) * signalFrameStride], 00212 signalSamples[(sampleB % numSignalFrames) * signalFrameStride], 00213 frac); 00214 data.currentPosition += increment; 00215 00216 if (checkPosition (info, data, numSignalFrames, loopFlag)) 00217 break; 00218 } 00219 } 00220 else 00221 { 00222 double ratePosition = 0.0; 00223 const double rateIncrement = double (rateBufferLength) / double (outputBufferLength); 00224 00225 while (numSamplesRemaining--) 00226 { 00227 const unsigned int sampleA (data.currentPosition); 00228 const unsigned int sampleB (sampleA + 1); 00229 const RateType frac (plonk::frac (data.currentPosition)); 00230 00231 *outputSamples++ = InterpType::interp (signalSamples[(sampleA % numSignalFrames) * signalFrameStride], 00232 signalSamples[(sampleB % numSignalFrames) * signalFrameStride], 00233 frac); 00234 00235 data.currentPosition += rateSamples[int (ratePosition)] * rateScale; 00236 00237 if (checkPosition (info, data, numSignalFrames, loopFlag)) 00238 break; 00239 00240 ratePosition += rateIncrement; 00241 } 00242 } 00243 00244 if (numSamplesRemaining > 0) 00245 { 00246 while (numSamplesRemaining--) 00247 *outputSamples++ = SampleType (0); 00248 } 00249 00250 if (data.done && data.deleteWhenDone) 00251 info.setShouldDelete(); 00252 } 00253 00254 private: 00255 }; 00256 00257 //------------------------------------------------------------------------------ 00258 00278 template<class SampleType> 00279 class SignalPlayUnit 00280 { 00281 public: 00282 typedef SignalPlayChannelInternal<SampleType> SignalPlayInternal; 00283 typedef typename SignalPlayInternal::Data Data; 00284 typedef ChannelBase<SampleType> ChannelType; 00285 typedef ChannelInternal<SampleType,Data> Internal; 00286 typedef UnitBase<SampleType> UnitType; 00287 typedef InputDictionary Inputs; 00288 typedef SignalBase<SampleType> SignalType; 00289 00290 typedef typename SignalPlayInternal::RateType RateType; 00291 typedef typename SignalPlayInternal::RateUnitType RateUnitType; 00292 typedef typename SignalPlayInternal::RateBufferType RateBufferType; 00293 00294 static inline UnitInfos getInfo() throw() 00295 { 00296 const double blockSize = (double)BlockSize::getDefault().getValue(); 00297 const double sampleRate = SampleRate::getDefault().getValue(); 00298 00299 return UnitInfo ("SignalPlay", "A signal player generator.", 00300 00301 // output 00302 ChannelCount::VariableChannelCount, 00303 IOKey::Generic, Measure::None, 0.0, IOLimit::None, 00304 IOKey::End, 00305 00306 // inputs 00307 IOKey::Signal, Measure::None, 00308 IOKey::Rate, Measure::Factor, 1.0, IOLimit::None, 00309 IOKey::Loop, Measure::Bool, 1.0, IOLimit::Clipped, Measure::NormalisedUnipolar, 0.0, 1.0, 00310 IOKey::Multiply, Measure::Factor, 1.0, IOLimit::None, 00311 IOKey::Add, Measure::None, 0.0, IOLimit::None, 00312 IOKey::AutoDeleteFlag, Measure::Bool, IOInfo::True, IOLimit::None, 00313 IOKey::BlockSize, Measure::Samples, blockSize, IOLimit::Minimum, Measure::Samples, 1.0, 00314 IOKey::SampleRate, Measure::Hertz, sampleRate, IOLimit::Minimum, Measure::Hertz, 0.0, 00315 IOKey::End); 00316 } 00317 00319 static UnitType ar (SignalType const& signal, 00320 RateUnitType const& rate = RateType (1), 00321 UnitType const& loop = SampleType (1), 00322 UnitType const& mul = SampleType (1), 00323 UnitType const& add = SampleType (0), 00324 const bool deleteWhenDone = true, 00325 BlockSize const& preferredBlockSize = BlockSize::getDefault(), 00326 SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw() 00327 { 00328 Inputs inputs; 00329 inputs.put (IOKey::Signal, signal); 00330 inputs.put (IOKey::Rate, rate); 00331 inputs.put (IOKey::Loop, loop); 00332 inputs.put (IOKey::Multiply, mul); 00333 inputs.put (IOKey::Add, add); 00334 00335 Data data = { { -1.0, -1.0 }, RateType (0), false, deleteWhenDone }; 00336 00337 return UnitType::template createFromInputs<SignalPlayInternal> (inputs, 00338 data, 00339 preferredBlockSize, 00340 preferredSampleRate); 00341 } 00342 00344 static UnitType kr (SignalType const& signal, 00345 RateUnitType const& rate, 00346 UnitType const& loop = SampleType (1), 00347 UnitType const& mul = SampleType (1), 00348 UnitType const& add = SampleType (0), 00349 const bool deleteWhenDone = true) throw() 00350 { 00351 return ar (signal, rate, loop, mul, add, deleteWhenDone, 00352 BlockSize::getControlRateBlockSize(), 00353 SampleRate::getControlRate()); 00354 } 00355 }; 00356 00357 typedef SignalPlayUnit<PLONK_TYPE_DEFAULT> SignalPlay; 00358 00359 00360 #endif // PLONK_SIGNALPLAY_H 00361