Class: MTK::Core::PitchClass

Inherits:
Object
  • Object
show all
Defined in:
lib/mtk/core/pitch_class.rb

Overview

A set of all pitches that are an integer number of octaves apart. A Pitch has the same PitchClass as the pitches one or more octaves away.

Constant Summary collapse

NAMES =

The preferred names of the 12 pitch classes in the chromatic scale. The index of each #name is the pitch class’s numeric #value.

%w( C Db D Eb E F Gb G Ab A Bb B ).freeze
VALID_NAMES_BY_VALUE =

All enharmonic names of the 12 pitch classes, including sharps, flats, double-sharps, and double-flats, organized such that each index contains the allowed names of the pitch class with a #value equal to that index.

See Also:

[ # (valid names ), # value # preferred name
  %w( B#  C  Dbb ), #   0   #   C
  %w( B## C# Db  ), #   1   #   Db
  %w( C## D  Ebb ), #   2   #   D
  %w( D#  Eb Fbb ), #   3   #   Eb
  %w( D## E  Fb  ), #   4   #   E
  %w( E#  F  Gbb ), #   5   #   F
  %w( E## F# Gb  ), #   6   #   Gb
  %w( F## G  Abb ), #   7   #   G
  %w( G#     Ab  ), #   8   #   Ab
  %w( G## A  Bbb ), #   9   #   A
  %w( A#  Bb Cbb ), #  10   #   Bb
  %w( A## B  Cb  )  #  11   #   B
].freeze
VALID_NAMES =

All valid enharmonic pitch class names in a flat list.

VALID_NAMES_BY_VALUE.flatten.freeze
VALUES_BY_NAME =

A mapping from valid names to the value of the pitch class with that name

Hash[ # a map from a list of name,value pairs
  VALID_NAMES_BY_VALUE.map.with_index do |valid_names,value|
    valid_names.map{|name| [name,value] }
  end.flatten(1)
].freeze
PITCH_CLASSES =

All 12 pitch classes in the chromatic scale. The index of each pitch class is the pitch class’s numeric #value.

NAMES.map{|name| from_name name }.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#nameObject (readonly)

The name of this pitch class. One of the NAMES defined by this class.



47
48
49
# File 'lib/mtk/core/pitch_class.rb', line 47

def name
  @name
end

#valueObject (readonly)

The value of this pitch class. An integer from 0..11 that indexes this pitch class in PITCH_CLASSES and the #name in NAMES.

This value is fairly arbitrary and just used for sorting purposes and mod 12 arithmetic when composing directly with pitch classes.



54
55
56
# File 'lib/mtk/core/pitch_class.rb', line 54

def value
  @value
end

Class Method Details

.[](name_or_value) ⇒ Object

Lookup a PitchClass by name or value.

Parameters:

Returns:

  • the PitchClass representing the argument

Raises:

  • ArgumentError for arguments that cannot be converted to a PitchClass



74
75
76
77
78
79
80
# File 'lib/mtk/core/pitch_class.rb', line 74

def self.[] name_or_value
  @flyweight[name_or_value] ||= case name_or_value
    when String,Symbol then from_name(name_or_value)
    when Numeric       then from_value(name_or_value.round)
    else raise ArgumentError.new("PitchClass.[] doesn't understand #{name_or_value.class}")
  end
end

.from_f(value) ⇒ Object

return the pitch class with the given float rounded to the nearest integer, mod 12

Parameters:

  • value (Float, #to_f)


112
113
114
# File 'lib/mtk/core/pitch_class.rb', line 112

def self.from_f(value)
  from_i value.to_f.round
end

.from_name(name) ⇒ Object Also known as: from_s

Lookup a PitchClass by name.

Parameters:



84
85
86
87
88
89
90
# File 'lib/mtk/core/pitch_class.rb', line 84

def self.from_name(name)
  @flyweight[name] ||= (
    valid_name = name.to_s.capitalize
    value = VALUES_BY_NAME[valid_name] or raise ArgumentError.new("Invalid PitchClass name: #{name}")
    new(valid_name,value)
  )
end

.from_value(value) ⇒ Object Also known as: from_i

return the pitch class with the given integer value mod 12

Parameters:

  • value (Integer, #to_i)


102
103
104
# File 'lib/mtk/core/pitch_class.rb', line 102

def self.from_value(value)
  PITCH_CLASSES[value.to_i % 12]
end

Instance Method Details

#+(interval) ⇒ Object Also known as: transpose

Transpose this pitch class by adding it’s value to the value given (mod 12)

Parameters:



149
150
151
152
# File 'lib/mtk/core/pitch_class.rb', line 149

def + interval
  new_value = (value + interval.to_f).round
  self.class.from_value new_value
end

#-(interval) ⇒ Object

Transpose this pitch class by subtracing the given value from this value (mod 12)

Parameters:



157
158
159
160
# File 'lib/mtk/core/pitch_class.rb', line 157

def - interval
  new_value = (value - interval.to_f).round
  self.class.from_value new_value
end

#<=>(other) ⇒ Object

Compare a pitch class with another pitch class or integer value

Parameters:

Returns:

  • -1, 0, or +1 depending on whether this pitch class’s value is less than, equal to, or greater than the other object’s integer value

See Also:



127
128
129
# File 'lib/mtk/core/pitch_class.rb', line 127

def <=> other
  @value <=> other.to_i
end

#==(other) ⇒ Object

Compare 2 pitch classes for equal values.

Parameters:

Returns:

  • true if this pitch class’s value is equal to the other pitch class’s value



119
120
121
# File 'lib/mtk/core/pitch_class.rb', line 119

def == other
  other.is_a? PitchClass and other.value == @value
end

#distance_to(pitch_class) ⇒ Object

the smallest interval in semitones that needs to be added to this PitchClass to reach the given PitchClass

Parameters:



171
172
173
174
175
176
177
178
179
180
# File 'lib/mtk/core/pitch_class.rb', line 171

def distance_to(pitch_class)
  delta = (pitch_class.value - value) % 12
  if delta > 6
    delta -= 12
  elsif delta == 6 and to_i >= 6
    # this is a special edge case to prevent endlessly ascending pitch sequences when alternating between two pitch classes a tritone apart
    delta = -6
  end
  delta
end

#invert(center) ⇒ Object

Inverts (mirrors) the pitch class around the given center

Parameters:

  • center (PitchClass, Pitch, Float, #to_f)

    the value to “mirror” this pitch class around



164
165
166
167
# File 'lib/mtk/core/pitch_class.rb', line 164

def invert(center)
  delta = (2*(center.to_f - value)).round
  self + delta
end

#to_fObject

This pitch class’s #value as a floating point number



143
144
145
# File 'lib/mtk/core/pitch_class.rb', line 143

def to_f
  @value.to_f
end

#to_iObject

This pitch class’s integer #value



138
139
140
# File 'lib/mtk/core/pitch_class.rb', line 138

def to_i
  @value.to_i
end

#to_sObject

This pitch class’s normalized #name.

See Also:



133
134
135
# File 'lib/mtk/core/pitch_class.rb', line 133

def to_s
  @name.to_s
end