📄 waveout.cpp
字号:
// the DSP task.
//
if((dwStartPos == 0) && (dwEndPos == m_ulDmaBufferSize))
{
bIsFirstFill = TRUE;
}
//
// Check to see if there are no more wave headers. If so, then we fill
// the next half of the DMA buffer with silence and set a flag to stop
// the DSP task when we receive the next interrupt. We have to fill the
// DMA buffer with silence since the DSP task will play part of that half
// of the DMA buffer before we are able to stop it...filling with silence
// insures that it will play silence. This code will only be executed
// when we are called by the stream callback...there will be wave headers
// on the list when we are called as a result of WODM_WRITE.
//
if(!m_pWaveNext)
{
//
// Fill the remainder of the DMA buffer with silence.
// Silence 0x0000 for 16 bit PCM streams.
//
memset((char *)((ULONG)m_pBuffer + dwStartPos), (char)0x00,
m_ulDmaBufferSize>> 1);
//
// Set a flag to cause playback to cease at the next interrupt.
//
m_bStopAtNextInterrupt = TRUE;
//
// Save off the previous start and length position.
//
m_dwPreviousStart = dwStartPos;
m_dwPreviousEnd = dwEndPos;
//
// We're done.
//
return;
}
//
// We have more DMA buffers so don't stop at the next interrupt.
//
m_bStopAtNextInterrupt = FALSE;
//
// While the DMA buffer is not full, try to fill it with wave data from
// the wave headers on our input queue.
//
while(!bIsFull)
{
//
// If there are no more wave headers on the input queue, then fill the
// remainder of the DMA buffer with silence.
//
if(!m_pWaveNext)
{
//
// Fill the DMA buffer with silence.
// Silence is 0x0000 for 16 bit PCM streams.
//
memset((char *)m_pBuffer + dwStartPos, (char)0x00,
dwEndPos - dwStartPos);
//
// We're done filling the DMA buffer.
//
break;
}
//
// See if the number of remaining bytes in the current wave header is
// less than the number of unused bytes in the DMA buffer.
//
if(((m_pWaveNext->dwBufferLength - m_pWaveNext->dwBytesRecorded)<<m_ulBufferShift) <
(dwEndPos - dwStartPos))
{
//
// Copy the remainder of the wave data in this wave header to the
// DMA buffer.
//
m_pfnConversion
(
(PVOID)((PUCHAR)m_pBuffer + dwStartPos),
(UCHAR *)(m_pWaveNext->lpData + m_pWaveNext->dwBytesRecorded),
m_pWaveNext->dwBufferLength - m_pWaveNext->dwBytesRecorded
);
//
// Increment the start point in the DMA buffer by the number of
// bytes copied into it.
//
dwStartPos += (m_pWaveNext->dwBufferLength - m_pWaveNext->dwBytesRecorded)<<m_ulBufferShift;
//
// Mark all the bytes in this wave header as being used.
//
m_pWaveNext->dwBytesRecorded = m_pWaveNext->dwBufferLength;
}
else
{
//
// Fill the remainder of the DMA buffer with wave data from this
// wave header.
//
m_pfnConversion
(
(PULONG)((PUCHAR)m_pBuffer + dwStartPos),
(PUCHAR)m_pWaveNext->lpData + m_pWaveNext->dwBytesRecorded,
(dwEndPos - dwStartPos)>>m_ulBufferShift
);
//
// Mark the bytes that were copied from this wave header as being
// consumed so that they will not be copied into the DMA buffer
// again.
//
m_pWaveNext->dwBytesRecorded += (dwEndPos - dwStartPos)>>m_ulBufferShift;
//
// Bump the start position up to the ending position.
//
dwStartPos = dwEndPos;
//
// Indicate that the DMA buffer is now full.
//
bIsFull = TRUE;
}
//
// If the wave data in the current wave header has been completely
// consumed, then we must move on to the next wave header.
//
if(m_pWaveNext->dwBytesRecorded == m_pWaveNext->dwBufferLength)
{
//
// See if we are in the middle of a loop, in which case we do not
// return this wave header since it will be needed again.
//
if(m_dwLoopCount)
{
//
// If this wave header is the last in the loop, then go back to
// the beginning of the loop.
//
if(m_pWaveNext->dwFlags & WHDR_ENDLOOP)
{
//
// Go back to the beginning of the loop.
//
m_pWaveNext = m_pWaveHead;
//
// We've completed a loop, so decrement the number of
// loops.
//
m_dwLoopCount--;
}
else
{
//
// This isn't the last wave header in the loop, so go on to
// the next one.
//
m_pWaveNext = m_pWaveNext->lpNext;
}
}
else
{
m_pWaveNext->dwFlags |= WHDR_DONE;
m_pWaveNext = m_pWaveNext->lpNext;
//
// If the next wave header is the beginning of a loop, then
// setup the loop count.
//
if(m_pWaveNext && (m_pWaveNext->dwFlags & WHDR_BEGINLOOP))
{
m_dwLoopCount = m_pWaveNext->dwLoops - 1;
}
}
//
// If there is another wave header on the list, then set its
// reserved field to zero, so that we will use all the wave data in
// the wave header. We do this here, in addition to in
// WaveOut::Write, since the reserved field will get incremented
// to the size of the wave header's buffer in the processing of
// consuming it's data, and we will want to reconsume all the wave
// data when we re-encounter a wave header in a loop.
//
if(m_pWaveNext)
{
m_pWaveNext->dwBytesRecorded = 0;
}
}
}
//
// Save off the previous start and length position.
//
m_dwPreviousStart = dwStartPos;
m_dwPreviousEnd = dwEndPos;
//
// Now that we've filled the DMA buffer, we need to try and start the DSP
// task, if the wave device is not currently paused and is not currently
// playing.
//
if(!m_bIsPaused && !m_bIsPlaying && !m_bStopAtNextInterrupt)
{
FUNC_WAVEOUT((L"WaveOut::FillDMABuffer Start\r\n"));
m_pCodec->StartPlayback(0);
Sleep(1);
m_Dma.Start();
//
// Indicate that we are currently playing.
//
m_bIsPlaying = TRUE;
}
}
//****************************************************************************
// WaveOut::InterruptHandler
//****************************************************************************
// Interrupt handler for Wave interface.
//
//
void WaveOut::InterruptHandler(void *Handle, BOOL bLastHalf)
{
WaveOut *pWaveOut = (WaveOut *)Handle;
DWORD dwAccessKey;
DWORD dwStartPos, dwEndPos;
EnterCriticalSection( &pWaveOut->m_CriticalSection);
dwAccessKey=GetCurrentPermissions();
SetProcPermissions((ULONG) -1); // access everybody
//
// Remove the completed buffers.
//
pWaveOut->RemoveCompleteBlocks();
if(pWaveOut->m_bStopAtNextInterrupt && !pWaveOut->m_pWaveNext)
{
pWaveOut->m_Dma.Stop();
Sleep(1);
pWaveOut->m_pCodec->StopPlayback(0);
pWaveOut->m_bIsPlaying = FALSE;
FUNC_WAVEOUT((L"WaveOut::IntHander Stop\r\n"));
}
else
{
//
// Find out which half of the DMA buffer we are playing.
//
if(bLastHalf)
{
dwStartPos = pWaveOut->m_ulDmaBufferSize/2;
dwEndPos = pWaveOut->m_ulDmaBufferSize;
}
else
{
dwStartPos = 0;
dwEndPos = pWaveOut->m_ulDmaBufferSize/2;
}
//
// Copy the data into the buffer.
//
pWaveOut->FillDMABuffer(dwStartPos, dwEndPos);
}
//
// change permission back
//
SetProcPermissions(dwAccessKey);
LeaveCriticalSection( &pWaveOut->m_CriticalSection);
return;
}
//****************************************************************************
// WaveOut::RemoveCompleteBlocks
//****************************************************************************
// Removes any blocks that have been completed.
//
//
void WaveOut::RemoveCompleteBlocks()
{
PWAVEHDR pWave;
while (m_pWaveHead != NULL)
{
if (IS_BUFFER_DONE(m_pWaveHead))
{
pWave = m_pWaveHead;
//
// Only remove a block if it's not in a loop.
//
//WODM_MSG((L"MM_WOM_DONE: pWave = 0x%08x\n",(DWORD)pWave));
m_dwBytePosition += m_pWaveHead->dwBytesRecorded;
m_pWaveHead = m_pWaveHead->lpNext;
MARK_BUFFER_DEQUEUED(pWave);
//
// Check to see if the next buffer is at the front.
// If so set it to the next one in the list.
//
if(pWave == m_pWaveNext)
{
m_pWaveNext = m_pWaveHead;
}
//
// Make the callback function call to the Wave API Manager
//
m_pfnCallback(m_hCallback, MM_WOM_DONE, m_dwInstance, (DWORD) pWave, 0);
}
else
{
//
// Only remove from the front of the list, but as many as are done.
//
break; // If the first one's not DONE, then break the loop.
}
}
}
//****************************************************************************
// WaveOut::AddBuffer
//****************************************************************************
// Adds a buffer to the end of the buffer list.
//
//
MMRESULT WaveOut::AddBuffer(WAVEHDR *pWave)
{
//FUNC_WAVEOUT((L"WaveOut::AddBuffer pWave = 0x%08x, playing = 0x%08x ,Pause = 0x%08x\n",(ULONG)pWave, (ULONG)m_bIsPlaying, (ULONG)m_bIsPaused));
PWAVEHDR p;
//
// set some default value assume it is only one node
//
pWave->lpNext = NULL;
pWave->dwFlags &= ~WHDR_DONE;
pWave->dwBytesRecorded=0;
pWave->reserved = (DWORD) FALSE; // mark as not a looped buffer by default.
//
// Add it to the end if the WaveHead is null.
//
if(!m_pWaveHead)
{
m_pWaveHead = m_pWaveNext = pWave;
//
// Set up the loop if this is the start of a loop.
//
if(m_pWaveNext->dwFlags & WHDR_BEGINLOOP)
{
m_dwLoopCount = m_pWaveNext->dwLoops - 1;
}
}
else
{
//
// add the buffer to the tail
//
p = m_pWaveHead;
while(p->lpNext)
p = p->lpNext;
p->lpNext = pWave;
//
// If the next wave header is NULL, then we've consumed all the wave
// data received so far in the loop, so set the next wave header to be
// the just written wave header (so we'll continue the loop with this
// wave header).
//
if(!m_pWaveNext)
{
m_pWaveNext = pWave;
}
}
MARK_BUFFER_QUEUED(pWave);
//FUNC_WAVEOUT((L"-WaveOut::AddBuffer\n"));
return(MMSYSERR_NOERROR);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -