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