# Scale degrees and modes

Hi, I was looking at some videos on degrees, and building chords in scales.

There’s a video that talks about the modes, and applying this to different scales, which got me thinking how this could be done in SP.

It looks like sp’s degree function is for note resolution.

I tried to get at the known interval sequences in the Scale class, but not sure if that’s even possible…

``````SCALE = lambda{
ionian_sequence     = [2, 2, 1, 2, 2, 2, 1]
hex_sequence        = [2, 2, 1, 2, 2, 3]
pentatonic_sequence = [3, 2, 2, 3, 2]
``````

then I reviewed a few related topics. Whilst I didn’t see anything that seemed identical to this, I’d be surprised if this is the first!

First version simply produces the notes for a given scale and mode by rotating.

``````
define :stm do |s = :major, t = 0, m = 1|
scale_steps = []
(Array scale t, s).to_a.each_cons(2) { |a, b| scale_steps << b - a }
scale_steps.rotate!(m-1)
notes = [t] #v1

scale_steps.each_with_index {|s,i| notes << notes[i]+s}
return notes
end

puts stm :major, 60, 2
puts scale :c, :dorian

``````

To make the method return the scale at given mode I added a start_pos variable, which I’m decrementing like with the mode indexer m

I thought it seemed to work a bit before “breaking” where the tonic stops climbing…

I tried to compare notes, but don’t think I’m quite there yet, with developing dorian functions and stuff like this

``````#WIP
define :stm do |s = :major, t = 0, m = 1, start_pos = 1|
scale_steps = []

(Array scale t, s).to_a.each_cons(2) { |a, b| scale_steps << b - a }
scale_steps.rotate!(m-1)

n = start_pos - 1
scale_steps.first(n).each {|s| t += s}
notes = [t] #v1

scale_steps.each_with_index {|s,i| notes << notes[i]+s}
return notes
end
``````

a test-loop

``````uncomment do
live_loop :scaling, init: 1 do |i|
use_synth :piano
tonic = :d
##| scale :c,  :melodic_minor
scl = :major
current_scale = stm scl, tonic, i, i
puts current_scale, i
play_pattern_timed current_scale, 0.25
wait 1
i+=1
end
end
``````

Optional-tags: `this doesn't work yet! buggy!! scales idea! pre-creation WIP`

Just putting this out there for feedback and stuff

1 Like

I thought it seemed to work a bit before “breaking” where the tonic stops climbing…

I played with rings first, suspecting indexed array items was the issue, eg you can’t “get 6” from an array of 3, and expect repetition, like a ring…

I retested and found `puts [0,1,2].ring.take(6)` yields the expected, so revised the line that instantiates first “modal-tonic” and think I fixed that

original - I tried to ring, then get first(n)
`scale_steps.first(n).each {|s| t += s}`

fix
`scale_steps.ring.take(n).each {|s| t += s}`

Originally I’d attempted to make notes a ring, but then I can’t add to it with the array.add operator `<<` - is there a way to “push” to a ring? Just curious!

``````define :stm do |s = :major, t = 0, m = 1, start_pos = 1|
scale_steps = []

(Array scale t, s).to_a.each_cons(2) { |a, b| scale_steps << b - a }
scale_steps.rotate!(m-1)

n = start_pos - 1
scale_steps.ring.take(n).each {|s| t += s}
notes = [t] #v1

scale_steps.each_with_index {|s,i| notes << notes[i]+s}
return notes
end
``````

don’t think I’m quite there yet, with developing dorian functions and stuff like this

That GPT 5 is able to comprehend me is astonishing enough. I got a bit of help for the dorian transform function bit…

Don’t ask me how these will be used yet, or why!

``````define :stm do |scale_type, tonic, mode|
scale_steps = []
(Array scale tonic, scale_type).to_a.each_cons(2) { |a, b| scale_steps << b - a }
scale_steps.rotate!(mode.zero? ? 0 : mode - 1)

current_note = tonic
notes = [current_note]
scale_steps.each { |step| notes << (current_note += step) }

return notes
end

define :generate_modes do |scale_type, tonic|
(1..7).map { |mode| stm(scale_type, tonic, mode) }
end

define :compare_scales do |original, transformed|
original.zip(transformed).map { |o, t| t - o }
end

# Example usage
scale_type = :major
tonic = :c
original_scale = stm(scale_type, tonic, 1) # Mode 1 (original major scale)

modes = generate_modes(scale_type, tonic)
modes.each_with_index do |mode_scale, index|
puts "Mode #{index + 1}: #{mode_scale}"
``````a = (ring 2, 4, 6)