2 piano-pedal-engraver.cc -- implement Piano_pedal_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2002 Jan Nieuwenhuizen <janneke@gnu.org>
8 Chris Jackson <chris@fluffhouse.org.uk> - extended to support
10 TODO: support for __| |__ or __| Ped instead of ___/\__ for pedal up-down
13 #include "engraver.hh"
14 #include "musical-request.hh"
17 #include "lily-guile.hh"
18 #include "side-position-interface.hh"
19 #include "staff-symbol-referencer.hh"
21 #include "axis-group-interface.hh"
22 #include "translator-group.hh"
23 #include "directional-element-interface.hh"
24 #include "note-column.hh"
26 class Piano_pedal_engraver : public Engraver
29 TRANSLATOR_DECLARATIONS(Piano_pedal_engraver);
30 ~Piano_pedal_engraver ();
32 virtual void initialize ();
33 virtual void finalize ();
34 virtual bool try_music (Music*);
35 virtual void stop_translation_timestep ();
36 virtual void start_translation_timestep ();
37 virtual void acknowledge_grob (Grob_info);
38 virtual void create_grobs ();
44 Span_req* start_req_l_;
45 Drul_array<Span_req*> req_l_drul_;
47 Spanner* bracket_p_; // A single portion of a pedal bracket
48 Spanner* finished_bracket_p_;
49 Spanner* line_spanner_; // This grob contains all the pedals of the same type on the same staff
50 Spanner* finished_line_spanner_;
51 Span_req* current_bracket_req_;
55 Pedal_info *info_list_;
57 Spanner *previous_p_ [4]; // Record a stack of the current pedal spanners, so if more than one pedal
58 int nspanners_i; // occurs simultaneously then extra space can be added between them.
59 void create_text_grobs (Pedal_info *p, SCM pedaltype);
60 void create_bracket_grobs (Pedal_info *p, SCM pedaltype);
66 Piano_pedal_engraver::Piano_pedal_engraver ()
71 Piano_pedal_engraver::initialize ()
73 info_list_ = new Pedal_info[4];
74 Pedal_info *p = info_list_;
77 for (int i = 0; i < 3; ++i)
81 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
88 p->finished_bracket_p_ = 0;
90 p->finished_line_spanner_ = 0;
91 p->current_bracket_req_ = 0;
92 p->req_l_drul_[START] = 0;
93 p->req_l_drul_[STOP] = 0;
101 Piano_pedal_engraver::~Piano_pedal_engraver ()
111 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
113 for (Pedal_info*p = info_list_; p && p->name_; p ++)
115 Grob *g = (Grob *) p->item_p_;
119 if (g && p->line_spanner_)
121 if (Note_column::has_interface (info.grob_l_))
123 Side_position_interface::add_support (p->line_spanner_, info.grob_l_);
124 add_bound_item (p->line_spanner_,dynamic_cast<Item*> (info.grob_l_));
126 if (Side_position_interface::get_axis (g) == X_AXIS
127 && !g->get_parent (Y_AXIS))
128 g->set_parent (info.grob_l_, Y_AXIS);
131 g = (Grob *) p->bracket_p_;
138 Piano_pedal_engraver::try_music (Music *m)
140 if (Span_req * s = dynamic_cast<Span_req*> (m))
142 for (Pedal_info*p = info_list_; p->name_; p ++)
144 if (ly_scm2string (s->get_mus_property ("span-type")) == "abort")
146 p->req_l_drul_[START] = 0;
147 p->req_l_drul_[STOP] = 0;
150 p->bracket_p_->suicide (); /* as in dynamic-engraver.cc */
153 if (scm_equal_p (s->get_mus_property ("span-type"),
154 ly_str02scm (p->name_))==SCM_BOOL_T)
156 p->req_l_drul_[s->get_span_dir ()] = s;
165 Piano_pedal_engraver::create_grobs ()
167 for (Pedal_info*p = info_list_; p && p->name_; p ++)
169 if (p->req_l_drul_[STOP] || p->req_l_drul_[START])
171 if (!p->line_spanner_)
173 p->line_spanner_ = new Spanner (get_property ( ( String (p->name_) + "PedalLineSpanner").ch_C() ));
174 Side_position_interface::set_axis (p->line_spanner_, Y_AXIS);
175 Axis_group_interface::set_interface (p->line_spanner_);
176 Axis_group_interface::set_axes (p->line_spanner_, Y_AXIS, Y_AXIS);
177 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
178 announce_grob (p->line_spanner_, rq->self_scm ());
181 // Choose the appropriate grobs to add to the line spanner
182 // These can be text items or text-spanners
184 SCM type = ly_cdr (scm_assoc (ly_symbol2scm("pedal-type"),
185 get_property( ( String (p->name_) + "Pedal").ch_C () )));
186 if (type == ly_symbol2scm("text") || // Ped. *Ped. *
187 type == ly_symbol2scm("mixed") ) // Ped. _____/\____|
189 create_text_grobs(p, type);
191 if (type == ly_symbol2scm("bracket") || // |_________/\____|
192 type == ly_symbol2scm("mixed") )
193 create_bracket_grobs(p, type);
201 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
205 SCM strings = get_property (("pedal" + String (p->name_) + "Strings").ch_C ());
207 if (! (scm_ilength (strings) < 3))
209 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
211 if (pedaltype == ly_symbol2scm("text"))
213 if (!p->start_req_l_)
215 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
219 s = ly_cadr (strings);
221 p->start_req_l_ = p->req_l_drul_[START];
225 else if (p->req_l_drul_[STOP])
227 if (pedaltype == ly_symbol2scm("text"))
229 if (!p->start_req_l_)
231 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
235 s = ly_caddr (strings);
242 else if ( p->req_l_drul_[START] )
244 p->start_req_l_ = p->req_l_drul_[START];
245 s = ly_car (strings);
246 if (pedaltype == ly_symbol2scm("text")) {
248 previous_p_[nspanners_i] = p->line_spanner_;
250 // add extra space below the previous already-occuring pedal
251 Side_position_interface::add_support(p->line_spanner_, previous_p_[nspanners_i - 1]);
257 String propname = String (p->name_) + "Pedal";
258 b = get_property (propname.ch_C ());
259 p->item_p_ = new Item (b);
260 p->item_p_->set_grob_property ("text", s);
261 Axis_group_interface::add_element (p->line_spanner_, p->item_p_);
263 announce_grob (p->item_p_,
264 (p->req_l_drul_[START]
265 ? p->req_l_drul_[START]
266 : p->req_l_drul_[STOP])->self_scm() );
269 if (pedaltype == ly_symbol2scm("text"))
271 p->req_l_drul_[START] = 0;
272 p->req_l_drul_[STOP] = 0;
278 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
281 if (p->req_l_drul_[STOP])
283 if (!p->start_req_l_)
285 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
287 else if (!p->req_l_drul_[START])
290 assert (!p->finished_bracket_p_ && p->bracket_p_);
292 p->bracket_p_->set_bound (RIGHT, unsmob_grob(get_property ("currentMusicalColumn")));
294 // Set a property so that the molecule-creating function will know whether the right edge should be angled ___/
295 p->bracket_p_->set_grob_property("angle-right", gh_bool2scm((bool) p->req_l_drul_[START]) );
296 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (RIGHT));
298 p->finished_bracket_p_ = p->bracket_p_;
300 p->current_bracket_req_ = 0;
301 p->start_req_l_ = p->req_l_drul_[START];
304 if (p->req_l_drul_[START])
306 p->start_req_l_ = p->req_l_drul_[START];
307 p->current_bracket_req_ = p->req_l_drul_[START];
309 p->bracket_p_ = new Spanner (get_property ("PianoPedalBracket"));
310 p->bracket_p_->set_interface (ly_symbol2scm ("piano-pedal-interface"));
312 // Set a property so that the molecule-creating function will know whether the left edge should be angled \___
313 p->bracket_p_->set_grob_property("angle-left", gh_bool2scm((bool) p->req_l_drul_[STOP]) );
315 // Set this property for 'mixed style' pedals, Ped._______/\ ,
316 // so the molecule function will shorten the ____ line by the length of the Ped. text.
317 p->bracket_p_->set_grob_property("text-start",
318 pedaltype == ly_symbol2scm("mixed") ?
319 gh_bool2scm((bool) ! p->req_l_drul_[STOP]) :
322 p->bracket_p_->set_parent (p->item_p_, Y_AXIS);
324 Side_position_interface::set_axis (p->bracket_p_, Y_AXIS);
325 Side_position_interface::set_direction (p->bracket_p_, UP);
326 p->bracket_p_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
327 Axis_group_interface::add_element (p->line_spanner_, p->bracket_p_);
329 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (LEFT));
330 announce_grob (p->bracket_p_, p->req_l_drul_[START]->self_scm());
332 if (!p->req_l_drul_[STOP]) {
335 previous_p_[nspanners_i] = p->line_spanner_;
338 // position new pedal spanner below the current one
339 Side_position_interface::add_support(p->line_spanner_, previous_p_[nspanners_i - 1]);
344 p->req_l_drul_[START] = 0;
345 p->req_l_drul_[STOP] = 0;
349 Piano_pedal_engraver::finalize ()
351 for (Pedal_info*p = info_list_; p && p->name_; p ++)
354 && p->line_spanner_->immutable_property_alist_ == SCM_EOL)
355 p->line_spanner_ = 0;
356 if (p->line_spanner_)
358 p->finished_line_spanner_ = p->line_spanner_;
362 && p->bracket_p_->immutable_property_alist_ == SCM_EOL)
366 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
367 p->bracket_p_->suicide ();
375 Piano_pedal_engraver::stop_translation_timestep ()
377 for (Pedal_info*p = info_list_; p && p->name_; p ++)
379 p->finished_line_spanner_ = p->line_spanner_;
386 Piano_pedal_engraver::typeset_all ()
391 for (Pedal_info*p = info_list_; p->name_; p ++)
393 if (p->finished_line_spanner_
394 && p->finished_line_spanner_->immutable_property_alist_ == SCM_EOL)
395 p->finished_line_spanner_ = 0;
396 if (p->finished_bracket_p_
397 && p->finished_bracket_p_->immutable_property_alist_ == SCM_EOL)
398 p->finished_bracket_p_ = 0;
399 if (p->name_ == String ("Sustain"))
400 sustain = p->item_p_;
407 if (p->name_ != String ("Sustain"))
411 Side_position_interface::add_support (p->item_p_,sustain);
414 typeset_grob (p->item_p_);
418 if (p->finished_bracket_p_)
420 if (!p->finished_bracket_p_->get_bound (RIGHT))
422 p->finished_bracket_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
424 if (p->finished_line_spanner_)
425 add_bound_item (p->finished_line_spanner_,
426 p->finished_bracket_p_->get_bound (RIGHT));
428 typeset_grob (p->finished_bracket_p_);
429 p->finished_bracket_p_ =0;
432 if (p->finished_line_spanner_)
434 Side_position_interface::add_staff_support (p->finished_line_spanner_);
435 Grob * l = p->finished_line_spanner_->get_bound (LEFT );
436 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
438 p->finished_line_spanner_->set_bound (RIGHT, l);
440 p->finished_line_spanner_->set_bound (LEFT, r);
443 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
444 Item * ci = dynamic_cast<Item*>(cc);
445 p->finished_line_spanner_->set_bound (RIGHT, ci);
446 p->finished_line_spanner_->set_bound (LEFT, ci);
448 typeset_grob (p->finished_line_spanner_);
449 p->finished_line_spanner_ = 0;
455 Piano_pedal_engraver::start_translation_timestep ()
457 for (Pedal_info*p = info_list_; p->name_; p ++)
459 p->req_l_drul_[STOP] = 0;
460 p->req_l_drul_[START] = 0;
463 ENTER_DESCRIPTION(Piano_pedal_engraver,
464 /* descr */ "Engrave piano pedal symbols and brackets.",
465 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
466 /* acks */ "note-column-interface",
467 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",