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 "AudioSource.h" 00021 00022 #include <algorithm> 00023 #include <cassert> 00024 00025 using namespace std; 00026 using namespace Marsyas; 00027 00028 AudioSource::AudioSource(string name):MarSystem("AudioSource", name) 00029 { 00030 audio_ = NULL; 00031 00032 isInitialized_ = false; 00033 stopped_ = true; 00034 00035 addControls(); 00036 } 00037 00038 AudioSource::~AudioSource() 00039 { 00040 delete audio_; 00041 00042 } 00043 00044 00045 MarSystem* 00046 AudioSource::clone() const 00047 { 00048 return new AudioSource(*this); 00049 } 00050 00051 void 00052 AudioSource::addControls() 00053 { 00054 addctrl("mrs_natural/nChannels", 1); 00055 00056 00057 #ifdef MARSYAS_MACOSX 00058 addctrl("mrs_natural/bufferSize", 1024); 00059 #else 00060 addctrl("mrs_natural/bufferSize", 256); 00061 #endif 00062 00063 00064 addctrl("mrs_bool/initAudio", false); 00065 setctrlState("mrs_bool/initAudio", true); 00066 00067 addctrl("mrs_bool/hasData", true); 00068 addctrl("mrs_real/gain", 1.0); 00069 00070 addControl("mrs_bool/realtime", false); 00071 setControlState("mrs_bool/realtime", true); 00072 } 00073 00074 void 00075 AudioSource::myUpdate(MarControlPtr sender) 00076 { 00077 (void) sender; //suppress warning of unused parameter(s) 00078 MRSDIAG("AudioSource::myUpdate"); 00079 00080 //set output controls 00081 setctrl("mrs_natural/onSamples", getctrl("mrs_natural/inSamples")); 00082 setctrl("mrs_real/osrate", getctrl("mrs_real/israte")); 00083 setctrl("mrs_natural/onObservations", getctrl("mrs_natural/nChannels")); 00084 00085 mrs_natural source_block_size = getctrl("mrs_natural/bufferSize")->to<mrs_natural>(); 00086 mrs_natural dest_block_size = getctrl("mrs_natural/inSamples")->to<mrs_natural>(); 00087 mrs_natural sample_rate = (mrs_natural) getctrl("mrs_real/israte")->to<mrs_real>(); 00088 mrs_natural channel_count = getctrl("mrs_natural/nChannels")->to<mrs_natural>(); 00089 bool realtime = getControl("mrs_bool/realtime")->to<mrs_bool>(); 00090 00091 if (getctrl("mrs_bool/initAudio")->to<mrs_bool>()) 00092 { 00093 stop(); 00094 00095 initRtAudio(sample_rate, &source_block_size, channel_count, realtime); 00096 00097 const bool do_resize_buffer = true; 00098 reformatBuffer(source_block_size, dest_block_size, channel_count, realtime, do_resize_buffer); 00099 00100 shared.sample_rate = sample_rate; 00101 shared.channel_count = channel_count; 00102 shared.overrun = false; 00103 00104 isInitialized_ = true; 00105 00106 //update bufferSize control which may have been changed 00107 //by RtAudio (see RtAudio documentation) 00108 setctrl("mrs_natural/bufferSize", (mrs_natural) source_block_size); 00109 00110 setctrl("mrs_bool/initAudio", false); 00111 } 00112 else if (isInitialized_) 00113 { 00114 const bool do_not_resize_buffer = false; 00115 00116 if (source_block_size != old_source_block_size_ 00117 || sample_rate != shared.sample_rate 00118 || (realtime != (shared.watermark == 0)) 00119 || !reformatBuffer(source_block_size, 00120 dest_block_size, 00121 channel_count, 00122 realtime, 00123 do_not_resize_buffer) ) 00124 { 00125 MRSERR("AudioSource: Reinitialization required!"); 00126 // stop processing until re-initialized; 00127 stop(); 00128 isInitialized_ = false; 00129 } 00130 } 00131 00132 old_source_block_size_ = source_block_size; 00133 old_dest_block_size_ = dest_block_size; 00134 } 00135 00136 00137 void 00138 AudioSource::initRtAudio( 00139 mrs_natural sample_rate, 00140 mrs_natural *block_size, 00141 mrs_natural channel_count, 00142 bool realtime 00143 ) 00144 { 00145 //marsyas represents audio data as float numbers 00146 if (audio_ == NULL) 00147 { 00148 audio_ = new RtAudio(); 00149 } 00150 else if (audio_->isStreamOpen()) 00151 { 00152 audio_->closeStream(); 00153 } 00154 00155 RtAudio::StreamParameters source_params; 00156 source_params.deviceId = audio_->getDefaultInputDevice(); 00157 source_params.nChannels = channel_count; 00158 source_params.firstChannel = 0; 00159 00160 RtAudio::StreamOptions options; 00161 options.streamName = "Marsyas"; 00162 options.numberOfBuffers = 0; // Use default. 00163 options.flags = RTAUDIO_SCHEDULE_REALTIME; 00164 options.priority = 70; 00165 if (realtime) 00166 options.flags |= RTAUDIO_MINIMIZE_LATENCY; // Use smallest possible 'numberOfBuffers'. 00167 00168 RtAudioFormat source_format = (sizeof(mrs_real) == 8) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32; 00169 00170 // Suppress useless warnings when both an AudioSource and 00171 // an AudioSink are being opened using ALSA: 00172 audio_->showWarnings(false); 00173 00174 try 00175 { 00176 unsigned int uint_block_size = *block_size; 00177 audio_->openStream(NULL, &source_params, source_format, sample_rate, 00178 &uint_block_size, &recordCallback, (void *)&shared, &options); 00179 *block_size = uint_block_size; 00180 } 00181 catch (RtError& e) 00182 { 00183 MRSERR("AudioSource: RtAudio error:"); 00184 e.printMessage(); 00185 exit(0); 00186 } 00187 00188 audio_->showWarnings(true); 00189 } 00190 00191 void 00192 AudioSource::start() 00193 { 00194 if ( stopped_ && isInitialized_ ) 00195 { 00196 clearBuffer(); 00197 audio_->startStream(); 00198 stopped_ = false; 00199 } 00200 } 00201 00202 void 00203 AudioSource::stop() 00204 { 00205 if ( !stopped_ ) 00206 { 00207 audio_->stopStream(); 00208 stopped_ = true; 00209 } 00210 } 00211 00212 void 00213 AudioSource::localActivate(bool state) 00214 { 00215 if(state) 00216 { 00217 start(); 00218 } 00219 else 00220 { 00221 stop(); 00222 } 00223 } 00224 00225 void AudioSource::clearBuffer() 00226 { 00227 assert(stopped_); 00228 shared.buffer.clear(); 00229 shared.overrun = false; 00230 } 00231 00232 bool AudioSource::reformatBuffer(mrs_natural source_block_size, 00233 mrs_natural dest_block_size, 00234 mrs_natural channel_count, 00235 bool realtime, bool resize) 00236 { 00237 mrs_natural new_capacity = source_block_size + dest_block_size + 1; 00238 if (!realtime) 00239 new_capacity = std::max( new_capacity * 4, (mrs_natural) 2000 ); 00240 00241 if (resize) 00242 { 00243 assert(stopped_); 00244 mrs_natural size = new_capacity * 2; 00245 if (size != shared.buffer.samples() || channel_count != shared.buffer.observations()) 00246 { 00247 bool do_clear_buffer = true; 00248 shared.buffer.resize(channel_count, size, new_capacity, do_clear_buffer); 00249 } 00250 else 00251 { 00252 shared.buffer.set_capacity(new_capacity); 00253 } 00254 shared.watermark = realtime ? 0 : new_capacity / 2; 00255 } 00256 else 00257 { 00258 if (channel_count != shared.buffer.observations() 00259 || new_capacity > shared.buffer.samples()) 00260 { 00261 MRSERR("AudioSource: Can not set requested buffer capacity or channel count without" 00262 " resizing the buffer!"); 00263 return false; 00264 } 00265 00266 //cout << "Changing capacity: " << new_capacity << "/" << shared.buffer.samples() << endl; 00267 mrs_natural new_watermark = realtime ? 0 : new_capacity / 2;; 00268 if (new_capacity > shared.buffer.capacity()) 00269 { 00270 // First increase capacity, then watermark. 00271 shared.buffer.set_capacity(new_capacity); 00272 shared.watermark = new_watermark; 00273 } 00274 else 00275 { 00276 // First decrease watermark, then capacity. 00277 shared.watermark = new_watermark; 00278 shared.buffer.set_capacity(new_capacity); 00279 } 00280 } 00281 00282 return true; 00283 } 00284 00285 int 00286 AudioSource::recordCallback(void *outputBuffer, void *inputBuffer, 00287 unsigned int nFrames, 00288 double streamTime, unsigned int status, 00289 void *userData) 00290 { 00291 (void) outputBuffer; 00292 (void) streamTime; 00293 (void) status; 00294 00295 mrs_real* data = (mrs_real*)inputBuffer; 00296 InputData &shared = *((InputData*) userData); 00297 unsigned int nChannels = shared.channel_count; 00298 00299 if (shared.overrun) 00300 shared.overrun = shared.buffer.write_capacity() <= shared.watermark; 00301 00302 if (!shared.overrun) 00303 { 00304 // Limit scope of realvec_queue_producer! 00305 realvec_queue_producer producer( shared.buffer, nFrames ); 00306 00307 if (producer.capacity() == nFrames) 00308 { 00309 for (unsigned int t=0; t < nFrames; t++) 00310 { 00311 for (unsigned int ch=0; ch < nChannels; ch++) { 00312 producer(ch, t) = data[nChannels*t+ch]; 00313 } 00314 } 00315 } 00316 else 00317 { 00318 shared.overrun = true; 00319 MRSWARN("AudioSource: buffer overrun!"); 00320 } 00321 } 00322 00323 shared.mutex.lock(); 00324 shared.condition.notify_all(); 00325 shared.mutex.unlock(); 00326 00327 return 0; 00328 } 00329 00330 void 00331 AudioSource::myProcess(realvec& in, realvec& out) 00332 { 00333 (void) in; 00334 00335 //check if RtAudio is initialized 00336 if (!isInitialized_) 00337 { 00338 return; 00339 } 00340 00341 //check MUTE 00342 if(ctrl_mute_->isTrue()) 00343 { 00344 return; 00345 } 00346 00347 //assure that RtAudio thread is running 00348 //(this may be needed by if an explicit call to start() 00349 //is not done before ticking or calling process() ) 00350 if ( stopped_ ) 00351 { 00352 start(); 00353 } 00354 00355 realvec_queue_consumer consumer(shared.buffer, onSamples_); 00356 00357 if ((mrs_natural) consumer.capacity() < onSamples_) 00358 { 00359 std::unique_lock<std::mutex> locker(shared.mutex); 00360 00361 shared.condition.wait ( 00362 locker, 00363 [&consumer, this]() 00364 { 00365 bool ok = consumer.reserve(onSamples_); 00366 if (shared.watermark > 0) 00367 ok = ok && shared.buffer.read_capacity() >= shared.watermark; 00368 return ok; 00369 } 00370 ); 00371 00372 locker.unlock(); 00373 } 00374 00375 MRSASSERT((mrs_natural) consumer.capacity() == onSamples_); 00376 00377 for (mrs_natural t=0; t < onSamples_; t++) 00378 { 00379 for (mrs_natural o=0; o < onObservations_; o++) 00380 { 00381 out(o,t) = consumer(o,t); 00382 } 00383 } 00384 } 00385