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 void stop_translation_timestep ();
68 DECLARE_ACKNOWLEDGER (note_column);
69 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 (char const *)];
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_note_column (Grob_info info)
132 for (Pedal_info *p = info_list_; p && p->name_; p++)
134 if (p->line_spanner_)
136 Side_position_interface::add_support (p->line_spanner_, info.grob ());
137 add_bound_item (p->line_spanner_, info.grob ());
140 add_bound_item (p->bracket_, info.grob ());
141 if (p->finished_bracket_)
142 add_bound_item (p->finished_bracket_, info.grob ());
147 Piano_pedal_engraver::try_music (Music *m)
149 if (m->is_mus_type ("pedal-event"))
151 for (Pedal_info *p = info_list_; p->name_; p++)
153 String nm = p->name_ + String ("Event");
154 if (ly_is_equal (m->get_property ("name"),
155 scm_str2symbol (nm.to_str0 ())))
157 Direction d = to_dir (m->get_property ("span-direction"));
158 p->event_drul_[d] = m;
167 Piano_pedal_engraver::process_music ()
169 for (Pedal_info *p = info_list_; p && p->name_; p++)
171 if (p->event_drul_[STOP] || p->event_drul_[START])
173 if (!p->line_spanner_)
175 String name = String (p->name_) + "PedalLineSpanner";
176 Music *rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
177 p->line_spanner_ = make_spanner (name.to_str0 (), rq->self_scm ());
180 /* Choose the appropriate grobs to add to the line spanner
181 These can be text items or text-spanners
185 ugh, code dup, should read grob to create from other
188 bracket: |_________/\____|
190 mixed: Ped. _____/\____|
193 String prop = String ("pedal") + p->name_ + "Style";
194 SCM style = get_property (prop.to_str0 ());
196 bool mixed = style == ly_symbol2scm ("mixed");
197 bool bracket = (mixed
198 || style == ly_symbol2scm ("bracket"));
199 bool text = (style == ly_symbol2scm ("text")
202 if (text && !p->item_)
203 create_text_grobs (p, mixed);
205 create_bracket_grobs (p, mixed);
211 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
214 SCM strings = get_property (("pedal" + String (p->name_) + "Strings").to_str0 ());
216 if (scm_ilength (strings) < 3)
218 Music *m = p->event_drul_[START];
219 if (!m) m = p->event_drul_ [STOP];
221 String msg = _f ("expect 3 strings for piano pedals, found: %d",
222 scm_ilength (strings));
224 m->origin ()->warning (msg);
231 if (p->event_drul_[STOP] && p->event_drul_[START])
236 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
238 s = scm_cadr (strings);
239 p->start_ev_ = p->event_drul_[START];
242 else if (p->event_drul_[STOP])
247 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
249 s = scm_caddr (strings);
253 else if (p->event_drul_[START])
255 p->start_ev_ = p->event_drul_[START];
256 s = scm_car (strings);
260 Code dup?! see below.
262 if (previous_.size ())
263 // add extra space below the previous already-occuring pedal
264 Side_position_interface::add_support (p->line_spanner_,
266 previous_.push (p->line_spanner_);
270 if (scm_is_string (s))
272 String propname = String (p->name_) + "Pedal";
274 p->item_ = make_item (propname.to_str0 (), (p->event_drul_[START]
275 ? p->event_drul_[START]
276 : p->event_drul_[STOP])->self_scm ());
278 p->item_->set_property ("text", s);
279 Axis_group_interface::add_element (p->line_spanner_, p->item_);
284 p->event_drul_[START] = 0;
285 p->event_drul_[STOP] = 0;
290 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
292 if (!p->bracket_ && p->event_drul_[STOP])
294 String msg = _f ("can't find start of piano pedal bracket: `%s'", p->name_);
295 p->event_drul_[STOP]->origin ()->warning (msg);
296 p->event_drul_[STOP] = 0;
299 if (p->event_drul_[STOP])
301 assert (!p->finished_bracket_);
303 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
305 if (!p->bracket_->get_bound (RIGHT))
306 p->bracket_->set_bound (RIGHT, cmc);
309 Set properties so that the stencil-creating function will
310 know whether the right edge should be flared ___/
313 if (!p->event_drul_[START])
315 SCM flare = p->bracket_->get_property ("bracket-flare");
316 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
317 scm_from_double (0)));
320 p->finished_bracket_ = p->bracket_;
322 p->current_bracket_ev_ = 0;
325 if (p->event_drul_[START])
327 p->start_ev_ = p->event_drul_[START];
328 p->current_bracket_ev_ = p->event_drul_[START];
330 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
333 Set properties so that the stencil-creating function will
334 know whether the left edge should be flared \___
337 if (!p->finished_bracket_)
339 SCM flare = p->bracket_->get_property ("bracket-flare");
340 p->bracket_->set_property ("bracket-flare", scm_cons (scm_from_double (0), scm_cdr (flare)));
343 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
344 so the stencil function will shorten the ____ line by the length of the Ped. text.
350 Mixed style: Store a pointer to the preceding text for use in
351 calculating the length of the line
356 WTF is pedal-text not the bound of the object? --hwn
359 p->bracket_->set_object ("pedal-text", p->item_->self_scm ());
363 We do not use currentMusicalColumn for the left span-point.
364 If the column as accidentals (eg on a different stave), the
365 currentMusicalColumn is too wide, making the bracket too big.
369 Hmm. What do we do when there are no notes when the spanner starts?
373 what about the right span point?
376 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
378 if (!p->event_drul_[STOP])
384 // position new pedal spanner below the current one
386 if (previous_.size ())
387 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
389 previous_.push (p->line_spanner_);
393 p->event_drul_[START] = 0;
394 p->event_drul_[STOP] = 0;
398 Piano_pedal_engraver::finalize ()
400 for (Pedal_info *p = info_list_; p && p->name_; p++)
406 && !p->line_spanner_->is_live ())
407 p->line_spanner_ = 0;
410 && !p->bracket_->is_live ())
415 SCM cc = get_property ("currentCommandColumn");
416 Item *c = unsmob_item (cc);
417 if (p->line_spanner_)
418 p->line_spanner_->set_bound (RIGHT, c);
419 p->bracket_->set_bound (RIGHT, c);
421 p->finished_bracket_ = p->bracket_;
423 p->finished_line_spanner_ = p->line_spanner_;
424 p->line_spanner_ = 0;
428 if (p->line_spanner_)
430 p->finished_line_spanner_ = p->line_spanner_;
437 Piano_pedal_engraver::del_linespanner (Spanner *g)
439 int idx = previous_.find_index (g);
445 Piano_pedal_engraver::stop_translation_timestep ()
447 for (Pedal_info *p = info_list_; p && p->name_; p++)
451 p->finished_line_spanner_ = p->line_spanner_;
452 p->line_spanner_ = 0;
453 del_linespanner (p->finished_line_spanner_);
459 for (Pedal_info *p = info_list_; p->name_; p++)
461 p->event_drul_[STOP] = 0;
462 p->event_drul_[START] = 0;
467 Piano_pedal_engraver::typeset_all (Pedal_info *p)
472 if (p->finished_line_spanner_
473 && !p->finished_line_spanner_->is_live ())
474 p->finished_line_spanner_ = 0;
475 if (p->finished_bracket_
476 && !p->finished_bracket_->is_live ())
477 p->finished_bracket_ = 0;
482 if (p->finished_bracket_)
484 Grob *r = p->finished_bracket_->get_bound (RIGHT);
486 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
488 p->finished_bracket_ = 0;
491 if (p->finished_line_spanner_)
493 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
494 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
496 p->finished_line_spanner_->set_bound (RIGHT, l);
498 p->finished_line_spanner_->set_bound (LEFT, r);
501 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
502 Item *ci = dynamic_cast<Item *> (cc);
503 p->finished_line_spanner_->set_bound (RIGHT, ci);
504 p->finished_line_spanner_->set_bound (LEFT, ci);
507 p->finished_line_spanner_ = 0;
511 #include "translator.icc"
512 ADD_ACKNOWLEDGER (Piano_pedal_engraver, note_column);
513 ADD_TRANSLATOR (Piano_pedal_engraver,
514 /* doc */ "Engrave piano pedal symbols and brackets.",
515 /* create */ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
516 /* accept */ "pedal-event",
517 /* read */ "currentCommandColumn "
518 "pedalSostenutoStrings "
519 "pedalSustainStrings "
520 "pedalUnaCordaStrings "
521 "pedalSostenutoStyle "
523 "pedalUnaCordaStyle",