]> git.donarmstrong.com Git - lilypond.git/commitdiff
lilypond-0.0.9
authorfred <fred>
Mon, 11 Nov 1996 23:48:36 +0000 (23:48 +0000)
committerfred <fred>
Mon, 11 Nov 1996 23:48:36 +0000 (23:48 +0000)
hdr/linespace.hh [new file with mode: 0644]
hdr/pscore.hh [new file with mode: 0644]
src/break.cc [new file with mode: 0644]
src/note.cc [new file with mode: 0644]

diff --git a/hdr/linespace.hh b/hdr/linespace.hh
new file mode 100644 (file)
index 0000000..5470450
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef PROBLEM_HH
+#define PROBLEM_HH
+
+#include "glob.hh"
+#include "plist.hh"
+#include "vray.hh"
+#include "pcol.hh"
+#include "matrix.hh"
+
+/// helper struct for #Spacing_problem#
+struct Colinfo {
+    const PCol *pcol_;
+    bool fixed;
+    Real fixpos;
+    Colinfo();
+    void print() const;
+    Real minright() const { return pcol_->width().max; }
+    Real minleft() const { return -pcol_->width().min; }
+};
+
+
+/// spacing for one line.
+class Spacing_problem {
+    svec<const Idealspacing*> ideals;
+    svec<Colinfo> cols;
+
+    /// the index of #c# in #cols#
+    int col_id(const PCol *c) const;
+
+    /// generate an (nonoptimal) solution
+    Vector find_initial_solution() const;
+
+    /// check if problem is too tight
+    bool check_feasible() const;
+    /// does #this# contain the column #w#? 
+    bool contains(const PCol *w);
+
+    /// make the energy function
+    void make_matrices(Matrix &quad, Vector &lin,Real&) const;
+
+    /// generate the LP constraints
+    void make_constraints(Mixed_qp& lp) const;
+
+public:
+    /// solve the spacing problem
+    svec<Real> solve() const;
+    /**
+    return the column positions, and the energy (last element)
+    */
+    /// add a idealspacing to the problem.
+    void add_ideal(const Idealspacing *i);
+    
+    /**
+    One pair of columns can have no, one or more idealspacings,
+    since they can be "summed" if the columns to which #i# refers are
+    not in this problem, the spacing is ignored.
+    */
+    
+    
+    /// add a col to the problem
+    void add_column(const PCol *, bool fixed=false, Real fixpos=0.0);
+    /** columns have to be added left to right. The column contains
+      info on it's minimum width.
+    */
+
+
+    bool check_constraints(Vector v) const;
+
+    Vector try_initial_solution() const;
+    void OK() const;
+    void print() const;
+    void print_ideal(const Idealspacing*)const;
+};
+
+
+/** the problem, given by the columns (which include constraints) and
+    intercolumn spacing. The problem is:
+
+    Generate a spacing which
+    \begin{itemize}
+    \item
+    Satisfies spacing constraints (notes can't be printed through each other)
+    \item
+    Looks good, ie tries to conform to  an ideal spacing as much as possible.
+    \end{itemize}
+    This is converted by regarding idealspacing as "springs" attached
+    to columns. The equilibrium of one spring is the ideal
+    distance. The columns have a size, this imposes "hard" constraints
+    on the distances. This transforms the problem into a quadratic
+    programming problem with linear constraints.
+
+    The quality is given by the total potential energy in the
+    springs. The lower the energy, the better the configuration.
+*/
+#endif
diff --git a/hdr/pscore.hh b/hdr/pscore.hh
new file mode 100644 (file)
index 0000000..70e783c
--- /dev/null
@@ -0,0 +1,102 @@
+// the breaking problem for a score.
+
+#ifndef PSCORE_HH
+#define PSCORE_HH
+
+
+#include "vray.hh"
+#include "pcol.hh"
+#include "pstaff.hh"
+
+/// all stuff which goes onto paper
+struct PScore {
+    Paperdef *paper_;          // indirection.
+    
+    /// the columns, ordered left to right
+    PointerList<PCol *> cols;
+
+    /// the idealspacings, no particular order
+    PointerList<Idealspacing*> suz;
+
+    /// the staffs ordered top to bottom
+    PointerList<PStaff*> staffs;
+
+    /// all symbols in score. No particular order.
+    PointerList<Item*> its;
+
+    /// if broken, the different lines
+    PointerList<Line_of_score*> lines;
+
+    /// crescs etc; no particular order
+    PointerList<Spanner *> spanners;
+
+    /****************************************************************/
+
+    svec<Item*> select_items(PStaff*, PCol*);
+
+    /// before calc_breaking
+    void preprocess();
+    
+    void calc_breaking();
+    /**
+      calculate where the lines are to be broken.
+
+      POST
+    
+      lines contain the broken lines.
+     */
+
+    /// after calc_breaking
+    void postprocess();
+    
+    /// search all pcols which are breakable.
+    svec<const PCol *> find_breaks() const;
+
+    /// add a line to the broken stuff. Positions given in #config#
+    void add_line(svec<const PCol *> curline, svec<Real> config);
+
+    /// helper: solve for the columns in #curline#.
+    svec<Real> solve_line(svec<const PCol *> curline) const;
+
+    void add(PStaff *);
+    /// add item
+    void typeset_item(Item *,  PCol *,PStaff*,int=1);
+
+    /// add an Spanner
+    void typeset_spanner(Spanner*, PStaff*);
+    ///    add to bottom of pcols
+    void add(PCol*);
+    /**
+
+    */
+    void output(Tex_stream &ts);
+
+    Idealspacing* get_spacing(PCol *, PCol *);
+    /*
+    get the spacing between c1 and c2, create one if necessary.
+    */
+
+    /// return argument as a cursor.
+    PCursor<PCol *> find_col(PCol *);
+
+    /// delete unused columns
+    void clean_cols();
+
+
+    /// check if the spacing/breaking problem is well-stated
+    void problem_OK() const;
+
+    /// invarinants
+    void OK()const;
+    PScore(Paperdef*);
+    void print() const;
+
+    /// does curline fit on the paper?
+    bool feasible(svec<const PCol *> curline) const;
+};
+/** notes, signs, symbols in a score can be grouped in two ways:
+    horizontally (staffwise), and vertically (columns). #PScore#
+    contains the items, the columns and the staffs.
+ */
+#endif
diff --git a/src/break.cc b/src/break.cc
new file mode 100644 (file)
index 0000000..de9a704
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+    do calculations for breaking problem
+    
+    */
+#include "paper.hh"
+#include "linespace.hh"
+#include "debug.hh"
+#include "scoreline.hh"
+#include "pscore.hh"
+
+// construct an appropriate Spacing_problem and solve it. 
+svec<Real>
+PScore::solve_line(svec<const PCol *> curline) const
+{
+   Spacing_problem sp;
+
+   sp.add_column(curline[0], true, 0.0);
+   for (int i=1; i< curline.sz()-1; i++)
+       sp.add_column(curline[i]);
+   sp.add_column(curline.last(), true, paper_->linewidth);
+
+   // misschien  moeven uit Spacing_problem? 
+   for (PCursor<Idealspacing *> i(suz); i.ok(); i++) {
+       sp.add_ideal(i);
+   }
+   svec<Real> the_sol=sp.solve();
+   return the_sol;
+}
+
+bool
+PScore::feasible(svec<const PCol *> curline) const
+{
+    Real l =0;
+    for (int i=0; i < curline.sz(); i++)
+       l +=curline[i]->width().length();
+    return l < paper_->linewidth;    
+}
+
+void
+PScore::problem_OK() const
+{
+    if (!cols.size())
+       error("PScore::problem_OK(): Score does not have any columns");
+    PCursor<PCol *> start(cols);
+    PCursor<PCol *> end (((PScore*)this)->cols.bottom());
+    
+    assert(start->breakable());    
+    assert(end->breakable());
+}
+
+struct Col_configuration {
+    svec<const PCol*> line;
+    svec<Real> config;
+    Real energy;
+
+    Col_configuration() {
+       energy = INFTY;
+    }
+    void add(const PCol*c) { line.add(c);}
+    void setsol(svec<Real> sol) {
+       config = sol;
+       energy = config.last();
+       config.pop();
+    }
+    void print() const {
+#ifndef NPRINT
+       mtor << "energy : " << energy << '\n';
+       mtor << "line of " << config.sz() << " cols\n";
+#endif
+    }
+};
+
+/// wordwrap type algorithm
+/* el stupido. This should be done more accurately:
+
+   It would be nice to have a Dynamic Programming type of algorithm
+   similar to TeX's
+   
+    */
+
+void
+PScore::calc_breaking()
+{
+    OK();
+    problem_OK();
+    PCursor<PCol *> curcol(cols);
+           
+    svec<const PCol *> breakpoints(find_breaks());
+    assert(breakpoints.sz()>=2);
+    for (int i=0 ; i < breakpoints.sz() -1; ) {
+       Col_configuration minimum;
+       Col_configuration current;
+
+        // do  another line
+       PCol *post = breakpoints[i]->postbreak;
+       current.add( post);
+       curcol++;               // skip the breakable.
+       i++;
+
+       while (i < breakpoints.sz()) {
+
+           // add another measure.
+           while(breakpoints[i] !=curcol){
+               
+               current.add(curcol);
+               curcol++;
+           }
+           current.add(breakpoints[i]->prebreak );
+           if (!feasible(current.line)) {
+               if (!minimum.line.sz())
+                   error("sorry, this measure is too long");
+               break;
+           }
+           current.setsol(solve_line(current.line));
+           current.print();
+           
+           if (current.energy < minimum.energy) {              
+               minimum = current;         
+           } else {            // we're one col too far.
+               i--;
+               while (curcol != breakpoints[i])
+                   curcol --;
+               
+               break;
+           }
+       
+           current.line.last()=breakpoints[i];
+           curcol ++;
+           i++;
+       }
+       mtor << "Adding line, next breakpoint " << i << '\n';
+       add_line(minimum.line, minimum.config); 
+    }
+}
+
diff --git a/src/note.cc b/src/note.cc
new file mode 100644 (file)
index 0000000..0041bb7
--- /dev/null
@@ -0,0 +1,206 @@
+#include <ctype.h>
+
+#include "string.hh"
+#include "real.hh"
+#include "debug.hh"
+#include "request.hh"
+#include "voice.hh"
+#include "notename.hh"
+#include "vray.hh"
+
+int default_duration = 4, default_dots=0, default_octave=0;
+
+void
+parse_duration(const char *a, int &j, int &intdur, int &dots)
+{    
+    String durstr;    
+    while (isdigit(a[j])) 
+       {
+       durstr += a[j++];
+       }
+
+    dots=default_dots;
+    
+    while (a[j] == '.') 
+       {
+       j++;
+       dots++;
+       }
+    
+    intdur = (durstr.len()) ?
+       durstr.value():default_duration;
+
+    mtor << "dur " << intdur << "dots " << dots<<eol;
+}
+
+
+
+void 
+parse_pitch( const char *a, int &j, int &oct, bool & overide_acc,
+            int & large, int & small)
+{
+    // octave
+    oct =default_octave;
+    
+    while (1) 
+       {       
+       if (a[j] == '\'')
+           oct ++;
+       else if (a[j] == '`')
+           oct --;
+       else
+           break;
+       j++;
+       
+       }
+
+       mtor << "oct " << oct;
+       
+    // accidental
+    overide_acc = false;
+    
+    if (a[j] == '!')
+       {       
+       overide_acc = true;
+       j++;
+       }
+
+    
+    // notename.
+    String nm;
+    while (isalpha(a[j])) 
+       {
+       nm += a[j++];
+       }
+    if (isupper(nm[0]))
+       {
+       oct--;  
+       nm.lower();
+       }
+        
+
+    lookup_notename(large,small,nm);
+    mtor << "override: " << overide_acc;    
+    mtor << "pitch "<< large <<", "<<small<<"\n";    
+}
+
+
+Voice_element *
+get_note_element(String pitch, String durstr)
+{
+    Voice_element*v = new Voice_element;
+    int i=0;
+    
+    int dur, dots;
+    parse_duration(durstr, i, dur, dots);
+    i=0;
+
+    Note_req * rq = new Note_req;
+
+    if (dur >= 2) {
+       Stem_req * st = new Stem_req(dur);
+       v->add(st);
+    }
+    
+    int oct, pit, acc;
+    bool forceacc;
+    parse_pitch(pitch, i, oct, forceacc, pit, acc);
+    char nm =  pit + 'c';
+    if (nm > 'g')
+       nm += 'a' - 'h';
+    rq->name =nm;
+    
+    rq->octave = oct;
+    rq->accidental = acc;
+    rq->forceacc = forceacc;
+    rq->balltype = dur;
+    rq->dots = dots;
+    
+    rq->print();
+
+    v->add(rq);
+
+    return v;
+}
+
+Voice_element *
+get_rest_element(String, String durstr)
+{    
+    Voice_element*v = new Voice_element;
+    int i=0;
+    
+    int dur, dots;
+    parse_duration(durstr, i, dur, dots);
+    i=0;
+
+    Rest_req * rq = new Rest_req;
+  
+    rq->balltype = dur;
+    rq->dots = dots;    
+    rq->print();
+    v->add(rq);
+
+    return v;
+}
+
+void
+set_default_duration(String d)
+{
+    int i=0;
+    parse_duration(d, i, default_duration, default_dots);
+}
+
+
+void
+set_default_pitch(String d)
+{
+    int i=0;
+    bool b;
+    int l,s;
+    parse_pitch(d, i, default_octave, b, l,s);
+}
+
+Request*
+get_request(char c)
+{
+    Request* ret=0;
+    switch (c) {
+    case '[':
+    case ']':
+       ret = new Beam_req;
+       break;
+
+    case ')':
+    case '(':
+       ret = new Slur_req;
+       break;
+    default:
+       assert(false);
+       break;
+    }
+    
+    switch (c) {
+    case '(':
+    case '[':
+       ret->span()->spantype = Span_req::START;
+       break;
+    case ')':
+    case ']':
+       ret->span()->spantype = Span_req::STOP;
+       break;
+    default:
+       assert(false);
+       break;
+    }
+
+    return ret;
+}
+
+void
+add_requests(Voice_element *v, svec<Request*> &req)
+{
+    for (int i = 0; i < req.sz(); i++) {
+       v->add(req[i]);
+    }
+    req.set_size(0);
+}