]> git.donarmstrong.com Git - lilypond.git/blob - lily/local-key-engraver.cc
patch::: 1.3.132.jcn2
[lilypond.git] / lily / local-key-engraver.cc
1 /*
2   local-key-engraver.cc -- implement Local_key_engraver
3
4   (c)  1997--2001 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 process_music();
35   virtual void acknowledge_grob (Grob_info);
36   virtual void stop_translation_timestep();
37   virtual void initialize ();
38   virtual void create_grobs ();
39   virtual void finalize ();
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<Grob> arpeggios_;
50   
51   Link_array<Note_req> mel_l_arr_;
52   Link_array<Grob> support_l_arr_;
53   Link_array<Item> forced_l_arr_;
54   Link_array<Grob> tie_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::initialize ()
69 {
70   last_keysig_ = get_property ("keySignature");
71   daddy_trans_l_->set_property ("localKeySignature",  last_keysig_);  
72 }
73
74 void
75 Local_key_engraver::create_grobs ()
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           Grob * support_l = support_l_arr_[i];
84           Note_req * note_l = mel_l_arr_[i];
85
86           int n = unsmob_pitch (note_l->get_mus_property ("pitch"))->notename_i_;
87           int o = unsmob_pitch (note_l->get_mus_property ("pitch"))->octave_i () ;
88           int a = unsmob_pitch (note_l->get_mus_property ("pitch"))->alteration_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           SCM prev_acc = (prev == SCM_BOOL_F) ? gh_int2scm(0) : gh_cdr (prev);
98           bool different = !gh_equal_p(prev_acc , gh_int2scm(a));
99           int p = gh_number_p(prev_acc) ? gh_scm2int(prev_acc) : 0;
100
101           /*
102             Find if we're
103             a. at right end of a tie -> tie_changes := different
104             b. at right end of broken tie -> tie_broken
105
106             Ugh: we're never case b., even when tie should be broken,
107             are we maybe called *before* line breaking?
108            */
109           bool tie_broken = false;
110           bool tie_changes = false;
111           for (int i=0; i < tie_l_arr_.size (); i++)
112             if (support_l == Tie::head (tie_l_arr_[i], RIGHT))
113               {
114                 tie_changes = different;
115                 Spanner *sp = dynamic_cast<Spanner*> (tie_l_arr_[i]);
116                 if (!Tie::head (tie_l_arr_[i], LEFT)
117                     || (sp && sp->broken_into_l_arr_.size ()
118                         && !Tie::head (sp->broken_into_l_arr_[0], LEFT)))
119                   tie_broken = true;
120                 break;
121               }
122
123           /*
124             Some comment here.
125             When do we want ties:
126
127               1. when property force-accidental is set, and not tie_changes
128               2. when different and not tie-changes
129               3. always after a line break -> why doesn't this work?
130             */
131           if (((to_boolean (note_l->get_mus_property ("force-accidental"))
132                 || different)
133                && !tie_changes)
134               || tie_broken)
135             {
136               if (!key_item_p_) 
137                 {
138                   key_item_p_ = new Item(get_property ("Accidentals"));
139                   Local_key_item::set_interface (key_item_p_);
140
141
142                   Staff_symbol_referencer::set_interface (key_item_p_);
143                          
144                   announce_grob (key_item_p_, 0);
145                 }
146
147               
148               bool extra_natural =
149                 sign (p) * (p - a) == 1
150                 && abs(p) == 2;
151
152               Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
153                                          to_boolean (note_l->get_mus_property ("cautionary")),
154                                          extra_natural);
155               Side_position::add_support (key_item_p_,support_l);
156             }
157           
158           /*
159             We should not record the accidental if it is the first
160             note and it is tied from the previous measure.
161
162             Checking whether it is tied also works mostly, but will it
163             always do the correct thing?
164
165            */
166           bool forget = to_boolean (get_property ("forgetAccidentals"));
167           if (tie_changes)
168             {
169               /*
170                 Remember an alteration that is different both from
171                 that of the tied note and of the key signature.
172
173                */
174               localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
175                                                              gh_int2scm (n)),
176                                           SCM_BOOL_T); 
177
178             }
179           else if (!forget)
180             {
181               /*
182                 not really really correct if there are more than one
183                 noteheads with the same notename.
184                */
185               localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
186                                                              gh_int2scm (n)),
187                                           gh_int2scm (a)); 
188
189             }
190         }
191
192
193   
194   
195       daddy_trans_l_->set_property ("localKeySignature",  localsig);
196     }
197   
198   if (key_item_p_ && grace_align_l_)
199     {
200       Side_position::add_support (grace_align_l_,key_item_p_);
201       grace_align_l_ =0;
202     }
203
204   if (key_item_p_)
205     {
206       /*
207         Hmm. Which one has to be on the left?
208
209         On which left, code or paper?
210
211         (Arpeggios are engraved left of accidentals, of course.)
212        */
213       for (int i=0;  i < arpeggios_.size ();  i++)
214         Side_position::add_support (arpeggios_[i], key_item_p_);
215
216       arpeggios_.clear ();
217     }
218 }
219
220 void
221 Local_key_engraver::finalize ()
222 {
223   // TODO: if grace ? signal accidentals to Local_key_engraver the 
224 }
225
226 void
227 Local_key_engraver::stop_translation_timestep()
228 {
229   if (key_item_p_)
230     {
231       for (int i=0; i < support_l_arr_.size(); i++)
232         Side_position::add_support (key_item_p_,support_l_arr_[i]);
233
234       typeset_grob (key_item_p_);
235       key_item_p_ =0;
236     }
237
238   grace_align_l_ = 0;
239   mel_l_arr_.clear();
240   arpeggios_.clear ();
241   tie_l_arr_.clear ();
242   support_l_arr_.clear();
243   forced_l_arr_.clear();        
244 }
245
246 void
247 Local_key_engraver::acknowledge_grob (Grob_info info)
248 {
249   SCM wg= get_property ("weAreGraceContext");
250   
251   bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
252   bool he_gr = to_boolean (info.elem_l_->get_grob_property ("grace"));
253
254   Item * item = dynamic_cast<Item*> (info.elem_l_);  
255   if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
256     {
257       grace_align_l_ = item;
258     }
259   if (he_gr != selfgr)
260     return;
261   
262   Note_req * note_l =  dynamic_cast <Note_req *> (info.req_l_);
263
264   if (note_l && Rhythmic_head::has_interface (info.elem_l_))
265     {
266       mel_l_arr_.push (note_l);
267       support_l_arr_.push (info.elem_l_);
268     }
269   else if (Tie::has_interface (info.elem_l_))
270     {
271       tie_l_arr_.push (info.elem_l_);
272     }
273   else if (Arpeggio::has_interface (info.elem_l_))
274     {
275       arpeggios_.push (info.elem_l_); 
276     }
277   
278 }
279
280 /*
281   ugh. repeated deep_copy generates lots of garbage.
282  */
283 void
284 Local_key_engraver::process_music()
285 {
286   SCM smp = get_property ("measurePosition");
287   Moment mp =  (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
288
289   SCM sig = get_property ("keySignature");
290
291   /*
292     Detect key sig changes. If we haven't found any, check if at start
293     of measure, and set localKeySignature anyhow.  */
294   if (last_keysig_ != sig) 
295     {
296       daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
297       last_keysig_ = sig;
298     }
299   else if (!mp)
300     {
301       if (!to_boolean (get_property ("noResetKey")))
302         daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
303     }
304 }
305
306
307
308 ADD_THIS_TRANSLATOR(Local_key_engraver);
309