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
36 * FIXME: this has gotten a bit too hairy.
39 class Dynamic_line_spanner : public Spanner
42 Dynamic_line_spanner (SCM);
43 VIRTUAL_COPY_CONS(Score_element);
44 void add_column (Note_column*);
45 void add_element (Score_element*);
48 Dynamic_line_spanner::Dynamic_line_spanner (SCM s)
51 set_elt_property ("transparent", SCM_BOOL_T);
52 Side_position_interface (this).set_axis (Y_AXIS);
53 Axis_group_interface (this).set_interface ();
54 Axis_group_interface (this).set_axes (X_AXIS, Y_AXIS);
58 Dynamic_line_spanner::add_column (Note_column* n)
60 if (!get_bound (LEFT))
70 Dynamic_line_spanner::add_element (Score_element* e)
72 e->set_parent (this, Y_AXIS);
73 Axis_group_interface (this).add_element (e);
77 print text & hairpin dynamics.
79 class Dynamic_engraver : public Engraver
82 Crescendo * finished_cresc_p_;
85 Text_script_req* text_req_l_;
86 Span_req * span_start_req_l_;
87 Drul_array<Span_req*> span_req_l_drul_;
89 Dynamic_line_spanner* line_spanner_;
90 Dynamic_line_spanner* finished_line_spanner_;
91 Moment last_request_mom_;
93 Array<Note_column*> pending_column_arr_;
94 Link_array<Score_element> pending_element_arr_;
99 VIRTUAL_COPY_CONS(Translator);
103 void announce_element (Score_element_info);
105 virtual void do_removal_processing ();
106 virtual void acknowledge_element (Score_element_info);
107 virtual bool do_try_music (Music *req_l);
108 virtual void do_process_music ();
109 virtual void do_pre_move_processing ();
110 virtual void do_post_move_processing ();
113 ADD_THIS_TRANSLATOR (Dynamic_engraver);
116 Dynamic_engraver::announce_element (Score_element_info i)
118 Group_interface (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
120 Engraver::announce_element (i);
124 Dynamic_engraver::Dynamic_engraver ()
127 finished_cresc_p_ = 0;
129 finished_line_spanner_ = 0;
130 span_start_req_l_ = 0;
134 span_req_l_drul_[START] = 0;
135 span_req_l_drul_[STOP] = 0;
139 Dynamic_engraver::do_post_move_processing ()
142 span_req_l_drul_[START] = 0;
143 span_req_l_drul_[STOP] = 0;
147 Dynamic_engraver::do_try_music (Music * m)
149 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
151 if (d->style_str_ == "dynamic")
157 else if (Span_req* s = dynamic_cast <Span_req*> (m))
159 if ((s->span_type_str_ == "crescendo"
160 || s->span_type_str_ == "decrescendo"))
162 span_req_l_drul_[s->span_dir_] = s;
170 Dynamic_engraver::do_process_music ()
172 if ((span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
174 && pending_element_arr_.size ())
176 line_spanner_ = new Dynamic_line_spanner (get_property ("basicDynamicLineSpannerProperties"));
177 for (int i = 0; i < pending_column_arr_.size (); i++)
178 line_spanner_->add_column (pending_column_arr_[i]);
179 pending_column_arr_.clear ();
180 announce_element (Score_element_info
182 text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
186 if (line_spanner_ && pending_element_arr_.size ())
188 for (int i = 0; i < pending_element_arr_.size (); i++)
189 line_spanner_->add_element (pending_element_arr_[i]);
190 pending_element_arr_.clear ();
194 TODO: This should be optionised:
195 * break when group of dynamic requests ends
196 * break now (only if no cresc. in progress)
197 * continue through piece */
198 if (span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
200 last_request_mom_ = now_mom ();
205 During a (de)crescendo, pending request will not be cleared,
206 and a line-spanner will always be created, as \< \! are already
209 Maybe always creating a line-spanner for a (de)crescendo (see
210 below) is not a good idea:
214 the \p will be centred on the line-spanner, and thus clash
215 with the hairpin. When axis-group code is in place, the \p
216 should move below the hairpin, which is probably better?
218 Urg, but line-spanner must always have at least same duration
219 as (de)crecsendo, b.o. line-breaking.
221 if (now_mom () > last_request_mom_ && !span_start_req_l_)
223 for (int i = 0; i < pending_element_arr_.size (); i++)
225 Score_element* e = pending_element_arr_[i];
226 Side_position_interface (e).set_axis (Y_AXIS);
227 Side_position_interface (e).add_staff_support ();
232 Direction d = directional_element (e).get ();
235 SCM s = get_property ("dynamicDirection");
237 s = get_property ("verticalDirection");
240 directional_element (e).set (d);
243 SCM s = get_property ("dynamicPadding");
245 e->set_elt_property ("padding", s);
246 s = get_property ("dynamicMinimumSpace");
248 e->set_elt_property ("minimum-space", s);
250 pending_element_arr_.clear ();
253 for (int i = 0; i < pending_column_arr_.size (); i++)
254 line_spanner_->add_column (pending_column_arr_[i]);
255 pending_column_arr_.clear ();
256 finished_line_spanner_ = line_spanner_;
264 String loud = text_req_l_->text_str_;
266 text_p_ = new Text_item (get_property ("basicDynamicTextProperties"));
267 text_p_->set_elt_property ("text", ly_str02scm (loud.ch_C ()));
268 if (Direction d=text_req_l_->get_direction ())
269 directional_element (text_p_).set (d);
270 pending_element_arr_.push (text_p_);
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 (SCM_EOL);
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");
327 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
329 cresc_p_->set_elt_property ("spanner", s);
330 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
331 + "Spanner", SCM_UNDEFINED);
334 cresc_p_->set_bound (LEFT, get_staff_info ().musical_pcol_l ());
338 We know how wide the text is, if we can be sure that the
339 text already has relevant pointers into the paperdef,
340 and it has its font-size property set.
342 Since font-size may be set by a context higher up, we
343 can not be sure of the size.
346 We shouldn't try to do this stuff here, the Item should
347 do it when the score is finished. We could maybe
348 set a callback to have the Item do the alignment if
349 it is not a special symbol, like Crescendo.
355 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
357 if (finished_cresc_p_)
358 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
361 pending_element_arr_.push (cresc_p_);
362 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
363 cresc_p_->add_offset_callback
364 (Side_position_interface::aligned_on_self, Y_AXIS);
365 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
371 Dynamic_engraver::do_pre_move_processing ()
377 Dynamic_engraver::do_removal_processing ()
381 typeset_element (cresc_p_ );
382 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
388 Side_position_interface (line_spanner_).add_staff_support ();
389 typeset_element (line_spanner_);
395 Dynamic_engraver::typeset_all ()
397 if (finished_cresc_p_)
399 typeset_element (finished_cresc_p_);
400 finished_cresc_p_ =0;
405 typeset_element (text_p_);
408 if (finished_line_spanner_)
410 Side_position_interface (finished_line_spanner_).add_staff_support ();
411 typeset_element (finished_line_spanner_);
412 finished_line_spanner_ = 0;
417 Dynamic_engraver::acknowledge_element (Score_element_info i)
419 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
423 Side_position_interface (line_spanner_).add_support (n);
424 line_spanner_->add_column (n);
428 pending_column_arr_.push (n);