entagged-sharp vs. GStreamer

I finished rolling entagged-sharp into Sonance today after doing some more API work on entagged-sharp, thus replacing GStreamer for metadata collection. Sonance uses a metadata parser to collect metadata for songs not in its database. I deleted my library, and asked Sonance to import 4086 files. entagged-sharp processed 3920, which is… 100% of all the audio files in the group of 4086 files (most of the remaining files were JPEG album covers). GStreamer on the other hand, processed only 3777 of the 4086. However, this is because the differing 143 audio files were AAC, and I don’t have gstreamer-faad installed. So no hard feelings on GStreamer for coming in second on the count.

However! Entagged processed all 3920 files in 12 minutes and 11 seconds. GStreamer on the other hand only processed 3777 files… in 19 minutes and 33 seconds!

Entagged: 731 s / 3920 songs = .186 s / song
GStreamer: 1173 s / 3777 songs = .311 s / song
Winner: Entagged! Over 1.67 times faster!

Not only are there performance benefits with Entagged, it’s just easier to use. There are no dependencies! It’s pure C#, relying only on core .NET classes. It’s potentially easier to deal with from a legal standpoint as well. And what I’m really looking forward to, is that entagged-sharp has tons of room for optimization.

The tests weren’t too scientific, but I did make sure to be running only Sonance, and left the computer alone during the entire import for both tests. Also, I rebooted each time to flush everything out and be fair. For the curious, the tests were done on a T40p IBM ThinkPad, with a 1.6GHz processor (throttled to about 1GHz during the tests), and 1GB of RAM.

Also, I added basic MP4/AAC support to entagged-sharp two nights ago. The parser does not yet parse encoding/channel/stream information – just metadata. So if anyone knows a bit about MP4 and would like to contribute to the MP4 parser, it would be much appreciated! Please contact me if you’re interested. All I know is that the informtaion is in the MVHD (I think?) container, and I don’t have the time right now (nor will I for a while) to research this.

Update:

Furthermore, since this post is somewhat related to another Sonance timing test, I am happy to report that loading all 3920 files directly from the library (no file system intervention) takes only 2.5 seconds for the initial read from the SQL DB, and waaayyy under 1 second to reload the cached audio objects after the SQL DB read. I’m pretty happy with this improvement :)

entagged-sharp, ipod-sharp, g-v-m

The last couple of weeks have been so busy, and have really flown by. It’s amazing how things are coming together with Sonance and related projects. There are two in particular that I’d like to mention. ipod-sharp, started by Snorp, is full a C# library to bring iPod support to GNOME/Mono. It is going to be a key part of Sonance. What’s of equal importance is the re-licensing of entagged-sharp (a C# port of the Java Entagged project) to the MIT license. I am working with Raphael Slinckx, the lead developer, to make entagged-sharp the audio metadata solution for Mono.

entagged-sharp is as of yesterday available from Mono SVN (entagged-sharp). The initial import featured a new build system, and some general cleaning of the code. Tonight I started on a cleaner, friendlier API front end to the Entagged library (AudioFileWrapper), that makes it much easier to use, and feels less like Java. If you wish to use entagged-sharp in your Mono application, it is highly recommended that you use the AudioFileWrapper class. This class will continue to be expanded until all of the Entagged features are exposed in a much saner, cleaner way, and other internal optimizations will follow. I would just like to thank Raphael for his eager support. I should also mention that entagged-sharp has no dependencies other than core .NET, and currently provides metadata/encoding information for APE, MPC, MP3, OGG, and FLAC formats. AAC is on the way, and hopefully ASF/WMA.

Back to ipod-sharp. Basically, this is going to rock. Snorp already has iTunes music database support (read/write), and we have been working together to first bring lower-level device support to ipod-sharp as well. A few weeks ago I started writing libipoddevice (available from GNOME CVS… at least when the servers are back up :-D), which provides lower-level device information and control (safe ejection!) through HAL and a number of custom functions that support the formats on the iPod. libipoddevice exposes lots of details about an iPod, including the user-assigned name (“Aaron’s Photo iPod” instead of “AARON’S IPO”), the volume name, the type of iPod (Photo, Regular, Mini, Shuffle), the volume size, the amount of free space, and much more. Snorp has written very nice bindings to libipoddevice in ipod-sharp. In the weeks and months to come, expect to see photo (thanks to Larry Ewing) and cover art support in ipod-sharp. I should also mention that Snorp has written a more useful test case for ipod-sharp that actually allows you to sync your iPod, called Dopi.

Edd Dumbill has written Monopod, which will probably use ipod-sharp at some point, as well as entagged-sharp.

I also can’t not mention fejj’s work in gnome-volume-manager to bring iPod support directly to GNOME. I’ve been working with fejj on isolating iPod/HAL issues, and getting it to just work. This is going to rock: plug in your iPod, automatically manage your music and your photos, with one or no clicks.

I’ve got some other iPod related GNOME ideas, which I may bring up in a later post. Myself and others basically want to see GNOME seamlessly support the iPod through a number of applications. Realizing this is not far off… not far off at all. The next few months are going to be exciting times.

Finally, I just finished listening to the entire 3+ hour talk at the Massachusetts Software Council that Nat mentioned in his blog today. Both he and Miguel were the presenters in the third segment. I found the entire thing immensely informative and at many points, entertaining. I recommend listening to all segments, and follow along with Nat’s PDF presentation during the third segment.

Major Update! entagged-sharp now with M4A/AAC support!

Yes, that’s right, a mere 4.5 hours after the initial post of this entry, I have added basic M4A/AAC support to entagged-sharp. I still need to write an InfoReader that reads stream/encoding information, but the metadata reader is pretty much complete. I’d like to thank Geoff Norton (kangaroo) for the base metadata parser, implemented in src/M4a/Util/M4aTagReader.cs.

Everyone is rushing to svn co, right?

iPod Work

I started working on a generic iPod device class that provides lots of information about the iPod and will work with Snorp’s ipod-sharp. It provides things like the name of the iPod (not the volume name, but the assigned name), the model/type (shuffle, regular, mini, photo), version info, serial numbers, capacity, used space, etc. It also supports safe ejection of the iPod. Initially I was doing this by just calling ‘eject’ on the device.

However, I decided I’d try doing this by making an ioctl call on the device. Not giving much thought to it, I came up with a few lines of code to eject a CD-ROM drive. It didn’t dawn on me until after the CD ejection code was working that the iPod is not a CD-ROM drive (it’s okay, you can smack me). It needs to be ejected as a SCSI device. The ioctl call[s] for this task are much more complicated (a structure must be passed to the device instead of a plain integer), and I’m not sure how to do this easily in C#. I’m not sure that it’s even worth it, and will probably go back to just execing ‘eject.’

Anyway, if anyone wants to eject a CD-ROM drive in C#, here you go. This may be useful for making basic ioctls in C# for other reasons. I’ve never seen an example of ioctl from C#, so maybe this is new.

<br /> using System;<br /> using System.Runtime.InteropServices;<br /> using Mono.Unix;</p> <p>public class SimpleEject<br /> {<br /> public static void Main(string [] args)<br /> {<br /> if(args.Length &lt;= 0) {<br /> Console.WriteLine(&#8220;Usage: mono-eject.exe [-t] <device>&#8220;);<br /> return;<br /> }</p> <p> string device = args[0];<br /> bool open = true;</p> <p> if(args.Length > 1 &#038;&#038; args[0].Equals(&#8220;-t&#8221;)) {<br /> device = args[1];<br /> open = false;<br /> }</p> <p> Console.WriteLine(Eject(device, open)<br /> ? String.Format(&#8220;Device {0} {1} successfully&#8221;, device,<br /> open ? &#8220;opened&#8221; : &#8220;closed&#8221;)<br /> : &#8220;Error ejecting device &#8221; + device);<br /> }</p> <p> [DllImport(&#8220;libc&#8221;)]<br /> static extern int ioctl(int device, EjectOperation request); </p> <p> private enum EjectOperation {<br /> Open = 0x5309,<br /> Close = 0x5319<br /> }</p> <p> public static bool Eject(string devicePath, bool open)<br /> {<br /> try {<br /> using(UnixStream stream = UnixFile.Open(devicePath,<br /> OpenFlags.O_RDONLY | OpenFlags.O_NONBLOCK)) {<br /> return ioctl(stream.Handle, open<br /> ? EjectOperation.Open<br /> : EjectOperation.Close) == 0;<br /> }<br /> } catch {<br /> return false;<br /> }<br /> }<br /> }<br /> </device>

And with that we have a simple Mono eject replacement for basic opening/closing CD-ROM trays. Woo-hoo!

Smooth Music and the LTM

It’s been a while since the last entry, but at least I’ve been up to some good. There have been some exciting happenings regarding Sonance, too numerous and exciting to post here, right now. However, lately I’ve been enjoying iTunes while developing Sonance. I now have an iPod, and am loving it – but it’s not just for play. Currently I am performing five concurrent tasks in iTunes, and am happy to say that Sonance’s backend is ready to handle the same tasks soon. All at once I am Ripping a CD, Importing music to the iPod, Downloading purchased music, Burning a CD, and listening to music. This task load started as me re-ripping most of my CD collection to AAC (vs OGG) in order to actually have content to fill the iPod. In many ways this is a shame – I’ve been using OGG for years, and the only reason to drop it is because the iPod doesn’t support it, and that really needs to change.

Anyway, Sonance handles all of its extensive IO tasks with no lag in the interface at all, like iTunes. This is due to the Library Transaction Manager (LTM). IO tasks are handled through Library Transactions, all which extend a base class, so the LTM can manage the actual transactions. Transactions of the same type cannot be executed concurrently, and are therefore executed in a queue (For instance, you couldn’t burn two CDs at once). However, transactions that are not of the same type can be executed concurrently (I can import, burn, rip, and listen all at once). Additionally, the LTM provides access to the top-most transaction (usually the last transaction initiated), and then an array of the top-most transactions of each type. The interface can then query each transaction for status information. This allows the UI to provide status pages like iTunes – the top-most transaction’s status is displayed first, with the option of cycling to other transactions.

Development for Sonance over the next three months is going to be extremely exciting. A few major target features are iPod support, CD Burning, and CD Ripping. More details on this are soon to follow, when I can find a spare moment.

In somewhat other news, I’ve implemented a nice test case for all sorts of common Drag-n-Drop functionality desired for GtkTreeViews, including multi-row DnD, drag reordering, drop between rows, and drop on a row (both vs. the default drop between or on). This functionality will be included in Sonance, but I wanted to iron out a test case for other projects and make sure the code might not suffer from unrelated factors. I’ll make this available when it’s a little more polished off, and I have another spare moment.

F-Spot, Server Monitoring, ASP.NET, and Crazy Dancing

Today I relaxed a little bit and decided to organize ~/Photos, which has been an all purpose photo dumping grounds for the last year or so. I don’t take many photos, mainly because I have a horrible 2MP camera with awful focus and lighting, so I only had about 400 photos to organize. I built F-Spot for the first time today, and am extremely impressed. However, I did this after manually cropping and rotating about 80 photos using The Gimp. I am extremely impressed with F-Spot – it makes me even more inclined to finally purchase a nice camera.

I love the simple photo touch up tools and the fact that it doesn’t overwrite the original, and of course tagging photos like “Favorites.” The timeline widget is amazing – too bad only a few of my images have EXIF information, because about 90% of my photos, as reported by F-Spot, were taken today, when I copied many of them to a new location. Not much can be done about that I guess.

Anywhoo, I started writing a simple standalone HTTP server in C# today to serve status information regarding the health of my server and its applications and services. It is made up of a simple multi-threaded HTTP server that sends XML “ResponsePackets” containing status information (like uptime, system load, process listings, whether a given service is actually running, memory usage, etc). Each ResponsePacket is handled in code by extending a base ResponseHandler class. These extended classes are then registered with the server at startup in a Hashtable. When a client sends a GET request in the form of “/a:b:c”, “a”, “b”, “c” are parsed out and used to look up the proper ResponseHandler to execute. It’s kinda nifty. I’ll write a simple front end client for it that can email and text message my phone if/when a service goes down.

Of course I’ll release the whole thing in a few weeks when it actually becomes useful.

I also finally managed to build Mono 1.1.7 under my Linode UML server. Before today, Mono would segfault and/or throw a NullReferenceException during compile of mcs. I found out today that it was TLS that was causing the problem, as it’s not well supported under UML. All is well, and I now have mod_mono setup and working, and I look forward to learning ASP.NET (I never thought I would say that!)

Finally, last week I went to my brother’s talent show at his high school. Per his request, I brought my video camera, and recorded most of the show. Some of it was rather amusing, and I think I may put parts of the show on my web site. I’ve started with Shay-Shay. Enjoy!

Modern Music Management Experience: In Linux

With Sonance gaining much attention, and development gaining steady ground (though sometimes slow, due to trumping obligations that pay my bills), it is starting to unfold into a more modern environment for managing and playing music.

I am overjoyed with how well Jon Lech Johansen’s SharpMusique works. I purchased my first song through it today. Beautiful. There are plans to integrate it into Sonance for the ultimate music experience yet to be seen under Linux. I can’t wait until I can search for new music in iTms, purchase it, and have it appear shortly thereafter in my Sonance library. Yes, it is sick.

I made an SVN commit today that shows off some of the new functionality/widgets in Sonance, but I’m sure I’ve broken somethings, specifically adding tracks to a playlist. The next SVN commit will be more pleasing and feature complete. After a few more SVN commits, the next public release will be available.

One snag though, regarding which I am rather upset. It appears that you can’t drag-n-drop multiple selected rows in a Gtk.TreeView. This is upsetting because to add new songs to a playlist from the library, I wanted to be able to select them, and drag them onto a playlist in the sources TreeView. Apparently the problem is in GTK, not gtk-sharp. I read there is a hack for the problem in egg, so I’ll investigate that, and see what I can do. It’ll need to be wrapped, which is annoying. It seems like this should be supported in GTK itself. If I am misinformed, or if anyone has suggestions, I’d be glad to hear them!

Change of Sonance Plans

After a few posts about Remix (now named Sonance), and getting ready for the first public release, I had a sudden life changing experience as a developer. I discoverd development under Mono. After quickly learning C# and exploring the .NET libraries and the GNOME/GTK bindings for Mono, I wrote a few test programs, and started rewiriting/porting Sonance to C#. Amazingly, the power of the language and bindings are allowing me to more efficiently develop Sonance, and in much less time. In just one week, I have re-developed Sonance with less code, to the same point that the C version was developed in about a month.

The major struggle was the lack of good documentation on the GStreamer bindings for C#, gst-sharp. I have been able to find about three gst-sharp applications. And honestly, and with no disrespect to their developers, their implementations are not very solid, nor featurefull. So in addition to porting Sonance, and developing a much better code base, I have developed a strong gst-sharp player with metadata support.

I am really excited about the rewrite, and new beginnings with the Mono platform. I still love C, but welcome the ease and power of this new platform. It is clearly the new path for GNOME, and I am glad to be a part of it.