4 #include "staff-symbol-referencer.hh"
7 #include "paper-def.hh"
8 #include "group-interface.hh"
9 #include "align-interface.hh"
11 const int INTER_QUANT_PENALTY = 1000;
12 const int SECONDARY_BEAM_DEMERIT = 15;
13 const int STEM_LENGTH_DEMERIT_FACTOR = 5;
15 // possibly ridiculous, but too short stems just won't do
16 const int STEM_LENGTH_LIMIT_PENALTY = 5000;
17 const int DAMPING_DIRECTIION_PENALTY = 800;
18 const int MUSICAL_DIRECTION_FACTOR = 400;
19 const int IDEAL_SLOPE_FACTOR = 10;
23 shrink_extra_weight (Real x)
25 return fabs (x) * ((x < 0) ? 1.5 : 1.0);
40 - Make all demerits customisable
42 - One sensible check per demerit (what's this --hwn)
44 - Add demerits for quants per se, as to forbid a specific quant
49 int best_quant_score_idx (Array<Quant_score> const & qscores)
53 for (int i = qscores.size (); i--;)
55 if (qscores[i].demerits < best)
57 best = qscores [i].demerits ;
65 MAKE_SCHEME_CALLBACK (Beam, quanting, 1);
67 Beam::quanting (SCM smob)
69 Grob *me = unsmob_grob (smob);
71 SCM s = me->get_grob_property ("positions");
72 Real yl = gh_scm2double (gh_car (s));
73 Real yr = gh_scm2double (gh_cdr (s));
75 Real ss = Staff_symbol_referencer::staff_space (me);
76 Real thickness = gh_scm2double (me->get_grob_property ("thickness")) / ss;
77 Real slt = me->paper_l ()->get_var ("linethickness") / ss;
80 SCM sdy = me->get_grob_property ("least-squares-dy");
81 Real dy_mus = gh_number_p (sdy) ? gh_scm2double (sdy) : 0.0;
84 Real sit = (thickness - slt) / 2;
86 Real hang = 1.0 - (thickness - slt) / 2;
87 Real quants [] = {straddle, sit, inter, hang };
89 int num_quants = int (sizeof (quants)/sizeof (Real));
94 going to REGION_SIZE == 2, yields another 0.6 second with
98 (result indexes between 70 and 575) ? --hwn.
105 Do stem computations. These depend on YL and YR linearly, so we can
106 precompute for every stem 2 factors.
108 Link_array<Grob> stems=
109 Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems");
110 Array<Stem_info> stem_infos;
111 Array<Real> base_lengths;
112 Array<Real> stem_xposns;
114 Drul_array<bool> dirs_found(0,0);
116 for (int a = 2; a--;)
117 common[a] = common_refpoint_of_array (stems, me, Axis(a));
119 Grob * fvs = first_visible_stem (me);
120 Grob *lvs = last_visible_stem (me);
121 Real xl = fvs ? fvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
122 Real xr = fvs ? lvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
125 We store some info to quickly interpolate.
127 Sometimes my head is screwed on backwards. The stemlength are
128 AFFINE linear in YL and YR. If YL == YR == 0, then we might have
129 stem_y != 0.0, when we're cross staff.
132 bool french = to_boolean (me->get_grob_property ("french-beaming"));
133 for (int i= 0; i < stems.size(); i++)
136 stem_infos.push (Stem::calc_stem_info (s));
137 dirs_found[stem_infos.top ().dir_] = true;
139 bool f = french && i > 0&& (i < stems.size () -1);
140 base_lengths.push (calc_stem_y (me, s, common, xl, xr,
142 stem_xposns.push (s->relative_coordinate (common[X_AXIS], X_AXIS));
148 Grob *commony = fvs->common_refpoint (lvs, Y_AXIS);
149 xstaff = Align_interface::has_interface (commony);
152 Direction ldir = Direction (stem_infos[0].dir_);
153 Direction rdir = Direction (stem_infos.top ().dir_);
154 bool knee_b = dirs_found[LEFT] && dirs_found[RIGHT];
157 int region_size = REGION_SIZE;
159 Knees are harder, lets try some more possibilities for knees.
164 for (int i = -region_size ; i < region_size; i++)
165 for (int j = 0; j < num_quants; j++)
167 quantsl.push (i + quants[j] + int (yl));
168 quantsr.push (i + quants[j] + int (yr));
171 Array<Quant_score> qscores;
173 for (int l =0; l < quantsl.size (); l++)
174 for (int r =0; r < quantsr.size (); r++)
185 This is a longish function, but we don't separate this out into
186 neat modular separate subfunctions, as the subfunctions would be
187 called for many values of YL, YR. By precomputing various
188 parameters outside of the loop, we can save a lot of time.
191 for (int i = qscores.size (); i--;)
192 if (qscores[i].demerits < 100)
195 += score_slopes_dy (me, qscores[i].yl, qscores[i].yr,
196 dy_mus, yr- yl, xstaff);
199 Real rad = Staff_symbol_referencer::staff_radius (me);
200 int beam_count = get_beam_count (me);
201 Real beam_space = beam_count < 4
202 ? (2*ss + slt - thickness) / 2.0
203 : (3*ss + slt - thickness) / 3.0;
205 for (int i = qscores.size (); i--;)
206 if (qscores[i].demerits < 100)
209 += score_forbidden_quants (me, qscores[i].yl, qscores[i].yr,
210 rad, slt, thickness, beam_space,
211 beam_count, ldir, rdir);
215 for (int i = qscores.size (); i--;)
216 if (qscores[i].demerits < 100)
219 += score_stem_lengths (stems, stem_infos,
220 base_lengths, stem_xposns,
223 me, qscores[i].yl, qscores[i].yr);
227 int best_idx = best_quant_score_idx (qscores);
228 me->set_grob_property ("positions",
229 gh_cons (gh_double2scm (qscores[best_idx].yl),
230 gh_double2scm (qscores[best_idx].yr))
236 me->set_grob_property ("quant-score",
237 gh_double2scm (qscores[best_idx].demerits));
238 me->set_grob_property ("best-idx", gh_int2scm (best_idx));
241 return SCM_UNSPECIFIED;
245 Beam::score_stem_lengths (Link_array<Grob>stems,
246 Array<Stem_info> stem_infos,
247 Array<Real> base_stem_ys,
254 Real demerit_score = 0.0 ;
255 Real pen = STEM_LENGTH_LIMIT_PENALTY;
257 for (int i=0; i < stems.size (); i++)
260 if (Stem::invisible_b (s))
265 Real beam_y = yr *(x - xl)/dx + yl * ( xr - x)/dx;
266 Real current_y = beam_y + base_stem_ys[i];
268 Stem_info info = stem_infos[i];
269 Direction d = info.dir_;
272 * (0 >? (info.dir_ * (info.shortest_y_ - current_y)));
274 demerit_score += STEM_LENGTH_DEMERIT_FACTOR
275 * shrink_extra_weight (d * current_y - info.dir_ * info.ideal_y_);
278 demerit_score *= 2.0 / stems.size ();
280 return demerit_score;
284 Beam::score_slopes_dy (Grob *me,
286 Real dy_mus, Real dy_damp,
292 if (sign (dy_damp) != sign (dy))
294 dem += DAMPING_DIRECTIION_PENALTY;
297 dem += MUSICAL_DIRECTION_FACTOR * (0 >? (fabs (dy) - fabs (dy_mus)));
300 Real slope_penalty = IDEAL_SLOPE_FACTOR;
303 Xstaff beams tend to use extreme slopes to get short stems. We
304 put in a penalty here.
309 dem += shrink_extra_weight (fabs (dy_damp) - fabs (dy))* slope_penalty;
316 return x - floor (x);
320 Beam::score_forbidden_quants (Grob*me,
324 Real thickness, Real beam_space,
326 Direction ldir, Direction rdir)
331 if (fabs (yl) < rad && fabs ( my_modf (yl) - 0.5) < 1e-3)
332 dem += INTER_QUANT_PENALTY;
333 if (fabs (yr) < rad && fabs ( my_modf (yr) - 0.5) < 1e-3)
334 dem += INTER_QUANT_PENALTY;
336 // todo: use beam_count of outer stems.
341 Real sit = (thickness - slt) / 2;
343 Real hang = 1.0 - (thickness - slt) / 2;
346 if (fabs (yl - ldir * beam_space) < rad
347 && fabs (my_modf (yl) - inter) < 1e-3)
348 dem += SECONDARY_BEAM_DEMERIT;
349 if (fabs (yr - rdir * beam_space) < rad
350 && fabs (my_modf (yr) - inter) < 1e-3)
351 dem += SECONDARY_BEAM_DEMERIT;
356 Can't we simply compute the distance between the nearest
357 staffline and the secondary beam? That would get rid of the
358 silly case analysis here (which is probably not when we have
359 different beam-thicknesses.)
365 // hmm, without Interval/Drul_array, you get ~ 4x same code...
366 if (fabs (yl - ldir * beam_space) < rad + inter)
368 if (ldir == UP && dy <= eps
369 && fabs (my_modf (yl) - sit) < eps)
370 dem += SECONDARY_BEAM_DEMERIT;
372 if (ldir == DOWN && dy >= eps
373 && fabs (my_modf (yl) - hang) < eps)
374 dem += SECONDARY_BEAM_DEMERIT;
377 if (fabs (yr - rdir * beam_space) < rad + inter)
379 if (rdir == UP && dy >= eps
380 && fabs (my_modf (yr) - sit) < eps)
381 dem += SECONDARY_BEAM_DEMERIT;
383 if (rdir == DOWN && dy <= eps
384 && fabs (my_modf (yr) - hang) < eps)
385 dem += SECONDARY_BEAM_DEMERIT;
390 if (fabs (yl - 2 * ldir * beam_space) < rad + inter)
392 if (ldir == UP && dy <= eps
393 && fabs (my_modf (yl) - straddle) < eps)
394 dem += SECONDARY_BEAM_DEMERIT;
396 if (ldir == DOWN && dy >= eps
397 && fabs (my_modf (yl) - straddle) < eps)
398 dem += SECONDARY_BEAM_DEMERIT;
401 if (fabs (yr - 2 * rdir * beam_space) < rad + inter)
403 if (rdir == UP && dy >= eps
404 && fabs (my_modf (yr) - straddle) < eps)
405 dem += SECONDARY_BEAM_DEMERIT;
407 if (rdir == DOWN && dy <= eps
408 && fabs (my_modf (yr) - straddle) < eps)
409 dem += SECONDARY_BEAM_DEMERIT;