📄 wavein.c
字号:
/*++
Copyright (c) 2001 BSQUARE Corporation. All rights reserved.
Module Name:
wavein.c
Module Description:
This module contains the implementation of the platform
audio input driver.
Author:
Benny Ng 25-June-2001
Revision History:
--*/
#include "chip.h"
#include "audio.h"
//TSAT* 05-Apr-2002 Turn on debug messages
//#undef DEBUGMSG
//#define DEBUGMSG(cond, msg) RETAILMSG(1,msg)
//
// Private Routines.
//
static
VOID
SilentDmaBuffer(
IN OUT PWAVE_RESOURCE WaveResource,
IN PULONG DestBuffer
)
{
ULONG *destData;
ULONG i;
destData = DestBuffer;
i = WaveResource->DmaBufferSize / sizeof(*destData);
for( ; i ; i-- )
*destData++ = 0;
}
//#define AVERAGE_ST_TO_MO
static
SHORT
StereoToMono(
IN USHORT leftSample,
IN USHORT rightSample
)
{
#ifdef AVERAGE_ST_TO_MO
LONG average;
average = leftSample + rightSample;
average /= 2;
return (SHORT)average;
#else
return rightSample;
#endif
}
static
VOID
EmptyDmaBuffer(
IN OUT PWAVE_RESOURCE WaveResource,
IN PUSHORT srcBuffer,
IN ULONG srcLength
)
/*++
--*/
{
BOOLEAN data16;
BOOLEAN stereo;
ULONG samplesPerSecond;
USHORT *srcData;
UCHAR *destData8;
SHORT *destData16;
ULONG averageNum;
ULONG averageCount;
PWAVEHDR Header;
ULONG iterations,i;
SHORT maxsamp=-32700, minsamp=32700;
SHORT sampleLeft,sampleRight;
ULONG destBytesRemaining;
ULONG LeftTotal=0;
ULONG RightTotal=0;
ULONG sampsum=0;
samplesPerSecond = WaveResource->WaveFormat.nSamplesPerSec;
data16 = (WaveResource->WaveFormat.wBitsPerSample == 16);
stereo = (WaveResource->WaveFormat.nChannels == 2);
srcData = srcBuffer;
Header = WaveResource->WaveHeader;
if( Header==NULL )
{
DEBUGMSG( 1, (TEXT("EmptyDmaBuffer: NULL Header.\r\n")));
goto ErrorReturn;
}
DEBUGMSG(1, (
TEXT("EmptyDmaBuffer: Buffer information:\r\n")
TEXT(" Length=%u Recorded=%u 16-bit=%u Stereo=%u")
TEXT(" Rate=%u.\r\n"),
Header->dwBufferLength,
Header->dwBytesRecorded,
(ULONG)data16,
(ULONG)stereo,
samplesPerSecond));
destBytesRemaining = Header->dwBufferLength - Header->dwBytesRecorded;
destData8 = Header->lpData + Header->dwBytesRecorded;
destData16 = (USHORT*)destData8;
//
// Calculate how many incoming samples we will need to average
// to convert from the CoDec rate of 44.1kHz to the stream's
// requesting sampling rate.
//
switch( samplesPerSecond )
{
case 8000:
averageNum = 6; // 44.1kHz / 6 = 7.35kHz (8.12% off)
break;
case 11025:
averageNum = 4; // 44.1kHz / 4 = 11.025kHz (exact)
break;
case 22050:
averageNum = 2; // 44.1kHz / 2 = 22.050kHz (exact)
break;
case 44100:
averageNum = 1; // No need to convert rates
break;
default:
DEBUGMSG(1, (TEXT("EmptyDmaBuffer: Unsupported sample rate %u.\r\n"),
samplesPerSecond ));
break;
}
//
// We have an input buffer full of 44.1kHz, stereo, 16bit samples
// This needs (maybe) converting to the stream's settings
//
iterations = WaveResource->DmaBufferSize / ( averageNum*BYTES_PER_SAMPLE);
for( i=0; i<iterations; i++ )
{
// Check that we aren't at the end of the output buffer already
// If we are then mark this buffer as complete and move on to the next
if( destBytesRemaining == 0 )
{
Header->dwBytesRecorded = Header->dwBufferLength;
Header = Header->lpNext;
if( Header == NULL )
{
DEBUGMSG(1, (TEXT("EmptyDmaBuffer: NULL wave buffer found.\r\n")));
goto dataDone;
}
DEBUGMSG(1, (TEXT("EmptyDmaBuffer: Chained to new wave buffer.\r\n")
TEXT(" Length=%u Recorded=%u.\r\n"),
Header->dwBufferLength,
Header->dwBytesRecorded));
destBytesRemaining = Header->dwBufferLength - Header->dwBytesRecorded;
if( destBytesRemaining == 0)
{
DEBUGMSG(1, (TEXT("EmptyDmaBuffer: Empty buffer found.\r\n")));
break;
}
else
{
destData8 = Header->lpData + Header->dwBytesRecorded;
destData16 = (USHORT*)destData8;
}
}
for( averageCount = 0; averageCount < averageNum; averageCount++ )
{
// Extract left and right samples, junking certain ones
// to adjust the sampling rate
sampleLeft = *srcData++;
sampleRight = *srcData++;
sampsum+=sampleLeft+sampleRight;
if (sampleLeft<minsamp) minsamp=sampleLeft;
if (sampleLeft>maxsamp) maxsamp=sampleLeft;
// RETAILMSG(1,(TEXT("L%D R%D "),(SHORT)sampleLeft,(SHORT)sampleRight));
}
if( data16 )
{
// 16bit destination data
if( stereo )
{
*destData16++ = sampleLeft;
*destData16++ = sampleRight;
}
else
{
// Mono, store average of left and right
sampleLeft = StereoToMono( sampleLeft, sampleRight );
*destData16++ = sampleLeft;
}
}
else
{
// 8bit destination data
if( stereo )
{
*destData8++ = (CHAR)((sampleLeft>>8)+128);
*destData8++ = (CHAR)((sampleRight>>8)+128);
}
else
{
// Mono, store average of left and right
sampleLeft = StereoToMono( sampleLeft, sampleRight );
*destData8++ = (CHAR)((sampleLeft>>8)+128);
}
}
// Adjust bytes remaining according to whether
// stream is 16bit or stereo
destBytesRemaining -= ((stereo ? 2:1) * (data16 ? 2:1 ));
}
Header->dwBytesRecorded = (Header->dwBufferLength - destBytesRemaining);
dataDone:
WaveResource->WaveHeader = Header;
DEBUGMSG(1, (TEXT("EmptyDmaBuffer: DMA buffer emptied.\r\n")
TEXT(" Base0=%X Base1=%X MaxCnt0=%X MaxCnt1=%X BDmaBufferABytes=%X DmaBufferBBytes=%X DMABase0=%X DMABase1=%X DMABufferA=%X DMABufferB=%X Header 0x%X: Length=%u, Recorded=%u maxsamp=%d minsamp=%d diff=%d sum=%d\r\n"),
READ_REGISTER_ULONG(&WaveResource->DmaRegPtr->Base0),READ_REGISTER_ULONG(&WaveResource->DmaRegPtr->Base1),READ_REGISTER_ULONG(&WaveResource->DmaRegPtr->MaxCnt0),READ_REGISTER_ULONG(&WaveResource->DmaRegPtr->MaxCnt1),WaveResource->DmaBufferABytes,WaveResource->DmaBufferBBytes,WaveResource->DmaRegPtr->Base0,WaveResource->DmaRegPtr->Base1,WaveResource->DmaBufferA,WaveResource->DmaBufferB,srcBuffer, Header->dwBufferLength,
Header->dwBytesRecorded,maxsamp,minsamp,maxsamp-minsamp,sampsum ));
ErrorReturn:
return;
}
//
// Exported Routines
//
VOID
WaveInStart(
IN OUT PWAVE_RESOURCE WaveResource,
IN OUT PWAVE_RESOURCE WaveOutResource,
IN OUT PWAVEHDR WaveHeader
)
/*++
Routine Description:
This routine handles the set up of a new wave input stream.
Arguments
WaveResource - Pointer to the wave resource structure corresponding to the
stream to be started.
WaveOutResource - Pointer to the wave resource structure corresponding to the
output stream that will provide a clock for input data.
WaveHeader - Pointer to the wave header information.
Return Value:
None.
--*/
{
DMA_CHANNEL_REG* DmaRegPtr;
DMA_CHANNEL_REG* DmaOutRegPtr;
ULONG *Buffer;
DmaRegPtr = WaveResource->DmaRegPtr;
DmaOutRegPtr = WaveOutResource->DmaRegPtr;
WaveResource->MoreData = TRUE;
//
// Ensure the DMA channel is off and any status bits are cleared.
//
ShutdownDma(WaveResource);
ClearDmaStatus(WaveResource);
ShutdownDma(WaveOutResource);
ClearDmaStatus(WaveOutResource);
WaveResource->NextDMABuf = 0;
//
// Initialize the transfer counts to 0.
//
WRITE_REGISTER_ULONG(&DmaRegPtr->MaxCnt0, 0);
WRITE_REGISTER_ULONG(&DmaRegPtr->MaxCnt1, 0);
WaveResource->BufferAPhysAddr.LowPart = 0;
WaveResource->BufferBPhysAddr.LowPart = 0;
WaveResource->StartBuffer = 0;
WRITE_REGISTER_ULONG(&DmaOutRegPtr->MaxCnt0, 0);
WRITE_REGISTER_ULONG(&DmaOutRegPtr->MaxCnt1, 0);
WaveOutResource->BufferAPhysAddr.LowPart = 0;
WaveOutResource->BufferBPhysAddr.LowPart = 0;
WaveOutResource->StartBuffer = 0;
//
// Store a copy of the specified wave header pointer into the resource
// structure.
//
WaveResource->WaveHeader = WaveHeader;
//
// Get next DMA buffer and set it ready to receive
//
Buffer = GetNextDmaBuffer(WaveResource);
if (Buffer == WaveResource->DmaBufferA) {
WaveResource->StartBuffer = 0;
}
else if (Buffer == WaveResource->DmaBufferB) {
WaveResource->StartBuffer = 1;
}
SetBufferSize( WaveResource, Buffer, WaveResource->DmaBufferSize);
MapTransfer(TRUE, WaveResource, Buffer );
NextDmaBuffer( WaveResource );
//
// Get next DMA buffer and set it ready to receive
//
Buffer = GetNextDmaBuffer(WaveResource);
SetBufferSize( WaveResource, Buffer, WaveResource->DmaBufferSize);
MapTransfer(TRUE, WaveResource, Buffer );
NextDmaBuffer( WaveResource );
//
// Get next output buffer, fill it with silence
// and set it ready to transmit
//
// Buffer = GetNextDmaBuffer(WaveOutResource);
// SilentDmaBuffer(WaveOutResource, Buffer);
// SetBufferSize(WaveOutResource, Buffer, WaveOutResource->DmaBufferSize);
// MapTransfer(TRUE, WaveOutResource, Buffer);
// NextDmaBuffer(WaveOutResource);
//
// Get next output buffer, fill it with silence
// and set it ready to transmit
//
// Buffer = GetNextDmaBuffer(WaveOutResource);
// SilentDmaBuffer(WaveOutResource, Buffer);
// SetBufferSize(WaveOutResource, Buffer, WaveOutResource->DmaBufferSize);
// MapTransfer(TRUE, WaveOutResource, Buffer);
// NextDmaBuffer(WaveOutResource);
DEBUGMSG(1, (TEXT("WaveInStart: Starting DMA.\r\n")));
InitiateDma(WaveResource);
//
// Start the RX DMA
//
StartDmaIn(WaveResource);
//
// Start the TX DMA
// Transmitting data will provide the clock for receive also
//
// StartDma(WaveOutResource);
InterruptDone(WaveResource->SysIntr);
}
VOID
WaveInContinue (
IN OUT PWAVE_RESOURCE WaveResource,
IN OUT PWAVE_RESOURCE WaveOutResource,
IN OUT PWAVEHDR WaveHeader
)
/*++
Routine Description:
This routine handles continuation of a recording audio input stream.
Arguments:
WaveResource - Pointer to the wave resource structure corresponding to the
stream to be started.
WaveOutResource - Pointer to the wave resource structure corresponding to the
output stream that will provide a clock for input data.
WaveHeader - Pointer to the wave header information.
Return Value:
None.
--*/
{
PULONG Buffer;
ULONG BufferLength;
WaveResource->WaveHeader = WaveHeader;
//
// Get full buffer
//
Buffer = GetNextDmaBuffer( WaveResource );
//
// Get full buffer length
//
BufferLength = GetBufferSize( WaveResource, Buffer, 0 ); // last param unused
//
// Empty the buffer
//
EmptyDmaBuffer( WaveResource, (PUSHORT)Buffer, BufferLength );
//
// Give it back to the DMA
//
SetBufferSize( WaveResource, Buffer, WaveResource->DmaBufferSize);
MapTransfer(FALSE, WaveResource, Buffer );
NextDmaBuffer( WaveResource );
//
// Setup the next silent output buffer
//
// Buffer = GetNextDmaBuffer(WaveOutResource);
// SetBufferSize(WaveOutResource, Buffer, WaveOutResource->DmaBufferSize);
// MapTransfer(FALSE, WaveOutResource, Buffer);
// NextDmaBuffer(WaveOutResource);
StartDmaIn(WaveResource);
InterruptDone(WaveResource->SysIntr);
}
VOID
WaveInStop(
IN OUT PWAVE_RESOURCE WaveResource,
IN OUT PWAVE_RESOURCE WaveOutResource
)
/*++
Routine Description:
This routines handles stopping of the audio input stream. DMA transfers are halted
and buffer data is handled appropriately.
Arguments:
WaveResource - Pointer to the wave resource structure corresponding to the
stream to be started.
Return Value:
None.
--*/
{
WaveResource->MoreData = FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -