Rather than stopping voices/sources when the device becomes disconnected, the
context can be set to leave them alone. As a consequence, their state will
remain as playing and they'll keep their last known sample offset indefinately.
For applications mindful of this behavior, it will allow resetting or reopening
the device to reconnect and automatically resume where it left off.
For the second-order decoder. Since the delays are adjusted to avoid most high
frequency phase cancelation, the energy-based scaling with the number of
channels used creates a significant HF increase. Using the RMS-based scaling
seems to create a more level response, though it's not perfect either. More
testing and measurements may be needed.
The inverted atomic flag replaces test_and_set+clear with test_and_clear+set,
essentially inverting the flag status. This makes more logical sense for
flagging dirty state, which is less confusing than flagging clean state. The
one caveat is ATOMIC_FLAG_INIT (or default construction in C++20) initializes
the state to true rather than false.
For HOA signals, the number of responses used with slightly varying delays
causes noticeable attenuation in the higher frequencies because of destructive
phase interference. This is not a result of minimum phase alignment (attempts
to compensate for minimum phase had negligible results), nor does it affect
first-order signals (which only has 4 unique responses on each side).
This alternate alignment is only used when doing second-order rendering for
HRTF output, which is not the default with HRTF. It's likely not very ideal,
but it's necessary to prevent second-order rendering with HRTF from sounding
muffled.
This uses a bit more memory (each voice needs to hold buffers for the
deinterleaved samples of each channel, instead of just one buffer for the
current channel being mixed on the device), but it will allow for handling
formats that need or prefer their channels decoded together.