/**************************************************************************** PROJECT: MusixTeX PreProcessor FILE : key.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 // toupper #include "key.h" #include "staff.h" #include "inote.h" #include "imacro.h" #include "init.h" #include "mpp.h" char flatArray[ 7 ][ 3 ][ 4 ] = { "bes", "b", "bis", "es", "e", "eis", "as", "a", "ais", "des", "d", "dis", "ges", "g", "gis", "ces", "c", "cis", "fes", "f", "fis" }; char sharpArray[ 7 ][ 3 ][ 4 ] = { "fes", "f", "fis", "ces", "c", "cis", "ges", "g", "gis", "des", "d", "dis", "as", "a", "ais", "es", "e", "eis", "bes", "b", "bis" }; /**************************************************************************** class Key --*/ Key::Key( const char *s, int fl, int sh ) : Macro( s ), flats( fl ), sharps( sh ) { ;// monitor << "Key::Key" << flush; // substitute = "\\generalsignature{"; // substitute += String( sharps - flats ); // substitute += "}%\n"; // this string is never destructed String& base = *new String( "\\generalsignature{" ); base += String( sharps - flats ); base += "}%\n"; baseSubstitute = base; } Key::~Key() { ;// monitor << "~Key" << endl; } void Key::execute( StringList& parameters, Staff& staff ) { ;// monitor << "Key::execute" << endl; substitute = baseSubstitute; // is this check really necessary ?? if ( staff != NOOBJECT ) { Key* key; // a key change in music if ( ( parameters != NOLIST ) && ( staff.transposedFrom ) ) { NoteName transposedFrom( staff.transposedFrom->name ); NoteName transposedTo( staff.key->name ); int transposeHeight = ( transposedTo.height - transposedFrom.height + 12 ) % 12; key = &transposeKey( staff.transpose, transposeHeight ); staff.transposedFrom = this; } else key = this; // modulation detected if ( ( staff.key != key ) && staff.barCount ) { staff.changeContext = 1; if ( staff.key ) staff.newKey = key; } else staff.key = key; } resetAccidentals(); setAccidentals(); if ( staff.transposedFrom && staff.key ) transposeAccidentals( staff.transpose ); } void Key::resetAccidentals() { NoteNameArrayIterator note( noteNames ); while ( note ) { note++.sign = NoteName::FLATFLAT; note++.sign = NoteName::FLAT; note++.sign = NoteName::PLAIN; note++.sign = NoteName::SHARP; note++.sign = NoteName::SHARPSHARP; } } void Key::setAccidental( const char* name, NESTED_IN( NoteName )Sign sign ) { #if 1 NoteName& noteName = noteNames.firstNoteName( Token::compare, (void*)name ); if ( noteName == NONOTENAME ) error( quoteString( "noteName not found", name ), __FILE__, __LINE__ ); noteName.sign = sign; #else if ( NoteName& noteName = noteNames.firstNoteName( Token::compare, (void*)name ) != NONOTENAME ) noteName.sign = sign; else error( quoteString( "noteName not found", name ), __FILE__, __LINE__ ); #endif } void Key::setAccidentals() { int i; for ( i = 0; i < flats; i++ ) { setAccidental( flatArray[ i ][ 0 ], NoteName::PLAIN ); setAccidental( flatArray[ i ][ 1 ], NoteName::NATURAL ); } for ( i = 0; i < sharps; i++ ) { setAccidental( sharpArray[ i ][ 1 ], NoteName::NATURAL ); setAccidental( sharpArray[ i ][ 2 ], NoteName::PLAIN ); } } void Key::sustain( int pitch, NESTED_IN( NoteName )Sign sign ) { // old implementation for list // use index( comparePitch, pitch ) NoteNameArrayIterator note( noteNames ); while ( note ) if ( note().pitch == pitch ) { for ( int i = 0; i < 5; i++, note++ ) note().sustain( sign ); return; } else note++; } void Key::transposeAccidentals( int transpose ) { monitor << "Key::transposeAccidentals: " << name << endl; // copy array NoteNameArray transposedNoteNames( noteNames.top() ); for ( int i = 0; i < noteNames.top(); i++ ) transposedNoteNames.put( *new NoteName( noteNames[ i ] ), i ); for ( int baseIndex = 0; baseIndex < noteNames.top(); baseIndex += 5 ) { int basePitch = noteNames[ baseIndex ].pitch; int transposedBasePitch = ( basePitch + transpose + 7 ) % 7; int transposedBaseIndex = noteNames.index( NoteName::comparePitch, &transposedBasePitch ); if ( transposedBaseIndex < noteNames.bottom() ) error( "interal error", __FILE__, __LINE__ ); int transposeSign = ( transposedNoteNames[ baseIndex ].height + 2 * transpose + 12 ) % 12 - transposedNoteNames[ transposedBaseIndex ].height ; for ( int i = 0; i < 5; i++ ) //?? // do not shift the double accidentals //?? for ( int i = 1; i < 4; i++ ) { if ( ( i + transposeSign >= 0 ) && ( i + transposeSign <= 4 ) ) noteNames[ baseIndex + i ].sign = transposedNoteNames[ transposedBaseIndex + i + transposeSign ].sign; else noteNames[ baseIndex + i ].sign = NoteName::INVALID; monitor << noteNames[ baseIndex + i ].name << ":"; monitor << transposedNoteNames[ transposedBaseIndex ].name << ","; monitor << transposeSign << ";"; monitor << noteNames[ baseIndex + i ].getSign() << endl; } } } Key& Key::transposeKey( int transpose, int transposeHeight ) { NoteName transposeFrom( name ); int transposedBasePitch = ( transposeFrom.pitch + transpose + 7 ) % 7; monitor << name << ":" << transposeFrom.pitch << ":" << transpose << endl; int transposedBaseIndex = noteNames.index( NoteName::comparePitch, &transposedBasePitch ); int i = noteNames[ transposedBaseIndex ].height - transposeFrom.height + transposeHeight; monitor << transposeHeight << ":" << transposedBasePitch << ":"; monitor << transposedBaseIndex << ":" << i << endl; if ( ( i < 1 ) || ( i > 3 ) ) // error(); error( "interal error", __FILE__, __LINE__ ); #if 1 String transposeTo( noteNames[ transposedBaseIndex + i ].name ); transposeTo = transposeTo.left( 1 ).upper() + transposeTo.right( transposeTo.len() - 1 ); #else String s( noteNames[ transposedBaseIndex + i ].name ); String transposeTo( (char)toupper( s[ 0 ] ) ); transposeTo += ( (const char*)s ) + 1; #endif Key& key = (Key&)macroList.firstMacro( Token::compare, (void*)(const char*)transposeTo ); if ( key == NOKEY ) error( quoteString( "key not found", transposeTo ), __FILE__, __LINE__ ); substitute = key.baseSubstitute; return key; } //-- class Key // /**************************************************************************** class Transpose --*/ Transpose::Transpose( const char* name ) : Macro( name, "", 1 ) { ;// monitor << "Transpose::Transpose"; } Transpose::~Transpose() { ;// monitor << "~Transpose"; } void Transpose::execute( StringList& parameters, Staff& staff ) { monitor << "Transpose::execute" << flush; NoteName keyName( char2istream( parameters.top() ) ); String s( keyName.name ); #if 1 s = s.left( 1 ).upper() + s.right( s.len() - 1 ); // s = parameters.top(); #else String sLower( keyName.name + 1 ); s.upper(); s = s + sLower; #endif monitor << endl; monitor << "(" << parameters.top() << "," << s << ")" << endl; Key* key; #if 0 ( *key ).execute( *(StringList*)ZERO, staff ); #else if ( (key = &(Key&)macroList.firstMacro( Token::compare, (void*)(const char*)s ) ) == ZERO ) staff.error( quoteString( "key not found", parameters.top() ) ); if ( !staff.transposedFrom ) { staff.transposedFrom = staff.key; NoteName fromNote( staff.transposedFrom->name ); NoteName toNote( key->name ); staff.transpose = toNote.getPitch() - fromNote.getPitch(); } else if ( staff.transposedFrom == key ) { staff.transpose = 0; staff.transposedFrom = 0; } if ( ( key != staff.transposedFrom ) && staff.barCount ) { substitute = key->baseSubstitute; staff.changeContext = 1; if ( staff.key ) staff.newKey = key; } else if ( !staff.changeContext ) staff.key = key; #endif } //-- class Transpose //