]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur.cc
release: 0.1.63
[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--1998, 1998 Han-Wen Nienhuys <hanwen@stack.nl>
7     Jan Nieuwenhuizen <jan@digicash.com>
8 */
9
10 /*
11   [TODO]
12     * URG: share code with tie
13     * begin and end should be treated as a Script.
14     * damping
15     * slur from notehead to stemend: c''()b''
16  */
17
18 #include "slur.hh"
19 #include "scalar.hh"
20 #include "lookup.hh"
21 #include "paper-def.hh"
22 #include "note-column.hh"
23 #include "stem.hh"
24 #include "p-col.hh"
25 #include "molecule.hh"
26 #include "debug.hh"
27 #include "boxes.hh"
28 #include "bezier.hh"
29 #include "encompass-info.hh"
30 #include "main.hh"
31
32 IMPLEMENT_IS_TYPE_B1(Slur,Bow);
33
34 Slur::Slur ()
35 {
36 }
37
38 void
39 Slur::add (Note_column*n)
40 {
41   encompass_arr_.push (n);
42   add_dependency (n);
43 }
44
45 void
46 Slur::set_default_dir ()
47 {
48   dir_ = DOWN;
49   for (int i=0; i < encompass_arr_.size (); i ++) 
50     {
51       if (encompass_arr_[i]->dir_ < 0) 
52         {
53           dir_ = UP;
54           break;
55         }
56     }
57 }
58
59 void
60 Slur::do_add_processing ()
61 {
62   set_bounds (LEFT, encompass_arr_[0]);    
63   if (encompass_arr_.size () > 1)
64     set_bounds (RIGHT, encompass_arr_.top ());
65 }
66
67 void
68 Slur::do_pre_processing ()
69 {
70   // don't set directions
71 }
72
73 void
74 Slur::do_substitute_dependency (Score_elem*o, Score_elem*n)
75 {
76   int i;
77   while ((i = encompass_arr_.find_i ((Note_column*)o->item ())) >=0) 
78     {
79       if (n)
80         encompass_arr_[i] = (Note_column*)n->item ();
81       else
82         encompass_arr_.del (i);
83     }
84 }
85
86 static int 
87 Note_column_compare (Note_column *const&n1 , Note_column* const&n2)
88 {
89   return Item::left_right_compare (n1, n2);
90 }
91
92 void
93 Slur::do_post_processing ()
94 {
95   encompass_arr_.sort (Note_column_compare);
96   if (!dir_)
97     set_default_dir ();
98
99   Real interline_f = paper ()->interline_f ();
100   Real internote_f = interline_f / 2;
101   Real notewidth_f = paper ()->note_width ();
102   Real slur_min = paper ()->get_var ("slur_x_minimum");
103
104   /* 
105    [OSU]: slur and tie placement
106
107    slurs:
108    * x = centre of head (upside-down: inner raakpunt stem) - d * gap
109
110    * y = length < 5ss : horizontal raakpunt + d * 0.25 ss
111      y = length >= 5ss : y next interline - d * 0.25 ss
112      --> height <= 5 length ?? we use <= 3 length, now...
113    */
114   
115   Real gap_f = paper ()->get_var ("slur_x_gap");
116
117   Drul_array<Note_column*> extrema;
118   extrema[LEFT] = encompass_arr_[0];
119   extrema[RIGHT] = encompass_arr_.top ();
120
121   Direction d=LEFT;
122  
123   do 
124     {
125       /*
126         broken slur
127        */
128       if (extrema[d] != spanned_drul_[d]) 
129         {
130           // ugh -- check if needed
131           dx_f_drul_[d] = -d 
132             *(spanned_drul_[d]->width ().length () - 0.5 * notewidth_f);
133
134           // prebreak
135           if (d == RIGHT)
136             {
137               dx_f_drul_[LEFT] = spanned_drul_[LEFT]->width ().length ();
138
139               // urg -- check if needed
140               if (encompass_arr_.size () > 1)
141                 dx_f_drul_[RIGHT] += notewidth_f;
142             }
143         }
144       /*
145         normal slur
146        */
147       else if (extrema[d]->stem_l_ && !extrema[d]->stem_l_->transparent_b_) 
148         {
149           Real notewidth_f = extrema[d]->width ().length ();
150           dy_f_drul_[d] = (int)rint (extrema[d]->stem_l_->height ()[dir_]);
151           dx_f_drul_[d] += 0.5 * notewidth_f - d * gap_f;
152           if (dir_ == extrema[d]->stem_l_->dir_)
153             {
154               if (dir_ == d)
155                 dx_f_drul_[d] += 0.5 * (dir_ * d) * d * notewidth_f;
156               else
157                 dx_f_drul_[d] += 0.25 * (dir_ * d) * d * notewidth_f;
158             }
159         }
160       else 
161         {
162           Real notewidth_f = extrema[d]->width ().length ();
163           dy_f_drul_[d] = (int)rint (extrema[d]->head_positions_interval ()
164             [dir_]) * internote_f;
165           dx_f_drul_[d] += 0.5 * notewidth_f - d * gap_f;
166         }
167       dy_f_drul_[d] += dir_ * interline_f;
168       if (extrema[d]->stem_l_ && (dir_ == extrema[d]->stem_l_->dir_))
169         dy_f_drul_[d] -= dir_ * internote_f;
170     }
171   while (flip(&d) != LEFT);
172
173   // now that both are set, do dependent
174   do 
175     {
176       /*
177         broken slur
178        */
179       if (extrema[d] != spanned_drul_[d]) 
180         {
181           Direction u = d;
182           flip(&u);
183
184           // postbreak
185           if (d == LEFT)
186             dy_f_drul_[u] += dir_ * internote_f;
187
188           dy_f_drul_[d] = dy_f_drul_[(Direction)-d];
189
190           // pre and post
191           if (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT] < slur_min)
192             {
193               dx_f_drul_[d] -= d * slur_min 
194                 - (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT]);
195               dx_f_drul_[d] = dx_f_drul_[(Direction)-d] + d * slur_min;
196             }
197         }
198      }
199   while (flip(&d) != LEFT);
200
201   /*
202     Avoid too steep slurs.
203       * slur from notehead to stemend: c''()b''
204    */
205   Real damp_f = paper ()->get_var ("slur_slope_damping");
206   Offset d_off = Offset (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT],
207     dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]);
208   d_off.x () += width ().length ();
209
210   Real ratio_f = abs (d_off.y () / d_off.x ());
211   if (ratio_f > damp_f)
212     dy_f_drul_[(Direction)(- dir_ * sign (d_off.y ()))] -=
213       dir_ * (damp_f - ratio_f) * d_off.x ();
214 }
215
216 Array<Offset>
217 Slur::get_encompass_offset_arr () const
218 {
219   Offset left = Offset (dx_f_drul_[LEFT], dy_f_drul_[LEFT]);
220   left.x () += encompass_arr_[0]->stem_l_->hpos_f ();
221
222   Offset d = Offset (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT],
223     dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]);
224   d.x () += width ().length ();
225
226   int first = 1;
227   int last = encompass_arr_.size () - 1;
228
229   // prebreak
230   if (encompass_arr_[0] != spanned_drul_[LEFT])
231     first--;
232
233   // postbreak
234   if (encompass_arr_.top () != spanned_drul_[RIGHT])
235     last++;
236
237 #define RESIZE_ICE
238 #ifndef RESIZE_ICE
239
240   Array<Offset> notes;
241   notes.push (Offset (0,0));
242
243   for (int i = first; i < last; i++)
244     {
245       Encompass_info info (encompass_arr_[i], dir_);
246       notes.push (info.o_ - left);
247     }
248   notes.push (d);
249
250 #else
251
252   int n = last - first + 2;
253   Array<Offset> notes (n);
254   notes[0] = Offset (0,0);
255
256   for (int i = first; i < last; i++)
257     {
258       Encompass_info info (encompass_arr_[i], dir_);
259       notes[i - first + 1] = info.o_ - left;
260     }
261   notes[n - 1] = Offset (d);
262
263 #endif
264
265   return notes;
266 }
267