2 figured-bass-engraver.cc -- implement Figured_bass_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2005--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
10 #include "engraver.hh"
12 #include "align-interface.hh"
13 #include "axis-group-interface.hh"
15 #include "grob-array.hh"
17 #include "pointer-group-interface.hh"
19 #include "stream-event.hh"
20 #include "text-interface.hh"
22 #include "translator.icc"
27 Spanner
*continuation_line_
;
36 Stream_event
*current_event_
;
37 bool force_no_continuation_
;
42 force_no_continuation_
= false;
43 continuation_line_
= 0;
45 alteration_
= SCM_EOL
;
47 diminished_
= SCM_EOL
;
48 augmented_slash_
= SCM_EOL
;
52 bool is_continuation () const
56 && !force_no_continuation_
57 && ly_is_equal (number_
,
58 current_event_
->get_property ("figure"))
59 && ly_is_equal (alteration_
,
60 current_event_
->get_property ("alteration"))
61 && ly_is_equal (augmented_
,
62 current_event_
->get_property ("augmented"))
63 && ly_is_equal (diminished_
,
64 current_event_
->get_property ("diminished"))
65 && ly_is_equal (augmented_slash_
,
66 current_event_
->get_property ("augmented-slash"));
70 struct Figured_bass_engraver
: public Engraver
72 TRANSLATOR_DECLARATIONS (Figured_bass_engraver
);
73 void clear_spanners ();
77 void center_continuations (vector
<Spanner
*> const &consecutive_lines
);
78 void center_repeated_continuations ();
80 vector
<Figure_group
> groups_
;
82 vector
<Stream_event
*> new_events_
;
84 bool new_event_found_
;
87 Stream_event
*rest_event_
;
89 DECLARE_TRANSLATOR_LISTENER (rest
);
90 DECLARE_TRANSLATOR_LISTENER (bass_figure
);
92 virtual void derived_mark () const;
94 void start_translation_timestep ();
95 void stop_translation_timestep ();
96 void process_music ();
100 Figured_bass_engraver::derived_mark () const
102 for (vsize i
= 0; i
< groups_
.size (); i
++)
104 scm_gc_mark (groups_
[i
].number_
);
105 scm_gc_mark (groups_
[i
].alteration_
);
106 scm_gc_mark (groups_
[i
].augmented_
);
107 scm_gc_mark (groups_
[i
].diminished_
);
108 scm_gc_mark (groups_
[i
].augmented_slash_
);
113 Figured_bass_engraver::stop_translation_timestep ()
116 || now_mom ().main_part_
< stop_moment_
.main_part_
117 || now_mom ().grace_part_
< Rational (0))
121 for (vsize i
= 0; !found
&& i
< groups_
.size (); i
++)
122 found
= found
|| groups_
[i
].current_event_
;
128 Figured_bass_engraver::Figured_bass_engraver ()
131 continuation_
= false;
133 new_event_found_
= false;
137 Figured_bass_engraver::start_translation_timestep ()
139 if (now_mom ().main_part_
< stop_moment_
.main_part_
140 || now_mom ().grace_part_
< Rational (0))
144 new_events_
.clear ();
145 for (vsize i
= 0; i
< groups_
.size (); i
++)
146 groups_
[i
].current_event_
= 0;
148 continuation_
= false;
153 IMPLEMENT_TRANSLATOR_LISTENER (Figured_bass_engraver
, rest
);
155 Figured_bass_engraver::listen_rest (Stream_event
*ev
)
157 if (to_boolean (get_property ("ignoreFiguredBassRest")))
159 new_event_found_
= true;
162 No ASSIGN_EVENT_ONCE () ; otherwise we get warnings about
169 IMPLEMENT_TRANSLATOR_LISTENER (Figured_bass_engraver
, bass_figure
);
171 Figured_bass_engraver::listen_bass_figure (Stream_event
*ev
)
173 new_event_found_
= true;
174 Moment stop
= now_mom () + get_event_length (ev
, now_mom ());
175 stop_moment_
= max (stop_moment_
, stop
);
177 if (to_boolean (get_property ("useBassFigureExtenders")))
179 SCM fig
= ev
->get_property ("figure");
180 for (vsize i
= 0; i
< groups_
.size (); i
++)
182 if (!groups_
[i
].current_event_
183 && ly_is_equal (groups_
[i
].number_
, fig
))
185 groups_
[i
].current_event_
= ev
;
186 groups_
[i
].force_no_continuation_
187 = to_boolean (ev
->get_property ("no-continuation"));
188 continuation_
= true;
193 new_events_
.push_back (ev
);
197 Figured_bass_engraver::center_continuations (vector
<Spanner
*> const &consecutive_lines
)
199 if (consecutive_lines
.size () == 2)
201 vector
<Grob
*> left_figs
;
202 for (vsize j
= consecutive_lines
.size (); j
--;)
203 left_figs
.push_back (consecutive_lines
[j
]->get_bound (LEFT
));
205 SCM ga
= Grob_array::make_array ();
206 unsmob_grob_array (ga
)->set_array (left_figs
);
208 for (vsize j
= consecutive_lines
.size (); j
--;)
209 consecutive_lines
[j
]->set_object ("figures",
210 unsmob_grob_array (ga
)->smobbed_copy ());
215 Figured_bass_engraver::center_repeated_continuations ()
217 vector
<Spanner
*> consecutive_lines
;
218 for (vsize i
= 0; i
<= groups_
.size (); i
++)
220 if (i
< groups_
.size ()
221 && groups_
[i
].continuation_line_
222 && (consecutive_lines
.empty ()
223 || (consecutive_lines
[0]->get_bound (LEFT
)->get_column ()
224 == groups_
[i
].continuation_line_
->get_bound (LEFT
)->get_column ()
225 && consecutive_lines
[0]->get_bound (RIGHT
)->get_column ()
226 == groups_
[i
].continuation_line_
->get_bound (RIGHT
)->get_column ())))
227 consecutive_lines
.push_back (groups_
[i
].continuation_line_
);
230 center_continuations (consecutive_lines
);
231 consecutive_lines
.clear ();
237 Figured_bass_engraver::clear_spanners ()
244 announce_end_grob (alignment_
, SCM_EOL
);
248 if (to_boolean (get_property ("figuredBassCenterContinuations")))
249 center_repeated_continuations ();
251 for (vsize i
= 0; i
< groups_
.size (); i
++)
253 if (groups_
[i
].group_
)
255 announce_end_grob (groups_
[i
].group_
, SCM_EOL
);
256 groups_
[i
].group_
= 0;
259 if (groups_
[i
].continuation_line_
)
261 announce_end_grob (groups_
[i
].continuation_line_
, SCM_EOL
);
262 groups_
[i
].continuation_line_
= 0;
266 /* Check me, groups_.clear () ? */
270 Figured_bass_engraver::add_brackets ()
272 vector
<Grob
*> encompass
;
274 for (vsize i
= 0; i
< groups_
.size (); i
++)
276 if (!groups_
[i
].current_event_
)
279 if (to_boolean (groups_
[i
].current_event_
->get_property ("bracket-start")))
282 if (inside
&& groups_
[i
].figure_item_
)
283 encompass
.push_back (groups_
[i
].figure_item_
);
285 if (to_boolean (groups_
[i
].current_event_
->get_property ("bracket-stop")))
289 Item
* brack
= make_item ("BassFigureBracket", groups_
[i
].current_event_
->self_scm ());
290 for (vsize j
= 0; j
< encompass
.size (); j
++)
292 Pointer_group_interface::add_grob (brack
,
293 ly_symbol2scm ("elements"),
302 Figured_bass_engraver::process_music ()
304 if (alignment_
&& !to_boolean (get_property ("useBassFigureExtenders")))
315 && new_events_
.empty ())
322 if (!new_event_found_
)
325 new_event_found_
= false;
328 Don't need to sync alignments, if we're not using extenders.
330 bool use_extenders
= to_boolean (get_property ("useBassFigureExtenders"));
343 for (vsize i
= 0; i
< new_events_
.size (); i
++)
345 while (k
< groups_
.size ()
346 && groups_
[k
].current_event_
)
349 if (k
>= groups_
.size ())
352 groups_
.push_back (group
);
355 groups_
[k
].current_event_
= new_events_
[i
];
356 groups_
[k
].figure_item_
= 0;
360 for (vsize i
= 0; i
< groups_
.size (); i
++)
362 if (!groups_
[i
].is_continuation ())
364 groups_
[i
].number_
= SCM_BOOL_F
;
365 groups_
[i
].alteration_
= SCM_BOOL_F
;
366 groups_
[i
].augmented_
= SCM_BOOL_F
;
367 groups_
[i
].diminished_
= SCM_BOOL_F
;
368 groups_
[i
].augmented_slash_
= SCM_BOOL_F
;
374 vector
<int> junk_continuations
;
375 for (vsize i
= 0; i
< groups_
.size (); i
++)
377 Figure_group
&group
= groups_
[i
];
379 if (group
.is_continuation ())
381 if (!group
.continuation_line_
)
384 = make_spanner ("BassFigureContinuation", SCM_EOL
);
385 Item
* item
= group
.figure_item_
;
386 group
.continuation_line_
= line
;
387 line
->set_bound (LEFT
, item
);
390 Don't add as child. This will cache the wrong
391 (pre-break) stencil when callbacks are triggered.
393 line
->set_parent (group
.group_
, Y_AXIS
);
394 Pointer_group_interface::add_grob (line
, ly_symbol2scm ("figures"), item
);
396 group
.figure_item_
= 0;
399 else if (group
.continuation_line_
)
400 junk_continuations
.push_back (i
);
406 vector
<Spanner
*> consecutive
;
407 if (to_boolean (get_property ("figuredBassCenterContinuations")))
409 for (vsize i
= 0; i
<= junk_continuations
.size (); i
++)
411 if (i
< junk_continuations
.size ()
412 && (i
== 0 || junk_continuations
[i
-1] == junk_continuations
[i
] - 1))
413 consecutive
.push_back (groups_
[junk_continuations
[i
]].continuation_line_
);
416 center_continuations (consecutive
);
417 consecutive
.clear ();
418 if (i
< junk_continuations
.size ())
419 consecutive
.push_back (groups_
[junk_continuations
[i
]].continuation_line_
);
423 for (vsize i
= 0; i
< junk_continuations
.size (); i
++)
424 groups_
[junk_continuations
[i
]].continuation_line_
= 0;
432 Figured_bass_engraver::create_grobs ()
435 = dynamic_cast<Item
*> (unsmob_grob (get_property ("currentMusicalColumn")));
438 alignment_
= make_spanner ("BassFigureAlignment", SCM_EOL
);
439 alignment_
->set_bound (LEFT
, muscol
);
441 alignment_
->set_bound (RIGHT
, muscol
);
443 SCM proc
= get_property ("figuredBassFormatter");
444 for (vsize i
= 0; i
< groups_
.size (); i
++)
446 Figure_group
&group
= groups_
[i
];
448 if (group
.current_event_
)
451 = make_item ("BassFigure",
452 group
.current_event_
->self_scm ());
455 SCM fig
= group
.current_event_
->get_property ("figure");
458 group
.group_
= make_spanner ("BassFigureLine", SCM_EOL
);
459 group
.group_
->set_bound (LEFT
, muscol
);
460 Align_interface::add_element (alignment_
,
464 if (scm_memq (fig
, get_property ("implicitBassFigures")) != SCM_BOOL_F
)
466 item
->set_property ("transparent", SCM_BOOL_T
);
467 item
->set_property ("implicit", SCM_BOOL_T
);
471 group
.alteration_
= group
.current_event_
->get_property ("alteration");
472 group
.augmented_
= group
.current_event_
->get_property ("augmented");
473 group
.diminished_
= group
.current_event_
->get_property ("diminished");
474 group
.augmented_slash_
= group
.current_event_
->get_property ("augmented-slash");
476 SCM text
= group
.current_event_
->get_property ("text");
477 if (!Text_interface::is_markup (text
)
478 && ly_is_procedure (proc
))
480 text
= scm_call_3 (proc
, fig
, group
.current_event_
->self_scm (),
481 context ()->self_scm ());
484 item
->set_property ("text", text
);
486 Axis_group_interface::add_element (group
.group_
, item
);
487 group
.figure_item_
= item
;
490 if (group
.continuation_line_
)
493 UGH should connect to the bass staff, and get the note heads.
495 group
.figure_item_
->set_property ("transparent", SCM_BOOL_T
);
496 group
.continuation_line_
->set_bound (RIGHT
, group
.figure_item_
);
499 if (groups_
[i
].group_
)
500 groups_
[i
].group_
->set_bound (RIGHT
, muscol
);
506 ADD_TRANSLATOR (Figured_bass_engraver
,
508 "Make figured bass numbers.",
512 "BassFigureAlignment "
514 "BassFigureContinuation "
518 "figuredBassAlterationDirection "
519 "figuredBassCenterContinuations "
520 "figuredBassFormatter "
521 "implicitBassFigures "
522 "useBassFigureExtenders "
523 "ignoreFiguredBassRest ",