Class: HeadMusic::Notation::MusicXML::NoteWriter
- Inherits:
-
Object
- Object
- HeadMusic::Notation::MusicXML::NoteWriter
- Includes:
- XmlText, PlacementValidation
- Defined in:
- lib/head_music/notation/music_xml/note_writer.rb
Overview
Serializes the
A placement becomes one
Instance Attribute Summary collapse
-
#lyric_writer ⇒ Object
readonly
private
Returns the value of attribute lyric_writer.
-
#plan ⇒ Object
readonly
private
Returns the value of attribute plan.
Instance Method Summary collapse
- #beam_lines(beams) ⇒ Object private
-
#element_lines(placement, component, pitch: nil, chord: false, beams: [], voice_number: nil, staff_number: nil) ⇒ Object
private
A chord note carries
as its first child, before , marking it as sounding with the preceding note; the lead note (and every single note and rest) omits it, so this path stays byte-identical for those. - #ensure_pitched_sounds(placement) ⇒ Object included from PlacementValidation private
- #escape(text) ⇒ Object included from XmlText private
-
#initialize(plan) ⇒ NoteWriter
constructor
A new instance of NoteWriter.
- #lines(placement, voice_number: nil, staff_number: nil) ⇒ Object
- #notation_lines(placement, component) ⇒ Object private
-
#note_slots(placement) ⇒ Object
private
A rest emits one empty slot; a sounded placement emits its pitches low to high, so the lowest note leads and the rest carry
. - #pitch_lines(pitch) ⇒ Object private
- #render_error_class ⇒ Object private
-
#tie_lines(placement, component) ⇒ Object
private
Rests take no tie elements; the links of a rest's tied chain render as consecutive independent rests.
-
#whole_measure_rest_lines(bar_number, voice_number: nil, staff_number: nil) ⇒ Object
The whole-measure rest that stands in for a bar the voice places nothing in.
Constructor Details
#initialize(plan) ⇒ NoteWriter
Returns a new instance of NoteWriter.
14 15 16 17 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 14 def initialize(plan) @plan = plan @lyric_writer = LyricWriter.new end |
Instance Attribute Details
#lyric_writer ⇒ Object (readonly, private)
Returns the value of attribute lyric_writer.
53 54 55 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 53 def lyric_writer @lyric_writer end |
#plan ⇒ Object (readonly, private)
Returns the value of attribute plan.
53 54 55 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 53 def plan @plan end |
Instance Method Details
#beam_lines(beams) ⇒ Object (private)
93 94 95 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 93 def beam_lines(beams) beams.map { |beam| %(#{INDENT * 4}<beam number="#{beam.number}">#{beam.type}</beam>) } end |
#element_lines(placement, component, pitch: nil, chord: false, beams: [], voice_number: nil, staff_number: nil) ⇒ Object (private)
A chord note carries
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 75 def element_lines(placement, component, pitch: nil, chord: false, beams: [], voice_number: nil, staff_number: nil) [ "#{INDENT * 3}<note>", *(chord ? ["#{INDENT * 4}<chord/>"] : []), *(pitch ? pitch_lines(pitch) : ["#{INDENT * 4}<rest/>"]), "#{INDENT * 4}<duration>#{component.duration}</duration>", *tie_lines(placement, component), voice_number && "#{INDENT * 4}<voice>#{voice_number}</voice>", "#{INDENT * 4}<type>#{component.type}</type>", *Array.new(component.dots) { "#{INDENT * 4}<dot/>" }, staff_number && "#{INDENT * 4}<staff>#{staff_number}</staff>", *beam_lines(beams), *notation_lines(placement, component), *lyric_writer.lines(placement, component, chord: chord), "#{INDENT * 3}</note>" ].compact end |
#ensure_pitched_sounds(placement) ⇒ Object (private) Originally defined in module PlacementValidation
#escape(text) ⇒ Object (private) Originally defined in module XmlText
#lines(placement, voice_number: nil, staff_number: nil) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 23 def lines(placement, voice_number: nil, staff_number: nil) ensure_pitched_sounds(placement) components_by_placement[placement].each_with_index.flat_map do |component, component_index| beams = beam_annotations[[placement, component_index]] || [] note_slots(placement).each_with_index.flat_map do |pitch, index| element_lines( placement, component, pitch: pitch, chord: index.positive?, beams: index.zero? ? beams : [], voice_number: voice_number, staff_number: staff_number ) end end end |
#notation_lines(placement, component) ⇒ Object (private)
119 120 121 122 123 124 125 126 127 128 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 119 def notation_lines(placement, component) return [] if placement.rest? || (!component.tie_start && !component.tie_stop) [ "#{INDENT * 4}<notations>", component.tie_stop ? %(#{INDENT * 5}<tied type="stop"/>) : nil, component.tie_start ? %(#{INDENT * 5}<tied type="start"/>) : nil, "#{INDENT * 4}</notations>" ].compact end |
#note_slots(placement) ⇒ Object (private)
A rest emits one empty slot; a sounded placement emits its pitches low to
high, so the lowest note leads and the rest carry
60 61 62 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 60 def note_slots(placement) placement.rest? ? [nil] : placement.pitches.sort end |
#pitch_lines(pitch) ⇒ Object (private)
97 98 99 100 101 102 103 104 105 106 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 97 def pitch_lines(pitch) attributes = PitchWriter.attributes(pitch) [ "#{INDENT * 4}<pitch>", "#{INDENT * 5}<step>#{attributes[:step]}</step>", attributes[:alter] && "#{INDENT * 5}<alter>#{attributes[:alter]}</alter>", "#{INDENT * 5}<octave>#{attributes[:octave]}</octave>", "#{INDENT * 4}</pitch>" ].compact end |
#render_error_class ⇒ Object (private)
64 65 66 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 64 def render_error_class RenderError end |
#tie_lines(placement, component) ⇒ Object (private)
Rests take no tie elements; the links of a rest's tied chain render as consecutive independent rests.
110 111 112 113 114 115 116 117 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 110 def tie_lines(placement, component) return [] if placement.rest? [ component.tie_stop ? %(#{INDENT * 4}<tie type="stop"/>) : nil, component.tie_start ? %(#{INDENT * 4}<tie type="start"/>) : nil ].compact end |
#whole_measure_rest_lines(bar_number, voice_number: nil, staff_number: nil) ⇒ Object
The whole-measure rest that stands in for a bar the voice places nothing in. It belongs to its voice and staff as much as a note does, or a reader stacks it onto voice 1 of staff 1.
40 41 42 43 44 45 46 47 48 49 |
# File 'lib/head_music/notation/music_xml/note_writer.rb', line 40 def whole_measure_rest_lines(, voice_number: nil, staff_number: nil) [ "#{INDENT * 3}<note>", %(#{INDENT * 4}<rest measure="yes"/>), "#{INDENT * 4}<duration>#{plan.whole_measure_duration()}</duration>", voice_number && "#{INDENT * 4}<voice>#{voice_number}</voice>", staff_number && "#{INDENT * 4}<staff>#{staff_number}</staff>", "#{INDENT * 3}</note>" ].compact end |