确定 wav 文件的位深度
Determining Bit-Depth of a wav file
我正在寻找一种快速的、最好是标准的库机制来确定 wav 文件的位深度,例如“16 位”或“24 位”。
我正在使用对 Sox 的子进程调用来获取过多的音频元数据,但是子进程调用非常慢,目前我只能从 Sox 可靠地获得的唯一信息是位深度。
内置的 wave 模块没有像 "getbitdepth()" 这样的功能,也不兼容 24 位 wav 文件 - 我可以使用 'try except' 通过 wave 模块访问文件元数据(如果有效,请手动记录它是 16 位),然后改为调用 sox(sox 将执行分析以准确记录其位深度)。我担心的是,这种方法感觉像是在猜测。如果读取一个 8bit 文件怎么办?如果不是,我会手动分配 16 位。
SciPy.io.wavefile 也不兼容 24 位音频,因此产生了类似的问题。
这个 tutorial 真的很有趣,甚至包括一些非常低级别(至少 Python 的低级别)脚本示例以从 wav 文件头中提取信息 - 不幸的是这些脚本不适用于 16 位音频。
有没有什么方法可以简单地(不调用 sox)确定我正在检查的 wav 文件的位深度?
我使用的wave header解析器脚本如下:
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
我强烈推荐 soundfile 模块(但请注意,我非常有偏见,因为我写了其中的很大一部分)。
您可以在那里打开文件作为 soundfile.SoundFile object, which has a subtype 属性,其中包含您要查找的信息。
在你的情况下可能是 'PCM_16'
或 'PCM_24'
。
基本上与 Matthias 的答案相同,但带有可复制粘贴的代码。
要求
pip install soundfile
代码
import soundfile as sf
ob = sf.SoundFile('example.wav')
print('Sample rate: {}'.format(ob.samplerate))
print('Channels: {}'.format(ob.channels))
print('Subtype: {}'.format(ob.subtype))
说明
- 声道:通常为 2 个,表示您有一个左扬声器和一个右扬声器。
- 采样率:音频信号是模拟的,但我们希望以数字方式表示它们。这意味着我们要在价值和时间上将它们离散化。采样率给出了我们每秒获得一个值的次数。单位是赫兹。采样率需要至少是原始声音中最高频率的两倍,否则会出现混叠。 Human hearing range 从 ~20Hz 到 ~20kHz,所以你可以切断 20kHz 以上的任何东西。意味着超过 40kHz 的采样率没有多大意义。
- Bit-depth:位深度越高,可以捕获的动态范围越大。动态范围是乐器、部分或音乐片段的最安静和最大音量之间的差异。典型值似乎是 16 位或 24 位。 16 位的位深度具有 96 dB 的理论动态范围,而 24 位具有 144 dB 的动态范围 (source)。
- Subtype:
PCM_16
表示16位深度,其中PCM代表Pulse-Code Modulation.
备选
如果你只是寻找一个命令行工具,那么我可以推荐MediaInfo:
$ mediainfo example.wav
General
Complete name : example.wav
Format : Wave
File size : 83.2 MiB
Duration : 8 min 14 s
Overall bit rate mode : Constant
Overall bit rate : 1 411 kb/s
Audio
Format : PCM
Format settings : Little / Signed
Codec ID : 1
Duration : 8 min 14 s
Bit rate mode : Constant
Bit rate : 1 411.2 kb/s
Channel(s) : 2 channels
Sampling rate : 44.1 kHz
Bit depth : 16 bits
Stream size : 83.2 MiB (100%)
我正在寻找一种快速的、最好是标准的库机制来确定 wav 文件的位深度,例如“16 位”或“24 位”。
我正在使用对 Sox 的子进程调用来获取过多的音频元数据,但是子进程调用非常慢,目前我只能从 Sox 可靠地获得的唯一信息是位深度。
内置的 wave 模块没有像 "getbitdepth()" 这样的功能,也不兼容 24 位 wav 文件 - 我可以使用 'try except' 通过 wave 模块访问文件元数据(如果有效,请手动记录它是 16 位),然后改为调用 sox(sox 将执行分析以准确记录其位深度)。我担心的是,这种方法感觉像是在猜测。如果读取一个 8bit 文件怎么办?如果不是,我会手动分配 16 位。
SciPy.io.wavefile 也不兼容 24 位音频,因此产生了类似的问题。
这个 tutorial 真的很有趣,甚至包括一些非常低级别(至少 Python 的低级别)脚本示例以从 wav 文件头中提取信息 - 不幸的是这些脚本不适用于 16 位音频。
有没有什么方法可以简单地(不调用 sox)确定我正在检查的 wav 文件的位深度?
我使用的wave header解析器脚本如下:
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
我强烈推荐 soundfile 模块(但请注意,我非常有偏见,因为我写了其中的很大一部分)。
您可以在那里打开文件作为 soundfile.SoundFile object, which has a subtype 属性,其中包含您要查找的信息。
在你的情况下可能是 'PCM_16'
或 'PCM_24'
。
基本上与 Matthias 的答案相同,但带有可复制粘贴的代码。
要求
pip install soundfile
代码
import soundfile as sf
ob = sf.SoundFile('example.wav')
print('Sample rate: {}'.format(ob.samplerate))
print('Channels: {}'.format(ob.channels))
print('Subtype: {}'.format(ob.subtype))
说明
- 声道:通常为 2 个,表示您有一个左扬声器和一个右扬声器。
- 采样率:音频信号是模拟的,但我们希望以数字方式表示它们。这意味着我们要在价值和时间上将它们离散化。采样率给出了我们每秒获得一个值的次数。单位是赫兹。采样率需要至少是原始声音中最高频率的两倍,否则会出现混叠。 Human hearing range 从 ~20Hz 到 ~20kHz,所以你可以切断 20kHz 以上的任何东西。意味着超过 40kHz 的采样率没有多大意义。
- Bit-depth:位深度越高,可以捕获的动态范围越大。动态范围是乐器、部分或音乐片段的最安静和最大音量之间的差异。典型值似乎是 16 位或 24 位。 16 位的位深度具有 96 dB 的理论动态范围,而 24 位具有 144 dB 的动态范围 (source)。
- Subtype:
PCM_16
表示16位深度,其中PCM代表Pulse-Code Modulation.
备选
如果你只是寻找一个命令行工具,那么我可以推荐MediaInfo:
$ mediainfo example.wav
General
Complete name : example.wav
Format : Wave
File size : 83.2 MiB
Duration : 8 min 14 s
Overall bit rate mode : Constant
Overall bit rate : 1 411 kb/s
Audio
Format : PCM
Format settings : Little / Signed
Codec ID : 1
Duration : 8 min 14 s
Bit rate mode : Constant
Bit rate : 1 411.2 kb/s
Channel(s) : 2 channels
Sampling rate : 44.1 kHz
Bit depth : 16 bits
Stream size : 83.2 MiB (100%)