]> git.donarmstrong.com Git - lilypond.git/blob - lily/local-key-engraver.cc
release: 1.3.109
[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   void deprecated_process_music();
35   virtual void acknowledge_grob (Grob_info);
36   virtual void stop_translation_timestep();
37   virtual void do_creation_processing ();
38   virtual void create_grobs ();
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<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> 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::create_grobs ()
76 {
77   deprecated_process_music ();
78
79   if (!key_item_p_ && mel_l_arr_.size()) 
80     {
81       SCM localsig = get_property ("localKeySignature");
82   
83       for (int i=0; i  < mel_l_arr_.size(); i++) 
84         {
85           Grob * support_l = support_l_arr_[i];
86           Note_req * note_l = mel_l_arr_[i];
87
88           int n = unsmob_pitch (note_l->get_mus_property ("pitch"))->notename_i_;
89           int o = unsmob_pitch (note_l->get_mus_property ("pitch"))->octave_i () ;
90           int a = unsmob_pitch (note_l->get_mus_property ("pitch"))->alteration_i_;
91           
92           /* see if there's a tie that "changes" the accidental */
93           /* works because if there's a tie, the note to the left
94              is of the same pitch as the actual note */
95
96           SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig);
97           if (prev == SCM_BOOL_F)
98             prev = scm_assoc (gh_int2scm (n), localsig);
99           int prev_acc = (prev == SCM_BOOL_F) ? 0 : gh_scm2int (gh_cdr (prev));
100           bool different = prev_acc != a;
101           
102           bool tie_changes = tied_l_arr_.find_l (support_l) && different;
103           if ((to_boolean (note_l->get_mus_property ("force-accidental"))
104               || different) && !tie_changes)
105             {
106               if (!key_item_p_) 
107                 {
108                   key_item_p_ = new Item(get_property ("Accidentals"));
109                   Local_key_item::set_interface (key_item_p_);
110
111
112                   Staff_symbol_referencer::set_interface (key_item_p_);
113                          
114                   announce_grob (key_item_p_, 0);
115                 }
116
117               
118               bool extra_natural =
119                 sign (prev_acc) * (prev_acc - a) == 1
120                 && abs(prev_acc) == 2;
121
122               Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
123                                          to_boolean (note_l->get_mus_property ("cautionary")),
124                                          extra_natural);
125               Side_position::add_support (key_item_p_,support_l);
126             }
127           
128           /*
129             We should not record the accidental if it is the first
130             note and it is tied from the previous measure.
131
132             Checking whether it is tied also works mostly, but will it
133             always do the correct thing?
134
135            */
136           bool forget = to_boolean (get_property ("forgetAccidentals"));
137           if (!forget && !tie_changes)
138             {
139               /*
140                 not really really correct if there are more than one
141                 noteheads with the same notename.
142                */
143               localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
144                                                              gh_int2scm (n)),
145                                           gh_int2scm (a)); 
146
147             }
148         }
149
150
151   
152   
153       daddy_trans_l_->set_property ("localKeySignature",  localsig);
154     }
155   
156   if (key_item_p_ && grace_align_l_)
157     {
158       Side_position::add_support (grace_align_l_,key_item_p_);
159       grace_align_l_ =0;
160     }
161
162   if (key_item_p_)
163     {
164       /*
165         Hmm. Which one has to be on the left?
166
167         On which left, code or paper?
168
169         (Arpeggios are engraved left of accidentals, of course.)
170        */
171       for (int i=0;  i < arpeggios_.size ();  i++)
172         Side_position::add_support (arpeggios_[i], key_item_p_);
173
174       arpeggios_.clear ();
175     }
176 }
177
178 void
179 Local_key_engraver::do_removal_processing ()
180 {
181   // TODO: if grace ? signal accidentals to Local_key_engraver the 
182 }
183
184 void
185 Local_key_engraver::stop_translation_timestep()
186 {
187   if (key_item_p_)
188     {
189       for (int i=0; i < support_l_arr_.size(); i++)
190         Side_position::add_support (key_item_p_,support_l_arr_[i]);
191
192       typeset_grob (key_item_p_);
193       key_item_p_ =0;
194     }
195
196   grace_align_l_ = 0;
197   mel_l_arr_.clear();
198   arpeggios_.clear ();
199   tied_l_arr_.clear();
200   support_l_arr_.clear();
201   forced_l_arr_.clear();        
202 }
203
204 void
205 Local_key_engraver::acknowledge_grob (Grob_info info)
206 {
207   SCM wg= get_property ("weAreGraceContext");
208   
209   bool selfgr = gh_boolean_p (wg) &&gh_scm2bool (wg);
210   bool he_gr = to_boolean (info.elem_l_->get_grob_property ("grace"));
211
212   Item * item = dynamic_cast<Item*> (info.elem_l_);  
213   if (he_gr && !selfgr && item && Grace_align_item::has_interface (item))
214     {
215       grace_align_l_ = item;
216     }
217   if (he_gr != selfgr)
218     return;
219   
220   Note_req * note_l =  dynamic_cast <Note_req *> (info.req_l_);
221
222   if (note_l && Rhythmic_head::has_interface (info.elem_l_))
223     {
224       mel_l_arr_.push (note_l);
225       support_l_arr_.push (info.elem_l_);
226     }
227   else if (Tie::has_interface (info.elem_l_))
228     {
229       tied_l_arr_.push (Tie::head (info.elem_l_, RIGHT));
230     }
231   else if (Arpeggio::has_interface (info.elem_l_))
232     {
233       arpeggios_.push (info.elem_l_); 
234     }
235   
236 }
237
238 /*
239   ugh. repeated deep_copy generates lots of garbage.
240  */
241 void
242 Local_key_engraver::deprecated_process_music()
243 {
244   SCM smp = get_property ("measurePosition");
245   Moment mp =  (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
246
247   SCM sig = get_property ("keySignature");
248
249   /*
250     Detect key sig changes. If we haven't found any, check if at start
251     of measure, and set localKeySignature anyhow.  */
252   if (last_keysig_ != sig) 
253     {
254       daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
255       last_keysig_ = sig;
256     }
257   else if (!mp)
258     {
259       if (!to_boolean (get_property ("noResetKey")))
260         daddy_trans_l_->set_property ("localKeySignature",  ly_deep_copy (sig));
261     }
262 }
263
264
265
266 ADD_THIS_TRANSLATOR(Local_key_engraver);
267