Don't accumulate the sends' direct occlusion levels
[dsound-openal.git] / eax4.c
blob185810309de32fa51598c0191465ca67c4a25b15
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 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
77 return DS_OK;
78 case EAXCONTEXT_LASTERROR:
79 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
80 return DS_OK;
82 FIXME("Unhandled propid: 0x%08lx\n", propid);
83 return E_PROP_ID_UNSUPPORTED;
86 HRESULT EAX4Context_Set(DSPrimary *prim, DWORD propid, void *pPropData, ULONG cbPropData)
88 if(!HAS_EXTENSION(prim->share, EXT_EFX))
89 return E_PROP_ID_UNSUPPORTED;
91 switch(propid)
93 case EAXCONTEXT_NONE: /* not setting any property, just applying */
94 return DS_OK;
96 case EAXCONTEXT_ALLPARAMETERS:
97 if(cbPropData >= sizeof(EAXCONTEXTPROPERTIES))
99 union { void *v; const EAXCONTEXTPROPERTIES *props; } data = { pPropData };
100 ALuint prim_slot;
101 TRACE("Parameters:\n\tPrimary FXSlot: %s\n\tDistance Factor: %f\n\t"
102 "Air Absorption: %f\n\tHF Reference: %f\n",
103 debug_fxslot(&data.props->guidPrimaryFXSlotID), data.props->flDistanceFactor,
104 data.props->flAirAbsorptionHF, data.props->flHFReference
107 prim_slot = 0;
108 if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot0))
109 prim_slot = prim->auxslot[0];
110 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot1))
111 prim_slot = prim->auxslot[1];
112 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot2))
113 prim_slot = prim->auxslot[2];
114 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot3))
115 prim_slot = prim->auxslot[3];
116 if(prim_slot == 0 && !IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAX_NULL_GUID))
118 ERR("Unexpected primary FXSlot: %s\n",
119 debug_fxslot(&data.props->guidPrimaryFXSlotID));
120 return DSERR_INVALIDPARAM;
122 if(!(data.props->flDistanceFactor >= DS3D_MINDISTANCEFACTOR &&
123 data.props->flDistanceFactor <= DS3D_MAXDISTANCEFACTOR))
125 ERR("Unexpected distance factor: %f\n", data.props->flDistanceFactor);
126 return DSERR_INVALIDPARAM;
128 if(!(data.props->flAirAbsorptionHF <= 0.0f && data.props->flAirAbsorptionHF >= -100.0f))
130 ERR("Unexpected air absorption: %f\n", data.props->flAirAbsorptionHF);
131 return DSERR_INVALIDPARAM;
133 if(!(data.props->flHFReference >= 1000.0f && data.props->flHFReference <= 20000.0f))
135 ERR("Unexpected HF reference: %f\n", data.props->flAirAbsorptionHF);
136 return DSERR_INVALIDPARAM;
139 prim->deferred.ctx = *data.props;
140 prim->primary_slot = prim_slot;
142 prim->dirty.bit.prim_slotid = 1;
143 prim->dirty.bit.distancefactor2 = 1;
144 prim->dirty.bit.air_absorbhf = 1;
145 prim->dirty.bit.hfreference = 1;
146 return DS_OK;
148 return DSERR_INVALIDPARAM;
150 case EAXCONTEXT_PRIMARYFXSLOTID:
151 if(cbPropData >= sizeof(GUID))
153 union { void *v; const GUID *guid; } data = { pPropData };
154 ALuint prim_slot;
155 TRACE("Primary FXSlot: %s\n", debug_fxslot(data.guid));
157 prim_slot = 0;
158 if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot0))
159 prim_slot = prim->auxslot[0];
160 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot1))
161 prim_slot = prim->auxslot[1];
162 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot2))
163 prim_slot = prim->auxslot[2];
164 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot3))
165 prim_slot = prim->auxslot[3];
166 if(prim_slot == 0 && !IsEqualGUID(data.guid, &EAX_NULL_GUID))
168 ERR("Unexpected primary FXSlot: %s\n", debug_fxslot(data.guid));
169 return DSERR_INVALIDPARAM;
172 prim->deferred.ctx.guidPrimaryFXSlotID = *data.guid;
173 prim->primary_slot = prim_slot;
175 prim->dirty.bit.prim_slotid = 1;
176 return DS_OK;
178 return DSERR_INVALIDPARAM;
180 case EAXCONTEXT_DISTANCEFACTOR:
181 if(cbPropData >= sizeof(float))
183 union { void *v; const float *fl; } data = { pPropData };
184 TRACE("Distance Factor: %f\n", *data.fl);
186 if(!(*data.fl >= DS3D_MINDISTANCEFACTOR && *data.fl <= DS3D_MAXDISTANCEFACTOR))
188 ERR("Unexpected distance factor: %f\n", *data.fl);
189 return DSERR_INVALIDPARAM;
192 prim->deferred.ctx.flDistanceFactor = *data.fl;
194 prim->dirty.bit.distancefactor2 = 1;
195 return DS_OK;
197 return DSERR_INVALIDPARAM;
199 case EAXCONTEXT_AIRABSORPTIONHF:
200 if(cbPropData >= sizeof(float))
202 union { void *v; const float *fl; } data = { pPropData };
203 TRACE("Air Absorption: %f\n", *data.fl);
205 if(!(*data.fl <= 0.0f && *data.fl >= -100.0f))
207 ERR("Unexpected air absorption: %f\n", *data.fl);
208 return DSERR_INVALIDPARAM;
211 prim->deferred.ctx.flAirAbsorptionHF = *data.fl;
213 prim->dirty.bit.air_absorbhf = 1;
214 return DS_OK;
216 return DSERR_INVALIDPARAM;
218 case EAXCONTEXT_HFREFERENCE:
219 if(cbPropData >= sizeof(float))
221 union { void *v; const float *fl; } data = { pPropData };
222 TRACE("HF Reference: %f\n", *data.fl);
224 if(!(*data.fl >= 1000.0f && *data.fl <= 20000.0f))
226 ERR("Unexpected HF reference: %f\n", *data.fl);
227 return DSERR_INVALIDPARAM;
230 prim->deferred.ctx.flHFReference = *data.fl;
232 prim->dirty.bit.hfreference = 1;
233 return DS_OK;
235 return DSERR_INVALIDPARAM;
237 FIXME("Unhandled propid: 0x%08lx\n", propid);
238 return E_PROP_ID_UNSUPPORTED;
241 #define GET_PROP(src, T) do { \
242 if(cbPropData >= sizeof(T)) \
244 union { void *v; T *props; } data = { pPropData }; \
245 *data.props = src; \
246 *pcbReturned = sizeof(T); \
247 return DS_OK; \
249 return DSERR_INVALIDPARAM; \
250 } while(0)
252 HRESULT EAX4Context_Get(DSPrimary *prim, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
254 if(!HAS_EXTENSION(prim->share, EXT_EFX))
255 return E_PROP_ID_UNSUPPORTED;
257 switch(propid)
259 case EAXCONTEXT_NONE:
260 *pcbReturned = 0;
261 return DS_OK;
263 case EAXCONTEXT_ALLPARAMETERS:
264 GET_PROP(prim->current.ctx, EAXCONTEXTPROPERTIES);
265 case EAXCONTEXT_PRIMARYFXSLOTID:
266 GET_PROP(prim->current.ctx.guidPrimaryFXSlotID, GUID);
267 case EAXCONTEXT_DISTANCEFACTOR:
268 GET_PROP(prim->current.ctx.flDistanceFactor, float);
269 case EAXCONTEXT_AIRABSORPTIONHF:
270 GET_PROP(prim->current.ctx.flAirAbsorptionHF, float);
271 case EAXCONTEXT_HFREFERENCE:
272 GET_PROP(prim->current.ctx.flHFReference, float);
274 case EAXCONTEXT_LASTERROR:
275 GET_PROP(InterlockedExchange(&prim->eax_error, EAX_OK), long);
277 FIXME("Unhandled propid: 0x%08lx\n", propid);
278 return E_PROP_ID_UNSUPPORTED;
282 HRESULT EAX4Slot_Query(DSPrimary *prim, LONG idx, DWORD propid, ULONG *pTypeSupport)
284 if(prim->auxslot[idx] == 0)
285 return E_PROP_ID_UNSUPPORTED;
287 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) < EAXFXSLOT_NONE)
289 if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
291 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) <= EAXREVERB_FLAGS)
293 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
294 return DS_OK;
296 FIXME("Unhandled reverb propid: 0x%08lx\n", propid);
298 else if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
300 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) <= EAXCHORUS_DELAY)
302 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
303 return DS_OK;
305 FIXME("Unhandled chorus propid: 0x%08lx\n", propid);
307 else /*if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_NULL)*/
309 FIXME("Unhandled null effect propid: 0x%08lx\n", propid);
311 return DSERR_INVALIDPARAM;
313 switch((propid&~EAXFXSLOT_PARAMETER_DEFERRED))
315 case EAXFXSLOT_NONE:
316 case EAXFXSLOT_ALLPARAMETERS:
317 case EAXFXSLOT_LOADEFFECT:
318 case EAXFXSLOT_VOLUME:
319 case EAXFXSLOT_LOCK:
320 case EAXFXSLOT_FLAGS:
321 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
322 return DS_OK;
324 FIXME("Unhandled propid: 0x%08lx\n", propid);
325 return E_PROP_ID_UNSUPPORTED;
329 HRESULT EAX4Slot_Set(DSPrimary *prim, LONG idx, DWORD propid, void *pPropData, ULONG cbPropData)
331 if(prim->auxslot[idx] == 0)
332 return E_PROP_ID_UNSUPPORTED;
334 if(propid < EAXFXSLOT_NONE)
336 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
337 return EAXReverb_Set(prim, idx, propid, pPropData, cbPropData);
338 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
339 return EAXChorus_Set(prim, idx, propid, pPropData, cbPropData);
341 ERR("Unexpected null effect propid 0x%08lx\n", propid);
342 return E_PROP_ID_UNSUPPORTED;
344 switch(propid)
346 case EAXFXSLOT_NONE: /* not setting any property, just applying */
347 return DS_OK;
349 case EAXFXSLOT_ALLPARAMETERS:
350 if(cbPropData >= sizeof(EAXFXSLOTPROPERTIES))
352 union { const void *v; const EAXFXSLOTPROPERTIES *props; } data = { pPropData };
353 DWORD effect_type;
354 TRACE("Parameters:\n\tLoad Effect: %s\n\tVolume: %ld\n\tLock: %ld\n\tFlags: 0x%lx\n",
355 debug_fxguid(&data.props->guidLoadEffect), data.props->lVolume, data.props->lLock,
356 data.props->dwFlags
359 effect_type = FXSLOT_EFFECT_NULL;
360 if(IsEqualGUID(&data.props->guidLoadEffect, &EAX_REVERB_EFFECT))
361 effect_type = FXSLOT_EFFECT_REVERB;
362 else if(IsEqualGUID(&data.props->guidLoadEffect, &EAX_CHORUS_EFFECT))
363 effect_type = FXSLOT_EFFECT_CHORUS;
364 else if(!IsEqualGUID(&data.props->guidLoadEffect, &EAX_NULL_GUID))
366 ERR("Unhandled effect: %s\n", debug_fxguid(&data.props->guidLoadEffect));
367 return DSERR_INVALIDPARAM;
370 if(data.props->lLock == EAXFXSLOT_LOCKED &&
371 prim->deferred.fxslot[idx].props.lLock == EAXFXSLOT_LOCKED &&
372 prim->deferred.fxslot[idx].effect_type != effect_type)
374 ERR("Attempting to change effect type for locked FXSlot\n");
375 return DSERR_INVALIDCALL;
378 if(prim->deferred.fxslot[idx].effect_type != effect_type)
380 alGetError();
381 alEffecti(prim->effect[idx], AL_EFFECT_TYPE,
382 (effect_type == FXSLOT_EFFECT_REVERB) ? AL_EFFECT_EAXREVERB :
383 (effect_type == FXSLOT_EFFECT_CHORUS) ? AL_EFFECT_CHORUS :
384 AL_EFFECT_NULL
386 if(alGetError() != AL_NO_ERROR)
388 ERR("Failed to set effect type %lu\n", effect_type);
389 return DSERR_INVALIDPARAM;
392 prim->deferred.fxslot[idx].effect_type = effect_type;
393 memset(&prim->deferred.fxslot[idx].fx, 0, sizeof(prim->deferred.fxslot[idx].fx));
394 if(effect_type == FXSLOT_EFFECT_REVERB)
395 prim->deferred.fxslot[idx].fx.reverb = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
396 else if(effect_type == FXSLOT_EFFECT_CHORUS)
398 const EAXCHORUSPROPERTIES chorus_def = CHORUS_PRESET_DEFAULT;
399 prim->deferred.fxslot[idx].fx.chorus = chorus_def;
402 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_EFFECT_BIT);
404 prim->deferred.fxslot[idx].props = *data.props;
406 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_VOL_BIT);
407 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_LOCK_BIT);
408 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_FLAGS_BIT);
409 return DS_OK;
411 return DSERR_INVALIDPARAM;
413 case EAXFXSLOT_LOADEFFECT:
414 if(cbPropData >= sizeof(GUID))
416 union { const void *v; const GUID *guid; } data = { pPropData };
417 DWORD effect_type;
418 TRACE("Load Effect: %s\n", debug_fxguid(data.guid));
420 effect_type = FXSLOT_EFFECT_NULL;
421 if(IsEqualGUID(data.guid, &EAX_REVERB_EFFECT))
422 effect_type = FXSLOT_EFFECT_REVERB;
423 else if(IsEqualGUID(data.guid, &EAX_CHORUS_EFFECT))
424 effect_type = FXSLOT_EFFECT_CHORUS;
425 else if(!IsEqualGUID(data.guid, &EAX_NULL_GUID))
427 ERR("Unhandled effect: %s\n", debug_fxguid(data.guid));
428 return DSERR_INVALIDPARAM;
431 if(prim->deferred.fxslot[idx].props.lLock == EAXFXSLOT_LOCKED)
433 ERR("Attempting to change effect type for locked FXSlot\n");
434 return DSERR_INVALIDCALL;
437 alGetError();
438 alEffecti(prim->effect[idx], AL_EFFECT_TYPE,
439 (effect_type == FXSLOT_EFFECT_REVERB) ? AL_EFFECT_EAXREVERB :
440 (effect_type == FXSLOT_EFFECT_CHORUS) ? AL_EFFECT_CHORUS :
441 AL_EFFECT_NULL
443 if(alGetError() != AL_NO_ERROR)
445 ERR("Failed to set effect type %lu\n", effect_type);
446 return DSERR_INVALIDPARAM;
449 prim->deferred.fxslot[idx].effect_type = effect_type;
450 memset(&prim->deferred.fxslot[idx].fx, 0, sizeof(prim->deferred.fxslot[idx].fx));
451 if(effect_type == FXSLOT_EFFECT_REVERB)
452 prim->deferred.fxslot[idx].fx.reverb = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
453 else if(effect_type == FXSLOT_EFFECT_CHORUS)
455 const EAXCHORUSPROPERTIES chorus_def = CHORUS_PRESET_DEFAULT;
456 prim->deferred.fxslot[idx].fx.chorus = chorus_def;
458 prim->deferred.fxslot[idx].props.guidLoadEffect = *data.guid;
460 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_EFFECT_BIT);
461 return DS_OK;
463 return DSERR_INVALIDPARAM;
465 case EAXFXSLOT_VOLUME:
466 if(cbPropData >= sizeof(long))
468 union { const void *v; const long *l; } data = { pPropData };
469 TRACE("Volume: %ld\n", *data.l);
471 prim->deferred.fxslot[idx].props.lVolume = *data.l;
473 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_VOL_BIT);
474 return DS_OK;
476 return DSERR_INVALIDPARAM;
478 case EAXFXSLOT_LOCK:
479 if(cbPropData >= sizeof(long))
481 union { const void *v; const long *l; } data = { pPropData };
482 TRACE("Lock: %ld\n", *data.l);
484 prim->deferred.fxslot[idx].props.lLock = *data.l;
486 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_LOCK_BIT);
487 return DS_OK;
489 return DSERR_INVALIDPARAM;
491 case EAXFXSLOT_FLAGS:
492 if(cbPropData >= sizeof(DWORD))
494 union { const void *v; const DWORD *dw; } data = { pPropData };
495 TRACE("Flags: 0x%lx\n", *data.dw);
497 prim->deferred.fxslot[idx].props.dwFlags = *data.dw;
499 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_FLAGS_BIT);
500 return DS_OK;
502 return DSERR_INVALIDPARAM;
504 FIXME("Unhandled propid: 0x%08lx\n", propid);
505 return E_PROP_ID_UNSUPPORTED;
508 HRESULT EAX4Slot_Get(DSPrimary *prim, LONG idx, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
510 if(prim->auxslot[idx] == 0)
511 return E_PROP_ID_UNSUPPORTED;
513 if(propid < EAXFXSLOT_NONE)
515 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
516 return EAXReverb_Get(prim, idx, propid, pPropData, cbPropData, pcbReturned);
517 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
518 return EAXChorus_Get(prim, idx, propid, pPropData, cbPropData, pcbReturned);
520 ERR("Unexpected null effect propid 0x%08lx\n", propid);
521 return E_PROP_ID_UNSUPPORTED;
523 switch(propid)
525 case EAXFXSLOT_NONE:
526 *pcbReturned = 0;
527 return DS_OK;
529 case EAXFXSLOT_ALLPARAMETERS:
530 GET_PROP(prim->current.fxslot[idx].props, EAXFXSLOTPROPERTIES);
531 case EAXFXSLOT_LOADEFFECT:
532 GET_PROP(prim->current.fxslot[idx].props.guidLoadEffect, GUID);
533 case EAXFXSLOT_VOLUME:
534 GET_PROP(prim->current.fxslot[idx].props.lVolume, long);
535 case EAXFXSLOT_LOCK:
536 GET_PROP(prim->current.fxslot[idx].props.lLock, long);
537 case EAXFXSLOT_FLAGS:
538 GET_PROP(prim->current.fxslot[idx].props.dwFlags, DWORD);
540 FIXME("Unhandled propid: 0x%08lx\n", propid);
541 return E_PROP_ID_UNSUPPORTED;
545 #define APPLY_WET0_PARAMS 1
546 #define APPLY_WET1_PARAMS 2
547 #define APPLY_DRY_PARAMS 4
548 #define APPLY_ALL_PARAMS (APPLY_WET0_PARAMS | APPLY_WET1_PARAMS | APPLY_DRY_PARAMS)
549 #define APPLY_ALLWET_PARAMS (APPLY_WET0_PARAMS | APPLY_WET1_PARAMS)
550 static void ApplyFilterParams(DSBuffer *buf, const EAXSOURCEPROPERTIES *props, int apply)
552 /* The LFRatio properties determine how much the given level applies to low
553 * frequencies as well as high frequencies. Technically, given that the
554 * obstruction/occlusion/exclusion levels are the absolute level applied to
555 * high frequencies (relative to full-scale, according to the EAX 2.0 spec)
556 * while the HF filter gains are relative to the low, the HF gains should
557 * increase as LFRatio increases.
559 * However it seems Creative was either wrong when writing out the spec,
560 * or implemented it incorrectly, as the HF filter still applies in full
561 * regardless of the LFRatio. So to replicate the hardware behavior, we do
562 * the same here.
564 /* The interaction of ratios is pretty wierd. The typical combination of
565 * the two act as a minimal baseline, while the sum minus one is used when
566 * larger. This creates a more linear change with the individual ratios as
567 * Direct/RoomRatio goes beyond 1, but eases down as the two ratios go
568 * toward 0.
570 float dryoccl = maxF(props->flOcclusionLFRatio+props->flOcclusionDirectRatio-1.0f,
571 props->flOcclusionLFRatio*props->flOcclusionDirectRatio) *
572 props->lOcclusion;
573 float dryocclhf = props->lOcclusion*props->flOcclusionDirectRatio;
574 float room_mb = props->lRoom + props->lExclusion*props->flExclusionLFRatio +
575 maxF(props->flOcclusionLFRatio+props->flOcclusionRoomRatio-1.0f,
576 props->flOcclusionLFRatio*props->flOcclusionRoomRatio) * props->lOcclusion;
577 float room_mbhf = props->lRoomHF + props->lExclusion +
578 props->lOcclusion*props->flOcclusionRoomRatio;
579 int i;
581 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
583 const struct Send *send = &buf->deferred.send[i];
584 if((apply&(1<<i)) && buf->filter[1+i])
586 /* Add the main room occlusion and exclusion properties with the
587 * sends', or take the minimum or maximum?
589 float mb = room_mb + send->lExclusion*send->flExclusionLFRatio +
590 maxF(send->flOcclusionLFRatio+send->flOcclusionRoomRatio-1.0f,
591 send->flOcclusionLFRatio*send->flOcclusionRoomRatio)*send->lOcclusion;
592 float mbhf = room_mbhf + send->lExclusion +
593 send->lOcclusion*send->flOcclusionRoomRatio;
595 alFilterf(buf->filter[1+i], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
596 alFilterf(buf->filter[1+i], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
599 /* Take the minimum, maximum, or average of the sends' direct occlusion with the main
600 * property?
602 dryoccl = minF(dryoccl,
603 maxF(send->flOcclusionLFRatio+send->flOcclusionDirectRatio-1.0f,
604 send->flOcclusionLFRatio*send->flOcclusionDirectRatio) * send->lOcclusion
606 dryocclhf = minF(dryocclhf, send->lOcclusion*send->flOcclusionDirectRatio);
608 if((apply&APPLY_DRY_PARAMS) && buf->filter[0])
610 float mb = props->lDirect + props->lObstruction*props->flObstructionLFRatio + dryoccl;
611 float mbhf = props->lDirectHF + props->lObstruction + dryocclhf;
613 alFilterf(buf->filter[0], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
614 alFilterf(buf->filter[0], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
616 checkALError();
619 static EAXOBSTRUCTIONPROPERTIES EAXSourceObstruction(const EAXSOURCEPROPERTIES *props)
621 EAXOBSTRUCTIONPROPERTIES ret;
622 ret.lObstruction = props->lObstruction;
623 ret.flObstructionLFRatio = props->flObstructionLFRatio;
624 return ret;
627 static EAXOCCLUSIONPROPERTIES EAXSourceOcclusion(const EAXSOURCEPROPERTIES *props)
629 EAXOCCLUSIONPROPERTIES ret;
630 ret.lOcclusion = props->lOcclusion;
631 ret.flOcclusionLFRatio = props->flOcclusionLFRatio;
632 ret.flOcclusionRoomRatio = props->flOcclusionRoomRatio;
633 ret.flOcclusionDirectRatio = props->flOcclusionDirectRatio;
634 return ret;
637 static EAXEXCLUSIONPROPERTIES EAXSourceExclusion(const EAXSOURCEPROPERTIES *props)
639 EAXEXCLUSIONPROPERTIES ret;
640 ret.lExclusion = props->lExclusion;
641 ret.flExclusionLFRatio = props->flExclusionLFRatio;
642 return ret;
645 static struct Send *FindCurrentSend(DSBuffer *buf, const GUID *guid)
647 int i;
648 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
650 DWORD target = buf->current.fxslot_targets[i];
651 if((target == FXSLOT_TARGET_0 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0)) ||
652 (target == FXSLOT_TARGET_1 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1)) ||
653 (target == FXSLOT_TARGET_2 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2)) ||
654 (target == FXSLOT_TARGET_3 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3)) ||
655 (target == FXSLOT_TARGET_PRIMARY && IsEqualGUID(guid, &EAX_PrimaryFXSlotID)) ||
656 (target == FXSLOT_TARGET_NULL && IsEqualGUID(guid, &EAX_NULL_GUID)))
657 return &buf->current.send[i];
659 return NULL;
662 static struct Send *FindDeferredSend(DSBuffer *buf, const GUID *guid)
664 int i;
665 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
667 DWORD target = buf->deferred.fxslot_targets[i];
668 if((target == FXSLOT_TARGET_0 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0)) ||
669 (target == FXSLOT_TARGET_1 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1)) ||
670 (target == FXSLOT_TARGET_2 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2)) ||
671 (target == FXSLOT_TARGET_3 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3)) ||
672 (target == FXSLOT_TARGET_PRIMARY && IsEqualGUID(guid, &EAX_PrimaryFXSlotID)) ||
673 (target == FXSLOT_TARGET_NULL && IsEqualGUID(guid, &EAX_NULL_GUID)))
674 return &buf->deferred.send[i];
676 return NULL;
679 HRESULT EAX4Source_Query(DSBuffer *buf, DWORD propid, ULONG *pTypeSupport)
681 if(!HAS_EXTENSION(buf->share, EXT_EFX))
682 return E_PROP_ID_UNSUPPORTED;
684 switch((propid&~EAXSOURCE_PARAMETER_DEFERRED))
686 case EAXSOURCE_NONE:
687 case EAXSOURCE_ALLPARAMETERS:
688 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
689 case EAXSOURCE_OCCLUSIONPARAMETERS:
690 case EAXSOURCE_EXCLUSIONPARAMETERS:
691 case EAXSOURCE_DIRECT:
692 case EAXSOURCE_DIRECTHF:
693 case EAXSOURCE_ROOM:
694 case EAXSOURCE_ROOMHF:
695 case EAXSOURCE_OBSTRUCTION:
696 case EAXSOURCE_OBSTRUCTIONLFRATIO:
697 case EAXSOURCE_OCCLUSION:
698 case EAXSOURCE_OCCLUSIONLFRATIO:
699 case EAXSOURCE_OCCLUSIONROOMRATIO:
700 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
701 case EAXSOURCE_EXCLUSION:
702 case EAXSOURCE_EXCLUSIONLFRATIO:
703 case EAXSOURCE_OUTSIDEVOLUMEHF:
704 case EAXSOURCE_DOPPLERFACTOR:
705 case EAXSOURCE_ROLLOFFFACTOR:
706 case EAXSOURCE_ROOMROLLOFFFACTOR:
707 case EAXSOURCE_AIRABSORPTIONFACTOR:
708 case EAXSOURCE_FLAGS:
709 case EAXSOURCE_SENDPARAMETERS:
710 case EAXSOURCE_ALLSENDPARAMETERS:
711 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
712 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
713 case EAXSOURCE_ACTIVEFXSLOTID:
714 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
715 return DS_OK;
717 FIXME("Unhandled propid: 0x%08lx\n", propid);
718 return E_PROP_ID_UNSUPPORTED;
721 HRESULT EAX4Source_Set(DSBuffer *buf, DWORD propid, void *pPropData, ULONG cbPropData)
723 if(!HAS_EXTENSION(buf->share, EXT_EFX))
724 return E_PROP_ID_UNSUPPORTED;
726 switch(propid)
728 case EAXSOURCE_NONE:
729 return DS_OK;
731 case EAXSOURCE_ALLPARAMETERS:
732 if(cbPropData >= sizeof(EAXSOURCEPROPERTIES))
734 union {
735 const void *v;
736 const EAXSOURCEPROPERTIES *props;
737 } data = { pPropData };
738 TRACE("Parameters:\n\tDirect: %ld\n\tDirect HF: %ld\n\tRoom: %ld\n\tRoom HF: %ld\n\t"
739 "Obstruction: %ld\n\tObstruction LF Ratio: %f\n\tOcclusion: %ld\n\t"
740 "Occlusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
741 "Occlusion Direct Ratio: %f\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n\t"
742 "Outside Volume HF: %ld\n\tDoppler Factor: %f\n\tRolloff Factor: %f\n\t"
743 "Room Rolloff Factor: %f\n\tAir Absorb Factor: %f\n\tFlags: 0x%02lx\n",
744 data.props->lDirect, data.props->lDirectHF, data.props->lRoom, data.props->lRoomHF,
745 data.props->lObstruction, data.props->flObstructionLFRatio, data.props->lOcclusion,
746 data.props->flOcclusionLFRatio, data.props->flOcclusionRoomRatio,
747 data.props->flOcclusionDirectRatio, data.props->lExclusion,
748 data.props->flExclusionLFRatio, data.props->lOutsideVolumeHF,
749 data.props->flDopplerFactor, data.props->flRolloffFactor,
750 data.props->flRoomRolloffFactor, data.props->flAirAbsorptionFactor,
751 data.props->dwFlags
754 buf->deferred.eax = *data.props;
755 ApplyFilterParams(buf, data.props, APPLY_ALL_PARAMS);
757 buf->dirty.bit.dry_filter = 1;
758 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
759 buf->dirty.bit.doppler = 1;
760 buf->dirty.bit.rolloff = 1;
761 buf->dirty.bit.room_rolloff = 1;
762 buf->dirty.bit.cone_outsidevolumehf = 1;
763 buf->dirty.bit.air_absorb = 1;
764 buf->dirty.bit.flags = 1;
765 return DS_OK;
767 return DSERR_INVALIDPARAM;
768 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
769 if(cbPropData >= sizeof(EAXOBSTRUCTIONPROPERTIES))
771 union {
772 const void *v;
773 const EAXOBSTRUCTIONPROPERTIES *props;
774 } data = { pPropData };
775 TRACE("Parameters:\n\tObstruction: %ld\n\tObstruction LF Ratio: %f\n",
776 data.props->lObstruction, data.props->flObstructionLFRatio);
778 buf->deferred.eax.lObstruction = data.props->lObstruction;
779 buf->deferred.eax.flObstructionLFRatio = data.props->flObstructionLFRatio;
780 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
782 buf->dirty.bit.dry_filter = 1;
783 return DS_OK;
785 return DSERR_INVALIDPARAM;
786 case EAXSOURCE_OCCLUSIONPARAMETERS:
787 if(cbPropData >= sizeof(EAXOCCLUSIONPROPERTIES))
789 union {
790 const void *v;
791 const EAXOCCLUSIONPROPERTIES *props;
792 } data = { pPropData };
793 TRACE("Parameters:\n\tOcclusion: %ld\n\tOcclusion LF Ratio: %f\n\t"
794 "Occlusion Room Ratio: %f\n\tOcclusion Direct Ratio: %f\n",
795 data.props->lOcclusion, data.props->flOcclusionLFRatio,
796 data.props->flOcclusionRoomRatio, data.props->flOcclusionDirectRatio
799 buf->deferred.eax.lOcclusion = data.props->lOcclusion;
800 buf->deferred.eax.flOcclusionLFRatio = data.props->flOcclusionLFRatio;
801 buf->deferred.eax.flOcclusionRoomRatio = data.props->flOcclusionRoomRatio;
802 buf->deferred.eax.flOcclusionDirectRatio = data.props->flOcclusionDirectRatio;
803 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
805 buf->dirty.bit.dry_filter = 1;
806 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
807 return DS_OK;
809 return DSERR_INVALIDPARAM;
810 case EAXSOURCE_EXCLUSIONPARAMETERS:
811 if(cbPropData >= sizeof(EAXEXCLUSIONPROPERTIES))
813 union {
814 const void *v;
815 const EAXEXCLUSIONPROPERTIES *props;
816 } data = { pPropData };
817 TRACE("Parameters:\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n",
818 data.props->lExclusion, data.props->flExclusionLFRatio);
820 buf->deferred.eax.lExclusion = data.props->lExclusion;
821 buf->deferred.eax.flExclusionLFRatio = data.props->flExclusionLFRatio;
822 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
824 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
825 return DS_OK;
827 return DSERR_INVALIDPARAM;
829 case EAXSOURCE_DIRECT:
830 if(cbPropData >= sizeof(long))
832 union { const void *v; const long *l; } data = { pPropData };
833 TRACE("Direct: %ld\n", *data.l);
835 buf->deferred.eax.lDirect = *data.l;
836 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
838 buf->dirty.bit.dry_filter = 1;
839 return DS_OK;
841 return DSERR_INVALIDPARAM;
842 case EAXSOURCE_DIRECTHF:
843 if(cbPropData >= sizeof(long))
845 union { const void *v; const long *l; } data = { pPropData };
846 TRACE("Direct HF: %ld\n", *data.l);
848 buf->deferred.eax.lDirectHF = *data.l;
849 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
851 buf->dirty.bit.dry_filter = 1;
852 return DS_OK;
854 return DSERR_INVALIDPARAM;
856 case EAXSOURCE_ROOM:
857 if(cbPropData >= sizeof(long))
859 union { const void *v; const long *l; } data = { pPropData };
860 TRACE("Room: %ld\n", *data.l);
862 buf->deferred.eax.lRoom = *data.l;
863 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
865 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
866 return DS_OK;
868 return DSERR_INVALIDPARAM;
869 case EAXSOURCE_ROOMHF:
870 if(cbPropData >= sizeof(long))
872 union { const void *v; const long *l; } data = { pPropData };
873 TRACE("Room HF: %ld\n", *data.l);
875 buf->deferred.eax.lRoomHF = *data.l;
876 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
878 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
879 return DS_OK;
881 return DSERR_INVALIDPARAM;
883 case EAXSOURCE_OBSTRUCTION:
884 if(cbPropData >= sizeof(long))
886 union { const void *v; const long *l; } data = { pPropData };
887 TRACE("Obstruction: %ld\n", *data.l);
889 buf->deferred.eax.lObstruction = *data.l;
890 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
892 buf->dirty.bit.dry_filter = 1;
893 return DS_OK;
895 return DSERR_INVALIDPARAM;
896 case EAXSOURCE_OBSTRUCTIONLFRATIO:
897 if(cbPropData >= sizeof(float))
899 union { const void *v; const float *fl; } data = { pPropData };
900 TRACE("Obstruction LF Ratio: %f\n", *data.fl);
902 buf->deferred.eax.flObstructionLFRatio = *data.fl;
903 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
905 buf->dirty.bit.dry_filter = 1;
906 return DS_OK;
908 return DSERR_INVALIDPARAM;
910 case EAXSOURCE_OCCLUSION:
911 if(cbPropData >= sizeof(long))
913 union { const void *v; const long *l; } data = { pPropData };
914 TRACE("Occlusion: %ld\n", *data.l);
916 buf->deferred.eax.lOcclusion = *data.l;
917 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
919 buf->dirty.bit.dry_filter = 1;
920 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
921 return DS_OK;
923 return DSERR_INVALIDPARAM;
924 case EAXSOURCE_OCCLUSIONLFRATIO:
925 if(cbPropData >= sizeof(float))
927 union { const void *v; const float *fl; } data = { pPropData };
928 TRACE("Occlusion LF Ratio: %f\n", *data.fl);
930 buf->deferred.eax.flOcclusionLFRatio = *data.fl;
931 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
933 buf->dirty.bit.dry_filter = 1;
934 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
935 return DS_OK;
937 return DSERR_INVALIDPARAM;
938 case EAXSOURCE_OCCLUSIONROOMRATIO:
939 if(cbPropData >= sizeof(float))
941 union { const void *v; const float *fl; } data = { pPropData };
942 TRACE("Occlusion Room Ratio: %f\n", *data.fl);
944 buf->deferred.eax.flOcclusionRoomRatio = *data.fl;
945 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
947 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
948 return DS_OK;
950 return DSERR_INVALIDPARAM;
951 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
952 if(cbPropData >= sizeof(float))
954 union { const void *v; const float *fl; } data = { pPropData };
955 TRACE("Occlusion Direct Ratio: %f\n", *data.fl);
957 buf->deferred.eax.flOcclusionDirectRatio = *data.fl;
958 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
960 buf->dirty.bit.dry_filter = 1;
961 return DS_OK;
963 return DSERR_INVALIDPARAM;
965 case EAXSOURCE_EXCLUSION:
966 if(cbPropData >= sizeof(long))
968 union { const void *v; const long *l; } data = { pPropData };
969 TRACE("Exclusion: %ld\n", *data.l);
971 buf->deferred.eax.lExclusion = *data.l;
972 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
974 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
975 return DS_OK;
977 return DSERR_INVALIDPARAM;
978 case EAXSOURCE_EXCLUSIONLFRATIO:
979 if(cbPropData >= sizeof(float))
981 union { const void *v; const float *fl; } data = { pPropData };
982 TRACE("Exclusion LF Ratio: %f\n", *data.fl);
984 buf->deferred.eax.flExclusionLFRatio = *data.fl;
985 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
987 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
988 return DS_OK;
990 return DSERR_INVALIDPARAM;
992 case EAXSOURCE_OUTSIDEVOLUMEHF:
993 if(cbPropData >= sizeof(long))
995 union { const void *v; const long *l; } data = { pPropData };
996 TRACE("Outisde Volume HF: %ld\n", *data.l);
998 buf->deferred.eax.lOutsideVolumeHF = *data.l;
1000 buf->dirty.bit.cone_outsidevolumehf = 1;
1001 return DS_OK;
1003 return DSERR_INVALIDPARAM;
1005 case EAXSOURCE_DOPPLERFACTOR:
1006 if(cbPropData >= sizeof(float))
1008 union { const void *v; const float *fl; } data = { pPropData };
1009 TRACE("Doppler Factor: %f\n", *data.fl);
1011 buf->deferred.eax.flDopplerFactor = *data.fl;
1013 buf->dirty.bit.doppler = 1;
1014 return DS_OK;
1016 return DSERR_INVALIDPARAM;
1018 case EAXSOURCE_ROLLOFFFACTOR:
1019 if(cbPropData >= sizeof(float))
1021 union { const void *v; const float *fl; } data = { pPropData };
1022 TRACE("Rolloff Factor: %f\n", *data.fl);
1024 buf->deferred.eax.flRolloffFactor = *data.fl;
1026 buf->dirty.bit.rolloff = 1;
1027 return DS_OK;
1029 return DSERR_INVALIDPARAM;
1031 case EAXSOURCE_ROOMROLLOFFFACTOR:
1032 if(cbPropData >= sizeof(float))
1034 union { const void *v; const float *fl; } data = { pPropData };
1035 TRACE("Room Rolloff Factor: %f\n", *data.fl);
1037 buf->deferred.eax.flRoomRolloffFactor = *data.fl;
1039 buf->dirty.bit.room_rolloff = 1;
1040 return DS_OK;
1042 return DSERR_INVALIDPARAM;
1044 case EAXSOURCE_AIRABSORPTIONFACTOR:
1045 if(cbPropData >= sizeof(float))
1047 union { const void *v; const float *fl; } data = { pPropData };
1048 TRACE("Air Absorb Factor: %f\n", *data.fl);
1050 buf->deferred.eax.flAirAbsorptionFactor = *data.fl;
1052 buf->dirty.bit.air_absorb = 1;
1053 return DS_OK;
1055 return DSERR_INVALIDPARAM;
1057 case EAXSOURCE_FLAGS:
1058 if(cbPropData >= sizeof(DWORD))
1060 union { const void *v; const DWORD *dw; } data = { pPropData };
1061 TRACE("Flags: 0x%lx\n", *data.dw);
1063 buf->deferred.eax.dwFlags = *data.dw;
1065 buf->dirty.bit.flags = 1;
1066 return DS_OK;
1068 return DSERR_INVALIDPARAM;
1070 case EAXSOURCE_SENDPARAMETERS:
1071 if(cbPropData >= sizeof(EAXSOURCESENDPROPERTIES))
1073 union { const void *v; const EAXSOURCESENDPROPERTIES *send; } data = { pPropData };
1074 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1075 LONG count = cbPropData / sizeof(EAXSOURCESENDPROPERTIES);
1076 LONG wetmask=0, i;
1078 if(count > buf->share->num_sends)
1080 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1081 return DSERR_INVALIDPARAM;
1084 for(i = 0;i < count;++i)
1086 TRACE("Send parameters:\n\tReceiving: %s\n\tSend: %ld\n\tSend HF: %ld\n",
1087 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1088 data.send[i].lSend, data.send[i].lSendHF
1090 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1091 if(!srcsend[i])
1093 ERR("Failed to find active FXSlot target: %s\n",
1094 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1095 return DSERR_INVALIDPARAM;
1097 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1100 for(i = 0;i < count;++i)
1102 srcsend[i]->lSend = data.send[i].lSend;
1103 srcsend[i]->lSendHF = data.send[i].lSendHF;
1105 ApplyFilterParams(buf, &buf->deferred.eax, wetmask);
1107 buf->dirty.bit.send_filter |= wetmask;
1108 return DS_OK;
1110 return DSERR_INVALIDPARAM;
1111 case EAXSOURCE_ALLSENDPARAMETERS:
1112 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1114 union { const void *v; const EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1115 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1116 LONG count = cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES);
1117 LONG wetmask=0, i;
1119 if(count > buf->share->num_sends)
1121 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1122 return DSERR_INVALIDPARAM;
1125 for(i = 0;i < count;++i)
1127 TRACE("All send parameters:\n\tReceiving: %s\n\tSend: %ld\n\tSend HF: %ld\n\t"
1128 "Occlusion: %ld\n\tOcclusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
1129 "Occlusion Direct Ratio: %f\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n",
1130 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1131 data.send[i].lSend, data.send[i].lSendHF, data.send[i].lOcclusion,
1132 data.send[i].flOcclusionLFRatio, data.send[i].flOcclusionRoomRatio,
1133 data.send[i].flOcclusionDirectRatio, data.send[i].lExclusion,
1134 data.send[i].flExclusionLFRatio
1136 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1137 if(!srcsend[i])
1139 ERR("Failed to find active FXSlot target: %s\n",
1140 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1141 return DSERR_INVALIDPARAM;
1143 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1146 for(i = 0;i < count;++i)
1148 srcsend[i]->lSend = data.send[i].lSend;
1149 srcsend[i]->lSendHF = data.send[i].lSendHF;
1150 srcsend[i]->lOcclusion = data.send[i].lOcclusion;
1151 srcsend[i]->flOcclusionLFRatio = data.send[i].flOcclusionLFRatio;
1152 srcsend[i]->flOcclusionRoomRatio = data.send[i].flOcclusionRoomRatio;
1153 srcsend[i]->flOcclusionDirectRatio = data.send[i].flOcclusionDirectRatio;
1154 srcsend[i]->lExclusion = data.send[i].lExclusion;
1155 srcsend[i]->flExclusionLFRatio = data.send[i].flExclusionLFRatio;
1157 ApplyFilterParams(buf, &buf->deferred.eax, wetmask|APPLY_DRY_PARAMS);
1159 buf->dirty.bit.dry_filter = 1;
1160 buf->dirty.bit.send_filter |= wetmask;
1161 return DS_OK;
1163 return DSERR_INVALIDPARAM;
1164 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1165 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1167 union { const void *v; const EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1168 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1169 LONG count = cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES);
1170 LONG wetmask=0, i;
1172 if(count > buf->share->num_sends)
1174 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1175 return DSERR_INVALIDPARAM;
1178 for(i = 0;i < count;++i)
1180 TRACE("Occlusion send parameters:\n\tReceiving: %s\n\tOcclusion: %ld\n\t"
1181 "Occlusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
1182 "Occlusion Direct Ratio: %f\n",
1183 debug_fxslot(&data.send[i].guidReceivingFXSlotID), data.send[i].lOcclusion,
1184 data.send[i].flOcclusionLFRatio, data.send[i].flOcclusionRoomRatio,
1185 data.send[i].flOcclusionDirectRatio
1187 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1188 if(!srcsend[i])
1190 ERR("Failed to find active FXSlot target: %s\n",
1191 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1192 return DSERR_INVALIDPARAM;
1194 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1197 for(i = 0;i < count;++i)
1199 srcsend[i]->lOcclusion = data.send[i].lOcclusion;
1200 srcsend[i]->flOcclusionLFRatio = data.send[i].flOcclusionLFRatio;
1201 srcsend[i]->flOcclusionRoomRatio = data.send[i].flOcclusionRoomRatio;
1202 srcsend[i]->flOcclusionDirectRatio = data.send[i].flOcclusionDirectRatio;
1204 ApplyFilterParams(buf, &buf->deferred.eax, wetmask|APPLY_DRY_PARAMS);
1206 buf->dirty.bit.dry_filter = 1;
1207 buf->dirty.bit.send_filter |= wetmask;
1208 return DS_OK;
1210 return DSERR_INVALIDPARAM;
1211 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1212 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1214 union { const void *v; const EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1215 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1216 LONG count = cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES);
1217 LONG wetmask=0, i;
1219 if(count > buf->share->num_sends)
1221 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1222 return DSERR_INVALIDPARAM;
1225 for(i = 0;i < count;++i)
1227 TRACE("Exclusion send parameters:\n\tReceiving: %s\n\tExclusion: %ld\n\t"
1228 "Exclusion LF Ratio: %f\n",
1229 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1230 data.send[i].lExclusion, data.send[i].flExclusionLFRatio
1232 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1233 if(!srcsend[i])
1235 ERR("Failed to find active FXSlot target: %s\n",
1236 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1237 return DSERR_INVALIDPARAM;
1239 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1242 for(i = 0;i < count;++i)
1244 srcsend[i]->lExclusion = data.send[i].lExclusion;
1245 srcsend[i]->flExclusionLFRatio = data.send[i].flExclusionLFRatio;
1247 ApplyFilterParams(buf, &buf->deferred.eax, wetmask);
1249 buf->dirty.bit.send_filter |= wetmask;
1250 return DS_OK;
1252 return DSERR_INVALIDPARAM;
1254 case EAXSOURCE_ACTIVEFXSLOTID:
1255 if(cbPropData && (cbPropData%sizeof(GUID)) == 0)
1257 union { const void *v; const GUID *guid; } data = { pPropData };
1258 DWORD targets[EAX_MAX_ACTIVE_FXSLOTS];
1259 LONG count = cbPropData / sizeof(GUID);
1260 LONG i;
1262 if(count > buf->share->num_sends)
1264 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1265 return DSERR_INVALIDPARAM;
1268 for(i = 0;i < count;i++)
1270 TRACE("Active FXSlot %ld: %s\n", i, debug_fxslot(&data.guid[i]));
1272 targets[i] = FXSLOT_TARGET_NULL;
1273 if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot0))
1274 targets[i] = FXSLOT_TARGET_0;
1275 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot1))
1276 targets[i] = FXSLOT_TARGET_1;
1277 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot2))
1278 targets[i] = FXSLOT_TARGET_2;
1279 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot3))
1280 targets[i] = FXSLOT_TARGET_3;
1281 else if(IsEqualGUID(&data.guid[i], &EAX_PrimaryFXSlotID))
1282 targets[i] = FXSLOT_TARGET_PRIMARY;
1283 if(targets[i] == FXSLOT_TARGET_NULL && !IsEqualGUID(&data.guid[i], &EAX_NULL_GUID))
1285 ERR("Invalid FXSlot: %s\n", debug_fxslot(&data.guid[i]));
1286 return DSERR_INVALIDPARAM;
1290 for(i = 0;i < count;++i)
1291 buf->deferred.fxslot_targets[i] = targets[i];
1292 buf->dirty.bit.send_filter |= (1<<count) - 1;
1293 return DS_OK;
1295 return DSERR_INVALIDPARAM;
1297 FIXME("Unhandled propid: 0x%08lx\n", propid);
1298 return E_PROP_ID_UNSUPPORTED;
1301 HRESULT EAX4Source_Get(DSBuffer *buf, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
1303 if(!HAS_EXTENSION(buf->share, EXT_EFX))
1304 return E_PROP_ID_UNSUPPORTED;
1306 switch(propid)
1308 case EAXSOURCE_NONE:
1309 *pcbReturned = 0;
1310 return DS_OK;
1312 case EAXSOURCE_ALLPARAMETERS:
1313 GET_PROP(buf->current.eax, EAXSOURCEPROPERTIES);
1315 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
1316 GET_PROP(EAXSourceObstruction(&buf->current.eax), EAXOBSTRUCTIONPROPERTIES);
1317 case EAXSOURCE_OCCLUSIONPARAMETERS:
1318 GET_PROP(EAXSourceOcclusion(&buf->current.eax), EAXOCCLUSIONPROPERTIES);
1319 case EAXSOURCE_EXCLUSIONPARAMETERS:
1320 GET_PROP(EAXSourceExclusion(&buf->current.eax), EAXEXCLUSIONPROPERTIES);
1322 case EAXSOURCE_DIRECT:
1323 GET_PROP(buf->current.eax.lDirect, long);
1324 case EAXSOURCE_DIRECTHF:
1325 GET_PROP(buf->current.eax.lDirectHF, long);
1327 case EAXSOURCE_ROOM:
1328 GET_PROP(buf->current.eax.lRoom, long);
1329 case EAXSOURCE_ROOMHF:
1330 GET_PROP(buf->current.eax.lRoomHF, long);
1332 case EAXSOURCE_OBSTRUCTION:
1333 GET_PROP(buf->current.eax.lObstruction, long);
1334 case EAXSOURCE_OBSTRUCTIONLFRATIO:
1335 GET_PROP(buf->current.eax.flObstructionLFRatio, float);
1337 case EAXSOURCE_OCCLUSION:
1338 GET_PROP(buf->current.eax.lOcclusion, long);
1339 case EAXSOURCE_OCCLUSIONLFRATIO:
1340 GET_PROP(buf->current.eax.flOcclusionLFRatio, float);
1341 case EAXSOURCE_OCCLUSIONROOMRATIO:
1342 GET_PROP(buf->current.eax.flOcclusionRoomRatio, float);
1343 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
1344 GET_PROP(buf->current.eax.flOcclusionDirectRatio, float);
1346 case EAXSOURCE_EXCLUSION:
1347 GET_PROP(buf->current.eax.lExclusion, long);
1348 case EAXSOURCE_EXCLUSIONLFRATIO:
1349 GET_PROP(buf->current.eax.flExclusionLFRatio, float);
1351 case EAXSOURCE_OUTSIDEVOLUMEHF:
1352 GET_PROP(buf->current.eax.lOutsideVolumeHF, long);
1354 case EAXSOURCE_DOPPLERFACTOR:
1355 GET_PROP(buf->current.eax.flDopplerFactor, float);
1357 case EAXSOURCE_ROLLOFFFACTOR:
1358 GET_PROP(buf->current.eax.flRolloffFactor, float);
1359 case EAXSOURCE_ROOMROLLOFFFACTOR:
1360 GET_PROP(buf->current.eax.flRoomRolloffFactor, float);
1362 case EAXSOURCE_AIRABSORPTIONFACTOR:
1363 GET_PROP(buf->current.eax.flAirAbsorptionFactor, float);
1365 case EAXSOURCE_FLAGS:
1366 GET_PROP(buf->current.eax.dwFlags, DWORD);
1368 case EAXSOURCE_SENDPARAMETERS:
1369 if(cbPropData >= sizeof(EAXSOURCESENDPROPERTIES))
1371 union { void *v; EAXSOURCESENDPROPERTIES *send; } data = { pPropData };
1372 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1373 LONG count = minI(cbPropData / sizeof(EAXSOURCESENDPROPERTIES),
1374 EAX_MAX_ACTIVE_FXSLOTS);
1375 LONG i;
1377 for(i = 0;i < count;++i)
1379 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1380 if(!srcsend[i])
1382 ERR("Failed to find active FXSlot target: %s\n",
1383 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1384 return DSERR_INVALIDPARAM;
1388 for(i = 0;i < count;++i)
1390 data.send[i].lSend = srcsend[i]->lSend;
1391 data.send[i].lSendHF = srcsend[i]->lSendHF;
1393 *pcbReturned = sizeof(EAXSOURCESENDPROPERTIES)*count;
1394 return DS_OK;
1396 return DSERR_INVALIDPARAM;
1398 case EAXSOURCE_ALLSENDPARAMETERS:
1399 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1401 union { void *v; EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1402 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1403 LONG count = minI(cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES),
1404 EAX_MAX_ACTIVE_FXSLOTS);
1405 LONG i;
1407 for(i = 0;i < count;++i)
1409 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1410 if(!srcsend[i])
1412 ERR("Failed to find active FXSlot target: %s\n",
1413 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1414 return DSERR_INVALIDPARAM;
1418 for(i = 0;i < count;++i)
1420 data.send[i].lSend = srcsend[i]->lSend;
1421 data.send[i].lSendHF = srcsend[i]->lSendHF;
1422 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1423 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1424 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1425 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1426 data.send[i].lExclusion = srcsend[i]->lExclusion;
1427 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1429 *pcbReturned = sizeof(EAXSOURCEALLSENDPROPERTIES)*count;
1430 return DS_OK;
1432 return DSERR_INVALIDPARAM;
1433 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1434 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1436 union { void *v; EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1437 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1438 LONG count = minI(cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES),
1439 EAX_MAX_ACTIVE_FXSLOTS);
1440 LONG i;
1442 for(i = 0;i < count;++i)
1444 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1445 if(!srcsend[i])
1447 ERR("Failed to find active FXSlot target: %s\n",
1448 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1449 return DSERR_INVALIDPARAM;
1453 for(i = 0;i < count;++i)
1455 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1456 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1457 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1458 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1460 *pcbReturned = sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES)*count;
1461 return DS_OK;
1463 return DSERR_INVALIDPARAM;
1464 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1465 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1467 union { void *v; EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1468 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1469 LONG count = minI(cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES),
1470 EAX_MAX_ACTIVE_FXSLOTS);
1471 LONG i;
1473 for(i = 0;i < count;++i)
1475 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1476 if(!srcsend[i])
1478 ERR("Failed to find active FXSlot target: %s\n",
1479 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1480 return DSERR_INVALIDPARAM;
1484 for(i = 0;i < count;++i)
1486 data.send[i].lExclusion = srcsend[i]->lExclusion;
1487 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1489 *pcbReturned = sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES)*count;
1490 return DS_OK;
1492 return DSERR_INVALIDPARAM;
1494 case EAXSOURCE_ACTIVEFXSLOTID:
1495 if(cbPropData >= sizeof(GUID))
1497 union { void *v; GUID *guid; } data = { pPropData };
1498 LONG count = minI(cbPropData / sizeof(GUID), EAX_MAX_ACTIVE_FXSLOTS);
1499 LONG i;
1501 for(i = 0;i < count;++i)
1503 if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_0)
1504 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot0;
1505 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_1)
1506 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot1;
1507 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_2)
1508 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot2;
1509 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_3)
1510 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot3;
1511 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_PRIMARY)
1512 data.guid[i] = EAX_PrimaryFXSlotID;
1513 else /*if(buf->current.fxslot_targets[i] >= FXSLOT_TARGET_NULL)*/
1514 data.guid[i] = EAX_NULL_GUID;
1517 *pcbReturned = sizeof(GUID)*count;
1518 return DS_OK;
1520 return DSERR_INVALIDPARAM;
1522 FIXME("Unhandled propid: 0x%08lx\n", propid);
1523 return E_PROP_ID_UNSUPPORTED;