Class: HeadMusic::Notation::RenderPlan
- Inherits:
-
Object
- Object
- HeadMusic::Notation::RenderPlan
show all
- Defined in:
- lib/head_music/notation/render_plan.rb
Overview
The measure-level facts every Writer needs, whatever format it emits; a
format's plan subclasses this and adds what only that format needs. Keys are
per part, because a mixed ensemble has as many written keys as it has
transpositions. Construction eagerly computes everything that can raise, so a
plan that builds successfully cannot fail assembly on those grounds.
Instance Attribute Summary collapse
Instance Method Summary
collapse
Constructor Details
#initialize(flow, transposed: false) ⇒ RenderPlan
Returns a new instance of RenderPlan.
12
13
14
15
16
|
# File 'lib/head_music/notation/render_plan.rb', line 12
def initialize(flow, transposed: false)
@flow = flow
@transposed = transposed
precompute_eager_data
end
|
Instance Attribute Details
#flow ⇒ Object
Returns the value of attribute flow.
10
11
12
|
# File 'lib/head_music/notation/render_plan.rb', line 10
def flow
@flow
end
|
Instance Method Details
#bar_numbers ⇒ Object
22
23
24
|
# File 'lib/head_music/notation/render_plan.rb', line 22
def bar_numbers
flow.earliest_bar_number..flow.latest_bar_number
end
|
#build_first_measure_key(part) ⇒ Object
81
82
83
84
|
# File 'lib/head_music/notation/render_plan.rb', line 81
def build_first_measure_key(part)
measure_key_changes(part)[bar_numbers.first] ||
written_key_value(part, bar_numbers.first, flow.timeline.opening_key_signature_event)
end
|
#build_measure_key_changes(part) ⇒ Object
86
87
88
89
90
91
|
# File 'lib/head_music/notation/render_plan.rb', line 86
def build_measure_key_changes(part)
changes = flow.key_signature_changes
.select { |bar_number, _| bar_numbers.cover?(bar_number) }
.to_h { |bar_number, event| [bar_number, written_key_value(part, bar_number, event)] }
changes.merge(instrument_change_keys(part))
end
|
#effective_key_event(bar_number) ⇒ Object
105
106
107
108
|
# File 'lib/head_music/notation/render_plan.rb', line 105
def effective_key_event(bar_number)
change_bar = flow.key_signature_changes.keys.select { |number| number <= bar_number }.max
change_bar ? flow.key_signature_changes[change_bar] : flow.timeline.opening_key_signature_event
end
|
#effective_meter(bar_number) ⇒ Object
44
45
46
47
|
# File 'lib/head_music/notation/render_plan.rb', line 44
def effective_meter(bar_number)
change_bar = measure_time_changes.keys.select { |number| number <= bar_number }.max
change_bar ? measure_time_changes[change_bar] : flow.meter
end
|
#first_measure_key(part = nil) ⇒ Object
36
37
38
|
# File 'lib/head_music/notation/render_plan.rb', line 36
def first_measure_key(part = nil)
keys_by_part[[:first, part]] ||= build_first_measure_key(part)
end
|
#first_measure_meter ⇒ Object
40
41
42
|
# File 'lib/head_music/notation/render_plan.rb', line 40
def first_measure_meter
@first_measure_meter ||= effective_meter(bar_numbers.first)
end
|
#instrument_change_keys(part) ⇒ Object
A part that changes instrument mid-flow changes written key with it, even
though the timeline holds no change there.
95
96
97
98
99
100
101
102
103
|
# File 'lib/head_music/notation/render_plan.rb', line 95
def instrument_change_keys(part)
return {} unless transposed? && part
bars = part.instrument_changes.keys.select { |bar| bar_numbers.cover?(bar) && bar > bar_numbers.first }
bars.filter_map { |bar|
value = written_key_value(part, bar, effective_key_event(bar))
[bar, value] unless value == written_key_value(part, bar - 1, effective_key_event(bar - 1))
}.to_h
end
|
#key_value(event) ⇒ Object
How the format renders a key signature event. The event rather than a key
signature, because MusicXML wants the signature and the interpretation as
separate elements and LilyPond can only say one of them.
125
126
127
|
# File 'lib/head_music/notation/render_plan.rb', line 125
def key_value(event)
raise NotImplementedError, "#{self.class} must map a key signature event to its rendering"
end
|
#keys_by_part ⇒ Object
77
78
79
|
# File 'lib/head_music/notation/render_plan.rb', line 77
def keys_by_part
@keys_by_part ||= {}
end
|
#measure_key_changes(part = nil) ⇒ Object
The key changes to print in this part, by bar. A nil part answers the
sounding key, which is every part's key in a concert-pitch plan.
28
29
30
|
# File 'lib/head_music/notation/render_plan.rb', line 28
def measure_key_changes(part = nil)
keys_by_part[[:changes, part]] ||= build_measure_key_changes(part)
end
|
#measure_time_changes ⇒ Object
32
33
34
|
# File 'lib/head_music/notation/render_plan.rb', line 32
def measure_time_changes
@measure_time_changes ||= flow.meter_changes.select { |bar_number, _| bar_numbers.cover?(bar_number) }
end
|
#placements_by_bar(voice) ⇒ Object
49
50
51
52
|
# File 'lib/head_music/notation/render_plan.rb', line 49
def placements_by_bar(voice)
@placements_by_bar ||= {}
@placements_by_bar[voice] ||= voice.placements.group_by { |placement| placement.position.bar_number }
end
|
#precompute_eager_data ⇒ Object
A subclass computes here whatever else must raise at construction, and
calls super for the signatures every format needs.
58
59
60
61
62
63
64
|
# File 'lib/head_music/notation/render_plan.rb', line 58
def precompute_eager_data
first_measure_key
first_measure_meter
measure_key_changes
measure_time_changes
precompute_part_keys
end
|
#precompute_part_keys ⇒ Object
A written key that no signature can print must raise here rather than
midway through assembly, so every part's keys are computed up front.
68
69
70
71
72
73
74
75
|
# File 'lib/head_music/notation/render_plan.rb', line 68
def precompute_part_keys
return unless transposed?
flow.parts.each do |part|
first_measure_key(part)
measure_key_changes(part)
end
end
|
#transposed? ⇒ Boolean
18
19
20
|
# File 'lib/head_music/notation/render_plan.rb', line 18
def transposed?
!!@transposed
end
|
#transposition_at(part, bar_number) ⇒ Object
116
117
118
119
120
|
# File 'lib/head_music/notation/render_plan.rb', line 116
def transposition_at(part, bar_number)
return nil unless transposed? && part
HeadMusic::Content::Layout::Transposition.for(part.instrument_at(bar_number))
end
|
#written_key_value(part, bar_number, event) ⇒ Object
In a concert-pitch plan the event is mapped exactly as it always was.
111
112
113
114
|
# File 'lib/head_music/notation/render_plan.rb', line 111
def written_key_value(part, bar_number, event)
transposition = transposition_at(part, bar_number)
key_value(transposition ? transposition.key_signature_event(event) : event)
end
|