⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wavein.c

📁 windows ce 下ARM9音频驱动代码
💻 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 + -