]> git.donarmstrong.com Git - lilypond.git/blob - lily/auto-beam-engraver.cc
patch::: 1.1.22.jcn5: autobiem
[lilypond.git] / lily / auto-beam-engraver.cc
1 /*   
2   auto-beam-engraver.cc --  implement Auto_beam_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999 Jan Nieuwenhuizen <janneke@gnu.org>
7   
8  */
9
10 #include "auto-beam-engraver.hh"
11 #include "musical-request.hh"
12 #include "beam.hh"
13 #include "grouping.hh"
14 #include "rest.hh"
15 #include "stem.hh"
16 #include "debug.hh"
17 #include "time-description.hh"
18
19 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
20
21 Auto_beam_engraver::Auto_beam_engraver ()
22 {
23   beam_p_ = 0;
24   finished_beam_p_ = 0;
25   finished_grouping_p_ = 0;
26   grouping_p_ = 0;
27 }
28
29 void
30 Auto_beam_engraver::do_process_requests ()
31 {
32   Time_description const *time = get_staff_info().time_C_;
33
34   //Moment begin_mom;
35   Real begin_f;
36   Scalar begin = get_property ("beamAutoBegin", 0);
37   if (begin.isnum_b ())
38     // brrr.
39     // begin_mom = (Real)begin;
40     begin_f = (Real)begin;
41   else
42     return;
43   
44   Scalar end = get_property ("beamAutoEnd", 0);
45   //Moment end_mom;
46   Real end_f;
47   if (end.isnum_b ())
48     // brrr.
49     // end_mom = (Real)end;
50     end_f = (Real)end;
51   else
52     return;
53   
54   Real epsilon_f = Moment (1, 512);
55   Real f;
56   if (beam_p_ && ((f=abs (fmod (time->whole_in_measure_, end_f))) < epsilon_f))
57     {
58       DOUT << String ("ending autobeam at: ") + now_moment ().str ();
59       if (beam_p_->stems_.size () < 2)
60         {
61           DOUT << "junking autombeam: less than two stems";
62           unbeam ();
63         }
64       else
65         {
66           finished_beam_p_ = beam_p_;
67           finished_grouping_p_ = grouping_p_;
68           beam_p_ = 0;
69           grouping_p_ = 0;
70         }
71     }
72   
73   /*
74     Allow already started autobeam to end
75    */
76   Scalar on = get_property ("beamAuto", 0);
77   if (!on.to_bool ())
78     return;
79
80   if (!beam_p_ && ((f=abs (fmod (time->whole_in_measure_, begin_f))) < epsilon_f))
81     {
82       DOUT << String ("starting autobeam at: ") + now_moment ().str ();
83       beam_p_ = new Beam;
84       grouping_p_ = new Rhythmic_grouping;
85
86       /* urg, copied from Beam_engraver */
87       Scalar prop = get_property ("beamslopedamping", 0);
88       if (prop.isnum_b ()) 
89         beam_p_->damping_i_ = prop;
90
91       prop = get_property ("beamquantisation", 0);
92       if (prop.isnum_b ()) 
93         beam_p_->quantisation_ = (Beam::Quantisation)(int)prop;
94  
95       // must set minVerticalAlign = = maxVerticalAlign to get sane results
96       // see input/test/beam-interstaff.ly
97       prop = get_property ("minVerticalAlign", 0);
98       if (prop.isnum_b ())
99         beam_p_->vertical_align_drul_[MIN] = prop;
100
101       prop = get_property ("maxVerticalAlign", 0);
102       if (prop.isnum_b ())
103         beam_p_->vertical_align_drul_[MAX] = prop;
104
105       announce_element (Score_element_info (beam_p_, 0));
106     }
107 }
108
109 void
110 Auto_beam_engraver::typeset_beam ()
111 {
112   if (finished_beam_p_)
113     {
114       Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_;
115       rg_C->extend (finished_grouping_p_->interval());
116       finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_);
117       typeset_element (finished_beam_p_);
118       finished_beam_p_ = 0;
119     
120       delete finished_grouping_p_;
121       finished_grouping_p_= 0;
122     }
123 }
124
125 void
126 Auto_beam_engraver::do_post_move_processing ()
127 {
128 }
129
130 void
131 Auto_beam_engraver::do_pre_move_processing ()
132 {
133   typeset_beam ();
134 }
135
136 void
137 Auto_beam_engraver::do_removal_processing ()
138 {
139   typeset_beam ();
140   if (beam_p_)
141     {
142       DOUT << "Unfinished beam";
143       unbeam ();
144     }
145 }
146
147 void
148 Auto_beam_engraver::acknowledge_element (Score_element_info info)
149 {
150   if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
151     {
152       if (beam_p_)
153         {
154           DOUT << "junking autobeam: beam encountered";
155           unbeam ();
156         }
157     }
158
159   if (beam_p_)
160     {
161       Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
162       if (!rhythmic_req)
163         return;
164
165       if (dynamic_cast<Rest *> (info.elem_l_))
166         {
167           DOUT << "junking autobeam: rest encountered";
168           unbeam ();
169           return;
170         }
171
172       Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
173       if (!stem_l)
174         return;
175
176       if (stem_l->beam_l_ && (stem_l->beam_l_ != beam_p_))
177         {
178           DOUT << "junking autobeam: beamed stem encountered";
179           unbeam ();
180           return;
181         }
182         
183
184       /*
185         now that we have last_add_mom_, perhaps we can (should) do away
186         with these individual unbeams
187        */
188       if (rhythmic_req->duration_.durlog_i_<= 2)
189         {
190           DOUT << "stem doesn't fit in beam";
191           unbeam ();
192           return;
193         }
194
195       Moment start = get_staff_info().time_C_->whole_in_measure_;
196       if (!grouping_p_->child_fit_b (start))
197         {
198           unbeam ();
199         }
200       else
201         {
202           grouping_p_->add_child (start, rhythmic_req->duration ());
203           stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
204           beam_p_->add_stem (stem_l);
205           Moment now = now_moment ();
206           last_add_mom_ = now;
207           extend_mom_ = extend_mom_ >? now + rhythmic_req->duration ();
208         }
209     }
210 }
211
212 void
213 Auto_beam_engraver::unbeam () 
214 {
215   assert (beam_p_);
216   for (int i=0; i < beam_p_->stems_.size (); i++)
217     {
218       Stem* s = beam_p_->stems_[i];
219       s->beams_i_drul_[LEFT] = 0;
220       s->beams_i_drul_[RIGHT] = 0;
221       s->mult_i_ = 0;
222       s->beam_l_ = 0;
223     }
224   
225   beam_p_->unlink ();
226   beam_p_ = 0;
227   delete grouping_p_;
228   grouping_p_ = 0;
229 }
230
231 void
232 Auto_beam_engraver::process_acknowledged ()
233 {
234   if (beam_p_)
235     {
236       Moment now = now_moment ();
237       if ((extend_mom_ < now)
238           || ((extend_mom_ == now) && (last_add_mom_ != now )))
239         {
240           DOUT << String ("junking autobeam: no stem added since: ")
241             + last_add_mom_.str ();
242           unbeam ();
243         }
244       else if (!beam_p_->stems_.size ())
245         {
246           DOUT << "junking started autobeam: no stems";
247           unbeam ();
248         }
249     }
250 }