class MTK::Groups::PitchClassSet
An ordered collection of {PitchClass}es.
Unlike a mathematical Set, a PitchClassSet
is ordered and may contain duplicates.
@see MTK::Groups::Melody
@see MTK::Groups::Chord
Attributes
pitch_classes[R]
Public Class Methods
all()
click to toggle source
# File lib/mtk/groups/pitch_class_set.rb, line 21 def self.all @all ||= new(MTK::Lang::PitchClasses::PITCH_CLASSES) end
from_a(enumerable)
click to toggle source
# File lib/mtk/groups/pitch_class_set.rb, line 42 def self.from_a enumerable new enumerable end
new(pitch_classes)
click to toggle source
@param pitch_classes
[#to_a] the collection of pitch classes
@see MTK#PitchClassSet
# File lib/mtk/groups/pitch_class_set.rb, line 29 def initialize(pitch_classes) @pitch_classes = pitch_classes.to_a.clone.freeze end
random_row()
click to toggle source
# 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)
click to toggle source
# File lib/mtk/groups/pitch_class_set.rb, line 149 def self.span_between(pc1, pc2) (pc2.to_i - pc1.to_i) % 12 end
Public Instance Methods
==(other)
click to toggle source
@param other [#pitch_classes, to_a, Array]
# 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)
click to toggle source
Compare for equality, ignoring order and duplicates @param other [#pitch_classes, Array, to_a]
# 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()
click to toggle source
the collection of elements that are not members of this set
# File lib/mtk/groups/pitch_class_set.rb, line 114 def complement self.class.all.difference(self) end
difference(other)
click to toggle source
the collection of elements from this set with any elements from the other set removed
# File lib/mtk/groups/pitch_class_set.rb, line 104 def difference(other) self.class.from_a(to_a - other.to_a) end
elements()
click to toggle source
@see Helper::Collection
# File lib/mtk/groups/pitch_class_set.rb, line 34 def elements @pitch_classes end
inspect()
click to toggle source
# File lib/mtk/groups/pitch_class_set.rb, line 145 def inspect @pitch_classes.inspect end
intersection(other)
click to toggle source
the collection of elements present in both sets
# 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()
click to toggle source
# 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()
click to toggle source
# 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)
click to toggle source
the collection of elements that are members of exactly one of the sets
# File lib/mtk/groups/pitch_class_set.rb, line 109 def symmetric_difference(other) union(other).difference( intersection(other) ) end
to_s()
click to toggle source
# File lib/mtk/groups/pitch_class_set.rb, line 141 def to_s @pitch_classes.join(' ') end
union(other)
click to toggle source
the collection of all elements present in either set
# File lib/mtk/groups/pitch_class_set.rb, line 99 def union(other) self.class.from_a(to_a | other.to_a) end