Class: MTK::Groups::PitchClassSet
- Inherits:
-
Object
- Object
- MTK::Groups::PitchClassSet
- Includes:
- PitchCollection
- Defined in:
- lib/mtk/groups/pitch_class_set.rb
Overview
An ordered collection of PitchClasses.
Unlike a mathematical Set, a PitchClassSet is ordered and may contain duplicates.
Instance Attribute Summary collapse
-
#pitch_classes ⇒ Object
readonly
Returns the value of attribute pitch_classes.
Class Method Summary collapse
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#=~(other) ⇒ Object
Compare for equality, ignoring order and duplicates.
-
#complement ⇒ Object
the collection of elements that are not members of this set.
-
#difference(other) ⇒ Object
the collection of elements from this set with any elements from the other set removed.
- #elements ⇒ Object
-
#initialize(pitch_classes) ⇒ PitchClassSet
constructor
A new instance of PitchClassSet.
- #inspect ⇒ Object
-
#intersection(other) ⇒ Object
the collection of elements present in both sets.
- #normal_form ⇒ Object
- #normal_order ⇒ Object
-
#symmetric_difference(other) ⇒ Object
the collection of elements that are members of exactly one of the sets.
- #to_s ⇒ Object
-
#union(other) ⇒ Object
the collection of all elements present in either set.
Methods included from PitchCollection
Methods included from Collection
#[], #clone, #concat, #each, #empty?, #enumerable_map, #first, #last, #map, #partition, #permute, #repeat, #reverse, #rotate, #size, #to_a
Constructor Details
#initialize(pitch_classes) ⇒ PitchClassSet
Returns a new instance of PitchClassSet.
29 30 31 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 29 def initialize(pitch_classes) @pitch_classes = pitch_classes.to_a.clone.freeze end |
Instance Attribute Details
#pitch_classes ⇒ Object (readonly)
Returns the value of attribute pitch_classes.
15 16 17 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 15 def pitch_classes @pitch_classes end |
Class Method Details
.all ⇒ Object
21 22 23 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 21 def self.all @all ||= new(MTK::Lang::PitchClasses::PITCH_CLASSES) end |
.from_a(enumerable) ⇒ Object
42 43 44 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 42 def self.from_a enumerable new enumerable end |
.random_row ⇒ Object
17 18 19 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 17 def self.random_row new(MTK::Lang::PitchClasses::PITCH_CLASSES.shuffle) end |
.span_between(pc1, pc2) ⇒ Object
149 150 151 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 149 def self.span_between(pc1, pc2) (pc2.to_i - pc1.to_i) % 12 end |
Instance Method Details
#==(other) ⇒ Object
119 120 121 122 123 124 125 126 127 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 119 def == other if other.respond_to? :pitch_classes @pitch_classes == other.pitch_classes elsif other.respond_to? :to_a @pitch_classes == other.to_a else @pitch_classes == other end end |
#=~(other) ⇒ Object
Compare for equality, ignoring order and duplicates
131 132 133 134 135 136 137 138 139 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 131 def =~ other @normalized_pitch_classes ||= @pitch_classes.uniq.sort @normalized_pitch_classes == case when other.respond_to?(:pitch_classes) then other.pitch_classes.uniq.sort when (other.is_a? Array and other.frozen?) then other when other.respond_to?(:to_a) then other.to_a.uniq.sort else other end end |
#complement ⇒ Object
the collection of elements that are not members of this set
114 115 116 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 114 def complement self.class.all.difference(self) end |
#difference(other) ⇒ Object
the collection of elements from this set with any elements from the other set removed
104 105 106 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 104 def difference(other) self.class.from_a(to_a - other.to_a) end |
#elements ⇒ Object
34 35 36 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 34 def elements @pitch_classes end |
#inspect ⇒ Object
145 146 147 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 145 def inspect @pitch_classes.inspect end |
#intersection(other) ⇒ Object
the collection of elements present in both sets
94 95 96 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 94 def intersection(other) self.class.from_a(to_a & other.to_a) end |
#normal_form ⇒ Object
87 88 89 90 91 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 87 def normal_form norder = normal_order first_pc_val = norder.first.to_i norder.map{|pitch_class| (pitch_class.to_i - first_pc_val) % 12 } end |
#normal_order ⇒ Object
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 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 46 def normal_order ordering = Array.new(@pitch_classes.uniq.sort) min_span, start_index_for_normal_order = nil, nil # check every rotation for the minimal span: size.times do |index| span = self.class.span_between ordering.first, ordering.last if min_span.nil? or span < min_span # best so far min_span = span start_index_for_normal_order = index elsif span == min_span # handle ties, minimize distance between first and second-to-last note, then first and third-to-last, etc span1, span2 = nil, nil tie_breaker = 1 while span1 == span2 and tie_breaker < size span1 = self.class.span_between( ordering[0], ordering[-1 - tie_breaker] ) span2 = self.class.span_between( ordering[start_index_for_normal_order], ordering[start_index_for_normal_order - tie_breaker] ) tie_breaker -= 1 end if span1 != span2 # tie cannot be broken, pick the one starting with the lowest pitch class if ordering[0].to_i < ordering[start_index_for_normal_order].to_i start_index_for_normal_order = index end elsif span1 < span2 start_index_for_normal_order = index end end ordering << ordering.shift # rotate end # we've rotated all the way around, so we now need to rotate back to the start index we just found: start_index_for_normal_order.times{ ordering << ordering.shift } ordering end |
#symmetric_difference(other) ⇒ Object
the collection of elements that are members of exactly one of the sets
109 110 111 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 109 def symmetric_difference(other) union(other).difference( intersection(other) ) end |
#to_s ⇒ Object
141 142 143 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 141 def to_s @pitch_classes.join(' ') end |
#union(other) ⇒ Object
the collection of all elements present in either set
99 100 101 |
# File 'lib/mtk/groups/pitch_class_set.rb', line 99 def union(other) self.class.from_a(to_a | other.to_a) end |