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
12 #include "engraver.hh"
13 #include "musical-request.hh"
16 #include "lily-guile.hh"
17 #include "side-position-interface.hh"
18 #include "staff-symbol-referencer.hh"
20 #include "axis-group-interface.hh"
21 #include "translator-group.hh"
22 #include "directional-element-interface.hh"
23 #include "note-column.hh"
25 class Piano_pedal_engraver : public Engraver
28 TRANSLATOR_DECLARATIONS(Piano_pedal_engraver);
29 ~Piano_pedal_engraver ();
31 virtual void initialize ();
32 virtual void finalize ();
33 virtual bool try_music (Music*);
34 virtual void stop_translation_timestep ();
35 virtual void start_translation_timestep ();
36 virtual void acknowledge_grob (Grob_info);
37 virtual void create_grobs ();
43 Span_req* start_req_l_;
44 Drul_array<Span_req*> req_l_drul_;
46 Spanner* bracket_p_; // A single portion of a pedal bracket
47 Spanner* finished_bracket_p_;
48 Spanner* line_spanner_; // This grob contains all the pedals of the same type on the same staff
49 Spanner* finished_line_spanner_;
50 Span_req* current_bracket_req_;
54 Pedal_info *info_list_;
56 Spanner *previous_p_ [4]; // Record a stack of the current pedal spanners, so if more than one pedal
57 int nspanners_i; // occurs simultaneously then extra space can be added between them.
58 Drul_array<SCM> edge_width_drul_; // Left and right flare widths of a \___/, as specified by the grob property edge-width.
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 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
176 announce_grob (p->line_spanner_, rq->self_scm ());
179 // Choose the appropriate grobs to add to the line spanner
180 // These can be text items or text-spanners
182 SCM type = ly_cdr (scm_assoc (ly_symbol2scm("pedal-type"),
183 get_property( ( String (p->name_) + "Pedal").ch_C () )));
184 if (type == ly_symbol2scm("text") || // Ped. *Ped. *
185 type == ly_symbol2scm("mixed") ) // Ped. _____/\____|
187 create_text_grobs(p, type);
189 if (type == ly_symbol2scm("bracket") || // |_________/\____|
190 type == ly_symbol2scm("mixed") )
191 create_bracket_grobs(p, type);
199 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
203 SCM strings = get_property (("pedal" + String (p->name_) + "Strings").ch_C ());
205 if (! (scm_ilength (strings) < 3))
207 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
209 if (pedaltype == ly_symbol2scm("text"))
211 if (!p->start_req_l_)
213 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
217 s = ly_cadr (strings);
219 p->start_req_l_ = p->req_l_drul_[START];
223 else if (p->req_l_drul_[STOP])
225 if (pedaltype == ly_symbol2scm("text"))
227 if (!p->start_req_l_)
229 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
233 s = ly_caddr (strings);
240 else if ( p->req_l_drul_[START] )
242 p->start_req_l_ = p->req_l_drul_[START];
243 s = ly_car (strings);
244 if (pedaltype == ly_symbol2scm("text")) {
246 previous_p_[nspanners_i] = p->line_spanner_;
248 // add extra space below the previous already-occuring pedal
249 Side_position_interface::add_support(p->line_spanner_, previous_p_[nspanners_i - 1]);
255 String propname = String (p->name_) + "Pedal";
256 b = get_property (propname.ch_C ());
257 p->item_p_ = new Item (b);
258 p->item_p_->set_grob_property ("text", s);
259 Axis_group_interface::add_element (p->line_spanner_, p->item_p_);
261 announce_grob (p->item_p_,
262 (p->req_l_drul_[START]
263 ? p->req_l_drul_[START]
264 : p->req_l_drul_[STOP])->self_scm() );
267 if (pedaltype == ly_symbol2scm("text"))
269 p->req_l_drul_[START] = 0;
270 p->req_l_drul_[STOP] = 0;
276 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
279 if (p->req_l_drul_[STOP])
281 if (!p->start_req_l_)
283 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
285 else if (!p->req_l_drul_[START])
288 assert (!p->finished_bracket_p_ && p->bracket_p_);
290 p->bracket_p_->set_bound (RIGHT, unsmob_grob(get_property ("currentMusicalColumn")));
292 // Set properties so that the molecule-creating function will know whether the right edge should be flared ___/
293 SCM eleft = ly_car ( p->bracket_p_->get_grob_property("edge-width") );
294 SCM eright = ( (bool) p->req_l_drul_[START] ?
295 edge_width_drul_[RIGHT] :
297 p->bracket_p_->set_grob_property("edge-width", gh_cons ( eleft, eright ) );
298 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (RIGHT));
300 p->finished_bracket_p_ = p->bracket_p_;
302 p->current_bracket_req_ = 0;
303 p->start_req_l_ = p->req_l_drul_[START];
306 if (p->req_l_drul_[START])
308 p->start_req_l_ = p->req_l_drul_[START];
309 p->current_bracket_req_ = p->req_l_drul_[START];
311 p->bracket_p_ = new Spanner (get_property ("PianoPedalBracket"));
313 // Set properties so that the molecule-creating function will know whether the left edge should be flared \___
314 edge_width_drul_[LEFT] = ly_car ( p->bracket_p_->get_grob_property("edge-width") );
315 edge_width_drul_[RIGHT] = ly_cdr ( p->bracket_p_->get_grob_property("edge-width") );
316 SCM eleft = ( (bool) p->req_l_drul_[STOP] ?
317 edge_width_drul_[LEFT] :
319 SCM eright = gh_double2scm(0);
320 p->bracket_p_->set_grob_property("edge-width", gh_cons ( eleft, eright ) );
322 // Set this property for 'mixed style' pedals, Ped._______/\ ,
323 // so the molecule function will shorten the ____ line by the length of the Ped. text.
324 p->bracket_p_->set_grob_property("text-start",
325 pedaltype == ly_symbol2scm("mixed") ?
326 gh_bool2scm((bool) ! p->req_l_drul_[STOP]) :
329 p->bracket_p_->set_parent (p->item_p_, Y_AXIS);
331 p->bracket_p_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
332 Axis_group_interface::add_element (p->line_spanner_, p->bracket_p_);
334 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (LEFT));
335 announce_grob (p->bracket_p_, p->req_l_drul_[START]->self_scm());
337 if (!p->req_l_drul_[STOP]) {
340 previous_p_[nspanners_i] = p->line_spanner_;
343 // position new pedal spanner below the current one
344 Side_position_interface::add_support(p->line_spanner_, previous_p_[nspanners_i - 1]);
349 p->req_l_drul_[START] = 0;
350 p->req_l_drul_[STOP] = 0;
354 Piano_pedal_engraver::finalize ()
356 for (Pedal_info*p = info_list_; p && p->name_; p ++)
359 && p->line_spanner_->immutable_property_alist_ == SCM_EOL)
360 p->line_spanner_ = 0;
361 if (p->line_spanner_)
363 p->finished_line_spanner_ = p->line_spanner_;
367 && p->bracket_p_->immutable_property_alist_ == SCM_EOL)
371 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
372 p->bracket_p_->suicide ();
380 Piano_pedal_engraver::stop_translation_timestep ()
382 for (Pedal_info*p = info_list_; p && p->name_; p ++)
384 p->finished_line_spanner_ = p->line_spanner_;
391 Piano_pedal_engraver::typeset_all ()
396 for (Pedal_info*p = info_list_; p->name_; p ++)
398 if (p->finished_line_spanner_
399 && p->finished_line_spanner_->immutable_property_alist_ == SCM_EOL)
400 p->finished_line_spanner_ = 0;
401 if (p->finished_bracket_p_
402 && p->finished_bracket_p_->immutable_property_alist_ == SCM_EOL)
403 p->finished_bracket_p_ = 0;
404 if (p->name_ == String ("Sustain"))
405 sustain = p->item_p_;
412 if (p->name_ != String ("Sustain"))
416 Side_position_interface::add_support (p->item_p_,sustain);
419 typeset_grob (p->item_p_);
423 if (p->finished_bracket_p_)
425 if (!p->finished_bracket_p_->get_bound (RIGHT))
427 p->finished_bracket_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
429 if (p->finished_line_spanner_)
430 add_bound_item (p->finished_line_spanner_,
431 p->finished_bracket_p_->get_bound (RIGHT));
433 typeset_grob (p->finished_bracket_p_);
434 p->finished_bracket_p_ =0;
437 if (p->finished_line_spanner_)
439 Side_position_interface::add_staff_support (p->finished_line_spanner_);
440 Grob * l = p->finished_line_spanner_->get_bound (LEFT );
441 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
443 p->finished_line_spanner_->set_bound (RIGHT, l);
445 p->finished_line_spanner_->set_bound (LEFT, r);
448 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
449 Item * ci = dynamic_cast<Item*>(cc);
450 p->finished_line_spanner_->set_bound (RIGHT, ci);
451 p->finished_line_spanner_->set_bound (LEFT, ci);
453 typeset_grob (p->finished_line_spanner_);
454 p->finished_line_spanner_ = 0;
460 Piano_pedal_engraver::start_translation_timestep ()
462 for (Pedal_info*p = info_list_; p->name_; p ++)
464 p->req_l_drul_[STOP] = 0;
465 p->req_l_drul_[START] = 0;
468 ENTER_DESCRIPTION(Piano_pedal_engraver,
469 /* descr */ "Engrave piano pedal symbols and brackets.",
470 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
471 /* acks */ "note-column-interface",
472 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",