使用Python从TIMIT数据库读取WAV文件

13

我想在Python中从TIMIT数据库读取WAV文件,但是出现了错误:

当我使用wave时:

wave.Error: file does not start with RIFF id

当我使用scipy时:

ValueError: File format b'NIST'... not understood.

当我使用librosa时,程序卡住了。 我尝试使用sox将其转换为wav格式:

cmd = "sox " + wav_file + " -t wav " + new_wav
subprocess.call(cmd, shell=True)

但这并没有帮助。我看到了一个提到scikits.audiolab包的旧答案,但是看起来它已经不再受支持。

我该如何读取这些文件以获得数据的ndarray?

谢谢


你可以尝试使用soundfile模块或其他libsndfile包装器之一来读取文件,这些包装器应该支持NIST格式。 - Matthias
6个回答

8

您的文件不是WAV格式,看起来它是NIST SPHERE文件。根据LDC网页的描述:“许多LDC语料库都包含NIST SPHERE格式的语音文件。” 根据NIST文件格式的描述,文件的前四个字符是。 这就是scipy报错提示的原因:它不知道如何读取以NIST开头的文件。

如果您想使用尝试过的任何库读取该文件,我怀疑您必须将文件转换为WAV格式。 使用程序强制转换为WAV,使用命令选项-f wav(或等效的-f rif),例如:

sph2pipe -f wav input.sph output.wav

我在我的回答中更新了一条关于使用“-f wav”的注释。 - Warren Weckesser
一个简单的方法是递归地在当前目录下运行所有文件,命令为 find . -name '*.WAV' -exec sph2pipe -f wav {} {}.wav \;。唯一的缺点是你最终会得到以 .WAV.wav 结尾的文件。 - Kyle

3

在命令行中发出此命令以验证它是否为wav文件......或者不是

xxd -b myaudiofile.wav | head

如果是wav格式,它会显示类似于以下内容
00000000: 01010010 01001001 01000110 01000110 10111100 10101111  RIFF..
00000006: 00000001 00000000 01010111 01000001 01010110 01000101  ..WAVE
0000000c: 01100110 01101101 01110100 00100000 00010000 00000000  fmt ..
00000012: 00000000 00000000 00000001 00000000 00000001 00000000  ......
00000018: 01000000 00011111 00000000 00000000 01000000 00011111  @...@.
0000001e: 00000000 00000000 00000001 00000000 00001000 00000000  ......
00000024: 01100100 01100001 01110100 01100001 10011000 10101111  data..
0000002a: 00000001 00000000 10000001 10000000 10000001 10000000  ......
00000030: 10000001 10000000 10000001 10000000 10000001 10000000  ......
00000036: 10000001 10000000 10000001 10000000 10000001 10000000  ......

这里有另一种显示二进制文件(如WAV)内容的方法

