Hi all,
First time posting here!
I was experimenting with MID and fooling around. I looked for a feature such as ‘with_fx :recorder’ but for midi events and didn’t find anything of the like. So I’ve started playing with it to see what I could do, I’ve managed something dirty so far and I’m not sure as well how I could save the data between runs (short of saving these as .csv file somewhere).
I have several questions:
- I’m looking for any general ideas of improvements and as well how to write these ‘helpers’ more easily than within the interface buffer, is there a “library” folder? Or can I simply do some ‘require’ at the top of the buffer?
- Also wondering why I can’t use the ‘live_loop’ method within a class, is there a specific reason?
- Last, in order to avoid symbol collisions, is there a better way to get random temporary name for live_loop or cue/etc. outside of generating a name as random as possible?
Code behavior is quite simple, it wait for you to play a note on a MIDI interface, then record every note_on and note_off until you stop playing for at least 4 beat. Then it’ll loop over what has been recorded.
Best,
Cyprien
def MIDILoop(input: , output:, bar_length: 4.0, bpm: 100.0)
# To store the notes on/off
buffer = []
# controlling state
done = false
start = nil
real_time_bar = (bar_length * 60.0 / bpm)
# simple metronome sound
live_loop :bpm do use_debug(false)
stop if done
use_bpm bpm
bar_length.times do
|i|
if i == 0 then
sample :drum_cymbal_pedal
else
sample :drum_cymbal_soft
end
sleep 1.0/bar_length
end
end
# capturing note_on
live_loop :internal_on do use_debug(false)
use_real_time
args = sync "#{input}/note_on"
stop if done
# start on first note
if start.nil? then
start = Time.now
end
# if a note after a bar, stop recording and start looping
if !buffer.empty? && Time.now - buffer.last[:t] > real_time_bar then
done = true
cue :done
else
# push information to buffer
buffer.push({on: true, t: Time.now, data: args})
end
end
# capture note_off
live_loop :internal_off do use_debug(false)
use_real_time
args = sync "#{input}/note_off"
stop if done
# push event
buffer.push({on: false, t: Time.now, data: args})
end
# looping the recorded buffer
live_loop :loop do use_debug(false)
# wait for record
if !done then
sync :done
end
current_time = start
# going through event
buffer.each {
|event|
# sleep time before event
sleep event[:t] - current_time
current_time = event[:t]
# note_on or off accordingly
n, v = event[:data]
if event[:on] then
midi_note_on n, vel_f: v/127.0 ,port: output
else
midi_note_off n, vel_f: v/127.0 ,port: output
end
}
total_duration = current_time - start
sleep real_time_bar - (total_duration % real_time_bar)
end
end
MIDILoop(input: "/midi/sv1_1_keyboard/*/*", output: "sv1_1_sound", bpm: 90)