For this demo I have two PCs. The remote PC is running Spi and VCV Rack. The Spi code simply picks up an OSC message /midi
and gets the paramters for note, volume, duration and channel. Then sends out a midi note to the loopmidi_port. These are picked up by a VCV Rack patch and played. The Rack patch has three voices, on channels 1,2 & 3.
#Remote Code
live_loop "osc2midi" do
use_real_time
n,v,d,ch = sync "/osc:192.168.1.64:4560/midi"
midi n, v, sustain: d, channel: ch, port: "loopmidi_port"
end
The controller PC is just running SPi and the code is a bit more involved, mostly because I’m changing chord in each bar, and I need to make sure that the local SPi loops and the remote midi calls get to use the correct chord at the correct time. And that the loop sending OSC is advanced in time to account for the latency. That’s in live_loop :main
. Otherwise it’s pretty straightforward, the live_loop external
sends out OSC /midi messages
use_bpm 120
roots = [:G4, :G4, :G4, :G4,
:G4, :G4, :G4, :G4,
:D4, :D4, :D4, :D4].ring
live_loop :external do
sync :ext
#Get some notes based on the current root note
notes = scale get[:extroot]-12, :blues_minor, num_octaves: 2
#Send OSC/midi notes to the remote PC
use_osc "192.168.1.3", 4560
in_thread do
8.times do
osc "/midi", notes["04005432".ring[look].to_i],127,0.1,1 if ("xxxxxxxx".ring[tick]=="x") ^ one_in(8)
sleep 0.5
end
end
in_thread do
12.times do
osc "/midi", notes["34262847".ring[look].to_i],127,0.3,2 if ("x-x-x-xxx".ring[tick]=="x") ^ one_in(0)
sleep 1.0/3
end
end
in_thread do
4.times do
osc "/midi", notes["0000".ring[look].to_i],127,0.5,3 if ("-x--".ring[tick]=="x") ^ one_in(0)
sleep 1
end
end
sleep 4
end
live_loop :main do
root = roots.tick(:root)
time_warp 3-rt(0.07) do
#Cue the external loop, slightly advanced for latency
#Set the root note to use, ahead of time so it's ready when the bar starts
set :extroot, root
sleep 1
cue :ext
end
time_warp 4.0-1.0/32 do
#Set the current root note, for the local Spi loops to pick up
set :root, root
end
sleep 4
cue :bar
cue :bar2 if tick%2==0
cue :bar4 if look%4==0
set :n, look
end
live_loop :arp1 do
#Play something local
sync :bar
notes = scale get[:root], :blues_minor, num_octaves: 2
notes = [get[:root]].ring
8.times do
play notes.tick, amp: 0.2
sleep 1.0/2
end
end
live_loop :drums do
sync :bar
n = tick(:bar)
s = [:bd_tek, :elec_cymbal, :mehackit_robot3, :elec_filt_snare]
with_fx :echo, mix: 0.2, phase: 0.75 do
in_thread do
16.times do
tick
sample s[0], amp: 0.4 if ("x---x---x---x---"[look]=="x") or one_in(16)
sample s[1], amp: 0.3 if ("--x---x---x---x-"[look]=="x") or one_in(24)
sample s[2], amp: 1.0 if ("---x------------"[look]=="x") and n%2==0
sample s[3], amp: 0.5 if ("------------x---"[look]=="x") and n%4==0
sleep 1.0/4
end
end
end
end