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 * fix vertical placement of orphaned items
36 class Dynamic_line_spanner : public Spanner
39 Dynamic_line_spanner ();
40 VIRTUAL_COPY_CONS(Score_element);
41 void add_column (Item*);
42 Direction get_default_dir () const;
45 Dynamic_line_spanner::Dynamic_line_spanner ()
47 set_elt_property ("transparent", SCM_BOOL_T);
48 side_position (this).set_axis (Y_AXIS);
52 Dynamic_line_spanner::add_column (Item* n)
54 if (!get_bound (LEFT))
63 Dynamic_line_spanner::get_default_dir () const
69 print text & hairpin dynamics.
71 class Dynamic_engraver : public Engraver
74 Crescendo * finished_cresc_p_;
77 Text_script_req* text_req_l_;
78 Span_req * span_start_req_l_;
79 Drul_array<Span_req*> span_req_l_drul_;
81 Dynamic_line_spanner* line_spanner_;
82 Moment last_request_mom_;
84 Note_column* pending_column_;
85 Link_array<Score_element> pending_element_arr_;
90 VIRTUAL_COPY_CONS(Translator);
94 void announce_element (Score_element_info);
96 virtual void do_removal_processing ();
97 virtual void acknowledge_element (Score_element_info);
98 virtual bool do_try_music (Music *req_l);
99 virtual void do_process_music ();
100 virtual void do_pre_move_processing ();
101 virtual void do_post_move_processing ();
102 virtual void typeset_element (Score_element*);
105 ADD_THIS_TRANSLATOR (Dynamic_engraver);
108 Dynamic_engraver::announce_element (Score_element_info i)
110 group (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
112 Engraver::announce_element (i);
116 Dynamic_engraver::Dynamic_engraver ()
119 finished_cresc_p_ = 0;
121 span_start_req_l_ = 0;
126 span_req_l_drul_[START] = 0;
127 span_req_l_drul_[STOP] = 0;
131 Dynamic_engraver::do_post_move_processing ()
134 span_req_l_drul_[START] = 0;
135 span_req_l_drul_[STOP] = 0;
137 /* ugr; we must attach the Dynamic_line_spanner to something
138 to be sure that the linebreaker will not be confused
140 // if (line_spanner_)
141 // line_spanner_->add_column (LEFT, get_staff_info ().command_pcol_l ());
145 Dynamic_engraver::do_try_music (Music * m)
147 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
149 if (d->style_str_ == "dynamic")
155 else if (Span_req* s = dynamic_cast <Span_req*> (m))
157 if ((s->span_type_str_ == "crescendo"
158 || s->span_type_str_ == "decrescendo"))
160 span_req_l_drul_[s->span_dir_] = s;
168 Dynamic_engraver::do_process_music ()
170 if ((span_req_l_drul_[START] || text_req_l_)
172 && pending_element_arr_.size ())
174 line_spanner_ = new Dynamic_line_spanner;
175 assert (pending_column_);
176 line_spanner_->add_column (pending_column_);
177 side_position (line_spanner_).set_axis (Y_AXIS);
178 announce_element (Score_element_info
180 text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
184 if (line_spanner_ && pending_element_arr_.size ())
186 for (int i = 0; i < pending_element_arr_.size (); i++)
187 pending_element_arr_[i]->set_parent (line_spanner_, Y_AXIS);
188 pending_element_arr_.clear ();
191 if (span_req_l_drul_[START] || text_req_l_)
192 last_request_mom_ = now_mom ();
194 pending_element_arr_.clear ();
199 String loud = text_req_l_->text_str_;
201 text_p_ = new Text_item;
202 text_p_->set_elt_property ("text",
203 ly_str02scm (loud.ch_C ()));
204 text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
205 text_p_->set_elt_property ("script-priority",
207 pending_element_arr_.push (text_p_);
208 text_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
209 text_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
210 (Side_position_interface::aligned_on_self);
211 //text_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
212 // (Side_position_interface::aligned_side);
213 announce_element (Score_element_info (text_p_, text_req_l_));
216 if (span_req_l_drul_[STOP])
220 span_req_l_drul_[STOP]->warning
221 (_ ("can't find start of (de)crescendo"));
225 assert (!finished_cresc_p_);
226 cresc_p_->set_bound(RIGHT, get_staff_info ().musical_pcol_l ());
227 finished_cresc_p_ = cresc_p_;
229 span_start_req_l_ = 0;
233 if (span_req_l_drul_[START])
235 if (span_start_req_l_)
237 span_req_l_drul_[START]->warning
238 (span_start_req_l_->span_dir_ == 1
240 _ ("already have a crescendo")
241 : _ ("already have a decrescendo"));
245 span_start_req_l_ = span_req_l_drul_[START];
246 cresc_p_ = new Crescendo;
247 cresc_p_->set_elt_property
249 gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
250 ? BIGGER : SMALLER));
252 SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
255 cresc_p_->set_elt_property ("start-text", s);
256 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
257 + "Text", SCM_UNDEFINED);
260 s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
261 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
263 cresc_p_->set_elt_property ("spanner", s);
264 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
265 + "Spanner", SCM_UNDEFINED);
268 cresc_p_->set_bound(LEFT, get_staff_info ().musical_pcol_l ());
272 We know how wide the text is, if we can be sure that the
273 text already has relevant pointers into the paperdef,
274 and it has its font-size property set.
276 Since font-size may be set by a context higher up, we
277 can not be sure of the size.
280 We shouldn't try to do this stuff here, the Item should
281 do it when the score is finished. We could maybe
282 set a callback to have the Item do the alignment if
283 it is not a special symbol, like Crescendo.
289 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
291 if (finished_cresc_p_)
292 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
295 pending_element_arr_.push (cresc_p_);
296 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
297 cresc_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
298 (Side_position_interface::aligned_on_self);
299 //cresc_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
300 // (Side_position_interface::aligned_side);
301 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
307 Dynamic_engraver::do_pre_move_processing ()
314 Dynamic_engraver::do_removal_processing ()
318 typeset_element (cresc_p_ );
319 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
325 typeset_element (line_spanner_);
331 Dynamic_engraver::typeset_element (Score_element* e)
333 side_position (e).add_staff_support ();
334 Engraver::typeset_element (e);
338 Dynamic_engraver::typeset_all ()
340 if (finished_cresc_p_)
342 typeset_element (finished_cresc_p_);
343 finished_cresc_p_ =0;
348 typeset_element (text_p_);
353 TODO: This should be optionised:
354 * break when group of dynamic requests ends
356 * continue through piece */
357 if (line_spanner_ && last_request_mom_ < now_mom ())
359 typeset_element (line_spanner_);
365 Dynamic_engraver::acknowledge_element (Score_element_info i)
367 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
371 side_position (line_spanner_).add_support (n);
372 line_spanner_->add_column (n);