]> git.donarmstrong.com Git - lilypond.git/blob - lily/new-dynamic-engraver.cc
Bump documentation license to v1.3+.
[lilypond.git] / lily / new-dynamic-engraver.cc
1 /* 
2   new-dynamic-engraver.cc -- implement New_dynamic_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2008--2009 Han-Wen Nienhuys <hanwen@lilypond.org>
7 */
8
9 #include "engraver.hh"
10 #include "hairpin.hh"
11 #include "international.hh"
12 #include "item.hh"
13 #include "note-column.hh"
14 #include "pointer-group-interface.hh"
15 #include "self-alignment-interface.hh"
16 #include "spanner.hh"
17 #include "stream-event.hh"
18 #include "text-interface.hh"
19
20 #include "translator.icc"
21
22 class New_dynamic_engraver : public Engraver
23 {
24   TRANSLATOR_DECLARATIONS (New_dynamic_engraver);
25   DECLARE_ACKNOWLEDGER (note_column);
26   DECLARE_TRANSLATOR_LISTENER (absolute_dynamic);
27   DECLARE_TRANSLATOR_LISTENER (span_dynamic);
28
29 protected:
30   virtual void process_music ();
31   virtual void stop_translation_timestep ();
32   virtual void finalize ();
33
34 private:
35   SCM get_property_setting (Stream_event *evt, char const *evprop,
36                             char const *ctxprop);
37   string get_spanner_type (Stream_event *ev);
38
39   Drul_array<Stream_event *> accepted_spanevents_drul_;
40   Spanner *current_spanner_;
41   Spanner *finished_spanner_;
42
43   Item *script_;
44   Stream_event *script_event_;
45   Stream_event *current_span_event_;
46 };
47
48 New_dynamic_engraver::New_dynamic_engraver ()
49 {
50   script_event_ = 0;
51   current_span_event_ = 0;
52   script_ = 0;
53   finished_spanner_ = 0;
54   current_spanner_ = 0;
55   accepted_spanevents_drul_.set (0, 0);
56 }
57
58 IMPLEMENT_TRANSLATOR_LISTENER (New_dynamic_engraver, absolute_dynamic);
59 void
60 New_dynamic_engraver::listen_absolute_dynamic (Stream_event *ev)
61 {
62   ASSIGN_EVENT_ONCE (script_event_, ev);
63 }
64
65 IMPLEMENT_TRANSLATOR_LISTENER (New_dynamic_engraver, span_dynamic);
66 void
67 New_dynamic_engraver::listen_span_dynamic (Stream_event *ev)
68 {
69   Direction d = to_dir (ev->get_property ("span-direction"));
70
71   ASSIGN_EVENT_ONCE (accepted_spanevents_drul_[d], ev);
72 }
73
74 SCM
75 New_dynamic_engraver::get_property_setting (Stream_event *evt,
76                                             char const *evprop,
77                                             char const *ctxprop)
78 {
79   SCM spanner_type = evt->get_property (evprop);
80   if (spanner_type == SCM_EOL)
81     spanner_type = get_property (ctxprop);
82   return spanner_type;
83 }
84
85 void
86 New_dynamic_engraver::process_music ()
87 {
88   if (current_spanner_
89       && (accepted_spanevents_drul_[STOP]
90           || script_event_
91           || accepted_spanevents_drul_[START]))
92     {
93       Stream_event *ender = accepted_spanevents_drul_[STOP];
94       if (!ender)
95         ender = script_event_;
96
97       if (!ender)
98         ender = accepted_spanevents_drul_[START];
99
100       finished_spanner_ = current_spanner_;
101       announce_end_grob (finished_spanner_, ender->self_scm ());
102       current_spanner_ = 0;
103       current_span_event_ = 0;
104     }
105
106   if (accepted_spanevents_drul_[START])
107     {
108       current_span_event_ = accepted_spanevents_drul_[START];
109
110       string start_type = get_spanner_type (current_span_event_);
111       SCM cresc_type = get_property_setting (current_span_event_, "span-type",
112                                              (start_type + "Spanner").c_str ());
113
114       if (cresc_type == ly_symbol2scm ("text"))
115         {
116           current_spanner_
117             = make_spanner ("DynamicTextSpanner",
118                             accepted_spanevents_drul_[START]->self_scm ());
119
120           SCM text = get_property_setting (current_span_event_, "span-text",
121                                            (start_type + "Text").c_str ());
122           if (Text_interface::is_markup (text))
123             current_spanner_->set_property ("text", text);
124         }
125       else
126         {
127           if (cresc_type != ly_symbol2scm ("hairpin"))
128             {
129               string as_string = ly_scm_write_string (cresc_type);
130               current_span_event_
131                 ->origin()->warning (_f ("unknown crescendo style: %s\ndefaulting to hairpin.", as_string.c_str()));
132             }
133           current_spanner_ = make_spanner ("Hairpin",
134                                            current_span_event_->self_scm ());
135         }
136       if (finished_spanner_)
137         {
138           if (Hairpin::has_interface (finished_spanner_))
139             Pointer_group_interface::add_grob (finished_spanner_,
140                                                ly_symbol2scm ("adjacent-spanners"),
141                                                current_spanner_);
142           if (Hairpin::has_interface (current_spanner_))
143             Pointer_group_interface::add_grob (current_spanner_,
144                                                ly_symbol2scm ("adjacent-spanners"),
145                                                finished_spanner_);
146         }
147     }
148
149   if (script_event_)
150     {
151       script_ = make_item ("DynamicText", script_event_->self_scm ());
152       script_->set_property ("text",
153                              script_event_->get_property ("text"));
154
155       if (finished_spanner_)
156         finished_spanner_->set_bound (RIGHT, script_);
157       if (current_spanner_)
158         {
159           current_spanner_->set_bound (LEFT, script_);
160
161           if (!Hairpin::has_interface (current_spanner_))
162             set_nested_property (current_spanner_,
163                                  scm_list_3 (ly_symbol2scm ("bound-details"),
164                                              ly_symbol2scm ("left"),
165                                              ly_symbol2scm ("attach-dir")),
166                                  scm_from_int (RIGHT));
167         }
168     }
169 }
170
171 void
172 New_dynamic_engraver::stop_translation_timestep ()
173 {
174   if (finished_spanner_ && !finished_spanner_->get_bound (RIGHT))
175     finished_spanner_
176       ->set_bound (RIGHT,
177                    unsmob_grob (get_property ("currentMusicalColumn")));
178
179   if (current_spanner_ && !current_spanner_->get_bound (LEFT))
180     current_spanner_
181       ->set_bound (LEFT,
182                    unsmob_grob (get_property ("currentMusicalColumn")));
183   script_ = 0;
184   script_event_ = 0;
185   accepted_spanevents_drul_.set (0, 0);
186   finished_spanner_ = 0;
187 }
188
189 void
190 New_dynamic_engraver::finalize ()
191 {
192   if (current_spanner_
193       && !current_spanner_->is_live ())
194     current_spanner_ = 0;
195   if (current_spanner_)
196     {
197       current_span_event_
198         ->origin ()->warning (_f ("unterminated %s",
199                                   get_spanner_type (current_span_event_)
200                                   .c_str ()));
201       current_spanner_->suicide ();
202       current_spanner_ = 0;
203     }
204 }
205
206 string
207 New_dynamic_engraver::get_spanner_type (Stream_event *ev)
208 {
209   string type;
210   SCM start_sym = ev->get_property ("class");
211
212   if (start_sym == ly_symbol2scm ("decrescendo-event"))
213     type = "decrescendo";
214   else if (start_sym == ly_symbol2scm ("crescendo-event"))
215     type = "crescendo";
216   else
217     programming_error ("unknown dynamic spanner type");
218
219   return type;
220 }
221
222 void
223 New_dynamic_engraver::acknowledge_note_column (Grob_info info)
224 {
225   if (script_ && !script_->get_parent (X_AXIS))
226     {
227       extract_grob_set (info.grob (), "note-heads", heads);
228       if (heads.size ())
229         {
230           Grob *head = heads[0];
231           script_->set_parent (head, X_AXIS);
232           Self_alignment_interface::set_center_parent (script_, X_AXIS);
233         }
234     }
235
236   if (current_spanner_ && !current_spanner_->get_bound (LEFT))
237     current_spanner_->set_bound (LEFT, info.grob ());
238   if (finished_spanner_ && !finished_spanner_->get_bound (RIGHT))
239     finished_spanner_->set_bound (RIGHT, info.grob ());
240 }
241
242 ADD_ACKNOWLEDGER (New_dynamic_engraver, note_column);
243 ADD_TRANSLATOR (New_dynamic_engraver,
244                 /* doc */
245                 "Create hairpins, dynamic texts, and their vertical"
246                 " alignments.  The symbols are collected onto a"
247                 " @code{DynamicLineSpanner} grob which takes care of vertical"
248                 " positioning.",
249
250                 /* create */
251                 "DynamicTextSpanner "
252                 "DynamicText "
253                 "Hairpin ",
254
255                 /* read */
256                 "crescendoSpanner "
257                 "crescendoText "
258                 "currentMusicalColumn "
259                 "decrescendoSpanner "
260                 "decrescendoText ",
261
262                 /* write */
263                 ""
264                 );