📄 mixengine.cpp
字号:
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] ;
}
#endif
HX_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 + -