Add missing file
[dsound-openal.git] / eax4.c
blobaa48da9feedfe1268441bf174e870c6a89d8e8a4
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 ALint prim_idx;
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_idx = -1;
106 if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot0))
107 prim_idx = 0;
108 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot1))
109 prim_idx = 1;
110 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot2))
111 prim_idx = 2;
112 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot3))
113 prim_idx = 3;
114 if(prim_idx == -1 && !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_idx = prim_idx;
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 ALint prim_idx;
153 TRACE("Primary FXSlot: %s\n", debug_fxslot(data.guid));
155 prim_idx = -1;
156 if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot0))
157 prim_idx = 0;
158 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot1))
159 prim_idx = 1;
160 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot2))
161 prim_idx = 2;
162 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot3))
163 prim_idx = 3;
164 if(prim_idx == -1 && !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_idx = prim_idx;
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_DRY_PARAMS (1<<EAX_MAX_FXSLOTS)
556 #define APPLY_ALLWET_PARAMS (APPLY_DRY_PARAMS-1)
557 #define APPLY_ALL_PARAMS (APPLY_DRY_PARAMS | APPLY_ALLWET_PARAMS)
558 static void ApplyFilterParams(DSBuffer *buf, const EAXSOURCEPROPERTIES *props, int apply)
560 /* The LFRatio properties determine how much the given level applies to low
561 * frequencies as well as high frequencies. Technically, given that the
562 * obstruction/occlusion/exclusion levels are the absolute level applied to
563 * high frequencies (relative to full-scale, according to the EAX 2.0 spec)
564 * while the HF filter gains are relative to the low, the HF gains should
565 * increase as LFRatio increases.
567 * However it seems Creative was either wrong when writing out the spec,
568 * or implemented it incorrectly, as the HF filter still applies in full
569 * regardless of the LFRatio. So to replicate the hardware behavior, we do
570 * the same here.
572 /* The interaction of ratios is pretty wierd. The typical combination of
573 * the two act as a minimal baseline, while the sum minus one is used when
574 * larger. This creates a more linear change with the individual ratios as
575 * Direct/RoomRatio goes beyond 1, but eases down as the two ratios go
576 * toward 0.
578 float dryoccl = maxF(props->flOcclusionLFRatio+props->flOcclusionDirectRatio-1.0f,
579 props->flOcclusionLFRatio*props->flOcclusionDirectRatio) *
580 props->lOcclusion;
581 float dryocclhf = props->lOcclusion*props->flOcclusionDirectRatio;
582 float room_mb = props->lRoom + props->lExclusion*props->flExclusionLFRatio +
583 maxF(props->flOcclusionLFRatio+props->flOcclusionRoomRatio-1.0f,
584 props->flOcclusionLFRatio*props->flOcclusionRoomRatio) * props->lOcclusion;
585 float room_mbhf = props->lRoomHF + props->lExclusion +
586 props->lOcclusion*props->flOcclusionRoomRatio;
587 int i;
589 for(i = 0;i < EAX_MAX_FXSLOTS;i++)
591 const struct Send *send = &buf->deferred.send[i];
592 if((apply&(1<<i)) && buf->filter[1+i])
594 /* Add the main room occlusion and exclusion properties with the
595 * sends', or take the minimum or maximum?
597 float mb = room_mb + send->lExclusion*send->flExclusionLFRatio +
598 maxF(send->flOcclusionLFRatio+send->flOcclusionRoomRatio-1.0f,
599 send->flOcclusionLFRatio*send->flOcclusionRoomRatio)*send->lOcclusion;
600 float mbhf = room_mbhf + send->lExclusion +
601 send->lOcclusion*send->flOcclusionRoomRatio;
603 alFilterf(buf->filter[1+i], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
604 alFilterf(buf->filter[1+i], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
607 /* Take the minimum, maximum, or average of the sends' direct occlusion with the main
608 * property?
610 dryoccl = minF(dryoccl,
611 maxF(send->flOcclusionLFRatio+send->flOcclusionDirectRatio-1.0f,
612 send->flOcclusionLFRatio*send->flOcclusionDirectRatio) * send->lOcclusion
614 dryocclhf = minF(dryocclhf, send->lOcclusion*send->flOcclusionDirectRatio);
616 if((apply&APPLY_DRY_PARAMS) && buf->filter[0])
618 float mb = props->lDirect + props->lObstruction*props->flObstructionLFRatio + dryoccl;
619 float mbhf = props->lDirectHF + props->lObstruction + dryocclhf;
621 alFilterf(buf->filter[0], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
622 alFilterf(buf->filter[0], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
624 checkALError();
627 static EAXOBSTRUCTIONPROPERTIES EAXSourceObstruction(const EAXSOURCEPROPERTIES *props)
629 EAXOBSTRUCTIONPROPERTIES ret;
630 ret.lObstruction = props->lObstruction;
631 ret.flObstructionLFRatio = props->flObstructionLFRatio;
632 return ret;
635 static EAXOCCLUSIONPROPERTIES EAXSourceOcclusion(const EAXSOURCEPROPERTIES *props)
637 EAXOCCLUSIONPROPERTIES ret;
638 ret.lOcclusion = props->lOcclusion;
639 ret.flOcclusionLFRatio = props->flOcclusionLFRatio;
640 ret.flOcclusionRoomRatio = props->flOcclusionRoomRatio;
641 ret.flOcclusionDirectRatio = props->flOcclusionDirectRatio;
642 return ret;
645 static EAXEXCLUSIONPROPERTIES EAXSourceExclusion(const EAXSOURCEPROPERTIES *props)
647 EAXEXCLUSIONPROPERTIES ret;
648 ret.lExclusion = props->lExclusion;
649 ret.flExclusionLFRatio = props->flExclusionLFRatio;
650 return ret;
653 static struct Send *FindCurrentSend(DSBuffer *buf, const GUID *guid)
655 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0))
656 return &buf->current.send[0];
657 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1))
658 return &buf->current.send[1];
659 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2))
660 return &buf->current.send[2];
661 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3))
662 return &buf->current.send[3];
663 return NULL;
666 static struct Send *FindDeferredSend(DSBuffer *buf, const GUID *guid)
668 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0))
669 return &buf->deferred.send[0];
670 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1))
671 return &buf->deferred.send[1];
672 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2))
673 return &buf->deferred.send[2];
674 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3))
675 return &buf->deferred.send[3];
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_filters = 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_filters = 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_filters = 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_filters = 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_filters = 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_filters = 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_filters = 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_filters = 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_filters = 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_filters = 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_FXSLOTS];
1075 LONG count = cbPropData / sizeof(EAXSOURCESENDPROPERTIES);
1076 LONG wetmask=0, i;
1078 if(count > buf->share->num_slots)
1080 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_slots);
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_filters = 1;
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_FXSLOTS];
1116 LONG count = cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES);
1117 LONG wetmask=0, i;
1119 if(count > buf->share->num_slots)
1121 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_slots);
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_filters = 1;
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_FXSLOTS];
1169 LONG count = cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES);
1170 LONG wetmask=0, i;
1172 if(count > buf->share->num_slots)
1174 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_slots);
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_filters = 1;
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_FXSLOTS];
1216 LONG count = cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES);
1217 LONG wetmask=0, i;
1219 if(count > buf->share->num_slots)
1221 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_slots);
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_filters = 1;
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_filters = 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_FXSLOTS];
1373 LONG count = minI(cbPropData / sizeof(EAXSOURCESENDPROPERTIES), EAX_MAX_FXSLOTS);
1374 LONG i;
1376 for(i = 0;i < count;++i)
1378 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1379 if(!srcsend[i])
1381 ERR("Failed to find active FXSlot target: %s\n",
1382 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1383 return DSERR_INVALIDPARAM;
1387 for(i = 0;i < count;++i)
1389 data.send[i].lSend = srcsend[i]->lSend;
1390 data.send[i].lSendHF = srcsend[i]->lSendHF;
1392 *pcbReturned = sizeof(EAXSOURCESENDPROPERTIES)*count;
1393 return DS_OK;
1395 return DSERR_INVALIDPARAM;
1397 case EAXSOURCE_ALLSENDPARAMETERS:
1398 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1400 union { void *v; EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1401 const struct Send *srcsend[EAX_MAX_FXSLOTS];
1402 LONG count = minI(cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES), EAX_MAX_FXSLOTS);
1403 LONG i;
1405 for(i = 0;i < count;++i)
1407 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1408 if(!srcsend[i])
1410 ERR("Failed to find active FXSlot target: %s\n",
1411 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1412 return DSERR_INVALIDPARAM;
1416 for(i = 0;i < count;++i)
1418 data.send[i].lSend = srcsend[i]->lSend;
1419 data.send[i].lSendHF = srcsend[i]->lSendHF;
1420 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1421 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1422 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1423 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1424 data.send[i].lExclusion = srcsend[i]->lExclusion;
1425 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1427 *pcbReturned = sizeof(EAXSOURCEALLSENDPROPERTIES)*count;
1428 return DS_OK;
1430 return DSERR_INVALIDPARAM;
1431 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1432 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1434 union { void *v; EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1435 const struct Send *srcsend[EAX_MAX_FXSLOTS];
1436 LONG count = minI(cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES),
1437 EAX_MAX_FXSLOTS);
1438 LONG i;
1440 for(i = 0;i < count;++i)
1442 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1443 if(!srcsend[i])
1445 ERR("Failed to find active FXSlot target: %s\n",
1446 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1447 return DSERR_INVALIDPARAM;
1451 for(i = 0;i < count;++i)
1453 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1454 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1455 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1456 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1458 *pcbReturned = sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES)*count;
1459 return DS_OK;
1461 return DSERR_INVALIDPARAM;
1462 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1463 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1465 union { void *v; EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1466 const struct Send *srcsend[EAX_MAX_FXSLOTS];
1467 LONG count = minI(cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES),
1468 EAX_MAX_FXSLOTS);
1469 LONG i;
1471 for(i = 0;i < count;++i)
1473 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1474 if(!srcsend[i])
1476 ERR("Failed to find active FXSlot target: %s\n",
1477 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1478 return DSERR_INVALIDPARAM;
1482 for(i = 0;i < count;++i)
1484 data.send[i].lExclusion = srcsend[i]->lExclusion;
1485 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1487 *pcbReturned = sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES)*count;
1488 return DS_OK;
1490 return DSERR_INVALIDPARAM;
1492 case EAXSOURCE_ACTIVEFXSLOTID:
1493 if(cbPropData >= sizeof(GUID))
1495 union { void *v; GUID *guid; } data = { pPropData };
1496 LONG count = minI(cbPropData / sizeof(GUID), EAX_MAX_ACTIVE_FXSLOTS);
1497 LONG i;
1499 for(i = 0;i < count;++i)
1501 if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_0)
1502 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot0;
1503 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_1)
1504 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot1;
1505 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_2)
1506 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot2;
1507 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_3)
1508 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot3;
1509 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_PRIMARY)
1510 data.guid[i] = EAX_PrimaryFXSlotID;
1511 else /*if(buf->current.fxslot_targets[i] >= FXSLOT_TARGET_NULL)*/
1512 data.guid[i] = EAX_NULL_GUID;
1515 *pcbReturned = sizeof(GUID)*count;
1516 return DS_OK;
1518 return DSERR_INVALIDPARAM;
1520 FIXME("Unhandled propid: 0x%08lx\n", propid);
1521 return E_PROP_ID_UNSUPPORTED;