2 fingering-engraver.cc -- implement New_fingering_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2008 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
,
134 Grob
*g
= make_item ("Script", event
->self_scm ());
135 make_script_from_event (g
, context (),
136 event
->get_property ("articulation-type"), 0);
138 ft
.script_
->set_parent (head
, X_AXIS
);
140 articulations_
.push_back (ft
);
144 New_fingering_engraver::add_fingering (Grob
*head
,
146 vector
<Finger_tuple
> *tuple_vector
,
148 Stream_event
*hevent
)
152 ft
.script_
= internal_make_item (grob_sym
, event
->self_scm (),
153 ly_symbol2string (grob_sym
).c_str (),
154 __FILE__
, __LINE__
, __FUNCTION__
157 Side_position_interface::add_support (ft
.script_
, head
);
159 ft
.finger_event_
= event
;
160 ft
.note_event_
= hevent
;
163 tuple_vector
->push_back (ft
);
167 New_fingering_engraver::position_scripts (SCM orientations
,
168 vector
<Finger_tuple
> *scripts
)
170 for (vsize i
= 0; i
< scripts
->size (); i
++)
171 if (stem_
&& to_boolean (scripts
->at (i
).script_
->get_property ("add-stem-support")))
172 Side_position_interface::add_support (scripts
->at (i
).script_
, stem_
);
175 This is not extremely elegant, but we have to do a little
176 formatting here, because the parent/child relations should be
177 known before we move on to the next time step.
179 A more sophisticated approach would be to set both X and Y parents
180 to the note head, and write a more flexible function for
181 positioning the fingerings, setting both X and Y coordinates.
183 for (vsize i
= 0; i
< scripts
->size (); i
++)
184 (*scripts
)[i
].position_
= scm_to_int ((*scripts
)[i
].head_
->get_property ("staff-position"));
186 for (vsize i
= scripts
->size (); i
--;)
187 for (vsize j
= heads_
.size (); j
--;)
188 Side_position_interface::add_support ((*scripts
)[i
].script_
, heads_
[j
]);
190 vector
<Finger_tuple
> up
, down
, horiz
;
191 for (vsize i
= scripts
->size (); i
--;)
193 SCM d
= (*scripts
)[i
].finger_event_
->get_property ("direction");
196 ((to_dir (d
) == UP
) ? up
: down
).push_back ((*scripts
)[i
]);
197 scripts
->erase (scripts
->begin () + i
);
201 vector_sort (*scripts
, less
<Finger_tuple
> ());
203 bool up_p
= scm_c_memq (ly_symbol2scm ("up"), orientations
) != SCM_BOOL_F
;
204 bool down_p
= scm_c_memq (ly_symbol2scm ("down"), orientations
) != SCM_BOOL_F
;
205 bool left_p
= scm_c_memq (ly_symbol2scm ("left"), orientations
) != SCM_BOOL_F
;
206 bool right_p
= scm_c_memq (ly_symbol2scm ("right"), orientations
) != SCM_BOOL_F
;
207 Direction hordir
= (right_p
) ? RIGHT
: LEFT
;
208 if (left_p
|| right_p
)
210 if (up_p
&& !up
.size () && scripts
->size ())
212 up
.push_back (scripts
->back ());
213 scripts
->pop_back ();
216 if (down_p
&& !down
.size () && scripts
->size ())
218 down
.push_back ((*scripts
)[0]);
219 scripts
->erase (scripts
->begin ());
222 horiz
.insert (horiz
.end (), scripts
->begin (), scripts
->end ());
224 else if (up_p
&& down_p
)
226 int center
= scripts
->size () / 2;
227 down
.insert (down
.end (), scripts
->begin (), scripts
->begin () + center
);
228 up
.insert (up
.end (), scripts
->begin () + center
, scripts
->end ());
232 up
.insert (up
.end (), scripts
->begin (), scripts
->end ());
239 warning (_ ("no placement found for fingerings"));
240 warning (_ ("placing below"));
242 down
.insert (down
.end (), scripts
->begin (), scripts
->end ());
246 for (vsize i
= 0; i
< horiz
.size (); i
++)
248 Finger_tuple ft
= horiz
[i
];
249 Grob
*f
= ft
.script_
;
250 f
->set_parent (ft
.head_
, X_AXIS
);
251 f
->set_parent (ft
.head_
, Y_AXIS
);
252 f
->set_property ("avoid-slur", SCM_BOOL_F
);
254 && unsmob_grob (ft
.head_
->get_object ("accidental-grob")))
255 Side_position_interface::add_support (f
,
256 unsmob_grob (ft
.head_
->get_object ("accidental-grob")));
258 Self_alignment_interface::set_align_self (f
, Y_AXIS
);
259 Self_alignment_interface::set_center_parent (f
, Y_AXIS
);
260 Side_position_interface::set_axis (f
, X_AXIS
);
262 f
->set_property ("direction", scm_from_int (hordir
));
266 Drul_array
< vector
<Finger_tuple
> > vertical (down
, up
);
269 for (vsize i
= 0; i
< vertical
[d
].size (); i
++)
271 Finger_tuple ft
= vertical
[d
][i
];
272 Grob
*f
= ft
.script_
;
273 int finger_prio
= robust_scm2int (f
->get_property ("script-priority"), 200);
274 f
->set_parent (ft
.head_
, X_AXIS
);
275 f
->set_property ("script-priority",
276 scm_from_int (finger_prio
+ d
* ft
.position_
));
278 Self_alignment_interface::set_align_self (f
, X_AXIS
);
279 Self_alignment_interface::set_center_parent (f
, X_AXIS
);
280 Side_position_interface::set_axis (f
, Y_AXIS
);
282 f
->set_property ("direction", scm_from_int (d
));
285 while (flip (&d
) != DOWN
);
289 New_fingering_engraver::stop_translation_timestep ()
298 New_fingering_engraver::position_all ()
300 if (fingerings_
.size ())
302 position_scripts (get_property ("fingeringOrientations"),
304 fingerings_
.clear ();
307 if (string_numbers_
.size ())
309 position_scripts (get_property ("stringNumberOrientations"),
311 string_numbers_
.clear ();
314 if (stroke_fingerings_
.size ())
316 position_scripts (get_property ("strokeFingerOrientations"),
317 &stroke_fingerings_
);
318 stroke_fingerings_
.clear ();
321 for (vsize i
= articulations_
.size (); i
--;)
323 Grob
*script
= articulations_
[i
].script_
;
325 for (vsize j
= heads_
.size (); j
--;)
326 Side_position_interface::add_support (script
, heads_
[j
]);
328 if (stem_
&& to_dir (script
->get_property ("side-relative-direction")))
329 script
->set_object ("direction-source", stem_
->self_scm ());
331 if (stem_
&& to_boolean (script
->get_property ("add-stem-support")))
332 Side_position_interface::add_support (script
, stem_
);
334 articulations_
.clear ();
337 New_fingering_engraver::New_fingering_engraver ()
343 ADD_ACKNOWLEDGER (New_fingering_engraver
, rhythmic_head
);
344 ADD_ACKNOWLEDGER (New_fingering_engraver
, stem
);
346 ADD_TRANSLATOR (New_fingering_engraver
,
348 "Create fingering scripts for notes in a new chord. This"
349 " engraver is ill-named, since it also takes care of"
350 " articulations and harmonic note heads.",
359 "fingeringOrientations "
361 "strokeFingerOrientations "
362 "stringNumberOrientations ",