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 Mixed style: Store a pointer to the preceding text for use in
356 calculating the length of the line
359 p->bracket_p_->set_grob_property ("pedal-text", p->item_p_->self_scm ());
361 p->bracket_p_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
362 Axis_group_interface::add_element (p->line_spanner_, p->bracket_p_);
364 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (LEFT));
365 announce_grob (p->bracket_p_, p->req_l_drul_[START]->self_scm ());
367 if (!p->req_l_drul_[STOP])
370 previous_p_[spanner_count_] = p->line_spanner_;
372 if (spanner_count_ > 1)
373 // position new pedal spanner below the current one
374 Side_position_interface::add_support (p->line_spanner_, previous_p_[spanner_count_ - 1]);
378 p->req_l_drul_[START] = 0;
379 p->req_l_drul_[STOP] = 0;
383 Piano_pedal_engraver::finalize ()
385 for (Pedal_info*p = info_list_; p && p->name_; p ++)
391 && !p->line_spanner_->live())
392 p->line_spanner_ = 0;
394 if (p->line_spanner_)
396 p->finished_line_spanner_ = p->line_spanner_;
400 && !p->bracket_p_->live())
404 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
405 p->bracket_p_->suicide ();
413 Piano_pedal_engraver::stop_translation_timestep ()
415 for (Pedal_info*p = info_list_; p && p->name_; p ++)
419 p->finished_line_spanner_ = p->line_spanner_;
420 p->line_spanner_ = 0;
429 Piano_pedal_engraver::typeset_all ()
432 for (Pedal_info*p = info_list_; p->name_; p ++)
437 if (p->finished_line_spanner_
438 && !p->finished_line_spanner_->live ())
439 p->finished_line_spanner_ = 0;
440 if (p->finished_bracket_p_
441 && !p->finished_bracket_p_->live())
442 p->finished_bracket_p_ = 0;
445 if (p->name_ == String ("Sustain"))
446 sustain = p->item_p_;
453 if (p->name_ != String ("Sustain"))
457 Side_position_interface::add_support (p->item_p_,sustain);
460 typeset_grob (p->item_p_);
464 if (p->finished_bracket_p_)
466 Grob * l = p->finished_bracket_p_->get_bound (LEFT);
467 Grob * r = p->finished_bracket_p_->get_bound (RIGHT);
470 p->finished_bracket_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
473 typeset_grob (p->finished_bracket_p_);
474 p->finished_bracket_p_ =0;
477 if (p->finished_line_spanner_)
479 Side_position_interface::add_staff_support (p->finished_line_spanner_);
480 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
481 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
483 p->finished_line_spanner_->set_bound (RIGHT, l);
485 p->finished_line_spanner_->set_bound (LEFT, r);
488 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
489 Item * ci = dynamic_cast<Item*> (cc);
490 p->finished_line_spanner_->set_bound (RIGHT, ci);
491 p->finished_line_spanner_->set_bound (LEFT, ci);
493 typeset_grob (p->finished_line_spanner_);
494 p->finished_line_spanner_ = 0;
500 Piano_pedal_engraver::start_translation_timestep ()
502 for (Pedal_info*p = info_list_; p->name_; p ++)
504 p->req_l_drul_[STOP] = 0;
505 p->req_l_drul_[START] = 0;
508 ENTER_DESCRIPTION (Piano_pedal_engraver,
509 /* descr */ "Engrave piano pedal symbols and brackets.",
510 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
511 /* acks */ "note-column-interface",
512 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",