读取*.wav音频文件

2024-06-01 07:38
文章标签 读取 音频文件 wav

本文主要是介绍读取*.wav音频文件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://blog.csdn.net/xiahouzuoxin/article/details/7875406


1、wav音频文件的格式

wav文件由文件头采样数据2部分组成。

文件头又分为RIFF(Resource Interchange File Format)、WAVE文件标识段 和 声音数据格式说明段组成。

各段的起始地址分别由RIFF标识符、WAVE标识符、以及波形格式标识符(FMT)标定。

(1)文件头格式

注意:下面的地址是连续的

 

(2)数据格式

 

虽然上图给出的数据标识符起始地址刚好是文件头的末地址+1,但并不代表总是这样。

因此,我们在读取数据时最好是找到数据标识符,该标识符的4个字节刚好是'd'、‘a’、‘t’、‘a’。

2、C语言读取wav文件

首先对一些类型使用了重定义

[cpp]  view plain copy print ?
  1. typedef unsigned char  uchar;  
  2. typedef unsigned char  uint8;  
  3. typedef unsigned short uint16;  
  4. typedef unsigned long  uint32;  
  5. typedef char           sint8;  
  6. typedef short          sint16;  
  7. typedef long           sint32;  
  8. typedef float          fp32;  
  9. typedef double         fp64;  
  10.   
  11. typedef enum BOOLEAN  
  12. {  
  13.     TRUE  = 1,  
  14.     FALSE = 0  
  15. } boolean;  


 

(1)wav结构体定义

[cpp]  view plain copy print ?
  1. //wave文件头  
  2. typedef struct WaveHeader  
  3. {  
  4.     uint8 riff[4];             //资源交换文件标志  
  5.     uint32 size;               //从下个地址开始到文件结尾的字节数  
  6.     uint8 wave_flag[4];        //wave文件标识  
  7.     uint8 fmt[4];              //波形格式标识  
  8.     uint32 fmt_len;            //过滤字节(一般为00000010H)  
  9.     uint16 tag;                //格式种类,值为1时,表示PCM线性编码  
  10.     uint16 channels;           //通道数,单声道为1,双声道为2  
  11.     uint32 samp_freq;          //采样频率  
  12.     uint32 byte_rate;          //数据传输率 (每秒字节=采样频率×每个样本字节数)  
  13.     uint16 block_align;        //块对齐字节数 = channles * bit_samp / 8  
  14.     uint16 bit_samp;           //bits per sample (又称量化位数)  
  15. } wave_header_t;  
  16.   
  17. typedef struct WaveStruct  
  18. {  
  19.     FILE *fp;                  //file pointer  
  20.     wave_header_t header;      //header  
  21.     uint8 data_flag[4];        //数据标识符  
  22.     uint32 length;             //采样数据总数  
  23.     uint32 *pData;             //data  
  24. } wave_t;  
  25. wave_t wave;  


 

(2)读取文件头信息

[cpp]  view plain copy print ?
  1. /* 
  2.  * open *.wav file 
  3.  */  
  4. void WaveOpen(char *file, int raw, int mono_stereo)  
  5. {  
  6.     uchar temp = 0;  
  7.     uint8 read_bytes = 0;  
  8.     char *channel_mappings[] = {NULL,"mono","stereo"};  
  9.     uint32 total_time = 0;  
  10.     struct PlayTime        //播放时间  
  11.     {  
  12.         uint8 hour;  
  13.         uint8 minute;  
  14.         uint8 second;  
  15.     } play_time;  
  16.   
  17.     if(NULL == (wave.fp=fopen(file, "rb")))                               /* open file */  
  18.     {  
  19.         printf("file %s open failure!\n", file);      
  20.     }  
  21.   
  22.     /* read heade information */  
  23.     if(4 != fread(wave.header.riff, sizeof(uint8), 4, wave.fp))           /* RIFF chunk */  
  24.     {  
  25.         printf("read riff error!\n");  
  26.         return;  
  27.     }  
  28.     if(1 != fread(&wave.header.size, sizeof(uint32), 1, wave.fp))         /* SIZE : from here to file end */  
  29.     {  
  30.         printf("read size error!\n");  
  31.         return;  
  32.     }  
  33.     if(4 != fread(wave.header.wave_flag, sizeof(uint8), 4, wave.fp))      /* wave file flag */  
  34.     {  
  35.         printf("read wave_flag error!\n");  
  36.         return;  
  37.     }  
  38.     if(4 != fread(wave.header.fmt, sizeof(uint8), 4, wave.fp))             /* fmt chunk */  
  39.     {  
  40.         printf("read fmt error!\n");  
  41.         return;  
  42.     }  
  43.     if(1 != fread(&wave.header.fmt_len, sizeof(uint32), 1, wave.fp))       /* fmt length */  
  44.     {  
  45.         printf("read fmt_len error!\n");  
  46.         return;  
  47.     }  
  48.     if(1 != fread(&wave.header.tag, sizeof(uint16), 1, wave.fp))           /* tag : PCM or not */  
  49.     {  
  50.         printf("read tag error!\n");  
  51.         return;  
  52.     }  
  53.     if(1 != fread(&wave.header.channels, sizeof(uint16), 1, wave.fp))      /* channels */  
  54.     {  
  55.         printf("read channels error!\n");  
  56.         return;  
  57.     }  
  58.     if(1 != fread(&wave.header.samp_freq, sizeof(uint32), 1, wave.fp))      /* samp_freq */  
  59.     {  
  60.         printf("read samp_freq error!\n");  
  61.         return;  
  62.     }  
  63.     if(1 != fread(&wave.header.byte_rate, sizeof(uint32), 1, wave.fp))      /* byte_rate : decode how many bytes per second */  
  64.     {                                                                       /* byte_rate = samp_freq * bit_samp */  
  65.         printf("read byte_rate error!\n");  
  66.         return;  
  67.     }  
  68.     if(1 != fread(&wave.header.block_align, sizeof(uint16), 1, wave.fp))       /* quantize bytes for per samp point */  
  69.     {  
  70.         printf("read byte_samp error!\n");  
  71.         return;  
  72.     }  
  73.     if(1 != fread(&wave.header.bit_samp, sizeof(uint16), 1, wave.fp))        /* quantize bits for per samp point */  
  74.     {                                                                        /* bit_samp = byte_samp * 8 */  
  75.         printf("read bit_samp error!\n");  
  76.         return;  
  77.     }  
  78.   
  79. <span style="color:#ff0000;">   </span><span style="color:#000000;">/* jump to "data" for reading data */  
  80.     do  
  81.     {  
  82.         fread(&temp, sizeof(uchar), 1, wave.fp);  
  83.     }  
  84.     while('d' != temp);  
  85.     wave.data_flag[0] = temp;  
  86.     if(3 != fread(&wave.data_flag[1], sizeof(uint8), 3, wave.fp))                 /* data chunk */  
  87.     {  
  88.         printf("read header data error!\n");  
  89.         return;  
  90.     }  
  91.     </span>if(1 != fread(&wave.length, sizeof(uint32), 1, wave.fp))                  /* data length */  
  92.     {  
  93.         printf("read length error!\n");  
  94.     }  
  95.   
  96.     /* jduge data chunk flag */  
  97.     if(!StrCmp(wave.data_flag, "data", 4))  
  98.     {  
  99.         printf("error : cannot read data!\n");  
  100.         return;  
  101.     }  
  102.   
  103.     total_time = wave.length / wave.header.byte_rate;  
  104.     play_time.hour = (uint8)(total_time / 3600);  
  105.     play_time.minute = (uint8)((total_time / 60) % 60);  
  106.     play_time.second = (uint8)(total_time % 60);  
  107.     /* printf file header information */  
  108.     printf("%s %ldHz %dbit, DataLen: %ld, Rate: %ld, Length: %2ld:%2ld:%2ld\n",  
  109.            channel_mappings[wave.header.channels],             //声道  
  110.            wave.header.samp_freq,                              //采样频率  
  111.            wave.header.bit_samp,                               //每个采样点的量化位数  
  112.            wave.length,  
  113.            wave.header.byte_rate,  
  114.            play_time.hour,play_time.minute,play_time.second);  
  115.   
  116.   
  117.     //fclose(wave.fp);                                               /* close wave file */  
  118. }  


按结构体一点点的读出文件头的信息,请注意

/* jump to "data" for reading data */

 的那一段,“先识别data标识符,再接着往下读取”。

 

(3)读数据

在读完数据长度之后就全是数据了,直接使用fread按uint32格式读取数据即可,我这里每次读取1152个数据(即一帧)。

