Doch, müsste.
OnPlayerStateChange wird auch durch cartPlayer getriggert, ist das beabsichtigt? Kann ich irgendwie die Art des Players abrufen? Also ob “ordinary Player”, CartPlayer oder PFL, oder oder oder…?
Oh, das ist ein Bug. Eigentlich sollten die Cartplayer-Zustände nur an OnCartPlayerStateChange gemeldet werden. Werde ich beheben.
Als Workaround kannst du dir den Rückgabewert von GetPlaybackControlIndex anschauen. Die normalen Player geben dort die Nummer der Playlist zurück (0 = erste Playlist usw.), die Cartplayer -1.
Nur fürs Protokoll: der ExtraPFL triggert auch OnPlayerStateChange und GetPlaybackControlIndex ist dann ebenfalls -1.
Sorry, dass ich so rumnerve… Ansonsten ist OnPlayerStateChange mit seinen State-Objekten ideal, danke.
Getestet hiermit:
[code]function StateToStr(TState: TPlayerState): String;
var
SState: String;
begin
Case Ord(TState) Of
0: SState := ‘psEmpty’;
1: SState := ‘psLoading’;
2: SState := ‘psLoaded’;
3: SState := ‘psPlaying’;
4: SState := ‘psFading’;
5: SState := ‘psEOF’;
6: SState := ‘psError’;
7: SState := ‘psPaused’;
8: SState := ‘psStopped’;
9: SState := ‘psPFL’;
10: SState := ‘psFlashEOF’;
11: SState := ‘psNext’;
else SState := ‘unknown’;
end;
Result := SState;
end;
procedure OnPlayerStateChange(PlayerControl: IPlayerControl; OldState: TPlayerState; NewState: TPlayerState);
var
PlayerType: String;
begin
Case PlayerControl.GetPlaybackControlIndex Of
-1: PlayerType := ‘Cartwall’;
else PlayerType := 'Playlist ’ + IntToStr(PlayerControl.GetPlaybackControlIndex);
End;
SystemLog(PlayerType + ’ Player ’ + IntToStr(PlayerControl.GetIndex) + ’ Change state from ’ + StateToStr(OldState) + ’ to ’ + StateToStr(NewState));
end;[/code]
Das 2. Case Of sollte natürlich noch durch 'ne simple If-Abfrage ersetzt werden, funktioniert so aber auch
Stop, böser Fehler! Im Prinzip funktioniert dein Script - im Moment. Was aber, wenn ich in Version 3.1.17 einen neuen Zustand einführe, und zwar nicht ganz am Ende, sondern irgendwo mittendrin? Dann ändert sich die Nummerierung. Und deine Case-Abfrage wird falsch.
Deswegen lieber durchgängig die symbolischen Namen benutzen, dann kann nichts schieflaufen:
function StateToStr(TState: TPlayerState): String;
var
SState: String;
begin
Case TState Of
psEmpty: SState := 'psEmpty';
psLoading: SState := 'psLoading';
psLoaded: SState := 'psLoaded';
psPlaying: SState := 'psPlaying';
psFading: SState := 'psFading';
psEOF: SState := 'psEOF';
psError: SState := 'psError';
psPaused: SState := 'psPaused';
psStopped: SState := 'psStopped';
psPFL: SState := 'psPFL';
psFlashEOF: SState := 'psFlashEOF';
psNext: SState := 'psNext';
else SState := 'unknown';
end;
Result := SState;
end;
Noch zwei kleine Vorschläge für die Schönheit:
- Du kannst auf die Variable SState verzichten, wenn du direkt “Result := ‘psEmpty’” usw. schreibst.
- Laut Konvention steht das T am Anfang eines Identifiers für einen Typ. TState ist aber eine Variable. Um Delphi-erfahrene Leser nicht verwirren, solltest du entweder auf das T verzichten oder einen anderen Prefix nehmen. Ich zum Beispiel nenne die Eingabeparameter immer was mit “i” am Anfang, zum Beispiel “iState”.
Ach, und nimm bitte meine Warnung wegen PlayerControl=nil ernst. Gerade beim PFL-Player kann es passieren, dass zum Zeitpunkt, wo der Status von Loaded auf Empty springt, das Player-Objekt schon aus dem Speicher gelöscht wurde, weil der Benutzer das Fenster zugemacht hat (was auch die Ursache für den Zustandswechsel war - vor dem Schließen entlädt sich der Player nämlich noch).
Guter Einwand, werde ich ändern, wenngleich ich das Script im Moment nur zum Testen und Herumspielen nutze, ich hab nicht vor mir dauerhaft die Zustandsänderungen ins Log zu schreiben, da bekommt man ja Zustände von… g
Das habe ich bereits gemerkt, gibt dann eine “TSimpleMessage Null Pointer Exception” und ab da wird das Script nicht weiter abgearbeitet. Aber wie bereits oben erwähnt, das ist im Moment erstmal nur zum Herumexperimentieren.
Sehr geil, nun klappt die Signalisierung so wie ich mir das gewünscht hatte:
Deck leer: LED aus
Deck geladen: LED an
Deck spielt: LED blinkt
Werde wohl die Firmware von Mixercontrol noch entsprechend anpassen, um z.b. Pause oder FadeOut durch andere Blinkfrequenz signalisieren zu können…
procedure OnPlayerStateChange(PlayerControl: IPlayerControl; OldState: TPlayerState; NewState: TPlayerState);
var
Port: Integer;
begin
If PlayerControl <> nil then
If PlayerControl.GetPlaybackControlIndex <> -1 Then
begin
Case PlayerControl.GetIndex Of
0: Port := 3;
1: Port := 4;
end;
Case NewState Of
psLoaded: ComPort('COM2').SendStr('PORT ' + IntToStr(Port) + ' 1' + #13#10);
psPlaying: ComPort('COM2').SendStr('PORT ' + IntToStr(Port) + ' 2' + #13#10);
psStopped: ComPort('COM2').SendStr('PORT ' + IntToStr(Port) + ' 1' + #13#10);
psPaused: ComPort('COM2').SendStr('PORT ' + IntToStr(Port) + ' 1' + #13#10);
psEmpty: ComPort('COM2').SendStr('PORT ' + IntToStr(Port) + ' 0' + #13#10);
end;
end;
end;
Hab nur noch Probleme wenn schnell hintereinander auf die serielle geschrieben wird, dass Mixercontrol manche Befehle verschluckt, vll doch in Zukunft mit DTR arbeiten, mal schauen und testen. Wartet mAirList denn brav, wenn DTR Low ist? Oder kümmert sich eh Windows um die Abarbeitung des SendBuffer?