Class: HeadMusic::Notation::ABC::PitchBuilder
- Inherits:
-
Object
- Object
- HeadMusic::Notation::ABC::PitchBuilder
- Defined in:
- lib/head_music/notation/abc/pitch_builder.rb
Overview
Converts lexed ABC note data into pitches, applying the key signature and ABC’s bar-persistent accidental rules.
Constant Summary collapse
- ACCIDENTAL_FRAGMENTS =
ABC accidental marks mapped to pitch-name fragments. The natural sign maps to an empty fragment because a natural pitch name carries no alteration symbol.
{ "^" => "#", "^^" => "x", "_" => "b", "__" => "bb", "=" => "" }.freeze
Instance Attribute Summary collapse
-
#key_signature ⇒ Object
readonly
Returns the value of attribute key_signature.
Instance Method Summary collapse
-
#accidental_fragment(letter_name, octave, accidental_marks) ⇒ Object
private
-
#explicit_fragment(letter_name, octave, accidental_marks) ⇒ Object
private
An explicit accidental applies to later unmarked notes of the same letter and octave until the next bar line.
-
#initialize(key_signature) ⇒ PitchBuilder
constructor
A new instance of PitchBuilder.
-
#key_signature_fragment(letter_name) ⇒ Object
private
-
#octave_for(letter, octave_marks) ⇒ Object
private
-
#pitch(letter, octave_marks = "", accidental_marks = nil) ⇒ Object
letter: raw ABC letter preserving case (“A”..”G” or “a”..”g”) octave_marks: a string of “’” and “,” characters (possibly empty or nil) accidental_marks: nil, “^”, “^^”, “_”, “__”, or “=”.
-
#present?(accidental_marks) ⇒ Boolean
private
-
#start_new_bar ⇒ Object
In ABC, accidentals persist only to the end of the bar.
Constructor Details
#initialize(key_signature) ⇒ PitchBuilder
Returns a new instance of PitchBuilder.
19 20 21 22 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 19 def initialize(key_signature) @key_signature = HeadMusic::Rudiment::KeySignature.get(key_signature) end |
Instance Attribute Details
#key_signature ⇒ Object (readonly)
Returns the value of attribute key_signature.
17 18 19 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 17 def key_signature @key_signature end |
Instance Method Details
#accidental_fragment(letter_name, octave, accidental_marks) ⇒ Object (private)
49 50 51 52 53 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 49 def accidental_fragment(letter_name, octave, accidental_marks) return explicit_fragment(letter_name, octave, accidental_marks) if present?(accidental_marks) @bar_accidentals.fetch([letter_name, octave]) { key_signature_fragment(letter_name) } end |
#explicit_fragment(letter_name, octave, accidental_marks) ⇒ Object (private)
An explicit accidental applies to later unmarked notes of the same letter and octave until the next bar line.
57 58 59 60 61 62 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 57 def explicit_fragment(letter_name, octave, accidental_marks) fragment = ACCIDENTAL_FRAGMENTS.fetch(accidental_marks) do raise ParseError, "invalid accidental marks: #{accidental_marks.inspect}" end @bar_accidentals[[letter_name, octave]] = fragment end |
#key_signature_fragment(letter_name) ⇒ Object (private)
64 65 66 67 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 64 def key_signature_fragment(letter_name) spelling = key_signature.alterations.find { |altered| altered.letter_name.to_s == letter_name } spelling ? spelling.alteration.to_s : "" end |
#octave_for(letter, octave_marks) ⇒ Object (private)
43 44 45 46 47 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 43 def octave_for(letter, octave_marks) base_octave = (letter == letter.upcase) ? 4 : 5 marks = octave_marks.to_s base_octave + marks.count("'") - marks.count(",") end |
#pitch(letter, octave_marks = "", accidental_marks = nil) ⇒ Object
letter: raw ABC letter preserving case (“A”..”G” or “a”..”g”) octave_marks: a string of “’” and “,” characters (possibly empty or nil) accidental_marks: nil, “^”, “^^”, “_”, “__”, or “=”
27 28 29 30 31 32 33 34 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 27 def pitch(letter, octave_marks = "", accidental_marks = nil) letter_name = letter.upcase octave = octave_for(letter, octave_marks) fragment = accidental_fragment(letter_name, octave, accidental_marks) name = "#{letter_name}#{fragment}#{octave}" HeadMusic::Rudiment::Pitch.from_name(name) || raise(ParseError, "invalid pitch: #{name.inspect}") end |
#present?(accidental_marks) ⇒ Boolean (private)
69 70 71 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 69 def present?(accidental_marks) !accidental_marks.to_s.empty? end |
#start_new_bar ⇒ Object
In ABC, accidentals persist only to the end of the bar.
37 38 39 |
# File 'lib/head_music/notation/abc/pitch_builder.rb', line 37 def @bar_accidentals = {} end |