2 dynamic-engraver.cc -- implement Dynamic_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "dimensions.hh"
10 #include "crescendo.hh"
11 #include "musical-request.hh"
12 #include "paper-column.hh"
13 #include "note-column.hh"
15 #include "side-position-interface.hh"
16 #include "engraver.hh"
17 #include "group-interface.hh"
18 #include "directional-element-interface.hh"
19 #include "translator-group.hh"
20 #include "axis-group-interface.hh"
26 * direction of text-dynamic-request if not equal to direction of
31 print text & hairpin dynamics.
33 class Dynamic_engraver : public Engraver
36 Spanner * finished_cresc_p_;
39 Text_script_req* text_req_l_;
41 Span_req * current_cresc_req_;
42 Drul_array<Span_req*> accepted_spanreqs_drul_;
44 Spanner* line_spanner_;
45 Spanner* finished_line_spanner_;
47 Link_array<Note_column> pending_column_arr_;
48 Link_array<Score_element> pending_element_arr_;
53 VIRTUAL_COPY_CONS(Translator);
57 virtual void do_removal_processing ();
58 virtual void acknowledge_element (Score_element_info);
59 virtual bool do_try_music (Music *req_l);
60 virtual void do_process_music ();
61 virtual void do_pre_move_processing ();
62 virtual void do_post_move_processing ();
65 ADD_THIS_TRANSLATOR (Dynamic_engraver);
68 Dynamic_engraver::Dynamic_engraver ()
71 finished_cresc_p_ = 0;
73 finished_line_spanner_ = 0;
74 current_cresc_req_ = 0;
78 accepted_spanreqs_drul_[START] = 0;
79 accepted_spanreqs_drul_[STOP] = 0;
83 Dynamic_engraver::do_post_move_processing ()
86 accepted_spanreqs_drul_[START] = 0;
87 accepted_spanreqs_drul_[STOP] = 0;
91 Dynamic_engraver::do_try_music (Music * m)
93 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
95 if (d->style_str_ == "dynamic")
101 else if (Span_req* s = dynamic_cast <Span_req*> (m))
103 if ((s->span_type_str_ == "crescendo"
104 || s->span_type_str_ == "decrescendo"))
106 accepted_spanreqs_drul_[s->span_dir_] = s;
114 Dynamic_engraver::do_process_music ()
116 if (accepted_spanreqs_drul_[START] || accepted_spanreqs_drul_[STOP] || text_req_l_)
121 line_spanner_ = new Spanner (get_property ("basicDynamicLineSpannerProperties"));
123 Side_position::set_axis (line_spanner_, Y_AXIS);
124 Axis_group_interface::set_interface (line_spanner_);
125 Axis_group_interface::set_axes (line_spanner_, Y_AXIS, Y_AXIS);
127 Request * rq = accepted_spanreqs_drul_[START];
128 if (text_req_l_) rq = text_req_l_ ;
129 announce_element (line_spanner_, rq);
136 finish side position alignment if the (de)cresc ends here, and
137 there are no new dynamics.
140 else if (accepted_spanreqs_drul_[STOP]
141 && !accepted_spanreqs_drul_[START] && !text_req_l_)
143 finished_line_spanner_ = line_spanner_;
148 todo: resurrect dynamic{direction, padding,minimumspace}
151 During a (de)crescendo, pending request will not be cleared,
152 and a line-spanner will always be created, as \< \! are already
155 Maybe always creating a line-spanner for a (de)crescendo (see
156 below) is not a good idea:
160 the \p will be centred on the line-spanner, and thus clash
161 with the hairpin. When axis-group code is in place, the \p
162 should move below the hairpin, which is probably better?
164 Urg, but line-spanner must always have at least same duration
165 as (de)crecsendo, b.o. line-breaking.
171 maybe we should leave dynamic texts to the text-engraver and
172 simply acknowledge them?
176 String loud = text_req_l_->text_str_;
178 text_p_ = new Item (get_property ("basicDynamicTextProperties"));
179 text_p_->set_elt_property ("text", ly_str02scm (loud.ch_C ()));
180 if (Direction d=text_req_l_->get_direction ())
181 Directional_element_interface::set (line_spanner_, d);
183 Axis_group_interface::add_element (line_spanner_, text_p_);
185 text_p_->add_offset_callback (Side_position::aligned_on_self,
187 announce_element (text_p_, text_req_l_);
190 if (accepted_spanreqs_drul_[STOP])
194 accepted_spanreqs_drul_[STOP]->origin ()->warning
195 (_ ("can't find start of (de)crescendo"));
199 assert (!finished_cresc_p_);
200 Score_element* cc = unsmob_element (get_property ("currentMusicalColumn"));
202 cresc_p_->set_bound (RIGHT, cc);
204 finished_cresc_p_ = cresc_p_;
206 current_cresc_req_ = 0;
210 if (accepted_spanreqs_drul_[START])
212 if (current_cresc_req_)
214 accepted_spanreqs_drul_[START]->origin ()->warning
215 (current_cresc_req_->span_dir_ == 1
216 ? _ ("already have a crescendo")
217 : _ ("already have a decrescendo"));
221 current_cresc_req_ = accepted_spanreqs_drul_[START];
222 cresc_p_ = new Spanner (get_property ("basicCrescendoProperties"));
223 Crescendo::set_interface (cresc_p_);
224 cresc_p_->set_elt_property
226 gh_int2scm ((accepted_spanreqs_drul_[START]->span_type_str_ == "crescendo")
227 ? BIGGER : SMALLER));
229 SCM s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Text").ch_C());
232 cresc_p_->set_elt_property ("start-text", s);
233 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
234 + "Text", SCM_UNDEFINED);
237 s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Spanner").ch_C());
243 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
245 cresc_p_->set_elt_property ("spanner", s);
246 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
247 + "Spanner", SCM_UNDEFINED);
250 Score_element *cc = unsmob_element (get_property ("currentMusicalColumn"));
251 cresc_p_->set_bound (LEFT, cc);
255 We know how wide the text is, if we can be sure that the
256 text already has relevant pointers into the paperdef,
257 and it has its font-size property set.
259 Since font-size may be set by a context higher up, we
260 can not be sure of the size.
263 We shouldn't try to do this stuff here, the Item should
264 do it when the score is finished. We could maybe
265 set a callback to have the Item do the alignment if
266 it is not a special symbol, like Crescendo.
272 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
273 LEFT, text_p_->self_scm ());
275 if (finished_cresc_p_
276 // I don't see why, but we need this check
277 && gh_pair_p (finished_cresc_p_->get_elt_property ("dynamic-drul")))
278 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
279 RIGHT, text_p_->self_scm ());
282 Axis_group_interface::add_element (line_spanner_, cresc_p_);
283 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
284 cresc_p_->add_offset_callback
285 (Side_position::aligned_on_self, Y_AXIS);
286 announce_element (cresc_p_, accepted_spanreqs_drul_[START]);
292 Dynamic_engraver::do_pre_move_processing ()
298 Dynamic_engraver::do_removal_processing ()
303 finished_line_spanner_ = line_spanner_;
309 current_cresc_req_->origin ()->warning (_ ("unterminated (de)crescendo"));
310 cresc_p_->suicide ();
316 Dynamic_engraver::typeset_all ()
318 if (finished_cresc_p_)
320 typeset_element (finished_cresc_p_);
321 finished_cresc_p_ =0;
326 typeset_element (text_p_);
329 if (finished_line_spanner_)
331 Side_position::add_staff_support (finished_line_spanner_);
332 extend_spanner_over_elements (finished_line_spanner_);
333 typeset_element (finished_line_spanner_);
334 finished_line_spanner_ = 0;
339 Dynamic_engraver::acknowledge_element (Score_element_info i)
341 if (Note_column::has_interface (i.elem_l_))
345 Side_position::add_support (line_spanner_,i.elem_l_);
346 add_bound_item (line_spanner_,dynamic_cast<Item*>(i.elem_l_));