最近在做傅里叶变换和小波变换时经常要通过显示波形来检验算法,但通过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. POJ 2104:K-th Number(整体二分)

    http://poj.org/problem?id=2104 题意:给出n个数和m个询问求区间第K小. 思路:以前用主席树做过,这次学整体二分来做.整体二分在yr大佬的指点下,终于大概懂了点了.对于二 ...

  2. 《Javascript权威指南》

    <Javascript权威指南> chorme.safari中的input或textarea html超链接(a)详细讲解 html5新增及删除标签 html表格 图片加alt属性

  3. JavaScript忍者秘籍——运行时代码求值

    1. 代码求值机制 JavaScript中,有很多不同的代码求值机制. ● eval()函数 ● 函数构造器 ● 定时器 ● <script>元素 - 用eval()方法进行求值 作为定义 ...

  4. python numpy基础 数组和矢量计算

    在python 中有时候我们用数组操作数据可以极大的提升数据的处理效率, 类似于R的向量化操作,是的数据的操作趋于简单化,在python 中是使用numpy模块可以进行数组和矢量计算. 下面来看下简单 ...

  5. linux(x64)下安装Matlab 2015b破解版(含安装包)

    注意:在安装前请查看安装目录是否有足够空间!完全安装大概需要12G的空间!本人在安装后系统盘满了,导致无法启动图形界面.小伙伴们不要重蹈覆辙~ Environment Linux debian8 (x ...

  6. Web多客户端单点登录

    一  数据库 除了用户表之外,新建一个外联表<用户票据表> fdUsTiUserID,fdUsTiType,fdUsTiTicket 分别对应用户ID,客户端类型(PC,mobile) 票 ...

  7. 郑州尚学堂:如何在Java中创建对象

    作为Java开发者,每天都会创建大量的对象,但是,我们总是使用管理依赖系统(如Spring框架)来创建这些对象.其实还有其他方法可以创建对象,在接下来的文章中我会进行详细介绍. 1.使用new关键字 ...

  8. Partial Tree

    Partial Tree 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5534 完全背包 做这题前去学习了下完全背包,觉得这个优化简直神技!(以前都是 ...

  9. C#_FindWindow

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  10. js--事件对象的理解1

    在触发DOM上的某个事件时,会产生一个事件对象event.这个对象中包含着所有与事件有关的信息.包括导致事件的元素,事件的类型以及其他与特定事件相关的信息. 举例鼠标操作导致的事件对象中,会包含鼠标位 ...