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>,
7 Erik Sandberg <mandolaerik@gmail.com>
9 Chris Jackson <chris@fluffhouse.org.uk> - extended to support
13 #include "engraver.hh"
15 #include "axis-group-interface.hh"
17 #include "directional-element-interface.hh"
18 #include "international.hh"
19 #include "lily-guile.hh"
20 #include "note-column.hh"
21 #include "side-position-interface.hh"
22 #include "staff-symbol-referencer.hh"
23 #include "stream-event.hh"
24 #include "string-convert.hh"
27 #include "translator.icc"
30 Urgh. This engraver is too complex. rewrite. --hwn
33 /* Ugh: This declaration is duplicated in piano-pedal-performer */
34 typedef enum Pedal_type {SOSTENUTO, SUSTAIN, UNA_CORDA, NUM_PEDAL_TYPES};
37 Static precalculated data (symbols and strings) for the different
40 struct Pedal_type_info
46 const char *pedal_line_spanner_c_str_;
47 const char *pedal_c_str_;
52 const Pedal_type_info *type_;
55 Event for currently running pedal.
57 Stream_event *current_bracket_ev_;
60 Event for currently starting pedal, (necessary?
62 distinct from current_bracket_ev_, since current_bracket_ev_ only
63 necessary for brackets, not for text style.
65 Stream_event *start_ev_;
68 Events that were found in this timestep.
70 Drul_array<Stream_event *> event_drul_;
72 Spanner *bracket_; // A single portion of a pedal bracket
73 Spanner *finished_bracket_;
76 This grob contains all the pedals of the same type on the same staff
78 Spanner *line_spanner_;
79 Spanner *finished_line_spanner_;
82 static Pedal_type_info pedal_types_[NUM_PEDAL_TYPES];
84 class Piano_pedal_engraver : public Engraver
87 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
88 ~Piano_pedal_engraver ();
90 virtual void initialize ();
91 virtual void finalize ();
92 DECLARE_TRANSLATOR_LISTENER (sustain);
93 DECLARE_TRANSLATOR_LISTENER (una_corda);
94 DECLARE_TRANSLATOR_LISTENER (sostenuto);
95 void stop_translation_timestep ();
96 DECLARE_ACKNOWLEDGER (note_column);
97 void process_music ();
100 Pedal_info info_list_[NUM_PEDAL_TYPES + 1];
103 Record a stack of the current pedal spanners, so if more than one pedal
104 occurs simultaneously then extra space can be added between them.
107 vector<Spanner*> previous_;
108 void del_linespanner (Spanner *);
110 void create_text_grobs (Pedal_info *p, bool);
111 void create_bracket_grobs (Pedal_info *p, bool);
112 void typeset_all (Pedal_info *p);
118 const char *names [NUM_PEDAL_TYPES];
119 names[SOSTENUTO] = "Sostenuto";
120 names[SUSTAIN] = "Sustain";
121 names[UNA_CORDA] = "UnaCorda";
123 for (int i = 0; i < NUM_PEDAL_TYPES; i++)
125 const char *name = names[i];
127 string base_name = name;
129 string base_ident = "";
132 for (cur_pos = 1; name[cur_pos]; cur_pos++)
133 if (isupper (name[cur_pos]))
135 base_ident = base_ident + String_convert::to_lower (string (name, prev_pos, cur_pos - prev_pos)) + "-";
138 base_ident += String_convert::to_lower (string (name, prev_pos, cur_pos - prev_pos));
140 Pedal_type_info *tbl = &pedal_types_[i];
141 tbl->base_name_ = name;
142 /* These symbols are static and need to be protected */
143 tbl->event_class_sym_ = scm_gc_protect_object (scm_str2symbol ((base_ident + "-event").c_str ()));
144 tbl->pedal_line_spanner_c_str_ = strdup ((base_name + "PedalLineSpanner").c_str ());
145 tbl->style_sym_ = scm_gc_protect_object (scm_str2symbol (("pedal" + base_name + "Style").c_str ()));
146 tbl->strings_sym_ = scm_gc_protect_object (scm_str2symbol (("pedal" + base_name + "Strings").c_str ()));
147 tbl->pedal_c_str_ = strdup ((base_name + "Pedal").c_str ());
150 ADD_SCM_INIT_FUNC (Piano_pedal_engraver_init_pedal_types_, init_pedal_types);
152 Piano_pedal_engraver::Piano_pedal_engraver ()
157 Piano_pedal_engraver::initialize ()
159 for (int i = 0; i < NUM_PEDAL_TYPES; i++)
161 Pedal_type_info *s = &pedal_types_[i];
162 Pedal_info *info = &info_list_[i];
167 info->finished_bracket_ = 0;
168 info->line_spanner_ = 0;
169 info->finished_line_spanner_ = 0;
170 info->current_bracket_ev_ = 0;
171 info->event_drul_[START] = 0;
172 info->event_drul_[STOP] = 0;
175 info_list_[NUM_PEDAL_TYPES].type_ = 0;
178 Piano_pedal_engraver::~Piano_pedal_engraver ()
187 Piano_pedal_engraver::acknowledge_note_column (Grob_info info)
189 for (Pedal_info *p = info_list_; p->type_; p++)
191 if (p->line_spanner_)
193 Side_position_interface::add_support (p->line_spanner_, info.grob ());
194 add_bound_item (p->line_spanner_, info.grob ());
197 add_bound_item (p->bracket_, info.grob ());
198 if (p->finished_bracket_)
199 add_bound_item (p->finished_bracket_, info.grob ());
203 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, sostenuto);
205 Piano_pedal_engraver::listen_sostenuto (Stream_event *r)
207 Direction d = to_dir (r->get_property ("span-direction"));
208 info_list_[SOSTENUTO].event_drul_[d] = r;
211 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, sustain);
213 Piano_pedal_engraver::listen_sustain (Stream_event *r)
215 Direction d = to_dir (r->get_property ("span-direction"));
216 info_list_[SUSTAIN].event_drul_[d] = r;
219 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, una_corda);
221 Piano_pedal_engraver::listen_una_corda (Stream_event *r)
223 Direction d = to_dir (r->get_property ("span-direction"));
224 info_list_[UNA_CORDA].event_drul_[d] = r;
228 Piano_pedal_engraver::process_music ()
230 for (Pedal_info *p = info_list_; p->type_; p++)
232 if (p->event_drul_[STOP] || p->event_drul_[START])
234 if (!p->line_spanner_)
236 const char *name = p->type_->pedal_line_spanner_c_str_;
237 Stream_event *rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
238 p->line_spanner_ = make_spanner (name, rq->self_scm ());
241 /* Choose the appropriate grobs to add to the line spanner
242 These can be text items or text-spanners
246 ugh, code dup, should read grob to create from other
249 bracket: |_________/\____|
251 mixed: Ped. _____/\____|
254 SCM style = internal_get_property (p->type_->style_sym_);
256 bool mixed = style == ly_symbol2scm ("mixed");
257 bool bracket = (mixed
258 || style == ly_symbol2scm ("bracket"));
259 bool text = (style == ly_symbol2scm ("text")
262 if (text && !p->item_)
263 create_text_grobs (p, mixed);
265 create_bracket_grobs (p, mixed);
271 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
274 SCM strings = internal_get_property (p->type_->strings_sym_);
276 if (scm_ilength (strings) < 3)
278 Stream_event *m = p->event_drul_[START];
279 if (!m) m = p->event_drul_ [STOP];
281 string msg = _f ("expect 3 strings for piano pedals, found: %ld",
282 scm_ilength (strings));
284 m->origin ()->warning (msg);
291 if (p->event_drul_[STOP] && p->event_drul_[START])
296 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->type_->base_name_.c_str ()));
298 s = scm_cadr (strings);
299 p->start_ev_ = p->event_drul_[START];
302 else if (p->event_drul_[STOP])
307 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->type_->base_name_.c_str ()));
309 s = scm_caddr (strings);
313 else if (p->event_drul_[START])
315 p->start_ev_ = p->event_drul_[START];
316 s = scm_car (strings);
320 Code dup?! see below.
322 if (previous_.size ())
323 // add extra space below the previous already-occuring pedal
324 Side_position_interface::add_support (p->line_spanner_,
326 previous_.push_back (p->line_spanner_);
330 if (scm_is_string (s))
332 const char *propname = p->type_->pedal_c_str_;
334 p->item_ = make_item (propname, (p->event_drul_[START]
335 ? p->event_drul_[START]
336 : p->event_drul_[STOP])->self_scm ());
338 p->item_->set_property ("text", s);
339 Axis_group_interface::add_element (p->line_spanner_, p->item_);
344 p->event_drul_[START] = 0;
345 p->event_drul_[STOP] = 0;
350 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
352 if (!p->bracket_ && p->event_drul_[STOP])
354 string msg = _f ("can't find start of piano pedal bracket: `%s'", p->type_->base_name_.c_str ());
355 p->event_drul_[STOP]->origin ()->warning (msg);
356 p->event_drul_[STOP] = 0;
359 if (p->event_drul_[STOP])
361 assert (!p->finished_bracket_);
363 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
365 if (!p->bracket_->get_bound (RIGHT))
366 p->bracket_->set_bound (RIGHT, cmc);
369 Set properties so that the stencil-creating function will
370 know whether the right edge should be flared ___/
373 if (!p->event_drul_[START])
375 SCM flare = p->bracket_->get_property ("bracket-flare");
376 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
377 scm_from_double (0)));
380 p->finished_bracket_ = p->bracket_;
382 p->current_bracket_ev_ = 0;
385 if (p->event_drul_[START])
387 p->start_ev_ = p->event_drul_[START];
388 p->current_bracket_ev_ = p->event_drul_[START];
390 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
393 Set properties so that the stencil-creating function will
394 know whether the left edge should be flared \___
397 if (!p->finished_bracket_)
399 SCM flare = p->bracket_->get_property ("bracket-flare");
400 p->bracket_->set_property ("bracket-flare", scm_cons (scm_from_double (0), scm_cdr (flare)));
403 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
404 so the stencil function will shorten the ____ line by the length of the Ped. text.
410 Mixed style: Store a pointer to the preceding text for use in
411 calculating the length of the line
416 WTF is pedal-text not the bound of the object? --hwn
419 p->bracket_->set_object ("pedal-text", p->item_->self_scm ());
423 We do not use currentMusicalColumn for the left span-point.
424 If the column as accidentals (eg on a different stave), the
425 currentMusicalColumn is too wide, making the bracket too big.
429 Hmm. What do we do when there are no notes when the spanner starts?
433 what about the right span point?
436 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
438 if (!p->event_drul_[STOP])
444 // position new pedal spanner below the current one
446 if (previous_.size ())
447 Side_position_interface::add_support (p->line_spanner_, previous_.back ());
449 previous_.push_back (p->line_spanner_);
453 p->event_drul_[START] = 0;
454 p->event_drul_[STOP] = 0;
458 Piano_pedal_engraver::finalize ()
460 for (Pedal_info *p = info_list_; p->type_; p++)
466 && !p->line_spanner_->is_live ())
467 p->line_spanner_ = 0;
470 && !p->bracket_->is_live ())
475 SCM cc = get_property ("currentCommandColumn");
476 Item *c = unsmob_item (cc);
477 if (p->line_spanner_)
478 p->line_spanner_->set_bound (RIGHT, c);
479 p->bracket_->set_bound (RIGHT, c);
481 p->finished_bracket_ = p->bracket_;
483 p->finished_line_spanner_ = p->line_spanner_;
484 p->line_spanner_ = 0;
488 if (p->line_spanner_)
490 p->finished_line_spanner_ = p->line_spanner_;
497 Piano_pedal_engraver::del_linespanner (Spanner *g)
499 vsize idx = find (previous_, g) - previous_.begin ();
500 if (idx != VPOS && idx < previous_.size ())
501 previous_.erase (previous_.begin () + idx);
505 Piano_pedal_engraver::stop_translation_timestep ()
507 for (Pedal_info *p = info_list_; p->type_; p++)
511 p->finished_line_spanner_ = p->line_spanner_;
512 p->line_spanner_ = 0;
513 del_linespanner (p->finished_line_spanner_);
519 for (Pedal_info *p = info_list_; p->type_; p++)
521 p->event_drul_[STOP] = 0;
522 p->event_drul_[START] = 0;
527 Piano_pedal_engraver::typeset_all (Pedal_info *p)
532 if (p->finished_line_spanner_
533 && !p->finished_line_spanner_->is_live ())
534 p->finished_line_spanner_ = 0;
535 if (p->finished_bracket_
536 && !p->finished_bracket_->is_live ())
537 p->finished_bracket_ = 0;
542 if (p->finished_bracket_)
544 Grob *r = p->finished_bracket_->get_bound (RIGHT);
546 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
548 p->finished_bracket_ = 0;
551 if (p->finished_line_spanner_)
553 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
554 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
556 p->finished_line_spanner_->set_bound (RIGHT, l);
558 p->finished_line_spanner_->set_bound (LEFT, r);
561 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
562 Item *ci = dynamic_cast<Item *> (cc);
563 p->finished_line_spanner_->set_bound (RIGHT, ci);
564 p->finished_line_spanner_->set_bound (LEFT, ci);
567 p->finished_line_spanner_ = 0;
571 ADD_ACKNOWLEDGER (Piano_pedal_engraver, note_column);
573 ADD_TRANSLATOR (Piano_pedal_engraver,
576 "Engrave piano pedal symbols and brackets.",
580 "SostenutoPedalLineSpanner "
582 "SustainPedalLineSpanner "
584 "UnaCordaPedalLineSpanner ",
590 "currentCommandColumn "
591 "pedalSostenutoStrings "
592 "pedalSostenutoStyle "
593 "pedalSustainStrings "
595 "pedalUnaCordaStrings "
596 "pedalUnaCordaStyle",