From: fred Date: Wed, 27 Mar 2002 02:03:21 +0000 (+0000) Subject: lilypond-1.5.15 X-Git-Tag: release/1.5.59~445 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=2c950f106b56fdfa677ffc304a03c1e7c4cc81db;p=lilypond.git lilypond-1.5.15 --- diff --git a/input/regression/accidental-double.ly b/input/regression/accidental-double.ly new file mode 100644 index 0000000000..eb37a7c289 --- /dev/null +++ b/input/regression/accidental-double.ly @@ -0,0 +1,15 @@ +\header { + texidoc = "If two forced accidentals happen at the same time, only one + sharp sign is printed." +} + + +\score { \notes \transpose c'' + \context Staff < + \key g \major + \context Voice=va { \stemUp c' fis! } + \context Voice=vb { \stemDown c fis! } + > +} + + diff --git a/input/regression/accidental.ly b/input/regression/accidental.ly index 614995069d..af01b459cf 100644 --- a/input/regression/accidental.ly +++ b/input/regression/accidental.ly @@ -7,10 +7,9 @@ fourth show forced and courtesy accidentals. " } -foo = \notes\relative c'' { \key as \major dis4 dis dis! dis? } +foo = \notes\relative c'' { \key as \major dis4 dis dis!^"force" dis? } \score { - < \foo \context NoteNames \foo > diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc new file mode 100644 index 0000000000..46914f6d20 --- /dev/null +++ b/lily/accidental-engraver.cc @@ -0,0 +1,297 @@ +/* + local-key-engraver.cc -- implement accidental_engraver + + (c) 1997--2001 Han-Wen Nienhuys +*/ + +#include "musical-request.hh" +#include "command-request.hh" +#include "local-key-item.hh" +#include "item.hh" +#include "tie.hh" +#include "rhythmic-head.hh" +#include "timing-translator.hh" +#include "engraver-group-engraver.hh" + +#include "staff-symbol-referencer.hh" +#include "side-position-interface.hh" +#include "engraver.hh" +#include "arpeggio.hh" + +/** + + + FIXME: should not compute vertical positioning of accidentals, but + get them from the noteheads + + The algorithm for accidentals should be documented, and made + tweakable. + +*/ + + +struct Accidental_engraver : Engraver { + Item *key_item_p_; +protected: + TRANSLATOR_DECLARATIONS(Accidental_engraver); + virtual void process_music (); + virtual void acknowledge_grob (Grob_info); + virtual void stop_translation_timestep (); + virtual void initialize (); + virtual void create_grobs (); + virtual void finalize (); +public: + + // todo -> property + SCM last_keysig_; + + /* + Urgh. Since the accidentals depend on lots of variables, we have to + store all information before we can really create the accidentals. + */ + Link_array arpeggios_; + + Link_array mel_l_arr_; + Link_array support_l_arr_; + Link_array forced_l_arr_; + Link_array tie_l_arr_; + +}; + +Accidental_engraver::Accidental_engraver () +{ + key_item_p_ =0; + last_keysig_ = SCM_EOL; +} + +void +Accidental_engraver::initialize () +{ + last_keysig_ = get_property ("keySignature"); + daddy_trans_l_->set_property ("localKeySignature", last_keysig_); +} + +void +Accidental_engraver::create_grobs () +{ + if (!key_item_p_ && mel_l_arr_.size ()) + { + SCM localsig = get_property ("localKeySignature"); + + for (int i=0; i < mel_l_arr_.size (); i++) + { + Grob * support_l = support_l_arr_[i]; + Note_req * note_l = mel_l_arr_[i]; + + int n = unsmob_pitch (note_l->get_mus_property ("pitch"))->notename_i_; + int o = unsmob_pitch (note_l->get_mus_property ("pitch"))->octave_i () ; + int a = unsmob_pitch (note_l->get_mus_property ("pitch"))->alteration_i_; + + /* see if there's a tie that "changes" the accidental */ + /* works because if there's a tie, the note to the left + is of the same pitch as the actual note */ + + SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig); + if (prev == SCM_BOOL_F) + prev = scm_assoc (gh_int2scm (n), localsig); + SCM prev_acc = (prev == SCM_BOOL_F) ? gh_int2scm (0) : ly_cdr (prev); + bool different = !gh_equal_p (prev_acc , gh_int2scm (a)); + int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0; + + Grob *tie_break_reminder = 0; + bool tie_changes = false; + for (int i=0; i < tie_l_arr_.size (); i++) + if (support_l == Tie::head (tie_l_arr_[i], RIGHT)) + { + tie_changes = different; + /* Enable accidentals for broken tie + + We only want an accidental on a broken tie, + if the tie changes the accidental. + + Maybe check property noTieBreakForceAccidental? */ + if (different) + tie_break_reminder = tie_l_arr_[i]; + break; + } + + /* When do we want accidentals: + + 1. when property force-accidental is set, and not + tie_changes + 2. when different and not tie-changes + 3. maybe when at end of a tie: we must later see if + we're after a line break */ + if (( (to_boolean (note_l->get_mus_property ("force-accidental")) + || different) + && !tie_changes) + || tie_break_reminder) + { + if (!key_item_p_) + { + key_item_p_ = new Item (get_property ("Accidentals")); + Local_key_item::set_interface (key_item_p_); + + + Staff_symbol_referencer::set_interface (key_item_p_); + SCM c0 = get_property ("centralCPosition"); + if (gh_number_p (c0)) + Staff_symbol_referencer::set_position (key_item_p_, gh_scm2int (c0)); + + announce_grob (key_item_p_, 0); + } + + + bool extra_natural = + sign (p) * (p - a) == 1 + && abs (p) == 2; + + Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")), + to_boolean (note_l->get_mus_property ("cautionary")), + extra_natural, + tie_break_reminder); + Side_position_interface::add_support (key_item_p_,support_l); + } + + /* + We should not record the accidental if it is the first + note and it is tied from the previous measure. + + Checking whether it is tied also works mostly, but will it + always do the correct thing? + + */ + bool forget = to_boolean (get_property ("forgetAccidentals")); + if (tie_changes) + { + /* + Remember an alteration that is different both from + that of the tied note and of the key signature. + + */ + localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o), + gh_int2scm (n)), + SCM_BOOL_T); + + } + else if (!forget) + { + /* + not really really correct if there are more than one + noteheads with the same notename. + */ + localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o), + gh_int2scm (n)), + gh_int2scm (a)); + + } + } + + + + + daddy_trans_l_->set_property ("localKeySignature", localsig); + } + + + if (key_item_p_) + { + /* + Hmm. Which one has to be on the left? + + On which left, code or paper? + + (Arpeggios are engraved left of accidentals, of course.) + */ + for (int i=0; i < arpeggios_.size (); i++) + Side_position_interface::add_support (arpeggios_[i], key_item_p_); + + arpeggios_.clear (); + } +} + +void +Accidental_engraver::finalize () +{ + +} + +void +Accidental_engraver::stop_translation_timestep () +{ + if (key_item_p_) + { + for (int i=0; i < support_l_arr_.size (); i++) + Side_position_interface::add_support (key_item_p_,support_l_arr_[i]); + + typeset_grob (key_item_p_); + key_item_p_ =0; + } + + + mel_l_arr_.clear (); + arpeggios_.clear (); + tie_l_arr_.clear (); + support_l_arr_.clear (); + forced_l_arr_.clear (); +} + +void +Accidental_engraver::acknowledge_grob (Grob_info info) +{ + Note_req * note_l = dynamic_cast (info.req_l_); + + if (note_l && Rhythmic_head::has_interface (info.grob_l_)) + { + mel_l_arr_.push (note_l); + support_l_arr_.push (info.grob_l_); + } + else if (Tie::has_interface (info.grob_l_)) + { + tie_l_arr_.push (info.grob_l_); + } + else if (Arpeggio::has_interface (info.grob_l_)) + { + arpeggios_.push (info.grob_l_); + } + +} + +/* + ugh. repeated deep_copy generates lots of garbage. + */ +void +Accidental_engraver::process_music () +{ + SCM smp = get_property ("measurePosition"); + Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0); + + SCM sig = get_property ("keySignature"); + + /* + Detect key sig changes. If we haven't found any, check if at start + of measure, and set localKeySignature anyhow. */ + if (last_keysig_ != sig) + { + daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig)); + last_keysig_ = sig; + } + else if (!mp.to_bool () ) + { + if (!to_boolean (get_property ("noResetKey"))) + daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig)); + } +} + + + + + +ENTER_DESCRIPTION(Accidental_engraver, +/* descr */ "Make accidentals. Catches note heads, ties and notices key-change +events. Due to interaction with ties (which don't come together +with note heads), this needs to be in a context higher than Tie_engraver. FIXME", +/* creats*/ "Accidentals", +/* acks */ "rhythmic-head-interface tie-interface arpeggio-interface", +/* reads */ "localKeySignature forgetAccidentals noResetKey", +/* write */ ""); diff --git a/lily/local-key-item.cc b/lily/local-key-item.cc index ff01726169..1ffc2c696c 100644 --- a/lily/local-key-item.cc +++ b/lily/local-key-item.cc @@ -28,7 +28,7 @@ static SCM pitch_less_proc; void init_pitch_funcs () { - pitch_less_proc = gh_new_procedure2_0 ("pits-less", &pitch_less); + pitch_less_proc = gh_new_procedure2_0 ("pitch-less", &pitch_less); } ADD_SCM_INIT_FUNC (lkpitch,init_pitch_funcs); @@ -40,7 +40,10 @@ Local_key_item::add_pitch (Grob*me, Pitch p, bool cautionary, bool natural, { SCM acs = me->get_grob_property ("accidentals"); SCM pitch = p.smobbed_copy (); - SCM opts = SCM_EOL; + SCM opts = scm_assoc (pitch, acs); + bool new_pitch = !gh_pair_p (opts); + opts= new_pitch ? SCM_EOL : gh_cdr (opts); + if (cautionary) opts = gh_cons (ly_symbol2scm ("cautionary"), opts); if (natural) @@ -52,8 +55,13 @@ Local_key_item::add_pitch (Grob*me, Pitch p, bool cautionary, bool natural, opts = gh_cons (ly_symbol2scm ("tie-break-reminder"), opts); } - pitch = gh_cons (pitch, opts); - acs = scm_merge_x (acs, gh_cons (pitch, SCM_EOL), pitch_less_proc); + if (new_pitch) + { + pitch = gh_cons (pitch, opts); + acs = scm_merge_x (acs, gh_cons (pitch, SCM_EOL), pitch_less_proc); + } + else + scm_assoc_set_x (acs, pitch, opts); me->set_grob_property ("accidentals", acs); } diff --git a/lily/span-bar.cc b/lily/span-bar.cc index 01020ca626..1700d181fc 100644 --- a/lily/span-bar.cc +++ b/lily/span-bar.cc @@ -177,17 +177,24 @@ void Span_bar::evaluate_glyph (Grob*me) { SCM elts = me->get_grob_property ("elements"); - Grob * b = unsmob_grob (ly_car (elts)); - SCM glsym =ly_symbol2scm ("glyph"); - SCM gl =b ->get_grob_property (glsym); + SCM glyph_symbol = ly_symbol2scm ("glyph"); + SCM gl = SCM_EOL; + + while (gh_pair_p (elts)) + { + gl = unsmob_grob (gh_car (elts))->get_grob_property (glyph_symbol); + if (gh_string_p (gl)) + break; + elts =gh_cdr (elts); + } + if (!gh_string_p (gl)) { me->suicide (); - return ; + return; } - - String type = ly_scm2string (gl); + String type = ly_scm2string (gl); if (type == "|:") { type = ".|"; @@ -202,8 +209,8 @@ Span_bar::evaluate_glyph (Grob*me) } gl = ly_str02scm (type.ch_C ()); - if (scm_equal_p (me->get_grob_property (glsym), gl) != SCM_BOOL_T) - me->set_grob_property (glsym, gl); + if (scm_equal_p (me->get_grob_property (glyph_symbol), gl) != SCM_BOOL_T) + me->set_grob_property (glyph_symbol, gl); } Interval diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 6261811a13..450d5b7784 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -27,7 +27,7 @@ StaffContext=\translator { \consists "Staff_symbol_engraver" \consists "Collision_engraver" \consists "Rest_collision_engraver" - \consists "Local_key_engraver" + \consists "Accidental_engraver" \consists "Piano_pedal_engraver" \consists "Instrument_name_engraver" @@ -379,6 +379,8 @@ ScoreContext = \translator { tupletNumberFormatFunction = #denominator-tuplet-formatter + subdivideBeams = ##f + keyAccidentalOrder = #'( (6 . -1) (2 . -1) (5 . -1 ) (1 . -1) (4 . -1) (0 . -1) (3 . -1) (3 . 1) (0 . 1) (4 . 1) (1 . 1) (5 . 1) (2 . 1) (6 . 1) diff --git a/scm/grob-property-description.scm b/scm/grob-property-description.scm index 9b8ec528b7..3f808ba8bf 100644 --- a/scm/grob-property-description.scm +++ b/scm/grob-property-description.scm @@ -29,6 +29,9 @@ (grob-property-description 'X-offset-callbacks list? "list of functions, each taking an grob and axis argument. The function determine the position relative to this grob's parent. The last one in the list is called first.") (grob-property-description 'Y-extent-callback procedure? "see @code{X-extent-callback}.") (grob-property-description 'Y-offset-callbacks list? "see @code{X-offset-callbacks}.") +(grob-property-description 'accidentals list? "Alist with (PITCH +. OPTION-LIST) entries. OPTION-LIST can contain 'cautionary, 'natural +and 'tie-break-reminder ") (grob-property-description 'add-stem boolean? "Add stem to porrectus?.") (grob-property-description 'after-line-breaking-callback procedure? "Procedure taking a grob as argument. This procedure is called (using dependency resolution) after line breaking. Return value is ignored.") diff --git a/scm/interface-description.scm b/scm/interface-description.scm index 8bd3ca2ed7..9d2249cac2 100644 --- a/scm/interface-description.scm +++ b/scm/interface-description.scm @@ -185,7 +185,7 @@ (lily-interface 'accidentals-interface "Accidentals" - '( + '(accidentals left-padding right-padding ))