因工程需要,需要截取一段PCM資料将其儲存為WAV檔案。網上代碼很多,這裡僅記錄一下,友善自己以後查閱。
關于WAV檔案格式不多餘贅述這裡直接上一張圖:
圖檔來源:https://www.cnblogs.com/danju/p/3716194.html

下面附代碼:
結構體聲明檔案:
#ifndef _CWAVEDEF_H
#define _CWAVEDEF_H
#include <MMSystem.h>
//RIFF頭的宏定義縮寫,便于後面的比較 低位元組-》高位元組讀取時比較使用
#define ID_RIFF mmioFOURCC('R', 'I', 'F', 'F')
#define ID_WAVE mmioFOURCC('W', 'A', 'V', 'E')
#define ID_DATA mmioFOURCC('d', 'a', 't', 'a')
#define ID_FMT mmioFOURCC('f', 'm', 't', '\x20')
#define ID_FACT mmioFOURCC('f', 'a', 'c', 't')
//WAVE檔案一般有四種塊,它們依次是:RIFF塊、格式塊、附加塊(可選),資料塊
struct RIFFFORMAT{//長度12
unsigned char Ckid[4]; //RIFF辨別
unsigned long FileSize; //檔案大小
unsigned char FccType[4]; //WAVE标志
};
//WAV格式塊
struct WAVE_FORMAT
{
unsigned char Ckid[4]; //fmt
unsigned long CkLen; //塊大小 16
unsigned short wFormatTag;//音頻格式一般為WAVE_FORMAT_PCM
unsigned short nChannels;//采樣聲道數
unsigned long nSamplesPerSec;//采樣率
unsigned long nAvgBytesPerSec;//每秒位元組數 采樣率*采樣精度/8(位元組位數)
unsigned short nBlockAlign;//塊大小 采樣位元組*聲道數
unsigned short wBitsPerSample;//采樣精度 采樣精度/8 = 采樣位元組
//unsigned short cbSize; //預留位元組 一般為0擴充域有的沒有
};
//wave資料塊
struct WAVE_DATA{
unsigned char Wdid[4]; //data 标志
unsigned long WdSize; //塊大小
//unsigned char* Wdbuf; //資料指針 有符号
};
#endif
儲存檔案:
void CycQueue::Save() //儲存檔案
{
time_t t;
struct tm * lt;
time (&t);//擷取Unix時間戳。
lt = localtime (&t);//轉為時間結構
char buf[30];
sprintf (buf,"../%4d%02d%02d%02d%02d%02d.wav",lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
fw = fopen(buf,"wb+");
Addhead();
return;
}
void CycQueue::Addhead()
{
RIFFFORMAT head;//RIFF塊
memcpy(head.Ckid,"RIFF",4);
head.FileSize = m_writeindex+36;
memcpy(head.FccType,"WAVE",4);
fwrite(&head,1,sizeof(RIFFFORMAT),fw); //寫入檔案
WAVE_FORMAT fmt;//格式塊
memcpy(fmt.Ckid,"fmt ",4);
fmt.CkLen = 16; //塊大小 16
fmt.wFormatTag = WAVE_FORMAT_PCM;//音頻格式一般為WAVE_FORMAT_PCM
fmt.nChannels = 1; //采樣聲道數
fmt.nSamplesPerSec = 44100; //采樣率
fmt.nAvgBytesPerSec = 88200; //每秒位元組數 采樣率*采樣精度/8(位元組位數)
fmt.nBlockAlign = 2; //塊大小 采樣位元組*聲道數
fmt.wBitsPerSample = 16; //采樣深度 (采樣精度/8 = 采樣位元組)
//fmt.cbSize = 0;
fwrite(&fmt,1,sizeof(WAVE_FORMAT),fw); //寫入檔案
WAVE_DATA data; //資料塊
memcpy(data.Wdid,"data",4);
data.WdSize = m_writeindex;
fwrite(&data,1,sizeof(WAVE_DATA),fw); //寫入檔案
fwrite(m_Audio,1,m_writeindex,fw);
fclose(fw); //關閉檔案,清零
fw = NULL;
return;
}
注:
特别注意格式塊中的保留位元組,也就是注釋掉的
//unsigned short cbSize; //預留位元組 一般為0擴充域有的沒有
這部分一般為wav檔案的擴充格式中才包含,還有事實塊等。簡單直接的wav檔案
不需要管。
部分振動資料的轉化
#include <iostream>
#include <fstream>
#include <string>
#include <memory>
RIFF頭的宏定義縮寫,便于後面的比較 低位元組-》高位元組
//#define ID_RIFF mmioFOURCC('R', 'I', 'F', 'F')
//#define ID_WAVE mmioFOURCC('W', 'A', 'V', 'E')
//#define ID_DATA mmioFOURCC('d', 'a', 't', 'a')
//#define ID_FMT mmioFOURCC('f', 'm', 't', '\x20')
//#define ID_FACT mmioFOURCC('f', 'a', 'c', 't')
//WAVE檔案一般有四種塊,它們依次是:RIFF塊、格式塊、附加塊(可選),資料塊
struct RIFFFORMAT{//長度12
unsigned char Ckid[4]; //RIFF辨別
unsigned long FileSize; //檔案大小
unsigned char FccType[4]; //WAVE标志
};
//WAV音頻頭
struct WAVE_FORMAT
{
unsigned char Ckid[4]; //fmt
unsigned long CkLen; //塊大小 16
unsigned short wFormatTag; //音頻格式一般為WAVE_FORMAT_PCM
unsigned short nChannels; //采樣聲道數
unsigned long nSamplesPerSec; //采樣率
unsigned long nAvgBytesPerSec; //每秒位元組數 采樣率*采樣精度/8(位元組位數)
unsigned short nBlockAlign; //塊大小 采樣位元組*聲道數
unsigned short wBitsPerSample; //采樣精度 采樣精度/8 = 采樣位元組
//unsigned short cbSize; //預留位元組 一般為0擴充域
};
//wave資料塊
struct WAVE_DATA{
unsigned char Wdid[4]; //data 标志
unsigned long WdSize; //塊大小
//unsigned char* Wdbuf; //資料指針 有符号
};
using namespace std;
int main()
{
//讀取振動資料
FILE* fp = fopen("../123.txt", "rb+");
if (!fp)return 0;
fseek(fp, 0L, SEEK_END);
long size = ftell(fp) - 34;//擷取檔案資料大小
unsigned char*data = new unsigned char[size];
memset(data, 0, size);
//讀取采樣率
fseek(fp, 22L, SEEK_SET);//高在前 低在後
fread(data, 8, 1, fp);
//采樣率
int sample = ((data[0] << 24) & 0xff000000) | ((data[1] << 16) & 0xff0000)| ((data[2] << 8) & 0xff00) | (data[3] & 0xff);
//時長
int duration =(data[4] << 24 & 0xff000000) | (data[5] << 16 & 0xff0000) | (data[6] << 8 & 0xff00) | (data[7] & 0xff);
//跳轉到資料區
fseek(fp, 34L, SEEK_SET);//高在前 低在後
fread(data, size, 1, fp);
//關閉檔案
fclose(fp);
//========開始WAV=======//
FILE*fw = fopen("../test.wav", "wb+");
RIFFFORMAT head;//RIFF塊
memcpy(head.Ckid, "RIFF", 4);
head.FileSize = size + 36;
memcpy(head.FccType, "WAVE", 4);
fwrite(&head, sizeof(RIFFFORMAT),1, fw); //寫入head
WAVE_FORMAT fmt;//格式塊
memcpy(fmt.Ckid, "fmt ", 4);
fmt.CkLen = 16; //塊大小 16
fmt.wFormatTag = 1; //音頻格式一般為WAVE_FORMAT_PCM
fmt.nChannels = 1; //采樣聲道數
fmt.nSamplesPerSec = sample; //采樣率
fmt.nAvgBytesPerSec = sample*4; //88200每秒位元組數 采樣率*采樣精度(指的bit位數)/8(位元組位數)
fmt.nBlockAlign = 4; //塊大小 = 采樣位元組*聲道數
fmt.wBitsPerSample = 32; //采樣深度 = 采樣位元組*位數 (采樣精度/8 = 采樣位元組)
//fmt.cbSize = 0;
fwrite(&fmt, sizeof(WAVE_FORMAT),1, fw); //寫入fmt
WAVE_DATA wdata; //資料塊
memcpy(wdata.Wdid, "data", 4);
wdata.WdSize = size;
fwrite(&wdata, sizeof(WAVE_DATA), 1, fw); //寫入data
fflush(fw);
for (int i = (size-1); i>-1; i--)
{
fwrite((void*)(&data[i]), 1, 1, fw);//pcm資料部分為低位元組在前高位元組在後
}
fclose(fw); //關閉檔案,清零
delete data;
return 0;