![]() |
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_PATCHCHANNEL_H 00040 #define PLONK_PATCHCHANNEL_H 00041 00042 #include "../channel/plonk_ChannelInternalCore.h" 00043 #include "../plonk_GraphForwardDeclarations.h" 00044 #include "plonk_Mixers.h" 00045 00046 template<class SampleType> class PatchChannelInternal; 00047 00048 PLONK_CHANNELDATA_DECLARE(PatchChannelInternal,SampleType) 00049 { 00050 ChannelInternalCore::Data base; 00051 int preferredNumChannels; 00052 SampleType fadeIncrement; 00053 SampleType fadeLevel; 00054 bool allowAutoDelete:1; 00055 }; 00056 00057 00060 template<class SampleType> 00061 class PatchChannelInternal 00062 : public ProxyOwnerChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(PatchChannelInternal,SampleType)> 00063 { 00064 public: 00065 typedef PLONK_CHANNELDATA_NAME(PatchChannelInternal,SampleType) Data; 00066 typedef ChannelBase<SampleType> ChannelType; 00067 typedef ObjectArray<ChannelType> ChannelArrayType; 00068 typedef PatchChannelInternal<SampleType> PatchChannelInternalType; 00069 typedef ProxyOwnerChannelInternal<SampleType,Data> Internal; 00070 typedef UnitBase<SampleType> UnitType; 00071 typedef InputDictionary Inputs; 00072 typedef NumericalArray<SampleType> Buffer; 00073 typedef Variable<UnitType&> UnitVariableType; 00074 00075 typedef typename TypeUtility<SampleType>::IndexType DurationType; 00076 typedef UnitBase<DurationType> DurationUnitType; 00077 typedef NumericalArray<DurationType> DurationBufferType; 00078 00079 00080 PatchChannelInternal (Inputs const& inputs, 00081 Data const& data, 00082 BlockSize const& blockSize, 00083 SampleRate const& sampleRate, 00084 ChannelArrayType& channels) throw() 00085 : Internal (data.preferredNumChannels > 0 ? data.preferredNumChannels : numChannelsInSource (inputs), 00086 inputs, data, blockSize, sampleRate, channels) 00087 { 00088 } 00089 00090 Text getName() const throw() 00091 { 00092 return "Patch"; 00093 } 00094 00095 IntArray getInputKeys() const throw() 00096 { 00097 const IntArray keys (IOKey::UnitVariable); 00098 return keys; 00099 } 00100 00101 void initChannel (const int channel) throw() 00102 { 00103 if ((channel % this->getNumChannels()) == 0) 00104 { 00105 UnitVariableType& var = ChannelInternalCore::getInputAs<UnitVariableType> (IOKey::UnitVariable); 00106 00107 if (var.isValueNotNull()) 00108 var.swapValues (currentSource); 00109 } 00110 00111 this->initProxyValue (channel, currentSource.getValue (channel)); 00112 } 00113 00114 void process (ProcessInfo& info, const int /*channel*/) throw() 00115 { 00116 Data& data = this->getState(); 00117 updateSources (info); 00118 00119 if (data.fadeLevel > Math<SampleType>::get0()) 00120 processFade (info); 00121 else 00122 processCopy (info); 00123 } 00124 00125 void processFade (ProcessInfo& info) 00126 { 00127 Data& data = this->getState(); 00128 const int numChannels = this->getNumChannels(); 00129 00130 const SampleType fadeIncrement = data.fadeIncrement; 00131 const SampleType fadeMax = TypeUtility<SampleType>::getTypePeak(); 00132 const SampleType fadeMin = Math<SampleType>::get0(); 00133 SampleType fadeOutLevel, fadeInLevel; 00134 00135 for (int channel = 0; channel < numChannels; ++channel) 00136 { 00137 fadeOutLevel = data.fadeLevel; 00138 fadeInLevel = fadeMax - fadeOutLevel; 00139 00140 Buffer& outputBuffer = this->getOutputBuffer (channel); 00141 SampleType* const outputSamples = outputBuffer.getArray(); 00142 const int outputBufferLength = outputBuffer.length(); 00143 00144 const Buffer fadeInSourceBuffer (currentSource.process (info, channel)); 00145 const SampleType* const fadeInSourceSamples = fadeInSourceBuffer.getArray(); 00146 const int fadeInSourceBufferLength = fadeInSourceBuffer.length(); 00147 00148 const Buffer fadeOutSourceBuffer (fadeSource.process (info, channel)); 00149 const SampleType* const fadeOutSourceSamples = fadeOutSourceBuffer.getArray(); 00150 const int fadeOutSourceBufferLength = fadeOutSourceBuffer.length(); 00151 00152 int i; 00153 00154 if ((fadeInSourceBufferLength == outputBufferLength) && 00155 (fadeInSourceBufferLength) == fadeOutSourceBufferLength) 00156 { 00157 for (i = 0; i < outputBufferLength; ++i) 00158 { 00159 outputSamples[i] = fadeInSourceSamples[i] * fadeInLevel + fadeOutSourceSamples[i] * fadeOutLevel; 00160 fadeInLevel = plonk::min (fadeInLevel + fadeIncrement, fadeMax); 00161 fadeOutLevel = plonk::max (fadeOutLevel - fadeIncrement, fadeMin); 00162 } 00163 } 00164 else 00165 { 00166 double fadeInSourcePosition = 0.0; 00167 const double fadeInSourceIncrement = double (fadeInSourceBufferLength) / double (outputBufferLength); 00168 double fadeOutSourcePosition = 0.0; 00169 const double fadeOutSourceIncrement = double (fadeOutSourceBufferLength) / double (outputBufferLength); 00170 00171 for (i = 0; i < outputBufferLength; ++i) 00172 { 00173 outputSamples[i] = fadeInSourceSamples[int (fadeInSourcePosition)] * fadeInLevel + 00174 fadeOutSourceSamples[int (fadeOutSourcePosition)] * fadeOutLevel; 00175 00176 fadeInLevel = plonk::min (fadeInLevel + fadeIncrement, fadeMax); 00177 fadeOutLevel = plonk::max (fadeOutLevel - fadeIncrement, fadeMin); 00178 00179 fadeInSourcePosition += fadeInSourceIncrement; 00180 fadeOutSourcePosition += fadeOutSourceIncrement; 00181 } 00182 } 00183 00184 if (data.allowAutoDelete == false) 00185 info.resetShouldDelete(); 00186 } 00187 00188 data.fadeLevel = fadeOutLevel; 00189 00190 if (fadeOutLevel <= fadeMin) 00191 { 00192 this->update (Text::getMessagePatchEnd(), fadeSource); 00193 fadeSource = UnitType::getNull(); 00194 } 00195 } 00196 00197 void processCopy (ProcessInfo& info) 00198 { 00199 Data& data = this->getState(); 00200 const int numChannels = this->getNumChannels(); 00201 00202 for (int channel = 0; channel < numChannels; ++channel) 00203 { 00204 Buffer& outputBuffer = this->getOutputBuffer (channel); 00205 SampleType* const outputSamples = outputBuffer.getArray(); 00206 const int outputBufferLength = outputBuffer.length(); 00207 00208 const Buffer sourceBuffer (currentSource.process (info, channel)); 00209 const SampleType* const sourceSamples = sourceBuffer.getArray(); 00210 const int sourceBufferLength = sourceBuffer.length(); 00211 00212 int i; 00213 00214 if (sourceBufferLength == outputBufferLength) 00215 { 00216 Buffer::copyData (outputSamples, sourceSamples, outputBufferLength); 00217 } 00218 else if (sourceBufferLength == 1) 00219 { 00220 NumericalArrayFiller<SampleType>::fill (outputSamples, sourceSamples[0], outputBufferLength); 00221 } 00222 else 00223 { 00224 double sourcePosition = 0.0; 00225 const double sourceIncrement = double (sourceBufferLength) / double (outputBufferLength); 00226 00227 for (i = 0; i < outputBufferLength; ++i) 00228 { 00229 outputSamples[i] = sourceSamples[int (sourcePosition)]; 00230 sourcePosition += sourceIncrement; 00231 } 00232 } 00233 00234 if (data.allowAutoDelete == false) 00235 info.resetShouldDelete(); 00236 } 00237 } 00238 00239 private: 00240 UnitType currentSource; 00241 UnitType fadeSource; 00242 00243 static inline int numChannelsInSource (Inputs const& inputs) throw() 00244 { 00245 const UnitVariableType& var = inputs[IOKey::UnitVariable].asUnchecked<UnitVariableType>(); 00246 return var.getValue().getNumChannels(); 00247 } 00248 00249 inline void updateSources (ProcessInfo& info) throw() 00250 { 00251 UnitVariableType& var = ChannelInternalCore::getInputAs<UnitVariableType> (IOKey::UnitVariable); 00252 00253 if (var.isValueNotNull()) 00254 { 00255 fadeSource = currentSource; 00256 currentSource = UnitType::getNull(); 00257 var.swapValues (currentSource); 00258 00259 this->update (Text::getMessagePatchStart(), currentSource); 00260 00261 Data& data = this->getState(); 00262 00263 DurationUnitType& durationUnit = ChannelInternalCore::getInputAs<DurationUnitType> (IOKey::Duration); 00264 plonk_assert (durationUnit.getNumChannels() == 1); 00265 const DurationBufferType& durationBuffer (durationUnit.process (info, 0)); 00266 const DurationType duration = durationBuffer.atUnchecked (0); 00267 00268 if (duration > Math<DurationType>::get0()) 00269 { 00270 const int fadeSamplesRemaining = int (duration * data.base.sampleRate + 0.5); 00271 data.fadeIncrement = TypeUtility<SampleType>::getTypePeak() / SampleType (fadeSamplesRemaining); 00272 data.fadeLevel = TypeUtility<SampleType>::getTypePeak(); 00273 } 00274 } 00275 } 00276 }; 00277 00278 00279 //------------------------------------------------------------------------------ 00280 00298 template<class SampleType> 00299 class PatchUnit 00300 { 00301 public: 00302 typedef PatchChannelInternal<SampleType> PatchChannelInternalType; 00303 typedef typename PatchChannelInternalType::Data Data; 00304 typedef ChannelBase<SampleType> ChannelType; 00305 typedef ChannelInternal<SampleType,Data> Internal; 00306 typedef ChannelInternalBase<SampleType> InternaBase; 00307 typedef UnitBase<SampleType> UnitType; 00308 typedef InputDictionary Inputs; 00309 typedef NumericalArray<SampleType> Buffer; 00310 typedef Variable<UnitType&> UnitVariableType; 00311 00312 typedef typename PatchChannelInternalType::DurationType DurationType; 00313 typedef typename PatchChannelInternalType::DurationUnitType DurationUnitType; 00314 typedef typename PatchChannelInternalType::DurationBufferType DurationBufferType; 00315 00316 static inline UnitInfos getInfo() throw() 00317 { 00318 const double blockSize = (double)BlockSize::getDefault().getValue(); 00319 const double sampleRate = SampleRate::getDefault().getValue(); 00320 00321 return UnitInfo ("Patch", "Threadsafe repatching of signals.", 00322 00323 // output 00324 1, 00325 IOKey::Generic, Measure::None, IOInfo::NoDefault, IOLimit::None, 00326 IOKey::End, 00327 00328 // inputs 00329 IOKey::UnitVariable, Measure::None, IOInfo::NoDefault, IOLimit::None, 00330 IOKey::AutoDeleteFlag, Measure::Bool, IOInfo::True, IOLimit::None, 00331 IOKey::PreferredNumChannels, Measure::Count, 0.0, IOLimit::None, 00332 IOKey::Duration, Measure::Seconds, 0.1, IOLimit::Minimum, Measure::Seconds, 0.0, 00333 IOKey::BlockSize, Measure::Samples, blockSize, IOLimit::Minimum, Measure::Samples, 1.0, 00334 IOKey::SampleRate, Measure::Hertz, sampleRate, IOLimit::Minimum, Measure::Hertz, 0.0, 00335 IOKey::End); 00336 } 00337 00339 static UnitType ar (UnitVariableType const& initialSource, 00340 const bool allowAutoDelete = true, 00341 const int preferredNumChannels = 0, 00342 DurationUnitType const& fadeDuration = DurationType (0.1), 00343 BlockSize const& preferredBlockSize = BlockSize::getDefault(), 00344 SampleRate const& preferredSampleRate = SampleRate::getDefault()) throw() 00345 { 00346 Inputs inputs; 00347 inputs.put (IOKey::Unknown, UnitType::getNull()); // ensure getNull() is called off the audio thread for the first time 00348 inputs.put (IOKey::UnitVariable, initialSource); 00349 inputs.put (IOKey::Duration, fadeDuration); 00350 00351 Data data = { { -1.0, -1.0 }, preferredNumChannels, 0, 0, allowAutoDelete }; 00352 00353 return UnitType::template proxiesFromInputs<PatchChannelInternalType> (inputs, 00354 data, 00355 preferredBlockSize, 00356 preferredSampleRate); 00357 } 00358 }; 00359 00360 typedef PatchUnit<PLONK_TYPE_DEFAULT> Patch; 00361 00362 00363 #endif // PLONK_PATCHCHANNEL_H 00364 00365