📄 audbeos.cpp
字号:
m_ulNextWriteOffset += ulAudioBytesWritten1 + ulAudioBytesWritten2;
if (pAudioOutData)
m_bGotAWrite = TRUE;
if (m_ulNextWriteOffset >= m_ulBufferSize)
{
m_ulNextWriteOffset -= m_ulBufferSize;
}
if (m_bFirstWrite)
{
m_bFirstWrite = FALSE;
}
} // lock
else
{
bCanContinue = FALSE;
if (!m_pPendingBufferList)
{
m_pPendingBufferList = new CHXSimpleList;
}
pBuffer->AddRef();
m_pPendingBufferList->AddHead((void*) pBuffer);
}
pBuffer->Release();
pBuffer = NULL;
if (bCanContinue && m_pPendingBufferList && m_pPendingBufferList->GetCount() > 0)
{
pBuffer = (IHXBuffer*) m_pPendingBufferList->RemoveHead();
}
} // while
if (m_bPlaying)
{
UINT32 ulCurrentTime = HX_GET_TICKCOUNT();
if (CALCULATE_ELAPSED_TICKS(m_ulLastTimeSync, ulCurrentTime) > 100)
{
m_ulLastTimeSync = ulCurrentTime;
OnTimeSync();
}
}
//@ This is an ugly hack, but it seems to work very well.
// Hopefully I can figure it out and fix it properly at some point.
// (mclifton 10/5/99)
/*if (pAudioOutData && m_bPlaying && m_pPendingBufferList && m_pPendingBufferList->GetCount() > 0)
{
snooze(50000);
_Imp_Write(NULL);
}
if (pAudioOutData && m_bPlaying && m_pPendingBufferList && m_pPendingBufferList->GetCount() > 0)
{
snooze(50000);
_Imp_Write(NULL);
}*/
return theErr;
}
HX_RESULT
CAudioOutBeOS::_Imp_Reset()
{
m_ulCurrentPlayTime = 0;
m_bFirstWrite = TRUE;
m_ulNextWriteOffset = 0;
if (m_player)
m_player->StopPlaying();
m_bPlaying = FALSE;
return HXR_OK;
}
HX_RESULT
CAudioOutBeOS::_Imp_Drain()
{
return HXR_OK;
}
BOOL
CAudioOutBeOS::_Imp_SupportsVolume()
{
return TRUE;
}
UINT16
CAudioOutBeOS::_Imp_GetVolume()
{
float vol = 0.0f;
if (m_player)
vol = m_player->Gain();
return (UINT16)(vol * 100.0f);
}
HX_RESULT
CAudioOutBeOS::_Imp_SetVolume(const UINT16 uVolume)
{
float vol = (float)uVolume / 100.0f;
if (m_player)
m_player->SetGain(vol);
return HXR_OK;
}
HX_RESULT
CAudioOutBeOS::_Imp_CheckFormat(const HXAudioFormat* pFormat)
{
return HXR_OK;
}
HX_RESULT
CAudioOutBeOS::_Imp_GetCurrentTime(ULONG32& ulCurrentTime)
{
size_t curPos = 0;
if (m_player)
{
if (m_player->IsPlaying())
curPos = m_player->CurrentPosition() * m_ulFrameSize;
// This method of calculating elapsed time was basically copied over from
// the DirectSound code. The bad news is that it is error-prone. Converting
// from bytes to milliseconds is prone to roundoff, leading to an accumulation
// of error, causing a drift of synchronization between audio and video.
// (That DirectSound code has caused me nothing but headaches...)
//m_ulCurrentPlayTime +=
// CalcMs(CalculateElapsedBytes(m_ulLastPlayCursor, curPos));
// The more accurate way to do it is to accumulate elapsed bytes, then
// convert the total to milliseconds. The elapsed bytes is accurate to
// within a video frame or so. Even though it can't be absolutely accurate,
// at least it won't drift over time.
m_ulCurrentPlayTime +=
CalculateElapsedBytes(m_ulLastPlayCursor, curPos);
m_ulLastPlayCursor = curPos;
}
// old method
//ulCurrentTime = m_ulCurrentPlayTime;
// new method
ulCurrentTime = CalcMs(m_ulCurrentPlayTime);
return HXR_OK;
}
UINT16
CAudioOutBeOS::_NumberOfBlocksRemainingToPlay(void)
{
UINT32 res = 0;
size_t curPos = 0;
// add up the number of audio bytes queued up
if (m_pPendingBufferList)
{
LISTPOSITION i = m_pPendingBufferList->GetHeadPosition();
while (i)
{
res += ((IHXBuffer *)m_pPendingBufferList->GetAt(i))->GetSize();
m_pPendingBufferList->GetNext(i);
}
}
// add in the bytes that are currently in the playback buffer
if (m_player)
{
UINT32 playingBytes = 0;
if (m_player->IsPlaying())
curPos = m_player->CurrentPosition() * m_ulFrameSize;
if (curPos < m_ulNextWriteOffset)
playingBytes += m_ulNextWriteOffset - curPos;
else
playingBytes += (m_ulBufferSize - curPos) + m_ulNextWriteOffset;
res += playingBytes;
}
if (m_bGotAWrite)
m_ulOldBytesLeft = res;
else if (res > m_ulOldBytesLeft)
{
fprintf(stderr, "Buffer overflow!\n");
// This is a bad situation - I wish this never happened.
// But what should I do when it does happen?
// I used to return 0, since I thought that would force more
// audio buffers my way, but it also seems to introduce more glitches.
//res = 0;
}
m_bGotAWrite = FALSE;
res /= m_ulBlockSize;
return res;
}
void
CAudioOutBeOS::SetFormat(const HXAudioFormat* pFormat)
{
::memset(&m_gameSoundFormat, 0, sizeof(gs_audio_format));
m_gameSoundFormat.frame_rate = pFormat->ulSamplesPerSec;
m_gameSoundFormat.channel_count = pFormat->uChannels;
switch (pFormat->uBitsPerSample)
{
case 8:
m_gameSoundFormat.format = gs_audio_format::B_GS_U8;
break;
case 16:
m_gameSoundFormat.format = gs_audio_format::B_GS_S16;
break;
}
m_gameSoundFormat.byte_order = B_MEDIA_LITTLE_ENDIAN;
m_gameSoundFormat.buffer_size = 2048;
m_ulFrameSize = m_gameSoundFormat.channel_count * ((m_gameSoundFormat.format==gs_audio_format::B_GS_U8)?1:2);
}
inline UINT32
CAudioOutBeOS::CalcMs(ULONG32 ulNumBytes)
{
return ( (ULONG32) (( 1000.0
/ (m_ulFrameSize
* m_gameSoundFormat.frame_rate) )
* ulNumBytes) );
}
inline UINT32
CAudioOutBeOS::CalculateElapsedBytes(UINT32 ulLastBytePos, UINT32 ulCurrentBytePos)
{
return ((ulCurrentBytePos >= ulLastBytePos) ? (ulCurrentBytePos - ulLastBytePos) : (ulCurrentBytePos + (m_ulBufferSize - ulLastBytePos)));
}
#if _BEOS_AUDIODEV_CALLBACK
void
CAudioOutBeOS::DoTimeSyncs(void)
{
ReschedPlaybackCheck();
OnTimeSync();
return;
}
HX_RESULT
CAudioOutBeOS::ReschedPlaybackCheck()
{
HX_RESULT theErr = HXR_OK;
if (m_bCallbackPending)
return theErr;
*m_pPlaybackCountCBTime += (int)(m_ulGranularity * 1000) / 2;
// Put this back in the scheduler.
HXPlaybackCountCb *pCallback = 0;
pCallback = new HXPlaybackCountCb(TRUE);
if (pCallback)
{
pCallback->m_pAudioDeviceObject = this;
m_bCallbackPending = TRUE;
m_PendingCallbackID = m_pScheduler->AbsoluteEnter(pCallback, *((HXTimeval *)m_pPlaybackCountCBTime));
}
else
theErr = HXR_OUTOFMEMORY; // but ignored, why?
return theErr;
}
CAudioOutBeOS::HXPlaybackCountCb::HXPlaybackCountCb(BOOL timed)
: m_lRefCount(0)
, m_pAudioDeviceObject(0)
, m_timed(timed)
{
}
CAudioOutBeOS::HXPlaybackCountCb::~HXPlaybackCountCb()
{
}
/*
* IUnknown methods
*/
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::QueryInterface
// Purpose:
// Implement this to export the interfaces supported by your
// object.
//
STDMETHODIMP CAudioOutBeOS::HXPlaybackCountCb::QueryInterface(REFIID riid, void** ppvObj)
{
if (IsEqualIID(riid, IID_IHXCallback))
{
AddRef();
*ppvObj = (IHXCallback*)this;
return HXR_OK;
}
else if (IsEqualIID(riid, IID_IUnknown))
{
AddRef();
*ppvObj = this;
return HXR_OK;
}
*ppvObj = NULL;
return HXR_NOINTERFACE;
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::AddRef
// Purpose:
// Everyone usually implements this the same... feel free to use
// this implementation.
//
STDMETHODIMP_(ULONG32) CAudioOutBeOS::HXPlaybackCountCb::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::Release
// Purpose:
// Everyone usually implements this the same... feel free to use
// this implementation.
//
STDMETHODIMP_(ULONG32) CAudioOutBeOS::HXPlaybackCountCb::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
/*
* IHXPlaybackCountCb methods
*/
STDMETHODIMP CAudioOutBeOS::HXPlaybackCountCb::Func(void)
{
if (m_pAudioDeviceObject)
{
if (!m_timed)
{
m_pAudioDeviceObject->_Imp_Write(NULL);
}
else
{
m_pAudioDeviceObject->_Imp_Write(NULL);
m_pAudioDeviceObject->m_bCallbackPending = FALSE;
m_pAudioDeviceObject->DoTimeSyncs();
}
}
return HXR_OK;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -