请教WAV文件16位数据段的存储格式及解析方法
16位WAV音频数据解析方案
核心原理
WAV文件中的16位音频数据是以小端字节序的有符号短整数存储的:
- 每个采样占2个连续字节,低字节在前、高字节在后
- 数值范围为
-32768到32767,对应音频振幅(0为静音,正负对应波形的上下摆动) - 单声道文件的采样连续排列;立体声则遵循左声道、右声道交替排列的规则(你的440Hz测试文件如果是单声道,直接按2字节一组解析即可)
代码修正与实现
你的现有代码完成了头文件验证,但在音频数据读取环节未按16位单元处理,同时存在部分逻辑错误,以下是修正后的完整代码:
## CHECK FILE VALIDITY ## # Import required libraries import sys import struct # 用标准库处理二进制数据更可靠 # Open the file fileName = sys.argv[1] with open(fileName, 'rb') as f: data = f.read() # Check RIFF header if data[:4] != b'RIFF': raise FileExistsError('Invalid RIFF header') # 验证PCM格式的WAV头(fmt块大小固定为16) if data[8:24] != b'WAVEfmt \x10\x00\x00\x00': raise FileExistsError('Invalid WAV format (only PCM 16-bit supported)') ## GET AND PRINT FILE INFO ## # Calculate total file size riff_chunk_size = struct.unpack('<I', data[4:8])[0] file_length = riff_chunk_size + 8 # RIFF大小不含自身8字节,需补全 print('\nFile Size:') if file_length < 1024 * 1024: print(f"{round(file_length / 1024, 1)}K") elif file_length < 1024 * 1024 * 1024: print(f"{round(file_length / (1024*1024), 2)}M") else: raise NotImplementedError('File too large, gigabyte size not implemented') # Get sample rate sampleRate = struct.unpack('<I', data[24:28])[0] print(f'\nSample Rate:\n{sampleRate}Hz') # Get bits per sample bitsPerSample = struct.unpack('<H', data[34:36])[0] print(f'\nBits per Sample:\n{bitsPerSample} Bits') if bitsPerSample != 16: raise ValueError('Unsupported or invalid Bits per Sample') # Find data chunk (跳过所有非data子块,兼容带额外块的WAV文件) data_start = 0 offset = 12 # 跳过RIFF、WAVE标识,从第一个子块开始遍历 while offset < len(data): chunk_id = data[offset:offset+4] chunk_size = struct.unpack('<I', data[offset+4:offset+8])[0] if chunk_id == b'data': data_start = offset + 8 data_length = chunk_size break offset += 8 + chunk_size # 移动到下一个子块 else: raise FileNotFoundError('No data chunk found in WAV file') print(f'\nData starts at offset {data_start}') print('\nParsing 16-bit audio data...') # 解析16位音频采样 audio_samples = [] # 按2字节一组读取,转换为小端有符号短整型 for i in range(0, data_length, 2): sample = struct.unpack('<h', data[data_start + i : data_start + i + 2])[0] audio_samples.append(sample) # 输出前10个采样验证(440Hz正弦波会呈现规律的正负交替数值) print('\nFirst 10 audio samples:') print(audio_samples[:10])
关键修改说明
- 用
struct库简化二进制处理:struct是Python处理二进制数据的标准工具,<h表示小端有符号短整型,<I表示小端无符号整型,比手动反转字节更高效可靠。 - 健壮查找data块:WAV文件可能包含额外子块(如LIST信息块),循环遍历子块查找
data标识的方式,比硬编码或逐个字节判断更兼容不同格式的WAV文件。 - 正确解析16位采样:每次读取2字节并转换为有符号短整数,得到的数值直接对应音频的振幅强度。
- 修正文件长度计算:RIFF块的大小字段不包含自身的8字节,因此总文件大小需要补加该部分长度。
内容的提问来源于stack exchange,提问作者Donovan Black
相关产品推荐
相关产品推荐

