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

📄 sound.cpp

📁 信道仿真源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//					  If this value is Zero, the soundcard is opened and
//						then closed. This is useful	for checking the
//						soundcard.
//		SampleLimit = limit on number of samples to be written. 0 signifies
//						continuous output stream.
//		card		= Which soundcard to use(0 to n-1) (-1 lets Windows decide)
//    returns:
//        0			if opened OK
//      ErrorCode	if not
//////////////////////////////////////////////////////////////////////
UINT CSound::OutOpen( WAVEFORMATEX* pWFX, DWORD BufSize, DWORD SampleLimit, INT card)
{
	m_OutWaiting = FALSE;
	m_OutUnderflow = FALSE;
	m_OutHeadPtr = 0;
	m_OutTailPtr = 0;
	m_OutSampleLimit = SampleLimit;
	m_OutSamplesWritten = 0;
	m_OutBufPosition = 0;
	m_OutFormat = *pWFX;
	m_OutBytesPerSample = (m_OutFormat.wBitsPerSample/8)*m_OutFormat.nChannels;
	m_OutBufferSize = BufSize * m_OutBytesPerSample;
// Event for callback function to signal next buffer is free
	m_OutEventHandle = CreateEvent(NULL, FALSE,FALSE,NULL);
	if( (m_ErrorCode = waveOutOpen( &m_hwvout, card , pWFX, 
				(DWORD)&WaveOutCallback, (DWORD)this, CALLBACK_FUNCTION ) )
						!= MMSYSERR_NOERROR )
	{
		OutClose();	// m_ErrorCode = MMSYSERR_xxx
		return m_ErrorCode;	
	}

	if( BufSize == 0 )  // see if just a soundcard check
	{
		InClose();	// if so close the soundcard input
		return 0;
	}

// start out paused so don't let output begin until some buffers are filled.
	if( (m_ErrorCode = waveOutPause( m_hwvout ))!= MMSYSERR_NOERROR )
	{
		OutClose();	// m_ErrorCode = MMSYSERR_xxx
		return m_ErrorCode;
	}
// allocate and prepare all the output buffers
	for(INT i=0; i<NUM_OUTPUT_SNDBUFFERS; i++ )
	{
		// allocate output buffer headers
		m_pOutputBuffer[i] = NULL;
		if( (m_pOutputBuffer[i] = new WAVEHDR[ sizeof(WAVEHDR)] ) == NULL )
		{
			OutClose();
			m_ErrorCode = MEMORY_ERROR;
			return m_ErrorCode;	
		}
		// allocate output data buffers
		m_pOutputBuffer[i]->dwBufferLength = m_OutBufferSize;
		m_pOutputBuffer[i]->dwFlags = 0;
		m_pOutputBuffer[i]->dwUser = NULL;
		m_pOutputBuffer[i]->dwLoops = NULL;
		if( (m_pOutputBuffer[i]->lpData = new char[m_OutBufferSize] ) == NULL )
		{
			OutClose();
			m_ErrorCode = MEMORY_ERROR;
			return m_ErrorCode;	
		}
		if(	(m_ErrorCode = waveOutPrepareHeader(m_hwvout, m_pOutputBuffer[i],
						sizeof *m_pOutputBuffer[i]) ) != MMSYSERR_NOERROR )
		{
			OutClose();	// m_ErrorCode = MMSYSERR_xxx
			return m_ErrorCode;	
		}
	}
	m_OutputOpen = TRUE;
	m_fOutputHoldoff = TRUE;
	return(0);
}


