]> git.donarmstrong.com Git - lilypond.git/blob - lily/local-key-engraver.cc
patch::: 1.3.103.jcn1
[lilypond.git] / lily / local-key-engraver.cc
1 /*
2   local-key-engraver.cc -- implement Local_key_engraver
3
4   (c)  1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5 */
6
7 #include "musical-request.hh"
8 #include "command-request.hh"
9 #include "local-key-item.hh"
10 #include "item.hh"
11 #include "tie.hh"
12 #include "rhythmic-head.hh"
13 #include "timing-translator.hh"
14 #include "engraver-group-engraver.hh"
15 #include "grace-align-item.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "side-position-interface.hh"
18 #include "engraver.hh"
19 #include "arpeggio.hh"
20
21 /**
22
23
24    FIXME: should not compute vertical positioning of accidentals, but
25    get them from the noteheads
26
27 */
28
29
30 struct Local_key_engraver : Engraver {
31   Item *key_item_p_;
32 protected:
33   VIRTUAL_COPY_CONS(Translator);
34   virtual void do_process_music();
35   virtual void acknowledge_element (Score_element_info);
36   virtual void do_pre_move_processing();
37   virtual void do_creation_processing ();
38   virtual void process_acknowledged ();
39   virtual void do_removal_processing ();
40 public:
41
42   // todo -> property
43   SCM last_keysig_;
44
45   /*
46     Urgh. Since the accidentals depend on lots of variables, we have to
47     store all information before we can really create the accidentals.
48    */
49   Link_array<Score_element> arpeggios_;
50   
51   Link_array<Note_req> mel_l_arr_;
52   Link_array<Score_element> support_l_arr_;
53   Link_array<Item> forced_l_arr_;
54   Link_array<Score_element> tied_l_arr_;
55   Local_key_engraver();
56
57   Item * grace_align_l_;
58 };
59
60 Local_key_engraver::Local_key_engraver()
61 {
62   key_item_p_ =0;
63   grace_align_l_ =0;
64   last_keysig_ = SCM_EOL;
65 }
66
67 void
68 Local_key_engraver::do_creation_processing ()
69 {
70   last_keysig_ = get_property ("keySignature");
71   daddy_trans_l_->set_property ("localKeySignature",  last_keysig_);  
72 }
73
74 void
75 Local_key_engraver::process_acknowledged ()
76 {
77   if (!key_item_p_ && mel_l_arr_.size()) 
78     {
79       SCM localsig = get_property ("localKeySignature");
80   
81       for (int i=0; i  < mel_l_arr_.size(); i++) 
82         {
83           Score_element * support_l = support_l_arr_[i];
84           Note_req * note_l = mel_l_arr_[i];
85
86           int n = note_l->pitch_.notename_i_;
87           int o = note_l->pitch_.octave_i_;
88           int a = note_l->pitch_.accidental_i_;
89           
90           /* see if there's a tie that "changes" the accidental */
91           /* works because if there's a tie, the note to the left
92              is of the same pitch as the actual note */
93
94           SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig);
95           if (prev == SCM_BOOL_F)
96             prev = scm_assoc (gh_int2scm (n), localsig);
97           int prev_acc = (prev == SCM_BOOL_F) ? 0 : gh_scm2int (gh_cdr (prev));
98           bool different = prev_acc != a;
99           
100           bool tie_changes = tied_l_arr_.find_l (support_l) && different;
101           if ((note_l->forceacc_b_ || different) && !tie_changes)
102             {
103               if (!key_item_p_) 
104                 {
105                   key_item_p_ = new Item(get_property ("Accidentals"));
106                   Local_key_item::set_interface (key_item_p_);
107
108
109                   Staff_symbol_referencer::set_interface (key_item_p_);
110                          
111                   announce_element (key_item_p_, 0);
112                 }
113
114               
115               bool extra_natural =
116                 sign (prev_acc) * (prev_acc - a) == 1
117                 && abs(prev_acc) == 2;
118
119               Local_key_item::add_pitch (key_item_p_, note_l->pitch_,
120                                          note_l->cautionary_b_,
121                                          extra_natural);
122               Side_position::add_support (key_item_p_,support_l);
123             }
124           
125           /*
126             We should not record the accidental if it is the first
127             note and it is tied from the previous measure.
128
129             Checking whether it is tied also works mostly, but will it
130             always do the correct thing?
131
132            */
133           bool forget = to_boolean (get_property ("forgetAccidentals"));
134           if (!forget && !tie_changes)
135             {
136               /*
137                 not really really correct if there are more than one
138                 noteheads with the same notename.
139                */
140               localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
141                                                              gh_int2scm (n)),
142                                           gh_int2scm (a)); 
143
144             }
145         }
146
147
148   
149   
150       daddy_trans_l_->set_property ("localKeySignature",  localsig);
151     }
152   
153   if (key_item_p_ && grace_align_l_)
154     {
155       Side_position::add_support (grace_align_l_,key_item_p_);
156       grace_align_l_ =0;
157     }
158
159   if (key_item_p_)
160     {
161       /*
162         Hmm. Which one has to be on the left?
163
164         On which left, code or paper?
165
166         (Arpeggios are engraved left of accidentals, of course.)
167        */
168       for (int i=0;  i < arpeggios_.size ();  i++)
169         Side_position::add_support (arpeggios_[i], key_item_p_);
170
171       arpeggios_.clear ();
172     }
173 }
174
175 void
176 Local_key_engraver::do_removal_processing ()
177 {
178   // TODO: if grace ? signal accidentals to Local_key_engraver the 
179 }
180
181 void
182 Local_key_engraver::do_pre_move_processing()
183 {
184   if (key_item_p_)
185     {
186       for (int i=0; i < support_l_arr_.size(); i++)
187         Side_position::add_support (key_item_p_,support_l_arr_[i]);
188
189       typeset_element (key_item_p_);
190       key_item_p_ =0;
191     }
192
193   grace_align_l_ = 0;
194   mel_l_arr_.clear();
195   arpeggios_.clear ();
196   tied_l_arr_.clear();
197   support_l_arr_.clear();
198   forced_l_arr_.clear();        
199 }
200
201 void
202 Local_key_engraver::acknowledge_element (Score_element_info info)
203 {
204   SCM wg= get_property ("weAreGraceContext");
205   
206   bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
207   bool he_gr = to_boolean (info.elem_l_->get_elt_property ("grace"));
208
209   Item * item = dynamic_cast<Item*> (info.elem_l_);  
210   if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
211     {
212       grace_align_l_ = item;
213     }
214   if (he_gr != selfgr)
215     return;
216   
217   Note_req * note_l =  dynamic_cast <Note_req *> (info.req_l_);
218
219   if (note_l && Rhythmic_head::has_interface (info.elem_l_))
220     {
221       mel_l_arr_.push (note_l);
222       support_l_arr_.push (info.elem_l_);
223     }
224   else if (Tie::has_interface (info.elem_l_))
225     {
226       tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
227     }
228   else if (Arpeggio::has_interface (info.elem_l_))
229     {
230       arpeggios_.push (info.elem_l_); 
231     }
232   
233 }
234
235 /*
236   ugh. repeated deep_copy generates lots of garbage.
237  */
238 void
239 Local_key_engraver::do_process_music()
240 {
241   SCM smp = get_property ("measurePosition");
242   Moment mp =  (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
243
244   SCM sig = get_property ("keySignature");
245
246   /*
247     Detect key sig changes. If we haven't found any, check if at start
248     of measure, and set localKeySignature anyhow.  */
249   if (last_keysig_ != sig) 
250     {
251       daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
252       last_keysig_ = sig;
253     }
254   else if (!mp)
255     {
256       if (!to_boolean (get_property ("noResetKey")))
257         daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
258     }
259 }
260
261
262
263 ADD_THIS_TRANSLATOR(Local_key_engraver);
264