00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "taptaudio_paimpl.h"
00011
00012 SDL_mutex *AudioSystemImpl::as_mutex = SDL_CreateMutex();
00013 SDL_mutex *AudioSystemImpl::registry_mutex = SDL_CreateMutex();
00014
00015 namespace {
00016 SDL_sem *stop_sem = SDL_CreateSemaphore(0);
00017
00018 #ifndef PAV19
00019 int my_callback(void *inputBuffer,
00020 void *outputBuffer,
00021 unsigned long framesPerBuffer,
00022 PaTimestamp outTime,
00023 void *userData) {
00024 return static_cast<AudioSystemImpl*>(userData)->
00025 callback(inputBuffer,
00026 outputBuffer,
00027 framesPerBuffer,
00028 outTime);
00029 }
00030 #else
00031 int my_callback(const void *input,
00032 void *output,
00033 unsigned long frameCount,
00034 const PaStreamCallbackTimeInfo* timeInfo,
00035 PaStreamCallbackFlags ,
00036 void *userData ) {
00037 return static_cast<AudioSystemImpl*>(userData)->
00038 callback(input,
00039 output,
00040 frameCount,
00041 timeInfo->outputBufferDacTime);
00042 }
00043 #endif
00044
00045 struct SaveInfo {
00046 Recording *r;
00047 std::string f;
00048 SaveInfo(Recording *rr, const std::string &file) : r(rr), f(file) {}
00049 };
00050
00051 int my_saver(void *data) {
00052 SaveInfo * si= static_cast<SaveInfo*>(data);
00053 int ret = si->r->save(si->f);
00054 delete si;
00055 return ret;
00056 }
00057 }
00058
00059
00060
00061
00062
00063 void AudioSystemImpl::waitstop() {
00064 SDL_SemWait(stop_sem);
00065 }
00066
00067 AudioSystemImpl::~AudioSystemImpl() {
00068 DODEBUG(INFO, ("[Ai] Not locking to close AudioSystem..."));
00069
00070
00071
00072 PaError err;
00073 DODEBUG(NOTICE, ("[An] Stopping stream..."));
00074
00075 err = Pa_StopStream(stream);
00076 DODEBUG(NOTICE, ("[An] Closing stream..."));
00077 err = Pa_CloseStream(stream);
00078 DODEBUG(NOTICE, ("[An] Clearing registry..."));
00079 for (REGISTRY::iterator it = registry.begin(); it != registry.end(); ++it)
00080 delete it->second;
00081
00082
00083
00084 DODEBUG(NOTICE, ("[An] Done."));
00085 }
00086
00087 AudioSystemImpl::AudioSystemImpl(unsigned inputChannels,
00088 unsigned outputChannels,
00089 double sampleRate,
00090 AUDIO_FORMAT format,
00091 int deviceIDin,
00092 int deviceIDout)
00093 :
00094 stream(0),
00095 stopping(false),
00096 inChannels(inputChannels),
00097 outChannels(outputChannels),
00098 sampRate(sampleRate == 0.0 ? 44100 : sampleRate),
00099 fmt(format == AF_Default ? AF_Int16 : format),
00100 cur_rec(0),
00101 cur_play(0),
00102 record_after_play(0)
00103 {
00104 int sz = 0;
00105 switch (fmt) {
00106 case AF_Float32:
00107 case AF_Int32: sz++;
00108 case AF_PackedInt24 :
00109 case AF_Int24: sz++;
00110 case AF_Int16: sz++;
00111 case AF_Int8:
00112 case AF_UInt8: sz++;
00113 default: break;
00114 }
00115 iframe_size = inChannels * sz;
00116 oframe_size = outChannels * sz;
00117
00118 PaError err;
00119 if ((err = Pa_Initialize()) != paNoError)
00120 throw err;
00121
00122 fakeMonoMic = inChannels == 1 && outChannels == 2;
00123
00124 #ifndef PAV19
00125 if (deviceIDin == 0 && deviceIDout == 0) {
00126 if ((err = Pa_OpenDefaultStream(&stream,
00127 fakeMonoMic ? 2 : inChannels,
00128 outChannels,
00129 fmt,
00130 sampRate,
00131 1024,
00132 0,
00133 my_callback,
00134 this)) != paNoError)
00135 throw err;
00136 } else {
00137 if ((err = Pa_OpenStream(&stream,
00138 deviceIDin,
00139 fakeMonoMic ? 2 : inChannels,
00140 fmt,
00141 0,
00142 deviceIDout,
00143 outChannels,
00144 fmt,
00145 0,
00146 sampRate,
00147 1024,
00148 0,
00149 0,
00150 my_callback,
00151 this)) != paNoError)
00152 throw err;
00153 }
00154 #else
00155 if (deviceIDin == 0 && deviceIDout == 0) {
00156 if ((err = Pa_OpenDefaultStream(&stream,
00157 fakeMonoMic ? 2 : inChannels,
00158 outChannels,
00159 fmt,
00160 sampRate,
00161 1024,
00162 my_callback,
00163 this)) != paNoError)
00164 throw err;
00165 } else {
00166 PaStreamParameters in, out;
00167 in.device = out.device = 0;
00168 in.channelCount = fakeMonoMic ? 2 : inChannels;
00169 out.channelCount = outChannels;
00170 in.sampleFormat = out.sampleFormat = fmt;
00171 in.suggestedLatency = out.suggestedLatency = 0.010;
00172 in.hostApiSpecificStreamInfo = out.hostApiSpecificStreamInfo = 0;
00173
00174 if ((err = Pa_OpenStream(&stream,
00175 &in, &out,
00176 sampRate,
00177 1024,
00178 0,
00179 my_callback,
00180 this)) != paNoError)
00181 throw err;
00182 }
00183 #endif
00184
00185 if ((err = Pa_StartStream(stream)) != paNoError)
00186 throw err;
00187
00188
00189 DODEBUG(NOTICE, ("[An] AudioSystem mixing at %fHz for %d input and %d output channels on device %d/%d...",
00190 sampRate, inChannels, outChannels, deviceIDin, deviceIDout));
00191 DODEBUG(INFO, ("[Ai] fakeMonoMic = %s, iframe_size = %u, oframe_size = %u, sz = %d.",
00192 fakeMonoMic ? "true" : "false", iframe_size, oframe_size, sz));
00193 }
00194
00195 int AudioSystemImpl::callback(const void *inputBuffer,
00196 void *outputBuffer,
00197 unsigned long framesPerBuffer,
00198 Timestamp outTime)
00199 {
00200 if (stopping) {
00201 SDL_SemPost(stop_sem);
00202 return 1;
00203 }
00204 SDL_mutexP(as_mutex);
00205 if (cur_rec)
00206 doRecord(inputBuffer, framesPerBuffer);
00207 doPlay(outputBuffer, framesPerBuffer, outTime);
00208 SDL_mutexV(as_mutex);
00209 return 0;
00210 }
00211
00212 void AudioSystemImpl::doRecord(const void *inputBuffer,
00213 unsigned long framesPerBuffer)
00214 {
00215 if (inputBuffer) {
00216
00217 if (fakeMonoMic)
00218 cur_rec->skipfill(inputBuffer, iframe_size * framesPerBuffer, iframe_size/2);
00219 else
00220 cur_rec->fill(inputBuffer, iframe_size * framesPerBuffer);
00221 } else {
00222 cur_rec->fillSilence(iframe_size * framesPerBuffer);
00223 }
00224 }
00225
00226 void AudioSystemImpl::doPlay(void *outputBuffer,
00227 unsigned long framesPerBuffer,
00228 Timestamp ) {
00229 if (outputBuffer) {
00230 memset(outputBuffer, 0, oframe_size * framesPerBuffer);
00231 if (cur_play) {
00232
00233 unsigned long nb = cur_play->numBytes();
00234 if (play_offset < nb) {
00235 unsigned long sz = framesPerBuffer * oframe_size;
00236 if (sz > nb - play_offset)
00237 sz = nb - play_offset;
00238
00239 if (cur_play->getChannels() == 1 && outChannels == 2) {
00240 sz /= 2;
00241 PCMSample::mono2stereo(static_cast<Uint8*>(outputBuffer),
00242 static_cast<const Uint8*>(cur_play->getBytes()) + play_offset,
00243 sz,
00244 oframe_size/2);
00245 } else {
00246 memcpy(outputBuffer,
00247 static_cast<const Uint8*>(cur_play->getBytes()) + play_offset,
00248 sz);
00249 }
00250 play_offset += sz;
00251 }
00252 if (play_offset >= nb - 1) {
00253
00254 --cur_play->refs;
00255 cur_play = 0;
00256 if (record_after_play) {
00257 cur_rec = record_after_play;
00258 record_after_play = 0;
00259 }
00260 }
00261 }
00262 }
00263 }
00264
00265
00266 ASSample* AudioSystemImpl::loadSample(const std::string &name) {
00267 ASSample *ret = 0;
00268
00269 SDL_mutexP(registry_mutex);
00270
00271 REGISTRY::iterator it = registry.find(name);
00272 if (it == registry.end()) {
00273 try {
00274 ret = new FileSample(name);
00275
00276 if (fmt == ret->getFormat() &&
00277 outChannels >= ret->getChannels() &&
00278 sampRate == ret->getSamRate()) {
00279
00280 registry.insert(REGISTRY::value_type(name, ret));
00281
00282 } else {
00283
00284 DODEBUG(WARNING, ("[Aw] The format of %s is not compatible with the current AudioSystem",
00285 name.c_str()));
00286 DODEBUG(WARNING, ("[Aw] (file = [%d]fmt %d ch @ %fHz != [%d]fmt %d ch @ %fHz = AudioSystem)",
00287 static_cast<int>(ret->getFormat()), ret->getChannels(), ret->getSamRate(),
00288 static_cast<int>(fmt), outChannels, sampRate));
00289
00290 delete ret;
00291
00292 }
00293 } catch (const char *err) {
00294 DODEBUG(ERROR, ("[Ae] Exception caught trying to load %s: %s",
00295 name.c_str(), err));
00296 } catch (std::bad_alloc &) {
00297 DODEBUG(ERROR, ("[Ae] Not enough memory to load %s",
00298 name.c_str()));
00299 }
00300 } else {
00301 ret = it->second;
00302 }
00303 SDL_mutexV(registry_mutex);
00304 return ret;
00305 }
00306
00307 bool AudioSystemImpl::freeSample(ASSample* samp) {
00308
00309 bool ret = false;
00310 SDL_mutexP(as_mutex);
00311 if (samp->refs) {
00312 SDL_mutexV(as_mutex);
00313 DODEBUG(WARNING, ("[Aw] Couldn't free sample -- maybe it is still playing"));
00314 return false;
00315 }
00316 SDL_mutexP(registry_mutex);
00317
00318 REGISTRY::iterator it = registry.begin();
00319 for (; it != registry.end() && it->second != samp; ++it)
00320 ;
00321
00322 if (it == registry.end()) {
00323 DODEBUG(ERROR, ("[Ae] Couldn't find sample in registry -- not freeing"));
00324 } else {
00325 registry.erase(it);
00326 delete samp;
00327 DODEBUG(INFO, ("[Ai] Sample removed from registry and deleted"));
00328 ret = true;
00329 }
00330 SDL_mutexV(registry_mutex);
00331 SDL_mutexV(as_mutex);
00332 return ret;
00333 }
00334
00335 ASSample* AudioSystemImpl::loadRawSample(const std::string &name, void* data, unsigned long size) {
00336 ASSample *ret = 0;
00337
00338 SDL_mutexP(registry_mutex);
00339
00340 REGISTRY::iterator it = registry.find(name);
00341 if (it != registry.end()) {
00342 registry.erase(it);
00343 }
00344 ret = new PCMSample(data, outChannels, size, sampRate, fmt);
00345 registry.insert(REGISTRY::value_type(name, ret));
00346 SDL_mutexV(registry_mutex);
00347 return ret;
00348 }
00349
00350
00351 ASSample** AudioSystemImpl::getSampleHolder(bool loop, float , unsigned* trackno) {
00352 if (trackno)
00353 *trackno = 0;
00354 if (!loop && !cur_play) {
00355 play_offset = 0;
00356 return &cur_play;
00357 }
00358 return 0;
00359 }
00360
00361 unsigned AudioSystemImpl::stopSample(ASSample *samp, int , bool lock) {
00362 if (cur_play == samp) {
00363 if (lock) SDL_mutexP(as_mutex);
00364 --cur_play->refs;
00365 cur_play = 0;
00366 if (lock) SDL_mutexV(as_mutex);
00367 return 1;
00368 }
00369 return 0;
00370 }
00371
00372 ASSample** AudioSystemMixer::getSampleHolder(bool loop, float vol, unsigned* trackno) {
00373 for (unsigned i = 0; i < tracks; ++i) {
00374 if (!track[i].sam) {
00375 track[i].off = 0;
00376 track[i].vol = vol;
00377 track[i].looping = loop;
00378 if (trackno)
00379 *trackno = i;
00380 return &(track[i].sam);
00381 }
00382 }
00383 return 0;
00384 }
00385
00386 unsigned AudioSystemMixer::stopSample(ASSample *samp, int trackno, bool lock) {
00387 unsigned ctr = 0;
00388 unsigned i = (trackno < 0) ? 0 : trackno;
00389 const unsigned max = (trackno < 0) ? tracks : trackno+1;
00390 if (lock) SDL_mutexP(as_mutex);
00391 for (; i < max; ++i) {
00392 if (track[i].sam == samp) {
00393 --track[i].sam->refs;
00394 track[i].sam = 0;
00395 ctr++;
00396 }
00397 }
00398 if (lock) SDL_mutexV(as_mutex);
00399 return ctr;
00400 }
00401
00402 unsigned AudioSystemMixer::setVolume(ASSample *samp, float vol, int trackno) {
00403 unsigned ctr = 0;
00404 unsigned i = (trackno < 0) ? 0 : trackno;
00405 const unsigned max = (trackno < 0) ? tracks : trackno+1;
00406 SDL_mutexP(as_mutex);
00407 for (; i < max; ++i) {
00408 if (track[i].sam == samp) {
00409 track[i].vol = vol;
00410 ctr++;
00411 }
00412 }
00413 SDL_mutexV(as_mutex);
00414 return ctr;
00415 }
00416
00417 bool AudioSystemImpl::mixSample(ASSample *samp, bool record_after, double record_size, bool loop, float vol, unsigned* trackno) {
00418 bool success = false;
00419 SDL_mutexP(as_mutex);
00420 ASSample **holder = getSampleHolder(loop, vol, trackno);
00421 if (holder) {
00422 *holder = samp;
00423 ++samp->refs;
00424 success = true;
00425 if (record_after && !cur_rec && !record_after_play)
00426 record_after_play = new Recording(static_cast<unsigned long>(record_size * sampRate * iframe_size),
00427 inChannels,
00428 fmt,
00429 sampRate);
00430 DODEBUG(FUNCTION, ("[Af] %sixing %lu bytes, %d channels @ %fHz",
00431 (*holder)->getChannels() == outChannels ? "M" : "Upm",
00432 (*holder)->numBytes(), (*holder)->getChannels(), (*holder)->getSamRate()));
00433 }
00434 SDL_mutexV(as_mutex);
00435 return success;
00436 }
00437
00438 bool AudioSystemImpl::loopSample(ASSample *samp, float vol, unsigned* trackno) {
00439 return mixSample(samp, false, 0.0, true, vol, trackno);
00440 }
00441
00442 bool AudioSystemImpl::startRec(double max_seconds) {
00443 DODEBUG(FUNCTION, ("[Af] Recording..."));
00444 SDL_mutexP(as_mutex);
00445 bool success = false;
00446 if (!cur_rec && !record_after_play) {
00447 try {
00448
00449 cur_rec = new Recording(static_cast<unsigned long>(max_seconds * sampRate * iframe_size),
00450 inChannels,
00451 fmt,
00452 sampRate);
00453 success = true;
00454 } catch (std::bad_alloc&) {
00455 }
00456 }
00457 SDL_mutexV(as_mutex);
00458 return success;
00459 }
00460
00461 ASSample* AudioSystemImpl::stopRec(const std::string &name, bool save, bool save_in_thread) {
00462 DODEBUG(FUNCTION, ("[Af] Stopping... "));
00463 Recording *ret = 0;
00464 SDL_mutexP(as_mutex);
00465 if (cur_rec) {
00466 cur_rec->trim();
00467 DODEBUG(INFO, ("[Ai] Size is %lu bytes\n",
00468 cur_rec->numBytes()));
00469 ret = cur_rec;
00470 cur_rec = 0;
00471
00472 {
00473 SDL_mutexP(registry_mutex);
00474 REGISTRY::iterator it = registry.find(name);
00475 if (it != registry.end()) {
00476 delete it->second;
00477 it->second = ret;
00478 } else {
00479 registry.insert(REGISTRY::value_type(name, ret));
00480 }
00481 SDL_mutexV(registry_mutex);
00482 }
00483
00484 if (save) {
00485 if (save_in_thread) {
00486 (void)SDL_CreateThread(my_saver, new SaveInfo(ret, name));
00487 } else {
00488 ret->save(name);
00489 }
00490 }
00491 }
00492 SDL_mutexV(as_mutex);
00493 return ret;
00494 }
00495
00496 void AudioSystemImpl::listDevices() {
00497 (void)Pa_Initialize();
00498 #ifndef PAV19
00499 int numdevices = Pa_CountDevices();
00500 int defaultin = Pa_GetDefaultInputDeviceID();
00501 int defaultout = Pa_GetDefaultOutputDeviceID();
00502
00503 fprintf(stderr, "Counted %d device%s. Device #0 for default (?).\n", numdevices, numdevices == 1 ? "" : "s");
00504 for (int i = 0; i < numdevices; ++i) {
00505 const PaDeviceInfo* d = Pa_GetDeviceInfo(i);
00506 fprintf(stderr,
00507 "Device #%d%s%s\n"
00508 "\tstructVersion : %d\n"
00509 "\tname : %s\n"
00510 "\tmaxInputChannels: %d\n"
00511 "\tmaxOutputChans : %d\n"
00512 "\tsampleFormats : %lx\n"
00513 "\tsampleRates : ",
00514 i,
00515 (i == defaultin ? " (Default Input)" : ""),
00516 (i == defaultout ? " (Default Output)" : ""),
00517 d->structVersion, d->name,
00518 d->maxInputChannels, d->maxOutputChannels,
00519 d->nativeSampleFormats);
00520 if (d->numSampleRates < 0) {
00521 fprintf(stderr,
00522 "%.0f -- %.0f\n",
00523 d->sampleRates[0], d->sampleRates[1]);
00524 } else {
00525 if (d->numSampleRates > 0)
00526 fprintf(stderr, "%.0f", d->sampleRates[0]);
00527 for (int j = 1; j < d->numSampleRates; ++j) {
00528 fprintf(stderr, ", %.0f", d->sampleRates[j]);
00529 }
00530 fprintf(stderr, "\n");
00531 }
00532 }
00533 #else
00534
00535 #endif
00536 }