///////////////////////////////////////////////////////////////////////
// Writes 'Length' double's to the soundcard output.
//    parameters:
//		pData	= pointer to block of 'Length' double's to output.
//		Length	= Number of samples to write from pData. If is zero
//					then the sound output is flushed and closed.
// Returns:
//		'Length' if data was succesfully placed in the output buffers.
//       0 if output has finished( reached the specified sample limit )
//      -1		 if error ( use GetError() to retrieve error )
///////////////////////////////////////////////////////////////////////
LONG CSound::OutWrite( double* pData, INT Length )
{
INT i;
	if( !m_OutputOpen )		// return -1 if output not running.
	{
		m_ErrorCode = SOUNDOUT_ERR_NOTOPEN;
		return -1;
	}
	if( m_OutUnderflow )
	{
		m_ErrorCode = SOUNDOUT_ERR_UNDERFLOW;
		OutClose();
		return -1;			// return -1 if underflow
	}

	if( Length == 0 )	// need to flush partially filled buffer
	{					// and exit
		OutClose();
		if(m_ErrorCode == NO_ERRORS )
			return Length;
		else
			return -1;
	}else	// here to add new data to soundcard buffer queue
	{
		if(m_OutFormat.wBitsPerSample == 16)
		{
			for( i=0; i < (Length*m_OutFormat.nChannels); i++ )
			{
				m_usTemp.both = (SHORT)(*(pData + i));
				*(m_pOutputBuffer[m_OutHeadPtr]->lpData
					+ (m_OutBufPosition++) ) = m_usTemp.bytes.lsb;
				*(m_pOutputBuffer[m_OutHeadPtr]->lpData
					+ (m_OutBufPosition++) ) = m_usTemp.bytes.msb;
			}
		}
		else
		{
			for( i=0; i < (Length*m_OutFormat.nChannels); i++ )
			{
				m_usTemp.both = (SHORT)(*(pData + i) + 32768.0);
				*( m_pOutputBuffer[m_OutHeadPtr]->lpData + (m_OutBufPosition++) )
										= m_usTemp.bytes.msb;
			}
		}
		if( m_OutBufPosition >= m_OutBufferSize )  //send it if full
		{
			waveOutWrite( m_hwvout, m_pOutputBuffer[m_OutHeadPtr],
							sizeof *m_pOutputBuffer[m_OutHeadPtr] );
			m_OutBufPosition = 0;
			if(	m_fOutputHoldoff )   // holdoff logic doesn't start sound
			{						// until half the buffers are full
				if( m_OutHeadPtr >= NUM_OUTPUT_SNDBUFFERS/2 )
				{
					m_fOutputHoldoff = FALSE;
					waveOutRestart( m_hwvout );
				}
			}
			EnterCriticalSection(&m_CriticalSection);
			if( ++m_OutHeadPtr >= NUM_OUTPUT_SNDBUFFERS)	// handle wrap around
				m_OutHeadPtr = 0;
			if( m_OutHeadPtr == m_OutTailPtr) //if all buffers full then need to wait
			{
				// wait for mmsystem to free up a new buffer
				m_OutWaiting = TRUE;
				LeaveCriticalSection(&m_CriticalSection);
				if( WaitForSingleObject( m_OutEventHandle,TIMELIMIT )
											!= WAIT_OBJECT_0 )
				{
					m_ErrorCode = SOUNDOUT_ERR_TIMEOUT;
					OutClose();
					return -1;
				}
			}
			else
				LeaveCriticalSection(&m_CriticalSection);
		}
		m_OutSamplesWritten += Length;
		if( (m_OutSampleLimit != 0) && (m_OutSamplesWritten >= m_OutSampleLimit) )
		{
			OutClose();
			if(m_ErrorCode == NO_ERRORS )
				return 0;
			else
				return -1;
		}
		return Length;	// return number Samples accepted OK
	}
}


//////////////////////////////////////////////////////////////////////
//  Private function that waits for all the output buffers to finish
//   outputing.  Returns zero if OK else error code.
//////////////////////////////////////////////////////////////////////
UINT CSound::WaitForFlush()
{
	EnterCriticalSection(&m_CriticalSection);
	while( m_OutHeadPtr != m_OutTailPtr )
	{	// wait for all buffers to finish
		// wait for mmsystem to free up a new buffer
		m_OutWaiting = TRUE;
		LeaveCriticalSection(&m_CriticalSection);
		if( WaitForSingleObject( m_OutEventHandle,TIMELIMIT )
									!= WAIT_OBJECT_0 )
		{
			m_ErrorCode = SOUNDOUT_ERR_TIMEOUT;
			return m_ErrorCode;
		}
		EnterCriticalSection(&m_CriticalSection);
	}
	LeaveCriticalSection(&m_CriticalSection);
	return m_ErrorCode;
}

