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 Support in GNOME… and Lightning!

So the last day or so has consisted of porting the lower-level iPod device detection code that I wrote in C# down to C so that it can be directly integrated into gnome-volume-manager. It’s all GObject/C, so I’ll be using GAPI2 to wrap the thing and merge it with the higher-level iPod code that will stay C#. By using C I managed to almost solve the problem of SCSI device ejection, because it can easily be done in C. What I didn’t take into account was that the eject program is SUID root. SCSI ejection will only work as root. In the end, it just left me execing ‘eject’, which is what I started with in C#. Go figure.

In other news, I was nearly struck by lightning twice today. I decided it was time to walk the dog just as it started pouring, thundering, and lightning. We didn’t care and started walking the trail through the woods around my neighborhood.

Ranger!

As soon as we got back onto the street and began to head home, an extremely close bolt of lightning struck the ground, probably no more than a block away. Everything was flushed white, and then almost instantly red, and immediately after that came extremely loud thunder. It was one of the coolest things I’ve ever seen. Needless to say, we started walking faster! About a block from the house and another really close bolt struck somewhere nearby – not as close as the first, but everything was flushed white again, but no red.

We got back inside, dried off, and I moved from upstairs to the screen porch to continue working. How relaxing.

I wish I had brought the camera with me… I don’t know how it would have happened, but it would have been awesome to catch the lightning on camera. Speaking of the camera, I need to take more photos in general. That picture of Ranger is from two years ago, I do believe!

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!