Class: HeadMusic::Analysis::DiatonicInterval

Inherits:
Object
  • Object
show all
Includes:
Comparable, Named
Defined in:
lib/head_music/analysis/diatonic_interval.rb

Overview

A diatonic interval is the distance between two spelled pitches.

Defined Under Namespace

Classes: Category, Naming, Parser, Semitones, Size

Constant Summary collapse

NUMBER_NAMES =
%w[
  unison second third fourth fifth sixth seventh octave
  ninth tenth eleventh twelfth thirteenth fourteenth fifteenth
  sixteenth seventeenth
].freeze
NAME_SUFFIXES =
Hash.new("th").merge(1 => "st", 2 => "nd", 3 => "rd").freeze
QUALITY_SEMITONES =
{
  unison: {perfect: 0},
  second: {major: 2},
  third: {major: 4},
  fourth: {perfect: 5},
  fifth: {perfect: 7},
  sixth: {major: 9},
  seventh: {major: 11},
  octave: {perfect: 12},
  ninth: {major: 14},
  tenth: {major: 16},
  eleventh: {perfect: 17},
  twelfth: {perfect: 19},
  thirteenth: {major: 21},
  fourteenth: {major: 23},
  fifteenth: {perfect: 24},
  sixteenth: {major: 26},
  seventeenth: {major: 28}
}.freeze
QUALITY_ABBREVIATIONS =
{
  P: "perfect",
  M: "major",
  m: "minor",
  d: "diminished",
  A: "augmented"
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(first_pitch, second_pitch) ⇒ DiatonicInterval

Returns a new instance of DiatonicInterval.



91
92
93
94
95
# File 'lib/head_music/analysis/diatonic_interval.rb', line 91

def initialize(first_pitch, second_pitch)
  first_pitch = HeadMusic::Rudiment::Pitch.get(first_pitch)
  second_pitch = HeadMusic::Rudiment::Pitch.get(second_pitch)
  @lower_pitch, @higher_pitch = [first_pitch, second_pitch].sort
end

Instance Attribute Details

#alias_name_keysObject (readonly) Originally defined in module Named

Returns the value of attribute alias_name_keys.

#higher_pitchObject (readonly)

Returns the value of attribute higher_pitch.



44
45
46
# File 'lib/head_music/analysis/diatonic_interval.rb', line 44

def higher_pitch
  @higher_pitch
end

#lower_pitchObject (readonly)

Returns the value of attribute lower_pitch.



44
45
46
# File 'lib/head_music/analysis/diatonic_interval.rb', line 44

def lower_pitch
  @lower_pitch
end

#name_keyObject (readonly) Originally defined in module Named

Returns the value of attribute name_key.

Class Method Details

.get(identifier) ⇒ Object

Accepts a name and returns the interval with middle c on the bottom



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/head_music/analysis/diatonic_interval.rb', line 78

def self.get(identifier)
  if identifier.is_a?(String) || identifier.is_a?(Symbol)
    name = Parser.new(identifier)
    semitones = Semitones.new(name.degree_name.to_sym, name.quality_name).count
    higher_pitch = HeadMusic::Rudiment::Pitch.from_number_and_letter(HeadMusic::Rudiment::Pitch.middle_c + semitones, name.higher_letter)
    interval = new(HeadMusic::Rudiment::Pitch.middle_c, higher_pitch)
    interval.ensure_localized_name(name: identifier.to_s)
    interval
  else
    identifier
  end
end

Instance Method Details

#<=>(other) ⇒ Object



172
173
174
175
# File 'lib/head_music/analysis/diatonic_interval.rb', line 172

def <=>(other)
  other = self.class.get(other) unless other.is_a?(HeadMusic::Analysis::DiatonicInterval)
  semitones <=> other.semitones
end

#above(pitch) ⇒ Object



150
151
152
153
# File 'lib/head_music/analysis/diatonic_interval.rb', line 150

def above(pitch)
  pitch = HeadMusic::Rudiment::Pitch.get(pitch)
  HeadMusic::Rudiment::Pitch.from_number_and_letter(pitch + semitones, pitch.letter_name.steps_up(number - 1))
end

#below(pitch) ⇒ Object



155
156
157
158
# File 'lib/head_music/analysis/diatonic_interval.rb', line 155

def below(pitch)
  pitch = HeadMusic::Rudiment::Pitch.get(pitch)
  HeadMusic::Rudiment::Pitch.from_number_and_letter(pitch - semitones, pitch.letter_name.steps_down(number - 1))
end

#categoryObject (private)



191
192
193
# File 'lib/head_music/analysis/diatonic_interval.rb', line 191

def category
  @category ||= Category.new(number)
end

#consonance(style = :standard_practice) ⇒ Object



114
115
116
# File 'lib/head_music/analysis/diatonic_interval.rb', line 114

def consonance(style = :standard_practice)
  consonance_analysis(style).consonance
end

#consonance?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/head_music/analysis/diatonic_interval.rb', line 118

def consonance?(style = :standard_practice)
  consonance(style).consonant?
end

#consonance_analysis(style = :standard_practice) ⇒ Object



142
143
144
# File 'lib/head_music/analysis/diatonic_interval.rb', line 142

def consonance_analysis(style = :standard_practice)
  HeadMusic::Analysis::IntervalConsonance.new(self, style)
end

#consonance_classification(style: :standard_practice) ⇒ Object



146
147
148
# File 'lib/head_music/analysis/diatonic_interval.rb', line 146

def consonance_classification(style: :standard_practice)
  consonance_analysis(style).classification
end

#consonant?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/head_music/analysis/diatonic_interval.rb', line 122

def consonant?(style = :standard_practice)
  consonance_analysis(style).consonant?
end

#dissonance?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


134
135
136
# File 'lib/head_music/analysis/diatonic_interval.rb', line 134

def dissonance?(style = :standard_practice)
  consonance_analysis(style).dissonant?
end

#dissonant?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/head_music/analysis/diatonic_interval.rb', line 138

def dissonant?(style = :standard_practice)
  consonance_analysis(style).dissonant?
end

#ensure_localized_name(name:, locale_code: Locale::DEFAULT_CODE, abbreviation: nil) ⇒ Object Originally defined in module Named

#imperfect_consonance?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


130
131
132
# File 'lib/head_music/analysis/diatonic_interval.rb', line 130

def imperfect_consonance?(style = :standard_practice)
  consonance_analysis(style).imperfect_consonance?
end

#interval_classObject



160
161
162
# File 'lib/head_music/analysis/diatonic_interval.rb', line 160

def interval_class
  [simple_semitones, 12 - simple_semitones].min
end

#interval_class_nameObject



164
165
166
# File 'lib/head_music/analysis/diatonic_interval.rb', line 164

def interval_class_name
  "ic #{interval_class}"
end

#inversionObject Also known as: invert



105
106
107
108
109
110
111
# File 'lib/head_music/analysis/diatonic_interval.rb', line 105

def inversion
  inverted_low_pitch = lower_pitch
  while inverted_low_pitch < higher_pitch
    inverted_low_pitch = HeadMusic::Rudiment::Pitch.fetch_or_create(lower_pitch.spelling, inverted_low_pitch.register + 1)
  end
  HeadMusic::Analysis::DiatonicInterval.new(higher_pitch, inverted_low_pitch)
end

#localized_name(locale_code: Locale::DEFAULT_CODE) ⇒ Object Originally defined in module Named

#localized_name_in_default_localeObject (private) Originally defined in module Named

#localized_name_in_locale_matching_language(locale) ⇒ Object (private) Originally defined in module Named

#localized_name_in_matching_locale(locale) ⇒ Object (private) Originally defined in module Named

#localized_namesObject Originally defined in module Named

Returns an array of LocalizedName instances that are synonymous with the name.

#name(locale_code: nil) ⇒ Object

Override Named module method to try I18n and fall back to computed name



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/head_music/analysis/diatonic_interval.rb', line 61

def name(locale_code: nil)
  if locale_code
    name_key = HeadMusic::Utilities::HashKey.for(naming.name)
    if I18n.backend.translations[locale_code]
      locale_data = I18n.backend.translations[locale_code][:head_music] || {}
      return locale_data[:diatonic_intervals][name_key] if locale_data.dig(:diatonic_intervals, name_key)
      return locale_data[:chromatic_intervals][name_key] if locale_data.dig(:chromatic_intervals, name_key)
    end
  end
  naming.name
end

#name=(name) ⇒ Object Originally defined in module Named

#namingObject (private)



195
196
197
# File 'lib/head_music/analysis/diatonic_interval.rb', line 195

def naming
  @naming ||= Naming.new(number: number, semitones: semitones)
end

#perfect_consonance?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
# File 'lib/head_music/analysis/diatonic_interval.rb', line 126

def perfect_consonance?(style = :standard_practice)
  consonance_analysis(style).perfect_consonance?
end

#qualityObject



101
102
103
# File 'lib/head_music/analysis/diatonic_interval.rb', line 101

def quality
  HeadMusic::Rudiment::Quality.get(quality_name)
end

#sizeObject (private)



187
188
189
# File 'lib/head_music/analysis/diatonic_interval.rb', line 187

def size
  @size ||= Size.new(@lower_pitch, @higher_pitch)
end

#spans?(pitch) ⇒ Boolean

Returns:

  • (Boolean)


97
98
99
# File 'lib/head_music/analysis/diatonic_interval.rb', line 97

def spans?(pitch)
  pitch.between?(lower_pitch, higher_pitch)
end

#to_sObject



73
74
75
# File 'lib/head_music/analysis/diatonic_interval.rb', line 73

def to_s
  name
end