When I wrote the Cathedral Composer one of the complicated bits was to decide when a harmonic change should take place. The way it worked was that the Harmony Analyser triggerd events whenever a potential new harmonic context was detected in the improvisation, and then the Composer evaluated if it was appropriate to establish that new harmony or not, according the current context of the piece. This happened to imply pretty complex (and bug nurturing) logic, which I managed to get reasonably useful after a fair bit of work (meaning around 100 lines of not-particularly-maintainable code).
The idea of dealing with that on every Composer I create was a bit spooky, so I set out to create a new type of object, the Evaluator, which would take care of all this logic, freeing the Composer to focus on more interesting things. The Harmony Evaluator in particular needed to be configurable to some extent, so that the Composer can tell it what kind of harmonies it's interested in (i.e. stick to pentatonic harmonies, or allow dissonant contexts, etc.). The elements to consider were varied:
- How reliable are the results provided by the Harmony Analyser? These results include a strict version and a guessed version, each with their confidence indicator. Depending on the context only certain results will be deemed 'good enough' to be established.
- The current context: do we have a current harmony? Is it known (i.e. C Major) or unknown (i.e. C, D, E, F, F#, A, Bb, B)?
- What are the preferred harmonies? (the Composer decides that). Should we stick to preferred harmonies or allow all sorts of changes?
There was a lot of drawing, testing, failing, drawing, testing, failing... you get the idea. In the end I came up with what seemed like a good algorithm:
And then proceeded to code the HarmonyEvaluator, with its configuration options to make it useful for different Composers and scenarios. Now my 100 lines of code in the composer have been reduced to:
I'm happy. :)