/
monkeypatches.rb
136 lines (121 loc) · 3.23 KB
/
monkeypatches.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module RangeZiffers
include SonicPi::Lang::WesternTheory
def to_z
self.to_a.map {|degree| get_ziff(degree) }
end
end
Range.include RangeZiffers
module NoteHelper
include SonicPi::Lang::WesternTheory
def to_h
(note_info self).to_h
end
end
Integer.include NoteHelper
class SonicPi::Scale
def self.patch(scales)
scales.each { |name, intervals|
self::SCALE[name] = intervals unless self::SCALE.key? name
}
end
def initialize(tonic, name, num_octaves=1)
if name.is_a?(Array)
intervals = name
name = :custom
elsif name.is_a?(Integer)
intervals = number_to_scale name
name = :custom
else
name = name.to_sym
intervals = SCALE[name]
end
unless intervals
begin
cents = parse_scala name
intervals = cents_to_semitones cents
rescue Exception
raise InvalidScaleError, "Invalid scale: #{name.inspect}"
end
end
raise InvalidScaleError, "Unknown scale name: #{name.inspect}" unless intervals
intervals = intervals * num_octaves
current = SonicPi::Note.resolve_midi_note(tonic)
res = [current]
intervals.each do |i|
current += i
res << current
end
@name = name
@tonic = tonic
@num_octaves = num_octaves
@notes = res
super(res)
end
end
class SonicPi::Chord
def self.patch(chords)
chords.each { |name, intervals|
unless self::CHORD.key? name.to_sym
self::CHORD[name.to_sym] = intervals
self::CHORD_LOOKUP[name.to_sym] = intervals
self::CHORD_NAMES.append(name)
end
}
end
end
#Missing scales based on: https://www.newjazz.dk/Compendiums/scales_of_harmonies.pdf
scales = lambda {
ionian1s = [1,2,1,2,2,2,2]
ionian5s = [2,2,1,3,1,2,1]
ionian6b = [2,2,1,2,1,3,1]
{
# Family 2
:ionian1s=>ionian1s,
:dorian7s=>ionian1s.rotate(1),
:phrygian6s=>ionian1s.rotate(2),
:lydian5s=>ionian1s.rotate(3),
:mixolydian4s=>ionian1s.rotate(4),
:aeolian3s=>ionian1s.rotate(5),
:locrian2s=>ionian1s.rotate(6),
# Family 3
:ionian5s=>ionian5s,
:dorian4s=>ionian5s.rotate(1),
:phrygian3s=>ionian5s.rotate(2),
:lydian2s=>ionian5s.rotate(3),
:mixolydian1s=>ionian5s.rotate(4),
:aeolian7s=>ionian5s.rotate(5),
:locrian6s=>ionian5s.rotate(6),
# Family 4
:ionian6b=>ionian6b,
:dorian5b=>ionian6b.rotate(1),
:phrygian4b=>ionian6b.rotate(2),
:lydian3b=>ionian6b.rotate(3),
:mixolydian2b=>ionian6b.rotate(4),
:aeolian1b=>ionian6b.rotate(5),
:locrian7b=>ionian6b.rotate(6),
}
}.call
chords = {
# https://en.wikipedia.org/wiki/Minor_major_seventh_chord
'mM7'=> [0, 3, 7, 11],
# https://en.wikipedia.org/wiki/Augmented_major_seventh_chord
'maj7+5'=> [0, 4, 8, 11],
'6+5'=> [0, 4, 8, 9],
# Missing majot 7 suspended chords
'maj7'=> [0, 2, 4, 6], # Same as ^major7
'maj7sus2'=> [0, 4, 6],
'maj7sus4'=> [0, 2, 6],
# Missing altered chords: https://en.wikipedia.org/wiki/Altered_chord
'7-5-3'=>[0, 3, 6, 10],
'7+5+9'=>[0, 4, 8, 10, 14],
'7-5-9'=>[0, 4, 6, 10, 13],
'7-5+9'=>[0, 4, 6, 10, 14]
}
SonicPi::Scale.patch(scales)
SonicPi::Chord.patch(chords)
def zlog text
File.open(ENV['HOME']+'/.sonic-pi/log/ziffers.log', 'a') {|log|
log.print text
log.print "\n"
}
end