Skip to content

Instantly share code, notes, and snippets.

@mhfs
Created July 9, 2010 02:43
Show Gist options
  • Save mhfs/468966 to your computer and use it in GitHub Desktop.
Save mhfs/468966 to your computer and use it in GitHub Desktop.
class Note; end
class C < Note; end
class Cs < C; end
class D < Note; end
class Db < D; end
class Ds < D; end
class E < Note; end
class Eb < E; end
class F < Note; end
class Fs < F; end
class G < Note; end
class Gb < G; end
class Gs < G; end
class A < Note; end
class Ab < A; end
class As < A; end
class B < Note; end
class Bb < B; end
module DiatonicScale
NOTES = [C, Cs, D, Ds, E, F, Fs, G, Gs, A, As, B]
DISTANCES = [2, 2, 1, 2, 2, 2]
INDEXES = {
C => 0,
Cs => 1, Db => 1,
D => 2,
Ds => 3, Eb => 3,
E => 4,
F => 5,
Fs => 6, Gb => 6,
G => 7,
Gs => 8, Ab => 8,
A => 9,
As => 10, Bb => 10,
B => 11
}
ADJUSTMENTS = {
Cs => Db,
Ds => Eb,
Fs => Gb,
Gs => Ab,
As => Bb
}
def + (distance)
NOTES[(INDEXES[self] + distance) % NOTES.size]
end
def diatonic_scale
DISTANCES.inject([self]) { |result, distance| result << adjust(result.last, result.last + distance) }
end
def adjust(prev, result)
result.superclass != prev ? result : ADJUSTMENTS[result]
end
end
Note.extend DiatonicScale
require 'test/unit'
class DiatonicScalesTest < Test::Unit::TestCase
def test_C
assert_equal [C, D, E, F, G, A, B], C.diatonic_scale
end
def test_D
assert_equal [D, E, Fs, G, A, B, Cs], D.diatonic_scale
end
def test_E
assert_equal [E, Fs, Gs, A, B, Cs, Ds], E.diatonic_scale
end
def test_F
assert_equal [F, G, A, Bb, C, D, E], F.diatonic_scale
end
def test_G
assert_equal [G, A, B, C, D, E, Fs], G.diatonic_scale
end
def test_A
assert_equal [A, B, Cs, D, E, Fs, Gs], A.diatonic_scale
end
def test_B
assert_equal [B, Cs, Ds, E, Fs, Gs, As], B.diatonic_scale
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment