]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur.cc
f8142f23ee55a6a9a7c07df59385594ed3cc03ff
[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
26 void
27 Slur::add (Note_column*n)
28 {
29   encompass_arr_.push (n);
30   add_dependency (n);
31 }
32
33 void
34 Slur::set_default_dir ()
35 {
36   dir_ = DOWN;
37   for (int i=0; i < encompass_arr_.size (); i ++) 
38     {
39       if (encompass_arr_[i]->dir_ < 0) 
40         {
41           dir_ = UP;
42           break;
43         }
44     }
45 }
46
47 void
48 Slur::do_add_processing ()
49 {
50   set_bounds (LEFT, encompass_arr_[0]);    
51   if (encompass_arr_.size () > 1)
52     set_bounds (RIGHT, encompass_arr_.top ());
53 }
54
55 void
56 Slur::do_pre_processing ()
57 {
58   // don't set directions
59 }
60
61 void
62 Slur::do_substitute_dependency (Score_elem*o, Score_elem*n)
63 {
64   int i;
65   while ((i = encompass_arr_.find_i ((Note_column*)o->item ())) >=0) 
66     {
67       if (n)
68         encompass_arr_[i] = (Note_column*)n->item ();
69       else
70         encompass_arr_.del (i);
71     }
72 }
73
74 static int 
75 Note_column_compare (Note_column *const&n1 , Note_column* const&n2)
76 {
77   return Item::left_right_compare (n1, n2);
78 }
79
80 void
81 Slur::do_post_processing ()
82 {
83   encompass_arr_.sort (Note_column_compare);
84   if (!dir_)
85     set_default_dir ();
86   Real interline_f = paper ()->interline_f ();
87   Real inter_f = interline_f / 2;
88
89   /* 
90    [OSU]: slur and tie placement
91
92    slurs:
93    * x = centre of head (upside-down: inner raakpunt stem) - d * gap
94
95    * y = length < 5ss : horizontal raakpunt + d * 0.25 ss
96      y = length >= 5ss : y next interline - d * 0.25 ss
97      --> height <= 5 length ?? we use <= 3 length, now...
98
99    * suggested gap = ss / 5;
100    */
101   // jcn: 1/5 seems so small?
102   Real gap_f = interline_f / 2; // 5;
103   
104   Drul_array<Note_column*> extrema;
105   extrema[LEFT] = encompass_arr_[0];
106   extrema[RIGHT] = encompass_arr_.top ();
107
108   Direction d=LEFT;
109   Real nw_f = paper ()->note_width ();
110  
111   do 
112     {
113       if  (extrema[d] != spanned_drul_[d]) 
114         {
115           dx_f_drul_[d] = -d 
116             *(spanned_drul_[d]->width ().length () -0.5*nw_f);
117         }
118       else if (extrema[d]->stem_l_ && !extrema[d]->stem_l_->transparent_b_) 
119         {
120           dy_f_drul_[d] = (int)rint (extrema[d]->stem_l_->height ()[dir_]);
121           /* normal slur from notehead centre to notehead centre, minus gap */
122           dx_f_drul_[d] += -d * gap_f;
123         }
124       else 
125         {
126           dy_f_drul_[d] = (int)rint (extrema[d]->head_positions_interval ()[dir_])* inter_f;
127         }
128       dy_f_drul_[d] += dir_ * interline_f;
129     }
130   while (flip(&d) != LEFT);
131 }
132
133 Real
134 Slur::height_f () const
135 {
136   /*
137    rather braindead way that of adjusting slur height 
138    for heads/stems that extend beyond default slur
139    works quite good
140    */
141
142   Real interline_f = paper ()->interline_f ();
143   Real nh_f = interline_f / 2;
144   Real h = 0;
145   Real dx = width ().length ();
146   Real dy = dy_f_drul_[RIGHT] - dy_f_drul_[LEFT];
147   Stem* stem = encompass_arr_[0]->stem_l_;
148   Real lx = stem->hpos_f ();
149   Real centre = (width ().min () + width ().max ()) / 2;
150   Real ly = stem->dir_ == dir_ ? stem->stem_end_f () : stem->stem_begin_f () 
151     + dir_ * nh_f / 2;
152   for (int i = 0; i < encompass_arr_.size (); i++) 
153     {
154       Stem* stem = encompass_arr_[i]->stem_l_;
155       Real sx = abs (centre - stem->hpos_f ());
156       Real sy = stem->dir_ == dir_ ? stem->stem_end_f () 
157         : stem->stem_begin_f () + dir_ * nh_f / 2;
158       sy = dir_ * (sy - (ly + ((stem->hpos_f () - lx) / dx) * dy));
159       /*
160         uhm, correct for guess bezier curve (more if further from centre)
161         forget the cos alpha...
162        */
163       if (sy > 0)
164         h = h >? sy * (1 + 2 * sx / dx);
165     }
166   Real ratio = 1.0/3; // duh
167   /* 
168     correct h for slur ratio
169    */
170   Real staffheight = paper ()->get_var ("barsize");
171   if (h)
172     h *= ((h * interline_f) / dx ) / ratio;
173   return h;
174 }
175
176 IMPLEMENT_IS_TYPE_B1(Slur,Spanner);