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

241 lines
6.5 KiB
C++

#include <guitar/Fretboard.hpp>
#include <guitar/GlobalDefs.hpp>
#include <common/block.hpp>
bool Fretboard::isOnFretboard(const Note &note)
{
for(int frIndex=0;frIndex<mFrets+1;frIndex++)
{
for(int srIndex=0;srIndex<size();srIndex++)
{
Note &srchNote=operator[](srIndex)[frIndex];
if(srchNote.getNote()==note.getNote()&&srchNote.getOctave()==note.getOctave())return true;
}
}
return false;
}
/*
searches for a note mapping starting at top (sixth string), fret 0,
*/
bool Fretboard::getAt(const Note &note,FrettedNote &frettedNote)
{
for(int srIndex=0;srIndex<size();srIndex++)
{
for(int frIndex=0;frIndex<mFrets+1;frIndex++)
{
Note &srchNote=operator[](srIndex)[frIndex];
if(srchNote.getNote()==note.getNote()&&srchNote.getOctave()==note.getOctave())
{
frettedNote.setNote(note);
frettedNote.setString(srIndex);
frettedNote.setFret(frIndex);
return true;
}
}
}
return false;
}
/*
searches for a note mapping starting at top (sixth string), fret 0,
*/
bool Fretboard::getAt(const Note &note,Block<FrettedNote> &frettedNotes)
{
frettedNotes.remove();
for(int srIndex=0;srIndex<size();srIndex++)
{
for(int frIndex=0;frIndex<mFrets+1;frIndex++)
{
Note &srchNote=operator[](srIndex)[frIndex];
if(srchNote.getNote()==note.getNote()&&srchNote.getOctave()==note.getOctave())
{
FrettedNote frettedNote;
frettedNote.setNote(note);
frettedNote.setString(srIndex);
frettedNote.setFret(frIndex);
frettedNotes.insert(&frettedNote);
}
}
}
return frettedNotes.size()?true:false;
}
/*
Get the fretted notes for the given chord. The root may be repeated.
Returns true if it mapped all of the notes of the chord, false if some
or all notes were unable to be mapped. Partial success would return
false but the frettedNotes array may contain some notes.
@param [In] Chord the chord to get fretting for.
@param [Out] Fretted notes corresponding to the chord
*/
bool Fretboard::getAt(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("'"));
GlobalDefs::outDebug(message);
returnCode=false;
}
}
// need to come up with a strategy here for mapping notes on the fretboard
if(isBarChord) // check to see if we can fill in some notes at the bar chord fret
{
getFillerNotes(frettedNotes[0].getFret(),chord,frettedNotes);
}
return returnCode;
}
/*
Find filler notes for given chord on given fret on empty string.
*/
bool Fretboard::getFillerNotes(int fret,const Music::Chord &chord,Block<FrettedNote> &frettedNotes)
{
bool notesInChord;
for(int stringIndex=0;stringIndex<size();stringIndex++)
{
Note &note=operator[](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;
}
bool Fretboard::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;
}
/*
* searches for a note mapping starting at top (sixth string), fret 0,
* 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 Fretboard::getAt(const Note &note,FrettedNote &frettedNote,Block<FrettedNote> &containedNotes)
{
for(int srIndex=0;srIndex<size();srIndex++)
{
for(int frIndex=0;frIndex<mFrets+1;frIndex++)
{
Note &srchNote=operator[](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)>4)continue;
return true;
}
}
}
return false;
}
/* 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 Fretboard::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;
}
/*
Returns the greatest distance between fretted note and grouping of notes
@param frettedNote - The fretted note to get distance.
@param frettedNotes - The collection of notes with which to compare distances
*/
int Fretboard::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;
}
return maxDistance;
}
void Fretboard::createFretboard(const Tuning &tuning,int frets)
{
mTuning=tuning;
mFrets=frets;
createFretboard();
}
bool Fretboard::play(MIDIOutputDevice &device)
{
for(int string=0;string<size();string++)
{
Notes &stringNotes=operator[](string);
stringNotes.play(device);
}
return true;
}
void Fretboard::createFretboard(void)
{
size(mTuning.getStrings());
for(int string=0;string<size();string++)
{
Notes &stringNotes=operator[](string);
stringNotes.size(mFrets+1);
Note fretNote=mTuning[string];
for(int fret=0;fret<mFrets+1;fret++)
{
stringNotes[fret]=fretNote;
fretNote++;
}
}
}
String Fretboard::toString(void)const
{
String strFretboard;
for(int string=0;string<size();string++)
{
Notes &stringNotes=((Array<Notes>&)*this).operator[](string);
strFretboard+=stringNotes.toString();
if(string<size()-1)strFretboard+=String("\n");
}
return strFretboard;
}