]> git.donarmstrong.com Git - lilypond.git/blob - lily/local-key-engraver.cc
release: 1.3.102
[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       for (int i=0;  i < arpeggios_.size ();  i++)
165         Side_position::add_support (arpeggios_[i], key_item_p_);
166
167       arpeggios_.clear ();
168     }
169 }
170
171 void
172 Local_key_engraver::do_removal_processing ()
173 {
174   // TODO: if grace ? signal accidentals to Local_key_engraver the 
175 }
176
177 void
178 Local_key_engraver::do_pre_move_processing()
179 {
180   if (key_item_p_)
181     {
182       for (int i=0; i < support_l_arr_.size(); i++)
183         Side_position::add_support (key_item_p_,support_l_arr_[i]);
184
185       typeset_element (key_item_p_);
186       key_item_p_ =0;
187     }
188
189   grace_align_l_ = 0;
190   mel_l_arr_.clear();
191   arpeggios_.clear ();
192   tied_l_arr_.clear();
193   support_l_arr_.clear();
194   forced_l_arr_.clear();        
195 }
196
197 void
198 Local_key_engraver::acknowledge_element (Score_element_info info)
199 {
200   SCM wg= get_property ("weAreGraceContext");
201   
202   bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
203   bool he_gr = to_boolean (info.elem_l_->get_elt_property ("grace"));
204
205   Item * item = dynamic_cast<Item*> (info.elem_l_);  
206   if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
207     {
208       grace_align_l_ = item;
209     }
210   if (he_gr != selfgr)
211     return;
212   
213   Note_req * note_l =  dynamic_cast <Note_req *> (info.req_l_);
214
215   if (note_l && Rhythmic_head::has_interface (info.elem_l_))
216     {
217       mel_l_arr_.push (note_l);
218       support_l_arr_.push (info.elem_l_);
219     }
220   else if (Tie::has_interface (info.elem_l_))
221     {
222       tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
223     }
224   else if (Arpeggio::has_interface (info.elem_l_))
225     {
226       arpeggios_.push (info.elem_l_); 
227     }
228   
229 }
230
231 /*
232   ugh. repeated deep_copy generates lots of garbage.
233  */
234 void
235 Local_key_engraver::do_process_music()
236 {
237   SCM smp = get_property ("measurePosition");
238   Moment mp =  (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
239
240   SCM sig = get_property ("keySignature");
241
242   /*
243     Detect key sig changes. If we haven't found any, check if at start
244     of measure, and set localKeySignature anyhow.  */
245   if (last_keysig_ != sig) 
246     {
247       daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
248       last_keysig_ = sig;
249     }
250   else if (!mp)
251     {
252       if (!to_boolean (get_property ("noResetKey")))
253         daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
254     }
255 }
256
257
258
259 ADD_THIS_TRANSLATOR(Local_key_engraver);
260