Skip to content

Instantly share code, notes, and snippets.

@Enkerli
Last active March 20, 2016 16:56
Show Gist options
  • Select an option

  • Save Enkerli/0687533338c5e40516fc to your computer and use it in GitHub Desktop.

Select an option

Save Enkerli/0687533338c5e40516fc to your computer and use it in GitHub Desktop.
Sonic Pi script to play with licks (short melodies notated in scale degrees). The function to convert degrees to notes is cobbled together from the built-in `resolve_degree` and `resolve_degree_index` methods.
# Sonic Pi script to play with licks (short melodies notated in scale degrees). The function to convert degrees to notes is cobbled together from the built-in `resolve_degree` and `resolve_degree_index` methods.
# Defining two new functions. Once defined, they don’t need to be included in other scripts.
# Lick player
def play_lick(lick, root, scale, time) # A “lick” is a list of scale degree numbers, with a set timing (i.e. “isorhythmic”).
spark lick # Show the lick as a text-based graph
lick.each{|note| play((degree_to_note note, root, scale)) ; sleep time } # Convert each degree number into a note and play it for the set amount of time. This function doesn’t use all the other `play` arguments such as `release:`and `amp:`. Could be useful in a future version, especially for timing.
end
DEGREES = {:i => 0, # Thought these were defined by default. They’re necessary for the degree conversion.
:ii => 1,
:iii => 2,
:iv => 3,
:v => 4,
:vi => 5,
:vii => 6,
:viii => 7,
:ix => 8,
:x => 9,
:xi => 10,
:xii => 11,
:r => 999 # While we’re at it, why not allow `:r` to become a rest, as elsewhere in Sonic Pi code?
}
# Degree to note converter
def degree_to_note(degree, tonic, scale) # Degree '0' should become a rest, the others should be converted to scale notes.
local_scale = Scale.new(tonic, scale) # Build a scale on the root note.
if degree.is_a?(Numeric) && degree==0 # Main change from the built-in `degree` function: we transform degree '0' into a rest.
return 0
elsif idx = DEGREES[degree] # Accommodate the notation in Roman numerals, e.g. “:iv” for the fourth degree of the scale.
index=idx
elsif degree.is_a? Numeric # If degree is a non-null integer, return the previous index in the scale, even if it’s negative
index=degree - 1
else # Catch non-numeric degrees.
raise InvalidDegreeError, "Invalid scale degree #{degree.inspect}, expecting #{DEGREES.keys.join ','} or a number"
end
local_scale.notes[index] # Return the scale note at the index position below the degree, if it’s a valid non-zero integer. Degree '1' returns the root note, degree '3' returns the third, degree "-1" returns the next to last note in the scale (the “subtonic”), etc.
end
# The “composition”: a simple loop allowing to change a lick in realtime.
root=52 # Put the tonic in a variable so it’s easy to change
scale=:minor # Put the scale type in a variable so it’s easy to change
use_tuning :just, root+1 # Since we can get acoustically perfect intervals, why not use them? Since the tuning is based on the major scale, adjustment may be needed for non-major scales
use_synth :pretty_bell # Some of the “softer” synths make sense, here, as we want to hear consonance.
live_loop :licking do # Infinite loop for live coding.
a=tick # Setting the first note in the lick to vary. At first, ticking through scale degrees, sequentially. Can then change this to a number, getting other degrees.
play_lick((ring a-7, 0, 3, 1).stretch(3), # Ha! Just found out that making the lick into a `ring` allows for the “ring chains” methods to be applied. Doh! <https://github.com/samaaron/sonic-pi/issues/1075#issuecomment-198870143>
root, scale, 0.1) # Otherwise, as simple a lick as possible, in a “dactyl” or “cretic” meter (depending on the duration after the lick), ending on the root.
sleep 0.45 # This duration causes the last lick note to play longer and then allows for a rest between licks.
end
# “Lix Explorer”
# Coded by Alex Enkerli, March 20, 2016
# Sonic Pi script to play with licks (short melodies notated in scale degrees). The function to convert degrees to notes is cobbled together from the built-in `resolve_degree` and `resolve_degree_index` methods.
def play_lick(lick, root, scale, time)
spark lick
lick.each{|note| play((degree_to_note note, root, scale)) ; sleep time }
end
DEGREES = {:i => 0,
:ii => 1,
:iii => 2,
:iv => 3,
:v => 4,
:vi => 5,
:vii => 6,
:viii => 7,
:ix => 8,
:x => 9,
:xi => 10,
:xii => 11,
:r => 999
}
def degree_to_note(degree, tonic, scale)
local_scale = Scale.new(tonic, scale)
if degree.is_a?(Numeric) && degree==0
return 0
elsif idx = DEGREES[degree]
index=idx
elsif degree.is_a? Numeric
index=degree - 1
else
raise InvalidDegreeError, "Invalid scale degree #{degree.inspect}, expecting #{DEGREES.keys.join ','} or a number"
end
local_scale.notes[index]
end
root=52
use_tuning :just, root+1
use_synth :pretty_bell
live_loop :licking do
a=tick
scale=:minor
play_lick((ring a-7, :r, 5, 1).stretch(3), root, scale, 0.1)
sleep 0.45
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment