/**************************************************************************** PROJECT: MusixTeX PreProcessor FILE : score.cc AUTHOR : J. C. Nieuwenhuizen copyright (c) FlowerSoft 1995 --*/ #define max(a,b) ( ( ( a ) > ( b ) ) ? (a) : ( b ) ) #define min(a,b) ( ( ( a ) < ( b ) ) ? (a) : ( b ) ) #define abs(a) ( ( ( a ) > 0 ) ? ( a ) : ( -( a ) ) ) #define sign(a) ( ( ( a ) > 0 ) ? ( 1 ) : ( -1 ) ) #if !defined( SCORE1 ) && !defined( SCORE2 ) #define SCORE0 #endif #if 1 // def __unix__ #define SCORE1 #define SCORE2 #endif #include #include #include "init.h" #include "mpp.h" #ifdef SCORE1 #include #include #include // memset class Staff; //#include "gciterate.h" #include "duration.h" #include "key.h" // execute #include "clef.h" // barToken #include "bar.h" #include "maclist.h" #endif #include "score.h" /**************************************************************************** class Score --*/ #ifdef SCORE0 Score::Score( const char* name ) : codeFile( 0 ), outName( name ), StaffList() { if ( !outName.len() || ( outName[ 0 ] == '-' ) ) { // ::error( "output to stdout not implemented", __FILE__, __LINE__ ); outName = "stdout"; codeFile = &_cout; cout = cnull; } else codeFile = new ofstream( outName ); if ( !*codeFile ) error( quoteString( "can't create", outName ), __FILE__, __LINE__ ); } Score::~Score() { #if 0 if ( codeFile ) delete codeFile; #endif } void Score::doFooter() { if ( !( mode & EXTRACT ) ) { *codeFile << "\\endpiece" << endl; *codeFile << "\\endmuflex" << endl; *codeFile << "\\end" << endl; } else *codeFile << "\\endextract" << endl; } void Score::doHeader() { *codeFile << "% MusiXTeX Source created by mpp "; time_t now = time( 0 ); *codeFile << asctime( localtime( &now ) ); *codeFile << "% File: " << outName << endl; *codeFile << "% From: "; ScoreIterator staffs( *this ); while ( staffs ) { Staff& staff = staffs++; if ( staff.instrumentStaff && staffs ) { *codeFile << '('; *codeFile << (const char*)staff.inName; *codeFile << ", "; *codeFile << (const char*)staffs++.inName; *codeFile << ')'; } else *codeFile << (const char*)staff.inName; // if ( &staffs() != &NOSTAFF ) if ( staffs ) *codeFile << ", "; } *codeFile << endl; *codeFile << '%' << endl; if ( !( mode & EXTRACT ) ) { // *codeFile << "\\input mpp" << endl; // *codeFile << "\\input " << execPrefix << "mpp" << endl; String macrosName = execPrefix; macrosName += "mpp.tex"; ifstream macrosFile( macrosName ); if ( !macrosFile ) error( quoteString( "can't open", macrosName ), __FILE__, __LINE__ ); char c; while ( ( c = macrosFile.get() ) != (char)EOF ) codeFile->put( c ); *codeFile << '%' << endl; } *codeFile << "\\instrumentnumber"; *codeFile << '{' << Staff::instrumentCount << '}' << endl; *codeFile << '%' << endl; // reversed order staffs.reset(); while ( staffs ) { Staff& staff = staffs++; Staff& nextStaff = staffs(); if ( ( &nextStaff != &NOSTAFF ) && ( staff.instrumentNumber == nextStaff.instrumentNumber ) ) { *codeFile << "\\setstaffs" << ( staff.instrumentNumber + 1 ); *codeFile << '{' << ( staff.instrumentStaff + 1 ) << '}' << endl; *codeFile << '%' << endl; staffs++; } else { *codeFile << "\\setstaffs" << ( staff.instrumentNumber + 1 ); *codeFile << '{' << ( staff.instrumentStaff + 1 ) << '}' << endl; *codeFile << '%' << endl; } } #if 0 \setname1{Piano} \setsign1{-3} \interstaff{11} #endif *codeFile << "\\def\\thetitle{" << bottom().inName << '}' << endl; *codeFile << '%' << endl; each( Staff::invokeDoMacros, (void*)(ostream*)codeFile ); *codeFile << '%' << endl; if ( !( mode & EXTRACT ) ) { // to be moved to titles.tex? // \def\titles{\blah} // cod << "\\titles"; *codeFile << "\\hbox to\\hsize{{\\hfill\\BIGtype\\bf\\thetitle\\hfill}}" << endl; *codeFile << "\\medskip\\medskip" << endl; *codeFile << "\\hbox to\\hsize{{\\hfill\\Bigtype\\thesubtitle\\hfill}}" << endl; *codeFile << "\\medskip" << endl; *codeFile << "\\hbox to\\hsize{{\\hfill\\bigtype\\bf\\therighttitle\\thecomposer}}" << endl; *codeFile << "\\hbox to\\hsize{{\\hfill\\eightrm typeset by MusixTeX}}" << endl; // *codeFile << "\\hbox to\\hsize{{\\hfill\\eightrm and mpp}}" << endl; *codeFile << "\\hbox to\\hsize{{\\hfill\\eightrm and music2tex}}" << endl; *codeFile << "\\medskip" << endl; *codeFile << "\\hbox to\\hsize{{\\hskip20mm\\bigtype\\bf\\thelefttitle\\hskip6mm" << endl; *codeFile << "\\medtype\\rm\\thetempo\\hskip6mm" << endl; *codeFile << "\\ifx\\themetron\\empty\\else\\raise.2ex" << endl; *codeFile << "\\hbox{\\medtype\\rm\\Notes\\expandafter\\metron\\themetron\\en}\\fi\\hfill}}" << endl; *codeFile << "\\bigskip" << endl; *codeFile << '%' << endl; *codeFile << "\\startmuflex" << endl; *codeFile << '%' << endl; } if ( Staff::instrumentCount > 2 ) { *codeFile << "\\vsize280mm" << endl; *codeFile << "\\voffset-20mm" << endl; *codeFile << "\\smallmusicsize" << endl; *codeFile << "\\def\\ppffstyle{\\ppffsixteen}" << endl; *codeFile << "\\def\\directstyle{\\tenit}" << endl; *codeFile << "\\def\\xpletstyle{\\eightit}" << endl; } else { *codeFile << "\\normalmusicsize" << endl; *codeFile << "\\def\\ppffstyle{\\ppfftwenty}" << endl; *codeFile << "\\def\\directstyle{\\twelveit}" << endl; *codeFile << "\\def\\xpletstyle{\\tenit}" << endl; } *codeFile << "\\ppff" << endl; *codeFile << '%' << endl; if ( !( mode & EXTRACT ) ) *codeFile << "\\startpiece" << endl; else { *codeFile << "\\let\\endpiece\\endextract" << endl; *codeFile << "\\startextract" << endl; } *codeFile << "\\addspace\\afterruleskip" << endl; } #endif // SCORE1 // #ifdef SCORE1 //declare( ConstIterator, Staff ); // checks duration of each bar (vertically), prints warning void Score::checkBarDuration() { ScoreIterator staffs( *this ); // genericStaffConstIterator staffs( *this ); while ( staffs ) { Staff& staff = staffs++; int leftOver = staff.duration - Staff::barDuration; if ( leftOver ) { char buf[ 81 ]; memset( buf, 0, 80 ); ostrstream oss( (char*)buf, 80 ); oss << Duration( abs( leftOver ) ) << ends; // El Weirdo string<->ostrstream String warn = "bar "; warn += String( staff.barCount ); warn += ( leftOver > 0 ? " overfull: " : " underfull: " ); warn += oss.str(); warn += leftOver > 0 ? " over" : " missing"; staff.warning( warn ); } staff.duration = 0; } } /* shortest note (vertically). Serves indication to each staff if it can print a new note */ int Score::getShortest() { int shortest = DURATION_WHOLE; ScoreIterator staffs( *this ); // genericStaffConstIterator staffs( *this ); while ( staffs ) { Staff& staff = staffs++; int duration = staff.getDuration(); shortest = min( shortest, abs( duration ) ); } return shortest; } /* some notes need more space (accidentals) each staff needs to know the current spacing (which is the widest (hor.) of all notes which are output */ int Score::getSpacing( int lastSpacing ) { int largest = 0; ScoreIterator staffs( *this ); // genericStaffConstIterator staffs( *this ); while ( staffs ) { Staff& staff = staffs++; int spacing = staff.getSpacing( lastSpacing ); if ( spacing > largest ) largest = spacing; } return largest; } /* non const printOn */ void Score::printBarOn( ostream& os )// (const) { ;// monitor << "Score::printBarOn" << endl; ScoreIterator staffs( *this ); // genericStaffConstIterator staffs( *this ); int shortest = 0; // while notes in (first) bar // bottom is just a member of the list (could have been top()) while ( bottom().getDuration() ) { each( Staff::invokePrintMacros, &os ); ;// monitor << "lastShortest:" << shortest << endl; int signSpacing = getSpacing( shortest ); // note spacing according to shortest note shortest = getShortest(); Duration durationSpacing( shortest ); os << durationSpacing.spacing(); staffs.reset(); /* stafflist ordered bottom to top... */ while ( staffs ) { Staff& staff = staffs++; staff.printSpacing( os, signSpacing ); // print some whitespace // print as many notes as possible in "shortest" duration. // (only one can be printed, actually) staff.printDuration( os, shortest ); // and fill to fit available space } os << "\\en%" << endl; } // (global) macros from a score are supposed to be in // bottom bar . if ( bottom().bar ) { os << bottom().bar->macroList; // os << endl << '%'; if ( bottom().bar->barToken ) os << *bottom().bar->barToken << '%' << endl; #if 0 if ( Staff::changeContext ) { *codeFile << "\\zchangecontext\n"; Staff::changeContext = 0; } #endif } else os << "\\bar" << endl; if ( Staff::barDuration ) checkBarDuration(); } /* */ void Score::process() { doHeader(); // input header, output header int _eof = 0; // progress indicator Staff::barCount = 1; do { cout << '[' << flush; int readBar = 0; ScoreIterator staffs( *this ); while ( staffs ) // get one bar from each file { Staff& staff = staffs++; staff.getBar(); if ( !staff.bar ) staff.error( "Score::process: no bar" ); ;// monitor << "before readBar [" << Staff::barCount << ']' << endl; if ( staff.bar->count() ) readBar = 1; ;// monitor << "after readBar" << endl; } cout << Staff::barCount++ << flush; if ( readBar ) // calc & print { each( Staff::invokeCalculate ); printBarOn( *codeFile ); } cout << "] " << flush; *codeFile << '%' << endl; staffs.reset(); while ( staffs ) { Staff& staff = staffs++; WhiteSpace ws( staff ); // eat space _eof = _eof || ( ws.length < 0 ); #if 1 if ( staff.newKey ) { staff.key = staff.newKey; staff.newKey = 0; staff.key->execute( *(StringList*)ZERO, staff ); } #endif } if ( Staff::newBarDuration ) // new meter { Staff::barDuration = Staff::newBarDuration; Staff::newBarDuration = 0; } } while ( !_eof ); // if ( staff._eoBar ) // staff.warning( "unexpected end of file" ); doFooter(); cout << " -> " << outName << endl; #if 0 //def __TURBOC__ // safe exit to dos error( "Using Turbo C", __FILE__, __LINE__ ); #endif } //-- class Score // #endif // SCORE1 //