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