在python中使用scipy和librosa读取wav文件

Jos*_*mon 6 python audio signal-processing

我正在尝试.wav使用 scipy 文件夹在 Python 中加载文件。我的最终目标是创建该音频文件的频谱图。读取文件的代码可以总结如下:

import scipy.io.wavfile as wav
(sig, rate) = wav.read(_wav_file_)
Run Code Online (Sandbox Code Playgroud)

对于某些.wav文件,我收到以下错误:

WavFileWarning:无法理解块(非数据),跳过它。WavFileWarning) ** ValueError: 不完整的 wav 块。

因此,我决定使用 librosa 使用以下命令读取文件:

import librosa
(sig, rate) = librosa.load(_wav_file_, sr=None)
Run Code Online (Sandbox Code Playgroud)

这适用于所有情况,但是,我注意到光谱图的颜色有所不同。然而,虽然它是完全相同的数字,但不知何故颜色颠倒了。更具体地说,我注意到当保持相同的功能来计算规格并仅改变我阅读的方式时,.wav就会出现这种差异。知道什么可以产生那种东西吗?这两种方法读取.wav文件的方式之间是否存在默认差异?

编辑:

(rate1, sig1) = wav.read(spec_file) # rate1 = 16000
sig, rate = librosa.load(spec_file) # rate 22050
sig = np.array(?*sig, dtype = "int16") 
Run Code Online (Sandbox Code Playgroud)

几乎有效的方法是将 sig 的结果与常数?alpha 相乘,该 alpha 是来自 scipy wavread 的信号的最大值与来自 librosa 的信号之间的比例。尽管信号速率不同。

fst*_*_22 8

这听起来像是一个量化问题。如果波形文件中的样本存储为 asfloat并且 librosa 只是对 an 执行直接转换int,则小于 1 的值将被截断为 0。很有可能,这就是为什么sig是全零数组的原因。在float必须被缩放以将其映射到的范围int。例如,

>>> a = sp.randn(10)
>>> a
array([-0.04250369,  0.244113  ,  0.64479281, -0.3665814 , -0.2836227 ,
       -0.27808428, -0.07668698, -1.3104602 ,  0.95253315, -0.56778205])
Run Code Online (Sandbox Code Playgroud)

将 a 转换为类型int而不缩放

>>> a.astype(int)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
Run Code Online (Sandbox Code Playgroud)

将 a 转换int为 16 位整数的缩放比例

>>> b = (a* 32767).astype(int)
>>> b
array([ -1392,   7998,  21127, -12011,  -9293,  -9111,  -2512, -42939,
        31211, -18604])
Run Code Online (Sandbox Code Playgroud)

转换缩放intfloat

>>> c = b/32767.0
>>> c
array([-0.04248177,  0.24408704,  0.64476455, -0.36655782, -0.28360851,
       -0.27805414, -0.0766625 , -1.31043428,  0.9525132 , -0.56776635])
Run Code Online (Sandbox Code Playgroud)

cb由于量化为,并且仅等于大约 3 或 4 个小数位int

如果 librosa 返回 a float,您可以按比例缩放2**15并将其转换为 anint以获得与 scipy wave reader 返回的相同范围的值。由于 librosa 正在返回 a float,因此值可能会位于一个小得多的范围内,例如[-1, +1],而不是将在[-32768, +32767]. 所以你需要缩放一个以获得匹配的范围。例如,

sig, rate = librosa.load(spec_file, mono=True)
sig = sig × 32767
Run Code Online (Sandbox Code Playgroud)


Duc*_*ers 6

  • 如果您自己不想进行量化,那么您可以使用pylabusing 该pylab.specgram函数来为您完成量化。您可以查看该函数的内部并了解它如何使用vminvmax

  • 从您的帖子(至少对我来说)来看,您想要实现的目标并不完全清楚(因为您事先既没有示例输入文件也没有任何脚本)。但无论如何,为了检查波形文件的频谱图是否存在显着差异,具体取决于从任何读取函数返回的信号数据是float32或 的情况int,我测试了以下 3 个函数。

Python脚本:

_wav_file_ = "africa-toto.wav"

def spectogram_librosa(_wav_file_):
    import librosa
    import pylab
    import numpy as np
    
    (sig, rate) = librosa.load(_wav_file_, sr=None, mono=True,  dtype=np.float32)
    pylab.specgram(sig, Fs=rate)
    pylab.savefig('spectrogram3.png')

def graph_spectrogram_wave(wav_file):
    import wave
    import pylab
    def get_wav_info(wav_file):
        wav = wave.open(wav_file, 'r')
        frames = wav.readframes(-1)
        sound_info = pylab.fromstring(frames, 'int16')
        frame_rate = wav.getframerate()
        wav.close()
        return sound_info, frame_rate
    sound_info, frame_rate = get_wav_info(wav_file)
    pylab.figure(num=3, figsize=(10, 6))
    pylab.title('spectrogram pylab with wav_file')
    pylab.specgram(sound_info, Fs=frame_rate)
    pylab.savefig('spectrogram2.png')


def graph_wavfileread(_wav_file_):
    import matplotlib.pyplot as plt
    from scipy import signal
    from scipy.io import wavfile
    import numpy as np   
    sample_rate, samples = wavfile.read(_wav_file_)   
    frequencies, times, spectrogram = signal.spectrogram(samples,sample_rate,nfft=1024)
    plt.pcolormesh(times, frequencies, 10*np.log10(spectrogram))
    plt.ylabel('Frequency [Hz]')
    plt.xlabel('Time [sec]')
    plt.savefig("spectogram1.png")
    

spectogram_librosa(_wav_file_)
#graph_wavfileread(_wav_file_)
#graph_spectrogram_wave(_wav_file_)
Run Code Online (Sandbox Code Playgroud)
  • 产生以下 3 个输出:

在此输入图像描述

在此输入图像描述

在此输入图像描述

除了大小和强度上的微小差异之外,无论读取方法、库或数据类型如何,看起来都非常相似,这让我有点疑问,出于什么目的需要输出“完全相同”以及它们应该有多精确。

  • 我确实觉得奇怪,虽然该librosa.load()函数提供了一个dtype参数,但无论如何只能使用float值。在这方面谷歌搜索导致我只找到了这个问题,这没有多大帮助,这个问题说这就是它与 librosa 的关系,因为在内部它似乎只使用浮动。