因此,我已经通过 此 网站的研究编写了验证并读取 wav 标头的代码。但我想知道,data段中的数据是如何存储的?它们位于 16 位部分中,彼此相邻放置。我认为在 Audacity 中制作 440hz 正弦波,然后导出它,会显示一些结果,并且字节确实看起来更整齐,但仍然像废话一样接缝。相信我,我已经在互联网上到处查找了,但是如果您知道,或者认为您可以找到答案,那么请务必这样做。如果您想尝试一下,这是我的代码。
## CHECK FILE VALIDIDITY ##
# Import required libarays
import sys
from numpy import take
# Make a function to read the byte data from the file
def postobytes(data, pos):
return bytes(take(data, pos).tolist())
# Open the file
fileName = sys.argv[1]
data = list(open(fileName, 'rb').read())
# Define the checking variables
headerCorrect1 = b'RIFF'
headerCorrect2 = b'WAVEfmt \0\0\0\0\0'
range1 = [0,1,2,3]
range2 = [8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]
# Check the header data
if postobytes(data, range1) == headerCorrect1 and postobytes(data, range2) == headerCorrect2:
print('Valid RIFF header')
else:
raise FileExistsError('Invalid RIFF header')
## GET AND PRINT FILE LENGTH ##
# Make a function to convert big endian to little endian
def bigtolittle(data):
return data[::-1]
def intfrompos(data, pos):
return int.from_bytes(bigtolittle(postobytes(data, pos)))
# Get the length of the file
lengthRange = [4,5,6,7]
length = intfrompos(data, lengthRange)
# Make human readable length
print('\nFile Size:')
if length/1000 < 1000:
print(str(round(length/100)/10)+'K')
elif length/1000000 < 1000000:
print(str(round(length/10000)/100)+'M')
else:
raise NotImplementedError('File to big, gigabyte and on not implemented')
## GET DATA AND FIND DATA START ##
# Get sample rate
srRange = [24,25,26,27]
sampleRate = intfrompos(data, srRange)
print('\nSample Rate:\n'+str(sampleRate)+'Hz')
# Get bits per sample
bpsRange = [34,35]
bitsPerSample = intfrompos(data, bpsRange)
print('\nBits per Sample:\n'+str(bitsPerSample)+' Bits')
if bitsPerSample != 16:
raise ValueError('Unsupported or invalid Bits per Sample')
# Find data starter
for pos, byte in enumerate(data):
if byte == 100:
if data[pos+1] == 97:
if data[pos+2] == 116:
if data[pos+3] == 97:
print('\nData Header at '+str(pos))
dhsp = pos # Data header start position
break
print('\nPlaying WAV file')
audio = []
dlRange = [dhsp+4,dhsp+5,dhsp+6,dhsp+7]
dl = intfrompos(data, lengthRange)
for pt, unused in enumerate(data):
pos = dhsp+pt+8
if pos > dl+6:
break
byte = data[pos]
audio.append(byte)
# FOR STACK OVERFLOW HELPERS: The audio list is all you need to mess with. Below is where you can do that.
我本来希望找到答案,但找不到。
当然可以!正在解码 WAV 文件格式的正确道路上。已经成功解析了标题,现在让我们解决数据部分是如何编码的:
WAV 文件中的音频数据表示
WAV 文件通常存储使用 脉冲编码调制 (PCM) 格式的音频数据。PCM 本质上是声波的数字表示。以下是它的工作原理:
- 采样: 采用模拟声波,并以规则的间隔对其幅度进行测量(采样)。每秒的采样数就是 采样率 (已经在代码中解析过)。
- 量化: 每个样本(幅度测量)都四舍五入到最接近的预定义离散值。这些值的数量由 位深度 (或每个样本的位数)确定,已正确识别为 16 位。
- 编码: 量化的样本表示为二进制值序列。对于 16 位音频,每个样本使用 16 位(2 个字节),这导致 65,536 个可能的幅度级别。
解释的 WAV 数据
由于已经确认的 WAV 文件使用 16 位 PCM,因此以下是解释数据部分中的字节的方法:
- 字节对: 数据中的每个两个连续字节表示一个音频样本。
- 字节顺序: WAV 文件通常使用 小端 字节顺序。这意味着第一个字节表示样本的最低有效字节,第二个字节表示最高有效字节。
- 有符号整数: 每个 16 位样本表示为有符号整数。要将其转换为更易于理解的格式,需要使用的编程语言将原始字节数据转换为有符号整数。
在 Python 中将原始字节转换为音频
的 Python 代码片段中缺少的部分是如何将原始字节数据转换为实际音频值。以下是如何使用
struct
模块来实现:
import struct
# ...(现有的代码来解析标题)...
audio = []
for i in range(dhsp + 8, len(data), 2): # 从数据块开始,每次迭代 2 个字节
sample_bytes = bytes(data[i:i+2]) # 获取 2 个字节的样本
sample_int, = struct.unpack('<h', sample_bytes) # 将其解压缩为有符号短整数(小端)
audio.append(sample_int)
# 现在,`audio` 列表包含代表音频波形的整数样本
可视化和分析
要更好地理解数据,可以使用以下方法对其进行可视化或进一步分析:
-
Matplotlib:
使用 Matplotlib 库绘制
audio
列表以查看音频波形。 - NumPy: 使用 NumPy 库对音频数据执行高级操作,例如计算 FFT 以进行频率分析。
其他注意事项
- 通道: 如果的 WAV 文件有多个通道(立体声有 2 个通道),则样本将交错。这意味着左声道的一个样本后跟右声道的一个样本,依此类推。
- 规范化: 音频样本通常在 -1 到 +1 的范围内进行规范化,以便于播放和处理。可能需要对解压缩的整数样本进行缩放以适应此范围。
请告诉我这是否有助于阐明 WAV 文件中音频数据的存储方式!
标签:python,audio,wav From: 78809000