📄 wavepdd.cpp
字号:
while ( (cbSrcBytes > 0) && (pwh != NULL)) {
if (pwh->dwBytesRecorded >= pwh->dwBufferLength) {
pwh = pwh->lpNext;
continue;
}
// trasfer max(data_in_dma, room_in_buffer)
ULONG cbDstBytes = pwh->dwBufferLength - pwh->dwBytesRecorded;
ULONG cbTransferSize = min(cbSrcBytes, cbDstBytes);
memcpy(pwh->lpData + pwh->dwBytesRecorded, pSrcBuffer, cbTransferSize);
pwh->dwBytesRecorded += cbTransferSize;
pSrcBuffer += cbTransferSize;
cbSrcBytes -= cbTransferSize;
}
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
VOID
private_WaveStart (
WAPI_INOUT apidir,
PWAVEHDR pwh
)
{
FUNC_WPDD("+PDD_WaveStart");
const ULONG ulInterruptPeriod = 5; // how often should we generate interrupts?
PWAVEFORMATEX pFormat = g_pwfx[apidir];
ULONG ulSamplesPerInterrupt = pFormat->nSamplesPerSec * ulInterruptPeriod / 1000;
g_dmapos[apidir] = 0;
if ( apidir == WAPI_OUT ) {
// for playback, pre-fill dma buffers with first bucket of data
private_AudioFillBuffer(pwh, g_dma_buffer[WAPI_OUT], dma_buffer_size);
}
pCES1371->SetDMAChannelFormat( g_dmachannel[apidir],
pFormat->nChannels,
(pFormat->wBitsPerSample==8)?0:1,
pFormat->nSamplesPerSec );
// Initialize the DMA position to fire interrupt
pCES1371->SetDMAChannelBuffer( g_dmachannel[apidir], dma_buffer_size, ulSamplesPerInterrupt);
DEBUGMSG(ZONE_VERBOSE,(TEXT("ES1371: %s @ %s%02d %dHz, %d samples/interrupt\n\r"),
(apidir == WAPI_IN) ? TEXT("Recording") : TEXT("Playing"),
(pFormat->nChannels == 1) ? TEXT("M") : TEXT("S"),
pFormat->wBitsPerSample,
pFormat->nSamplesPerSec,
ulSamplesPerInterrupt
));
pCES1371->StartDMAChannel( g_dmachannel[apidir] );
FUNC_WPDD("-PDD_WaveStart");
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
VOID
private_WaveContinue (
WAPI_INOUT apidir,
PWAVEHDR pwh
)
{
FUNC_VERBOSE("+PDD_WaveContinue");
ULONG size1, size2;
ULONG newpos = pCES1371->GetDMAPosition(g_dmachannel[apidir]);
ULONG lastpos = g_dmapos[apidir];
g_dmapos[apidir] = newpos;
// if dma position has wrapped past the end of the buffer,
// we'll have to perform two transfers
// otherwise, just transfer to the new position
// note that we treat new==last as a full wrap - we transfer the entire buffer
if (newpos <= lastpos) {
size1 = dma_buffer_size - lastpos;
size2 = newpos;
}
else {
size1 = newpos - lastpos;
size2 = 0;
}
g_pfnDmaTransfer[apidir](pwh, g_dma_buffer[apidir] + lastpos, size1);
if (size2 > 0) {
g_pfnDmaTransfer[apidir](pwh, g_dma_buffer[apidir], size2);
}
FUNC_VERBOSE("-PDD_WaveContinue");
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
VOID
private_WaveStop(
WAPI_INOUT apidir
)
{
FUNC_WPDD("+private_WaveStop");
pCES1371->StopDMAChannel( g_dmachannel[apidir] );
FUNC_WPDD("-private_WaveStop");
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
VOID
private_WaveStandby(
WAPI_INOUT apidir
)
{
//
// We are going to be idle. so power off what we can.
//
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
MMRESULT
private_WaveOpen(
WAPI_INOUT apidir,
LPWAVEFORMATEX lpFormat,
BOOL fQueryFormatOnly
)
{
MMRESULT mmRet = MMSYSERR_NOERROR;
FUNC_WPDD("+PDD_WaveOpen");
//
// Allow PCM, mono or stereo, 8 or 16 bit at 11k or 22k Hz
//
if ((lpFormat->wFormatTag != WAVE_FORMAT_PCM) ||
(lpFormat->nChannels != 1 && lpFormat->nChannels != 2) ||
(lpFormat->nSamplesPerSec < 4000 || lpFormat->nSamplesPerSec > 48000) ||
(lpFormat->wBitsPerSample != 16 && lpFormat->wBitsPerSample != 8) )
{
mmRet = WAVERR_BADFORMAT;
goto EXIT;
}
//
// Only checking if format is supported
//
if (fQueryFormatOnly)
{
goto EXIT;
}
//
// The hardware can support input and output at the sametime
// but not multiple output and inputs return MMSYSERR_ALLOCATED
// if the input or output is alread in use.
//
if (g_fInUse[apidir])
{
mmRet = MMSYSERR_ALLOCATED;
goto EXIT;
}
g_fInUse[apidir] = TRUE;
//
// Save format the device was opened in
//
g_pwfx[apidir] = lpFormat;
g_silence = (lpFormat->wBitsPerSample == 8) ? 0x80 : 0;
EXIT:
FUNC_WPDD("-PDD_WaveOpen");
return mmRet;
}
void private_waveOutGetVolume(PULONG pvol)
{
*pvol = g_VolumeSettings.dwMasterVolume;
}
void private_waveOutSetVolume(ULONG vol)
{
USHORT rvol,lvol;
UCHAR rindex,lindex;
USHORT nVolume;
lindex = (UCHAR)((0xF8000000 - (vol & 0xF8000000)) >> 27);
rindex = (UCHAR)((0x0000F800 - (vol & 0x0000F800)) >> 11);
lvol = volumeLUT[lindex] << 8;
rvol = volumeLUT[rindex];
nVolume = lvol | rvol;
g_VolumeSettings.dwMasterVolume = vol;
g_VolumeSettings.fMasterMute = (vol == 0);
if (vol == 0) {
nVolume |= 0x8000; // bit 15 means mute. Use this to get total attenuation.
}
// write master volume
pCES1371->WriteCodecRegister( AC97_MASTER_VOL_STEREO, nVolume );
}
void
SetMute (UCHAR reg, BOOL muted)
{
USHORT vol;
vol = pCES1371->ReadCodecRegister(reg);
if (muted) {
vol |= 0x8000; // set mute bit
}
else {
vol &= ~0x8000; // clear mute bit
}
pCES1371->WriteCodecRegister(reg, vol);
}
void UpdateInputSelect(void)
{
USHORT input_select;
ULONG volume, regval;
switch (g_VolumeSettings.dwInputSelect) {
case WPDMX_LINE_MIC:
input_select = AC97_RECMUX_MIC;
if (g_VolumeSettings.fMicMute) {
volume = 0;
}
else {
volume = g_VolumeSettings.dwMicVolume & 0xffff;
volume = volume | (volume << 16); // incoming volume is mono, cvt. to stereo
}
break;
case WPDMX_LINE_IN:
input_select = AC97_RECMUX_LINE;
if (g_VolumeSettings.fLineInMute) {
volume = 0;
}
else {
volume = g_VolumeSettings.dwLineInVolume;
}
break;
default:
DEBUGMSG(ZONE_ERROR, (TEXT("UpdateInputSelect: illegal setting %04x\r\n"), g_VolumeSettings.dwInputSelect));
return;
}
if (volume == 0) {
regval = 0x8000;
}
else {
regval = ((volume >> 20) & 0x0F00) | ((volume >> 12) & 0x000F);
}
DEBUGMSG(ZONE_VOLUME, (TEXT("UpdateInputSelect: sel=%04x vol=%04x\r\n"), input_select, regval));
pCES1371->WriteCodecRegister(AC97_RECORD_SELECT, input_select);
pCES1371->WriteCodecRegister(AC97_RECORD_GAIN, (USHORT) regval);
}
MMRESULT
private_SetMixerValue(DWORD dwControl, DWORD dwSetting)
{
DWORD dwControlType = dwSetting & WPDMX_CTL_MASK;
DWORD dwLine = dwSetting & WPDMX_LINE_MASK;
DEBUGMSG(ZONE_VOLUME, (TEXT("private_SetMixerValue(%04x, %08x)\r\n"), dwControl, dwSetting));
switch (dwControl) {
// volume controls
case WPDMX_MASTER_VOL:
private_waveOutSetVolume(dwSetting);
break;
case WPDMX_LINEIN_VOL:
g_VolumeSettings.dwLineInVolume = dwSetting;
UpdateInputSelect();
break;
case WPDMX_MIC_VOL:
g_VolumeSettings.dwMicVolume = dwSetting;
UpdateInputSelect();
break;
// Mute controls
case WPDMX_MASTER_MUTE:
g_VolumeSettings.fMasterMute = dwSetting;
SetMute(AC97_MASTER_VOL_STEREO, g_VolumeSettings.fMasterMute);
break;
case WPDMX_LINEIN_MUTE:
g_VolumeSettings.fLineInMute = dwSetting;
UpdateInputSelect();
break;
case WPDMX_MIC_MUTE:
g_VolumeSettings.fMicMute = dwSetting;
UpdateInputSelect();
break;
// The input Mux
case WPDMX_INPUT_MUX:
g_VolumeSettings.dwInputSelect = dwSetting;
UpdateInputSelect();
break;
default:
DEBUGMSG(ZONE_ERROR, (TEXT("private_SetMixerValue: unsupported control %d\r\n"), dwControl));
return MMSYSERR_NOTSUPPORTED;
}
return MMSYSERR_NOERROR;
}
MMRESULT
private_GetMixerValue(DWORD dwControl, PDWORD pdwSetting)
{
switch (dwControl) {
case WPDMX_MASTER_VOL:
private_waveOutGetVolume(pdwSetting);
break;
case WPDMX_MASTER_MUTE:
*pdwSetting = g_VolumeSettings.fMasterMute;
break;
case WPDMX_LINEIN_VOL:
*pdwSetting = g_VolumeSettings.dwLineInVolume;
break;
case WPDMX_LINEIN_MUTE:
*pdwSetting = g_VolumeSettings.fLineInMute;
break;
case WPDMX_MIC_VOL:
*pdwSetting = g_VolumeSettings.dwMicVolume;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -