]> git.donarmstrong.com Git - lilypond.git/blob - lily/key-engraver.cc
Merge branch 'lilypond/translation' of ssh://jomand@git.sv.gnu.org/srv/git/lilypond...
[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   SCM c = get_property ("createKeyOnClefChange");
125   if (to_boolean (c))
126     create_key (false);
127 }
128
129 void
130 Key_engraver::acknowledge_bar_line (Grob_info /* info */)
131 {
132   if (scm_is_pair (get_property ("keySignature")))
133     create_key (true);
134 }
135
136 void
137 Key_engraver::process_music ()
138 {
139   if (key_event_
140       || get_property ("lastKeySignature") != get_property ("keySignature"))
141     create_key (false);
142 }
143
144 void
145 Key_engraver::stop_translation_timestep ()
146 {
147   item_ = 0;
148   context ()->set_property ("lastKeySignature", get_property ("keySignature"));
149   cancellation_ = 0;
150   key_event_ = 0;
151 }
152
153 void
154 Key_engraver::read_event (Stream_event const *r)
155 {
156   SCM p = r->get_property ("pitch-alist");
157   if (!scm_is_pair (p))
158     return;
159
160   SCM accs = SCM_EOL;
161
162   SCM alist = scm_list_copy (p);
163   SCM order = get_property ("keyAlterationOrder");
164   for (SCM s = order;
165        scm_is_pair (s) && scm_is_pair (alist); s = scm_cdr (s))
166     {
167       SCM head = scm_member (scm_car (s), alist);
168       
169       if (scm_is_pair (head))
170         {
171           accs = scm_cons (scm_car (head), accs);
172           alist = scm_delete_x (scm_car (head), alist);
173         }
174     }
175
176   if (scm_is_pair (alist))
177     {
178       bool warn = false;
179       for (SCM s = alist; scm_is_pair (s); s = scm_cdr (s))
180         if (ly_scm2rational (scm_cdar (s)))
181           {
182             warn = true;
183             accs = scm_cons (scm_car (s), accs);
184           }
185
186       if (warn)
187         r->origin ()->warning ("No ordering for key signature alterations");      
188     }
189   
190   context ()->set_property ("keySignature", accs);
191   context ()->set_property ("tonic",
192                             r->get_property ("tonic"));
193 }
194
195 void
196 Key_engraver::initialize ()
197 {
198   context ()->set_property ("keySignature", SCM_EOL);
199   context ()->set_property ("lastKeySignature", SCM_EOL);
200
201   Pitch p (0, 0, 0);
202   context ()->set_property ("tonic", p.smobbed_copy ());
203 }
204
205 ADD_ACKNOWLEDGER (Key_engraver, clef);
206 ADD_ACKNOWLEDGER (Key_engraver, bar_line);
207
208 ADD_TRANSLATOR (Key_engraver,
209                 /* doc */
210                 "Engrave a key signature.",
211
212                 /* create */
213                 "KeySignature ",
214                 
215                 /* read */
216                 "createKeyOnClefChange "
217                 "explicitKeySignatureVisibility "
218                 "extraNatural "
219                 "keyAlterationOrder "
220                 "keySignature "
221                 "lastKeySignature "
222                 "printKeyCancellation ",
223                 
224                 /* write */
225                 "keySignature "
226                 "lastKeySignature "
227                 "tonic "
228                 );