Clamp filter gains
[dsound-openal.git] / eax.c
blobd10883fe083487a89bab092d94cd5b5c1ba72fe0
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
18 #define CONST_VTABLE
19 #include <stdarg.h>
20 #include <string.h>
22 #include "windows.h"
23 #include "dsound.h"
25 #include "dsound_private.h"
28 static void ApplyReverbParams(DS8Primary *prim, const EAX30LISTENERPROPERTIES *props)
30 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
31 prim->deferred.eax = *props;
32 alEffectf(prim->effect, AL_EAXREVERB_DENSITY,
33 clampF(powf(props->flEnvironmentSize, 3.0f) / 16.0f, 0.0f, 1.0f)
35 alEffectf(prim->effect, AL_EAXREVERB_DIFFUSION, props->flEnvironmentDiffusion);
37 alEffectf(prim->effect, AL_EAXREVERB_GAIN, mB_to_gain(props->lRoom));
38 alEffectf(prim->effect, AL_EAXREVERB_GAINHF, mB_to_gain(props->lRoomHF));
39 alEffectf(prim->effect, AL_EAXREVERB_GAINLF, mB_to_gain(props->lRoomLF));
41 alEffectf(prim->effect, AL_EAXREVERB_DECAY_TIME, props->flDecayTime);
42 alEffectf(prim->effect, AL_EAXREVERB_DECAY_HFRATIO, props->flDecayHFRatio);
43 alEffectf(prim->effect, AL_EAXREVERB_DECAY_LFRATIO, props->flDecayLFRatio);
45 alEffectf(prim->effect, AL_EAXREVERB_REFLECTIONS_GAIN, mB_to_gain(props->lReflections));
46 alEffectf(prim->effect, AL_EAXREVERB_REFLECTIONS_DELAY, props->flReflectionsDelay);
47 alEffectfv(prim->effect, AL_EAXREVERB_REFLECTIONS_PAN, &props->vReflectionsPan.x);
49 alEffectf(prim->effect, AL_EAXREVERB_LATE_REVERB_GAIN, mB_to_gain(props->lReverb));
50 alEffectf(prim->effect, AL_EAXREVERB_LATE_REVERB_DELAY, props->flReverbDelay);
51 alEffectfv(prim->effect, AL_EAXREVERB_LATE_REVERB_PAN, &props->vReverbPan.x);
53 alEffectf(prim->effect, AL_EAXREVERB_ECHO_TIME, props->flEchoTime);
54 alEffectf(prim->effect, AL_EAXREVERB_ECHO_DEPTH, props->flEchoDepth);
56 alEffectf(prim->effect, AL_EAXREVERB_MODULATION_TIME, props->flModulationTime);
57 alEffectf(prim->effect, AL_EAXREVERB_MODULATION_DEPTH, props->flModulationDepth);
59 alEffectf(prim->effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF,
60 mB_to_gain(props->flAirAbsorptionHF));
62 alEffectf(prim->effect, AL_EAXREVERB_HFREFERENCE, props->flHFReference);
63 alEffectf(prim->effect, AL_EAXREVERB_LFREFERENCE, props->flLFReference);
65 alEffectf(prim->effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, props->flRoomRolloffFactor);
67 alEffecti(prim->effect, AL_EAXREVERB_DECAY_HFLIMIT,
68 (props->dwFlags&EAX30LISTENERFLAGS_DECAYHFLIMIT) ?
69 AL_TRUE : AL_FALSE);
71 checkALError();
73 prim->dirty.bit.effect = 1;
76 #define APPLY_DRY_PARAMS 1
77 #define APPLY_WET_PARAMS 2
78 static void ApplyFilterParams(DS8Buffer *buf, const EAX30BUFFERPROPERTIES *props, int apply)
80 /* The LFRatio properties determine how much the given level applies to low
81 * frequencies as well as high frequencies. Given that the high frequency
82 * levels are specified relative to the low, they should increase as the
83 * low frequency levels reduce.
85 FLOAT occl = props->lOcclusion * props->flOcclusionLFRatio;
86 FLOAT occlhf = props->lOcclusion * (1.0f-props->flOcclusionLFRatio);
88 if((apply&APPLY_DRY_PARAMS))
90 FLOAT obstr = props->lObstruction * props->flObstructionLFRatio;
91 FLOAT obstrhf = props->lObstruction * (1.0f-props->flObstructionLFRatio);
92 FLOAT occldirect = props->flOcclusionDirectRatio;
93 FLOAT mb = props->lDirect + obstr + occldirect*occl;
94 FLOAT mbhf = props->lDirectHF + obstrhf + occldirect*occlhf;
96 alFilterf(buf->filter[0], AL_LOWPASS_GAIN, clampF(mB_to_gain(mb), 0.0f, 1.0f));
97 alFilterf(buf->filter[0], AL_LOWPASS_GAINHF, clampF(mB_to_gain(mbhf), 0.0f, 1.0f));
99 if((apply&APPLY_WET_PARAMS))
101 FLOAT excl = props->lExclusion * props->flExclusionLFRatio;
102 FLOAT exclhf = props->lExclusion * (1.0f-props->flExclusionLFRatio);
103 FLOAT occlroom = props->flOcclusionRoomRatio;
104 FLOAT mb = props->lRoom + excl + occlroom*occl;
105 FLOAT mbhf = props->lRoomHF + exclhf + occlroom*occlhf;
107 alFilterf(buf->filter[1], AL_LOWPASS_GAIN, clampF(mB_to_gain(mb), 0.0f, 1.0f));
108 alFilterf(buf->filter[1], AL_LOWPASS_GAINHF, clampF(mB_to_gain(mbhf), 0.0f, 1.0f));
110 checkALError();
114 /*******************
115 * EAX 3 stuff
116 ******************/
118 HRESULT EAX3_Set(DS8Primary *prim, DWORD propid, void *pPropData, ULONG cbPropData)
120 HRESULT hr;
122 if(prim->effect == 0)
123 return E_PROP_ID_UNSUPPORTED;
125 hr = DSERR_INVALIDPARAM;
126 switch(propid)
128 case DSPROPERTY_EAX30LISTENER_NONE: /* not setting any property, just applying */
129 hr = DS_OK;
130 break;
132 case DSPROPERTY_EAX30LISTENER_ALLPARAMETERS:
133 if(cbPropData >= sizeof(EAX30LISTENERPROPERTIES))
135 union {
136 const void *v;
137 const EAX30LISTENERPROPERTIES *props;
138 } data = { pPropData };
140 /* FIXME: There's some unknown behavior here. When RightMark3DSound
141 * deals with environment panning and morphing, the current preset
142 * ID will sometimes be repeated, which seems to expect some
143 * parameters to stay unmodified. Other cases see preset ID 26,
144 * which is out of range. I'm not sure how these values are
145 * supposed to be treated.
147 ApplyReverbParams(prim, data.props);
148 hr = DS_OK;
150 break;
152 case DSPROPERTY_EAX30LISTENER_ENVIRONMENT:
153 if(cbPropData >= sizeof(DWORD))
155 union { const void *v; const DWORD *dw; } data = { pPropData };
156 if(*data.dw < EAX_ENVIRONMENT_COUNT)
158 ApplyReverbParams(prim, &EnvironmentDefaults[*data.dw]);
159 hr = DS_OK;
162 break;
164 case DSPROPERTY_EAX30LISTENER_ENVIRONMENTSIZE:
165 if(cbPropData >= sizeof(FLOAT))
167 union { const void *v; const FLOAT *fl; } data = { pPropData };
168 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
170 float scale = (*data.fl)/prim->deferred.eax.flEnvironmentSize;
172 prim->deferred.eax.flEnvironmentSize = *data.fl;
174 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_DECAYTIMESCALE))
176 prim->deferred.eax.flDecayTime *= scale;
177 prim->deferred.eax.flDecayTime = clampF(prim->deferred.eax.flDecayTime, 0.1f, 20.0f);
179 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_REFLECTIONSSCALE))
181 prim->deferred.eax.lReflections -= gain_to_mB(scale);
182 prim->deferred.eax.lReflections = clampI(prim->deferred.eax.lReflections, -10000, 1000);
184 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_REFLECTIONSDELAYSCALE))
186 prim->deferred.eax.flReflectionsDelay *= scale;
187 prim->deferred.eax.flReflectionsDelay = clampF(prim->deferred.eax.flReflectionsDelay, 0.0f, 0.3f);
189 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_REVERBSCALE))
191 prim->deferred.eax.lReverb -= gain_to_mB(scale);
192 prim->deferred.eax.lReverb = clampI(prim->deferred.eax.lReverb, -10000, 2000);
194 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_REVERBDELAYSCALE))
196 prim->deferred.eax.flReverbDelay *= scale;
197 prim->deferred.eax.flReverbDelay = clampF(prim->deferred.eax.flReverbDelay, 0.0f, 0.1f);
199 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_ECHOTIMESCALE))
201 prim->deferred.eax.flEchoTime *= scale;
202 prim->deferred.eax.flEchoTime = clampF(prim->deferred.eax.flEchoTime, 0.075f, 0.25f);
204 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_MODTIMESCALE))
206 prim->deferred.eax.flModulationTime *= scale;
207 prim->deferred.eax.flModulationTime = clampF(prim->deferred.eax.flModulationTime, 0.04f, 4.0f);
210 ApplyReverbParams(prim, &prim->deferred.eax);
211 hr = DS_OK;
214 break;
215 case DSPROPERTY_EAX30LISTENER_ENVIRONMENTDIFFUSION:
216 if(cbPropData >= sizeof(FLOAT))
218 union { const void *v; const FLOAT *fl; } data = { pPropData };
220 prim->deferred.eax.flEnvironmentDiffusion = *data.fl;
221 alEffectf(prim->effect, AL_EAXREVERB_DIFFUSION,
222 prim->deferred.eax.flEnvironmentDiffusion);
223 checkALError();
225 prim->dirty.bit.effect = 1;
226 hr = DS_OK;
228 break;
230 case DSPROPERTY_EAX30LISTENER_ROOM:
231 if(cbPropData >= sizeof(LONG))
233 union { const void *v; const LONG *l; } data = { pPropData };
235 prim->deferred.eax.lRoom = *data.l;
236 alEffectf(prim->effect, AL_EAXREVERB_GAIN,
237 mB_to_gain(prim->deferred.eax.lRoom));
238 checkALError();
240 prim->dirty.bit.effect = 1;
241 hr = DS_OK;
243 break;
244 case DSPROPERTY_EAX30LISTENER_ROOMHF:
245 if(cbPropData >= sizeof(LONG))
247 union { const void *v; const LONG *l; } data = { pPropData };
249 prim->deferred.eax.lRoomHF = *data.l;
250 alEffectf(prim->effect, AL_EAXREVERB_GAINHF,
251 mB_to_gain(prim->deferred.eax.lRoomHF));
252 checkALError();
254 prim->dirty.bit.effect = 1;
255 hr = DS_OK;
257 break;
258 case DSPROPERTY_EAX30LISTENER_ROOMLF:
259 if(cbPropData >= sizeof(LONG))
261 union { const void *v; const LONG *l; } data = { pPropData };
263 prim->deferred.eax.lRoomLF = *data.l;
264 alEffectf(prim->effect, AL_EAXREVERB_GAINLF,
265 mB_to_gain(prim->deferred.eax.lRoomLF));
266 checkALError();
268 prim->dirty.bit.effect = 1;
269 hr = DS_OK;
271 break;
273 case DSPROPERTY_EAX30LISTENER_DECAYTIME:
274 if(cbPropData >= sizeof(FLOAT))
276 union { const void *v; const FLOAT *fl; } data = { pPropData };
278 prim->deferred.eax.flDecayTime = *data.fl;
279 alEffectf(prim->effect, AL_EAXREVERB_DECAY_TIME,
280 prim->deferred.eax.flDecayTime);
281 checkALError();
283 prim->dirty.bit.effect = 1;
284 hr = DS_OK;
286 break;
287 case DSPROPERTY_EAX30LISTENER_DECAYHFRATIO:
288 if(cbPropData >= sizeof(FLOAT))
290 union { const void *v; const FLOAT *fl; } data = { pPropData };
292 prim->deferred.eax.flDecayHFRatio = *data.fl;
293 alEffectf(prim->effect, AL_EAXREVERB_DECAY_HFRATIO,
294 prim->deferred.eax.flDecayHFRatio);
295 checkALError();
297 prim->dirty.bit.effect = 1;
298 hr = DS_OK;
300 break;
301 case DSPROPERTY_EAX30LISTENER_DECAYLFRATIO:
302 if(cbPropData >= sizeof(FLOAT))
304 union { const void *v; const FLOAT *fl; } data = { pPropData };
306 prim->deferred.eax.flDecayLFRatio = *data.fl;
307 alEffectf(prim->effect, AL_EAXREVERB_DECAY_LFRATIO,
308 prim->deferred.eax.flDecayLFRatio);
309 checkALError();
311 prim->dirty.bit.effect = 1;
312 hr = DS_OK;
314 break;
316 case DSPROPERTY_EAX30LISTENER_REFLECTIONS:
317 if(cbPropData >= sizeof(LONG))
319 union { const void *v; const LONG *l; } data = { pPropData };
321 prim->deferred.eax.lReflections = *data.l;
322 alEffectf(prim->effect, AL_EAXREVERB_REFLECTIONS_GAIN,
323 mB_to_gain(prim->deferred.eax.lReflections));
324 checkALError();
326 prim->dirty.bit.effect = 1;
327 hr = DS_OK;
329 break;
330 case DSPROPERTY_EAX30LISTENER_REFLECTIONSDELAY:
331 if(cbPropData >= sizeof(FLOAT))
333 union { const void *v; const FLOAT *fl; } data = { pPropData };
335 prim->deferred.eax.flReflectionsDelay = *data.fl;
336 alEffectf(prim->effect, AL_EAXREVERB_REFLECTIONS_DELAY,
337 prim->deferred.eax.flReflectionsDelay);
338 checkALError();
340 prim->dirty.bit.effect = 1;
341 hr = DS_OK;
343 break;
344 case DSPROPERTY_EAX30LISTENER_REFLECTIONSPAN:
345 if(cbPropData >= sizeof(EAXVECTOR))
347 union { const void *v; const EAXVECTOR *vec; } data = { pPropData };
349 prim->deferred.eax.vReflectionsPan = *data.vec;
350 alEffectfv(prim->effect, AL_EAXREVERB_REFLECTIONS_PAN,
351 &prim->deferred.eax.vReflectionsPan.x);
352 checkALError();
354 prim->dirty.bit.effect = 1;
355 hr = DS_OK;
357 break;
359 case DSPROPERTY_EAX30LISTENER_REVERB:
360 if(cbPropData >= sizeof(LONG))
362 union { const void *v; const LONG *l; } data = { pPropData };
364 prim->deferred.eax.lReverb = *data.l;
365 alEffectf(prim->effect, AL_EAXREVERB_LATE_REVERB_GAIN,
366 mB_to_gain(prim->deferred.eax.lReverb));
367 checkALError();
369 prim->dirty.bit.effect = 1;
370 hr = DS_OK;
372 break;
373 case DSPROPERTY_EAX30LISTENER_REVERBDELAY:
374 if(cbPropData >= sizeof(FLOAT))
376 union { const void *v; const FLOAT *fl; } data = { pPropData };
378 prim->deferred.eax.flReverbDelay = *data.fl;
379 alEffectf(prim->effect, AL_EAXREVERB_LATE_REVERB_DELAY,
380 prim->deferred.eax.flReverbDelay);
381 checkALError();
383 prim->dirty.bit.effect = 1;
384 hr = DS_OK;
386 break;
387 case DSPROPERTY_EAX30LISTENER_REVERBPAN:
388 if(cbPropData >= sizeof(EAXVECTOR))
390 union { const void *v; const EAXVECTOR *vec; } data = { pPropData };
392 prim->deferred.eax.vReverbPan = *data.vec;
393 alEffectfv(prim->effect, AL_EAXREVERB_LATE_REVERB_PAN,
394 &prim->deferred.eax.vReverbPan.x);
395 checkALError();
397 prim->dirty.bit.effect = 1;
398 hr = DS_OK;
400 break;
402 case DSPROPERTY_EAX30LISTENER_ECHOTIME:
403 if(cbPropData >= sizeof(FLOAT))
405 union { const void *v; const FLOAT *fl; } data = { pPropData };
407 prim->deferred.eax.flEchoTime = *data.fl;
408 alEffectf(prim->effect, AL_EAXREVERB_ECHO_TIME,
409 prim->deferred.eax.flEchoTime);
410 checkALError();
412 prim->dirty.bit.effect = 1;
413 hr = DS_OK;
415 break;
416 case DSPROPERTY_EAX30LISTENER_ECHODEPTH:
417 if(cbPropData >= sizeof(FLOAT))
419 union { const void *v; const FLOAT *fl; } data = { pPropData };
421 prim->deferred.eax.flEchoDepth = *data.fl;
422 alEffectf(prim->effect, AL_EAXREVERB_ECHO_DEPTH,
423 prim->deferred.eax.flEchoDepth);
424 checkALError();
426 prim->dirty.bit.effect = 1;
427 hr = DS_OK;
429 break;
431 case DSPROPERTY_EAX30LISTENER_MODULATIONTIME:
432 if(cbPropData >= sizeof(FLOAT))
434 union { const void *v; const FLOAT *fl; } data = { pPropData };
436 prim->deferred.eax.flModulationTime = *data.fl;
437 alEffectf(prim->effect, AL_EAXREVERB_MODULATION_TIME,
438 prim->deferred.eax.flModulationTime);
439 checkALError();
441 prim->dirty.bit.effect = 1;
442 hr = DS_OK;
444 break;
445 case DSPROPERTY_EAX30LISTENER_MODULATIONDEPTH:
446 if(cbPropData >= sizeof(FLOAT))
448 union { const void *v; const FLOAT *fl; } data = { pPropData };
450 prim->deferred.eax.flModulationDepth = *data.fl;
451 alEffectf(prim->effect, AL_EAXREVERB_MODULATION_DEPTH,
452 prim->deferred.eax.flModulationDepth);
453 checkALError();
455 prim->dirty.bit.effect = 1;
456 hr = DS_OK;
458 break;
460 case DSPROPERTY_EAX30LISTENER_AIRABSORPTIONHF:
461 if(cbPropData >= sizeof(FLOAT))
463 union { const void *v; const FLOAT *fl; } data = { pPropData };
465 prim->deferred.eax.flAirAbsorptionHF = *data.fl;
466 alEffectf(prim->effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF,
467 mB_to_gain(prim->deferred.eax.flAirAbsorptionHF));
468 checkALError();
470 prim->dirty.bit.effect = 1;
471 hr = DS_OK;
473 break;
475 case DSPROPERTY_EAX30LISTENER_HFREFERENCE:
476 if(cbPropData >= sizeof(FLOAT))
478 union { const void *v; const FLOAT *fl; } data = { pPropData };
480 prim->deferred.eax.flHFReference = *data.fl;
481 alEffectf(prim->effect, AL_EAXREVERB_HFREFERENCE,
482 prim->deferred.eax.flHFReference);
483 checkALError();
485 prim->dirty.bit.effect = 1;
486 hr = DS_OK;
488 break;
489 case DSPROPERTY_EAX30LISTENER_LFREFERENCE:
490 if(cbPropData >= sizeof(FLOAT))
492 union { const void *v; const FLOAT *fl; } data = { pPropData };
494 prim->deferred.eax.flLFReference = *data.fl;
495 alEffectf(prim->effect, AL_EAXREVERB_LFREFERENCE,
496 prim->deferred.eax.flLFReference);
497 checkALError();
499 prim->dirty.bit.effect = 1;
500 hr = DS_OK;
502 break;
504 case DSPROPERTY_EAX30LISTENER_ROOMROLLOFFFACTOR:
505 if(cbPropData >= sizeof(FLOAT))
507 union { const void *v; const FLOAT *fl; } data = { pPropData };
509 prim->deferred.eax.flRoomRolloffFactor = *data.fl;
510 alEffectf(prim->effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR,
511 prim->deferred.eax.flRoomRolloffFactor);
512 checkALError();
514 prim->dirty.bit.effect = 1;
515 hr = DS_OK;
517 break;
519 case DSPROPERTY_EAX30LISTENER_FLAGS:
520 if(cbPropData >= sizeof(DWORD))
522 union { const void *v; const DWORD *dw; } data = { pPropData };
524 prim->deferred.eax.dwFlags = *data.dw;
525 alEffecti(prim->effect, AL_EAXREVERB_DECAY_HFLIMIT,
526 (prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_DECAYHFLIMIT) ?
527 AL_TRUE : AL_FALSE);
528 checkALError();
530 prim->dirty.bit.effect = 1;
531 hr = DS_OK;
533 break;
535 default:
536 hr = E_PROP_ID_UNSUPPORTED;
537 FIXME("Unhandled listener propid: 0x%08lx\n", propid);
538 break;
541 return hr;
544 HRESULT EAX3_Get(DS8Primary *prim, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
546 HRESULT hr;
548 if(prim->effect == 0)
549 return E_PROP_ID_UNSUPPORTED;
551 #define GET_PROP(src, T) do { \
552 if(cbPropData >= sizeof(T)) \
554 union { void *v; T *props; } data = { pPropData }; \
555 *data.props = src; \
556 *pcbReturned = sizeof(T); \
557 hr = DS_OK; \
559 } while(0)
560 hr = DSERR_INVALIDPARAM;
561 switch(propid)
563 case DSPROPERTY_EAX30LISTENER_NONE:
564 *pcbReturned = 0;
565 hr = DS_OK;
566 break;
568 case DSPROPERTY_EAX30LISTENER_ALLPARAMETERS:
569 GET_PROP(prim->deferred.eax, EAX30LISTENERPROPERTIES);
570 break;
572 case DSPROPERTY_EAX30LISTENER_ENVIRONMENT:
573 GET_PROP(prim->deferred.eax.dwEnvironment, DWORD);
574 break;
576 case DSPROPERTY_EAX30LISTENER_ENVIRONMENTSIZE:
577 GET_PROP(prim->deferred.eax.flEnvironmentSize, FLOAT);
578 break;
579 case DSPROPERTY_EAX30LISTENER_ENVIRONMENTDIFFUSION:
580 GET_PROP(prim->deferred.eax.flEnvironmentDiffusion, FLOAT);
581 break;
583 case DSPROPERTY_EAX30LISTENER_ROOM:
584 GET_PROP(prim->deferred.eax.lRoom, LONG);
585 break;
586 case DSPROPERTY_EAX30LISTENER_ROOMHF:
587 GET_PROP(prim->deferred.eax.lRoomHF, LONG);
588 break;
589 case DSPROPERTY_EAX30LISTENER_ROOMLF:
590 GET_PROP(prim->deferred.eax.lRoomLF, LONG);
591 break;
593 case DSPROPERTY_EAX30LISTENER_DECAYTIME:
594 GET_PROP(prim->deferred.eax.flDecayTime, FLOAT);
595 break;
596 case DSPROPERTY_EAX30LISTENER_DECAYHFRATIO:
597 GET_PROP(prim->deferred.eax.flDecayHFRatio, FLOAT);
598 break;
599 case DSPROPERTY_EAX30LISTENER_DECAYLFRATIO:
600 GET_PROP(prim->deferred.eax.flDecayLFRatio, FLOAT);
601 break;
603 case DSPROPERTY_EAX30LISTENER_REFLECTIONS:
604 GET_PROP(prim->deferred.eax.lReflections, LONG);
605 break;
606 case DSPROPERTY_EAX30LISTENER_REFLECTIONSDELAY:
607 GET_PROP(prim->deferred.eax.flReflectionsDelay, FLOAT);
608 break;
609 case DSPROPERTY_EAX30LISTENER_REFLECTIONSPAN:
610 GET_PROP(prim->deferred.eax.vReflectionsPan, EAXVECTOR);
611 break;
613 case DSPROPERTY_EAX30LISTENER_REVERB:
614 GET_PROP(prim->deferred.eax.lReverb, LONG);
615 break;
616 case DSPROPERTY_EAX30LISTENER_REVERBDELAY:
617 GET_PROP(prim->deferred.eax.flReverbDelay, FLOAT);
618 break;
619 case DSPROPERTY_EAX30LISTENER_REVERBPAN:
620 GET_PROP(prim->deferred.eax.vReverbPan, EAXVECTOR);
621 break;
623 case DSPROPERTY_EAX30LISTENER_ECHOTIME:
624 GET_PROP(prim->deferred.eax.flEchoTime, FLOAT);
625 break;
626 case DSPROPERTY_EAX30LISTENER_ECHODEPTH:
627 GET_PROP(prim->deferred.eax.flEchoDepth, FLOAT);
628 break;
630 case DSPROPERTY_EAX30LISTENER_MODULATIONTIME:
631 GET_PROP(prim->deferred.eax.flModulationTime, FLOAT);
632 break;
633 case DSPROPERTY_EAX30LISTENER_MODULATIONDEPTH:
634 GET_PROP(prim->deferred.eax.flModulationDepth, FLOAT);
635 break;
637 case DSPROPERTY_EAX30LISTENER_AIRABSORPTIONHF:
638 GET_PROP(prim->deferred.eax.flAirAbsorptionHF, FLOAT);
639 break;
641 case DSPROPERTY_EAX30LISTENER_HFREFERENCE:
642 GET_PROP(prim->deferred.eax.flHFReference, FLOAT);
643 break;
644 case DSPROPERTY_EAX30LISTENER_LFREFERENCE:
645 GET_PROP(prim->deferred.eax.flLFReference, FLOAT);
646 break;
648 case DSPROPERTY_EAX30LISTENER_ROOMROLLOFFFACTOR:
649 GET_PROP(prim->deferred.eax.flRoomRolloffFactor, FLOAT);
650 break;
652 case DSPROPERTY_EAX30LISTENER_FLAGS:
653 GET_PROP(prim->deferred.eax.dwFlags, DWORD);
654 break;
656 default:
657 hr = E_PROP_ID_UNSUPPORTED;
658 FIXME("Unhandled listener propid: 0x%08lx\n", propid);
659 break;
661 #undef GET_PROP
663 return hr;
666 HRESULT EAX3Buffer_Set(DS8Buffer *buf, DWORD propid, void *pPropData, ULONG cbPropData)
668 HRESULT hr;
670 if(buf->filter[0] == 0)
671 return E_PROP_ID_UNSUPPORTED;
673 hr = DSERR_INVALIDPARAM;
674 switch(propid)
676 case DSPROPERTY_EAX30BUFFER_NONE: /* not setting any property, just applying */
677 hr = DS_OK;
678 break;
680 case DSPROPERTY_EAX30BUFFER_ALLPARAMETERS:
681 if(cbPropData >= sizeof(EAX30BUFFERPROPERTIES))
683 union {
684 const void *v;
685 const EAX30BUFFERPROPERTIES *props;
686 } data = { pPropData };
688 buf->deferred.eax = *data.props;
689 ApplyFilterParams(buf, data.props, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
691 buf->dirty.bit.dry_filter = 1;
692 buf->dirty.bit.wet_filter = 1;
693 buf->dirty.bit.room_rolloff = 1;
694 buf->dirty.bit.cone_outsidevolumehf = 1;
695 buf->dirty.bit.air_absorb = 1;
696 buf->dirty.bit.flags = 1;
697 hr = DS_OK;
699 break;
701 case DSPROPERTY_EAX30BUFFER_DIRECT:
702 if(cbPropData >= sizeof(LONG))
704 union { const void *v; const LONG *l; } data = { pPropData };
706 buf->deferred.eax.lDirect = *data.l;
707 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
709 buf->dirty.bit.dry_filter = 1;
710 hr = DS_OK;
712 break;
713 case DSPROPERTY_EAX30BUFFER_DIRECTHF:
714 if(cbPropData >= sizeof(LONG))
716 union { const void *v; const LONG *l; } data = { pPropData };
718 buf->deferred.eax.lDirectHF = *data.l;
719 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
721 buf->dirty.bit.dry_filter = 1;
722 hr = DS_OK;
724 break;
725 case DSPROPERTY_EAX30BUFFER_DIRECTLF:
726 if(cbPropData >= sizeof(LONG))
728 union { const void *v; const LONG *l; } data = { pPropData };
730 buf->deferred.eax.lDirectLF = *data.l;
731 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
733 buf->dirty.bit.dry_filter = 1;
734 hr = DS_OK;
736 break;
738 case DSPROPERTY_EAX30BUFFER_ROOM:
739 if(cbPropData >= sizeof(LONG))
741 union { const void *v; const LONG *l; } data = { pPropData };
743 buf->deferred.eax.lRoom = *data.l;
744 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
746 buf->dirty.bit.wet_filter = 1;
747 hr = DS_OK;
749 break;
750 case DSPROPERTY_EAX30BUFFER_ROOMHF:
751 if(cbPropData >= sizeof(LONG))
753 union { const void *v; const LONG *l; } data = { pPropData };
755 buf->deferred.eax.lRoomHF = *data.l;
756 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
758 buf->dirty.bit.wet_filter = 1;
759 hr = DS_OK;
761 break;
762 case DSPROPERTY_EAX30BUFFER_ROOMLF:
763 if(cbPropData >= sizeof(LONG))
765 union { const void *v; const LONG *l; } data = { pPropData };
767 buf->deferred.eax.lRoomLF = *data.l;
768 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
770 buf->dirty.bit.wet_filter = 1;
771 hr = DS_OK;
773 break;
775 case DSPROPERTY_EAX30BUFFER_ROOMROLLOFFFACTOR:
776 if(cbPropData >= sizeof(FLOAT))
778 union { const void *v; const FLOAT *fl; } data = { pPropData };
780 buf->deferred.eax.flRoomRolloffFactor = *data.fl;
782 buf->dirty.bit.room_rolloff = 1;
783 hr = DS_OK;
785 break;
787 case DSPROPERTY_EAX30BUFFER_OBSTRUCTION:
788 if(cbPropData >= sizeof(LONG))
790 union { const void *v; const LONG *l; } data = { pPropData };
792 buf->deferred.eax.lObstruction = *data.l;
793 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
795 buf->dirty.bit.dry_filter = 1;
796 hr = DS_OK;
798 break;
799 case DSPROPERTY_EAX30BUFFER_OBSTRUCTIONLFRATIO:
800 if(cbPropData >= sizeof(FLOAT))
802 union { const void *v; const FLOAT *fl; } data = { pPropData };
804 buf->deferred.eax.flObstructionLFRatio = *data.fl;
805 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
807 buf->dirty.bit.dry_filter = 1;
808 hr = DS_OK;
810 break;
812 case DSPROPERTY_EAX30BUFFER_OCCLUSION:
813 if(cbPropData >= sizeof(LONG))
815 union { const void *v; const LONG *l; } data = { pPropData };
817 buf->deferred.eax.lOcclusion = *data.l;
818 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
820 buf->dirty.bit.dry_filter = 1;
821 buf->dirty.bit.wet_filter = 1;
822 hr = DS_OK;
824 break;
825 case DSPROPERTY_EAX30BUFFER_OCCLUSIONLFRATIO:
826 if(cbPropData >= sizeof(FLOAT))
828 union { const void *v; const FLOAT *fl; } data = { pPropData };
830 buf->deferred.eax.flOcclusionLFRatio = *data.fl;
831 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
833 buf->dirty.bit.dry_filter = 1;
834 buf->dirty.bit.wet_filter = 1;
835 hr = DS_OK;
837 break;
838 case DSPROPERTY_EAX30BUFFER_OCCLUSIONROOMRATIO:
839 if(cbPropData >= sizeof(FLOAT))
841 union { const void *v; const FLOAT *fl; } data = { pPropData };
843 buf->deferred.eax.flOcclusionRoomRatio = *data.fl;
844 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
846 buf->dirty.bit.wet_filter = 1;
847 hr = DS_OK;
849 break;
850 case DSPROPERTY_EAX30BUFFER_OCCLUSIONDIRECTRATIO:
851 if(cbPropData >= sizeof(FLOAT))
853 union { const void *v; const FLOAT *fl; } data = { pPropData };
855 buf->deferred.eax.flOcclusionDirectRatio = *data.fl;
856 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
858 buf->dirty.bit.dry_filter = 1;
859 hr = DS_OK;
861 break;
863 case DSPROPERTY_EAX30BUFFER_EXCLUSION:
864 if(cbPropData >= sizeof(LONG))
866 union { const void *v; const LONG *l; } data = { pPropData };
868 buf->deferred.eax.lExclusion = *data.l;
869 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
871 buf->dirty.bit.wet_filter = 1;
872 hr = DS_OK;
874 break;
875 case DSPROPERTY_EAX30BUFFER_EXCLUSIONLFRATIO:
876 if(cbPropData >= sizeof(FLOAT))
878 union { const void *v; const FLOAT *fl; } data = { pPropData };
880 buf->deferred.eax.flExclusionLFRatio = *data.fl;
881 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
883 buf->dirty.bit.wet_filter = 1;
884 hr = DS_OK;
886 break;
888 case DSPROPERTY_EAX30BUFFER_OUTSIDEVOLUMEHF:
889 if(cbPropData >= sizeof(LONG))
891 union { const void *v; const LONG *l; } data = { pPropData };
893 buf->deferred.eax.lOutsideVolumeHF = *data.l;
895 buf->dirty.bit.cone_outsidevolumehf = 1;
896 hr = DS_OK;
898 break;
900 case DSPROPERTY_EAX30BUFFER_AIRABSORPTIONFACTOR:
901 if(cbPropData >= sizeof(FLOAT))
903 union { const void *v; const FLOAT *fl; } data = { pPropData };
905 buf->deferred.eax.flAirAbsorptionFactor = *data.fl;
907 buf->dirty.bit.air_absorb = 1;
908 hr = DS_OK;
910 break;
912 case DSPROPERTY_EAX30BUFFER_FLAGS:
913 if(cbPropData >= sizeof(DWORD))
915 union { const void *v; const DWORD *dw; } data = { pPropData };
917 buf->deferred.eax.dwFlags = *data.dw;
919 buf->dirty.bit.flags = 1;
920 hr = DS_OK;
922 break;
924 default:
925 hr = E_PROP_ID_UNSUPPORTED;
926 FIXME("Unhandled buffer propid: 0x%08lx\n", propid);
927 break;
930 return hr;
933 HRESULT EAX3Buffer_Get(DS8Buffer *buf, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
935 HRESULT hr;
937 if(buf->filter[0] == 0)
938 return E_PROP_ID_UNSUPPORTED;
940 #define GET_PROP(src, T) do { \
941 if(cbPropData >= sizeof(T)) \
943 union { void *v; T *props; } data = { pPropData }; \
944 *data.props = src; \
945 *pcbReturned = sizeof(T); \
946 hr = DS_OK; \
948 } while(0)
949 hr = DSERR_INVALIDPARAM;
950 switch(propid)
952 case DSPROPERTY_EAX30BUFFER_NONE:
953 *pcbReturned = 0;
954 hr = DS_OK;
955 break;
957 case DSPROPERTY_EAX30BUFFER_ALLPARAMETERS:
958 GET_PROP(buf->deferred.eax, EAX30BUFFERPROPERTIES);
959 break;
961 case DSPROPERTY_EAX30BUFFER_DIRECT:
962 GET_PROP(buf->deferred.eax.lDirect, LONG);
963 break;
964 case DSPROPERTY_EAX30BUFFER_DIRECTHF:
965 GET_PROP(buf->deferred.eax.lDirectHF, LONG);
966 break;
967 case DSPROPERTY_EAX30BUFFER_DIRECTLF:
968 GET_PROP(buf->deferred.eax.lDirectLF, LONG);
969 break;
971 case DSPROPERTY_EAX30BUFFER_ROOM:
972 GET_PROP(buf->deferred.eax.lRoom, LONG);
973 break;
974 case DSPROPERTY_EAX30BUFFER_ROOMHF:
975 GET_PROP(buf->deferred.eax.lRoomHF, LONG);
976 break;
977 case DSPROPERTY_EAX30BUFFER_ROOMLF:
978 GET_PROP(buf->deferred.eax.lRoomLF, LONG);
979 break;
981 case DSPROPERTY_EAX30BUFFER_ROOMROLLOFFFACTOR:
982 GET_PROP(buf->deferred.eax.flRoomRolloffFactor, FLOAT);
983 break;
985 case DSPROPERTY_EAX30BUFFER_OBSTRUCTION:
986 GET_PROP(buf->deferred.eax.lObstruction, LONG);
987 break;
988 case DSPROPERTY_EAX30BUFFER_OBSTRUCTIONLFRATIO:
989 GET_PROP(buf->deferred.eax.flObstructionLFRatio, FLOAT);
990 break;
992 case DSPROPERTY_EAX30BUFFER_OCCLUSION:
993 GET_PROP(buf->deferred.eax.lOcclusion, LONG);
994 break;
995 case DSPROPERTY_EAX30BUFFER_OCCLUSIONLFRATIO:
996 GET_PROP(buf->deferred.eax.flOcclusionLFRatio, FLOAT);
997 break;
998 case DSPROPERTY_EAX30BUFFER_OCCLUSIONROOMRATIO:
999 GET_PROP(buf->deferred.eax.flOcclusionRoomRatio, FLOAT);
1000 break;
1001 case DSPROPERTY_EAX30BUFFER_OCCLUSIONDIRECTRATIO:
1002 GET_PROP(buf->deferred.eax.flOcclusionDirectRatio, FLOAT);
1003 break;
1005 case DSPROPERTY_EAX30BUFFER_EXCLUSION:
1006 GET_PROP(buf->deferred.eax.lExclusion, LONG);
1007 break;
1008 case DSPROPERTY_EAX30BUFFER_EXCLUSIONLFRATIO:
1009 GET_PROP(buf->deferred.eax.flExclusionLFRatio, FLOAT);
1010 break;
1012 case DSPROPERTY_EAX30BUFFER_OUTSIDEVOLUMEHF:
1013 GET_PROP(buf->deferred.eax.lOutsideVolumeHF, LONG);
1014 break;
1016 case DSPROPERTY_EAX30BUFFER_AIRABSORPTIONFACTOR:
1017 GET_PROP(buf->deferred.eax.flAirAbsorptionFactor, FLOAT);
1018 break;
1020 case DSPROPERTY_EAX30BUFFER_FLAGS:
1021 GET_PROP(buf->deferred.eax.dwFlags, DWORD);
1022 break;
1024 default:
1025 hr = E_PROP_ID_UNSUPPORTED;
1026 FIXME("Unhandled buffer propid: 0x%08lx\n", propid);
1027 break;
1029 #undef GET_PROP
1031 return hr;
1035 /*******************
1036 * EAX 2 stuff
1037 ******************/
1039 #define EAX2LISTENERFLAGS_MASK (EAX20LISTENERFLAGS_DECAYTIMESCALE | \
1040 EAX20LISTENERFLAGS_REFLECTIONSSCALE | \
1041 EAX20LISTENERFLAGS_REFLECTIONSDELAYSCALE | \
1042 EAX20LISTENERFLAGS_REVERBSCALE | \
1043 EAX20LISTENERFLAGS_REVERBDELAYSCALE | \
1044 EAX20LISTENERFLAGS_DECAYHFLIMIT)
1046 static EAX20LISTENERPROPERTIES EAX3To2(const EAX30LISTENERPROPERTIES *props)
1048 EAX20LISTENERPROPERTIES ret;
1049 ret.lRoom = props->lRoom;
1050 ret.lRoomHF = props->lRoomHF;
1051 ret.flRoomRolloffFactor = props->flRoomRolloffFactor;
1052 ret.flDecayTime = props->flDecayTime;
1053 ret.flDecayHFRatio = props->flDecayHFRatio;
1054 ret.lReflections = props->lReflections;
1055 ret.flReflectionsDelay = props->flReflectionsDelay;
1056 ret.lReverb = props->lReverb;
1057 ret.flReverbDelay = props->flReverbDelay;
1058 ret.dwEnvironment = props->dwEnvironment;
1059 ret.flEnvironmentSize = props->flEnvironmentSize;
1060 ret.flEnvironmentDiffusion = props->flEnvironmentDiffusion;
1061 ret.flAirAbsorptionHF = props->flAirAbsorptionHF;
1062 ret.dwFlags = props->dwFlags & EAX2LISTENERFLAGS_MASK;
1063 return ret;
1066 static EAX20BUFFERPROPERTIES EAXBuffer3To2(const EAX30BUFFERPROPERTIES *props)
1068 EAX20BUFFERPROPERTIES ret;
1069 ret.lDirect = props->lDirect;
1070 ret.lDirectHF = props->lDirectHF;
1071 ret.lRoom = props->lRoom;
1072 ret.lRoomHF = props->lRoomHF;
1073 ret.flRoomRolloffFactor = props->flRoomRolloffFactor;
1074 ret.lObstruction = props->lObstruction;
1075 ret.flObstructionLFRatio = props->flObstructionLFRatio;
1076 ret.lOcclusion = props->lOcclusion;
1077 ret.flOcclusionLFRatio = props->flOcclusionLFRatio;
1078 ret.flOcclusionRoomRatio = props->flOcclusionRoomRatio;
1079 ret.lOutsideVolumeHF = props->lOutsideVolumeHF;
1080 ret.flAirAbsorptionFactor = props->flAirAbsorptionFactor;
1081 ret.dwFlags = props->dwFlags;
1082 return ret;
1086 HRESULT EAX2_Set(DS8Primary *prim, DWORD propid, void *pPropData, ULONG cbPropData)
1088 HRESULT hr;
1090 if(prim->effect == 0)
1091 return E_PROP_ID_UNSUPPORTED;
1093 hr = DSERR_INVALIDPARAM;
1094 switch(propid)
1096 case DSPROPERTY_EAX20LISTENER_NONE: /* not setting any property, just applying */
1097 hr = DS_OK;
1098 break;
1100 case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS:
1101 if(cbPropData >= sizeof(EAX20LISTENERPROPERTIES))
1103 union {
1104 const void *v;
1105 const EAX20LISTENERPROPERTIES *props;
1106 } data = { pPropData };
1107 EAX30LISTENERPROPERTIES props3 = REVERB_PRESET_GENERIC;
1108 if(data.props->dwEnvironment < EAX_ENVIRONMENT_COUNT)
1110 props3 = EnvironmentDefaults[data.props->dwEnvironment];
1111 props3.dwEnvironment = data.props->dwEnvironment;
1113 props3.flEnvironmentSize = data.props->flEnvironmentSize;
1114 props3.flEnvironmentDiffusion = data.props->flEnvironmentDiffusion;
1115 props3.lRoom = data.props->lRoom;
1116 props3.lRoomHF = data.props->lRoomHF;
1117 props3.flDecayTime = data.props->flDecayTime;
1118 props3.flDecayHFRatio = data.props->flDecayHFRatio;
1119 props3.lReflections = data.props->lReflections;
1120 props3.flReflectionsDelay = data.props->flReflectionsDelay;
1121 props3.lReverb = data.props->lReverb;
1122 props3.flReverbDelay = data.props->flReverbDelay;
1123 props3.flAirAbsorptionHF = data.props->flAirAbsorptionHF;
1124 props3.flRoomRolloffFactor = data.props->flRoomRolloffFactor;
1125 props3.dwFlags = data.props->dwFlags;
1127 ApplyReverbParams(prim, &props3);
1128 hr = DS_OK;
1130 break;
1132 case DSPROPERTY_EAX20LISTENER_ROOM:
1133 if(cbPropData >= sizeof(LONG))
1135 union { const void *v; const LONG *l; } data = { pPropData };
1137 prim->deferred.eax.lRoom = *data.l;
1138 alEffectf(prim->effect, AL_EAXREVERB_GAIN,
1139 mB_to_gain(prim->deferred.eax.lRoom));
1140 checkALError();
1142 prim->dirty.bit.effect = 1;
1143 hr = DS_OK;
1145 break;
1146 case DSPROPERTY_EAX20LISTENER_ROOMHF:
1147 if(cbPropData >= sizeof(LONG))
1149 union { const void *v; const LONG *l; } data = { pPropData };
1151 prim->deferred.eax.lRoomHF = *data.l;
1152 alEffectf(prim->effect, AL_EAXREVERB_GAINHF,
1153 mB_to_gain(prim->deferred.eax.lRoomHF));
1154 checkALError();
1156 prim->dirty.bit.effect = 1;
1157 hr = DS_OK;
1159 break;
1161 case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR:
1162 if(cbPropData >= sizeof(FLOAT))
1164 union { const void *v; const FLOAT *fl; } data = { pPropData };
1166 prim->deferred.eax.flRoomRolloffFactor = *data.fl;
1167 alEffectf(prim->effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR,
1168 prim->deferred.eax.flRoomRolloffFactor);
1169 checkALError();
1171 prim->dirty.bit.effect = 1;
1172 hr = DS_OK;
1174 break;
1176 case DSPROPERTY_EAX20LISTENER_DECAYTIME:
1177 if(cbPropData >= sizeof(FLOAT))
1179 union { const void *v; const FLOAT *fl; } data = { pPropData };
1181 prim->deferred.eax.flDecayTime = *data.fl;
1182 alEffectf(prim->effect, AL_EAXREVERB_DECAY_TIME,
1183 prim->deferred.eax.flDecayTime);
1184 checkALError();
1186 prim->dirty.bit.effect = 1;
1187 hr = DS_OK;
1189 break;
1190 case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO:
1191 if(cbPropData >= sizeof(FLOAT))
1193 union { const void *v; const FLOAT *fl; } data = { pPropData };
1195 prim->deferred.eax.flDecayHFRatio = *data.fl;
1196 alEffectf(prim->effect, AL_EAXREVERB_DECAY_HFRATIO,
1197 prim->deferred.eax.flDecayHFRatio);
1198 checkALError();
1200 prim->dirty.bit.effect = 1;
1201 hr = DS_OK;
1203 break;
1205 case DSPROPERTY_EAX20LISTENER_REFLECTIONS:
1206 if(cbPropData >= sizeof(LONG))
1208 union { const void *v; const LONG *l; } data = { pPropData };
1210 prim->deferred.eax.lReflections = *data.l;
1211 alEffectf(prim->effect, AL_EAXREVERB_REFLECTIONS_GAIN,
1212 mB_to_gain(prim->deferred.eax.lReflections));
1213 checkALError();
1215 prim->dirty.bit.effect = 1;
1216 hr = DS_OK;
1218 break;
1219 case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY:
1220 if(cbPropData >= sizeof(FLOAT))
1222 union { const void *v; const FLOAT *fl; } data = { pPropData };
1224 prim->deferred.eax.flReflectionsDelay = *data.fl;
1225 alEffectf(prim->effect, AL_EAXREVERB_REFLECTIONS_DELAY,
1226 prim->deferred.eax.flReflectionsDelay);
1227 checkALError();
1229 prim->dirty.bit.effect = 1;
1230 hr = DS_OK;
1232 break;
1234 case DSPROPERTY_EAX20LISTENER_REVERB:
1235 if(cbPropData >= sizeof(LONG))
1237 union { const void *v; const LONG *l; } data = { pPropData };
1239 prim->deferred.eax.lReverb = *data.l;
1240 alEffectf(prim->effect, AL_EAXREVERB_LATE_REVERB_GAIN,
1241 mB_to_gain(prim->deferred.eax.lReverb));
1242 checkALError();
1244 prim->dirty.bit.effect = 1;
1245 hr = DS_OK;
1247 break;
1248 case DSPROPERTY_EAX20LISTENER_REVERBDELAY:
1249 if(cbPropData >= sizeof(FLOAT))
1251 union { const void *v; const FLOAT *fl; } data = { pPropData };
1253 prim->deferred.eax.flReverbDelay = *data.fl;
1254 alEffectf(prim->effect, AL_EAXREVERB_LATE_REVERB_DELAY,
1255 prim->deferred.eax.flReverbDelay);
1256 checkALError();
1258 prim->dirty.bit.effect = 1;
1259 hr = DS_OK;
1261 break;
1263 case DSPROPERTY_EAX20LISTENER_ENVIRONMENT:
1264 if(cbPropData >= sizeof(DWORD))
1266 union { const void *v; const DWORD *dw; } data = { pPropData };
1267 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1269 ApplyReverbParams(prim, &EnvironmentDefaults[*data.dw]);
1270 hr = DS_OK;
1273 break;
1275 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE:
1276 if(cbPropData >= sizeof(FLOAT))
1278 union { const void *v; const FLOAT *fl; } data = { pPropData };
1279 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1281 float scale = (*data.fl)/prim->deferred.eax.flEnvironmentSize;
1283 prim->deferred.eax.flEnvironmentSize = *data.fl;
1285 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_DECAYTIMESCALE))
1287 prim->deferred.eax.flDecayTime *= scale;
1288 prim->deferred.eax.flDecayTime = clampF(prim->deferred.eax.flDecayTime, 0.1f, 20.0f);
1290 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_REFLECTIONSSCALE))
1292 prim->deferred.eax.lReflections -= gain_to_mB(scale);
1293 prim->deferred.eax.lReflections = clampI(prim->deferred.eax.lReflections, -10000, 1000);
1295 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_REFLECTIONSDELAYSCALE))
1297 prim->deferred.eax.flReflectionsDelay *= scale;
1298 prim->deferred.eax.flReflectionsDelay = clampF(prim->deferred.eax.flReflectionsDelay, 0.0f, 0.3f);
1300 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_REVERBSCALE))
1302 prim->deferred.eax.lReverb -= gain_to_mB(scale);
1303 prim->deferred.eax.lReverb = clampI(prim->deferred.eax.lReverb, -10000, 2000);
1305 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_REVERBDELAYSCALE))
1307 prim->deferred.eax.flReverbDelay *= scale;
1308 prim->deferred.eax.flReverbDelay = clampF(prim->deferred.eax.flReverbDelay, 0.0f, 0.1f);
1310 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_ECHOTIMESCALE))
1312 prim->deferred.eax.flEchoTime *= scale;
1313 prim->deferred.eax.flEchoTime = clampF(prim->deferred.eax.flEchoTime, 0.075f, 0.25f);
1315 if((prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_MODTIMESCALE))
1317 prim->deferred.eax.flModulationTime *= scale;
1318 prim->deferred.eax.flModulationTime = clampF(prim->deferred.eax.flModulationTime, 0.04f, 4.0f);
1321 ApplyReverbParams(prim, &prim->deferred.eax);
1322 hr = DS_OK;
1325 break;
1326 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION:
1327 if(cbPropData >= sizeof(FLOAT))
1329 union { const void *v; const FLOAT *fl; } data = { pPropData };
1331 prim->deferred.eax.flEnvironmentDiffusion = *data.fl;
1332 alEffectf(prim->effect, AL_EAXREVERB_DIFFUSION,
1333 prim->deferred.eax.flEnvironmentDiffusion);
1334 checkALError();
1336 prim->dirty.bit.effect = 1;
1337 hr = DS_OK;
1339 break;
1341 case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF:
1342 if(cbPropData >= sizeof(FLOAT))
1344 union { const void *v; const FLOAT *fl; } data = { pPropData };
1346 prim->deferred.eax.flAirAbsorptionHF = *data.fl;
1347 alEffectf(prim->effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF,
1348 mB_to_gain(prim->deferred.eax.flAirAbsorptionHF));
1349 checkALError();
1351 prim->dirty.bit.effect = 1;
1352 hr = DS_OK;
1354 break;
1356 case DSPROPERTY_EAX20LISTENER_FLAGS:
1357 if(cbPropData >= sizeof(DWORD))
1359 union { const void *v; const DWORD *dw; } data = { pPropData };
1361 prim->deferred.eax.dwFlags = *data.dw;
1362 alEffecti(prim->effect, AL_EAXREVERB_DECAY_HFLIMIT,
1363 (prim->deferred.eax.dwFlags&EAX30LISTENERFLAGS_DECAYHFLIMIT) ?
1364 AL_TRUE : AL_FALSE);
1365 checkALError();
1367 prim->dirty.bit.effect = 1;
1368 hr = DS_OK;
1370 break;
1372 default:
1373 hr = E_PROP_ID_UNSUPPORTED;
1374 FIXME("Unhandled listener propid: 0x%08lx\n", propid);
1375 break;
1378 return hr;
1381 HRESULT EAX2_Get(DS8Primary *prim, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
1383 HRESULT hr;
1385 if(prim->effect == 0)
1386 return E_PROP_ID_UNSUPPORTED;
1388 #define GET_PROP(src, T) do { \
1389 if(cbPropData >= sizeof(T)) \
1391 union { void *v; T *props; } data = { pPropData }; \
1392 *data.props = src; \
1393 *pcbReturned = sizeof(T); \
1394 hr = DS_OK; \
1396 } while(0)
1397 hr = DSERR_INVALIDPARAM;
1398 switch(propid)
1400 case DSPROPERTY_EAX20LISTENER_NONE:
1401 *pcbReturned = 0;
1402 hr = DS_OK;
1403 break;
1405 case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS:
1406 GET_PROP(EAX3To2(&prim->deferred.eax), EAX20LISTENERPROPERTIES);
1407 break;
1409 case DSPROPERTY_EAX20LISTENER_ROOM:
1410 GET_PROP(prim->deferred.eax.lRoom, LONG);
1411 break;
1412 case DSPROPERTY_EAX20LISTENER_ROOMHF:
1413 GET_PROP(prim->deferred.eax.lRoomHF, LONG);
1414 break;
1416 case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR:
1417 GET_PROP(prim->deferred.eax.flRoomRolloffFactor, FLOAT);
1418 break;
1420 case DSPROPERTY_EAX20LISTENER_DECAYTIME:
1421 GET_PROP(prim->deferred.eax.flDecayTime, FLOAT);
1422 break;
1423 case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO:
1424 GET_PROP(prim->deferred.eax.flDecayHFRatio, FLOAT);
1425 break;
1427 case DSPROPERTY_EAX20LISTENER_REFLECTIONS:
1428 GET_PROP(prim->deferred.eax.lReflections, LONG);
1429 break;
1430 case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY:
1431 GET_PROP(prim->deferred.eax.flReflectionsDelay, FLOAT);
1432 break;
1434 case DSPROPERTY_EAX20LISTENER_REVERB:
1435 GET_PROP(prim->deferred.eax.lReverb, LONG);
1436 break;
1437 case DSPROPERTY_EAX20LISTENER_REVERBDELAY:
1438 GET_PROP(prim->deferred.eax.flReverbDelay, FLOAT);
1439 break;
1441 case DSPROPERTY_EAX20LISTENER_ENVIRONMENT:
1442 GET_PROP(prim->deferred.eax.dwEnvironment, DWORD);
1443 break;
1445 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE:
1446 GET_PROP(prim->deferred.eax.flEnvironmentSize, FLOAT);
1447 break;
1448 case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION:
1449 GET_PROP(prim->deferred.eax.flEnvironmentDiffusion, FLOAT);
1450 break;
1452 case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF:
1453 GET_PROP(prim->deferred.eax.flAirAbsorptionHF, FLOAT);
1454 break;
1456 case DSPROPERTY_EAX20LISTENER_FLAGS:
1457 GET_PROP(prim->deferred.eax.dwFlags&EAX2LISTENERFLAGS_MASK, DWORD);
1458 break;
1460 default:
1461 hr = E_PROP_ID_UNSUPPORTED;
1462 FIXME("Unhandled listener propid: 0x%08lx\n", propid);
1463 break;
1465 #undef GET_PROP
1467 return hr;
1471 HRESULT EAX2Buffer_Set(DS8Buffer *buf, DWORD propid, void *pPropData, ULONG cbPropData)
1473 HRESULT hr;
1475 if(buf->filter[0] == 0)
1476 return E_PROP_ID_UNSUPPORTED;
1478 hr = DSERR_INVALIDPARAM;
1479 switch(propid)
1481 case DSPROPERTY_EAX20BUFFER_NONE: /* not setting any property, just applying */
1482 hr = DS_OK;
1483 break;
1485 case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS:
1486 if(cbPropData >= sizeof(EAX20BUFFERPROPERTIES))
1488 union {
1489 const void *v;
1490 const EAX20BUFFERPROPERTIES *props;
1491 } data = { pPropData };
1493 buf->deferred.eax.lDirect = data.props->lDirect;
1494 buf->deferred.eax.lDirectHF = data.props->lDirectHF;
1495 buf->deferred.eax.lRoom = data.props->lRoom;
1496 buf->deferred.eax.lRoomHF = data.props->lRoomHF;
1497 buf->deferred.eax.flRoomRolloffFactor = data.props->flRoomRolloffFactor;
1498 buf->deferred.eax.lObstruction = data.props->lObstruction;
1499 buf->deferred.eax.flObstructionLFRatio = data.props->flObstructionLFRatio;
1500 buf->deferred.eax.lOcclusion = data.props->lOcclusion;
1501 buf->deferred.eax.flOcclusionLFRatio = data.props->flOcclusionLFRatio;
1502 buf->deferred.eax.flOcclusionRoomRatio = data.props->flOcclusionRoomRatio;
1503 buf->deferred.eax.lOutsideVolumeHF = data.props->lOutsideVolumeHF;
1504 buf->deferred.eax.flAirAbsorptionFactor = data.props->flAirAbsorptionFactor;
1505 buf->deferred.eax.dwFlags = data.props->dwFlags;
1506 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
1508 buf->dirty.bit.dry_filter = 1;
1509 buf->dirty.bit.wet_filter = 1;
1510 buf->dirty.bit.room_rolloff = 1;
1511 buf->dirty.bit.cone_outsidevolumehf = 1;
1512 buf->dirty.bit.air_absorb = 1;
1513 buf->dirty.bit.flags = 1;
1514 hr = DS_OK;
1516 break;
1518 case DSPROPERTY_EAX20BUFFER_DIRECT:
1519 if(cbPropData >= sizeof(LONG))
1521 union { const void *v; const LONG *l; } data = { pPropData };
1523 buf->deferred.eax.lDirect = *data.l;
1524 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
1526 buf->dirty.bit.dry_filter = 1;
1527 hr = DS_OK;
1529 break;
1530 case DSPROPERTY_EAX20BUFFER_DIRECTHF:
1531 if(cbPropData >= sizeof(LONG))
1533 union { const void *v; const LONG *l; } data = { pPropData };
1535 buf->deferred.eax.lDirectHF = *data.l;
1536 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
1538 buf->dirty.bit.dry_filter = 1;
1539 hr = DS_OK;
1541 break;
1543 case DSPROPERTY_EAX20BUFFER_ROOM:
1544 if(cbPropData >= sizeof(LONG))
1546 union { const void *v; const LONG *l; } data = { pPropData };
1548 buf->deferred.eax.lRoom = *data.l;
1549 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
1551 buf->dirty.bit.wet_filter = 1;
1552 hr = DS_OK;
1554 break;
1555 case DSPROPERTY_EAX20BUFFER_ROOMHF:
1556 if(cbPropData >= sizeof(LONG))
1558 union { const void *v; const LONG *l; } data = { pPropData };
1560 buf->deferred.eax.lRoomHF = *data.l;
1561 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
1563 buf->dirty.bit.wet_filter = 1;
1564 hr = DS_OK;
1566 break;
1568 case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR:
1569 if(cbPropData >= sizeof(FLOAT))
1571 union { const void *v; const FLOAT *fl; } data = { pPropData };
1573 buf->deferred.eax.flRoomRolloffFactor = *data.fl;
1575 buf->dirty.bit.room_rolloff = 1;
1576 hr = DS_OK;
1578 break;
1580 case DSPROPERTY_EAX20BUFFER_OBSTRUCTION:
1581 if(cbPropData >= sizeof(LONG))
1583 union { const void *v; const LONG *l; } data = { pPropData };
1585 buf->deferred.eax.lObstruction = *data.l;
1586 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
1588 buf->dirty.bit.dry_filter = 1;
1589 hr = DS_OK;
1591 break;
1592 case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO:
1593 if(cbPropData >= sizeof(FLOAT))
1595 union { const void *v; const FLOAT *fl; } data = { pPropData };
1597 buf->deferred.eax.flObstructionLFRatio = *data.fl;
1598 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
1600 buf->dirty.bit.dry_filter = 1;
1601 hr = DS_OK;
1603 break;
1605 case DSPROPERTY_EAX20BUFFER_OCCLUSION:
1606 if(cbPropData >= sizeof(LONG))
1608 union { const void *v; const LONG *l; } data = { pPropData };
1610 buf->deferred.eax.lOcclusion = *data.l;
1611 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
1613 buf->dirty.bit.dry_filter = 1;
1614 buf->dirty.bit.wet_filter = 1;
1615 hr = DS_OK;
1617 break;
1618 case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO:
1619 if(cbPropData >= sizeof(FLOAT))
1621 union { const void *v; const FLOAT *fl; } data = { pPropData };
1623 buf->deferred.eax.flOcclusionLFRatio = *data.fl;
1624 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
1626 buf->dirty.bit.dry_filter = 1;
1627 buf->dirty.bit.wet_filter = 1;
1628 hr = DS_OK;
1630 break;
1631 case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO:
1632 if(cbPropData >= sizeof(FLOAT))
1634 union { const void *v; const FLOAT *fl; } data = { pPropData };
1636 buf->deferred.eax.flOcclusionRoomRatio = *data.fl;
1637 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
1639 buf->dirty.bit.dry_filter = 1;
1640 buf->dirty.bit.wet_filter = 1;
1641 hr = DS_OK;
1643 break;
1645 case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF:
1646 if(cbPropData >= sizeof(LONG))
1648 union { const void *v; const LONG *l; } data = { pPropData };
1650 buf->deferred.eax.lOutsideVolumeHF = *data.l;
1652 buf->dirty.bit.cone_outsidevolumehf = 1;
1653 hr = DS_OK;
1655 break;
1657 case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR:
1658 if(cbPropData >= sizeof(FLOAT))
1660 union { const void *v; const FLOAT *fl; } data = { pPropData };
1662 buf->deferred.eax.flAirAbsorptionFactor = *data.fl;
1664 buf->dirty.bit.air_absorb = 1;
1665 hr = DS_OK;
1667 break;
1669 case DSPROPERTY_EAX20BUFFER_FLAGS:
1670 if(cbPropData >= sizeof(DWORD))
1672 union { const void *v; const DWORD *dw; } data = { pPropData };
1674 buf->deferred.eax.dwFlags = *data.dw;
1676 buf->dirty.bit.flags = 1;
1677 hr = DS_OK;
1679 break;
1681 default:
1682 hr = E_PROP_ID_UNSUPPORTED;
1683 FIXME("Unhandled buffer propid: 0x%08lx\n", propid);
1684 break;
1687 return hr;
1690 HRESULT EAX2Buffer_Get(DS8Buffer *buf, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
1692 HRESULT hr;
1694 if(buf->filter[0] == 0)
1695 return E_PROP_ID_UNSUPPORTED;
1697 #define GET_PROP(src, T) do { \
1698 if(cbPropData >= sizeof(T)) \
1700 union { void *v; T *props; } data = { pPropData }; \
1701 *data.props = src; \
1702 *pcbReturned = sizeof(T); \
1703 hr = DS_OK; \
1705 } while(0)
1706 hr = DSERR_INVALIDPARAM;
1707 switch(propid)
1709 case DSPROPERTY_EAX20BUFFER_NONE:
1710 *pcbReturned = 0;
1711 hr = DS_OK;
1712 break;
1714 case DSPROPERTY_EAX20BUFFER_ALLPARAMETERS:
1715 GET_PROP(EAXBuffer3To2(&buf->deferred.eax), EAX20BUFFERPROPERTIES);
1716 break;
1718 case DSPROPERTY_EAX20BUFFER_DIRECT:
1719 GET_PROP(buf->deferred.eax.lDirect, LONG);
1720 break;
1721 case DSPROPERTY_EAX20BUFFER_DIRECTHF:
1722 GET_PROP(buf->deferred.eax.lDirectHF, LONG);
1723 break;
1725 case DSPROPERTY_EAX20BUFFER_ROOM:
1726 GET_PROP(buf->deferred.eax.lRoom, LONG);
1727 break;
1728 case DSPROPERTY_EAX20BUFFER_ROOMHF:
1729 GET_PROP(buf->deferred.eax.lRoomHF, LONG);
1730 break;
1732 case DSPROPERTY_EAX20BUFFER_ROOMROLLOFFFACTOR:
1733 GET_PROP(buf->deferred.eax.flRoomRolloffFactor, FLOAT);
1734 break;
1736 case DSPROPERTY_EAX20BUFFER_OBSTRUCTION:
1737 GET_PROP(buf->deferred.eax.lObstruction, LONG);
1738 break;
1739 case DSPROPERTY_EAX20BUFFER_OBSTRUCTIONLFRATIO:
1740 GET_PROP(buf->deferred.eax.flObstructionLFRatio, FLOAT);
1741 break;
1743 case DSPROPERTY_EAX20BUFFER_OCCLUSION:
1744 GET_PROP(buf->deferred.eax.lOcclusion, LONG);
1745 break;
1746 case DSPROPERTY_EAX20BUFFER_OCCLUSIONLFRATIO:
1747 GET_PROP(buf->deferred.eax.flOcclusionLFRatio, FLOAT);
1748 break;
1749 case DSPROPERTY_EAX20BUFFER_OCCLUSIONROOMRATIO:
1750 GET_PROP(buf->deferred.eax.flOcclusionRoomRatio, FLOAT);
1751 break;
1753 case DSPROPERTY_EAX20BUFFER_OUTSIDEVOLUMEHF:
1754 GET_PROP(buf->deferred.eax.lOutsideVolumeHF, LONG);
1755 break;
1757 case DSPROPERTY_EAX20BUFFER_AIRABSORPTIONFACTOR:
1758 GET_PROP(buf->deferred.eax.flAirAbsorptionFactor, FLOAT);
1759 break;
1761 case DSPROPERTY_EAX20BUFFER_FLAGS:
1762 GET_PROP(buf->deferred.eax.dwFlags, DWORD);
1763 break;
1765 default:
1766 hr = E_PROP_ID_UNSUPPORTED;
1767 FIXME("Unhandled buffer propid: 0x%08lx\n", propid);
1768 break;
1770 #undef GET_PROP
1772 return hr;
1776 /*******************
1777 * EAX 1 stuff
1778 ******************/
1780 HRESULT EAX1_Set(DS8Primary *prim, DWORD propid, void *pPropData, ULONG cbPropData)
1782 static const float eax1_env_volume[EAX_ENVIRONMENT_COUNT] = {
1783 0.5f, 0.25f, 0.417f, 0.653f, 0.208f, 0.5f, 0.403f, 0.5f, 0.5f,
1784 0.361f, 0.5f, 0.153f, 0.361f, 0.444f, 0.25f, 0.111f, 0.111f,
1785 0.194f, 1.0f, 0.097f, 0.208f, 0.652f, 1.0f, 0.875f, 0.139f, 0.486f
1787 static const float eax1_env_dampening[EAX_ENVIRONMENT_COUNT] = {
1788 0.5f, 0.0f, 0.666f, 0.166f, 0.0f, 0.888f, 0.5f, 0.5f, 1.304f,
1789 0.332f, 0.3f, 2.0f, 0.0f, 0.638f, 0.776f, 0.472f, 0.224f, 0.472f,
1790 0.5f, 0.224f, 1.5f, 0.25f, 0.0f, 1.388f, 0.666f, 0.806f
1792 HRESULT hr;
1794 if(prim->effect == 0)
1795 return E_PROP_ID_UNSUPPORTED;
1797 hr = DSERR_INVALIDPARAM;
1798 switch(propid)
1800 case DSPROPERTY_EAX1_ALL:
1801 if(cbPropData >= sizeof(EAX1_REVERBPROPERTIES))
1803 union {
1804 const void *v;
1805 const EAX1_REVERBPROPERTIES *props;
1806 } data = { pPropData };
1808 if(data.props->dwEnvironment < EAX_ENVIRONMENT_COUNT)
1810 /* NOTE: I'm not quite sure how to handle the volume. It's
1811 * important to deal with since it can have a notable impact on
1812 * the output levels, but given the default EAX1 environment
1813 * volumes, they don't align with the gain/room volume for
1814 * EAX2+ environments. Presuming the default volumes are
1815 * correct, it's possible the reverb implementation was
1816 * different and relied on different gains to get the intended
1817 * output levels.
1819 * Rather than just blindly applying the volume, we take the
1820 * difference from the EAX1 environment's default volume and
1821 * apply that as an offset to the EAX2 environment's volume.
1823 EAX30LISTENERPROPERTIES env = EnvironmentDefaults[data.props->dwEnvironment];
1824 LONG db_vol = clampI(
1825 gain_to_mB(data.props->fVolume / eax1_env_volume[data.props->dwEnvironment]),
1826 -10000, 10000
1828 env.lRoom = clampI(env.lRoom + db_vol, -10000, 0);
1829 env.flDecayTime = data.props->fDecayTime;
1830 prim->deferred.eax1_volume = data.props->fVolume;
1831 prim->deferred.eax1_dampening = data.props->fDamping;
1832 ApplyReverbParams(prim, &env);
1833 hr = DS_OK;
1836 break;
1838 case DSPROPERTY_EAX1_ENVIRONMENT:
1839 if(cbPropData >= sizeof(DWORD))
1841 union { const void *v; const DWORD *dw; } data = { pPropData };
1843 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1845 prim->deferred.eax1_volume = eax1_env_volume[*data.dw];
1846 prim->deferred.eax1_dampening = eax1_env_dampening[*data.dw];
1847 ApplyReverbParams(prim, &EnvironmentDefaults[*data.dw]);
1848 hr = DS_OK;
1851 break;
1853 case DSPROPERTY_EAX1_VOLUME:
1854 if(cbPropData >= sizeof(FLOAT))
1856 union { const void *v; const FLOAT *fl; } data = { pPropData };
1857 LONG db_vol = clampI(
1858 gain_to_mB(*data.fl / eax1_env_volume[prim->deferred.eax.dwEnvironment]),
1859 -10000, 10000
1861 LONG room_vol = clampI(
1862 EnvironmentDefaults[prim->deferred.eax.dwEnvironment].lRoom + db_vol,
1863 -10000, 0
1866 prim->deferred.eax.lRoom = room_vol;
1867 prim->deferred.eax1_volume = *data.fl;
1868 alEffectf(prim->effect, AL_EAXREVERB_GAIN, mB_to_gain(room_vol));
1869 checkALError();
1871 prim->dirty.bit.effect = 1;
1872 hr = DS_OK;
1874 break;
1875 case DSPROPERTY_EAX1_DECAYTIME:
1876 if(cbPropData >= sizeof(FLOAT))
1878 union { const void *v; const FLOAT *fl; } data = { pPropData };
1880 prim->deferred.eax.flDecayTime = *data.fl;
1881 alEffectf(prim->effect, AL_EAXREVERB_DECAY_TIME,
1882 prim->deferred.eax.flDecayTime);
1883 checkALError();
1885 prim->dirty.bit.effect = 1;
1886 hr = DS_OK;
1888 break;
1889 case DSPROPERTY_EAX1_DAMPING:
1890 if(cbPropData >= sizeof(FLOAT))
1892 union { const void *v; const FLOAT *fl; } data = { pPropData };
1894 prim->deferred.eax1_dampening = *data.fl;
1896 hr = DS_OK;
1898 break;
1900 default:
1901 hr = E_PROP_ID_UNSUPPORTED;
1902 FIXME("Unhandled listener propid: 0x%08lx\n", propid);
1903 break;
1906 return hr;
1909 HRESULT EAX1_Get(DS8Primary *prim, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
1911 HRESULT hr;
1913 if(prim->effect == 0)
1914 return E_PROP_ID_UNSUPPORTED;
1916 hr = DSERR_INVALIDPARAM;
1917 switch(propid)
1919 case DSPROPERTY_EAX1_ALL:
1920 if(cbPropData >= sizeof(EAX1_REVERBPROPERTIES))
1922 union {
1923 void *v;
1924 EAX1_REVERBPROPERTIES *props;
1925 } data = { pPropData };
1927 data.props->dwEnvironment = prim->deferred.eax.dwEnvironment;
1928 data.props->fVolume = prim->deferred.eax1_volume;
1929 data.props->fDecayTime = prim->deferred.eax.flDecayTime;
1930 data.props->fDamping = prim->deferred.eax1_dampening;
1932 *pcbReturned = sizeof(EAX1_REVERBPROPERTIES);
1933 hr = DS_OK;
1935 break;
1937 case DSPROPERTY_EAX1_ENVIRONMENT:
1938 if(cbPropData >= sizeof(DWORD))
1940 union { void *v; DWORD *dw; } data = { pPropData };
1942 *data.dw = prim->deferred.eax.dwEnvironment;
1944 *pcbReturned = sizeof(DWORD);
1945 hr = DS_OK;
1947 break;
1949 case DSPROPERTY_EAX1_VOLUME:
1950 if(cbPropData >= sizeof(FLOAT))
1952 union { void *v; FLOAT *fl; } data = { pPropData };
1954 *data.fl = prim->deferred.eax1_volume;
1956 *pcbReturned = sizeof(FLOAT);
1957 hr = DS_OK;
1959 break;
1961 case DSPROPERTY_EAX1_DECAYTIME:
1962 if(cbPropData >= sizeof(FLOAT))
1964 union { void *v; FLOAT *fl; } data = { pPropData };
1966 *data.fl = prim->deferred.eax.flDecayTime;
1968 *pcbReturned = sizeof(FLOAT);
1969 hr = DS_OK;
1971 break;
1973 case DSPROPERTY_EAX1_DAMPING:
1974 if(cbPropData >= sizeof(FLOAT))
1976 union { void *v; FLOAT *fl; } data = { pPropData };
1978 *data.fl = prim->deferred.eax1_dampening;
1980 *pcbReturned = sizeof(FLOAT);
1981 hr = DS_OK;
1983 break;
1985 default:
1986 hr = E_PROP_ID_UNSUPPORTED;
1987 FIXME("Unhandled listener propid: 0x%08lx\n", propid);
1988 break;
1991 return hr;
1994 HRESULT EAX1Buffer_Set(DS8Buffer *buf, DWORD propid, void *pPropData, ULONG cbPropData)
1996 HRESULT hr;
1998 if(buf->filter[0] == 0)
1999 return E_PROP_ID_UNSUPPORTED;
2001 hr = DSERR_INVALIDPARAM;
2002 switch(propid)
2004 /* NOTE: DSPROPERTY_EAX1BUFFER_ALL is for EAX1BUFFER_REVERBPROPERTIES,
2005 * however that struct just contains the single ReverbMix float property.
2007 case DSPROPERTY_EAX1BUFFER_ALL:
2008 case DSPROPERTY_EAX1BUFFER_REVERBMIX:
2009 if(cbPropData >= sizeof(FLOAT))
2011 union { const void *v; const FLOAT *fl; } data = { pPropData };
2013 buf->deferred.eax.lRoom = gain_to_mB(*data.fl);
2014 buf->deferred.eax1_reverbmix = *data.fl;
2015 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_WET_PARAMS);
2017 buf->dirty.bit.wet_filter = 1;
2018 hr = DS_OK;
2020 break;
2022 default:
2023 hr = E_PROP_ID_UNSUPPORTED;
2024 FIXME("Unhandled buffer propid: 0x%08lx\n", propid);
2025 break;
2028 return hr;
2031 HRESULT EAX1Buffer_Get(DS8Buffer *buf, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
2033 HRESULT hr;
2035 if(buf->filter[0] == 0)
2036 return E_PROP_ID_UNSUPPORTED;
2038 hr = DSERR_INVALIDPARAM;
2039 switch(propid)
2041 case DSPROPERTY_EAX1BUFFER_ALL:
2042 case DSPROPERTY_EAX1BUFFER_REVERBMIX:
2043 if(cbPropData >= sizeof(FLOAT))
2045 union { void *v; FLOAT *fl; } data = { pPropData };
2047 *data.fl = buf->deferred.eax1_reverbmix;
2048 *pcbReturned = sizeof(FLOAT);
2049 hr = DS_OK;
2051 break;
2053 default:
2054 hr = E_PROP_ID_UNSUPPORTED;
2055 FIXME("Unhandled buffer propid: 0x%08lx\n", propid);
2056 break;
2059 return hr;