522 lines
13 KiB
C++
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 ¬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;
|
|
}
|
|
}; |