//////////////////////////////////////////////////////////////////////
//  Closes the Soundcard Output if open.
//////////////////////////////////////////////////////////////////////
void CSound::OutClose()
{
	m_OutputOpen = FALSE;
	if(m_hwvout != NULL)
	{
		if( !m_ErrorCode && (m_OutBufPosition > 0) )
		{		// flush out all remaining data in local buffers
			waveOutRestart( m_hwvout );	//make sure soundcard is running
			m_pOutputBuffer[m_OutHeadPtr]->dwBufferLength = m_OutBufPosition;
			waveOutWrite( m_hwvout, m_pOutputBuffer[m_OutHeadPtr],
								sizeof *m_pOutputBuffer[m_OutHeadPtr] );
			if( ++m_OutHeadPtr >= NUM_OUTPUT_SNDBUFFERS)	// handle wrap around
				m_OutHeadPtr = 0;
		}
		m_ErrorCode = WaitForFlush();		//wait to finish
		Sleep(50);
		waveOutReset(m_hwvout);
		Sleep(50);
		for(INT i=0; i<NUM_OUTPUT_SNDBUFFERS; i++ )
		{
			if( m_pOutputBuffer[i] )
			{
				if( m_pOutputBuffer[i]->lpData != NULL )
				{
					if( m_pOutputBuffer[i]->dwFlags&WHDR_PREPARED )
					{
						waveOutUnprepareHeader(m_hwvout, m_pOutputBuffer[i],
							sizeof *m_pOutputBuffer[i]);
					}
					if( m_pOutputBuffer[i]->lpData )
					{
						delete m_pOutputBuffer[i]->lpData;
						m_pOutputBuffer[i]->lpData = NULL;
					}
				}
				if( m_pOutputBuffer[i] )
				{
					delete m_pOutputBuffer[i];
					m_pOutputBuffer[i] = NULL;
				}
			}
		}
		waveOutClose(m_hwvout);
		Sleep(50);
		m_hwvout = NULL;
	}
	if(m_OutEventHandle)
	{
		CloseHandle(m_OutEventHandle);
		m_OutEventHandle = NULL;
	}
}

////////////////////////////////////////////////////////////
//  callback Routine called by mmsystem when a buffer becomes full.
//      no system calls except SetEvent may be called from here.
//  ( not a member function of CSound Class )
////////////////////////////////////////////////////////////
void CALLBACK WaveInCallback( HWAVEIN m_hwvin, UINT uMsg, CSound* pCSound, 
							DWORD dwParam1, DWORD dwParam2 )
{
	if( uMsg == MM_WIM_DATA )	// ignore all but buff full messages
	{
		EnterCriticalSection(&pCSound->m_CriticalSection);
		if( ++pCSound->m_InHeadPtr >= NUM_INPUT_SNDBUFFERS)	//inc ptr
			pCSound->m_InHeadPtr = 0;	// handle wrap around
		if( pCSound->m_InHeadPtr == pCSound->m_InTailPtr )	//chk for overflo
			pCSound->m_InOverflow = TRUE;
		if(pCSound->m_InWaiting)	//if user thread is waiting for buffer
		{
			pCSound->m_InWaiting = FALSE;
			SetEvent( pCSound->m_InEventHandle);	//signal it
		}
		LeaveCriticalSection(&pCSound->m_CriticalSection);
	}
}

////////////////////////////////////////////////////////////
//   callback Routine called by mmsystem when a buffer becomes empty.
//      no system calls except SetEvent may be called from here.
//  ( not a member function of CSound Class )
////////////////////////////////////////////////////////////
void CALLBACK WaveOutCallback( HWAVEOUT m_hwvout, UINT uMsg, CSound* pCSound, 
							DWORD dwParam1, DWORD dwParam2 )
{
	if( uMsg == WOM_DONE )	// ignore all but buffer empty messages
	{
		EnterCriticalSection(&pCSound->m_CriticalSection);
		if( ++pCSound->m_OutTailPtr >= NUM_INPUT_SNDBUFFERS)	//inc ptr
			pCSound->m_OutTailPtr = 0;	// handle wrap around
		if( pCSound->m_OutHeadPtr == pCSound->m_OutTailPtr ) //chk for underflo
			pCSound->m_OutUnderflow = TRUE;
		if(pCSound->m_OutWaiting)	//if user thread is waiting for buffer
		{
			pCSound->m_OutWaiting = FALSE;
			SetEvent( pCSound->m_OutEventHandle);
		}
		LeaveCriticalSection(&pCSound->m_CriticalSection);
	}
}

///////////////////////////////////////////////////////

⌨️ 快捷键说明

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