CLAM-Development  1.4.0
RtAAudioDevice.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 #include "RtAAudioDevice.hxx"
22 
23 /*
24 #include "RtAudio.hxx"
25 #include "AudioIO.hxx"
26 #include "AudioIn.hxx"
27 #include "AudioOut.hxx"
28 #include "AudioDeviceList.hxx"
29 #include "AudioDevice.hxx"
30 #include <cstdio>
31 */
32 
33 namespace CLAM {
34 /*
35 #ifdef __MACOSX_CORE__
36 #define MACOSX_WORKAROUND
37 #endif
38 */
39 
40 //#ifdef __MACOSX_CORE__
41 /* a kludgy factor 2 (22050->44100) sample rate conversion
42 ** because macosx drivers do not handle 22050 */
43  /*
44 #define FACTOR2SRC_KLUDGE
45 #endif
46 */
47 
48 //#define DEBUG_RDWR_POS
49 
50 
51 /*
52  typedef signed short MY_TYPE;
53  #define FORMAT RtAudio::RTAUDIO_SINT16
54  class RtAAudioDevice: public AudioDevice
55  {
56  private:
57  class Buffer
58  {
59  friend class RtAAudioDevice;
60  private:
61  Buffer(int channels = 0,int frames = 0)
62  {
63  mData = 0;
64  Alloc(channels,frames);
65  mChannelsDone = 0;
66  mReadIndex = 0;
67  mWriteIndex = 0;
68  }
69  void Alloc(int channels = 0,int frames = 0)
70  {
71  if (mData) delete mData;
72  mChannels = channels;
73  mFrames = frames;
74  if (mChannels && mFrames)
75  {
76  mData = new TData[mChannels*mFrames];
77  }else{
78  mData = 0;
79  }
80  }
81 
82  TData* mData;
83  int mReadIndex;
84  int mWriteIndex;
85  int mChannels;
86  int mChannelsDone;
87  int mFrames;
88  int Filled(void)
89  {
90  return mWriteIndex >= mReadIndex ?
91  mWriteIndex - mReadIndex :
92  mWriteIndex + mFrames - mReadIndex;
93  }
94 
95  void CopyTo(MY_TYPE* ptr,int frames)
96  {
97  int cnt = frames*mChannels;
98  int limit = mFrames*mChannels;
99  int i = mReadIndex*mChannels;
100 
101 #ifdef DEBUG_RDWR_POS
102  printf("copyto: r=%d %d\n",mReadIndex,frames);
103 #endif
104  while (cnt--)
105  {
106  *ptr++ = (MY_TYPE)(mData[i++]*32767.);
107  if (i==limit) i = 0;
108  }
109  mReadIndex += frames;
110  if (mReadIndex >= mFrames) mReadIndex -= mFrames;
111 
112  }
113 
114 #ifdef FACTOR2SRC_KLUDGE
115  void CopyToFactor2SRC(MY_TYPE* ptr,int frames)
116  {
117  int cnt = frames*mChannels;
118  int limit = mFrames*mChannels;
119  int i = mReadIndex*mChannels;
120 
121 #ifdef DEBUG_RDWR_POS
122  printf("copyto: r=%d %d\n",mReadIndex,frames);
123 #endif
124  while (cnt--)
125  {
126  *ptr++ = (MY_TYPE)(mData[i]*32767.);
127  *ptr++ = (MY_TYPE)(mData[i]*32767.);
128  i++;
129  if (i==limit) i = 0;
130  }
131  mReadIndex += frames;
132  if (mReadIndex >= mFrames) mReadIndex -= mFrames;
133 
134  }
135 #endif
136 
137  void CopyFrom(MY_TYPE* ptr,int frames)
138  {
139  int cnt = frames*mChannels;
140  int limit = mFrames*mChannels;
141  int i = mWriteIndex*mChannels;
142 
143 #ifdef DEBUG_RDWR_POS
144  printf("copyfrom: w=%d %d\n",mWriteIndex,frames);
145 #endif
146  while (cnt--)
147  {
148  mData[i++] = TData(*ptr++)/32767.;
149  if (i==limit) i = 0;
150  }
151  mWriteIndex += frames;
152  if (mWriteIndex >= mFrames) mWriteIndex -= mFrames;
153  }
154 
155 #ifdef FACTOR2SRC_KLUDGE
156  void CopyFromDoFactor2SRC(MY_TYPE* ptr,int frames)
157  {
158  int cnt = frames*mChannels;
159  int limit = mFrames*mChannels;
160  int i = mWriteIndex*mChannels;
161 
162 #ifdef DEBUG_RDWR_POS
163  printf("copyfrom: w=%d %d\n",mWriteIndex,frames);
164 #endif
165  while (cnt--)
166  {
167  TData t = TData(*ptr++);
168  t += TData(*ptr++);
169  t /= 65534.;
170  mData[i++] = t;
171  if (i==limit) i = 0;
172  }
173  mWriteIndex += frames;
174  if (mWriteIndex >= mFrames) mWriteIndex -= mFrames;
175  }
176 #endif
177 
178  void ChannelCopyFrom(TData* ptr,int size,int chnId)
179  {
180  int i = mWriteIndex*mChannels+chnId;
181  int n = size;
182  int limit = mChannels*mFrames;
183 
184 #ifdef DEBUG_RDWR_POS
185  printf("ChannelCopyFrom: w=%d %d\n",mWriteIndex,size);
186 #endif
187  fflush(stdout);
188  while (n--)
189  {
190  mData[i] = *ptr++;
191  i += mChannels;
192  if (i>=limit) i = chnId;
193  }
194  mChannelsDone++;
195  if (mChannelsDone==mChannels)
196  {
197  mWriteIndex += size;
198  if (mWriteIndex >= mFrames) mWriteIndex -= mFrames;
199  mChannelsDone = 0;
200  }
201  }
202 
203  void ChannelCopyTo(TData* ptr,int size,int chnId)
204  {
205  int i = mReadIndex*mChannels+chnId;
206  int n = size;
207  int limit = mChannels*mFrames;
208 
209 #ifdef DEBUG_RDWR_POS
210  printf("ChannelCopyTo: r=%d %d\n",mReadIndex,size);
211 #endif
212  while (n--)
213  {
214  *ptr++ = mData[i];
215  i += mChannels;
216  if (i>=limit) i = chnId;
217  }
218  mChannelsDone++;
219  if (mChannelsDone==mChannels)
220  {
221  mReadIndex += size;
222  if (mReadIndex >= mFrames) mReadIndex -= mFrames;
223  mChannelsDone = 0;
224  }
225  }
226  };
227 
228  RtAudio *mRtAudio;
229  int mRtAudioStream;
230  MY_TYPE *mRtAudioBuffer;
231  int mRtAudioBufferSize;
232 #ifdef MACOSX_WORKAROUND
233  int mInternalRtAudioBufferSize;
234 #endif
235  Buffer mWriteBuffer;
236  Buffer mReadBuffer;
237  bool mStarted;
238  bool mTickOnRead;
239  bool mTickOnWrite;
240  int mDevice;
241 #ifdef FACTOR2SRC_KLUDGE
242  bool mDoFactor2SRC;
243 #endif
244  public:
245  RtAAudioDevice(const std::string& name,int _device);
246  ~RtAAudioDevice();
247 
248  void Start(void) throw(Err);
249  void Stop(void) throw(Err);
250  void Tick(void);
251  void Read(Audio& audio,const int channelID);
252  void Write(const Audio& audio,const int channelID);
253  };
254  */
255  RtAAudioDevice::RtAAudioDevice(const std::string& name,int _device):
256  AudioDevice(name)
257  {
258  mStarted = false;
259  mRtAudio = 0;
260  mTickOnRead = false;
261  mTickOnWrite = false;
262  mDevice = _device;
263  }
264 
265  void RtAAudioDevice::Start(void) throw(Err)
266  {
267  if (!mRtAudio)
268  {
269  int fs = SampleRate();
270  mRtAudioBufferSize = Latency();
271 
272 #ifdef __WINDOWS_DS__
273  if (mRtAudioBufferSize<4096)
274  {
275  mRtAudioBufferSize = 4096;
276  }
277 #endif
278 
279 #ifdef FACTOR2SRC_KLUDGE
280  mDoFactor2SRC = false;
281  if (fs == 22050)
282  {
283  mDoFactor2SRC = true;
284  }
285 
286  if (mDoFactor2SRC)
287  {
288  /* multiply the rt audio buffer size by two,
289  ** because while we will work on 22050 hz,
290  ** rtaudio will work at 44100, so it's internal
291  ** buffer will be double the size. when we access
292  ** the rt audio buffer in CopyFromDoFactor2SRC
293  ** and CopyToFactor2SRC, we indeed copy double
294  ** mRtAudioBufferSize.
295  ** We multiply by two now, and device by two
296  ** later on to go back to our buffer size
297  */
298  mRtAudioBufferSize *= 2;
299  fs *= 2;
300  }
301 #endif
302 
303 #ifdef MACOSX_WORKAROUND
304  mInternalRtAudioBufferSize = mRtAudioBufferSize;
305  if (mInternalRtAudioBufferSize>2048)
306  {
307  mInternalRtAudioBufferSize = 2048;
308  }
309 #endif
310 
311  try {
312  mRtAudio = new RtAudio(&mRtAudioStream,
313  mDevice, mOutputs.size(),
314  mDevice, mInputs.size(),
315  FORMAT, fs,
316 #ifdef MACOSX_WORKAROUND
317  &mInternalRtAudioBufferSize,
318 #else
319  &mRtAudioBufferSize,
320 #endif
321  2);
322  }
323  catch (RtError &) {
324  exit(EXIT_FAILURE);
325  }
326 
327 #ifdef MACOSX_WORKAROUND
328  mRtAudioBufferSize = mInternalRtAudioBufferSize*((mRtAudioBufferSize+mInternalRtAudioBufferSize-1)/mInternalRtAudioBufferSize);
329 #endif
330 
331 
332 #ifdef FACTOR2SRC_KLUDGE
333  if (mDoFactor2SRC)
334  {
335  /* see comment above */
336  mRtAudioBufferSize /= 2;
337 #ifdef MACOSX_WORKAROUND
338  mInternalRtAudioBufferSize /= 2;
339 #endif
340  }
341 #endif
342 
343  /* update the latency value of the audiomanager */
344  SetLatency(mRtAudioBufferSize);
345 
346 
347  mWriteBuffer.Alloc(mOutputs.size(),mRtAudioBufferSize*2);
348  mReadBuffer.Alloc(mInputs.size(),mRtAudioBufferSize*2);
349 
350  try {
351  mRtAudioBuffer = (MY_TYPE *) mRtAudio->getStreamBuffer(mRtAudioStream);
352  }
353  catch (RtError &) {
354  exit(EXIT_FAILURE);
355  }
356  }
357 
358  mStarted = false;
359  }
360 
361  void RtAAudioDevice::Stop(void) throw(Err)
362  {
363  if (mRtAudio)
364  {
365  mRtAudio->stopStream(mRtAudioStream);
366  mStarted = false;
367  delete mRtAudio;
368  mRtAudio = 0;
369  }
370  }
371 
373  {
374  Stop();
375  }
376 
377  void RtAAudioDevice::Read(Audio& a,const int channelID)
378  {
379  if (!mStarted)
380  {
381  mRtAudio->startStream(mRtAudioStream);
382  mStarted = true;
383  mTickOnRead = true;
384 
385  /* TODO: explain this: */
386  int k = mRtAudioBufferSize/a.GetSize();
387  if (a.GetSize()*k==mRtAudioBufferSize)
388  {
389  mWriteBuffer.mWriteIndex = mRtAudioBufferSize;
390  }
391  }
392 
393  if (mTickOnRead && mReadBuffer.Filled()<a.GetSize())
394  {
395  Tick();
396  }
397 
398  mReadBuffer.ChannelCopyTo(a.GetBuffer().GetPtr(),a.GetSize(),channelID);
399  }
400 
401  void RtAAudioDevice::Write(const Audio& a,const int channelID)
402  {
403  if (!mStarted)
404  {
405  mRtAudio->startStream(mRtAudioStream);
406  mStarted = true;
407  mTickOnWrite = true;
408  }
409 
410  mWriteBuffer.ChannelCopyFrom(a.GetBuffer().GetPtr(),a.GetSize(),channelID);
411 
412  if (mTickOnWrite && mWriteBuffer.Filled()>=mRtAudioBufferSize)
413  {
414  Tick();
415  }
416  }
417 
419  {
420 #ifdef MACOSX_WORKAROUND
421  int i = mRtAudioBufferSize/mInternalRtAudioBufferSize;
422 
423 #ifdef FACTOR2SRC_KLUDGE
424  if (mDoFactor2SRC)
425  {
426  while (i--)
427  {
428  mWriteBuffer.CopyToFactor2SRC(mRtAudioBuffer,mInternalRtAudioBufferSize);
429  mRtAudio->tickStream(mRtAudioStream);
430  mReadBuffer.CopyFromDoFactor2SRC(mRtAudioBuffer,mInternalRtAudioBufferSize);
431  }
432  }else
433 #endif
434  {
435  while (i--)
436  {
437  mWriteBuffer.CopyTo(mRtAudioBuffer,mInternalRtAudioBufferSize);
438  mRtAudio->tickStream(mRtAudioStream);
439  mReadBuffer.CopyFrom(mRtAudioBuffer,mInternalRtAudioBufferSize);
440  }
441  }
442 #else
443 #ifdef FACTOR2SRC_KLUDGE
444  if (mDoFactor2SRC)
445  {
446  mWriteBuffer.CopyToFactor2SRC(mRtAudioBuffer,mRtAudioBufferSize);
447  mRtAudio->tickStream(mRtAudioStream);
448  mReadBuffer.CopyFromDoFactor2SRC(mRtAudioBuffer,mRtAudioBufferSize);
449  }
450  else
451 #endif
452  {
453  mWriteBuffer.CopyTo(mRtAudioBuffer,mRtAudioBufferSize);
454  mRtAudio->tickStream(mRtAudioStream);
455  mReadBuffer.CopyFrom(mRtAudioBuffer,mRtAudioBufferSize);
456  }
457 #endif
458  }
459 
460  /*
461  class RtAAudioDeviceList : public AudioDeviceList
462  {
463  private:
464  static RtAAudioDeviceList sDevices;
465 
466  RtAAudioDeviceList();
467 
468  std::vector< int > mDevIDs;
469 
470  protected:
471 
472  void EnumerateAvailableDevices() throw ( Err );
473 
474  public:
475 
476  virtual ~RtAAudioDeviceList();
477  static std::string foo()
478  {
479  return std::string("buabua");
480  }
481 
482  inline std::string DefaultDevice()
483  {
484  return "default";
485  }
486 
487  AudioDevice* Create( const std::string& name, const std::string& device );
488 
489  };
490  */
491  RtAAudioDeviceList::RtAAudioDeviceList()
492  : AudioDeviceList( std::string("rtaudio") )
493  {
494 
495  EnumerateAvailableDevices();
496 
497  AddMe();
498  }
499 
501  {
502  // std::cout << "rtaudio initialized" << std::endl;
503  }
504 
506  {
507  }
508 
510  {
511  RtAudio* instance = NULL;
512 
513  try {
514  instance = new RtAudio();
515 
516  int numDevs = instance->getDeviceCount();
517  int k;
518  RtAudio::RTAUDIO_DEVICE devnfo;
519 
520  mAvailableDevices.push_back("default");
521  mDevIDs.push_back( 0 );
522 
523  for ( k = 1; k <= numDevs; k++ )
524  {
525  instance->getDeviceInfo( k, &devnfo );
526  mAvailableDevices.push_back( devnfo.name );
527  mDevIDs.push_back( k );
528  }
529  delete instance;
530  } catch( ::RtError& err ) {
531  if ( instance )
532  delete instance;
533  Err new_err("RtAAudioDeviceList::EnumerateAvailableDevices failed");
534  new_err.Embed( err.getMessage() );
535  throw ( new_err );
536  }
537 
538  }
539 
540  AudioDevice* RtAAudioDeviceList::Create( const std::string& name, const std::string& device )
541  {
542  unsigned int i = 0;
543 
544  for ( i=0; i < mAvailableDevices.size(); i++ )
545  {
546  if ( device == mAvailableDevices[i] )
547  return new RtAAudioDevice( name, mDevIDs[i] );
548  }
549  for ( i=0; i < mAvailableDevices.size(); i++ )
550  {
551  char tmp[16];
552  sprintf(tmp,"%d",mDevIDs[i]);
553  if ( device == tmp )
554  return new RtAAudioDevice( name, mDevIDs[i] );
555  }
556 
557  return 0;
558  }
559 
560  RtAAudioDeviceList RtAAudioDeviceList::sDevices;
561 }
562 
563