调用CImg库显示WAV格式音频波形

在做傅里叶变换和小波变换时经常要通过显示波形来检验算法,但通过visual studio之类显示波形又显得麻烦,而且不能跨平台。

CImg是一个跨平台的C++的图像处理库,提供的图像处理等功能十分强大,而且加入项目中十分轻便,只需将头文件包含在项目中即可,十分轻便。

可自行到http://www.cimg.eu/下载

利用它来在linux、Mac OS X中显示波形,再合适不过了,下面是音频波形显示的代码。

主函数

main.cpp

#include <iostream>
#include "wavfile.h"
#include "CImg.h"

using namespace std;
using namespace cimg_library;
using namespace AudioUtils;

int main(void)
{
    WaveFile *wf=new WaveFile();
    /*
    读取本目录里的audio.wav文件,并生成波形
    */
    wf->readwav("audio.wav");

    int datalength=wf->size()/wf->bit();

    wf->output_WAVfile_info();

    int *data=(int*)malloc(sizeof(int)*datalength);
    for(int i=0;i<datalength;i++)
    {
        data[i]=(float)(wf->data[i]/100);
    }
    /*
    调用CImg显示波形
    */
    const unsigned char red[] = { 255, 0, 0 }, yellow[] = { 255, 255, 0 },
    green[] = { 0, 255, 0 };
    /*
    一维信号
    */
    int num=wf->size()/(8*(wf->bit()));
    CImg<float> signal_wav(num,1, 1, 1, 0);
    for(int i=0;i<num;i++)
    {
        signal_wav[i]=(data[i*8])*100;
    }

    CImg<unsigned char> signal_visu( 1200, 400, 1, 3, 0 );
   /*
   画格子
   */
    signal_visu.draw_grid( 50, 50, 0, 0, 0, 0, yellow, 0.5 );

    signal_visu.draw_graph(signal_wav,red,1,3,0,35000,-35000,0);
    /*
    画波形
    */
    CImgDisplay main_disp_wav (signal_visu,  "signal" );

    getchar();

    return 0;
} 

