]> git.donarmstrong.com Git - lilypond.git/blob - lily/key-engraver.cc
Run `make grand-replace'.
[lilypond.git] / lily / key-engraver.cc
1 /*
2   key-engraver.cc -- implement Key_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "bar-line.hh"
10 #include "clef.hh"
11 #include "context.hh"
12 #include "engraver.hh"
13 #include "item.hh"
14 #include "pitch.hh"
15 #include "protected-scm.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "stream-event.hh"
18
19 #include "translator.icc"
20
21 class Key_engraver : public Engraver
22 {
23   void create_key (bool);
24   void read_event (Stream_event const *r);
25
26   Stream_event *key_event_;
27   Item *item_;
28   Item *cancellation_;
29 public:
30   TRANSLATOR_DECLARATIONS (Key_engraver);
31
32 protected:
33   virtual void initialize ();
34   virtual void finalize ();
35   void stop_translation_timestep ();
36   void process_music ();
37
38   DECLARE_TRANSLATOR_LISTENER (key_change);
39   DECLARE_ACKNOWLEDGER (clef);
40   DECLARE_ACKNOWLEDGER (bar_line);
41 };
42
43 void
44 Key_engraver::finalize ()
45 {
46 }
47
48 Key_engraver::Key_engraver ()
49 {
50   key_event_ = 0;
51   item_ = 0;
52   cancellation_ = 0;
53 }
54
55
56 void
57 Key_engraver::create_key (bool is_default)
58 {
59   if (!item_)
60     {
61       item_ = make_item ("KeySignature",
62                          key_event_ ? key_event_->self_scm () : SCM_EOL);
63
64       item_->set_property ("c0-position",
65                            get_property ("middleCPosition"));
66
67       SCM last = get_property ("lastKeySignature");
68       SCM key = get_property ("keySignature");
69       bool extranatural = to_boolean (get_property ("extraNatural"));
70
71       if ((to_boolean (get_property ("printKeyCancellation"))
72            || key == SCM_EOL)
73           && !scm_is_eq (last, key))
74         {
75           SCM restore = SCM_EOL;
76           SCM *tail = &restore;
77           for (SCM s = last; scm_is_pair (s); s = scm_cdr (s))
78             {
79               SCM new_alter_pair = scm_assoc (scm_caar (s), key);
80               Rational old_alter = robust_scm2rational (scm_cdar (s), 0);
81               if (new_alter_pair == SCM_BOOL_F
82                   || extranatural
83                   && (ly_scm2rational (scm_cdr (new_alter_pair)) - old_alter)*old_alter < Rational (0))
84                 {
85                   *tail = scm_cons (scm_car (s), *tail);
86                   tail = SCM_CDRLOC (*tail);
87                 }
88             }
89
90           if (scm_is_pair (restore))
91             {
92               cancellation_ = make_item ("KeyCancellation",
93                                          key_event_
94                                          ? key_event_->self_scm () : SCM_EOL);
95               
96               cancellation_->set_property ("alteration-alist", restore);
97               cancellation_->set_property ("c0-position",
98                                            get_property ("middleCPosition"));
99             }
100         }
101
102       item_->set_property ("alteration-alist", key);
103     }
104
105   if (!is_default)
106     {
107       SCM visibility = get_property ("explicitKeySignatureVisibility");
108       item_->set_property ("break-visibility", visibility);
109     }
110 }
111
112 IMPLEMENT_TRANSLATOR_LISTENER (Key_engraver, key_change);
113 void
114 Key_engraver::listen_key_change (Stream_event *ev)
115 {
116   /* do this only once, just to be on the safe side.  */
117   if (ASSIGN_EVENT_ONCE (key_event_, ev))
118     read_event (key_event_);
119 }
120
121 void
122 Key_engraver::acknowledge_clef (Grob_info info)
123 {
124   (void)info;
125   SCM c = get_property ("createKeyOnClefChange");
126   if (to_boolean (c))
127     create_key (false);
128 }
129
130 void
131 Key_engraver::acknowledge_bar_line (Grob_info info)
132 {
133   (void)info;
134   if (scm_is_pair (get_property ("keySignature")))
135     create_key (true);
136 }
137
138 void
139 Key_engraver::process_music ()
140 {
141   if (key_event_
142       || get_property ("lastKeySignature") != get_property ("keySignature"))
143     create_key (false);
144 }
145
146 void
147 Key_engraver::stop_translation_timestep ()
148 {
149   item_ = 0;
150   context ()->set_property ("lastKeySignature", get_property ("keySignature"));
151   cancellation_ = 0;
152   key_event_ = 0;
153 }
154
155 void
156 Key_engraver::read_event (Stream_event const *r)
157 {
158   SCM p = r->get_property ("pitch-alist");
159   if (!scm_is_pair (p))
160     return;
161
162   SCM accs = SCM_EOL;
163
164   SCM alist = scm_list_copy (p);
165   SCM order = get_property ("keyAlterationOrder");
166   for (SCM s = order;
167        scm_is_pair (s) && scm_is_pair (alist); s = scm_cdr (s))
168     {
169       SCM head = scm_member (scm_car (s), alist);
170       
171       if (scm_is_pair (head))
172         {
173           accs = scm_cons (scm_car (head), accs);
174           alist = scm_delete_x (scm_car (head), alist);
175         }
176     }
177
178   if (scm_is_pair (alist))
179     {
180       bool warn = false;
181       for (SCM s = alist; scm_is_pair (s); s = scm_cdr (s))
182         if (ly_scm2rational (scm_cdar (s)))
183           {
184             warn = true;
185             accs = scm_cons (scm_car (s), accs);
186           }
187
188       if (warn)
189         r->origin ()->warning ("No ordering for key signature alterations");      
190     }
191   
192   context ()->set_property ("keySignature", accs);
193   context ()->set_property ("tonic",
194                             r->get_property ("tonic"));
195 }
196
197 void
198 Key_engraver::initialize ()
199 {
200   context ()->set_property ("keySignature", SCM_EOL);
201   context ()->set_property ("lastKeySignature", SCM_EOL);
202
203   Pitch p (0, 0, 0);
204   context ()->set_property ("tonic", p.smobbed_copy ());
205 }
206
207 ADD_ACKNOWLEDGER (Key_engraver, clef);
208 ADD_ACKNOWLEDGER (Key_engraver, bar_line);
209
210 ADD_TRANSLATOR (Key_engraver,
211                 /* doc */
212                 "Engrave a key signature.",
213
214                 /* create */
215                 "KeySignature ",
216                 
217                 /* read */
218                 "createKeyOnClefChange "
219                 "explicitKeySignatureVisibility "
220                 "extraNatural "
221                 "keyAlterationOrder "
222                 "keySignature "
223                 "lastKeySignature "
224                 "printKeyCancellation ",
225                 
226                 /* write */
227                 "keySignature "
228                 "lastKeySignature "
229                 "tonic "
230                 );