Class: HeadMusic::Analysis::PitchClassSet
- Inherits:
-
Object
- Object
- HeadMusic::Analysis::PitchClassSet
- Defined in:
- lib/head_music/analysis/pitch_class_set.rb
Overview
A PitchClassSet represents a pitch-class set or pitch collection. See also: PitchCollection, PitchClass
Instance Attribute Summary collapse
-
#pitch_classes ⇒ Object
readonly
Returns the value of attribute pitch_classes.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#compare_forms(form1, form2) ⇒ Object
private
Compare two normal forms and return the more compact one If equal, return the first one.
- #decachord? ⇒ Boolean
- #dichord? ⇒ Boolean (also: #dyad?)
- #dodecachord? ⇒ Boolean
- #equivalent?(other) ⇒ Boolean
-
#find_most_compact_rotation(rotations) ⇒ Object
private
Find the most compact rotation Returns the rotation with the smallest span In case of tie, prefer the one with smaller intervals from the left.
-
#generate_rotations ⇒ Object
private
Generate all rotations of the pitch class set.
- #heptachord? ⇒ Boolean
- #hexachord? ⇒ Boolean
-
#initialize(identifiers) ⇒ PitchClassSet
constructor
A new instance of PitchClassSet.
-
#inversion ⇒ Object
Returns the inversion of the pitch class set Inversion maps each pitch class to its inverse around 0 For pitch class n, the inversion is (12 - n) mod 12.
- #monochord? ⇒ Boolean (also: #monad?)
- #nonachord? ⇒ Boolean
-
#normal_form ⇒ Object
Returns the normal form of the pitch class set The normal form is the most compact rotation of the set Algorithm: 1.
- #octachord? ⇒ Boolean
- #pentachord? ⇒ Boolean
-
#prime_form ⇒ Object
Returns the prime form of the pitch class set The prime form is the most compact form among the normal form and its inversion Algorithm: 1.
- #size ⇒ Object
- #tetrachord? ⇒ Boolean
- #to_s ⇒ Object (also: #inspect)
-
#transpose_to_zero(pcs) ⇒ Object
private
Transpose a set of pitch classes to start at 0.
- #trichord? ⇒ Boolean
- #undecachord? ⇒ Boolean
Constructor Details
#initialize(identifiers) ⇒ PitchClassSet
Returns a new instance of PitchClassSet.
12 13 14 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 12 def initialize(identifiers) @pitch_classes = identifiers.map { |identifier| HeadMusic::Rudiment::PitchClass.get(identifier) }.uniq.sort end |
Instance Attribute Details
#pitch_classes ⇒ Object (readonly)
Returns the value of attribute pitch_classes.
7 8 9 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 7 def pitch_classes @pitch_classes end |
Instance Method Details
#==(other) ⇒ Object
21 22 23 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 21 def ==(other) pitch_classes == other.pitch_classes end |
#compare_forms(form1, form2) ⇒ Object (private)
Compare two normal forms and return the more compact one If equal, return the first one
162 163 164 165 166 167 168 169 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 162 def compare_forms(form1, form2) normalized1 = transpose_to_zero(form1).map(&:to_i) normalized2 = transpose_to_zero(form2).map(&:to_i) # Compare lexicographically element by element comparison = normalized1 <=> normalized2 (comparison && comparison <= 0) ? form1 : form2 end |
#decachord? ⇒ Boolean
71 72 73 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 71 def decachord? size == 10 end |
#dichord? ⇒ Boolean Also known as: dyad?
38 39 40 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 38 def dichord? size == 2 end |
#dodecachord? ⇒ Boolean
79 80 81 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 79 def dodecachord? size == 12 end |
#equivalent?(other) ⇒ Boolean
25 26 27 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 25 def equivalent?(other) pitch_classes == other.pitch_classes end |
#find_most_compact_rotation(rotations) ⇒ Object (private)
Find the most compact rotation Returns the rotation with the smallest span In case of tie, prefer the one with smaller intervals from the left
153 154 155 156 157 158 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 153 def find_most_compact_rotation(rotations) rotations.min_by do |rotation| # Create a comparison key: [span, intervals from left] [rotation.last] + rotation end end |
#generate_rotations ⇒ Object (private)
Generate all rotations of the pitch class set
138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 138 def generate_rotations return [pitch_classes] if size <= 1 numbers = pitch_classes.map(&:to_i) (0...size).map do |i| rotation = numbers.rotate(i) # Normalize each rotation to start from the first element first = rotation.first rotation.map { |n| (n - first) % 12 } end end |
#heptachord? ⇒ Boolean
59 60 61 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 59 def heptachord? size == 7 end |
#hexachord? ⇒ Boolean
55 56 57 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 55 def hexachord? size == 6 end |
#inversion ⇒ Object
Returns the inversion of the pitch class set Inversion maps each pitch class to its inverse around 0 For pitch class n, the inversion is (12 - n) mod 12
86 87 88 89 90 91 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 86 def inversion @inversion ||= self.class.new( pitch_classes.map { |pc| (12 - pc.to_i) % 12 } ) end |
#monochord? ⇒ Boolean Also known as: monad?
33 34 35 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 33 def monochord? size == 1 end |
#nonachord? ⇒ Boolean
67 68 69 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 67 def nonachord? size == 9 end |
#normal_form ⇒ Object
Returns the normal form of the pitch class set The normal form is the most compact rotation of the set Algorithm:
- Generate all rotations of the pitch class set
- For each rotation, calculate the span (difference between first and last)
- Choose the rotation with the smallest span
- If there's a tie, choose the one with the smallest intervals from the left
100 101 102 103 104 105 106 107 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 100 def normal_form return self if size <= 1 @rotations ||= generate_rotations @most_compact_rotation ||= find_most_compact_rotation(@rotations) self.class.new(@most_compact_rotation) end |
#octachord? ⇒ Boolean
63 64 65 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 63 def octachord? size == 8 end |
#pentachord? ⇒ Boolean
51 52 53 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 51 def pentachord? size == 5 end |
#prime_form ⇒ Object
Returns the prime form of the pitch class set The prime form is the most compact form among the normal form and its inversion Algorithm:
- Find the normal form of the original set
- Find the normal form of the inverted set
- Compare and choose the most compact one
- Transpose to start at 0
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 116 def prime_form @prime_form ||= begin # Handle edge cases return self if size.zero? return self.class.new([0]) if size == 1 normal = normal_form.pitch_classes inverted_normal = inversion.normal_form.pitch_classes # Compare which is more compact chosen = compare_forms(normal, inverted_normal) # Transpose to start at 0 transposed = transpose_to_zero(chosen) self.class.new(transposed) end end |
#size ⇒ Object
29 30 31 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 29 def size @size ||= pitch_classes.length end |
#tetrachord? ⇒ Boolean
47 48 49 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 47 def tetrachord? size == 4 end |
#to_s ⇒ Object Also known as: inspect
16 17 18 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 16 def to_s pitch_classes.map(&:to_i).inspect end |
#transpose_to_zero(pcs) ⇒ Object (private)
Transpose a set of pitch classes to start at 0
172 173 174 175 176 177 178 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 172 def transpose_to_zero(pcs) return pcs if pcs.empty? numbers = pcs.map(&:to_i) first = numbers.first numbers.map { |n| HeadMusic::Rudiment::PitchClass.get((n - first) % 12) } end |
#trichord? ⇒ Boolean
43 44 45 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 43 def trichord? size == 3 end |
#undecachord? ⇒ Boolean
75 76 77 |
# File 'lib/head_music/analysis/pitch_class_set.rb', line 75 def undecachord? size == 11 end |