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