基于wince的录音机
基于D:\WINCE500\PUBLIC\COMMON\SDK\SAMPLES\AUDIO\WAVREC 的录音程序
建立: PCRecord MFC 工程
工程加入:
wavrec.cpp
wavefile.cpp
wavefile.h
将wavrec.cpp 的 winmain 函数声明去掉,把 winmain(){} 的{}改为void StartRecord(char *pFile);
函数(为了避免一开始就执行录音窗口)
PCRecordDlg.cpp 加入
#include "wavefile.h"
#include "wavrec.h" //wavrec.h 加入void StartRecord(char *pFile);
1. 加入 edit 组件名为IDC_SAVE_FILE,加入按钮IDC_BROWSE,并加入按钮事件
CFileDialog Dlg(false);
if (Dlg.DoModal() == IDCANCEL)
return;
m_strFile = Dlg.GetPathName();
m_strFile+= ".wav";
//MessageBox(m_strFile,TEXT("msg"),MB_OK);
UpdateData(false);
2. DoDataExchange 在这里加入DDX_Text(pDX, IDC_SAVE_FILE, m_strFile); 数据更新,这就实现了路径的显示
3. 加入按钮OnStart,事件为:
void CPCRecordDlg::OnBnClickedOnstart()
{ //MessageBox(NULL,(LPCTSTR)pFile,TEXT("msg"),MB_OK);
if (m_strFile.IsEmpty())
{
AfxMessageBox(_T("请先输入要保存的文件名"));
return;
}
UpdateData(true);
StartRecord((char *)m_strFile.GetBuffer(m_strFile.GetLength()));
}
4. 将PTSTR pszFilename = (PTSTR)pFile; 估计 TEXT 是PTSTR型
5. 到此是可以正常玩一个录音的了,但是,只能有一个主线程在转啊,所以一旦运行录音整个dialog就停止了,只能等到录音完,所以必须创建一个进程来跑这个函数!看下面在类中创建线程
void CPCRecordDlg::OnBnClickedOnstart()
{
if (m_strFile.IsEmpty())
{
AfxMessageBox(_T("请先输入要保存的文件名"));
return;
}
//pFile=m_strFile.GetBuffer(m_strFile.GetLength());
//MessageBox(pFile,TEXT("msg"),MB_OK);
UpdateData(true);
SetTimer(1, 10, NULL);
//
DWORD dwThreadID;
HANDLE hThread = CreateThread(NULL, // no security attributes
0, // use default stack size
(LPTHREAD_START_ROUTINE)ThreadFunc,
(LPVOID)NULL, // 可以通过这个参数传送一个参数的指针到处理函数中
0, // creation flag
&dwThreadID); // thread identifier
if (hThread == NULL)
MessageBox(TEXT("创建线程出错!"),TEXT("msg"),MB_OK);;
StartRe=(char *)m_strFile.GetBuffer(m_strFile.GetLength());
}
DWORD ThreadFunc(LPVOID lpVoid) //lpVoid即为创建线程时传入的参数,可以为空
{
//在你的线程中的处理。
//MessageBox(NULL,TEXT("msg"),TEXT("msg"),MB_OK);
StartRecord(StartRe);
return 0;
}
6. 在空白处加上线程处理函数
DWORD ThreadFunc(LPVOID lpVoid) //lpVoid即为创建线程时传入的参数,可以为空
{
//在你的线程中的处理。
//MessageBox(NULL,TEXT("msg"),TEXT("msg"),MB_OK);
StartRecord(StartRe);
return 0;
}
7. 在头文件中加入
static DWORD WINAPI ThreadFunc(LPVOID lpVoid);
static char *StartRe;
先上张PIC
随时可以停,但不能边录边写文件,因为我还没研究到这一步,呵呵
下面代码部分:
工程要加入wince里面的
wavefile.cpp
wavefile.h
waveInOpen(&hwi,WAVE_MAPPER, pwfx, (DWORD)this->m_hWnd, NULL, CALLBACK_WINDOW);//CALLBACK_WINDOW 被这个搞惨,如果是CALLBACK_EVENT 那些
ON_THREAD_MESSAGE(MM_WIM_OPEN,OnMM_WIM_OPEN)
ON_THREAD_MESSAGE(MM_WIM_DATA,OnMM_WIM_DATA)
ON_THREAD_MESSAGE(MM_WIM_CLOSE,OnMM_WIM_CLOSE)
就不会响应!
中途还改用线程,也不好操作!
// WinceRecordDlg.cpp : implementation file
//
#include "stdafx.h"
#include "WinceRecord.h"
#include "WinceRecordDlg.h"
#include "wavefile.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define MRCHECK(mr,str)\
if ((mr != MMSYSERR_NOERROR)) { RETAILMSG(1, (TEXT(#str) TEXT(" failed. mr=%08x\r\n"), mr)); goto ERROR_DONE;}
/
// CWinceRecordDlg dialog
CWinceRecordDlg::CWinceRecordDlg(CWnd* pParent /*=NULL*/)
: CDialog(CWinceRecordDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CWinceRecordDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CWinceRecordDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CWinceRecordDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
DDX_Text(pDX, IDC_SAVE_FILE, m_strFile);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CWinceRecordDlg, CDialog)
//{{AFX_MSG_MAP(CWinceRecordDlg)
ON_THREAD_MESSAGE(MM_WIM_OPEN,OnMM_WIM_OPEN)
ON_THREAD_MESSAGE(MM_WIM_DATA,OnMM_WIM_DATA)
ON_THREAD_MESSAGE(MM_WIM_CLOSE,OnMM_WIM_CLOSE)
ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
ON_BN_CLICKED(IDC_REC_START, OnRecStart)
ON_BN_CLICKED(IDC_REC_STOP, OnRecStop)
ON_BN_CLICKED(IDC_PLAY, OnPlay)
ON_BN_CLICKED(IDC_STOP, OnStop)
ON_BN_CLICKED(IDC_PAUSE, OnPause)
ON_BN_CLICKED(IDC_CONTINUE, OnContinue)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_REC_HOLD, OnRecHold)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_BN_CLICKED(IDC_REC_CON, OnRecCon)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CWinceRecordDlg message handlers
BOOL CWinceRecordDlg::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
saved=false;
GetDlgItem(IDC_REC_START)->EnableWindow(false);
GetDlgItem(IDC_REC_STOP)->EnableWindow(false);
GetDlgItem(IDC_PLAY)->EnableWindow(false);
GetDlgItem(IDC_STOP)->EnableWindow(false);
GetDlgItem(IDC_PAUSE)->EnableWindow(false);
GetDlgItem(IDC_CONTINUE)->EnableWindow(false);
GetDlgItem(IDC_REC_CON)->EnableWindow(false);
GetDlgItem(IDC_REC_HOLD)->EnableWindow(false);
return TRUE; // return TRUE unless you set the focus to a control
}
void CWinceRecordDlg::OnBrowse()
{
// TODO: Add your control notification handler code here
CString defFilter("Wave File(*.wav)|*.wav|");
CFileDialog Dlg(FALSE,NULL,NULL,OFN_HIDEREADONLY,defFilter);
if (Dlg.DoModal() == IDCANCEL)
return;
m_strFile = Dlg.GetPathName();
m_strFile+= ".wav";
//MessageBox(m_strFile,TEXT("msg"),MB_OK);
UpdateData(false);
if(m_strFile!="")
{
GetDlgItem(IDC_REC_START)->EnableWindow(true);
SetDlgItemText(IDC_REC_START,L"录制");
}
}
void CWinceRecordDlg::OnRecStart()
{
// TODO: Add your control notification handler code here
if (m_strFile.IsEmpty())
{
AfxMessageBox(_T("请先输入要保存的文件名"));
return;
}
UpdateData(true);
time=GetDlgItemInt(IDC_TIME);
//参数配置
pszFilename = m_strFile.GetBuffer(m_strFile.GetLength());;
dwDuration =time * 1000; // record for 5 seconds
dwChannels = 1; // default to mono
dwBitsPerSample = 16; // default to 16-bit samples
dwSampleRate = 11025; // default to 11.025KHz sample rate
dwDeviceId = WAVE_MAPPER; // capture from device 0
pwfx=&wfx;
wfx.cbSize = 0;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.wBitsPerSample = (WORD) dwBitsPerSample;
wfx.nSamplesPerSec = dwSampleRate;
wfx.nChannels = (WORD) dwChannels;
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
dwBufferSize = (dwDuration * pwfx->nSamplesPerSec / 1000) * pwfx->nBlockAlign;
if(dwDuration==0) //如果设为不是定时的话,就开20M内存
{
dwBufferSize= 20000000;
}
// try to allocate the capture buffer
pBufferBits = new BYTE [dwBufferSize];
if (pBufferBits == NULL) {
RETAILMSG (1, (TEXT("Unable to allocate %d bytes for %d ms of audio data\r\n"), dwBufferSize, dwDuration));
}
// let user know what's going on
RETAILMSG(1, (TEXT("Recording %5d ms to \"%s\": %c%02d %5dHz (%8d bytes)\r\n")
, dwDuration
, pszFilename
, pwfx->nChannels == 2 ? L'S' : L'M'
, pwfx->wBitsPerSample
, pwfx->nSamplesPerSec
, dwBufferSize
));
memset(&hdr, 0, sizeof(WAVEHDR));
hdr.dwBufferLength = dwBufferSize;
hdr.lpData = (char *) pBufferBits;
// create an event so we know when capture is completed
// open the wave capture device
MMRESULT mr = waveInOpen(&hwi,WAVE_MAPPER, pwfx, (DWORD)this->m_hWnd, NULL, CALLBACK_WINDOW);//CALLBACK_WINDOW 被这个害死
if (mr != MMSYSERR_NOERROR) {
RETAILMSG(1, (TEXT("waveInOpen failed. mr=%08x\r\n"), mr));
}
mr = waveInPrepareHeader(hwi, &hdr, sizeof(WAVEHDR));
// submit the buffer for capture
mr = waveInAddBuffer(hwi, &hdr, sizeof(WAVEHDR));
// start capturing
RETAILMSG(1, (TEXT("Starting capture...\r\n\n\n")));
mr = waveInStart(hwi);
//RecordWaveBuffer(&hdr, dwDeviceId, pwfx, dwDuration);
//RecordWaveFile (pszFilename, dwDeviceId, pwfx, dwDuration);
GetDlgItem(IDC_REC_STOP)->EnableWindow(true);
GetDlgItem(IDC_REC_START)->EnableWindow(false);
GetDlgItem(IDC_REC_HOLD)->EnableWindow(true);
saved=true;
str=0;
SetTimer(1,100,NULL);//设置定时器
}
void CWinceRecordDlg::OnMM_WIM_OPEN(UINT wParam, LONG lParam)
{
// TODO: Add your message handler code here and/or call default
RETAILMSG(1, (TEXT("OnMM_WIM_OPEN...\r\n\n\n")));
}
void CWinceRecordDlg::OnMM_WIM_DATA(UINT wParam, LONG lParam)
{
RETAILMSG(1, (TEXT("OnMM_WIM_DATA...\r\n\n\n")));
waveInReset(hwi);
waveInClose(hwi);
// and we're done
// RecordWaveFile(pszFilename,dwDeviceId, &wfx, dwDuration);
}
void CWinceRecordDlg::OnMM_WIM_CLOSE(UINT wParam, LONG lParam)
{
RETAILMSG(1, (TEXT("OnMM_WIM_CLOSE...\r\n\n\n")));
mr = waveInReset(hwi);
mr = waveInUnprepareHeader(hwi, &hdr, sizeof(WAVEHDR));
RETAILMSG(1, (TEXT("Capture completed. Writing %s\r\n"), pszFilename));
mr = WriteWaveFile(pszFilename, pwfx, hdr.dwBytesRecorded, pBufferBits);
GetDlgItem(IDC_REC_STOP)->EnableWindow(false);
GetDlgItem(IDC_PLAY)->EnableWindow(true);
GetDlgItem(IDC_REC_START)->EnableWindow(true);
GetDlgItem(IDC_REC_CON)->EnableWindow(false);
GetDlgItem(IDC_REC_HOLD)->EnableWindow(false);
SetDlgItemText(IDC_REC_START,L"重录");
saved=false;
KillTimer(1);//关闭
SetDlgItemInt(IDC_STATIC_TIME,time);
delete [] pBufferBits;
}
void CWinceRecordDlg::OnRecStop()
{
// TODO: Add your control notification handler code here
RETAILMSG(1, (TEXT("OnRecStop\r\n\n\n")));
waveInReset(hwi);
waveInClose(hwi);
//PostMessage(MM_WIM_CLOSE, 0, 0);
}
void CDialog::OnCancel()
{
RETAILMSG(1, (TEXT("2.saved=%d\r\n"), saved));
if(saved==1)
{
RETAILMSG(1, (TEXT("3.saved=%d\r\n"), saved));
if(MessageBox(L"录音未保存,你要保存录音吗?",L"系统录音提示",MB_YESNO|MB_ICONQUESTION)==IDYES)
{
::PostMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDC_REC_STOP,BN_CLICKED),0);
RETAILMSG(1, (TEXT("ExitProcess(0)\r\n\n\n")));
PostQuitMessage(0); //这个最常用
}
else
{
ExitProcess(0);//这个关得最快
}
}
else
{
ExitProcess(0);//这个关得最快
}
}
void CWinceRecordDlg::OnPlay()
{
hThread = CreateThread(NULL, // no security attributes
0, // use default stack size
(LPTHREAD_START_ROUTINE)ThreadFunc,
(LPVOID)NULL, // 可以通过这个参数传送一个参数的指针到处理函数中
0, // creation flag
&dwThreadID); // thread identifier
if (hThread == NULL)
MessageBox(TEXT("创建线程出错!"),TEXT("msg"),MB_OK);
GetDlgItem(IDC_PLAY)->EnableWindow(false);
GetDlgItem(IDC_PAUSE)->EnableWindow(true);
GetDlgItem(IDC_STOP)->EnableWindow(true);
}
void CWinceRecordDlg::OnStop()
{
// TODO: Add your control notification handler code here
PlaySound(NULL,NULL,SND_FILENAME|SND_ASYNC);
GetDlgItem(IDC_PLAY)->EnableWindow(true);
GetDlgItem(IDC_PAUSE)->EnableWindow(false);
}
void CWinceRecordDlg::OnPause()
{
// TODO: Add your control notification handler code here
SuspendThread(hThread);
GetDlgItem(IDC_CONTINUE)->EnableWindow(true);
GetDlgItem(IDC_PAUSE)->EnableWindow(false);
RETAILMSG(1, (TEXT("SuspendThread(hThread);\r\n\n\n")));
}
DWORD CWinceRecordDlg::ThreadFunc(LPVOID lpVoid) //lpVoid即为创建线程时传入的参数,可以为空
{
//在你的线程中的处理。
PlaySound(pszFilename,NULL,SND_FILENAME|SND_ASYNC);
return 0;
}
void CWinceRecordDlg::OnContinue()
{
// TODO: Add your control notification handler code here
GetDlgItem(IDC_CONTINUE)->EnableWindow(false);
GetDlgItem(IDC_PAUSE)->EnableWindow(true);
ResumeThread(hThread);
RETAILMSG(1, (TEXT("ResumeThread(hThread);\r\n\n\n")));
}
void CWinceRecordDlg::OnTimer(UINT nIDEvent)
{
str+=100;
str1.Format(L"%.1f",str/1000);
SetDlgItemText(IDC_STATIC_TIME,str1+L"s");
str1.Format(L"%.1f",(str/1000)*28);
SetDlgItemText(IDC_STATIC_SIZE,str1+L"k");
//SetDlgItemText(IDC_STATIC_TIME,dura);
}
void CWinceRecordDlg::OnRecHold()
{
// TODO: Add your control notification handler code here
waveInStop(hwi);
GetDlgItem(IDC_REC_CON)->EnableWindow(true);
GetDlgItem(IDC_REC_HOLD)->EnableWindow(false);
SetDlgItemText(IDC_REC_START,L"重录");
KillTimer(1);//关闭
}
void CWinceRecordDlg::OnRecCon()
{
// TODO: Add your control notification handler code here
waveInStart(hwi);
GetDlgItem(IDC_REC_HOLD)->EnableWindow(true);
GetDlgItem(IDC_REC_CON)->EnableWindow(false);
str+=200;
SetTimer(1,1000,NULL);//重启定时器
}
/
// WinceRecordDlg.h : header file
//
#if !defined(AFX_WINCERECORDDLG_H__99C636C1_A7B4_428B_B5E7_A3D68BD2B689__INCLUDED_)
#define AFX_WINCERECORDDLG_H__99C636C1_A7B4_428B_B5E7_A3D68BD2B689__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
static PTSTR pszFilename;
static bool saved;
/
// CWinceRecordDlg dialog
class CWinceRecordDlg : public CDialog
{
// Construction
public:
CWinceRecordDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CWinceRecordDlg)
enum { IDD = IDD_WINCERECORD_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CWinceRecordDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
WAVEFORMATEX wfx,*pwfx;
// Generated message map functions
//{{AFX_MSG(CWinceRecordDlg)
virtual BOOL OnInitDialog();
afx_msg void OnMM_WIM_OPEN(UINT wParam,LONG lParam);
afx_msg void OnMM_WIM_DATA(UINT wParam,LONG lParam);
afx_msg void OnMM_WIM_CLOSE(UINT wParam,LONG lParam);
afx_msg void OnBrowse();
afx_msg void OnRecStart();
afx_msg void OnRecStop();
afx_msg void OnDestroy();
afx_msg void OnPlay();
afx_msg void OnStop();
afx_msg void OnPause();
afx_msg void OnContinue();
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnRecHold();
afx_msg void OnRecCon();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
MMRESULT RecordWaveFile(PCTSTR pszFilename, DWORD dwDeviceId, PWAVEFORMATEX pwfx, DWORD dwDuration);
CString m_strFile;
int time;
MMRESULT mr;
PBYTE pBufferBits;
DWORD dwBufferSize;
WAVEHDR hdr;
DWORD dwWait;
HANDLE hevDone;
HWAVEIN hwi;
DWORD dwTolerance;
DWORD dwDuration;
DWORD dwDeviceId; // capture from device 0
DWORD dwChannels;
DWORD dwBitsPerSample;
DWORD dwSampleRate;
static DWORD WINAPI ThreadFunc(LPVOID lpVoid);
DWORD dwThreadID;
HANDLE hThread;
float str;
CString str1;
};
//{{AFX_INSERT_LOCATION}}
// Microsoft eMbedded Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_WINCERECORDDLG_H__99C636C1_A7B4_428B_B5E7_A3D68BD2B689__INCLUDED_)