Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

ss16:logbuch

Logbuch

Eintrag 26/05/16

Vorläufige Definition der Meilensteine:

  1. Eingangssignal aufnehmen und Datensatz erstellen
  2. Verarbeitung des Datensatzes mit Hilfe von Fourier-Analysis
  3. Abgleich der verarbeiteten Daten mit einer Datenbank (ggf. eigene Erstellung oder Verwendung von Beispieldaten )
  4. Ausgabe

Erweiterung der Erweiterungen:

  • Nachträgliche Evaluation des Nutzers, ob Musik-Erkennung erfolgreich war (+ crappy yay animation?)
  • Reflektion des Programms für eigene Fehlerkorrektur
  • machine learning - Genauigkeit und Trefferquote verbessern, Störgeräusche filtern
  • … tbc

Eintrag 02/06/2016

  • Nachvollziehen Audiobeispiel pdf-Datei
  • Fourier-Fingerabdruck verstehen, evtl. erstellen
  • Aufgabenverteilung bis nächste Woche: B: Aufnahme von Sound & Speichern in Array N: FFT evtl. Fingerprint

Eintrag 09/06/2016

  • Programm für Fourieranalyse und anschließendem Spektrogramm funktioniert
  • Programm zum Einlesen von Audio in Echtzeit über das Mikrofon des Laptops funktioniert, die Dateien werden in ein Array geschrieben und können so für die Fourieranalyse genutzt werden

Einlesen von Audio-Dateien

# -*- 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

Datenverarbeitung mittels Short-Time Fourier Transform

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)

Eintrag 16/06/2016

  • Zusammenführen der beiden Programme und Beginn der Optimierung: statt dem Frequenzbereich von ca 22.000 Hz wollen wir auf 4000 Hz reduzieren
  • das Programm ist auf das wesentlichste reduziert und zeigt nach der Aufnahmezeit sehr schnell das Spektogramm

Zusammenfassung: Echtzeit-Aufnahme und Umwandlung in Spektogramm

# -*- 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

Eintrag 23/06/2016

  • Fingerprinting: Bilddatenverarbeitung um Peaks zu finden funktioniert angewendet auf unser Programm noch nicht
  • Grafikarbeiten, anschaulichere Plots
# -*- 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

Eintrag 30/06/2016

  • Fingerprinting: Peaks werden gefunden
  • Funktionsmanagement: Peak-Funktion und bisheriges Programm zusammengeführt, eigene Funktion für Plots
  • Erweiterung auf verschiedene Quellen: entweder Echtzeit-Aufnahme oder bereits erstellte Dateien
# -*- 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()

Eintrag 07/07/16

  • Auslagern der Funktion, um Peaks zu finden
  • Verstehen des Prinzips der Hash-Funktion
  • Beispielcode von Hash-Fingerprinting angeschaut: https://github.com/worldveil/dejavu/blob/master/dejavu/fingerprint.py
  • Problem erkannt: komische Zeit-Werte im Plot für die lokalen Maxima. Stellte sich letztendlich als kein Problem heraus. Es muss nur umgedacht werden
  • Arbeiten an der Datenbank
# -*- 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()

Eintrag 14/07/2016

  • Funktion für Fingerprints geschrieben
  • Fingerprints werden per Pickle gespeichert und können so zum vergleichen wieder abgerufen werden, d.h. nur Vergleiche zwischen einzelnen Dateien möglich → Optimierungsbedraf
  • jetzt fehlt eigentlich auch nur noch das genannte vergleichen
# -*- 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()

Eintrag 19/09/2016

  • aktuellste Version
  • die Datenbank ist jetzt umgesetzt, die aktuelle Wiedergabe wird mit der gesamten Datenbank verglichen. Dies ist auch im roten Text im Programm erklärt
  • das Vergleichen wurde umgesetzt, dauert aber etwas länger, da die Funktion recht simpel geschrieben ist und die Datenmengen vergleichweise groß
  • das Vergleichen funktioniert folgendermaßen:

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()
ss16/logbuch.txt · Zuletzt geändert: 2016/09/30 11:43 von zoppl