Musikplayer mit Java Sound API

Die Java Sound API bietet die Möglichkeit Audio-Files in Java abzuspielen. Die dabei unterstützten Dateiformate sind .wav, .aiff, .au und .mid, wobei letzteres außerdem den Funktoinsumfang mit sich bringt, Soundspuren aufzunehmen. Für die Multimedia-Vorlesung sind nun zwei Programme entstanden, welche die Sound API nutzen.

Sound Applet

Um sich mit der Sound API vertraut zu machen, diente zunächst ein Applet, welches mittels eines AudioClip einen Stream von einer URL ausliest und diese dann abspielt. Dabei schränkt sich der Funktionsumfang auf einen Play- und einen Stop-Button ein.

Musikplayer

Nach dem Schnupperkurs mit dem Sound Applet galt es nun einen Musikplayer zu implementieren, der gepuffert eine Musik-Datei abspielen können sollte. Durch die Freiheit ein Applet oder eine Desktop-Anwendung zu implementieren, habe ich mich für eine Desktop-Anwendung entschieden. Die Implementierung unterstützt .wav, .au und .aiff – Dateien.

Mockup

Mockup Desktop Music Player

Mit der Erstellung des Mockups war der Grundstein für den Musikplayer gelegt. Aus dem Mockup erkennbar gehen auch die Use Cases hervor, die für den Musikplayer relevant sind:

  • Laden von Soundfiles von Festplatte und/oder Internet
  • Play
  • Pause
  • Stop
  • Anzeige des aktuellen Titels
  • Regulierung der Lautstärke
  • Visualisierung der Position im Song
Klassendiagramm

Klassendiagramm Musikplayer

Das hier abgebildete Klassendiagramm möchte ich im folgenden Abschnitt nun etwas näher erläutern.

Implementierung

Die Implementierung des Musikplayers ist deutlich aufwändiger als die des Sound Applets. Dadurch ist es auch nicht verwunderlich, dass es einen enormen Zuwachs an Klassen gibt. Eine weitere wesentliche Änderung zum Sound Applet ist, dass als Audio-Spur nun nicht mehr ein AudioClip sondern eine SourceDataLine verwendet wird. Diese ermöglicht ein gepuffertes abspielen der Audiodateien.

GUI
Die genauere Erklärung möchte ich bei der GUI beginnen. Diese befindet sich in der Klasse PlayerGui, wie auch schon aus dessen Name ersichtlich wird. Die Klasse besitzt, wie im Mockup oben ersichtlich diverse Buttons, Labels und einen Slider. Diese sind mit diversen Listenern versehen und ermöglichen somit die Interaktion mit dem zwischen Nutzer und Player.
Weiterhin besitzt die Klasse eine Referenz auf das Interface Player und einen Setter für das Player-Objekt.

Interface Player
Das eben angesprochene Interface stellt eine Schnittstelle für alle Funktionen des Musikplayers zur Verfügung. Dabei sind die folgenden Methoden enthalten: play() , pause(), stop(), setVolume(), mute(), setFile(), getFile(), getStatus() und addTimeListener(). Was die einzelnen Methoden machen, sollte aus dem Methodennamen hervorgehen, daher werde ich nur auf vier dieser Methoden etwas näher eingehen.

setFile() – Diese Methode teilt dem Player mit, welches Lied er abspielen soll. Das Gegenstück dazu ist getFile(), welche das aktuelle Fileobjekt des Players zurück liefert. Das wird benötigt, um den aktuellen Titel in der GUI anzeigen zu können.
Mit getStatus() wird der aktuelle Status des Players, welcher durch ein Enum Status repräsentiert wird, zurückgegeben. Dieses Enum kann die Werte stopped, playing oder paused annehmen. Die Methode addTimeListener() fügt einen neuen TimeListener einer Liste von TimeListenern hinzu.

Interface TimeListener
Was es mit dem TimeListener auf sich hat, möchte ich noch etwas genauer ausführen. TimeListener ist ebenfalls ein Interface, welches die Methode setTime() bereitstellt. Diese Methode aktualisiert die Zeitanzeige in der GUI. Dabei ist die Implementierung hier über das Observerpattern gelöst, wobei die GUI mittels addTimeListener() einen Listener beim Player anmeldet.

Die Klasse PlayerImpl
Die Klasse PlayerImplimplementiert das Interface Player und hat somit auch alle Methoden dieses Interfaces. Des Weiteren besitzt diese Klasse einen Status, ein File, eine SourceDataLine sowie einen Boolean isMute. Zudem enthält sie eine Liste von TimeListenern, welche über addTimeListener(), wie oben beschrieben hinzugefügt werden.

