2 beam.cc -- implement Beam
4 source file of the GNU LilyPond music typesetter
6 (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
10 Less hairy code. knee: ([\stem 1; c8 \stem -1; c8]
21 #include "abbreviation-beam.hh"
25 #include "molecule.hh"
26 #include "leastsquares.hh"
28 #include "paper-def.hh"
30 #include "grouping.hh"
31 #include "stem-info.hh"
32 //#include "main.hh" // experimental features
35 IMPLEMENT_IS_TYPE_B1 (Beam
, Spanner
);
38 const Real MINIMUM_STEMLEN
[] = {
52 quantisation_
= NORMAL
;
60 s
->add_dependency (this);
63 if (!spanned_drul_
[LEFT
])
70 Beam::brew_molecule_p () const
72 Molecule
*mol_p
= new Molecule
;
73 Real inter_f
= paper ()->internote_f ();
74 Real x0
= stems_
[0]->hpos_f ();
75 for (int j
=0; j
<stems_
.size (); j
++)
78 Stem
* prev
= (j
> 0)? stems_
[j
-1] : 0;
79 Stem
* next
= (j
< stems_
.size ()-1) ? stems_
[j
+1] :0;
81 Molecule sb
= stem_beams (i
, next
, prev
);
82 Real x
= i
->hpos_f ()-x0
;
83 sb
.translate (Offset (x
, (x
* slope_f_
+ left_y_
)* inter_f
));
86 mol_p
->translate_axis (x0
- spanned_drul_
[LEFT
]->absolute_coordinate (X_AXIS
), X_AXIS
);
93 Real w
= (paper ()->note_width () + width ().length ())/2.0;
94 return Offset (w
, (left_y_
+ w
* slope_f_
)*paper ()->internote_f ());
98 Beam::do_pre_processing ()
105 Beam::do_print () const
108 DOUT
<< "slope_f_ " <<slope_f_
<< "left ypos " << left_y_
;
109 Spanner::do_print ();
114 Beam::do_post_processing ()
116 if (stems_
.size () < 2)
118 warning (_ ("Beam with less than 2 stems"));
119 transparent_b_
= true;
127 Beam::do_substitute_dependent (Score_elem
*o
,Score_elem
*n
)
129 if (o
->is_type_b (Stem::static_name ()))
130 stems_
.substitute ((Stem
*)o
->item (), n
? (Stem
*) n
->item ():0);
134 Beam::do_width () const
136 return Interval (stems_
[0]->hpos_f (),
137 stems_
.top ()->hpos_f ());
141 Beam::set_default_dir ()
143 Drul_array
<int> total
;
144 total
[UP
] = total
[DOWN
] = 0;
145 Drul_array
<int> count
;
146 count
[UP
] = count
[DOWN
] = 0;
149 for (int i
=0; i
<stems_
.size (); i
++)
152 int current
= s
->dir_
153 ? (1 + d
* s
->dir_
)/2
154 : s
->get_center_distance ((Direction
)-d
);
162 } while (flip(&d
) != DOWN
);
167 } while (flip(&d
) != DOWN
);
171 [Ross] states that the majority of the notes dictates the
172 direction (and not the mean of "center distance")
174 dir_
= (total
[UP
] > total
[DOWN
]) ? UP
: DOWN
;
176 for (int i
=0; i
<stems_
.size (); i
++)
178 Stem
*sl
= stems_
[i
];
184 should use minimum energy formulation (cf linespacing)
189 Array
<Stem_info
> sinfo
;
190 for (int j
=0; j
<stems_
.size (); j
++)
194 i
->set_default_extents ();
195 if (i
->invisible_b ())
202 slope_f_
= left_y_
= 0;
203 else if (sinfo
.size () == 1)
206 left_y_
= sinfo
[0].idealy_f_
;
211 Real leftx
= sinfo
[0].x
;
213 for (int i
=0; i
< sinfo
.size (); i
++)
216 l
.input
.push (Offset (sinfo
[i
].x
, sinfo
[i
].idealy_f_
));
219 l
.minimise (slope_f_
, left_y_
);
223 for (int i
=0; i
< sinfo
.size (); i
++)
225 Real y
= sinfo
[i
].x
* slope_f_
+ left_y_
;
226 Real my
= sinfo
[i
].miny_f_
;
237 This neat trick is by Werner Lemberg, damped = tanh (slope_f_) corresponds
238 with some tables in [Wanske]
241 slope_f_
= 0.6 * tanh (slope_f_
) / damping_i_
;
245 // y-values traditionally use internote dimension: therefore slope = (y/in)/x
246 // but mf and beam-lookup use PT dimension for y (as used for x-values)
247 // ugh --- there goes our simplified but careful quantisation
248 Real sl
= slope_f_
* paper ()->internote_f ();
249 paper ()->lookup_l ()->beam (sl
, 20 PT
, 1 PT
);
250 slope_f_
= sl
/ paper ()->internote_f ();
254 Beam::quantise_yspan ()
257 [Ross] (simplification of)
258 Try to set slope_f_ complying with y-span of:
260 - beam_thickness / 2 + staffline_thickness / 2
261 - beam_thickness + staffline_thickness
268 Real interline_f
= paper ()->interline_f ();
269 Real internote_f
= interline_f
/ 2;
270 Real staffline_thickness
= paper ()->rule_thickness ();
271 Real beam_thickness
= 0.48 * (interline_f
- staffline_thickness
);
273 const int QUANTS
= 3;
276 beam_thickness
/ 2 + staffline_thickness
/ 2,
277 beam_thickness
+ staffline_thickness
280 Real xspan_f
= stems_
.top ()->hpos_f () - stems_
[0]->hpos_f ();
281 // y-values traditionally use internote dimension: therefore slope = (y/in)/x
282 Real yspan_f
= xspan_f
* abs (slope_f_
* internote_f
);
283 int yspan_i
= (int)(yspan_f
/ interline_f
);
284 Real q
= (yspan_f
/ interline_f
- yspan_i
) * interline_f
;
286 for (; i
< QUANTS
- 1; i
++)
287 if ((q
>= qdy
[i
]) && (q
<= qdy
[i
+ 1]))
289 if (q
- qdy
[i
] < qdy
[i
+ 1] - q
)
299 yspan_f
= (Real
)yspan_i
* interline_f
+ q
;
300 // y-values traditionally use internote dimension: therefore slope = (y/in)/x
301 slope_f_
= yspan_f
/ xspan_f
/ internote_f
* sign (slope_f_
);
305 Beam::quantise_left_y (Beam::Pos pos
, bool extend_b
)
308 quantising left y should suffice, as slope is quantised too
309 if extend then stems must not get shorter
315 Real interline_f
= paper ()->interline_f ();
316 Real internote_f
= interline_f
/ 2;
317 Real staffline_thickness
= paper ()->rule_thickness ();
318 Real beam_thickness
= 0.48 * (interline_f
- staffline_thickness
);
320 const int QUANTS
= 7;
326 interline_f
/ 2 + beam_thickness
/ 2 + staffline_thickness
/ 2,
328 interline_f
+ beam_thickness
/ 2,
329 interline_f
+ beam_thickness
332 ugh, using i triggers gcc 2.7.2.1 internal compiler error (far down):
333 for (int i = 0; i < QUANTS; i++)
337 for (int ii
= 0; ii
< QUANTS
; ii
++)
338 qy
[ii
] -= 0.5 *beam_thickness
;
350 // y-values traditionally use internote dimension
351 Real y
= left_y_
* internote_f
;
352 int y_i
= (int)floor(y
/ interline_f
);
353 y
= (y
/ interline_f
- y_i
) * interline_f
;
356 for (int ii
= 0; ii
< QUANTS
; ii
++)
357 qy
[ii
] -= interline_f
;
361 for (; i
< QUANTS
; i
++)
365 // found if lower_i is allowed, and nearer (from below) y than new pos
366 if ((pos
& qpos
[lower_i
]) && (y
- qy
[lower_i
] < y
- qy
[i
]))
368 // if new pos is allowed or old pos isn't: assign new pos
369 if ((pos
& qpos
[i
]) || !(pos
& qpos
[lower_i
]))
373 int upper_i
= QUANTS
- 1;
374 for (i
= QUANTS
- 1; i
>= 0; i
--)
378 // found if upper_i is allowed, and nearer (from above) y than new pos
379 if ((pos
& qpos
[upper_i
]) && (qy
[upper_i
] - y
< qy
[i
] - y
))
381 // if new pos is allowed or old pos isn't: assign new pos
382 if ((pos
& qpos
[i
]) || !(pos
& qpos
[upper_i
]))
386 // y-values traditionally use internote dimension
387 Real upper_y
= (qy
[upper_i
] + interline_f
* y_i
) / internote_f
;
388 Real lower_y
= (qy
[lower_i
] + interline_f
* y_i
) / internote_f
;
391 left_y_
= (dir_
> 0 ? upper_y
: lower_y
);
393 left_y_
= (upper_y
- y
< y
- lower_y
? upper_y
: lower_y
);
397 Beam::set_stemlens ()
399 Real x0
= stems_
[0]->hpos_f ();
402 Real interline_f
= paper ()->interline_f ();
403 Real internote_f
= interline_f
/ 2;
404 Real staffline_thickness
= paper ()->rule_thickness ();
405 Real beam_thickness
= 0.48 * (interline_f
- staffline_thickness
);
406 Real interbeam_f
= paper ()->interbeam_f ();
408 interbeam_f
+= 2.0 * staffline_thickness
/ 4;
409 Real xspan_f
= stems_
.top ()->hpos_f () - stems_
[0]->hpos_f ();
411 ugh, y values are in "internote" dimension
413 Real yspan_f
= xspan_f
* abs (slope_f_
* internote_f
);
414 int yspan_i
= (int)(yspan_f
/ interline_f
);
418 if ((yspan_f
< staffline_thickness
/ 2) || (quantisation_
== NORMAL
))
419 left_pos
= (Pos
)(STRADDLE
| SIT
| HANG
);
421 left_pos
= (Pos
) (sign (slope_f_
) > 0 ? STRADDLE
| HANG
425 ugh, slope currently mangled by availability mf chars...
426 be more generous regarding beam position between stafflines
428 Real q
= (yspan_f
/ interline_f
- yspan_i
) * interline_f
;
429 if ((quantisation_
< NORMAL
) && (q
< interline_f
/ 3 - beam_thickness
/ 2))
430 left_pos
= (Pos
) (left_pos
| INTER
);
434 left_pos
= (Pos
) (dir_
> 0 ? HANG
: SIT
);
436 // ugh, rounding problems! (enge floots)
437 const Real EPSILON
= interline_f
/ 10;
440 left_y_
+= dy
* dir_
;
441 quantise_left_y (left_pos
, dy
);
443 for (int i
=0; i
< stems_
.size (); i
++)
446 if (s
->transparent_b_
)
449 Real x
= s
->hpos_f () - x0
;
450 s
->set_stemend (left_y_
+ slope_f_
* x
);
451 Real y
= s
->stem_length_f ();
453 // int mult_i = stems_[i]->beams_left_i_ >? stems_[i]->beams_right_i_;
454 int mult_i
= multiple_i_
;
456 // dim(y) = internote
457 y
-= (Real
)(mult_i
- 1) * interbeam_f
/ internote_f
;
458 if (y
< MINIMUM_STEMLEN
[mult_i
])
459 dy
= dy
>? (MINIMUM_STEMLEN
[mult_i
] - y
);
461 } while (abs (dy
) > EPSILON
);
465 Beam::set_grouping (Rhythmic_grouping def
, Rhythmic_grouping cur
)
469 assert (cur
.children
.size () == stems_
.size ());
476 for (int j
=0; j
<stems_
.size (); j
++)
480 int f
= s
->flag_i_
- 2;
485 b
= cur
.generate_beams (flags
, fi
);
488 assert (stems_
.size () == b
.size ()/2);
491 for (int j
=0, i
=0; i
< b
.size () && j
<stems_
.size (); i
+= 2, j
++)
494 s
->beams_left_i_
= b
[i
];
495 s
->beams_right_i_
= b
[i
+1];
496 multiple_i_
= multiple_i_
>? (b
[i
] >? b
[i
+1]);
501 beams to go with one stem.
504 Beam::stem_beams (Stem
*here
, Stem
*next
, Stem
*prev
) const
506 assert (!next
|| next
->hpos_f () > here
->hpos_f ());
507 assert (!prev
|| prev
->hpos_f () < here
->hpos_f ());
509 Real staffline_thickness
= paper ()->rule_thickness ();
510 Real interbeam_f
= paper ()->interbeam_f ();
511 Real internote_f
=paper ()->internote_f ();
512 Real interline_f
= 2 * internote_f
;
513 Real beamheight_f
= 0.48 * (interline_f
- staffline_thickness
);
515 interbeam_f
+= 2.0 * staffline_thickness
/ 4;
516 Real dy
= interbeam_f
;
517 Real stemdx
= staffline_thickness
;
518 Real sl
= slope_f_
* internote_f
;
519 paper ()->lookup_l ()->beam (sl
, 20 PT
, 1 PT
);
524 /* half beams extending to the left. */
527 int lhalfs
= lhalfs
= here
->beams_left_i_
- prev
->beams_right_i_
;
528 int lwholebeams
= here
->beams_left_i_
<? prev
->beams_right_i_
;
529 Real w
= (here
->hpos_f () - prev
->hpos_f ())/4 <? paper ()->note_width ();;
531 if (lhalfs
) // generates warnings if not
532 a
= paper ()->lookup_l ()->beam (sl
, w
, beamheight_f
);
533 a
.translate (Offset (-w
, -w
* sl
));
534 for (int j
= 0; j
< lhalfs
; j
++)
537 b
.translate_axis (-dir_
* dy
* (lwholebeams
+j
), Y_AXIS
);
544 int rhalfs
= here
->beams_right_i_
- next
->beams_left_i_
;
545 int rwholebeams
= here
->beams_right_i_
<? next
->beams_left_i_
;
547 Real w
= next
->hpos_f () - here
->hpos_f ();
548 Atom a
= paper ()->lookup_l ()->beam (sl
, w
+ stemdx
, beamheight_f
);
549 a
.translate_axis( - stemdx
/2, X_AXIS
);
552 if (here
->beam_gap_i_
)
554 int nogap
= rwholebeams
- here
->beam_gap_i_
;
555 for (; j
< nogap
; j
++)
558 b
.translate_axis (-dir_
* dy
* j
, Y_AXIS
);
561 // TODO: notehead widths differ for different types
562 gap_f
= paper ()->note_width () / 2;
564 a
= paper ()->lookup_l ()->beam (sl
, w
+ stemdx
, beamheight_f
);
567 for (; j
< rwholebeams
; j
++)
570 b
.translate (Offset (gap_f
, -dir_
* dy
* j
));
574 w
= w
/4 <? paper ()->note_width ();
576 a
= paper ()->lookup_l ()->beam (sl
, w
, beamheight_f
);
578 for (; j
< rwholebeams
+ rhalfs
; j
++)
581 b
.translate_axis (-dir_
* dy
* j
, Y_AXIS
);
586 leftbeams
.add (rightbeams
);
589 Does beam quanting think of the asymetry of beams?
590 Refpoint is on bottom of symbol. (FIXTHAT) --hwn.