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_));
241 s = scm_cadr (strings);
243 p->start_ev_ = p->event_drul_[START];
246 else if (p->event_drul_[STOP])
252 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
256 s = scm_caddr (strings);
261 else if (p->event_drul_[START])
263 p->start_ev_ = p->event_drul_[START];
264 s = scm_car (strings);
268 Code dup?! see below.
270 if (previous_.size ())
271 // add extra space below the previous already-occuring pedal
272 Side_position_interface::add_support (p->line_spanner_,
274 previous_.push (p->line_spanner_);
278 if (scm_is_string (s))
280 String propname = String (p->name_) + "Pedal";
282 p->item_ = make_item (propname.to_str0 (), (p->event_drul_[START]
283 ? p->event_drul_[START]
284 : p->event_drul_[STOP])->self_scm ());
286 p->item_->set_property ("text", s);
287 Axis_group_interface::add_element (p->line_spanner_, p->item_);
292 p->event_drul_[START] = 0;
293 p->event_drul_[STOP] = 0;
298 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
300 if (!p->bracket_ && p->event_drul_[STOP])
302 String msg = _f ("can't find start of piano pedal bracket: `%s'", p->name_);
303 p->event_drul_[STOP]->origin ()->warning (msg);
304 p->event_drul_[STOP] = 0;
307 if (p->event_drul_[STOP])
309 assert (!p->finished_bracket_);
311 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
313 if (!p->bracket_->get_bound (RIGHT))
314 p->bracket_->set_bound (RIGHT, cmc);
317 Set properties so that the stencil-creating function will
318 know whether the right edge should be flared ___/
321 if (!p->event_drul_[START])
323 SCM flare = p->bracket_->get_property ("bracket-flare");
324 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
325 scm_from_double (0)));
328 p->finished_bracket_ = p->bracket_;
330 p->current_bracket_ev_ = 0;
333 if (p->event_drul_[START])
335 p->start_ev_ = p->event_drul_[START];
336 p->current_bracket_ev_ = p->event_drul_[START];
338 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
341 Set properties so that the stencil-creating function will
342 know whether the left edge should be flared \___
345 if (!p->finished_bracket_)
347 SCM flare = p->bracket_->get_property ("bracket-flare");
348 p->bracket_->set_property ("bracket-flare", scm_cons (scm_from_double (0), scm_cdr (flare)));
351 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
352 so the stencil function will shorten the ____ line by the length of the Ped. text.
358 Mixed style: Store a pointer to the preceding text for use in
359 calculating the length of the line
364 WTF is pedal-text not the bound of the object? --hwn
367 p->bracket_->set_object ("pedal-text", p->item_->self_scm ());
371 We do not use currentMusicalColumn for the left span-point.
372 If the column as accidentals (eg on a different stave), the
373 currentMusicalColumn is too wide, making the bracket too big.
377 Hmm. What do we do when there are no notes when the spanner starts?
381 what about the right span point?
384 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
386 if (!p->event_drul_[STOP])
392 // position new pedal spanner below the current one
394 if (previous_.size ())
395 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
397 previous_.push (p->line_spanner_);
401 p->event_drul_[START] = 0;
402 p->event_drul_[STOP] = 0;
406 Piano_pedal_engraver::finalize ()
408 for (Pedal_info *p = info_list_; p && p->name_; p++)
414 && !p->line_spanner_->is_live ())
415 p->line_spanner_ = 0;
418 && !p->bracket_->is_live ())
423 SCM cc = get_property ("currentCommandColumn");
424 Item *c = unsmob_item (cc);
425 if (p->line_spanner_)
427 p->line_spanner_->set_bound (RIGHT, c);
429 p->bracket_->set_bound (RIGHT, c);
431 p->finished_bracket_ = p->bracket_;
433 p->finished_line_spanner_ = p->line_spanner_;
434 p->line_spanner_ = 0;
438 if (p->line_spanner_)
440 p->finished_line_spanner_ = p->line_spanner_;
447 Piano_pedal_engraver::del_linespanner (Spanner *g)
449 int idx = previous_.find_index (g);
455 Piano_pedal_engraver::stop_translation_timestep ()
457 for (Pedal_info *p = info_list_; p && p->name_; p++)
461 p->finished_line_spanner_ = p->line_spanner_;
462 p->line_spanner_ = 0;
463 del_linespanner (p->finished_line_spanner_);
469 for (Pedal_info *p = info_list_; p->name_; p++)
471 p->event_drul_[STOP] = 0;
472 p->event_drul_[START] = 0;
477 Piano_pedal_engraver::typeset_all (Pedal_info *p)
482 if (p->finished_line_spanner_
483 && !p->finished_line_spanner_->is_live ())
484 p->finished_line_spanner_ = 0;
485 if (p->finished_bracket_
486 && !p->finished_bracket_->is_live ())
487 p->finished_bracket_ = 0;
494 if (p->finished_bracket_)
496 Grob *r = p->finished_bracket_->get_bound (RIGHT);
499 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
502 p->finished_bracket_ = 0;
505 if (p->finished_line_spanner_)
507 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
508 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
510 p->finished_line_spanner_->set_bound (RIGHT, l);
512 p->finished_line_spanner_->set_bound (LEFT, r);
515 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
516 Item *ci = dynamic_cast<Item *> (cc);
517 p->finished_line_spanner_->set_bound (RIGHT, ci);
518 p->finished_line_spanner_->set_bound (LEFT, ci);
521 p->finished_line_spanner_ = 0;
525 #include "translator.icc"
526 ADD_ACKNOWLEDGER (Piano_pedal_engraver,note_column);
527 ADD_TRANSLATOR (Piano_pedal_engraver,
528 /* doc */ "Engrave piano pedal symbols and brackets.",
529 /* create */ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
530 /* accept */ "pedal-event",
531 /* read */ "currentCommandColumn "
532 "pedalSostenutoStrings pedalSustainStrings "
533 "pedalUnaCordaStrings pedalSostenutoStyle "
534 "pedalSustainStyle pedalUnaCordaStyle",