00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #pragma once
00024
00025 #include "cinder/Cinder.h"
00026 #include "cinder/audio/Io.h"
00027 #include "cinder/audio/PcmBuffer.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 createLoader( Target *target ) { return LoaderSourceCallback<T,U>::createRef( this, target ); }
00047 double getDuration() const { return 100.0; }
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, BufferGeneric *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 std::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 std::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 std::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 std::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( 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 std::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();
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, BufferGeneric *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;
00162 sourceDescription.mFormatFlags = CalculateLPCMFlags( mSource->getBitsPerSample(), mSource->getBlockAlign() * 8, mSource->isFloat(), mSource->isBigEndian(), ( ! mSource->isInterleaved() ) );
00163 sourceDescription.mSampleRate = source->getSampleRate();
00164 sourceDescription.mBytesPerPacket = ( mSource->getBlockAlign() );
00165 sourceDescription.mFramesPerPacket = 1;
00166 sourceDescription.mBytesPerFrame = ( mSource->getBlockAlign() );
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;
00177 targetDescription.mFormatFlags = CalculateLPCMFlags( target->getBitsPerSample(), target->getBlockAlign() * 8, target->isFloat(), target->isBigEndian(), ( ! target->isInterleaved() ) );
00178 targetDescription.mSampleRate = target->getSampleRate();
00179 targetDescription.mBytesPerPacket = target->getBlockAlign();
00180 targetDescription.mFramesPerPacket = 1;
00181 targetDescription.mBytesPerFrame = ( target->getBlockAlign() );
00182 targetDescription.mChannelsPerFrame = target->getChannelCount();
00183 targetDescription.mBitsPerChannel = target->getBitsPerSample();
00184
00185 mConverter = std::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( BufferList *ioData ) {
00191 #if defined( CINDER_COCOA )
00192 mConverter->loadData( ioData );
00193 mSampleOffset += ioData->mBuffers[0].mSampleCount;
00194 #elif defined( CINDER_MSW )
00195 mSource->getData( mSampleOffset, ioData->mBuffers[0].mSampleCount, &ioData->mBuffers[0] );
00196 mSampleOffset += ioData->mBuffers[0].mSampleCount;
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 }}