]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/beam.cc
release: 0.0.73pre
[lilypond.git] / lily / beam.cc
index 87e9114caf10d9355732fe32d64c5f7a3e40361d..d4f741d78893dd82a1451ed98d0e6b8b811de791 100644 (file)
@@ -1,5 +1,20 @@
-#include "varray.hh"
+/*
+  beam.cc -- implement Beam
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
+
+  TODO
+
+  Less hairy code.  knee: ([\stem 1; c8 \stem -1; c8]
+  
+*/
 
+#include <math.h>
+
+#include "p-col.hh"
+#include "varray.hh"
 #include "proto.hh"
 #include "dimen.hh"
 #include "beam.hh"
@@ -8,7 +23,6 @@
 #include "symbol.hh"
 #include "molecule.hh"
 #include "leastsquares.hh"
-#include "p-col.hh"
 #include "stem.hh"
 #include "paper-def.hh"
 #include "lookup.hh"
 
 struct Stem_info {
     Real x;
-    Real idealy;
-    Real miny;
-    int no_beams;
+    int dir_i_;
+    Real idealy_f_;
+    Real miny_f_;
+    int beams_i_;
 
-    
     Stem_info(){}
-    Stem_info(const Stem*);
+    Stem_info(Stem const *);
 };
 
-Stem_info::Stem_info(const Stem*s)
+Stem_info::Stem_info(Stem const *s)
 {
-    x = s->hindex();
-    int dir = s->dir;
-    idealy  = max(dir*s->top, dir*s->bot);
-    miny = max(dir*s->minnote, dir*s-> maxnote);
-    assert(miny <= idealy);
-
+    x = s->hpos_f();
+    dir_i_ = s->dir_i_;
+    beams_i_ = intlog2( s->flag_i_ ) - 2;
+
+    /*
+     [todo] 
+         * get algorithm
+        * runtime
+
+     Breitkopf + H\"artel:
+         miny_f_ = interline + #beams * interbeam
+        ideal8 = 2 * interline + interbeam
+        ideal16,32,64,128 = 1.5 * interline + #beams * interbeam
+
+     * B\"arenreiter:
+         miny_f_ = interline + #beams * interbeam
+        ideal8,16 = 2 interline + #beams * interbeam
+        ideal32,64,128 = 1.5 interline + #beams * interbeam
+         
+     */
+
+    Real notehead_y = s->paper()->interline_f();
+    // huh? why do i need the / 2
+//    Real interbeam_f = s->paper()->interbeam_f();
+    Real interbeam_f = s->paper()->interbeam_f() / 2;
+           
+    /* well eh, huh?
+    idealy_f_  = dir_i_ * s->stem_start_f() + beams_i_ * interbeam_f; 
+    if ( beams_i_ < 3 )
+       idealy_f_ += 2 * interline_f;
+    else
+       idealy_f_ += 1.5 * interline_f;
+    */
+
+    idealy_f_  = dir_i_ * s->stem_end_f();
+
+    miny_f_ = dir_i_ * s->stem_start_f() + notehead_y + beams_i_ * interbeam_f;
+
+    idealy_f_ =  miny_f_ >? idealy_f_;
+//    assert(miny_f_ <= idealy_f_);
 }
 
+
 /* *************** */
 
+
 Offset
 Beam::center()const
 {
-    assert(status >= POSTCALCED);
-
     Real w=(paper()->note_width() + width().length())/2.0;
-    return Offset(w, (left_pos + w* slope)*paper()->internote());
+    return Offset(w, (left_pos + w* slope)*paper()->internote_f());
 }
 
 
