]> git.donarmstrong.com Git - lilypond.git/blob - lily/a2-engraver.cc
release: 1.5.29
[lilypond.git] / lily / a2-engraver.cc
1 /*
2   a2-engraver.cc -- implement A2_engraver
3
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2000--2002 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "engraver.hh"
10 #include "item.hh"
11 #include "note-head.hh"
12 #include "stem.hh"
13 #include "slur.hh"
14 #include "translator-group.hh"
15 #include "side-position-interface.hh"
16 #include "directional-element-interface.hh"
17 #include "multi-measure-rest.hh"
18
19 class A2_engraver : public Engraver
20 {
21   TRANSLATOR_DECLARATIONS(A2_engraver);
22
23 protected:
24   virtual void acknowledge_grob (Grob_info);
25   virtual void create_grobs ();
26   virtual void stop_translation_timestep ();
27 private:
28   Item* text_p_;
29   enum State { SOLO, SPLIT_INTERVAL, UNIRHYTHM, UNISILENCE, UNISON } state_;
30 };
31
32
33
34 A2_engraver::A2_engraver ()
35 {
36   text_p_ = 0;
37   state_ = UNISILENCE;
38 }
39
40 void
41 A2_engraver::create_grobs ()
42 {
43   if (!to_boolean (get_property ("combineParts")))
44     return ;
45   if (!text_p_)
46     {
47       SCM unison = get_property ("unison");
48       SCM solo = get_property ("solo");
49       SCM solo_adue = get_property ("soloADue");
50
51       if (solo_adue == SCM_BOOL_T
52           && ((solo == SCM_BOOL_T && state_ != SOLO)
53               || (unison == SCM_BOOL_T && state_ != UNISON
54                   && daddy_trans_l_->id_str_.left_str (3) == "one")))
55         {
56           text_p_ = new Item (get_property ("TextScript"));
57           Side_position_interface::set_axis (text_p_, Y_AXIS);
58           announce_grob (text_p_, 0);
59       
60           Direction dir = UP;
61           SCM text = SCM_EOL;
62           if (solo == SCM_BOOL_T)
63             {
64               state_ = SOLO;
65               if (daddy_trans_l_->id_str_.left_str (3) == "one")
66                 {
67                   text = get_property ("soloText");
68                 }
69               else
70                 {
71                   text = get_property ("soloIIText");
72                   dir = DOWN;
73                 }
74             }
75           else if (unison == SCM_BOOL_T)
76             {
77               state_ = UNISON;
78               if (daddy_trans_l_->id_str_.left_str (3) == "one")
79                 text = get_property ("aDueText");
80             }
81           
82           Side_position_interface::set_direction (text_p_, dir);
83           text_p_->set_grob_property ("text", text);
84         }
85     }
86 }
87
88 void
89 A2_engraver::acknowledge_grob (Grob_info i)
90 {
91   if (!to_boolean (get_property ("combineParts")))
92     return ;
93   
94   if (text_p_)
95     {
96       if (Note_head::has_interface (i.grob_l_))
97         {
98           Grob*t = text_p_;
99           Side_position_interface::add_support (t, i.grob_l_);
100           if (Side_position_interface::get_axis (t) == X_AXIS
101               && !t->get_parent (Y_AXIS))
102             t->set_parent (i.grob_l_, Y_AXIS);
103         }
104       if (Stem::has_interface (i.grob_l_))
105         {
106           Side_position_interface::add_support (text_p_, i.grob_l_);
107         }
108     }
109           
110   SCM unisilence = get_property ("unisilence");
111   SCM unison = get_property ("unison");
112   SCM unirhythm = get_property ("unirhythm");
113   SCM solo = get_property ("solo");
114   SCM split_interval = get_property ("split-interval");
115   SCM solo_adue = get_property ("soloADue");
116   
117   State previous_state = state_;
118   if (unisilence == SCM_BOOL_T)
119     /*
120       state_ = UNISILENCE;
121     */
122     ;
123   else if (solo == SCM_BOOL_T)
124     state_ = SOLO;
125   else if (unison == SCM_BOOL_T)
126     state_ = UNISON;
127   else if (unirhythm == SCM_BOOL_T && split_interval == SCM_BOOL_T)
128     state_ = SPLIT_INTERVAL;
129   else if (unirhythm)
130     state_ = UNIRHYTHM;
131
132   Direction d = CENTER;
133   if (daddy_trans_l_->id_str_.left_str (3) == "one")
134     d =  UP;
135   else if (daddy_trans_l_->id_str_.left_str (3) == "two")
136     d = DOWN;
137
138   /* Must only set direction for VoiceCombines, not for StaffCombines:
139      we can't detect that here, so, ugh, yet another property */
140   if (!to_boolean (get_property ("noDirection"))
141       && (Stem::has_interface (i.grob_l_)
142           || Slur::has_interface (i.grob_l_)
143           // || Tie::has_interface (i.grob_l_)
144           || i.grob_l_->has_interface (ly_symbol2scm ("tie-interface"))
145           
146           /*
147             Usually, dynamics are removed by *_devnull_engravers for the
148             second voice.  On the one hand, we don't want all dynamics for
149             the first voice to be placed above the staff.  On the other
150             hand, colliding of scripts may be worse.
151             So, we don't set directions for these when we're playing solo.
152           */
153           || (i.grob_l_->has_interface (ly_symbol2scm ("dynamic-interface"))
154               && state_ != SOLO)
155           || (i.grob_l_->has_interface (ly_symbol2scm ("text-interface"))
156               && state_ != SOLO)
157           ))
158     {
159       /*
160         Hmm.  We must set dir when solo, in order to get
161         the rests collided to the right position
162       */
163       if ((unirhythm != SCM_BOOL_T) || (solo == SCM_BOOL_T)
164           || ((unisilence == SCM_BOOL_T && previous_state != UNISON))
165           || (unirhythm == SCM_BOOL_T && split_interval == SCM_BOOL_T
166               && (unison != SCM_BOOL_T || solo_adue != SCM_BOOL_T)))
167         {
168         
169           /*
170             Blunt axe method: every grob gets a propertysetting.
171            */
172           i.grob_l_->set_grob_property ("direction", gh_int2scm (d));
173         }
174     }
175
176   /*
177     todo: should we have separate state variable for being "rest while
178     other has solo?"  */
179   if ( Multi_measure_rest::has_interface (i.grob_l_) && d )
180     if (state_ == UNIRHYTHM
181         && unisilence != SCM_BOOL_T)
182     {
183       i.grob_l_->set_grob_property ("staff-position", gh_int2scm (d * 6));
184     }
185 }
186
187 void 
188 A2_engraver::stop_translation_timestep ()
189 {
190   if (text_p_)
191     {
192       Side_position_interface::add_staff_support (text_p_);
193       typeset_grob (text_p_);
194       text_p_ = 0;
195     }
196 }
197
198 ENTER_DESCRIPTION(A2_engraver,
199 /* descr */       "Part combine engraver for orchestral scores.
200
201 The markings @emph{a2}, @emph{Solo} and @emph{Solo II}, are
202 created by this engraver.  It also acts upon instructions of the part
203 combiner.  Another thing that the this engraver, is forcing of stem,
204 slur and tie directions, always when both threads are not identical;
205 up for the musicexpr called @code{one}, down for the musicexpr called
206 @code{two}.
207
208 ",
209 /* creats*/       "TextScript",
210 /* acks  */       "grob-interface tie-interface note-head-interface ",
211 /* reads */       "combineParts noDirection soloADue soloText soloIIText aDueText split-interval unison solo unisilence unirhythm",
212 /* write */       "");