2 script-engraver.cc -- engrave Scripts: Articulations.
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
10 #include "directional-element-interface.hh"
11 #include "engraver.hh"
13 #include "note-column.hh"
14 #include "paper-column.hh"
15 #include "rhythmic-head.hh"
16 #include "script-interface.hh"
17 #include "side-position-interface.hh"
18 #include "staff-symbol-referencer.hh"
26 bool follow_into_staff_
;
29 follow_into_staff_
= false;
35 class Script_engraver
: public Engraver
37 Array
<Script_tuple
> scripts_
;
41 virtual bool try_music (Music
*);
42 void stop_translation_timestep ();
43 void process_music ();
45 DECLARE_ACKNOWLEDGER (slur
);
46 DECLARE_ACKNOWLEDGER (rhythmic_head
);
47 DECLARE_ACKNOWLEDGER (stem
);
48 DECLARE_ACKNOWLEDGER (note_column
);
51 TRANSLATOR_DECLARATIONS (Script_engraver
);
54 Script_engraver::Script_engraver ()
60 Script_engraver::try_music (Music
*m
)
62 if (m
->is_mus_type ("articulation-event"))
64 /* Discard double articulations for part-combining. */
65 int script_count
= scripts_
.size ();
66 for (int i
= 0; i
< script_count
; i
++)
67 if (ly_is_equal (scripts_
[i
].event_
68 ->get_property ("articulation-type"),
69 m
->get_property ("articulation-type")))
81 copy_property (Grob
*g
, SCM sym
, SCM alist
)
83 if (g
->internal_get_property (sym
) == SCM_EOL
)
85 SCM entry
= scm_assoc (sym
, alist
);
86 if (scm_is_pair (entry
))
87 g
->internal_set_property (sym
, scm_cdr (entry
));
91 /* Add the properties, one by one for each Script. A little memory
92 could be saved by tacking the props onto the Script grob (i.e. make
93 ScriptStaccato , ScriptMarcato, etc. ).
95 void make_script_from_event (Grob
*p
, bool *follow
, Context
*tg
,
96 SCM art_type
, int index
)
98 SCM alist
= tg
->get_property ("scriptDefinitions");
99 SCM art
= scm_assoc (art_type
, alist
);
101 if (art
== SCM_BOOL_F
)
104 warning (_ ("don't know how to interpret articulation: "));
105 warning (_ ("scheme encoding: "));
106 scm_write (art_type
, scm_current_error_port ());
113 SCM follow_scm
= scm_assoc (ly_symbol2scm ("follow-into-staff"),
116 *follow
= scm_is_pair (follow_scm
) && to_boolean (scm_cdr (follow_scm
));
117 bool priority_found
= false;
119 for (SCM s
= art
; scm_is_pair (s
); s
= scm_cdr (s
))
121 SCM sym
= scm_caar (s
);
122 SCM type
= scm_object_property (sym
, ly_symbol2scm ("backend-type?"));
123 if (!ly_is_procedure (type
))
126 SCM val
= scm_cdar (s
);
128 if (sym
== ly_symbol2scm ("script-priority"))
130 priority_found
= true;
131 /* Make sure they're in order of user input by adding index i.
132 Don't use the direction in this priority. Smaller means closer
134 int prio
= scm_to_int (val
) + index
;
136 val
= scm_from_int (prio
);
138 if (p
->internal_get_property (sym
) == SCM_EOL
)
139 p
->internal_set_property (sym
, val
);
144 p
->set_property ("script-priority",
145 scm_from_int (index
));
148 Side_position_interface::set_axis (p
, Y_AXIS
);
152 Script_engraver::process_music ()
154 for (int i
= 0; i
< scripts_
.size (); i
++)
156 Music
*m
= scripts_
[i
].event_
;
158 Grob
*p
= make_item ("Script", m
->self_scm ());
160 make_script_from_event (p
, &scripts_
[i
].follow_into_staff_
, context (),
161 m
->get_property ("articulation-type"),
164 scripts_
[i
].script_
= p
;
166 SCM force_dir
= m
->get_property ("direction");
167 if (is_direction (force_dir
) && to_dir (force_dir
))
168 p
->set_property ("direction", force_dir
);
173 Script_engraver::acknowledge_stem (Grob_info info
)
175 int script_count
= scripts_
.size ();
176 for (int i
= 0; i
< script_count
; i
++)
178 Grob
*e
= scripts_
[i
].script_
;
180 if (to_dir (e
->get_property ("side-relative-direction")))
181 e
->set_object ("direction-source", info
.grob ()->self_scm ());
183 /* FIXME: add dependency */
184 e
->add_dependency (info
.grob ());
185 Side_position_interface::add_support (e
, info
.grob ());
190 Script_engraver::acknowledge_rhythmic_head (Grob_info info
)
192 if (info
.music_cause ())
194 for (int i
= 0; i
< scripts_
.size (); i
++)
196 Grob
*e
= scripts_
[i
].script_
;
198 if (Side_position_interface::get_axis (e
) == X_AXIS
199 && !e
->get_parent (Y_AXIS
))
201 e
->set_parent (info
.grob (), Y_AXIS
);
202 e
->add_dependency (info
.grob ());
204 Side_position_interface::add_support (e
, info
.grob ());
210 Script_engraver::acknowledge_note_column (Grob_info info
)
212 /* Make note column the parent of the script. That is not
213 correct, but due to seconds in a chord, noteheads may be
214 swapped around horizontally.
216 As the note head to put it on is not known now, postpone this
217 decision to Script_interface::before_line_breaking (). */
219 for (int i
= 0; i
< scripts_
.size (); i
++)
221 Grob
*e
= scripts_
[i
].script_
;
223 if (!e
->get_parent (X_AXIS
)
224 && Side_position_interface::get_axis (e
) == Y_AXIS
)
225 e
->set_parent (info
.grob (), X_AXIS
);
230 Script_engraver::acknowledge_slur (Grob_info info
)
232 slur_
= info
.spanner ();
236 Script_engraver::stop_translation_timestep ()
238 int script_count
= scripts_
.size ();
239 for (int i
= 0; i
< script_count
; i
++)
240 if (scripts_
[i
].follow_into_staff_
)
242 Grob
*sc
= scripts_
[i
].script_
;
243 sc
->add_offset_callback (Side_position_interface
244 ::quantised_position_proc
, Y_AXIS
);
245 sc
->set_property ("staff-padding", SCM_EOL
);
251 #include "translator.icc"
253 ADD_ACKNOWLEDGER (Script_engraver
, slur
);
254 ADD_ACKNOWLEDGER (Script_engraver
, rhythmic_head
);
255 ADD_ACKNOWLEDGER (Script_engraver
, stem
);
256 ADD_ACKNOWLEDGER (Script_engraver
, note_column
);
258 ADD_TRANSLATOR (Script_engraver
,
259 /* doc */ "Handles note scripted articulations.",
260 /* create */ "Script",
261 /* accept */ "script-event articulation-event",
262 /* read */ "scriptDefinitions",