1. 音频文件读取与基础信息提取

任务目标

读取一个WAV音频文件,提取采样率、位深、通道数、采样点数与时长等基础信息,并绘制波形图以直观验证读取结果。本案例使用Python标准库wave与struct完成WAV解析,不依赖第三方音频库,确保最小可复现。

环境依赖

  • Python 3.8+(仅标准库)
  • matplotlib(用于波形绘制,需单独安装:pip install matplotlib)

完整实现代码

import wave
import struct
import matplotlib.pyplot as plt

def read_wav_info(filepath):
    """读取WAV文件并返回基本信息与音频数据"""
    with wave.open(filepath, 'rb') as wf:
        channels = wf.getnchannels()
        sampwidth = wf.getsampwidth()  # 字节数
        framerate = wf.getframerate()
        nframes = wf.getnframes()
        comptype = wf.getcomptype()
        
        # 读取全部帧数据(bytes)
        raw_data = wf.readframes(nframes)
    
    # 位深 = 采样宽度(字节) * 8
    bit_depth = sampwidth * 8
    duration = nframes / framerate
    
    # 解析PCM数据为整数列表(仅支持16位PCM,WAV最常见格式)
    if sampwidth == 2:
        fmt = f'<{nframes * channels}h'  # 小端16位有符号
        samples = struct.unpack(fmt, raw_data)
    else:
        raise ValueError(f"当前仅支持16位PCM,实际位深为{bit_depth}bit")
    
    # 按通道分离
    channel_data = []
    for ch in range(channels):
        channel_data.append(list(samples[ch::channels]))
    
    info = {
        'channels': channels,
        'sampwidth_bytes': sampwidth,
        'bit_depth': bit_depth,
        'framerate': framerate,
        'nframes': nframes,
        'duration_sec': round(duration, 3),
        'compression': comptype
    }
    return info, channel_data

def plot_waveform(channel_data, framerate, title="Waveform"):
    """绘制波形图(最多显示前2个通道)"""
    n_channels = len(channel_data)
    fig, axes = plt.subplots(n_channels, 1, figsize=(10, 3*n_channels), squeeze=False)
    
    for ch in range(n_channels):
        data = channel_data[ch]
        time_axis = [i / framerate for i in range(len(data))]
        axes[ch][0].plot(time_axis, data, linewidth=0.3)
        axes[ch][0].set_xlabel("Time (s)")
        axes[ch][0].set_ylabel(f"Amplitude (ch{ch+1})")
        axes[ch][0].set_title(f"{title} - Channel {ch+1}")
        axes[ch][0].grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

if __name__ == "__main__":
    # 使用正弦波生成测试WAV文件(16位单声道,44.1kHz,1秒)
    import math
    test_file = "test_tone.wav"
    sample_rate = 44100
    freq = 440.0
    amplitude = 0.6
    n_samples = sample_rate  # 1秒
    
    with wave.open(test_file, 'w') as wf:
        wf.setnchannels(1)
        wf.setsampwidth(2)
        wf.setframerate(sample_rate)
        for i in range(n_samples):
            value = int(amplitude * 32767 * math.sin(2 * math.pi * freq * i / sample_rate))
            wf.writeframes(struct.pack('<h', value))
    
    # 读取并显示信息
    info, ch_data = read_wav_info(test_file)
    print("=== WAV 文件基本信息 ===")
    for key, val in info.items():
        print(f"{key}: {val}")
    
    # 绘制波形
    plot_waveform(ch_data, info['framerate'], title=test_file)

运行与验证

  1. 将上述代码保存为wav_reader.py,在终端执行:python wav_reader.py
  2. 程序会先自动生成一个440Hz、1秒、16位单声道的测试文件test_tone.wav,然后读取并打印其信息。
  3. 预期输出(与代码逻辑严格一致):
    channels: 1
    sampwidth_bytes: 2
    bit_depth: 16
    framerate: 44100
    nframes: 44100
    duration_sec: 1.0
    compression: NONE
  4. 波形验证:应弹出matplotlib窗口,显示一条频率为440Hz的正弦波曲线,横轴时间范围约0~1秒,纵轴幅度在-0.6~0.6之间(归一化后)。若波形正确显示且信息与预期一致,则案例验证通过。

关键说明

  • 代码仅支持16位PCM WAV(最常见格式)。若需处理其他位深,需扩展struct解包格式。
  • 波形绘制使用matplotlib,若需在无图形界面环境运行,可将plt.show()替换为plt.savefig('waveform.png')保存图片。
  • 读取大文件时readframes(nframes)会一次性载入全部数据,本案例适用于教学演示的小文件;处理大文件时应分块读取。