Workshop Harmonielehre: Obertonreihen für alternative Universen (Teil 1)
Hallo AMAZONA! Ich bin MatthiasH und bereits seit Ewigkeiten Leser dieser Plattform. Im Hauptberuf arbeite ich in der Forschung (Informatik/Computergrafik), nachts bin ich eher Musiker. Den Dämmerstunden dazwischen entstammt gewissermaßen die Arbeit, über die ich euch hier berichten möchte.
Inhaltsverzeichnis
Ihr bekommt hier die seltene Gelegenheit, einem Naturwissenschaftler über die Schultern zu schauen, der (außerhalb seiner Kernexpertise wildernd) ein musikalisches Problem entdeckt, daraus eine Forschungshypothese formuliert und diese dann experimentell zu validieren versucht. Ich lade euch ein, mich auf dieser Entdeckungsreise zu begleiten, unterwegs selbst einige Dinge auszuprobieren und mit mir zusammen vor allem viel Spaß dabei zu haben.
Entsprechend der Natur der hier verhandelten Inhalte wird es im Folgenden nicht ganz anspruchslos zugehen. So gibt es unter anderem einen kleinen Programmierworkshop in Audiodatenverarbeitung, und auch ein paar ordentliche Mathebissen erwarten euch. Leser:innen mit einschlägigen Vorkenntnissen und solche, die es einfach mal probieren wollen, sind herzlich eingeladen, ein Python-Notebook aufzuklappen und mitzumachen. Aber auch für alle anderen fällt hoffentlich der eine oder andere interessante Krümel ab. Da es nicht zuletzt auch um Musik geht, muss ich auch hier gewisse Grundkenntnisse in Musiktheorie voraussetzen, werde aber versuchen, euch alle so gut es geht abzuholen. (Vielleicht hilft es hier ja, dass ich selbst kein Experte bin.) Am Ende der Reise steht uns das neuartige Werkzeug der „Overtone F*ckery“ zur Verfügung, mit dem wir Musik für alternative Universen komponieren, neue harmonische Entdeckungen machen oder einfach nur unseren Spaß haben können. Und allerspätestens mit den fertigen Samplesets, auf die ihr leider noch bis zur nächsten Folge warten müsst, steht die Spielwiese dann wirklich jeder Leserin und jedem Leser weit offen.
Das Moll-Dilemma und ein Ansatz zu dessen Lösung
Bei mir begann alles mit dem Konsum eines Videos mit dem großartigen Jacob Collier, den ich hier sicher nicht vorzustellen brauche. Darin beantwortet er „Tech Support“-Anfragen von Musiker:innen und Musikinteressierten aus sozialen Netzwerken und erklärt dabei unter anderem, warum Moll-Akkorde so traurig klingen.
Jeder Ton, den ich auf einem x-beliebigen Instrument (von einem Sinusoszillator abgesehen) spiele, bringt neben dem Grundton auch immer eine Reihe von Obertönen mit. Diese bestehen aus ganzzahligen Vielfachen eines Grundtons (die „Harmonischen“), derer es prinzipiell unendlich viele gibt. Im Fall eines „tiefen C“ fängt diese Reihe so an:

