Brother John’s Projects: Foobar2000 Scripting

Creating the Columns’ Scripts

First things first! And regardless of all the lovely eyecandy, what would a playlist be without the textual information about the songs? So we’re going to take care of this first. Of course when developing a design on your own, the different stages would never be so clear cut. Especially creating the text and colour scripts goes hand in hand because to a large extent the colour scheme determines how all the text has to be arranged. And vice versa. Oh, and probably this is a good place to say it again: no one forces you to re-create my design to the letter. If something doesn’t fit your needs, simply adapt it. After all that’s the spirit of Foobar2000: you make your own choices without being restricted by some preset configuration.

Sorry for babbling. ;-) Go to Foobar2000 / Preferences, select Display / Columns UI / Playlist view from the tree and open the Columns tab. On the left side is a box with a list of all present columns. We’re going to start from scratch, so just use the Delete button to get rid of them all.

The Artist/Album Column

There are two buttons for creating new columns: New creates a new column at the end of the list, i.e. on the far right side of the playlist. The Insert button places the new column before the currently selected one.

Our first column contains info about the artist and album. Hit New to create a column automatically named New column. Delete that name from the Display name field and replace it with Artist/Album (or something you like better). Set width to 250 pixels and Alignment to Left. Really essential is the large input field below. If the Display tab is not yet active, click on it now to be ready for entering code.

In most columns we must distinguish between tracks belonging to a full album (I’ll call them ‘album tracks’ from now on.) and single tracks. The script's task is this: If working on an album track, do some stuff. If it’s a single track, do something else. Of course, an if construction is perfect for this.

$if($get_global(isAlbum)
,
// Tasks for album tracks go here
,
// Tasks for single tracks go here
)

Note the bold part. Because we need the album/single track distinction all over the place, the efficient solution is to do that query once, store it in a global variable and only access the variable from everywhere else. This safes us from typing the same lines over and over again and makes the script faster, because the actual query has to be done only once.

Head over to the Globals tab, tick Use global variables for display and activate the Variables tab below. Here you enter the album checking code.

$if($and(%tracknumber%,%album tracks%,%album%),
$set_global(isAlbum,1)
)

The first line uses the $and() function to check for the presence of the tracknumber, album tracks and album tags. The expression only becomes true, if all three are there. In less technical words we assume a song to be an album track, if it has all three of those tags. Otherwise it’s considered to be a single track.

On the second line $set_global() creates a variable called isAlbum and assigns it a value of 1. So now we have the isAlbum variable present, if all three tags are there. Otherwise there is no variable.

Everything defined here on the Global / Variables tab with $set_global() can be accessed anywhere else in the code with $get_global(). And that’s exactly what we do in the first script. Let’s go back there and insert the code for single tracks.

$if($get_global(isAlbum)
,
// Tasks for album tracks go here
,
// Tasks for single tracks go here
[%artist%]
)

Very easy and very boring, isn’t it? We just look for the artist tag (remember the field remapping behind it) and use the brackets to prevent a question mark showing when the tag is absent.

Album tracks are more interesting. Have a second look at the screenshot of the finished design. There’s text on the first five lines of an album. To achieve this we use the $select() function to filter by tracknumber (which essentially represents the line number within an album).

$select(%tracknumber%,
// Track 1
$if($strcmp(%codec%,'ATSC A/52'),'dolby digital ac3',
$if($info(lame_version),'lame',
$lower(%codec%)
))
' album {',
// Track 2
'   '$if2(%album artist%,'<no artist>'),
// Track 3
'   '$if2(%album%,'<no album>'),
// Track 4
'   '['Disc '%disc%$tab()]$if2(%album date%,[%date%])$tab(),
// Track 5
'}'
)

On track 1 first look at the third line reading $lower(%codec%). This gives us the audio codec’s name. Of course we take a small leap of faith here because %codec% returns only the codec used for track one of the album. But why would anyone want to encode tracks from one album with different codecs? $Lower() converts the codec name to lowercase letters.

