Wednesday, December 3, 2008

Rewriting the Library

This developer commentary explains the trials and tribulations of Mixxx's library code, and what the Mixxx developers are doing to improve it.

In the (long) development cycle between Mixxx 1.5.0 and 1.6.0, several changes were made to the library. Some of the more visible changes were the addition of our search box and "Browse" mode, which allows you to play songs off your hard drive without importing them into the library. There was also significant work done on playlist handling and management.

Mixxx 1.5.0, with our old-school library

Mixxx 1.6.1, with the new library

One not-so-apparent difference is that the underlying code was changed to use the Model-View-Controller (MVC) paradigm, which is easy to do with Qt 4 (... or so we thought).

As it turns out, many of the library problems that have been discovered since 1.6.0 are tied to the fact that we botched our use of MVC. Even if you grasp the MVC concepts at a high level, when you get deep into coding it, the separation between "models", "views", and the organization of GUI code can become mucky. Basically, we made some design mistakes, and the only way to correct them and allow us to continue improving the library is to go back and rewrite it from scratch. Some of the library-related bugs in our tracker are going to be very tough to fix because of the current poor design (#194415, #202594, #257769, #258955, #275198, etc!). Rewriting the library code will prevent many of these bugs from reappearing, and should also prevent us from being in a quagmire like this again in the future. Of course, this all depends on us having learned from our mistakes, and I hope that we have. :)

Mixxx with the even newer library! (work-in-progress)

Back in October at the GSoC Mentor Summit, I started hacking our library to use an integrated SQLite database to store track metadata, instead of storing them in a flat XML file on disk. I quickly discovered that there were two separate problems - The first being how the library was stored inside Mixxx at runtime, and the other being how it was stored on disk (XML).

At runtime, we were using a gigantic skip-list to store the metadata of every single track in the library. If you had a library with 100,000 songs, we were keeping the metadata (eg. ID3 tag info) for every song in memory. As you might guess, this was probably something the original Mixxx developers didn't think very hard about, because it doesn't scale well to large libraries. This brings us to the second problem.

When Mixxx starts up or is shut down, it read/writes all of this track metadata to an XML file (mixxxtrack.xml). Again, this simply doesn't scale well for large libraries because it takes a very long time to write metadata for a library of 100,000 songs (and is another example of where the original Mixxx developers didn't think hard enough).

When I started hacking SQLite integration into Mixxx, I started replacing the XML file loading/saving stuff. I quickly realized that I was going to need to fix the skip-list problem too, and then the lightbulb went on - Switching to SQLite solves both of these problems. Rather than storing metadata for all the tracks in memory at runtime, we could simply query the database to retrieve what we need. With that thought, I started deleting as much of the old library code as possible - It was a complete write-off.

I wanted to start from scratch to prevent myself from falling into the trap of the poor design of the old library. I coded many of the changes to the library that were made in 1.6.0, and it took a long time for me to finally give up and realize it was never going to be salvageable. I find this amusing because history is repeating itself - I made major changes to the soundcard I/O code inside Mixxx several times before I gave up and rewrote it all from scratch (which enabled things like vinyl control and multiple soundcard support to happen). For me, this is the fuel that keeps me coding. I know that cool things will be possible if I rewrite the library the Right Way (TM).

There is still a very long way to go before the new library code is complete, but I already have a few new features that people have been requesting, like the ability to move the columns in the library around (which saves automatically too!). Starting and shutting down Mixxx is faster, and I'm hoping that searching will be faster as well. The rewrite has also improved other areas of Mixxx's code - Some pieces of the old library were tied to seemingly unrelated parts of Mixxx, and fortunately I've been able to separate them, which solves many of the code organization problems that the old library had.

Some of the (big) things that need to be added still are playlist support, browse mode, and some sort of intelligent library scanning. The last item is being worked on by a new contributor, and we've been playing around with some cool ideas that we're both hoping will improve the library scanning/rescanning situation greatly. (That topic probably deserves a blog article on it's own.) :) In any event, the new library code won't be ready for at least another release or two.

Anyways, the main focus is to reimplement all the library functionality that was there before, but while I'm hacking the library, I want to hear what cool new features you (Mixxx users) want. If you want to share a neat idea, please leave a comment!


  1. In decreasing importance order, I would suggest:

    * LastFM support (even if Plunderphonics performances won't be logged, as a track can be "scrobbled" once half of its length or 30s have passed).

    * In addition to the current file tree browser, a more CoverFlow-like approach with album cover retrieval. Try Elisa's flowing authors/albums initials browsing mode as well.

    * OpenSoundControl to support even more devices.

    * Proper pitch-independent time stretching, using the Rubber Band library instead of the current SoundTouch?

    Keep up the good work!

  2. I'd just like to say that I'm loving using mixxx. I'm just getting back into DJing after 10 years or so away from it, and am loving it. :-)

    One feature that would be really useful would be when your mouse ran over the waveform, a box with the time of the position in the waveform was displayed.

  3. Hi GameGod,

    I just got hold of Mixxx, and it looks great. Since you're asking for feature requests I have a few which aren't necessarily cool, but would work for me and maybe a lot of other people.

    Basically, I'm hoping to find something on the Mac side of things that will automatically handle segues for a queue, at those times when the DJ wants to just set up a few songs and get out and dance a while.

    Although it's pretty techy, I've been able to set this up under Windows using foobar 2000 -- which will never show up on a Mac -- and since I want to share DJ duties with guys on Macs I'm hoping to find something that will work on both.

    There’s a short list of features that makes this work well enough for unattended operation in a fairly casual situation. I have no idea whether these would be easy or hard to implement, but here goes:

    First, the program needs to work with Replay Gain tags or similar, to normalize volume fairly well between tracks. Maybe Mixxx already does that, but I haven’t found it. In a pinch someone could just recode all their tracks to a normalized volume, but that’s a lot more work than just adding a Replay Gain tag, and you’ll lose a little quality along the way.

    Second, you want to be able to lose the tail-end silence or slow fade when the volume falls below some threshold, something like your general noise level, so you don’t have random-length gaps between tracks. A real quick fadeout at that point would be great

    Third, once you’ve established where one track ends, you want to be able to set up standard transitions between tracks, if not for each segue. For my own purposes I just need a fixed length of silence between tracks, so people know when that song is over and may want to go find another partner. Other lazy DJs might want to specify a standard crossfade overlap time. You wouldn’t expect it to beat-match, unless the program actually tries to synchronize the beats it finds automatically.

    So, this may be easy or hard stuff, which you may find interesting or not, but you asked. I haven’t found anything on the Mac that will do a good job of running playlists unattended, much less anything that will also do regular hands-on DJ stuff. It’s probably over my head, but I can take a look at what it would take to code up plug-ins, or whatever you use set up additional features.

    In any case, thanks for all the great work,

  4. * I'd love to see Pitch and BPM to be calculated and displayed also in vinyl-controlled-mode, so the waveforme-stretching.

    * An Indicator, that there are only 30 seconds left on the song would be great (so you can tune in the next) - the best that you can configure your own amount of seconds

  5. Good stuff so far guys, keep the ideas coming! :)

    (P.S. Christian - I hacked Rubber Band support into Mixxx a while ago, but I couldn't get it working and it was too slow. At the time, nobody had used RB in a real-time application, so the author wasn't sure if it was going to work. It looks like it's been updated, and it's possible that I just screwed up my implementation. I'll try to take another look at this.)

  6. i think trakor pro is state of the art
    perfect sync of every track is great but maybe to difficult.

    but i think there are a view things that could be made:
    1. centered gui in fullscreen mode

    2. looping like in traktor pro or at least ability to select a variable sequence and set it on loop

    3. coverart

    4. free arrangement of gui elements

    5. genre search

    6. possibility to set keyboard keys as effect keys - so your are able to work with a small midi interface, and a powerfull software - i hope you understand what i mean

    great stuff!!! only a open source arduino based dj mixer with ad/da sound interface is missing.
    or maybe is some thing out there beside aurora - please let me know

  7. Thanks for your great work guys, Mixxx is a wonderfull app, it is really a pleasure to work with it, and your support is second to none - continue the good job!

    As for feature requests, here's what comes to my mind:
    1 - more accurate BPM detection (current implentation just doesn't work well), with maybe an option to batch scan the full library.
    2 - looping support
    3 - resizeable GUI
    4 - jack transport: this would allow to send BPM data to other applications, for example to sync a delay or flanger to the tempo, or combine with other live music creation software.

  8. I would like to see ( in order of increasing difficulty to implement)
    1)The pitch behaviour option moved from the preferences window to the main UI, and settable for each deck individually. This should just be a single lock/unlock pitch toggle button for each deck.

    2) Pitch shifting independent of the playback speed (sort of the opposite of being able to change the speed without changing the pitch). This would probably only work for a few tones, si,ilar to how the speed can only be altered about 10-20% before sound artifacts start becoming noticable.

    3) key detection as well as beat detection - so you could see what key a song is in, when played at it's normal speed, and be able to better select other tracks that will mix well with it.

  9. Many of the comments preceding suggest really nice features, so I won't repeat them. I'd like to suggest three that may be less complex. These may mesh well with Mixxx's upcoming migration to an SQLite song database.

    (1) Have an option for Mixxx to cache the waveforms it creates for each song in a file or database, so it doesn't have to regenerate waveforms for the same songs each session.

    (2) Give the application's song database some modularity. Some of the fields listed may not be that useful to some. Create an interface in 'Preferences' that would make some fields optional or allow for the creation of new fields.

    (3) Create a means in which fields in the database can be directed to reference custom fields on ID3 tags. Mimic the code that reads the BPM tag on MP3s, but facilitate certain fields to point to other tag categories. For example, ID3 can have a "Comment" field, but Mixxx does not currently read for it.

    I posted something to the Forums that addresses (3) in more depth, should anyone care to read...

    I love this software. Thanks to all the developers.

  10. Something else that would be really good would be support for 3 channel mixing.