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])
237 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])
250 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
253 s = scm_caddr (strings);
257 else if (p->event_drul_[START])
259 p->start_ev_ = p->event_drul_[START];
260 s = scm_car (strings);
264 Code dup?! see below.
266 if (previous_.size ())
267 // add extra space below the previous already-occuring pedal
268 Side_position_interface::add_support (p->line_spanner_,
270 previous_.push (p->line_spanner_);
274 if (scm_is_string (s))
276 String propname = String (p->name_) + "Pedal";
278 p->item_ = make_item (propname.to_str0 (), (p->event_drul_[START]
279 ? p->event_drul_[START]
280 : p->event_drul_[STOP])->self_scm ());
282 p->item_->set_property ("text", s);
283 Axis_group_interface::add_element (p->line_spanner_, p->item_);
288 p->event_drul_[START] = 0;
289 p->event_drul_[STOP] = 0;
294 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
296 if (!p->bracket_ && p->event_drul_[STOP])
298 String msg = _f ("can't find start of piano pedal bracket: `%s'", p->name_);
299 p->event_drul_[STOP]->origin ()->warning (msg);
300 p->event_drul_[STOP] = 0;
303 if (p->event_drul_[STOP])
305 assert (!p->finished_bracket_);
307 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
309 if (!p->bracket_->get_bound (RIGHT))
310 p->bracket_->set_bound (RIGHT, cmc);
313 Set properties so that the stencil-creating function will
314 know whether the right edge should be flared ___/
317 if (!p->event_drul_[START])
319 SCM flare = p->bracket_->get_property ("bracket-flare");
320 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
321 scm_from_double (0)));
324 p->finished_bracket_ = p->bracket_;
326 p->current_bracket_ev_ = 0;
329 if (p->event_drul_[START])
331 p->start_ev_ = p->event_drul_[START];
332 p->current_bracket_ev_ = p->event_drul_[START];
334 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
337 Set properties so that the stencil-creating function will
338 know whether the left edge should be flared \___
341 if (!p->finished_bracket_)
343 SCM flare = p->bracket_->get_property ("bracket-flare");
344 p->bracket_->set_property ("bracket-flare", scm_cons (scm_from_double (0), scm_cdr (flare)));
347 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
348 so the stencil function will shorten the ____ line by the length of the Ped. text.
354 Mixed style: Store a pointer to the preceding text for use in
355 calculating the length of the line
360 WTF is pedal-text not the bound of the object? --hwn
363 p->bracket_->set_object ("pedal-text", p->item_->self_scm ());
367 We do not use currentMusicalColumn for the left span-point.
368 If the column as accidentals (eg on a different stave), the
369 currentMusicalColumn is too wide, making the bracket too big.
373 Hmm. What do we do when there are no notes when the spanner starts?
377 what about the right span point?
380 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
382 if (!p->event_drul_[STOP])
388 // position new pedal spanner below the current one
390 if (previous_.size ())
391 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
393 previous_.push (p->line_spanner_);
397 p->event_drul_[START] = 0;
398 p->event_drul_[STOP] = 0;
402 Piano_pedal_engraver::finalize ()
404 for (Pedal_info *p = info_list_; p && p->name_; p++)
410 && !p->line_spanner_->is_live ())
411 p->line_spanner_ = 0;
414 && !p->bracket_->is_live ())
419 SCM cc = get_property ("currentCommandColumn");
420 Item *c = unsmob_item (cc);
421 if (p->line_spanner_)
422 p->line_spanner_->set_bound (RIGHT, c);
423 p->bracket_->set_bound (RIGHT, c);
425 p->finished_bracket_ = p->bracket_;
427 p->finished_line_spanner_ = p->line_spanner_;
428 p->line_spanner_ = 0;
432 if (p->line_spanner_)
434 p->finished_line_spanner_ = p->line_spanner_;
441 Piano_pedal_engraver::del_linespanner (Spanner *g)
443 int idx = previous_.find_index (g);
449 Piano_pedal_engraver::stop_translation_timestep ()
451 for (Pedal_info *p = info_list_; p && p->name_; p++)
455 p->finished_line_spanner_ = p->line_spanner_;
456 p->line_spanner_ = 0;
457 del_linespanner (p->finished_line_spanner_);
463 for (Pedal_info *p = info_list_; p->name_; p++)
465 p->event_drul_[STOP] = 0;
466 p->event_drul_[START] = 0;
471 Piano_pedal_engraver::typeset_all (Pedal_info *p)
476 if (p->finished_line_spanner_
477 && !p->finished_line_spanner_->is_live ())
478 p->finished_line_spanner_ = 0;
479 if (p->finished_bracket_
480 && !p->finished_bracket_->is_live ())
481 p->finished_bracket_ = 0;
488 if (p->finished_bracket_)
490 Grob *r = p->finished_bracket_->get_bound (RIGHT);
493 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
496 p->finished_bracket_ = 0;
499 if (p->finished_line_spanner_)
501 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
502 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
504 p->finished_line_spanner_->set_bound (RIGHT, l);
506 p->finished_line_spanner_->set_bound (LEFT, r);
509 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
510 Item *ci = dynamic_cast<Item *> (cc);
511 p->finished_line_spanner_->set_bound (RIGHT, ci);
512 p->finished_line_spanner_->set_bound (LEFT, ci);
515 p->finished_line_spanner_ = 0;
519 #include "translator.icc"
520 ADD_ACKNOWLEDGER (Piano_pedal_engraver, note_column);
521 ADD_TRANSLATOR (Piano_pedal_engraver,
522 /* doc */ "Engrave piano pedal symbols and brackets.",
523 /* create */ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
524 /* accept */ "pedal-event",
525 /* read */ "currentCommandColumn "
526 "pedalSostenutoStrings pedalSustainStrings "
527 "pedalUnaCordaStrings pedalSostenutoStyle "
528 "pedalSustainStyle pedalUnaCordaStyle",