2 fingering-engraver.cc -- implement New_fingering_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
11 #include "international.hh"
12 #include "rhythmic-head.hh"
13 #include "script-interface.hh"
14 #include "self-alignment-interface.hh"
15 #include "side-position-interface.hh"
17 #include "stream-event.hh"
21 #include "translator.icc"
29 Stream_event
*note_event_
;
30 Stream_event
*finger_event_
;
31 bool follow_into_staff_
;
38 note_event_
= finger_event_
= 0;
39 follow_into_staff_
= false;
44 operator< (Finger_tuple
const &a
, Finger_tuple
const &b
)
46 return a
.position_
< b
.position_
;
49 class New_fingering_engraver
: public Engraver
51 vector
<Finger_tuple
> fingerings_
;
52 vector
<Finger_tuple
> stroke_fingerings_
;
53 vector
<Finger_tuple
> articulations_
;
54 vector
<Finger_tuple
> string_numbers_
;
61 TRANSLATOR_DECLARATIONS (New_fingering_engraver
);
63 void stop_translation_timestep ();
64 DECLARE_ACKNOWLEDGER (rhythmic_head
);
65 DECLARE_ACKNOWLEDGER (stem
);
66 void add_fingering (Grob
*, SCM
,
67 vector
<Finger_tuple
> *,
68 Stream_event
*, Stream_event
*);
69 void add_script (Grob
*, Stream_event
*, Stream_event
*);
70 void add_string (Grob
*, Stream_event
*, Stream_event
*);
71 void position_scripts (SCM orientations
, vector
<Finger_tuple
> *);
75 New_fingering_engraver::acknowledge_rhythmic_head (Grob_info inf
)
77 Stream_event
*note_ev
= inf
.event_cause ();
81 SCM arts
= note_ev
->get_property ("articulations");
83 for (SCM s
= arts
; scm_is_pair (s
); s
= scm_cdr (s
))
85 Stream_event
*ev
= unsmob_stream_event (scm_car (s
));
90 if (ev
->in_event_class ("fingering-event"))
91 add_fingering (inf
.grob (),
92 ly_symbol2scm ("Fingering"),
95 else if (ev
->in_event_class ("text-script-event"))
96 ev
->origin ()->warning (_ ("cannot add text scripts to individual note heads"));
97 else if (ev
->in_event_class ("script-event"))
98 add_script (inf
.grob (), ev
, note_ev
);
99 else if (ev
->in_event_class ("string-number-event"))
100 add_fingering (inf
.grob (),
101 ly_symbol2scm ("StringNumber"), &string_numbers_
,
103 else if (ev
->in_event_class ("stroke-finger-event"))
104 add_fingering (inf
.grob (),
105 ly_symbol2scm ("StrokeFinger"), &stroke_fingerings_
,
107 else if (ev
->in_event_class ("harmonic-event"))
109 inf
.grob ()->set_property ("style", ly_symbol2scm ("harmonic"));
110 Grob
*d
= unsmob_grob (inf
.grob ()->get_object ("dot"));
111 if (d
&& !to_boolean (get_property ("harmonicDots")))
116 heads_
.push_back (inf
.grob ());
120 New_fingering_engraver::acknowledge_stem (Grob_info inf
)
126 New_fingering_engraver::add_script (Grob
*head
,
128 Stream_event
* /* note */)
132 Grob
*g
= make_item ("Script", event
->self_scm ());
133 make_script_from_event (g
, context (),
134 event
->get_property ("articulation-type"), 0);
136 ft
.script_
->set_parent (head
, X_AXIS
);
138 articulations_
.push_back (ft
);
142 New_fingering_engraver::add_fingering (Grob
*head
,
144 vector
<Finger_tuple
> *tuple_vector
,
146 Stream_event
*hevent
)
150 ft
.script_
= internal_make_item (grob_sym
, event
->self_scm (),
151 ly_symbol2string (grob_sym
).c_str (),
152 __FILE__
, __LINE__
, __FUNCTION__
155 Side_position_interface::add_support (ft
.script_
, head
);
157 ft
.finger_event_
= event
;
158 ft
.note_event_
= hevent
;
161 tuple_vector
->push_back (ft
);
165 New_fingering_engraver::position_scripts (SCM orientations
,
166 vector
<Finger_tuple
> *scripts
)
168 for (vsize i
= 0; i
< scripts
->size (); i
++)
169 if (stem_
&& to_boolean (scripts
->at (i
).script_
->get_property ("add-stem-support")))
170 Side_position_interface::add_support (scripts
->at (i
).script_
, stem_
);
173 This is not extremely elegant, but we have to do a little
174 formatting here, because the parent/child relations should be
175 known before we move on to the next time step.
177 A more sophisticated approach would be to set both X and Y parents
178 to the note head, and write a more flexible function for
179 positioning the fingerings, setting both X and Y coordinates.
181 for (vsize i
= 0; i
< scripts
->size (); i
++)
182 (*scripts
)[i
].position_
= scm_to_int ((*scripts
)[i
].head_
->get_property ("staff-position"));
184 for (vsize i
= scripts
->size (); i
--;)
185 for (vsize j
= heads_
.size (); j
--;)
186 Side_position_interface::add_support ((*scripts
)[i
].script_
, heads_
[j
]);
188 vector
<Finger_tuple
> up
, down
, horiz
;
189 for (vsize i
= scripts
->size (); i
--;)
191 SCM d
= (*scripts
)[i
].finger_event_
->get_property ("direction");
194 ((to_dir (d
) == UP
) ? up
: down
).push_back ((*scripts
)[i
]);
195 scripts
->erase (scripts
->begin () + i
);
199 vector_sort (*scripts
, less
<Finger_tuple
> ());
201 bool up_p
= scm_c_memq (ly_symbol2scm ("up"), orientations
) != SCM_BOOL_F
;
202 bool down_p
= scm_c_memq (ly_symbol2scm ("down"), orientations
) != SCM_BOOL_F
;
203 bool left_p
= scm_c_memq (ly_symbol2scm ("left"), orientations
) != SCM_BOOL_F
;
204 bool right_p
= scm_c_memq (ly_symbol2scm ("right"), orientations
) != SCM_BOOL_F
;
205 Direction hordir
= (right_p
) ? RIGHT
: LEFT
;
206 if (left_p
|| right_p
)
208 if (up_p
&& !up
.size () && scripts
->size ())
210 up
.push_back (scripts
->back ());
211 scripts
->pop_back ();
214 if (down_p
&& !down
.size () && scripts
->size ())
216 down
.push_back ((*scripts
)[0]);
217 scripts
->erase (scripts
->begin ());
220 horiz
.insert (horiz
.end (), scripts
->begin (), scripts
->end ());
222 else if (up_p
&& down_p
)
224 int center
= scripts
->size () / 2;
225 down
.insert (down
.end (), scripts
->begin (), scripts
->begin () + center
);
226 up
.insert (up
.end (), scripts
->begin () + center
, scripts
->end ());
230 up
.insert (up
.end (), scripts
->begin (), scripts
->end ());
237 warning (_ ("no placement found for fingerings"));
238 warning (_ ("placing below"));
240 down
.insert (down
.end (), scripts
->begin (), scripts
->end ());
244 for (vsize i
= 0; i
< horiz
.size (); i
++)
246 Finger_tuple ft
= horiz
[i
];
247 Grob
*f
= ft
.script_
;
248 f
->set_parent (ft
.head_
, X_AXIS
);
249 f
->set_parent (ft
.head_
, Y_AXIS
);
250 f
->set_property ("avoid-slur", SCM_BOOL_F
);
252 && unsmob_grob (ft
.head_
->get_object ("accidental-grob")))
253 Side_position_interface::add_support (f
,
254 unsmob_grob (ft
.head_
->get_object ("accidental-grob")));
255 else if (unsmob_grob (ft
.head_
->get_object ("dot")))
256 Side_position_interface::add_support (f
,
257 unsmob_grob (ft
.head_
->get_object ("dot")));
259 Self_alignment_interface::set_align_self (f
, Y_AXIS
);
260 Self_alignment_interface::set_center_parent (f
, Y_AXIS
);
261 Side_position_interface::set_axis (f
, X_AXIS
);
263 f
->set_property ("direction", scm_from_int (hordir
));
267 Drul_array
< vector
<Finger_tuple
> > vertical (down
, up
);
270 for (vsize i
= 0; i
< vertical
[d
].size (); i
++)
272 Finger_tuple ft
= vertical
[d
][i
];
273 Grob
*f
= ft
.script_
;
274 int finger_prio
= robust_scm2int (f
->get_property ("script-priority"), 200);
275 f
->set_parent (ft
.head_
, X_AXIS
);
276 f
->set_property ("script-priority",
277 scm_from_int (finger_prio
+ d
* ft
.position_
));
279 Self_alignment_interface::set_align_self (f
, X_AXIS
);
280 Self_alignment_interface::set_center_parent (f
, X_AXIS
);
281 Side_position_interface::set_axis (f
, Y_AXIS
);
283 f
->set_property ("direction", scm_from_int (d
));
286 while (flip (&d
) != DOWN
);
290 New_fingering_engraver::stop_translation_timestep ()
299 New_fingering_engraver::position_all ()
301 if (fingerings_
.size ())
303 position_scripts (get_property ("fingeringOrientations"),
305 fingerings_
.clear ();
308 if (string_numbers_
.size ())
310 position_scripts (get_property ("stringNumberOrientations"),
312 string_numbers_
.clear ();
315 if (stroke_fingerings_
.size ())
317 position_scripts (get_property ("strokeFingerOrientations"),
318 &stroke_fingerings_
);
319 stroke_fingerings_
.clear ();
322 for (vsize i
= articulations_
.size (); i
--;)
324 Grob
*script
= articulations_
[i
].script_
;
326 for (vsize j
= heads_
.size (); j
--;)
327 Side_position_interface::add_support (script
, heads_
[j
]);
329 if (stem_
&& to_dir (script
->get_property ("side-relative-direction")))
330 script
->set_object ("direction-source", stem_
->self_scm ());
332 if (stem_
&& to_boolean (script
->get_property ("add-stem-support")))
333 Side_position_interface::add_support (script
, stem_
);
335 articulations_
.clear ();
338 New_fingering_engraver::New_fingering_engraver ()
344 ADD_ACKNOWLEDGER (New_fingering_engraver
, rhythmic_head
);
345 ADD_ACKNOWLEDGER (New_fingering_engraver
, stem
);
347 ADD_TRANSLATOR (New_fingering_engraver
,
349 "Create fingering scripts for notes in a new chord. This"
350 " engraver is ill-named, since it also takes care of"
351 " articulations and harmonic note heads.",
360 "fingeringOrientations "
362 "strokeFingerOrientations "
363 "stringNumberOrientations ",