* lexer-gcc-3.1.sh: Remove.
[lilypond/patrick.git] / lily / beam-quanting.cc
blobe4cec84364b670b23da5f15980d5c498ae0a1999
1 /*
2 beam-quanting.cc -- implement Beam quanting functions
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
8 */
10 #include "beam.hh"
12 #include <algorithm>
13 using namespace std;
15 #include "align-interface.hh"
16 #include "international.hh"
17 #include "output-def.hh"
18 #include "pointer-group-interface.hh"
19 #include "staff-symbol-referencer.hh"
20 #include "stem.hh"
21 #include "warn.hh"
22 #include "main.hh"
24 Real
25 get_detail (SCM alist, SCM sym, Real def)
27 SCM entry = scm_assq (sym, alist);
29 if (scm_is_pair (entry))
30 return robust_scm2double (scm_cdr (entry), def);
31 return def;
34 void
35 Beam_quant_parameters::fill (Grob *him)
37 SCM details = him->get_property ("details");
39 INTER_QUANT_PENALTY = get_detail (details, ly_symbol2scm ("inter-quant-penalty"), 1000.0);
40 SECONDARY_BEAM_DEMERIT = get_detail (details, ly_symbol2scm ("secondary-beam-demerit"), 10.0);
41 STEM_LENGTH_DEMERIT_FACTOR = get_detail (details, ly_symbol2scm ("stem-length-demerit-factor"), 5);
42 REGION_SIZE = get_detail (details, ly_symbol2scm ("region-size"), 2);
43 BEAM_EPS = get_detail (details, ly_symbol2scm ("beam-eps"), 1e-3);
45 // possibly ridiculous, but too short stems just won't do
46 STEM_LENGTH_LIMIT_PENALTY = get_detail (details, ly_symbol2scm ("stem-length-limit-penalty"), 5000);
47 DAMPING_DIRECTION_PENALTY = get_detail (details, ly_symbol2scm ("damping-direction-penalty"), 800);
48 MUSICAL_DIRECTION_FACTOR = get_detail (details, ly_symbol2scm ("musical-direction-factor"), 400);
49 IDEAL_SLOPE_FACTOR = get_detail (details, ly_symbol2scm ("ideal-slope-factor"), 10);
50 ROUND_TO_ZERO_SLOPE = get_detail (details, ly_symbol2scm ("round-to-zero-slope"), 0.02);
53 static Real
54 shrink_extra_weight (Real x, Real fac)
56 return fabs (x) * ((x < 0) ? fac : 1.0);
59 struct Quant_score
61 Real yl;
62 Real yr;
63 Real demerits;
65 #if DEBUG_BEAM_SCORING
66 string score_card_;
67 #endif
71 TODO:
73 - Make all demerits customisable
75 - One sensible check per demerit (what's this --hwn)
77 - Add demerits for quants per se, as to forbid a specific quant
78 entirely
81 int
82 best_quant_score_idx (vector<Quant_score> const &qscores)
84 Real best = 1e6;
85 int best_idx = -1;
86 for (vsize i = qscores.size (); i--;)
88 if (qscores[i].demerits < best)
90 best = qscores [i].demerits;
91 best_idx = i;
95 return best_idx;
98 MAKE_SCHEME_CALLBACK (Beam, quanting, 2);
99 SCM
100 Beam::quanting (SCM smob, SCM posns)
102 Grob *me = unsmob_grob (smob);
104 Beam_quant_parameters parameters;
105 parameters.fill (me);
107 Real yl = scm_to_double (scm_car (posns));
108 Real yr = scm_to_double (scm_cdr (posns));
111 Calculations are relative to a unit-scaled staff, i.e. the quants are
112 divided by the current staff_space.
115 Real ss = Staff_symbol_referencer::staff_space (me);
116 Real thickness = Beam::get_thickness (me) / ss;
117 Real slt = Staff_symbol_referencer::line_thickness (me) / ss;
119 Real dy_mus = robust_scm2double (me->get_property ("least-squares-dy"), 0);
120 Real straddle = 0.0;
121 Real sit = (thickness - slt) / 2;
122 Real inter = 0.5;
123 Real hang = 1.0 - (thickness - slt) / 2;
124 Real quants [] = {straddle, sit, inter, hang };
126 int num_quants = int (sizeof (quants) / sizeof (Real));
127 vector<Real> quantsl;
128 vector<Real> quantsr;
131 going to REGION_SIZE == 2, yields another 0.6 second with
132 wtk1-fugue2.
135 (result indexes between 70 and 575) ? --hwn.
140 Do stem computations. These depend on YL and YR linearly, so we can
141 precompute for every stem 2 factors.
143 vector<Grob*> stems
144 = extract_grob_array (me, "stems");
145 vector<Stem_info> stem_infos;
146 vector<Real> base_lengths;
147 vector<Real> stem_xposns;
149 Drul_array<bool> dirs_found (0, 0);
150 Grob *common[2];
151 for (int a = 2; a--;)
152 common[a] = common_refpoint_of_array (stems, me, Axis (a));
154 Grob *fvs = first_visible_stem (me);
155 Grob *lvs = last_visible_stem (me);
156 Real xl = fvs ? fvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
157 Real xr = fvs ? lvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
160 We store some info to quickly interpolate.
162 Sometimes my head is screwed on backwards. The stemlength are
163 AFFINE linear in YL and YR. If YL == YR == 0, then we might have
164 stem_y != 0.0, when we're cross staff.
167 for (vsize i = 0; i < stems.size (); i++)
169 Grob *s = stems[i];
171 Stem_info si (Stem::get_stem_info (s));
172 si.scale (1 / ss);
173 stem_infos.push_back (si);
174 dirs_found[stem_infos.back ().dir_] = true;
176 bool f = to_boolean (s->get_property ("french-beaming"))
177 && s != lvs && s != fvs;
179 base_lengths.push_back (calc_stem_y (me, s, common, xl, xr,
180 Interval (0, 0), f) / ss);
181 stem_xposns.push_back (s->relative_coordinate (common[X_AXIS], X_AXIS));
184 bool xstaff = false;
185 if (lvs && fvs)
187 Grob *commony = fvs->common_refpoint (lvs, Y_AXIS);
188 xstaff = Align_interface::has_interface (commony);
191 Direction ldir = Direction (stem_infos[0].dir_);
192 Direction rdir = Direction (stem_infos.back ().dir_);
193 bool is_knee = dirs_found[LEFT] && dirs_found[RIGHT];
195 int region_size = (int) parameters.REGION_SIZE;
198 Knees are harder, lets try some more possibilities for knees.
200 if (is_knee)
201 region_size += 2;
204 Asymetry ? should run to <= region_size ?
206 for (int i = -region_size; i < region_size; i++)
207 for (int j = 0; j < num_quants; j++)
209 quantsl.push_back (i + quants[j] + int (yl));
210 quantsr.push_back (i + quants[j] + int (yr));
213 vector<Quant_score> qscores;
215 for (vsize l = 0; l < quantsl.size (); l++)
216 for (vsize r = 0; r < quantsr.size (); r++)
218 Quant_score qs;
219 qs.yl = quantsl[l];
220 qs.yr = quantsr[r];
221 qs.demerits = 0.0;
223 qscores.push_back (qs);
226 /* This is a longish function, but we don't separate this out into
227 neat modular separate subfunctions, as the subfunctions would be
228 called for many values of YL, YR. By precomputing various
229 parameters outside of the loop, we can save a lot of time. */
230 for (vsize i = qscores.size (); i--;)
232 Real d = score_slopes_dy (qscores[i].yl, qscores[i].yr,
233 dy_mus, yr- yl,
234 xr - xl,
235 xstaff, &parameters);
236 qscores[i].demerits += d;
238 #if DEBUG_BEAM_SCORING
239 qscores[i].score_card_ += to_string ("S%.2f", d);
240 #endif
243 Real rad = Staff_symbol_referencer::staff_radius (me);
244 Drul_array<int> edge_beam_counts
245 (Stem::beam_multiplicity (stems[0]).length () + 1,
246 Stem::beam_multiplicity (stems.back ()).length () + 1);
248 Real beam_translation = get_beam_translation (me) / ss;
250 Real reasonable_score = (is_knee) ? 200000 : 100;
251 for (vsize i = qscores.size (); i--;)
252 if (qscores[i].demerits < reasonable_score)
254 Real d = score_forbidden_quants (qscores[i].yl, qscores[i].yr,
255 rad, slt, thickness, beam_translation,
256 edge_beam_counts, ldir, rdir, &parameters);
257 qscores[i].demerits += d;
259 #if DEBUG_BEAM_SCORING
260 qscores[i].score_card_ += to_string (" F %.2f", d);
261 #endif
264 for (vsize i = qscores.size (); i--;)
265 if (qscores[i].demerits < reasonable_score)
267 Real d = score_stem_lengths (stems, stem_infos,
268 base_lengths, stem_xposns,
269 xl, xr,
270 is_knee,
271 qscores[i].yl, qscores[i].yr, &parameters);
272 qscores[i].demerits += d;
274 #if DEBUG_BEAM_SCORING
275 qscores[i].score_card_ += to_string (" L %.2f", d);
276 #endif
279 int best_idx = best_quant_score_idx (qscores);
281 #if DEBUG_BEAM_SCORING
282 SCM inspect_quants = me->get_property ("inspect-quants");
283 if (to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring")))
284 && scm_is_pair (inspect_quants))
286 Drul_array<Real> ins = ly_scm2interval (inspect_quants);
288 Real mindist = 1e6;
289 for (vsize i = 0; i < qscores.size (); i++)
291 Real d = fabs (qscores[i].yl- ins[LEFT]) + fabs (qscores[i].yr - ins[RIGHT]);
292 if (d < mindist)
294 best_idx = i;
295 mindist = d;
298 if (mindist > 1e5)
299 programming_error ("can't find quant");
301 #endif
303 Interval final_positions;
304 if (best_idx < 0)
306 warning (_ ("no feasible beam position"));
307 final_positions = Interval (0, 0);
309 else
311 final_positions = Drul_array<Real> (qscores[best_idx].yl,
312 qscores[best_idx].yr);
315 #if DEBUG_BEAM_SCORING
316 if (best_idx >= 0
317 && to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring"))))
319 qscores[best_idx].score_card_ += to_string ("i%d", best_idx);
321 // debug quanting
322 me->set_property ("quant-score",
323 scm_makfrom0str (qscores[best_idx].score_card_.c_str ()));
325 #endif
327 return ly_interval2scm (final_positions);
330 Real
331 Beam::score_stem_lengths (vector<Grob*> const &stems,
332 vector<Stem_info> const &stem_infos,
333 vector<Real> const &base_stem_ys,
334 vector<Real> const &stem_xs,
335 Real xl, Real xr,
336 bool knee,
337 Real yl, Real yr,
339 Beam_quant_parameters const *parameters)
341 Real limit_penalty = parameters->STEM_LENGTH_LIMIT_PENALTY;
342 Drul_array<Real> score (0, 0);
343 Drul_array<int> count (0, 0);
345 for (vsize i = 0; i < stems.size (); i++)
347 Grob *s = stems[i];
348 if (Stem::is_invisible (s))
349 continue;
351 Real x = stem_xs[i];
352 Real dx = xr - xl;
353 Real beam_y = dx ? yr * (x - xl) / dx + yl * (xr - x) / dx : (yr + yl) / 2;
354 Real current_y = beam_y + base_stem_ys[i];
355 Real length_pen = parameters->STEM_LENGTH_DEMERIT_FACTOR;
357 Stem_info info = stem_infos[i];
358 Direction d = info.dir_;
360 score[d] += limit_penalty * max (0.0, (d * (info.shortest_y_ - current_y)));
362 Real ideal_diff = d * (current_y - info.ideal_y_);
363 Real ideal_score = shrink_extra_weight (ideal_diff, 1.5);
365 /* We introduce a power, to make the scoring strictly
366 convex. Otherwise a symmetric knee beam (up/down/up/down)
367 does not have an optimum in the middle. */
368 if (knee)
369 ideal_score = pow (ideal_score, 1.1);
371 score[d] += length_pen * ideal_score;
373 count[d]++;
376 Direction d = DOWN;
378 score[d] /= max (count[d], 1);
379 while (flip (&d) != DOWN)
382 return score[LEFT] + score[RIGHT];
385 Real
386 Beam::score_slopes_dy (Real yl, Real yr,
387 Real dy_mus, Real dy_damp,
388 Real dx,
389 bool xstaff,
391 Beam_quant_parameters const *parameters)
393 Real dy = yr - yl;
394 Real dem = 0.0;
397 DAMPING_DIRECTION_PENALTY is a very harsh measure, while for
398 complex beaming patterns, horizontal is often a good choice.
400 TODO: find a way to incorporate the complexity of the beam in this
401 penalty.
403 if (fabs (dy / dx) > parameters->ROUND_TO_ZERO_SLOPE
404 && sign (dy_damp) != sign (dy))
405 dem += parameters->DAMPING_DIRECTION_PENALTY;
407 dem += parameters->MUSICAL_DIRECTION_FACTOR
408 * max (0.0, (fabs (dy) - fabs (dy_mus)));
410 Real slope_penalty = parameters->IDEAL_SLOPE_FACTOR;
412 /* Xstaff beams tend to use extreme slopes to get short stems. We
413 put in a penalty here. */
414 if (xstaff)
415 slope_penalty *= 10;
417 /* Huh, why would a too steep beam be better than a too flat one ? */
418 dem += shrink_extra_weight (fabs (dy_damp) - fabs (dy), 1.5)
419 * slope_penalty;
421 return dem;
424 static Real
425 my_modf (Real x)
427 return x - floor (x);
431 TODO: The fixed value SECONDARY_BEAM_DEMERIT is probably flawed:
432 because for 32nd and 64th beams the forbidden quants are relatively
433 more important than stem lengths.
435 Real
436 Beam::score_forbidden_quants (Real yl, Real yr,
437 Real radius,
438 Real slt,
439 Real thickness, Real beam_translation,
440 Drul_array<int> beam_counts,
441 Direction ldir, Direction rdir,
443 Beam_quant_parameters const *parameters)
445 Real dy = yr - yl;
446 Drul_array<Real> y (yl, yr);
447 Drul_array<Direction> dirs (ldir, rdir);
449 Real extra_demerit = parameters->SECONDARY_BEAM_DEMERIT / (max (beam_counts[LEFT], beam_counts[RIGHT]));
451 Direction d = LEFT;
452 Real dem = 0.0;
453 Real eps = parameters->BEAM_EPS;
457 for (int j = 1; j <= beam_counts[d]; j++)
459 Direction stem_dir = dirs[d];
462 The 2.2 factor is to provide a little leniency for
463 borderline cases. If we do 2.0, then the upper outer line
464 will be in the gap of the (2, sit) quant, leading to a
465 false demerit.
467 Real gap1 = y[d] - stem_dir * ((j - 1) * beam_translation + thickness / 2 - slt / 2.2);
468 Real gap2 = y[d] - stem_dir * (j * beam_translation - thickness / 2 + slt / 2.2);
470 Interval gap;
471 gap.add_point (gap1);
472 gap.add_point (gap2);
474 for (Real k = -radius;
475 k <= radius + eps; k += 1.0)
476 if (gap.contains (k))
478 Real dist = min (fabs (gap[UP] - k), fabs (gap[DOWN] - k));
481 this parameter is tuned to grace-stem-length.ly
483 Real fixed_demerit = 0.4;
485 dem += extra_demerit
486 * (fixed_demerit
487 + (1 - fixed_demerit) * (dist / gap.length ()) * 2);
491 while ((flip (&d)) != LEFT);
493 if (max (beam_counts[LEFT], beam_counts[RIGHT]) >= 2)
495 Real straddle = 0.0;
496 Real sit = (thickness - slt) / 2;
497 Real inter = 0.5;
498 Real hang = 1.0 - (thickness - slt) / 2;
500 Direction d = LEFT;
503 if (beam_counts[d] >= 2
504 && fabs (y[d] - dirs[d] * beam_translation) < radius + inter)
506 if (dirs[d] == UP && dy <= eps
507 && fabs (my_modf (y[d]) - sit) < eps)
508 dem += extra_demerit;
510 if (dirs[d] == DOWN && dy >= eps
511 && fabs (my_modf (y[d]) - hang) < eps)
512 dem += extra_demerit;
515 if (beam_counts[d] >= 3
516 && fabs (y[d] - 2 * dirs[d] * beam_translation) < radius + inter)
518 if (dirs[d] == UP && dy <= eps
519 && fabs (my_modf (y[d]) - straddle) < eps)
520 dem += extra_demerit;
522 if (dirs[d] == DOWN && dy >= eps
523 && fabs (my_modf (y[d]) - straddle) < eps)
524 dem += extra_demerit;
527 while (flip (&d) != LEFT);
530 return dem;