]> git.donarmstrong.com Git - lilypond.git/blob - lily/ambitus-engraver.cc
dded40139a7b1408d4c68fd7ec7d5f0625b79ccc
[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       Drul_array<bool> expands = pitch_interval_.add_point (pitch);
126       if (expands[UP])
127         causes_[UP] = nr;
128       if (expands[DOWN])
129         causes_[DOWN] = nr;
130     }
131 }
132
133 void
134 Ambitus_engraver::finalize ()
135 {
136   if (ambitus_ && !pitch_interval_.is_empty ())
137     {
138       Grob *accidental_placement =
139         make_item ("AccidentalPlacement",
140                    accidentals_[DOWN]->self_scm ());
141
142       Direction d = DOWN;
143       do
144         {
145           Pitch p = pitch_interval_[d];
146           heads_[d]->set_property ("cause", causes_[d]->self_scm());
147           heads_[d]->set_property ("staff-position",
148                                    scm_from_int (start_c0_
149                                                  + p.steps ()));
150
151           SCM handle = scm_assoc (scm_cons (scm_from_int (p.get_octave ()),
152                                             scm_from_int (p.get_notename ())),
153                                   start_key_sig_);
154
155           if (handle == SCM_BOOL_F)
156             handle = scm_assoc (scm_from_int (p.get_notename ()),
157                                 start_key_sig_);
158
159           Rational sig_alter = (handle != SCM_BOOL_F)
160             ? robust_scm2rational (scm_cdr (handle), Rational (0)) : Rational (0);
161
162           if (sig_alter == p.get_alteration ())
163             {
164               accidentals_[d]->suicide ();
165               heads_[d]->set_object ("accidental-grob", SCM_EOL);
166             }
167           else
168             {
169               accidentals_[d]->set_property ("alteration", ly_rational2scm (p.get_alteration ()));
170             }
171           Separation_item::add_conditional_item (heads_[d], accidental_placement);
172           Accidental_placement::add_accidental (accidental_placement, accidentals_[d]);
173         }
174       while (flip (&d) != DOWN);
175
176
177       Pointer_group_interface::add_grob (ambitus_, ly_symbol2scm ("note-heads"), heads_[DOWN]);
178       Pointer_group_interface::add_grob (ambitus_, ly_symbol2scm ("note-heads"), heads_[UP]);
179       Axis_group_interface::add_element (group_, accidental_placement);
180     }
181   else
182     {
183       Direction d = DOWN;
184       do
185         {
186           accidentals_[d]->suicide ();
187           heads_[d]->suicide ();
188         }
189       while (flip (&d) != DOWN);
190
191       ambitus_->suicide ();
192     }
193 }
194
195 ADD_ACKNOWLEDGER (Ambitus_engraver, note_head);
196 ADD_TRANSLATOR (Ambitus_engraver,
197                 /* doc */
198                 "",
199
200                 /* create */
201                 "AccidentalPlacement "
202                 "Ambitus "
203                 "AmbitusAccidental "
204                 "AmbitusLine "
205                 "AmbitusNoteHead ",
206
207                 /* read */
208                 "",
209
210                 /* write */
211                 ""
212                 );