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_REVERB_DENSITY
,
60 clampF(powf(props
->flEnvironmentSize
, 3.0f
) / 16.0f
, 0.0f
, 1.0f
)
62 alEffectf(prim
->effect
, AL_REVERB_DIFFUSION
, props
->flEnvironmentDiffusion
);
64 alEffectf(prim
->effect
, AL_REVERB_GAIN
, mB_to_gain(props
->lRoom
));
65 alEffectf(prim
->effect
, AL_REVERB_GAINHF
, mB_to_gain(props
->lRoomHF
));
67 alEffectf(prim
->effect
, AL_REVERB_DECAY_TIME
, props
->flDecayTime
);
68 alEffectf(prim
->effect
, AL_REVERB_DECAY_HFRATIO
, props
->flDecayHFRatio
);
70 alEffectf(prim
->effect
, AL_REVERB_REFLECTIONS_GAIN
, mB_to_gain(props
->lReflections
));
71 alEffectf(prim
->effect
, AL_REVERB_REFLECTIONS_DELAY
, props
->flReflectionsDelay
);
73 alEffectf(prim
->effect
, AL_REVERB_LATE_REVERB_GAIN
, mB_to_gain(props
->lReverb
));
74 alEffectf(prim
->effect
, AL_REVERB_LATE_REVERB_DELAY
, props
->flReverbDelay
);
76 alEffectf(prim
->effect
, AL_REVERB_AIR_ABSORPTION_GAINHF
,
77 mB_to_gain(props
->flAirAbsorptionHF
));
79 alEffectf(prim
->effect
, AL_REVERB_ROOM_ROLLOFF_FACTOR
, props
->flRoomRolloffFactor
);
81 alEffecti(prim
->effect
, AL_REVERB_DECAY_HFLIMIT
,
82 (props
->dwFlags
&EAX30LISTENERFLAGS_DECAYHFLIMIT
) ?
87 prim
->dirty
.bit
.effect
= 1;
90 #define APPLY_DRY_PARAMS 1
91 #define APPLY_WET_PARAMS 2
92 static void ApplyFilterParams(DS8Buffer
*buf
, const EAX20BUFFERPROPERTIES
*props
, int apply
)
94 /* The LFRatio properties determine how much the given level applies to low
95 * frequencies as well as high frequencies. Given that the high frequency
96 * levels are specified relative to the low, they should increase as the
97 * low frequency levels reduce.
99 FLOAT occl
= props
->lOcclusion
* props
->flOcclusionLFRatio
;
100 FLOAT occlhf
= props
->lOcclusion
* (1.0f
-props
->flOcclusionLFRatio
);
102 if((apply
&APPLY_DRY_PARAMS
))
104 FLOAT obstr
= props
->lObstruction
* props
->flObstructionLFRatio
;
105 FLOAT obstrhf
= props
->lObstruction
* (1.0f
-props
->flObstructionLFRatio
);
106 FLOAT mb
= props
->lDirect
+ obstr
+ occl
;
107 FLOAT mbhf
= props
->lDirectHF
+ obstrhf
+ occlhf
;
109 alFilterf(buf
->filter
[0], AL_LOWPASS_GAIN
, mB_to_gain(mb
));
110 alFilterf(buf
->filter
[0], AL_LOWPASS_GAINHF
, mB_to_gain(mbhf
));
112 if((apply
&APPLY_WET_PARAMS
))
114 FLOAT occlroom
= props
->flOcclusionRoomRatio
;
115 FLOAT mb
= props
->lRoom
+ occlroom
*occl
;
116 FLOAT mbhf
= props
->lRoomHF
+ occlroom
*occlhf
;
118 alFilterf(buf
->filter
[1], AL_LOWPASS_GAIN
, mB_to_gain(mb
));
119 alFilterf(buf
->filter
[1], AL_LOWPASS_GAINHF
, mB_to_gain(mbhf
));
125 HRESULT
EAX2_Set(DS8Primary
*prim
, DWORD propid
, void *pPropData
, ULONG cbPropData
)
129 if(prim
->effect
== 0)
130 return E_PROP_ID_UNSUPPORTED
;
132 hr
= DSERR_INVALIDPARAM
;
135 case DSPROPERTY_EAX20LISTENER_NONE
: /* not setting any property, just applying */
139 case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS
:
140 if(cbPropData
>= sizeof(EAX20LISTENERPROPERTIES
))
144 const EAX20LISTENERPROPERTIES
*props
;
145 } data
= { pPropData
};
146 EAX30LISTENERPROPERTIES props3
= REVERB_PRESET_GENERIC
;
147 if(data
.props
->dwEnvironment
< EAX_ENVIRONMENT_COUNT
)
149 props3
= EnvironmentDefaults
[data
.props
->dwEnvironment
];
150 props3
.dwEnvironment
= data
.props
->dwEnvironment
;
152 props3
.flEnvironmentSize
= data
.props
->flEnvironmentSize
;
153 props3
.flEnvironmentDiffusion
= data
.props
->flEnvironmentDiffusion
;
154 props3
.lRoom
= data
.props
->lRoom
;
155 props3
.lRoomHF
= data
.props
->lRoomHF
;
156 props3
.flDecayTime
= data
.props
->flDecayTime
;
157 props3
.flDecayHFRatio
= data
.props
->flDecayHFRatio
;
158 props3
.lReflections
= data
.props
->lReflections
;
159 props3
.flReflectionsDelay
= data
.props
->flReflectionsDelay
;
160 props3
.lReverb
= data
.props
->lReverb
;
161 props3
.flReverbDelay
= data
.props
->flReverbDelay
;
162 props3
.flAirAbsorptionHF
= data
.props
->flAirAbsorptionHF
;
163 props3
.flRoomRolloffFactor
= data
.props
->flRoomRolloffFactor
;
164 props3
.dwFlags
= data
.props
->dwFlags
;
166 ApplyReverbParams(prim
, &props3
);
171 case DSPROPERTY_EAX20LISTENER_ROOM
:
172 if(cbPropData
>= sizeof(LONG
))
174 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
176 prim
->deferred
.eax
.lRoom
= *data
.l
;
177 alEffectf(prim
->effect
, AL_REVERB_GAIN
,
178 mB_to_gain(prim
->deferred
.eax
.lRoom
));
181 prim
->dirty
.bit
.effect
= 1;
185 case DSPROPERTY_EAX20LISTENER_ROOMHF
:
186 if(cbPropData
>= sizeof(LONG
))
188 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
190 prim
->deferred
.eax
.lRoomHF
= *data
.l
;
191 alEffectf(prim
->effect
, AL_REVERB_GAINHF
,
192 mB_to_gain(prim
->deferred
.eax
.lRoomHF
));
195 prim
->dirty
.bit
.effect
= 1;
200 case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR
:
201 if(cbPropData
>= sizeof(FLOAT
))
203 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
205 prim
->deferred
.eax
.flRoomRolloffFactor
= *data
.fl
;
206 alEffectf(prim
->effect
, AL_REVERB_ROOM_ROLLOFF_FACTOR
,
207 prim
->deferred
.eax
.flRoomRolloffFactor
);
210 prim
->dirty
.bit
.effect
= 1;
215 case DSPROPERTY_EAX20LISTENER_DECAYTIME
:
216 if(cbPropData
>= sizeof(FLOAT
))
218 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
220 prim
->deferred
.eax
.flDecayTime
= *data
.fl
;
221 alEffectf(prim
->effect
, AL_REVERB_DECAY_TIME
,
222 prim
->deferred
.eax
.flDecayTime
);
225 prim
->dirty
.bit
.effect
= 1;
229 case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO
:
230 if(cbPropData
>= sizeof(FLOAT
))
232 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
234 prim
->deferred
.eax
.flDecayHFRatio
= *data
.fl
;
235 alEffectf(prim
->effect
, AL_REVERB_DECAY_HFRATIO
,
236 prim
->deferred
.eax
.flDecayHFRatio
);
239 prim
->dirty
.bit
.effect
= 1;
244 case DSPROPERTY_EAX20LISTENER_REFLECTIONS
:
245 if(cbPropData
>= sizeof(LONG
))
247 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
249 prim
->deferred
.eax
.lReflections
= *data
.l
;
250 alEffectf(prim
->effect
, AL_REVERB_REFLECTIONS_GAIN
,
251 mB_to_gain(prim
->deferred
.eax
.lReflections
));
254 prim
->dirty
.bit
.effect
= 1;
258 case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY
:
259 if(cbPropData
>= sizeof(FLOAT
))
261 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
263 prim
->deferred
.eax
.flReflectionsDelay
= *data
.fl
;
264 alEffectf(prim
->effect
, AL_REVERB_REFLECTIONS_DELAY
,
265 prim
->deferred
.eax
.flReflectionsDelay
);
268 prim
->dirty
.bit
.effect
= 1;
273 case DSPROPERTY_EAX20LISTENER_REVERB
:
274 if(cbPropData
>= sizeof(LONG
))
276 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
278 prim
->deferred
.eax
.lReverb
= *data
.l
;
279 alEffectf(prim
->effect
, AL_REVERB_LATE_REVERB_GAIN
,
280 mB_to_gain(prim
->deferred
.eax
.lReverb
));
283 prim
->dirty
.bit
.effect
= 1;
287 case DSPROPERTY_EAX20LISTENER_REVERBDELAY
:
288 if(cbPropData
>= sizeof(FLOAT
))
290 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
292 prim
->deferred
.eax
.flReverbDelay
= *data
.fl
;
293 alEffectf(prim
->effect
, AL_REVERB_LATE_REVERB_DELAY
,
294 prim
->deferred
.eax
.flReverbDelay
);
297 prim
->dirty
.bit
.effect
= 1;
302 case DSPROPERTY_EAX20LISTENER_ENVIRONMENT
:
303 if(cbPropData
>= sizeof(DWORD
))
305 union { const void *v
; const DWORD
*dw
; } data
= { pPropData
};
306 if(*data
.dw
< EAX_ENVIRONMENT_COUNT
)
308 ApplyReverbParams(prim
, &EnvironmentDefaults
[*data
.dw
]);
314 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE
:
315 if(cbPropData
>= sizeof(FLOAT
))
317 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
318 if(*data
.fl
>= 1.0f
&& *data
.fl
<= 100.0f
)
320 float scale
= (*data
.fl
)/prim
->deferred
.eax
.flEnvironmentSize
;
322 prim
->deferred
.eax
.flEnvironmentSize
= *data
.fl
;
324 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_DECAYTIMESCALE
))
326 prim
->deferred
.eax
.flDecayTime
*= scale
;
327 prim
->deferred
.eax
.flDecayTime
= clampF(prim
->deferred
.eax
.flDecayTime
, 0.1f
, 20.0f
);
329 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_REFLECTIONSSCALE
))
331 prim
->deferred
.eax
.lReflections
-= gain_to_mB(scale
);
332 prim
->deferred
.eax
.lReflections
= clampI(prim
->deferred
.eax
.lReflections
, -10000, 1000);
334 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_REFLECTIONSDELAYSCALE
))
336 prim
->deferred
.eax
.flReflectionsDelay
*= scale
;
337 prim
->deferred
.eax
.flReflectionsDelay
= clampF(prim
->deferred
.eax
.flReflectionsDelay
, 0.0f
, 0.3f
);
339 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_REVERBSCALE
))
341 prim
->deferred
.eax
.lReverb
-= gain_to_mB(scale
);
342 prim
->deferred
.eax
.lReverb
= clampI(prim
->deferred
.eax
.lReverb
, -10000, 2000);
344 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_REVERBDELAYSCALE
))
346 prim
->deferred
.eax
.flReverbDelay
*= scale
;
347 prim
->deferred
.eax
.flReverbDelay
= clampF(prim
->deferred
.eax
.flReverbDelay
, 0.0f
, 0.1f
);
349 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_ECHOTIMESCALE
))
351 prim
->deferred
.eax
.flEchoTime
*= scale
;
352 prim
->deferred
.eax
.flEchoTime
= clampF(prim
->deferred
.eax
.flEchoTime
, 0.075f
, 0.25f
);
354 if((prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_MODTIMESCALE
))
356 prim
->deferred
.eax
.flModulationTime
*= scale
;
357 prim
->deferred
.eax
.flModulationTime
= clampF(prim
->deferred
.eax
.flModulationTime
, 0.04f
, 4.0f
);
360 ApplyReverbParams(prim
, &prim
->deferred
.eax
);
365 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION
:
366 if(cbPropData
>= sizeof(FLOAT
))
368 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
370 prim
->deferred
.eax
.flEnvironmentDiffusion
= *data
.fl
;
371 alEffectf(prim
->effect
, AL_REVERB_DIFFUSION
,
372 prim
->deferred
.eax
.flEnvironmentDiffusion
);
375 prim
->dirty
.bit
.effect
= 1;
380 case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF
:
381 if(cbPropData
>= sizeof(FLOAT
))
383 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
385 prim
->deferred
.eax
.flAirAbsorptionHF
= *data
.fl
;
386 alEffectf(prim
->effect
, AL_REVERB_AIR_ABSORPTION_GAINHF
,
387 mB_to_gain(prim
->deferred
.eax
.flAirAbsorptionHF
));
390 prim
->dirty
.bit
.effect
= 1;
395 case DSPROPERTY_EAX20LISTENER_FLAGS
:
396 if(cbPropData
>= sizeof(DWORD
))
398 union { const void *v
; const DWORD
*dw
; } data
= { pPropData
};
400 prim
->deferred
.eax
.dwFlags
= *data
.dw
;
401 alEffecti(prim
->effect
, AL_REVERB_DECAY_HFLIMIT
,
402 (prim
->deferred
.eax
.dwFlags
&EAX30LISTENERFLAGS_DECAYHFLIMIT
) ?
406 prim
->dirty
.bit
.effect
= 1;
412 hr
= E_PROP_ID_UNSUPPORTED
;
413 FIXME("Unhandled listener propid: 0x%08lx\n", propid
);
420 HRESULT
EAX2_Get(DS8Primary
*prim
, DWORD propid
, void *pPropData
, ULONG cbPropData
, ULONG
*pcbReturned
)
424 if(prim
->effect
== 0)
425 return E_PROP_ID_UNSUPPORTED
;
427 #define GET_PROP(src, T) do { \
428 if(cbPropData >= sizeof(T)) \
430 union { void *v; T *props; } data = { pPropData }; \
432 *pcbReturned = sizeof(T); \
436 hr
= DSERR_INVALIDPARAM
;
439 case DSPROPERTY_EAX20LISTENER_NONE
:
444 case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS
:
445 GET_PROP(EAX3To2(&prim
->deferred
.eax
), EAX20LISTENERPROPERTIES
);
448 case DSPROPERTY_EAX20LISTENER_ROOM
:
449 GET_PROP(prim
->deferred
.eax
.lRoom
, LONG
);
451 case DSPROPERTY_EAX20LISTENER_ROOMHF
:
452 GET_PROP(prim
->deferred
.eax
.lRoomHF
, LONG
);
455 case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR
:
456 GET_PROP(prim
->deferred
.eax
.flRoomRolloffFactor
, FLOAT
);
459 case DSPROPERTY_EAX20LISTENER_DECAYTIME
:
460 GET_PROP(prim
->deferred
.eax
.flDecayTime
, FLOAT
);
462 case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO
:
463 GET_PROP(prim
->deferred
.eax
.flDecayHFRatio
, FLOAT
);
466 case DSPROPERTY_EAX20LISTENER_REFLECTIONS
:
467 GET_PROP(prim
->deferred
.eax
.lReflections
, LONG
);
469 case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY
:
470 GET_PROP(prim
->deferred
.eax
.flReflectionsDelay
, FLOAT
);
473 case DSPROPERTY_EAX20LISTENER_REVERB
:
474 GET_PROP(prim
->deferred
.eax
.lReverb
, LONG
);
476 case DSPROPERTY_EAX20LISTENER_REVERBDELAY
:
477 GET_PROP(prim
->deferred
.eax
.flReverbDelay
, FLOAT
);
480 case DSPROPERTY_EAX20LISTENER_ENVIRONMENT
:
481 GET_PROP(prim
->deferred
.eax
.dwEnvironment
, DWORD
);
484 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE
:
485 GET_PROP(prim
->deferred
.eax
.flEnvironmentSize
, FLOAT
);
487 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION
:
488 GET_PROP(prim
->deferred
.eax
.flEnvironmentDiffusion
, FLOAT
);
491 case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF
:
492 GET_PROP(prim
->deferred
.eax
.flAirAbsorptionHF
, FLOAT
);
495 case DSPROPERTY_EAX20LISTENER_FLAGS
:
496 GET_PROP(prim
->deferred
.eax
.dwFlags
&EAX2LISTENERFLAGS_MASK
, DWORD
);
500 hr
= E_PROP_ID_UNSUPPORTED
;
501 FIXME("Unhandled listener propid: 0x%08lx\n", propid
);
510 HRESULT
EAX2Buffer_Set(DS8Buffer
*buf
, DWORD propid
, void *pPropData
, ULONG cbPropData
)
514 if(buf
->filter
[0] == 0)
515 return E_PROP_ID_UNSUPPORTED
;
517 hr
= DSERR_INVALIDPARAM
;
520 case DSPROPERTY_EAX20BUFFER_NONE
: /* not setting any property, just applying */
524 case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS
:
525 if(cbPropData
>= sizeof(EAX20BUFFERPROPERTIES
))
529 const EAX20BUFFERPROPERTIES
*props
;
530 } data
= { pPropData
};
532 buf
->deferred
.eax
= *data
.props
;
533 ApplyFilterParams(buf
, data
.props
, APPLY_DRY_PARAMS
|APPLY_WET_PARAMS
);
535 buf
->dirty
.bit
.dry_filter
= 1;
536 buf
->dirty
.bit
.wet_filter
= 1;
537 buf
->dirty
.bit
.room_rolloff
= 1;
538 buf
->dirty
.bit
.cone_outsidevolumehf
= 1;
539 buf
->dirty
.bit
.air_absorb
= 1;
540 buf
->dirty
.bit
.flags
= 1;
545 case DSPROPERTY_EAX20BUFFER_DIRECT
:
546 if(cbPropData
>= sizeof(LONG
))
548 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
550 buf
->deferred
.eax
.lDirect
= *data
.l
;
551 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
);
553 buf
->dirty
.bit
.dry_filter
= 1;
557 case DSPROPERTY_EAX20BUFFER_DIRECTHF
:
558 if(cbPropData
>= sizeof(LONG
))
560 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
562 buf
->deferred
.eax
.lDirectHF
= *data
.l
;
563 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
);
565 buf
->dirty
.bit
.dry_filter
= 1;
570 case DSPROPERTY_EAX20BUFFER_ROOM
:
571 if(cbPropData
>= sizeof(LONG
))
573 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
575 buf
->deferred
.eax
.lRoom
= *data
.l
;
576 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_WET_PARAMS
);
578 buf
->dirty
.bit
.wet_filter
= 1;
582 case DSPROPERTY_EAX20BUFFER_ROOMHF
:
583 if(cbPropData
>= sizeof(LONG
))
585 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
587 buf
->deferred
.eax
.lRoomHF
= *data
.l
;
588 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_WET_PARAMS
);
590 buf
->dirty
.bit
.wet_filter
= 1;
595 case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR
:
596 if(cbPropData
>= sizeof(FLOAT
))
598 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
600 buf
->deferred
.eax
.flRoomRolloffFactor
= *data
.fl
;
602 buf
->dirty
.bit
.room_rolloff
= 1;
607 case DSPROPERTY_EAX20BUFFER_OBSTRUCTION
:
608 if(cbPropData
>= sizeof(LONG
))
610 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
612 buf
->deferred
.eax
.lObstruction
= *data
.l
;
613 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
);
615 buf
->dirty
.bit
.dry_filter
= 1;
619 case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO
:
620 if(cbPropData
>= sizeof(FLOAT
))
622 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
624 buf
->deferred
.eax
.flObstructionLFRatio
= *data
.fl
;
625 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
);
627 buf
->dirty
.bit
.dry_filter
= 1;
632 case DSPROPERTY_EAX20BUFFER_OCCLUSION
:
633 if(cbPropData
>= sizeof(LONG
))
635 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
637 buf
->deferred
.eax
.lOcclusion
= *data
.l
;
638 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_DRY_PARAMS
|APPLY_WET_PARAMS
);
640 buf
->dirty
.bit
.dry_filter
= 1;
641 buf
->dirty
.bit
.wet_filter
= 1;
645 case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO
:
646 if(cbPropData
>= sizeof(FLOAT
))
648 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
650 buf
->deferred
.eax
.flOcclusionLFRatio
= *data
.fl
;
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_OCCLUSIONROOMRATIO
:
659 if(cbPropData
>= sizeof(FLOAT
))
661 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
663 buf
->deferred
.eax
.flOcclusionRoomRatio
= *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;
672 case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF
:
673 if(cbPropData
>= sizeof(LONG
))
675 union { const void *v
; const LONG
*l
; } data
= { pPropData
};
677 buf
->deferred
.eax
.lOutsideVolumeHF
= *data
.l
;
679 buf
->dirty
.bit
.cone_outsidevolumehf
= 1;
684 case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR
:
685 if(cbPropData
>= sizeof(FLOAT
))
687 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
689 buf
->deferred
.eax
.flAirAbsorptionFactor
= *data
.fl
;
691 buf
->dirty
.bit
.air_absorb
= 1;
696 case DSPROPERTY_EAX20BUFFER_FLAGS
:
697 if(cbPropData
>= sizeof(DWORD
))
699 union { const void *v
; const DWORD
*dw
; } data
= { pPropData
};
701 buf
->deferred
.eax
.dwFlags
= *data
.dw
;
703 buf
->dirty
.bit
.flags
= 1;
709 hr
= E_PROP_ID_UNSUPPORTED
;
710 FIXME("Unhandled buffer propid: 0x%08lx\n", propid
);
717 HRESULT
EAX2Buffer_Get(DS8Buffer
*buf
, DWORD propid
, void *pPropData
, ULONG cbPropData
, ULONG
*pcbReturned
)
721 if(buf
->filter
[0] == 0)
722 return E_PROP_ID_UNSUPPORTED
;
724 #define GET_PROP(src, T) do { \
725 if(cbPropData >= sizeof(T)) \
727 union { void *v; T *props; } data = { pPropData }; \
729 *pcbReturned = sizeof(T); \
733 hr
= DSERR_INVALIDPARAM
;
736 case DSPROPERTY_EAX20BUFFER_NONE
:
741 case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS
:
742 GET_PROP(buf
->deferred
.eax
, EAX20BUFFERPROPERTIES
);
745 case DSPROPERTY_EAX20BUFFER_DIRECT
:
746 GET_PROP(buf
->deferred
.eax
.lDirect
, LONG
);
748 case DSPROPERTY_EAX20BUFFER_DIRECTHF
:
749 GET_PROP(buf
->deferred
.eax
.lDirectHF
, LONG
);
752 case DSPROPERTY_EAX20BUFFER_ROOM
:
753 GET_PROP(buf
->deferred
.eax
.lRoom
, LONG
);
755 case DSPROPERTY_EAX20BUFFER_ROOMHF
:
756 GET_PROP(buf
->deferred
.eax
.lRoomHF
, LONG
);
759 case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR
:
760 GET_PROP(buf
->deferred
.eax
.flRoomRolloffFactor
, FLOAT
);
763 case DSPROPERTY_EAX20BUFFER_OBSTRUCTION
:
764 GET_PROP(buf
->deferred
.eax
.lObstruction
, LONG
);
766 case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO
:
767 GET_PROP(buf
->deferred
.eax
.flObstructionLFRatio
, FLOAT
);
770 case DSPROPERTY_EAX20BUFFER_OCCLUSION
:
771 GET_PROP(buf
->deferred
.eax
.lOcclusion
, LONG
);
773 case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO
:
774 GET_PROP(buf
->deferred
.eax
.flOcclusionLFRatio
, FLOAT
);
776 case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO
:
777 GET_PROP(buf
->deferred
.eax
.flOcclusionRoomRatio
, FLOAT
);
780 case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF
:
781 GET_PROP(buf
->deferred
.eax
.lOutsideVolumeHF
, LONG
);
784 case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR
:
785 GET_PROP(buf
->deferred
.eax
.flAirAbsorptionFactor
, FLOAT
);
788 case DSPROPERTY_EAX20BUFFER_FLAGS
:
789 GET_PROP(buf
->deferred
.eax
.dwFlags
, DWORD
);
793 hr
= E_PROP_ID_UNSUPPORTED
;
794 FIXME("Unhandled buffer propid: 0x%08lx\n", propid
);
803 HRESULT
EAX1_Set(DS8Primary
*prim
, DWORD propid
, void *pPropData
, ULONG cbPropData
)
805 static const float eax1_env_volume
[EAX_ENVIRONMENT_COUNT
] = {
806 0.5f
, 0.25f
, 0.417f
, 0.653f
, 0.208f
, 0.5f
, 0.403f
, 0.5f
, 0.5f
,
807 0.361f
, 0.5f
, 0.153f
, 0.361f
, 0.444f
, 0.25f
, 0.111f
, 0.111f
,
808 0.194f
, 1.0f
, 0.097f
, 0.208f
, 0.652f
, 1.0f
, 0.875f
, 0.139f
, 0.486f
810 static const float eax1_env_dampening
[EAX_ENVIRONMENT_COUNT
] = {
811 0.5f
, 0.0f
, 0.666f
, 0.166f
, 0.0f
, 0.888f
, 0.5f
, 0.5f
, 1.304f
,
812 0.332f
, 0.3f
, 2.0f
, 0.0f
, 0.638f
, 0.776f
, 0.472f
, 0.224f
, 0.472f
,
813 0.5f
, 0.224f
, 1.5f
, 0.25f
, 0.0f
, 1.388f
, 0.666f
, 0.806f
817 if(prim
->effect
== 0)
818 return E_PROP_ID_UNSUPPORTED
;
820 hr
= DSERR_INVALIDPARAM
;
823 case DSPROPERTY_EAX1_ALL
:
824 if(cbPropData
>= sizeof(EAX1_REVERBPROPERTIES
))
828 const EAX1_REVERBPROPERTIES
*props
;
829 } data
= { pPropData
};
831 if(data
.props
->dwEnvironment
< EAX_ENVIRONMENT_COUNT
)
833 /* NOTE: I'm not quite sure how to handle the volume. It's
834 * important to deal with since it can have a notable impact on
835 * the output levels, but given the default EAX1 environment
836 * volumes, they don't align with the gain/room volume for
837 * EAX2+ environments. Presuming the default volumes are
838 * correct, it's possible the reverb implementation was
839 * different and relied on different gains to get the intended
842 * Rather than just blindly applying the volume, we take the
843 * difference from the EAX1 environment's default volume and
844 * apply that as an offset to the EAX2 environment's volume.
846 EAX30LISTENERPROPERTIES env
= EnvironmentDefaults
[data
.props
->dwEnvironment
];
847 LONG db_vol
= clampI(
848 gain_to_mB(data
.props
->fVolume
/ eax1_env_volume
[data
.props
->dwEnvironment
]),
851 env
.lRoom
= clampI(env
.lRoom
+ db_vol
, -10000, 0);
852 env
.flDecayTime
= data
.props
->fDecayTime
;
853 prim
->deferred
.eax1_volume
= data
.props
->fVolume
;
854 prim
->deferred
.eax1_dampening
= data
.props
->fDamping
;
855 ApplyReverbParams(prim
, &env
);
861 case DSPROPERTY_EAX1_ENVIRONMENT
:
862 if(cbPropData
>= sizeof(DWORD
))
864 union { const void *v
; const DWORD
*dw
; } data
= { pPropData
};
866 if(*data
.dw
< EAX_ENVIRONMENT_COUNT
)
868 prim
->deferred
.eax1_volume
= eax1_env_volume
[*data
.dw
];
869 prim
->deferred
.eax1_dampening
= eax1_env_dampening
[*data
.dw
];
870 ApplyReverbParams(prim
, &EnvironmentDefaults
[*data
.dw
]);
876 case DSPROPERTY_EAX1_VOLUME
:
877 if(cbPropData
>= sizeof(FLOAT
))
879 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
880 LONG db_vol
= clampI(
881 gain_to_mB(*data
.fl
/ eax1_env_volume
[prim
->deferred
.eax
.dwEnvironment
]),
884 LONG room_vol
= clampI(
885 EnvironmentDefaults
[prim
->deferred
.eax
.dwEnvironment
].lRoom
+ db_vol
,
889 prim
->deferred
.eax
.lRoom
= room_vol
;
890 prim
->deferred
.eax1_volume
= *data
.fl
;
891 alEffectf(prim
->effect
, AL_REVERB_GAIN
, mB_to_gain(room_vol
));
894 prim
->dirty
.bit
.effect
= 1;
898 case DSPROPERTY_EAX1_DECAYTIME
:
899 if(cbPropData
>= sizeof(FLOAT
))
901 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
903 prim
->deferred
.eax
.flDecayTime
= *data
.fl
;
904 alEffectf(prim
->effect
, AL_REVERB_DECAY_TIME
,
905 prim
->deferred
.eax
.flDecayTime
);
908 prim
->dirty
.bit
.effect
= 1;
912 case DSPROPERTY_EAX1_DAMPING
:
913 if(cbPropData
>= sizeof(FLOAT
))
915 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
917 prim
->deferred
.eax1_dampening
= *data
.fl
;
924 hr
= E_PROP_ID_UNSUPPORTED
;
925 FIXME("Unhandled listener propid: 0x%08lx\n", propid
);
932 HRESULT
EAX1_Get(DS8Primary
*prim
, DWORD propid
, void *pPropData
, ULONG cbPropData
, ULONG
*pcbReturned
)
936 if(prim
->effect
== 0)
937 return E_PROP_ID_UNSUPPORTED
;
939 hr
= DSERR_INVALIDPARAM
;
942 case DSPROPERTY_EAX1_ALL
:
943 if(cbPropData
>= sizeof(EAX1_REVERBPROPERTIES
))
947 EAX1_REVERBPROPERTIES
*props
;
948 } data
= { pPropData
};
950 data
.props
->dwEnvironment
= prim
->deferred
.eax
.dwEnvironment
;
951 data
.props
->fVolume
= prim
->deferred
.eax1_volume
;
952 data
.props
->fDecayTime
= prim
->deferred
.eax
.flDecayTime
;
953 data
.props
->fDamping
= prim
->deferred
.eax1_dampening
;
955 *pcbReturned
= sizeof(EAX1_REVERBPROPERTIES
);
960 case DSPROPERTY_EAX1_ENVIRONMENT
:
961 if(cbPropData
>= sizeof(DWORD
))
963 union { void *v
; DWORD
*dw
; } data
= { pPropData
};
965 *data
.dw
= prim
->deferred
.eax
.dwEnvironment
;
967 *pcbReturned
= sizeof(DWORD
);
972 case DSPROPERTY_EAX1_VOLUME
:
973 if(cbPropData
>= sizeof(FLOAT
))
975 union { void *v
; FLOAT
*fl
; } data
= { pPropData
};
977 *data
.fl
= prim
->deferred
.eax1_volume
;
979 *pcbReturned
= sizeof(FLOAT
);
984 case DSPROPERTY_EAX1_DECAYTIME
:
985 if(cbPropData
>= sizeof(FLOAT
))
987 union { void *v
; FLOAT
*fl
; } data
= { pPropData
};
989 *data
.fl
= prim
->deferred
.eax
.flDecayTime
;
991 *pcbReturned
= sizeof(FLOAT
);
996 case DSPROPERTY_EAX1_DAMPING
:
997 if(cbPropData
>= sizeof(FLOAT
))
999 union { void *v
; FLOAT
*fl
; } data
= { pPropData
};
1001 *data
.fl
= prim
->deferred
.eax1_dampening
;
1003 *pcbReturned
= sizeof(FLOAT
);
1009 hr
= E_PROP_ID_UNSUPPORTED
;
1010 FIXME("Unhandled listener propid: 0x%08lx\n", propid
);
1017 HRESULT
EAX1Buffer_Set(DS8Buffer
*buf
, DWORD propid
, void *pPropData
, ULONG cbPropData
)
1021 if(buf
->filter
[0] == 0)
1022 return E_PROP_ID_UNSUPPORTED
;
1024 hr
= DSERR_INVALIDPARAM
;
1027 /* NOTE: DSPROPERTY_EAX1BUFFER_ALL is for EAX1BUFFER_REVERBPROPERTIES,
1028 * however that struct just contains the single ReverbMix float property.
1030 case DSPROPERTY_EAX1BUFFER_ALL
:
1031 case DSPROPERTY_EAX1BUFFER_REVERBMIX
:
1032 if(cbPropData
>= sizeof(FLOAT
))
1034 union { const void *v
; const FLOAT
*fl
; } data
= { pPropData
};
1036 buf
->deferred
.eax
.lRoom
= gain_to_mB(*data
.fl
);
1037 buf
->deferred
.eax1_reverbmix
= *data
.fl
;
1038 ApplyFilterParams(buf
, &buf
->deferred
.eax
, APPLY_WET_PARAMS
);
1040 buf
->dirty
.bit
.wet_filter
= 1;
1046 hr
= E_PROP_ID_UNSUPPORTED
;
1047 FIXME("Unhandled buffer propid: 0x%08lx\n", propid
);
1054 HRESULT
EAX1Buffer_Get(DS8Buffer
*buf
, DWORD propid
, void *pPropData
, ULONG cbPropData
, ULONG
*pcbReturned
)
1058 if(buf
->filter
[0] == 0)
1059 return E_PROP_ID_UNSUPPORTED
;
1061 hr
= DSERR_INVALIDPARAM
;
1064 case DSPROPERTY_EAX1BUFFER_ALL
:
1065 case DSPROPERTY_EAX1BUFFER_REVERBMIX
:
1066 if(cbPropData
>= sizeof(FLOAT
))
1068 union { void *v
; FLOAT
*fl
; } data
= { pPropData
};
1070 *data
.fl
= buf
->deferred
.eax1_reverbmix
;
1071 *pcbReturned
= sizeof(FLOAT
);
1077 hr
= E_PROP_ID_UNSUPPORTED
;
1078 FIXME("Unhandled buffer propid: 0x%08lx\n", propid
);