]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur.cc
release: 0.1.55
[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   Real interline = paper ()->interline_f ();
151   Real notewidth = paper ()->note_width ();
152   Real internote = interline / 2;
153
154   /*
155    having the correct (i.e. exactly the same as the ps stuff)
156    x,y coordinates is essential.
157    getting them is quite a mess, currently.
158    */
159
160   Stem* left_stem =encompass_arr_[0]->stem_l_; 
161   Real left_x = left_stem->hpos_f ();
162   // ugh, do bow corrections (see brew_mol)
163   left_x += dx_f_drul_[LEFT] + 0.5 * notewidth;
164
165 //  Real left_y = left_stem->dir_ == dir_ ? left_stem->stem_end_f () + dir_
166 //    : left_stem->stem_begin_f () + 0.5 * dir_;
167 //  left_y *= internote;
168   // ugh, do bow corrections (see brew_mol)
169 //  left_y = dy_f_drul_[LEFT];
170
171   // ugh, do bow corrections (see brew_mol)
172   Real left_y = dy_f_drul_[LEFT];
173
174   // ugh, where does this asymmetry come from?
175   if (dir_ == DOWN)
176     left_y -= dir_ * internote;
177
178   Real dx = width ().length ();
179   Real dy = (dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]);
180   Real centre_x = dx / 2;
181
182
183   // ugh, need staffheight for bow damping
184   Bezier_bow b (paper ());
185
186   if (check_debug && !monitor->silent_b ("Slur"))
187     {
188       cout << "*****************" << endl;
189       cout << "dir: " << (int)dir_ << endl;
190       cout << "dx: " << dx << endl;
191       cout << "dy: " << dy << endl;
192       cout << "centre: " << centre_x << endl;
193       for (int i = 0; i < encompass_arr_.size (); i++)
194         cout << "i: " << i << " x: " 
195             << encompass_arr_[i]->stem_l_->hpos_f () - left_x << endl;
196     }
197   Real height = 0;
198   Real dh = 0;
199   do
200     {
201       height += dh;
202       dh = 0;
203       b.calc (dx, dy, height, dir_);
204       
205       if (check_debug && !monitor->silent_b ("Slur"))
206         cout << "----" << endl;
207       for (int i = 1; i < encompass_arr_.size () - 1; i++) 
208         {
209           Stem* stem = encompass_arr_[i]->stem_l_;
210           /* 
211             set x to middle of notehead or on exact x position of stem,
212             according to slur direction
213            */
214           Real x = stem->hpos_f () - left_x + notewidth / 2;
215           if (stem->dir_ != dir_)
216             x += notewidth / 2;
217           else if (stem->dir_ == UP)
218             x += notewidth;
219           Real y = stem->dir_ == dir_ ? stem->stem_end_f ()
220             : stem->stem_begin_f () + 1.5 * dir_;
221
222           /*
223             leave a gap: slur mustn't touch head/stem
224            */
225           y += 2.5 * dir_;
226           y *= internote;
227           y -= left_y;
228
229           Real shift = dir_ * (y - b.y (x));
230
231           if (check_debug && !monitor->silent_b ("Slur"))
232             {
233               cout << "x: " << x << " (" << abs (centre_x - x) << ")" << endl;
234               cout << "y: " << y << ", curve: " << b.y (x) << endl;
235               cout << "shift: " << shift << endl;
236             }
237
238           if (shift > 0.1 * internote)
239             dh = dh >? shift * pos_correct (abs (centre_x - x), dx, dy);
240         }
241     } while (dh);
242
243   return height;
244 }
245
246 IMPLEMENT_IS_TYPE_B1(Slur,Spanner);