pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_AudioHostBase.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_AUDIOHOSTBASE_H
00040 #define PLONK_AUDIOHOSTBASE_H
00041 
00042 
00043 template<class SampleType>
00044 class AudioHostBase;
00045 
00048 template<class SampleType>
00049 class AudioHostBase : public PlonkBase
00050 {
00051 public:    
00052     typedef NumericalArray<SampleType*>            BufferArray;
00053     typedef NumericalArray<const SampleType*>      ConstBufferArray;
00054 
00055     typedef UnitBase<SampleType>                UnitType;
00056     typedef BusBuffer<SampleType>               BusType;
00057     typedef PLONK_BUSARRAYBASETYPE<BusType>     BussesType;
00058     typedef Dictionary<Dynamic>                 OptionDictionary;
00059     typedef NumericalArray<SampleType>          BufferType;
00060     
00062     AudioHostBase() throw()
00063     :   preferredHostSampleRate (0.0),
00064         preferredHostBlockSize (0),
00065         preferredGraphBlockSize (0),
00066         isRunning (false),
00067         isPaused (false)
00068     { 
00069     }
00070         
00072     virtual ~AudioHostBase() 
00073     {
00074     }
00075         
00077     inline bool getIsRunning() const throw() { return isRunning.getValue(); }
00078     
00080     inline bool getIsPaused() const throw() { return isPaused.getValue(); }
00081 
00083     inline const UnitType& getOutputUnit() const throw() { return outputUnit; }
00084     
00086     inline int getNumInputs() const throw()  { return this->inputs.length(); }
00087     
00089     inline int getNumOutputs() const throw() { return this->outputs.length(); }
00090     
00092     inline double getPreferredHostSampleRate() const throw() { return preferredHostSampleRate; }
00093     
00095     inline int getPreferredHostBlockSize() const throw() { return preferredHostBlockSize; }
00096     
00099     inline void setPreferredHostSampleRate (const double newRate) throw() { preferredHostSampleRate = newRate; }
00100     
00103     inline void setPreferredHostBlockSize (const int newSize) throw() {  preferredHostBlockSize = newSize; }
00104     
00106     inline int getPreferredGraphBlockSize() const throw() { return preferredGraphBlockSize; }
00107         
00110     inline void setPreferredGraphBlockSize (const int newSize) throw() {  preferredGraphBlockSize = newSize; }
00111     
00114     void setNumInputs (const int numInputs) throw();
00115     
00118     void setNumOutputs (const int numOutputs) throw();
00119     
00121     OptionDictionary getOtherOptions() const throw() { return otherOptions; }
00122     
00123     virtual void pauseHost() throw() { plonk_assertfalse; }     // the host implementation needs to support pausing
00124     virtual void resumeHost() throw() { plonk_assertfalse; }    // the host implementation needs to support pausing
00125     
00126 protected:
00128     inline const ConstBufferArray& getInputs() const throw()    { return this->inputs; }
00129     
00131     inline ConstBufferArray& getInputs() throw()                { return this->inputs; }
00132 
00134     inline const BufferArray& getOutputs() const throw()        { return this->outputs; }
00135     
00137     inline BufferArray& getOutputs() throw()                    { return this->outputs; }
00138 
00140     virtual Text getHostName() const = 0;
00141     
00143     virtual Text getNativeHostName() const = 0;
00144     
00146     virtual Text getInputName() const = 0;
00147     
00149     virtual Text getOutputName() const = 0;
00150     
00152     virtual double getCpuUsage() const = 0;
00153 
00155     virtual void startHost() = 0;
00156     
00158     virtual void stopHost() = 0;
00159         
00160     virtual void hostStopped() throw()  { }
00161     virtual void hostStarting() throw() { }
00162     virtual void hostPaused() throw()   { }
00163     virtual void hostResuming() throw() { }
00164 
00167     virtual UnitType constructGraph() = 0;
00168     
00170     inline void process() throw()
00171     {
00172         int i;
00173 
00174 #ifdef PLONK_DEBUG
00175         Threading::ID currentThreadID = Threading::getCurrentThreadID();
00176         if (currentThreadID != Threading::getAudioThreadID())
00177             Threading::setAudioThreadID (Threading::getCurrentThreadID());
00178 #endif
00179         const int numInputs = this->inputs.length();
00180         const int numOutputs = this->outputs.length();
00181         plonk_assert (this->busses.length() == numInputs);
00182 
00183         int blockRemain = preferredHostBlockSize;        
00184         const int graphBlockSize = BlockSize::getDefault().getValue();
00185         
00186         // must do more checks in case the block sizes are not compatible on this run
00187         
00188         while (blockRemain > 0)
00189         {
00190             for (i = 0; i < numInputs; ++i)
00191             {
00192                 this->busses.atUnchecked (i).write (this->info.getTimeStamp(), 
00193                                                     graphBlockSize, 
00194                                                     this->inputs.atUnchecked (i)); 
00195                 this->inputs.atUnchecked (i) += graphBlockSize;
00196             }
00197             
00198             this->outputUnit.process (info);
00199             
00200             if (this->outputUnit.isNotNull())
00201             {
00202                 for (i = 0; i < numOutputs; ++i)
00203                 {
00204                     const SampleType* const unitOutput = this->outputUnit.getOutputSamples (i);
00205                     BufferType::copyData (this->outputs.atUnchecked (i), unitOutput, graphBlockSize);   
00206                     this->outputs.atUnchecked (i) += graphBlockSize;
00207                 }
00208             }
00209             else if (numOutputs > 0)
00210             {
00211                 for (i = 0; i < numOutputs; ++i)
00212                 {
00213                     BufferType::zeroData (this->outputs.atUnchecked (i), graphBlockSize);   
00214                     this->outputs.atUnchecked (i) += graphBlockSize;
00215                 }
00216             }
00217                         
00218             this->info.offsetTimeStamp (SampleRate::getDefault().getSampleDurationInTicks() * graphBlockSize);
00219             
00220             blockRemain -= graphBlockSize;
00221         }
00222         
00223 #if PLONK_DEBUG
00224         // null the pointers to cause crash if buffers are not updated each HW block
00225         this->inputs.zero();
00226         this->outputs.zero();
00227 #endif
00228     }
00229     
00231     void startHostInternal() throw()
00232     {
00233         initFormat();
00234         outputUnit = constructGraph();
00235         hostStarting();
00236         setIsRunning (true);
00237     }
00238     
00239 protected:
00243     inline void setIsRunning (const bool state) throw() { isRunning = state; }
00244 
00245     inline void setIsPaused (const bool state) throw() { isPaused = state; }
00246     
00247 private:
00248     double preferredHostSampleRate;
00249     int preferredHostBlockSize;
00250     int preferredGraphBlockSize;
00251         AtomicInt isRunning;
00252     AtomicInt isPaused;
00253     OptionDictionary otherOptions;
00254 
00255     ProcessInfo info;
00256     UnitType outputUnit;
00257     BussesType busses;
00258     ConstBufferArray inputs;
00259     BufferArray outputs;    
00260     
00261     inline void initFormat() throw()
00262     {
00263         SampleRate::getDefault().setValue (preferredHostSampleRate);
00264         
00265         // preferredGraphBlockSize must be less that the hardware size 
00266         // and divide into the hardware size without a remainder.
00267         if ((preferredGraphBlockSize == 0) ||
00268             (preferredHostBlockSize <= preferredGraphBlockSize) ||
00269             ((preferredHostBlockSize % preferredGraphBlockSize) != 0))
00270         {
00271             preferredGraphBlockSize = preferredHostBlockSize;
00272         }
00273         
00274         BlockSize::getDefault().setValue (preferredGraphBlockSize); 
00275     }
00276 
00277 };
00278 
00279 //------------------------------------------------------------------------------
00280 
00281 template<class SampleType>
00282 void AudioHostBase<SampleType>::setNumInputs (const int numInputs) throw()
00283 {
00284     plonk_assert (numInputs >= 0);
00285     
00286     if (numInputs != this->getNumInputs())
00287     {
00288         this->busses.clear();
00289         
00290         if (numInputs != 0)
00291         {
00292             inputs.setSize (numInputs, false);
00293             
00294             for (int i = 0; i < numInputs; ++i)
00295             {
00296                 this->inputs.atUnchecked (i) = 0;
00297                 this->busses.add (BusType (i));
00298             }
00299         }
00300         else this->inputs.clear();
00301     }
00302 }
00303 
00304 template<class SampleType>
00305 void AudioHostBase<SampleType>::setNumOutputs (const int numOutputs) throw()
00306 {
00307     plonk_assert (numOutputs >= 0);
00308     
00309     if (numOutputs != this->getNumOutputs())
00310     {            
00311         if (numOutputs != 0)
00312         {
00313             outputs.setSize (numOutputs, false);
00314             
00315             for (int i = 0; i < numOutputs; ++i)
00316                 this->outputs.atUnchecked (i) = 0;
00317         }
00318         else this->outputs.clear();
00319     }
00320 }
00321 
00322 
00323 #endif // PLONK_AUDIOHOSTBASE_H
 All Classes Functions Typedefs Enumerations Enumerator Properties