*** empty log message ***
[lilypond.git] / lily / beam-quanting.cc
blobc7dc9848879c2f37e65f4529a1b576a0febe9fb6
1 /*
2 beam-quanting.cc -- implement Beam quanting functions
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
9 */
13 #include <math.h>
15 #include "grob.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "beam.hh"
18 #include "stem.hh"
19 #include "paper-def.hh"
20 #include "group-interface.hh"
21 #include "align-interface.hh"
23 const int INTER_QUANT_PENALTY = 1000;
24 const int SECONDARY_BEAM_DEMERIT = 15;
25 const int STEM_LENGTH_DEMERIT_FACTOR = 5;
27 // possibly ridiculous, but too short stems just won't do
28 const int STEM_LENGTH_LIMIT_PENALTY = 5000;
29 const int DAMPING_DIRECTIION_PENALTY = 800;
30 const int MUSICAL_DIRECTION_FACTOR = 400;
31 const int IDEAL_SLOPE_FACTOR = 10;
34 static Real
35 shrink_extra_weight (Real x, Real fac)
37 return fabs (x) * ((x < 0) ? fac : 1.0);
41 struct Quant_score
43 Real yl;
44 Real yr;
45 Real demerits;
50 TODO:
52 - Make all demerits customisable
54 - One sensible check per demerit (what's this --hwn)
56 - Add demerits for quants per se, as to forbid a specific quant
57 entirely
61 int best_quant_score_idx (Array<Quant_score> const & qscores)
63 Real best = 1e6;
64 int best_idx = -1;
65 for (int i = qscores.size (); i--;)
67 if (qscores[i].demerits < best)
69 best = qscores [i].demerits ;
70 best_idx = i;
74 return best_idx;
77 MAKE_SCHEME_CALLBACK (Beam, quanting, 1);
78 SCM
79 Beam::quanting (SCM smob)
81 Grob *me = unsmob_grob (smob);
83 SCM s = me->get_grob_property ("positions");
84 Real yl = gh_scm2double (gh_car (s));
85 Real yr = gh_scm2double (gh_cdr (s));
87 Real ss = Staff_symbol_referencer::staff_space (me);
88 Real thickness = gh_scm2double (me->get_grob_property ("thickness")) / ss;
89 Real slt = me->get_paper ()->get_realvar (ly_symbol2scm ("linethickness")) / ss;
92 SCM sdy = me->get_grob_property ("least-squares-dy");
93 Real dy_mus = gh_number_p (sdy) ? gh_scm2double (sdy) : 0.0;
95 Real straddle = 0.0;
96 Real sit = (thickness - slt) / 2;
97 Real inter = 0.5;
98 Real hang = 1.0 - (thickness - slt) / 2;
99 Real quants [] = {straddle, sit, inter, hang };
101 int num_quants = int (sizeof (quants)/sizeof (Real));
102 Array<Real> quantsl;
103 Array<Real> quantsr;
106 going to REGION_SIZE == 2, yields another 0.6 second with
107 wtk1-fugue2.
110 (result indexes between 70 and 575) ? --hwn.
117 Do stem computations. These depend on YL and YR linearly, so we can
118 precompute for every stem 2 factors.
120 Link_array<Grob> stems=
121 Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems");
122 Array<Stem_info> stem_infos;
123 Array<Real> base_lengths;
124 Array<Real> stem_xposns;
126 Drul_array<bool> dirs_found(0,0);
127 Grob *common[2];
128 for (int a = 2; a--;)
129 common[a] = common_refpoint_of_array (stems, me, Axis(a));
131 Grob * fvs = first_visible_stem (me);
132 Grob *lvs = last_visible_stem (me);
133 Real xl = fvs ? fvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
134 Real xr = fvs ? lvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
137 We store some info to quickly interpolate.
139 Sometimes my head is screwed on backwards. The stemlength are
140 AFFINE linear in YL and YR. If YL == YR == 0, then we might have
141 stem_y != 0.0, when we're cross staff.
144 for (int i= 0; i < stems.size(); i++)
146 Grob*s = stems[i];
147 stem_infos.push (Stem::get_stem_info (s));
148 dirs_found[stem_infos.top ().dir_] = true;
150 bool f = to_boolean (s->get_grob_property ("french-beaming"))
151 && s != lvs && s != fvs;
153 base_lengths.push (calc_stem_y (me, s, common, xl, xr,
154 Interval (0,0), f));
155 stem_xposns.push (s->relative_coordinate (common[X_AXIS], X_AXIS));
158 bool xstaff= false;
159 if (lvs && fvs)
161 Grob *commony = fvs->common_refpoint (lvs, Y_AXIS);
162 xstaff = Align_interface::has_interface (commony);
165 Direction ldir = Direction (stem_infos[0].dir_);
166 Direction rdir = Direction (stem_infos.top ().dir_);
167 bool knee_b = dirs_found[LEFT] && dirs_found[RIGHT];
170 int region_size = REGION_SIZE;
172 Knees are harder, lets try some more possibilities for knees.
174 if (knee_b)
175 region_size += 2;
178 Asymetry ? should run to <= region_size ?
180 for (int i = -region_size ; i < region_size; i++)
181 for (int j = 0; j < num_quants; j++)
183 quantsl.push (i + quants[j] + int (yl));
184 quantsr.push (i + quants[j] + int (yr));
187 Array<Quant_score> qscores;
189 for (int l =0; l < quantsl.size (); l++)
190 for (int r =0; r < quantsr.size (); r++)
192 Quant_score qs;
193 qs.yl = quantsl[l];
194 qs.yr = quantsr[r];
195 qs.demerits = 0.0;
197 qscores.push (qs);
200 /* This is a longish function, but we don't separate this out into
201 neat modular separate subfunctions, as the subfunctions would be
202 called for many values of YL, YR. By precomputing various
203 parameters outside of the loop, we can save a lot of time. */
204 for (int i = qscores.size (); i--;)
206 qscores[i].demerits
207 += score_slopes_dy (qscores[i].yl, qscores[i].yr,
208 dy_mus, yr- yl, xstaff);
211 Real rad = Staff_symbol_referencer::staff_radius (me);
212 int beam_count = get_beam_count (me);
213 Real beam_translation = get_beam_translation (me);
215 Real reasonable_score = (knee_b) ? 200000 : 100;
216 for (int i = qscores.size (); i--;)
217 if (qscores[i].demerits < reasonable_score)
219 qscores[i].demerits
220 += score_forbidden_quants (qscores[i].yl, qscores[i].yr,
221 rad, slt, thickness, beam_translation,
222 beam_count, ldir, rdir);
225 // ; /* silly gdb thinks best_idx is inside for loop. */
226 for (int i = qscores.size (); i--;)
227 if (qscores[i].demerits < reasonable_score)
229 qscores[i].demerits
230 += score_stem_lengths (stems, stem_infos,
231 base_lengths, stem_xposns,
232 xl, xr,
233 knee_b,
234 qscores[i].yl, qscores[i].yr);
237 // ; /* silly gdb thinks best_idx is inside for loop. */
238 int best_idx = best_quant_score_idx (qscores);
239 me->set_grob_property ("positions",
240 gh_cons (gh_double2scm (qscores[best_idx].yl),
241 gh_double2scm (qscores[best_idx].yr))
244 #if DEBUG_QUANTING
246 // debug quanting
247 me->set_grob_property ("quant-score",
248 gh_double2scm (qscores[best_idx].demerits));
249 me->set_grob_property ("best-idx", scm_int2num (best_idx));
250 #endif
252 return SCM_UNSPECIFIED;
255 Real
256 Beam::score_stem_lengths (Link_array<Grob> const &stems,
257 Array<Stem_info> const &stem_infos,
258 Array<Real> const &base_stem_ys,
259 Array<Real> const &stem_xs,
260 Real xl, Real xr,
261 bool knee,
262 Real yl, Real yr)
264 Real limit_penalty = STEM_LENGTH_LIMIT_PENALTY;
265 Drul_array<Real> score (0, 0);
266 Drul_array<int> count (0, 0);
268 for (int i=0; i < stems.size (); i++)
270 Grob* s = stems[i];
271 if (Stem::invisible_b (s))
272 continue;
274 Real x = stem_xs[i];
275 Real dx = xr-xl;
276 Real beam_y = dx ? yr *(x - xl)/dx + yl * ( xr - x)/dx : (yr + yl)/2;
277 Real current_y = beam_y + base_stem_ys[i];
278 Real length_pen = STEM_LENGTH_DEMERIT_FACTOR;
280 Stem_info info = stem_infos[i];
281 Direction d = info.dir_;
283 score[d] += limit_penalty * (0 >? (d * (info.shortest_y_ - current_y)));
285 Real ideal_diff = d * (current_y - info.ideal_y_);
286 Real ideal_score = shrink_extra_weight (ideal_diff, 1.5);
288 /* We introduce a power, to make the scoring strictly
289 convex. Otherwise a symmetric knee beam (up/down/up/down)
290 does not have an optimum in the middle. */
291 if (knee)
292 ideal_score = pow (ideal_score, 1.1);
294 score[d] += length_pen * ideal_score;
296 count[d] ++;
299 Direction d = DOWN;
302 score[d] /= (count[d] >? 1);
304 while (flip (&d) != DOWN);
306 return score[LEFT]+score[RIGHT];
309 Real
310 Beam::score_slopes_dy (Real yl, Real yr,
311 Real dy_mus, Real dy_damp,
312 bool xstaff)
314 Real dy = yr - yl;
316 Real dem = 0.0;
317 if (sign (dy_damp) != sign (dy))
319 dem += DAMPING_DIRECTIION_PENALTY;
322 dem += MUSICAL_DIRECTION_FACTOR * (0 >? (fabs (dy) - fabs (dy_mus)));
325 Real slope_penalty = IDEAL_SLOPE_FACTOR;
327 /* Xstaff beams tend to use extreme slopes to get short stems. We
328 put in a penalty here. */
329 if (xstaff)
330 slope_penalty *= 10;
332 /* Huh, why would a too steep beam be better than a too flat one ? */
333 dem += shrink_extra_weight (fabs (dy_damp) - fabs (dy), 1.5)
334 * slope_penalty;
335 return dem;
338 static Real
339 my_modf (Real x)
341 return x - floor (x);
344 Real
345 Beam::score_forbidden_quants (Real yl, Real yr,
346 Real radius,
347 Real slt,
348 Real thickness, Real beam_translation,
349 int beam_count,
350 Direction ldir, Direction rdir)
352 Real dy = yr - yl;
354 Real dem = 0.0;
355 for (int i = 0; i < 2; i++)
357 Real y = i? yl : yr;
358 if (fabs (y) <= (radius + 0.5) && fabs ( my_modf (y) - 0.5) < 1e-3)
359 dem += INTER_QUANT_PENALTY;
362 // todo: use beam_count of outer stems.
363 if (beam_count >= 2)
365 Real straddle = 0.0;
366 Real sit = (thickness - slt) / 2;
367 Real inter = 0.5;
368 Real hang = 1.0 - (thickness - slt) / 2;
371 if (fabs (yl - ldir * beam_translation) < radius
372 && fabs (my_modf (yl) - inter) < 1e-3)
373 dem += SECONDARY_BEAM_DEMERIT;
374 if (fabs (yr - rdir * beam_translation) < radius
375 && fabs (my_modf (yr) - inter) < 1e-3)
376 dem += SECONDARY_BEAM_DEMERIT;
378 Real eps = 1e-3;
381 Can't we simply compute the distance between the nearest
382 staffline and the secondary beam? That would get rid of the
383 silly case analysis here (which is probably not valid when we
384 have different beam-thicknesses.)
386 --hwn
390 // hmm, without Interval/Drul_array, you get ~ 4x same code...
391 if (fabs (yl - ldir * beam_translation) < radius + inter)
393 if (ldir == UP && dy <= eps
394 && fabs (my_modf (yl) - sit) < eps)
395 dem += SECONDARY_BEAM_DEMERIT;
397 if (ldir == DOWN && dy >= eps
398 && fabs (my_modf (yl) - hang) < eps)
399 dem += SECONDARY_BEAM_DEMERIT;
402 if (fabs (yr - rdir * beam_translation) < radius + inter)
404 if (rdir == UP && dy >= eps
405 && fabs (my_modf (yr) - sit) < eps)
406 dem += SECONDARY_BEAM_DEMERIT;
408 if (rdir == DOWN && dy <= eps
409 && fabs (my_modf (yr) - hang) < eps)
410 dem += SECONDARY_BEAM_DEMERIT;
413 if (beam_count >= 3)
415 if (fabs (yl - 2 * ldir * beam_translation) < radius + inter)
417 if (ldir == UP && dy <= eps
418 && fabs (my_modf (yl) - straddle) < eps)
419 dem += SECONDARY_BEAM_DEMERIT;
421 if (ldir == DOWN && dy >= eps
422 && fabs (my_modf (yl) - straddle) < eps)
423 dem += SECONDARY_BEAM_DEMERIT;
426 if (fabs (yr - 2 * rdir * beam_translation) < radius + inter)
428 if (rdir == UP && dy >= eps
429 && fabs (my_modf (yr) - straddle) < eps)
430 dem += SECONDARY_BEAM_DEMERIT;
432 if (rdir == DOWN && dy <= eps
433 && fabs (my_modf (yr) - straddle) < eps)
434 dem += SECONDARY_BEAM_DEMERIT;
439 return dem;