release commit
[lilypond.git] / lily / piano-pedal-engraver.cc
blob85f7ce27cc4247c31f8204078b5d9d9cb4656269
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"
25 struct Pedal_info
27 char const * name_;
28 Music* start_req_;
29 Drul_array<Music*> req_l_drul_;
30 Item* item_;
31 Spanner* bracket_; // A single portion of a pedal bracket
32 Spanner* finished_bracket_;
35 This grob contains all the pedals of the same type on the same staff
37 Spanner* line_spanner_;
38 Spanner* finished_line_spanner_;
39 Music* current_bracket_req_;
43 class Piano_pedal_engraver : public Engraver
45 public:
46 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
47 ~Piano_pedal_engraver ();
48 protected:
49 virtual void initialize ();
50 virtual void finalize ();
51 virtual bool try_music (Music*);
52 virtual void stop_translation_timestep ();
53 virtual void start_translation_timestep ();
54 virtual void acknowledge_grob (Grob_info);
55 virtual void process_acknowledged_grobs ();
57 private:
59 Pedal_info *info_list_;
62 Record a stack of the current pedal spanners, so if more than one pedal
63 occurs simultaneously then extra space can be added between them.
66 Why 4, why not 3. Why not 3423 ? ---hwn.
69 Spanner *previous_ [4];
71 int spanner_count_;
74 Left and right flare widths of a \___/, as specified by the grob
75 property edge-widen.
77 Drul_array<SCM> edge_width_drul_;
79 void create_text_grobs (Pedal_info *p, SCM pedaltype);
80 void create_bracket_grobs (Pedal_info *p, SCM pedaltype);
81 void typeset_all ();
85 Piano_pedal_engraver::Piano_pedal_engraver ()
87 info_list_ = 0;
90 void
91 Piano_pedal_engraver::initialize ()
93 info_list_ = new Pedal_info[4];
94 Pedal_info *p = info_list_;
96 spanner_count_ = 0;
97 for (int i = 0; i < 3; ++i)
98 previous_[i] = 0;
101 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
102 char **np = names ;
105 p->name_ = *np;
106 p->item_ = 0;
107 p->bracket_ = 0;
108 p->finished_bracket_ = 0;
109 p->line_spanner_ = 0;
110 p->finished_line_spanner_ = 0;
111 p->current_bracket_req_ = 0;
112 p->req_l_drul_[START] = 0;
113 p->req_l_drul_[STOP] = 0;
114 p->start_req_ = 0;
116 p++;
118 while (* (np ++));
121 Piano_pedal_engraver::~Piano_pedal_engraver ()
123 delete[] info_list_;
127 Urg: Code dup
128 I'm a script
130 void
131 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
133 for (Pedal_info*p = info_list_; p && p->name_; p ++)
135 if (Note_column::has_interface (info.grob_))
137 if (p->line_spanner_)
139 Side_position_interface::add_support (p->line_spanner_, info.grob_);
141 add_bound_item (p->line_spanner_,info.grob_);
143 if (p->bracket_)
144 add_bound_item (p->bracket_,info.grob_);
150 bool
151 Piano_pedal_engraver::try_music (Music *m)
153 if (m->is_mus_type ("abort-event"))
155 for (Pedal_info*p = info_list_; p->name_; p ++)
157 p->req_l_drul_[START] = 0;
158 p->req_l_drul_[STOP] = 0;
160 if (p->bracket_)
161 p->bracket_->suicide (); /* as in dynamic-engraver.cc */
162 p->bracket_ = 0;
165 else if (m->is_mus_type ("pedal-event"))
167 for (Pedal_info*p = info_list_; p->name_; p ++)
169 String nm = p->name_ + String ("Event");
170 if (gh_equal_p (m->get_mus_property ("name") ,
171 gh_symbol2scm (nm.to_str0())))
173 Direction d = to_dir (m->get_mus_property ("span-direction"));
174 p->req_l_drul_[d] = m;
175 return true;
179 return false;
182 void
183 Piano_pedal_engraver::process_acknowledged_grobs ()
185 for (Pedal_info*p = info_list_; p && p->name_; p ++)
187 if (p->req_l_drul_[STOP] || p->req_l_drul_[START])
189 if (!p->line_spanner_)
191 String name = String (p->name_) + "PedalLineSpanner";
192 p->line_spanner_ = new Spanner (get_property (name.to_str0 ()));
195 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
196 announce_grob (p->line_spanner_, rq->self_scm ());
199 /* Choose the appropriate grobs to add to the line spanner
200 These can be text items or text-spanners
202 SCM type = ly_cdr (scm_assoc (ly_symbol2scm ("pedal-type"),
203 get_property ( (String (p->name_) + "Pedal").to_str0 ())));
204 if (type == ly_symbol2scm ("text") || // Ped. *Ped. *
205 type == ly_symbol2scm ("mixed") ) // Ped. _____/\____|
207 if (! p->item_)
208 create_text_grobs (p, type);
210 if (type == ly_symbol2scm ("bracket") || // |_________/\____|
211 type == ly_symbol2scm ("mixed") )
213 create_bracket_grobs (p, type);
220 void
221 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
223 SCM b;
224 SCM s = SCM_EOL;
225 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
227 if (scm_ilength (strings) >= 3)
229 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
231 if (pedaltype == ly_symbol2scm ("text"))
233 if (!p->start_req_)
235 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
237 else
239 s = ly_cadr (strings);
241 p->start_req_ = p->req_l_drul_[START];
244 else if (p->req_l_drul_[STOP])
246 if (pedaltype == ly_symbol2scm ("text"))
248 if (!p->start_req_)
250 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
252 else
254 s = ly_caddr (strings);
255 spanner_count_ --;
257 p->start_req_ = 0;
260 else if (p->req_l_drul_[START])
262 p->start_req_ = p->req_l_drul_[START];
263 s = ly_car (strings);
264 if (pedaltype == ly_symbol2scm ("text"))
266 spanner_count_ ++;
267 previous_[spanner_count_] = p->line_spanner_;
268 if (spanner_count_ > 1)
269 // add extra space below the previous already-occuring pedal
270 Side_position_interface::add_support (p->line_spanner_,
271 previous_[spanner_count_ - 1]);
275 if (gh_string_p (s))
277 String propname = String (p->name_) + "Pedal";
278 b = get_property (propname.to_str0 ());
279 p->item_ = new Item (b);
280 p->item_->set_grob_property ("text", s);
281 Axis_group_interface::add_element (p->line_spanner_, p->item_);
283 announce_grob (p->item_,
284 (p->req_l_drul_[START]
285 ? p->req_l_drul_[START]
286 : p->req_l_drul_[STOP])->self_scm ());
289 if (pedaltype == ly_symbol2scm ("text"))
291 p->req_l_drul_[START] = 0;
292 p->req_l_drul_[STOP] = 0;
297 void
298 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
301 if (p->req_l_drul_[STOP])
303 if (!p->start_req_)
305 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
307 else if (!p->req_l_drul_[START])
308 spanner_count_ -- ;
310 assert (!p->finished_bracket_ && p->bracket_);
312 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
313 p->bracket_->set_bound (RIGHT, cmc);
316 Set properties so that the molecule-creating function will
317 know whether the right edge should be flared ___/
319 SCM eleft = ly_car (p->bracket_->get_grob_property ("edge-widen"));
320 SCM eright = (p->req_l_drul_[START] ? edge_width_drul_[RIGHT] : gh_double2scm (0));
321 p->bracket_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
323 p->finished_bracket_ = p->bracket_;
324 p->bracket_ = 0;
325 p->current_bracket_req_ = 0;
326 p->start_req_ = p->req_l_drul_[START];
329 if (p->req_l_drul_[START])
331 p->start_req_ = p->req_l_drul_[START];
332 p->current_bracket_req_ = p->req_l_drul_[START];
334 p->bracket_ = new Spanner (get_property ("PianoPedalBracket"));
337 Set properties so that the molecule-creating function will
338 know whether the left edge should be flared \___
341 SCM ew = p->bracket_->get_grob_property ("edge-widen");
342 edge_width_drul_[LEFT] = ly_car (ew);
343 edge_width_drul_[RIGHT] = ly_cdr (ew);
345 SCM eleft = ( (bool) p->req_l_drul_[STOP] ?
346 edge_width_drul_[LEFT] :
347 gh_double2scm (0));
348 SCM eright = gh_double2scm (0);
349 p->bracket_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
351 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
352 so the molecule function will shorten the ____ line by the length of the Ped. text.
355 p->bracket_->set_grob_property ("text-start",
356 pedaltype == ly_symbol2scm ("mixed") ?
357 gh_bool2scm ( (bool) ! p->req_l_drul_[STOP]) :
358 gh_bool2scm (false));
361 Mixed style: Store a pointer to the preceding text for use in
362 calculating the length of the line
364 if (p->item_)
365 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
367 p->bracket_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
368 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
370 add_bound_item (p->line_spanner_, p->bracket_->get_bound (LEFT));
371 announce_grob (p->bracket_, p->req_l_drul_[START]->self_scm ());
373 if (!p->req_l_drul_[STOP])
375 spanner_count_ ++;
376 previous_[spanner_count_] = p->line_spanner_;
378 if (spanner_count_ > 1)
379 // position new pedal spanner below the current one
380 Side_position_interface::add_support (p->line_spanner_, previous_[spanner_count_ - 1]);
384 p->req_l_drul_[START] = 0;
385 p->req_l_drul_[STOP] = 0;
388 void
389 Piano_pedal_engraver::finalize ()
391 for (Pedal_info*p = info_list_; p && p->name_; p ++)
394 suicide?
396 if (p->line_spanner_
397 && !p->line_spanner_->live())
398 p->line_spanner_ = 0;
400 if (p->line_spanner_)
402 p->finished_line_spanner_ = p->line_spanner_;
403 typeset_all ();
405 if (p->bracket_
406 && !p->bracket_->live())
407 p->bracket_ = 0;
408 if (p->bracket_)
410 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
411 p->bracket_->suicide ();
412 p->bracket_ = 0;
418 void
419 Piano_pedal_engraver::stop_translation_timestep ()
421 for (Pedal_info*p = info_list_; p && p->name_; p ++)
423 if (!p->bracket_)
425 p->finished_line_spanner_ = p->line_spanner_;
426 p->line_spanner_ = 0;
430 typeset_all ();
434 void
435 Piano_pedal_engraver::typeset_all ()
437 Item * sustain = 0;
438 for (Pedal_info*p = info_list_; p->name_; p ++)
441 Handle suicide.
443 if (p->finished_line_spanner_
444 && !p->finished_line_spanner_->live ())
445 p->finished_line_spanner_ = 0;
446 if (p->finished_bracket_
447 && !p->finished_bracket_->live())
448 p->finished_bracket_ = 0;
451 if (p->name_ == String ("Sustain"))
452 sustain = p->item_;
454 if (p->item_)
457 Hmm.
459 if (p->name_ != String ("Sustain"))
461 if (sustain)
463 Side_position_interface::add_support (p->item_,sustain);
466 typeset_grob (p->item_);
467 p->item_ = 0;
470 if (p->finished_bracket_)
472 Grob * r = p->finished_bracket_->get_bound (RIGHT);
473 if (!r)
475 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
478 typeset_grob (p->finished_bracket_);
479 p->finished_bracket_ =0;
482 if (p->finished_line_spanner_)
484 Side_position_interface::add_staff_support (p->finished_line_spanner_);
485 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
486 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
487 if (!r && l)
488 p->finished_line_spanner_->set_bound (RIGHT, l);
489 else if (!l && r)
490 p->finished_line_spanner_->set_bound (LEFT, r);
491 else if (!r && !l)
493 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
494 Item * ci = dynamic_cast<Item*> (cc);
495 p->finished_line_spanner_->set_bound (RIGHT, ci);
496 p->finished_line_spanner_->set_bound (LEFT, ci);
498 typeset_grob (p->finished_line_spanner_);
499 p->finished_line_spanner_ = 0;
504 void
505 Piano_pedal_engraver::start_translation_timestep ()
507 for (Pedal_info*p = info_list_; p->name_; p ++)
509 p->req_l_drul_[STOP] = 0;
510 p->req_l_drul_[START] = 0;
513 ENTER_DESCRIPTION (Piano_pedal_engraver,
514 /* descr */ "Engrave piano pedal symbols and brackets.",
515 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
516 /* accepts */ "pedal-event abort-event",
517 /* acks */ "note-column-interface",
518 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",
519 /* write */ "");