Voice Allocation

Most adapter drivers that contain a synthesizer miniport driver also contain DirectSound hardware acceleration. This brings up the question of voice allocation between synthesizer voices and hardware-accelerated DirectSound buffers.

DirectMusic synths--both hardware and software--should support multiple instances in order to maximize the number of concurrent clients. A synth writer might be tempted to statically allocate voices to synths, but should probably consider all available instances of synths as drawing from a common, dynamic voice pool. Each instance then reports the available number of voices as the total number available in the pool.

When implemented this way, even a hardware synth with a limited number of physical voices can support numerous synth instances. In real time, the STATS call informs the client of how many voices each instance is currently using. If the dynamic pool is depleted and a synth instance requires a new voice, then that synth instance must implement a voice-stealing scheme to free a voice from within that instance.

The following allocation scheme is based on the idea that voices used by a synthesizer are more easily shared than DirectSound buffers because the driver has control over what data goes in what voice and can make decisions about voice stealing (outlined in the DLS Level 1 specification).

All of the voices available to the miniport driver (hardware, software, or some combination of hardware and software) are divided into two pools. The first pool, the free pool, consists of voices that are not committed anywhere. The second pool, the dynamic pool, consists of voices that are committed to use by synthesizer instances. These voices may or may not currently be in use by a synthesizer instance. The dynamic pool is sized as the maximum number of voices requested by any synthesizer instance, subject to the current contents of the free pool. DirectSound buffers are removed from the free pool upon allocation and returned on deallocation.

The following table contains an example sequence of voice allocations that illustrate the scheme in practice.

Time Request Free Pool Dynamic Pool Miniport Driver Action

T0

Power Up

64

0

Initialize.

T1

DSound (4)

60

0

Statically allocate four voices to DirectSound buffers.

T2

Synth (32)

28

32

Increase dynamic pool to 32 voices.

T3

Synth (24)

28

32

No action. There are already more than 24 voices in the dynamic pool.

T4

DSound (24)

4

32

Statically allocate 24 voices to DirectSound buffers.

T5

Synth (48)

0

36

Increase dynamic pool to 36 voices. (The method that creates the port returns S_FALSE and sets DMUS_PORTPARAMS.dwVoices = 36.)

T6

DSound (10)

0

36

Fail. No voices in free pool.

T7

DSound (-5)

5

36

Free five voices. Note that these do not go back into the dynamic pool, even though the last request (at time T5) was for more than were granted.

Note that DirectSound buffers are actually allocated one by one, and are grouped together in the table for the purpose of readability.

Immediately after a synthesizer pin instance is created, no voices should be allocated based on it. Shortly after creation, a KSPROPERTY_SYNTH_PORTPARAMETERS property item is received. This property item indicates, among other things, the number of voices that are to be associated with this instance. This item also gives the miniport driver the chance to report back the actual new size of the dynamic pool in case all requested voices could not be allocated.