瑞芯微-I2S|语音文件格式wav与pcm快速入门-4

原创 一口Linux 2024-05-20 11:50

点击左上方蓝色“一口Linux”,选择“设为星标

第一时间看干货文章 

【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式知识点-思维导图-免费获取
【就业】一个可以写到简历的基于Linux物联网综合项目
【就业】找工作简历模版



 1

一口君后面会陆续更新基于瑞芯微rk3568的I2S系列文章。

预计10篇左右。有对语音感兴趣的朋友,可以收藏该专题。

《瑞芯微 | I2S-音频基础 -1》

《瑞芯微-I2S | 音频驱动调试基本命令和工具-基于rk3568-2》

《瑞芯微-I2S | ALSA基础-3 》

调试I2S,最常用到的测试文件就是wav格式和pcm格式,本文主要讲解语音格式相关知识点。

本文还用到逻辑分析仪,使用方法如下:

《推荐最近在使用的还不错的一款逻辑分析仪》

本文用到的 音频文件+逻辑分析仪软件+i2s数据波形 后台回复:i2s

一、pcm

与pcm相关的几个参数:

1. PCM数据常用量化指标

  • 采样率(Sample rate):每秒钟采样多少次,以Hz为单位。采样率表示音频信号每秒的数字快照数。该速率决定了音频文件的频率范围。采样率越高,数字波形的形状越接近原始模拟波形。低采样率会限制可录制的频率范围,这可导致录音表现原始声音的效果不佳。

根据 奈奎斯特采样定理,为了重现给定频率,采样率必须至少是该频率的两倍。例如,CD 的采样率为每秒 44,100 个采样,因此可重现最高为 22,050 Hz 的频率,此频率刚好超过人类的听力极限 20,000 Hz。

  1. 位深度(Bit-depth):表示用多少个二进制位来描述采样数据,一般为16bit。位深度决定动态范围。采样声波时,为每个采样指定最接近原始声波振幅的振幅值。较高的位深度可提供更多可能的振幅值,产生更大的动态范围、更低的噪声基准和更高的保真度。

  2. 字节序:表示音频PCM数据存储的字节序是大端存储(big-endian)还是小端存储(little-endian),为了数据处理效率的高效,通常为小端存储。

  3. 声道数(channel number):当前PCM文件中包含的声道数,是单声道(mono)、双声道(stereo)?此外还有5.1声道等。

  4. 采样数据是否有符号(Sign):要表达的就是字面上的意思,需要注意的是,使用有符号的采样数据不能用无符号的方式播放。

以FFmpeg中常见的PCM数据格式s16le为例:

  • 它描述的是有符号16位小端PCM数据
s表示有符号,
16表示位深,
le表示小端存储。

2. PCM数据流

PCM (Pulse Code Modulation) 也被称为脉冲编码调制。PCM 音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样、量化、编码转换成的标准的数字音频数据。

PCM 音频数据的存储

如果是单声道的音频文件,采样数据按时间的先后顺序依次存入(有的时候也会采用 LRLRLR 方式存储,只是另一个声道的数据为 0),如果是双声道的话通常按照 LRLRLR 的方式存储,存储的时候还和机器的大小端有关。

小端模式如下图所示:

PCM 音频数据是未经压缩的数据,所以通常都比较大,常见的 MP3 格式都是经过压缩的,128Kbps 的 MP3 压缩率可以达到 1:11

PCM 音频数据的参数

一般我们描述 PCM 音频数据的参数的时候有如下描述方式:

  • 44100HZ 16bit stereo:
每秒钟有 44100 次采样, 
采样数据用 16 位(2 字节)记录, 
双声道(立体声)

44100Hz 指的是采样率,它的意思是每秒取样 44100 次。采样率越大,存储数字音频所占的空间就越大。

16bit 指的是采样精度,意思是原始模拟信号被采样后,每一个采样点在计算机中用 16 位(两个字节)来表示。采样精度越高越能精细地表示模拟信号的差异。

Stereo 指的是声道数,也即采样时用到的麦克风的数量,麦克风越多就越能还原真实的采样环境(当然麦克风的放置位置也是有规定的)。

其他格式例子:

  • 22050HZ 8bit  mono:
