Чтение wav-файла с помощью scipy и librosa в python - PullRequest
0 голосов
/ 01 февраля 2019

Я пытаюсь загрузить файл .wav в Python, используя папку scipy.Моя конечная цель - создать спектрограмму этого аудиофайла.Код для чтения файла может быть обобщен следующим образом:

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

Для некоторых файлов .wav я получаю следующую ошибку:

WavFileWarning: Chunk (не для данных) не понял, пропустил.WavFileWarning) ** ValueError: Incomplete wav chunk.

Поэтому я решил использовать 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.Тем не менее, хотя скорость сигнала была другой.

Ответы [ 3 ]

0 голосов
/ 04 февраля 2019
  • Если вы сами не хотите выполнять квантование, то вы можете использовать pylab с помощью функции pylab.specgram, чтобы сделать это за вас.Вы можете заглянуть внутрь функции и увидеть, как она использует vmin и vmax.

  • Из вашего поста (по крайней мере для меня) не совсем ясно, чего вы хотите достичь(поскольку у вас также нет ни образца входного файла, ни какого-либо сценария заранее).Но в любом случае, чтобы проверить, имеет ли спектрограмма волнового файла существенные различия в зависимости от случая, когда данные сигнала, возвращаемые любой из функций чтения, равны 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

, которые, за исключением незначительных различий в размере и интенсивности, кажутся довольно схожими, независимо от того,метод read, библиотека или тип данных, который заставляет меня задуматься, для каких целей выходные данные должны быть «точно» и насколько точными они должны быть.

  • Хотя я нахожу странным, чтоФункция librosa.load() предлагает параметр dtype, но в любом случае работает только со значениями float.Поиск в Google в этом отношении привел меня только к этой проблеме , которая не сильно помогла, и эта проблема говорит о том, что так будет и с librosa, так как внутренне кажется, что она использует только float.
0 голосов
/ 05 июля 2019

В дополнение к сказанному, в 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)
0 голосов
/ 04 февраля 2019

Это звучит как проблема квантования.Если сэмплы в волновом файле хранятся как 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])

Преобразование в тип 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])

c и b равны только примерно 3 или 4 десятичным знакам из-за квантования в int.

Если librosa возвращает float, вы можете масштабировать ее на 2**15 и привести ее к int, чтобы получить тот же диапазон значений, который возвращает читатель scipy wave.Поскольку librosa возвращает float, скорее всего, значения будут лежать в гораздо меньшем диапазоне, например [-1, +1], чем 16-разрядное целое число, которое будет в [-32768, +32767].Так что вам нужно масштабировать единицу, чтобы получить диапазоны для соответствияНапример,

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