Saturday, January 29, 2011

I found the perfect project to dive into Haskell

I've had a recurring project in my life, a modular software synth. See here to get an idea of what I'm doing. The difference being that with software synths, you're not limited to how many components you have and how they're configured. I somehow thought I came to this revelation on my own years ago, but there's plenty of this sort of thing out there, such as SuperCollider, which sounds like it's fairly popular.

I've been trying to get into Haskell, but have been struggling to get myself out of my Python comfort zone. A friend of mine actually told me about SuperCollider recently, and I realized that my own synth would be the perfect project to get me started on Haskell, and one day last week I got inspired to get started. I found a simple example to start with of a sine wave being played through Pulse Audio and I went from there. Here's my repo

Unfortunately, you need PulseAudio to run this. I'm working on either getting Alsa output or file generation working soon.

When I was making this a few times before, I made it in C++, the latest instance being several years ago. Amazingly enough, despite still being a novice in the language, I found that doing this in Haskell is easier. The infinite lazy lists work perfectly as signals. Before I considered each component to be an object that had a value, and input signals. And I had to have a global "tick" that conveyed info between items. (And I thought that was really neat at the time.) Now I just have components be functions that "output" (return) infinite lists, and take infinite lists as inputs. It all sortof just sorts itself out.

Speed is sacrificed to be sure, at least so far, but real-time synths have been made for Haskell, so I bet I can profile it and optimize it significantly.

Also you will notice that everything is hard coded! I sortof like it that way, it's amusing, particularly when it starts making beat sequences (which is a point I got to in my old version), but I'll probably make an interface at some point. Or maybe not, Haskell is a nice interface.

Here's why I'm writing now of all times though. On top of being functional with the lazy infinite lists and such, Haskell also has a type system from Nazi Germany. This is actually an advantage, though. I have some trouble remembering all the unit conversions involved in the oscillators, when I'm dealing with cycles, seconds, and samples. So today, I made a type framework that provided functions that did the conversions properly. When I was writing out an improved version of my oscillator function, I used these types.

It took me a long time to figure out exactly how I wanted it all to work, and how to make it work. I would start on an expression, and then realize that I was adding different units, and Haskell wouldn't let me do it. Or sometimes the compiler told me so. But eventually I got through it. This is the monstrosity that resulted.

And the kicker: I used this to make a new version of the square wave oscillator, and it sounded exactly the same as the old one, the first time I ran it.

Sunday, January 2, 2011

Testing Multiple Login Sessions Simultaneously

One annoyance in developing websites is that you sometimes have to log in and out all the time to test interaction between multiple users.

Have you ever visited or administered a website (say, www.example.com) which lets you visit "www.example.com" or "www2.example.com", etc, and doesn't forward to "example.com"? Did you ever try logging in at one subdomain, and then switch to another? You'll be logged out, it's a different login session. If you needed to test something remotely with multiple users logging in at once, that's a nice trick to use.

Now let's do the same thing locally (*nix systems only afaik, sorry):

In /etc/hosts you should see:

127.0.0.1 localhost

Add the following:

127.0.0.1 localhost2
127.0.0.1 localhost3
127.0.0.1 localhost4

And so on for however many you need. Now each one will access your site with a different session, so you can log in as a different user for each.