程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 簡單錄、放音並保存為wav文件程序

簡單錄、放音並保存為wav文件程序

編輯:關於VC++

引言

我是C++的初學者,入門都要靠VCKBASE,好在裡面有很多適合於初學者的例子,讓我少走了很多彎路,為了回饋大家,我也把我最近剛完成的一個簡單的小程序提供給大家,讓那些曾經和我一樣徘徊在C++大門之外的人能快些掌握要領,大家不妨看一看。

本文以VC知識庫第26期 栾義明 先生的《基於API的錄音機程序》為基礎的,在此深表感謝!相同之處不再重復,我在此基礎上增加了將錄音保存為wav文件的格式,便於大家參考。

基本步驟及思想:設定音頻采集參數(采樣率、聲道等),打開音頻設備、准備wave數據頭和開辟緩存,操作采集的數據並保存為wav文件。設定音頻回放參數,打開回放設備、准備wave數據頭和寫wave數據。另外樣本程序需包含#include <mmsystem.h>和#pragma comment(lib,"WINMM.LIB")多媒體支持。

在介紹程序前,需要你對wave文件的格式和相關一些基礎概念有所了解,這些均可以在msdn中查找,為方便理解,我們將其整理,如果對這些基礎知識已有所了解,可以跳過。

概念1、定義波形數據格式

typedef struct{WORD wFormatTag;
   WORD nChannels;
   DWORD nSamplesPerSec;
   DWORD nAvgBytesPerSec;
   WORD nBlockAlign;
   WORD wBitsPerSample;
   WORD cbSize; } WAVEFORMATEX;

具體參數解釋如下:

wFormatTag:波形數據的格式,定義在MMREG.H文件中

nChannels:波形數據的通道數:單聲道或立體聲

nSamplesPerSec:采樣率,對於PCM格式的波形數據,采樣率有8.0 kHz,11.025kHz,22.05 kHz,44.1 kHz等

nAvgBytesPerSec:數據率,對於PCM格式的波形數據,數據率等於采樣率乘以每樣點字節數

nBlockAlign:每個樣點字節數

wBitsPerSample:采樣精度,對於PCM格式的波形數據,采樣精度為8或16

cbSize:附加格式信息的數據塊大小

概念2、定義設備頭結構

WAVEHDR定義了指向波形數據緩沖區的設備頭。

typedef struct { LPSTR lpData;
  DWORD dwBufferLength;
  DWORD dwBytesRecorded;
  DWORD dwUser;
  DWORD dwFlags;
  DWORD dwLoops;
  struct wavehdr_tag * lpNext;
  DWORD reserved; } WAVEHDR;

lpData:波形數據的緩沖區地址

dwBufferLength:波形數據的緩沖區地址的長度

dwBytesRecorded:當設備用於錄音時,標志已經錄入的數據長度

dwUser:用戶數據

dwFlags:波形數據的緩沖區的屬性

dwLoops:播放循環的次數,僅用於播放控制中

lpNext和reserved均為保留值

注意:上述結構體以及我們在程序中所使用到的“HWAVEIN””HWAVEOUT”結構體均是系統已經存在的,我們只需要對其進行賦值即可。

概念3、消息處理函數

MM_WIM_OPEN //設備的打開

MM_WIM_DATA //設備數據的采集及操作

MM_WIM_CLOSE //設備的關閉

相應回放設備的消息分別為MM_WOM_OPEN,MM_WOM_DATA,MM_WOM_CLOSE.

注意:消息處理函數是消息自我驅動的,不需要我們的人為干預。比如:當我們打開設備時,系統會自動調用MM_WIM_OPEN,當我們將數據添加到緩沖區,而緩沖區滿時,系統會自動調用MM_WIM_DATA,我們所需要做的,就是對該函數編好相應的源代碼。

現在,我們進入正題:如何實現一個錄音機。

⑴先對WAVEFORMATEX結構體進行賦值,然後為緩沖區分配內存

pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);
pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);

對設備頭結構體分配內存

pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
pWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));

然後使用wave音頻相關函數對輸入數據進行操作:

①為波形輸入設備准備緩沖區

waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR));
waveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));

②為波形輸入設備添加緩沖區

waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

③啟動聲音輸入設備,將輸入數據寫入內存

waveInStart (hWaveIn) ;

⑵編寫消息處理函數,其中,MM_WIM_DATA 函數是本程序的核心。其主要作用是將輸入數據另行保存在一緩沖區內(pSaveBuffer),該緩沖區的長度將隨著已錄入數據的大小而增加,從而實現保存輸入話音數據的功能。同時,可將緩沖區內數據保存為wav文件。其具體實現如下:

CFile m_file;
CFileException fileException;
CString m_csFileName= "F:\\audio.wav";//保存路徑
m_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);
DWORD m_WaveHeaderSize = 38;
DWORD m_WaveFormatSize = 18;
m_file.SeekToBegin();
m_file.Write("RIFF",4);
unsigned int Sec=(sizeof pSaveBuffer + m_WaveHeaderSize);
m_file.Write(&Sec,sizeof(Sec));
m_file.Write("WAVE",4);
m_file.Write("fmt ",4);
m_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));
m_file.Write(&waveform.wFormatTag,sizeof(waveform.wFormatTag));
m_file.Write(&waveform.nChannels,sizeof(waveform.nChannels));
m_file.Write(&waveform.nSamplesPerSec,sizeof(waveform.nSamplesPerSec));
m_file.Write(&waveform.nAvgBytesPerSec,sizeof(waveform.nAvgBytesPerSec));
m_file.Write(&waveform.nBlockAlign,sizeof(waveform.nBlockAlign));
m_file.Write(&waveform.wBitsPerSample,sizeof(waveform.wBitsPerSample));
m_file.Write(&waveform.cbSize,sizeof(waveform.cbSize));
m_file.Write("data",4);
m_file.Write(&dwDataLength,sizeof(dwDataLength));
m_file.Write(pSaveBuffer,dwDataLength);
m_file.Seek(dwDataLength,CFile::begin);
m_file.Close();

存在的問題:

我們也才開始vc學習,只是將自己了解的知識與和我們水平相當的新手們分享,希望一起提高。本程序有時不穩定,但音質很好,可能還有尚未暴露的錯誤,懇請廣大高手們不吝賜教。E-mail: [email protected][email protected]

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved