00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "AudioDevice.hxx"
00023 #include "AudioDeviceList.hxx"
00024 #include "RtAudio.h"
00025 #include "RtAudioUtils.hxx"
00026
00027 #include "CLAM_windows.h"
00028 #undef GetClassName
00029 #include <iostream>
00030
00031 using std::cout;
00032 using std::endl;
00033
00034 namespace CLAM
00035 {
00036
00037 class RtAAudioDevice : public AudioDevice
00038 {
00039 enum IOModalities
00040 {
00041 eFullDuplex=0,
00042 eHalfDuplexIn,
00043 eHalfDuplexOut,
00044 eNoneYet
00045 };
00046
00047 public:
00048
00049 RtAAudioDevice( const std::string& str, int devID );
00050 ~RtAAudioDevice( );
00051
00052 void Start() throw( ErrRtAudio );
00053 void Stop() throw ( ErrRtAudio );
00054 void Read( Audio& samples, const int channelID );
00055 void Write( const Audio& samples, const int channelID );
00056
00057 virtual void GetInfo( AudioDevice::TInfo& );
00058
00059 protected:
00060
00061 void SetupMonoOutputStream() throw( ErrRtAudio );
00062 void SetupStereoOutputStream() throw( ErrRtAudio );
00063 void SetupMultiOutputStream() throw( ErrRtAudio );
00064 void SetupMonoInputStream() throw( ErrRtAudio );
00065 void SetupStereoInputStream() throw( ErrRtAudio );
00066 void SetupMultiInputStream() throw( ErrRtAudio );
00067 void SetupStereoFullDuplexStream() throw( ErrRtAudio );
00068
00069 private:
00070
00071 unsigned mNChannelsWritten;
00072 bool mChannelsWritten[256];
00073
00074 unsigned mNChannelsRead;
00075 bool mChannelsRead[256];
00076
00077 int mFramesPerBuffer;
00078
00079 int mDevID;
00080
00081 short* mInputSamples;
00082 short* mOutputSamples;
00083
00084 int mInputStreamId;
00085 int mOutputStreamId;
00086
00087 IOModalities mIOModel;
00088 RtAudio* mDevice;
00089
00090 bool mStarted;
00091 };
00092
00093
00094 class RtAAudioDeviceList : public AudioDeviceList
00095 {
00096 private:
00097 static RtAAudioDeviceList sDevices;
00098
00099 RtAAudioDeviceList();
00100
00101 std::vector< int > mDevIDs;
00102
00103 protected:
00104
00105 void EnumerateAvailableDevices() throw ( ErrRtAudio );
00106
00107 public:
00108
00109 virtual ~RtAAudioDeviceList();
00110
00111 inline std::string DefaultDevice()
00112 {
00113 return mAvailableDevices[0];
00114 }
00115
00116 AudioDevice* Create( const std::string& name, const std::string& device );
00117
00118 };
00119
00120 RtAAudioDevice::RtAAudioDevice( const std::string& name, int devID )
00121 : AudioDevice(name), mDevID( devID ),
00122 mIOModel( eNoneYet ),mStarted(false), mDevice( NULL ),
00123 mInputSamples( NULL ), mOutputSamples( NULL ), mInputStreamId( -1 ), mOutputStreamId( -1)
00124 {
00125
00126
00127 int i;
00128
00129 mNChannelsWritten = 0;
00130 for (i=0;i<256;i++)
00131 {
00132 mChannelsWritten[i] = false;
00133 }
00134
00135 mNChannelsRead = 0;
00136 for (i=0;i<256;i++)
00137 {
00138 mChannelsRead[i] = false;
00139 }
00140
00141 }
00142
00143 RtAAudioDevice::~RtAAudioDevice( )
00144 {
00145 if ( mDevice )
00146 delete mDevice;
00147 }
00148
00149 void RtAAudioDevice::Start() throw( ErrRtAudio )
00150 {
00151 if ( mStarted )
00152 return;
00153
00154 unsigned outChannels = mOutputs.size();
00155 unsigned inChannels = mInputs.size();
00156
00157 try
00158 {
00159
00160 if ( (outChannels > 0) && (inChannels > 0) && (outChannels==inChannels) )
00161 {
00162
00163
00164 mIOModel = eFullDuplex;
00165 mNChannels = outChannels;
00166 mFramesPerBuffer = Latency();
00167
00168 mDevice = new RtAudio();
00169 mOutputStreamId= mDevice->openStream( mDevID,mNChannels, 0, 0,
00170 RtAudio::RTAUDIO_SINT16, SampleRate(), &mFramesPerBuffer, NumberOfInternalBuffers() );
00171 mInputStreamId= mDevice->openStream( 0, 0, mDevID, mNChannels, RtAudio::RTAUDIO_SINT16,
00172 SampleRate(), &mFramesPerBuffer, NumberOfInternalBuffers() );
00173
00174 mOutputSamples = (short*) mDevice->getStreamBuffer( mOutputStreamId );
00175 mDevice->startStream( mOutputStreamId );
00176 mInputSamples = (short*) mDevice->getStreamBuffer( mInputStreamId );
00177 mDevice->startStream( mInputStreamId );
00178
00179 }
00180
00181 else if ( (inChannels == 0) && (outChannels > 0))
00182 {
00183 mIOModel = eHalfDuplexOut;
00184 mNChannels = outChannels;
00185
00186 mFramesPerBuffer = Latency();
00187 mDevice = new RtAudio();
00188 mOutputStreamId= mDevice->openStream( mDevID,mNChannels, 0, 0,
00189 RtAudio::RTAUDIO_SINT16, SampleRate(), &mFramesPerBuffer, NumberOfInternalBuffers() );
00190 mOutputSamples = (short*) mDevice->getStreamBuffer( mOutputStreamId );
00191 mDevice->startStream( mOutputStreamId );
00192
00193 }
00194
00195 else if ( (outChannels == 0) && (inChannels > 0))
00196 {
00197 mIOModel = eHalfDuplexIn;
00198
00199 mNChannels = inChannels;
00200 mFramesPerBuffer = Latency();
00201 mDevice = new RtAudio();
00202 mInputStreamId= mDevice->openStream( 0, 0, mDevID, mNChannels, RtAudio::RTAUDIO_SINT16,
00203 SampleRate(), &mFramesPerBuffer, NumberOfInternalBuffers());
00204 mInputSamples = (short*) mDevice->getStreamBuffer( mInputStreamId );
00205 mDevice->startStream( mInputStreamId );
00206
00207 }
00208 else
00209 {
00210
00211 CLAM_ASSERT( false, "Check the number of AudioIn's and AudioOut's in your system.\n"
00212 "I have detected a input output mismatch( either you have none input and some outputs or\n"
00213 " some input or none output or just the same number of inputs and outputs)");
00214 }
00215 mStarted = true;
00216 }
00217 catch( RtError& e )
00218 {
00219 ErrRtAudio new_e( e );
00220 throw ( new_e );
00221 }
00222 }
00223
00224 void RtAAudioDevice::Stop() throw( ErrRtAudio )
00225 {
00226 switch ( mIOModel )
00227 {
00228 case eFullDuplex:
00229 mDevice->stopStream( mOutputStreamId );
00230 mDevice->stopStream( mInputStreamId );
00231 mDevice->closeStream( mOutputStreamId );
00232 mDevice->closeStream( mInputStreamId );
00233 delete mDevice;
00234 mDevice=NULL;
00235 mInputSamples = NULL;
00236 mOutputSamples = NULL;
00237 mOutputStreamId = -1;
00238 mInputStreamId = -1;
00239 break;
00240 case eHalfDuplexIn:
00241 mDevice->stopStream( mInputStreamId );
00242 mDevice->closeStream( mInputStreamId );
00243 delete mDevice;
00244 mDevice=NULL;
00245 mInputSamples = NULL;
00246 mInputStreamId = -1;
00247 break;
00248 case eHalfDuplexOut:
00249 mDevice->stopStream( mOutputStreamId );
00250 mDevice->closeStream( mOutputStreamId );
00251 delete mDevice;
00252 mDevice=NULL;
00253 mOutputSamples = NULL;
00254 mOutputStreamId = -1;
00255 break;
00256 case eNoneYet:
00257 CLAM_ASSERT( false, "You cannot stop what hasn't been started" );
00258 break;
00259 }
00260 mStarted = false;
00261 }
00262
00263 void RtAAudioDevice::GetInfo( AudioDevice::TInfo& nfo )
00264 {
00265 AudioDevice::GetInfo( nfo );
00266 }
00267
00268 void RtAAudioDevice::Read( Audio& samples, const int channelID )
00269 {
00270 TData* dst = samples.GetBuffer().GetPtr();
00271 short* src = NULL;
00272 unsigned samples_to_read = mFramesPerBuffer;
00273
00274
00275 CLAM_ASSERT( mInputStreamId!=-1, "No Input stream over the device has been created yet!" );
00276 CLAM_ASSERT( samples_to_read == samples.GetSize(), "Inconsistent Audio size" );
00277
00278 static TData inv_2_15 = 1 / TData(32767.);
00279
00280 src = mInputSamples + channelID;
00281
00282 while ( samples_to_read-- )
00283 {
00284 *dst++ = TData(*src)*inv_2_15;
00285 src+=mNChannels;
00286 }
00287
00288
00289 mChannelsRead[channelID] = true;
00290 mNChannelsRead++;
00291
00292 if (mNChannelsRead==mNChannels)
00293 {
00294 mNChannelsRead = 0;
00295 for (int i=0;i<mNChannels;i++)
00296 mChannelsRead[i] = false;
00297 mDevice->tickStream( mInputStreamId );
00298 }
00299
00300
00301 }
00302
00303 void RtAAudioDevice::Write( const Audio& samples, const int channelID )
00304 {
00305 unsigned samples_to_write = mFramesPerBuffer;
00306
00307 CLAM_ASSERT( mOutputStreamId!=-1, "No Output stream over the device has been created yet!" );
00308 CLAM_ASSERT( samples_to_write == samples.GetSize(), "Inconsistent Audio size" );
00309
00310 short* dst = mOutputSamples + channelID;
00311 TData* src = samples.GetBuffer().GetPtr();
00312
00313 while ( samples_to_write-- )
00314 {
00315 *dst = (short) ( 32767. * (*src++));
00316 dst+=mNChannels;
00317 }
00318 mChannelsWritten[channelID] = true;
00319 mNChannelsWritten++;
00320
00321 if (mNChannelsWritten==mNChannels)
00322 {
00323
00324
00325 mNChannelsWritten = 0;
00326 for (int i=0;i<mNChannels;i++)
00327 mChannelsWritten[i] = false;
00328
00329 mDevice->tickStream( mOutputStreamId );
00330 }
00331
00332
00333 }
00334
00335 RtAAudioDeviceList::RtAAudioDeviceList()
00336 : AudioDeviceList( std::string("rtaudio") )
00337 {
00338
00339 EnumerateAvailableDevices();
00340
00341 AddMe();
00342 }
00343
00344 RtAAudioDeviceList::~RtAAudioDeviceList()
00345 {
00346 }
00347
00348 void RtAAudioDeviceList::EnumerateAvailableDevices() throw ( ErrRtAudio )
00349 {
00350 RtAudio* instance = NULL;
00351
00352 try
00353 {
00354 instance = new RtAudio();
00355
00356 int numDevs = instance->getDeviceCount();
00357 int k = 0;
00358 RtAudio::RTAUDIO_DEVICE devnfo;
00359
00360 for ( k = 0; k < numDevs; k++ )
00361 {
00362 instance->getDeviceInfo( k, &devnfo );
00363 mAvailableDevices.push_back( devnfo.name );
00364 mDevIDs.push_back( k );
00365 }
00366 delete instance;
00367 }
00368 catch( RtError& err )
00369 {
00370 if ( instance )
00371 delete instance;
00372 ErrRtAudio new_err( err );
00373 throw ( new_err );
00374 }
00375
00376 }
00377
00378 AudioDevice* RtAAudioDeviceList::Create( const std::string& name, const std::string& device )
00379 {
00380 int i = 0;
00381
00382 for ( i=0; i < mAvailableDevices.size(); i++ )
00383 {
00384 if ( device == mAvailableDevices[i] )
00385 return new RtAAudioDevice( name, mDevIDs[i] );
00386 }
00387
00388 return 0;
00389 }
00390
00391 RtAAudioDeviceList RtAAudioDeviceList::sDevices;
00392
00393 }
00394