使用Python编辑WAV文件
在我的wav文件中,每个单词之间都有完全的静音(我用Hex workshop检查过,静音是用0来表示的)。
我该怎么剪掉那些不是静音的声音呢?
我正在用python编程。
谢谢!
6 个回答
我最近在研究一个项目,发现了提供的解决方案中有几个问题,特别是判断静音的方法不太对。一个“更正确”的实现方法是:
import struct
import wave
wave_file = wave.open("sound_file.wav", "r")
for i in range(wave_file.getnframes()):
# read a single frame and advance to next frame
current_frame = wave_file.readframes(1)
# check for silence
silent = True
# wave frame samples are stored in little endian**
# this example works for a single channel 16-bit per sample encoding
unpacked_signed_value = struct.unpack("<h", current_frame) # *
if abs(unpacked_signed_value[0]) > 500:
silent = False
if silent:
print "Frame %s is silent." % wave_file.tell()
else
print "Frame %s is not silent." % wave_file.tell()
参考资料和有用链接
*Struct Unpacking
在这里会很有用: https://docs.python.org/2/library/struct.html
**我找到的一个很好的参考资料,讲解了处理不同大小位编码和多个通道的波形文件格式是: http://www.piclist.com/techref/io/serial/midi/wave.html
在Python中,使用内置的ord()函数对readframes(x)方法返回的字符串对象的第一个元素进行操作是行不通的。
另一个关键点是,多通道音频是交错存储的,因此在处理通道时需要一些额外的逻辑。再次强调,上面的链接对此进行了详细说明。
希望这能对将来某些人有所帮助。
以下是链接中一些更重要的要点,以及我觉得有用的内容。
数据组织
所有数据都以8位字节的形式存储,采用Intel 80x86(即小端)格式。多个字节值的字节是先存储低位字节(即最不重要的字节)。数据位的排列如下(即,上面显示的是位编号):
7 6 5 4 3 2 1 0
+-----------------------+
char: | lsb msb |
+-----------------------+
7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8
+-----------------------+-----------------------+
short: | lsb byte 0 | byte 1 msb |
+-----------------------+-----------------------+
7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
+-----------------------+-----------------------+-----------------------+-----------------------+
long: | lsb byte 0 | byte 1 | byte 2 | byte 3 msb |
+-----------------------+-----------------------+-----------------------+-----------------------+
交错存储
对于多通道声音(例如,立体声波形),每个通道的单个采样点是交错存储的。举个例子,假设有一个立体声(即2个通道)波形。我们不会先存储所有左声道的采样点,然后再存储所有右声道的采样点,而是将两个通道的采样点“混合”在一起。我们会先存储左声道的第一个采样点。接着,存储右声道的第一个采样点。然后,存储左声道的第二个采样点。接下来,存储右声道的第二个采样点,依此类推,交替存储每个通道的下一个采样点。这就是交错数据的意思;你依次存储每个通道的下一个采样点,以便那些需要“同时播放”(即发送到DAC)的采样点是连续存储的。
Python有一个叫做wav模块。你可以用它来打开一个wav文件进行读取,并使用`getframes(1)`命令逐帧查看文件。
import wave
w = wave.open('beeps.wav', 'r')
for i in range():
frame = w.readframes(1)
返回的帧会是一个包含十六进制值的字节字符串。如果文件是立体声,结果大概是这样的(4个字节):
'\xe2\xff\xe2\xff'
如果是单声道,它的数据会少一半(2个字节):
'\xe2\xff'
每个声道的长度是2个字节,因为音频是16位的。如果是8位的,每个声道只有一个字节。你可以用getsampwidth()
方法来确定这一点。同时,getchannels()
可以告诉你是单声道还是立体声。
你可以遍历这些字节,看看它们是否都等于零,这意味着两个声道都是静音。在下面的例子中,我使用ord()
函数将'\xe2'
的十六进制值转换为整数。
import wave
w = wave.open('beeps.wav', 'r')
for i in range(w.getnframes()):
### read 1 frame and the position will updated ###
frame = w.readframes(1)
all_zero = True
for j in range(len(frame)):
# check if amplitude is greater than 0
if ord(frame[j]) > 0:
all_zero = False
break
if all_zero:
# perform your cut here
print 'silence found at frame %s' % w.tell()
print 'silence found at second %s' % (w.tell()/w..getframerate())
值得注意的是,单个静音帧并不一定表示空白区域,因为音频的幅度可能会穿过0这个标记,正常的频率也会出现。因此,建议观察一定数量的0帧后,再决定这个区域是否真的静音。