* python/lilylib.py (setup_temp): temporary directories are mode 700.
[lilypond.git] / lily / stem.cc
blob7a63f20b7c5eeb0e5d6a8f023f11ca07faadc34e
1 /*
2 stem.cc -- implement Stem
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
9 TODO: This is way too hairy
11 TODO: fix naming.
13 Stem-end, chord-start, etc. is all confusing naming.
16 #include <math.h> // rint
18 #include "lookup.hh"
19 #include "directional-element-interface.hh"
20 #include "note-head.hh"
21 #include "stem.hh"
22 #include "warn.hh"
23 #include "paper-def.hh"
24 #include "rhythmic-head.hh"
25 #include "font-interface.hh"
26 #include "molecule.hh"
27 #include "paper-column.hh"
28 #include "misc.hh"
29 #include "beam.hh"
30 #include "rest.hh"
31 #include "group-interface.hh"
32 #include "staff-symbol-referencer.hh"
33 #include "spanner.hh"
34 #include "side-position-interface.hh"
35 #include "dot-column.hh"
37 void
38 Stem::set_beaming (Grob*me, int beam_count, Direction d)
40 SCM pair = me->get_grob_property ("beaming");
42 if (!gh_pair_p (pair))
44 pair = gh_cons (SCM_EOL, SCM_EOL);
45 me->set_grob_property ("beaming", pair);
48 SCM l = index_get_cell (pair, d);
49 for( int i = 0; i< beam_count; i++)
51 l = gh_cons (gh_int2scm (i), l);
53 index_set_cell (pair, d, l);
57 Interval
58 Stem::head_positions (Grob*me)
60 if (!head_count (me))
62 Interval iv;
63 return iv;
66 Drul_array<Grob*> e (extremal_heads (me));
68 return Interval (Staff_symbol_referencer::get_position (e[DOWN]),
69 Staff_symbol_referencer::get_position (e[UP]));
73 Real
74 Stem::chord_start_y (Grob*me)
76 return head_positions (me)[get_direction (me)]
77 * Staff_symbol_referencer::staff_space (me)/2.0;
80 Real
81 Stem::stem_end_position (Grob*me)
83 SCM p =me->get_grob_property ("stem-end-position");
84 Real pos;
85 if (!gh_number_p (p))
87 pos = get_default_stem_end_position (me);
88 me->set_grob_property ("stem-end-position", gh_double2scm (pos));
90 else
91 pos = gh_scm2double (p);
93 return pos;
96 Direction
97 Stem::get_direction (Grob*me)
99 Direction d = Directional_element_interface::get (me);
101 if (!d)
103 d = get_default_dir (me);
104 // urg, AAARGH!
105 Directional_element_interface::set (me, d);
107 return d ;
111 void
112 Stem::set_stemend (Grob*me, Real se)
114 // todo: margins
115 Direction d= get_direction (me);
117 if (d && d * head_positions (me)[get_direction (me)] >= se*d)
118 me->warning (_ ("Weird stem size; check for narrow beams"));
120 me->set_grob_property ("stem-end-position", gh_double2scm (se));
125 Note head that determines hshift for upstems
127 WARNING: triggers direction
129 Grob*
130 Stem::support_head (Grob*me)
132 SCM h = me->get_grob_property ("support-head");
133 Grob * nh = unsmob_grob (h);
134 if (nh)
135 return nh;
136 else if (head_count (me) == 1)
139 UGH.
142 return unsmob_grob (ly_car (me->get_grob_property ("note-heads")));
144 else
145 return first_head (me);
150 Stem::head_count (Grob*me)
152 return Pointer_group_interface::count (me, "note-heads");
156 The note head which forms one end of the stem.
158 WARNING: triggers direction
160 Grob*
161 Stem::first_head (Grob*me)
163 Direction d = get_direction (me);
164 if (!d)
165 return 0;
166 return extremal_heads (me)[-d];
170 The note head opposite to the first head.
172 Grob*
173 Stem::last_head (Grob*me)
175 Direction d = get_direction (me);
176 if (!d)
177 return 0;
178 return extremal_heads (me)[d];
182 START is part where stem reaches `last' head.
184 Drul_array<Grob*>
185 Stem::extremal_heads (Grob*me)
187 const int inf = 1000000;
188 Drul_array<int> extpos;
189 extpos[DOWN] = inf;
190 extpos[UP] = -inf;
192 Drul_array<Grob *> exthead;
193 exthead[LEFT] = exthead[RIGHT] =0;
195 for (SCM s = me->get_grob_property ("note-heads"); gh_pair_p (s); s = ly_cdr (s))
197 Grob * n = unsmob_grob (ly_car (s));
200 int p = int (Staff_symbol_referencer::get_position (n));
202 Direction d = LEFT;
203 do {
204 if (d* p > d* extpos[d])
206 exthead[d] = n;
207 extpos[d] = p;
209 } while (flip (&d) != DOWN);
212 return exthead;
215 static int
216 icmp (int const &a, int const &b)
218 return a-b;
221 Array<int>
222 Stem::note_head_positions (Grob *me)
224 Array<int> ps ;
225 for (SCM s = me->get_grob_property ("note-heads"); gh_pair_p (s); s = ly_cdr (s))
227 Grob * n = unsmob_grob (ly_car (s));
228 int p = int (Staff_symbol_referencer::get_position (n));
230 ps.push (p);
233 ps.sort (icmp);
234 return ps;
238 void
239 Stem::add_head (Grob*me, Grob *n)
241 n->set_grob_property ("stem", me->self_scm ());
242 n->add_dependency (me);
244 if (Note_head::has_interface (n))
246 Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-heads"), n);
250 bool
251 Stem::invisible_b (Grob*me)
253 return ! (head_count (me)
254 && gh_scm2int (me->get_grob_property ("duration-log")) >= 1);
257 Direction
258 Stem::get_default_dir (Grob*me)
260 int staff_center = 0;
261 Interval hp = head_positions (me);
262 if (hp.empty_b())
264 return CENTER;
267 int udistance = (int) (UP * hp[UP] - staff_center);
268 int ddistance = (int) (DOWN* hp[DOWN] - staff_center);
270 if (sign (ddistance - udistance))
271 return Direction (sign (ddistance -udistance));
273 return to_dir (me->get_grob_property ("neutral-direction"));
276 Real
277 Stem::get_default_stem_end_position (Grob*me)
279 /* Tab notation feature: make stem end extend out of staff. */
280 SCM up_to_staff = me->get_grob_property ("up-to-staff");
281 if (to_boolean (up_to_staff))
283 int line_count = Staff_symbol_referencer::line_count (me);
284 Direction dir = get_direction (me);
285 return dir * (line_count + 3.5);
288 bool grace_b = to_boolean (me->get_grob_property ("grace"));
289 SCM s;
290 Array<Real> a;
292 Real length_f = 3.5;
293 SCM scm_len = me->get_grob_property ("length");
294 if (gh_number_p (scm_len))
296 length_f = gh_scm2double (scm_len);
298 else
300 s = me->get_grob_property ("lengths");
301 if (gh_pair_p (s))
303 length_f = 2* gh_scm2double (robust_list_ref (duration_log(me) -2, s));
307 Real shorten_f = 0.0;
309 SCM sshorten = me->get_grob_property ("stem-shorten");
310 if (gh_pair_p (sshorten))
312 shorten_f = 2* gh_scm2double (robust_list_ref ((duration_log (me) - 2) >? 0, sshorten));
315 /* On boundary: shorten only half */
316 if (abs (chord_start_y (me)) == 0.5)
317 shorten_f *= 0.5;
319 /* URGURGURG
320 'set-default-stemlen' sets direction too
322 Direction dir = get_direction (me);
323 if (!dir)
325 dir = get_default_dir (me);
326 Directional_element_interface::set (me, dir);
329 /* stems in unnatural (forced) direction should be shortened,
330 according to [Roush & Gourlay] */
331 if (chord_start_y (me)
332 && (get_direction (me) != get_default_dir (me)))
333 length_f -= shorten_f;
335 Interval hp = head_positions (me);
336 Real st = hp[dir] + dir * length_f;
340 TODO: change name to extend-stems to staff/center/'()
342 bool no_extend_b = to_boolean (me->get_grob_property ("no-stem-extend"));
343 if (!grace_b && !no_extend_b && dir * st < 0) // junkme?
344 st = 0.0;
347 Make a little room if we have a upflag and there is a dot.
348 previous approach was to lengthen the stem. This is not
349 good typesetting practice.
352 if (!get_beam (me) && dir == UP
353 && duration_log (me) > 2)
355 Grob * closest_to_flag = extremal_heads (me)[dir];
356 Grob * dots = closest_to_flag
357 ? Rhythmic_head::get_dots (closest_to_flag ) : 0;
359 if (dots)
361 Real dp = Staff_symbol_referencer::get_position (dots);
362 Real flagy = flag (me).extent (Y_AXIS)[-dir] * 2
363 / Staff_symbol_referencer::staff_space (me);
366 Very gory: add myself to the X-support of the parent,
367 which should be a dot-column.
369 if (dir * (st + flagy - dp) < 0.5)
371 Grob *par = dots->get_parent (X_AXIS);
373 if (Dot_column::has_interface (par))
375 Side_position_interface::add_support (par, me);
378 TODO: apply some better logic here. The flag is
379 curved inwards, so this will typically be too
380 much.
388 return st;
395 the log of the duration (Number of hooks on the flag minus two)
398 Stem::duration_log (Grob*me)
400 SCM s = me->get_grob_property ("duration-log");
401 return (gh_number_p (s)) ? gh_scm2int (s) : 2;
404 void
405 Stem::position_noteheads (Grob*me)
407 if (!head_count (me))
408 return;
410 Link_array<Grob> heads =
411 Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-heads");
413 heads.sort (compare_position);
414 Direction dir =get_direction (me);
416 if (dir < 0)
417 heads.reverse ();
420 bool invisible = invisible_b (me);
421 Real thick = gh_scm2double (me->get_grob_property ("thickness"))
422 * me->get_paper ()->get_var ("linethickness");
425 Grob *hed = support_head (me);
426 Real w = Note_head::head_extent (hed,X_AXIS)[dir];
427 for (int i=0; i < heads.size (); i++)
429 heads[i]->translate_axis (w - Note_head::head_extent (heads[i],X_AXIS)[dir],
430 X_AXIS);
433 bool parity= true; // todo: make me settable.
434 int lastpos = int (Staff_symbol_referencer::get_position (heads[0]));
435 for (int i=1; i < heads.size (); i ++)
437 Real p = Staff_symbol_referencer::get_position (heads[i]);
438 int dy =abs (lastpos- (int)p);
440 if (dy <= 1)
442 if (parity)
444 Real l = Note_head::head_extent (heads[i], X_AXIS).length ();
446 Direction d = get_direction (me);
447 /* reversed head should be shifted l-thickness, but this looks
448 too crowded, so we only shift l-0.5*thickness.
449 Notice that this leads to assymetry: Normal heads overlap
450 the stem 100% whereas reversed heads only overlaps the stem
451 50% */
452 #define magic 0.5
453 heads[i]->translate_axis ((l-thick*magic) * d, X_AXIS);
455 if (invisible_b(me))
456 heads[i]->translate_axis (-thick*(2-magic) * d , X_AXIS);
459 /* TODO:
461 For some cases we should kern some more: when the
462 distance between the next or prev note is too large, we'd
463 get large white gaps, eg.
467 |X <- kern this.
473 parity = !parity;
475 else
476 parity = true;
478 lastpos = int (p);
482 MAKE_SCHEME_CALLBACK (Stem,before_line_breaking,1);
484 Stem::before_line_breaking (SCM smob)
486 Grob*me = unsmob_grob (smob);
490 Do the calculations for visible stems, but also for invisible stems
491 with note heads (i.e. half notes.)
493 if (head_count (me))
495 stem_end_position (me); // ugh. Trigger direction calc.
496 position_noteheads (me);
498 else
500 me->set_grob_property ("molecule-callback", SCM_EOL);
503 return SCM_UNSPECIFIED;
507 ugh.
508 When in a beam with tuplet brackets, brew_mol is called early,
509 caching a wrong value.
511 MAKE_SCHEME_CALLBACK (Stem, height, 2);
513 Stem::height (SCM smob, SCM ax)
515 Axis a = (Axis)gh_scm2int (ax);
516 Grob * me = unsmob_grob (smob);
517 assert (a == Y_AXIS);
519 SCM mol = me->get_uncached_molecule ();
520 Interval iv;
521 if (mol != SCM_EOL)
522 iv = unsmob_molecule (mol)->extent (a);
523 if (Grob *b =get_beam (me))
525 Direction d = get_direction (me);
526 iv[d] += d * Beam::get_thickness (b) /2.0 ;
529 return ly_interval2scm (iv);
533 Molecule
534 Stem::flag (Grob*me)
536 /* TODO: maybe property stroke-style should take different values,
537 e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
538 '() or "grace"). */
539 String flag_style;
541 SCM flag_style_scm = me->get_grob_property ("flag-style");
542 if (gh_symbol_p (flag_style_scm))
544 flag_style = ly_symbol2string (flag_style_scm);
547 if (flag_style == "no-flag")
549 return Molecule ();
552 bool adjust = to_boolean (me->get_grob_property ("adjust-if-on-staffline"));
554 String staffline_offs;
555 if (String::compare (flag_style, "mensural") == 0)
556 /* Mensural notation: For notes on staff lines, use different
557 flags than for notes between staff lines. The idea is that
558 flags are always vertically aligned with the staff lines,
559 regardless if the note head is on a staff line or between two
560 staff lines. In other words, the inner end of a flag always
561 touches a staff line.
564 if (adjust)
566 /* Urrgh! We have to detect wether this stem ends on a staff
567 line or between two staff lines. But we can not call
568 stem_end_position(me) or get_default_stem_end_position(me),
569 since this encounters the flag and hence results in an
570 infinite recursion. However, in pure mensural notation,
571 there are no multiple note heads attached to a single stem,
572 neither is there usually need for using the stem_shorten
573 property (except for 32th and 64th notes, but that is not a
574 problem since the stem length in this case is augmented by
575 an integral multiple of staff_space). Hence, it should be
576 sufficient to just take the first note head, assume it's
577 the only one, look if it's on a staff line, and select the
578 flag's shape accordingly. In the worst case, the shape
579 looks slightly misplaced, but that will usually be the
580 programmer's fault (e.g. when trying to attach multiple
581 note heads to a single stem in mensural notation). */
584 perhaps the detection whether this correction is needed should
585 happen in a different place to avoid the recursion.
587 --hwn.
589 int p = (int)rint (Staff_symbol_referencer::get_position (first_head (me)));
590 staffline_offs = Staff_symbol_referencer::on_staffline (me, p) ?
591 "1" : "0";
593 else
595 staffline_offs = "2";
598 else
600 staffline_offs = "";
603 char dir = (get_direction (me) == UP) ? 'u' : 'd';
604 String font_char =
605 flag_style + to_string (dir) + staffline_offs + to_string (duration_log (me));
606 Font_metric *fm = Font_interface::get_default_font (me);
607 Molecule flag = fm->find_by_name ("flags-" + font_char);
608 if (flag.empty_b ())
610 me->warning (_f ("flag `%s' not found", font_char));
613 SCM stroke_style_scm = me->get_grob_property ("stroke-style");
614 if (gh_string_p (stroke_style_scm))
616 String stroke_style = ly_scm2string (stroke_style_scm);
617 if (!stroke_style.empty_b ())
619 String font_char = to_string (dir) + stroke_style;
620 Molecule stroke = fm->find_by_name ("flags-" + font_char);
621 if (stroke.empty_b ())
623 me->warning (_f ("flag stroke `%s' not found", font_char));
625 else
627 flag.add_molecule (stroke);
632 return flag;
635 MAKE_SCHEME_CALLBACK (Stem,dim_callback,2);
637 Stem::dim_callback (SCM e, SCM ax)
639 Axis a = (Axis) gh_scm2int (ax);
640 assert (a == X_AXIS);
641 Grob *se = unsmob_grob (e);
642 Interval r (0, 0);
643 if (unsmob_grob (se->get_grob_property ("beam")) || abs (duration_log (se)) <= 2)
644 ; // TODO!
645 else
647 r = flag (se).extent (X_AXIS);
649 return ly_interval2scm (r);
654 MAKE_SCHEME_CALLBACK (Stem,brew_molecule,1);
657 Stem::brew_molecule (SCM smob)
659 Grob*me = unsmob_grob (smob);
660 Molecule mol;
661 Direction d = get_direction (me);
665 Real y1;
668 This is required to avoid stems passing in tablature chords...
673 TODO: make the stem start a direction ?
675 if (to_boolean (me->get_grob_property ("avoid-note-head")))
677 Grob * lh = last_head (me);
678 if (!lh)
679 return SCM_EOL;
680 y1 = Staff_symbol_referencer::get_position (lh);
682 else
684 Grob * lh = first_head (me);
685 if (!lh)
686 return SCM_EOL;
687 y1 = Staff_symbol_referencer::get_position (lh);
690 Real y2 = stem_end_position (me);
692 Interval stem_y (y1 <? y2,y2 >? y1);
695 // dy?
696 Real dy = Staff_symbol_referencer::staff_space (me) * 0.5;
698 if (Grob *hed = support_head (me))
701 must not take ledgers into account.
703 Interval head_height = Note_head::head_extent (hed,Y_AXIS);
704 Real y_attach = Note_head::stem_attachment_coordinate ( hed, Y_AXIS);
706 y_attach = head_height.linear_combination (y_attach);
707 stem_y[Direction (-d)] += d * y_attach/dy;
710 if (!invisible_b (me))
712 Real stem_width = gh_scm2double (me->get_grob_property ("thickness"))
713 // URG
714 * me->get_paper ()->get_var ("linethickness");
716 Molecule ss =Lookup::filledbox (Box (Interval (-stem_width/2, stem_width/2),
717 Interval (stem_y[DOWN]*dy, stem_y[UP]*dy)));
718 mol.add_molecule (ss);
721 if (!get_beam (me) && abs (duration_log (me)) > 2)
723 Molecule fl = flag (me);
724 fl.translate_axis (stem_y[d]*dy, Y_AXIS);
725 mol.add_molecule (fl);
728 return mol.smobbed_copy ();
732 move the stem to right of the notehead if it is up.
734 MAKE_SCHEME_CALLBACK (Stem,off_callback,2);
736 Stem::off_callback (SCM element_smob, SCM)
738 Grob *me = unsmob_grob (element_smob);
740 Real r=0;
742 if (head_count (me) == 0)
744 return gh_double2scm (0.0);
747 if (Grob * f = first_head (me))
749 Interval head_wid = Note_head::head_extent(f, X_AXIS);
752 Real attach =0.0;
754 if (invisible_b (me))
756 attach = 0.0;
758 else
759 attach = Note_head::stem_attachment_coordinate(f, X_AXIS);
761 Direction d = get_direction (me);
763 Real real_attach = head_wid.linear_combination (d * attach);
765 r = real_attach;
768 If not centered: correct for stem thickness.
770 if (attach)
772 Real rule_thick
773 = gh_scm2double (me->get_grob_property ("thickness"))
774 * me->get_paper ()->get_var ("linethickness");
777 r += - d * rule_thick * 0.5;
780 return gh_double2scm (r);
783 Grob*
784 Stem::get_beam (Grob*me)
786 SCM b= me->get_grob_property ("beam");
787 return unsmob_grob (b);
790 Stem_info
791 Stem::get_stem_info (Grob *me)
793 /* Return cached info if available */
794 SCM scm_info = me->get_grob_property ("stem-info");
795 if (!gh_pair_p (scm_info))
797 calc_stem_info (me);
798 scm_info = me->get_grob_property ("stem-info");
801 Stem_info si;
802 si.dir_ = Directional_element_interface::get (me);
803 si.ideal_y_ = gh_scm2double (gh_car (scm_info));
804 si.shortest_y_ = gh_scm2double (gh_cadr (scm_info));
805 return si;
808 void
809 Stem::calc_stem_info (Grob *me)
811 /* Tab notation feature: make stem end extend out of staff. */
812 SCM up_to_staff = me->get_grob_property ("up-to-staff");
813 if (to_boolean (up_to_staff))
815 int line_count = Staff_symbol_referencer::line_count (me);
816 Direction dir = get_direction (me);
817 Real ideal_y = dir * (line_count + 1.5);
818 Real shortest_y = ideal_y;
820 me->set_grob_property ("stem-info",
821 scm_list_n (gh_double2scm (ideal_y),
822 gh_double2scm (shortest_y),
823 SCM_UNDEFINED));
824 return;
827 Direction my_dir = Directional_element_interface::get (me);
828 Real staff_space = Staff_symbol_referencer::staff_space (me);
829 Grob *beam = get_beam (me);
830 Real beam_translation = Beam::get_beam_translation (beam);
831 Real beam_thickness = gh_scm2double (beam->get_grob_property ("thickness"));
832 int beam_count = Beam::get_direction_beam_count (beam, my_dir);
835 /* Simple standard stem length */
836 Real ideal_length =
837 gh_scm2double (robust_list_ref
838 (beam_count - 1,
839 me->get_grob_property ("beamed-lengths")))
840 * staff_space
841 /* stem only extends to center of beam */
842 - 0.5 * beam_thickness;
845 /* Condition: sane minimum free stem length (chord to beams) */
846 Real ideal_minimum_free =
847 gh_scm2double (robust_list_ref
848 (beam_count - 1,
849 me->get_grob_property ("beamed-minimum-free-lengths")))
850 * staff_space;
853 /* UGH
854 It seems that also for ideal minimum length, we must use
855 the maximum beam count (for this direction):
857 \score{ \notes\relative c''{ [a8 a32] }}
859 must be horizontal. */
860 Real height_of_my_beams = beam_thickness
861 + (beam_count - 1) * beam_translation;
863 Real ideal_minimum_length = ideal_minimum_free
864 + height_of_my_beams
865 /* stem only extends to center of beam */
866 - 0.5 * beam_thickness;
868 ideal_length = ideal_length >? ideal_minimum_length;
871 /* Convert to Y position, calculate for dir == UP */
872 Real note_start =
873 /* staff positions */
874 head_positions (me)[my_dir] * 0.5
875 * my_dir;
876 Real ideal_y = note_start + ideal_length;
879 /* Conditions for Y position */
881 /* Lowest beam of (UP) beam must never be lower than second staffline
883 Reference?
885 Although this (additional) rule is probably correct,
886 I expect that highest beam (UP) should also never be lower
887 than middle staffline, just as normal stems.
889 Reference?
891 Obviously not for grace beams.
893 Also, not for knees. Seems to be a good thing. */
894 SCM grace = me->get_grob_property ("grace");
895 bool grace_b = to_boolean (grace);
896 bool no_extend_b = to_boolean (me->get_grob_property ("no-stem-extend"));
897 bool knee_b = to_boolean (beam->get_grob_property ("knee"));
898 if (!grace_b && !no_extend_b && !knee_b)
900 /* Highest beam of (UP) beam must never be lower than middle
901 staffline */
902 ideal_y = ideal_y >? 0;
903 /* Lowest beam of (UP) beam must never be lower than second staffline */
904 ideal_y = ideal_y >? (-staff_space
905 - beam_thickness + height_of_my_beams);
909 SCM shorten = beam->get_grob_property ("shorten");
910 if (gh_number_p (shorten))
911 ideal_y -= gh_scm2double (shorten);
914 Real minimum_free =
915 gh_scm2double (robust_list_ref
916 (beam_count - 1,
917 me->get_grob_property
918 ("beamed-extreme-minimum-free-lengths")))
919 * staff_space;
921 Real minimum_length = minimum_free
922 + height_of_my_beams
923 /* stem only extends to center of beam */
924 - 0.5 * beam_thickness;
926 Real minimum_y = note_start + minimum_length;
929 ideal_y *= my_dir;
930 Real shortest_y = minimum_y * my_dir;
932 me->set_grob_property ("stem-info",
933 scm_list_n (gh_double2scm (ideal_y),
934 gh_double2scm (shortest_y),
935 SCM_UNDEFINED));
938 Slice
939 Stem::beam_multiplicity (Grob *stem)
941 SCM beaming= stem->get_grob_property ("beaming");
942 Slice l = int_list_to_slice (gh_car (beaming));
943 Slice r = int_list_to_slice (gh_cdr (beaming));
944 l.unite (r);
946 return l;
950 ADD_INTERFACE (Stem,"stem-interface",
951 "A stem",
952 "french-beaming up-to-staff avoid-note-head adjust-if-on-staffline thickness stem-info beamed-lengths beamed-minimum-free-lengths beamed-extreme-minimum-free-lengths lengths beam stem-shorten duration-log beaming neutral-direction stem-end-position support-head note-heads direction length flag-style no-stem-extend stroke-style");