Closed mrpippy closed 3 years ago
First guess is that we may need to return an appropriate HRESULT to get working behavior. Otherwise I can only imagine there being a path where the input/output channels match... seems unlikely though, especially 5.1->5.1 which would be really expensive to process.
My mistake... looks like we already do, but it's a pretty sloppy block:
I suppose we'll have to figure out how to handle this non-destructively (assuming that 5.1->5.1 path doesn't exist... man I hope it doesn't).
Looks like the source to XAudio2.7 matches the documentation, so the above block is indeed the real issue:
https://github.com/Microsoft/DirectXTK/issues/170#issuecomment-479617599
I made a test app that makes the same calls as the game, and the SetEffectChain()
call that fails with FAudio succeeds on Windows. I guess that means it actually supports 5.1->5.1?
https://gist.github.com/mrpippy/f2ddbf57bed572c0f056612dbdf8f98f
The game later crashes when it tries to call SetEffectParameters()
on the submix voice, but the effect chain never got set.
Odd, it produces working sound as well? I wonder if there's a path for matching channels.
In any case this moves the issue to reverb, which is less scary but does involve messing with all the arrays to support 6<->6 processing.
Yeah, the game produces working sound on Windows (just a laptop with 2 channel output)
Some quick shortcut links...
I think those are the only spots that need new code, but as with most things I always forget some detail in there.
I was able to stub-out the 5.1->5.1 reverb support and the game gets to the menu, I don't have the audio knowledge to take this farther though.
Also the game uses XAPO FXECHO (see the bottom of the test app) which isn't implemented.
diff --git a/src/FAudioFX_reverb.c b/src/FAudioFX_reverb.c
index bd58a06..1fbd60b 100644
--- a/src/FAudioFX_reverb.c
+++ b/src/FAudioFX_reverb.c
@@ -521,7 +521,7 @@ static inline void DspReverb_Create(
) {
int32_t i, c;
- FAudio_assert(in_channels == 1 || in_channels == 2);
+ FAudio_assert(in_channels == 1 || in_channels == 2 || out_channels == 6);
FAudio_assert(out_channels == 1 || out_channels == 2 || out_channels == 6);
FAudio_zero(reverb, sizeof(DspReverb));
@@ -1015,6 +1015,65 @@ static inline float DspReverb_INTERNAL_Process_2_to_5p1(
return squared_sum;
}
+static inline float DspReverb_INTERNAL_Process_5p1_to_5p1(
+ DspReverb *reverb,
+ float *restrict samples_in,
+ float *restrict samples_out,
+ size_t sample_count
+) {
+ const float *in_end = samples_in + sample_count;
+ float in, in_ratio, early, late[4];
+ float squared_sum = 0;
+ int32_t c;
+
+ while (samples_in < in_end)
+ {
+#if 0
+ /* Input - Combine 2 channels into 1 */
+ in = (samples_in[0] + samples_in[1]) / 2.0f;
+ in_ratio = in * reverb->dry_ratio;
+ samples_in += 2;
+
+ /* Early Reflections */
+ early = DspReverb_INTERNAL_ProcessEarly(reverb, in);
+
+ /* Reverberation with Wet/Dry Mix */
+ for (c = 0; c < 4; c += 1)
+ {
+ late[c] = (DspReverb_INTERNAL_ProcessChannel(
+ reverb,
+ &reverb->channel[c],
+ early
+ ) * reverb->wet_ratio) + in_ratio;
+ squared_sum += late[c] * late[c];
+ }
+
+ /* Output */
+ *samples_out++ = late[0]; /* Front Left */
+ *samples_out++ = late[1]; /* Front Right */
+ *samples_out++ = 0.0f; /* Center */
+ *samples_out++ = 0.0f; /* LFE */
+ *samples_out++ = late[2]; /* Rear Left */
+ *samples_out++ = late[3]; /* Rear Right */
+#endif
+
+ squared_sum += *samples_in * *samples_in;
+ *samples_out++ = *samples_in++; /* Front Left */
+ squared_sum += *samples_in * *samples_in;
+ *samples_out++ = *samples_in++; /* Front Right */
+ squared_sum += *samples_in * *samples_in;
+ *samples_out++ = *samples_in++; /* Center */
+ squared_sum += *samples_in * *samples_in;
+ *samples_out++ = *samples_in++; /* LFE */
+ squared_sum += *samples_in * *samples_in;
+ *samples_out++ = *samples_in++; /* Rear Left */
+ squared_sum += *samples_in * *samples_in;
+ *samples_out++ = *samples_in++; /* Rear Right */
+ }
+
+ return squared_sum;
+}
+
#undef OUTPUT_SAMPLE
/* Reverb FAPO Implementation */
@@ -1252,7 +1311,9 @@ uint32_t FAudioFXReverb_LockForProcess(
pOutputLockedParameters->pFormat->nChannels == 6)) ||
(pInputLockedParameters->pFormat->nChannels == 2 &&
(pOutputLockedParameters->pFormat->nChannels == 2 ||
- pOutputLockedParameters->pFormat->nChannels == 6))))
+ pOutputLockedParameters->pFormat->nChannels == 6)) ||
+ (pInputLockedParameters->pFormat->nChannels == 6 &&
+ pOutputLockedParameters->pFormat->nChannels == 6)))
{
return FAPO_E_FORMAT_UNSUPPORTED;
}
@@ -1295,7 +1356,7 @@ static inline void FAudioFXReverb_CopyBuffer(
return;
}
- /* 1 -> 1 or 2 -> 2 */
+ /* 1 -> 1, 2 -> 2, 5.1 -> 5.1 */
if (fapo->inBlockAlign == fapo->outBlockAlign)
{
FAudio_memcpy(
@@ -1421,10 +1482,14 @@ void FAudioFXReverb_Process(
{
total = PROCESS(1, 5p1);
}
- else
+ else if (fapo->reverb.in_channels == 2)
{
total = PROCESS(2, 5p1);
}
+ else
+ {
+ total = PROCESS(5p1, 5p1);
+ }
break;
}
#undef PROCESS
See #262. Supporting 5p1->5p1 reverb is enough to get sound working for me in the game. I didn't see any evidence that it tries to create an echo fx.
Should be fixed in master now.
Rez Infinite from Steam asserts in
FAudioFXReverb_LockForProcess()
soon after startup, it looks like the issue is that input and output channels are both 5.1. I'm not sure if the XAudio2 reverb APO actually supports this (despite claiming not to), or if the channel counts just aren't correct.Log messages: https://gist.github.com/mrpippy/3edad985fd515c2d9d71e4cc8cac1261