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.
Constant Summary
collapse
- TRICHORD_INTERVALS =
[
%w[M3 P5], %w[m3 P5], %w[m3 d5], %w[M3 A5], %w[P4 P5], %w[M2 P5] ].freeze
- 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] ].freeze
- ALTERATION_SIGNS =
{-2 => "bb", -1 => "b", 0 => "", 1 => "#", 2 => "##"}.freeze
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
#diatonic_spellings ⇒ Object
137
138
139
|
# File 'lib/head_music/analysis/dyad.rb', line 137
def diatonic_spellings
@diatonic_spellings ||= key.scale.spellings
end
|
#enharmonic_equivalents_for(pitch) ⇒ Object
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
# File 'lib/head_music/analysis/dyad.rb', line 162
def enharmonic_equivalents_for(pitch)
target_pitch_class = pitch.pitch_class
equivalents = [pitch]
HeadMusic::Rudiment::LetterName.all.each do |letter_name|
ALTERATION_SIGNS.each_value do |sign|
spelling = HeadMusic::Rudiment::Spelling.get("#{letter_name}#{sign}")
next unless spelling && spelling.pitch_class == target_pitch_class
next if equivalents.any? { |equiv| equiv.spelling == spelling }
equivalents << HeadMusic::Rudiment::Pitch.fetch_or_create(spelling, pitch.register)
end
end
equivalents
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
121
122
123
124
125
126
127
|
# File 'lib/head_music/analysis/dyad.rb', line 121
def filter_by_key(pitch_collections)
return pitch_collections unless key
pitch_collections.select do |pitch_collection|
pitch_collection.pitches.all? { |pitch| diatonic_spellings.include?(pitch.spelling) }
end
end
|
#generate_enharmonic_respellings ⇒ Object
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
# File 'lib/head_music/analysis/dyad.rb', line 141
def generate_enharmonic_respellings
respellings = []
pitch1_equivalents = enharmonic_equivalents_for(pitch1)
pitch2_equivalents = enharmonic_equivalents_for(pitch2)
pitch1_equivalents.each do |lower|
pitch2_equivalents.each do |upper|
next if lower.spelling == pitch1.spelling && upper.spelling == pitch2.spelling
respellings << self.class.new(lower, upper, key: key)
end
end
respellings
end
|
#generate_possible_chords(interval_sets) ⇒ Object
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
# File 'lib/head_music/analysis/dyad.rb', line 101
def generate_possible_chords(interval_sets)
dyad_pitch_classes = [lower_pitch.pitch_class, upper_pitch.pitch_class]
chords = []
HeadMusic::Rudiment::Spelling::CHROMATIC_SPELLINGS.each do |root_spelling|
root_pitch = HeadMusic::Rudiment::Pitch.get("#{root_spelling}4")
interval_sets.each do |intervals|
chord_pitches = [root_pitch] + intervals.map { |name| HeadMusic::Analysis::DiatonicInterval.get(name).above(root_pitch) }
pitch_collection = HeadMusic::Analysis::PitchCollection.new(chord_pitches)
if dyad_pitch_classes.all? { |pc| pitch_collection.pitch_classes.include?(pc) }
chords << pitch_collection
end
end
end
chords.uniq { |chord| chord.pitch_classes.sort.map(&:to_i) }
end
|
#generate_possible_seventh_chords ⇒ Object
97
98
99
|
# File 'lib/head_music/analysis/dyad.rb', line 97
def generate_possible_seventh_chords
generate_possible_chords(SEVENTH_CHORD_INTERVALS)
end
|
#generate_possible_trichords ⇒ Object
93
94
95
|
# File 'lib/head_music/analysis/dyad.rb', line 93
def generate_possible_trichords
generate_possible_chords(TRICHORD_INTERVALS)
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
129
130
131
132
133
134
135
|
# File 'lib/head_music/analysis/dyad.rb', line 129
def sort_by_diatonic_agreement(pitch_collections)
return pitch_collections unless key
pitch_collections.sort_by do |pitch_collection|
-pitch_collection.pitches.count { |pitch| diatonic_spellings.include?(pitch.spelling) }
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
|