od -A x -t x1z -v  audio_util_test_file_custom.wav   | head 
000000 52 49 46 46 24 80 00 00 57 41 56 45 66 6d 74 20  >RIFF$...WAVEfmt <
000010 10 00 00 00 01 00 01 00 44 ac 00 00 88 58 01 00  >........D....X..<
000020 02 00 10 00 64 61 74 61 00 80 00 00 00 00 78 05  >....data......x.<
000030 ed 0a 5e 10 c6 15 25 1b 77 20 ba 25 eb 2a 08 30  >..^...%.w .%.*.0<
000040 0e 35 fc 39 cf 3e 84 43 1a 48 8e 4c de 50 08 55  >.5.9.>.C.H.L.P.U<
000050 0b 59 e4 5c 91 60 12 64 63 67 85 6a 74 6d 30 70  >.Y.\.`.dcg.jtm0p<
000060 b8 72 0a 75 25 77 09 79 b4 7a 26 7c 5d 7d 5a 7e  >.r.u%w.y.z&|]}Z~<
000070 1c 7f a3 7f ee 7f fd 7f d0 7f 67 7f c3 7e e3 7d  >..........g..~.}<
000080 c9 7c 74 7b e6 79 1e 78 1f 76 e8 73 7b 71 d9 6e  >.|t{.y.x.v.s{q.n<
000090 03 6c fa 68 c1 65 57 62 c0 5e fd 5a 0f 57 f8 52  >.l.h.eWb.^.Z.W.R<

请注意,wav文件以RIFF字符开头,这是文件使用wav编解码器的强制指示符...如果您的系统(我正在使用Linux)没有上述命令行实用程序:xxd,则使用{{link1:任何十六进制编辑器,如wxHexEditor}}类似地检查您的wav文件以确认您是否看到RIFF ...如果没有RIFF,则不是一个wav文件。
以下是wav格式规范的详细信息。

http://soundfile.sapp.org/doc/WaveFormat/

http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html

http://unusedino.de/ec64/technical/formats/wav.html

http://www.drdobbs.com/database/inside-the-riff-specification/184409308

https://www.gamedev.net/articles/programming/general-and-gameplay-programming/loading-a-wave-file-r709

http://www.topherlee.com/software/pcm-tut-wavformat.html

http://www.labbookpages.co.uk/audio/javaWavFiles.html

http://www.johnloomis.org/cpe102/asgn/asgn1/riff.html

http://nagasm.org/ASL/sound05/


2
如果您希望得到一个适用于文件夹中每个wav文件的通用代码,请运行以下命令:
forfiles /s /m *.wav /c "cmd /c sph2pipe -f wav @file @fnameRIFF.wav"

它搜索可以找到的每个wav文件,并创建一个wav文件,同时使用名称< base_name >RIFF.wav,这两个文件都可以用scipy和wave读取。


这与Warren Weckesser的sph2pipe解决方案相辅相成...我本来想把它放在评论中,但我还没有足够的声望。 - J Agustin Barrachina
1
如果您不想安装forfiles,请使用以下命令:find . -name '*.WAV' -exec sph2pipe -f wav {} {}.wav \; - Kyle

2
请使用sounddevice和soundfile获取numpy数组数据(以及播放),使用以下代码:
import matplotlib.pyplot as plt
import soundfile as sf
import sounddevice as sd
# https://catalog.ldc.upenn.edu/desc/addenda/LDC93S1.wav
data, fs = sf.read('LDC93S1.wav')
print(data.shape,fs)
sd.play(data, fs, blocking=True)
plt.plot(data)
plt.show()

输出

(46797,) 16000

enter image description here

一个TIMIT数据库的示例wav文件: https://catalog.ldc.upenn.edu/desc/addenda/LDC93S1.wav


1
我编写了一个Python脚本,可以将所有方言的所有发音人以NIST格式存储的.WAV文件转换为可在您的系统上播放的.WAV文件。
注意:所有方言文件夹都位于./TIMIT/TRAIN/中。您可能需要根据您的项目结构(或者如果您在Windows上)更改dialects_path。
from sphfile import SPHFile

dialects_path = "./TIMIT/TRAIN/"

for dialect in dialects:
    dialect_path = dialects_path + dialect
    speakers = os.listdir(path = dialect_path)
    for speaker in speakers:
        speaker_path =  os.path.join(dialect_path,speaker)        
        speaker_recordings = os.listdir(path = speaker_path)

        wav_files = glob.glob(speaker_path + '/*.WAV')

        for wav_file in wav_files:
            sph = SPHFile(wav_file)
            txt_file = ""
            txt_file = wav_file[:-3] + "TXT"

            f = open(txt_file,'r')
            for line in f:
                words = line.split(" ")
                start_time = (int(words[0])/16000)
                end_time = (int(words[1])/16000)
            print("writing file ", wav_file)
            sph.write_wav(wav_file.replace(".WAV",".wav"),start_time,end_time)    

0
有时这可能是由于错误的 7zip 文件提取方法引起的。我也遇到过类似的问题。我通过使用 7z x <datasetname>.7z 来提取数据集来解决了这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接