Marsyas  0.5.0-beta1
/Users/jleben/code/marsyas/src/marsyas/marsystems/AudioSink.cpp
Go to the documentation of this file.
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