1 /* DirectSound EAX interface
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "dsound_private.h"
28 #define EAX2LISTENERFLAGS_MASK (EAX20LISTENERFLAGS_DECAYTIMESCALE | \
29 EAX20LISTENERFLAGS_REFLECTIONSSCALE | \
30 EAX20LISTENERFLAGS_REFLECTIONSDELAYSCALE | \
31 EAX20LISTENERFLAGS_REVERBSCALE | \
32 EAX20LISTENERFLAGS_REVERBDELAYSCALE | \
33 EAX20LISTENERFLAGS_DECAYHFLIMIT)
35 static EAX20LISTENERPROPERTIES
EAX3To2(const EAX30LISTENERPROPERTIES
*props
)
37 EAX20LISTENERPROPERTIES ret
;
38 ret
.lRoom
= props
->lRoom
;
39 ret
.lRoomHF
= props
->lRoomHF
;
40 ret
.flRoomRolloffFactor
= props
->flRoomRolloffFactor
;
41 ret
.flDecayTime
= props
->flDecayTime
;
42 ret
.flDecayHFRatio
= props
->flDecayHFRatio
;
43 ret
.lReflections
= props
->lReflections
;
44 ret
.flReflectionsDelay
= props
->flReflectionsDelay
;
45 ret
.lReverb
= props
->lReverb
;
46 ret
.flReverbDelay
= props
->flReverbDelay
;
47 ret
.dwEnvironment
= props
->dwEnvironment
;
48 ret
.flEnvironmentSize
= props
->flEnvironmentSize
;
49 ret
.flEnvironmentDiffusion
= props
->flEnvironmentDiffusion
;
50 ret
.flAirAbsorptionHF
= props
->flAirAbsorptionHF
;
51 ret
.dwFlags
= props
->dwFlags
& EAX2LISTENERFLAGS_MASK
;
55 static void ApplyReverbParams(DS8Primary
*prim
, const EAX30LISTENERPROPERTIES
*props
)
57 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
58 prim
->deferred
.eax
= *props
;
59 alEffectf(prim
->effect
, AL_EAXREVERB_DENSITY
,
60 clampF(powf(props
->flEnvironmentSize
, 3.0f
) / 16.0f
, 0.0f
, 1.0f
)
62 alEffectf(prim
->effect
, AL_EAXREVERB_DIFFUSION
, props
->flEnvironmentDiffusion
);
64 alEffectf(prim
->effect
, AL_EAXREVERB_GAIN
, mB_to_gain(props
->lRoom
));
65 alEffectf(prim
->effect
, AL_EAXREVERB_GAINHF
, mB_to_gain(props
->lRoomHF
));
66 alEffectf(prim
->effect
, AL_EAXREVERB_GAINLF
, mB_to_gain(props
->lRoomLF
));
68 alEffectf(prim
->effect
, AL_EAXREVERB_DECAY_TIME
, props
->flDecayTime
);
69 alEffectf(prim
->effect
, AL_EAXREVERB_DECAY_HFRATIO
, props
->flDecayHFRatio
);
70 alEffectf(prim
->effect
, AL_EAXREVERB_DECAY_LFRATIO
, props
->flDecayLFRatio
);
72 alEffectf(prim
->effect
, AL_EAXREVERB_REFLECTIONS_GAIN
, mB_to_gain(props
->lReflections
));
73 alEffectf(prim
->effect
, AL_EAXREVERB_REFLECTIONS_DELAY
, props
->flReflectionsDelay
);
74 alEffectfv(prim
->effect
, AL_EAXREVERB_REFLECTIONS_PAN
, &props
->vReflectionsPan
.x
);
76 alEffectf(prim
->effect
, AL_EAXREVERB_LATE_REVERB_GAIN
, mB_to_gain(props
->lReverb
));
77 alEffectf(prim
->effect
, AL_EAXREVERB_LATE_REVERB_DELAY
, props
->flReverbDelay
);
78 alEffectfv(prim
->effect
, AL_EAXREVERB_LATE_REVERB_PAN
, &props
->vReverbPan
.x
);
80 alEffectf(prim
->effect
, AL_EAXREVERB_ECHO_TIME
, props
->flEchoTime
);
81 alEffectf(prim
->effect
, AL_EAXREVERB_ECHO_DEPTH
, props
->flEchoDepth
);
83 alEffectf(prim
->effect
, AL_EAXREVERB_MODULATION_TIME
, props
->flModulationTime
);
84 alEffectf(prim
->effect
, AL_EAXREVERB_MODULATION_DEPTH
, props
->flModulationDepth
);
86 alEffectf(prim
->effect
, AL_EAXREVERB_AIR_ABSORPTION_GAINHF
,
87 mB_to_gain(props
->flAirAbsorptionHF
));
89 alEffectf(prim
->effect
, AL_EAXREVERB_HFREFERENCE
, props
->flHFReference
);
90 alEffectf(prim
->effect
, AL_EAXREVERB_LFREFERENCE
, props
->flLFReference
);
92 alEffectf(prim
->effect
, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR
, props
->flRoomRolloffFactor
);
94 alEffecti(prim
->effect
, AL_EAXREVERB_DECAY_HFLIMIT
,
95 (props
->dwFlags
&EAX30LISTENERFLAGS_DECAYHFLIMIT
) ?
100 prim
->dirty
.bit
.effect
= 1;
103 #define APPLY_DRY_PARAMS 1
104 #define APPLY_WET_PARAMS 2
105 static void ApplyFilterParams(DS8Buffer
*buf
, const EAX20BUFFERPROPERTIES
*props
, int apply
)
107 /* The LFRatio properties determine how much the given level applies to low
108 * frequencies as well as high frequencies. Given that the high frequency
109 * levels are specified relative to the low, they should increase as the
110 * low frequency levels reduce.
112 FLOAT occl
= props
->lOcclusion
* props
->flOcclusionLFRatio
;
113 FLOAT occlhf
= props
->lOcclusion
* (1.0f
-props
->flOcclusionLFRatio
);
115 if((apply
&APPLY_DRY_PARAMS
))
117 FLOAT obstr
= props
->lObstruction
* props
->flObstructionLFRatio
;
118 FLOAT obstrhf
= props
->lObstruction
* (1.0f
-props
->flObstructionLFRatio
);
119 FLOAT mb
= props
->lDirect
+ obstr
+ occl
;
120 FLOAT mbhf
= props
->lDirectHF
+ obstrhf
+ occlhf
;
122 alFilterf(buf
->filter
[0], AL_LOWPASS_GAIN
, mB_to_gain(mb
));
123 alFilterf(buf
->filter
[0], AL_LOWPASS_GAINHF
, mB_to_gain(mbhf
));
125 if((apply
&APPLY_WET_PARAMS
))
127 FLOAT occlroom
= props
->flOcclusionRoomRatio
;
128 FLOAT mb
= props
->lRoom
+ occlroom
*occl
;
129 FLOAT mbhf
= props
->lRoomHF
+ occlroom
*occlhf
;
131 alFilterf(buf
->filter
[1], AL_LOWPASS_GAIN
, mB_to_gain(mb
));
132 alFilterf(buf
->filter
[1], AL_LOWPASS_GAINHF
, mB_to_gain(mbhf
));
138 HRESULT
EAX2_Set(DS8Primary
*prim
, DWORD propid
, void *pPropData
, ULONG cbPropData
)
142 if(prim
->effect
== 0)
143 return E_PROP_ID_UNSUPPORTED
;
145 hr
= DSERR_INVALIDPARAM
;
148 case DSPROPERTY_EAX20LISTENER_NONE
: /* not setting any property, just applying */
152 case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS
:
153 if(cbPropData
>= sizeof(EAX20LISTENERPROPERTIES
))
157 const EAX20LISTENERPROPERTIES
*props
;
158 } data
= { pPropData
};
159 EAX30LISTENERPROPERTIES props3
= REVERB_PRESET_GENERIC
;
160 if(data
.props
->dwEnvironment
< EAX_ENVIRONMENT_COUNT
)
162 props3
= EnvironmentDefaults
[data
.props
->dwEnvironment
];
163 props3
.dwEnvironment
= data
.props
->dwEnvironment
;
165 props3
.flEnvironmentSize
= data
.props
->flEnvironmentSize
;
166 props3
.flEnvironmentDiffusion
= data
.props
->flEnvironmentDiffusion
;
167 props3
.lRoom
= data
.props
->lRoom
;
168 props3
.lRoomHF
= data
.props
->lRoomHF
;
169 props3
.flDecayTime
= data
.props
->flDecayTime
;
170 props3
.flDecayHFRatio
= data
.props
->flDecayHFRatio
;
171 props3
.lReflections
= data
.props
->lReflections
;
172 props3
.flReflectionsDelay
= data
.props
->flReflectionsDelay
;
173 props3
.lReverb
= data
.props
->lReverb
;
174 props3
.flReverbDelay
= data
.props
->flReverbDelay
;
175 props3
.flAirAbsorptionHF
= data
.props
->flAirAbsorptionHF
;
176 props3
.flRoomRolloffFactor
= data
.props
->flRoomRolloffFactor
;
177 props3
.dwFlags
= data
.props
->dwFlags
;
179 ApplyReverbParams(prim
, &props3
);
184 case DSPROPERTY_EAX20LISTENER_ROOM
:
185 if(cbPropData
>= sizeof(LONG
))
187 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
189 prim
->deferred
.eax
.lRoom
= *data
.l
;
190 alEffectf(prim
->effect
, AL_EAXREVERB_GAIN
,
191 mB_to_gain(prim
->deferred
.eax
.lRoom
));
194 prim
->dirty
.bit
.effect
= 1;
198 case DSPROPERTY_EAX20LISTENER_ROOMHF
:
199 if(cbPropData
>= sizeof(LONG
))
201 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
203 prim
->deferred
.eax
.lRoomHF
= *data
.l
;
204 alEffectf(prim
->effect
, AL_EAXREVERB_GAINHF
,
205 mB_to_gain(prim
->deferred
.eax
.lRoomHF
));
208 prim
->dirty
.bit
.effect
= 1;
213 case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR
:
214 if(cbPropData
>= sizeof(FLOAT
))
216 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
218 prim
->deferred
.eax
.flRoomRolloffFactor
= *data
.fl
;
219 alEffectf(prim
->effect
, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR
,
220 prim
->deferred
.eax
.flRoomRolloffFactor
);
223 prim
->dirty
.bit
.effect
= 1;
228 case DSPROPERTY_EAX20LISTENER_DECAYTIME
:
229 if(cbPropData
>= sizeof(FLOAT
))
231 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
233 prim
->deferred
.eax
.flDecayTime
= *data
.fl
;
234 alEffectf(prim
->effect
, AL_EAXREVERB_DECAY_TIME
,
235 prim
->deferred
.eax
.flDecayTime
);
238 prim
->dirty
.bit
.effect
= 1;
242 case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO
:
243 if(cbPropData
>= sizeof(FLOAT
))
245 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
247 prim
->deferred
.eax
.flDecayHFRatio
= *data
.fl
;
248 alEffectf(prim
->effect
, AL_EAXREVERB_DECAY_HFRATIO
,
249 prim
->deferred
.eax
.flDecayHFRatio
);
252 prim
->dirty
.bit
.effect
= 1;
257 case DSPROPERTY_EAX20LISTENER_REFLECTIONS
:
258 if(cbPropData
>= sizeof(LONG
))
260 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
262 prim
->deferred
.eax
.lReflections
= *data
.l
;
263 alEffectf(prim
->effect
, AL_EAXREVERB_REFLECTIONS_GAIN
,
264 mB_to_gain(prim
->deferred
.eax
.lReflections
));
267 prim
->dirty
.bit
.effect
= 1;
271 case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY
:
272 if(cbPropData
>= sizeof(FLOAT
))
274 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
276 prim
->deferred
.eax
.flReflectionsDelay
= *data
.fl
;
277 alEffectf(prim
->effect
, AL_EAXREVERB_REFLECTIONS_DELAY
,
278 prim
->deferred
.eax
.flReflectionsDelay
);
281 prim
->dirty
.bit
.effect
= 1;
286 case DSPROPERTY_EAX20LISTENER_REVERB
:
287 if(cbPropData
>= sizeof(LONG
))
289 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
291 prim
->deferred
.eax
.lReverb
= *data
.l
;
292 alEffectf(prim
->effect
, AL_EAXREVERB_LATE_REVERB_GAIN
,
293 mB_to_gain(prim
->deferred
.eax
.lReverb
));
296 prim
->dirty
.bit
.effect
= 1;
300 case DSPROPERTY_EAX20LISTENER_REVERBDELAY
:
301 if(cbPropData
>= sizeof(FLOAT
))
303 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
305 prim
->deferred
.eax
.flReverbDelay
= *data
.fl
;
306 alEffectf(prim
->effect
, AL_EAXREVERB_LATE_REVERB_DELAY
,
307 prim
->deferred
.eax
.flReverbDelay
);
310 prim
->dirty
.bit
.effect
= 1;
315 case DSPROPERTY_EAX20LISTENER_ENVIRONMENT
:
316 if(cbPropData
>= sizeof(DWORD
))
318 union { const void *v
; const DWORD
*dw
; } data
= { pPropData
};
319 if(*data
.dw
< EAX_ENVIRONMENT_COUNT
)
321 ApplyReverbParams(prim
, &EnvironmentDefaults
[*data
.dw
]);
327 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE
:
328 if(cbPropData
>= sizeof(FLOAT
))
330 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
331 if(*data
.fl
>= 1.0f
&& *data
.fl
<= 100.0f
)
333 float scale
= (*data
.fl
)/prim
->deferred
.eax
.flEnvironmentSize
;
335 prim
->deferred
.eax
.flEnvironmentSize
= *data
.fl
;
337 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_DECAYTIMESCALE
))
339 prim
->deferred
.eax
.flDecayTime
*= scale
;
340 prim
->deferred
.eax
.flDecayTime
= clampF(prim
->deferred
.eax
.flDecayTime
, 0.1f
, 20.0f
);
342 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_REFLECTIONSSCALE
))
344 prim
->deferred
.eax
.lReflections
-= gain_to_mB(scale
);
345 prim
->deferred
.eax
.lReflections
= clampI(prim
->deferred
.eax
.lReflections
, -10000, 1000);
347 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_REFLECTIONSDELAYSCALE
))
349 prim
->deferred
.eax
.flReflectionsDelay
*= scale
;
350 prim
->deferred
.eax
.flReflectionsDelay
= clampF(prim
->deferred
.eax
.flReflectionsDelay
, 0.0f
, 0.3f
);
352 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_REVERBSCALE
))
354 prim
->deferred
.eax
.lReverb
-= gain_to_mB(scale
);
355 prim
->deferred
.eax
.lReverb
= clampI(prim
->deferred
.eax
.lReverb
, -10000, 2000);
357 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_REVERBDELAYSCALE
))
359 prim
->deferred
.eax
.flReverbDelay
*= scale
;
360 prim
->deferred
.eax
.flReverbDelay
= clampF(prim
->deferred
.eax
.flReverbDelay
, 0.0f
, 0.1f
);
362 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_ECHOTIMESCALE
))
364 prim
->deferred
.eax
.flEchoTime
*= scale
;
365 prim
->deferred
.eax
.flEchoTime
= clampF(prim
->deferred
.eax
.flEchoTime
, 0.075f
, 0.25f
);
367 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_MODTIMESCALE
))
369 prim
->deferred
.eax
.flModulationTime
*= scale
;
370 prim
->deferred
.eax
.flModulationTime
= clampF(prim
->deferred
.eax
.flModulationTime
, 0.04f
, 4.0f
);
373 ApplyReverbParams(prim
, &prim
->deferred
.eax
);
378 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION
:
379 if(cbPropData
>= sizeof(FLOAT
))
381 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
383 prim
->deferred
.eax
.flEnvironmentDiffusion
= *data
.fl
;
384 alEffectf(prim
->effect
, AL_EAXREVERB_DIFFUSION
,
385 prim
->deferred
.eax
.flEnvironmentDiffusion
);
388 prim
->dirty
.bit
.effect
= 1;
393 case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF
:
394 if(cbPropData
>= sizeof(FLOAT
))
396 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
398 prim
->deferred
.eax
.flAirAbsorptionHF
= *data
.fl
;
399 alEffectf(prim
->effect
, AL_EAXREVERB_AIR_ABSORPTION_GAINHF
,
400 mB_to_gain(prim
->deferred
.eax
.flAirAbsorptionHF
));
403 prim
->dirty
.bit
.effect
= 1;
408 case DSPROPERTY_EAX20LISTENER_FLAGS
:
409 if(cbPropData
>= sizeof(DWORD
))
411 union { const void *v
; const DWORD
*dw
; } data
= { pPropData
};
413 prim
->deferred
.eax
.dwFlags
= *data
.dw
;
414 alEffecti(prim
->effect
, AL_EAXREVERB_DECAY_HFLIMIT
,
415 (prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_DECAYHFLIMIT
) ?
419 prim
->dirty
.bit
.effect
= 1;
425 hr
= E_PROP_ID_UNSUPPORTED
;
426 FIXME("Unhandled listener propid: 0x%08lx\n", propid
);
433 HRESULT
EAX2_Get(DS8Primary
*prim
, DWORD propid
, void *pPropData
, ULONG cbPropData
, ULONG
*pcbReturned
)
437 if(prim
->effect
== 0)
438 return E_PROP_ID_UNSUPPORTED
;
440 #define GET_PROP(src, T) do { \
441 if(cbPropData >= sizeof(T)) \
443 union { void *v; T *props; } data = { pPropData }; \
445 *pcbReturned = sizeof(T); \
449 hr
= DSERR_INVALIDPARAM
;
452 case DSPROPERTY_EAX20LISTENER_NONE
:
457 case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS
:
458 GET_PROP(EAX3To2(&prim
->deferred
.eax
), EAX20LISTENERPROPERTIES
);
461 case DSPROPERTY_EAX20LISTENER_ROOM
:
462 GET_PROP(prim
->deferred
.eax
.lRoom
, LONG
);
464 case DSPROPERTY_EAX20LISTENER_ROOMHF
:
465 GET_PROP(prim
->deferred
.eax
.lRoomHF
, LONG
);
468 case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR
:
469 GET_PROP(prim
->deferred
.eax
.flRoomRolloffFactor
, FLOAT
);
472 case DSPROPERTY_EAX20LISTENER_DECAYTIME
:
473 GET_PROP(prim
->deferred
.eax
.flDecayTime
, FLOAT
);
475 case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO
:
476 GET_PROP(prim
->deferred
.eax
.flDecayHFRatio
, FLOAT
);
479 case DSPROPERTY_EAX20LISTENER_REFLECTIONS
:
480 GET_PROP(prim
->deferred
.eax
.lReflections
, LONG
);
482 case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY
:
483 GET_PROP(prim
->deferred
.eax
.flReflectionsDelay
, FLOAT
);
486 case DSPROPERTY_EAX20LISTENER_REVERB
:
487 GET_PROP(prim
->deferred
.eax
.lReverb
, LONG
);
489 case DSPROPERTY_EAX20LISTENER_REVERBDELAY
:
490 GET_PROP(prim
->deferred
.eax
.flReverbDelay
, FLOAT
);
493 case DSPROPERTY_EAX20LISTENER_ENVIRONMENT
:
494 GET_PROP(prim
->deferred
.eax
.dwEnvironment
, DWORD
);
497 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE
:
498 GET_PROP(prim
->deferred
.eax
.flEnvironmentSize
, FLOAT
);
500 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION
:
501 GET_PROP(prim
->deferred
.eax
.flEnvironmentDiffusion
, FLOAT
);
504 case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF
:
505 GET_PROP(prim
->deferred
.eax
.flAirAbsorptionHF
, FLOAT
);
508 case DSPROPERTY_EAX20LISTENER_FLAGS
:
509 GET_PROP(prim
->deferred
.eax
.dwFlags
&EAX2LISTENERFLAGS_MASK
, DWORD
);
513 hr
= E_PROP_ID_UNSUPPORTED
;
514 FIXME("Unhandled listener propid: 0x%08lx\n", propid
);
523 HRESULT
EAX2Buffer_Set(DS8Buffer
*buf
, DWORD propid
, void *pPropData
, ULONG cbPropData
)
527 if(buf
->filter
[0] == 0)
528 return E_PROP_ID_UNSUPPORTED
;
530 hr
= DSERR_INVALIDPARAM
;
533 case DSPROPERTY_EAX20BUFFER_NONE
: /* not setting any property, just applying */
537 case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS
:
538 if(cbPropData
>= sizeof(EAX20BUFFERPROPERTIES
))
542 const EAX20BUFFERPROPERTIES
*props
;
543 } data
= { pPropData
};
545 buf
->deferred
.eax
= *data
.props
;
546 ApplyFilterParams(buf
, data
.props
, APPLY_DRY_PARAMS
|APPLY_WET_PARAMS
);
548 buf
->dirty
.bit
.dry_filter
= 1;
549 buf
->dirty
.bit
.wet_filter
= 1;
550 buf
->dirty
.bit
.room_rolloff
= 1;
551 buf
->dirty
.bit
.cone_outsidevolumehf
= 1;
552 buf
->dirty
.bit
.air_absorb
= 1;
553 buf
->dirty
.bit
.flags
= 1;
558 case DSPROPERTY_EAX20BUFFER_DIRECT
:
559 if(cbPropData
>= sizeof(LONG
))
561 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
563 buf
->deferred
.eax
.lDirect
= *data
.l
;
564 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
);
566 buf
->dirty
.bit
.dry_filter
= 1;
570 case DSPROPERTY_EAX20BUFFER_DIRECTHF
:
571 if(cbPropData
>= sizeof(LONG
))
573 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
575 buf
->deferred
.eax
.lDirectHF
= *data
.l
;
576 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
);
578 buf
->dirty
.bit
.dry_filter
= 1;
583 case DSPROPERTY_EAX20BUFFER_ROOM
:
584 if(cbPropData
>= sizeof(LONG
))
586 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
588 buf
->deferred
.eax
.lRoom
= *data
.l
;
589 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_WET_PARAMS
);
591 buf
->dirty
.bit
.wet_filter
= 1;
595 case DSPROPERTY_EAX20BUFFER_ROOMHF
:
596 if(cbPropData
>= sizeof(LONG
))
598 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
600 buf
->deferred
.eax
.lRoomHF
= *data
.l
;
601 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_WET_PARAMS
);
603 buf
->dirty
.bit
.wet_filter
= 1;
608 case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR
:
609 if(cbPropData
>= sizeof(FLOAT
))
611 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
613 buf
->deferred
.eax
.flRoomRolloffFactor
= *data
.fl
;
615 buf
->dirty
.bit
.room_rolloff
= 1;
620 case DSPROPERTY_EAX20BUFFER_OBSTRUCTION
:
621 if(cbPropData
>= sizeof(LONG
))
623 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
625 buf
->deferred
.eax
.lObstruction
= *data
.l
;
626 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
);
628 buf
->dirty
.bit
.dry_filter
= 1;
632 case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO
:
633 if(cbPropData
>= sizeof(FLOAT
))
635 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
637 buf
->deferred
.eax
.flObstructionLFRatio
= *data
.fl
;
638 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
);
640 buf
->dirty
.bit
.dry_filter
= 1;
645 case DSPROPERTY_EAX20BUFFER_OCCLUSION
:
646 if(cbPropData
>= sizeof(LONG
))
648 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
650 buf
->deferred
.eax
.lOcclusion
= *data
.l
;
651 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
|APPLY_WET_PARAMS
);
653 buf
->dirty
.bit
.dry_filter
= 1;
654 buf
->dirty
.bit
.wet_filter
= 1;
658 case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO
:
659 if(cbPropData
>= sizeof(FLOAT
))
661 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
663 buf
->deferred
.eax
.flOcclusionLFRatio
= *data
.fl
;
664 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
|APPLY_WET_PARAMS
);
666 buf
->dirty
.bit
.dry_filter
= 1;
667 buf
->dirty
.bit
.wet_filter
= 1;
671 case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO
:
672 if(cbPropData
>= sizeof(FLOAT
))
674 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
676 buf
->deferred
.eax
.flOcclusionRoomRatio
= *data
.fl
;
677 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
|APPLY_WET_PARAMS
);
679 buf
->dirty
.bit
.dry_filter
= 1;
680 buf
->dirty
.bit
.wet_filter
= 1;
685 case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF
:
686 if(cbPropData
>= sizeof(LONG
))
688 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
690 buf
->deferred
.eax
.lOutsideVolumeHF
= *data
.l
;
692 buf
->dirty
.bit
.cone_outsidevolumehf
= 1;
697 case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR
:
698 if(cbPropData
>= sizeof(FLOAT
))
700 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
702 buf
->deferred
.eax
.flAirAbsorptionFactor
= *data
.fl
;
704 buf
->dirty
.bit
.air_absorb
= 1;
709 case DSPROPERTY_EAX20BUFFER_FLAGS
:
710 if(cbPropData
>= sizeof(DWORD
))
712 union { const void *v
; const DWORD
*dw
; } data
= { pPropData
};
714 buf
->deferred
.eax
.dwFlags
= *data
.dw
;
716 buf
->dirty
.bit
.flags
= 1;
722 hr
= E_PROP_ID_UNSUPPORTED
;
723 FIXME("Unhandled buffer propid: 0x%08lx\n", propid
);
730 HRESULT
EAX2Buffer_Get(DS8Buffer
*buf
, DWORD propid
, void *pPropData
, ULONG cbPropData
, ULONG
*pcbReturned
)
734 if(buf
->filter
[0] == 0)
735 return E_PROP_ID_UNSUPPORTED
;
737 #define GET_PROP(src, T) do { \
738 if(cbPropData >= sizeof(T)) \
740 union { void *v; T *props; } data = { pPropData }; \
742 *pcbReturned = sizeof(T); \
746 hr
= DSERR_INVALIDPARAM
;
749 case DSPROPERTY_EAX20BUFFER_NONE
:
754 case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS
:
755 GET_PROP(buf
->deferred
.eax
, EAX20BUFFERPROPERTIES
);
758 case DSPROPERTY_EAX20BUFFER_DIRECT
:
759 GET_PROP(buf
->deferred
.eax
.lDirect
, LONG
);
761 case DSPROPERTY_EAX20BUFFER_DIRECTHF
:
762 GET_PROP(buf
->deferred
.eax
.lDirectHF
, LONG
);
765 case DSPROPERTY_EAX20BUFFER_ROOM
:
766 GET_PROP(buf
->deferred
.eax
.lRoom
, LONG
);
768 case DSPROPERTY_EAX20BUFFER_ROOMHF
:
769 GET_PROP(buf
->deferred
.eax
.lRoomHF
, LONG
);
772 case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR
:
773 GET_PROP(buf
->deferred
.eax
.flRoomRolloffFactor
, FLOAT
);
776 case DSPROPERTY_EAX20BUFFER_OBSTRUCTION
:
777 GET_PROP(buf
->deferred
.eax
.lObstruction
, LONG
);
779 case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO
:
780 GET_PROP(buf
->deferred
.eax
.flObstructionLFRatio
, FLOAT
);
783 case DSPROPERTY_EAX20BUFFER_OCCLUSION
:
784 GET_PROP(buf
->deferred
.eax
.lOcclusion
, LONG
);
786 case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO
:
787 GET_PROP(buf
->deferred
.eax
.flOcclusionLFRatio
, FLOAT
);
789 case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO
:
790 GET_PROP(buf
->deferred
.eax
.flOcclusionRoomRatio
, FLOAT
);
793 case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF
:
794 GET_PROP(buf
->deferred
.eax
.lOutsideVolumeHF
, LONG
);
797 case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR
:
798 GET_PROP(buf
->deferred
.eax
.flAirAbsorptionFactor
, FLOAT
);
801 case DSPROPERTY_EAX20BUFFER_FLAGS
:
802 GET_PROP(buf
->deferred
.eax
.dwFlags
, DWORD
);
806 hr
= E_PROP_ID_UNSUPPORTED
;
807 FIXME("Unhandled buffer propid: 0x%08lx\n", propid
);
816 HRESULT
EAX1_Set(DS8Primary
*prim
, DWORD propid
, void *pPropData
, ULONG cbPropData
)
818 static const float eax1_env_volume
[EAX_ENVIRONMENT_COUNT
] = {
819 0.5f
, 0.25f
, 0.417f
, 0.653f
, 0.208f
, 0.5f
, 0.403f
, 0.5f
, 0.5f
,
820 0.361f
, 0.5f
, 0.153f
, 0.361f
, 0.444f
, 0.25f
, 0.111f
, 0.111f
,
821 0.194f
, 1.0f
, 0.097f
, 0.208f
, 0.652f
, 1.0f
, 0.875f
, 0.139f
, 0.486f
823 static const float eax1_env_dampening
[EAX_ENVIRONMENT_COUNT
] = {
824 0.5f
, 0.0f
, 0.666f
, 0.166f
, 0.0f
, 0.888f
, 0.5f
, 0.5f
, 1.304f
,
825 0.332f
, 0.3f
, 2.0f
, 0.0f
, 0.638f
, 0.776f
, 0.472f
, 0.224f
, 0.472f
,
826 0.5f
, 0.224f
, 1.5f
, 0.25f
, 0.0f
, 1.388f
, 0.666f
, 0.806f
830 if(prim
->effect
== 0)
831 return E_PROP_ID_UNSUPPORTED
;
833 hr
= DSERR_INVALIDPARAM
;
836 case DSPROPERTY_EAX1_ALL
:
837 if(cbPropData
>= sizeof(EAX1_REVERBPROPERTIES
))
841 const EAX1_REVERBPROPERTIES
*props
;
842 } data
= { pPropData
};
844 if(data
.props
->dwEnvironment
< EAX_ENVIRONMENT_COUNT
)
846 /* NOTE: I'm not quite sure how to handle the volume. It's
847 * important to deal with since it can have a notable impact on
848 * the output levels, but given the default EAX1 environment
849 * volumes, they don't align with the gain/room volume for
850 * EAX2+ environments. Presuming the default volumes are
851 * correct, it's possible the reverb implementation was
852 * different and relied on different gains to get the intended
855 * Rather than just blindly applying the volume, we take the
856 * difference from the EAX1 environment's default volume and
857 * apply that as an offset to the EAX2 environment's volume.
859 EAX30LISTENERPROPERTIES env
= EnvironmentDefaults
[data
.props
->dwEnvironment
];
860 LONG db_vol
= clampI(
861 gain_to_mB(data
.props
->fVolume
/ eax1_env_volume
[data
.props
->dwEnvironment
]),
864 env
.lRoom
= clampI(env
.lRoom
+ db_vol
, -10000, 0);
865 env
.flDecayTime
= data
.props
->fDecayTime
;
866 prim
->deferred
.eax1_volume
= data
.props
->fVolume
;
867 prim
->deferred
.eax1_dampening
= data
.props
->fDamping
;
868 ApplyReverbParams(prim
, &env
);
874 case DSPROPERTY_EAX1_ENVIRONMENT
:
875 if(cbPropData
>= sizeof(DWORD
))
877 union { const void *v
; const DWORD
*dw
; } data
= { pPropData
};
879 if(*data
.dw
< EAX_ENVIRONMENT_COUNT
)
881 prim
->deferred
.eax1_volume
= eax1_env_volume
[*data
.dw
];
882 prim
->deferred
.eax1_dampening
= eax1_env_dampening
[*data
.dw
];
883 ApplyReverbParams(prim
, &EnvironmentDefaults
[*data
.dw
]);
889 case DSPROPERTY_EAX1_VOLUME
:
890 if(cbPropData
>= sizeof(FLOAT
))
892 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
893 LONG db_vol
= clampI(
894 gain_to_mB(*data
.fl
/ eax1_env_volume
[prim
->deferred
.eax
.dwEnvironment
]),
897 LONG room_vol
= clampI(
898 EnvironmentDefaults
[prim
->deferred
.eax
.dwEnvironment
].lRoom
+ db_vol
,
902 prim
->deferred
.eax
.lRoom
= room_vol
;
903 prim
->deferred
.eax1_volume
= *data
.fl
;
904 alEffectf(prim
->effect
, AL_EAXREVERB_GAIN
, mB_to_gain(room_vol
));
907 prim
->dirty
.bit
.effect
= 1;
911 case DSPROPERTY_EAX1_DECAYTIME
:
912 if(cbPropData
>= sizeof(FLOAT
))
914 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
916 prim
->deferred
.eax
.flDecayTime
= *data
.fl
;
917 alEffectf(prim
->effect
, AL_EAXREVERB_DECAY_TIME
,
918 prim
->deferred
.eax
.flDecayTime
);
921 prim
->dirty
.bit
.effect
= 1;
925 case DSPROPERTY_EAX1_DAMPING
:
926 if(cbPropData
>= sizeof(FLOAT
))
928 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
930 prim
->deferred
.eax1_dampening
= *data
.fl
;
937 hr
= E_PROP_ID_UNSUPPORTED
;
938 FIXME("Unhandled listener propid: 0x%08lx\n", propid
);
945 HRESULT
EAX1_Get(DS8Primary
*prim
, DWORD propid
, void *pPropData
, ULONG cbPropData
, ULONG
*pcbReturned
)
949 if(prim
->effect
== 0)
950 return E_PROP_ID_UNSUPPORTED
;
952 hr
= DSERR_INVALIDPARAM
;
955 case DSPROPERTY_EAX1_ALL
:
956 if(cbPropData
>= sizeof(EAX1_REVERBPROPERTIES
))
960 EAX1_REVERBPROPERTIES
*props
;
961 } data
= { pPropData
};
963 data
.props
->dwEnvironment
= prim
->deferred
.eax
.dwEnvironment
;
964 data
.props
->fVolume
= prim
->deferred
.eax1_volume
;
965 data
.props
->fDecayTime
= prim
->deferred
.eax
.flDecayTime
;
966 data
.props
->fDamping
= prim
->deferred
.eax1_dampening
;
968 *pcbReturned
= sizeof(EAX1_REVERBPROPERTIES
);
973 case DSPROPERTY_EAX1_ENVIRONMENT
:
974 if(cbPropData
>= sizeof(DWORD
))
976 union { void *v
; DWORD
*dw
; } data
= { pPropData
};
978 *data
.dw
= prim
->deferred
.eax
.dwEnvironment
;
980 *pcbReturned
= sizeof(DWORD
);
985 case DSPROPERTY_EAX1_VOLUME
:
986 if(cbPropData
>= sizeof(FLOAT
))
988 union { void *v
; FLOAT
*fl
; } data
= { pPropData
};
990 *data
.fl
= prim
->deferred
.eax1_volume
;
992 *pcbReturned
= sizeof(FLOAT
);
997 case DSPROPERTY_EAX1_DECAYTIME
:
998 if(cbPropData
>= sizeof(FLOAT
))
1000 union { void *v
; FLOAT
*fl
; } data
= { pPropData
};
1002 *data
.fl
= prim
->deferred
.eax
.flDecayTime
;
1004 *pcbReturned
= sizeof(FLOAT
);
1009 case DSPROPERTY_EAX1_DAMPING
:
1010 if(cbPropData
>= sizeof(FLOAT
))
1012 union { void *v
; FLOAT
*fl
; } data
= { pPropData
};
1014 *data
.fl
= prim
->deferred
.eax1_dampening
;
1016 *pcbReturned
= sizeof(FLOAT
);
1022 hr
= E_PROP_ID_UNSUPPORTED
;
1023 FIXME("Unhandled listener propid: 0x%08lx\n", propid
);
1030 HRESULT
EAX1Buffer_Set(DS8Buffer
*buf
, DWORD propid
, void *pPropData
, ULONG cbPropData
)
1034 if(buf
->filter
[0] == 0)
1035 return E_PROP_ID_UNSUPPORTED
;
1037 hr
= DSERR_INVALIDPARAM
;
1040 /* NOTE: DSPROPERTY_EAX1BUFFER_ALL is for EAX1BUFFER_REVERBPROPERTIES,
1041 * however that struct just contains the single ReverbMix float property.
1043 case DSPROPERTY_EAX1BUFFER_ALL
:
1044 case DSPROPERTY_EAX1BUFFER_REVERBMIX
:
1045 if(cbPropData
>= sizeof(FLOAT
))
1047 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
1049 buf
->deferred
.eax
.lRoom
= gain_to_mB(*data
.fl
);
1050 buf
->deferred
.eax1_reverbmix
= *data
.fl
;
1051 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_WET_PARAMS
);
1053 buf
->dirty
.bit
.wet_filter
= 1;
1059 hr
= E_PROP_ID_UNSUPPORTED
;
1060 FIXME("Unhandled buffer propid: 0x%08lx\n", propid
);
1067 HRESULT
EAX1Buffer_Get(DS8Buffer
*buf
, DWORD propid
, void *pPropData
, ULONG cbPropData
, ULONG
*pcbReturned
)
1071 if(buf
->filter
[0] == 0)
1072 return E_PROP_ID_UNSUPPORTED
;
1074 hr
= DSERR_INVALIDPARAM
;
1077 case DSPROPERTY_EAX1BUFFER_ALL
:
1078 case DSPROPERTY_EAX1BUFFER_REVERBMIX
:
1079 if(cbPropData
>= sizeof(FLOAT
))
1081 union { void *v
; FLOAT
*fl
; } data
= { pPropData
};
1083 *data
.fl
= buf
->deferred
.eax1_reverbmix
;
1084 *pcbReturned
= sizeof(FLOAT
);
1090 hr
= E_PROP_ID_UNSUPPORTED
;
1091 FIXME("Unhandled buffer propid: 0x%08lx\n", propid
);