Jumping two lines up. Imagine dealing with an album in AC3 format (granted, it’s unlikely). The %codec% command would return ‘ATSC A/52’ as the codecs name. Of course technically this is perfectly correct as it’s the official name of the international AC3 standard. However hardly anyone is familiar with that name. Therefore we use an $if() in combination with $strcmp() (which tells us, if the two strings given in the arguments are identical) to keep an eye open for ‘ATSC A/52’ and output ‘dolby digital ac3’ instead.

On the next line a similar thing happens. The $info() function is used to access technical fields. Here we look for lame_version to identify MP3 files encoded with the Lame encoder. If we encounter one of those, we display ‘lame’ instead of the ‘MP3’ we would get by using %codec%. Non-lame encoded MP3’s don’t have the lame_version field and don’t trigger this $if(). They will show up simply as ‘mp3’. Right now all your Lame encodings will show up as ‘mp3’ as well because Foobar2000 0.9 currently doesn’t offer lame_version detection. But I’m pretty sure this feature will become available eventually.

We’ve already looked at the $lower(%codec%) line. Afterwards the two round brackets close the two ifs. The next line just adds a static string after the codec info.

The track 1 code is also our first example of nesting, where the otherwise part of the first $if() is a second $if(). Put into plain English: If the codec used is called ‘ATSC A/52’, display the more well known ‘dolby digital ac3’. Otherwise execute the second if-command: Check for the lame_version field and display ‘lame’. If this field is not present, use the output from %codec%. And this concludes album line 1.

Line 2 starts with a string of three spaces as indentation in the playlist. The $if2() looks for and outputs the %album artist% tag (again, remember field remapping) or the ‘no-artist’ message for those files you didn’t tag properly. Exactly the same happens on line 3 with the album tag.

Line 4 contains the information about disc number and date. First we check for %disc% and display e.g. Disc 1, using the square brackets to ensure display only when the tag is present. Then follows $tab() to insert a tabulator character, which controls text alignment in the column. It works like this:

left-justified text $tab() right-justified text
left-justified text $tab() centred text $tab() right-justified text

For multiple disc albums we now have the disc info on the left side of the column including the command to right-justify following text. For single disc albums the column is still empty except for the three indentation spaces.

The $if2() now takes care of date display. First we check for and, if existent, display the album date tag; remember it is used for compilations where the album’s date differs from the tracks’ dates. If no %album date% is found, the contents of the date tag get shown; but because of the square brackets only if present.

Till now we either have only left-justified date info in the column or left-justified disc number info and right-justified date info. The latter turned out not to look too good and I inserted an additional $tab() to move the date to the centre.

Hm, there’s really nothing to say about line 5. Just closing the eyecandy bracket we opened on line 1. And that’s all for album mode display in this column. Insert it into the code from further above to complete the script for the Album/Artist column. It should look like this:

$if($get_global(isAlbum)
,
// --- Album view ---
$select(%tracknumber%,
// Track 1
$if($strcmp(%codec%,'ATSC A/52'),'dd_ac3',
$if($info(lame_version),'lame',
$lower(%codec%)
))
' album {',
// Track 2
'   '$if2(%album artist%,'<no artist>'),
// Track 3
'   '$if2(%album%,'<no album>'),
// Track 4
'   '['Disc '%disc%$tab()]$if2(%album date%,[%date%])$tab(),
// Track 5
'}'
),

// --- Single view ---
[%artist%]
)

The Tracknumber Column

Create a new column, name it #, give it a width of 30 pixels and set Alignment to Centre. Here we display the tracknumber for albums and nothing for single tracks. The script is quite simple.

$if($get_global(isAlbum),
$ifgreater(%tracknumber%,9,
%tracknumber%,
'0'$num(%tracknumber%,1)
))

The first line should look familiar. It checks for album tracks and executes or skips the following lines accordingly.

The three lines below are a single $ifgreater() command doing this: If the tracknumber is greater than 9 (meaning two digits wide), display the tracknumber. Otherwise display a 0 and then the tracknumber without a leading zero.

Generally note that you cannot omit the otherwise part in $ifgreater() commands. Only simple $if() allows this.

