]> git.donarmstrong.com Git - lilypond.git/blob - lily/key-engraver.cc
Use a `define-builtin-markup-command' macro for builtin markups, which
[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--2006 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 /*
22   TODO: The representation  of key sigs is all fucked.
23 */
24
25 /**
26    Make the key signature.
27 */
28 class Key_engraver : public Engraver
29 {
30   void create_key (bool);
31   void read_event (Stream_event const *r);
32
33   Stream_event *key_event_;
34   Item *item_;
35   Item *cancellation_;
36 public:
37   TRANSLATOR_DECLARATIONS (Key_engraver);
38
39 protected:
40   virtual void initialize ();
41   virtual void finalize ();
42   void stop_translation_timestep ();
43   void process_music ();
44
45   DECLARE_TRANSLATOR_LISTENER (key_change);
46   DECLARE_ACKNOWLEDGER (clef);
47   DECLARE_ACKNOWLEDGER (bar_line);
48 };
49
50 void
51 Key_engraver::finalize ()
52 {
53 }
54
55 Key_engraver::Key_engraver ()
56 {
57   key_event_ = 0;
58   item_ = 0;
59   cancellation_ = 0;
60 }
61
62 void
63 Key_engraver::create_key (bool is_default)
64 {
65   if (!item_)
66     {
67       item_ = make_item ("KeySignature",
68                          key_event_ ? key_event_->self_scm () : SCM_EOL);
69
70       item_->set_property ("c0-position",
71                            get_property ("middleCPosition"));
72
73       SCM last = get_property ("lastKeySignature");
74       SCM key = get_property ("keySignature");
75       bool extranatural = to_boolean(get_property("extraNatural"));
76
77       if ((to_boolean (get_property ("printKeyCancellation"))
78            || key == SCM_EOL)
79           && !scm_is_eq (last, key))
80         {
81           SCM restore = SCM_EOL;
82           SCM *tail = &restore;
83           for (SCM s = last; scm_is_pair (s); s = scm_cdr (s))
84             {
85               SCM new_alter_pair = scm_assoc (scm_caar (s), key);
86               int old_alter = scm_to_int (scm_cdar (s));
87               if (new_alter_pair == SCM_BOOL_F
88                   || extranatural
89                      && (scm_to_int(scm_cdr(new_alter_pair))-old_alter)*old_alter < 0)
90                 {
91                   *tail = scm_cons (scm_car (s), *tail);
92                   tail = SCM_CDRLOC (*tail);
93                 }
94             }
95
96           if (scm_is_pair (restore))
97             {
98               cancellation_ = make_item ("KeyCancellation",
99                                          key_event_
100                                          ? key_event_->self_scm () : SCM_EOL);
101               
102               cancellation_->set_property ("alteration-alist", restore);
103               cancellation_->set_property ("c0-position",
104                                            get_property ("middleCPosition"));
105             }
106         }
107       item_->set_property ("alteration-alist", key);
108     }
109
110   if (!is_default)
111     {
112       SCM visibility = get_property ("explicitKeySignatureVisibility");
113       item_->set_property ("break-visibility", visibility);
114       if (cancellation_)
115         cancellation_->set_property ("break-visibility", visibility);
116     }
117 }
118
119 IMPLEMENT_TRANSLATOR_LISTENER (Key_engraver, key_change);
120 void
121 Key_engraver::listen_key_change (Stream_event *ev)
122 {
123   /* do this only once, just to be on the safe side.  */
124   if (ASSIGN_EVENT_ONCE (key_event_, ev))
125     read_event (key_event_);
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 (Stream_event 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                 
207                 /* read */
208                 "createKeyOnClefChange "
209                 "explicitKeySignatureVisibility "
210                 "extraNatural "
211                 "keyAlterationOrder "
212                 "keySignature "
213                 "keySignature "
214                 "lastKeySignature "
215                 "printKeyCancellation "
216                 ,
217                 
218                 /* write */
219                 "keySignature "
220                 "lastKeySignature "
221                 "tonic ")