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.



94
95
96
97
98
# File 'lib/head_music/analysis/diatonic_interval.rb', line 94

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



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

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
    middle_c = HeadMusic::Rudiment::Pitch.middle_c
    higher_pitch = HeadMusic::Rudiment::Pitch.from_number_and_letter(middle_c + semitones, name.higher_letter)
    interval = new(middle_c, higher_pitch)
    interval.ensure_localized_name(name: identifier.to_s)
    interval
  else
    identifier
  end
end

Instance Method Details

#<=>(other) ⇒ Object



175
176
177
178
# File 'lib/head_music/analysis/diatonic_interval.rb', line 175

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

#above(pitch) ⇒ Object



153
154
155
156
# File 'lib/head_music/analysis/diatonic_interval.rb', line 153

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



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

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)



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

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

#consonance(style = :standard_practice) ⇒ Object



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

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

#consonance?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#consonance_analysis(style = :standard_practice) ⇒ Object



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

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

#consonance_classification(style: :standard_practice) ⇒ Object



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

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

#consonant?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#dissonance?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#dissonant?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


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

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)


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

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

#interval_classObject



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

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

#interval_class_nameObject



167
168
169
# File 'lib/head_music/analysis/diatonic_interval.rb', line 167

def interval_class_name
  "ic #{interval_class}"
end

#inversionObject Also known as: invert



108
109
110
111
112
113
114
# File 'lib/head_music/analysis/diatonic_interval.rb', line 108

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
72
73
# File 'lib/head_music/analysis/diatonic_interval.rb', line 61

def name(locale_code: nil)
  computed_name = naming.name
  return computed_name unless locale_code

  translations = I18n.backend.translations[locale_code]
  return computed_name unless translations

  name_key = HeadMusic::Utilities::HashKey.for(computed_name)
  locale_data = translations[:head_music] || {}
  locale_data.dig(:diatonic_intervals, name_key) ||
    locale_data.dig(:chromatic_intervals, name_key) ||
    computed_name
end

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

#namingObject (private)



198
199
200
# File 'lib/head_music/analysis/diatonic_interval.rb', line 198

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

#perfect_consonance?(style = :standard_practice) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#qualityObject



104
105
106
# File 'lib/head_music/analysis/diatonic_interval.rb', line 104

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

#sizeObject (private)



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

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

#spans?(pitch) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#to_sObject



75
76
77
# File 'lib/head_music/analysis/diatonic_interval.rb', line 75

def to_s
  name
end