pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_FilePlay.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_FILEPLAY_H
00040 #define PLONK_FILEPLAY_H
00041 
00042 #include "../channel/plonk_ChannelInternalCore.h"
00043 #include "../plonk_GraphForwardDeclarations.h"
00044 
00045 template<class SampleType> class FilePlayChannelInternal;
00046 
00047 PLONK_CHANNELDATA_DECLARE(FilePlayChannelInternal,SampleType)
00048 {    
00049     ChannelInternalCore::Data base;
00050     int numChannels;
00051     int cueIndex;
00052     
00053     bool done:1;
00054     bool deleteWhenDone:1;
00055 };
00056 
00057 //------------------------------------------------------------------------------
00058 
00060 template<class SampleType>
00061 class FilePlayChannelInternal
00062 :   public ProxyOwnerChannelInternal<SampleType, PLONK_CHANNELDATA_NAME(FilePlayChannelInternal,SampleType)>
00063 {
00064 public:
00065     typedef PLONK_CHANNELDATA_NAME(FilePlayChannelInternal,SampleType)  Data;
00066     typedef ChannelBase<SampleType>                                     ChannelType;
00067     typedef ObjectArray<ChannelType>                                    ChannelArrayType;
00068     typedef FilePlayChannelInternal<SampleType>                         FilePlayInternal;
00069     typedef ProxyOwnerChannelInternal<SampleType,Data>                  Internal;
00070     typedef UnitBase<SampleType>                                        UnitType;
00071     typedef InputDictionary                                             Inputs;
00072     typedef NumericalArray<SampleType>                                  Buffer;
00073 
00074     FilePlayChannelInternal (Inputs const& inputs, 
00075                              Data const& data, 
00076                              BlockSize const& blockSize,
00077                              SampleRate const& sampleRate,
00078                              ChannelArrayType& channels) throw()
00079     :   Internal (decideNumChannels (inputs, data), 
00080                   inputs, data, blockSize, sampleRate,
00081                   channels),
00082         zero (0)
00083     {
00084 //        AudioFileReader& file = this->getInputAsAudioFileReader (IOKey::AudioFileReader);
00085 //        file.setOwner (this);
00086     }
00087     
00088     ~FilePlayChannelInternal()
00089     {
00090 //        AudioFileReader& file = this->getInputAsAudioFileReader (IOKey::AudioFileReader);
00091 //        file.setOwner (0);
00092     }
00093             
00094     Text getName() const throw()
00095     {
00096         return "File Play";
00097     }       
00098     
00099     IntArray getInputKeys() const throw()
00100     {
00101         const IntArray keys (IOKey::AudioFileReader, IOKey::Loop);
00102         return keys;
00103     }    
00104         
00105     void initChannel (const int channel) throw()
00106     {       
00107         if ((channel % this->getNumChannels()) == 0)
00108         {
00109             const AudioFileReader& file = this->getInputAsAudioFileReader (IOKey::AudioFileReader);
00110 
00111             double fileSampleRate = file.getSampleRate();
00112             
00113             if (fileSampleRate <= 0.0)
00114                 fileSampleRate = file.getDefaultSampleRate();
00115 
00116             this->setSampleRate (SampleRate::decide (fileSampleRate, this->getSampleRate()));
00117             buffer.setSize (this->getBlockSize().getValue() * file.getNumChannels(), false);
00118         }
00119         
00120         this->initProxyValue (channel, 0);
00121     }
00122     
00123     void process (ProcessInfo& info, const int /*channel*/) throw()
00124     {
00125         Data& data = this->getState();
00126         
00127         IntVariable& loopCount (this->template getInputAs<IntVariable> (IOKey::LoopCount));
00128         int channel;
00129         int offset = 0;
00130         const int blockSize = this->getBlockSize().getValue();
00131         int blockRemain = blockSize;
00132 
00133         while (offset < blockSize)
00134         {
00135             AudioFileReader& file = this->getInputAsAudioFileReader (IOKey::AudioFileReader);
00136             
00137             const int numChannels = this->getNumChannels();
00138             const int fileNumChannels = file.getNumChannels();
00139             int bufferSize = blockRemain * fileNumChannels;
00140             
00141             const LongLong numFrames = file.getNumFrames();
00142             LongLong filePosition = file.getFramePosition();
00143             bool willHitEOF = false;
00144             
00145             if (numFrames > 0)
00146             {
00147                 LongLong framesRemaining = numFrames - filePosition;
00148                 
00149                 if (framesRemaining == 0)
00150                 {
00151                     if ((loopCount.getValue() == 0) || (loopCount.getValue() > 1))
00152                     {
00153                         file.resetFramePosition();
00154                         data.cueIndex = 0;
00155                         
00156                         if (loopCount.getValue() > 1)
00157                             loopCount.setValue (loopCount.getValue() - 1);
00158                     }
00159                     
00160                     filePosition = file.getFramePosition();
00161                     framesRemaining = numFrames - filePosition;
00162                 }
00163                 
00164                 if (framesRemaining <= LongLong (blockRemain))
00165                 {
00166                     bufferSize = int (plonk::min (LongLong (bufferSize), framesRemaining * fileNumChannels));
00167                     willHitEOF = true;
00168                 }
00169             }
00170             
00171             const AudioFileMetaData metaData = file.getMetaData();
00172             
00173             if (metaData.isNotNull())
00174             {
00175                 const AudioFileCuePointArray cuePoints = metaData.getCuePoints();
00176                 AudioFileCuePoint cue = cuePoints[data.cueIndex];
00177                 
00178                 bool renderToNextCue = false;
00179                 
00180                 if (cue.isNotNull())
00181                 {
00182                     if (cue.getFramePosition (file.getSampleRate()) == filePosition)
00183                     {
00184                         this->update (Text::getMessageCuePoint(), Text (cue.getLabel()));
00185                         
00186                         ++data.cueIndex;
00187                         cue = cuePoints[data.cueIndex];
00188                         
00189                         if (cue.isNotNull())
00190                             renderToNextCue = true;
00191                     }
00192                     else
00193                     {
00194                         renderToNextCue = true;
00195                     }
00196                     
00197                     if (renderToNextCue)
00198                     {
00199                         const LongLong framesToNextCue = cue.getFramePosition (file.getSampleRate()) - filePosition;
00200                         
00201                         if (framesToNextCue < LongLong (bufferSize / fileNumChannels))
00202                         {
00203                             bufferSize = int (plonk::min (LongLong (bufferSize), framesToNextCue * fileNumChannels));
00204                             willHitEOF = false;
00205                         }
00206                     }
00207                 }
00208             }
00209             
00210             buffer.setSize (bufferSize, false);
00211             file.readFrames (buffer, zero);
00212             const bool changedNumChannels = file.didNumChannelsChange();
00213             const bool audioFileChanged = file.didAudioFileChange();
00214             const bool hitEOF = file.didHitEOF();
00215             const int bufferAvailable = buffer.length();
00216             
00217             if ((bufferAvailable == 0) || data.done)
00218             {
00219                 for (channel = 0; channel < numChannels; ++channel)
00220                 {
00221                     Buffer& outputBuffer = this->getOutputBuffer (channel);
00222                     SampleType* const outputSamples = outputBuffer.getArray() + offset;
00223                     const int outputBufferLength = outputBuffer.length() - offset;
00224                     
00225                     for (int i = 0; i < outputBufferLength; ++i)
00226                         outputSamples[i] = SampleType (0);
00227                 }
00228                 
00229                 offset = blockSize;
00230                 blockRemain = 0;
00231             }
00232             else if (willHitEOF || hitEOF)
00233             {
00234                 const int bufferFramesAvailable = bufferAvailable / fileNumChannels;
00235                 
00236                 for (channel = 0; channel < numChannels; ++channel)
00237                 {
00238                     Buffer& outputBuffer = this->getOutputBuffer (channel);
00239                     SampleType* const outputSamples = outputBuffer.getArray() + offset;
00240                     const int outputBufferLength = outputBuffer.length() - offset;
00241                     const int outputLengthToWrite = plonk::min (bufferFramesAvailable, outputBufferLength);
00242                     
00243                     const SampleType* bufferSamples = buffer.getArray() + ((unsigned int)channel % (unsigned int)fileNumChannels);
00244                     
00245                     for (int i = 0; i < outputLengthToWrite; ++i, bufferSamples += fileNumChannels)
00246                         outputSamples[i] = *bufferSamples;
00247                 }
00248                 
00249                 if ((loopCount.getValue() == 0) || (loopCount.getValue() > 1))
00250                 {
00251                     file.resetFramePosition();
00252                     data.cueIndex = 0;
00253                     
00254                     if (loopCount.getValue() > 1)
00255                         loopCount.setValue (loopCount.getValue() - 1);
00256                 }
00257                 else if (!data.done)
00258                 {
00259                     data.done = true;
00260                     this->update (Text::getMessageDone(), Dynamic::getNull());
00261                 }
00262                 
00263                 offset += bufferFramesAvailable;
00264                 blockRemain -= bufferFramesAvailable;
00265             }
00266             else 
00267             {                
00268                 const int bufferFramesAvailable = bufferAvailable / fileNumChannels;
00269                 
00270                 for (channel = 0; channel < numChannels; ++channel)
00271                 {
00272                     Buffer& outputBuffer = this->getOutputBuffer (channel);
00273                     SampleType* const outputSamples = outputBuffer.getArray() + offset;
00274                     const int outputBufferLength = outputBuffer.length() - offset;
00275                     const int outputLengthToWrite = plonk::min (bufferFramesAvailable, outputBufferLength);
00276                     
00277                     const SampleType* bufferSamples = buffer.getArray() + ((unsigned int)channel % (unsigned int)fileNumChannels);
00278                     
00279                     for (int i = 0; i < outputLengthToWrite; ++i, bufferSamples += fileNumChannels)
00280                         outputSamples[i] = *bufferSamples;
00281                 }
00282                                 
00283                 offset += bufferFramesAvailable;
00284                 blockRemain -= bufferFramesAvailable;
00285             }
00286             
00287             if (audioFileChanged)
00288                 this->update (Text::getMessageAudioFileChanged(), file);
00289                 
00290             if (changedNumChannels)
00291                 this->update (Text::getMessageNumChannelsChanged(), IntVariable (fileNumChannels));
00292         }
00293         
00294         if (data.done && data.deleteWhenDone)
00295             info.setShouldDelete();
00296     }
00297 
00298     
00299 //    void process (ProcessInfo& info, const int /*channel*/) throw()
00300 //    {
00301 //        Data& data = this->getState();        
00302 //        
00303 //        IntVariable& loopCount (this->template getInputAs<IntVariable> (IOKey::LoopCount));
00304 //        int channel;
00305 //        int offset = 0;
00306 //        bool done = false;
00307 //                
00308 //        while (!done)
00309 //        {
00310 //            AudioFileReader& file = this->getInputAsAudioFileReader (IOKey::AudioFileReader);
00311 //            
00312 //            const int numChannels = this->getNumChannels();
00313 //            const int fileNumChannels = file.getNumChannels();
00314 //            const int blockSize = this->getBlockSize().getValue();
00315 //            int bufferSize = blockSize * fileNumChannels;
00316 //            
00317 //            const LongLong numFrames = file.getNumFrames();
00318 //            const LongLong filePosition = file.getFramePosition();
00319 //            bool willHitEOF = false;
00320 //
00321 //            if (numFrames > 0)
00322 //            {
00323 //                const LongLong framesRemaining = numFrames - filePosition;
00324 //                
00325 //                if (framesRemaining <= (LongLong)blockSize)
00326 //                {
00327 //                    bufferSize = plonk::min (blockSize, (int)framesRemaining * fileNumChannels);
00328 //                    willHitEOF = true;
00329 //                }
00330 //            }
00331 //            
00332 //            const AudioFileMetaData metaData = file.getMetaData();
00333 //            
00334 //            if (metaData.isNotNull())
00335 //            {
00336 //                const AudioFileCuePointArray cuePoints = metaData.getCuePoints();
00337 //                AudioFileCuePoint cue = cuePoints[data.cueIndex];
00338 //                                
00339 //                bool renderToNextCue = false;
00340 //                
00341 //                if (cue.isNotNull())
00342 //                {
00343 //                    if (cue.getPosition() == filePosition)
00344 //                    {
00345 //                        this->update (Text::getMessageCuePoint(), Text (cue.getLabel()));
00346 //                        
00347 //                        ++data.cueIndex;
00348 //                        cue = cuePoints[data.cueIndex];
00349 //                        
00350 //                        if (cue.isNotNull())
00351 //                            renderToNextCue = true;                            
00352 //                    }
00353 //                    else
00354 //                    {
00355 //                        renderToNextCue = true;
00356 //                    }
00357 //                    
00358 //                    if (renderToNextCue)
00359 //                    {
00360 //                        const LongLong framesToNextCue = cue.getPosition() - filePosition;
00361 //                        
00362 //                        if (framesToNextCue < (LongLong)blockSize)
00363 //                            bufferSize = plonk::min (bufferSize, (int)framesToNextCue * fileNumChannels);
00364 //                    }
00365 //                }
00366 //            }
00367 //            
00368 //            buffer.setSize (bufferSize, false);
00369 //            file.readFrames (buffer, zero);
00370 //            const bool changedNumChannels = file.didNumChannelsChange();
00371 //            const int bufferAvailable = buffer.length();
00372 //
00373 //            if (bufferAvailable == 0)
00374 //            {
00375 //                for (channel = 0; channel < numChannels; ++channel)
00376 //                {
00377 //                    Buffer& outputBuffer = this->getOutputBuffer (channel);
00378 //                    SampleType* const outputSamples = outputBuffer.getArray() + offset;
00379 //                    const int outputBufferLength = outputBuffer.length() - offset;
00380 //                                        
00381 //                    for (int i = 0; i < outputBufferLength; ++i)
00382 //                        outputSamples[i] = SampleType (0);
00383 //                }
00384 //                
00385 //                done = true;
00386 //            }
00387 //            else if (willHitEOF)
00388 //            {
00389 //                const int bufferFramesAvailable = bufferAvailable / fileNumChannels;
00390 //                
00391 //                for (channel = 0; channel < numChannels; ++channel)
00392 //                {
00393 //                    Buffer& outputBuffer = this->getOutputBuffer (channel);
00394 //                    SampleType* const outputSamples = outputBuffer.getArray() + offset;
00395 //                    const int outputBufferLength = outputBuffer.length() - offset;
00396 //                    const int outputLengthToWrite = plonk::min (bufferFramesAvailable, outputBufferLength);
00397 //                    
00398 //                    const SampleType* bufferSamples = buffer.getArray() + ((unsigned int)channel % (unsigned int)fileNumChannels);
00399 //                    
00400 //                    for (int i = 0; i < outputLengthToWrite; ++i, bufferSamples += fileNumChannels)
00401 //                        outputSamples[i] = *bufferSamples;                        
00402 //                }
00403 //                
00404 //                if ((loopCount.getValue() == 0) || (loopCount.getValue() > 1))
00405 //                {
00406 //                    file.resetFramePosition();
00407 //                    data.cueIndex = 0;
00408 //                    
00409 //                    if (loopCount.getValue() > 1)
00410 //                        loopCount.setValue (loopCount.getValue() - 1);
00411 //                }
00412 //                else if (!data.done)
00413 //                {
00414 //                    data.done = true;
00415 //                    this->update (Text::getMessageDone(), Dynamic::getNull());
00416 //                }
00417 //                
00418 //                offset += bufferFramesAvailable;
00419 //                done = false;
00420 //            }
00421 //            else if (changedNumChannels)
00422 //            {
00423 //                this->update (Text::getMessageNumChannelsChanged(), IntVariable (fileNumChannels));
00424 //                
00425 //                const int bufferFramesAvailable = bufferAvailable / fileNumChannels;
00426 //                
00427 //                for (channel = 0; channel < numChannels; ++channel)
00428 //                {
00429 //                    Buffer& outputBuffer = this->getOutputBuffer (channel);
00430 //                    SampleType* const outputSamples = outputBuffer.getArray() + offset;
00431 //                    const int outputBufferLength = outputBuffer.length() - offset;
00432 //                    const int outputLengthToWrite = plonk::min (bufferFramesAvailable, outputBufferLength);
00433 //                    
00434 //                    const SampleType* bufferSamples = buffer.getArray() + ((unsigned int)channel % (unsigned int)fileNumChannels);
00435 //                    
00436 //                    for (int i = 0; i < outputLengthToWrite; ++i, bufferSamples += fileNumChannels)
00437 //                        outputSamples[i] = *bufferSamples;
00438 //                }
00439 //                
00440 //                offset += bufferFramesAvailable;
00441 //                done = false;
00442 //            }
00443 //            else
00444 //            {
00445 //                for (channel = 0; channel < numChannels; ++channel)
00446 //                {
00447 //                    Buffer& outputBuffer = this->getOutputBuffer (channel);
00448 //                    SampleType* const outputSamples = outputBuffer.getArray() + offset;
00449 //                    const int outputBufferLength = outputBuffer.length() - offset;
00450 //                    
00451 //                    const SampleType* bufferSamples = buffer.getArray() + ((unsigned int)channel % (unsigned int)fileNumChannels);
00452 //                    
00453 //                    for (int i = 0; i < outputBufferLength; ++i, bufferSamples += fileNumChannels)
00454 //                        outputSamples[i] = *bufferSamples;
00455 //                }
00456 //                
00457 //                done = true;
00458 //            }
00459 //        }
00460 //        
00461 //        if (data.done && data.deleteWhenDone)
00462 //            info.setShouldDelete();
00463 //    }
00464 
00465 
00466 private:
00467     Buffer buffer; // might need to use a signal...
00468     IntVariable zero;
00469     
00470     static const int decideNumChannels (Inputs const& inputs, Data const& data) throw()
00471     {
00472         if (data.numChannels > 0)
00473         {
00474             return data.numChannels;
00475         }
00476         else
00477         {
00478             const AudioFileReader& file = inputs[IOKey::AudioFileReader].asUnchecked<AudioFileReader>();
00479             return file.getNumChannels();
00480         }
00481     }
00482 };
00483 
00484 //------------------------------------------------------------------------------
00485 
00509 template<class SampleType>
00510 class FilePlayUnit
00511 {
00512 public:    
00513     typedef FilePlayChannelInternal<SampleType>         FilePlayInternal;
00514     typedef typename FilePlayInternal::Data             Data;
00515     typedef ChannelBase<SampleType>                     ChannelType;
00516     typedef ChannelInternal<SampleType,Data>            Internal;
00517     typedef UnitBase<SampleType>                        UnitType;
00518     typedef InputDictionary                             Inputs;
00519         
00520     
00521     static inline UnitInfos getInfo() throw()
00522     {
00523         const double blockSize = (double)BlockSize::getDefault().getValue();
00524         const double sampleRate = SampleRate::getDefault().getValue();
00525         
00526         return UnitInfo ("FilePlay", "A signal player generator.",
00527                          
00528                          // output
00529                          ChannelCount::VariableChannelCount, 
00530                          IOKey::Generic,            Measure::None,      0.0,            IOLimit::None,
00531                          IOKey::End,
00532                          
00533                          // inputs
00534                          IOKey::AudioFileReader,    Measure::None,
00535                          IOKey::LoopCount,          Measure::Count,     0.0,            IOLimit::Minimum,   Measure::Count,                 0.0,
00536                          IOKey::Multiply,           Measure::Factor,    1.0,            IOLimit::None,
00537                          IOKey::Add,                Measure::None,      0.0,            IOLimit::None,
00538                          IOKey::AutoDeleteFlag,     Measure::Bool,      IOInfo::True,   IOLimit::None,
00539                          IOKey::BlockSize,          Measure::Samples,   blockSize,      IOLimit::Minimum,   Measure::Samples,               1.0,
00540                          IOKey::SampleRate,         Measure::Hertz,     sampleRate,     IOLimit::Minimum,   Measure::Hertz,                 0.0,
00541                          IOKey::End);
00542     }
00543     
00545     static UnitType ar (AudioFileReader const& file,
00546                         IntVariable const& loopCount = 0,
00547                         UnitType const& mul = SampleType (1),
00548                         UnitType const& add = SampleType (0),
00549                         const bool deleteWhenDone = true,
00550                         BlockSize const& preferredBlockSize = BlockSize::getDefault(),
00551                         SampleRate const& preferredSampleRate = SampleRate::noPreference()) throw()
00552     {             
00553         if (file.isReady() && !file.isOwned())
00554         {            
00555             Inputs inputs;
00556             inputs.put (IOKey::AudioFileReader, file);
00557             inputs.put (IOKey::LoopCount, loopCount);
00558             inputs.put (IOKey::Multiply, mul);
00559             inputs.put (IOKey::Add, add);
00560                             
00561             Data data = { { -1.0, -1.0 }, file.getDefaultNumChannels(), 0, false, deleteWhenDone };
00562             
00563             return UnitType::template proxiesFromInputs<FilePlayInternal> (inputs, 
00564                                                                            data, 
00565                                                                            preferredBlockSize, 
00566                                                                            preferredSampleRate);
00567         } 
00568         else return UnitType::getNull();
00569     }
00570         
00575     class Simple
00576     {
00577     public:
00578         typedef InputTaskUnit<SampleType,Interp::Linear>        TaskType;
00579         typedef ResampleUnit<SampleType,Interp::Linear>         ResampleType;
00580         typedef typename ResampleType::RateType                 RateType;
00581         typedef typename ResampleType::RateUnitType             RateUnitType;
00582         
00583         static UnitType ar (AudioFileReader const& file,
00584                             RateUnitType const& rate = Math<RateUnitType>::get1(),
00585                             IntVariable const& loopCount = 0,
00586                             const int blockSizeMultiplier = 0,
00587                             const int numBuffers = 4)
00588         {
00589             double fileSampleRate = file.getSampleRate();
00590             
00591             if (fileSampleRate <= 0.0)
00592                 fileSampleRate = file.getDefaultSampleRate();
00593             
00594             const DoubleVariable multiplier = blockSizeMultiplier <= 0 ? 
00595                                               (DoubleVariable (fileSampleRate) / SampleRate::getDefault()).ceil() * 2.0 :
00596                                               DoubleVariable (blockSizeMultiplier);
00597             
00598             UnitType play = FilePlayUnit::ar (file, loopCount,
00599                                               SampleType (1), SampleType (0),
00600                                               false,
00601                                               BlockSize::getMultipleOfDefault (multiplier));
00602             
00603             UnitType task = TaskType::ar (play, numBuffers);
00604             
00605             return ResampleType::ar (task, rate);
00606         }
00607         
00608         class HQ
00609         {
00610         public:
00611             typedef InputTaskUnit<SampleType,Interp::Lagrange3>     TaskType;
00612             typedef ResampleUnit<SampleType,Interp::Lagrange3>      ResampleType;
00613             typedef typename ResampleType::RateType                 RateType;
00614             typedef typename ResampleType::RateUnitType             RateUnitType;
00615             
00616             static UnitType ar (AudioFileReader const& file,
00617                                 RateUnitType const& rate = Math<RateUnitType>::get1(),
00618                                 IntVariable const& loopCount = 0,
00619                                 const int blockSizeMultiplier = 0,
00620                                 const int numBuffers = 4)
00621             {
00622                 double fileSampleRate = file.getSampleRate();
00623                 
00624                 if (fileSampleRate <= 0.0)
00625                     fileSampleRate = file.getDefaultSampleRate();
00626 
00627                 const DoubleVariable multiplier = blockSizeMultiplier <= 0 ?
00628                                                   (DoubleVariable (fileSampleRate) / SampleRate::getDefault()).ceil() * 2.0 :
00629                                                   DoubleVariable (blockSizeMultiplier);
00630                 
00631                 UnitType play = FilePlayUnit::ar (file, loopCount,
00632                                                   SampleType (1), SampleType (0),
00633                                                   false,
00634                                                   BlockSize::getMultipleOfDefault (multiplier));
00635                 
00636                 UnitType task = TaskType::ar (play, numBuffers);
00637                 
00638                 return ResampleType::ar (task, rate);
00639             }
00640         };
00641 
00642     };
00643 };
00644 
00645 typedef FilePlayUnit<PLONK_TYPE_DEFAULT> FilePlay;
00646 
00647 
00648 #endif // PLONK_FILEPLAY_H
00649 
 All Classes Functions Typedefs Enumerations Enumerator Properties