The $num(number,length) function works like this: It takes the number number and prefixes it with zeros until it becomes length characters long. If number is already longer than length, no change takes place. And if number is already zero-padded to longer than length, the superfluous zeros get removed. This last feature is the one we need in the script, because a length of 1 always removes any leading zeros and Foobar2000’s tag remapping by default zero-pads tracknumbers to two-digit length. You might have noticed that the $ifgreater() does the zero-padding manually: displaying just the number when the number is at least 10 and padding with a zero below. We use this manual method because we later want to display the leading zero in a different colour. But we couldn’t access it individually using automatic padding.

At this point the Tracknumber column is finished. However, I decided to add another bit of eyecandy by displaying the tracknumber in hexadecimal format. If you find this too confusing, just ignore it. The hexadecimal system does not work with ten digits (from 0 to 9) like the decimal system, but uses sixteen digits from 0 to 9 and then A to F. Counting works like this: 0, 1 ... 9, A, B ... E, F, 10, 11 .... Converting a number to hex is easily done with the $hex() function resulting in this alternative Tracknumber script:

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

The syntax for $hex() is the same as for $num(). All we have to do is put all displayed tracknumbers into a $hex() function and change the manual padding code. The hexadecimal system switches from one to two digits long after the F, which is 15 in decimal notation. Accordingly the 9 in script line 2 must be changed to 15.

Use whichever tracknumber display you like better. I’m a fan of the hex display and will use that script for the rest of the tutorial.

The Track Column

Add a third column called Track, make it 350 pixels wide and left-aligned. Here we display the song names for all tracks, no matter if album or single track.

$if($and($get_global(isAlbum),$meta(album artist)),
[$meta(artist)' - ']
)

%title%

The first three lines take care of various artists albums. For those the album artist tag usually contains ‘Various Artists’, which is displayed as artist name in the Artist/Album column. But the artists for the individual tracks are still missing and we’re going to put them here in the Track column - actually that’s why I called it Track and not Title.

The $if() checks for the album artist tag identifying a various artists album. We must use $meta(album artist) instead of just %album artist% to disable field remapping. Without this we would look for ...

$if3($meta(album artist),$meta(artist),$meta(composer),$meta(performer))

... automatically getting the artist tag, if album artist is absent. Which is exactly what we don’t want because this would make the if-condition true for non-various-artists albums as well.

The [$meta(artist)' - '] part looks for the artist tag. Again without remapping because if no artist tag is present, we would get the contents of album artist, which we don’t want to display on individual tracks. If %artist% is present we display the tag followed by a dash as separator to the actual song name. Later we’ll change the artist name’s colour to make the division even more distinct.

What’s left to do is display the title; outside the $if() because we want to show it under all circumstances. Thanks to field remapping we automatically get the filename (without extension), if no title is present. Another column done.

The Time Column

Create a new column called Time, 50 pixels wide and right-aligned. This one stores the track lengths.

$if2(%_length%,'n/a')

The %_length% field returns the track length formatted as minutes and seconds. In the rare occasions when Foobar2000 might not be able to determine a length we display ‘n/a’.

The RGain Column

Create one last column named RGain, set width to 60 and make it right-aligned. This one holds replaygain info: the album gain value for album tracks and the track gain value for single tracks. You might want to read some more about replaygain on replaygain.org.

$if($get_global(isAlbum)
,
$if2(%__replaygain_album_gain%,'n/a')
,
$if2(%__replaygain_track_gain%,'n/a')
)

Nothing fancy here. We check for album tracks and display %__replaygain_album_gain% info or %__replaygain_track_gain% info respectively. Missing replaygain triggers ‘n/a’ display like in the Time column.

Done

We created all the necessary columns and filled them with the appropriate scripts to display everything we want to have in the playlist. In this state Foobar2000 should look similar to the following screenshot.

Screenshot of stage 1
Click to enlarge

You also can have a look at the complete Columns UI config so far to compare with your own code: Dark Connections, Stage 1. Load it by using the Import button on the Main tab of Colums UI preferences. But don't forget to Export your own config first.

In the following chapter we will add the colour scheme on top of the displayed information.