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