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 cresc_p_->suicide ();
114 else if ((s->span_type_str_ == "crescendo"
115 || s->span_type_str_ == "decrescendo"))
117 accepted_spanreqs_drul_[s->span_dir_] = s;
125 Dynamic_engraver::do_process_music ()
127 if (accepted_spanreqs_drul_[START] || accepted_spanreqs_drul_[STOP] || text_req_l_)
132 line_spanner_ = new Spanner (get_property ("DynamicLineSpanner"));
134 Side_position::set_axis (line_spanner_, Y_AXIS);
135 Axis_group_interface::set_interface (line_spanner_);
136 Axis_group_interface::set_axes (line_spanner_, Y_AXIS, Y_AXIS);
138 Request * rq = accepted_spanreqs_drul_[START];
139 if (text_req_l_) rq = text_req_l_ ;
140 announce_element (line_spanner_, rq);
147 finish side position alignment if the (de)cresc ends here, and
148 there are no new dynamics.
151 else if (accepted_spanreqs_drul_[STOP]
152 && !accepted_spanreqs_drul_[START] && !text_req_l_)
154 finished_line_spanner_ = line_spanner_;
159 todo: resurrect dynamic{direction, padding,minimumspace}
162 During a (de)crescendo, pending request will not be cleared,
163 and a line-spanner will always be created, as \< \! are already
166 Maybe always creating a line-spanner for a (de)crescendo (see
167 below) is not a good idea:
171 the \p will be centred on the line-spanner, and thus clash
172 with the hairpin. When axis-group code is in place, the \p
173 should move below the hairpin, which is probably better?
175 Urg, but line-spanner must always have at least same duration
176 as (de)crecsendo, b.o. line-breaking.
182 maybe we should leave dynamic texts to the text-engraver and
183 simply acknowledge them?
187 String loud = text_req_l_->text_str_;
189 text_p_ = new Item (get_property ("DynamicText"));
190 text_p_->set_elt_property ("text", ly_str02scm (loud.ch_C ()));
191 if (Direction d=text_req_l_->get_direction ())
192 Directional_element_interface::set (line_spanner_, d);
194 Axis_group_interface::add_element (line_spanner_, text_p_);
196 announce_element (text_p_, text_req_l_);
199 if (accepted_spanreqs_drul_[STOP])
203 accepted_spanreqs_drul_[STOP]->origin ()->warning
204 (_ ("can't find start of (de)crescendo"));
208 assert (!finished_cresc_p_);
209 Score_element* cc = unsmob_element (get_property ("currentMusicalColumn"));
211 cresc_p_->set_bound (RIGHT, cc);
213 finished_cresc_p_ = cresc_p_;
215 current_cresc_req_ = 0;
219 if (accepted_spanreqs_drul_[START])
221 if (current_cresc_req_)
223 accepted_spanreqs_drul_[START]->origin ()->warning
224 (current_cresc_req_->span_dir_ == 1
225 ? _ ("already have a crescendo")
226 : _ ("already have a decrescendo"));
230 current_cresc_req_ = accepted_spanreqs_drul_[START];
231 cresc_p_ = new Spanner (get_property ("Crescendo"));
232 Crescendo::set_interface (cresc_p_);
233 cresc_p_->set_elt_property
235 gh_int2scm ((accepted_spanreqs_drul_[START]->span_type_str_ == "crescendo")
236 ? BIGGER : SMALLER));
238 SCM s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Text").ch_C());
241 cresc_p_->set_elt_property ("start-text", s);
242 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
243 + "Text", SCM_UNDEFINED);
246 s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Spanner").ch_C());
252 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
254 cresc_p_->set_elt_property ("spanner", s);
255 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
256 + "Spanner", SCM_UNDEFINED);
259 Score_element *cc = unsmob_element (get_property ("currentMusicalColumn"));
260 cresc_p_->set_bound (LEFT, cc);
264 We know how wide the text is, if we can be sure that the
265 text already has relevant pointers into the paperdef,
266 and it has its font-size property set.
268 Since font-size may be set by a context higher up, we
269 can not be sure of the size.
272 We shouldn't try to do this stuff here, the Item should
273 do it when the score is finished. We could maybe
274 set a callback to have the Item do the alignment if
275 it is not a special symbol, like Crescendo.
281 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
282 LEFT, text_p_->self_scm ());
284 if (finished_cresc_p_
285 // I don't see why, but we need this check
286 && gh_pair_p (finished_cresc_p_->get_elt_property ("dynamic-drul")))
287 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
288 RIGHT, text_p_->self_scm ());
291 Axis_group_interface::add_element (line_spanner_, cresc_p_);
292 announce_element (cresc_p_, accepted_spanreqs_drul_[START]);
298 Dynamic_engraver::do_pre_move_processing ()
304 Dynamic_engraver::do_removal_processing ()
309 finished_line_spanner_ = line_spanner_;
315 current_cresc_req_->origin ()->warning (_ ("unterminated (de)crescendo"));
316 cresc_p_->suicide ();
322 Dynamic_engraver::typeset_all ()
324 if (finished_cresc_p_)
326 typeset_element (finished_cresc_p_);
327 finished_cresc_p_ =0;
332 typeset_element (text_p_);
335 if (finished_line_spanner_)
337 Side_position::add_staff_support (finished_line_spanner_);
338 extend_spanner_over_elements (finished_line_spanner_);
339 typeset_element (finished_line_spanner_);
340 finished_line_spanner_ = 0;
345 Dynamic_engraver::acknowledge_element (Score_element_info i)
347 if (Note_column::has_interface (i.elem_l_))
351 Side_position::add_support (line_spanner_,i.elem_l_);
352 add_bound_item (line_spanner_,dynamic_cast<Item*>(i.elem_l_));