在wav文件中,每个单词之间都有完整的静音(我用Hex Workshop检查过了,静音用0表示)。
我该如何剪切非静音声音?
我正在使用Python进行编程。
谢谢!
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帧。
ord(frame[j])
是什么?它是波的振幅吗? - Jaseem我正在为一个项目进行一些研究,涉及IT技术相关内容。然而,我发现了解决方案中存在一些问题,主要是判断静默的方法不正确。一个“更正确”的实现方式如下:
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
**我发现一篇很好的参考资料,它解释了针对不同大小位编码和多个通道处理wave文件的格式: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)的采样点被连续存储。
我对此没有经验,但可以看看标准库中的wave模块。那可能会做你想要的事情。否则,您将不得不将文件读取为字节流,并剪切出0字节序列(但您不能仅剪切所有0字节,因为那样会使文件无效...)
您可能想尝试使用sox,这是一个命令行音频处理工具。它有许多模式之一是silence
:
silence:从声音文件的开头、中间或结尾删除静音。静音是低于指定阈值的任何声音。
它支持多种音频格式,并且速度相当快,因此解析大型文件不应该是问题。
要从文件中间删除静音,请指定一个负的
below_periods
。然后将此值视为正值,并且还用于指示效果应按照above_periods
指定的方式重新启动处理,使其适用于删除声音文件中间的静音段落。
我没有找到任何libsox的Python构建,但是您可以像在Python中使用所有命令行程序一样使用它(或者您可以重写它-使用sox源代码作为指导)。
在剪切之前,您需要想出一些连续零的最小数量的阈值。否则,您将从正常音频数据的中间删除完全有效的零。您可以遍历波形文件,复制任何非零值,并缓冲零值。当您缓冲零并最终遇到下一个非零时,如果缓冲区的样本少于阈值,请将它们复制过去,否则请丢弃它。
然而,Python不是这种任务的好工具。 :(