class HeadMusic::Pitch

A pitch is a named frequency represented by a spelling and a register.

Attributes

register[R]
spelling[R]

Public Class Methods

concert_a() click to toggle source
# File lib/head_music/pitch.rb, line 40
def self.concert_a
  get('A4')
end
fetch_or_create(spelling, register = nil) click to toggle source
# File lib/head_music/pitch.rb, line 78
def self.fetch_or_create(spelling, register = nil)
  register ||= HeadMusic::Register::DEFAULT
  return unless spelling && (-1..9).cover?(register)

  @pitches ||= {}
  hash_key = [spelling, register].join
  @pitches[hash_key] ||= new(spelling, register)
end
from_name(name) click to toggle source
# File lib/head_music/pitch.rb, line 50
def self.from_name(name)
  return nil unless name == name.to_s

  fetch_or_create(HeadMusic::Spelling.get(name), HeadMusic::Register.get(name).to_i)
end
from_number(number) click to toggle source
# File lib/head_music/pitch.rb, line 56
def self.from_number(number)
  return nil unless number == number.to_i

  fetch_or_create(HeadMusic::Spelling.from_number(number), (number.to_i / 12) - 1)
end
from_number_and_letter(number, letter_name) click to toggle source
# File lib/head_music/pitch.rb, line 62
def self.from_number_and_letter(number, letter_name)
  letter_name = HeadMusic::LetterName.get(letter_name)
  natural_letter_pitch = natural_letter_pitch(number, letter_name)
  sign_interval = natural_letter_pitch.smallest_interval_to(HeadMusic::PitchClass.get(number))
  sign = HeadMusic::Sign.by(:semitones, sign_interval) if sign_interval != 0
  spelling = HeadMusic::Spelling.fetch_or_create(letter_name, sign)
  fetch_or_create(spelling, natural_letter_pitch.register)
end
from_pitch_class(pitch_class) click to toggle source
# File lib/head_music/pitch.rb, line 44
def self.from_pitch_class(pitch_class)
  return nil unless pitch_class.is_a?(HeadMusic::PitchClass)

  fetch_or_create(pitch_class.sharp_spelling)
end
get(value) click to toggle source

Fetches a pitch identified by the information passed in.

Accepts:

- a Pitch instance
- a PitchClass instance
- a name string, such as 'Ab4'
- a number corresponding to the midi note number
# File lib/head_music/pitch.rb, line 30
def self.get(value)
  from_pitch_class(value) ||
    from_name(value) ||
    from_number(value)
end
middle_c() click to toggle source
# File lib/head_music/pitch.rb, line 36
def self.middle_c
  get('C4')
end
natural_letter_pitch(number, letter_name) click to toggle source
# File lib/head_music/pitch.rb, line 71
def self.natural_letter_pitch(number, letter_name)
  natural_letter_pitch = get(HeadMusic::LetterName.get(letter_name).pitch_class)
  natural_letter_pitch += 12 while (number.to_i - natural_letter_pitch.to_i) >= 6
  natural_letter_pitch -= 12 while (number.to_i - natural_letter_pitch.to_i) <= -6
  get(natural_letter_pitch)
end

Private Class Methods

new(spelling, register) click to toggle source
# File lib/head_music/pitch.rb, line 87
def initialize(spelling, register)
  @spelling = HeadMusic::Spelling.get(spelling.to_s)
  @register = register.to_i
end

Public Instance Methods

+(other) click to toggle source
# File lib/head_music/pitch.rb, line 119
def +(other)
  if other.is_a?(HeadMusic::DiatonicInterval)
    # return a pitch
    other.above(self)
  else
    # assume value represents an interval in semitones and return another pitch
    HeadMusic::Pitch.get(to_i + other.to_i)
  end
end
-(other) click to toggle source
# File lib/head_music/pitch.rb, line 129
def -(other)
  if other.is_a?(HeadMusic::DiatonicInterval)
    # return a pitch
    other.below(self)
  elsif other.is_a?(HeadMusic::Pitch)
    # return an interval
    HeadMusic::ChromaticInterval.get(to_i - other.to_i)
  else
    # assume value represents an interval in semitones and return another pitch
    HeadMusic::Pitch.get(to_i - other.to_i)
  end
end
<=>(other) click to toggle source
# File lib/head_music/pitch.rb, line 147
def <=>(other)
  midi_note_number <=> other.midi_note_number
end
==(other) click to toggle source
# File lib/head_music/pitch.rb, line 142
def ==(other)
  other = HeadMusic::Pitch.get(other)
  to_s == other.to_s
