【问题标题】:remove silence at the beginning and at the end of wave files with PyDub使用 PyDub 删除波形文件开头和结尾的静音
【发布时间】:2015-04-09 19:25:46
【问题描述】:

如何使用 PyDub 从波形文件的开头和结尾删除静音?

我想我应该逐段访问并检查它是否静音(但我无法做到):/

例如我有一个在开头、结尾或两者都有静音的波形文件(如下所示),我想删除文件开头和结尾的静音:

例如我要导入它

sound = AudioSegment.from_wav(inputfile)

循环每个声音样本以检查它是否无声并标记自波浪开始以来的最后一个无声样本(marker1), 然后到达波形结束前的最后一个样本(marker2),我可以从两个标记中导出新的声音文件

newsound = sound[marker1:marker2]

newsound.export(outputfile, format="wav")

【问题讨论】:

    标签: python wave pydub


    【解决方案1】:

    我建议您以至少 10 毫秒的周期循环,以便更快地完成(更少的迭代),并且因为单个样本并没有真正的“响度”。

    声音是振动,所以至少需要 2 个样本来检测是否真的有声音,(但这只会告诉你高频)。

    无论如何......这样的事情可以工作:

    from pydub import AudioSegment
    
    def detect_leading_silence(sound, silence_threshold=-50.0, chunk_size=10):
        '''
        sound is a pydub.AudioSegment
        silence_threshold in dB
        chunk_size in ms
    
        iterate over chunks until you find the first one with sound
        '''
        trim_ms = 0 # ms
    
        assert chunk_size > 0 # to avoid infinite loop
        while sound[trim_ms:trim_ms+chunk_size].dBFS < silence_threshold and trim_ms < len(sound):
            trim_ms += chunk_size
    
        return trim_ms
    
    sound = AudioSegment.from_file("/path/to/file.wav", format="wav")
    
    start_trim = detect_leading_silence(sound)
    end_trim = detect_leading_silence(sound.reverse())
    
    duration = len(sound)    
    trimmed_sound = sound[start_trim:duration-end_trim]
    

    【讨论】:

    • 这正是我想要的,谢谢!我不知道属性 .dBFS 包含每个声音块的 db,以及您可以通过这种方式迭代声音......它还强制实现阈值和块的大小(究竟是什么我在想)。
    • 为了为这个功能做出贡献,我将添加一个小技巧:1) 在声音离开 0 db 的位置精确剪切声音(这样你就不会错过任何毫秒声音的开始/偏移)通过丢弃阈值 2)一个参数,如果需要,可以在声音的开头或结尾添加给定数量的静音
    • @DaniPaniz 似乎您可以在修剪步骤中应用静音缓冲区,例如 sound[start_trim - buffer : duration - end_trim + buffer]
    • 在这里完成,非常感谢Jiaaro,您的帮助将在我的作品中被引用:) for f in files: if f[-4:] == '.wav': fp = path_files + f end_trim = detect_leading_silence(sound.reverse()) duration = len(sound) trimmed_sound = sound[:duration-end_trim+10] trimmed_sound.export(fp, format="wav")
    • Jiaaro,感谢您的代码。我注意到当输入文件全是噪声时,循环是无限的。因此,添加了一些条件来避免它。
    【解决方案2】:

    你可以用这个代码:

    from pydub.silence import detect_nonsilent
    
    def remove_sil(path_in, path_out, format="wav"):
        sound = AudioSegment.from_file(path_in, format=format)
        non_sil_times = detect_nonsilent(sound, min_silence_len=50, silence_thresh=sound.dBFS * 1.5)
        if len(non_sil_times) > 0:
            non_sil_times_concat = [non_sil_times[0]]
            if len(non_sil_times) > 1:
                for t in non_sil_times[1:]:
                    if t[0] - non_sil_times_concat[-1][-1] < 200:
                        non_sil_times_concat[-1][-1] = t[1]
                    else:
                        non_sil_times_concat.append(t)
            non_sil_times = [t for t in non_sil_times_concat if t[1] - t[0] > 350]
            sound[non_sil_times[0][0]: non_sil_times[-1][1]].export(path_out, format='wav')
    

    【讨论】:

      【解决方案3】:

      pydub 可能自首次提出此问题以来已更新,但这是我用来修剪尾随和前导沉默的代码:

      from pydub import AudioSegment
      from pydub.silence import detect_leading_silence
      
      trim_leading_silence: AudioSegment = lambda x: x[detect_leading_silence(x) :]
      trim_trailing_silence: AudioSegment = lambda x: trim_leading_silence(x.reverse()).reverse()
      strip_silence: AudioSegment = lambda x: trim_trailing_silence(trim_leading_silence(x))
      
      sound = AudioSegment.from_file(file_path_here)
      stripped = strip_silence(sound)
      

      detect_leading_silence 来自pydub.silence 为您提供索引,您可以使用这些索引对加载的AudioSegment 进行切片。基本上,您可以反转AudioSegment,修剪它,然后再次反转它以修剪尾随的静音。去除两端的静默就等于修剪前导和尾随的静默。

      请注意,如果加载的 AudioSegment 处于静默状态或在修剪操作后变为静默状态,strip_silence 应引发 IndexError

      我上次查看时,默认块大小为 10 毫秒,默认静音阈值为 -50 dBFS。

      pydub 的版本是 0.25.1,ffmpeg 的版本是 4.3.1。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-22
        相关资源
        最近更新 更多