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 Moment last_request_mom_;
105 Note_column* pending_column_;
106 Link_array<Score_element> pending_element_arr_;
111 VIRTUAL_COPY_CONS(Translator);
115 void announce_element (Score_element_info);
117 virtual void do_removal_processing ();
118 virtual void acknowledge_element (Score_element_info);
119 virtual bool do_try_music (Music *req_l);
120 virtual void do_process_music ();
121 virtual void do_pre_move_processing ();
122 virtual void do_post_move_processing ();
125 ADD_THIS_TRANSLATOR (Dynamic_engraver);
128 Dynamic_engraver::announce_element (Score_element_info i)
130 group (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
132 Engraver::announce_element (i);
136 Dynamic_engraver::Dynamic_engraver ()
139 finished_cresc_p_ = 0;
141 span_start_req_l_ = 0;
146 span_req_l_drul_[START] = 0;
147 span_req_l_drul_[STOP] = 0;
151 Dynamic_engraver::do_post_move_processing ()
154 span_req_l_drul_[START] = 0;
155 span_req_l_drul_[STOP] = 0;
157 /* ugr; we must attach the Dynamic_line_spanner to something
158 to be sure that the linebreaker will not be confused
160 // if (line_spanner_)
161 // line_spanner_->add_column (LEFT, get_staff_info ().command_pcol_l ());
165 Dynamic_engraver::do_try_music (Music * m)
167 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
169 if (d->style_str_ == "dynamic")
175 else if (Span_req* s = dynamic_cast <Span_req*> (m))
177 if ((s->span_type_str_ == "crescendo"
178 || s->span_type_str_ == "decrescendo"))
180 span_req_l_drul_[s->span_dir_] = s;
188 Dynamic_engraver::do_process_music ()
190 if ((span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
192 && pending_element_arr_.size ())
194 line_spanner_ = new Dynamic_line_spanner;
195 assert (pending_column_);
196 line_spanner_->add_column (pending_column_);
197 announce_element (Score_element_info
199 text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
203 if (line_spanner_ && pending_element_arr_.size ())
205 for (int i = 0; i < pending_element_arr_.size (); i++)
206 pending_element_arr_[i]->set_parent (line_spanner_, Y_AXIS);
207 pending_element_arr_.clear ();
210 if (span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
211 last_request_mom_ = now_mom ();
217 Maybe always creating a line-spanner for a (de)crescendo (see
218 below) is not a good idea:
222 the \p will be centred on the line-spanner, and thus clash
223 with the hairpin. When axis-group code is in place, the \p
224 should move below the hairpin, which is probably better?
226 if (now > last_request_mom_)
229 During a (de)crescendo, pending request will not be cleared,
230 and a line-spanner will always be created, as \< \! are already
233 if (now > last_request_mom_ && !span_start_req_l_)
236 for (int i = 0; i < pending_element_arr_.size (); i++)
238 Score_element* e = pending_element_arr_[i];
239 side_position (e).set_axis (Y_AXIS);
240 side_position (e).add_staff_support ();
245 Direction d = directional_element (e).get ();
248 SCM s = get_property ("dynamicDirection");
250 s = get_property ("verticalDirection");
253 directional_element (e).set (d);
256 SCM s = get_property ("dynamicPadding");
258 e->set_elt_property ("padding", s);
259 s = get_property ("dynamicMinimumSpace");
261 e->set_elt_property ("minimum-space", s);
263 pending_element_arr_.clear ();
269 String loud = text_req_l_->text_str_;
271 text_p_ = new Text_item;
272 text_p_->set_elt_property ("text",
273 ly_str02scm (loud.ch_C ()));
274 text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
275 text_p_->set_elt_property ("script-priority",
277 if (Direction d=text_req_l_->get_direction ())
278 directional_element (text_p_).set (d);
279 pending_element_arr_.push (text_p_);
280 text_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
281 text_p_->add_offset_callback (Side_position_interface::aligned_on_self,
283 announce_element (Score_element_info (text_p_, text_req_l_));
286 if (span_req_l_drul_[STOP])
290 span_req_l_drul_[STOP]->warning
291 (_ ("can't find start of (de)crescendo"));
295 assert (!finished_cresc_p_);
296 cresc_p_->set_bound(RIGHT, get_staff_info ().musical_pcol_l ());
297 finished_cresc_p_ = cresc_p_;
299 span_start_req_l_ = 0;
303 if (span_req_l_drul_[START])
305 if (span_start_req_l_)
307 span_req_l_drul_[START]->warning
308 (span_start_req_l_->span_dir_ == 1
310 _ ("already have a crescendo")
311 : _ ("already have a decrescendo"));
315 span_start_req_l_ = span_req_l_drul_[START];
316 cresc_p_ = new Crescendo;
317 cresc_p_->set_elt_property
319 gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
320 ? BIGGER : SMALLER));
322 SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
325 cresc_p_->set_elt_property ("start-text", s);
326 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
327 + "Text", SCM_UNDEFINED);
330 s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
331 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
333 cresc_p_->set_elt_property ("spanner", s);
334 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
335 + "Spanner", SCM_UNDEFINED);
338 cresc_p_->set_bound(LEFT, get_staff_info ().musical_pcol_l ());
342 We know how wide the text is, if we can be sure that the
343 text already has relevant pointers into the paperdef,
344 and it has its font-size property set.
346 Since font-size may be set by a context higher up, we
347 can not be sure of the size.
350 We shouldn't try to do this stuff here, the Item should
351 do it when the score is finished. We could maybe
352 set a callback to have the Item do the alignment if
353 it is not a special symbol, like Crescendo.
359 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
361 if (finished_cresc_p_)
362 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
365 pending_element_arr_.push (cresc_p_);
366 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
367 cresc_p_->add_offset_callback
368 (Side_position_interface::aligned_on_self, Y_AXIS);
369 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
375 Dynamic_engraver::do_pre_move_processing ()
381 Dynamic_engraver::do_removal_processing ()
385 typeset_element (cresc_p_ );
386 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
392 side_position (line_spanner_).add_staff_support ();
393 typeset_element (line_spanner_);
399 Dynamic_engraver::typeset_all ()
401 if (finished_cresc_p_)
403 typeset_element (finished_cresc_p_);
404 finished_cresc_p_ =0;
409 typeset_element (text_p_);
414 TODO: This should be optionised:
415 * break when group of dynamic requests ends
417 * continue through piece */
418 if (line_spanner_ && last_request_mom_ < now_mom ())
420 side_position (line_spanner_).add_staff_support ();
421 typeset_element (line_spanner_);
427 Dynamic_engraver::acknowledge_element (Score_element_info i)
429 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
433 side_position (line_spanner_).add_support (n);
434 line_spanner_->add_column (n);