每秒钟有 22050 次采样, 采样数据用 8 位(1 字节)记录, 单声道
  • 48000HZ 32bit 51ch:
每秒钟有 48000 次采样, 采样数据用 32 位(4 字节浮点型)记录, 5.1 声道

二、WAV文件

WAV 是 Microsoft 和 IBM 为 PC 开发的一种声音文件格式,它符合 RIFF(Resource Interchange File Format)文件规范,用于保存 Windows 平台的音频信息资源,被 Windows 平台及其应用程序所广泛支持。

1. wav文件头

WAVE 文件通常只是一个具有单个 “WAVE” 块的 RIFF 文件,该块由两个子块(”fmt” 子数据块和 ”data” 子数据块),它的标准格式如下图所示:图片来源:

http://soundfile.sapp.org/doc/WaveFormat/

该格式的实质就是在 PCM 文件的前面加了一个文件头,各字段含义如下:

偏移与大小名称说明
0 4ChunkID包含 ASCII 形式的字母“RIFF”(0x52494646 大端形式)。
4 4ChunkSize36 + SubChunk2Size,或更准确地说:4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)这是此数字之后的块的其余部分的大小。这是整个文件的大小(以字节为单位)减去未包含在此计数中的两个字段的 8 字节:ChunkID 和 ChunkSize。
8 4格式包含字母“WAVE”(0x57415645 大端形式)。
12 4Subchunk1ID包含字母“fmt”(0x666d7420 大端格式)。
16 4Subchunk1Size16 用于 PCM。这是该数字之后的其余子块的大小。
20 2AudioFormatPCM = 1(即线性量化)1 以外的值表示某种形式的压缩。
22 2NumChannelsMono = 1、Stereo = 2 等
24 4SampleRate8000、44100 等
28 4ByteRate== SampleRate * NumChannels * BitsPerSample/8
32 2BlockAlign== NumChannels * BitsPerSample/8 1 的字节数样本包括所有通道。
34 2BitsPerSample8 位 = 8,16 位 = 16,等等
2ExtraParamSize如果是 PCM,则不存在
XExtraParams用于额外参数的空间
36 4Subchunk2ID包含字母“数据”(0x64617461 大端形式)。
40 4Subchunk2Size== NumSamples * NumChannels * BitsPerSample/8 这是数据中的字节数。您还可以将其视为该数字后面的子块的读取大小。
44 *Data实际的声音数据。

2. wav文件头结构体

wav文件头信息对应结构体:

typedef struct {
    char          ChunkID[4]; //内容为"RIFF"
    unsigned long ChunkSize;  //存储文件的字节数(不包含ChunkID和ChunkSize这8个字节)
    char          Format[4];  //内容为"WAVE“
} WAVE_HEADER;

typedef struct {
   char           Subchunk1ID[4]; //内容为"fmt"
   unsigned long  Subchunk1Size;  //存储该子块的字节数(不含前面的Subchunk1ID和Subchunk1Size这8个字节)
   unsigned short AudioFormat;    //存储音频文件的编码格式,例如若为PCM则其存储值为1。
   unsigned short NumChannels;    //声道数,单声道(Mono)值为1,双声道(Stereo)值为2,等等
   unsigned long  SampleRate;     //采样率,如8k,44.1k等
   unsigned long  ByteRate;       //每秒存储的bit数,其值 = SampleRate * NumChannels * BitsPerSample / 8
   unsigned short BlockAlign;     //块对齐大小,其值 = NumChannels * BitsPerSample / 8
   unsigned short BitsPerSample;  //每个采样点的bit数,一般为8,16,32等。
} WAVE_FMT;

typedef struct {
   char          Subchunk2ID[4]; //内容为“data”
   unsigned long Subchunk2Size;  //接下来的正式的数据部分的字节数,其值 = NumSamples * NumChannels * BitsPerSample / 8
} WAVE_DATA;

3. WAV 文件头解析实例

下面通过提供给大家的音频文件《xiaoniao.wav》来详细讲解wav文件格式,该音频文件格式为:S16_LE

peng@ubuntu:~/test$ ls -l xiaoniao.wav 
-rwxrw-rw- 1 peng peng 1764448 May 10 20:41 xiaoniao.wav

用ue打开该文件,自动显示为十六进制数字,