@@ -58,71 +106,117 @@ Beam::Beam()
 void
 Beam::add(Stem*s)
 {
-    stems.bottom().add(s);
+    stems.push(s);
     s->add_dependency(this);
-    s->print_flag = false;
+    s->print_flag_b_ = false;
 }
 
 void
 Beam::set_default_dir()
 {
-    int dirs[2];
-    dirs[0]=0; dirs[1] =0;
-    for (iter_top(stems,i); i.ok(); i++) {
-       int d = i->get_default_dir();
-       dirs[(d+1)/2] ++;
-    }
-    dir_i_ =  (dirs[0] > dirs[1]) ? -1 : 1;
-    for (iter_top(stems,i); i.ok(); i++) {
-       i->dir = dir_i_;
+    int up = 0, down = 0;
+    int up_count = 0, down_count = 0;
+
+    for (int i=0; i <stems.size(); i++) {
+       Stem *sl = stems[i];
+       int cur_down = sl->get_center_distance_from_top();
+       int cur_up = sl->get_center_distance_from_bottom();
+       if (cur_down) {
+           down += cur_down;
+           down_count++;
+       }
+       if (cur_up) {
+           up += cur_up;
+           up_count++;
+       }
     }
+    if (!down)
+       down_count = 1;
+    if (!up)
+       up_count = 1;
+
+    // the following relation is equal to
+    //        up / up_count > down / down_count
+    dir_i_ = (up * down_count > down * up_count) ? 1 : -1;
+
+   for (int i=0; i <stems.size(); i++) {
+       Stem *sl = stems[i];
+       sl->dir_i_ = dir_i_;
+   }
 }
 
 /*
   should use minimum energy formulation (cf linespacing)
-  */
+
+  [todo]
+  the y of the (start) of the beam should be quantisized,
+  so that no stafflines appear just in between two beam-flags
+
+*/
 void
 Beam::solve_slope()
 {
     Array<Stem_info> sinfo;
-    for (iter_top(stems,i); i.ok(); i++) {
+    for (int j=0; j <stems.size(); j++) {
+       Stem *i = stems[j];
+
        i->set_default_extents();
+       if (i->invisible_b())
+           continue;
+       
        Stem_info info(i);
        sinfo.push(info);
     }
-    Real leftx = sinfo[0].x;
-    Least_squares l;
-    for (int i=0; i < sinfo.size(); i++) {
-       sinfo[i].x -= leftx;
-       l.input.push(Offset(sinfo[i].x, sinfo[i].idealy));
-    }
+    if (! sinfo.size() )
+       slope = left_pos = 0;
+    else if (sinfo.size() == 1) {
+       slope = 0;
+       left_pos = sinfo[0].idealy_f_;
+    } else {
+       
+       Real leftx = sinfo[0].x;
+       Least_squares l;
+       for (int i=0; i < sinfo.size(); i++) {
+           sinfo[i].x -= leftx;
+           l.input.push(Offset(sinfo[i].x, sinfo[i].idealy_f_));
+       }
 
-    l.minimise(slope, left_pos);
+       l.minimise(slope, left_pos);
+    }
+    
     Real dy = 0.0;
     for (int i=0; i < sinfo.size(); i++) {
        Real y = sinfo[i].x * slope + left_pos;
-       Real my = sinfo[i].miny;
+       Real my = sinfo[i].miny_f_;
 
        if (my - y > dy)
            dy = my -y; 
     }
     left_pos += dy;
     left_pos *= dir_i_;    
+
     slope *= dir_i_;
 
-                               // URG
-    Real sl = slope*paper()->internote();
+    /*
+      This neat trick is by Werner Lemberg, damped = tanh(slope) corresponds
+      with some tables in [Wanske]
+     */
+    slope = 0.6 * tanh(slope);  
+
+                               // ugh
+    Real sl = slope*paper()->internote_f();
     paper()->lookup_l()->beam(sl, 20 PT);
-    slope = sl /paper()->internote();
+    slope = sl /paper()->internote_f();
 }
 
 void
 Beam::set_stemlens()
 {
-    iter_top(stems,s);
-    Real x0 = s->hindex();    
-    for (; s.ok() ; s++) {
-       Real x =  s->hindex()-x0;
+    Real x0 = stems[0]->hpos_f();    
+    for (int j=0; j <stems.size(); j++) {
+       Stem *s = stems[j];
+
+       Real x =  s->hpos_f()-x0;
        s->set_stemend(left_pos + slope * x);   
     }
 }
@@ -131,6 +225,11 @@ Beam::set_stemlens()
 void
 Beam::do_post_processing()
 {
+    if ( stems.size() < 2) {
+       warning("Beam with less than 2 stems");
+       transparent_b_ = true;
+       return ;
+    }
     solve_slope();    
     set_stemlens();
 }
@@ -146,10 +245,11 @@ Beam::set_grouping(Rhythmic_grouping def, Rhythmic_grouping cur)
 
     Array<int> b;
     {
-       iter_top(stems,s);
        Array<int> flags;
-       for (; s.ok(); s++) {
-           int f = intlog2(abs(s->flag))-2;
+       for (int j=0; j <stems.size(); j++) {
+           Stem *s = stems[j];
+
+           int f = intlog2(abs(s->flag_i_))-2;
            assert(f>0);
            flags.push(f);
        }
@@ -160,29 +260,16 @@ Beam::set_grouping(Rhythmic_grouping def, Rhythmic_grouping cur)
        assert(stems.size() == b.size()/2);
     }
 
-    iter_top(stems,s);
-    for (int i=0; i < b.size() && s.ok(); i+=2, s++) {
-       s->beams_left = b[i];
-       s->beams_right = b[i+1];
+    for (int j=0, i=0; i < b.size() && j <stems.size(); i+= 2, j++) {
+       Stem *s = stems[j];
+       s->beams_left_i_ = b[i];
+       s->beams_right_i_ = b[i+1];
     }
 }
 
-
-// todo.
-Spanner *
-Beam::do_break_at( PCol *, PCol *) const
-{
-    Beam *beam_p= new Beam(*this);
-    
-    return beam_p;
-}
-
 void
 Beam::do_pre_processing()
 {
-    left  = (*stems.top())   ->pcol_l_;
-    right = (*stems.bottom())->pcol_l_;    
-    assert(stems.size()>1);
     if (!dir_i_)
        set_default_dir();
 
@@ -190,11 +277,10 @@ Beam::do_pre_processing()
 
 
 Interval
-Beam::width() const
+Beam::do_width() const
 {
-    Beam * me = (Beam*) this;  // ugh
-    return Interval( (*me->stems.top()) ->hindex(),
-                    (*me->stems.bottom()) ->hindex() );
+    return Interval( stems[0]->hpos_f(),
+                    stems.top()->hpos_f() );
 }
 
 /*
@@ -203,11 +289,12 @@ Beam::width() const
 Molecule
 Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const
 {
-    assert( !next || next->hindex() > here->hindex()  );
-    assert( !prev || prev->hindex() < here->hindex()  );
-    Real dy=paper()->internote()*2;
+    assert( !next || next->hpos_f() > here->hpos_f()  );
+    assert( !prev || prev->hpos_f() < here->hpos_f()  );
+//    Real dy=paper()->internote_f()*2;
+    Real dy = paper()->interbeam_f();
     Real stemdx = paper()->rule_thickness();
-    Real sl = slope*paper()->internote();
+    Real sl = slope*paper()->internote_f();
     paper()->lookup_l()->beam(sl, 20 PT);
 
     Molecule leftbeams;
@@ -215,9 +302,9 @@ Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const
 
     /* half beams extending to the left. */
     if (prev) {
-       int lhalfs= lhalfs = here->beams_left - prev->beams_right ;
-       int lwholebeams= here->beams_left <? prev->beams_right ;
-       Real w = (here->hindex() - prev->hindex())/4;
+       int lhalfs= lhalfs = here->beams_left_i_ - prev->beams_right_i_ ;
+       int lwholebeams= here->beams_left_i_ <? prev->beams_right_i_ ;
+       Real w = (here->hpos_f() - prev->hpos_f())/4;
        Symbol dummy;
        Atom a(dummy);
        if (lhalfs)             // generates warnings if not
@@ -225,22 +312,22 @@ Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const
        a.translate(Offset (-w, -w * sl));
        for (int j = 0; j  < lhalfs; j++) {
            Atom b(a);
-           b.translate(Offset(0, -dir_i_ * dy * (lwholebeams+j)));
+           b.translate_y( -dir_i_ * dy * (lwholebeams+j));
            leftbeams.add( b );
        }
     }
        
     if (next){
-       int rhalfs = here->beams_right - next->beams_left;
-       int rwholebeams = here->beams_right <? next->beams_left
+       int rhalfs = here->beams_right_i_ - next->beams_left_i_;
+       int rwholebeams = here->beams_right_i_ <? next->beams_left_i_
 
-       Real w = next->hindex() - here->hindex();
+       Real w = next->hpos_f() - here->hpos_f();
        Atom a = paper()->lookup_l()->beam(sl, w + stemdx);
        
        int j = 0;
        for (; j  < rwholebeams; j++) {
            Atom b(a);
-           b.translate(Offset(0, -dir_i_ * dy * j));
+           b.translate_y( -dir_i_ * dy * j);
            rightbeams.add( b ); 
        }
 
@@ -250,7 +337,7 @@ Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const
        
        for (; j  < rwholebeams + rhalfs; j++) {
            Atom b(a);
-           b.translate(Offset(0, -dir_i_ * dy * j));
+           b.translate_y( -dir_i_ * dy * j);
            rightbeams.add(b ); 
        }
        
@@ -261,26 +348,31 @@ Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const
 
 
 Molecule*
-Beam::brew_molecule_p() const return out;
+Beam::brew_molecule_p() const 
 {
-    Real inter=paper()->internote();
-    out = new Molecule;
-    Real x0 = stems.top()->hindex();
-    
-    for (iter_top(stems,i); i.ok(); i++) {
-       PCursor<Stem*> p(i-1);
-       PCursor<Stem*> n(i+1);
-       Stem * prev = p.ok() ? p.ptr() : 0;
-       Stem * next = n.ok() ? n.ptr() : 0;
+    Molecule *mol_p = new Molecule;
+    // huh? inter-what
+//    Real inter_f = paper()->interbeam_f();
+    Real inter_f = paper()->internote_f();
+    Real x0 = stems[0]->hpos_f();
+    for (int j=0; j <stems.size(); j++) {
+       Stem *i = stems[j];
+       Stem * prev = (j > 0)? stems[j-1] : 0;
+       Stem * next = (j < stems.size()-1) ? stems[j+1] :0;
 
        Molecule sb = stem_beams(i, next, prev);
-       Real  x = i->hindex()-x0;
-       sb.translate(Offset(x, (x * slope  + left_pos)* inter));
-       out->add(sb);
+       Real  x = i->hpos_f()-x0;
+       sb.translate(Offset(x, (x * slope  + left_pos)* inter_f));
+       mol_p->add(sb);
     }
-    out->translate(Offset(x0 - left->hpos,0));
+    mol_p->translate_x(x0 - left_col_l_->hpos);
+    return mol_p;
 }
 
+IMPLEMENT_STATIC_NAME(Beam);
+IMPLEMENT_IS_TYPE_B1(Beam, Spanner);
+
 void
 Beam::do_print()const
 {
@@ -289,8 +381,13 @@ Beam::do_print()const
     Spanner::print();
 #endif
 }
-
-Beam::~Beam()
+/*
+  duh. The stem is not a dependency but a dependent
+ */
+void
+Beam::do_substitute_dependency(Score_elem*o,Score_elem*n)
 {
-
+    if (o->is_type_b( Stem::static_name() )) {
+       stems.substitute( (Stem*)o->item(),  n?(Stem*) n->item():0);
+    }
 }