J'essaie de créer un spectrogramme à partir d'un fichier .wav en python3.
Je veux que l'image enregistrée finale ressemble à cette image:
J'ai essayé ce qui suit:
Ce poste de débordement de pile: spectrogramme d’un fichier wave
Ce poste a fonctionné, un peu. Après l'avoir lancé, j'ai eu
Cependant, ce graphique ne contient pas les couleurs dont j'ai besoin. J'ai besoin d'un spectrogramme qui a des couleurs. J'ai essayé de bricoler ce code pour essayer d'ajouter des couleurs, mais après y avoir consacré beaucoup de temps et d'efforts, je ne pouvais pas le comprendre!
J'ai ensuite essayé this tutoriel.
Ce code s'est écrasé (ligne 17) lorsque j'ai essayé de l'exécuter avec l'erreur TypeError: l'objet 'numpy.float64' ne peut pas être interprété comme un entier.
ligne 17:
samples = np.append(np.zeros(np.floor(frameSize/2.0)), sig)
J'ai essayé de le réparer en coulant
samples = int(np.append(np.zeros(np.floor(frameSize/2.0)), sig))
et j'ai aussi essayé
samples = np.append(np.zeros(int(np.floor(frameSize/2.0)), sig))
Cependant, ni l'un ni l'autre n'a fonctionné à la fin.
J'aimerais vraiment savoir comment convertir mes fichiers .wav en spectrogrammes en couleur pour pouvoir les analyser! Toute aide serait appréciée!!!!!
Dites-moi si vous souhaitez que je vous fournisse plus d'informations sur ma version de Python, ce que j'ai essayé ou ce que je veux réaliser.
Utilisation scipy.signal.spectrogram
.
import matplotlib.pyplot as plt
from scipy import signal
from scipy.io import wavfile
sample_rate, samples = wavfile.read('path-to-mono-audio-file.wav')
frequencies, times, spectrogram = signal.spectrogram(samples, sample_rate)
plt.pcolormesh(times, frequencies, spectrogram)
plt.imshow(spectrogram)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()
Assurez-vous que votre fichier wav est mono (canal unique) et non stéréo (canal double) avant d'essayer de le faire. Je recommande fortement de lire la documentation de scipy à l’adresse suivante: https://docs.scipy.org/doc/scipy- 0.19.0/reference/généré/scipy.signal.spectrogram.html.
En mettant plt.pcolormesh
avant plt.imshow
semble résoudre certains problèmes, comme l'a souligné @Davidjb, et si une erreur de déballage se produit, suivez les étapes de @cgnorthcutt ci-dessous.
J'ai corrigé les erreurs que vous rencontrez pour http://www.frank-zalkow.de/en/code-snippets/create-audio-spectrograms-with-python.html
Cette implémentation est préférable car vous pouvez modifier le binsize
(par exemple, binsize=2**8
)
import numpy as np
from matplotlib import pyplot as plt
import scipy.io.wavfile as wav
from numpy.lib import stride_tricks
""" short time fourier transform of audio signal """
def stft(sig, frameSize, overlapFac=0.5, window=np.hanning):
win = window(frameSize)
hopSize = int(frameSize - np.floor(overlapFac * frameSize))
# zeros at beginning (thus center of 1st window should be for sample nr. 0)
samples = np.append(np.zeros(int(np.floor(frameSize/2.0))), sig)
# cols for windowing
cols = np.ceil( (len(samples) - frameSize) / float(hopSize)) + 1
# zeros at end (thus samples can be fully covered by frames)
samples = np.append(samples, np.zeros(frameSize))
frames = stride_tricks.as_strided(samples, shape=(int(cols), frameSize), strides=(samples.strides[0]*hopSize, samples.strides[0])).copy()
frames *= win
return np.fft.rfft(frames)
""" scale frequency axis logarithmically """
def logscale_spec(spec, sr=44100, factor=20.):
timebins, freqbins = np.shape(spec)
scale = np.linspace(0, 1, freqbins) ** factor
scale *= (freqbins-1)/max(scale)
scale = np.unique(np.round(scale))
# create spectrogram with new freq bins
newspec = np.complex128(np.zeros([timebins, len(scale)]))
for i in range(0, len(scale)):
if i == len(scale)-1:
newspec[:,i] = np.sum(spec[:,int(scale[i]):], axis=1)
else:
newspec[:,i] = np.sum(spec[:,int(scale[i]):int(scale[i+1])], axis=1)
# list center freq of bins
allfreqs = np.abs(np.fft.fftfreq(freqbins*2, 1./sr)[:freqbins+1])
freqs = []
for i in range(0, len(scale)):
if i == len(scale)-1:
freqs += [np.mean(allfreqs[int(scale[i]):])]
else:
freqs += [np.mean(allfreqs[int(scale[i]):int(scale[i+1])])]
return newspec, freqs
""" plot spectrogram"""
def plotstft(audiopath, binsize=2**10, plotpath=None, colormap="jet"):
samplerate, samples = wav.read(audiopath)
s = stft(samples, binsize)
sshow, freq = logscale_spec(s, factor=1.0, sr=samplerate)
ims = 20.*np.log10(np.abs(sshow)/10e-6) # amplitude to decibel
timebins, freqbins = np.shape(ims)
print("timebins: ", timebins)
print("freqbins: ", freqbins)
plt.figure(figsize=(15, 7.5))
plt.imshow(np.transpose(ims), Origin="lower", aspect="auto", cmap=colormap, interpolation="none")
plt.colorbar()
plt.xlabel("time (s)")
plt.ylabel("frequency (hz)")
plt.xlim([0, timebins-1])
plt.ylim([0, freqbins])
xlocs = np.float32(np.linspace(0, timebins-1, 5))
plt.xticks(xlocs, ["%.02f" % l for l in ((xlocs*len(samples)/timebins)+(0.5*binsize))/samplerate])
ylocs = np.int16(np.round(np.linspace(0, freqbins-1, 10)))
plt.yticks(ylocs, ["%.02f" % freq[i] for i in ylocs])
if plotpath:
plt.savefig(plotpath, bbox_inches="tight")
else:
plt.show()
plt.clf()
return ims
ims = plotstft(filepath)
import os
import wave
import pylab
def graph_spectrogram(wav_file):
sound_info, frame_rate = get_wav_info(wav_file)
pylab.figure(num=None, figsize=(19, 12))
pylab.subplot(111)
pylab.title('spectrogram of %r' % wav_file)
pylab.specgram(sound_info, Fs=frame_rate)
pylab.savefig('spectrogram.png')
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
pour A Capella Science - Bohemian Gravity! cela donne:
Utilisez graph_spectrogram(path_to_your_wav_file)
. Je ne me souviens pas du blog d'où j'ai pris cet extrait. Je vais ajouter le lien chaque fois que je le revois.