Marsyas
0.6.0-alpha
|
00001 /* 00002 ** Copyright (C) 1998-2013 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 #include "../common_source.h" 00020 #include "AudioSink.h" 00021 #include "Resample.h" 00022 #include <algorithm> 00023 #include <cassert> 00024 #include <cstdlib> 00025 00026 using std::ostringstream; 00027 using std::cout; 00028 using std::endl; 00029 using std::min; 00030 00031 using namespace Marsyas; 00032 00033 AudioSink::AudioSink(mrs_string name): 00034 MarSystem("AudioSink", name), 00035 old_source_sample_rate_(-1), 00036 old_dest_block_size_(-1), 00037 resampler_(NULL), 00038 audio_ (NULL), 00039 isInitialized_(false), 00040 stopped_(true), 00041 is_resampling_(false) 00042 { 00043 addControls(); 00044 } 00045 00046 00047 00048 AudioSink::AudioSink(const AudioSink& a): 00049 MarSystem(a), 00050 old_source_sample_rate_(-1), 00051 old_dest_block_size_(-1), 00052 resampler_(NULL), 00053 audio_ (NULL), 00054 isInitialized_(false), 00055 stopped_(true), 00056 is_resampling_(false) 00057 {} 00058 00059 AudioSink::~AudioSink() 00060 { 00061 delete resampler_; 00062 delete audio_; 00063 } 00064 00065 MarSystem* 00066 AudioSink::clone() const 00067 { 00068 return new AudioSink(*this); 00069 } 00070 00071 void 00072 AudioSink::addControls() 00073 { 00074 00075 addctrl("mrs_natural/bufferSize", 512); 00076 addctrl("mrs_bool/initAudio", false); 00077 setctrlState("mrs_bool/initAudio", true); 00078 addctrl("mrs_natural/device", 0); 00079 addControl("mrs_string/backend", ""); 00080 addControl("mrs_bool/realtime", false); 00081 setControlState("mrs_bool/realtime", true); 00082 } 00083 00084 void 00085 AudioSink::myUpdate(MarControlPtr sender) 00086 { 00087 MRSDIAG("AudioSink::myUpdate"); 00088 00089 MarSystem::myUpdate(sender); 00090 00091 // get input format params 00092 mrs_natural source_block_size = getctrl("mrs_natural/inSamples")->to<mrs_natural>(); 00093 mrs_real source_sample_rate = getctrl("mrs_real/israte")->to<mrs_real>(); 00094 mrs_natural channel_count = getctrl("mrs_natural/inObservations")->to<mrs_natural>(); 00095 00096 // get output format params 00097 mrs_natural requested_dest_block_size = getctrl("mrs_natural/bufferSize")->to<mrs_natural>(); 00098 00099 // get other params 00100 bool realtime = getControl("mrs_bool/realtime")->to<mrs_bool>(); 00101 00102 // If user requests audio device initialization: 00103 if (getctrl("mrs_bool/initAudio")->to<mrs_bool>()) 00104 { 00105 stop(); 00106 00107 unsigned int dest_sample_rate = (unsigned int) source_sample_rate; 00108 unsigned int dest_block_size = (unsigned int) requested_dest_block_size; 00109 initRtAudio(&dest_sample_rate, &dest_block_size, 00110 channel_count, realtime); 00111 00112 mrs_natural resampled_block_size; 00113 configureResampler(source_sample_rate, source_block_size, 00114 (mrs_real) dest_sample_rate, &resampled_block_size, 00115 channel_count); 00116 00117 const bool do_resize_buffer = true; 00118 reformatBuffer(resampled_block_size, (mrs_natural) dest_block_size, 00119 channel_count, realtime, do_resize_buffer); 00120 00121 shared.sample_rate = dest_sample_rate; 00122 shared.channel_count = (unsigned int) channel_count; 00123 shared.underrun = false; 00124 00125 isInitialized_ = true; 00126 00127 // update control to reflect block size forced by audio device: 00128 setctrl("mrs_natural/bufferSize", requested_dest_block_size); 00129 // disable handled request flag 00130 setctrl("mrs_bool/initAudio", false); 00131 } 00132 // If no request for audio device initialization this time, 00133 // but it has previously been initialized: 00134 else if (isInitialized_) 00135 { 00136 bool can_continue = 00137 (source_sample_rate == old_source_sample_rate_) && 00138 (requested_dest_block_size == old_dest_block_size_) && 00139 (realtime == (shared.watermark == 0)); 00140 00141 if (can_continue) 00142 { 00143 mrs_natural resampled_block_size; 00144 updateResamplerBlockSize(source_block_size, &resampled_block_size, 00145 channel_count); 00146 00147 const bool do_not_resize_buffer = false; 00148 00149 can_continue = reformatBuffer(resampled_block_size, 00150 requested_dest_block_size, 00151 channel_count, 00152 realtime, 00153 do_not_resize_buffer); 00154 } 00155 00156 if (!can_continue) 00157 { 00158 MRSERR("AudioSink: Reinitialization required!"); 00159 // stop processing until re-initialized; 00160 stop(); 00161 isInitialized_ = false; 00162 } 00163 } 00164 00165 // We will always pass input to output unchanged: 00166 ctrl_onSamples_->setValue(ctrl_inSamples_, NOUPDATE); 00167 ctrl_onObservations_->setValue(ctrl_inObservations_, NOUPDATE); 00168 ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE); 00169 00170 // Cache current parameters, 00171 // just so they can be compared for change next time 00172 old_source_sample_rate_ = source_sample_rate; 00173 old_dest_block_size_ = requested_dest_block_size; 00174 } 00175 00176 00177 void AudioSink::configureResampler(mrs_real in_sample_rate, mrs_natural in_block_size, 00178 mrs_real out_sample_rate, mrs_natural *out_block_size, 00179 mrs_natural channel_count) 00180 { 00181 is_resampling_ = out_sample_rate != in_sample_rate; 00182 00183 mrs_natural resampled_block_size; 00184 00185 if (is_resampling_) 00186 { 00187 if (!resampler_) 00188 resampler_ = new Resample("resampler"); 00189 00190 resampler_->updControl("mrs_natural/inSamples", in_block_size); 00191 resampler_->updControl("mrs_natural/inObservations", channel_count); 00192 resampler_->updControl("mrs_real/israte", in_sample_rate); 00193 resampler_->updControl("mrs_real/newSamplingRate", out_sample_rate); 00194 00195 resampled_block_size = resampler_->getControl("mrs_natural/onSamples")->to<mrs_natural>(); 00196 00197 resampler_output_.create(channel_count, resampled_block_size); 00198 } 00199 else 00200 { 00201 resampled_block_size = in_block_size; 00202 } 00203 00204 if (out_block_size) 00205 { 00206 *out_block_size = resampled_block_size; 00207 } 00208 } 00209 00210 void AudioSink::updateResamplerBlockSize(mrs_natural in_block_size, 00211 mrs_natural *out_block_size, 00212 mrs_natural channel_count) 00213 { 00214 mrs_natural resampled_block_size; 00215 00216 if (resampler_) 00217 { 00218 resampler_->updControl("mrs_natural/inSamples", in_block_size); 00219 resampled_block_size = resampler_->getControl("mrs_natural/onSamples")->to<mrs_natural>(); 00220 resampler_output_.create(channel_count, resampled_block_size); 00221 } 00222 else 00223 { 00224 resampled_block_size = in_block_size; 00225 } 00226 00227 if (out_block_size) 00228 *out_block_size = resampled_block_size; 00229 } 00230 00231 void 00232 AudioSink::initRtAudio( 00233 unsigned int *sample_rate, 00234 unsigned int *block_size, 00235 unsigned int channel_count, 00236 bool realtime 00237 ) 00238 { 00239 mrs_string backend = getControl("mrs_string/backend")->to<mrs_string>(); 00240 00241 RtAudio::Api rt_audio_api = RtAudio::UNSPECIFIED; 00242 if (!backend.empty()) { 00243 if (backend == "jack") 00244 rt_audio_api = RtAudio::UNIX_JACK; 00245 else if (backend == "alsa") 00246 rt_audio_api = RtAudio::LINUX_ALSA; 00247 else if (backend == "pulse") 00248 rt_audio_api = RtAudio::LINUX_PULSE; 00249 else if (backend == "oss") 00250 rt_audio_api = RtAudio::LINUX_OSS; 00251 else if (backend == "core-audio") 00252 rt_audio_api = RtAudio::MACOSX_CORE; 00253 else if (backend == "asio") 00254 rt_audio_api = RtAudio::WINDOWS_ASIO; 00255 else if (backend == "direct-sound") 00256 rt_audio_api = RtAudio::WINDOWS_DS; 00257 else 00258 MRSWARN("AudioSink: audio backend '" << backend << "' not supported."); 00259 } 00260 00261 if (audio_ == NULL) 00262 audio_ = new RtAudio(rt_audio_api); 00263 else if (audio_->isStreamOpen()) 00264 audio_->closeStream(); 00265 00266 int device_id = (int) getctrl("mrs_natural/device")->to<mrs_natural>(); 00267 if (device_id == 0) 00268 { 00269 device_id = audio_->getDefaultOutputDevice(); 00270 } 00271 00272 std::vector<unsigned int> supported_sample_rates; 00273 supported_sample_rates = audio_->getDeviceInfo(device_id).sampleRates; 00274 00275 unsigned int target_sample_rate = *(supported_sample_rates.begin()); 00276 for (std::vector<unsigned int>::iterator i = supported_sample_rates.begin(); 00277 i != supported_sample_rates.end(); i++) 00278 { 00279 00280 ostringstream msg; 00281 msg << *i << "-" << *sample_rate; 00282 00283 if (*i == (unsigned int) *sample_rate) { 00284 target_sample_rate = *sample_rate; 00285 break; 00286 } 00287 } 00288 00289 if (target_sample_rate != (unsigned int) *sample_rate) { 00290 ostringstream msg; 00291 msg << "AudioSink: Audio device does not support sample rate " << *sample_rate << "Hz. Resampling to " << target_sample_rate << "Hz."; 00292 MRSWARN(msg.str()); 00293 } 00294 *sample_rate = (mrs_natural) target_sample_rate; 00295 00296 00297 // expand mono to stereo 00298 channel_count = std::max((unsigned int) 2, channel_count); 00299 00300 RtAudio::StreamParameters output_params; 00301 output_params.deviceId = device_id; 00302 output_params.nChannels = channel_count; 00303 output_params.firstChannel = 0; 00304 00305 RtAudio::StreamOptions options; 00306 options.streamName = "Marsyas"; 00307 options.numberOfBuffers = 0; // Use default. 00308 options.flags = RTAUDIO_SCHEDULE_REALTIME; 00309 options.priority = 70; 00310 if (realtime) 00311 options.flags |= RTAUDIO_MINIMIZE_LATENCY; // Use smallest possible 'numberOfBuffers'. 00312 00313 RtAudioFormat format = (sizeof(mrs_real) == 8) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32; 00314 00315 // Suppress useless warnings when both an AudioSource and 00316 // an AudioSink are being opened using ALSA: 00317 audio_->showWarnings(false); 00318 00319 try 00320 { 00321 audio_->openStream(&output_params, NULL, format, *sample_rate, 00322 block_size, &playCallback, (void *)&shared, &options); 00323 } 00324 catch (RtError& e) 00325 { 00326 MRSERR("AudioSink: RtAudio error:"); 00327 e.printMessage(); 00328 exit(0); 00329 } 00330 00331 audio_->showWarnings(true); 00332 } 00333 00334 void 00335 AudioSink::start() 00336 { 00337 if ( stopped_ && isInitialized_ ) 00338 { 00339 clearBuffer(); 00340 audio_->startStream(); 00341 stopped_ = false; 00342 } 00343 } 00344 00345 void 00346 AudioSink::stop() 00347 { 00348 if ( !stopped_) { 00349 00350 audio_->stopStream(); 00351 stopped_ = true; 00352 } 00353 } 00354 00355 00356 void 00357 AudioSink::localActivate(bool state) 00358 { 00359 if(state) 00360 start(); 00361 else 00362 stop(); 00363 } 00364 00365 void AudioSink::clearBuffer() 00366 { 00367 assert(stopped_); 00368 shared.buffer.clear(); 00369 shared.underrun = false; 00370 } 00371 00372 bool AudioSink::reformatBuffer(mrs_natural source_block_size, 00373 mrs_natural dest_block_size, 00374 mrs_natural channel_count, 00375 bool realtime, bool resize) 00376 { 00377 00378 mrs_natural new_capacity = source_block_size + dest_block_size + 1; 00379 if (!realtime) 00380 new_capacity = std::max( new_capacity * 4, (mrs_natural) 2000 ); 00381 00382 if (resize) 00383 { 00384 assert(stopped_); 00385 mrs_natural size = new_capacity * 2; 00386 if (size != shared.buffer.samples() || channel_count != shared.buffer.observations()) 00387 { 00388 bool do_clear_buffer = true; 00389 shared.buffer.resize(channel_count, size, new_capacity, do_clear_buffer); 00390 } 00391 else 00392 { 00393 shared.buffer.set_capacity(new_capacity); 00394 } 00395 shared.watermark = realtime ? 0 : new_capacity / 2; 00396 } 00397 else 00398 { 00399 if (channel_count != shared.buffer.observations() 00400 || new_capacity > shared.buffer.samples()) 00401 { 00402 MRSERR("AudioSink: Can not set requested buffer capacity or channel count without" 00403 " resizing the buffer!"); 00404 return false; 00405 } 00406 00407 //cout << "Changing capacity: " << new_capacity << "/" << shared.buffer.samples() << endl; 00408 unsigned int new_watermark = realtime ? 0 : new_capacity / 2;; 00409 if (new_capacity > shared.buffer.capacity()) 00410 { 00411 // First increase capacity, then watermark. 00412 shared.buffer.set_capacity(new_capacity); 00413 shared.watermark = new_watermark; 00414 } 00415 else 00416 { 00417 // First decrease watermark, then capacity. 00418 shared.watermark = new_watermark; 00419 shared.buffer.set_capacity(new_capacity); 00420 } 00421 } 00422 00423 return true; 00424 } 00425 00426 void 00427 AudioSink::myProcess(realvec& in, realvec& out) 00428 { 00429 // always pass input unchanged 00430 out = in; 00431 00432 //check if RtAudio is initialized 00433 if (!isInitialized_) 00434 return; 00435 00436 // assure that RtAudio thread is running 00437 // (this may be needed by if an explicit call to start() 00438 // is not done before ticking or calling process() ) 00439 if ( stopped_ ) 00440 { 00441 start(); 00442 } 00443 00444 //check MUTE 00445 if(ctrl_mute_->isTrue()) 00446 { 00447 return; 00448 } 00449 00450 if (is_resampling_) 00451 resampler_->process(in, resampler_output_); 00452 00453 const realvec & source = is_resampling_ ? resampler_output_ : in; 00454 mrs_natural out_samples = source.getCols(); 00455 mrs_natural out_observations = source.getRows(); 00456 00457 realvec_queue_producer producer(shared.buffer, out_samples); 00458 00459 if ((mrs_natural) producer.capacity() < out_samples) 00460 { 00461 // cout << "Producer waiting..." << endl; 00462 00463 auto resume_condition = [&]() 00464 { 00465 // cout << "Producer awake..." << endl; 00466 bool ok = producer.reserve(out_samples); 00467 if (shared.watermark > 0) 00468 ok = ok && shared.buffer.write_capacity() >= shared.watermark; 00469 return ok; 00470 }; 00471 00472 std::unique_lock<std::mutex> locker(shared.mutex); 00473 00474 shared.condition.wait ( locker, resume_condition ); 00475 00476 locker.unlock(); 00477 //cout << "Producer continuing..." << endl; 00478 } 00479 00480 for (mrs_natural t=0; t < out_samples; t++) 00481 { 00482 for (mrs_natural o=0; o < out_observations; o++) 00483 producer(o,t) = source(o,t); 00484 } 00485 } 00486 00487 00488 int 00489 AudioSink::playCallback(void *outputBuffer, void *inputBuffer, 00490 unsigned int nFrames, double streamTime, 00491 unsigned int status, void *userData) 00492 { 00493 (void) inputBuffer; 00494 (void) streamTime; 00495 (void) status; 00496 00497 00498 mrs_real* data = (mrs_real*)outputBuffer; 00499 OutputData &shared = *((OutputData*)userData); 00500 unsigned int nChannels = shared.channel_count; 00501 00502 //cout << "-- Consuming " << nFrames << endl; 00503 00504 if (shared.underrun) 00505 shared.underrun = shared.buffer.read_capacity() <= shared.watermark; 00506 00507 if (!shared.underrun) 00508 { 00509 // Limit scope of realvec_queue_consumer! 00510 realvec_queue_consumer consumer(shared.buffer, nFrames); 00511 00512 if (consumer.capacity() >= nFrames) 00513 { 00514 for (unsigned int t=0; t < nFrames; t++) 00515 { 00516 unsigned int t2 = t * 2; 00517 if (nChannels == 1) 00518 { 00519 mrs_real val = consumer(0, t); 00520 data[t2] = val; 00521 data[t2+1] = val; 00522 } 00523 else 00524 { 00525 for (unsigned int ch=0; ch < nChannels; ch++) { 00526 data[nChannels*t+ch] = consumer(ch, t); 00527 } 00528 } 00529 } 00530 //cout << "-- Consumed." << endl; 00531 } 00532 else 00533 { 00534 shared.underrun = true; 00535 MRSWARN("AudioSink: buffer underrun!"); 00536 } 00537 } 00538 00539 if (shared.underrun) 00540 { 00541 // write silence: 00542 nChannels = std::max(nChannels, (unsigned int) 2); 00543 std::memset(outputBuffer, 0, nChannels * nFrames * sizeof(mrs_real)); 00544 } 00545 00546 shared.mutex.lock(); 00547 shared.condition.notify_all(); 00548 shared.mutex.unlock(); 00549 00550 return 0; 00551 } 00552