So I've gone through Overtone Getting Started a few times, and am up and running. Only trick at all is that I already have my own jackd wrapper script to get jack started. Just like the other times that I went through this tutorial, I get to this point and say "now what?"
There are two different directions to explore. I have the REPL working, but it would be nice to be able to execute from a file and also do some interactive editing via Vim (or Emacs I suppose). The other path is to ... you know ... make some music (er... noise).
So I go on a reading spree. Things I learn:
Today I'm watching Overtone and ClojureScript which is a coding session of someone setting up an web UI to play Overtone stuff. Building a UI like this reminds me of the one-string guitar that I got at an art festival the other day. Clearly home-made, including an energy drink as the echo chamber. And very awesome. Also fun to see someone iterate through their development. Lots of interesting things in there, most of them I can read more or less but doesn't mean I could write them. One thing I noticed was (:use ...) to pull in instrument libs. I'll try that.
The Cheat Sheet is interesting, but I don't know enough to actually use a lot of the things on there. Current mission is to get the instruments working.
Ah! I need to do (use 'overtone.inst.piano) not (:use overtone.inst.piano).
(defn play-song [metro beat-num notes]
(map-indexed (fn [index n]
(at (metro (+ index beat-num)) (piano :note (note n)))
) notes)
)
Good progress today -- I made a hack to get around that BUNCHES of midi issue. I also got Overtone Vim Integration working. Well technically I already had it working (had fireplace.vim installed, etc), I just didn't know it. Now I can start up the REPL in one terminal and start up vim in another. In vim do ":Require" and it finds the running REPL and hooks into it. I also added "nnoremap
(ns noise.core)
(use 'overtone.live)
(use 'overtone.inst.piano)
(on-event [:midi :note-on]
(fn [e]
(let [note (:note e)
vel (:velocity e)
device-name (:name (:device e))]
(if (= "VirMIDI [hw:1,0,1]" device-name)
(piano note vel)
()
)
)
)
::midi-keyboard-handler
)
So that takes midi events specifically from that device (I picked one of my 64 virtual devices at random, seems to work) piped to the piano instrument. Next I'm going to make a new instrument of my own and hook that in!
http://ibisandbaboon.com/2013/01/13/playing-with-music-and-overtone-i/ - nice intro
http://hg.postspectacular.com/resonate-2013 - need to check out
2013-12-26
This is awesome -- In The Composing Schemer the author uses "core.logic" (which I assume is a clojure lib for doing rule/inference programming) to generate melodies!
Today I'm playing with Open Sound Control (OSC), which is more general-purpose than midi but kinda similar idea. I have an android app on my phone named Control which has a few existing UIs, in my case I'm playing with the multi-touch. I set it to have two touch inputs.
In my Overtone REPL I first set it up to listen for OSC events, and dump out whatever events it sees:
(def server (osc-server 44100 "osc-clj"))
(osc-listen server (fn [msg] (println msg)) :debug)
**Turn off with:** (osc-rm-listener server :debug)
I got both my laptop and phone on the wifi (which allows peer-to-peer communication) and told the Control app to connect to my laptop server (192.168.0.15 port 44100, in this case). Now when I touch the screen I get a bunch of messages about the generated OSC events. They look like:
{:src-port 45161, :src-host 192.168.0.25, :path /multi/1, :type-tag ff, :args (0.36825398 0.3961456)}
From this I see that the path I want to react to is "/multi/1" and "/multi/2". Dragging my fingers around, the args are the x and y coordinates normalized to (0..1). For now I'll just make it beep a bit when it gets an event. I'm hooking the first touch up so the X axis generates a frequency, and the second touch up so that the Y axis generates a frequency (just as a test), giving:
(osc-handle server "/multi/1" (fn [msg]
(let [
x (nth (:args msg) 0)
y (nth (:args msg) 1)]
(demo 0.1 (saw (+ 100 (* 100 x))))
)
))
(osc-handle server "/multi/2" (fn [msg]
(let [
x (nth (:args msg) 0)
y (nth (:args msg) 1)]
(demo 0.1 (saw (+ 100 (* 100 y))))
)
))
Each touch plays for 1/10th of a second, so if I drag around these overlap a bunch. In fact, if I drag around a lot then something gets backed up and the sound is delayed.
BONUS
Control comes with the ability to dynamically create controls, even over OSC itself! This video shows dynmically creating widgets in Control from SuperCollider, which should be straightforward to translate into Overtone.
Three part tutorial on creating reactive Control interfaces
One of my goals is to hook up my midi keyboard to an instrument and then hook up some of my midi knob controllers and/or OSC from my phone to adjust instrument parameters. I only needed one more thing to make this happen -- clojure refs. First I define an instrument that is parameterized:
(definst steel-drum [note 60 amp 0.8 sustain 0.1 subfreq 7]
(let [freq (midicps note)]
(* amp
(env-gen (perc envp 1) 1 1 0 1 :action FREE)
(+ (square (/ freq 2))
(rlpf (saw freq) (* multix freq) 0.2)
)
)
)
)
Next I'll define some refs. I give them the same name, but note that the above names were local to the steel-drum, so are irrelevant here.
(def sustain (ref 0.1))
(def subfreq (ref 7))
Now when we get a midi note we need to use these params when we trigger the instrument. As with a previous article, ignore the bit where I'm filtering down my midi device :)
(on-event [:midi :note-on]
(fn [e]
(let [note (:note e)
vel (:velocity e)
device-name (:name (:device e))]
(if (= "VirMIDI [hw:1,0,1]" device-name)
(steel-drum note vel @sustain @subfreq)
()
)
)
)
::midi-steeldrum-handler
)
Great! Now to modify those refs I can do (dosync (ref-set sustain 0.3)) for example. This says start a transaction, and then do an inconsiderate re-assignment of the sustain. That is, do it without regard to what any other transaction might have done. "assign" is nicer than "ref-set", but we don't need to be nice.
To access the current value we can use "@sustain" as we did above. Now what we need to do is listen to some inputs and overwrite the current values. For this I'll use OSC with a x,y touch UI. I'll use the x-coordinate as sustain and the y-coordinate as the subfreq.
(osc-handle server "/multi/1" (fn [msg]
(let [
x (nth (:args msg) 0)
y (nth (:args msg) 1)]
(dosync (ref-set sustain (/ x 2)))
(dosync (ref-set subfreq (* y 20)))
)
))
And with that I can drag around on my touch UI and it changes the sustain and underlying frequency of my instrument, so I simultaneously bang on my virtual keyboard and get different sounds!