Dies ist eine alte Version des Dokuments!
Die Datei schallwerkzeuge.py
stammt aus der digitalen Feder von Stefan Born und ist, wie der Name schon vermuten lässt, eine Sammlung von allerlei nützlichen Werkzeugen um mit pyaudio
Schall zu erzeugen und zu verarbeiten. Wir haben diese Funktionen vielfach in unserem Projekt benutzt und willen hier die einzelnen Komponenten beschreiben.
In der Präambel werden einige Module importiert und globale Variablen gesetzt.
#!/usr/bin/python # coding=utf8 ## Verhalten von / wie in Python 3 a/b = float from __future__ import division ### Audio-Module import pyaudio from scipy.io import wavfile from scipy import signal ### Fourier, Numerik import numpy.fft as FFT import numpy as np ############## # Graphik import matplotlib.pyplot as plt ### CHANNELS=1 RATE=44100 DAUER=1 ANZAHL=DAUER*RATE # ANZAHL der Frames, CHUNK=2**10 # Anzahl der Frames, die auf einmal an die Soundkarte # geschickt werden # globale Variablen, schlechter Programmierstil, hier aber ganz # praktisch: Nach Aufnahme oder Lesen werden diese Variablen # entsprechend gesetzt.
Die Funktion recordsnd
dient zur Aufnahme von akustischen Signalen über das Mikrofon.
def recordsnd(filename, time): ''' Nimmt eine time Sekunden lange Schallsequenz auf (mit der Samplerate 48000 Hz) auf und speichert, speichert sie in der Datei filename und gibt die Aufnahme als numpy-array mit Werten zwischen -1 und 1 zurück ''' global ANZAHL global RATE global DAUER global CHANNELS DAUER=time ANZAHL=int(RATE*DAUER) p = pyaudio.PyAudio() raw_input("Aufnehmen "+str(time)+ " Sekunden): Eingabetaste drücken...") stream = p.open(format =pyaudio.paInt16 , channels = CHANNELS, rate = RATE, input = True, frames_per_buffer = CHUNK)#ANZAHL) yy=stream.read(ANZAHL) y=np.fromstring(yy,dtype=np.short) if CHANNELS==2: y=y.reshape((y.shape[0]//2,2)) print("Aufgenomen: " + str(ANZAHL) + " Frames") stream.close() p.terminate() yy=np.array(y,dtype='d')/32768.0 if filename!=None: wavwrite(filename, yy) return yy def wavwrite(filename, y): '''Schreibt ein wav-File aus einem numpy-array''' wavfile.write(filename, RATE, np.array(y*2**15, dtype=int))
Über wavwrite
lassen sich Aufnahmen als wav-Dateien speichern und über wavread
wieder einlesen.
def wavread(filename): '''Liest ein wav-File in ein numpy-Array''' global ANZAHL global RATE global DAUER global CHANNELS RATE,y=wavfile.read(filename) ANZAHL=y.shape[0] if len(y.shape)==2: CHANNELS=y.shape[1] else: CHANNELS=1 DAUER=ANZAHL/RATE return np.array(y,dtype=np.float)/2**15
playsnd
ist für uns eine sehr wichtige Funktion, da sie ermöglicht Arrays mit Audio-Daten über den Lautsprecher abzuspielen.
def playsnd(y, r): ''' spielt das numpy-array (bzw. Vektor) y als Klang mit der Samplerate r [Hz] ab. ''' p = pyaudio.PyAudio() stream = p.open(format =pyaudio.paInt16 , channels = CHANNELS, rate = r, output = True, frames_per_buffer=CHUNK)#ANZAHL) yy=np.array(y.flatten()*2**15,dtype=np.short) for i in range(0,len(yy),CHANNELS*CHUNK): stream.write(yy[i:i+CHANNELS*CHUNK].tostring(order='F')) stream.close() p.terminate()
Über inspectsnd
lassen sich Aufnahmen als Graph visualisieren, inspectspec
stellt dagegen das Frequenz-Spektrum der Aufnahme durch die Diskrete Fourier-Transformation dar.
def inspectsnd(y): '''Zeigt einen Plot von y''' n=y.shape[0] fig=plt.Figure(figsize=(6,4),dpi=100) ax=fig.add_subplot(111) x=np.arange(0,n,1)/np.float32(RATE) plt.plot(x,y) plt.show() def inspectspec(y): '''zeigt einen Plot des DFT-Spektrums von y''' global RATE # Vorbereitungen, um ein Fenster zum Plotten zu kriegen plt.figure(1) n=len(y) window=np.blackman(n) sumw=sum(window*window) A=FFT.fft(y*window) B2=(A*np.conjugate(A)).real sumw*=2.0 sumw/=1/np.float(RATE) # sample rate B2=B2/sumw x=np.arange(0,n/2,1)/np.float(n)*RATE eps=1e-8 plt.plot(x, np.log10(B2[0:n/2]+eps)) plt.show()
Auch sinewave
ist wichtig zur Schallerzeugung, da die Methode ein Sinus-Signal mit der gewünschten Frequenz liefert, welches dann wiedergegeben werden kann.
def sinewave(f,r,d): '''erzeugt die Daten einer Sinusschwingung mit Frequenz f, Dauer d und Samplerate r''' global RATE global DAUER global ANZAHL RATE=r DAUER=d ANZAHL=DAUER*RATE y=np.zeros(int(r*d)) for i in range(0,int(r*d)): y[i]=np.sin(2*np.pi*f*i/float(r)) return y