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 = _f ("expect 3 strings for piano pedals, found: %d",
225 scm_ilength (strings));
227 m->origin ()->warning (msg);
234 if (p->event_drul_[STOP] && p->event_drul_[START])
240 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
244 s = scm_cadr (strings);
246 p->start_ev_ = p->event_drul_[START];
249 else if (p->event_drul_[STOP])
255 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
259 s = scm_caddr (strings);
264 else if (p->event_drul_[START])
266 p->start_ev_ = p->event_drul_[START];
267 s = scm_car (strings);
271 Code dup?! see below.
273 if (previous_.size ())
274 // add extra space below the previous already-occuring pedal
275 Side_position_interface::add_support (p->line_spanner_,
277 previous_.push (p->line_spanner_);
281 if (scm_is_string (s))
283 String propname = String (p->name_) + "Pedal";
285 p->item_ = make_item (propname.to_str0 (), (p->event_drul_[START]
286 ? p->event_drul_[START]
287 : p->event_drul_[STOP])->self_scm ());
289 p->item_->set_property ("text", s);
290 Axis_group_interface::add_element (p->line_spanner_, p->item_);
295 p->event_drul_[START] = 0;
296 p->event_drul_[STOP] = 0;
301 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
303 if (!p->bracket_ && p->event_drul_[STOP])
305 String msg = _f ("can't find start of piano pedal bracket: `%s'", p->name_);
306 p->event_drul_[STOP]->origin ()->warning (msg);
307 p->event_drul_[STOP] = 0;
310 if (p->event_drul_[STOP])
312 assert (!p->finished_bracket_);
314 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
316 if (!p->bracket_->get_bound (RIGHT))
317 p->bracket_->set_bound (RIGHT, cmc);
320 Set properties so that the stencil-creating function will
321 know whether the right edge should be flared ___/
324 if (!p->event_drul_[START])
326 SCM flare = p->bracket_->get_property ("bracket-flare");
327 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
331 p->finished_bracket_ = p->bracket_;
333 p->current_bracket_ev_ = 0;
336 if (p->event_drul_[START])
338 p->start_ev_ = p->event_drul_[START];
339 p->current_bracket_ev_ = p->event_drul_[START];
341 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
344 Set properties so that the stencil-creating function will
345 know whether the left edge should be flared \___
348 if (!p->finished_bracket_)
350 SCM flare = p->bracket_->get_property ("bracket-flare");
351 p->bracket_->set_property ("bracket-flare", scm_cons (scm_make_real (0), scm_cdr (flare)));
354 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
355 so the stencil function will shorten the ____ line by the length of the Ped. text.
361 Mixed style: Store a pointer to the preceding text for use in
362 calculating the length of the line
367 WTF is pedal-text not the bound of the object? --hwn
370 p->bracket_->set_property ("pedal-text", p->item_->self_scm ());
374 We do not use currentMusicalColumn for the left span-point.
375 If the column as accidentals (eg on a different stave), the
376 currentMusicalColumn is too wide, making the bracket too big.
380 Hmm. What do we do when there are no notes when the spanner starts?
384 what about the right span point?
387 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
389 if (!p->event_drul_[STOP])
395 // position new pedal spanner below the current one
397 if (previous_.size ())
398 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
400 previous_.push (p->line_spanner_);
404 p->event_drul_[START] = 0;
405 p->event_drul_[STOP] = 0;
409 Piano_pedal_engraver::finalize ()
411 for (Pedal_info *p = info_list_; p && p->name_; p++)
417 && !p->line_spanner_->is_live ())
418 p->line_spanner_ = 0;
421 && !p->bracket_->is_live ())
426 SCM cc = get_property ("currentCommandColumn");
427 Item *c = unsmob_item (cc);
428 if (p->line_spanner_)
430 p->line_spanner_->set_bound (RIGHT, c);
432 p->bracket_->set_bound (RIGHT, c);
434 p->finished_bracket_ = p->bracket_;
436 p->finished_line_spanner_ = p->line_spanner_;
437 p->line_spanner_ = 0;
441 if (p->line_spanner_)
443 p->finished_line_spanner_ = p->line_spanner_;
450 Piano_pedal_engraver::del_linespanner (Spanner *g)
452 int idx = previous_.find_index (g);
458 Piano_pedal_engraver::stop_translation_timestep ()
460 for (Pedal_info *p = info_list_; p && p->name_; p++)
464 p->finished_line_spanner_ = p->line_spanner_;
465 p->line_spanner_ = 0;
466 del_linespanner (p->finished_line_spanner_);
472 for (Pedal_info *p = info_list_; p->name_; p++)
474 p->event_drul_[STOP] = 0;
475 p->event_drul_[START] = 0;
480 Piano_pedal_engraver::typeset_all (Pedal_info *p)
485 if (p->finished_line_spanner_
486 && !p->finished_line_spanner_->is_live ())
487 p->finished_line_spanner_ = 0;
488 if (p->finished_bracket_
489 && !p->finished_bracket_->is_live ())
490 p->finished_bracket_ = 0;
497 if (p->finished_bracket_)
499 Grob *r = p->finished_bracket_->get_bound (RIGHT);
502 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
505 p->finished_bracket_ = 0;
508 if (p->finished_line_spanner_)
510 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
511 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
513 p->finished_line_spanner_->set_bound (RIGHT, l);
515 p->finished_line_spanner_->set_bound (LEFT, r);
518 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
519 Item *ci = dynamic_cast<Item *> (cc);
520 p->finished_line_spanner_->set_bound (RIGHT, ci);
521 p->finished_line_spanner_->set_bound (LEFT, ci);
524 p->finished_line_spanner_ = 0;
528 ADD_TRANSLATOR (Piano_pedal_engraver,
529 /* descr */ "Engrave piano pedal symbols and brackets.",
530 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
531 /* accepts */ "pedal-event",
532 /* acks */ "note-column-interface",
533 /* reads */ "currentCommandColumn "
534 "pedalSostenutoStrings pedalSustainStrings "
535 "pedalUnaCordaStrings pedalSostenutoStyle "
536 "pedalSustainStyle pedalUnaCordaStyle",