--- /dev/null
+MAJVER=0
+MINVER=0
+PATCHLEVEL=1
+
+#
+#
+
+include Sources.make
+progdocs=$(hdr) $(mycc)
+gencc=parser.cc lexer.cc
+cc=$(mycc) $(gencc)
+obs=$(cc:.cc=.o)
+
+
+#dist
+
+DOCDIR=docdir
+VERSION=$(MAJVER).$(MINVER).$(PATCHLEVEL)
+PACKAGENAME=lilypond
+DNAME=$(PACKAGENAME)-$(VERSION)
+othersrc=lexer.l parser.y
+OFILES=Makefile Sources.make symbol.ini suzan.ly depend lilyponddefs.tex test.tex make_version
+DFILES=$(hdr) $(mycc) $(othersrc) $(OFILES)
+
+#compiling
+LOADLIBES=-L$(FLOWERDIR) -lflower
+FLOWERDIR=../flower
+CXXFLAGS=-I$(FLOWERDIR) -pipe -Wall -g
+
+exe=$(PACKAGENAME)
+
+
+
+$(exe): $(obs)
+ $(CXX) -o $(exe) $(obs) $(LOADLIBES)
+clean:
+ rm -f $(exe) *.o $(DOCDIR)/* TAGS
+
+all: kompijl doc
+
+# doc++ documentation of classes
+doc:
+ -mkdir $(DOCDIR)
+ doc++ -p -I -d $(DOCDIR) $(progdocs)
+
+back:
+ zip -u ~/backs/spacer *cc *hh
+
+depend: Sources.make
+ $(CXX) $(CXXFLAGS) -MM $(cc) > depend
+
+include depend
+
+parser.cc: parser.y
+ bison -d $<
+ mv parser.tab.h parser.hh
+ mv parser.tab.c parser.cc
+
+parser.hh: parser.cc
+
+version.o: $(obs) version.hh
+
+version.hh: Makefile make_version
+ make_version $(MAJVER) $(MINVER) $(PATCHLEVEL) > version.hh
+
+lexer.cc: lexer.l
+ flex -+ -t lexer.l > lexer.cc
+
+DDIR=$(DNAME)
+dist:
+ -mkdir $(DDIR)
+ ln $(DFILES) $(DDIR)/
+ tar cfz $(DNAME).tar.gz $(DDIR)/*
+ rm -rf $(DDIR)/
+
+
+TAGS: $(mycc) $(hdr) Sources.make
+ etags -CT $(mycc) $(hdr)
--- /dev/null
+hdr=matrix.hh qlp.hh smat.hh vsmat.hh\
+ linespace.hh qlpsolve.hh vector.hh\
+ cols.hh proto.hh pstaff.hh line.hh\
+ const.hh glob.hh molecule.hh boxes.hh pscore.hh item.hh tex.hh\
+ request.hh voice.hh command.hh staff.hh linestaff.hh \
+ tstream.hh dstream.hh mtime.hh rhythmstaf.hh\
+ parseconstruct.hh real.hh debug.hh globvars.hh keyword.hh\
+ misc.hh score.hh notename.hh lexer.hh symtable.hh\
+ choleski.hh
+
+mycc=smat.cc matrix.cc choleski.cc qlp.cc qlpsolve.cc \
+ break.cc linespace.cc molecule.cc line.cc\
+ pscore.cc tex.cc item.cc cols.cc staff.cc rhythmstaf.cc\
+ score.cc note.cc dstream.cc main.cc misc.cc \
+ symbol.cc request.cc notename.cc voice.cc\
+ keyword.cc linestaff.cc table.cc command.cc\
+ warn.cc debug.cc symtable.cc boxes.cc\
+ pstaff.cc vector.cc tstream.cc version.cc\
+ calcideal.cc\
+ template.cc template2.cc
--- /dev/null
+#include "boxes.hh"
+#include "const.hh"
+
+void
+Interval:: set_empty() {
+ min = INFTY;
+ max = -INFTY;
+}
+
+Box::Box(svec<Real> s)
+{
+ assert(s.sz() == 4);
+ x.min = s[0];
+ x.max = s[1];
+ y.min = s[2];
+ y.max = s[3];
+}
+
+Box::Box()
+{
+
+}
--- /dev/null
+/*
+ some 2D geometrical concepts
+*/
+
+#ifndef BOXES_HH
+#define BOXES_HH
+
+#include "textdb.hh"
+#include "real.hh"
+#include "vray.hh"
+
+/// 2d vector
+struct Offset {
+ Real x,y;
+
+ Offset operator+(Offset o)const {
+ Offset r(*this);
+ r+=o;
+ return r;
+ }
+
+ Offset operator+=(Offset o) {
+ x+=o.x;
+ y+=o.y;
+ return *this;
+ }
+ Offset(Real ix , Real iy) {
+ x=ix;
+ y=iy;
+ }
+ Offset() {
+ x=0.0;
+ y=0.0;
+ }
+};
+
+/// a Real interval
+struct Interval {
+ Real min, max;
+
+ void translate(Real t) {
+ min += t;
+ max += t;
+ }
+
+ void unite(Interval h) {
+ if (h.min<min)
+ min = h.min;
+ if (h.max>max)
+ max = h.max;
+ }
+
+ void set_empty() ;
+ bool empty() { return min > max; }
+ Interval() {
+ set_empty();
+ }
+ Interval(Real m, Real M) {
+ min =m;
+ max = M;
+ }
+};
+
+
+/// a 4-tuple of #Real#s
+struct Box {
+ Interval x, y;
+
+ void translate(Offset o) {
+ x.translate(o.x);
+ y.translate(o.y);
+ }
+ void unite(Box b) {
+ x.unite(b.x);
+ y.unite(b.y);
+ }
+ Box(svec<Real> );
+ Box();
+};
+
+
+#endif
--- /dev/null
+/*
+ do calculations for breaking problem
+
+ */
+
+#include "linespace.hh"
+#include "debug.hh"
+#include "line.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;
+ // mtor << "line of " << curline.sz() << " cols\n";
+ 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, 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;
+}
+
+
+void
+PScore::problem_OK()
+{
+ if (!cols.size())
+ error("PScore::problem_OK(): Score does not have any columns");
+ PCursor<PCol *> start(cols);
+ PCursor<PCol *> end (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();
+ }
+};
+
+/// wordwrap type algorithm
+/* el stupido. This should be optimised...
+ */
+
+void
+PScore::calc_breaking()
+{
+ 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
+ current.add(breakpoints[i]->postbreak );
+ 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 );
+ current.setsol(solve_line(current.line));
+
+
+ if (current.energy < minimum.energy) {
+ minimum = current;
+ } else {
+ break;
+ }
+
+ current.line.last()=breakpoints[i];
+ curcol ++;
+ i++;
+ }
+
+ add_line(minimum.line, minimum.config);
+ }
+}
+
--- /dev/null
+#include "tstream.hh"
+#include "score.hh"
+#include "pscore.hh"
+#include "staff.hh"
+#include "misc.hh"
+#include "debug.hh"
+
+
+void
+Score::do_connect(PCol *c1, PCol *c2, Real d)
+{
+ Idealspacing*sp=pscore_->get_spacing(c1,c2);
+
+ if (!sp->hooke){
+ sp->hooke = 1.0;
+ sp->space =d;
+ }
+}
+
+void
+Score::connect_nonmus(PCol* c1, PCol *c2, Real d)
+{
+ if (c2->used && c1->used) {
+ do_connect(c1,c2,d);
+
+ // alert! this is broken!
+ if (c1->breakable) {
+ do_connect(c1->postbreak, c2,d);
+ }
+ if (c2->breakable) {
+ do_connect(c1, c2->prebreak,d);
+ }
+ if (c1->breakable &&c2->breakable) {
+ do_connect(c1->postbreak, c2->prebreak,d);
+ }
+ }
+}
+/* this needs A LOT of rethinking.
+
+ generate springs between columns.
+ */
+void
+Score::calc_idealspacing()
+{
+ PCursor<Score_column*> sc(cols_);
+
+ for (; sc.ok(); sc++) {
+ if (sc->musical)
+ for (int i=0; i < sc->durations.sz(); i++) {
+ Mtime d = sc->durations[i];
+ Real dist = duration_to_idealspace(d);
+ PCol * c2 = find_col(sc->when + d,true)->pcol;
+ connect_nonmus(sc->pcol, c2, dist);
+ c2 = find_col(sc->when + d,false)->pcol;
+ connect_nonmus(sc->pcol, c2, dist);
+ }
+ else if (sc->used()) { // ignore empty columns
+ PCol * c2 = find_col(sc->when,true)->pcol;
+ connect_nonmus(sc->pcol,c2,0.0);
+ }
+ }
+}
+
+
--- /dev/null
+#include "choleski.hh"
+
+Vector
+Choleski_decomposition::solve(Vector rhs)const
+{
+ int n= rhs.dim();
+ assert(n == L.dim());
+ Vector y(n);
+
+ // forward substitution
+ for (int i=0; i < n; i++) {
+ Real sum(0.0);
+ for (int j=0; j < i; j++)
+ sum += y(j) * L(i,j);
+ y(i) = (rhs(i) - sum)/L(i,i);
+ }
+ for (int i=0; i < n; i++) {
+ assert(D(i));
+ y(i) /= D(i);
+ }
+ Vector x(n);
+ for (int i=n-1; i >= 0; i--) {
+ Real sum(0.0);
+ for (int j=i+1; j < n; j++)
+ sum += L(j,i)*x(j);
+ x(i) = (y(i) - sum)/L(i,i);
+ }
+ return x;
+}
+
+Choleski_decomposition::Choleski_decomposition(Matrix P)
+ : L(P.dim()), D(P.dim())
+{
+ int n = P.dim();
+ assert((P-P.transposed()).norm() < EPS);
+ L.unit();
+ for (int k= 0; k < n; k++) {
+ for (int j = 0; j < k; j++){
+ Real sum(0.0);
+ for (int l=0; l < j; l++)
+ sum += L(k,l)*L(j,l)*D(l);
+ L(k,j) = (P(k,j) - sum)/D(j);
+ }
+ Real sum=0.0;
+
+ for (int l=0; l < k; l++)
+ sum += sqr(L(k,l))*D(l);
+ Real d = P(k,k) - sum;
+ D(k) = d;
+ }
+
+ #ifdef NDEBUG
+ assert((original()-P).norm() < EPS);
+ #endif
+}
+
+Matrix
+Choleski_decomposition::original() const
+{
+ Matrix T(L.dim());
+ T.set_diag(D);
+ return L*T*L.transposed();
+}
+
+Matrix
+Choleski_decomposition::inverse() const
+{
+ int n=L.dim();
+ Matrix invm(n);
+ Vector e_i(n);
+ for (int i = 0; i < n; i++) {
+ e_i.set_unit(i);
+ Vector inv(solve(e_i));
+ for (int j = 0 ; j<n; j++)
+ invm(i,j) = inv(j);
+ }
+
+#ifdef NDEBUG
+ Matrix I1(n), I2(original());
+ I1.unit();
+ assert((I1-original()*invm).norm() < EPS);
+ #endif
+
+ return invm;
+}
--- /dev/null
+#ifndef CHOLESKI_HH
+#define CHOLESKI_HH
+
+#include "matrix.hh"
+
+struct Choleski_decomposition {
+
+ /// lower triangle of Choleski decomposition
+ Matrix L;
+
+ /// diagonal
+ Vector D;
+ ///Create decomposition of P
+ Choleski_decomposition(Matrix P);
+ /**
+ PRE
+ P needs to be symmetric positive definite
+ */
+
+ Vector solve(Vector rhs) const;
+ Vector operator * (Vector rhs) const { return solve (rhs); }
+ /**
+ solve Px = rhs
+ */
+
+ Matrix inverse() const;
+ /**
+ return the inverse of the matrix P.
+ */
+
+ Matrix original() const;
+ /**
+ return P, calc'ed from L and D
+ */
+
+};
+/**
+ structure for using the LU decomposition of a positive definite .
+
+ #P# is split into
+
+ LD transpose(L)
+ */
+
+
+#endif
--- /dev/null
+#include "cols.hh"
+#include "pstaff.hh"
+
+Idealspacing::Idealspacing(const PCol * l,const PCol * r)
+{
+ space = 0.0;
+ hooke = 0.0;
+ left = l;
+ right = r;
+}
+void
+Idealspacing::OK() const
+{
+ assert(hooke >= 0 && left && right);
+}
+
+Interval
+PCol::width() const
+{
+ Interval w;
+
+ for (PCursor<const Item *> ic(its); ic.ok(); ic++)
+ w.unite(ic->width());
+ if (w.empty())
+ w.unite(Interval(0,0));
+ return w;
+}
+/****************************************************************/
+
+int
+PCol::compare(const PCol &c1, const PCol &c2)
+{
+ assert(false);
+}
+
+void
+PCol::OK () const
+{
+ if (prebreak || postbreak ) {
+ assert(breakable);
+ }
+}
+
+void
+PCol::set_breakable()
+{
+ if (breakable)
+ return;
+
+ prebreak = new PCol(this);
+ postbreak = new PCol(this);
+ breakable = true;
+ used = true;
+}
+
+PCol::PCol(PCol *parent) {
+ daddy = parent;
+ prebreak=0;
+ postbreak=0;
+ breakable=false;
+ line=0;
+ used = false;
+}
+
+PCol::~PCol()
+{
+ delete prebreak;
+ delete postbreak;
+}
+
+void
+PCol::add(const Item *i)
+{
+ its.bottom().add(i);
+ used = true;
+}
+
--- /dev/null
+#ifndef COLS_HH
+#define COLS_HH
+
+#include "glob.hh"
+#include "boxes.hh"
+#include "list.hh"
+#include "item.hh"
+
+/// stuff grouped vertically.
+struct PCol {
+ List<const Item*> its;
+ List<const Spanner*> stoppers, starters;
+
+ /// Can this be broken? true eg. for bars.
+ bool breakable;
+
+ /// does this column have items, does it have spacings attached?
+ bool used;
+
+ /// prebreak is put before end of line.
+ PCol *prebreak;
+ /**
+ if broken here, then (*this) column is discarded, and prebreak
+ is put at end of line, owned by Col
+ */
+
+ /// postbreak at beginning of the new line
+ PCol *postbreak;
+ /** \See{prebreak}
+ */
+ PCol *daddy;
+ /*
+ if this column is pre or postbreak, then this field points to the parent.
+ */
+ /// if lines are broken then this column is in #line#
+ const Line_of_score *line;
+
+ /// if lines are broken then this column x-coord #hpos#
+ Real hpos;
+
+
+ /****************************************************************/
+
+ void add(const Item*i);
+
+ Interval width() const;
+ ~PCol();
+ PCol(PCol * parent);
+ /// initialize the prebreak and postbreak fields
+ setup_breaks();
+
+ /// which col comes first?
+ static int compare(const PCol &c1, const PCol &c2);
+ /**
+ signed compare on columns.
+
+ return < 0 if c1 < c2.
+ */
+
+ void OK() const;
+ void set_breakable();
+
+};
+/**
+ This is a class to address items vertically. It contains the data for:
+ \begin{itemize}
+ \item
+ unbroken score
+ \item
+ broken score
+ \item
+ the linespacing problem
+ \end{itemize}
+ */
+
+#include "compare.hh"
+instantiate_compare(const PCol &, PCol::compare);
+
+
+/// ideal spacing between two columns
+struct Idealspacing {
+
+ /// the ideal distance
+ Real space;
+
+ /// Hooke's constant: how strong are the "springs" attached to columns
+ Real hooke;
+
+ /// the two columns
+ const PCol *left, *right;
+
+ void OK() const ;
+ Idealspacing(const PCol *left,const PCol *right);
+};
+
+#endif
--- /dev/null
+#include "string.hh"
+#include "command.hh"
+
+
+Command*
+get_bar_command(Real w)
+{
+ Command*c = new Command;
+ c->when = w;
+ c->code = TYPESET;
+ c->args.add( "|");
+ return c;
+}
--- /dev/null
+#ifndef COMMAND_HH
+#define COMMAND_HH
+#include "glob.hh"
+#include "mtime.hh"
+#include "vray.hh"
+enum Commandcode {
+ NOP,
+ INTERPRET,
+ TYPESET,
+ BREAK_PRE,BREAK_MIDDLE, BREAK_POST, BREAK_END,
+};
+/// set a nonrythmical symbol
+struct Command {
+ Commandcode code;
+
+ Mtime when;
+ /// analogous to argv[]
+ svec<String> args;
+};
+
+/**
+ A nonrhythmical "thing" in a staff is called a "command".
+ Commands have these properties:
+
+ \begin{itemize}
+ \item They are \bf{not} rhythmical, i.e. they do not have a duration
+ \item They have a staff-wide impact, i.e. a command cannot be targeted at
+ only one voice in the staff: two voices sharing a staff can't have
+ different clefs
+ \item Commands are ordered, that is, when from musical point of view the
+ commands happen simultaneously, the order in which Staff receives the
+ commands can still make a difference in the output
+ \item Some commands are actually score wide, so Score has to issue these
+ commands to the Staff, eg. BREAK commands
+ \end{itemize}
+
+ At this moment we have three classes of commands:
+ \begin{description}
+ INTERPRET commands are not grouped.
+ \item[TYPESET] These commands instruct the Staff to
+ typeset symbols on the output, eg meter/clef/key changes
+ \item[INTERPRET] These commands do not produce output, instead,
+ they change the interpretation of other commands or requests.
+ example: shift output vertically, set the key.
+ \item[BREAK_XXX] These commands group TYPESET commands in
+ prebreak and postbreak commands. \See{Col}.
+ Staff can insert additional commands in a sequence of BREAK_XXX
+ commands, eg. key change commands
+
+ \end{description}
+
+ These commands are generated by Score, since they have to be the
+ same for the whole score.
+
+
+ \begin{description}
+ \item[BREAK_PRE]
+ \item[BREAK_MIDDLE]
+ \item[BREAK_POST]
+ \item[BREAK_END]
+ \item[TYPESET] METER,BAR
+ \end{description}
+
+
+ Commands can be freely copied, they do not have virtual methods.
+ */
+
+
+#endif
--- /dev/null
+/*
+ global constants
+ */
+
+
+const Real CM_TO_PT=72/2.54;
+const Real VERT_TO_PT=CM_TO_PT; // tex output
+const Real HOR_TO_PT=CM_TO_PT; // tex output
+const Real EPS=1e-7; // qlpsolve.hh
+const int MAXITER=100; // qlpsolve.hh
+const Real INFTY=1e8;
--- /dev/null
+#include "debug.hh"
+int debug_flags;
+
+void
+set_debug(String s)
+{
+ if (s.pos ('t')) {
+ debug_flags |= DEBUGTOKEN;
+ mtor << " Turning on token debug\n";
+ }
+ if (s.pos ('p')){
+ debug_flags |= DEBUGPARSER;
+ mtor << "Turning on parser debugger\n";
+ }
+}
--- /dev/null
+#ifndef DEBUG_HH
+#define DEBUG_HH
+#include <assert.h>
+#include <iostream.h>
+#include "dstream.hh"
+
+
+
+#define WARN warnout << "warning: "<<__FUNCTION__ << ": "
+extern ostream &warnout ;
+extern ostream *mlog;
+extern dstream mtor; // monitor
+
+void error(String s);
+void warning(String s);
+
+extern int debug_flags;
+
+void
+set_debug(String s);
+const int DEBUGPARSER = 0x01;
+const int DEBUGTOKEN = 0x02;
+const int DEBUGITEMS = 0x04;
+
+#endif
--- /dev/null
+smat.o: smat.cc smat.hh ../flower/vray.hh vsmat.hh real.hh
+matrix.o: matrix.cc matrix.hh vsmat.hh ../flower/vray.hh real.hh \
+ vector.hh glob.hh proto.hh const.hh ../flower/string.hh \
+ ../flower/stringutil.hh debug.hh dstream.hh
+choleski.o: choleski.cc choleski.hh matrix.hh vsmat.hh \
+ ../flower/vray.hh real.hh vector.hh glob.hh proto.hh const.hh
+qlp.o: qlp.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh qlp.hh matrix.hh vsmat.hh ../flower/vray.hh \
+ real.hh vector.hh glob.hh proto.hh const.hh choleski.hh
+qlpsolve.o: qlpsolve.cc qlpsolve.hh qlp.hh matrix.hh vsmat.hh \
+ ../flower/vray.hh real.hh vector.hh glob.hh proto.hh const.hh \
+ debug.hh dstream.hh ../flower/string.hh ../flower/stringutil.hh \
+ choleski.hh
+break.o: break.cc linespace.hh glob.hh real.hh proto.hh const.hh \
+ ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl \
+ ../flower/vray.hh cols.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ item.hh tex.hh ../flower/compare.hh matrix.hh vsmat.hh vector.hh \
+ debug.hh dstream.hh line.hh pstaff.hh pscore.hh
+linespace.o: linespace.cc linespace.hh glob.hh real.hh proto.hh \
+ const.hh ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl \
+ ../flower/vray.hh cols.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ item.hh tex.hh ../flower/compare.hh matrix.hh vsmat.hh vector.hh \
+ debug.hh dstream.hh qlp.hh ../flower/unionfind.hh
+molecule.o: molecule.cc glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh molecule.hh \
+ ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh item.hh \
+ tex.hh
+line.o: line.cc line.hh real.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl ../flower/vray.hh glob.hh proto.hh const.hh \
+ pstaff.hh item.hh boxes.hh ../flower/textdb.hh ../flower/textstr.hh \
+ ../flower/string.hh ../flower/stringutil.hh tex.hh cols.hh \
+ ../flower/compare.hh pscore.hh
+pscore.o: pscore.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh line.hh real.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl ../flower/vray.hh glob.hh \
+ proto.hh const.hh pstaff.hh item.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh tex.hh pscore.hh cols.hh ../flower/compare.hh \
+ tstream.hh
+tex.o: tex.cc tex.hh ../flower/string.hh ../flower/stringutil.hh \
+ boxes.hh ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh \
+ real.hh const.hh
+item.o: item.cc line.hh real.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl ../flower/vray.hh glob.hh proto.hh const.hh \
+ pstaff.hh item.hh boxes.hh ../flower/textdb.hh ../flower/textstr.hh \
+ ../flower/string.hh ../flower/stringutil.hh tex.hh cols.hh \
+ ../flower/compare.hh
+cols.o: cols.cc cols.hh glob.hh real.hh proto.hh const.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/string.hh \
+ ../flower/stringutil.hh ../flower/vray.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl item.hh tex.hh \
+ ../flower/compare.hh
+staff.o: staff.cc staff.hh score.hh ../flower/vray.hh cols.hh glob.hh \
+ real.hh proto.hh const.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl item.hh \
+ tex.hh ../flower/compare.hh mtime.hh command.hh voice.hh request.hh \
+ debug.hh dstream.hh pscore.hh pstaff.hh
+rhythmstaf.o: rhythmstaf.cc request.hh glob.hh real.hh proto.hh \
+ const.hh ../flower/string.hh ../flower/stringutil.hh mtime.hh \
+ debug.hh dstream.hh linestaff.hh pstaff.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl item.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh tex.hh \
+ staff.hh score.hh cols.hh ../flower/compare.hh command.hh voice.hh \
+ pscore.hh molecule.hh rhythmstaf.hh
+score.o: score.cc tstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh score.hh ../flower/vray.hh cols.hh glob.hh \
+ real.hh proto.hh const.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl item.hh tex.hh ../flower/compare.hh mtime.hh \
+ command.hh pscore.hh pstaff.hh staff.hh voice.hh request.hh misc.hh \
+ debug.hh dstream.hh
+note.o: note.cc ../flower/string.hh ../flower/stringutil.hh real.hh \
+ debug.hh dstream.hh request.hh glob.hh proto.hh const.hh mtime.hh \
+ voice.hh ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl notename.hh
+dstream.o: dstream.cc dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh
+main.o: main.cc ../flower/lgetopt.hh misc.hh mtime.hh real.hh debug.hh \
+ dstream.hh ../flower/string.hh ../flower/stringutil.hh score.hh \
+ ../flower/vray.hh cols.hh glob.hh proto.hh const.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl item.hh tex.hh \
+ ../flower/compare.hh command.hh globvars.hh
+misc.o: misc.cc misc.hh mtime.hh real.hh glob.hh proto.hh const.hh
+symbol.o: symbol.cc tex.hh ../flower/string.hh ../flower/stringutil.hh \
+ boxes.hh ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh \
+ real.hh
+request.o: request.cc request.hh glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh mtime.hh
+notename.o: notename.cc glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh
+voice.o: voice.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh voice.hh mtime.hh real.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl request.hh glob.hh proto.hh \
+ const.hh
+keyword.o: keyword.cc glob.hh real.hh proto.hh const.hh lexer.hh
+linestaff.o: linestaff.cc linestaff.hh pstaff.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl item.hh glob.hh real.hh \
+ proto.hh const.hh boxes.hh ../flower/textdb.hh ../flower/textstr.hh \
+ ../flower/string.hh ../flower/stringutil.hh ../flower/vray.hh tex.hh
+table.o: table.cc glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh keyword.hh parser.hh
+command.o: command.cc ../flower/string.hh ../flower/stringutil.hh \
+ command.hh glob.hh real.hh proto.hh const.hh mtime.hh \
+ ../flower/vray.hh
+warn.o: warn.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh
+debug.o: debug.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh
+symtable.o: symtable.cc misc.hh mtime.hh real.hh debug.hh dstream.hh \
+ ../flower/string.hh ../flower/stringutil.hh tex.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh \
+ ../flower/assoc.hh symtable.hh const.hh
+boxes.o: boxes.cc boxes.hh ../flower/textdb.hh ../flower/textstr.hh \
+ ../flower/string.hh ../flower/stringutil.hh ../flower/vray.hh real.hh \
+ const.hh
+pstaff.o: pstaff.cc pstaff.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl item.hh glob.hh real.hh proto.hh const.hh \
+ boxes.hh ../flower/textdb.hh ../flower/textstr.hh ../flower/string.hh \
+ ../flower/stringutil.hh ../flower/vray.hh tex.hh
+vector.o: vector.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh vector.hh glob.hh real.hh proto.hh const.hh \
+ ../flower/vray.hh
+tstream.o: tstream.cc tex.hh ../flower/string.hh \
+ ../flower/stringutil.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/vray.hh real.hh tstream.hh debug.hh \
+ dstream.hh
+version.o: version.cc ../flower/string.hh ../flower/stringutil.hh
+calcideal.o: calcideal.cc tstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh score.hh ../flower/vray.hh cols.hh glob.hh \
+ real.hh proto.hh const.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl item.hh tex.hh ../flower/compare.hh mtime.hh \
+ command.hh pscore.hh pstaff.hh staff.hh voice.hh request.hh misc.hh \
+ debug.hh dstream.hh
+template.o: template.cc line.hh real.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl ../flower/vray.hh glob.hh \
+ proto.hh const.hh pstaff.hh item.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ tex.hh cols.hh ../flower/compare.hh request.hh mtime.hh score.hh \
+ command.hh staff.hh voice.hh ../flower/list.cc ../flower/cursor.cc
+template2.o: template2.cc line.hh real.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl ../flower/vray.hh glob.hh \
+ proto.hh const.hh pstaff.hh item.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ tex.hh voice.hh mtime.hh request.hh molecule.hh staff.hh score.hh \
+ cols.hh ../flower/compare.hh command.hh ../flower/list.cc \
+ ../flower/cursor.cc
+parser.o: parser.cc lexer.hh proto.hh real.hh staff.hh score.hh \
+ ../flower/vray.hh cols.hh glob.hh const.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/string.hh \
+ ../flower/stringutil.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl item.hh tex.hh ../flower/compare.hh mtime.hh \
+ command.hh voice.hh request.hh keyword.hh globvars.hh debug.hh \
+ dstream.hh parseconstruct.hh
+lexer.o: lexer.cc glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh lexer.hh keyword.hh \
+ ../flower/vray.hh parser.hh debug.hh dstream.hh
--- /dev/null
+// implementation of debug/TeX stream.
+#include <fstream.h>
+
+#include "dstream.hh"
+#include "string.hh"
+
+
+
+dstream mtor(cout);
+
+///
+dstream &
+dstream::operator<<(String s)
+{
+ for (const char *cp = s ; *cp; cp++)
+ switch(*cp)
+ {
+ case '{':
+ case '[':
+ case '(': indentlvl += INDTAB;
+ *os << *cp;
+ break;
+
+ case ')':
+ case ']':
+ case '}':
+ indentlvl -= INDTAB;
+ *os << *cp ;
+
+ if (indentlvl<0) indentlvl = 0;
+ break;
+
+ case '\n':
+ *os << '\n' << String (' ', indentlvl) << flush;
+ break;
+ default:
+ *os << *cp;
+ break;
+ }
+ return *this;
+
+}
+
+/** only output possibility. Delegates all conversion to String class.
+ */
+
--- /dev/null
+// debug_stream
+
+#ifndef DSTREAM_HH
+#define DSTREAM_HH
+
+#include "string.hh"
+
+const char eol= '\n';
+
+/// debug stream
+class dstream
+{
+ ostream *os;
+ int indentlvl;
+
+ /// indent of each level
+ const INDTAB = 3;
+public:
+ dstream(ostream &r){
+ os = &r;
+ indentlvl = 0;
+ }
+ dstream &operator << (String s);
+};
+ /**
+ a class for providing debug output of nested structures,
+ with indents according to \{\}()[]
+ */
+#endif
--- /dev/null
+MAJVER=1
+MINVER=0
+PATCHLEVEL=1
+
+PACKAGENAME=flower
+VERSION=$(MAJVER).$(MINVER).$(PATCHLEVEL)
+DNAME=$(PACKAGENAME)-$(VERSION)
+CXXFLAGS+=-g -Wall
+
+cc=lgetopt.cc string.cc dataf.cc textdb.cc unionfind.cc
+
+templatecc=cursor.cc list.cc
+inl=findcurs.inl link.inl list.inl
+hh=cursor.hh cursor.inl lgetopt.hh link.hh list.hh \
+ string.hh stringutil.hh vray.hh textdb.hh textstr.hh assoc.hh\
+ findcurs.hh unionfind.hh compare.hh handle.hh
+
+
+
+obs=$(cc:.cc=.o)
+staticlib=libflower.a
+$(staticlib): $(obs)
+ ar cr libflower.a $(obs)
+
+include depend
+
+depend: Makefile
+ $(CXX) -MM $(cc) > depend
+
+
+clean:
+ rm depend $(obs) $(staticlib)
+
+DFILES=$(hh) $(cc) $(inl) $(templatecc) Makefile
+DDIR=$(DNAME)
+
+dist:
+ -mkdir $(DDIR)
+ ln $(DFILES) $(DDIR)/
+ tar cfz $(DNAME).tar.gz $(DDIR)/*
+ rm -rf $(DDIR)/
+
+
--- /dev/null
+#ifndef ASSOC_HH
+#define ASSOC_HH
+
+#include "vray.hh"
+
+template<class K,class V>
+struct Assoc_ent_ {
+ bool free;
+ K key;
+ V val;
+};
+
+template<class K, class V>
+struct Assoc {
+ svec< Assoc_ent_<K,V> > arr;
+
+ /****************/
+
+ int find(K key) const {
+ for (int i = 0; i < arr.sz(); i++) {
+ if (!arr[i].free && key == arr[i].key)
+ return i;
+ }
+ return -1;
+ }
+ int find_creat(K key) {
+ int free = -1;
+ for (int i = 0; i < arr.sz(); i++) {
+ if (key == arr[i].key) {
+ return i;
+ } else if (arr[i].free ) {
+ free = i;
+ }
+ }
+ if (free >= 0){
+ arr[free].free = false;
+ arr[free].key = key;
+ return free;
+ }
+
+ Assoc_ent_<K,V> ae;
+ ae.free = false;
+ ae.key = key;
+ arr.add(ae);
+ return arr.sz() -1;
+ }
+public:
+ bool elt_query(K key) const {
+ return find(key) >= 0;
+ }
+ void del(K key) {
+ assert(elt_query(key));
+ int i= find(key);
+ arr[i].free = true;
+ }
+ void
+ add(K key, V val) {
+ int i = find_creat(key);
+ arr[i].val = val;
+ }
+ /**
+ should create "set" template
+ */
+ V& operator[](K key) {
+ return arr[find_creat(key)].val;
+ }
+ const V& operator[](K key) const {
+ assert(elt_query(key));
+ return arr[find(key)].val;
+ }
+
+};
+#endif
--- /dev/null
+#ifndef COMPARE_HH
+#define COMPARE_HH
+
+/// handy notations for a signed comparison
+#define instantiate_compare(type, function) \
+inline bool operator>(type t1, type t2) { return function(t1, t2) > 0; } \
+ inline bool operator>=(type t1, type t2) { return function(t1, t2) >= 0; } \
+ inline bool operator==(type t1, type t2) { return function(t1, t2) == 0; } \
+ inline bool operator<=(type t1, type t2) { return function(t1, t2) <= 0; } \
+ inline bool operator<(type t1, type t2) { return function(t1, t2) < 0; } \
+ inline type MAX(type t1, type t2) { return (t1 > t2 )? t1 : t2; }\
+ inline type MIN(type t1, type t2) { return (t1 < t2 )? t1 : t2; }\
+ \
+ bool operator<(type t1, type t2) /* stupid fix to allow ; */
+ /**
+ make the operators{<,<=,==,>=,>} and the MAX and MIN of two.
+ Please fill a & in the type argument if necessary.
+ */
+
+
+
+
+#endif
+
--- /dev/null
+// cursor.cc
+#ifndef CURSOR_CC
+#define CURSOR_CC
+
+#include "cursor.hh"
+//#define inline
+//#include "cursor.inl"
+#include <assert.h>
+
+template<class T>
+Cursor<T>
+Cursor<T>::operator ++( int )
+{
+ Cursor<T> r = *this;
+ assert( pointer_ );
+ pointer_ = pointer_->next();
+ return r;
+}
+template<class T>
+Cursor<T>
+Cursor<T>::operator -=( int j )
+{
+ while (j--)
+ (*this)--;
+ return *this;
+}
+template<class T>
+Cursor<T>
+Cursor<T>::operator +=( int j )
+{
+ while (j++)
+ (*this)++;
+ return *this;
+}
+
+template<class T>
+Cursor<T>
+Cursor<T>::operator --( int )
+{
+ Cursor<T> r = *this;
+ assert( pointer_ );
+ pointer_ = pointer_->previous();
+ return r;
+}
+
+template<class T>
+Cursor<T>
+Cursor<T>::operator +( int i ) const
+{
+ Cursor<T> r = *this;
+
+ if (i<0)
+ return r -(-i);
+
+ while (i--)
+ r++;
+
+ return r;
+}
+
+template<class T>
+Cursor<T>
+Cursor<T>::operator -( int i ) const
+{
+ Cursor<T> r = *this;
+ if (i<0)
+ return r +(-i);
+
+ while (i--)
+ r--;
+
+ return r;
+}
+
+#endif
--- /dev/null
+// cursor.hh
+
+#ifndef __CURSOR_HH
+#define __CURSOR_HH
+
+#include "link.hh"
+template<class T> class List;
+
+///
+template<class T>
+class Cursor
+{
+ public:
+ Cursor( List<T>& list, Link<T>* pointer = 0 );
+ Cursor( const Cursor<T>& cursor );
+
+ /// return current T
+ T& operator *();
+ operator T() { return *(*this); }
+ Cursor<T> operator =( const Cursor<T>& c );
+
+ /// make cursor with #no# items back
+ Cursor<T> operator -( int no) const;
+
+ /// make cursor with #no# items further
+ Cursor<T> operator +( int no) const;
+
+ Cursor<T> operator -=(int);
+ Cursor<T> operator +=(int);
+
+ /// return current and move one down
+ Cursor<T> operator ++( int );
+
+ /// return current and move one up
+ Cursor<T> operator --( int );
+
+ /// point to link?
+ bool ok();
+
+ /// ++ items left?
+ bool forward();
+
+ /// -- items left?
+ bool backward();
+
+ /// put (copy) after me in List
+ void add( const T& thing );
+ /**
+ analogously to editor. ok() interpreted as at end
+ of line.
+
+ PRE: !ok, POST: added to bottom()
+
+ PRE: ok, POST: added after me
+
+ cursor points to same object, cursor.next() is newly added
+ object.
+ */
+
+ /// put (copy) before me in List
+ void insert( const T& thing );
+ /**
+ analogously to editor. ok() interpreted as at begin of
+ line.
+
+ PRE: !ok, POST: add to top()
+
+ PRE: ok, POST: add before me
+
+ cursor points to same object, cursor.previous()
+ is newly inserted object.
+ */
+ /// remove and cleanup Link // HWN: backspace or del?
+ void remove();
+
+ /// access the list this came from
+ const List<T>& list() const ;
+ Link<T>* pointer();
+
+private:
+ List<T>& list_;
+ Link<T>* pointer_;
+};
+
+
+/**
+ add and insert extend the list
+ items are always stored as copies in List, but:
+ List<String> : copies of String stored
+ List<String*> : copies of String* stored!
+
+ the operations add and insert actually delegate the work to List class.
+ */
+
+
+
+/// cursor which feels like a pointer
+template<class T>
+struct PCursor : public Cursor<T> {
+
+ /// make cursor with #no# items back
+ PCursor<T> operator -( int no) const {
+ return PCursor<T> (Cursor<T>::operator-(no));
+ }
+
+ /// make cursor with #no# items further
+ PCursor<T> operator +( int no) const {
+ return PCursor<T> (Cursor<T>::operator+(no));
+ }
+ PCursor(List<T> & l) : Cursor<T> (l) {}
+
+ PCursor( const Cursor<T>& cursor ) : Cursor<T>(cursor) { }
+ T operator ->() { return *(*this); }
+
+};
+/**
+ HWN: I'd like an operator->(), so here it is.
+
+ Cursor to go with pointer list.
+ */
+
+#include "list.hh"
+#include "cursor.inl"
+
+#endif // __CURSOR_HH //
--- /dev/null
+ // cursor.inl
+#ifndef CURSOR_INL
+#define CURSOR_INL
+#include <assert.h>
+//#include "list.hh"
+
+template<class T>
+inline
+Cursor<T>::Cursor( List<T>& list, Link<T>* pointer ) :
+ list_( list )
+{
+ if ( list.size() )
+ pointer_ = pointer ? pointer : list.top().pointer_;
+ else
+ pointer_ = pointer;
+}
+
+template<class T>
+inline
+Cursor<T>::Cursor( const Cursor<T>& cursor ) :
+ list_( cursor.list_ )
+{
+ pointer_ = cursor.pointer_;
+}
+
+template<class T>
+inline T&
+Cursor<T>::operator *()
+{
+ assert( pointer_ );
+ return pointer_->thing();
+}
+
+template<class T>
+Cursor<T>
+Cursor<T>::operator =( const Cursor<T>& c )
+{
+ assert( &list_ == &c.list_ );
+ pointer_ = c.pointer_;
+ return *this;
+}
+
+template<class T>
+inline void
+Cursor<T>::add( const T& thing )
+{
+ list_.add( thing, *this );
+}
+
+template<class T>
+inline void
+Cursor<T>::insert( const T& thing )
+{
+ list_.insert( thing, *this );
+}
+
+template<class T>
+inline void
+Cursor<T>::remove()
+{
+ assert( pointer_ );
+ list_.remove( *this );
+}
+
+template<class T>
+inline const List<T>&
+Cursor<T>::list() const
+{
+ return list_;
+}
+
+template<class T>
+inline Link<T>*
+Cursor<T>::pointer()
+{
+ return pointer_;
+}
+
+template<class T>
+inline bool
+Cursor<T>::backward()
+{
+ return ( pointer_ != 0 );
+}
+
+template<class T>
+inline bool
+Cursor<T>::forward()
+{
+ return ( pointer_ != 0 );
+}
+
+template<class T>
+inline bool
+Cursor<T>::ok()
+{
+ return ( pointer_ != 0 );
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <fstream.h>
+#include <ctype.h>
+
+#include "textstr.hh"
+Text_stream::Text_stream(String fn)
+{
+ if (fn == "")
+ {
+ name = "<STDIN>";
+ f = stdin;
+ }
+
+ else
+ {
+ name = fn;
+ f = fopen(fn, "r");
+ }
+
+ if (!f) {
+ cerr <<__FUNCTION__<< ": can't open `" << fn << "'\n";
+ exit(1);
+ }
+
+ line_no = 1;
+ }
+
+void
+Text_stream::message(String s)
+{
+ cerr << "\n"<<get_name() << ": " << line()<<": "<<s<<endl;
+}
+
+void
+Data_file::gobble_white()
+{
+ char c;
+
+ while ((c=data_get()) == ' ' ||c == '\t')
+ if (eof())
+ break;
+
+ data_unget(c);
+}
+
+String
+Data_file::get_word()
+{// should handle escape seq's
+ String s;
+
+ while (1)
+ {
+ char c = data_get();
+
+ if (isspace(c) || eof())
+ {
+ data_unget(c);
+ break;
+ }
+
+
+ if (c == '\"')
+ {
+ rawmode= true;
+
+ while ((c = data_get()) != '\"')
+ if (eof())
+ error("EOF in a string");
+ else
+ s += c;
+
+
+ rawmode= false;
+ }
+ else
+ s += c;
+ }
+
+ return s;
+}
+
+/// get a char.
+char
+Data_file::data_get() {
+ char c = get();
+ if (!rawmode && c == '#') // gobble comment
+ {
+ while ((c = get()) != '\n' && !eof())
+ ;
+ return '\n';
+ }
+
+ return c;
+}
+/**
+ Only class member who uses text_file::get
+ */
+
+/// read line, gobble '\n'
+String Data_file::get_line()
+{
+ char c;
+ String s;
+
+ while ((c = data_get()) != '\n' && !eof())
+ s += c;
+ return s;
+}
+
+/// gobble stuff before first entry on a line.
+void
+Data_file::gobble_leading_white()
+{
+ char c;
+
+ // eat blank lines.
+ while (!eof())
+ {
+ c = data_get();
+ if (!isspace(c))
+ break;
+ }
+ data_unget(c);
+}
+
+
--- /dev/null
+template<class T, class U>
+class FindCursor : public Cursor<T>
+{
+public:
+ FindCursor( List<T>& list, Link<T>* pointer = 0 );
+ FindCursor( const Cursor<T>& cursor );
+
+ Cursor<T> operator =( const Cursor<T>& c );
+ FindCursor<T, U> find( const T& thing );
+};
+
+#include "findcurs.inl"
--- /dev/null
+template<class T, class U>
+inline
+FindCursor<T, U>::FindCursor( List<T>& list, Link<T>* pointer ) :
+ Cursor<T>( list, pointer )
+{
+}
+
+template<class T, class U>
+inline
+FindCursor<T, U>::FindCursor( const Cursor<T>& cursor ) :
+ Cursor<T>( cursor )
+{
+}
+
+template<class T, class U>
+Cursor<T>
+FindCursor<T, U>::operator =( const Cursor<T>& c )
+{
+ ( (Cursor<T>&)*this ) = c;
+ return *this;
+}
+
+template<class T, class U>
+inline FindCursor<T, U>
+FindCursor<T, U>::find( const T& thing )
+{
+ Cursor<T> c( *this );
+ while( c.forward() )
+ {
+ T& look = *c;
+ if ( U::equal( look, thing ) )
+ return c;
+ c++;
+ }
+
+ return FindCursor( *this ); // cursor is not .ok()
+}
--- /dev/null
+#ifndef HANDLE_HH
+#define HANDLE_HH
+/// reference counting handle
+template<class T>
+class Handle {
+ T *obj;
+ int *refs;
+
+ /// let go of ref. Delete if necessary
+ void down() {
+ if (!(*refs--)) {
+ delete obj;
+ delete refs;
+ }
+ obj = 0;
+ refs = 0;
+ }
+ /// point to new object.
+ void up(T *t, int *r=0) {
+ if (!r) {
+ refs = new int;
+ *refs = 1;
+ } else {
+ refs =r;
+ *refs++;
+ }
+ obj = t;
+ }
+ /// POST: *refs == 1
+ void copy() {
+ if(*refs != 1){
+ T * newobj = new T(*obj );
+ down();
+ up(newobj);
+ }
+ }
+ Handle(Handle const &src) {
+ up(src.obj, src.refs);
+ }
+ Handle(T & o) {
+ up (&o);
+ }
+ void operator=(Handle const& src) {
+ if (this == &src)
+ return;
+ down();
+ up(src.o, src.refs);
+ }
+ operator const T&() {
+ return *obj;
+ }
+ operator T&() {
+ copy();
+ return *obj;
+ }
+}
+#endif
--- /dev/null
+/*
+ process command line, GNU style.
+
+
+ this is (Copyleft) 1996, Han-Wen Nienhuys, <hanwen@stack.urc.tue.nl>
+ */
+#include <stdio.h>
+#include <iostream.h>
+#include <assert.h>
+#include "lgetopt.hh"
+
+long
+Getopt_long::intarg() {
+ long l;
+ if (sscanf(optarg, "%ld", &l) != 1)
+ report(E_ILLEGALARG);
+
+ return l;
+}
+long_option_init *
+Getopt_long::parselong() {
+ const char *optnm = argv[optind] + 2 ;
+ assert(*optnm);
+
+ char *endopt = strchr(optnm, '=');
+ int searchlen = (endopt) ? endopt - optnm : strlen(optnm);
+
+ beet=0;
+ for (int i=0; i< table_len; i++) {
+ const char *ln = the_opts[i].longname;
+
+ if (ln && !strncmp(ln, optnm, searchlen)) {
+ beet = the_opts+i;
+ break;
+ }
+ }
+
+ if (!beet) {
+ report(E_UNKNOWNOPTION);
+ return 0;
+ }
+ optind++;
+ optindind = 0;
+
+
+ if (beet->take_arg) {
+ if (endopt)
+ optarg = endopt +1; // a '='
+ else {
+ optarg = argv[optind];
+ optind++;
+ }
+ if (!optarg)
+ report(E_ARGEXPECT);
+
+ } else {
+ optarg = 0;
+ if (endopt)
+ report(E_NOARGEXPECT);
+ }
+
+ return beet;
+}
+
+
+ostream &
+long_option_init::printon(ostream &errorout)
+{
+ if (shortname)
+ errorout <<"-" << shortname;
+ if (shortname && longname)
+ errorout << ", ";
+ if (longname)
+ errorout << "`--" << longname << "'";
+ return errorout;
+}
+
+// report an error, GNU style.
+void
+Getopt_long::report(Errorcod c)
+{
+ error = c;
+ if (!errorout)
+ return;
+
+ *errorout << argv[0] << ": ";
+ switch (c) {
+ case E_ARGEXPECT:
+ *errorout<< "option ";
+ beet->printon(*errorout);
+ *errorout << "requires an argument"<<endl;
+ break;
+ case E_NOARGEXPECT:
+ *errorout << "option `--" << beet->longname << "' does not allow an argument"<<endl;
+ break;
+
+ case E_UNKNOWNOPTION:
+ *errorout << "unrecognized option ";
+ if (optindind)
+ *errorout << "-" << argv[optind][optindind] << endl;
+ else
+ *errorout << argv[optind] << endl;
+
+ break;
+ case E_ILLEGALARG:
+ *errorout << "illegal argument `" << optarg << "\'to option ";
+ beet->printon(*errorout);
+ *errorout << '\n';
+ default:
+ assert(false);
+ }
+ exit(2);
+}
+
+long_option_init *
+Getopt_long::parseshort() {
+ char c=argv[optind][optindind];
+ beet=0;
+ assert(c);
+
+ for (int i=0; i < table_len; i++)
+ if (the_opts[i].shortname == c) {
+ beet = the_opts+i;
+ break;
+ }
+
+ if (!beet){
+ report(E_UNKNOWNOPTION);
+ return 0;
+ }
+
+ optindind++;
+ if (!beet->take_arg){
+ optarg = 0;
+ return beet;
+ }
+ optarg = argv[optind] + optindind;
+
+ optind ++;
+ optindind = 0;
+
+ if (!optarg[0]) {
+ optarg = argv[optind];
+ optind ++;
+ }
+ if (!optarg) {
+ report(E_ARGEXPECT);
+ }
+
+ return beet;
+}
+
+long_option_init *
+Getopt_long::operator()() {
+ if (!next())
+ return 0;
+
+ if (optindind)
+ return parseshort();
+
+ if (argv[optind][0] != '-')
+ return 0;
+
+ if (argv[optind][1] == '-') {// what to do with "command -- bla"
+ return parselong();
+ } else {
+ optindind = 1;
+ return parseshort();
+ }
+}
+
+Getopt_long::Getopt_long(int c, char **v, long_option_init *lo) {
+ the_opts = lo;
+ errorout = &cerr;
+ argv = v;
+ argc = c;
+ optind = 1;
+ optindind = 0;
+
+ // reached end of option table?
+ int i;
+ for (i = 0; the_opts[i].longname ||the_opts[i].shortname; i++)
+ ;
+ table_len = i;
+}
+
+bool Getopt_long::next() {
+ error = E_NOERROR;
+ while (optind < argc && !argv[optind][optindind]) {
+ optind++;
+ optindind = 0;
+ }
+ return (optind < argc);
+}
+
+char *
+Getopt_long::current_arg()
+{
+ if (optind >= argc)
+ return 0;
+ char * a = argv[optind];
+ return a + optindind;
+}
+
+char *
+Getopt_long::get_next_arg()
+{
+ char * a = current_arg();
+ if ( a) {
+ optind ++;
+ optindind = 0;
+ }
+ return a;
+}
--- /dev/null
+#ifndef LGETOPT_HH
+#define LGETOPT_HH
+
+#include <string.h>
+
+
+class ostream;
+
+struct long_option_init {
+ bool take_arg;
+ const char* longname;
+ char shortname;
+
+ ostream &printon(ostream &errorout);
+};
+
+
+///
+class Getopt_long {
+public:
+ ///
+ enum Errorcod { E_NOERROR = 0, E_ARGEXPECT, E_NOARGEXPECT, E_UNKNOWNOPTION,
+ E_ILLEGALARG } ;
+
+ /** errorcodes: no error, argument expected, no argument expected,
+ unknown option, illegal argument (eg. int expected). */
+
+private:
+
+ /// the option info.
+ long_option_init *the_opts;
+ int table_len;
+
+ /// if doing short option, argv[optind][optindind] is processed next.
+ int optindind;
+
+ /// the option found
+ long_option_init *beet;
+
+ /// get ready for processing next error.
+ bool next();
+ long_option_init *parselong();
+ long_option_init *parseshort();
+
+ ostream *errorout;
+
+ /// report an error and abort
+ void report(Errorcod c);
+public:
+ /// what to do with errors
+ void seterror(ostream *os);
+ /**
+ report messages on #*os#, and abort.
+ if #os# is null, then do not report nor abort, just set #error#
+ */
+
+ /// argument. Set to 0 if not present
+ char* optarg;
+
+
+ /// return an integer (with err. detect)
+ long intarg();
+ /// argv[optind] will be processed next.
+ int optind;
+
+ /// the arguments
+ char **argv;
+
+ /// the arg. count
+ int argc;
+
+ /// construct: pass arguments and option info.
+ Getopt_long(int c, char **v, long_option_init *lo);
+
+ /// get the next option
+ long_option_init *operator()();
+ /**
+ RETURN: pointer to next option found.
+ 0 if error occurred, or next argument is no option.
+ */
+
+ char *current_arg();
+ char * get_next_arg();
+ Errorcod error;
+};
+/**
+ C++ for version of long_getopt. For processing GNU style command line arguments.
+ No pointer (return values, arguments) contents are copied.
+ */
+#endif
--- /dev/null
+// link.hh
+
+#ifndef __LINK_HH
+#define __LINK_HH
+template<class T>
+class List;
+
+
+/// class for List
+template<class T>
+class Link
+{
+// friend class Cursor<T>;
+public:
+ Link( const T& thing );
+
+ Link<T>* previous();
+ Link<T>* next();
+
+ /// put new Link item after me in list
+ void add( const T& thing );
+ /// put new Link item before me in list
+ void insert( const T& thing );
+ void remove(List<T> &l);
+
+ T& thing();
+ void OK() const;
+private:
+ Link( Link<T>* previous, Link<T>* next, const T& thing );
+
+ T thing_;
+ Link<T>* previous_;
+ Link<T>* next_;
+};
+
+#include "link.inl"
+
+#endif // __LINK_HH //
--- /dev/null
+// link.inl -*-c++-*-
+#ifndef LINK_INL
+#define LINK_INL
+#include <assert.h>
+template<class T>
+inline
+void
+Link<T>::OK() const
+{
+ if (previous_) {
+ assert(previous_->next_ == this);
+ }
+ if (next_) {
+ assert(next_->previous_ == this);
+ }
+}
+
+template<class T>
+inline
+Link<T>::Link( const T& thing ) :
+ thing_( thing )
+{
+ previous_ = next_ = 0;
+}
+
+template<class T>
+inline
+Link<T>::Link( Link<T>* previous, Link<T>* next, const T& thing ) :
+ thing_( thing )
+{
+ previous_ = previous;
+ next_ = next;
+}
+
+template<class T>
+inline
+Link<T>*
+Link<T>::next()
+{
+ return next_;
+}
+
+template<class T>
+inline
+Link<T>*
+Link<T>::previous()
+{
+ return previous_;
+}
+
+template<class T>
+inline
+void
+Link<T>::add( const T& thing )
+{
+
+ Link<T>* l = new Link<T>( this, next_, thing );
+ if ( next_ )
+ next_->previous_ = l;
+ next_ = l;
+}
+
+template<class T>
+inline void
+Link<T>::insert( const T& thing )
+{
+ // Link<T>* l = new Link<T>( next_, this, thing );
+ // bugfix hwn 16/9/96
+ Link<T>* l = new Link<T>( previous_, this, thing );
+ if ( previous_ )
+ previous_->next_ = l;
+ previous_ = l;
+}
+
+/*
+ don't forget to adjust #l#'s top_ and bottom_.
+ */
+template<class T>
+inline void
+Link<T>::remove(List<T> &l)
+{
+ if ( previous_ )
+ previous_->next_ = next_;
+ else
+ l.top_ = next_;
+
+ if ( next_ )
+ next_->previous_ = previous_;
+ else
+ l.bottom_ = previous_;
+}
+
+template<class T>
+inline
+T&
+Link<T>::thing()
+{
+ return thing_;
+}
+#endif
--- /dev/null
+#ifndef LIST_CC
+#define LIST_CC
+
+#include "list.hh"
+
+template<class T>
+void
+List<T>::OK() const
+{
+ int i = size_;
+ Link<T> *lp = top_;
+ while (i--) {
+ assert(lp);
+ lp->OK();
+ lp = lp->next();
+ }
+ assert(!lp);
+ i = size_;
+ lp = bottom_;
+ while (i--) {
+ assert(lp);
+ lp->OK();
+ lp = lp->previous();
+ }
+ assert(!lp);
+}
+
+template<class T>
+Cursor<T>
+List<T>::top()
+{
+
+ // ?? waarvoor is deze if ?
+ if ( top_ ) // equivalent: if ( size_ )
+ {
+ Link<T>* t = top_->previous();
+ assert( t != top_ ); // silly link
+ while ( t )
+ {
+ top_ = t;
+ t = top_->previous();
+ }
+ }
+ // list empty: Cursor not ok()
+ return Cursor<T>( *this, top_ );
+}
+
+
+template<class T>
+Cursor<T>
+List<T>::bottom()
+{
+ /* wat is dit voor zooi? kan dit niet weg?
+
+ (invarianten!)
+ */
+ if ( bottom_ ) // equivalent: if ( size_ )
+ {
+ Link<T>* b = bottom_->next();
+ assert( b != bottom_ ); // silly link
+ while ( b )
+ {
+ bottom_ = b;
+ b = bottom_->next();
+ }
+ }
+ // list empty: Cursor not ok()
+ return Cursor<T>( *this, bottom_ );
+}
+
+
+// not inlined since it assumes knowledge of destructor.
+template<class T>
+inline void
+PointerList<T>::remove( Cursor<T> me )
+{
+ if ( me.ok() )
+ {
+
+ delete *me;
+ List<T>::remove( me );
+ }
+}
+
+
+
+
+#endif
--- /dev/null
+// list.hh
+
+#ifndef __LIST_HH
+#define __LIST_HH
+
+class ostream;
+template<class T> class Cursor;
+template<class T> class Link;
+
+/// all purpose list
+template<class T>
+class List
+{
+ public:
+ /// construct empty list
+ List();
+
+ /// construct list from first item.
+ List( const T& thing );
+
+ virtual ~List();
+
+ Cursor<T> bottom();
+
+ int size() const;
+ Cursor<T> top();
+ void OK() const;
+ protected:
+ friend class Cursor<T>;
+ friend class Link<T>;
+
+ /// add after after_me
+ void add( const T& thing, Cursor<T> after_me );
+
+ /// put thing before #before_me#
+ void insert( const T& thing, Cursor<T> before_me );
+ virtual void remove( Cursor<T> me );
+
+ int size_;
+ Link<T>* top_;
+ Link<T>* bottom_;
+};
+/**
+ a doubly linked list;
+ List can be seen as all items written down on paper,
+ from top to bottom
+
+ class Cursor is used to extend List
+
+ items are always stored as copies in List, but:
+ #List<String># : copies of #String# stored
+ #List<String*># : copies of #String*# stored!
+ (do not use, use \Ref{PointerList}#<String*># instead.)
+
+ {\bf note:}
+ retrieving "invalid" cursors, i.e.
+ #top()/bottom()# from empty list, #find()# without success,
+ results in a nonvalid Cursor ( #!ok()# )
+
+
+ INVARIANTEN!
+*/
+
+
+/// Use for list of pointers, e.g. PointerList<AbstractType*>.
+template<class T>
+class PointerList : public List<T>
+{
+ public:
+ PointerList();
+ PointerList( const T& thing );
+
+ ///
+ virtual ~PointerList();
+ /**
+ This function deletes deletes the allocated pointers of all links.
+ #\Ref{~List}# is used to delete the links themselves.
+ */
+
+ protected:
+ virtual void remove( Cursor<T> me );
+};
+
+#include "list.inl"
+#include "cursor.hh"
+
+// instantiate a template: explicit instantiation.
+#define L_instantiate(a) template class List<a>; template class Cursor<a>; \
+ template class Link<a>
+#define PL_instantiate(a) L_instantiate(a *); template class PointerList<a*>
+
+#endif // __LIST_HH //
+
+
+
+
--- /dev/null
+// -*-c++-*-
+#ifndef LIST_INL
+#define LIST_INL
+template<class T>
+inline
+List<T>::List()
+{
+ top_ = bottom_ = 0;
+ size_ = 0;
+}
+
+template<class T>
+inline
+List<T>::List( const T& thing )
+{
+ top_ = bottom_ = 0;
+ size_ = 0;
+ add( thing, Cursor<T>( *this, bottom_ ) );
+}
+
+template<class T>
+inline
+List<T>::~List()
+{
+ for ( Cursor<T> c( *this ); c.forward(); c++ )
+ remove( c );
+}
+
+template<class T>
+inline void
+List<T>::add( const T& thing, Cursor<T> after_me )
+{
+#if 0
+ if ( after_me.ok() )
+ after_me.pointer()->add( thing );
+ else if ( size_ )
+ bottom().pointer()->add( thing );
+ else
+ bottom_ = top_ = new Link<T>( thing );
+#endif
+
+ if (!size_) { // not much choice if list is empty
+ bottom_ = top_ = new Link<T>( thing );
+ } else { // add at aprioprate place
+ Link<T> *p = ( after_me.ok() ) ?
+ after_me.pointer() : bottom().pointer();
+ p->add(thing);
+ if (p == bottom_) // adjust bottom_ if necessary.
+ bottom_ = p->next();
+ }
+
+ size_++;
+}
+/**
+
+ Procedure:
+ \begin{itemize}
+ \item if #after_me# is #ok()#, add after #after_me#, else
+ \item if list !empty simply add to bottom, else
+ \item list is empty: create first \Ref{Link} and initialize
+ #bottom_# and #top_#.
+ \end{itemize}
+*/
+
+template<class T>
+inline void
+List<T>::insert( const T& thing, Cursor<T> before_me )
+{
+ if (!size_) {
+ bottom_ = top_ = new Link<T>( thing );
+ } else {
+ Link<T> *p =
+ (before_me.ok())?
+ before_me.pointer() : top().pointer();
+
+ p->insert(thing);
+ if (p == top_)
+ top_ = p->previous();
+ }
+
+ size_++;
+#if 0 // rewrite hwn 16/9
+ if ( before_me.ok() )
+ before_me.pointer()->insert( thing );
+ else if ( size_ )
+ top().pointer()->insert( thing );
+ else
+ bottom_ = top_ = new Link<T>( thing );
+ size_++;
+#endif
+}
+
+template<class T>
+inline void
+List<T>::remove( Cursor<T> me )
+{
+ if ( me.ok() )
+ {
+ me.pointer()->remove(*this);
+ delete me.pointer();
+ size_--;
+ }
+}
+
+template<class T>
+inline int
+List<T>::size() const
+{
+ return size_;
+}
+
+template<class T>
+inline
+PointerList<T>::PointerList() :
+ List<T>()
+{
+}
+
+template<class T>
+inline
+PointerList<T>::PointerList( const T& thing ) :
+ List<T>( thing )
+{
+}
+
+template<class T>
+inline
+PointerList<T>::~PointerList()
+{
+ for ( Cursor<T> c( *this ); c.forward(); c++ )
+ remove( c );
+}
+
+template<class T>
+inline void
+PointerList_print( PointerList<T> const & l )
+{
+ List<T>& promises_to_be_const = (List<T>&) l;
+ for ( Cursor<T> c( promises_to_be_const ); c.forward(); c++ )
+ (*c)->print();
+}
+
+
+#endif
--- /dev/null
+/****************************************************************************
+ PROJECT: FlowerSoft C++ library
+ FILE : string.cc
+
+ Rehacked by HWN 3/nov/95
+ removed String &
+ introduced Class String_handle
+--*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+//#include "globals.hh"
+#include "string.hh"
+
+char* strlwr( char* s )
+{
+ char* p = s;
+
+ while( *p )
+ {
+ *p = tolower( *p ); /* a macro on some compilers */
+ p++;
+ }
+ return s;
+}
+
+char* strupr( char* s )
+{
+ char* p = s;
+
+ while( *p )
+ {
+ *p = toupper( *p ); /* a macro on some compilers */
+ p++;
+ }
+ return s;
+}
+
+// return array, alloced with new.
+char *
+String::copy_array() const
+{
+ const char *src = data;
+ char *dest = new char[data.len() + 1];
+ strcpy(dest, src);
+ return dest;
+}
+
+void
+String::printOn(ostream& os) const
+{
+ os << (const char*) data;
+}
+
+String::String (bool b)
+{
+ *this = (const char *) (b ? "true" : "false");
+}
+String::String( const char* source )
+{
+ assert(source);
+ data = source;
+}
+
+void
+String::operator +=(String s)
+{
+ *this += (const char *) s;
+}
+
+int
+String::len() const
+{
+ return data.len();
+}
+
+String::String(char c, int n)
+{
+ int l = n;
+ assert(n >= 0 && n <= 80); // what the fuck is 80?
+//min(max( n, 0 ), 80);
+ char s[81];
+ memset(s, c, l);
+ s[l] = 0;
+ data = s;
+}
+
+String::String(int i)
+{
+ char digits[ 81 ]; // who the FUCK is 80???
+ digits[ 0 ] = '\0';
+ sprintf(digits, "%d", i ); // assume radix 10
+ data = digits;
+}
+
+String::String( const int i, const int n, const char c )
+{
+ char fillChar = c;
+ if ( fillChar)
+ fillChar = '0';
+
+ String v( i );
+
+ data = String( fillChar, n - v.len() ) + String( v );
+ // String convd to const char *
+}
+
+ const char*
+String::ptr() const
+{
+ return data;
+}
+
+
+
+#ifdef CENTRAL_OBJECT // everything derived from Sortable object
+// comparisons.
+int
+String::operator ==( const Sortable& test ) const
+{
+ const String *s = (const String *) &test;
+ return *this == *s;
+}
+
+int
+String::operator &&(const Object& test) const
+{
+ const String *s = (const String *) &test;
+
+ int i = min( len(), s->len() );
+ return ( i > 0 ) ?
+ ( !strncmp( data, s->data, i ) ) : 0;
+}
+
+int
+String::operator >( const Sortable& test ) const
+{
+ const String *s = (const String *) &test;
+ return strcmp( data, s->data ) > 0;
+}
+#endif
+
+// signed comparison, analogous to strcmp;
+int
+String::compare( const char* test ) const
+{
+ if (test == (const char *) data)
+ return 0;
+
+ return strcmp(data, test);
+}
+
+
+int
+String::lastPos( const char c ) const
+{
+ const char *me = data;
+ int pos = 0;
+ if ( len() )
+ {
+ const char* p = strrchr(me, c );
+ if ( p )
+ pos = p - me + 1;
+ }
+ return pos;
+}
+
+int
+String::lastPos( const char* string ) const
+{
+ int pos = 0;
+ int length = strlen( string );
+ if ( len() && length )
+ {
+ int nextpos = this->pos( string );
+ while( nextpos )
+ {
+ pos += nextpos;
+ nextpos = right( len() - pos - length + 1 ).pos( string );
+ }
+ }
+ return pos;
+}
+
+// find c
+// return 0 if not found.
+
+// ? should return len()?, as in string.left(pos(delimiter))
+int
+String::pos(char c ) const
+{
+ const char *me = data;
+ int pos = 0;
+ if ( len() )
+ {
+ const char* p = strchr( me, c );
+ if ( p )
+ pos = p - me + 1;
+ }
+ return pos;
+}
+
+// find searchfor. (what if this == "" && searchfor == "") ???
+int
+String::pos( const char* searchfor ) const
+{
+ const char *me = data;
+ int pos = 0;
+ if ( len() && searchfor)
+ {
+ const char* p = strstr(me, searchfor);
+ if ( p )
+ pos = p - me + 1;
+ }
+ return pos;
+}
+
+// find chars of a set.
+int
+String::posAny( const char* string ) const
+{
+ int pos = 0;
+ const char *s = (const char *)data;
+ if ( len() && string )
+ {
+ const char* p = strpbrk( s, string );
+ if ( p )
+ pos = p - s + 1;
+ }
+ return pos;
+}
+
+String
+String::left( int n ) const
+{
+ if (n >= len())
+ return *this;
+
+ String retval;
+ if (n < 1)
+ return retval;
+
+ retval = *this;
+ retval.data.trunc(n);
+ return retval;
+}
+
+
+// n rightmst chars
+String
+String::right( int n ) const
+{
+ if (n > len())
+ return *this;
+
+ String retval;
+ if ( n < 1)
+ return retval;
+
+ const char *src = (const char *)data + len() - n;
+ retval += src;
+
+ return retval;
+}
+
+
+String
+String::nomid( const int pos, const int n ) const
+{
+ String retval;
+
+ if ( pos < 1 )
+ return String("");
+ if ( pos > len())
+ return *this;
+
+ return String( String( left( pos - 1 ) ) + right( len() - pos - n + 1 ));
+}
+
+
+String
+String::mid( int pos, int n ) const
+{
+ String retval;
+
+ // HWN. This SUX:
+ // pos 1 == data->string[ 0 ];
+ // pos 0 allowed for convenience
+ if ( !len() || ( pos < 0 ) || ( pos > len() ) && ( n < 1 ) )
+ return retval;
+
+ retval = ((const char *) data) + pos -1;
+ if (n > retval.len())
+ n =retval.len();
+ retval.data.trunc(n);
+ return retval;
+}
+
+
+// to uppercase
+String
+String::upper()
+{
+ char *s = data.array_for_modify();
+ strupr(s );
+ return *this;
+}
+
+
+// to lowercase
+String String::lower()
+{
+ char *s = data.array_for_modify();
+ strlwr(s);
+ return *this;
+}
+
+String::String (double f, const char *fmt)
+{
+ char buf[100]; // ugly
+ if (!fmt)
+ sprintf(buf, "%f", f);
+ else
+ sprintf(buf, fmt,f);
+ *this = buf;
+}
+
+long
+String::value() const
+{
+ long l =0;
+ if (len()) {
+ int conv = sscanf(data, "%ld", &l);
+ assert(conv);
+ }
+ return l;
+}
+
+double
+String::fvalue() const
+{
+ double d =0;
+ if (len()) {
+ int conv = sscanf(data, "%lf", &d);
+ assert(conv);
+ }
+ return d;
+}
+
+
+String quoteString( String msg, String quote)
+{
+ return msg + " `" + quote + "' ";
+}
+
+
+char *strrev(char *s)
+{
+ char c;
+ char *p = s;
+ char *q = s + strlen(s) - 1;
+
+ while (q > p) {
+ c = *p;
+ *p++ = *q;
+ *q-- = c;
+ }
+ return s;
+}
+
+
+String
+String::reversed() const
+{
+ String retval=*this;
+ char *s = retval.data.array_for_modify();
+ strrev(s);
+ return retval;
+}
+bool
+String::to_bool() const
+{
+ if (!len())
+ return false;
+ if (*this == "0")
+ return false;
+ String u (*this);
+ u.upper();
+ if (u== "FALSE")
+ return false;
+ return true;
+}
--- /dev/null
+/*
+
+ FILE : string.hh -- implement String inline helper classes,
+ and declare stringclass.
+
+
+ Rehacked by HWN 3/nov/95
+ removed String & 's
+ introduced Class String_handle
+ */
+
+#ifndef STRING_HH
+#define STRING_HH
+
+
+#include <string.h>
+#include <iostream.h>
+
+
+#include "stringutil.hh"
+
+/// the smart string class.
+class String
+{
+protected:
+ String_handle data; // should derive String from String_handle?
+
+public:
+ /// init to ""
+ String() { }
+ /** needed because other constructors are provided.*/
+
+ /// String s = "abc";
+ String( const char* source );
+
+ /// "ccccc"
+ String( char c, int n = 1 );
+
+ /// String s( 10 );
+ String( int i );
+
+ /// 'true' or 'false'
+ String(bool );
+
+ /// String s( 3.14, 6, '#' );
+ String ( double f , const char *fmt =0);
+ String( int i, int n, char c = ' ' );
+
+ /// return a "new"-ed copy of contents
+ char *copy_array() const; // return a "new"-ed copy of contents
+
+ const char *ptr() const;
+ /// return the data. Don't use for writing the data.
+ operator const char *() const { return ptr(); }
+
+ String operator =( const String & source ) { data = source.data; return *this; }
+
+ /// concatenate s
+ void operator += (const char *s) { data += s; }
+ void operator += (String s);
+
+ char operator []( int n ) const { return data[n]; }
+
+ /// return n leftmost chars
+ String left( int n ) const;
+
+ /// return n rightmost chars
+ String right( int n ) const;
+
+ /// convert this to upcase
+ String upper();
+
+ /// convert this to downcase
+ String lower(); // & ??
+
+ /// return the "esrever" of *this
+ String reversed() const;
+
+
+ /// return a piece starting at pos (first char = pos 1), length n
+ String mid(int pos, int n ) const;
+
+ /// cut out a middle piece, return remainder
+ String nomid(int pos, int n ) const;
+
+ /// signed comparison, analogous to strcmp;
+ int compare( const char* s ) const;
+
+ /// index of rightmost c
+ int lastPos( char c) const;
+ /// index of rightmost element of string
+ int lastPos( const char* string ) const;
+
+ /// index of leftmost c
+ int pos(char c ) const;
+ /**
+ RETURN:
+ 0 if not found, else index + 1
+ */
+ int pos(const char* string ) const;
+ int posAny(const char* string ) const;
+
+
+ /// provide Stream output
+ void printOn(ostream& os) const;
+
+ /// convert to an integer
+ long value() const;
+
+ /// convert to a double
+ double fvalue() const;
+
+ /// the length of the string
+ int len() const;
+
+ /// DO NOT MAKE THIS INTO AN OPERATOR
+ bool to_bool() const;
+ /** perl -like string to bool conversion
+ */
+};
+/**
+
+ Intuitive string class. provides
+
+ ref counting thru #String_handle#
+
+ conversion from bool, int, double, char *, char.
+
+ conversion to int, upcase, downcase
+
+
+ printable.
+
+ indexing (pos, posAny, lastPos)
+
+ cutting (left, right, mid)
+
+ concat (+=, +)
+
+ signed comparison (<, >, ==, etc)
+
+ No operator[] is provided, since this would be enormously slow. If needed,
+ convert to const char *.
+*/
+
+
+// because const char* also has an operator ==, this is for safety:
+inline bool operator==(String s1, String s2){ return !(s1.compare(s2));}
+inline bool operator==(String s1, const char *s2){ return !(s1.compare(s2));}
+inline bool operator==(const char *s1, String s2){ return !(s2.compare(s1));}
+inline bool operator!=(String s1, const char *s2 ) { return s1.compare(s2);}
+inline bool operator!=(const char *s1,String s2) { return s2.compare(s1);}
+inline bool operator!=(String s1, String s2 ) { return s1.compare(s2);}
+
+inline String
+operator + (String s1, String s2)
+{
+ s1 += s2;
+ return s1;
+}
+
+inline ostream &
+operator << ( ostream& os, String d )
+{
+ d.printOn(os);
+ return os;
+}
+
+
+String quoteString(String message, String quote);
+
+#endif
--- /dev/null
+#ifndef STRINGUTIL_HH
+#define STRINGUTIL_HH
+#include <assert.h>
+
+#ifndef EVELYN
+#define NDEBUG BLONDE
+ // switching into "blonde" mode
+ // i trust stringclass nowadays.
+#endif
+
+class String_handle;
+/// Internal String struct
+class StringData {
+ // GNU malloc: storage overhead is 8 bytes anyway.
+ const int INITIALMAX = 8;
+
+friend class String_handle;
+ int maxlen; // maxlen is arraysize-1
+
+ int length;
+ char* string;
+ int references;
+
+ /// init to ""
+ StringData() {
+ references=0;
+ maxlen = INITIALMAX;
+ string = new char[maxlen + 1];
+ string[0] = 0;
+ length = 0;
+ }
+
+ /// init from src. Conservative allocation.
+ StringData(StringData const &src) {
+ references=0;
+ maxlen = length = src.length;
+ string = new char[maxlen+1]; // should calc GNU 8byte overhead.
+ strcpy(string, src.string);
+ }
+
+ ~StringData() {
+ assert(references == 0);
+ delete[] string;
+ }
+
+
+ void setmax(int j) {
+ OKW();
+ if (j > maxlen) {
+ delete string;
+ maxlen = j;
+ string = new char[maxlen + 1];
+
+ string[0] = 0;
+ length = 0;
+ }
+ }
+ /** POST: maxlen >= j.
+ IN: j, maximum stringlength.
+ contents thrown away.
+ */
+ ///
+ void remax(int j) {
+ OKW();
+ if (j > maxlen) {
+ maxlen = j;
+ char *p = new char[maxlen + 1];
+ strcpy(p,string);
+ delete[] string;
+ string = p;
+ // length = strlen(string);
+ }
+ }
+ /** POST: maxlen >= j.
+ IN: j, maximum stringlength.
+ contents are kept if it grows.
+ */
+ /// check if writeable.
+ void OKW() {
+
+ assert (references == 1);
+
+ }
+
+ /// check state.
+ void OK() {
+ assert(strlen(string) == size_t(length));
+ assert(maxlen >= length);
+ assert(bool(string));
+ assert(references >= 1);
+ }
+
+ // needed?
+ void update() {
+ length = strlen (string);
+ }
+
+ /// reduce memory usage.
+ void tighten() { // should be dec'd const
+ maxlen = length;
+ char *p = new char[maxlen + 1];
+ strcpy(p,string);
+ delete[] string;
+ string = p;
+ }
+
+ // assignment.
+ void set(const char *s) {
+ OKW();
+
+ assert(s);
+
+ length = strlen (s);
+ remax(length);
+ strcpy(string,s);
+ }
+
+ /// concatenation.
+ void operator += (const char *s) {
+ OK();
+ OKW();
+ int old = length;
+
+ length += strlen(s);
+ remax (length);
+ strcpy(string + old, s);
+ }
+
+ /// the array itself
+ operator const char *() const { return string; }
+
+ // idem, non const
+ char *array_for_modify() {
+ OKW();
+ return string;
+ }
+ void trunc(int j) {
+ OKW();
+ assert(j >= 0 && j <= length);
+ string[j] = 0;
+ length = j;
+ }
+
+ /** not really safe. Can alter length without StringData knowing it.
+ */
+ char &operator [](int j) {
+ assert(j >= 0 && j <= length);
+ return string[j] ;
+ }
+
+ char operator [](int j) const {
+ assert(j >= 0 && j <= length);
+ return string[j];
+ }
+};
+
+/**
+ the data itself. Handles simple tasks (resizing, resetting)
+ */
+/****************************************************************/
+/// ref. counting for strings
+class String_handle {
+ StringData* data;
+
+ /// decrease ref count. Named kind of like a Tanenbaum semafore
+ void down() { if (!(--data->references)) delete data; data = 0; }
+
+ /// increase ref count
+ void up(StringData *d) { data=d; data->references ++; }
+
+ /** make sure data has only one reference.
+ POST: data->references == 1
+ */
+ void copy() {
+ if (data->references !=1){
+ StringData *newdata = new StringData(*data);
+ down();
+ up(newdata);
+ }
+ }
+
+public:
+
+ String_handle() {
+ up(new StringData);
+ }
+ ~String_handle() {
+ down();
+ }
+ String_handle(String_handle const & src) {
+ up(src.data);
+ }
+
+ /// retrieve the actual array.
+ operator const char *() const { return *data; }
+ char *array_for_modify() {
+ copy();
+ return data->array_for_modify();
+ }
+
+ void operator =(String_handle const &src) {
+ if (this == &src)
+ return;
+ down();
+ up(src.data);
+ }
+
+ void operator += (const char *s) {
+ copy();
+ *data += s;
+ }
+
+
+ char operator[](int j) const { return (*data)[j]; }
+
+ // !NOT SAFE!
+ // don't use this for loops. Use array_for_modify()
+ char &operator[](int j) {
+ copy(); // hmm. Not efficient
+ return data->array_for_modify()[j];
+ }
+
+ void operator = (char const *p) {
+ copy();
+ data->set(p);
+ }
+
+ void trunc(int j) { copy(); data->trunc(j); }
+ int len() const { return data->length; }
+};
+/**
+ handles ref. counting, and provides a very thin
+ interface using char *
+ */
+
+
+#ifdef NDEBUG
+#if (NDEBUG == BLONDE)
+#undef NDEBUG
+#endif
+#endif
+
+
+
+#endif // STRINGUTIL_HH
--- /dev/null
+#include "textdb.hh"
+bool
+Text_db::eof()
+{
+ Data_file::gobble_leading_white();
+ return Data_file::eof();
+}
+
+void
+Text_db::gobble_leading_white()
+{
+ while (1) {
+ Data_file::gobble_leading_white();
+ if (eof())
+ return ;
+ char c;
+ if ((c = data_get()) !='\n'){
+ data_unget (c);
+ return ;
+ }
+ }
+}
+
+
+Text_record
+Text_db::get_record()
+{
+ while (1) {
+ String s;
+ svec<String> fields;
+ assert(!eof());
+
+ while ((s = get_word()) != "")
+ {
+ fields.add(s);
+ gobble_white();
+ }
+
+
+ if (get_line() != "")
+ assert(false);
+
+ assert (fields.sz());
+ return Text_record(fields, get_name(), line());
+ }
+}
+
+
--- /dev/null
+#ifndef TEXTDB_HH
+#define TEXTDB_HH
+
+#include "textstr.hh"
+
+/**: do "#" comments, read quote enclosed fields */
+
+/// a "const" svec. Contents can't be changed.
+class Text_record : svec<String>
+{
+ int line_no;
+ String filename;
+
+public:
+ Text_record() { } // needed because of other ctor
+
+ /// report an error in this line.
+ message(String s) {
+ cerr << '\n'<< filename << ": "<< line_no << s << "\n";
+ }
+ String operator[](int j) {
+ return svec<String>::operator[](j);
+ }
+
+ Text_record(svec<String> s, String fn, int j) : svec<String>(s) {
+ filename = fn; line_no = j;
+ }
+ svec<String>::sz;
+};
+
+/// abstraction for a datafile
+class Text_db : private Data_file
+{
+ void gobble_leading_white();
+public:
+ /// get a line with records
+ Text_record get_record();
+
+ Text_db(String fn):Data_file(fn) { }
+ Data_file::error;
+ bool eof();
+
+ /// get next line.
+ Text_record operator++(int) {
+ return get_record();
+ }
+ /// are we done yet?
+ operator bool() {
+ return !eof();
+ }
+};
+
+
+/**
+ add a subrec/fieldsep/record separator
+ */
+#endif
--- /dev/null
+#include <stdio.h>
+#include <ctype.h>
+
+//#include "globals.hh"
+#include "string.hh"
+#include "vray.hh"
+
+/// line counting input stream.
+class Text_stream
+{
+ int line_no;
+
+ // could just have used streams.
+ FILE *f;
+ sstack<char> pushback;
+ String name;
+
+ public:
+ Text_stream(String fn);
+ String get_name() { return name; }
+ bool eof() {
+ return feof(f);
+ }
+ bool eol() {
+ return (peek() == '\n');
+ }
+ char peek() {
+ char c = get();
+ unget(c);
+ return c;
+ }
+ int line(){
+ return line_no;
+ }
+
+ char get() {
+ char c;
+
+ if (pushback.empty())
+ c = getc(f);
+ else
+ c = pushback.pop();
+
+ if (c =='\n')
+ line_no++;
+ return c;
+ }
+ void unget(char c) {
+ if (c =='\n')
+ line_no--;
+ pushback.push(c);
+ }
+ ~Text_stream (){
+ if (!eof())
+ cerr <<__FUNCTION__<< ": closing unended file";
+
+ fclose(f);
+ }
+
+ /// GNU format message.
+ void message(String s);
+};
+/**
+ a stream for textfiles. linecounting. Thin interface getchar and
+ ungetchar. (ungetc is unlimited)
+
+ should protect get and unget against improper use
+*/
+
+
+/// read a data file
+class Data_file : private Text_stream
+{
+
+ public:
+ bool rawmode;
+
+ Text_stream::line;
+ Text_stream::eof;
+ Text_stream::get_name;
+
+ char data_get();
+ void data_unget(char c) {
+ unget(c);
+ }
+
+ /// read line, eat #\n#
+ String get_line();
+
+ /// read a word till next space, leave space. Also does quotes
+ String get_word();
+
+ /// gobble horizontal white stuff.
+ void gobble_white();
+
+ /// gobble empty stuff before first field.
+ void gobble_leading_white();
+ Data_file(String s) : Text_stream(s) {
+ //*mlog << "(" << s << flush;
+ rawmode= false;
+ }
+
+ ~Data_file() {
+ // *mlog << ")"<<flush;
+ }
+
+ warning(String s) {
+ message("warning: " + s);
+ }
+ error(String s){
+ message(s);
+ exit(1);
+ }
+};
--- /dev/null
+#include "unionfind.hh"
+/*
+ see a book on data structures
+ */
+
+Union_find::Union_find(int n)
+{
+ classes.set_size(n);
+
+ for (int i=0; i < n; i++) {
+ classes[i] = i;
+ }
+}
+
+int
+Union_find::find(int i)
+{
+ int rep = i;
+ while (classes[rep] != rep)
+ rep = classes[rep];
+ while (classes[i] != rep) {
+ int next =classes[i];
+ classes[i] = rep;
+ i = next;
+ }
+ return rep;
+}
+
+void
+Union_find::connect(int i, int j)
+{
+ i = find(i);
+ j = find(j);
+ classes[i] = j;
+}
--- /dev/null
+#ifndef UNIONFIND_HH
+#define UNIONFIND_HH
+#include "vray.hh"
+
+/// which points of a graph are connected?
+struct Union_find {
+ void connect(int i, int j);
+ int find(int i);
+ bool equiv(int i, int j) { return find(i) == find(j); }
+ Union_find(int sz);
+
+private:
+ svec<int> classes;
+
+};
+/*
+ Union find, a standard algorithm:
+
+ Union_find represents an undirected graph of N points. You can
+ connect two points using #connect()#. #find(i)# finds a uniquely
+ determined representant of the equivalence class of points
+ connected to #i#.
+
+ */
+#endif
--- /dev/null
+/*
+ (c) Han-Wen Nienhuys 1995,96
+
+ Distributed under GNU GPL
+*/
+
+#ifndef SVEC_H
+#define SVEC_H
+#include <assert.h>
+
+/// copy a bare (C-)array from #src# to #dest# sized #count#
+template<class T>
+inline void arrcpy(T*dest, T*src, int count) {
+ for (int i=0; i < count ; i++)
+ *dest++ = *src++;
+}
+
+///scaleable array template, for T with def ctor.
+template<class T>
+class svec {
+protected:
+
+ int max;
+
+ /// the data itself
+ T *thearray;
+
+ /// stretch or shrink array.
+ void remax(int newmax) {
+ T* newarr = new T[newmax];
+ size = (newmax < size) ? newmax : size;
+ arrcpy(newarr, thearray, size);
+
+ delete[] thearray;
+ thearray = newarr;
+ max = newmax;
+ }
+ int size;
+
+public:
+ /// check invariants
+ void OK() const {
+ assert(max >= size && size >=0);
+ if (max) assert(thearray);
+ }
+ /// report the size. See {setsize}
+ int sz() const { return size; }
+
+ /// POST: sz() == 0
+ void clear() { size = 0; }
+
+ svec() { thearray = 0; max =0; size =0; }
+ /// set the size to #s#
+ void set_size(int s) {
+ if (s >= max) remax(s);
+ size = s;
+ }
+ /** POST: sz() == s.
+ Warning: contents are unspecified */
+
+ ~svec() { delete[] thearray; }
+
+ /// return a "new"ed copy of array
+ T* copy_array() const {
+ T* Tarray = new T[size];
+ arrcpy(Tarray, thearray, size);
+ return Tarray;
+ }
+ // depracated
+ operator T* () const {
+ return copy_array();
+ }
+ void operator=(svec const & src) {
+ set_size (src.size);
+ arrcpy(thearray,src.thearray, size);
+ }
+ svec(const svec & src) {
+ thearray = src.copy_array();
+ max = size = src.size;
+ }
+
+ /// tighten array size.
+ void precompute () { remax(size); }
+
+ /// this makes svec behave like an array
+ T &operator[] (const int i) const {
+ assert(i >=0&&i<size);
+ return ((T*)thearray)[i];
+ }
+
+ /// add to the end of array
+ void add(T x) {
+ if (size == max)
+ remax(2*max + 1);
+
+ // T::operator=(T &) is called here. Safe to use with automatic
+ // vars
+ thearray[size++] = x;
+ }
+
+ /// junk last entry.
+ void pop() { size -- ; }
+
+ /// return last entry
+ T& last(int j=0) {
+ return (*this)[size-j-1];
+ }
+ void swap (int i,int j) {
+ T t((*this)[i]);
+ (*this)[i]=(*this)[j];
+ (*this)[j]=t;
+ }
+ bool empty() { return !size; }
+ void insert(T&k, int j) {
+ assert(j >=0 && j<= size);
+ set_size(size+1);
+ for (int i=size-1; i > j; i--)
+ thearray[i] = thearray[i-1];
+ thearray[j] = k;
+ }
+ void del(int i) {
+ assert(i >=0&& i < size);
+ arrcpy(thearray+i, thearray+i+1, size-i-1);
+ size--;
+ }
+ // quicksort.
+ void sort (int (*compare)(T& , T& ),
+ int lower = -1, int upper = -1 ) {
+ if (lower < 0) {
+ lower = 0 ;
+ upper = sz();
+ }
+ if (lower >= upper)
+ return;
+ swap(lower, (lower+upper)/2);
+ int last = lower;
+ for (int i= lower +1; i <= upper; i++)
+ if (compare(thearray[i], thearray[lower]) < 0 )
+ swap( ++last,i);
+ swap(lower, last);
+ sort(compare, lower, last-1);
+ sort(compare, last+1, lower);
+ }
+};
+/**
+
+ This template implements a scaleable vector. With (or without) range
+ checking. It may be flaky for objects with complicated con- and
+ destructors. The type T should have a default constructor. It is
+ best suited for simple types, such as int, double or String
+
+ */
+
+/// A simple stack based on svec.
+template<class T>
+class sstack : svec<T> {
+ public:
+ T top() { return last(); }
+ T pop() {
+ assert(!empty());
+ T l = last();
+ svec<T>::pop();
+ return l;
+ }
+ void push(T l) { add(l); }
+ bool empty() { return svec<T>::empty(); }
+};
+/**
+ Same as for #svec# goes here.
+*/
+#endif
--- /dev/null
+#ifndef GLOB_HH
+#define GLOB_HH
+#include <assert.h>
+#include <math.h>
+#include "real.hh"
+
+#include "proto.hh"
+#include "const.hh"
+#endif
--- /dev/null
+extern Score *the_score;
--- /dev/null
+#include "line.hh"
+
+
+#include "cols.hh"
+String
+Spanner::TeXstring() const
+{
+ assert(right->line);
+ Real w = left->hpos - right->hpos;
+ return (*strets)(w);
+}
+
+Spanner *
+Spanner::broken_at(const PCol *c1, const PCol *c2) const
+{
+ Spanner *sp = new Spanner(*this);
+ sp->left = c1;
+ sp->right = c2;
+ return sp;
+}
+
+Spanner::Spanner()
+{
+ pstaff_=0;
+ strets=0;
+ left = right = 0;
+}
+
+/****************************************************************/
+String
+Item::TeXstring() const
+{
+ return output->TeXstring();
+}
+
+Interval
+Item::width() const
+{
+ return output->extent().x;
+}
+
+/****************************************************************/
+
+Item::Item()
+{
+ col = 0;
+ output = 0;
+ pstaff_ = 0;
+}
--- /dev/null
+#ifndef ITEM_HH
+#define ITEM_HH
+
+#include "glob.hh"
+#include "boxes.hh"
+#include "string.hh"
+#include "tex.hh"
+
+/// a symbol which is attached between two columns.
+struct Spanner {
+ const PCol *left, *right;
+ Stretchable_symbol *strets;
+ PStaff * pstaff_;
+ /// clone a piece of this spanner.
+ Spanner *broken_at(const PCol *c1, const PCol *c2) const;
+ /**
+
+ PRE
+ c1 >= start, c2 <= stop
+ */
+ String TeXstring () const ;
+ Spanner();
+};
+/** Spanner should know about the items which it should consider:
+ e.g. slurs should be steep enough to "enclose" all those items. This
+ is absolutely necessary for beams, since they have to adjust the
+ length of stems of notes they encompass.
+
+ */
+
+/// a fixed size element of the score
+struct Item {
+ virtual Interval width() const;
+
+ const PCol * col;
+ Output *output;
+
+ PStaff *pstaff_;
+ /** needed for knowing at which staff to output this item
+ */
+ String TeXstring () const ;
+ Item();
+};
+/** An item must be part of a Column
+*/
+
+#endif
--- /dev/null
+/*
+ keyword.cc -- keywords and identifiers
+ */
+
+#include <stdlib.h>
+
+#include "glob.hh"
+#include "lexer.hh"
+//#include "mudobs.hh"
+//#include "gram.hh"
+
+/* for the keyword table */
+struct Keyword_ent
+{
+ const char *name;
+ int tokcode;
+};
+
+struct Keyword_table
+{
+ Keyword_ent *table;
+ int maxkey;
+ Keyword_table(Keyword_ent *);
+ int lookup(const char *s) const;
+};
+
+
+/* for qsort */
+int
+ tabcmp(const void * p1, const void * p2)
+{
+ return strcmp(((const Keyword_ent *) p1)->name,
+ ((const Keyword_ent *) p2)->name);
+}
+
+Keyword_table::Keyword_table(Keyword_ent *tab)
+{
+ table = tab;
+
+ /* count keywords */
+ for (maxkey = 0; table[maxkey].name; maxkey++);
+
+ /* sort them */
+ qsort(table, maxkey, sizeof(Keyword_ent), tabcmp);
+}
+
+/*
+ lookup with binsearch, return tokencode.
+*/
+int
+Keyword_table::lookup(const char *s)const
+{
+ int lo,
+ hi,
+ cmp,
+ result;
+ lo = 0;
+ hi = maxkey;
+
+ /* binary search */
+ do
+ {
+ cmp = (lo + hi) / 2;
+
+ result = strcmp(s, table[cmp].name);
+
+ if (result < 0)
+ hi = cmp;
+ else
+ lo = cmp;
+ }
+ while (hi - lo > 1);
+ if (!strcmp(s, table[lo].name))
+ {
+ return table[lo].tokcode;
+ } else
+ return -1; /* not found */
+}
+
--- /dev/null
+/* for the keyword table */
+struct Keyword_ent
+{
+ const char *name;
+ int tokcode;
+};
+
+struct Keyword_table
+{
+ Keyword_ent *table;
+ int maxkey;
+ Keyword_table(Keyword_ent *);
+ int lookup(const char *s) const;
+};
+
+struct Identifier{
+};
--- /dev/null
+#ifndef LEXER_HH
+#define LEXER_HH
+
+#include "proto.hh"
+
+void new_input(String s);
+bool close_input();
+int yylex();
+void yyerror(char *s);
+
+int lookup_keyword(String s);
+Identifier* lookup_identifier(String s);
+
+#endif
--- /dev/null
+%{ // -*-Fundamental-*-
+
+#include <fstream.h>
+#include <stdio.h>
+#include "glob.hh"
+#include "string.hh"
+
+#include "lexer.hh"
+#include "keyword.hh"
+#include "vray.hh"
+#include "parser.hh"
+#include "debug.hh"
+
+sstack<istream *> include_stack;
+static int last_print;
+const int DOTPRINT=50; // every 50 lines dots
+%}
+
+%option c++
+%option noyywrap
+%option nodefault
+%option yylineno
+%option debug
+%x notes
+%x incl
+
+OPTSIGN !?
+NOTENAMEI A|B|C|D|E|F|G|As|Bes|Ces|Des|Es|Fes|Ges|Ais|Bis|Cis|Dis|Eis|Fis|Gis
+NOTENAMEII a|b|c|d|e|f|g|as|bes|ces|des|es|fes|ges|ais|bis|cis|dis|eis|fis|gis
+NOTENAMEIII Ases|Beses|Ceses|Deses|Eses|Feses|Geses|Aisis|Bisis|Cisis|Disis|Eisis|Fisis|Gisis
+NOTENAMEIIII ases|beses|ceses|deses|eses|feses|geses|aisis|bisis|cisis|disis|eisis|fisis|gisis
+RESTNAME r|s
+NOTENAME {NOTENAMEI}|{NOTENAMEII}|{NOTENAMEIII}|{NOTENAMEIIII}
+PITCH ['`]*{OPTSIGN}{NOTENAME}
+DURNAME 1|2|4|8|16|32
+DURATION {DURNAME}\.*
+FULLNOTE {PITCH}{DURATION}?
+WORD [a-zA-Z]+
+REAL [0-9]+(\.[0-9]*)?
+
+%%
+
+\$ {
+ BEGIN(notes); return '$';
+}
+
+<notes>{RESTNAME} {
+ const char *s = YYText();
+ yylval.string = new String (s);
+ if (debug_flags & DEBUGTOKEN)
+ mtor << "rest:"<< yylval.string;
+ return RESTNAME;
+}
+<notes>{PITCH} {
+ const char *s = YYText();
+ yylval.string = new String (s);
+ if (debug_flags & DEBUGTOKEN)
+ mtor << "pitch:"<< yylval.string;
+ return PITCH;
+}
+<notes>{DURATION} {
+ yylval.string = new String (YYText());
+ return DURATION;
+}
+<notes>[:space:]+ {
+}
+<notes>[ \t\n]+ {
+}
+<notes>%.* {
+
+}
+<notes>\$ {
+ BEGIN(INITIAL); return '$';
+}
+<notes>. {
+ cout << "SCANNER <notes> HOLE `" << YYText()<<'\''<<endl;
+ return YYText()[0];
+}
+<<EOF>> {
+ if(!close_input())
+ yyterminate();
+}
+{WORD} {
+ int l = lookup_keyword(YYText());
+ if (l == -1){
+ yylval.id = lookup_identifier(YYText());
+ return IDENTIFIER;
+ } else
+ return l;
+}
+
+{REAL} {
+ Real r;
+ sscanf (YYText(), "%lf", &r);
+ yylval.real = r;
+ return REAL;
+}
+
+[\{\}\[\]\(\)] {
+ if (debug_flags & DEBUGTOKEN)
+ cout << "parens\n";
+ return YYText()[0];
+}
+[ \t\n]+ {
+
+}
+%.* {
+ //ignore
+}
+. {
+ error("lexer error: illegal character '"+String(YYText()[0])+
+ "' encountered");
+ return YYText()[0];
+}
+
+%%
+
+yyFlexLexer *lexer=0;
+
+// set the new input to s, remember old file.
+void
+new_input(String s)
+{
+ istream *newin ;
+
+ if (s=="")
+ newin = &cin;
+ else
+ newin = new ifstream( s ); //
+
+ if ( ! *newin)
+ error("cant open " + s);
+ cout << "["<<s<<flush;
+
+ include_stack.push(newin);
+
+ if (!lexer) {
+ lexer = new yyFlexLexer;
+ lexer->set_debug( bool(debug_flags & DEBUGPARSER));
+ }
+
+ lexer->switch_streams(newin);
+}
+
+
+// pop the inputstack.
+bool
+close_input()
+{
+
+ istream *closing= include_stack.pop();
+ if (closing != &cin)
+ delete closing;
+
+ cout << "]" << flush;
+
+ if (include_stack.empty())
+ return false ;
+ else
+ lexer->switch_streams(include_stack.top());
+ return true;
+}
+
+int
+yylex() {
+ return lexer->yylex();
+}
+
+void
+yyerror(char *s)
+{
+ *mlog << "error in line " << lexer->lineno() << ": " << s << '\n';
+ exit(1);
+}
+
+
+#if 0
+
+<notes>{NOTENAME} {
+ yylval.string = new String (YYText());
+ return NOTENAME;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+
+
+\def\musixtwentydefs{
+ \font\musicfnt=musix20
+% \hulplijnbreedte5pt
+ %\hlijnhoogte1pt
+ %\balkskip4pt
+}
+\musixtwentydefs
+\def\mdef#1#2{\def#1{{\musicfnt\char#2}}}
+\mdef\quartball{'007}
+\mdef\halfball{'010}
+\mdef\wholeball{'011}
+\mdef\wholerest{'074}
+\mdef\halfrest{'072}
+\mdef\quartrest{'076}
+\mdef\eighthrest{'077}
+\mdef\sixteenthrest{'078}
+\mdef\thirtysecondrest{'079}
+\mdef\sharp{'065}
+\mdef\flat{'063}
+\mdef\natural{'067}
+\mdef\singledot{'00}
+\mdef\doubledot{'01}
+\mdef\tripledot{'02}
+\def\maatstreep{\vrule height10pt width 1pt}
+\parindent0pt
+
+
--- /dev/null
+#include "line.hh"
+#include "cols.hh"
+#include "pscore.hh"
+
+String
+Line_of_staff::TeXstring() const
+{
+ String s("%line_of_staff\n\\vbox to ");
+ s += String(height * VERT_TO_PT) +"pt{";
+
+ //make some room
+ s += vstrut(base* VERT_TO_PT);
+
+ // the staff itself: eg lines, accolades
+ s += "\\hbox{";
+ {
+ s+=(*pstaff_->stafsym)(scor->score->linewidth);
+ PCursor<const PCol *> cc(scor->cols);
+ Real lastpos=cc->hpos;
+
+ // all items in the current line & staff.
+ for (; cc.ok(); cc++) {
+ Real delta=cc->hpos - lastpos;
+ lastpos = cc->hpos;
+
+ // moveover
+ s +=String( "\\kern ") + HOR_TO_PT*delta + "pt ";
+
+ // now output the items.
+
+ for (PCursor<const Item *> ic(cc->its); ic.ok(); ic++) {
+ if (ic->pstaff_ == pstaff_)
+ s += ic->TeXstring();
+ }
+ // spanners.
+ for (PCursor<const Spanner *> sc(cc->starters); sc.ok(); sc++)
+ if (sc->pstaff_ == pstaff_)
+ s += sc->TeXstring();
+ }
+ }
+ s+="\\hss}}";
+ return s;
+}
+
+String
+Line_of_score::TeXstring() const
+{
+ String s("\\vbox{");
+ for (PCursor<Line_of_staff*> sc(staffs); sc.ok(); sc++)
+ s += sc->TeXstring();
+ s += "}";
+ return s;
+}
+
+/// testing this entry
+Line_of_score::Line_of_score(svec<const PCol *> sv,
+ const PScore *ps)
+{
+ score = ps;
+ for (int i=0; i< sv.sz(); i++) {
+ PCol *p=(PCol *) sv[i];
+ cols.bottom().add(p);
+ p->line=this;
+ }
+
+ for (PCursor<PStaff*> sc(score->staffs); sc.ok(); sc++)
+ staffs.bottom().add(new Line_of_staff(this, sc));
+}
+/** construct a line with the named columns. Make the line field
+ in each column point to this
+
+ #sv# isn't really const!!
+ */
+
+Line_of_staff::Line_of_staff(Line_of_score * sc, PStaff*st)
+{
+ // [don't know how to calc dimensions yet.]
+ height = 0.0;
+ base =0.0;
+
+ scor=sc;
+ pstaff_=st;
+
+ const PCol *linestart= sc->cols.top();
+ const PCol *linestop=sc->cols.bottom();
+
+ for (PCursor<const Spanner*> sp(pstaff_->spans); sp.ok(); sp++) {
+ const PCol *brokenstart = &MAX(*linestart, *sp->left);
+ const PCol *brokenstop = &MIN(*linestop, *sp->right);
+
+ if (*brokenstop < *brokenstart)
+ brokenspans.bottom().add(sp->broken_at(brokenstop, brokenstart));
+ }
+}
--- /dev/null
+#ifndef LINE_HH
+#define LINE_HH
+
+/*
+ horizontal structures for broken scores.
+*/
+
+#include "real.hh"
+#include "list.hh"
+#include "vray.hh"
+#include "glob.hh"
+#include "pstaff.hh"
+
+
+
+/// the columns of a score that form one line.
+struct
+Line_of_score {
+ List<const PCol *> cols;
+
+ // need to store height of each staff.
+ PointerList<Line_of_staff*> staffs;
+ const PScore * score; // needed to generate staffs
+
+ /****************/
+
+ Line_of_score(svec<const PCol *> sv, const PScore *);
+
+ String TeXstring() const;
+
+ // is #c# contained in #*this#?
+ bool element(const PCol *c);
+};
+
+/// one broken line of staff.
+struct Line_of_staff {
+ Real height;
+
+ /// y-pos of the baseline, measured from the top.
+ Real base;
+
+ PointerList<Spanner *> brokenspans;
+ Line_of_score const * scor;
+ const PStaff *pstaff_;
+
+ /****************/
+
+ String TeXstring() const;
+ Line_of_staff(Line_of_score*, PStaff *);
+};
+
+#endif
--- /dev/null
+#include <math.h>
+#include "linespace.hh"
+#include "debug.hh"
+#include "qlp.hh"
+#include "unionfind.hh"
+
+const Real COLFUDGE=1e-3;
+//#define COLFUDGE 1e-3
+bool
+Spacing_problem::contains(const PCol *w)
+{
+ for (int i=0; i< cols.sz(); i++)
+ if (cols[i].col == w)
+ return true;
+ return false;
+}
+
+int
+Spacing_problem::col_id(const PCol *w)const
+{
+ for (int i=0; i< cols.sz(); i++)
+ if (cols[i].col == w)
+ return i;
+ assert(false);
+}
+
+void
+Spacing_problem::OK() const
+{
+ Union_find connected(cols.sz());
+
+ for (int i=0; i < ideals.sz(); i++) {
+ assert(ideals[i]->hooke > 0);
+ int l = col_id(ideals[i]->left);
+ int r = col_id(ideals[i]->right);
+ connected.connect(l,r);
+ }
+
+ for (int i = 0; i < cols.sz(); i++) {
+ assert( connected.equiv(0,i));
+ }
+}
+
+bool
+Spacing_problem::check_constraints(Vector v) const
+{
+ int dim=v.dim();
+ // mtor << "checking solution " << v << '\n';
+ for (int i=0; i < dim; i++) {
+
+ if (cols[i].fixed&& ABS(cols[i].fixpos - v(i)) > COLFUDGE) {
+ return false;
+ }
+ if (!i)
+ continue;
+
+ Real mindist=cols[i-1].minright()
+ +cols[i].minleft();
+
+ // ugh... compares
+ Real dif =v(i) - v(i-1)- mindist;
+ bool b = (dif > - COLFUDGE);
+
+
+#if 1
+ if (!b)
+ return false;
+
+#else
+ mtor << "dif= "<<dif<<" fudge= " << COLFUDGE<< " dif >fudge= "<<
+ b << "\n";
+
+ /* fucks up for unknown reasons */
+ if (dif < -COLFUDGE)
+ return false;
+#endif
+
+ }
+ return true;
+}
+
+bool
+Spacing_problem::check_feasible() const
+{
+ Vector sol(try_initial_solution());
+ return check_constraints(sol);
+}
+
+// generate a solution which obeys the min distances and fixed positions
+Vector
+Spacing_problem::try_initial_solution() const
+{
+ int dim=cols.sz();
+ Vector initsol(dim);
+ for (int i=0; i < dim; i++) {
+ if (cols[i].fixed) {
+ initsol(i)=cols[i].fixpos;
+ } else {
+ Real mindist=cols[i-1].minright()
+ +cols[i].minleft();
+ assert(mindist >= 0.0);
+ initsol(i)=initsol(i-1)+mindist;
+
+ //nog niet
+ //if (i>0)
+ // assert(initsol(i) > initsol(i-1));
+ }
+ }
+
+ return initsol;
+}
+Vector
+Spacing_problem::find_initial_solution() const
+{
+ Vector v(try_initial_solution());
+ assert(check_constraints(v));
+ return v;
+}
+// generate the matrices
+void
+Spacing_problem::make_matrices(Matrix &quad, Vector &lin) const
+{
+ quad.fill(0);
+ lin.fill(0);
+ for (int j=0; j < ideals.sz(); j++){
+ Idealspacing const*i=ideals[j];
+ int l = col_id(i->left);
+ int r = col_id(i->right);
+
+ quad(r,r) += i->hooke;
+ quad(r,l) -= i->hooke;
+ quad(l,r) -= i->hooke;
+ quad(l,l) += i->hooke;
+
+ lin(r) -= i->space*i->hooke;
+ lin(l) += i->space*i->hooke;
+ }
+}
+
+// put the constraints into the LP problem
+void
+Spacing_problem::make_constraints(Optimisation_problem& lp) const
+{
+ for (int j=0; j < cols.sz(); j++) {
+ Colinfo *c=&(cols[j]);
+ int dim=cols.sz();
+
+ if (c->fixed) {
+ lp.add_fixed_var(j,c->fixpos);
+ continue;
+ }else {
+
+ Vector c1(dim);
+ Vector c2(dim);
+
+
+ c1(j)=1.0 ;
+ c1(j-1)=-1.0 ;
+ lp.add_inequality_cons(c1, cols[j-1].minright() +
+ cols[j].minleft());
+
+ c2(j)=-1.0 ;
+ c2(j+1)=1.0;
+ lp.add_inequality_cons(c2,
+ cols[j+1].minleft() +
+ cols[j].minright());
+ }
+ }
+}
+
+svec<Real>
+Spacing_problem::solve() const
+{
+ OK();
+ assert(check_feasible());
+ // print();
+
+ /* optimalisatiefunctie */
+ Optimisation_problem lp(cols.sz());
+ make_matrices(lp.quad,lp.lin);
+ make_constraints(lp);
+ Vector start=find_initial_solution();
+ Vector sol(lp.solve(start));
+ if (!check_constraints(sol)) {
+ error( "solution doesn't solve. Sorry");
+ }
+
+
+ svec<Real> posns(sol);
+ posns.add(lp.eval(sol));
+ return posns;
+}
+
+/*
+ add one column to the problem.
+*/
+void
+Spacing_problem::add_column(const PCol *col, bool fixed, Real fixpos)
+{
+ Colinfo c;
+ c.fixed=fixed;
+ c.fixpos=fixpos;
+ c.col=col;
+ cols.add(c);
+}
+
+void
+Spacing_problem::add_ideal(const Idealspacing *i)
+{
+ const PCol *l =i->left;
+ const PCol *r= i->right;
+
+ if (!contains(l) || !contains(r)) {
+ return;
+ }
+ ideals.add(i);
+}
+
+void
+Spacing_problem::print_ideal(const Idealspacing*id)const
+{
+ int l = col_id(id->left);
+ int r = col_id(id->right);
+
+ mtor << "idealspacing { between " << l <<","<<r<<'\n';
+ mtor << "distance "<<id->space<< " strength " << id->hooke << "}\n";
+}
+
+void
+Spacing_problem::print() const
+{
+ for (int i=0; i < cols.sz(); i++) {
+ mtor << "col " << i<<' ';
+ cols[i].print();
+ }
+ for (int i=0; i < ideals.sz(); i++) {
+ print_ideal(ideals[i]);
+ }
+}
+
+void
+Colinfo::print() const
+{
+ mtor << "column { ";
+ if (fixed)
+ mtor << "fixed at " << fixpos<<", ";
+ mtor << "[" << minleft() << ", " << minright() << "]";
+ mtor <<"}\n";
+}
--- /dev/null
+#ifndef PROBLEM_HH
+#define PROBLEM_HH
+
+#include "glob.hh"
+#include "list.hh"
+#include "vray.hh"
+#include "cols.hh"
+#include "matrix.hh"
+
+/// helper struct for #Spacing_problem#
+struct Colinfo {
+ const PCol *col;
+ bool fixed;
+ Real fixpos;
+ Colinfo() {
+ fixed=false;
+ col=0;
+ }
+ void print() const;
+ Real minright()const { return col->width().max; }
+ Real minleft()const { return -col->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) const;
+
+ /// generate the LP constraints
+ void make_constraints(Optimisation_problem& 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
--- /dev/null
+#include "linestaff.hh"
+#include "tex.hh"
+
+Linestaff::Linestaff(int l)
+{
+ nolines = l;
+ stafsym = Stretchable_symbol::get_linestaff(l);
+}
+
--- /dev/null
+#include "pstaff.hh"
+
+struct Linestaff : PStaff {
+ int nolines;
+
+ Linestaff(int);
+
+};
--- /dev/null
+#include <iostream.h>
+#include "lgetopt.hh"
+#include "misc.hh"
+#include "debug.hh"
+#include "score.hh"
+#include "globvars.hh"
+
+extern void parse_file(String s);
+Score *the_score =0;
+
+long_option_init theopts[] = {
+ 1, "debug", 'd',
+ 1, "output", 'o',
+ 0,0,0
+};
+
+
+String outfn="lelie.uit";
+
+void
+set_output(String s)
+{
+ outfn = s;
+}
+
+int
+main (int argc, char **argv)
+{
+ Getopt_long oparser(argc, argv,theopts);
+
+ cout << get_version()
+ << "copyright 1996 Han-Wen Nienhuys\n";
+
+ while (long_option_init * opt = oparser()) {
+ switch ( opt->shortname){
+ case 'd':
+ set_debug(oparser.optarg);
+ break;
+ case 'o':
+ set_output(oparser.optarg);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ char *arg = oparser.get_next_arg();
+
+ if (!arg) arg = "";
+ parse_file(arg);
+
+ the_score->process();
+ the_score->output(outfn);
+}
--- /dev/null
+#!/bin/sh
+echo '#ifndef VERSION_HH'
+echo '#define VERSION_HH'
+echo '#define MAJORVERSION ' $1
+echo '#define MINORVERSION ' $2
+echo '#define PATCHLEVEL ' $3
+echo '#define VERSIONSTR "'$1.$2.$3'"'
+echo '#endif'
--- /dev/null
+#include "matrix.hh"
+#include "string.hh"
+
+
+Real
+Matrix::norm() const
+{
+ Real r =0.0;
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ r += sqr(dat->elem(i,j));
+ return sqrt(r);
+}
+
+//inline
+Real
+Matrix::operator()(int i,int j) const
+{
+ assert(i >= 0 && j >= 0);
+ assert(i < rows() && j < cols());
+ return dat->elem(i,j);
+}
+
+//inline
+Real &
+Matrix::operator()(int i, int j)
+{
+ assert(i >= 0 && j >= 0);
+ assert(i < rows() && j < cols());
+ return dat->elem(i,j);
+}
+
+void
+Matrix::fill(Real r)
+{
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dat->elem(i,j)=r;
+}
+
+void
+Matrix::set_diag(Real r)
+{
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dat->elem(i,j)=(i==j) ? r: 0.0;
+}
+
+void
+Matrix::set_diag(Vector d)
+{
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dat->elem(i,j)=(i==j) ? d(i): 0.0;
+}
+
+void
+Matrix::operator+=(const Matrix&m)
+{
+ assert(m.cols() == cols());
+ assert(m.rows() == rows());
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dat->elem(i,j) += m(i,j);
+}
+
+void
+Matrix::operator-=(const Matrix&m)
+{
+ assert(m.cols() == cols());
+ assert(m.rows() == rows());
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dat->elem(i,j) -= m(i,j);
+}
+
+
+void
+Matrix::operator*=(Real a)
+{
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dat->elem(i,j) *= a;
+}
+
+void
+Matrix::operator=(const Matrix&m)
+{
+ if (&m == this)
+ return ;
+ delete dat;
+ dat = m.dat->clone();
+}
+
+Matrix::Matrix(const Matrix &m)
+{
+ m.OK();
+
+ dat = m.dat->clone();
+}
+
+
+Matrix::Matrix(int n, int m)
+{
+ dat = virtual_smat::get_full(n,m);
+ fill(0);
+}
+
+Matrix::Matrix(int n)
+{
+ dat = virtual_smat::get_full(n,n);
+ fill(0);
+}
+
+Matrix::Matrix(Vector v, Vector w)
+{
+ dat = virtual_smat::get_full(v.dim(), w.dim());
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dat->elem(i,j)=v(i)*w(j);
+}
+
+
+Vector
+Matrix::row(int k) const
+{
+ int n=cols();
+
+
+ Vector v(n);
+ for(int i=0; i < n; i++)
+ v(i)=dat->elem(k,i);
+
+ return v;
+}
+
+Vector
+Matrix::col(int k) const
+{
+ int n=rows();
+ Vector v(n);
+ for(int i=0; i < n; i++)
+ v(i)=dat->elem(i,k);
+ return v;
+}
+
+Vector
+Matrix::left_multiply(const Vector& v) const
+{
+ Vector dest(v.dim());
+ assert(dat->cols()==v.dim());
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dest(i)+= dat->elem(j,i)*v(j);
+ return dest;
+}
+
+Vector
+Matrix::operator *(const Vector& v) const
+{
+ Vector dest(rows());
+ assert(dat->cols()==v.dim());
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+ dest(i)+= dat->elem(i,j)*v(j);
+ return dest;
+}
+
+Matrix
+operator /(Matrix const& m1,Real a)
+{
+ Matrix m(m1);
+ m /= a;
+ return m;
+}
+
+void
+Matrix::transpose() // delegate to storage?
+{
+ for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j)) {
+ if (i >= j)
+ continue;
+ Real r=dat->elem(i,j);
+ dat->elem(i,j) = dat->elem(j,i);
+ dat->elem(j,i)=r;
+ }
+}
+
+Matrix
+Matrix::operator-() const
+{
+ OK();
+ Matrix m(*this);
+ m*=-1.0;
+ return m;
+}
+
+Matrix
+Matrix::transposed() const
+{
+ Matrix m(*this);
+ m.transpose();
+ return m;
+}
+
+
+/* should do something smarter: bandmatrix * bandmatrix is also banded matrix. */
+Matrix
+operator *(const Matrix &m1, const Matrix &m2)
+{
+ Matrix result(m1.rows(), m2.cols());
+ result.set_product(m1,m2);
+ return result;
+}
+
+void
+Matrix::set_product(const Matrix &m1, const Matrix &m2)
+{
+ assert(m1.cols()==m2.rows());
+ assert(cols()==m2.cols() && rows()==m1.rows());
+
+ for (int i=0, j=0; dat->mult_ok(i,j);
+ dat->mult_next(i,j)) {
+ Real r=0.0;
+ for (int k = 0; k < m1.cols(); k++)
+ r += m1(i,k)*m2(k,j);
+ dat->elem(i,j)=r;
+ }
+}
+
+void
+Matrix::insert_row(Vector v, int k)
+{
+ assert(v.dim()==cols());
+ dat->insert_row(k);
+ for (int j=0; j < cols(); j++)
+ dat->elem(k,j)=v(j);
+}
+
+
+void
+Matrix::swap_columns(int c1, int c2)
+{
+ assert(c1>=0&& c1 < cols()&&c2 < cols() && c2 >=0);
+ for (int i=0; i< rows(); i++) {
+ Real r=dat->elem(i,c1);
+ dat->elem(i,c1) = dat->elem(i,c2);
+ dat->elem(i,c2)=r;
+ }
+}
+
+void
+Matrix::swap_rows(int c1, int c2)
+{
+ assert(c1>=0&& c1 < rows()&&c2 < rows() && c2 >=0);
+ for (int i=0; i< cols(); i++) {
+ Real r=dat->elem(c1,i);
+ dat->elem(c1,i) = dat->elem(c2,i);
+ dat->elem(c2,i)=r;
+ }
+}
+
+
+int
+Matrix::dim() const
+{
+ assert(cols() == rows());
+ return rows();
+}
+
+Matrix::operator String() const
+{
+ String s("matrix {\n");
+ for (int i=0; i< rows(); i++){
+ for (int j = 0; j < cols(); j++) {
+ s+= String(dat->elem(i,j), "%6f ");
+ }
+ s+="\n";
+ }
+ s+="}\n";
+ return s;
+}
+
+
+
+#include "debug.hh"
+void
+Matrix::print() const
+{
+ mtor << *this;
+}
--- /dev/null
+#ifndef MATRIX_HH
+#define MATRIX_HH
+
+
+#include "vsmat.hh"
+#include "vector.hh"
+
+/// a Real matrix
+class Matrix {
+ virtual_smat *dat;
+
+public:
+ void OK() const { dat->OK(); }
+ int cols() const { return dat->cols(); }
+ int rows() const { return dat->rows(); }
+
+ /// return the size of a matrix
+ int dim() const;
+ /**
+ PRE
+ the matrix needs to be square.
+ */
+
+ // Matrix() { dat = 0; }
+ ~Matrix() { delete dat; }
+
+ /// set entries to r
+ void fill(Real r);
+
+ /// set diagonal to d
+ void set_diag(Real d);
+
+ void set_diag(Vector d);
+ /// set unit matrix
+ void unit() { set_diag(1.0); }
+
+ void operator+=(const Matrix&m);
+ void operator-=(const Matrix&m);
+ void operator*=(Real a);
+ void operator/=(Real a) { (*this) *= 1/a; }
+
+ /// add a row
+ void insert_row(Vector v,int k);
+ /**
+ add a row to the matrix before row k
+
+ PRE
+ v.dim() == cols()
+ 0 <= k <= rows()
+ */
+ ///
+ void delete_row(int k) { dat->delete_row(k); }
+ /**
+ delete a row from this matrix.
+
+ PRE
+ 0 <= k < rows();
+ */
+ void delete_column(int k) { dat->delete_column(k); }
+ ///
+ Matrix(int n);
+ /**
+ square n matrix, initialised to null
+ */
+ ///
+ Matrix(int n, int m);
+ /**
+ n x m matrix, init to 0
+ */
+ Matrix(const Matrix &m);
+
+ /// dyadic product: v * w.transpose
+ Matrix(Vector v, Vector w);
+ void operator=(const Matrix&m);
+
+ /// access an element
+ Real operator()(int i,int j) const;
+
+ /// access an element
+ Real &operator()(int i, int j);
+
+ /// Matrix multiply with vec (from right)
+ Vector operator *(const Vector &v) const;
+
+ /// set this to m1*m2.
+ void set_product(const Matrix &m1, const Matrix &m2);
+
+
+ Vector left_multiply(Vector const &) const;
+
+ Matrix operator-() const;
+
+ /// transpose this.
+ void transpose();
+
+ /// return a transposed copy.
+ Matrix transposed() const ;
+
+ Real norm() const;
+ /// swap
+ void swap_columns(int c1, int c2);
+ /**
+ PRE
+ 0 <= c1,c2 < cols()
+ */
+
+ /// swap
+ void swap_rows(int c1, int c2);
+ /**
+ PRE
+ 0 <= c1,c2 < rows()
+ */
+
+
+ Vector row(int ) const;
+ Vector col(int) const;
+
+ operator String() const;
+ void print() const;
+};
+
+/** This is a class for a nonsquare block of #Real#s. The
+ implementation of sparse matrices is done in the appropriate #smat#
+ class. Matrix only does the mathematical actions (adding,
+ multiplying, etc.)
+
+
+ TODO
+ implement ref counting? */
+
+
+inline Vector
+operator *(Vector &v, const Matrix& m) { return m.left_multiply(v); }
+Matrix operator *(const Matrix& m1,const Matrix &m2);
+Matrix operator /(const Matrix &m1,Real a);
+inline Matrix operator -(Matrix m1,const Matrix m2)
+{
+ m1 -= m2;
+ return m1;
+}
+#endif
--- /dev/null
+#include "misc.hh"
+#include "glob.hh"
+#include "mtime.hh"
+#include <math.h>
+
+int intlog2(int d) {
+ int i=0;
+ while (!(d&1)) {
+ d/= 2; i++;
+ }
+ assert(!(d/2));
+ return i;
+}
+
+double log2(double x) {
+ return log(x) /log(2.0);
+}
+
+
+// golden ratio
+
+const Real PHI = (1+sqrt(5))/2;
+const double ENGRAVERS_SPACE = PHI;
+const double WHOLE_SPACE = 10.0;
+
+
+Real
+duration_to_idealspace(Mtime d)
+{
+ // see Roelofs, p. 57
+ return WHOLE_SPACE * pow(ENGRAVERS_SPACE, log2(d));
+}
--- /dev/null
+#ifndef MISC_HH
+#define MISC_HH
+#include "mtime.hh"
+int intlog2(int d);
+Real duration_to_idealspace(Mtime d);
+class String;
+char *get_version();
+#endif
--- /dev/null
+#include "glob.hh"
+#include "string.hh"
+#include "molecule.hh"
+
+String
+Atom::TeXstring() const
+{
+ // whugh.. Hard coded...
+ String s("\\raise");
+ s+= String(off.y * VERT_TO_PT)+"pt\\hbox to 0pt{\\kern ";
+ s+=String(off.x * HOR_TO_PT) + "pt" + sym->tex + "\\hss}";
+ return s;
+}
+
+/****************************************************************/
+
+String
+Molecule::TeXstring() const
+{
+ String s;
+ for(Cursor<Atom> c(ats); c.ok(); c++)
+ s+=(*c).TeXstring();
+ return s;
+}
+
+Box
+Molecule::extent() const
+{
+ Box b;
+ for(Cursor<Atom> c(ats); c.ok(); c++)
+ b.unite((*c).extent());
+ return b;
+}
+
+void
+Molecule::translate(Offset o)
+{
+ for(Cursor<Atom> c(ats); c.ok(); c++)
+ (*c).translate(o);
+}
+
+void
+Molecule::add(const Molecule &m)
+{
+ for (Cursor<Atom> c(m.ats); c.ok(); c++) {
+ Atom a(c);
+ ats.bottom().add(a);
+ }
+}
+
+void
+Molecule::add_right(const Molecule &m)
+{
+ Real xof=extent().x.max - m.extent().x.min;
+ Molecule toadd(m);
+ toadd.translate(Offset(xof, 0.0));
+ add(toadd);
+}
+
+void
+Molecule::add_left(const Molecule &m)
+{
+ Real xof=extent().x.min - m.extent().x.max;
+ Molecule toadd(m);
+ toadd.translate(Offset(xof, 0.0));
+ add(toadd);
+}
+
+
+void
+Molecule::add_top(const Molecule &m)
+{
+ Real yof=extent().y.max - m.extent().y.min;
+ Molecule toadd(m);
+ toadd.translate(Offset(0,yof));
+ add(toadd);
+}
+
+void
+Molecule::add_bot(const Molecule &m)
+{
+ Real yof=extent().y.min- m.extent().y.max;
+ Molecule toadd(m);
+ toadd.translate(Offset(0,yof));
+ add(toadd);
+}
+
--- /dev/null
+#ifndef MOLECULE_HH
+#define MOLECULE_HH
+
+#include "list.hh"
+#include "boxes.hh"
+#include "item.hh"
+
+/// a symbol which can be translated, and freely copied
+struct Atom {
+ Offset off;
+ const Symbol * sym;
+
+ void translate(Offset o) {
+ off += o;
+ }
+
+ /// how big is #this#?
+ Box extent() const {
+ Box b( sym->dim);
+ b.translate(off);
+ return b;
+ }
+ Atom(const Symbol*s) {
+ sym=s;
+ }
+ String TeXstring() const;
+};
+
+/// a group of #Atom#s
+struct Molecule : Output {
+ List<Atom> ats;
+
+ Molecule() { }
+ Molecule(Atom a) { ats.bottom().add(a); }
+ // Molecule(Molecule const&src);
+ void add_right(const Molecule &m);
+ void add_left(const Molecule &m);
+ void add_top(const Molecule &m);
+ void add_bot(const Molecule &m);
+ void add(Molecule const &m);
+ void translate(Offset);
+
+ /// how big is #this#?
+ Box extent() const;
+
+ String TeXstring() const;
+};
+/** a group of individually translated symbols. You can add molecules
+ to the top, to the right, etc. */
+#endif
--- /dev/null
+#ifndef MTIME_HH
+#define MTIME_HH
+
+#include "real.hh"
+
+typedef Real Mtime;
+
+#endif MTIME_HH
--- /dev/null
+#include <ctype.h>
+#include "string.hh"
+#include "real.hh"
+#include "debug.hh"
+#include "request.hh"
+#include "voice.hh"
+#include "notename.hh"
+
+int default_duration = 4;
+
+void
+parse_duration(const char *a, int &j, int &intdur, int &dots)
+{
+ String durstr;
+ while (isdigit(a[j]))
+ {
+ durstr += a[j++];
+ }
+
+ dots=0;
+
+ while (a[j] == '.')
+ {
+ j++;
+ dots++;
+ }
+ intdur = (durstr.len()) ?
+ durstr.value():default_duration;
+
+ if (debug_flags & DEBUGTOKEN)
+ 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 =0;
+
+ while (1)
+ {
+ if (a[j] == '\'')
+ oct ++;
+ else if (a[j] == '`')
+ oct --;
+ else
+ break;
+ j++;
+
+ }
+ if (debug_flags & DEBUGTOKEN) mtor << "oct " << oct;
+
+ // accidental
+ overide_acc = false;
+
+ if (a[j] == '!')
+ {
+ overide_acc = true;
+ j++;
+ }
+
+ if (debug_flags & DEBUGTOKEN)
+ mtor << "ov " << overide_acc;
+
+ // notename.
+ String nm;
+ while (isalpha(a[j]))
+ {
+ nm += a[j++];
+ }
+ if (isupper(nm[0]))
+ {
+ oct--;
+ nm.lower();
+ }
+
+
+ lookup_notename(large,small,nm);
+ if (debug_flags & DEBUGTOKEN)
+ mtor << "int "<< large <<" "<<small<<" ";
+}
+
+
+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( v);
+
+ int oct, pit, acc;
+ bool forceacc;
+ parse_pitch(pitch, i, oct, forceacc, pit, acc);
+
+ rq->octave = oct;
+ rq->accidental = acc;
+ rq->forceacc = forceacc;
+ rq->balltype = dur;
+ rq->dots = dots;
+
+
+ v->add(rq);
+ return v;
+}
+
+Voice_element *
+get_rest_element(String type, 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(v);
+
+ rq->balltype = dur;
+ rq->dots = dots;
+
+ v->add(rq);
+ return v;
+}
--- /dev/null
+#include "glob.hh"
+#include "string.hh"
+
+
+/// change this along with lex file for other notenames.
+const char *notetab[] =
+{
+"ceses", "ces", "c", "cis", "cisis",
+"deses", "des", "d", "dis", "disis",
+"eses", "es", "e", "eis", "eisis",
+"feses", "fes", "f", "fis", "fisis",
+"geses", "ges", "g", "gis", "gisis",
+"ases", "as", "a", "ais", "aisis",
+"beses", "bes", "b", "bis", "bisis",
+0
+};
+
+void
+lookup_notename(int &large, int &small, String s)
+{
+ int i;
+ for (i =0; notetab[i]; i++)
+ if (s == notetab[i])
+ {
+ large = i /5;
+ small = i %5 - 2;
+ return;
+ }
+ assert(false);
+}
--- /dev/null
+
+void lookup_notename(int &large, int &small, String s);
--- /dev/null
+
+#include "proto.hh"
+
+Staff * get_new_rhythmstaff();
+Voice_element * get_note_element(String,String);
+Voice_element* get_rest_element(String,String);
+Command * get_bar_command(Real);
--- /dev/null
+%{ // -*-Fundamental-*-
+#include <iostream.h>
+//#include "mudobs.hh"
+#include "lexer.hh"
+#include "staff.hh"
+#include "score.hh"
+#include "keyword.hh"
+#include "globvars.hh"
+#include "debug.hh"
+#include "parseconstruct.hh"
+#define YYDEBUG 1
+
+
+%}
+
+
+%union {
+ int i;
+ Real real;
+ Command *command;
+ Identifier *id;
+
+ Voice *voice;
+ Voice_element *el;
+ Staff *staff;
+ String *string;
+ Score *score;
+}
+
+%token VOICE STAFF SCORE TITLE RHYTHMSTAFF BAR NOTENAME
+
+%token <id> IDENTIFIER
+%token <string> PITCH DURATION RESTNAME
+%token <real> REAL
+
+
+%type <voice> voice_block voice_body voice_elts voice_elts_dollar
+%type <el> voice_elt
+%type <command> score_command
+%type <score> score_block score_body
+%type <staff> staff_block rhythmstaff_block rhythmstaff_body
+
+%%
+
+mudela:
+ score_block {
+ delete the_score;
+ the_score = $1;
+ }
+ ;
+
+
+score_block: SCORE '{' score_body '}' { $$ = $3; }
+ ;
+
+score_body: { $$ = new Score; }
+ | score_body staff_block { $$->add($2); }
+ | score_body score_command { $$->add($2); }
+ ;
+
+staff_block:
+ rhythmstaff_block
+ ;
+
+rhythmstaff_block:
+ RHYTHMSTAFF '{' rhythmstaff_body '}' { $$ = $3; }
+ ;
+
+rhythmstaff_body:
+ /* empty */ { $$ = get_new_rhythmstaff(); }
+ | rhythmstaff_body voice_block { $$->add_voice($2); }
+ ;
+
+voice_block:
+ VOICE '{' voice_body '}' { $$ = $3; }
+ ;
+
+
+voice_body:
+ REAL voice_elts_dollar { $$ = $2; $$->start = $1; }
+ | voice_elts_dollar { $$ = $1; }
+ ;
+
+voice_elts_dollar:
+ '$' voice_elts '$' { $$ = $2; }
+ ;
+
+voice_elts:
+ /* empty */ {
+ $$ = new Voice;
+ }
+ | voice_elts voice_elt {
+ $$->add($2);
+ }
+ ;
+
+voice_elt:
+ PITCH DURATION { $$ = get_note_element(*$1, *$2);
+
+ }
+ | RESTNAME DURATION { $$ = get_rest_element(*$1, *$2);
+
+ }
+ ;
+
+score_command:
+ BAR REAL {
+ $$ = get_bar_command($2);
+ }
+ ;
+
+%%
+
+void
+parse_file(String s)
+{
+ *mlog << "Parsing ... ";
+ yydebug = debug_flags & DEBUGPARSER;
+ new_input(s);
+ yyparse();
+}
--- /dev/null
+#include "real.hh"
+
+class Vector;
+class Matrix;
+class Line_of_score;
+class Line_of_staff;
+class PCol;
+class PStaff;
+class Staff;
+class Staff_column;
+class Score;
+class Score_column;
+class Voice;
+class Voice_element;
+class Voicegroup;
+class Request;
+class Command;
+class Request;
+class Stem_req;
+class Span_req;
+class Slur_req;
+class Decresc_req;
+class Cresc_req;
+class Bracket_req;
+class Script_req;
+class Rest_req;
+class Note_req;
+class Lyric_req;
+class Chord;
+class Absdynamic_req;
+struct Offset;
+struct Interval;
+struct Box;
+struct PCol;
+struct Idealspacing;
+struct Spanner;
+struct Item;
+struct Line_of_staff;
+struct Colinfo;
+struct Linestaff;
+struct Atom;
+struct Molecule;
+struct PScore;
+struct Request;
+struct Note_req;
+struct Lyric_req;
+struct Script_req;
+struct Rest_req;
+struct Chord;
+struct Stem_req;
+struct Span_req;
+struct Beam_req;
+struct Bracket_req;
+struct Slur_req;
+struct Dynamic;
+struct Cresc_req;
+struct Decresc_req;
+struct Absdynamic_req;
+struct Score_column;
+struct Score;
+struct Staff_column;
+struct Staff;
+struct Command;
+struct Symbol;
+struct Stretchable_symbol;
+struct Output;
+struct Text_gob;
+struct Voice;
+struct Voicegroup;
+struct Voice_element;
+struct String;
+struct Tex_stream;
+struct Identifier;
+struct Keyword;
+class Mixed_qp;
+typedef Mixed_qp Optimisation_problem;
--- /dev/null
+// utility functions for PScore
+#include "debug.hh"
+#include "line.hh"
+#include "pscore.hh"
+#include "tstream.hh"
+
+void
+PScore::clean_cols()
+{
+ for (PCursor<PCol *> c(cols); c.ok(); c++)
+ if (!c->used) {
+ c.remove();
+ //mtor << "removing pcol\n";
+ }
+}
+
+
+void
+PScore::add(PStaff *s)
+{
+ staffs.bottom().add(s);
+}
+
+void
+PScore::typeset_item(Item *i, PCol *c, PStaff *s, int breakstat)
+{
+ assert(c && i && s);
+ if (breakstat == 1 ) {
+ typeset_item(i, c->prebreak, s, 0);
+ } if (breakstat == 3)
+ typeset_item(i, c->prebreak, s, 0 );
+ else{
+ its.bottom().add(i);
+ s->add(i);
+ c->add(i);
+ }
+}
+
+void
+PScore::add_line(svec<const PCol *> curline, svec<Real> config)
+{
+ Line_of_score *p = new Line_of_score(curline,this);
+ lines.bottom().add(p);
+ for (int i=0; i < curline.sz(); i++){
+ PCol *c=(PCol *)curline[i]; // so, this isn't really const.
+ c->hpos= config[i];
+ }
+}
+
+Idealspacing*
+PScore::get_spacing(PCol*l, PCol*r)
+{
+ assert(l!=r);
+ for (PCursor<Idealspacing*> ic (suz); ic.ok(); ic++) {
+ if (ic->left == l && ic->right == r){
+ return ic;
+ }
+ }
+
+ Idealspacing*ip =new Idealspacing(l,r);
+ suz.bottom().add(ip);
+ // l->used = r->used = true;
+ return ip;
+}
+
+svec<const PCol *>
+PScore::find_breaks() const
+{
+ svec<const PCol *> retval;
+ for (PCursor<PCol *> c(cols); c.ok(); c++)
+ if (c->breakable)
+ retval.add(c);
+
+ return retval;
+}
+
+void
+PScore::add(PCol *p)
+{
+ cols.bottom().add(p);
+}
+/*
+ todo: config of width
+ */
+PScore::PScore()
+{
+ linewidth = 15; // in cm for now
+}
+
+void
+PScore::output(Tex_stream &ts)
+{
+ int l=1;
+ ts << "% linewidth " << linewidth * HOR_TO_PT << " pt\n";
+ for (PCursor<Line_of_score*> lic(lines); lic.ok(); lic++) {
+ ts << "% line of score no. " << l++ <<"\n";
+ ts << lic->TeXstring();
+ }
+}
--- /dev/null
+// the breaking problem for a score.
+
+#ifndef PSCORE_HH
+#define PSCORE_HH
+
+
+#include "vray.hh"
+#include "cols.hh"
+#include "pstaff.hh"
+
+/// all stuff which goes onto paper
+struct PScore {
+ /// width of paper
+ Real linewidth;
+
+ /// 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;
+
+ /****************************************************************/
+
+ void calc_breaking();
+ /**
+ calculate where the lines are to be broken.
+
+ POST
+
+ lines contain the broken lines.
+ */
+
+ /// 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);
+ /// 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.
+ */
+
+
+ PCursor<PCol *> find_col(PCol *);
+ void clean_cols();
+ void problem_OK() ;
+
+ PScore();
+};
+/** 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
--- /dev/null
+#include "pstaff.hh"
+
+PStaff::PStaff()
+{
+ stafsym = 0;
+}
+
+void
+PStaff::add(Item *i )
+{
+ its.bottom().add(i);
+ i->pstaff_ = this;
+}
--- /dev/null
+#ifndef PSTAFF_HH
+#define PSTAFF_HH
+
+#include "list.hh"
+#include "item.hh"
+
+/// items grouped vertically.
+class PStaff {
+public:
+ Stretchable_symbol *stafsym;
+ List<const Spanner*> spans;
+ List<Item*> its;
+
+ void add(Item*i);
+ PStaff();
+ virtual ~PStaff() {}
+};
+
+#endif
--- /dev/null
+#include "debug.hh"
+#include "qlp.hh"
+#include "choleski.hh"
+void
+Mixed_qp::add_equality_cons(Vector v, double r)
+{
+ assert(false);
+}
+void
+Mixed_qp::add_fixed_var(int i, Real r)
+{
+
+ eq_cons.add(i);
+ eq_consrhs.add(r);
+}
+ void
+Ineq_constrained_qp::add_inequality_cons(Vector c, double r)
+{
+ cons.add(c);
+ consrhs.add(r);
+}
+
+Ineq_constrained_qp::Ineq_constrained_qp(int novars):
+ quad(novars),
+ lin(novars)
+{
+}
+
+void
+Ineq_constrained_qp::OK()const
+{
+ assert(cons.sz() == consrhs.sz());
+ Matrix Qdif= quad - quad.transposed();
+ assert(Qdif.norm() < EPS);
+}
+
+
+Real
+Ineq_constrained_qp::eval (Vector v)
+{
+ return v * quad * v + lin * v ;
+}
+/*
+ eliminate appropriate variables, until we have a Ineq_constrained_qp
+ then solve that.
+
+ PRE
+ cons should be ascending
+ */
+Vector
+Mixed_qp::solve(Vector start) const
+{
+
+ Ineq_constrained_qp pure(*this);
+
+ for (int i= eq_cons.sz()-1; i>=0; i--) {
+ pure.eliminate_var(eq_cons[i], eq_consrhs[i]);
+ start.del(eq_cons[i]);
+ }
+ Vector sol = pure.solve(start);
+ for (int i= 0; i < eq_cons.sz(); i++) {
+ sol.insert( eq_consrhs[i],eq_cons[i]);
+ }
+ return sol;
+}
+
+/*
+ assume x(idx) == value, and adjust constraints, lin and quad accordingly
+ */
+void
+Ineq_constrained_qp::eliminate_var(int idx, Real value)
+{
+ Vector row(quad.row(idx));
+ row*= value;
+
+ quad.delete_row(idx);
+
+ quad.delete_column(idx);
+
+ lin.del(idx);
+ row.del(idx);
+ lin +=row ;
+
+ for (int i=0; i < cons.sz(); i++) {
+ consrhs[i] -= cons[i](idx) *value;
+ cons[i].del(idx);
+ }
+}
+
+
+
+
+Mixed_qp::Mixed_qp(int n)
+ : Ineq_constrained_qp(n)
+{
+}
+
+void
+Mixed_qp::OK()const
+{
+ Ineq_constrained_qp::OK();
+ assert(eq_consrhs.sz() == eq_cons.sz());
+}
+void
+Ineq_constrained_qp::print() const
+{
+
+ mtor << "Quad " << quad;
+ mtor << "lin " << lin <<"\n";
+ for (int i=0; i < cons.sz(); i++) {
+ mtor << "constraint["<<i<<"]: " << cons[i] << " >= " << consrhs[i];
+ mtor << "\n";
+ }
+}
+void
+Mixed_qp::print() const
+{
+ Ineq_constrained_qp::print();
+ for (int i=0; i < eq_cons.sz(); i++) {
+ mtor << "eq cons "<<i<<": x["<<eq_cons[i]<<"] == " << eq_consrhs[i]<<"\n";
+ }
+}
+
+
+void
+Ineq_constrained_qp::assert_solution(Vector sol) const
+{
+ svec<int> binding;
+ for (int i=0; i < cons.sz(); i++) {
+ Real R=cons[i] * sol- consrhs[i];
+ assert(R> -EPS);
+ if (R < EPS)
+ binding.add(i);
+ }
+ // KKT check...
+ // todo
+}
--- /dev/null
+#ifndef QLP_HH
+#define QLP_HH
+
+#include "matrix.hh"
+
+/// inequality constrained quadratic program
+class Ineq_constrained_qp {
+ friend class Active_constraints;
+
+ svec<Vector> cons;
+ svec<Real> consrhs;
+public:
+ Matrix quad;
+ Vector lin;
+
+
+ ///
+ void assert_solution(Vector sol) const;
+ /**
+ use a KKT method to assert optimality of sol
+ */
+ /// solve the problem using a variable metric method
+ Vector solve(Vector start) const;
+
+ int dim() const{
+ return lin.dim();
+ }
+ /** return the number of variables in the problem */
+ ///
+ void add_inequality_cons(Vector c, double r);
+ /**
+ add a constraint
+
+
+ c*vars >= r
+
+ PRE
+ c.dim() == dim();
+
+ */
+ ///
+ Ineq_constrained_qp(int novars);
+ /** set up matrices to go with the problem. */
+
+ Real eval(Vector v);
+ /**
+ evaluate the quadratic function for input #v#
+ */
+
+ void eliminate_var(int idx, Real value);
+ void OK()const;
+ void print() const;
+
+};
+
+/// Quadratic programming with mixed linear constraints
+class Mixed_qp :public Ineq_constrained_qp {
+ svec<int> eq_cons;
+ svec<Real> eq_consrhs;
+public:
+ Mixed_qp(int n);
+ void OK() const;
+ void print() const;
+
+ Vector solve(Vector start) const;
+ void add_fixed_var(int i , Real value);
+
+ ///
+ void add_equality_cons(Vector c, double r);
+ /**
+ add a constraint,
+
+ c*vars == r
+
+ PRE
+ c.dim()==dim();
+ */
+
+};
+/**
+ problem definition of a quadratic optimisation problem with linear
+ inequality and equality constraints
+
+
+ x^T QUAD x /2 + b^T x
+*/
+
+typedef Mixed_qp Optimisation_problem;
+#endif
--- /dev/null
+#include "qlpsolve.hh"
+#include "debug.hh"
+#include "choleski.hh"
+
+const Real TOL=1e-2; // roughly 1/10 mm
+
+String
+Active_constraints::status() const
+{
+ String s("Active|Inactive [");
+ for (int i=0; i< active.sz(); i++) {
+ s += String(active[i]) + " ";
+ }
+
+ s+="|";
+ for (int i=0; i< inactive.sz(); i++) {
+ s += String(inactive[i]) + " ";
+ }
+ s+="]";
+
+ return s;
+}
+
+void
+Active_constraints::OK() {
+ H.OK();
+ A.OK();
+ assert(active.sz() +inactive.sz() == opt->cons.sz());
+ assert(H.dim() == opt->dim());
+ assert(active.sz() == A.rows());
+ svec<int> allcons;
+
+ for (int i=0; i < opt->cons.sz(); i++)
+ allcons.add(0);
+ for (int i=0; i < active.sz(); i++) {
+ int j = active[i];
+ allcons[j]++;
+ }
+ for (int i=0; i < inactive.sz(); i++) {
+ int j = inactive[i];
+ allcons[j]++;
+ }
+ for (int i=0; i < allcons.sz(); i++)
+ assert(allcons[i] == 1);
+}
+
+Vector
+Active_constraints::get_lagrange(Vector gradient)
+{
+ Vector l(A*gradient);
+
+ return l;
+}
+
+void
+Active_constraints::add(int k)
+{
+ // add indices
+ int cidx=inactive[k];
+ active.add(cidx);
+
+ inactive.swap(k,inactive.sz()-1);
+ inactive.pop();
+
+ Vector a( opt->cons[cidx] );
+ // update of matrices
+ Vector Ha = H*a;
+ Real aHa = a*Ha;
+
+ H -= Matrix(Ha , Ha)/(aHa);
+
+ Vector addrow(Ha/(aHa));
+ A -= Matrix(A*a, addrow);
+ A.insert_row(addrow,A.rows());
+}
+
+void
+Active_constraints::drop(int k)
+{
+ int q=active.sz()-1;
+
+ // drop indices
+ inactive.add(active[k]);
+ active.swap(k,q);
+ A.swap_rows(k,q);
+ active.pop();
+
+ Vector a(A.row(q));
+ H += Matrix(a,a)/(a*opt->quad*a);
+ A -= A*opt->quad*Matrix(a,a)/(a*opt->quad*a);
+
+ Vector rem_row(A.row(q));
+ assert(rem_row.norm() < EPS);
+ A.delete_row(q);
+}
+
+
+Active_constraints::Active_constraints(Ineq_constrained_qp const *op)
+ : A(0,op->dim()),
+ H(op->dim()),
+ opt(op)
+{
+ for (int i=0; i < op->cons.sz(); i++)
+ inactive.add(i);
+ Choleski_decomposition chol(op->quad);
+ H=chol.inverse();
+}
+
+/* Find the optimum which is in the planes generated by the active
+ constraints.
+ */
+Vector
+Active_constraints::find_active_optimum(Vector g)
+{
+ return H*g;
+}
+
+/****************************************************************/
+
+int
+min_elt_index(Vector v)
+{
+ Real m=INFTY; int idx=-1;
+ for (int i = 0; i < v.dim(); i++)
+ if (v(i) < m) {
+ idx = i;
+ m = v(i);
+ }
+ return idx;
+}
+
+///the numerical solving
+Vector
+Ineq_constrained_qp::solve(Vector start) const
+{
+ Active_constraints act(this);
+
+
+ act.OK();
+
+
+ Vector x(start);
+ Vector gradient=quad*x+lin;
+
+
+ Vector last_gradient(gradient);
+ int iterations=0;
+
+ while (iterations++ < MAXITER) {
+ Vector direction= - act.find_active_optimum(gradient);
+
+ // mtor << "gradient "<< gradient<< "\ndirection " << direction<<"\n";
+
+ if (direction.norm() > EPS) {
+ // mtor << act.status() << '\n';
+
+ Real minalf = INFTY;
+
+ Inactive_iter minidx(act);
+
+
+ /*
+ we know the optimum on this "hyperplane". Check if we
+ bump into the edges of the simplex
+ */
+
+ for (Inactive_iter ia(act); ia.ok(); ia++) {
+
+ if (ia.vec() * direction >= 0)
+ continue;
+ Real alfa= - (ia.vec()*x - ia.rhs())/
+ (ia.vec()*direction);
+
+ if (minalf > alfa) {
+ minidx = ia;
+ minalf = alfa;
+ }
+ }
+ Real unbounded_alfa = 1.0;
+ Real optimal_step = MIN(minalf, unbounded_alfa);
+
+ Vector deltax=direction * optimal_step;
+ x += deltax;
+ gradient += optimal_step * (quad * deltax);
+
+ //mtor << "step = " << optimal_step<< " (|dx| = " <<
+ //deltax.norm() << ")\n";
+
+ if (minalf < unbounded_alfa) {
+ /* bumped into an edge. try again, in smaller space. */
+ act.add(minidx.idx());
+ continue;
+ }
+ /*ASSERT: we are at optimal solution for this "plane"*/
+
+
+ }
+
+ Vector lagrange_mult=act.get_lagrange(gradient);
+ int m= min_elt_index(lagrange_mult);
+
+ if (m>=0 && lagrange_mult(m) > 0) {
+ break; // optimal sol.
+ } else if (m<0 && gradient.norm() < EPS) {
+ break;
+ }
+
+ mtor << "dropping cons " << m<<'\n';
+ act.drop(m);
+ }
+ if (iterations >= MAXITER)
+ WARN<<"didn't converge!\n";
+
+ // mtor << ": found " << x<<" in " << iterations <<" iterations\n";
+ assert_solution(x);
+ return x;
+}
+
+/** Mordecai Avriel, Nonlinear Programming: analysis and methods (1976)
+ Prentice Hall.
+
+ Section 13.3
+
+ This is a "projected gradient" algorithm. Starting
+ from a point x the next point is found in a direction determined by
+ projecting the gradient onto the active constraints. */
+
+/*
+ thoroughly hacked to barely living tiny pieces by HW
+ */
--- /dev/null
+#include "qlp.hh"
+#include "matrix.hh"
+
+
+class Active_constraints {
+ friend class Inactive_iter;
+
+
+ Matrix A,H;
+ svec<int> active;
+ svec<int> inactive; // actually this is a set, not an array.
+ const Ineq_constrained_qp *opt;
+
+public:
+ String status()const;
+
+ Vector vec(int k) const { return opt->cons[k]; }
+ Real rhs(int k) const { return opt->consrhs[k]; }
+
+ /// drop constraint
+ void drop (int k);
+ /** drop constraint k from the active set. k is the index of the
+ constraint in #active#
+
+ */
+
+ /// add constraint j
+ void add(int j);
+ /**
+ add constraint j to the active set j is the index of the
+ constraint in #inactive#
+ */
+
+ /// exchange in and out.
+ void exchange(int in, int out) { add(in); drop (out); }
+
+ ///
+ Vector find_active_optimum(Vector g);
+
+ /// get lagrange multipliers.
+ Vector get_lagrange(Vector v);
+
+ Active_constraints(Ineq_constrained_qp const *op);
+ /** construct: no constraints active, n vars. Put the equalities
+ into the constraints. */
+
+ /// check invariants
+ void OK();
+};
+
+/**
+ This class represents the set of active (binding) constraints
+ which can be active while the QLP algorithm is in a feasible
+ point. The active constraints are numbered.
+ If the constraints are of the form
+
+ A^T*x >= b
+
+ then the binding constraints are those where the >= is equality.
+
+ */
+
+///
+class Inactive_iter {
+ int j;
+ Active_constraints const* ac;
+public:
+ Inactive_iter(Active_constraints const &c) { ac=&c; j=0; }
+ int idx() const { return j; }
+ void operator ++(int) { j++; }
+ int constraint_id() const { return ac->inactive[j]; }
+ Vector vec() const { return ac->vec(constraint_id()); }
+ Real rhs() const { return ac->rhs(constraint_id()); }
+ bool ok() const { return j < ac->inactive.sz(); }
+};
+/**
+ loop through the inactive constraints.
+ */
--- /dev/null
+#ifndef REAL_HH
+#define REAL_HH
+typedef double Real;
+inline Real sqr(Real x){
+ return x*x;
+}
+inline Real MIN(Real x, Real y) {
+ return (x < y)? x : y;
+}
+
+inline Real MAX(Real x, Real y) {
+ return (x > y) ? x : y;
+}
+
+inline Real ABS(Real x)
+{
+ return (x>0)? x:-x;
+}
+inline
+int sgn(Real x) {
+ if (!x)return 0;
+ return (x > 0) ?1: -1;
+}
+
+#endif
--- /dev/null
+#include "request.hh"
+Request::Request(Voice_element*v)
+{
+ elt = v;
+ tag = UNKNOWN;
+}
+
+Note_req::Note_req(Voice_element*v):
+ Request(v)
+{
+ name = 'c';
+ octave = 0;
+ accidental = 0;
+ forceacc = false;
+ balltype = 1;
+ dots = 0;
+ tag = NOTE;
+}
+
+Rest_req::Rest_req(Voice_element*v)
+ :Request(v)
+{
+ balltype = 1;
+ dots = 0;
+ tag =REST;
+}
+
+Request::Request()
+{
+ elt = 0;
+ tag = UNKNOWN;
+}
+
+Note_req*
+Request::note()
+{
+ assert(tag == NOTE);
+ return (Note_req*)this;
+}
+
+Rest_req*
+Request::rest()
+{
+ assert(tag == REST);
+ return (Rest_req*)this;
+}
+
+
+Real
+wholes(int dur, int dots)
+{
+ Real f = 1.0/Real(dur);
+ Real delta = f;
+
+ while (dots--) {
+ delta /= 2.0;
+ f += delta;
+ }
+ return f;
+}
+
+Real
+Note_req::duration() const {
+ return wholes( balltype,dots);
+}
+Real
+Rest_req::duration() const{
+ return wholes( balltype,dots);
+}
+
--- /dev/null
+// mpp96's second egg of columbus!
+#ifndef REQUEST_HH
+#define REQUEST_HH
+
+#include "glob.hh"
+#include "string.hh"
+#include "mtime.hh"
+struct Request {
+ Voice_element*elt;
+ enum {
+ UNKNOWN, NOTE, REST, LYRIC, SCRIPT, CHORD, BEAM,
+ BRACKET, STEM, SLUR, CRESC, DECRESC, ABSDYNAMIC
+ } tag;
+
+ Note_req *note();
+ Rest_req *rest();
+ Request(Voice_element*);
+ Request();
+ virtual Real duration() const { return 0.0; }
+};
+
+/**
+ Any Voice_element can do a number of requests. A request is done
+ to the #Staff# which contains the #Voice_element#. The staff decides
+ whether to to honor the request, ignore it, or merge it with other
+ requests. Merging of requests is preferably done with other
+ requests done by members of the same voicegroups (beams, brackets, stems)
+
+ Please refer to the documentation of the Child classes of
+ #Request# for explanation of each request type.
+
+ The result of a request will be an #Item# or a #Spanner#, which
+ will be put on a #PStaff#. Note that the #PStaff# and the original
+ #Staff# need not have anything in common. For example, the
+ ``double'' piano Staff could interpret commands which juggle
+ melodies across the left and right hand, and may put the result in
+ two five-line PStaffs (maybe with extra PStaffs to carry the dynamic
+ signs and any lyric.
+
+ The class #Staff# should be thought as a container for the
+ #Voice#s, and an interpreter for #Request#s and #Command#s.
+ Different staffs can produce different outputs; a melodious voice
+ which is put into a percussion-Staff, will be typeset as the rythm of
+ that voice.
+
+ After #Staff# made up her mind (Would #Staff# be a smart
+ name? How about #struct Lily {}# :-), the resultant items and
+ spanners are put on the PScore, and pointers to these items are
+ stored in the #Voice_element#. This construction enables the
+ beams/stems to look up the balls it has to connect to. */
+
+
+
+/// Put a note of specified type, height, and with accidental on the staff.
+struct Note_req : Request {
+ char name;
+ int octave;
+ int accidental;
+ bool forceacc;
+ int balltype;
+ int dots;
+
+ Real duration() const;
+ Note_req(Voice_element*v);
+};
+/**
+Staff has to decide if the ball should be hanging left or right. This
+influences the horizontal dimensions of a column, and this is why
+request processing should be done before horizontal spacing.
+
+Other voices' frivolities may cause the need for accidentals, so this
+is also for the Staff to decide. The Staff can decide on positioning
+based on ottava commands and the appropriate clef.
+*/
+
+///Put a lyric above or below (?) this staff.
+struct Lyric_req : Request {
+ String text;
+};
+
+
+///Put a script above or below this ``note''
+struct Script_req : Request {
+ int orientation;
+ Symbol *sym;
+};
+/**
+eg upbow, downbow. Why a request? These symbols may conflict with slurs and brackets, so this
+also a request
+*/
+
+
+///Put a rest on the staff.
+struct Rest_req : Request {
+ int balltype;
+ int dots;
+ Rest_req(Voice_element*);
+ Real duration() const;
+};
+/**
+Why a request? It might be a good idea to not typeset the rest, if the paper is too crowded.
+*/
+
+
+
+///Draw a (Guitar) chord above or below this ``note''
+struct Chord : Request {
+ // don't know how this looks.
+};
+/**
+Why a request?
+Because everything else is done in requests.
+*/
+
+
+/// for absolute dynamics
+enum Loudness {
+ FFF, FF, F, MF, MP, P, PP, PPP
+} ;
+
+/// attach a stem to the noteball
+struct Stem_req : Request {
+ /// 4,8,16, ..
+ int stem_number ;
+};
+/// requests to start or stop something.
+struct Span_req : Request {
+ /// should the spanner start or stop, or is it unwanted?
+ enum {
+ NOSPAN, START, STOP
+ } spantype ;
+};
+/**
+ This type of request typically results in the creation of a #Spanner#
+*/
+
+
+///Start / stop a beam at this note.
+struct Beam_req : Span_req {
+ int nplet;
+};
+/** Staff will have to combine this with the stem_request, since the
+ number of flags that a stem wants to carry will determine the
+ number of beams. if #nplet# is set, the staff will try to put an
+ appropriate number over the beam
+
+ [what to do if the nplet fields of start and stop conflict?]
+ */
+
+///Start / stop a slur or a bracket.
+struct Bracket_req : Span_req {
+ int nplet;
+};
+/**
+Start/stop a bracket at this note. if #nplet# is set, the staff will
+try to put an appropriate number over the bracket
+*/
+
+/// a slur
+struct Slur_req : Span_req {
+
+};
+
+/// helper in the hierarchy
+struct Dynamic {
+ Mtime subtime;
+};
+/** Each dynamic is bound to one note ( a crescendo spanning multiple
+ notes is thought to be made of two "dynamics": a start and a stop).
+ Dynamic changes can occur in a smaller time than the length of its
+ note, therefore fore each Dynamic request carries a time, measured
+ from the start of its note.
+
+ This subfield would come in handy, if mpp96 was adapted for midi
+ support.
+
+ Dynamic should have been derived from request, but I don't want to
+ fuss with virtual baseclasses. */
+
+/// do a crescendo
+struct Cresc_req : Span_req, Dynamic {
+
+};
+
+/// do a decrescendo
+struct Decresc_req : Span_req, Dynamic {
+
+};
+
+/// do a dynamic like "fff" or "mp"
+struct Absdynamic_req : Request, Dynamic {
+ Loudness loudness;
+};
+
+#endif
--- /dev/null
+#include "request.hh"
+#include "debug.hh"
+#include "linestaff.hh"
+#include "staff.hh"
+#include "pstaff.hh"
+#include "pscore.hh"
+#include "command.hh"
+#include "molecule.hh"
+#include "rhythmstaf.hh"
+
+
+
+Rhythmic_column::Rhythmic_column(Score_column*s, Rhythmic_staff *rs)
+ : Staff_column(s)
+{
+ the_note = 0;
+ staff_ = rs;
+}
+
+
+void
+Rhythmic_staff::set_output(PScore* ps )
+{
+ theline = new Linestaff(1);
+ pscore_ = ps;
+ pscore_->add(theline);
+}
+
+// should integrate handling of BREAK commands into Staff_column
+void
+Rhythmic_column::process_commands( )
+{
+ int breakstat = BREAK_END;
+ for (int i = 0 ; i < s_commands.sz(); i++) {
+ Command *com = s_commands[i];
+ switch (com->code){
+ case INTERPRET:
+ break;
+ case BREAK_PRE:
+ case BREAK_MIDDLE:
+ case BREAK_POST:
+ case BREAK_END:
+ score_column->set_breakable();
+ breakstat = com->code;
+ break;
+
+ case TYPESET:
+ typeset_command ( com , breakstat);
+ break;
+ default :
+ break;
+ }
+
+ }
+}
+/**
+ accept:
+
+ BREAK: all
+ TYPESET: bar, meter
+
+ */
+
+
+
+void
+Rhythmic_column::process_requests()
+{
+ for (int i = 0 ; i < v_elts.sz(); i ++)
+ for (PCursor<Request *> rqc(v_elts[i]->reqs); rqc.ok(); rqc++) {
+ Request *rq= rqc;
+ switch(rq->tag){
+ case Request::NOTE:
+ case Request::REST:
+ if (the_note){
+ WARN << "too many notes.\n";
+ return;
+ }
+ the_note = rq;
+ break;
+
+ default:
+ return;
+ }
+ }
+
+}
+
+
+void
+Rhythmic_column::typeset_command(Command *com, int breakst)
+{
+ Item *i = new Item;
+ const Symbol*s=0;
+
+ if (com -> args[0] == "|" ) {
+ s = Symbol::find_bar("|");
+ } else
+ assert(false);
+
+ i->output=new Molecule(Atom(s));
+ staff_->pscore_->typeset_item(i, score_column->pcol,
+ staff_->theline,breakst);
+}
+
+void
+Rhythmic_column::typeset_req(Request *rq)
+{
+ Item *i = new Item;
+ const Symbol*s=0;
+
+ switch(rq->tag){
+ case Request::NOTE:
+ s = Symbol::find_ball(rq->note()->balltype);
+ break;
+ case Request::REST:
+ s = Symbol::find_rest(rq->rest()->balltype);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ i->output = new Molecule(Atom(s));
+
+ staff_->pscore_->typeset_item(i, score_column->pcol, staff_->theline,0 );
+}
+
+void
+Rhythmic_staff::grant_requests()
+{
+ for (PCursor<Staff_column*> cc(cols); cc.ok(); cc++) {
+ Rhythmic_column *rp = (Rhythmic_column*)*cc;
+ if (rp->the_note)
+ rp->typeset_req( rp->the_note);
+ }
+}
+
+Staff_column*
+Rhythmic_staff::create_col(Score_column*s)
+{
+ Rhythmic_column *rc = new Rhythmic_column(s,this);
+
+ return rc;
+}
+
+Staff *
+get_new_rhythmstaff()
+{
+ return new Rhythmic_staff;
+}
--- /dev/null
+struct Rhythmic_staff;
+
+/// column of Rhythmic_staff
+struct Rhythmic_column : Staff_column {
+ // mega-stupido. only do notes, one at a time
+ Request *the_note;
+ Rhythmic_staff* staff_;
+
+ /****************/
+
+ void typeset_req(Request *rq);
+ void take_request(Request *rq);
+ void typeset_command(Command *, int brs);
+ void process_commands( );
+ void process_requests();
+
+ Rhythmic_column(Score_column*s,Rhythmic_staff*rs);
+};
+
+
+/// simple percussion staff
+struct Rhythmic_staff : Staff {
+ /// indirection to the PStaff.
+ PStaff *theline;
+ void set_output(PScore *);
+ void process_commands( PCursor<Command*> &where);
+
+ void grant_requests();
+ Staff_column * create_col(Score_column*);
+};
+
--- /dev/null
+#include <time.h>
+#include "tstream.hh"
+#include "score.hh"
+#include "pscore.hh"
+#include "staff.hh"
+#include "misc.hh"
+#include "debug.hh"
+
+void
+Score::add(Command *c)
+{
+ commands_.bottom().add(new Command(*c));
+}
+
+void
+Score::add(Staff*s)
+{
+ s->score_ = this;
+ staffs_.bottom().add(s);
+}
+
+
+void
+Score::do_pcols()
+{
+ PCursor<Score_column*> sc(cols_);
+ for (;sc.ok(); sc++) {
+ pscore_->add(sc->pcol);
+ }
+}
+/*
+ this sux. Really makeshift.
+ */
+void
+Score::do_miscs()
+{
+ Command c;
+
+ c.when = 0.0;
+
+ c.code = BREAK_END;
+ commands_.top().insert(new Command(c));
+ c.code = BREAK_POST;
+ commands_.top().insert(new Command(c));
+ c.code = BREAK_MIDDLE;
+ commands_.top().insert(new Command(c));
+ c.code = BREAK_PRE;
+ commands_.top().insert(new Command(c));
+
+ PCursor<Command*> bot(commands_.bottom());
+ c.when = last();
+ while (bot.ok() && bot->when > c.when) {
+// mtor <<"removing "<< bot->code <<" at " << bot->when<<'\n';
+ bot.remove();
+ bot = commands_.bottom();
+ }
+
+ c.code = BREAK_PRE;
+ bot.add(new Command(c));
+ bot++;
+ c.code = BREAK_MIDDLE;
+ bot.add(new Command(c));
+ bot++;
+ c.code = BREAK_POST;
+ bot.add(new Command(c));
+ bot++;
+ c.code = BREAK_END;
+ bot.add(new Command(c));
+
+ commands_.OK();
+}
+
+Mtime
+Score::last() const
+{
+ Mtime l = 0;
+ for (PCursor<Staff*> stc(staffs_); stc.ok(); stc++) {
+ l = MAX(l, stc->last());
+ }
+ return l;
+}
+void
+Score::clean_commands()
+{
+ Mtime l= last();
+ for (PCursor<Command*> cc(commands_); cc.ok(); cc++) {
+ if (cc->when > l){
+ mtor << "remming \n";
+ cc.remove();
+ }
+ }
+}
+void
+Score::process()
+{
+ do_miscs();
+
+ /// distribute commands to disciples
+ distribute_commands();
+
+ pscore_ = new PScore;
+ for (PCursor<Staff*> sc(staffs_); sc.ok(); sc++) {
+ sc->set_output(pscore_);
+ sc->process();
+ }
+ do_pcols();
+ calc_idealspacing();
+ clean_cols();
+ OK();
+ // print();
+ pscore_->calc_breaking();
+}
+
+// remove empty cols with no spacing attached.
+/* should rethink ownership of cols
+ */
+void
+Score::clean_cols()
+{
+ for (PCursor<Staff * > sc(staffs_); sc.ok(); sc++)
+ sc->clean_cols();
+ for (PCursor<Score_column*> c(cols_); c.ok(); c++) {
+ if (!c->pcol->used) {
+// mtor << "removing : "; c->print();
+ c.remove();
+ }
+ }
+
+ pscore_->clean_cols();
+}
+/* this sux. We should have Score_column create the appropriate PCol.
+ Unfortunately, PCols don't know about their position.
+ */
+// todo
+PCursor<Score_column*>
+Score::create_cols(Mtime w)
+{
+ Score_column* c1 = new Score_column(w);
+ Score_column* c2 = new Score_column(w);
+
+ c1->musical = false;
+ c2->musical = true;
+
+ PCursor<Score_column*> scc(cols_);
+
+ for (; scc.ok(); scc++) {
+ assert(scc->when != w);
+ if (scc->when > w)
+ break;
+ }
+
+ if (!scc.ok()) {
+ cols_.bottom().add(c1);
+ cols_.bottom().add(c2);
+ scc = cols_.bottom();
+ scc --;
+ } else {
+ scc.insert(c1);
+ scc.insert(c2);
+ scc -= 2;
+ }
+ return scc;
+}
+
+Score_column*
+Score::find_col(Mtime w,bool mus)
+{
+ PCursor<Score_column*> scc(cols_);
+ for (; scc.ok(); scc++) {
+ if (scc->when == w && scc->musical == mus)
+ return scc;
+ if (scc->when > w)
+ break;
+ }
+ scc = create_cols(w);
+ if (mus)
+ scc++;
+ return scc;
+}
+
+void
+Score::distribute_commands(void)
+{
+ for (PCursor<Staff*> sc(staffs_); sc.ok(); sc++) {
+ sc->add_commands(commands_);
+ }
+}
+
+
+void
+Score::output(String s)
+{
+ OK();
+ mtor << "output to " << s << "...\n";
+
+ Tex_stream the_output(s);
+ the_output << "% Automatically generated by LilyPond 0.0 at";
+ time_t t(time(0));
+ the_output << ctime(&t)<<"\n";
+ the_output << "% from input file ..\n";
+ pscore_->output(the_output);
+}
+
+void
+Score::OK() const
+{
+ for (PCursor<Staff*> sc(staffs_); sc.ok(); sc++) {
+ sc->OK();
+ assert(sc->score_ == this);
+ }
+ staffs_.OK();
+ cols_.OK();
+ for (PCursor<Score_column*> cc(cols_); cc.ok() && (cc+1).ok(); cc++) {
+ assert(cc->when <= (cc+1)->when);
+ }
+ for (PCursor<Command*> cc(commands_); cc.ok() && (cc+1).ok(); cc++) {
+ assert(cc->when <= (cc+1)->when);
+ }
+
+}
+
+void
+Score::print() const
+{
+ mtor << "score {\n";
+ for (PCursor<Staff*> sc(staffs_); sc.ok(); sc++) {
+ sc->print();
+ }
+ for (PCursor<Score_column*> sc(cols_); sc.ok(); sc++) {
+ sc->print();
+ }
+ mtor << "}\n";
+}
+
+/****************************************************************/
+
+Score_column::Score_column(Mtime w)
+{
+ when = w;
+ pcol = new PCol(0);
+ musical = false;
+}
+
+bool
+Score_column::used() {
+ return pcol->used;
+}
+
+void
+Score_column::print() const
+{
+ mtor << "Score_column { mus "<< musical <<" at " << when<<'\n';
+ mtor << " # symbols: " << pcol->its.size() << "\n";
+ mtor << "durations: [" ;
+ for (int i=0; i < durations.sz(); i++)
+ mtor << durations[i] << " ";
+ mtor << "]\n}\n";
+}
--- /dev/null
+#ifndef SCORE_HH
+#define SCORE_HH
+
+#include "vray.hh"
+#include "cols.hh"
+#include "mtime.hh"
+#include "command.hh"
+
+struct Score_column {
+ PCol * pcol;
+ svec<Mtime> durations;
+ Mtime when;
+
+ ///
+ bool musical;
+
+
+ Score_column(Mtime when);
+
+ static int compare(Score_column & c1, Score_column &c2) {
+ return sgn(c1.when - c2.when);
+ }
+ void set_breakable() {
+ pcol->set_breakable();
+ }
+ bool used();
+ void print() const;
+};
+/**
+
+ When typesetting hasn't started on PScore yet, the columns which
+ contain data have a rhythmical position. Score_column is the type
+ with a rhythmical time attached to it. The calculation of
+ idealspacing is done with data in these columns. (notably: the
+ #durations# field)
+
+ */
+
+instantiate_compare(Score_column&, Score_column::compare);
+
+
+/// the total music def of one movement
+struct Score {
+ /// staffs_ and commands_ form the problem definition.
+ PointerList<Staff *> staffs_;
+ PointerList<Command*> commands_;
+
+ /// "runtime" fields for setting up spacing
+ PointerList<Score_column*> cols_;
+ PScore *pscore_;
+
+ /****************************************************************/
+
+ /// add #Idealspacings# to #pscore_#
+ void calc_idealspacing();
+ void process();
+
+ /// construction
+ void add_staff(Staff *st);
+
+ void distribute_commands();
+ /** add the score wide commands (bars, breaks) to each staff so
+ they can process (typeset) them if needed */
+ void OK() const;
+ Score_column *find_col(Mtime,bool);
+ void do_pcols();
+ void add(Command *);
+ void add(Staff*);
+ void output(String fn);
+ PCursor<Score_column*> create_cols(Mtime);
+ void print() const;
+ void do_miscs() ;
+ Mtime last() const;
+ void clean_cols();
+ void clean_commands();
+
+ void do_connect(PCol *c1, PCol *c2, Real d);
+ void connect_nonmus(PCol* c1, PCol *c2, Real d);
+};
+/**
+
+ */
+#endif
--- /dev/null
+#include "smat.hh"
+
+void
+Full_storage::operator=(Full_storage const &fs)
+{
+ resize(fs.h, fs.w);
+ OK();
+ fs.OK();
+ for (int i=0; i<h; i++)
+ for (int j=0; j<w; j++)
+ els[i][j]= fs.els[i][j];
+}
+
+void
+Full_storage::OK() const
+{
+ // static Real dummy;
+ assert(maxh >= h && maxw >= w);
+ assert(h >= 0 && w >= 0);
+ assert(els||!maxh);
+ if (maxh>0) { // access outer elts.
+ Real *r = els[maxh -1];
+ if (maxw>0) {
+ assert(r);
+ Real s = r[maxw -1];
+ s = sin(s);
+ }
+ }
+}
+void
+Full_storage::resize_cols(int newh)
+{
+ if (newh <= maxh) {
+ h=newh;
+ return;
+ }
+
+ Real ** newa=new Real*[newh];
+ int j=0;
+ for (; j < h; j++)
+ newa[j] = els[j];
+ for (; j < newh; j++)
+ newa[j] = new Real[maxw];
+ delete[] els;
+ els=newa;
+
+ h = maxh = newh;
+}
+
+void
+Full_storage::resize_rows(int neww)
+{
+ if (neww <= maxw) {
+ w=neww;
+ return;
+ }
+ for (int i=0; i < maxh ; i++) {
+ Real* newa=new Real[neww];
+ for (int k=0; k < w; k++)
+ newa[k] = els[i][k];
+
+ delete[] els[i];
+ els[i] = newa;
+ }
+ w = maxw = neww;
+}
+
+Full_storage::~Full_storage() {
+ for (int i=0; i < maxh; i++)
+ delete [] els[i];
+ delete[] els;
+}
+
+void
+Full_storage::resize(int rows, int cols)
+{
+ OK();
+ resize_cols(rows);
+ resize_rows(cols);
+
+}
+
+
+bool
+Full_storage::mult_ok(int i, int j) const
+{
+ return valid(i,j);
+}
+
+bool
+Full_storage::trans_ok(int i, int j) const
+{
+ return valid(i,j);
+}
+
+
+void
+Full_storage::trans_next(int &i, int &j) const
+{
+ assert(trans_ok(i,j));
+ i++;
+ if (i >= h) {
+ i=0;
+ j ++;
+ }
+}
+
+void
+Full_storage::mult_next(int &i, int &j) const
+{
+ assert(mult_ok(i,j));
+ j++;
+ if (j >= w) {
+ j=0;
+ i++;
+ }
+}
+
+void
+Full_storage::delete_column(int k)
+{
+ assert(0 <= k &&k<w);
+ for (int i=0; i< h ; i++)
+ for (int j=k+1; j <w; j++)
+ els[i][j-1]=els[i][j];
+ w--;
+}
+void
+Full_storage::delete_row(int k)
+{
+ assert(0 <= k &&k<h);
+ for (int i=k+1; i < h ; i++)
+ for (int j=0; j < w; j++)
+ els[i-1][j]=els[i][j];
+ h--;
+}
+
+
+void
+Full_storage::insert_row(int k)
+{
+ assert(0 <= k&& k <=h);
+ resize_cols(h+1);
+ for (int i=h-1; i > k ; i--)
+ for (int j=0; j <w; j++)
+ els[i][j]=els[i-1][j];
+
+}
+
+
+svec<Real>
+Full_storage::row(int n) const
+{
+ svec<Real> r;
+ for (int j = 0; j < w; j++)
+ r.add(els[n][j]);
+ return r;
+}
+
+svec<Real>
+Full_storage::column(int n) const
+{
+
+ svec<Real> r;
+ for (int i = 0; i<h; i++)
+ r.add(els[i][n]);
+ return r;
+}
+
+
+Full_storage::Full_storage(Full_storage&s)
+{
+ init();
+ (*this) = s;
+}
+virtual_smat*
+Full_storage::clone()
+{
+ return new Full_storage(*this);
+}
+/****************************************************************/
+
+virtual_smat *
+virtual_smat::get_full(int n, int m)
+{
+ return new Full_storage(n,m);
+}
--- /dev/null
+#ifndef SMAT_HH
+#define SMAT_HH
+#include "vray.hh"
+#include "vsmat.hh"
+#include "real.hh"
+/// simplest matrix storage. refer to its baseclass for the doco.
+class Full_storage : public virtual_smat
+{
+ /// height, width
+ int h,w;
+ /// maxima.
+ int maxh, maxw;
+
+ /// the storage
+ Real** els;
+ void
+ init() {
+ els=0;
+ h=w=maxh=maxw=0;
+
+ }
+
+ bool valid(int i, int j) const {
+ return (i>=0 && i < h)
+ && (j < w && j >=0);
+ }
+
+
+ void resize_rows(int);
+ void resize_cols(int);
+
+public:
+ virtual int rows() const {
+ return h;
+ }
+ virtual int cols() const {
+ return w;
+ }
+
+
+ virtual void set_size(int i, int j)
+ {
+ resize(i,j); //this could be more efficient.
+ }
+
+ virtual void set_size(int i) {
+ set_size(i,i);
+ }
+ virtual void resize(int i, int j);
+ virtual void resize(int i) {
+ resize(i,i);
+ }
+
+ virtual Real& elem(int i,int j) {
+ assert(valid(i,j));
+ return els[i][j];
+ }
+ virtual const Real& elem(int i, int j) const {
+ assert(valid(i,j));
+ return els[i][j];
+ }
+ virtual svec<Real> row(int i) const;
+ virtual svec<Real> column(int j) const;
+
+ Full_storage() {
+ init();
+ }
+ Full_storage(int i, int j) {
+ init();
+ set_size(i,j);
+ }
+ Full_storage(Full_storage&);
+ Full_storage(int i) {
+ init();
+ set_size(i);
+ }
+ void OK() const;
+ void operator=(Full_storage const &);
+
+ virtual void insert_row(int k);
+ virtual void delete_row(int k);
+ virtual void delete_column(int k);
+
+
+ ~Full_storage();
+ virtual bool mult_ok(int i, int j)const;
+ virtual void mult_next(int &i, int &j) const ;
+ virtual bool trans_ok(int i, int j) const;
+ virtual void trans_next(int &i, int &j) const;
+ virtual virtual_smat * clone();
+};
+
+#endif
--- /dev/null
+#include "staff.hh"
+#include "debug.hh"
+#include "pscore.hh"
+
+void
+Staff::clean_cols()
+{
+ PCursor<Staff_column *> stc(cols);
+ for(; stc.ok(); stc++){
+ if (!stc->score_column->used())
+ stc.remove();
+ }
+}
+
+/*
+ maak een staff column, met specs in args.
+
+ (sorry wat is het vroeg vandaag..)
+ */
+Staff_column *
+Staff::get_col(Mtime w, bool mus)
+{
+ Score_column* sc = score_->find_col(w,mus);
+ assert(sc->when == w);
+ PCursor<Staff_column *> stc(cols);
+ for (; stc.ok(); stc++) {
+ if (*sc < *stc->score_column)
+ break;
+ if (sc == stc->score_column)
+ return stc;
+ }
+ Staff_column* newst = create_col(sc);
+
+ if (!stc.ok()) {
+ cols.bottom().add(newst);
+ return cols.bottom();
+ }
+
+ if (mus) {
+ stc.insert(newst);
+ return newst;
+ }
+
+ if ((stc-1)->when() == newst->when()) {
+ stc--;
+ }
+
+ stc.insert(newst);
+
+ return newst;
+}
+
+
+void
+Staff::add_voice(Voice *v)
+{
+ voices.bottom().add(v);
+}
+
+/*
+ put all stuff grouped vertically in the Staff_cols
+ */
+void
+Staff::setup_staffcols()
+{
+
+ for (PCursor<Voice*> vc(voices); vc.ok(); vc++) {
+
+ Mtime now = vc->start;
+ for (PCursor<Voice_element *> ve(vc->elts); ve.ok(); ve++) {
+
+ Staff_column *sc=get_col(now,true);
+ sc->add(ve);
+ now += ve->duration;
+ }
+ }
+
+ for (PCursor<Command*> cc(commands); cc.ok(); cc++) {
+ Staff_column *sc=get_col(cc->when,false);
+ sc->s_commands.add(cc);
+ }
+}
+
+/// merge commands from score
+void
+Staff::add_commands(PointerList<Command*> const &cl)
+{
+ PCursor<Command*> score_c(cl);
+ PCursor<Command*> cc(commands);
+
+ while (score_c.ok()) {
+ while (cc.ok() && cc->when <= score_c->when)
+ cc++;
+
+ Command*nc = new Command (*(* score_c));
+ if (cc.ok()) {
+ // cc->when > score_c->when
+ cc.insert( nc );
+ } else {
+ commands.bottom().add( nc);
+ cc = commands.bottom();
+ }
+ score_c++;
+ }
+
+ // now integrate break commands with other commands.
+ // may be do this in derived functions.
+}
+
+void
+Staff::process()
+{
+ setup_staffcols();
+ OK();
+ for (PCursor<Staff_column*> sc(cols); sc.ok(); sc++) {
+ sc->process_commands();
+ sc->process_requests();
+ }
+ grant_requests();
+}
+
+void
+Staff::OK() const
+{
+ cols.OK();
+ commands.OK();
+ voices.OK();
+ assert(score_);
+
+}
+
+
+Mtime
+Staff::last() const {
+ Mtime l = 0.0;
+ for (PCursor<Voice*> vc(voices); vc.ok(); vc++) {
+ l = MAX(l, vc->last());
+ }
+ return l;
+}
+
+
+void
+Staff::print() const
+{
+ mtor << "Staff {\n";
+ for (PCursor<Voice*> vc(voices); vc.ok(); vc++) {
+ vc->print();
+
+ }
+ mtor <<"}\n";
+}
+
+/****************************************************************/
+
+bool
+Staff_column::mus() const
+{
+ return score_column->musical;
+}
+
+Mtime
+Staff_column::when() const
+{
+ return score_column->when;
+}
+void
+Staff_column::add(Voice_element*ve)
+{
+ Mtime d= ve->duration;
+ if (d){
+ score_column->durations.add(d);
+ }
+
+ v_elts.add(ve);
+}
+Staff_column::Staff_column(Score_column*s) {
+ score_column = s;
+}
--- /dev/null
+#ifndef STAFF_HH
+#define STAFF_HH
+
+#include "score.hh"
+#include "voice.hh"
+#include "command.hh"
+
+struct Staff_column {
+ Score_column *score_column;
+
+ /// fields to collect data vertically.
+ svec<Voice_element *> v_elts;
+ svec<Command *> s_commands;
+
+ Staff_column(Score_column*s);
+ bool mus() const ;
+ Mtime when() const;
+ void add(Voice_element*ve);
+ /****************************************************************
+ VIRTUAL
+ ****************************************************************/
+ virtual void process_requests()=0;
+ virtual void process_commands()=0;
+ virtual ~Staff_column() { }
+};
+
+
+/// base class for a collection of voices.
+struct Staff {
+ /// synchronous horizontal stuff
+ PointerList<Voice*> voices;
+
+ /// commands in chronological order
+ PointerList<Command *> commands;
+ PointerList<Staff_column*> cols;
+
+ /// indirections to the Score and PScore
+ Score *score_;
+ PScore *pscore_;
+
+ void add_voice(Voice *v);
+ void add_staff_column(Staff_column *sp);
+
+
+ /// interpret all requests and add items to #destination#.
+ void process();
+ /**
+ This routines calls virtual functions from Staff, to delegate the
+ interpretation of requests to a derived class of Staff */
+
+
+ /****************************************************************
+ VIRTUALS
+ ****************************************************************/
+
+ void setup_staffcols();
+
+ virtual void set_output(PScore * destination)=0;
+ virtual void grant_requests()=0;
+
+ Staff_column * get_col(Mtime,bool);
+
+ void add_commands(PointerList<Command* >const & sv);
+ /**
+ add all commands from sv.
+
+ PRE
+ sv is time-ordered.
+ */
+ virtual Staff_column * create_col(Score_column * )=0;
+
+ void OK() const;
+ void print() const;
+ Mtime last() const;
+ void clean_cols() ;
+ virtual ~Staff() { }
+};
+#endif
--- /dev/null
+% testje
+
+score{
+ rhythmstaff {
+ voice { $ c4 c2 c4 $ }
+ }
+ rhythmstaff {
+ voice { $ c2 c2 $ }
+ }
+ rhythmstaff {
+ voice { $ c4 c4 c4 c4 $ }
+ }
+ bar 2
+}
--- /dev/null
+#include "tex.hh"
+
+Symbol::Symbol(String s, Box b)
+ : tex(s), dim(b)
+{
+}
+
--- /dev/null
+# TeXstring, xmin xmax ymin ymax
+
+table balls
+ 1 \wholeball -1 1 -1 1
+ 2 \halfball -1 1 -1 1
+ 4 \quartball -1 1 -1 1
+end
+
+table bars
+ | \maatstreep 0 1 0 10
+end
+
+table rests
+ 1 \wholerest -1 1 -1 1
+ 2 \halfrest -1 1 -1 1
+ 4 \quartrest -1 1 -1 1
+ 8 \eighthrest -1 1 -1 1
+ 16 \sixteenthrest -1 1 -1 1
+ 32 \thirtysecondrest -1 1 -1 1
+end
\ No newline at end of file
--- /dev/null
+#include "misc.hh"
+#include "debug.hh"
+#include "real.hh"
+#include "tex.hh"
+#include "assoc.hh"
+#include "symtable.hh"
+#include "const.hh"
+
+Symtable*
+Symtables::operator()(String s)
+{
+ if (!done_reading){ // read on demand
+ *mlog << '(' << fname ;
+ read();
+ done_reading = true;
+ *mlog << ")\n";
+ }
+ return Assoc<String, Symtable*>::operator[](s);
+}
+
+void
+Symtables::read()
+{
+ Text_db symini(fname);
+ while (1) {
+ if (symini.eof())
+ break;
+ Text_record r( symini++);
+ if (!r.sz())
+ continue;
+
+ assert (r[0] == "table");
+
+ String tabnam = r[1];
+ Symtable * sp = new Symtable;
+ while (1) {
+ r = symini++;
+ if (!r.sz())
+ continue;
+ if (r[0] == "end")
+ break;
+
+ assert(r.sz() == 6);
+ int i=0;
+ String id=r[i++];
+ String tex=r[i++];
+ svec<Real> dims;
+ for (int j=0; j < 4; j++)
+ dims.add( r[i++].fvalue() *1.0/CM_TO_PT);
+
+ Symbol s(tex, Box(dims));
+ (*sp)[id] = s;
+ }
+ (*this)[tabnam] = sp;
+ }
+}
+
+Symtables the_sym_tables("symbol.ini");
+
+
+const Symbol*
+Symbol::find_ball(int i)
+{
+ int j = intlog2(i);
+ if (j > 4) j = 4;
+ Symtable * st = the_sym_tables("balls");
+ return &(*st)[String(j)];
+
+}
+
+const Symbol*
+Symbol::find_rest(int i)
+{
+ int j = intlog2(i);
+ return &(*the_sym_tables("rests"))[String(j)];
+}
+const Symbol*
+Symbol::find_bar(String s)
+{
+ return &(*the_sym_tables("bars"))[s];
+}
+/****************************************************************/
+// bare bones.
+
+struct Linestaf_symbol : Stretchable_symbol {
+ int lines;
+ String operator ()(Real w);
+ Linestaf_symbol(int n) { lines = n;}
+};
+// should be done in TeX
+String
+Linestaf_symbol::operator()(Real w)
+{
+ String s;
+ s += "\\hbox to 0pt{";
+ s+= "\\vbox to 0pt{";
+ for (int i=0; i<lines; i++) {
+ if (i) s+= "\\vskip1pt";
+ s+= "\\hrule width " + String(w* HOR_TO_PT) +"pt";
+ }
+ s+="\\vss}\\hss}";
+ return s;
+}
+
+const Stretchable_symbol *
+Stretchable_symbol::get_linestaff(int n)
+{
+ return new Linestaf_symbol(n);
+}
--- /dev/null
+struct Symtable : public Assoc<String, Symbol> {
+
+};
+
+
+struct Symtables : private Assoc<String, Symtable*> {
+ String fname;
+ bool done_reading;
+ Symtables(String s) : fname (s) {
+ done_reading = false;
+ }
+ void read() ;
+ Symtable* operator()(String s);
+
+};
+
--- /dev/null
+#include "glob.hh"
+#include "string.hh"
+#include "keyword.hh"
+#include "parser.hh"
+
+static Keyword_ent the_key_tab[]={
+ "voice", VOICE,
+ "rhythmstaff", RHYTHMSTAFF,
+ "score", SCORE,
+ "bar", BAR,
+ 0,0
+} ;
+
+
+int
+lookup_keyword(String s)
+{
+ static Keyword_table table(the_key_tab);
+ return table.lookup(s);
+}
+
+Identifier*
+lookup_identifier(String s)
+{
+ assert(false);
+ return 0;
+}
--- /dev/null
+#include "line.hh"
+
+#include "list.hh"
+#include "cols.hh"
+#include "item.hh"
+#include "request.hh"
+#include "score.hh"
+#include "command.hh"
+#include "staff.hh"
+
+#include "list.cc"
+#include "cursor.cc"
+
+
+PL_instantiate(Line_of_staff);
+PL_instantiate(Item);
+PL_instantiate(Line_of_score);
+PL_instantiate(Request);
+PL_instantiate(Spanner);
+PL_instantiate(PStaff);
+PL_instantiate(Idealspacing);
+PL_instantiate(PCol);
+PL_instantiate(Command);
+PL_instantiate(Score_column);
+
+
--- /dev/null
+#include "line.hh"
+#include "voice.hh"
+#include "molecule.hh"
+#include "staff.hh"
+
+
+
+
+#include "list.cc"
+#include "cursor.cc"
+PL_instantiate(Staff_column);
+PL_instantiate(Staff);
+PL_instantiate(Voice_element);
+PL_instantiate(Voice);
+L_instantiate(Atom);
+
--- /dev/null
+\input lilyponddefs
+\input lelie.uit
+\vfil\bye
\ No newline at end of file
--- /dev/null
+#include "tex.hh"
+#include "const.hh"
+/*
+ #TeXstring# should generate a TeX string to typeset the object in
+ a hbox or vbox of exactly the objects' dimension.
+*/
+
+
+/// #h# is in points
+String
+vstrut(Real h)
+{
+ return String("\\vrule height ") + h + "pt depth 0pt width 0pt";
+}
+
+
+/// the staff with five lines.
+ struct Fiveline_staff: Stretchable_symbol {
+ String operator()(Real width) {
+ String s("\\normalebalk{ ");
+ s+=width * HOR_TO_PT;
+ s+= "pt}";
+ return s;
+ }
+};
+
--- /dev/null
+#ifndef TEX_HH
+#define TEX_HH
+#include "string.hh"
+#include "boxes.hh"
+
+struct Symbol {
+ String tex;
+ Box dim;
+
+ Symbol (String, Box );
+ static const Symbol*find_ball(int);
+ static const Symbol*find_rest(int);
+ static const Symbol*find_bar(String);
+ Symbol() { }
+};
+
+/// a symbol with a variable width
+struct Stretchable_symbol {
+public:
+
+ /// return a string for a symbol in this width.
+ virtual String operator ()(Real width)=0;
+
+ static const Stretchable_symbol* get_linestaff(int n);
+};
+
+/// anything which can be output
+struct Output {
+ virtual String TeXstring() const=0;
+ /** generate a TeX string, which typesets the symbol. Vertical
+ base position is the "origin" of the staff
+ */
+ virtual Box extent() const=0;
+};
+/**
+ any output should (at least) be outputtable for TeX, and have a
+ dimension
+*/
+
+
+/// an idea
+struct Text_gob : Output {
+ String text;
+ // fonts, sizes, etc?
+ virtual String TeXstring() const;
+ virtual Box extent() const;
+};
+
+
+/// #h# is in points
+String vstrut(Real h);
+
+
+#endif
--- /dev/null
+#include <fstream.h>
+#include "tex.hh"
+#include "tstream.hh"
+#include "debug.hh"
+
+Tex_stream::Tex_stream(String filename)
+{
+
+ os = new ofstream(filename);
+ if (!*os)
+ error("can't open " + filename);
+ nest_level = 0;
+ outputting_comment=false;
+}
+
+Tex_stream::~Tex_stream()
+{
+ assert(nest_level == 0);
+ delete os;
+}
+
+// print string. don't forget indent.
+Tex_stream &
+Tex_stream::operator<<(String s)
+{
+ for (const char *cp = s; *cp; cp++) {
+ if (outputting_comment) {
+ *os << *cp;
+ if (*cp == '\n') {
+ outputting_comment=false;
+
+ }
+ continue;
+ }
+ switch(*cp)
+ {
+ case '%':
+ outputting_comment = true;
+ *os << *cp;
+ break;
+ case '{':
+ nest_level++;
+ *os << *cp;
+ break;
+ case '}':
+ nest_level--;
+ *os << *cp;
+ assert (nest_level >= 0);
+ /* FALL THROUGH */
+
+ case '\n':
+ *os << "%\n";
+ *os << String(' ', nest_level);
+ break;
+ default:
+ *os << *cp;
+ break;
+ }
+ }
+ return *this;
+}
+
+
+/****************************************************************/
--- /dev/null
+#ifndef TSTREAM__HH
+#define TSTREAM__HH
+
+#include <iostream.h>
+#include "string.hh"
+
+/// TeX output
+struct Tex_stream {
+ bool outputting_comment;
+ ostream *os;
+ int nest_level;
+
+ /// open a file for writing
+ Tex_stream(String filename);
+
+ /// delegate conversion to string class.
+ Tex_stream &operator<<(String);
+
+ /// close the file
+ ~Tex_stream();
+};
+/**
+ Use this class for writing to a TeX file.
+ It counts braces to prevent nesting errors, and
+ it will add a comment sign before each newline.
+ */
+#endif
--- /dev/null
+#include "debug.hh"
+#include "vector.hh"
+#include "string.hh"
+
+Vector::Vector(const Vector&n)
+ :dat(n.dat)
+ // this makes GCC 272 barf
+{
+ //dat = n.dat;
+}
+
+Vector::operator String() const
+{
+ int i=0;
+ String s("vector [");
+ for (; i < dim(); i++) {
+ s += String(dat[i], "%6f") + ' ';
+ }
+ s+="]";
+ return s;
+}
+
+
+void
+Vector::print() const
+{
+ mtor << *this<<'\n';
+}
+
+Vector
+Vector::operator-() const
+{
+ Vector v(*this); v*=-1; return v;
+}
+
+void
+Vector::set_unit(int j)
+{
+ fill(0.0);
+ dat[j] = 1.0;
+}
--- /dev/null
+#ifndef VECTOR_HH
+#define VECTOR_HH
+
+#include "glob.hh"
+#include "vray.hh"
+
+/// a row of numbers
+class Vector {
+ svec<Real> dat;
+public:
+ void OK() const { dat.OK();}
+ int dim() const { return dat.sz(); }
+ Vector() { }
+ Vector(const Vector&n);
+ Vector(int n) {
+ dat.set_size(n);
+ fill(0);
+ }
+ void insert(Real v, int i) {
+ dat.insert(v,i);
+ }
+ void del(int i) { dat.del(i); }
+ operator String() const;
+ void fill(Real r) {
+ for (int i=0; i < dim(); i++)
+ dat[i] =r;
+ }
+
+ void operator +=(Vector v) {
+ assert(v.dim() == dim());
+ for (int i=0; i < dim(); i++)
+ dat[i] += v.dat[i];
+ }
+
+ void operator /=(Real a) {
+ (*this) *= 1/a;
+ }
+
+ void operator *=(Real a) {
+ for (int i=0; i < dim(); i++)
+ dat[i] *= a;
+ }
+
+ void operator -=(Vector v) {
+ assert(v.dim() == dim());
+ for (int i=0; i < dim(); i++)
+ dat[i] -= v(i);
+ }
+
+ Real &operator()(int i) { return dat[i]; }
+ Real operator()(int i) const { return dat[i]; }
+ Real elem(int i) { return dat[i]; }
+ Real operator *(Vector v) const {
+ Real ip=0;
+ assert(v.dim() == dim());
+ for (int i=0; i < dim(); i++)
+ ip += dat[i] *v(i);
+ return ip;
+ }
+ Vector operator-() const;
+ Real norm() {
+ return sqrt(norm_sq() );
+ }
+ Real norm_sq() {
+ return ((*this) * (*this));
+ }
+ operator svec<Real> () { return dat; }
+ void print() const;
+ /// set to j-th element of unit-base
+ void set_unit(int j) ;
+};
+/**
+ a vector. Storage is handled in svec, Vector only does the mathematics.
+ */
+
+inline Vector
+operator+(Vector a, Vector const &b) {
+ a += b;
+ return a;
+}
+
+inline Vector
+operator-(Vector a, Vector const &b) {
+ a -= b;
+ return a;
+}
+
+inline Vector
+operator*(Vector v, Real a) {
+ v *= a;
+ return v;
+}
+
+inline Vector
+operator*( Real a,Vector v) {
+ v *= a;
+ return v;
+}
+
+inline Vector
+operator/(Vector v,Real a) {
+ v *= 1/a;
+ return v;
+}
+
+#endif
--- /dev/null
+#include "version.hh"
+
+static char *s = "LilyPond version " VERSIONSTR " compiled on " __DATE__ " at " __DATE__ "\n";
+
+char *
+get_version()
+{
+ return s;
+}
--- /dev/null
+#include "debug.hh"
+#include "voice.hh"
+
+void
+Voice_element::add(Request*r)
+{
+ if (r->tag == Request::NOTE ||r->tag == Request::REST) {
+ assert (!duration);
+ duration = r->duration();
+ }
+ reqs.bottom().add(r);
+}
+
+Voice::Voice()
+{
+ start = 0.0;
+}
+
+void
+Voice::add(Voice_element*v)
+{
+ elts.bottom().add(v);
+}
+
+Voice_element::Voice_element()
+{
+ voice = 0;
+ group = 0;
+ duration = 0.0;
+}
+
+void
+Voice::print() const
+{
+ mtor << "start: "<< start<<eol;
+ for (PCursor<Voice_element*> vec(elts); vec.ok(); vec++)
+ vec->print();
+}
+void
+Voice_element::print() const
+{
+ mtor << "voice_element { dur :"<< duration <<"\n";
+ for (PCursor<Request*> rc(reqs); rc.ok(); rc++) {
+ mtor << "reqtag: " << rc->tag<<eol;
+ }
+ mtor << "}\n";
+}
+
+Mtime
+Voice::last() const
+{
+ Mtime l =start;
+ for (PCursor<Voice_element*> vec(elts); vec.ok(); vec++)
+ l += vec->duration;
+ return l;
+}
--- /dev/null
+#ifndef VOICE_HH
+#define VOICE_HH
+
+#include "mtime.hh"
+#include "list.hh"
+#include "request.hh"
+
+/// class for horizontal stuff.
+struct Voice {
+ PointerList<Voice_element *> elts;
+ Mtime start;
+
+ /****************/
+ Mtime when(const Voice_element*)const;
+ Mtime last() const;
+ Voice();
+ void add(Voice_element*);
+ void print() const;
+};
+/**
+
+ Voice is a ordered row of Voice_elements. It is strictly horizontal:
+ you cannot have two rhythmic elements running parallel in a Voice
+
+ */
+
+struct Voicegroup {
+ /// don't know how to identify these.
+};
+
+///
+struct Voice_element {
+ Mtime duration;
+ const Voicegroup *group;
+ const Voice *voice;
+ PointerList<Request*> reqs;
+
+ List<const Item *> granted_items;
+ List<const Spanner *> granted_spanners;
+ void add(Request*);
+ Voice_element();
+
+ void print ()const;
+};
+/** Apart from being a container for the requests, Voice_element is
+ glue between related items and spanners, between requests and
+ (voice)groups
+ */
+#endif
--- /dev/null
+#ifndef VSMAT_HH
+#define VSMAT_HH
+#include "vray.hh"
+#include "real.hh"
+/// a matrix storage baseclass.
+class virtual_smat {
+
+
+public:
+ /// check invariants
+ virtual void OK() const=0;
+
+ /// height of matrix
+ virtual int rows() const = 0;
+
+ /// width of matrix
+ virtual int cols() const = 0;
+
+ /// set the size. contents lost
+ virtual void set_size(int i, int j) = 0;
+ /**
+ PRE
+ i >=0, j>=0
+ */
+
+ /// set the size to square dimen. contents lost
+ virtual void set_size(int i) = 0;
+ /**
+ PRE
+ i>=0
+ */
+ /// set the size to i
+ virtual void resize(int i, int j) = 0;
+ /**
+
+ keep contents. If enlarged contents unspecified
+
+ PRE
+ i>=0, j>=0
+
+ */
+
+ /// set the size to square dimen. contents kept
+ virtual void resize(int i) = 0;
+ /**
+ Keep contents. If enlarged contents are unspecified
+
+ PRE
+ i>=0
+ */
+
+ /// access an element
+ virtual Real& elem(int i,int j) = 0;
+ /**
+ access an element.
+
+ Generate an errormessage, if this happens
+ in the 0-part of a sparse matrix.
+ */
+
+ /// access a element, no modify
+ virtual const Real& elem(int i, int j) const = 0;
+
+#if 1
+ virtual svec<Real> row(int i) const = 0;
+ virtual svec<Real> column(int j) const = 0;
+#endif
+
+ /// add a row
+ virtual void insert_row(int k)=0;
+ /**
+ add a row to the matrix before row k. Contents
+ of added row are unspecified
+
+ 0 <= k <= rows()
+ */
+
+ /// delete a row
+ virtual void delete_row(int k)=0;
+ /**
+ delete a row from this matrix.
+
+ PRE
+ 0 <= k < rows();
+ */
+ virtual void delete_column(int k)=0;
+ virtual ~virtual_smat() { }
+ virtual virtual_smat *clone()=0;
+
+
+ /// is there a next?
+ virtual bool mult_ok(int i, int j) const=0;
+ /**
+ at end of matrix? when doing loop
+
+ for(i=0; i<h; i++)
+ for(j=0; j<w; j++)
+ ...
+
+ */
+ /// iterate
+ virtual void mult_next(int &i, int &j) const = 0;
+ /**
+ walk through matrix (regular multiply)
+ get next j for row i, or get next row i and reset j.
+ this will make sparse matrix implementation easy.
+
+ PRE
+ mult_ok(i,j)
+ */
+ virtual bool trans_ok(int i, int j) const=0;
+ /**
+ valid matrix entry. return false if at end of row
+ */
+ virtual void trans_next(int &i, int &j) const = 0;
+ /**
+ walk through matrix (transposed multiply).
+ Get next i (for column j)
+
+ PRE
+ ver_ok(i,j)
+ */
+
+ /// generate a "Full_storage" matrix
+ static virtual_smat *get_full(int n, int m);
+
+};
+
+/** base class for interface with matrix storageclasses. There are no
+ iterators for matrixclasses, since matrices are (like arrays)
+ explicitly int-indexed.
+
+ Iteration is provided by *_next, *_ok, which update and check both
+ index variables simultaneously.
+
+ TODO
+ determine type of product matrix.
+
+*/
+
+#endif
--- /dev/null
+#include "debug.hh"
+ ostream &warnout (cerr);
+ ostream *mlog(&cerr);
+
+
+
+void warning(String s)
+{
+ WARN << s;
+}
+
+
+void error(String s)
+{
+ cerr << "\n" << s << "\nexiting..\n";
+ exit(1);
+}
+