使用python编辑wav文件

时间:2009-05-17 20:54:38

标签: python audio

在wav文件中的每个单词之间,我完全沉默(我使用Hex工作室检查,静音用0表示)。

如何切断非静音?

我正在使用python进行编程。

谢谢!

6 个答案:

答案 0 :(得分:15)

Python有一个wav module。您可以使用它打开一个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处观察到一定数量的帧。

答案 1 :(得分:5)

我一直在为我正在进行的项目做一些关于这个主题的研究,我遇到了提供解决方案的一些问题,即确定沉默的方法是不正确的。 A"更正确"实施将是:

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

在readframes(x)方法返回的字符串对象的第一个元素上使用Python中的内置ord()函数将无法正常工作。

另一个关键点是多通道音频是交错的,因此处理通道需要一些额外的逻辑。同样,上面的链接详细说明了这一点。

希望这有助于将来。

以下是该链接中的一些更重要的观点,以及我发现的有用的内容。

数据组织


所有数据都以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声道)波形。不是首先存储左通道的所有采样点,然后存储下一个右通道的所有采样点,而是&#34;混合&#34;两个频道&#39;样本点在一起。您将存储左通道的第一个采样点。接下来,您将存储右通道的第一个采样点。接下来,您将存储左通道的第二个采样点。接下来,您将存储右通道的第二个采样点,依此类推,在存储每个通道的下一个采样点之间交替。这就是交错数据的含义;你依次存储每个通道的下一个采样点,这样就可以了解&#34;播放&#34; (即,发送到DAC)同时连续存储。

答案 2 :(得分:2)

答案 3 :(得分:1)

我对此没有经验,但请查看标准库中的wave模块。这可能会做你想要的。否则你将不得不将文件作为字节流读取一个0字节的剪切序列(但你不能只删除所有0字节,因为这会使文件无效......)

答案 4 :(得分:1)

您可能想尝试使用命令行声音处理工具sox。它有许多模式,其中之一是silence

  

沉默:从声音文件的开头,中间或结尾删除静音。沉默低于指定的阈值。

它支持多种声音格式并且速度非常快,因此解析大文件应该不是问题。

  

要从文件中间删除静音,请指定为负数的below_periods。然后将此值视为正值,并且还用于指示效果应重新开始above_periods指定的处理,使其适合删除声音文件中间的静音期。

我没有为libsox找到任何python构建,但你可以使用它,因为你在python中使用所有命令行程序(或者你可以重写它 - 然后使用sox源作为指导)。

答案 5 :(得分:1)

在剪切之前,您需要提供最小连续零数的阈值。否则,您将从正常音频数据的中间删除完全有效的零。您可以遍历wave文件,复制任何非零值,并缓冲零值。当你缓冲零并最终遇到下一个非零时,如果缓冲区的样本数量少于阈值,则复制它们,否则丢弃它。

但Python并不是这类任务的好工具。 :(