[sdiy] Voice assignment algorithms
Scott Gravenhorst
music.maker at gte.net
Thu Mar 25 19:06:45 CET 2010
Tom Wiltshire <tom at electricdruid.net> wrote:
>Hi All,
>
>I've been thinking about voice assignment recently, and doing some
>experiments with software. Once I've got an algorithm I'm happy with,
>I'll probably move the principles onto a PIC or dsPIC in either C or
>assembly. But first I need to know what I'm doing - I'd be a damn
>fool to try and develop the logic in assembly.
>
>The system I've got currently stores two stacks of voices; the free
>stack and the busy stack. All the free voices are stored in the free
>stack, and all the voices that are playing a note are in the busy
>stack. Each stack also stores pointers to the first voice in the
>stack and the last voice. Additionally, there is an array of all the
>MIDI notes, which stores which voice is playing that note, if any
>(the 'notes' array).
>
>When a new note is played (a Note On event) the voice assigner looks
>to see if the pointer to the first free voice is valid. If it is,
>we've got a free voice, and it removes that voice from the free stack
>and puts it on the end of the busy stack (at the position indicated
>by the 'last' pointer for that stack). If there's no free voice, it
>instead takes the voice from the front of the busy stack (e.g. the
>oldest busy voice), sets it up with its new data, and sticks it back
>on the end of the busy stack.
>
>When a Note Off event arrives, we can look up which voice is playing
>that note in the 'notes' array. This is mostly for speed and
>convenience- I could have searched through the stack, it wouldn't
>have taken *that* long. The voice is then removed from the busy stack
>(from whichever position it's in) and placed back on the end of the
>free stack.
>
>This seems like a reasonable scheme from many points of view (and
>seems to be fast), but there are things it doesn't do. For example,
>it doesn't cope particularly well when set up with only a single
>voice (e.g. monophonic). And specifically, if you play and release a
>note whilst holding down a previous note, you'll get silence after
>the release, whereas most monophonic synths store the held keys and
>fall back to the previously-held key.
>
>Does anyone know of any papers that discuss this sort of stuff, or
>where I could find more information? Has anyone else tried writing
>polyphonic/monophonic voice assignment schemes? Any experience to offer?
Yes, I've done polyphonic synthesis with more than one FPGA synth design. These are
8 and 16 voice designs using an 8 bit processor. Regardless of the fact that I'm
using a completely different technology, there are some similarities between what you
want and what I've done.
My MIDI controller runs in an embedded soft microcontroller (PicoBlaze). This does
the same things as a PIC or whatever might be used if an external uC were used. It
executes a RISC set of assembly language instructions.
In my designs, the MIDI controller does the voice assignment. It keeps track of
playing versus silent voices with a bit that is set or clear for each voice. There
is also a byte of SRAM dedicated to the note number value of each note that is playing.
My assignment system is based on round-robin which handles voice stealing when
required. When a NOTE ON is received, the gate bits are checked with the round robin
algorithm to hopefully locate a silent voice. When the voice is found, the bit is
set and the NOTE ON note number is stored in that voice's RAM location. If there are
no silent voices available, the "thief pointer" is used to select a playing voice
(the algorithm will select the "oldest" playing voice). Then the thief pointer is
incremented with modulo [voices]. On NOTE OFF, the gate bits are again scanned to
locate any playing voices. For each playing voice, the note number stored for the
voice is compared with the note number contained within the NOTE OFF message and if a
match is found, the gate bit is cleared and the gate output bit for that voice is
cleared.
I didn't consider a stack system because while the PicoBlaze uC has a stack, it's not
that robust. I also wanted round robin so as to support steal-the-oldest where a
stack system is LIFO, but FIFO seemed more useful to me.
For my monosynths, I use different code precisely for the reason you mentioned. My
monosynth code supports holding down as many as 32 keys and upon key releases, the
pitch will follow the sequence backwards until the last one is released (assuming the
releases are done in the opposite order of presses - I don't remember testing what
happens if they are released in a different order, but I may have and I believe the
code works correctly). As you wrote, this is done by storing the note values in RAM
in the order they came in.
I don't believe that my polysynth uC code will work in a musically correct way for a
mononsynth.
HTH
-- ScottG
________________________________________________________________________
-- Scott Gravenhorst
-- FPGA MIDI Synthesizer Information: home1.gte.net/res0658s/FPGA_synth/
-- FatMan: home1.gte.net/res0658s/fatman/
-- NonFatMan: home1.gte.net/res0658s/electronics/
-- When the going gets tough, the tough use the command line.
More information about the Synth-diy
mailing list