Brother John’s Projects: Foobar2000 Scripting

Adding Now Playing Animation

Until now the only indication of the currently playing song is in the title bar and status bar of Foobar2000. In this chapter we are going to add an indicator including a little animation to the playlist as well.

Main Indicator in the Track Column

The first component of pointing out the currently playing song is giving its Track column a different colour. The new background is stored in cBgPlay: dark grey. Of course this does not go well with the default black text colour and we define white text in cTxtPlay.

To apply the new colours go to the Track column’s Style tab and add these lines at the end of the existing script.

[...]

$if(%isplaying%,
$set_style(text,$get_global(cTxtPlay),$get_global(cTxtPlay))
$set_style(back,$get_global(cBgPlay),$get_global(cBgPlay))
)

The %isplaying% field is true, if a track is currently playing and false otherwise. Accordingly the $if() is only executed for the playing song. To not let the now-playing indicator disappear when a track is selected, we set cTxtPlay and cBgPlay for both normal and selected tracks.

We face one problem with VA albums. Their red track artist names are hardly readable on the dark grey background. We solve this by defining a new colour variable cTxtVAPlay to use the selected-track background colour instead. It’s not a 100 % optimal solution but I was just too lazy to define yet another red. ;-)

Of course the variable must be applied in the script. The right place to do this is the Track column’s Display tab where we initially inserted the red artist names.

$if($and($get_global(isAlbum),$meta(album artist)),

$if(%isplaying%,
$get_global(cTxtVAPlay),
$ifequal(%tracknumber%,1,$get_global(cTxtVA1),$get_global(cTxtVA))
)

[$meta(artist)' - ']$rgb()
)

%title%

If the track is playing we apply cTxtVAPlay as text colour, otherwise we use the colours set in the previous chapter.

Animated Indicators

The now-playing animation consists of two parts. The first one concerns the Time column. Here we want to show the song’s remaining playback time. The Display tab is the right place to do that.

$if(%_time_remaining%,
'['%_time_remaining%']',
$if2(%_length%,'n/a')
)

We check for the existence of %_time_remaining% containing the remaining playback time and then display its value in square brackets. Using the quotes around the brackets is essential because otherwise Foobar2000 would interpret them as the short-form $if() and not as simple text. Also don’t forget the closing round bracket at the very end of the script.

The reason for not using the usual %isplaying% to identify the playing song is those potential audio files where Foobar2000 cannot determine the length. In such a case there couldn’t be a proper %_time_remaining% as well, in contrast to the perfectly possible %isplaying%. So using the remaining time variable as condition works around those rare problem files.

Because %_time_remaining% as well as the playlist display is updated every second, this script shows the remaining time continuously counting down to zero. And that’s the first part of the animation.

The second part takes place in the tracknumber column. There we are going to display four closing brackets )))) that from left to right change one by one to opening brackets (((( in a different colour. Those change back one by one to the original state.

To achieve this animation we need a timer defining the intervals between all the states. Unfortunately Tagz is not equipped with an explicit timer. But we can build one on our own using the $mod() function and %_time_elapsed_seconds% field that together can act as a one-second-interval timer. Let’s have a look at the tracknumber column’s Display tab script. There we need an additional bit of script including this:

$ifequal($put(foo,$mod(%_time_elapsed_seconds%,8)),0,
'))))',
// insert states 1 to 7 here
)

Two things are especially interesting. First the $put() and $get() functions. We already know about $set_globa() and $get_global() defining and accessing global variables. Now we deal with private variables that are only valid within one script. E.g. $put(aname,%artist%) stores the artist’s name into a variable called aname and additionally outputs the artist name as if the tag field was used on its own. In a lot of cases this output is not desired and we use $puts() in exactly the same way to get rid of the output. If we want to access our variable later, we use $get(aname). This works only in the same script. If we defined aname on the tracknumber column’s Display tab, it’s only valid there and nowhere else.

The second interesting thing is of course the counter construction itself. Its core is $mod(%_time_elapsed_seconds%,8). Remember that $mod() gives us the remainder of a division - here the elapsed seconds divided by 8. Like %_time_remaining% %_time_elapsed_seconds% is updated every second which makes the $mod() return changing values beginning from 0 and counting up to 7, then starting at 0 again. Hence we are now able to distinguish between eight different cases. And that’s exactly how much we need when you consider the nature of our animation. Changing from four )))) to four (((( and back requires exactly eight different stages.

To save a little time we not only calculate the $mod() function but additionally use $put() to store it into a variable called foo. We’re going to need the result of the calculation again in a while. Here $put() without the silent mode is necessary because otherwise the $ifequal() function wouldn’t receive anything to evaluate.

$Ifequal() takes care of a remainder of zero. This is our starting point because $mod(0,8) equals 0. Accordingly we output '))))' (again the quotes are essential). The rest of the animation is managed by a $select() statement.

$ifequal($put(foo,$mod(%_time_elapsed_seconds%,8)),0,
'))))',
$select($get(foo),
$get_global(cTxtDim)'('$rgb()')))',
$get_global(cTxtDim)'(('$rgb()'))',
$get_global(cTxtDim)'((('$rgb()')',
$get_global(cTxtDim)'((((',
')'$get_global(cTxtDim)'(((',
'))'$get_global(cTxtDim)'((',
')))'$get_global(cTxtDim)'('
)
)

That two-part construction is necessary because we cannot test for 0 with $select().

The $get(foo) accesses the stored result of the $mod() operation and uses this as the condition for $select(). The rest is very straight forward. We cycle through the different stages from 1 to 7 advancing the animation one step further each. For all opening brackets we set a different (light grey) colour with $get_global(cTxtDim) and return to the default with rgb() for following closing brackets. If you find it too messy to understand in its finished state, leave out all the colour changing code first.

What is left is wrapping the existing script and the new part into an $if(%isplaying%,,) construction. Here is the complete script (don’t forget the new closing bracket at the very end).

$if(%isplaying%
,
$ifequal($put(foo,$mod(%_time_elapsed_seconds%,8)),0,
'))))',
$select($get(foo),
$get_global(cTxtDim)'('$rgb()')))',
$get_global(cTxtDim)'(('$rgb()'))',
$get_global(cTxtDim)'((('$rgb()')',
$get_global(cTxtDim)'((((',
')'$get_global(cTxtDim)'(((',
'))'$get_global(cTxtDim)'((',
')))'$get_global(cTxtDim)'('
))

,
$if($get_global(isAlbum),
$ifgreater(%tracknumber%,15,
$hex(%tracknumber%,1),
$get_global(cTxtDim)'0'$rgb()$hex(%tracknumber%,1)
))
)

Of course you can take any characters you like for an animation. Use Windows’ character map programme to select one, take the unicode number from the status bar and use the scientific view of Calculator to convert it from hexadecimal to decimal notation. Then you can use the resulting number with Tagz and the $char() function. E.g. $char(32) is a simple space, $char(9835) is a little musical note. Which characters actually are available depends on the font. Our Franklin Gothic Medium for example provides less characters than Lucida Sans Unicode.

Done

With the animation finished our design is ready for general use for the first time. Bits and pieces are still missing, but the stage 3 screenshot doesn’t look that different from the final version. Oh, and here is the link to the FCS: Dark Connections, Stage3.

Screenshot of stage 3
Click to enlarge

In the next chapter we’ll take care of the missing pieces. But at least the playlist is completely finished now.