📄 hxaudstr.cpp
字号:
{
return HXR_WOULD_BLOCK;
}
if (m_DryNotificationMap.GetCount() > 0)
{
IHXDryNotification* pDryNotification = 0;
CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap.Begin();
for (; lIter != m_DryNotificationMap.End(); ++lIter)
{
pDryNotification = (IHXDryNotification*) (*lIter);
pDryNotification->OnDryNotification(ulLastWriteTime, ulNumMsRequired);
}
if (m_Owner->GetState() != E_PLAYING)
{
return HXR_OK;
}
}
}
}
m_Owner->DataInAudioDevice(TRUE);
// /////////////////////////////////////////////////////////////
// There may be no buffers in the list. No packets? Play silence.
// Still need to increment time.
if ( m_pDataList->IsEmpty() && m_pInstantaneousList->IsEmpty() )
{
m_llLastWriteTime += CAST_TO_INT64 m_ulGranularity;
//{FILE* f1 = ::fopen("e:\\MixIntoBuffer.txt", "a+"); ::fprintf(f1, "%lu\t%p\t%lu\n", HX_GET_BETTERTICKCOUNT(), this, (UINT32)m_llLastWriteTime);::fclose(f1);}
return HXR_NO_DATA;
}
UCHAR* pSourceBuffer = 0;
ULONG32 ulMaxBytes = 0;
ULONG32 ulMaxFramesIn = 0;
ULONG32 ulMaxFramesOut = 0;
ULONG32 ulNumBytesMixed = 0;
BOOL bMonoToStereoMayBeConverted = TRUE;
BOOL bResampleBufferDirty = FALSE;
// /////////////////////////////////////////////////////////////
// If no resampling, mix stream data directly into the player
// buffer.
if ( !m_pResampler)
{
pSourceBuffer = pPlayerBuf;
ulMaxBytes = m_ulInputBytesPerGran;
/* For only those sound cards which do not
* support stereo - a RARE (non-existent) case
*/
if (m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1)
{
/* We should never reach here since this case
* should be handled by the Resampler
* Temporary ASSERT...
*/
HX_ASSERT(FALSE);
}
/* Mono->Stereo conversion*/
else if (m_bChannelConvert)
{
HX_ASSERT(ulMaxBytes <= ulBufSize/2);
/* Avoid GPF in retail builds! */
if (ulMaxBytes > ulBufSize/2)
{
ulMaxBytes = ulBufSize/2;
}
}
else
{
HX_ASSERT(ulMaxBytes <= ulBufSize);
/* Avoid GPF in retail builds! */
if (ulMaxBytes > ulBufSize)
{
ulMaxBytes = ulBufSize;
}
}
}
#if defined(HELIX_FEATURE_RESAMPLER)
// /////////////////////////////////////////////////////////////
// If resampling, mix stream data into a tmp buffer. Then
// resample this buffer and mix the final resampled buffer into
// the player buffer.
else
{
bMonoToStereoMayBeConverted = FALSE;
// memset(m_pTmpResBuf, 0, HX_SAFESIZE_T(m_ulMaxBlockSize));
pSourceBuffer = m_pTmpResBuf;
/*
* Audio Session will always ask for m_ulOutputBytesPerGran bytes to be mixed
* in MixIntoBuffer() call. So we need to produce these many number of bytes.
* If there is any mono-stereo conversion that happens in the mixing, number
* of output bytes required from the resampler are half the number of
* m_ulOutputBytesPerGran bytes.
*/
if (m_pResampler)
{
ulMaxFramesOut = m_ulOutputBytesPerGran/(m_DeviceFmt.uBitsPerSample==8 ? 1 : 2);
if (m_DeviceFmt.uChannels == 2)
{
ulMaxFramesOut /= 2;
}
ulMaxFramesIn = m_pResampler->Requires(ulMaxFramesOut);
ulMaxBytes = ulMaxFramesIn * ((m_AudioFmt.uBitsPerSample==8)? 1 : 2)
* m_AudioFmt.uChannels;
}
else
{
ulMaxBytes = m_ulInputBytesPerGran;
}
HX_ASSERT(ulMaxBytes <= m_ulMaxBlockSize);
}
#endif /* HELIX_FEATURE_RESAMPLER */
// /////////////////////////////////////////////////////////////
// Mix n bytes of data into buffer
ulNumBytesMixed = MixData(pSourceBuffer, ulMaxBytes, bMonoToStereoMayBeConverted,
(!m_pResampler) ? bIsMixBufferDirty : bResampleBufferDirty);
/*
if (ulNumBytesMixed > 0)
{
::fwrite(pSourceBuffer, ulNumBytesMixed, 1, fdbefore);
}
*/
#if defined(HELIX_FEATURE_RESAMPLER)
// /////////////////////////////////////////////////////////////
// If we need to resample , then do this and then mix data into
// the player buffer.
// Only resample and mix if volume is *not* zero and there
// are some bytes to mix.
if (m_pResampler && ulNumBytesMixed > 0 && m_uVolume > 0 && !m_bMute)
{
if(ulNumBytesMixed < ulMaxBytes && 8==m_AudioFmt.uBitsPerSample)
{
//fill remainder with 128's (-1), silence:
UCHAR* pTmp = &pSourceBuffer[ulNumBytesMixed];
ULONG32 ulNumBytesLeftToSilence = ulMaxBytes-ulNumBytesMixed;
do
{
*pTmp = 128;
pTmp++;
} while(--ulNumBytesLeftToSilence);
}
ULONG32 ulOutBytes = 0;
if (m_pResampler)
{
ulOutBytes = m_pResampler->Resample((UINT16*)pSourceBuffer,
ulMaxBytes,
(UINT16*)m_pResampleBuf);
/*
FILE* fp = fopen("c:\\temp\\audio.txt", "w+");
::fwrite(m_pResampleBuf, ulOutBytes, 1, fp);
fclose(fp);
*/
/* Resampler will do stereo to mono conversion for us.*/
HX_ASSERT(ulMaxFramesOut == (ulOutBytes / 2 /
(m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1 ? 1 : m_AudioFmt.uChannels))) ;
}
if (m_bChannelConvert)
{
HX_ASSERT(ulOutBytes*2 <= ulBufSize);
if ( ulOutBytes > ulBufSize/2 )
{
ulOutBytes = ulBufSize/2;
}
}
else
{
HX_ASSERT(ulOutBytes <= ulBufSize);
ulOutBytes = ulBufSize;
}
BOOL bBeforeMixBufferDirty = bIsMixBufferDirty;
UINT32 ulMixedNumBytes = 0;
#if defined(HELIX_FEATURE_MIXER)
ulMixedNumBytes = CHXMixer::MixBuffer( m_pResampleBuf, pPlayerBuf,
ulOutBytes, m_bChannelConvert,
m_uVolume, m_DeviceFmt.uBitsPerSample, bIsMixBufferDirty);
#else
::memcpy(pPlayerBuf, m_pResampleBuf, ulOutBytes); /* Flawfinder: ignore */
bIsMixBufferDirty = TRUE;
ulMixedNumBytes = ulOutBytes;
#endif /* HELIX_FEATURE_MIXER */
// If we mixed only a partial buffer, make the remaining buffer silent
if (!bBeforeMixBufferDirty && ulMixedNumBytes < ulBufSize)
{
::memset(pPlayerBuf+ulMixedNumBytes, 0, ulBufSize-ulMixedNumBytes);
}
}
afterMixing:
#endif /* HELIX_FEATURE_RESAMPLER */
#ifdef _TESTING
if ( g_log > 0 )
{
write( g_log, pPlayerBuf, ulNumBytesMixed);
}
#endif
/* This is for *FROM* stream */
if (bGetCrossFadeData)
{
m_bFadeAlreadyDone = TRUE;
}
/* If we are cross-fading, we have data from this stream in pPlayerBuf
* Now get data to be cross-faded from *From* stream in
* m_pCrossFadeBuffer
*/
#if defined(HELIX_FEATURE_CROSSFADE) && defined(HELIX_FEATURE_MIXER)
else if (bCrossFadeThisTime)
{
/* Allocate CrossFade Buffer */
if (!m_pCrossFadeBuffer)
{
m_ulCrossFadeBufferSize = ulBufSize;
m_pCrossFadeBuffer = new UCHAR[m_ulCrossFadeBufferSize];
}
memset(m_pCrossFadeBuffer, 0, HX_SAFESIZE_T(m_ulCrossFadeBufferSize));
UINT32 ulCrossFadeLen = m_ulCrossFadeBufferSize;
UINT32 ulTmpBufTime = 0;
BOOL bIsDrity = FALSE;
m_pCrossFadeStream->MixIntoBuffer(m_pCrossFadeBuffer,
ulCrossFadeLen, ulTmpBufTime, bIsDrity, TRUE);
/* Now it is time to perform cross-fading between
* pPlayerBuf and m_pCrossFadeBuffer
*/
UINT32 ulStartByteToFade = 0;
UINT32 ulNumMsInThisBuffer = CalcDeviceMs(ulBufSize);
UINT32 ulNumBytesToBeCrossFaded = ulBufSize;
UINT32 ulSampleSize = ((m_DeviceFmt.uBitsPerSample==8)? 1 : 2)
* m_DeviceFmt.uChannels;
/* Make sure we have integral number of samples */
HX_ASSERT(ulBufSize == (ulBufSize/ulSampleSize) * ulSampleSize);
/* Only partial buffer needs to be cross-faded.
* -------------
* ~~_____________|
*
* -----------
* |___________~~
*
*
* -----
* |_____| <-- Granularity size block that is mixed.
*
* <--> Only partial block needs to be faded
*/
if (ulTimeActuallyFaded < ulNumMsInThisBuffer)
{
ulNumBytesToBeCrossFaded = (UINT32) (ulBufSize *
(ulTimeActuallyFaded*1./ulNumMsInThisBuffer)) ;
UINT32 ulOutOfPhase = ulNumBytesToBeCrossFaded % ulSampleSize;
if (ulOutOfPhase > 0)
{
ulNumBytesToBeCrossFaded =
ulNumBytesToBeCrossFaded - ulOutOfPhase;
}
ulStartByteToFade = ulBufSize - ulNumBytesToBeCrossFaded;
}
if (ulTimeActuallyFaded > m_ulCrossFadeDuration)
{
ulNumBytesToBeCrossFaded = (UINT32) (ulBufSize *
(m_ulCrossFadeDuration*1./ulNumMsInThisBuffer)) ;
UINT32 ulOutOfPhase = ulNumBytesToBeCrossFaded % ulSampleSize;
if (ulOutOfPhase > 0)
{
ulNumBytesToBeCrossFaded =
ulNumBytesToBeCrossFaded - ulOutOfPhase;
}
}
UINT16 uNumSamples = (UINT16) (ulNumBytesToBeCrossFaded/
ulSampleSize);
BOOL bWasDirty = bIsMixBufferDirty;
/* Mix the initial bytes that are not cross-faded*/
if (ulStartByteToFade > 0)
{
CHXMixer::MixBuffer( m_pCrossFadeBuffer, pPlayerBuf,
ulStartByteToFade, FALSE, 100, 8, bWasDirty);
}
m_pCrossFader->CrossFade((INT16*) (m_pCrossFadeBuffer+ulStartByteToFade),
(INT16*) (pPlayerBuf+ulStartByteToFade),
uNumSamples);
/* make sure we have silence in bytes that were not touched */
if (!bIsMixBufferDirty &&
(ulStartByteToFade + (uNumSamples*ulSampleSize)) < ulBufSize)
{
::memset(pPlayerBuf+ulStartByteToFade + (uNumSamples*ulSampleSize), 0,
ulBufSize - (ulStartByteToFade + (uNumSamples*ulSampleSize)));
}
bIsMixBufferDirty = TRUE;
}
if (bGetCrossFadeData || bCrossFadeThisTime)
{
if (bGetCrossFadeData)
{
HX_ASSERT(m_llLastWriteTime >= m_llCrossFadeStartTime);
if (m_llLastWriteTime >= m_llCrossFadeStartTime)
{
HX_ASSERT(m_llLastWriteTime - m_llCrossFadeStartTime < MAX_TIMESTAMP_GAP);
ulTimeActuallyFaded = INT64_TO_UINT32(m_llLastWriteTime - m_llCrossFadeStartTime);
}
}
if (ulTimeActuallyFaded >= m_ulCrossFadeDuration)
{
m_bCrossFadingToBeDone = FALSE;
HX_RELEASE(m_pCrossFadeStream);
/* We should release any extra buffers if it is a
* *from* stream
*/
if (!m_bFadeToThisStream)
{
/* Do not remove any instantaenous buffers */
FlushBuffers(FALSE);
}
}
else
{
m_ulCrossFadeDuration -= ulTimeActuallyFaded;
m_llCrossFadeStartTime += CAST_TO_INT64 ulTimeActuallyFaded;
}
}
else if (m_bCrossFadingToBeDone && !m_bFadeToThisStream)
{
m_pCrossFadeStream->SyncStream(m_llLastWriteTime);
}
#endif /* HELIX_FEATURE_CROSSFADE && HELIX_FEATURE_MIXER */
//{FILE* f1 = ::fopen("e:\\MixIntoBuffer.txt", "a+"); ::fprintf(f1, "%lu\t%p\t%lu\n", HX_GET_BETTERTICKCOUNT(), this, (UINT32)m_llLastWriteTime);::fclose(f1);}
return HXR_OK;
}
/************************************************************************
* Method:
* CHXAudioStream::MixData
* Purpose:
* Mix all valid data in my auxilliary list into the buffer.
*
* Thoughts:
* while there are buffers available
* if (buffertime is more than endtime) break;
* if (any part of buffer is >startime and < endtime)
* we are in business.
* mix that part of the buffer, update offset,
* update max of num bytes written in this round.
* Looks like we need to keep LastWrite time and offsets for all buffers
* that get written in one pass.
* Consider this scenario:
*
*
----------------- -----------------
|________________| |_______________| -> Skew 1
________ __________
|_______| |_________| ->Skew 2 5
____________________________________
|__________________|_|_______________| Skew in opposite direction 3
_______
|_______| 4
____________
|____________| <- Buffer to be mixed currently
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -