During the discussion on the recent PR for Figured Bass realisation, by going by bits and pieces, things became unncessarily complex and the global picture harder to get. My impression is that, once we start from the basic 'rule': "sharp => major | flat => minor", there is a quite simpler way to proceed, as I think that there is only one piece of info needed from the context of the F.b. chord, i.e. the current key signature; everything else can be rather easily computed from the F.b. data themselves with a handful of code lines and a few table lookups. Each interval can be diminished, minor, neutral-or-just, major, augmented; with 7 intervals from unison to 7th, there are 35 possibilities for the pitch offset and the TPC offset of each interval type: Pitch offset dimin. minor n.o.j major augm.Unison -1 -- 0 -- +1Second 0 +1 ? +2 +3Third +2 +3 ? +4 +5Fourth +4 -- 5 -- +6 and so on. Same for TPC offsets: Unison -7 -- 0 -- +7Second -12 -5 ? +2 +9Third -10 -3 ? +4 +13Fourth -8 -- -1 -- +6 and so on. Some combinations do not exist (the '--': unison, 4th anf 5th cannot be minor or major) and can be filled with arbitrary values as they will never be used. Some cells (the '?': neutral 2nd, 3rd, 6th and 7th) cannot be computed without knowing the current key signature: more about them later. From the F.b. figures, the interval number is easy; for the interval type, let's start from the basics: for 2b/Ø/#, 3b/Ø/#, 6b/Ø/, 7b/Ø/#: b => minor Ø => neutral # => major For 4b/Ø/# and 5b/Ø/#: b => diminished Ø => just # => augmented Once we know the interval to compute, for all combinations except the '?', the derived note can be computed quite easily: Note* derivedNote = new Note(score);int derivedNotePitchOffset = pitchOffsetTable[intervalNumber][intervalType];int derivedNoteTPCOffset = tpcOffsetTable[intervalNumber][intervalType];derivedNote->setPitch(bassNote->pitch() + derivedNotePitchOffset, bassNote->tpc1() + derivedNoteTPCOffset, bassNote->tpc2() + derivedNoteTPCOffset); If the TPC lookup returned '?' (the Tpc::TPC_INVALID enum value can be used for it), we have to position the bass note in the current key signature scale and retrieve the derived note as specified by the same scale. Note that any degree, 'native' or altered, of a scale has a known relationship in pitch and in TPC with the tonic: Pitch TPC DegreeDegree 1 b -1 -7 0Degree 1 0 0 0 *Degree 1 # +1 +7 0Degree 2 b +1 -5 1Degree 2 +2 +2 1 *Degree 2 # +3 +9 1Degree 3 b +3 -3 2Degree 3 +4 +4 2 *Degree 3 # +5 +13 2 and so on (ignore the '*' for the moment). This table is shown above sorted by degree order, but it is actually accessed by TPC, so it is better to sort it by increasing TPC value. Another table is handy to have, which is derived from the above table by keeping only the lines marked with an * (the 'native' scale degrees), sorted by degree. The current key sig. for the bass staff can be obtained and converted into the TPC of its tonic and the bass note TPC can be converted into a scale degree with: Chord bassChord = bassNote->chord();Key key = bassChord->staff()->key(bassChord->tick());int tonicTPC = key + (Tpc::TPC_C - Key::C);int bassNoteTPCOffset = bassNote->tpc1() - tonicTPC;int bassNotePitchOffset = scaleTable[bassNoteTPCOffset][PITCH];int bassNoteDegree = scaleTable[bassNoteTPCOffset][DEGREE];// locate the derived scale degreeint derivedNoteDegree = bassNoteDegree + intervalnumber;// locate the derived note pitch and TPC position relative to the scale tonicint derivedNotePitchOffset = degreeTable[derivedNoteDegree][PITCH];int derivedNoteTPCOffset = degreeTable[derivedNoteDegree][TPC];// ready to fill the derived note valuesderivedNote->setPitch( bassNote->pitch() - bassNotePitchOffset + derivedNotePitchOffset, bassNote->tpc1() - bassNoteTPCOffset + derivedNoteTPCOffset, bassNote->tpc2() - bassNoteTPCOffset + derivedNoteTPCOffset); Finally, the derived note can be added to its destination chord with: derivedNote->setParent(derivedNoteChord);score->undoAddElement(derivedNote); An attempt of a function returning a derived note from a bass note, an interval number and an interval type could be: Note * createDerivedNote(Note* bassNote, int intervalnumber, int intervaltype){ Note* derivedNote = new Note(score); int derivedNotePitchOffset = pitchOffsetTable[intervalNumber][intervalType]; int derivedNoteTPCOffset = tpcOffsetTable[intervalNumber][intervalType]; if (derivedNoteTPCOffset != Tpc::TPC_INVALID) { derivedNote->setPitch(bassNote->pitch() + derivedNotePitchOffset, bassNote->tpc1() + derivedNoteTPCOffset, bassNote->tpc2() + derivedNoteTPCOffset); } else { Key key = bassChord->staff()->key(bassChord->tick()); int tonicTPC = key + (Tpc::TPC_C - Key::C); int bassNoteTPCOffset = bassNote->tpc1() - tonicTPC; int bassNotePitchOffset = scaleTable[bassNoteTPCOffset][PITCH]; int bassNoteDegree = scaleTable[bassNoteTPCOffset][DEGREE]; // locate the derived scale degree int derivedNoteDegree = bassNoteDegree + intervalnumber; // locate the derived note pitch and TPC position relative to the scale tonic int derivedNotePitchOffset = degreeTable[derivedNoteDegree][PITCH]; int derivedNoteTPCOffset = degreeTable[derivedNoteDegree][TPC]; // ready to fill the derived note values derivedNote->setPitch( bassNote->pitch() - bassNotePitchOffset + derivedNotePitchOffset, bassNote->tpc1() - bassNoteTPCOffset + derivedNoteTPCOffset, bassNote->tpc2() - bassNoteTPCOffset + derivedNoteTPCOffset); } return derivedNote;} Probably, it is wise to add a few tests on parameters and TPC over/underflow and to factorize out the key sig. function call, which is known not to change at least within each measure and is probably the most expensive function call. It is quite possible that some of the above tables already exist in the current code base, as rather similar tasks are needed in, for instance, diatonic transposition. Hoping it helps, Maurizio
-- View this message in context: http://dev-list.musescore.org/More-thoughts-on-Figured-Bass-realisation-tp7579405.html Sent from the MuseScore Developer mailing list archive at Nabble.com. ------------------------------------------------------------------------------ One dashboard for servers and applications across Physical-Virtual-Cloud Widest out-of-the-box monitoring support with 50+ applications Performance metrics, stats and reports that give you Actionable Insights Deep dive visibility with transaction tracing using APM Insight. http://ad.doubleclick.net/ddm/clk/290420510;117567292;y _______________________________________________ Mscore-developer mailing list Mscore-developer@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mscore-developer