A jak tańczyć to przy muzyce. Dziś najprostszy odtwarzacz mp3 na stronę www. Oczywiście przy wykorzystaniu JavaFX Script.
Na początek ustalimy jedną rzecz. Wszystkie piosenki będą pobierane z XMLa:

Listing 1. Przykład XMLa z listą utworów

<?xml version="1.0" encoding="UTF-8"?>
<songs>
    <song>
        <url></url>
        <title></title>
        <artist></artist>
    </song>
</songs>

Ważna rzecz numer 1. JavaFX słabo obsługuje polskie znaki w nazwach plików. Nie radzi sobie z tym po prostu. Założyłem już temat na forum i czekam na odpowiedź czy to jest bug. W każdym bądź razie naszego xmla mapujemy do klasy modelu:

Listing 2. Klasa Song

package pl.koziolekweb.fxmusicplayer;

import javafx.scene.media.Media;

/**
 * @author koziolek
 */

public class Song {
    public var url:String;
    public var title:String;
    public var artist:String;
    public var media:Media;
    public override function toString():String{
        return "{artist}:{title} url:{url}";
    }
}

Na razie wystarczy zabawy z modelem. Trzeba zająć się tworzeniem GUI dla naszego playera.

Przyciski itepe

Jako, że tworzymy najprostszą odmianę playera to wystarczy nam jeden przycisk. Będzie on odpowiadał za odtwarzanie i zatrzymywanie utworu. Do tego należy dodać tekst zawierający nazwę wykonawcy i tytuł piosenki i aktualny czas odtwarzania. Czyli nic trudnego.

Listing 3. GUI dumnie brzmi

var currentTime:Number = bind player.currentTime.toSeconds();
var maxTime:Number = bind player.media.duration.toSeconds();
var currentSongName: String = bind "{currentSongNumber}.{currentSong.artist}: {currentSong.title}   {currentTime}:{maxTime}";
var contenGroup: Group= Group{
    content: [
        Text{
            font: Font{
                name:"Arial"
                size: 10
            }
            x: 10
            y: 10
            content: bind currentSongName;
        }
        Polygon {
            points: [ 20,20, 30,30, 20,40]
            fill: Color.RED
            onMouseClicked: function( e: MouseEvent ):Void {
                if(status){
                    player.pause();
                    status= false;
                }
                else {
                    player.play();
                    status= true;
                }
            }
        }
    ]
}

//...
Stage {
    title: "Application title"
    width: 300
    height: 80
    scene: Scene {
        content: contenGroup
    }
}

Co my tu mamy. Nasz przycisk stworzony za pomocą Polygon, bo chciałem wam pokazać, że takie coś istnieje. Zmienne currentSong,currentSongNumber i currentTime odpowiadają za przechowywanie aktualnej piosenki – Song, jej miejsca w playliście i aktualnego czasu odtwarzana. Zmienna maxTime określa czas trwania utworu w sekundach. Nie piszę tu kolejnego winampa więc olałem ładne formatowanie godzin, minut i sekund. Jest jeszcze magiczna zmienna player. O niej za chwilkę. Najpierw popatrzymy na pobieranie danych.

30… 30… 30 ton, czyli playlista

Playlista jest pobierana z serwera jako XML (ten na górze) i następnie przetwarzana:

Listing 4. Parser xml tworzy listę utworów

var parserHelper:Song;
def parser : PullParser = PullParser{
    documentType: PullParser.XML
    input: new FileInputStream(
        new File("./music.xml"));
    onEvent:function(event: Event) {
        if (event.type == PullParser.START_ELEMENT) {
            if(event.qname.name == "song" and event.level == 1) {
                parserHelper = new Song();
            }
        }
        if (event.type == PullParser.TEXT) {
            if(event.qname.name == "url" and event.level == 2) {
                if("{event.text.trim()}" != "")
                parserHelper.url = event.text;
            }
        }
        if (event.type == PullParser.TEXT) {
            if(event.qname.name == "title" and event.level == 2) {
                if("{event.text.trim()}" != "")
                parserHelper.title = event.text;
            }
        }
        if (event.type == PullParser.TEXT) {
            if(event.qname.name == "artist" and event.level == 2) {
                if("{event.text.trim()}" != "")
                parserHelper.artist = event.text;
            }
        }
        if (event.type == PullParser.END_ELEMENT) {
            if(event.qname.name == "song" and event.level == 1) {
                parserHelper.media = Media{
                    source: parserHelper.url
                }
                insert parserHelper into songs;
            }
        }
        if (event.type == PullParser.END_DOCUMENT){
            next();
        }
    }
};
parser.parse();

Ostatnia linijka spowoduje, że przy ładowaniu dokumentu rozpocznie się parsowanie co pozwoli na rozpoczęcie odtwarzania jak tylko będzie to możliwe najszybciej. Przy okazji zapoznamy się z funkcją next(), która „kieruje ruchem” w odtwarzaczu:

Listing 5. Funkcja next(), centrum kontroli

var trackListLength :Integer = bind songs.size();
var currentSongNumber: Integer = 0;
function next():Void{
    player.stop();
    currentSong = songs.get(currentSongNumber);
    player.play();
    status = true;
    currentSongNumber++;
    if(currentSongNumber == trackListLength){
        currentSongNumber = 0;
    }
}

Czas na wisienkę na naszym torcie…

Odtwarzacz

Mogło by się wydawać, że odtwarzanie utworu jest skomplikowane. Mam dla was złą wiadomość. W JavaFX Script sprowadza się to do kilku linijek kodu:

Listing 6. Zmienna player – super skomplikowany odtwarzacz

var status:Boolean = false;
var songs:Song[]=[];
var currentSong: Song;
def player : MediaPlayer = MediaPlayer{
    media: bind currentSong.media;
    autoPlay:true;
    volume: 1.0;
    onEndOfMedia: function():Void{
        next();
    }
}

Jedyną wadą obiektu MediaPlayer jest brak możliwości sprawdzenia stanu. Stąd zmienna status.
No i tyle. W kolejnym odcinku będziemy przerabiać nasz odtwarzacz na troszkę bardziej skomplikowany.