Closed morffiy closed 5 years ago
Send a patch with a test to verify this and we should be all set. I generally don’t touch this file without a very specific test to compare with.
@flibitijibibo 1.) Set all DSPSetting in F3DAUDIO_DISTANCE_CURVE_POINT for pLFECurve in F3DAUDIO_EMITTER to 0.0f 2.) Run CalculateMatrix with F3DAUDIO_CALCULATE_REDIRECT_TO_LFE.
LFE channel must be silent but it is not due to you redirect pVolumeCurve but not pLFECurve
Makes sense - we probably just need to pass LFEattenuation into that function and change the line as you suggested. If you can send this in patch form I can merge it along with the other one, provided these fix whatever it is you’re running into.
@@ -947,6 +947,7 @@ static inline void ComputeEmitterChannelCoefficients(
float innerRadius,
F3DAUDIO_VECTOR channelPosition,
float attenuation,
+ float LFEattenuation,
uint32_t flags,
uint32_t currentChannel,
uint32_t numSrcChannels,
@@ -1124,7 +1125,7 @@ static inline void ComputeEmitterChannelCoefficients(
if (flags & F3DAUDIO_CALCULATE_REDIRECT_TO_LFE)
{
FAudio_assert(curConfig->LFSpeakerIdx != -1);
- pMatrixCoefficients[curConfig->LFSpeakerIdx * numSrcChannels + currentChannel] += attenuation;
+ pMatrixCoefficients[curConfig->LFSpeakerIdx * numSrcChannels + currentChannel] += LFEattenuation;
}
}
@@ -1288,6 +1289,7 @@ static inline void CalculateMatrix(
pEmitter->InnerRadius,
listenerToEmChannel,
attenuation,
+ LFEattenuation,
Flags,
0 /* currentChannel */,
1 /* numSrcChannels */,
@@ -1330,6 +1332,7 @@ static inline void CalculateMatrix(
pEmitter->InnerRadius,
listenerToEmChannel,
attenuation,
+ 0.0f,
Flags,
iEC,
pEmitter->ChannelCount,
Should we be using LFEattenuation instead of 0.0f for multi-channel emitters?
LFEattenuation is used by multi-channel emitters: https://github.com/FNA-XNA/FAudio/blob/5f27fa295d4f54c2aa22a7f2055dd10511db4d29/src/F3DAudio.c#L1310 IMHO it would be better to get rid of this "if" and pass LFEattenuation to ComputeEmitterChannelCoefficients instead of 0.0f
I'm thinking the same thing - if we can do exactly that and have the math come out right in the official 3D sample (EDIT: Maybe not, I don't think this has a multi-channel emitter sample)...
https://github.com/walbourn/directx-sdk-samples/tree/master/XAudio2/XAudio2Sound3D https://github.com/SveSop/wine_patches/blob/master/xaudio.tar.xz
... then that's probably the best way to fix this.
Remembered @lamarqua's test case for this: https://github.com/lamarqua/F3DAudio_tool/blob/master/smalltool/smalltool.cpp#L827
Okay, so it turns out it's really weird. Here's a test program:
#include <stdio.h>
#include <F3DAudio.h>
int main(int argc, char **argv)
{
F3DAUDIO_HANDLE instance;
F3DAUDIO_LISTENER listener;
F3DAUDIO_EMITTER emitter;
F3DAUDIO_DSP_SETTINGS dsp;
float matrix[12];
float kChannelAzimuths2[] = { 0.0f, F3DAUDIO_PI / 2.0f, F3DAUDIO_PI, F3DAUDIO_PI / 4.0f };
F3DAUDIO_DISTANCE_CURVE_POINT volPt[] = { { 0.0f, 0.5f }, { 1.0f, 0.5f } };
F3DAUDIO_DISTANCE_CURVE_POINT lfePt[] = { { 0.0f, 0.3f }, { 1.0f, 0.3f } };
F3DAUDIO_DISTANCE_CURVE volume = { volPt, 2 };
F3DAUDIO_DISTANCE_CURVE lfe = { lfePt, 2 };
listener.OrientFront.x = 0.0f;
listener.OrientFront.y = -1.0f;
listener.OrientFront.z = 0.0f;
listener.OrientTop.x = 1.0f;
listener.OrientTop.y = 0.0f;
listener.OrientTop.z = 0.0f;
listener.Position.x = 0.0f;
listener.Position.y = 0.0f;
listener.Position.z = 0.0f;
listener.Velocity.x = 0.0f;
listener.Velocity.y = 0.0f;
listener.Velocity.z = 0.0f;
listener.pCone = NULL;
emitter.pCone = NULL;
emitter.OrientFront.x = 0.0f;
emitter.OrientFront.y = 1.0f;
emitter.OrientFront.z = 0.0f;
emitter.OrientTop.x = 1.0f;
emitter.OrientTop.y = 0.0f;
emitter.OrientTop.z = 0.0f;
emitter.Position.x = 0.0f;
emitter.Position.y = -1.0f;
emitter.Position.z = 0.0f;
emitter.Velocity.x = 0.0f;
emitter.Velocity.y = 0.0f;
emitter.Velocity.z = 0.0f;
emitter.InnerRadius = 0.0f;
emitter.InnerRadiusAngle = 0.0f;
emitter.ChannelCount = 4;
emitter.ChannelRadius = 0.0f;
emitter.pChannelAzimuths = kChannelAzimuths2;
emitter.pVolumeCurve = &volume;
emitter.pLFECurve = &lfe;
emitter.pLPFDirectCurve = NULL;
emitter.pLPFReverbCurve = NULL;
emitter.pReverbCurve = NULL;
emitter.CurveDistanceScaler = 1.0f;
emitter.DopplerScaler = 1.0f;
dsp.pMatrixCoefficients = matrix;
dsp.pDelayTimes = NULL;
dsp.SrcChannelCount = 4;
dsp.DstChannelCount = 3;
F3DAudioInitialize(SPEAKER_2POINT1, 343.1f, instance);
F3DAudioCalculate(instance, &listener, &emitter, F3DAUDIO_CALCULATE_MATRIX | F3DAUDIO_CALCULATE_REDIRECT_TO_LFE, &dsp);
printf("%f\t%f\t%f\n%f\t%f\t%f\n%f\t%f\t%f\n%f\t%f\t%f\n",
dsp.pMatrixCoefficients[0], dsp.pMatrixCoefficients[1], dsp.pMatrixCoefficients[2],
dsp.pMatrixCoefficients[3], dsp.pMatrixCoefficients[4], dsp.pMatrixCoefficients[5],
dsp.pMatrixCoefficients[6], dsp.pMatrixCoefficients[7], dsp.pMatrixCoefficients[8],
dsp.pMatrixCoefficients[9], dsp.pMatrixCoefficients[10], dsp.pMatrixCoefficients[11]);
return 0;
}
It turns out that you not only have to pass in LFEattenuation even in that scenario, but you actually have to divide the value by the source channel count! I tried this with various counts and curve values and this definitely seems to be what it does:
https://github.com/FNA-XNA/FAudio/commit/998e914985a40d17811e0da28248cc8b624ef4c4
This was a weird one, thanks for the report!
@flibitijibibo Are sure about this ?
if (emChAzimuth == F3DAUDIO_2PI)
{
MatrixCoefficients[curConfig->LFSpeakerIdx * pEmitter->ChannelCount + iEC] = LFEattenuation;
}
Turns out that actually doesn't intersect with REDIRECT
; if you have an LFE channel in your emitter with that flag set it's an invalid call entirely:
Apply an equal mix of all source channels to a low frequency effect (LFE) destination channel. Only applies to matrix calculations with a source that does not have an LFE channel and a destination that does have an LFE channel. This flag is only valid if X3DAUDIO_CALCULATE_MATRIX is also set.
@flibitijibibo right, just slipped out of my mind.
Same, I actually ran into the assertion failure myself by accident :P
@flibitijibibo
https://github.com/FNA-XNA/FAudio/blob/998e914985a40d17811e0da28248cc8b624ef4c4/src/FAudio.c#L2279
BTW there is a bug in xaudio in GetState method.
voice->SubmitSourceBuffer( &buffer )
voice->Start()
... let it play a bit
voice->Stop()
voice->FlushSourceBuffers()
voice->SubmitSourceBuffer( &buffer )
voice->Start()
XAUDIO2_VOICE_STATE state;
voice->GetState( &state );
ASSERT( state.SamplesPlayed == 0 )
voice->Stop()
voice->FlushSourceBuffers()
if you loop this code the state.SamplesPlayed will never be zero again it will grow to infinity
@flibitijibibo Regarding this
* Note: It is SUSPICIOUSLY close to 1/sqrt(2), but I haven't figured out why.
and this
/* Lerping here is an approximation.
* TODO: High accuracy version. Having stared at the curves long
* enough, I'm pretty sure this is a quadratic, but trying to
* polyfit with numpy didn't give nice, round polynomial
* coefficients...
* -Adrien
*/
1/sqrt(2) = -3db = 45 degrees
i think this
ms = LERP(2.0f * normalizedRadialDist, 0.0f, DIFFUSION_LERP_MIDPOINT_VALUE);
should be
float DBToLinear( float db ) {
return powf( 2.0f, db * ( 1.0f / 6.0f ) );
}
ms = DBToLinear( LERP(2.0f * normalizedRadialDist, -96, -3 ) );
and this
ms = LERP(2.0f * (normalizedRadialDist - 0.5f), DIFFUSION_LERP_MIDPOINT_VALUE, 1.0f);
should be
float DBToLinear( float db ) {
return powf( 2.0f, db * ( 1.0f / 6.0f ) );
}
ms = DBToLinear( LERP(2.0f * (normalizedRadialDist - 0.5f), -3, 0.0f) );
BR Tima
Can you run the 3D idea against @lamarqua’s tests?
https://github.com/lamarqua/F3DAudio_tool
The SamplesPlayed idea should be added to this test program:
https://github.com/FNA-XNA/FAudio/blob/master/tests/xaudio2.c
Your GetState report appears to be invalid:
https://github.com/FNA-XNA/FAudio/commit/f9dd17926d30fee149430f30f082c00a4d19bcf3 EDIT: https://github.com/FNA-XNA/FAudio/commit/49461af86d0f67b0ee0c0b4d18f01d00120f456c
Wait, so the bug is on your end...? It sounds like the assert is deliberately wrong.
Why deliberately wrong ? After the voice is started the SamplesPlayed should be ~0 but in my case it points deep inside, ~somewhere it was stopped before it was playing.
AFAIK that's the official behavior - the specification suggests that stopping the voice will reset SamplesPlayed but it looks like stopping and even flushing the buffers doesn't do this. The only way to reset the value is either to submit a buffer with END_OF_STREAM or call Discontinuity(), which sets the flag after submitting the buffer.
No. either END_OF_STREAM or call Discontinuity() won't help, i double checked it.
You'll most likely have to wait for the buffer to completely finish - you'll get an OnStreamEnd event:
No. i did check it too. I waited ~1 minute before starting the voice which has been stopped and it still keeps on fire the assert.
Very well - you will need to write the unit test yourself, I cannot verify this on my end and I can't spend any more time on it.
/* Lerping here is an approximation. * TODO: High accuracy version. Having stared at the curves long * enough, I'm pretty sure this is a quadratic, but trying to * polyfit with numpy didn't give nice, round polynomial * coefficients... * -Adrien */
1/sqrt(2) = -3db = 45 degrees
i think this
ms = LERP(2.0f * normalizedRadialDist, 0.0f, DIFFUSION_LERP_MIDPOINT_VALUE);
should be
float DBToLinear( float db ) { return powf( 2.0f, db * ( 1.0f / 6.0f ) ); } ms = DBToLinear( LERP(2.0f * normalizedRadialDist, -96, -3 ) );
and this
ms = LERP(2.0f * (normalizedRadialDist - 0.5f), DIFFUSION_LERP_MIDPOINT_VALUE, 1.0f);
should be
float DBToLinear( float db ) { return powf( 2.0f, db * ( 1.0f / 6.0f ) ); } ms = DBToLinear( LERP(2.0f * (normalizedRadialDist - 0.5f), -3, 0.0f) );
I don't quite remember all the minutiae about this but I think you might be onto something. I recently read a paper on spatialization and it seems that there are a whole bunch of methods to preserve constant power (rather than amplitude). See this article for example, section 1 ("Law of tangents", maybe this is equivalent to what you're doing but I can't do the formulation / calculation right now). I was going to return to this and fix it eventually but sounds like you are already on it :)
https://github.com/FNA-XNA/FAudio/blob/f7a0ce7e84933ea4913ca130d74cd39e5c080259/src/F3DAudio.c#L1127
The ComputeEmitterChannelCoefficients function does not take into acount LFEDistanceCurve. Maybe this line should look like:
pMatrixCoefficients[ curConfig->LFSpeakerIdx * numSrcChannels + currentChannel ] += LFEattenuation;
The comment in CalculateMatrix function seems to be true
/* TODO: this could be skipped if the destination has no LFE */
:+1: It really skipped for none multi-channel emitters..