📄 wavein.cpp
字号:
//**********************************************************************
//
// Filename: wavein.cpp
//
// Description: Implements the WIDM_XXX messages that are passed to the
// wave audio driver via the <f WAV_IOControl> function.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Use of this source code is subject to the terms of the Cirrus end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to
// use this source code. For a copy of the EULA, please see the
// EULA.RTF on your install media.
//
// Copyright(c) Cirrus Logic Corporation 2005, All Rights Reserved
//
//**********************************************************************
#include "wavecommon.h"
//
// Sample conversion functions.
//
void ConvertWordsToBytes
(
PVOID pUnused,
PULONG pulSrc,
PUCHAR pucDst,
PULONG pulSrcSamples,
PULONG pulDstSamples
);
void ConvertWordsToShorts
(
PVOID pUnused,
PULONG pulSrc,
PUSHORT pusDst,
PULONG pulSrcSamples,
PULONG pulDstSamples
);
void ConvertWordsToBytesStereoToMono
(
PVOID pUnused,
PULONG pulSrc,
PUCHAR pucDst,
PULONG pulSrcSamples,
PULONG pulDstSamples
);
void ConvertWordsToShortsStereoToMono
(
PVOID pUnused,
PULONG pulSrc,
PUSHORT pusDst,
PULONG pulSrcSamples,
PULONG pulDstSamples
);
void ConvertShortsToShorts
(
PVOID pUnused,
PUSHORT pusSrc,
PUCHAR pucDst,
PULONG pulSrcSamples,
PULONG pulDstSamples
);
void ConvertShortsToBytesStereoToMono
(
PVOID pUnused,
PUSHORT pusSrc,
PUCHAR pucDst,
PULONG pulSrcSamples,
PULONG pulDstSamples
);
void ConvertShortsStereoToMono
(
PVOID pUnused,
PUSHORT pusSrc,
PUSHORT pusDst,
PULONG pulSrcSamples,
PULONG pulDstSamples
);
void ConvertShortsToBytes
(
PVOID pUnused,
PUSHORT pusSrc,
PUCHAR pucDst,
PULONG pulSrcSamples,
PULONG pulDstSamples
);
#define MAX_RATE_CONVERTER_TAPS 13
#define MAX_POLY_PHASES 23
#define MAX_FILTER_SIZE (MAX_RATE_CONVERTER_TAPS * MAX_POLY_PHASES)
//****************************************************************************
// WaveIn::WaveIn
//****************************************************************************
//
//
//
WaveIn::WaveIn(): m_pCodec(0),
m_pWaveHead(0),
m_pWaveNext(0),
m_pfnCallback(0),
m_hCallback(0),
m_dwInstance(0),
m_dwRecordedBytes(0),
m_bIsRecording(FALSE),
m_dwSourceFactor(0),
m_dwDestFactor(0),
m_pfnWaveCopyFunc(0),
m_bUseSrc(FALSE),
m_pRateConverterBuffer(0),
m_pBuffer(0),
m_pDmaBuffer(0),
m_ulDmaBufferSize(0)
{
FUNC_WAVEIN((L"+WaveIn::WaveIn"));
memset(&m_WaveFormat,sizeof(WAVEFORMATEX), 0);
memset(&m_Src, sizeof(tSRC),0);
//
// Initialize the Critical Section.
//
InitializeCriticalSection(&m_CriticalSection);
FUNC_WAVEIN((L"-WaveIn::WaveIn"));
}
//****************************************************************************
// WaveIn::~WaveIn
//****************************************************************************
//
//
//
WaveIn::~WaveIn()
{
FUNC_WAVEIN((L"+WaveIn::~WaveIn"));
//
// Delete the Critical Section.
//
DeleteCriticalSection(&m_CriticalSection);
if(m_pRateConverterBuffer)
{
delete m_pRateConverterBuffer;
m_pRateConverterBuffer = 0;
}
FUNC_WAVEIN((L"-WaveIn::~WaveIn"));
}
//****************************************************************************
// WaveIn::Initialize
//****************************************************************************
//
//
//
MMRESULT WaveIn::Initialize(CodecInterface * ci, BOOL bPIO)
{
FUNC_WAVEIN((L"+WaveIn::~Initialize"));
BOOL bAC97;
MMRESULT mmRet = MMSYSERR_NOERROR;
//
// Get the information to the codec.
//
m_pCodec = ci;
m_ulDmaBufferSize = DMA_BUFFER_SIZE * (m_pCodec->DmaSampleSize() / 8);
m_bPIO = bPIO;
//
// Initialize the DMA class
//
if(bPIO)
{
//
// For now assume that if it has an SRC then it is an AC97 codec.
//
bAC97 = m_pCodec->HasSRC();
mmRet = m_SwDma.Initialize
(
NULL,
m_ulDmaBufferSize,
bAC97,
FALSE
);
m_pDma = &m_SwDma;
}
else
{
mmRet = m_HwDma.Initialize
(
NULL,
DMA_M2P1_RX_BASE,
m_pCodec->GetDmaPort(),
m_ulDmaBufferSize,
FALSE
);
m_pDma = &m_HwDma;
}
if(mmRet == MMSYSERR_NOERROR)
{
m_pDmaBuffer = m_pDma->GetVirtBuffAddress();
mmRet =m_pDmaBuffer?MMSYSERR_NOERROR: MMSYSERR_NOMEM;
}
//
// If the codec has a sample rate converter there is no need to copy
// extra bytes.
//
if(!m_pCodec->HasSRC())
{
//
// Allocate a buffer that is cached for fast Sample rate conversion.
//
m_pRateConverterBuffer =
new UCHAR[m_ulDmaBufferSize + ((MAX_FILTER_SIZE) * sizeof(ULONG) * 2)];
if(!m_pRateConverterBuffer)
{
mmRet = m_pRateConverterBuffer ? MMSYSERR_NOERROR : MMSYSERR_NOMEM;
}
}
else
{
m_pBuffer = m_pDmaBuffer;
}
//
// Set the callback function to the interrupt handler.
//
m_pDma->SetCallBack(WaveIn::InterruptHandler, (HANDLE )this);
FUNC_WAVEIN((L"-WaveIn::~Initialize"));
return(mmRet);
}
//****************************************************************************
// WaveIn::AddBuffer
//****************************************************************************
//
//
//
MMRESULT WaveIn::AddBuffer
(
PWAVEHDR pWaveHdr,
DWORD dwSize
)
{
FUNC_WAVEIN((L"+WaveIn::AddBuffer"));
PWAVEHDR pTempHdr;
EnterCriticalSection( &m_CriticalSection);
//
// Mark the Wave header nas not done and as in the queue.
//
pWaveHdr->dwFlags &= ~WHDR_DONE;
pWaveHdr->dwFlags |= WHDR_INQUEUE;
pWaveHdr->lpNext = (LPWAVEHDR)NULL;
pWaveHdr->dwBytesRecorded = 0;
//
// If there are currently no wave headers on the list, then start the list
// with this wave header.
//
if(!m_pWaveHead)
{
ASSERT(!m_pWaveNext);
//
// Place the wave header at the start of the list (and therefore also
// at the end)
//
m_pWaveHead = pWaveHdr;
}
else
{
//
// Find the end of the list.
//
for(pTempHdr = m_pWaveHead; pTempHdr->lpNext;
pTempHdr = pTempHdr->lpNext)
{
}
//
// Add this wave header to the end of the list
//
pTempHdr->lpNext = pWaveHdr;
}
//
// If the next list is empty then put the next item on the list in the buffer.
//
if(!m_pWaveNext)
{
m_pWaveNext = pWaveHdr;
}
LeaveCriticalSection( &m_CriticalSection);
FUNC_WAVEIN((L"-WaveIn::AddBuffer"));
return(MMSYSERR_NOERROR);
}
//****************************************************************************
// WaveIn::Close
//****************************************************************************
//
//
//
MMRESULT WaveIn::Close()
{
FUNC_WAVEIN((L"+WaveIn::Close"));
//
// If there are unfilled wave headers then the wave device can not be
// closed.
//
if(m_pWaveHead)
{
return(WAVERR_STILLPLAYING);
}
m_pCodec->m_bRecordOpened= FALSE;
Reset();
//
// Make the callback function call to the Wave API Manager
//
WIDM_MSG((L"WaveIn: WIM_OPEN\r\n"));
m_pfnCallback(m_hCallback, MM_WIM_CLOSE, m_dwInstance, 0, 0);
FUNC_WAVEIN((L"-WaveIn::Close"));
return(MMSYSERR_NOERROR);
}
//****************************************************************************
// WaveIn::GetDevCaps
//****************************************************************************
//
//
//
MMRESULT WaveIn::GetDevCaps
(
PWAVEINCAPS pCaps,
DWORD dwSize
)
{
FUNC_WAVEIN((L"+WaveIn::GetDevCaps"));
MMRESULT mmRet = MMSYSERR_NOERROR;
if (pCaps == NULL || dwSize < sizeof(WAVEINCAPS))
{
//
// If pCaps == NULL, we are requesting if the driver PDD
// is capable of this mode at all. In other words, if
// APIDIR == WAPI_IN, we return no error if input is
// supported, and MMSYSERR_NOTSUPPORTED otherwise. Since
// Odo has both, we return MMSYSERR_NOERROR regardless.
//
mmRet = MMSYSERR_NOTSUPPORTED;
}
if(MMSUCCESS(mmRet))
{
//
// Fill in the DevCaps here.
//
pCaps->wMid = MM_CRYSTAL; // (MMREG.H) Replace MM_MICROSOFT.
pCaps->wPid = MM_CRYSTAL_EP9312_WAVEIN;
pCaps->vDriverVersion = 0x0001;
wsprintf (pCaps->szPname, TEXT("EP9312 Audio (%hs)"), __DATE__);
pCaps->dwFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | // 11km8/16
WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 | // 11ks8/16
WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 | // 22km8/16
WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16 | // 22ks8/16
WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 | // 44km8/16
WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16; // 44ks8/16
pCaps->wChannels = 2;
}
FUNC_WAVEIN((L"-WaveIn::GetDevCaps"));
return(mmRet);
}
//****************************************************************************
// WaveIn::GetPosition
//****************************************************************************
//
//
//
MMRESULT WaveIn::GetPosition
(
MMTIME *pTime,
DWORD dwSize
)
{
FUNC_WAVEIN((L"+WaveIn::GetPosition"));
MMRESULT mmRet;
DWORD dwBytePosition;
if (IsBadWritePtr((PVOID)pTime, sizeof(MMTIME)))
{
PRINTMSG
(
ZONE_WARN,
(
TEXT("WARNING : WaveOut::GetPosition was passed a bad pointer (0x%X)\r\n"),
pTime
)
);
mmRet = MMSYSERR_INVALPARAM;
}
else
{
//
// This is not sample accurate but I don't think windows CE cares.
//
//dwBytePosition = m_dwBytePosition;
dwBytePosition = m_dwRecordedBytes;
switch (pTime->wType)
{
case TIME_BYTES:
pTime->u.cb = dwBytePosition;
break;
case TIME_SAMPLES:
pTime->u.sample = (dwBytePosition * 8) /
(m_WaveFormat.nChannels * m_WaveFormat.wBitsPerSample);
break;
case TIME_MS:
if (m_WaveFormat.nAvgBytesPerSec != 0)
pTime->u.ms = (dwBytePosition * 1000) / m_WaveFormat.nAvgBytesPerSec;
else
{
pTime->wType = TIME_BYTES;
pTime->u.cb = dwBytePosition;
}
break;
case TIME_MIDI:
case TIME_TICKS:
case TIME_SMPTE:
//
// We don't support these, so return TIME_BYTES instead.
//
pTime->wType = TIME_BYTES;
pTime->u.cb = dwBytePosition;
break;
}
mmRet = MMSYSERR_NOERROR;
}
FUNC_WAVEIN((L"-WaveIn::GetPosition"));
return(MMSYSERR_NOERROR);
}
//****************************************************************************
// WaveIn::Open
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -