Class: HeadMusic::Rudiment::Pitch

Inherits:
Base
  • Object
show all
Includes:
Comparable
Defined in:
lib/head_music/rudiment/pitch.rb

Overview

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

Defined Under Namespace

Classes: EnharmonicEquivalence, OctaveEquivalence, Parser

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(spelling, register) ⇒ Pitch

Returns a new instance of Pitch.



93
94
95
96
# File 'lib/head_music/rudiment/pitch.rb', line 93

def initialize(spelling, register)
  @spelling = HeadMusic::Rudiment::Spelling.get(spelling.to_s)
  @register = register.to_i
end

Instance Attribute Details

#registerObject (readonly)

Returns the value of attribute register.



7
8
9
# File 'lib/head_music/rudiment/pitch.rb', line 7

def register
  @register
end

#spellingObject (readonly)

Returns the value of attribute spelling.



7
8
9
# File 'lib/head_music/rudiment/pitch.rb', line 7

def spelling
  @spelling
end

Class Method Details

.concert_aObject



42
43
44
# File 'lib/head_music/rudiment/pitch.rb', line 42

def self.concert_a
  get("A4")
end

.fetch_or_create(spelling, register = nil) ⇒ Object



84
85
86
87
88
89
90
91
# File 'lib/head_music/rudiment/pitch.rb', line 84

def self.fetch_or_create(spelling, register = nil)
  register ||= HeadMusic::Rudiment::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) ⇒ Object



52
53
54
55
56
# File 'lib/head_music/rudiment/pitch.rb', line 52

def self.from_name(name)
  return nil unless name == name.to_s

  Parser.parse(name)
end

.from_number(number) ⇒ Object



58
59
60
61
62
63
64
65
# File 'lib/head_music/rudiment/pitch.rb', line 58

def self.from_number(number)
  return nil unless number.respond_to?(:to_i)

  number_int = number.to_i
  return nil unless number == number_int

  fetch_or_create(HeadMusic::Rudiment::Spelling.from_number(number), (number_int / 12) - 1)
end

.from_number_and_letter(number, letter_name) ⇒ Object



67
68
69
70
71
72
73
74
# File 'lib/head_music/rudiment/pitch.rb', line 67

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

.from_pitch_class(pitch_class) ⇒ Object



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

def self.from_pitch_class(pitch_class)
  return nil unless pitch_class.is_a?(HeadMusic::Rudiment::PitchClass)

  fetch_or_create(pitch_class.sharp_spelling)
end

.get(value) ⇒ Object

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



30
31
32
33
34
35
36
# File 'lib/head_music/rudiment/pitch.rb', line 30

def self.get(value)
  return value if value.is_a?(HeadMusic::Rudiment::Pitch)

  from_pitch_class(value) ||
    from_name(value) ||
    from_number(value)
end

.middle_cObject



38
39
40
# File 'lib/head_music/rudiment/pitch.rb', line 38

def self.middle_c
  get("C4")
end

.natural_letter_pitch(number, letter_name) ⇒ Object



76
77
78
79
80
81
82
# File 'lib/head_music/rudiment/pitch.rb', line 76

def self.natural_letter_pitch(number, letter_name)
  number_int = number.to_i
  natural_letter_pitch = get(HeadMusic::Rudiment::LetterName.get(letter_name).pitch_class)
  natural_letter_pitch += 12 while (number_int - natural_letter_pitch.to_i) >= 6
  natural_letter_pitch -= 12 while (number_int - natural_letter_pitch.to_i) <= -6
  get(natural_letter_pitch)
end

Instance Method Details

#+(other) ⇒ Object



129
130
131
132
133
134
135
136
137
# File 'lib/head_music/rudiment/pitch.rb', line 129

def +(other)
  if other.is_a?(HeadMusic::Analysis::DiatonicInterval)
    # return a pitch
    other.above(self)
  else
    # assume value represents an interval in semitones and return another pitch
    HeadMusic::Rudiment::Pitch.get(to_i + other.to_i)
  end
end

#-(other) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/head_music/rudiment/pitch.rb', line 139

def -(other)
  case other
  when HeadMusic::Analysis::DiatonicInterval
    # return a pitch
    other.below(self)
  when HeadMusic::Rudiment::Pitch
    # return an interval
    HeadMusic::Rudiment::ChromaticInterval.get(to_i - other.to_i)
  else
    # assume value represents an interval in semitones and return another pitch
    HeadMusic::Rudiment::Pitch.get(to_i - other.to_i)
  end
end

#<=>(other) ⇒ Object



158
159
160
# File 'lib/head_music/rudiment/pitch.rb', line 158

def <=>(other)
  midi_note_number <=> other.midi_note_number
end

#==(other) ⇒ Object



153
154
155
156
# File 'lib/head_music/rudiment/pitch.rb', line 153

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

#enharmonic_equivalenceObject (private)



193
194
195
# File 'lib/head_music/rudiment/pitch.rb', line 193

def enharmonic_equivalence
  @enharmonic_equivalence ||= HeadMusic::Rudiment::Pitch::EnharmonicEquivalence.get(self)
