📄 sound.cpp
字号:
//////////////////////////////////////////////////////////////////////
// Sound.cpp: implementation of the CSound class.
//////////////////////////////////////////////////////////////////////
// Copyright 2000. Moe Wheatley AE4JY <ae4jy@mindspring.com>
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
////////////////////////////////////////////////////////////////////////
// This class implements an object that reads/writes to a soundcard.
//
// The following member functions are used to perform all the tasks:
//
// UINT m_InOpen( WAVEFORMATEX* pWFX, DWORD BufSize, DWORD SampleLimit, INT card);
// LONG m_InRead( double* pData, INT Length );
// void InClose();
//
// UINT m_OutOpen( WAVEFORMATEX* pWFX, DWORD BufSize, DWORD SampleLimit, INT card);
// LONG m_OutWrite( double* pData, INT Length );
// void OutClose();
//
//+++++++++++++ WAVEFORMATEX member variables +++++++++++++++++++
//typedef struct {
// WORD wFormatTag;
// WORD nChannels;
// DWORD nSamplesPerSec;
// DWORD nAvgBytesPerSec;
// WORD nBlockAlign;
// WORD wBitsPerSample;
// WORD cbSize;
//} WAVEFORMATEX;
#include "stdafx.h"
#include "Sound.h"
#include "ErrorCodes.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//local defines
#define TIMELIMIT 2000 // time limit to wait on a new soundcard buffer
// to become ready in milliSeconds.
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSound::CSound()
{
m_InputOpen = FALSE;
m_OutputOpen = FALSE;
m_hwvin = NULL;
m_hwvout = NULL;
m_InEventHandle = NULL;
m_OutEventHandle = NULL;
m_ErrorCode = 0;
InitializeCriticalSection(&m_CriticalSection);
}
CSound::~CSound()
{
DeleteCriticalSection(&m_CriticalSection);
}
//////////////////////////////////////////////////////////////////////
// This function opens a Soundcard for input. Sample size can be
// 1,2 or 4 bytes long depending on bits per sample and number of channels.
//( ie. a 1000 sample buffer for 16 bit stereo will be a 4000 byte buffer)
// Sampling begins immediately so the thread must start calling m_InRead()
// to prevent buffer overflow.
// parameters:
// pWFX = WAVEFORMATEX structure with desired soundcard settings
// BufSize = DWORD specifies the soundcard buffer size number
// in number of samples to buffer.
// 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 read. 0 signifies
// continuous input stream.
// card = Which soundcard to use(0 to n-1) (-1 lets Windows decide)
// returns:
// 0 if opened OK
// ErrorCode if not
//////////////////////////////////////////////////////////////////////
UINT CSound::InOpen( WAVEFORMATEX* pWFX, DWORD BufSize, DWORD SampleLimit, INT card)
{
INT i;
m_InWaiting = FALSE;
m_InOverflow = FALSE;
m_InHeadPtr = 0;
m_InTailPtr = 0;
m_InSamplesRead = 0;
m_InBufPosition = 0;
m_InFormat = *pWFX;
m_InBytesPerSample = (m_InFormat.wBitsPerSample/8)*m_InFormat.nChannels;
m_InBufferSize = BufSize * m_InBytesPerSample;
m_InSampleLimit = SampleLimit;
// event for callback function to notify new buffer available
m_InEventHandle = CreateEvent(NULL, FALSE,FALSE,NULL);
// open sound card input and get handle(m_hwvin) to device
if( (m_ErrorCode = waveInOpen( &m_hwvin, card , pWFX,
(DWORD)&WaveInCallback, (DWORD)this, CALLBACK_FUNCTION ) )
!= MMSYSERR_NOERROR )
{
InClose(); // 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;
}
for(i=0; i<NUM_INPUT_SNDBUFFERS; i++ )
{
// allocate input buffer headers
m_pInputBuffer[i] = NULL;
if( ( m_pInputBuffer[i] = new WAVEHDR[ sizeof(WAVEHDR)] ) == NULL )
{
m_ErrorCode = MEMORY_ERROR;
InClose();
return m_ErrorCode;
}
// allocate input data buffers
m_pInputBuffer[i]->dwBufferLength = m_InBufferSize;
m_pInputBuffer[i]->dwFlags = 0;
m_pInputBuffer[i]->dwUser = NULL;
m_pInputBuffer[i]->dwBytesRecorded = NULL;
if( (m_pInputBuffer[i]->lpData = new char[m_InBufferSize] ) == NULL )
{
m_ErrorCode = MEMORY_ERROR;
InClose();
return m_ErrorCode;
}
if( (m_ErrorCode = waveInPrepareHeader(m_hwvin, m_pInputBuffer[i],
sizeof *m_pInputBuffer[i])) != MMSYSERR_NOERROR )
{
InClose( ); // m_ErrorCode = MMSYSERR_xxx
return m_ErrorCode;
}
if( (m_ErrorCode = waveInAddBuffer(m_hwvin, m_pInputBuffer[i],
sizeof *m_pInputBuffer[i]) )!= MMSYSERR_NOERROR )
{
InClose(); // m_ErrorCode = MMSYSERR_xxx
return m_ErrorCode;
}
}
//
// start input capturing to buffer
if( (m_ErrorCode = waveInStart( m_hwvin) )!= MMSYSERR_NOERROR )
{
InClose(); // m_ErrorCode = MMSYSERR_xxx
return m_ErrorCode;
}
m_InputOpen = TRUE;
return 0;
}
///////////////////////////////////////////////////////////////////////
// Reads 'Length' samples of double data from the opened soundcard input
// returns:
// Length if 'Length' samples were succesfully read
// 0 = if reaches the specified sample limit
// -1 = if there is an error ( use GetError() to retrieve error )
///////////////////////////////////////////////////////////////////////
LONG CSound::InRead( double* pData, INT Length)
{
INT i;
if( !m_InputOpen ) // return -1 if no inputs are active
{
m_ErrorCode = SOUNDIN_ERR_NOTOPEN;
return -1;
}
if( m_InOverflow )
{
m_ErrorCode = SOUNDIN_ERR_OVERFLOW;
InClose();
return -1; // return -1 if overflow
}
EnterCriticalSection(&m_CriticalSection);
if( m_InTailPtr == m_InHeadPtr ) //if no buffer is filled
{
// wait for mmsystem to fill up a new buffer
m_InWaiting = TRUE;
LeaveCriticalSection(&m_CriticalSection);
if( WaitForSingleObject( m_InEventHandle,TIMELIMIT )
!= WAIT_OBJECT_0 )
{
m_ErrorCode = SOUNDIN_ERR_TIMEOUT; // if took too long error out
InClose();
return -1;
}
}
else
LeaveCriticalSection(&m_CriticalSection);
//here if there is data to retrieved
if( m_InFormat.wBitsPerSample == 16 )
{
for( i=0; i < (Length*m_InFormat.nChannels); i++ )
{
m_usTemp.bytes.lsb = *(m_pInputBuffer[m_InTailPtr]->lpData
+ (m_InBufPosition++) );
m_usTemp.bytes.msb = *(m_pInputBuffer[m_InTailPtr]->lpData
+ (m_InBufPosition++) );
*(pData + i) = (double)m_usTemp.both;
}
}
else
{
m_usTemp.bytes.lsb = 0;
for( i=0; i < (Length*m_InFormat.nChannels); i++ )
{
m_usTemp.bytes.msb = *(m_pInputBuffer[m_InTailPtr]->lpData
+ (m_InBufPosition++) ) - 128;
*(pData + i) = (double)m_usTemp.both;
}
}
if( m_InBufPosition >= m_InBufferSize ) //finished with this buffer
{ //so add it back in to the Queue
m_pInputBuffer[m_InTailPtr]->dwBytesRecorded = NULL;
waveInAddBuffer(m_hwvin, m_pInputBuffer[m_InTailPtr], sizeof *m_pInputBuffer[m_InTailPtr]);
m_InBufPosition = 0;
if( ++m_InTailPtr >= NUM_INPUT_SNDBUFFERS) // handle wrap around
m_InTailPtr = 0;
}
m_InSamplesRead += Length;
if( (m_InSampleLimit != 0) && (m_InSamplesRead >= m_InSampleLimit) )
{
InClose();
return 0;
}
return Length;
}
//////////////////////////////////////////////////////////////////////
// Closes the Soundcard Input if open and free up resources.
//
//////////////////////////////////////////////////////////////////////
void CSound::InClose()
{
INT i;
m_InputOpen = FALSE;
if (NULL != m_hwvin)
{
waveInReset(m_hwvin);
Sleep(100);
for( i=0; i<NUM_INPUT_SNDBUFFERS; i++ )
{
if( m_pInputBuffer[i] )
{
if( m_pInputBuffer[i]->lpData != NULL )
{
if( m_pInputBuffer[i]->dwFlags&WHDR_PREPARED )
{
waveInUnprepareHeader(m_hwvin, m_pInputBuffer[i],
sizeof *m_pInputBuffer[i]);
}
if( m_pInputBuffer[i]->lpData )
{
delete m_pInputBuffer[i]->lpData;
m_pInputBuffer[i]->lpData = NULL;
}
}
if( m_pInputBuffer[i] )
{
delete m_pInputBuffer[i];
m_pInputBuffer[i] = NULL;
}
}
}
Sleep(50);
waveInClose(m_hwvin);
Sleep(50);
m_hwvin = NULL;
}
if(m_InEventHandle)
{
CloseHandle(m_InEventHandle);
m_InEventHandle = NULL;
}
}
//////////////////////////////////////////////////////////////////////
// This function opens a Soundcard for writing.
//Sample size can be 1,2 or 4 bytes long depending on bits per sample
// and number of channels.( ie. a 1000 sample buffer for 16 bit stereo
// will be a 4000 byte buffer)
// Output does not start until at least half the buffers are filled
// or m_OutWrite() is called with a length of '0' to flush all buffers.
// parameters:
// pWFX = WAVEFORMATEX structure with desired soundcard settings
// BufSize = DWORD specifies the soundcard buffer size number
// in number of samples to buffer.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -