2 beam.cc -- implement Beam
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
14 * shorter! (now +- 1000 lines)
19 #include <math.h> // tanh.
21 #include "molecule.hh"
22 #include "directional-element-interface.hh"
26 #include "least-squares.hh"
28 #include "paper-def.hh"
30 #include "group-interface.hh"
31 #include "staff-symbol-referencer.hh"
37 Beam::add_stem (Grob
*me
, Grob
*s
)
39 Pointer_group_interface:: add_element (me
, "stems", s
);
41 s
->add_dependency (me
);
43 assert (!Stem::beam_l (s
));
44 s
->set_grob_property ("beam", me
->self_scm ());
46 add_bound_item (dynamic_cast<Spanner
*> (me
), dynamic_cast<Item
*> (s
));
50 Beam::get_multiplicity (Grob
*me
)
53 for (SCM s
= me
->get_grob_property ("stems"); gh_pair_p (s
); s
= gh_cdr (s
))
55 Grob
* sc
= unsmob_grob (gh_car (s
));
57 if (Stem::has_interface (sc
))
58 m
= m
>? Stem::beam_count (sc
,LEFT
) >? Stem::beam_count (sc
,RIGHT
);
64 After pre-processing all directions should be set.
65 Several post-processing routines (stem, slur, script) need stem/beam
67 Currenly, this means that beam has set all stem's directions.
68 [Alternatively, stems could set its own directions, according to
69 their beam, during 'final-pre-processing'.]
71 MAKE_SCHEME_CALLBACK (Beam
,before_line_breaking
,1);
73 Beam::before_line_breaking (SCM smob
)
75 Grob
* me
= unsmob_grob (smob
);
79 Why what? Why the warning (beams with less than 2 stems are
80 degenerate beams, should never happen), or why would this ever
81 happen (don't know). */
82 if (visible_stem_count (me
) < 2)
84 warning (_ ("beam has less than two stems"));
86 if (visible_stem_count (me
) >= 1)
88 if (!Directional_element_interface::get (me
))
89 Directional_element_interface::set (me
, get_default_dir (me
));
91 consider_auto_knees (me
);
92 set_stem_directions (me
);
93 set_stem_shorten (me
);
99 Beam::get_default_dir (Grob
*me
)
101 Drul_array
<int> total
;
102 total
[UP
] = total
[DOWN
] = 0;
103 Drul_array
<int> count
;
104 count
[UP
] = count
[DOWN
] = 0;
107 Link_array
<Item
> stems
=
108 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
110 for (int i
=0; i
<stems
.size (); i
++)
113 Direction sd
= Directional_element_interface::get (s
);
114 int current
= sd
? (1 + d
* sd
)/2
115 : Stem::get_center_distance (s
, (Direction
)-d
);
123 } while (flip (&d
) != DOWN
);
125 SCM func
= me
->get_grob_property ("dir-function");
126 SCM s
= gh_call2 (func
,
127 gh_cons (gh_int2scm (count
[UP
]),
128 gh_int2scm (count
[DOWN
])),
129 gh_cons (gh_int2scm (total
[UP
]),
130 gh_int2scm (total
[DOWN
])));
132 if (gh_number_p (s
) && gh_scm2int (s
))
136 If dir is not determined: get default
138 return to_dir (me
->get_grob_property ("default-neutral-direction"));
143 Set all stems with non-forced direction to beam direction.
144 Urg: non-forced should become `without/with unforced' direction,
145 once stem gets cleaned-up.
148 Beam::set_stem_directions (Grob
*me
)
150 Link_array
<Item
> stems
151 =Pointer_group_interface__extract_elements (me
, (Item
*) 0, "stems");
152 Direction d
= Directional_element_interface::get (me
);
154 for (int i
=0; i
<stems
.size (); i
++)
157 SCM force
= s
->remove_grob_property ("dir-forced");
158 if (!gh_boolean_p (force
) || !gh_scm2bool (force
))
159 Directional_element_interface ::set (s
,d
);
164 Simplistic auto-knees; only consider vertical gap between two
167 `Forced' stem directions are ignored. If you don't want auto-knees,
168 don't set, or unset auto-knee-gap.
171 Beam::consider_auto_knees (Grob
*me
)
173 SCM scm
= me
->get_grob_property ("auto-knee-gap");
175 if (gh_number_p (scm
))
179 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
180 Real gap
= gh_scm2double (scm
) / staff_space
;
182 Direction d
= Directional_element_interface::get (me
);
183 Link_array
<Item
> stems
=
184 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
186 Grob
*common
= me
->common_refpoint (stems
[0], Y_AXIS
);
187 for (int i
=1; i
< stems
.size (); i
++)
188 if (!Stem::invisible_b (stems
[i
]))
189 common
= common
->common_refpoint (stems
[i
], Y_AXIS
);
192 for (int i
=1; i
< stems
.size (); i
++)
194 if (!Stem::invisible_b (stems
[i
-1]))
196 if (Stem::invisible_b (stems
[l
]))
198 if (Stem::invisible_b (stems
[i
]))
201 Real left
= Stem::extremal_heads (stems
[l
])[d
]
202 ->relative_coordinate (common
, Y_AXIS
);
203 Real right
= Stem::extremal_heads (stems
[i
])[-d
]
204 ->relative_coordinate (common
, Y_AXIS
);
206 Real dy
= right
- left
;
210 knee_y
= (right
+ left
) / 2;
218 for (int i
=0; i
< stems
.size (); i
++)
220 if (Stem::invisible_b (stems
[i
]))
223 Real y
= Stem::extremal_heads (stems
[i
])[d
]
224 ->relative_coordinate (common
, Y_AXIS
);
226 Directional_element_interface::set (s
, y
< knee_y
? UP
: DOWN
);
227 s
->set_grob_property ("dir-forced", SCM_BOOL_T
);
234 Set stem's shorten property if unset.
236 take some y-position (chord/beam/nearest?) into account
237 scmify forced-fraction
240 Beam::set_stem_shorten (Grob
*m
)
242 Spanner
*me
= dynamic_cast<Spanner
*> (m
);
244 Real forced_fraction
= forced_stem_count (me
) / visible_stem_count (me
);
245 if (forced_fraction
< 0.5)
248 int multiplicity
= get_multiplicity (me
);
250 SCM shorten
= me
->get_grob_property ("beamed-stem-shorten");
251 if (shorten
== SCM_EOL
)
254 int sz
= scm_ilength (shorten
);
256 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
257 SCM shorten_elt
= scm_list_ref (shorten
, gh_int2scm (multiplicity
<? (sz
- 1)));
258 Real shorten_f
= gh_scm2double (shorten_elt
) * staff_space
;
260 /* cute, but who invented me -- how to customise ? */
261 if (forced_fraction
< 1)
264 Link_array
<Item
> stems
=
265 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
267 for (int i
=0; i
< stems
.size (); i
++)
270 if (Stem::invisible_b (s
))
272 if (gh_number_p (s
->get_grob_property ("shorten")))
273 s
->set_grob_property ("shorten", gh_double2scm (shorten_f
));
278 Call list of y-dy-callbacks, that handle setting of
279 grob-properties y, dy.
281 User may set grob-properties: y-position-hs and height-hs
282 (to be fixed) that override the calculated y and dy.
284 Because y and dy cannot be calculated and quanted separately, we
285 always calculate both, then check for user override.
287 MAKE_SCHEME_CALLBACK (Beam
, after_line_breaking
, 1);
289 Beam::after_line_breaking (SCM smob
)
291 Grob
* me
= unsmob_grob (smob
);
293 me
->set_grob_property ("y", gh_double2scm (0));
294 me
->set_grob_property ("dy", gh_double2scm (0));
296 /* Hmm, callbacks should be called by, a eh, callback mechanism
297 somewhere (?), I guess, not by looping here. */
299 SCM list
= me
->get_grob_property ("y-dy-callbacks");
300 for (SCM i
= list
; gh_pair_p (i
); i
= gh_cdr (i
))
301 gh_call1 (gh_car (i
), smob
);
303 // UGH. Y is not in staff position unit?
304 // Ik dacht datwe daar juist van weg wilden?
306 // Hmm, nu hebben we 3 dimensies, want inmiddels zijn we daar
307 // weer terug, maar dan / 2
308 // (staff-space iso staff-position)
310 set_stem_lengths (me
);
312 return SCM_UNSPECIFIED
;
316 MAKE_SCHEME_CALLBACK (Beam
, least_squares
, 1);
318 Beam::least_squares (SCM smob
)
320 Grob
*me
= unsmob_grob (smob
);
322 if (visible_stem_count (me
) <= 1)
323 return SCM_UNSPECIFIED
;
328 /* Stem_info, and thus y,dy in this function are corrected for beam-dir */
329 Real first_ideal
= Stem::calc_stem_info (first_visible_stem (me
)).idealy_f_
;
330 if (first_ideal
== Stem::calc_stem_info (last_visible_stem (me
)).idealy_f_
)
337 Array
<Offset
> ideals
;
339 // ugh -> use commonx
340 Real x0
= first_visible_stem (me
)->relative_coordinate (0, X_AXIS
);
341 Link_array
<Item
> stems
=
342 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
344 for (int i
=0; i
< stems
.size (); i
++)
347 if (Stem::invisible_b (s
))
349 ideals
.push (Offset (s
->relative_coordinate (0, X_AXIS
) - x0
,
350 Stem::calc_stem_info (s
).idealy_f_
));
353 minimise_least_squares (&dydx
, &y
, ideals
);
355 Real dx
= last_visible_stem (me
)->relative_coordinate (0, X_AXIS
) - x0
;
359 /* Store true, not dir-corrected values */
360 Direction dir
= Directional_element_interface::get (me
);
361 me
->set_grob_property ("y", gh_double2scm (y
* dir
));
362 me
->set_grob_property ("dy", gh_double2scm (dy
* dir
));
363 return SCM_UNSPECIFIED
;
366 MAKE_SCHEME_CALLBACK (Beam
, cancel_suspect_slope
, 1);
368 Beam::cancel_suspect_slope (SCM smob
)
370 Grob
*me
= unsmob_grob (smob
);
372 if (visible_stem_count (me
) <= 1)
373 return SCM_UNSPECIFIED
;
375 /* Stem_info, and thus y,dy in this function are corrected for beam-dir */
376 Direction dir
= Directional_element_interface::get (me
);
377 Real y
= gh_scm2double (me
->get_grob_property ("y")) * dir
;
378 Real dy
= gh_scm2double (me
->get_grob_property ("dy")) * dir
;
380 /* steep slope running against lengthened stem is suspect */
381 Real first_ideal
= Stem::calc_stem_info (first_visible_stem (me
)).idealy_f_
;
382 Real last_ideal
= Stem::calc_stem_info (last_visible_stem (me
)).idealy_f_
;
383 Real lengthened
= gh_scm2double (me
->get_grob_property ("outer-stem-length-limit"));
384 Real steep
= gh_scm2double (me
->get_grob_property ("slope-limit"));
386 // ugh -> use commonx
387 Real dx
= last_visible_stem (me
)->relative_coordinate (0, X_AXIS
) - first_visible_stem (me
)->relative_coordinate (0, X_AXIS
);
388 Real dydx
= dy
&& dx
? dy
/dx
: 0;
390 if (( (y
- first_ideal
> lengthened
) && (dydx
> steep
))
391 || ((y
+ dy
- last_ideal
> lengthened
) && (dydx
< -steep
)))
393 Real adjusted_y
= y
+ dy
/ 2;
394 /* Store true, not dir-corrected values */
395 me
->set_grob_property ("y", gh_double2scm (adjusted_y
* dir
));
396 me
->set_grob_property ("dy", gh_double2scm (0));
398 return SCM_UNSPECIFIED
;
402 This neat trick is by Werner Lemberg,
403 damped = tanh (slope)
404 corresponds with some tables in [Wanske]
406 MAKE_SCHEME_CALLBACK (Beam
, slope_damping
, 1);
408 Beam::slope_damping (SCM smob
)
410 Grob
*me
= unsmob_grob (smob
);
412 if (visible_stem_count (me
) <= 1)
413 return SCM_UNSPECIFIED
;
415 SCM s
= me
->get_grob_property ("damping");
416 int damping
= gh_scm2int (s
);
420 /* y,dy in this function are corrected for beam-dir */
421 Direction dir
= Directional_element_interface::get (me
);
422 Real y
= gh_scm2double (me
->get_grob_property ("y")) * dir
;
423 Real dy
= gh_scm2double (me
->get_grob_property ("dy")) * dir
;
425 // ugh -> use commonx
426 Real dx
= last_visible_stem (me
)->relative_coordinate (0, X_AXIS
)
427 - first_visible_stem (me
)->relative_coordinate (0, X_AXIS
);
428 Real dydx
= dy
&& dx
? dy
/dx
: 0;
429 dydx
= 0.6 * tanh (dydx
) / damping
;
431 Real damped_dy
= dydx
* dx
;
432 Real adjusted_y
= y
+ (dy
- damped_dy
) / 2;
433 /* Store true, not dir-corrected values */
434 me
->set_grob_property ("y", gh_double2scm (adjusted_y
* dir
));
435 me
->set_grob_property ("dy", gh_double2scm (damped_dy
* dir
));
437 return SCM_UNSPECIFIED
;
441 Quantise dy (height) of beam.
442 Generalisation of [Ross].
444 MAKE_SCHEME_CALLBACK (Beam
, quantise_dy
, 1);
446 Beam::quantise_dy (SCM smob
)
448 Grob
*me
= unsmob_grob (smob
);
450 if (visible_stem_count (me
) <= 1)
451 return SCM_UNSPECIFIED
;
454 SCM proc
= me
->get_grob_property ("height-quants");
455 SCM quants
= gh_call2 (proc
, me
->self_scm (),
456 gh_double2scm (me
->paper_l ()->get_var ("stafflinethickness")
459 for (SCM s
= quants
; gh_pair_p (s
); s
= gh_cdr (s
))
460 a
.push (gh_scm2double (gh_car (s
)));
464 /* y,dy in this function are corrected for beam-dir */
465 Direction dir
= Directional_element_interface::get (me
);
466 Real y
= gh_scm2double (me
->get_grob_property ("y")) * dir
;
467 Real dy
= gh_scm2double (me
->get_grob_property ("dy")) * dir
;
469 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
471 Interval iv
= quantise_iv (a
, abs (dy
)/staff_space
) * staff_space
;
472 Real q
= (abs (dy
) - iv
[SMALLER
] <= iv
[BIGGER
] - abs (dy
))
476 Real quantised_dy
= q
* sign (dy
);
477 Real adjusted_y
= y
+ (dy
- quantised_dy
) / 2;
478 /* Store true, not dir-corrected values */
479 me
->set_grob_property ("y", gh_double2scm (adjusted_y
* dir
));
480 me
->set_grob_property ("dy", gh_double2scm (quantised_dy
* dir
));
482 return SCM_UNSPECIFIED
;
485 /* It's tricky to have the user override y,dy directly, so we use this
486 translation func. Also, if our staff_space != 1 (smaller staff, eg),
487 user will expect staff-position to be discrete values. */
488 MAKE_SCHEME_CALLBACK (Beam
, user_override
, 1);
490 Beam::user_override (SCM smob
)
492 Grob
*me
= unsmob_grob (smob
);
493 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
495 SCM s
= me
->get_grob_property ("staff-position");
498 Real y
= gh_scm2double (s
) * staff_space
;
499 me
->set_grob_property ("y", gh_double2scm (y
));
502 /* Name suggestions? Tilt, slope, vertical-* ? */
503 s
= me
->get_grob_property ("height");
506 Real dy
= gh_scm2double (s
) * staff_space
;
507 me
->set_grob_property ("dy", gh_double2scm (dy
));
510 return SCM_UNSPECIFIED
;
514 Ugh, this must be last, after user_override
515 Assumes directionised y/dy.
517 MAKE_SCHEME_CALLBACK (Beam
, do_quantise_y
, 1);
519 Beam::do_quantise_y (SCM smob
)
521 Grob
*me
= unsmob_grob (smob
);
524 If the user set y-position, we shouldn't do quanting.
526 if (gh_number_p (me
->get_grob_property ("y-position-hs")))
527 return SCM_UNSPECIFIED
;
529 Real y
= gh_scm2double (me
->get_grob_property ("y"));
530 Real dy
= gh_scm2double (me
->get_grob_property ("dy"));
532 /* we can modify y, so we should quantise y */
533 Real half_space
= Staff_symbol_referencer::staff_space (me
) / 2;
534 Real y_shift
= check_stem_length_f (me
, y
, dy
);
536 y
= quantise_y_f (me
, y
, dy
, 0);
539 Hmm, this is a bit keyhole operation: we're passing `this' as a
540 parameter, and member vars as SCM properties. We should decide on
541 SCM/C/C++ boundary */
542 me
->set_grob_property ("y", gh_double2scm (y
));
543 set_stem_lengths (me
);
544 y
= gh_scm2double (me
->get_grob_property ("y"));
546 y_shift
= check_stem_length_f (me
, y
, dy
);
548 if (y_shift
> half_space
/ 4)
553 for significantly lengthened or shortened stems,
554 request quanting the other way.
557 if (abs (y_shift
) > half_space
/ 2)
558 quant_dir
= sign (y_shift
) * Directional_element_interface::get (me
);
559 y
= quantise_y_f (me
, y
, dy
, quant_dir
);
562 me
->set_grob_property ("y", gh_double2scm (y
));
563 // me->set_grob_property ("dy", gh_double2scm (dy));
564 return SCM_UNSPECIFIED
;
569 Beam::calc_stem_y_f (Grob
*me
,Item
* s
, Real y
, Real dy
)
571 int beam_multiplicity
= get_multiplicity (me
);
572 int stem_multiplicity
= (Stem::flag_i (s
) - 2) >? 0;
574 SCM space_proc
= me
->get_grob_property ("space-function");
575 SCM space
= gh_call1 (space_proc
, gh_int2scm (beam_multiplicity
));
577 Real thick
= gh_scm2double (me
->get_grob_property ("thickness")) ;
578 Real interbeam_f
= gh_scm2double (space
) ;
580 // ugh -> use commonx
581 Real x0
= first_visible_stem (me
)->relative_coordinate (0, X_AXIS
);
582 Real dx
= last_visible_stem (me
)->relative_coordinate (0, X_AXIS
) - x0
;
583 Real stem_y
= (dy
&& dx
? (s
->relative_coordinate (0, X_AXIS
) - x0
) / dx
* dy
: 0) + y
;
586 Direction dir
= Directional_element_interface::get (me
);
587 Direction sdir
= Directional_element_interface::get (s
);
593 * (thick
/ 2 + (beam_multiplicity
- 1) * interbeam_f
);
597 // huh, why not for first visible?
598 if (Staff_symbol_referencer::staff_symbol_l (s
)
599 != Staff_symbol_referencer::staff_symbol_l (last_visible_stem (me
)))
600 stem_y
+= Directional_element_interface::get (me
)
601 * (beam_multiplicity
- stem_multiplicity
) * interbeam_f
;
608 Beam::check_stem_length_f (Grob
*me
,Real y
, Real dy
)
612 Direction dir
= Directional_element_interface::get (me
);
614 Link_array
<Item
> stems
=
615 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
617 for (int i
=0; i
< stems
.size (); i
++)
620 if (Stem::invisible_b (s
))
623 Real stem_y
= calc_stem_y_f (me
, s
, y
, dy
);
626 Stem_info info
= Stem::calc_stem_info (s
);
628 // if (0 > info.maxy_f_ - stem_y)
629 shorten
= shorten
<? info
.maxy_f_
- stem_y
;
630 // if (0 < info.miny_f_ - stem_y)
631 lengthen
= lengthen
>? info
.miny_f_
- stem_y
;
634 if (lengthen
&& shorten
)
635 warning (_ ("weird beam vertical offset"));
637 /* when all stems are too short, normal stems win */
638 return dir
* ((shorten
) ? shorten
: lengthen
);
642 Hmm. At this time, beam position and slope are determined. Maybe,
643 stem directions and length should set to relative to the chord's
644 position of the beam. */
646 Beam::set_stem_lengths (Grob
*me
)
648 if (visible_stem_count (me
) <= 1)
651 Real y
= gh_scm2double (me
->get_grob_property ("y"));
652 Real dy
= gh_scm2double (me
->get_grob_property ("dy"));
654 Real half_space
= Staff_symbol_referencer::staff_space (me
)/2;
655 Link_array
<Item
> stems
=
656 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
658 Grob
*common
= me
->common_refpoint (stems
[0], Y_AXIS
);
659 for (int i
=1; i
< stems
.size (); i
++)
660 if (!Stem::invisible_b (stems
[i
]))
661 common
= common
->common_refpoint (stems
[i
], Y_AXIS
);
663 for (int i
=0; i
< stems
.size (); i
++)
666 if (Stem::invisible_b (s
))
669 Real stem_y
= calc_stem_y_f (me
, s
, y
, dy
);
671 /* caution: stem measures in staff-positions */
672 Real id
= me
->relative_coordinate (common
, Y_AXIS
)
673 - stems
[i
]->relative_coordinate (common
, Y_AXIS
);
674 Stem::set_stemend (s
, (stem_y
+ id
) / half_space
);
679 Prevent interference from stafflines and beams.
681 We only need to quantise the (left) y of the beam,
682 since dy is quantised too.
683 if extend_b then stems must *not* get shorter
686 Beam::quantise_y_f (Grob
*me
,Real y
, Real dy
, int quant_dir
)
688 int multiplicity
= get_multiplicity (me
);
690 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
691 Real thick
= me
->paper_l ()->get_var ("stafflinethickness");
694 SCM proc
= me
->get_grob_property ("vertical-position-quant-function");
695 SCM quants
= scm_apply (proc
,
697 gh_list (gh_int2scm (multiplicity
),
698 gh_double2scm (dy
/staff_space
),
699 gh_double2scm (thick
/staff_space
),
700 SCM_EOL
, SCM_UNDEFINED
));
704 for (; gh_pair_p (quants
); quants
= gh_cdr (quants
))
705 a
.push (gh_scm2double (gh_car (quants
)));
710 Real up_y
= Directional_element_interface::get (me
) * y
;
711 Interval iv
= quantise_iv (a
, up_y
/staff_space
) * staff_space
;
713 Real q
= up_y
- iv
[SMALLER
] <= iv
[BIGGER
] - up_y
714 ? iv
[SMALLER
] : iv
[BIGGER
];
716 q
= iv
[ (Direction
)quant_dir
];
718 return q
* Directional_element_interface::get (me
);
722 Beam::set_beaming (Grob
*me
,Beaming_info_list
*beaming
)
724 Link_array
<Grob
> stems
=
725 Pointer_group_interface__extract_elements (me
, (Grob
*)0, "stems");
728 for (int i
=0; i
< stems
.size (); i
++)
732 /* Don't overwrite user override (?) */
733 if (Stem::beam_count (stems
[i
], d
) == 0
734 /* Don't set beaming for outside of outer stems */
735 && ! (d
== LEFT
&& i
== 0)
736 && ! (d
== RIGHT
&& i
== stems
.size () -1))
738 int b
= beaming
->infos_
.elem (i
).beams_i_drul_
[d
];
739 Stem::set_beaming (stems
[i
], b
, d
);
742 while (flip (&d
) != LEFT
);
749 beams to go with one stem.
754 Beam::stem_beams (Grob
*me
,Item
*here
, Item
*next
, Item
*prev
,
758 // ugh -> use commonx
759 if ((next
&& ! (next
->relative_coordinate (0, X_AXIS
) > here
->relative_coordinate (0, X_AXIS
))) ||
760 (prev
&& ! (prev
->relative_coordinate (0, X_AXIS
) < here
->relative_coordinate (0, X_AXIS
))))
761 programming_error ("Beams are not left-to-right");
763 Real staffline_f
= me
->paper_l ()->get_var ("stafflinethickness");
764 int multiplicity
= get_multiplicity (me
);
766 SCM space_proc
= me
->get_grob_property ("space-function");
767 SCM space
= gh_call1 (space_proc
, gh_int2scm (multiplicity
));
769 Real thick
= gh_scm2double (me
->get_grob_property ("thickness")) ;
770 Real interbeam_f
= gh_scm2double (space
) ;
772 Real bdy
= interbeam_f
;
773 Real stemdx
= staffline_f
;
775 // ugh -> use commonx
776 Real dx
= visible_stem_count (me
) ?
777 last_visible_stem (me
)->relative_coordinate (0, X_AXIS
) - first_visible_stem (me
)->relative_coordinate (0, X_AXIS
)
784 if (!Stem::first_head (here
))
787 int t
= Stem::type_i (here
);
789 SCM proc
= me
->get_grob_property ("flag-width-function");
790 SCM result
= gh_call1 (proc
, gh_int2scm (t
));
791 nw_f
= gh_scm2double (result
);
795 Direction dir
= Directional_element_interface::get (me
);
797 /* half beams extending to the left. */
800 int lhalfs
= lhalfs
= Stem::beam_count (here
,LEFT
) - Stem::beam_count (prev
,RIGHT
);
801 int lwholebeams
= Stem::beam_count (here
,LEFT
) <? Stem::beam_count (prev
,RIGHT
) ;
803 Half beam should be one note-width,
804 but let's make sure two half-beams never touch
806 Real w
= here
->relative_coordinate (0, X_AXIS
) - prev
->relative_coordinate (0, X_AXIS
);
809 if (lhalfs
) // generates warnings if not
810 a
= Lookup::beam (dydx
, w
, thick
);
811 a
.translate (Offset (-w
, -w
* dydx
));
812 for (int j
= 0; j
< lhalfs
; j
++)
815 b
.translate_axis (-dir
* bdy
* (lwholebeams
+j
), Y_AXIS
);
816 leftbeams
.add_molecule (b
);
822 int rhalfs
= Stem::beam_count (here
,RIGHT
) - Stem::beam_count (next
,LEFT
);
823 int rwholebeams
= Stem::beam_count (here
,RIGHT
) <? Stem::beam_count (next
,LEFT
) ;
825 Real w
= next
->relative_coordinate (0, X_AXIS
) - here
->relative_coordinate (0, X_AXIS
);
826 Molecule a
= Lookup::beam (dydx
, w
+ stemdx
, thick
);
827 a
.translate_axis (- stemdx
/2, X_AXIS
);
831 SCM gap
= me
->get_grob_property ("gap");
832 if (gh_number_p (gap
))
834 int gap_i
= gh_scm2int ((gap
));
835 int nogap
= rwholebeams
- gap_i
;
837 for (; j
< nogap
; j
++)
840 b
.translate_axis (-dir
* bdy
* j
, Y_AXIS
);
841 rightbeams
.add_molecule (b
);
843 // TODO: notehead widths differ for different types
846 a
= Lookup::beam (dydx
, w
+ stemdx
, thick
);
849 for (; j
< rwholebeams
; j
++)
852 b
.translate (Offset (Stem::invisible_b (here
) ? 0 : gap_f
, -dir
* bdy
* j
));
853 rightbeams
.add_molecule (b
);
858 a
= Lookup::beam (dydx
, w
, thick
);
860 for (; j
< rwholebeams
+ rhalfs
; j
++)
863 b
.translate_axis (- dir
* bdy
* j
, Y_AXIS
);
864 rightbeams
.add_molecule (b
);
868 leftbeams
.add_molecule (rightbeams
);
871 Does beam quanting think of the asymetry of beams?
872 Refpoint is on bottom of symbol. (FIXTHAT) --hwn.
877 MAKE_SCHEME_CALLBACK (Beam
,brew_molecule
,1);
879 Beam::brew_molecule (SCM smob
)
881 Grob
* me
=unsmob_grob (smob
);
884 if (!gh_pair_p (me
->get_grob_property ("stems")))
887 Link_array
<Item
>stems
=
888 Pointer_group_interface__extract_elements (me
, (Item
*) 0, "stems");
889 if (visible_stem_count (me
))
891 // ugh -> use commonx
892 x0
= first_visible_stem (me
)->relative_coordinate (0, X_AXIS
);
893 dx
= last_visible_stem (me
)->relative_coordinate (0, X_AXIS
) - x0
;
897 x0
= stems
[0]->relative_coordinate (0, X_AXIS
);
898 dx
= stems
.top ()->relative_coordinate (0, X_AXIS
) - x0
;
904 TODO: the naming of the grob properties sucks.
906 SCM dy_s
= me
->get_grob_property ("dy");
907 SCM y_s
= me
->get_grob_property ("y");
910 Real dy
= gh_number_p (dy_s
) ? gh_scm2double (dy_s
) : 0.0;
911 Real dydx
= dy
&& dx
? dy
/dx
: 0;
912 Real y
= gh_number_p (y_s
) ? gh_scm2double (y_s
) : 0.0;
915 for (int j
=0; j
<stems
.size (); j
++)
918 Item
* prev
= (j
> 0)? stems
[j
-1] : 0;
919 Item
* next
= (j
< stems
.size ()-1) ? stems
[j
+1] :0;
921 Molecule sb
= stem_beams (me
, i
, next
, prev
, dy
, dydx
);
922 Real x
= i
->relative_coordinate (0, X_AXIS
)-x0
;
923 sb
.translate (Offset (x
, x
* dydx
+ y
));
924 mol
.add_molecule (sb
);
926 mol
.translate_axis (x0
927 - dynamic_cast<Spanner
*> (me
)->get_bound (LEFT
)->relative_coordinate (0, X_AXIS
), X_AXIS
);
929 return mol
.smobbed_copy ();
933 Beam::forced_stem_count (Grob
*me
)
935 Link_array
<Item
>stems
=
936 Pointer_group_interface__extract_elements (me
, (Item
*) 0, "stems");
938 for (int i
=0; i
< stems
.size (); i
++)
942 if (Stem::invisible_b (s
))
945 if (( (int)Stem::chord_start_f (s
))
946 && (Stem::get_direction (s
) != Stem::get_default_dir (s
)))
956 use filter and standard list functions.
959 Beam::visible_stem_count (Grob
*me
)
961 Link_array
<Item
>stems
=
962 Pointer_group_interface__extract_elements (me
, (Item
*) 0, "stems");
964 for (int i
= stems
.size (); i
--;)
966 if (!Stem::invisible_b (stems
[i
]))
973 Beam::first_visible_stem (Grob
*me
)
975 Link_array
<Item
>stems
=
976 Pointer_group_interface__extract_elements (me
, (Item
*) 0, "stems");
978 for (int i
= 0; i
< stems
.size (); i
++)
980 if (!Stem::invisible_b (stems
[i
]))
987 Beam::last_visible_stem (Grob
*me
)
989 Link_array
<Item
>stems
=
990 Pointer_group_interface__extract_elements (me
, (Item
*) 0, "stems");
991 for (int i
= stems
.size (); i
--;)
993 if (!Stem::invisible_b (stems
[i
]))
1002 handle rest under beam (do_post: beams are calculated now)
1003 what about combination of collisions and rest under beam.
1007 rest -> stem -> beam -> interpolate_y_position ()
1009 MAKE_SCHEME_CALLBACK (Beam
,rest_collision_callback
,2);
1011 Beam::rest_collision_callback (SCM element_smob
, SCM axis
)
1013 Grob
*rest
= unsmob_grob (element_smob
);
1014 Axis a
= (Axis
) gh_scm2int (axis
);
1016 assert (a
== Y_AXIS
);
1018 Grob
* st
= unsmob_grob (rest
->get_grob_property ("stem"));
1021 return gh_double2scm (0.0);
1022 Grob
* beam
= unsmob_grob (stem
->get_grob_property ("beam"));
1023 if (!beam
|| !Beam::has_interface (beam
) || !Beam::visible_stem_count (beam
))
1024 return gh_double2scm (0.0);
1026 // make callback for rest from this.
1031 // todo: make sure this calced already.
1032 SCM s
= beam
->get_grob_property ("dy");
1033 if (gh_number_p (s
))
1034 beam_dy
= gh_scm2double (s
);
1036 s
= beam
->get_grob_property ("y");
1037 if (gh_number_p (s
))
1038 beam_y
= gh_scm2double (s
);
1040 // ugh -> use commonx
1041 Real x0
= first_visible_stem (beam
)->relative_coordinate (0, X_AXIS
);
1042 Real dx
= last_visible_stem (beam
)->relative_coordinate (0, X_AXIS
) - x0
;
1043 Real dydx
= beam_dy
&& dx
? beam_dy
/dx
: 0;
1045 Direction d
= Stem::get_direction (stem
);
1046 Real beamy
= (stem
->relative_coordinate (0, X_AXIS
) - x0
) * dydx
+ beam_y
;
1048 Real staff_space
= Staff_symbol_referencer::staff_space (rest
);
1051 Real rest_dim
= rest
->extent (rest
, Y_AXIS
)[d
]*2.0 / staff_space
; // refp??
1054 = gh_scm2double (rest
->get_grob_property ("minimum-beam-collision-distance"));
1056 minimum_dist
+ -d
* (beamy
- rest_dim
) >? 0;
1058 int stafflines
= Staff_symbol_referencer::line_count (rest
);
1060 // move discretely by half spaces.
1061 int discrete_dist
= int (ceil (dist
));
1063 // move by whole spaces inside the staff.
1064 if (discrete_dist
< stafflines
+1)
1065 discrete_dist
= int (ceil (discrete_dist
/ 2.0)* 2.0);
1067 return gh_double2scm (-d
* discrete_dist
);
1072 Beam::has_interface (Grob
*me
)
1074 return me
->has_interface (ly_symbol2scm ("beam-interface"));