end

#frequencyObject



170
171
172
# File 'lib/head_music/rudiment/pitch.rb', line 170

def frequency
  tuning.frequency_for(self)
end

#helmholtz_letter_nameObject (private)



228
229
230
231
232
233
# File 'lib/head_music/rudiment/pitch.rb', line 228

def helmholtz_letter_name
  spelling_str = spelling.to_s
  return spelling_str.downcase if HeadMusic::Rudiment::Register.get(register).helmholtz_case == :lower

  spelling_str
end

#helmholtz_marksObject (private)



235
236
237
# File 'lib/head_music/rudiment/pitch.rb', line 235

def helmholtz_marks
  HeadMusic::Rudiment::Register.get(register).helmholtz_marks
end

#helmholtz_notationObject



121
122
123
# File 'lib/head_music/rudiment/pitch.rb', line 121

def helmholtz_notation
  helmholtz_letter_name + helmholtz_marks
end

#midi_note_numberObject Also known as: midi, number



102
103
104
# File 'lib/head_music/rudiment/pitch.rb', line 102

def midi_note_number
  (register + 1) * 12 + letter_name.pitch_class.to_i + alteration_semitones.to_i
end

#nameObject



98
99
100
# File 'lib/head_music/rudiment/pitch.rb', line 98

def name
  [spelling, register].join
end

#naturalObject



125
126
127
# File 'lib/head_music/rudiment/pitch.rb', line 125

def natural
  HeadMusic::Rudiment::Pitch.get(to_s.gsub(HeadMusic::Rudiment::Alteration::PATTERN, ""))
end

#natural_steps(num_steps) ⇒ Object



166
167
168
# File 'lib/head_music/rudiment/pitch.rb', line 166

def natural_steps(num_steps)
  HeadMusic::Rudiment::Pitch.get([target_letter_name(num_steps), register + octaves_delta(num_steps)].join)
end

#octave_adjustment_to(other) ⇒ Object (private)



185
186
187
# File 'lib/head_music/rudiment/pitch.rb', line 185

def octave_adjustment_to(other)
  (pitch_class_above?(other) ? 1 : 0)
end

#octave_changes_to(other) ⇒ Object (private)



181
182
183
# File 'lib/head_music/rudiment/pitch.rb', line 181

def octave_changes_to(other)
  other.register - register - octave_adjustment_to(other)
end

#octave_equivalenceObject (private)



197
198
199
# File 'lib/head_music/rudiment/pitch.rb', line 197

def octave_equivalence
  @octave_equivalence ||= HeadMusic::Rudiment::Pitch::OctaveEquivalence.get(self)
end

#octaves_delta(num_steps) ⇒ Object (private)



205
206
207
208
209
210
211
212
213
# File 'lib/head_music/rudiment/pitch.rb', line 205

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) ⇒ Boolean (private)

Returns:

  • (Boolean)


189
190
191
# File 'lib/head_music/rudiment/pitch.rb', line 189

def pitch_class_above?(other)
  natural_pitch_class_number > other.natural_pitch_class_number
end

#pitched?Boolean

Returns:

  • (Boolean)


113
114
115
# File 'lib/head_music/rudiment/pitch.rb', line 113

def pitched?
  true
end

#scale(scale_type_name = nil) ⇒ Object



162
163
164
# File 'lib/head_music/rudiment/pitch.rb', line 162

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

#steps_to(other) ⇒ Object



174
175
176
177
# File 'lib/head_music/rudiment/pitch.rb', line 174

def steps_to(other)
  other = HeadMusic::Rudiment::Pitch.get(other)
  letter_name_steps_to(other) + 7 * octave_changes_to(other)
end

#target_letter_name(num_steps) ⇒ Object (private)



223
224
225
226
# File 'lib/head_music/rudiment/pitch.rb', line 223

def target_letter_name(num_steps)
  @target_letter_name ||= {}
  @target_letter_name[num_steps] ||= letter_name.steps_up(num_steps)
end

#to_iObject



117
118
119
# File 'lib/head_music/rudiment/pitch.rb', line 117

def to_i
  midi_note_number
end

#to_sObject



109
110
111
# File 'lib/head_music/rudiment/pitch.rb', line 109

def to_s
  name
end

#tuningObject (private)



201
202
203
# File 'lib/head_music/rudiment/pitch.rb', line 201

def tuning
  @tuning ||= HeadMusic::Rudiment::Tuning.new
end

#wrapped_down?(num_steps) ⇒ Boolean (private)

Returns:

  • (Boolean)


215
216
217
# File 'lib/head_music/rudiment/pitch.rb', line 215

def wrapped_down?(num_steps)
  num_steps.negative? && target_letter_name(num_steps).position > letter_name.position
end

#wrapped_up?(num_steps) ⇒ Boolean (private)

Returns:

  • (Boolean)


219
220
221
# File 'lib/head_music/rudiment/pitch.rb', line 219

def wrapped_up?(num_steps)
  num_steps.positive? && target_letter_name(num_steps).position < letter_name.position
end