]> git.donarmstrong.com Git - lilypond.git/blob - lily/ambitus-engraver.cc
Fix 530.
[lilypond.git] / lily / ambitus-engraver.cc
1 /*
2   ambitus-engraver.cc -- implement Ambitus_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2002--2007 Juergen Reuter <reuter@ipd.uka.de>
7
8   Han-Wen Nienhuys <hanwen@xs4all.nl
9 */
10
11 #include "engraver.hh"
12
13 #include "accidental-placement.hh"
14 #include "axis-group-interface.hh"
15 #include "item.hh"
16 #include "note-head.hh"
17 #include "pitch-interval.hh"
18 #include "pointer-group-interface.hh"
19 #include "protected-scm.hh"
20 #include "side-position-interface.hh"
21 #include "separation-item.hh"
22 #include "staff-symbol-referencer.hh" 
23 #include "stream-event.hh"
24
25 #include "translator.icc"
26
27 class Ambitus_engraver : public Engraver
28 {
29 public:
30   TRANSLATOR_DECLARATIONS (Ambitus_engraver);
31   void process_music ();
32   void acknowledge_note_head (Grob_info);
33   void stop_translation_timestep ();
34   virtual void finalize ();
35   virtual void derived_mark () const;
36
37 private:
38   void create_ambitus ();
39   Item *ambitus_;
40   Item *group_;
41   Drul_array<Item *> heads_;
42   Drul_array<Item *> accidentals_;
43   Drul_array<Stream_event *> causes_;
44   Pitch_interval pitch_interval_;
45   bool is_typeset_;
46   int start_c0_;
47   SCM start_key_sig_;
48 };
49
50 void
51 Ambitus_engraver::derived_mark () const
52 {
53   scm_gc_mark (start_key_sig_);
54 }
55
56 void
57 Ambitus_engraver::create_ambitus ()
58 {
59   ambitus_ = make_item ("AmbitusLine", SCM_EOL);
60   group_ = make_item ("Ambitus", SCM_EOL);
61   Direction d = DOWN;
62   do
63     {
64       heads_[d] = make_item ("AmbitusNoteHead", SCM_EOL);
65       accidentals_[d] = make_item ("AmbitusAccidental", SCM_EOL);
66       accidentals_[d]->set_parent (heads_[d], Y_AXIS);
67       heads_[d]->set_object ("accidental-grob",
68                              accidentals_[d]->self_scm ());
69       Axis_group_interface::add_element (group_, heads_[d]);
70       Axis_group_interface::add_element (group_, accidentals_[d]);
71     }
72   while (flip (&d) != DOWN);
73
74   ambitus_->set_parent (heads_[DOWN], X_AXIS);
75   Axis_group_interface::add_element (group_, ambitus_);
76
77   is_typeset_ = false;
78 }
79
80 Ambitus_engraver::Ambitus_engraver ()
81 {
82   ambitus_ = 0;
83   heads_[LEFT] = heads_[RIGHT] = 0;
84   accidentals_[LEFT] = accidentals_[RIGHT] = 0;
85   group_ = 0;
86   is_typeset_ = false;
87   start_key_sig_ = SCM_EOL;
88 }
89
90 void
91 Ambitus_engraver::process_music ()
92 {
93   /*
94    * Ensure that ambitus is created in the very first timestep
95    */
96   if (!ambitus_)
97     create_ambitus ();
98 }
99
100 void
101 Ambitus_engraver::stop_translation_timestep ()
102 {
103   if (ambitus_ && !is_typeset_)
104     {
105       /*
106        * Evaluate middleCPosition not until now, since otherwise we
107        * may then oversee a clef that is defined in a staff context if
108        * we are in a voice context; middleCPosition would then be
109        * assumed to be 0.
110        */
111       start_c0_ = robust_scm2int (get_property ("middleCPosition"), 0);
112       start_key_sig_ = get_property ("keySignature");
113
114       is_typeset_ = true;
115     }
116 }
117
118 void
119 Ambitus_engraver::acknowledge_note_head (Grob_info info)
120 {
121   Stream_event *nr = info.event_cause ();
122   if (nr && nr->in_event_class ("note-event"))
123     {
124       Pitch pitch = *unsmob_pitch (nr->get_property ("pitch"));
125       Direction expand_dir = pitch_interval_.add_point (pitch);
126       if (expand_dir)
127         causes_[expand_dir] = nr;
128     }
129 }
130
131 void
132 Ambitus_engraver::finalize ()
133 {
134   if (ambitus_ && !pitch_interval_.is_empty ())
135     {
136       Grob * accidental_placement =
137         make_item ("AccidentalPlacement",
138                    accidentals_[DOWN]->self_scm ());
139
140       Direction d = DOWN;
141       do
142         {
143           Pitch p = pitch_interval_[d];
144           heads_[d]->set_property ("cause", causes_[d]->self_scm());
145           heads_[d]->set_property ("staff-position",
146                                    scm_from_int (start_c0_
147                                                  + p.steps ()));
148
149           SCM handle = scm_assoc (scm_cons (scm_from_int (p.get_octave ()),
150                                             scm_from_int (p.get_notename ())),
151                                   start_key_sig_);
152
153           if (handle == SCM_BOOL_F)
154             handle = scm_assoc (scm_from_int (p.get_notename ()),
155                                 start_key_sig_);
156
157           Rational sig_alter = (handle != SCM_BOOL_F)
158             ? robust_scm2rational (scm_cdr (handle), Rational (0)) : Rational (0);
159
160           if (sig_alter == p.get_alteration ())
161             {
162               accidentals_[d]->suicide ();
163               heads_[d]->set_object ("accidental-grob", SCM_EOL);
164             }
165           else
166             {
167               accidentals_[d]->set_property ("alteration", ly_rational2scm (p.get_alteration ()));
168             }
169           Separation_item::add_conditional_item (heads_[d], accidental_placement);
170           Accidental_placement::add_accidental (accidental_placement, accidentals_[d]);
171         }
172       while (flip (&d) != DOWN);
173
174
175       Pointer_group_interface::add_grob (ambitus_, ly_symbol2scm ("note-heads"), heads_[DOWN]);
176       Pointer_group_interface::add_grob (ambitus_, ly_symbol2scm ("note-heads"), heads_[UP]);
177       Axis_group_interface::add_element (group_, accidental_placement);
178     }
179   else
180     {
181       Direction d = DOWN;
182       do
183         {
184           accidentals_[d]->suicide ();
185           heads_[d]->suicide ();
186         }
187       while (flip (&d) != DOWN);
188
189       ambitus_->suicide ();
190     }
191 }
192
193 ADD_ACKNOWLEDGER (Ambitus_engraver, note_head);
194 ADD_TRANSLATOR (Ambitus_engraver,
195                 /* doc */ "",
196                 /* create */
197                 "Ambitus "
198                 "AmbitusLine "
199                 "AmbitusNoteHead "
200                 "AmbitusAccidental",
201                 /* read */ "",
202                 /* write */ "");