2017-09-13 201 views
1

我正在寻找一种快速的,最好是标准库机制来确定wav文件的位深度,例如, '16位'或'24位'。确定wav文件的位深度

我正在使用一个子进程调用Sox来获取大量音频元数据,但子进程调用非常缓慢,目前我只能从Sox获得可靠的唯一信息是位深度。

内置wave模块没有像getbitdepth()这样的函数,并且与24位wav文件不兼容 - 我可以使用'try except'来使用wave模块访问文件元数据(如果它工作,手动记录它是16位),然后打开,除了调用sox(sox将执行分析以准确记录其位深度)。我担心的是,这种方法就像猜测一样。如果读取8位文件会怎么样?如果不是,我会手动分配16位。

SciPy.io.wavefile也与24位音频不兼容,因此会产生类似的问题。

这个tutorial真的很有趣,甚至包括一些非常低的级别(对于Python来说至少是低级别的)从wav文件头中提取信息的脚本示例 - 不幸的是这些脚本不适用于16位音频。

有什么办法可以简单地(并且不用调用sox)来确定我正在检查的wav文件的位深度是多少?

我使用的波头分析器脚本如下:

import struct 
import os 

def print_wave_header(f): 
    ''' 
    Function takes an audio file path as a parameter and 
    returns a dictionary of metadata parsed from the header 
    ''' 
    r = {} #the results of the header parse 
    r['path'] = f 
    fin = open(f,"rb") # Read wav file, "r flag" - read, "b flag" - binary 
    ChunkID=fin.read(4) # First four bytes are ChunkID which must be "RIFF" in ASCII 
    r["ChunkID"]=ChunkID 
    ChunkSizeString=fin.read(4) # Total Size of File in Bytes - 8 Bytes 
    ChunkSize=struct.unpack('I',ChunkSizeString) # 'I' Format is to to treat the 4 bytes as unsigned 32-bit inter 
    TotalSize=ChunkSize[0]+8 # The subscript is used because struct unpack returns everything as tuple 
    r["TotalSize"]=TotalSize 
    DataSize=TotalSize-44 # This is the number of bytes of data 
    r["DataSize"]=DataSize 
    Format=fin.read(4) # "WAVE" in ASCII 
    r["Format"]=Format 
    SubChunk1ID=fin.read(4) # "fmt " in ASCII 
    r["SubChunk1ID"]=SubChunk1ID 
    SubChunk1SizeString=fin.read(4) # Should be 16 (PCM, Pulse Code Modulation) 
    SubChunk1Size=struct.unpack("I",SubChunk1SizeString) # 'I' format to treat as unsigned 32-bit integer 
    r["SubChunk1Size"]=SubChunk1Size 
    AudioFormatString=fin.read(2) # Should be 1 (PCM) 
    AudioFormat=struct.unpack("H",AudioFormatString) ## 'H' format to treat as unsigned 16-bit integer 
    r["AudioFormat"]=AudioFormat[0] 
    NumChannelsString=fin.read(2) # Should be 1 for mono, 2 for stereo 
    NumChannels=struct.unpack("H",NumChannelsString) # 'H' unsigned 16-bit integer 
    r["NumChannels"]=NumChannels[0] 
    SampleRateString=fin.read(4) # Should be 44100 (CD sampling rate) 
    SampleRate=struct.unpack("I",SampleRateString) 
    r["SampleRate"]=SampleRate[0] 
    ByteRateString=fin.read(4) # 44100*NumChan*2 (88200 - Mono, 176400 - Stereo) 
    ByteRate=struct.unpack("I",ByteRateString) # 'I' unsigned 32 bit integer 
    r["ByteRate"]=ByteRate[0] 
    BlockAlignString=fin.read(2) # NumChan*2 (2 - Mono, 4 - Stereo) 
    BlockAlign=struct.unpack("H",BlockAlignString) # 'H' unsigned 16-bit integer 
    r["BlockAlign"]=BlockAlign[0] 
    BitsPerSampleString=fin.read(2) # 16 (CD has 16-bits per sample for each channel) 
    BitsPerSample=struct.unpack("H",BitsPerSampleString) # 'H' unsigned 16-bit integer 
    r["BitsPerSample"]=BitsPerSample[0] 
    SubChunk2ID=fin.read(4) # "data" in ASCII 
    r["SubChunk2ID"]=SubChunk2ID 
    SubChunk2SizeString=fin.read(4) # Number of Data Bytes, Same as DataSize 
    SubChunk2Size=struct.unpack("I",SubChunk2SizeString) 
    r["SubChunk2Size"]=SubChunk2Size[0] 
    S1String=fin.read(2) # Read first data, number between -32768 and 32767 
    S1=struct.unpack("h",S1String) 
    r["S1"]=S1[0] 
    S2String=fin.read(2) # Read second data, number between -32768 and 32767 
    S2=struct.unpack("h",S2String) 
    r["S2"]=S2[0] 
    S3String=fin.read(2) # Read second data, number between -32768 and 32767 
    S3=struct.unpack("h",S3String) 
    r["S3"]=S3[0] 
    S4String=fin.read(2) # Read second data, number between -32768 and 32767 
    S4=struct.unpack("h",S4String) 
    r["S4"]=S4[0] 
    S5String=fin.read(2) # Read second data, number between -32768 and 32767 
    S5=struct.unpack("h",S5String) 
    r["S5"]=S5[0] 
    fin.close() 
    return r 
+0

每个wav文件的头部都有bit_depth(前44个字节)...每个wav库都必须解析头文件...它很容易执行这个头文件自己解析 –

+0

使用我在示例中标记的教程是已经能够解析报头,但比特深度并不总是清晰的,例如 =块ID b'RIFF ' 总计TOTALSIZE = 602914 数据尺寸= 602870 格式= b'WAVE' SubChunk1ID = b'JUNK” SubChunk1Size = 92 的AudioFormat = 0 NumChannels = 0 SAMPLERATE = 0 ByteRate = 0 BlockAlign = 0 BitsPerSample = 0 SubChunk2ID = b '\ X00 \ X00 \ X00 \ X00' SubChunk2Size = 0 S1 = 0 S2 = 0 S3 = 0 S4 = 0 S5 = 0 根据文件 压缩标题是否可读,但我希望能够读取它,而不管文件格式/压缩如何,没有任何转换过程。 – user3535074

+0

其红色标志为0表示所有这些标头设置 - 无论是文件损坏或库是错误的...即使wav文件被压缩(我从来没有见过压缩的wav文件)头肯定不会压缩...这里是一个简洁的WAV规范总结http://soundfile.sapp.org/doc/WaveFormat/ ...如果你写自己的头解析器特别注意头字段和数据部分的字节顺序......你可以在两页代码 –

回答

1

我强烈建议soundfile模块(但你要知道,我是非常偏颇的,因为我写的很大一部分)。

在那里您可以打开文件作为soundfile.SoundFile对象,该对象具有一个subtype属性,该属性包含您正在查找的信息。

在你的情况下,这可能是'PCM_16''PCM_24'

+0

我会试试这个。你知道soundfile对象是否可以异步实例化吗? – user3535074

+0

你能澄清你的意思是“异步”吗?如果你的意思是,如果有任何函数(我猜你在谈论构造函数)是“等待”的,那么没有。是否有任何声音文件模块支持? – Matthias

+0

你理解正确。我不知道有任何可用的音频模块是可以等待的 - 如果soundfile足够快,那么也许我可以尝试在没有异步的情况下工作。 – user3535074