web-dev-qa-db-fra.com

Lecture d'un fichier WAV avec Scipy et Librosa In python

J'essaie de charger un .wav Fichier in Python à l'aide du dossier SCIPY. Mon objectif final est de créer le spectrogramme de ce fichier audio. Le code de lecture du fichier pourrait être résumé comme suit:

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

Pour certains .wav Fichiers Je reçois l'erreur suivante:

WAVFILEWARNING: CHUNK (non-données) non compris, sautez-la. WAVFILEWARNING) ** ValueError: Chunk incomplet WAV.

Par conséquent, j'ai décidé d'utiliser LibroSa pour la lecture des fichiers à l'aide de:

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

Cela fonctionne correctement pour tous les cas, cependant, j'ai remarqué une différence dans les couleurs du spectrogramme. Bien que c'était le même chiffre exact, cependant, les couleurs ont été inversées. Plus précisément, j'ai remarqué que lorsque vous maintenez la même fonction pour calculer les spécifications et changer uniquement la façon dont je lis le .wav Il y avait cette différence. Une idée de ce que peut produire cette chose? Existe-t-il une différence par défaut entre la manière dont les deux approches ont lu le .wav fichier?

Edit :

(rate1, sig1) = wav.read(spec_file) # rate1 = 16000
sig, rate = librosa.load(spec_file) # rate 22050
sig = np.array(α*sig, dtype = "int16") 

Quelque chose qui a presque fonctionné est de multiplier le résultat de SIG avec une constante α Alpha c'était la balance entre les valeurs max du signal de Scipy WAVREAD et le signal dérivé de Librosa. Toujours bien que les taux de signal étaient différents.

5
Jose Ramon

Cela ressemble à un problème de quantification. Si des échantillons dans le fichier d'ondes sont stockés en tant que float et que Liberosa est juste exécutant une mise en forme droite sur un int, et la valeur inférieure à 1 sera tronquée à 0. Plus que probablement, c'est pourquoi c'est pourquoi sig est un tableau de tous les zéros. Le float doit être mis à l'échelle pour la modifier dans la plage d'un int. Par exemple,

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

Convertir A en Tapez int sans échec

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

Convertir A en int avec la mise à l'échelle pour un entier 16 bits

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

Convertir à l'échelle int retour à 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 et b ne sont égaux que d'environ 3 ou 4 décimales en raison de la quantification à int.

Si Librosa renvoie un float, vous pouvez l'accabler par 2**15 et le jeter à un int pour obtenir la même gamme de valeurs que le lecteur SciPy Wave est renvoyé. Puisque Librosa renvoie un float, il y a de fortes chances que les valeurs vont se situer dans une plage beaucoup plus petite, telle que [-1, +1], qu'un entier 16 bits qui sera dans [-32768, +32767]. Donc, vous devez mettre à l'échelle une pour que les gammes correspondent au match. Par exemple,

sig, rate = librosa.load(spec_file, mono=True)
sig = sig × 32767
4
fstop_22
  • Si vous ne voulez pas faire la quantification, vous pouvez utiliser pylab à l'aide de la fonction pylab.specgram, Pour le faire pour vous. Vous pouvez regarder dans la fonction et voir comment il utilise vmin et vmax.

  • Il n'est pas complètement clair de votre message (au moins pour moi) ce que vous voulez réaliser (car il n'y a pas non plus de fichier d'entrée ni de script à vous de vous). Mais de toute façon, pour vérifier si le spectrogramme d'un fichier d'ondes a des différences significatives en fonction du cas que les données du signal renvoyées à partir de l'une des fonctions de lecture sont float32 Ou int, j'ai testé les 3 suivants les fonctions.

Script 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_)
  • qui produisit les 3 sorties suivantes:

enter image description here

enter image description here

enter image description here

lequel à part les différences mineures de taille et d'intensité semblent assez similaires, quelle que soit la méthode de lecture, la bibliothèque ou le type de données, ce qui me fait question un peu, à quel but besoin les sorties doivent être "exactement" et à quel point ils devraient être exacts.

  • Je trouve étrange cependant que la fonction librosa.load() offre un paramètre dtype, mais fonctionne de toute façon avec float valeurs. Googling à cet égard me conduisit à cela problème qui n'était pas beaucoup d'aide et que ceci problème dit que c'est comme ça que cela va rester avec Librosa, comme en interne, il semble que Utilisez des flotteurs.
1
Duck Dodgers

Pour ajouter à ce qui a été dit, Librosa a une utilité pour convertir des tableaux entier en flotteurs.

float_audio = librosa.util.buf_to_float(sig)

J'utilise cela pour un grand succès lors de la production de spectrogrammes d'audiose pydub. N'oubliez pas que l'un de ses arguments est le nombre d'octets par échantillon. Il est par défaut à 2. Vous pouvez en savoir plus dans la documentation ici . Voici le code source :

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
Austin