📄 recorderdlg.cpp
字号:
/****************************************Copyright (c)**************************************************
** Guangzhou ZHIYUAN electronics Co.,LTD.
**
** http://www.embedtools.com
**
**--------------File Info-------------------------------------------------------------------------------
** File Name: RecorderDlg.cpp
** Last modified Date: 2007.12.20
** Last Version: V1.0
** Description: 录音示例程序对话框类
**
**------------------------------------------------------------------------------------------------------
** Created By: Fuqiang Song 宋福强
** Created date: 2007.12.20
** Version: V1.0
** Descriptions: The original version 初始版本
**
**
*********************************************************************************************************/
// RecorderDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Recorder.h"
#include "RecorderDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CRecorderDlg dialog
CRecorderDlg::CRecorderDlg(CWnd* pParent /*=NULL*/)
: CDialog(CRecorderDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CRecorderDlg)
m_strRecLen = _T("");
m_strSavePath = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CRecorderDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CRecorderDlg)
DDX_Control(pDX, IDC_EDIT_POS, m_btnPos);
DDX_Text(pDX, IDC_EDIT_LEN, m_strRecLen);
DDV_MaxChars(pDX, m_strRecLen, 2);
DDX_Text(pDX, IDC_EDIT_SAVEPATH, m_strSavePath);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CRecorderDlg, CDialog)
//{{AFX_MSG_MAP(CRecorderDlg)
ON_BN_CLICKED(IDC_BUTTON_RECORD, OnButtonRecord)
ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnButtonBrowse)
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CRecorderDlg message handlers
/********************************************************************************************************
** Function name: CRecorderDlg::OnInitDialog()
** Descriptions: 对话框初始化事件处理函数
** Input parameters: 无
** Output parameters: 无
** Returned value: TRUE
*********************************************************************************************************/
BOOL CRecorderDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
CenterWindow(GetDesktopWindow()); // center to the hpc screen
// TODO: Add extra initialization here
m_bRec = FALSE;
m_pBuffer = NULL;
m_RecFormat.wFormatTag = 1; /* PCM格式音频 */
m_RecFormat.nChannels = 1; /* 声道数为1(单声道) */
m_RecFormat.nSamplesPerSec = 11025; /* 采样率 */
m_RecFormat.nAvgBytesPerSec = 22050; /* 每秒字节数 */
m_RecFormat.nBlockAlign = 2; /* 块字节长度 */
m_RecFormat.wBitsPerSample = 16; /* 采样位数 */
m_RecFormat.cbSize = 0; /* 附加数据长度 */
m_hRecStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL); /* 创建录音结束或停止通知事件 */
m_btnPos.SetWindowText(_T("0")); /* 设置“录音进度”编辑框初值 */
m_strRecLen = _T("10"); /* “录音长度”编辑框初始值 */
m_strSavePath = _T("\\RecordTest.wav"); /* “保存路径”编辑框初始值 */
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
/********************************************************************************************************
** Function name: CRecorderDlg::OnButtonRecord()
** Descriptions: “开始”按钮单击事件处理函数
** Input parameters: 无
** Output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void CRecorderDlg::OnButtonRecord()
{
// TODO: Add your control notification handler code here
CButton *pBtnRec = (CButton *)GetDlgItem(IDC_BUTTON_RECORD); /* “开始”按钮指针 */
CButton *pBtnStop = (CButton *)GetDlgItem(IDC_BUTTON_STOP); /* “停止”按钮指针 */
DWORD dwRecLen;
MMRESULT rst;
WAVEHDR Head;
UpdateData(TRUE);
_stscanf(m_strRecLen, _T("%d"), &dwRecLen); /* 得到"录音长度"编辑框的值 */
if (!dwRecLen) { /* 判断录音长度值是否为0 */
MessageBox(_T("录音长不能为0!"));
return;
}
if (!m_File.Open(m_strSavePath, CFile::modeCreate | CFile::modeWrite)) {
/* 判断创建用于保存录音的文件 */
/* 是否成功 */
MessageBox(_T("写入文件失败!"));
return;
}
rst = waveInOpen(&m_hwi, WAVE_MAPPER, &m_RecFormat, /* 打开波形音频输入设备 */
(DWORD)m_hRecStopEvent, 0, CALLBACK_EVENT);
if (FAILED(rst)) { /* 判断打开音频输入设备是否成 */
/* 功 */
MessageBox(_T("打开录音设备失败!"));
return;
}
m_dwBufferLen = m_RecFormat.nAvgBytesPerSec * dwRecLen;
Head.dwBufferLength = m_dwBufferLen;
m_pBuffer = new BYTE[m_dwBufferLen];
Head.lpData = (char *)m_pBuffer;
rst = waveInPrepareHeader(m_hwi, &Head, sizeof(WAVEHDR)); /* 准备录音缓冲区 */
if (FAILED(rst)) {
MessageBox(_T("准备录音缓冲区失败!"));
delete[] m_pBuffer;
return;
}
rst = waveInAddBuffer(m_hwi, &Head, sizeof(WAVEHDR)); /* 添加录音缓冲添加录音缓冲 */
if (FAILED(rst)) {
MessageBox(_T("添加录音缓冲区失败!"));
delete[] m_pBuffer;
return;
}
rst = waveInStart(m_hwi); /* 开始录音 */
if (FAILED(rst)) {
MessageBox(_T("启动录音失败!"));
delete[] m_pBuffer;
return;
}
ResetEvent(m_hRecStopEvent);
DWORD dwId;
HANDLE hThread = CreateThread(NULL, 0, RecordThread, this, /* 创建录音线程 */
0, &dwId);
CloseHandle(hThread);
pBtnRec->EnableWindow(FALSE); /* "开始"按钮变灰 */
pBtnStop->EnableWindow(TRUE); /* "开始"按钮变亮 */
m_bRec = TRUE;
}
/********************************************************************************************************
** Function name: CRecorderDlg::RecordThread()
** Descriptions: 录音线程函数
** Input parameters: pData: 线程传入参数
** Output parameters: 无
** Returned value: 0
*********************************************************************************************************/
DWORD CRecorderDlg::RecordThread(LPVOID pData)
{
CRecorderDlg *pDlg = (CRecorderDlg *)pData;
CButton *pBtnRec = (CButton *)pDlg->GetDlgItem(IDC_BUTTON_RECORD);
CButton *pBtnStop = (CButton *)pDlg->GetDlgItem(IDC_BUTTON_STOP);
DWORD dwCurRecLen = 0;
CString strInfo; /* 用于打印已录音秒数的字符串类*/
MMTIME MmTime; /* 多媒体数据时间信息结构体 */
WAVEFILEHEAD FileHead;
MmTime.wType = TIME_SAMPLES; /* 设置要获取的时间类型为采样数*/
while (TRUE) {
DWORD dwObjectId = WaitForSingleObject(pDlg->m_hRecStopEvent, 100);
if (waveInGetPosition(pDlg->m_hwi, &MmTime, sizeof(MMTIME)) == 0) {
/* 取得当前录音位置,并判断是 */
/* 否成功 */
dwCurRecLen = (DWORD)((double)MmTime.u.sample
/ pDlg->m_RecFormat.nSamplesPerSec
* pDlg->m_RecFormat.nAvgBytesPerSec);
strInfo.Format(_T("%.1f"), (float)dwCurRecLen /* 将录音秒数打印到strInfo字符 */
/ pDlg->m_RecFormat.nAvgBytesPerSec); /* 串 */
pDlg->m_btnPos.SetWindowText(strInfo); /* 在编辑框中显示已录音秒数 */
}
if (dwObjectId == WAIT_OBJECT_0) { /* 判断是否等到录音停止通知事 */
/* 件被标记 */
break; /* 跳出循环 */
}
}
pDlg->m_btnPos.SetWindowText(_T("正在保存"));
waveInStop(pDlg->m_hwi); /* 停止录音 */
waveInClose(pDlg->m_hwi); /* 关闭音频输入设备 */
pDlg->m_File.SeekToBegin();
pDlg->BuildWaveFileHead(&FileHead, pDlg->m_RecFormat, dwCurRecLen); /* 构建WAV文件头信息 */
pDlg->m_File.Write(&FileHead, sizeof(WAVEFILEHEAD)); /* 写入文件头信息 */
pDlg->m_File.Write(pDlg->m_pBuffer, dwCurRecLen); /* 写入录音流数据 */
pDlg->m_File.Close(); /* 关闭文件 */
delete[] pDlg->m_pBuffer;
pDlg->m_pBuffer = NULL;
pDlg->m_bRec = FALSE;
pBtnRec->EnableWindow(TRUE);
pDlg->m_btnPos.SetWindowText(_T("0"));
pBtnStop->EnableWindow(FALSE);
return 0;
}
/********************************************************************************************************
** Function name: CRecorderDlg::OnButtonBrowse()
** Descriptions: “浏览”按钮单击事件处理函数
** Input parameters: 无
** Output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void CRecorderDlg::OnButtonBrowse()
{
// TODO: Add your control notification handler code here
CFileDialog dlg(FALSE, _T("*.wav"), _T("RecordTest"), /* 定义文件对话框类变量,默认 */
OFN_HIDEREADONLY, /* 扩展名为“.wav”,默认文件 */
_T("波形音频文件 (*.WAV)|*.wav||"), NULL); /* 名为"RecordTest",隐藏只读 */
/* 复选框,过滤掉"*.wav"以外 */
/* 类型文件 */
if (dlg.DoModal() == IDOK) { /* 判断是否单击了OK按钮 */
m_strSavePath = dlg.GetPathName(); /* 取得文件路径 */
UpdateData(FALSE);
}
}
/********************************************************************************************************
** Function name: CRecorderDlg::BuildWaveFileHead()
** Descriptions: 构建WAV文件头
** Input parameters: format: 波形音频扩展格式
dwDataLen: 流数据长度
** Output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void CRecorderDlg::BuildWaveFileHead(WAVEFILEHEAD *filehead,
WAVEFORMATEX format,
DWORD dwDataLen)
{
if (!filehead) return;
memcpy(filehead->szRIFF, "RIFF", 4);
filehead->dwTotalSize = dwDataLen + sizeof(WAVEFILEHEAD) - 8;
memcpy(filehead->szWAVE, "WAVE", 4);
memcpy(filehead->szFMT, "fmt ", 4);
filehead->dwChunk0Size = 16;
memcpy(filehead->Format, &format, 16);
memcpy(filehead->szDATA, "data", 4);
filehead->dwChunk1Size = dwDataLen;
}
/********************************************************************************************************
** Function name: CRecorderDlg::OnButtonStop()
** Descriptions: "停止"按钮单击事件处理函数
** Input parameters: 无
** Output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void CRecorderDlg::OnButtonStop()
{
// TODO: Add your control notification handler code here
SetEvent(m_hRecStopEvent);
}
/********************************************************************************************************
** Function name: CRecorderDlg::OnDestroy()
** Descriptions: 窗口销毁事件处理函数
** Input parameters: 无
** Output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void CRecorderDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
if (m_bRec) {
waveInReset(m_hwi); /* 先复位录音位置才能停止录音 */
waveInStop(m_hwi); /* 停止录音 */
waveInClose(m_hwi); /* 关闭录音 */
}
if (m_pBuffer) {
delete[] m_pBuffer; /* 释放申请的内存 */
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -