📄 audrec.cpp
字号:
// AudRec.cpp : implementation file
//
#include "stdafx.h"
#include "AudRec.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAudRec
CAudRec::CAudRec() : m_nBuffSize(0)
,m_nBuffNum(0)
,m_nDataQueueNum(0)
,m_nDeviceID(0)
,m_szAryInData(NULL)
,m_pAryHdr(NULL)
,m_hRecord(NULL)
,m_funCallBackDataWork(NULL)
,m_hwndParent(NULL)
,m_bSaveFile(FALSE)
,m_bRecording(FALSE)
,m_eStatus(ENUM_STATUS_INVALID)
,m_hWaveFile(NULL)
{
memset( &m_Format, 0, sizeof(WAVEFORMATEX) );
ZeroMemory(&m_MMCKInfoParent,sizeof(m_MMCKInfoParent));
ZeroMemory(&m_MMCKInfoChild,sizeof(m_MMCKInfoChild));
}
CAudRec::~CAudRec()
{
StopAndFreeAll();
}
BEGIN_MESSAGE_MAP(CAudRec, CWnd)
//{{AFX_MSG_MAP(CAudRec)
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CAudRec::PreTranslateMessage(MSG* pMsg)
{
if( (pMsg->message >= MM_WOM_OPEN) && (pMsg->message <= MM_MOM_DONE) )
{
switch ( pMsg->message )
{
case MM_WIM_DATA:
OnMM_WIM_DATA ( pMsg->wParam, pMsg->lParam );
break;
case MM_WIM_CLOSE:
m_eStatus = ENUM_STATUS_READY;
m_nDataQueueNum = 0;
m_bRecording = FALSE;
break;
case MM_WOM_DONE:
break;
case MM_WOM_CLOSE:
m_eStatus = ENUM_STATUS_READY;
m_bRecording = FALSE;
break;
case MM_WIM_OPEN:
break;
case MM_WOM_OPEN:
break;
}
}
return CWnd::PreTranslateMessage(pMsg);
}
BOOL CAudRec::Record()
{
if( m_eStatus == ENUM_STATUS_RECORDING )
{
TRACE ( "Already Recording ...\n" );
return TRUE;
}
m_bRecording = TRUE;
MMRESULT mmReturn = 0;
if( m_eStatus != ENUM_STATUS_READY )
{
AfxMessageBox ( "Class status error" );
return FALSE;
}
SetRecordFormat( m_Format );
if( !SetRelateParaAfterGetWaveFormat() )
{
return FALSE;
}
//打开设备
mmReturn = ::waveInOpen( &m_hRecord, m_nDeviceID, &m_Format,
(DWORD)GetSafeHwnd(), NULL, CALLBACK_WINDOW );
if ( mmReturn )
{
waveErrorMsg( mmReturn, "waveInOpen()");
goto failed;
}
else
{
// //设置缓冲区并加入输入队列
for(UINT i=0; i < m_nBuffNum; i++)
{
AddInputBufferToQueue( i );
}
//开始录音
mmReturn = ::waveInStart( m_hRecord );
if ( mmReturn )
{
waveErrorMsg( mmReturn, "waveInStart() failed");
goto failed;
}
}
m_eStatus = ENUM_STATUS_RECORDING;
if( TRUE == m_bSaveFile )
{
CreateWaveFile();
}
return TRUE;
failed:
FreeBuffer();
return FALSE;
}
void CAudRec::Stop()
{
if ( m_eStatus != ENUM_STATUS_RECORDING )
{
return;
}
if( m_eStatus == ENUM_STATUS_RECORDING )
{
SetTimer ( TIMER_EVENT_STOPREC, 1000, NULL );
}
Invalidate ( TRUE );
m_eStatus = ENUM_STATUS_STOPING;
}
void CAudRec::StopAndFreeAll()
{
if ( m_hRecord )
{
StopRec();
}
FreeBuffer();
}
void CAudRec::StopRec()
{
if ( !m_hRecord )
{
return;
}
if ( m_eStatus != ENUM_STATUS_RECORDING && m_eStatus != ENUM_STATUS_STOPING )
{
return;
}
MMRESULT mmReturn = 0;
mmReturn = ::waveInReset ( m_hRecord );
if ( mmReturn )
{
waveErrorMsg ( mmReturn, "waveInReset() failed" );
}
//关键,给线程退出时间
::Sleep ( 10 );
::mmioAscend( m_hWaveFile, &m_MMCKInfoChild, 0 );
::mmioAscend( m_hWaveFile, &m_MMCKInfoParent, 0 );
::mmioClose( m_hWaveFile, 0 );
m_hWaveFile = NULL;
mmReturn = ::waveInClose ( m_hRecord );
m_hRecord = NULL;
if( mmReturn )
{
waveErrorMsg ( mmReturn, "waveInClose() failed" );
}
}
/////////////////////////////////////////////////////////////////////////////
// CAudRec message handlers
BOOL CAudRec::Create(HWND hwndParent, LPRECT lpRect)
{
LPCTSTR lpszClassName = AfxRegisterWndClass(
0,
LoadCursor(AfxGetInstanceHandle(), IDC_ARROW),
NULL,
NULL);
CRect rc(0, 0, 0, 0);
if( lpRect )
{
rc = *lpRect;
}
if( !CreateEx( 0, lpszClassName, "", WS_CHILD | WS_TABSTOP,
rc.left, rc.top, rc.Width(), rc.Height(),
hwndParent, NULL, NULL) )
{
AfxMessageBox("Creat the Record Wnd failed!");
return FALSE;
}
if( lpRect )
{
ShowWindow( SW_SHOW );
}
else
{
ShowWindow( SW_HIDE );
}
//GetClientRect ( &m_rcClient );
return TRUE;
}
/*
CAudRec m_rec;
WAVEFORMATEX wf;
wf.ss = 11025
wf.bits = 16
CALLBACK rr(dd,dd);
{
}
CRect rc
m_rec.init( wf, true, 2034, 0, this->getsafehandle(), &rc, rr)
mrec.record(
m_.stop
*/
BOOL CAudRec::Init( WAVEFORMATEX sRecordFormat,
BOOL IsSaveFile,
UINT nBuffSize,
UINT nDeviceID,
HWND hwndParent,
LPRECT lpRect,
CALLBACK_DATAWORK proc_CallBack_DataWork
)
{
SetDeviceID( nDeviceID );
m_nBuffSize = nBuffSize;
m_bSaveFile = IsSaveFile;
m_hwndParent = hwndParent;
m_rcClient = lpRect;
m_funCallBackDataWork = proc_CallBack_DataWork;
memcpy(&m_Format, &sRecordFormat, sizeof(WAVEFORMATEX) );
// 创建窗口用来接收消息
if ( !Create ( m_hwndParent, m_rcClient ) )
{
AfxMessageBox("failed in Init to Create child windows for get message!");
}
m_eStatus = ENUM_STATUS_READY;
return TRUE;
}
VOID CAudRec::SetDeviceID(UINT uDeviceID)
{
StopAndFreeAll ();
m_nDeviceID = uDeviceID;
}
void CAudRec::waveErrorMsg(MMRESULT result, LPCTSTR addstr)
{
char errorbuffer[100];
waveInGetErrorText ( result, errorbuffer, 100 );
CString csMsg;
csMsg.Format ( "WAVEIN:%x:%s %s", result, errorbuffer, addstr );
AfxMessageBox ( csMsg );
}
LRESULT CAudRec::OnMM_WIM_DATA ( WPARAM wParam, LPARAM lParam )
{
MMRESULT mmReturn = 0;
LPWAVEHDR pHdr = (LPWAVEHDR) lParam;
ASSERT ( pHdr );
mmReturn = ::waveInUnprepareHeader( m_hRecord, pHdr, sizeof(WAVEHDR));
if( mmReturn )
{
waveErrorMsg ( mmReturn, "waveInUnprepareHeader() failed" );
return -1L;
}
if( m_eStatus == ENUM_STATUS_RECORDING )
{
if( TRUE == m_bSaveFile )
{
UINT length = ::mmioWrite( m_hWaveFile, (CHAR*)pHdr->lpData, pHdr->dwBytesRecorded );
if( length != pHdr->dwBytesRecorded )
{
Stop();
m_nDataQueueNum --;
AfxMessageBox ( "Write file failed" );
return -1L;
}
}
if( m_funCallBackDataWork )
{
m_funCallBackDataWork( (UCHAR*)pHdr->lpData, pHdr->dwBytesRecorded);
}
mmReturn = ::waveInPrepareHeader( m_hRecord, pHdr, sizeof(WAVEHDR) );
if ( mmReturn )
{
waveErrorMsg( mmReturn, "waveInPrepareHeader() failed in OnMM_WIM_DATA" );
}
else
{
mmReturn = ::waveInAddBuffer( m_hRecord, pHdr, sizeof(WAVEHDR) );
if ( mmReturn )
{
waveErrorMsg( mmReturn, "waveInAddBuffer() failed in OnMM_WIM_DATA");
}
else
{
return 0L;
}
}
}
else
{
if ( m_nDataQueueNum == 1 )
{
StopRec();
}
else
{
m_nDataQueueNum--;
}
}
return 0L;
}
BOOL CAudRec::AddInputBufferToQueue(INT nIndex)
{
ASSERT( (UINT(nIndex) >= 0) && (UINT(nIndex) < m_nBuffNum) );
ASSERT( m_szAryInData[nIndex] );
MMRESULT mmReturn = 0;
LPWAVEHDR pHdr = m_pAryHdr[nIndex];
ZeroMemory( pHdr, sizeof(WAVEHDR) );
pHdr->lpData = (char*)m_szAryInData[nIndex];
pHdr->dwBufferLength = m_nBuffSize;
mmReturn = ::waveInPrepareHeader( m_hRecord, pHdr, sizeof(WAVEHDR) );
if ( mmReturn )
{
waveErrorMsg ( mmReturn, "AddInputBufferToQueue Failed");
return FALSE;
}
mmReturn = ::waveInAddBuffer( m_hRecord, pHdr, sizeof(WAVEHDR) );
if ( mmReturn )
{
waveErrorMsg ( mmReturn, "waveInAddBuffer() failed");
return FALSE;
}
m_nDataQueueNum++;
return TRUE;
}
BOOL CAudRec::AllocateBuffer(UINT dwBufferSize)
{
m_nBuffSize = dwBufferSize;
ASSERT ( m_nBuffNum > 0 );
m_szAryInData = new char*[m_nBuffNum];
m_pAryHdr = new WAVEHDR*[m_nBuffNum];
if ( !m_szAryInData )
{
::AfxThrowMemoryException();
return FALSE;
}
memset( m_szAryInData, 0, sizeof(char*) * m_nBuffNum );
memset( m_pAryHdr, 0, sizeof(WAVEHDR*) * m_nBuffNum );
for ( UINT i=0; i < m_nBuffNum; i++ )
{
m_szAryInData[i] = new char[m_nBuffSize];
m_pAryHdr[i] = new WAVEHDR;
if ( !m_szAryInData[i] || !m_pAryHdr[i] )
{
::AfxThrowMemoryException ();
return FALSE;
}
TRACE( "Alloc m_nBuffNum = %d\n", i);
memset ( m_szAryInData[i], 0, m_nBuffSize );
memset ( m_pAryHdr[i], 0, sizeof(WAVEHDR) );
}
return TRUE;
}
void CAudRec::FreeBuffer()
{
if ( m_szAryInData )
{
for ( UINT i=0; i < m_nBuffNum; i++ )
{
if ( m_szAryInData[i] )
delete[] m_szAryInData[i];
TRACE( "Delete m_nBuffNum = %d\n", i);
}
memset ( m_szAryInData, 0, sizeof(char*)*m_nBuffNum );
delete[] m_szAryInData;
m_szAryInData = NULL;
}
if ( m_pAryHdr )
{
for ( UINT i=0; i < m_nBuffNum; i++ )
{
if ( m_pAryHdr[i] )
delete[] m_pAryHdr[i];
}
memset ( m_pAryHdr, 0, sizeof(WAVEHDR*)*m_nBuffNum );
delete[] m_pAryHdr;
m_pAryHdr = NULL;
}
}
void CAudRec::OnTimer(UINT nIDEvent)
{
switch( nIDEvent )
{
case TIMER_EVENT_STOPREC:
KillTimer( nIDEvent );
StopRec();
break;
}
CWnd::OnTimer(nIDEvent);
}
void CAudRec::SetRecordFormat(WAVEFORMATEX sFormat)
{
memset ( &m_Format, 0, sizeof(WAVEFORMATEX) );
m_Format.cbSize = sFormat.cbSize;
m_Format.nAvgBytesPerSec = sFormat.nAvgBytesPerSec;
m_Format.nBlockAlign = sFormat.nBlockAlign;
m_Format.nChannels = sFormat.nChannels;
m_Format.nSamplesPerSec = sFormat.nSamplesPerSec;
m_Format.wBitsPerSample = sFormat.wBitsPerSample;
m_Format.wFormatTag = sFormat.wFormatTag;
}
BOOL CAudRec::SetRelateParaAfterGetWaveFormat()
{
FreeBuffer();
m_nBuffNum = (UINT)( m_Format.nChannels + m_Format.wBitsPerSample/8
+ m_Format.nSamplesPerSec/11025 );
if ( !AllocateBuffer( m_nBuffSize ) )
{
AfxMessageBox("Failed in SetRecordFormat AllocateBuffer!");
return FALSE;
}
return TRUE;
}
UINT CAudRec::GetWaveInCount()
{
return waveInGetNumDevs();
}
void CAudRec::CreateWaveFile()
{
INT nPos;
CHAR buffer[20];
CTime t = CTime::GetCurrentTime();
nPos = sprintf( buffer, "%d", t.GetYear() );
nPos += sprintf( buffer + nPos, "%d", t.GetMonth() );
nPos += sprintf( buffer + nPos, "%d", t.GetDay() );
nPos += sprintf( buffer + nPos, "%d", t.GetHour() );
nPos += sprintf( buffer + nPos, "%d", t.GetMinute() );
nPos += sprintf( buffer + nPos, "%d", t.GetSecond() );
strcat( buffer, ".wav");
// if existing the same file, delete it
::mmioOpen ( (LPTSTR)buffer, NULL, MMIO_DELETE );
m_hWaveFile = ::mmioOpen( buffer, NULL, MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE|MMIO_ALLOCBUF );
if( NULL == m_hWaveFile )
{
AfxMessageBox("can not create the wave file!");
}
WAVEFORMATEX wfx = m_Format;
ZeroMemory ( &m_MMCKInfoParent, sizeof(MMCKINFO) );
m_MMCKInfoParent.fccType = mmioFOURCC('W','A','V','E');
MMRESULT mmResult = ::mmioCreateChunk( m_hWaveFile,&m_MMCKInfoParent, MMIO_CREATERIFF);
ZeroMemory ( &m_MMCKInfoChild, sizeof(MMCKINFO) );
m_MMCKInfoChild.ckid = mmioFOURCC('f','m','t',' ');
m_MMCKInfoChild.cksize = sizeof(WAVEFORMATEX) + wfx.cbSize;
mmResult = ::mmioCreateChunk(m_hWaveFile, &m_MMCKInfoChild, 0);
mmResult = ::mmioWrite(m_hWaveFile, (char*)&wfx, sizeof(WAVEFORMATEX) + wfx.cbSize);
mmResult = ::mmioAscend(m_hWaveFile, &m_MMCKInfoChild, 0);
m_MMCKInfoChild.ckid = mmioFOURCC('d', 'a', 't', 'a');
mmResult = ::mmioCreateChunk ( m_hWaveFile, &m_MMCKInfoChild, 0 );
}
UINT CAudRec::GetBuffSize()
{
return m_nBuffSize;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -