Class: Clef::Renderer::PdfRenderer
- Includes:
- NotationHelpers
- Defined in:
- lib/clef/renderer/pdf_renderer.rb
Constant Summary collapse
- LEFT_PADDING =
80- TOP_PADDING =
56- STAFF_START_X =
160
Constants included from NotationHelpers
NotationHelpers::ACCIDENTAL_FALLBACK, NotationHelpers::ACCIDENTAL_GLYPH_KEYS, NotationHelpers::FLAT_ORDER, NotationHelpers::REST_LABELS, NotationHelpers::SHARP_ORDER
Instance Attribute Summary
Attributes inherited from Base
#font_manager, #glyph_table, #style
Instance Method Summary collapse
- #draw_accidental(pdf, pitch, x, y, key_signature, state) ⇒ Object
- #draw_articulations(pdf, articulations, x, y) ⇒ Object
- #draw_barline(pdf, x, baseline) ⇒ Object
- #draw_chord(pdf, chord, x, baseline, clef, accidental_state:, key_signature:) ⇒ Object
- #draw_chord_stem(pdf, notes, x, ys, clef) ⇒ Object
- #draw_clef(pdf, clef, x, baseline) ⇒ Object
- #draw_dot(pdf, duration, x, y) ⇒ Object
- #draw_element(pdf, element, x, baseline, clef) ⇒ Object
- #draw_fermata(pdf, x, y) ⇒ Object
- #draw_measure(pdf, measure, staff, start_x, baseline, measure_start = Clef::Ir::Moment.new(0), positions = nil, layout = nil, system: nil) ⇒ Hash
- #draw_measures(pdf, staff, start_x, baseline, positions = nil, layout = nil, system: nil) ⇒ Object
- #draw_metadata(pdf, staff, x, baseline) ⇒ Object
- #draw_note(pdf, note, x, baseline, clef, accidental_state:, key_signature:) ⇒ Object
- #draw_notehead(pdf, x, y, duration:) ⇒ Object
- #draw_rest(pdf, rest, x, baseline) ⇒ Object
- #draw_score(pdf, score, positions, layout: nil) ⇒ Object
- #draw_slurs(pdf, slurs = [], note_points: {}) ⇒ Object
- #draw_staff(pdf, staff, baseline, positions: nil, layout: nil) ⇒ Object
- #draw_staff_lines(pdf, baseline) ⇒ Object
- #draw_stem(pdf, note, x, y, clef) ⇒ Object
- #draw_ties(pdf, ties = [], note_points: {}) ⇒ Object
- #draw_tuplet(pdf, tuplet, x, baseline, clef, accidental_state:, key_signature:, note_points: {}) ⇒ Object
- #render(score, path, positions: nil, layout: nil, **_options) ⇒ Object
Methods inherited from Base
Constructor Details
This class inherits a constructor from Clef::Renderer::Base
Instance Method Details
#draw_accidental(pdf, pitch, x, y, key_signature, state) ⇒ Object
287 288 289 290 291 292 293 294 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 287 def draw_accidental(pdf, pitch, x, y, key_signature, state) alteration = accidental_for_pitch(pitch, key_signature, state) return if alteration.nil? key = accidental_glyph_key(alteration) glyph = smufl_enabled? ? glyph_table[key] : accidental_text(alteration) pdf.text_box(glyph, at: [x - 12, y + 5], size: 9) end |
#draw_articulations(pdf, articulations, x, y) ⇒ Object
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 313 def draw_articulations(pdf, articulations, x, y) articulations.each do |articulation| case articulation when :staccato pdf.circle([x, y + 12], 1.5) pdf.fill when :tenuto pdf.stroke_line [x - 4, y + 12], [x + 4, y + 12] when :accent pdf.text_box(">", at: [x - 4, y + 14], size: 9) when :marcato pdf.stroke_line [x - 4, y + 10], [x, y + 16] pdf.stroke_line [x, y + 16], [x + 4, y + 10] when :fermata draw_fermata(pdf, x, y) else pdf.text_box(articulation.to_s, at: [x - 4, y + 12], size: 6) end end end |
#draw_barline(pdf, x, baseline) ⇒ Object
349 350 351 352 353 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 349 def (pdf, x, baseline) top = baseline + (style.staff_space * 0.5) bottom = baseline - (style.staff_space * 4.5) pdf.stroke_line [x, top], [x, bottom] end |
#draw_chord(pdf, chord, x, baseline, clef, accidental_state:, key_signature:) ⇒ Object
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 203 def draw_chord(pdf, chord, x, baseline, clef, accidental_state:, key_signature:) notes = chord_notes(chord) offsets = chord_note_offsets(notes) ys = [] notes.each_with_index do |note, index| y = pitch_to_y(note.pitch, baseline, clef) ys << y note_x = x + offsets[index] draw_ledger_lines(pdf, note_x, y, baseline) draw_notehead(pdf, note_x, y, duration: chord.duration) draw_accidental(pdf, note.pitch, note_x - accidental_offset(index), y, key_signature, accidental_state) end draw_chord_stem(pdf, notes, x, ys, clef) if stem_required?(chord.duration) ys.each { |y| draw_dot(pdf, chord.duration, x, y) } end |
#draw_chord_stem(pdf, notes, x, ys, clef) ⇒ Object
270 271 272 273 274 275 276 277 278 279 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 270 def draw_chord_stem(pdf, notes, x, ys, clef) direction = Clef::Layout::Stem.direction(notes, clef) anchor_note = chord_stem_anchor_note(notes, direction) anchor_index = notes.index(anchor_note) anchor_y = ys[anchor_index] stem_len = style.staff_space * chord_stem_length(notes, clef, direction) y2 = (direction == :up) ? anchor_y + stem_len : anchor_y - stem_len stem_x = (direction == :up) ? x + 3 : x - 3 pdf.stroke_line [stem_x, anchor_y], [stem_x, y2] end |
#draw_clef(pdf, clef, x, baseline) ⇒ Object
75 76 77 78 79 80 81 82 83 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 75 def draw_clef(pdf, clef, x, baseline) glyph = smufl_enabled? ? glyph_table[:"clef_#{clef.type}"] : fallback_clef_text(clef) glyph ||= fallback_clef_text(clef) size = smufl_enabled? ? 16 : 10 y = smufl_enabled? ? (baseline - style.staff_space) : (baseline + (style.staff_space * 1.5)) pdf.text_box(glyph, at: [x, y], size: size) x + text_width(pdf, glyph, size: size) end |
#draw_dot(pdf, duration, x, y) ⇒ Object
300 301 302 303 304 305 306 307 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 300 def draw_dot(pdf, duration, x, y) return if duration.dots.zero? duration.dots.times do |index| pdf.circle([x + 8 + (index * 3), y], 1) pdf.fill end end |
#draw_element(pdf, element, x, baseline, clef) ⇒ Object
153 154 155 156 157 158 159 160 161 162 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 153 def draw_element(pdf, element, x, baseline, clef) case element when Clef::Core::Note then draw_note(pdf, element, x, baseline, clef, accidental_state: {}, key_signature: nil) when Clef::Core::Rest then draw_rest(pdf, element, x, baseline) when Clef::Core::Chord then draw_chord(pdf, element, x, baseline, clef, accidental_state: {}, key_signature: nil) when Clef::Core::Tuplet then draw_tuplet(pdf, element, x, baseline, clef, accidental_state: {}, key_signature: nil) when Clef::Notation::Dynamic then draw_dynamic(pdf, element, x, baseline) when Clef::Core::Tempo then draw_tempo_change(pdf, element, x, baseline) end end |
#draw_fermata(pdf, x, y) ⇒ Object
334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 334 def draw_fermata(pdf, x, y) if pdf.respond_to?(:stroke_curve) pdf.stroke_curve [x - 7, y + 12], [x + 7, y + 12], bounds: [[x - 5, y + 18], [x + 5, y + 18]] else pdf.stroke_line [x - 7, y + 12], [x, y + 17] pdf.stroke_line [x, y + 17], [x + 7, y + 12] end pdf.circle([x, y + 12], 1.2) pdf.fill end |
#draw_measure(pdf, measure, staff, start_x, baseline, measure_start = Clef::Ir::Moment.new(0), positions = nil, layout = nil, system: nil) ⇒ Hash
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 128 def draw_measure(pdf, measure, staff, start_x, baseline, measure_start = Clef::Ir::Moment.new(0), positions = nil, layout = nil, system: nil) note_points = {} voice_elements = {} accidental_state = {} measure.voices.each_with_index do |(voice_id, voice), index| voice_elements[voice_id] = voice.elements cursor = Clef::Ir::Moment.new(measure_start.value) voice_baseline = baseline + voice_vertical_offset(index) voice.elements.each do |element| if system.nil? || system.include_moment?(cursor) x = x_for_moment(positions, cursor, start_x, position_offset: system&.position_offset) draw_element_with_context(pdf, element, x, voice_baseline, staff, measure, accidental_state, note_points) end cursor += element.length end draw_beams(pdf, layout, staff, measure, voice_id, note_points) end [note_points, voice_elements] end |
#draw_measures(pdf, staff, start_x, baseline, positions = nil, layout = nil, system: nil) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 100 def draw_measures(pdf, staff, start_x, baseline, positions = nil, layout = nil, system: nil) note_points = {} voice_elements = Hash.new { |hash, key| hash[key] = [] } measure_start = Clef::Ir::Moment.new(0) staff.measures.each do |measure| measure_points, measure_voice_elements = draw_measure(pdf, measure, staff, start_x, baseline, measure_start, positions, layout, system: system) note_points.merge!(measure_points) measure_voice_elements.each { |voice_id, elements| voice_elements[voice_id].concat(elements) } = measure_start + measure_length_for(measure) if system.nil? || system.include_moment?() = x_for_moment(positions, , start_x, position_offset: system&.position_offset) (pdf, , baseline) end measure_start += measure_length_for(measure) end voice_elements.each_value { |elements| draw_note_connections(pdf, elements, note_points) } note_points end |
#draw_metadata(pdf, staff, x, baseline) ⇒ Object
89 90 91 92 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 89 def (pdf, staff, x, baseline) cursor = draw_key_signature(pdf, staff.key_signature, x, baseline) draw_time_signature(pdf, staff.time_signature, cursor + style.staff_space, baseline) end |
#draw_note(pdf, note, x, baseline, clef, accidental_state:, key_signature:) ⇒ Object
169 170 171 172 173 174 175 176 177 178 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 169 def draw_note(pdf, note, x, baseline, clef, accidental_state:, key_signature:) y = pitch_to_y(note.pitch, baseline, clef) draw_ledger_lines(pdf, x, y, baseline) draw_notehead(pdf, x, y, duration: note.duration) draw_accidental(pdf, note.pitch, x, y, key_signature, accidental_state) draw_stem(pdf, note, x, y, clef) if stem_required?(note.duration) draw_flag(pdf, note, x, y, clef) if flag_required?(note.duration) draw_dot(pdf, note.duration, x, y) draw_articulations(pdf, note.articulations, x, y) end |
#draw_notehead(pdf, x, y, duration:) ⇒ Object
239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 239 def draw_notehead(pdf, x, y, duration:) pdf.fill_color("000000") if filled_notehead?(duration) pdf.circle([x, y], style.notehead_width / 2.0) pdf.fill else pdf.fill_color("FFFFFF") pdf.ellipse([x, y], style.notehead_width / 2.0, 2.5) pdf.fill_and_stroke pdf.fill_color("000000") end end |
#draw_rest(pdf, rest, x, baseline) ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 184 def draw_rest(pdf, rest, x, baseline) return if rest.kind == :invisible || rest.kind == :spacer glyph = if smufl_enabled? glyph_table[rest_glyph_key(rest.duration)] || glyph_table[:rest_quarter] else rest_label(rest.duration) end pdf.text_box(glyph, at: [x, rest_y(rest, baseline)], size: 14) return unless rest.kind == :multi_measure && rest.measures > 1 pdf.text_box(rest.measures.to_s, at: [x - 2, baseline + style.staff_space], size: 8) end |
#draw_score(pdf, score, positions, layout: nil) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 32 def draw_score(pdf, score, positions, layout: nil) return draw_systems(pdf, score, layout) if layout&.dig(:systems)&.any? draw_header(pdf, score) staff_index = 0 score.staff_groups.each do |group| group_start = pdf.cursor - TOP_PADDING - (staff_index * style.staff_gap) group.staves.each do |staff| baseline = pdf.cursor - TOP_PADDING - (staff_index * style.staff_gap) draw_staff(pdf, staff, baseline, positions: positions, layout: layout) staff_index += 1 end draw_staff_group(pdf, group, group_start, staff_index - 1) if group.staves.length > 1 end end |
#draw_slurs(pdf, slurs = [], note_points: {}) ⇒ Object
358 359 360 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 358 def draw_slurs(pdf, slurs = [], note_points: {}) slurs.each { |slur| draw_notation_connection(pdf, slur, note_points, lift: 14) } end |
#draw_staff(pdf, staff, baseline, positions: nil, layout: nil) ⇒ Object
53 54 55 56 57 58 59 60 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 53 def draw_staff(pdf, staff, baseline, positions: nil, layout: nil) draw_staff_lines(pdf, baseline) cursor = draw_clef(pdf, staff.clef, LEFT_PADDING - 24, baseline) cursor = draw_key_signature(pdf, staff.key_signature, cursor + style.staff_space, baseline) cursor = draw_time_signature(pdf, staff.time_signature, cursor + style.staff_space, baseline) note_points = draw_measures(pdf, staff, [cursor + style.measure_padding, STAFF_START_X].max, baseline, positions, layout) draw_lyrics(pdf, staff, note_points, baseline) end |
#draw_staff_lines(pdf, baseline) ⇒ Object
64 65 66 67 68 69 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 64 def draw_staff_lines(pdf, baseline) 5.times do |index| y = baseline - (index * style.staff_space) pdf.stroke_line [LEFT_PADDING, y], [staff_right_bound(pdf), y] end end |
#draw_stem(pdf, note, x, y, clef) ⇒ Object
257 258 259 260 261 262 263 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 257 def draw_stem(pdf, note, x, y, clef) direction = Clef::Layout::Stem.direction(note, clef) stem_len = style.staff_space * Clef::Layout::Stem.length(note, clef, direction) y2 = (direction == :up) ? y + stem_len : y - stem_len stem_x = (direction == :up) ? x + 3 : x - 3 pdf.stroke_line [stem_x, y], [stem_x, y2] end |
#draw_ties(pdf, ties = [], note_points: {}) ⇒ Object
365 366 367 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 365 def draw_ties(pdf, ties = [], note_points: {}) ties.each { |tie| draw_notation_connection(pdf, tie, note_points, lift: 8) } end |
#draw_tuplet(pdf, tuplet, x, baseline, clef, accidental_state:, key_signature:, note_points: {}) ⇒ Object
224 225 226 227 228 229 230 231 232 233 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 224 def draw_tuplet(pdf, tuplet, x, baseline, clef, accidental_state:, key_signature:, note_points: {}) cursor = x staff_context = Struct.new(:clef, :key_signature).new(clef, key_signature) measure_context = Struct.new(:key_signature).new(key_signature) tuplet.elements.each do |element| draw_element_with_context(pdf, element, cursor, baseline, staff_context, measure_context, accidental_state, note_points) cursor += duration_spacing(element) * tuplet.ratio end pdf.text_box(tuplet.actual.to_s, at: [x + ((cursor - x) / 2.0), baseline + style.staff_space], size: 8) end |
#render(score, path, positions: nil, layout: nil, **_options) ⇒ Object
18 19 20 21 22 23 24 25 26 |
# File 'lib/clef/renderer/pdf_renderer.rb', line 18 def render(score, path, positions: nil, layout: nil, **) return render_to_io(score, path, positions: positions, layout: layout) if path.respond_to?(:write) ensure_parent_directory!(path) Prawn::Document.generate(path, page_size: style.page_size, margin: style.margin) do |pdf| prepare_canvas(pdf) draw_score(pdf, score, positions, layout: layout) end end |