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

Reply via email to