📄 mixengine.cpp
字号:
200, 170, 152, 140, 130, 122, 115, 110, 105, 100, 96, 92, 89, 85, 82, 80, 77, 74, 72, 70, 68, 66, 64, 62, 60, 59, 57, 55, 54, 52, 51, 49, 48, 47, 46, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 28, 27, 26, 25, 24, 24, 23, 22, 21, 21, 20, 19, 19, 18, 17, 17, 16, 15, 15, 14, 14, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0 } ; if (vol > HX_MAX_VOLUME) return 0 ; else if (vol <= 0) return VOLUME_SILENT ; else return -(INT32)vol2TenthOfDb[vol] ;}#endifHX_RESULT HXAudioSvcMixEngine::MixIntoBuffer(void* pPlayerbuf0, UINT32 ulBufSizeInBytes_4, BOOL &bIsMixBufferDirty){ // our caller's sense of "dirty" is inverted bIsMixBufferDirty = !bIsMixBufferDirty ; char *pPlayerbuf = (char*)pPlayerbuf0 ; // keep the original around BOOL bHadInput = FALSE ; // optimization lazy-init of buffers. // We only allocate the sample buffers when we really need them (the first // time MixIntoBuffer() is called) if (!m_pBuffer_1) { // allocate both buffers m_pBuffer_1 = new tAudioSample[m_ulChunkSize_1] ; if (!m_pBuffer_1) return HXR_OUTOFMEMORY ; if (m_pResampler) { m_pBuffer_3 = new tAudioSample[m_ulBufferSize_3] ; if (!m_pBuffer_3) return HXR_OUTOFMEMORY ; } } UINT32 nSamplesOutput_4 = ulBufSizeInBytes_4 / m_ulBytesPerSample ; // make sure we are being handed right-sized buffers. if (nSamplesOutput_4 / m_nChannels_4 * (m_ulBytesPerSample * m_nChannels_4) != ulBufSizeInBytes_4) { HX_ASSERT(0) ; return HXR_FAIL ; } // tile output into chunks while (nSamplesOutput_4) { // Figure out how many samples we need on the resampler output. // If we have left-overs from last time, adjust the tile size UINT32 nSamples_3 = MIN(nSamplesOutput_4 / m_nChannels_4 * m_nChannels_2_3, m_ulChunkSize_3) ; // how many samples in do we need on input? UINT32 nSamples_2 ;#ifdef HELIX_FEATURE_RESAMPLER if (m_pResampler) nSamples_2 = m_pResampler->GetMinInput(nSamples_3 - m_nOutputSamplesLeft_3) ; else#endif nSamples_2 = (nSamples_3 - m_nOutputSamplesLeft_3) ; UINT32 nSamples_1 = nSamples_2 * m_nChannels_1 / m_nChannels_2_3 ; // make sure that we don't overflow the input buffer (if we did, that would // be a design error) HX_ASSERT(nSamples_1 <= m_ulChunkSize_1) ; // // Phase 1: Get the input // // get input BOOL bHaveInput = m_pCvt->ConvertIntoBuffer(m_pBuffer_1, nSamples_1, m_llTimestamp_1); // update the time stamp. m_llTimestamp_1 += nSamples_1 ; // // Phase 2: Downmix if necessary. This might need headroom and create overgain // (not implemented yet) // // downmix if necessary (creates nSamples_2 samples) if (bHaveInput && m_nChannels_2_3 != m_nChannels_1) (*this.*m_pfDownmix)(m_pBuffer_1, nSamples_1) ; // // apply any volume changes //#ifdef HELIX_FEATURE_GAINTOOL if (bHaveInput) gainFeed(m_pBuffer_1, nSamples_2, m_pGaintool) ;#endif // // Phase 3: Resample // // resample, but only if we have data. This is a hack -- it ignores // the buffers in the resamplers, and thus looses some data, and time- // shifts other data. This needs to be worked out. tAudioSample *pResampOutput_3 ; if (m_pResampler && bHaveInput) {#ifdef HELIX_FEATURE_RESAMPLER // compiler should optimize one of these branches away. if (NBITS_PER_AUDIOSAMPLE == 32) m_nOutputSamplesLeft_3 += m_pResampler->Resample(m_pBuffer_1, nSamples_2, (signed int*)(m_pBuffer_3 + m_nOutputSamplesLeft_3) ) ; else m_nOutputSamplesLeft_3 += m_pResampler->Resample(m_pBuffer_1, nSamples_2, (signed short*)(m_pBuffer_3 + m_nOutputSamplesLeft_3) ) ; // assert that the resampler did not write out-of-bounds HX_ASSERT(m_nOutputSamplesLeft_3 <= m_ulBufferSize_3) ; // assert that we got at least nSamples_3 samples HX_ASSERT(m_nOutputSamplesLeft_3 >= nSamples_3) ; pResampOutput_3 = m_pBuffer_3 ;#endif } else // estimate the resampler output. { m_ulResamplerPhase += (nSamples_2 / m_nChannels_2_3) * m_ulSampleRate_3_4 ; int sampleFramesOut = m_ulResamplerPhase / m_ulSampleRate_1_2 ; m_ulResamplerPhase -= sampleFramesOut * m_ulSampleRate_1_2 ; m_nOutputSamplesLeft_3 += sampleFramesOut * m_nChannels_2_3 ; pResampOutput_3 = m_pResampler ? m_pBuffer_3 : m_pBuffer_1 ; // pass-through } // m_nOutputSamplesLeft_3 is the total number of resampled samples (including leftovers // from the last time around). Do all further DSP only on nSamples_3 samples, leaving // any leftovers for the next time.#ifdef HELIX_FEATURE_CROSSFADE // We apply the crossfade even if we won't use the data, in order to // kick its timestamp keeping forward. // The performance impact should be negligible, though, since we won't be // in crossfades most of the time. // // if we are at the start of a fade, notify the xfader // // // m_llTimestamp ts+nsamples // +-------------------------------------+ incoming // XFade // | // nSamplesBeforeFade nSamplesInFade // // m_llTimestamp ts+nsamples // +-------------------------------------+ incoming // XFade // |------V----------------------------------| // nSamplesInFade // nSamplesBeforeFade < 0 INT64 nSamplesBeforeFade = m_llFadeStart - m_llTimestamp_3 ; INT64 nSamplesInFade = nSamples_3 - nSamplesBeforeFade ; if (nSamplesBeforeFade >= 0 // fade starts after this segment start && nSamplesInFade > 0) // fade starts before this segment end { // time to start an XFade m_bPastXFade = TRUE ; XFader_start(m_ulXFadeSamples, m_pXFader) ; } // if we have passed the X-Fade point, we always run the signal through // the XFader. Since it has a fast path when the XFade is done, this is // not a resource drain. if (m_bPastXFade) { if (nSamplesBeforeFade < 0) // fade was started earlier { nSamplesInFade += nSamplesBeforeFade ; // == nSamples_3 nSamplesBeforeFade = 0 ; } HX_ASSERT( nSamplesInFade > 0 ); if (XFader_active(m_pXFader)) Fader_feed(pResampOutput_3 + nSamplesBeforeFade, (INT32)nSamplesInFade, m_eCrossFadeDirection == FADE_OUT, m_pXFader) ; }#endif // // Phase 3.5: Run the limiter if needed //#ifdef HELIX_FEATURE_LIMITER if (m_pLimiter && NBITS_PER_AUDIOSAMPLE == 32) { LimiterProcess((int*)pResampOutput_3, nSamples_3, m_pLimiter); } else#endif { // TODO: insert clipping code } // // Phase 4: Mix into the output buffer. // UINT32 nSamples_4 = nSamples_3 / m_nChannels_2_3 * m_nChannels_4 ; if (bHaveInput) { if (!bHadInput && bIsMixBufferDirty) { // if we did not have input earlier, but we now receive data, we need to clean out // the parts that have not been touched so far. memset(pPlayerbuf0,0,pPlayerbuf - (char*)pPlayerbuf0) ; } // and mix into output (mix) buffer switch (m_ulBytesPerSample) { case 2: upmix(pResampOutput_3, (INT16*)pPlayerbuf, m_upmixMachine, nSamples_3, bIsMixBufferDirty) ; break ; case 4: upmix(pResampOutput_3, (INT32*)pPlayerbuf, m_upmixMachine, nSamples_3, bIsMixBufferDirty) ; break ; } // if we have input anywhere, the buffer is not "dirty" anymore. bHadInput = TRUE ; } else { if (bHadInput && bIsMixBufferDirty) { // if we did have input earlier, but do not now, we need to clean the output // buffer (because it will not be marked "dirty" anymore). memset(pPlayerbuf, 0, nSamples_4 * m_ulBytesPerSample) ; } } // save left-over samples m_nOutputSamplesLeft_3 -= nSamples_3 ; m_llTimestamp_3 += nSamples_3 ; // if there is no resampler, there should be no left-over samples if (!m_pResampler) HX_ASSERT(m_nOutputSamplesLeft_3 == 0) ; // if left-over samples if (m_nOutputSamplesLeft_3) memcpy(m_pBuffer_3, m_pBuffer_3 + nSamples_3, m_nOutputSamplesLeft_3 * sizeof(*m_pBuffer_3)) ; nSamplesOutput_4 -= nSamples_4 ; pPlayerbuf += nSamples_4 * m_ulBytesPerSample ; } // if we had input anywhere within this function, the buffer is not dirty anymore. bIsMixBufferDirty &= !bHadInput ; bIsMixBufferDirty = !bIsMixBufferDirty ; return HXR_OK ;}HX_RESULT HXAudioSvcMixEngine::SetCrossFade( enum eCrossfadeDirection inOut, // FADE_IN and FADE_OUT INT64 llStarttimeInSamples, // output side! INT64 llEndtimeInSamples){#if defined(HELIX_FEATURE_CROSSFADE) m_eCrossFadeDirection = inOut ; HX_ASSERT(llStarttimeInSamples % m_nChannels_4 == 0 && llEndtimeInSamples % m_nChannels_4 == 0 ) ; m_llFadeStart = llStarttimeInSamples ; // both are pre-resampler if (llEndtimeInSamples - llStarttimeInSamples > INT_MAX || llEndtimeInSamples - llStarttimeInSamples < 0) { // we don't support such long fades return HXR_FAIL ; } // duration is in part 3 samples m_ulXFadeSamples = (INT32)(llEndtimeInSamples - llStarttimeInSamples) / m_nChannels_4 * m_nChannels_2_3 ; m_bPastXFade = FALSE ; return HXR_OK ;#else return HXR_NOTIMPL ;#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -