Skip to content

Instantly share code, notes, and snippets.

@rbnpi rbnpi/ReadME.md
Created Apr 24, 2019

Embed
What would you like to do?
Visor Live and Sonic Pi play Elfen Lied Lilium music box. Video at https://youtu.be/TB1_i39c4XY

The accompanying two files play a visual display in VisorLive driven by Sonic Pi. The VisorMusicBoxFinal.rb file is loaded as a project file into visor version 0.4.0 www.visor.live A midi connection is established between the two (I used the iac driver on a Mac). The mapping file used was LaunchControlXL.json (supplied in the midi folder with visor.live) The sound output of Sonic Pi is linked to the input of visor.live I normally use Rogue Amoeba's LoopBack utility, but it I have also tested the project using the free soundflower utility. NB if you do use this you must disable loopback if you have that installed as well.

https://github.com/mattingalls/Soundflower/releases/tag/2.0b2 1.Install Soundflower.

2.Go to Audio MIDI Setup

3.Click the '+' sign at the bottom left of the window and select 'Create Multi-Output Device'(Aggregate is just the same,but I'm using Multi-Output)

4.Check the boxes at the 'Use' column next to Built-In Output and Soundflower 2ch(64ch is not recommended).Also tick the box in the 'Drift Correction' column for Built-In Output.

5.Adjust your volume before switching(I'll tell you why in the next step)

6.Go to System Preferences->Sound->Output and choose your Multi-Output device(or whatever you named it).BEWARE that this option will make your volume unadjustable.

7.select soundflower (2ch) as your sound input device in Visor

  1. You will hear the sound also in your local speakers/headphones. A video of the project is on youtube/rbn1tube https://youtu.be/TB1_i39c4XY
# ===== Default : Default
colorMode HSB,100,100,100
def polygon (x, y, radius1, radius2, npoints,k)
pushMatrix
translate x,y
rotate k if ka1==1 #rotate star on/off
angle = TWO_PI / npoints
halfAngle = angle/2.0
beginShape()
0.step(TWO_PI,angle) do |a|
sx =cos(a) * radius2
sy =sin(a) * radius2
vertex(sx, sy)
sx = cos(a+halfAngle) * radius1
sy = sin(a+halfAngle) * radius1
vertex(sx,sy)
end
endShape(CLOSE)
popMatrix
end
def draw
background volume*400,80,80*ka4
noStroke
if ka2==1 #switch central star colour
fn=30;fc=50
else
fn=80;fc=20
end
px=width*0.2;py=width*0.1
fill fn+frameCount%fc,100,100,180
pushMatrix
translate width/2,height/2
scale 1+volume*5
polygon(0,0,px,py,5+frameCount/5%14.to_i,frameCount*0.1) if ka3==1 #switch pat. stars
popMatrix
translate width/2,height/2
scale 1+10*volume if ka5==1 #switch scale on/off
rotate frameCount*volume*0.2 if ka6==1 #rotate fwd on off
#rotate -frameCount*volume*0.2 if ka7==1 #rotate bkwd on/off
translate -height/2,-height/2
xs=height/10;ys=height/10
for x in(xs..9*xs).step 100 do
for y in(ys..9*ys).step 100 do
fv=(x+y)/18# if x <450
fv =(x-y)/10 if ka7==1
fill fv,100,100
polygon(x,y,volume*300,volume*600,3+volume*200.to_i,0.1) if ka8==1
end
end
end
colorMode HSB,100,100,100
def polygon (x, y, radius1, radius2, npoints,k)
pushMatrix
translate x,y
rotate k if ka1==1 #rotate star on/off
angle = TWO_PI / npoints
halfAngle = angle/2.0
beginShape()
0.step(TWO_PI,angle) do |a|
sx =cos(a) * radius2
sy =sin(a) * radius2
vertex(sx, sy)
sx = cos(a+halfAngle) * radius1
sy = sin(a+halfAngle) * radius1
vertex(sx,sy)
end
endShape(CLOSE)
popMatrix
end
def draw
afactor=1.2 #adjust for optimum vloume effect
background volume*400,80,80*ka4
noStroke
if ka2==1 #switch central star colour
fn=30;fc=50
else
fn=80;fc=20
end
px=width*0.2;py=width*0.1
fill fn+frameCount%fc,100,100,180
pushMatrix
translate width/2,height/2
scale 1+volume*5
polygon(0,0,px,py,5+frameCount/5%14.to_i,frameCount*0.1) if ka3==1 #switch pat. stars
popMatrix
translate width/2,height/2
scale 1+10*volume*afactor if ka5==1 #switch scale on/off
rotate frameCount*volume*0.2*afactor if ka6==1 #rotate fwd on off
#rotate -frameCount*volume*0.2 if ka7==1 #rotate bkwd on/off
translate -height/2,-height/2
xs=height/10;ys=height/10
for x in(xs..9*xs).step 100 do
for y in(ys..9*ys).step 100 do
fv=(x+y)/18# if x <450
fv =(x-y)/10 if ka7==1
fill fv,100,100
polygon(x,y,volume*300*afactor,volume*600*afactor,3+volume*200*afactor.to_i,0.1) if ka8==1
end
end
end
#Elfen Lied Lillium music box tune by Dan Tramte
#Arranged to drive Visor graphics by Robin Newman, April 2019
use_debug false
use_midi_logging false
use_midi_defaults port: "iac_driver_sonicpi",channel: 1
notes =(ring 78, 85,
[80, 65], 73, 77, 81, [81, 66], :r, 78, 85,
[80, 65], 73, 77, 81, [83, 66] ,81,
[78, 62], 69, 74, 69, 71, 80, 76, 74,
[76, 61], 68, 73, 68, 70, 78, 74, 73,
[74, 59], 76, 78, 71, 60, [80, 63], [81, 66], 83,
[81, 61], 66, 73, 66, [80, 61], :r, 78, 85,
[80, 65], 73, 77, 81, [81, 66], :r, 78, 85,
[80, 65], 73, 77, 81, [83, 66], 81,
[78, 62], 69, 74, 69, 71, 80, 76, 74,
[76, 61], 68, 73, 68, 70, 78, 74, 73,
[74, 59], 83, [81, 60], 80, [78, 61], 77, [75, 73], 77,
[78, 66], [82, 78], [83, 80], [85, 82],
[86, 59, 71], 81, [80, 52, 64], 86, [85, 57, 69], 88, [81, 50, 62], 85,
[83, 67], 81, [80, 61], 77, 74, [73, 66], [82, 78], [83, 80], [85, 82],
[86, 59, 71], 81, [80, 52, 64], 86, [85, 57, 69], 88, [81, 50, 62], 85,
[84, 63], 81, 80, 78, [81, 61], 73, 66, 83,
[80, 65, 73], :r,:r,:r,:r,:r)
#puts notes.length;stop
##commented code prints out note data in the log from where it can be copied
##| notes.each_with_index do |n,i|
##| if n.class == Array then
##| puts "#{i} #{(note_info n[0]).to_s[17..-2].to_sym}"
##| puts "#{i} #{(note_info n[1]).to_s[17..-2].to_sym}"
##| puts "#{i} #{(note_info n[2]).to_s[17..-2].to_sym}"if n[2] != nil
##| else
##| if n !=:r
##| puts "#{i} #{(note_info n).to_s[17..-2].to_sym}"
##| else
##| puts "#{i} rest"
##| end
##| end
##| end
##| stop
#barline notes
bl=[2,6,10,14,17,20,24,28,32,36,40,44,48,52,56,60,63,66,70,74,78,82,86,90,94,98,103,107,111,115,119,123,127].map {|x| [x,true]}.to_h
#start of melody change
mel=[2,10,48,56,90,107,123].map {|x| [x,true]}.to_h
#prominent bass notes
bass=[3,6,10,14,16,24,32,40,44,48,52,56,60,62,70,78,80,82,84,86,90,92,94,96,98,103,107,109,111,113,115,119,123].map {|x| [x,true]}.to_h
define :midiRes do #reset all midi_cc, and stored values
8.times do |i|
midi_cc 13+i,0
set ("m"+i.to_s).to_sym,0
sleep 0.05
end
end
midiRes
sleep 0.5 #make sure completed
set :bpm,60
set :kill,false #flag used to stop loops at end of piece
set :mpass,3 #number of tune passes
k=(line 60,180,steps: 129) #generate bpm value list k
k=k+k[0..-1].reverse
#puts k
sleep 0.5 #make sure setup completed
live_loop :speed do #loop sweeps speed up and down 60 - 180 in 129 steps twice
use_bpm get(:bpm)
set :bpm, k.tick #store current bpm
sleep 0.25
stop if get(:kill)# stop loop at end
end
use_synth :pretty_bell
with_fx :reverb, room: 1, mix: 0.6 do
live_loop :music_box do #main tune play loop
use_bpm get(:bpm)
tick
if notes.look.class == Array then #split off harmony notes
play notes.look[0],pan: 0.5
#puts "#{look}: #{note_info notes.look[0]}" if notes.look[0] !=:r
with_synth :pretty_bell do #can try different synth for these
play notes.look[1],pan: -0.5
play notes.look[2],pan: -0.5
end
else
#puts "#{look}: #{note_info notes.look}" if notes.look !=:r
play notes.look,pan: 1 #play single notes here
end
#puts look%notes.length
sleep !(100..102).cover?(look%notes.length)? 0.5 : 1/3.0 #use cover? and look to alter time for triplet
if look ==128*get(:mpass)-2 #on last pass play end chord
mPulse 15,0 #switch of central star
sleep rt(1)
play :fs4,pan: 0.5
play :a4,pan: -0.5
play :cs5,pan: -0.5
play :fs5,pan: 0.5
sleep 2
set :kill,true #flag end of piece
stop
end
end
end
define :mPulse do |n,state| #send one midi_cc value
midi_cc n,state
set ("m"+n.to_s).to_sym,state #store value sent
end
define :mSwap do |n| #toggle or swap one midi_cc value and update store
state = get(("m"+n.to_s).to_sym)
if state==0
state=127
else
state=0
end
midi_cc n,state
set ("m"+n.to_s).to_sym,state
end
#Midi control allocations
#13=spin centre
#14=centre colour
#15=centre on/off
#16=background
#17=scale star field
#18=spin star filed
#19=colour star field
#20=starfield on/off
live_loop :timing do
use_real_time
use_bpm get(:bpm)
if get(:kill) #close down at the end
midiRes
stop
end
tick #reset every time tune completes
tick(:gl) #global tick. Doesn't reset each pass
if look(:gl)<128 #in first pass through tune
mSwap 20 if mel.has_key? look #control starfield using mel notes
mPulse 15,127 if look ==0 #switch on central star at start of tune
else #on 2nd or subsequent pass through tune
mSwap 15 if mel.has_key? look and look(:gl) < 128*get(:mpass)#toggle central star with mel notes (not at last pass)
mPulse 20,127 if look ==0 #switch on star field
end
if look(:gl) > 128*2 #on third pass of tune
mSwap 19 if (bl.has_key? look) and one_in(3) #switch star field colour on a thord of beats at random
mSwap 17 if bass.has_key? look #switch starfield scale using bass notes
end
mSwap 14 if (bl.has_key? look) and one_in(3) #switch central star colour on a third of all barlines
mSwap 16 if bass.has_key? look #switch background colour on all bass notes
mPulse 18,127 if look==86 #switch star field rotate on for second half of tune
mPulse 18,0 if look==127 #switch starfield rotate off at start of tune
mSwap 13 if bl.has_key? look #switch cental star spin on each barline.
sleep 0.5
tick_reset if look==127 #reset all controls at end of each tune
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.