]> git.donarmstrong.com Git - lilypond.git/blob - lily/key-engraver.cc
a35134c165b86ae076b288f541078120d3983de3
[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--2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "item.hh"
10 #include "bar-line.hh"
11 #include "staff-symbol-referencer.hh"
12 #include "context.hh"
13 #include "engraver.hh"
14 #include "protected-scm.hh"
15 #include "clef.hh"
16 #include "pitch.hh"
17
18 #include "translator.icc"
19
20 /*
21   TODO: The representation  of key sigs is all fucked.
22 */
23
24 /**
25    Make the key signature.
26 */
27 class Key_engraver : public Engraver
28 {
29   void create_key (bool);
30   void read_event (Music const *r);
31
32   Music *key_event_;
33   Item *item_;
34   Item *cancellation_;
35 public:
36   TRANSLATOR_DECLARATIONS (Key_engraver);
37
38 protected:
39   virtual void initialize ();
40   virtual void finalize ();
41   virtual bool try_music (Music *event);
42   void stop_translation_timestep ();
43   void process_music ();
44
45   DECLARE_ACKNOWLEDGER (clef);
46   DECLARE_ACKNOWLEDGER (bar_line);
47 };
48
49 void
50 Key_engraver::finalize ()
51 {
52 }
53
54 Key_engraver::Key_engraver ()
55 {
56   key_event_ = 0;
57   item_ = 0;
58   cancellation_ = 0;
59 }
60
61 void
62 Key_engraver::create_key (bool is_default)
63 {
64   if (!item_)
65     {
66       item_ = make_item ("KeySignature",
67                          key_event_ ? key_event_->self_scm () : SCM_EOL);
68
69       item_->set_property ("c0-position",
70                            get_property ("middleCPosition"));
71
72       SCM last = get_property ("lastKeySignature");
73       SCM key = get_property ("keySignature");
74
75       if ((to_boolean (get_property ("printKeyCancellation"))
76            || key == SCM_EOL)
77           && !scm_is_eq (last, key))
78         {
79           SCM restore = SCM_EOL;
80           SCM *tail = &restore;
81           for (SCM s = last; scm_is_pair (s); s = scm_cdr (s))
82             {
83               if (scm_assoc (scm_caar (s), key) == SCM_BOOL_F)
84                 {
85                   *tail = scm_acons (scm_caar (s),
86                                      scm_from_int (0), *tail);
87                   tail = SCM_CDRLOC (*tail);
88                 }
89             }
90
91           if (scm_is_pair (restore))
92             {
93               cancellation_ = make_item ("KeyCancellation",
94                                          key_event_
95                                          ? key_event_->self_scm () : SCM_EOL);
96           
97               cancellation_->set_property ("alteration-alist", restore);
98               cancellation_->set_property ("c0-position",
99                                            get_property ("middleCPosition"));
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 bool
113 Key_engraver::try_music (Music *event)
114 {
115   if (event->is_mus_type ("key-change-event"))
116     {
117       /* do this only once, just to be on the safe side.  */
118       if (!key_event_)
119         {
120           key_event_ = event;
121           read_event (key_event_);
122         }
123       return true;
124     }
125   return false;
126 }
127
128 void
129 Key_engraver::acknowledge_clef (Grob_info info)
130 {
131   (void)info;
132   SCM c = get_property ("createKeyOnClefChange");
133   if (to_boolean (c))
134     create_key (false);
135 }
136
137 void
138 Key_engraver::acknowledge_bar_line (Grob_info info)
139 {
140   (void)info;
141   if (scm_is_pair (get_property ("keySignature")))
142     create_key (true);
143 }
144
145 void
146 Key_engraver::process_music ()
147 {
148   if (key_event_
149       || get_property ("lastKeySignature") != get_property ("keySignature"))
150     create_key (false);
151 }
152
153 void
154 Key_engraver::stop_translation_timestep ()
155 {
156   item_ = 0;
157   context ()->set_property ("lastKeySignature", get_property ("keySignature"));
158   cancellation_ = 0;
159   key_event_ = 0;
160 }
161
162 void
163 Key_engraver::read_event (Music const *r)
164 {
165   SCM p = r->get_property ("pitch-alist");
166   if (!scm_is_pair (p))
167     return;
168
169   SCM n = scm_list_copy (p);
170   SCM accs = SCM_EOL;
171   for (SCM s = get_property ("keyAlterationOrder");
172        scm_is_pair (s); s = scm_cdr (s))
173     {
174       if (scm_is_pair (scm_member (scm_car (s), n)))
175         {
176           accs = scm_cons (scm_car (s), accs);
177           n = scm_delete_x (scm_car (s), n);
178         }
179     }
180
181   for (SCM s = n; scm_is_pair (s); s = scm_cdr (s))
182     if (scm_to_int (scm_cdar (s)))
183       accs = scm_cons (scm_car (s), accs);
184
185   context ()->set_property ("keySignature", accs);
186   context ()->set_property ("tonic",
187                             r->get_property ("tonic"));
188 }
189
190 void
191 Key_engraver::initialize ()
192 {
193   context ()->set_property ("keySignature", SCM_EOL);
194   context ()->set_property ("lastKeySignature", SCM_EOL);
195
196   Pitch p (0, 0, 0);
197   context ()->set_property ("tonic", p.smobbed_copy ());
198 }
199
200 ADD_ACKNOWLEDGER (Key_engraver, clef);
201 ADD_ACKNOWLEDGER (Key_engraver, bar_line);
202
203 ADD_TRANSLATOR (Key_engraver,
204                 /* doc */ "",
205                 /* create */ "KeySignature",
206                 /* accept */ "key-change-event",
207                 /* read */ "keySignature printKeyCancellation lastKeySignature "
208                 "explicitKeySignatureVisibility createKeyOnClefChange "
209                 "keyAlterationOrder keySignature",
210                 /* write */ "lastKeySignature tonic keySignature");