Thursday, August 16, 2012

Jamming With Overtone at the London Clojure Dojo

At Wednesday's Clojure Dojo, we succeeded in connecting multiple slime clients to one swank server, enabling us to "jam" together in Overtone, with me controlling the bass and Jen playing notes and samples over the top. There was some interest in how we got this working so here it is:

Firstly, we needed some ready-made code to start playing with so we cloned Overtone from here onto my laptop:

https://github.com/overtone/overtone

Next, we decided to use Sam Aaron's internal sequencer example which you can see in this video: http://vimeo.com/47578617

The example is located in the overtone source tree so I opened it in emacs: src/overtone/examples/timing/internal_sequencer.clj

Next, I added the following to my project.clj in order to enable the leiningen swank plugin:

:plugins [[lein-swank "1.4.4"]]

Back in emacs, I ran M-x clojure-jack-in to start the swank server and connect to it. This worked fine but the others weren't able to connect because the swank server started by clojure-jack-in very sensibly listens for connections only from localhost.

I therefore disconnected from the swank server by running M-x slime-disconnect. I didn't kill the repl buffer at this point for reasons that will become clear in a moment.

Next, I returned to the command line and ran:

lein swank 4005 0.0.0.0

This tells the swank server to listen for connections on port 4005 from any host. After opening up that port in the firewall, the others were able to connect.

Having done that, we were all able to connect to the server by running M-x slime-connect in emacs and giving it my ip address and port 4005. Note that we needed to have left the repl buffer open previously because, being emacs noobs, we haven't figured out how to get a repl buffer to open when we do slime-connect.

It should be pointed out at this point that swank isn't secure and, while it was running, it would have been possible for someone to connect and evaluate:

(.. Runtime (getRuntime) (exec "rm -r ~/*"))

Worse, they could have screwed around with our synths!

The hacking was now ready to begin. Our version of Sam Aaron's internal sequencer example can be found here:

https://gist.github.com/ae9560f932792a8a1a7e

We only made a few changes to it. The first was to load in some awesome samples:

(def something-s (sample (freesound-path 8323)))
(def heart-s (sample (freesound-path 16309)))
(def bovine-cow-s (sample (freesound-path 16568)))
(def jet-s (sample (freesound-path 9088)))
(def cackle-s (sample (freesound-path 80187)))

... which Jen could then play by evaluating the samples like a function in order to really get in touch with our totem animals:

(bovine-cow-s)

I created a few really short functions so that I could control the bass and treble on the fly:

(defn b [note]
  (ctl dubstep
     :note note
     :wobble (* BEAT-FRACTION 1.2)
     :lag-delay 0.5
     :hi-man 0
     :lo-man 1
     :deci-man 0)
  )
(defn t [note]
  (supersaw2 (midi->hz note) :amp 1 :fil-mul ssaw-fil-mul :rq ssaw-rq)
  )

I was then able to get on stage and "wow" everyone with simple basslines while Jen played samples over wireless from back in the audience. While it was pretty simple stuff in the grand scheme of things, I'm quite pleased with how easy it is to do totally awesome things in Overtone with (in my case) little experience. Overtone rocks.

The only thing that I wasn't happy with was our inability to get a repl to come up when we did slime-connect. If anyone knows a bit more about emacs and slime than me and has this figured out then please let me know!

5 comments:

Oliver Godby said...

Wow, this is effing awesome! Thanks for sharing the "how" :-)

Anonymous said...

Nice work, sorry to have missed it.

It probably makes sense to run clojure in a jvm with a security manager installed to protect against the Runtime#exec() problem.

Not sure what Overtone needs, but a simple repl is as simple as:

adding:

:jvm-opts
["-Djava.secutity.manager"
"-Djava.security.policy=sec.pol"]

to project.clj

and contents of file sec.pol would look something like:

grant {
// Allow files to be loaded, OS perms still apply
permission java.io.FilePermission
"<>", "read";

// Required for clojure runtime
permission java.util.PropertyPermission "clojure.*", "read";
permission java.lang.RuntimePermission "createClassLoader";
permission java.lang.RuntimePermission "setContextClassLoader";
permission java.lang.RuntimePermission "accessDeclaredMembers";

// Required for REPL
permission java.net.SocketPermission "localhost:*", "connect, accept";
};

Which gives this:


user=> (.exec (Runtime/getRuntime) "rm /home/neale/foo")
AccessControlException access denied ("java.io.FilePermission" "<>" "execute") java.security.AccessControlContext.checkPermission (AccessControlContext.java:366)

Chris said...

Thanks Neale :-). I hadn't really given much thought to using a security manager but that would definitely prevent against a certain category of attacks. You'd probably need to restrict a few more permissions too (for example, to prevent against modification of my .bashrc to add something malicious) and it would be important to do so in such a way that it doesn't interfere with the correct operation of Overtone too :-)

Anonymous said...

actually, the config I posted only gives read only access to file system, so no modification of .bashrc would be possible.

Remember that all permission are revoked when you install a SecurityManager (basically), and you then grant only what you need.

unfortunately blogger has 'eaten' a bit of the config in my comment and I didn't notice.

the FilePermission should be:

java.io.FilePermission "<<ALL FILES>>", "read";

Chris said...

Many thanks :-)