This cycling74 Max patch generates chords from an on-screen keyboard or MIDI, with dynamic voice allocation and transposition, key, scale, and velocity remapping. When the note is turned off, the other notes in the generated chord are turned off. The number of active generated notes can be changed at any time.
1. Design Implementation
The chord generator uses a modified version of thePolyvoice 3 Advanced Polyphony Manager to manage played notes. This version has three main enhancements over the original prototype:
- The object keeps record of two pitches for each voice: the original played pitch, and the transposed pitch. When a note-off event is received, the original pitch store is checked to determine if the note has not been turned off due to note-on events exceeding the available polyphony. If the original played pitch is found in that note store, a note-off event is issued for the transposed pitch. In this manner, pitch transpositions can occur at any time, not disrupt the finding of the original played note, and the pitch of turned-off notes is available for updating the keyboard display.
- The object maintains an index counter and stores its value for each note in an additional array. The counter increments for each received note-on event. The same counter value is then stored for the voices of all notes added by the chord generator. Subsequently, after a note-off event is received and its voice index found in the original note store, the object looks up the index number associated with that original note, then searches the index store for any other notes with the same index value. Note-off events are then issued for all found notes with the same index, turning off the chord.
- It correctly maintains and restores the voice queue when the number of playing voices is increased or reduced at any time. When the number of permitted voices is reduced, note-off events for those voices are issued. When the maximum number of voices is increased, the voices are restored in the same age sequence. In this manner, any notes still in the release phase after being turned off by reducing the voice limit are retriggered and reused as needed, if the max-voice count changes rapidly during play.
The design contains several subpatches. The following diagram shows preparation of notes from the kslider object on the left, and the generation of gate routing values from chord lookup tables on the right. If the current setting does not require one of the chord notes, a gate at the top of the main patch stops additional unnecessary processing. The pitch transpositions are stored in a list at initialization, and the pitch offset added to the original pitch as it arrives. That is, all note processing occurs on new notes; playing notes will already have been sent out, and are not modified.
After pitch offset and velocity scaling, the pitch passes through a single lookup for key, scale, and global transposition, then clipped to the audible MIDI range. As previously described in the articleYofiel Scale Remapper, transpositions are applied before key and scale remapping without requiring any additional processing overhead during play.
When the maximum number of voices decreases, an additional subpatch stores the age-queue values which are truncated from the available voice-age queue. It then restores the saved queue values if the number of voices subsequently increases.
During play, the demonstration patch creates outputs for the display kslider from three resulting data strings: a voice-pitch-gate list, in a PACK object, whence voice-on messages may be also extracted for poly~ control; a "$1 0" message which clears the stored values for the voice in $1, whence voice-off and mute messages may be created; and a "set $1 0" message which deactivates the transposed pitch on the second kslider display. With the open-architecture design, additional messages to control pitch and voices may be generated as needed.
This design is from a subcomponent of the Godel 3.1 instrument, which is currently still in alpha.
A demonstration patch is available in the Synthcore2 bundle.