Special-case EAX2's occlusion room ratio
[dsound-openal.git] / eax4.c
blob6b4d25689d228363ac8815925166e510faf153af
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"
26 #include "eax-presets.h"
29 static const char *debug_fxslot(const GUID *guid)
31 #define HANDLE_ID(id) if(IsEqualGUID(guid, &(id))) return #id
32 HANDLE_ID(EAX_NULL_GUID);
33 HANDLE_ID(EAX_PrimaryFXSlotID);
34 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot0);
35 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot1);
36 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot2);
37 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot3);
38 #undef HANDLE_ID
39 return debugstr_guid(guid);
42 static const char *debug_fxguid(const GUID *guid)
44 #define HANDLE_ID(id) if(IsEqualGUID(guid, &(id))) return #id
45 HANDLE_ID(EAX_NULL_GUID);
46 HANDLE_ID(EAX_REVERB_EFFECT);
47 HANDLE_ID(EAX_AGCCOMPRESSOR_EFFECT);
48 HANDLE_ID(EAX_AUTOWAH_EFFECT);
49 HANDLE_ID(EAX_CHORUS_EFFECT);
50 HANDLE_ID(EAX_DISTORTION_EFFECT);
51 HANDLE_ID(EAX_ECHO_EFFECT);
52 HANDLE_ID(EAX_EQUALIZER_EFFECT);
53 HANDLE_ID(EAX_FLANGER_EFFECT);
54 HANDLE_ID(EAX_FREQUENCYSHIFTER_EFFECT);
55 HANDLE_ID(EAX_VOCALMORPHER_EFFECT);
56 HANDLE_ID(EAX_PITCHSHIFTER_EFFECT);
57 HANDLE_ID(EAX_RINGMODULATOR_EFFECT);
58 #undef HANDLE_ID
59 return debugstr_guid(guid);
63 HRESULT EAX4Context_Query(DSPrimary *prim, DWORD propid, ULONG *pTypeSupport)
65 if(!HAS_EXTENSION(prim->share, EXT_EFX))
66 return E_PROP_ID_UNSUPPORTED;
68 switch((propid&~EAXCONTEXT_PARAMETER_DEFERRED))
70 case EAXCONTEXT_NONE:
71 case EAXCONTEXT_ALLPARAMETERS:
72 case EAXCONTEXT_PRIMARYFXSLOTID:
73 case EAXCONTEXT_DISTANCEFACTOR:
74 case EAXCONTEXT_AIRABSORPTIONHF:
75 case EAXCONTEXT_HFREFERENCE:
76 case EAXCONTEXT_LASTERROR:
77 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
78 return DS_OK;
80 FIXME("Unhandled propid: 0x%08lx\n", propid);
81 return E_PROP_ID_UNSUPPORTED;
84 HRESULT EAX4Context_Set(DSPrimary *prim, DWORD propid, void *pPropData, ULONG cbPropData)
86 if(!HAS_EXTENSION(prim->share, EXT_EFX))
87 return E_PROP_ID_UNSUPPORTED;
89 switch(propid)
91 case EAXCONTEXT_NONE: /* not setting any property, just applying */
92 return DS_OK;
94 case EAXCONTEXT_ALLPARAMETERS:
95 if(cbPropData >= sizeof(EAXCONTEXTPROPERTIES))
97 union { void *v; const EAXCONTEXTPROPERTIES *props; } data = { pPropData };
98 ALuint prim_slot;
99 TRACE("Parameters:\n\tPrimary FXSlot: %s\n\tDistance Factor: %f\n\t"
100 "Air Absorption: %f\n\tHF Reference: %f\n",
101 debug_fxslot(&data.props->guidPrimaryFXSlotID), data.props->flDistanceFactor,
102 data.props->flAirAbsorptionHF, data.props->flHFReference
105 prim_slot = 0;
106 if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot0))
107 prim_slot = prim->auxslot[0];
108 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot1))
109 prim_slot = prim->auxslot[1];
110 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot2))
111 prim_slot = prim->auxslot[2];
112 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot3))
113 prim_slot = prim->auxslot[3];
114 if(prim_slot == 0 && !IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAX_NULL_GUID))
116 ERR("Unexpected primary FXSlot: %s\n",
117 debug_fxslot(&data.props->guidPrimaryFXSlotID));
118 return DSERR_INVALIDPARAM;
120 if(!(data.props->flDistanceFactor >= DS3D_MINDISTANCEFACTOR &&
121 data.props->flDistanceFactor <= DS3D_MAXDISTANCEFACTOR))
123 ERR("Unexpected distance factor: %f\n", data.props->flDistanceFactor);
124 return DSERR_INVALIDPARAM;
126 if(!(data.props->flAirAbsorptionHF <= 0.0f && data.props->flAirAbsorptionHF >= -100.0f))
128 ERR("Unexpected air absorption: %f\n", data.props->flAirAbsorptionHF);
129 return DSERR_INVALIDPARAM;
131 if(!(data.props->flHFReference >= 1000.0f && data.props->flHFReference <= 20000.0f))
133 ERR("Unexpected HF reference: %f\n", data.props->flAirAbsorptionHF);
134 return DSERR_INVALIDPARAM;
137 prim->deferred.ctx = *data.props;
138 prim->primary_slot = prim_slot;
140 prim->dirty.bit.prim_slotid = 1;
141 prim->dirty.bit.distancefactor2 = 1;
142 prim->dirty.bit.air_absorbhf = 1;
143 prim->dirty.bit.hfreference = 1;
144 return DS_OK;
146 return DSERR_INVALIDPARAM;
148 case EAXCONTEXT_PRIMARYFXSLOTID:
149 if(cbPropData >= sizeof(GUID))
151 union { void *v; const GUID *guid; } data = { pPropData };
152 ALuint prim_slot;
153 TRACE("Primary FXSlot: %s\n", debug_fxslot(data.guid));
155 prim_slot = 0;
156 if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot0))
157 prim_slot = prim->auxslot[0];
158 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot1))
159 prim_slot = prim->auxslot[1];
160 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot2))
161 prim_slot = prim->auxslot[2];
162 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot3))
163 prim_slot = prim->auxslot[3];
164 if(prim_slot == 0 && !IsEqualGUID(data.guid, &EAX_NULL_GUID))
166 ERR("Unexpected primary FXSlot: %s\n", debug_fxslot(data.guid));
167 return DSERR_INVALIDPARAM;
170 prim->deferred.ctx.guidPrimaryFXSlotID = *data.guid;
171 prim->primary_slot = prim_slot;
173 prim->dirty.bit.prim_slotid = 1;
174 return DS_OK;
176 return DSERR_INVALIDPARAM;
178 case EAXCONTEXT_DISTANCEFACTOR:
179 if(cbPropData >= sizeof(float))
181 union { void *v; const float *fl; } data = { pPropData };
182 TRACE("Distance Factor: %f\n", *data.fl);
184 if(!(*data.fl >= DS3D_MINDISTANCEFACTOR && *data.fl <= DS3D_MAXDISTANCEFACTOR))
186 ERR("Unexpected distance factor: %f\n", *data.fl);
187 return DSERR_INVALIDPARAM;
190 prim->deferred.ctx.flDistanceFactor = *data.fl;
192 prim->dirty.bit.distancefactor2 = 1;
193 return DS_OK;
195 return DSERR_INVALIDPARAM;
197 case EAXCONTEXT_AIRABSORPTIONHF:
198 if(cbPropData >= sizeof(float))
200 union { void *v; const float *fl; } data = { pPropData };
201 TRACE("Air Absorption: %f\n", *data.fl);
203 if(!(*data.fl <= 0.0f && *data.fl >= -100.0f))
205 ERR("Unexpected air absorption: %f\n", *data.fl);
206 return DSERR_INVALIDPARAM;
209 prim->deferred.ctx.flAirAbsorptionHF = *data.fl;
211 prim->dirty.bit.air_absorbhf = 1;
212 return DS_OK;
214 return DSERR_INVALIDPARAM;
216 case EAXCONTEXT_HFREFERENCE:
217 if(cbPropData >= sizeof(float))
219 union { void *v; const float *fl; } data = { pPropData };
220 TRACE("HF Reference: %f\n", *data.fl);
222 if(!(*data.fl >= 1000.0f && *data.fl <= 20000.0f))
224 ERR("Unexpected HF reference: %f\n", *data.fl);
225 return DSERR_INVALIDPARAM;
228 prim->deferred.ctx.flHFReference = *data.fl;
230 prim->dirty.bit.hfreference = 1;
231 return DS_OK;
233 return DSERR_INVALIDPARAM;
235 case EAXCONTEXT_LASTERROR:
236 if(cbPropData >= sizeof(long))
238 union { void *v; const long *l; } data = { pPropData };
239 TRACE("Last Error: %ld\n", *data.l);
241 prim->eax_error = *data.l;
243 return DS_OK;
245 return DSERR_INVALIDPARAM;
247 FIXME("Unhandled propid: 0x%08lx\n", propid);
248 return E_PROP_ID_UNSUPPORTED;
251 #define GET_PROP(src, T) do { \
252 if(cbPropData >= sizeof(T)) \
254 union { void *v; T *props; } data = { pPropData }; \
255 *data.props = src; \
256 *pcbReturned = sizeof(T); \
257 return DS_OK; \
259 return DSERR_INVALIDPARAM; \
260 } while(0)
262 HRESULT EAX4Context_Get(DSPrimary *prim, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
264 if(!HAS_EXTENSION(prim->share, EXT_EFX))
265 return E_PROP_ID_UNSUPPORTED;
267 switch(propid)
269 case EAXCONTEXT_NONE:
270 *pcbReturned = 0;
271 return DS_OK;
273 case EAXCONTEXT_ALLPARAMETERS:
274 GET_PROP(prim->current.ctx, EAXCONTEXTPROPERTIES);
275 case EAXCONTEXT_PRIMARYFXSLOTID:
276 GET_PROP(prim->current.ctx.guidPrimaryFXSlotID, GUID);
277 case EAXCONTEXT_DISTANCEFACTOR:
278 GET_PROP(prim->current.ctx.flDistanceFactor, float);
279 case EAXCONTEXT_AIRABSORPTIONHF:
280 GET_PROP(prim->current.ctx.flAirAbsorptionHF, float);
281 case EAXCONTEXT_HFREFERENCE:
282 GET_PROP(prim->current.ctx.flHFReference, float);
284 case EAXCONTEXT_LASTERROR:
285 GET_PROP(InterlockedExchange(&prim->eax_error, EAX_OK), long);
287 FIXME("Unhandled propid: 0x%08lx\n", propid);
288 return E_PROP_ID_UNSUPPORTED;
292 HRESULT EAX4Slot_Query(DSPrimary *prim, LONG idx, DWORD propid, ULONG *pTypeSupport)
294 if(prim->auxslot[idx] == 0)
295 return E_PROP_ID_UNSUPPORTED;
297 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) < EAXFXSLOT_NONE)
299 if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
301 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) <= EAXREVERB_FLAGS)
303 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
304 return DS_OK;
306 FIXME("Unhandled reverb propid: 0x%08lx\n", propid);
308 else if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
310 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) <= EAXCHORUS_DELAY)
312 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
313 return DS_OK;
315 FIXME("Unhandled chorus propid: 0x%08lx\n", propid);
317 else /*if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_NULL)*/
319 FIXME("Unhandled null effect propid: 0x%08lx\n", propid);
321 return DSERR_INVALIDPARAM;
323 switch((propid&~EAXFXSLOT_PARAMETER_DEFERRED))
325 case EAXFXSLOT_NONE:
326 case EAXFXSLOT_ALLPARAMETERS:
327 case EAXFXSLOT_LOADEFFECT:
328 case EAXFXSLOT_VOLUME:
329 case EAXFXSLOT_LOCK:
330 case EAXFXSLOT_FLAGS:
331 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
332 return DS_OK;
334 FIXME("Unhandled propid: 0x%08lx\n", propid);
335 return E_PROP_ID_UNSUPPORTED;
339 HRESULT EAX4Slot_Set(DSPrimary *prim, LONG idx, DWORD propid, void *pPropData, ULONG cbPropData)
341 if(prim->auxslot[idx] == 0)
342 return E_PROP_ID_UNSUPPORTED;
344 if(propid < EAXFXSLOT_NONE)
346 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
347 return EAXReverb_Set(prim, idx, propid, pPropData, cbPropData);
348 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
349 return EAXChorus_Set(prim, idx, propid, pPropData, cbPropData);
351 ERR("Unexpected null effect propid 0x%08lx\n", propid);
352 return E_PROP_ID_UNSUPPORTED;
354 switch(propid)
356 case EAXFXSLOT_NONE: /* not setting any property, just applying */
357 return DS_OK;
359 case EAXFXSLOT_ALLPARAMETERS:
360 if(cbPropData >= sizeof(EAXFXSLOTPROPERTIES))
362 union { const void *v; const EAXFXSLOTPROPERTIES *props; } data = { pPropData };
363 DWORD effect_type;
364 TRACE("Parameters:\n\tLoad Effect: %s\n\tVolume: %ld\n\tLock: %ld\n\tFlags: 0x%lx\n",
365 debug_fxguid(&data.props->guidLoadEffect), data.props->lVolume, data.props->lLock,
366 data.props->dwFlags
369 effect_type = FXSLOT_EFFECT_NULL;
370 if(IsEqualGUID(&data.props->guidLoadEffect, &EAX_REVERB_EFFECT))
371 effect_type = FXSLOT_EFFECT_REVERB;
372 else if(IsEqualGUID(&data.props->guidLoadEffect, &EAX_CHORUS_EFFECT))
373 effect_type = FXSLOT_EFFECT_CHORUS;
374 else if(!IsEqualGUID(&data.props->guidLoadEffect, &EAX_NULL_GUID))
376 ERR("Unhandled effect: %s\n", debug_fxguid(&data.props->guidLoadEffect));
377 return DSERR_INVALIDPARAM;
380 if(data.props->lLock == EAXFXSLOT_LOCKED &&
381 prim->deferred.fxslot[idx].props.lLock == EAXFXSLOT_LOCKED &&
382 prim->deferred.fxslot[idx].effect_type != effect_type)
384 ERR("Attempting to change effect type for locked FXSlot\n");
385 return DSERR_INVALIDCALL;
388 if(prim->deferred.fxslot[idx].effect_type != effect_type)
390 alGetError();
391 alEffecti(prim->effect[idx], AL_EFFECT_TYPE,
392 (effect_type == FXSLOT_EFFECT_REVERB) ? AL_EFFECT_EAXREVERB :
393 (effect_type == FXSLOT_EFFECT_CHORUS) ? AL_EFFECT_CHORUS :
394 AL_EFFECT_NULL
396 if(alGetError() != AL_NO_ERROR)
398 ERR("Failed to set effect type %lu\n", effect_type);
399 return DSERR_INVALIDPARAM;
402 prim->deferred.fxslot[idx].effect_type = effect_type;
403 memset(&prim->deferred.fxslot[idx].fx, 0, sizeof(prim->deferred.fxslot[idx].fx));
404 if(effect_type == FXSLOT_EFFECT_REVERB)
405 prim->deferred.fxslot[idx].fx.reverb = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
406 else if(effect_type == FXSLOT_EFFECT_CHORUS)
408 const EAXCHORUSPROPERTIES chorus_def = CHORUS_PRESET_DEFAULT;
409 prim->deferred.fxslot[idx].fx.chorus = chorus_def;
412 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_EFFECT_BIT);
414 prim->deferred.fxslot[idx].props = *data.props;
416 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_VOL_BIT);
417 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_LOCK_BIT);
418 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_FLAGS_BIT);
419 return DS_OK;
421 return DSERR_INVALIDPARAM;
423 case EAXFXSLOT_LOADEFFECT:
424 if(cbPropData >= sizeof(GUID))
426 union { const void *v; const GUID *guid; } data = { pPropData };
427 DWORD effect_type;
428 TRACE("Load Effect: %s\n", debug_fxguid(data.guid));
430 effect_type = FXSLOT_EFFECT_NULL;
431 if(IsEqualGUID(data.guid, &EAX_REVERB_EFFECT))
432 effect_type = FXSLOT_EFFECT_REVERB;
433 else if(IsEqualGUID(data.guid, &EAX_CHORUS_EFFECT))
434 effect_type = FXSLOT_EFFECT_CHORUS;
435 else if(!IsEqualGUID(data.guid, &EAX_NULL_GUID))
437 ERR("Unhandled effect: %s\n", debug_fxguid(data.guid));
438 return DSERR_INVALIDPARAM;
441 if(prim->deferred.fxslot[idx].props.lLock == EAXFXSLOT_LOCKED)
443 ERR("Attempting to change effect type for locked FXSlot\n");
444 return DSERR_INVALIDCALL;
447 alGetError();
448 alEffecti(prim->effect[idx], AL_EFFECT_TYPE,
449 (effect_type == FXSLOT_EFFECT_REVERB) ? AL_EFFECT_EAXREVERB :
450 (effect_type == FXSLOT_EFFECT_CHORUS) ? AL_EFFECT_CHORUS :
451 AL_EFFECT_NULL
453 if(alGetError() != AL_NO_ERROR)
455 ERR("Failed to set effect type %lu\n", effect_type);
456 return DSERR_INVALIDPARAM;
459 prim->deferred.fxslot[idx].effect_type = effect_type;
460 memset(&prim->deferred.fxslot[idx].fx, 0, sizeof(prim->deferred.fxslot[idx].fx));
461 if(effect_type == FXSLOT_EFFECT_REVERB)
462 prim->deferred.fxslot[idx].fx.reverb = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
463 else if(effect_type == FXSLOT_EFFECT_CHORUS)
465 const EAXCHORUSPROPERTIES chorus_def = CHORUS_PRESET_DEFAULT;
466 prim->deferred.fxslot[idx].fx.chorus = chorus_def;
468 prim->deferred.fxslot[idx].props.guidLoadEffect = *data.guid;
470 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_EFFECT_BIT);
471 return DS_OK;
473 return DSERR_INVALIDPARAM;
475 case EAXFXSLOT_VOLUME:
476 if(cbPropData >= sizeof(long))
478 union { const void *v; const long *l; } data = { pPropData };
479 TRACE("Volume: %ld\n", *data.l);
481 prim->deferred.fxslot[idx].props.lVolume = *data.l;
483 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_VOL_BIT);
484 return DS_OK;
486 return DSERR_INVALIDPARAM;
488 case EAXFXSLOT_LOCK:
489 if(cbPropData >= sizeof(long))
491 union { const void *v; const long *l; } data = { pPropData };
492 TRACE("Lock: %ld\n", *data.l);
494 prim->deferred.fxslot[idx].props.lLock = *data.l;
496 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_LOCK_BIT);
497 return DS_OK;
499 return DSERR_INVALIDPARAM;
501 case EAXFXSLOT_FLAGS:
502 if(cbPropData >= sizeof(DWORD))
504 union { const void *v; const DWORD *dw; } data = { pPropData };
505 TRACE("Flags: 0x%lx\n", *data.dw);
507 prim->deferred.fxslot[idx].props.dwFlags = *data.dw;
509 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_FLAGS_BIT);
510 return DS_OK;
512 return DSERR_INVALIDPARAM;
514 FIXME("Unhandled propid: 0x%08lx\n", propid);
515 return E_PROP_ID_UNSUPPORTED;
518 HRESULT EAX4Slot_Get(DSPrimary *prim, LONG idx, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
520 if(prim->auxslot[idx] == 0)
521 return E_PROP_ID_UNSUPPORTED;
523 if(propid < EAXFXSLOT_NONE)
525 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
526 return EAXReverb_Get(prim, idx, propid, pPropData, cbPropData, pcbReturned);
527 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
528 return EAXChorus_Get(prim, idx, propid, pPropData, cbPropData, pcbReturned);
530 ERR("Unexpected null effect propid 0x%08lx\n", propid);
531 return E_PROP_ID_UNSUPPORTED;
533 switch(propid)
535 case EAXFXSLOT_NONE:
536 *pcbReturned = 0;
537 return DS_OK;
539 case EAXFXSLOT_ALLPARAMETERS:
540 GET_PROP(prim->current.fxslot[idx].props, EAXFXSLOTPROPERTIES);
541 case EAXFXSLOT_LOADEFFECT:
542 GET_PROP(prim->current.fxslot[idx].props.guidLoadEffect, GUID);
543 case EAXFXSLOT_VOLUME:
544 GET_PROP(prim->current.fxslot[idx].props.lVolume, long);
545 case EAXFXSLOT_LOCK:
546 GET_PROP(prim->current.fxslot[idx].props.lLock, long);
547 case EAXFXSLOT_FLAGS:
548 GET_PROP(prim->current.fxslot[idx].props.dwFlags, DWORD);
550 FIXME("Unhandled propid: 0x%08lx\n", propid);
551 return E_PROP_ID_UNSUPPORTED;
555 #define APPLY_WET0_PARAMS 1
556 #define APPLY_WET1_PARAMS 2
557 #define APPLY_DRY_PARAMS 4
558 #define APPLY_ALL_PARAMS (APPLY_WET0_PARAMS | APPLY_WET1_PARAMS | APPLY_DRY_PARAMS)
559 #define APPLY_ALLWET_PARAMS (APPLY_WET0_PARAMS | APPLY_WET1_PARAMS)
560 static void ApplyFilterParams(DSBuffer *buf, const EAXSOURCEPROPERTIES *props, int apply)
562 /* The LFRatio properties determine how much the given level applies to low
563 * frequencies as well as high frequencies. Technically, given that the
564 * obstruction/occlusion/exclusion levels are the absolute level applied to
565 * high frequencies (relative to full-scale, according to the EAX 2.0 spec)
566 * while the HF filter gains are relative to the low, the HF gains should
567 * increase as LFRatio increases.
569 * However it seems Creative was either wrong when writing out the spec,
570 * or implemented it incorrectly, as the HF filter still applies in full
571 * regardless of the LFRatio. So to replicate the hardware behavior, we do
572 * the same here.
574 /* The interaction of ratios is pretty wierd. The typical combination of
575 * the two act as a minimal baseline, while the sum minus one is used when
576 * larger. This creates a more linear change with the individual ratios as
577 * Direct/RoomRatio goes beyond 1, but eases down as the two ratios go
578 * toward 0.
580 float dryoccl = maxF(props->flOcclusionLFRatio+props->flOcclusionDirectRatio-1.0f,
581 props->flOcclusionLFRatio*props->flOcclusionDirectRatio) *
582 props->lOcclusion;
583 float dryocclhf = props->lOcclusion*props->flOcclusionDirectRatio;
584 float room_mb = props->lRoom + props->lExclusion*props->flExclusionLFRatio +
585 maxF(props->flOcclusionLFRatio+props->flOcclusionRoomRatio-1.0f,
586 props->flOcclusionLFRatio*props->flOcclusionRoomRatio) * props->lOcclusion;
587 float room_mbhf = props->lRoomHF + props->lExclusion +
588 props->lOcclusion*props->flOcclusionRoomRatio;
589 int i;
591 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
593 const struct Send *send = &buf->deferred.send[i];
594 if((apply&(1<<i)) && buf->filter[1+i])
596 /* Add the main room occlusion and exclusion properties with the
597 * sends', or take the minimum or maximum?
599 float mb = room_mb + send->lExclusion*send->flExclusionLFRatio +
600 maxF(send->flOcclusionLFRatio+send->flOcclusionRoomRatio-1.0f,
601 send->flOcclusionLFRatio*send->flOcclusionRoomRatio)*send->lOcclusion;
602 float mbhf = room_mbhf + send->lExclusion +
603 send->lOcclusion*send->flOcclusionRoomRatio;
605 alFilterf(buf->filter[1+i], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
606 alFilterf(buf->filter[1+i], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
609 /* Take the minimum, maximum, or average of the sends' direct occlusion with the main
610 * property?
612 dryoccl = minF(dryoccl,
613 maxF(send->flOcclusionLFRatio+send->flOcclusionDirectRatio-1.0f,
614 send->flOcclusionLFRatio*send->flOcclusionDirectRatio) * send->lOcclusion
616 dryocclhf = minF(dryocclhf, send->lOcclusion*send->flOcclusionDirectRatio);
618 if((apply&APPLY_DRY_PARAMS) && buf->filter[0])
620 float mb = props->lDirect + props->lObstruction*props->flObstructionLFRatio + dryoccl;
621 float mbhf = props->lDirectHF + props->lObstruction + dryocclhf;
623 alFilterf(buf->filter[0], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
624 alFilterf(buf->filter[0], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
626 checkALError();
629 static EAXOBSTRUCTIONPROPERTIES EAXSourceObstruction(const EAXSOURCEPROPERTIES *props)
631 EAXOBSTRUCTIONPROPERTIES ret;
632 ret.lObstruction = props->lObstruction;
633 ret.flObstructionLFRatio = props->flObstructionLFRatio;
634 return ret;
637 static EAXOCCLUSIONPROPERTIES EAXSourceOcclusion(const EAXSOURCEPROPERTIES *props)
639 EAXOCCLUSIONPROPERTIES ret;
640 ret.lOcclusion = props->lOcclusion;
641 ret.flOcclusionLFRatio = props->flOcclusionLFRatio;
642 ret.flOcclusionRoomRatio = props->flOcclusionRoomRatio;
643 ret.flOcclusionDirectRatio = props->flOcclusionDirectRatio;
644 return ret;
647 static EAXEXCLUSIONPROPERTIES EAXSourceExclusion(const EAXSOURCEPROPERTIES *props)
649 EAXEXCLUSIONPROPERTIES ret;
650 ret.lExclusion = props->lExclusion;
651 ret.flExclusionLFRatio = props->flExclusionLFRatio;
652 return ret;
655 static struct Send *FindCurrentSend(DSBuffer *buf, const GUID *guid)
657 int i;
658 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
660 DWORD target = buf->current.fxslot_targets[i];
661 if((target == FXSLOT_TARGET_0 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0)) ||
662 (target == FXSLOT_TARGET_1 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1)) ||
663 (target == FXSLOT_TARGET_2 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2)) ||
664 (target == FXSLOT_TARGET_3 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3)) ||
665 (target == FXSLOT_TARGET_PRIMARY && IsEqualGUID(guid, &EAX_PrimaryFXSlotID)) ||
666 (target == FXSLOT_TARGET_NULL && IsEqualGUID(guid, &EAX_NULL_GUID)))
667 return &buf->current.send[i];
669 return NULL;
672 static struct Send *FindDeferredSend(DSBuffer *buf, const GUID *guid)
674 int i;
675 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
677 DWORD target = buf->deferred.fxslot_targets[i];
678 if((target == FXSLOT_TARGET_0 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0)) ||
679 (target == FXSLOT_TARGET_1 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1)) ||
680 (target == FXSLOT_TARGET_2 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2)) ||
681 (target == FXSLOT_TARGET_3 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3)) ||
682 (target == FXSLOT_TARGET_PRIMARY && IsEqualGUID(guid, &EAX_PrimaryFXSlotID)) ||
683 (target == FXSLOT_TARGET_NULL && IsEqualGUID(guid, &EAX_NULL_GUID)))
684 return &buf->deferred.send[i];
686 return NULL;
689 HRESULT EAX4Source_Query(DSBuffer *buf, DWORD propid, ULONG *pTypeSupport)
691 if(!HAS_EXTENSION(buf->share, EXT_EFX))
692 return E_PROP_ID_UNSUPPORTED;
694 switch((propid&~EAXSOURCE_PARAMETER_DEFERRED))
696 case EAXSOURCE_NONE:
697 case EAXSOURCE_ALLPARAMETERS:
698 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
699 case EAXSOURCE_OCCLUSIONPARAMETERS:
700 case EAXSOURCE_EXCLUSIONPARAMETERS:
701 case EAXSOURCE_DIRECT:
702 case EAXSOURCE_DIRECTHF:
703 case EAXSOURCE_ROOM:
704 case EAXSOURCE_ROOMHF:
705 case EAXSOURCE_OBSTRUCTION:
706 case EAXSOURCE_OBSTRUCTIONLFRATIO:
707 case EAXSOURCE_OCCLUSION:
708 case EAXSOURCE_OCCLUSIONLFRATIO:
709 case EAXSOURCE_OCCLUSIONROOMRATIO:
710 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
711 case EAXSOURCE_EXCLUSION:
712 case EAXSOURCE_EXCLUSIONLFRATIO:
713 case EAXSOURCE_OUTSIDEVOLUMEHF:
714 case EAXSOURCE_DOPPLERFACTOR:
715 case EAXSOURCE_ROLLOFFFACTOR:
716 case EAXSOURCE_ROOMROLLOFFFACTOR:
717 case EAXSOURCE_AIRABSORPTIONFACTOR:
718 case EAXSOURCE_FLAGS:
719 case EAXSOURCE_SENDPARAMETERS:
720 case EAXSOURCE_ALLSENDPARAMETERS:
721 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
722 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
723 case EAXSOURCE_ACTIVEFXSLOTID:
724 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
725 return DS_OK;
727 FIXME("Unhandled propid: 0x%08lx\n", propid);
728 return E_PROP_ID_UNSUPPORTED;
731 HRESULT EAX4Source_Set(DSBuffer *buf, DWORD propid, void *pPropData, ULONG cbPropData)
733 if(!HAS_EXTENSION(buf->share, EXT_EFX))
734 return E_PROP_ID_UNSUPPORTED;
736 switch(propid)
738 case EAXSOURCE_NONE:
739 return DS_OK;
741 case EAXSOURCE_ALLPARAMETERS:
742 if(cbPropData >= sizeof(EAXSOURCEPROPERTIES))
744 union {
745 const void *v;
746 const EAXSOURCEPROPERTIES *props;
747 } data = { pPropData };
748 TRACE("Parameters:\n\tDirect: %ld\n\tDirect HF: %ld\n\tRoom: %ld\n\tRoom HF: %ld\n\t"
749 "Obstruction: %ld\n\tObstruction LF Ratio: %f\n\tOcclusion: %ld\n\t"
750 "Occlusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
751 "Occlusion Direct Ratio: %f\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n\t"
752 "Outside Volume HF: %ld\n\tDoppler Factor: %f\n\tRolloff Factor: %f\n\t"
753 "Room Rolloff Factor: %f\n\tAir Absorb Factor: %f\n\tFlags: 0x%02lx\n",
754 data.props->lDirect, data.props->lDirectHF, data.props->lRoom, data.props->lRoomHF,
755 data.props->lObstruction, data.props->flObstructionLFRatio, data.props->lOcclusion,
756 data.props->flOcclusionLFRatio, data.props->flOcclusionRoomRatio,
757 data.props->flOcclusionDirectRatio, data.props->lExclusion,
758 data.props->flExclusionLFRatio, data.props->lOutsideVolumeHF,
759 data.props->flDopplerFactor, data.props->flRolloffFactor,
760 data.props->flRoomRolloffFactor, data.props->flAirAbsorptionFactor,
761 data.props->dwFlags
764 buf->deferred.eax = *data.props;
765 ApplyFilterParams(buf, data.props, APPLY_ALL_PARAMS);
767 buf->dirty.bit.dry_filter = 1;
768 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
769 buf->dirty.bit.doppler = 1;
770 buf->dirty.bit.rolloff = 1;
771 buf->dirty.bit.room_rolloff = 1;
772 buf->dirty.bit.cone_outsidevolumehf = 1;
773 buf->dirty.bit.air_absorb = 1;
774 buf->dirty.bit.flags = 1;
775 return DS_OK;
777 return DSERR_INVALIDPARAM;
778 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
779 if(cbPropData >= sizeof(EAXOBSTRUCTIONPROPERTIES))
781 union {
782 const void *v;
783 const EAXOBSTRUCTIONPROPERTIES *props;
784 } data = { pPropData };
785 TRACE("Parameters:\n\tObstruction: %ld\n\tObstruction LF Ratio: %f\n",
786 data.props->lObstruction, data.props->flObstructionLFRatio);
788 buf->deferred.eax.lObstruction = data.props->lObstruction;
789 buf->deferred.eax.flObstructionLFRatio = data.props->flObstructionLFRatio;
790 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
792 buf->dirty.bit.dry_filter = 1;
793 return DS_OK;
795 return DSERR_INVALIDPARAM;
796 case EAXSOURCE_OCCLUSIONPARAMETERS:
797 if(cbPropData >= sizeof(EAXOCCLUSIONPROPERTIES))
799 union {
800 const void *v;
801 const EAXOCCLUSIONPROPERTIES *props;
802 } data = { pPropData };
803 TRACE("Parameters:\n\tOcclusion: %ld\n\tOcclusion LF Ratio: %f\n\t"
804 "Occlusion Room Ratio: %f\n\tOcclusion Direct Ratio: %f\n",
805 data.props->lOcclusion, data.props->flOcclusionLFRatio,
806 data.props->flOcclusionRoomRatio, data.props->flOcclusionDirectRatio
809 buf->deferred.eax.lOcclusion = data.props->lOcclusion;
810 buf->deferred.eax.flOcclusionLFRatio = data.props->flOcclusionLFRatio;
811 buf->deferred.eax.flOcclusionRoomRatio = data.props->flOcclusionRoomRatio;
812 buf->deferred.eax.flOcclusionDirectRatio = data.props->flOcclusionDirectRatio;
813 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
815 buf->dirty.bit.dry_filter = 1;
816 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
817 return DS_OK;
819 return DSERR_INVALIDPARAM;
820 case EAXSOURCE_EXCLUSIONPARAMETERS:
821 if(cbPropData >= sizeof(EAXEXCLUSIONPROPERTIES))
823 union {
824 const void *v;
825 const EAXEXCLUSIONPROPERTIES *props;
826 } data = { pPropData };
827 TRACE("Parameters:\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n",
828 data.props->lExclusion, data.props->flExclusionLFRatio);
830 buf->deferred.eax.lExclusion = data.props->lExclusion;
831 buf->deferred.eax.flExclusionLFRatio = data.props->flExclusionLFRatio;
832 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
834 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
835 return DS_OK;
837 return DSERR_INVALIDPARAM;
839 case EAXSOURCE_DIRECT:
840 if(cbPropData >= sizeof(long))
842 union { const void *v; const long *l; } data = { pPropData };
843 TRACE("Direct: %ld\n", *data.l);
845 buf->deferred.eax.lDirect = *data.l;
846 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
848 buf->dirty.bit.dry_filter = 1;
849 return DS_OK;
851 return DSERR_INVALIDPARAM;
852 case EAXSOURCE_DIRECTHF:
853 if(cbPropData >= sizeof(long))
855 union { const void *v; const long *l; } data = { pPropData };
856 TRACE("Direct HF: %ld\n", *data.l);
858 buf->deferred.eax.lDirectHF = *data.l;
859 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
861 buf->dirty.bit.dry_filter = 1;
862 return DS_OK;
864 return DSERR_INVALIDPARAM;
866 case EAXSOURCE_ROOM:
867 if(cbPropData >= sizeof(long))
869 union { const void *v; const long *l; } data = { pPropData };
870 TRACE("Room: %ld\n", *data.l);
872 buf->deferred.eax.lRoom = *data.l;
873 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
875 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
876 return DS_OK;
878 return DSERR_INVALIDPARAM;
879 case EAXSOURCE_ROOMHF:
880 if(cbPropData >= sizeof(long))
882 union { const void *v; const long *l; } data = { pPropData };
883 TRACE("Room HF: %ld\n", *data.l);
885 buf->deferred.eax.lRoomHF = *data.l;
886 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
888 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
889 return DS_OK;
891 return DSERR_INVALIDPARAM;
893 case EAXSOURCE_OBSTRUCTION:
894 if(cbPropData >= sizeof(long))
896 union { const void *v; const long *l; } data = { pPropData };
897 TRACE("Obstruction: %ld\n", *data.l);
899 buf->deferred.eax.lObstruction = *data.l;
900 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
902 buf->dirty.bit.dry_filter = 1;
903 return DS_OK;
905 return DSERR_INVALIDPARAM;
906 case EAXSOURCE_OBSTRUCTIONLFRATIO:
907 if(cbPropData >= sizeof(float))
909 union { const void *v; const float *fl; } data = { pPropData };
910 TRACE("Obstruction LF Ratio: %f\n", *data.fl);
912 buf->deferred.eax.flObstructionLFRatio = *data.fl;
913 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
915 buf->dirty.bit.dry_filter = 1;
916 return DS_OK;
918 return DSERR_INVALIDPARAM;
920 case EAXSOURCE_OCCLUSION:
921 if(cbPropData >= sizeof(long))
923 union { const void *v; const long *l; } data = { pPropData };
924 TRACE("Occlusion: %ld\n", *data.l);
926 buf->deferred.eax.lOcclusion = *data.l;
927 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
929 buf->dirty.bit.dry_filter = 1;
930 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
931 return DS_OK;
933 return DSERR_INVALIDPARAM;
934 case EAXSOURCE_OCCLUSIONLFRATIO:
935 if(cbPropData >= sizeof(float))
937 union { const void *v; const float *fl; } data = { pPropData };
938 TRACE("Occlusion LF Ratio: %f\n", *data.fl);
940 buf->deferred.eax.flOcclusionLFRatio = *data.fl;
941 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
943 buf->dirty.bit.dry_filter = 1;
944 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
945 return DS_OK;
947 return DSERR_INVALIDPARAM;
948 case EAXSOURCE_OCCLUSIONROOMRATIO:
949 if(cbPropData >= sizeof(float))
951 union { const void *v; const float *fl; } data = { pPropData };
952 TRACE("Occlusion Room Ratio: %f\n", *data.fl);
954 buf->deferred.eax.flOcclusionRoomRatio = *data.fl;
955 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
957 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
958 return DS_OK;
960 return DSERR_INVALIDPARAM;
961 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
962 if(cbPropData >= sizeof(float))
964 union { const void *v; const float *fl; } data = { pPropData };
965 TRACE("Occlusion Direct Ratio: %f\n", *data.fl);
967 buf->deferred.eax.flOcclusionDirectRatio = *data.fl;
968 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
970 buf->dirty.bit.dry_filter = 1;
971 return DS_OK;
973 return DSERR_INVALIDPARAM;
975 case EAXSOURCE_EXCLUSION:
976 if(cbPropData >= sizeof(long))
978 union { const void *v; const long *l; } data = { pPropData };
979 TRACE("Exclusion: %ld\n", *data.l);
981 buf->deferred.eax.lExclusion = *data.l;
982 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
984 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
985 return DS_OK;
987 return DSERR_INVALIDPARAM;
988 case EAXSOURCE_EXCLUSIONLFRATIO:
989 if(cbPropData >= sizeof(float))
991 union { const void *v; const float *fl; } data = { pPropData };
992 TRACE("Exclusion LF Ratio: %f\n", *data.fl);
994 buf->deferred.eax.flExclusionLFRatio = *data.fl;
995 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
997 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
998 return DS_OK;
1000 return DSERR_INVALIDPARAM;
1002 case EAXSOURCE_OUTSIDEVOLUMEHF:
1003 if(cbPropData >= sizeof(long))
1005 union { const void *v; const long *l; } data = { pPropData };
1006 TRACE("Outisde Volume HF: %ld\n", *data.l);
1008 buf->deferred.eax.lOutsideVolumeHF = *data.l;
1010 buf->dirty.bit.cone_outsidevolumehf = 1;
1011 return DS_OK;
1013 return DSERR_INVALIDPARAM;
1015 case EAXSOURCE_DOPPLERFACTOR:
1016 if(cbPropData >= sizeof(float))
1018 union { const void *v; const float *fl; } data = { pPropData };
1019 TRACE("Doppler Factor: %f\n", *data.fl);
1021 buf->deferred.eax.flDopplerFactor = *data.fl;
1023 buf->dirty.bit.doppler = 1;
1024 return DS_OK;
1026 return DSERR_INVALIDPARAM;
1028 case EAXSOURCE_ROLLOFFFACTOR:
1029 if(cbPropData >= sizeof(float))
1031 union { const void *v; const float *fl; } data = { pPropData };
1032 TRACE("Rolloff Factor: %f\n", *data.fl);
1034 buf->deferred.eax.flRolloffFactor = *data.fl;
1036 buf->dirty.bit.rolloff = 1;
1037 return DS_OK;
1039 return DSERR_INVALIDPARAM;
1041 case EAXSOURCE_ROOMROLLOFFFACTOR:
1042 if(cbPropData >= sizeof(float))
1044 union { const void *v; const float *fl; } data = { pPropData };
1045 TRACE("Room Rolloff Factor: %f\n", *data.fl);
1047 buf->deferred.eax.flRoomRolloffFactor = *data.fl;
1049 buf->dirty.bit.room_rolloff = 1;
1050 return DS_OK;
1052 return DSERR_INVALIDPARAM;
1054 case EAXSOURCE_AIRABSORPTIONFACTOR:
1055 if(cbPropData >= sizeof(float))
1057 union { const void *v; const float *fl; } data = { pPropData };
1058 TRACE("Air Absorb Factor: %f\n", *data.fl);
1060 buf->deferred.eax.flAirAbsorptionFactor = *data.fl;
1062 buf->dirty.bit.air_absorb = 1;
1063 return DS_OK;
1065 return DSERR_INVALIDPARAM;
1067 case EAXSOURCE_FLAGS:
1068 if(cbPropData >= sizeof(DWORD))
1070 union { const void *v; const DWORD *dw; } data = { pPropData };
1071 TRACE("Flags: 0x%lx\n", *data.dw);
1073 buf->deferred.eax.dwFlags = *data.dw;
1075 buf->dirty.bit.flags = 1;
1076 return DS_OK;
1078 return DSERR_INVALIDPARAM;
1080 case EAXSOURCE_SENDPARAMETERS:
1081 if(cbPropData >= sizeof(EAXSOURCESENDPROPERTIES))
1083 union { const void *v; const EAXSOURCESENDPROPERTIES *send; } data = { pPropData };
1084 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1085 LONG count = cbPropData / sizeof(EAXSOURCESENDPROPERTIES);
1086 LONG wetmask=0, i;
1088 if(count > buf->share->num_sends)
1090 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1091 return DSERR_INVALIDPARAM;
1094 for(i = 0;i < count;++i)
1096 TRACE("Send parameters:\n\tReceiving: %s\n\tSend: %ld\n\tSend HF: %ld\n",
1097 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1098 data.send[i].lSend, data.send[i].lSendHF
1100 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1101 if(!srcsend[i])
1103 ERR("Failed to find active FXSlot target: %s\n",
1104 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1105 return DSERR_INVALIDPARAM;
1107 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1110 for(i = 0;i < count;++i)
1112 srcsend[i]->lSend = data.send[i].lSend;
1113 srcsend[i]->lSendHF = data.send[i].lSendHF;
1115 ApplyFilterParams(buf, &buf->deferred.eax, wetmask);
1117 buf->dirty.bit.send_filter |= wetmask;
1118 return DS_OK;
1120 return DSERR_INVALIDPARAM;
1121 case EAXSOURCE_ALLSENDPARAMETERS:
1122 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1124 union { const void *v; const EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1125 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1126 LONG count = cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES);
1127 LONG wetmask=0, i;
1129 if(count > buf->share->num_sends)
1131 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1132 return DSERR_INVALIDPARAM;
1135 for(i = 0;i < count;++i)
1137 TRACE("All send parameters:\n\tReceiving: %s\n\tSend: %ld\n\tSend HF: %ld\n\t"
1138 "Occlusion: %ld\n\tOcclusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
1139 "Occlusion Direct Ratio: %f\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n",
1140 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1141 data.send[i].lSend, data.send[i].lSendHF, data.send[i].lOcclusion,
1142 data.send[i].flOcclusionLFRatio, data.send[i].flOcclusionRoomRatio,
1143 data.send[i].flOcclusionDirectRatio, data.send[i].lExclusion,
1144 data.send[i].flExclusionLFRatio
1146 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1147 if(!srcsend[i])
1149 ERR("Failed to find active FXSlot target: %s\n",
1150 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1151 return DSERR_INVALIDPARAM;
1153 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1156 for(i = 0;i < count;++i)
1158 srcsend[i]->lSend = data.send[i].lSend;
1159 srcsend[i]->lSendHF = data.send[i].lSendHF;
1160 srcsend[i]->lOcclusion = data.send[i].lOcclusion;
1161 srcsend[i]->flOcclusionLFRatio = data.send[i].flOcclusionLFRatio;
1162 srcsend[i]->flOcclusionRoomRatio = data.send[i].flOcclusionRoomRatio;
1163 srcsend[i]->flOcclusionDirectRatio = data.send[i].flOcclusionDirectRatio;
1164 srcsend[i]->lExclusion = data.send[i].lExclusion;
1165 srcsend[i]->flExclusionLFRatio = data.send[i].flExclusionLFRatio;
1167 ApplyFilterParams(buf, &buf->deferred.eax, wetmask|APPLY_DRY_PARAMS);
1169 buf->dirty.bit.dry_filter = 1;
1170 buf->dirty.bit.send_filter |= wetmask;
1171 return DS_OK;
1173 return DSERR_INVALIDPARAM;
1174 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1175 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1177 union { const void *v; const EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1178 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1179 LONG count = cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES);
1180 LONG wetmask=0, i;
1182 if(count > buf->share->num_sends)
1184 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1185 return DSERR_INVALIDPARAM;
1188 for(i = 0;i < count;++i)
1190 TRACE("Occlusion send parameters:\n\tReceiving: %s\n\tOcclusion: %ld\n\t"
1191 "Occlusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
1192 "Occlusion Direct Ratio: %f\n",
1193 debug_fxslot(&data.send[i].guidReceivingFXSlotID), data.send[i].lOcclusion,
1194 data.send[i].flOcclusionLFRatio, data.send[i].flOcclusionRoomRatio,
1195 data.send[i].flOcclusionDirectRatio
1197 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1198 if(!srcsend[i])
1200 ERR("Failed to find active FXSlot target: %s\n",
1201 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1202 return DSERR_INVALIDPARAM;
1204 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1207 for(i = 0;i < count;++i)
1209 srcsend[i]->lOcclusion = data.send[i].lOcclusion;
1210 srcsend[i]->flOcclusionLFRatio = data.send[i].flOcclusionLFRatio;
1211 srcsend[i]->flOcclusionRoomRatio = data.send[i].flOcclusionRoomRatio;
1212 srcsend[i]->flOcclusionDirectRatio = data.send[i].flOcclusionDirectRatio;
1214 ApplyFilterParams(buf, &buf->deferred.eax, wetmask|APPLY_DRY_PARAMS);
1216 buf->dirty.bit.dry_filter = 1;
1217 buf->dirty.bit.send_filter |= wetmask;
1218 return DS_OK;
1220 return DSERR_INVALIDPARAM;
1221 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1222 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1224 union { const void *v; const EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1225 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1226 LONG count = cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES);
1227 LONG wetmask=0, i;
1229 if(count > buf->share->num_sends)
1231 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1232 return DSERR_INVALIDPARAM;
1235 for(i = 0;i < count;++i)
1237 TRACE("Exclusion send parameters:\n\tReceiving: %s\n\tExclusion: %ld\n\t"
1238 "Exclusion LF Ratio: %f\n",
1239 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1240 data.send[i].lExclusion, data.send[i].flExclusionLFRatio
1242 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1243 if(!srcsend[i])
1245 ERR("Failed to find active FXSlot target: %s\n",
1246 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1247 return DSERR_INVALIDPARAM;
1249 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1252 for(i = 0;i < count;++i)
1254 srcsend[i]->lExclusion = data.send[i].lExclusion;
1255 srcsend[i]->flExclusionLFRatio = data.send[i].flExclusionLFRatio;
1257 ApplyFilterParams(buf, &buf->deferred.eax, wetmask);
1259 buf->dirty.bit.send_filter |= wetmask;
1260 return DS_OK;
1262 return DSERR_INVALIDPARAM;
1264 case EAXSOURCE_ACTIVEFXSLOTID:
1265 if(cbPropData && (cbPropData%sizeof(GUID)) == 0)
1267 union { const void *v; const GUID *guid; } data = { pPropData };
1268 DWORD targets[EAX_MAX_ACTIVE_FXSLOTS];
1269 LONG count = cbPropData / sizeof(GUID);
1270 LONG i;
1272 if(count > buf->share->num_sends)
1274 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1275 return DSERR_INVALIDPARAM;
1278 for(i = 0;i < count;i++)
1280 TRACE("Active FXSlot %ld: %s\n", i, debug_fxslot(&data.guid[i]));
1282 targets[i] = FXSLOT_TARGET_NULL;
1283 if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot0))
1284 targets[i] = FXSLOT_TARGET_0;
1285 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot1))
1286 targets[i] = FXSLOT_TARGET_1;
1287 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot2))
1288 targets[i] = FXSLOT_TARGET_2;
1289 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot3))
1290 targets[i] = FXSLOT_TARGET_3;
1291 else if(IsEqualGUID(&data.guid[i], &EAX_PrimaryFXSlotID))
1292 targets[i] = FXSLOT_TARGET_PRIMARY;
1293 if(targets[i] == FXSLOT_TARGET_NULL && !IsEqualGUID(&data.guid[i], &EAX_NULL_GUID))
1295 ERR("Invalid FXSlot: %s\n", debug_fxslot(&data.guid[i]));
1296 return DSERR_INVALIDPARAM;
1300 for(i = 0;i < count;++i)
1301 buf->deferred.fxslot_targets[i] = targets[i];
1302 buf->dirty.bit.send_filter |= (1<<count) - 1;
1303 return DS_OK;
1305 return DSERR_INVALIDPARAM;
1307 FIXME("Unhandled propid: 0x%08lx\n", propid);
1308 return E_PROP_ID_UNSUPPORTED;
1311 HRESULT EAX4Source_Get(DSBuffer *buf, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
1313 if(!HAS_EXTENSION(buf->share, EXT_EFX))
1314 return E_PROP_ID_UNSUPPORTED;
1316 switch(propid)
1318 case EAXSOURCE_NONE:
1319 *pcbReturned = 0;
1320 return DS_OK;
1322 case EAXSOURCE_ALLPARAMETERS:
1323 GET_PROP(buf->current.eax, EAXSOURCEPROPERTIES);
1325 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
1326 GET_PROP(EAXSourceObstruction(&buf->current.eax), EAXOBSTRUCTIONPROPERTIES);
1327 case EAXSOURCE_OCCLUSIONPARAMETERS:
1328 GET_PROP(EAXSourceOcclusion(&buf->current.eax), EAXOCCLUSIONPROPERTIES);
1329 case EAXSOURCE_EXCLUSIONPARAMETERS:
1330 GET_PROP(EAXSourceExclusion(&buf->current.eax), EAXEXCLUSIONPROPERTIES);
1332 case EAXSOURCE_DIRECT:
1333 GET_PROP(buf->current.eax.lDirect, long);
1334 case EAXSOURCE_DIRECTHF:
1335 GET_PROP(buf->current.eax.lDirectHF, long);
1337 case EAXSOURCE_ROOM:
1338 GET_PROP(buf->current.eax.lRoom, long);
1339 case EAXSOURCE_ROOMHF:
1340 GET_PROP(buf->current.eax.lRoomHF, long);
1342 case EAXSOURCE_OBSTRUCTION:
1343 GET_PROP(buf->current.eax.lObstruction, long);
1344 case EAXSOURCE_OBSTRUCTIONLFRATIO:
1345 GET_PROP(buf->current.eax.flObstructionLFRatio, float);
1347 case EAXSOURCE_OCCLUSION:
1348 GET_PROP(buf->current.eax.lOcclusion, long);
1349 case EAXSOURCE_OCCLUSIONLFRATIO:
1350 GET_PROP(buf->current.eax.flOcclusionLFRatio, float);
1351 case EAXSOURCE_OCCLUSIONROOMRATIO:
1352 GET_PROP(buf->current.eax.flOcclusionRoomRatio, float);
1353 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
1354 GET_PROP(buf->current.eax.flOcclusionDirectRatio, float);
1356 case EAXSOURCE_EXCLUSION:
1357 GET_PROP(buf->current.eax.lExclusion, long);
1358 case EAXSOURCE_EXCLUSIONLFRATIO:
1359 GET_PROP(buf->current.eax.flExclusionLFRatio, float);
1361 case EAXSOURCE_OUTSIDEVOLUMEHF:
1362 GET_PROP(buf->current.eax.lOutsideVolumeHF, long);
1364 case EAXSOURCE_DOPPLERFACTOR:
1365 GET_PROP(buf->current.eax.flDopplerFactor, float);
1367 case EAXSOURCE_ROLLOFFFACTOR:
1368 GET_PROP(buf->current.eax.flRolloffFactor, float);
1369 case EAXSOURCE_ROOMROLLOFFFACTOR:
1370 GET_PROP(buf->current.eax.flRoomRolloffFactor, float);
1372 case EAXSOURCE_AIRABSORPTIONFACTOR:
1373 GET_PROP(buf->current.eax.flAirAbsorptionFactor, float);
1375 case EAXSOURCE_FLAGS:
1376 GET_PROP(buf->current.eax.dwFlags, DWORD);
1378 case EAXSOURCE_SENDPARAMETERS:
1379 if(cbPropData >= sizeof(EAXSOURCESENDPROPERTIES))
1381 union { void *v; EAXSOURCESENDPROPERTIES *send; } data = { pPropData };
1382 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1383 LONG count = minI(cbPropData / sizeof(EAXSOURCESENDPROPERTIES),
1384 EAX_MAX_ACTIVE_FXSLOTS);
1385 LONG i;
1387 for(i = 0;i < count;++i)
1389 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1390 if(!srcsend[i])
1392 ERR("Failed to find active FXSlot target: %s\n",
1393 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1394 return DSERR_INVALIDPARAM;
1398 for(i = 0;i < count;++i)
1400 data.send[i].lSend = srcsend[i]->lSend;
1401 data.send[i].lSendHF = srcsend[i]->lSendHF;
1403 *pcbReturned = sizeof(EAXSOURCESENDPROPERTIES)*count;
1404 return DS_OK;
1406 return DSERR_INVALIDPARAM;
1408 case EAXSOURCE_ALLSENDPARAMETERS:
1409 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1411 union { void *v; EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1412 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1413 LONG count = minI(cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES),
1414 EAX_MAX_ACTIVE_FXSLOTS);
1415 LONG i;
1417 for(i = 0;i < count;++i)
1419 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1420 if(!srcsend[i])
1422 ERR("Failed to find active FXSlot target: %s\n",
1423 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1424 return DSERR_INVALIDPARAM;
1428 for(i = 0;i < count;++i)
1430 data.send[i].lSend = srcsend[i]->lSend;
1431 data.send[i].lSendHF = srcsend[i]->lSendHF;
1432 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1433 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1434 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1435 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1436 data.send[i].lExclusion = srcsend[i]->lExclusion;
1437 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1439 *pcbReturned = sizeof(EAXSOURCEALLSENDPROPERTIES)*count;
1440 return DS_OK;
1442 return DSERR_INVALIDPARAM;
1443 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1444 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1446 union { void *v; EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1447 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1448 LONG count = minI(cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES),
1449 EAX_MAX_ACTIVE_FXSLOTS);
1450 LONG i;
1452 for(i = 0;i < count;++i)
1454 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1455 if(!srcsend[i])
1457 ERR("Failed to find active FXSlot target: %s\n",
1458 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1459 return DSERR_INVALIDPARAM;
1463 for(i = 0;i < count;++i)
1465 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1466 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1467 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1468 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1470 *pcbReturned = sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES)*count;
1471 return DS_OK;
1473 return DSERR_INVALIDPARAM;
1474 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1475 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1477 union { void *v; EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1478 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1479 LONG count = minI(cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES),
1480 EAX_MAX_ACTIVE_FXSLOTS);
1481 LONG i;
1483 for(i = 0;i < count;++i)
1485 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1486 if(!srcsend[i])
1488 ERR("Failed to find active FXSlot target: %s\n",
1489 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1490 return DSERR_INVALIDPARAM;
1494 for(i = 0;i < count;++i)
1496 data.send[i].lExclusion = srcsend[i]->lExclusion;
1497 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1499 *pcbReturned = sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES)*count;
1500 return DS_OK;
1502 return DSERR_INVALIDPARAM;
1504 case EAXSOURCE_ACTIVEFXSLOTID:
1505 if(cbPropData >= sizeof(GUID))
1507 union { void *v; GUID *guid; } data = { pPropData };
1508 LONG count = minI(cbPropData / sizeof(GUID), EAX_MAX_ACTIVE_FXSLOTS);
1509 LONG i;
1511 for(i = 0;i < count;++i)
1513 if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_0)
1514 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot0;
1515 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_1)
1516 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot1;
1517 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_2)
1518 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot2;
1519 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_3)
1520 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot3;
1521 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_PRIMARY)
1522 data.guid[i] = EAX_PrimaryFXSlotID;
1523 else /*if(buf->current.fxslot_targets[i] >= FXSLOT_TARGET_NULL)*/
1524 data.guid[i] = EAX_NULL_GUID;
1527 *pcbReturned = sizeof(GUID)*count;
1528 return DS_OK;
1530 return DSERR_INVALIDPARAM;
1532 FIXME("Unhandled propid: 0x%08lx\n", propid);
1533 return E_PROP_ID_UNSUPPORTED;