Files
Work/guitar/ChordMapper.cpp
2024-08-07 09:16:27 -04:00

233 lines
7.0 KiB
C++

#include <guitar/ChordMapper.hpp>
bool ChordMapper::map(const Music::Chord &chord,Block<FrettedNote> &frettedNotes)
{
FrettedNote frettedNote;
bool returnCode=true;
bool isBarChord=false;
frettedNotes.remove();
if(getAt(chord.getRoot(),frettedNote,frettedNotes)) // try to set the root on the top string
{
frettedNotes.insert(&frettedNote);
isBarChord=true;
}
for(int index=chord.size()-1;index>=0;index--)
{
Note &note=((Music::Chord&)chord)[index];
if(getAt(note,frettedNote,frettedNotes))frettedNotes.insert(&frettedNote);
else
{
String message("[Fretboard::getAt] Unable to map note '"+note.toString()+String("'"));
returnCode=false;
}
}
if(!returnCode)
{
isBarChord=false;
returnCode=true;
frettedNotes.remove();
int noteCount=0;
int chordIndex=2;
int direction=-1;
/*
while(noteCount<chord.size())
{
if(chordIndex<0)chordIndex=chord.size()-1;
else if(chordIndex>=chord.size())chordIndex=0;
Note &note=((Music::Chord&)chord)[chordIndex];
if(getAt(Fretboard::Strings-1,-1,note,frettedNote,frettedNotes))frettedNotes.insert(&frettedNote);
else returnCode=false;
chordIndex+=direction;
noteCount++;
}
*/
}
if(isBarChord && frettedNotes.size()) // check to see if we can fill in some notes at the bar chord fret
{
getFillerNotes(frettedNotes[0].getFret(),chord,frettedNotes);
}
return returnCode;
}
/*
* searches for a note mapping starting at given string at fret 0 (note string 0 is the top (6th)string
* takes care of string collisions.
* @param note - The note to find a mapping for.
* @param fretted note - If result is true contains note mapping.
* @param containedNotes - Notes that are already in the mapping, used
to limit selected notes and to minimize distance between notes.
*/
bool ChordMapper::getAt(int startingString,int direction,const Note &note,FrettedNote &frettedNote,Block<FrettedNote> &containedNotes)
{
for(int stringCount=0,srIndex=startingString;stringCount<Fretboard::Strings;stringCount++,srIndex+=direction)
{
if(srIndex>=Fretboard::Strings)srIndex=0;
else if(srIndex<0)srIndex=Fretboard::Strings-1;
for(int frIndex=0;frIndex<mFretboard.getFrets()+1;frIndex++)
{
Note &srchNote=mFretboard[srIndex][frIndex];
if(srchNote.getNote()==note.getNote())
{
frettedNote.setNote(note);
frettedNote.setString(srIndex);
frettedNote.setFret(frIndex);
if(contains(frettedNote,containedNotes))continue;
if(distance(frettedNote,containedNotes)>MaxFretDistance)continue;
return true;
}
}
}
return false;
}
/*
Get the FrettedNote for the given Note.
@param note - The note we are looking to map.
@param frettedNote - The fretted note we are looking for (get's filled in on success)
@param containedNotes - List of frettednotes we already have (so don't choose any of these).
*/
bool ChordMapper::getAt(const Note &note,FrettedNote &frettedNote,Block<FrettedNote> &containedNotes)
{
for(int srIndex=0;srIndex<mFretboard.size();srIndex++)
{
if(srIndex>=Fretboard::Strings)srIndex=0;
for(int frIndex=0;frIndex<mFretboard.getFrets()+1;frIndex++)
{
Note &srchNote=mFretboard[srIndex][frIndex];
if(srchNote.getNote()==note.getNote())
{
frettedNote.setNote(note);
frettedNote.setString(srIndex);
frettedNote.setFret(frIndex);
if(contains(frettedNote,containedNotes))continue;
if(distance(frettedNote,containedNotes)>MaxFretDistance)continue;
return true;
}
}
}
return false;
}
/*
Returns the greatest distance between fretted note and grouping of notes
Distance is simply fret distance, does not account for string distance
@param frettedNote - The fretted note to get distance.
@param frettedNotes - The collection of notes with which to compare distances
*/
int ChordMapper::distance(const FrettedNote &frettedNote,Block<FrettedNote> &frettedNotes)
{
int maxDistance=0;
int currDistance;
for(int index=0;index<frettedNotes.size();index++)
{
FrettedNote &currNote=frettedNotes[index];
currDistance=frettedNote.getFret()-currNote.getFret();
if(currDistance<0)currDistance=-currDistance;
if(currDistance>maxDistance)maxDistance=currDistance;
}
OutputDebugString(String(String("Distance is :")+String().fromInt(maxDistance)+String("\n")).str());
return maxDistance;
}
/*
Return the distance between two fretted notes.
*/
int ChordMapper::distance(const FrettedNote &firstNote,const FrettedNote &secondNote)
{
int fretDistance=firstNote.getFret()-secondNote.getFret();
return fretDistance<0?-fretDistance:fretDistance;
}
/*
Find filler notes for given chord on given fret on empty string.
*/
bool ChordMapper::getFillerNotes(int fret,const Music::Chord &chord,Block<FrettedNote> &frettedNotes)
{
bool notesInChord;
for(int stringIndex=0;stringIndex<mFretboard.size();stringIndex++)
{
Note &note=mFretboard[stringIndex][fret];
FrettedNote frettedNote;
frettedNote.setNote(note);
frettedNote.setString(stringIndex);
frettedNote.setFret(fret);
if(!contains(frettedNote,frettedNotes)&&isIn(frettedNote,chord))frettedNotes.insert(&frettedNote);
}
return true;
}
/* Check to see if the fretted note exists in the collection of fretted notes.
* @param frettedNote - The fretted note to check for
* @param frettedNotes - The collection of fretted notes
*/
bool ChordMapper::contains(const FrettedNote &frettedNote,Block<FrettedNote> &frettedNotes)
{
for(int index=0;index<frettedNotes.size();index++)
{
FrettedNote &currNote=frettedNotes[index];
if(currNote.getString()==frettedNote.getString())return true;
}
return false;
}
/*
Check to see if the given note is part of the chord
@param frettedNote - The note
@param chord - The chord
@return - True if the given note is part of the chord, false otherwise
*/
bool ChordMapper::isIn(const FrettedNote &frettedNote,const Music::Chord &chord)
{
for(int index=0;index<chord.size();index++)
if(frettedNote.getNote()==((Music::Chord&)chord)[index])return true;
return false;
}
void ChordMapper::getNearestNote(const FrettedNote &frettedNote,const Note &srchNote,FrettedNote &foundNote)
{
bool found=false;
int stringOffset=1;
int fretOffset=1;
while(!found)
{
if(getNearestNoteInRange(frettedNote,srchNote,foundNote,stringOffset,fretOffset))found=true;
stringOffset++;
fretOffset++;
}
}
bool ChordMapper::getNearestNoteInRange(const FrettedNote &frettedNote,const Note &srchNote,FrettedNote &foundNote,int stringOffset,int fretOffset)
{
for(int currentString=frettedNote.getString()-1;currentString<frettedNote.getString()+1;currentString++)
{
for(int currentFret=frettedNote.getFret()-1;currentFret<frettedNote.getFret()+1;currentFret++)
{
if(currentString>=Fretboard::Strings || currentString<0)continue;
if(currentFret>=Fretboard::Frets || currentFret<0)continue;
Note &note=mFretboard[currentString][currentFret];
if(note==srchNote)
{
FrettedNote frettedNote;
frettedNote.setNote(note);
frettedNote.setString(currentString);
frettedNote.setFret(currentFret);
return true;
}
}
}
return false;
}