Dies ist eine alte Version des Dokuments!
Vorläufige Definition der Meilensteine:
Erweiterung der Erweiterungen:
# -*- coding: utf8 -*- import pyaudio import numpy as np import matplotlib.pyplot as plt CHUNKSIZE = 1024 #festgelegte Chunksize #den Audioeingang initialisieren p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=CHUNKSIZE) #Daten schreiben frames = [] #Liste von Chunks(Blöcken) for i in range(0, int(44100 / CHUNKSIZE*5)): data = stream.read(CHUNKSIZE) frames.append(np.fromstring(data, dtype=np.int16))#evtl nur normal int? Datengröße müssen wir wohl später abschätzen was sinnvoll ist #Liste der numpy-arrays in 1D-array konvertieren numpydata = np.hstack(frames) print numpydata #Daten plotten plt.plot(numpydata) plt.show() #stream schließen stream.stop_stream() stream.close() p.terminate
from __future__ import division # -*- coding: utf-8 -*- import scipy import numpy.fft as FFT import matplotlib.pyplot as plt """ füge aus schallwerkzeuge ein, um schallwerkzeuge datei redundant zu machen DAUER = RATE = ANZAHL = """ execfile("schallwerkzeuge.py") """ Short-Time Fourier Transform """ def stft(x, fs, framesz, hop): x=np.concatenate((x,np.zeros(1))) halfwindow = int(np.round(framesz*fs/2)) framesamp=2*halfwindow+1 hopsamp = int(np.round(hop*fs)) w = scipy.hamming(framesamp) X = scipy.array([scipy.fft(w*x[i-halfwindow:i+halfwindow+1]) for i in range(halfwindow, len(x)-halfwindow, hopsamp)]) return X """ berechne Spektrum """ def spect(): global DAUER global RATE global ANZAHL fensterdauer=0.1 fensterueberlappung=0.05 # jeweils in Sekunden sig=wavread("i.wav") # füge hier array aus audiostream ein A=stft(sig,RATE,fensterdauer,fensterueberlappung) eps=1e-8 # Offset, um logarithmieren zu koennen r,s=A.shape yl=scipy.linspace(0,DAUER, r) xl=scipy.linspace(0,RATE/2,s/2) X,Y=scipy.meshgrid(xl,yl) plt.figure(1) plt.pcolor(Y,X,np.log10(np.absolute(A[:,:s/2]+eps))) plt.show()
To Do: Zeige nur Spektrum bis 4000Hz (oder so) an, zur Geräuschunterdrückung (mit Slicing)
# -*- coding: utf8 -*- from __future__ import division import pyaudio import numpy as np import numpy.fft as FFT import matplotlib.pyplot as plt import scipy """ globale Variablen """ CHUNKSIZE = 1024 # CHANNELS = 1 # RATE = 44100 # DAUER = 5 # Dauer, wie lange aufgenommen wird """ empfange Audiosignale und schreibe sie in ein Numpy-Array """ def getAudio(): # Audioeingang initialisieren p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNKSIZE) # Daten schreiben frames = [] # Liste von Chunks(Blöcken) for i in range(0, int(RATE / CHUNKSIZE*DAUER)): data = stream.read(CHUNKSIZE) frames.append(np.fromstring(data, dtype=np.int16)) # evtl nur normal int? Datengröße müssen wir wohl später abschätzen was sinnvoll ist # Liste der numpy-arrays in 1D-array konvertieren numpydata = np.hstack(frames) # Daten plotten plt.plot(numpydata) plt.show() # Stream schließen stream.stop_stream() stream.close() p.terminate return numpydata """ Short-Time Fourier Transform """ def stft(x, fs, framesz, hop): print x.shape x=np.concatenate((x,np.zeros(1))) halfwindow = int(np.round(framesz*fs/2)) framesamp=2*halfwindow+1 hopsamp = int(np.round(hop*fs)) w = scipy.hamming(framesamp) X = scipy.array([scipy.fft(w*x[i-halfwindow:i+halfwindow+1]) for i in range(halfwindow, len(x)-halfwindow, hopsamp)]) #print X.shape return X """ berechne Spektrum """ def spect(): fensterdauer=0.1 fensterueberlappung=0.025 # jeweils in Sekunden sig = getAudio() # Daten aus Audiostream A=stft(sig,RATE,fensterdauer,fensterueberlappung) A = A[:,0:800] eps=1e-8 # Offset, um logarithmieren zu koennen r,s=A.shape #print r #print s # Größe des transformierten Arrays yl=scipy.linspace(0,DAUER, r) xl=scipy.linspace(0,4000,s/2) X,Y=scipy.meshgrid(xl,yl) plt.figure(1) plt.pcolormesh(Y,X,np.log10(np.absolute(A[:,:s/2]+eps))) plt.show() return 0 spect() #scipy sig spect
# -*- coding: utf8 -*- from __future__ import division import pyaudio import numpy as np import numpy.fft as FFT import matplotlib.pyplot as plt import scipy """ globale Variablen """ CHUNKSIZE = 1024 # CHANNELS = 1 # RATE = 44100 # DAUER = 5 # Dauer, wie lange aufgenommen wird """ empfange Audiosignale und schreibe sie in ein Numpy-Array """ def getAudio(): # Audioeingang initialisieren p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNKSIZE) # Daten schreiben frames = [] # Liste von Chunks(Blöcken) for i in range(0, int(RATE / CHUNKSIZE*DAUER)): data = stream.read(CHUNKSIZE) frames.append(np.fromstring(data, dtype=np.int16)) # evtl nur normal int? Datengröße müssen wir wohl später abschätzen was sinnvoll ist # Liste der numpy-arrays in 1D-array konvertieren numpydata = np.hstack(frames) ''' # Daten plotten plt.plot(numpydata) plt.show() ''' # Stream schließen stream.stop_stream() stream.close() p.terminate return numpydata """ Short-Time Fourier Transform """ def stft(x, fs, framesz, hop): print x.shape x=np.concatenate((x,np.zeros(1))) halfwindow = int(np.round(framesz*fs/2)) framesamp=2*halfwindow+1 hopsamp = int(np.round(hop*fs)) w = scipy.hamming(framesamp) X = scipy.array([scipy.fft(w*x[i-halfwindow:i+halfwindow+1]) for i in range(halfwindow, len(x)-halfwindow, hopsamp)]) #print X.shape return X """ berechne Spektrum """ def spect(): fensterdauer=0.1 fensterueberlappung=0.025 # jeweils in Sekunden sig = getAudio() # Daten aus Audiostream A=stft(sig,RATE,fensterdauer,fensterueberlappung) A = A[:,0:800] # eps=1e-8 # Offset, um logarithmieren zu koennen r,s=A.shape #print r #print s # Größe des transformierten Arrays yl=scipy.linspace(0,DAUER, r) xl=scipy.linspace(0,4000,s/2) X,Y=scipy.meshgrid(xl,yl) # Größe des Fensters initialisieren plt.switch_backend('QT4Agg') figManager = plt.get_current_fig_manager() figManager.window.showMaximized() # Numpydata (hier als sig) plotten. Also Frequenz über Zeit aus der Funktion GetAudio plt.subplot(2,2,1) plt.plot(sig) # das Spektrosgramm plotten plt.subplot(2,2,2) plt.pcolormesh(Y,X,np.log10(np.absolute(A[:,:s/2]+eps))) plt.show() return 0 spect() #scipy sig spect
# -*- coding: utf8 -*- from __future__ import division import pyaudio import numpy as np import numpy.fft as FFT import matplotlib.pyplot as plt import scipy from scipy import ndimage as ndi from skimage.feature import peak_local_max from skimage import color """ globale Variablen """ CHUNKSIZE = 1024 # CHANNELS = 1 # RATE = 44100 # DAUER = 5 # Dauer, wie lange aufgenommen wird """Quelle abfragen""" def quelle(): inp = raw_input("Welche Daten sollen verwendet werden? 'rec' (Aufnahme), 'd' (aus Datei)") if inp == "rec": numpydata = getAudio() elif inp == "d": numpydata = open_datarray() else: print "Falsche Eingabe" initAnalysis() return numpydata """open data from a file and use it as the numpydata""" def open_datarray(): fname = raw_input("Dateiname zum öffnen: ") numpydata = np.loadtxt(fname) return numpydata """ empfange Audiosignale und schreibe sie in ein Numpy-Array """ def getAudio(): # Audioeingang initialisieren p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNKSIZE) # Daten schreiben frames = [] # Liste von Chunks(Blöcken) for i in range(0, int(RATE / CHUNKSIZE*DAUER)): data = stream.read(CHUNKSIZE) frames.append(np.fromstring(data, dtype=np.int16)) # evtl nur normal int? Datengröße müssen wir wohl später abschätzen was sinnvoll ist # Liste der numpy-arrays in 1D-array konvertieren numpydata = np.hstack(frames) # Stream schließen stream.stop_stream() stream.close() p.terminate return numpydata """ Short-Time Fourier Transformation """ def stft(x, fs, framesz, hop): print x.shape x=np.concatenate((x,np.zeros(1))) halfwindow = int(np.round(framesz*fs/2)) framesamp=2*halfwindow+1 hopsamp = int(np.round(hop*fs)) w = scipy.hamming(framesamp) X = scipy.array([scipy.fft(w*x[i-halfwindow:i+halfwindow+1]) for i in range(halfwindow, len(x)-halfwindow, hopsamp)]) #print X.shape return X """Spektrosgramm erstellen""" def spect(numpydata): fensterdauer=0.1 fensterueberlappung=0.025 # jeweils in Sekunden A=stft(numpydata,RATE,fensterdauer,fensterueberlappung) A = A[:,0:800] eps=1e-8 # Offset, um logarithmieren zu koennen r,s=A.shape return A """Peaks finden""" def localmax(numpydata): data = spect(numpydata) # transponierte Matrix bzgl. Spektogramm r,s = data.shape eps = 1e-8 data = np.log10(np.absolute(data[:,:s/2]+eps)) im = color.rgb2gray(data) return im """alle Plots""" def plot(numpydata, A, im): # Größe des Fensters initialisieren plt.switch_backend('QT4Agg') figManager = plt.get_current_fig_manager() figManager.window.showMaximized() # Numpydata plotten. Also Frequenz über Zeit aus der Funktion GetAudio plt.subplot(2,2,1) plt.plot(numpydata) # Spektrosgramm plotten r,s = A.shape eps = 1e-8 yl=scipy.linspace(0,DAUER, r) xl=scipy.linspace(0,4000,s/2) X,Y=scipy.meshgrid(xl,yl) plt.subplot(2,2,2) plt.pcolormesh(Y,X,np.log10(np.absolute(A[:,:s/2]+eps))) # Peaks plotten image_max = ndi.maximum_filter(im, size=10, mode='constant') coordinates = peak_local_max(im, min_distance=10) plt.subplot(2,2,3) plt.imshow(im, cmap=plt.cm.gray) plt.autoscale(False) plt.plot(coordinates[:, 1], coordinates[:, 0], 'r.') plt.axis('off') plt.title('peak local max (transposed form)') # Plots anzeigen plt.show() """Speicherung abfragen""" def speicher(): sav = raw_input("Soll der Datensatz gespeichert werden? [j]a oder [n]ein?") if sav == "j": data_to_file(numpydata) """speichert den Datensatz nach der Aufnahme in einer Datei, falls gewollt""" def data_to_file(numpydata): fname = raw_input("Dateiname zum speichern: ") np.savetxt(fname, numpydata) """main""" def shazam(): numpydata = quelle() S = spect(numpydata) im = localmax(numpydata) plot(numpydata, S, im) #speicher() shazam()
# -*- coding: utf8 -*- from __future__ import division import pyaudio import numpy as np import numpy.fft as FFT import matplotlib.pyplot as plt import scipy from scipy import ndimage as ndi from skimage.feature import peak_local_max from skimage import color """ globale Variablen """ CHUNKSIZE = 1024 # CHANNELS = 1 # RATE = 44100 # DAUER = 5 # Dauer, wie lange aufgenommen wird """Quelle abfragen""" def quelle(): inp = raw_input("Welche Daten sollen verwendet werden? 'r' (Aufnahme), 'd' (aus Datei): ") if inp == "r": numpydata = getAudio() elif inp == "d": numpydata = open_datarray() else: print "Falsche Eingabe" initAnalysis() return numpydata """open data from a file and use it as the numpydata""" def open_datarray(): fname = raw_input("Dateiname zum öffnen: ") numpydata = np.loadtxt(fname) return numpydata """ empfange Audiosignale und schreibe sie in ein Numpy-Array """ def getAudio(): # Audioeingang initialisieren p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNKSIZE) # Daten schreiben frames = [] # Liste von Chunks(Blöcken) for i in range(0, int(RATE / CHUNKSIZE*DAUER)): data = stream.read(CHUNKSIZE) frames.append(np.fromstring(data, dtype=np.int16)) # evtl nur normal int? Datengröße müssen wir wohl später abschätzen was sinnvoll ist # Liste der numpy-arrays in 1D-array konvertieren numpydata = np.hstack(frames) # Stream schließen stream.stop_stream() stream.close() p.terminate return numpydata """ Short-Time Fourier Transformation """ def stft(x, fs, framesz, hop): print x.shape x=np.concatenate((x,np.zeros(1))) halfwindow = int(np.round(framesz*fs/2)) framesamp=2*halfwindow+1 hopsamp = int(np.round(hop*fs)) w = scipy.hamming(framesamp) X = scipy.array([scipy.fft(w*x[i-halfwindow:i+halfwindow+1]) for i in range(halfwindow, len(x)-halfwindow, hopsamp)]) #print X.shape return X """Spektrosgramm erstellen""" def spect(numpydata): fensterdauer=0.1 fensterueberlappung=0.025 # jeweils in Sekunden A=stft(numpydata,RATE,fensterdauer,fensterueberlappung) A = A[:,0:800] eps=1e-8 # Offset, um logarithmieren zu koennen r,s=A.shape return A """Peaks finden bzw. Bild einlesen""" def im_conversion(numpydata): data = spect(numpydata) # transponierte Matrix bzgl. Spektogramm r,s = data.shape eps = 1e-8 data = np.log10(np.absolute(data[:,:s/2]+eps)) im = color.rgb2gray(data) return im def fpeaks(im): peaks = peak_local_max(im, min_distance=9) # min_distance bestimmt Anzahl der Peaks peaks = zip(peaks[:,0], peaks[:,1]) return peaks """alle Plots""" def plot(numpydata, A, im, peaks): # Größe des Fensters initialisieren """plt.switch_backend('QT4Agg') figManager = plt.get_current_fig_manager() figManager.window.showMaximized()""" # Numpydata plotten. Also Frequenz über Zeit aus der Funktion GetAudio plt.subplot(2,2,1) plt.plot(numpydata) plt.title("Eingangssignal") # Spektrosgramm plotten r,s = A.shape eps = 1e-8 yl=scipy.linspace(0,DAUER, r) xl=scipy.linspace(0,4000,s/2) X,Y=scipy.meshgrid(xl,yl) plt.subplot(2,2,2) plt.pcolormesh(Y,X,np.log10(np.absolute(A[:,:s/2]+eps))) plt.title("Spektrogramm") # Peaks plotten xval= [x[1] for x in peaks] yval= [x[0] for x in peaks] plt.subplot(2,2,3) plt.imshow(im, cmap=plt.cm.gray) plt.autoscale(False) plt.plot(xval,yval,'r.') plt.axis('on') plt.title('Lokale Peaks (transponiert!)') # Plots anzeigen plt.show() """Speicherung abfragen""" def speicher(): sav = raw_input("Soll der Datensatz gespeichert werden? [j]a oder [n]ein?") if sav == "j": data_to_file(numpydata) """speichert den Datensatz nach der Aufnahme in einer Datei, falls gewollt""" def data_to_file(numpydata): fname = raw_input("Dateiname zum speichern: ") np.savetxt(fname, numpydata) """main""" def shazam(): numpydata = quelle() S = spect(numpydata) im = im_conversion(numpydata) peaks = fpeaks(im) plot(numpydata, S, im, peaks) #speicher() shazam()
# -*- coding: utf8 -*- from __future__ import division import pyaudio import numpy as np import numpy.fft as FFT import matplotlib.pyplot as plt import scipy from scipy import ndimage as ndi from skimage.feature import peak_local_max from skimage import color import hashlib import cPickle as pickle """ globale Variablen """ CHUNKSIZE = 1024 # CHANNELS = 1 # RATE = 44100 # DAUER = 5 # Dauer, wie lange aufgenommen wird FINGERPRINT_CUT = 20 # bestimmt wie lang fingerprint maximal ist PAIR_VAL = 15 # bestimmt zu welchem Grad ein Peak mit benachbartem Peak für einen fingerprint gepaart werden kann # je höher, desto mehr fingerprints MIN_HASH_TIME_DELTA = 0 MAX_HASH_TIME_DELTA = 50 # min und max zeit der zwischen zwei peaks liegen darf, damit sie für fingerprint gepairt werden """Quelle abfragen""" def quelle(): inp = raw_input("Welche Daten sollen verwendet werden? 'r' (Aufnahme), 'd' (aus Datei): ") if inp == "r": numpydata = getAudio() elif inp == "d": numpydata = open_datarray() else: print "Falsche Eingabe" initAnalysis() return numpydata """open data from a file and use it as the numpydata""" def open_datarray(): fname = raw_input("Dateiname zum öffnen: ") numpydata = np.loadtxt(fname) return numpydata """ empfange Audiosignale und schreibe sie in ein Numpy-Array """ def getAudio(): # Audioeingang initialisieren p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNKSIZE) # Daten schreiben frames = [] # Liste von Chunks(Blöcken) for i in range(0, int(RATE / CHUNKSIZE*DAUER)): data = stream.read(CHUNKSIZE) frames.append(np.fromstring(data, dtype=np.int16)) # evtl nur normal int? Datengröße müssen wir wohl später abschätzen was sinnvoll ist # Liste der numpy-arrays in 1D-array konvertieren numpydata = np.hstack(frames) # Stream schließen stream.stop_stream() stream.close() p.terminate return numpydata """ Short-Time Fourier Transformation """ def stft(x, fs, framesz, hop): x=np.concatenate((x,np.zeros(1))) halfwindow = int(np.round(framesz*fs/2)) framesamp=2*halfwindow+1 hopsamp = int(np.round(hop*fs)) w = scipy.hamming(framesamp) X = scipy.array([scipy.fft(w*x[i-halfwindow:i+halfwindow+1]) for i in range(halfwindow, len(x)-halfwindow, hopsamp)]) return X """Spektrogramm erstellen""" def spect(numpydata): fensterdauer=0.1 fensterueberlappung=0.025 # jeweils in Sekunden A=stft(numpydata,RATE,fensterdauer,fensterueberlappung) A = A[:,0:800] eps=1e-8 # Offset, um logarithmieren zu koennen r,s=A.shape return A """Spektrogramm als Bild einlesen""" def im_conversion(numpydata): data = spect(numpydata) # transponierte Matrix bzgl. Spektogramm r,s = data.shape eps = 1e-8 data = np.log10(np.absolute(data[:,:s/2]+eps)) im = color.rgb2gray(data) return im """ finde lokale Maxima im Bild """ def fpeaks(im): peaks = peak_local_max(im, min_distance=9) # min_distance bestimmt Anzahl der Peaks peaks = zip(peaks[:,0], peaks[:,1]) return peaks """ erstelle fingerprint hashes """ def fingerprint(peaks): # peaks tupel sind schon bzgl. zeit sortiert fingerprint_list = [] for i in range(len(peaks)): for j in range(1, PAIR_VAL): if (i+j < len(peaks)): freq1 = peaks[i][1] # nimmt 2. wert, heißt die frequenz, des zeit/freq tupels (stelle 1) freq2 = peaks[i+j][1] # zweiter peak time1 = peaks[i][0] # nimmt 1. wert, heißt die zeit, des zeit/freq tupels (stelle 0) time2 = peaks[i+j][0] # zeit des zweiten peaks delta_time = time2 - time1 # zeitliche differenz zwischen den peaks if (delta_time >= MIN_HASH_TIME_DELTA and delta_time <= MAX_HASH_TIME_DELTA): h = hashlib.sha1("%s|%s|%s" % (str(freq1), str(freq2), str(delta_time))) fingerprint_list.append((h.hexdigest()[0:FINGERPRINT_CUT], time1)) return fingerprint_list """alle Plots""" def plot(numpydata, A, im, peaks): # Vollbild initialisieren """plt.switch_backend('QT4Agg') figManager = plt.get_current_fig_manager() figManager.window.showMaximized()""" # Numpydata plotten. Also Frequenz über Zeit aus der Funktion GetAudio plt.subplot(2,2,1) plt.plot(numpydata) plt.title("Eingangssignal") # Spektrosgramm plotten r,s = A.shape eps = 1e-8 yl=scipy.linspace(0,DAUER, r) xl=scipy.linspace(0,4000,s/2) X,Y=scipy.meshgrid(xl,yl) plt.subplot(2,2,2) plt.pcolormesh(Y,X,np.log10(np.absolute(A[:,:s/2]+eps))) plt.title("Spektrogramm") # Peaks plotten xval= [x[1] for x in peaks] yval= [x[0] for x in peaks] plt.subplot(2,2,3) plt.imshow(im, cmap=plt.cm.gray) plt.autoscale(False) plt.plot(xval,yval,'r.') plt.axis('on') plt.title('Lokale Peaks (transponiert!)') # Plots anzeigen plt.show() """Speicherung für Eingangssignal""" def sav_sig(numpydata): sav = raw_input("Soll das Eingangssignal gespeichert werden? [j]a oder [n]ein?") if sav == "j": fname = raw_input("Dateiname zum speichern: ") np.savetxt(fname, numpydata) """Aktion für Fingerprint wählen""" def act_fingprt(fingerprints): sav = raw_input("Soll der Fingerprint gespeichert [s] und/ oder verglichen [c] werden? [sc] für beides: ") if sav == "s": sav_fingprt(fingerprints) if sav == "c": comp_fingprt() if sav == "sc": sav_fingprt(figerprints) comp_fingprt() """Speicherung für Fingerprint""" def sav_fingprt(fingerprints): fname = raw_input("Dateiname zum speichern: ") with open(fname,"w") as f: pickle.dump(fingerprints, f) """Vergleich mit Fingerprint aus Datenbank""" def comp_fingprt(): fname = raw_input("Dateiname zum öffnen: ") with open(fname,"r") as f: fingprt_datenbank = pickle.load(f) print fingprt_datenbank """main""" def shazam(): numpydata = quelle() S = spect(numpydata) im = im_conversion(numpydata) peaks = fpeaks(im) fingerprints = fingerprint(peaks) print fingerprints plot(numpydata, S, im, peaks) #sav_sig(numpydata) act_fingprt(fingerprints) shazam()
die Aufnahme (5 Sekunden) wird in fingerprints umgewandelt. Wie bereits oben erwähnt, sind diese in Form von Hashes gespeichert, also Datenpaketen, die einen charakteristischen Punkt und seinen Zeitpunkt im Lied beinhalten. Diese Datenpakete existieren ebenfalls in größerer Anzahl für die Lieder in der Datenbank. Daher werden die Datenpakete der Aufnahme wie ein Fenster über die Datenpakete der Lieder in der Datenbank geschoben und suchen dabei gleiche Datenpakete. Dies geschieht in dem Übereinstimmung von charakteristischen Punkten geprüft wird. Ist dies der Fall, wird die Differenz der beiden Zeitpunkte (Aufnahme und Datenbank) gebildet. Dies muss getan werden, weil die Zeitpunkte in Form von Ganzen Zahlen gespeichert werden. Läuft das Lied um einen Bruchteil einer Sekunde weiter, erhöht sich die Zahl, angefangen bei 1. Wenn man die Differenz nicht bildet, könnte die Aufnahme also nur mit dem Anfang des Liedes übereinstimmen. Um dem entgegenzuwirken, bildet man also die Differenz der Zeitpunkte. Diese sollte konstant sein, da die charakteristika ja in gleichem Abstand zueinander stehen sollten (bei gleicher BpM-Zahl). Dies ist jedoch nicht ganz eindeutig, kleine Abweichungen können dabei leicht auftreten. Dementsprechend werden die Übereinstimmungen der charakteristischen Punkte gezählt und die Standardabweichung für die zeitlichen Differenzen gebildet. Für die ch. P. wird ein Mindestwert festgelegt und für die Standardabweichung ein Maximalwert. Werden diese eingehalten, ist es ein „Match“, die Lieder stimmen überein, ansonsten eben kein Match.
# -*- coding: utf8 -*- from __future__ import division import pyaudio import numpy as np import numpy.fft as FFT import matplotlib.pyplot as plt import scipy from scipy import ndimage as ndi from scipy.io import wavfile from skimage.feature import peak_local_max from skimage import color import hashlib import cPickle as pickle """ Zur Vorbereitung sollten alle Titel in WAV-Format, eine Textdatei "einlesen.txt" und das Programm Arktische Affen.py in einen Ordner gelegt werden. In der Main namens "action" wird zunächst abgefragt, ob in die Datenbank eingelesen werden soll, oder mit der Datenbank verglichen. Das Einlesen erfolgt über die Datei "einlesen". Dort werden die Namen aller einzulesenen Titel ohne die .wav-Endung (die wird automatisch vom Programm Arktische Affen angehangen) zeilenweise geschrieben. Die Funktion "read" greift anhand der Titelnamen dann nacheinander auf die WAV-Dateien zu und erstellt jeweils einen fingerprint für den Titel. Dieser wird mit dem Titelnamen und der Endung ".txt" in eine Textdatei innerhalb des Ordners gespeichert. Anschließend wird der Titelname zusätzlich ohne Endung (ähnlich wie bei der Datei "einlesen", das erleichtert das Programmieren) in eine Textdatei geschrieben, bzw. angehängt. Diese heißt "Datenbank" und beinhaltet zeilenweise alle eingelesenen Titel, um sie später beim Vergleich abrufen zu können. Wie bereits erwähnt, stehen in der Datei "Datenbank" nur Titelnamen. Diese ermöglichen lediglich den Zugriff auf die gleichnamigen Textdateien, in denen die fingerprints gespeichert sind, so wie die Datei "einlesen" nur die Titelnamen beinhaltet und damit auf die WAV-Dateien zugreift. Der Vergleich kann über zwei Quellen erfolgen. Entweder es wird eine bereits früher getätigte und gespeicherte Aufnahme als Quelle genommen, oder es wird anschließend für 5 Sekunden mit dem Mikrofon aufgenommen (dies passiert, sobald die Meldungen "Jack Server is not running" etc. erscheinen). Letztere Variante ermöglicht das Abgleichen mit zB der Ausgabe eines Handys etc., was dadurch ganz hübsch ist, dass man direktes Feedback bekommt. Wenn eine Aufnahme besonders gelungen ist, kann sie abgespeichert werden. Dazu muss dann die Option gewählt werden und ein Dateiname ohne Endung (auch die wird vom Programm eingefügt) eingegeben werden. Die erste Variante eignet sich zum Testen sehr gut. Wenn eine Aufnahme gespeichert wurde, kann diese ganz leicht wieder aufgerufen werden. Dabei muss der Name der abgespeicherten Datei anschließend angegeben werden. Sobald die Quelle entschieden ist und die Plots (dienen der Veranschaulichung) geschlossen wurden, erstellt das Programm aus der angegebenen Audio-Quelle ebenfalls einen fingerprint und vergleicht diesen mit denen aus der Datenbank. Bei genügender Übereinstimmung gibt das Programm die entsprechenden Titelnamen aus, im Normal-/Idealfall nur einen! """ """ globale Variablen """ CHUNKSIZE = 1024 # CHANNELS = 1 # RATE = 44100 # DAUER = 5 # Dauer, wie lange aufgenommen wird ANZAHL = 0 # Anzahl frames FINGERPRINT_CUT = 20 # bestimmt wie lang fingerprint maximal ist PAIR_VAL = 15 # bestimmt zu welchem Grad ein Peak mit benachbartem Peak für einen fingerprint gepaart werden kann # je höher, desto mehr fingerprints MIN_HASH_TIME_DELTA = 0 MAX_HASH_TIME_DELTA = 50 # min und max zeit die zwischen zwei peaks liegen darf, damit sie für fingerprint gepairt werden """Einlesen oder Vergleichen abfragen""" def action(): act = raw_input("Soll in die Datenbank eingelesen [u] oder mit der Datenbank verglichen [c] werden? ") if act == "u": read() if act == "c": compare() """Liest ein wav-File in ein numpy-Array""" def wavread(filename): global ANZAHL global RATE global DAUER RATE,y = wavfile.read(filename) # in y ist die Anzahl der Frames und bei mehreren Channels die Anzahl der Channels gespeichert ANZAHL = y.shape[0] if len(y.shape)==2: y = y.astype(float) yKonf = y.sum(axis=1) / 2 else: yKonf = y DAUER=ANZAHL/RATE return np.array(yKonf,dtype=np.float)/2**15 """Quelle abfragen""" def quelle(): inp = raw_input("Welche Daten sollen verwendet werden? 'r' (Aufnahme), 'd' (aus Datei): ") if inp == "r": numpydata = getAudio() elif inp == "d": numpydata = open_datarray() else: print "Falsche Eingabe" initAnalysis() return numpydata """open data from a file and use it as the numpydata""" def open_datarray(): fname = raw_input("Dateiname zum öffnen: ") numpydata = np.loadtxt(fname) return numpydata """ empfange Audiosignale und schreibe sie in ein Numpy-Array """ def getAudio(): # Audioeingang initialisieren p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNKSIZE) # Daten schreiben frames = [] # Liste von Chunks(Blöcken) for i in range(0, int(RATE / CHUNKSIZE*DAUER)): data = stream.read(CHUNKSIZE) frames.append(np.fromstring(data, dtype=np.int16)) # evtl nur normal int? Datengröße müssen wir wohl später abschätzen was sinnvoll ist # Liste der numpy-arrays in 1D-array konvertieren numpydata = np.hstack(frames) # Stream schließen stream.stop_stream() stream.close() p.terminate return numpydata """Spektrogramm erstellen""" #""" def spect(numpydata): fensterdauer=0.1 fensterueberlappung=0.025 # jeweils in Sekunden A=stft(numpydata,RATE,fensterdauer,fensterueberlappung) A = A[:,0:800] eps=1e-8 # Offset, um logarithmieren zu koennen r,s=A.shape return A #""" """ Short-Time Fourier Transformation """ #bisherige Funktion def stft(x, fs, framesz, hop): x=np.concatenate((x,np.zeros(1))) halfwindow = int(np.round(framesz*fs/2)) framesamp=2*halfwindow+1 hopsamp = int(np.round(hop*fs)) w = scipy.hamming(framesamp) X = scipy.array([scipy.fft(w*x[i-halfwindow:i+halfwindow+1]) for i in range(halfwindow, len(x)-halfwindow, hopsamp)]) return X #schnellere Funktion, hanning statt hamming, framesamp geändert """ def stft(x, fs, framesz, hop): x=np.concatenate((x,np.zeros(1))) halfwindow = int(np.round(framesz*fs/2)) framesamp=2*halfwindow hopsamp = int(np.round(hop*fs)) w = scipy.hanning(framesamp) X = scipy.array([scipy.fft(w*x[i-halfwindow:i+halfwindow]) for i in range(halfwindow, len(x)-halfwindow, hopsamp)]) print X.shape return X[:,0:800] """ """Spektrogramm als Bild einlesen""" def im_conversion(data): r,s = data.shape eps = 1e-8 data = np.log10(np.absolute(data[:,:s/2]+eps)) im = color.rgb2gray(data) return im """ finde lokale Maxima im Bild """ def fpeaks(im): peaks = peak_local_max(im, min_distance=9) # min_distance bestimmt Anzahl der Peaks peaks = zip(peaks[:,0], peaks[:,1]) #print len(peaks) return peaks """ erstelle fingerprint hashes """ def fingerprint(peaks): # peaks tupel sind schon bzgl. zeit sortiert fingerprint_list = [] for i in range(len(peaks)): for j in range(1, PAIR_VAL): if (i+j < len(peaks)): freq1 = peaks[i][1] # nimmt 2. wert, heißt die frequenz, des zeit/freq tupels (stelle 1) freq2 = peaks[i+j][1] # zweiter peak time1 = peaks[i][0] # nimmt 1. wert, heißt die zeit, des zeit/freq tupels (stelle 0) time2 = peaks[i+j][0] # zeit des zweiten peaks delta_time = time2 - time1 # zeitliche differenz zwischen den peaks if (delta_time >= MIN_HASH_TIME_DELTA and delta_time <= MAX_HASH_TIME_DELTA): h = hashlib.sha1("%s|%s|%s" % (str(freq1), str(freq2), str(delta_time))) fingerprint_list.append((h.hexdigest()[0:FINGERPRINT_CUT], time1)) return fingerprint_list """alle Plots""" def plot(numpydata, A, im, peaks): # Vollbild initialisieren """plt.switch_backend('QT4Agg') figManager = plt.get_current_fig_manager() figManager.window.showMaximized()""" # Numpydata plotten. Also Frequenz über Zeit aus der Funktion GetAudio plt.subplot(2,2,1) plt.plot(numpydata) plt.title("Eingangssignal") # Spektrosgramm plotten r,s = A.shape eps = 1e-8 yl=scipy.linspace(0,DAUER, r) xl=scipy.linspace(0,4000,s/2) X,Y=scipy.meshgrid(xl,yl) plt.subplot(2,2,2) plt.pcolormesh(Y,X,np.log10(np.absolute(A[:,:s/2]+eps))) plt.title("Spektrogramm") # Peaks plotten xval= [x[1] for x in peaks] yval= [x[0] for x in peaks] plt.subplot(2,2,3) plt.imshow(im, cmap=plt.cm.gray) plt.autoscale(False) plt.plot(xval,yval,'r.') plt.axis('on') plt.title('Lokale Peaks (transponiert!)') # Plots anzeigen plt.show() """Speicherung für Eingangssignal""" def sav_sig(numpydata): sav = raw_input("Soll das Eingangssignal gespeichert werden? [j]a oder [n]ein?") if sav == "j": fname = raw_input("Dateiname zum speichern: ") np.savetxt(fname, numpydata) """Vergleich mit Fingerprint aus Datenbank""" def comp_fingprt(fpaktuell): with open("Datenbank.txt","r") as db: # Datenbank ist ein Text-File mit allen Dateinamen, mit denen verglichen werden soll for fname in db: fname = fname.rstrip("\n") # mit der append-Funktion wird beim einlesen ein newline an den Dateinamen angehängt with open("%s.txt" % fname,"r") as f: # das newline Zeichen muss hier gestrichen werden fpdatenbank = pickle.load(f) """ check if fingprt_aktuell is in fingprt_datenbank """ matches = [] differences = [] for hash_a, time_a in fpaktuell: for hash_d, time_d in fpdatenbank: if hash_a == hash_d: matches.append((hash_a,time_a,time_d)) tdiff = time_d - time_a differences.append(tdiff) variance = np.var(differences) if len(matches) > 250 and variance < 10000000: # durch verändern der Werte wird Toleranz bestimmt print fname # len(matches) = Anz. der Übereinstimmungen, Varianz = Index für Zeitfehler """main für Vergleich""" def compare(): numpydata = quelle() S = spect(numpydata) im = im_conversion(S) peaks = fpeaks(im) fingerprints = fingerprint(peaks) with open("fingerprint_aktuell.txt","w") as f: pickle.dump(fingerprints, f) plot(numpydata, S, im, peaks) sav_sig(numpydata) comp_fingprt(fingerprints) """main für Einlesen""" def read(): with open("einlesen.txt","r") as el: # in die Datei "einlesen" werden alle Songs zum einlesen mit titelnamen geschrieben for filename in el: filename = filename.rstrip("\n") numpydata = wavread("%s.wav" % filename) S = spect(numpydata) im = im_conversion(S) peaks = fpeaks(im) fingerprints = fingerprint(peaks) with open("%s.txt" % filename,"w") as f: pickle.dump(fingerprints, f) with open("Datenbank.txt", "a") as f: # append hängt den Namen des eingelesen Files an die Datenbank an f.write("%s\n" % filename) #plot(numpydata, S, im, peaks) action()