LEFT | RIGHT |
1 /* | 1 /* |
2 accidental-engraver.cc -- implement Accidental_engraver | 2 accidental-engraver.cc -- implement Accidental_engraver |
3 | 3 |
4 source file of the GNU LilyPond music typesetter | 4 source file of the GNU LilyPond music typesetter |
5 | 5 |
6 (c) 1997--2008 Han-Wen Nienhuys <hanwen@xs4all.nl> | 6 (c) 1997--2009 Han-Wen Nienhuys <hanwen@xs4all.nl> |
7 Modified 2001--2002 by Rune Zedeler <rz@daimi.au.dk> | 7 Modified 2001--2002 by Rune Zedeler <rz@daimi.au.dk> |
8 */ | 8 */ |
9 | 9 |
10 #include "accidental-placement.hh" | 10 #include "accidental-placement.hh" |
11 #include "arpeggio.hh" | 11 #include "arpeggio.hh" |
12 #include "context.hh" | 12 #include "context.hh" |
13 #include "duration.hh" | 13 #include "duration.hh" |
14 #include "engraver.hh" | 14 #include "engraver.hh" |
15 #include "international.hh" | 15 #include "international.hh" |
16 #include "item.hh" | 16 #include "item.hh" |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 void | 107 void |
108 Accidental_engraver::update_local_key_signature (SCM new_sig) | 108 Accidental_engraver::update_local_key_signature (SCM new_sig) |
109 { | 109 { |
110 last_keysig_ = new_sig; | 110 last_keysig_ = new_sig; |
111 set_context_property_on_children (context (), | 111 set_context_property_on_children (context (), |
112 ly_symbol2scm ("localKeySignature"), | 112 ly_symbol2scm ("localKeySignature"), |
113 new_sig); | 113 new_sig); |
114 | 114 |
115 Context *trans = context ()->get_parent_context (); | 115 Context *trans = context ()->get_parent_context (); |
116 | 116 |
117 /* Reset parent contexts so that e.g. piano-accidentals won't remember old | 117 /* |
118 cross-staff accidentals after key-sig-changes */ | 118 Reset parent contexts so that e.g. piano-accidentals won't remember old |
| 119 cross-staff accidentals after key-sig-changes. |
| 120 */ |
119 | 121 |
120 SCM val; | 122 SCM val; |
121 while (trans && trans->where_defined (ly_symbol2scm ("localKeySignature"), &va
l)==trans) | 123 while (trans && trans->where_defined (ly_symbol2scm ("localKeySignature"), &va
l) == trans) |
122 { | 124 { |
123 trans->set_property ("localKeySignature", ly_deep_copy (last_keysig_)); | 125 trans->set_property ("localKeySignature", ly_deep_copy (last_keysig_)); |
124 trans = trans->get_parent_context (); | 126 trans = trans->get_parent_context (); |
125 } | 127 } |
126 } | |
127 | |
128 | |
129 /** Calculate the number of accidentals on basis of the current local key | |
130 sig (passed as argument) | |
131 | |
132 * First check step+octave (taking into account barnumbers if necessary). | |
133 | |
134 * Then check the global signature (only step). | |
135 | |
136 Return number of accidentals (0, 1 or 2). */ | |
137 | |
138 static bool | |
139 recent_enough (int bar_number, SCM alteration_def, SCM laziness) | |
140 { | |
141 if (scm_is_number (alteration_def) | |
142 || laziness == SCM_BOOL_T) | |
143 return true; | |
144 | |
145 return (bar_number <= scm_to_int (scm_cadr (alteration_def)) + scm_to_int (laz
iness)); | |
146 } | |
147 | |
148 static Rational | |
149 extract_alteration (SCM alteration_def) | |
150 { | |
151 if (scm_is_number (alteration_def)) | |
152 return ly_scm2rational (alteration_def); | |
153 else if (scm_is_pair (alteration_def)) | |
154 return ly_scm2rational (scm_car (alteration_def)); | |
155 else if (alteration_def == SCM_BOOL_F) | |
156 return Rational (0); | |
157 else | |
158 assert (0); | |
159 return Rational (0); | |
160 } | |
161 | |
162 bool | |
163 is_tied (SCM alteration_def) | |
164 { | |
165 SCM tied = ly_symbol2scm ("tied"); | |
166 return (alteration_def == tied | |
167 || (scm_is_pair (alteration_def) && scm_car (alteration_def) == tied))
; | |
168 } | 128 } |
169 | 129 |
170 struct Accidental_result | 130 struct Accidental_result |
171 { | 131 { |
172 bool need_acc; | 132 bool need_acc; |
173 bool need_restore; | 133 bool need_restore; |
174 | 134 |
175 Accidental_result () | 135 Accidental_result () |
176 { | 136 { |
177 need_restore = need_acc = false; | 137 need_restore = need_acc = false; |
(...skipping 11 matching lines...) Expand all Loading... |
189 need_acc = to_boolean (scm_cdr (scm)); | 149 need_acc = to_boolean (scm_cdr (scm)); |
190 } | 150 } |
191 | 151 |
192 int score () const | 152 int score () const |
193 { | 153 { |
194 return need_acc ? 1 : 0 | 154 return need_acc ? 1 : 0 |
195 + need_restore ? 1 : 0; | 155 + need_restore ? 1 : 0; |
196 } | 156 } |
197 }; | 157 }; |
198 | 158 |
199 LY_DEFINE (ly_check_pitch_against_signature, "ly:check-pitch-against-signature",
5, 0, 0, | |
200 (SCM context, SCM pitch_scm, SCM barnum, SCM laziness, SCM octaveness
), | |
201 "Checks the need for an accidental and a @q{restore} accidental again
st" | |
202 " @code{localKeySignature}. The @var{laziness} is the number of meas
ures" | |
203 " for which reminder accidentals are used (i.e., if @var{laziness} is
zero," | |
204 " only cancel accidentals in the same measure; if @var{laziness} is t
hree," | |
205 " we cancel accidentals up to three measures after they first appear.
" | |
206 " @var{octaveness} is either @code{'same-octave} or @code{'any-octave
} and" | |
207 " it specifies whether accidentals should be canceled in different oc
taves.") | |
208 { | |
209 Context *ctx = unsmob_context (context); | |
210 LY_ASSERT_SMOB (Context, context, 1); | |
211 LY_ASSERT_TYPE (unsmob_pitch, pitch_scm, 2); | |
212 LY_ASSERT_TYPE (scm_is_integer, barnum, 3); | |
213 LY_ASSERT_TYPE (ly_is_symbol, octaveness, 5); | |
214 | |
215 bool symbol_ok = (octaveness == ly_symbol2scm ("any-octave") | |
216 || octaveness == ly_symbol2scm ("same-octave")); | |
217 | |
218 SCM_ASSERT_TYPE (symbol_ok, octaveness, SCM_ARG5, __FUNCTION__, "'any-octave o
r 'same-octave"); | |
219 | |
220 Pitch *pitch = unsmob_pitch (pitch_scm); | |
221 int bar_number = scm_to_int (barnum); | |
222 bool ignore_octave = ly_symbol2scm ("any-octave") == octaveness; | |
223 | |
224 Accidental_result result; | |
225 SCM keysig = ctx->get_property ("keySignature"); | |
226 SCM localkeysig = ctx->get_property ("localKeySignature"); | |
227 int n = pitch->get_notename (); | |
228 int o = pitch->get_octave (); | |
229 | |
230 SCM previous_alteration = SCM_BOOL_F; | |
231 | |
232 SCM from_same_octave = ly_assoc_get (scm_cons (scm_from_int (o), | |
233 scm_from_int (n)), localkeysig,
SCM_BOOL_F); | |
234 SCM from_key_signature = ly_assoc_get (scm_from_int (n), localkeysig, SCM_BOOL
_F); | |
235 /* | |
236 If no key signature match is found, we may have a custom type with octave-sp
ecific | |
237 entries of the form ((octave . pitch) alteration) instead of (pitch . alter
ation). | |
238 Since this type cannot coexist with entries in localKeySignature, try extrac
ting | |
239 key signature from keySignature instead. | |
240 */ | |
241 if (from_key_signature == SCM_BOOL_F) | |
242 from_key_signature = ly_assoc_get (scm_cons (scm_from_int (o), | |
243 scm_from_int (n)), keysig, SCM_
BOOL_F); | |
244 SCM from_other_octaves = SCM_BOOL_F; | |
245 for (SCM s = localkeysig; scm_is_pair (s); s = scm_cdr (s)) | |
246 { | |
247 SCM entry = scm_car (s); | |
248 if (scm_is_pair (scm_car (entry)) | |
249 && scm_cdar (entry) == scm_from_int (n)) | |
250 { | |
251 from_other_octaves = scm_cdr (entry); | |
252 break; | |
253 } | |
254 } | |
255 | |
256 if (!ignore_octave | |
257 && from_same_octave != SCM_BOOL_F | |
258 && recent_enough (bar_number, from_same_octave, laziness)) | |
259 previous_alteration = from_same_octave; | |
260 else if (ignore_octave | |
261 && from_other_octaves != SCM_BOOL_F | |
262 && recent_enough (bar_number, from_other_octaves, laziness)) | |
263 previous_alteration = from_other_octaves; | |
264 else if (from_key_signature != SCM_BOOL_F) | |
265 previous_alteration = from_key_signature; | |
266 | |
267 if (is_tied (previous_alteration)) | |
268 { | |
269 result.need_acc = true; | |
270 } | |
271 else | |
272 { | |
273 Rational prev = extract_alteration (previous_alteration); | |
274 Rational alter = pitch->get_alteration (); | |
275 | |
276 if (alter != prev) | |
277 { | |
278 result.need_acc = true; | |
279 if (alter.sign () | |
280 && (alter.abs () < prev.abs () | |
281 || (prev * alter).sign () < 0)) | |
282 result.need_restore = true; | |
283 } | |
284 } | |
285 | |
286 return scm_cons (scm_from_bool (result.need_restore), scm_from_bool (result.ne
ed_acc)); | |
287 } | |
288 | |
289 static | 159 static |
290 Accidental_result | 160 Accidental_result |
291 check_pitch_against_rules (Pitch const &pitch, Context *origin, | 161 check_pitch_against_rules (Pitch const &pitch, Context *origin, |
292 SCM rules, int bar_number, SCM measurepos) | 162 SCM rules, int bar_number, SCM measurepos) |
293 { | 163 { |
294 Accidental_result result; | 164 Accidental_result result; |
295 SCM pitch_scm = pitch.smobbed_copy (); | 165 SCM pitch_scm = pitch.smobbed_copy (); |
296 SCM barnum_scm = scm_from_int (bar_number); | 166 SCM barnum_scm = scm_from_int (bar_number); |
297 | 167 |
298 if (scm_is_pair (rules) && !scm_is_symbol (scm_car (rules))) | 168 if (scm_is_pair (rules) && !scm_is_symbol (scm_car (rules))) |
299 warning (_f ("accidental typesetting list must begin with context-name: %s", | 169 warning (_f ("accidental typesetting list must begin with context-name: %s", |
300 ly_scm2string (scm_car (rules)).c_str ())); | 170 ly_scm2string (scm_car (rules)).c_str ())); |
301 | 171 |
302 for (; scm_is_pair (rules) && origin; | 172 for (; scm_is_pair (rules) && origin; rules = scm_cdr (rules)) |
303 rules = scm_cdr (rules)) | |
304 { | 173 { |
305 SCM rule = scm_car (rules); | 174 SCM rule = scm_car (rules); |
306 if (ly_is_procedure (rule)) | 175 if (ly_is_procedure (rule)) |
307 { | 176 { |
308 SCM rule_result_scm = scm_call_4 (rule, origin->self_scm (), | 177 SCM rule_result_scm = scm_call_4 (rule, origin->self_scm (), |
309 pitch_scm, barnum_scm, measurepos); | 178 pitch_scm, barnum_scm, measurepos); |
310 | |
311 Accidental_result rule_result (rule_result_scm); | 179 Accidental_result rule_result (rule_result_scm); |
312 | 180 |
313 result.need_acc |= rule_result.need_acc; | 181 result.need_acc |= rule_result.need_acc; |
314 result.need_restore |= rule_result.need_restore; | 182 result.need_restore |= rule_result.need_restore; |
315 } | 183 } |
316 | 184 |
317 /* if symbol then it is a context name. Scan parent contexts to | 185 /* |
318 » find it. */ | 186 » If symbol then it is a context name. Scan parent contexts to |
| 187 » find it. |
| 188 */ |
319 else if (scm_is_symbol (rule)) | 189 else if (scm_is_symbol (rule)) |
320 { | 190 { |
321 Context *dad = origin; | 191 Context *dad = origin; |
322 while (dad && !dad->is_alias (rule)) | 192 while (dad && !dad->is_alias (rule)) |
323 dad = dad->get_parent_context (); | 193 dad = dad->get_parent_context (); |
324 | 194 |
325 if (dad) | 195 if (dad) |
326 origin = dad; | 196 origin = dad; |
327 } | 197 } |
328 else | 198 else |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 acc.need_acc |= caut.need_acc;· | 237 acc.need_acc |= caut.need_acc;· |
368 acc.need_restore |= caut.need_restore;· | 238 acc.need_restore |= caut.need_restore;· |
369 | 239 |
370 cautionary = true; | 240 cautionary = true; |
371 } | 241 } |
372 | 242 |
373 bool forced = to_boolean (note->get_property ("force-accidental")); | 243 bool forced = to_boolean (note->get_property ("force-accidental")); |
374 if (!acc.need_acc && forced) | 244 if (!acc.need_acc && forced) |
375 acc.need_acc = true; | 245 acc.need_acc = true; |
376 | 246 |
377 » /* Cannot look for ties: it's not guaranteed that they reach | 247 » /* |
378 » us before the notes. */ | 248 » Cannot look for ties: it's not guaranteed that they reach |
| 249 » us before the notes. |
| 250 » */ |
379 if (!note->in_event_class ("trill-span-event")) | 251 if (!note->in_event_class ("trill-span-event")) |
380 { | 252 { |
381 if (acc.need_acc)······· | 253 if (acc.need_acc)······· |
382 create_accidental (&accidentals_[i], acc.need_restore, cautionar
y); | 254 create_accidental (&accidentals_[i], acc.need_restore, cautionar
y); |
383 | 255 |
384 if (forced || cautionary) | 256 if (forced || cautionary) |
385 accidentals_[i].accidental_->set_property ("forced", SCM_BOOL_T)
; | 257 accidentals_[i].accidental_->set_property ("forced", SCM_BOOL_T)
; |
386 } | 258 } |
387 } | 259 } |
388 } | 260 } |
(...skipping 16 matching lines...) Expand all Loading... |
405 if (restore_natural) | 277 if (restore_natural) |
406 { | 278 { |
407 if (to_boolean (get_property ("extraNatural"))) | 279 if (to_boolean (get_property ("extraNatural"))) |
408 a->set_property ("restore-first", SCM_BOOL_T); | 280 a->set_property ("restore-first", SCM_BOOL_T); |
409 } | 281 } |
410 | 282 |
411 entry->accidental_ = a; | 283 entry->accidental_ = a; |
412 } | 284 } |
413 | 285 |
414 Grob * | 286 Grob * |
415 Accidental_engraver::make_standard_accidental (Stream_event *note, | 287 Accidental_engraver::make_standard_accidental (Stream_event * /* note */, |
416 Grob *note_head, | 288 Grob *note_head, |
417 Engraver *trans, | 289 Engraver *trans, |
418 bool cautionary) | 290 bool cautionary) |
419 { | 291 { |
420 (void)note; | |
421 | |
422 /* | 292 /* |
423 We construct the accidentals at the originating Voice | 293 We construct the accidentals at the originating Voice |
424 level, so that we get the property settings for | 294 level, so that we get the property settings for |
425 Accidental from the respective Voice. | 295 Accidental from the respective Voice. |
426 */ | 296 */ |
427 Grob *a = 0; | 297 Grob *a = 0; |
428 if (cautionary) | 298 if (cautionary) |
429 a = trans->make_item ("AccidentalCautionary", note_head->self_scm ()); | 299 a = trans->make_item ("AccidentalCautionary", note_head->self_scm ()); |
430 else | 300 else |
431 a = trans->make_item ("Accidental", note_head->self_scm ()); | 301 a = trans->make_item ("Accidental", note_head->self_scm ()); |
(...skipping 17 matching lines...) Expand all Loading... |
449 accidental_placement_ = make_item ("AccidentalPlacement", | 319 accidental_placement_ = make_item ("AccidentalPlacement", |
450 a->self_scm ()); | 320 a->self_scm ()); |
451 Accidental_placement::add_accidental (accidental_placement_, a); | 321 Accidental_placement::add_accidental (accidental_placement_, a); |
452 | 322 |
453 note_head->set_object ("accidental-grob", a->self_scm ()); | 323 note_head->set_object ("accidental-grob", a->self_scm ()); |
454 ·· | 324 ·· |
455 return a; | 325 return a; |
456 } | 326 } |
457 | 327 |
458 Grob * | 328 Grob * |
459 Accidental_engraver::make_suggested_accidental (Stream_event *note, | 329 Accidental_engraver::make_suggested_accidental (Stream_event * /* note */, |
460 Grob *note_head, | 330 Grob *note_head, |
461 Engraver *trans) | 331 Engraver *trans) |
462 { | 332 { |
463 (void) note; | |
464 | |
465 Grob *a = trans->make_item ("AccidentalSuggestion", note_head->self_scm ()); | 333 Grob *a = trans->make_item ("AccidentalSuggestion", note_head->self_scm ()); |
466 | 334 |
467 Side_position_interface::add_support (a, note_head); | 335 Side_position_interface::add_support (a, note_head); |
468 if (Grob *stem = unsmob_grob (a->get_object ("stem"))) | 336 if (Grob *stem = unsmob_grob (a->get_object ("stem"))) |
469 Side_position_interface::add_support (a, stem); | 337 Side_position_interface::add_support (a, stem); |
470 | 338 |
471 a->set_parent (note_head, X_AXIS); | 339 a->set_parent (note_head, X_AXIS); |
472 return a; | 340 return a; |
473 } | 341 } |
474 | 342 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 bool change = false; | 392 bool change = false; |
525 if (accidentals_[i].tied_ | 393 if (accidentals_[i].tied_ |
526 && !(to_boolean (accidentals_[i].accidental_->get_property ("force
d")))) | 394 && !(to_boolean (accidentals_[i].accidental_->get_property ("force
d")))) |
527 { | 395 { |
528 /* | 396 /* |
529 Remember an alteration that is different both from | 397 Remember an alteration that is different both from |
530 that of the tied note and of the key signature. | 398 that of the tied note and of the key signature. |
531 */ | 399 */ |
532 localsig = ly_assoc_prepend_x (localsig, key,scm_cons (ly_symbol2s
cm ("tied"), | 400 localsig = ly_assoc_prepend_x (localsig, key,scm_cons (ly_symbol2s
cm ("tied"), |
533 position)); | 401 position)); |
534 | |
535 change = true; | 402 change = true; |
536 } | 403 } |
537 else | 404 else |
538 { | 405 { |
539 /* | 406 /* |
540 » » not really really correct if there are more than one | 407 » » not really really correct if there is more than one |
541 » » noteheads with the same notename. | 408 » » note head with the same notename. |
542 */ | 409 */ |
543 localsig = ly_assoc_prepend_x (localsig, key, | 410 localsig = ly_assoc_prepend_x (localsig, key, |
544 scm_cons (ly_rational2scm (a), | 411 scm_cons (ly_rational2scm (a), |
545 position)); | 412 position)); |
546 change = true; | 413 change = true; |
547 } | 414 } |
548 | 415 |
549 if (change) | 416 if (change) |
550 origin->set_property ("localKeySignature", localsig); | 417 origin->set_property ("localKeySignature", localsig); |
551 | 418 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 "autoCautionaries " | 512 "autoCautionaries " |
646 "internalBarNumber " | 513 "internalBarNumber " |
647 "extraNatural " | 514 "extraNatural " |
648 "harmonicAccidentals " | 515 "harmonicAccidentals " |
649 "keySignature " | 516 "keySignature " |
650 "localKeySignature ", | 517 "localKeySignature ", |
651 | 518 |
652 /* write */ | 519 /* write */ |
653 "localKeySignature " | 520 "localKeySignature " |
654 ); | 521 ); |
LEFT | RIGHT |