release commit
[lilypond.git] / lily / piano-pedal-engraver.cc
blob67a877306ed6d06c63730f8a58f6a5c4e3e71bcf
1 /*
2 piano-pedal-engraver.cc -- implement Piano_pedal_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
8 Chris Jackson <chris@fluffhouse.org.uk> - extended to support
9 bracketed pedals.
12 #include "engraver.hh"
13 #include "event.hh"
14 #include "grob.hh"
15 #include "item.hh"
16 #include "lily-guile.hh"
17 #include "side-position-interface.hh"
18 #include "staff-symbol-referencer.hh"
19 #include "item.hh"
20 #include "axis-group-interface.hh"
21 #include "translator-group.hh"
22 #include "directional-element-interface.hh"
23 #include "note-column.hh"
24 #include "warn.hh"
26 struct Pedal_info
28 char const * name_;
31 Event for currently running pedal.
33 Music* current_bracket_ev_;
35 Event for currently starting pedal, (necessary?
37 distinct from current_bracket_ev_, since current_bracket_ev_ only
38 necessary for brackets, not for text style.
40 Music* start_ev_;
45 Events that were found in this timestep.
47 Drul_array<Music*> event_drul_;
48 Item* item_;
49 Spanner* bracket_; // A single portion of a pedal bracket
50 Spanner* finished_bracket_;
53 This grob contains all the pedals of the same type on the same staff
55 Spanner* line_spanner_;
56 Spanner* finished_line_spanner_;
60 class Piano_pedal_engraver : public Engraver
62 public:
63 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
64 ~Piano_pedal_engraver ();
65 protected:
66 virtual void initialize ();
67 virtual void finalize ();
68 virtual bool try_music (Music*);
69 virtual void stop_translation_timestep ();
70 virtual void start_translation_timestep ();
71 virtual void acknowledge_grob (Grob_info);
72 virtual void process_music ();
74 private:
76 Pedal_info *info_list_;
79 Record a stack of the current pedal spanners, so if more than one pedal
80 occurs simultaneously then extra space can be added between them.
83 Link_array<Spanner> previous_;
87 void create_text_grobs (Pedal_info *p, bool);
88 void create_bracket_grobs (Pedal_info *p, bool);
89 void typeset_all ();
93 Piano_pedal_engraver::Piano_pedal_engraver ()
95 info_list_ = 0;
98 void
99 Piano_pedal_engraver::initialize ()
102 previous_.clear ();
104 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
106 info_list_ = new Pedal_info[sizeof (names)/ sizeof (const char*)];
107 Pedal_info *p = info_list_;
109 char **np = names ;
112 p->name_ = *np;
113 p->item_ = 0;
114 p->bracket_ = 0;
115 p->finished_bracket_ = 0;
116 p->line_spanner_ = 0;
117 p->finished_line_spanner_ = 0;
118 p->current_bracket_ev_ = 0;
119 p->event_drul_[START] = 0;
120 p->event_drul_[STOP] = 0;
121 p->start_ev_ = 0;
123 p++;
125 while (* (np ++));
128 Piano_pedal_engraver::~Piano_pedal_engraver ()
130 delete[] info_list_;
134 Urg: Code dup
135 I'm a script
137 void
138 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
140 for (Pedal_info*p = info_list_; p && p->name_; p ++)
142 if (Note_column::has_interface (info.grob_))
144 if (p->line_spanner_)
146 Side_position_interface::add_support (p->line_spanner_, info.grob_);
148 add_bound_item (p->line_spanner_,info.grob_);
150 if (p->bracket_)
151 add_bound_item (p->bracket_,info.grob_);
157 bool
158 Piano_pedal_engraver::try_music (Music *m)
160 if (m->is_mus_type ("abort-event"))
162 for (Pedal_info*p = info_list_; p->name_; p ++)
164 p->event_drul_[START] = 0;
165 p->event_drul_[STOP] = 0;
167 if (p->bracket_)
168 p->bracket_->suicide ();
169 p->bracket_ = 0;
172 else if (m->is_mus_type ("pedal-event"))
174 for (Pedal_info*p = info_list_; p->name_; p ++)
176 String nm = p->name_ + String ("Event");
177 if (gh_equal_p (m->get_mus_property ("name") ,
178 gh_symbol2scm (nm.to_str0())))
180 Direction d = to_dir (m->get_mus_property ("span-direction"));
181 p->event_drul_[d] = m;
182 return true;
186 return false;
189 void
190 Piano_pedal_engraver::process_music ()
192 for (Pedal_info*p = info_list_; p && p->name_; p ++)
194 if (p->event_drul_[STOP] || p->event_drul_[START])
196 if (!p->line_spanner_)
198 String name = String (p->name_) + "PedalLineSpanner";
199 p->line_spanner_ = new Spanner (get_property (name.to_str0 ()));
202 Music * rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
203 announce_grob (p->line_spanner_, rq->self_scm ());
206 /* Choose the appropriate grobs to add to the line spanner
207 These can be text items or text-spanners
211 ugh, code dup, should read grob to create from other
212 property.
214 bracket: |_________/\____|
215 text: Ped. *Ped. *
216 mixed: Ped. _____/\____|
220 String prop = String ("pedal") + p->name_ + "Style";
221 SCM style = get_property (prop.to_str0 ());
222 bool mixed = style == ly_symbol2scm ("mixed");
223 if (style == ly_symbol2scm ("text") ||
224 mixed)
226 if (! p->item_)
227 create_text_grobs (p, mixed);
229 if (style == ly_symbol2scm ("bracket") ||
230 mixed)
232 create_bracket_grobs (p, mixed);
238 void
239 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
241 SCM s = SCM_EOL;
242 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
244 if (scm_ilength (strings) < 3)
246 Music * m = p->event_drul_[START];
247 if (!m) m = p->event_drul_ [STOP];
249 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
250 if (m)
251 m->origin()->warning (msg);
252 else
253 warning (msg);
255 return ;
258 if (p->event_drul_[STOP] && p->event_drul_[START])
260 if (!mixed)
262 if (!p->start_ev_)
264 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
266 else
268 s = ly_cadr (strings);
270 p->start_ev_ = p->event_drul_[START];
273 else if (p->event_drul_[STOP])
275 if (!mixed)
277 if (!p->start_ev_)
279 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
281 else
283 s = ly_caddr (strings);
284 if (previous_.size ())
285 previous_.pop();
287 p->start_ev_ = 0;
290 else if (p->event_drul_[START])
292 p->start_ev_ = p->event_drul_[START];
293 s = ly_car (strings);
294 if (!mixed)
297 Code dup?! see below.
299 if (previous_.size ())
300 // add extra space below the previous already-occuring pedal
301 Side_position_interface::add_support (p->line_spanner_,
302 previous_.top ());
303 previous_.push ( p->line_spanner_);
307 if (gh_string_p (s))
309 String propname = String (p->name_) + "Pedal";
311 SCM b = get_property (propname.to_str0 ());
312 p->item_ = new Item (b);
313 p->item_->set_grob_property ("text", s);
314 Axis_group_interface::add_element (p->line_spanner_, p->item_);
316 announce_grob (p->item_,
317 (p->event_drul_[START]
318 ? p->event_drul_[START]
319 : p->event_drul_[STOP])->self_scm ());
322 if (!mixed)
324 p->event_drul_[START] = 0;
325 p->event_drul_[STOP] = 0;
329 void
330 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
332 if (!p->bracket_ && p->event_drul_[STOP])
334 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
335 p->event_drul_[STOP]->origin ()->warning (msg);
336 p->event_drul_[STOP] = 0;
339 if (p->event_drul_[STOP])
341 if (!p->event_drul_[START])
343 if (previous_.size())
344 previous_.pop();
347 assert (!p->finished_bracket_);
349 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
350 p->bracket_->set_bound (RIGHT, cmc);
353 Set properties so that the molecule-creating function will
354 know whether the right edge should be flared ___/
357 if (!p->event_drul_[START])
359 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
360 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_car (flare),
361 gh_double2scm (0)));
364 p->finished_bracket_ = p->bracket_;
365 p->bracket_ = 0;
366 p->current_bracket_ev_ = 0;
369 if (p->event_drul_[START])
371 p->start_ev_ = p->event_drul_[START];
372 p->current_bracket_ev_ = p->event_drul_[START];
374 p->bracket_ = new Spanner (get_property ("PianoPedalBracket"));
377 Set properties so that the molecule-creating function will
378 know whether the left edge should be flared \___
381 if (!p->finished_bracket_)
383 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
384 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_double2scm (0),gh_cdr (flare)));
388 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
389 so the molecule function will shorten the ____ line by the length of the Ped. text.
392 if (mixed)
395 Mixed style: Store a pointer to the preceding text for use in
396 calculating the length of the line
399 TODO:
401 WTF is pedal-text not the bound of the object? --hwn
403 if (p->item_)
404 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
407 p->bracket_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
408 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
410 add_bound_item (p->line_spanner_, p->bracket_->get_bound (LEFT));
411 announce_grob (p->bracket_, p->event_drul_[START]->self_scm ());
413 if (!p->event_drul_[STOP])
417 code dup. --hwn.
419 // position new pedal spanner below the current one
421 if (previous_.size())
422 Side_position_interface::add_support (p->line_spanner_, previous_.top());
424 previous_.push (p->line_spanner_);
428 p->event_drul_[START] = 0;
429 p->event_drul_[STOP] = 0;
432 void
433 Piano_pedal_engraver::finalize ()
435 for (Pedal_info*p = info_list_; p && p->name_; p ++)
438 suicide?
440 if (p->line_spanner_
441 && !p->line_spanner_->live())
442 p->line_spanner_ = 0;
444 if (p->line_spanner_)
446 p->finished_line_spanner_ = p->line_spanner_;
447 typeset_all ();
449 if (p->bracket_
450 && !p->bracket_->live())
451 p->bracket_ = 0;
453 if (p->bracket_)
455 p->current_bracket_ev_->origin ()->warning (_ ("unterminated pedal bracket"));
456 p->bracket_->suicide ();
457 p->bracket_ = 0;
463 void
464 Piano_pedal_engraver::stop_translation_timestep ()
466 for (Pedal_info*p = info_list_; p && p->name_; p ++)
468 if (!p->bracket_)
470 p->finished_line_spanner_ = p->line_spanner_;
471 p->line_spanner_ = 0;
475 typeset_all ();
479 void
480 Piano_pedal_engraver::typeset_all ()
482 Item * sustain = 0;
483 for (Pedal_info*p = info_list_; p->name_; p ++)
486 Handle suicide.
488 if (p->finished_line_spanner_
489 && !p->finished_line_spanner_->live ())
490 p->finished_line_spanner_ = 0;
491 if (p->finished_bracket_
492 && !p->finished_bracket_->live())
493 p->finished_bracket_ = 0;
496 if (p->name_ == String ("Sustain"))
497 sustain = p->item_;
499 if (p->item_)
502 Hmm.
504 if (p->name_ != String ("Sustain"))
506 if (sustain)
508 Side_position_interface::add_support (p->item_,sustain);
511 typeset_grob (p->item_);
512 p->item_ = 0;
515 if (p->finished_bracket_)
517 Grob * r = p->finished_bracket_->get_bound (RIGHT);
518 if (!r)
520 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
523 typeset_grob (p->finished_bracket_);
524 p->finished_bracket_ =0;
527 if (p->finished_line_spanner_)
529 Side_position_interface::add_staff_support (p->finished_line_spanner_);
530 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
531 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
532 if (!r && l)
533 p->finished_line_spanner_->set_bound (RIGHT, l);
534 else if (!l && r)
535 p->finished_line_spanner_->set_bound (LEFT, r);
536 else if (!r && !l)
538 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
539 Item * ci = dynamic_cast<Item*> (cc);
540 p->finished_line_spanner_->set_bound (RIGHT, ci);
541 p->finished_line_spanner_->set_bound (LEFT, ci);
543 typeset_grob (p->finished_line_spanner_);
544 p->finished_line_spanner_ = 0;
549 void
550 Piano_pedal_engraver::start_translation_timestep ()
552 for (Pedal_info*p = info_list_; p->name_; p ++)
554 p->event_drul_[STOP] = 0;
555 p->event_drul_[START] = 0;
559 ENTER_DESCRIPTION (Piano_pedal_engraver,
560 /* descr */ "Engrave piano pedal symbols and brackets.",
561 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
562 /* accepts */ "pedal-event abort-event",
563 /* acks */ "note-column-interface",
564 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings pedalSostenutoStyle pedalSustainStyle pedalUnaCordaStyle",
565 /* write */ "");