Harmonische Reihe (Obertonreihe). Die Dur-Terzen (5. und 10. Harmonische) sind hervorgehoben.
Angepasst von: https://commons.wikimedia.org/wiki/File:Harmonics.svg (Baba66 unter CC-BY 2.5)
Zweierpotenzen, also die 2., 4., 8., 16., … Harmonischen entsprechen reinen Oktaven. Dazwischen passen aber zu höheren Ordnungen hin immer mehr Zwischentöne. Irgendwann liegen diese so nah beieinander, dass sich nicht mehr sinnvoll in unserem 12-Ton-System aufschreiben lassen. Bei der 3. Harmonischen handelt es sich um die Quinte über der Oktave, ebenso bei der 6., also wiederum der Oktave über ebendieser Quinte. Und die 5. Harmonische liegt eben genau eine große Terz über der 4. Harmonischen. Seit Pythagoras ist eine perfekte große Terz definiert als das Frequenzverhältnis 4:5. Fügen wir die Quinte hinzu, ergibt sich also aus den 4., 5. und 6. Harmonischen ein perfekter Durdreiklang. Drücke ich auf dem Klavier nur eine einzige Taste (am besten hört man es bei den tiefen Tönen), dann spiele ich beispielsweise:
und ohne weiteres Zutun tönet die Obertonreihe in herrlichstem C-Dur (grün markiert):
Wer ein akustisches Klavier zur Verfügung hat, kann durch sanftes Auflegen eines Fingers bei einem Viertel, Fünftel oder Sechstel der Saitenlänge genau diese Teiltöne ausfindig machen und isolieren. Es werden dann alle Frequenzen gedämpft, die an der Position des Fingers keinen Schwingungsknoten haben, und nur die jeweilige Harmonische kann klingen. Die Gitarrist:innen unter euch kennen ja die Flageolettpositionen am 5, 4. und 3. Bund – auch da bekommen wir die 4., 5. und 6. Obertöne und somit einen Durdreiklang – die Physik dahinter ist absolut die gleiche wie beim Klavier. Ohne Fingerauflegen klingen alle Obertöne und formen gemeinsam den charakteristischen Klang des Instruments.
Hier habe ich einmal einen Klavierton mit einem Verfahren, das wir unten noch kennenlernen werden, zu in seine Bestandteile zerlegt. Zunächst erklingt der Originalton, dann beginnend beim Grundton die Obertöne und schließlich wieder die Summe aller Komponenten. Lest beim Hören mal die Notenschrift über diesem Absatz mit und achtet insbesondere auf den (grünen) Durdreiklang, gebildet aus den vierten, fünften und sechsten Teiltönen.
Ein C im Bass schafft also klare Fakten in Richtung C-Dur. Möchte ich darüber aber lieber C-Moll spielen, habe ich erst einmal schlechte Karten. Kennzeichnend für den Mollakkord ist ja eben die kleine Terz, bei C-Moll also das Eb. Das reibt sich aber mit dem E aus der Obertonreihe des Grundtons, das ja nur einen Halbton entfernt ist.
Zusammen klingt es dann dissonant oder traurig oder wie man es auch immer sehen mag.
Hypothese
Für den Hobby-Musikforscher in mir ergab sich daraus nun sozusagen als wissenschaftliche Fragestellung: Klingen Moll-Tonarten besser bzw. konsonanter, wenn das Obertonspektrum des verwendeten Instruments ebenfalls in Moll ist? Intuitiv könnte man ja meinen, dass sich die Teiltöne dann besser vertragen und der Gesamtklang harmonischer wird. Hier eine schematische Darstellung dieser Arbeitshypothese:
Material
Um dieser Frage auf den Grund zu gehen, brauchen wir zunächst Versuchsmaterial. Für ersteres wähle ich ein frei erhältliches Piano-Multisample aus, nämlich das frei erhältliche „Salamander Grand Piano“ von Alexander Holm. Hier finden wir angefangen vom tiefen A jede dritte Taste eines Flügels in 16 Dynamikstufen abgesampelt, hinzu kommen jede Menge Extras wie Release- und Pedalgeräusche, die uns im Rahmen dieser Forschungsexpedition aber nicht weiter interessieren sollen. Als Anschauungsobjekt soll uns das C2 in Velocity-Stufe 9 dienen, das wir oben bereits einmal zerlegt hatten:
Das Instrument der Fourieranalyse
Nun, da das Material beschafft ist, stellt sich die Frage nach dem geeigneten Werkzeugkasten. Insbesondere wollen wir uns ein Verfahren konstruieren, um Obertöne zu verschieben. Wie kommt man an diese überhaupt heran? Hierzu verwenden wir das Instrument der Fourieranalyse bzw. -transformation, die in den meisten Programmiersprachen mit gut ausgestatteter Numerikbibliothek standardmäßig verfügbar ist. Sie verwandelt ein auf der Zeitachse gegebenes periodisches Signal p(t) (der vom Mikrofon zu bestimmten Zeitpunkten gemessene Luftdruck) in seine Sinus- und Cosinusbestandteile verschiedener Frequenzen um:
Es können prinzipiell beliebig hohe Frequenzen enthalten sein, der Index k bei beiden Summen läuft bis ins Unendliche und zu jeder Frequenz verraten uns die Koeffizienten ak und bk die Koeffizienten der zugehörigen Cosinus- und Sinusanteile für die k-te Frequenz. Bei digital abgetasteten Signalen ist allerdings bei der Nyquistfrequenz (halbe Abtastrate) Schluss.
Aus Faulheit (im Mathematikerjargon auch „Eleganz“ genannt) werden nun üblicherweise noch die Amplituden ak und bk zu einer gegebenen Frequenz in einer einzigen komplexen Zahl ck zusammengefasst: der Cosinus im Realteil und der Sinus im Imaginärteil.
Mit der inversen Fouriertransformation erhält man dann aus dem Frequenzspektrum dann wieder die Zeitdarstellung, also den Luftdruck als Funktion der Zeit.
Hier ist eine sehr anschauliche Animation dieses Dualismus zwischen Zeitraum und Frequenzraum, von Lucas Barbosa bereitgestellt unter CC-0 (Public Domain).

