]> git.donarmstrong.com Git - lilypond.git/blob - lily/a2-engraver.cc
*** empty log message ***
[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--2003 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_;
30   enum State { SOLO, SPLIT_INTERVAL, UNIRHYTHM, UNISILENCE, UNISON } state_;
31 };
32
33
34
35 A2_engraver::A2_engraver ()
36 {
37   text_ = 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_)
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_->id_string_.left_string (3) == "one")))
56         {
57           text_ = new Item (get_property ("TextScript"));
58           Side_position_interface::set_axis (text_, Y_AXIS);
59           announce_grob(text_, 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_->id_string_.left_string (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_->id_string_.left_string (3) == "one")
80                 text = get_property ("aDueText");
81             }
82           
83           Side_position_interface::set_direction (text_, dir);
84           text_->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_)
96     {
97       if (Note_head::has_interface (i.grob_))
98         {
99           Grob*t = text_;
100           Side_position_interface::add_support (t, i.grob_);
101           if (Side_position_interface::get_axis (t) == X_AXIS
102               && !t->get_parent (Y_AXIS))
103             t->set_parent (i.grob_, Y_AXIS);
104         }
105       if (Stem::has_interface (i.grob_))
106         {
107           Side_position_interface::add_support (text_, i.grob_);
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_->id_string_.left_string (3) == "one")
135     d =  UP;
136   else if (daddy_trans_->id_string_.left_string (3) == "two")
137     d = DOWN;
138
139   /* Must only set direction for VoiceCombines, not for StaffCombines:
140      we can't detect that here, so we use yet another property */
141   if (!to_boolean (get_property ("noDirection"))
142       && (Stem::has_interface (i.grob_)
143           || Slur::has_interface (i.grob_)
144           || Tie::has_interface (i.grob_)
145           /* Usually, dynamics are removed by *_devnull_engravers for
146              the second voice.  On the one hand, we don't want all
147              dynamics for the first voice to be placed above the
148              staff.  On the other hand, colliding of scripts may be
149              worse.  So, we don't set directions for these when we're
150              playing solo. */
151           || (i.grob_->internal_has_interface (ly_symbol2scm
152                                                  ("dynamic-interface"))
153               && state_ != SOLO)
154           || (i.grob_->internal_has_interface (ly_symbol2scm
155                                                  ("text-interface"))
156               && state_ != SOLO)
157           ))
158     {
159       /* When in solo a due mode, and we have solo, every grob in
160          other thread gets annihilated, so we don't set dir.
161
162          Maybe that should be optional? */
163       if ((solo != SCM_BOOL_T && solo_adue == SCM_BOOL_T)
164
165           /* When not same rhythm, we set dir */
166           && (unirhythm != SCM_BOOL_T
167               /* When both have rests, but previously played something
168                  different, we set dir */
169               || ((unisilence == SCM_BOOL_T && previous_state != UNISON))
170               /* When same rhythm, and split stems, but not same pitch
171                  or not solo a du mode, we set dir */
172               || (unirhythm == SCM_BOOL_T && split_interval == SCM_BOOL_T
173                   && (unison != SCM_BOOL_T || solo_adue != SCM_BOOL_T))))
174         {
175         
176           /* Blunt axe method: every grob gets a propertysetting. */
177           i.grob_->set_grob_property ("direction", scm_int2num (d));
178         }
179     }
180
181   /* Should we have separate state variable for being "rest
182      while other has solo?"  */
183   if (Multi_measure_rest::has_interface (i.grob_) && d)
184     if (state_ == UNIRHYTHM
185         && unisilence != SCM_BOOL_T)
186     {
187       i.grob_->set_grob_property ("staff-position", scm_int2num (d * 6));
188     }
189 }
190
191 void 
192 A2_engraver::stop_translation_timestep ()
193 {
194   if (text_)
195     {
196       Side_position_interface::add_staff_support (text_);
197       typeset_grob (text_);
198       text_ = 0;
199     }
200 }
201
202 ENTER_DESCRIPTION(A2_engraver,
203 /* descr */       "Part combine engraver for orchestral scores.         "
204 "The markings @emph{a2}, @emph{Solo} and @emph{Solo II}, are            "
205 "created by this engraver.  It also acts upon instructions of the part  "
206 "combiner.  Another thing that the this engraver, is forcing of stem,   "
207 "slur and tie directions, always when both threads are not identical;   "
208 "up for the musicexpr called @code{one}, down for the musicexpr called  "
209 "@code{two}.                                                            "
210 ,
211 /* creats*/       "TextScript",
212 /* accepts */     "",
213 /* acks  */       "multi-measure-rest-interface "
214 "slur-interface stem-interface tie-interface note-head-interface dynamic-interface text-interface"
215 ,/* reads */       "combineParts noDirection soloADue soloText soloIIText aDueText split-interval unison solo unisilence unirhythm",
216 /* write */       "");