The application supports integration with Sonic Pi, utilizing the Open Sound Control protocol. Melody variations can be generated from MIDI sources and from messages sent by Sonic Pi directly in real-time. Two backends for algorithmic music generation are implemented: Markov chains and a wrapper around Magenta’s MusicRNN chord_pitches_improvcheckpoint.
The source code needs to be polished a bit, but I will upload it on Github soon.
It’s sounding really awesome so far! Personally, I’d run the piano through a subtle morphing high-cut effect to give the piano some more movement but that’s just me.
@Doffu Thanks! Here is the code for the piano part and the loops that receive and play the generated sequences. Would really appreciate any suggestions on how to optimize it or make the sound better
# Coded by Viktor Pavlov
# Piano part from Arvo Pärt's "Spiegel im Spiegel"
use_bpm 80
set :sequence, []
live_loop :receive_sequence do
use_real_time
seq = sync "/osc*/gen/sequence"
s = sync "/osc*/gen/steps"
set :sequence, seq.zip(s)
end
live_loop :metronome do
sleep 1
end
with_fx :reverb, room: 1 do
live_loop :piano_part, sync: :metronome do
F = (ring :C5, :F5, :A5)
Gm7 = (ring :As4, :F5, :G5)
Bbmaj7 = (ring :D5, :A5, :Bb5)
use_synth :piano
use_synth_defaults sustain: 0.8, release: 0.2, hard: 0.1
18.times do
play F.tick
sleep 1
end
6.times do
play Gm7.tick
sleep 1
end
24.times do
play F.tick
sleep 1
end
6.times do
play Bbmaj7.tick
sleep 1
end
end
live_loop :play_gen_sequence, sync: :metronome do
notes = get[:sequence] || []
puts notes
if notes.empty?
sleep 1
else
notes.each do |note, step|
use_synth :blade
use_synth_defaults amp: 0.4, attack: step * 0.4, decay: step * 0.1,
sustain: step * 0.3, release: step * 0.2, vibrato_rate: 7
play note
use_synth :square
play note, amp: 0.03
sleep step
end
end
end
end
Interesting as coding is concerned but musically “it lacks sweat” and human feelings. We are better than machines to express our feelings with music.
Just my point of view.
Next step : how to add sweat into a sonic pi tune
see you
Something like this… keep in mind this isn’t perfect. I’m not 100% grasping the way that you coded this piece as it’s very different from how I typically code. There is probably a much better way to code this automation in your own personal way but this should give you an idea of how you could automate the LPF effect.
I just defined an LFO variable that steps through different values for every tick. Then I added the LPF effect on the piano instrument and ‘looked’ at the current tick to decide what the cutoff frequency should be at any given time.
If you want to get more fancy with it you could create multiple LFO variable that are all modulating at different rates, then apply them to various effect parameters like amp, cutoff, resonance, phase, pan, etc… This will give a feeling that the instrument’s timbre is morphing over time.
# Coded by Viktor Pavlov
# Piano part from Arvo Pärt's "Spiegel im Spiegel"
use_bpm 80
set :sequence, []
# AUTOMATION:
lfo0 = (line 50, 100, inclusive: true, steps: 32).mirror
live_loop :receive_sequence do
use_real_time
seq = sync "/osc*/gen/sequence"
s = sync "/osc*/gen/steps"
set :sequence, seq.zip(s)
end
live_loop :metronome do
sleep 1
end
with_fx :reverb, room: 1 do
live_loop :piano_part, sync: :metronome do
F = (ring :C5, :F5, :A5)
Gm7 = (ring :As4, :F5, :G5)
Bbmaj7 = (ring :D5, :A5, :Bb5)
use_synth :piano
use_synth_defaults sustain: 0.8, release: 0.2, hard: 0.1
18.times do
with_fx :lpf, cutoff: lfo0.look do
play F.tick
sleep 1
end
end
6.times do
play Gm7.tick
sleep 1
end
24.times do
play F.tick
sleep 1
end
6.times do
play Bbmaj7.tick
sleep 1
end
end
live_loop :play_gen_sequence, sync: :metronome do
notes = get[:sequence] || []
puts notes
if notes.empty?
sleep 1
else
notes.each do |note, step|
use_synth :blade
use_synth_defaults amp: 0.4, attack: step * 0.4, decay: step * 0.1,
sustain: step * 0.3, release: step * 0.2, vibrato_rate: 7
play note
use_synth :square
play note, amp: 0.03
sleep step
end
end
end
end