Salutations! (A Journey into Sonic Pi and MIDI)

My name is Allen and I live outside of Memphis, TN. I’ve been working on electronic music since the early…never mind. I’m a complete coding noob. Last Tuesday a friend of mine posted an article from CDM about Live Coding. I did some searching and watched several of Sam’s presentations on youtube. I was impressed with how things seemed to work and all the possibilities. Also there seemed to be a diy spirit to everything. My only question was, “Can I live code this table of hardware?”.

A week later and the answer is yes and I’m loving it!

Last night I learned functions and they seem super powerful. Here is what I did for the Arturia Drumbrute.

#Drumbrute Functions
define :dbk1          do  midi_note_on 36, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbk2          do  midi_note_on 37, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbsn          do  midi_note_on 38, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbclp         do  midi_note_on 39, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbrim        do  midi_note_on 40, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbclav       do  midi_note_on 41, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbohat      do  midi_note_on 42, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbchat      do  midi_note_on 43, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbconghi  do  midi_note_on 44, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbtomhi    do  midi_note_on 45, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbconglo  do  midi_note_on 46, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbtomlo    do  midi_note_on 47, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbcym      do  midi_note_on 48, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbrev        do  midi_note_on 49, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbmara    do  midi_note_on 50, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbtam      do  midi_note_on 51, release: 1,channel:10 ,port:"akai_eie_pro_midi" end
define :dbzap      do  midi_note_on 52, release: 1,channel:10 ,port:"akai_eie_pro_midi" end 

I would like to code something like this for my synths. I have some ideas. Variables for the midi channels/ports maybe? Less typing is good right?

1 Like

That’s one way of doing it but I think that it would be more efficient to just give names to your midi notes and not to the whole package of informations.

Something like:

dbk1 = 36
dbk2 = 37

And then:

midi (ring dbk1, dbk2).tick(:brute), release: [0.5, 1].choose, channel: 1

This way, you have less things to type, and more possibilities to modulate your midi output. In your situation, the only crucial information you have in your function is the midi number to trigger the right sound. I don’t think that you need a function to store this information.

2 Likes

Hey @M_Rollers,

A warm welcome to you - thanks for joining our community. Great to hear that you’re starting your journey experimenting with controlling your external synths with algorithms and code. Please do continue to share your thoughts and ideas with us - you have no idea how many people you’ll end up inspiring!

Looking forward to hearing some of your coded beats!

1 Like

Hi @M_Rollers - welcome!

I agree that less typing is good - especially in live situations. And functions are indeed super powerful. One thing that they’re great for is reducing repetition. And since functions can call other functions, one suggestion I might have is to create a separate :brute function that handles all of the values that are the same, and accepts the midi note as a parameter.

Maybe something like this:

define :brute do |midi_note|
  midi_note_on midi_note, release: 1, channel:10, port:"akai_eie_pro_midi"
end

define :dbk1 do brute 36 end
define :dbk2 do brute 37 end
define :dbsn do brute 38 end
# etc...

This way, if you ever want to change the release, channel, or port, you just have to do it in one place. Less typing! :smiley:

I hope that answers your question, and if not, please let us know. Have fun, and please post some recordings of what you’re up to!

1 Like

Thanks for your response. I chose functions because from my understanding, you can load at the beginning of a session, then erase and your functions still work. I’m sure my code will evolve over time and I will make tweaks to make it more efficient. I love seeing people ideas, it can really give a fresh perspective. As it is now my Drumbrute sequencing is looking like this.

use_bpm 120

live_loop :db1 do
  dbk2
  sleep 0.5
  dbchat
  sleep 0.5
  dbk2
  #dbclp
  sleep 0.5
  dbchat
  sleep 0.5
end
live_loop :db2 do
  sleep 1.25
  dbtomlo
  sleep 0.25
  dbrev
end
live_loop :db3 do
  sleep 0.75
  dbmara
  sleep 0.125
  dbmara
  sleep 0.005
  dbclav
  sleep 1
end
live_loop :db4 do
  dbcym
  sleep 0.25
end

THIS is the sort of thing I definitely need to set up with the synths! The thing about MIDI is it doesn’t always work the same. Case in point, Behringer Model D and Neutron. They both are a bit ticky to trigger with midi, the midi note has to be a certain length for the ADSR(or ADS on Model D) to work right. This is the case with my Zaquencer, Renoise, Ableton, etc. My Yamaha CS5 with Kenton Pro Solo mkii works perfect and as expected. I guess you get what you pay for. I like the Behringers and think they sound great for the price, but they have some quirks. More on this later. I think I got my ASIO working with Sonic Pi so maybe I can get to recording soon. If not I may can record my audio into Live.

I’ve been having a lot of fun working with Sonic Pi and Ableton. So far, I’ve just been using Ableton as a host for AU plugins, and using the midi out in Sonic Pi to play through the plugins. It’s nice to be able to use Sonic Pi as the coding environment, but still be able to use any sound source.

It’s super cool that you’re using it to drive hardware!

2 Likes

@M_Rollers: if you want your code to be optimal and without repetition, I really think that you should aim at writing every instruction only once. I still think that wrapping parameters inside a function is not always a good idea because it makes you jump in your code too often. I do prefer using a dense writing style that helps me moving fast when I improvise.

Here is an example. You posted the following code:

 live_loop :db1 do
  dbk2
  sleep 0.5
  dbchat
  sleep 0.5
  dbk2
  #dbclp
  sleep 0.5
  dbchat
  sleep 0.5
