00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "PACLAMCallbacks.hxx"
00023 #include "CLAM_windows.h"
00024 #undef GetClassName
00025 #include <iostream>
00026 using std::cout;
00027 using std::endl;
00028
00029 #include "AudioIO.hxx"
00030 #include "AudioDevice.hxx"
00031 #include "AudioDeviceList.hxx"
00032 #include <portaudio.h>
00033 #include "PortAudioUtils.hxx"
00034 #include "PAAudioInputStream.hxx"
00035 #include "PAAudioOutputStream.hxx"
00036 #include "PAAudioFullDuplexStream.hxx"
00037
00038 #include "DoubleBuffer.hxx"
00039
00040 namespace CLAM
00041 {
00042
00043 class PAAudioDevice : public AudioDevice
00044 {
00045 enum IOModalities
00046 {
00047 eFullDuplex=0,
00048 eHalfDuplexIn,
00049 eHalfDuplexOut,
00050 eNoneYet
00051 };
00052
00053 public:
00054
00055 PAAudioDevice( const std::string& str, PaDeviceIndex devID );
00056 ~PAAudioDevice( );
00057
00058 void Start() throw( ErrPortAudio );
00059 void Stop() throw ( ErrPortAudio );
00060 void Read( Audio& samples, const int channelID );
00061 void Write( const Audio& samples, const int channelID );
00062
00063 virtual void GetInfo( AudioDevice::TInfo& );
00064
00065 protected:
00066
00067 void SetupMonoOutputStream() throw( ErrPortAudio );
00068 void SetupStereoOutputStream() throw( ErrPortAudio );
00069 void SetupMultiOutputStream() throw( ErrPortAudio );
00070 void SetupMonoInputStream() throw( ErrPortAudio );
00071 void SetupStereoInputStream() throw( ErrPortAudio );
00072 void SetupMultiInputStream() throw( ErrPortAudio );
00073 void SetupStereoFullDuplexStream() throw( ErrPortAudio );
00074
00075 private:
00076
00077 unsigned mNChannelsWritten;
00078 bool mChannelsWritten[256];
00079
00080 unsigned mNChannelsRead;
00081 bool mChannelsRead[256];
00082
00083 unsigned mWriteBuffSize;
00084 unsigned mReadBuffSize;
00085
00086 PaDeviceIndex mDevID;
00087
00088 DoubleBuffer mInputIntBuffer;
00089 DoubleBuffer mOutputIntBuffer;
00090
00091 PAAudioInputStream* mInStream;
00092 PAAudioOutputStream* mOutStream;
00093 PAAudioFullDuplexStream* mFullDuplexStream;
00094
00095 IOModalities mIOModel ;
00096
00097 bool mStarted;
00098 };
00099
00100
00101 class PAAudioDeviceList : public AudioDeviceList
00102 {
00103 private:
00104 static PAAudioDeviceList mDevices;
00105
00106 PAAudioDeviceList();
00107
00108 std::vector< PaDeviceIndex > mDevIDs;
00109
00110 protected:
00111
00112 void EnumerateAvailableDevices();
00113
00114 public:
00115
00116 virtual ~PAAudioDeviceList();
00117
00118 inline std::string DefaultDevice()
00119 {
00120 return mAvailableDevices[0];
00121 }
00122
00123 AudioDevice* Create( const std::string& name, const std::string& device );
00124
00125 };
00126
00127 PAAudioDevice::PAAudioDevice( const std::string& name, PaDeviceIndex devID )
00128 : AudioDevice(name), mDevID( devID ),
00129 mInStream( NULL ), mOutStream( NULL ), mIOModel( eNoneYet ),mStarted(false)
00130 {
00131
00132
00133 int i;
00134
00135 mNChannelsWritten = 0;
00136 for (i=0;i<256;i++)
00137 {
00138 mChannelsWritten[i] = false;
00139 }
00140
00141 mNChannelsRead = 0;
00142 for (i=0;i<256;i++)
00143 {
00144 mChannelsRead[i] = false;
00145 }
00146
00147 }
00148
00149 PAAudioDevice::~PAAudioDevice( )
00150 {
00151 mInputIntBuffer.DeAllocate();
00152 mOutputIntBuffer.DeAllocate();
00153
00154 if ( mInStream )
00155 delete mInStream;
00156
00157 if ( mOutStream )
00158 delete mOutStream;
00159
00160 if ( mFullDuplexStream )
00161 delete mFullDuplexStream;
00162 }
00163
00164 void PAAudioDevice::Start() throw( Err )
00165 {
00166 if ( mStarted && (((mInputs.size() | mOutputs.size()) != mNChannels) ||
00167 (mInputIntBuffer.GetSize() != mInputs.size()*Latency()) ||
00168 (mOutputIntBuffer.GetSize() != mOutputs.size()*Latency())))
00169 {
00170 switch ( mIOModel )
00171 {
00172 case eFullDuplex:
00173 mFullDuplexStream->Stop();
00174 delete mFullDuplexStream;
00175 break;
00176 case eHalfDuplexIn:
00177 mInStream->Stop();
00178 delete mInStream;
00179 break;
00180 case eHalfDuplexOut:
00181 mOutStream->Stop();
00182 delete mOutStream;
00183 break;
00184 case eNoneYet:
00185 CLAM_ASSERT( false, "You cannot stop what hasn't been started" );
00186 break;
00187 }
00188 mStarted = false;
00189 }
00190
00191 if ( mStarted )
00192 return;
00193
00194 unsigned outChannels = mOutputs.size();
00195 unsigned inChannels = mInputs.size();
00196
00197 try
00198 {
00199
00200 if ( (outChannels > 0) && (inChannels > 0) && (outChannels==inChannels) )
00201 {
00202
00203
00204 mIOModel = eFullDuplex;
00205 mNChannels = outChannels;
00206 switch ( outChannels )
00207 {
00208 case 1:
00209 break;
00210 case 2:
00211 SetupStereoFullDuplexStream();
00212 break;
00213 default:
00214 break;
00215 };
00216
00217 mFullDuplexStream->Start();
00218 }
00219
00220 else if ( (inChannels == 0) && (outChannels > 0))
00221 {
00222 mIOModel = eHalfDuplexOut;
00223 mNChannels = outChannels;
00224
00225 switch ( outChannels )
00226 {
00227 case 1:
00228 SetupMonoOutputStream();
00229 break;
00230 case 2:
00231 SetupStereoOutputStream();
00232 break;
00233 default:
00234 SetupMultiOutputStream();
00235 break;
00236 };
00237
00238 mOutStream->Start();
00239 }
00240
00241 else if ( (outChannels == 0) && (inChannels > 0))
00242 {
00243 mIOModel = eHalfDuplexIn;
00244
00245 mNChannels = inChannels;
00246 switch( inChannels )
00247 {
00248 case 1:
00249 SetupMonoInputStream();
00250 break;
00251 case 2:
00252 SetupStereoInputStream();
00253 break;
00254 default:
00255 SetupMultiInputStream();
00256 break;
00257 };
00258 mInStream->Start();
00259 }
00260 else
00261 {
00262
00263 CLAM_ASSERT( false, "Check the number of AudioIn's and AudioOut's in your system.\n"
00264 "I have detected a input output mismatch( either you have none input and some outputs or\n"
00265 " some input or none output or just the same number of inputs and outputs)");
00266 }
00267 mStarted = true;
00268 }
00269 catch( Err& e )
00270 {
00271 ErrPortAudio new_e( "Error Starting PortAudio Device:\n" );
00272 new_e.Embed( e );
00273 throw ( new_e );
00274 }
00275 }
00276
00277 void PAAudioDevice::SetupMonoOutputStream() throw ( ErrPortAudio )
00278 {
00279 PAAudioStreamConfig cfg;
00280 cfg.SetSampleRate( SampleRate() );
00281 cfg.SetChannelNumber( 1 );
00282 cfg.SetCallback( monoOutCallback );
00283 cfg.SetDeviceID( mDevID );
00284 mOutputIntBuffer.DeAllocate();
00285 mOutputIntBuffer.Allocate( Latency() );
00286 cfg.SetOutputDblBuffer( &mOutputIntBuffer);
00287
00288 mOutStream = new PAAudioOutputStream( cfg );
00289
00290 }
00291
00292 void PAAudioDevice::SetupStereoOutputStream() throw ( ErrPortAudio )
00293 {
00294 PAAudioStreamConfig cfg;
00295 cfg.SetSampleRate( SampleRate() );
00296 cfg.SetChannelNumber( 2 );
00297 cfg.SetCallback( stereoOutCallback );
00298 cfg.SetDeviceID( mDevID );
00299 mOutputIntBuffer.DeAllocate();
00300 mOutputIntBuffer.Allocate( 2 * Latency() );
00301 cfg.SetOutputDblBuffer( &mOutputIntBuffer);
00302
00303 mOutStream = new PAAudioOutputStream( cfg );
00304
00305 }
00306
00307 void PAAudioDevice::SetupMultiOutputStream() throw( ErrPortAudio )
00308 {
00309 PAAudioStreamConfig cfg;
00310 cfg.SetSampleRate( SampleRate() );
00311 cfg.SetChannelNumber( mNChannels );
00312 cfg.SetCallback( multiOutCallback );
00313 cfg.SetDeviceID( mDevID );
00314 mOutputIntBuffer.DeAllocate();
00315 mOutputIntBuffer.Allocate( mNChannels * Latency() );
00316 cfg.SetOutputDblBuffer( &mOutputIntBuffer);
00317
00318 mOutStream = new PAAudioOutputStream( cfg );
00319
00320 }
00321
00322 void PAAudioDevice::SetupMonoInputStream() throw ( ErrPortAudio )
00323 {
00324 PAAudioStreamConfig cfg;
00325 cfg.SetSampleRate( SampleRate() );
00326 cfg.SetChannelNumber( 1 );
00327 cfg.SetCallback( monoInCallback );
00328 cfg.SetDeviceID( mDevID );
00329 mInputIntBuffer.DeAllocate();
00330 mInputIntBuffer.Allocate( Latency() );
00331 cfg.SetInputDblBuffer( &mInputIntBuffer);
00332
00333 mInStream = new PAAudioInputStream( cfg );
00334
00335 }
00336
00337 void PAAudioDevice::SetupStereoInputStream() throw ( ErrPortAudio )
00338 {
00339 PAAudioStreamConfig cfg;
00340 cfg.SetSampleRate( SampleRate() );
00341 cfg.SetChannelNumber( 2 );
00342 cfg.SetCallback( stereoInCallback );
00343 cfg.SetDeviceID( mDevID );
00344 mInputIntBuffer.DeAllocate();
00345 mInputIntBuffer.Allocate( 2*Latency() );
00346 cfg.SetInputDblBuffer( &mInputIntBuffer);
00347
00348 mInStream = new PAAudioInputStream( cfg );
00349
00350 }
00351
00352 void PAAudioDevice::SetupMultiInputStream() throw ( ErrPortAudio )
00353 {
00354 PAAudioStreamConfig cfg;
00355 cfg.SetSampleRate( SampleRate() );
00356 cfg.SetChannelNumber( mInputs.size() );
00357 cfg.SetCallback( multiInCallback );
00358 cfg.SetDeviceID( mDevID );
00359 mInputIntBuffer.DeAllocate();
00360 mInputIntBuffer.Allocate( mInputs.size()*Latency() );
00361 cfg.SetInputDblBuffer( &mInputIntBuffer);
00362
00363 mInStream = new PAAudioInputStream( cfg );
00364
00365 }
00366
00367 void PAAudioDevice::SetupStereoFullDuplexStream() throw ( ErrPortAudio )
00368 {
00369 PAAudioStreamConfig cfg;
00370 cfg.SetSampleRate( SampleRate() );
00371 cfg.SetChannelNumber( mNChannels );
00372 cfg.SetCallback( stereoFDCallback );
00373 cfg.SetDeviceID( mDevID );
00374 mInputIntBuffer.DeAllocate();
00375 mOutputIntBuffer.DeAllocate();
00376 mInputIntBuffer.Allocate( 2*Latency() );
00377 mOutputIntBuffer.Allocate( 2*Latency() );
00378 cfg.SetInputDblBuffer( &mInputIntBuffer);
00379 cfg.SetOutputDblBuffer( &mOutputIntBuffer );
00380
00381 mFullDuplexStream = new PAAudioFullDuplexStream( cfg );
00382
00383 }
00384
00385
00386 void PAAudioDevice::Stop() throw( ErrPortAudio )
00387 {
00388 switch ( mIOModel )
00389 {
00390 case eFullDuplex:
00391 mFullDuplexStream->Stop();
00392 break;
00393 case eHalfDuplexIn:
00394 mInStream->Stop();
00395 break;
00396 case eHalfDuplexOut:
00397 mOutStream->Stop();
00398 break;
00399 case eNoneYet:
00400 CLAM_ASSERT( false, "You cannot stop what hasn't been started" );
00401 break;
00402 }
00403 mStarted = false;
00404 }
00405
00406 void PAAudioDevice::GetInfo( AudioDevice::TInfo& nfo )
00407 {
00408 AudioDevice::GetInfo( nfo );
00409 }
00410
00411 void PAAudioDevice::Read( Audio& samples, const int channelID )
00412 {
00413 TData* dst = samples.GetBuffer().GetPtr();
00414 short* src = NULL;
00415 unsigned samples_to_read = (mInputIntBuffer.GetSize()/mInputs.size());
00416
00417
00418 CLAM_ASSERT( !mChannelsRead[channelID], "Tried to read twice from the same channel in single time frame!" );
00419 CLAM_ASSERT( mInStream || mFullDuplexStream, "No Input stream over the device has been created yet!" );
00420 CLAM_ASSERT( samples_to_read == samples.GetSize(), "Inconsistent Audio size" );
00421
00422 static TData inv_2_15 = 1 / TData(32767.);
00423
00424 WaitForSingleObject( mInputIntBuffer.mBackBufferReady, INFINITE );
00425
00426 src = mInputIntBuffer.mBackBuffer + channelID;
00427
00428 while ( samples_to_read-- )
00429 {
00430 *dst++ = TData(*src)*inv_2_15;
00431 src+=mNChannels;
00432 }
00433 mChannelsRead[channelID] = true;
00434 mNChannelsRead++;
00435
00436 if (mNChannelsRead==mInputs.size())
00437 {
00438 mNChannelsRead = 0;
00439
00440
00441 std::fill(mChannelsRead, mChannelsRead + mInputs.size(), false);
00442 ResetEvent( mInputIntBuffer.mBackBufferReady );
00443 }
00444
00445
00446 }
00447
00448 void PAAudioDevice::Write( const Audio& samples, const int channelID )
00449 {
00450 unsigned samples_to_write = (mOutputIntBuffer.GetSize()/mNChannels);
00451
00452 CLAM_ASSERT( !mChannelsWritten[channelID], "Tried to read twice from the same channel in single time frame!" );
00453 CLAM_ASSERT( mOutStream || mFullDuplexStream, "No Input stream over the device has been created yet!" );
00454 CLAM_ASSERT( samples_to_write == samples.GetSize(), "Inconsistent Audio size" );
00455
00456 short* dst = mOutputIntBuffer.mFrontBuffer + channelID;
00457 TData* src = samples.GetBuffer().GetPtr();
00458
00459 while ( samples_to_write-- )
00460 {
00461 *dst = (short) ( 32767. * (*src++));
00462 dst+=mNChannels;
00463 }
00464 mChannelsWritten[channelID] = true;
00465 mNChannelsWritten++;
00466
00467 if (mNChannelsWritten==mOutputs.size())
00468 {
00469
00470
00471 mNChannelsWritten = 0;
00472
00473
00474 std::fill(mChannelsWritten, mChannelsWritten + mOutputs.size(), false);
00475
00476 mOutputIntBuffer.SwapBuffers();
00477 }
00478
00479
00480 }
00481
00482 PAAudioDeviceList::PAAudioDeviceList()
00483 : AudioDeviceList( std::string("portaudio") )
00484 {
00485 Pa_Initialize();
00486
00487 EnumerateAvailableDevices();
00488
00489 AddMe();
00490 }
00491
00492 PAAudioDeviceList::~PAAudioDeviceList()
00493 {
00494 Pa_Terminate();
00495 }
00496
00497 void PAAudioDeviceList::EnumerateAvailableDevices()
00498 {
00499 int numDevs = Pa_GetDeviceCount();
00500 int k = 0;
00501 const PaDeviceInfo* devnfo = NULL;
00502
00503 for ( k = 0; k < numDevs; k++ )
00504 {
00505 devnfo = Pa_GetDeviceInfo( k );
00506 mAvailableDevices.push_back( devnfo->name );
00507 mDevIDs.push_back( k );
00508 }
00509
00510 }
00511
00512 AudioDevice* PAAudioDeviceList::Create( const std::string& name, const std::string& device )
00513 {
00514 int i = 0;
00515
00516 for ( i=0; i < mAvailableDevices.size(); i++ )
00517 {
00518 if ( device == mAvailableDevices[i] )
00519 return new PAAudioDevice( name, mDevIDs[i] );
00520 }
00521
00522 return 0;
00523 }
00524
00525 PAAudioDeviceList PAAudioDeviceList::mDevices;
00526 }
00527