]> git.donarmstrong.com Git - lilypond.git/blob - lily/key-engraver.cc
(create_key): always print a cancellation
[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@cs.uu.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           cancellation_ = make_item ("KeyCancellation",
80                                      key_event_
81                                      ? key_event_->self_scm () : SCM_EOL);
82
83           SCM restore = SCM_EOL;
84           SCM *tail = &restore;
85           for (SCM s = last; scm_is_pair (s); s = scm_cdr (s))
86             {
87               if (scm_assoc (scm_caar (s), key) == SCM_BOOL_F)
88                 {
89                   *tail = scm_acons (scm_caar (s),
90                                      scm_from_int (0), *tail);
91                   tail = SCM_CDRLOC(*tail);
92                 }
93             }
94           
95           cancellation_->set_property ("accidentals", restore);
96           cancellation_->set_property ("c0-position",
97                                        get_property ("middleCPosition"));
98         }
99       item_->set_property ("accidentals", key);
100     }
101
102   if (!is_default)
103     {
104       SCM visibility = get_property ("explicitKeySignatureVisibility");
105       item_->set_property ("break-visibility", visibility);
106     }
107 }
108
109 bool
110 Key_engraver::try_music (Music *event)
111 {
112   if (event->is_mus_type ("key-change-event"))
113     {
114       /* do this only once, just to be on the safe side.  */
115       if (!key_event_)
116         {
117           key_event_ = event;
118           read_event (key_event_);
119         }
120       return true;
121     }
122   return false;
123 }
124
125 void
126 Key_engraver::acknowledge_clef (Grob_info info)
127 {
128   (void)info;
129   SCM c = get_property ("createKeyOnClefChange");
130   if (to_boolean (c))
131     {
132       create_key (false);
133     }
134 }
135
136 void
137 Key_engraver::acknowledge_bar_line (Grob_info info)
138 {
139   (void)info;
140   if (scm_is_pair (get_property ("keySignature")))
141     {
142       create_key (true);
143     }
144 }
145
146 void
147 Key_engraver::process_music ()
148 {
149   if (key_event_
150       || get_property ("lastKeySignature") != get_property ("keySignature"))
151     create_key (false);
152 }
153
154 void
155 Key_engraver::stop_translation_timestep ()
156 {
157   item_ = 0;
158   context ()->set_property ("lastKeySignature", get_property ("keySignature"));
159   cancellation_ = 0;
160   key_event_ = 0;
161 }
162
163 void
164 Key_engraver::read_event (Music const *r)
165 {
166   SCM p = r->get_property ("pitch-alist");
167   if (!scm_is_pair (p))
168     return;
169
170   SCM n = scm_list_copy (p);
171   SCM accs = SCM_EOL;
172   for (SCM s = get_property ("keyAccidentalOrder");
173        scm_is_pair (s); s = scm_cdr (s))
174     {
175       if (scm_is_pair (scm_member (scm_car (s), n)))
176         {
177           accs = scm_cons (scm_car (s), accs);
178           n = scm_delete_x (scm_car (s), n);
179         }
180     }
181
182   for (SCM s = n; scm_is_pair (s); s = scm_cdr (s))
183     if (scm_to_int (scm_cdar (s)))
184       accs = scm_cons (scm_car (s), accs);
185
186   context ()->set_property ("keySignature", accs);
187   context ()->set_property ("tonic",
188                             r->get_property ("tonic"));
189 }
190
191 void
192 Key_engraver::initialize ()
193 {
194   context ()->set_property ("keySignature", SCM_EOL);
195   context ()->set_property ("lastKeySignature", SCM_EOL);
196
197   Pitch p (0, 0, 0);
198   context ()->set_property ("tonic", p.smobbed_copy ());
199 }
200
201
202 ADD_ACKNOWLEDGER (Key_engraver,clef);
203 ADD_ACKNOWLEDGER (Key_engraver,bar_line);
204
205 ADD_TRANSLATOR (Key_engraver,
206                 /* descr */ "",
207                 /* creats*/ "KeySignature",
208                 /* accepts */ "key-change-event",
209                 /* reads */ "keySignature printKeyCancellation lastKeySignature "
210                 "explicitKeySignatureVisibility createKeyOnClefChange "
211                 "keyAccidentalOrder keySignature",
212                 /* write */ "lastKeySignature tonic keySignature");