/**************************************************************************** PROJECT: MusixTeX PreProcessor FILE : beam.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 ) ) #include #include "intlist.h" #include "notename.h" #include "duration.h" #include "interval.h" #include "beam.h" #include "slur.h" #include "init.h" #include "staff.h" #include "mpp.h" //#define TRIPLET 1 /**************************************************************************** class InitiateBeam --*/ const int InitiateBeam::MAXCORRECT = 12; const int InitiateBeam::NORMALSLOPE = 2; const int InitiateBeam::NORMALNOTESKIP = 10; const int InitiateBeam::NORMALSTEM = 4; int InitiateBeam::minimumStem = InitiateBeam::NORMALSTEM; int InitiateBeam::slopeFactor = InitiateBeam::NORMALSLOPE; // MusiXTeX does not make beams steep enough int InitiateBeam::noteSkipFactor = 2 * InitiateBeam::NORMALNOTESKIP; InitiateBeam& InitiateBeam::getInitiateBeam( Staff& staff ) { WhiteSpace ws( staff ); char c = staff.is->peek(); if ( c == '[' ) return *new InitiateBeam( staff ); else return NOBEAM; } InitiateBeam::InitiateBeam( Staff& s ) : mother( NOBEAM ), multiplicity( 1 ), noPrint( 0 ), nPlet( 1 ), noteCount( 0 ), noteStart( staff.noteCount ), number( staff.number ), pitch( 0 ), pitchList( *new IntegerList() ), slope( 0 ), slopeCalculation( 1 ), staff( s ), Initiator( "InitiateBeam" ) { ;// monitor << "InitiateBeam" << endl; istream& is = *staff.is; staff.expect( '[' ); char c; is.get( c ); c = is.peek(); if ( isdigit( c ) ) { is.get( c ); number = int( c - '0' ); number--; if ( number != staff.number ) noPrint = 1; c = is.peek(); } staff.beamCount++; switch( c ) { case '^' : is.get( c ); orientation = UP; break; case 'v' : is.get( c ); orientation = DOWN; break; default : orientation = UNDEFINED; if ( *staff.slur != NOSLUR ) orientation = Orientation( -staff.slur->orientation ); } staff.beam = this; } InitiateBeam::InitiateBeam( InitiateBeam& m ) : mother( m ), multiplicity( 1 ), noPrint( 0 ), nPlet( 1 ), noteCount( 0 ), noteStart( staff.noteCount ), number( staff.number ), orientation( mother.orientation ), pitch( 0 ), pitchList( *new IntegerList() ), slope( 0 ), slopeCalculation( 1 ), staff( m.staff ), Initiator( "InitiateBeam" ) { ;// monitor << "InitiateBeam1" << endl; if ( mother == NOBEAM ) staff.error( "InitiateBeam: no beam" ); staff.beam = this; } InitiateBeam::~InitiateBeam() { delete &pitchList; } void InitiateBeam::addPitch( int pitch ) { ;// monitor << "InitiateBeam::addPitch" << pitch << endl; noteCount++; pitchList.put( *new Integer ( pitch ) ); } void InitiateBeam::calculate() { ;// monitor << "InitiateBeam::calculate" << endl; ;// monitor << '(' << (int)pitchList.top() << ',' << (int)pitchList.bottom() << ')'; #ifdef TRIPLET if ( mother != NOBEAM ) { mother.nPlet = nPlet; mother.calculate(); } #endif if ( orientation == UNDEFINED ) calculateOrientation(); if ( slopeCalculation ) calculateSlope(); calculatePitch(); ;// monitor << '(' << pitch << ',' << slope << ')' << endl; } void InitiateBeam::calculateOrientation() { int generalOrientation = - pitchList.count() * staff.midPitch; pitchList.each( Integer::sum, &generalOrientation ); orientation = ( generalOrientation > 0 ? DOWN : UP ); } void InitiateBeam::calculatePitch() { IntegerListIterator pitches( pitchList ); pitch = pitchList.top(); for( int noteCount = 1 ; pitches; noteCount++ ) { ;// monitor << '.' << flush; int notePitch = pitches++; int correctionCount = 0; // while ( ( effectivePitch( i ) - p + BEAM_NORMALSTEM < minimumStem ) && ( j < BEAM_MAXCORRECT ) ) // while ( ( p - effectivePitch( i ) + BEAM_NORMALSTEM < minimumStem ) && ( j < BEAM_MAXCORRECT ) ) while ( ( orientation * ( effectivePitch( noteCount ) - notePitch ) + NORMALSTEM < minimumStem ) && ( correctionCount < MAXCORRECT ) ) { ;// monitor << "+(" << notePitch << ';' << pitch << ',' << effectivePitch( noteCount ) << ')' << flush; pitch += orientation; correctionCount++; } if ( correctionCount >= MAXCORRECT ) slope = 0; } if ( ( pitch < 0 ) || ( pitch > 8 * 7 ) ) pitch = 0; } void InitiateBeam::calculateSlope() { if ( ( noteCount > 1 ) && ( pitchList.count() > 1 ) ) slope = slopeFactor * ( pitchList.bottom() - pitchList.top() ) / ( pitchList.count() - 1 ); slope = min( 9 , max( - 9, slope ) ); } int InitiateBeam::effectivePitch( const int n ) const { if ( !slope ) return pitch; else { int pitches = slope * ( n - 1 ); pitches /= slopeFactor; return max( pitches + pitch, 0 ); } } int InitiateBeam::musixSlope() const { int noteSkip = staff.noteCount2NoteSkip( Interval( noteStart, noteCount ) ); // == 3 for eight notes // == 2 for sixteenth if ( !noteSkip ) { noteSkip = 3; staff.warning( "zero noteSkip" ); } #if 0 int correction = 3 * noteCount / noteSkip; // should (again!) increase first stemlength if too steep return min( correction * slope, 9 ); #else int correction; if ( noteCount ) correction = max( noteSkip / noteCount / 2, 1 ); else correction = 0; return slope / correction; #endif } /* The macros \keyindex{butext} and \keyindex{bltext} are helpful to indicate triplets and others. You can change what it contains by redefining the macro \keyindex{txt} which is set up by UNDEFINED to: \verb|\def\txt{\eightit 3}%| */ #define MUSIXBEAM 1 #ifndef MUSIXBEAM void InitiateBeam::printOn( ostream& os ) const { ;// monitor << "InitiateBeam::printOn" << endl; if ( noPrint ) //yak return; os << "\\ib"; os << ( orientation == UP ? 'u' : 'l' ); os << number; os << '{' << NoteName( pitch ) << '}'; os << '{' << musixSlope() << '}'; } #else // MUSIXBEAM void InitiateBeam::printOn( ostream& os ) const { ;// monitor << "InitiateBeam::printOn" << endl; if ( noPrint ) return; os << "\\Ib"; os << ( orientation == UP ? 'u' : 'l' ); os << number; os << '{' << NoteName( pitch ) << '}'; // steeper if more notes os << '{' << NoteName( effectivePitch( noteCount * noteSkipFactor / NORMALNOTESKIP ) ) << '}'; os << '{' << staff.noteCount2NoteSkip( Interval( noteStart, noteCount ) ) << '}'; } #endif // MUSIXBEAM void InitiateBeam::setSlope( int s ) { slope = s; slopeCalculation = 0; } //-- class InitiateBeam // /**************************************************************************** class TerminateBeam --*/ TerminateBeam& TerminateBeam::getTerminateBeam( Staff& staff ) { WhiteSpace ws( staff ); char c = staff.is->peek(); if ( c == ']' ) return *new TerminateBeam( staff ); else return NOTERMINATEBEAM; } TerminateBeam::TerminateBeam( Staff& s ) : mother( *staff.beam ), noPrint( 0 ), number( staff.number ), staff( s ), Terminator( "TerminateBeam" ) { ;// monitor << "TerminateBeam" << endl; istream& is = *staff.is; staff.expect( ']' ); char c; is.get( c ); c = is.peek(); if ( isdigit( c ) ) { is.get( c ); number = int( c - '0' ); number--; if ( number == staff.number ) noPrint = 1; c = is.peek(); } if ( ( number == staff.number ) && mother.multiplicity ) { if ( staff.beamCount < 1 ) staff.error( "unexpected `]\'" ); else staff.beamCount--; } switch( c ) { case '^' : is.get( c ); orientation = UP; break; case 'v' : is.get( c ); orientation = DOWN; break; default : orientation = UNDEFINED; if ( mother != NOBEAM ) { #ifdef TRIPLET #else mother.calculate(); #endif orientation = mother.orientation; } break; } c = is.peek(); if ( mother != NOBEAM ) { mother.nPlet = Duration::getNPletFrom( staff ); // mother.multiplicity = 0; mother.multiplicity = 1; } else staff.warning( "TerminateBeam: no mother" ); #ifdef TRIPLET // nasty [ 4 4 r ]/3 patch if ( mother != NOBEAM ) mother.calculate(); #else if ( !staff.beamCount ) staff.beam = ZEROBEAM; #endif } TerminateBeam::TerminateBeam( InitiateBeam& m ) : mother( m ), noPrint( mother.noPrint ), number( mother.number ), // number( m.staff.number ), // for testing // orientation( mother.orientation ), orientation( UNDEFINED ), staff( m.staff ), Terminator( "TerminateBeam" ) { ;// monitor << "TerminateBeam1" << endl; if ( mother == NOBEAM ) staff.error( "TerminateBeam: no beam" ); mother.multiplicity = 0; } TerminateBeam::~TerminateBeam() { ;// monitor << "~TerminateBeam"; if ( !staff.beamCount ) staff.beam = ZEROBEAM; } void TerminateBeam::printOn( ostream& os ) const { if ( noPrint ) return; os << "\\tb"; #ifdef TRIPLET if ( orientation ) os << ( orientation == UP ? 'u' : 'l' ); else os << ( mother.orientation == UP ? 'u' : 'l' ); #else os << ( orientation == UP ? 'u' : 'l' ); #endif os << number; } //-- class TerminateBeam // /**************************************************************************** class InitMultiBeam --*/ InitMultiBeam::InitMultiBeam( InitiateBeam& m, int mult, NESTED_IN( InitiateBeam)Flag single ) : mother( m ), multiplicity( mult ), singleFlag( single ), Initiator( "InitMultiBeam" ) { if ( mother == NOBEAM ) error( "no beam", __FILE__, __LINE__ ); mother.multiplicity = multiplicity; } InitMultiBeam::~InitMultiBeam() { } void InitMultiBeam::printOn( ostream& os ) const { if ( singleFlag ) os << "\\loff"; //// os << "\\loffset{" << singleFlag << "}"; os << "{\\n"; os << String( 'b', multiplicity ); os << ( mother.orientation == UP ? 'u' : 'l' ); os << mother.number; os << '}'; } //-- class InitMultiBeam // /**************************************************************************** class TermMultiBeam --*/ TermMultiBeam::TermMultiBeam( InitiateBeam& m, int mult, NESTED_IN( InitiateBeam )Flag single ) : mother( m ), multiplicity( mult ), singleFlag( single ), Terminator( "TermMultiBeam" ) { if ( mother == NOBEAM ) error( "no beam", __FILE__, __LINE__ ); if ( multiplicity < 1 ) mother.staff.warning( "TermMultiBeam: zero multiplicity" ); mother.multiplicity = multiplicity; #if 0 if ( !multiplicity ) { if ( mother.staff.beamCount < 1 ) mother.staff.error( "unexpected `]\'" ); mother.staff.beamCount--; } #endif } TermMultiBeam::~TermMultiBeam() { } void TermMultiBeam::printOn( ostream& os ) const { if ( singleFlag ) // InitiateBeam::LEFT == 2 RIGHT == 1 // there is a discrepancy between before // and after musixflex beams... // always run musixflex! os << "\\loffset{2}"; // os << "\\loffset{" << singleFlag << "}"; os << "{\\t"; os << String( 'b', multiplicity + 1 ); os << ( mother.orientation == UP ? 'u' : 'l' ); os << mother.number; os << '}'; } //-- class TermMultiBeam //