]> git.donarmstrong.com Git - lilypond.git/blob - lily/piano-pedal-align-engraver.cc
Web-ja: update introduction
[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--2015 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 #include "engraver.hh"
22
23 #include "spanner.hh"
24 #include "item.hh"
25 #include "side-position-interface.hh"
26 #include "stream-event.hh"
27 #include "warn.hh"
28 #include "axis-group-interface.hh"
29
30 #include "translator.icc"
31
32 /*
33   TODO:
34
35
36   * Detach from pedal specifics,
37
38   * Also use this engraver for dynamics.
39 */
40
41 struct Pedal_align_info
42 {
43   Spanner *line_spanner_;
44   Grob *carrying_item_;
45   Spanner *carrying_spanner_;
46   Spanner *finished_carrying_spanner_;
47
48   Pedal_align_info ()
49   {
50     clear ();
51
52   }
53   void clear ()
54   {
55     line_spanner_ = 0;
56     carrying_spanner_ = 0;
57     carrying_item_ = 0;
58     finished_carrying_spanner_ = 0;
59   }
60   bool is_finished ()
61   {
62     bool do_continue = carrying_item_;
63
64     do_continue |= (carrying_spanner_ && !finished_carrying_spanner_);
65     do_continue |= (carrying_spanner_ && finished_carrying_spanner_ != carrying_spanner_);
66
67     return !do_continue;
68   }
69 };
70
71 class Piano_pedal_align_engraver : public Engraver
72 {
73 public:
74   TRANSLATOR_DECLARATIONS (Piano_pedal_align_engraver);
75
76 protected:
77   virtual void finalize ();
78
79   void acknowledge_piano_pedal_script (Grob_info);
80   void acknowledge_piano_pedal_bracket (Grob_info);
81   void acknowledge_note_column (Grob_info);
82
83   void acknowledge_end_piano_pedal_bracket (Grob_info);
84
85   void stop_translation_timestep ();
86   void start_translation_timestep ();
87
88 private:
89   enum Pedal_type
90   {
91     SOSTENUTO,
92     SUSTAIN,
93     UNA_CORDA,
94     NUM_PEDAL_TYPES
95   };
96   Pedal_align_info pedal_info_[NUM_PEDAL_TYPES];
97   vector<Grob *> supports_;
98
99   Pedal_type get_grob_pedal_type (Grob_info g);
100   Spanner *make_line_spanner (Pedal_type t, SCM);
101 };
102
103 Piano_pedal_align_engraver::Piano_pedal_align_engraver (Context *c)
104   : Engraver (c)
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               if (pedal_info_[i].finished_carrying_spanner_)
141                 pedal_info_[i].line_spanner_->set_bound (RIGHT,
142                                                          pedal_info_[i].finished_carrying_spanner_->get_bound (RIGHT));
143             }
144
145           for (vsize j = 0; j < supports_.size (); j++)
146             {
147               Side_position_interface::add_support (pedal_info_[i].line_spanner_, supports_[j]);
148             }
149
150           if (pedal_info_[i].is_finished ())
151             {
152               announce_end_grob (pedal_info_[i].line_spanner_, SCM_EOL);
153               pedal_info_[i].clear ();
154             }
155         }
156
157       pedal_info_[i].carrying_item_ = 0;
158     }
159 }
160
161 Piano_pedal_align_engraver::Pedal_type
162 Piano_pedal_align_engraver::get_grob_pedal_type (Grob_info g)
163 {
164   if (g.event_cause ()->in_event_class ("sostenuto-event"))
165     return SOSTENUTO;
166   if (g.event_cause ()->in_event_class ("sustain-event"))
167     return SUSTAIN;
168   if (g.event_cause ()->in_event_class ("una-corda-event"))
169     return UNA_CORDA;
170
171   programming_error ("Unknown piano pedal type.  Defaulting to sustain");
172   return SUSTAIN;
173 }
174
175 Spanner *
176 Piano_pedal_align_engraver::make_line_spanner (Pedal_type t, SCM cause)
177 {
178   Spanner *sp = pedal_info_[t].line_spanner_;
179   if (!sp)
180     {
181       switch (t)
182         {
183         case (SOSTENUTO):
184           sp = make_spanner ("SostenutoPedalLineSpanner", cause);
185           break;
186         case (SUSTAIN):
187           sp = make_spanner ("SustainPedalLineSpanner", cause);
188           break;
189         case (UNA_CORDA):
190           sp = make_spanner ("UnaCordaPedalLineSpanner", cause);
191           break;
192         default:
193           programming_error ("No pedal type fonud!");
194           return sp;
195         }
196
197       pedal_info_[t].line_spanner_ = sp;
198     }
199
200   return sp;
201 }
202
203 void
204 Piano_pedal_align_engraver::acknowledge_note_column (Grob_info gi)
205 {
206   supports_.push_back (gi.grob ());
207 }
208
209 void
210 Piano_pedal_align_engraver::acknowledge_piano_pedal_bracket (Grob_info gi)
211 {
212   Pedal_type type = get_grob_pedal_type (gi);
213   Grob *sp = make_line_spanner (type, gi.grob ()->self_scm ());
214
215   Axis_group_interface::add_element (sp, gi.grob ());
216   pedal_info_[type].carrying_spanner_ = gi.spanner ();
217 }
218
219 void
220 Piano_pedal_align_engraver::acknowledge_end_piano_pedal_bracket (Grob_info gi)
221 {
222   Pedal_type type = get_grob_pedal_type (gi);
223   pedal_info_[type].finished_carrying_spanner_ = gi.spanner ();
224 }
225
226 void
227 Piano_pedal_align_engraver::acknowledge_piano_pedal_script (Grob_info gi)
228 {
229   Pedal_type type = get_grob_pedal_type (gi);
230
231   Grob *sp = make_line_spanner (type, gi.grob ()->self_scm ());
232   Axis_group_interface::add_element (sp, gi.grob ());
233   pedal_info_[type].carrying_item_ = gi.grob ();
234 }
235
236 void
237 Piano_pedal_align_engraver::finalize ()
238 {
239   for (int i = 0; i < NUM_PEDAL_TYPES; i++)
240     {
241       if (pedal_info_[i].line_spanner_)
242         {
243           SCM cc = get_property ("currentCommandColumn");
244           Item *c = unsmob<Item> (cc);
245           pedal_info_[i].line_spanner_->set_bound (RIGHT, c);
246
247           pedal_info_[i].clear ();
248         }
249     }
250 }
251
252
253
254 void
255 Piano_pedal_align_engraver::boot ()
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   ADD_END_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_bracket);
261 }
262
263 ADD_TRANSLATOR (Piano_pedal_align_engraver,
264                 /* doc */
265                 "Align piano pedal symbols and brackets.",
266
267                 /* create */
268                 "SostenutoPedalLineSpanner "
269                 "SustainPedalLineSpanner "
270                 "UnaCordaPedalLineSpanner ",
271
272                 /* read */
273                 "currentCommandColumn ",
274
275                 /* write */
276                 ""
277                );