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 ("DynamicLineSpanner"));
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 ("DynamicText"));
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 announce_element (text_p_, text_req_l_);
196 if (accepted_spanreqs_drul_[STOP])
200 accepted_spanreqs_drul_[STOP]->origin ()->warning
201 (_ ("can't find start of (de)crescendo"));
205 assert (!finished_cresc_p_);
206 Score_element* cc = unsmob_element (get_property ("currentMusicalColumn"));
208 cresc_p_->set_bound (RIGHT, cc);
210 finished_cresc_p_ = cresc_p_;
212 current_cresc_req_ = 0;
216 if (accepted_spanreqs_drul_[START])
218 if (current_cresc_req_)
220 accepted_spanreqs_drul_[START]->origin ()->warning
221 (current_cresc_req_->span_dir_ == 1
222 ? _ ("already have a crescendo")
223 : _ ("already have a decrescendo"));
227 current_cresc_req_ = accepted_spanreqs_drul_[START];
228 cresc_p_ = new Spanner (get_property ("Crescendo"));
229 Crescendo::set_interface (cresc_p_);
230 cresc_p_->set_elt_property
232 gh_int2scm ((accepted_spanreqs_drul_[START]->span_type_str_ == "crescendo")
233 ? BIGGER : SMALLER));
235 SCM s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Text").ch_C());
238 cresc_p_->set_elt_property ("start-text", s);
239 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
240 + "Text", SCM_UNDEFINED);
243 s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Spanner").ch_C());
249 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
251 cresc_p_->set_elt_property ("spanner", s);
252 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
253 + "Spanner", SCM_UNDEFINED);
256 Score_element *cc = unsmob_element (get_property ("currentMusicalColumn"));
257 cresc_p_->set_bound (LEFT, cc);
261 We know how wide the text is, if we can be sure that the
262 text already has relevant pointers into the paperdef,
263 and it has its font-size property set.
265 Since font-size may be set by a context higher up, we
266 can not be sure of the size.
269 We shouldn't try to do this stuff here, the Item should
270 do it when the score is finished. We could maybe
271 set a callback to have the Item do the alignment if
272 it is not a special symbol, like Crescendo.
278 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
279 LEFT, text_p_->self_scm ());
281 if (finished_cresc_p_
282 // I don't see why, but we need this check
283 && gh_pair_p (finished_cresc_p_->get_elt_property ("dynamic-drul")))
284 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
285 RIGHT, text_p_->self_scm ());
288 Axis_group_interface::add_element (line_spanner_, cresc_p_);
289 announce_element (cresc_p_, accepted_spanreqs_drul_[START]);
295 Dynamic_engraver::do_pre_move_processing ()
301 Dynamic_engraver::do_removal_processing ()
306 finished_line_spanner_ = line_spanner_;
312 current_cresc_req_->origin ()->warning (_ ("unterminated (de)crescendo"));
313 cresc_p_->suicide ();
319 Dynamic_engraver::typeset_all ()
321 if (finished_cresc_p_)
323 typeset_element (finished_cresc_p_);
324 finished_cresc_p_ =0;
329 typeset_element (text_p_);
332 if (finished_line_spanner_)
334 Side_position::add_staff_support (finished_line_spanner_);
335 extend_spanner_over_elements (finished_line_spanner_);
336 typeset_element (finished_line_spanner_);
337 finished_line_spanner_ = 0;
342 Dynamic_engraver::acknowledge_element (Score_element_info i)
344 if (Note_column::has_interface (i.elem_l_))
348 Side_position::add_support (line_spanner_,i.elem_l_);
349 add_bound_item (line_spanner_,dynamic_cast<Item*>(i.elem_l_));