J'essaye de charger un fichier .wav
en Python en utilisant le dossier scipy. Mon objectif final est de créer le spectrogramme de ce fichier audio. Le code de lecture du fichier peut être résumé comme suit:
(rate1, sig1) = wav.read(spec_file) # rate1 = 16000 sig, rate = librosa.load(spec_file) # rate 22050 sig = np.array(α*sig, dtype = "int16")
Pour certains fichiers .wav
, je reçois l'erreur suivante:
WavFileWarning: Chunk (non-data) non compris, saute. WavFileWarning) ** ValueError: bloc wav incomplet.
Par conséquent, j'ai décidé d'utiliser librosa pour lire les fichiers en utilisant:
import librosa (sig, rate) = librosa.load(_wav_file_, sr=None)
Cela fonctionne correctement dans tous les cas, cependant, j'ai remarqué une différence aux couleurs du spectrogramme. Bien que ce soit le même chiffre exact, cependant, les couleurs ont été inversées. Plus précisément, j'ai remarqué qu'en conservant la même fonction pour le calcul des spécifications et en changeant uniquement la façon dont je lis le .wav
, il y avait cette différence. Une idée de ce qui peut produire cette chose? Y a-t-il une différence par défaut entre la façon dont les deux approches lisent le fichier .wav
?
EDIT:
import scipy.io.wavfile as wav (sig, rate) = wav.read(_wav_file_)
3 Réponses :
Cela ressemble à un problème de quantification. Si les échantillons du fichier wave sont stockés en tant que float
et que la librosa effectue simplement un cast direct en un int
, et une valeur inférieure à 1 sera tronquée à 0. Plus que probable , c'est pourquoi sig
est un tableau de tous les zéros. Le float
doit être mis à l'échelle pour le mapper dans la plage d'un int
. Par exemple,
sig, rate = librosa.load(spec_file, mono=True) sig = sig à 32767
Convertit a en type int
sans mise à l'échelle
>>> 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])
Convertit a en int
avec 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])
Conversion de int
mis à l'échelle en float
>>> a.astype(int) array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
c
et b
ne sont égaux qu'à environ 3 ou 4 décimales en raison de la quantification en int
.
Si la librosa renvoie un float
, vous pouvez le mettre à l'échelle de 2 ** 15
et le transtyper en un int code > pour obtenir la même plage de valeurs que celle renvoyée par le lecteur scipy wave. Puisque la librosa renvoie un
float
, il est probable que les valeurs se trouvent dans une plage beaucoup plus petite, telle que [-1, +1]
, qu'un entier de 16 bits qui sera dans [-32768, +32767]
. Vous devez donc en mettre un à l'échelle pour que les plages correspondent. 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])
Mais pour faire la mise à l'échelle, je dois trouver le minimum et le maximum de chaque ensemble de données. C'est un peu impossible pour moi.
Le facteur d'échelle est plus que probablement constant. Si ce n'était pas le cas, le volume du fichier wave changerait pour chaque bloc de données lu.
Quelle est la source des données et qu'est-ce qui est utilisé pour créer le fichier wav?
Cette information est malheureusement quelque chose auquel je n'ai pas accès. Les fichiers wav font partie d'une base de données qui peut être trouvée ici: zenodo.org/record/1188976#. XFmYoVxKi73
Oui, j'ai essayé mais de manière un peu arbitraire. Je viens de mettre à l'échelle mais j'ai trouvé le max et le min dans les deux cas dans 20-30 fichiers wav.
De cette façon, les spectrogrammes sont un peu similaires. Il reste encore un problème, je suppose, c'est que les deux méthodes ont une fréquence d'échantillonnage différente. Je pensais que la fréquence d'échantillonnage était définie par le fichier .wav. Cependant, il semble que ce ne soit pas le cas.
La fréquence d'échantillonnage doit être la même. Quelles valeurs obtenez-vous pour les taux d'échantillonnage?
Pour le scipy wav.read, il est de 16.000 alors que pour la librosa 22050.
Il semble que librosa et scipy utilisent différents formats pour le fichier wav.
Si vous ne souhaitez pas effectuer vous-même la quantification, vous pouvez utiliser pylab
en utilisant la fonction pylab.specgram
, pour le faire pour vous. Vous pouvez regarder à l'intérieur de la fonction et voir comment elle utilise vmin
et vmax
.
Ce que vous voulez réaliser n'est pas tout à fait clair dans votre message (du moins pour moi) (car il n'y a pas non plus de fichier d'entrée d'exemple ni de script de votre part). Mais de toute façon, pour vérifier si le spectrogramme d'un fichier wave présente des différences significatives selon le cas où les données de signal renvoyées par l'une des fonctions de lecture sont float32
ou int
, je testé les 3 fonctions suivantes.
_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, mis à part les différences mineures de taille et d'intensité semblent assez similaires, peu importe la méthode de lecture, la bibliothèque ou le type de données, ce qui me fait un peu questionner, dans quel but besoin les sorties sont «exactement» les mêmes et à quel point elles devraient être exactes.
librosa.load ()
offre un paramètre dtype
mais ne fonctionne de toute façon qu'avec des valeurs float
. Google à cet égard ne m'a conduit qu'à ce problème qui n'a pas beaucoup aidé et ce problème indique que c'est ainsi qu'il restera avec librosa, car en interne, il semble seulement utilisez des flotteurs. Je souhaite lire l'audio puis calculer le spectrogramme en suivant les exemples suivants: haythamfayek.com/2016/04/21/... . J'ai remarqué qu'avec librosa et scipy waveread, il y avait une différence dans les couleurs obtenues.
Pour ajouter à ce qui a été dit, Librosa a un utilitaire pour convertir des tableaux d'entiers en floats.
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)
J'utilise ceci avec beaucoup de succès lors de la production de spectrogrammes de segments audio Pydub. Gardez à l'esprit que l'un de ses arguments est le nombre d'octets par échantillon. La valeur par défaut est 2. Vous pouvez en savoir plus dans la documentation ici . Voici le code source :
float_audio = librosa.util.buf_to_float(sig)