Marsyas
0.6.0-alpha
|
00001 /* 00002 ** Copyright (C) 1998-2011 George Tzanetakis <gtzan@cs.uvic.ca> 00003 ** 00004 ** This program is free software; you can redistribute it and/or modify 00005 ** it under the terms of the GNU General Public License as published by 00006 ** the Free Software Foundation; either version 2 of the License, or 00007 ** (at your option) any later version. 00008 ** 00009 ** This program is distributed in the hope that it will be useful, 00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 ** GNU General Public License for more details. 00013 ** 00014 ** You should have received a copy of the GNU General Public License 00015 ** along with this program; if not, write to the Free Software 00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 */ 00018 00019 00020 #include "../common_source.h" 00021 #include "AudioSinkBlocking.h" 00022 00023 00024 00025 #include "RtAudio3.h" 00026 00027 00028 00029 00030 using std::ostringstream; 00031 using std::cout; 00032 using std::endl; 00033 00034 using namespace Marsyas; 00035 00036 AudioSinkBlocking::AudioSinkBlocking(mrs_string name):MarSystem("AudioSinkBlocking", name) 00037 { 00038 bufferSize_ = 0; 00039 00040 start_ = 0; 00041 end_ = 0; 00042 00043 preservoirSize_ = 0; 00044 pnChannels_ = 1; 00045 00046 data_ = NULL; 00047 audio_ = NULL; 00048 00049 rtSrate_ = 0; 00050 bufferSize_ = 0; 00051 00052 isInitialized_ = false; 00053 stopped_ = true;//lmartins 00054 00055 rtSrate_ = 0; 00056 bufferSize_ = 0; 00057 rtChannels_ = 0; 00058 rtDevice_ = 0; 00059 00060 addControls(); 00061 } 00062 00063 AudioSinkBlocking::~AudioSinkBlocking() 00064 { 00065 delete audio_; 00066 data_ = NULL; // RtAudio deletes the buffer itself. 00067 } 00068 00069 MarSystem* 00070 AudioSinkBlocking::clone() const 00071 { 00072 return new AudioSinkBlocking(*this); 00073 } 00074 00075 void 00076 AudioSinkBlocking::addControls() 00077 { 00078 00079 #ifdef MARSYAS_MACOSX 00080 addctrl("mrs_natural/bufferSize", 512); 00081 #else 00082 addctrl("mrs_natural/bufferSize", 256); 00083 #endif 00084 00085 addctrl("mrs_bool/initAudio", false); 00086 setctrlState("mrs_bool/initAudio", true); 00087 00088 addctrl("mrs_natural/device", 0); 00089 00090 } 00091 00092 void 00093 AudioSinkBlocking::myUpdate(MarControlPtr sender) 00094 { 00095 MRSDIAG("AudioSinkBlocking::myUpdate"); 00096 00097 MarSystem::myUpdate(sender); 00098 00099 00100 nChannels_ = getctrl("mrs_natural/inObservations")->to<mrs_natural>();//does nothing... [?] 00101 00102 if (getctrl("mrs_bool/initAudio")->to<mrs_bool>()) 00103 initRtAudio(); 00104 00105 //Resize reservoir if necessary 00106 inSamples_ = getctrl("mrs_natural/inSamples")->to<mrs_natural>(); 00107 00108 00109 00110 if (inSamples_ < bufferSize_) 00111 reservoirSize_ = 2 * bufferSize_; 00112 else 00113 { 00114 if (2 * inSamples_ > preservoirSize_) 00115 reservoirSize_ = 2 * inSamples_; 00116 } 00117 00118 00119 if ((reservoirSize_ > preservoirSize_)||(nChannels_ != pnChannels_)) 00120 { 00121 //cout << "NCHANNELS = " << nChannels_ << endl; 00122 reservoir_.stretch(nChannels_, reservoirSize_); 00123 } else { 00124 reservoirSize_ = preservoirSize_; 00125 } 00126 00127 preservoirSize_ = reservoirSize_; 00128 pnChannels_ = nChannels_; 00129 00130 } 00131 00132 void 00133 AudioSinkBlocking::initRtAudio() 00134 { 00135 00136 rtSrate_ = (int)getctrl("mrs_real/israte")->to<mrs_real>(); 00137 srate_ = rtSrate_; 00138 bufferSize_ = (int)getctrl("mrs_natural/bufferSize")->to<mrs_natural>(); 00139 rtDevice_= (int)getctrl("mrs_natural/device")->to<mrs_natural>(); 00140 00141 #ifdef MARSYAS_MACOSX 00142 if (rtSrate_ == 22050) 00143 { 00144 rtSrate_ = 44100; 00145 bufferSize_ = 2 * bufferSize_; 00146 } 00147 #endif 00148 00149 00150 00151 00152 //marsyas represents audio data as float numbers 00153 RtAudio3Format rtFormat = (sizeof(mrs_real) == 8) ? RTAUDIO3_FLOAT64 : RTAUDIO3_FLOAT32; 00154 00155 // hardwire channels to stereo playback even for mono 00156 int rtChannels = nChannels_; 00157 00158 00159 if (rtChannels == 1) // make mono playback in stereo 00160 rtChannels = 2; 00161 00162 //create new RtAudio object (delete any existing one) 00163 if (audio_ != NULL) 00164 { 00165 audio_->stopStream(); 00166 delete audio_; 00167 } 00168 00169 try 00170 { 00171 audio_ = new RtAudio3(rtDevice_, rtChannels, 0, 0, rtFormat, 00172 rtSrate_, &bufferSize_, 4); 00173 00174 data_ = (mrs_real *) audio_->getStreamBuffer(); 00175 } 00176 catch (RtError3 &error) 00177 { 00178 error.printMessage(); 00179 } 00180 00181 if (audio_ != NULL) 00182 { 00183 audio_->startStream(); 00184 } 00185 00186 if (rtDevice_ !=0) { 00187 RtAudio3DeviceInfo info; 00188 info = audio_->getDeviceInfo(rtDevice_); 00189 cout << "Using output device: " << info.name << endl; 00190 } 00191 00192 00193 //update bufferSize control which may have been changed 00194 //by RtAudio (see RtAudio documentation) 00195 setctrl("mrs_natural/bufferSize", (mrs_natural)bufferSize_); 00196 00197 isInitialized_ = true; 00198 setctrl("mrs_bool/initAudio", false); 00199 00200 } 00201 00202 void 00203 AudioSinkBlocking::start() 00204 { 00205 if ( stopped_ && audio_) { 00206 audio_->startStream(); 00207 stopped_ = false; 00208 } 00209 } 00210 00211 void 00212 AudioSinkBlocking::stop() 00213 { 00214 if ( !stopped_ && audio_) { 00215 audio_->abortStream(); 00216 stopped_ = true; 00217 } 00218 } 00219 00220 void 00221 AudioSinkBlocking::localActivate(bool state) 00222 { 00223 if(state) 00224 start(); 00225 else 00226 stop(); 00227 } 00228 00229 void 00230 AudioSinkBlocking::myProcess(realvec& in, realvec& out) 00231 { 00232 mrs_natural t,o; 00233 // cout << "AudioSinkBlocking::myProcess start" << endl; 00234 // check MUTE 00235 if(ctrl_mute_->isTrue()) 00236 { 00237 for (t=0; t < inSamples_; t++) 00238 { 00239 for (o=0; o < inObservations_; o++) 00240 { 00241 out(o,t) = in(o,t); 00242 } 00243 } 00244 00245 if (audio_ != NULL) 00246 { 00247 // for (t=0; t < bufferSize_; t++) 00248 // { 00249 // data_[2*t] = 0.0; 00250 // data_[2*t+1] = 0.0; 00251 // } 00252 // 00253 // try 00254 // { 00255 // audio_->tickStream(); 00256 // } 00257 00258 try 00259 { 00260 audio_->stopStream(); 00261 } 00262 catch (RtError3 &error) 00263 { 00264 error.printMessage(); 00265 } 00266 } 00267 00268 return; 00269 } 00270 00271 // copy to output and into reservoir 00272 00273 00274 00275 for (t=0; t < inSamples_; t++) 00276 { 00277 for (o=0; o < inObservations_; o++) 00278 { 00279 reservoir_(o, end_) = in(o,t); 00280 out(o,t) = in(o,t); 00281 } 00282 end_ ++; 00283 if (end_ == reservoirSize_) 00284 end_ = 0; 00285 } 00286 00287 00288 00289 //check if RtAudio is initialized 00290 if (!isInitialized_) { 00291 return; 00292 } 00293 00294 00295 //assure that RtAudio thread is running 00296 //(this may be needed by if an explicit call to start() 00297 //is not done before ticking or calling process() ) 00298 if ( stopped_ ) 00299 { 00300 start(); 00301 } 00302 00303 00304 //update reservoir pointers 00305 rsize_ = bufferSize_; 00306 #ifdef MARSYAS_MACOSX 00307 if (srate_ == 22050) 00308 rsize_ = bufferSize_/2; // upsample to 44100 00309 else 00310 rsize_ = bufferSize_; 00311 #endif 00312 00313 if (end_ >= start_) 00314 diff_ = end_ - start_; 00315 else 00316 diff_ = reservoirSize_ - (start_ - end_); 00317 00318 //send audio data in reservoir to RtAudio 00319 00320 // cout << "diff_=" << diff_ << " rsize_=" << rsize_ << " reservoirSize_=" << reservoirSize_ << " start_=" << start_ << " end_=" << end_ << endl; 00321 while (diff_ >= rsize_) 00322 { 00323 // cout << "diff_=" << diff_ << endl; 00324 for (t =0; t < rsize_; t++) 00325 { 00326 int rt = (start_ + t); 00327 00328 while (rt >= reservoirSize_) 00329 rt -= reservoirSize_; 00330 while (rt < 0) 00331 rt += reservoirSize_; 00332 00333 const int t2 = 2 * t; 00334 00335 // What does this do? - LG 00336 // Why is this defined?? - <3 lg 00337 //#ifndef MARSYAS_MACOSX 00338 // 00339 // if (inObservations_ == 1) 00340 // { 00341 // for (int j=0; j < nChannels_; j++) 00342 // { 00343 // data_[t2+j] = reservoir_(0, rt); 00344 // } 00345 // } 00346 // else 00347 // { 00348 // for (int j=0; j < nChannels_; j++) 00349 // { 00350 // data_[t2+j] = reservoir_(0+j, rt); 00351 // } 00352 // 00353 // } 00354 // 00355 //#else 00356 const int t4 = 4 * t; 00357 if (srate_ == 22050) 00358 { 00359 00360 if (inObservations_ == 1) 00361 { 00362 data_[t4] = reservoir_(0,rt); 00363 data_[t4+1] = reservoir_(0,rt); 00364 data_[t4+2] = reservoir_(0,rt); 00365 data_[t4+3] = reservoir_(0,rt); 00366 } 00367 else 00368 { 00369 for (int j=0; j < nChannels_; j++) 00370 { 00371 data_[t4] = reservoir_(0+j,rt); 00372 data_[t4+2+j] = reservoir_(0+j,rt); 00373 } 00374 } 00375 00376 } 00377 else 00378 { 00379 if (inObservations_ == 1) 00380 { 00381 00382 mrs_real foo = reservoir_(0, rt); 00383 data_[t2] = foo; 00384 data_[t2+1] = foo; 00385 } 00386 else 00387 { 00388 00389 for (int j=0; j < nChannels_; j++) 00390 { 00391 data_[t2+j] = reservoir_(j, rt); 00392 } 00393 00394 } 00395 } 00396 //#endif 00397 } 00398 00399 //tick RtAudio 00400 try 00401 { 00402 audio_->tickStream(); 00403 } 00404 catch (RtError3 &error) 00405 { 00406 error.printMessage(); 00407 } 00408 00409 00410 //update reservoir pointers 00411 start_ = (start_ + rsize_) % reservoirSize_; 00412 if (end_ >= start_) 00413 diff_ = end_ - start_; 00414 else 00415 diff_ = reservoirSize_ - (start_ - end_); 00416 00417 } 00418 // cout << "AudioSinkBlocking::myProcess end" << endl; 00419 00420 }