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"
27 #include "axis-group-interface.hh"
33 * direction of text-dynamic-request if not equalt to direction
37 class Dynamic_line_spanner : public Spanner
40 Dynamic_line_spanner ();
41 VIRTUAL_COPY_CONS(Score_element);
42 void add_column (Note_column*);
43 void add_element (Score_element*);
46 Dynamic_line_spanner::Dynamic_line_spanner ()
48 set_elt_property ("transparent", SCM_BOOL_T);
49 side_position (this).set_axis (Y_AXIS);
50 axis_group (this).set_interface ();
51 axis_group (this).set_axes (X_AXIS, Y_AXIS);
55 Dynamic_line_spanner::add_column (Note_column* n)
57 if (!get_bound (LEFT))
67 Dynamic_line_spanner::add_element (Score_element* e)
69 e->set_parent (this, Y_AXIS);
70 axis_group (this).add_element (e);
74 print text & hairpin dynamics.
76 class Dynamic_engraver : public Engraver
79 Crescendo * finished_cresc_p_;
82 Text_script_req* text_req_l_;
83 Span_req * span_start_req_l_;
84 Drul_array<Span_req*> span_req_l_drul_;
86 Dynamic_line_spanner* line_spanner_;
87 Dynamic_line_spanner* finished_line_spanner_;
88 Moment last_request_mom_;
90 Note_column* pending_column_;
91 Link_array<Score_element> pending_element_arr_;
96 VIRTUAL_COPY_CONS(Translator);
100 void announce_element (Score_element_info);
102 virtual void do_removal_processing ();
103 virtual void acknowledge_element (Score_element_info);
104 virtual bool do_try_music (Music *req_l);
105 virtual void do_process_music ();
106 virtual void do_pre_move_processing ();
107 virtual void do_post_move_processing ();
110 ADD_THIS_TRANSLATOR (Dynamic_engraver);
113 Dynamic_engraver::announce_element (Score_element_info i)
115 group (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
117 Engraver::announce_element (i);
121 Dynamic_engraver::Dynamic_engraver ()
124 finished_cresc_p_ = 0;
126 finished_line_spanner_ = 0;
127 span_start_req_l_ = 0;
132 span_req_l_drul_[START] = 0;
133 span_req_l_drul_[STOP] = 0;
137 Dynamic_engraver::do_post_move_processing ()
140 span_req_l_drul_[START] = 0;
141 span_req_l_drul_[STOP] = 0;
143 /* ugr; we must attach the Dynamic_line_spanner to something
144 to be sure that the linebreaker will not be confused
146 // if (line_spanner_)
147 // line_spanner_->add_column (LEFT, get_staff_info ().command_pcol_l ());
151 Dynamic_engraver::do_try_music (Music * m)
153 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
155 if (d->style_str_ == "dynamic")
161 else if (Span_req* s = dynamic_cast <Span_req*> (m))
163 if ((s->span_type_str_ == "crescendo"
164 || s->span_type_str_ == "decrescendo"))
166 span_req_l_drul_[s->span_dir_] = s;
174 Dynamic_engraver::do_process_music ()
176 if ((span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
178 && pending_element_arr_.size ())
180 line_spanner_ = new Dynamic_line_spanner;
181 assert (pending_column_);
182 line_spanner_->add_column (pending_column_);
183 announce_element (Score_element_info
185 text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
189 if (line_spanner_ && pending_element_arr_.size ())
191 for (int i = 0; i < pending_element_arr_.size (); i++)
192 line_spanner_->add_element (pending_element_arr_[i]);
193 pending_element_arr_.clear ();
196 if (span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
197 last_request_mom_ = now_mom ();
203 Maybe always creating a line-spanner for a (de)crescendo (see
204 below) is not a good idea:
208 the \p will be centred on the line-spanner, and thus clash
209 with the hairpin. When axis-group code is in place, the \p
210 should move below the hairpin, which is probably better?
212 Urg, but line-spanner must always have at least same duration
213 as (de)crecsendo, b.o. line-breaking.
215 if (now_mom () > last_request_mom_)
218 During a (de)crescendo, pending request will not be cleared,
219 and a line-spanner will always be created, as \< \! are already
222 if (now_mom () > last_request_mom_ && !span_start_req_l_)
225 for (int i = 0; i < pending_element_arr_.size (); i++)
227 Score_element* e = pending_element_arr_[i];
228 side_position (e).set_axis (Y_AXIS);
229 side_position (e).add_staff_support ();
234 Direction d = directional_element (e).get ();
237 SCM s = get_property ("dynamicDirection");
239 s = get_property ("verticalDirection");
242 directional_element (e).set (d);
245 SCM s = get_property ("dynamicPadding");
247 e->set_elt_property ("padding", s);
248 s = get_property ("dynamicMinimumSpace");
250 e->set_elt_property ("minimum-space", s);
252 pending_element_arr_.clear ();
253 finished_line_spanner_ = line_spanner_;
260 String loud = text_req_l_->text_str_;
262 text_p_ = new Text_item;
263 text_p_->set_elt_property ("text",
264 ly_str02scm (loud.ch_C ()));
265 text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
266 text_p_->set_elt_property ("script-priority",
268 if (Direction d=text_req_l_->get_direction ())
269 directional_element (text_p_).set (d);
270 pending_element_arr_.push (text_p_);
271 text_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
272 text_p_->add_offset_callback (Side_position_interface::aligned_on_self,
274 announce_element (Score_element_info (text_p_, text_req_l_));
277 if (span_req_l_drul_[STOP])
281 span_req_l_drul_[STOP]->warning
282 (_ ("can't find start of (de)crescendo"));
286 assert (!finished_cresc_p_);
287 cresc_p_->set_bound(RIGHT, get_staff_info ().musical_pcol_l ());
288 finished_cresc_p_ = cresc_p_;
290 span_start_req_l_ = 0;
294 if (span_req_l_drul_[START])
296 if (span_start_req_l_)
298 span_req_l_drul_[START]->warning
299 (span_start_req_l_->span_dir_ == 1
301 _ ("already have a crescendo")
302 : _ ("already have a decrescendo"));
306 span_start_req_l_ = span_req_l_drul_[START];
307 cresc_p_ = new Crescendo;
308 cresc_p_->set_elt_property
310 gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
311 ? BIGGER : SMALLER));
313 SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
316 cresc_p_->set_elt_property ("start-text", s);
317 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
318 + "Text", SCM_UNDEFINED);
321 s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
322 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
324 cresc_p_->set_elt_property ("spanner", s);
325 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
326 + "Spanner", SCM_UNDEFINED);
329 cresc_p_->set_bound(LEFT, get_staff_info ().musical_pcol_l ());
333 We know how wide the text is, if we can be sure that the
334 text already has relevant pointers into the paperdef,
335 and it has its font-size property set.
337 Since font-size may be set by a context higher up, we
338 can not be sure of the size.
341 We shouldn't try to do this stuff here, the Item should
342 do it when the score is finished. We could maybe
343 set a callback to have the Item do the alignment if
344 it is not a special symbol, like Crescendo.
350 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
352 if (finished_cresc_p_)
353 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
356 pending_element_arr_.push (cresc_p_);
357 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
358 cresc_p_->add_offset_callback
359 (Side_position_interface::aligned_on_self, Y_AXIS);
360 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
366 Dynamic_engraver::do_pre_move_processing ()
372 Dynamic_engraver::do_removal_processing ()
376 typeset_element (cresc_p_ );
377 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
383 side_position (line_spanner_).add_staff_support ();
384 typeset_element (line_spanner_);
390 Dynamic_engraver::typeset_all ()
392 if (finished_cresc_p_)
394 typeset_element (finished_cresc_p_);
395 finished_cresc_p_ =0;
400 typeset_element (text_p_);
405 TODO: This should be optionised:
406 * break when group of dynamic requests ends
408 * continue through piece */
409 // if (line_spanner_ && last_request_mom_ < now_mom ())
410 if (finished_line_spanner_)
412 side_position (finished_line_spanner_).add_staff_support ();
413 typeset_element (finished_line_spanner_);
414 finished_line_spanner_ = 0;
419 Dynamic_engraver::acknowledge_element (Score_element_info i)
421 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
425 side_position (line_spanner_).add_support (n);
426 line_spanner_->add_column (n);