当创建并读写wav文件时,要以二进制打开
#include <windows.h>
#include <mmsystem.h>
#include <iostream>
#include<fstream>
#include<math.h>
#include <vector>
#define WAVE_HEAD_LENGTH 44//wav头文件长度
#define m_samplefreq 22050 //每秒采样数-采样速率(22050Hz)
#define m_channels 1 //通道数量,1为单通道,2为双通道
#define m_channelbits 8
#define MATH_PI 3.1415
using namespace std;
//.wav文件的文件头结构
typedef struct
{
char chRIFF[4]; //头部那个RIFF;
DWORD dwRIFFLen; //存的是后面所有文件的大小;
char chWAVE[4];
char chFMT[4];
DWORD dwFMTLen; //存的是fmt保存的大小,包含这之后,data前面几个,共16个;
PCMWAVEFORMAT pwf;
char chDATA[4];
DWORD dwDATALen; //数据的长度;
//UINT8* pBufer;
}WaveHeader;
//采样率、频率、音量、数据空间、采样点数
void MakeWaveData(int rate, int freq, int amp, char* p, int len)
{
int flag = 0;
if (m_channelbits == 16) //16位
{
if (m_channels == 1)
{
for (int i = 0; i < len; i++)
{
INT16 v = INT16(amp/100*32768 * sin(2 * MATH_PI * freq * i / rate));
*(p + flag) = v & 0xFF;//低8位
*(p + flag + 1) = (v >> 8) & 0xFF;//16bit量化 高8位
flag += 2;
}
}
else
{
for (int i = 0; i < len; i++)
{
INT16 vl = INT16(amp / 100 * 32768 * sin(2 * MATH_PI * freq * i / rate)) ;
INT16 vr = INT16(amp / 100 * 32768 * sin((2 * MATH_PI * freq * (i+5) )/ rate)) ;
*(p + flag) = (vl & 0xFF);
*(p + flag + 1) = ((vl >> 8) & 0xFF);
*(p + flag + 2) = (vr & 0xFF);
*(p + flag + 3) = ((vr >> 8) & 0xFF);
flag += 4;
}
}
}
else
{
if (m_channels == 1)
{
for (int i = 0; i < len; i++)
{
*(p + i) = char(sin(i * (MATH_PI * 2) / rate * freq) * amp * 128 / 100 + 128);
}
}
else
{
for (int i = 0; i < len; i++)
{
*(p + flag)= char(sin(i * (MATH_PI * 2) / rate * freq) * amp * 128 / 100+128);
*(p + flag + 1)= char(sin((i+5) * (MATH_PI * 2) / rate * freq) * amp * 128 / 100+128);
flag += 2;
}
}
}
}
//频率、音量、持续时间、wav文件保存路径(包含文件名+后缀
int Create(vector<int> freqVec, int volume, int durations, std::string wavPath)
{
WaveHeader *pHeader = new WaveHeader;
DWORD totalLen = (m_samplefreq * m_channels * m_channelbits / 8) * durations + 44;//文件总长度=(采样率 * 通道数 * 比特数 / 8) * 持续时间(s)
pHeader->chRIFF[0] = 'R';
pHeader->chRIFF[1] = 'I';
pHeader->chRIFF[2] = 'F';
pHeader->chRIFF[3] = 'F';
pHeader->dwRIFFLen = totalLen - 8;//文件的总长度-8bits
pHeader->chWAVE[0] = 'W';
pHeader->chWAVE[1] = 'A';
pHeader->chWAVE[2] = 'V';
pHeader->chWAVE[3] = 'E';
pHeader->chFMT[0] = 'f';
pHeader->chFMT[1] = 'm';
pHeader->chFMT[2] = 't';
pHeader->chFMT[3] = ' ';
pHeader->dwFMTLen = 0x0010;//一般情况下Size为16,如果为18则最后多了2个字节的附加信息
pHeader->pwf.wf.wFormatTag = 0x0001;//波形声音的格式-编码方式
pHeader->pwf.wf.nChannels = m_channels; //通道数量,1为单通道,2为双通道
pHeader->pwf.wf.nSamplesPerSec = m_samplefreq; //采样速率 =44.1KHz
pHeader->pwf.wf.nAvgBytesPerSec = m_samplefreq * m_channels * m_channelbits / 8;//平均数据传输率,每秒所需字节数、缓冲区大小
pHeader->pwf.wf.nBlockAlign = m_channels * m_channelbits / 8;//以字节为单位设置块对齐,一个采样的字节数
pHeader->pwf.wBitsPerSample = m_channelbits;//每次采样样本的大小;16位,即设置PCM的方式为16位立体声(双通道)
pHeader->chDATA[0] = 'd';
pHeader->chDATA[1] = 'a';
pHeader->chDATA[2] = 't';
pHeader->chDATA[3] = 'a';
pHeader->dwDATALen = totalLen - WAVE_HEAD_LENGTH;//数据的长度,=文件总长度-头长度(44bit)
char *pWaveBuffer = new char[totalLen]; //音频数据
memcpy(pWaveBuffer, pHeader, WAVE_HEAD_LENGTH);
int freNum = freqVec.size();
int singleLen = m_samplefreq*durations/freNum;
char* tempBuffer = pWaveBuffer + WAVE_HEAD_LENGTH;
for ( int iFre = 0; iFre < freNum; ++iFre )
{
if ( iFre > 0 )
{
tempBuffer += singleLen;
}
//TODO:最后一个参数
MakeWaveData(pHeader->pwf.wf.nSamplesPerSec, freqVec[iFre], volume, tempBuffer, singleLen);//采样点数
}
ofstream ocout;
ocout.open(wavPath, ios::out | ios::binary);//以二进制形式打开文件
if (ocout)
ocout.write(pWaveBuffer, totalLen);
else
return 0;
ocout.close();
delete(pHeader);
return 1;
}
int main()
{
vector<int> freqVec;
freqVec.push_back(262);
freqVec.push_back(294);
freqVec.push_back(330);
freqVec.push_back(349);
freqVec.push_back(392);
freqVec.push_back(440);
freqVec.push_back(494);
freqVec.push_back(524);
std::string wavPath = "D:\\lhcWave.wav";
if (Create(freqVec, 20, freqVec.size()/2, wavPath))
cout << "创建成功!" << endl;
else
cout << "创建失败!" << endl;
//system( "pause" );
return 0;
}