wavfile.h

  1 #ifndef WAVFILE_H
  2 #define WAVFILE_H
  3 #include <iostream>
  4 #include <fstream>
  5 using namespace std;
  6
  7 /*
  8 BYTE=unsigned char(完全等同)         WORD=unsigned short(完全等同)         DWORD=unsigned long(完全等同)
  9
 10 unsigned char是无符号字节型
 11 */
 12 namespace AudioUtils
 13 {
 14     /*
 15     RIFF WAVE Chunk
 16     ==================================
 17     |       |所占字节数|  具体内容   |
 18     ==================================
 19     | ID    |  4 Bytes |   ‘RIFF‘    |
 20     ----------------------------------
 21     | Size  |  4 Bytes |             |
 22     ----------------------------------
 23     | Type  |  4 Bytes |   ‘WAVE‘    |
 24     ----------------------------------
 25
 26
 27     */
 28     class RiffBlock
 29     {
 30     public:
 31         void ReadRiff(ifstream &infile)
 32         {
 33             int i=0;
 34             for(i=0;i<4;i++)
 35             {
 36                 infile.read((char*)&m_RiffID[i],1);
 37             }
 38             infile.read((char*)&m_RiffSize,4);
 39             for(i=0;i<4;i++)
 40             {
 41                 infile.read((char*)&Format[i],1);
 42             }
 43         }
 44
 45         /*
 46         此处应当声明为pravte 用函数return, 不安全代码,暂简略处理
 47         */
 48         unsigned char m_RiffID[4];
 49         unsigned long m_RiffSize;
 50         unsigned char Format[4];
 51     };
 52     /*
 53     ====================================================================
 54     |               |   字节数  |              具体内容                |
 55     ====================================================================
 56     | ID            |  4 Bytes  |   ‘fmt ‘                             |
 57     --------------------------------------------------------------------
 58     | Size          |  4 Bytes  | 数值为16或18,18则最后又附加信息     |
 59     --------------------------------------------------------------------  ----
 60     | FormatTag     |  2 Bytes  | 编码方式,一般为0x0001               |     |
 61     --------------------------------------------------------------------     |
 62     | Channels      |  2 Bytes  | 声道数目,1--单声道;2--双声道       |     |
 63     --------------------------------------------------------------------     |
 64     | SamplesPerSec |  4 Bytes  | 采样频率                             |     |
 65     --------------------------------------------------------------------     |
 66     | AvgBytesPerSec|  4 Bytes  | 每秒所需字节数                       |     |===> WAVE_FORMAT
 67     --------------------------------------------------------------------     |
 68     | BlockAlign    |  2 Bytes  | 数据块对齐单位(每个采样需要的字节数) |     |
 69     --------------------------------------------------------------------     |
 70     | BitsPerSample |  2 Bytes  | 每个采样需要的bit数                  |     |
 71     --------------------------------------------------------------------     |
 72     |               |  2 Bytes  | 附加信息(可选,通过Size来判断有无) |     |
 73     --------------------------------------------------------------------  ----
 74
 75     */
 76     class FmtBlock
 77     {
 78     public:
 79         //seekg()移动文件指针
 80         void ReadFmt(ifstream &infile)
 81         {
 82             int i=0;
 83             for(i=0;i<4;i++)
 84             {
 85                 infile.read((char*)&m_FmtID[i],1);
 86             }
 87             infile.read((char*)&m_FmtSize,4);
 88             int size=m_FmtSize;
 89             infile.read((char*)&m_FmtTag,2);
 90             infile.read((char*)&m_Channels,2);
 91             infile.read((char*)&m_SamplesPerSec,4);
 92             infile.read((char*)&m_AverageBytesPerSec,4);
 93             infile.read((char*)&m_BlockAlign,2);
 94             infile.read((char*)&m_BitsPerSample,2);
 95             if(size==18)
 96             {
 97                 infile.read((char*)&m_OtherMeg,2);
 98             }
 99         }
100
101         int BitsPerSample()
102         {
103             return (m_BitsPerSample/8);
104         }
105
106         unsigned char m_FmtID[4];
107         unsigned long m_FmtSize;
108         unsigned short m_FmtTag;
109         unsigned short m_Channels;
110         unsigned long m_SamplesPerSec;
111         unsigned long m_AverageBytesPerSec;
112         unsigned short m_BlockAlign;
113         unsigned short m_BitsPerSample;
114         unsigned short m_OtherMeg;
115     };
116
117     /*
118     Data Chunk
119     ==================================
120     |       |所占字节数|  具体内容   |
121     ==================================
122     | ID    |  4 Bytes |   ‘data‘    |
123     ----------------------------------
124     | Size  |  4 Bytes |             |
125     ----------------------------------
126     | data  |          |             |
127     ----------------------------------
128
129     1Bytes
130     ---------------------------------------------------------------------
131     |   单声道    |    取样1    |    取样2    |    取样3    |    取样4    |
132     |                   |  --------------------------------------------------------
133     |  8bit量化 |    声道0    |    声道0    |    声道0    |    声道0    |
134     ---------------------------------------------------------------------
135     |   双声道    |          取样1                      |           取样2                      |
136     |                   |--------------------------------------------------------
137     |  8bit量化 |  声道0(左)  |  声道1(右)  |  声道0(左)  |  声道1(右)  |
138    1WORD
139    ---------------------------------------------------------------------
140     |                    |          取样1                        |           取样2                       |
141     |   单声道     |--------------------------------------------------------
142     | 16bit量化 |    声道0       |  声道0          |    声道0       |  声道0          |
143     |                    | (低位字节)  | (高位字节)  | (低位字节)  | (高位字节)   |
144     ---------------------------------------------------------------------
145     |                    |                         取样1                                                       |
146     |   双声道     |--------------------------------------------------------
147     | 16bit量化 |  声道0(左)    |  声道0(左)  |  声道1(右)   |  声道1(右)   |
148     |                     | (低位字节)  | (高位字节)  | (低位字节)  | (高位字节)  |
149     ---------------------------------------------------------------------
150
151     */
152     class DataBlock
153     {
154     public:
155         void ReadData(ifstream &infile,int BitsPerSample)//BitsPerSample:1 8bit;2 16bit
156         {
157             int i=0;
158
159             bool un_find_data=true;
160             while(un_find_data)
161             {
162                 infile.read((char*)&temp,1);
163                 if(temp==‘d‘)
164                 {
165                     infile.read((char*)&temp,1);
166                     if(temp==‘a‘)
167                     {
168                         infile.read((char*)&temp,1);
169                         if(temp==‘t‘)
170                         {
171                             infile.read((char*)&temp,1);
172                             if(temp==‘a‘)
173                             {
174                                 un_find_data=false;
175                             }
176                         }
177                     }
178
179                 }
180             }
181
182             infile.read((char*)&m_DataSize,4);
183             m_NumSamples=m_DataSize/BitsPerSample;
184             if(BitsPerSample==1)
185             {
186               m_Data8=new char[m_NumSamples];
187               for(i=0;i<m_NumSamples;i++)
188               {
189                 infile.read((char*)&m_Data8[i],BitsPerSample);
190               }
191             }
192             else if(BitsPerSample==2)
193             {
194               m_Data16=new short[m_NumSamples];
195               for(i=0;i<m_NumSamples;i++)
196               {
197                 infile.read((char*)&m_Data16[i],BitsPerSample);
198               }
199             }
200
201
202         }
203
204         short *m_Data16;
205         char *m_Data8;
206
207         unsigned char temp;
208         unsigned char m_DataID[4];
209         unsigned long m_DataSize;
210
211
212         int    m_NumSamples;//样本数量
213     };
214     class WaveFile
215     {
216     public:
217         void readwav(char *path)
218         {
219             ifstream infile(path,ios::binary);
220             m_Riff = new RiffBlock();
221             m_Fmt = new FmtBlock();
222             m_Data = new DataBlock();
223
224             m_Riff->ReadRiff(infile);
225             m_Fmt->ReadFmt(infile);
226             m_Data->ReadData(infile,m_Fmt->BitsPerSample());
227             int i=0;
228             data=new int[m_Data->m_DataSize/m_Fmt->BitsPerSample()];
229             for(i=0;i<(m_Data->m_DataSize)/(m_Fmt->BitsPerSample());i++)
230             {
231
232                 if(m_Fmt->BitsPerSample()==1)
233                 {
234                    data[i]=(int)m_Data->m_Data8[i];
235                 }
236                 else if(m_Fmt->BitsPerSample()==2)
237                 {
238                    data[i]=(int)m_Data->m_Data16[i];
239                 }
240             }
241
242         }
243
244
245         void output_WAVfile_info(void)//test
246         {
247             cout<<"Audio Msg:"<<endl;
248             /*
249             RIFF WAVE Chunk Message
250             */
251             cout<<m_Riff->m_RiffID<<endl;
252             cout<<m_Riff->m_RiffSize<<endl;
253             cout<<m_Riff->Format<<endl;
254
255             /*
256             Fmt Message
257             */
258             cout<<m_Fmt->m_FmtID<<endl;
259             cout<<m_Fmt->m_FmtSize<<endl;
260             cout<<m_Fmt->m_FmtTag<<endl;
261             cout<<m_Fmt->m_Channels<<endl;
262             cout<<m_Fmt->m_SamplesPerSec<<endl;
263             cout<<m_Fmt->m_AverageBytesPerSec<<endl;
264             cout<<m_Fmt->m_BlockAlign<<endl;
265             cout<<m_Fmt->m_BitsPerSample<<endl;
266             cout<<m_Fmt->m_OtherMeg<<endl;
267             /*
268             Data Chunk Message
269             */
270             cout<<m_Data->temp<<endl;
271             cout<<m_Data->m_DataID<<endl;
272             cout<<m_Data->m_DataSize<<endl;
273
274         }
275         int size(void)//音频长度
276         {
277             return m_Data->m_DataSize;
278         }
279         int channels(void)
280         {
281             return m_Fmt->m_Channels;
282         }
283         int bit(void)
284         {
285             return m_Fmt->BitsPerSample();
286         }
287         int *data;
288     private:
289          RiffBlock            *m_Riff;
290          FmtBlock            *m_Fmt;
291          DataBlock            *m_Data;
292     };
293 }
294
295 #endif