文件头信息解析如下图:

数据是小端,比如采样率4个字段是 44 AC 00 00实际数据是0x0000ac44,转换成10进制是44100

读者对照结构体,可以解析出改文件的所有信息。

三、i2s音频波形分析

wav文件格式我们搞清楚了,那么它和i2s是什么关系呢?

1. 嵌入式设备音频架构

一个典型的嵌入式设备的音频架构大致如下【以rk3568为例】,

当我们使用aplay工具播放wav文件时:

  1. 解析wav文件头,读取相应信息
  2. 然后通过i2s控制器驱动,将pcm音频流通过i2s接口发送给codec rk809,
  3. codec rk809会将pcm音频流进行DAC转换成对应的模拟信号,并通过耳机/喇叭播放出去。

2. 播放命令

播放命令:

root@ATK-DLRK356X:/sdcard# aplay -v xiaoniao.wav
Playing WAVE 'xiaoniao.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
ALSA <-> PulseAudio PCM I/O Plugin
Its setup is:
  stream       : PLAYBACK
  access       : RW_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 44100
  exact rate   : 44100 (44100/1)
  msbits       : 16
  buffer_size  : 22050
  period_size  : 5512
  period_time  : 125000
  tstamp_mode  : NONE
  tstamp_type  : GETTIMEOFDAY
  period_step  : 1
  avail_min    : 5512
  period_event : 0
  start_threshold  : 22050
  stop_threshold   : 22050
  silence_threshold: 0
  silence_size : 0
  boundary     : 6206523236469964800

3.波形分析

现在我在图中i2s控制器与codec之间位置用逻辑分析仪抓取了i2s数据波形,

【该操作需要飞线,建议找硬件工程师帮忙】

波形文件aplay_xiaoniao.kvdat

一口君实际测试的i2s控制器为24位小端格式。由上图可知:

  1. xiaomiao.wav文件为s16_le格式,所以i2s控制器依次每次读取data后面2个字节的数据
  2. 根据帧时钟,依次在左右声道时隙,将pcm数据放到数据线中。
  3. 因为控制器是24位,所以各channel会有24个bit的时钟周期;
  4. 根据i2s协议,默认有效数据靠左,并且空1个bit的位置;多出来的8个bit位置默认补充填0。

5. codec就会通过该波形提取对应的pcm数据,做出相应处理之后就可以播放出去了。

四、如何在各种音频格式之间进行转换

处于测试需要,我们还需要经常转换文件格式,可以通过FFmpeg工具

1. FFmpeg

对于其他格式的音频文件,一般用FFmpeg软件进行转换,先在当前的设备安装好FFmpeg软件,然后用命令行就可以进行转换了,常用的示范如下:

  • 将mp4视频提取wav格式:
ffmpeg -i D:\input.mp4 -vn -acodec pcm_s16le -ar 44100 -ac 2 D:\output.wav
  • 将wav格式转变为pcm格式:
ffmpeg -i D:\output.wav -f s16le -acodec pcm_s16le D:\output.pcm
  • 将pcm格式转变为wav格式:
ffmpeg -f s16le -ar 44100 -ac 2 -i D:\output.pcm c:\output.wav

注意上面的命令中指定的采样率为44.1k ,双声道,存储格式是s16le

2. 编写代码实现PCM → WAV 代码

下面是一个实现将pcm文件转换成wav文件的代码实例:

