Reverse-engineering Nokia's MUSICARRAY SAVEFILE

By dkl9, written 2025-244, revised 2025-244 (0 revisions)


Like most humans, I like to listen to music sometimes, and it'd be convenient to do so via an especially portable device, such as a smartphone. My feature phone can store and play audio. Its capacity is a mere few megabytes, but a microSD card (partitioned right) fixes that. The music I pick ought to stay grouped in albums and soundtracks, but a built-in playlist feature handles that.

The last obstacle is the Nokia phone's interface to make playlists. Files can be picked for a playlist only one at a time. It takes several scrolls and clicks to add each one. The whole process is error-prone. Mess up, and the only solution is to delete the playlist or leave it wrong.

My laptop is far more flexible and powerful. If nothing else, I could copy a directory of music files to the phone, and ls *.mp3 >playlist.txt along with it. That would be a lot quicker and more reliable than tediously clicking thru a GUI.

But a newline-separated list of files wouldn't cut it for Nokia/HMD's programmers. The phone's storage holds playlist files in various D:\System\Mp3_res\PlaylistTitle.lst — Mocor OS uses Windows-style paths. Instead of text files, these follow a bespoke format that starts with an ASCII header MUSICARRAY SAVEFILE 01.00.0. Nowhere on the searchable web could I find this MUSICARRAY format documented. So I had some fun subtracting byte-offsets from xxd's output.

After the 27-byte header, each .lst file has 788 bytes per playlist entry. Each entry starts with 512 bytes for a path to the audio file. After that are 32 bytes of obscure meaning, 172 null bytes, and 72 bytes for a title. The path and title are strings, encoded with two little-endian bytes per character, padded as needed with null bytes.

I copied the 32 opaque bytes from an existing example, and generated the other fields by a script following the obvious format. Copy the audio files, download this new .lst to the right directory, and see nothing new when you try to open a playlist on the phone.

Apparently fetching the list of files D:\System\Mp3_res\*.lst wouldn't cut it for Nokia/HMD's programmers. The paths to usable playlists are in D:\System\Mp3_res\listinfo.data. This, too, has a 27-byte header, then 532-byte entries for each playlist to show in the GUI. Each entry contains a one-byte type-marker, then seven null bytes, then 512 bytes for a path, then a little-endian length for the path, padded to 12 bytes by nulls.

For all normal playlists, I saw the type-marker as 3, so I copied that. The length counts characters (pairs of bytes), rather than bytes. Append another 532 bytes as above to listinfo.data, open the playlist from the GUI, and all the files show up as "not found".

An LLM remarked that perhaps fetching metadata from audio files as needed wouldn't cut it for Nokia/HMD's programmers. Bytes 16-17 (zero-indexed, little-endian) of the critical 32-byte mess in a MUSICARRAY entry give the duration of each track in seconds. Check file durations as you rebuild the .lst, open the playlist, and only a select few entries can be played. Those select entries were those with the shortest titles.

Sith looking for a null character to end a string wouldn't cut it for Nokia/HMD's programmers. The length field was more obvious in listinfo.data, being surrounded by nulls. More study revealed a similar length field, for the path to the audio file, at bytes 0-1 in the playlist's 32-byte mess. Replace that length as needed for each track, and the playlist works well enough.

The whole process comes together in a Python script.