]> git.donarmstrong.com Git - lilypond.git/blob - lily/piano-pedal-align-engraver.cc
Merge branch 'master' into lilypond/translation
[lilypond.git] / lily / piano-pedal-align-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2006--2011 Han-Wen Nienhuys <hanwen@lilypond.org>
5   
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22 #include "engraver.hh"
23
24 #include "spanner.hh"
25 #include "item.hh"
26 #include "side-position-interface.hh"
27 #include "stream-event.hh"
28 #include "warn.hh"
29 #include "axis-group-interface.hh"
30
31
32 /*
33   TODO:
34
35
36   * Detach from pedal specifics,
37   
38   * Also use this engraver for dynamics.
39   
40 */
41
42
43 struct Pedal_align_info
44 {
45   Spanner *line_spanner_;
46   Grob *carrying_item_;
47   Spanner *carrying_spanner_;
48   Spanner *finished_carrying_spanner_;
49
50   Pedal_align_info ()
51   {
52     clear ();
53
54   }
55   void clear ()
56   {
57     line_spanner_ = 0;
58     carrying_spanner_ = 0;
59     carrying_item_ = 0;
60     finished_carrying_spanner_ = 0;
61   }
62   bool is_finished ()
63   {
64     bool do_continue = carrying_item_;
65
66     do_continue |= (carrying_spanner_ && !finished_carrying_spanner_);
67     do_continue |= (carrying_spanner_ && finished_carrying_spanner_ != carrying_spanner_);
68
69     return !do_continue;
70   }
71 };
72
73 class Piano_pedal_align_engraver : public Engraver
74 {
75 public:
76   TRANSLATOR_DECLARATIONS (Piano_pedal_align_engraver);
77
78 protected:
79   virtual void finalize ();
80   
81   DECLARE_ACKNOWLEDGER (piano_pedal_script);
82   DECLARE_ACKNOWLEDGER (piano_pedal_bracket);
83   DECLARE_ACKNOWLEDGER (note_column);
84
85   DECLARE_END_ACKNOWLEDGER (piano_pedal_bracket);
86
87   void stop_translation_timestep ();
88   void start_translation_timestep ();
89   
90 private:
91   enum Pedal_type {
92     SOSTENUTO,
93     SUSTAIN,
94     UNA_CORDA,
95     NUM_PEDAL_TYPES
96   };
97   Pedal_align_info pedal_info_[NUM_PEDAL_TYPES];
98   vector<Grob *> supports_;
99
100   Pedal_type get_grob_pedal_type (Grob_info g);
101   Spanner *make_line_spanner (Pedal_type t, SCM);
102 };
103
104 Piano_pedal_align_engraver::Piano_pedal_align_engraver ()
105 {
106 }
107
108 void
109 Piano_pedal_align_engraver::start_translation_timestep ()
110 {
111   supports_.clear ();
112 }
113
114 void
115 Piano_pedal_align_engraver::stop_translation_timestep ()
116 {
117   for (int i = 0; i < NUM_PEDAL_TYPES; i ++)
118     {
119       if (pedal_info_[i].line_spanner_)
120         {
121           
122           if (pedal_info_[i].carrying_item_)
123             {
124               if (!pedal_info_[i].line_spanner_->get_bound (LEFT))
125                 pedal_info_[i].line_spanner_->set_bound (LEFT,
126                                                          pedal_info_[i].carrying_item_);
127
128               pedal_info_[i].line_spanner_->set_bound (RIGHT,
129                                                        pedal_info_[i].carrying_item_);
130             }
131           else if (pedal_info_[i].carrying_spanner_
132                    || pedal_info_[i].finished_carrying_spanner_
133                    )
134             {
135               if (!pedal_info_[i].line_spanner_->get_bound (LEFT)
136                   && pedal_info_[i].carrying_spanner_->get_bound (LEFT))
137                 pedal_info_[i].line_spanner_->set_bound (LEFT,
138                                                          pedal_info_[i].carrying_spanner_->get_bound (LEFT));
139               
140
141               if (pedal_info_[i].finished_carrying_spanner_)
142                 pedal_info_[i].line_spanner_->set_bound (RIGHT,
143                                                          pedal_info_[i].finished_carrying_spanner_->get_bound (RIGHT));
144             }
145           
146           for (vsize j = 0; j < supports_.size (); j++)
147             {
148               Side_position_interface::add_support (pedal_info_[i].line_spanner_, supports_[j]);
149             }
150
151           if (pedal_info_[i].is_finished ())
152             {
153               announce_end_grob (pedal_info_[i].line_spanner_, SCM_EOL);
154               pedal_info_[i].clear ();
155             }
156         }
157
158       pedal_info_[i].carrying_item_ = 0;
159     }
160 }
161
162 Piano_pedal_align_engraver::Pedal_type
163 Piano_pedal_align_engraver::get_grob_pedal_type (Grob_info g)
164 {
165   if (g.event_cause ()->in_event_class ("sostenuto-event"))
166     return SOSTENUTO;
167   if (g.event_cause ()->in_event_class ("sustain-event"))
168     return SUSTAIN;
169   if (g.event_cause ()->in_event_class ("una-corda-event"))
170     return UNA_CORDA;
171
172   programming_error ("Unknown piano pedal type. Defaulting to sustain");
173   return SUSTAIN;
174 }
175
176
177 Spanner *
178 Piano_pedal_align_engraver::make_line_spanner (Pedal_type t, SCM cause)
179 {
180   Spanner *sp = pedal_info_[t].line_spanner_;
181   if (!sp)
182     {
183       switch (t)
184         {
185         case (SOSTENUTO):
186           sp = make_spanner ("SostenutoPedalLineSpanner", cause);
187           break;
188         case (SUSTAIN):
189           sp = make_spanner ("SustainPedalLineSpanner", cause);
190           break;
191         case (UNA_CORDA):
192           sp = make_spanner ("UnaCordaPedalLineSpanner", cause);
193           break;
194         default:
195           programming_error ("No pedal type fonud!") ;
196           return sp;
197         }
198   
199       pedal_info_[t].line_spanner_ = sp;
200     }
201   
202   return sp;
203 }
204
205 void
206 Piano_pedal_align_engraver::acknowledge_note_column (Grob_info gi)
207 {
208   supports_.push_back (gi.grob ());
209 }
210
211 void
212 Piano_pedal_align_engraver::acknowledge_piano_pedal_bracket (Grob_info gi)
213 {
214   Pedal_type type = get_grob_pedal_type (gi);
215   Grob *sp = make_line_spanner (type, gi.grob ()->self_scm ());
216
217   Axis_group_interface::add_element (sp, gi.grob ());
218   pedal_info_[type].carrying_spanner_ = gi.spanner ();
219 }
220
221 void
222 Piano_pedal_align_engraver::acknowledge_end_piano_pedal_bracket (Grob_info gi)
223 {
224   Pedal_type type = get_grob_pedal_type (gi);
225   pedal_info_[type].finished_carrying_spanner_ = gi.spanner ();
226 }
227
228 void
229 Piano_pedal_align_engraver::acknowledge_piano_pedal_script (Grob_info gi)
230 {
231   Pedal_type type = get_grob_pedal_type (gi);
232   
233   Grob *sp = make_line_spanner (type, gi.grob ()->self_scm ());
234   Axis_group_interface::add_element (sp, gi.grob ());
235   pedal_info_[type].carrying_item_ = gi.grob ();
236 }
237
238
239 void
240 Piano_pedal_align_engraver::finalize ()
241 {
242  for (int i = 0; i < NUM_PEDAL_TYPES; i ++)
243     {
244       if (pedal_info_[i].line_spanner_)
245         {
246           SCM cc = get_property ("currentCommandColumn");
247           Item *c = unsmob_item (cc);
248           pedal_info_[i].line_spanner_->set_bound (RIGHT, c);
249
250           pedal_info_[i].clear ();
251         }
252     }
253 }
254
255 #include "translator.icc"
256
257 ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, note_column);
258 ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_bracket);
259 ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_script);
260
261 ADD_END_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_bracket);
262
263
264 ADD_TRANSLATOR (Piano_pedal_align_engraver,
265                 /* doc */
266                 "Align piano pedal symbols and brackets.",
267
268                 /* create */
269                 "SostenutoPedalLineSpanner "
270                 "SustainPedalLineSpanner "
271                 "UnaCordaPedalLineSpanner ",
272
273                 /* read */
274                 "currentCommandColumn ",
275
276                 /* write */
277                 ""
278                 );