]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur.cc
release: 0.1.56
[lilypond.git] / lily / slur.cc
1 /*
2   slur.cc -- implement  Slur
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1996, 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7 */
8
9 /*
10   TODO:
11   
12   think about crossing stems.
13   Begin and end should be treated as a Script.
14  */
15 #include "slur.hh"
16 #include "scalar.hh"
17 #include "lookup.hh"
18 #include "paper-def.hh"
19 #include "note-column.hh"
20 #include "stem.hh"
21 #include "p-col.hh"
22 #include "molecule.hh"
23 #include "debug.hh"
24 #include "boxes.hh"
25 #include "bezier.hh"
26
27 void
28 Slur::add (Note_column*n)
29 {
30   encompass_arr_.push (n);
31   add_dependency (n);
32 }
33
34 void
35 Slur::set_default_dir ()
36 {
37   dir_ = DOWN;
38   for (int i=0; i < encompass_arr_.size (); i ++) 
39     {
40       if (encompass_arr_[i]->dir_ < 0) 
41         {
42           dir_ = UP;
43           break;
44         }
45     }
46 }
47
48 void
49 Slur::do_add_processing ()
50 {
51   set_bounds (LEFT, encompass_arr_[0]);    
52   if (encompass_arr_.size () > 1)
53     set_bounds (RIGHT, encompass_arr_.top ());
54 }
55
56 void
57 Slur::do_pre_processing ()
58 {
59   // don't set directions
60 }
61
62 void
63 Slur::do_substitute_dependency (Score_elem*o, Score_elem*n)
64 {
65   int i;
66   while ((i = encompass_arr_.find_i ((Note_column*)o->item ())) >=0) 
67     {
68       if (n)
69         encompass_arr_[i] = (Note_column*)n->item ();
70       else
71         encompass_arr_.del (i);
72     }
73 }
74
75 static int 
76 Note_column_compare (Note_column *const&n1 , Note_column* const&n2)
77 {
78   return Item::left_right_compare (n1, n2);
79 }
80
81 void
82 Slur::do_post_processing ()
83 {
84   encompass_arr_.sort (Note_column_compare);
85   if (!dir_)
86     set_default_dir ();
87   Real interline_f = paper ()->interline_f ();
88   Real inter_f = interline_f / 2;
89
90   /* 
91    [OSU]: slur and tie placement
92
93    slurs:
94    * x = centre of head (upside-down: inner raakpunt stem) - d * gap
95
96    * y = length < 5ss : horizontal raakpunt + d * 0.25 ss
97      y = length >= 5ss : y next interline - d * 0.25 ss
98      --> height <= 5 length ?? we use <= 3 length, now...
99
100    * suggested gap = ss / 5;
101    */
102   // jcn: 1/5 seems so small?
103   Real gap_f = interline_f / 2; // 5;
104   
105   Drul_array<Note_column*> extrema;
106   extrema[LEFT] = encompass_arr_[0];
107   extrema[RIGHT] = encompass_arr_.top ();
108
109   Direction d=LEFT;
110   Real nw_f = paper ()->note_width ();
111  
112   do 
113     {
114       if  (extrema[d] != spanned_drul_[d]) 
115         {
116           dx_f_drul_[d] = -d 
117             *(spanned_drul_[d]->width ().length () -0.5*nw_f);
118         }
119       else if (extrema[d]->stem_l_ && !extrema[d]->stem_l_->transparent_b_) 
120         {
121           dy_f_drul_[d] = (int)rint (extrema[d]->stem_l_->height ()[dir_]);
122           /* normal slur from notehead centre to notehead centre, minus gap */
123           dx_f_drul_[d] += -d * gap_f;
124         }
125       else 
126         {
127           dy_f_drul_[d] = (int)rint (extrema[d]->head_positions_interval ()[dir_])* inter_f;
128         }
129       dy_f_drul_[d] += dir_ * interline_f;
130     }
131   while (flip(&d) != LEFT);
132 }
133
134 static Real
135 pos_correct (Real x, Real dx, Real dy)
136 {
137   /*
138     guess how much we can safely increase 'h'
139     parameter of bow without taking too large
140     or too many steps.
141     empiric computer science
142    */
143 //  return (1.0 + 2.0 * x / dx) / 4.0;
144   return 1.0;
145 }
146
147 Real
148 Slur::height_f () const
149 {
150   return 0.0;
151   
152   Real interline = paper ()->interline_f ();
153   Real notewidth = paper ()->note_width ();
154   Real internote = interline / 2;
155
156   /*
157    having the correct (i.e. exactly the same as the ps stuff)
158    x,y coordinates is essential.
159    getting them is quite a mess, currently.
160    */
161
162   Stem* left_stem =encompass_arr_[0]->stem_l_; 
163   Real left_x = left_stem->hpos_f ();
164   // ugh, do bow corrections (see brew_mol)
165   left_x += dx_f_drul_[LEFT] + 0.5 * notewidth;
166
167 //  Real left_y = left_stem->dir_ == dir_ ? left_stem->stem_end_f () + dir_
168 //    : left_stem->stem_begin_f () + 0.5 * dir_;
169 //  left_y *= internote;
170   // ugh, do bow corrections (see brew_mol)
171 //  left_y = dy_f_drul_[LEFT];
172
173   // ugh, do bow corrections (see brew_mol)
174   Real left_y = dy_f_drul_[LEFT];
175
176   // ugh, where does this asymmetry come from?
177   if (dir_ == DOWN)
178     left_y -= dir_ * internote;
179
180   Real dx = width ().length ();
181   Real dy = (dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]);
182   Real centre_x = dx / 2;
183
184
185   // ugh, need staffheight for bow damping
186   Bezier_bow b (paper ());
187
188   if (check_debug && !monitor->silent_b ("Slur"))
189     {
190       cout << "*****************" << endl;
191       cout << "dir: " << (int)dir_ << endl;
192       cout << "dx: " << dx << endl;
193       cout << "dy: " << dy << endl;
194       cout << "centre: " << centre_x << endl;
195       for (int i = 0; i < encompass_arr_.size (); i++)
196         cout << "i: " << i << " x: " 
197             << encompass_arr_[i]->stem_l_->hpos_f () - left_x << endl;
198     }
199   Real height = 0;
200   Real dh = 0;
201   do
202     {
203       height += dh;
204       dh = 0;
205       b.calc (dx, dy, height, dir_);
206       
207       if (check_debug && !monitor->silent_b ("Slur"))
208         cout << "----" << endl;
209       for (int i = 1; i < encompass_arr_.size () - 1; i++) 
210         {
211           Stem* stem = encompass_arr_[i]->stem_l_;
212           /* 
213             set x to middle of notehead or on exact x position of stem,
214             according to slur direction
215            */
216           Real x = stem->hpos_f () - left_x + notewidth / 2;
217           if (stem->dir_ != dir_)
218             x += notewidth / 2;
219           else if (stem->dir_ == UP)
220             x += notewidth;
221           Real y = stem->dir_ == dir_ ? stem->stem_end_f ()
222             : stem->stem_begin_f () + 1.5 * dir_;
223
224           /*
225             leave a gap: slur mustn't touch head/stem
226            */
227           y += 2.5 * dir_;
228           y *= internote;
229           y -= left_y;
230
231           Real shift = dir_ * (y - b.y (x));
232
233           if (check_debug && !monitor->silent_b ("Slur"))
234             {
235               cout << "x: " << x << " (" << abs (centre_x - x) << ")" << endl;
236               cout << "y: " << y << ", curve: " << b.y (x) << endl;
237               cout << "shift: " << shift << endl;
238             }
239
240           if (shift > 0.1 * internote)
241             dh = dh >? shift * pos_correct (abs (centre_x - x), dx, dy);
242         }
243     } while (dh);
244
245   return height;
246 }
247
248 IMPLEMENT_IS_TYPE_B1(Slur,Spanner);