From f48e3b29e56bf36984edb475fc661e7596acedff Mon Sep 17 00:00:00 2001 From: fred Date: Mon, 11 Nov 1996 23:48:36 +0000 Subject: [PATCH] lilypond-0.0.9 --- hdr/linespace.hh | 95 ++++++++++++++++++++++ hdr/pscore.hh | 102 +++++++++++++++++++++++ src/break.cc | 135 +++++++++++++++++++++++++++++++ src/note.cc | 206 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 538 insertions(+) create mode 100644 hdr/linespace.hh create mode 100644 hdr/pscore.hh create mode 100644 src/break.cc create mode 100644 src/note.cc diff --git a/hdr/linespace.hh b/hdr/linespace.hh new file mode 100644 index 0000000000..54704508e6 --- /dev/null +++ b/hdr/linespace.hh @@ -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 ideals; + svec 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 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 index 0000000000..70e783c889 --- /dev/null +++ b/hdr/pscore.hh @@ -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 cols; + + /// the idealspacings, no particular order + PointerList suz; + + /// the staffs ordered top to bottom + PointerList staffs; + + /// all symbols in score. No particular order. + PointerList its; + + /// if broken, the different lines + PointerList lines; + + /// crescs etc; no particular order + PointerList spanners; + + /****************************************************************/ + + svec 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 find_breaks() const; + + /// add a line to the broken stuff. Positions given in #config# + void add_line(svec curline, svec config); + + /// helper: solve for the columns in #curline#. + svec solve_line(svec 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 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 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 index 0000000000..de9a704984 --- /dev/null +++ b/src/break.cc @@ -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 +PScore::solve_line(svec 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 i(suz); i.ok(); i++) { + sp.add_ideal(i); + } + svec the_sol=sp.solve(); + return the_sol; +} + +bool +PScore::feasible(svec 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 start(cols); + PCursor end (((PScore*)this)->cols.bottom()); + + assert(start->breakable()); + assert(end->breakable()); +} + +struct Col_configuration { + svec line; + svec config; + Real energy; + + Col_configuration() { + energy = INFTY; + } + void add(const PCol*c) { line.add(c);} + void setsol(svec 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 curcol(cols); + + svec 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 index 0000000000..0041bb7238 --- /dev/null +++ b/src/note.cc @@ -0,0 +1,206 @@ +#include + +#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<= 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 &req) +{ + for (int i = 0; i < req.sz(); i++) { + v->add(req[i]); + } + req.set_size(0); +} -- 2.39.5