编译时运行如下命令:

1 g++ -o out main.cpp -O2 -lm -lpthread -L/usr/X11R6/lib -lm -lpthread -lX11

结果:

时间: 2024-10-26 22:24:51

调用CImg库显示WAV格式音频波形的相关文章

(原创)speex与wav格式音频文件的互相转换

我们的司信项目又有了新的需求,就是要做会议室.然而需求却很纠结,要继续按照原来发语音消息那样的形式来实现这个会议的功能,还要实现语音播放的计时,暂停,语音的拼接,还要绘制频谱图等等. 如果是wav,mp3不论你怎么拼接,绘制频谱图,我也没有问题,网上都有现成的例子.然而这一次居然让用speex的音频做这一切. 于是看了司信之前的发语音消息部分speex的代码,天啊,人家录的时候这是实时录音实时编码的好不好,人家放的时候也是实时解码实时播放的好不好.你这让我怎么通过 一个speex文件就得到全部的

音频文件解析(二):WAV格式文件波形绘制

解析WAV头部信息后,接下来就可以根据相关参数和DATA块数据绘制波形. 1.重新编码(转换为8bits,单声道数据) Public Function GetFormatData(ByVal pData() As Byte, ByVal pWaveHeader As waveHeaderStructre) As Byte() Dim temp As Integer Dim data() As Byte = {} If pWaveHeader.BitsPerSample = 8 And pWave

