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"
28 Span_req* start_req_l_;
29 Drul_array<Span_req*> req_l_drul_;
31 Spanner* bracket_p_; // A single portion of a pedal bracket
32 Spanner* finished_bracket_p_;
35 This grob contains all the pedals of the same type on the same staff
37 Spanner* line_spanner_;
38 Spanner* finished_line_spanner_;
39 Span_req* current_bracket_req_;
43 class Piano_pedal_engraver : public Engraver
46 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
47 ~Piano_pedal_engraver ();
49 virtual void initialize ();
50 virtual void finalize ();
51 virtual bool try_music (Music*);
52 virtual void stop_translation_timestep ();
53 virtual void start_translation_timestep ();
54 virtual void acknowledge_grob (Grob_info);
55 virtual void process_acknowledged_grobs ();
59 Pedal_info *info_list_;
62 Record a stack of the current pedal spanners, so if more than one pedal
63 occurs simultaneously then extra space can be added between them.
66 Why 4, why not 3. Why not 3423 ? ---hwn.
69 Spanner *previous_p_ [4];
74 Left and right flare widths of a \___/, as specified by the grob
77 Drul_array<SCM> edge_width_drul_;
79 void create_text_grobs (Pedal_info *p, SCM pedaltype);
80 void create_bracket_grobs (Pedal_info *p, SCM pedaltype);
85 Piano_pedal_engraver::Piano_pedal_engraver ()
91 Piano_pedal_engraver::initialize ()
93 info_list_ = new Pedal_info[4];
94 Pedal_info *p = info_list_;
97 for (int i = 0; i < 3; ++i)
101 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
108 p->finished_bracket_p_ = 0;
109 p->line_spanner_ = 0;
110 p->finished_line_spanner_ = 0;
111 p->current_bracket_req_ = 0;
112 p->req_l_drul_[START] = 0;
113 p->req_l_drul_[STOP] = 0;
121 Piano_pedal_engraver::~Piano_pedal_engraver ()
131 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
133 for (Pedal_info*p = info_list_; p && p->name_; p ++)
135 if (Note_column::has_interface (info.grob_l_))
137 if (p->line_spanner_)
139 Side_position_interface::add_support (p->line_spanner_, info.grob_l_);
141 add_bound_item (p->line_spanner_,info.grob_l_);
144 add_bound_item (p->bracket_p_,info.grob_l_);
151 Piano_pedal_engraver::try_music (Music *m)
153 if (Span_req * s = dynamic_cast<Span_req*> (m))
155 for (Pedal_info*p = info_list_; p->name_; p ++)
157 if (ly_scm2string (s->get_mus_property ("span-type")) == "abort")
159 p->req_l_drul_[START] = 0;
160 p->req_l_drul_[STOP] = 0;
163 p->bracket_p_->suicide (); /* as in dynamic-engraver.cc */
166 if (scm_equal_p (s->get_mus_property ("span-type"),
167 ly_str02scm (p->name_))==SCM_BOOL_T)
169 p->req_l_drul_[s->get_span_dir ()] = s;
178 Piano_pedal_engraver::process_acknowledged_grobs ()
180 for (Pedal_info*p = info_list_; p && p->name_; p ++)
182 if (p->req_l_drul_[STOP] || p->req_l_drul_[START])
184 if (!p->line_spanner_)
186 String name = String (p->name_) + "PedalLineSpanner";
187 p->line_spanner_ = new Spanner (get_property (name.ch_C ()));
188 Side_position_interface::set_axis (p->line_spanner_, Y_AXIS);
189 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
190 announce_grob (p->line_spanner_, rq->self_scm ());
193 /* Choose the appropriate grobs to add to the line spanner
194 These can be text items or text-spanners
196 SCM type = ly_cdr (scm_assoc (ly_symbol2scm ("pedal-type"),
197 get_property ( (String (p->name_) + "Pedal").ch_C ())));
198 if (type == ly_symbol2scm ("text") || // Ped. *Ped. *
199 type == ly_symbol2scm ("mixed") ) // Ped. _____/\____|
202 create_text_grobs (p, type);
204 if (type == ly_symbol2scm ("bracket") || // |_________/\____|
205 type == ly_symbol2scm ("mixed") )
207 create_bracket_grobs (p, type);
215 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
219 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").ch_C ());
221 if (scm_ilength (strings) >= 3)
223 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
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_cadr (strings);
235 p->start_req_l_ = p->req_l_drul_[START];
238 else if (p->req_l_drul_[STOP])
240 if (pedaltype == ly_symbol2scm ("text"))
242 if (!p->start_req_l_)
244 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
248 s = ly_caddr (strings);
254 else if (p->req_l_drul_[START])
256 p->start_req_l_ = p->req_l_drul_[START];
257 s = ly_car (strings);
258 if (pedaltype == ly_symbol2scm ("text"))
261 previous_p_[spanner_count_] = p->line_spanner_;
262 if (spanner_count_ > 1)
263 // add extra space below the previous already-occuring pedal
264 Side_position_interface::add_support (p->line_spanner_,
265 previous_p_[spanner_count_ - 1]);
271 String propname = String (p->name_) + "Pedal";
272 b = get_property (propname.ch_C ());
273 p->item_p_ = new Item (b);
274 p->item_p_->set_grob_property ("text", s);
275 Axis_group_interface::add_element (p->line_spanner_, p->item_p_);
277 announce_grob (p->item_p_,
278 (p->req_l_drul_[START]
279 ? p->req_l_drul_[START]
280 : p->req_l_drul_[STOP])->self_scm ());
283 if (pedaltype == ly_symbol2scm ("text"))
285 p->req_l_drul_[START] = 0;
286 p->req_l_drul_[STOP] = 0;
292 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
295 if (p->req_l_drul_[STOP])
297 if (!p->start_req_l_)
299 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
301 else if (!p->req_l_drul_[START])
304 assert (!p->finished_bracket_p_ && p->bracket_p_);
306 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
307 p->bracket_p_->set_bound (RIGHT, cmc);
310 Set properties so that the molecule-creating function will
311 know whether the right edge should be flared ___/
313 SCM eleft = ly_car (p->bracket_p_->get_grob_property ("edge-widen"));
314 SCM eright = (p->req_l_drul_[START] ? edge_width_drul_[RIGHT] : gh_double2scm (0));
315 p->bracket_p_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
317 p->finished_bracket_p_ = p->bracket_p_;
319 p->current_bracket_req_ = 0;
320 p->start_req_l_ = p->req_l_drul_[START];
323 if (p->req_l_drul_[START])
325 p->start_req_l_ = p->req_l_drul_[START];
326 p->current_bracket_req_ = p->req_l_drul_[START];
328 p->bracket_p_ = new Spanner (get_property ("PianoPedalBracket"));
331 Set properties so that the molecule-creating function will
332 know whether the left edge should be flared \___
335 SCM ew = p->bracket_p_->get_grob_property ("edge-widen");
336 edge_width_drul_[LEFT] = ly_car (ew);
337 edge_width_drul_[RIGHT] = ly_cdr (ew);
339 SCM eleft = ( (bool) p->req_l_drul_[STOP] ?
340 edge_width_drul_[LEFT] :
342 SCM eright = gh_double2scm (0);
343 p->bracket_p_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
345 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
346 so the molecule function will shorten the ____ line by the length of the Ped. text.
349 p->bracket_p_->set_grob_property ("text-start",
350 pedaltype == ly_symbol2scm ("mixed") ?
351 gh_bool2scm ( (bool) ! p->req_l_drul_[STOP]) :
352 gh_bool2scm (false));
355 Warning: we can't hang the bracket on an item in Y-direction:
356 it will cause problems when the bracket is broken, because the
357 item can be on another line.
359 p->bracket_p_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
360 Axis_group_interface::add_element (p->line_spanner_, p->bracket_p_);
362 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (LEFT));
363 announce_grob (p->bracket_p_, p->req_l_drul_[START]->self_scm ());
365 if (!p->req_l_drul_[STOP])
368 previous_p_[spanner_count_] = p->line_spanner_;
370 if (spanner_count_ > 1)
371 // position new pedal spanner below the current one
372 Side_position_interface::add_support (p->line_spanner_, previous_p_[spanner_count_ - 1]);
376 p->req_l_drul_[START] = 0;
377 p->req_l_drul_[STOP] = 0;
381 Piano_pedal_engraver::finalize ()
383 for (Pedal_info*p = info_list_; p && p->name_; p ++)
389 && p->line_spanner_->immutable_property_alist_ == SCM_EOL)
390 p->line_spanner_ = 0;
392 if (p->line_spanner_)
394 p->finished_line_spanner_ = p->line_spanner_;
398 && p->bracket_p_->immutable_property_alist_ == SCM_EOL)
402 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
403 p->bracket_p_->suicide ();
411 Piano_pedal_engraver::stop_translation_timestep ()
413 for (Pedal_info*p = info_list_; p && p->name_; p ++)
417 p->finished_line_spanner_ = p->line_spanner_;
418 p->line_spanner_ = 0;
427 Piano_pedal_engraver::typeset_all ()
430 for (Pedal_info*p = info_list_; p->name_; p ++)
435 if (p->finished_line_spanner_
436 && p->finished_line_spanner_->immutable_property_alist_ == SCM_EOL)
437 p->finished_line_spanner_ = 0;
438 if (p->finished_bracket_p_
439 && p->finished_bracket_p_->immutable_property_alist_ == SCM_EOL)
440 p->finished_bracket_p_ = 0;
443 if (p->name_ == String ("Sustain"))
444 sustain = p->item_p_;
451 if (p->name_ != String ("Sustain"))
455 Side_position_interface::add_support (p->item_p_,sustain);
458 typeset_grob (p->item_p_);
462 if (p->finished_bracket_p_)
464 Grob * l = p->finished_bracket_p_->get_bound (LEFT);
465 Grob * r = p->finished_bracket_p_->get_bound (RIGHT);
468 p->finished_bracket_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
471 typeset_grob (p->finished_bracket_p_);
472 p->finished_bracket_p_ =0;
475 if (p->finished_line_spanner_)
477 Side_position_interface::add_staff_support (p->finished_line_spanner_);
478 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
479 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
481 p->finished_line_spanner_->set_bound (RIGHT, l);
483 p->finished_line_spanner_->set_bound (LEFT, r);
486 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
487 Item * ci = dynamic_cast<Item*> (cc);
488 p->finished_line_spanner_->set_bound (RIGHT, ci);
489 p->finished_line_spanner_->set_bound (LEFT, ci);
491 typeset_grob (p->finished_line_spanner_);
492 p->finished_line_spanner_ = 0;
498 Piano_pedal_engraver::start_translation_timestep ()
500 for (Pedal_info*p = info_list_; p->name_; p ++)
502 p->req_l_drul_[STOP] = 0;
503 p->req_l_drul_[START] = 0;
506 ENTER_DESCRIPTION (Piano_pedal_engraver,
507 /* descr */ "Engrave piano pedal symbols and brackets.",
508 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
509 /* acks */ "note-column-interface",
510 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",