Meloncillo – eine graphische Benutzeroberfläche zur musikalischen
Transcription
Meloncillo – eine graphische Benutzeroberfläche zur musikalischen
Meloncillo – eine graphische Benutzeroberfläche zur musikalischen Raumklangsteuerung mit Implementierung einer OSC-Schnittstelle zur Klangsynthese Magisterarbeit von Hanns Holger Rutz, Matr.-Nr. 192946 Technische Universität Berlin Kommunikationswissenschaft Betreuer: Prof. Dr. Stefan Weinzierl La musique du futur? Sûrement basée sur le son et au-delà des notes“ ” (Edgard Varèse 1947) Varèses Denken war empirisch. Er interessierte sich dafür, ” wie es klang – nicht wie es gemacht war.“ (Morton Feldman 1966) Die selbständige Anfertigung versichere ich an Eides Statt. Inhaltsverzeichnis 1 Einführung 1.1 Begriff der Raumklangsteuerung . . . . . . . . . . 1.1.1 Abgrenzung zu Auralisationsverfahren . . . 1.1.2 Abgrenzung zu Live-Diffusionsverfahren . . 1.2 Historische Wurzeln . . . . . . . . . . . . . . . . . 1.3 Vorhandene Software zur Raumklangsteuerung . . 1.3.1 APB-Tools Σ 1 . . . . . . . . . . . . . . . . 1.3.2 zplane.development z.matrix . . . . . . . . 1.3.3 Wonder . . . . . . . . . . . . . . . . . . . . 1.3.4 Surround Panning Objekte . . . . . . . . . 1.4 Hardware basierte Raumklangsteuerung . . . . . . 1.5 Raumklang-Synthese Plug-Ins . . . . . . . . . . . . 1.5.1 VBAP – Vector Based Amplitude Panning 1.5.2 IRCAM Spat˜ . . . . . . . . . . . . . . . . 1.5.3 Spatialisierung mit CSound . . . . . . . . . 1.6 Notwendigkeit einer neuen Raumklangsteuerung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 8 8 9 10 10 12 13 13 14 16 16 17 18 19 2 Entwicklung des Programms Meloncillo 2.1 Tendenzen in der Entwicklung von Musiksoftware . . . . 2.2 Designspezifikation für eine neue Raumklangsteuerung . 2.2.1 Trennung von Oberfläche und Signalverarbeitung 2.2.2 Abstraktion vom Synthesemodell . . . . . . . . . 2.2.3 Anwender mit und ohne Programmiererfahrung . 2.2.4 Unabhängigkeit vom Betriebssystem . . . . . . . 2.2.5 Zwei grundlegende Objekttypen . . . . . . . . . 2.2.6 Echtzeit und Offline Modus . . . . . . . . . . . . 2.2.7 Diskrete Datenströme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 20 21 21 22 23 23 24 24 25 . . . . . . . . 26 26 28 28 30 31 32 32 33 3 Programmarchitektur 3.1 Sprache und Arbeitsumgebung . . 3.2 Packages Überblick . . . . . . . . . 3.3 Session . . . . . . . . . . . . . . . . 3.4 Receiver, ReceiverCollection . . . . 3.5 Transmitter, TransmitterCollection 3.6 Timeline . . . . . . . . . . . . . . . 3.7 Events . . . . . . . . . . . . . . . . 3.8 Threads . . . . . . . . . . . . . . . . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inhaltsverzeichnis 4 Graphische Benutzeroberfläche 4.1 Surface : zweidimensionale Momentansicht 4.1.1 Hilfs-Paletten und Werkzeuge . . . 4.1.2 ReceiverEditor . . . . . . . . . . . 4.1.3 Matrix Meter . . . . . . . . . . . . 4.2 Timeline : horizontale Zeitdarstellung . . 4.2.1 Trajektorien Daten-Format . . . . 4.2.2 Transport Palette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 35 37 39 40 40 41 43 5 Plug-In Schnittstellen 5.1 Offline (Nicht-Echtzeit) . . . . . . . . 5.2 Realtime (Echtzeit) . . . . . . . . . . . 5.3 Common Lisp für Java . . . . . . . . . 5.3.1 Die LispPlugIn Klasse . . . . . 5.3.2 Ein Beispielscript . . . . . . . . 5.4 Open Sound Control . . . . . . . . . . 5.4.1 Protokollübersicht . . . . . . . 5.4.2 Implementierung in Meloncillo 5.4.3 Anbindung an SuperCollider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 44 46 49 50 51 54 54 56 57 6 Resumé 6.1 Anwendungsbeispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Probleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3 Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 62 67 68 Literaturverzeichnis 70 Anhang: Abbildungen, Quelltexte 73 4 . . . . . . . . . . . . . . . . . . 1 Einführung Die vorliegende Magisterarbeit beschreibt den Entwurf und die Realisierung einer SoftwareApplikation zur musikalischen Raumklangsteuerung. Das im wesentlichen aus einer graphischen Benutzeroberfläche bestehende Programm mit dem Namen Meloncillo“ erlaubt die ” Gestaltung von Trajektorien in einem zweidimensionalen Raum und kann in Verbindung mit einem existierenden Klangsynthese-Programm wie SuperCollider dazu verwendet werden, verräumlichte Klänge zu berechnen oder in Echtzeit abzuspielen. Für die Echtzeit-Steuerung ist eine Open Sound Control (OSC) Schnittstelle vorgesehen. Eine script-gesteuerte Plug-In Schnittstelle ermöglicht es, unterschiedliche Modelle der Verräumlichung zu benutzen. Die Arbeit ist dadurch motiviert, daß die Raumklangsteuerungen, die dem Autor bekannt sind, zu wenig gestalterische Freiheiten bieten oder nicht ohne weiteres für die heute gängigen Computer-Plattformen verfügbar sind. Das hier vorgestellte Programm soll neue Sichtweisen auf musikalische Räumlichkeit öffnen. CD-ROM Der Quelltext und die Quelltext-Dokumentation können aus Platzgründen nicht abgedruckt werden. Eine CD-ROM ist beigefügt, die alle nötigen Dateien enthält: • Quelltext • HTML Dokumentation aller Pakete und Klassen (javadoc) • Xcode IDE Projekt-Datei • kompiliertes Programm und Mac OS X Application Wrapper • externe Bibliotheken • Beispiel-Script, -Session und -Klänge 1.1 Begriff der Raumklangsteuerung Der Begriff Raumklang enthält bereits ein musikalisches Element, während die englische Übersetzung, etwa spatial sound, einen physikalischeren Charakter bekommt – sound kann rückübersetzt auch Schall heißen. Physikalische Begriffe wären Raumschall oder Raumakustik.1 Zwischen Raumklang und Raumakustik besteht ein wesentlicher Unterschied: Raumakustik beschreibt den Klang des Raumes, während Raumklang die Gestaltung von Klang im Raum meint. Da eine musikalische Aufführung meist in einem geschlossenen Raum stattfindet, muß 1 vgl. [Haller 1995], S. 75 5 1 Einführung sich der Komponist natürlich auch mit Raumakustik befassen. Das ist jedoch nicht Gegenstand dieser Arbeit. Raumakustik tritt beispielsweise nicht bei Kopfhörerübertragung oder Beschallung im offenen Feld auf. Ein anderer Fall ohne äußere Raumeinwirkung sind Körperschallübertragung und Körperstimulation durch Aktuatoren.2 Die ganz unterschiedlich akzentuierten Aspekte von Räumlichkeit sind eines der Hauptmerkmale von Klangkunst und Klanginstallation. Für einen Überblick sei auf die Artikel des Katalogs Klangkunst zum Festival Sonambiente 1996 hingewiesen3 . Ein paar Beispiele: In Bill Fontanas Klangbrücke Köln-Tokyo wird das akustische Bild zweier sehr weit voneinander entfernter Orte auf der Welt durch Satelliten-Transmission ausgetauscht. Die Arbeit steht in gewissem Kontext zu der von Murray Schafer entwickelten Idee der Klangökologie. Alvin Lucier läßt dagegen in I’m Sitting in a Room die Resonanzen der Aufführungsorte sprechen, La Monte Young verwendete stehende Wellen. In soundbits von Robin Minard wird die Räumlichkeit nicht nur durch dem Objekt Gegenüberstehen, sondern gleichfalls durch Herantreten und Entlangschreiten an diesem ausgedehnten und in die Architektur integrierten Gebilde erfahren. Die begriffliche Nähe von Raumklang und Raumakustik kann leicht zu Verwirrungen führen: Der Komponist orientiert sich am geometrischen Raum und versucht, in dessen ” erkennbaren Grenzen einen ebenfalls erkennbaren, d.h. erhörbaren Klangraum zu schaffen. Dieser Klangraum kann dem geometrischen Raum entsprechen, er muß es nicht.“ 4 Raum“ wird in zwei unterschiedlichen Bedeutungen benutzt, obwohl Hans Peter Haller ver” sucht, die Verschiedenheit durch die Attribute geometrisch respektive klanglich zu betonen.5 Viele Metaphern in der Musik sind räumlich-geometrischer Natur, so spricht man beispielsweise von einer hohen Tonlage, einer melodischen Linie oder Kontur; die Menge der verwendeten Töne bildet den Ton-Raum6 . Herbert Eimert unterscheidet neben diesem metaphorischen Raum zwischen dem Musik-Raum, der durch die Raumakustik bestimmt ist, und dem musi” kalischen Vorstellungsraum, wie er in der Phantasie des Komponisten besteht, wie er vom Hörer nachvollzogen wird und wie er sich in den Noten, im Notationsraum der aufgezeichneten Musik niederschlägt.“ 7 Wird Musik räumlich verteilt wiedergegeben, so kann dieser neue Raum für das Ohr ein gekrümmter, nicht euklidischer Raum“ sein. Eimert nennt die” sen Raum einen Raummusik-R[aum], in dem die Tonbewegung in die räumlich-plastische ” Konfiguration der Klangfelder überführt wird.“ Die Verortung dieser Arbeit wird klarer, wenn wir den Begriff der Steuerung betrachten. Haller gibt eine sehr ingenieursmäßige Beschreibung von Klangsteuerung: 2 Beim Klanganzug der Künstlerin Lynn Pook werden sechzehn Lautsprecher am Körper befestigt – Der ” menschliche Körper wird zum Klangraum“. Das Beispiel zeigt, daß Raumerfahrung nicht nur durch (echte oder simulierte) von unterschiedlichen Seiten auf das Ohr treffende Schallwellen gemacht werden kann. Dazu zählen auch einige Arbeiten von Bernhard Leitner. 3 [de la Motte-Haber 1996] 4 [Haller 1995], S. 75. Kurz davor geht Haller explizit darauf ein, daß bei der Gestaltung von Klangwegen die Interaktion mit der Raumakustik bedacht werden muß. 5 Bezeichnenderweise beginnt Martin Supper in seinem Buch über Elektronische Musik ([Supper 1997]) das Kapitel über Raumklang mit einem Zitat von Rudolf Carnap über die Konfusion, die durch die unterschiedliche Verwendung des Raumbegriffs entsteht. 6 [Eimert/Humpert 1973], S. 271f 7 ebd. 6 1 Einführung Klangsteuerung in der Elektronischen Klangumformung bedeutet weder Trans” formation noch Selektion einer Tonquelle. Sie kann für beide eine kontrollierende Funktion übernehmen, hat jedoch auf die direkte Erweiterung eines Klangspektrums keinen Einfluß. Klangsteuerung heißt – wie der Name aussagt – Steuerung von Klanginformationen jeglicher Art, von Instrumenten oder Stimmen, original oder elektronisch bearbeitet.“ 8 Anders ausgedrückt ist Klangsteuerung ein formgebender Prozeß, der auf einer hierarchisch übergeordneten Ebene stattfindet. Die Prozeßhaftigkeit, der dynamische Charakter der Klangsteuerung, wird durch weitere Bezugnahme auf Regelungstechnik wie auch die kontrollie” rende Funktion“ unterstrichen.9 In Hallers Geräten wird zur Kontrolle oft ein Mikrophon benutzt, das während der Performance eine Klangumformung steuert. In den klassischen nach MUSIC V modellierten Musiksprachen bezeichnen Kontrolldaten diejenigen Daten, die dynamisch über die Zeit – und in der Regel mit konstanter Rate abgetastet – Einfluß auf Klangparameter und -transformationen nehmen.10 Raumklangsteuerung wird nun definiert als ein Mittel zur dynamischen Formgebung von Bewegungen, Verteilungen und Transformationen von Klängen, die räumlich, das heißt über mehrere Lautsprecher wiedergeben werden sollen. Das bedeutet, daß die Mehrkanaligkeit bereits in den Klangverteilungen und -transformationen angelegt ist und explizit gestaltet werden kann. Beispiel: Wenn ein monophoner Ausgangsklang mit unterschiedlichem Frequenzgang gefiltert und auf verschiedenen Lautsprechern ausgeben wird, ist das eine Form von Raumklang, denn der Klang wurde räumlich gestaltet. Der benutzte Filter ist jedoch nur dann als Raumklangsteuerung zu bezeichnen, wenn in ihm selbst a) die dynamische, zeitveränderliche Steuerung und b) die Variation des Frequenzganges über verschiedene Ausgangskanäle (oder allgemein eine räumliche Situation) vorhanden sind. Umgekehrt wird ein Objekt zur Raumklangsteuerung, wenn es andere Objekte – ob einen Mixer oder ein Filter spielt dabei keine Rolle – dynamisch räumlich kontrolliert, zum Beispiel indem es für jeden Ausgangskanal einen separaten Filter ansteuert. Das Adjektiv in musikalischer Raumklangsteuerung soll unterstreichen, was in der eingangs zitierten Aussage Morton Feldmans über Edgard Varèse zum Ausdruck kommt, und was Trevor Wishart nur unmerklich variiert, wenn er in Audible Design schreibt: We [composers] may embark on signal-processing procedures which will appear ” bizarre to the scientifically sophisticated [...] The question we must ask as musicians however is not, are these procedures scientifically valid, or even predictable, but rather, do they produce aesthetically useful results on at least some types of sound materials.“ 11 Dies ist nicht als Aufforderung zu verstehen, unwissenschaftlich zu sein, sondern im Gegenteil, sich wissenschaftlicher Erkenntnisse zu bedienen, aber sich – also hier das Programm – nicht auf das zu beschränken, was zunächst wissenschaftlich oder physikalisch plausibel scheint. 8 [Haller 1995], S. 67. vgl. auch [Eimert/Humpert 1973], S. 328 10 Die Rate dieser Daten wird als Controlrate, abgekürzt kr, bezeichnet und liegt aus rechenökonomischen Gründen meist etwa ein bis zwei Größenordnungen unter der Abtastrate für Audiodaten. 11 [Wishart 1994], S. 5 9 7 1 Einführung Musikalische Raumklangsteuerung bedeutet sowohl, daß nicht-physikalische Raumvorstellungen umgesetzt werden können, als auch, daß Brücken zu algorithmischer Komposition vorgesehen sind. 1.1.1 Abgrenzung zu Auralisationsverfahren Auralisation ist ein Verfahren, das unter Verwendung physikalischer oder mathematischer Modelle das Schallfeld, in dem sich eine Klangquelle befindet, reproduziert und dem Hörer den Eindruck vermittelt, tatsächlich an einer bestimmten Position in diesem Schallfeld zu sein.12 Ein anderer Ausdruck ist somit Soundfield Reproduction, zu deutsch Schallfeldreproduktion, als Unterkategorie von (virtueller) Raumakustik. Die wichtigsten technischen Verfahren sind die Binauraltechnik, das heißt die Raumsimulation durch Einbezug der Kopfübertragungsfunktion (HRTF) und Wiedergabe über Kopfhörer, und die als Transaural-Technik bezeichnete Lautsprecher-Variante im reflexionsarmen Raum. Daneben wird auch die neuere Wellenfeldsynthese (WFS) als Auralisationstechnik verwendet.13 Das Ziel der Raumklangsteuerung ist nicht die Auralisation. Kurz dargestellt werden soll jedoch das WFS Programm Wonder (Abschnitt 1.3.3), da es sich explizit als musikalische Raumklangsteuerung versteht. Das in dieser Arbeit entwickelte Programm kann natürlich mit einem Auralisationsverfahren verknüpft werden, es ist allerdings nicht speziell dafür konzipiert. Insbesondere sind Binaural- und Ambisonics-Rendering durch Steuerung von CSound möglich (siehe Abschnitt 1.5.3). Es wird jedoch nicht auf die akustischen Grundlagen der Schallfeldreproduktion und des räumlichen Hörens eingegangen.14 1.1.2 Abgrenzung zu Live-Diffusionsverfahren Das Haupteinsatzgebiet der Software soll in der Komposition liegen, das heißt sie soll optimiert werden für eine Arbeitsweise, • in der die Zeitebene der Bearbeitung von der Zeitebene der Performance des Stückes entkoppelt ist • in der die Daten nichtlinear bearbeitet werden • in der sich die Bearbeitung über mehrere Sitzungen erstreckt • in der Bearbeitungen evtl. verworfen werden Dies resultiert sowohl aus persönlichen Präferenzen als auch aus der Tatsache, daß im Bereich der Live-Elektronik bereits sehr mächtige Werkzeuge vorhanden sind. Es ist nicht Aufgabe dieser Arbeit, eine Software wie Max/MSP zu überbieten, stattdessen soll genau an den Punkten angesetzt werden, die durch die weitgehende Fixierung auf Echtzeit-Fähigkeit in Max nicht oder nur ungenügend beachtet werden. Weitere Erläuterung dazu folgen in der Designspezifikation. 12 sinngemäß nach [Kleiner et al. 1993] Eine sehr knappe Einführung zu WFS geben [de Vries/Boone 1999]; eine mit Medien aufbereitete Website ist http://wfs.topicbase.net/ 14 Siehe dazu z.B. [Stuart 1996] oder [Schneider 1995], S. 1–22. Im Aufsatz von D. G. Malham wird die Schallfeldreproduktion am Ambisonics Verfahren erläutert ([Malham 1998]). 13 8 1 Einführung Aus diesem Grund wird auch nicht weiter auf spezielle Live-Diffusions-Strategien eingegangen. Kurz genannt werden soll zumindest die akusmatische Diffusion, in der in der Regel ein ein- oder zweikanaliges Stück mit Hilfe einer Live-Mischung ( Interpretation“) auf eine ” Vielzahl unterschiedlicher Lautsprecher verteilt wird, wobei die variablen Charakteristiken der Lautsprecher gezielt als instrumentale Formung des Klanges betrachtet werden.15 1.2 Historische Wurzeln Obwohl der Raum als Parameter auch in der klassischen Musik nicht unbekannt war, sich zum Beispiel in der räumlichen Aufteilung der Instrumentengruppen manifestierte, in der Ausnutzung der Raumakustik in Kirchen für Chöre usw., und ohne auf spezielle Projekte wie die utopische Universe Symphony von Charles Ives einzugehen,16 beginnt die gezieltere Auseinandersetzung mit dem Einsatz von Lautsprechern in der elektronischen und konkreten Musik, das heißt in den 50er Jahren.17 In Karlheinz Stockhausens Gesang der Jünglinge von 1956 werden fünf kreisförmig angeordnete Lautsprecher-Gruppen verwendet, die das Publikum umgeben, statt ihm frontal zu begegnen.18 Auch in der fünf Jahre davor uraufgeführten Symphonie pour un homme seul von Pierre Schaeffer und Pierre Henry (1950) werden die Klänge von im Raum verteilten Lautsprechergruppen wiedergegeben. Im Gegensatz zu Stockhausen ist diese Verteilung weniger Ergebnis eines strikten Auskomponierens, sondern geschieht durch eine Live-Interpretation auf den unterschiedlich klingenden LautsprecherInstrumenten. Neben der Erfindung des Radios als der Verräumlichung des Klanges – indem zwischen Sender und Empfänger praktisch beliebige Distanzen liegen können – ist die Auseinandersetzung mit Zeit in der Malerei als symmetrischer Gegenpart dafür zu nennen, daß Anfang des 20. Jahrhunderts die Musik begann sich zu verräumlichen. Der einer älteren Generation angehörende, nach Amerika ausgewanderte Franzose Edgard Varèse arbeitete seit 1929 am letztlich nicht realisierten Werk Espace, das diese neue Aufmerksamkeit bereits im Titel zeigt. Realisiert worden ist 1958 das bekannte Poème Électronique für den Pavillon der Firma Philips auf der Weltausstellung jenes Jahres. Mehrere hundert Lautsprecher auf den Innenflächen des von Le Corbusier und Iannis Xenakis entworfenen zeltartigen Baus standen ihm für eine räumliche Komposition zur Verfügung. Das Ausgangsmaterial von Varèse hatte die Form eines Tonbands mit drei Spuren, von denen zwei stereophonisch verteilt werden konnten und die dritte aufgezeichneten Raumhall enthielt. Die räumliche Verteilung geschah mit Hilfe von synchronen Bändern, die Steuerbefehle für Relais enthielten. Die Relais schalteten die Lautsprecher-Gruppen ein und aus, mit denen sich bestimmte Klangbewegungen realisieren ließen. Angeblich hat Varèse die Intonation“ der Bewegungen der Verantwortung der ” Ingenieure überlassen.19 15 vgl. [Gertig et al. 1995], S. 325 vgl. [de la Motte-Haber 1996], S. 209 17 Mit dem Beginn des Rundfunks datieren die ersten Lautsprecher in die 20er Jahre, vgl. [Ruschkowski 1998], S. 56–60; der Aspekt der räumlichen Wiedergabe mittels mehrerer Lautsprecher spielte dabei noch keine Rolle. 18 [Ruschkowski 1998], S. 242, 252f 19 [de la Motte-Haber 1993], S. 83–110. Nach einem Drehbuch von Le Corbusier wurden zur Musik von Varèse Dias an die Wände projiziert. 16 9 1 Einführung 1.3 Vorhandene Software zur Raumklangsteuerung Bei der Entwicklung einer neuen Software ist zunächst zu betrachten, welche bestehenden Lösungen bereits existieren und wo ihre Vorteile und Nachteile liegen. Ohne Anspruch auf Vollständigkeit und ohne auf die Vielzahl individueller Patches in Sprachen wie Max einzugehen, sollen die gängigsten Programme vorgestellt werden. Die auf Hardware basierenden Implementationen werden kurz im Anschluß dargestellt. Darauf folgt eine kursorische Übersicht über Raumklang-Syntheseverfahren, die in Form von Plug-Ins durch eine HostApplikation gesteuert werden können. Die Grundkonzepte unterscheiden sich in den meisten Fällen nicht von der Pionier-Arbeit John Chownings20 zu Beginn der 70er Jahre. Darin beschreibt er die akustischen Merkmale der räumlichen Ortung (interaurale Intensitäts- und Laufzeitunterschiede) und schlägt vor, zur Simulation räumlicher Distanz variable Reverberation und Frequenz-Filterung zu benutzen. Nach seinem Modell wird mit Hilfe von quadrophonisch den Hörer umgebenden Lautsprechern ein virtueller Raum um den tatsächlichen Abhörraum konstruiert. Die Klangquelle wird zwischen jeweils benachbarten Lautsprechern gepannt21 , durch variables Delay entsteht ein Doppler-Shift in Abhängigkeit von der Geschwindigkeit der Bewegung. Die Bewegungen können entweder mit einer mechanischen Eingabevorrichtung in Echtzeit22 oder in Form einfacher geometrischer Pfade direkt vom Computer erzeugt werden. Eine Verfeinerung dieses Prinzips wurde später unter anderen im CMusic System von F. Richard Moore vollzogen.23 Dabei werden zusätzlich die ersten Reflexionen der Klangquelle von den Wänden des virtuellen Raumes mit einer Tapped-Delay-Line simuliert. Desweiteren besitzen die Klangquellen eine Abstrahlcharakteristik, die sich aus einer richtungsabhängigen Lautstärke-Dämpfung ergibt. In CMusic können die Dimensionen der vier Wände des virtuellen und des Abhörraumes bestimmt und die Länge der Hallfahne festgelegt werden. Der Unit-Generator24 space synthetisiert den Klang im Raum. Das separate Programm sndpath dient dem Erstellen von Trajektorien-Dateien, die mit dem quad UGen in CMusic eingelesen werden können.25 1.3.1 APB-Tools Σ 1 Σ 1 (sprich Sigma-One) steht am Beginn der Betrachtung, weil es die flexibelste Raumklangsteuerung darstellt und hinsichtlich der Oberfläche als auch für die Receiver Objekte in dem hier entwickelten Programm Vorbild war. Technische Details und Funktionsweise können so- 20 [Chowning 1971] Das englische Wort Panning läßt sich leider schlecht übersetzen. Es beschreibt den Einstellvorgang des Panoramas, das heißt die Positionierung eines Klangs im (Stereo-)Bild. 22 Eine Wiedergabe in Echtzeit war noch nicht möglich; der Klang wurde nach Ende der Aufzeichnung vom Computer synthetisiert. 23 [Moore 1983] 24 Zu MUSIC-V vgl. [Ruschkowski 1998], S. 287–291. Eine Übersicht über die MUSIC-V Familie mit Verknüpfungen zum Konzept der Unit-Generatoren bietet http://www.wordiq.com/definition/MUSIC-N 25 siehe dazu [Moore 1985], S.61f, 76–78 und [Loy 1985]. Die Pfade sind durch Stützpunkte definiert, zwischen denen mit Hilfe von Spline-Funktionen interpoliert wird. 21 10 1 Einführung Abbildung 1.1: Σ 1 Oberfläche wohl in der Magisterarbeit von Thomas Schneider26 , auf deren Basis das Programm entstand, als auch im Online-Manual27 nachgelesen werden. Σ 1 ist eine Standalone-Applikation für Mac OS Classic, die über eine Mixer-Matrix bis zu 32 Eingangssignale auf bis zu 24 Ausgangskanäle verteilen kann. Die Matrix wird auf Digidesign ProTools TDM Hardware realisiert und verwendet dazu softwareseitig die Digidesign Audio Engine (DAE). Dies stellt zugleich Hauptmanko und Hauptvorteil des Programms dar. Zum einen ist teure Hardware nötig28 , zum anderen arbeitet das Programm nicht mehr mit DAE Version 5.1 und höher zusammen. Bis eine Neuauflage des Programms erscheint, muß also – da pro Bootpartition nur eine DAE existieren kann – zum Betrieb eine separate Mac OS 8 oder 9 Partition gebootet werden. Vorteil der DAE Benutzung ist die Möglichkeit, TDM Plug-Ins verwenden und direkt Spuren aus ProTools Sessions einspielen zu können, wobei allerdings nur die Regionen-Positionen und die Volume-Automation erkannt werden. Die Flexibilität des Programms resultiert, abgesehen von der hohen Zahl der Ein- und Ausgänge, aus der Möglichkeit, Schallquellen auf beliebigen zweidimensionalen Pfaden bewegen und die sogenannten virtuellen Lautsprecher frei positionieren und konfigurieren zu können. Jedem virtuellen Lautsprecher kann eine benutzerdefinierte Richtcharakteristik“ ” gegeben werden, indem zwei sogenannte Coverage-Tables editiert werden. Die Empfindlichkeit der virtuellen Lautsprecher ergibt sich dabei aus der Summe einer distanzabhängigen und einer richtungsabhängigen Dämpfung, so daß sich neben Kugel, Niere, Keule und Acht eine Vielzahl möglicher Charakteristiken ergibt. Die Oberfläche von Σ 1 besteht aus der zweidimensionalen Raumansicht, Stage genannt, einem Transport-Fenster, einem Mixer- und Aux-Fenster und einer Region-Playlist sowie einer Reihe von Werkzeug- und Aktions-spezifischen Dialogen. In Abbildung 1.1 sind Beispiele für 26 [Schneider 1995], S. 39–82. Sein Programm wurde mit Hilfe von Max und externem MIDI-Mixer realisiert, entspricht jedoch vom gesamten Konzept und der Oberfläche her dem späteren Σ 1. 27 http://apbtools.com bzw. http://apbtools.com/PDFs/SIGMA1_MANUAL.pdf 28 Pro Tools d24 + MIX Farm, Pro Tools MIX oder Pro Tools MIX Plus. Es gibt einen sogenannten OfflineModus, darin ist jedoch keine Audioausgabe möglich. 11 1 Einführung eine Stage-Anordnung (links) und Coverage-Tables (rechts) abgebildet. Die diskusförmigen Objekte in der Stage-Ebene stellen die Mittelpunkte der virtuellen Lautsprecher dar, um sie herum ist die Charakteristik durch abgestufte Farben dargestellt. Die kleinen ballförmigen Objekte stellen die beweglichen Schallquellen dar. Ihre Bewegungspfade sind als Linienzüge sichtbar. Neben der Aufzeichnung von Pfaden in Echtzeit durch Bewegen der Maus29 gibt es die Möglichkeit, im Offline-Modus Linien und Kreise zu zeichnen und Pfade zu kopieren, zu verschieben und zu löschen. Die Berechnung der Ausgangsklänge erfolgt als Intensitätspanning mit Hilfe der dynamischen M × N Matrix, die aus den M Eingangskanälen und N Ausgangskanälen besteht. Jede Zelle (m, n) enthält den Quellklang (Zeile m) multipliziert mit der Lautstärkeinformation, die aus dem Abstand des Klanges von und seinem Winkel zu einem Lautsprecher (Spalte n) gewonnen wird. Die Summierung einer Spalte ergibt das Ausgangssignal für den jeweiligen Lautsprecher. 1.3.2 zplane.development z.matrix Einen ähnlichen Ansatz wie Σ 1 verfolgt z.matrix der Firma zplane.development. Wie der Name andeutet, arbeitet z.matrix ebenfalls mit einer Matrix von Eingangs- und Ausgangskanälen, die Größe ist auf 16 × 16 beschränkt. Auch hier hat man sich auf eine HardwarePlattform festgelegt, die DSP-Karten der Firma Creamware (Pulsar und Scope), was dem Programm ähnlich wie Σ 1 fast zum Verhängnis wurde, als Creamware im Jahr 2003 Insolvenz anmelden mußte. Mittlerweile hat eine Nachfolgefirma die Creamware-Produkte übernommen, aber die Zukunft der DSP-Systeme ist noch nicht endgültig gesichert. Das Kernelement der Oberfläche ist die Surface, wieder ein zweidimensionales Momentanbild mit beweglichen Icons für Lautsprecher und Klangquellen. Daneben existieren Level-Meter für die Ein- und Ausgänge. Ein Element, das in Σ 1 nicht vorhanden ist, ist der Sweat Spot, der optimale Abhörpunkt, der bei Mehrkanalbeschallung automatisch entsteht, wenn Panning nach dem Prinzip der Phantomschallquellen arbeitet. z.matrix gleicht unterschiedliche Entfernungen der Lautsprecher zum Sweat Spot durch ein gegensätzliches Delay aus, so daß – vorausgesetzt der Hörer sitzt in einer identischen Kopie der Szenerie tatsächlich im Sweat Spot – alle direkten Wellenfronten kohärent (gleichzeitig) beim Hörer ankommen. Da aus der Forschung zum räumlichen Hören bekannt ist, daß unterschiedliche Indizien bei der Ortung in komplexer Weise zusammenwirken, versucht man hier, die Ortung durch Laufzeitunterschiede zu minimieren, so daß sie sich nur an den Intensitäten orientieren kann. Interessant ist ferner die Möglichkeit, mehrere Quellen in Master/Slave Anordnung zu gruppieren, so daß die Slave-Objekte dem Master entweder in kartesischen oder polaren Koordinaten folgen. Im Gegensatz zu Σ 1 besteht keine fixierte Pixelauflösung der Surface, sie läßt sich beliebig vergrößern, und Quellen können frei benannt werden. In z.matrix lassen sich die Lautsprecher-Charakteristiken nicht explizit einstellen, allerdings gibt es einen Divergenz-Parameter für jede Quelle und die Möglichkeit einer Lautstärken- 29 Das Handbuch erwähnt außerdem, daß ein MIDI Joystick oder Dataglove verwendet werden können, macht dazu allerdings keinerlei weitere Angaben, so daß davon auszugehen ist, daß diese Funktion noch in Planung ist (zumal das Handbuch als preliminary“ bezeichnet wird). ” 12 1 Einführung Abnahme in Abhängigkeit der Distanz einer Quelle vom Mittelpunkt der Surface. Zusätzlich ist pro Quelle ein mit variablen Delays realisierter Doppler-Effekt einschaltbar. 1.3.3 Wonder Wonder von Marije Baalman30 ist ein Akronym für Wavefield Synthesis of New Dimensions of ” Electronic Music in Realtime“. Es stellt eine Oberfläche für das Faltungsprogramm BruteFIR dar, das gemäß den Prinzipien der Wellenfeldsynthese die Eingangssignale verzögert, dämpft und filtert, bevor sie auf die einzelnen Kanäle eines Lautsprecher-Arrays gegeben werden. Um Klänge im virtuellen Raum zu bewegen, müssen die Wellenfelder dynamisch erzeugt werden, das heißt die FIR Filter kontinuierlich überblendet werden. Mit einem Raster wird festgelegt, von welchen Orten aus der Klang abstrahlen kann. Die Abstrahlung kann alternativ kugelförmig (als Punktquelle) oder planar (als ebene Welle) erfolgen. Zusätzlich können erste Reflexionen simuliert werden. Die Bewegungen können linear zwischen manuell eingegebenen Breakpoints stattfinden oder im Realtime Modus als Mausbewegung aufgezeichnet werden. Um zu gewährleisten, daß die Bewegungen synchron mit der Audiowiedergabe abgespielt werden, wird Wonder durch eine von Daniel Plewe programmierte Open Sound Control Schnittstelle ferngesteuert. Beispielsweise kann ein Max/MSP Patch gleichzeitig die Audio Dateien abspielen und BewegungsKoordinaten an Wonder senden. Sehr interessant ist die geplante Erweiterung um geometrisch ausgedehnte Klangquellen. 1.3.4 Surround Panning Objekte Mittlerweile sind die Mixer in allen gängigen Harddisk-Recording-Programmen um SurroundFähigkeiten erweitert worden. Mit den Automations-Engines dieser Programme vereint, stellen sie einfache Raumklangsteuerungen dar. Der Aufbau in den verschiedenen Programmen ähnelt sich dabei sehr stark. Die Automation geschieht meist spurorientiert, das heißt für jeden Kanalzug des Mischers existieren neben der Audiospur zusätzlich Spuren für jeden automatisierten Parameter, wie Lautstärke, Equalizer oder Panorama. Die Automation kann in der Regel live aufgezeichnet werden, also durch Bewegen von Software-Reglern mit der Maus – oder externen Controllern wie MIDI-Fadern –, während der Transport läuft. Für eine Offline-Editierung wird eine Breakpoint-Darstellung der Automationsdaten über oder unter den Audio-Regionen im Arrangier-Fenster eingeblendet. Mehrdimensionale Parameter wie ein Surround-Pan werden aus separaten eindimensionalen Werten zusammengesetzt, wie zum Beispiel Front↔Rear. Die Panner orientieren sich alle an den Filmformaten, so daß man sich lediglich entscheiden kann, ob man 5.1“ oder 10.2“ usw. mischen möchte. Die graphische Oberfläche ist eine zwei” ” dimensionale Fläche, auf der die Lautsprecher als Icons abgebildet sind, angeordnet entweder im Rechteck oder kreisförmig. Entsprechend wird das Panorama in das Informations-Paar Azimut/Divergenz oder das Tripel Front-Position/Rear-Position/Front-Rear zerlegt. Emagic 30 http://gigant.kgw.tu-berlin.de/~baalman/ 13 1 Einführung Abbildung 1.2: Panning Objekte in Digital Performer Logic Pro (Version 6) verwendet den polaren Ansatz, Digidesign ProTools TDM (Version 6) den kartesischen Ansatz mit dem Tripel-Vektor. Mark Of The Unicorn’s Digital Performer (Version 4) beinhaltet dagegen beide Modelle und darüber hinaus ein weiteres PanoramaPlug-In, das eine Reverb-Einheit und weitere akustische Modellingfunktionen wie Dopplereffekt und Kopfabschattung enthält.31 Abbildung 1.2 zeigt die Surround-Panner von Digital Performer. Von Drittanbietern gibt es diverse Plug-Ins für diese Harddisk-Recording-Programme, die auf Surround-Formate abgestimmt sind, so zum Beispiel das 360◦ Surround Tools“ Paket ” der Firma Waves, das Mixer-, Reverb-, Spatializer- und Dynamik-Plug-Ins für die TDM Schnittstelle enthält.32 Ein weiteres Beispiel ist das Reverb-Plug-In RealVerb 5.1 der Firma Kind Of Loud. Alle erhältlichen Surround-Plug-Ins hier aufzuführen, würde den Rahmen sprengen, zumal sich der Markt für Plug-Ins laufend ändert. 1.4 Hardware basierte Raumklangsteuerung Bevor Computer schnell genug waren, mußten Raumklangsteuerungen mit Hilfe von spezieller Hardware realisiert werden. Da das Anwendungsfeld kaum kommerzielles Potential besitzt – wenn man von Surround-Joysticks für Digitalpulte absieht –, handelt es meist um einzelne Spezialanfertigungen für ein Studio oder ein Projekt. Das von Hans Peter Haller und Peter Lawo gebaute Halaphon hat durch seine Verankerung im Freiburger Experimentalstudio der Heinrich-Strobel-Stiftung (Südwestrundfunk) und den Einsatz in Konzerten von beispielsweise Luigi Nono einige Bekanntheit erlangt. In der ursprünglichen Fassung von 1971 wurden die Lautstärken von vier Lautsprechern mittels spannungsgesteuerter Verstärker (VCA) geregelt.33 Jeder VCA ist mit einem Oszillator ver- 31 Inwieweit hier eine HRTF Filterung stattfindet, ist unklar. Leider stand mir das Programm nicht zur Verfügung, und MOTU bietet keinerlei Demoversionen an. Auch spricht die Produktbeschreibung von einem vierten kartesischen Panner mit der Bezeichnung n-Panner ; worin er sich von dem im Bild gezeigten TriPan unterscheidet, bleibt ebenfalls unklar. 32 siehe http://waves.com/default.asp?url=content.asp?id=56 33 Die Erläuterung folgt den Ausführungen in [Haller 1995], S. 77–90 14 1 Einführung bunden, der bestimmte Hüllkurvenverläufe realisieren kann. Durch zeitlich programmierten Ablauf der Hüllkurven und Umschalten der Zuordnung von Kanälen zu Lautsprechern lassen sich bewegte Phantomschallquellen realisieren. Das Gerät wurde im Laufe der Zeit an neue technische Entwicklungen angepaßt und die Kanalzahl erhöht. Haller griff die Ideen Chownings auf (vgl. Abschnitt 1.2), erweiterte den Signalweg im Halaphon um Harmonizer zur Simulation von Doppler-Effekten, einen Frequenz-Filter und ein Hallgerät. Die Hüllkurven konnten schließlich graphisch an einem Bildschirm erstellt, abgespeichert und wieder geladen werden. Für den Einsatz des Halaphons in Konzert-Situationen kann der Ablauf live gesteuert werden. So kann eine Klangbewegung zum Beispiel direkt durch die Dynamik des Mikrophonsignals eines Instruments verlangsamt oder beschleunigt werden. Andere Hardware basierte Systeme gehen ähnlich dem Halaphon von einer Art programmierbarem Mischpult aus. Das Problem vorhandener Mischpulte ist meist die beschränkte Zahl von Ausgangskanälen und die eingeschränkten Routingmöglichkeiten. Für den Raumklangeinsatz müssen gerade die Verteilmöglichkeiten groß sein, während die Zahl der Eingangskanäle untergeordnet ist. Ein solches umgedrehtes“ Mischpult ist der Topoph24, den Sukan” dar Kartadinata für die Installations-Projekte des Duos <sabine schäfer // joachim krebs> gebaut hat.34 Ein Hauptrechner steuert mit einem Sequenzer sowohl die Klangerzeuger – zum Beispiel Sampler – als auch per MIDI einen zweiten Computer, der Raumbeschreibungen in einzelne Steueranweisungen umrechnet, die wiederum per MIDI an den Steuercomputer des Mischpults geleitet werden. Das Mischpult verteilt die Audiosignale mit Hilfe von VCAs, die vom Steuercomputer kontrolliert werden. Ebenso verteilt die Raumklangsteuerung RKS.1 von Werner Schaller Ausgangssignale mit einem VCA-Mischer auf bis zu 24 Lautsprecher.35 Mit einem graphischen Editor können Figuren“ erstellt und per MIDI an den Mischer übertragen werden. Die für eine Figur ver” wendeten Kanäle können beliebig gewählt werden und müssen nicht benachbarte Lautsprecher repräsentieren. Das Mapping von Kanälen auf Lautsprecher kann später leicht angepaßt werden. MIDI war eine der wichtigsten Schnittstellen, um Computer mit Hardware Peripherie zu verbinden. Die Vorarbeit von Σ 1 basierte noch auf einem Max-Patch, das einen Mischer über MIDI ansteuerte. Einige Jahre früher, 1988, wurde an der TU Berlin ein MIDI Mischer gebaut, der bis zu 15 Eingangssignale auf 4 Ausgangskanäle verteilen konnte. Um einen hohen Rauschabstand zu gewährleisten, wurden dabei multiplizierende D/A Wandler statt VCAs eingesetzt. Das Programm arbeitete mit einem Nulldurchgangs-Detektor, der Knackgeräusche minimierte, die durch die grobe Rasterung der Lautstärke-Stufen entstanden. Der MIDI Mischer von Torsten Radtke wurde dann 1990 von Thomas Seelig um eine graphische Benutzeroberfläche erweitert, die auf einem Atari Computer lief. Dadurch konnten die Klangquellen geometrisch plaziert und bewegt werden.36 34 http://www.topophonien.de/2.5-w-d-topoph24.html vgl. [Hein 1999], S. 106 36 [Radtke 1988] resp. [Seelig 1990] 35 15 1 Einführung 1.5 Raumklang-Synthese Plug-Ins In diesem Abschnitt sollen einige Plug-Ins und Unit-Generatoren vorgestellt werden, die interessante Synthese-Ansätze für Raumklang darstellen, von sich aus jedoch keine oder kaum graphische Steuermöglichkeiten bieten. Im Zusammenhang mit der Entwicklung einer Steueroberfläche stellen sie potentielle Synthese- Maschinen“ dar (vgl. Abschnitte 2.2.1 und 2.2.2). ” 1.5.1 VBAP – Vector Based Amplitude Panning Vector Based Amplitude Panning ist, wie der Begriff vermuten läßt, keine feststehende Software, sondern ein bestimmtes Modell von räumlicher Klangverteilung. Dieses wurde von dem Finnländer Ville Pulkki entwickelt und steht in Form eines freien Plug-Ins für CSound, Max/ MSP und Pure Data zur Verfügung.37 VBAP verallgemeinert ein auf der sogenannten Tangenten-Regel beruhendes Modell des Stereo-Pannings auf eine beliebige zweidimensionale (2-D VBAP) oder dreidimensionale (3-D VBAP) Anordnung von Lautsprechern. Dabei erfolgt ein Amplitudenpanning über die jeweils zwei respektive drei Lautsprecher, die der Klangquelle am dichtesten sind. VBAP liefert nur die Gain-Werte, die Programm-Umgebung, in der VBAP eingesetzt wird, muß selbst dafür sorgen, daß unterschiedliche Abstände der Lautsprecher zum Hörer durch entsprechende Delays nivelliert werden, damit als auditorischer Cue nur die Intensitätsunterschiede wirken.38 Die durch die Tupel oder Tripel aufgespannten Teilebenen bzw. -räume werden so berechnet, daß sie sich nicht überschneiden und im Falle einer Bewegung der Klangquelle automatisch ein weicher Übergang von einem Teilraum in den anderen stattfindet.39 Da die Forschung ergeben hat, daß bei diesem Verfahren der Eindruck der Ausdehnung der Quelle (spread ) unterschiedlich ist, je nachdem ob ein Klang von einem oder mehreren Lautsprechern (Phantomschallquelle) abgestrahlt wird, wurde ein Divergenzverfahren integriert. Das Grundkonzept des VBAP, daß eine Quelle maximal von zwei respektive drei Lautsprechern repräsentiert wird, wird dabei durch einen Trick aufrecht erhalten: Aus einer Quelle werden mehrere beieinander liegende Quellen gemacht, die intern summiert werden. Der Abstand dieser Quellen voneinander hängt von der Höhe der gewählten Divergenz ab.40 VBAP als Plug-In allein ist noch keine vollwertige Raumklangsteuerung, allerdings läßt sich eine solche mit wenigen Klicks erstellen, wie der Max/MSP-Patch in Abbildung 1.3 zeigt. Hier wurde der Azimut-Parameter automatisiert, indem mit der Maus der Knopf im Panel links oben bewegt wird. Alternativ wird durch Klicken auf start rotation“ eine gleichmäßige ” Kreisbewegung ausgeführt.41 Als Klang wird ein Mono-Soundfile verwendet. Grundsätzlich verarbeitet ein VBAP Objekt die Steuerdaten für einen Quellklang; sollen mehrere Klänge unabhängig bewegt werden, müssen weitere VBAP Instanzen erzeugt werden. 37 http://www.acoustics.hut.fi/~ville/software/ . Dort ist auch noch ein älteres Standalone-Demo für SGI Computer zu finden. 38 vgl. [Pulkki 2001], S. 16f 39 Im Falle der dreidimensionalen Anordnung wird der Klang im Übergangspunkt nur noch von den zwei Lautsprechern abgestrahlt, die beiden Teilräumen gemeinsam sind. 40 ebd., S. 18 41 vorausgesetzt natürlich, die Lautsprecher sind, wie im define_loudspeakers Objekt zu sehen, kreisförmig angeordnet. 16 1 Einführung Abbildung 1.3: VBAP Anwendung in Max/MSP Das Lautsprecher-Setup im abgebildeten Patch ist kreisförmig in der horizontalen Ebene (2D), daher wird die Bewegung in der Vertikalen (Elevation 42 ) nicht benutzt. Die Divergenz läßt sich mit dem Schieberegler einstellen. 1.5.2 IRCAM Spat˜ Das Spat˜ Plug-In, von Jean-Marc Jot und Olivier Warusfel am IRCAM entwickelt,43 hat einen integrierteren Ansatz als VBAP. Das kommerziell vertriebene Paket besteht aus einer Reihe zusammengehöriger Objekte für Max/MSP oder IRCAM’s jMax. Insgesamt vier Stufen durchläuft ein Klang, bis er an den Ausgangskanälen oder Lautsprechern angelangt: • Source~ versieht ein Quellsignal mit einer optionalen Entzerrung und variablem Delay, womit ein Doppler Effekt erzeugt werden kann • Room~ ist eine synthetische Multikanal-Reverb-Einheit • Pan~ verteilt die Quelle und das Hallsignal im Raum • Out~ versieht die zu den Ausgangskanälen geleiteten Klänge mit einer optionalen Entzerrung und einstellbarem Delay und kompensiert so Nichtlinearitäten im Frequenzgang der Lautsprecher und deren Abstand vom Hörer Prinzipiell lassen sich die Objekte einzeln benutzen, beispielsweise kann ein Klang direkt in den Panner geschickt und dessen Output direkt an Lautsprecher gegeben werden, wenn man auf psychoakustische Modellierung und virtuellen Hall verzichten möchte. Etwas ungewöhnlich mag die Reihenfolge der Module wirken, wonach der Panner hinter dem Hallobjekt sitzt. Der Grund dafür ist, daß in Pan~ die Lautsprecher-Konfiguration bestimmt wird. Das Room~ Objekt produziert einen formatunabhängigen Hall, der dann in Pan~ je nach Aufstellung der Lautsprecher mit einer Ambisonics-Matrizierung verteilt wird. 42 43 im VBAP External das dritte Inlet siehe [Jot/Warusfel 1995] 17 1 Einführung Abbildung 1.4: Perzeptive Parameter in Spat˜ Das Pan~-Objekt von Spat˜ erlaubt bis zu acht Lautsprecher in einer horizontalen Ebene mit einstellbaren Winkeln. Für Kopfhörer-Wiedergabe kann auch eine Binaural-Faltung benutzt werden. Die Positionierung der Quelle wird wie beim VBAP mit den Parametern Azimut und Elevation eingestellt, allerdings läßt sich ein Quellsignal im Source~ Objekt verzögern und mit dem Raumprozessor so bearbeiten, daß Nähe- oder Ferne-Effekte entstehen. Für jede der vier genannten Signal-Stufen gibt es ein Low-Level Kontroll-Objekt, mit dem die wichtigsten Parameter eingestellt werden können, beispielsweise Room_ für die Earlyund Late-Reflections-Charakteristik des Room~ Objekts. Für Spat~ selbst wurde der spezielle Spat_OPer Patch entwickelt, der in Abbildung 1.4 zu sehen ist. Spat_OPer enthält perzeptions-basierte“ Parameter, die dann intern auf die DSP Parameter umgerechnet wer” den. Statt direkt die Raumgröße in physikalischen Einheiten bestimmen zu können, hat man sich dafür entschieden, qualitative Parameter zu benutzen. Interessant ist vor allem der Subpatcher, der sich hinter der Bezeichnung radiation verbirgt. Er enthält eigentlich nur zwei parametrische Dreiband-Equalizer. Mit einer geeigneten dynamischen Steuerung jedoch kann die Klangfarben-Änderung simuliert werden, die entsteht, wenn eine Klangquelle mit richtungsabhängiger Abstrahlung bewegt wird. Eine einfache Steueroberfläche wird bereits in Form des Circ Patchers von Gerhard Eckel mitgeliefert. Bis zu drei Klangquellen können auf einem quadratischen Feld bewegt werden. Neben Azimut und Distanz wird auch die Abstrahlcharakteristik in Form eines Kreissegments dargestellt. Die Kontrolldaten von Circ können mit den Spat_Circ und Pan_Circ Patches so umgerechnet werden, daß die Klangquelle entsprechend der Mausbewegung folgt und die Radiation-Filterkurven verändert werden. 1.5.3 Spatialisierung mit CSound Für CSound existieren verschiedene Verräumlichungs-Opcodes. Neben dem beschriebenen VBAP gibt es die einfachen quadrophonen Panner locsig (polar), pan und space (kartesisch), einen Ambisonics-Panner namens spat3d und einen Binaural-Panner namens hrtfer. Der Ambisonics-Panner benötigt als Parameter die Position der Klangquelle (x, y, z). Eine Verzögerung ist ebenfalls vorgesehen, diese läßt sich allerdings nicht dynamisch verändern – in diesem Fall muß ein anderer CSound Opcode wie vdelayx benutzt werden. Für die Generierung von Nachhall kann eine spezielle Tabelle angegeben werden, die die Distanzen und Absorptionswerte für die sechs Wände eines virtuellen kubischen Raumes beschreibt. 18 1 Einführung spat3d erzeugt ausgangsseitig die vier B-Format Signale W, X, Y, Z. Diese kann man sich als virtuelle Aufnahmen eines Soundfield-Mikrophons vorstellen, das aus drei orthogonalen Achter-Charakteristiken und einer Kugel besteht. Mit geeigneten Matrizierungsformeln lassen sich daraus Signale für beliebig angeordnete Lautsprecher gewinnen.44 spat3d beinhaltet außerdem eine Stereo-Mixdown Option. Der Binaural-Panner hrtfer benötigt eine Datei mit Impulsantworten für die Kopfübertragungsfunktion. Das Format ist leider nicht dokumentiert, jedoch gibt es eine entsprechende Datei auf dem CSound FTP Server. Die Synthese-Parameter sind Azimut und Elevation, eine entfernungsabhängige Dämpfung oder Verhallung muß separat programmiert werden. 1.6 Notwendigkeit einer neuen Raumklangsteuerung Das Feld an Raumklang-Software, die flexibel zu gebrauchen ist, ohne daß der Komponist selbst umfangreiche Programmierarbeiten erledigen muß, ist also recht übersichtlich. Auf die Einführung der DVD und die zunehmende Verbreitung kleiner Surroundsysteme in Wohnzimmerkinos haben zwar alle Hersteller gängiger kommerzieller Software mit der Erweiterung ihrer Produkte um Surround-Ausgabe-Möglichkeiten reagiert. Viel mehr als eine leichte Extrapolation der bisherigen Stereo-Technologien hat dabei aber kaum stattgefunden. Eine Raumklang-Steuerung, die einfach zu bedienen ist, dabei jedoch größtmögliche Flexibilität bietet und den Benutzer nicht auf ein enges Anwendungsfeld beschränkt, die außerdem einen kompositorischen Umgang mit Raumgestaltung nicht nur erlaubt sondern auch fördert, und mit der an bereits bestehende Klangsynthese-Software angeknüpft werden kann, ist eine Lücke, die mit diesem Magisterarbeitsprojekt geschlossen werden soll. 44 Zu Ambisonics und dem B-Format siehe [Malham 1998]. 19 2 Entwicklung des Programms Meloncillo 2.1 Tendenzen in der Entwicklung von Musiksoftware In der gegenwärtigen Entwicklung von Software im Bereich experimenteller Musik sind folgende Tendenzen zu entdecken: Zum einen das rasche Anwachsen der Open-Source Community, das heißt der Entwicklung von Programmen, deren Quelltexte öffentlich zugänglich sind und die oft in gemeinsamer Arbeit mehrerer Programmierern entstehen. Zu nennen sind CSound – an Universitäten entstanden, war es bereits vor der Entwicklung im Open-Source Verfahren kostenlos zugänglich –, SuperCollider, das im Zuge des Wechsels des Autors James McCartney zu Apple Inc. in ein Open-Source Projekt umgewandelt wurde, zahlreiche kleinere Programme wie RTcmix, und auch ein Teil der IRCAM Software – vielleicht am beachtlichsten, wenn man die ansonsten eher verschlossene Vertriebspolitik bedenkt –, darunter die graphische Klangsynthese-Sprache jMax und eine Umgebung für algorithmische Komposition, OpenMusic. Für das Betriebssystem Linux, das selbst Open-Source ist, entwickelt sich momentan eine eigene Audio Community. Mit den Soundeditoren snd und Audacity, dem MIDI Sequenzer Rosegarden und dem Harddisk-Recording-Tool Ardour, den plattformübergreifenden Klangsynthese-Programmen jMax, SuperCollider, CSound und Pure Data sowie der Unterstützung professioneller Soundkarten u.a. von RME steht eine günstige Arbeitsumgebung bereit. Eine logische Folge daraus ist, daß Programmierer viel mehr Möglichkeiten haben, Schnittstellen zwischen diesen Programmen zu entwerfen. Auch kommerzielle Musiksoftwarefirmen sind sich bewußt, daß sie den Mehrwert ihrer gewerblich angebotenen Programme erheblich steigern können, wenn sie eine Entwicklergemeinde finden, die für eine Schnittstelle programmiert, die ihre Software unterstützt. Als wichtiger Anstoß darf die Einführung des VST PlugIn Standards der Firma Steinberg gelten, der sich schnell auf mehreren Rechnerplattformen und über die Basisapplikation Cubase hinaus durchgesetzt hat. Der Wunsch, mehrere Audioprogramme miteinander zu verbinden, manifestiert sich seitdem in zahlreichen Schnittstellen. Im kommerziellen Sektor ist ReWire zu nennen, einer gemeinsamen Entwicklung der Firmen Propellerhead und Steinberg. Im Open-Source Bereich ist ein ähnlicher Versuch mit dem virtuellen Patchsystem Jack zu beobachten, einer zunächst auf Linux entwickelten Audiotreiber-Schnittstelle, die mittlerweile auch auf den anderen Rechnerplattformen verfügbar ist und die u.a. von SuperCollider, jMax, PD, Ardour, Rosegarden und snd unterstützt wird. Die durchschlagendste Entwicklung im Open-Source Bereich dagegen beschäftigt sich nicht direkt mit dem Transport von Audioströmen, sondern der gegenseitigen Kontrolle und Highlevel-Steuerung von Programmen. Es handelt sich um ein Kommunikationsprotokoll mit dem Namen Open Sound Control (OSC), das von Matt Wright und Adrian Freed am Zentrum für Neue Musik und Audiotechnologie CNMAT (Universität Berkeley) entwickelt wurde. 20 2 Entwicklung des Programms Meloncillo In gewisser Weise als inoffizieller Nachfolger von MIDI1 gedacht, werden in OSC mit einem Textkommando beginnende Nachrichten versandt. Definiert ist nur die Syntax, welche konkreten Befehle eine Applikation versteht, ist dabei nicht festgelegt. OSC eignet sich damit besonders für offene Systeme, die der Benutzer zum Teil oder vollständig selbst programmieren kann, wie SuperCollider, dessen Synthese-Engine in der Version 3 vollständig über OSC gesteuert wird und das damit als Paradebeispiel für OSC gelten kann, Max/MSP oder Pure Data (PD). Damit wird es zum ersten Mal möglich, daß zum Beispiel ein Max/MSP Patch Teile oder die gesamte Klangsynthese an SuperCollider delegiert und sich auf die graphische Oberfläche als wesentliche Stärke von Max konzentrieren kann.2 Und dies, ohne daß der Anwender einen C-Compiler bedienen und eigene sogenannte Externals oder Unit-Generatoren programmieren muß. Ein wichtiger Aspekt in der Entwicklung neuer Musiksoftware wird damit die Anstrengung sein, Stärken bereits bestehender Systeme auf neue Art und Weise miteinander zu verknüpfen. 2.2 Designspezifikation für eine neue Raumklangsteuerung Die Kernelemente der neuen Software sollen sein: • Trennung von Oberfläche und Signalverarbeitung. Dabei weitgehende Beschränkung auf eine graphische Benutzeroberfläche und Rückgriff auf externe klanggenerierende Programme • Abstraktion der Oberfläche von dem zugrundeliegenden Synthesemodell • Unterstützung sowohl von Anwendern ohne Programmiererfahrung, als auch von solchen, die mittels Musikprogrammiersprachen weitergehenden Einfluß auf die BewegungsGestaltung und Klangsynthese nehmen möchten • Betriebssystemunabhängige Implementierung Desweiteren wurden folgende Entscheidungen zur Programmarchitektur gefällt: • Komplementarität aus zwei grundlegenden Objekttypen • Komplementarität aus Echtzeit und Offline Anwendung mit Schwerpunkt auf NichtEchtzeit-Betrieb • Diskretisierung von Datenströmen Die genannten Aspekte werden im folgenden erläutert: 2.2.1 Trennung von Oberfläche und Signalverarbeitung Da für die Entwicklung einer graphischen Benutzeroberfläche und eines SignalverarbeitungsKernels grundsätzlich andere Programmiertechniken verwendet werden – weil auch verschie- 1 2 Ein Überblick über die MIDI Schnittstelle ist zum Beispiel in [Ruschkowski 1998], S. 371–412 zu finden. Tatsächlich war Pyrite“, ein Vorläufer der SuperCollider Language Application, einmal ein Max Objekt, ” vgl. [McCartney 1996] 21 2 Entwicklung des Programms Meloncillo dene Designziele existieren3 –, spricht vieles für eine Trennung dieser beiden Programmteile. Sind diese Teile hinreichend modularisiert, ergibt sich vor allem der Vorteil, daß größere Änderungen in einem Teil vorgenommen werden können, ohne in den jeweils anderen Part eingreifen zu müssen. Dieselbe Oberfläche kann möglicherweise mit unterschiedlichen austauschbaren Signalverarbeitungs-Modulen arbeiten und umgekehrt. Außerdem können Alterungserscheinungen abgefedert werden: This architecture allows to define user-interfaces that provide access to exactly ” the functionality that is needed by the user, while the back-end can be scaled to a compromise between the current needs and the hardware possiblities.“ 4 Die gegenwärtigen Klangsynthese Programme sind vom Gesichtspunkt der Signalverarbeitung sehr ausgereift und effizient. Dies kann dagegen nicht von ihren Benutzeroberflächen gesagt werden, wenn man SuperCollider oder CSound betrachtet. Max/MSP hat eine sehr ausgereifte Benutzeroberfläche, die Programmierung größer angelegter Patches kann jedoch leicht unübersichtlich werden, und das Programm ist sehr stark auf den Echtzeit Betrieb ausgerichtet. Von normalen Desktop Anwendungen erwartete Features wie Drag-and-Drop oder Clipboard Austausch sind höchstens rudimentär vorhanden. Eine klare Trennung von einem Patch als Instrument und den eingestellten Parametern als Dokument oder Stück ist nicht vorhanden. Die zu entwickelnde Software soll sich aus dieser Überlegung heraus weitgehend auf die Oberfläche konzentrieren und im Falle der Signalverarbeitung die Stärken der vorhandenen Programme nutzen. 2.2.2 Abstraktion vom Synthesemodell In dem Moment, wo die Oberfläche prinzipiell von der Signalverarbeitung getrennt ist, läßt sich noch ein weiterer Abstraktionsschritt vollführen: Zwischen die Datenstrukturen, die hinter den Oberflächen-Elementen verborgen sind, und der Klangsynthese wird eine Vermittlungsinstanz eingesetzt, die dafür sorgt, daß sich trotz einheitlicher Oberfläche unterschiedliche Arten oder Modelle von Signalverarbeitungen realisieren lassen. Diese Instanz soll eine kompakte und leicht zu programmierende Script-Sprache sein. Das bedeutet zum Beispiel, daß Meloncillo weder zu wissen braucht, in welchem exakten Format und in welcher Reihenfolge die Syntheseengine die Quelldaten benötigt, noch, ob bei der Synthese eine reine Amplituden-Matrizierung oder eine Kombination mit Filtern oder Delays verwendet wird. Dies ist die Voraussetzung dafür, daß verschiedene Programme als Syntheseengines benutzt werden können, ohne auf deren Eigenheiten und Stärken verzichten zu müssen. 3 Während es in der Signalverarbeitung vor allem um Recheneffizienz und -genauigkeit geht, muß eine Oberfläche in erster Linie Anforderungen an Ergonomie und Konsistenz mit betriebssystemspezifischen StyleGuides erfüllen. Die Programmierung des Oberfläche legt grundsätzlich viel stärkeres Gewicht auf die Wartbarkeit und Flexibilität des Quellcodes, auch wenn dies nicht immer mit bestmöglicher Performanz vereinbar ist. Da das Event-Handling nicht auf exaktes Timing angewiesen ist, können hier andere Entwurfsschemata verwendet werden. 4 [Zmölnig et al. 2003]. Der Autor weist auch auf den Vorteil hin, Oberfläche und Audio-Engine auf verschiedenen Rechnern laufen lassen zu können. 22 2 Entwicklung des Programms Meloncillo Diese Abstraktion ist zugleich der Garant dafür, daß ein Komponist mit Meloncillo neue Ideen verwirklichen kann, ohne daß jede Idee in der Programmstruktur a priori vorgedacht worden sein muß. Das weiche Element zwischen Oberfläche und DSP Instanz federt die Erfordernis ab, bei Entwürfen zu neuen Klangsynthese-Verfahren wieder in den Quelltext von Meloncillo eingreifen zu müssen. 2.2.3 Anwender mit und ohne Programmiererfahrung In der elektroakustischen Musik sind zwei unterschiedliche Künstler-Charaktere anzutreffen: Die einen finden Gefallen daran, selbst die instrumentalen Grundlagen ihrer Stücke zu entwickeln – die ja, anders als in der Instrumentalmusik, nicht automatisch gegeben sind – oder musikalische Strukturen mit Hilfe von Algorithmen zu erzeugen. Sie besitzen Programmiererfahrung und begegnen rein graphisch orientierten Programmen mit Skepsis. Die andere Gruppe entwickelt ihre kompositorischen Vorstellungen eher unabhängig von den technischen Rahmenbedingungen der Software und sucht nach Mitteln, diese Vorstellungen mit möglichst intuitiv zu bedienenden Programmen umzusetzen. Der Gedanke, ästhetische Ideen ingenieursmäßig auf technische Abläufe herunterzubrechen, schreckt sie ab. Die graphische Oberfläche soll so gestaltet werden, daß sie von Benutzern bedient werden kann, deren Computer-Kenntnisse nicht viel weiter reichen als nötig ist, um mit ProTools zu arbeiten. Der tiefere Eingriff in das Programm und die Verknüpfung mit anderen Programmen wie CSound oder SuperCollider soll durch Definition von Plug-In Schnittstellen geöffnet werden. 2.2.4 Unabhängigkeit vom Betriebssystem Applikationen, die über den reinen Charakter eines Utility“ hinausgehen, haben in der Regel ” eine längere Lebensdauer als das Betriebssystem, für das sie ursprünglich vorgesehen waren. Dies gilt selbstredend für Programme mit langer Tradition wie CSound, Max, CDP oder die IRCAM Software. Aber auch jüngere Programme waren beispielsweise von dem Neuanfang Apple’s mit Mac OS X betroffen. Eine zu enge Festlegung auf ein bestimmtes Betriebssystem kann das frühzeitige Ende eines Programmes bedeuten, wenn Zeit oder Geld fehlen, jede Migration mitzumachen, oder wenn eine Plattform mehr oder weniger komplett verschwindet wie im Falle von Atari, NeXT oder SGI. Benutzer sind oft gezwungen, sich für eine bestimmte Plattform zu entscheiden, weil es ihr Geldbeutel diktiert, weil eine bestimmte für sie wichtige Software nur auf dieser Plattform existiert, oder weil sie in einem Studio arbeiten, das auf diese Plattform ausgerichtet ist. Die momentan wichtigsten Betriebssysteme im Musikkontext sind Mac OS X, Linux und Windows XP. Mit den meisten Sprachen läßt sich plattformunabhängig programmieren. Schwierigkeiten entstehen dann, wenn über eine reine Consolen-Ausgabe hinaus zum Beispiel eine graphische Oberfläche oder Interaktion mit der Computer-Peripherie (Audio-Hardware) gewünscht sind. Folgende Möglichkeiten stehen zur Verfügung: 23 2 Entwicklung des Programms Meloncillo • eine Sprache mit plattformunabhängigen Bibliotheken wie Java. • kommerzielle Produkte wie Xanalysis LispWorks5 , die auf den drei genannten Plattformen einschließlich der Bibliotheken kompilieren. Der Preis von LispWorks beträgt 1000 $, eine Weiterentwicklung als Open-Source Projekt scheidet damit auch aus. • eine plattformunabhängige Sprache wie ANSI C oder C++, die mit freien Bibliotheken gelinkt wird. Verbreitet ist Trolltech’s QT Bibliothek6 , die allerdings entweder unter der GPL (siehe Abschnitt 3.1) oder kostenpflichtig lizensiert ist. Eine Alternative ist die Verwendung von Tk/Tcl; die Flexibilität und Ästhetik der erstellten GUIs ist eher bescheiden.7 2.2.5 Zwei grundlegende Objekttypen Bei der Betrachtung der vorhandenen Raumklang-Software fällt auf, daß die graphische Oberfläche meist zwei Typen von Objekten kennt: Klangquellen und Lautsprecher. Diese korrespondieren im Signalfluß mit den Eingängen und Ausgängen. Die Beschränkung auf zwei interagierende Objekte trägt dazu bei, daß die Struktur des Programmes sehr klar bleibt. Die feste Rollenzuteilung steht einer flexiblen Anwendung jedoch im Wege. Diese zwei Objekte sollen also rollenunabhängig sein und dennoch komplementäre, sich ergänzende Eigenschaften besitzen: • Ein Receiver ist ein statisches Objekt, das eine flächenförmige Ausdehnung besitzt und seine Charakteristik – genannt Sensitivität – aus einer Funktion des Ortes auf dieser Fläche gewinnt. • Ein Transmitter ist ein punktförmiges Objekt, das seine Charakteristik aus einer Bewegung als Funktion der Zeit gewinnt. Die Bezeichnungen wurden aus Ermangelung besserer Begriffe gewählt und sollen nicht darüber hinweg täuschen, daß ein Receiver keinesfalls die Rolle eines passiven und ein Transmitter keinesfalls die Rolle eines aktiven Elements übernehmen muß. Vielmehr stehen beide in einer Beziehung zueinander, die je nach gewähltem Synthesemodell nutzbar gemacht werden kann. Obgleich zum Beispiel die Receiver rein optisch den virtuellen Lautsprechern von Σ 1 ähneln, können sie auch Klangfelder repräsentieren, die durch Transmitter als bewegte ” Mikrophone“ abgetastet werden. 2.2.6 Echtzeit und Offline Modus Im Prozeß des Komponierens gibt es unterschiedliche, sich abwechselnde Formen von Zeit (vgl. Abschnitt 1.1.2). Ein Stück kann über die Dauer von Wochen bis Jahren entstehen, die einzelnen Sektionen müssen nicht chronologisch gewachsen sein. Der Vorteil von schnellen Computern – der auch ein Nachteil sein kann – ist die Möglichkeit, unmittelbar die Resultate eines halbfertigen Stückes anhören zu können. Es ist also anzustreben, daß an dem 5 http://www.lispworks.com/ http://www.trolltech.com/products/qt/ 7 Der CSound Frontend Cecilia ist ein Beispiel für eine gelungene Nutzung von Tk/Tcl. Trevor Wisharts Soundloom Frontend für CDP ist ebenfalls in Tk/Tcl geschrieben. Ebenso die Oberfläche von Pure Data. Ein halbwegs angenehmes Arbeitsgefühl will sich jedoch – zumindest unter Mac OS X – nicht einstellen. 6 24 2 Entwicklung des Programms Meloncillo Stück gearbeitet werden kann, indem die performative Zeit des Stücks angehalten wird und beispielsweise Teile verkürzt oder umgruppiert werden, und zugleich in Echtzeit kontrolliert werden kann, ob das Ergebnis den Wünschen entspricht. Da vielfach auch eine gestische Beschreibung von räumlichen Bewegungen gewünscht ist, sollen solche Gesten in Echtzeit aufgezeichnet werden können. Ein Offline Modus ist auch vom signalverarbeitungstechnischen Gesichtspunkt wünschenswert, weil dadurch Modelle realisiert werden können, deren Berechnung in Echtzeit aus Gründen der CPU-Kapazität derzeit ausscheidet. 2.2.7 Diskrete Datenströme Die Funktionswerte der in Abschnitt 2.2.5 genannten Basisobjekte können analytischer und diskretisierter Natur sein. Eine analytische Beschreibung eines Receivers wäre etwa: Die Sensitivität ist umgekehrt proportional zur Entfernung (f (d) ∼ 1/d). Eine diskretisierte Beschreibung wäre: gegeben sei eine Tabelle mit 1000 Punkten, die durch Abtastung der Funktion f (dn ) = 1/dn ; dn = n · extent/1000 entstanden ist. Die Sensitivität an einem Punkt mit dem Abstand d vom Receiver entspricht dem Tabellenwert mit dem Index round(d · 1000/extent). Entsprechend kann die Bewegung eines Transmitters analytisch durch eine beliebige Kette von Funktions-Abschnitten gedacht werden: Der Transmitter bewege sich zwischen Sekunde 10 und Sekunde 20 mit konstanter Geschwindigkeit von Punkt (0.25, 0.25) nach Punkt (0.667, 0.8). Die diskrete Beschreibung wiederum wäre eine Abtastung dieser analytischen Funktion an gleichmäßig voneinander entfernten Stützpunkten. Der Vorteil einer analytischen Beschreibung ist die Exaktheit, denn durch die Abtastung entstehen zwangsläufig Aliasing-Fehler. Eine analytische Beschreibung ist auch viel kompakter, denn im vorangegangenen Beispiel wird die Linie durch zwei Punkte beschrieben, während eine Abtastung bei 100 Hz für die Bewegung über zehn Sekunden bereits 1000 Punkte benötigt. Soll zu einem späteren Zeitpunkt die Linie verkürzt oder verlängert oder verlagert werden, so entstehen keine Artefakte und die gesamte Komposition bleibt sehr sauber“. ” Die Abtastung hat jedoch entscheidende Vorteile: Der Datenstrom kann an beliebigen Stellen zerschnitten und umgeordnet werden, ohne daß dadurch kompliziertere Berechnungen nötig sind. Bei einer Beschreibung mit Hilfe von Breakpoints müssen in diesem Fall neue Punkte eingefügt werden. Soll jetzt zusätzlich eine Sektion rotiert werden, beginnt die Umrechnung der Breakpoint-Funktionen kompliziert zu werden, es sind trigonometrische Funktions-Abschnitte nötig. Soll weiterhin eine Unregelmäßigkeit erzeugt werden, kann dem diskreten Datenstrom einfach Rauschen hinzugefügt werden; in der Breakpoint-Darstellung ist dies nicht möglich, es müßten also zahlreiche zufällige Punkte erzeugt werden, womit man de facto bei einer gesampelten Funktion endet und zugleich einen immensen Verwaltungsaufwand hat. Der Vorteil der diskreten Datenströme ist ferner, daß der Datendurchsatz unabhängig von der Editierung konstant bleibt. Aus diesen Gründen soll zumindest den Transmittern ein diskretes Modell zugrundegelegt werden. Für die Receiver spielt die Wahl eine eher untergeordnete Rolle. Obwohl bekannt ist, daß das Ohr eine relativ schlechte räumliche Auflösung besitzt, sollen die Samples der Transmitter-Trajektorien eine Auflösung von 32-Bit Floating Point und eine beliebige Abtastrate haben. So wird auch durch wiederholte Transformationen die Signalqualität nicht frühzeitig beeinträchtigt. Der Benutzer kann die Rate seinen Wünschen gemäß anpassen und beispielsweise mit Modulationen im Audio-Frequenzbereich experimentieren. 25 3 Programmarchitektur Konventionen Im Fließtext werden programmiersprachliche Schlüsselwörter, Namen von Klassen, Paketen und Variablen in Schreibmaschinenschrift gesetzt. In den Klassendiagrammen wird eine Auszeichnung nach Abbildung 3.1 vorgenommen. 3.1 Sprache und Arbeitsumgebung Meloncillo wurde mit Java 1.4.2 SE entwickelt1 . Als integrierte Programmierumgebung (IDE) diente Apple Xcode Version 1.12 . Die Entwicklung fand auf einem G4/800 mit Mac OS 10.3 statt. Interface implementor/ subclass Ein Kernelement von Java ist jedoch die Möglichkeit, vollkommen Abstract Class plattformunabhängige Programme zu erstellen. Voraussetzung ist, daß auf der Zielplattform eine sogenannte Virtual Machine (VM) Class verfügbar ist. Die VM enthält einen Just-in-Time (JIT) Compiler, der die vorkompilierten Java Klassen in dem Moment, in dem instance variable sie benötigt werden, übersetzt. Eine Vielzahl der Bibliotheken des instanceof Standard-API arbeitet sehr eng mit nativen (plattformabhängigen) Collection Bibliotheken zusammen – dies gilt beispielsweise für die GraphikAusgabe –, so daß die Performance von Java Applikationen im allgemeinen sehr hoch ist. Als für Echtzeitanwendungen hinderlich wird oft angesehen, daß der Programmierer keine Kontrolle über Abbildung 3.1: Legende den automatischen Garbage-Collector hat3 . Tatsächlich entscheidender ist das Fehlen von präzisen Clock Objekten, die erst für kommende Java Versionen angekündigt sind. Dieses Problem wird bei der Echtzeit-Schnittstelle erläutert. 1 Zur Sprachspezifikation von Java siehe [Gosling et al. 2000]. Diese hat sich über die verschiedenen Versionen praktisch nicht geändert, neu in Version 1.4 ist lediglich das Konzept der Assertions (siehe http://java. sun.com/j2se/1.4.2/docs/guide/lang/assert.html) Die wesentlichen Änderungen zu Vorgängerversionen bestehen stets aus der Erweiterung der Bibliotheken. Wichtige Bibliotheken von Version 1.4, auf die in Meloncillo zurückgegriffen wird, sind u.a. die java.util.prefs (für Preferences) und java.nio (NewI/O für Eingabe- und Ausgabeströme) Packages. SE ist die Standard-Edition von Java, deren SDK frei erhältlich ist, daneben gibt es noch eine Enterprise-Edition (EE), die hier jedoch keine Rolle spielt. 2 kurz vor Fertigstellung wurde auf Version 1.5 gewechselt 3 Im Gegensatz zu C++ werden in Java nur in Ausnahmefällen finalize Methoden, d.h. Methoden zur Freigabe von Ressourcen nicht mehr benötigter Objekte, explizit benutzt. Stattdessen verfolgt der GarbageCollector, wann ein Objekt nicht mehr referenziert wird und damit freigegeben werden kann. Diese Freigaben erfolgen in unregelmäßigen Intervallen und können damit das Echtzeit-Timing beeinträchtigen. 26 3 Programmarchitektur Meloncillo wurde erfolgreich auf Mac OS X und mit der Sun VM auf Windows XP und Linux/KDE getestet. Sun’s Linux Support beschränkt sich auf Intel-Prozessoren, auf PowerPC (Macintosh) Computern ist eine alternative VM wie Blackdown erforderlich. Die Blackdown PPC Version reicht momentan leider nur bis Java 1.2.2.4 Java wurde als Sprache gewählt, weil der objekt-orientierte Ansatz (OOP) sich hervorragend für die Entwicklung modularer Systeme eignet. Da der Hauptaspekt von Meloncillo auf der Programmierung der graphischen Oberfläche liegt, spielt Java hier mit den Technologien Swing und Java2D seine Vorteile gegenüber C++ aus. Swing ist eine umfangreiche Bibliothek zum Erzeugen von GUI Objekten wie Fenstern, Menüs, Buttons, Listen, Textfeldern usw. Es bietet ein ausgereiftes Event-Management5 und eine Vielzahl von Layout-Managern6 an. Für das tatsächliche Aussehen der GUI Elemente wird ein austauschbares Look-and-Feel verwendet, so daß sich Java Programme an die Optik nativer Programme anlehnen können. Java2D ist eine Graphikbibliothek für zweidimensionale Oberflächen, auf die später noch genauer eingegangen wird. Im Zuge der Anbindung von Meloncillo an Open Sound Control kann auf die Packages java.net (Netzwerk-Funktionen) und java.nio (Input/Output Funktionen und Buffer) zurückgegriffen werden. Durch die automatische Garbage-Collection und umfangreiche Debugging Möglichkeiten zur Laufzeit (Java Reflection) wird die Programmentwicklung und -wartung erheblich erleichtert. Nicht zuletzt ausschlaggebend für die Sprachwahl ist die umfangreiche Erfahrung des Autors mit Java. Neben den Standard-Java-Bibliotheken werden folgende externe Bibliotheken verwendet: • MRJAdapter von Steve Roy stellt Funktionen zur Verfügung, mit denen das Programm sich besser an das Look-and-Feel von Mac OS anpassen kann, ohne dadurch seine Plattformunabhängigkeit einbüßen zu müssen.7 • Jatha von Micheal Hewett stellt eine kompakte Common Lisp Umgebung mit Brückenfunktionen zu Java dar und wird im Plug-In Teil genauer erläutert. Beide Bibliotheken stehen unter der GNU Lesser General Public License (LGPL) und lassen sich damit rechtlich unkompliziert benutzen8 . 4 http://www.blackdown.org/java-linux/java2-status/index.html Events sind hier Ereignisse, die durch Aktionen des Benutzers an GUI Elementen ausgelöst werden. Ein ActionEvent kann z.B. durch Klicken auf einen Button ausgelöst werden, ein ComponentEvent durch Vergrößern eines Objekts bei Änderung der Fenstergröße. Die Applikation installiert sogenannte Listener, d.h. Callback-Interfaces, die Benachrichtigungen über diese Events bekommen. 6 Ein Layout-Manager benutzt ein bestimmtes Modell, um die GUI Elemente dynamisch, d.h. zur Laufzeit und in Abhängigkeit von der Fenstergröße, Schriftgröße usw., anzuordnen. Einfache Manager verwenden z.B. ein Raster-Modell, andere benutzen Modelle mit elastischen Modulen zwischen Objekten (javax.swing.SpringLayout). Im Sinne der Objektorientierung fragen sie die Objekte nach ihren bevorzugten, minimalen und maximalen Ausmaßen. 7 MRJAdapter verwaltet z.B. grundlegende Menü-Punkte wie Preferences und Quit. Es erlaubt das Versehen von Dokumentdateien mit sogenannten Creator-Codes und File-Types. http://www.roydesign.net/ mrjadapter/ 8 Diese von der Free Software Foundation erarbeite Lizenz für Open-Source Bibliotheken sichert wie die bekanntere General Public License (GPL) die Rechte des Benutzers – er darf zum Beispiel die Software selbst modifizieren –, hat jedoch aus Sicht des Programmierers, der diese Bibliothek benutzen will, den Vorteil, daß dessen eigene Applikation nicht wie im Falle der GPL ebenfalls frei (unkommerziell und OpenSource) sein muß. http://www.gnu.org/licenses/lgpl.html 5 27 3 Programmarchitektur 3.2 Packages Überblick Inhaltlich zusammengehörige Klassen werden zu Paketen (packages) zusammengefaßt, dabei wird üblicherweise eine durch Punkte getrennte, von links nach rechts absteigende Hierarchie benutzt, die an Internet-URLs anlehnt ist. Dadurch können später andere Pakete ergänzt werden, ohne daß Namenskonflikte auftreten. Das hierarchisch oberste Paket (root) heißt de.sciss.meloncillo. Es enthält die Klasse Main, die von der VM gestartet wird und die Klasse Session, die das Dokument des Programms beschreibt (Abschnitt 3.3). Die untergeordneten Packages sind: • debug : Fehlerkontrolle während der Programmentwicklung • edit : Editierungen, die rückgängig gemacht werden können (Undo/Redo) • gui : Graphical User Interface Elemente • io : Datei Input/Output • lisp : Lisp-Interpreter und Erweiterungen • math : mathematische Funktionen und Signalverarbeitung • net : Netzwerkobjekte (Open Sound Control) • plugin : allgemeine Plug-In Schnittstelle • realtime : Echtzeit Plug-In Schnittstelle • receiver : Receiver-Objekte, -Gruppen, -Ereignisse • render : Offline Plug-In Schnittstelle • timeline : Timeline-Objekte • transmitter : Transmitter-Objekte, -Gruppen, -Ereignisse • util : verschiedene Hilfsklassen 3.3 Session Meloncillo ist als Single-Document-Application (SDA) konzipiert, das heißt, der Benutzer hat es stets mit einem aktuellen Dokument zu tun, das alle relevanten Datenobjekte enthält. Diese Objekte werden beim Löschen des Dokuments entfernt, beim Laden des Dokuments ausgetauscht, bestehen also für die Dauer einer Sitzung. Das zentrale Dokument in der Applikation wird daher – in Analogie zu Digidesign ProTools und ähnlichen Programmen9 – als Session bezeichnet. Die Session Klasse besteht im wesentlichen aus den drei Objekten ReceiverCollection10 , TransmitterCollection und Timeline, wie in Abbildung 3.2 gezeigt. Diese sind direkt als öffentliche Instanzvariablen zugänglich. 9 Ein Gegenbeispiel für eine Multi-Document-Application ist Emagic Logic Pro, bei dem grundsätzlich beliebig viele Dokumente gleichzeitig geöffnet sein können. Dies erhöht allerdings die Anforderungen an den Programmierentwurf erheblich, so daß auf ein MDA Design verzichtet wurde. 10 Collection ist ein grundlegendes, im Paket java.util enthaltenes interface, das die Gruppierung von Elementen beschreibt und Methoden zum Hinzufügen und Entfernen von Elementen definiert. ReceiverCollection und TransmitterCollection enthalten ähnlich benannte Wrapper-Methoden für die Gruppe von Receivern und Transmittern, die sie verwalten. 28 3 Programmarchitektur Session receiverCollection transmitterCollection timeline Timeline rate length position visibleSpan selectionSpan ReceiverCollection collReceivers collSelection TransmitterCollection collTransmitters collSelection Receiver ReceiverEditor Transmitter TransmitterEditor AbstractReceiver AbstractReceiverEditor AbstractTransmitter AbstractTransmitterEditor SigmaReceiverEditor SimpleTransmitter SigmaReceiver distanceTable rotationTable rcv SimpleTransmitterEditor mte trns Abbildung 3.2: Session Struktur Sowohl Session, als auch ReceiverCollection, TransmitterCollection und Timeline implementieren das Interface11 XMLRepresentation. Dieses ist über zwei Methoden definiert: Quelltext 3.1: XMLRepresentation.java (io package) public interface XMLRepresentation { public void toXML( Document domDoc, Element node ) throws IOException; public void fromXML( Document domDoc, Element node ) throws IOException; } XML steht für Extensible Markup Language und ist eine aus SGML hervorgegangene Datenbeschreibungs-Sprache, die vom W3C (World Wide Web Consortium) standardisiert wird12 . Das Interface besagt, daß die Session in eine XML Node umgewandelt werden kann oder seine Elemente aus einer XML Node regeneriert werden können13 . Diese Methoden werden benutzt, um die Session abzuspeichern und zu laden. XML bietet zahlreiche Vorteile, darunter die einfache Lesbarkeit der Dateien im Textformat ( human readable“) und die automatische ” 11 Java Interfaces definieren Methoden, die ein Objekt implementiert. Der Ausdruck Interface ist recht zutreffend, weil es sich dabei in der Regel um Fähigkeiten handelt, die nicht spezifisch für eine bestimmte Klasse sind, sondern eher die Schnittstelle zu einer anderen Technologie beschreiben. Während eine Klasse nur eine Superclass beerben kann, kann sie beliebig viele Interfaces implementieren. Das zweite Interface, das Session implementiert, heißt FilenameFilter und ist im Paket java.io definiert. Es besagt, daß Session die Fähigkeit besitzt, Dateinamen nach einem bestimmten Prinzip zu filtern. Dies wird benutzt, um beim Öffnen der Session nur XML Dateien anzuzeigen. 12 http://www.w3.org/XML/1999/XML-in-10-points . Zur Einführung sei auch auf die FAQ http://www.ucc. ie/xml/ verwiesen. 13 Ein XML Dokument besteht aus einer hierarchischen Baumstruktur mit Knoten, die Nodes genannt werden. 29 3 Programmarchitektur Verifizierung der Dateien anhand einer Document Type Definition (DTD). Die Entwicklung einer DTD ist ein nicht ganz triviales Unterfangen, und Meloncillo Sessions benutzen im Moment noch keine explizite DTD. Wird die Session abgespeichert, enthält die XML Datei die entsprechenden Repräsentationen der Session Objekte und der Collection-Elemente – Receiver und Transmitter –, die ihrerseits das Interface unterstützen. Mit abgespeichert werden ferner Programm Preferences, die für die Session relevant sind. Große binäre Datenmengen wie die Trajektorien der Transmitter können nicht zufriedenstellend mit XML dargestellt werden und werden daher in einem speziellen Unterordner unabhängig von der Session-Datei abgespeichert. 3.4 Receiver, ReceiverCollection Das ReceiverCollection Objekt verwaltet die Receiver einer Session. Es beinhaltet Methoden zum Hinzufügen und Entfernen von Receivern. Ein Subset von Methoden dupliziert diese Collection-Operationen in Hinblick auf eine Untergruppe der Receiver, nämlich die Gruppe der ausgewählten Receiver. Dies bezieht sich auf die graphische Oberfläche, auf der der Benutzer ein oder mehrere Receiver auswählen kann. Die ausgewählten Receiver werden optisch anders dargestellt und stellen die Untergruppe der Receiver dar, auf die Editierungs-Befehle wie Ausschneiden, Kopieren, Umbenennen oder Bewegen wirken. Die selektionsbezogenen Methoden beginnen mit dem Term selection. Kann zum Beispiel mit ReceiverCollection. contains() befragt werden, ob ein Receiver in der Gruppe aller Receiver enthalten ist, so liefert ReceiverCollection.selectionContains() Auskunft darüber, ob ein Receiver der Gruppe der ausgewählten Receiver angehört usw. Die eigentlichen Receiver Objekte werden fast ausschließlich über das Receiver Interface angesprochen, das im folgenden abgedruckt ist: Quelltext 3.2: Receiver.java (receiver package) public interface Receiver { public static final DataFlavor receiverFlavor = new DataFlavor( Receiver.class, null ); public void setAnchor( Point2D newAnchor ); public void setSize( Dimension2D newSize ); public Point2D getAnchor(); public Dimension2D getSize(); public Rectangle2D getBounds(); public void setName( String newName ); public String getName(); public void setDirectory( File f ); public File getDirectory(); public void getSensitivities( float[][] points, float[] sense, int off, int stop, int step ); public Shape getOutline(); public Class getDefaultEditor(); } Die Entscheidung, für die Receiver ein Interface zu definieren, begründet sich durch den Abstraktionsgrad, der den Receivern zugeschrieben werden soll. Außerdem erlaubt es einer 30 3 Programmarchitektur Klasse, gleichzeitig das Receiver und Transmitter Interface zu implementieren. Die Abstraktion besteht darin, beispielsweise nicht festzulegen, daß ein Receiver kreisförmige Ausmaße haben muß und seine Charakteristik aus einer Distanz- und einer Rotationstabelle schöpft, sondern nur zu definieren, • daß der Receiver über einen Ankerpunkt und ein äußeres, seinen Umriß umspannendes Rahmenrechteck verfügen soll (getAnchor() und getBounds()). • daß der Receiver über einen Namen identifiziert werden kann (getName()) • daß der Receiver durch eine schematische Umrißlinie dargestellt werden kann (getOutline())14 • daß der Receiver eine bestimmte ortsabhängige Sensitivität besitzt (getSensitivities). points ist eine Liste von kartesischen Koordinaten; die Sensitivitäten an diesen Punkten werden als Ergebnis in das Array sense geschrieben. • daß es einen Standard-Editor gibt, um den Receiver zu bearbeiten (getDefaultEditor()) Um diese grundlegenden Methoden nicht jedesmal vollständig implementieren zu müssen, wurde die Klasse AbstractReceiver entworfen, von der dann spezielle Receiver wie der später beschriebene SigmaReceiver erben können. Die File bezogenen Methoden waren nötig, um das Laden und Abspeichern der Daten, die den Receiver konstituieren, zu ermöglichen. Sie hätten vielleicht besser in einem eigenen Interface untergebracht werden sollen. DataFlavor gehört zum Paket java.awt.datatransfer und beschreibt die Möglichkeit, ein Objekt für Clipboard- oder Drag-and-Drop Operationen zu formatieren. Das Feld receiverFlavor beschreibt das Wrapper-Format, mit dem Receiver beim Benutzen der Funktionen Ausschneiden / Kopieren / Einfügen dargestellt werden. 3.5 Transmitter, TransmitterCollection Die theoretische Komplementarität von Receivern und Transmittern soll auch in der Programmstruktur deutlich werden. TransmitterCollection beschreibt damit spiegelbildlich alle Gruppierungsfunktionen, die in ReceiverCollection vorhanden sind, wendet sie jedoch auf die Transmitter einer Session an. Entsprechend ist Transmitter ein Interface, das verschiedene konkrete Transmitter mit unterschiedlichen Datenmodellen unterfüttern können: Quelltext 3.3: Transmitter.java (transmitter package) public interface Transmitter { public void setName( String newName ); public String getName(); public void setDirectory( File f ); public File getDirectory(); public Class getDefaultEditor(); public MultirateTrackEditor getTrackEditor(); } 14 java.awt.Shape ist eines der grundlegenden Interfaces von Java2D, das beliebig geformte Umrißlinien oder Flächen beschreibt 31 3 Programmarchitektur Mit der Methode getTrackEditor wurde jedoch schon eine weitgehende Festlegung getroffen. Sie liefert ein Objekt, das die Trajektorien des Transmitters verwaltet. Um in einer späteren Programmversion andere Datenmodelle zu verwenden als das gegenwärtige der Klasse SimpleTransmitter, sollte hier wahrscheinlich statt der konkreten Klasse MultirateTrackEditor ebenfalls ein Interface TrackEditor zurückgeliefert werden. Analog zu Receiver gibt es eine basale implementierende Klasse AbstractTransmitter, von der konkrete Transmitter erben können. 3.6 Timeline Das Timeline Objekt beschreibt die Länge der Session, die gegenwärtige Zeitposition und die Sample-Rate der Trajektorien. Sie verwaltet zwei Teilbereiche, selectionSpan – der aktuell ausgewählte Zeitbereich, der von Editierungs-Operationen betroffen ist – und visibleSpan – der im TimelineFrame dargestellte Zeitausschnitt. 3.7 Events Objekte sollten von dem Innenleben anderer Objekte so wenig wie möglich wissen, sie kennen nur die öffentlich gemachten Methoden.15 Um die Flexibilität zu wahren, sollte die Interaktion zwischen Objekten von unten“ realisiert werden; das bedeutet, daß ein Objekt sich möglichst ” selbst darum kümmern sollte, an benötigte Informationen zu gelangen, statt diesen Vorgang durch ein hierarchisch übergeordnetes Objekt zu initiieren. Die ReceiverCollection braucht zum Beispiel nicht wissen, welche Objekte daran interessiert sind, auf Receiver zuzugreifen. Stattdessen bietet sie eine standardisierte Schnittstelle an, über die sich Interessenten registrieren lassen können. Die einzig erforderliche Gemeinsamkeit dieser Interessenten ist die Implementierung eines Listener Interfaces. Hier das Beispiel des ReceiverCollectionListeners: Quelltext 3.4: ReceiverCollectionListener.java (receiver package) public interface ReceiverCollectionListener extends EventListener { public void receiverCollectionChanged( ReceiverCollectionEvent e ); public void receiverCollectionTransformed( ReceiverCollectionEvent e ); public void receiverCollectionSelected( ReceiverCollectionEvent e ); } Die ReceiverCollection bietet Methoden zum Anmelden und Abmelden eines ReceiverCollectionListeners an. Wenn eine Veränderung eines Receivers oder einer Gruppe von Receivern auftritt, so werden alle angemeldeten Listener benachrichtigt, indem eine der im Quelltext 3.4 gezeigten Callback-Methoden aufgerufen wird. Klickt der Benutzer zum Beispiel einen Receiver an, so stellt dies eine Veränderung der Gruppe der selektierten Receiver dar, 15 Methoden, die mit dem Schlüsselwort public beginnen; Methoden, die protected deklariert werden, sind innerhalb desselben Pakets öffentlich. 32 3 Programmarchitektur und die Methode receiverCollectionSelected jedes einzelnen Listeners wird aufgerufen. Genauere Informationen zu dem Ereignis kann er dem ReceiverCollectionEvent Argument entnehmen. Der Vorteil von diesem Konzept, das in ähnlicher Art auch von den Java AWT und Swing Paketen verwendet wird, ist die Möglichkeit, daß sich neue Objekte dynamisch in die Eventverarbeitung einklinken können. Alle Objekte, die Events generieren – neben den drei Bestandteilen der Session sind dies vor allem GUI Elemente wie VectorEditor usw. –, implementieren das Interface EventManager.Listener. Sie generieren ein Hilfsobjekt, den EventManager, der den eigentlichen Dispatcher darstellt, das heißt die Verwaltung der Listener und des Event-Queue übernimmt und neu eingetroffene Ereignisse weiterleitet. Um das Multitasking berechenbar zu machen, werden in Analogie zum Event System von Java Swing alle Events von Meloncillo ebenfalls über den Swing Event Thread verteilt. 3.8 Threads Der Event Thread16 ist der Hauptthread in Meloncillo. Alle Reaktionen auf das GUI werden zunächst innerhalb des Event Threads bearbeitet. Preferences Änderungen, die zumindest in der Apple VM einen separaten Dispatcher verwenden, werden mit der Hilfsklasse LaterInvocationManager ebenfalls an den GUI Event Thread delegiert. Wenn zeitaufwendige Prozesse anstehen, zum Beispiel das Öffnen einer Session, das Rendern von Trajektorien-Daten oder das Bounce-to-Disk, muß ein zweiter Thread gestartet werden, um die Reaktivität der GUI nicht zu stoppen. Dies geschieht in der Regel durch eine neue Instanz von ProcessingThread.17 Ein weiterer wichtiger Thread ist der Transport, ein Objekt, das die Echtzeit-Verarbeitung verwaltet. Dieser Thread wird zum Programmstart generiert und pausiert, wenn der Transport gestoppt ist; während des Wartens auf Transport-Befehle findet keine CPU Belastung statt. Damit der Rhythmus der Uhr-Ticks im Echtzeit-Betrieb nicht beeinträchtigt wird, versendet das Lisp Realtime Plug-In (Abschnitt 5.3.1) OSC Datenpakete nicht aus dem Transport, sondern aus einem weiteren Thread. Der letzte wichtige Fall für eigenständige Threads ist der Empfang von OSC Nachrichten, der von der Klasse OSCReceiver bewerkstelligt wird. Der Thread pausiert automatisch, wenn keine Nachrichten eintreffen. Erreicht ein neues Datagramm den Empfänger, wird der Thread 16 Threads sind nebenläufige Prozesse. Zwar arbeiten in der Regel nur ein oder zwei Prozessoren im Computer, das Betriebssystem schaltet jedoch in rascher Reihenfolge zwischen den aktiven Threads um, so daß praktisch mehrere Aufgaben (Tasks) gleichzeitig bewerkstelligt werden können. In Java ist ein bestimmter Thread – der Event Dispatcher Thread – für die gesamte GUI Verwaltung zuständig, einschließlich der Bekanntmachung von Eingabe-Ereignissen (z.B. Mausbewegungen, Button-Klicks) und dem Aufruf von Methoden, die die GUI Elemente zeichnen (paint Methode). Zur Einführung in Java-Threads siehe [Lea 1997], S. 8–26 17 Wenn der Prozeß synchronisiert ist (einen blockierenden sogenannten Monitor auf ein Objekt besitzt), werden die Dispatcher währenddessen angehalten, so daß Veränderungen erst im Anschluß weitergeleitet werden. Zum Beispiel werden beim Öffnen einer Session viele verschiedene Änderungen an der Gruppe der Receiver und Transmitter vorgenommen. Diese Veränderungen werden weitergeleitet, wenn der Lade-Vorgang abgeschlossen ist, um eine Deadlock-Situation, die durch konkurrierende Synchronisierungsversuche entstünde, zu vermeiden. 33 3 Programmarchitektur fortgesetzt, und er benachrichtigt alle registrierten Listener. OSC wird im Abschnitt 5.4.2 beschrieben. Objekte, auf die potentiell von verschiedenen Threads zugegriffen werden kann, müssen synchronisiert werden, das heißt mit einem Mechanismus ausgestattet sein, der Interferenzen unterbindet, die zu undefinierten Zuständen in oder ungültigen Informationen über diese Objekte führen. Dafür wurde die Klasse LockManager entwickelt, die über das einfache Synchronisations-Konzept von Java hinaus zwischen geteilten Lese- und exklusiven Schreib-Zugriffen unterscheidet.18 Die Session besitzt einen LockManager für die Objekte ReceiverCollection, TransmitterCollection und Timeline. 18 vgl. [Lea 1997], S. 133–136 und 169–171 34 4 Graphische Benutzeroberfläche 4.1 Surface : zweidimensionale Momentansicht Das graphische Hauptelement der meisten Raumklangsteuerungen ist eine schematische Sicht auf das räumliche Szenario. Dabei handelt es sich oft um eine zweidimensionale Momentansicht. Durch Bewegen der Zeitachsen-Position oder Starten des Transports werden die dynamischen Objekte animiert. Diesem Videoschirm-Paradigma“ folgt auch Meloncillo. Während ” einige Programme auch dreidimensionale Raumansichten bieten1 oder als Middleware für Virtual Reality 3D-Applikationen fungieren2 , folgt die planare Editierung aus der ausschließlichen Zweidimensionalität gegenwärtiger Computersysteme (Bildschirm, Maus/Joystick/ Tablett). Die Surface Klasse ist zuständig für die 2D-Sicht in Meloncillo. Eine solche Darstellung ist in Abbildung 4.1 abgedruckt. Receiver und Transmitter werden durch kleine rote respektive grüne Fadenkreuze dargestellt, die mit dem Namen der Objekte versehen sind. Die Umrißlinie der Receiver ist gestrichelt dargestellt. Optional wird die Sensitivität der Receiver in Grauschattierungen gezeigt. Wird die Zeitachsen-Position verändert, bewegen sich die Transmitter entsprechend. Um die Trajektorien besser beurteilen zu können, werden sie optional eingeblendet: Ein grüner gestrichelter Pfad stellt den Verlauf der Trajektorien der ausgewählten Transmitter im ausgewählten Zeitabschnitt dar. Die Auflösung, d.h. die Zahl der Stützpunkte, wird automatisch heruntergeschaltet, wenn der Zeitabschnitt größer wird, um eine ausreichende Geschwindigkeit der Graphikdarstellung zu gewährleisten. Das Konzept der stufenweise aufgelösten Trajektoriendaten wird im Abschnitt 4.2.1 erläutert. Alle Graphikbefehle sind im Rahmen von Java2D realisiert, dadurch läßt sich das Surface Fenster stufenlos vergrößern. Alle Objektkoordinaten werden in einem virtuellen Raum ausgedrückt, der auf die Größe 1.0×1.0 normalisiert ist. Dazu implementiert Surface das Interface VirtualSurface: Quelltext 4.1: VirtualSurface.java (gui package) public interface VirtualSurface { public Point2D snap( Point2D freePt, boolean virtual ); public Point2D screenToVirtual( Point2D screenPt ); public Point2D virtualToScreen( Point2D virtualPt ); public Rectangle virtualToScreenClip( Rectangle2D virtualClip ); public Shape virtualToScreen( Shape virtualShape ); public Shape screenToVirtual( Shape screenShape ); } 1 2 vgl. die IEM-Cube Software in [Zmölnig et al. 2003]. Siehe auch [Momenti/Wessel 2003]. vgl. das Scream Projekt in [Leahy 2004], das eine Anbindung an 3D Spiele und Multimedia vorsieht; ähnlich das Sonificator Projekt in [Mühlethaler/Schuppisser 2004], für das eine graphische Java3D Anwendung geschrieben wurde. 35 4 Graphische Benutzeroberfläche Abbildung 4.1: Surface Fenster Abbildung 4.2: Hilfspaletten VirtualSurface beschreibt also Methoden, um Koordinaten (wie sie beispielsweise von der Maus generiert werden) von der Bildschirm-Ebene in die virtuelle Ebene und umgekehrt zu transformieren. Die Objekte Point2D und Rectangle2D sind Teil des Hauptpakets von Java2D, java.awt.geom. Darin sind vor allem das Interface Shape und die Klasse AffineTransform interessant: Shape beschreibt eine beliebige zweidimensionale geometrische Form, die in eine Folge von einfachen Segmenten (den PathIterator) zerlegt werden kann. Shape Objekte können darauf getestet werden, ob sie bestimmte Punkte enthalten oder andere Shape Objekte überschneiden. Einige Klassen, die Shape implementieren, bieten Menge-Operatoren wie UND- oder Exklusive-ODER Verknüpfung. Mit einer AffineTransform lassen sich geometrische Skalierungen, Scherungen und Rotationen beschreiben. Diese können auf Point2D und Shape Objekte angewandt werden. Die graphische Realisation findet in einem Graphics2D Kontext statt. Die Methode fill zeichnet dabei mit beliebiger Farbe, Verlauf oder Muster die Flächeninhalte von Shapes. Die Methode draw zeichnet mit beliebiger Strichstärke und Form die Umrißlinie von Shapes. Das Graphics2D Objekt bietet die Möglichkeit, sogenannte RenderingHints zu setzen und damit die Qualität der Graphik, zum Beispiel bei Skalierungen oder der Verwendung von Anti-Aliasing Techniken, zu kontrollieren. Trotz der hohen Performance von Java2D muß in der Echtzeit-Umgebung versucht werden, aufwendige Graphikoperationen wie Skalierungen und semitransparentes Zeichnen zu minimieren. Dazu werden die statischen Elemente in ein Offscreen-Image gerendert, das dann relativ schnell wiederholt gezeichnet werden kann. Die Darstellung der Receiver-Sensitivität 36 4 Graphische Benutzeroberfläche selbst ist eine grob aufgelöste Bitmap-Graphik (8-Bit Graustufen), deren Berechnung relativ langsam ist. 4.1.1 Hilfs-Paletten und Werkzeuge In der Abbildung 4.2 sind zwei Hilfs-Paletten zu sehen, die weitere Funktionalität für die Surface und andere Objekte bereitstellen. Die ObserverPalette stellt kontextsensitive TextInformationen dar. Sie enthält verschiedene Karten, die in Abhängigkeit von der BenutzerAktion umgeschaltet werden. Wählt der Benutzer beispielsweise einen Receiver aus, wird die Rcv“-Karte angezeigt. Sie enthält die exakten Koordinaten des Anker-Punktes (Mittel” punktes) des Receivers, seine Ausdehnung und seinen Namen. Diese Angaben können durch Texteingabe geändert werden. Durch Anwählen einer Gruppe von Receivern können diese gleichzeitig verändert und ausgerichtet werden. Die weiteren Karten des Observers betreffen die ausgewählten Transmitter und die Timeline. Die Csr“-Karte stellt die aktuellen Maus” koordinaten (im virtuellen Bezugssystem) dar. Die ToolPalette stellt die grundlegenden Editierungsfunktionen für die Surface bereit. Von links nach rechts zu sehen sind • Auswahl-Werkzeug : Es dient der Auswahl und dem Bewegen von Receivern • Linien-Werkzeug : Zum Generieren linearer Trajektorien-Verläufe • Kurven-Werkzeug : Generiert Trajektorien-Verläufe anhand von kubischen Kurven • Kreissegment-Werkzeug : Generiert Trajektorien, die entlang einer Kreisbahn verlaufen • Freihand-Werkzeug : Dient der Echtzeit-Aufzeichnung von Mausbewegungen • Blending-Option : Versieht die Editierungen mit einer Überblendung (Crossfade) Linien, Kurven und Kreissegmente sind Offline-Werkzeuge, sie arbeiten unabhängig vom Transport. Der Benutzer bestimmt einen Zeitausschnitt, über den sich der TrajektorienAbschnitt erstrecken soll. Er zieht die werkzeugspezifische Grundform, die durch zwei Stützpunkte definiert ist. Anschließend kann er durch Anfassen und Ziehen der Kontrollpunkte die Form anpassen. Mit Tastaturbefehlen (Escape und Return) wird die Geste abgebrochen oder ausgeführt (gerendert). Über eine spezielle Tastenkombination kann eine Serie von zusammenhängenden Segmenten gezeichnet werden. Da diese drei Werkzeuge analytische (durch eine Funktion beschriebene) Formen darstellen, können sie an beliebigen Punkten ausgewertet werden. Aufgrund dieser Überlegung wurde ein Velocity-Modus integriert, der dem Benutzer erlaubt, die Start- und Endgeschwindigkeit der Bewegung zu beeinflussen. Um zu verdeutlichen, was damit gemeint ist, sehen wir uns die dafür vorgesehenen Methoden in der Super-Klasse AbstractGeomTool an: 37 4 Graphische Benutzeroberfläche Quelltext 4.2: AbstractGeomTool.java (gui package) public abstract class AbstractGeomTool extends AbstractTool implements KeyListener { [...] protected boolean canAccelerate() { return true; } protected boolean initFunctionEvaluation( Point2D[] ctrlPoints ) { return false; } protected void evaluateFunction( float[] warpedTime, float[][] interpBuf, int len ) {} [...] } Die Fähigkeit, die Funktion an variablen Zeitpunkten auszuwerten, wird durch die Methode canAccelerate erfragt. Die Methode initFunctionEvaluation dient der Initialisierung von Parametern, die nur einmal berechnet werden müssen. Der eigentlichen Methode evaluateFunction wird ein Array von Zeit-Werten übergeben, die monoton steigend aber nicht linear verteilt sein müssen. Die Bezeichnung warpedTime besagt, daß die EingangsZeitwerte ungleichmäßig angeordnet sind, die ihnen zugeordneten (in der Methode berechneten) Funktionswerte jedoch als mit konstanter Sampling-Rate abgetasteter TrajektorienAbschnitt aufgefaßt werden. Mit anderen Worten, wenn eine Strecke mit dem Linien-Werkzeug gezeichnet und die Funktion so ausgewertet wird, daß die Eingangs-Zeitwerte zu Beginn dichter beieinander liegen als zum Schluß, so ergibt sich eine lineare Bewegung des Transmitters, deren Geschwindigkeit zunimmt.3 Durch Doppelklick auf die Surface wird dem Benutzer eine einfache Möglichkeit gegeben, die Start- und Endgeschwindigkeit der geometrischen Form anzupassen. Der Verlauf der Geschwindigkeit wird mit einer kubischen Funktion so berechnet, daß unabhängig von den Einstellungen des Benutzers der gewählte Zeitabschnitt exakt ausgefüllt wird. Die Geschwindigkeit wird durch eine transparente gelbe Hüllkurve dargestellt, die der geometrischen Grundform folgt (Graudarstellung in Abbildung 4.3). In einer zukünftigen Version sollte die Möglichkeit, mehrere Linienzüge nacheinander zu zeichnen, so erweitert werden, daß auch der Geschwindigkeitsvektor im Schnittpunkt zwischen zwei Segmenten stetig ist. Die Funktion des Freihand-Tools wird im Abschnitt über den Transport dargestellt. Um beim Einzeichnen von Trajektorien-Abschnitten zu vermeiden, daß ein Transmitter sprunghaft den Ort wechselt, kann durch Aktivierung der Blending-Option ein automatischer Crossfade zwischen den vorherigen und den neuen Trajektorien-Daten erzeugt werden. Dies ist auch hilfreich beim Filtern der Trajektorien mit Plug-Ins, die in vielen Fällen eine Unstetigkeit an den Rändern des gefilterten Zeitausschnittes erzeugen. Ebenso kann mit einer 3 Die Geschwindigkeit ist proportional zu ∆twarped /T mit T = Sampleperiode der Trajektorien. 38 4 Graphische Benutzeroberfläche Abbildung 4.3: Bézier-Kurve mit variabler Geschwindigkeit langen Blending-Dauer der Output einfacher Filter ein- und ausgeblendet werden, so daß eine dynamische Transformation stattfindet, obwohl die Filter selbst keine zeitvariablen Parameter besitzen. 4.1.2 ReceiverEditor Mit Doppelklick auf den Anker eines Receivers wird ein Editor geöffnet (Abbildung 4.4), mit dem die Sensitivität des Receivers eingestellt werden kann. Grundsätzlich sind Receiver und ReceiverEditor Interfaces in Meloncillo, so daß sich verschiedene Modelle für die Berechnung der Sensitivität integrieren lassen. In der aktuellen Version ist lediglich eine Klasse von Receivern vorhanden, der SigmaReceiver, der in Analogie zu Σ 1 eine Kreuzung zweier Tabellen vorsieht: Die Distance-Tabelle beschreibt die Empfindlichkeit des Receivers in Abhängigkeit eines Abstandes vom Anker-Punkt. Die Rotation-Tabelle beschreibt die Abhängigkeit vom Winkel, den ein Transmitter zum Anker-Punkt des Receivers einnimmt. Die Tabellen-Werte sind momentan linear skaliert und werden daher multipliziert: sense(r, φ) = distance table[r] · rotation table[φ] Dadurch lassen sich alle Standard-Formen von Kugel bis Niere und Acht beschreiben. Da die Tabellen hinreichend groß sind (jeweils 1024 Punkte4 ), lassen sich durch harte Kanten oder Rauschen auch experimentelle nicht-stetige Empfindlichkeitsverläufe realisieren. Dazu stehen per Popup-Menü verschiedene Signalgeneratoren und mathematische Operationen zur Verfügung. Um Zipper-Noise bei langsamen Bewegungen und tieffrequenten harmonischen Tönen zu vermeiden, werden die Tabellen-Werte linear interpoliert. Im klassischen Amplituden-Panning werden die Sensitivitäten direkt auf Lautstärken gemappt. Durch Vergrößern der Receiverfläche und Editieren der Tabellen lassen sich praktisch alle Panning-Verläufe umsetzen und Divergenzen simulieren. Wird ein anderes Verfahren benutzt, beispielsweise VBAP, so sind für das reine Panning nur die Receiver-Koordinaten von Bedeutung; die Sensitivität kann in diesem Fall ganz anders genutzt werden, etwa als Parameter für die Ansteuerung eines Raumhalls, einer Filterung oder Verzerrung.5 4 5 Dies wird in einer zukünftigen Version vom Benutzer konfigurierbar sein. In einer zukünftigen Version wird es eine weitere Receiver-Klasse geben, die gar keine Sensitivitäts-Daten generiert und somit effektiv ist, wenn darauf ohnehin verzichtet wird, wie z.B. in einer HRTF Synthese. 39 4 Graphische Benutzeroberfläche Abbildung 4.4: Editor für SigmaReceiver Abbildung 4.5: Matrix Meter 4.1.3 Matrix Meter Der Observer zeigt während der Tabellen-Editierung die exakte Sensitivität eines Receivers an. Um zu kontrollieren, wie der Übergang von einem Receiver zum nächsten verläuft, kann das sogenannte Matrix Meter Fenster eingeblendet werden (Abbildung 4.5). Es zeigt jeweils eine Zeile oder Spalte der aus Transmittern und Receivern gebildeten Matrix an. Durch Klick auf einen Transmitter Namen werden die momentanen Empfindlichkeiten aller Receiver an der Stelle dargestellt, an der sich dieser Transmitter befindet. Umgekehrt werden durch Klick auf einen Receiver Namen die Sensitivitäten dieses Receivers zu allen momentanen TransmitterPositionen dargestellt. In einer zukünftigen Version wird das Meter optional logarithmisch dargestellt6 , außerdem sollen die exakten Werte im Observer ausgegeben werden. 4.2 Timeline : horizontale Zeitdarstellung Für einen simultanen Überblick über den Verlauf der Trajektorien und die Gesamtform der Komposition sorgt das TimelineFrame (Abbildung 4.6). Ähnlich dem Arrangier-Fenster eines Harddisk-Recording-Programms ist hier die Zeitachse horizontal aufgetragen, während die verschiedenen Spuren, die die Trajektorien der Transmitter zeigen, vertikal angeordnet sind. Jede Spur besteht aus zwei eindimensionalen Vektoren, die die kartesischen Koordinaten (x, y) der Trajektorien zeigen. Möglicherweise zeigt eine zukünftige Version optional eine Polar-Koordinaten-Sicht. Die kartesische Darstellung hat jedoch den Vorteil, daß sie der internen Datendarstellung entspricht und somit schnell gezeichnet werden kann, davon abgesehen müßten Winkel mit der Periode 2π umgebrochen werden. 6 Die jetzige Darstellung ist linear. 40 4 Graphische Benutzeroberfläche Abbildung 4.6: Timeline Fenster Abbildung 4.7: Transport Palette Die Darstellung der Koordinaten-Vektoren erfolgt mit einem VectorEditor, dadurch ist das direkte Einzeichnen mit der Maus möglich. Komfortabler ist jedoch die Editierung auf der Surface oder mittels Filterung, wie sie im Plug-In Kapitel beschrieben wird. Die Editierung, die typischerweise im Timeline Fenster gemacht wird, ist das Ausschneiden, Kopieren und Einfügen von Trajektorien-Abschnitten. Am oberen Rand des Fensters ist eine Zeitachse zu erkennen. Durch Klicken mit der Maus kann die gegenwärtige Zeitposition, die durch die vertikale rote Linie symbolisiert wird, verschoben werden. Durch Halten der Umschalttaste kann eine Region selektiert werden, die durch dunklere Schattierung hervorgehoben wird. Durch Klick auf die Namen der Transmitter-Spuren können diese Transmitter selektiert und deselektiert werden. Die Cut- und Copy-Befehle wirken auf die Trajektorien-Ausschnitte, die durch die selektierten Transmitter und den selektierten Zeitausschnitt bestimmt sind. Die Paste-Operation fügt den Clipboard-Inhalt in die Trajektorien der gewählten Transmitter ein, an der Stelle, an der sich die Zeitposition befindet. 4.2.1 Trajektorien Daten-Format Die Darstellung des Timeline Fensters kann horizontal und vertikal vergrößert und verkleinert werden. Durch die Diskretisierung der Trajektorien kann der Fall auftreten, daß durch Herauszoomen ein Ausschnitt dargestellt wird, dem mehrere Tausend bis Hunderttausende von Frames entsprechen. Eine solch große Zahl von Frames einzulesen ist sowohl zu zeit- als auch zu speicherintensiv. Die Lösung besteht in einer Unterabtastung der Trajektorien. Dies geschieht in mehreren Schritten, um stets eine optimale Auflösung zur Verfügung zu haben. Jede Dezimations-Stufe verringert die Frame-Rate um den Faktor vier. Da VectorEditor die Daten als Vektorgraphik darstellt, wird der Umschaltpunkt so gelegt, daß maximal doppelt soviele und minimal halb soviele Punkte wie die aktuelle Fensterbreite gezeichnet werden. Insgesamt werden sechs dezimierte Tracks pro Trajektorie berechnet. Angenommen den extrem unwahrscheinlichen Fall, daß die Framerate in der Größenordnung von Audioraten liegt, zum Beispiel 48 kHz, so besitzt der am stärksten dezimierte Track (Faktor 1/4096) eine Rate 41 4 Graphische Benutzeroberfläche 1/1 :4 1/4 :4 1/16 Abbildung 4.8: Dezimation von Trajektorien von ca. 12 Hz. Wenn innerhalb einer Fensterbreite eine halbe Stunde dargestellt werden sollte, wäre damit eine Puffergröße von 21094 Frames verbunden. In dem wahrscheinlicheren Fall einer Framerate von 4800 Hz oder weniger könnte eine volle Stunde mit gerade 4219 dezimierten Frames dargestellt werden, was einen geringen RAM-Verbrauch und geringe CPU Belastung bedeutet. Die gespeicherte Session enthält die Trajektorien in Form von Floating-Point Dateien in einem separaten Unterordner trns. Die dezimierten Dateien werden momentan nicht gespeichert, sondern beim Laden einer Session adhoc erstellt, was akzeptabel schnell verläuft. Die im temporären Verzeichnis gespeicherten dezimierten Trajektorien benötigen ca. 1/3 der Größe der Originaldatei. Die Editierung der Trajektorien geschieht nicht-destruktiv, das heißt, die Originaldatei wird bis zum Abspeichern der Session nicht verändert. Die Verwaltung dieser nichtlinearen und nicht-destruktiven Editierung übernimmt die Klasse MultirateTrackEditor (MTE), die im wesentlichen sieben SubsampleTrackEditoren verwaltet. Diese repräsentieren die Trajektorien-Daten in voller respektive dezimierter Rate. Um auch bei stärkerer Dezimation eine möglichst gute Annäherung an die Signaleigenschaften zu erhalten, wird in jeder Stufe aus den jeweils vier Ausgangsframes jedes dezimierten Frames der Median berechnet. Abbildung 4.8 zeigt zwei Stufen des Dezimations-Prozesses. Der MTE verwaltet eine sogenannte TrackList, eine chronologische Liste aus TrackSpan Objekten, die wie folgt aussehen: Quelltext 4.3: TrackSpan.java (io package) public class TrackSpan { public Span span; public final InterleavedFloatFile f; public long offset; [...] } Span ist eine Klasse, die sehr häufig in Meloncillo benutzt wird. Sie beschreibt eine Zeitspanne durch Angabe eines Start- und Endframes. Die Spannen der Track-Liste fügen sich nahtlos aneinander. Wird eine Session geöffnet, so besteht die Liste lediglich aus einem TrackSpan, der die gesamte Dauer der Session umfaßt. Wird jetzt ein Teil der Trajektorie herausgeschnitten, so wird diese TrackSpan durch zwei neue ersetzt, die die Spannen vor und nach dem Schnitt beschreiben. Die Datei vom Typ InterleavedFloatFile, die die Trajektorien-Daten enthält, 42 4 Graphische Benutzeroberfläche bleibt unverändert. Das Feld offset wird jedoch stets so angepaßt, daß es auf den richtigen Punkt innerhalb dieser Datei zeigt. Wird jetzt eine Trajektorie zum Beispiel mit dem LinienWerkzeug überzeichnet, so wird der neue Abschnitt in einer temporären Datei gerendert und in Form einer neuen TrackSpan in die Track-Liste eingefügt. Gegebenenfalls wird am Insert-Punkt die alte TrackSpan in zwei separate Objekte aufgeteilt. Der MTE sorgt dafür, daß nach jeder Editierung der Trajektorien die Dezimations-Files auf den aktuellen Stand gebracht werden. Die SubsampleTrackEditoren enthalten ebenfalls eine Liste von TrackSpans, deren Spannen jedoch durch die spezialisierte BiasedSpan Klasse beschrieben werden. BiasedSpan sorgt dafür, daß die Rundungsfehler, die durch die Unterabtastung hinsichtlich der Start- und Stopframes entstehen, stets minimiert werden. 4.2.2 Transport Palette Abbildung 4.7 zeigt ein Fenster mit einfachen Transport-Funktionen. Der Transport ist eng mit der Realtime-Engine des Programms verknüpft. Er enthält einen eigenen Event-Dispatcher, der registrierte Listener über Start- und Stop-Vorgänge informiert. Die Palette enthält einen Play- und Stop-Button und einen Loop-Umschalter. Das ballförmige Symbol ganz rechts aktiviert das Realtime-Plug-In, das im nächsten Kapitel beschrieben wird. Der Transport dient neben dem Realtime-Preview auch dem Aufzeichnen von TransmitterBewegungen in Echtzeit. Während der Transport läuft, kann mit dem Freihand Werkzeug auf der Surface entlanggefahren werden. Die Bewegung wird zwischen den Stützpunkten linear interpoliert. Die Editierung wird gerendert, wenn der Mausknopf losgelassen wird. Das impliziert, daß die Bewegung im Moment des Zeichnens noch nicht über das Preview-Plug-In zu hören ist. Eine Lösung dafür wird in der nächsten Programm-Version angestrebt. 43 5 Plug-In Schnittstellen An drei Punkten wird im Programm auf ein Plug-In Konzept zurückgegriffen: • Filterung von Trajektorien • Bouncen (Rendern) der Klang-Synthese auf Harddisk • Realtime Vorschau der Klang-Synthese Die Verwaltung dieser Plug-In Typen übernehmen drei Objekte, die das PlugInHost Interface implementieren: Es sind FilterDialog, BounceDialog und RealtimeFrame. Das Diagramm 5.1 zeigt die Hierarchie der am Plug-In Konzept beteiligten Klassen und Interfaces. 5.1 Offline (Nicht-Echtzeit) Die nicht-echtzeit-basierten Filter- und Bounce-Plug-Ins implementieren das Interface RenderPlugIn: Quelltext 5.1: RenderPlugIn.java (render package) public interface RenderPlugIn extends PlugIn { public boolean producerBegin( RenderContext context, RenderSource source ) throws IOException; public boolean producerRender( RenderContext context, RenderSource source ) throws IOException; public boolean producerFinish( RenderContext context, RenderSource source ) throws IOException; public void producerCancel( RenderContext context, RenderSource source ) throws IOException; } Es übernimmt als Subinterface von PlugIn eine Methode zur Generierung einer Plug-InOberfläche (getSettingsView()), die vom RenderHost innerhalb eines Fensters dargestellt wird. Der Host reagiert auf die Aktionen des Benutzers. Wenn dieser den Render-Vorgang startet, ruft er nacheinander nach dem Push-Verfahren die Methoden producerBegin, producerRender und producerFinish des Plug-Ins auf, wobei producerRender gegebenenfalls mehrfach mit Teilblöcken der zu rendernden Zeit aufgerufen wird. 44 5 Plug-In Schnittstellen PlugIn PlugInHost RealtimePlugIn RenderPlugIn RealtimeConsumer RealtimeHost Transport RenderHost BasicRenderDialog BounceDialog LispRealtimePlugIn LispRenderPlugIn LispBounce TimeWarpFilter RenderConsumer FilterDialog VectorTransformFilter LispFilter Abbildung 5.1: Plug-In Interfaces und Klassen Im Falle des Trajektorien-Filters müssen die gefilterten Daten wieder zurück zur Applikation fließen. Dazu übergibt der Host dem Plug-In ein Objekt, das das Interface RenderConsumer implementiert. Es ist ganz ähnlich dem RenderPlugIn aufgebaut: Quelltext 5.2: RenderConsumer.java (render package) public interface RenderConsumer { public boolean consumerBegin( RenderContext context, RenderSource source ) throws IOException; public boolean consumerRender( RenderContext context, RenderSource source ) throws IOException; public boolean consumerFinish( RenderContext context, RenderSource source ) throws IOException; public void consumerCancel( RenderContext context, RenderSource source ) throws IOException; } Das Plug-In fungiert dann als eigener Host, der den Consumer mit Datenblocks füttert. Der FilterDialog ist bidirektional aufgebaut – das heißt, er empfängt die gefilterten Trajektorien und fügt sie wieder in die Session ein –, implementiert daher sowohl RenderHost als auch RenderConsumer. Grundsätzlich werden zwei Typen von Daten unterschieden, die während der Plug-In Bearbeitung Informationen liefern: statische Daten, die in einem PlugInContext Objekt zusammengefaßt sind – beispielsweise die gesamte zu bearbeitende Zeitspanne, die beteiligten Transmitter und Receiver. Und dynamische Datenströme, die blockweise generiert werden und in Form des RenderSource Objekts zur Verfügung stehen. Wenn das Plug-In durch Aufruf von producerBegin initialisiert wird, kann es sogenannte Request-Felder im RenderSource ausfüllen und gibt damit bekannt, welche Datenströme 45 5 Plug-In Schnittstellen Abbildung 5.2: Plug-Ins zur Trajektorien-Filterung erzeugt werden müssen. Ein Plug-In kann zum Beispiel nur an den Trajektorien-Daten (wie im Falle der Filter-Klassen) oder nur an den Sensitivitäten der beteiligten Receiver interessiert sein. Für die Filterung von Trajektorien stehen momentan drei Plug-Ins bereit, deren SettingsViews in Abbildung 5.2 zu sehen sind. • Der TimeWarpFilter ordnet anhand einer Tabelle die Eingangszeitwerte (Ordinate) den Ausgangszeitwerten (Abszisse) zu, d.h. traj 0 (t) ← traj(f (t)). Eine absteigende Gerade bewirkt, daß die ursprünglichen Bewegungen rückwärts wieder gegeben werden. Eine Parabel würde ein Vorwärts- und Rückwärtslaufen simulieren, ein Sägezahn mit drei Perioden würde die ausgewählte Trajektorie dreimal mit dreifacher Geschwindigkeit wiederholen. • Der VectorTransformFilter bietet die Möglichkeit, x und y Werte (alternativ Radius und Winkel zu einem Bezugspunkt) mit einer mathematischen Funktion zu bearbeiten. Unter anderem steht ein Funktionsgenerator zur Verfügung, mit dem sich einfache geometrische Figuren wie Spiralen und Linien oder das Hinzufügen von Unregelmäßigkeiten (Rauschen) realisieren lassen. • Der LispFilter stellt ein frei programmierbares Plug-In dar, das über Common Lisp Scripte gesteuert wird. Es wird in Abschnitt 5.3 erklärt. 5.2 Realtime (Echtzeit) Aus Abbildung 5.1 geht hervor, daß momentan genau ein RealtimeHost und ein RealtimePlugIn existieren. Die implementierenden Klassen sind Transport und LispRealtimePlugIn. Transport ist der Motor des Echtzeit-Betriebs. Er ist ein spezieller Thread, der läuft, wenn der Play-Knopf der Transport-Palette gedrückt wird. RealtimeConsumer können sich bei ihm registrieren, so daß sie im Benachrichtigungs-Rhythmus mit neuen Informationen 46 5 Plug-In Schnittstellen Klasse Surface MeterFrame TimelineFrame TransportPalette Request traj sense clock clock Rate 30 Hz 15 Hz 30 Hz 15 Hz Aktivität Nachführung der Transmitter Bewegungen Monitoring der Sensitivitäten Animation der Zeitachsen-Positions-Linie Update des Zeitachsen-Positions-Textfeldes Abbildung 5.3: RealtimeConsumer Profile versorgt werden. Die Genauigkeit der Uhr-Information in Java liegt bei einer Millisekunde. Die Methode Thread→sleep( long millis, int nanos ) kann benutzt werden, um den Thread für eine bestimmte Zahl zu pausieren. Die suggerierte Genauigkeit im Bereich von Nanosekunden ist jedoch überhaupt nicht gegeben. Selbst wenn eine Millisekunde lang gewartet wird, ist nicht garantiert, daß der Thread wirklich nach einer Millisekunde fortgesetzt wird. Deshalb wird im Transport-Kern ein Mechanismus benutzt, der laufend die aktuelle und die geforderte Rate vergleicht und entsprechend kürzer oder länger wartet. Der entstehende Jitter ist optisch irrelevant und tangiert die externe Klangsynthese nicht, die Daten blockweise erhält und ihren eigenen Scheduler hat. Im Gegensatz zur Trajektorien-Filterung und Bounce-to-Disk gibt es im Echtzeit-Betrieb mehrere Consumer. Das bedarf einer Erläuterung: Im Klassen-Diagramm ist zu erkennen, daß LispRealtimePlugIn sowohl RealtimePlugIn als auch RealtimeConsumer implementiert. Worin besteht der Unterschied? Das Plug-In ist dafür zuständig, mit externen KlangsyntheseProgrammen zu kommunizieren. Das Interface beinhaltet Methoden zum Aktivieren und Deaktivieren des Plug-Ins, das heißt, es kann auf Bypass geschaltet werden. Der eigentliche Datenaustausch jedoch ist Teil des Consumer Interfaces. Neben dem Lisp Plug-In gibt es weitere Consumer in Meloncillo, die in Abbildung 5.3 gelistet sind. Je nach Anwendung sind also unterschiedliche Datenraten gefragt. Die tabellierten Klassen sind alle Teil der graphischen Oberfläche und benötigen daher nur Raten, die einen optisch fließenden Eindruck vermitteln. Die verschiedenen Requests werden dynamisch verwaltet von einem Objekt, das eng mit Transport zusammenarbeitet, dem RealtimeProducer: Quelltext 5.3: RealtimeProducer.java (realtime package) public class RealtimeProducer implements LaterInvocationManager.Listener { [...] public RealtimeProducer.Source source; [...] public void changeContext( RealtimeContext c ) { [...] } public void requestProduction( Span blockSpan, boolean even, long deadline ) { [...] } public void produceNow( Span blockSpan, boolean even ) { [...] } public void produceOffhand( long currentPos ) { [...] } [...] } Der RealtimeProducer produziert blockweise die geforderten Daten innerhalb des Event Threads. Eine neue Anfrage wird vom Transport durch Aufruf der requestProduction Methode gestellt. Der RealtimeProducer soll darin die Daten, die zur Zeitspanne blockSpan gehören, produzieren. Um Dropouts zu vermeiden, darf er dafür maximal deadline Milli- 47 5 Plug-In Schnittstellen 0 16 32 48 64 80 traj : 1/1 sense : 1/2 96 112 128 plugin sense read : 1/2 plugin notification : 1/8 surface traj read / timeline frame notif. : 1/16 transport palette notif. : 1/32 Abbildung 5.4: Realtime Datenströme sekunden benötigen. Mit anderen Worten, der RealtimeProducer wird bereits im voraus beauftragt, einen neuen Block Daten zu generieren. Diese Daten sind in Arrays des source Objekts gespeichert. Die Consumer streichen im Clock-Rhythmus zirkulär durch diese Puffer. Jedesmal, wenn die aktuelle Zeit den Puffer-Anfang oder die Puffer-Mitte überschreitet, wird die jeweils obsolete Puffer-Hälfte, spezifiziert durch den even Parameter, aktualisiert. Wenn der Transport gestartet wird, muß ein voller Block vorproduziert werden, dazu dient die Methode produceNow. Da die Oberfläche auch auf manuelles Ziehen der Zeitachsen-PositionsLinie durch den Benutzer reagieren soll, ohne daß der Transport läuft, wurde die Methode produceOffhand eingeführt, die nur ein einzelnes Zeitframe produziert. Wenn der Benutzer die Session verändert, zum Beispiel Receiver löscht oder hinzufügt, müssen die Puffer neu angelegt werden. Dazu werden die Consumer kurzzeitig angehalten, der Kontext mittels changeContext aktualisiert, und ein neues Profil von allen Consumern angefordert. Wie findet die Koordination zwischen mehreren gewünschten Datenraten statt? Nehmen wir dazu an, daß neben den in Tabelle 5.3 aufgeführten Consumern ein Lisp-Echtzeit-Plug-In läuft. Die Session habe eine Trajektorien-Datenrate von 500 Hz1 . Nehmen wir an, das PlugIn steuert den SuperCollider-Synthesizer, dessen Controlrate ca. 690 Hz beträgt. Das Plug-In fordere aus Gründen der CPU Belastung Sensitivitäten mit maximal 345 Hz an. Nehmen wir weiter an, ein voller Datenpuffer entspräche etwa 1/4 Sekunde, nämlich 128 Frames. Dann ergibt sich ein Datenstrom-Produktions- und Konsumptions-Schema nach Abbildung 5.4. Der RealtimeProducer produziert prinzipiell Trajektorien-Daten (traj ) mit voller Datenrate – also durchgängig alle 128 Frames eines Blocks –, da sie direkt von der Harddisk gelesen werden und eine Unterabtastung eher Rechenzeit vergeuden als sparen würde. Sensitivitäts-Daten (sense)werden nur produziert, wenn sie nachgefragt werden. Der einzige Request kommt vom Realtime Plug-In (345 Hz). Grundsätzlich müssen die Faktoren der Unterabtastungen einer Zweierpotenz entsprechen, somit ergeben sich hier 250 Hz beziehungsweise eine Schrittweite von zwei Frames. Alle ungeraden Frame-Indices des Puffers werden ignoriert und haben keinen gültigen Inhalt. Der Transport sorgt dafür, daß die Consumer mit der von ihnen angegebenen Rate benachrichtigt werden2 . Auch hier gilt die Zweierpotenz-Regel, so daß sich die leicht veränderten Frequenzen von 31.25 Hz bzw. 15.625 Hz ergeben. Im Falle von blockverarbeitenden Con- 1 2 Die Voreinstellung beträgt 1 kHz. Notification, in der Abbildung mit notif.“ abgekürzt. ” 48 5 Plug-In Schnittstellen sumern wie dem Plug-In ist die Benachrichtigungs-Rate in der Regel niedriger als die Rate der angeforderten Daten-Ströme. Im gezeigten Beispiel beträgt sie 1/8 der vollen Rate. Die Erklärung dafür wird im Abschnitt 5.4.3 in Zusammenhang mit der SuperCollider Anbindung geliefert. 5.3 Common Lisp für Java Die Lisp-Plug-Ins sind weniger dafür gedacht, direkte Manipulationen zum Beispiel der Trajektorien zu vollbringen, vielmehr sollen sie ein elastisches Bindeglied zu externen Klangsynthese Programmen sein. Aus diesem Grund wurde in einer frühen Version des Programms ein XML-Script zur Steuerung der externen Programme benutzt. XML erweist sich jedoch als unpraktisch, wenn programmiersprachliche Konstrukte wie Schleifen (do-while) oder Bedingungen (if-then-else) benötigt werden. Diese hätten alle zu Fuß“ in den XML Interpreter ” eingebaut werden müssen. Stattdessen wurde eine einfach strukturierte, kompakte, in Java integrierbare Interpreter-Sprache gesucht. Die Wahl fiel auf Common Lisp: Die Syntax ist sehr überschaubar3 , mehrere algorithmische Musiksprachen basieren auf Lisp4 , und es gibt mit Jatha eine einfache freie Implementation in Java. Micheal Hewett entwickelte Jatha über die letzten zehn Jahre, und es erweist sich als zuverlässig im Betrieb. Ein paar der Vorteile von Jatha: • maximale rechtliche Freiheit durch GLPL Lizenz • kompakte Bibliothek (232 KB) • plattformunabhängig • Ausnutzung des automatischen Garbage-Collectors von Java • sehr einfache Konvertierung zwischen primitiven Lisp und Java Datentypen • neue Funktionen lassen sich durch einfache Java Klassen bereitstellen • neue Symbole können von Java aus in das Environment eingefügt werden • kann als reines API ohne eigene Console oder GUI verwendet werden Die wesentlichen Nachteile sind die eher langsame Geschwindigkeit – trotz gegenteiliger Behauptungen des Autors – und der geringe Funktionsumfang. In der Selbstbeschreibung heißt es sehr zurückhaltend, Jatha implementiere a large part of the core of Common Lisp“ 5 . Das ” bedeutet unter anderem, daß praktisch keine weitergehenden APIs eingebaut sind. Zum Beispiel gibt es keine Funktionen zum Lesen und Schreiben von Files. Auch Standard-Konzepte wie Streams, Arrays und Macros fehlen komplett. Im Rahmen der Anforderung als einfaches Scripting-Bindeglied wurden diese Nachteile in Kauf genommen. 3 zur Sprache Common Lisp vgl. [Mayer 1995] z.B. OpenMusic und Common Music, RSC als SuperCollider Client in Scheme, sowie die Klangsynthese Sprache Common Lisp Music. 5 http://jatha.sourceforge.net/doc/short-description.html 4 49 5 Plug-In Schnittstellen 5.3.1 Die LispPlugIn Klasse Oberklasse für alle Lisp basierten Plug-Ins ist die Klasse LispPlugIn. • Sie stellt eine standardisierte Oberfläche bereit, die eine Auswahl-Box für die konkreten Lisp Scripte (Sourcecodes) enthält und die Möglichkeit bietet, GUI Elemente darzustellen, die direkt von den Scripten erzeugt werden (vgl. Abb. 5.2 rechts). • Sie verwaltet die Jatha Umgebung und stellt zusätzliche Funktionen und Symbole zur Verfügung. • Sie stellt die Methode executeLisp zur Verfügung, mit der zur Renderzeit beliebige im Script definierte Funktionen ausgeführt werden können. Die Namen dieser Funktionen hängen vom Plug-In Typ ab. Für die Filterung von Trajektorien werden in Analogie zum RenderPlugIn Interface (Quellcode 5.1) die benutzerdefinierten Lisp Funktionen prepare, render und cleanup ausgeführt. prepare ermöglicht dem Script, grundlegende Initialisierungen durchzuführen und Requests anzumelden. render wird im Gegensatz zu RenderPlugIn→producerRender() nur einmal ausgeführt. Dies geschieht, nachdem die angeforderten Datenströme in Form von temporären Dateien bereitgestellt wurden, so daß hier üblicherweise der Aufruf des externen Klangsynthese-Programms, z.B. CSound, erfolgen kann. Aufräumarbeiten wie das Schließen oder Löschen von Dateien werden in der cleanup Funktion erledigt. Die zusätzlich von Meloncillo bereitgestellten Lisp Funktionen beinhalten unter anderem: • Öffnen von Audio-Dateien (AIFF, IRCAM oder AU Format) • Allokation und Beschreiben von Byte-Puffern (als Ersatz für den fehlenden VectorDatentyp) • Öffnen und Beschreiben von Dateien • Erweiterte String-Operationen wie Formatierung von Zahlen und Pattern Matching mit Regulären Ausdrücken • Versenden von UDP Datagrammen (vgl. Abschnitt 5.4.2) • Generierung von OSC Paketen (vgl. Abschnitt 5.4.2) • Festlegung von Quelldaten und Zieldaten Requests (d.h. welche Trajektorien- und Sensitivitätsdaten benötigt und zurückgeliefert werden) • Ausführen von externen Programmen • Erzeugen von GUI Elementen Die GUI Elemente dienen dazu, dem Benutzer die wichtigsten Script Parameter in Form von Checkboxes und Textfeldern zu präsentieren, ohne daß dieser für jede Session separate Script-Dateien editieren muß. GUI Elemente werden in der speziellen Funktion create-gui definiert. Das Script erhält außerdem ein Dictionary6 , das die wichtigsten statischen Parameter enthält. Hier kann das Script nachschlagen, wieviele Transmitter und Receiver beim Rendern beteiligt sind, was ihre Namen sind usw., wie hoch die Datenrate ist und welche Werte die Plug-In 6 in Form des speziellen Lisp-Datentyps LispHashTable 50 5 Plug-In Schnittstellen relevanten Preferences-Settings haben, etwa die voreingestellte Audio-Rate und der voreingestellte Pfad zur CSound Applikation. 5.3.2 Ein Beispielscript Während die Besonderheiten für Echtzeit-Scripte im folgenden Abschnitt erläutert werden, wird hier das Beispiel einer Trajektorien Filterung mit CSound durchgegangen. Nehmen wir an, CSound soll die Trajektorien tiefpaßfiltern, so daß die Transmitter-Bewegungen weniger hektisch und dafür flüssiger werden.7 Das Lisp Script ist in der Datei "csfl-smooth.lisp" gespeichert. Wenn es im Filter Dialog ausgewählt wird (Abb. 5.2 rechts), wird der Quelltext geladen und übersetzt. Anschließend wird die Funktion create-gui ausgeführt, die ein numerisches Eingabefeld für die Filter-Frequenz erzeugt: (defun create−gui NIL (progn (gadget−make NIL "LABEL" ’(1 1) "Cutoff Frequency" NIL) (gadget−make filter−freq "NUMBER" ’(2 1) 1.0 (list "Hz" 0.0 1000.0 0.01)) T ; success ) ) Der erste gadget-make Befehl erzeugt die Beschriftung. Die Argumente für gadget-make sind (1) ein Lisp-Symbol, das stets den aktuellen Wert des GUI-Elements – in diesem Fall die Frequenz – enthält, (2) der Gadget-Typ, (3) die Position des Gadget auf der Oberfläche, (4) der voreingestellte Wert, (5) spezifische Optionen – hier die physikalische Einheit der Werte und die erlaubten Minimum- und Maximum-Werte. Die Funktion liefert T (wahr) zurück um zu signalisieren, daß keine Fehler aufgetreten sind. Durch Klick auf den Process-Knopf wird die Filterung gestartet. Ein RenderContext der gerade ausgewählten Transmitter und des Zeitausschnitts wird erstellt. Die Lisp-Funktion prepare wird ausgeführt: (defun prepare NIL (progn (setq colltrns (gethash "TRANSMITTERS" cillo)) (setq numtrns (length colltrns)) (setq prefs (gethash "PREFERENCES" cillo)) (setq timeline (gethash "TIMELINE" cillo)) (setq duration (− (gethash "STOP" timeline) (gethash "START" timeline))) (setq sense−rate (gethash "SENSERATE" prefs)) (setq trnsidx 0) (trnsiter ’(progn (let ((trns (elt colltrns trnsidx)) (bufidx trnsidx) (temp−input−file (temp−file−make)) (temp−output−file (temp−file−make))) (audio−file−open bufidx temp−input−file "raw" "float32" sense−rate 2) (source−request "TRAJ" trnsidx bufidx) (target−request "TRAJ" trnsidx temp−output−file) 7 Der Einfachheit halber wird die Ausführung weiter im Indikativ geschrieben. 51 5 Plug-In Schnittstellen (setf−gethash "INPUT−FILE" trns temp−input−file) (setf−gethash "OUTPUT−FILE" trns temp−output−file) ) )) T ; success ) ) Mit der Funktion gethash werden der RenderContext und die Programm-Preferences ausgelesen. Die Hashtable cillo wird als globales Symbol von LispPlugIn erzeugt. Die Liste der Transmitter colltrns, die Zahl der Transmitter numtrns, die Länge des Zeitausschnitts duration und die Datenrate sense-rate werden ermittelt. In einer Schleife8 wird für jeden Transmitter eine Eingabe- und Ausgabe-Datei im temporären Verzeichnis erzeugt. Mit audio-file-open wird das Eingabeformat festgelegt, hier eine raw“ 9 Datei für 32bit Floa” ting-Point Samples und zwei Kanäle. Diese Datei wird über den Identifier bufidx als Ziel für die Quelldaten bestimmt (source-request). Dem Lisp-Plug-In wird mitgeteilt, daß die Zieldaten in einer Datei temp-output-file zu erwarten sind. Für die spätere Verwendung in der render Funktion werden die Dateinamen in der Hashtable gespeichert, die für jeden Transmitter existiert. Nachdem die Funktion zurückkehrt, arbeitet das Lisp-Plug-In die Requests ab und schreibt die angeforderten Trajektorien-Daten in die temporären Dateien. Anschließend ruft es die Script Funktion render auf: (defun render NIL (progn (setq trnsidx 0) (setq return−code 0) (trnsiter ’(progn (let ((trns (elt colltrns trnsidx)) (bufidx trnsidx) (csd−file (temp−file−make ".csd"))) (file−close bufidx) ; close traj data files ; −−−− create CSound unified Orc/Sco file −−−− (file−open 1977 csd−file "w") (file−write 1977 (concat "<CSoundSynthesizer>\\n<CsInstruments>\\n" "nchnls = 2\\n" "#include \"smooth.orc\"\\n" "</CsInstruments>\\n<CsScore>\\n" "i88 0 " duration "\\n" "i14 0 " duration " \"" (gethash "INPUT−FILE" trns) "\" " filter−freq "\\n" "</CsScore>\\n</CSoundSynthesizer>\\n" )) (file−close 1977) ; −−−− launch csound −−−− (let ((exec−args (list (gethash "CSOUNDAPP" prefs) "−A" "−3" "−o" (gethash "OUTPUT−FILE" trns) "−r" sense−rate "−k" sense−rate csd−file))) 8 Mangels einer Iterations-Funktion in Jatha wurde dafür eine hier nicht abgedruckte rekursive Funktion trnsiter definiert, die die Variable trnsidx von 0 bis numtrns - 1 hochzählt. 9 D.h. ohne Header – headerless – nur aus den Audio-Frames bestehend 52 5 Plug-In Schnittstellen (println (concat "\\n∗∗∗∗∗ Transmitter \"" (gethash "NAME" trns) "\" executing:\\n" (concat−args exec−args))) (setq return−code (execute parse−cs−output exec−args NIL (car (path−split csd−file)))) (println (concat "Exited with return code " return−code)) (if (not (eql return−code 0)) (setq trnsidx numtrns) NIL) ) ) )) (eql return−code 0) ; success if return code is 0 ) ) Da CSound sich etwas schwierig tut, mehrkanalige Dateien zu schreiben, ruft das Script CSound jeweils getrennt für die einzelnen Transmitter auf; in jedem Durchgang der Iteration wird eine Text-Datei geöffnet (file-open), in der die CSound Score generiert wird. Das Script bindet das bereits auf der Harddisk gespeicherte Orchestra-File "smooth.orc" ein (siehe Quelltext 5.4) und schreibt zwei Instrumenten-Aufrufe: i88 und i14. Instrument 88 ist ein Hilfsinstrument, daß in Intervallen den Processing-Fortschritt in die Console schreibt. Instrument 14 liest die Trajektorien ein, filtert sie mit einem reson Unit-Generator der gewählten Frequenz und schreibt das Ergebnis in das CSound Ausgabefile. CSound selbst wird durch die Lisp-Funktion execute gestartet. Der Pfad zu CSound wird durch Auslesen des Preferences-Feldes CSOUNDAPP ermittelt. Das erste Argument von execute ist eine Callback-Funktion im Script, die die Console-Ausgabe des ausgeführten Programmes auswertet. Sie leitet diese Console-Ausgabe einfach mittels println in die Console von Meloncillo um und filtert die von Instrument 88 generierten Strings heraus, um stattdessen mit progression-set die Fortschritts-Anzeige von Meloncillo zu aktualisieren: (defun parse−cs−output (textline) (if (and (eql 10 (length textline)) (eql "CILLO " (substring textline 0 6))) (progression−set (car (format−parse "{0,number}" (substring textline 6 10)))) ; else (println textline) ) ) Nachdem alle execute Befehle ausgeführt wurden, kehrt die Funktion render zurück. Das Lisp-Plug-In kopiert nun die von CSound generierten neuen Trajektorien-Dateien zurück in die Session und ruft abschließend die Script-Funktion cleanup auf. Quelltext 5.4: smooth.orc ; read a transmitter path and write its lowpass ; filtered transformation back to the output file ; p4 = traj input path; p5 = cutoff frequency [Hz] instr 14 ; bug in CSound 4.23f11 −− channels are swapped aty atx diskin p4, 1, 0, 0, 6 ; path, pitch, offset, wrap, format aoutx reson atx, 0, p5, 1 aouty reson aty, 0, p5, 1 outch 1, aoutx outch 2, aouty endin 53 5 Plug-In Schnittstellen ; print progress information every 2 seconds instr 88 iweight = 1.0 / p3 kschoko times printks "CILLO %.2f\\n", 2, kschoko ∗ iweight endin 5.4 Open Sound Control Open Sound Control (OSC) wurde am CNMAT in Berkeley von Matt Wright und Adrian Freed entwickelt. Es ist als Kommunikationsprotokoll gedacht, mit dem sich Computer und Computeranwendungen, insbesondere Multimedia-Hardware und -Software verständigen können. Das Grundkonzept wurde von den Autoren auf der ICMC 1997 vorgestellt.10 Nachdem der Boom im Bereich von Software-Synthesizern begonnen hatte und neue schnelle ComputerSchnittstellen wie Firewire und USB sich durchzusetzen begannen, stellte sich die Frage, wie voneinander getrennte Komponenten ihre Daten austauschen sollten. Die MusikinstrumenteIndustrie (Yamaha) hatte bereits vorgeschlagen, auf dem etablierten MIDI Standard aufzubauen. OSC hingegen versucht, die offensichtlichen Beschränkungen des damals 14-jährigen MIDI Standards zu umgehen: MIDI ist unskalierbar – der Befehlssatz ist festgelegt und überdies hochproblematisch11 –, hat eine viel zu geringe Datenrate (31.25 kbs), kennt nur eine beschränkte Zahl von Adressaten (MIDI-Kanäle) und kann praktisch keine zwei Befehle gleichzeitig ausführen. 5.4.1 Protokollübersicht In der Erkenntnis, daß Transport-Protokolle und Hardware-Interfaces sich schneller ändern können als ein Musik-Kommunikations-Protokoll, wurde OSC transportunabhängig definiert. Es ist jedoch an die Erfordernisse von Netzwerk-Transport wie UDP angepaßt und geht von einer Paket (Datagramm) Struktur aus. OSC Befehle sind in einem OSC-Paket verpackt,12 das leicht als UDP-Datagramm versandt werden kann. Zwei Typen von OSC-Paketen werden unterschieden: Messages und Bundles. Bundles gruppieren synchron auszuführende Messages oder weitere Bundles in einem einzelnen Paket. Sie beginnen mit dem speziellen String "#bundle" gefolgt von einem sogenannten Time-Tag, das den Zeitpunkt beschreibt, zu dem die enthaltenen Messages auszuführen sind.13 Eine Message enthält den eigentlichen Befehl. Sie besteht aus einem URL-ähnlichen symbolischen Adreß-String und einer beliebigen Zahl von binär kodierten Argumenten. Die symbolische Message-Adresse wird vom Empfänger ausgewertet, in einer objekt-orientierten Umgebung üblicherweise von links nach rechts hierarchisch absteigend, so daß eine Adresse wie 10 [Wright/Freed 1997] Dazu zählt die ideologische Festlegung auf Tasteninstrumente mit 127 Halbtonschritten; natürlich ist MIDI anders interpretierbar, aber die Umdefinierung von Controller-Changes oder das Hantieren mit SysExBefehlen kann nur als Notbehelf betrachtet werden. 12 Die aktuellen Spezifikationen sind unter der Adresse http://www.cnmat.berkeley.edu/OpenSoundControl/ OSC-spec.html zu finden. 13 Die zwei oder mehreren kommunizierenden Objekte sind dafür verantwortlich, daß sie auf dieselbe SystemZeit zugreifen. Innerhalb desselben Computers ist dies automatisch gegeben, in einem Netzwerk müssen sich die Systeme ggf. per Network-Time-Protocol (NTP) prüfen an einer Netzwerk-Uhr orientieren. 11 54 5 Plug-In Schnittstellen z.B. "/synth/oscillators/sawtooth/set-frequency" zuerst an das Synthesizer-Objekt geschickt wird, das sie an die Oszillator-Sektion weitergibt, die wiederum an den SägezahnGenerator, der dann den Befehl zum Ändern der Frequenz ausführt. Im Gegensatz zu MIDI kann sich der Adreß-Raum grundsätzlich dynamisch verändern. Das ursprüngliche OSC Protokoll sieht folgende spezielle Message-Adressen vor: • Wildcards wie ’*’ oder ’?’, die es erlauben, eine Nachricht an mehrere Adressaten zu verschicken, deren Adressen auf das Wildcard Pattern passen • Objekt-spezifische Informations-Anfragen, die durch Zurücksenden einer Nachricht beantwortet werden14 • Anfragen zum Adreß-Raum, d.h. zu den verfügbaren Unteradressen eines Objekts • Anfragen zu den erwarteten Argumenten und Daten-Typen eines Befehls • Eine "/documentation" Anfrage, die einen Text zurückliefern soll, der vom Benutzer gelesen werden kann • Eine "/current-value" Anfrage, die den aktuellen Parameter-Wert (etwa die OszillatorFrequenz im obigen Beispiel) zurückliefern soll Sechs Jahre nach Einführung von OSC gibt es bereits zahlreiche OSC-Implementationen. Der Umfang, in dem Time-Tags, Pattern-Matching und die speziellen Messages unterstützt werden, variiert jedoch erheblich. Eine klarere Rollen-Teilung der kommunizierenden Objekte wird in den Ausdrücken OSC-Server und OSC-Client deutlich.15 Im Client/Server-Modell stellt der Server Dienste zur Verfügung, ein oder mehrere Clients benutzen diese Dienste, die Kommunikation verläuft überwiegend in Richtung Server, der gegebenenfalls AntwortNachrichten zurückschickt. Das CNMAT führt eine Liste an Applikationen, die OSC unterstützen,16 sie ist allerdings unvollständig und zum Teil obsolet. Zu den Musik- und Klang-Programmen zählen SuperCollider, Max/MSP, PD, jMax, OpenMusic, RTcmix und Siren. Im Bereich Multimedia sind OSC-Anbindungen an Macromedia Flash (flosc) und Director (OSCar) zu nennen. Am IRCAM wurde mit EtherSense ein Sensor-Gerät für Live-Performances entwickelt, das direkt OSC über Ethernet an einen Computer überträgt. Das vom CNMAT herausgegebene OSCKit, eine OSC-Bibliothek in C, wurde in weitere Sprachen wie Java, Objective-C, Common Lisp und Ruby übertragen. In der Implementation von OSC in James McCartneys SuperCollider wurde eine entscheidende Erweiterung des Protokolls vorgenommen, die sich übergreifend durchgesetzt hat: Die wenigsten Implementationen unterstützen derzeit das Type-Querying, also das Abfragen der Daten-Typen für Message-Parameter. In der Praxis ist dem Client oder Anwender bereits bekannt, wie die Messages eines Servers aufgebaut sind. Auf der Server-Seite wiederum muß ein allgemeines OSC-Empfangs-Objekt in der Lage sein, die Message-Argumente korrekt zu dekodieren, bevor sie vom eigentlichen Adressaten weiterverarbeitet werden.17 Daher wurde der Type-Tag-String in OSC-Messages eingeführt. Er stellt das erste Argument jeder Message 14 Der Sender wird nicht direkt in der Message vermerkt, kann jedoch normalerweise vom Transport-Layer erfragt werden. UDP Datagramme enthalten z.B. eine Return-Adresse. 15 vgl. [Wright et al. 2003]. Die Ausdrücke sind offenkundig von SuperCollider 3 übernommen. 16 http://www.cnmat.berkeley.edu/OpenSoundControl/ 17 Das Max-External OpenSoundControl zum Beispiel generiert eine Liste mit Max-Primitives aus den empfangenen OSC-Nachrichten; diese wird dann normalerweise über OSC-route an die Adressaten verteilt. Ohne Type-Tags kann OpenSoundControl also nur raten“, welche Daten-Typen gemeint sind. ” 55 5 Plug-In Schnittstellen dar und besteht aus einem Komma-Charakter gefolgt von einer Kette von Type-Charakteren, die den Daten-Typ aller Argumente angeben. Die wichtigsten Typen sind ’i’ für 32bit lineare ganze Zahlen, ’f’ für 32bit Floating-Point Zahlen, ’s’ für Strings oder Symbole und ’b’ für den sogenannten ’Blob’, einen binären Datenblock. Type-Tags machen komplizierte ArgumentPrüfung und Heuristiken überflüssig. 5.4.2 Implementierung in Meloncillo Die eigentlichen OSC-Klassen von Meloncillo befinden sich im Paket net. Es sind • OSCPacket : Superclass von Messages und Bundles, die Methoden zum En- und Dekodieren von Paketen enthält • OSCMessage : Die Message Klasse, die Java-Primitives in Binärform kodiert bzw. aus der binären empfangenen Nachricht dekodiert • OSCBundle : Die Bundle Klasse. Messages und Bundles werden zunächst einzeln hinzugefügt und anschließend in Binärform kodiert. Neben den normalen absoluten TimeTags des OSC Standards werden die relativen Time-Tags des SuperCollider NonRealTime-Modus (NRT) unterstützt • OSCReceiver : Objekte dieser Klasse können in einem eigenen Thread auf das Eintreffen von Nachrichten warten • OSCListener : Listener für einen OSCReceiver, der beim Empfang von Nachrichten informiert wird • OSCException : Klasse für OSC-bezogene Fehler Während sich die Klassen zunächst an die bereits existente Java-Bibliothek JavaOSC18 anlehnten, wurden sie aus Gründen der Effizienz und etwas umständlichen Art von JavaOSC neu programmiert und auf die nötigsten Elemente beschränkt. Sie unterstützen momentan kein Pattern-Matching19 und keine mit Brackets (’[’, ’]’) getypten Arrays20 , außerdem gibt es keinen separaten Dispatcher. Stattdessen wird mit entsprechenden Methoden der java.net und java.nio Pakete einfach ein DatagramChannel geöffnet, die zu versendenden Pakete in einen ByteBuffer kodiert (dies erledigt OSCPacket) und mit write in den DatagramChannel geschickt. Im Paket lisp existieren die Wrapper-Klassen OSCBundleSendPrimitive und OSCBundleSendAndWaitPrimitive. Sie stehen den Lisp Scripten zur Verfügung. Während die erste Funktion ein OSC-Bundle asynchron verschickt, wartet die zweite Funktion nach dem Versand für eine angegebene Zeit auf eine bestimmte Rückmeldung. Konkrete Beispiele für den Gebrauch von OSC-Messages in Lisp werden im Abschnitt 5.4.3 gezeigt. 18 http://www.mat.ucsb.edu/~c.ramakr/illposed/javaosc.html Dies macht nur für OSC-Server Sinn. Ein Client-Listener kann jedoch auf die mächtigen Funktionen von java.util.regex zurückgreifen. Den gegenwärtigen Diskussionen des Forums [email protected] kann darüber hinaus entnommen werden, daß sich das Pattern-Konzept in zukünftigen OSC Versionen voraussichtlich ändern wird. 20 Dies auch vor dem Hintergrund, daß sclang ebenfalls keine Brackets benutzt, sondern Arrays einfach direkt in die einzelnen Elemente auflöst. 19 56 5 Plug-In Schnittstellen 5.4.3 Anbindung an SuperCollider SuperCollider is an environment for real time audio synthesis which runs on a ” Power Macintosh with no additional hardware“ [McCartney 1996] Diese knappe Beschreibung der ersten Version von SuperCollider aus dem Jahre 1996 trifft im wesentlichen noch für Version 3 zu, obwohl das Programm konzeptuell einige Änderungen erfahren hat.21 Während SuperCollider 1 gerade aus der Fusion zweier Vorläuferprogramme hervorging, einer Klangsynthese-Sprache (Synth-O-Matic) und einer Interpreter-Umgebung für Max (Pyrite), besteht der wesentliche Unterschied von Version 3 zu Version 2 darin, daß es sich eigentlich wieder um zwei unabhängige Programme handelt, die SuperCollider Language Application (kurz sclang) und die SuperCollider Synthesis Engine (kurz scsynth). sclang bietet eine auf der Sprache SmallTalk basierende Programmierumgebung, die zur Klanggenerierung mit scsynth über OSC kommuniziert. scsynth hat grundsätzlich nichts mit SmallTalk oder überhaupt einer höheren Sprache zu tun. Der einfache Befehlssatz, der aus ca. 50 einzelnen Kommandos eines flachen Adreßraums besteht22 , und die Effizienz der DSP Algorithmen prädestinieren scsynth dazu, von Frontends verschiedenster Art als reine Rechenmaschine verwendet zu werden, mit der der Anwender nicht direkt etwas zu tun bekommt. In dieser Konstellation wird SuperCollider als Server und die Steueranwendung als Client bezeichnet. Ein Beispiel für einen SuperCollider Client ist die in einer Fußnote in Abschnitt 4.1 erwähnte Scream Umgebung bzw. die damit erstellte Applikation AmbiGranusampler. Ein weiteres Beispiel ist der dort ebenfalls kurz dargestellte Sonificator, der ähnlich wie Scream als ProgrammSchnittstelle (API) für Audio-Patches konzipiert ist, auf der lightweight Java Applikationen aufsetzen können. Da Meloncillo fast nichts von SuperCollider weiß – dies liegt in der Obhut der Scripte –, läßt sich prinzipiell auch sclang als Server benutzen, wodurch komplexere algorithmische Verfahren möglich sind. Der Einfachheit halber wird jedoch nur ein Beispiel für die direkte Kommunikation mit scsynth dargestellt. Im Gegensatz zu sclang wurde der Synth Server bereits auf andere Plattformen portiert und kann unter Mac OS X, Linux i386, Linux PPC und Win32 benutzt werden. Da Meloncillo die OSC Messages über UDP an SuperCollider versendet, kann SuperCollider auch auf einem anderen Rechner als Meloncillo laufen, wenn diese Rechner über ein LAN verbunden sind. Die Synchronisation der Uhren beider Rechner ist hingegen noch ungelöst (vgl. Abschnitt 6.2). SuperCollider kann sowohl in Echtzeit, als auch in einem speziellen NonRealTime-Modus (NRT) gestartet werden. Mit wenigen Anpassungen lassen sich die Lisp Scripte und SuperCollider Patches gleichzeitig für Realtime-Synthese und Bounce-to-Disk verwenden, da SuperCollider im NRT Modus weiterhin über OSC gesteuert wird. Die OSC-Bundles werden dabei sequentiell aus einer Datei gelesen, statt sie in Echtzeit zu empfangen. 21 22 siehe dazu [McCartney 2002] Deren Zahl halbiert sich etwa, wenn man eng verwandte Befehle zusammenfaßt, wie /b_set und /b_setn für das Beschreiben eines Puffers. Flacher Adreßraum bedeutet, daß Kommandos nicht hierarchisch geschachtelt und durch Schrägstriche getrennt werden, also ein Puffer beispielsweise direkt mit "/b_free 789" statt "/buffer/789/free" freigegeben wird. 57 5 Plug-In Schnittstellen Root Node numTrns = Zahl der Transmitter (5) numRcv = Zahl der Receiver (4) Master Group Input Group Mix Group Phasor Synth Control−Bus 0...numTrns−1 Vektor aus Input Synths Matrix aus Mix Synths Audio−File Buffer Audio−Bus Audio−File Buffer Audio−Bus Audio−File Buffer Audio−Bus Audio−File Buffer Audio−Bus Audio−File Buffer Audio−Bus Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Sense−Buf Matrix aus Sensitivitäts−Puffern Audio−Hardware−Output Sense−Buf Audio−Hardware−Output Sense−Buf Audio−Hardware−Output Sense−Buf Audio−Hardware−Output Sense−Buf 0...numRcv−1 Abbildung 5.5: Nodes, Busse und Buffer für einen Amplituden-Mixer in SuperCollider Beispiel eines einfachen Amplituden-Pannings scsynth verwaltet in gewisser Analogie zum MUSIC V Konzept Synthesizer, die aus UnitGeneratoren bestehen. Ein solcher durch eine UGen-Graph-Function beschriebener Synthesizer ist ein Knoten-Punkt in einem hierarchischen Baum, den scsynth verwaltet. Neben Synth-Nodes gibt es Group-Nodes, die mehrere Synthesizer oder Gruppen zusammenfassen. Eine Gruppe ist eine Liste aus Knoten. Neue Knoten werden entweder an den Anfang oder das Ende der Liste gesetzt. Innerhalb einer Gruppe werden die Knoten in der Reihenfolge ihrer Position in der Liste abgearbeitet. Die Reihenfolge ist entscheidend beim Entwurf eines Patches – wird zum Beispiel ein Soundfile eingelesen (Input-Knoten) und auf einen Bus geschickt, auf den ein Mixer zugreifen soll (Mix-Knoten), so muß der Input-Knoten vor dem Mix-Knoten ausgeführt werden. In den OSC Messages werden Synthesizer und Gruppen durch eine eindeutige ganze Zahl, die Node-ID, angesprochen, die jedoch keinen Einfluß auf die Reihenfolge der Abarbeitung hat. 58 5 Plug-In Schnittstellen Ebenfalls klassisch in SuperCollider ist die Trennung zwischen Controlrate- und AudiorateSignalen. Diese laufen über ein globales Bussystem, was vor allem hinsichtlich der AudioDaten den Vorteil hat, daß beliebig viele Synthesizer aus einem Audio-Bus lesen oder in einem Audio-Bus zusammengemischt werden können. Neben Bussen gibt es Puffer, die intern oder per OSC blockweise beschrieben werden können. Um einen einfachen Matrix-Mixer nach dem Amplituden-Panning Prinzip zu realisieren, werden Gruppen und Synthesizer nach dem in Abbildung 5.5 dargestellten Schema kreiert. Drei verschiedene Synthesizer kommen zum Einsatz, die in sclang programmiert wurden: Quelltext 5.5: synthdef-sources.sc // reads input from sound file // and writes it to an audio bus SynthDef( "cillo−input", { arg i aInBuf, i aOutBus, i gain = 1.0; Out.ar( bus: i aOutBus, channelsArray: DiskIn.ar( numChannels: 1, bufnum: i aInBuf ) ∗ i gain ); }).writeDefFile( p ); // mixing pipe taking an input audio // bus, a control buf for amplitude // modulation and an audio output bus SynthDef( "cillo−mix", { arg i aInBus, i aOutBus, i kInBuf, i kPhasorBus; Out.ar( bus: i aOutBus, channelsArray: In.ar( bus: i aInBus ) ∗ BufRd.kr( numChannels: 1, bufnum: i kInBuf, phase: In.kr( bus: i kPhasorBus ))); }).writeDefFile( p ); // one phasor object represents something // like a synchronized motor for all // control rate amplitude buffer reads. // a trigger is fired twice per buffer cycle SynthDef( "cillo−phasor", { arg i rate, i bufSize, i kPhasorBus; var clockTrig, phasorTrig, clockRate, phasorRate, controlRate; controlRate phasorRate clockRate clockTrig phasorTrig = = = = = SampleRate.ir / 64; i rate / controlRate; 2 ∗ i rate / i bufSize; Impulse.kr( freq: clockRate ); PulseDivider.kr( trig: clockTrig, div: 2, start: 1 ); SendTrig.kr( in: clockTrig, id: 0, value: PulseCount.kr( trig: clockTrig )); Out.kr( bus: i kPhasorBus, channelsArray: Phasor.kr( trig: phasorTrig, rate: phasorRate, start: 0, end: i bufSize )); }).writeDefFile( p ) cillo-input liest mit dem DiskIn UGen ein Soundfile ein und schreibt es auf einen Bus, cillo-mix mischt einen Eingangsbus (Soundfile) auf einen Ausgangsbus (Soundkarten-Ausgang). Die Lautstärke wird aus Puffern gelesen, die blockweise mit dem OSC Befehl "/b_setn" von Meloncillo gefüllt werden. Der Phasor-Synthesizer generiert ein Sägezahn-Signal, das diese Puffer zyklisch abtastet. Die Instantiierung der Gruppen und Synthesizer erfolgt vom Lisp-Script aus mit der osc-bundle-send[-and-wait] Funktion. Hier ein Beispiel: 59 5 Plug-In Schnittstellen (datagram−channel−open 1977 "localhost" 57110) (if (null (osc−bundle−send−and−wait 1977 0.0 (list (list "/g new" master−group 1 0 input−group 0 master−group mix−group 1 master−group) (list "/d load" synthdefs)) "/done" 2000 )) (println "TIMEOUT! group creation, definition load") ; else NIL ) 1977 ist der Identifier für den in der ersten Zeile geöffneten Datagramm-Kanal. Das Bundle enthält die zwei Messages "/g_new" zur Erzeugung der Gruppen-Knoten und "/d_load" zum Einlesen der Synthesizer-Definitionen aus einer Festplatten-Datei. Die letzten beiden Argumente der OSC-Funktion legen fest, daß maximal zwei Sekunden auf die Antwort-Nachricht "/done" gewartet werden soll. Die Funktion liefert diese Antwort-Nachricht zurück oder NIL, wenn innerhalb dieser Zeitspanne nicht geantwortet wurde. Während der Realtime Modus aktiv ist, werden die Transport-Befehle an das Lisp-Script weitergegeben. Es muß dafür die Funktionen position, play und stop definieren. Aus Performance-Gründen wird das Script nicht damit beauftragt, kontinuierlich OSC-Nachrichten zum Auffüllen der Sense-Puffer zu erzeugen. Stattdessen übergibt es der im Realtime-Modus etwas modifizierten source-request Funktion einen vorher mit dem Skelett der OSC-Message ("/b_setn") initialisierten Byte-Buffer und eine Liste von Anweisungen, die auf diesem Puffer ausgeführt werden sollen: (source−request "SENSE" (cons trnsidx rcvidx) 1978 (list (list "INT" bufidx msgbuf−off) (list "VAR" "BUFOFF" (+ msgbuf−off 4)) (list "STREAM" (+ msgbuf−off 12)) (list "SEND" 1977) )) 1978 ist der Identifier des Byte-Buffers, in den die Nachricht kodiert wird. Die Befehlsliste bewirkt, daß der (SuperCollider-)Puffer-Index und der Puffer-Lese-Index jeweils ersetzt und die Sensitivitätsdaten ("STREAM") übertragen werden, bevor die Nachricht an den DatagrammKanal mit dem Identifier 1977 versandt wird. Meloncillo kennt darüber hinaus einen speziellen Sync-Befehl23 : Der Phasor in Quelltext 5.5 sendet zweimal pro Durchlauf mit dem SendTrig UGen eine OSC-Nachricht "/tr" an Meloncillo. Dadurch wird der Versand neuer Sensitivitäts-Puffer ausgelöst. Würde Meloncillo nach seiner internen Uhr die Puffer versenden, könnten diese manchmal zu früh ankommen. Neue Trigger-Befehle werden mehrfach pro Puffer-Periode ausgewertet, dies ist der Grund für die spezielle Notification-Rate in Abbildung 5.4. Gleichzeitig kann das Programm überprüfen, ob Drop-Outs aufgetreten sind und meldet dies dem Benutzer. Für eine zukünftige Version wird geprüft, ob sich die Synchronisierung einfacher durch die Time-Tags der Bundles lösen läßt. Das Script und die SynthDefs können als Ausgangspunkt dienen, mit neuen Synthese-Modellen zu experimentieren. Die Input-Synths könnten zum Beispiel durch Live-Inputs ersetzt wer- 23 (target-request "SYNC" 0 <datagram-channel-id>) 60 5 Plug-In Schnittstellen den24 , zwischen die Input- und Mix-Stufe kann eine Filter, (Doppler-)Delay oder VerzerrerEinheit gesetzt werden. Die Mix-Stufe selbst kann modifiziert werden, oder ihre Ausgänge auf weitere Busse statt direkt auf die Hardware-Outputs geschickt werden. 24 Da scsynth allerdings kein MIDI versteht, muß noch eine Lösung zur Synchronisierung z.B. mit einem Harddisk-Recording-Programm gefunden werden. Man kann versuchen, dazu sclang zu verwenden. 61 6 Resumé 6.1 Anwendungsbeispiel Abschließend sollen an einem SuperCollider Patch ein paar Möglichkeiten des Programms demonstriert werden. Ausgangspunkt ist ein Synthesizer nach Abbildung 5.5. Er soll wie folgt erweitert werden: • zuschaltbarer Doppler-Effekt für die Transmitter-Bewegungen • zuschaltbarer räumlich gerichteter Verzerrer • zuschaltbarer Hall • optionale Umkehrung des Modells, so daß die Receiver die Ausgangsklänge symbolisieren und die Transmitter diese Klangfelder als bewegte Mikrophone“ abtasten und zu ” den Lautsprechern leiten Doppler-Effekt Der Doppler-Effekt beschreibt das Phänomen, daß sich die wahrgenommene Tonhöhe eines Klangkörpers in Abhängigkeit von seiner Bewegung relativ zum Beobachter verändert. Nähert sich der Klangkörper dem Beobachter, so wird die Wellenlänge effektiv verkürzt und die Tonhöhe steigt, der umgekehrte Fall tritt auf, wenn sich der Klangkörper wegbewegt. Um einen Doppler-Effekt zu realisieren, bedient man sich einer variablen interpolierenden DelayLine. Die momentane Delay-Zeit korrespondiert mit dem Abstand der Klangquelle vom Beobachter und beträgt im Medium Luft bei Raumtemperatur etwa ∆t = ∆d/(344m/s). Der Doppler-Effekt wird als Insert in den Signalfluß gesetzt. Ein Insert kann in SuperCollider realisiert werden, indem ein Audio-Bus mittels In.ar eingelesen und das Ergebnis mit ReplaceOut.ar zurückgeschrieben wird. Zur Berechnung des Doppler-Shifts werden im Lisp Script mit weiteren (source-request) Befehlen nun zusätzlich zu den Sensitivitäten auch die Trajektorien-Koordinaten angefordert. Für die Beobachter-Position wird vereinfachend der Surface-Mittelpunkt (0.5, 0.5) angenommen, dies läßt sich später leicht parametrisieren. Die Trajektorien-Daten werden analog zum Mix-Synth (Quelltext 5.5) mit einem durch den Phasor betriebenen BufRd abgetastet. Das aus X- und Y-Koordinaten bestehende StereoSignal wird mit Select UGens aufgetrennt und die Distanz nach dem Satz des Pythagoras berechnet: 62 6 Resumé Quelltext 6.1: cillo-doppler.sc SynthDef( "cillo−doppler", { arg i aBus, i kInBuf, i kPhasorBus, i extent = 0.04; var traj, dly; traj= BufRd.kr( numChannels: phase: In.kr( bus: i dly = ((Select.kr( which: 0, (Select.kr( which: 1, 2, bufnum: i kInBuf, kPhasorBus )); array: traj ) − 0.5).squared + array: traj ) − 0.5).squared).sqrt ∗ i extent; ReplaceOut.ar( bus: i aBus, channelsArray: DelayC.ar( in: In.ar( bus: i aBus ), maxdelaytime: 2 ∗ i extent, delaytime: dly )); }).writeDefFile( p ); Der Benutzer bestimmt die Raum-Größe auf der graphischen Oberfläche des Lisp Plug-Ins. Der Normalisierungsfaktor für die Delay-Zeit i_extent wird bereits im Lisp Script berechnet. DelayC ist eine kubisch interpolierende Delay-Line. maxdelaytime bestimmt die interne Puffergröße und muß so gewählt sein, daß keine Verzögerungen auftreten, die größer als dieser Wert sind. Verzerrer Unter Verzerrung kann man allgemein eine Signaltransformation verstehen, die nicht durch ein lineares System beschrieben werden kann. Eine einfache Verzerrung ist beispielsweise die Transformation y ← x2 . Ein Verzerrer kann mit einem Median-Filter gebaut werden. Wenn man jeweils von wenigen benachbarten Samples den Median berechnet, werden kurze Spikes eliminiert. Subtrahiert man nun das Originalsignal, bleiben hauptsächlich diese kurzen Signalspitzen übrig. Das Differenz-Signal wird mit dem geglätteten Median-Signal moduliert. Mit einem Amplituden-Envelope-Follower kann das verzerrte Signal grob an die ursprüngliche Lautstärke angepaßt werden. Der Verzerrer soll von einem Richtungsvektor gesteuert werden. Ein zusätzlicher Transmitter wird dafür benutzt. Er bekommt den speziellen Namen ’d’ (Distortion) und wird aufgrund dieses Namens vom Lisp Script erkannt und separat behandelt. Für jeden Ausgangskanal wird ein Distortion-Synth erzeugt, der in Abhängigkeit von diesem d-Transmitter zwischen dem trockenen und verzerrten Signal überblendet. Das Mischungsverhältnis wird aufgrund des Winkels, den der d-Transmitter und der jeweilige Receiver zum Surface-Mittelpunkt bilden, gewählt. Wenn A die gegenwärtige Position des d-Transmitters, B der Surface-Mittelpunkt und C der Ankerpunkt des Receivers sind, ergibt sich der Winkel nach arctan (Cx −Bx )·(Ay −By )−(Cy −By )·(Ax −Bx ) (Cx −Bx )·(Ax −Bx )+(Cy −By )·(Ay −By) Das Mischungsverhältnis wird daraus so berechnet, daß bei einem Winkel von 0◦ nur die Verzerrung, bei 180◦ nur das trockene Signal zu hören ist. Mit einem Divergenz-Parameter i_narrow läßt sich die Verlauf zwischen 0◦ und 180◦ einstellen. Hier die Synthesizer-Definition: 63 6 Resumé Quelltext 6.2: cillo-distortion.sc SynthDef( "cillo−distortion", { arg i aBus, i kInBuf, i kPhasorBus, i locX, i locY, i gain = 2.0, i narrow = 4.0; var traj, dtrajx, dtrajy, dstatx, dstaty, da, dry, mix, med, flt, norm mul, norm add; dstatx = dstaty = norm mul= norm add= traj dtrajx dtrajy i locX − 0.5; i locY − 0.5; −1.0 / pi; 1.0; = BufRd.kr( numChannels: 2, bufnum: i kInBuf, phase: In.kr( bus: i kPhasorBus )); = Select.kr( which: 0, array: traj ) − 0.5; = Select.kr( which: 1, array: traj ) − 0.5; // delta angle normalized to 0.0 ... 1.0 // (where 1.0 is 0 degrees, 0.5 is +/− 90 degrees, // 0.0 is 180 degrees) da = abs( atan2( (dstatx ∗ dtrajy) − (dstaty ∗ dtrajx), (dstatx ∗ dtrajx) + (dstaty ∗ dtrajy) )) ∗ norm mul + norm add; mix = min( 1.0, (dtrajx.squared + dtrajy.squared) / 0.125 ) ∗ da.pow( i narrow ); dry med flt = In.ar( bus: i aBus ); = Median.ar( length: 3, in: dry ); = Normalizer.ar( in: (dry − med) ∗ med, level: Amplitude.kr( in: dry, mul: i gain ), dur: 0.005 ); ReplaceOut.ar( bus: i aBus, channelsArray: Median.ar( length: 3, in: flt, mul: mix, add: DelayN.ar( in: dry, mul: 1.0 − mix, delaytime: 0.1, maxdelaytime: 0.01 ))); }).writeDefFile( p ); Das trockene Signal muß mit DelayN verzögert werden, um den Look-Ahead des MedianFilters auszugleichen und Kammfilter-Effekte bei der Überblendung zu verhindern. Hall Mit Allpass-Filtern kann man einen primitiven Hall simulieren. Ähnlich dem Verzerrer verwenden wir ein Session-Objekt zur Steuerung des Halls: Einen zusätzlichen Receiver mit dem speziellen Namen ’e’ (Echos). Angenommen, die normalen Receiver befinden sich in einer kreisförmigen Anordnung. Dann kann der e-Receiver einfach in deren Mitte plaziert werden; wird ein Transmitter von der Kreisbahn zur Mitte hin abgelenkt, so wird sein Signal in die Hall-Sektion gegeben. Der Einfachheit halber ist der Input dieser Hall-Sektion ein Mono-Bus, und für jeden Ausgangskanal wird dieses Mono-Signal mit einem Allpass-Filter verhallt, das eine zufällige variierende Delay-Zeit hat: 64 6 Resumé Normaler Modus Input Group Doppler Group Mix Group Echo + Distortion Group Input−Synth Echo−Synth Mix−Synths Matrix ... Input−Synth Sense−Bufs (e−Receiver) ... numInputs Sense−Buf Matrix Echo−Synth (insert) Doppler−Synth Audio−Output Audio−Output ... Traj−Buf Matrix Distortion−Synth ... (insert) ... Doppler−Synth Distortion−Synth Traj−Buf (d−Transmitter) numInputs = Zahl der Transmitter numOutputs = Zahl der Receiver numOutputs Umgedrehter Modus Distortion Group Input−Synth Mix Group Doppler Group Sense−Buf Matrix Mix−Synths Matrix ... Input−Synth (insert) (insert) Distortion−Synth ... Audio−Output ... Traj−Buf (d−Transmitter) Audio−Output Distortion−Synth Doppler−Synth ... numInputs Input Group Doppler−Synth Traj−Buf Matrix numInputs = Zahl der Receiver numOutputs = Zahl der Transmitter numOutputs Abbildung 6.1: Erweiterter SuperCollider Synthesizer 65 6 Resumé Abbildung 6.2: Steuerelemente und Script Oberfläche für den erweiterten Synth Quelltext 6.3: cillo-echo.sc SynthDef( "cillo−echo", { arg i aInBus, i aOutBus; Out.ar( bus: i aOutBus, channelsArray: LPZ2.ar( in: AllpassL.ar( in: In.ar( bus: i aInBus ), maxdelaytime: 0.31, delaytime: LFNoise1.kr( 0.1, mul: 0.1, add: 0.2 ), decaytime: 3 ) ) ); }).writeDefFile( p ); Der Lowpass-Filter LPZ2 dunkelt die Hallfarbe etwas ab. Modell-Umkehrung Um das Modell so umzukehren, daß die Receiver Klangfelder darstellen und die Transmitter bewegte Mikrophone/Lautsprecher, muß das Lisp Script so verändert werden, daß Receiver durch abstrakte Output-Objekte und Transmitter durch abstrakte Input-Objekte ersetzt werden. In der Initialisierung kann dann die Zuordnung einfach umgetauscht werden. Zusätzlicher Aufwand entsteht dadurch, daß die Indices der Transmitter und Receiver bei der Quelldaten-Anforderung mit (source-request) nicht umgedreht werden dürfen. Auch müssen die Gruppen-Knoten unterschiedlich angeordnet werden, damit die Reihenfolge der DSP-Blöcke korrekt bleibt. Wenn man davon ausgeht, daß die Verzerrer unabhängig vom Modell immer die Receiver bearbeiten und der Doppler immer auf die Transmitter einwirkt (die Receiver sind ja unbewegt und können daher keinen Doppler-Shift erzeugen), ergeben sich die beiden Schemata nach Abbildung 6.1. Das Lisp Script scrt-demo.lisp ist zusammen mit einer Beispiel-Session und BeispielKlängen auf der beigefügten CD-ROM enthalten. Die vom Script generierten GUI Para- 66 6 Resumé meter sind in Abbildung 6.2 rechts zu sehen. Der Normal-Modus, in dem die Transmitter den Soundfiles zugeordnet sind, ist angewählt. Die Surface links zeigt einen Ausschnitt der d-Transmitter Trajektorie zum Steuern der Verzerrung. Zu sehen ist auch der kreisförmige Umriß des in der Mitte plazierten e-Receivers zum Ansteuern des Halls. 6.2 Probleme Während der Entwicklung der vorliegenden Arbeit sind keine ungelösten Probleme im internen Programmverhalten aufgetreten. Die Thread-Synchronisierung hat einige Zeit in Anspruch genommen und insbesondere in der Anfangsphase viele Bugs enthalten. Dasselbe gilt für die dynamische Anpassung an Preferences-Änderungen mit dem java.util.prefs Paket. Insbesondere hat sich als nachteilig erwiesen, daß es einen eigenen Event-Dispatcher verwendet, der außerhalb des AWT Threads läuft, und daß die Ereignisse keine Informationen darüber tragen, wer die Preferences verändert hat, so daß umfangreiche Vorkehrungen zur Verhinderung von Deadlocks getroffen werden mußten. Die interne Umstellung aller Objekte beim Laden einer Session hätte eleganter durch einen zentralen Mechanismus gelöst werden können. Das Programm enthält in der aktuellen Version 0.66 noch zahlreiche kleinere Bugs, die nicht vital für die Benutzung sind. Mit dem Update der Apple Java VM von Version 1.4.2 03 nach 1.4.2 05 kurz vor Fertigstellung der Arbeit wurde die Graphikdarstellung des Timeline Fensters im Echtzeit Modus leider sehr langsam und flackert.1 Dieses Problem ist vermutlich auf eine Änderung des Double-Buffering Mechanismus zurückzuführen und muß in der nächsten Version von Meloncillo dringend beseitigt werden. Ungelöst sind noch Probleme beim Betrieb im Netzwerk. Obwohl in der Anfangsphase ein Test erfolgreich lief, in dem auf einem Computer Meloncillo und auf dem anderen SuperCollider lief, wurde die Realtime-Engine von Meloncillo aus Performance-Gründen später neu geschrieben. Weitere jüngst vorgenommene Tests ergaben, daß die beiden Rechner nicht synchron bleiben. Die Zeitspanne, die vergeht, bis die ersten Dropouts auftreten, schwankt je nach Rechner-Paar zwischen einer halben Minute und einer Viertelstunde. Da die Clock-Unterschiede eigentlich so klein sein sollten, daß bei entsprechend gewählten PufferGrößen ein Synchronisationsverlust erst nach einer Zeitspanne in der Größenordnung von Stunden auftreten kann, muß die Ursache im Timing-Schema des OSC-Datenversands gesucht werden. Möglicherweise läßt sich das Problem lösen, indem die OSC-Befehle zum Puffer-Update mit Time-Tags versehen werden.2 Nichtsdestotrotz sollte langfristig eine SlaveSynchronisierung in Meloncillo integriert werden, um eine synchronen Betrieb mit HarddiskRecording-Programmen zu ermöglichen. 1 Man kann sich momentan nur behelfen, indem das Fenster zeitweilig geschlossen wird. Ein positiver Aspekt des VM Updates ist das Verschwinden eines Bugs, der sich in gelegentlichen Stack-Overflows äußerte, die innerhalb der Bibliotheken auftraten und damit unmöglich zu eliminieren waren. 2 Ein Vorteil des gegenwärtigen Mechanismus – der Versand nach Aufforderung durch eine /tr Nachricht – besteht darin, daß eine Anbindung an Max/MSP leichter zu realisieren ist, denn die OSC-Externals von Max/MSP behandeln Time-Tags derzeit nicht automatisch. 67 6 Resumé 6.3 Ausblick Die weitere Entwicklung des Programms kann in Detailverbesserungen und größere Ergänzungen und Umstrukturierungen unterteilt werden. Zur ersten Kategorie zu zählen sind • Anpassung der Oberfläche und Tastatur-Shortcuts unter Linux und Windows • konfigurierbare Farbgebung • Dehnen und Kürzen des Zeitabschnitts im Filter Dialog (Resampling) • Verbesserung der geometrischen Zeichentools • Entwicklung einer DTD für die Session-Datei • Shuffle- und Slip-Modus für Timeline-Operationen analog zu ProTools Die größeren Ergänzungen hängen im wesentlichen davon ab, wie sich das Programm in der Praxis bewährt. Wichtige Elemente werden sein • Stabile Realtime Performance im Netzwerk • Synchronisierung mit Harddisk-Recording Programmen • Anbindung an Max/MSP 4.5 • Erweiterung der Timeline um frei setzbare Markierungen • evtl. Erweiterung um eine Layer-Struktur • Erweiterung der Receiver und Transmitter Interfaces um Attribute • script-generierte Preferences Karten Wie bereits geschildert, bricht die Synchronisation momentan bei Betrieb im Netzwerk früher oder später zusammen. Obwohl sich das Problem voraussichtlich leicht lösen läßt, wird eine Unterstützung von OSC-Time-Tags angestrebt. Wenn eine Slave-Synchronisierung in Meloncillo eingebaut wird, sollte zugleich ein grundlegendes Konzept für eine OSC-Server Schnittstelle entworfen werden. Eine einfache Timecode Steuerung (z.B. auf MIDI-Timecode Basis) sollte entwickelt werden, so daß ein synchrones Einspielen von Spuren aus einem Harddisk-Recording Programm möglich wird; momentan müssen die zu spatialisierenden Klänge zunächst gebounct werden, was sehr hinderlich ist. Eine Zwischenlösung kann wahrscheinlich mit sclang erreicht werden. Es läßt sich ebenso wie scsynth von einem OSC-Client steuern. Ein OSCresponderNode Objekt müßte auf den Transport-Start in Meloncillo reagieren und einen entsprechenden MIDI Befehl an eine Applikation wie Logic Pro weiterleiten. Das Ansteuern von Max/MSP macht momentan wenig Sinn, weil das OSC-Objekt otudp read von Matt Wright alle Message-Argumente in primitive Max-Typen übersetzt, was für das Senden großer Floating-Point Puffer ungeeignet ist. Max/MSP 4.5 bietet eine integrierte Java-Schnittstelle (mxj) an. Ein einfaches Plug-In soll dafür entwickelt werden, das die Sensitivitäts-UDP-Pakete empfängt und direkt in MSP-Puffer schreibt. Um ein Stück besser überblicken zu können, sind Zeitmarker erforderlich. Diese könnten auch mit Scripten generiert werden oder von Scripten ausgelesen und zur Klangsynthese benutzt werden. 68 6 Resumé Wenn, wie im letzten Beispiel gezeigt, mit mehreren Klangtransformationen gearbeitet wird, kann die Surface schnell unübersichtlich werden. Zu überlegen ist, wie möglichst einfach die Form einer Ebenen-Struktur in die Session gebracht werden kann. Diese Ebenen könnten entweder optisch umgeschaltet oder überlagert dargestellt werden. Receiver und Transmitter sollten mit einer Attribute-Mappe ausgestattet werden. Um einfache Features zu integrieren, wie zum Beispiel die Möglichkeit, Transmitter stummzuschalten oder solo abzuhören, müssen die Scripte momentan spezielle GUI Felder auf ihre Plug-In Oberflächen addieren. Er wäre effektiver, mit einem einfachen get und set Mechanismus den Transmittern und Receivern beliebige Attribute hinzuzufügen, die dann auch von den Editoren unterstützt werden. Ein Transmitter Editor könnte dann Solo- und MuteButtons direkt im Timeline Fenster darstellen. Getrennte Methoden wie getName, setName, getAnchor, setAnchor würden in diesem allgemeinen Attribute-System aufgelöst werden. Von Beta-Testern ist der Wunsch geäußert worden, eine Input/Output Konfiguration für die Audio-Hardware in Meloncillo vornehmen zu können. Das kollidiert zunächst mit der Grundidee, daß das Programm nichts über konkrete Signalverarbeitung weiß. Eine Alternative wären Preferences-Karten, die dynamisch von Scripts generiert werden. Wenn in einer der nächsten Versionen die Anbindung an Max/MSP realisiert ist, müßten die Preferences nicht innerhalb des Programmes erweitert, sondern lediglich ein zusätzliches Preferences-Script angemeldet werden. Die Hauptaufgabe wird jedoch sein, das Programm ausführlicher durch möglichst viele verschiedene Anwender in der Praxis zu erproben. 69 Literaturverzeichnis [Chowning 1971] John Chowning, The Simulation of Moving Sound Sources. Journal of the AES Vol. 19, No. 1, Januar 1971 (Nachdruck in Computer Music Journal Vol. 1 No. 3, Juni 1977, S. 48–52) [Eimert/Humpert 1973] Herbert Eimert / Hans Ulrich Humpert, Das Lexikon der elektronischen Musik (Artikel Raum“, Raumton“, Raumakustik“ und ” ” ” Steuerung“). Regensburg 1973 ” Frank Gertig / Julia Gerlach / Golo Föllmer, Musik..., verwandelt – Das Elektronische Studio der TU Berlin 1953–1995. Hofheim 1995 [Gertig et al. 1995] [Gosling et al. 2000] James Gosling / Bill Joy / Guy Steele / Gilad Bracha, The Java Language Specification, 2nd Edition. Boston 2000. Online publiziert: http://java.sun.com/docs/books/jls/second_edition/ html/j.title.doc.html [Haller 1995] Hans Peter Haller, Das Experimentalstudio der Heinrich-StrobelStifung des Südwestfunks Freiburg 1971–1989 : Die Erforschung der Elektronischen Klangumformung und ihre Geschichte (Band 1, Zur Technik der Elektronischen Klangumformung). Baden-Baden 1995 [Hein 1999] Folkmar Hein, Von der Quadrophonie zur Raumklangsteuerung – Überlegungen zur Konzeption des neuen TU-Studios. In: Bernhard Feiten / Folkmar Hein / Axel Röbel / Werner Schaller (Hrsg.), Impulse und Antworten – Festschrift für Manfred Krause. Berlin 1999, S. 85–110 [Jot/Warusfel 1995] Jean-Marc Jot / Olivier Warusfel, Spat˜ : A Spatial Processor for Musicians and Sound Engineers. CIARM: International Conference on Acoustics and Musical Research, Mai 1995 [Kleiner et al. 1993] Mendel Kleiner / Bengt-Inge Dalenbäck / Peter Svensson, Auralization – An Overview. Journal of the AES Vol. 41, No. 11, November 1993, S. 861-875 [Lea 1997] Doug Lea, Concurrent Programming in Java – Entwurfsprinzipien und Muster. Bonn 1997 [Leahy 2004] Michael Leahy, SCREAM – SuperCollider Resource for ElectroAcoustic Music. Online-Publikation 2004: http://audio.egregious.net/scream/whitepapers/scream_ whitepaper.v1.1.1.pdf 70 Literaturverzeichnis [Loy 1985] Gareth Loy, SNDPATH. In: Computer Audio Research Laboratory (CARL) Program Guide. La Jolla 1985 [Mayer 1995] Otto Mayer, Programmieren in COMMON LISP. Heidelberg, 1995 [Malham 1998] D. G. Malham, Spatial Hearing Mechanisms and Sound Reproduction. Online-Publikation 1998: http://www.york.ac.uk/ inst/mustech/3d_audio/ambis2.htm [McCartney 1996] James McCartney, SuperCollider: A New Real Time Synthesis Language. ICMC Paper 1996 [McCartney 2002] James McCartney, Rethinking the Computer Music Language: SuperCollider. In: Computer Music Journal Vol. 26, No. 4, Winter 2002, S. 61–68 [Momenti/Wessel 2003] Ali Momenti / David Wessel, Characterizing and Controlling Musical Material Intuitively with Geometric Models. Proc. of the 2003 Conference on New Interfaces for Musical Expression (NIME-03), Montreal, S. 54–62 [Moore 1983] F. Richard Moore, A General Model for Spatial Processing of Sounds. Computer Music Journal Vol. 7, No. 3, Herbst 1983, S. 6–15 [Moore 1985] F. Richard Moore, The CMusic Sound Synthesis Program. La Jolla 1985 [de la Motte-Haber 1996] Helga de la Motte-Haber (Red.), Klangkunst. Katalog von Sonambiente – Festival für Hören und Sehen. Hrsg. von der Akademie der Künste, Berlin 1996 [de la Motte-Haber 1993] Helga de la Motte-Haber, Die Musik von Edgard Varèse. Hofheim 1993 [Mühlethaler/Schuppisser 2004] Christian Mühlethaler / Alexander Schuppisser, Sonificator – A Java Framework for writing Applications that use SuperCollider as Sound-Engine. Vortrag auf der Linux Audio Developer (LAD) Conference 2004. Online-Slides: http://www.linuxdj. com/audio/lad/contrib/zkm_meeting_2004/slides/friday/ muehletaler+schuppisser-supercollider.pdf [Pulkki 2001] Ville Pulkki, Spatial Sound Generation and Perception by Amplitude Panning Techniques. Espoo, 2001 [Radtke 1988] Torsten Radtke, Entwurf und Bau eines computergesteuerten 4Kanal-Mischers nach ARD-Pflichtenheft. Diplomarbeit TU Berlin 1988 [Ruschkowski 1998] André Ruschkowski, Elektronische Klänge und musikalische Entdeckungen. Stuttgart 1988 [Schneider 1995] Thomas Schneider, Programm zur Steuerung multipler Audiosignale zur Simulation räumlich bewegter Schallquellen. Magisterarbeit TU Berlin 1995 71 Literaturverzeichnis [Seelig 1990] Thomas Seelig, Entwicklung einer grafischen Benutzeroberfläche für ein MIDI-gesteuertes quadrophones Mischpult. Magisterarbeit TU Berlin 1990 [Stuart 1996] J. Robert Stuart, The Psychoacoustics of Multichannel Audio. AES UK Audio for New Media Conference, Paper ANM-12, 1996 [Supper 1997] Martin Supper, Elektroakustische Musik und Computermusik: Geschichte, Ästhetik, Methoden, Systemen. Darmstadt 1977 [de Vries/Boone 1999] Diemer de Vries / Marinus M. Boone, Wave Field Synthesis and Analysis Using Array Technology. Proc. IEEE Workshop on Appl. of Signal Proc. to Audio and Acoustics, New Paltz, Oktober 1999 [Wishart 1994] Trevor Wishart, Audible Design : A Plain and Easy Introduction to Practical Sound Composition. York 1994 [Wright/Freed 1997] Matthew Wright / Adrian Freed, Open SoundControl : A New Protocol for Communicating with Sound Synthesizers. Proc. of the 1997 Intl. Computer Music Conference (ICMC), Thessaloniki, S. 101–104 [Wright et al. 2003] Matthew Wright / Adrian Freed / Ali Momenti, OpenSound Control : State of the Art 2003. Proc. of the 2003 Conference on New Interfaces for Musical Expression (NIME-03), Montreal, S. 153–159 [Zmölnig et al. 2003] Johannes Zmölnig / Alois Sontacchi / Winfried Ritsch, The IEMCube : A Periphonic Re-/Production System. Proc. of the AES 24th Intl. Conference, 2003, S. 21–25 72 Anhang: Abbildungen, Quelltexte Abbildungsverzeichnis 1.1 1.2 1.3 1.4 Σ 1 Oberfläche . . . . . . . . . . . . . Panning Objekte in Digital Performer VBAP Anwendung in Max/MSP . . . Perzeptive Parameter in Spat˜ . . . . . . . . . . . . . . . . . . . . . . . . 11 14 17 18 3.1 3.2 Legende . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Session Struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 29 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 Surface Fenster . . . . . . . . . . . . . . . . Hilfspaletten . . . . . . . . . . . . . . . . . Bézier-Kurve mit variabler Geschwindigkeit Editor für SigmaReceiver . . . . . . . . . . Matrix Meter . . . . . . . . . . . . . . . . . Timeline Fenster . . . . . . . . . . . . . . . Transport Palette . . . . . . . . . . . . . . . Dezimation von Trajektorien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 36 39 40 40 41 41 42 5.1 5.2 5.3 5.4 5.5 Plug-In Interfaces und Klassen . . . . . . . . . . . . . . . . . . . . . . Plug-Ins zur Trajektorien-Filterung . . . . . . . . . . . . . . . . . . . . RealtimeConsumer Profile . . . . . . . . . . . . . . . . . . . . . . . . . Realtime Datenströme . . . . . . . . . . . . . . . . . . . . . . . . . . . Nodes, Busse und Buffer für einen Amplituden-Mixer in SuperCollider . . . . . . . . . . . . . . . . . . . . 45 46 47 48 58 6.1 6.2 Erweiterter SuperCollider Synthesizer . . . . . . . . . . . . . . . . . . . . . . Steuerelemente und Script Oberfläche für den erweiterten Synth . . . . . . . 65 66 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Quelltexte 3.1 3.2 3.3 3.4 4.1 4.2 4.3 5.1 5.2 XMLRepresentation.java (io package) . . . . . . Receiver.java (receiver package) . . . . . . . . . . Transmitter.java (transmitter package) . . . . . . ReceiverCollectionListener.java (receiver package) VirtualSurface.java (gui package) . . . . . . . . . AbstractGeomTool.java (gui package) . . . . . . TrackSpan.java (io package) . . . . . . . . . . . . RenderPlugIn.java (render package) . . . . . . . RenderConsumer.java (render package) . . . . . . 73 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 30 31 32 35 38 42 44 45 Quelltexte 5.3 5.4 5.5 6.1 6.2 6.3 RealtimeProducer.java smooth.orc . . . . . . synthdef-sources.sc . . cillo-doppler.sc . . . . cillo-distortion.sc . . . cillo-echo.sc . . . . . . (realtime package) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 53 59 63 64 66