CLAM-Development
1.1
|
00001 /* 00002 * Copyright (c) 2001-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 #include "RtAAudioDevice.hxx" 00022 00023 /* 00024 #include "RtAudio.hxx" 00025 #include "AudioIO.hxx" 00026 #include "AudioIn.hxx" 00027 #include "AudioOut.hxx" 00028 #include "AudioDeviceList.hxx" 00029 #include "AudioDevice.hxx" 00030 #include <cstdio> 00031 */ 00032 00033 namespace CLAM { 00034 /* 00035 #ifdef __MACOSX_CORE__ 00036 #define MACOSX_WORKAROUND 00037 #endif 00038 */ 00039 00040 //#ifdef __MACOSX_CORE__ 00041 /* a kludgy factor 2 (22050->44100) sample rate conversion 00042 ** because macosx drivers do not handle 22050 */ 00043 /* 00044 #define FACTOR2SRC_KLUDGE 00045 #endif 00046 */ 00047 00048 //#define DEBUG_RDWR_POS 00049 00050 00051 /* 00052 typedef signed short MY_TYPE; 00053 #define FORMAT RtAudio::RTAUDIO_SINT16 00054 class RtAAudioDevice: public AudioDevice 00055 { 00056 private: 00057 class Buffer 00058 { 00059 friend class RtAAudioDevice; 00060 private: 00061 Buffer(int channels = 0,int frames = 0) 00062 { 00063 mData = 0; 00064 Alloc(channels,frames); 00065 mChannelsDone = 0; 00066 mReadIndex = 0; 00067 mWriteIndex = 0; 00068 } 00069 void Alloc(int channels = 0,int frames = 0) 00070 { 00071 if (mData) delete mData; 00072 mChannels = channels; 00073 mFrames = frames; 00074 if (mChannels && mFrames) 00075 { 00076 mData = new TData[mChannels*mFrames]; 00077 }else{ 00078 mData = 0; 00079 } 00080 } 00081 00082 TData* mData; 00083 int mReadIndex; 00084 int mWriteIndex; 00085 int mChannels; 00086 int mChannelsDone; 00087 int mFrames; 00088 int Filled(void) 00089 { 00090 return mWriteIndex >= mReadIndex ? 00091 mWriteIndex - mReadIndex : 00092 mWriteIndex + mFrames - mReadIndex; 00093 } 00094 00095 void CopyTo(MY_TYPE* ptr,int frames) 00096 { 00097 int cnt = frames*mChannels; 00098 int limit = mFrames*mChannels; 00099 int i = mReadIndex*mChannels; 00100 00101 #ifdef DEBUG_RDWR_POS 00102 printf("copyto: r=%d %d\n",mReadIndex,frames); 00103 #endif 00104 while (cnt--) 00105 { 00106 *ptr++ = (MY_TYPE)(mData[i++]*32767.); 00107 if (i==limit) i = 0; 00108 } 00109 mReadIndex += frames; 00110 if (mReadIndex >= mFrames) mReadIndex -= mFrames; 00111 00112 } 00113 00114 #ifdef FACTOR2SRC_KLUDGE 00115 void CopyToFactor2SRC(MY_TYPE* ptr,int frames) 00116 { 00117 int cnt = frames*mChannels; 00118 int limit = mFrames*mChannels; 00119 int i = mReadIndex*mChannels; 00120 00121 #ifdef DEBUG_RDWR_POS 00122 printf("copyto: r=%d %d\n",mReadIndex,frames); 00123 #endif 00124 while (cnt--) 00125 { 00126 *ptr++ = (MY_TYPE)(mData[i]*32767.); 00127 *ptr++ = (MY_TYPE)(mData[i]*32767.); 00128 i++; 00129 if (i==limit) i = 0; 00130 } 00131 mReadIndex += frames; 00132 if (mReadIndex >= mFrames) mReadIndex -= mFrames; 00133 00134 } 00135 #endif 00136 00137 void CopyFrom(MY_TYPE* ptr,int frames) 00138 { 00139 int cnt = frames*mChannels; 00140 int limit = mFrames*mChannels; 00141 int i = mWriteIndex*mChannels; 00142 00143 #ifdef DEBUG_RDWR_POS 00144 printf("copyfrom: w=%d %d\n",mWriteIndex,frames); 00145 #endif 00146 while (cnt--) 00147 { 00148 mData[i++] = TData(*ptr++)/32767.; 00149 if (i==limit) i = 0; 00150 } 00151 mWriteIndex += frames; 00152 if (mWriteIndex >= mFrames) mWriteIndex -= mFrames; 00153 } 00154 00155 #ifdef FACTOR2SRC_KLUDGE 00156 void CopyFromDoFactor2SRC(MY_TYPE* ptr,int frames) 00157 { 00158 int cnt = frames*mChannels; 00159 int limit = mFrames*mChannels; 00160 int i = mWriteIndex*mChannels; 00161 00162 #ifdef DEBUG_RDWR_POS 00163 printf("copyfrom: w=%d %d\n",mWriteIndex,frames); 00164 #endif 00165 while (cnt--) 00166 { 00167 TData t = TData(*ptr++); 00168 t += TData(*ptr++); 00169 t /= 65534.; 00170 mData[i++] = t; 00171 if (i==limit) i = 0; 00172 } 00173 mWriteIndex += frames; 00174 if (mWriteIndex >= mFrames) mWriteIndex -= mFrames; 00175 } 00176 #endif 00177 00178 void ChannelCopyFrom(TData* ptr,int size,int chnId) 00179 { 00180 int i = mWriteIndex*mChannels+chnId; 00181 int n = size; 00182 int limit = mChannels*mFrames; 00183 00184 #ifdef DEBUG_RDWR_POS 00185 printf("ChannelCopyFrom: w=%d %d\n",mWriteIndex,size); 00186 #endif 00187 fflush(stdout); 00188 while (n--) 00189 { 00190 mData[i] = *ptr++; 00191 i += mChannels; 00192 if (i>=limit) i = chnId; 00193 } 00194 mChannelsDone++; 00195 if (mChannelsDone==mChannels) 00196 { 00197 mWriteIndex += size; 00198 if (mWriteIndex >= mFrames) mWriteIndex -= mFrames; 00199 mChannelsDone = 0; 00200 } 00201 } 00202 00203 void ChannelCopyTo(TData* ptr,int size,int chnId) 00204 { 00205 int i = mReadIndex*mChannels+chnId; 00206 int n = size; 00207 int limit = mChannels*mFrames; 00208 00209 #ifdef DEBUG_RDWR_POS 00210 printf("ChannelCopyTo: r=%d %d\n",mReadIndex,size); 00211 #endif 00212 while (n--) 00213 { 00214 *ptr++ = mData[i]; 00215 i += mChannels; 00216 if (i>=limit) i = chnId; 00217 } 00218 mChannelsDone++; 00219 if (mChannelsDone==mChannels) 00220 { 00221 mReadIndex += size; 00222 if (mReadIndex >= mFrames) mReadIndex -= mFrames; 00223 mChannelsDone = 0; 00224 } 00225 } 00226 }; 00227 00228 RtAudio *mRtAudio; 00229 int mRtAudioStream; 00230 MY_TYPE *mRtAudioBuffer; 00231 int mRtAudioBufferSize; 00232 #ifdef MACOSX_WORKAROUND 00233 int mInternalRtAudioBufferSize; 00234 #endif 00235 Buffer mWriteBuffer; 00236 Buffer mReadBuffer; 00237 bool mStarted; 00238 bool mTickOnRead; 00239 bool mTickOnWrite; 00240 int mDevice; 00241 #ifdef FACTOR2SRC_KLUDGE 00242 bool mDoFactor2SRC; 00243 #endif 00244 public: 00245 RtAAudioDevice(const std::string& name,int _device); 00246 ~RtAAudioDevice(); 00247 00248 void Start(void) throw(Err); 00249 void Stop(void) throw(Err); 00250 void Tick(void); 00251 void Read(Audio& audio,const int channelID); 00252 void Write(const Audio& audio,const int channelID); 00253 }; 00254 */ 00255 RtAAudioDevice::RtAAudioDevice(const std::string& name,int _device): 00256 AudioDevice(name) 00257 { 00258 mStarted = false; 00259 mRtAudio = 0; 00260 mTickOnRead = false; 00261 mTickOnWrite = false; 00262 mDevice = _device; 00263 } 00264 00265 void RtAAudioDevice::Start(void) throw(Err) 00266 { 00267 if (!mRtAudio) 00268 { 00269 int fs = SampleRate(); 00270 mRtAudioBufferSize = Latency(); 00271 00272 #ifdef __WINDOWS_DS__ 00273 if (mRtAudioBufferSize<4096) 00274 { 00275 mRtAudioBufferSize = 4096; 00276 } 00277 #endif 00278 00279 #ifdef FACTOR2SRC_KLUDGE 00280 mDoFactor2SRC = false; 00281 if (fs == 22050) 00282 { 00283 mDoFactor2SRC = true; 00284 } 00285 00286 if (mDoFactor2SRC) 00287 { 00288 /* multiply the rt audio buffer size by two, 00289 ** because while we will work on 22050 hz, 00290 ** rtaudio will work at 44100, so it's internal 00291 ** buffer will be double the size. when we access 00292 ** the rt audio buffer in CopyFromDoFactor2SRC 00293 ** and CopyToFactor2SRC, we indeed copy double 00294 ** mRtAudioBufferSize. 00295 ** We multiply by two now, and device by two 00296 ** later on to go back to our buffer size 00297 */ 00298 mRtAudioBufferSize *= 2; 00299 fs *= 2; 00300 } 00301 #endif 00302 00303 #ifdef MACOSX_WORKAROUND 00304 mInternalRtAudioBufferSize = mRtAudioBufferSize; 00305 if (mInternalRtAudioBufferSize>2048) 00306 { 00307 mInternalRtAudioBufferSize = 2048; 00308 } 00309 #endif 00310 00311 try { 00312 mRtAudio = new RtAudio(&mRtAudioStream, 00313 mDevice, mOutputs.size(), 00314 mDevice, mInputs.size(), 00315 FORMAT, fs, 00316 #ifdef MACOSX_WORKAROUND 00317 &mInternalRtAudioBufferSize, 00318 #else 00319 &mRtAudioBufferSize, 00320 #endif 00321 2); 00322 } 00323 catch (RtError &) { 00324 exit(EXIT_FAILURE); 00325 } 00326 00327 #ifdef MACOSX_WORKAROUND 00328 mRtAudioBufferSize = mInternalRtAudioBufferSize*((mRtAudioBufferSize+mInternalRtAudioBufferSize-1)/mInternalRtAudioBufferSize); 00329 #endif 00330 00331 00332 #ifdef FACTOR2SRC_KLUDGE 00333 if (mDoFactor2SRC) 00334 { 00335 /* see comment above */ 00336 mRtAudioBufferSize /= 2; 00337 #ifdef MACOSX_WORKAROUND 00338 mInternalRtAudioBufferSize /= 2; 00339 #endif 00340 } 00341 #endif 00342 00343 /* update the latency value of the audiomanager */ 00344 SetLatency(mRtAudioBufferSize); 00345 00346 00347 mWriteBuffer.Alloc(mOutputs.size(),mRtAudioBufferSize*2); 00348 mReadBuffer.Alloc(mInputs.size(),mRtAudioBufferSize*2); 00349 00350 try { 00351 mRtAudioBuffer = (MY_TYPE *) mRtAudio->getStreamBuffer(mRtAudioStream); 00352 } 00353 catch (RtError &) { 00354 exit(EXIT_FAILURE); 00355 } 00356 } 00357 00358 mStarted = false; 00359 } 00360 00361 void RtAAudioDevice::Stop(void) throw(Err) 00362 { 00363 if (mRtAudio) 00364 { 00365 mRtAudio->stopStream(mRtAudioStream); 00366 mStarted = false; 00367 delete mRtAudio; 00368 mRtAudio = 0; 00369 } 00370 } 00371 00372 RtAAudioDevice::~RtAAudioDevice() 00373 { 00374 Stop(); 00375 } 00376 00377 void RtAAudioDevice::Read(Audio& a,const int channelID) 00378 { 00379 if (!mStarted) 00380 { 00381 mRtAudio->startStream(mRtAudioStream); 00382 mStarted = true; 00383 mTickOnRead = true; 00384 00385 /* TODO: explain this: */ 00386 int k = mRtAudioBufferSize/a.GetSize(); 00387 if (a.GetSize()*k==mRtAudioBufferSize) 00388 { 00389 mWriteBuffer.mWriteIndex = mRtAudioBufferSize; 00390 } 00391 } 00392 00393 if (mTickOnRead && mReadBuffer.Filled()<a.GetSize()) 00394 { 00395 Tick(); 00396 } 00397 00398 mReadBuffer.ChannelCopyTo(a.GetBuffer().GetPtr(),a.GetSize(),channelID); 00399 } 00400 00401 void RtAAudioDevice::Write(const Audio& a,const int channelID) 00402 { 00403 if (!mStarted) 00404 { 00405 mRtAudio->startStream(mRtAudioStream); 00406 mStarted = true; 00407 mTickOnWrite = true; 00408 } 00409 00410 mWriteBuffer.ChannelCopyFrom(a.GetBuffer().GetPtr(),a.GetSize(),channelID); 00411 00412 if (mTickOnWrite && mWriteBuffer.Filled()>=mRtAudioBufferSize) 00413 { 00414 Tick(); 00415 } 00416 } 00417 00418 void RtAAudioDevice::Tick(void) 00419 { 00420 #ifdef MACOSX_WORKAROUND 00421 int i = mRtAudioBufferSize/mInternalRtAudioBufferSize; 00422 00423 #ifdef FACTOR2SRC_KLUDGE 00424 if (mDoFactor2SRC) 00425 { 00426 while (i--) 00427 { 00428 mWriteBuffer.CopyToFactor2SRC(mRtAudioBuffer,mInternalRtAudioBufferSize); 00429 mRtAudio->tickStream(mRtAudioStream); 00430 mReadBuffer.CopyFromDoFactor2SRC(mRtAudioBuffer,mInternalRtAudioBufferSize); 00431 } 00432 }else 00433 #endif 00434 { 00435 while (i--) 00436 { 00437 mWriteBuffer.CopyTo(mRtAudioBuffer,mInternalRtAudioBufferSize); 00438 mRtAudio->tickStream(mRtAudioStream); 00439 mReadBuffer.CopyFrom(mRtAudioBuffer,mInternalRtAudioBufferSize); 00440 } 00441 } 00442 #else 00443 #ifdef FACTOR2SRC_KLUDGE 00444 if (mDoFactor2SRC) 00445 { 00446 mWriteBuffer.CopyToFactor2SRC(mRtAudioBuffer,mRtAudioBufferSize); 00447 mRtAudio->tickStream(mRtAudioStream); 00448 mReadBuffer.CopyFromDoFactor2SRC(mRtAudioBuffer,mRtAudioBufferSize); 00449 } 00450 else 00451 #endif 00452 { 00453 mWriteBuffer.CopyTo(mRtAudioBuffer,mRtAudioBufferSize); 00454 mRtAudio->tickStream(mRtAudioStream); 00455 mReadBuffer.CopyFrom(mRtAudioBuffer,mRtAudioBufferSize); 00456 } 00457 #endif 00458 } 00459 00460 /* 00461 class RtAAudioDeviceList : public AudioDeviceList 00462 { 00463 private: 00464 static RtAAudioDeviceList sDevices; 00465 00466 RtAAudioDeviceList(); 00467 00468 std::vector< int > mDevIDs; 00469 00470 protected: 00471 00472 void EnumerateAvailableDevices() throw ( Err ); 00473 00474 public: 00475 00476 virtual ~RtAAudioDeviceList(); 00477 static std::string foo() 00478 { 00479 return std::string("buabua"); 00480 } 00481 00482 inline std::string DefaultDevice() 00483 { 00484 return "default"; 00485 } 00486 00487 AudioDevice* Create( const std::string& name, const std::string& device ); 00488 00489 }; 00490 */ 00491 RtAAudioDeviceList::RtAAudioDeviceList() 00492 : AudioDeviceList( std::string("rtaudio") ) 00493 { 00494 00495 EnumerateAvailableDevices(); 00496 00497 AddMe(); 00498 } 00499 00500 void RtAAudioDeviceList::init() 00501 { 00502 // std::cout << "rtaudio initialized" << std::endl; 00503 } 00504 00505 RtAAudioDeviceList::~RtAAudioDeviceList() 00506 { 00507 } 00508 00509 void RtAAudioDeviceList::EnumerateAvailableDevices() throw ( Err ) 00510 { 00511 RtAudio* instance = NULL; 00512 00513 try { 00514 instance = new RtAudio(); 00515 00516 int numDevs = instance->getDeviceCount(); 00517 int k; 00518 RtAudio::RTAUDIO_DEVICE devnfo; 00519 00520 mAvailableDevices.push_back("default"); 00521 mDevIDs.push_back( 0 ); 00522 00523 for ( k = 1; k <= numDevs; k++ ) 00524 { 00525 instance->getDeviceInfo( k, &devnfo ); 00526 mAvailableDevices.push_back( devnfo.name ); 00527 mDevIDs.push_back( k ); 00528 } 00529 delete instance; 00530 } catch( ::RtError& err ) { 00531 if ( instance ) 00532 delete instance; 00533 Err new_err("RtAAudioDeviceList::EnumerateAvailableDevices failed"); 00534 new_err.Embed( err.getMessage() ); 00535 throw ( new_err ); 00536 } 00537 00538 } 00539 00540 AudioDevice* RtAAudioDeviceList::Create( const std::string& name, const std::string& device ) 00541 { 00542 unsigned int i = 0; 00543 00544 for ( i=0; i < mAvailableDevices.size(); i++ ) 00545 { 00546 if ( device == mAvailableDevices[i] ) 00547 return new RtAAudioDevice( name, mDevIDs[i] ); 00548 } 00549 for ( i=0; i < mAvailableDevices.size(); i++ ) 00550 { 00551 char tmp[16]; 00552 sprintf(tmp,"%d",mDevIDs[i]); 00553 if ( device == tmp ) 00554 return new RtAAudioDevice( name, mDevIDs[i] ); 00555 } 00556 00557 return 0; 00558 } 00559 00560 RtAAudioDeviceList RtAAudioDeviceList::sDevices; 00561 } 00562 00563