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.