/**************************************************************************** PROJECT: MusixTeX PreProcessor FILE : chord.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 "token.h" #include "duration.h" //#include "noteslis.h" #include "beam.h" #include "beamlist.h" #include "slurlist.h" #include "maclist.h" #include "simpnote.h" #include "chord.h" #include "init.h" #include "staff.h" #include "mpp.h" static Duration whole( 1 ); static int ordWhole = whole.ord(); #if 1 // !defined( CHORD1 ) && !defined( CHORD2 ) #define CHORD0 #endif #if 1 // def __unix__ #define CHORD1 #define CHORD2 #endif #ifdef CHORD0 /**************************************************************************** class Chord --*/ Chord::Chord( Staff& staff ) : NoteSortedList( 1 ), // reversed sorted list Note( staff ) { staff.noteCount--; istream& is = *staff.is; staff.expect( '{' ); char c; is.get( c ); int beamChord = 0; c = is.peek(); SimpleNote* note = 0; while ( ( note != ZERONOTE ) && ( c != '}' ) ) { note = &SimpleNote::getSimpleNote( staff ); if ( note->stem & BEAM ) beamChord++; if ( beamChord > 1 ) { note->beam.noteCount--; note->beam.setSlope( 0 ); } put( *note ); WhiteSpace ws( staff ); c = is.peek(); } if ( c == '}' ) { is.get( c ); WhiteSpace ws( staff ); c = is.peek(); if ( ( c != '\\' ) && ( c != '|' ) && ( c!= ':' ) ) { macroList.putList( MacroList( staff ) ); // if ( note != &NOSIMPLENOTE ) // note->slurList.putList( SlurList( staff ) ); SlurList slurList( staff); if ( !slurList.empty() ) { if ( ( (InitiateSlur&)slurList.top() ).orientation == Token::UP ) top().slurList.putList( slurList ); else bottom().slurList.putList( slurList ); } macroList.putList( MacroList( staff ) ); top().terminateBeamList.putList( TerminateBeamList( staff ) ); } } } #endif // CHORD0 // #ifdef CHORD1 Chord::~Chord() { ;// monitor << "~Chord"; } Chord& Chord::getChord( Staff& staff ) { return *new Chord( staff ); } void Chord::calculate() { ;// monitor << "Chord::calculate" << endl; // now that orientation remains invariant calculateStem(); NoteSortedList::each( Note::invokeCalculate ); calculateSignSpacing(); ChordIterator notes( *this ); while ( notes ) { SimpleNote& note = notes++; macroList.putList( note.macroList ); if ( top() != (Object&)note ) { top().beamList.putList( note.beamList ); top().terminateBeamList.putList( note.terminateBeamList ); } } } void Chord::calculateStem() { ;// monitor << "Chord::calculateStem" << endl; NoteSortedList::each( SimpleNote::invokeCalculateStem ); ChordIterator notes( *this ); while ( notes ) { SimpleNote& note = notes++; note.chord = TRUE; // note.calculateStem(); // let note calculate orientation first if ( notes() != NOOBJECT ) { // high, low // notes().calculateStem(); if ( abs( note.pitch() - notes().pitch() ) < 2 ) calculateShift( note, notes() ); calculateChordStem( note, notes() ); } if ( notes ) note.stem = Stem( note.stem | CHORD ); } } #include "notename.h" void Chord::calculateSignSpacing() { int signShift = 0; ChordIterator notes( *this ); while ( notes ) { SimpleNote& note = notes++; // if ( name.getSign() ) if ( ( note.name.sign != NoteName::PLAIN ) && ( note.name.sign != NoteName::INVALID ) ) { note.signShift = signShift++; signShift %= 3; } } } void Chord::calculateShift( SimpleNote& high, SimpleNote& low ) { /* to be moved to Chord::calculateChord to handle multi-note chords chords of two notes that differ less than two pitches * stem up: - lowest has stem - highest right or lowest right * stem down: - highest has stem - lowest left or highest left */ if ( ( low.pitch() < 0 ) || ( high.pitch() < 0 ) ) return; if ( low._duration.ord() == high._duration.ord() ) { // chord has orientation up if ( ( low.orientation == UP ) || ( high.orientation == UP ) ) { // lowest gets stem, // highest shifts to the right low.orientation = UP; if ( low.stem != NO ) high.stem = NO; high.style = RIGHT; } // chord has orientation down else { // comment obsolete // highest gets stem, // lowest shifts to the left low.orientation = DOWN; if ( !( high.stem & BEAM ) ) high.stem = NO; low.style = LEFT; } } // of different duration -> different stems else if ( !( low.style & RIGHT ) ) high.style = RIGHT; } void Chord::calculateChordStem( SimpleNote& high, SimpleNote& low ) { ;// monitor << "Chord::calculateChordStem"; ;// monitor << " high: " << high.pitch() << " " << high.stem; ;// monitor << " low: " << low.pitch() << " " << low.stem; // put chords with notes of different duration // on different stems if ( ( low._duration.ord() != high._duration.ord() ) && !( ( ( high.stem == BEAM ) || ( high.stem == FORCED ) ) && ( ( low.stem == BEAM ) || ( low.stem == FORCED ) ) ) ) { ;// monitor << "diff "; if ( ( high.stem == FORCED ) || ( high.stem == BEAM ) ) low.orientation = StemOrientation( -high.orientation ); else if ( ( low.stem == FORCED ) || ( low.stem == BEAM ) ) high.orientation = StemOrientation( -low.orientation ); else { high.orientation = UP; high.stem = FORCED; low.orientation = DOWN; low.stem = FORCED; } } // same duration, always assume one stem else if ( !( high.stem == FORCED ) || !( low.stem == FORCED ) ) { ;// monitor << "same "; if ( ( high.stem == DEFAULT ) && !( low.stem == NO ) ) { high.stem = NO; // orientation needed for feature placement high.orientation = low.orientation; // low.stem = FORCED; // assure no recalculation by (...)::calculate // has this become a double check together // with orientation (...)::calculate check ? } else if ( ( low.stem == DEFAULT ) && !( high.stem == NO ) ) { high.stem = NO; low.orientation = high.orientation; // low.stem = FORCED; // assure no recalculation by (...)::calculate // has this become a double check together // with orientation (...)::calculate check ? } } } int Chord::duration() { int shortest = whole.duration(); ChordIterator notes( *this ); while( notes ) { int duration = notes++.duration(); if ( duration < shortest ) shortest = duration; } return shortest; } int Chord::pitch() const { return 0; } void Chord::printOn( ostream& os ) const { ;// monitor << "Chord::printOn" << endl; NoteSortedList::printOn( os ); } #if 0 int Note::smallest( int Note::(*)() ) { static int smallest; smallest = 0; } static inline void Note::smallest( Object& note, void* function ) { ( (Note&)note ).function(); } each( Note::smallest, Note::spacing ); #endif int Chord::spacing( int additionalSpacing ) { int largest = 0; ChordIterator notes( *this ); while( notes ) { int spacing = notes++.spacing( additionalSpacing ); if ( spacing > largest ) largest = spacing; } return largest; } //-- class Chord // #endif // CHORD1