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