]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur.cc
3e8cbdfe26d5eb40667d4bd5a07fc1bb4297f792
[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     Jan Nieuwenhuizen <jan@digicash.com>
8 */
9
10 /*
11   [TODO]
12     * begin and end should be treated as a Script.
13     * damping
14     * slur from notehead to stemend: c''()b''
15  */
16
17 #include "slur.hh"
18 #include "scalar.hh"
19 #include "lookup.hh"
20 #include "paper-def.hh"
21 #include "note-column.hh"
22 #include "stem.hh"
23 #include "p-col.hh"
24 #include "molecule.hh"
25 #include "debug.hh"
26 #include "boxes.hh"
27 #include "bezier.hh"
28
29 //IMPLEMENT_IS_TYPE_B1(Slur,Spanner);
30 IMPLEMENT_IS_TYPE_B1(Slur,Bow);
31
32 Slur::Slur ()
33 {
34 }
35
36 void
37 Slur::add (Note_column*n)
38 {
39   encompass_arr_.push (n);
40   add_dependency (n);
41 }
42
43 void
44 Slur::set_default_dir ()
45 {
46   dir_ = DOWN;
47   for (int i=0; i < encompass_arr_.size (); i ++) 
48     {
49       if (encompass_arr_[i]->dir_ < 0) 
50         {
51           dir_ = UP;
52           break;
53         }
54     }
55 }
56
57 void
58 Slur::do_add_processing ()
59 {
60   set_bounds (LEFT, encompass_arr_[0]);    
61   if (encompass_arr_.size () > 1)
62     set_bounds (RIGHT, encompass_arr_.top ());
63 }
64
65 void
66 Slur::do_pre_processing ()
67 {
68   // don't set directions
69 }
70
71 void
72 Slur::do_substitute_dependency (Score_elem*o, Score_elem*n)
73 {
74   int i;
75   while ((i = encompass_arr_.find_i ((Note_column*)o->item ())) >=0) 
76     {
77       if (n)
78         encompass_arr_[i] = (Note_column*)n->item ();
79       else
80         encompass_arr_.del (i);
81     }
82 }
83
84 static int 
85 Note_column_compare (Note_column *const&n1 , Note_column* const&n2)
86 {
87   return Item::left_right_compare (n1, n2);
88 }
89
90 void
91 Slur::do_post_processing ()
92 {
93   encompass_arr_.sort (Note_column_compare);
94   if (!dir_)
95     set_default_dir ();
96   Real interline_f = paper ()->interline_f ();
97   Real inter_f = interline_f / 2;
98
99   /* 
100    [OSU]: slur and tie placement
101
102    slurs:
103    * x = centre of head (upside-down: inner raakpunt stem) - d * gap
104
105    * y = length < 5ss : horizontal raakpunt + d * 0.25 ss
106      y = length >= 5ss : y next interline - d * 0.25 ss
107      --> height <= 5 length ?? we use <= 3 length, now...
108
109    * suggested gap = ss / 5;
110    */
111   // jcn: 1/5 seems so small?
112   Real gap_f = interline_f / 2; // 5;
113   
114   Drul_array<Note_column*> extrema;
115   extrema[LEFT] = encompass_arr_[0];
116   extrema[RIGHT] = encompass_arr_.top ();
117
118   Direction d=LEFT;
119   Real nw_f = paper ()->note_width ();
120  
121   do 
122     {
123       if (extrema[d] != spanned_drul_[d]) 
124         {
125           dx_f_drul_[d] = -d 
126             *(spanned_drul_[d]->width ().length () -0.5*nw_f);
127           Direction u = d;
128           flip(&u);
129           if ((extrema[u] == spanned_drul_[u]) && extrema[u]->stem_l_)
130             {
131               dy_f_drul_[d] = extrema[u]->stem_l_->height ()[dir_];
132               dy_f_drul_[u] = extrema[u]->stem_l_->height ()[dir_];
133             }
134         }
135       else if (extrema[d]->stem_l_ && !extrema[d]->stem_l_->transparent_b_) 
136         {
137           dy_f_drul_[d] = (int)rint (extrema[d]->stem_l_->height ()[dir_]);
138           dx_f_drul_[d] += 0.5 * nw_f - d * gap_f;
139           if (dir_ == extrema[d]->stem_l_->dir_)
140             {
141               if (dir_ == d)
142                 dx_f_drul_[d] += 0.5 * (dir_ * d) * d * nw_f;
143               else
144                 dx_f_drul_[d] += 0.25 * (dir_ * d) * d * nw_f;
145             }
146         }
147       else 
148         {
149           dy_f_drul_[d] = (int)rint (extrema[d]->head_positions_interval ()
150             [dir_])* inter_f;
151         }
152       dy_f_drul_[d] += dir_ * interline_f;
153     }
154   while (flip(&d) != LEFT);
155 }
156
157 Array<Offset>
158 Slur::get_encompass_offset_arr () const
159 {
160   Real interline = paper ()->interline_f ();
161   Real notewidth = paper ()->note_width ();
162   Real internote = interline / 2;
163
164   Stem* left_stem = encompass_arr_[0]->stem_l_;
165   Real left_x = left_stem->hpos_f ();
166   left_x += dx_f_drul_[LEFT];
167
168   Real left_y = dy_f_drul_[LEFT];
169
170   Real dx = width ().length ();
171   dx += (dx_f_drul_[RIGHT] - dx_f_drul_[LEFT]);
172   dx = dx <? 1000;
173   dx = dx >? 2 * interline;
174
175   Real dy = (dy_f_drul_[RIGHT] - dy_f_drul_[LEFT]);
176   if (abs (dy) > 1000)
177     dy = sign (dy) * 1000;
178
179   int first = 1;
180   int last = encompass_arr_.size () - 1;
181   if (encompass_arr_[0] != spanned_drul_[LEFT])
182     {
183       first = 0;
184       left_x = spanned_drul_[LEFT]->width ().length ();
185       left_x -= 2 * notewidth;
186 //      left_y = 0;
187       Stem* stem = encompass_arr_[last]->stem_l_;
188       left_y = stem->dir_ == dir_ ? stem->stem_end_f ()
189         : stem->stem_begin_f () + 0.5 * dir_;
190       dy = 0;
191     }
192   if (encompass_arr_.top () != spanned_drul_[RIGHT])
193     {
194       last += 1;
195       dy = 0;
196     }
197
198   Array<Offset> notes;
199   notes.push (Offset (0,0));
200   for (int i = first; i < last; i++)
201     {
202       Stem* stem = encompass_arr_[i]->stem_l_;
203       /* 
204         set x to middle of notehead or on exact x position of stem,
205         according to slur direction
206            */
207       Real x = stem->hpos_f ();
208
209       if (stem->dir_ != dir_)
210         x += 0.5 * notewidth;
211       else if (stem->dir_ == UP)
212         x += 1.0 * notewidth;
213
214       x -= left_x;
215
216       Real y = stem->dir_ == dir_ ? stem->stem_end_f ()
217         : stem->stem_begin_f () + 0.5 * dir_;
218
219       /*
220         leave a gap: slur mustn't touch head/stem
221        */
222       y += 2.5 * dir_;
223
224       // ugh: huh?
225       if (dir_ == DOWN)
226         y += 1.5 * dir_;
227
228       y *= internote;
229       y -= left_y;
230
231       notes.push (Offset (x, y));
232     }
233
234   notes.push (Offset (dx, dy));
235
236   return notes;
237 }
238