00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "common.h"
00020 #include "AudioSink.h"
00021
00022
00023 using std::ostringstream;
00024 using std::cout;
00025 using std::endl;
00026 using std::min;
00027
00028 using namespace Marsyas;
00029
00030
00031 #ifdef MARSYAS_AUDIOIO
00032 #include "RtAudio.h"
00033 #endif
00034
00035
00036
00037 AudioSink::AudioSink(mrs_string name):MarSystem("AudioSink", name)
00038 {
00039 #ifdef MARSYAS_AUDIOIO
00040 audio_ = NULL;
00041 #endif
00042
00043 pringBufferSize_ = 0;
00044 pnChannels_ = 1;
00045
00046
00047 rtSrate_ = 0;
00048
00049 isInitialized_ = false;
00050 stopped_ = true;
00051
00052 rtSrate_ = 0;
00053 bufferSize_ = 0;
00054 rtChannels_ = 0;
00055 rtDevice_ = 0;
00056
00057
00058
00059 addControls();
00060 }
00061
00062 AudioSink::~AudioSink()
00063 {
00064 #ifdef MARSYAS_AUDIOIO
00065 delete audio_;
00066 #endif
00067
00068 }
00069
00070 MarSystem*
00071 AudioSink::clone() const
00072 {
00073 return new AudioSink(*this);
00074 }
00075
00076 void
00077 AudioSink::addControls()
00078 {
00079
00080 #ifdef MARSYAS_MACOSX
00081 addctrl("mrs_natural/bufferSize", 256);
00082 #else
00083 addctrl("mrs_natural/bufferSize", 256);
00084 #endif
00085
00086 addctrl("mrs_bool/initAudio", false);
00087 setctrlState("mrs_bool/initAudio", true);
00088
00089 addctrl("mrs_natural/device", 0);
00090
00091 }
00092
00093 void
00094 AudioSink::myUpdate(MarControlPtr sender)
00095 {
00096 MRSDIAG("AudioSink::myUpdate");
00097
00098 MarSystem::myUpdate(sender);
00099
00100 inSamples_ = getctrl("mrs_natural/inSamples")->to<mrs_natural>();
00101
00102 if (inSamples_ < bufferSize_)
00103 ringBufferSize_ = 8 * bufferSize_;
00104 else
00105 {
00106 ringBufferSize_ = 8 * inSamples_;
00107 }
00108 odata_.ringBufferSize = ringBufferSize_;
00109 odata_.high_watermark = ringBufferSize_ / 4;
00110 odata_.low_watermark = ringBufferSize_ /8;
00111 odata_.samplesInBuffer = 0;
00112
00113
00114
00115 nChannels_ = getctrl("mrs_natural/inObservations")->to<mrs_natural>();
00116 if ((ringBufferSize_ > pringBufferSize_)||(nChannels_ != pnChannels_))
00117 {
00118 ringBuffer_.stretch(nChannels_, ringBufferSize_);
00119 }
00120 pringBufferSize_ = ringBufferSize_;
00121 pnChannels_ = nChannels_;
00122
00123
00124
00125
00126 if (getctrl("mrs_bool/initAudio")->to<mrs_bool>())
00127 initRtAudio();
00128 }
00129
00130
00131 void
00132 AudioSink::initRtAudio()
00133 {
00134
00135 rtSrate_ = (int)getctrl("mrs_real/israte")->to<mrs_real>();
00136 srate_ = rtSrate_;
00137 bufferSize_ = (int)getctrl("mrs_natural/bufferSize")->to<mrs_natural>();
00138 rtDevice_= (int)getctrl("mrs_natural/device")->to<mrs_natural>();
00139
00140 #ifdef MARSYAS_MACOSX
00141
00142
00143
00144 if (rtSrate_ == 22050)
00145 {
00146
00147 rtSrate_ = 44100;
00148 bufferSize_ = 2 * bufferSize_;
00149 }
00150 #endif
00151
00152 #ifdef MARSYAS_AUDIOIO
00153 if (audio_ == NULL)
00154 audio_ = new RtAudio();
00155
00156 unsigned int bufferFrames;
00157 bufferFrames = bufferSize_;
00158
00159
00160 rtChannels_ = 2;
00161
00162 RtAudio::StreamParameters oParams;
00163 if (rtDevice_ == 0)
00164 {
00165 rtDevice_ = audio_->getDefaultOutputDevice();
00166 }
00167 oParams.deviceId = rtDevice_;
00168 oParams.nChannels = rtChannels_;
00169 oParams.firstChannel = 0;
00170
00171 odata_.ringBuffer = &ringBuffer_;
00172 odata_.wp = 0;
00173 odata_.rp = 0;
00174 odata_.ringBufferSize = ringBufferSize_;
00175 odata_.inchannels = inObservations_;
00176 odata_.myself = this;
00177 odata_.srate = srate_;
00178
00179
00180
00181 RtAudioFormat rtFormat = (sizeof(mrs_real) == 8) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
00182
00183
00184 rtFormat = RTAUDIO_FLOAT64;
00185
00186 RtAudio::StreamOptions options;
00187 audio_->showWarnings(true);
00188
00189
00190
00191
00192
00193
00194 if (rtDevice_ != audio_->getDefaultOutputDevice())
00195 {
00196 RtAudio::DeviceInfo info;
00197 info = audio_->getDeviceInfo(rtDevice_);
00198 }
00199
00200
00201 try
00202 {
00203 audio_->openStream(&oParams, NULL, rtFormat, rtSrate_,
00204 &bufferFrames, &playCallback, (void *)&odata_, NULL);
00205 }
00206 catch (RtError& e)
00207 {
00208 e.printMessage();
00209 exit(0);
00210 }
00211
00212
00213
00214
00215
00216 setctrl("mrs_natural/bufferSize", (mrs_natural)bufferFrames);
00217
00218 #endif
00219 isInitialized_ = true;
00220 setctrl("mrs_bool/initAudio", false);
00221
00222 }
00223
00224 void
00225 AudioSink::start()
00226 {
00227 #ifdef MARSYAS_AUDIOIO
00228 if ( stopped_) {
00229 audio_->startStream();
00230 stopped_ = false;
00231 }
00232 #endif
00233 }
00234
00235
00236
00237 #ifdef MARSYAS_AUDIOIO
00238
00239 int
00240 AudioSink::playCallback(void *outputBuffer, void *inputBuffer,
00241 unsigned int nBufferFrames, double streamTime,
00242 unsigned int status, void *userData)
00243 {
00244 unsigned int drain_count = 0;
00245
00246 mrs_real* data = (mrs_real*)outputBuffer;
00247 OutputData *odata = (OutputData *)userData;
00248
00249 realvec& ringBuffer = *(odata->ringBuffer);
00250 unsigned int t;
00251
00252 if (odata->srate == 22050)
00253 nBufferFrames = nBufferFrames/2;
00254
00255
00256
00257 for (t=0; t < nBufferFrames; t++)
00258 {
00259 if (odata->samplesInBuffer >= odata->low_watermark)
00260 {
00261
00262 const int t4 = 4 * t;
00263 const int t2 = 2 * t;
00264
00265 if (odata->srate == 22050)
00266 {
00267
00268 if (odata->inchannels == 1)
00269 {
00270 mrs_real val = ringBuffer(0, odata->rp);
00271 data[t4] = val;
00272 data[t4+1] = val;
00273 data[t4+2] = val;
00274 data[t4+3] = val;
00275 }
00276 else
00277 {
00278 for (int j=0; j < (int)odata->inchannels; j++)
00279 {
00280 data[t4+j] = ringBuffer(0+j,odata->rp);
00281 data[t4+1+j] = ringBuffer(0+j,odata->rp);
00282 }
00283 }
00284
00285 }
00286 else
00287 {
00288
00289 if (odata->inchannels == 1)
00290 {
00291
00292 mrs_real val = ringBuffer(0,odata->rp);
00293 data[t2] = val;
00294 data[t2+1] = val;
00295 }
00296 else
00297 {
00298
00299
00300 for (int j=0; j < (int)odata->inchannels; j++)
00301 {
00302 data[t2+j] = ringBuffer(j,odata->rp);
00303 }
00304 }
00305 }
00306
00307 odata->rp = ++(odata->rp) % odata->ringBufferSize;
00308 if (odata->wp >= odata->rp)
00309 odata->samplesInBuffer = odata->wp - odata->rp;
00310 else
00311 odata->samplesInBuffer = odata->ringBufferSize - (odata->rp - odata->wp);
00312 }
00313 }
00314
00315 while (odata->samplesInBuffer < odata->low_watermark)
00316 {
00317
00318 SLEEP(1);
00319 drain_count++;
00320 if (drain_count == 1000)
00321 return 1;
00322 }
00323 return 0;
00324 }
00325
00326 #endif
00327
00328
00329 void
00330 AudioSink::stop()
00331 {
00332 #ifdef MARSYAS_AUDIOIO
00333 if ( !stopped_) {
00334
00335 audio_->stopStream();
00336 stopped_ = true;
00337 }
00338 #endif
00339 }
00340
00341
00342 void
00343 AudioSink::localActivate(bool state)
00344 {
00345 if(state)
00346 start();
00347 else
00348 stop();
00349 }
00350
00351
00352 unsigned int
00353 AudioSink::getSpaceAvailable()
00354 {
00355 unsigned int free = (odata_.rp - odata_.wp -1 + odata_.ringBufferSize) % odata_.ringBufferSize;
00356 unsigned int underMark = odata_.high_watermark - getSamplesAvailable();
00357
00358 return(min(underMark, free));
00359 }
00360
00361
00362 unsigned int
00363 AudioSink::getSamplesAvailable()
00364 {
00365 unsigned int samplesAvailable = (odata_.wp - odata_.rp +odata_.ringBufferSize) % odata_.ringBufferSize;
00366 return samplesAvailable;
00367 }
00368
00369
00370 void
00371 AudioSink::myProcess(realvec& in, realvec& out)
00372 {
00373
00374 mrs_natural t,o;
00375
00376
00377 if(ctrl_mute_->isTrue())
00378 {
00379 for (t=0; t < inSamples_; t++)
00380 {
00381 for (o=0; o < inObservations_; o++)
00382 {
00383 out(o,t) = in(o,t);
00384 }
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 }
00412 else
00413 {
00414
00415
00416 for (t=0; t < inSamples_; t++)
00417 {
00418 for (o=0; o < inObservations_; o++)
00419 {
00420 out(o,t) = in(o,t);
00421 }
00422 }
00423
00424
00425
00426 if (!isInitialized_)
00427 return;
00428
00429
00430 for (t=0; t < onSamples_; t++)
00431 {
00432 if (odata_.samplesInBuffer <= odata_.high_watermark)
00433 {
00434
00435 for (o=0; o < onObservations_; o++)
00436 ringBuffer_(o,odata_.wp) = in(o,t);
00437
00438 odata_.wp = ++ (odata_.wp) % odata_.ringBufferSize;
00439 if (odata_.wp >= odata_.rp)
00440 odata_.samplesInBuffer = odata_.wp - odata_.rp;
00441 else
00442 odata_.samplesInBuffer = odata_.ringBufferSize - (odata_.rp - odata_.wp);
00443 }
00444 else
00445 {
00446 while (odata_.samplesInBuffer > odata_.high_watermark)
00447 {
00448 SLEEP(1);
00449 }
00450 }
00451 }
00452 }
00453
00454
00455
00456
00457
00458 if ( stopped_ )
00459 {
00460 start();
00461 }
00462
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475