Class: HeadMusic::Analysis::PitchCollection
- Inherits:
-
Object
- Object
- HeadMusic::Analysis::PitchCollection
- Defined in:
- lib/head_music/analysis/pitch_collection.rb
Overview
A PitchCollection is a collection of one or more pitches with specific registers. In music theory, "pitch collection" refers to an ordered or unordered group of actual pitches, as distinct from a "pitch-class set" which abstracts away register and octave equivalence. See also: PitchClassSet
Constant Summary collapse
- TERTIAN_SONORITIES =
{ implied_triad: [3], triad: [3, 5], seventh_chord: [3, 5, 7], ninth_chord: [2, 3, 5, 7], eleventh_chord: [2, 3, 4, 5, 7], thirteenth_chord: [2, 3, 4, 5, 6, 7] # a.k.a. diatonic scale }.freeze
Instance Attribute Summary collapse
-
#pitches ⇒ Object
readonly
Returns the value of attribute pitches.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #augmented_triad? ⇒ Boolean
- #bass_pitch ⇒ Object
- #consonant_triad? ⇒ Boolean
- #diatonic_intervals ⇒ Object
- #diatonic_intervals_above_bass_pitch ⇒ Object
- #diminished_triad? ⇒ Boolean
- #eleventh_chord? ⇒ Boolean
- #equivalent?(other) ⇒ Boolean
- #first_inversion_seventh_chord? ⇒ Boolean
- #first_inversion_triad? ⇒ Boolean
-
#initialize(pitches) ⇒ PitchCollection
constructor
A new instance of PitchCollection.
- #inspect ⇒ Object
- #integer_notation ⇒ Object
- #invert ⇒ Object
- #major_triad? ⇒ Boolean
- #minor_triad? ⇒ Boolean
- #ninth_chord? ⇒ Boolean
- #pitch_class_set ⇒ Object
- #pitch_classes ⇒ Object
- #pitches_above_bass_pitch ⇒ Object
- #reduction ⇒ Object
- #reduction_pitches ⇒ Object private
- #root_position_seventh_chord? ⇒ Boolean
- #root_position_triad? ⇒ Boolean
- #scale_degrees ⇒ Object
- #scale_degrees_above_bass_pitch ⇒ Object
- #second_inversion_seventh_chord? ⇒ Boolean
- #second_inversion_triad? ⇒ Boolean
- #seventh_chord? ⇒ Boolean
- #size ⇒ Object
- #sonority ⇒ Object
- #tertian? ⇒ Boolean
- #third_inversion_seventh_chord? ⇒ Boolean
- #thirteenth_chord? ⇒ Boolean
- #to_s ⇒ Object
- #triad? ⇒ Boolean
- #uninvert ⇒ Object
Constructor Details
#initialize(pitches) ⇒ PitchCollection
Returns a new instance of PitchCollection.
27 28 29 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 27 def initialize(pitches) @pitches = pitches.map { |pitch| HeadMusic::Rudiment::Pitch.get(pitch) }.sort.uniq end |
Instance Attribute Details
#pitches ⇒ Object (readonly)
Returns the value of attribute pitches.
18 19 20 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 18 def pitches @pitches end |
Instance Method Details
#==(other) ⇒ Object
93 94 95 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 93 def ==(other) pitches.sort == other.pitches.sort end |
#augmented_triad? ⇒ Boolean
125 126 127 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 125 def augmented_triad? [%w[M3 M3], %w[M3 d4], %w[d4 M3]].include? reduction_diatonic_intervals.map(&:shorthand) end |
#bass_pitch ⇒ Object
81 82 83 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 81 def bass_pitch @bass_pitch ||= pitches.first end |
#consonant_triad? ⇒ Boolean
109 110 111 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 109 def consonant_triad? major_triad? || minor_triad? end |
#diatonic_intervals ⇒ Object
43 44 45 46 47 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 43 def diatonic_intervals @diatonic_intervals ||= pitches.each_cons(2).map do |pitch_pair| HeadMusic::Analysis::DiatonicInterval.new(*pitch_pair) end end |
#diatonic_intervals_above_bass_pitch ⇒ Object
49 50 51 52 53 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 49 def diatonic_intervals_above_bass_pitch @diatonic_intervals_above_bass_pitch ||= pitches_above_bass_pitch.map do |pitch| HeadMusic::Analysis::DiatonicInterval.new(bass_pitch, pitch) end end |
#diminished_triad? ⇒ Boolean
121 122 123 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 121 def diminished_triad? [%w[m3 m3], %w[m3 A4], %w[A4 m3]].include? reduction_diatonic_intervals.map(&:shorthand) end |
#eleventh_chord? ⇒ Boolean
165 166 167 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 165 def eleventh_chord? hexachord? && tertian? end |
#equivalent?(other) ⇒ Boolean
97 98 99 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 97 def equivalent?(other) pitch_classes.sort == other.pitch_classes.sort end |
#first_inversion_seventh_chord? ⇒ Boolean
149 150 151 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 149 def first_inversion_seventh_chord? tetrachord? && reduction.uninvert.diatonic_intervals.all?(&:third?) end |
#first_inversion_triad? ⇒ Boolean
133 134 135 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 133 def first_inversion_triad? trichord? && reduction.uninvert.diatonic_intervals.all?(&:third?) end |
#inspect ⇒ Object
85 86 87 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 85 def inspect pitches.map(&:to_s).join(" ") end |
#integer_notation ⇒ Object
59 60 61 62 63 64 65 66 67 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 59 def integer_notation # questions: # - should this be absolute? 0 = C? # - should there be both absolute and relative versions? @integer_notation ||= begin return [] if pitches.empty? diatonic_intervals_above_bass_pitch.map { |interval| interval.semitones % 12 }.flatten.sort.unshift(0).uniq end end |
#invert ⇒ Object
69 70 71 72 73 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 69 def invert inverted_pitch = pitches[0] + HeadMusic::Analysis::DiatonicInterval.get("perfect octave") new_pitches = pitches.drop(1) + [inverted_pitch] HeadMusic::Analysis::PitchCollection.new(new_pitches) end |
#major_triad? ⇒ Boolean
113 114 115 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 113 def major_triad? [%w[M3 m3], %w[m3 P4], %w[P4 M3]].include? reduction_diatonic_intervals.map(&:shorthand) end |
#minor_triad? ⇒ Boolean
117 118 119 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 117 def minor_triad? [%w[m3 M3], %w[M3 P4], %w[P4 m3]].include? reduction_diatonic_intervals.map(&:shorthand) end |
#ninth_chord? ⇒ Boolean
161 162 163 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 161 def ninth_chord? pentachord? && tertian? end |
#pitch_class_set ⇒ Object
35 36 37 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 35 def pitch_class_set @pitch_class_set ||= HeadMusic::Analysis::PitchClassSet.new(pitch_classes) end |
#pitch_classes ⇒ Object
31 32 33 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 31 def pitch_classes @pitch_classes ||= reduction_pitches.map(&:pitch_class).uniq end |
#pitches_above_bass_pitch ⇒ Object
55 56 57 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 55 def pitches_above_bass_pitch @pitches_above_bass_pitch ||= pitches.drop(1) end |
#reduction ⇒ Object
39 40 41 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 39 def reduction @reduction ||= HeadMusic::Analysis::PitchCollection.new(reduction_pitches) end |
#reduction_pitches ⇒ Object (private)
198 199 200 201 202 203 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 198 def reduction_pitches pitches.map do |pitch| pitch = HeadMusic::Rudiment::Pitch.fetch_or_create(pitch.spelling, pitch.register - 1) while pitch > bass_pitch + 12 pitch end.sort end |
#root_position_seventh_chord? ⇒ Boolean
145 146 147 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 145 def root_position_seventh_chord? tetrachord? && reduction_diatonic_intervals.all?(&:third?) end |
#root_position_triad? ⇒ Boolean
129 130 131 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 129 def root_position_triad? trichord? && reduction_diatonic_intervals.all?(&:third?) end |
#scale_degrees ⇒ Object
184 185 186 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 184 def scale_degrees @scale_degrees ||= pitches.empty? ? [] : scale_degrees_above_bass_pitch.unshift(1) end |
#scale_degrees_above_bass_pitch ⇒ Object
188 189 190 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 188 def scale_degrees_above_bass_pitch @scale_degrees_above_bass_pitch ||= diatonic_intervals_above_bass_pitch.map(&:simple_number).sort - [8] end |
#second_inversion_seventh_chord? ⇒ Boolean
153 154 155 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 153 def second_inversion_seventh_chord? tetrachord? && reduction.uninvert.uninvert.diatonic_intervals.all?(&:third?) end |
#second_inversion_triad? ⇒ Boolean
137 138 139 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 137 def second_inversion_triad? trichord? && reduction.invert.diatonic_intervals.all?(&:third?) end |
#seventh_chord? ⇒ Boolean
141 142 143 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 141 def seventh_chord? tetrachord? && tertian? end |
#size ⇒ Object
101 102 103 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 101 def size pitches.length end |
#sonority ⇒ Object
192 193 194 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 192 def sonority @sonority ||= HeadMusic::Analysis::Sonority.new(self) end |
#tertian? ⇒ Boolean
173 174 175 176 177 178 179 180 181 182 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 173 def tertian? return false unless diatonic_intervals.any? inversion = reduction pitches.length.times do return true if TERTIAN_SONORITIES.value?(inversion.scale_degrees_above_bass_pitch) inversion = inversion.invert end false end |
#third_inversion_seventh_chord? ⇒ Boolean
157 158 159 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 157 def third_inversion_seventh_chord? tetrachord? && reduction.invert.diatonic_intervals.all?(&:third?) end |
#thirteenth_chord? ⇒ Boolean
169 170 171 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 169 def thirteenth_chord? heptachord? && tertian? end |
#to_s ⇒ Object
89 90 91 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 89 def to_s pitches.map(&:to_s).join(" ") end |
#triad? ⇒ Boolean
105 106 107 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 105 def triad? trichord? && tertian? end |
#uninvert ⇒ Object
75 76 77 78 79 |
# File 'lib/head_music/analysis/pitch_collection.rb', line 75 def uninvert inverted_pitch = pitches[-1] - HeadMusic::Analysis::DiatonicInterval.get("perfect octave") new_pitches = [inverted_pitch] + pitches[0..-2] HeadMusic::Analysis::PitchCollection.new(new_pitches) end |