2 fingering-engraver.cc -- implement New_fingering_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
11 #include "engraver.hh"
12 #include "side-position-interface.hh"
16 #include "rhythmic-head.hh"
17 #include "self-alignment-interface.hh"
34 note_event_
= finger_event_
= 0;
35 description_
= SCM_EOL
;
37 static int compare (Finger_tuple
const & c1
, Finger_tuple
const & c2
)
39 return c1
.position_
- c2
.position_
;
44 class New_fingering_engraver
: public Engraver
46 Array
<Finger_tuple
> fingerings_
;
47 Array
<Finger_tuple
> articulations_
;
48 Link_array
<Grob
> heads_
;
52 TRANSLATOR_DECLARATIONS(New_fingering_engraver
);
54 virtual void stop_translation_timestep ();
55 virtual void acknowledge_grob (Grob_info
);
56 void add_fingering (Grob
*, Music
*,Music
*);
57 void add_script (Grob
*, Music
*,Music
*);
58 void position_scripts();
62 New_fingering_engraver::acknowledge_grob (Grob_info inf
)
64 if (Rhythmic_head::has_interface (inf
.grob_
))
66 Music
* note_ev
=inf
.music_cause ();
68 SCM arts
= note_ev
->get_mus_property ("articulations");
70 for (SCM s
= arts
; gh_pair_p (s
); s
= gh_cdr (s
))
72 Music
* m
= unsmob_music (gh_car (s
));
78 if (m
->is_mus_type ("fingering-event"))
80 add_fingering (inf
.grob_
, m
, note_ev
);
82 else if (m
->is_mus_type ("script-event"))
84 add_script (inf
.grob_
, m
, note_ev
);
88 heads_
.push (inf
.grob_
);
90 else if (Stem::has_interface (inf
.grob_
))
96 extern Grob
*make_script_from_event (SCM
* descr
, Translator_group
*tg
, Music
* event
,
99 New_fingering_engraver::add_script (Grob
* head
,
105 ft
.script_
=make_script_from_event (&ft
.description_
, daddy_trans_
, event
, 0);
107 articulations_
.push (ft
);
108 announce_grob (ft
.script_
, event
->self_scm ());
111 ft
.script_
->set_parent (head
, X_AXIS
);
117 New_fingering_engraver::add_fingering (Grob
* head
,
123 ft
.script_
= new Item (get_property ("Fingering"));
124 announce_grob (ft
.script_
, event
->self_scm());
126 Side_position_interface::add_support (ft
.script_
, head
);
128 int d
= gh_scm2int ( event
->get_mus_property ("digit"));
133 Should add support for thumb. It's a little involved, since
134 the thumb lives in a different font. Maybe it should be moved?
140 music for the softenon children?
142 event
->origin()->warning (_("music for the martians."));
144 SCM sstr
= scm_number_to_string (gh_int2scm (d
), gh_int2scm (10)) ;
145 ft
.script_
->set_grob_property ("text", sstr
);
147 ft
.finger_event_
= event
;
148 ft
.note_event_
= hevent
;
151 fingerings_
.push (ft
);
155 New_fingering_engraver::position_scripts ()
159 This is not extremely elegant, but we have to do a little
160 formatting here, because the parent/child relations should be
161 known before we move on to the next time step.
163 A more sophisticated approach would be to set both X and Y parents
164 to the note head, and write a more flexible function for
165 positioning the fingerings, setting both X and Y coordinates.
167 for (int i
= 0; i
< fingerings_
.size(); i
++)
169 fingerings_
[i
].position_
= gh_scm2int (fingerings_
[i
].head_
-> get_grob_property( "staff-position"));
172 for (int i
= fingerings_
.size(); i
--;)
173 for (int j
= heads_
.size() ; j
--;)
174 Side_position_interface::add_support (fingerings_
[i
].script_
, heads_
[j
]);
176 Array
<Finger_tuple
> up
, down
, horiz
;
177 for (int i
= fingerings_
.size(); i
--;)
179 SCM d
= fingerings_
[i
].finger_event_
->get_mus_property ("direction");
182 ((to_dir (d
) == UP
) ? up
: down
).push (fingerings_
[i
]);
187 fingerings_
.sort (&Finger_tuple::compare
);
188 SCM orientations
= get_property ("fingeringOrientations");
190 bool up_p
= scm_memq (ly_symbol2scm ("up"), orientations
) != SCM_BOOL_F
;
191 bool down_p
= scm_memq (ly_symbol2scm ("down"), orientations
) != SCM_BOOL_F
;
192 bool left_p
= scm_memq (ly_symbol2scm ("left"), orientations
) != SCM_BOOL_F
;
193 bool right_p
= scm_memq (ly_symbol2scm ("right"), orientations
) != SCM_BOOL_F
;
194 Direction hordir
= (right_p
) ? RIGHT
: LEFT
;
195 if (left_p
|| right_p
)
197 if (up_p
&& !up
.size () && fingerings_
.size ())
198 up
.push (fingerings_
.pop());
200 if (down_p
&& !down
.size () && fingerings_
.size())
202 down
.push (fingerings_
[0]);
206 horiz
.concat (fingerings_
);
208 else if (up_p
&& down_p
)
210 int center
= fingerings_
.size() / 2;
211 down
.concat (fingerings_
.slice (0,center
));
212 up
.concat (fingerings_
.slice (center
, fingerings_
.size()));
216 up
.concat (fingerings_
);
217 fingerings_
.clear ();
222 warning(_ ("Fingerings are also not down?! Putting them down anyway."));
223 down
.concat (fingerings_
);
227 for (int i
= 0; i
< horiz
.size(); i
++)
229 Finger_tuple ft
= horiz
[i
];
230 Grob
* f
= ft
.script_
;
231 f
->set_parent (ft
.head_
, X_AXIS
);
232 f
->set_parent (ft
.head_
, Y_AXIS
);
233 f
->add_offset_callback (Self_alignment_interface::centered_on_parent_proc
, Y_AXIS
);
234 f
->add_offset_callback (Self_alignment_interface::aligned_on_self_proc
, Y_AXIS
);
235 f
->add_offset_callback (Side_position_interface::aligned_side_proc
, X_AXIS
);
237 f
->set_grob_property ("direction", gh_int2scm (hordir
));
241 int finger_prio
= 200;
242 for (int i
= 0; i
< up
.size(); i
++)
244 Finger_tuple ft
= up
[i
];
245 Grob
* f
= ft
.script_
;
246 f
->set_parent (ft
.head_
, X_AXIS
);
247 f
->set_grob_property ("script-priority",
248 gh_int2scm (finger_prio
+ i
));
249 f
->add_offset_callback (Side_position_interface::aligned_side_proc
, Y_AXIS
);
250 f
->add_offset_callback (Self_alignment_interface::centered_on_parent_proc
, X_AXIS
);
251 f
->add_offset_callback (Self_alignment_interface::aligned_on_self_proc
, X_AXIS
);
253 f
->set_grob_property ("direction", gh_int2scm (UP
));
255 Side_position_interface::add_staff_support (f
);
259 for (int i
= 0; i
< down
.size(); i
++)
261 Finger_tuple ft
= down
[i
];
262 Grob
* f
= ft
.script_
;
263 f
->set_parent (ft
.head_
, X_AXIS
);
264 f
->set_grob_property ("script-priority",
265 gh_int2scm (finger_prio
+ down
.size() - i
));
267 f
->add_offset_callback (Self_alignment_interface::centered_on_parent_proc
, X_AXIS
);
268 f
->add_offset_callback (Self_alignment_interface::aligned_on_self_proc
, X_AXIS
);
269 f
->add_offset_callback (Side_position_interface::aligned_side_proc
, Y_AXIS
);
270 f
->set_grob_property ("direction", gh_int2scm (DOWN
));
271 Side_position_interface::add_staff_support (f
);
277 New_fingering_engraver::stop_translation_timestep ()
279 if (fingerings_
.size ())
282 fingerings_
.clear ();
285 for (int i
= articulations_
.size(); i
--;)
287 Grob
*sc
= articulations_
[i
].script_
;
289 for (int j
= heads_
.size() ; j
--;)
290 Side_position_interface::add_support (sc
, heads_
[j
]);
292 if (stem_
&& to_dir (sc
->get_grob_property ("side-relative-direction")))
293 sc
->set_grob_property ("direction-source", stem_
->self_scm ());
295 SCM follow
= scm_assoc (ly_symbol2scm ("follow-into-staff"), articulations_
[i
].description_
);
296 if (gh_pair_p (follow
) && to_boolean (gh_cdr (follow
)))
297 sc
->add_offset_callback (Side_position_interface::quantised_position_proc
, Y_AXIS
);
299 Side_position_interface::add_staff_support (sc
);
305 articulations_
.clear();
309 New_fingering_engraver::New_fingering_engraver()
314 ENTER_DESCRIPTION(New_fingering_engraver
,
315 /* descr */ "Create fingering-scripts for notes in a new chord.",
316 /* creats*/ "Fingering",
318 /* acks */ "rhythmic-head-interface stem-interface",
319 /* reads */ "fingeringOrientations",