• 音频存储格式wav介绍与解析


    音频格式

    音频格式中 规定了使用多少 bits 来对信号进行编码。

    • 无压缩的格式
    • 无损压缩
    • 有损压缩

    1. wav 音频格式介绍

    微软 和 IBM 于 1991 年 提出的资源交换的文件格式 RIFF( resource interchange File Format);

    wav 是 属于RIFF 中的一个应用实例;

    1.1 RIFF 的组成

    RIFF的其他实例还包含了其他的音视频格式 AVI, 图像动画ANI;
    RIFF 文件由一个表头 header, 多个区块 chunk 组成;

    1.2 wav 的组成

    打开该网址:

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

    在这里插入图片描述

    wav 的 Header : 使用 32 位正整数表示整个文件的大小, 故wav 大小不超过 4 GB;

    第一个区块,格式子块,Format chunk: 记录了音频的相关格式信息包括如下:
    编码格式, 通道数,采样率,Byte Rate 传输速率(字节每秒), 块对齐,

    第二个区块,数据子块,data chunk :开始存储音频的数据,

    注意到在数据块中,左通道和右通道的数据有依次间隔存放的,按照 
    左通道1,右通道1,左通道2, 右通道2 这样的顺序依次交替存放;

    在这里插入图片描述

    2. python 读取 wav 文件,

    调用 struct module,

    https://docs.python.org/3/library/struct.html?highlight=struct#struct.unpack_from

    注意,使用 struct.unpack(),

    其中,关键点:

    1. 字节顺序 byte order : 区分高位在前还是低位在前;

    < 表示, 低位在前;
    >表示,高位在前;

    1. 数据类型:
    H unsigned short  integer 2  
    
    • 1

    H 表示无符号的短整形, integer,  占2 个字节;

    I unsigned int integer 4
    
    • 1

    I: 表示无符号的整形, integer占4 个字节;

    2.1 struct.unpack() 的使用

    注意到根据字节序来判断使用的场景,

    byteorder 是big:  即高位在前时, 使用 f.read()直接打开;

    byteorder 是little:  即低位在前时, 使用 struct.unpack() 函数打开;

    import struct
    
    f = open("./male_audio.wav",  mode = "rb") # 以二进制的只读模式打开该文件;
    
    
    chunk_id = f.read(4)  #  文件的前4byte 字节代表 RIFF;
    print("the chunk id:", chunk_id)
    
    
    # < 代表 低位在前,  I:代表无符号的整数, 4byte;
    chunk_size = struct.unpack(', f.read(4))[0]
    print("the chunk size :", chunk_size)
    
    
    wav_format = f.read(4)
    print("the wav format", wav_format)
    
    sub_chunck_1_id = f.read(4)
    print("the first sub chunk id:", sub_chunck_1_id)
    
    sub_chunck_1_size = struct.unpack(', f.read(4))[0]
    print("the sub chunk 1 size: ", sub_chunck_1_size)
    
    # < 代表 低位在前,  H:代表无符号的短整数, 2个字节;
    audio_format = struct.unpack(', f.read(2))[0]
    print("the audio format", audio_format)
    #  PCM = 1 (i.e. Linear quantization)
    #  Values other than 1 indicate some form of compression.
    
    # Mono = 1, Stereo = 2, etc.
    num_channel = struct.unpack(', f.read(2))[0]
    print(" the num  channel of audio:", num_channel)
    
    
    # sampel rate 8000, 44100, etc.
    sample_rate = struct.unpack(', f.read(4))[0]
    print("the sample rate: ", sample_rate)
    
    #ByteRate == SampleRate * NumChannels * BitsPerSample / 8
    byte_rate = struct.unpack(', f.read(4))[0]
    print("the byte rate: ", byte_rate)
    
    
    # BlockAlign  == NumChannels * BitsPerSample/8
    # The number of bytes for one sample including
    #  all channels. I wonder what happens when
    #  this number isn't an integer?
    block_align = struct.unpack(', f.read(2))[0]
    print(" the block align:", block_align)
    
    
    # BitsPerSample    8 bits = 8, 16 bits = 16, etc.
    bits_per_sample =  struct.unpack(', f.read(2))[0]
    print("the bits per sample:", bits_per_sample)
    
    
    
    # ---- the following   data  sub chunk---
    
    sub_chunck_2_id = f.read(4)
    print("\n the sub chunk 2:", sub_chunck_2_id)
    
    
    sub_chunck_2_size = struct.unpack(', f.read(4))[0]
    print("the sub chunk_2_size:", sub_chunck_2_size)
    
    data0  = struct.unpack(', f.read(2))[0]
    print("the first data:", data0)
    
    # 这里需要注意, 第一个前4 个字节中, 前两个
    字节代表左声道, 后两字节代表右声道;
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    2.2 f.read() 函数的使用:

    # ”读“的细节操作
    # 1. # f.read(字节数):读取的是字节
    # 字节数默认是文件长度;下标会自动后移
    # f = open('test.txt','r')
    # print(f.read())
    # f.close()
     
    # 2.f.readline([limit])
    # 读取一行数据
    # limit
    # 限制的最大字节数
    # f = open('test.txt', 'r')
    #
    # content = f.readline()#只读取一行
    # print(content)
    #
    # content = f.readline()#只读取一行
    # print(content)
    # f.close()
     
    # 3.f.readlines()
    # 会自动的将文件按照换行符进行处理
    # 将处理好的每一行组成一个列表返回
    f = open('test.txt', 'r')
    cn = f.readlines()
    for line in cn:
        print(line, end='')
    f.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3. 其他存储格式

    RIFF: 由微软和IBM提出;
    AIFF : 苹果公司提出;

    • 无损格式: FLAC
       free lossless audio codec;

    • lossy : 有损格式

    MP3, mostly for music, based on:
    • Modified discrete cosine transform (MDCT)
    • Sub-band coding
    • Advanced Audio Coding (AAC)
    • OPUS
    • Speex
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    WPF 值转换
    卷积神经网络简介
    Jenkins:持续集成与持续部署的利器
    HLS直播协议详解
    MutationObserver对象
    Java数字处理类--Math类--大数字运算
    设计模式-组合模式(决策树)
    springboot+jsp 农产品电子商城网站maven idea
    6242. 二叉搜索树最近节点查询
    详解设计模式:策略模式
  • 原文地址:https://blog.csdn.net/chumingqian/article/details/126401499