首页 > 代码库 > 调用CImg库显示WAV格式音频波形

调用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=http://www.mamicode.com/(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 Chunk119     ==================================120     |       |所占字节数|  具体内容   |121     ==================================122     | ID    |  4 Bytes |   ‘data‘    |123     ----------------------------------124     | Size  |  4 Bytes |             |125     ----------------------------------126     | data  |          |             |127     ----------------------------------128 129     1Bytes130     ---------------------------------------------------------------------131     |   单声道    |    取样1    |    取样2    |    取样3    |    取样4    |132     |                   |  --------------------------------------------------------133     |  8bit量化 |    声道0    |    声道0    |    声道0    |    声道0    |134     ---------------------------------------------------------------------135     |   双声道    |          取样1                      |           取样2                      |136     |                   |--------------------------------------------------------137     |  8bit量化 |  声道0(左)  |  声道1(右)  |  声道0(左)  |  声道1(右)  |138    1WORD139    ---------------------------------------------------------------------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 DataBlock153     {154     public:155         void ReadData(ifstream &infile,int BitsPerSample)//BitsPerSample:1 8bit;2 16bit156         {157             int i=0;158 159             bool un_find_data=http://www.mamicode.com/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=http://www.mamicode.com/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 WaveFile215     {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 = http://www.mamicode.com/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=http://www.mamicode.com/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)//test246         {247             cout<<"Audio Msg:"<<endl;248             /*249             RIFF WAVE Chunk Message250             */251             cout<<m_Riff->m_RiffID<<endl;252             cout<<m_Riff->m_RiffSize<<endl;253             cout<<m_Riff->Format<<endl;254 255             /*256             Fmt Message257             */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 Message269             */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

 

结果:

技术分享

 

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