end

Here is how I would have written it:

live_loop :db1 do ; tick ; use_bpm 120
midi (ring dkb2, dbchat, dbk2, dbchat).look, release: 1, channel: 1
sleep (ring 0.5).look 
end

I think that this gives you the opportunity of making changes really fast. For instance, I only have to add a comma and another number to create rhythmic variation. I just have to write something like [0.5, 1].choose to play with the release time, etc…

What do you mean by “jump in your code”? I tried your code, it doesn’t sound the same at all. The timing is all off. Mine alternates kick and hat, yours plays kick and hat at the same time. Are you calculating the release time in? Honestly I can take it out of my code completely, because it has no effect on the Drumbrute.

Maybe there is some hardware specifics that I don’t know about. You may need to have the release time to be equal or superior to 1. However, this doesn’t mean that my example is wrong. I was just not aware that the DrumBrute was meant to be used with this amount of release. For instance, check the following code:

live_loop :db1 do ; tick ; use_bpm 120
  sample (ring :drum_bass_soft, :drum_cymbal_closed, :drum_snare_soft, :drum_cymbal_closed, :drum_bass_soft,
          :drum_cymbal_closed, :drum_snare_soft, :drum_cymbal_closed).look, release: 1, channel: 1
  sleep (ring 0.5).look
end

I’ve replaced the midi operator with the sample one so we can be sure that we will hear the same thing. You will hear a steady beat, without tempo fluctuation or overlapping sounds.

EDIT: Of course, in my old example, I was still talking about having dkb1, dkb2 and all these things being declared as follow:

dbk1 = 36
dbk2 = 37

Cool. I was able to reformat your last code a bit and it worked on the drumbrute. I went ahead and did the other parts as well(except the last one). Just used Midi note numbers to get it working. Do I need the .tick and use_bpm for each live_loop?

live_loop :db1 do ; tick ; use_bpm 120
  midi_note_on (ring 37,43,39,43).look,channel:10 ,port:"akai_eie_pro_midi"
  sleep (ring 0.5).look
end
live_loop :db2 do ; tick ; use_bpm 120
  midi_note_on (ring 47,49).look,channel:10 ,port:"akai_eie_pro_midi"
  sleep (ring 1.75,0.25).look
end
live_loop :db3 do ; tick ; use_bpm 120
  midi_note_on (ring 50,50,41).look,channel:10 ,port:"akai_eie_pro_midi"
  sleep (ring 1.75,0.125,1).look
end
live_loop :db4 do  tick ; use_bpm 120
  dbcym
  sleep 0.25
end

Tick and Look are very strange things. Think about them like counters that are counting nothing. They just tell Sonic-Pi to read the next value stored in a ring or an array.

These things can have names if you want multiple instances of this counter:

tick(:one) ; tick(:two) ; tick(:three)

I guess that this is because sometimes it is cool to be able to have conditionnal counters and stuff like that for generating complex patterns.

I guess you can stick to it for the moment. Tick will be your unnamed counter for each loop, and use_bpm can be modified if you want one pattern to be faster than the other. It can be a fun effect. Something like use_bpm 120 VS use_bpm 60 or 240.

Thank you for your help. This is a lot to process. I have used the .tick to make arpeggios with a chord, the look is new to me. The more I understand how the code is working, the easier it will be.

Yes, you’ll see, it’s just some getting used to. After a while, you will not even be thinking about all that and it will be like a second nature. Once you feel confident using rings for easy and fast sequencing, try to learn the less obvious types of rings. There are a few of them that nobody is talking about, and some of them are great for MIDI_CC controls and more precise, specialised sequencing (line, octave, bools, etc…) Here is a small repository of some examples taken from the tutorial / guide I wrote earlier about this topic:

BOOLEAN DRUM MACHINE

live_loop :perc do ; tick
  sample :bd_boom, amp: 1 if bools(1, 0, 0, 1, 0).look
  sample :perc_snap2, amp: 1 if bools(1, 0, 1, 0).look
  sample :drum_cowbell, amp: 1 if bools(0, 0, 0, 1).look
  sample :drum_snare_hard, amp: 0.7 if bools(0, 0, 1, 0).look
  sleep 0.25
end

LINE AND PARAMETRICAL CHANGE SMOOTHING

live_loop :line do ; tick
  use_synth :noise
  play :c4, release: (line 0.001, 0.10, steps: 10).look
  sleep 0.125
end

EUCLIDIAN SEQUENCES

live_loop :euclidien do ; tick
  play :c3 if spread(1, 4).look
  play :g3 if spread(4.5, 10).look
  play :g4 if spread(4.5, 11).look
  play :g5, amp: 0.1 if spread(15, 32).look
  sleep 0.25
end

KNIT FOR REPEATING VALUES

live_loop :knit do ; tick
  play (knit :f4, 2, :g4, 2, :ab4, 2).look, release: 0.1
  play (knit :c5, 2, :bb4, 2, :f4, 2).look, release: 0.1
  sleep (knit 0.125, 16, 0.125/2, 2, 0.125, 16, 0.5, 1).look
end

And to give you even more control on these sequences, you can create combinations with the.tick method. For instance, you can do something like .mirror.tick or .shuffle.tick. Take your time with these things, but if you are playing with hardware machines, it will some good days of midi sequencing jams.

EDIT: And I guess that it’s 90% of what you need to know to master midi sequencing in SP.

2 Likes