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