vs2010音频文件压缩 调用lame_enc.dll将WAV格式转换成MP3

/* //My_lame.h */ #pragma once#include "stdafx.h"#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <string>#include "BladeMP3EncDLL.h"class My_lame{public: My_lame(void); ~My_lame(void); HINSTANC

iOS 使用EZAudio库生成wav出错的情况

使用EZAudio库 录M4A格式可以参考该库例子中的代码. 录wav格式得改下源码.看下面的代码 1 AVAudioSession *session = [AVAudioSession sharedInstance]; 2 NSError *error = nil; 3 [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; 4 if (error) NSLog(@"audio session ca

Python 调用pyaudio库录制以及播放wav音频文件

1.Pyaudio简介 PyAudio 是语音处理的 Python 库,提供了比较丰富的功能. 2.功能 python的Pyaud模块可以调用电脑的麦克风或音响进行录音,音频播放,生成wav文件等. wave是录音是用的标准的WINDOWS文件格式,扩展名为WAV,数据本身的格式为PCM或压缩型,属于无损音乐格式的一种. 3.Pyaudio安装 pip install pyaudio 推荐使用清华源哦,速度快 pip install pyaudio -i https://pypi.tuna.ts

Android音频: 如何使用AudioTrack播放一个WAV格式文件?

翻译 By Long Luo 原文链接:Android Audio: Play a WAV file on an AudioTrack 译者注: 1. 由于这是技术文章,所以有些词句使用原文,表达更准确. 2. 由于水平有效,有些地方可能翻译的不够准确,如有不当之处,敬请批评指正. 3. 针对某些语句,适当补充了上下文及更适合中文阅读,尽量做到信达雅. 如果你已经成功地了解了关于AudioTrack的一些话题,那么你可能享受它带来的好处,例如低延迟(在STATIC(静态)模式),能够生成流式音频

音频文件解析(一):WAV格式文件头部解析

WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源. 1.RIFF块(RIFF-Chunk) 偏移地址 字节数 数据类型 内容 &H00 4 String 'RIFF'文件标志 &H04 4 UInteger 文件总长 &H08  4  String  'WAVE'文件标志 2.格式化块(Format-Chunk) 偏移地址 字节数 数据类

多浏览器播放wav格式的音频文件

html5的audio标签只在火狐下支持wav格式的音频播放,无法兼容IE和google , 使用audioplayer.js 基本上能支持大部分浏览器播放wav音频文件,经测试IE.火狐.google浏览器都可以播放wav格式的音频 当audio标签不支持或者audio不能播放相应格式的文件时,播放器将使用迷你模式,使用embed元素来播放音频,功能支持将较少 使用方法: 1.html中加入audio标签 <audio controls="controls" id="

基于matlab的音频波形实时采集显示 v0.1

robj = audiorecorder(44100,16,1); %设置采样频率.采样位数.通道数 recordblocking(robj,1); %采集初步数据(1s长度) rdata = getaudiodata(robj); %获取音频数据 plot(rdata); %绘制波形 axis([1,44100,-0.1,0.1]); %设置固定坐标轴 drawnow %刷新显示 n = 100; %设定后续的采样更新次数,n与m可联合计算后续更新时间长度 m = 0.1; %设定更新间隔,m