Class: HeadMusic::Notation::MusicXML::LyricWriter
- Inherits:
-
Object
- Object
- HeadMusic::Notation::MusicXML::LyricWriter
- Includes:
- XmlText
- Defined in:
- lib/head_music/notation/music_xml/lyric_writer.rb
Overview
Serializes the
One instance serves a whole document so the walk back to the previous sung note — which decides whether a syllable begins, continues, or ends a word — is memoized per voice and verse.
Instance Method Summary collapse
-
#escape(text) ⇒ Object
included
from XmlText
private
-
#lines(placement, component, chord:) ⇒ Object
is the last child of . -
#previous_syllable(placement, verse) ⇒ Object
private
The syllable on the nearest earlier placement in the same voice carrying text for this verse.
-
#syllabic(placement, syllable) ⇒ Object
private
Derives MusicXML’s single/begin/middle/end from our stored hyphen_after booleans: this syllable’s, and the previous sung note’s for the same verse.
Instance Method Details
#escape(text) ⇒ Object (private) Originally defined in module XmlText
#lines(placement, component, chord:) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/head_music/notation/music_xml/lyric_writer.rb', line 17 def lines(placement, component, chord:) return [] if chord || placement.rest? || component.tie_stop placement.syllables.keys.sort.flat_map do |verse| syllable = placement.syllables[verse] [ %(#{INDENT * 4}<lyric number="#{verse}">), "#{INDENT * 5}<syllabic>#{syllabic(placement, syllable)}</syllabic>", "#{INDENT * 5}<text>#{escape(syllable.text)}</text>", "#{INDENT * 4}</lyric>" ] end end |
#previous_syllable(placement, verse) ⇒ Object (private)
The syllable on the nearest earlier placement in the same voice carrying text for this verse. Placements are position-sorted, and melisma gaps are skipped because only sung placements are collected. Array#index compares with ==, which on Placement is position-only, but a voice holds at most one placement per position (Voice#insert_into_placements), so that still locates this exact placement.
50 51 52 53 54 55 56 57 58 |
# File 'lib/head_music/notation/music_xml/lyric_writer.rb', line 50 def previous_syllable(placement, verse) @sung_placements ||= {} sung = @sung_placements[[placement.voice, verse]] ||= placement.voice.placements.select { |candidate| candidate.syllable(verse) } index = sung.index(placement) return nil if index.nil? || index.zero? sung[index - 1].syllable(verse) end |
#syllabic(placement, syllable) ⇒ Object (private)
Derives MusicXML’s single/begin/middle/end from our stored hyphen_after booleans: this syllable’s, and the previous sung note’s for the same verse.
35 36 37 38 39 40 41 42 |
# File 'lib/head_music/notation/music_xml/lyric_writer.rb', line 35 def syllabic(placement, syllable) from_previous = previous_syllable(placement, syllable.verse)&.hyphen_after? if from_previous syllable.hyphen_after? ? "middle" : "end" else syllable.hyphen_after? ? "begin" : "single" end end |