Cinder

  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

include/cinder/audio/Callback.h

Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2009, The Barbarian Group
00003  All rights reserved.
00004 
00005  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00006  the following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00009     the following disclaimer.
00010     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00011     the following disclaimer in the documentation and/or other materials provided with the distribution.
00012 
00013  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00014  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00015  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00016  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00017  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00018  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00019  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00020  POSSIBILITY OF SUCH DAMAGE.
00021 */
00022 
00023 #pragma once
00024 
00025 #include "cinder/Cinder.h"
00026 #include "cinder/audio/Io.h"
00027 #include "cinder/audio/Buffer.h"
00028 
00029 #if defined( CINDER_COCOA )
00030     #include "cinder/audio/CocoaCaConverter.h"
00031 #endif
00032 
00033 #include <boost/type_traits/is_same.hpp>
00034 
00035 namespace cinder { namespace audio {
00036 
00037 template<typename,typename> class LoaderSourceCallback;
00038 
00039 template<typename T, typename U>
00040 class Callback : public Source {
00041  public: 
00042     typedef void (T::*CallbackFunction)( uint64_t inSampleOffset, uint32_t inSampleCount, BufferT<U> *ioBuffer );
00043     
00044     virtual ~Callback();
00045     
00046     LoaderRef getLoader( Target *target ) { return LoaderSourceCallback<T,U>::createRef( this, target ); }
00047     double getDuration() const { return 100.0; } //TODO: support for endless sources
00048     
00049  private:
00050     Callback( T* callbackObj, CallbackFunction callbackFn, bool ownCallbackObj, uint32_t aSampleRate, uint16_t aChannelCount );
00051   
00052     void getData( uint64_t inSampleOffset, uint32_t ioSampleCount, Buffer *ioBuffer );
00053     
00054     T* mCallbackObj;
00055     CallbackFunction mCallbackFn;
00056     bool mOwnsCallbackObj;
00057     
00058     friend class LoaderSourceCallback<T,U>;
00059     template <typename T2, typename U2>
00060     friend shared_ptr<Callback<T2,U2> > createCallback( T2* callbackObj, void (T2::*callbackFn)( uint64_t inSampleOffset, uint32_t inSampleCount, BufferT<U2> *ioBuffer ), bool ownCallbackObj, uint32_t aSampleRate, uint16_t aChannelCount );
00061 };
00062 
00063 template<typename T, typename U>
00064 shared_ptr<Callback<T,U> > createCallback( T* callbackObj, void (T::*callbackFn)( uint64_t inSampleOffset, uint32_t inSampleCount, BufferT<U> *ioBuffer ), bool ownCallbackObj = false, uint32_t aSampleRate = 44100, uint16_t aChannelCount = 2 )
00065 {
00066     return shared_ptr<Callback<T,U> >( new Callback<T,U>( callbackObj, callbackFn, ownCallbackObj, aSampleRate, aChannelCount ) );
00067 }
00068 
00069 template<typename T, typename U>
00070 class LoaderSourceCallback : public Loader {
00071  public:
00072     static LoaderRef    createRef( Callback<T,U> *source, Target *target )
00073     {
00074         return shared_ptr<LoaderSourceCallback<T,U> >( new LoaderSourceCallback<T,U>( source, target ) );
00075     }
00076     
00077     ~LoaderSourceCallback() {}
00078     
00079     uint64_t getSampleOffset() const { return mSampleOffset; }
00080     void setSampleOffset( uint64_t anOffset ) { mSampleOffset = anOffset; }
00081     void loadData( uint32_t *ioSampleCount, BufferList *ioData );
00082   private:
00083     LoaderSourceCallback( Callback<T,U> *source, Target *target );
00084     Callback<T,U>                       * mSource;
00085     uint64_t                        mSampleOffset;
00086 
00087 #if defined(CINDER_COCOA)
00088     static void dataInputCallback( Loader* aLoader, uint32_t *ioSampleCount, BufferList *ioData, AudioStreamPacketDescription * packetDescriptions );
00089     shared_ptr<CocoaCaConverter>    mConverter;
00090 #endif  
00091 };
00092 
00093 template<typename T, typename U>
00094 Callback<T,U>::Callback( T* callbackObj, CallbackFunction callbackFn, bool ownCallbackObj, uint32_t aSampleRate, uint16_t aChannelCount )
00095     : Source(), mCallbackFn( callbackFn ), mCallbackObj( callbackObj ), mOwnsCallbackObj( ownCallbackObj )
00096 {
00097     mIsPcm = true;
00098     mSampleRate = aSampleRate;
00099     mChannelCount = aChannelCount;
00100     mIsInterleaved = true;
00101     mIsBigEndian = false;
00102     
00103     if( boost::is_same<U,uint8_t>::value ) {
00104         mDataType = Io::UINT8;
00105         mBitsPerSample = 8;
00106     } else if( boost::is_same<U,int8_t>::value ) {
00107         mDataType = Io::INT8;
00108         mBitsPerSample = 8;
00109     } else if( boost::is_same<U,uint16_t>::value ) {
00110         mDataType = Io::UINT16;
00111         mBitsPerSample = 16;
00112     } else if( boost::is_same<U,int16_t>::value ) {
00113         mDataType = Io::INT16;
00114         mBitsPerSample = 16;
00115     } else if( boost::is_same<U,uint32_t>::value ) {
00116         mDataType = Io::UINT32;
00117         mBitsPerSample = 32;
00118     } else if( boost::is_same<U,int32_t>::value ) {
00119         mDataType = Io::UINT32;
00120         mBitsPerSample = 32;
00121     } else if( boost::is_same<U,float>::value ) {
00122         mDataType = Io::FLOAT32;
00123         mBitsPerSample = 32;
00124     } else {
00125         throw IoExceptionUnsupportedDataType(); //This callback seems to be providing an unsupprted type of data
00126     }
00127     
00128     mBlockAlign = ( mBitsPerSample / 8 ) * mChannelCount;
00129 }
00130 
00131 template<typename T, typename U>
00132 Callback<T,U>::~Callback()
00133 {
00134     if( mOwnsCallbackObj ) {
00135         delete mCallbackObj;
00136     }
00137 }
00138 
00139 template<typename T, typename U>
00140 void Callback<T,U>::getData( uint64_t inSampleOffset, uint32_t ioSampleCount, Buffer *ioBuffer ) 
00141 {
00142     BufferT<U> typedBuffer;
00143     typedBuffer.mNumberChannels = ioBuffer->mNumberChannels;
00144     typedBuffer.mDataByteSize = ioBuffer->mDataByteSize;
00145     typedBuffer.mData = reinterpret_cast<U*>( ioBuffer->mData );
00146     
00147     ( mCallbackObj->*mCallbackFn )( inSampleOffset, ioSampleCount, &typedBuffer );
00148     
00149     ioBuffer->mNumberChannels = typedBuffer.mNumberChannels;
00150     ioBuffer->mDataByteSize = typedBuffer.mDataByteSize;
00151     ioBuffer->mData = reinterpret_cast<void*>( typedBuffer.mData );
00152 }
00153     
00154 template<typename T, typename U>
00155 LoaderSourceCallback<T,U>::LoaderSourceCallback( Callback<T,U> *source, Target *target )
00156     : mSource( source ), mSampleOffset( 0 )
00157 {
00158 #if defined( CINDER_COCOA )
00159     AudioStreamBasicDescription sourceDescription;
00160     
00161     sourceDescription.mFormatID = kAudioFormatLinearPCM; //kAudioFormatLinearPCM;
00162     sourceDescription.mFormatFlags = CalculateLPCMFlags( mSource->getBitsPerSample(), mSource->getBlockAlign() * 8, mSource->isFloat(), mSource->isBigEndian(), ( ! mSource->isInterleaved() ) /*is non interleaved*/ );
00163     sourceDescription.mSampleRate = source->getSampleRate();
00164     sourceDescription.mBytesPerPacket = ( mSource->getBlockAlign() ); //( mSource->getBitsPerSample() * mSource->getChannelCount() ) / 8;
00165     sourceDescription.mFramesPerPacket = 1;
00166     sourceDescription.mBytesPerFrame = ( mSource->getBlockAlign() );//( mSource->getBitsPerSample() * mSource->getChannelCount() ) / 8;
00167     sourceDescription.mChannelsPerFrame = source->getChannelCount();
00168     sourceDescription.mBitsPerChannel = source->getBitsPerSample();
00169     
00170     AudioStreamBasicDescription targetDescription;
00171     
00172     if( ! target->isPcm() ) {
00173         throw IoExceptionUnsupportedDataFormat();
00174     }
00175     
00176     targetDescription.mFormatID = kAudioFormatLinearPCM; //target->mNativeFormatId;
00177     targetDescription.mFormatFlags = CalculateLPCMFlags( target->getBitsPerSample(), target->getBlockAlign() * 8, target->isFloat(), target->isBigEndian(), ( ! target->isInterleaved() ) ); //target->mNativeFormatFlags
00178     targetDescription.mSampleRate = target->getSampleRate();
00179     targetDescription.mBytesPerPacket =  target->getBlockAlign(); //target->mBytesPerPacket;
00180     targetDescription.mFramesPerPacket = 1; //target->mFramesPerPacket;
00181     targetDescription.mBytesPerFrame = ( target->getBlockAlign() ); //target->mBytesPerFrame;
00182     targetDescription.mChannelsPerFrame = target->getChannelCount();
00183     targetDescription.mBitsPerChannel = target->getBitsPerSample();
00184     
00185     mConverter = shared_ptr<CocoaCaConverter>( new CocoaCaConverter( this, &LoaderSourceCallback<T,U>::dataInputCallback, sourceDescription, targetDescription, mSource->getBlockAlign() ) );
00186 #endif
00187 }
00188 
00189 template<typename T, typename U>
00190 void LoaderSourceCallback<T,U>::loadData( uint32_t *ioSampleCount, BufferList *ioData ) {   
00191 #if defined( CINDER_COCOA )
00192     mConverter->loadData( ioSampleCount, ioData );
00193     mSampleOffset += *ioSampleCount;
00194 #elif defined( CINDER_MSW )
00195     mSource->getData( mSampleOffset, *ioSampleCount, &ioData->mBuffers[0] );
00196     mSampleOffset += *ioSampleCount;
00197 #endif
00198 }   
00199 
00200 #if defined( CINDER_COCOA )
00201 template<typename T, typename U>
00202 void LoaderSourceCallback<T,U>::dataInputCallback( Loader* aLoader, uint32_t *ioSampleCount, BufferList *ioData, AudioStreamPacketDescription * packetDescriptions ) {
00203     LoaderSourceCallback * theLoader = dynamic_cast<LoaderSourceCallback *>( aLoader );
00204     Callback<T,U> * theSource = theLoader->mSource; 
00205     theSource->getData( theLoader->mSampleOffset, *ioSampleCount, &ioData->mBuffers[0] );
00206 }
00207 #endif
00208     
00209 
00210 }} //namespace