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 "dimension-cache.hh"
11 #include "crescendo.hh"
12 #include "musical-request.hh"
14 #include "paper-def.hh"
15 #include "paper-column.hh"
16 #include "staff-symbol.hh"
17 #include "note-column.hh"
18 #include "text-item.hh"
19 #include "side-position-interface.hh"
20 #include "engraver.hh"
22 #include "note-head.hh"
23 #include "group-interface.hh"
24 #include "directional-element-interface.hh"
25 #include "staff-symbol-referencer.hh"
26 #include "translator-group.hh"
32 * direction of text-dynamic-request if not equalt to direction
36 class Dynamic_line_spanner : public Spanner
39 Dynamic_line_spanner ();
40 VIRTUAL_COPY_CONS(Score_element);
41 void add_column (Item*);
44 virtual void after_line_breaking ();
47 Dynamic_line_spanner::Dynamic_line_spanner ()
49 set_elt_property ("transparent", SCM_BOOL_T);
50 side_position (this).set_axis (Y_AXIS);
54 Dynamic_line_spanner::add_column (Item* n)
56 if (!get_bound (LEFT))
65 Dynamic_line_spanner::after_line_breaking ()
70 We hebben hier een probleempje: er is een verschil tussen
71 dynamics zonder en met line-spanner.
72 Allen zijn gecentreerd (aligned-on-self), wat okee is,
73 maar de losse hebben zelf een padding tov de staff.
75 Deze padding werkt niet op items die in line-spanner zitten:
76 de padding werkt op line-spanner zelf.
77 De line-spanner moet dus eigenlijk zoveel naar beneden of boven
78 als er items uitsteken, maar Hmm.
81 Direction dir = directional_element (this).get ();
85 //translate_axis (extent (Y_AXIS)[dir], Y_AXIS);
86 translate_axis (staff_symbol_referencer (this).staff_space () * dir, Y_AXIS);
90 print text & hairpin dynamics.
92 class Dynamic_engraver : public Engraver
95 Crescendo * finished_cresc_p_;
98 Text_script_req* text_req_l_;
99 Span_req * span_start_req_l_;
100 Drul_array<Span_req*> span_req_l_drul_;
102 Dynamic_line_spanner* line_spanner_;
103 Dynamic_line_spanner* finished_line_spanner_;
104 Moment last_request_mom_;
106 Note_column* pending_column_;
107 Link_array<Score_element> pending_element_arr_;
112 VIRTUAL_COPY_CONS(Translator);
116 void announce_element (Score_element_info);
118 virtual void do_removal_processing ();
119 virtual void acknowledge_element (Score_element_info);
120 virtual bool do_try_music (Music *req_l);
121 virtual void do_process_music ();
122 virtual void do_pre_move_processing ();
123 virtual void do_post_move_processing ();
126 ADD_THIS_TRANSLATOR (Dynamic_engraver);
129 Dynamic_engraver::announce_element (Score_element_info i)
131 group (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
133 Engraver::announce_element (i);
137 Dynamic_engraver::Dynamic_engraver ()
140 finished_cresc_p_ = 0;
142 finished_line_spanner_ = 0;
143 span_start_req_l_ = 0;
148 span_req_l_drul_[START] = 0;
149 span_req_l_drul_[STOP] = 0;
153 Dynamic_engraver::do_post_move_processing ()
156 span_req_l_drul_[START] = 0;
157 span_req_l_drul_[STOP] = 0;
159 /* ugr; we must attach the Dynamic_line_spanner to something
160 to be sure that the linebreaker will not be confused
162 // if (line_spanner_)
163 // line_spanner_->add_column (LEFT, get_staff_info ().command_pcol_l ());
167 Dynamic_engraver::do_try_music (Music * m)
169 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
171 if (d->style_str_ == "dynamic")
177 else if (Span_req* s = dynamic_cast <Span_req*> (m))
179 if ((s->span_type_str_ == "crescendo"
180 || s->span_type_str_ == "decrescendo"))
182 span_req_l_drul_[s->span_dir_] = s;
190 Dynamic_engraver::do_process_music ()
192 if ((span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
194 && pending_element_arr_.size ())
196 line_spanner_ = new Dynamic_line_spanner;
197 assert (pending_column_);
198 line_spanner_->add_column (pending_column_);
199 announce_element (Score_element_info
201 text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
205 if (line_spanner_ && pending_element_arr_.size ())
207 for (int i = 0; i < pending_element_arr_.size (); i++)
208 pending_element_arr_[i]->set_parent (line_spanner_, Y_AXIS);
209 pending_element_arr_.clear ();
212 if (span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
213 last_request_mom_ = now_mom ();
219 Maybe always creating a line-spanner for a (de)crescendo (see
220 below) is not a good idea:
224 the \p will be centred on the line-spanner, and thus clash
225 with the hairpin. When axis-group code is in place, the \p
226 should move below the hairpin, which is probably better?
228 if (now_mom () > last_request_mom_)
231 During a (de)crescendo, pending request will not be cleared,
232 and a line-spanner will always be created, as \< \! are already
235 if (now_mom () > last_request_mom_ && !span_start_req_l_)
238 for (int i = 0; i < pending_element_arr_.size (); i++)
240 Score_element* e = pending_element_arr_[i];
241 side_position (e).set_axis (Y_AXIS);
242 side_position (e).add_staff_support ();
247 Direction d = directional_element (e).get ();
250 SCM s = get_property ("dynamicDirection");
252 s = get_property ("verticalDirection");
255 directional_element (e).set (d);
258 SCM s = get_property ("dynamicPadding");
260 e->set_elt_property ("padding", s);
261 s = get_property ("dynamicMinimumSpace");
263 e->set_elt_property ("minimum-space", s);
265 pending_element_arr_.clear ();
266 finished_line_spanner_ = line_spanner_;
273 String loud = text_req_l_->text_str_;
275 text_p_ = new Text_item;
276 text_p_->set_elt_property ("text",
277 ly_str02scm (loud.ch_C ()));
278 text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
279 text_p_->set_elt_property ("script-priority",
281 if (Direction d=text_req_l_->get_direction ())
282 directional_element (text_p_).set (d);
283 pending_element_arr_.push (text_p_);
284 text_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
285 text_p_->add_offset_callback (Side_position_interface::aligned_on_self,
287 announce_element (Score_element_info (text_p_, text_req_l_));
290 if (span_req_l_drul_[STOP])
294 span_req_l_drul_[STOP]->warning
295 (_ ("can't find start of (de)crescendo"));
299 assert (!finished_cresc_p_);
300 cresc_p_->set_bound(RIGHT, get_staff_info ().musical_pcol_l ());
301 finished_cresc_p_ = cresc_p_;
303 span_start_req_l_ = 0;
307 if (span_req_l_drul_[START])
309 if (span_start_req_l_)
311 span_req_l_drul_[START]->warning
312 (span_start_req_l_->span_dir_ == 1
314 _ ("already have a crescendo")
315 : _ ("already have a decrescendo"));
319 span_start_req_l_ = span_req_l_drul_[START];
320 cresc_p_ = new Crescendo;
321 cresc_p_->set_elt_property
323 gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
324 ? BIGGER : SMALLER));
326 SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
329 cresc_p_->set_elt_property ("start-text", s);
330 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
331 + "Text", SCM_UNDEFINED);
334 s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
335 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
337 cresc_p_->set_elt_property ("spanner", s);
338 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
339 + "Spanner", SCM_UNDEFINED);
342 cresc_p_->set_bound(LEFT, get_staff_info ().musical_pcol_l ());
346 We know how wide the text is, if we can be sure that the
347 text already has relevant pointers into the paperdef,
348 and it has its font-size property set.
350 Since font-size may be set by a context higher up, we
351 can not be sure of the size.
354 We shouldn't try to do this stuff here, the Item should
355 do it when the score is finished. We could maybe
356 set a callback to have the Item do the alignment if
357 it is not a special symbol, like Crescendo.
363 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
365 if (finished_cresc_p_)
366 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
369 pending_element_arr_.push (cresc_p_);
370 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
371 cresc_p_->add_offset_callback
372 (Side_position_interface::aligned_on_self, Y_AXIS);
373 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
379 Dynamic_engraver::do_pre_move_processing ()
385 Dynamic_engraver::do_removal_processing ()
389 typeset_element (cresc_p_ );
390 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
396 side_position (line_spanner_).add_staff_support ();
397 typeset_element (line_spanner_);
403 Dynamic_engraver::typeset_all ()
405 if (finished_cresc_p_)
407 typeset_element (finished_cresc_p_);
408 finished_cresc_p_ =0;
413 typeset_element (text_p_);
418 TODO: This should be optionised:
419 * break when group of dynamic requests ends
421 * continue through piece */
422 // if (line_spanner_ && last_request_mom_ < now_mom ())
423 if (finished_line_spanner_)
425 side_position (finished_line_spanner_).add_staff_support ();
426 typeset_element (finished_line_spanner_);
427 finished_line_spanner_ = 0;
432 Dynamic_engraver::acknowledge_element (Score_element_info i)
434 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
438 side_position (line_spanner_).add_support (n);
439 line_spanner_->add_column (n);