[cpp]  view plain copy print ?
  1. /* 
  2.  * get wave data  
  3.  */  
  4. uint32* GetWave(void)  
  5. {  
  6.     static uint32 buffer[1152] = {0};     
  7.     uint16 n = 0;  
  8.     uint16 p = 0;  
  9.   
  10.     p = fread(buffer, sizeof(uint32), n, wave.fp);  
  11.     if(!p)  
  12.     {  
  13.         return 0;  
  14.     }  
  15.     else  
  16.     {  
  17.         for(; p<n; p++)  
  18.         {  
  19.             buffer[p] = 0;  
  20.         }  
  21.         return buffer;  
  22.     }  
  23. }  

上面程序中注意几点,

(1)不要定义大容量的局部变量,因为局部变量存放在堆栈中。如果一定要定义,要定义成static类型。

(2)不要返回局部变量的的地址,因为在堆栈中的地址值是不确定的。

上面的程序返回局部数组的指针,前提是 已经将数据存放在静态数据存储区。

但不管怎样,返回局部变量的地址总是不好的。


这篇关于读取*.wav音频文件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1020383

相关文章

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

matlab读取NC文件(含group)

matlab读取NC文件(含group): NC文件数据结构: 代码: % 打开 NetCDF 文件filename = 'your_file.nc'; % 替换为你的文件名% 使用 netcdf.open 函数打开文件ncid = netcdf.open(filename, 'NC_NOWRITE');% 查看文件中的组% 假设我们想读取名为 "group1" 的组groupName

argodb自定义函数读取hdfs文件的注意点,避免FileSystem已关闭异常

一、问题描述 一位同学反馈,他写的argo存过中调用了一个自定义函数,函数会加载hdfs上的一个文件,但有些节点会报FileSystem closed异常,同时有时任务会成功,有时会失败。 二、问题分析 argodb的计算引擎是基于spark的定制化引擎,对于自定义函数的调用跟hive on spark的是一致的。udf要通过反射生成实例,然后迭代调用evaluate。通过代码分析,udf在

下载/保存/读取 文件,并转成流输出

最近对文件的操作又熟悉了下;现在记载下来:学习在于 坚持!!!不以细小而不为。 实现的是:文件的下载、文件的保存到SD卡、文件的读取输出String 类型、最后是文件转换成流输出;一整套够用了; 重点: 1:   操作网络要记得开线程; 2:更新网络获取的数据 切记用Handler机制; 3:注意代码的可读性(这里面只是保存到SD卡,在项目中切记要对SD卡的有无做判断,然后再获取路径!)

ROS1 + Realsense d455 固件安装+读取rostopic数据

目录 安装固件(一定要匹配)ROS1 wrapper 安装方法Realsense SDK 安装方法Realsense Firmware 安装方法 修改roslaunch配置文件,打开双目图像和IMU数据其他坑点参考链接 安装固件(一定要匹配) 如果你是使用ROS1获取realsense数据的话,一定要注意,SDK, Firmware的版本不是越新越好!!,这是因为intel已经不

Python批量读取身份证信息录入系统和重命名

前言 大家好, 如果你对自动化处理身份证图片感兴趣,可以尝试以下操作:从身份证图片中快速提取信息,填入表格并提交到网页系统。如果你无法完成这个任务,我们将在“Python自动化办公2.0”课程中详细讲解实现整个过程。 实现过程概述: 模块与功能: re 模块:用于从 OCR 识别出的文本中提取所需的信息。 日期模块:计算年龄。 pandas:处理和操作表格数据。 PaddleOCR:百度的

java读取resource/通过文件名获取文件类型

java读取resource java读取resource目录下文件的方法: 借助Guava库的Resource类 Resources.getResource("test.txt") 通过文件名获取文件类型 mongodb java

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(4)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)-CSDN博客  这节就是真正的存储数据了   理清一下思路: 1.存储路径并检查 //2进制文件类存储private static string Data_Binary_Pa

Linux下读取默认MAC地址

一、适用范围 这里主要介绍读取网卡MAC地址的方法,适用于EasyARM-i.MX287A开发套件,其应用原理及配套示例也适用于下表1.1所列出的产品型号。 二、原理介绍 MAC(Media Access Control,介质访问控制)是用来定义网络设备的位置。用来表示互联网上每一个站点的标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构RA负责给

win7上R读取excel过程

win7上R读取excel过程 按照书上操作,出现 Error in odbcConnectExcel("c:/r-workspace/contacts.xls") :    odbcConnectExcel is only usable with 32-bit Windows 测试使用剪贴板(先将数据复制,则存在剪贴板了)的读取excel的方法,是可