2 piano-pedal-engraver.cc -- implement Piano_pedal_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2006 Jan Nieuwenhuizen <janneke@gnu.org>
8 Chris Jackson <chris@fluffhouse.org.uk> - extended to support
12 #include "engraver.hh"
14 #include "axis-group-interface.hh"
16 #include "directional-element-interface.hh"
17 #include "international.hh"
18 #include "lily-guile.hh"
19 #include "note-column.hh"
20 #include "side-position-interface.hh"
21 #include "staff-symbol-referencer.hh"
25 Urgh. This engraver is too complex. rewrite. --hwn
33 Event for currently running pedal.
35 Music *current_bracket_ev_;
38 Event for currently starting pedal, (necessary?
40 distinct from current_bracket_ev_, since current_bracket_ev_ only
41 necessary for brackets, not for text style.
46 Events that were found in this timestep.
48 Drul_array<Music *> event_drul_;
50 Spanner *bracket_; // A single portion of a pedal bracket
51 Spanner *finished_bracket_;
54 This grob contains all the pedals of the same type on the same staff
56 Spanner *line_spanner_;
57 Spanner *finished_line_spanner_;
60 class Piano_pedal_engraver : public Engraver
63 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
64 ~Piano_pedal_engraver ();
66 virtual void initialize ();
67 virtual void finalize ();
68 virtual bool try_music (Music *);
69 void stop_translation_timestep ();
70 DECLARE_ACKNOWLEDGER (note_column);
71 void process_music ();
75 Pedal_info *info_list_;
78 Record a stack of the current pedal spanners, so if more than one pedal
79 occurs simultaneously then extra space can be added between them.
82 vector<Spanner*> previous_;
83 void del_linespanner (Spanner *);
85 void create_text_grobs (Pedal_info *p, bool);
86 void create_bracket_grobs (Pedal_info *p, bool);
87 void typeset_all (Pedal_info *p);
90 Piano_pedal_engraver::Piano_pedal_engraver ()
96 Piano_pedal_engraver::initialize ()
98 char *names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
100 info_list_ = new Pedal_info[sizeof (names) / sizeof (char const *)];
101 Pedal_info *p = info_list_;
109 p->finished_bracket_ = 0;
110 p->line_spanner_ = 0;
111 p->finished_line_spanner_ = 0;
112 p->current_bracket_ev_ = 0;
113 p->event_drul_[START] = 0;
114 p->event_drul_[STOP] = 0;
122 Piano_pedal_engraver::~Piano_pedal_engraver ()
132 Piano_pedal_engraver::acknowledge_note_column (Grob_info info)
134 for (Pedal_info *p = info_list_; p && p->name_; p++)
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 ());
149 Piano_pedal_engraver::try_music (Music *m)
151 if (m->is_mus_type ("pedal-event"))
153 for (Pedal_info *p = info_list_; p->name_; p++)
155 string nm = p->name_ + string ("Event");
156 if (ly_is_equal (m->get_property ("name"),
157 scm_str2symbol (nm.c_str ())))
159 Direction d = to_dir (m->get_property ("span-direction"));
160 p->event_drul_[d] = m;
169 Piano_pedal_engraver::process_music ()
171 for (Pedal_info *p = info_list_; p && p->name_; p++)
173 if (p->event_drul_[STOP] || p->event_drul_[START])
175 if (!p->line_spanner_)
177 string name = string (p->name_) + "PedalLineSpanner";
178 Music *rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
179 p->line_spanner_ = make_spanner (name.c_str (), rq->self_scm ());
182 /* Choose the appropriate grobs to add to the line spanner
183 These can be text items or text-spanners
187 ugh, code dup, should read grob to create from other
190 bracket: |_________/\____|
192 mixed: Ped. _____/\____|
195 string prop = string ("pedal") + p->name_ + "Style";
196 SCM style = get_property (prop.c_str ());
198 bool mixed = style == ly_symbol2scm ("mixed");
199 bool bracket = (mixed
200 || style == ly_symbol2scm ("bracket"));
201 bool text = (style == ly_symbol2scm ("text")
204 if (text && !p->item_)
205 create_text_grobs (p, mixed);
207 create_bracket_grobs (p, mixed);
213 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
216 SCM strings = get_property (("pedal" + string (p->name_) + "Strings").c_str ());
218 if (scm_ilength (strings) < 3)
220 Music *m = p->event_drul_[START];
221 if (!m) m = p->event_drul_ [STOP];
223 string msg = _f ("expect 3 strings for piano pedals, found: %ld",
224 scm_ilength (strings));
226 m->origin ()->warning (msg);
233 if (p->event_drul_[STOP] && p->event_drul_[START])
238 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
240 s = scm_cadr (strings);
241 p->start_ev_ = p->event_drul_[START];
244 else if (p->event_drul_[STOP])
249 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
251 s = scm_caddr (strings);
255 else if (p->event_drul_[START])
257 p->start_ev_ = p->event_drul_[START];
258 s = scm_car (strings);
262 Code dup?! see below.
264 if (previous_.size ())
265 // add extra space below the previous already-occuring pedal
266 Side_position_interface::add_support (p->line_spanner_,
268 previous_.push_back (p->line_spanner_);
272 if (scm_is_string (s))
274 string propname = string (p->name_) + "Pedal";
276 p->item_ = make_item (propname.c_str (), (p->event_drul_[START]
277 ? p->event_drul_[START]
278 : p->event_drul_[STOP])->self_scm ());
280 p->item_->set_property ("text", s);
281 Axis_group_interface::add_element (p->line_spanner_, p->item_);
286 p->event_drul_[START] = 0;
287 p->event_drul_[STOP] = 0;
292 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
294 if (!p->bracket_ && p->event_drul_[STOP])
296 string msg = _f ("can't find start of piano pedal bracket: `%s'", p->name_);
297 p->event_drul_[STOP]->origin ()->warning (msg);
298 p->event_drul_[STOP] = 0;
301 if (p->event_drul_[STOP])
303 assert (!p->finished_bracket_);
305 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
307 if (!p->bracket_->get_bound (RIGHT))
308 p->bracket_->set_bound (RIGHT, cmc);
311 Set properties so that the stencil-creating function will
312 know whether the right edge should be flared ___/
315 if (!p->event_drul_[START])
317 SCM flare = p->bracket_->get_property ("bracket-flare");
318 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
319 scm_from_double (0)));
322 p->finished_bracket_ = p->bracket_;
324 p->current_bracket_ev_ = 0;
327 if (p->event_drul_[START])
329 p->start_ev_ = p->event_drul_[START];
330 p->current_bracket_ev_ = p->event_drul_[START];
332 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
335 Set properties so that the stencil-creating function will
336 know whether the left edge should be flared \___
339 if (!p->finished_bracket_)
341 SCM flare = p->bracket_->get_property ("bracket-flare");
342 p->bracket_->set_property ("bracket-flare", scm_cons (scm_from_double (0), scm_cdr (flare)));
345 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
346 so the stencil function will shorten the ____ line by the length of the Ped. text.
352 Mixed style: Store a pointer to the preceding text for use in
353 calculating the length of the line
358 WTF is pedal-text not the bound of the object? --hwn
361 p->bracket_->set_object ("pedal-text", p->item_->self_scm ());
365 We do not use currentMusicalColumn for the left span-point.
366 If the column as accidentals (eg on a different stave), the
367 currentMusicalColumn is too wide, making the bracket too big.
371 Hmm. What do we do when there are no notes when the spanner starts?
375 what about the right span point?
378 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
380 if (!p->event_drul_[STOP])
386 // position new pedal spanner below the current one
388 if (previous_.size ())
389 Side_position_interface::add_support (p->line_spanner_, previous_.back ());
391 previous_.push_back (p->line_spanner_);
395 p->event_drul_[START] = 0;
396 p->event_drul_[STOP] = 0;
400 Piano_pedal_engraver::finalize ()
402 for (Pedal_info *p = info_list_; p && p->name_; p++)
408 && !p->line_spanner_->is_live ())
409 p->line_spanner_ = 0;
412 && !p->bracket_->is_live ())
417 SCM cc = get_property ("currentCommandColumn");
418 Item *c = unsmob_item (cc);
419 if (p->line_spanner_)
420 p->line_spanner_->set_bound (RIGHT, c);
421 p->bracket_->set_bound (RIGHT, c);
423 p->finished_bracket_ = p->bracket_;
425 p->finished_line_spanner_ = p->line_spanner_;
426 p->line_spanner_ = 0;
430 if (p->line_spanner_)
432 p->finished_line_spanner_ = p->line_spanner_;
439 Piano_pedal_engraver::del_linespanner (Spanner *g)
441 vsize idx = find (previous_, g) - previous_.begin ();
442 if (idx != VPOS && idx < previous_.size ())
443 previous_.erase (previous_.begin () + idx);
447 Piano_pedal_engraver::stop_translation_timestep ()
449 for (Pedal_info *p = info_list_; p && p->name_; p++)
453 p->finished_line_spanner_ = p->line_spanner_;
454 p->line_spanner_ = 0;
455 del_linespanner (p->finished_line_spanner_);
461 for (Pedal_info *p = info_list_; p->name_; p++)
463 p->event_drul_[STOP] = 0;
464 p->event_drul_[START] = 0;
469 Piano_pedal_engraver::typeset_all (Pedal_info *p)
474 if (p->finished_line_spanner_
475 && !p->finished_line_spanner_->is_live ())
476 p->finished_line_spanner_ = 0;
477 if (p->finished_bracket_
478 && !p->finished_bracket_->is_live ())
479 p->finished_bracket_ = 0;
484 if (p->finished_bracket_)
486 Grob *r = p->finished_bracket_->get_bound (RIGHT);
488 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
490 p->finished_bracket_ = 0;
493 if (p->finished_line_spanner_)
495 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
496 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
498 p->finished_line_spanner_->set_bound (RIGHT, l);
500 p->finished_line_spanner_->set_bound (LEFT, r);
503 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
504 Item *ci = dynamic_cast<Item *> (cc);
505 p->finished_line_spanner_->set_bound (RIGHT, ci);
506 p->finished_line_spanner_->set_bound (LEFT, ci);
509 p->finished_line_spanner_ = 0;
513 #include "translator.icc"
515 ADD_ACKNOWLEDGER (Piano_pedal_engraver, note_column);
517 ADD_TRANSLATOR (Piano_pedal_engraver,
520 "Engrave piano pedal symbols and brackets.",
524 "SostenutoPedalLineSpanner "
526 "SustainPedalLineSpanner "
528 "UnaCordaPedalLineSpanner ",
534 "currentCommandColumn "
535 "pedalSostenutoStrings "
536 "pedalSostenutoStyle "
537 "pedalSustainStrings "
539 "pedalUnaCordaStrings "
540 "pedalUnaCordaStyle",