Java - AG Audio - Ausgabe mit Java 3. Juli 2001 Frank Münster Arten von Sound „Sampled“ MIDI Sampled: MIDI: Audiodaten liegen in einer Sounddatei vor Audiodaten liegen in Form bestimmter abrufbarer Klänge innerhalb der Hardware vor. ( MIDI - Musical Instrument Digital Interface ) Packages des Java-Sound API javax.sound.sampled javax.sound.midi javax.sound.sampled.spi javax.sound.midi.spi Wir beschäftigen uns mit dem „sampled“-Package. Die „ spi “-Packages („Service Provider Interface“) dienen der „Erweiterung“ von Java, z.B. zusätzliche Unterstützung von .mp3 Dateien, etc. FileFormat / AudioFileFormat Der Unterschied zwischen FileFormat und AudioFileFormat: AudioFormat: Datenformat, Art des Sample, Art der Codierung AudioFileFormat: Dateiformat, die Art, wie die Daten in Dateiform gespeichert werden. Unterstützte FileFormats: Unterstützte AudioFileFormats: .wav PCM .au mu-law ( m-law ) .aiff a-law .rmf Das „Sampled“-Package Wichtige Klassen: Wichtige Interfaces: AudioSystem AudioInputStream AudioFormat DataLine.Info Line Clip SourceDataLine Mixer LineListener Audio-Wiedergabe Interface Clip Interface SourceDataLine Geben wir Sound-Dateien als Clip wieder, so wird die komplette Datei vor dem Abspielen in den Speicher geladen. Wir haben die Möglichkeit des „loopens“, entweder den kompletten Sound oder Ausschnitte. void loop(int count); void setLoopPoints(int start, int end) Unter Verwendung einer SourceDataLine werden jeweils nur Stücke der Datei in einen Buffer geladen, diese werden dann abgespielt, währenddessen wird der Buffer erneut mit den darauf folgenden Daten beschrieben. Somit eignet sich die SouceDataLine besonders für große Dateien. Interface Line Die zuvor beschriebenen Interfaces Clip und SourceDataLine sind vom Interface Line abgeleitet. Abspielen einer Datei - Vorgehensweise 1. „File“-Objekt mit der gewünschten Dataei anlegen 2. „AudioInputStream“ anfordern 3. „AudioFormat“ des Sample überprüfen 4. Zum AudioFormat „passende“ Line anfordern 5. ggf. „LineListener“ hinzufügen 6. Line öffnen 7. Wiedergabe starten 8. ggf. Wiedergabe stoppen 9. Line schließen File-Objekt anlegen import java.io.File; import java.io.IOException; ... File audiodatei = new File(„e:\\beispiele\\beisp.wav“); // Verzeichnisse werden mit doppeltem // Backslash angegeben AudioInputStream anfordern AudioInputStream audioinput = null; try { audioinput = AudioSystem.getAudioInputStream(Audiofile); } catch (Exception e) { ... } AudioFormat des Sample überprüfen ... AudioFormat format = audioinput.getFormat(); System.out.println(format.toString() ); DataLine.Info info = new DataLine.Info(Clip.class, format); // DataLine.Info Objekt wird später zum // anfordern einer „passenden“ Line (hier vom // Typ „Clip“) benötigt. „Passende“ Line anfordern ... Clip line; try { line = (Clip) AudioSystem.getLine(info); // „info“ ist das zuvor angelegte DataLine.Info // Objekt. Java kann über dieses Objekt eine Line // mit den für das Sample benötigten Spezi// fikationen anfordern) catch (Exception e) {...} „LineListener“ hinzufügen try { line = (Clip) AudioSystem.getLine(info); line.addLineListener(this); } catch ... ... public void update(final javax.sound.sampled.LineEvent p1) { if (p1.getType().equals(LineEvent.Type.STOP)) ...} {...} Öffnen, starten etc. der Line try { line = (Clip) AudioSystem.getLine(info); line.open(audioinput); line.start(); // oder line.loop(n); ... // evtl. line.stop(); } catch ... Line schließen ... public void update(final javax.sound.sampled.LineEvent p1) { if (p1.getType().equals(LineEvent.Type.STOP)) { line.close(); } ... } // Line muß unbedingt geschlossen werden!!! // Wird das Programm vor dem Schließen beendet, ist ein //Schließen der Line nicht mehr möglich, sie bleibt bis //zum Neustart des Rechners „reserviert“. // Mögl. Resultat: „Audio Device unavailable“ Line schließen (2) Von Line abgeleitete Objekte ( SourceDataLine, Clip, Mixer, Port, etc.) repräsentieren physische Einheiten innerhalb der Hardware (z.B. auf der Soundkarte). Daher ist die Erzeugung dieser Objekte hardwarebedingt, d.h. es können nicht beliebig viele dieser Objekte gleichzeitig existent sein. Schließen wir die Lines nach der Verwendung nicht, so kann diese Line für nichts Anderes mehr verwendet werden, da sie nicht „freigegeben“ wurde. Die nächste Anforderung muß also auf eine andere Line zurückgreifen. Gibt es keine andere Line mehr, wirft Java eine LineUnavailableException aus. Auch andere Anwendungen können in diesem Fall keine Sounds mehr abspielen und liefern Meldungen wie z.B: „Audio Device unavailable“. Besonderheiten SourceDataLine Daten werden Stück für Stück in einem Buffer gelesen und verarbeitet Buffer wird in einer Schleife jeweils mit neuen Daten gefüllt Schleife wird bei EndOfFile (Rückgabewert -1) unterbrochen (oder bei Benutzer-Stop) Line wird geschlossen SourceDataLine try { line = (SourceDataLine) AudioSystem.getLine(info); line open(format, int b); // b ist die Größe des Buffers in // Bytes, den die Line besitzen // soll. b kann auch weggelassen // werden, Java legt dann die Buffergröße // fest. int BUFFER_SIZE = line.getBufferSize(); int read = 0; byte[] data = new byte[BUFFER_SIZE]); int written; SourceDataLine (2) while (read != -1) //read wird -1, wenn Dateiende erreicht { read = audioinput.read(data, 0, BUFFER_SIZE); // 0 (int offset) bedeutet, daß die // Datei beginnend bei Position 0 // (Dateianfang) gelesen werden // soll. if(read >= 0) { written = line.write(data, 0, read); } else break; } line.drain(); } // Ende von try{} catch... finally{line.close();} Methoden AudioSystem.getAudioInputStream(file); // Liefert einen AudioInputStream, mit welchem die Daten aus der Sounddatei gelesen werden können. Audioinputstream.getFormat(); // Liefert ein AudioFormat - Objekt, welches Informationen über Das Format der in der Datei enthaltenen Audiodaten enthält. new DataLine.Info(Clip.class, audioformat); // Erzeugt ein DataLine.Info - Objekt anhand der AudioFormatInformationen. Unter der Angabe der gewünschten Line (hier Clip) enthält das erzeugte Objekt speziellere Informationen als AudioFormat, welche zur Anforderung einer passenden „Line“ benötigt werden. Methoden (2) DataLine.Info info.toString(); // Wandelt die im DataLine.Info Objekt enthaltenen Info‘s in einen String um, der dann angezeigt werden kann. Clip line =(Clip) AudioSystem.getLine(info); // Liefert eine den Spezifikationen des DataLine.Info Objektes entsprechende Line (hier vom Typ Clip). Der Aufruf dieser Methode muß innerhab von „try“ stehen, da möglicherweise keine entsprechende Line vorhanden ist; andernfalls wird es gar nicht erst von Java compiliert. line.open(); line.start(); line.loop(n); line.stop(); line.close(); // Verwendung selbsterklärend, loop(n) kann nur bei Lines vom Typ Clip verwendet werden, n ist die Anzahl der Wiederholungen Methoden (3) line.addLineListener(this); // „heftet“ den LineListener (this, da er in diese Klasse implementiert ist, und Objekte dieser Klasse somit auch LineListener-Objekte sind) an die Line. In der „update“Methode kann der LineListener dann auf „LineEvents“ reagieren (z.B. STOP-Event, CLOSE-Event, etc.) int read = audioinputstream.read(byte[] data, int offset, int Buffersize); // Das Array repräsentiert den Buffer, Offset die Startposition, Buffersize die Größe des Buffers, also die Größe des Arrays. Beginnend bei Offset werden Daten aus audioinputstream in den buffer gelesen, wobei die Methode jeweils die Anzahl der gelesenen Bytes zurückliefert (int read). Methoden (4) int written = line.write(byte[] data, int Offset, int read); // Umgekehrt werden hier die zuvor in den Buffer gelesenen Daten in die Line „geschrieben“, damit eine Wiedergabe erfolgen kann. line.drain(); // Befinden sich noch Daten im Buffer, werden diese noch gelesen und verarbeitet (abgespielt), bis der Buffer leer ist. line.flush(); // Die restliche Daten werden „weggespült“, ohne daß sie weiter verarbeitet werden. Literatur Leider läßt sich zur Zeit noch nicht allzuviel Literatur zu diesem Thema finden, möglicherweise auch weil das Java Sound-API erst seit Version 1.3 im JDK enthalten ist. Zuvor war Sound in Java nur bedingt möglich, und ohne größere Probleme nur in Applets. Zu empfehlen ist der Java Sound-API Programmer‘s Guide von Sun, welchen man sich unter http://ftp.java.sun.com/docs/j2se1.3/javasound.pdf als pdf (Adobe Acrobat) - Datei heruterladen kann. Diese Anleitung ist allerdings in HTML-Form auch in die APIDocs, welche im GIS-Labor zugänglich sind, integriert.