Class: HeadMusic::Notation::ABC::PitchWriter
- Inherits:
-
Object
- Object
- HeadMusic::Notation::ABC::PitchWriter
- Defined in:
- lib/head_music/notation/abc/pitch_writer.rb
Overview
Converts pitches into ABC note tokens, emitting the minimal accidental marks required under the key signature and ABC’s bar-persistent rules.
A live PitchBuilder acts as an oracle: if an unmarked token would already parse back to the target pitch, no accidental is written. Emitted tokens are fed back through the oracle so its bar state matches what a parser will accumulate when re-reading the output.
Instance Attribute Summary collapse
-
#key_signature ⇒ Object
readonly
Returns the value of attribute key_signature.
-
#oracle ⇒ Object
readonly
private
Returns the value of attribute oracle.
Instance Method Summary collapse
-
#accidental_marks(pitch) ⇒ Object
private
-
#accidental_marks_by_fragment ⇒ Object
private
-
#commit_and_verify(pitch, letter, octave_marks, marks) ⇒ Object
private
Feeding the marked token through the oracle updates its bar state exactly as a parser reading the output would — this call is load-bearing, not just a verification; later unmarked notes depend on the state it writes.
-
#initialize(key_signature) ⇒ PitchWriter
constructor
A new instance of PitchWriter.
-
#letter_token(pitch) ⇒ Object
private
-
#octave_marks(pitch) ⇒ Object
private
-
#start_new_bar ⇒ Object
In ABC, accidentals persist only to the end of the bar.
-
#token(pitch) ⇒ Object
Returns the ABC note token for the pitch, without any duration multiplier.
Constructor Details
#initialize(key_signature) ⇒ PitchWriter
Returns a new instance of PitchWriter.
13 14 15 16 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 13 def initialize(key_signature) @key_signature = HeadMusic::Rudiment::KeySignature.get(key_signature) @oracle = PitchBuilder.new(@key_signature) end |
Instance Attribute Details
#key_signature ⇒ Object (readonly)
Returns the value of attribute key_signature.
11 12 13 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 11 def key_signature @key_signature end |
#oracle ⇒ Object (readonly, private)
Returns the value of attribute oracle.
37 38 39 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 37 def oracle @oracle end |
Instance Method Details
#accidental_marks(pitch) ⇒ Object (private)
52 53 54 55 56 57 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 52 def accidental_marks(pitch) fragment = pitch.alteration&.ascii.to_s accidental_marks_by_fragment.fetch(fragment) do raise RenderError, "cannot express #{pitch} in ABC notation" end end |
#accidental_marks_by_fragment ⇒ Object (private)
59 60 61 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 59 def accidental_marks_by_fragment @accidental_marks_by_fragment ||= PitchBuilder::ACCIDENTAL_FRAGMENTS.invert end |
#commit_and_verify(pitch, letter, octave_marks, marks) ⇒ Object (private)
Feeding the marked token through the oracle updates its bar state exactly as a parser reading the output would — this call is load-bearing, not just a verification; later unmarked notes depend on the state it writes.
66 67 68 69 70 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 66 def commit_and_verify(pitch, letter, octave_marks, marks) return if oracle.pitch(letter, octave_marks, marks) == pitch raise RenderError, "cannot express #{pitch} in ABC notation" end |
#letter_token(pitch) ⇒ Object (private)
39 40 41 42 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 39 def letter_token(pitch) letter = pitch.letter_name.to_s (pitch.register >= 5) ? letter.downcase : letter end |
#octave_marks(pitch) ⇒ Object (private)
44 45 46 47 48 49 50 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 44 def octave_marks(pitch) if pitch.register >= 5 "'" * (pitch.register - 5) else "," * (4 - pitch.register) end end |
#start_new_bar ⇒ Object
In ABC, accidentals persist only to the end of the bar.
31 32 33 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 31 def oracle. end |
#token(pitch) ⇒ Object
Returns the ABC note token for the pitch, without any duration multiplier.
19 20 21 22 23 24 25 26 27 28 |
# File 'lib/head_music/notation/abc/pitch_writer.rb', line 19 def token(pitch) pitch = HeadMusic::Rudiment::Pitch.get(pitch) letter = letter_token(pitch) octave_marks = octave_marks(pitch) return "#{letter}#{octave_marks}" if oracle.pitch(letter, octave_marks) == pitch marks = accidental_marks(pitch) commit_and_verify(pitch, letter, octave_marks, marks) "#{marks}#{letter}#{octave_marks}" end |