Audio thread. This loop responds to requests from the soundcard to fill 'blocks' with audio data. If no requests are available it goes dormant until the sound card is ready for more data. The block is fille by the "user" in some manner and then issued to the soundcard.
| 518 | // card is ready for more data. The block is fille by the "user" in some manner |
| 519 | // and then issued to the soundcard. |
| 520 | void SOUND::AudioThread() |
| 521 | { |
| 522 | m_fGlobalTime = 0.0f; |
| 523 | static float fTimeStep = 1.0f / (float)m_nSampleRate; |
| 524 | |
| 525 | // Goofy hack to get maximum integer for a type at run-time |
| 526 | short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1; |
| 527 | float fMaxSample = (float)nMaxSample; |
| 528 | short nPreviousSample = 0; |
| 529 | |
| 530 | auto tp1 = std::chrono::system_clock::now(); |
| 531 | auto tp2 = std::chrono::system_clock::now(); |
| 532 | |
| 533 | while (m_bAudioThreadActive) |
| 534 | { |
| 535 | // Wait for block to become available |
| 536 | if (m_nBlockFree == 0) |
| 537 | { |
| 538 | std::unique_lock<std::mutex> lm(m_muxBlockNotZero); |
| 539 | while (m_nBlockFree == 0) // sometimes, Windows signals incorrectly |
| 540 | m_cvBlockNotZero.wait(lm); |
| 541 | } |
| 542 | |
| 543 | // Block is here, so use it |
| 544 | m_nBlockFree--; |
| 545 | |
| 546 | // Prepare block for processing |
| 547 | if (m_pWaveHeaders[m_nBlockCurrent].dwFlags & WHDR_PREPARED) |
| 548 | waveOutUnprepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR)); |
| 549 | |
| 550 | short nNewSample = 0; |
| 551 | int nCurrentBlock = m_nBlockCurrent * m_nBlockSamples; |
| 552 | |
| 553 | auto clip = [](float fSample, float fMax) |
| 554 | { |
| 555 | if (fSample >= 0.0) |
| 556 | return fmin(fSample, fMax); |
| 557 | else |
| 558 | return fmax(fSample, -fMax); |
| 559 | }; |
| 560 | |
| 561 | tp2 = std::chrono::system_clock::now(); |
| 562 | std::chrono::duration<float> elapsedTime = tp2 - tp1; |
| 563 | tp1 = tp2; |
| 564 | |
| 565 | // Our time per frame coefficient |
| 566 | float fElapsedTime = elapsedTime.count(); |
| 567 | |
| 568 | for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels) |
| 569 | { |
| 570 | // User Process |
| 571 | for (unsigned int c = 0; c < m_nChannels; c++) |
| 572 | { |
| 573 | nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime + fTimeStep * (float)n, fTimeStep), 1.0) * fMaxSample); |
| 574 | m_pBlockMemory[nCurrentBlock + n + c] = nNewSample; |
| 575 | nPreviousSample = nNewSample; |
| 576 | } |
| 577 | } |