CLAM-Development
1.1
|
00001 /* 00002 * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) 00003 * UNIVERSITAT POMPEU FABRA 00004 * 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 // MRJ: Read/Written Channel Masks initialization 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 // Check for Full Duplex I/O 00160 if ( (outChannels > 0) && (inChannels > 0) && (outChannels==inChannels) ) 00161 { 00162 // both outChannels and inChannels have the same value 00163 // and are above zero 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 // Check for Half Duplex Ouput 00181 else if ( (inChannels == 0) && (outChannels > 0)) 00182 { 00183 mIOModel = eHalfDuplexOut; 00184 mNChannels = outChannels; 00185 // depending on outChannels value 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 // Check for Half Duplex Input 00195 else if ( (outChannels == 0) && (inChannels > 0)) 00196 { 00197 mIOModel = eHalfDuplexIn; 00198 // depending on the value of inChannels 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 // Error. None of the supported I/O modalities. 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 // Some error checking - proof of concepts 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