用Scipy和Librosa在Python中读取WAV文件

9

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

import scipy.io.wavfile as wav
(sig, rate) = wav.read(_wav_file_)

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

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

因此,我决定使用 librosa 来读取这些文件,使用以下代码:

import librosa
(sig, rate) = librosa.load(_wav_file_, sr=None)

这在所有情况下都可以正常工作,但我注意到频谱图的颜色有所不同。虽然它是完全相同的图像,但颜色却被反转了。更具体地说,我注意到当保持相同的规格计算函数,只改变读取.wav的方式时,就会出现这种差异。有什么想法可以解释这个问题吗?两种方法读取.wav文件之间是否存在默认差异?
(rate1, sig1) = wav.read(spec_file) # rate1 = 16000
sig, rate = librosa.load(spec_file) # rate 22050
sig = np.array(α*sig, dtype = "int16") 

有一个几乎有效的方法是将sig的结果与常量α相乘,这个alpha是从scipy wavread和librosa导出的信号的最大值之间的比例尺。然而,两个信号的速率仍然不同。

3个回答

9
这似乎是一个量化问题。如果音频文件中的样本以float形式存储,并且librosa只是直接将其转换为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])

将a转换为int类型,不进行缩放

>>> a.astype(int)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

使用16位整数缩放将a转换为int

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

将缩放的int转换回float

>>> 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])

cb由于量化为int,只相等于约3或4个小数位。

如果librosa返回一个float,您可以将其乘以2**15并将其转换为int,以获得与scipy wave reader返回的相同范围的值。由于librosa返回的是float,因此其值可能会落在一个更小的范围内,例如[-1, +1],而16位整数将在[-32768, +32767]中。因此,您需要对其中一个进行缩放,使范围匹配。例如:

sig, rate = librosa.load(spec_file, mono=True)
sig = sig × 32767

1
但是为了进行缩放,我需要从每个数据集中找到最小值和最大值。这对我来说有点不可能。 - Jose Ramon
数据的来源是什么,用于创建wav文件的是什么? - fstop_22
这样,频谱图有点相似。但是我想还有一个问题,就是两种方法的采样率不同。我原以为采样率是由.wav文件定义的。然而,似乎并非如此。 - Jose Ramon
采样率应该是相同的。你得到的采样率数值是多少? - fstop_22
对于scipy wav.read,它是16.000,而对于librosa则是22050。 - Jose Ramon
显示剩余4条评论

5
  • 如果您自己不想进行量化,则可以使用pylab.specgram函数使用pylab为您完成。您可以查看函数内部如何使用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_)
  • 该代码产生了以下3个输出:

enter image description here

enter image description here

enter image description here

除了大小和强度方面的微小差异,无论读取方法、库还是数据类型,它们似乎都非常相似,这让我有些怀疑输出需要“完全”相同的目的以及它们应该有多么准确。

  • 然而,我发现librosa.load()函数提供了一个dtype参数,但仍然只使用float值。在这方面进行谷歌搜寻时,我只找到了这个问题,没什么帮助,而这个问题则表示,由于在内部似乎只使用浮点数,因此librosa将保持这种情况。

我想读取音频,然后根据以下示例计算声谱图:https://haythamfayek.com/2016/04/21/speech-processing-for-machine-learning.html。我注意到使用librosa和scipy waveread时,结果颜色有所不同。 - Jose Ramon

0
补充一下之前的内容,Librosa有一个工具可以将整数数组转换为浮点数。
float_audio = librosa.util.buf_to_float(sig)

当我生成Pydub音频段的频谱图时,我使用它非常成功。请记住,其中一个参数是每个样本的字节数。默认为2。您可以在此处的文档中了解更多信息。这是源代码

def buf_to_float(x, n_bytes=2, dtype=np.float32):
    """Convert an integer buffer to floating point values.
    This is primarily useful when loading integer-valued wav data
    into numpy arrays.
    See Also
    --------
    buf_to_float
    Parameters
    ----------
    x : np.ndarray [dtype=int]
        The integer-valued data buffer
    n_bytes : int [1, 2, 4]
        The number of bytes per sample in `x`
    dtype : numeric type
        The target output type (default: 32-bit float)
    Returns
    -------
    x_float : np.ndarray [dtype=float]
        The input data buffer cast to floating point
    """

    # Invert the scale of the data
    scale = 1./float(1 << ((8 * n_bytes) - 1))

    # Construct the format string
    fmt = '<i{:d}'.format(n_bytes)

    # Rescale and format the data buffer
    return scale * np.frombuffer(x, fmt).astype(dtype)

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