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);
126 announce_element (line_spanner_,
127 text_req_l_ ? text_req_l_ : accepted_spanreqs_drul_[START]);
133 finish side position alignment if the (de)cresc ends here, and
134 there are no new dynamics.
137 else if (accepted_spanreqs_drul_[STOP]
138 && !accepted_spanreqs_drul_[START] && !text_req_l_)
140 finished_line_spanner_ = line_spanner_;
145 todo: resurrect dynamic{direction, padding,minimumspace}
148 During a (de)crescendo, pending request will not be cleared,
149 and a line-spanner will always be created, as \< \! are already
152 Maybe always creating a line-spanner for a (de)crescendo (see
153 below) is not a good idea:
157 the \p will be centred on the line-spanner, and thus clash
158 with the hairpin. When axis-group code is in place, the \p
159 should move below the hairpin, which is probably better?
161 Urg, but line-spanner must always have at least same duration
162 as (de)crecsendo, b.o. line-breaking.
168 maybe we should leave dynamic texts to the text-engraver and
169 simply acknowledge them?
173 String loud = text_req_l_->text_str_;
175 text_p_ = new Item (get_property ("basicDynamicTextProperties"));
176 text_p_->set_elt_property ("text", ly_str02scm (loud.ch_C ()));
177 if (Direction d=text_req_l_->get_direction ())
178 Directional_element_interface::set (line_spanner_, d);
180 Axis_group_interface::add_element (line_spanner_, text_p_);
182 text_p_->add_offset_callback (Side_position::aligned_on_self,
184 announce_element (text_p_, text_req_l_);
187 if (accepted_spanreqs_drul_[STOP])
191 accepted_spanreqs_drul_[STOP]->origin ()->warning
192 (_ ("can't find start of (de)crescendo"));
196 assert (!finished_cresc_p_);
197 Score_element* cc = unsmob_element (get_property ("currentMusicalColumn"));
199 cresc_p_->set_bound (RIGHT, cc);
201 finished_cresc_p_ = cresc_p_;
203 current_cresc_req_ = 0;
207 if (accepted_spanreqs_drul_[START])
209 if (current_cresc_req_)
211 accepted_spanreqs_drul_[START]->origin ()->warning
212 (current_cresc_req_->span_dir_ == 1
213 ? _ ("already have a crescendo")
214 : _ ("already have a decrescendo"));
218 current_cresc_req_ = accepted_spanreqs_drul_[START];
219 cresc_p_ = new Spanner (get_property ("basicCrescendoProperties"));
220 Crescendo::set_interface (cresc_p_);
221 cresc_p_->set_elt_property
223 gh_int2scm ((accepted_spanreqs_drul_[START]->span_type_str_ == "crescendo")
224 ? BIGGER : SMALLER));
226 SCM s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Text").ch_C());
229 cresc_p_->set_elt_property ("start-text", s);
230 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
231 + "Text", SCM_UNDEFINED);
234 s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Spanner").ch_C());
240 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
242 cresc_p_->set_elt_property ("spanner", s);
243 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
244 + "Spanner", SCM_UNDEFINED);
247 Score_element *cc = unsmob_element (get_property ("currentMusicalColumn"));
248 cresc_p_->set_bound (LEFT, cc);
252 We know how wide the text is, if we can be sure that the
253 text already has relevant pointers into the paperdef,
254 and it has its font-size property set.
256 Since font-size may be set by a context higher up, we
257 can not be sure of the size.
260 We shouldn't try to do this stuff here, the Item should
261 do it when the score is finished. We could maybe
262 set a callback to have the Item do the alignment if
263 it is not a special symbol, like Crescendo.
269 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
270 LEFT, text_p_->self_scm ());
271 if (finished_cresc_p_)
272 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
273 RIGHT, text_p_->self_scm ());
276 Axis_group_interface::add_element (line_spanner_, cresc_p_);
277 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
278 cresc_p_->add_offset_callback
279 (Side_position::aligned_on_self, Y_AXIS);
280 announce_element (cresc_p_, accepted_spanreqs_drul_[START]);
286 Dynamic_engraver::do_pre_move_processing ()
292 Dynamic_engraver::do_removal_processing ()
297 finished_line_spanner_ = line_spanner_;
303 current_cresc_req_->origin ()->warning (_ ("unterminated (de)crescendo"));
304 cresc_p_->suicide ();
309 Dynamic_engraver::typeset_all ()
311 if (finished_cresc_p_)
313 typeset_element (finished_cresc_p_);
314 finished_cresc_p_ =0;
319 typeset_element (text_p_);
322 if (finished_line_spanner_)
324 Side_position::add_staff_support (finished_line_spanner_);
325 extend_spanner_over_elements (finished_line_spanner_);
326 typeset_element (finished_line_spanner_);
327 finished_line_spanner_ = 0;
332 Dynamic_engraver::acknowledge_element (Score_element_info i)
334 if (Note_column::has_interface (i.elem_l_))
338 Side_position::add_support (line_spanner_,i.elem_l_);
339 add_bound_item (line_spanner_,dynamic_cast<Item*>(i.elem_l_));