最近在做傅里叶变换和小波变换时经常要通过显示波形来检验算法,但通过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=;i<datalength;i++)
{
data[i]=(float)(wf->data[i]/);
}
/*
调用CImg显示波形
*/
const unsigned char red[] = { , , }, yellow[] = { , , },
green[] = { , , };
/*
一维信号
*/
int num=wf->size()/(*(wf->bit()));
CImg<float> signal_wav(num,, , , );
for(int i=;i<num;i++)
{
signal_wav[i]=(data[i*])*;
} CImg<unsigned char> signal_visu( , , , , );
/*
画格子
*/
signal_visu.draw_grid( , , , , , , yellow, 0.5 ); signal_visu.draw_graph(signal_wav,red,,,,,-,);
/*
画波形
*/
CImgDisplay main_disp_wav (signal_visu, "signal" ); getchar(); return ;
}

wavfile.h

读取WAV格式文件

 #ifndef WAVFILE_H
#define WAVFILE_H
#include <iostream>
#include <fstream>
using namespace std; /*
BYTE=unsigned char(完全等同)         WORD=unsigned short(完全等同)         DWORD=unsigned long(完全等同) unsigned char是无符号字节型
*/
namespace AudioUtils
{
/*
RIFF WAVE Chunk
==================================
| |所占字节数| 具体内容 |
==================================
| ID | 4 Bytes | 'RIFF' |
----------------------------------
| Size | 4 Bytes | |
----------------------------------
| Type | 4 Bytes | 'WAVE' |
---------------------------------- */
class RiffBlock
{
public:
void ReadRiff(ifstream &infile)
{
int i=;
for(i=;i<;i++)
{
infile.read((char*)&m_RiffID[i],);
}
infile.read((char*)&m_RiffSize,);
for(i=;i<;i++)
{
infile.read((char*)&Format[i],);
}
} /*
此处应当声明为pravte 用函数return, 不安全代码,暂简略处理
*/
unsigned char m_RiffID[];
unsigned long m_RiffSize;
unsigned char Format[];
};
/*
====================================================================
| | 字节数 | 具体内容 |
====================================================================
| ID | 4 Bytes | 'fmt ' |
--------------------------------------------------------------------
| Size | 4 Bytes | 数值为16或18,18则最后又附加信息 |
-------------------------------------------------------------------- ----
| FormatTag | 2 Bytes | 编码方式,一般为0x0001 | |
-------------------------------------------------------------------- |
| Channels | 2 Bytes | 声道数目,1--单声道;2--双声道 | |
-------------------------------------------------------------------- |
| SamplesPerSec | 4 Bytes | 采样频率 | |
-------------------------------------------------------------------- |
| AvgBytesPerSec| 4 Bytes | 每秒所需字节数 | |===> WAVE_FORMAT
-------------------------------------------------------------------- |
| BlockAlign | 2 Bytes | 数据块对齐单位(每个采样需要的字节数) | |
-------------------------------------------------------------------- |
| BitsPerSample | 2 Bytes | 每个采样需要的bit数 | |
-------------------------------------------------------------------- |
| | 2 Bytes | 附加信息(可选,通过Size来判断有无) | |
-------------------------------------------------------------------- ---- */
class FmtBlock
{
public:
//seekg()移动文件指针
void ReadFmt(ifstream &infile)
{
int i=;
for(i=;i<;i++)
{
infile.read((char*)&m_FmtID[i],);
}
infile.read((char*)&m_FmtSize,);
int size=m_FmtSize;
infile.read((char*)&m_FmtTag,);
infile.read((char*)&m_Channels,);
infile.read((char*)&m_SamplesPerSec,);
infile.read((char*)&m_AverageBytesPerSec,);
infile.read((char*)&m_BlockAlign,);
infile.read((char*)&m_BitsPerSample,);
if(size==)
{
infile.read((char*)&m_OtherMeg,);
}
} int BitsPerSample()
{
return (m_BitsPerSample/);
} unsigned char m_FmtID[];
unsigned long m_FmtSize;
unsigned short m_FmtTag;
unsigned short m_Channels;
unsigned long m_SamplesPerSec;
unsigned long m_AverageBytesPerSec;
unsigned short m_BlockAlign;
unsigned short m_BitsPerSample;
unsigned short m_OtherMeg;
}; /*
Data Chunk
==================================
| |所占字节数| 具体内容 |
==================================
| ID | 4 Bytes | 'data' |
----------------------------------
| Size | 4 Bytes | |
----------------------------------
| data | | |
---------------------------------- 1Bytes
---------------------------------------------------------------------
| 单声道 | 取样1 | 取样2 | 取样3 | 取样4 |
| | --------------------------------------------------------
| 8bit量化 | 声道0 | 声道0 | 声道0 | 声道0 |
---------------------------------------------------------------------
| 双声道 | 取样1 | 取样2 |
| |--------------------------------------------------------
| 8bit量化 | 声道0(左) | 声道1(右) | 声道0(左) | 声道1(右) |
1WORD
---------------------------------------------------------------------
| | 取样1 | 取样2 |
| 单声道 |--------------------------------------------------------
| 16bit量化 | 声道0 | 声道0 | 声道0 | 声道0 |
| | (低位字节) | (高位字节) | (低位字节) | (高位字节) |
---------------------------------------------------------------------
| | 取样1 |
| 双声道 |--------------------------------------------------------
| 16bit量化 | 声道0(左) | 声道0(左) | 声道1(右) | 声道1(右) |
| | (低位字节) | (高位字节) | (低位字节) | (高位字节) |
--------------------------------------------------------------------- */
class DataBlock
{
public:
void ReadData(ifstream &infile,int BitsPerSample)//BitsPerSample:1 8bit;2 16bit
{
int i=; bool un_find_data=true;
while(un_find_data)
{
infile.read((char*)&temp,);
if(temp=='d')
{
infile.read((char*)&temp,);
if(temp=='a')
{
infile.read((char*)&temp,);
if(temp=='t')
{
infile.read((char*)&temp,);
if(temp=='a')
{
un_find_data=false;
}
}
} }
} infile.read((char*)&m_DataSize,);
m_NumSamples=m_DataSize/BitsPerSample;
if(BitsPerSample==)
{
m_Data8=new char[m_NumSamples];
for(i=;i<m_NumSamples;i++)
{
infile.read((char*)&m_Data8[i],BitsPerSample);
}
}
else if(BitsPerSample==)
{
m_Data16=new short[m_NumSamples];
for(i=;i<m_NumSamples;i++)
{
infile.read((char*)&m_Data16[i],BitsPerSample);
}
} } short *m_Data16;
char *m_Data8; unsigned char temp;
unsigned char m_DataID[];
unsigned long m_DataSize; int m_NumSamples;//样本数量
};
class WaveFile
{
public:
void readwav(char *path)
{
ifstream infile(path,ios::binary);
m_Riff = new RiffBlock();
m_Fmt = new FmtBlock();
m_Data = new DataBlock(); m_Riff->ReadRiff(infile);
m_Fmt->ReadFmt(infile);
m_Data->ReadData(infile,m_Fmt->BitsPerSample());
int i=;
data=new int[m_Data->m_DataSize/m_Fmt->BitsPerSample()];
for(i=;i<(m_Data->m_DataSize)/(m_Fmt->BitsPerSample());i++)
{ if(m_Fmt->BitsPerSample()==)
{
data[i]=(int)m_Data->m_Data8[i];
}
else if(m_Fmt->BitsPerSample()==)
{
data[i]=(int)m_Data->m_Data16[i];
}
} } void output_WAVfile_info(void)//test
{
cout<<"Audio Msg:"<<endl;
/*
RIFF WAVE Chunk Message
*/
cout<<m_Riff->m_RiffID<<endl;
cout<<m_Riff->m_RiffSize<<endl;
cout<<m_Riff->Format<<endl; /*
Fmt Message
*/
cout<<m_Fmt->m_FmtID<<endl;
cout<<m_Fmt->m_FmtSize<<endl;
cout<<m_Fmt->m_FmtTag<<endl;
cout<<m_Fmt->m_Channels<<endl;
cout<<m_Fmt->m_SamplesPerSec<<endl;
cout<<m_Fmt->m_AverageBytesPerSec<<endl;
cout<<m_Fmt->m_BlockAlign<<endl;
cout<<m_Fmt->m_BitsPerSample<<endl;
cout<<m_Fmt->m_OtherMeg<<endl;
/*
Data Chunk Message
*/
cout<<m_Data->temp<<endl;
cout<<m_Data->m_DataID<<endl;
cout<<m_Data->m_DataSize<<endl; }
int size(void)//音频长度
{
return m_Data->m_DataSize;
}
int channels(void)
{
return m_Fmt->m_Channels;
}
int bit(void)
{
return m_Fmt->BitsPerSample();
}
int *data;
private:
RiffBlock *m_Riff;
FmtBlock *m_Fmt;
DataBlock *m_Data;
};
} #endif

