Files
Work/music/parser.cpp
2024-08-07 09:16:27 -04:00

522 lines
13 KiB
C++

#include <music/parser.hpp>
#include <music/scales.hpp>
#include <music/IonianScale.hpp>
namespace Music
{
bool Parser::parse(Emitter &emitter,Music::Chord &chord)
{
mEmitter=&emitter;
mIndex=0;
Byte peekSymbol;
mNotes.remove();
chord.size(0);
mIsInError=false;
while(true)
{
insertSymbols(ScanSymbols::Note1);
if(!nextSymbol())break; // this needs to be removed
if(symbolIn(ScanSymbols::Note1))
{
parseNote();
if(!nextSymbol())break;
}
removeSymbols(ScanSymbols::Note1);
if(symbolIn(ScanSymbols::Verb1))
{
if(!parseVerb())break;
if(!nextSymbol())break;
}
if(symbolIn(ScanSymbols::HalfDiminished1))
{
parseHalfDiminished();
if(!nextSymbol())break;
}
if(symbolIn(ScanSymbols::Diminished1))
{
parseDiminished();
if(!nextSymbol())break;
}
if(symbolIn(ScanSymbols::MinorMajor71))
{
parseMinorMajor();
if(!nextSymbol())break;
}
if(symbolIn(ScanSymbols::Minor1)) // parseMinor looks for minor-degree
{
parseMinor();
if(!nextSymbol())break;
}
if(symbolIn(ScanSymbols::Major71))
{
parseMajorSeventh();
}
if(symbolIn(ScanSymbols::Degree1))
{
parseDegree();
if(!nextSymbol())break;
}
if(symbolIn(ScanSymbols::Alter1))
{
parseAlteration();
if(!nextSymbol())break;
}
}
if(mIsInError)return false;
if(!mNotes.size())
{
chord.create(mRootNote,Music::Chord::MajorTriad);
}
else
{
Notes &notes=(Notes&)chord;
notes.size(mNotes.size()+1);
notes[0]=mRootNote;
for(int index=0;index<mNotes.size();index++)notes[index+1]=mNotes[index];
}
return true;
}
bool Parser::parseHalfDiminished(void) // half diminished is a minor seventh with a flatted fifth
{
Note minorThird=mRootNote.getThird();
Note minorFifth=mRootNote.getFifth();
Note minorSeventh=mRootNote.getSeventh();
minorSeventh--;
minorThird--;
minorFifth--;
if(!haveNote(minorThird))mNotes.insert(&minorThird);
if(!haveNote(minorFifth))mNotes.insert(&minorFifth);
if(!haveNote(minorSeventh))mNotes.insert(&minorSeventh);
return true;
}
bool Parser::parseDiminished(void) // diminished is
{
DiminishedWholeScale diminishedWholeScale(mRootNote);
if(!haveNote(diminishedWholeScale.getDegree(Degree::III)))mNotes.insert(&diminishedWholeScale.getDegree(Degree::III));
if(!haveNote(diminishedWholeScale.getDegree(Degree::V)))mNotes.insert(&diminishedWholeScale.getDegree(Degree::V));
if(!haveNote(diminishedWholeScale.getDegree(Degree::VII)))mNotes.insert(&diminishedWholeScale.getDegree(Degree::VII));
return true;
}
bool Parser::parseVerb(void)
{
if(mStrValue=="sus") // the sus chord is like a 7 chord except it has a fourth instead of a third
{ // the fourth usually resolves down half step to become the third
Note fourth=mRootNote.getFourth();
Note perfectFifth=mRootNote.getFifth();
Note minorSeventh=mRootNote.getSeventh();
minorSeventh--;
if(!haveNote(fourth))mNotes.insert(&fourth);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(minorSeventh))mNotes.insert(&minorSeventh);
return true;
}
else
{
mIsInError=true;
return false;
}
}
bool Parser::parseMajorSeventh(void)
{
expect(ScanSymbols::Major71);
Note third=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
Note seventh=mRootNote.getSeventh();
mNotes.insert(&third);
mNotes.insert(&perfectFifth);
mNotes.insert(&seventh);
return true;
}
bool Parser::parseMinor(void)
{
Byte peekSymbol=this->peekSymbol();
if(ScanSymbols::Degree1!=peekSymbol)
{
Note minorThird;
Note perfectFifth;
minorThird=mRootNote.getThird();
minorThird--;
mNotes.insert(&minorThird);
perfectFifth=mRootNote.getFifth();
mNotes.insert(&perfectFifth);
}
else if(ScanSymbols::Degree1==peekSymbol)
{
expect(ScanSymbols::Degree1);
if(3==mByteValue.value())
{
Note minorThird=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
minorThird--;
if(!haveNote(minorThird))mNotes.insert(&minorThird);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
}
else if(4==mByteValue.value())
{
Note minorFourth=mRootNote.getFourth();
Note perfectFifth=mRootNote.getFifth();
minorFourth--;
if(!haveNote(minorFourth))mNotes.insert(&minorFourth);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
}
else if(5==mByteValue.value())
{
Note minorFifth=mRootNote.getFifth();
Note minorThird=mRootNote.getThird();
minorFifth--;
minorThird--;
if(!haveNote(minorFifth))mNotes.insert(&minorFifth);
if(!haveNote(minorThird))mNotes.insert(&minorThird);
}
else if(6==mByteValue.value())
{
Note perfectFifth=mRootNote.getFifth();
Note minorThird=mRootNote.getThird();
Note majorSixth=mRootNote.getSixth();
minorThird--;
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(minorThird))mNotes.insert(&minorThird);
if(!haveNote(majorSixth))mNotes.insert(&majorSixth);
}
else if(7==mByteValue.value())
{
Note minorThird=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
Note minorSeventh=mRootNote.getSeventh();
minorSeventh--;
minorThird--;
if(!haveNote(minorThird))mNotes.insert(&minorThird);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(minorSeventh))mNotes.insert(&minorSeventh);
}
else if(9==mByteValue.value())
{
Note minorThird=mRootNote.getThird();
Note minorNinth=mRootNote.getNinth();
Note perfectFifth=mRootNote.getFifth();
minorNinth--;
minorThird--;
if(!haveNote(minorThird))mNotes.insert(&minorThird);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(minorNinth))mNotes.insert(&minorNinth);
}
else if(11==mByteValue.value())
{
Note minorThird=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
Note minorEleventh=mRootNote.getEleventh();
minorThird--;
minorEleventh--;
if(!haveNote(minorThird))mNotes.insert(&minorThird);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(minorEleventh))mNotes.insert(&minorEleventh);
}
else if(13==mByteValue.value())
{
Note minorThird=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
Note minorThirteenth=mRootNote.getThirteenth();
minorThirteenth--;
minorThird--;
if(!haveNote(minorThird))mNotes.insert(&minorThird);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(minorThirteenth))mNotes.insert(&minorThirteenth);
}
}
return true;
}
bool Parser::parseMinorMajor(void) // minor major is basically a minor chord with a #7
{
Note minorThird;
Note perfectFifth;
Note majorSeventh;
minorThird=mRootNote.getThird();
minorThird--;
mNotes.insert(&minorThird);
perfectFifth=mRootNote.getFifth();
mNotes.insert(&perfectFifth);
majorSeventh=mRootNote.getSeventh();
mNotes.insert(&majorSeventh);
return true;
}
bool Parser::parseDegree(void)
{
if(3==mByteValue.value())
{
Note third=mRootNote.getThird();
if(!haveNote(third))mNotes.insert(&third);
}
else if(4==mByteValue.value())
{
Note fourth=mRootNote.getFourth();
if(!haveNote(fourth))mNotes.insert(&fourth);
}
else if(5==mByteValue.value())
{
Note fifth=mRootNote.getFifth();
if(!haveNote(fifth))mNotes.insert(&fifth);
}
else if(6==mByteValue.value())
{
Note sixth=mRootNote.getSixth();
Note third=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
if(!haveNote(sixth))mNotes.insert(&sixth);
if(!haveNote(third))mNotes.insert(&third);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
}
else if(7==mByteValue.value())
{
Note third=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
Note minorSeventh=mRootNote.getSeventh();
minorSeventh--;
if(!haveNote(third))mNotes.insert(&third);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(minorSeventh))mNotes.insert(&minorSeventh);
}
else if(9==mByteValue.value())
{
Note third=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
Note ninth=mRootNote.getNinth();
if(!haveNote(third))mNotes.insert(&third);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(ninth))mNotes.insert(&ninth);
}
else if(11==mByteValue.value())
{
Note third=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
Note eleventh=mRootNote.getEleventh();
if(!haveNote(third))mNotes.insert(&third);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(eleventh))mNotes.insert(&eleventh);
}
else if(13==mByteValue.value())
{
Note third=mRootNote.getThird();
Note perfectFifth=mRootNote.getFifth();
Note thirteenth=mRootNote.getThirteenth();
if(!haveNote(third))mNotes.insert(&third);
if(!haveNote(perfectFifth))mNotes.insert(&perfectFifth);
if(!haveNote(thirteenth))mNotes.insert(&thirteenth);
}
return false;
}
bool Parser::parseAlteration(void)
{
Byte inflection=mByteValue;
expect(ScanSymbols::Degree1);
Note note(mRootNote.getNinth());
if(3==mByteValue.value())
{
note=mRootNote.getThird();
}
else if(4==mByteValue.value())
{
note=mRootNote.getFourth();
}
else if(5==mByteValue.value())
{
note=mRootNote.getFifth();
}
else if(6==mByteValue.value())
{
note=mRootNote.getSixth();
}
else if(7==mByteValue.value())
{
note=mRootNote.getSeventh();
}
else if(9==mByteValue.value())
{
note=mRootNote.getNinth();
}
else if(11==mByteValue.value())
{
note=mRootNote.getEleventh();
}
else if(13==mByteValue.value())
{
note=mRootNote.getThirteenth();
}
mNotes.remove(note); // if the note already exists then remove it because we're altering it.
if(ScanSymbols::Sharp1==inflection)note++;
else note--;
mNotes.insert(&note);
return true;
}
bool Parser::parseNote(void)
{
switch(mByteValue.value())
{
case 'A' :
mRootNote=Note(Note::A);
mRootNote.setOctave(mRootNote.getOctave()-1);
break;
case 'B' :
mRootNote=Note(Note::B);
mRootNote.setOctave(mRootNote.getOctave()-1);
break;
case 'C' :
mRootNote=Note(Note::C);
mRootNote.setOctave(mRootNote.getOctave()-1);
break;
case 'D' :
mRootNote=Note(Note::D);
mRootNote.setOctave(mRootNote.getOctave()-1);
break;
case 'E' :
mRootNote=Note(Note::E);
mRootNote.setOctave(mRootNote.getOctave()-1);
break;
case 'F' :
mRootNote=Note(Note::F);
mRootNote.setOctave(mRootNote.getOctave()-1);
break;
case 'G' :
mRootNote=Note(Note::G);
mRootNote.setOctave(mRootNote.getOctave()-1);
break;
}
if(ScanSymbols::Alter1==peekSymbol())
{
expect(ScanSymbols::Alter1);
if(mByteValue.value()==ScanSymbols::Sharp1)mRootNote++;
else mRootNote--;
}
return true;
}
ScanSymbols::ScanSymbol Parser::peekSymbol(void)
{
if(mIndex>=mEmitter->size())return ScanSymbols::Stop1;
return (ScanSymbols::ScanSymbol)(*mEmitter)[mIndex].value();
}
bool Parser::nextSymbol()
{
int length;
int index;
bool returnCode;
if(mIndex+1>=mEmitter->size())return false;
returnCode=true;
mKey=(ScanSymbols::ScanSymbol)(*mEmitter)[mIndex++].value();
switch(mKey)
{
case ScanSymbols::Note1 :
mByteValue=(*mEmitter)[mIndex++].value();
break;
case ScanSymbols::Degree1 :
mByteValue=(*mEmitter)[mIndex++].value();
break;
case ScanSymbols::Alter1 :
mByteValue=(*mEmitter)[mIndex++].value();
break;
case ScanSymbols::Verb1 :
length=(*mEmitter)[mIndex++].value();
mStrValue.reserve(length+1);
for(index=0;index<length;index++)
mStrValue.setAt(index,(*mEmitter)[mIndex++].value());
mStrValue.setAt(index,0);
break;
default :
mByteValue=mKey;
break;
case ScanSymbols::Stop1 :
returnCode=false;
break;
}
return returnCode;
}
bool Parser::expect(ScanSymbols::ScanSymbol symbol)
{
nextSymbol();
if(!symbolIn(Byte(symbol)))return false;
return true;
}
bool Parser::checkSymbol(void)
{
return symbolIn(Byte(mKey));
}
bool Parser::symbolIn(Block<Byte> &symbols)
{
for(int index=0;index<symbols.size();index++)
{
if(mKey==symbols[index])return true;
}
return false;
}
bool Parser::symbolIn(ScanSymbols::ScanSymbol symbol)
{
return symbolIn(Byte(symbol));
}
bool Parser::symbolIn(Byte &symbol)
{
if(mKey==symbol)return true;
return false;
}
void Parser::removeSymbols(Block<Byte> &symbols)
{
for(int index=0;index<symbols.size();index++)
removeSymbols((ScanSymbols::ScanSymbol)symbols[index].value());
}
void Parser::insertSymbols(Block<Byte> &symbols)
{
for(int index=0;index<symbols.size();index++)
insertSymbols((ScanSymbols::ScanSymbol)symbols[index].value());
}
void Parser::insertSymbols(ScanSymbols::ScanSymbol symbol)
{
mSymbols.insert(&Byte(symbol));
}
void Parser::removeSymbols(ScanSymbols::ScanSymbol symbol)
{
for(int index=0;index<mSymbols.size();index++)
{
if(symbol==mSymbols[index])mSymbols.remove(index);
}
}
bool Parser::haveNote(const Note &note)
{
for(int index=0;index<mNotes.size();index++)
{
if(mNotes[index]==note)return true;
}
return false;
}
bool Parser::isMinor(void)const
{
if(!mNotes.size())return false; // can't be minor with just a root note
IonianScale scale(mRootNote);
Note third=scale.getDegree(Degree::III);
if(((Block<Note>&)mNotes)[0]==third)return false;
return true;
}
};