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

📄 cx5530audio.cpp

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	
    return  true;
}


//////////////////////////////////////////////////////////////////
//  ReadAC97 - reads a 16-bit value from a register on an 
//      AC97 compliant audio codec.
//  Input:  Index - register index to read
//          Codec - index of codec to read (primary or secondary)
//  Output: return TRUE for success or FALSE if CODEC timed out
//  Notes:  
////////////////////////////////////////////////////////////////
bool CCX5530Audio::ReadAC97(USHORT Index, USHORT &wReadValue)
{
    USHORT  i=0;
    int readCount;
	union CodecStatus status;
	
	// Index has only 7 bit for register address;
    if(Index > 0x7F ) 
	{
        ERRMSG1("ReadAC97: Register Index Out Of Range For Read: %d", Index);
        return  false;
    }
	
   	CriticalSectionAcquisition csa(&m_csCX5530Audio);
	
	// wait for the codec to finish processing previous command
	
	// loop until either we tried CODEC_TIMEOUT_COUNT times, 
	// or the command becomes invalid (that is, it's been sent)
	readCount = CODEC_TIMEOUT_COUNT;
	
	while(readCount > 0 && m_pAudioRegisters->regCodecCommand.fields.bCommandValid)
	{	
		readCount--;
		Sleep(1);
    }
    
	// command still not sent?
	if (m_pAudioRegisters->regCodecCommand.fields.bCommandValid)
	{
		ERRMSG("Codec Not Allowing Read");
        return  false;
    }
	
	while (readCount > 0)
	{
		// tell the codec we want to read AC97 register Index
		// we do that by setting the MSB of the index
		if (!WriteAC97(Index | CODEC_RD, 0))
		{
			ERRMSG("Can't write command!");
			return false;
		}
		
   	    // Wait for a valid reply, check AC CODEC access time out
        for(i=0; i < CODEC_TIMEOUT_COUNT; i++ ) 
		{
			// read the status value
			status.dwValue = m_pAudioRegisters->regCodecStatus.dwValue;
			//INFMSG1("Status read is 0x%8.8x", status.dwValue);
			
			// is is new and valid? if so, see if it's for us
			if (status.fields.bStatusValid && Index == status.fields.StatusAddress)
			{
				// all's well, we got data; return it
				wReadValue = status.fields.Status;
				return true;
			}
			
			// not valid or not ours; wait a bit, retry
			//INFMSG3("Bad status: new = %u, valid = %u, index = %u", 
			//	status.fields.bStatusNew,
			//	status.fields.bStatusValid,
			//	status.fields.StatusAddress);
			
			Sleep(1);
		}
		// timeout or data not ours; retry up to readCount times
		readCount--;
    }
	ERRMSG1("Codec Read Failed, status is 0x%8.8x", status.dwValue);
	return  false;
}

// since the class is a singleton class, we need a function to get an
// object (*the* object) of the class. This is it.

CCX5530Audio* CCX5530Audio::GetCX5530AudioObject()
{
//	FUNCMSG("+CCX5530Audio::GetCX5530AudioObject()");
	if (!m_pSingleObject)
	{
		m_pSingleObject = new CCX5530Audio();
		if (!m_pSingleObject || !m_pSingleObject->Initialize())
		{
			ERRMSG("Error creating or initializing single CX5530Audio object!");
			delete m_pSingleObject;
			m_pSingleObject = NULL;
		}
	}
//	FUNCMSG1("-CCX5530Audio::GetCX5530AudioObject(): 0x%8.8x", m_pSingleObject);
	return m_pSingleObject;
}

void CCX5530Audio::DeleteObject()
{
	delete m_pSingleObject;
	m_pSingleObject = NULL;
}

UINT CCX5530Audio::GetMaxBuffers()
{
	return MAX_PLAYBACK_CHANNELS;	// the maximum number of supported buffers
}

bool CCX5530Audio::SetupCapture(USHORT uChannelIndex, WORD nChannels, WORD wBitsPerSample, DWORD wFrequency)
{
	//	WORD outputRateValue;
    FUNCMSG2("+CCX5530Audio::SetupCapture() channel %d, freq: %d", uChannelIndex, wFrequency);
	
	ASSERT(uChannelIndex < MAX_CAPTURE_CHANNELS);
	
	// this device only supports stereo 16 bit capture
    ASSERT (2 == nChannels && 16 == wBitsPerSample);

	m_pCodec->SetSampleRate(true, WORD(wFrequency));
		
	FUNCMSG("-CCX5530Audio::SetupPlay()");
	return true;
}

