Sunday, November 22, 2009

txamqp vs the java amqp client

Whew, what a difference.

I did some benchmarking with a modified version (not modified for performance) of the java amqp client (for rabbitmq) and txamqp. Man is it a world of hurt for txamqp.
I get a sustained 33k/sec msg rate with the java amqp client and there's some poor code in there which could use some hashtables. This is for the consumer program which I describe below.
The better setup I have in txamqp though only is about 1k/sec for the consumer program... a pretty huge difference.
Both clients are doing the same work - the benchmark consists of two programs for each client: a producer and consumer.
Producers produce a small json object built from the library - it contains some random data per object so we always have to make/serialize a new object.
Consumers register a consumer to a queue and parse the json object for each message and then explicitly basic-ack the message has been processed.

Each is done as fast as possible with the rabbitmq (1.7.0) running completely in ram (no swap). However each is also done at a different time to assure that only one is executing at a time. I do it in bursts of 100k msgs. And finally, both version's producer's are faster than the consumer.
but again it's hugely in the java client's favor. 350 msecs to send 100k msgs. It takes about 20 seconds for the same workload with txamqp.

Here's hoping there's an improvement - I did some profiling though and couldn't figure anything in particular except maybe txamqp's codec implementation. Profile file here:

Wednesday, October 14, 2009

qpaeq dynamic band subdivision

So heres a slick little feature to qpaeq you aren't likely to find in any other equalizer out there... simply widen the window and watch the magic happen.

Normal - this is the default number of bands available in most equalizers

A little more...

a little bit mooore...

and here's the widest I've ever made it

Notice that this still all has an octave feel to it. You get diminishing returns with that - all you've got to do is change the DEFAULT_FREQS in the though, preferably to something linear. I'll make a linear bands an option in the future (along with the default of octaves) - it's useful for my own purposes as I explain below.

Why did I do this? Elementary my dear Watson - hand crafted notch filters, that's why! I've got a bunch of songs with horrible noise in them that I can never find the frequency the noise belongs to - this makes it only a few minute ordeal and I've gotten results much better than audacity's stuff in less time. Oh and it just looks cool - go get qpaeq and try it out - it's nice and interactive while you stretch and shrink.

One of these days I'll try and record filtered audio (not too hard thanks to pulseaudio and monitors) to show people the difference equalization can make.

Oh, btw - I'm finally in pulseaudio mainline. You can also get qpaeq in releasish form here:

Configuring redmine to be your all in one project manager

Well, it was a lot of work (when I did it the first time), but it could have been worse. The goal was to take redmine's user/group information and tie it into the sourcecode management stuff with all the groups preserved. There are recipes for subversion integration of this kind and this was a great base, but not only was this subversion only, I didn't like that a magic script ran every x minutes to create repositories that didn't exist. But I used all of the stuff up to and including the mysql auth stuff. So follow that tutorial first and break off when you've completed mysql nss/pam configuration. A word of warning btw, I tried to make this stuff as secure as possible, but I could not do everything needed without resorting to two very careful entries in the /etc/sudoers file.

I should also point out that you probably will want to run redmine as a system user. I created a redmine user for this and wrote an appropriate configuration for lighttpd. I also made redmine work over HTTPS, but this is something googleable. From here on out, it's assumed that the redmine user exists and is whom redmine runs as.

Lets configure and take a look at the environment.

Perform the following actions as root.
mkdir /home/redmineusers
chown -R root:root /home/redmineusers
cd /home/redmineusers
mkdir bin projects
chown -R root:root bin
chown -R redmine:root projects

After following the above tutorial, make a change to the shell_column property:
users.shell_column = "/bin/rbash";
users.homedir_column = "/home/redmineusers/";

umask 0007
export PATH=$HOME/bin/
There are symbolics links from .bashrc and .bash_login. This seemed necessary for ssh to work ok with the environment.

SRVSTRING="^-R projects/[a-z0-9-]+ serve --stdio$"
export PATH=/bin:/usr/bin:$PATH
CWD="$(dirname "$PWD/")/$(basename "$PWD/")"
HOME="$(dirname "$HOME/")/$(basename "$HOME/")"
if [[ $CWD == $HOME && $@ =~ $SRVSTRING ]]
/usr/bin/hg -R "$2" serve --stdio
if [[ $? == 0 ]]
/usr/bin/sudo /usr/local/bin/fixrepoperms "$2" 2>/dev/null
exit 0
exit 1
exit 1
Make a symbolic link in /home/redmineusers/bin/hg -> /usr/local/bin/hg.wrapper