编译时运行如下命令:

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

结果:

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

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

    我们的司信项目又有了新的需求,就是要做会议室.然而需求却很纠结,要继续按照原来发语音消息那样的形式来实现这个会议的功能,还要实现语音播放的计时,暂停,语音的拼接,还要绘制频谱图等等. 如果是wav,m ...

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

    之前写过了如何将speex与wav格式的音频互相转换,如果没有看过的请看一下连接 http://www.cnblogs.com/dongweiq/p/4515186.html 虽然自己实现了相关的压缩 ...

  3. c#使用SoundPlayer播放wav格式音频

    1.引用System.Media名称空间下的类SoundPlayer   SoundPlayer player = new SoundPlayer(); 2.方法调用Play(); public vo ...

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

    解析WAV头部信息后,接下来就可以根据相关参数和DATA块数据绘制波形. 1.重新编码(转换为8bits,单声道数据) Public Function GetFormatData(ByVal pDat ...

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

    /* //My_lame.h */ #pragma once#include "stdafx.h"#include <windows.h>#include <st ...

  6. Android 音视频开发(一):PCM 格式音频的播放与采集

    什么是 PCM 格式 声音从模拟信号转化为数字信号的技术,经过采样.量化.编码三个过程将模拟信号数字化. 采样 顾名思义,对模拟信号采集样本,该过程是从时间上对信号进行数字化,例如每秒采集 44100 ...

  7. WAV格式文件无损合并&帧头数据体解析(python)(原创)

    一,百度百科 WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频 ...

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

    使用EZAudio库 录M4A格式可以参考该库例子中的代码. 录wav格式得改下源码.看下面的代码 AVAudioSession *session = [AVAudioSession sharedIn ...

  9. Android音频: 怎样使用AudioTrack播放一个WAV格式文件?

    翻译 By Long Luo 原文链接:Android Audio: Play a WAV file on an AudioTrack 译者注: 1. 因为这是技术文章,所以有些词句使用原文,表达更准 ...

随机推荐

  1. 《C++反汇编与逆向分析技术揭秘》——观察各种表达式的求值过程

    ---恢复内容开始--- 加法: 示例: 常量相加,则在编译期间就计算出两个常量相加后的结果,直接将这个结果参与运算,减少了运行期的计算.当有变量参与运算时,会先取出内存中的数据,放入通用寄存器中,再 ...

  2. java通过JDBC链接SQLServer2012 (含1433端口打通)

    首先,在连接数据库之前必须保证SQL Server 2012是采用SQL Server身份验证方式而不是windows身份验证方式.如果在安装时选用了后者,则重新设置如下: http://blog.1 ...

  3. requests模拟登录

    #coding:utf-8 #author:jwong import requests import urllib2 import re from bs4 import BeautifulSoup a ...

  4. HDU 1329 Hanoi Tower Troubles Again!(乱搞)

    Hanoi Tower Troubles Again! Problem Description People stopped moving discs from peg to peg after th ...

  5. sqlserver 操作xml

    1.xml.exist    输入为XQuery表达式,返回0,1或是Null.0表示不存在,1表示存在,Null表示输入为空 2.xml.value    输入为XQuery表达式,返回一个SQL ...

  6. Python基础知识学习_Day1

    1,python介绍 诞生于1989年圣诞节,目前越来越受到业界认可.应用领域十分广泛 云计算: 云计算最火的语言, 典型应用OpenStack WEB开发: 众多优秀的WEB框架,众多大型网站均为P ...

  7. java 缩放函数drawImage理解(个人总结)

    drawImagepublic abstract boolean drawImage(Image img,                                  int dx1,      ...

  8. 服务管理--systemctl命令

    摘要: systemctl 是系统服务管理器命令,它实际上将 service 和 chkconfig 这两个命令组合到一起. 任务 旧指令 新指令 使某服务自动启动 chkconfig --level ...

  9. EM算法及其推广的要点

    1.EM算法是含有隐变量的变量的概率模型极大似然估计或极大后验概率估计的迭代算法,含有隐变量的概率模型的数据表示为$P(Y,Z|\theta)$.这里,$Y$是观测变量的数据,$Z$是隐变量的数据,$ ...

  10. libimobiledevice命令

    Mac 安装 1. 安装HomeBrew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m ...