* lily/music-iterator.cc (quit, do_quit): new function: break link
[lilypond.git] / lily / stem.cc
blob510ca1b60d38a3e300fbebd7cbd2e8fe4e838c0a
1 /*
2 stem.cc -- implement Stem
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2002 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 = 0.0;
422 if (invisible)
423 thick = gh_scm2double (me->get_grob_property ("thickness"))
424 * me->get_paper ()->get_var ("linethickness");
427 Grob *hed = support_head (me);
428 Real w = Note_head::head_extent (hed,X_AXIS)[dir];
429 for (int i=0; i < heads.size (); i++)
431 heads[i]->translate_axis (w - Note_head::head_extent (heads[i],X_AXIS)[dir],
432 X_AXIS);
435 bool parity= true; // todo: make me settable.
436 int lastpos = int (Staff_symbol_referencer::get_position (heads[0]));
437 for (int i=1; i < heads.size (); i ++)
439 Real p = Staff_symbol_referencer::get_position (heads[i]);
440 int dy =abs (lastpos- (int)p);
442 if (dy <= 1)
444 if (parity)
446 Real l = Note_head::head_extent (heads[i], X_AXIS).length ();
448 Direction d = get_direction (me);
449 heads[i]->translate_axis (l * d, X_AXIS);
451 if (invisible_b(me))
452 heads[i]->translate_axis (-thick *2* d , X_AXIS);
455 /* TODO:
457 For some cases we should kern some more: when the
458 distance between the next or prev note is too large, we'd
459 get large white gaps, eg.
463 |X <- kern this.
469 parity = !parity;
471 else
472 parity = true;
474 lastpos = int (p);
478 MAKE_SCHEME_CALLBACK (Stem,before_line_breaking,1);
480 Stem::before_line_breaking (SCM smob)
482 Grob*me = unsmob_grob (smob);
486 Do the calculations for visible stems, but also for invisible stems
487 with note heads (i.e. half notes.)
489 if (head_count (me))
491 stem_end_position (me); // ugh. Trigger direction calc.
492 position_noteheads (me);
494 else
496 me->set_grob_property ("molecule-callback", SCM_EOL);
499 return SCM_UNSPECIFIED;
503 ugh.
504 When in a beam with tuplet brackets, brew_mol is called early,
505 caching a wrong value.
507 MAKE_SCHEME_CALLBACK (Stem, height, 2);
509 Stem::height (SCM smob, SCM ax)
511 Axis a = (Axis)gh_scm2int (ax);
512 Grob * me = unsmob_grob (smob);
513 assert (a == Y_AXIS);
515 SCM mol = me->get_uncached_molecule ();
516 Interval iv;
517 if (mol != SCM_EOL)
518 iv = unsmob_molecule (mol)->extent (a);
519 if (Grob *b =get_beam (me))
521 Direction d = get_direction (me);
522 iv[d] += d * Beam::get_thickness (b) /2.0 ;
525 return ly_interval2scm (iv);
529 Molecule
530 Stem::flag (Grob*me)
532 /* TODO: rename flag-style into something more appropriate,
533 e.g. "stroke-style", maybe with values "" (i.e. no stroke),
534 "single" and "double". Needs more discussion.
536 String style, fstyle, staffline_offs;
537 SCM fst = me->get_grob_property ("flag-style");
538 if (gh_string_p (fst))
540 fstyle = ly_scm2string (fst);
543 SCM st = me->get_grob_property ("style");
544 if (gh_symbol_p (st))
546 style = (ly_scm2string (scm_symbol_to_string (st)));
548 else
550 style = "";
552 bool adjust = to_boolean (me->get_grob_property ("adjust-if-on-staffline"));
554 if (String::compare (style, "mensural") == 0)
555 /* Mensural notation: For notes on staff lines, use different
556 flags than for notes between staff lines. The idea is that
557 flags are always vertically aligned with the staff lines,
558 regardless if the note head is on a staff line or between two
559 staff lines. In other words, the inner end of a flag always
560 touches a staff line.
563 if (adjust)
565 /* Urrgh! We have to detect wether this stem ends on a staff
566 line or between two staff lines. But we can not call
567 stem_end_position(me) or get_default_stem_end_position(me),
568 since this encounters the flag and hence results in an
569 infinite recursion. However, in pure mensural notation,
570 there are no multiple note heads attached to a single stem,
571 neither is there usually need for using the stem_shorten
572 property (except for 32th and 64th notes, but that is not a
573 problem since the stem length in this case is augmented by
574 an integral multiple of staff_space). Hence, it should be
575 sufficient to just take the first note head, assume it's
576 the only one, look if it's on a staff line, and select the
577 flag's shape accordingly. In the worst case, the shape
578 looks slightly misplaced, but that will usually be the
579 programmer's fault (e.g. when trying to attach multiple
580 note heads to a single stem in mensural notation). */
583 perhaps the detection whether this correction is needed should
584 happen in a different place to avoid the recursion.
586 --hwn.
588 Grob *first = first_head(me);
589 int sz = Staff_symbol_referencer::line_count (me)-1;
590 int p = (int)rint (Staff_symbol_referencer::get_position (first));
591 staffline_offs = (((p ^ sz) & 0x1) == 0) ? "1" : "0";
593 else
595 staffline_offs = "2";
598 else
600 staffline_offs = "";
602 char c = (get_direction (me) == UP) ? 'u' : 'd';
603 String index_string
604 = String ("flags-") + style + to_string (c) + staffline_offs + to_string (duration_log (me));
605 Molecule m
606 = Font_interface::get_default_font (me)->find_by_name (index_string);
607 if (!fstyle.empty_b ())
608 m.add_molecule (Font_interface::get_default_font (me)->find_by_name (String ("flags-") + to_string (c) + fstyle));
609 return m;
612 MAKE_SCHEME_CALLBACK (Stem,dim_callback,2);
614 Stem::dim_callback (SCM e, SCM ax)
616 Axis a = (Axis) gh_scm2int (ax);
617 assert (a == X_AXIS);
618 Grob *se = unsmob_grob (e);
619 Interval r (0, 0);
620 if (unsmob_grob (se->get_grob_property ("beam")) || abs (duration_log (se)) <= 2)
621 ; // TODO!
622 else
624 r = flag (se).extent (X_AXIS);
626 return ly_interval2scm (r);
631 MAKE_SCHEME_CALLBACK (Stem,brew_molecule,1);
634 Stem::brew_molecule (SCM smob)
636 Grob*me = unsmob_grob (smob);
637 Molecule mol;
638 Direction d = get_direction (me);
642 Real y1;
645 This is required to avoid stems passing in tablature chords...
650 TODO: make the stem start a direction ?
655 if (to_boolean (me->get_grob_property ("avoid-note-head")))
657 Grob * lh = last_head (me);
658 if (!lh)
659 return SCM_EOL;
660 y1 = Staff_symbol_referencer::get_position (lh);
662 else
664 Grob * lh = first_head (me);
665 if (!lh)
666 return SCM_EOL;
667 y1 = Staff_symbol_referencer::get_position (lh);
670 Real y2 = stem_end_position (me);
672 Interval stem_y (y1 <? y2,y2 >? y1);
675 // dy?
676 Real dy = Staff_symbol_referencer::staff_space (me) * 0.5;
678 if (Grob *hed = support_head (me))
681 must not take ledgers into account.
683 Interval head_height = Note_head::head_extent (hed,Y_AXIS);
684 Real y_attach = Note_head::stem_attachment_coordinate ( hed, Y_AXIS);
686 y_attach = head_height.linear_combination (y_attach);
687 stem_y[Direction (-d)] += d * y_attach/dy;
690 if (!invisible_b (me))
692 Real stem_width = gh_scm2double (me->get_grob_property ("thickness"))
693 // URG
694 * me->get_paper ()->get_var ("linethickness");
696 Molecule ss =Lookup::filledbox (Box (Interval (-stem_width/2, stem_width/2),
697 Interval (stem_y[DOWN]*dy, stem_y[UP]*dy)));
698 mol.add_molecule (ss);
701 if (!get_beam (me) && abs (duration_log (me)) > 2)
703 Molecule fl = flag (me);
704 fl.translate_axis (stem_y[d]*dy, Y_AXIS);
705 mol.add_molecule (fl);
708 return mol.smobbed_copy ();
712 move the stem to right of the notehead if it is up.
714 MAKE_SCHEME_CALLBACK (Stem,off_callback,2);
716 Stem::off_callback (SCM element_smob, SCM)
718 Grob *me = unsmob_grob (element_smob);
720 Real r=0;
722 if (head_count (me) == 0)
724 return gh_double2scm (0.0);
727 if (Grob * f = first_head (me))
729 Interval head_wid = Note_head::head_extent(f, X_AXIS);
732 Real attach =0.0;
734 if (invisible_b (me))
736 attach = 0.0;
738 else
739 attach = Note_head::stem_attachment_coordinate(f, X_AXIS);
741 Direction d = get_direction (me);
743 Real real_attach = head_wid.linear_combination (d * attach);
745 r = real_attach;
748 If not centered: correct for stem thickness.
750 if (attach)
752 Real rule_thick
753 = gh_scm2double (me->get_grob_property ("thickness"))
754 * me->get_paper ()->get_var ("linethickness");
757 r += - d * rule_thick * 0.5;
760 return gh_double2scm (r);
763 Grob*
764 Stem::get_beam (Grob*me)
766 SCM b= me->get_grob_property ("beam");
767 return unsmob_grob (b);
770 Stem_info
771 Stem::get_stem_info (Grob *me)
773 /* Return cached info if available */
774 SCM scm_info = me->get_grob_property ("stem-info");
775 if (!gh_pair_p (scm_info))
777 calc_stem_info (me);
778 scm_info = me->get_grob_property ("stem-info");
781 Stem_info si;
782 si.dir_ = Directional_element_interface::get (me);
783 si.ideal_y_ = gh_scm2double (gh_car (scm_info));
784 si.shortest_y_ = gh_scm2double (gh_cadr (scm_info));
785 return si;
788 void
789 Stem::calc_stem_info (Grob *me)
791 /* Tab notation feature: make stem end extend out of staff. */
792 SCM up_to_staff = me->get_grob_property ("up-to-staff");
793 if (to_boolean (up_to_staff))
795 int line_count = Staff_symbol_referencer::line_count (me);
796 Direction dir = get_direction (me);
797 Real ideal_y = dir * (line_count + 1.5);
798 Real shortest_y = ideal_y;
800 me->set_grob_property ("stem-info",
801 scm_list_n (gh_double2scm (ideal_y),
802 gh_double2scm (shortest_y),
803 SCM_UNDEFINED));
804 return;
807 Direction my_dir = Directional_element_interface::get (me);
808 Real staff_space = Staff_symbol_referencer::staff_space (me);
809 Grob *beam = get_beam (me);
810 Real beam_translation = Beam::get_beam_translation (beam);
811 Real beam_thickness = gh_scm2double (beam->get_grob_property ("thickness"));
812 int beam_count = Beam::get_direction_beam_count (beam, my_dir);
815 /* Simple standard stem length */
816 Real ideal_length =
817 gh_scm2double (robust_list_ref
818 (beam_count - 1,
819 me->get_grob_property ("beamed-lengths")))
820 * staff_space
821 /* stem only extends to center of beam */
822 - 0.5 * beam_thickness;
825 /* Condition: sane minimum free stem length (chord to beams) */
826 Real ideal_minimum_free =
827 gh_scm2double (robust_list_ref
828 (beam_count - 1,
829 me->get_grob_property ("beamed-minimum-free-lengths")))
830 * staff_space;
833 /* UGH
834 It seems that also for ideal minimum length, we must use
835 the maximum beam count (for this direction):
837 \score{ \notes\relative c''{ [a8 a32] }}
839 must be horizontal. */
840 Real height_of_my_beams = beam_thickness
841 + (beam_count - 1) * beam_translation;
843 Real ideal_minimum_length = ideal_minimum_free
844 + height_of_my_beams
845 /* stem only extends to center of beam */
846 - 0.5 * beam_thickness;
848 ideal_length = ideal_length >? ideal_minimum_length;
851 /* Convert to Y position, calculate for dir == UP */
852 Real note_start =
853 /* staff positions */
854 head_positions (me)[my_dir] * 0.5
855 * my_dir;
856 Real ideal_y = note_start + ideal_length;
859 /* Conditions for Y position */
861 /* Lowest beam of (UP) beam must never be lower than second staffline
863 Reference?
865 Although this (additional) rule is probably correct,
866 I expect that highest beam (UP) should also never be lower
867 than middle staffline, just as normal stems.
869 Reference?
871 Obviously not for grace beams.
873 Also, not for knees. Seems to be a good thing. */
874 SCM grace = me->get_grob_property ("grace");
875 bool grace_b = to_boolean (grace);
876 bool no_extend_b = to_boolean (me->get_grob_property ("no-stem-extend"));
877 bool knee_b = to_boolean (beam->get_grob_property ("knee"));
878 if (!grace_b && !no_extend_b && !knee_b)
880 /* Highest beam of (UP) beam must never be lower than middle
881 staffline */
882 ideal_y = ideal_y >? 0;
883 /* Lowest beam of (UP) beam must never be lower than second staffline */
884 ideal_y = ideal_y >? (-staff_space
885 - beam_thickness + height_of_my_beams);
889 SCM shorten = beam->get_grob_property ("shorten");
890 if (gh_number_p (shorten))
891 ideal_y -= gh_scm2double (shorten);
894 Real minimum_free =
895 gh_scm2double (robust_list_ref
896 (beam_count - 1,
897 me->get_grob_property
898 ("beamed-extreme-minimum-free-lengths")))
899 * staff_space;
901 Real minimum_length = minimum_free
902 + height_of_my_beams
903 /* stem only extends to center of beam */
904 - 0.5 * beam_thickness;
906 Real minimum_y = note_start + minimum_length;
909 ideal_y *= my_dir;
910 Real shortest_y = minimum_y * my_dir;
912 me->set_grob_property ("stem-info",
913 scm_list_n (gh_double2scm (ideal_y),
914 gh_double2scm (shortest_y),
915 SCM_UNDEFINED));
918 Slice
919 Stem::beam_multiplicity (Grob *stem)
921 SCM beaming= stem->get_grob_property ("beaming");
922 Slice l = int_list_to_slice (gh_car (beaming));
923 Slice r = int_list_to_slice (gh_cdr (beaming));
924 l.unite (r);
926 return l;
930 ADD_INTERFACE (Stem,"stem-interface",
931 "A stem",
932 "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 style no-stem-extend flag-style");