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 create_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::create_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-width"));
314 SCM eright = (p->req_l_drul_[START] ? edge_width_drul_[RIGHT] : gh_double2scm (0));
315 p->bracket_p_->set_grob_property ("edge-width", 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-width");
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-width", 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));
354 p->bracket_p_->set_parent (p->item_p_, Y_AXIS);
356 p->bracket_p_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
357 Axis_group_interface::add_element (p->line_spanner_, p->bracket_p_);
359 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (LEFT));
360 announce_grob (p->bracket_p_, p->req_l_drul_[START]->self_scm ());
362 if (!p->req_l_drul_[STOP])
365 previous_p_[spanner_count_] = p->line_spanner_;
367 if (spanner_count_ > 1)
368 // position new pedal spanner below the current one
369 Side_position_interface::add_support (p->line_spanner_, previous_p_[spanner_count_ - 1]);
373 p->req_l_drul_[START] = 0;
374 p->req_l_drul_[STOP] = 0;
378 Piano_pedal_engraver::finalize ()
380 for (Pedal_info*p = info_list_; p && p->name_; p ++)
386 && p->line_spanner_->immutable_property_alist_ == SCM_EOL)
387 p->line_spanner_ = 0;
389 if (p->line_spanner_)
391 p->finished_line_spanner_ = p->line_spanner_;
395 && p->bracket_p_->immutable_property_alist_ == SCM_EOL)
399 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
400 p->bracket_p_->suicide ();
408 Piano_pedal_engraver::stop_translation_timestep ()
410 for (Pedal_info*p = info_list_; p && p->name_; p ++)
414 p->finished_line_spanner_ = p->line_spanner_;
415 p->line_spanner_ = 0;
424 Piano_pedal_engraver::typeset_all ()
427 for (Pedal_info*p = info_list_; p->name_; p ++)
432 if (p->finished_line_spanner_
433 && p->finished_line_spanner_->immutable_property_alist_ == SCM_EOL)
434 p->finished_line_spanner_ = 0;
435 if (p->finished_bracket_p_
436 && p->finished_bracket_p_->immutable_property_alist_ == SCM_EOL)
437 p->finished_bracket_p_ = 0;
440 if (p->name_ == String ("Sustain"))
441 sustain = p->item_p_;
448 if (p->name_ != String ("Sustain"))
452 Side_position_interface::add_support (p->item_p_,sustain);
455 typeset_grob (p->item_p_);
459 if (p->finished_bracket_p_)
462 Grob * l = p->finished_bracket_p_->get_bound (LEFT);
463 Grob * r = p->finished_bracket_p_->get_bound (RIGHT);
466 p->finished_bracket_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
469 typeset_grob (p->finished_bracket_p_);
470 p->finished_bracket_p_ =0;
473 if (p->finished_line_spanner_)
475 Side_position_interface::add_staff_support (p->finished_line_spanner_);
476 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
477 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
479 p->finished_line_spanner_->set_bound (RIGHT, l);
481 p->finished_line_spanner_->set_bound (LEFT, r);
484 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
485 Item * ci = dynamic_cast<Item*> (cc);
486 p->finished_line_spanner_->set_bound (RIGHT, ci);
487 p->finished_line_spanner_->set_bound (LEFT, ci);
489 typeset_grob (p->finished_line_spanner_);
490 p->finished_line_spanner_ = 0;
496 Piano_pedal_engraver::start_translation_timestep ()
498 for (Pedal_info*p = info_list_; p->name_; p ++)
500 p->req_l_drul_[STOP] = 0;
501 p->req_l_drul_[START] = 0;
504 ENTER_DESCRIPTION (Piano_pedal_engraver,
505 /* descr */ "Engrave piano pedal symbols and brackets.",
506 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
507 /* acks */ "note-column-interface",
508 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",