]> git.donarmstrong.com Git - lilypond.git/blob - lily/dynamic-engraver.cc
release: 1.3.32
[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 "lookup.hh"
13 #include "paper-def.hh"
14 #include "paper-column.hh"
15 #include "staff-symbol.hh"
16 #include "note-column.hh"
17 #include "text-item.hh"
18 #include "side-position-interface.hh"
19 #include "engraver.hh"
20 #include "stem.hh"
21 #include "note-head.hh"
22 #include "group-interface.hh"
23 #include "directional-element-interface.hh"
24 #include "staff-symbol-referencer.hh"
25 #include "translator-group.hh"
26
27 /*
28  Wat mij betreft wel DYN_LINE
29  */
30 #define DYN_LINE
31
32
33 #ifdef DYN_LINE
34 class Dynamic_line_spanner : public Spanner
35 {
36 public:
37   Dynamic_line_spanner ();
38   
39   void add_column (Note_column*);
40   Direction get_default_dir () const;
41 protected:
42   virtual void do_post_processing ();
43 };
44
45 Dynamic_line_spanner::Dynamic_line_spanner ()
46 {
47   set_elt_property ("transparent", SCM_BOOL_T);
48   side_position (this).set_axis (Y_AXIS);
49 }
50
51 void
52 Dynamic_line_spanner::add_column (Note_column* n)
53 {
54   if (!spanned_drul_[LEFT])
55     set_bounds (LEFT, n);
56   set_bounds (RIGHT, n);
57
58   add_dependency (n);
59 }
60
61 Direction
62 Dynamic_line_spanner::get_default_dir () const
63 {
64   return DOWN;
65 }
66
67 void
68 Dynamic_line_spanner::do_post_processing ()
69 {
70   Spanner::do_post_processing ();
71   Direction dir = directional_element (this).get ();
72   if (!dir)
73     dir = get_default_dir ();
74
75   /*
76     Hier is ook vast iets voor?
77    */
78   Staff_symbol_referencer_interface si (this);
79   Real above_staff = si.line_count () + 2;
80
81 #if 0
82   // Aargh, nu snap ik waarom ik het niet snap
83   // zie Staff_symbol_referencer_interface::set_position 
84
85   if (si.position_f () * dir < above_staff)
86     si.set_position (above_staff * (int)dir);
87
88   SCM s = get_elt_property ("padding");
89   if (gh_number_p (s))
90     {
91       si.set_position (si.position_f () + gh_scm2double (s) * (int) dir);
92     }
93 #else
94   Real dy = 0;
95   Real pos = si.position_f () * dir;
96   if (pos * dir < above_staff)
97     dy = above_staff;
98
99   SCM s = get_elt_property ("padding");
100   if (gh_number_p (s))
101     dy += gh_scm2double (s);
102   
103   Real half_space = si.staff_space () / 2;
104   translate_axis (dy*half_space*dir, Y_AXIS);
105 #endif
106   
107 }
108
109 #endif
110 /*
111   TODO:
112     Baseline alignment / character metrics of dynamic symbols.
113  */
114
115 /**
116    print text & hairpin dynamics.
117  */
118 class Dynamic_engraver : public Engraver
119 {
120   Text_item * text_p_;
121   Crescendo * finished_cresc_p_;
122   Crescendo * cresc_p_;
123
124   Text_script_req* text_req_l_;
125   Span_req * span_start_req_l_;
126   Drul_array<Span_req*> span_req_l_drul_;
127
128 #ifdef DYN_LINE
129   Dynamic_line_spanner* line_spanner_;
130 #else
131   Spanner* line_spanner_;
132 #endif
133   Moment last_request_mom_;
134   
135   void  typeset_all ();
136
137 public:
138   VIRTUAL_COPY_CONS(Translator);
139   Dynamic_engraver ();
140   
141 protected:
142   void announce_element (Score_element_info);
143   
144   virtual void do_removal_processing ();
145   virtual void acknowledge_element (Score_element_info);
146   virtual bool do_try_music (Music *req_l);
147   virtual void do_process_requests ();
148   virtual void do_pre_move_processing ();
149   virtual void do_post_move_processing ();
150 };
151
152 ADD_THIS_TRANSLATOR (Dynamic_engraver);
153
154 void
155 Dynamic_engraver::announce_element (Score_element_info i)
156 {
157   group (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
158   
159   Engraver::announce_element (i);
160 }
161
162
163 Dynamic_engraver::Dynamic_engraver ()
164 {
165   text_p_ = 0;
166   finished_cresc_p_ = 0;
167   line_spanner_ = 0;
168   span_start_req_l_ = 0;
169   cresc_p_ =0;
170
171   text_req_l_ = 0;
172   span_req_l_drul_[START] = 0;
173   span_req_l_drul_[STOP] = 0;
174 }
175
176 void
177 Dynamic_engraver::do_post_move_processing ()
178 {
179   text_req_l_ = 0;
180   span_req_l_drul_[START] = 0;
181   span_req_l_drul_[STOP] = 0;
182 }
183
184 bool
185 Dynamic_engraver::do_try_music (Music * m)
186 {
187   if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
188     {
189       if (d->style_str_ == "dynamic")
190         {
191           text_req_l_ = d;
192           return true;
193         }
194     }
195   else if (Span_req* s =  dynamic_cast <Span_req*> (m))
196     {
197       if ((s->span_type_str_ == "crescendo"
198            || s->span_type_str_ == "decrescendo"))
199         {
200           span_req_l_drul_[s->span_dir_] = s;
201           return true;
202         }
203     }
204   return false;
205 }
206
207 void
208 Dynamic_engraver::do_process_requests ()
209 {
210   if ((span_req_l_drul_[START] || text_req_l_) && !line_spanner_)
211     {
212 #ifdef DYN_LINE
213       line_spanner_ = new Dynamic_line_spanner;
214 #else
215       line_spanner_ = new Spanner;
216       line_spanner_->set_elt_property ("transparent", SCM_BOOL_T);
217       side_position (line_spanner_).set_axis (Y_AXIS);
218 #endif
219       announce_element (Score_element_info
220                         (line_spanner_,
221                          text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
222
223     }
224           
225   if (span_req_l_drul_[START] || text_req_l_)
226     last_request_mom_ = now_mom ();
227   
228 #ifndef DYN_LINE
229   if (line_spanner_)
230     {
231       /*
232         Generic property will handle this for a Dynamic_line_spanner
233        */
234       Direction dir = DOWN;
235       SCM s = get_property ("dynamicDirection");
236       if (!isdir_b (s))
237         {
238           s = get_property ("verticalDirection");
239         }
240       
241       if (isdir_b (s) && to_dir (s))
242         dir = to_dir (s);
243       
244       line_spanner_->set_elt_property ("direction", gh_int2scm ((int)dir));
245
246       s = get_property ("dynamicPadding");
247       Real padding;
248       if (gh_number_p (s))
249         padding = gh_scm2double (s);
250       else
251         padding = 2;
252       line_spanner_->set_elt_property ("padding", gh_double2scm (padding));
253     }
254 #endif 
255   
256   if (text_req_l_)
257     {
258       String loud = text_req_l_->text_str_;
259
260       text_p_ = new Text_item;
261       text_p_->set_elt_property ("text",
262                                           ly_str02scm (loud.ch_C ()));
263       text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
264       text_p_->set_elt_property ("script-priority",
265                                           gh_int2scm (100));
266           
267       assert (line_spanner_);
268       text_p_->set_parent (line_spanner_, Y_AXIS);
269       announce_element (Score_element_info (text_p_, text_req_l_));
270     }
271
272   if (span_req_l_drul_[STOP])
273     {
274       if (!cresc_p_)
275         {
276           span_req_l_drul_[STOP]->warning
277             (_ ("can't find start of (de)crescendo"));
278         }
279       else
280         {
281           assert (!finished_cresc_p_);
282           cresc_p_->set_bounds(RIGHT, get_staff_info ().musical_pcol_l ());
283           finished_cresc_p_ = cresc_p_;
284           cresc_p_ = 0;
285           span_start_req_l_ = 0;
286         }
287     }
288
289   if (span_req_l_drul_[START])
290     {
291       if (span_start_req_l_)
292         {
293           span_req_l_drul_[START]->warning
294             (span_start_req_l_->span_dir_ == 1
295              ?
296              _ ("already have a crescendo")
297              : _ ("already have a decrescendo"));
298         }
299       else
300         {
301           span_start_req_l_ = span_req_l_drul_[START];
302           cresc_p_  = new Crescendo;
303           cresc_p_->set_elt_property
304             ("grow-direction",
305              gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
306                          ? BIGGER : SMALLER));
307               
308           SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
309           if (gh_string_p (s))
310             {
311               cresc_p_->set_elt_property ("start-text", s);
312               daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
313                                             + "Text", SCM_UNDEFINED);
314             }
315
316           s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
317           if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
318             {
319               cresc_p_->set_elt_property ("spanner", s);
320               daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
321                                             + "Spanner", SCM_UNDEFINED);
322             }
323
324           cresc_p_->set_bounds(LEFT, get_staff_info ().musical_pcol_l ());
325           cresc_p_->set_bounds(RIGHT, get_staff_info ().musical_pcol_l ());
326
327           // arrragh, brr, urg: we know how wide text is, no?
328           if (text_p_)
329             {
330               index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
331                               LEFT, SCM_BOOL_T);
332               if (finished_cresc_p_)
333                 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
334                                 RIGHT, SCM_BOOL_T);
335             }
336
337           assert (line_spanner_);
338           cresc_p_->set_parent (line_spanner_, Y_AXIS);
339           announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
340         }
341     }
342 }
343
344 void
345 Dynamic_engraver::do_pre_move_processing ()
346 {
347   typeset_all ();
348 }
349
350 void
351 Dynamic_engraver::do_removal_processing ()
352 {
353   if (cresc_p_)
354     {
355       typeset_element (cresc_p_ );
356       span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
357       cresc_p_ =0;
358     }
359   typeset_all ();
360   if (line_spanner_)
361     {
362 #ifndef DYN_LINE
363       Direction dir = directional_element (line_spanner_).get ();
364       Real staff_space = Staff_symbol_referencer_interface (line_spanner_).staff_space ();
365       SCM s = line_spanner_->get_elt_property ("padding");
366       line_spanner_->translate_axis (gh_scm2double (s) * staff_space * (int)dir, Y_AXIS);
367 #endif
368       typeset_element (line_spanner_);
369       line_spanner_ = 0;
370     }
371 }
372
373
374 void
375 Dynamic_engraver::typeset_all ()
376 {  
377   if (finished_cresc_p_)
378     {
379       finished_cresc_p_->set_bounds (RIGHT, get_staff_info ().musical_pcol_l ());
380       typeset_element (finished_cresc_p_);
381       finished_cresc_p_ =0;
382     }
383   
384   if (text_p_)
385     {
386       typeset_element (text_p_);
387       text_p_ = 0;
388     }
389
390   /*
391     TODO: This should be optionised:
392       * break when group of dynamic requests ends
393       * break now 
394       * continue through piece
395    */
396   if (line_spanner_ && last_request_mom_ < now_mom ())
397     {
398 #ifndef DYN_LINE
399       Direction dir = directional_element (line_spanner_).get ();
400       Real staff_space = Staff_symbol_referencer_interface (line_spanner_).staff_space ();
401       SCM s = line_spanner_->get_elt_property ("padding");
402       line_spanner_->translate_axis (gh_scm2double (s) * staff_space * (int)dir, Y_AXIS);
403 #endif
404       typeset_element (line_spanner_);
405       line_spanner_ = 0;
406     }
407 }
408
409 void
410 Dynamic_engraver::acknowledge_element (Score_element_info i)
411 {
412   if (line_spanner_)
413     {
414       if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
415         {
416           side_position (line_spanner_).add_support (n);
417 #ifdef DYN_LINE
418           line_spanner_->add_column (n);
419 #else
420           if (!line_spanner_->spanned_drul_[LEFT])
421             line_spanner_->set_bounds (LEFT, n);
422           line_spanner_->set_bounds (RIGHT, n);
423           
424           line_spanner_->add_dependency (n);
425 #endif
426         }
427     }
428 }