PlayerImpl hat noch eine Methode updateTimeListener() welche auf alle TimeListener setTime() ausführt, wodurch eine Zeitübergabe und damit die Aktualisierung der Zeit in der GUI ausgeführt werden kann.

Innere Klasse PlayerThread
Da das Abspielen der Musik in einem separaten Thread erfolgen muss und der Thread aber auch auf die Attribute von PlayerImpl zugreifen muss, war es sinnvoll, diesen Thread als innere Klasse zu realisieren.

Nachdem die SourceDataLine geöffnet wurde, wird in der While-Schleife, die sich in der run()-Methode befindet, der Status des Players überprüft. Da diese Schleife unendlich lang läuft bleibt der Player also auch so lange pausiert, bis man ihm einen anderen Status zuweist.

Die Grundstruktur des Players ist damit erklärt, nun möchte ich noch auf die enthaltenen Funktionen etwas näher eingehen.

Files auswählen
Um einen File von der Festplatte an den Player zu übergeben, habe ich mich des JFileChooser’s bedient, welcher einen Dialog zur Auswahl einer Datei von der Festplatte bereit stellt.

Abspielen des Streams
Zum Abspielen eines Streams sind einige Schritte der Vorbereitung notwendig. Man muss zunächst ein File Objekt anlegen, wonach man einen AudioInputStream anfordern muss. Ist dies geschehen erfolgt eine Überprüfung des Audioformates und es wird eine Line zum Audioformat angefordert. Jetzt kann die Line geöffnet werden und die Wiedergabe kann starten. Wenn die Wiedergabe gestoppt ist, muss die Line wieder geschlossen werden, weil sonst das AudioDevice nicht verfügbar wäre, über welches die Musik abgespielt wird. Dieser Zustand würde sich erst nach einem Neustart des Computers beheben lassen.

Position des Titels

Über diesen Aufruf kann man die aktuelle Position des Liedes bestimmen. Sie befindet sich im PlayerThread und wird durch die updateTimeListeners()– Methode ständig aktuell gehalten.

Lautstärkeregelung
Die Lautstärkeregelung kann zum einen über den Mute-Button vorgenommen werden, welcher den Player beim drücken auf stumm schaltet und bei erneutem drücken wieder auf die Ausgangslautstärke zurücksetzt.
Zum anderen kann man zur Lautstärkeregelung aber auch den Slider benutzen, welcher mit einem ChangeListener versehen ist und somit den aktuellen Wert für die Lautstärke auch augenblicklich verändern kann. Dies geschieht mit Hilfe von einer kleinen Berechnung, die den Wert in Dezibel wiedergibt:

Dabei ist FloatControl eine Methode die die Sound API zur Verfügung stellt, um die Lautstärkeregelung zu beeinflussen. Als Anmerkung sei gesagt, dass es sich bei Dezibel um eine logarithmische Größe handelt, weshalb in der Methode auch mit der Logarithmusfunktion gearbeitet wurde.

Downloads und weiterführende Links

Code des SoundApplets
Ausführbare Jar Datei des Players
Code des Musikplayers

Programmer’s Guide zur Sound API

Marlene Knoche Verfasst von:

Informatikerin mit Hang zur Kunst. - Theaterbegeistert, mag Katzen und Kaffee.

8 Comments

  1. 17. April 2011
    Reply

    Cool cool. Der Player fetzt schon so. Da hast du es tatsächlich eher geschafft, nen Funktionierenden Player zu basteln als ich. Meiner braucht noch ne weile^^

  2. Nico
    8. März 2012
    Reply

    Schöne Sache, da konnte ich mir direkt ein paar Anregungen für meinen Player holen. 🙂

    • Marlene Knoche
      8. März 2012
      Reply

      Das freut mich, wenn ich dich so inspirieren konnte! 🙂

      • Bernhard
        23. April 2012
        Reply

        Hallo, sehr netter Blog bzw. Beitrag gerade zufällig drauf gestoßen und wollte mir den Code zu Gemüte führen, leider funktioniert der Link nicht mehr…wäre super wenn du den Link erneuern könntest
        lg

  3. Marlene Knoche
    23. April 2012
    Reply

    Hallo Bernhard, habe den Link gefixt, danke für den Hinweis. 😉

  4. Guest
    1. August 2016
    Reply

    Die Links funktionieren nicht …..
    Bitte fixen
    DANKE 🙂

    • Marlene Knoche
      12. August 2016
      Reply

      Fixe ich die Tage mal – hab momentan leider zu viel um die Ohren. Melde mich wieder, sobald das geschehen ist. 😉

Schreibe einen Kommentar zu birgitt Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload CAPTCHA.