[EMAIL PROTECTED] writes:
> could anyone please explain to a dummy e.g. how to
> use lilypond's dependencies (which functions to call - when to use
> add_dependency() and for what reason ... etc.).
> 
> I'd definitely like to hack on the source, and there's still so much
> missing, but right now it's just a waste of time and it seems virtually
> impossible without comments and documentation. :-((
> 
> thank you ..
> 
> -- 

Ah! You have really been looking :-)

The idea of dependencies is the following: the properties of some
graphical objects depend on properties of other types of objects, for
example the placement of a staccato dot depends on the direction of
the stem.  This means that the stem-direction has to be calculated
before the staccato dot placement.

You can tell this from the code. (Staff_side captures the placing info
of a staccato dot. )

        staff-side.cc

        void
        Staff_side::add_support (Score_elem*i)
        {
          support_l_arr_.push (i);
          add_dependency (i);
        }

Some properties influence horizontal dimensions, so they have to be
calculated before breaking the lines.  Some properties depend on the
line breaks chosen.  So the calculation of properties like
stem-direction is grouped.  For these categories different subtypes of
Score_elem have different virtual functions called do_XXX_processing.

All the passes are listed in lily/super-elem.cc 

        /**
            for administration of what was done already
            */
        enum Score_elem_status {
          ORPHAN=0,                     // not yet added to pstaff
          VIRGIN,                       // added to pstaff
          PREBROKEN,
          PRECALCING,
          PRECALCED,            // calcs before spacing done
          SPACING,
          SPACED,
          BROKEN,
          POSTCALCING,          // busy calculating. This is used to trap cyclic deps.
          POSTCALCED,           // after spacing calcs done
          BREWING,
          BREWED,
          UNLINKING,
          UNLINKED,
        };

Score_elem has the following virtuals that can be overriden

  ///executed directly after the item is added to the Paper_score
  virtual void do_add_processing();
  /// do calculations before determining horizontal spacing
  virtual void do_pre_processing();

  /// generate rods & springs
  virtual void do_space_processing ();

  virtual void do_breakable_col_processing();
  /// do calculations after determining horizontal spacing
  virtual void do_post_processing();


In essence the staccato dot could also have been written as


        Staccato_dot::xxx ()
        {
                Direction d = this->stem_pointer->get_direction ();
                /*
                        currently code would look like

                        Direction d = this->stem_pointer->direction;
                */
        }

and use method calls instead.  The reason that this can't be done is
linebreaking: when the score is broken in to lines, a lot of pointers
get changed: if a slur is broken in two pieces, then pointers to the
slur should be changed into pointers to the broken pieces.  For this
kind of trickery, you have do_substitute_dependency.  It is a derived
call that should make sure that the pointers inside the definition of
(in this example) Staccato_dot are changed:

        void
        Staff_side::do_substitute_dependency (Score_elem*o, Score_elem*n)
        {
          support_l_arr_.unordered_substitute (o,n);
        }

or (more pseudo codish)


        Staccato_dot::do_substitute_dependency (Score_elem* old_pointer, Score_elem* 
new_pointer)
        {
                if (this->stem_pointer == old_pointer)
                        {
                                this->stem_pointer = (Stem*) new_pointer;
                        }
        }


The real work for the dependencies is done in score-elem.cc:

        void
        Score_elem::calcalute_dependencies (int final, int busy,
                                            Score_elem_method_pointer funcptr)
        {
          if (status_i_ >= final)
            return;

          assert (status_i_!= busy);
          status_i_= busy;

          for (int i=0; i < dependency_size(); i++)
            dependency (i)->calcalute_dependencies (final, busy, funcptr);

          Link_array<Score_elem> extra (get_extra_dependencies());
          for (int i=0; i < extra.size(); i++)
            extra[i]->calcalute_dependencies (final, busy, funcptr);

          invalidate_cache (X_AXIS);
          invalidate_cache (Y_AXIS);

          (this->*funcptr)(); /* this is the call to do_XXX_processing*/

          status_i_= final;
        }


The order for different passes comes from p-score.cc

        void
        Paper_score::process ()
        {
          clean_cols ();
          print ();
          *mlog << _ ("Preprocessing elements...") << " " << flush;
          super_elem_l_->breakable_col_processing ();
          super_elem_l_->pre_processing ();

          *mlog << '\n' << _ ("Calculating column positions...") << " " << flush;
          super_elem_l_->space_processing ();
          calc_breaking ();
          *mlog << _ ("Postprocessing elements...") << " " << endl;
          super_elem_l_->post_processing ();
          tex_output ();
        }


Does this satisfy your curiosity?  I will be writing a paper on this
system RSN, but I'd be glad to explain more.  It helps me with writing
my paper :-)


-- 

Han-Wen Nienhuys, [EMAIL PROTECTED] ** GNU LilyPond - The Music Typesetter 
      http://www.cs.uu.nl/people/hanwen/lilypond/index.html 

Reply via email to