Skip to content

Instantly share code, notes, and snippets.

@amiika
Forked from emlyn/guitar.rb
Last active September 17, 2022 12:29
Show Gist options
  • Save amiika/66b3ce4ace5ac60b64bca2f6c03a0064 to your computer and use it in GitHub Desktop.
Save amiika/66b3ce4ace5ac60b64bca2f6c03a0064 to your computer and use it in GitHub Desktop.
Strumming guitar chords in Sonic Pi
# Guitar Strumming - by Emlyn (modified by amiika)
# This tries to work out the guitar (or ukulele etc.) fingering for arbitrary chords (and tuning).
# It seems to work reasonably well for basic chords, but is quite naive and probably makes many mistakes.
# Ideas, bug reports, fixes etc. gratefully received, just comment below, or tweet @emlyn77.
# Feel free to make use of this code as you like (with attribution if you feel like it, but you don't have to).
# Thanks to @Project_Hell_CK for fixing the tuning, and spotting that it gets chord(:f, :major) not quite right.
define :next_note do |n, c|
# Make sure n is a number
n = note(n)
# Get distances to each note in chord, add smallest to base note
n + (c.map {|x| (note(x) - n) % 12}).min
end
ukulele = [:g, :c, :e, :a]
guitar_standard = [:e2, :a2, :d3, :g3, :b3, :e4]
# Return ring representing the chord chrd, as played on a guitar with given tuning
define :guitar do |chrd, tuning=guitar_standard|
# For each string, get the next higher note that is in the chord
c = tuning.map {|n| next_note(n, chrd)}.ring
# We want the lowest note to be the root of the chord
root = note(chrd[0])
first_root = c.take_while {|n| (n - root) % 12 != 0}.count
# Drop up to half the lowest strings to make that the case if possible
if first_root > 0 and first_root < tuning.count / 2
c = (ring :r) * first_root + c.drop(first_root)
end
# Display chord fingering
#puts c.zip(tuning).map {|n, s| if n == :r then 'x' else (n - note(s)) end}.join, c
c
end
#! Removed thread ... works better on my machine.
# Strum a chord with a certain delay between strings
define :strum do |c, d=0.05, vol=0.25, pan=0|
play_pattern_timed c, d, amp: vol, pan: pan
end
# Function that transforms progression arrays to rings (easier to maintain)
define :fromProgression do |pname, pkey, pscale|
progs = {
gypsy: [:i, :vi, :ii, :v, :i, :vi, :ii, :v],
swing: [:i,:i,:iv,:iv,:v,:v,:i,:i,:iv,:vii,:iii,:vi,:ii,:v,:i,:v],
simple: [:i,:iv, :v],
basic: [:i, :vi, :ii, :v],
blues: [:i,:i,:i,:i,:iv,:iv,:i,:i,:v,:iv,:i,:v],
jazzy: [:vi, :iv, :ii, :iii]
}
progs[pname].map do |deg|
chord_degree deg, pkey, pscale
end.ring
end
use_debug false
use_bpm 130
use_octave -1
# New way of gettin chords
# Check out scale from help
chords = fromProgression :gypsy, :c, :major
#chords = fromProgression :basic, :a, :gong
#strumming = ring("DD.DD.DU..DU")
# Custom progression rings works too with sonic pi: chord or chord_degree
#chords = ring((guitar chord :a, :m), (guitar chord :c, :M), (guitar chord :d, :M), (ring :r, :r, 53, 57, 60, 65),
# (guitar chord :a, :m), (guitar chord :c, :M), (guitar chord :e, :M), (guitar chord :e, '7'))
# Strumming as a ring makes it more interesting
strumming = ring("UD..D.","uD..D.","UD..D.","uD..D.",".D..U.",".D..d.",".D..d.","UD.UD*")
print chords
live_loop :guit do
with_fx :reverb do
with_fx :lpf, cutoff: 130 do
with_synth :pluck do
tick
strumming.look.split(//).each do |s|
if s == 'D' # Down stroke
strum chords.look, 0.02, 0.4
elsif s == 'U' # Up stroke
strum chords.look.reverse, 0.02, 0.4
elsif s == 'd'
strum chords.look, 0.02, 0.3, -1
elsif s == 'u'
strum chords.look.reverse, 0.02, 0.3, -1
end
if s == '*'
sleep 0.15
else
sleep 0.25
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment