
                     Playlists on the Rockbox

1. Demand-loading of Playlist Filenames from Disk

A playlist is simply a list of track names. These lists can either be 
created dynamically by the user, or they can be predefined and placed
into a text file with an .m3u extension.

The 2048 KB of RAM is the reason we need to get this right. If an average
track name (i.e. \music\cure\disintegration\01-pictures_of_you.mp3) 
is assumed to be 50 characters long, then:

A playlist of    15 tracks is    15 * 50 ~= 750 bytes
A playlist of   100 tracks is   100 * 50 ~=   5 kilobytes
A playlist of  3500 tracks is  3500 * 50 ~= 175 kilobytes
A playlist of 10000 tracks is 10000 * 50 ~= 1/4 megabyte

From these figures, it can be seen that for large playlists, storing 
the entire list of track names in memory significantly reduces the 
capacity available to the audio data buffer, which in turn has a negative
impact on the performance of the system.

One method of reducing the total memory consumption of a playlist is 
to delay bringing the actual filenames into memory until needed. Instead,
the playlist text file can be scanned, and an in-memory array constructed 
with one element for each track present in the text file. Progressing 
through the playlist entails getting the appropriate entry from the array,
and using that to perform a lookup of the corresponding filename entry 
from the playlist text file.

With this method, and given that an integer on the Rockbox's CPU is 4 bytes:

A playlist of    15 tracks is    15 * 4 ~=  60 bytes
A playlist of   100 tracks is   100 * 4 ~= 400 bytes
A playlist of  3500 tracks is  3500 * 4 ~=  13 kilobytes
A playlist of 10000 tracks is 10000 * 4 ~=  39 kilobytes

It is clear that these are substantial savings, albeit at the cost of 
increased complexity and disk i/o. Prefetch strategies could improve 
performance compared to demand-loading a single entry.

2. Implementation Options

Keeping the track names in a file on disk is easy enough for a predefined
m3u playlist, but for dynamically created playlists, where the user 
browses the filesystem and adds tracks or entire directory hierarchies
at will, we will need to store the playlist track names in a dedicated
file. This will be called the Anonymous Playlist, the location of which
can be set by the user, but will default to \anonymous.m3u or somesuch. 
The current contents of the Anonymous Playlist can be named and saved at
any time. 

The data structure to support playlists would therefore be:

typedef struct 
{
    char filename[256] ; /* path name of m3u playlist on disk       */
    int *indices;        /* array of indices into the playlist      */
    int  index;          /* index of current track within playlist  */
} playlist_info_t;

So far, so good: we read from an existing m3u file, or we create an 
anonymous one. But what do we do if we start with an existing m3u file, 
and then the user wants to dynamically add tracks to it? A few options 
exist:

a) we disallow playlist modification of existing m3u files, offering
   instead to replace the current playlist with the new one.

b) we give the user the option of appending the new tracks to the 
   existing m3u file. 

c) we copy the contents of the existing m3u playlist to the anonymous one, 
   and then append the new tracks to that. If the m3u playlist is large,
   this could be wasteful and potentially time-consuming. However, choosing
   this option would provide the facility to insert or append entire 
   existing m3u playlists 'into' one another, a feature missng from the 
   commercial firmware.





