使用 wave 模块在 2GB WAV 文件中搜索 dropouts

search a 2GB WAV file for dropouts using wave module

`使用 wave 模块分析 2GB WAV 文件(1khz 音调)音频丢失的最佳方法是什么?我尝试了下面的脚本

import wave
file1 = wave.open("testdropout.wav", "r")
file2 = open("silence.log", "w")
for i in xrange(file1.getnframes()):
  frame = file1.readframes(i)

  zero = True

  for j in xrange(len(frame)):
      # check if amplitude is greater than 0
      # the ord() function converts the hex values to integers
    if ord(frame[j]) > 0:
      zero = False
      break

    if zero:
      print >> file2, 'dropout at second %s' % (file1.tell()/file1.getframerate())
file1.close()
file2.close()

我认为一个简单的解决方案是考虑音频文件的帧速率相当高。我计算机上的示例文件恰好具有 8,000 帧速率。这意味着对于每一秒的音频,我有 8,000 个样本。如果您丢失了音频,我相信它会在一秒钟内跨多个帧存在,因此您基本上可以在您的标准允许的范围内大幅减少比较。如果我是你,我会尝试迭代每 1,000 个样本而不是音频文件中的每个样本。这基本上意味着它会检查每 1/8 秒的音频,看看它是否死了。不那么精确,但希望它能完成工作。

import wave

file1 = wave.open("testdropout.wav", "r")
file2 = open("silence.log", "w")
for i in range(file1.getnframes()):
  frame = file1.readframes(i)

  zero = True

  for j in range(0, len(frame), 1000):
      # check if amplitude is greater than 0
      # the ord() function converts the hex values to integers
    if ord(frame[j]) > 0:
      zero = False
      break

    if zero:
      print >> file2, 'dropout at second %s' % (file1.tell()/file1.getframerate())

file1.close()
file2.close()

目前,您正在将整个文件读入内存,这并不理想。如果您查看可用于 "Wave_read" 对象的方法,其中之一是 setpos(pos),它将文件指针的位置设置为 pos。如果你更新这个位置,你应该能够在任何给定时间只保留你想要的帧在内存中,防止错误。以下是一个粗略的轮廓:

import wave

file1 = wave.open("testdropout.wav", "r")
file2 = open("silence.log", "w")

def scan_frame(frame):
    for j in range(len(frame)):
        # check if amplitude is less than 0
        # It makes more sense here to check for the desired case (low amplitude) 
        # rather than breaking at higher amplitudes 
        if ord(frame[j]) <= 0:
            return True

for i in range(file1.getnframes()):
    frame = file1.readframes(1) # only read the frame at the current file position

    zero = scan_frame(frame)

    if zero:
       print >> file2, 'dropout at second %s' % (file1.tell()/file1.getframerate())

    pos = file1.tell()  # States current file position
    file1.setpos(pos + len(frame)) # or pos + 1, or whatever a single unit in a wave 
                                   # file is, I'm not entirely sure

file1.close()
file2.close()

希望对您有所帮助!

我以前没有使用过wave模块,但是file1.readframes(i)看起来它在第一帧时读取1帧,在第二帧时读取2帧,当你在第十帧时有 10 帧,而一个 2Gb CD 质量的文件可能有一百万帧 - 当你在帧 100,000 读取 100,000 帧时......每次循环都变慢了吗?

根据我的评论,在 Python 2 range() 中首先生成一个完整大小的内存数组,而 xrange() 不会,但根本不使用范围帮助更多。

并使用 any() 将循环向下推到较低层,以使代码更短,并可能更快:

import wave

file1 = wave.open("testdropout.wav", "r")
file2 = open("silence.log", "w")

chunksize = file1.getframerate()
chunk = file1.readframes(chunksize)

while chunk:
  if not any(ord(sample) for sample in chunk):
    print >> file2, 'dropout at second %s' % (file1.tell()/chunksize)

  chunk = file1.readframes(chunksize)

file1.close()
file2.close()

这应该以 1 秒的块读取文件。