Animierte Illustration des Dualismus zwischen Zeit- und Frequenzdarstellung. Veröffentlicht von Lucas Barbosa unter CC-0 (Public Domain)
Das soll an Hintergrund erst einmal genügen. Das Schöne an der Fouriertransformation ist, dass man sie als Werkzeug einsetzen kann, ohne die Mathematik dahinter völlig durchdrungen zu haben. Hier also nochmal in aller Kürze die wichtigsten Punkte:
- Die Fouriertransformation liefert die Amplituden der im Signal enthaltenen Frequenzanteile.
- Weil die Fouriertheorie von periodischen Signalen ausgeht, können nur Vielfache der Wiederholfrequenz abgebildet werden.
- Die kleinste darstellbare Frequenz ist f0=1/Periode. Das entspricht einer Sinusfunktion mit einem Berg und einem Tal je Periode.
- Sinus und Cosinus derselben Frequenz treten in der Regel gemischt auf und werden durch komplexe Amplituden ausgedrückt.
Die Annahme, dass unser Signal wie in diesem Beispiel periodisch ist, trifft in der Praxis natürlich so gut wie nie zu. In der Praxis soll uns das aber nicht daran hindern, Fourieranalysen durchzuführen. Wir schneiden das Signal einfach in Stücke konstanter Länge und analysieren jedes dieser Scheibchen so, als würde es sich bis in alle Ewigkeit wiederholen. Das Ergebnis ist eine zeitliche Abfolge von Frequenzspektren, je Scheibchen eins: ein „Spektrogramm“. Sicherlich hat der Audio-Editor eures Vertrauens auch eine entsprechende Funktion. In Audacity beispielsweise gibt es einen Spektrogramm-Darstellungsmodus, in dem die Teiltöne unseres Klaviers deutlich sichtbar werden. Die horizontale Achse ist die Zeit, die vertikale die Frequenz. Angefangen beim Grundton (ganz unten) sehen wir viele parallele Linien in regelmäßigen Abständen, jede eine Harmonische von C2. Man sieht auch einige andere Dinge – zum Beispiel, dass die höheren Frequenzen (durch Reibungsverluste) schneller abklingen als der Grundton.
Es zeichnet sich also bereits schematisch ab, wie der (noch zu konstruierende) Oberton-Verbiege-Apparat ungefähr aussehen wird:
1. Fouriertransformation
2. Editieren der Obertöne
3. Inverse Fouriertransformation
Gerade der zweite Schritt gestaltet sich nicht ganz einfach. Gern handelt man sich beim Herumfummeln an Frequenzspektren Phasenverschiebungen ein, die nach der Rücktransformation als Knackser unangenehm hörbar werden. Wenn man aber einige Kleinigkeiten beachtet, ist das Problem aber einigermaßen gut lösbar.
Audio-Signalverarbeitung mit Python für Dilettanten und -onkels
Der Autor dieser Zeilen ist nicht mit einer exorbitanten Aufmerksamkeitsspanne gesegnet und hat sich daher effektive Vermeidungsmechanismen angeeignet, wenn theoretische Tiefen zu ergründen sind. Statt dessen will ich euch einladen, die oben postulierte Hypothese „Mit Moll klingt‘s toll“ gemeinsam in der Praxis zu erproben. Krempelt also die Ärmel hoch, jetzt wird programmiert! Wir brauchen:
- Eine Programmierumgebung unserer Wahl mit geeigneter Numerikbibliothek, Funktionen für die „Fast Fourier Transform“ (FFT und iFFT) sowie die Möglichkeit zum Lesen und Schreiben von Audiodateien.
Ich habe das hier beschriebene Verfahren zunächst in MATLAB getestet, dann mit Python nochmal nachgebaut. Beide sind mit allem ausgestattet, was wir brauchen; letztere ist kostenlos erhältlich und es gibt viele komfortable Möglichkeiten, sie in Webumgebungen (Notebooks) einzubinden. Mit einem Google-Account kann man über Google Drive sehr bequem loslegen.
- Um die Eingabedaten haben wir uns ja schon gekümmert.
Die Programmierumgebung
Wir fangen an, indem wir in Google Drive ein neues Objekt anlegen, und zwar vom Typ „Google Colaboratory“.
Google Colaboratory – neues Notebook anlegen
Öffnen wir dieses, erscheint folgendes Fenster, in dem wir Programmcode in einzeln ausführbaren „Zellen“ organisieren können, und zahlreiche weitere Funktionen zum Verwalten von Daten und Bibliotheken.