bool CCX5530Audio::SetupPlay(USHORT uChannelIndex, WORD nChannels, WORD wBitsPerSample,  DWORD wFrequency, bool bLoop)
{
	//	WORD outputRateValue;
    FUNCMSG2("+CCX5530Audio::SetupPlay() channel %d, %s", uChannelIndex, bLoop?TEXT("LOOPING"):TEXT("NOT LOOPING"));
	
	ASSERT(uChannelIndex < MAX_PLAYBACK_CHANNELS);
	
	// this device only supports stereo 16 bit playback
    ASSERT (2 == nChannels && 16 == wBitsPerSample);
	
	m_pCodec->SetSampleRate(false, WORD(wFrequency));
		
	FUNCMSG("-CCX5530Audio::SetupPlay()");
	return true;
}

void CCX5530Audio::InterruptThreadRoutine(void)
{
	CHardwareBuffer *pBuffer = NULL;
	
	FUNCMSG("+CCX5530Audio::InterruptThreadRoutine()");
	
	while (true) 
	{
        switch(WaitForSingleObject(m_hInterruptEvent, INFINITE))
		{
		case WAIT_OBJECT_0:
			
			if (m_bExiting)
				return;
			
		case WAIT_TIMEOUT:
			
			while ((pBuffer = GetInterruptSource()) != NULL)	// process all interrupt sources
			{
				pBuffer->ProcessInterrupt();
				 
			}
			// complete the interrupt
			InterruptDone(m_dwInterrupt);
			break;
		default:
			ERRMSG("InterruptThread wait failed!");
			// what now? We should abort;
			Sleep(1);
        }
    }
}

CHardwareBuffer *CCX5530Audio::GetInterruptSource()
{
	FUNCMSG("+CCX5530Audio::GetInterruptSource()");
	UINT i;

	// who caused the interrupt?
	// since NSC doesn't report the SMI source anymore, we need to poll the DMA channels 
	// and see which one's DMA table entry has changed

#ifdef DEBUG
//	DumpRegisters();
#endif


	// check what busmaster set the interrupt
	//INFMSG1("wSMI is 0x%4.4x", wSMI);
	for (i = 0; i < MAX_CAPTURE_CHANNELS; i++)
	{
		if (m_CaptureChannels[i] && m_CaptureChannels[i]->HasInterrupt())
		{
			// Ok, found one
			INFMSG1("Interrupt from capture channel %d", i);
			return dynamic_cast<CHardwareBuffer*>(m_CaptureChannels[i]);
		}

	}
	for (i = 0; i < MAX_PLAYBACK_CHANNELS; i++)
	{
		if (m_PlaybackChannels[i] && m_PlaybackChannels[i]->HasInterrupt())
		{
			INFMSG1("Interrupt from playback channel %d", i);
			// Ok, found one
			return  dynamic_cast<CHardwareBuffer*>(m_PlaybackChannels[i]);
		}
	}
/*

	if (!intsrc.pChannel)
	{
		//ERRMSG("No busmaster generated the interrupt!");
		intsrc.intType = INT_UNKNOWN;
		return intsrc;
	}

	BYTE bStatus = intsrc.pChannel-> .regBusMasterStatus;	// this clears the end of page flag
//	INFMSG1("CCX5530Audio::GetInterruptSource() status 0 is %2.2x", bStatus);
		
	if (bStatus & BUSMASTER_ERROR)
	{
		INFMSG("BUSMASTER_ERROR");
		intsrc.intType = INT_EOL;
	}
	else if (bStatus & BUSMASTER_EOP)
	{
		intsrc.intType = INT_FLAG;
	}
		
	// Note: there are two ways to stop DMA on the CX5530: one is to set an EOT (as this driver does)
	// the other is to simply ignore the first interruptl the second one causes BUSMASTER_ERROR 
	// in this case you'd probably change the error message
	else
	{
		ERRMSG("Unknown flag in interrupt!");
		intsrc.intType = INT_UNKNOWN;
	}
	return intsrc;
*/
	INFMSG("Unknown interrupt source");

	return NULL;
}

#if 0
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	Function:

	CCX5530Audio::RegisterIntHandler

	Description:
	Allows a driver buffer to request notification for an interrupt.

	Arguments:

	LPVOID lpObject :
	INTHANDLER pFunction :	NULL to unregister

	Return Value: bool
-------------------------------------------------------------------*/
bool CCX5530Audio::RegisterIntHandler(LPVOID lpObject, INTHANDLER *pFunction)
{
	//	FUNCMSG("+CCX5530Audio::RegisterIntHandler");
	if (lpObject == NULL)
		return false;
	if (pFunction == NULL)	// somebody wants to unregister
	{
		for (int i = 0; i < sizeof(m_IntHandlers)/sizeof(m_IntHandlers[0]); i++)
			if (m_IntHandlers[i].m_Object == lpObject)
			{
				m_IntHandlers[i].m_Object = m_IntHandlers[i].m_pFunction = NULL;
			}
	}
	else
	{
		for (int i = 0; i < sizeof(m_IntHandlers)/sizeof(m_IntHandlers[0]); i++)
			if (m_IntHandlers[i].m_Object == NULL)
			{
				m_IntHandlers[i].m_Object = lpObject;
				m_IntHandlers[i].m_pFunction = pFunction;
				break;
			}
	}
	//	FUNCMSG("-CCX5530Audio::RegisterIntHandler");
	return true;
}
#endif

HRESULT CCX5530Audio::SetVolumePan(USHORT uChannel, PDSVOLUMEPAN pdsVolumePan)
{

/*
	typedef struct 
	{
	DWORD       dwTotalLeftAmpFactor;
	DWORD       dwTotalRightAmpFactor;
	LONG        lVolume;
	DWORD       dwVolAmpFactor;
	LONG        lPan;
	DWORD       dwPanLeftAmpFactor;
	DWORD       dwPanRightAmpFactor;
	}DSVOLUMEPAN, *PDSVOLUMEPAN;

	The DirectSound API specifies volume in hundredths of decibels (dB), 
	where 0 is the original volume of the stream (no adjustment done). Positive decibels correspond 
	to amplification, and negative decibels correspond to attenuation. The decibel (dB) scale corresponds 
	to the logarithmic hearing characteristics of the ear: positive decibels . An attenuation of 10 dB 
	makes a buffer sound half as loud; an attenuation of 20 dB makes a buffer sound one quarter as loud. 
	DirectSound volumes range from 0 (0 dB, no volume adjustment) to -10000 (-100 dB, basically silent). 
	Amplification is not currently supported. 

	The DirectSound API also specifies pan in hundredths of dB, in the range of -10000 to 10000. 
	Zero is the neutral value; a pan of 0 means that both channels are at full volume (that is, 
	they are attenuated by 0 dB). At any other setting, one of the channels is at full volume and the 
	other is attenuated. For example, a pan of -2173 means that the left channel is at full volume and the 
	right channel is attenuated by 21.73 dB. Similarly, a pan of 870 means that the left channel is attenuated by 8.7 dB 
	and the right channel is at full volume. A pan of -10000 means that the right channel is silent (the sound is 
	"all the way to the left"), and a pan of 10000 means that the left channel is silent (the sound is "all the way 
	to the right"). Many readers may consider this behavior to be "balance" rather than "pan". 

	The volume and pan values are passed to DirectSound drivers in a DSVOLUMEPAN structure. 
	Although both are specified, if the buffer only supports one or the other, the values reflect only the supported control.
	The structure specifies the input volume and pan (in hundredths of dB) in the lVolume and lPan members. 
	It also provides the linear equivalents in a fixed point 16.16 representation in the dwVolAmpFactor member (for volume) 
	and the dwPanLeftAmpFactor and dwPanRightAmpFactor members (for pan). Finally, since volume and pan are cumulative, 
	it specifies the total combined linear factors in the dwTotalLeftAmpFactor and dwTotalRightAmpFactor members. 
	Drivers should use the values that are most convenient
*/
	
	HRESULT hr = DS_OK;
	if (!g_pDriverContext)
	{
		ERRMSG("CCX5530Audio::SetVolumePan: mixer context is NULL!");
		return DSERR_NODRIVER;
	}
	
	switch (uChannel)
	{
	case 0:	// main channel, set the volume of the PCM player
		if (NO_ERROR != SetMixerVolume(g_pDriverContext, PCM_VOLUME, pdsVolumePan->dwTotalLeftAmpFactor, pdsVolumePan->dwTotalRightAmpFactor))
			hr = DSERR_GENERIC;
		break;
	default:
		ERRMSG1("CCX5530Audio::SetVolumePan: Unknown channel(%d)", uChannel);
		hr = DSERR_GENERIC;
	}
	return hr;
}

void CCX5530Audio::CleanUpObject()
{
	DeleteCriticalSection(&m_csCX5530Audio);

	if (m_hInterruptThread)
	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -