From: fred Date: Tue, 4 Mar 1997 19:42:17 +0000 (+0000) Subject: lilypond-0.0.39 X-Git-Tag: release/1.5.59~6272 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=f72d86b51b78626a1325186d705bb96e3cccd73b;p=lilypond.git lilypond-0.0.39 --- diff --git a/bin/genheader b/bin/genheader new file mode 100755 index 0000000000..7c36afe0ae --- /dev/null +++ b/bin/genheader @@ -0,0 +1,31 @@ +#!/usr/bin/perl -w + +die "arg needed\n" if (!($#ARGV+1)); +my $fn = $ARGV[0]; +my $hh_q = ($fn =~ /hh$/ ); +my $MAILADRESS=$ENV{MAILADRESS}; +my @pw=(getpwuid($<)); +my $username=$pw[6]; +my $what="implement "; +$what = "declare " if ($hh_q); +my $headstr ="/* + $fn -- $what + + source file of the LilyPond music typesetter + + (c) 1997 $username <$MAILADRESS> +*/\n"; + +my $startdef= $fn; +$startdef =~ s/[\.-]/_/g; +$startdef =~ tr/a-z/A-Z/; +my $terminatestr="\n"; +if ($hh_q) { + $headstr .= "\n\n#ifndef $startdef\n#define $startdef\n"; + $terminatestr .= "#endif // $startdef\n" +} + +print $headstr, $terminatestr; + + + diff --git a/lib/include/input-file.hh b/lib/include/input-file.hh new file mode 100644 index 0000000000..a01ea75076 --- /dev/null +++ b/lib/include/input-file.hh @@ -0,0 +1,28 @@ +/* + input-file.hh -- declare Input_file + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#ifndef INPUT_FILE_HH +#define INPUT_FILE_HH +#include +#include "proto.hh" +#include "fproto.hh" +#include "varray.hh" +#include "string.hh" + +struct Input_file { + istream* is; + char const* defined_ch_c_l_; + Source_file* sourcefile_l_; + int line; + String name; + + Input_file(String); + ~Input_file(); +}; + +#endif // INPUT_FILE_HH diff --git a/lib/include/source-file.hh b/lib/include/source-file.hh new file mode 100644 index 0000000000..7f7168eb7e --- /dev/null +++ b/lib/include/source-file.hh @@ -0,0 +1,40 @@ +// +// source-file.hh -- declare Source_file +// +// copyright 1997 Jan Nieuwenhuizen + +#ifndef SOURCE_FILE_HH +#define SOURCE_FILE_HH + +/// class for reading and mapping a file. +class Source_file +{ +public: + /** Ugh! filename gets changed! The path to the opened file may + change, since it might be searched in multiple directories. */ + Source_file( String& filename_str_r ); + virtual ~Source_file(); + + char const* ch_c_l(); + virtual String error_str( char const* pos_ch_c_l ); + istream* istream_l(); + bool in_b( char const* pos_ch_c_l ); + off_t length_off(); + virtual int line_i( char const* pos_ch_c_l ); + String name_str(); + String file_line_no_str( char const* ch_c_l ); + +private: + void close(); + void map(); + void open(); + void unmap(); + + istream* istream_p_; + int fildes_i_; + String name_str_; + off_t size_off_; + caddr_t data_caddr_; +}; + +#endif // SOURCE_FILE_HH // diff --git a/lib/input-file.cc b/lib/input-file.cc new file mode 100644 index 0000000000..a0f1018be6 --- /dev/null +++ b/lib/input-file.cc @@ -0,0 +1,47 @@ +/* + input-file.cc -- implement Input_file + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys Jan Nieuwenhuizen +*/ + +#include +#include +#include "proto.hh" +#include "plist.hh" +#include "input-file.hh" +#include "debug.hh" +#include "source-file.hh" +#include "binary-source-file.hh" +#include "source.hh" + +Input_file::Input_file(String s) +{ + name = s; + line = 1; + String pf(s); + if ( pf == "" ) { + is = &cin; + defined_ch_c_l_ = 0; + sourcefile_l_ = 0; + } + else { + Source_file* sourcefile_p = 0; + // ugh, very dirty, need to go away + if ( ( pf.right_str( 3 ).lower_str() == "mid" ) || ( pf.right_str( 4 ).lower_str() == "midi" ) ) + sourcefile_p = new Binary_source_file( pf ); + else + sourcefile_p = new Source_file( pf ); + source_l_g->add( sourcefile_p ); + sourcefile_l_ = sourcefile_p; + is = sourcefile_l_->istream_l(); + defined_ch_c_l_ = sourcefile_l_->ch_c_l(); + } + cout << "[" << pf << flush; +} + +Input_file::~Input_file() +{ + cout << "]" << flush; +} diff --git a/lib/source.cc b/lib/source.cc new file mode 100644 index 0000000000..8a8c528835 --- /dev/null +++ b/lib/source.cc @@ -0,0 +1,36 @@ +// +// source.cc +// + +#include + +#include "string.hh" +#include "proto.hh" +#include "plist.hh" + +#include "source-file.hh" +#include "source.hh" + +Source::Source() +{ +} + +Source::~Source() +{ +} + +void +Source::add( Source_file* sourcefile_p ) +{ + sourcefile_p_iplist_.bottom().add( sourcefile_p ); +} + +Source_file* +Source::sourcefile_l( char const* ch_c_l ) +{ + PCursor sourcefile_l_pcur( sourcefile_p_iplist_.top() ); + for ( ; sourcefile_l_pcur.ok(); sourcefile_l_pcur++ ) + if ( sourcefile_l_pcur->in_b( ch_c_l ) ) + return *sourcefile_l_pcur; + return 0; +} diff --git a/lily/bar-reg.cc b/lily/bar-reg.cc new file mode 100644 index 0000000000..b72eca8755 --- /dev/null +++ b/lily/bar-reg.cc @@ -0,0 +1,79 @@ +/* + bar-reg.cc -- implement Bar_register + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "bar-reg.hh" +#include "bar.hh" +#include "commandrequest.hh" +#include "score-column.hh" +#include "time-description.hh" + +Bar_register::Bar_register() +{ + post_move_processing(); +} + +bool +Bar_register::try_request(Request*r_l) +{ + Command_req* c_l = r_l->command(); + if (!c_l|| !c_l->bar()) + return false; + + assert(!bar_req_l_); + bar_req_l_ = c_l->bar(); + + return true; +} + +void +Bar_register::process_requests() +{ + if (bar_req_l_ ) { + bar_p_ = new Bar(bar_req_l_->type_str_); + } else if (!get_staff_info().time_c_l_->whole_in_measure_) { + bar_p_ = new Bar("|"); + } + + if (bar_p_){ + announce_element(Staff_elem_info(bar_p_, bar_req_l_) ); + } +} + +void +Bar_register::split_bar(Bar *& pre, Bar * no, Bar * &post) +{ + String s= no->type; + if (s == ":|:") { + pre = new Bar(":|"); + post = new Bar("|:"); + }else if (s=="|:") { + post = new Bar(s); + } else { + pre = new Bar(*no); + } +} + +void +Bar_register::pre_move_processing() +{ + if (bar_p_) { + Bar * post_p =0; + Bar * pre_p =0; + split_bar(pre_p, bar_p_, post_p); + + typeset_breakable_item(pre_p, bar_p_, post_p); + bar_p_ =0; + } +} + +void +Bar_register::post_move_processing() +{ + bar_req_l_ = 0; + bar_p_ =0; +} diff --git a/lily/bar.cc b/lily/bar.cc new file mode 100644 index 0000000000..32a7cd5fe6 --- /dev/null +++ b/lily/bar.cc @@ -0,0 +1,28 @@ +#include "bar.hh" +#include "string.hh" +#include "molecule.hh" +#include "paper-def.hh" +#include "lookup.hh" +#include "debug.hh" + + + +Bar::Bar( String t) +{ + type = t; +} + +void +Bar::do_print()const +{ + mtor << type; +} + +Molecule* +Bar::brew_molecule_p()const +{ + Symbol s = paper()->lookup_p_->bar(type); + Molecule*output = new Molecule(Atom(s)); + return output; +} + diff --git a/lily/beam.cc b/lily/beam.cc new file mode 100644 index 0000000000..64f3e3cf77 --- /dev/null +++ b/lily/beam.cc @@ -0,0 +1,295 @@ +#include "varray.hh" + +#include "dimen.hh" +#include "beam.hh" +#include "misc.hh" +#include "debug.hh" +#include "symbol.hh" +#include "molecule.hh" +#include "leastsquares.hh" +#include "pcol.hh" +#include "stem.hh" +#include "paper-def.hh" +#include "lookup.hh" +#include "grouping.hh" + + + +struct Stem_info { + Real x; + Real idealy; + Real miny; + int no_beams; + + + Stem_info(){} + Stem_info(const Stem*); +}; + +Stem_info::Stem_info(const Stem*s) +{ + x = s->hindex(); + int dir = s->dir; + idealy = max(dir*s->top, dir*s->bot); + miny = max(dir*s->minnote, dir*s-> maxnote); + assert(miny <= idealy); + +} + +/* *************** */ + +Offset +Beam::center()const +{ + assert(status >= POSTCALCED); + + Real w=(paper()->note_width() + width().length())/2.0; + return Offset(w, (left_pos + w* slope)*paper()->internote()); +} + + +Beam::Beam() +{ + slope = 0; + left_pos = 0.0; +} + +void +Beam::add(Stem*s) +{ + stems.bottom().add(s); + s->add_dependency(this); + s->print_flag = false; +} + +void +Beam::set_default_dir() +{ + int dirs[2]; + dirs[0]=0; dirs[1] =0; + for (iter_top(stems,i); i.ok(); i++) { + int d = i->get_default_dir(); + dirs[(d+1)/2] ++; + } + dir_i_ = (dirs[0] > dirs[1]) ? -1 : 1; + for (iter_top(stems,i); i.ok(); i++) { + i->dir = dir_i_; + } +} + +/* + should use minimum energy formulation (cf linespacing) + */ +void +Beam::solve_slope() +{ + Array sinfo; + for (iter_top(stems,i); i.ok(); i++) { + i->set_default_extents(); + Stem_info info(i); + sinfo.push(info); + } + Real leftx = sinfo[0].x; + Least_squares l; + for (int i=0; i < sinfo.size(); i++) { + sinfo[i].x -= leftx; + l.input.push(Offset(sinfo[i].x, sinfo[i].idealy)); + } + + l.minimise(slope, left_pos); + Real dy = 0.0; + for (int i=0; i < sinfo.size(); i++) { + Real y = sinfo[i].x * slope + left_pos; + Real my = sinfo[i].miny; + + if (my - y > dy) + dy = my -y; + } + left_pos += dy; + left_pos *= dir_i_; + slope *= dir_i_; + + // URG + Real sl = slope*paper()->internote(); + paper()->lookup_p_->beam(sl, 20 PT); + slope = sl /paper()->internote(); +} + +void +Beam::set_stemlens() +{ + iter_top(stems,s); + Real x0 = s->hindex(); + for (; s.ok() ; s++) { + Real x = s->hindex()-x0; + s->set_stemend(left_pos + slope * x); + } +} + + +void +Beam::do_post_processing() +{ + solve_slope(); + set_stemlens(); +} + +void +Beam::set_grouping(Rhythmic_grouping def, Rhythmic_grouping cur) +{ + def.OK(); + cur.OK(); + assert(cur.children.size() == stems.size()); + + cur.split(def); + + Array b; + { + iter_top(stems,s); + Array flags; + for (; s.ok(); s++) { + int f = intlog2(abs(s->flag))-2; + assert(f>0); + flags.push(f); + } + int fi =0; + b= cur.generate_beams(flags, fi); + b.insert(0,0); + b.push(0); + assert(stems.size() == b.size()/2); + } + + iter_top(stems,s); + for (int i=0; i < b.size() && s.ok(); i+=2, s++) { + s->beams_left = b[i]; + s->beams_right = b[i+1]; + } +} + + +// todo. +Spanner * +Beam::do_break_at( PCol *, PCol *) const +{ + Beam *beam_p= new Beam(*this); + + return beam_p; +} + +void +Beam::do_pre_processing() +{ + left = (*stems.top()) ->pcol_l_; + right = (*stems.bottom())->pcol_l_; + assert(stems.size()>1); + if (!dir_i_) + set_default_dir(); + +} + + +Interval +Beam::width() const +{ + Beam * me = (Beam*) this; // ugh + return Interval( (*me->stems.top()) ->hindex(), + (*me->stems.bottom()) ->hindex() ); +} + +/* + beams to go with one stem. + */ +Molecule +Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const +{ + assert( !next || next->hindex() > here->hindex() ); + assert( !prev || prev->hindex() < here->hindex() ); + Real dy=paper()->internote()*2; + Real stemdx = paper()->rule_thickness(); + Real sl = slope*paper()->internote(); + paper()->lookup_p_->beam(sl, 20 PT); + + Molecule leftbeams; + Molecule rightbeams; + + /* half beams extending to the left. */ + if (prev) { + int lhalfs= lhalfs = here->beams_left - prev->beams_right ; + int lwholebeams= here->beams_left beams_right ; + Real w = (here->hindex() - prev->hindex())/4; + Symbol dummy; + Atom a(dummy); + if (lhalfs) // generates warnings if not + a = paper()->lookup_p_->beam(sl, w); + a.translate(Offset (-w, -w * sl)); + for (int j = 0; j < lhalfs; j++) { + Atom b(a); + b.translate(Offset(0, -dir_i_ * dy * (lwholebeams+j))); + leftbeams.add( b ); + } + } + + if (next){ + int rhalfs = here->beams_right - next->beams_left; + int rwholebeams = here->beams_right beams_left; + + Real w = next->hindex() - here->hindex(); + Atom a = paper()->lookup_p_->beam(sl, w + stemdx); + + int j = 0; + for (; j < rwholebeams; j++) { + Atom b(a); + b.translate(Offset(0, -dir_i_ * dy * j)); + rightbeams.add( b ); + } + + w /= 4; + if (rhalfs) + a = paper()->lookup_p_->beam(sl, w); + + for (; j < rwholebeams + rhalfs; j++) { + Atom b(a); + b.translate(Offset(0, -dir_i_ * dy * j)); + rightbeams.add(b ); + } + + } + leftbeams.add(rightbeams); + return leftbeams; +} + + +Molecule* +Beam::brew_molecule_p() const return out; +{ + Real inter=paper()->internote(); + out = new Molecule; + Real x0 = stems.top()->hindex(); + + for (iter_top(stems,i); i.ok(); i++) { + PCursor p(i-1); + PCursor n(i+1); + Stem * prev = p.ok() ? p.ptr() : 0; + Stem * next = n.ok() ? n.ptr() : 0; + + Molecule sb = stem_beams(i, next, prev); + Real x = i->hindex()-x0; + sb.translate(Offset(x, (x * slope + left_pos)* inter)); + out->add(sb); + } + out->translate(Offset(x0 - left->hpos,0)); +} + +void +Beam::do_print()const +{ +#ifndef NPRINT + mtor << "slope " <breakable_b()) + retval.push(c); + assert(retval.top() == pscore_.cols.bottom().ptr()); + return retval; +} + +// construct an appropriate Spacing_problem and solve it. +Col_hpositions +Break_algorithm::solve_line(Line_of_cols curline) const +{ + Spacing_problem sp; + + sp.add_column(curline[0], true, 0.0); + for (int i=1; i< curline.size()-1; i++) + sp.add_column(curline[i]); + sp.add_column(curline.top(), true, linelength); + + // misschien moeven uit Spacing_problem? + for (iter_top(pscore_.suz,i); i.ok(); i++) { + sp.add_ideal(i); + } + Array the_sol=sp.solve(); + Col_hpositions col_hpos; + col_hpos.cols = curline; + col_hpos.energy = the_sol.pop(); + col_hpos.config = the_sol; + col_hpos.OK(); + return col_hpos; +} + +Break_algorithm::Break_algorithm(PScore&s) + :pscore_(s) +{ + linelength = s.paper_l_->linewidth; +} + +bool +Break_algorithm::feasible(Line_of_cols curline) const +{ + Real l =0; + for (int i=0; i < curline.size(); i++) + l +=curline[i]->width().length(); + return l < linelength; +} + +void +Break_algorithm::problem_OK() const +{ + if (!pscore_.cols.size()) + error("Score does not have any columns"); +#ifndef NDEBUG + iter_top(pscore_.cols,start); + PCursor end (pscore_.cols.bottom()); + + assert(start->breakable_b()); + assert(end->breakable_b()); +#endif +} diff --git a/lily/calcideal.cc b/lily/calcideal.cc new file mode 100644 index 0000000000..5ead08dd39 --- /dev/null +++ b/lily/calcideal.cc @@ -0,0 +1,53 @@ +#include "idealspacing.hh" +#include "score.hh" +#include "pscore.hh" +#include "paper-def.hh" +#include "score-column.hh" +#include "dimen.hh" + + +/** + this needs A LOT of rethinking. + + generate springs between columns. + + */ +void +Score::calc_idealspacing() +{ + iter_top(cols_,i); + + for (; i.ok(); i++) { + assert(i->used_b()); + PCursor j(i+1); + if (i->musical_b()) { + assert(j.ok()); + for (int n=0; n < i->durations.size(); n++) { + Moment d = i->durations[n]; + Real dist = paper_p_->duration_to_dist(d); + Real strength = i->durations[0]/i->durations[n]; + assert(strength <= 1.0); + + while (j->when() < d + i->when()) + j++; + Moment delta_desired = j->when() - (d+i->when()); + dist += paper_p_->duration_to_dist(delta_desired); + + pscore_p_->connect(i->pcol_l_, j->pcol_l_, dist, strength); + } + } else if (j.ok()) { + + /* attach i to the next column in use. This exists, since + the last col is breakable, and therefore in use + */ + + Moment d = j->when() - i->when(); + Real dist = (d) ? paper_p_->duration_to_dist(d) : 2 PT; // todo + + pscore_p_->connect(i->pcol_l_, j->pcol_l_, dist, (d) ? 1.0:1.0); + } + // !j.ok() might hold if we're at the last col. + } +} + + diff --git a/lily/clef-item.cc b/lily/clef-item.cc new file mode 100644 index 0000000000..528623eed6 --- /dev/null +++ b/lily/clef-item.cc @@ -0,0 +1,54 @@ +/* + clef-item.cc -- implement Clef_item + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "clef-item.hh" +#include "string.hh" +#include "molecule.hh" +#include "paper-def.hh" +#include "lookup.hh" +#include "clef-reg.hh" + + + +Clef_item::Clef_item() +{ + change = true; + read("violin"); +} + +void +Clef_item::read(String t) +{ + type = t; + if (type == "violin") + y_off = 2; + if (type == "alto") + y_off = 4; + if (type == "tenor") + y_off = 6; + if (type == "bass") + y_off = 6; +} +void +Clef_item::read(Clef_register const &k) +{ + read(k.clef_type_str_); +} + +Molecule* +Clef_item::brew_molecule_p()const +{ + String t = type; + if (change) + t += "_change"; + Symbol s = paper()->lookup_p_->clef(t); + Molecule*output = new Molecule(Atom(s)); + output->translate(Offset(0, paper()->internote() * y_off)); + return output; +} + diff --git a/lily/clef-reg.cc b/lily/clef-reg.cc new file mode 100644 index 0000000000..2d9dcc112b --- /dev/null +++ b/lily/clef-reg.cc @@ -0,0 +1,107 @@ +/* + clef.cc -- implement Clef_register + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys , + Mats Bengtsson +*/ + +#include "clef-reg.hh" +#include "clef-item.hh" +#include "debug.hh" +#include "commandrequest.hh" +#include "time-description.hh" +#include "staff-column.hh" + +Clef_register::Clef_register() +{ + clef_p_ = 0; + + /* ugly hack to prevent segfault (daddy_reg_l_ == 0 at construction) */ + clef_type_str_ = ""; +} + +bool +Clef_register::set_type(String s) +{ + clef_type_str_ = s; + if (clef_type_str_ == "violin") { + c0_position_i_= -2; + } else if (clef_type_str_ == "alto") { + c0_position_i_= 4; + } else if (clef_type_str_ == "tenor") { + c0_position_i_= 6; + } else if (clef_type_str_ == "bass") { + c0_position_i_= 10; + }else + return false; + *get_staff_info().c0_position_i_ = c0_position_i_; + + return true; +} + +void +Clef_register::read_req(Clef_change_req*c_l) +{ + if (!set_type(c_l->clef_str_)) + error("unknown clef type ", c_l->defined_ch_c_l_); +} + +bool +Clef_register::try_request(Request * r_l) +{ + Command_req* creq_l= r_l->command(); + if (!creq_l || !creq_l->clefchange()) + return false; + + clef_req_l_ = creq_l->clefchange(); + + // do it now! Others have to read c0_pos. + read_req(creq_l->clefchange()); + return true; +} + +void +Clef_register::process_requests() +{ + const Time_description *time_l = get_staff_info().time_c_l_; + if (!clef_req_l_ && (!time_l->whole_in_measure_|| !time_l->when_)) { + clef_p_ = new Clef_item; + clef_p_->change = false; + } else if (clef_req_l_) { + clef_p_ = new Clef_item; + clef_p_->change = true; + } + if (clef_p_) { + clef_p_->read(*this); + announce_element(Staff_elem_info(clef_p_, + clef_req_l_)); + } +} + +void +Clef_register::pre_move_processing() +{ + if (!clef_p_) + return; + if (clef_p_->change) { + Clef_item* post_p = new Clef_item(*clef_p_); + post_p->change = false; + typeset_breakable_item(new Clef_item(*clef_p_), + clef_p_, post_p); + } else { + typeset_breakable_item(0, 0, clef_p_); + } + clef_p_ = 0; +} + +void +Clef_register::post_move_processing() +{ + clef_req_l_ = 0; + /* not in ctor, since the reg might not be linked in.*/ + if (clef_type_str_ == "") { + set_type("violin"); + } +} diff --git a/lily/colhpos.cc b/lily/colhpos.cc new file mode 100644 index 0000000000..530e4d4483 --- /dev/null +++ b/lily/colhpos.cc @@ -0,0 +1,35 @@ +#include "colhpos.hh" +#include "real.hh" +#include "debug.hh" +#include "const.hh" +#include "vector.hh" + +Col_hpositions::Col_hpositions() +{ + energy = INFTY; +} + +void +Col_hpositions::add( PCol*c) +{ + cols.push(c); +} + +void +Col_hpositions::print() const +{ +#ifndef NPRINT + mtor << "energy : " << energy << '\n'; + mtor << "line of " << config.size() << " cols\n"; + Vector v(config); + mtor << v; +#endif +} + +void +Col_hpositions::OK()const +{ +#ifndef NDEBUG + assert(config.size() == cols.size()); +#endif +} diff --git a/lily/commandrequest.cc b/lily/commandrequest.cc new file mode 100644 index 0000000000..5cf0912417 --- /dev/null +++ b/lily/commandrequest.cc @@ -0,0 +1,149 @@ +/* + commandrequest.cc -- implement Nonmusical reqs + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "commandrequest.hh" +#include "debug.hh" +#include "musicalrequest.hh" + + +void +Cadenza_req::do_print()const +{ + mtor << on_b_; +} + +Cadenza_req::Cadenza_req(bool b) +{ + on_b_ =b; +} +/* *************** */ + + +int +Bar_req::compare(const Bar_req &c1)const +{ + return type_str_ == c1.type_str_; +} + +void +Bar_req::do_print() const +{ + mtor << type_str_; +} + +Bar_req::Bar_req(String s) +{ + type_str_ = s; +} + +Partial_measure_req::Partial_measure_req(Moment m) +{ + duration_ =m; +} +/* *************** */ +Meter_change_req::Meter_change_req() +{ + beats_i_ = 0; + one_beat_i_ =0; +} +void +Meter_change_req::set(int b,int o) +{ + beats_i_=b; + one_beat_i_=o; +} + +void +Timing_req::do_print()const{} + +void +Command_req::do_print()const{} +/* *************** */ +void +Barcheck_req::do_print() const{} + +/* *************** */ +void +Clef_change_req::do_print() const +{ + mtor << clef_str_ ; +} + +Clef_change_req::Clef_change_req(String s) +{ + clef_str_ = s; +} +/* *************** */ +void +Group_feature_req::do_print() const +{ + mtor << "stemdir " << stemdir_i_; +} + +Group_feature_req::Group_feature_req() +{ + stemdir_i_ = 0; +} + +void +Group_change_req::do_print()const +{ + mtor << "id : " << newgroup_str_; +} +/* *************** */ +void +Terminate_voice_req::do_print()const +{ +} + +/* *************** */ +void +Partial_measure_req::do_print() const +{ + mtor << duration_; +} + +void +Meter_change_req::do_print() const +{ + mtor << beats_i_ << "*" << one_beat_i_; +} + +/* *************** */ + +void +Measure_grouping_req::do_print() const +{ + for (int i=0; i < elt_length_arr_.size(); i++) { + mtor << beat_i_arr_[i] <<"*" << elt_length_arr_[i]<<" "; + } +} +/* *************** */ +void +Key_change_req::do_print() const +{ + for (int i=0; i < melodic_p_arr_.size(); i++) { + melodic_p_arr_[i]->print(); + } +} + +Key_change_req::Key_change_req() +{ +} +Key_change_req::Key_change_req(Key_change_req const&c) +{ + for (int i=0; i < c.melodic_p_arr_.size(); i++) { + melodic_p_arr_.push( c.melodic_p_arr_[i]->clone()->melodic() ); + } +} + +Key_change_req::~Key_change_req() +{ + for (int i=0; i < melodic_p_arr_.size(); i++) + delete melodic_p_arr_[i]; +} diff --git a/lily/complex-staff.cc b/lily/complex-staff.cc new file mode 100644 index 0000000000..bb13274449 --- /dev/null +++ b/lily/complex-staff.cc @@ -0,0 +1,37 @@ +#include "complex-staff.hh" +#include "complex-walker.hh" +#include "score.hh" +#include "pscore.hh" +#include "staffsym.hh" +#include "score-column.hh" + +const NO_LINES = 5; + +/** Aside from putting fields right, this generates the staff symbol. + */ +void +Complex_staff::set_output(PScore* pscore_l ) +{ + pstaff_l_ = new PStaff(pscore_l); + pscore_l_ = pscore_l; + pscore_l_->add(pstaff_l_); + + Staff_symbol *span_p = new Staff_symbol(NO_LINES); + + Score_column* col_last + =score_l_->find_col(score_l_->last(), false); + Score_column* col_first= + score_l_->find_col(0, false); + + span_p->set_extent(col_first->pcol_l_->postbreak_p_, + col_last->pcol_l_->prebreak_p_); + + pscore_l_->typeset_spanner(span_p, pstaff_l_); +} + + +Staff_walker * +Complex_staff::get_walker_p() +{ + return new Complex_walker(this); +} diff --git a/lily/debug.cc b/lily/debug.cc new file mode 100644 index 0000000000..01a35bd140 --- /dev/null +++ b/lily/debug.cc @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include "debug.hh" +#include "dstream.hh" +#include "vector.hh" + +Dstream *monitor=0; +ostream * nulldev =0; + +struct _Dinit { + _Dinit() { + nulldev = new ofstream("/dev/null"); + monitor = new Dstream(&cout,".dstreamrc"); + } + ~_Dinit() { + delete nulldev; + delete monitor; + } +} dinit; + + + +/* + want to do a stacktrace . + */ +void +mynewhandler() +{ + assert(false); +} + +void +float_handler(int) +{ + cerr << "Floating point exception .. \n"<< flush; + assert(false); +} + +void +debug_init() +{ +#ifndef NDEBUG + set_new_handler(&mynewhandler); +#endif + set_matrix_debug(*monitor); + signal(SIGFPE, float_handler); +} + +bool check_debug=false; + +void +set_debug(bool b) +{ + check_debug =b; +} + + diff --git a/lily/dimen.cc b/lily/dimen.cc new file mode 100644 index 0000000000..9489ae9a1e --- /dev/null +++ b/lily/dimen.cc @@ -0,0 +1,39 @@ +#include +#include "dimen.hh" +#include "debug.hh" +#include "string.hh" + +Real +parse_dimen(String dim) +{ + int i=dim.length_i()-1; + const char *s = dim; + while (i > 0 && (isspace(s[i]) || isalpha(s[i])) ){ + i--; + } + String unit(s + i+1); + return convert_dimen(dim.value_f(), unit); +} + + +Real +convert_dimen(Real quant, String unit) +{ + if (unit == "cm") + return quant * CM_TO_PT; + if (unit == "pt") + return quant; + if (unit == "mm") + return quant*CM_TO_PT/10; + if (unit == "in") + return quant * INCH_TO_PT; + error ("unknown length unit: `" + unit+"'"); +} + +String +print_dimen(Real r) +{ + String s(r); + s += "pt "; + return s; +} diff --git a/lily/directional-spanner.cc b/lily/directional-spanner.cc new file mode 100644 index 0000000000..7e2bb7c878 --- /dev/null +++ b/lily/directional-spanner.cc @@ -0,0 +1,6 @@ +#include "directional-spanner.hh" + +Directional_spanner::Directional_spanner() +{ + dir_i_ = 0; +} diff --git a/lily/grouping.cc b/lily/grouping.cc new file mode 100644 index 0000000000..bc665a19c0 --- /dev/null +++ b/lily/grouping.cc @@ -0,0 +1,350 @@ +/* + grouping.cc -- implement Rhythmic_grouping + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "debug.hh" +#include "grouping.hh" +#include "interval.hh" + +void +Rhythmic_grouping::init() +{ + interval_ = 0; + children.set_size(0); +} + +void +Rhythmic_grouping::OK()const +{ +#ifndef NDEBUG + assert(bool(children.size()) != bool(interval_)); + + for (int i= 0; i < children.size(); i++) { + children[i]->OK(); + if (i>0) + assert(children[i-1]->interval().right == + children[i]->interval().left); + } +#endif +} + +Moment +Rhythmic_grouping::length() const +{ + return interval().length(); +} + +MInterval +Rhythmic_grouping::interval()const +{ + if (interval_) + return *interval_; + else + return + MInterval(children[0]->interval().left, + children.top()->interval().right); +} + +void +Rhythmic_grouping::split(Rhythmic_grouping r) +{ + if (interval_) + return ; + + r.intersect(interval()); + split(r.intervals()); + + for (int i= 0; i < children.size(); i++) { + if (!children[i]->interval_) { + Rhythmic_grouping here(r); + children[i]->split(here); + } + } +} + + +Array +Rhythmic_grouping::intervals() +{ + Array r; + if (interval_ || children.size() == 1) { + MInterval i(interval()); + MInterval r1(i), r2(i); + r1.right = r2.left = i.center(); + r.push(r1); r.push(r2); + } else { + for (int i=0; i < children.size(); i++) + r.push(children[i]->interval()); + } + return r; +} + +void +Rhythmic_grouping::intersect(MInterval t) +{ + if (interval_) { + interval_->intersect(t); + return; + } + + for (int i=0; i < children.size(); i++) { + MInterval inter = intersection(t, children[i]->interval()); + if (inter.empty() || inter.length() <= Rational( 0 )) { + delete children[i]; + children[i] =0; + } else { + children[i]->intersect(t); + } + } + for (int i=0; i < children.size(); ) { + if (!children[i]) + children.del(i); + else + i++; + } + +} + +/** + Put our children in branches of #this#. + The min and max time intervals coincide with elements of #splitpoints# + + I really should be documenting what is happening here, but I find + that difficult, since I don't really understand what's going on here. + + */ +void +Rhythmic_grouping::split(Array splitpoints) +{ + //check on splitpoints.. + int j = 0, i = 0, starti = 0, startj = 0; + + Array ch; + while (1) { + if ( i >= children.size() || j >= splitpoints.size()) + break; + + assert( + children[starti]->interval().left== splitpoints[startj].left); + if (children[i]->interval().right < splitpoints[j].right) { + i ++; + } else if (children[i]->interval().right > splitpoints[j].right ) { + j ++; + } else { + + if (i == starti) { + ch.push(children[i]); + } else { + Rhythmic_grouping *newchild=new Rhythmic_grouping( + children.subvec(starti, i+1)); + + ch.push(newchild); + } + i ++; + j++; + starti = i; + startj = j; + + + } + } + if (ch.size() != 1) + children = ch; + } + + +Rhythmic_grouping::Rhythmic_grouping(MInterval t, int n) +{ + init(); + if (n == 1 || !n) { + interval_ = new MInterval(t); + return; + } + Moment dt = t.length()/Rational(n); + MInterval basic = MInterval(t.left, t.left+dt); + for (int i= 0; i < n; i++) + children.push(new Rhythmic_grouping( dt*Rational(i) + basic )); +} + + +Rhythmic_grouping::Rhythmic_grouping(Array r) + :children(r) +{ + interval_ =0; +} + +Rhythmic_grouping::~Rhythmic_grouping() +{ + junk(); +} + +void +Rhythmic_grouping::copy(Rhythmic_grouping const&s) +{ + interval_ = (s.interval_)? new MInterval(*s.interval_) : 0; + for (int i=0; i < s.children.size(); i++) + children.push(new Rhythmic_grouping(*s.children[i])); +} + +void +Rhythmic_grouping::operator=(Rhythmic_grouping const &s) +{ + junk(); + copy(s); +} + +Rhythmic_grouping::Rhythmic_grouping(Rhythmic_grouping const&s) +{ + init(); + copy(s); +} + +void +Rhythmic_grouping::junk() +{ + delete interval_; + for (int i=0; i < children.size(); i++) + delete children[i]; + init(); +} + +void +Rhythmic_grouping::print()const +{ +#ifndef NPRINT + mtor << "{ \n"; + if (interval_) + mtor<<" Interval "<< interval_->str(); + for (int i=0; i < children.size(); i++) { + children[i]->print(); + } + mtor << "}\n"; +#endif +} + +bool +Rhythmic_grouping::child_fit_query(Moment start) +{ + if (children.size()) + return ( children.top()->interval().right== start); + + return true; +} + +void +Rhythmic_grouping::add_child(Moment start, Moment len) +{ + Moment stop = start+len; + + assert(child_fit_query(start)); + children.push(new Rhythmic_grouping(MInterval(start, stop))); +} + +Rhythmic_grouping::Rhythmic_grouping() +{ + interval_ =0; +} + +int +min_elt(Array v) +{ + int i = 1000; // ugh + for (int j = 0 ; j < v.size(); j++) + i = i +Rhythmic_grouping::generate_beams(Array flags, int &flagidx) +{ + assert (!interval_) ; + + Array< Array > children_beams; + for (int i=0; i < children.size(); i++) { + Array child_beams; + if (children[i]->interval_) { + int f = flags[flagidx++]; + child_beams.push(f); + } else { + child_beams = children[i]-> + generate_beams(flags, flagidx); + } + children_beams.push(child_beams); + } + Array beams; + int lastm, m, nextm; + for (int i=0; i < children_beams.size(); i++) { + bool add_left = (i >0); + bool add_right = (i < children_beams.size() -1); + + if (!i) + m = min_elt(children_beams[i]); + if (add_right) + nextm = min_elt(children_beams[i+1]); + + if (children_beams[i].size() == 1) { + if (add_right) + beams.push(m); + if (add_left) + beams.push(m); + } else { + if (add_left) + beams.push(lastm translate(m); +} + +void +Rhythmic_grouping::extend(MInterval m)const +{ + assert(m.left >= interval().left); + while (m.right >interval().right ) { + Array a(children); + for (int i=0; i < a.size(); i++) { + a[i] =new Rhythmic_grouping(*children[i]); + a[i]->translate(children.top()->interval().right); + } + ((Rhythmic_grouping*)this)->children.concat(a); + } + assert(m.right <= interval().right); + OK(); +} + +Rhythmic_grouping +parse_grouping(Array beat_i_arr, Array elt_length_arr) +{ + Moment here =0; + assert(beat_i_arr.size() == elt_length_arr.size()); + + Array children; + for (int i=0; i < beat_i_arr.size(); i++) { + Moment last = here; + here += elt_length_arr[i] * Moment(beat_i_arr[i]); + children.push( + new Rhythmic_grouping(MInterval(last, here), + beat_i_arr[i] )); + } + return Rhythmic_grouping(children); +} + diff --git a/lily/headreg.cc b/lily/headreg.cc new file mode 100644 index 0000000000..dc5d72d572 --- /dev/null +++ b/lily/headreg.cc @@ -0,0 +1,76 @@ +/* + headreg.cc -- part of LilyPond + + (c) 1997 Han-Wen Nienhuys +*/ +#include "rest.hh" +#include "notehead.hh" +#include "headreg.hh" +#include "paper-def.hh" +#include "complex-walker.hh" +#include "musicalrequest.hh" + +Notehead_register::Notehead_register() +{ + note_p_ = 0; + set_feature(Features::dir(0)); + post_move_processing(); +} + +bool +Notehead_register::try_request(Request *req_l) +{ + if (req_l->note() || req_l->rest()) + note_req_l_=req_l->rhythmic(); + else + return false; + + return true; +} +void +Notehead_register::set_feature(Features d) +{ + if(d.direction_i_ || d.initialiser_b_) + dir_i_ = d.direction_i_; +} + +void +Notehead_register::process_requests() +{ + if (!note_req_l_) + return; + + + if (note_req_l_->note()) { + Notehead*n_p = new Notehead(8); // ugh + note_p_ = n_p; + n_p->set_rhythmic(note_req_l_->rhythmic()); + n_p->position = note_req_l_->note()->height() + + *get_staff_info().c0_position_i_; + } else { + note_p_ = new Rest ( note_req_l_->rhythmic()->balltype, + note_req_l_->rhythmic()->dots); + if (note_req_l_->rhythmic()->balltype <= 2) + note_p_->translate( + Offset(0, + 6 * paper()->internote())); + } + Staff_elem_info itinf(note_p_,note_req_l_); + announce_element(itinf); +} + +void +Notehead_register::pre_move_processing() +{ + if (note_p_) { + if (dir_i_ && note_p_->name() == Rest::static_name()) + note_p_->translate(Offset(0, 4*dir_i_ * paper()->internote())); + typeset_element(note_p_); + note_p_ = 0; + } +} +void +Notehead_register::post_move_processing() +{ + note_req_l_ = 0; +} diff --git a/lily/idealspacing.cc b/lily/idealspacing.cc new file mode 100644 index 0000000000..3ceaff1e6d --- /dev/null +++ b/lily/idealspacing.cc @@ -0,0 +1,31 @@ +#include "idealspacing.hh" +#include "pcol.hh" +#include "pscore.hh" +#include "pstaff.hh" +#include "debug.hh" + +void +Idealspacing::print() const +{ +#ifndef NPRINT + mtor << "idealspacing {" ; + mtor << "distance "<rank() << " right " << right->rank() << "}\n"; +#endif +} + +Idealspacing::Idealspacing(const PCol * l,const PCol * r) +{ + space = 0.0; + hooke = 0.0; + left = l; + right = r; +} + +void +Idealspacing::OK() const +{ +#ifndef NDEBUG + assert(hooke >= 0 && left && right); +#endif +} diff --git a/lily/identifier.cc b/lily/identifier.cc new file mode 100644 index 0000000000..59f1ff5d83 --- /dev/null +++ b/lily/identifier.cc @@ -0,0 +1,56 @@ +/* + identifier.cc -- implement identifier and derived classes + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include + +#include "identifier.hh" +#include "lexer.hh" +#include "debug.hh" + +void +Identifier::error(String expect) +{ + String e("Wrong identifier type: "); + e += String(classname()) + "(expected " + expect + ")"; + ::error(e); +} + +void +Identifier::print()const +{ + mtor << "identifier \'" << name << "\'="; + do_print(); +} + +/* ugh. */ +#define DEFAULT_PRINT(Class, Content_type, accessor) \ +void \ +Class::do_print() const { \ + ((Class*)this)->accessor(false)->print(); \ +} \ +class Class + +DEFAULT_PRINT(Script_id, Script_def, script); +DEFAULT_PRINT(Lookup_id, Lookup, lookup); +DEFAULT_PRINT(Symtables_id, Symtables, symtables); +DEFAULT_PRINT(Staff_id, Input_staff, staff); +DEFAULT_PRINT(M_chord_id, Music_general_chord, mchord); +DEFAULT_PRINT(M_voice_id, Music_voice, mvoice); + +void +Real_id::do_print() const +{ + Identifier::print(); + mtor << *((Real_id*)this)->real(false)<< "\n"; +} + +void +Notetab_id::do_print() const +{ + mtor << "unknown" << "\n"; +} diff --git a/lily/include/bar-reg.hh b/lily/include/bar-reg.hh new file mode 100644 index 0000000000..c73e5d1f4f --- /dev/null +++ b/lily/include/bar-reg.hh @@ -0,0 +1,31 @@ +/* + bar-reg.hh -- declare Bar_register + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef BARREG_HH +#define BARREG_HH +#include "register.hh" + +/** + generate bars. Either user ("|:"), or default (new measure) + */ +class Bar_register : public Request_register { + void split_bar(Bar *& pre, Bar * no, Bar * &post); +public: + Bar_req * bar_req_l_; + Bar * bar_p_; + + virtual bool try_request(Request *req_l); + virtual void process_requests(); + virtual void pre_move_processing(); + virtual void post_move_processing(); + Bar_register(); + NAME_MEMBERS(Bar_register); +}; + +#endif // BARREG_HH diff --git a/lily/include/bar.hh b/lily/include/bar.hh new file mode 100644 index 0000000000..3727358d96 --- /dev/null +++ b/lily/include/bar.hh @@ -0,0 +1,20 @@ +/* + bar.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef BAR_HH +#define BAR_HH +#include "item.hh" + +struct Bar: Item { + String type; + + Bar(String type); +NAME_MEMBERS(Bar); + void do_print() const; + Molecule*brew_molecule_p()const; +}; +#endif // BAR_HH + diff --git a/lily/include/beam.hh b/lily/include/beam.hh new file mode 100644 index 0000000000..8eb2f148b5 --- /dev/null +++ b/lily/include/beam.hh @@ -0,0 +1,51 @@ +/* + beam.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef BEAM_HH +#define BEAM_HH +#include "proto.hh" +#include "directional-spanner.hh" +#include "plist.hh" + +/** a beam connects multiple stems Beam adjusts the stems its owns to + make sure that they reach the beam and that point in the correct + direction */ +struct Beam: public Directional_spanner { + PointerList stems; + /// the slope of the beam in posns / point (dimension) + Real slope; + + /// position of leftmost end of beam + Real left_pos; + + + /* *************** */ +NAME_MEMBERS(Beam); + + virtual Interval width()const; + Offset center() const; + Spanner *do_break_at(PCol *, PCol *) const; + Beam(); + void add(Stem*); + + + void set_default_dir(); + void do_pre_processing(); + void do_post_processing(); + + void do_print() const; + void set_grouping(Rhythmic_grouping def, Rhythmic_grouping current); + void set_stemlens(); + ~Beam(); + +private: + Molecule stem_beams(Stem *here, Stem *next, Stem *prev)const; + void solve_slope(); + Molecule*brew_molecule_p()const; +}; + +#endif // BEAM_HH + diff --git a/lily/include/class-name.hh b/lily/include/class-name.hh new file mode 100644 index 0000000000..26da52dc0e --- /dev/null +++ b/lily/include/class-name.hh @@ -0,0 +1,19 @@ +/* + class-name.hh -- declare + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef CLASS_NAME_HH +#define CLASS_NAME_HH + +/// a macro to declare the classes name as a static and virtual function. +#define NAME_MEMBERS(c) \ +static const char *static_name(){ return #c; }\ +virtual const char *name() const{ return c::static_name(); } \ +int a_stupid_nonexistent_function_to_allow_the_semicolon_come_out() + +#endif // CLASS-NAME_HH diff --git a/lily/include/clef-item.hh b/lily/include/clef-item.hh new file mode 100644 index 0000000000..341204f8ea --- /dev/null +++ b/lily/include/clef-item.hh @@ -0,0 +1,31 @@ + +/* + clef-item.hh -- declare Clef_item + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef CLEFITEM_HH +#define CLEFITEM_HH +#include "item.hh" + + +struct Clef_item : Item { + String type; + int y_off; + + /// is this a change clef (smaller size)? + bool change; + + + /* *************** */ +NAME_MEMBERS(Clef_item); + Clef_item(); + void read(Clef_register const&); + void read(String); + Molecule* brew_molecule_p()const; +}; + +#endif // CLEFITEM_HH + + diff --git a/lily/include/clef-reg.hh b/lily/include/clef-reg.hh new file mode 100644 index 0000000000..cc3a8a90e9 --- /dev/null +++ b/lily/include/clef-reg.hh @@ -0,0 +1,34 @@ +/* + clef.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef CLEF_HH +#define CLEF_HH + +#include "scalar.hh" +#include "varray.hh" +#include "register.hh" + +/// where is c-0 in the staff? +class Clef_register : public Request_register { + Clef_item *clef_p_; + Clef_change_req * clef_req_l_; + +public: + int c0_position_i_; + String clef_type_str_; + + /* ************** */ + virtual void process_requests(); + virtual void pre_move_processing(); + virtual void post_move_processing(); + virtual bool try_request(Request*); + Clef_register(); + NAME_MEMBERS(Clef_register); + void read_req(Clef_change_req*); + bool set_type(String); +}; +#endif // CLEF_HH + diff --git a/lily/include/complex-staff.hh b/lily/include/complex-staff.hh new file mode 100644 index 0000000000..0a37e3a5f7 --- /dev/null +++ b/lily/include/complex-staff.hh @@ -0,0 +1,25 @@ +/* + complex-staff.hh -- declare Complex_staff + + (c) 1996,1997 Han-Wen Nienhuys +*/ + +#ifndef COMPLEXSTAF_HH +#define COMPLEXSTAF_HH + + +#include "key.hh" +#include "staff.hh" +#include "staff-walker.hh" + +/// +struct Complex_staff : Staff { + + /* *************** */ + + virtual void set_output(PScore *); + virtual Staff_walker *get_walker_p(); +}; + +#endif // COMPLEXSTAF_HH + diff --git a/lily/include/complex-walker.hh b/lily/include/complex-walker.hh new file mode 100644 index 0000000000..861cee77f8 --- /dev/null +++ b/lily/include/complex-walker.hh @@ -0,0 +1,47 @@ +/* + complex-walker.hh -- declare Complex_walker + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef COMPLEXWALKER_HH +#define COMPLEXWALKER_HH + +#include "proto.hh" +#include "staff-walker.hh" +#include "staff-elem-info.hh" + +/** + A staff walker which uses registers to decide what to print + */ +class Complex_walker: public Staff_walker { + bool try_command_request(Command_req *req_l); + void do_announces(); + void try_request(Request*req); + + + +public: + int c0_position_i_; + Walker_registers *walk_regs_p_; + + /* *************** */ + + void regs_process_requests(); + void typeset_element(Staff_elem *elem_p); + void announce_element(Staff_elem_info); + virtual void process_requests(); + virtual void do_post_move(); + virtual void do_pre_move(); + + Complex_walker(Complex_staff*); + ~Complex_walker(); + + Complex_staff *staff(); +private: +}; + + +#endif // COMPLEXWALKER_HH + + diff --git a/lily/include/directional-spanner.hh b/lily/include/directional-spanner.hh new file mode 100644 index 0000000000..9399b71c4d --- /dev/null +++ b/lily/include/directional-spanner.hh @@ -0,0 +1,26 @@ +/* + directional-spanner.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef DIRECTIONALSPANNER_HH +#define DIRECTIONALSPANNER_HH + +#include "spanner.hh" + +/// a spanner which can be pointing "up" or "down" +struct Directional_spanner : Spanner{ + + /// -1 below heads, +1 above heads. + int dir_i_; + + /// offset of "center" relative to left-column/0-pos of staff + virtual Offset center() const=0; + virtual void set_default_dir()=0; + Directional_spanner(); + +}; + +#endif // DIRECTIONALSPANNER_HH + diff --git a/lily/include/grouping.hh b/lily/include/grouping.hh new file mode 100644 index 0000000000..06b4421b0a --- /dev/null +++ b/lily/include/grouping.hh @@ -0,0 +1,62 @@ +/* + grouping.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef GROUPING_HH +#define GROUPING_HH + +#include "moment.hh" +#include "interval.hh" +#include "varray.hh" + +typedef Interval_t MInterval; + +/** data structure which represents rhythmic units this is a tree. It groupes notes according to rules + */ +struct Rhythmic_grouping { + Array children; + MInterval *interval_; + + /* *************** */ + + Array intervals(); + MInterval interval()const; + Moment length() const; + void intersect(MInterval); + + void operator=(Rhythmic_grouping const&); + Rhythmic_grouping(Rhythmic_grouping const&); + Rhythmic_grouping(MInterval, int n=1); + Rhythmic_grouping(); + Rhythmic_grouping(Array); + ~Rhythmic_grouping(); + + void add_child(Moment start, Moment len); + bool child_fit_query(Moment start); + void split(Rhythmic_grouping r); + void split(Array); + void split(int n); + + void print() const; + void OK() const; + + Array generate_beams(Array, int&); + + /** multiply self to span #i#. + In implementation, this isn't really const, but conceptually it is. + */ + void extend(MInterval i) const; + void translate(Moment); +private: + void init(); + void junk(); + void copy(Rhythmic_grouping const&); +}; + + +Rhythmic_grouping parse_grouping(Array beat_i_arr, Array elt_length_arr); + + +#endif diff --git a/lily/include/headreg.hh b/lily/include/headreg.hh new file mode 100644 index 0000000000..eaa2d6f9d7 --- /dev/null +++ b/lily/include/headreg.hh @@ -0,0 +1,28 @@ +/* + headreg.hh -- part of LilyPond + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef HEADREG_HH +#define HEADREG_HH +#include "register.hh" + +struct Notehead_register : Request_register { + Item* note_p_; + Rhythmic_req * note_req_l_; + int dir_i_; + + /* *************** */ + Notehead_register(); + virtual bool try_request(Request *req_l) ; + virtual void process_requests(); + virtual void pre_move_processing(); + virtual void post_move_processing(); + void set_feature(Features); + NAME_MEMBERS(Notehead_register); +}; + + +#endif // HEADREG_HH diff --git a/lily/include/identifier.hh b/lily/include/identifier.hh new file mode 100644 index 0000000000..1aa7f7d0c4 --- /dev/null +++ b/lily/include/identifier.hh @@ -0,0 +1,42 @@ + +/* + identifier.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef IDENTIFIER_HH +#define IDENTIFIER_HH +#include "identparent.hh" +#include "symtable.hh" +#include "input-staff.hh" +#include "input-music.hh" +#include "notename.hh" +#include "lookup.hh" +#include "script-def.hh" + +#define make_id_class(Idclass, Class, accessor) \ +struct Idclass : Identifier {\ + virtual const char *classname() { return #Class; }\ + Idclass(String s, Class*st):Identifier(s) { data = st; }\ + virtual Class* accessor(bool copy) {\ + if (copy)\ + return new Class(* (Class*) data);\ + else\ + return (Class*) data;\ + }\ + ~Idclass() { delete accessor(false); }\ + virtual void do_print()const; \ +}\ + +make_id_class(Real_id, Real, real); +make_id_class(Script_id, Script_def, script); +make_id_class(Lookup_id, Lookup, lookup); +make_id_class(Symtables_id, Symtables, symtables); +make_id_class(Staff_id, Input_staff, staff); +make_id_class(M_chord_id, Music_general_chord, mchord); +make_id_class(M_voice_id, Music_voice, mvoice); +make_id_class(Notetab_id, Notename_tab, notename_tab); + +#endif // IDENTIFIER_HH + diff --git a/lily/include/identparent.hh b/lily/include/identparent.hh new file mode 100644 index 0000000000..3e6d566ee7 --- /dev/null +++ b/lily/include/identparent.hh @@ -0,0 +1,45 @@ +/* + identparent.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef IDENTPARENT_HH +#define IDENTPARENT_HH + +#include "proto.hh" +#include "string.hh" + +/* boolean argument to accesor is copy_b..*/ +#define IDACCESSOR( Input_staff, staff)\ + virtual Input_staff * staff(bool) { error(#Input_staff); return 0; } + +struct Identifier { + void *data; + String name; + + Identifier(String n) : name(n) { } + virtual ~Identifier() {} + + void print()const; + virtual const char*classname() { return "new Identifier"; } + void error(String); + IDACCESSOR(Input_staff, staff) + IDACCESSOR(Input_music, music) + IDACCESSOR(Music_voice, mvoice) + IDACCESSOR(Script_def, script) + IDACCESSOR(Symtables, symtables) + IDACCESSOR(Music_general_chord, mchord) + IDACCESSOR(Lookup,lookup) + IDACCESSOR(Real,real) + IDACCESSOR(Notename_tab, notename_tab) +protected: + virtual void do_print()const=0; +private: + Identifier(Identifier const&){} + +}; +#endif // IDENTPARENT_HH + + + diff --git a/lily/include/input-music.hh b/lily/include/input-music.hh new file mode 100644 index 0000000000..1d7a8caa66 --- /dev/null +++ b/lily/include/input-music.hh @@ -0,0 +1,140 @@ +/* + input-music.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef INPUTMUSIC_HH +#define INPUTMUSIC_HH + +#include "plist.hh" +#include "proto.hh" +#include "voice.hh" +#include "moment.hh" + +struct Voice_list : public PointerList { + void translate_time(Moment dt); +}; + +/** + + A set voices. + Input_music is anything that can simply be regarded as/converted to + a set of voices "cooperating" or independant. It has some basic + characteristics that real music has too: + + - it is rhythmic (it has a length, and can be translated horizontally) + - a pitch (it can be transposed) + + */ +struct Input_music { + virtual Voice_list convert()const=0; + void check_plet(Voice_element* velt_l); + virtual Moment length()const=0; + virtual void translate_time(Moment dt)=0; + virtual ~Input_music(){} + virtual void print() const =0; + virtual void set_default_group(String)=0; + virtual bool find_plet_start_bo(char c, Moment& moment_r) = 0; + virtual void set_plet_backwards(Moment& now_moment_r, Moment until_moment, int num_i, int den_i) = 0; + // virtual void transpose(...) const =0; + + + virtual Input_music *clone() const = 0; + virtual Simple_music *simple() { return 0; } +}; + +/// Simple music consists of one voice +struct Simple_music : Input_music { + Voice voice_; + + /* *** */ + virtual Simple_music*simple() { return this; } + void add(Voice_element*); + virtual void set_default_group(String g) { voice_.set_default_group(g); } + virtual Moment length()const; + virtual Voice_list convert()const; + virtual void translate_time(Moment dt); + virtual void print() const; + virtual bool find_plet_start_bo(char c, Moment& moment_r); + virtual void set_plet_backwards(Moment& now_moment_r, Moment until_moment, int num_i, int den_i); + virtual Input_music *clone() const { + return new Simple_music(*this); + } + +}; + +/// Complex_music consists of multiple voices +struct Complex_music : Input_music { + IPointerList elts; + /* *************** */ + virtual void set_default_group(String g); + void add(Input_music*); + Complex_music(); + Complex_music(Complex_music const &); + virtual void print() const ; + void concatenate(Complex_music*); + virtual bool find_plet_start_bo(char c, Moment& moment_r); + virtual void set_plet_backwards(Moment& now_moment_r, Moment until_moment, int num_i, int den_i); + +}; + + +/** + A voice like list of music. + + different music forms which start after each other ( concatenated, + stacked "horizontally ) + + */ + +struct Music_voice : Complex_music { + + + /* *************** */ + Moment length()const; + virtual void translate_time(Moment dt); + virtual Voice_list convert()const; + void add_elt(Voice_element*); + virtual Input_music *clone() const { + return new Music_voice(*this); + } + virtual void print() const ; +}; + +/** + Multiple musicstuff stacked on top of each other + chord like : + + - different music forms which start at the same time ( stacked "vertically" ) + + */ +struct Music_general_chord : Complex_music { + + + /* *************** */ + + virtual Moment length()const; + virtual Voice_list convert()const; + virtual void translate_time(Moment dt); + void add_elt(Voice_element*); + virtual Input_music *clone() const { + return new Music_general_chord(*this); + } + + virtual void print() const ; +}; + +struct Multi_voice_chord : Music_general_chord { + void set_default_group(String); + virtual Input_music *clone() const { + return new Multi_voice_chord(*this); + } +}; +struct Voice_group_chord : Music_general_chord { + + virtual Input_music *clone() const { + return new Voice_group_chord(*this); + } +}; +#endif // INPUTMUSIC_HH diff --git a/lily/include/input-score.hh b/lily/include/input-score.hh new file mode 100644 index 0000000000..4286f4b60b --- /dev/null +++ b/lily/include/input-score.hh @@ -0,0 +1,46 @@ +/* + input-score.hh -- declare + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef INPUTSCORE_HH +#define INPUTSCORE_HH + +#include "varray.hh" +#include "proto.hh" +#include "plist.hh" +#include "string.hh" + + +/// the total music def of one movement +struct Input_score { + /// defined where? + const char* defined_ch_c_l_; + int errorlevel_i_; + + /// paper_, staffs_ and commands_ form the problem definition. + Paper_def *paper_p_; + Midi_def* midi_p_; + IPointerList staffs_; + + Input_music * score_wide_music_p_; + + /* *************************************************************** */ + Input_score(); + Input_score(Input_score const&); + + void add(Input_staff*); + ~Input_score(); + /// construction + void set(Paper_def*); + void set(Midi_def* midi_p); + void print() const; + Score*parse(); + void set(Input_music*); +}; + +#endif diff --git a/lily/include/input-staff.hh b/lily/include/input-staff.hh new file mode 100644 index 0000000000..3b874a1b39 --- /dev/null +++ b/lily/include/input-staff.hh @@ -0,0 +1,35 @@ +/* + input-staff.hh -- declare Input_staff + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef INPUTSTAFF_HH +#define INPUTSTAFF_HH + +#include "string.hh" +#include "plist.hh" +#include "varray.hh" +#include "proto.hh" + +struct Input_staff { + + const char * defined_ch_c_l_; + String type; + + IPointerList music_; + Input_music * score_wide_music_p_; + + /* *************** */ + ~Input_staff(); + void add(Input_music*m); + Input_staff(Input_staff const&); + Input_staff(String); + void set_score_wide(Input_music*m); + Staff* parse(Score*, Input_music *score_wide); + void print() const; +}; + + +#endif // INPUTSTAFF_HH + diff --git a/lily/include/item.hh b/lily/include/item.hh new file mode 100644 index 0000000000..d1fc8c8bfa --- /dev/null +++ b/lily/include/item.hh @@ -0,0 +1,32 @@ +#ifndef ITEM_HH +#define ITEM_HH + +#include "glob.hh" +#include "boxes.hh" +#include "string.hh" +#include "staff-elem.hh" + +/** + a horizontally fixed size element of the score + + Item is the datastructure for printables whose width is known + before the spacing is calculated + + NB. This doesn't mean an Item has to initialize the output field before + spacing calculation. + +*/ +struct Item : Staff_elem { + /// indirection to the column it is in + PCol * pcol_l_; + + /* *************** */ + virtual Item *item() { return this; } + Item(); + void do_print()const; + + NAME_MEMBERS(Item); +}; + + +#endif diff --git a/lily/include/key-item.hh b/lily/include/key-item.hh new file mode 100644 index 0000000000..e56af8e682 --- /dev/null +++ b/lily/include/key-item.hh @@ -0,0 +1,31 @@ +/* + key-item.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef KEYITEM_HH +#define KEYITEM_HH + +#include "item.hh" +#include "varray.hh" + + +/// An item which places accidentals at the start of the line +struct Key_item : Item { + Array pitch; + Array acc; + int c_position; + + + /* *************** */ +NAME_MEMBERS(Key_item); + Key_item(int cposition); + void add(int pitch, int acc); + void read(const Key_register&); + void set_c_position(int); + void preprocess(); + Molecule* brew_molecule_p()const; +}; + +#endif // KEYITEM_HH diff --git a/lily/include/key-reg.hh b/lily/include/key-reg.hh new file mode 100644 index 0000000000..d8a96d066e --- /dev/null +++ b/lily/include/key-reg.hh @@ -0,0 +1,35 @@ +/* + key-reg.hh -- declare Key_register + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef KEYREG_HH +#define KEYREG_HH + +#include "register.hh" +#include "key.hh" + +struct Key_register : Request_register { + Key key_; + Key_change_req * keyreq_l_; + Key_item * kit_p_; + Array accidental_idx_arr_; + bool default_key_b_; + + virtual bool try_request(Request *req_l); + virtual void process_requests(); + virtual void pre_move_processing(); + virtual void post_move_processing(); + virtual void acknowledge_element(Staff_elem_info); + Key_register(); + NAME_MEMBERS(Key_register); +private: + + void read_req(Key_change_req * r); +}; + +#endif // KEYREG_HH diff --git a/lily/include/lexer.hh b/lily/include/lexer.hh new file mode 100644 index 0000000000..6a9d21a98e --- /dev/null +++ b/lily/include/lexer.hh @@ -0,0 +1,51 @@ +/* + lexer.hh -- declare My_flex_lexer + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#ifndef LEXER_HH +#define LEXER_HH +#include +#include "proto.hh" +#include "fproto.hh" +#include "varray.hh" +#include "string.hh" + +int yylex(); +void yyerror(const char *s); +bool busy_parsing(); +void kill_lexer(); +void set_lexer(); + +/// lexer with provisions for include files. +struct My_flex_lexer : yyFlexLexer { + + Array include_stack; + Assoc *the_id_tab; + Keyword_table * keytable; + Notename_tab * defaulttab; + int errorlevel_i_; + /* *************** */ + int ret_notename(int *p, String text, int octave_mod); + char const* here_ch_c_l(); + void set(Notename_tab *n); + int lookup_keyword(String); + void lookup_notename(int &large, int &small, String s); + void LexerError(const char *); + String spot() const; + Identifier*lookup_identifier(String s); + My_flex_lexer(); + void add_identifier(Identifier*i); + ~My_flex_lexer(); + void new_input(String s); + bool close_input(); + int yylex(); + void print_declarations() const; +}; + +extern My_flex_lexer *lexer; + +#endif diff --git a/lily/include/local-key-item.hh b/lily/include/local-key-item.hh new file mode 100644 index 0000000000..96bad9999e --- /dev/null +++ b/lily/include/local-key-item.hh @@ -0,0 +1,33 @@ +/* + local-key-item.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef LOCALKEYITEM_HH +#define LOCALKEYITEM_HH +#include "item.hh" +#include "varray.hh" + +struct Local_acc { + int name , acc, octave; + static int compare(Local_acc&, Local_acc&); +}; + +struct Local_key_item : Item { +NAME_MEMBERS(Local_key_item); + Array accs; + Array support_items_; + int c0_position; + + /* *************** */ + + Local_key_item(int c0position); + void add(Item*); + void add(int oct, int pitch, int acc); + void add(Melodic_req*); + void do_pre_processing(); + Molecule* brew_molecule_p()const; +}; +#endif // LOCALKEYITEM_HH + diff --git a/lily/include/local-key-reg.hh b/lily/include/local-key-reg.hh new file mode 100644 index 0000000000..d0a2867a87 --- /dev/null +++ b/lily/include/local-key-reg.hh @@ -0,0 +1,25 @@ +/* + local-key-reg.hh -- declare Local_key_register + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef LOCALKEYREG_HH +#define LOCALKEYREG_HH +#include "register.hh" +#include "key.hh" + +struct Local_key_register : Request_register { + Local_key local_key_; + Local_key_item* key_item_p_; + const Key *key_c_l_; + /* *************** */ + virtual void process_requests(); + virtual void acknowledge_element(Staff_elem_info); + virtual void pre_move_processing(); + Local_key_register(); + NAME_MEMBERS(Local_key_register); +}; + +#endif // LOCALKEYREG_HH diff --git a/lily/include/lookup.hh b/lily/include/lookup.hh new file mode 100644 index 0000000000..524cdf1958 --- /dev/null +++ b/lily/include/lookup.hh @@ -0,0 +1,57 @@ +/* + lilypond, (c) 1996,97 Han-Wen Nienhuys +*/ +#ifndef LOOKUPSYMS_HH +#define LOOKUPSYMS_HH + +#include "symbol.hh" +#include "fproto.hh" +#include "scalar.hh" + +/// intuitive interface to symbol table +struct Lookup { + Symtables *symtables_; + String texsetting; + /* *************** */ + void add(String, Symtable*); + void print()const; + Real internote(); + + Symbol linestaff(int n, Real w); + Symbol fill(Box b); + Symbol beam_element(int,int,Real=0); + + /// round slope to closest TeXslope + Symbol beam(Real&,Real); + + /** + pos == 3 : 3 lines above staff (extending below note) + + pos == -3: below staff + */ + Symbol streepjes(int pos); + + Symbol meter(Array); + Symbol stem(Real y1_pos, Real y2_pos); + Symbol rule_symbol(Real height, Real width); + Symbol accidental(int); + Symbol ball(int); + Symbol flag(int); + Symbol rest(int); + Symbol clef(String); + Symbol bar(String); + Symbol dots(int); + Symbol slur(int dy, Real &dx, int dir); + Symbol half_slur(int dy, Real &dx, int dir, int xpart); + Symbol half_slur_middlepart(Real &dx, int dir); + Symbol big_slur(int dy, Real &dx, int dir); + Symbol text(String style, String text, int align = 1); + Symbol script(String idx); + Symbol hairpin(Real & width, bool decresc); + + Lookup(); + Lookup(Lookup const &); + ~Lookup(); +}; + +#endif diff --git a/lily/include/lyric-walker.hh b/lily/include/lyric-walker.hh new file mode 100644 index 0000000000..1a80523883 --- /dev/null +++ b/lily/include/lyric-walker.hh @@ -0,0 +1,28 @@ +// +// lyricwalker.hh -- declare Lyric_walker +// +// (c) 1996,97 Han-Wen Nienhuys, Jan Nieuwenhuizen +// + +#ifndef LYRICWALKER_HH +#define LYRICWALKER_HH + +#include "proto.hh" +#include "grouping.hh" +#include "staff-walker.hh" + +/// a simple walker which collects words, and then print them, first on top +struct Lyric_walker: Staff_walker { + Array litem_l_array_; + + /* *************** */ + virtual void process_requests(); + + Lyric_walker(Lyric_staff* lstaff_l); + Lyric_staff* lstaff_l(); +}; + + +#endif // LYRICWALKER_HH + + diff --git a/lily/include/meter-reg.hh b/lily/include/meter-reg.hh new file mode 100644 index 0000000000..6ebe18c282 --- /dev/null +++ b/lily/include/meter-reg.hh @@ -0,0 +1,29 @@ +/* + meter-reg.hh -- declare Meter_register + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef METERREG_HH +#define METERREG_HH +#include "register.hh" + +/** + generate meters. + */ +class Meter_register : public Request_register { +public: + Meter_change_req * meter_req_l_; + Meter * meter_p_; + + virtual bool try_request(Request *req_l); + virtual void process_requests(); + virtual void pre_move_processing(); + virtual void post_move_processing(); + Meter_register(); + NAME_MEMBERS(Meter_register); +}; +#endif // METERREG_HH diff --git a/lily/include/meter.hh b/lily/include/meter.hh new file mode 100644 index 0000000000..928434b28a --- /dev/null +++ b/lily/include/meter.hh @@ -0,0 +1,22 @@ +/* + meter.hh -- declare Meter + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef METER_HH +#define METER_HH +#include "item.hh" +#include "varray.hh" +#include "scalar.hh" + +struct Meter: Item { + Array args; + /* *************** */ +NAME_MEMBERS(Meter); + + Meter(Array args) ; + Molecule*brew_molecule_p() const; +}; +#endif // METER_HH + diff --git a/lily/include/midi-def.hh b/lily/include/midi-def.hh new file mode 100644 index 0000000000..7a559adf58 --- /dev/null +++ b/lily/include/midi-def.hh @@ -0,0 +1,38 @@ +/* + midi-def.hh -- declare + + source file of the LilyPond music typesetter + + (c) 1997 Jan Nieuwenhuizen +*/ + + +#ifndef MIDIDEF_HH +#define MIDIDEF_HH +#include "proto.hh" +#include "real.hh" +#include "string.hh" +#include "moment.hh" + + +/** + */ +struct Midi_def { + /// output file name + String outfile_str_; + + /// duration of whole note + Real whole_seconds_f_; + + Midi_def(); + Midi_def(Midi_def const& midi_c_r); + ~Midi_def(); + + Real duration_to_seconds_f(Moment); + int get_tempo_i( Moment moment ); + void set_tempo( Moment moment, int count_per_minute_i ); + void print() const; +}; + +#endif // MIDIDEF_HH // + diff --git a/lily/include/midi-walker.hh b/lily/include/midi-walker.hh new file mode 100644 index 0000000000..e7c26380f4 --- /dev/null +++ b/lily/include/midi-walker.hh @@ -0,0 +1,41 @@ +/* + midi-walker.hh -- declare Midi_walker + + (c) 1996,97 Han-Wen Nienhuys, Jan Nieuwenhuizen + */ + +#ifndef MIDIWALKER_HH +#define MIDIWALKER_HH + +#include "proto.hh" +#include "grouping.hh" +#include "staff-walker.hh" +#include "pcursor.hh" +#include "pqueue.hh" + + +/** + a simple walker which collects midi stuff, and then outputs. + + Should derive from Staff_walker + */ +class Midi_walker : public PCursor { + Midi_track *track_l_; + PQueue stop_notes; + Moment last_moment_; + + /* *************** */ + void do_stop_notes(Moment); + + void output_event(Midi_item&, Moment); +public: + + Midi_walker(Staff*, Midi_track*); + void process_requests(); + ~Midi_walker(); +}; + + +#endif // MIDIWALKER_HH + + diff --git a/lily/include/notehead.hh b/lily/include/notehead.hh new file mode 100644 index 0000000000..d7a68e7798 --- /dev/null +++ b/lily/include/notehead.hh @@ -0,0 +1,45 @@ +/* + notehead.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef NOTEHEAD_HH +#define NOTEHEAD_HH +#include "item.hh" + +/** + ball at the end of the stem +takes care of: + + * help lines + * proper placing of dots + + */ + +struct Notehead : Item { + NAME_MEMBERS(Notehead); + + int position; + /// -1 = lowest, 0 = inside, 1 = top + int extremal; + /// needed for the help-lines + int staff_size; + int dots; + int balltype; + int x_dir; + + /* *************** */ + + void set_rhythmic(Rhythmic_req *); + + /** + position of top line (5 linestaff: 8) + */ + Notehead(int staff_size); + void do_print()const; + static int compare(Notehead * const &a, Notehead *const &b) ; + Molecule* brew_molecule_p()const; +}; +#endif // NOTEHEAD_HH + diff --git a/lily/include/paper-def.hh b/lily/include/paper-def.hh new file mode 100644 index 0000000000..ae557258b0 --- /dev/null +++ b/lily/include/paper-def.hh @@ -0,0 +1,54 @@ +/* + paper-def.hh -- declare + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef Paper_def_HH +#define Paper_def_HH +#include "proto.hh" +#include "real.hh" +#include "string.hh" +#include "moment.hh" + + +/** symbols, dimensions and constants + + This struct takes care of all kinds of symbols, dimensions and + constants. Most of them are related to the point-size of the fonts, + so therefore, the lookup table for symbols is also in here. + + see TODO + */ +struct Paper_def { + Lookup *lookup_p_; + String outfile; + + Real linewidth; + + /// how much space does a whole note take (ideally?) + Real whole_width; + + /// ideal = geometric_ ^ log2(duration) + Real geometric_; + + /* *************** */ + void reinit(); + Paper_def(Lookup*); + void set(Lookup*); + ~Paper_def(); + Paper_def(Paper_def const&); + Real interline()const; + Real internote()const; + Real rule_thickness()const; + Real standard_height()const; + Real note_width() const; + void print() const; + Real duration_to_dist(Moment); +}; + +#endif // Paper_def_HH + diff --git a/lily/include/pscore.hh b/lily/include/pscore.hh new file mode 100644 index 0000000000..b7ad49c0e1 --- /dev/null +++ b/lily/include/pscore.hh @@ -0,0 +1,106 @@ +// the breaking problem for a score. + +#ifndef PSCORE_HH +#define PSCORE_HH + +#include "colhpos.hh" +#include "varray.hh" +#include "pcol.hh" +#include "pstaff.hh" + + +/** all stuff which goes onto paper. 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. + */ + +struct PScore { + Paper_def *paper_l_; + + /// the columns, ordered left to right + IPointerList cols; + + /// the idealspacings, no particular order + IPointerList suz; + + /// the staffs ordered top to bottom + IPointerList staffs; + + /// all symbols in score. No particular order. + IPointerList its; + + /// if broken, the different lines + IPointerList lines; + + /// crescs etc; no particular order + IPointerList spanners; + + /// broken spanners + IPointerList broken_spans; + + /* *************** */ + /* CONSTRUCTION */ + + PScore(Paper_def*); + /// add a line to the broken stuff. Positions given in #config# + void set_breaking(Array); + + void add(PStaff *); + + + /** add an item. + add the item in specified containers. If breakstatus is set + properly, add it to the {pre,post}break of the pcol. + */ + void typeset_item(Item *item_p, PCol *pcol_l,PStaff*pstaf_l,int breakstatus=1); + + /// add a Spanner + void typeset_spanner(Spanner*, PStaff*); + + /// add to bottom of pcols + void add(PCol*); + void add_broken(Spanner*); + + /* INSPECTION */ + Array select_items(PStaff*, PCol*); + + /** + @return argument as a cursor of the list + */ + PCursor find_col(const PCol *)const; + + /* MAIN ROUTINES */ + void process(); + + /// last deed of this struct + void output(Tex_stream &ts); + + /* UTILITY ROUTINES */ + + /// get the spacing between c1 and c2, create one if necessary. + Idealspacing* get_spacing(PCol *c1, PCol *c2); + + /// connect c1 and c2 + void do_connect(PCol *c1, PCol *c2, Real distance_f, Real strength_f); + + /// connect c1 and c2 and any children of c1 and c2 + void connect(PCol* c1, PCol *c2, Real distance_f,Real strength_f= 1.0); + + /* STANDARD ROUTINES */ + void OK()const; + void print() const; +private: + /// before calc_breaking + void preprocess(); + + /// calculate where the lines are to be broken, and use results + void calc_breaking(); + + /// after calc_breaking + void postprocess(); + + /// delete unused columns + void clean_cols(); +}; + +#endif diff --git a/lily/include/pstaff.hh b/lily/include/pstaff.hh new file mode 100644 index 0000000000..50a7f0c719 --- /dev/null +++ b/lily/include/pstaff.hh @@ -0,0 +1,25 @@ +#ifndef PSTAFF_HH +#define PSTAFF_HH + +#include "proto.hh" +#include "plist.hh" +#include "item.hh" +#include "symbol.hh" + +/// items grouped horizontally +struct PStaff { + PScore * pscore_l_; + + + PointerList spans; + PointerList its; + + /* *************** */ + void add(Item*i); + PStaff(PScore*); + +private: + PStaff(PStaff const&); +}; + +#endif diff --git a/lily/include/register.hh b/lily/include/register.hh new file mode 100644 index 0000000000..da80db38fe --- /dev/null +++ b/lily/include/register.hh @@ -0,0 +1,107 @@ +/* + register.hh -- part of LilyPond + + (c) 1996,1997 Han-Wen Nienhuys +*/ + +#ifndef REGISTER_HH +#define REGISTER_HH + +#include "proto.hh" +#include "varray.hh" +#include "request.hh" +#include "staff-elem-info.hh" + +/** + a struct which processes requests, and creates the #Staff_elem#s. + It may use derived classes. Hungarian postfix: register + */ +class Request_register { + friend class Register_group_register; + /** + You cannot copy a Request_register + */ + Request_register(const Request_register&){} +protected: + + /// utility + virtual Paper_def * paper() const; + + /** + try to fit the request in this register + + @return + false: not noted, not taken. + + true: request swallowed. Don't try to put the request elsewhere. + + + Default: always return false + */ + virtual bool try_request(Request *req_l); + + /// make items/spanners with the requests you got + virtual void process_requests(){} + + /** typeset any items/spanners. Default: do nothing + */ + virtual void pre_move_processing(){} + /** reset any appropriate data. Default: do nothing + */ + virtual void post_move_processing(){} + + /** + Is this request eligible to be processed? Default: return false. + */ + virtual bool acceptable_request_b(Request*) const; + + /** + typeset a "command" item. Default: pass on to daddy. + If the column is not breakable, #pre_p# and #post_p# are junked + */ + virtual void typeset_breakable_item(Item * pre_p , + Item * nobreak_p, Item * post_p); + /** + Invoke walker method to typeset element. Default: pass on to daddy. + */ + virtual void typeset_element(Staff_elem*elem_p); + + /** + take note of item/spanner + put item in spanner. Adjust local key; etc. + + Default: ignore the info + */ + virtual void acknowledge_element(Staff_elem_info) {} + /** + Announce element. Default: pass on to daddy. Utility + */ + virtual void announce_element(Staff_elem_info); + /** + Set features of the register(s). Default: ignore features. + */ + virtual void set_feature(Features){} + /** + Does this equal or contain a certain register? + */ + virtual bool contains_b(Request_register*reg_l); + /** + Get information on the staff. Default: ask daddy. + */ + virtual Staff_info get_staff_info(); + + virtual void do_print()const; +public: + /** Every Request_register (except for the 'top' which is directly + inside the Staff_walker, is a element of a group. */ + Register_group_register * daddy_reg_l_; + + Request_register(); + virtual ~Request_register(){} + NAME_MEMBERS(Request_register); + void print() const; +}; + + +#endif // REGISTER_HH + diff --git a/lily/include/registergroup.hh b/lily/include/registergroup.hh new file mode 100644 index 0000000000..6d6e76a15b --- /dev/null +++ b/lily/include/registergroup.hh @@ -0,0 +1,54 @@ +/* + registergroup.hh -- declare + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef REGISTERGROUP_HH +#define REGISTERGROUP_HH + + +#include "plist.hh" +#include "staff-elem-info.hh" +#include "register.hh" + +/** + Group a number of registers. Usually delegates everything to its contents. + Postfix: group + */ +class Register_group_register : public Request_register { +protected: + IPointerList reg_list_; + virtual void do_print()const; +public: + + /** + Junk #reg_l#. + + Pre: + #reg_l# is in #reg_list_# + */ + virtual void terminate_register(Request_register * reg_l); + + /** + Remove #reg_l# from the list, and return it. + */ + Request_register * get_register_p(Request_register*reg_l); + virtual void set_feature(Features i); + virtual bool acceptable_request_b(Request*); + virtual void pre_move_processing(); + virtual void post_move_processing(); + virtual void acknowledge_element(Staff_elem_info info); + virtual bool try_request(Request*); + virtual void process_requests(); + virtual ~Register_group_register(); + virtual void add(Request_register* reg_p); + virtual bool contains_b(Request_register*); +}; + +#endif // REGISTERGROUP_HH + + diff --git a/lily/include/request.hh b/lily/include/request.hh new file mode 100644 index 0000000000..1936d5a2ab --- /dev/null +++ b/lily/include/request.hh @@ -0,0 +1,73 @@ +/* + request.hh -- declare Request baseclasses. + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#ifndef REQUEST_HH +#define REQUEST_HH +// LilyPond's second egg of columbus! + +#include "glob.hh" +#include "string.hh" +#include "moment.hh" +#include "class-name.hh" + +/** + a voice element wants something printed. + Hungarian postfix: req + @see lilygut manpage + */ +class Request { +public: + Voice_element*elt_l_; + char const* defined_ch_c_l_; + + /* *************** */ + Voice * voice_l(); + Request(); + Request(Request const&); + virtual ~Request(){} + + NAME_MEMBERS(Request); + virtual Request* clone() const { return new Request(*this); } + void print()const ; + + virtual Moment duration() const { return 0; } + + /* accessors for children + maybe checkout RTTI + */ + virtual Barcheck_req *barcheck() { return 0; } + virtual Note_req *note() { return 0;} + virtual Script_req *script() { return 0;} + virtual Stem_req *stem() { return 0;} + virtual Text_req*text() { return 0; } + virtual Rest_req *rest() { return 0; } + virtual Span_req *span() { return 0; } + virtual Beam_req *beam() { return 0 ; } + virtual Plet_req* plet() { return 0; } + virtual Slur_req *slur() { return 0 ; } + virtual Rhythmic_req*rhythmic() { return 0; } + virtual Lyric_req* lreq_l() { return 0; } + virtual Melodic_req *melodic() { return 0; } + virtual Terminate_voice_req *terminate() {return 0;} + virtual Group_change_req * groupchange() { return 0;} + virtual Group_feature_req * groupfeature() { return 0; } + virtual Spacing_req * spacing() { return 0; } + virtual Blank_req * blank() { return 0; } + virtual Musical_req *musical() { return 0; } + virtual Command_req * command() { return 0; } +protected: + virtual void do_print()const ; +}; + +#define REQUESTMETHODS(T,accessor) \ +virtual T * accessor() { return this;}\ +NAME_MEMBERS(T);\ +virtual Request *clone() const { return new T(*this); } \ +virtual void do_print() const + +#endif diff --git a/lily/include/rest.hh b/lily/include/rest.hh new file mode 100644 index 0000000000..85c7266677 --- /dev/null +++ b/lily/include/rest.hh @@ -0,0 +1,25 @@ +/* + rest.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef REST_HH +#define REST_HH +#include "item.hh" + +struct Rest : Item { + + int dots; + int balltype; + + /* *************** */ + + + Rest(int dur,int dots); + void do_print()const; +NAME_MEMBERS(Rest); + Molecule* brew_molecule_p()const; +}; +#endif + diff --git a/lily/include/score-walker.hh b/lily/include/score-walker.hh new file mode 100644 index 0000000000..b3d304256e --- /dev/null +++ b/lily/include/score-walker.hh @@ -0,0 +1,37 @@ +/* + score-walker.hh -- declare Score_walker + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef SCOREWALKER_HH +#define SCOREWALKER_HH +#include "pcursor.hh" +#include "proto.hh" +#include "varray.hh" + + +/** + walk through the score_columns, and while doing so, walk all staffs in a score. + */ +class Score_walker : public PCursor +{ + Score* score_l_; + /// walkers for the individual staves. + Array walker_p_arr_; + Array disallow_break_walk_l_arr; + int disallow_break_count_; + void reinit(); +public: + void allow_break(Staff_walker*w); + Score_walker(Score*); + ~Score_walker(); + Moment when(); + void operator++(int); + /// process staff walkers. + void process(); +}; +#endif // SCOREWALKER_HH diff --git a/lily/include/score.hh b/lily/include/score.hh new file mode 100644 index 0000000000..a865ed02f3 --- /dev/null +++ b/lily/include/score.hh @@ -0,0 +1,90 @@ +/* + score.hh -- declare Score + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef SCORE_HH +#define SCORE_HH + +#include "varray.hh" +#include "proto.hh" +#include "plist.hh" +#include "moment.hh" +#include "assoc.hh" +#include "string.hh" + +/// the total music def of one movement +struct Score { + /// paper_, staffs_ and commands_ form the problem definition. + Paper_def *paper_p_; + Midi_def *midi_p_; + IPointerList staffs_; + + /// "runtime" fields for setting up spacing + IPointerList cols_; + PScore *pscore_p_; + + const char *defined_ch_c_l_; + int errorlevel_i_; + + /* *************************************************************** */ + + /// construction + Score(); + ~Score(); + void add(Staff*); + + /// do everything except outputting to file + void process(); + + /// output to file + void output(String fn); + + + /// + void set(Midi_def* midi_p); + /// + void set(Paper_def* midi_p); + + // standard + void OK() const; + void print() const; + + /// find a column. + PCursor find_col(Moment,bool); + + /// when does the last *musical* element finish? + Moment last() const; + +private: + void paper_output(); + void setup_music(); + void process_music(); + /// do midi stuff + void midi(); + + /// do paper stuff + void paper(); + + // utils: + PCursor create_cols(Moment); + + Score(Score const&){} + + /** + make the pcol_l_ fields of each Score_column point to the correct PCol, + remove any unnecessary Score_column's + */ + void do_cols(); + + /// remove unused cols + void clean_cols(); + + /// add #Idealspacings# to #pscore_# + void calc_idealspacing(); +}; +#endif diff --git a/lily/include/script-def.hh b/lily/include/script-def.hh new file mode 100644 index 0000000000..8b5be32561 --- /dev/null +++ b/lily/include/script-def.hh @@ -0,0 +1,25 @@ +/* + script-def.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef SCRIPTDEF_HH +#define SCRIPTDEF_HH +#include "string.hh" +struct Script_def{ + int stemdir; + int staffdir; + + bool invertsym; + String symidx; + + /* *************** */ + int compare(Script_def const &); + void print() const; + Script_def(String, int, int ,bool); +}; + + +#endif // SCRIPTDEF_HH + diff --git a/lily/include/script-reg.hh b/lily/include/script-reg.hh new file mode 100644 index 0000000000..33592cae03 --- /dev/null +++ b/lily/include/script-reg.hh @@ -0,0 +1,29 @@ +/* + script-reg.hh -- part of LilyPond + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef SCRIPTREG_HH +#define SCRIPTREG_HH + +#include "register.hh" + + +struct Script_register : Request_register { + Script * script_p_; + Script_req * script_req_l_; + int dir_i_; + /* *************** */ + void set_feature(Features dir_i_); + Script_register(); + virtual bool try_request(Request*); + virtual void process_requests(); + virtual void acknowledge_element(Staff_elem_info); + virtual void pre_move_processing(); + virtual void post_move_processing(); + NAME_MEMBERS(Script_register); +}; + +#endif // SCRIPTREG_HH diff --git a/lily/include/script.hh b/lily/include/script.hh new file mode 100644 index 0000000000..df408f0435 --- /dev/null +++ b/lily/include/script.hh @@ -0,0 +1,41 @@ +/* + script.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef SCRIPT_HH +#define SCRIPT_HH + +#include "script-def.hh" +#include "item.hh" + +struct Script : Item { + int dir; + int symdir; + int pos; + int staffsize; + Script_def *specs_l_; + Stem *stem_l_; + Array support; + + /* *************** */ + NAME_MEMBERS(Script); + Molecule *brew_molecule_p()const; + virtual void do_post_processing(); + virtual void do_pre_processing(); + Script(Script_req*, int staffsize); + void set_support(Item*); + void set_stem(Stem*); + Interval support_height()const; + virtual Interval width() const; +private: + void set_symdir(); + void set_default_dir(); + void set_default_index(); + Symbol symbol()const; +}; + + +#endif // SCRIPT_HH + diff --git a/lily/include/slur-reg.hh b/lily/include/slur-reg.hh new file mode 100644 index 0000000000..e357c8795e --- /dev/null +++ b/lily/include/slur-reg.hh @@ -0,0 +1,33 @@ +/* + slur-reg.hh -- declare Slur_register + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef SLURREG_HH +#define SLURREG_HH + +#include "register.hh" + +struct Slur_register : Request_register { + Array requests_arr_; + Array new_slur_req_l_arr_; + Array slur_l_stack_; + Array end_slur_l_arr_; + + int dir_i_; + + /* *************** */ + ~Slur_register(); + Slur_register(); + virtual bool try_request(Request*); + virtual void process_requests(); + virtual void acknowledge_element(Staff_elem_info); + virtual void pre_move_processing(); + virtual void post_move_processing(); + virtual void set_feature(Features); + NAME_MEMBERS(Slur_register); +}; + +#endif // SLURREG_HH diff --git a/lily/include/slur.hh b/lily/include/slur.hh new file mode 100644 index 0000000000..87f1fe855e --- /dev/null +++ b/lily/include/slur.hh @@ -0,0 +1,37 @@ +/* + slur.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef SLUR_HH +#define SLUR_HH + +#include "directional-spanner.hh" +#include "fproto.hh" +#include "varray.hh" + +struct Slur : Directional_spanner { + + Array encompass; + + bool open_left, open_right; + + /* *************** */ + Offset center() const; + Slur(); + void do_post_processing(); + void do_pre_processing(); + void add(Notehead*); + void set_default_dir(); + + Spanner* do_break_at( PCol*, PCol*) const; + void process(); +private: + Molecule*brew_molecule_p()const; + NAME_MEMBERS(Slur); +}; + +#endif // SLUR_HH + + diff --git a/lily/include/spanner.hh b/lily/include/spanner.hh new file mode 100644 index 0000000000..43a3567fa5 --- /dev/null +++ b/lily/include/spanner.hh @@ -0,0 +1,54 @@ +/* + spanner.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef SPANNER_HH +#define SPANNER_HH + +#include "proto.hh" +#include "staff-elem.hh" + + +/** a symbol which is attached between two columns. A spanner is a symbol which spans across several columns, so its + final appearance can only be calculated after the breaking problem + is solved. + + Examples + + - (de)crescendo + - slur + - beam + - bracket + + + 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. + + */ +struct Spanner:Staff_elem { + PCol *left, *right; + + + /* *************** */ + + Spanner(); + virtual Interval width()const; + void do_print()const; + + Spanner *broken_at(PCol *c1, PCol *c2) const; + virtual Spanner* spanner() { return this; } +protected: + + /** + clone a piece of this spanner. + PRE + c1 >= start, c2 <= stop + */ + virtual Spanner *do_break_at( PCol *c1, PCol *c2) const=0; + NAME_MEMBERS(Spanner); +}; +#endif diff --git a/lily/include/staff-column.hh b/lily/include/staff-column.hh new file mode 100644 index 0000000000..dd6303ea8c --- /dev/null +++ b/lily/include/staff-column.hh @@ -0,0 +1,48 @@ +/* + staff-column.hh -- declare Staff_column + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef STAFFCOLUMN_HH +#define STAFFCOLUMN_HH +#include "proto.hh" +#include "varray.hh" +#include "moment.hh" + +/// store simultaneous requests +class Staff_column { + + Staff_column(Staff_column const&); + +public: + Array creationreq_l_arr_; + Array musicalreq_l_arr_; + Array commandreq_l_arr_; + Staff * staff_l_; + + /// fields to collect timing data vertically. + Array timing_req_l_arr_; + Score_column *musical_column_l_, *command_column_l_; + + /* *************** */ + + Staff_column(); + + Moment when() const; + void set_cols(Score_column *c1, Score_column *c2); + void add(Voice_element*ve); + void OK() const; + ~Staff_column(); + void typeset_breakable_items(Array &pre_p_arr, + Array &nobreak_p_arr, + Array &post_p_arr); + void typeset_musical_item(Item *i); +protected: + void setup_one_request(Request*); +}; + + + +#endif // STAFFCOLUMN_HH + diff --git a/lily/include/staff-elem-info.hh b/lily/include/staff-elem-info.hh new file mode 100644 index 0000000000..9c6264a86b --- /dev/null +++ b/lily/include/staff-elem-info.hh @@ -0,0 +1,43 @@ +/* + staff-elem-info.hh -- declare Staff_elem_info + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef STAFFELEMINFO_HH +#define STAFFELEMINFO_HH + +#include "proto.hh" +#include "varray.hh" +/// data container. +struct Staff_elem_info { + Staff_elem * elem_p_; + Request*req_l_; + const Voice * voice_l_; + Array origin_reg_l_arr_; + + + /* *** */ + Staff_elem_info(Staff_elem*, Request*); + Staff_elem_info(); +}; + +struct Staff_info { + int *c0_position_i_; + Staff_walker *walk_l_; + const Time_description *time_c_l_; + const Rhythmic_grouping *rhythmic_c_l_; +}; + + +struct Features { + bool initialiser_b_; + int direction_i_; + + Features(); + static Features dir(int); +}; +#endif // STAFFELEMINFO_HH diff --git a/lily/include/staff-elem.hh b/lily/include/staff-elem.hh new file mode 100644 index 0000000000..e2fce84582 --- /dev/null +++ b/lily/include/staff-elem.hh @@ -0,0 +1,88 @@ +/* + staff-elem.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef STAFFELEM_HH +#define STAFFELEM_HH +#include "varray.hh" +#include "proto.hh" +#include "offset.hh" +#include "molecule.hh" +#include "class-name.hh" + + +/** Both Spanner and Item are Staff_elem's. Most Staff_elem's depend + on other Staff_elem's, eg, Beam needs to know and set direction of + Stem. So the Beam has to be calculated *before* Stem. This is + accomplished with the dependencies field of struct Staff_elem. + + */ +struct Staff_elem { + enum Status { + ORPHAN, // not yet added to pstaff + VIRGIN, // added to pstaff + PRECALCING, + PRECALCED, // calcs before spacing done + POSTCALCING, + POSTCALCED, // after spacing calcs done + OUTPUT, // molecule has been output + } status; + + /// the pstaff it is in + PStaff *pstaff_l_; + + /* *************** */ + Staff_elem(Staff_elem const&); + String TeXstring () const ; + virtual void print() const; + virtual Interval width() const; + virtual Interval height() const; + Paper_def *paper() const; + virtual ~Staff_elem(); + Staff_elem(); + NAME_MEMBERS(Staff_elem); + void translate(Offset); + void add_processing(); + void pre_processing(); + void post_processing(); + void molecule_processing(); + + virtual Spanner* spanner() { return 0; } + virtual Item * item() { return 0; } + void add_dependency(Staff_elem* ); + void substitute_dependency(Staff_elem* old, Staff_elem * newdep); + +protected: + + /// do printing of derived info. + virtual void do_print() const=0; + /// generate the molecule + virtual Molecule* brew_molecule_p()const=0; + ///executed directly after the item is added to the PScore + virtual void do_add_processing(); + /// do calculations before determining horizontal spacing + virtual void do_pre_processing(); + + /// do calculations after determining horizontal spacing + virtual void do_post_processing(); + + Array dependants; + +private: + /// member: the symbols + Molecule *output; // should scrap, and use temp var? + + + /** + This is needed, because #output# may still be + NULL. + */ + Offset offset_; + Array dependencies; +}; + + +#endif // STAFFELEM_HH + diff --git a/lily/include/staff-walker.hh b/lily/include/staff-walker.hh new file mode 100644 index 0000000000..fb0d098e07 --- /dev/null +++ b/lily/include/staff-walker.hh @@ -0,0 +1,47 @@ +/* + staff-walker.hh -- declare Staff_walker + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef STAFFWALKER_HH +#define STAFFWALKER_HH + +#include "proto.hh" +#include "time-description.hh" +#include "pcursor.hh" + +/** + manage run-time info when walking staffcolumns such as: key, + meter, pending beams & slurs + */ +struct Staff_walker : public PCursor { + Staff * staff_l_; + PScore * pscore_l_; + Score_walker *score_walk_l_; + Time_description time_; + Rhythmic_grouping *default_grouping; + + /* *************** */ + + Moment when() const; + virtual ~Staff_walker(); + Staff_walker(Staff*, PScore*); + void process() ; + + void operator++(int); + void allow_break(); + +protected: + /// every time before ++ is called + virtual void do_pre_move(){} + /// every time after ++ is called + virtual void do_post_move(){} + virtual void process_requests()=0; +private: + void process_timing_reqs(); + Staff_walker(Staff_walker const&); +}; + +#endif // STAFFWALKER_HH + diff --git a/lily/include/staff.hh b/lily/include/staff.hh new file mode 100644 index 0000000000..959859b6e4 --- /dev/null +++ b/lily/include/staff.hh @@ -0,0 +1,61 @@ +/* + staff.hh -- declare Staff + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#ifndef STAFF_HH +#define STAFF_HH + +#include "plist.hh" +#include "proto.hh" +#include "moment.hh" + +/// base class for a collection of voices. +class Staff { + Staff(const Staff&src); + + /// synchronous horizontal stuff + IPointerList voice_list_; + Staff_column *get_col(Moment, PCursor * last= 0); + +public: + + /// runtime field + IPointerList cols_; + + Score *score_l_; + PScore *pscore_l_; + PStaff *pstaff_l_; + + /* *************************************************************** */ + + void add(const PointerList &s); + + void add_voice(Voice *v); + Paper_def*paper()const; + + void setup_staffcols(); + + void OK() const; + void print() const; + + /// when does the last *musical* element finish? + Moment last() const; + +// /// extract midi info +// Midi_track* midi_track_p(); + + /// remove unused cols + void clean_cols() ; + Staff(); + + virtual void set_output(PScore * destination)=0; + virtual Staff_walker *get_walker_p()=0; + virtual ~Staff() { } +protected: + +}; +#endif diff --git a/lily/include/staffsym.hh b/lily/include/staffsym.hh new file mode 100644 index 0000000000..bcec2bfaff --- /dev/null +++ b/lily/include/staffsym.hh @@ -0,0 +1,30 @@ +/* + staffsym.hh -- declare Staff_symbol + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef STAFFSYM_HH +#define STAFFSYM_HH +#include "spanner.hh" +/** + This spanner draws the lines of a pstaff. + The bottom line is position 0. + */ +class Staff_symbol : public Spanner +{ +public: + /// this many lines. + int no_lines_i_; + + NAME_MEMBERS(Staff_symbol); + Staff_symbol(int lines); + virtual Molecule* brew_molecule_p() const; + void set_extent(PCol* p1, PCol* p2); + virtual void do_print()const; + virtual Spanner *do_break_at( PCol *c1, PCol *c2) const; +}; +#endif // STAFFSYM_HH diff --git a/lily/include/stem-beam-reg.hh b/lily/include/stem-beam-reg.hh new file mode 100644 index 0000000000..dddba269a4 --- /dev/null +++ b/lily/include/stem-beam-reg.hh @@ -0,0 +1,33 @@ +/* + stem-beam-reg.hh -- part of LilyPond + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef STEMBEAMREG_HH +#define STEMBEAMREG_HH +#include "register.hh" + +struct Stem_beam_register : Request_register { + Stem * stem_p_; + Beam * beam_p_; + Beam_req * beam_req_l_; + Stem_req * stem_req_l_; + Beam_req * start_req_l_; + bool end_beam_b_; + Rhythmic_grouping *current_grouping; + int default_dir_i_; + + /* *************** */ + Stem_beam_register(); + ~Stem_beam_register(); + virtual void set_feature(Features dir_i_); + virtual bool try_request(Request*); + virtual void process_requests(); + virtual void acknowledge_element(Staff_elem_info); + virtual void pre_move_processing(); + virtual void post_move_processing(); + NAME_MEMBERS(Stem_beam_register); +}; +#endif // STEMBEAMREG_HH diff --git a/lily/include/stem.hh b/lily/include/stem.hh new file mode 100644 index 0000000000..34776ea49c --- /dev/null +++ b/lily/include/stem.hh @@ -0,0 +1,81 @@ +/* + stem.hh -- declare Stem + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef STEM_HH +#define STEM_HH +#include "item.hh" +#include "varray.hh" +#include "moment.hh" + + +/**the rule attached to the ball. + takes care of: + + \begin{itemize} + \item the rule + \item the flag + \item up/down position. + \end{itemize} + */ + +struct Stem : Item { + /// heads that the stem encompasses (positions) + int minnote, maxnote; + + /// false if in beam + bool print_flag; + + int beams_left; + int beams_right; + + /// needed for determining direction/length + int staff_center; + + + /**extent of the stem (positions). + fractional, since Beam has to adapt them. + */ + + Real bot, top; + Real stemlen; + + /// flagtype? 4 none, 8 8th flag, 0 = beam. + int flag; + + + /** + geen gedonder, jij gaat onder. + -1 stem points down, +1: stem points up + */ + + int dir; + Real stem_xoffset; + + Array heads; + + /* *************** */ + Stem(int center); //, Moment duration); + + /// ensure that this Stem also encompasses the Notehead #n# + void add(Notehead*n); + + NAME_MEMBERS(Stem); + + Real hindex()const; + void do_print() const; + void set_stemend(Real); + int get_default_dir(); + void set_default_dir(); + void set_default_stemlen(); + void set_default_extents(); + void set_noteheads(); + void do_pre_processing(); + + Interval width() const; + + Molecule* brew_molecule_p() const; +}; +#endif diff --git a/lily/include/symbol.hh b/lily/include/symbol.hh new file mode 100644 index 0000000000..c166fa5bcf --- /dev/null +++ b/lily/include/symbol.hh @@ -0,0 +1,17 @@ +#ifndef SYMBOL_HH +#define SYMBOL_HH + +#include "string.hh" +#include "boxes.hh" +#include "proto.hh" + +struct Symbol { + String tex; + Box dim; + + Symbol (String, Box); + Symbol(); + String str()const; // for printing. +}; + +#endif diff --git a/lily/include/symtable.hh b/lily/include/symtable.hh new file mode 100644 index 0000000000..f96d02c1ec --- /dev/null +++ b/lily/include/symtable.hh @@ -0,0 +1,28 @@ +/* + lilypond, (c) 1996,97 Han-Wen Nienhuys +*/ +#ifndef SYMTABLE_HH +#define SYMTABLE_HH +#include "assoc.hh" +#include "string.hh" +#include "symbol.hh" + +struct Symtable : public Assoc { + Symbol lookup(String)const; + void print()const; +}; + + +struct Symtables : private Assoc { + + Symtable* operator()(String s); + ~Symtables(); + Symtables(); + Symtables(Symtables const&); + Assoc::add; + void print()const; +}; + + +#endif + diff --git a/lily/include/text-def.hh b/lily/include/text-def.hh new file mode 100644 index 0000000000..cc9c3c95b3 --- /dev/null +++ b/lily/include/text-def.hh @@ -0,0 +1,29 @@ +/* + text-def.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef TEXTDEF_HH +#define TEXTDEF_HH + +#include "string.hh" +#include "proto.hh" + +struct Text_def { + int align_i_; + String text_str_; + String style_str_; + char const* defined_ch_c_l_; + + + /* ****************/ + virtual ~Text_def() {}; + bool compare(const Text_def&); + Text_def(); + virtual void print() const; + virtual Atom create_atom(Paper_def*) const; +}; + +#endif // TEXTDEF_HH + diff --git a/lily/include/text-item.hh b/lily/include/text-item.hh new file mode 100644 index 0000000000..ae0b556308 --- /dev/null +++ b/lily/include/text-item.hh @@ -0,0 +1,30 @@ +/* + text.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef TEXT_ITEM_HH +#define TEXT_ITEM_HH + +#include "text-def.hh" +#include "item.hh" + +struct Text_item : Item { + int pos_i_; + int staffsize_i_; + int dir_i_; + Text_def* tdef_l_; + + /* ***************/ + NAME_MEMBERS(Text_item); + virtual void set_default_index(); + Molecule* brew_molecule_p() const; + void do_pre_processing(); + + Text_item(Text_req*,int); +}; + + +#endif // TEXT_HH + diff --git a/lily/include/text-reg.hh b/lily/include/text-reg.hh new file mode 100644 index 0000000000..59317e5bcd --- /dev/null +++ b/lily/include/text-reg.hh @@ -0,0 +1,26 @@ +/* + text-reg.hh -- part of LilyPond + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef TEXTREG_HH +#define TEXTREG_HH +#include "register.hh" + +struct Text_register : Request_register{ + Text_item * text_p_; + Text_req * text_req_l_; + int dir_i_; + /* *************** */ + virtual void set_feature(Features ); + Text_register(); + virtual bool try_request(Request*); + virtual void process_requests(); + virtual void pre_move_processing(); + virtual void post_move_processing(); + NAME_MEMBERS(Text_register); +}; + +#endif // TEXTREG_HH diff --git a/lily/include/text-spanner.hh b/lily/include/text-spanner.hh new file mode 100644 index 0000000000..dbdea979ad --- /dev/null +++ b/lily/include/text-spanner.hh @@ -0,0 +1,34 @@ +/* + textspanner.hh -- part of LilyPond + + (c) 1996,97 Han-Wen Nienhuys +*/ + +#ifndef TEXTSPANNER_HH +#define TEXTSPANNER_HH + +#include "string.hh" +#include "directional-spanner.hh" +#include "text-def.hh" + +/** a spanner which puts texts on top of other spanners. Use for + triplets, eentweetjes, ottava, etc. */ +struct Text_spanner : Spanner { + Text_def spec; + Offset text_off_; + Directional_spanner*support; + + /* *************** */ + + NAME_MEMBERS(Text_spanner); + virtual void do_pre_processing(); + virtual void do_post_processing(); + virtual Interval height() const ; + virtual Molecule* brew_molecule_p()const; + virtual void do_print() const; + virtual Spanner* do_break_at(PCol*,PCol*)const; + Text_spanner(); + void set_support(Directional_spanner*); +}; +#endif // TEXTSPANNER_HH + diff --git a/lily/include/voice-element.hh b/lily/include/voice-element.hh new file mode 100644 index 0000000000..0c5b6b1328 --- /dev/null +++ b/lily/include/voice-element.hh @@ -0,0 +1,37 @@ +/* + voice-element.hh -- declare Voice_element + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef VOICE_ELEMENT_HH +#define VOICE_ELEMENT_HH + +#include "proto.hh" +#include "plist.hh" +#include "moment.hh" + +/** one horizontal bit. Voice_element is nothing but a container for + *the requests, */ +struct Voice_element { + Moment duration; + char const* defined_ch_c_l_; + const Voice *voice_l_; + IPointerList reqs; + + /* *************** */ + + Voice_element(); + Voice_element(Voice_element const & src ); + + void add(Request*); + bool find_plet_start_bo(char c, Moment& moment_r); + void print ()const; + void set_default_group(String id); + void set_plet_backwards(Moment& now_moment_r, Moment until_moment, int num_i, int den_i); +}; + +#endif // VOICE-ELEMENT_HH diff --git a/lily/include/voice-group-regs.hh b/lily/include/voice-group-regs.hh new file mode 100644 index 0000000000..7c1b4ed78a --- /dev/null +++ b/lily/include/voice-group-regs.hh @@ -0,0 +1,29 @@ +/* + voice-group-regs.hh -- declare Voice_group_registers + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef VOICEGROUPREGS_HH +#define VOICEGROUPREGS_HH + +#include "registergroup.hh" + +struct Voice_group_registers : Register_group_register { + String group_id_str_; + Array voice_regs_l_; + + /* *************** */ + + NAME_MEMBERS(Voice_group_registers); + static bool static_acceptable_request_b(Request*); + virtual void terminate_register(Request_register*); + virtual void do_print() const; + virtual void add(Request_register*); + Voice_group_registers(String id); + virtual bool try_request(Request*); +}; +#endif // VOICEGROUPREGS_HH diff --git a/lily/include/voice-regs.hh b/lily/include/voice-regs.hh new file mode 100644 index 0000000000..82070a704e --- /dev/null +++ b/lily/include/voice-regs.hh @@ -0,0 +1,31 @@ +/* + voice-regs.hh -- declare Voice_registers + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef VOICEREGS_HH +#define VOICEREGS_HH + +#include "registergroup.hh" + +class Voice_registers : public Register_group_register { + + +public: + Voice *voice_l_; + /* *************** */ + + NAME_MEMBERS(Voice_registers); + virtual bool acceptable_request_b(Request*); + virtual void acknowledge_element(Staff_elem_info info); + virtual bool try_request(Request*); + Voice_registers(Voice*); + virtual void do_print() const; +}; + + +#endif // VOICEREGS_HH diff --git a/lily/include/voice.hh b/lily/include/voice.hh new file mode 100644 index 0000000000..06e6e1da27 --- /dev/null +++ b/lily/include/voice.hh @@ -0,0 +1,35 @@ +#ifndef VOICE_HH +#define VOICE_HH + +#include "proto.hh" +#include "plist.hh" +#include "moment.hh" + +/** class for horizontal stuff. + + Voice is a ordered row of Voice_elements. It is strictly + horizontal: you cannot have two rhythmic elements running parallel + in a Voice. For proper processing, each Voice should have + Group_change_req as a first element. + + */ + +struct Voice { + IPointerList elts; + Moment start; + + /* *************** */ + Voice(); + Voice(Voice const&); + + Moment when(const Voice_element*)const; + Moment last() const; + + void add(Voice_element*); + bool find_plet_start_bo(char c, Moment& moment_r); + void print() const; + void set_default_group(String id); + void set_plet_backwards(Moment& now_moment_r, Moment until_moment, int num_i, int den_i); +}; + +#endif diff --git a/lily/include/walk-regs.hh b/lily/include/walk-regs.hh new file mode 100644 index 0000000000..643ce57605 --- /dev/null +++ b/lily/include/walk-regs.hh @@ -0,0 +1,50 @@ +/* + walkregs.hh -- declare Walker_registers + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + + +#ifndef WALKREGS_HH +#define WALKREGS_HH + + +#include "registergroup.hh" + +/** + Top level registers: the interface to Complex_walker. + + [sigh. Sometimes I wish C++ could do better late binding.] + */ +struct Walker_registers : Register_group_register { + Array prebreak_item_p_arr_; + Array nobreak_item_p_arr_; + Array postbreak_item_p_arr_; + Array announce_info_arr_; + Array group_l_arr_; + Complex_walker * walk_l_; + + /* *************** */ + void change_group(Group_change_req * greq_l, + Voice_registers *voice_regs_l, + Voice_group_registers * old_group); + Voice_group_registers * get_group(String id); + void typeset_musical_item(Staff_elem * elem_p); + Walker_registers(Complex_walker*); + void do_announces(); + void terminate_register(Request_register * reg); + virtual bool try_request(Request * r); + virtual Staff_info get_staff_info(); + + virtual void announce_element(Staff_elem_info); + virtual void acknowledge_element(Staff_elem_info); + virtual void typeset_breakable_item(Item * pre_p , Item * nobreak_p, Item * post_p); + virtual void typeset_element(Staff_elem*elem_p); + virtual void pre_move_processing(); + virtual void post_move_processing(); + virtual Paper_def * paper() const; +}; + +#endif // WALKREGS_HH diff --git a/lily/input-music.cc b/lily/input-music.cc new file mode 100644 index 0000000000..f1047e8bf9 --- /dev/null +++ b/lily/input-music.cc @@ -0,0 +1,252 @@ +#include "debug.hh" +#include "input-music.hh" +#include "voice.hh" +#include "musicalrequest.hh" +#include "voice-element.hh" + +void +Input_music::check_plet(Voice_element* velt_l) +{ + for (iter_top(velt_l->reqs,i); i.ok(); i++) + if ( i->plet() ) { + Moment start_moment = 0; + if ( !find_plet_start_bo( i->plet()->type_c_, start_moment ) ) { + error( "begin of plet not found", i->defined_ch_c_l_ ); + break; + } + Moment moment = 0; + set_plet_backwards( moment, start_moment, i->plet()->dur_i_, i->plet()->type_i_ ); + i.del(); + break; + } +} + +void +Simple_music::add(Voice_element*v) +{ + voice_.add(v); +} + +Moment +Simple_music::length()const +{ + return voice_.last(); +} +void +Simple_music::translate_time(Moment t) +{ + voice_.start += t; +} + +Voice_list +Simple_music::convert()const +{ + Voice_list l; + l.bottom().add(new Voice(voice_)); + return l; +} + + +void +Simple_music::print() const +{ + mtor << "Simple_music {"; + voice_.print(); + mtor << "}\n"; +} +bool +Simple_music::find_plet_start_bo(char c, Moment& moment_r) +{ + return voice_.find_plet_start_bo(c, moment_r); +} +void +Simple_music::set_plet_backwards(Moment& now_moment_r, Moment until_moment, int num_i, int den_i) +{ + voice_.set_plet_backwards(now_moment_r, until_moment, num_i, den_i); +} + +/* *************** */ + +void +Complex_music::add(Input_music*v) +{ + elts.bottom().add(v); +} + +void +Complex_music::print() const +{ + for (iter_top(elts,i); i.ok(); i++) + i->print(); +} + +void +Complex_music::concatenate(Complex_music*h) +{ + for (iter_top(h->elts,i); i.ok(); i++) + add(i->clone()); +} + +Complex_music::Complex_music() +{ +} + +Complex_music::Complex_music(Complex_music const&s) +{ + for (iter_top(s.elts,i); i.ok(); i++) + add(i->clone()); +} +void +Complex_music::set_default_group(String g) +{ + for (iter_top(elts,i); i.ok(); i++) + i->set_default_group(g); +} +bool +Complex_music::find_plet_start_bo(char c, Moment& moment_r) +{ + for (iter_bot(elts,i); i.ok(); i--) { + if ( i->find_plet_start_bo(c, moment_r) ) + return true; + } + return false; +} +void +Complex_music::set_plet_backwards(Moment& now_moment_r, Moment until_moment, int num_i, int den_i) +{ + for (iter_bot(elts,i); i.ok(); i--) { + i->set_plet_backwards(now_moment_r, until_moment, num_i, den_i); + } +} +/* *************************************************************** */ + +void +Music_voice::print() const +{ + mtor << "Music_voice {"; + Complex_music::print(); + mtor << "}\n"; +} + +void +Music_voice::add_elt(Voice_element*v) +{ + PCursor c(elts.bottom()); + if (!c.ok() || !c->simple()) { + Simple_music*vs = new Simple_music; + + c.add(vs); + } + + c = elts.bottom(); + Simple_music *s = c->simple(); + s->add(v); + + check_plet(v); +} + +Moment +Music_voice::length()const +{ + Moment l = 0; + + for (iter_top(elts,i); i.ok(); i++) + l += i->length(); + return l; +} + + +Voice_list +Music_voice::convert()const +{ + Voice_list l; + Moment here = 0; + + for (iter_top(elts,i); i.ok(); i++) { + Moment len = i->length(); + Voice_list k(i->convert()); + k.translate_time(here); + l.concatenate(k); + here +=len; + } + return l; +} + +void +Music_voice::translate_time(Moment t) +{ + elts.bottom()->translate_time(t); +} + + + +/* *************** */ + +void +Music_general_chord::add_elt(Voice_element*v) +{ + Simple_music*vs = new Simple_music; + vs->add(v); + elts.bottom().add(vs); + + check_plet(v); +} + +void +Music_general_chord::print() const +{ + mtor << "Music_general_chord {"; + Complex_music::print(); + mtor << "}\n"; +} + +void +Music_general_chord::translate_time(Moment t) +{ + for (iter_top(elts,i); i.ok(); i++) + i->translate_time(t); +} + +Moment +Music_general_chord::length()const +{ + Moment l =0; + + for (iter_top(elts,i); i.ok(); i++) + l = l >? i->length(); + return l; +} + +Voice_list +Music_general_chord::convert()const +{ + Voice_list l; + for (iter_top(elts,i); i.ok(); i++) { + Voice_list k(i->convert()); + l.concatenate(k); + } + return l; +} + +/* *************** */ + +void +Multi_voice_chord::set_default_group(String g) +{ + int j=0; + for (iter_top(elts, i); i.ok(); i++) { + i->set_default_group(g + String(j)); + j++; + } +} + + +/* *************** */ + +void +Voice_list::translate_time(Moment x) +{ + for (iter_top(*this,i); i.ok(); i++) + i->start += x; +} + diff --git a/lily/input-score.cc b/lily/input-score.cc new file mode 100644 index 0000000000..f39d47a4b1 --- /dev/null +++ b/lily/input-score.cc @@ -0,0 +1,102 @@ +/* + input-score.cc -- implement Input_score + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "debug.hh" +#include "input-score.hh" +#include "input-staff.hh" +#include "input-music.hh" +#include "score.hh" +#include "paper-def.hh" +#include "midi-def.hh" +#include "staff.hh" + + +void +Input_score::add(Input_staff*s) +{ + staffs_.bottom().add(s); +} + +void +Input_score::set(Paper_def*p) +{ + delete paper_p_; + paper_p_ = p; +} + +void +Input_score::set(Midi_def* midi_p) +{ + delete midi_p_; + midi_p_ = midi_p; +} + +Input_score::Input_score(Input_score const&s) +{ + paper_p_ = (s.paper_p_)? new Paper_def(*s.paper_p_) :0; + midi_p_ = (s.midi_p_)? new Midi_def(*s.midi_p_) : 0; + defined_ch_c_l_ = s.defined_ch_c_l_; + errorlevel_i_ = s.errorlevel_i_; + score_wide_music_p_ = (s.score_wide_music_p_) ? + s.score_wide_music_p_->clone():0; +} + +Score* +Input_score::parse() +{ + Score *s_p = new Score; + s_p->defined_ch_c_l_= defined_ch_c_l_; + s_p->errorlevel_i_ = errorlevel_i_; + if (midi_p_) + s_p->set(new Midi_def(*midi_p_)); + if (paper_p_) + s_p->set( new Paper_def(*paper_p_)); + + for (iter_top(staffs_,i); i.ok(); i++) { + Staff* staf_p=i->parse(s_p, score_wide_music_p_); + s_p->add(staf_p); + } + + return s_p; +} + +void +Input_score::set(Input_music *m_p) +{ + delete score_wide_music_p_; + score_wide_music_p_ =m_p; +} + + +Input_score::~Input_score() +{ + delete paper_p_; + delete score_wide_music_p_; + delete midi_p_; +} + +Input_score::Input_score() +{ + score_wide_music_p_ =0; + defined_ch_c_l_=0; + paper_p_= 0; + midi_p_ = 0; + errorlevel_i_ = 0; +} + +void +Input_score::print()const +{ +#ifndef NPRINT + mtor << "Input_score {\n"; + for (iter_top(staffs_,i); i.ok(); i++) { + i->print(); + } + mtor << "}\n"; +#endif +} diff --git a/lily/item.cc b/lily/item.cc new file mode 100644 index 0000000000..e653c46ac6 --- /dev/null +++ b/lily/item.cc @@ -0,0 +1,18 @@ +#include "debug.hh" +#include "item.hh" + + + +Item::Item() +{ + pcol_l_ = 0; +} + +void +Item::do_print() const +{ +#ifndef NPRINT + mtor << "(unknown)"; +#endif +} + diff --git a/lily/key-item.cc b/lily/key-item.cc new file mode 100644 index 0000000000..963b1bc578 --- /dev/null +++ b/lily/key-item.cc @@ -0,0 +1,70 @@ +#include "key-item.hh" +#include "key.hh" +#include "debug.hh" +#include "molecule.hh" +#include "paper-def.hh" +#include "lookup.hh" +//#include "clef-reg.hh" +#include "key-reg.hh" + +const int FLAT_TOP_PITCH=2; /* fes,ges,as and bes typeset in lower octave */ +const int SHARP_TOP_PITCH=4; /* ais and bis typeset in lower octave */ + + + +Key_item::Key_item(int c) +{ + set_c_position(c); +} + +void +Key_item::read(const Key_register& key_reg_r) +{ + const Array &idx_arr =key_reg_r.accidental_idx_arr_; + for (int i = 0 ; i< idx_arr.size(); i++) { + int note = idx_arr[i]; + int acc = key_reg_r.key_.acc(note); + + add(note, acc); + } +} + +void +Key_item::set_c_position(int c0) +{ + int octaves =(abs(c0) / 7) +1 ; + c_position=(c0 + 7*octaves)%7; +} + + +void +Key_item::add(int p, int a) +{ + if ((a<0 && p>FLAT_TOP_PITCH) || + (a>0 && p>SHARP_TOP_PITCH)) { + p -= 7; /* Typeset below c_position */ + } + pitch.push(p); + acc.push(a); +} + + +Molecule* +Key_item::brew_molecule_p()const +{ + Molecule*output = new Molecule; + Real inter = paper()->internote(); + + for (int i =0; i < pitch.size(); i++) { + Symbol s= paper()->lookup_p_->accidental(acc[i]); + Atom a(s); + a.translate(Offset(0,(c_position + pitch[i]) * inter)); + Molecule m(a); + output->add_right(m); + } + Molecule m(paper()->lookup_p_->fill(Box( + Interval(0, paper()->note_width()), + Interval(0,0)))); + output->add_right(m); + return output; +} diff --git a/lily/key-reg.cc b/lily/key-reg.cc new file mode 100644 index 0000000000..84b0e268c6 --- /dev/null +++ b/lily/key-reg.cc @@ -0,0 +1,99 @@ +/* + key-reg.cc -- implement Key_register + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys + + todo: key undo + + */ +#include "time-description.hh" +#include "key-reg.hh" +#include "key-item.hh" +#include "commandrequest.hh" +#include "staff-column.hh" +#include "local-key-reg.hh" +#include "musicalrequest.hh" + +Key_register::Key_register() +{ + post_move_processing(); +} + +bool +Key_register::try_request(Request * req_l) +{ + Command_req* creq_l= req_l->command(); + if (!creq_l|| !creq_l->keychange()) + return false; + + assert(!keyreq_l_); // todo + keyreq_l_ = creq_l->keychange(); + read_req(keyreq_l_); + return true; +} + +void +Key_register::acknowledge_element(Staff_elem_info info) +{ + Command_req * r_l = info.req_l_->command() ; + if (r_l && r_l->clefchange() && !kit_p_) { + int c0_i= *get_staff_info().c0_position_i_; + kit_p_ = new Key_item(c0_i); + kit_p_->read(*this); + announce_element(Staff_elem_info(kit_p_, keyreq_l_)); + } +} + +void +Key_register::process_requests() +{ + const Time_description *time_l = get_staff_info().time_c_l_; + + if (!keyreq_l_ && + (!time_l->whole_in_measure_|| !time_l->when_)) { + default_key_b_ = true; + } + + if ( default_key_b_ || keyreq_l_) { + int c0_i= *get_staff_info().c0_position_i_; + kit_p_ = new Key_item(c0_i); + kit_p_->read(*this); + announce_element(Staff_elem_info(kit_p_, keyreq_l_)); + } +} + +void +Key_register::pre_move_processing() +{ + if (kit_p_) { + if (default_key_b_) + typeset_breakable_item(0,0,kit_p_); + else + typeset_breakable_item( + new Key_item(*kit_p_), kit_p_, new Key_item(*kit_p_)); + kit_p_ = 0; + } +} + + + +void +Key_register::read_req(Key_change_req * r) +{ + accidental_idx_arr_.set_size(0); + for (int i = 0; i < r->melodic_p_arr_.size(); i ++) { + int n_i=r->melodic_p_arr_[i]->notename_i_; + key_.set(n_i, r->melodic_p_arr_[i]->accidental_i_); + accidental_idx_arr_.push(n_i); + } +} + +void +Key_register::post_move_processing() +{ + keyreq_l_ = 0; + default_key_b_ = false; + kit_p_ = 0; +} diff --git a/lily/key.cc b/lily/key.cc new file mode 100644 index 0000000000..7e23464ccf --- /dev/null +++ b/lily/key.cc @@ -0,0 +1,38 @@ +#include "key.hh" + +const int OCTAVES=14; // ugh.. +const int ZEROOCTAVE=7; + +Key::Key() +{ + accidental_i_arr_.set_size(7); + for (int i= 0; i < 7 ; i++) + accidental_i_arr_[i] = 0; +} + +Local_key::Local_key() +{ + octaves.set_size(OCTAVES); +} + +Key& +Local_key::oct(int i) +{ + return octaves[i+ZEROOCTAVE]; +} + +void +Key::set(int i, int a) +{ + assert(a > -3 && a < 3); + accidental_i_arr_[i]=a; +} + + +void +Local_key::reset(Key k) +{ + for (int i= 0; i < OCTAVES ; i++) + octaves[i] = k; +} + diff --git a/lily/keyword.cc b/lily/keyword.cc new file mode 100644 index 0000000000..14903cfb61 --- /dev/null +++ b/lily/keyword.cc @@ -0,0 +1,79 @@ +/* + keyword.cc -- keywords and identifiers + */ + +#include + +#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 */ +} + diff --git a/lily/leastsquares.cc b/lily/leastsquares.cc new file mode 100644 index 0000000000..cf9ec478e4 --- /dev/null +++ b/lily/leastsquares.cc @@ -0,0 +1,35 @@ +#include "leastsquares.hh" +void +Least_squares::OK() const +{ + assert( input.size() > 1 ); + Real dx = 0.0; + for (int i=1; i < input.size(); i++) + dx += abs (input[i-1].x - input[i].x); + + assert(dx); +} +void +Least_squares::minimise(Real &coef, Real &offset) +{ + OK(); + Real sx = 0.0; + Real sy = 0.0; + Real sqx =0.0; + Real sxy = 0.0; + + for (int i=0; i < input.size();i++) { + Real x=input[i].x; + Real y = input[i].y; + sx += x; + sy += y; + sqx += sqr(x); + sxy += x*y; + } + int N = input.size(); + + + coef = (N * sxy - sx*sy )/(N*sqx - sqr(sx)); + offset = (sy - coef * sx)/N; + +} diff --git a/lily/lexerinit.cc b/lily/lexerinit.cc new file mode 100644 index 0000000000..2eb9ed4e50 --- /dev/null +++ b/lily/lexerinit.cc @@ -0,0 +1,30 @@ +/* + lexerinit.cc -- implement some stuff + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include +#include +#include "proto.hh" +#include "plist.hh" +#include "lexer.hh" +#include "debug.hh" +#include "main.hh" +#include "source-file.hh" +#include "source.hh" + +My_flex_lexer *lexer=0; + +int +yylex() { + return lexer->yylex(); +} + +bool +busy_parsing() +{ + return lexer; +} diff --git a/lily/linespace.cc b/lily/linespace.cc new file mode 100644 index 0000000000..a7bfa1df9b --- /dev/null +++ b/lily/linespace.cc @@ -0,0 +1,288 @@ +#include +#include "linespace.hh" +#include "pcol.hh" +#include "debug.hh" +#include "qlp.hh" +#include "unionfind.hh" +#include "idealspacing.hh" + +const Real COLFUDGE=1e-3; + + +bool +Spacing_problem::contains(const PCol *w) +{ + for (int i=0; i< cols.size(); i++) + if (cols[i].pcol_ == w) + return true; + return false; +} + +int +Spacing_problem::col_id(const PCol *w)const +{ + for (int i=0; i< cols.size(); i++) + if (cols[i].pcol_ == w) + return i; + assert(false); + return -1; +} + +void +Spacing_problem::OK() const +{ +#ifndef NDEBUG + Union_find connected(cols.size()); + Array fixed; + for (int i=0; i < ideals.size(); 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.size(); i++) + if (cols[i].fixed()) + fixed.push(i); + for (int i = 0; i < cols.size(); i++) { + bool c=false; + for (int j =0; j 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 (!b) + return false; + + } + 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.size(); + Vector initsol(dim); + for (int i=0; i < dim; i++) { + if (cols[i].fixed()) { + initsol(i)=cols[i].fixed_position(); + } 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, Real &c) const +{ + quad.fill(0); + lin.fill(0); + c = 0; + for (int j=0; j < ideals.size(); 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; + + c += sqr(i->space); + } +} + +// put the constraints into the LP problem +void +Spacing_problem::make_constraints(Mixed_qp& lp) const +{ + int dim=cols.size(); + for (int j=0; j < dim; j++) { + Colinfo *c=&(cols[j]); + if (c->fixed()) { + lp.add_fixed_var(j,c->fixed_position()); + } + if (j > 0){ + Vector c1(dim); + + c1(j)=1.0 ; + c1(j-1)=-1.0 ; + lp.add_inequality_cons(c1, cols[j-1].minright() + + cols[j].minleft()); + } + } +} + +Array +Spacing_problem::solve() const +{ + print(); + OK(); + assert(check_feasible()); + + /* optimalisatiefunctie */ + Mixed_qp lp(cols.size()); + make_matrices(lp.quad,lp.lin, lp.const_term); + make_constraints(lp); + Vector start=find_initial_solution(); + Vector sol(lp.solve(start)); + if (!check_constraints(sol)) { + WARN << "solution doesn't satisfy constraints.\n" ; + } + + + Array posns(sol); + posns.push(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(col,(fixed)? &fixpos : 0); + cols.push(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.push(i); +} + +void +Spacing_problem::print_ideal(const Idealspacing*id)const +{ +#ifndef NPRINT + int l = col_id(id->left); + int r = col_id(id->right); + + mtor << "between " << l <<","<print(); +#endif +} + +void +Spacing_problem::print() const +{ +#ifndef NPRINT + for (int i=0; i < cols.size(); i++) { + mtor << "col " << i<<' '; + cols[i].print(); + } + for (int i=0; i < ideals.size(); i++) { + print_ideal(ideals[i]); + } +#endif + +} + +/* **************** */ + +void +Colinfo::print() const +{ +#ifndef NPRINT + mtor << "column { "; + if (fixed()) + mtor << "fixed at " << fixed_position()<<", "; + assert(pcol_); + mtor << "[" << minleft() << ", " << minright() << "]"; + mtor <<"}\n"; +#endif +} + +Colinfo::Colinfo(Colinfo const&c) +{ + fixpos = (c.fixpos)?new Real(*c.fixpos):0; + pcol_ = c.pcol_; + width = c.width; +} + +Colinfo::Colinfo(const PCol*col_p, const Real*fixed_r_p ) +{ + fixpos = (fixed_r_p)? new Real(*fixed_r_p) : 0; + pcol_ = col_p; + width = pcol_->width(); +} + +Colinfo::~Colinfo() +{ + delete fixpos; +} + +Colinfo::Colinfo() +{ + pcol_=0; + fixpos = 0; +} +void +Colinfo::operator=(Colinfo const&c ) +{ + delete fixpos; + fixpos = (c.fixpos)?new Real(*c.fixpos):0; + pcol_ = c.pcol_; + width = c.width; +} diff --git a/lily/local-key-item.cc b/lily/local-key-item.cc new file mode 100644 index 0000000000..425982120c --- /dev/null +++ b/lily/local-key-item.cc @@ -0,0 +1,93 @@ +#include "local-key-item.hh" +#include "molecule.hh" +#include "scalar.hh" +#include "lookup.hh" +#include "paper-def.hh" +#include "musicalrequest.hh" +#include "notehead.hh" +#include "misc.hh" + + + +Local_key_item::Local_key_item(int i) +{ + c0_position = i; +} + +void +Local_key_item::add(Item*head_l) +{ + support_items_.push(head_l); + add_dependency(head_l); +} + +void +Local_key_item::add(Melodic_req*m_l) +{ + add(m_l->octave_i_, m_l->notename_i_, m_l->accidental_i_); +} +void +Local_key_item::add (int o, int p , int a) +{ + Local_acc l; + l.octave = o; + l.name = p; + l.acc = a; + accs.push(l); +} + +void +Local_key_item::do_pre_processing() +{ + accs.sort(Local_acc::compare); +} + +Molecule* +Local_key_item::brew_molecule_p()const +{ + Molecule* output = new Molecule; + Molecule*octmol = 0; + int lastoct = -100; + for (int i = 0; i < accs.size(); i++) { + // do one octave + if (accs[i].octave != lastoct) { + if (octmol){ + Real dy =lastoct*7*paper()->internote(); + octmol->translate(Offset(0, dy)); + output->add(*octmol); + delete octmol; + } + octmol= new Molecule; + } + lastoct = accs[i].octave; + Symbol s =paper()->lookup_p_->accidental(accs[i].acc); + Atom a(s); + Real dy = (accs[i].name + c0_position) * paper()->internote(); + a.translate(Offset(0,dy)); + + octmol->add_right(a); + } + + if (octmol){ + Real dy =lastoct*7*paper()->internote(); + octmol->translate(Offset(0, dy)); + output->add(*octmol); + delete octmol; + } + + Interval head_width=itemlist_width(support_items_); + output->translate(Offset(-output->extent().x.right + head_width.left ,0)); + + return output; +} + +int +Local_acc::compare(Local_acc&a, Local_acc&b) +{ + if (a.octave - b.octave) + return a.octave - b.octave; + if (a.name - b.name) + return a.name - b.name; + + assert(false); +}; diff --git a/lily/lookup.cc b/lily/lookup.cc new file mode 100644 index 0000000000..ffd668e75d --- /dev/null +++ b/lily/lookup.cc @@ -0,0 +1,222 @@ +/* + lookup.cc -- implement simple Lookup methods. + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "lookup.hh" +#include "debug.hh" +#include "symtable.hh" +#include "dimen.hh" +#include "tex.hh" +#include "scalar.hh" + +Lookup::Lookup() +{ + texsetting = "\\unknowntexsetting"; + symtables_ = new Symtables; +} + +Lookup::Lookup(Lookup const &s) +{ + texsetting = s.texsetting; + symtables_ = new Symtables(*s.symtables_); +} +Lookup::~Lookup() +{ + delete symtables_; +} + +void +Lookup::add(String s, Symtable*p) +{ + symtables_->add(s, p); +} + +void +Lookup::print()const +{ + mtor << "Lookup: " << texsetting << " {\n"; + symtables_->print(); + mtor << "}\n"; +} + +Symbol +Lookup::text(String style, String text, int dir) +{ + Array a; + + a.push(text); + Symbol tsym = (*symtables_)("style")->lookup(style); + a[0] = substitute_args(tsym.tex,a); + + Symbol s = (*symtables_)("align")->lookup(dir); + s.tex = substitute_args(s.tex,a); + s.dim.y = tsym.dim.y; + return s; +} + + +Real +Lookup::internote() +{ + return ball(4).dim.y.length()/2; +} + +Symbol +Lookup::ball(int j) +{ + if (j > 4) + j = 4; + + Symtable * st = (*symtables_)("balls"); + return st->lookup(String(j)); +} + +Symbol +Lookup::rest(int j) +{ + return (*symtables_)("rests")->lookup(String(j)); +} + +Symbol +Lookup::fill(Box b) +{ + Symbol s( (*symtables_)("param")->lookup("fill")); + s.dim = b; + return s; +} + +Symbol +Lookup::accidental(int j) +{ + return (*symtables_)("accidentals")->lookup(String(j)); +} + + +Symbol +Lookup::bar(String s) +{ + return (*symtables_)("bars")->lookup(s); +} + +Symbol +Lookup::script(String s) +{ + return (*symtables_)("scripts")->lookup(s); +} + +Symbol +Lookup::clef(String s) +{ + return (*symtables_)("clefs")->lookup(s); +} + +Symbol +Lookup::dots(int j) +{ + if (j>3) + error("max 3 dots"); // todo + return (*symtables_)("dots")->lookup(j); +} + +Symbol +Lookup::flag(int j) +{ + return (*symtables_)("flags")->lookup(j); +} + +Symbol +Lookup::streepjes(int i) +{ + assert(i); + + int arg; + String idx; + + if (i < 0) { + idx = "botlines"; + arg = -i; + } else { + arg = i; + idx = "toplines"; + } + Symbol ret = (*symtables_)("streepjes")->lookup(idx); + + Array a; + a.push(arg); + ret.tex = substitute_args(ret.tex, a); + + return ret; +} + +Symbol +Lookup::hairpin(Real &wid, bool decresc) +{ + int idx = int(rint(wid / 6 PT)); + if(!idx) idx ++; + wid = idx*6 PT; + String idxstr = (decresc)? "decrescendosym" : "crescendosym"; + Symbol ret=(*symtables_)("param")->lookup(idxstr); + + Array a; + a.push(idx); + ret.tex = substitute_args(ret.tex, a); + ret.dim.x = Interval(0,wid); + return ret; +} + +Symbol +Lookup::linestaff(int lines, Real wid) +{ + Symbol s; + s.dim.x = Interval(0,wid); + Real dy = (lines >0) ? (lines-1)*internote()*2 : 0; + s.dim.y = Interval(0,dy); + + Array a; + a.push(lines); + a.push(print_dimen(wid)); + + s.tex = (*symtables_)("param")->lookup("linestaf").tex; + s.tex = substitute_args(s.tex, a); + + return s; +} + + +Symbol +Lookup::meter(Array a) +{ + Symbol s; + s.dim.x = Interval( 0 PT, 10 PT); + s.dim.y = Interval(0, 20 PT); // todo + String src = (*symtables_)("param")->lookup("meter").tex; + s.tex = substitute_args(src,a); + return s; +} + + +Symbol +Lookup::stem(Real y1,Real y2) +{ + if (y1 > y2) { + Real t = y1; + y1 = y2; + y2 = t; + } + Symbol s; + + s.dim.x = Interval(0,0); + s.dim.y = Interval(y1,y2); + + Array a; + a.push(print_dimen(y1)); + a.push(print_dimen(y2)); + + String src = (*symtables_)("param")->lookup("stem").tex; + s.tex = substitute_args(src,a); + return s; +} diff --git a/lily/meter-reg.cc b/lily/meter-reg.cc new file mode 100644 index 0000000000..a27737c076 --- /dev/null +++ b/lily/meter-reg.cc @@ -0,0 +1,64 @@ +/* + meter-reg.cc -- implement Meter_register + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "meter-reg.hh" +#include "meter.hh" +#include "commandrequest.hh" + +Meter_register::Meter_register() + +{ + post_move_processing(); +} + +bool +Meter_register::try_request(Request*r_l) +{ + Command_req* creq_l= r_l->command(); + if (!creq_l || !creq_l->meterchange()) + return false; + + assert(!meter_req_l_); + meter_req_l_ = r_l->command()->meterchange(); + + return true; +} + +void +Meter_register::process_requests() +{ + if (meter_req_l_ ) { + Array args; + args.push(meter_req_l_->beats_i_); + args.push(meter_req_l_->one_beat_i_); + + meter_p_ = new Meter(args); + } + + if (meter_p_) + announce_element(Staff_elem_info(meter_p_, meter_req_l_) ); +} + +void +Meter_register::pre_move_processing() +{ + if (meter_p_) { + Meter * post_p =new Meter(*meter_p_); + Meter * pre_p =new Meter(*meter_p_); + + typeset_breakable_item(pre_p, meter_p_, post_p); + meter_p_ =0; + } +} + +void +Meter_register::post_move_processing() +{ + meter_req_l_ = 0; + meter_p_ =0; +} diff --git a/lily/meter.cc b/lily/meter.cc new file mode 100644 index 0000000000..94f6b6c5e9 --- /dev/null +++ b/lily/meter.cc @@ -0,0 +1,18 @@ +#include "scalar.hh" +#include "molecule.hh" +#include "meter.hh" +#include "paper-def.hh" +#include "lookup.hh" + +Meter::Meter(Arraya) + :args(a) +{ +} + +Molecule* +Meter::brew_molecule_p()const +{ + Symbol s = paper()->lookup_p_->meter(args); + return new Molecule(Atom(s)); +} + diff --git a/lily/midi-walker.cc b/lily/midi-walker.cc new file mode 100644 index 0000000000..801ba32e12 --- /dev/null +++ b/lily/midi-walker.cc @@ -0,0 +1,71 @@ +/* + midi-walker.cc -- implement Midi_walker + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys , Jan Nieuwenhuizen +*/ + +#include "musicalrequest.hh" +#include "pscore.hh" +#include "staff.hh" +#include "midi-walker.hh" +#include "midi-item.hh" +#include "midi-stream.hh" +#include "debug.hh" +#include "staff-column.hh" + +Midi_walker::Midi_walker(Staff *st_l, Midi_track* track_l) + : PCursor(st_l->cols_) +{ + track_l_ = track_l; + last_moment_= 0; +} + +/** + output notestop events for all notes which end before #max_moment# + */ +void +Midi_walker::do_stop_notes(Moment max_moment) +{ + while (stop_notes.size() && stop_notes.front_idx() <= max_moment) { + Moment stop_moment = stop_notes.front_idx(); + Melodic_req * req_l = stop_notes.get(); + + Midi_note note(req_l, track_l_->number_i_, false); + output_event(note, stop_moment); + } +} +/** advance the track to #now#, output the item, and adjust current + "moment". */ +void +Midi_walker::output_event(Midi_item &i, Moment now) +{ + Moment delta_t = now - last_moment_ ; + last_moment_ += delta_t; + track_l_->add(delta_t, &i ); +} + +void +Midi_walker::process_requests() +{ + do_stop_notes(ptr()->when()); + for ( int i = 0; i < ptr()->musicalreq_l_arr_.size(); i++ ) { + + Rhythmic_req *n = ptr()->musicalreq_l_arr_[i]->rhythmic(); + if ( !n) + continue; + Note_req * note_l = n->note(); + if (!note_l) + continue; + + Midi_note note(note_l, track_l_->number_i_, true); + stop_notes.enter(note_l, n->duration() + ptr()->when() ); + output_event(note, ptr()->when()); + } +} + +Midi_walker::~Midi_walker() +{ + do_stop_notes( last_moment_ + Moment(10,1)); // ugh +} diff --git a/lily/misc.cc b/lily/misc.cc new file mode 100644 index 0000000000..093af7f0d4 --- /dev/null +++ b/lily/misc.cc @@ -0,0 +1,53 @@ +#include + +#include "item.hh" +#include "misc.hh" +#include "glob.hh" +#include "moment.hh" + + +// depreciated, see struct Duration* +Moment +wholes(int dur, int dots) +{ + if (!dur) + return 0; + + Moment f = Rational(1)/Moment(dur); + Moment delta = f; + + while (dots--) { + delta /= 2.0; + f += delta; + } + return f; +} +int +intlog2(int d) { + int i=0; + while (!(d&1)) { + d/= 2; + i++; + } + assert(!(d/2)); + return i; +} + +double +log_2(double x) { + return log(x) /log(2.0); +} + +Interval +itemlist_width(const Array &its) +{ + Interval iv ; + iv.set_empty(); + + for (int j =0; j < its.size(); j++){ + iv.unite (its[j]->width()); + + } + return iv; +} + diff --git a/lily/molecule.cc b/lily/molecule.cc new file mode 100644 index 0000000000..c52fdc7b32 --- /dev/null +++ b/lily/molecule.cc @@ -0,0 +1,146 @@ +#include "varray.hh" +#include "interval.hh" +#include "dimen.hh" +#include "string.hh" +#include "molecule.hh" +#include "symbol.hh" +#include "debug.hh" +#include "tex.hh" + +void +Atom::print() const +{ + mtor << "texstring: " < a; + a.push(print_dimen(off.y)); + a.push(print_dimen(off.x)); + a.push(sym.tex); + return substitute_args(s, a); +} + +/* *************** */ + +String +Molecule::TeXstring() const +{ + String s; + for(iter_top(ats,c); c.ok(); c++) + s+=c->TeXstring(); + return s; +} + +Box +Molecule::extent() const +{ + Box b; + for(iter_top(ats,c); c.ok(); c++) + b.unite(c->extent()); + return b; +} + +void +Molecule::translate(Offset o) +{ + for (iter_top(ats,c); c.ok(); c++) + c->translate(o); +} + +void +Molecule::add(const Molecule &m) +{ + for (iter_top(m.ats,c); c.ok(); c++) { + add(**c); + } +} + +void +Molecule::add_right(const Molecule &m) +{ + if (!ats.size()) { + add(m); + return; + } + Real xof=extent().x.right - m.extent().x.left; + Molecule toadd(m); + toadd.translate(Offset(xof, 0.0)); + add(toadd); +} + +void +Molecule::add_left(const Molecule &m) +{ + if (!ats.size()) { + add(m); + return; + } + Real xof=extent().x.left - m.extent().x.right; + Molecule toadd(m); + toadd.translate(Offset(xof, 0.0)); + add(toadd); +} + + +void +Molecule::add_top(const Molecule &m) +{ + if (!ats.size()) { + add(m); + return; + } + Real yof=extent().y.right - m.extent().y.left; + Molecule toadd(m); + toadd.translate(Offset(0,yof)); + add(toadd); +} + +void +Molecule::add_bottom(const Molecule &m) +{ + if (!ats.size()) { + add(m); + return; + } + Real yof=extent().y.left- m.extent().y.right; + Molecule toadd(m); + toadd.translate(Offset(0,yof)); + add(toadd); +} + +void +Molecule::operator = (const Molecule&) +{ + assert(false); +} + +Molecule::Molecule(const Molecule&s) +{ + add(s); +} + +void +Molecule::print() const +{ + for (iter_top(ats,c); c.ok(); c++) + c->print(); +} diff --git a/lily/mylexer.cc b/lily/mylexer.cc new file mode 100644 index 0000000000..7da6dddec8 --- /dev/null +++ b/lily/mylexer.cc @@ -0,0 +1,196 @@ +#include + +#include "interval.hh" +#include "identparent.hh" +#include "assoc-iter.hh" +#include "lexer.hh" +#include "input-file.hh" +#include "parser.hh" +#include "keyword.hh" +#include "assoc.hh" +#include "lexer.hh" +#include "debug.hh" +#include "notename.hh" +#include "source-file.hh" +#include "parseconstruct.hh" + +static Keyword_ent the_key_tab[]={ + "bar", BAR, + "cadenza", CADENZA, + "clef", CLEF, + "cm", CM_T, + "command", COMMAND, + "commands", COMMANDS, + "duration", DURATIONCOMMAND, + "geometric", GEOMETRIC, + "goto", GOTO, + "in", IN_T, + "key", KEY, + "meter", METER, + "midi", MIDI, + "mm", MM_T, + "multivoice", MULTIVOICE, + "octave", OCTAVECOMMAND, + "output", OUTPUT, + "partial", PARTIAL, + "paper", PAPER, + "plet", PLET, + "pt", PT_T, + "score", SCORE, + "script", SCRIPT, + "skip", SKIP, + "staff", STAFF, + "start", START_T, + "stem", STEM, + "table", TABLE, + "symboltables", SYMBOLTABLES, + "notenames", NOTENAMES, + "tempo", TEMPO, + "texid", TEXID, + "textstyle", TEXTSTYLE, + "unitspace", UNITSPACE, + "voice", VOICE, + "voices", VOICES, + "width", WIDTH, + "music", MUSIC, + "grouping", GROUPING, + 0,0 +}; + +int +My_flex_lexer::ret_notename(int *p, String text, int octave_mod) +{ + text = text.lower_str(); + char const* ch_c_l = here_ch_c_l(); + if ( ch_c_l ) { + ch_c_l--; + while ( ( *ch_c_l == ' ' ) + || ( *ch_c_l == '\t' ) || ( *ch_c_l == '\n' ) ) + ch_c_l--; + ch_c_l++; + } + + lookup_notename(p[0], p[1], text); + p[2] = octave_mod; + mtor << "notename: "<< text <; + defaulttab = 0; + errorlevel_i_ = 0; +} + +int +My_flex_lexer::lookup_keyword(String s) +{ + return keytable->lookup(s); +} + +Identifier* +My_flex_lexer::lookup_identifier(String s) +{ + if (!the_id_tab->elt_query(s)) + return 0; + + return (*the_id_tab)[s]; +} + +char const* +My_flex_lexer::here_ch_c_l() +{ + return include_stack.top()->sourcefile_l_->ch_c_l() + yyin->tellg(); +} + +void +My_flex_lexer::add_identifier(Identifier*i) +{ + delete lookup_identifier(i->name); + (*the_id_tab)[i->name] = i; +} + +My_flex_lexer::~My_flex_lexer() +{ + delete keytable; + delete defaulttab; + for (Assoc_iter ai(*the_id_tab); ai.ok(); ai++) { + mtor << "deleting: " << ai.key()<<'\n'; + delete ai.val(); + } + delete the_id_tab; +} +void +My_flex_lexer::print_declarations()const +{ + for (Assoc_iter ai(*the_id_tab); ai.ok(); ai++) { + ai.val()->print(); + } +} + +String +My_flex_lexer::spot()const +{ + return include_stack.top()->name + ": " + String( lineno() ); +} + +void +My_flex_lexer::LexerError(const char *s) +{ + if (lexer->include_stack.empty()) { + *mlog << "error at EOF" << s << '\n'; + } else { + char const* ch_c_l = here_ch_c_l(); + if ( ch_c_l ) { + ch_c_l--; + while ( ( *ch_c_l == ' ' ) || ( *ch_c_l == '\t' ) || ( *ch_c_l == '\n' ) ) + ch_c_l--; + ch_c_l++; + } + errorlevel_i_ |= 1; + error( s, ch_c_l ); + } +} + +// set the new input to s, remember old file. +void +My_flex_lexer::new_input(String s) +{ + if (!include_stack.empty()) { + include_stack.top()->line = lineno(); + // should this be saved at all? + include_stack.top()->defined_ch_c_l_ = defined_ch_c_l; + } + + Input_file *newin = new Input_file(s); + include_stack.push(newin); + switch_streams(newin->is); + + yylineno = 1; +} + +// pop the inputstack. +bool +My_flex_lexer::close_input() +{ + Input_file *old = include_stack.pop(); + bool ok = true; + if (include_stack.empty()) { + ok = false; + } else { + Input_file *i = include_stack.top(); + switch_streams(i->is); + yylineno = i->line; + defined_ch_c_l = i->defined_ch_c_l_; + } + delete old; + return ok; +} diff --git a/lily/note.cc b/lily/note.cc new file mode 100644 index 0000000000..496d892e5b --- /dev/null +++ b/lily/note.cc @@ -0,0 +1,321 @@ +/* + could use cleanup + */ +#include +#include "lexer.hh" +#include "string.hh" +#include "real.hh" +#include "debug.hh" +#include "musicalrequest.hh" +#include "commandrequest.hh" +#include "voice.hh" +#include "notename.hh" +#include "identparent.hh" +#include "varray.hh" +#include "text-def.hh" +#include "parseconstruct.hh" +#include "input-music.hh" +#include "voice-element.hh" + +int default_duration = 4, default_dots=0, default_octave=0; +int default_plet_type = 1, default_plet_dur = 1; +String textstyle="roman"; // in lexer? + +bool last_duration_mode = false; + +void +set_duration_mode(String s) +{ + s = s.upper_str(); + last_duration_mode = (s== "LAST"); +} + +void +last_duration(int n) +{ + if (last_duration_mode) + default_duration = n; +} + +/* triplet is '2/3' */ +void +set_plet(int num,int den) +{ + assert(num >0&& den>0); + default_plet_dur = num; + default_plet_type = den; +} + +Text_def* +get_text(String s) return t; +{ + t= new Text_def; + t->text_str_= s; + t->style_str_ = textstyle; + t->defined_ch_c_l_ = defined_ch_c_l; + return t; +} + +void +set_text_style(String s) +{ + textstyle = s; +} + +void +parse_octave (const char *a, int &j, int &oct) +{ + while (1) + { + if (a[j] == '\'') + oct ++; + else if (a[j] == '`') + oct --; + else + break; + j++; + } +} + +void +parse_pitch( const char *a, Melodic_req* mel_l) +{ + int j=0; + + // octave + mel_l->octave_i_ = default_octave; + parse_octave(a,j,mel_l->octave_i_); + + // accidental + mel_l->forceacc_b_ = false; + + if (a[j] == '!'){ + mel_l->forceacc_b_ = true; + j++; + } +} + +Voice_element * +get_note_element(String pitch, int * notename, int * duration ) +{ + Voice_element*v = new Voice_element; + v->defined_ch_c_l_ = defined_ch_c_l; + + + int dur = duration[0]; + int dots = duration[1]; + + if (dur >= 2) { + Stem_req * stem_req_p = new Stem_req(dur,dots); + stem_req_p->plet_factor = Moment(default_plet_dur, default_plet_type); + stem_req_p->defined_ch_c_l_ = defined_ch_c_l; + v->add(stem_req_p); + } + + if ( !defined_ch_c_l ) + defined_ch_c_l = lexer->here_ch_c_l(); + + Note_req * rq = new Note_req; + rq->notename_i_ =notename[0]; + rq->accidental_i_ = notename[1]; + parse_pitch(pitch, rq); + rq->octave_i_ += notename[2]; + + rq->balltype = dur; + rq->dots = dots; + rq->plet_factor = Moment(default_plet_dur, default_plet_type); + rq->defined_ch_c_l_ = defined_ch_c_l; + + v->add(rq); + + return v; +} + +Voice_element* +get_word_element(Text_def* tdef_p, int* duration) +{ + Voice_element* velt_p = new Voice_element; + velt_p->defined_ch_c_l_ = defined_ch_c_l; + + int dur = duration[0]; + int dots=duration[1]; + + tdef_p->defined_ch_c_l_ = defined_ch_c_l; + + Lyric_req* lreq_p = new Lyric_req(tdef_p); + + lreq_p->balltype = dur; + lreq_p->dots = dots; + lreq_p->plet_factor = Moment(default_plet_dur, default_plet_type); + lreq_p->print(); + lreq_p->defined_ch_c_l_ = defined_ch_c_l; + + velt_p->add(lreq_p); + + return velt_p; +} + +Voice_element * +get_rest_element(String, int * duration ) +{ + Voice_element* velt_p = new Voice_element; + velt_p->defined_ch_c_l_ = defined_ch_c_l; + + Rest_req * rest_req_p = new Rest_req; + rest_req_p->plet_factor = Moment(default_plet_dur, default_plet_type); + rest_req_p->balltype = duration[0]; + rest_req_p->dots = duration[1]; + rest_req_p->print(); + rest_req_p->defined_ch_c_l_ = defined_ch_c_l; + + velt_p->add(rest_req_p); + + return velt_p; +} + +void +get_default_duration(int *p) +{ + *p++ = default_duration; + *p = default_dots; +} + +void +set_default_duration(int *p) +{ + default_duration = *p++; + default_dots = *p++; +} + + +void +set_default_octave(String d) +{ + int i=0; + default_octave=0; + parse_octave(d, i, default_octave); +} + +Request* +get_plet_request( char c, int dur_i, int type_i ) +{ + Plet_req* plet_req_p = new Plet_req; + plet_req_p->dur_i_ = dur_i; + plet_req_p->type_i_ = type_i; + plet_req_p->type_c_ = c; + return plet_req_p; +} + +Request* +get_request(char c) +{ + Request* req_p=0; + switch (c) { + case '|': + req_p = new Barcheck_req; + break; + + case '[': + case ']': + { + Beam_req*b = new Beam_req; + if (default_plet_type != 1) + b->nplet = default_plet_type; + req_p = b; + } + break; + + + case ')': + case '(': + req_p = new Slur_req; + break; + default: + assert(false); + break; + } + + switch (c) { + case '(': + case '[': + req_p->span()->spantype = Span_req::START; + break; + case ')': + case ']': + req_p->span()->spantype = Span_req::STOP; + break; + + default: + break; + } + + req_p->defined_ch_c_l_ = req_defined_ch_c_l; + return req_p; +} + +void +add_requests(Voice_element *v, Array &req) +{ + for (int i = 0; i < req.size(); i++) { + v->add(req[i]); + } + req.set_size(0); +} + +Script_def* +get_scriptdef(char c) +{ + String s; + switch (c) { + case '^' : s = "marcato"; + break; + case '+' : s = "stopped"; + break; + case '-' : s = "tenuto"; + break; + case '|': s = "staccatissimo"; + break; + case 'o' : s = ""; + break; + case '>' : s = "accent"; + break; + case 'v' : s = ""; + break; + case '.' : s = "staccato"; + break; + } + return lexer->lookup_identifier(s)->script(1); +} + +Request* +get_script_req(int d , Script_def*def) +{ + Script_req* script_req_p = new Script_req(d, def); + return script_req_p; +} + +Request* +get_text_req(int d , Text_def*def) +{ + Text_req* text_req_p = new Text_req(d, def); + return text_req_p; +} + +Request* +get_stemdir_req(int d) +{ + Group_feature_req * gfreq_p = new Group_feature_req; + gfreq_p->stemdir_i_ =d; + return gfreq_p; +} + +Request* +get_grouping_req(Array i_arr) +{ + Measure_grouping_req * mr_p = new Measure_grouping_req; + for (int i=0; i beat_i_arr_.push(i_arr[i++]); + mr_p->elt_length_arr_.push(Moment(1, i_arr[i++])); + } + return mr_p; +} diff --git a/lily/notehead.cc b/lily/notehead.cc new file mode 100644 index 0000000000..722b231e68 --- /dev/null +++ b/lily/notehead.cc @@ -0,0 +1,77 @@ +#include "misc.hh" +#include "notehead.hh" +#include "dimen.hh" +#include "debug.hh" +#include "paper-def.hh" +#include "lookup.hh" +#include "molecule.hh" +#include "musicalrequest.hh" + + + +Notehead::Notehead(int ss) +{ + x_dir = 0; + staff_size=ss; + position = 0; + balltype = 0; + dots = 0; + extremal = 0; +} + +void +Notehead::set_rhythmic(Rhythmic_req*r_req_l) +{ + balltype = r_req_l->balltype; + dots = r_req_l->dots; +} + +void +Notehead::do_print()const +{ +#ifndef NPRINT + mtor << "balltype "<< balltype << ", position = "<< position + << "dots " << dots; +#endif +} + + +int +Notehead::compare(Notehead *const &a, Notehead * const &b) +{ + return a->position - b->position; +} + +Molecule* +Notehead::brew_molecule_p() const return out; +{ + Paper_def *p = paper(); + + Real dy = p->internote(); + Symbol s = p->lookup_p_->ball(balltype); + + out = new Molecule(Atom(s)); + if (dots) { + Symbol d = p->lookup_p_->dots(dots); + Molecule dm; + dm.add(Atom(d)); + if (!(position %2)) + dm.translate(Offset(0,dy)); + out->add_right(dm); + } + out->translate(Offset(x_dir * p->note_width(),0)); + bool streepjes = (position<-1)||(position > staff_size+1); + if (streepjes) { + int dir = sign(position); + int s =(position<-1) ? -((-position)/2): (position-staff_size)/2; + Symbol str = p->lookup_p_->streepjes(s); + Molecule sm; + sm.add(Atom(str)); + if (position % 2) + sm.translate(Offset(0,-dy* dir)); + out->add(sm); + } + + out->translate(Offset(0,dy*position)); +} + diff --git a/lily/notename.cc b/lily/notename.cc new file mode 100644 index 0000000000..e6d62644b2 --- /dev/null +++ b/lily/notename.cc @@ -0,0 +1,47 @@ +#include "glob.hh" +#include "string.hh" +#include "notename.hh" +#include "lexer.hh" +#include "identifier.hh" + + + +void +Notename_tab::lookup(int &large, int &small, String s) +{ + large = -1; + small = 0; + + for (int i =0; i < 7*5; i++) + if (s == notetab[i]) + { + large = i /5; + small = i %5 - 2; + return; + } +} + + +void +Notename_tab::set(int l, int s, String n) +{ + assert(l < 8 && s <= 2 && s >= -2 && l >=0); + notetab[l * 5 + s +2] = n; +} +/* *************** */ +void +My_flex_lexer::set(Notename_tab *n) +{ + delete defaulttab; + defaulttab = n; +} + +void +My_flex_lexer::lookup_notename(int &large, int &small, String s) +{ + if (!defaulttab) + set(lookup_identifier("default_table")-> + notename_tab(true)); + + defaulttab->lookup(large, small, s); +} diff --git a/lily/paper-def.cc b/lily/paper-def.cc new file mode 100644 index 0000000000..b49a53fc8e --- /dev/null +++ b/lily/paper-def.cc @@ -0,0 +1,91 @@ +#include +#include "misc.hh" +#include "paper-def.hh" +#include "debug.hh" +#include "lookup.hh" +#include "dimen.hh" + + + +// golden ratio +const Real PHI = (1+sqrt(5))/2; + +// see Roelofs, p. 57 +Real +Paper_def::duration_to_dist(Moment d) +{ + if (!d) + return 0; + + return whole_width * pow(geometric_, log_2(d)); +} + +Real +Paper_def::rule_thickness()const +{ + return 0.4 PT; +} + +Paper_def::Paper_def(Lookup *l) +{ + lookup_p_ = l; + linewidth = 15 *CM_TO_PT; // in cm for now + whole_width = 8 * note_width(); + geometric_ = sqrt(2); + outfile = "lelie.out"; +} + +Paper_def::~Paper_def() +{ + delete lookup_p_; +} +Paper_def::Paper_def(Paper_def const&s) +{ + lookup_p_ = new Lookup(*s.lookup_p_); + geometric_ = s.geometric_; + whole_width = s.whole_width; + outfile = s.outfile; + linewidth = s.linewidth; +} + +void +Paper_def::set(Lookup*l) +{ + assert(l != lookup_p_); + delete lookup_p_; + lookup_p_ = l; +} + +Real +Paper_def::interline() const +{ + return lookup_p_->ball(4).dim.y.length(); +} + +Real +Paper_def::internote() const +{ + return lookup_p_->internote(); +} +Real +Paper_def::note_width()const +{ + return lookup_p_->ball(4).dim.x.length( ); +} +Real +Paper_def::standard_height() const +{ + return 20 PT; +} + +void +Paper_def::print() const +{ +#ifndef NPRINT + mtor << "Paper {width: " << print_dimen(linewidth); + mtor << "whole: " << print_dimen(whole_width); + mtor << "out: " <print(); + mtor << "}\n"; +#endif +} diff --git a/lily/pcol.cc b/lily/pcol.cc new file mode 100644 index 0000000000..4f1b65dcd7 --- /dev/null +++ b/lily/pcol.cc @@ -0,0 +1,121 @@ +#include "pcol.hh" +#include "pscore.hh" +#include "pstaff.hh" +#include "debug.hh" + +Interval +PCol::width() const +{ + Interval w; + + for (iter_top(its,i); i.ok(); i++) + w.unite(i->width()); + if (w.empty()) + w.unite(Interval(0,0)); + return w; +} + +int +PCol::rank() const +{ + if(!pscore_l_) + return -1; + PCursor me=pscore_l_->find_col( (PCol*)this); + if (!me.ok()) + return -1; + PCursor bot(pscore_l_->cols.top()); + return me - bot; +} + +void +PCol::print() const +{ +#ifndef NPRINT + mtor << "PCol {"; + + if (rank() >= 0) + mtor << "rank: " << rank() << '\n'; + + mtor << "# symbols: " << its.size() ; + if (breakable_b()){ + mtor << "\npre,post: "; + prebreak_p_->print(); + postbreak_p_->print(); + } else if (daddy_l_) { + mtor<<'\n' << ((this == daddy_l_->prebreak_p_) ? + "prebreak" : "postbreak"); + mtor << '\n'; + } + mtor << "extent: " << width().str() << "\n"; + mtor << "}\n"; +#endif +} + +int +PCol::compare(const PCol &c1, const PCol &c2) +{ + PScore*ps_l = c1.pscore_l_; + PCursor ac(ps_l->find_col(&c1)); + PCursor bc(ps_l->find_col(&c2)); + assert(ac.ok() && bc.ok()); + return ac - bc; +} + +void +PCol::OK() const +{ +#ifndef NDEBUG + if (prebreak_p_ || postbreak_p_ ) { + assert(prebreak_p_&&postbreak_p_); + assert(prebreak_p_->daddy_l_ == this); + assert(postbreak_p_->daddy_l_ == this); + } +#endif +} + +void +PCol::set_breakable() +{ + if (breakable_b()) + return; + + prebreak_p_ = new PCol(this); + postbreak_p_ = new PCol(this); + prebreak_p_->pscore_l_ = pscore_l_; + postbreak_p_->pscore_l_ = pscore_l_; +} + +bool +PCol::breakable_b() const +{ + return prebreak_p_||postbreak_p_; +} + +PCol::PCol(PCol *parent) +{ + daddy_l_ = parent; + prebreak_p_=0; + postbreak_p_=0; + line_l_=0; + hpos = -1.0; + pscore_l_ = 0; +} + +PCol::~PCol() +{ + delete prebreak_p_; + delete postbreak_p_; +} + +void +PCol::add( Item *i) +{ + its.bottom().add(i); + i->pcol_l_ = this; +} + +bool +PCol::used_b()const +{ + return breakable_b() || its.size(); +} diff --git a/lily/pscore.cc b/lily/pscore.cc new file mode 100644 index 0000000000..1f4a8b68c8 --- /dev/null +++ b/lily/pscore.cc @@ -0,0 +1,257 @@ +#include "idealspacing.hh" +#include "debug.hh" +#include "lookup.hh" +#include "spanner.hh" +#include "paper-def.hh" +#include "molecule.hh" +#include "dimen.hh" +#include "scoreline.hh" +#include "pscore.hh" +#include "tex-stream.hh" +#include "item.hh" +#include "break.hh" + +Idealspacing* +PScore::get_spacing(PCol*l, PCol*r) +{ + assert(l!=r); + + Idealspacing*i_p =new Idealspacing(l,r); + suz.bottom().add(i_p); + + return i_p; +} + + +void +PScore::clean_cols() +{ + for (iter_top(cols,c); c.ok(); ) + if (!c->used_b()) { + delete c.remove_p(); + } else + c++; +} + + +void +PScore::add(PStaff *s) +{ + assert(s->pscore_l_ == this); + staffs.bottom().add(s); +} + + +void +PScore::do_connect(PCol *c1, PCol *c2, Real d, Real h) +{ + if (!c1 || !c2 ) + return; + Idealspacing*s_l=get_spacing(c1,c2); + + + s_l->hooke = h; + s_l->space =d; +} + +void +PScore::connect(PCol* c1, PCol *c2, Real d, Real h) +{ + do_connect(c1,c2,d,h); + do_connect(c1->postbreak_p_, c2,d,h); + do_connect(c1, c2->prebreak_p_,d,h); + do_connect(c1->postbreak_p_, c2->prebreak_p_,d,h); +} + +void +PScore::typeset_item(Item *i, PCol *c, PStaff *s, int breakstat) +{ + assert(c && i && s); + + if (breakstat == 0) { + typeset_item(i, c->prebreak_p_, s); + return; + } + + if (breakstat == 2) { + typeset_item(i, c->postbreak_p_, s); + return; + } + + + its.bottom().add(i); + s->add(i); + c->add(i); + + /* first do this, because i->width() may follow the 0-pointer */ + i->add_processing(); +} + +void +PScore::typeset_spanner(Spanner*span_p, PStaff*ps) +{ + span_p->pstaff_l_ = ps; + spanners.bottom().add(span_p); + ps->spans.bottom().add(span_p); + + // do not init start/stop fields. These are for broken spans only. + span_p->add_processing(); +} + + +void +PScore::add(PCol *p) +{ + p->pscore_l_ = this; + if (p->breakable_b()){ + p->prebreak_p_->pscore_l_ = this; + p->postbreak_p_->pscore_l_ = this; + } + cols.bottom().add(p); +} + +PScore::PScore( Paper_def*p) +{ + paper_l_ = p; +} + +void +PScore::output(Tex_stream &ts) +{ + int l=1; + + ts << "\n "<< paper_l_->lookup_p_->texsetting << "%(Tex id)\n"; + for (iter_top(lines,lic); lic.ok(); lic++) { + ts << "% line of score no. " << l++ <<"\n"; + ts << lic->TeXstring(); + if ((lic+1).ok()) + ts << "\\interscoreline\n"; + } +} + + +Array +PScore::select_items(PStaff*ps, PCol*pc) +{ + Array ret; + assert(ps && pc); + for (iter_top(pc->its,i); i.ok(); i++){ + if (i->pstaff_l_ == ps) + ret.push((Item*)(const Item*)i); + } + return ret; +} + +void +PScore::OK()const +{ +#ifdef NDEBUG + for (iter_top(cols,cc); cc.ok(); cc++) + cc->OK(); + for (iter_top(suz,i); i.ok(); i++) + i->OK(); +#endif +} + +void +PScore::print() const +{ +#ifndef NPRINT + mtor << "PScore { "; + paper_l_->print(); + mtor << "\ncolumns: "; + for (iter_top(cols,cc); cc.ok(); cc++) + cc->print(); + + mtor << "\nideals: "; + for (iter_top(suz,i); i.ok(); i++) + i->print(); + mtor << "}\n"; +#endif +} + +void +PScore::preprocess() +{ + for (iter_top(spanners,i); i.ok(); i++) { + i->pre_processing(); + } + for (iter_top(its,i); i.ok(); i++){ + i->pre_processing(); + } +} + +void +PScore::postprocess() +{ + for (iter_top(broken_spans,i); i.ok(); i++) { // could chase spans as well. + i->post_processing(); + } + for (iter_top(its,i); i.ok(); i++){ + i->post_processing(); + } + + for (iter_top(broken_spans,i); i.ok(); i++) { + i->molecule_processing(); + } + for (iter_top(its,i); i.ok(); i++){ + i->molecule_processing(); + } + + for (iter_top(lines,i); i.ok(); i++) + i->process(); + +} + +PCursor +PScore::find_col(const PCol *c)const +{ + const PCol*what = c; + if (what->daddy_l_ ) + what = what->daddy_l_; + + return cols.find((PCol*)what); +} + +void +PScore::add_broken(Spanner*s) +{ + assert(s->left->line_l_ == s->right->line_l_); + broken_spans.bottom().add(s); + s->left->starters.bottom().add (s); + s->right->stoppers.bottom().add (s); +} + +void +PScore::set_breaking(Array breaking) +{ + for (int j=0; j < breaking.size(); j++) { + Array &curline(breaking[j].cols); + Array &config(breaking[j].config); + + Line_of_score *s_p = new Line_of_score(curline,this); + lines.bottom().add(s_p); + for (int i=0; i < curline.size(); i++){ + curline[i]->hpos = config[i]; + } + } +} + +void +PScore::calc_breaking() +{ + Word_wrap w(*this); + set_breaking(w.solve()); +} + +void +PScore::process() +{ + clean_cols(); + *mlog << "Preprocessing ... " <pstaff_l_ = this; +} diff --git a/lily/qlp.cc b/lily/qlp.cc new file mode 100644 index 0000000000..e6696acf39 --- /dev/null +++ b/lily/qlp.cc @@ -0,0 +1,155 @@ +#include "debug.hh" +#include "const.hh" +#include "qlp.hh" +#include "choleski.hh" + +void +Mixed_qp::add_equality_cons(Vector , double ) +{ + assert(false); +} + +void +Mixed_qp::add_fixed_var(int i, Real r) +{ + eq_cons.push(i); + eq_consrhs.push(r); +} + +void +Ineq_constrained_qp::add_inequality_cons(Vector c, double r) +{ + cons.push(c); + consrhs.push(r); +} + +Ineq_constrained_qp::Ineq_constrained_qp(int novars): + quad(novars), + lin(novars), + const_term (0.0) +{ +} + +void +Ineq_constrained_qp::OK() const +{ +#ifndef NDEBUG + assert(cons.size() == consrhs.size()); + Matrix Qdif= quad - quad.transposed(); + assert(Qdif.norm()/quad.norm() < EPS); +#endif +} + + +Real +Ineq_constrained_qp::eval (Vector v) +{ + return v * quad * v + lin * v + const_term; +} + +/** + 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 +{ + print(); + Ineq_constrained_qp pure(*this); + + for (int i= eq_cons.size()-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.size(); i++) { + sol.insert( eq_consrhs[i],eq_cons[i]); + } + return sol; +} + +/* + assume x(idx) == value, and adjust constraints, lin and quad accordingly + + TODO: add const_term + */ +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.size(); i++) { + consrhs[i] -= cons[i](idx) *value; + cons[i].del(idx); + } +} + + + +void +Ineq_constrained_qp::assert_solution(Vector sol) const +{ + Array binding; + for (int i=0; i < cons.size(); i++) { + Real R=cons[i] * sol- consrhs[i]; + assert(R> -EPS); + if (R < EPS) + binding.push(i); + } + // KKT check... + // todo +} + +void +Ineq_constrained_qp::print() const +{ +#ifndef NPRINT + mtor << "Quad " << quad; + mtor << "lin " << lin <<"\n" + << "const " << const_term<<"\n"; + for (int i=0; i < cons.size(); i++) { + mtor << "constraint["<= " << consrhs[i]; + mtor << "\n"; + } +#endif +} + +/* *************** */ + +Mixed_qp::Mixed_qp(int n) + : Ineq_constrained_qp(n) +{ +} + +void +Mixed_qp::OK() const +{ +#ifndef NDEBUG + Ineq_constrained_qp::OK(); + assert(eq_consrhs.size() == eq_cons.size()); +#endif +} + +void +Mixed_qp::print() const +{ +#ifndef NPRINT + Ineq_constrained_qp::print(); + for (int i=0; i < eq_cons.size(); i++) { + mtor << "eq cons "<cons.size()); + assert(H.dim() == opt->dim()); + assert(active.size() == A.rows()); + Array allcons; + + for (int i=0; i < opt->cons.size(); i++) + allcons.push(0); + for (int i=0; i < active.size(); i++) { + int j = active[i]; + allcons[j]++; + } + for (int i=0; i < inactive.size(); i++) { + int j = inactive[i]; + allcons[j]++; + } + for (int i=0; i < allcons.size(); i++) + assert(allcons[i] == 1); +#endif +} + +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.push(cidx); + + inactive.swap(k,inactive.size()-1); + inactive.pop(); + + Vector a( opt->cons[cidx] ); + // update of matrices + Vector Ha = H*a; + Real aHa = a*Ha; + Vector addrow(Ha.dim()); + if (abs(aHa) > EPS) { + /* + a != 0, so if Ha = O(EPS), then + Ha * aH / aHa = O(EPS^2/EPS) + + if H*a == 0, the constraints are dependent. + */ + H -= Matrix(Ha/aHa , Ha); + + + /* + sorry, don't know how to justify this. .. + */ + addrow=Ha; + addrow/= aHa; + A -= Matrix(A*a, addrow); + A.insert_row(addrow,A.rows()); + }else + WARN << "degenerate constraints"; +} + +void +Active_constraints::drop(int k) +{ + int q=active.size()-1; + + // drop indices + inactive.push(active[k]); + active.swap(k,q); + A.swap_rows(k,q); + active.pop(); + + Vector a(A.row(q)); + if (a.norm() > EPS) { + /* + + */ + Real q = a*opt->quad*a; + H += Matrix(a,a/q); + A -= A*opt->quad*Matrix(a,a/q); + }else + WARN << "degenerate constraints"; + #ifndef NDEBUG + Vector rem_row(A.row(q)); + assert(rem_row.norm() < EPS); + #endif + + 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.size(); i++) + inactive.push(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); + } + assert(v(i) <= INFTY); + } + return idx; +} + + +/**the numerical solving. 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. (well, not really the + gradient. The optimal solution obeying the active constraints is + tried. This is why H = Q^-1 in initialisation) ) + + + */ +Vector +Ineq_constrained_qp::solve(Vector start) const +{ + Active_constraints act(this); + + + act.OK(); + + + Vector x(start); + Vector gradient=quad*x+lin; +// Real fvalue = x*quad*x/2 + lin*x + const_term; +// it's no use. + + 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()); + mtor << "adding cons "<< minidx.idx()<<'\n'; + 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) { + assert(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; +} + + diff --git a/lily/register.cc b/lily/register.cc new file mode 100644 index 0000000000..126507cc6b --- /dev/null +++ b/lily/register.cc @@ -0,0 +1,88 @@ +/* + register.cc -- implement Request_register + + Sourcefile of LilyPond musictypesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "voice.hh" +#include "musicalrequest.hh" +#include "register.hh" +#include "notehead.hh" +#include "complex-walker.hh" +#include "local-key-item.hh" +#include "complex-staff.hh" +#include "registergroup.hh" +#include "debug.hh" + + +bool +Request_register::try_request(Request*) +{ + return false; +} + +Request_register::Request_register() +{ + daddy_reg_l_ = 0; +} + +void +Request_register::announce_element(Staff_elem_info i) +{ + i.origin_reg_l_arr_.push(this); + daddy_reg_l_->announce_element(i); +} + +void +Request_register::typeset_element(Staff_elem*p) +{ + daddy_reg_l_->typeset_element(p); +} + +Paper_def* +Request_register::paper()const +{ + return daddy_reg_l_->paper(); +} + +void +Request_register::typeset_breakable_item(Item * pre_p , Item * nobreak_p, + Item * post_p) +{ + daddy_reg_l_->typeset_breakable_item(pre_p, nobreak_p, post_p); +} + +bool +Request_register::acceptable_request_b(Request*)const +{ + return false; +} + +bool +Request_register::contains_b(Request_register *reg_l) +{ + return this == reg_l; +} + +Staff_info +Request_register::get_staff_info() return inf; +{ + inf = daddy_reg_l_->get_staff_info(); +} + +void +Request_register::print() const +{ +#ifndef NPRINT + mtor << name() << " {"; + do_print(); + mtor << "}\n"; +#endif +} + +void +Request_register::do_print()const +{ +} diff --git a/lily/request.cc b/lily/request.cc new file mode 100644 index 0000000000..ecfe68c881 --- /dev/null +++ b/lily/request.cc @@ -0,0 +1,300 @@ +/* + request.cc -- implement all musical requests. + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "musicalrequest.hh" +#include "misc.hh" +#include "debug.hh" +#include "script-def.hh" +#include "text-def.hh" +#include "voice.hh" +#include "voice-element.hh" + +void +Stem_req::do_print() const +{ + Rhythmic_req::do_print(); + mtor << "dir : " << dir_i_; +} + +Stem_req::Stem_req(int s, int d) + : Rhythmic_req(s,d) +{ + dir_i_ = 0; +} + +/* ************** */ +void Musical_req::do_print()const{} +void Request::do_print() const{} + +/* *************** */ + +void +Request::print() const +{ + mtor << name() << " {"; + do_print(); + mtor << "}\n"; +} + + + +void +Span_req::do_print() const +{ +#ifndef NPRINT + mtor << spantype ; +#endif +} + +Request::Request() +{ + elt_l_ = 0; + defined_ch_c_l_ = 0; +} +Request::Request(Request const&src) +{ + elt_l_ = 0; + defined_ch_c_l_ = src.defined_ch_c_l_; +} +/* *************** */ +Spacing_req::Spacing_req() +{ + next = 0; + distance = 0; + strength = 0; +} +void +Spacing_req::do_print()const +{ + mtor << "next " << next << "dist " << distance << "strength\n"; +} + +void +Blank_req::do_print()const +{ + Spacing_req::do_print(); +} +/* *************** */ +Melodic_req::Melodic_req() +{ + notename_i_ = 0; + octave_i_ = 0; + accidental_i_ = 0; + forceacc_b_ = false; +} + +void +Melodic_req::do_print() const +{ + mtor << "notename: " << notename_i_ << " acc: " <align_i_ = 0; // centre + dir_i_ = -1; // lyrics below (invisible) staff +} + +void +Lyric_req::do_print() const +{ + Rhythmic_req::do_print(); + Text_req::do_print(); +} +/* *************** */ +void +Note_req::do_print() const +{ + Melodic_req::do_print(); + Rhythmic_req::do_print(); +} +/* *************** */ +void +Rest_req::do_print() const +{ + Rhythmic_req::do_print(); +} + +/* *************** */ +Beam_req::Beam_req() +{ + nplet = 0; +} + +void Beam_req::do_print()const{} +/* *************** */ +void Slur_req::do_print()const{} +/* *************** */ +int +Span_req:: compare(const Span_req &r1, const Span_req &r2) +{ + return r1.spantype - r2.spantype; +} + +Span_req::Span_req() +{ + spantype = NOSPAN; +} + +/* *************** */ +Script_req::Script_req(int d , Script_def*def) +{ + dir_i_ = d; + scriptdef_p_ = def; +} + +int +Script_req::compare(const Script_req &d1, const Script_req &d2) +{ + return d1.dir_i_ == d2.dir_i_ && + d1.scriptdef_p_->compare(*d2.scriptdef_p_); +} + +Script_req::Script_req(Script_req const &s) + : Request( s ) +{ + dir_i_ = s.dir_i_; + scriptdef_p_ = new Script_def(*s.scriptdef_p_); +} + +void +Script_req::do_print() const +{ + mtor << " dir " << dir_i_ ; + scriptdef_p_->print(); +} + + +Script_req::~Script_req() +{ + delete scriptdef_p_; +} +/* *************** */ +int +Text_req:: compare(const Text_req &r1, const Text_req &r2) +{ + bool b1 = (r1.dir_i_ == r2.dir_i_); + bool b2 = (r1.tdef_p_ ->compare(*r2.tdef_p_)); + return b1 && b2; +} +Text_req::~Text_req() +{ + delete tdef_p_; + tdef_p_ = 0; +} + +Text_req::Text_req(Text_req const& src) +{ + tdef_p_ = new Text_def(*src.tdef_p_); + dir_i_ = src.dir_i_; +} + +Text_req::Text_req(int dir_i, Text_def* tdef_p) +{ + dir_i_ = dir_i; + tdef_p_ = tdef_p; +} + +void +Text_req::do_print() const +{ + mtor << " dir " << dir_i_ ; + tdef_p_->print(); +} + +/* *************** */ + +Moment +Skip_req::duration() const +{ + return duration_; +} + +void +Skip_req::do_print() const +{ + mtor << "duration: " << duration(); +} + +Voice * +Request::voice_l() +{ + if (!elt_l_) + return 0; + else + return (Voice*)elt_l_->voice_l_; +} diff --git a/lily/rest.cc b/lily/rest.cc new file mode 100644 index 0000000000..0e4394a3c6 --- /dev/null +++ b/lily/rest.cc @@ -0,0 +1,42 @@ +#include "rest.hh" +#include "dimen.hh" +#include "debug.hh" +#include "paper-def.hh" +#include "lookup.hh" +#include "molecule.hh" + + +Rest::Rest(int t, int d) +{ + balltype = t; + dots = d; +} + + +void +Rest::do_print()const +{ +#ifndef NPRINT + mtor << "Rest "<lookup_p_->rest(balltype); + + Molecule *m = new Molecule(Atom(s)); + if (dots) { + Symbol d =p->lookup_p_->dots(dots); + Molecule dm; + dm.add(Atom(d)); + m->add_right(dm); + } + return m; +} + diff --git a/lily/score-column.cc b/lily/score-column.cc new file mode 100644 index 0000000000..4387630e8d --- /dev/null +++ b/lily/score-column.cc @@ -0,0 +1,77 @@ +/* + score-column.cc -- implement Score_column + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "debug.hh" +#include "pcol.hh" +#include "score-column.hh" + +int +Score_column::compare(Score_column & c1, Score_column &c2) +{ + return sign(c1.when_ - c2.when_); +} + +void +Score_column::set_breakable() +{ + pcol_l_->set_breakable(); +} + +Score_column::Score_column(Moment w) +{ + when_ = w; + pcol_l_ = new PCol(0); + musical_b_ = false; +} + +bool +Score_column::used_b() { + return pcol_l_->used_b(); +} + +void +Score_column::print() const +{ +#ifndef NPRINT + mtor << "Score_column { mus "<< musical_b_ <<" at " << when_<<'\n'; + mtor << "durations: ["; + for (int i=0; i < durations.size(); i++) + mtor << durations[i] << " "; + mtor << "]\n"; + pcol_l_->print(); + mtor << "}\n"; +#endif +} + +int +Moment_compare(Moment &a , Moment& b) +{ + return sign(a-b); +} + +void +Score_column::preprocess() +{ + durations.sort(Moment_compare); +} +void +Score_column::add_duration(Moment d) +{ + assert(d); + for (int i = 0; i< durations.size(); i++) { + if (d == durations[i]) + return ; + } + durations.push(d); +} + +bool +Score_column::breakable_b() +{ + return pcol_l_->breakable_b(); +} diff --git a/lily/score.cc b/lily/score.cc new file mode 100644 index 0000000000..88e2e2f07b --- /dev/null +++ b/lily/score.cc @@ -0,0 +1,288 @@ +/* + score.cc -- implement Score + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ +#include "tex-stream.hh" +#include "score.hh" +#include "score-column.hh" +#include "pscore.hh" +#include "staff.hh" +#include "debug.hh" +#include "paper-def.hh" +#include "main.hh" +#include "source.hh" +#include "source-file.hh" +#include "score-walker.hh" +#include "midi-output.hh" +#include "midi-def.hh" + +extern String default_out_fn; + +void +Score::setup_music() +{ + *mlog << "\nSetting up music ..." << flush; + if (last() == Moment(0)) { + errorlevel_i_ |= 1; + error("Need to have music in a score.", defined_ch_c_l_); + } + + for (iter_top(staffs_,i); i.ok(); i++) { + i->setup_staffcols(); + i->OK(); + } +} + +void +Score::process_music() +{ + *mlog << "Processing music ..." << flush; + for (Score_walker w(this); w.ok(); w++) { + w.process(); + } +} + +void +Score::process() +{ + setup_music(); + + paper(); + midi(); +} + +void +Score::paper() +{ + if (!paper_p_) + return; + + pscore_p_ = new PScore(paper_p_); + + find_col(0, false)->set_breakable(); // ugh + find_col(last(), false)->set_breakable(); + do_cols(); + + for (iter_top(staffs_,i); i.ok(); i++) + i->set_output(pscore_p_); + + + process_music(); + clean_cols(); // can't move clean_cols() farther up. + print(); + calc_idealspacing(); + + // debugging + OK(); + *mlog << endl; + pscore_p_->process(); + + // output + paper_output(); + +} + +/** + Remove empty cols, preprocess other columns. + */ +void +Score::clean_cols() +{ + for (iter_top(staffs_,i); i.ok(); i++) + i->clean_cols(); + + for (iter_top(cols_,c); c.ok(); ) { + if (!c->pcol_l_->used_b()) { + delete c.remove_p(); + } else { + c->preprocess(); + c++; + } + } +} + +/** + Create columns at time #w#. + this sux. We should have Score_column create the appropriate PCol. + Unfortunately, PCols don't know about their position. + + @return cursor pointing to the nonmusical (first) column + */ +PCursor +Score::create_cols(Moment w) +{ + Score_column* c1 = new Score_column(w); + Score_column* c2 = new Score_column(w); + + c1->musical_b_ = false; + c2->musical_b_ = true; + + iter_top(cols_,i); + + for (; i.ok(); i++) { + assert(i->when() != w); + if (i->when() > w) + break; + } + + if (!i.ok()) { + cols_.bottom().add(c1); + cols_.bottom().add(c2); + i = cols_.bottom(); + i --; + } else { + i.insert(c1); + i.insert(c2); + i -= 2; + } + return i; +} + +PCursor +Score::find_col(Moment w, bool mus) +{ + iter_top( cols_,i); + + for (; i.ok(); i++) { + if (i->when() == w && i->musical_b_ == mus) + return i; + if (i->when() > w) + break; + } + i = create_cols(w); + if (mus) + i++; + return i; +} + +void +Score::do_cols() +{ + iter_top(cols_,i); + for (; i.ok(); i++) { + pscore_p_->add(i->pcol_l_); + } +} + +Moment +Score::last() const +{ + Moment l = 0; + for (iter_top(staffs_,i); i.ok(); i++) { + l = l>? i->last(); + } + return l; +} + +void +Score::set(Paper_def *pap_p) +{ + delete paper_p_; + paper_p_ = pap_p; +} + +void +Score::set(Midi_def* midi_p) +{ + delete midi_p_; + midi_p_ = midi_p; +} + +void +Score::OK() const +{ +#ifndef NDEBUG + for (iter_top(staffs_,i); i.ok(); i++) { + i->OK(); + assert(i->score_l_ == this); + } + staffs_.OK(); + cols_.OK(); + for (iter_top(cols_,cc); cc.ok() && (cc+1).ok(); cc++) { + assert(cc->when() <= (cc+1)->when()); + } +#endif +} + + +void +Score::print() const +{ +#ifndef NPRINT + mtor << "score {\n"; + for (iter_top(staffs_,i); i.ok(); i++) { + i->print(); + } + for (iter_top(cols_,i); i.ok(); i++) { + i->print(); + } + if (pscore_p_) + pscore_p_->print(); + if (midi_p_) + midi_p_->print(); + + mtor << "}\n"; +#endif +} + +Score::Score() +{ + pscore_p_=0; + paper_p_ = 0; + midi_p_ = 0; + errorlevel_i_ = 0; + defined_ch_c_l_ = 0; +} + +Score::~Score() +{ + delete pscore_p_; + delete paper_p_; + delete midi_p_; +} + +void +Score::paper_output() +{ + OK(); + if (paper_p_->outfile=="") + paper_p_->outfile = default_out_fn + ".out"; + + if ( errorlevel_i_ ) { + *mlog << "lilypond: warning: no output to: " << paper_p_->outfile + << " (errorlevel=" << errorlevel_i_ << ")" << endl; + return; + } + + *mlog << "TeX output to " << paper_p_->outfile << " ...\n"; + + Tex_stream the_output(paper_p_->outfile); + + the_output << "% outputting Score, defined at: " << + source_l_g-> + sourcefile_l (defined_ch_c_l_)->file_line_no_str(defined_ch_c_l_) << "\n"; + pscore_p_->output(the_output); +} + +void +Score::midi() +{ + if (!midi_p_) + return; + + if (midi_p_->outfile_str_ == "") + midi_p_->outfile_str_ = default_out_fn + ".midi"; + + *mlog << "midi output to " << midi_p_->outfile_str_ << " ...\n"; + Midi_output(this, midi_p_); +} + +void +Score::add(Staff*s) +{ + s->score_l_ = this; + staffs_.bottom().add(s); +} diff --git a/lily/scoreline.cc b/lily/scoreline.cc new file mode 100644 index 0000000000..2f8f0f3a4b --- /dev/null +++ b/lily/scoreline.cc @@ -0,0 +1,51 @@ +#include "scoreline.hh" +#include "staffline.hh" +#include "dimen.hh" +#include "spanner.hh" +#include "symbol.hh" +#include "paper-def.hh" +#include "pcol.hh" +#include "pscore.hh" + + +String +Line_of_score::TeXstring() const +{ + String s("\\vbox{%<- line of score\n"); + for (iter_top(staffs,sc); sc.ok(); sc++){ + s += sc->TeXstring(); + if ((sc+1).ok()) + s+= "\\interstaffline\n"; + } + s += "}"; + return s; +} + + +Line_of_score::Line_of_score(Array sv, + PScore *ps) +{ + pscore_l_ = ps; + for (int i=0; i< sv.size(); i++) { + PCol *p=(PCol *) sv[i]; + cols.bottom().add(p); + p->line_l_=this; + } + + for (iter_top(pscore_l_->staffs,sc); 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!! + */ + + +void +Line_of_score::process() +{ + for (iter_top(staffs,i); i.ok(); i++) + i->process(); +} + diff --git a/lily/scores.cc b/lily/scores.cc new file mode 100644 index 0000000000..a6df7ead96 --- /dev/null +++ b/lily/scores.cc @@ -0,0 +1,48 @@ +#include "main.hh" +#include "input-score.hh" +#include "score.hh" +#include "string.hh" +#include "paper-def.hh" +#include "debug.hh" + +static Array score_array_global; +String default_out_fn = "lelie"; + +void +do_scores() +{ + for (int i=0; i < score_array_global.size(); i++) { + Input_score* &is_p = score_array_global[i]; + if (is_p->errorlevel_i_) { + warning("Score contains errors. Will not process it. ", + is_p->defined_ch_c_l_); + delete is_p; + continue; + } + + if (only_midi) { + delete is_p->paper_p_; + is_p->paper_p_ = 0; + } + + Score * s_p = is_p->parse(); + delete is_p; + s_p->print (); + s_p->process(); + delete s_p; + } + score_array_global.set_size(0); +} + +void +add_score(Input_score * s) +{ + score_array_global.push(s); +} + +void +set_default_output(String s) +{ + default_out_fn = s; +} + diff --git a/lily/script-def.cc b/lily/script-def.cc new file mode 100644 index 0000000000..53bdd121ef --- /dev/null +++ b/lily/script-def.cc @@ -0,0 +1,24 @@ +#include "debug.hh" +#include "script-def.hh" + +Script_def::Script_def(String idx, int stem, int staff ,bool invert) +{ + symidx = idx ; + stemdir =stem; + staffdir = staff; + invertsym = invert; +} +void +Script_def::print() const +{ + mtor << "Script_def{ idx: " << symidx + << " direction, stem: " << stemdir << " staff : " << staffdir << "}\n"; +} +int +Script_def::compare(Script_def const & c) +{ + return !(symidx == c.symidx && + stemdir == c.stemdir&& + staffdir == c.staffdir&& + invertsym == c.invertsym); +} diff --git a/lily/script-reg.cc b/lily/script-reg.cc new file mode 100644 index 0000000000..6cfba0f397 --- /dev/null +++ b/lily/script-reg.cc @@ -0,0 +1,76 @@ +/* + script-reg.cc -- implement Script_register + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "script-reg.hh" +#include "script.hh" +#include "musicalrequest.hh" +#include "complex-walker.hh" +#include "stem.hh" + +Script_register::Script_register() +{ + script_p_ = 0; + post_move_processing(); +} + +bool +Script_register::try_request(Request *r_l) +{ + if (!r_l->script()) + return false ; + + if (script_req_l_ + && Script_req::compare(*script_req_l_, *r_l->script())) + + return false; + + script_req_l_ = r_l->script(); + + return true; +} + +void +Script_register::process_requests() +{ + if (script_req_l_) { + script_p_ = new Script(script_req_l_, 10); + announce_element( + Staff_elem_info(script_p_, script_req_l_)); + } +} + +void +Script_register::acknowledge_element(Staff_elem_info info) +{ + if (!script_p_) + return; + if (info.elem_p_->name() == Stem::static_name()) + script_p_->set_stem((Stem*)info.elem_p_); + else if (info.req_l_->rhythmic()) + script_p_->set_support(info.elem_p_->item()); +} + +void +Script_register::pre_move_processing() +{ + if (script_p_){ + script_p_->dir = dir_i_; + typeset_element(script_p_); + script_p_ = 0; + } +} +void +Script_register::post_move_processing() +{ + script_req_l_ = 0; +} + +void +Script_register::set_feature(Features i) +{ + if (i.direction_i_|| i.initialiser_b_) + dir_i_ = i.direction_i_; +} diff --git a/lily/script.cc b/lily/script.cc new file mode 100644 index 0000000000..2a31133c33 --- /dev/null +++ b/lily/script.cc @@ -0,0 +1,129 @@ +#include "musicalrequest.hh" +#include "paper-def.hh" +#include "script.hh" +#include "stem.hh" +#include "molecule.hh" +#include "lookup.hh" + + + +void +Script::set_stem(Stem*st_l) +{ + stem_l_ = st_l; + add_dependency(st_l); +} + +void +Script::set_support(Item*i) +{ + support.push(i); + add_dependency(i); +} + +Script::Script(Script_req* rq, int staflen) +{ + staffsize =staflen; + specs_l_ = rq->scriptdef_p_; + stem_l_ = 0; + pos = 0; + symdir=1; + dir =rq->dir_i_; +} + +void +Script::set_symdir() +{ + if (specs_l_->invertsym) + symdir = (dir < 0) ? -1:1; +} + +void +Script::set_default_dir() +{ + if (specs_l_->stemdir) { + if (!stem_l_) + dir = 1; + else + dir = stem_l_->dir * specs_l_->stemdir; + } +} + +Interval +Script::support_height() const return r; +{ + for (int i=0; i < support.size(); i++) + r.unite(support[i]->height()); +} + +void +Script::set_default_index() +{ + Real inter_f= paper()->internote(); + Interval dy = symbol().dim.y; + + int d = specs_l_->staffdir; + Real y ; + if (!d) { + Interval v= support_height(); + y = v[dir] -dy[-dir] + 2*dir*inter_f; + } else { + y = (d > 0) ? staffsize + 2: -2; // ug + y *=inter_f; + Interval v= support_height(); + + if (d > 0) { + y = y >? v.max(); + } else if (d < 0) { + y = y height(); + + if (d > 0 || (!d && dir > 0)) { + y = y >? v.max(); + }else if (d < 0 || (!d && dir < 0)) { + y = y lookup_p_->script(preidx_str + specs_l_->symidx); +} + +void +Script::do_pre_processing() +{ + set_default_dir(); + set_symdir(); +} + +void +Script::do_post_processing() +{ + set_default_index(); +} + +Molecule* +Script::brew_molecule_p() const +{ + Real dy = paper()->internote(); + + Molecule*out = new Molecule(Atom(symbol())); + out->translate(Offset(0,dy * pos)); + return out; +} diff --git a/lily/slur.cc b/lily/slur.cc new file mode 100644 index 0000000000..ba77a6948e --- /dev/null +++ b/lily/slur.cc @@ -0,0 +1,135 @@ +/* + + TODO: + think about crossing stems. + */ +#include "slur.hh" +#include "scalar.hh" +#include "lookup.hh" +#include "paper-def.hh" +#include "notehead.hh" +#include "pcol.hh" +#include "molecule.hh" +#include "debug.hh" +#include "boxes.hh" + + + +Slur::Slur() +{ + open_right=open_left=false; +} + +Offset +Slur::center() const +{ + int pos1 = encompass.top()->position; + int pos2 = encompass[0]->position; + + int dy = pos1-pos2; + + Real w = width().length(); + + return Offset(w/2,dy * paper()->internote()); +} + +void +Slur::add(Notehead*n) +{ + encompass.push(n); + add_dependency(n); +} + +void +Slur::set_default_dir() +{ + int sumpos=0; + for (int i=0; i < encompass.size(); i ++) { + sumpos += encompass[i]->position; + } + + /* should consult stems */ + Real meanpos = sumpos/Real(encompass.size()); + if (meanpos < 5) // todo + dir_i_ = -1; + else + dir_i_ = 1; +} + +void +Slur::do_pre_processing() +{ + right = encompass.top()->pcol_l_; + left = encompass[0]->pcol_l_; +} + +Spanner* +Slur::do_break_at(PCol*l, PCol*r) const +{ + assert(l->line_l_ == r->line_l_); + Slur*ret = new Slur(*this); + + ret->encompass.set_size(0); + for (int i =0; i < encompass.size(); i++) { + if (encompass[i]->pcol_l_->line_l_==l->line_l_) + ret->encompass.push(encompass[i]); + } + if (right != r) + ret->open_right = true; + if (left != l) + ret->open_left = true; + + + return ret; +} + +void +Slur::do_post_processing() +{ + if (!dir_i_) + set_default_dir(); +} + +Molecule* +Slur::brew_molecule_p() const +{ + Molecule*output = new Molecule; + + int minp=1000, maxp=-1000; // todo + for (int i=0; iposition position >? maxp; + } + assert(encompass.size()>0); // todo + + Notehead *lnote_p =encompass[0]; + Notehead *rnote_p =encompass.top(); + int lpos_i = lnote_p->position; + int rpos_i = rnote_p->position; + Offset left_off(lnote_p->x_dir, lpos_i + 2*dir_i_); + Offset right_off(lnote_p->x_dir, rpos_i + 2*dir_i_); + if (!lnote_p->extremal) + left_off += Offset(0.5, -dir_i_); + if (!rnote_p->extremal) + right_off+= Offset(-0.5, -dir_i_); + + int dy = int(right_off.y - left_off.y); + + Real nw_f = paper()->note_width(); + Real nh_f = paper()->internote(); + Real w = width().length(); + + w+= (right_off.x - left_off.x) * nw_f ; + Real round_w = w; // slur lookup rounds the slurwidth . + + Symbol sl = paper()->lookup_p_->slur(dy , round_w, dir_i_); + + Real error = w-round_w; + + Atom a(sl); + a.translate(Offset((left_off.x + 0.5 )*nw_f + error/2, + left_off.y * nh_f)); + output->add(a); + return output; +} + diff --git a/lily/spanner.cc b/lily/spanner.cc new file mode 100644 index 0000000000..cc57686393 --- /dev/null +++ b/lily/spanner.cc @@ -0,0 +1,43 @@ +#include "debug.hh" +#include "spanner.hh" +#include "pcol.hh" + + + +void +Spanner::do_print()const +{ + mtor << " (unknown) "; +} + +Spanner* +Spanner::broken_at(PCol*c1, PCol *c2)const +{ + Spanner *span_p = do_break_at(c1,c2); + + for (int i=0; i < dependants.size(); i++) { + dependants[i]->substitute_dependency((Staff_elem*)this, span_p); + } + + span_p->left = c1; + span_p->right = c2; + + return span_p; +} + +Spanner::Spanner() +{ + left = right = 0; +} + + +Interval +Spanner::width()const +{ + Real r = right->hpos; + Real l = left->hpos; + assert(*left < *right); + assert(r>=l); + + return Interval(0, r-l); +} diff --git a/lily/staff-elem-info.cc b/lily/staff-elem-info.cc new file mode 100644 index 0000000000..9a6283e373 --- /dev/null +++ b/lily/staff-elem-info.cc @@ -0,0 +1,38 @@ +/* + staff-elem-info.cc -- implement Staff_elem_info + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "staff-elem-info.hh" +#include "request.hh" + +Staff_elem_info::Staff_elem_info(Staff_elem*s_l, Request*r_l) +{ + elem_p_ = s_l; + voice_l_ = (r_l)?r_l->voice_l():0; + req_l_ = r_l; +} + +Staff_elem_info::Staff_elem_info() +{ + elem_p_ = 0; + voice_l_ = 0; + + req_l_ = 0; +} + +Features::Features() +{ + direction_i_ = 0; + initialiser_b_ = false; +} + +Features +Features::dir(int d) return f; +{ + f.initialiser_b_ = true; + f.direction_i_ = d; +} diff --git a/lily/staff-elem.cc b/lily/staff-elem.cc new file mode 100644 index 0000000000..b24172fa63 --- /dev/null +++ b/lily/staff-elem.cc @@ -0,0 +1,200 @@ +#include "pscore.hh" +#include "symbol.hh" +#include "pstaff.hh" +#include "molecule.hh" +#include "staff-elem.hh" +#include "debug.hh" + +String +Staff_elem::TeXstring() const +{ + Molecule m(*output); + m.translate(offset_); // ugh? + return m.TeXstring(); +} + +Staff_elem::Staff_elem(Staff_elem const&s) + : dependants(s.dependants), + dependencies(s.dependencies) +{ + status = s.status; + assert(!s.output); + output = 0; + pstaff_l_ = s.pstaff_l_; + offset_ = Offset(0,0); +} +/** + TODO: + If deleted, then remove dependants depency! + */ +Staff_elem::~Staff_elem() +{ + delete output; +} + +void +Staff_elem::translate(Offset O) +{ + offset_ += O; +} +Interval +Staff_elem::width() const +{ + Interval r; + + if (!output){ + Molecule*m = brew_molecule_p(); + r = m->extent().x; + delete m; + } else + r = output->extent().x; + + if (!r.empty()) // float exception on DEC Alpha + r+=offset_.x; + + return r; +} +Interval +Staff_elem::height() const +{ + Interval r; + + if (!output){ + Molecule*m = brew_molecule_p(); + r = m->extent().y; + delete m; + } else + r = output->extent().y; + + if (!r.empty()) + r+=offset_.y; + + + return r; +} + +void +Staff_elem::print()const +{ +#ifndef NPRINT + mtor << name() << "{\n"; + do_print(); + if (output) + output->print(); + + mtor << "}\n"; +#endif +} + + + +Staff_elem::Staff_elem() +{ + pstaff_l_=0; + offset_ = Offset(0,0); + output = 0; + status = ORPHAN; +} + + +Paper_def* +Staff_elem::paper() const +{ + assert(pstaff_l_); + return pstaff_l_->pscore_l_->paper_l_; +} + +void +Staff_elem::add_processing() +{ + if (status >= VIRGIN) + return; + status = VIRGIN; + do_add_processing(); +} + +void +Staff_elem::pre_processing() +{ + if (status >= PRECALCED ) + return; + assert(status != PRECALCING); // cyclic dependency + status = PRECALCING; + + for (int i=0; i < dependencies.size(); i++) + if (dependencies[i]) + dependencies[i]->pre_processing(); + + + do_pre_processing(); + status = PRECALCED; +} +void +Staff_elem::post_processing() +{ + if (status >= POSTCALCED) + return; + assert(status != POSTCALCING);// cyclic dependency + status=POSTCALCING; + + for (int i=0; i < dependencies.size(); i++) + if (dependencies[i]) + dependencies[i]->post_processing(); + do_post_processing(); + status=POSTCALCED; +} + +void +Staff_elem::molecule_processing() +{ + if (status >= OUTPUT) + return; + status = OUTPUT; // do it only once. + for (int i=0; i < dependencies.size(); i++) + if (dependencies[i]) + dependencies[i]->molecule_processing(); + + output= brew_molecule_p(); +} + +void +Staff_elem::do_post_processing() +{ +} + +void +Staff_elem::do_pre_processing() +{ +} + +void +Staff_elem::do_add_processing() +{ +} + +void +Staff_elem::substitute_dependency(Staff_elem * old, Staff_elem * newdep) +{ + bool hebbes_b=false; + for (int i=0; i < dependencies.size(); i++) { + if (dependencies[i] == old){ + dependencies[i] = newdep; + hebbes_b = true; + } else if (dependencies[i] == newdep) { + hebbes_b = true; + } + } + if (!hebbes_b) + dependencies.push(newdep); +} + +void +Staff_elem::add_dependency(Staff_elem * p) +{ + for (int i=0; i < dependencies.size(); i ++) + if (dependencies[i] == p) + return; + + dependencies.push(p); + p->dependants.push(p); +} diff --git a/lily/staffline.cc b/lily/staffline.cc new file mode 100644 index 0000000000..5d18b219e6 --- /dev/null +++ b/lily/staffline.cc @@ -0,0 +1,110 @@ +#include "staffline.hh" +#include "scoreline.hh" +#include "dimen.hh" +#include "spanner.hh" +#include "symbol.hh" +#include "paper-def.hh" +#include "molecule.hh" +#include "pcol.hh" +#include "pscore.hh" + +static String +make_vbox(Interval i) +{ + Real r = (i.empty()) ? 0.0 : i.length(); + String s("\\vbox to "); + s += print_dimen(r); + s += "{\\vskip "+print_dimen(i.right)+" "; + return s; +} + + +String +Line_of_staff::TeXstring() const +{ + String s("%line_of_staff\n"); + + s+=make_vbox(height()); + // the staff itself: eg lines, accolades + s += "\\hbox{"; + { + iter_top(line_of_score_l_->cols,cc); + Real lastpos=cc->hpos; + + // all items in the current line & staff. + for (; cc.ok(); cc++) { + Real delta=cc->hpos - lastpos; + lastpos = cc->hpos; + + // moveover + if (delta) + s +=String( "\\kern ") + print_dimen(delta); + + // now output the items. + for (iter_top(cc->its,i); i.ok(); i++) { + if (i->pstaff_l_ == pstaff_l_) + s += i->TeXstring(); + } + // spanners. + for (iter_top(cc->starters,i); i.ok(); i++) + if (i->pstaff_l_ == pstaff_l_) + s += i->TeXstring(); + } + } + s+="\\hss}\\vss}"; + return s; +} + +Line_of_staff::Line_of_staff(Line_of_score * sc, PStaff*st) +{ + line_of_score_l_=sc; + pstaff_l_=st; + + PCol *linestart = sc->cols.top(); + PCol *linestop = sc->cols.bottom(); + + for (iter_top(pstaff_l_->spans,i); i.ok(); i++) { + PCol *brokenstart = &max(*linestart, *i->left); + PCol *brokenstop = &min(*linestop, *i->right); + if ( *brokenstart < *brokenstop) { + Spanner*span_p =i->broken_at(brokenstart,brokenstop); + line_of_score_l_->pscore_l_-> // higghl + add_broken(span_p); + } + } +} + + +Interval +Line_of_staff::height() const +{ + Interval y(0,0); + + iter_top(line_of_score_l_->cols,cc); + + // all items in the current line & staff. + for (; cc.ok(); cc++) { + for (iter_top(cc->its,i); i.ok(); i++) { + if (i->pstaff_l_ == pstaff_l_) + y.unite(i->height()); + + } + // spanners. + for (iter_top(cc->starters,i); i.ok(); i++) + if (i->pstaff_l_ == pstaff_l_) { + y.unite(i->height()); + } + } + + return y; +} + +void +Line_of_staff::process() +{ +#if 0 + if (!pstaff_l_->stafsym_p_) + pstaff_l_->brew_molecule_p(line_of_score_l_->pscore_l_-> + paper_l_->linewidth); +#endif +} diff --git a/lily/staffsym.cc b/lily/staffsym.cc new file mode 100644 index 0000000000..631a5f3673 --- /dev/null +++ b/lily/staffsym.cc @@ -0,0 +1,46 @@ +/* + staffsym.cc -- implement Staff_symbol + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ +#include "staffsym.hh" +#include "lookup.hh" +#include "paper-def.hh" +#include "debug.hh" + + + +Staff_symbol::Staff_symbol(int l) +{ + no_lines_i_ = l; +} + +void +Staff_symbol::do_print()const +{ + mtor << "lines: " << no_lines_i_; +} + +Molecule* +Staff_symbol::brew_molecule_p() const +{ + Atom a = paper()->lookup_p_->linestaff(no_lines_i_, width().length()); + return new Molecule(a); +} + +Spanner* +Staff_symbol::do_break_at(PCol*p1, PCol*p2)const +{ + Staff_symbol *span_p=new Staff_symbol(*this); + return span_p; +} + +void +Staff_symbol::set_extent(PCol*p1, PCol*p2) +{ + assert(p1&&p2); + left = p1; + right = p2; +} diff --git a/lily/stem.cc b/lily/stem.cc new file mode 100644 index 0000000000..74ea4b57fc --- /dev/null +++ b/lily/stem.cc @@ -0,0 +1,200 @@ +#include "stem.hh" +#include "dimen.hh" +#include "debug.hh" +#include "paper-def.hh" +#include "notehead.hh" +#include "lookup.hh" +#include "molecule.hh" +#include "pcol.hh" +#include "misc.hh" + +const int STEMLEN=7; + + +Stem::Stem(int c) //, Moment len) +{ + beams_left = 0; + beams_right = 0; + minnote = 1000; // invalid values + maxnote = -1000; + bot = top = 0; + flag = 4; + dir =0; + staff_center=c; + stemlen=0; + print_flag=true; + stem_xoffset=0; +} + +void +Stem::do_print() const +{ +#ifndef NPRINT + mtor << "flag "<< flag << " print_flag " << print_flag + << "min,max [" << minnote << ", " << maxnote << "]"; +#endif +} +void +Stem::set_stemend(Real se) +{ + + // todo: margins + if (! ((dir > 0 && se >= maxnote) || (se <= minnote && dir <0)) ) + warning("Weird stem size; check for narrow beams",0); + + top = (dir < 0) ? maxnote : se; + bot = (dir < 0) ? se : minnote; + flag = dir*abs(flag); +} + +void +Stem::add(Notehead *n) +{ + assert(status < PRECALCED); + + if (n->balltype == 1) + return; + int p = n->position; + if (p < minnote) + minnote = p; + if (p > maxnote) + maxnote = p; + heads.push(n); + n->add_dependency(this); +} + + +int +Stem::get_default_dir() +{ + if (dir) + return dir; + Real mean = (minnote+maxnote)/2; + return (mean > staff_center) ? -1: 1; +} + +void +Stem::set_default_dir() +{ + dir = get_default_dir(); +} + +void +Stem::set_default_stemlen() +{ + if (!dir) + set_default_dir(); + + int stafftop = 2*staff_center; + stemlen = STEMLEN + (maxnote - minnote); + + // uhh... how about non 5-line staffs? + if (maxnote < -2 && dir == 1){ + int t = staff_center - staff_center/2; + stemlen = t - minnote +2; + } else if (minnote > stafftop + 2 && dir == -1) { + int t = staff_center + staff_center/2; + stemlen = maxnote -t +2; + } + + assert(stemlen); +} + + +void +Stem::set_default_extents() +{ + if (minnote > maxnote) { + warning("Empty stem. Ugh!", 0); + minnote = -10; + maxnote = 20; + } + + if (!stemlen) + set_default_stemlen(); + + set_stemend((dir< 0) ? maxnote-stemlen: minnote +stemlen); + if (dir > 0){ + stem_xoffset = paper()->note_width()-paper()->rule_thickness(); + } else + stem_xoffset = 0; +} + +void +Stem::set_noteheads() +{ + if(!heads.size()) + return; + heads.sort(Notehead::compare); + heads[0]->extremal = -1; + heads.top()->extremal = 1; + int parity=1; + int lastpos = heads[0]->position; + for (int i=1; i < heads.size(); i ++) { + int dy =abs(lastpos- heads[i]->position); + + if (dy <= 1) { + if (parity) + heads[i]->x_dir = (stem_xoffset>0) ? 1:-1; + parity = !parity; + } else + parity = 0; + lastpos = heads[i]->position; + } +} + +void +Stem::do_pre_processing() +{ + if (bot == top) + set_default_extents(); + set_noteheads(); +} + + +Interval +Stem::width()const +{ + if (!print_flag || abs(flag) <= 4) + return Interval(0,0); // TODO! + Paper_def*p= paper(); + Interval r(p->lookup_p_->flag(flag).dim.x); + r+= stem_xoffset; + return r; +} + +Molecule* +Stem::brew_molecule_p()const return out; +{ + assert(bot!=top); + + + Paper_def *p =paper(); + + Real dy = p->internote(); + Symbol ss =p->lookup_p_->stem(bot*dy,top*dy); + + + out = new Molecule(Atom(ss)); + + if (print_flag&&abs(flag) > 4){ + Symbol fl = p->lookup_p_->flag(flag); + Molecule m(fl); + if (flag < -4){ + out->add_bottom(m); + } else if (flag > 4) { + out->add_top(m); + } else + assert(false); + } + + out->translate(Offset(stem_xoffset,0)); +} + +Real +Stem::hindex()const +{ + return pcol_l_->hpos + stem_xoffset; // hmm. + offset_.x; +} + + diff --git a/lily/symbol.cc b/lily/symbol.cc new file mode 100644 index 0000000000..becdf1e29f --- /dev/null +++ b/lily/symbol.cc @@ -0,0 +1,21 @@ +#include "symbol.hh" +#include "varray.hh" + + +Symbol::Symbol() + : dim(Interval(0,0),Interval(0,0)) +{ + tex = "\\unknown"; +} +Symbol::Symbol(String s, Box b) + : dim(b) +{ + tex = s; +} + + +String +Symbol::str()const return s; +{ + s = "symbol(\'"+tex+"\', (" + dim.x.str() + ", " + dim.y.str() + "))"; +} diff --git a/lily/symtable.cc b/lily/symtable.cc new file mode 100644 index 0000000000..d55e9ac59b --- /dev/null +++ b/lily/symtable.cc @@ -0,0 +1,61 @@ +#include "misc.hh" +#include "dimen.hh" +#include "debug.hh" +#include "real.hh" +#include "symbol.hh" +#include "assoc.hh" +#include "assoc-iter.hh" +#include "symtable.hh" + +Symtables::Symtables() +{ +} + +Symtables::Symtables(Symtables const &s) +{ + for (Assoc_iter i(s); i.ok(); i++) { + add(i.key(), new Symtable(*i.val())); + } +} + +Symtables::~Symtables() +{ + for (Assoc_iter i(*this); i.ok(); i++) { + delete i.val(); + } +} + +Symbol +Symtable::lookup(String s) const +{ + if (elt_query(s)) + return (*this)[s]; + else { + error( "Unknown symbol `" +s+"'\n"); + } + Symbol sy; // unreachable + return sy; +} + +Symtable* +Symtables::operator()(String s) +{ + return Assoc::operator[](s); +} +void +Symtables::print() const +{ + for (Assoc_iter i(*this); i.ok(); i++) { + mtor << "table \'" << i.key() << "\' {\n"; + i.val()->print(); + mtor << "}\n"; + } +} +void +Symtable::print() const +{ + for (Assoc_iter i(*this); i.ok(); i++) { + mtor << "\'" << i.key() << "\'->" << i.val().str() << "\n"; + } +} + diff --git a/lily/template2.cc b/lily/template2.cc new file mode 100644 index 0000000000..0f581474c3 --- /dev/null +++ b/lily/template2.cc @@ -0,0 +1,27 @@ +/* + template2.cc -- instantiate some list templates. + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "symbol.hh" +#include "voice.hh" +#include "voice-element.hh" +#include "musicalrequest.hh" +#include "staff.hh" +#include "score-column.hh" +#include "staff-column.hh" +#include "spanner.hh" +#include "plist.tcc" +#include "pcursor.tcc" + +IPL_instantiate(Request); +IPL_instantiate(Score_column); +IPL_instantiate(Staff_column); +IPL_instantiate(Staff); +IPL_instantiate(Voice_element); +IPL_instantiate(Voice); + + diff --git a/lily/template3.cc b/lily/template3.cc new file mode 100644 index 0000000000..7df0ef372b --- /dev/null +++ b/lily/template3.cc @@ -0,0 +1,15 @@ +#include "request.hh" +#include "input-score.hh" +#include "input-staff.hh" +#include "input-music.hh" +#include "molecule.hh" +#include "source-file.hh" +#include "voice-element.hh" +#include "plist.tcc" +#include "pcursor.tcc" + +IPL_instantiate(Atom); +IPL_instantiate(Atom); +IPL_instantiate(Input_staff); +IPL_instantiate(Input_music); +IPL_instantiate(Source_file); diff --git a/lily/template4.cc b/lily/template4.cc new file mode 100644 index 0000000000..d26e748e6f --- /dev/null +++ b/lily/template4.cc @@ -0,0 +1,13 @@ +/* + template4.cc -- instantiate PointerList baseclass. + + source file of the LilyPond music typesetter + + (c) 1997 Han-Wen Nienhuys +*/ + +#include "proto.hh" +#include "list.tcc" +#include "cursor.tcc" + +L_instantiate(void *); diff --git a/lily/template5.cc b/lily/template5.cc new file mode 100644 index 0000000000..a1ab7e8df3 --- /dev/null +++ b/lily/template5.cc @@ -0,0 +1,9 @@ +#include "proto.hh" +#include "string.hh" +#include "moment.hh" +#include "real.hh" + +#include "interval.tcc" + +Interval__instantiate(Real); +Interval__instantiate(Rational); diff --git a/lily/template6.cc b/lily/template6.cc new file mode 100644 index 0000000000..0401c8cd93 --- /dev/null +++ b/lily/template6.cc @@ -0,0 +1,10 @@ +#include "proto.hh" +#include "plist.tcc" +#include "register.hh" +#include "voice-group-regs.hh" +#include "voice-regs.hh" + + +IPL_instantiate(Voice_registers); +IPL_instantiate(Voice_group_registers); +IPL_instantiate(Request_register); diff --git a/lily/tex-beam.cc b/lily/tex-beam.cc new file mode 100644 index 0000000000..c9f3c95481 --- /dev/null +++ b/lily/tex-beam.cc @@ -0,0 +1,106 @@ +/* + + Code to generate beams for TeX + + */ + +#include +#include "symbol.hh" +#include "molecule.hh" +#include "tex.hh" +#include "symtable.hh" +#include "dimen.hh" +#include "debug.hh" +#include "lookup.hh" + +Symbol +Lookup::beam_element(int sidx, int widx, Real slope) +{ + Symbol bs=(*symtables_)("beamslopes")->lookup("slope"); + + Array args; + args.push(sidx); + args.push(widx); + bs.tex = substitute_args(bs.tex,args); + int w = 2 << widx; + Real width = w PT; + bs.dim.x = Interval(0,width); + bs.dim.y = Interval(0,width*slope); + return bs; +} + +// ugh.. hard wired tex-code. +static int +slope_index(Real &s) +{ + if (abs(s) > 0.5) { + WARN << "beam steeper than 0.5 (" << s << ")\n"; + s = sign(s) * 0.5; + } + + int i = int(rint(s * 20.0)); + + s = i/20.0; + if (s>0) + return 6*i +122; + else + return -6 * i+ 186; +} + +Symbol +Lookup::rule_symbol(Real height, Real width) +{ + Symbol bs=(*symtables_)("beamslopes")->lookup("horizontal"); + Array args; + args.push(print_dimen(height)); + args.push(print_dimen(width)); + bs.tex = substitute_args(bs.tex,args); + bs.dim.x = Interval(0,width); + bs.dim.y = Interval(0,height); + return bs; +} + +Symbol +Lookup::beam(Real &slope, Real width) +{ + int sidx = slope_index(slope); + if (!slope) + return rule_symbol(2 PT, width); + if (width < 2 PT) { + WARN<<"Beam too narrow. (" << print_dimen(width) <<")\n"; + width = 2 PT; + } + Real elemwidth = 64 PT; + int widx = 5; + + Molecule m; + + while (elemwidth > width) { + widx --; + elemwidth /= 2.0; + } + Real overlap = elemwidth/4; + Real last_x = width - elemwidth; + Real x = overlap; + Atom elem(beam_element(sidx, widx, slope)); + Atom a(elem); + m.add(a); + while (x < last_x) { + a=elem; + a.translate(Offset(x-overlap, (x-overlap)*slope)); + m.add(a); + x += elemwidth - overlap; + } + a=elem; + a.translate(Offset(last_x, (last_x) * slope)); + m.add(a); + + Symbol ret; + ret.tex = m.TeXstring(); + ret.dim.y = Interval(0,width*slope); + ret.dim.x = Interval(0,width); + + return ret; +} + + diff --git a/lily/tex-slur.cc b/lily/tex-slur.cc new file mode 100644 index 0000000000..71cded9529 --- /dev/null +++ b/lily/tex-slur.cc @@ -0,0 +1,208 @@ +#include +#include "misc.hh" +#include "lookup.hh" +#include "molecule.hh" +#include "dimen.hh" +#include "debug.hh" + +static +char direction_char(int y_sign) +{ + char c='#'; + switch(y_sign){ + case -1: + c = 'd'; + break; + case 0: + c = 'h'; + break; + case 1: + c = 'u'; + break; + default: + assert(false); + } + return c; +} + +Symbol +Lookup::half_slur_middlepart(Real &dx, int dir) +{ + if (dx >= 400 PT) {// todo + WARN<<"halfslur too large" <= 96 PT) { + WARN << "Slur half too wide." << print_dimen(orig_dx) << " shrinking (ugh)\n"; + dx = 96 PT; + } + + widx = int(rint(dx/12.0)); + dx = widx*12.0; + if (widx) + widx --; + else { + WARN << "slur too narrow " << print_dimen(orig_dx)<<"\n"; + } + + Symbol s; + s.dim.x = Interval(0,dx); + s.dim.y = Interval(min(0,dy), max(0,dy)); + + + String f = String("\\hslurchar"); + + f+= direction_char(dir); + + int hidx = dy; + if (hidx <0) + hidx = -hidx; + hidx --; + int idx =-1; + + + idx = widx * 16 + hidx; + if (xpart < 0) + idx += 128; + + f+=String( "{" ) + String( idx ) + "}"; + + + s.tex = f; + + return s; +} + +Symbol +Lookup::slur (int dy , Real &dx, int dir) +{ + assert(dx >=0 && abs(dir) <= 1); + int y_sign = sign(dy); + + bool large = dy > 16; + + if (y_sign) { + large |= dx>= 4*16 PT; + } else + large |= dx>= 4*54 PT; + + if (large) { + return big_slur(dy, dx, dir); + } + Real orig_dx = dx; + int widx = int(floor(dx/4.0)); // slurs better too small.. + dx = 4.0 * widx; + if (widx) + widx --; + else { + WARN << "slur too narrow: " << print_dimen(orig_dx) << "\n"; + } + + int hidx = dy; + if (hidx <0) + hidx = -hidx; + hidx --; + if (hidx > 16) { + WARN<<"slur to steep: " << dy << " shrinking (ugh)\n"; + } + + Symbol s; + s.dim.x = Interval(0,dx); + s.dim.y = Interval(min(0,dy), max(0,dy)); + + String f = String("\\slurchar") + String( direction_char(y_sign) ); + + int idx=-1; + if (y_sign) { + idx = hidx * 16 + widx; + if (dir < 0) + idx += 128; + } else { + if (dx >= 4*54 PT) { + WARN << "slur too wide: " << print_dimen(dx) << + " shrinking (ugh)\n"; + dx = 4*54 PT; + } + idx = widx; + if (dir < 0) + idx += 54; + } + + f+=String( "{" ) + String( idx ) + "}"; + s.tex = f; + + Atom a(s); + a.translate(Offset(dx/2,0)); + s.dim = a.extent(); + s.tex = a.TeXstring(); + return s; +} + +Symbol +Lookup::big_slur(int dy , Real &dx, int dir) +{ + assert(dx >= 24 PT); + Real slur_extra =abs(dy) /2.0 + 2; + int l_dy = int(Real (dy)/2 + slur_extra*dir); + int r_dy = dy - l_dy; + + Real left_wid = dx/4.0; + Real right_wid = left_wid; + + Atom l = half_slur(l_dy, left_wid, dir, -1); + Atom r = half_slur(r_dy, right_wid, dir, 1); + Real mid_wid = dx - left_wid - right_wid; + + Atom m = half_slur(0, mid_wid, dir, 0); + + Molecule mol; + mol.add(l); + Atom a(m); + a.translate(Offset(0,slur_extra * internote())); + mol.add_right(m); + mol.add_right(r); + mol.translate(Offset(0, l_dy * internote())); + Symbol s; + s.tex = mol.TeXstring(); + s.dim = mol.extent(); + return s; +} + + diff --git a/lily/tex.cc b/lily/tex.cc new file mode 100644 index 0000000000..e8349e63cc --- /dev/null +++ b/lily/tex.cc @@ -0,0 +1,44 @@ +#include "dimen.hh" +#include "tex.hh" +#include "symbol.hh" +#include "const.hh" +#include "varray.hh" + +String +vstrut(Real h) +{ + return String("\\vrule height ") + print_dimen(h) + "depth 0pt width 0pt"; +} + + +static void +substitute_arg(String& r, String arg) +{ + int p = r.index_i('%'); + if (p < 0) + return ; + + r = r.left_str(p) + arg + r.right_str(r.length_i() - p -1); +} + + +String +substitute_args(String source, Array args) +{ + String retval (source); + for (int i = 0 ; i < args.size(); i++) + substitute_arg(retval, args[i]); + while (retval.index_i('%') >= 0) + substitute_arg(retval, ""); + return retval; +} + +String +substitute_args(String source, Array args) +{ + Array sv; + for (int i = 0 ; i < args.size(); i++) + sv.push(args[i]); + + return substitute_args(source, sv); +} diff --git a/lily/text-def.cc b/lily/text-def.cc new file mode 100644 index 0000000000..d67622e141 --- /dev/null +++ b/lily/text-def.cc @@ -0,0 +1,31 @@ +#include "debug.hh" +#include "lookup.hh" +#include "paper-def.hh" +#include "molecule.hh" +#include "text-def.hh" + +Text_def::Text_def() +{ + align_i_ = 1; // right + style_str_ = "roman"; + defined_ch_c_l_ = 0; +} +bool +Text_def::compare(const Text_def&def) +{ + return align_i_ == def.align_i_ && text_str_ == def.text_str_ + && style_str_ == def.style_str_; +} + +Atom +Text_def::create_atom(Paper_def*p) const +{ + return p->lookup_p_->text(style_str_, text_str_, -align_i_); +} + +void +Text_def::print() const +{ + mtor << "Text `" << text_str_ << "\', style " << + style_str_ << "align " << align_i_ << '\n'; +} diff --git a/lily/version.cc b/lily/version.cc new file mode 100644 index 0000000000..b2a57def4a --- /dev/null +++ b/lily/version.cc @@ -0,0 +1,11 @@ +#include "version.hh" +#include "fversion.hh" + +static char *s = "LilyPond " VERSIONSTR "/FlowerLib " FVERSIONSTR +". Compile: " __DATE__ ", " __TIME__ " (" COMPILER ")\n"; + +const char * +get_version() +{ + return s; +} diff --git a/lily/wordwrap.cc b/lily/wordwrap.cc new file mode 100644 index 0000000000..f217a63b08 --- /dev/null +++ b/lily/wordwrap.cc @@ -0,0 +1,78 @@ +#include "break.hh" +#include "pscore.hh" +#include "debug.hh" + +/** el stupido. This should be done more accurately: + + It would be nice to have a Dynamic Programming type of algorithm + similar to TeX's + + */ +Array +Word_wrap::solve() +{ + problem_OK(); + iter_top(pscore_.cols,curcol); + Array breaking; + Line_of_cols breakpoints(find_breaks()); + assert(breakpoints.size()>=2); + + int break_idx_i=0; + while ( break_idx_i < breakpoints.size() -1) { + Col_hpositions minimum; + Col_hpositions current; + + // do another line + PCol *post = breakpoints[break_idx_i]->postbreak_p_; + current.add( post); + curcol++; // skip the breakable. + break_idx_i++; + + while (break_idx_i < breakpoints.size()) { + + // add another measure. + while (breakpoints[break_idx_i] != curcol.ptr()){ + current.add(curcol); + curcol++; + } + current.add(breakpoints[break_idx_i]->prebreak_p_ ); + + // try to solve + if (!feasible(current.cols)) { + if (!minimum.cols.size()) + error("sorry, this measure is too long, breakpoint: " + + String(break_idx_i) ); + current.energy = INFTY; // make sure we go back + } else { + current = solve_line(current.cols); + current.print(); + } + + // update minimum, or backup. + if (current.energy < minimum.energy) { + minimum = current; + } else { // we're one col too far. + break_idx_i--; + while (curcol.ptr() != breakpoints[break_idx_i]) + curcol --; + break; // do the next line. + } + + + // add nobreak version of breakable column + current.cols.top()=breakpoints[break_idx_i]; + curcol ++; + break_idx_i++; + } + + *mlog << "[" <