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.
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
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.
_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_)
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.
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.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)