Sound - Institut für Informatik
Transcription
Sound - Institut für Informatik
Kapitel 10: Signalverarbeitung mit Python: Sound Einführung in die Informatik Wintersemester 2007/08 Prof. Bernhard Jung Übersicht Signalverarbeitung mit Python: Sound Repräsentation von Sound Algorithmen: Erhöhen der Lautstärke Normalisierung von Sound Rückwärts-Sound Konkatenierung von Sound Kombination von Sounds Akkorde Echo Synthetischer Sound Frequenz von Sounds erhöhen / verringern Hauptlernziele • Repräsentation von digitalem Sound verstehen • Digitalen Sound als eine Art von Messwerten verstehen • Einfache Python-Programme zur Soundverarbeitung entwickeln können • Wdh: Schleifen (for) und bedingte Anweisungen (if … else) verstehen Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 1 Akustik – die Lehre vom Schall Schallwellen sind zyklisch Frequenz einer Welle Anzahl der Zyklen pro Sekunde gemessen in Hertz (1 Hz = 1 Zyklus / Sekunde) Amplitude Amplitude maximale Höhe der Welle 1 Zyklus Natürlich vorkommende Klänge bestehen aus Überlagerung einer Vielzahl von Schallwellen Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Psychoakustik – Wahrnehmung von Schall Lautstärke und Tonhöhe Wahrgenommene Lautstärke korreliert (logarithmisch) mit Amplitude Verdopplung der Amplitude Æ ca. 3 Dezibel lauter Dezibel: Maß für wahrgenommene Lautstärke 0 dB: Schwellwert für Wahrnehmbarkeit von Geräuschen 60 dB: Unterhaltungsgespräch 80 dB: Schreien Wahrgenommene Tonhöhe korreliert (logarithmisch) mit Frequenz Höhere Frequenz Æ größere Tonhöhe Verdopplung der Frequenz Æ 1 Oktave höher Menschliches Gehör: 5 Hz – 20.000 Hz Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 2 Digitalisierung von Sound Sound Sample numerische Repräsentation der Amplitude zu einem bestimmten Zeitpunkt (Messung des Drucks, den SoundWelle an Mikrofonmembran erzeugt) Æ Beschreibung der Sound-Welle durch hinreichende Anzahl von Samples AD-Wandler (Analog-Digital) wie viele Samples notwendig? Prof. B. Jung PCM – Pulse Code Modulation: Digitale Repräsentation eines analogen Signals, bei welcher das Signal in uniformen Intervallen abgetastet wird und die Signalgröße in digitaler Form quantisiert wird Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Theorem von Nyquist Theorem von Nyquist (bezogen auf Sound): Zur Repräsentation (und späteren Wiedergabe) von Sound mit maximaler Frequenz n Hertz müssen mindestens 2n Samples abgenommen werden Sampling Rate: Anzahl der erfassten Samples pro Sekunde z.B. Menschliche Stimmen: maximale Frequenz 4000 Hz z.B. Menschliches Gehör: maximale Frequenz ca. 22000 Hz Prof. B. Jung Æ 8000 Samples pro Sekunde notwendig (Telefon) Æ ca. 44000 Samples pro Sekunde notwendig Æ CD-Qualität: 44.100 Samples / Sekunde Æ 3-Minuten Song benötigt 158.760.000 Samples (Stereo × 2) Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 3 Digitaler Sound: Repräsentation von Sound in Computern Typischerweise jeder Sample-Wert wird durch 2 Byte repräsentiert Digitaler Sound = Feld (Array) von Sound-Samples 2 Byte = 16 Bit d.h. 216 = 65.536 verschiedene Zahlen darstellbar Æ Sample-Werte: -32.768 … 32.767 Bem: Viele Varianten möglich, z.B. 8 Bit pro Sample Achtung: Komprimierte Speicherung in üblichen Datei-Formaten (z.B. mp3) 59 19 -1 -111 -30 18 18 0 1 2 3 4 5 6 Digitale Soundverarbeitung = Manipulation von Feldern Ändern der Sample-Werte Ändern der Feldgröße Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg WAVE-Dateiformat Teil von Microsofts RIFFSpezifikation für Multimedia Dateien Repräsentation von Samplewerten und Formatinformationen größtenteils als "little endian" z.B. Bytefolge 24 17 1e 13 repräsentiert Hex-Zahl 0x131e1724 = 320739108 Falls 16 Bits per Sample, werden Samplewerte vorzeichenbehaftet (im Zweierkomplement) gespeichert, d.h. Wertebereich -32768 … 32767 Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Quelle: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ 4 WAVE-Dateiformat / Beispiel Mono = 1, Stereo =2 0x00000824 = 2084 0x5622 = 22050 0x0d1ace11 = 219860497 Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Quelle: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ TUBAFSound.py Funktionen für die Sound-Verarbeitung Skript mit Funktionen zur einfachen Verarbeitung von digitalem Sound Einschränkungen an Sound-Dateien .wav Format 16 Bit Sample-Breite mono (laden von Stereo ok) bevorzugte Samplingrate 22050 from TUBAFSound import * sound = makeSound('c4.wav') playSound(sound) saveSound(sound,'c4-copy.wav') Verwendung Skript auf Kurs-Webseite Speichern im Arbeitsverzeichnis funktioniert aber auch mit anderen Samplingrates >>> >>> >>> >>> mit eigenen Skripten Sound-Dateien Abspielen von Sound nur auf Windows u. Linux alle Plattformen: Bearbeiteten Sound speichern, dann mit geeignetem Player abspielen Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 5 TUBAF Sound: Funktionen für die Sound-Verarbeitung (Auswahl) Öffnen von Sound-Dateien makeSound(dateiname) – Erzeugt internes Sound-Objekt Lesen und Setzen von Sample-Werten nur .wav Dateien ! getSamples(sound) – liefert Liste aller Samplewerte setSamples(sound, samples) – setzt die Samplewerte getSample(sound, index) – liefert Wert eines Samples (als Integer-Zahl) setSample(sound, index, value) – setzt Wert eines Samples getLength(sound) bzw len(sound) – liefert Länge des Sounds (Anzahl der Samples) Speichern / Abspielen von Sounds saveSound(sound, filename) – abspeichern des Sounds als .wav Datei playSound(sound) – bis jetzt nur Windows und Linux Prof. B. Jung andere Plattformen: Abspeichern des Sounds, Abspielen mit jeweiligem Audio-Player Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg TUBAF Sound: Beispiele für Sound-Funktionen >>> from TUBAFSound import * >>> filename = r'C:\Dokumente und Einstellungen\Jung\Eigene Dateien\c4.wav' >>> sound = makeSound(filename) >>> print sound Sound of length 55125 >>> getSample(sound, 0) 20 >>> getSample(sound, 55124) 4225 >>> samples = getSamples(sound) >>> print samples[0:10] # ':' ist sog. 'slice'-operator [20, 946, 1948, 2919, 3814, 4748, 5673, 6547, 7333, 8130] >>> playSound(sound) # nur Windows u. Linux >>> saveSound(sound, 'c4-copy.wav') # alle Plattformen Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 6 Erinnerung: range() Funktion >>> range(3) [0, 1, 2] >>> range(1, 3) [1, 2] >>> range(3, 1) [] >>> range(-1, 5) [-1, 0, 1, 2, 3, 4] >>> range(100) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, … 99] Oft Verwendung in Zählschleifen: for index in range(10): … Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Erinnerung: Bearbeitung von Listen mit Zählschleifen Beispiel: Verdoppeln aller Listenelemente >>> def verdopple( liste): for index in range( len(liste) ): wert = liste[index] # Zugriff auf i. Element liste[index] = wert * 2 # Zuweisung an i. Element >>> liste = [10,11,12,13,14] >>> verdopple(liste) >>> liste [20, 22, 24, 26, 28] >>> liste = [10,11,12,13,14,15,16,17,18,19] >>> verdopple(liste) >>> liste [20, 22, 24, 26, 28, 30, 32, 34, 36, 38] >>> Sound-Bearbeitung = Manipulation von Arrays/Listen analog zu obigem Beispiel Listen allerdings länger, z.B. 22050 Elemente pro Sekunde des Sounds Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 7 TUBAF Sound: Einfaches Gerüst für Programme zur Sound-Verarbeitung Iteration über alle Samples mit for-Schleife ! Python-Skript def manipulateSound(sound): for index in range( getLength(sound) ): value1 = getSample(sound, index) value2 = value1 # oder sinnvolleren neuen Wert setSample(sound, index, value2) Benutzung >>> >>> >>> >>> >>> >>> from TUBAFSound import * filename = "techno_mono.wav" sound = makeSound(file) manipulateSound(sound) playSound(sound) Prof. B. Jung # bzw. andere wav-Datei TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Beispiel: Lautstärke erhöhen Amplitude des Sounds muss größer werden Æ alle Sample-Werte z.B. verdoppeln alt: neu: 59 19 -1 -111 -30 18 18 0 1 2 3 4 5 6 118 38 -2 -222 -60 36 36 0 1 2 3 4 5 6 Python-Skript: def increaseVolume(sound): for index in range(getLength(sound)): value = getSample(sound, index) setSample(sound, index, value*2) >>> >>> >>> >>> >>> Prof. B. Jung Benutzung: filename = "techno_mono.wav" sound = makeSound(filename) increaseVolume(sound) playSound(sound) Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 8 Arbeitsweise von increaseVolume(): Start der Schleife for Schleife setzt index = 0 def increaseVolume(sound): for index in range(getLength(sound)): sample = getSample(sound, index) setSample(sound, index, sample*2) 59 19 -1 -111 -30 0 1 2 3 4 … index Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Arbeitsweise von increaseVolume(): Ausführung des Blocks sample erhält den Wert des ersten Samples (d.h. index 0) von sound Wert des Samples an index wird neu gesetzt (bisheriger Wert mal 2) def increaseVolume(sound): for index in range(getLength(sound)): sample = getSample(sound, index) setSample(sound, index, sample*2) sample 118 19 -1 -111 -30 0 1 2 3 4 … index Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 9 Arbeitsweise von increaseVolume(): Das nächste Sample … Kontrolle kehrt zum Schleifenanfang zurück; index wird nun inkrementiert und erhält somit den Wert 1 def increaseVolume(sound): for index in range(getLength(sound)): sample = getSample(sound, index) setSample(sound, index, sample*2) 118 19 -1 -111 -30 0 1 2 3 4 … index Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Arbeitsweise von increaseVolume(): … verdoppeln des nächsten Samples def increaseVolume(sound): nun wird Wert des nun aktuellen Samples (index = 1) gelesen … … und auf den neuen Wert 38 gesetzt for index in range(getLength(sound)): sample = getSample(sound, index) setSample(sound, index, sample*2) sample 118 38 -1 -111 -30 0 1 2 3 4 … index Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 10 Arbeitsweise von increaseVolume(): … und so weiter für alle Samples def increaseVolume(sound): Schleife iteriert über alle Indices somit sind alle SampleWerte nun verdoppelt for index in range(getLength(sound)): sample = getSample(sound, index) setSample(sound, index, sample*2) sample 118 38 -2 -222 -60 0 1 2 3 4 … index Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Beispiel: Benutzung von increaseVolume() >>> >>> >>> >>> >>> >>> sound = makeSound("techno_mono.wav") playSound(sound) increaseVolume(sound) playSound(sound) saveSound(sound, "techno_mono_louder.wav") Zur Erinnerung: Verdopplung Amplitude ≠ doppelte Lautstärke (logarithm. Korrelation) original Amplitude * 2 Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 11 Beispiel: Wiederholtes Erhöhen der Lautstärke original Amplitude * 2 Amplitude * 4 Clipping – Physikalische Schallwelle wird aufgrund der Beschränkung auf 16 Bit pro Sample nicht adäquat repräsentiert Æ schlechte Klangqualität Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Test: Extremer Sound Sound soll nur Samples mit extremen Sample-Werten enthalten: Falls Sample-Wert im Original >= 0, dann neuer Wert = 32767 Andernfalls neuer Wert = -32768 Æ Verwendung von if … else original extrem Prof. B. Jung def toTheExtreme(sound): for index in range(len(sound)): value = getSample(sound, index) if (value>=0): setSample(sound, index, 32767) else: setSample(sound, index, -32768) Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 12 Normalisierung von Sound Skalierung der Amplituden in einem Sound, so dass maximaler SampleWert = 32767 (und minimaler Sample-Wert = -32768) Schritte: 1.) Maximalen Sample-Wert loudest in Sound ermitteln 2.) Ermittlung des Verstärkungsfaktors amp, so dass amp * loudest = 32767 d.h. amp = 32767/loudest 3.) Verstärkung aller Sample-Werte durch Multiplikation mit amp original normalisiert Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Normalisierung von Sound def normalize(sound): loudest = 0 for s in getSamples(sound): loudest = max(loudest, s ) amp = 32767.0 / loudest print "Groesster Sample-Wert in Original: ", print "Verstaerkungsfaktor: ", amp loudest for index in range( len(sound) ): value = getSample(sound, index) louder = int(amp * value) setSample(sound, index, louder) >>> sound = makeSound("techno_mono.wav") >>> normalize(sound) Groesster Sample-Wert in Original: 14007 Verstaerkungsfaktor: 2.33933033483 >>> saveSound(sound,"techno_mono_normalized.wav") >>> Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 13 Rückwärts-Sound “[Revolution] number 9, number 9, number 9” Rückwärts-Abspielen von Sound war zu Beatles-Zeiten beliebt … Umsetzung mit digitalem Sound siehe z.B. en.wikipedia.org zu "Revolution 9" Sound-Array einfach umkehren: vorwärts: rückwärts: 59 19 -1 -111 -30 18 18 0 1 2 3 4 5 6 18 18 -30 -111 -1 19 59 0 1 2 3 4 5 6 Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Rückwärts-Listen Vorgehen: Zweite Liste listeRueckwaerts erzeugen, die Ergebnis enthalten soll Verwendung von zwei Indices (Laufvariablen) indexRueck – läuft von 0, 1, 2, …, n-1, zum Durchlaufen von listeRueckwaerts indexVor – läuft von n-1, n-2, …, 2, 1, 0, zum Durchlaufen der Originalliste Bei jedem Schleifendurchlauf wird indexRueck um 1 erhöht, durch range-Funktion indexVor um 1 erniedrigt, per expliziter Zuweisung ein Wert von Originalliste in neue Liste listeRueckwaerts kopiert def rueckwaerts(liste): listeRueckwaerts = [0] * len(liste) indexVor = len(liste) - 1 for indexRueck in range( len(liste) ): wert = liste[indexVor] listeRueckwaerts[indexRueck] = wert indexVor = indexVor - 1 return listeRueckwaerts Am Ende der Liste anfangen indexVor läuft rückwärts Test: >>> rueckwaerts([1,2,3]) >>> rueckwaerts([0,-1,88,7]) >>> rueckwaerts([]) [3, Prof. B.2, Jung1] [7, 88, -1, 0] WS 2007/08 Einführung in die Informatik, [] TU Bergakademie Freiberg 14 Rückwärts-Sound Vorgehen (analog zu Umkehrung von Listen): Kopien des Original-Sounds erzeugen (sound Æ destSound) Verwendung von zwei Indices (Laufvariablen) destIndex – läuft von 0, 1, 2, …, n-1 srcIndex – läuft von n-1, n-2, …, 2, 1, 0 Bei jedem Schleifendurchlauf wird destIndex um 1 erhöht, durch range-Funktion srcIndex um 1 erniedrigt, per expliziter Zuweisung Am Ende des Sounds anfangen from TUBAFSound import * def backwards(sound): destSound = copySound(sound) srcIndex = getLength(sound) - 1 for destIndex in range( getLength(sound) ): sample = getSample(sound, srcIndex) setSample(destSound, destIndex, sample) srcIndex = srcIndex - 1 return destSound Prof. B. Jung Einführung in die Informatik, WS 2007/08 srcIndex läuft rückwärts TU Bergakademie Freiberg Rückwärts-Sound “number 9, number 9, number 9” “Turn me on, dead man” ??? def backwards(sound): destSound = copySound(sound) srcIndex = getLength(sound) - 1 for destIndex in range( getLength(sound) ): sample = getSample(sound, srcIndex) setSample(destSound, destIndex, sample) srcIndex = srcIndex - 1 return destSound Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 15 Konkatenierung von Sound Aneinanderhängen von Sounds in zwei Dateien zu Sound in einer Datei Æ Aneinanderhängen von Sample-Arrays 59 19 -1 -111 0 1 2 3 + -30 18 18 0 1 2 = 59 19 -1 -111 -30 18 18 0 1 2 3 4 5 6 Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Konkatenierung von Sound Vorgehen zur Konkatenierung von zwei Sounds: 1. Erzeuge neues, leeres Sound-Objekt, das mindestes so lang ist wie beide Eingabe-Sounds zusammen 2. 3. TUBAF Sound: makeEmptySound(t) – t ist Länge des Sounds in Sekunden Kopiere Sample-Werte von erstem Sound-Objekt an Anfang von neuem Sound-Objekt Kopiere Sample-Werte von zweitem Sound-Objekt in neues SoundObjekt, beginnend hinter den Samples des ersten Sounds 59 0 Prof. B. Jung 19 1 -1 2 + = -111 3 59 19 -1 -111 0 1 2 3 -30 0 18 1 18 2 -30 18 18 4 5 6 Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 16 Konkatenierung von Sound Neues Teilproblem: Berechnung der Dauer eines Sounds in Sekunden Relevante Funktionen von TUBAFSound: getLength(sound) – Anzahl Samples eines Sounds getSamplingRate(sound) z.B. 22050 oder 44100 Samples / Sekunde Æ Dauer eines Sounds in Sekunden: duration(sound) in TUBAF-Sound enthalten definiert als: getLength(sound) / getSamplingRate(sound) Liefert i.d.R. float-Wert, z.B. 3.219 >>> snd = makeSound("techno_mono.wav") >>> duration(snd) 3.8552380952380951 >>> Prof. B. Jung Einführung in die Informatik, WS 2007/08 Konkatenierung von Sound def concatSounds(sound1, sound2): dur = duration(sound1) + duration(sound2) print "Duration:", dur sound = makeEmptySound( dur ) index = 0 for i in range(len(sound1)): value = getSample(sound1,i) setSample(sound, index, value) index = index + 1 for i in range(len(sound2)): value = getSample(sound2,i) setSample(sound, index, value) index = index + 1 return sound >>> snd1 = makeSound("InformatikMachtSpass.wav") >>> snd2 = makeSound("meistens.wav") >>> snd3 = concatSounds(snd1,snd2) Duration: 3.26063492063 >>> playSound(snd3) >>> Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Länge des konkatenierten Sounds berechnen (in Sekunden) Leeren Sound erzeugen Alle Samples von Sound1 kopieren Alle Samples von Sound2 kopieren TU Bergakademie Freiberg 17 Kontext: Manipulation digitaler Medien … ist einfach: nur Ersetzung von Bytes durch andere Bytes z.B. Bilder z.B. Sound www.br-online.de, 2005 echtes Zitat des Dozenten: "Informatik macht Spaß" auch mal gesagt: "meistens" nie gesagt: "Informatik macht Spaß … meistens" Prof. B. Jung selbst falls Sound-Dateien dieses Inhalts existieren sollten! Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Nachtrag: Sound-Bearbeitung mittels Builtin-Funktionen von Python für Listen Eingebaute Funktionen zur Manipulation von Listen in Python, u.a.: sei liste = [1,2,3] Liste rückwärts: liste.reverse() Æ [3,2,1] Konkatenierung von Listen: liste+[4,5] Æ [1,2,3,4,5] Erweitern um zweite Liste: liste.extend([2,1]) Æ [1,2,3,2,1] damit sind vereinfachte Funktionen zur Sound-Manipulation möglich: def backwards_usingBuiltIns(sound): sound.getSamples().reverse() return sound def concatSounds_usingBuiltIns(sound1,sound2): sound = makeEmptySound(0) setSamples(sound, getSamples(sound1) + getSamples(sound2)) return sound def concatSounds_usingBuiltIns2(sound1,sound2): sound1.getSamples().extend(sound2.getSamples()) sound1 Prof.return B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 18 Addition von Sound Natürlich vorkommende Sounds sind oft die Überlagerung mehrerer einfacherer Sounds Addition digitaler Sounds ist einfach: nur Sample-Werte addieren Anwendungen Mixen von Sound einfache Akkorde Mischen von komplexer Sounds auch Übergänge (fade-in / fade-out) durch Verändern der Lautstärke Erzeugen von Echos … Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Addieren von Sound + 10 20 30 40 50 60 20 1 6 2 12 3 18 4 28 5 38 6 -15 7 -40 16 32 48 68 88 45 -20 0 1 2 3 4 5 6 def addSounds(sound1,sound2): for index in range( getLength(sound1) ): s1Sample = getSample(sound1,index) s2Sample = getSample(sound2,index) setSample(sound1,index,s1Sample+s2Sample) return sound1 Kombinierter Sound in sound1 d.h. sound1 ist nach Funktionsaufruf verändert (sound2 bleibt wie zuvor) Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 19 Erzeugen von Akkorden durch Mischen von drei Sounds >>> >>> >>> >>> >>> >>> >>> >>> >>> c4=makeSound("bassoon-c4.wav") e4=makeSound("bassoon-e4.wav") g4=makeSound("bassoon-g4.wav") playSound(c4) addSounds(c4,e4) playSound(c4) addSounds(c4,g4) playSound(c4) bassoon (engl.): Fagott oder auch: >>> >>> >>> >>> >>> c4=makeSound("bassoon-c4.wav") e4=makeSound("bassoon-e4.wav") g4=makeSound("bassoon-g4.wav") playSound( addSounds( addSounds(c4,e4), g4) ) (c4+e4) (c4+e4) + g4 Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Akkord mit Delay z.B. zweiter Sound mit Delay von 5000 Samples z.B. dritter Sound mit Delay von 10000 Samples def makeChord(sound1,sound2,sound3): for index in range( getLength(sound1) ): s1Sample = getSample(sound1,index) if index > 5000: sound1 wird s2Sample=getSample(sound2,index-5000) überschrieben setSample(sound1,index,s1Sample+s2Sample) if index > 10000: s3Sample = getSample(sound3,index-10000) setSample(sound1,index,s1Sample+s2Sample+s3Sample) return sound1 >>> makeChord(c4,e4,g4) <TUBAFSound.Sound instance at 0x00C454E0> >>> playSound(c4) >>> Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 20 Erzeugen von Echos Idee: Neuer Sample-Wert erhält Anteile des bisherigen Samples + Anteile des Samples, das delay Samples zurück liegt Zur Vermeidung, dass Amplitude über Maximalwert liegt (d.h. neuer SampleWert > 32767) fließen altes und Echo-Sample mit Faktoren < 1 in neuen Sound ein Beispiel: Delay 4 (realistisch: 10000-20000) 10 20 30 40 50 60 70 0 1 2 3 4 5 6 Faktor 0.6 Faktor 0.4 Prof. B. Jung 6 12 18 24+4 =28 30+8 =38 36+12 =48 42+16 =58 0 1 2 3 4 5 6 TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Erzeugen von Echos Python-Code Kopie des Eingabe-Sounds def echo(sound, delay): destSound = copySound(sound) for index in range(delay): origSample = getSample(sound, index) setSample(destSound,index,int(0.6*origSample)) for index in range(delay, getLength(sound)): origSample = getSample(sound,index) echoSample = getSample(sound,index-delay) newSample = int(0.6*origSample+0.4*echoSample) setSample(destSound,index,newSample) return destSound nur Kopie wird verändert! >>> snd = makeSound("InformatikMachtSpass.wav") >>> playSound( echo(snd, 10000) ) >>> playSound( echo(snd, 20000) ) Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 21 Synthetischer Sound Z.B. Elektrische Orgeln, 1934 Synthesizer, 1964 (Moog) Prinzip: Überlagerung mehrerer Sinus-Wellen ("additive Synthese") Hörbeispiel: "Popcorn", 1969; erster nur mit Synthesizer eingespielter Pop-Hit Hammond-Orgel, wikipedia.org MIDI, 1983 "Musical Instrument Digital Interface" Befehle zur Ansteuerung von digitalen Instrumenten bzw. Soundkarten (analog zu Vektorgrafik) Hörbeispiel Moog-Synthesizer www.wendycarlos.com Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Innovation 1970er Jahre: "Wall of Synthesizers" Foto: Emerson, Lake & Palmer, 1974 (Moog-Synthesizer) Prof. B. Jung Moderne Synthesizer Foto: Kraftwerk, www.kraftwerk.com Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 22 Synthetischer Sound Generierung von Sinus-Wellen Wie viele Zyklen pro Sekunde? Wie viele Samples pro Zyklus? 0 2π Frequenz = Anzahl der Zyklen pro Sekunde Æ SamplesPerCycle = SamplingRate / Frequenz z.B. 22050 / 440 = 50.11 Wert des i.-ten Samples (i = 1…22050): π 1 Zyklus Bereich -1.0 ... +1.0: sin(i / SamplesPerCycle * 2 * pi) Multiplikation mit max. Amplitude! def sineWave(freq, amplitude = 4000): '''Generate a 1 second sine wave sound''' from math import pi, sin buildSin = makeEmptySound(1) # make a 1 sec. empty sound sr = getSamplingRate(buildSin) # e.g. 22050 samplesPerCycle = float(sr) / freq # e.g. 22050 / 440 = 50.11 for pos in range( len(buildSin) ): rawSample = sin( (pos / samplesPerCycle) * 2 * pi) sampleVal = int( amplitude*rawSample) setSample(buildSin, pos, sampleVal) return buildSin Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Synthetischer Sound Generierung von Rechteckwellen-Wellen Rechteckwellen Generierung (etwas) komplexerer Klang als Sinuswellen falls Sinus > 0 : Samplewert = Amplitude sonst: Samplewert = -Amplitude def squareWave(freq, amplitude = 4000): '''Generate a 1 second square wave sound''' from math import pi, sin buildSquare = makeEmptySound(1) # make a 1 sec. empty sound sr = getSamplingRate(buildSquare) # e.g. 22050 samplesPerCycle = float(sr) / freq # e.g. 22050 / 440 = 50.11 for pos in range( len(buildSquare) ): if sin( (pos / samplesPerCycle) * 2 * pi) >= 0: sampleVal = amplitude else: sampleVal = - amplitude setSample(buildSquare, pos, sampleVal) Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 return buildSquare 23 Synthetischer Sound – weitere Wellenformen http://commons.wikimedia.org/wiki/Image:Waveforms.png Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Ändern der Frequenz von Sounds Vorige Vorlesung: Ändern der Amplitude von Sounds Amplitude (logarithmisch) korreliert mit Lautstärke Jetzt: Ändern der Frequenz von Sounds Frequenz (logarithmisch) korreliert mit Tonhöhe Auswirkung auf Tonhöhe und Geschwindigkeit Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 24 Halbieren der Frequenz von Sounds: Idee Sample-Werte des Original-Sounds jeweils doppelt in Ziel-Sound kopieren 59 19 -1 -111 -30 18 18 0 1 2 3 4 5 6 59 59 19 19 -1 -1 -111 0 1 2 3 4 5 6 [Besser als doppeltes Kopieren wäre Interpolation der Sample-Werte] Prof. B. Jung Einführung in die Informatik, WS 2007/08 Halbieren der Frequenz: Python-Skript TU Bergakademie Freiberg Kopie des Sounds erzeugen (und später bearbeiten) def half(sound): destSound = copySound(sound) Konvertierung Float Æ Integer z.B. 1.5 Æ 1 srcIndex = 0.0 for destIndex in range( getLength(destSound) ): sample = getSample(sound, int(srcIndex) ) setSample(destSound, destIndex, sample) srcIndex = srcIndex + 0.5 return destSound >>> >>> >>> >>> >>> Prof. B. Jung Trace der Laufvariablen je Schleifendurchlauf: destIndex: 0, 1, 2, 3, 4, 5, 6, 7, … srcIndex: 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, … int(srcIndex): 0, 0, 1, 1, 2, 2, 3, 3, 4, … snd = makeSound("techno_mono.wav") playSound(snd) snd2 = half(snd) playSound(snd2) Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 25 Verringern der Frequenz um beliebigen Faktor Python-Skript (fast identisch mit vorigem Skript) def slower(sound, rate): "make the sound slower, rate should be at most 1.0" destSound = copySound(sound) srcIndex = 0.0 for destIndex in range( getLength(destSound) ): sample = getSample(sound, int(srcIndex) ) setSample(destSound, destIndex, sample) srcIndex = srcIndex + rate return destSound Trace der Laufvariablen je Schleifendurchlauf bei rate = 0.8: destIndex: 0, 1, 2, 3, 4, 5, 6, 7, … srcIndex: 0.0, 0.8, 1.6, 2.4, 3.2, 4.0, 4.8, 5.6, … int(srcIndex): 0, 0, 1, 2, 3, 4, 4, 5, … >>> snd = makeSound("techno_mono.wav") >>> snd2 = slower(snd, 0.8) >>> playSound(snd2) Prof. B. Jung TU Bergakademie Freiberg Einführung in die Informatik, WS 2007/08 Verdoppeln der Frequenz von Sounds: Idee Nur jedes zweite Sample des Original-Sounds in Ziel-Sound kopieren Falls Ziel-Sound (formal) gleiche Länge wie Original haben soll: zweite Hälfte des Ziel-Sounds: z.B. mit Nullen füllen Prof. B. Jung 59 19 -1 -111 -30 18 18 0 1 2 3 4 5 6 59 -1 -30 18 0 0 0 0 1 2 3 4 5 6 Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 26 Verdoppeln der Frequenz: Python-Skript Trace der Laufvariablen je Schleifendurchlauf: def double(sound): sourceIndex: 0, 2, 4, 6, 8 … destSound = copySound(sound) destIndex: 0,1, 2, 3, 4, 5, … destIndex = 0 for sourceIndex in range(0, len(sound), 2): value = getSample(sound, sourceIndex) setSample( destSound, destIndex, value) destIndex = destIndex + 1 # Zero out the rest of the target sound -- it's only half full! # Zeros are silent. for secondHalf in range(len(destSound)/2, len( destSound)): setSample(destSound, destIndex, 0) destIndex = destIndex + 1 return destSound >>> snd = makeSound("techno_mono.wav") >>> snd2 = double(snd) >>> playSound(snd2) Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Verdoppeln der Frequenz OHNE Auffüllen des Ziel-Sounds mit Nullen def doubleNoClear(sound): destSound = copySound(sound) destIndex = 0 for sourceIndex in range(0, getLength(sound), 2): value = getSample(sound, sourceIndex) setSample( destSound, destIndex, value) destIndex = destIndex + 1 return destSound >>> snd = makeSound("techno_mono.wav") >>> snd2 = doubleNoClear(snd) >>> playSound(snd2) Æ 2. Hälfte des neuen Sounds wie Original-Sound Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 27 Beliebiges Verändern der Frequenz von Sounds basiert auf slower-Skript def changeFreq(sound, rate): destSound = copySound(sound) srcIndex = 0.0 for destIndex in range( len(destSound) ): if srcIndex <= getLength(sound): sample = getSample(sound, int(srcIndex) ) else: # possibly fill end of sound with zeros sample = 0 wie slower-Skript, aber mit Auffüllen von Nullen, falls notwendig setSample(destSound, destIndex, sample) srcIndex = srcIndex + rate return destSound >>> playSound( changeFreq(snd, 0.8) ) >>> playSound( changeFreq(snd, 1.3) ) Prof. B. Jung # langsamer # schneller Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg Singender Eisberg entdeckt Ein Lied von Kälte und Einsamkeit Eigentlich wollten Forscher des Bremerhavener Alfred-Wegener-Instituts für Polar- und Meeresforschung seismische Signale in der Antarktis untersuchen. Als sie die Aufnahmen auswerteten, entdeckten sie völlig unerwartet ein neues Talent: ein Eisberg, der musikalisch anmutende Klänge erzeugt. Mit einer Frequenz von 0,5 Hertz ist der von den Forschern als "harmonischer Tremor" beschriebene Ton für das menschliche Ohr zwar nicht wahrnehmbar. Auf schnellerer Geschwindigkeit abgespielt hört er sich jedoch an wie ein Bienenschwarm oder ein sich warmspielendes Orchester, berichteten die Forscher. Redaktionsmitglieder von tagesschau.de fühlten sich eher an die Geräuschkulisse eines Formel-1-Rennens oder sogar an Celine Dions Lied "My Heart will go on" aus dem Film Titanic erinnert. … www.tagesschau.de, 25.11.2005 eisberg.wav Prof. B. Jung Einführung in die Informatik, WS 2007/08 TU Bergakademie Freiberg 28