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"
29 Drul_array<Span_req*> req_l_drul_;
31 Spanner* bracket_; // A single portion of a pedal bracket
32 Spanner* finished_bracket_;
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_ [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_ = 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_))
137 if (p->line_spanner_)
139 Side_position_interface::add_support (p->line_spanner_, info.grob_);
141 add_bound_item (p->line_spanner_,info.grob_);
144 add_bound_item (p->bracket_,info.grob_);
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_->suicide (); /* as in dynamic-engraver.cc */
166 if (scm_equal_p (s->get_mus_property ("span-type"),
167 scm_makfrom0str (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.to_str0 ()));
190 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
191 announce_grob (p->line_spanner_, rq->self_scm ());
194 /* Choose the appropriate grobs to add to the line spanner
195 These can be text items or text-spanners
197 SCM type = ly_cdr (scm_assoc (ly_symbol2scm ("pedal-type"),
198 get_property ( (String (p->name_) + "Pedal").to_str0 ())));
199 if (type == ly_symbol2scm ("text") || // Ped. *Ped. *
200 type == ly_symbol2scm ("mixed") ) // Ped. _____/\____|
203 create_text_grobs (p, type);
205 if (type == ly_symbol2scm ("bracket") || // |_________/\____|
206 type == ly_symbol2scm ("mixed") )
208 create_bracket_grobs (p, type);
216 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
220 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
222 if (scm_ilength (strings) >= 3)
224 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
226 if (pedaltype == ly_symbol2scm ("text"))
230 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
234 s = ly_cadr (strings);
236 p->start_req_ = p->req_l_drul_[START];
239 else if (p->req_l_drul_[STOP])
241 if (pedaltype == ly_symbol2scm ("text"))
245 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
249 s = ly_caddr (strings);
255 else if (p->req_l_drul_[START])
257 p->start_req_ = p->req_l_drul_[START];
258 s = ly_car (strings);
259 if (pedaltype == ly_symbol2scm ("text"))
262 previous_[spanner_count_] = p->line_spanner_;
263 if (spanner_count_ > 1)
264 // add extra space below the previous already-occuring pedal
265 Side_position_interface::add_support (p->line_spanner_,
266 previous_[spanner_count_ - 1]);
272 String propname = String (p->name_) + "Pedal";
273 b = get_property (propname.to_str0 ());
274 p->item_ = new Item (b);
275 p->item_->set_grob_property ("text", s);
276 Axis_group_interface::add_element (p->line_spanner_, p->item_);
278 announce_grob (p->item_,
279 (p->req_l_drul_[START]
280 ? p->req_l_drul_[START]
281 : p->req_l_drul_[STOP])->self_scm ());
284 if (pedaltype == ly_symbol2scm ("text"))
286 p->req_l_drul_[START] = 0;
287 p->req_l_drul_[STOP] = 0;
293 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
296 if (p->req_l_drul_[STOP])
300 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
302 else if (!p->req_l_drul_[START])
305 assert (!p->finished_bracket_ && p->bracket_);
307 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
308 p->bracket_->set_bound (RIGHT, cmc);
311 Set properties so that the molecule-creating function will
312 know whether the right edge should be flared ___/
314 SCM eleft = ly_car (p->bracket_->get_grob_property ("edge-widen"));
315 SCM eright = (p->req_l_drul_[START] ? edge_width_drul_[RIGHT] : gh_double2scm (0));
316 p->bracket_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
318 p->finished_bracket_ = p->bracket_;
320 p->current_bracket_req_ = 0;
321 p->start_req_ = p->req_l_drul_[START];
324 if (p->req_l_drul_[START])
326 p->start_req_ = p->req_l_drul_[START];
327 p->current_bracket_req_ = p->req_l_drul_[START];
329 p->bracket_ = new Spanner (get_property ("PianoPedalBracket"));
332 Set properties so that the molecule-creating function will
333 know whether the left edge should be flared \___
336 SCM ew = p->bracket_->get_grob_property ("edge-widen");
337 edge_width_drul_[LEFT] = ly_car (ew);
338 edge_width_drul_[RIGHT] = ly_cdr (ew);
340 SCM eleft = ( (bool) p->req_l_drul_[STOP] ?
341 edge_width_drul_[LEFT] :
343 SCM eright = gh_double2scm (0);
344 p->bracket_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
346 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
347 so the molecule function will shorten the ____ line by the length of the Ped. text.
350 p->bracket_->set_grob_property ("text-start",
351 pedaltype == ly_symbol2scm ("mixed") ?
352 gh_bool2scm ( (bool) ! p->req_l_drul_[STOP]) :
353 gh_bool2scm (false));
356 Mixed style: Store a pointer to the preceding text for use in
357 calculating the length of the line
360 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
362 p->bracket_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
363 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
365 add_bound_item (p->line_spanner_, p->bracket_->get_bound (LEFT));
366 announce_grob (p->bracket_, p->req_l_drul_[START]->self_scm ());
368 if (!p->req_l_drul_[STOP])
371 previous_[spanner_count_] = p->line_spanner_;
373 if (spanner_count_ > 1)
374 // position new pedal spanner below the current one
375 Side_position_interface::add_support (p->line_spanner_, previous_[spanner_count_ - 1]);
379 p->req_l_drul_[START] = 0;
380 p->req_l_drul_[STOP] = 0;
384 Piano_pedal_engraver::finalize ()
386 for (Pedal_info*p = info_list_; p && p->name_; p ++)
392 && !p->line_spanner_->live())
393 p->line_spanner_ = 0;
395 if (p->line_spanner_)
397 p->finished_line_spanner_ = p->line_spanner_;
401 && !p->bracket_->live())
405 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
406 p->bracket_->suicide ();
414 Piano_pedal_engraver::stop_translation_timestep ()
416 for (Pedal_info*p = info_list_; p && p->name_; p ++)
420 p->finished_line_spanner_ = p->line_spanner_;
421 p->line_spanner_ = 0;
430 Piano_pedal_engraver::typeset_all ()
433 for (Pedal_info*p = info_list_; p->name_; p ++)
438 if (p->finished_line_spanner_
439 && !p->finished_line_spanner_->live ())
440 p->finished_line_spanner_ = 0;
441 if (p->finished_bracket_
442 && !p->finished_bracket_->live())
443 p->finished_bracket_ = 0;
446 if (p->name_ == String ("Sustain"))
454 if (p->name_ != String ("Sustain"))
458 Side_position_interface::add_support (p->item_,sustain);
461 typeset_grob (p->item_);
465 if (p->finished_bracket_)
467 Grob * l = p->finished_bracket_->get_bound (LEFT);
468 Grob * r = p->finished_bracket_->get_bound (RIGHT);
471 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
474 typeset_grob (p->finished_bracket_);
475 p->finished_bracket_ =0;
478 if (p->finished_line_spanner_)
480 Side_position_interface::add_staff_support (p->finished_line_spanner_);
481 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
482 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
484 p->finished_line_spanner_->set_bound (RIGHT, l);
486 p->finished_line_spanner_->set_bound (LEFT, r);
489 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
490 Item * ci = dynamic_cast<Item*> (cc);
491 p->finished_line_spanner_->set_bound (RIGHT, ci);
492 p->finished_line_spanner_->set_bound (LEFT, ci);
494 typeset_grob (p->finished_line_spanner_);
495 p->finished_line_spanner_ = 0;
501 Piano_pedal_engraver::start_translation_timestep ()
503 for (Pedal_info*p = info_list_; p->name_; p ++)
505 p->req_l_drul_[STOP] = 0;
506 p->req_l_drul_[START] = 0;
509 ENTER_DESCRIPTION (Piano_pedal_engraver,
510 /* descr */ "Engrave piano pedal symbols and brackets.",
511 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
512 /* acks */ "note-column-interface",
513 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",