Initial
This commit is contained in:
522
music/parser.cpp
Normal file
522
music/parser.cpp
Normal file
@@ -0,0 +1,522 @@
|
||||
#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 ¬es=(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(¬e);
|
||||
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 ¬e)
|
||||
{
|
||||
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;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user