MeMP - Mein einfacher Mp3-Player
Kapitel 6. Events
Wenn wir jetzt auf den Play-Button klicken, dann fängt die Wiedergabe an, falls wir zuvor eine Datei ausgewählt haben. Allerdings steht dann auf dem Button weiterhin „Play“, obwohl er dann ja eigentlich die Funktion „Pause“ besitzt. Wir könnten nun im OnClick-Event das Ändern der Caption einfügen. Und wenn wir dann auf Stop klicken, muss die Caption des Play-Buttons wieder zurück auf Play gesetzt werden.
Wenn man den Player später ausbauen möchte, verliert man so schnell den Überblick, und wenn man an einer Stelle vergisst, den Code zu ändern, führt das für den User schnell zu Inkonsistenzen und sehr unschönen Effekten. Und für uns als Programmierer zu einem unglaublichen Chaos.
Wir fügen unserer Player-Klasse daher einige Events hinzu, die bei passender Gelegenheit abgefeuert werden, und auf die wir in unserer Anwendung dann entsprechend reagieren können.
TMeMPPlayer = class
private
fOnPlay : TNotifyEvent;
fOnPause : TNotifyEvent;
fOnResume : TNotifyEvent;
fOnStop : TNotifyEvent;
fOnChange : TNotifyEvent;
fOnEndFile : TNotifyEvent;
fFileEndSyncHandle: DWord;
procedure SetEndSync;
public
property OnPlay : TNotifyEvent read fOnPlay write fOnPlay ;
property OnPause : TNotifyEvent read fOnPause write fOnPause ;
property OnResume : TNotifyEvent read fOnResume write fOnResume ;
property OnStop : TNotifyEvent read fOnStop write fOnStop ;
property OnChange : TNotifyEvent read fOnChange write fOnChange ;
property OnEndFile : TNotifyEvent read fOnEndFile write fOnEndFile ;
end;
OnPlay, OnPause, ...
Diese Events werden ausgelöst, wenn sich der Status des Players ändert. Unsere Pause-Methode sieht dann z.B. so aus:
procedure TMeMPPlayer.Pause;
begin
BASS_ChannelPause(fMainStream);
if assigned(fOnPause) then fOnPause(Self);
end;
Die Methoden Play, Stop und Resume müssen entsprechend erweitert werden.
OnChange
Dieses Event wird zusätzlich zu OnPlay ausgelöst, um z.B. eine Aktualisierung der Titelanzeige vornehmen zu können. Zu diesem Zweck führen wir auch eine neue Property ein, die einfach den Playlistentitel des zugrunde liegenden Audiofiles weiterleitet.
TMeMPPlayer = class
private
function GetPlaylistTitel: String;
public
property PlaylistTitel: String read GetPlaylistTitel;
end;
function TMeMPPlayer.GetPlaylistTitel: String;
begin
if assigned(fMainAudioFile) then
result := fMainAudioFile.PlaylistTitel
else
result := '-';
end;
OnEndFile
Wir wollen ja später einen Player haben, der nicht nur ein Lied abspielt, sondern im Anschluss daran direkt das nächste. Die bass.dll bietet einem nun die Möglichkeit, bei Ende eines Liedes benachrichtigt zu werden. Dies geschieht über so genannte Synchronizer, die nach Erzeugen des Streams diesem hinzugefügt werden können.
procedure TMeMPPlayer.SetEndSync;
begin
if Assigned(fOnEndFile) then
fFileEndSyncHandle := Bass_ChannelSetSync(fMainStream,
BASS_SYNC_END, 0, @EndFileProc, Self);
end;
Wir fügen hier unserer Wiedergabe einen Synchronizer vom Typ BASS_SYNC_END hinzu. Wenn es soweit ist, wird die Prozedur EndFileProc ausgeführt, die als Parameter unter anderem das aufrufende Player-Objekt erhält. Diese feuert dann einfach das OnEndFile Event ab:
procedure EndFileProc(handle: HWND; Channel, Data, User: DWord); stdcall;
begin
TMeMPPlayer(User).OnEndFile(TMeMPPlayer(User));
end;
Die Aufrufkonvention stdcall ist hierbei wichtig. Auf ähnliche Art könnte man auch einen Synchronizer setzen, der uns benachrichtigt, wenn wir fast am Ende des Stückes sind. In so einem Fall könnten wir die laufende Wiedergabe sanft ausblenden, die nächste einblenden und so einen schöneren Übergang zwischen einzelnen Titeln zu erhalten.