2 slur.cc -- implement Slur
4 source file of the GNU LilyPond music typesetter
6 (c) 1996, 1997 Han-Wen Nienhuys <hanwen@stack.nl>
12 think about crossing stems.
13 Begin and end should be treated as a Script.
18 #include "paper-def.hh"
19 #include "note-column.hh"
22 #include "molecule.hh"
28 IMPLEMENT_IS_TYPE_B1(Slur
,Spanner
);
31 Slur::add (Note_column
*n
)
33 encompass_arr_
.push (n
);
38 Slur::set_default_dir ()
41 for (int i
=0; i
< encompass_arr_
.size (); i
++)
43 if (encompass_arr_
[i
]->dir_
< 0)
52 Slur::do_add_processing ()
54 set_bounds (LEFT
, encompass_arr_
[0]);
55 if (encompass_arr_
.size () > 1)
56 set_bounds (RIGHT
, encompass_arr_
.top ());
60 Slur::do_pre_processing ()
62 // don't set directions
66 Slur::do_substitute_dependency (Score_elem
*o
, Score_elem
*n
)
69 while ((i
= encompass_arr_
.find_i ((Note_column
*)o
->item ())) >=0)
72 encompass_arr_
[i
] = (Note_column
*)n
->item ();
74 encompass_arr_
.del (i
);
79 Note_column_compare (Note_column
*const&n1
, Note_column
* const&n2
)
81 return Item::left_right_compare (n1
, n2
);
85 Slur::do_post_processing ()
87 encompass_arr_
.sort (Note_column_compare
);
90 Real interline_f
= paper ()->interline_f ();
91 Real inter_f
= interline_f
/ 2;
94 [OSU]: slur and tie placement
97 * x = centre of head (upside-down: inner raakpunt stem) - d * gap
99 * y = length < 5ss : horizontal raakpunt + d * 0.25 ss
100 y = length >= 5ss : y next interline - d * 0.25 ss
101 --> height <= 5 length ?? we use <= 3 length, now...
103 * suggested gap = ss / 5;
105 // jcn: 1/5 seems so small?
106 Real gap_f
= interline_f
/ 2; // 5;
108 Drul_array
<Note_column
*> extrema
;
109 extrema
[LEFT
] = encompass_arr_
[0];
110 extrema
[RIGHT
] = encompass_arr_
.top ();
113 Real nw_f
= paper ()->note_width ();
117 if (extrema
[d
] != spanned_drul_
[d
])
120 *(spanned_drul_
[d
]->width ().length () -0.5*nw_f
);
122 else if (extrema
[d
]->stem_l_
&& !extrema
[d
]->stem_l_
->transparent_b_
)
124 dy_f_drul_
[d
] = (int)rint (extrema
[d
]->stem_l_
->height ()[dir_
]);
125 /* normal slur from notehead centre to notehead centre, minus gap */
126 // ugh: diff between old and new slurs
127 if (!experimental_features_global_b
)
128 dx_f_drul_
[d
] += -d
* gap_f
;
130 dx_f_drul_
[d
] += 0.5 * nw_f
- d
* gap_f
;
134 dy_f_drul_
[d
] = (int)rint (extrema
[d
]->head_positions_interval ()[dir_
])* inter_f
;
136 dy_f_drul_
[d
] += dir_
* interline_f
;
138 while (flip(&d
) != LEFT
);
142 Slur::height_f () const
144 Bezier_bow
bow (paper ());
145 Array
<Offset
> notes
= get_notes ();
146 bow
.set (notes
, dir_
);
149 Real dy1
= bow
.calc_f (height
);
154 bow
.set (notes
, dir_
);
155 Real dy2
= bow
.calc_f (height
);
159 if (abs (dy2
- dy1
) < paper ()->rule_thickness ())
168 Then we get for height = h{dy=0}
170 Real a
= (dy2
- dy1
) / dy1
;
174 if (check_debug
&& !monitor
->silent_b ("Slur"))
176 cout
<< "************" << endl
;
177 cout
<< "dy1: " << dy1
<< endl
;
178 cout
<< "dy2: " << dy2
<< endl
;
179 cout
<< "a: " << a
<< endl
;
180 cout
<< "b: " << b
<< endl
;
181 cout
<< "h: " << height
<< endl
;
188 Slur::brew_molecule_p () const
190 if (!experimental_features_global_b
)
191 return Bow::brew_molecule_p ();
193 Molecule
* mol_p
= new Molecule
;
195 Real dy_f
= dy_f_drul_
[RIGHT
] - dy_f_drul_
[LEFT
];
197 Real dx_f
= width ().length ();
198 dx_f
+= (dx_f_drul_
[RIGHT
] - dx_f_drul_
[LEFT
]);
200 Atom a
= paper ()->lookup_l ()->control_slur (get_controls (), dx_f
, dy_f
);
202 Real interline_f
= paper ()->interline_f ();
203 Real gap_f
= interline_f
/ 2; // 5;
204 Real nw_f
= paper ()->note_width ();
205 a
.translate (Offset (dx_f
+ 0.5 * nw_f
+ gap_f
, dy_f
+ dy_f_drul_
[LEFT
]));
211 Slur::get_notes () const
213 Real interline
= paper ()->interline_f ();
214 Real notewidth
= paper ()->note_width ();
215 Real internote
= interline
/ 2;
217 Stem
* left_stem
= encompass_arr_
[0]->stem_l_
;
218 Real left_x
= left_stem
->hpos_f ();
219 // ugh, do bow corrections (see brew_mol)
220 left_x
+= dx_f_drul_
[LEFT
] + 0.5 * notewidth
;
222 // ugh, do bow corrections (see brew_mol)
223 Real left_y
= dy_f_drul_
[LEFT
];
224 // ugh, where does this asymmetry come from?
226 left_y
-= dir_
* internote
;
229 urg, corrections for broken slurs: extra begin or end position
232 int n
= encompass_arr_
.size ();
233 if (encompass_arr_
[0] != spanned_drul_
[LEFT
])
237 left_x
= spanned_drul_
[LEFT
]->width ().length ();
240 if (encompass_arr_
.top () != spanned_drul_
[RIGHT
])
246 Real dx
= width ().length ();
247 dx
+= (dx_f_drul_
[RIGHT
] - dx_f_drul_
[LEFT
]);
249 dx
= dx
>? 2 * interline
;
251 Real dy
= (dy_f_drul_
[RIGHT
] - dy_f_drul_
[LEFT
]);
253 dy
= sign (dy
) * 1000;
257 notes
[n
- 1].x () = dx
;
258 notes
[n
- 1].y () = dy
;
259 for (int i
= 1; i
< n
- 1; i
++)
261 Stem
* stem
= encompass_arr_
[i
- first
]->stem_l_
;
263 set x to middle of notehead or on exact x position of stem,
264 according to slur direction
266 Real x
= stem
->hpos_f () - left_x
+ notewidth
/ 2;
267 if (stem
->dir_
!= dir_
)
269 else if (stem
->dir_
== UP
)
271 Real y
= stem
->dir_
== dir_
? stem
->stem_end_f ()
272 : stem
->stem_begin_f () + 2.5 * dir_
;
275 leave a gap: slur mustn't touch head/stem
288 Slur::get_controls () const
290 Bezier_bow
b (paper ());
291 b
.set (get_notes (), dir_
);
293 Array
<Offset
> controls
;
294 controls
.set_size (8);
295 for (int i
= 0; i
< 4; i
++)
296 controls
[i
] = b
.control_
[i
];
297 for (int i
= 0; i
< 4; i
++)
298 controls
[i
+ 4] = b
.return_
[i
];