2 slur.cc -- implement Slur
4 source file of the GNU LilyPond music typesetter
6 (c) 1996, 1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
12 * begin and end should be treated as a/acknowledge Scripts.
13 * broken slur should have uniform trend
19 #include "paper-def.hh"
20 #include "note-column.hh"
22 #include "paper-column.hh"
23 #include "molecule.hh"
27 #include "encompass-info.hh"
36 Slur::add_column (Note_column
*n
)
38 if (!n
->head_l_arr_
.size ())
39 warning (_ ("Putting slur over rest. Ignoring"));
42 encompass_arr_
.push (n
);
48 Slur::get_default_dir () const
51 for (int i
=0; i
< encompass_arr_
.size (); i
++)
53 if (encompass_arr_
[i
]->dir () < 0)
63 Slur::do_add_processing ()
65 set_bounds (LEFT
, encompass_arr_
[0]);
66 if (encompass_arr_
.size () > 1)
67 set_bounds (RIGHT
, encompass_arr_
.top ());
71 Slur::do_pre_processing ()
73 // don't set directions
77 Slur::do_substitute_element_pointer (Score_element
*o
, Score_element
*n
)
80 while ((i
= encompass_arr_
.find_i (dynamic_cast<Note_column
*> (o
))) >=0)
83 encompass_arr_
[i
] = dynamic_cast<Note_column
*> (n
);
85 encompass_arr_
.del (i
);
90 Note_column_compare (Note_column
*const&n1
, Note_column
* const&n2
)
92 return Item::left_right_compare (n1
, n2
);
96 Slur::do_post_processing ()
98 encompass_arr_
.sort (Note_column_compare
);
100 dir_
= get_default_dir ();
103 Slur and tie placement [OSU]
106 * x = centre of head - d * x_gap_f
109 * y = length < 5ss : horizontal tangent + d * 0.25 ss
110 y = length >= 5ss : y next interline - d * 0.25 ss
113 Real interline_f
= paper_l ()->get_realvar (interline_scm_sym
);
114 Real internote_f
= interline_f
/ 2;
116 Real x_gap_f
= paper_l ()->get_var ("slur_x_gap");
117 Real y_gap_f
= paper_l ()->get_var ("slur_y_gap");
119 Drul_array
<Note_column
*> note_column_drul
;
120 note_column_drul
[LEFT
] = encompass_arr_
[0];
121 note_column_drul
[RIGHT
] = encompass_arr_
.top ();
123 bool fix_broken_b
= false;
127 dx_f_drul_
[d
] = dy_f_drul_
[d
] = 0;
128 if ((note_column_drul
[d
] == spanned_drul_
[d
])
129 && note_column_drul
[d
]->head_l_arr_
.size ()
130 && (note_column_drul
[d
]->stem_l_
))
132 Stem
* stem_l
= note_column_drul
[d
]->stem_l_
;
134 side directly attached to note head;
135 no beam getting in the way
137 if ((stem_l
->extent (Y_AXIS
).empty_b ()
138 || !((stem_l
->dir_
== dir_
) && (dir_
!= d
)))
139 && !((dir_
== stem_l
->dir_
)
140 && stem_l
->beam_l_
&& (stem_l
->beams_i_drul_
[-d
] >= 1)))
142 dx_f_drul_
[d
] = spanned_drul_
[d
]->extent (X_AXIS
).length () / 2;
143 dx_f_drul_
[d
] -= d
* x_gap_f
;
145 if (stem_l
->dir_
!= dir_
)
147 dy_f_drul_
[d
] = note_column_drul
[d
]->extent (Y_AXIS
)[dir_
];
151 dy_f_drul_
[d
] = stem_l
->chord_start_f ()
152 + dir_
* internote_f
;
154 dy_f_drul_
[d
] += dir_
* y_gap_f
;
157 side attached to (visible) stem
161 dx_f_drul_
[d
] = stem_l
->hpos_f ()
162 - spanned_drul_
[d
]->absolute_coordinate (X_AXIS
);
164 side attached to beamed stem
166 if (stem_l
->beam_l_
&& (stem_l
->beams_i_drul_
[-d
] >= 1))
168 dy_f_drul_
[d
] = stem_l
->extent (Y_AXIS
)[dir_
];
169 dy_f_drul_
[d
] += dir_
* 2 * y_gap_f
;
172 side attached to notehead, with stem getting in the way
176 dx_f_drul_
[d
] -= d
* x_gap_f
;
178 dy_f_drul_
[d
] = stem_l
->chord_start_f ()
179 + dir_
* internote_f
;
180 dy_f_drul_
[d
] += dir_
* y_gap_f
;
190 need break-align too. what about other spanners?
193 dx_f_drul_
[d
] = spanned_drul_
[LEFT
]->extent (X_AXIS
).length ();
196 broken: should get y from other piece, so that slur
197 continues up/down trend
199 for now: be horizontal..
204 while (flip (&d
) != LEFT
);
206 int interstaff_i
= 0;
207 for (int i
= 0; i
< encompass_arr_
.size (); i
++)
209 Encompass_info
info (encompass_arr_
[i
], dir_
, this);
210 if (info
.interstaff_f_
)
215 bool interstaff_b
= interstaff_i
&& (interstaff_i
< encompass_arr_
.size ());
217 Drul_array
<Encompass_info
> info_drul
;
218 info_drul
[LEFT
] = Encompass_info (encompass_arr_
[0], dir_
, this);
219 info_drul
[RIGHT
] = Encompass_info (encompass_arr_
.top (), dir_
, this);
220 Real interstaff_f
= info_drul
[RIGHT
].interstaff_f_
221 - info_drul
[LEFT
].interstaff_f_
;
225 Direction d
= (encompass_arr_
.top () != spanned_drul_
[RIGHT
]) ?
227 dy_f_drul_
[d
] = info_drul
[d
].o_
[Y_AXIS
];
230 dy_f_drul_
[d
] -= info_drul
[d
].interstaff_f_
;
234 dy_f_drul_
[LEFT
] += info_drul
[d
].interstaff_f_
;
235 dy_f_drul_
[RIGHT
] += info_drul
[d
].interstaff_f_
;
242 Now we've got a fine slur
243 Catch and correct some ugly cases
253 height_damp_f
= paper_l ()->get_var ("slur_height_damping");
254 slope_damp_f
= paper_l ()->get_var ("slur_slope_damping");
255 snap_f
= paper_l ()->get_var ("slur_snap_to_stem");
256 snap_max_dy_f
= paper_l ()->get_var ("slur_snap_max_slope_change");
260 height_damp_f
= paper_l ()->get_var ("slur_interstaff_height_damping");
261 slope_damp_f
= paper_l ()->get_var ("slur_interstaff_slope_damping");
262 snap_f
= paper_l ()->get_var ("slur_interstaff_snap_to_stem");
263 snap_max_dy_f
= paper_l ()->get_var ("slur_interstaff_snap_max_slope_change");
267 dy_f_drul_
[RIGHT
] += interstaff_f
;
269 Real dy_f
= dy_f_drul_
[RIGHT
] - dy_f_drul_
[LEFT
];
271 dy_f
-= interstaff_f
;
272 Real dx_f
= do_width ().length () + dx_f_drul_
[RIGHT
] - dx_f_drul_
[LEFT
];
275 Avoid too steep slurs.
277 Real slope_ratio_f
= abs (dy_f
/ dx_f
);
278 if (slope_ratio_f
> slope_damp_f
)
280 Direction d
= (Direction
)(- dir_
* (sign (dy_f
)));
283 Real damp_f
= (slope_ratio_f
- slope_damp_f
) * dx_f
;
285 must never change sign of dy
287 damp_f
= damp_f
<? abs (dy_f
);
288 dy_f_drul_
[d
] += dir_
* damp_f
;
294 Wierd slurs may look a lot better after they have been
296 So, we'll do this in 3 steps
298 for (int i
= 0; i
< 3; i
++)
300 Drul_array
<Interval
> curve_xy_drul
= curve_extent_drul ();
301 Real height_f
= curve_xy_drul
[Y
].length ();
302 Real width_f
= curve_xy_drul
[X
].length ();
304 dy_f
= dy_f_drul_
[RIGHT
] - dy_f_drul_
[LEFT
];
306 dy_f
-= interstaff_f
;
308 Real height_ratio_f
= abs (height_f
/ width_f
);
309 if (height_ratio_f
> height_damp_f
)
311 Direction d
= (Direction
)(- dir_
* (sign (dy_f
)));
314 /* take third step */
315 Real damp_f
= (height_ratio_f
- height_damp_f
) * width_f
/ 3;
317 if y positions at about the same height, correct both ends
319 if (abs (dy_f
/ dx_f
) < slope_damp_f
)
321 dy_f_drul_
[-d
] += dir_
* damp_f
;
322 dy_f_drul_
[d
] += dir_
* damp_f
;
325 don't change slope too much, would have been catched by slope damping
329 damp_f
= damp_f
<? abs (dy_f
/2);
330 dy_f_drul_
[d
] += dir_
* damp_f
;
336 If, after correcting, we're close to stem-end...
338 Drul_array
<Real
> snapy_f_drul
;
339 snapy_f_drul
[LEFT
] = snapy_f_drul
[RIGHT
] = 0;
340 Drul_array
<Real
> snapx_f_drul
;
341 snapx_f_drul
[LEFT
] = snapx_f_drul
[RIGHT
] = 0;
342 Drul_array
<bool> snapped_b_drul
;
343 snapped_b_drul
[LEFT
] = snapped_b_drul
[RIGHT
] = false;
346 if ((note_column_drul
[d
] == spanned_drul_
[d
])
347 && (note_column_drul
[d
]->stem_l_
)
348 && (note_column_drul
[d
]->stem_l_
->dir_
== dir_
)
349 && (abs (note_column_drul
[d
]->stem_l_
->extent (Y_AXIS
)[dir_
]
350 - dy_f_drul_
[d
] + (d
== LEFT
? 0 : interstaff_f
))
354 prepare to attach to stem-end
356 Stem
* stem_l
= note_column_drul
[d
]->stem_l_
;
357 snapx_f_drul
[d
] = stem_l
->hpos_f ()
358 - spanned_drul_
[d
]->absolute_coordinate (X_AXIS
);
359 snapy_f_drul
[d
] = stem_l
->extent (Y_AXIS
)[dir_
];
360 snapy_f_drul
[d
] += info_drul
[d
].interstaff_f_
;
361 snapy_f_drul
[d
] += dir_
* 2 * y_gap_f
;
362 snapped_b_drul
[d
] = true;
365 while (flip (&d
) != LEFT
);
368 only use snapped positions if sign (dy) will not change
369 and dy doesn't change too much
372 dy_f
+= interstaff_f
;
373 if (snapped_b_drul
[LEFT
] && snapped_b_drul
[RIGHT
]
374 && ((sign (snapy_f_drul
[RIGHT
] - snapy_f_drul
[LEFT
]) == sign (dy_f
)))
375 && (!dy_f
|| (abs (snapy_f_drul
[RIGHT
] - snapy_f_drul
[LEFT
] - dy_f
)
376 < abs (dy_f
* snap_max_dy_f
))))
380 dy_f_drul_
[d
] = snapy_f_drul
[d
];
381 dx_f_drul_
[d
] = snapx_f_drul
[d
];
383 while (flip (&d
) != LEFT
);
386 else if (snapped_b_drul
[LEFT
]
387 && ((sign (dy_f_drul_
[RIGHT
] - snapy_f_drul
[LEFT
]) == sign (dy_f
)))
388 && (!dy_f
|| (abs (dy_f_drul_
[RIGHT
] - snapy_f_drul
[LEFT
] - dy_f
)
389 < abs (dy_f
* snap_max_dy_f
))))
392 dy_f_drul_
[d
] = snapy_f_drul
[d
];
393 dx_f_drul_
[d
] = snapx_f_drul
[d
];
395 else if (snapped_b_drul
[RIGHT
]
396 && ((sign (snapy_f_drul
[RIGHT
] - dy_f_drul_
[LEFT
]) == sign (dy_f
)))
397 && (!dy_f
|| (abs (snapy_f_drul
[RIGHT
] - dy_f_drul_
[LEFT
] - dy_f
)
398 < abs (dy_f
* snap_max_dy_f
))))
401 dy_f_drul_
[d
] = snapy_f_drul
[d
];
402 dx_f_drul_
[d
] = snapx_f_drul
[d
];
407 Slur::get_encompass_offset_arr () const
409 Array
<Offset
> offset_arr
;
412 check non-disturbed slur
413 FIXME: x of ends off by a tiny bit!!
415 offset_arr
.push (Offset (0, dy_f_drul_
[LEFT
]));
416 offset_arr
.push (Offset (0, dy_f_drul_
[RIGHT
]));
420 int interstaff_i
= 0;
421 for (int i
= 0; i
< encompass_arr_
.size (); i
++)
423 Encompass_info
info (encompass_arr_
[i
], dir_
, this);
424 if (info
.interstaff_f_
)
429 bool interstaff_b
= interstaff_i
&& (interstaff_i
< encompass_arr_
.size ());
431 Offset
origin (absolute_coordinate (X_AXIS
), 0);
434 int last
= encompass_arr_
.size () - 2;
436 offset_arr
.push (Offset (dx_f_drul_
[LEFT
], dy_f_drul_
[LEFT
]));
440 if (encompass_arr_
[0] != spanned_drul_
[LEFT
])
443 Encompass_info
left_info (encompass_arr_
[0], dir_
, this);
445 offset_arr
[0][Y_AXIS
] += left_info
.interstaff_f_
;
451 if (encompass_arr_
.top () != spanned_drul_
[RIGHT
])
456 for (int i
= first
; i
<= last
; i
++)
458 Encompass_info
info (encompass_arr_
[i
], dir_
, this);
459 offset_arr
.push (info
.o_
- origin
);
462 offset_arr
.push (Offset (do_width ().length () + dx_f_drul_
[RIGHT
],
470 Slur::get_rods () const
474 r
.item_l_drul_
= spanned_drul_
;
475 r
.distance_f_
= paper_l ()->get_var ("slur_x_minimum");