]> git.donarmstrong.com Git - lilypond.git/blob - lily/dynamic-engraver.cc
9093c2aa66d9ca5f3274e5bb37323e3d8bb95409
[lilypond.git] / lily / dynamic-engraver.cc
1 /*
2   dynamic-engraver.cc -- implement Dynamic_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include "debug.hh"
9 #include "dimensions.hh"
10 #include "crescendo.hh"
11 #include "musical-request.hh"
12 #include "paper-column.hh"
13 #include "note-column.hh"
14 #include "item.hh"
15 #include "side-position-interface.hh"
16 #include "engraver.hh"
17 #include "group-interface.hh"
18 #include "directional-element-interface.hh"
19 #include "translator-group.hh"
20 #include "axis-group-interface.hh"
21
22
23 /*
24   TODO:
25
26   * direction of text-dynamic-request if not equal to direction of
27   line-spanner
28 */
29
30 /**
31    print text & hairpin dynamics.
32  */
33 class Dynamic_engraver : public Engraver
34 {
35   Item * text_p_;
36   Spanner * finished_cresc_p_;
37   Spanner * cresc_p_;
38
39   Text_script_req* text_req_l_;
40   
41   Span_req * current_cresc_req_;
42   Drul_array<Span_req*> accepted_spanreqs_drul_;
43
44   Spanner* line_spanner_;
45   Spanner* finished_line_spanner_;
46
47   Link_array<Note_column> pending_column_arr_;
48   Link_array<Score_element> pending_element_arr_;
49   
50   void typeset_all ();
51
52 public:
53   VIRTUAL_COPY_CONS(Translator);
54   Dynamic_engraver ();
55   
56 protected:
57   virtual void do_removal_processing ();
58   virtual void acknowledge_element (Score_element_info);
59   virtual bool do_try_music (Music *req_l);
60   virtual void do_process_music ();
61   virtual void do_pre_move_processing ();
62   virtual void do_post_move_processing ();
63 };
64
65 ADD_THIS_TRANSLATOR (Dynamic_engraver);
66
67
68 Dynamic_engraver::Dynamic_engraver ()
69 {
70   text_p_ = 0;
71   finished_cresc_p_ = 0;
72   line_spanner_ = 0;
73   finished_line_spanner_ = 0;
74   current_cresc_req_ = 0;
75   cresc_p_ =0;
76
77   text_req_l_ = 0;
78   accepted_spanreqs_drul_[START] = 0;
79   accepted_spanreqs_drul_[STOP] = 0;
80 }
81
82 void
83 Dynamic_engraver::do_post_move_processing ()
84 {
85   text_req_l_ = 0;
86   accepted_spanreqs_drul_[START] = 0;
87   accepted_spanreqs_drul_[STOP] = 0;
88 }
89
90 bool
91 Dynamic_engraver::do_try_music (Music * m)
92 {
93   if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
94     {
95       if (d->style_str_ == "dynamic")
96         {
97           text_req_l_ = d;
98           return true;
99         }
100     }
101   else if (Span_req* s =  dynamic_cast <Span_req*> (m))
102     {
103       if ((s->span_type_str_ == "crescendo"
104            || s->span_type_str_ == "decrescendo"))
105         {
106           accepted_spanreqs_drul_[s->span_dir_] = s;
107           return true;
108         }
109     }
110   return false;
111 }
112
113 void
114 Dynamic_engraver::do_process_music ()
115 {
116   if (accepted_spanreqs_drul_[START] || accepted_spanreqs_drul_[STOP] || text_req_l_)
117     
118     {
119       if (!line_spanner_)
120         {
121           line_spanner_ = new Spanner (get_property ("basicDynamicLineSpannerProperties"));
122
123           Side_position::set_axis (line_spanner_, Y_AXIS);
124           Axis_group_interface::set_interface (line_spanner_);
125           Axis_group_interface::set_axes (line_spanner_, Y_AXIS, Y_AXIS);
126           announce_element (line_spanner_,
127                              text_req_l_ ? text_req_l_ : accepted_spanreqs_drul_[START]);
128
129         }
130     }
131
132   /*
133     TODO: should finish and create new spanner if vertical dyn-direction is changed.
134    */
135   else if (!accepted_spanreqs_drul_[START] && !text_req_l_)
136     {
137       finished_line_spanner_ = line_spanner_;
138       line_spanner_ = 0;
139     }
140
141         /*
142         todo: resurrect  dynamic{direction, padding,minimumspace}
143         */
144         /*
145         During a (de)crescendo, pending request will not be cleared,
146         and a line-spanner will always be created, as \< \! are already
147         two requests.
148
149         Maybe always creating a line-spanner for a (de)crescendo (see
150         below) is not a good idea:
151
152             a\< b\p \!c
153
154         the \p will be centred on the line-spanner, and thus clash
155         with the hairpin.  When axis-group code is in place, the \p
156         should move below the hairpin, which is probably better?
157
158         Urg, but line-spanner must always have at least same duration
159         as (de)crecsendo, b.o. line-breaking.
160         */
161
162
163   if (text_req_l_)
164     {
165       String loud = text_req_l_->text_str_;
166
167       text_p_ = new Item (get_property ("basicDynamicTextProperties"));
168       text_p_->set_elt_property ("text", ly_str02scm (loud.ch_C ()));
169       if (Direction d=text_req_l_->get_direction ())
170         Directional_element_interface::set (line_spanner_, d);
171
172       Axis_group_interface::add_element (line_spanner_, text_p_);
173
174       text_p_->add_offset_callback (Side_position::aligned_on_self,
175                                     Y_AXIS);
176       announce_element (text_p_, text_req_l_);
177     }
178
179   if (accepted_spanreqs_drul_[STOP])
180     {
181       if (!cresc_p_)
182         {
183           accepted_spanreqs_drul_[STOP]->origin ()->warning
184             (_ ("can't find start of (de)crescendo"));
185         }
186       else
187         {
188           assert (!finished_cresc_p_);
189           cresc_p_->set_bound (RIGHT, unsmob_element (get_property ("currentMusicalColumn")));
190           finished_cresc_p_ = cresc_p_;
191           cresc_p_ = 0;
192           current_cresc_req_ = 0;
193         }
194     }
195
196   if (accepted_spanreqs_drul_[START])
197     {
198       if (current_cresc_req_)
199         {
200           accepted_spanreqs_drul_[START]->origin ()->warning
201             (current_cresc_req_->span_dir_ == 1
202              ? _ ("already have a crescendo")
203              : _ ("already have a decrescendo"));
204         }
205       else
206         {
207           current_cresc_req_ = accepted_spanreqs_drul_[START];
208           cresc_p_  = new Spanner (get_property ("basicCrescendoProperties"));
209           Crescendo::set_interface (cresc_p_);
210           cresc_p_->set_elt_property
211             ("grow-direction",
212              gh_int2scm ((accepted_spanreqs_drul_[START]->span_type_str_ == "crescendo")
213                          ? BIGGER : SMALLER));
214               
215           SCM s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Text").ch_C());
216           if (gh_string_p (s))
217             {
218               cresc_p_->set_elt_property ("start-text", s);
219               daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
220                                             + "Text", SCM_UNDEFINED);
221             }
222
223           s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Spanner").ch_C());
224
225
226           /*
227             TODO: Use symbols.
228            */
229           if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
230             {
231               cresc_p_->set_elt_property ("spanner", s);
232               daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
233                                             + "Spanner", SCM_UNDEFINED);
234             }
235
236           cresc_p_->set_bound (LEFT, unsmob_element (get_property ("currentMusicalColumn")));
237
238
239           /* 
240               We know how wide the text is, if we can be sure that the
241               text already has relevant pointers into the paperdef,
242               and it has its font-size property set.
243
244               Since font-size may be set by a context higher up, we
245               can not be sure of the size.
246
247
248               We shouldn't try to do this stuff here, the Item should
249               do it when the score is finished.  We could maybe
250               set a callback to have the Item do the alignment if
251               it is not a special symbol, like Crescendo.
252           */
253
254           
255           if (text_p_)
256             {
257               index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
258                               LEFT, text_p_->self_scm ());
259               if (finished_cresc_p_)
260                 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
261                                 RIGHT, text_p_->self_scm ());
262             }
263
264           Axis_group_interface::add_element (line_spanner_, cresc_p_);
265           cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
266           cresc_p_->add_offset_callback
267             (Side_position::aligned_on_self, Y_AXIS);
268           announce_element (cresc_p_, accepted_spanreqs_drul_[START]);
269         }
270     }
271 }
272
273 void
274 Dynamic_engraver::do_pre_move_processing ()
275 {
276   typeset_all ();
277 }
278
279 void
280 Dynamic_engraver::do_removal_processing ()
281 {
282   typeset_all ();
283
284 #if 0  
285   if (cresc_p_)
286     {
287       typeset_element (cresc_p_ );
288       finished_cresc_p_ = cresc_p_;
289
290       current_cresc_req_->origin ()->warning (_ ("unterminated (de)crescendo"));
291     }
292   if (line_spanner_)
293     {
294       finished_line_spanner_ = line_spanner_;
295     }
296   typeset_all ();
297 #else
298   if (cresc_p_)
299     {
300       current_cresc_req_->origin ()->warning (_ ("unterminated (de)crescendo"));
301       cresc_p_->suicide ();
302     }
303   if (line_spanner_)
304     {
305       line_spanner_->suicide ();
306     }
307 #endif
308 }
309
310 void
311 Dynamic_engraver::typeset_all ()
312 {  
313   if (finished_cresc_p_)
314     {
315       typeset_element (finished_cresc_p_);
316       finished_cresc_p_ =0;
317     }
318   
319   if (text_p_)
320     {
321       typeset_element (text_p_);
322       text_p_ = 0;
323     }
324   if (finished_line_spanner_)
325     {
326       Side_position::add_staff_support (finished_line_spanner_);
327
328       if (!finished_line_spanner_->get_bound (LEFT))
329         {
330           Score_element * cmc
331             = unsmob_element (get_property ("currentMusicalColumn"));
332           finished_line_spanner_->set_bound (LEFT, cmc);
333         }
334       if (!finished_line_spanner_->get_bound (RIGHT))
335         finished_line_spanner_->set_bound (RIGHT,
336                                            finished_line_spanner_->get_bound (LEFT));
337       
338       
339       typeset_element (finished_line_spanner_);
340       finished_line_spanner_ = 0;
341     }
342 }
343
344 void
345 Dynamic_engraver::acknowledge_element (Score_element_info i)
346 {
347   if (Note_column::has_interface (i.elem_l_))
348     {
349       if (line_spanner_)
350         {
351           Side_position::add_support (line_spanner_,i.elem_l_);
352           add_bound_item (line_spanner_,dynamic_cast<Item*>(i.elem_l_));
353         }
354     }
355 }