2013-12-19 46 views
5

我试图从.wav文件读取数据。Python波形字节数据

import wave 
wr = wave.open("~/01 Road.wav", 'r') 
# sample width is 2 bytes 
# number of channels is 2 
wave_data = wr.readframes(1) 
print(wave_data) 

这给:

b'\x00\x00\x00\x00' 

这是歌曲的 “第一帧”。这4个字节显然对应于每帧(2通道* 2字节采样宽度)字节,但每个字节对应于什么?

特别是,我试图将它转换为单声道幅度信号。

回答

16

如果你想了解'框架'是什么,你将不得不阅读波形文件格式的标准。例如:https://web.archive.org/web/20140221054954/http://home.roadrunner.com/~jgglatt/tech/wave.htm

从该文档:

被意在“播放”的采样点即发送到数字到模拟转换器(DAC)同时被统称为采样帧 。在我们的立体声波形的例子中,每两个采样点构成另一个采样帧。下面为该立体示例进行说明。

sample  sample    sample 
frame 0  frame 1    frame N 
_____ _____ _____ _____   _____ _____ 
| ch1 | ch2 | ch1 | ch2 | . . . | ch1 | ch2 | 
|_____|_____|_____|_____|  |_____|_____| 
_____ 
|  | = one sample point 
|_____| 

要转换为单声道,你可以做这样的事情,

import wave 

def stereo_to_mono(hex1, hex2): 
    """average two hex string samples""" 
    return hex((ord(hex1) + ord(hex2))/2) 

wr = wave.open('piano2.wav','r') 

nchannels, sampwidth, framerate, nframes, comptype, compname = wr.getparams() 

ww = wave.open('piano_mono.wav','wb') 
ww.setparams((1,sampwidth,framerate,nframes,comptype,compname)) 

frames = wr.readframes(wr.getnframes()-1) 

new_frames = '' 

for (s1, s2) in zip(frames[0::2],frames[1::2]): 
    new_frames += stereo_to_mono(s1,s2)[2:].zfill(2).decode('hex') 

ww.writeframes(new_frames) 

没有明确的方式,从立体声转到单声道。你可以放下一个频道。以上,我正在平均渠道。这一切都取决于你的应用程序。

+0

谢谢,该链接是非常翔实的,有趣的阅读。 – jameh

+1

我可以得到一点点赞扬和/或接受的答案吗? –

2

作为对您的问题的直接回答:两个字节以“常用”方式生成一个16位整数值,由明确公式给出:value = ord(data[0]) + 256 * ord(data[1])。但使用struct模块是一种更好的方式来解码(以及后来的重新编码)等多字节的整数:

import struct 
print(struct.unpack("HH", b"\x00\x00\x00\x00")) 
# -> gives a 2-tuple of integers, here (0, 0) 

或者,如果我们想要一个签署 16位整数(我认为这是在.WAV的情况下文件),请使用"hh"而不是"HH"。 (我给你找出如何确切地说两个字节可以编码从-32768到32767的整数值的任务:-)

+0

在这种情况下,'struct'模块非常有用。比我的答案中的十六进制/解码/解码混乱要好得多。我不知道它存在。 –

+1

我相信这些字节是little-endian,它要求你使用'struct。解压缩(“ jameh

3

对于wav文件IO我宁愿使用scipy。读取wav文件可能有些过火,但通常在读取wav后,下游处理更容易。

import scipy.io.wavfile 
fs1, y1 = scipy.io.wavfile.read(filename) 

从这里数据y1将是N个样本长,并且将具有Z列,其中每列对应于一个通道。要转换为单声道wav文件,您不会说您希望如何进行转换。你可以拿平均数,或者其他任何你想要的。对于平均使用

monoChannel = y1.mean(axis=1)