end
frequency() click to toggle source
# File lib/head_music/pitch.rb, line 159
def frequency
  tuning.frequency_for(self)
end
helmholtz_notation() click to toggle source
# File lib/head_music/pitch.rb, line 111
def helmholtz_notation
  helmholtz_letter_name + helmholtz_marks
end
midi()
Alias for: midi_note_number
midi_note_number() click to toggle source
# File lib/head_music/pitch.rb, line 96
def midi_note_number
  (register + 1) * 12 + letter_name.pitch_class.to_i + sign_semitones.to_i
end
Also aliased as: midi, number
name() click to toggle source
# File lib/head_music/pitch.rb, line 92
def name
  [spelling, register].join
end
natural() click to toggle source
# File lib/head_music/pitch.rb, line 115
def natural
  HeadMusic::Pitch.get(to_s.gsub(HeadMusic::Sign.matcher, ''))
end
natural_steps(num_steps) click to toggle source
# File lib/head_music/pitch.rb, line 155
def natural_steps(num_steps)
  HeadMusic::Pitch.get([target_letter_name(num_steps), register + octaves_delta(num_steps)].join)
end
number()
Alias for: midi_note_number
scale(scale_type_name = nil) click to toggle source
# File lib/head_music/pitch.rb, line 151
def scale(scale_type_name = nil)
  HeadMusic::Scale.get(self, scale_type_name)
end
steps_to(other) click to toggle source
# File lib/head_music/pitch.rb, line 163
def steps_to(other)
  other = HeadMusic::Pitch.get(other)
  letter_name_steps_to(other) + 7 * octave_changes_to(other)
end
to_i() click to toggle source
# File lib/head_music/pitch.rb, line 107
def to_i
  midi_note_number
end
to_s() click to toggle source
# File lib/head_music/pitch.rb, line 103
def to_s
  name
end

Private Instance Methods

enharmonic_equivalence() click to toggle source
# File lib/head_music/pitch.rb, line 184
def enharmonic_equivalence
  @enharmonic_equivalence ||= HeadMusic::Pitch::EnharmonicEquivalence.get(self)
end
helmholtz_letter_name() click to toggle source
# File lib/head_music/pitch.rb, line 219
def helmholtz_letter_name
  return spelling.to_s.downcase if HeadMusic::Register.get(register).helmholtz_case == :lower

  spelling.to_s
end
helmholtz_marks() click to toggle source
# File lib/head_music/pitch.rb, line 225
def helmholtz_marks
  HeadMusic::Register.get(register).helmholtz_marks
end
octave_adjustment_to(other) click to toggle source
# File lib/head_music/pitch.rb, line 176
def octave_adjustment_to(other)
  (pitch_class_above?(other) ? 1 : 0)
end
octave_changes_to(other) click to toggle source
# File lib/head_music/pitch.rb, line 172
def octave_changes_to(other)
  other.register - register - octave_adjustment_to(other)
end
octave_equivalence() click to toggle source
# File lib/head_music/pitch.rb, line 188
def octave_equivalence
  @octave_equivalence ||= HeadMusic::Pitch::OctaveEquivalence.get(self)
end
octaves_delta(num_steps) click to toggle source
# File lib/head_music/pitch.rb, line 196
def octaves_delta(num_steps)
  octaves_delta = (num_steps.abs / 7) * (num_steps >= 0 ? 1 : -1)
  if wrapped_down?(num_steps)
    octaves_delta -= 1
  elsif wrapped_up?(num_steps)
    octaves_delta += 1
  end
  octaves_delta
end
pitch_class_above?(other) click to toggle source
# File lib/head_music/pitch.rb, line 180
def pitch_class_above?(other)
  natural_pitch_class_number > other.natural_pitch_class_number
end
target_letter_name(num_steps) click to toggle source
# File lib/head_music/pitch.rb, line 214
def target_letter_name(num_steps)
  @target_letter_name ||= {}
  @target_letter_name[num_steps] ||= letter_name.steps_up(num_steps)
end
tuning() click to toggle source
# File lib/head_music/pitch.rb, line 192
def tuning
  @tuning ||= HeadMusic::Tuning.new
end
wrapped_down?(num_steps) click to toggle source
# File lib/head_music/pitch.rb, line 206
def wrapped_down?(num_steps)
  num_steps.negative? && target_letter_name(num_steps).position > letter_name.position
end
wrapped_up?(num_steps) click to toggle source
# File lib/head_music/pitch.rb, line 210
def wrapped_up?(num_steps)
  num_steps.positive? && target_letter_name(num_steps).position < letter_name.position
end