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_ == "abort")
105 accepted_spanreqs_drul_[LEFT] = 0;
106 accepted_spanreqs_drul_[RIGHT] = 0;
108 line_spanner_->suicide ();
111 else if ((s->span_type_str_ == "crescendo"
112 || s->span_type_str_ == "decrescendo"))
114 accepted_spanreqs_drul_[s->span_dir_] = s;
122 Dynamic_engraver::do_process_music ()
124 if (accepted_spanreqs_drul_[START] || accepted_spanreqs_drul_[STOP] || text_req_l_)
129 line_spanner_ = new Spanner (get_property ("basicDynamicLineSpannerProperties"));
131 Side_position::set_axis (line_spanner_, Y_AXIS);
132 Axis_group_interface::set_interface (line_spanner_);
133 Axis_group_interface::set_axes (line_spanner_, Y_AXIS, Y_AXIS);
135 Request * rq = accepted_spanreqs_drul_[START];
136 if (text_req_l_) rq = text_req_l_ ;
137 announce_element (line_spanner_, rq);
144 finish side position alignment if the (de)cresc ends here, and
145 there are no new dynamics.
148 else if (accepted_spanreqs_drul_[STOP]
149 && !accepted_spanreqs_drul_[START] && !text_req_l_)
151 finished_line_spanner_ = line_spanner_;
156 todo: resurrect dynamic{direction, padding,minimumspace}
159 During a (de)crescendo, pending request will not be cleared,
160 and a line-spanner will always be created, as \< \! are already
163 Maybe always creating a line-spanner for a (de)crescendo (see
164 below) is not a good idea:
168 the \p will be centred on the line-spanner, and thus clash
169 with the hairpin. When axis-group code is in place, the \p
170 should move below the hairpin, which is probably better?
172 Urg, but line-spanner must always have at least same duration
173 as (de)crecsendo, b.o. line-breaking.
179 maybe we should leave dynamic texts to the text-engraver and
180 simply acknowledge them?
184 String loud = text_req_l_->text_str_;
186 text_p_ = new Item (get_property ("basicDynamicTextProperties"));
187 text_p_->set_elt_property ("text", ly_str02scm (loud.ch_C ()));
188 if (Direction d=text_req_l_->get_direction ())
189 Directional_element_interface::set (line_spanner_, d);
191 Axis_group_interface::add_element (line_spanner_, text_p_);
193 text_p_->add_offset_callback (Side_position::aligned_on_self,
195 announce_element (text_p_, text_req_l_);
198 if (accepted_spanreqs_drul_[STOP])
202 accepted_spanreqs_drul_[STOP]->origin ()->warning
203 (_ ("can't find start of (de)crescendo"));
207 assert (!finished_cresc_p_);
208 Score_element* cc = unsmob_element (get_property ("currentMusicalColumn"));
210 cresc_p_->set_bound (RIGHT, cc);
212 finished_cresc_p_ = cresc_p_;
214 current_cresc_req_ = 0;
218 if (accepted_spanreqs_drul_[START])
220 if (current_cresc_req_)
222 accepted_spanreqs_drul_[START]->origin ()->warning
223 (current_cresc_req_->span_dir_ == 1
224 ? _ ("already have a crescendo")
225 : _ ("already have a decrescendo"));
229 current_cresc_req_ = accepted_spanreqs_drul_[START];
230 cresc_p_ = new Spanner (get_property ("basicCrescendoProperties"));
231 Crescendo::set_interface (cresc_p_);
232 cresc_p_->set_elt_property
234 gh_int2scm ((accepted_spanreqs_drul_[START]->span_type_str_ == "crescendo")
235 ? BIGGER : SMALLER));
237 SCM s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Text").ch_C());
240 cresc_p_->set_elt_property ("start-text", s);
241 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
242 + "Text", SCM_UNDEFINED);
245 s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Spanner").ch_C());
251 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
253 cresc_p_->set_elt_property ("spanner", s);
254 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
255 + "Spanner", SCM_UNDEFINED);
258 Score_element *cc = unsmob_element (get_property ("currentMusicalColumn"));
259 cresc_p_->set_bound (LEFT, cc);
263 We know how wide the text is, if we can be sure that the
264 text already has relevant pointers into the paperdef,
265 and it has its font-size property set.
267 Since font-size may be set by a context higher up, we
268 can not be sure of the size.
271 We shouldn't try to do this stuff here, the Item should
272 do it when the score is finished. We could maybe
273 set a callback to have the Item do the alignment if
274 it is not a special symbol, like Crescendo.
280 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
281 LEFT, text_p_->self_scm ());
283 if (finished_cresc_p_
284 // I don't see why, but we need this check
285 && gh_pair_p (finished_cresc_p_->get_elt_property ("dynamic-drul")))
286 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
287 RIGHT, text_p_->self_scm ());
290 Axis_group_interface::add_element (line_spanner_, cresc_p_);
291 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
292 cresc_p_->add_offset_callback
293 (Side_position::aligned_on_self, Y_AXIS);
294 announce_element (cresc_p_, accepted_spanreqs_drul_[START]);
300 Dynamic_engraver::do_pre_move_processing ()
306 Dynamic_engraver::do_removal_processing ()
311 finished_line_spanner_ = line_spanner_;
317 current_cresc_req_->origin ()->warning (_ ("unterminated (de)crescendo"));
318 cresc_p_->suicide ();
324 Dynamic_engraver::typeset_all ()
326 if (finished_cresc_p_)
328 typeset_element (finished_cresc_p_);
329 finished_cresc_p_ =0;
334 typeset_element (text_p_);
337 if (finished_line_spanner_)
339 Side_position::add_staff_support (finished_line_spanner_);
340 extend_spanner_over_elements (finished_line_spanner_);
341 typeset_element (finished_line_spanner_);
342 finished_line_spanner_ = 0;
347 Dynamic_engraver::acknowledge_element (Score_element_info i)
349 if (Note_column::has_interface (i.elem_l_))
353 Side_position::add_support (line_spanner_,i.elem_l_);
354 add_bound_item (line_spanner_,dynamic_cast<Item*>(i.elem_l_));