繁体   English   中英

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

[英]Reading a wav file with scipy and librosa in python

我正在尝试使用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的结果α的α,这是从SciPy的wavread和该信号的最大值从librosa得到的信号之间的比例。 尽管信号速率不同。

这听起来像一个量化问题。 如果将wave文件中的样本存储为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])

将比例转换为int并转换为16位整数

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

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

如果librosa返回的是float ,则可以将其缩放2**15并将其强制转换为int以获得与scipy Wave阅读器返回的值相同的范围。 由于librosa返回的是float ,因此这些值很有可能位于一个比[-32768, +32767]的16位整数小得多的范围内,例如[-1, +1] [-32768, +32767] 因此,您需要缩放一个以匹配范围。 例如,

sig, rate = librosa.load(spec_file, mono=True)
sig = sig × 32767
  • 如果您自己不想进行量化,则可以通过pylab.specgram函数使用pylab来完成。 您可以查看该函数的内部,看看它如何使用vminvmax

  • 从您的帖子中(至少对我而言)尚不清楚要实现什么(因为事先也没有示例输入文件或脚本)。 但是无论如何,要检查wave文件的频谱图是否存在明显差异,这取决于从任何读取函数返回的信号数据是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_)
  • 产生了以下三个输出:

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

除了大小和强度上的微小差异外,无论是读取方法,库还是数据类型,它们看起来都非常相似,这使我有些疑问,输出的目的是“完全”相同是什么,输出应该是多么精确。

  • 我确实发现奇怪,尽管librosa.load()函数提供了dtype参数,但无论如何仅适用于float值。 在这方面进行谷歌搜索仅导致我遇到的问题并没有太大帮助,该问题表明这就是librosa的问题,因为在内部它似乎仅使用浮点数。

补充说一下,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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM