Tom Says: Safe code is boring code! Why??
Previous page:
Springy Scanning Synthesis
Next page:
Go
The advertised way of patching MIDI between Archaeopteryx and software like ChucK (which doesn't register itself as a MIDI endpoint) is to use MIDI Patchbay. Apparently, as an alternative, you can create a MIDI bus with OS X's "Audio MIDI Setup.app".

Double-click "IAC Driver"

Then check "Device is online" and make sure there's at least one bus in the "Ports" list.

Then you'll see, in chuck --probe, for example:
[chuck]: ------( chuck -- 1 MIDI inputs )------ [chuck]: [0] : "IAC Driver Bus 1" [chuck]: [chuck]: ------( chuck -- 1 MIDI outputs )----- [chuck]: [0] : "IAC Driver Bus 1"
I don't know what the drawbacks to this approach are, but testing with SimpleSynth worked pretty well. One less thing to do at the start of an Archaeopteryx session.
I feel more comfortable with physical controllers than virtual ones. So even when I first started live-coding with Arkx, I wanted to use real devices to drive my patches. The possibility of controlling number_generator with a slider, for example, would be handy.
Adding OSC was ridiculously easy, thanks to the rosc library. I added an OSC server to eval_style.rb. It accepts messages containing a single float and stores them all in a big hash. Very simple.
# Add to eval_style.rb
require "osc"
serv = OSC::UDPServer.new
serv.bind "localhost", 5000
on_msg = L do |msg|
domain, port, host, ip = msg.source
$oscvars[msg.address] = msg.args.first
puts "#{msg.address} -> #{msg.args.inspect} from #{host}:#{port}"
end
serv.add_method "/*/*", "f", &on_msg
serv.add_method "/*", "f", &on_msg
Thread.new { serv.serve }
$oscvars = {}
Along with a little Range helper (class Range def rand; Kernel.rand * (last - first) + first end end), my :number_generator library has grown a bit (my_definition.rb):
# :number_generator => L{0.9},
# :number_generator => L{rand},
# :number_generator => L{$oscvars["/slider/0"] || 1.0},
:number_generator => L{(($oscvars["/slider/0"] || 1.0)..1.0).rand},
You can use it elsewhere, like to set note velocity, or choose your queue-selection algorithm, or wherever else. They're just floats in a hash.
You need some other software to send OSC messages. I prefer ChucK for this because of its support for a variety of input devices: mouse, keyboard, built-in accelerometer, MIDI, OSC, joysticks, gamepads, what-have-you.
First is a script I built for reading the laptop's accelerometer (useless, but an extremely simple proof-of-concept).
// accelerometer.ck
HidIn hi;
HidMsg msg;
if( !hi.openTiltSensor() ) {
<<< "tilt sensor unavailable", "" >>>;
me.exit();
}
OscSend xmit;
xmit.setHost( "localhost", 5000 );
while( true ) {
xmit.startMsg( "/accel/x", "f" );
hi.read( 9, 0, msg );
msg.x/256.0/2.0 + 0.5 => xmit.addFloat;
0.1::second => now;
}
Next I made a script for reading slider values from my Trigger Finger controller (16 pressure-sensitive buttons, 4 sliders, 8 knobs, fully programmable).
Note: Archaeopteryx has MIDI-in support now. I haven't tried it, but it's probably great!
Things get tricky when you plug in a device like this which is a MIDI source and a MIDI sink. At the time of this writing, Arkx will choose to send to the first MIDI device it sees. My Trigger Finger takes priority in my MIDI device list, as I can see with chuck --probe:
[chuck]: ------( chuck -- 2 MIDI inputs )------ [chuck]: [0] : "USB Trigger Finger" [chuck]: [1] : " MIDI Patchbay" [chuck]: [chuck]: ------( chuck -- 2 MIDI outputs )----- [chuck]: [0] : "USB Trigger Finger" [chuck]: [1] : " MIDI Patchbay"
To get Arkx to send to the second MIDI device, pass :midi_destination to Arkx.new in your eval_style.rb. Once that's done, the ChucK script is easy:
// run like: chuck midi-tf.ck:0
// where "0" is the MIDI device number of the Trigger Finger
// (see chuck --probe)
MidiIn min;
MidiMsg msg;
OscSend xmit;
if ( !min.open(Std.atoi(me.arg(0))) ) me.exit();
xmit.setHost("localhost", 5000);
fun void update(string name, float value) {
<<< "sending", name, value >>>;
xmit.startMsg(name, "f");
value => xmit.addFloat;
}
while( true ) {
min => now;
while( min.recv( msg ) )
{
<<< msg.data1, msg.data2, msg.data3 >>>;
if(msg.data2 == 7) update("/slider/0", msg.data3 / 127.);
if(msg.data2 == 1) update("/slider/1", msg.data3 / 127.);
if(msg.data2 == 71) update("/slider/2", msg.data3 / 127.);
if(msg.data2 == 74) update("/slider/3", msg.data3 / 127.);
}
}
Posted Oct 12, 2008, in the afternoon. Updated updated Nov 18, 2008, in the afternoon: Added trick for adding a MIDI bus on OS X, and made some long-overdue corrections.