Class: HeadMusic::Rudiment::Spelling

Inherits:
Base
  • Object
show all
Defined in:
lib/head_music/rudiment/spelling.rb

Overview

Represents the spelling of a pitch, such as C# or Db. Composite of a LetterName and an optional Alteration. Does not include the octave. See Pitch for that.

Defined Under Namespace

Classes: EnharmonicEquivalence

Constant Summary collapse

LetterName =
HeadMusic::Rudiment::LetterName
Alteration =
HeadMusic::Rudiment::Alteration
MATCHER =
/^\s*(#{LetterName::PATTERN})(#{Alteration::PATTERN})?(-?\d+)?\s*$/i
CHROMATIC_SPELLINGS =

All chromatic spellings using single sharps and flats (ASCII notation)

%w[C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(letter_name, alteration = nil) ⇒ Spelling

Returns a new instance of Spelling.



65
66
67
68
69
# File 'lib/head_music/rudiment/spelling.rb', line 65

def initialize(letter_name, alteration = nil)
  @letter_name = HeadMusic::Rudiment::LetterName.get(letter_name.to_s)
  @alteration = HeadMusic::Rudiment::Alteration.get(alteration)
  @pitch_class = HeadMusic::Rudiment::PitchClass.get(semitones_above_c)
end

Instance Attribute Details

#alterationObject (readonly)

Returns the value of attribute alteration.



16
17
18
# File 'lib/head_music/rudiment/spelling.rb', line 16

def alteration
  @alteration
end

#letter_nameObject (readonly)

Returns the value of attribute letter_name.



16
17
18
# File 'lib/head_music/rudiment/spelling.rb', line 16

def letter_name
  @letter_name
end

#pitch_classObject (readonly)

Returns the value of attribute pitch_class.



16
17
18
# File 'lib/head_music/rudiment/spelling.rb', line 16

def pitch_class
  @pitch_class
end

Class Method Details

.fetch_or_create(letter_name, alteration) ⇒ Object



61
62
63
# File 'lib/head_music/rudiment/spelling.rb', line 61

def self.fetch_or_create(letter_name, alteration)
  fetch_or_register([letter_name, alteration].join, letter_name, alteration)
end

.from_name(name) ⇒ Object



34
35
36
37
38
39
40
41
42
43
# File 'lib/head_music/rudiment/spelling.rb', line 34

def self.from_name(name)
  return nil unless matching_string(name)

  letter_name, sign_string, _octave = matching_string(name).captures
  letter_name = HeadMusic::Rudiment::LetterName.get(letter_name)
  return nil unless letter_name

  alteration = HeadMusic::Rudiment::Alteration.get(sign_string)
  fetch_or_create(letter_name, alteration)
end

.from_number(number) ⇒ Object



45
46
47
48
49
50
51
# File 'lib/head_music/rudiment/spelling.rb', line 45

def self.from_number(number)
  return nil unless number == number.to_i

  pitch_class_number = number.to_i % 12
  letter_name = HeadMusic::Rudiment::LetterName.from_pitch_class(pitch_class_number)
  from_number_and_letter(number, letter_name)
end

.from_number_and_letter(number, letter_name) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/head_music/rudiment/spelling.rb', line 53

def self.from_number_and_letter(number, letter_name)
  letter_name = HeadMusic::Rudiment::LetterName.get(letter_name)
  natural_letter_pitch_class = letter_name.pitch_class
  alteration_interval = natural_letter_pitch_class.smallest_interval_to(HeadMusic::Rudiment::PitchClass.get(number))
  alteration = HeadMusic::Rudiment::Alteration.by(:semitones, alteration_interval) if alteration_interval != 0
  fetch_or_create(letter_name, alteration)
end

.get(identifier) ⇒ Object



24
25
26
27
28
# File 'lib/head_music/rudiment/spelling.rb', line 24

def self.get(identifier)
  return identifier if identifier.is_a?(HeadMusic::Rudiment::Spelling)

  from_name(identifier) || from_number(identifier)
end

.matching_string(string) ⇒ Object



30
31
32
# File 'lib/head_music/rudiment/spelling.rb', line 30

def self.matching_string(string)
  string.to_s.match(MATCHER)
end

Instance Method Details

#==(other) ⇒ Object



86
87
88
89
# File 'lib/head_music/rudiment/spelling.rb', line 86

def ==(other)
  other = HeadMusic::Rudiment::Spelling.get(other)
  to_s == other.to_s
end

#alteration_semitonesObject (private)



101
102
103
# File 'lib/head_music/rudiment/spelling.rb', line 101

def alteration_semitones
  alteration&.semitones || 0
end

#enharmonic_equivalenceObject (private)



105
106
107
# File 'lib/head_music/rudiment/spelling.rb', line 105

def enharmonic_equivalence
  @enharmonic_equivalence ||= EnharmonicEquivalence.get(self)
end

#nameObject



78
79
80
# File 'lib/head_music/rudiment/spelling.rb', line 78

def name
  [letter_name, alteration].join
end

#natural?Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/head_music/rudiment/spelling.rb', line 95

def natural?
  !alteration || alteration.natural?
end

#scale(scale_type_name = nil) ⇒ Object



91
92
93
# File 'lib/head_music/rudiment/spelling.rb', line 91

def scale(scale_type_name = nil)
  HeadMusic::Rudiment::Scale.get(self, scale_type_name)
end

#semitones_above_cObject

Where the spelling sits in the octave, counted from C and deliberately left unwrapped: B♯ is 12 rather than 0. A pitch needs it this way round, so that B♯4 and C5 come out as the same key rather than an octave apart.



74
75
76
# File 'lib/head_music/rudiment/spelling.rb', line 74

def semitones_above_c
  letter_name.pitch_class.to_i + alteration_semitones
end

#to_sObject



82
83
84
# File 'lib/head_music/rudiment/spelling.rb', line 82

def to_s
  name
end