C++根据频率生成wav音频文件
来源:互联网 发布:张家港美工设计培训 编辑:程序博客网 时间:2024/06/06 13:18
最近在研究如何根据频率来产生wav音频文件。经过一番查阅资料发现了挺不错的解决方案,整理了一下写出来与大家分享。(ps:第一次写博客还不是很熟悉,诸如排版之类的问题还请大家见谅)
一.WAV文件格式
WAVE文件是非常简单的一种RIFF文件,它的格式类型为”WAVE”。RIFF块包含两个子块,这两个子块的ID分别是”fmt”和”data”,其中”fmt”子块由结构PCMWAVEFORMAT所组成,其子块的大小就是sizeofof(PCMWAVEFORMAT),数据组成就是PCMWAVEFORMAT结构中的数据。(详细介绍于http://blog.csdn.net/zhihu008/article/details/7854529中查看,这里只作简要介绍)
wav文件结构
PCMWAVEFORMAT结构定义如下:
typedef struct{ WAVEFORMAT wf; // 波形格式; WORD wBitsPerSample;//WAVE文件的采样大小;} PCMWAVEFORMAT;
WAVEFORMAT结构定义如下:
typedef struct{ WORD wFormatag;//编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等 WORD nChannls;//声道数,单声道为1,双声道为2 DWORD nSamplesPerSec;//采样频率 DWORD nAvgBytesperSec;//每秒的数据量 WORD nBlockAlign;//块对齐(每个采样的字节长度)} WAVEFORMAT;
WAV文件头结构:
typedef struct{ char chRIFF[4];//"RIFF" DWORD dwRIFFLen;//总长度-8 char chWAVE[4];//"WAVE" char chFMT[4];//"fmt " DWORD dwFMTLen;//sizeof(PCMWAVEFORMAT ) PCMWAVEFORMAT pwf; char chDATA[4];//"data" DWORD dwDATALen;//音频数据长度}WaveHeader;
其中的字符数组都是固定格式。以下分别对应8、16比特单双通道的数据存储格式图:
8bit、单通道:
8bit、双通道:
16bit、单通道:
16bit、双通道:
二.实现代码
代码有个很玄学的地方,我也不懂该怎么描述。的确能创建出指定频率的wav文件,但是生成8bit和16bit波形数据有一些不懂,我找了很久也没能发现原因。其中值得注意的是,当创建并读写wav文件时,要以二进制打开。
#include <windows.h> #include <mmsystem.h>#include <iostream>#include<fstream> #include<math.h>#define WAVE_HEAD_LENGTH 44//wav头文件长度#define m_samplefreq 44100#define m_channels 2#define m_channelbits 8#define MATH_PI 3.1415using namespace std;//.wav文件的文件头结构 typedef struct{ char chRIFF[4]; DWORD dwRIFFLen; char chWAVE[4]; char chFMT[4]; DWORD dwFMTLen; 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 = 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 = amp / 100 * 32768 * sin(2 * MATH_PI * freq * i / rate) ; INT16 vr = 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) = sin(i * (MATH_PI * 2) / rate * freq) * amp * 128 / 100 + 128; } } else { for (int i = 0; i < len; i++) { *(p + flag)= sin(i * (MATH_PI * 2) / rate * freq) * amp * 128 / 100+128; *(p + flag + 1)= sin((i+5) * (MATH_PI * 2) / rate * freq) * amp * 128 / 100+128; flag += 2; } } }}int Create(int freq, int volume, int durations)//频率、音量、持续时间{ 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); MakeWaveData(pHeader->pwf.wf.nSamplesPerSec, freq, volume, pWaveBuffer+ WAVE_HEAD_LENGTH, m_samplefreq*durations);//采样点数 ofstream ocout; ocout.open("D:\\newWave.wav", ios::out | ios::binary);//以二进制形式打开文件 if (ocout) ocout.write(pWaveBuffer, totalLen); else return 0; ocout.close(); delete(pHeader); return 1;}int main(){ if (Create(10000, 100, 5)) cout << "创建成功!" << endl; else cout << "创建失败!" << endl; return 0;}
生成的8bit音频文件频谱:
参考资料:
http://blog.csdn.net/zhihu008/article/details/7854529#comments
http://bbs.csdn.net/topics/390026541/
1 0
- C++根据频率生成wav音频文件
- C语言创建生成WAV音频文件
- wav音频文件
- WAV音频文件
- C#WAV音频文件转化PCM数据文件PCM转化WAV音频
- wav音频文件的结构
- 读取*.wav音频文件
- 微软Wav音频文件解析
- WAV音频文件格式
- 读取*.wav音频文件
- OpenAL播放WAV音频文件
- WP8录制Wav音频文件
- wav音频文件格式分析
- wav音频文件头解析
- MFC播放wav音频文件
- wav音频文件格式解析
- java切割wav音频文件
- 音频文件pcm转换wav
- 2.7
- java hasNextInt判断是否为数字
- CMake&yacc&lex
- 公钥、密钥、SSL、会话密钥的简单解释
- 智能电子时钟(定时、报警、灯光自动调节)
- C++根据频率生成wav音频文件
- 网络请求框架对比
- Android端和服务端Tomcat的https添加记录
- java基础学习之函数 三
- oracle特有分析函数
- cocos2dx 函数作为参数进行传递和调用(std::function跟CC_CALLBACK_1的使用)
- PowerDesigner:导入SQL脚本
- python将日志导入数据库代码案例 3
- C++指针的引用