Audio callback
| 456 | |
| 457 | // Audio callback |
| 458 | static void audioCallback(void* userData, unsigned char* outputBuffer, int bufsize) |
| 459 | { |
| 460 | f32* buffer = (f32*)outputBuffer; |
| 461 | u32 bufferSize = (u32)bufsize; |
| 462 | u32 frames = bufferSize / (AUDIO_CHANNEL_COUNT * sizeof(f32)); |
| 463 | |
| 464 | #if AUDIO_TIMING == 1 |
| 465 | u64 soundIterStart = TFE_System::getCurrentTimeInTicks(); |
| 466 | #endif |
| 467 | |
| 468 | // First clear samples |
| 469 | memset(buffer, 0, bufferSize); |
| 470 | |
| 471 | SDL_LockMutex(s_mutex); |
| 472 | // Then call the audio thread callback |
| 473 | if (s_audioThreadCallback && !s_paused) |
| 474 | { |
| 475 | static f32 callbackBuffer[(AUDIO_CALLBACK_BUFFER_SIZE + 2)*AUDIO_CHANNEL_COUNT]; // 256 stereo + oversampling. |
| 476 | s_audioThreadCallback(callbackBuffer, AUDIO_CALLBACK_BUFFER_SIZE, s_soundFxVolume * c_soundHeadroom); |
| 477 | // The audio buffer is 1/4 as large as it should be. |
| 478 | // This means that in-between samples must be interpolated. |
| 479 | if (!s_silentAudioFrames) |
| 480 | { |
| 481 | if (s_upsampleFilter == AUF_NONE) |
| 482 | { |
| 483 | upsample4x_point(buffer, callbackBuffer, AUDIO_CALLBACK_BUFFER_SIZE*AUDIO_CHANNEL_COUNT); |
| 484 | } |
| 485 | else if (s_upsampleFilter == AUF_LINEAR) |
| 486 | { |
| 487 | upsample4x_linear(buffer, callbackBuffer, AUDIO_CALLBACK_BUFFER_SIZE*AUDIO_CHANNEL_COUNT); |
| 488 | } |
| 489 | } |
| 490 | } |
| 491 | |
| 492 | // Then loop through the sources. |
| 493 | // Note: this is no longer used by Dark Forces. However I decided to keep direct sound support around |
| 494 | // so it can be used for tools. |
| 495 | SoundSource* snd = s_sources; |
| 496 | for (u32 s = 0; s < s_sourceCount && !s_paused; s++, snd++) |
| 497 | { |
| 498 | if (!(snd->flags&SND_FLAG_PLAYING)) { continue; } |
| 499 | assert(snd->buffer->data); |
| 500 | |
| 501 | // Skip sound sample processing the sound is too quiet... |
| 502 | const u32 sndBufferSize = snd->buffer->size; |
| 503 | if (snd->volume < SND_CULL_VOLUME) |
| 504 | { |
| 505 | // Pretend we played the sound and handle looping. |
| 506 | snd->sampleIndex += frames; |
| 507 | if (snd->sampleIndex >= sndBufferSize) |
| 508 | { |
| 509 | if (snd->flags&SND_FLAG_LOOPING) |
| 510 | { |
| 511 | snd->sampleIndex = (snd->sampleIndex % sndBufferSize) + snd->buffer->loopStart; |
| 512 | } |
| 513 | else |
| 514 | { |
| 515 | snd->flags &= ~SND_FLAG_PLAYING; |
nothing calls this directly
no test coverage detected