MASARYK UNIVERSITY FACULTY}w¡¢£¤¥¦§¨  OF I !"#$%&'()+,-./012345

Automatically generated

BACHELOR’STHESIS

Tomáš Šedoviˇc

Brno, fall 2008 Declaration

Hereby I declare, that this paper is my original authorial work, which I have worked out by my own. All sources, references and literature used or excerpted during elaboration of this work are properly cited and listed in complete reference to the due source.

Advisor: Mgr. Jan Kasprzak

ii Acknowledgement

I would like to express my thanks to the following people: Mgr. Jan Kasprzak for giving me the opportunity to work on this project, thus making myself to finally dive into “that stuff”. Which is a good thing. Michael Grigoriev, the author of the IMMS system, for his wonderful support with more complex areas of his code. Fabien Ninoles, for his positive feedback about IMMSMPD, provived patches and ideas about its future direction.

iii Abstract

There is a group of people who likes to hear a different set of songs in a different order every time they listen to the . To satisfy them, most music players support a random playback feature. However, the users would appreciate if the some songs were played more often than the others – ideally without the need to manually tamper with their musical . The current music players offer this functionality either poorly or not at all. This project attempts to provide a suitable solution.

iv Keywords music player, playlist, random playback, MPD, IMMS, unix-like, /

v Contents

1 Introduction ...... 1 2 Investigation ...... 3 2.1 Design goals ...... 3 2.2 Music Player ...... 3 2.2.1 Introduction ...... 3 2.2.1.1 Features ...... 3 2.2.2 Architecture ...... 4 2.2.2.1 Server ...... 4 2.2.2.2 Client ...... 5 2.2.3 Protocol Description ...... 5 2.2.3.1 Establishing Connection ...... 5 2.2.3.2 Command Arguments ...... 5 2.2.3.3 Command Lists ...... 6 2.2.3.4 Server Responses ...... 6 2.2.3.5 Highlighted Commands ...... 7 2.3 Getting the Song Ratings ...... 12 2.3.1 Explicit Rating ...... 13 2.3.2 Implicit Rating ...... 13 2.3.3 Conclusion ...... 14 2.4 Usage Behaviour ...... 15 2.4.1 Generating the Playlist ...... 15 2.4.2 On-the-fly Song Selection ...... 15 2.4.3 Conclusion ...... 16 2.5 Integration With MPD ...... 17 2.5.1 Server-side Implementation ...... 17 2.5.2 Client-side Implementation ...... 17 2.5.3 Conclusion ...... 18 2.6 Intelligent Multimedia Management System ...... 19 2.6.1 Features ...... 19 2.6.2 Architecture ...... 20 3 Implementation ...... 21 3.1 Functional Specification ...... 21 3.1.1 ...... 22 3.1.1.1 Starting IMMSMPD ...... 22 3.1.1.2 Closing IMMSMPD ...... 22 3.1.2 Logging ...... 23 3.1.3 Configuration ...... 23 3.1.3.1 Description ...... 23 3.1.3.2 Structure ...... 23 3.1.3.3 Content ...... 24

vi 3.2 Architecture ...... 24 3.2.1 MPD Interface ...... 24 3.2.1.1 Playback Queue ...... 25 3.2.2 Interpreter ...... 25 3.2.2.1 Flag: Bad ...... 25 3.2.2.2 Flag: Ended ...... 26 3.2.2.3 Flag: Jumped ...... 26 3.2.3 IMMS interface ...... 26 3.3 Code-related Facts ...... 27 3.3.1 Language ...... 27 3.3.2 Used libraries ...... 27 4 Finalization ...... 29 4.1 Next steps ...... 29 4.1.1 MPD Playqueue ...... 29 4.1.2 MPD Get Next Played Song ...... 30 4.1.3 IMMS Protocol ...... 30 4.1.4 Lower the dependency on the IMMS code ...... 30 4.2 Conclusion ...... 31 Bibliography ...... 33

vii Chapter 1 Introduction

Music plays important role in our lives. It can serve us as an entertainment, relaxation or an emotional outlet. Being one of the oldest art forms, its diversity is enormous. Every person that listens to a music is different. They like different genres, listen to dif- ferent songs and on different occasions. Some prefer hearing classical music in theatres and operas, others love to lose themselves dancing to a psytrance track in a music bar, while yet others enjoy the rhythm of a hip-hop during their jogging excersise. Even the approach to order of the songs differs greatly: There are people who listen to albums just as the author of the music released them. There are others, who like to build their own mixes or , taking only the songs they like best and putting them into the order they prefer the most. And there are those, who would like to have every listening experience different, to have every playlist fresh, not knowing which song will follow the current one. This text and the program behind it is for this group of people. Nowadays, almost every music player (be it a software or a hardware) provides a way of playing selected songs in a pseudo-random mode. In such case, the order of the played songs is determined by a pseudo-random number generator inside the player. Which basically means that the user has no way of knowing what the next-to-be-played song is going to be. However, the listeners still do have a musical preference. They do prefer some songs over the others. And some tracks (spoken introductions and intermezzos for example) that work greatly in an album, are just not fit for a random playback. The goal of this project is to devise a solution for these users. It is then to be implemented into the MPD1 (Music Player Daemon) program, preferably in a way that could be extended to other music players such as XMMS2 (X Multimedia System). The text is divided into four chapters. After this introduction follows the second part, which consists of the investigation of the current situation and various design approaches. Each considered approach is described in detail along with the final decision and the reason behind it. The final chapter provides the details of the solution’s implementation into the MPD player and the last one concludes what has and has not been accomplished, what should

1. 2.

1 1. INTRODUCTION have been done differently and where to move on in the future.

2 Chapter 2 Investigation

2.1 Design goals

There are some guidelines I dedided to follow while making choices about various aspects of the final solution. Of course, the ultimate goal lies in the usefulness of the program. If it is being used and the users are happy with it then I have succeeded. Still, I believe in following these guidelines unless there is a good reason not to. Sorted from the most important one to the least important:

1. Don’t break any of the existing MPD clients

2. Easy to use

3. Don’t change users’ listening habits

4. Try to avoid the horrible installation experience typical for unix-like software

2.2 Music Player Daemon

2.2.1 Introduction Music Player Daemon is an open-source program used for listening to music. There is one significant difference between MPD and most other programs for playing music. As its name suggests, the software itself is run as a daemon1. It has no user interface per se, instead, MPD operates on the client/server architecture.

2.2.1.1 Features MPD offers the following features[2]:

• Playing the music

• Random playback

• Playlist shuffling

1. Program, running on background. Its parent is usually the init process and has no controlling terminal.[1]

3 2.2. MUSIC PLAYER DAEMON

• Save, load, and manage playlists

• Crossfading support

• Playlist versioning

• Musical collection as a SQL database

• SUPPORTED MUSIC FORMATS:

– AudioFile – MP3 – OggFlac – OggVorbis

• METADATA:

– id3v1 – id3v2 – MP4 –

• PROTOCOLS:

– TCP – IPv6 – Unix Domain Sockets

The complete feature list is on the MPD official page[2].

2.2.2 Architecture 2.2.2.1 Server MPD itself is a server program. It does not depend on the terminal it has been run from, therefore, it will continue to work even if a user logs out or restarts her X Window Server. It handles the task of actually playing the music, reading song metadata and taking care of playlists. However, none of these features is dicectly accessible to a user. Instead, MPD needs a client, communacating with the server via a custom protocol, that transfers the user’s commands and displays the status of the server.

4 2.2. MUSIC PLAYER DAEMON

2.2.2.2 Client One of the most important tasks of the MPD clients is to provide the actual interface to the user. Every graphical or command-line representation of the player is in fact an MPD client. MPD clients come in various shapes and sizes. There are single-purposed tools, designed for a particular task, be it a playback control, playlist managing, remote control or programs. On the other hand, one may encounter more complex applications, that would support multiple features and rich user interface – for example GMPC 2. The advantage of this approach is, that users can use different programs for different tasks. For example, they might use a command-line interface for their hacking time, while have visualization and better playlist management tools when being in GUI (). Additionaly, when no user interface suits someone’s needs, it is much easier to develop a frontend to MPD than to implement a full music player.

2.2.3 Protocol Description The MPD command protocol is built over the TCP network protocol[3]. By default, it runs on the port 6600, although it is possible to use a different one. The protocol uses plain text for transmitting messages. It is line-based (every command must end with end-of-line character or sequence). The text must be encoded using UTF-83. The communication is always initiated by client. Server sends only responses to client’s queries or commands. Therefore, any change in the player state (such as song stopped playing, new playlist was loaded, etc.) has to be retrieved by periodically asking the server and comparing the current state with the previous one.

2.2.3.1 Establishing Connection When the client connects to the server, the server responds with the following message[3]: OK MPD version

The version value represents the version of the used MPD protocol.

2.2.3.2 Command Arguments While some commands are sent alone (e.g. clear for emtying the playlist), others require additional information specified. A typical example would be playing a specified song. MPD command parameters are entered after the command on the same line. They are separated from the command and each other by a linear whitespace (space and characters)[3]. For example:

2. 3.

5 2.2. MUSIC PLAYER DAEMON swap 5 9

Will swap songs at the positions 5 and 9 in the current playlist. Should the parameter itself contain whitespace characters, it must be enclosed by double quotation marks[3]: search artist "art ensemble of chicago"

2.2.3.3 Command Lists

It is possible to send multiple commands to the server at one time. The benefit of this ap- proach is faster processing of the commands[8]. There are two commands used to initiate the command list sequence: command_list_begin command_list_ok_begin

These are folowed by the actual commands that are to be processed by MPD. The com- mands are entered in the same way as if they were standalone commands and not part of the list. However, MPD does not process these commands immediatelly – it waits untill all commands have been entered. After sending all the commands, the following command closes the list and instructs MPD to process it: command_list_end

If processing some command from the list results in an error, no other commands are processed and the error code for the failed command is returned.

2.2.3.4 Server Responses

Whenever the server responds, it returns any output produced by the command that has been issued, followed by a completion code. The completion code is a string that describes the status of the entered command. If the command succeeded, MPD returns:

OK

Otherwise, the following error message is displayed:

ACK [error@command_listNum] {current_command} message_text

The ACK string means that an error occured. The other parameters provide the error’s identification:

6 2.2. MUSIC PLAYER DAEMON error: Numeric representation of the error command_listNum: Offset of the command in the command list that resulted in error. If the command was not sent using command list, the value is 0. current_command: Name of the command that produced the error. If the error generated because an unknown command was entered, the current_command is empty. message_text: Text representation of the error type.

The following example[4] shows a sample exchange between the client and the server. The ’>>’ mark indicates client command, while the ’<<’ mark means server response. Note that these marks are merely illustrative and are not a part of the protocol.

<< OK MPD 0.13.0 >> pay << ACK [5@0] {} unknown command "pay" >> play << OK >> play "Gilberto Santa Rosa - Perdoname." << ACK [2@0] {play} need a positive integer >> play 1000 << ACK [50@0] {play} song doesn’t exist: "1000" >> play 10 << OK >> command_list_begin >> play >> play >> pay >> play >> command_list_end << ACK [5@2] {} unknown command "pay"

2.2.3.5 Highlighted Commands In this section are described the most important MPD commands. For the complete list see[5].

• Command: status Arguments: n/a

7 2.2. MUSIC PLAYER DAEMON

Description: Returns the current status of MPD. Following information is always returned:

– Current volume – Repeat status – Whether the player is in the random mode – Version of the current playlist – Number of songs in the current playlist – The crossfade time – Playback status (playing, paused, stopped)

This information is returned only if it has an appropriate value to display:

– Current song’s playlist position – ID of the current song – Elapsed and total time of the current song’s playback – Bitrate of the current song – Message text of the last occured error

• Command: play Arguments: Description: Plays the song at the specified position in playlist. If the position is not specified or is equal -1, the most recent song will be played. However, if a song is already being played, nothing happens. The position is zero-based. • Command: pause Arguments: n/a Description: Stops the song that is currently being played. If the song is played again before any other song, it resumes playing from the position it was stopped. • Command: stop Arguments: n/a Description: Stops the playback. If the stopped song is played again, it will start from the begin- nig.

8 2.2. MUSIC PLAYER DAEMON

• Command: next Arguments: n/a Description: Plays the next song from the playlist.

• Command: previous Arguments: n/a Description: Plays the previous song from the playlist.

• Command: seek Arguments: Description: Starts playing the specified song at the entered position in the song.

• Command: repeat Arguments: Description: If state is set to 1, the playback will start over when the last song is played. If state is 0, the playback will stop when the end of the playlist is reached.

• Command: random Arguments: Description: If the state is 1, play the songs in a random order. If the state is 0, play the playlist sequentialy.

• Command: currentsong Arguments: n/a Description: Displays the metadata for the currently played song. Also returns the following data about the current song:

– Number of seconds the song has been played – Possition of the song in the playlist – ID of the song in the MPD database

9 2.2. MUSIC PLAYER DAEMON

• Command: playlistinfo Arguments: Description: Displays metadata for all the songs in the playlist. If the optional song parameter is entered, only the metadata for the song at this position are displayed.

• Command: clear Arguments: n/a Description: Empties the current playlist. Increments the playlist version by one.

• Command: add Arguments: Description: If the item is a path to a song file in the database, this song is added to the end of the current playlist. If the item is a path to a directory, all files in that directory and its subdirectories are added to the playlist. Passing the slash character (add /) will add all songs in the database into the current playlist. Increments the playlist version by one for each added song.

• Command: delete Arguments: Description: Removes the song at the specified position from the playlist. Increments the playlist version by one.

• Command: move Arguments: Description: Moves the song at the from position to the to position in the current playlist. Increments the playlist version by one.

10 2.2. MUSIC PLAYER DAEMON

• Command: swap Arguments: Description: Swaps the songs at the specified positions in the current playlist. Increments the playlist version by one.

• Command: shuffle Arguments: n/a Description: Randomly rearranges the songs in the current playlist. Increments the playlist version by one.

• Command: plchanges Arguments: Description: Compares the current playlist with the playlist at the specified playlist_version. Returns the metadata of all songs that were added or changed since the playlist_version.

• Command: save Arguments: Description: Saves the current playlist to the playlist directory with the specified name.

• Command: load Arguments: Description: Loads the specified playlist from the playlist directory. Increments the playlist version by the number of added songs.

• Command: search Arguments: Description: Searches the database for all songs that match the value in the metadata field spec- ified by the type. Returns the metadata of the matched songs. type can be artist, album, title, track, name, genre, date, composer, performer, comment, disc, filename or all.

11 2.3. GETTING THE SONG RATINGS

The matching is case insensitive and substring-based.

• Command: count Arguments: Description: Searches the database for all songs that match the value in the metadata field spec- ified by the type. Returns the number of found songs and their total playback time in the following format:

songs: playtime:

Unlike the search command, the matching is case-sensitive and it must be an exact string match. Example: count artist radiohead

songs: 0 playtime: 0 OK

count artist Radiohead

songs: 84 playtime: 20975 OK

• Command: ping Arguments: n/a Description: The server returns OK. Used to check that the connection is still alive.

2.3 Getting the Song Ratings

There is one thing that is essential for the prioritized music playing to work – the algorithm must have data about the user’s fondness of each song. Without knowing which songs the user likes and which dislikes, it is not possible to provide much better results than an already existing random song selection.

12 2.3. GETTING THE SONG RATINGS

Thusly, we need to provide the user with a way to assign a rating to each song according to their preferences. There are two approaches that can be used. The first method requires the user’s direct input, whereas the second option relies on observing the user’s behaviour and adjusting the songs’ rating based on certain observed actions.

2.3.1 Explicit Rating

Probably the first idea that comes in mind is that the user would explicitly enter rating for every song he or she listens to. This could be achieved by assigning a number to a song (percentage or a school grade for example) or by sorting the songs according to the user’s liking. In order to maximize the user’s convinience, the rating should be possible to be entered and modified in two places. Firstly, it would be possible to browse through the user’s entire music collection and rating each song or group of songs from there. Secondly, the rating could be changed for the song that is currently being played directly through the music player interface. Ideally, both methods would be incorporated to the very music player software and playlist managing program that the user is already familiar with. One example of this method put in practice is iPod – the portable music player devel- opped by Apple company. It allows to assign a number of stars to each song. These stars represents how much the user likes the particular song. The more stars the better, while the maximum of stars that can be assigned is equal to five. The rating can be set either through iTunes, which is a program that organizes the user’s music collection, or directly from the portable device.

2.3.2 Implicit Rating

This algorithm would learn the user’s preferences by observing his or her listening habits. More specifically, this approach relies on silent observing of the user’s behaviour and interpreting certain actions (e.g. skipping a track) as the user’s way of expressing his or her fondness of the song. As oposed to the previous method which sets an absolute rating value for each song, this approach uses relative modification of the rating. That means that when the rating is to be changed, a small amount is either added to it or subtracted from it. There are three user actions that should result in a rating change:

• Skipping a song

• Listening to the whole song

• Jumping to a song (i.e. selecting other song than the one that would be played nor- mally)

13 2.3. GETTING THE SONG RATINGS

When the user skips a song that has recently started playing (first thirty seconds or so), it is expected that he or she doesn’t want to be listening to it. Therefore, whenever a song is skipped, its rating is decreased. When the user listens to the whole song, it is reasonable to deduce that she did like the song indeed and hence, its rating is increased. When the user specifically selects a particular song (instead of letting the software to play the one that would come naturally next), the song is expected to be user’s favourite and it receives another rating boost. Because human beings vary greatly, it is never possible to interpret every user’s action correctly. To cope with the situations, where the rating is modified incorrectly, the value by which the rating is modified should be rather small. As a result, in statistically significant number of user actions, the errors would be diminished by the correctly assigned rating changes. Unfortunatelly, this also means, that it takes some time of observing the user until the rating database actually reflects his or her preferences. The exact amount of required time depends on the number of songs in the user’s collection, the time he or she actually spends listening to music. In addition, it depends on the ratio between the rating scale and the value by which the rating is modified – the lesser impact each user action has, the longer it takes for the algorithm to learn the preferences.

2.3.3 Conclusion

I do not think that the explicit rating system would work very well. It relies too much on the direct user action. When the user is to do something, it must give him or her benefits that outweights the time and effort spent doing this action. Yet, for this method to work, the user eventually has to go through each song in his or her musical collection and provide a rating for it. Even with a ten albums total, it would mean having to personally set preferences for about one or two hundreds songs. And there are users whose musical libraries are orders of magnitude larger. In addition, this method requires user to manually adjust songs’ rating everytime he or she receives some new music or her taste changes. It is very likely that he or she will have different oppinion on a certain song or an album after the first, tenth and the hundredth listening. If the rating is left unattended, the time will very likely render it obsolete. Moreover, it is often very difficult to really compare two songs and decide which of them is better. As mentioned before, Apple implemented this feature in their iPod music players. I have been using an iPod for over two years now, knowing and being excited about this feature from the very start. Still, there are only three songs for which I have actually set any rating. I just never seemed to have enough time to sit in front of the computer just to rate at least some of the songs from my music collection. Doing so would simply take too much effort and it never

14 2.4. USAGE BEHAVIOUR seemed worth it. And setting the rating directly through the portable device did not work either – I have been busy doing something else. Users usually listen to music either while working, relaxing, or (in case of a portable music device) being outside. To have to decide on a rating every time a song changes would break the user’s concentration when working (thus hurting the user’s performance), disturb the relaxation or, in the very least, prevent from being immersed into the music. On the other hand, a plugin for implicit rating method has already been succesfully implemented for the famous XMMS music player. It is called IMMS4 (Intelligent Multimedia Management System) and it has been in active development and use since 2004[6]. Therefore, I have decided to implement the second approach, where the algorithm learns the ratings by observing the user. I believed that this method would be much more success- ful, because no action is required from the user side – he or she would listen to music in the exact same way as before, and the program would take care of the ratings. The most significant drawback of this solution is, that it doesn’t work right away. User is required to be patient, because it takes some time for the algorithm to learn. However, as the users are likely to be using the random playback already, it should not prove to be such a problem, because after they have installed the tool, they will listen to music exactly as they did before, with the difference that the order of the songs will gradually become more affected by their preferences.

2.4 Usage Behaviour

2.4.1 Generating the Playlist One way of providing the desired functionality is to generate a new playlist from a given set of songs. The algorithm would either do a permutation of the input playlist, taking the rating into account, or build a brand new playlist that could be shorter or longer than the original, meaning that some songs would be excluded or repeated in the result. Given the nature of this approach, it is possible to save the generated playlist and listen to it over and over again, should the order and the selection of the songs be worth it. It remains arguable that doing so would actually go against the very idea of this work (it is expected that the users who are going to turn to the resulting program do so for the reason of not hearing the same set of songs in the same order again and again). However, from the same reason why some musicians learn a previously improvised part note by note, the ability to store a particulary well generated playlist is benefitial.

2.4.2 On-the-fly Song Selection Instead of the playlist generating method, it is possible to leave the playlist as it is and mod- ify the order of the songs that are being played. Instead of a sequential order, the songs

4.

15 2.4. USAGE BEHAVIOUR would play on a seemingly random order, but again, with the user’s rating taken into con- sideration. Most of the music player programs already support random playback feature. When user switches the random mode on, the order of the songs becomes unpredictable from the user’s point of view. The benefit is, that user will hear the songs in different order every time she starts the playback, without the need of changing the playlist – if the set of the song is good. To achieve this using the former method, user would have to generate new playlist each time he or she wanted to listen to it again.

2.4.3 Conclusion

In the end, I have decided to implement the second option – modifying the playback order instead of generating a new playlist. The resulting program will observe the music player’s state and when the mode is switched to random playback, it will override the player’s de- fault behaviour by dictating whitch songs are to be played. The random playback switch is already implemented in virtually every existing music player. The playback shuffle feature is not as frequent. Moreover, the MPD protocol does not provide a way of knowing that the user requested the playlist to be reshuffled. Therefore, this action would have to have been provided externally, thus modifying the user’s habits of doing things. On the other hand, with the on-the-fly song selection, there is no need to modify the user interface of the existing programs, which in turn means that the user doesn’t have to learn how to operate new software. I believe that maintaining this sense of familiarity would be benefitial from the user’s point of view. As Joel Spolsky [7] notes: “A user interface is well-designed when the pro- gram behaves exactly how the user thought it would.” Not introducing new concepts to the existing user interface trivially fulfills this premise. In addition, it allows more flexibility toward the rating change. If a song’s rating de- crease, it will be played less often from now on. Whereas the playlist generation method will not acknowledge the change until a new playlist is to be generated. Finally, there already exists a solution called mpd-weighted-playlist 5. It is a small script, written in Python, that expects a list of songs and their ratings for an input and produces a playlist that is random, but the order and the occurence of the songs is based on the provided rating. As I have found no implementation of the randomized playback method for Music Player Daemon program, I feel even more compelled to provide one so that users may choose the one that better suits their need. And as a user, I would appreciate this method more.

5.

16 2.5. INTEGRATION WITH MPD

2.5 Integration With MPD

The rating and song-selecting solutions can be incorporated either into the MPD server itself or as a client that would communicate with the server.

2.5.1 Server-side Implementation

Given the previous design decisions, the server-side solutino would be done by changing the under-the-hood behaviour of some MPD protocol commands. Commands play, stop, next, previous and several others would have to be modified to gather and send information about the user’s listening habits. The whole solution requires having some sort of database which stores the rating for each song. Given the fact, that MPD already has a database of the user’s songs, it would seem logical to add the information in there instead of creating a separate database. Therefore, the MPD song database would have to be modified. Luckily, the nature of the modification would probably not require modification of the already written MPD database- access code. In the end, the user needs to have a mean of starting the prioritized random playback. Again, the most logical way seems to be the modification of the command random. It is possible, that some of the users would like to have an option to switch back to the original “truly random” playback. Should such need arise, I would suggest adding a new protocol command that would switch between prioritized and simple random modes. However, such change would re- quire modification of the status command output and could in theory result in incompati- bility with some of the poorly written clients. On the other hand, this is not very important feature and it is very well possible, that the old random playback would never be missed – at least for the majority of users.

2.5.2 Client-side Implementation

Instead of modifying the MPD itself, it is possible to write a MPD client that would take care of the user’s feedback and then, when the server would enter the random playback mode, the client would specify the songs to play, overruling the server’s default random song generator. The client would monitor the MPD status and interpret the status changes as user ac- tions. For instance, it would ask MPD what the currently playing song is. It would keep track of how long it has been played and when should it end. Then, when another song would start playing, the client would find out whether the previous one was skipped by the song’s length and the time it actualy had been played. If the actual playback time is substantialy lower, it can be assumed that the user skipped this song in favour of another one.

17 2.5. INTEGRATION WITH MPD

Similarly, it is possible to compute whether the current song was jumped (manually se- lected to be played) or not. When the player would enter the random mode, the client would detect this. Using the rating and the weigted pseudo-random song-selection algorithm, it would decide which song is to be played next. After the current song would have ended, the client would com- mand server to play the selected song instead of the server’s “random” one. Given the current state of MPD, however, there are some caveats to this approach. Firstly, using the command protocol, the client has no means of knowing how the current song was selected to be played. The song could have started naturally, because the last one has ended correctly, or it could have been selected by the next or the play command. Such information is not trans- mited over the MPD protocol. In most cases, it can be guessed by keeping track of the playlist, songs’ lengths and positions, however, there are some situations, where this information would be very helpful and yet, it is not possible to find out exactly what happened. Another weakness of the client approach is performance. As the MPD protocol is not event-based, the client must poll for the player status peri- odically. In order to provide good listening experience in random mode, the polling interval should be much shorter than in most other clients. The reason is, that since MPD has not implemented any way of specifying the next-to- be-played song, the client must literaly watch for the ending of the current song and then command the server to play the selected song. If the polling interval is too long, either the end of the song will be cut, or a short portion of the MPD default song will be played before the client “catches its breath” and sends MPD the correct song to play.

2.5.3 Conclusion

Despite the mentioned deficiencies, I have decided to implement the solution on the client side of the MPD system. Preliminary testing showed that the listening experience is satisfying even with the polling interval set to 250 millisecond, which is very generous value for the typical use (both server and client run on the same desktop computer with moderate configuration). The second argument against the use of the client approach is the fact that some user actions are not visible to the client. In particular, when the player is in the random mode, the client doesn’t know, whether the song that started playing was selected by player (i.e. jumped) or by the server (i.e. the previous song ended correctly or user skipped it by calling the next command). This effectively means, that every time a song ends in the random playback mode, it will be overriden by the song that the client selected. Even though this is a great drawback and it actually goes against one of the previously set design goals (do not try to modify the user’s behaviour), I am convinced that it is better than the alternative.

18 2.6. INTELLIGENT MULTIMEDIA MANAGEMENT SYSTEM

The very core idea of the MPD design is that the player itself will implement only the essential features (such as playing music, reading songs’ metadata and handling playlists and playback), while everything that is either subjective, or would not benefit most or all of the users, is to be implemented outside the MPD code base in clients. Moreover, the required changes would have to take place in the MPD code, which would increase the probability of making program errors with much greater impact than errors in a client. Lastly, according to the MPD official page, the version under development should bring changes in the protocol that may be able to solve the current issues with the client-based approach.

2.6 Intelligent Multimedia Management System

IMMS (Intelligent Multimedia Management System) was initialy developped as a pluggin for the famous XMMS music player. Its main goals were very similar to the ones laid out in this text – transparent for the users, automatic learning of the songs’ ratings and modifying the existing current random playback instead of generating new playlists. Since the version 2.0 it has decoupled from XMMS, becaming more of a standalone solu- tion for the common problem, that could be easily modified for other music software.

2.6.1 Features

• Client-server approach for customizing IMMS for other players

• Silent song rating (no special user intervention required)

• Ability to recognize remixes and treat them as one song

• Rating and other internal data about the song are stored in a SQL database

• VARIOUSTECHNIQUESTODETERMINETHEPLAYORDEROFTHESONGS:

– Rating of the song (gathered from user’s listening habits) – Song’s tempo – Frequency spectrum of the song – The last-played date and time of the song

After studying the IMMS system and communicating with its autor, Michal Grigoriev, I have decided to implement an IMMS plugin that would make it work with MPD instead of de- vising my own algorithm. The algorithm for selecting the order in which the songs are to be played is rather com- and takes into account more parameters than I have thought of. Moreover, it has been

19 2.6. INTELLIGENT MULTIMEDIA MANAGEMENT SYSTEM used and tested for more than three years. During this time, its author has perfected the al- gorithm. Since it does work quite well, it seems to be a better idea to join the its community and extending it by bringing the program benefits to new set of users instead of creating a (possibly sub-optimal) competition. Using the existing solution, it takes less time and effort to write the target program and therefore have more time and flexibility to react to the users’ responses. I believe my efforts would be better spent by improving and promoting the idea itself than basically creating a copy of an existing product – especially when there is no obvious need of such copy.

2.6.2 Architecture IMMS has an architecture similar to MPD. The server’s main goals are to manage the song rating database and to suggest appropriate songs to be played when the client asks. The client’s responsibility is to interface with the music player. The client must be able to gather essential information (such as what is the current playlist, which song is being played at the moment and so on), and forward them to the server. Additionaly, when the player is in the random mode, the client asks server for song suggestions and then makes sure that these songs are played at the appropriate time.

20 Chapter 3 Implementation

3.1 Functional Specification

We have made the basic decisions and thus, we have a general picture about how the pro- gram will work (MPD client, will observe user’s listening behaviour and in random mode will provide songs to be played based on the rating of the songs in the current playlist). Let us take a step closer and look at the actual implementation. On one side we have the MPD server. Its communication protocol allows us to find out the songs that are currently in the playlist, name and the elapsed time of the song that is being played and the state of the player (playing/stopped, sequential/random playback, repeating/not repeating playlist). Moreover, we are able to command the server to play the song we require. On the other side, we have the IMMS server. It require up-to-date information about the current playlist and the way how any song started and ended. IMMS assigns and re-evaluate rating for each song and, when asked, it uses these rat- ings, pseudo-random generator and songs’ tempo and spectrum analysis to provide the appropriate track for the moment. Now, what we need for these two programs to work together, is an application, that is connected to both of them, getting tha playback information from MPD, interpreting them to correct user actions, and send these to IMMS. Then, when the MPD switches to the random playback mode, our program will ask IMMS for the song suggestions and at appropriate times send them back to MPD to play them to user. The whole process is to be as transparent for the user as possible. Idealy, after having installed and set up the tools, he or she would not even notice, that they are present – except for the more pleasant song selection in random playback mode. Later in this text, the program is going to be refered to as IMMSMPD. Despite the fact, that it is not the most poetic program name ever devised, it serves its purpose, I believe. It is expected that the IMMSMPD will be active at the same time as MPD. Because MPD is a daemon, it is important that IMMSMPD must be a daemon as well. For instance, as a daemon, MPD is not affected by the restart of the X server (graphical interface of UNIX/Linux systems). If IMMSMPD was not a daemon, it would be closed on such occasion, which would not be intuitive behaviour from the user’s perspective.

21 3.1. FUNCTIONAL SPECIFICATION

3.1.1 User Interface

Because of the requirements, there is no need for a user inteface per se. Apart from the program configuration and its running and stopping, the only thing that the user need to control is the playback mode – whether it is sequential (and thus IMMSMPD should not take control over which songs are to be played) or random (in which case it should). However, this should be strictly related to the state of the music player itself. Therefore, the user does this playback mode selection in the MPD client(s) he or she is already using by pressing the random button or issuing a similar command there. It is IMMSMPD’s job to notice the chande of the player state and react accordingly. This is done automatically. No command-line options are required and neither is any GUI (graphical user interface).

3.1.1.1 Starting IMMSMPD To run IMMSMPD, user simply types: immsmpd

The program will start as a daemon. If it succeeds, the following confirmation message is displayed at the standard output:

IMMSMPD successfuly started. To close it, type: immsmpd exit

In the case of an error, a message is written to the standard error output and IMMSMPD exits with nonzero return code. It is possible to start multiple instances of IMMSMPD, however, it is not recommended. They will interfere witch each other.

3.1.1.2 Closing IMMSMPD Because IMMSMPD is a daemon and has no user interface, the user cannot close it within itself as with most other programs. Nor will IMMSMPD close on its own (unless an unrecov- erable error happens), because its job is to stay in memory and silently monitor the user’s listening actions. As a result, there is a set of commands that close all active IMMSMPD sessionns. immsmpd exit immsmpd quit immsmpd close immsmpd --kill

All of these commands have the same function – to close the running IMMSMPD.

22 3.1. FUNCTIONAL SPECIFICATION

There are different variants of the same command to make it more accessible for the user. He or she does not have to remember the one particular word to close the program. The most intuitive options work. The -kill option is used because MPD uses it for closing the daemon. Therefore, we can expect that some users will try to close it in the same way. On success, the followng message is displayed:

IMMSMPD closed successfuly.

If the program was not running at the time, the following message is shown instead:

IMMSMPD is not running -- nothing to close.

In both cases, the message is written to the standard output and the exit code is 0.

3.1.2 Logging While in the daemonized state, the program doesn’t write to the terminal it was run from. However, there is a need for some way of letting user know that something is wrong. Every message that IMMSMPD need to output will be sent uning syslog1, because it is de facto standard for logging on unix-like systems.

3.1.3 Configuration 3.1.3.1 Description Even though I strive to make the program as simple as possible, some aspects of the program should be customizeable. To be true to the target platform, I decided to use the idea of configuration files. The file itself is stored at the following location:

/$HOME/.imms/immsmpd.conf

The .imms directory in the user’s home location is already used for IMMS related files.

3.1.3.2 Structure The structure of the configuration file is similar to the most UNIX/Linux config files. It is a text file, where every line contains a pair of option and the corresponding value. The option and value are separated by the equals character (’=’). Any leading and trail- ing whitespace of both option and value is ignored. It is also possible to specify comments in the file. Any text after the hash character (#) until the end of the line is ignored.

1.

23 3.2. ARCHITECTURE

3.1.3.3 Content

The default configuration file has the following content:

# MPD_host = localhost # MPD_port = 6600 poll_interval_ms = 100

MPD_port: specifies the port number which is used for connecting to the MPD server. MPD_host: specifies the name or IP address of the MPD host to connect to. poll_interval_ms: the interval (in miliseconds) at which the client refreshes the informa- tion from MPD. As much as the performance of the user’s platform allows, the lower this value, the better the overall experience.

3.2 Architecture

The IMMSMPD program consists of three logical parts. As the program has to communicate with two other servers, there is an MPD interface and an IMMS interface. The third part’s purpose is to interpret the players’ states as the user’s fondness of the played songs.

3.2.1 MPD Interface

The MPD interface’s task is to provide the useable abstraction of the MPD server for the rest of the program. It takes care of the following actions:

• Connecting to MPD and keeping the connection alive

• Providing the current playlist

• Allowing to get and set the current playback mode (sequential / random)

• Providing the playback queue functionality

• RAISINGEVENTSWHEN:

– A current song stopped playing – A new song started playing – The playlist changed – The playback queue should be updated

24 3.2. ARCHITECTURE

3.2.1.1 Playback Queue The playback queue (or a playqueue in short) is an abstraction, that allows the user of the MPD interface module to queue up songs that should be played with priority. Because the whole module was written for the very specific purposes (providing the information necessary for the IMMS algorithm), the playback queue functions only in the random mode. The reason for this feature is to provide easier work with the module and to be able to have suggested songs available when the connection to IMMS cannot be established for whatever reason. The greater the playqueue size, the longer the program can go without being connected to the IMMS server. However, large-sized playqueue may result in sub-optimaly suggested songs, because it may not be up-to-date with the latest changes in the rating. Currently, the playqueue maximum size is restricted to two songs. Given the fact that typical song is about three minutes long, this should be enough time for solving the connec- tion issue with IMMS and it can be expected that, if no song is suggested during that time, there are problems that are likely out of the IMMSMPD program’s reach. Whenever the playque is not full, an event, asking for a suggested song is raised. If the playqueue gets empty during the random playback, MPD interface will not inter- fere with the MPD server and choosing the next song is upon the original MPD algorithm.

3.2.2 Interpreter

Whenever a song ends, the information must be forwarded to IMMS server, so that it can adjust the song’s rating. To be able to do that, IMMS requires three pieces of information about the user’s ap- proach to this song. Each of these pieces carries a true-false value and it is the Interpreter’s job to provide that value.

3.2.2.1 Flag: Bad This flag describes whether the user didn’t like the song enough to skip it. Setting it on results in a rating drop for the affected song. As this flag should describe that the user really doesn’t want to listen to this song, it is not a good idea to set this flag whenever the song is ended prematurely. When a user stops a song halfway through, it is unlikely that he or she wishes the decrease its rating – more probable explanation is that he or she is interupted or wants to listen to a different song. Therfore, when a new songs starts to play, there is a time window in which changing the song results in raising the Bad flag. Once past that window, the value is set to zero. The original idea was to set this interval to 30 seconds. For the most songs, this is an acceptable value. It gives the user enough time to find out what the song is about) and yet it is not too long to cause much trouble. The same time was used in the IMMS plugin for the XMMS music player.

25 3.2. ARCHITECTURE

However, for songs shorter than one minute, this could result in a situation, when the both the Bad and the Ended flags are set, which is not acceptable. In these cases of doubt, it is better to err on the side of not setting the flag than the other way around. That way, the ratings for the good songs will not be harmed, while the unfavoured songs will get their decrease eventually – only it would take a bit longer. In the end, the song is marked by this flag, if it has been played for less than 30 seconds and the played time did not exceed 13 per cent of the usual song length (between three and five minutes). The percent value was determined so that it corresponds with the 30 seconds to the average track length ratio.

3.2.2.2 Flag: Ended This flag describes that the song was played from the beginning to the end. Therefore, we can expect that the user liked the song and thus, it gains a rating increase. The value is computed in a way similar to the previous flag. If the played time when the song ended was less than 92% of the total time and the difference did not cross 20 seconds, the song is considered correctly ended. The reasons for this time interval are same as for the Bad flag decision – both the per- centual and the difference values matches at the average time and combining them prevents unexpected behaviour for too short or too long songs.

3.2.2.3 Flag: Jumped When the Jumped value is set, it means that the user selected this particular song, instead of a one that would be played naturally. It is expected, that he or she selected the song because it is their favourite and therefore it receives a rating increase. It can combined with both Bad and Ended flags or it can stand alone. In the sequential playback mode the flag is set, when the previous song is not directly before the current one in the playlist. The playlist rotation is also taken into consideration. In the random mode the flag is never set. The reason is, that the current version of the MPD protocol does not allow to find out which song would be played next by the pseudo- random algorithm. Therefore, the MPD client can not find out whether the song was selected by the server algorithm or by the user.

3.2.3 IMMS interface This module is designed to provide the program interface with the IMMS server. Its task is to initiate and keep alive the connection to the server and provide it with the information IMMS needs to do its work. Whenever a current song stops playing, a new one starts playing or the current playlist is changed, this information (along with the data from the Interpreter module) is forwarded

26 3.3. CODE-RELATED FACTS by this module to the IMMS server. In adition, whenever the server asks for a particular song from the playlist, IMMS inter- face provides it. Lastly, when the MPD player’s playqueue is empty, this module sends the request for a song suggestion to the IMMS server and forwards the result to the player. Because the IMMS server should be invisible to the user, this module is responsible for starting the server and restarting it when the connection is lost. This behaviour contrasts with the MPD interface which merely attempts to form a connection with MPD, but does not start the server when it is not running.

3.3 Code-related Facts

The following section describes the tools and processes used while writing IMMSMPD.

3.3.1 Language

The program is written in ANSI/ISO 1998 standard ++ language. There were two main reason for this language decision. Firstly, given the target platform (UNIX/Linux), it was the language I knew most about at the time (with the exception of C# which was ruled out because of the Mono .NET frame- work requirement). In addition, IMMS was written using that language and a C/C++ client library already existed.

3.3.2 Used libraries libmpdclient: Library designed for writing MPD clients. It is written in plain C and it is basically a direct transfer from the MPD protocol to C environment. It had to be modified a little, because some of the implicit pointer conversions in the library are forbidden in stan- dard C++. Even though the library is a rather low-level one and probably somewhat too compli- cated for the few simple tasks required by this particular program, it helped to get the work done. clientstub: IMMS server comes with a library that is designed for writing the client pro- grams. It provides a simple way of accessing the server and abstracts away the connection to the communication socket and the low-level protocol system. It comes with an almost functional class with three virtual methods to be implemented:

• Return the current playlist’s length

• Get the path of the song at the specified playlist position

• Enqueue the suggested song to the music player

27 3.3. CODE-RELATED FACTS

When the code for these tasks is provided, the interface is ready to be used with the client. Glib 2: Glib is a multi-purpose library for writing complex applications. It is a core of the GTK+ library for writing GUI-based programs. It provides a way of handling timers, main event loop and command-line arguments processing (and many more interesting features that were not used in this project). It is already being used in IMMS for operating the socket file that transfers communi- cation between the client and the server. In order to compile the IMMS clients using the provided library, the Glib is required. IMMSMPD itself uses Glib for the main program loop and the MPD poll timer function- ality. Standard Template Library: The C++ language is strongly coupled with the Standard Template Library which provides the most essential structures, data types and algorithms for everyday use such as Strings, Lists and Vectors, and handling the input and output. As with most of the C++ projects, the library is used in numerous times throughout the IMMSMPD code, mainly for string operations and containers.

28 Chapter 4 Finalization

4.1 Next steps

Even though the program is working and ready to use, the whole project is far from being finished. To become a valuable member of the community there are actions to be taken that are beyond just writing the code. Firstly, the program should be more promoted to the target audience. The first steps were already taken as the program is hosted on both MPD and IMMS official pages. The IMMSMPD hosting page1 should be improved to provide better communication channel between the users and the developer and to make the whole experience of finding out about the program easier. As the program heavily relies on MPD and IMMS to work, it is imperative, that their development must be closely watched to make sure that the program works with the latest versions. In addition, there are a few code related things that could improve IMMSMPD’s perfor- mance or usability:

4.1.1 MPD Playqueue

The current client-based implementation of the playqueue is not really good. The client has to repeatedly check MPD for a song change and when in happens, it commands the server to play a different song. This results in a possibility, that a small portion of the original song (the one that would play without the playqueue implementation) may be heard. The probability of this happening depends on the client-server connection latency and the client’s polling interval. The testing showed that the 100 milliseconds interval produces good listening experience and is acceptable from the performance point of view. However, it would be better if the playqueue functionality was implemented on the server side. As of writing this text, this feature is actually in development on the MPD side. Therefore, when the new version of the player is released, IMMSMPD should be updated to support it.

1.

29 4.1. NEXT STEPS

4.1.2 MPD Get Next Played Song

Currently, the MPD clients have no way of knowing what the next-to-be-played song is going to be in random mode. This results in two issues with IMMSMPD. The first one is, that in random mode, we cannot determine whether the next song should have the rating boost for being selected by the user or not. The second and more important problem lies in the fact that we are unable to find out, whether the next song is to be overrined by the suggested song or not. As a result, even if the user specifically selects a song from playlist, IMMSMPD can not distinguish it from the action of skipping a song and therefore, a suggested track will be played instead of the selected one. These issues concern only the random playback. In sequential mode, both features work correctly. The functionality to prevent this is being developped for the next version of the MPD.

4.1.3 IMMS Protocol

The IMMS architecture contain one design issue, that results in unnecessary load of com- munication between the server and the client. Every time a client asks for a new song suggestion, the server requests from the client the paths to songs at certain playlist positions. The author of IMMS explained that this is done because the XMMS player did not provide a way of letting its plugins know when the current playlist changed. Therefore, the IMMS checks part of the playlist to check that it is still unchanged. While this solution does work, it would be better done on the client part. The client already has a way of telling the server that the playlist has been changed. Therefore it seems unreasonable for the server to do this again. It would make things easier if the deciding whether the playlist changed was moved entirely under the client competence.

4.1.4 Lower the dependency on the IMMS code

Currently, IMMSMPD is very strongly to the IMMS system. It uses the module for plugin creation that was provided as part of IMMS. Unfortunatelly, while it makes the implementation of a IMMS client less difficult than doing so by using the communication protocol directly, it dictates some aspects of the de- velopment and couples the client too strongly with the server. To avoid the direct use of the protocol, the developper is forced to use the C++ language, for instance. Moreover, to compile the client, the IMMS code is required to be present and compiled as well. This results in a loss of flexibility and may lead into installation or update problems. In addition, I believe that the client should be able to be distributed separately from both MPD

30 4.2. CONCLUSION and IMMS, even though the program itself is useless without the two. To achieve this, IMMSMPD should be modified not to use the IMMS client library. In- stead, a new library should be developped – one that is more extensible and not dependent on the original IMMS code. It would communicate with the server using the protocol di- rectly and it would provide a well-documented interface for writing IMMS clients.

4.2 Conclusion

While working on the project, I have first-handedly experienced some of the numerous fail- ure cases that are threatening software development. In the beginning, I did not use any source control system or regular backups. Satisfyingly, this lead to a data loss, which in turn made me to set up and starting to use a revision control for both the source code and this text. Having located the repository on a different location from my development machine, it serves as a backup solution as well. Nearing the end of the programming phase, I have decided to redesign and rewrite the whole code from scratch. There were two reasons for this action: the code had become rather messy over time and after having finished the class in Systems Analysis and Design, I wanted to do the right thing and do the formally correct analysis before writing any new code. This proved to be a catastrophic idea. The blind and rigid following of the rules and creating the necessary diagrams took much longer than if done informally. I have found out the hard way that not every methodology is optimal or even helpful for project of any type or size. As for the rewriting from scratch, it didn’t help much either. I kept falling into the same traps as before and I have lost too much time writing the code again. In the end, the result was better than the first version, however, the same result would be accomplished with a fraction of time using careful refactoring. Lastly, the choice of the language itself didn’t prove to be the best one either. The strength of the C++ language lies in different areas than in writing small programs whose main task is to manipulate strings and implement a simple program logic with a few alrogithms. Using Python, or Ruby would probably have been much better choice. It would lead to less code (which would meand easier maintaining) with cleaner and more readable architecture. In addition, the result would not be as strongly bound to the IMMS and the set up process would be easier as well, because compiling the program would not be required. Despite these errors in judgement and foolishly lost time, I have succeeded in writing a working solution. It is available through the MPD official web page, IMMS page and it has its own site with description, download and usage instructions. There are people who actively use the program. So far, I have no way of knowing how many users the program have. The only mean of getting the feedback is by e-mail, which can discouradge users to providing any. On the other hand, the little feedback I have recieved was helpful and mostly positive (patches for little bugs and expressions of satisfaction with the program).

31 4.2. CONCLUSION

The most important step to take from here is to bring IMMSMPD closer to the users. This should be done by making the set up process easier, by providing a better project page and by spreading the word of its existence to potential users. Whether the project succeeds or fails, only time will tell. However, I am very glad for being able to work on. It taught me valuable lessons about software development and provided me with experience that will hopefully help me make better decisions and – in extension – software in the future.

32 Bibliography

[1] Wikipedia contributors: Daemon (computer software), Wikipedia, The Free Ency- clopedia, 23 December 2008 16:35 UTC, . 1

[2] Music Player Daemon Wiki contributors: Music Player Daemon Wiki: Features, Wikia, Inc., 26 November 2008 17:38, . 2.2.1.1

[3] Music Player Daemon Wiki contributors: Music Player Daemon Wiki: Protocol Out- line, Wikia, Inc., 12 August 2008 15:45, . 2.2.3, 2.2.3.1, 2.2.3.2

[4] Music Player Daemon Wiki contributors: Music Player Daemon Wiki: ACK Re- sponses, Wikia, Inc., 23 April 2008 13:52, . 2.2.3.4

[5] Music Player Daemon Wiki contributors: Music Player Daemon Wiki: Daemon Com- mands, Wikia, Inc., 7 October 2008 23:52, . 2.2.3.5

[6] Grigoriev, M.: IMMS.Download History, Michael Grigoriev, 02 March 2008 21:23, . 2.3.3

[7] Spolsky, J.: User Interface Design for , Apress, 26 June 2001, 978- 1893115941. 2.4.3

[8] Music Player Daemon Wiki contributors: Music Player Daemon Wiki: Command List, Wikia, Inc., 7 October 2008 23:52, . 2.2.3.3

33