#RE="^[a-zA-Z0-9 ]+$"
if [[ $1 =~ $RE ]]
/usr/bin/hg init "$1"
chown -R redmine:"$1" "$1"
chmod -R o-rwx "$1"
find "$1" -type d -exec chmod a+s "{}" ";"
chmod -R g+rw "$1"

#RE="^[a-zA-Z0-9 ]+$"
export PATH=/bin:/usr/bin:$PATH
CWD="$(dirname "$PWD/")/$(basename "$PWD/")"
HOME="$(dirname "$HOME/")/$(basename "$HOME/")"
if [[ $CWD == $HOME && $@ =~ $RE ]]
prj=`basename "$1"`
chown -R redmine:"$prj" "$1"
chmod -R o-rwx "$1"
find "$1" -type d -exec chmod a+s "{}" ";"
chmod -R g+rw "$1"
And now two additions to to your /etc/sudoers:
redmine ALL = NOPASSWD: /usr/local/bin/createrepo
ALL ALL = NOPASSWD: /usr/local/bin/fixrepoperms
And now you apply a patch. Its dirtyish code but it works ok and is much cleaner than things I've seen in the past for this stuff - for instance when you create your project, you won't have to wait x minutes for the repo to show up!

Index: app/controllers/projects_controller.rb
--- app/controllers/projects_controller.rb (revision 2924)
+++ app/controllers/projects_controller.rb (working copy)
@@ -74,6 +74,13 @@
@project.enabled_module_names = Redmine::AccessControl.available_project_modules
@project.enabled_module_names = params[:enabled_modules]
+ r = Repository.factory("Mercurial",:root_url => "/home/redmineusers/projects/#{@project.identifier}",
+ :url => "/home/redmineusers/projects/#{@project.identifier}")
+ @project.repository = r
+ g ={ "lastname" => @project.identifier} ) #blidly create a new accompanying group
+ gr = Role.givable.find_by_name("Developer")
+ gm = => g, :roles => [gr], :project => @project)
+ @project.members << m =""> User.current, :roles => [r])
@project.members << controller =""> 'projects', :action => 'settings', :id => @project

def copy
Index: extra/svn/create_views.sql
--- extra/svn/create_views.sql (revision 2924)
+++ extra/svn/create_views.sql (working copy)
@@ -13,7 +13,7 @@
from projects;

-select login AS username, CONCAT_WS(' ', firstname, lastname) as realname, (id + 5000) AS uid, 'x' AS password
+select login AS username, CONCAT_WS(' ', firstname, lastname) as realname, (id + 5000) AS uid, 'x' AS password,
from users
where status = 1;
Make sure you rerun the create_views.sql script. It should rerun just fine and now users have to be active rather than just exist.

If you've completed the above, congratulations. You now have a secure, private sandboxed environment for every project (in which you're protected by good old unix permissions) that is tied to your redmine user/group database. Each project gets it's own group on creation and you must add developers to this group to get sourcecode management access. You also have a secured / restricted environment for users to ssh into - but really only as a gateway to hg serve. You should be able to configure this to your needs for your flavor of SCM. Redmine should also have your repository entered upon project creation (it seems you must make a commit though before it looks like it works, this is understandable).

project management - the FOSS choices

Long time no post. Well, I've recently had to come up with a sourcecode management system, one which would work well for a growing buisiness. I took to researching the available options and here is a summary of my results. I checked out many options, but mainly two came out on top (and the only two I have time give a blog based comparison to).
  • Trac
  • Redmine
Trac is well known and quite good if you've only got one project. But given it's limitation's, it's had many offshoots now. Officially, trac is only subversion, but things are changing and branched projects exist for using git at least. Of keen interest though is that while there is a issue/ticket tracking system - there is only support for one project. There is a goal to change this in the future but we're all in the here and now.

Redmine, though. Here's the underdog. I mean who's heard of it, right? It's built on ruby on rails, if you care about that. For me, given prior knowledge of similar frameworks, that made it pretty easy to hop in and get some interesting things done, in a more proper way than the typical alternatives (these still are hackish things though). I'll go into those changes next post. But there's a few great features up for consideration that are built in to redmine:
  • Built in non hackish support for multiple projects and the management framework for users/groups.
  • tickets are cross project (after the option is clicked in the admin settings)
  • support for most any SCM (mercurial, git, bzr, subversion) out there
Now of considerable importance to me was mercurial. I view mercurial/git/bzr as mostly equivilent but their crossplatform support is anything but. mercurial has tortoisehg for the non cli window users though and works without a hitch other places though and thus is my SCM of choice for a business environment. What's that, why not subversion? Subversion, while useable sucks. The master repo goes down, well guess what - you can't check in your changes or have a VCS until its back up. Alternatively, this means you can work locally without having inet or being connected to that master server. Additionally, there's no tree support - this kills parallel development by multiple users. Well anyway, to recap -
I was motivated to find project management software which handled multiple projects, had ticket tracking, and SCM integration (focusing on mercurial) with users/groups working as expected all throughout the stack. I didn't find a complete and ready solution, but I got very close, and I'd be interested if anyone found something better. Until then, I thank the redmine crew, they've made an excellent system.

Wednesday, September 2, 2009

single disk backups and splitting the songs... such a pain

Ever backup a cd and find that you ripped it as one freaking file? Yes, I've been there and done that. It's a real pain to get the files to sane names and preserve the metadata on the cue sheet. So I found this blog entry, which works almost ok . I'm surprised it even handles a few formats. But guess what? The whole freaking thing FAILS at spaces and anything beyond basic ascii? Why oh why do people insist on using bash for these things? The end product is always so quirky. But you know what? I'm stepping up to this. I've already created the audiomap project with similar goals in mind. And now I'm expanding my bullcrap free softwares to include tagrename: a program which renames files based on their metadata and format strings. I'd like to expand it a little more in terms of the formatting strings (I whipped up this guy in about a half hour), but it's quite usable right now.

It accepts format strings.. use like:
./tagrename.rb -f "%track - %title" *.flac -v

Get help like:
./tagrename.rb -h

(with all possible tag properties title,artist,album,comment,genre,year,track). Tags can properties can even appear multiple times if that is your thing. I will try to include printf like formatting for numbers in the future. As usual though, any audio format is supported with no variance in behavior. Get your menial tasks done and be on your way with your life.

Sorry to those who only know how to use GUIs. I might add utilities to guitize my programs in the future, but for now you're on your own.

ps. If the file is not in the release copies, go check git, I may not have packaged it yet.

Tuesday, August 25, 2009


Palm pre/webOS is an interesting new platform, I've gotten a look at the emulator recently and I must say I like most of the tools out of the box more than android. Configs are in json and javascript/html is the main development environment (with css for themeing). I particularly like json because it avoids xml hell involved with many java projects who choose to abuse it. Anywho, I now know how webOS got it's name. Kudos to palm, this should also be one of the fastest/easiest platforms (graphics/reactivity seems to say that alone) but they can take advantage of the javascript engine wars (dalvik can often be terribly slow, it was a big mistake IMHO on android, they should've stuck with mono). One thing that weirded me out about the SDK for webOS though was official support only for ubuntu i386 linux (among macos/windows). Thankfully it worked without a hitch on opensuse x86_64 (they should really let people know it works great when not using ubuntu or even i386 for that matter! also virtualpc 3.0 as opposed to 2.2) but when I tried it inside qemu of 32bit ubuntu 9.04, the virtualpc emulator is uses seems to have problems and dies right after grub is loaded. It turns out qemu (with kvm acceleration) and virtualpc (uses something along those lines) are mutually exclusive. But you won't get the nice helpful error message if you try running it inside of the emulator... you will just get a black screen right after grub. I hope others don't make the same mistake, this cost me quite a few hours the other day to find the cause for such a stupid little thing. Why should emulators using kvm or whatever be mutually exclusive or not run within each-other...? Whatever, up next: pqaeq, the pulse audio equalizer front-end.

Thursday, August 20, 2009

another new old project posted

exploder: uniform simple and sane unarchiving
Handles even passwords and make's sure to always put the resultant files in a subdirectory so your home never gets polluted again.

Tuesday, August 18, 2009


New project! audiomap: Bullcrap free audio conversion. I say new but I actually finished it over a year ago. Cheers.

Wednesday, August 12, 2009

Composition over Inheritance: The functional approach to GUI Programming

Ever program with a GUI toolkit? Far too many classes and inheritance for some of the small tasks, right? This is especially true of event handlers meaning this isn't just GUIs though, it's any type of FSM (Finite State Machine) setup. The problem is that the event callback has to do some randomly scoped work that the actual FSM code can't be designed to handle easily.

So there are two approaches taken:

  • Event handlers are a function that takes a pointer and a userdata struct (this approach is often taken in c/c++).
  • Event handlers are an object which implements an interface (an adapter/wrapper class).

The second approach is the one Java often takes. It's painful and you will usually get buried under many trivial classes (inner-anonymous or implemented in their own separate file) and syntax. This is a large barrier and makes a simple problem more complicated. I prefer a solution closer to the first, but the way it is typically implemented is still wrong! There is almost just as much syntax wasted what with creating the function somewhere else in the code and declaring, packing, and unpacking each of these userdata structs. It's just ugly. It doesn't need to be so bad though.

Essentially, one needs to gain an insight of what information the callback actually needs access to. These would be the fields in your userdata struct or what the adaptor classes access from the instantiating class. This tends to be the entire class (if applicable), one or two parameters, or nothing at all. An FSM model really just wants to do the following:
If condition x, perform callback y
That's pretty much the conceptual for every given state/node for all pairs (x,y) of condition/callbacks each respective node contains. Simple right? Well, we just need to get back to our conceptual roots. Enter partials or currying from the functional languages to make that possible.
You might have heard of lambdas or anonymous functions before. Often one must use these to get away with partial function application if not in a purely function language. Languages like Python, Ruby (blocks too), lisp, haskell, and even Matlab all have these in one form or another. Some like, python, can make it a little more tricky to use partials than it should be but a fairly natural way exists. Now Python (and thus also Ruby, to some degree) are going to be the focus of the rest of this entry because these languages have bindings to every GUI toolkit known to man. They are also dubbed RAD (Rapid Application Development) or prototyping languages because how fast one might implement a fairly complex program.

Ruby implements this a little more correctly so not much needs to be said there other than an example like this:
def multiply(x, y); x * y; end
multiply_by_z = lambda { |x| multiply(z,x) }
In python, we can get away with this like the following:
from functools import partial
def multiply(x,y): return x*y
Now here's how to code less when hooking things up in FSMs and thus GUIs. Remember how we really were going through a roundabout way of just saving/packing parameters so that we could use them later in a callback for an event? Well, now you just make your function up or perform your adaptive-behavior in a simple lambda (if applicable) or nested function (this part isn't that new except in languages such as Ruby/Python you have nested functions which allow you to put the callback right where it makes sense and possibly not making you name mundane things which are obvious like the multiply above). Ruby automatically saves the arguments you've specified in the function call already and in python you wrap them with a partial object. So now when you hand the callback to your FSM model addEventOnCondition(callback()) or addEventOn(condition(), callback()) methods you will notice that on the FSM side, you only need to take void/no argument functions! The callbacks already have had their arguments set, they just haven't been called yet. This simplifies the FSM code as well as gets rid of all those userdata struct classes. There is also no need for any adapter classes. The FSM classes implement just what they conceptually need. Functions/Event callbacks are handed just what they need before their actual application, right where you have the most natural access to them. The syntax barrier is low. The code is short and as close as currently possible to the ideal. This all translates into less effort spent and less bugs to deal with.

Using partials/currying makes sense. I encourage every programmer to try and use these constructs, it's staggering how much they can simplify your designs. Bonus points if you start using map/each instead of writing for-loops all the time.

Wiki for the equalizer

Here I've you can run make install at the moment you're fine unless you're using opensuse factory. I'll try to whip up those ubuntu packages soon.

Equalization Abound!

Alright so I promised a post on equalization, but first I'm going to discuss a bit of theatricals. Many people have heard of equalization but most probably don't have a very good idea of what it really does. You see most speakers don't respond to all frequencies of music/sound ideally and so the equalizer provides a way to amplify/attenuate the frequencies that don't do well so that they then play to our ears ideally. As one might imagine, there's more than one way one can do this. But the method implemented is all about tradeoffs. Audiophiles listen up:
  • Analog
  • Digital - IIR (Infinite Impulse Response)
  • Digital - FIR (Finite Impulse Response)
Now I'm not an analog electronics expert/novice (yet!) but I do know analog is very tricky and nothing works exactly the way you want it to, you will always have non-linear side-effects. Not to mention you need to buy some expensive equipment to get analog filtering stuff or be an expert yourself. If you want cheap and practical (and experts agree, even best performing!) go with digital. But here you have a choice. IIR, much like analog, has some unwanted side effects.
IIR pros:
  • Low latency
  • Little computing power necessary (for where it will run at least)
IIR cons:
  • need very high precision (floats/single precision barely cut it) or things get unstable
  • Tough to design = hard to reconfigure
  • Limitations on how close your filter is to it's ideal response, often pretty big limitations.
  • Possible PITA to code in C (what most system software is) if you use filter banks to offset the problem of high precision.
  • Need upfront good CPU to design the filter/solve coefficients if you can't do it by hand
Lastly we have digital FIR filters.
FIR pros:
  • High (but fixed!) latency, dependent on filter type however (for equalization, the latency is high).
  • Very high accuracy
  • If you can imagine a frequency response, you can do it with this method.
  • The filter works exactly as you designed it to.
FIR cons:
  • Moderate to High Computing power necessary depending on the size and FIR computation algorithm.
  • Need to have a good FFT algorithm to work with reasonably sized filters and this isn't that trivial.

So for my little venture into the audio DSP world (previously I just did alot of image work), I chose the last one as its the easiest to design/reconfigure on the fly and leads to the best results. Additionally, anything newer than a Pentium 2 shouldn't have problems playing music. It's also the kind of filtering I have the most experience with. But as a rather neat detail, let me make this clear:
You've maybe heard of low/high pass filters, shelf filters etc? Well, anything short of adding delay or echo to the signal this one "equalizer" can do (It can actually do that sort of thing with only a few small modifications for which I see no value in ATM). It's really more of a full on general DSP filter offering pretty much all of that functionality in one. The only real limitation that would require some restructuring is filter size but most people would probably be happy with a filter of size 2^16 (don't panic, FFT loves 2^n numbers and goes through it in a blaze in real time).

So yes, I'm happy about the theoretical aspects of "equalizer" and have gotten some kicks out of it. But now lets discuss some prior work and motive. If you're reading this, you might've heard about LADSPA and Steve Harris' plugins. He offers a few plugins, most of which I wasn't interested in except for mbeq (multi-band equalizer). It was useful to me and I thank the man for his work, but it just doesn't work properly in many ways. Its a PITA to configure with the setup of the ladspa sink in pulseaudio. One must put in numbers for which only gain meaning if you read the source (though you kinda get a feel for what positive and negative numbers do for the most part). There's a few problems with Harris' approach to the equalizer:
  • The frequency bands (hz) used/defined there!=frequencies we speak of naturally. They are proportional, however.
  • Each band then represents ~46 frequency bands (varies by sink sample rate) which while not too bad, is not the finest level of control
  • It should'nt be such a hassle to change the frequency band coefficients and instead I will be opting towards a gui so users can see frequency modification in realtime, the only real way things like this are tunable. This bit is actually more against pulseaudio's current implementation with ladspa, not with Harris.

Now why am I doing my equalizer again? Well, the start of it was my logitech X-540 5.1 speaker system which I bought a few months ago. Terrific speaker OMG way too much base. They have one bass dial which allows you to trade between tremble/bass but sound sounds so crappy if its less than half way maximum. It feels empty. Don't get me wrong though, I don't really like too much base like most people seem to enjoy (I don't understand why people feel it so necessary to hear those LFE which shouldn't usually be there anyway). It took some time to configure and some tradeoffs but with MBEQ and the ladspa sink, I got pretty good audio. You see, the Frequencies below 60hz from any speaker are also sent to this subwoofer from the X-540 set = way too much bass for most things. I also live in an apartment and I'm sure my neighbors wouldn't appreciate my subwoofer blasting them at 3 in the morning or some such. The ladspa sink has had a problematic past as of late with PA though and it broke quite a few times which left me hanging out to dry and gave me a difficult time a few days when I needed to listen to music/watch stuff. And finally, I just wanted to process some audio. I had filtered some other songs in the past with audacity, was amazed at the difficulty I had doing it. After enough time/effort, was impressed with the results on some songs that had some static in the background. It had cleaned them up and gotten rid of the parts that were bad while having no loss to the quality of the song, in fact this is one of those times where the quality of the song is improved. Audacious goes out of its way to use some of the above techniques I've mentioned but guard you from making up the specifics of the actual filter used, which I find interesting/weird.

Anywho, I knew right where to implement my equalizer so it'd have maximum effect: pulseaudio. A lowlatency audio framework with I believe a very promising future. On top of making plugins like mine possible (most OS's sound stuff doesn't like floats which are a requirement!), it does some interesting stuff that makes forwarding sound streams between sound cards or networks trivial. Oh yes, its also cross platform. And this isn't your run of the mill winamp equalizer, its system level baby. Every application can easily take advantage (whether it wants to or not, flash) of it if you forward the stream using paman or somesuch or set it as your default sink (as I do). Up next I'll explain how to set up your own equalizer until my packages make it into the Ubuntu repos. Opensuse Factory users are lucky enough to already have packages availble. But you'll still have to wait for the next post to find out where to dl :-)

Monday, August 10, 2009

First Post!

This is pretty much my first blog. I will be trying to show off some of my more useful software/personal projects.

Who am I? Well, I think I'm an upcoming linux/kernel/GUI/AI/DSP and all around software-renaissance-man (soon to get into the EE portion of things when I get money for supplies/screwing around). I graduated from UCI in 2009 majoring in Computer Science from the Donald Brend School of Computer Science (I nearly had a 3.65 GPA, some class screwed me over by .003 or something! Also, OUCH to the like 3 Cish grades I got in my entire UCI stay, those things hurt!). I studied alot of image processing, AI, Computer Vision (face recognition), automatic 3d model creation from commodity hardware (specifically 2 canon digital cameras, a tripod, and matlab), BioInformatics, Computer Hardware/Architecture (esp MIPS, also used VHDL), and Operating Systems design, and of course algorithms/graphs. The rest is pretty much GE or major requirements that aren't all that interesting.

I've been using linux since 2002, starting with slackware linux (hitting the end of version 8 and just in time for version 9). I moved on to use gentoo at some point between 2004 and 2005 and then switched to Ubuntu as this is around the time the clamour started on how much of a bs-free desktop it was. I didn't quite agree at the time but it was better than compiling all your own packages or dealing with third party people just to get up-to-date GNOME (specifically dropline gnome in slackware). Eventually I realized that pretty much all distro's were the same and that the only things that varied were their choices of versions of software, package format (tgz,deb,rpm), and how often they provided real updates to their system software. Ubuntu was too slow updating for me when I had a new laptop, and it broke a few times to many, so I tried out OpenSuSe in 2008 and have stuck with it on my laptop/desktop since. But I don't have anything against ubuntu. I actually put it on my mom's and sister's computers. It works enough for them it seems (doesn't make much difference of linux/windows if "things" work out of the box and you have no previous computer experience). But for doing this I never have to worry about them getting spyware/virii much, just falling for phishing (it's happened a few times already, alright!). Ubuntu does a good job of making sure those things which are difficult and of questionable legality (from the distro's POV) are properly dealt with and given to the user for a BS-free distro. Not many distros try and do this, I commend them for it. If only they allowed more things to be a bit more up to date! Oh well, there's always PPA's in the future. OpenSuse just has more "official" "stablizing" (aka stable) software branches and bleeding edge branches. And it also offers something like the PPA system as well. I like this approach better for my home machines. I also think writing rpm spec's is a bit easier than deb's control files though I think ubuntu has documented this pretty well in the last year so I may have to re-evaluate.

Anywho, In my time I've had to mess around/fix with quite a bit of computers, including my friend's/relatives. I've also been trapped in borked systems where the only two things working where the sole instance of bash running and sln (staticly linked ln) fixing bad glibc upgrades (it's alot of fun when tab completion becomes your only method of ls'ing) . I'd like to think there's no faulty software system I can't fix given some time. I've made a ton of small time software projects and a few big ones (with respect to me at least) for JPL and a RCC/WSTF NASA project in various languages (mostly C/C++/Java/Python) covering many subject areas.

I also can't wait till I can afford to get into robotics again and hope I can get into creating some interesting pet projects if not help out with making the first real automatic cars (human drivers suck!). Things have been quiet since the last DARPA grand challenge, but hopefully I don't miss the boat (fun fact: I believe one of the machines (Stanford?) used Ubuntu Dapper Drake LTS).

Anyway, I'll soon post a follow up about my new work with pulseaudio and equalization including why the ladspa solution sucks and doesn't work like how you think it does. I'll try and post some of my cool/usefull scripts sometime after that.