Class: HeadMusic::Analysis::Dyad
- Inherits:
-
Object
- Object
- HeadMusic::Analysis::Dyad
show all
- Defined in:
- lib/head_music/analysis/dyad.rb
Overview
A Dyad is a two-pitch combination that can imply various chords.
It analyzes the harmonic implications of two pitches sounding together.
Instance Attribute Summary collapse
Instance Method Summary
collapse
Constructor Details
#initialize(pitch1, pitch2, key: nil) ⇒ Dyad
Returns a new instance of Dyad.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args, &block) ⇒ Object
61
62
63
|
# File 'lib/head_music/analysis/dyad.rb', line 61
def method_missing(method_name, *args, &block)
respond_to_missing?(method_name) ? interval.send(method_name, *args, &block) : super
end
|
Instance Attribute Details
#key ⇒ Object
Returns the value of attribute key.
7
8
9
|
# File 'lib/head_music/analysis/dyad.rb', line 7
def key
@key
end
|
#pitch1 ⇒ Object
Returns the value of attribute pitch1.
7
8
9
|
# File 'lib/head_music/analysis/dyad.rb', line 7
def pitch1
@pitch1
end
|
#pitch2 ⇒ Object
Returns the value of attribute pitch2.
7
8
9
|
# File 'lib/head_music/analysis/dyad.rb', line 7
def pitch2
@pitch2
end
|
Instance Method Details
#alteration_sign(semitones) ⇒ Object
220
221
222
223
224
225
226
227
228
|
# File 'lib/head_music/analysis/dyad.rb', line 220
def alteration_sign(semitones)
case semitones
when -2 then "bb"
when -1 then "b"
when 0 then ""
when 1 then "#"
when 2 then "##"
end
end
|
#enharmonic_respellings ⇒ Object
53
54
55
|
# File 'lib/head_music/analysis/dyad.rb', line 53
def enharmonic_respellings
@enharmonic_respellings ||= generate_enharmonic_respellings
end
|
#filter_by_key(pitch_collections) ⇒ Object
155
156
157
158
159
160
161
162
163
|
# File 'lib/head_music/analysis/dyad.rb', line 155
def filter_by_key(pitch_collections)
return pitch_collections unless key
diatonic_spellings = key.scale.spellings
pitch_collections.select do |pitch_collection|
pitch_collection.pitches.all? { |pitch| diatonic_spellings.include?(pitch.spelling) }
end
end
|
#generate_enharmonic_respellings ⇒ Object
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
# File 'lib/head_music/analysis/dyad.rb', line 177
def generate_enharmonic_respellings
respellings = []
pitch1_equivalents = get_enharmonic_equivalents(pitch1)
pitch2_equivalents = get_enharmonic_equivalents(pitch2)
pitch1_equivalents.each do |p1|
pitch2_equivalents.each do |p2|
next if p1.spelling == pitch1.spelling && p2.spelling == pitch2.spelling
respellings << self.class.new(p1, p2, key: key)
end
end
respellings
end
|
#generate_possible_seventh_chords ⇒ Object
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
# File 'lib/head_music/analysis/dyad.rb', line 111
def generate_possible_seventh_chords
seventh_chords = []
pitch_classes = [lower_pitch.pitch_class, upper_pitch.pitch_class]
HeadMusic::Rudiment::Spelling::CHROMATIC_SPELLINGS.each do |root_spelling|
root_pitch = HeadMusic::Rudiment::Pitch.get("#{root_spelling}4")
seventh_chord_intervals = [
%w[M3 P5 M7], %w[M3 P5 m7], %w[m3 P5 m7], %w[m3 P5 M7], %w[m3 d5 m7], %w[m3 d5 d7], %w[M2 M3 P5 m7], %w[m2 M3 P5 m7], %w[M2 m3 P5 m7], %w[M2 M3 P5 M7] ]
seventh_chord_intervals.each do |intervals|
chord_pitches = [root_pitch]
intervals.each do |interval_name|
interval = HeadMusic::Analysis::DiatonicInterval.get(interval_name)
next_pitch = interval.above(root_pitch)
chord_pitches << next_pitch
end
pitch_collection = HeadMusic::Analysis::PitchCollection.new(chord_pitches)
chord_pitch_classes = pitch_collection.pitch_classes
if pitch_classes.all? { |pc| chord_pitch_classes.include?(pc) }
seventh_chords << pitch_collection
end
end
end
seventh_chords.uniq { |c| c.pitch_classes.sort.map(&:to_i) }
end
|
#generate_possible_trichords ⇒ Object
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
|
# File 'lib/head_music/analysis/dyad.rb', line 71
def generate_possible_trichords
trichords = []
pitch_classes = [lower_pitch.pitch_class, upper_pitch.pitch_class]
HeadMusic::Rudiment::Spelling::CHROMATIC_SPELLINGS.each do |root_spelling|
root_pitch = HeadMusic::Rudiment::Pitch.get("#{root_spelling}4")
trichord_intervals = [
%w[M3 P5], %w[m3 P5], %w[m3 d5], %w[M3 A5], %w[P4 P5], %w[M2 P5] ]
trichord_intervals.each do |intervals|
trichord_pitches = [root_pitch]
intervals.each do |interval_name|
interval = HeadMusic::Analysis::DiatonicInterval.get(interval_name)
next_pitch = interval.above(root_pitch)
trichord_pitches << next_pitch
end
pitch_collection = HeadMusic::Analysis::PitchCollection.new(trichord_pitches)
trichord_pitch_classes = pitch_collection.pitch_classes
if pitch_classes.all? { |pc| trichord_pitch_classes.include?(pc) }
trichords << pitch_collection
end
end
end
trichords.uniq { |t| t.pitch_classes.sort.map(&:to_i) }
end
|
#get_enharmonic_equivalents(pitch) ⇒ Object
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
# File 'lib/head_music/analysis/dyad.rb', line 198
def get_enharmonic_equivalents(pitch)
equivalents = [pitch]
pitch_class = pitch.pitch_class
letter_names = HeadMusic::Rudiment::LetterName.all
letter_names.each do |letter_name|
[-2, -1, 0, 1, 2].each do |alteration_semitones|
spelling = HeadMusic::Rudiment::Spelling.get("#{letter_name}#{alteration_sign(alteration_semitones)}")
next unless spelling
if spelling.pitch_class == pitch_class
equivalent_pitch = HeadMusic::Rudiment::Pitch.fetch_or_create(spelling, pitch.register)
equivalents << equivalent_pitch unless equivalents.any? { |p| p.spelling == spelling }
end
end
end
equivalents
end
|
#lower_pitch ⇒ Object
25
26
27
|
# File 'lib/head_music/analysis/dyad.rb', line 25
def lower_pitch
@lower_pitch ||= [pitch1, pitch2].min
end
|
#pitches ⇒ Object
21
22
23
|
# File 'lib/head_music/analysis/dyad.rb', line 21
def pitches
[pitch1, pitch2]
end
|
#possible_seventh_chords ⇒ Object
45
46
47
48
49
50
51
|
# File 'lib/head_music/analysis/dyad.rb', line 45
def possible_seventh_chords
@possible_seventh_chords ||= begin
seventh_chords = generate_possible_seventh_chords
seventh_chords = filter_by_key(seventh_chords) if key
sort_by_diatonic_agreement(seventh_chords)
end
end
|
#possible_triads ⇒ Object
41
42
43
|
# File 'lib/head_music/analysis/dyad.rb', line 41
def possible_triads
@possible_triads ||= possible_trichords.select(&:triad?)
end
|
#possible_trichords ⇒ Object
33
34
35
36
37
38
39
|
# File 'lib/head_music/analysis/dyad.rb', line 33
def possible_trichords
@possible_trichords ||= begin
trichords = generate_possible_trichords
trichords = filter_by_key(trichords) if key
sort_by_diatonic_agreement(trichords)
end
end
|
#respond_to_missing?(method_name, *_args) ⇒ Boolean
65
66
67
|
# File 'lib/head_music/analysis/dyad.rb', line 65
def respond_to_missing?(method_name, *_args)
interval.respond_to?(method_name)
end
|
#sort_by_diatonic_agreement(pitch_collections) ⇒ Object
165
166
167
168
169
170
171
172
173
174
175
|
# File 'lib/head_music/analysis/dyad.rb', line 165
def sort_by_diatonic_agreement(pitch_collections)
return pitch_collections unless key
diatonic_spellings = key.scale.spellings
pitch_collections.sort_by do |pitch_collection|
diatonic_count = pitch_collection.pitches.count { |pitch| diatonic_spellings.include?(pitch.spelling) }
-diatonic_count end
end
|
#to_s ⇒ Object
57
58
59
|
# File 'lib/head_music/analysis/dyad.rb', line 57
def to_s
"#{pitch1} - #{pitch2}"
end
|
#upper_pitch ⇒ Object
29
30
31
|
# File 'lib/head_music/analysis/dyad.rb', line 29
def upper_pitch
@upper_pitch ||= [pitch1, pitch2].max
end
|