The original reason I tried Sonic Pi was for its xenharmonic capabilities. I’ve written a bunch of variations of functions for building scales, but these are probably more useful for how we usually use Sonic Pi.
# Equal Temperament, edx = "equal divisions of x"
define :edx do
| mode = [2,2,1,2,2,2],
tet = 12,
equave = 2,
root = 60 |
notes = [midi_to_hz(root)]
for i in 0..(mode.length-1) do
notes = notes.append(notes[i] * equave ** (1.0*mode[i] / tet))
end
notes.ring.map { |n| hz_to_midi(n) }
end
# Just Intonation
define :ji do
| values = [9/8.0, 5/4.0, 4/3.0, 3/2.0, 5/3.0, 15/8.0],
root = 60 |
notes = [midi_to_hz(root)]
for i in 0..(values.length - 1) do
notes = notes.append(notes[0] * values[i])
end
notes.ring.map { |n| hz_to_midi(n) }
end
# convert midi to sample pitch: values
define :midi_pitch do |notes, center=nil|
if center.nil?
center = notes[0] + (notes[notes.length - 1] - notes[0]) / 2
end
notes.map { |n| n - center }
end
# Usage examples
use_synth :bass_foundation
# Bohlen-Pierce scale, equal tempered (13 equal divisions of tritave)
bp = edx([1]*23, 13, 3, 52)
# Bohlen-Pierce, Moll I (decatonic mode)
moll1 = edx([2,1,2,1,1,2,1,2,1], 13, 3, 60)
# Diatonic 12 TET
play_pattern(edx(), sustain: 0.75)
sleep 0.5
# Diatonic 12 JI
play_pattern(ji(), sustain: 0.75)
sleep 0.5
# `sample` example
10.times do
sample :bass_thick_c, pitch: midi_pitch(moll1).shuffle.tick(:tic1), amp: 1
sleep 1.5
end
sleep 2
# BP Just Intonation
bpj = ji([27/25.0,25/21.0,9/7.0,7/5.0,75/49.0,5/3.0,9/5.0,49/25.0,15/7.0,7/3.0,63/25.0,25/9.0,3/1.0],
48)
play_pattern_timed(bpj.values_at(6, 4, 8, 9) + [:r] + bpj.values_at(3, 2, 4, 6),
[1, 0.5, 0.5, 0.5, 0.5])
sleep 1
# 7 EDO/TET
t7 = edx([1]*10, 7, 2, 54)
play_pattern_timed(t7.values_at(6, 4, 8, 9) + [:r] + t7.values_at(3, 2, 4, 6),
[1, 0.5, 0.5, 0.5, 0.5])