📄 waveout.c
字号:
/*++
Copyright (c) 2001, 2002, 2004 BSQUARE Corporation. All rights reserved.
Module Name:
waveout.c
Module Description:
This module contains the implementation of the platform
audio output driver.
Author:
Benny Ng 25-june-2001
Revision History:
Yuqun Cao 22-Mar-2002
1. WaveOutStart(): Prime DMA buffers before starting DMA engine.
This gets rid of the noise heard during the wave start sometimes.
2. Changes not check for WaveIn portion of the driver, because it
does not work anyway.
Jason Browne Jan-2004
Fixed DMA buffering issue
--*/
#include "audio.h"
#include "chip.h"
#include "ac97.h"
//Turn on debug messages
//#undef DEBUGMSG
//#define DEBUGMSG(cond, msg) RETAILMSG(cond, msg)
//
// Private Routines.
//
VOID
AudioDataSend(
IN OUT PWAVE_RESOURCE WaveResource,
PULONG NextBuffer,
ULONG FillAmount)
{
UCHAR ucTmp = 0;
ULONG ulTmp = 0;
ULONG LoopCount = 0;
PUSHORT DataBuffer = (PUSHORT) NextBuffer;
volatile ULONG * pAACSR1 = &(WaveResource->AacRegPtr->AACSR1);
volatile ULONG * pAACDR1 = &(WaveResource->AacRegPtr->AACDR1);
DEBUGMSG(1, (TEXT("AudioDataSend: FillAmount=%u.\r\n"), FillAmount));
for (LoopCount = 0; LoopCount <= (FillAmount >> 1); LoopCount++)
{
while ((*pAACSR1) & AAC_SR_TXFF) // wait for fifo not full
{
}
ulTmp = (*DataBuffer) & 0xFFFFF;
DataBuffer++;
*pAACDR1 = ulTmp;
} // endfor
}
typedef enum {
PCM_TYPE_M8,
PCM_TYPE_M16,
PCM_TYPE_S8,
PCM_TYPE_S16
} PCM_TYPE, *PPCM_TYPE;
static
ULONG
FillDmaBuffer(
IN OUT PWAVE_RESOURCE WaveResource,
OUT PUCHAR pBuffer
)
{
int WaveToDmaExpansionShift;
int WaveXferSize;
int DmaXferSize;
ULONG DmaXferByteCount = 0;
PINT16 volatile pDmaBuffer = (PINT16) pBuffer;
PINT16 volatile pDmaBufferSave = (PINT16) pBuffer;
PUCHAR pDmaEnd = pBuffer + DMA_BUFFER_SIZE;
PUCHAR pRawSample8;
PINT16 pRawSample16;
int NumIterations,NumIterationsSave;
INT16 Sample16;
int AvailableDmaSpace;
BOOL WaveXferComplete = FALSE;
PWAVEHDR pWaveHeader;
PCM_TYPE pcmtype;
ULONG SamplesPerSecond;
ULONG SamplesRateValue;
pWaveHeader = WaveResource->WaveHeader;
WaveXferSize = (pWaveHeader->dwBufferLength - pWaveHeader->dwBytesRecorded);
if(WaveXferSize ==0) {
return 0;
}
SamplesPerSecond = WaveResource->WaveFormat.nSamplesPerSec;
//
// All data going to the CODEC is in 16-bit stereo. Determine the
// expansion factor for wave sample info to CODEC sample data.
//
if (WaveResource->WaveFormat.wBitsPerSample == 8) {
if (WaveResource->WaveFormat.nChannels == 1) {
pcmtype = PCM_TYPE_M8;
WaveToDmaExpansionShift = 2;
}
else {
pcmtype = PCM_TYPE_S8;
WaveToDmaExpansionShift = 1;
}
}
else {
if (WaveResource->WaveFormat.nChannels == 1) {
pcmtype = PCM_TYPE_M16;
WaveToDmaExpansionShift = 1;
}
else {
pcmtype = PCM_TYPE_S16;
WaveToDmaExpansionShift = 0;
}
}
//
// Setup the Sample per second rate
//
switch (SamplesPerSecond) {
case 8000:
SamplesRateValue = 0x1F40;
break;
case 11025:
SamplesRateValue = 0x2B11;
break;
case 22050:
SamplesRateValue = 0x5622;
break;
case 44100:
SamplesRateValue = 0xAC44;
break;
default:
DEBUGMSG(1, (TEXT("FillDmaBuffer: Unsupported sample rate %u.\r\n"), SamplesPerSecond));
break;
} // end switch (SamplesPerSecond)
//
// Fill the buffer
//
DEBUGMSG(1, (TEXT("FillDmaBuf: Len=%u Recorded=%u\r\n"),
pWaveHeader->dwBufferLength,
pWaveHeader->dwBytesRecorded));
//
// Calculate the amount of data to transfer
//
DmaXferSize = WaveXferSize << WaveToDmaExpansionShift;
AvailableDmaSpace = DMA_BUFFER_SIZE - DmaXferByteCount;
pRawSample8 = pWaveHeader->lpData + pWaveHeader->dwBytesRecorded;
pDmaBuffer = (PINT16) pBuffer + DmaXferByteCount;
pDmaBufferSave = (PINT16) pBuffer + DmaXferByteCount;
DEBUGMSG(1, (TEXT("WaveXferSize=%u DmaXferSize=%u AvailableDmaSpace=%u\r\n"),
WaveXferSize,DmaXferSize,AvailableDmaSpace));
DEBUGMSG(1, (TEXT("FillDmaBuffer: pDmaBuffer: 0x%8.8X\r\n"), pDmaBuffer));
if (DmaXferSize <= AvailableDmaSpace) {
//
// Transfer all data.
//
// 16-bit samples, two samples per loop iteration (thus divide by 4).
NumIterations = DmaXferSize >> 2;
DmaXferByteCount += DmaXferSize;
pWaveHeader->dwBytesRecorded += WaveXferSize;
DEBUGMSG(1, (TEXT("1:NumIter=%u DmaXferByteCnt=%u ExpanShift=%u dwBytesRecorded=%u\r\n"),
NumIterations,
DmaXferByteCount,
WaveToDmaExpansionShift,
pWaveHeader->dwBytesRecorded));
}
else {
//
// Transfer maximum allowable DMA size.
//
// 16-bit samples, two samples per loop iteration (thus divide by 4).
NumIterations = AvailableDmaSpace >> 2;
DmaXferByteCount += AvailableDmaSpace;
pWaveHeader->dwBytesRecorded += AvailableDmaSpace >> WaveToDmaExpansionShift;
DEBUGMSG(1, (TEXT("2:NumIter=%u DmaXferByteCnt=%u ExpanShift=%u dwBytesRecorded=%u\r\n"),
NumIterations,
DmaXferByteCount,
WaveToDmaExpansionShift,
pWaveHeader->dwBytesRecorded));
}
//
// NumIterations is calculated for the loops below. Two iterations per
// loop, so NumIterations has be be multiplied by two to get the number
// of samples.
//
NumIterationsSave=NumIterations;
switch (pcmtype) {
case PCM_TYPE_M8:
for (; NumIterations > 0; NumIterations--) {
Sample16 = BITS_8_TO_16(*pRawSample8);
*pDmaBuffer++ = Sample16;
*pDmaBuffer++ = Sample16;
pRawSample8++;
}
break;
case PCM_TYPE_S8:
for (; NumIterations > 0; NumIterations--) {
*pDmaBuffer++ = BITS_8_TO_16(*pRawSample8);
pRawSample8++;
*pDmaBuffer++ = BITS_8_TO_16(*pRawSample8);
pRawSample8++;
}
break;
case PCM_TYPE_M16:
pRawSample16 = (PINT16) pRawSample8;
for (; NumIterations > 0; NumIterations--) {
Sample16 = *pRawSample16++;
*pDmaBuffer++ = Sample16;
*pDmaBuffer++ = Sample16;
}
break;
case PCM_TYPE_S16:
//
// Since there's no expansion for stereo 16-bit data,
// just do memcpy.
//
memcpy(pDmaBuffer, pRawSample8, NumIterations << 2);
pDmaBuffer += NumIterations << 1;
break;
default:
break;
}
DEBUGMSG(1, (TEXT("FillDmaBuf:ByteRet=%u\r\n"),DmaXferByteCount));
return DmaXferByteCount;
}
//
// Exported Routines.
//
MMRESULT
GetOutputVolume(
IN PWAVE_DEVICE_INSTANCE WaveInstance,
OUT PULONG VolumeSetting
)
/*++
Routine Description:
Arguments:
VolumeSetting - Pointer to the volume variable.
Return Value:
Returns MMSYSERR_NOERROR if successful, MMSYSERR_NOMEM if
unsuccessful. Note that this is probably not a good error
code to return, but it's the best of the bunch to choose from.
--*/
{
ULONG Volume;
Volume = CodecGetVolume(WaveInstance->CodecDevice);
*VolumeSetting = MAKEWORD(Volume, Volume);
DEBUGMSG(1, (TEXT("GetOutputVolume: Volume=0x%x VolumeSetting=0x%x\r\n"),
Volume, *VolumeSetting));
return MMSYSERR_NOERROR;
}
MMRESULT
SetOutputVolume(
IN PWAVE_DEVICE_INSTANCE WaveInstance,
IN ULONG VolumeSetting
)
/*++
Routine Description:
Takes the input volume setting and sets the UCB attenuation
accordingly. The input volume has a scale from 0 to 0xFFFF,
where 0 is for silence and 0xFFFF for the highest volume
setting. Note that the high order 16-bits are masked
because for stereo sound, it is the right channel volume.
Arguments:
VolumeSetting - Requested volume variable.
Return Value:
Returns MMSYSERR_NOERROR if successful, MMSYSERR_NOMEM if
unsuccessful. Note that this is probably not a good error
code to return, but it's the best of the bunch to choose from.
--*/
{
BOOLEAN Success;
Success = CodecSetVolume(WaveInstance->CodecDevice, VolumeSetting);
if (Success == FALSE) {
DEBUGMSG(1, (TEXT("SetOutputVolume: Failed codec write.\r\n")));
return MMSYSERR_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -