LWN.net Logo

Collections in the XMMS2 music player

June 13, 2007

This article was contributed by Sébastien Cevey

The number of music players on Linux has been steadily increasing lately, but while these projects have been getting more and more polished, we have yet to see revolutionary improvements in terms of user experience. Indeed, the trend has been to borrow as many features as possible from other projects, rather than questioning the reasons behind their design.

This article describes XMMS2's attempt to address long-standing limitations of music players, through its new support for Collections.

Design Rationale

I have been concerned with the state of music players for a long time. Two years ago, I wrote a Manifesto for a Better Music Player. Although my ideas have evolved since then, the general conclusions of that article still hold.

One important argument I made is that the design of a music player should focus on the users' needs, rather than on a list of well-known features. All the traditional features (playlist, media library, cover browsing, etc) and hacks (play queue, random mode, etc) stem from the needs users have for:

  • playing music non-linearly
  • searching for specific media
  • browsing their media library
  • organizing their music

Non-linear playback was first introduced in a crude form as the "random mode", directly inspired from legacy CD players. iTunes later popularized its "Party Shuffle" mode, which solved the unpredictability of playback by maintaining a queue of randomly selected songs. What we are still waiting for, though, is a smarter mode that would also take into account beat, artist similarity, or other semantic information.

Music players that are based on a media library typically provide a search feature. Unfortunately, the power of the search function is often hindered by annoyingly complex forms used to choose the fields to query. Few developers seem to have noticed the success of Google's search interface: minimalistic, but enriched by rating heuristics and a rich syntax for advanced users.

The other axis required by our ever-growing music libraries is browsing. Media library browsing is always present in some form, although mostly simplistic and uninspired. When they are not cloning iTunes genre/artist/album filters or the browsing of cover art, most music players simply present the users with the list of all their media in a plain multi-column layout. Easy to implement, but hard on the eyes for the users. Interestingly, Foobar2000 (freeware) is the only popular player to allow a rich customization of the layout, which greatly improves readability.

The lack of features that help users organize their media library contributes to the difficulty of addressing the two previous issues. In the physical world, users can arrange their CDs spatially in their own personal way (by artist, date of release, mood, etc), set a couple of albums aside for playing at a party, or highlight their latest acquisitions on a shelf. This lets them build a cognitive map of the location of items. On computer-based music players, however, they are barely provided with the possibility to create playlists, possibly dynamic, but seldom integrated well enough to be used powerfully. Even bare files have richer organizational possibilities, using directories!

The reason behind these limitations is not that they are inherently unsolvable. The truth is that a lot of effort is required to implement new approaches in any of these fields. Experimentation, either conceptual or in terms of interface, is expensive.

The Collections Concept

The goal of Collections is to address this problem by creating a common abstraction layer. Search, browsing and organization all share one property: they act on subsets of the media library. Computers are especially good at handling sets, but music players haven't really exploited that fact yet.

A collection is defined as a subset of the media library. This set of media (songs) can be dynamic, for instance "All media by Kraftwerk released prior to 1980" or "All media added to the media library last week, except those by Justin Timberlake". A static set, for instance hand-picked media selected for parties, is just a special case of dynamic sets.

Note that a collection is not merely what some players call a "Smart Playlist" (or "Dynamic Playlist"). A "Smart Playlist" is only used to play an arbitrary list of media, while a collection is a generic representation of a set of media. For instance, this includes the results of a search, a filtered view of the media library, the list of tracks from a given album, etc.

Because a collection is an abstract representation, it can be used ubiquitously throughout all the features of the music player: browsing, searching in the media library or the playlist, enqueuing, jumping, etc. A collection can also be saved on the server, thus allowing the users to organize their music and reuse their selection in homogeneous and flexible ways.

Collections for the XMMS2 player

The XMMS2 project turned out to be the perfect ground to implement collections. Unlike its popular predecessor XMMS, XMMS2 hasn't gathered much attention yet. However, it features all that you would expect from a recent music player: a media library, support for many audio formats and multiple platforms (Linux, *BSD, OS X, Windows, etc), bindings for many languages (C, C++, Ruby, Python, Perl, Java), and a friendly community open to innovation.

In addition, the player was designed according to a client-server architecture, so that the server is responsible for all the boring work (audio decoding, media library management, tag extraction, etc), while any flavor of user interface can be implemented as a client connected to the server, possibly across the network.

Collections have been implemented in XMMS2 as a student project during the Google Summer of Code 2006, and finally merged into the stable tree on May 20, 2007 as part of the DrJekyll release.

Support for collections was implemented on the server as a layer above the media library, and playlists are exposed to the clients through a collections API. This API allows clients to save collections on the server, query the media library, enqueue the content of a collection, etc. Thus, although the user interface depends on the client, the server and the clients all share the same abstract representation.

Clients are also freed from the need to generate complex SQL queries themselves; instead, they can easily build a (DBMS-agnostic) collection and the tedious query is performed by the server. In addition, a parser is provided to generate a collection from a string with an enriched search syntax.

Collections make it essentially trivial to browse and search the media library. Moreover, advanced features are either natively available or very easy to implement: iTunes-like Party Shuffle, recursive filtering (e.g. search inside the playlist), display Top 10 or never played songs, changing the equalizer settings if the playing song is in a particular collection (e.g. "Jazz Vinyl rips"), etc.

Implementation

Strictly speaking, collections are implemented as a directed acyclic graph (DAG), each node of which is a collection operator. In fact, because the structure is recursive, each node of the graph corresponds to a collection. This model was chosen to emphasize the aggregated nature of users' music collections.

Collection operators come in four different flavors:

  • set operators
  • filter operators
  • list operators
  • reference operator

The set operators take an arbitrary number of operands and returns the collection obtained by applying the corresponding set operation to them. For instance, "any music by The Beatles or any music by The Rolling Stones". Available set operators: union, intersection, complement.

The filter operators enforce conditions on properties of the media; the resulting collection only contains the media that match the filtering attributes. For instance, "all the songs with 'stairway' in their title". Available filter operators: equals, match (partial matching of strings using wildcards), larger/smaller (for numbers), has (checks whether a property is present).

The list operators are a bit special. The basic list operator (called "idlist") does not accept any operands; instead, it simply generates the collection corresponding to the custom list of media it contains. Because list operators store static, ordered lists of media, they are used as playlists in XMMS2. Available list operators: list, queue (pop songs once they have been played), Party Shuffle (takes an operand, used to randomly feed the list with new entries).

The reference operator is simply used to refer to the content of a saved collection or playlist. For instance, "all the songs released in 2007 in the Foo playlist". A reference operator is also used to refer to the whole media library (all media).

Now, let's illustrate all this with a sample collection structure: [Collection Diagram] The nodes represent collection operators, while edges simply connect operands to operators.

Here, "All Media" is a reference to the whole media library, and we use a Match operator to only keep media for which the artist has a name starting by "A" (1). We then take the union (3) of this and the content of the "Rock 90's" saved collection (2). The result is passed as an operand to a Party Shuffle operator (4), which we save under the name "Interesting" (5).

When the user plays the "Interesting" playlist, songs are popped from the list as soon as they are finished, and new songs matching the operand collection (3) are automatically enqueued, so that the list always contains at least 20 items. This is specified by the "size" attribute of the Party Shuffle. Of course, the user can also edit the playlist and add tracks to it manually.

This is only one example of collections among many. As you can see, the modular structure of collections allows virtually unlimited possibilities. As such, they have been tightly integrated both on the server and in the client API.

On the server, a dedicated module is responsible for handling collection features. When a collection is queried, it serializes the structure into an SQL query, runs it in the media library and returns the matching media, either as a list of media ids or hashes containing the requested media properties. When a collection is saved on the server, it is added to the collection DAG and kept in memory while the server is running. On shutdown, the whole DAG is serialized into the database. Note that playlists are nothing but collections, albeit restricted to list operators and saved into a dedicated namespace.

In the client API, collections introduced many important changes. First, executing raw SQL queries has been deprecated; all queries are now to be performed using collections. Collection data structures can be built either using a set of dedicated functions, or by calling the collection parser on a string given by the user. Finally, many XMMS2 methods have been extended to support collections (e.g. to enqueue media) and new methods allow clients to query, save and retrieve collections from the server.

If you want to learn more about the concept of collections, please have a look at the collections concept page on the XMMS2 wiki. For more details about the implementation, check the collections design page and the API documentation.

Adoption and future directions

Several XMMS2 clients have started offering features based on collections, including Abraca (GTK2 client) and gntxmms2 (console client). Other clients have ported search and browsing to the collections API: Esperanza (Qt4 client), gxmms2 (GTK2 client) and the official command-line interface.

Hopefully, client developers will start exploring new directions now that collections are in the main release. The XMMS2 CLI client has already been scheduled for a full rewrite.

Several improvements are also expected to address current limitations of the collections implementation. One limitation is that all collections are treated equally as media sets; if a filter is applied on a playlist, the order and duplicated items will be lost. A smarter internal distinction between lists and sets inside the DAG is in the works. An ordering collection operator could then be introduced to transform a set into an ordered list, as well as an operator to select subsequences of such lists, similarly to SQL LIMIT operation. They could be used to create a collection containing the "list of the 20 most recently added media". The SQL query generator could also be further optimized, unless we decide to replace the database backend completely.

Collections have just made it into the official XMMS2 distribution, but people already use them through features like search, Party Shuffle or groups of songs saved in the media library. They are a powerful toy for developing new features in the clients and hopefully helping users organize and use their music library.

It's an exciting time to come up with fresh ideas in the XMMS2 world, and I hope the rest of the developers in the music player community will take the time to reflect on and discuss all these questions earnestly!


(Log in to post comments)

Collections in the XMMS2 music player

Posted Jun 14, 2007 9:19 UTC (Thu) by vblum (guest, #1151) [Link]

Thanks for the interesting article. Could the Kraftwerk part be shipped by default ;-)

Collections in the XMMS2 music player

Posted Jun 14, 2007 15:57 UTC (Thu) by nix (subscriber, #2304) [Link]

I'm not certain that this solves one problem common among those of us who listen to classical music and audiobooks.

The case we'd generally like is `shuffle entire works'. You might be able to do this in the structure described by defining `media' to be `a list of MP3 files in a specific directory' or something, but this seems crocky. Essentially you'd want a way to chain media together (into little lists which may themselves have sublists and so on, so you get a tree of media?) such that operators such as sorting only apply to the first element in the list (or to a selected one? XPath for music collections! ;) ).

Rockbox acquired something that sort of works in this area by providing random directory autochanging. This is a kludge but it sort of works if you turn shuffle off and keep one work in each directory: but it's a lot less elegant than having a shuffling/selection mechanism that actually *understands* that certain media should only be played in sequence with others (unless explicitly requested: maybe you *want* to listen to only the third movement of some work, but generally speaking you'd want to start with the first movement and play to the last: shuffled movements are basically never desirable).

Collections in the XMMS2 music player

Posted Jun 14, 2007 16:54 UTC (Thu) by scevey (guest, #45734) [Link]

Good point.

This has been discussed in the XMMS2 community, and so far the idea was to introduce a "selector property" attribute to the Party Shuffle. This attribute would define what property is used to randomly enqueue media from the operand collection. For instance, if you set it to "album", whenever the Party Shuffle needs to be refilled, it will select a set of song sharing the same "album" property, thus enqueing a full work rather than a single song. The current behaviour would still be activated by default by setting the "selector property" to "id".

It's not implemented yet, but it's definitely planned (Issue #1352)!

Thanks for your input!

Collections in the XMMS2 music player

Posted Jun 15, 2007 19:29 UTC (Fri) by nix (subscriber, #2304) [Link]

Yeah, but even *that* isn't quite enough. Some of the stuff on my player
I'd like to be played albumwise; some is song-by-song stuff and can be
shuffled more finely.

I wonder if what we have isn't a concept of a `subcollection', where
collections of files can be grouped into a `subcollection' which has its
own operators which apply to its members by default. So the shuffling
would apply to a bunch of individual things, and a bunch of subcollections
(`albums'), and *those* then have, by default, play-in-sequence operators
applied to them.

(But maybe I'm babbling and should shut up.)

Collections in the XMMS2 music player

Posted Jun 14, 2007 17:43 UTC (Thu) by thoffman (subscriber, #3063) [Link]

Yes, I'd like to be able to teach my music player that Tracks 1-4 on a particular CD are "Symphony #41" and should always be played together, in sequence, and tracks 5-9 are "Symphony #42" with the same restriction, but track 10 is a single work and can be played without restriction.

Note also it isn't just classical music that has this restriction. I have a bunch of "non-stop dance mixes" of various techno and electronica which meant to be played all the way through the whole CD with no breaks between songs. Or, at least between most songs.

Although, long stretches from a single CD can kind of defeat the purpose of shuffle play... maybe an option like: When shuffle play is enabled, only shuffle in the middle of this sequence with a given probability. For instance, p=0.25 would on average break the sequences into four-track lengths.

Hmmm.... you know, that would be useful for non-sequenced music too. I sometimes find it disconcerting when shuffle play jumps between radically different styles of music. If I could adjust a probability (or some other tunable) so that once shuffle chose a track from a CD, there would be a strong probability that it would then play at least one or two more tracks from that CD before going on to a different CD, I'd probably use that.

The collections thing with binary operators sounds also really useful. It would even be better if there were relational operators which could work on ID3 tags. Then could tag all my tracks as "Live" or "Studio", and with a relational '<' ID3.YEAR operator, easily have a collection of "Pre-1990 Live U2" for instance.

Of course, with all these features there has to be a really, really convenient user interface, otherwise it's just too much trouble to bother with. On my IPod I usually end up shuffle-playing within a single genre just because it's easier than putting together a playlist.

I mainly want to listen to music, not futz around in a clunky UI for hours.

Collections in the XMMS2 music player

Posted Jun 19, 2007 7:34 UTC (Tue) by scevey (guest, #45734) [Link]

I can see different ways to solve your complex shuffling use case. It's quite similar to nix's requirements in the post above.

Because we're trying to avoid adding too much complexity to the server, different new projects were discussed to make PShuffle more customizable. The first one was a Lisp interpretor that would allow all collection operators to be written in Lisp, and clients could write and save their own on the server. Obviously, it's far from being trivial, and we didn't get enough GSoC2007 slots to have it sponsored this year. An alternative could be to move the PShuffle inside a service client, which is a new GSoC2007 project by Ning Shi, which I'm mentoring. Clients could then rely on a more customizable client to do the shuffling, or even write their own shuffling service with special rules like the ones you and nix proposed.

As long as you either tag (using media properties) the media or put them in a dedicated collection, i.e. as long as they can be identified using collections, there isn't any reason why crazy shuffling methods wouldn't be possible :-)

The collections thing with binary operators sounds also really useful. It would even be better if there were relational operators which could work on ID3 tags. Then could tag all my tracks as "Live" or "Studio", and with a relational '<' ID3.YEAR operator, easily have a collection of "Pre-1990 Live U2" for instance.

The filtering operator work on media properties, which are automatically extracted from tags (ID3, Ogg comments, etc). So your use case is already supported by the current state of Collections!

Of course, with all these features there has to be a really, really convenient user interface, otherwise it's just too much trouble to bother with.

Of course, it's an important point. Work is still needed in that area, but it's certainly possible. So far, the text pattern syntax is one powerful way to build collections.

For instance:

(artist:"Pink Floyd" l:Meddle) OR (genre:Rock AND +compilation) OR (title:The* in:Playlists/Foo (NOT year>2000))

Builds a collection containing Meddle by Pink Floyd, all media that have "Rock" as genre and which are flagged (using a media property) as compilations, and all media in the Foo playlist whose title starts by "The" and which were release prior to 2000. Note: the AND is implicit when several conditions are put in a sequence.

Collections in the XMMS2 music player

Posted Jun 20, 2007 21:07 UTC (Wed) by nix (subscriber, #2304) [Link]

Lisp interpreters *are* trivial at their core, especially if (as for an
app like this) efficiency is completely unimportant. Something like SIOD
is really not hard to integrate, and SIOD is way more complex than a
minimal Lisp interpreter needs to be.

(Read McCarthy's original paper sometime, it's brilliant. That most
ancient of Lisps isn't one I'd recommend writing an interpreter for today,
but it does show how easy it can be.)

(btw, I'm not really sure `play these as a unit' really counts as
`special'. It's something *everyone* listening to classical music will
want, for example, and we're not as rare as all that. Not just classical
stuff, either: Steve Reich's not exactly classical, but shuffling the
movements of _The Desert Music_ would leave you with a meaningless
jumble.)

Collections in the XMMS2 music player

Posted Jun 21, 2007 7:03 UTC (Thu) by scevey (guest, #45734) [Link]

Writing a Lisp interpreter is indeed trivial. Integrating a Lisp interpreter in a music server daemon, so that it has access to all the internal resources (and possibly event hooks), including libraries to access the Net, read various XML, JSON or whatever feeds, while still allowing Lisp collection operators to expose self-describing customizable attributes, and monitoring their behaviour to make sure they're running correctly, is not trivial. If you want to do it, you are of course welcome :-)

I qualified your use-case (play these as a unit, and these not) as special because I don't know any player (physical or computer-based) that would support it. However using collections it would be quite trivial to implement it in the client, as you have all the facilities to do it. A 30-line Python script would probably do.

Collections in the XMMS2 music player

Posted Jun 21, 2007 20:09 UTC (Thu) by nix (subscriber, #2304) [Link]

Yeah, agreed, doing all *that* is distinctly nontrivial, but I didn't know
that collection operators had to access the net! It seemed like a simple
data-massaging to me, not a massive integration from multiple sources.
(But maybe I was misreading.)

And Rockbox can support this use case, sort of (the random
auto-change-directory feature).

And collections are deeply cool: combined with the client-server part of
XMMS2 (so I don't have to put up with the IMHO odious skins) it looks like
it might be a worthwhile replacement for/addition to MPD on my local
net :)

Collections in the XMMS2 music player

Posted Jun 24, 2007 10:42 UTC (Sun) by scevey (guest, #45734) [Link]

It does not to offer all these features per se, but if you want to allow advanced operators that, for instance, use Artist similarity from Last.Fm, or other data feeds, you would need them.

Anyway, right now I think we'll be focusing on Collections API + Service clients for this kind of thing.

Please feel free to let us know if you have suggestions or comments on XMMS2, either through the Mailing-List or the IRC channel (#xmms2 on freenode)!

Collections in the XMMS2 music player

Posted Jun 21, 2007 18:47 UTC (Thu) by TRauMa (guest, #16483) [Link]

As long as you tell Quod Libet each classical work is a seperate "Album", it supports your use case.

It also has dynamic playlist based on search and filter terms, although no SoC-Projects and new terms like "Collection".

http://www.sacredchao.net/quodlibet

Collections in the XMMS2 music player

Posted Jun 28, 2007 15:04 UTC (Thu) by scevey (guest, #45734) [Link]

Quod Libet is really quite a cool player. I thought I had mentioned it in the manifesto but apparently not. I like the choice of browsing "views", the search syntax. It's not super fancy, but it's definitely interesting.

In the case of collections, the challenge was to abstract the concept and the API so that it could be used by all clients ("interfaces", if you want) and all the internal parts of XMMS2 transparently. In fact, it's only a building block for more advanced features (Party Shuffle, tagging, mlib organization, etc).

Collections in the XMMS2 music player

Posted Jun 15, 2007 23:19 UTC (Fri) by wolfgang.oertl (subscriber, #7418) [Link]

> What we are still waiting for, though, is a smarter mode that would also
> take into account beat, artist similarity, or other semantic information.

You're probably aware of gjay for xmms (http://gjay.sf.net/) which implements at least part of this, i.e. beat and frequency analysis. This project hasn't had any releases in the last 3 years or so, though...

Collections in the XMMS2 music player

Posted Jun 18, 2007 11:27 UTC (Mon) by KaiRo (subscriber, #1987) [Link]

It's really cool to hear of new concepts being developed in that area, and I think collections should give us a really good new perspective to achieve things we couldn't so far.

What I really miss most from multimedia apps that include "media libraries" of some sort is a fuzzy search like in the abandoned Yammi project, which was really cool when you wanted to find only roughly known song titles, etc.

Collections in the XMMS2 music player

Posted Jun 19, 2007 7:38 UTC (Tue) by scevey (guest, #45734) [Link]

Mh, fuzzy search could be implemented as a new collection operator, but I am not sure the current DBMS we're using (SQLite) would be appropriate and effective for such operations. Our favourite smartest bearded lead developer is investigating a new storage backend, so maybe performance will allow that in the future.

Collections in the XMMS2 music player

Posted Jun 21, 2007 16:51 UTC (Thu) by leandro (guest, #1460) [Link]

I am not sure the current DBMS we're using (SQLite) would be appropriate

That is the problem with DBMS-agnostic applications: the lowest common denominator. I think what Apple did, in using full-featured but yet light enough PostgreSQL everywhere, just makes more sense.

Collections in the XMMS2 music player

Posted Jun 28, 2007 14:58 UTC (Thu) by tru (guest, #30161) [Link]

Didn't apple go with sqlite too? or are we talking about leopard?

Collections in the XMMS2 music player

Posted Jul 27, 2012 21:41 UTC (Fri) by leandro (guest, #1460) [Link]

Sorry for ðe late reply. I juſt (finally) figure actually Apple uſes SQLite for its ISO compatibility, inherited from PoſtgreSQL (ƿhich is ðe reference for SQLite’s language), in ðe deſktop, and PoſtgreSQL in ðe ſerver.

Not ðat it matters much, noƿ ðat Apple effectively gave up on ſervers.

Collections in the XMMS2 music player

Posted Jul 6, 2007 17:26 UTC (Fri) by KaiRo (subscriber, #1987) [Link]

Would be cool if that would be possible, it's a feature I really miss a lot in all other such apps.

Yammi has/had used XML as the storage backend, probably loading the whole "database" into memory, which obviously might sound a bit heavy on memory but is very fast (and I never saw memory problems with it).

The fuzzy search code it used is at http://yammi.cvs.sourceforge.net/yammi/kyammi/src/fuzzsrc... and is under the GPLv2 (but I guess Oliver might be open to relicensing if you need a different license).

Copyright © 2007, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds