/**************************************************************************** PROJECT: MusixTeX PreProcessor FILE : simpnote.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 ) ) #include "notename.h" #include "duration.h" #include "beamlist.h" #include "featlist.h" #include "maclist.h" #include "slurlist.h" #include "beamnote.h" //#include "strike.h" //#include "cresc.h" //#include "init.h" #include "staff.h" //#include "mpp.h" static Duration duration4( 4 ); static int ord4 = duration4.ord(); static Duration whole( 1 ); static int ordWhole = whole.ord(); //#define TRIPLET 1 #if !defined( SIMPLENOTE1 ) && !defined( SIMPLENOTE2 ) #define SIMPLENOTE0 #endif #if 1 // def __unix__ #define SIMPLENOTE1 #define SIMPLENOTE2 #endif #ifdef SIMPLENOTE0 /**************************************************************************** class SimpleNote --*/ //static int featurePitchAdjustInitArray[ 3 ] = { 0, 0, 0 }; #include "cresc.h" /* Important */ //static SimpleNote& SimpleNote::getSimpleNote( Staff& staff ) { // should also try to read cresc.list everywhere MacroList macroList( staff ); BeamList beamList( staff ); macroList.putList( MacroList( staff ) ); FeatureList crescendoList; //"genericFeatureList ()" --!--> "g...List" InitiateCrescendo* crescendo = &InitiateCrescendo::getCrescendo( staff ); while ( *crescendo != NOCRESCENDO ) { crescendoList.put( *crescendo ); crescendo = &InitiateCrescendo::getCrescendo( staff ); } macroList.putList( MacroList( staff ) ); TerminateSlurList terminateSlurList( staff ); macroList.putList( MacroList( staff ) ); // this will read [accidental], name, duration, features SimpleNote scratchNote( staff ); #ifdef TRIPLET // nasty [ 4 4 r ]/3 patch int nobeam = 0; if ( ( scratchNote.beam != NOBEAM ) && ( *staff.beam == NOBEAM ) ) { staff.beam = &scratchNote.beam; nobeam = 1; } if ( staff.beamCount && ( ( scratchNote.stem == DEFAULT ) || ( scratchNote.stem & BEAM ) ) ) { if ( ( scratchNote._duration.ord() > ord4 ) && ( scratchNote.pitch() >= 0 ) ) { if ( !scratchNote.beam.multiplicity ) scratchNote.terminateBeamList.insert( *new InitiateBeam( scratchNote.beam ) ); } } #endif // simplenote is also construct for reading all kinds of notes // no need to check chords, done note::something SimpleNote* note; if ( scratchNote.pitch() == Rest::_pitch ) note = new Rest( scratchNote ); else if ( scratchNote.pitch() == GhostNote::_pitch ) note = new GhostNote( scratchNote ); else if ( scratchNote.stem == BEAM ) note = new BeamNote( scratchNote ); else note = new SimpleNote( scratchNote ); #ifdef TRIPLET // nasty [ 4 4 r ]/3 patch if ( nobeam) staff.beam = &NOBEAM; if ( ( staff.beamCount ) && ( ( note->_duration.ord() <= ord4 ) || ( note->pitch() < 0 ) ) ) if ( note->beam.multiplicity && !note->chord ) { if ( note->terminateBeamList.empty() ) beamList.put( *new TerminateBeam( *staff.beam ) ); // if ( !note->beam.noteCount ) if ( !note->beam.multiplicity ) { note->beam.noPrint = 1; ( (TerminateBeam&)beamList.bottom() ).noPrint = 1; } } if ( ( note->beam != NOBEAM ) && !note->chord && !note->terminateBeamList.empty() && ( ( note->_duration.ord() <= ord4 ) || ( note->pitch() < 0 ) ) ) ( (TerminateBeam&)note->terminateBeamList.bottom() ).noPrint = 1; #endif note->beamList.putList( beamList ); note->macroList.putList( macroList ); note->terminateSlurList.putList( terminateSlurList ); note->crescendoList.putList( crescendoList ); return *note; } #endif //SIMPLENOTE0 #ifdef SIMPLENOTE1 SimpleNote::SimpleNote( const SimpleNote& note ) : Note( note ), #ifdef TRIPLET // nasty [ 4 4 r ]/3 patch beam( ( *staff.beam != NOBEAM ? *staff.beam : note.beam ) ), #else beam( note.beam ), #endif beamList( *new BeamList( note.beamList ) ), beamNumber( note.beamNumber ), crescendoList( *new FeatureList( note.crescendoList ) ), featureList( *new FeatureList( note.featureList ) ), // Expression expected // featurePitchArray( { 0, 0, 0 } ), // Cannot initialize 'int[ 3 ]' with 'int' // featurePitchArray( 0, 0, 0 ), // member "SimpleNote::featurePitchArray" // may not be initialized // featurePitchArray( featurePitchAdjustInitArray ), featurePitch( &featurePitchArray[ 1 ] ), _duration( *new Duration( note._duration ) ), name( *new NoteName( note.name ) ), orientation( note.orientation ), signShift( note.signShift ), slurList( *new SlurList( note.slurList ) ), stem( note.stem ), style( note.style ), terminateBeamList( *new TerminateBeamList( note.terminateBeamList ) ), terminateSlurList( *new TerminateSlurList( note.terminateSlurList ) ) { featurePitchArray[ 0 ] = 0; featurePitchArray[ 1 ] = 0; featurePitchArray[ 2 ] = 0; } /* "scratch" note */ /* while you're reading, don't forget to visit the Eindhovens Jongeren Ensemble Scratch day 1996 */ SimpleNote::SimpleNote( Staff& staff ) : Note( staff ), beam( *staff.beam ), beamList( *new BeamList() ), beamNumber( staff.number ), crescendoList( *new FeatureList() ), featureList( *new FeatureList() ), // featurePitchArray( featurePitchAdjustInitArray ), featurePitch( &featurePitchArray[ 1 ] ), _duration( *new Duration( staff ) ), name( *new NoteName( staff ) ), orientation( UNDEFINED ), signShift( 0 ), slurList( *new SlurList() ), stem( DEFAULT ), style( Style( staff.style ) ), terminateBeamList( *new TerminateBeamList() ), terminateSlurList( *new TerminateSlurList() ) { featurePitchArray[ 0 ] = 0; featurePitchArray[ 1 ] = 0; featurePitchArray[ 2 ] = 0; Feature* feature; while ( *( feature = &Feature::getFeature( staff, *this ) ) != NOFEATURE ) { feature->execute( *this ); if ( feature->substitute == "" ) { delete feature; } else featureList.put( *feature ); } if ( staff.beamCount && ( ( stem == DEFAULT ) || ( stem & BEAM ) ) ) { if ( ( _duration.ord() > ord4 ) && ( pitch() >= 0 ) ) { stem = BEAM; // must be done before beam.calculate // which might ( still ) occur while // reading the terminate beam beam.addPitch( pitch() ); } #if 0 // def TRIPLET // nasty [ 4 4 r ]/3 patch else beam.noteCount++; #endif } istream& is = *staff.is; WhiteSpace ws( staff ); char c = is.peek(); if ( ( c != '\\' ) && ( c != '|' ) && ( c!= ':' ) ) { macroList.putList( MacroList( staff ) ); slurList.putList( SlurList( staff ) ); macroList.putList( MacroList( staff ) ); terminateBeamList.putList( TerminateBeamList( staff ) ); } } SimpleNote::~SimpleNote() { ;// monitor << "~SimpleNote"; delete &beamList; delete &_duration; delete &crescendoList; delete &featureList; delete &name; delete &slurList; delete &terminateBeamList; delete &terminateSlurList; } #endif //SIMPLENOTE1 #ifdef SIMPLENOTE2 #include "strike.h" void SimpleNote::calculate() { ;// monitor << "SimpleNote::calculate" << endl; calculateStem(); // invoked by Chord too, without checking; calculateFeaturePitch(); if ( !slurList.empty() && !terminateSlurList.empty() ) if ( ( (InitiateSlur&)slurList.top() ).orientation == ( (TerminateSlur&) terminateSlurList.top() ).orientation ) ( (InitiateSlur&)slurList.top() ).pitchAdjust -= ( (InitiateSlur&)slurList.top() ).orientation; // merge featureList and slurLists // only if one of lists not empty if ( !featureList.empty() || !slurList.empty() || !terminateSlurList.empty() ) { // move featureList to features FeatureList features( featureList ); while ( !features.empty() && // features and accents first ( ( features.top().type == Feature::ACCENT ) || ( features.top().type == Feature::FEATURE ) ) ) featureList.put( features.get() ); // then slurs featureList.putList( (FeatureList&)terminateSlurList ); featureList.putList( (FeatureList&)slurList ); // then remaining features featureList.putList( features ); } featureList.putList( crescendoList ); featureList.each( Feature::invokeCalculate, this ); if ( _duration.multiplicity ) // abbrevs { if ( stem & BEAM ) { if ( terminateBeamList.empty() ) beamList.put( *new StrikeInitiateBeam( beam, _duration.multiplicity ) ); else terminateBeamList.insert( *new StrikeInitiateBeam( beam, _duration.multiplicity ) ); } else beamList.put( *new StrikeBeam( staff.number, pitch(), NESTED_IN( Token )Orientation( orientation) , _duration.multiplicity ) ); } ;// monitor << "leaving SimpleNote::calculate" << endl; } void SimpleNote::calculateFeaturePitch() { featurePitch[ DOWN ] = pitch(); featurePitch[ UP ] = pitch(); ;// monitor << featurePitchArray[ 0 ] << endl; // featurePitch[ orientation ] += orientation * stemLength; } void SimpleNote::calculateStem() { if ( stem != DEFAULT ) // invoked by Chord too, without checking; return; // must always do e.g. BeamNote::calculate if ( _duration.ord() == ordWhole ) { stem = NO; return; } if ( orientation ) return; #ifdef TRIPLET // no beam present if ( ( beam == NOBEAM ) || !beam.multiplicity ) #else if ( beam == NOBEAM ) // no beam present #endif orientation = ( pitch() - staff.midPitch < 0 ) ? UP : DOWN; else // beam present if ( _duration.ord() <= ord4 ) orientation = StemOrientation( -beam.orientation ); #if 0 if ( !staff.slurCount ) else // slur, no beam stem = ( staff.slur->orientation & Token::DOWN ) ? DEFAULT | UP : DEFAULT | DOWN; #endif } int SimpleNote::duration() { return _duration.duration(); } int SimpleNote::pitch() const { return name.getPitch(); } void SimpleNote::printDurationOn( ostream& os ) const { os << _duration.alpha(); } void SimpleNote::printListsOn( ostream& os ) const { // os << macroList; we can't have multiple mulooseness etc. os << terminateBeamList; // os << terminateSlurList; emptied os << beamList; // os << slurList; emptied os << featureList; } /* Accidentals can be introduced in two ways. The first way, the \textit{manual} way of coding them, consists for example in coding \keyindex{fl}\verb|a| to put a \textit{flat} at the pitch $a$, supposedly before the further note of that pitch. There is no control upon the fact that a note will be put at this position and at this pitch. Naturals, sharps, double flats and double sharps are coded \keyindex{na}~$p$, \keyindex{sh}~$p$, \keyindex{dfl}~$p$ and \keyindex{dsh}~$p$ respectively. Alternate procedures \keyindex{lfl}, \keyindex{lna}, \keyindex{lsh}, \keyindex{ldfl} and \keyindex{ldsh} place the same accidentals, but their abscissa is shifted one note head width on the left. The purpose of this is to avoid collision of accidentals in a chord with narrow intervals. */// obsolete? void SimpleNote::printNameOn( ostream& os ) const { // os << '{' << name.getSign() << name << '}'; os << '{' << name << '}'; } // Magic happens here void SimpleNote::printOn( ostream& os ) const { ;// monitor << "SimpleNote::printOn" << endl; printSignOn( os ); printListsOn( os ); // feature,macro,beamlist etc. printSetSizeOn( os ); // font size #if 0 // to be reimplemented in chord if ( _duration.dots && ( chord.count() > 1 ) && ( last != NONOTE ) ) if ( last.name.getPitch() - name.getPitch() == 1 ) && !( ( abs( name.getPitch() - chord.staff.midPitch ) ) % 2 ) ) { os << "\\r" << String( 'p', _duration.dots ) << 't'; os << '{' << NoteName( name.getPitch() - 1 ) << '}'; } #endif // printSignOn( os ); os << '\\'; printStyleOn( os ); printDurationOn( os ); printStemOn( os ); os << String( 'p', _duration.dots ); printNameOn( os ); printResetSizeOn( os ); } void SimpleNote::printResetSizeOn( ostream& os ) const { if ( ( style & ( ~TINY | ~SMALL ) ) != staff.style ) { if ( staff.style & TINY ) os << "\\tinynotesize"; else if ( staff.style & SMALL ) os << "\\smallnotesize"; else os << "\\normalnotesize"; } } void SimpleNote::printSetSizeOn( ostream& os ) const { if ( ( style & ( ~TINY | ~SMALL ) ) != staff.style ) { if ( style & TINY ) os << "\\tinynotesize"; else if ( style & SMALL ) os << "\\smallnotesize"; else os << "\\normalnotesize"; } } void SimpleNote::printSignOn( ostream& os ) const { if ( ( name.sign != NoteName::PLAIN ) && ( name.sign != NoteName::INVALID ) ) { os << '\\'; os << String( 'l', signShift ); os << name.getSign(); SimpleNote::printNameOn( os ); } } void SimpleNote::printStemOn( ostream& os ) const { if ( stem && ( stem != CHORD ) ) os << ( orientation == UP ? 'u' : 'l' ); #if 0 { if ( orientation == UP ) os << 'u'; else if ( orientation == DOWN ) os << 'l'; } #endif } void SimpleNote::printStyleOn( ostream& os ) const { if ( style & LEFT ) os << 'l'; else if ( style & RIGHT ) os << 'r'; else if ( style & GRACE ) os << "gr"; // else if ( chord ) else if ( stem & CHORD ) os << 'z'; } int SimpleNote::spacing( int additionalSpacing ) { // grace note should be fixed this way too if ( ( name.sign != NoteName::PLAIN ) && ( name.sign != NoteName::INVALID ) ) return signShift + additionalSpacing; else return 0; } #endif // SIMPLENOTE2 //-- class SimpleNote //