zoukankan      html  css  js  c++  java
  • 调用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

    读取WAV格式文件

      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

    结果:

  • 相关阅读:
    字典对象的 Pythonic 用法(上篇:转载)
    代码这样写更优雅(Python 版)(转载)
    [Python爬虫] 之二十七:Selenium +phantomjs 利用 pyquery抓取今日头条视频
    [Python爬虫] 之二十六:Selenium +phantomjs 利用 pyquery抓取智能电视网站图片信息
    [Python爬虫] 之二十五:Selenium +phantomjs 利用 pyquery抓取今日头条网数据
    [Python爬虫] 之二十四:Selenium +phantomjs 利用 pyquery抓取中广互联网数据
    [Python爬虫] 之二十三:Selenium +phantomjs 利用 pyquery抓取智能电视网数据
    MOVE降低高水位 HWM
    select查询语句执行顺序
    Oracle表空间维护总结
  • 原文地址:https://www.cnblogs.com/bindong/p/5862102.html
Copyright © 2011-2022 走看看