2 piano-pedal-engraver.cc -- implement Piano_pedal_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2005 Jan Nieuwenhuizen <janneke@gnu.org>
8 Chris Jackson <chris@fluffhouse.org.uk> - extended to support
12 #include "engraver.hh"
13 #include "lily-guile.hh"
14 #include "side-position-interface.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "axis-group-interface.hh"
18 #include "directional-element-interface.hh"
19 #include "note-column.hh"
23 Urgh. This engraver is too complex. rewrite. --hwn
31 Event for currently running pedal.
33 Music *current_bracket_ev_;
36 Event for currently starting pedal, (necessary?
38 distinct from current_bracket_ev_, since current_bracket_ev_ only
39 necessary for brackets, not for text style.
44 Events that were found in this timestep.
46 Drul_array<Music *> event_drul_;
48 Spanner *bracket_; // A single portion of a pedal bracket
49 Spanner *finished_bracket_;
52 This grob contains all the pedals of the same type on the same staff
54 Spanner *line_spanner_;
55 Spanner *finished_line_spanner_;
58 class Piano_pedal_engraver : public Engraver
61 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
62 ~Piano_pedal_engraver ();
64 virtual void initialize ();
65 virtual void finalize ();
66 virtual bool try_music (Music *);
67 virtual void stop_translation_timestep ();
68 virtual void acknowledge_grob (Grob_info);
69 virtual void process_music ();
73 Pedal_info *info_list_;
76 Record a stack of the current pedal spanners, so if more than one pedal
77 occurs simultaneously then extra space can be added between them.
80 Link_array<Spanner> previous_;
81 void del_linespanner (Spanner *);
83 void create_text_grobs (Pedal_info *p, bool);
84 void create_bracket_grobs (Pedal_info *p, bool);
85 void typeset_all (Pedal_info *p);
88 Piano_pedal_engraver::Piano_pedal_engraver ()
94 Piano_pedal_engraver::initialize ()
96 char *names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
98 info_list_ = new Pedal_info[sizeof (names) / sizeof (const char *)];
99 Pedal_info *p = info_list_;
107 p->finished_bracket_ = 0;
108 p->line_spanner_ = 0;
109 p->finished_line_spanner_ = 0;
110 p->current_bracket_ev_ = 0;
111 p->event_drul_[START] = 0;
112 p->event_drul_[STOP] = 0;
120 Piano_pedal_engraver::~Piano_pedal_engraver ()
130 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
132 for (Pedal_info *p = info_list_; p && p->name_; p++)
134 if (Note_column::has_interface (info.grob_))
136 if (p->line_spanner_)
138 Side_position_interface::add_support (p->line_spanner_, info.grob_);
139 add_bound_item (p->line_spanner_, info.grob_);
142 add_bound_item (p->bracket_, info.grob_);
143 if (p->finished_bracket_)
144 add_bound_item (p->finished_bracket_, info.grob_);
150 Piano_pedal_engraver::try_music (Music *m)
152 if (m->is_mus_type ("pedal-event"))
154 for (Pedal_info *p = info_list_; p->name_; p++)
156 String nm = p->name_ + String ("Event");
157 if (ly_c_equal_p (m->get_property ("name"),
158 scm_str2symbol (nm.to_str0 ())))
160 Direction d = to_dir (m->get_property ("span-direction"));
161 p->event_drul_[d] = m;
170 Piano_pedal_engraver::process_music ()
172 for (Pedal_info *p = info_list_; p && p->name_; p++)
174 if (p->event_drul_[STOP] || p->event_drul_[START])
176 if (!p->line_spanner_)
178 String name = String (p->name_) + "PedalLineSpanner";
179 Music *rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
180 p->line_spanner_ = make_spanner (name.to_str0 (), rq->self_scm ());
183 /* Choose the appropriate grobs to add to the line spanner
184 These can be text items or text-spanners
188 ugh, code dup, should read grob to create from other
191 bracket: |_________/\____|
193 mixed: Ped. _____/\____|
196 String prop = String ("pedal") + p->name_ + "Style";
197 SCM style = get_property (prop.to_str0 ());
199 bool mixed = style == ly_symbol2scm ("mixed");
200 bool bracket = (mixed
201 || style == ly_symbol2scm ("bracket"));
202 bool text = (style == ly_symbol2scm ("text")
205 if (text && !p->item_)
206 create_text_grobs (p, mixed);
208 create_bracket_grobs (p, mixed);
214 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
217 SCM strings = get_property (("pedal" + String (p->name_) + "Strings").to_str0 ());
219 if (scm_ilength (strings) < 3)
221 Music *m = p->event_drul_[START];
222 if (!m) m = p->event_drul_ [STOP];
224 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
226 m->origin ()->warning (msg);
233 if (p->event_drul_[STOP] && p->event_drul_[START])
239 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
243 s = scm_cadr (strings);
245 p->start_ev_ = p->event_drul_[START];
248 else if (p->event_drul_[STOP])
254 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
258 s = scm_caddr (strings);
263 else if (p->event_drul_[START])
265 p->start_ev_ = p->event_drul_[START];
266 s = scm_car (strings);
270 Code dup?! see below.
272 if (previous_.size ())
273 // add extra space below the previous already-occuring pedal
274 Side_position_interface::add_support (p->line_spanner_,
276 previous_.push (p->line_spanner_);
280 if (scm_is_string (s))
282 String propname = String (p->name_) + "Pedal";
284 p->item_ = make_item (propname.to_str0 (), (p->event_drul_[START]
285 ? p->event_drul_[START]
286 : p->event_drul_[STOP])->self_scm ());
288 p->item_->set_property ("text", s);
289 Axis_group_interface::add_element (p->line_spanner_, p->item_);
294 p->event_drul_[START] = 0;
295 p->event_drul_[STOP] = 0;
300 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
302 if (!p->bracket_ && p->event_drul_[STOP])
304 String msg = _f ("can't find start of piano pedal bracket: `%s'", p->name_);
305 p->event_drul_[STOP]->origin ()->warning (msg);
306 p->event_drul_[STOP] = 0;
309 if (p->event_drul_[STOP])
311 assert (!p->finished_bracket_);
313 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
315 if (!p->bracket_->get_bound (RIGHT))
316 p->bracket_->set_bound (RIGHT, cmc);
319 Set properties so that the stencil-creating function will
320 know whether the right edge should be flared ___/
323 if (!p->event_drul_[START])
325 SCM flare = p->bracket_->get_property ("bracket-flare");
326 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
330 p->finished_bracket_ = p->bracket_;
332 p->current_bracket_ev_ = 0;
335 if (p->event_drul_[START])
337 p->start_ev_ = p->event_drul_[START];
338 p->current_bracket_ev_ = p->event_drul_[START];
340 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
343 Set properties so that the stencil-creating function will
344 know whether the left edge should be flared \___
347 if (!p->finished_bracket_)
349 SCM flare = p->bracket_->get_property ("bracket-flare");
350 p->bracket_->set_property ("bracket-flare", scm_cons (scm_make_real (0), scm_cdr (flare)));
353 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
354 so the stencil function will shorten the ____ line by the length of the Ped. text.
360 Mixed style: Store a pointer to the preceding text for use in
361 calculating the length of the line
366 WTF is pedal-text not the bound of the object? --hwn
369 p->bracket_->set_property ("pedal-text", p->item_->self_scm ());
373 We do not use currentMusicalColumn for the left span-point.
374 If the column as accidentals (eg on a different stave), the
375 currentMusicalColumn is too wide, making the bracket too big.
379 Hmm. What do we do when there are no notes when the spanner starts?
383 what about the right span point?
386 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
388 if (!p->event_drul_[STOP])
394 // position new pedal spanner below the current one
396 if (previous_.size ())
397 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
399 previous_.push (p->line_spanner_);
403 p->event_drul_[START] = 0;
404 p->event_drul_[STOP] = 0;
408 Piano_pedal_engraver::finalize ()
410 for (Pedal_info *p = info_list_; p && p->name_; p++)
416 && !p->line_spanner_->is_live ())
417 p->line_spanner_ = 0;
420 && !p->bracket_->is_live ())
425 SCM cc = get_property ("currentCommandColumn");
426 Item *c = unsmob_item (cc);
427 if (p->line_spanner_)
429 p->line_spanner_->set_bound (RIGHT, c);
431 p->bracket_->set_bound (RIGHT, c);
433 p->finished_bracket_ = p->bracket_;
435 p->finished_line_spanner_ = p->line_spanner_;
436 p->line_spanner_ = 0;
440 if (p->line_spanner_)
442 p->finished_line_spanner_ = p->line_spanner_;
449 Piano_pedal_engraver::del_linespanner (Spanner *g)
451 int idx = previous_.find_index (g);
457 Piano_pedal_engraver::stop_translation_timestep ()
459 for (Pedal_info *p = info_list_; p && p->name_; p++)
463 p->finished_line_spanner_ = p->line_spanner_;
464 p->line_spanner_ = 0;
465 del_linespanner (p->finished_line_spanner_);
471 for (Pedal_info *p = info_list_; p->name_; p++)
473 p->event_drul_[STOP] = 0;
474 p->event_drul_[START] = 0;
479 Piano_pedal_engraver::typeset_all (Pedal_info *p)
484 if (p->finished_line_spanner_
485 && !p->finished_line_spanner_->is_live ())
486 p->finished_line_spanner_ = 0;
487 if (p->finished_bracket_
488 && !p->finished_bracket_->is_live ())
489 p->finished_bracket_ = 0;
496 if (p->finished_bracket_)
498 Grob *r = p->finished_bracket_->get_bound (RIGHT);
501 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
504 p->finished_bracket_ = 0;
507 if (p->finished_line_spanner_)
509 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
510 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
512 p->finished_line_spanner_->set_bound (RIGHT, l);
514 p->finished_line_spanner_->set_bound (LEFT, r);
517 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
518 Item *ci = dynamic_cast<Item *> (cc);
519 p->finished_line_spanner_->set_bound (RIGHT, ci);
520 p->finished_line_spanner_->set_bound (LEFT, ci);
523 p->finished_line_spanner_ = 0;
527 ADD_TRANSLATOR (Piano_pedal_engraver,
528 /* descr */ "Engrave piano pedal symbols and brackets.",
529 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
530 /* accepts */ "pedal-event",
531 /* acks */ "note-column-interface",
532 /* reads */ "currentCommandColumn "
533 "pedalSostenutoStrings pedalSustainStrings "
534 "pedalUnaCordaStrings pedalSostenutoStyle "
535 "pedalSustainStyle pedalUnaCordaStyle",