精华内容
下载资源
问答
  • C++读取Wav文件

    万次阅读 热门讨论 2018-08-23 14:47:55
    C++的新手,自从搞了算法和kaldi开始着手C++,所以有很多坑没有趟过。最近需要把手头的matlab程序...首先在做这个问题之前,确保你自己知道,你的wav文件的采样率和位数,我这里以最普遍的16k和16bit的wav文件来说明...

    C++的新手,自从搞了算法和kaldi开始着手C++,所以有很多坑没有趟过。最近需要把手头的matlab程序转化成C++,其中涉及到读取wav音频文件的部分,着实头疼,所以上网搜了一下,并且自己进行了尝试和改写,写了自己的一个版本,在这里主要记录一下其中遇到的教训和经验理解。

    首先在做这个问题之前,确保你自己知道,你的wav文件的采样率和位数,我这里以最普遍的16k和16bit的wav文件来说明。有很大一部分人在想:我直接用二进制流暴力的读取不行吗,怎么那么多说道。同学这个思想是好的,不过有偏差。不知道你玩没玩过auditon,即使没玩过也应该听过cool edit,两款音频编辑软件。你往里面扔wav,mp3等格式的文件的时候,他什么都不会问你,自己就知道采样率和位数声道数等。而如果你扔进去pcm格式的音频的时候,他会问这问那,下面是Adobe audition的截图:

    那么你会想为什么呢?同样的两种文件为什么一个他啥都知道,一个他啥都不知道呢?仔细想不难想出:wav(mp3)等文件里面有某种标识的部分,并且已经成为了某种标准,所以按照某种解码去解读就能获取相关内容。而pcm什么都没有。那么很明显了,wav里面含有标识位,在没有把标识位找出来的请路况下直接暴力读取很明显是错误的。顺着这个思路我们上网上搜一下关于wav标识位的内容,找到如下图:

    这里的position都是字节,一定要注意。那么我们看到了每个字节都有标识什么内容,接下来我们开始设计我们的程序。用一个struct标识这个结构,由于是16位的,所以对于整数类型的我们按照两个字节一个来读取,所以我是用int16_t来表示一个最小读取单位(char除外)。那么下面给出程序:

    #include <iostream>
    #include <fstream>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    
    struct WavData{
    	public:
    		int16_t* data;
    		long size;
    		
    		WavData(){
    			data=NULL;
    			size=0;
    		}	
    };
    
    
    void loadWavFile(const char* fname,WavData *ret){
    	FILE* fp=fopen(fname,"rb");
    	if(fp){
    		char id[5];
    	        int32_t size;
    		int16_t format_tag,channels,block_align,bits_per_sample;
    		int32_t format_length,sample_rate,avg_bytes_sec,data_size;		
    		
    		fread(id,sizeof(char),4,fp);
    		id[4]='\0';
    		
    		if(!strcmp(id,"RIFF")){
    			fread(&size,sizeof(int16_t),2,fp);
    			fread(id,sizeof(char),4,fp);
    			id[4]='\0';
    
    			if(!strcmp(id,"WAVE")){
    				fread(id,sizeof(char),4,fp);
    				fread(&format_length,sizeof(int16_t),2,fp);
    				fread(&format_tag,sizeof(int16_t),1,fp);
    				fread(&channels,sizeof(int16_t),1,fp);
    				fread(&sample_rate,sizeof(int16_t),2,fp);
    				fread(&avg_bytes_sec,sizeof(int16_t),2,fp);
    				fread(&block_align,sizeof(int16_t),1,fp);
    				fread(&bits_per_sample,sizeof(int16_t),2,fp);
    				fread(id,sizeof(char),4,fp);
    				fread(&data_size,sizeof(int16_t),2,fp);
    				
    				ret->size=data_size/sizeof(int16_t);
    				// 动态分配了空间,记得要释放
    				ret->data=(int16_t*)malloc(data_size);
    				fread(ret->data,sizeof(int16_t),ret->size,fp);
    			}
    			else{
    				cout<<"Error: RIFF File but not a wave file\n";
    			}
    		}
    	else{
    		cout<<"ERROR: not a RIFF file\n";
    	}
    	}
    	fclose(fp);
    }
    
    void freeSource(WavData* data){
    	free(data->data);
    }
    
    int main(){
    	WavData song;
    	ofstream out("city_16k.txt");
    	const char* fname="city_16k.wav"; 
    	loadWavFile(fname,&song);
    	cout<<song.size<<endl;
    
    	for(long i=0;i<song.size;i++){
    		out<<song.data[i]<<',';
    	}
    
    	out.close();	
    	freeSource(&song);
    	return 0;
    }

    结果可以考证,希望帮得到大家。

    展开全文
  • 200行代码实现PCM格式的WAV文件读写,使用标准C++库实现,不依赖于其他库。 // Write WAv文件 Wave_header header(1, 48000, 16); uint32_t length = header.fmt_data->sample_per_sec * 10 * header.fmt_data...
  • 主要介绍了C++读取WAV音频文件的头部数据的实现方法的相关资料,希望通过本文能帮助到大家,让大家实现这样的方法,需要的朋友可以参考下
  • C++读取WAV格式音频文件

    热门讨论 2012-04-02 19:54:44
    这里面主要是用C++读取WAV文件的信息,包括采样率,位数,数据值等信息!
  • 最近的项目需要读下位机的数据,写成WAV文件。之前没接触过音频这块,百度了一下,过程有点曲折,但好在问题都解决了。分享一下我学习的流程和遇到的问题。 ......

    最近的项目需要读下位机的数据,写成WAV文件。之前没接触过音频这块,百度了一下,过程有点曲折,但好在问题都解决了。分享一下我学习的流程和遇到的问题。

    https://www.cnblogs.com/wangguchangqing/p/5957531.html

    展开全文
  • c++读取wav音频方法

    2020-11-03 09:42:39
    为了为接下来学习DSP做准备,我今天查了一些关于读取wav文件的资料,现将其总结与此,并编程实现(代码部分参考了网络上一些代码,修改了其中一些错误之处)。下图是我绘制的wav文件格式结构图: 代码如下: ...

    wav音频格式是微软的制定的一种文件格式,其结构非常简单音频存储格式。为了为接下来学习DSP做准备,我今天查了一些关于读取wav文件的资料,现将其总结与此,并编程实现(代码部分参考了网络上一些代码,修改了其中一些错误之处)。下图是我绘制的wav文件格式结构图:

    
    代码如下:
    
    struct ret_value
    {
        char *data;
        unsigned long size;
    
       ret_value()
       {
          data = 0;
          size = 0;
       }
    };
    
    void load_wave_file(char *fname, struct ret_value *ret)
    {
        FILE *fp;
    
        fp = fopen(fname,"rb");
        if (fp)
        {
           char id[5];         // 5个字节存储空间存储'RIFF'和'\0',这个是为方便利用strcmp
           unsigned long size;  // 存储文件大小
    
             short format_tag, channels, block_align, bits_per_sample;    // 16位数据
    
             unsigned long format_length, sample_rate, avg_bytes_sec, data_size; // 32位数据
    
           fread(id, sizeof(char), 4, fp); // 读取'RIFF'
           id[4] = '\0';
      
           if (!strcmp(id, "RIFF"))
           { 
               fread(&size, sizeof(unsigned long), 1, fp); // 读取文件大小
               fread(id, sizeof(char), 4, fp);        // 读取'WAVE'
               id[4] = '\0';
    
               if (!strcmp(id,"WAVE"))
               { 
                   fread(id, sizeof(char), 4, fp);     // 读取4字节 "fmt ";
                   fread(&format_length, sizeof(unsigned long),1,fp);
                   fread(&format_tag, sizeof(short), 1, fp); // 读取文件tag
                   fread(&channels, sizeof(short),1,fp);    // 读取通道数目
                   fread(&sample_rate, sizeof(unsigned long), 1, fp);   // 读取采样率大小
    
                     fread(&avg_bytes_sec, sizeof(unsigned long), 1, fp); // 读取每秒数据量
    
                     fread(&block_align, sizeof(short), 1, fp);     // 读取块对齐
                   fread(&bits_per_sample, sizeof(short), 1, fp);      // 读取每一样本大小
                   fread(id, sizeof(char), 4, fp);                     // 读入'data'
                   fread(&data_size, sizeof(unsigned long), 1, fp);    // 读取数据大小
                   ret->size = data_size;
                   ret->data = (char *) malloc(sizeof(char)*data_size); // 申请内存空间
                   fread(ret->data, sizeof(char), data_size, fp);      // 读取数据
    
               }
               else
              {
                   printf("Error: RIFF file but not a wave file\n");
               }
           }
           else
          {
               printf("Error: not a RIFF file\n");
          }
        }
    }
    

    南无阿弥陀佛

    展开全文
  • C++标准库实现WAV文件读写

    千次阅读 2018-10-22 21:51:40
    C++标准库实现WAV文件读写 在上一篇文章RIFF和WAVE音频文件格式中对WAV的文件格式做了介绍,本文将使用标准C++库实现对数据为PCM格式的WAV文件读写操作,只使用标准C++库函数,不依赖于其他的库。 WAV文件结构 ...

    C++标准库实现WAV文件读写

    在上一篇文章RIFF和WAVE音频文件格式中对WAV的文件格式做了介绍,本文将使用标准C++库实现对数据为PCM格式的WAV文件的读写操作,只使用标准C++库函数,不依赖于其他的库。

    WAV文件结构

    WAV是符合RIFF标准的多媒体文件,其文件结构可以如下:

    WAV 文件结构
    RIFF块
    WAVE FOURCC
    fmt 块
    fact 块(可选)
    data块(包含PCM数据)

    首先是一个RIFF块,有块标识RIFF,指明该文件是符合RIFF标准的文件;接着是一个FourCC,WAVE,该文件为WAV文件;fmt块包含了音频的一些属性:采样率、码率、声道等;fact 块是一个可选块,不是PCM数据格式的需要该块;最后data块,则包含了音频的PCM数据。实际上,可以将一个WAV文件看着由两部分组成:文件头和PCM数据,则WAV文件头各字段的意义如下:

    本文实现的是一个能够读取PCM数据格式的单声道或者双声道的WAV文件,是没有fact块以及扩展块。

    结构体定义

    通过上面的介绍发现,WAV的头文件所包含的内容有两种:RIFF文件格式标准中需要的数据和关于音频格式的信息。对于RIFF文件格式所需的信息,声明结构体如下:

    // The basic chunk of RIFF file format
    struct Base_chunk{
    
        FOURCC fcc;    // FourCC id
        uint32_t cb_size; // 数据域的大小
    
        Base_chunk(FOURCC fourcc)
            : fcc(fourcc)
        {
            cb_size = 0;
        }
    };

     

    chunk是RIFF文件的基本单元,首先一个4字节的标识FOURCC,用来指出该块的类型;cb_size则是改块数据域中数据的大小。

    文件头中另一个信息则是音频的格式信息,实际上是frm chunk的数据域信息,其声明如下:

    // Format chunk data field
    struct Wave_format{
    
        uint16_t format_tag;      // WAVE的数据格式,PCM数据该值为1
        uint16_t channels;        // 声道数
        uint32_t sample_per_sec;  // 采样率
        uint32_t bytes_per_sec;   // 码率,channels * sample_per_sec * bits_per_sample / 8
        uint16_t block_align;     // 音频数据块,每次采样处理的数据大小,channels * bits_per_sample / 8
        uint16_t bits_per_sample; // 量化位数,8、16、32等
        uint16_t ex_size;         // 扩展块的大小,附加块的大小
    
        Wave_format()
        {
            format_tag      = 1; // PCM format data
            ex_size         = 0; // don't use extesion field
    
            channels        = 0;
            sample_per_sec  = 0;
            bytes_per_sec   = 0;
            block_align     = 0;
            bits_per_sample = 0;
        }
    
        Wave_format(uint16_t nb_channel, uint32_t sample_rate, uint16_t sample_bits)
            :channels(nb_channel), sample_per_sec(sample_rate), bits_per_sample(sample_bits)
        {
            format_tag    = 0x01;                                            // PCM format data
            bytes_per_sec = channels * sample_per_sec * bits_per_sample / 8; // 码率
            block_align   = channels * bits_per_sample / 8;
            ex_size       = 0;                                               // don't use extension field
        }
    };

    关于各个字段的信息,在上面图中有介绍,这里主要说明两个字段:

    • format_tag表示以何种数据格式存储音频的sample值,这里设置为0x01表示用PCM格式,非压缩格式,不需要fact块。
    • ex_size表示的是扩展块的大小。有两种方法来设置不使用扩展块,一种是设置fmt中的size字段为16(无ex_size字段);或者,有ex_size,设置其值为0.在本文中,使用第二种方法,设置ex_size的值为0,不使用扩展块。

    有了上面两个结构体的定义,对于WAV的文件头,可以表示如下:

     

    /*
    
        数据格式为PCM的WAV文件头
        --------------------------------
        | Base_chunk | RIFF |
        ---------------------
        | WAVE              |
        ---------------------
        | Base_chunk | fmt  |   Header
        ---------------------
        | Wave_format|      |
        ---------------------
        | Base_chunk | data |
        --------------------------------
    */
    struct Wave_header{
    
        shared_ptr<Base_chunk> riff;
        FOURCC wave_fcc;
        shared_ptr<Base_chunk> fmt;
        shared_ptr<Wave_format>  fmt_data;
        shared_ptr<Base_chunk> data;
    
        Wave_header(uint16_t nb_channel, uint32_t sample_rate, uint16_t sample_bits)
        {
            riff      = make_shared<Base_chunk>(MakeFOURCC<'R', 'I', 'F', 'F'>::value);
            fmt       = make_shared<Base_chunk>(MakeFOURCC<'f', 'm', 't', ' '>::value);
            fmt->cb_size = 18;
    
            fmt_data  = make_shared<Wave_format>(nb_channel, sample_rate, sample_bits);
            data      = make_shared<Base_chunk>(MakeFOURCC<'d', 'a', 't', 'a'>::value);
    
            wave_fcc = MakeFOURCC<'W', 'A', 'V', 'E'>::value;
        }
    
        Wave_header()
        {
            riff         = nullptr;
            fmt          = nullptr;
    
            fmt_data     = nullptr;
            data         = nullptr;
    
            wave_fcc     = 0;
        }
    };

    在WAV的文件头中有三种chunk,分别为:RIFF,fmt,data,然后是音频的格式信息Wave_format。在RIFF chunk的后面是一个4字节非FOURCC:WAVE,表示该文件为WAV文件。另外,Wave_format的构造函数只需要三个参数:声道数、采样率和量化精度,关于音频的其他信息都可以使用这三个数值计算得到。注意,这里设置fmt chunk的size为18。

    实现

    有了上面结构体后,再对WAV文件进行读写就比较简单了。由于RIFF文件中使用FOURCC老标识chunk的类型,这里有两个FOURCC的实现方法:使用宏和使用模板,具体如下:

    #define FOURCC uint32_t 
    
    #define MAKE_FOURCC(a,b,c,d) \
    ( ((uint32_t)d) | ( ((uint32_t)c) << 8 ) | ( ((uint32_t)b) << 16 ) | ( ((uint32_t)a) << 24 ) )
    template <char ch0, char ch1, char ch2, char ch3> struct MakeFOURCC{ enum { value = (ch0 << 0) + (ch1 << 8) + (ch2 << 16) + (ch3 << 24) }; };
    

    Write WAVE file

    写WAV文件过程,首先是填充文件头信息,对于Wave_format只需要三个参数:声道数、采样率和量化精度,将文件头信息写入后,紧接这写入PCM数据就完成了WAV文件的写入。其过程如下:

    Wave_header header(1, 48000, 16);
    
        uint32_t length = header.fmt_data->sample_per_sec * 10 * header.fmt_data->bits_per_sample / 8;
        uint8_t *data = new uint8_t[length];
    
        memset(data, 0x80, length);
    
        CWaveFile::write("e:\\test1.wav", header, data, length);

    首先够着WAV文件头,然后写入文件即可。将数据写入的实现也比较简单,按照WAv的文件结构,依次将数据写入文件。在设置各个chunk的size值时要注意其不同的意义:

    • RIFF chunk 的size表示的是其数据的大小,其包含各个chunk的大小以及PCM数据的长度。该值 + 8 就是整个WAV文件的大小。
    • fmt chunk 的size是Wave_format的大小,这里为18
    • data chunk 的size 是写入的PCM数据的长度

    Read WAVE file

    知道了WAV的文件结构后,读取其数据就更为简单了。有一种直接的方法,按照PCM相对于文件起始的位置的偏移位置,直接读取PCM数据;或者是按照其文件结构依次读取信息,本文的将依次读取WAV文件的信息填充到相应的结构体中,其实现代码片段如下:

    header = make_unique<Wave_header>();
    
        // Read RIFF chunk
        FOURCC fourcc;
        ifs.read((char*)&fourcc, sizeof(FOURCC));
    
        if (fourcc != MakeFOURCC<'R', 'I', 'F', 'F'>::value) // 判断是不是RIFF
            return false;
        Base_chunk riff_chunk(fourcc);
        ifs.read((char*)&riff_chunk.cb_size, sizeof(uint32_t));
    
        header->riff = make_shared<Base_chunk>(riff_chunk);
    
        // Read WAVE FOURCC
        ifs.read((char*)&fourcc, sizeof(FOURCC));
        if (fourcc != MakeFOURCC<'W', 'A', 'V', 'E'>::value)
            return false;
        header->wave_fcc = fourcc;
        ...

     

    实例

    调用本文的实现,写入一个单声道,16位量化精度,采样率为48000Hz的10秒钟WAV文件,代码如下:

     Wave_header header(1, 48000, 16);
    
        uint32_t length = header.fmt_data->sample_per_sec * 10 * header.fmt_data->bits_per_sample / 8;
        uint8_t *data = new uint8_t[length];
    
        memset(data, 0x80, length);
    
        CWaveFile::write("e:\\test1.wav", header, data, length);

    这里将所有的sample按字节填充为0x80,以16进制打开该wav文件,结果如下:

    可以参照上图给出的WAV文件头信息,看看各个字节的意义。音频的格式信息在FOURCC fmt后面

    • 4字节 00000012 fmt数据的长度 18字节
    • 2字节 0001 数据的存储格式为PCM
    • 2字节 0001 声道个数
    • 4字节 0000BB80 采样率 48000Hz
    • 4字节 00017700 码率 96000bps
    • 2字节 0002 数据块大小
    • 2字节 0010 量化精度 16位
    • 2字节 0000 扩展块的大小
    • 4字节 FOURCC data
    • 4字节 数据长度 0x000EA600

    代码

    最后将本文的代码封装在了类CWaveFile中,使用简单。

    • 写WAV文件
    Wave_header header(1, 48000, 16);
    
        uint32_t length = header.fmt_data->sample_per_sec * 10 * header.fmt_data->bits_per_sample / 8;
        uint8_t *data = new uint8_t[length];
    
        memset(data, 0x80, length);
    
        CWaveFile::write("e:\\test1.wav", header, data, length);

     

    • 读取WAV文件
        CWaveFile wave;
        wave.read("e:\\test1.wav");
        wave.data // PCM数据
    展开全文
  • RIFF,资源交换文件标志。 04H 4byte 从下一个地址开始到文件尾的总字节数。高位字节在后面,这里就是001437ECH,换成十进制是1325036byte,算上这之前的8byte就正好1325044byte了。 08H
  • C++和C读取WAV文件头的疑惑

    千次阅读 2014-07-19 12:43:54
    很多时候我们要对音频进行处理,首先你要考虑的是读取音频信息。下面是百度百科得到wav文件头信息
  • C++ 切割wav文件句末静音段

    千次阅读 2018-07-27 15:04:24
     由于我需要句末没有静音的wav文件,开始时使用的方法是直接对wav进行指定字节数读写,虽然重新写入的wav文件播放至静音段时就停止播放,但是音频的总时长未发生改变。查阅资料得到wav文件的总时长t=文件字节总数/...
  • 使用标准C++库实现实现PCM格式的WAV文件读写。 class CWaveFile { public: CWaveFile(void); ~CWaveFile(void); // Write wav head bool static WriteHead(const string& filename, uint32_t length); // ...
  • C语言读取wav文件

    2021-05-13 11:01:55
    代码的思路是编写wave.h,根据wav文件结构定义struct。大佬的执行结果为 然而我在运行代码的时候遇到的问题: 可以看到fmt长度为18,然而还是按照16来处理,导致读取data的时候只读取到后两位。 第一次尝试...
  • 该程序用API实现了语音采集并实时写入wav文件,用wave函数实现
  • C++下的文件转换吧 WAV文件 进行转换为PCM 文件的
  • C++根据频率生成wav音频文件

    千次阅读 2017-02-07 18:21:47
    (ps:第一次写博客还不是很熟悉,诸如排版之类的问题还请大家见谅)一.WAV文件格式WAVE文件是非常简单的一种RIFF文件,它的格式类型为”WAVE”。RIFF块包含两个子块,这两个子块的ID分别是”fmt”和”data”,其中”...
  • libsndfile动态库在VS2015下的调用并读取wav文件到txt
  • C++在windows下播放wav音频文件

    千次阅读 2016-10-13 12:14:11
    C++在windows下播放wav音频文件
  • 基于VS2013,c++有关WAV文件读取和G.711编解码的源代码
  • C++读取音频文件mp3、flac的曲名、歌手、专辑等ID3v2标签 (libzplay) 音乐的标签信息,以前用ID3v1来储存,直接存放文件最后128字节里,每一个属性的空间是固定大小的。现在的ID3v2则把标签存放在文件开头,每一属性...
  • 同事提供了分析音频的python接口,我需要集成到C++服务中,以下是将wav文件传输给python并获取返回结果的一种方式 1.wav文件格式 WAV是符合RIFF标准的多媒体文件,其文件结构可以如下: WAV 文件结构 RIFF块 ...
  • vc中读取wav文件的时长和文件播放的几种方式 读取wav文件的时长: int GetTimeLength()  //获取声音文件数据的函数,pString参数指向要打开的声音文件;  {  HMMIO file;//定义HMMIO文件句柄;  file=...
  • WAV 文件读写

    千次阅读 2018-09-25 10:10:58
    1.WAV 写入  需要头函数 #include &lt;iostream&gt; #include &lt;fstream&gt; #include &lt;string.h&gt; #include&lt;math.h&gt; #include&lt;c...
  • MP3 wav音频文件数据读取

    热门讨论 2010-11-12 12:55:04
    包里有MP3 和wav文件的格式,程序通过其格式获取其播放音乐的数据
  • Python读取wav格式文件

    千次阅读 2019-04-09 17:42:12
    转:...我们经常需要处理wav格式的文件读取其中的声音信号和相关参数,来做一些事情。如果我们使用C++来做,那么需要对文件的底层存储格式有一个透彻的了解才行,而且考虑不周还有可能出B...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,515
精华内容 1,406
关键字:

c++读取wav文件

c++ 订阅