int simplest_pcm16le_to_waveconst char *pcmpath, int channels, int sample_rate, const char *wavepath )
// 省去错误判断
    short pcmData;
    FILE* fp = fopen( pcmpath, "rb" );
    FILE* fpout = fopen( wavepath, "wb+" );
    
    // 填充 WAVE_HEADER
    WAVE_HEADER pcmHEADER;
    memcpy( pcmHEADER.ChunkID, "RIFF"strlen"RIFF" ) );
    memcpy( pcmHEADER.Format, "WAVE"strlen"WAVE" ) );
    fseek( fpout, sizeof( WAVE_HEADER ), 1 );
    
    //填充 WAVE_FMT 
    WAVE_FMT pcmFMT;
    pcmFMT.SampleRate = sample_rate;
    pcmFMT.ByteRate = sample_rate * sizeof( pcmData );
    pcmFMT.BitsPerSample = 8 * sizeof( pcmData );
    memcpy( pcmFMT.Subchunk1ID, "fmt "strlen"fmt " ) );
    pcmFMT.Subchunk1Size = 16;
    pcmFMT.BlockAlign = channels * sizeof( pcmData );
    pcmFMT.NumChannels = channels;
    pcmFMT.AudioFormat = 1;
    fwrite( &pcmFMT, sizeof( WAVE_FMT ), 1, fpout );

    //填充 WAVE_DATA;
    WAVE_DATA pcmDATA;
    memcpy( pcmDATA.Subchunk2ID, "data"strlen"data" ) );
    pcmDATA.Subchunk2Size = 0;
    fseek( fpout, sizeof( WAVE_DATA ), SEEK_CUR );
    fread( &m_pcmData, sizeof( short ), 1, fp );
    while ( !feof( fp ) ) {
         pcmDATA.dwSize += 2;
         fwrite( &m_pcmData, sizeof( short ), 1, fpout );
         fread( &m_pcmData, sizeof( short ), 1, fp );
    }
    
    int headerSize = sizeof( pcmHEADER.Format ) + sizeof( WAVE_FMT ) + sizeof( WAVE_DATA ); // 36
    pcmHEADER.ChunkSize = headerSize + pcmDATA.Subchunk2Size;

    rewind( fpout );
    fwrite( &pcmHEADER, sizeof( WAVE_HEADER ), 1, fpout );
    fseek( fpout, sizeof( WAVE_FMT ), SEEK_CUR );
    fwrite( &pcmDATA, sizeof( WAVE_DATA ), 1, fpout );
    fclose( fp );
    fclose( fpout );
    return 0;
}

大家可以用我提供的sound.pcmxiaoniao.wav语音文件,测试一下。

end



一口Linux 


关注,回复【1024】海量Linux资料赠送


精彩文章合集

文章推荐

【专辑】ARM
【专辑】粉丝问答
【专辑】所有原创
专辑linux入门
专辑计算机网络
专辑Linux驱动
【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式所有知识点-思维导图


一口Linux 写点代码,写点人生!
评论
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 73浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 101浏览
  • 《高速PCB设计经验规则应用实践》+PCB绘制学习与验证读书首先看目录,我感兴趣的是这一节;作者在书中列举了一条经典规则,然后进行详细分析,通过公式推导图表列举说明了传统的这一规则是受到电容加工特点影响的,在使用了MLCC陶瓷电容后这一条规则已经不再实用了。图书还列举了高速PCB设计需要的专业工具和仿真软件,当然由于篇幅所限,只是介绍了一点点设计步骤;我最感兴趣的部分还是元件布局的经验规则,在这里列举如下:在这里,演示一下,我根据书本知识进行电机驱动的布局:这也算知行合一吧。对于布局书中有一句:
    wuyu2009 2024-11-30 20:30 125浏览
  • 戴上XR眼镜去“追龙”是种什么体验?2024年11月30日,由上海自然博物馆(上海科技馆分馆)与三湘印象联合出品、三湘印象旗下观印象艺术发展有限公司(下简称“观印象”)承制的《又见恐龙》XR嘉年华在上海自然博物馆重磅开幕。该体验项目将于12月1日正式对公众开放,持续至2025年3月30日。双向奔赴,恐龙IP撞上元宇宙不久前,上海市经济和信息化委员会等部门联合印发了《上海市超高清视听产业发展行动方案》,特别提到“支持博物馆、主题乐园等场所推动超高清视听技术应用,丰富线下文旅消费体验”。作为上海自然
    电子与消费 2024-11-30 22:03 98浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 111浏览
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 87浏览
  • TOF多区传感器: ND06   ND06是一款微型多区高集成度ToF测距传感器,其支持24个区域(6 x 4)同步测距,测距范围远达5m,具有测距范围广、精度高、测距稳定等特点。适用于投影仪的无感自动对焦和梯形校正、AIoT、手势识别、智能面板和智能灯具等多种场景。                 如果用ND06进行手势识别,只需要经过三个步骤: 第一步&
    esad0 2024-12-04 11:20 58浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 102浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 111浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 119浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 68浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 120浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