====== Audio ====== ===== Töne selbst erzeugen ===== Bei uns ging es zunächst darum Töne zu erzeugen, was hauptsächlich über die Erzeugung von Sinuskurven mit verschiedenen Frequenzen und Amplituden realisierbar ist. ==== Eigene Variante ==== Eine Sinuskurve allgemein mit variabler Frequenz und Amplitude zu erzeugen ist mit dem Modul Numpy relativ einfach. def erzeuge_sinus(f,T): global RATE yy=np.zeros(int(T*RATE)) for i in range(0,len(yy)): yy[i]=np.sin(2*np.pi*f*i/float(RATE)) return yy Mit diesem Code kann man einzelne Sinuskurven generieren. Ebenso kann man die Sinuskurve durch verschiedene periodische Funktionen begrenzen, wodurch sich die Töne ebenfalls modellieren lassen. Als Beispiel haben wir eine Dreiecksperiode: def erzeuge_dreieckhk(T0,T1,T=2.): global RATE yy=np.zeros(int(T*RATE)) for i in range(0,len(yy)): t=i/float(RATE) if 0<=t<=T0: yy[i]=t/float(T0) elif T0 ==== Mit Stefans Hilfe ==== Da wir allerdings mehrere Sinuskurven mit unterschiedlichen Frequenzen und Amplituden aneinanderreihen wollten, mussten wir uns Gedanken machen, wie wir das Umsetzen. Da dies und das erstellen eines Interface über unseren Fähigkeiten lag, hat Stefan uns bei der Lösung dieser Probleme ausgeholfen. Hierbei entstand folgender krasser Code: #### Sinusgenerator-Klasse class sinus_generator(generator): '''Sinus-Tongenerator''' def __init__(self,freq=440): self.freq=freq self.phaseshift=0.0 def generate(self,T): '''Erzeugt einen Sinusklang der Dauer T. Damit Stücke ohne Knacksen verbunden werden, können, merkt sich die Funktion die Phasenverschiebung am Ende des letzten Stücks''' yy=np.fromfunction(lambda i: i, (int(T*RATE),),dtype=int)*2*np.pi*self.freq/RATE\ +self.phaseshift*np.ones(int(T*RATE)) yy=np.sin(yy) self.phaseshift+=T*2*np.pi*self.freq return yy.copy() class fm_generator(generator): '''FM-Generator''' def __init__(self,freq1=440, freq2=110, I=3.): self.freq1=freq1 self.freq2=freq2 self.I=I self.T=0.0 def generate(self,T): '''Erzeugt ein FM-Synthese der Dauer T. Damit Stücke ohne Knacksen verbunden werden, können, merkt sich Zeit am Ende des letzten Stücks''' y1=np.fromfunction(lambda i: i, (int(T*RATE),),dtype=int) y2=np.sin(y1*2*np.pi*self.freq1/RATE\ +self.T*2*np.pi*self.freq1*np.ones(int(T*RATE))) yy=np.sin(y1*2*np.pi*self.freq2/RATE\ +self.T*2*np.pi*self.freq2*np.ones(int(T*RATE)) +self.I*y2) self.T+=T return yy.copy() #### Der 'große Generator', der aus Verknüpfung von anderen besteht: class klang1(generator): def __init__(self): self.gen=[] self.vol=[] # Alle Generatoren und zugehörigen Volumina in die Liste # einfügen. Durch entsprechende Gewichte und Frequenzen -- Fourier! -- # kannn man Tongeneratoren ganz verschiedener Charakteristiken # erzeugen. self.gen.append(sinus_generator(440)) self.gen.append(sinus_generator(1.5*440)) self.vol.append(0.2) self.vol.append(0.2) frq0=440*1.5 for i in range(15): frq0=frq0*(i+4)/(i+3) self.gen.append(sinus_generator(frq0)) #self.vol.append(1/(i+2)**2) self.vol.append(1/i) ===== Fourier Transformation ===== Mit der Fourier Transformation lassen sich unter anderem bereits existente Töne analysieren und in Daten umwandeln, sodass man sie modellieren kann. ==== Diskret ==== Zunächst haben wir probiert selbst einen Code für die Diskrete Fourier Transformation zu implementieren. Dieser sieht folgendermaßen aus: ==== Fast ==== Da wir hier leider auf Speicher Probleme stießen, mussten wir doch auf den in Numpy vorhandenen Fast-Fourier-Transformation Code zurückgreifen: