Cart Player Loop Status

I’m looking for a way to sense the Cartplayer Loop Button via a script in order to address the corresponding LED on the Cartwall keyboard.
(ref: http://forum.mairlist.com/index.php/topic,4103.0.html)

Does anybody know if this is feasible via scripting. It rather looks to me like Loop, Hook, etc… are not available.

regards:
-Serge-

The Loop and Hook modes are part of the Options of the IPlayerControl object (TPlayerControlOptions, poHookMode and poLoopAudio). Unfortunately, there is currently no way to trigger a script when the options change. You could only use an OnTimer procedure and check the values periodically - however, as far as I know, timers don’t work correctly either since I moved the notification script stuff into a background thread.

OK,

so this might be a lack for users with “huge” midi-interfaced keyboards as well. I can imagine that these users might want to assign a dedicated colour to their keyboard for a cart being in loop mode.

Or otherwise spoken: What would be the effort to add these states to the OnStateChange object?
It’s nothing urgent at all, but it would rather complete the access to the player options.

BTW, I cannot get psFlashEOF to work. Bug?

regards:
-Serge-

There’s no sense in making “loop” and “hook” states, because it’s a completely different thing, independent from the actual state of the player. (Computer scientists call that “orthogonal” - while hook or loop (or both) is on, the player can still be in any state, playing, paused, whatever.)

Providing the opportunity to specify colors for a player in hook or loop mode (but what then? loaded?) is a good idea, but it’s still not a state then, just an orthogonal option.

There are a couple of “fake” states in the TPlayerState enumeration, namely psFlashEOF and psNext. They are used to ease skin.ini processing, but the player will never actually be in either of these states. The skin loading algorithm just loops through all elements of TPlayerState and checks if there is entries in skin.ini for that state. When the player is drawn, the drawing algorithm then “diverts” to these fake states if the conditions are met (psFlashEOF instead of psPlaying if position is after EOF warning point and time/500ms is odd; psNext instead of psLoaded if Next flag is set on the player).

This works quite well because both psFlashEOF and psNext are a specialization of exactly one “real” state each (psFlashEOF = psPlaying; psNext = psLoaded) and thus not orthogonal to the state system. Loop and Hook would be different, because the user might want to have different colors for each state when loop is set etc.

OK,

I agree that these are not real states of a player, however, how does one with a sophisticated illuminated keybord will accomodate the following situation:
Assign a button for each cartplayer Looptoggle to the Keyboard. How does he get it switched on/off (the button LED I mean) when pressed.

Also If a player is in EOF flash mode, how does he get this visualized on the keyboard?
Usually if there is a dedicated Play and Stop button, the Playbutton starts flashing when in Fadeout or EOF-x seconds.
I mean psFlashEOF is there, it simply does not change its state when used in a script. So how can it be accessed?

regards:
-Serge-

Hook and Loop are two elements of the TPlayerControlOptions (poHookMode, poLoopAudio) set, to be accessed trough IPlayerControl.GetOptions.

But as mentioned above, there is no “options have changed” hook for notification scripts at the time being. That means that you can of course check from a script whether hook or loop are set on a specific player, but there is no way to call a script automatically when the options change.

I see two possible solutions:

  1. Establish an OnPlayerOptionsChange (and OnCartPlayerOptionsChange) hook for notification scripts - medium effort.

  2. Introduce a way to receive messages from the internal messaging system with a notification script. The messaging system is used by various internal objects for asynchronous communication with each other. For example, the non-visual objects (e.g. a PlayerControl object) will broadcast notification messages when it has changed in a way (e.g. its options) so the visual objects can update themselves to reflect the change in the GUI. With this interface, a notification script could hook to whatever event, but the programming would actually be very low-level. (There is of course no documentation about the internal messages and their meanings, and I’m not going to write one.)

Regarding your question about EOF: The player control broadcasts an internal message when it passes the EOF warning point (default: 10s before the end of the song). The notification script interface reacts on this message by calling OnPlayerEOFWarning. But this is only done once, so you cannot implement flashing this way.

The GUI player object does not rely on this broadcast message at all but checks on its own whether the EOF warning point has been passed, and if so, changes the color of the player. As this check is carried out periodically (twice a second), it is able to “flash” by choosing a different color each time.

OK,

I’m just a bit upset by reading your answers. (not for the comment but the fact that it is not feasible) :wink:

Well, you mentioned OnTimer procedures. What’s the problem with those? Don’t they work anymore at all, or did they just got inaccurate by moving them to a background thread. I can live with that, for me it is irrelevant if the event gets written a few hundrets of ms later.
All I need is to have the status of the Loopbutton available in an file.

On the other hand I personally consider the missing EOFwarning possibility not only as a nice-to-have item when using midi or whatever keyboards. I’ve seen it several times in Studios that the playerbutton starts flashing when reaching EOF.
There’s a real benefit if you can rely on your keyboard information in front of you during liveshows rather than always having an eye on the monitor.

regards:
-Serge-

Hold it! This is exactly what I need. I did not understand this during my first reading.
For me the Event has to be fired only once. When fired, it will write a “3” to a file. This will make my interface to start flashing. On player stop, the contents of the file gets overwritten by a “0” from the OnPlayerStateChange event which will make the port interface to switch the output off.

See, it’s all there ;D (at least for the player [fake] states)

I’ll test that tomorrow, maybe I find an example script. Or could you point me to the syntax of the first line. What do I have to declare there?

procedure OnPlayerEOFWarning(????: ????; .....);

Take a look at the Notification Script Template in the scripts directory.

Thanks for the hint!

procedure OnCartPlayerEOFWarning(PlayerIndex: integer); begin end;
easy as that… ;D

Any comment regarding the OnTimer procedure not working? I would really consider this as an option!

On the other hand, I made up my mind a bit whist being on the bus now for getting home.
The whole player status stuff could be handled much more easier an more flexible (as of my opinion)
My background on programming is besides C++, VB#, etc … more on the “low level side” like PLCs and DCS systems.
Well, one word (2bytes) could handle all the player states if you consider it bitwise.
Assume bit 1 is psEmpty …aso…
like
psEmpty
psLoading
psLoaded
psPlaying
psFading
psEOF
psError
psPaused
psStopped
psPFL
psFlashEOF
psNext

there’s space for additional 4 states. So having bit 4 & 5 set would mean fading
Bit 4 & 13 set would mean playing and Loop set ;D

Demuxing such a word into its bits is just a piece of cake. A simple XOR with an AND will mask out every bit.

regards:
-Serge-

Oh, yes, sorry. I was on the subway train, writing on my iPhone, thus the very brief reply :wink:

In mAirList 2.2 a TTimer component was used, but that only works in the main thread. For mAirList 3, I need to find a totally different way to achieve periodic calls. For example using a dedicated timer thread, or using a central timed “callback” mechanism.

TPlayerState is implemented as an enumeration. It’s pretty much a list of constants as you would declare it in C++, but it can be declared and handled much easier. The bitwise combination you’re talking about is a “set” in Delphi. Again, it is implemented using constants (1, 2, 4, …) internally as you would do in C++, but accessing the values is much easier, because you can use operators like “in” or “+” (union) instead of using the binary operators AND, OR etc.

But, and that’s the point: There is no sense in making TPlayerState a set. Because a player can only be in (exactly) one state at a time. For example, it cannot be playing and paused at the same time. This is why TPlayerState is not a set but a simple enumeration. (Please ignore psPFL, psFlashEOF, and psNext for the moment, they are just a trick to speed up skin processing.)

Of course you could use the spare bits to store additional information (e.g. the loop and hook flags) in the same variable, but there’s no sense in that either, it would only mess up your code and make it unreadble to anyone else. This information should rather be stored in an extra variable. In this particular case, I decided to store the flags along with the other toggable player options in the “Options” variable, which is of type TPlayerControlOptions, declared as a “set of TPlayerControlOption”, where TPlayerControlOption is an enumeration (see the help file for the possible values).

And after all, we’re only talking about notification scripts getting notified about a change in the options, don’t we? Then the most feasible solution would be to introduce a new function for that, instead of squeezing the information into the parameters of another function, wouldn’t it?

Yessss! ;D
Agree with you, the only thing I don’t get out of your messages is if you plan to migrate the “options” set into a notification function (sorry) 8)

I can only speak for myself now, but I hope other users using external keyboards might speak up too.

The possibility of using a timer is always a nice feature. So “fixing” this would be highly appreciated.

However, I understand your opinion regarding player state but i do not fully agree on your point of view. We have players here that can be put into pause mode and being stopped. They just don’t cue the song then. Only after pressing play then, the song gets cued and remains in pause until pause gets released (pause is toggle)
See, this is just a different approach. By defining a bitset with the different states, there are always some that exclude others, but that should be pretty handled by the automation software, mAirList. The user has no influence on that.
OK, I’ll stop now as this will lead into an endless discussion ;D
Looks like Delphi and C++ or Assembler somehow are different worlds. :o

regards:
-Serge-

From the theoretical point of view, the player is a finite state machine: http://en.wikipedia.org/wiki/Finite-state_machine

Its state (in the theoretical sense) is made up of the values of all of its variables (fields). It is totally irrelevant how that data is stored, if its bits of a single variable, or split into several variables. That is just a matter of style.

I’m pretty sure that it’s “best practive” what I am doing, that is, splitting it into logical units. The Hook and Loop flags are completely indenpendent from the TPlayerState value (they can be turned on and off at any time, regardless of the current TPlayerState), so they should be in separate variables. I could even have implemented them as two separate boolean variables, but using a common set-style variable for all on/off options is much easier to implement (you don’t need to declare a new variable or add fields to the dialog and menus each time you introduce a new option, just add a new value to the enum the set is based on).

Regarding the “will I implement it or not” question, I have to focus my work on what’s useful for the majority of users, or what will help me to sell enough licenses to make a living from mAirList. For example, I urgently need to finish the German manual. I should not “waste” my time on serving too many feature requests at the moment. That is not to say that I am not going to implement it at all, but not right now.

Yes Torben, I fully agree with you! I truly understand that you have to get both ends together somewhere, sometime.
Please don’t get me wrong, 'cause what you deliver to the community and your customers is really outstanding.

So there might really be no need to get all the player states or Loop/repeat options displayed on a high-cost fancy midi keyboard.
I really feel myself now completely wrong… ::slight_smile:
Again, don’t get me wrong now, but I did not expect this answer. As other users like Peter promoted fancy keyboards like the APC, I cannot understand this point of view.
However, I’ll respect it. I just have to make up my mind on how to tweak/bypass this now…

regards:
-Serge-

I have to say that I agree with Torben on this one. In Delphi terms, and given my limited understanding of Delphi :D, I’d say that Torben’s implementation of the state flags is correct.

BFN
CAD

;D
Well there are different point of views then, although I fully agree with you both to have it split up into “logical units”.

Just one final comment:
Please explain me why psPFL, psFlashEOF and psNext are included in the set?
In order to accomodate with your “consistency” argument, they should rather reside in a separate procedure like OnPlayerGUIChange or OnPlayerFakeChange or whatever the name would be…

BTW, and that’s the reason for my posting, the OnPlayerEOFWarning exactly does what I want.
There’s just the PlaylistIndex variable missing in the template.
So the correct syntax should be:

procedure OnPlayerEOFWarning(PlaylistIndex: integer; PlayerIndex: integer); begin end.

Well about the OnTimer notification script to fetch the IPlayerControl object (TPlayerControlOptions, poLoopAudio) periodically; would that work? How could it be implemented for let’s say, fetch the data on a 1 second basis?
The template only indicates:

procedure OnTimer; begin end;
How do I set the timer interval and what triggers it off? I simply don’t understand how this works.

regards:
-Serge-

To quote Torben from earlier in this thread:

Does that answer your question, Serge?

Oh: and when I said “I’d say that Torben’s implementation of the state flags is correct,” I meant his implementation of these flags as an Enumeration and not as a set of bit flags. Enumerations are much easier to define, handle, and use in languages such as Delphi and Visual Basic.

Bit-flag representations are sort of a hangover from assembly languages, where every processing cycle was important and using bit flags was much faster than (say) storing whole byte values and comparing those against known byte values. They are commonly used in hardware devices and since you have experience of programming PLCs, that would explain why you think they would be a ‘better’ or ‘more correct’ approach. But honestly: in high-level languages, where you are almost completely ‘divorced’ from the generated machine code, Enumerations are MUCH easier to use, and they really don’t affect the performance of the compiled program.

I hope that explains things better?

BFN
CAD

First of all: It’s an enumeration, not a set. But I think this has eventually been clarified now :wink:

The second thing to note is that these are only “fake states” which will never occur. For example, a loaded player marked as Next will still be in psLoaded and not in psNext.

But why do these fake states exist anyway?

As you know, you can use skin.ini to specify a different color for each player state. For example, you can make the player be red while playing, green while loaded, blue when EOF etc. In the implementation of the player GUI object, the colors set in skin.ini are stored in an array which is declared like this:

fColors: array[TPlayerState] of TColor;

This declaration is much easier than defining separate TColor variables for each state: You can look for matching skin.ini lines in a loop, and when the player is drawn, you simply use fColors[currentState]. In case I ever happen to introduce an additional state (= value in the TPlayerState enum), the player GUI object code doesn’t need to be modified at all, it will instantly adapt itself to the new set of possible states.

Now in addition to the state-dependent colors, you can also define colors for (a) a player being in PFL mode, (b) a loaded player being marked as NEXT, and (c) the color used for flashing during EOF warning. Instead of defining additional variables for these extra conditions, I decided to introduce the fake states, so the colors can be processed in the same way as the ordinary state colors.

CAD, thanks for pointing this out.

I’m well aware about enumerations. They existed already in Pascal some 25 years ago when we had to learn that language in school.
Enumerations also exist in C++ and VB#. So that’s not really the point. If I consider it that way, Torben’s enumeration that include the skin speedup values is then more of a typeless structure. But again in this case you are allowed to include everything with it.

OK, we shall stop bitching now and focus back on the important things. You are perfectly right with your assumption regarding PLCs. I do consider this machine related programming technique as more performant and (most important) more logical.

But this does not solve my timer problem now to fetch the Loopstatus. ;D

regards:
-Serge-

OK Torben, the postings overlaped while replying to CAD.

I fully agree with you if we consider this enumeration as being used solely for the GUI.
BUT, and that’s where I have touble to understand, is that the same object is also used in notification scripts for automation an control purpose. That’s a kinda contradictionary to me.

regards:
-Serge-