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