Ein Notebook mit Code- und Ausgabebereich (rechts) sowie einigen Reitern zur Verwaltung von Dateien und Variablen (links).
Unter dem Reiter „Dateien“ befindet sich ein Dateimanager, in dem schon einige Beispieldatensätze liegen. Unser Klaviersample C2v9.wav fügen wir hier via Drag-and-Drop dem Ordner sample_data hinzu. Wer auf die Schnelle keine Kopie findet: hier ist eine. Achtung: auf diese Weise hochgeladene Dateien sind flüchtig und gehen beim Schließen des Notebooks wieder verloren. Aber so eine Datei ist ja im Zweifel schnell wieder hochgeladen. Wie ihr seht, habe ich auch schon ein wenig Programmcode eingefüllt (der, wie bei Google-Dokumenten üblich, ständig gespeichert wird und daher auch beim Schließen erhalten bleibt). Kopiert den folgenden Code in die erste Zelle eueres Notebooks:
import soundfile as sf # Sounddateien lesen und schreiben data, fs = sf.read('sample_data/C2v9.wav')
Es soll demnach die Bibliothek soundfile unter dem Kürzel sf geladen werden; anschließend lesen wir mit der darin enthaltenen Funktion sf.read(…) die WAV-Datei ein.
Nun führt die Zelle per Knopfdruck oder Shift+Enter aus. Es passiert zunächst einmal: nichts. (Statt nichts könnte ggf. auch ein Fehler auftreten, nämlich wenn die Datei unauffindbar ist. In diesem Fall überprüft bitte nochmals den Dateipfad im Code, und dass die Datei auch wirklich an der richtigen Stelle liegt.)
Bei näherem Hinsehen finden wir einen kleinen Haken, der anzeigt, dass der Code dieser Zelle ohne Fehler ausgeführt worden ist. Wie ich mich dann in der „Variablen“-Ansicht vergewissern kann, sind zwei Variablen angelegt worden: die Sampledaten als zweidimensionales Array data (Anzahl der Samples mal Anzahl der Kanäle), sowie die Abtastfrequenz fs. Es handelt sich um eine Stereo-Datei mit 48kHz Abtastate und einer Länge von 1069602 Samples.
Nun, da das offenbar funktioniert hat, lasst uns noch eine Reihe weiterer Bibliotheken laden, die wir später noch brauchen werden. Ersetzt den gesamten Code der Zelle durch diesen hier:
import soundfile as sf # Sounddateien lesen und schreiben import numpy as np # Numerik Grundfunktionen import numpy.fft as fft # FFT und iFFT import matplotlib.pyplot as plt # Grafikausgabe from IPython.display import Audio # Soundausgabe data, fs = sf.read('sample_data/C2v9.wav') num_channels = data.shape[1] num_samples = data.shape[0] Audio(data.transpose(), rate=fs, autoplay=True)
und führt die Zelle wieder aus. Nun sollte ein kleiner Audioplayer erscheinen, der die Datei auch gleich abspielt. Nebenbei haben wir uns die Länge und Kanalzahl in eigene Variablen herausgeschrieben.
Daten verarbeiten
Als nächstes wollen wir die Audiodaten verarbeiten und in eine neue Datei zurückschreiben. Hierzu setze ich euch erst mal einen größeren Brocken Programmcode vor (bitte keinen Schreck bekommen), den ihr gerne 1:1 in eine neue Zelle kopieren könnt. Wer schon einmal programmiert hat, wird sofort Bescheid wissen; für alle anderen habe ich hoffentlich genügend Klartext-Kommentare hinzugefügt, dass die wesentlichen Schritte klar werden. Kurz gesagt, unterteilen wir das Signal, das in der Variable data vorliegt, in Schnipsel konstanter Länge (Fenster) und fügen diese anschließend wieder in data_out zusammen. Wieviele solcher Fenster wir brauchen, hängt von der gewählten Fenstergröße (hier: 512) und der Länge des Audiomaterials ab. Ein eventuelles unvollständiges Fenster ganz am Ende könnte man, wenn man den unbedingt wollte, noch mit Nullen auffüllen. Wir werfen es statt dessen einfach weg, indem wir die Anzahl der Fragmente auf die nächstkleinere ganze Zahl runden. Der Schaden ist überschaubar – 512 Samples bei 48kHz entspricht ein paar Millisekunden an Schall. Bei einem Klavierton, der bereits 20 Sekunden lang ausgeklungen ist, sollte sich der Verlust eines halben Fensters also einigermaßen verschmerzen lassen.
window_size = 512; # Anzahl der Fragmente num_fragments = int(num_samples / window_size) # Ausgabevariable initialisieren data_out = np.zeros([num_fragments*window_size,2]) for ch in range(num_channels): # für alle Kanäle: for i in range(num_fragments): # prozessiere alle Fragmente # Fragment aus dem Eingabe-Array holen frag_in = data[i*window_size:(i+1)*window_size,ch] # Fragment unverändert übernehmen frag_out = frag_in # Ins Ausgabe-Array zurückschreiben data_out[i*window_size:(i+1)*window_size,ch] = frag_out # und schließlich alles zurück in eine Datei schreiben sf.write('sample_data/C2v9_out.wav',data_out,fs,'PCM_24') # Ausgabe über Mediaplayer Audio(data_out.transpose(),rate=fs, autoplay=True)
Eine Python-Besonderheit ist das Indizieren von Arrays mit Teilbereichen (ranges). data[a:b] liefert ein Teilarray, welches Elemente mit Index a bis b-1 aus data enthält. Die Zählung beginnt bei Null, aber auch negative Indizes sind erlaubt. data[-1] bezeichnet das letzte Element des Arrays, data[-3] das drittletzte und so weiter. Das werden wir später noch brauchen, um an die negativen Frequenzen zu gelangen. Zu beachten ist auch, dass die Zeile
# Fragment unverändert übernehmen frag_out = frag_in
nicht etwa die Daten kopiert (deep copy), sondern die Variable frag_out nur als Referenz auf frag_in anlegt. Da kann man fies hinfallen, wenn man an einer Variablen herumoperiert und dabei versehentlich die andere verändert. Nachdem ihr auch diese neue Zellen ausgeführt habt, sollte im Dateimanager eine neue Datei auftauchen. Ladet sie herunter und hört sie euch an. Mit etwas Glück erklingt wieder das vertraute C2 vom Klavier. Falls nicht, könnte es an einer inkonsistenten Einrückung der Zeilen liegen. Programmblöcke, Schleifen usw. werden in Python durch Leerzeichen bzw. Tabs am Zeilenanfang ausgezeichnet. Andere Sprachen verwenden deutlicher sichtbare Syntax wie begin…end oder Klammern {}. Ein weiterer klassischer Fallstrick für die armen Python-Neulinge.
Kurzzeit-Fouriertransformation (STFT)
Warum haben wir uns nun die Mühe gemacht, das Signal erst zu zerstückeln und anschließend wieder zusammenzufügen? Wir hätten es ja schließlich auch gleich in einem Rutsch verarbeiten können. Nun, der Grund hierfür liegt in einer Eigenschaft der diskreten Fouriertransformationen (so auch der FFT), bei der die Länge des Fensters starr an die Auflösung der Frequenzbänder gekoppelt ist. Wir hatten oben ja schon festgestellt, dass wir unsere Frequenzspektren in Vielfachen der fensterspezifischen Grundfrequenz erhalten, also der Sinuswelle, die genau einmal in die Fensterlänge hineinpasst. Im Fall unserer Fensterlänge von 512 wäre diese:
print('Fourier-Grundfrequenz: {:5.2f} Hz'.format(sf/window_size))
Ausgabe:
Fourier-Grundfrequenz: 93.75 Hz
Suchen wir nun etwa nach der Frequenz 187.5 Hz (= 2 * 93.75 Hz), wüssten wir, dass wir diese dank der fixen Fenstergröße immer im 2. Frequenzband finden. Dies wäre beispielsweise nicht der Fall, wenn wir das komplette Audiosignal in ein Fenster packen, dessen Länge dann je nach Sample ja immer eine andere wäre. Auch wenn wir noch nicht genau wissen, an welche Frequenzen wir überhaupt heranmüssen: unser Eingabesample ist ein C2, entsprechend einem Grundton von 65.4 Hz bzw. einer Periode von ungefähr 734 Samples. Lasst uns daher im Folgenden lieber auf eine window_size von 734 wechseln. Und nun laufen wir mit diesem Fenster also über die Audiodaten und können für jedes Scheibchen das Frequenzspektrum berechnen. Wo wir in der inneren Schleife bisher einfach nur kopiert haben:
# Fragment unverändert übernehmen frag_out = frag_in
transformieren wir jedes Scheibchen nun einmal in die Frequenzdarstellung und dann gleich wieder zurück:
# Fouriertransformation spec = fft.fft(frag_in) # [hier wird später die Wurscht gemacht] # Rücktransformation frag_out = np.real(fft.ifft(spec))
Überprüft am besten gleich wieder, ob die Audiodaten noch intakt sind. Der Klavierklang hat es nun immerhin schon einmal überlebt, einmal in den Fourierraum und wieder zurück transformiert zu werden. Die Frage ist nun: was finden wir im Frequenzspektrum spec vor und wie können wir es manipulieren?
Orientierung im Fourierraum
Zunächst einmal, o Schreck, hat das Fourierspektrum spec zwar die gleiche Länge wie das Eingabefragment, aber wir erinnern uns: Fourierkoeffizienten kommen als komplexe Zahlen daher. Auch wen wir das jetzt von der mathematischen Seite her nicht komplett durchdringen können, ist aber wichtig zu bedenken, dass es in der Fourier-Welt positive und negative Frequenzen gibt. Nur wenn ich die paarweise zusammen anfasse, kann ich (bis auf Rechenungenauigkeiten) sicherstellen, dass ich nach der Rücktransformation keine komplexen Zahlen herausbekomme. Außerdem sind, wie wir bereits wissen, sind die im Fourierspektrum aufgelösten Frequenzbänder ganzzahlige Vielfache der FFT-Grundfrequenz. Konkret auf unser spec bezogen, finde ich das n-te Frequenzband an der Stelle spec[n] und die dazugehörige negative Frequenz an der Stelle spec[-n], also im n-t-letzten Element des Arrays. spec[0] ist die DC-Komponente, also der konstante Anteil. Als erstes Experiment könnten wir uns an einem Hochpassfilter versuchen. Wenn wir Frequenzbänder -5 bis 5 auf Null setzen, sollte das doch ungefähr einem Lowcut um 450Hz entsprechen. Probieren wir es doch mal aus:
# Fouriertransformation spec = fft.fft(frag_in) # Manipulation des Spektrums - hier: Hochpassfilter spec[0:5] = 0 spec[-5:len(spec)] = 0 # Frequenzbänder -5 bis -1 # Rücktransformation frag_out = np.real(fft.ifft(spec))
Spielen wir die Ausgabe dieses Codes ab, hören wir in der Tat eine Variante des Pianosamples, bei dem hohe Frequenzen stark gedämpft sind. Ebenfalls zu hören ist aber auch ein ziemlich fieses Gebritzel. Dieses hängt mit der scheibchenweisen Prozessierung des Audiosignals zusammen. Nach Manipulation passen die Fragmente nicht mehr nahtlos aneinander, es gibt Wertesprünge und die sind als Knackser deutlich hörbar. Hier helfen wir uns, indem wir jedes Fragment mit einer linearen “Korrekturrampe” versehen, die den Start- und Endwert auf den alten Wert zurückzieht.
# Zu Reduzierung von Knacksern Anfangs- und Endpunkte anpassen
correction_ramp = np.linspace(frag_in[0]-frag_out[0],
frag_in[-1]-frag_out[-1],
window_size)
# Ins Ausgabe-Array schreiben
data_out[i*window_size:(i+1)*window_size,ch] = frag_out + correction_ramp
Das ist nun sicher noch nicht die ganz hohe Schule der Audiosignalverarbeitung, aber das Britzelproblem bekommen wir damit einigermaßen effektiv in den Griff.
Fazit und Hausaufgaben
So, ihr Lieben – die nötigen Vorarbeiten sind gemacht. Wir verstehen jetzt, warum Mollakkorde einen physikalischen Nachteil gegenüber Durakkorden haben. Und wir haben Material und Handwerkszeug beisammen, um dagegen etwas zu tun. Unter anderem können wir jetzt schon:
- Audiodaten in Python laden,
- diese Daten in Fragmente zerlegen und wieder zusammenfügen,
- Audiodaten in den Fourierraum und zurück in die Zeitdarstellung transformieren und
- einfache spektrale Veränderungen vornehmen.
Während ich Teil 2 dieses Workshops aufschreibe, versucht euch doch auch mal an eigenen Manipulationen. Zum Beispiel könntet ihr ein Tief- oder Bandpassfilter implementieren oder Frequenzanteile im Spektrum herumschieben. Probiert auch mal aus, was mit Fenstergröße 512 klingt – es funktioniert schon alles deutlich besser, wenn das Analysefenster aufs Tonmaterial angepasst ist. Ganz Mutige dürfen sich auch gerne schon einmal an der Mollifikation versuchen – fairerweise sei hier aber verraten, dass wir vorher noch ein klein wenig mehr rechnen müssen. Einstweilen hier schon einmal mein eigenes Ergebnis als Amuse-Gueule:
Nun seid ihr dran – tobt euch aus und berichtet in den Kommentaren von eueren Ergebnissen. Ich freue mich auf eure Rückmeldungen!









