2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2010 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "engraver.hh"
22 #include "international.hh"
23 #include "rhythmic-head.hh"
24 #include "script-interface.hh"
25 #include "self-alignment-interface.hh"
26 #include "side-position-interface.hh"
28 #include "stream-event.hh"
32 #include "translator.icc"
40 Stream_event
*note_event_
;
41 Stream_event
*finger_event_
;
42 bool follow_into_staff_
;
49 note_event_
= finger_event_
= 0;
50 follow_into_staff_
= false;
55 operator< (Finger_tuple
const &a
, Finger_tuple
const &b
)
57 return a
.position_
< b
.position_
;
60 class New_fingering_engraver
: public Engraver
62 vector
<Finger_tuple
> fingerings_
;
63 vector
<Finger_tuple
> stroke_fingerings_
;
64 vector
<Finger_tuple
> articulations_
;
65 vector
<Finger_tuple
> string_numbers_
;
72 TRANSLATOR_DECLARATIONS (New_fingering_engraver
);
74 void stop_translation_timestep ();
75 DECLARE_ACKNOWLEDGER (rhythmic_head
);
76 DECLARE_ACKNOWLEDGER (stem
);
77 void add_fingering (Grob
*, SCM
,
78 vector
<Finger_tuple
> *,
79 Stream_event
*, Stream_event
*);
80 void add_script (Grob
*, Stream_event
*, Stream_event
*);
81 void add_string (Grob
*, Stream_event
*, Stream_event
*);
82 void position_scripts (SCM orientations
, vector
<Finger_tuple
> *);
86 New_fingering_engraver::acknowledge_rhythmic_head (Grob_info inf
)
88 Stream_event
*note_ev
= inf
.event_cause ();
92 SCM arts
= note_ev
->get_property ("articulations");
94 for (SCM s
= arts
; scm_is_pair (s
); s
= scm_cdr (s
))
96 Stream_event
*ev
= unsmob_stream_event (scm_car (s
));
101 if (ev
->in_event_class ("fingering-event"))
102 add_fingering (inf
.grob (),
103 ly_symbol2scm ("Fingering"),
106 else if (ev
->in_event_class ("text-script-event"))
107 ev
->origin ()->warning (_ ("cannot add text scripts to individual note heads"));
108 else if (ev
->in_event_class ("script-event"))
109 add_script (inf
.grob (), ev
, note_ev
);
110 else if (ev
->in_event_class ("string-number-event"))
111 add_fingering (inf
.grob (),
112 ly_symbol2scm ("StringNumber"), &string_numbers_
,
114 else if (ev
->in_event_class ("stroke-finger-event"))
115 add_fingering (inf
.grob (),
116 ly_symbol2scm ("StrokeFinger"), &stroke_fingerings_
,
118 else if (ev
->in_event_class ("harmonic-event"))
120 inf
.grob ()->set_property ("style", ly_symbol2scm ("harmonic"));
121 Grob
*d
= unsmob_grob (inf
.grob ()->get_object ("dot"));
122 if (d
&& !to_boolean (get_property ("harmonicDots")))
127 heads_
.push_back (inf
.grob ());
131 New_fingering_engraver::acknowledge_stem (Grob_info inf
)
137 New_fingering_engraver::add_script (Grob
*head
,
139 Stream_event
* /* note */)
143 Grob
*g
= make_item ("Script", event
->self_scm ());
144 make_script_from_event (g
, context (),
145 event
->get_property ("articulation-type"), 0);
147 ft
.script_
->set_parent (head
, X_AXIS
);
149 articulations_
.push_back (ft
);
153 New_fingering_engraver::add_fingering (Grob
*head
,
155 vector
<Finger_tuple
> *tuple_vector
,
157 Stream_event
*hevent
)
161 ft
.script_
= internal_make_item (grob_sym
, event
->self_scm (),
162 ly_symbol2string (grob_sym
).c_str (),
163 __FILE__
, __LINE__
, __FUNCTION__
166 Side_position_interface::add_support (ft
.script_
, head
);
168 ft
.finger_event_
= event
;
169 ft
.note_event_
= hevent
;
172 tuple_vector
->push_back (ft
);
176 New_fingering_engraver::position_scripts (SCM orientations
,
177 vector
<Finger_tuple
> *scripts
)
179 for (vsize i
= 0; i
< scripts
->size (); i
++)
180 if (stem_
&& to_boolean (scripts
->at (i
).script_
->get_property ("add-stem-support")))
181 Side_position_interface::add_support (scripts
->at (i
).script_
, stem_
);
184 This is not extremely elegant, but we have to do a little
185 formatting here, because the parent/child relations should be
186 known before we move on to the next time step.
188 A more sophisticated approach would be to set both X and Y parents
189 to the note head, and write a more flexible function for
190 positioning the fingerings, setting both X and Y coordinates.
192 for (vsize i
= 0; i
< scripts
->size (); i
++)
193 (*scripts
)[i
].position_
= scm_to_int ((*scripts
)[i
].head_
->get_property ("staff-position"));
195 for (vsize i
= scripts
->size (); i
--;)
196 for (vsize j
= heads_
.size (); j
--;)
197 Side_position_interface::add_support ((*scripts
)[i
].script_
, heads_
[j
]);
199 vector
<Finger_tuple
> up
, down
, horiz
;
200 for (vsize i
= scripts
->size (); i
--;)
202 SCM d
= (*scripts
)[i
].finger_event_
->get_property ("direction");
205 ((to_dir (d
) == UP
) ? up
: down
).push_back ((*scripts
)[i
]);
206 scripts
->erase (scripts
->begin () + i
);
210 vector_sort (*scripts
, less
<Finger_tuple
> ());
212 bool up_p
= scm_c_memq (ly_symbol2scm ("up"), orientations
) != SCM_BOOL_F
;
213 bool down_p
= scm_c_memq (ly_symbol2scm ("down"), orientations
) != SCM_BOOL_F
;
214 bool left_p
= scm_c_memq (ly_symbol2scm ("left"), orientations
) != SCM_BOOL_F
;
215 bool right_p
= scm_c_memq (ly_symbol2scm ("right"), orientations
) != SCM_BOOL_F
;
216 Direction hordir
= (right_p
) ? RIGHT
: LEFT
;
217 if (left_p
|| right_p
)
219 if (up_p
&& !up
.size () && scripts
->size ())
221 up
.push_back (scripts
->back ());
222 scripts
->pop_back ();
225 if (down_p
&& !down
.size () && scripts
->size ())
227 down
.push_back ((*scripts
)[0]);
228 scripts
->erase (scripts
->begin ());
231 horiz
.insert (horiz
.end (), scripts
->begin (), scripts
->end ());
233 else if (up_p
&& down_p
)
235 int center
= scripts
->size () / 2;
236 down
.insert (down
.end (), scripts
->begin (), scripts
->begin () + center
);
237 up
.insert (up
.end (), scripts
->begin () + center
, scripts
->end ());
241 up
.insert (up
.end (), scripts
->begin (), scripts
->end ());
248 warning (_ ("no placement found for fingerings"));
249 warning (_ ("placing below"));
251 down
.insert (down
.end (), scripts
->begin (), scripts
->end ());
255 for (vsize i
= 0; i
< horiz
.size (); i
++)
257 Finger_tuple ft
= horiz
[i
];
258 Grob
*f
= ft
.script_
;
259 f
->set_parent (ft
.head_
, X_AXIS
);
260 f
->set_parent (ft
.head_
, Y_AXIS
);
261 f
->set_property ("avoid-slur", SCM_BOOL_F
);
263 && unsmob_grob (ft
.head_
->get_object ("accidental-grob")))
264 Side_position_interface::add_support (f
,
265 unsmob_grob (ft
.head_
->get_object ("accidental-grob")));
266 else if (unsmob_grob (ft
.head_
->get_object ("dot")))
267 Side_position_interface::add_support (f
,
268 unsmob_grob (ft
.head_
->get_object ("dot")));
270 Self_alignment_interface::set_align_self (f
, Y_AXIS
);
271 Self_alignment_interface::set_center_parent (f
, Y_AXIS
);
272 Side_position_interface::set_axis (f
, X_AXIS
);
274 f
->set_property ("direction", scm_from_int (hordir
));
278 Drul_array
< vector
<Finger_tuple
> > vertical (down
, up
);
281 for (vsize i
= 0; i
< vertical
[d
].size (); i
++)
283 Finger_tuple ft
= vertical
[d
][i
];
284 Grob
*f
= ft
.script_
;
285 int finger_prio
= robust_scm2int (f
->get_property ("script-priority"), 200);
286 f
->set_parent (ft
.head_
, X_AXIS
);
287 f
->set_property ("script-priority",
288 scm_from_int (finger_prio
+ d
* ft
.position_
));
290 Self_alignment_interface::set_align_self (f
, X_AXIS
);
291 Self_alignment_interface::set_center_parent (f
, X_AXIS
);
292 Side_position_interface::set_axis (f
, Y_AXIS
);
294 f
->set_property ("direction", scm_from_int (d
));
297 while (flip (&d
) != DOWN
);
301 New_fingering_engraver::stop_translation_timestep ()
310 New_fingering_engraver::position_all ()
312 if (fingerings_
.size ())
314 position_scripts (get_property ("fingeringOrientations"),
316 fingerings_
.clear ();
319 if (string_numbers_
.size ())
321 position_scripts (get_property ("stringNumberOrientations"),
323 string_numbers_
.clear ();
326 if (stroke_fingerings_
.size ())
328 position_scripts (get_property ("strokeFingerOrientations"),
329 &stroke_fingerings_
);
330 stroke_fingerings_
.clear ();
333 for (vsize i
= articulations_
.size (); i
--;)
335 Grob
*script
= articulations_
[i
].script_
;
337 for (vsize j
= heads_
.size (); j
--;)
338 Side_position_interface::add_support (script
, heads_
[j
]);
340 if (stem_
&& to_dir (script
->get_property ("side-relative-direction")))
341 script
->set_object ("direction-source", stem_
->self_scm ());
343 if (stem_
&& to_boolean (script
->get_property ("add-stem-support")))
344 Side_position_interface::add_support (script
, stem_
);
346 articulations_
.clear ();
349 New_fingering_engraver::New_fingering_engraver ()
355 ADD_ACKNOWLEDGER (New_fingering_engraver
, rhythmic_head
);
356 ADD_ACKNOWLEDGER (New_fingering_engraver
, stem
);
358 ADD_TRANSLATOR (New_fingering_engraver
,
360 "Create fingering scripts for notes in a new chord. This"
361 " engraver is ill-named, since it also takes care of"
362 " articulations and harmonic note heads.",
371 "fingeringOrientations "
373 "strokeFingerOrientations "
374 "stringNumberOrientations ",