I released Mono.Zeroconf 0.7.4 last night which is a minor bug fix release. Packages are available for openSUSE, SUSE Linux Enterprise, and Fedora. Sources and binaries are available for Linux, Windows and OS X.

What I have found interesting about Mono.Zeroconf is a growing adoption by the Windows crowd. I have been getting almost weekly emails from a new Windows developer using Mono.Zeroconf. A few bugs have been fixed in the process, though mostly in the Bonjour provider, which doesn’t affect modern Linux distros (because they use the Avahi provider, of course).

Since there’s been good feedback from the Windows world, I spent a little time making Mono.Zeroconf actually build on Windows in Visual Studio (yikes!). I am producing .zip files of the regular sources as well to make releases more accessible on Windows. Additionally, I generate a -binary.zip file which contains just pre-compiled assemblies.

The fun thing with all of this is validating how truly remarkable Mono is. I had never written any of Mono.Zeroconf specifically for Windows, never tested it on Windows, yet released the precompiled assemblies (built in Linux by Mono) for the hell of it. And without any changes, everything “just works” on Windows/.NET (and Mac OS X as well).

Leap
Andy made the leap to Linux.

So what’s so important about this? These new Mono.Zeroconf users on Windows inherit the fact that Mono.Zeroconf is truly cross platform, which means their applications are immediately more portable to Linux and other platforms that Mono supports. By luring Windows developers with delicious, easy to use libraries that are already cross platform, we make it easier and more enticing for those developers to bring their awesome applications to Linux.

Awesome. Mono rocks.

The new Banshee logo Only a few months overdue, we’ve finally released a new stable Banshee. This release includes a slew of important bug fixes and a handful of new features.

iPod

On the iPod side of things, there have been some pretty heavy changes since the last release. We now require PodSleuth and the latest ipod-sharp. This is the first release that drops libipoddevice, the hardware layer that was obsoleted by PodSleuth.

What users should care about is that this release supports the new Nano and Classic iPods. We currently are not supporting the iPod Touch nor the iPhone. Of course, my personal stance towards any iPod, especially the iPod Touch and the iPhone is to simply avoid the hardware and the lock-in that goes with it.

Last.fm

The biggest new feature users will notice is the Last.fm streaming plugin that Gabriel Burt wrote a few months ago. This plugin allows you to listen to Last.fm radio stations with all the love/ban glory expected from Last.fm clients.

We have opted to disable this plugin at runtime by default for now, but it is built by default and can easily be enabled through the plugins dialog. Gabriel has blogged in detail about this awesome new plugin.

Album Track Editing… now even easier… again

A couple of months ago I found myself in the position, yet again, of wanting to import a CD that didn’t have metadata in MusicBrainz. I have blogged about the excellent track editor in Banshee before, but I continue to want to improve it. Editing an entire album’s metadata can be a tedious task, but I think I have greatly simplified it yet again.

Now you can select a table or list (from a web site, for example) of track names for the album you are editing and paste the entire selection into the first “Title” field in the track editor. The selection will be parsed and applied to all of the tracks in the editor.

For example, I went to Amazon.com, found the album, selected all of the tracks, and pasted it into the first title entry in the Banshee track editor. I didn’t have to type any of the titles on the CD. I created a screencast of the entire process of filling in all of the album metadata manually. Slick, though it’s still of course always better if the metadata can be found in the first place via MusicBrainz.

Batch pasting titles into the track editor for an album
Screencast demoing the new batch title editing for albums without automatically resolved metadata. Ogg/Theora, 46 seconds, 3.2 MB.

With metadata on the mind, I should note that Banshee’s metadata services stack is very versatile and allows for any number of metadata providers. We have a few, including MusicBrainz, Rhapsody, and Amazon. However, the Amazon provider does not fetch metadata, it just downloads cover art (and same applies for the Rhapsody one). It would be really nice if someone provided a full Amazon provider (or Rhapsody) that used their web services API.

The problem with this however, for Amazon, is that it requires a developer key (at least it did in years past), and this is why we have never invested time into implementing one. Instead we just rely on MusicBrainz, and perform cover art downloads from Amazon if the MusicBrainz metadata has an associated ASIN.

Ugh, this song sucks!

Another minor little feature users may notice is a new “Play next song” button that shows up in the notification area bubbles. It’s quite nice when you’re listening to music in the background and a song you hate starts playing. Easy to skip without switching interfaces. Of course, if you have multimedia keys set up, I suppose that’s even easier.

Notification bubble allows skipping songs
Notification bubble allows skipping songs!

MTP

Alan McGovern has nearly completely rewritten our MTP support and we are close to enabling it by default. The next release should have solid MTP support, and we hope to roll 0.13.3 within the next two weeks. The new MTP support uses libmtp instead of libgphoto2. This decision was made for a number of reasons, though I am really not informed enough to convey them properly. Alan has blogged a bit about his changes and his reasons for switching libraries.

We encourage users to try the new MTP support in this release, but we do not want to see distributions packaging it at this time. To enable MTP support from source, pass --enable-mtp to configure. There are a handful of known issues with many MTP devices, and these will be addressed in 0.13.3. Nevertheless, we wanted to get something out the door.

Mono.Zeroconf

I blogged about my new Mono.Zeroconf library a few weeks ago, and this release of Banshee is the first to require it. It greatly simplifies zeroconf logic inside Banshee itself by allowing us to target only one API instead of two (Bonjour and Avahi). Only the DAAP plugin uses it, so if you do not wish to install Mono.Zeroconf, pass --disable-daap to configure.

Great, but what about the really cool stuff?

While 0.13.2 is a solid release with some exciting new features, the real goodies are in our unstable trunk. We have done a ton of work on trunk, rewriting Banshee nearly from the ground up. Performance improvements are massive, and we expect to have some sort of preview release out within the next two months. Now that we are winding down with this stable series, 0.13.2 is out the door, and winter holidays are over, we will be heads down on trunk, making great strides.

Expect lots of blogging in the coming months about details of trunk. In the mean time we have a high level roadmap that can be tracked. Stay tuned, because a lot of really exciting stuff is happening in the Banshee universe!

I started working on Mono/.NET bindings to Bonjour/mDNSResponder almost two years ago. The code was quite useful but we found ourselves adding a lot of nasty preprocessor directives — yes, in C# — and configure junk to support both Mono.Zeroconf (Bonjour) and Avahi in software like daap-sharp and Banshee.

Earlier this year I found some time to start finishing my grand goal for Mono.Zeroconf — to support both Avahi and Bonjour through a simple, unified API.

Say what, exactly?

Today Mono.Zeroconf provides an easy to use API that covers the most common operations for mDNS (Browsing, Publishing, full TXT record support). It works either against Avahi (via the avahi-sharp bindings) or Bonjour on Linux, Windows, and Mac.

If your application needs to be cross platform (or even just cross-distro if you’re concerned about targeting older Linux distros) and perform Zeroconf networking, Mono.Zeroconf is the library for you. On Windows, the Mono.Zeroconf binaries work under both Mono and .NET.

It should be noted that Mono.Zeroconf does not support many of the more advanced mDNS features that Avahi in particular exposes. It is an intersection of the most common operations supported by both Bonjour and Avahi.

If your application needs advanced mDNS features, you most likely will care about the mDNS provider that you actually use (and I hope you choose Avahi). Therefore, I do not expect the functionality of Mono.Zeroconf to expand much and the current API is considered stable and complete. I may however add domain enumeration support in the future if it becomes a requested feature.

And how do I use it?

There are a couple of C# examples on the Mono.Zeroconf page that show how to browse, resolve, and publish services through Mono.Zeroconf. Here’s a quick adapted example on how to browse:

using Mono.Zeroconf;
...
ServiceBrowser browser = new ServiceBrowser ();
browser.ServiceAdded += delegate (object o, ServiceBrowseEventArgs args) {
    Console.WriteLine ("Found Service: {0}", args.Service.Name);
    // Connect to args.Service.Resolved event
    // Call args.Service.Resolve ()
};
browser.Browse ("_daap._tcp", "local");

There is also a small command line utility included in Mono.Zeroconf called mzclient. This works much like the traditional Bonjour command line tool, but it’s slightly nicer in ways I don’t remember. The source code to mzclient is probably the best example on what Mono.Zeroconf can do and how to do it.

Monodoc API documentation is also available.

Where is it?

Mono.Zeroconf will be part of the tarball set for the next Mono release (1.2.7). It is a separately maintained project and not bound to the Mono release schedule, but the upstream sources will be available in the same place. Packages will also be available through official Mono repositories.

For now, I have released sources on the Banshee web site. Packages (noarch) are available through the wonderful openSUSE Build Service for openSUSE Factory, 10.3, 10.2, 10.1; SLE 10; and Fedora 6, 7, and 8.

Sebastian Dröge is pushing it into Debian and Ubuntu, so packages should be available there soon. Will Farrington is working on a Conary recipe for Foresight.

Mono.Zeroconf is of course available in Mono SVN:

$ svn co http://anonsvn.mono-project.com/source/trunk/Mono.Zeroconf

We are hard at work on the next generation of Banshee, and I’ll be posting details and juicy screencasts and screenshots soon. What I’m curious about now is what we should call Plugins in our UI. We use Mono.Addins in trunk now, and I have been thinking about renaming Plugins in the UI to something else, such as Extensions. My first thought was, “what does everyone else use?”

That wasn’t so helpful:

  • Banshee, Totem, gedit: Plugins
  • F-Spot, Epiphany, Firefox: Extensions
  • Tomboy: Add-ins

While this is just a small sampling of GNOME applications I thought of in 30 seconds, by far I think Tomboy loses. Add-ins, especially hyphenated, is weird. Note that Firefox seems to mix Extensions and Add-ons. Extra weird.

So the vote is between keeping it Plugins or switching to Extensions. I don’t care either way, but it would be nice to settle on some consistency within GNOME. Or maybe it doesn’t matter. Just a thought.

Some other names we have thought of include: Plugstensions, Bundleups, Snap-Ins, Snap-Ons, and snorp even recommended Butt-Plugs, but I don’t want to think too far into that one. I am sure Strap-Ons was in the running at some point too.

This is where you leave your €0.02. I hope it gets philosophical.

UPDATE: It seems like Extensions wins. Bugs filed against Totem, gedit, Rhythmbox, Tomboy, MonoDevelop, and Banshee. Other applications I’ve run across are already using Extensions, like F-Spot and Epiphany.

PodSleuth is a new project I started last May that aims to probe, identify, and expose properties and metadata bound to iPods. It obsoletes libipoddevice, which had the same goals, but due to many reasons ended up being a mess of spaghetti code and hacks due to effectively being obsoleted overnight about a year ago when Apple made a particular firmware release.

PodSleuth takes the many lessons learned from libipoddevice and evolutions of the iPod itself and implements hardware support in a more future proof, yet backwards compatible and easy to maintain way.

The Technical

The core of its design is platform independent, although PodSleuth in its current and complete form is most usable in the context of HAL. A HAL layer is provided that is used now in Banshee, and we would like to see other certain iPod libraries at least optionally support PodSleuth. This layer is implemented as a HAL callout. Because the callout runs as the same user as the HAL daemon (typically root), it is allowed to cleanly perform operations that were implemented as hacks in libipoddevice (like reading from SCSI code pages).

The metadata that PodSleuth collects is then merged into the HAL device as properties. Once the PodSleuth callout ends, HAL finishes probing the device and exposes the iPod on the Global Device List (GDL) where the mount daemon (i.e. gnome-volume-manager) will then mount the iPod in a manner accessible to the user session. The key here is that by the time the iPod is exposed on the GDL, all PodSleuth properties will have been merged into the device. This makes application and user session library support for PodSleuth properties very easy and straight forward. One need only check for org.podsleuth.version on the device to check if PodSleuth ran against the device. If that property exists, other properties will be available that expose iPod metadata.

if (device.PropertyExists ("org.podsleuth.version")) {
    // We have a PodSleuthed iPod, it's ok to expect
    // at least the minimum set of properties

    Console.WriteLine (String.Join (", ", device.GetPropertyStringList
        ("org.podsleuth.ipod.capabilities")));
}

One of the most important changes that affects the end user directly is that the iPod will always be supported based on metadata extracted from the plist file located in the SCSI code pages. This means that even if the iPod is not found in the model table, no functional limitations will be imposed. That is, the model table is now only purely cosmetic (for presenting things like shell color and the right icon). This is in contrast to earlier versions of libipoddevice.

Additionally, PodSleuth sets the info.icon property in HAL which means that once we get new icons for the new iPods and update the existing ones to follow the new required naming specification, the proper iPod icon will finally show up in Nautilus and elsewhere (provided you are running a recent enough GNOME). A cute thing indeed.

The Files

PodSleuth will see its first official release within the next week, alongside a new ipod-sharp release, and Banshee 0.13.2. All of these releases spell out support for new iPods (Classics and Nanos), so stay tuned. PodSleuth is developed in GNOME subversion under the podsleuth module.

The Unfortunately Political

The fun part is that PodSleuth is written in C# of course, a detail that I like to think doesn’t matter, but it certainly and most unfortunately offends many for various reasons. There are two lovely facts that I like to point out when opposition to my language of choice for this project arises:

  • Because PodSleuth is not used as a library, any application written in any language with HAL support can benefit from PodSleuth. I could have written PodSleuth in shell, and it would not affect applications wishing to support it.

    Furthermore, PodSleuth requires only the ECMA approved portions of Mono (which is a 100% open source project and has a strict policy to keep patented code out) and Mono.Posix (which is an open source library wrapping POSIX system calls). Therefore there are no patent concerns (although I know the facts don’t matter to the noisy zealots).

    What matters on the technical side of this point is that most modern distributions ship at least this core subset of Mono these days, so I feel the dependency argument falls apart here as well.

  • My favorite argument against PodSleuth because it is Mono-based comes from the crowd that hates Mono for unfounded political reasons, yet require free software support for their iPod.

    Let’s see, the iPod is closed hardware, proprietary software, contains DRM, supports proprietary formats (doesn’t even have any open format support), and just recently added a hashing mechanism against the primary track database to lock out third party clients. I’m not sure if I’ve ever come across a more proprietary device, yet this zealot crowd has the nerve to scream about Mono!

    This theme is unfortunately all too common in our community (”Oh, it’s OK to run a Mac! Just don’t use Windows! The Mac is shiny too!”).

    In response to this very argument a few days ago in the #banshee IRC channel and mocking what could be seen as a double standard, Jorge Castro quipped,

    “I value freedom so I refuse to use Mono, oh look, a new iPod!”

    So true, so sad. On a somewhat related topic, I recently looked at the APSL next to the Ms-PL. Now that’s funny.

The Bottom Line

There is no reason an application or library focused around iPods shouldn’t support PodSleuth. Regardless of political alignment, PodSleuth is designed in such a way to make it very easy to optionally support. Supporting it technically places zero dependencies on a library or application. If a distribution happens to provide PodSleuth, then why not take advantage of the properties that would be readily available to you? They’re just strings in HAL! If the properties exist, use them. If not, fall back to what you’re doing today.

Think of your users! There’s a very small majority of users out there who will actually care about what a PodSleuth is, let alone what it’s written in. They just want their iPod to work, and PodSleuth provides a very solid hardware metadata layer in a clean language and platform agnostic way. Of course, these users should already be using or are already using Banshee, which has provided this experience from the get-go.

People who care about the political issue and oppose the platform shouldn’t be using iPods anyway, lest they be hypocrites.

A couple of weeks ago I really started investing a lot of time into what will become the new Banshee. There are a few big goals for this effort, including a full client UI/services stack split, insane performance improvements, and greatly improved library management and playback support.

Banshee will be split into two core stacks: a “headless” services stack and the thick client UI stack (what one would traditionally call “Banshee”).

Headless Services

One of the biggest areas of focus for Banshee will soon be on platform integration and the ability to run different client UIs against Banshee’s core.

There will be a headless services stack, which will include the source manager (which in turn provides access to the library, playlists, and other sources) and the playback controller. Everything here will be exposed over D-Bus, and can be extended through Mono.Addins.

So for instance, F-Spot could integrate the Banshee library into its slide show functionality; PiTiVi could access the same to offer music to a user for video editing; Elisa could be extended to pull its content from Banshee; Joe’s Banshee Music Server will talk to this stack to serve a user their content from any browser in the world.

The services stack is highly efficient - serving data is extremely fast, and consumes very little memory - and yes, it’s running on Mono.

The Thick Client

Banshee’s primary UI won’t be changing too drastically, but there are some key things to note.

There will at last be a multi-select artist/album browser, even though I’m still not a fan of this feature. It is however the number one most requested feature. There will also be a play queue, which battles for the browser as the most requested feature.

Most importantly, I am dropping the GtkTreeView for our track view. The biggest problem in Banshee over the past two years has been the memory use and speed of the track view. This is because it is not possible to write custom tree models in Gtk# - which lacks GInterface support - and thus we have had to rely on the simple GtkListStore model. This is not good when you need to map directly to a database, for example. It requires loading everything from the database ahead of time, which means the startup time is O(N), and memory consumption the same.

Now, before you start jumping to conclusions or throwing out solutions to this problem that would still allow us to use the GtkTreeView, let me cover the available options:

  • Write the model in C, bind that. While this would work, it would mean we’d have to rely on a native library for Banshee (and I am trying to work away from libbanshee, which currently only does GStreamer work). Extending this model would be painful in the managed realm as well, as we really want this to be a strong extension point.
  • Fix Gtk# to support GInterfaces. Well this one is obvious. If Gtk# properly supported GInterfaces, I would have written a managed custom tree model long ago, but would then have been done with it. Read on, and I’ll tell you why I’m “glad” GInterfaces aren’t supported. However, this does seriously need to be fixed. It’s the biggest hole in our binding.
  • Use P/Invoke hacks to implement the custom model in C#. While possible, it’s quite ugly. It’s not so bad for simple models that aren’t meant to be reused, but when you need to implement sorting, filtering, drag and drop, and other features, this gets out of control quickly. It’s just a gross hack, not to be taken seriously. It says more for the native interop in Mono than anything else.

The solution? I started writing a new widget, similar to GtkTreeView, but only for lists at the moment. I have no intentions of supporting trees, as this widget is designed specifically with our Banshee needs in mind (but is meant to be used in other managed applications that need list-based data binding).

The first thing you will notice is that startup time is ridiculously fast. The view needs only to know two things from the model: a row count, and a method for fetching a row at an index. Simple.

Columns are managed by a ColumnController, which is not a part of the view (one of the things that irritates me about the GtkTreeView). Columns in the ColumnController provide cell renderers, much like those in core GTK. With this all pieced together, when a row comes into view, the model is queried. The object returned from the model is then used when the view iterates the columns in the ColumnController, which is then passed to each renderer for binding.

Objects returned by the model have attributes on either the class or its properties which binds them to certain columns. The renderer is then responsible for rendering the bound object or property thereof. Pretty simple, but wildly effective, and insanely fast.

Also, the width of the columns are percentage based, like ETable in Evolution. It’s slick. I hate horizontal scrolling. There is support for a minimum absolute width and completely fixed width columns.

I will save a more detailed technical overview for some developer doc on our Wiki. Now on to a screencast.

This first one shows the new view and browser operating on a very sane collection with a decent amount of cover art. But it’s not a very large collection and doesn’t do the performance of the view justice. It’s nice however. No comments on the music selection - this database was carefully crafted by hand from a collection of databases so I could have a “nice” database with full collections of albums and proper metadata - that is, it’s not mine!

Theora Screencast

This second one shows the startup performance. It really is O(1). However, sorting and filtering gets slow when you reach such a high value. With the use of indexes in sqlite and a cache table though, filtering and sorting works against the cache, not the primary tables, once an initial sort or filter is applied. That is, it gets faster as you narrow your results, as to be expected.

Theora Screencast

I don’t really think anyone has a million songs, but this new model/view can still cope, even if it is slightly sluggish. However, my goals for performance optimization are to be fast at 100k songs. I think that’s a pretty high average, and we’re almost there. Just some more SQL tuning and I think we’ll have it. The limitation currently is that sorting and filtering starts to get “sluggish” at about 75k rows on my machine.

Oh, and this database was generated by a tool I wrote yesterday that uses a dictionary to randomly create a music library. It came up with some rather interesting band names. Other projects might find it useful for performance testing.

I’ll close on this point just by leaving a few stats, all tests based on a 25,000 song database.

Old Banshee New Banshee
Startup Time 32 Seconds 0.8 Seconds
RSS Consumption 81 MB 8.5 MB

Now, these tests weren’t performed very scientifically, but the point is that the differences are so vast. What’s more is that the Old Banshee numbers are based off O(N) efficiency, while the New Banshee numbers are O(1) - the same startup time and memory consumption exists for the database with almost a million rows. It would probably take an hour or so to load that with Old Banshee, and I don’t think I have the memory for it.

Great, but where can I get this?

All of this work is being performed on a separate branch, currently called “list-view” in Banshee trunk. I do not recommend anyone use this new work yet, however. I can reasonably say that it will not munge your existing data, but it will migrate it into new tables.

There is still a lot of work to be done in the coming weeks, but I hope to merge this back into Banshee trunk proper sometime around GUADEC.

That is all for now.

  • Novell and EFF team on patent reform - Awesomeness

    “I think it’s fair to say that we’ve been talking a lot about patents within Novell in the last twelve months. More than we have in the past,” he said. Novell concluded that the patent system is broken and that patents are hobbling innovation and open standards, by putting companies on the defensive.
    –Nat Friedman

  • My good friend Jeff Tickle is working on an awesome Tomboy/Gtk# project called Virtual Paper, and has been making some wonderful progress. He could really use some expert Cairo advise regarding custom gradients on a stroke. I think Jeff should always blog from Virtual Paper itself and never again use the keyboard.

  • Late last week Miguel started white-boarding the drawing engine for Moonlight, and has made some progress since getting his canvas to draw a rectangle.

  • After a frantic brute-force apartment hunt in Boston last Thursday and Friday, I found a nice place in Kenmore/Back Bay, and will be moving out of my apartment in Raleigh at the end of next week. I’ll spend a week at my parents’ house visiting with family we have coming into town, and then will drive up to Boston on the 10th. I can’t wait!

  • I have been working on some major performance improvements in Banshee and will write more about this later. 0.13.x is going to be completely awesome and noticeably faster. Unfortunately I’ve spent so much time this month preparing for the move to Boston that I haven’t been able to spend as much time as I want hacking. The good thing is that I am in one of those mad-hacking moods where I stay up all night and get real work done. These come and go in cycles, and usually last a long time.

Banshee was rejected from the Summer of Code, as was GStreamer. I’ll just echo that having GStreamer rejected came as a bit of a surprise, and it would be nice to have some kind of justification. Some of the projects approved are rather “interesting” to say the least. I’m just curious as to what the selection criteria is, how selections are made, etc. Or maybe it’s not my place to wonder or care.

However, I have put a few of the more high-profile Banshee SoC ideas under Mono, and maybe one or two could go under GNOME as well - perhaps the more GStreamer related ones? Maybe there are already too many under GNOME? Maybe we’re not cool enough? I was hoping to put one or two under GStreamer’s SoC if Banshee was rejected - but we both lose! A little sad only because there were lots of existing Banshee contributor-students looking to hack on it with dedicated time this summer. I only applied because of their eagerness and community involvement.

If you have any exciting ideas not listed, we’re open to them, but the number of applications we can accept for Banshee under Mono will be limited compared to what we could have accepted if we were not rejected as our own organization.

Welcome to the second part of the “Things you may not know about Banshee” series of posts, where I highlight some cool features about Banshee that have been introduced in the 0.11.x series. I’m making up for all the blogging I haven’t done in the last 4-5 months.

Just before the GNOME Summit last year, I started working on a user friendly way to perform audio profile configuration. For example, selecting the desired bitrate for an MP3 stream. I had a few goals in mind at the time:

  1. Must be audio framework agnostic. Banshee supports both GStreamer and Helix, and this needs to work with both frameworks without any issues. The user should be able to configure profiles using the same interface and not know which audio framework will be doing the heavy lifting. Essentially, the audio profiles framework should not actually need to know anything about specific audio frameworks. Ever.

  2. Must provide a straight-forward, sensible user interface for configuring complex pipelines. The primary point here is that the user should never have to edit a raw pipeline. A user should not have to “know GStreamer” to change their desired encoding bitrate.

    The current GNOME audio profiles editor
    The current GNOME audio profiles editor :-(

  3. Multiple configurations should be supported on the same profile. Profiles are things like “MP3″, “Ogg Vorbis”, “FLAC”. The profile contains the pipeline and interface description. Configurations are sets of values that can be merged into and saved from a profile. This allows a user to configure a 128 Kbps MP3 encoding setting for their iPod and a 192 Kbps encoding setting for ripping CDs to their local library. Each configuration uses the same base profile, but its settings are different.

  4. Never show profiles that the user won’t be able to use. Not all users have the necessary components installed to be able to encode AAC or MP3 for example. Profiles for these formats should be provided, but if they won’t be able to run, they should not be shown. This means profiles should be tested against their default configuration values before ever presenting a user interface.

With all this in mind, I set out to write the beast. The user interface is defined in XML. Variables define a UI control type, possible values, etc. “Processes” are also defined in the XML with an audio framework ID, for instance “gstreamer.” For GStreamer, the process is the pipeline definition.

However, as of early this morning, the process definition is now an S-Expression. Before, it was simply a pipeline string that had $variables in it, which would be expanded based on the user configuration.

Since the GNOME Summit, I have been working with this profile stuff on and off. It’s been functional since Banshee 0.11.2 (a few months ago), but has been evolving in various ways since then. During this time it was clear that more expressiveness was needed for generating the actual process/pipeline definition. For example, in GStreamer if a user chooses to use VBR in LAME, the xingmux element should be added to the pipeline. However, xingmux is in gst-plugins-bad, and chances are not many users actually have xingmux. This means xingmux should only be appended to the pipeline if VBR is enabled and xingmux is actually available. Other reasons for needing more expressiveness are arguments for GStreamer elements that may be mutually exclusive. If I use mode X, I must provide arguments A and B but not C. If I use mode Y, I must provide arguments C but neither A nor B.

Last night I decided I needed to write an S-Expression evaluator to make this expressiveness a reality. 10 hours later, we now have SExpEngine, and it can do some really cool things. Functions are very easy to add to it and there are a number of built-in functions for logic, conditionals, comparisons, casting, arithmetic, and strings. It also supports variables, which can either be value types or a callback method that returns a tree.

I added a function to allow process S-Expressions to test sub-parts of a pipeline before merging it in to the resulting/final pipeline (think xingmux, from above). Additional GStreamer functionality can be added to build variations of a pipeline based on available elements, differences in GStreamer versions, etc. S-Expressions mean configurability (woo - fake words), reliability, and compatibility.

The result is something I’m quite happy with. For example, here is the S-Expression for the GStreamer LAME process:

+ "audioconvert ! "
"audio/x-raw-int,rate=" $sample_rate ",channels=" $channels " ! "
"audioconvert ! "

"lame mode=" $mode " "

(if (= $vbr_mode 0)
  (+ "bitrate=" $bitrate)
  (+ "vbr-mode=" $vbr_mode
    " vbr-quality=" (- 9 $vbr_quality)
    (if (gst-element-is-available "xingmux")
      " ! xingmux"
      ""
    )
  )
) 

(if (gst-element-is-available "id3v2mux")
  " ! id3v2mux"
  " ! id3mux"
)

To make sense of the variables, take a look at the full XML LAME profile..

Now, getting back to the “okay, why should I, as a user, care” side of things, I’ll close the post with a screencast (ooooh, fancy, I’ve never done one of these!) that shows all of the profile stuff in action. For the sake of also demoing how the S-Expression evaluates into a proper GStreamer pipeline, I ran Banshee in debug mode for most of the screencast, which shows a text view and a “Test S-Expr” button. Rest assured, if you’re running Banshee like a normal user, you’ll never see this part of the profile configuration dialog :-).

Banshee's audio profiles
What I hope one day can replace the GNOME audio profiles editor so applications other than Banshee can take advantage of the sweetness. Click the screenshot to watch the screencast. (Ogg/Theora).

I’m still working a lot of things out with this, but it’s my hopes to some day make this work outside of Banshee. It’s written with that in mind. At the very least, I’d like to make the XML profile and S-Expression format some kind of standard.

I spent the better part of today finally reorganizing the bulk of the source tree in Banshee. I’ve been blocking on the transition from GNOME CVS to Subversion for this moment, and things are now much more organized and clean.

A lot of the reorganization was motivated by wanting to get all of the Banshee components properly buildable in MonoDevelop, which is finally a reality. The only problem I had initially was getting Banshee to properly run from MonoDevelop. I knew this wouldn’t really be a possibility because running Banshee uninstalled requires a number of environment variables to be set, which overload where plugins and engines are loaded from, and set things like LD_LIBRARY_PATH and MONO_PATH.

Banseee running from MonoDevelop

Luckily, I’ve got some really nice build variables that come together to form all of this information, so it’s possible to simply execute ‘make run’ from src/. I decided to take advantage of this and created a MonoDevelopBootstrap project that simply creates a small Mono program:

using System;
using System.Diagnostics;

public class MonoDevelopBootstrap
{
    public static void Main()
    {
        Process process = Process.Start("make", "run");
        process.WaitForExit();
    }
}

Using the “Run” feature in MonoDevelop causes all projects in the master solution to properly build, and then MonoDevelopBootstrap will run, which in turn runs “make run” in src/. The end result is simply being able to press F5 in MonoDevelop to build and run Banshee. Hopefully this will only attract more contributors to the project, who aren’t used to dealing much with autotools.

There’s currently one drawback to this however - you can’t simply check Banshee out and build/run in MonoDevelop. You must run autogen/configure, as some files for the build are generated, and make needs to be run in ext/ and libbanshee/. ext/ has external dependencies that are bundled, and libbanshee is, well, a C library.

Next Page »