Store source send properties for all possible effect slots
[dsound-openal.git] / eax4.c
blobd0502701f5abd67603925323376d7ff0062cd8dc
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_WET0_PARAMS 1
556 #define APPLY_WET1_PARAMS 2
557 #define APPLY_WET2_PARAMS 3
558 #define APPLY_WET3_PARAMS 4
559 #define APPLY_DRY_PARAMS 4
560 #define APPLY_ALL_PARAMS (APPLY_WET0_PARAMS | APPLY_WET1_PARAMS | APPLY_WET2_PARAMS | APPLY_WET3_PARAMS | APPLY_DRY_PARAMS)
561 #define APPLY_ALLWET_PARAMS (APPLY_WET0_PARAMS | APPLY_WET1_PARAMS | APPLY_WET2_PARAMS | APPLY_WET3_PARAMS)
562 static void ApplyFilterParams(DSBuffer *buf, const EAXSOURCEPROPERTIES *props, int apply)
564 /* The LFRatio properties determine how much the given level applies to low
565 * frequencies as well as high frequencies. Technically, given that the
566 * obstruction/occlusion/exclusion levels are the absolute level applied to
567 * high frequencies (relative to full-scale, according to the EAX 2.0 spec)
568 * while the HF filter gains are relative to the low, the HF gains should
569 * increase as LFRatio increases.
571 * However it seems Creative was either wrong when writing out the spec,
572 * or implemented it incorrectly, as the HF filter still applies in full
573 * regardless of the LFRatio. So to replicate the hardware behavior, we do
574 * the same here.
576 /* The interaction of ratios is pretty wierd. The typical combination of
577 * the two act as a minimal baseline, while the sum minus one is used when
578 * larger. This creates a more linear change with the individual ratios as
579 * Direct/RoomRatio goes beyond 1, but eases down as the two ratios go
580 * toward 0.
582 float dryoccl = maxF(props->flOcclusionLFRatio+props->flOcclusionDirectRatio-1.0f,
583 props->flOcclusionLFRatio*props->flOcclusionDirectRatio) *
584 props->lOcclusion;
585 float dryocclhf = props->lOcclusion*props->flOcclusionDirectRatio;
586 float room_mb = props->lRoom + props->lExclusion*props->flExclusionLFRatio +
587 maxF(props->flOcclusionLFRatio+props->flOcclusionRoomRatio-1.0f,
588 props->flOcclusionLFRatio*props->flOcclusionRoomRatio) * props->lOcclusion;
589 float room_mbhf = props->lRoomHF + props->lExclusion +
590 props->lOcclusion*props->flOcclusionRoomRatio;
591 int i;
593 for(i = 0;i < EAX_MAX_FXSLOTS;i++)
595 const struct Send *send = &buf->deferred.send[i];
596 if((apply&(1<<i)) && buf->filter[1+i])
598 /* Add the main room occlusion and exclusion properties with the
599 * sends', or take the minimum or maximum?
601 float mb = room_mb + send->lExclusion*send->flExclusionLFRatio +
602 maxF(send->flOcclusionLFRatio+send->flOcclusionRoomRatio-1.0f,
603 send->flOcclusionLFRatio*send->flOcclusionRoomRatio)*send->lOcclusion;
604 float mbhf = room_mbhf + send->lExclusion +
605 send->lOcclusion*send->flOcclusionRoomRatio;
607 alFilterf(buf->filter[1+i], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
608 alFilterf(buf->filter[1+i], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
611 /* Take the minimum, maximum, or average of the sends' direct occlusion with the main
612 * property?
614 dryoccl = minF(dryoccl,
615 maxF(send->flOcclusionLFRatio+send->flOcclusionDirectRatio-1.0f,
616 send->flOcclusionLFRatio*send->flOcclusionDirectRatio) * send->lOcclusion
618 dryocclhf = minF(dryocclhf, send->lOcclusion*send->flOcclusionDirectRatio);
620 if((apply&APPLY_DRY_PARAMS) && buf->filter[0])
622 float mb = props->lDirect + props->lObstruction*props->flObstructionLFRatio + dryoccl;
623 float mbhf = props->lDirectHF + props->lObstruction + dryocclhf;
625 alFilterf(buf->filter[0], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
626 alFilterf(buf->filter[0], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
628 checkALError();
631 static EAXOBSTRUCTIONPROPERTIES EAXSourceObstruction(const EAXSOURCEPROPERTIES *props)
633 EAXOBSTRUCTIONPROPERTIES ret;
634 ret.lObstruction = props->lObstruction;
635 ret.flObstructionLFRatio = props->flObstructionLFRatio;
636 return ret;
639 static EAXOCCLUSIONPROPERTIES EAXSourceOcclusion(const EAXSOURCEPROPERTIES *props)
641 EAXOCCLUSIONPROPERTIES ret;
642 ret.lOcclusion = props->lOcclusion;
643 ret.flOcclusionLFRatio = props->flOcclusionLFRatio;
644 ret.flOcclusionRoomRatio = props->flOcclusionRoomRatio;
645 ret.flOcclusionDirectRatio = props->flOcclusionDirectRatio;
646 return ret;
649 static EAXEXCLUSIONPROPERTIES EAXSourceExclusion(const EAXSOURCEPROPERTIES *props)
651 EAXEXCLUSIONPROPERTIES ret;
652 ret.lExclusion = props->lExclusion;
653 ret.flExclusionLFRatio = props->flExclusionLFRatio;
654 return ret;
657 static struct Send *FindCurrentSend(DSBuffer *buf, const GUID *guid)
659 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0))
660 return &buf->current.send[0];
661 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1))
662 return &buf->current.send[1];
663 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2))
664 return &buf->current.send[2];
665 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3))
666 return &buf->current.send[3];
667 return NULL;
670 static struct Send *FindDeferredSend(DSBuffer *buf, const GUID *guid)
672 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0))
673 return &buf->deferred.send[0];
674 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1))
675 return &buf->deferred.send[1];
676 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2))
677 return &buf->deferred.send[2];
678 if(IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3))
679 return &buf->deferred.send[3];
680 return NULL;
683 HRESULT EAX4Source_Query(DSBuffer *buf, DWORD propid, ULONG *pTypeSupport)
685 if(!HAS_EXTENSION(buf->share, EXT_EFX))
686 return E_PROP_ID_UNSUPPORTED;
688 switch((propid&~EAXSOURCE_PARAMETER_DEFERRED))
690 case EAXSOURCE_NONE:
691 case EAXSOURCE_ALLPARAMETERS:
692 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
693 case EAXSOURCE_OCCLUSIONPARAMETERS:
694 case EAXSOURCE_EXCLUSIONPARAMETERS:
695 case EAXSOURCE_DIRECT:
696 case EAXSOURCE_DIRECTHF:
697 case EAXSOURCE_ROOM:
698 case EAXSOURCE_ROOMHF:
699 case EAXSOURCE_OBSTRUCTION:
700 case EAXSOURCE_OBSTRUCTIONLFRATIO:
701 case EAXSOURCE_OCCLUSION:
702 case EAXSOURCE_OCCLUSIONLFRATIO:
703 case EAXSOURCE_OCCLUSIONROOMRATIO:
704 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
705 case EAXSOURCE_EXCLUSION:
706 case EAXSOURCE_EXCLUSIONLFRATIO:
707 case EAXSOURCE_OUTSIDEVOLUMEHF:
708 case EAXSOURCE_DOPPLERFACTOR:
709 case EAXSOURCE_ROLLOFFFACTOR:
710 case EAXSOURCE_ROOMROLLOFFFACTOR:
711 case EAXSOURCE_AIRABSORPTIONFACTOR:
712 case EAXSOURCE_FLAGS:
713 case EAXSOURCE_SENDPARAMETERS:
714 case EAXSOURCE_ALLSENDPARAMETERS:
715 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
716 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
717 case EAXSOURCE_ACTIVEFXSLOTID:
718 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
719 return DS_OK;
721 FIXME("Unhandled propid: 0x%08lx\n", propid);
722 return E_PROP_ID_UNSUPPORTED;
725 HRESULT EAX4Source_Set(DSBuffer *buf, DWORD propid, void *pPropData, ULONG cbPropData)
727 if(!HAS_EXTENSION(buf->share, EXT_EFX))
728 return E_PROP_ID_UNSUPPORTED;
730 switch(propid)
732 case EAXSOURCE_NONE:
733 return DS_OK;
735 case EAXSOURCE_ALLPARAMETERS:
736 if(cbPropData >= sizeof(EAXSOURCEPROPERTIES))
738 union {
739 const void *v;
740 const EAXSOURCEPROPERTIES *props;
741 } data = { pPropData };
742 TRACE("Parameters:\n\tDirect: %ld\n\tDirect HF: %ld\n\tRoom: %ld\n\tRoom HF: %ld\n\t"
743 "Obstruction: %ld\n\tObstruction LF Ratio: %f\n\tOcclusion: %ld\n\t"
744 "Occlusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
745 "Occlusion Direct Ratio: %f\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n\t"
746 "Outside Volume HF: %ld\n\tDoppler Factor: %f\n\tRolloff Factor: %f\n\t"
747 "Room Rolloff Factor: %f\n\tAir Absorb Factor: %f\n\tFlags: 0x%02lx\n",
748 data.props->lDirect, data.props->lDirectHF, data.props->lRoom, data.props->lRoomHF,
749 data.props->lObstruction, data.props->flObstructionLFRatio, data.props->lOcclusion,
750 data.props->flOcclusionLFRatio, data.props->flOcclusionRoomRatio,
751 data.props->flOcclusionDirectRatio, data.props->lExclusion,
752 data.props->flExclusionLFRatio, data.props->lOutsideVolumeHF,
753 data.props->flDopplerFactor, data.props->flRolloffFactor,
754 data.props->flRoomRolloffFactor, data.props->flAirAbsorptionFactor,
755 data.props->dwFlags
758 buf->deferred.eax = *data.props;
759 ApplyFilterParams(buf, data.props, APPLY_ALL_PARAMS);
761 buf->dirty.bit.dry_filter = 1;
762 buf->dirty.bit.send_filters = 1;
763 buf->dirty.bit.doppler = 1;
764 buf->dirty.bit.rolloff = 1;
765 buf->dirty.bit.room_rolloff = 1;
766 buf->dirty.bit.cone_outsidevolumehf = 1;
767 buf->dirty.bit.air_absorb = 1;
768 buf->dirty.bit.flags = 1;
769 return DS_OK;
771 return DSERR_INVALIDPARAM;
772 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
773 if(cbPropData >= sizeof(EAXOBSTRUCTIONPROPERTIES))
775 union {
776 const void *v;
777 const EAXOBSTRUCTIONPROPERTIES *props;
778 } data = { pPropData };
779 TRACE("Parameters:\n\tObstruction: %ld\n\tObstruction LF Ratio: %f\n",
780 data.props->lObstruction, data.props->flObstructionLFRatio);
782 buf->deferred.eax.lObstruction = data.props->lObstruction;
783 buf->deferred.eax.flObstructionLFRatio = data.props->flObstructionLFRatio;
784 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
786 buf->dirty.bit.dry_filter = 1;
787 return DS_OK;
789 return DSERR_INVALIDPARAM;
790 case EAXSOURCE_OCCLUSIONPARAMETERS:
791 if(cbPropData >= sizeof(EAXOCCLUSIONPROPERTIES))
793 union {
794 const void *v;
795 const EAXOCCLUSIONPROPERTIES *props;
796 } data = { pPropData };
797 TRACE("Parameters:\n\tOcclusion: %ld\n\tOcclusion LF Ratio: %f\n\t"
798 "Occlusion Room Ratio: %f\n\tOcclusion Direct Ratio: %f\n",
799 data.props->lOcclusion, data.props->flOcclusionLFRatio,
800 data.props->flOcclusionRoomRatio, data.props->flOcclusionDirectRatio
803 buf->deferred.eax.lOcclusion = data.props->lOcclusion;
804 buf->deferred.eax.flOcclusionLFRatio = data.props->flOcclusionLFRatio;
805 buf->deferred.eax.flOcclusionRoomRatio = data.props->flOcclusionRoomRatio;
806 buf->deferred.eax.flOcclusionDirectRatio = data.props->flOcclusionDirectRatio;
807 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
809 buf->dirty.bit.dry_filter = 1;
810 buf->dirty.bit.send_filters = 1;
811 return DS_OK;
813 return DSERR_INVALIDPARAM;
814 case EAXSOURCE_EXCLUSIONPARAMETERS:
815 if(cbPropData >= sizeof(EAXEXCLUSIONPROPERTIES))
817 union {
818 const void *v;
819 const EAXEXCLUSIONPROPERTIES *props;
820 } data = { pPropData };
821 TRACE("Parameters:\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n",
822 data.props->lExclusion, data.props->flExclusionLFRatio);
824 buf->deferred.eax.lExclusion = data.props->lExclusion;
825 buf->deferred.eax.flExclusionLFRatio = data.props->flExclusionLFRatio;
826 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
828 buf->dirty.bit.send_filters = 1;
829 return DS_OK;
831 return DSERR_INVALIDPARAM;
833 case EAXSOURCE_DIRECT:
834 if(cbPropData >= sizeof(long))
836 union { const void *v; const long *l; } data = { pPropData };
837 TRACE("Direct: %ld\n", *data.l);
839 buf->deferred.eax.lDirect = *data.l;
840 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
842 buf->dirty.bit.dry_filter = 1;
843 return DS_OK;
845 return DSERR_INVALIDPARAM;
846 case EAXSOURCE_DIRECTHF:
847 if(cbPropData >= sizeof(long))
849 union { const void *v; const long *l; } data = { pPropData };
850 TRACE("Direct HF: %ld\n", *data.l);
852 buf->deferred.eax.lDirectHF = *data.l;
853 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
855 buf->dirty.bit.dry_filter = 1;
856 return DS_OK;
858 return DSERR_INVALIDPARAM;
860 case EAXSOURCE_ROOM:
861 if(cbPropData >= sizeof(long))
863 union { const void *v; const long *l; } data = { pPropData };
864 TRACE("Room: %ld\n", *data.l);
866 buf->deferred.eax.lRoom = *data.l;
867 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
869 buf->dirty.bit.send_filters = 1;
870 return DS_OK;
872 return DSERR_INVALIDPARAM;
873 case EAXSOURCE_ROOMHF:
874 if(cbPropData >= sizeof(long))
876 union { const void *v; const long *l; } data = { pPropData };
877 TRACE("Room HF: %ld\n", *data.l);
879 buf->deferred.eax.lRoomHF = *data.l;
880 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
882 buf->dirty.bit.send_filters = 1;
883 return DS_OK;
885 return DSERR_INVALIDPARAM;
887 case EAXSOURCE_OBSTRUCTION:
888 if(cbPropData >= sizeof(long))
890 union { const void *v; const long *l; } data = { pPropData };
891 TRACE("Obstruction: %ld\n", *data.l);
893 buf->deferred.eax.lObstruction = *data.l;
894 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
896 buf->dirty.bit.dry_filter = 1;
897 return DS_OK;
899 return DSERR_INVALIDPARAM;
900 case EAXSOURCE_OBSTRUCTIONLFRATIO:
901 if(cbPropData >= sizeof(float))
903 union { const void *v; const float *fl; } data = { pPropData };
904 TRACE("Obstruction LF Ratio: %f\n", *data.fl);
906 buf->deferred.eax.flObstructionLFRatio = *data.fl;
907 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
909 buf->dirty.bit.dry_filter = 1;
910 return DS_OK;
912 return DSERR_INVALIDPARAM;
914 case EAXSOURCE_OCCLUSION:
915 if(cbPropData >= sizeof(long))
917 union { const void *v; const long *l; } data = { pPropData };
918 TRACE("Occlusion: %ld\n", *data.l);
920 buf->deferred.eax.lOcclusion = *data.l;
921 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
923 buf->dirty.bit.dry_filter = 1;
924 buf->dirty.bit.send_filters = 1;
925 return DS_OK;
927 return DSERR_INVALIDPARAM;
928 case EAXSOURCE_OCCLUSIONLFRATIO:
929 if(cbPropData >= sizeof(float))
931 union { const void *v; const float *fl; } data = { pPropData };
932 TRACE("Occlusion LF Ratio: %f\n", *data.fl);
934 buf->deferred.eax.flOcclusionLFRatio = *data.fl;
935 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
937 buf->dirty.bit.dry_filter = 1;
938 buf->dirty.bit.send_filters = 1;
939 return DS_OK;
941 return DSERR_INVALIDPARAM;
942 case EAXSOURCE_OCCLUSIONROOMRATIO:
943 if(cbPropData >= sizeof(float))
945 union { const void *v; const float *fl; } data = { pPropData };
946 TRACE("Occlusion Room Ratio: %f\n", *data.fl);
948 buf->deferred.eax.flOcclusionRoomRatio = *data.fl;
949 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
951 buf->dirty.bit.send_filters = 1;
952 return DS_OK;
954 return DSERR_INVALIDPARAM;
955 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
956 if(cbPropData >= sizeof(float))
958 union { const void *v; const float *fl; } data = { pPropData };
959 TRACE("Occlusion Direct Ratio: %f\n", *data.fl);
961 buf->deferred.eax.flOcclusionDirectRatio = *data.fl;
962 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
964 buf->dirty.bit.dry_filter = 1;
965 return DS_OK;
967 return DSERR_INVALIDPARAM;
969 case EAXSOURCE_EXCLUSION:
970 if(cbPropData >= sizeof(long))
972 union { const void *v; const long *l; } data = { pPropData };
973 TRACE("Exclusion: %ld\n", *data.l);
975 buf->deferred.eax.lExclusion = *data.l;
976 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
978 buf->dirty.bit.send_filters = 1;
979 return DS_OK;
981 return DSERR_INVALIDPARAM;
982 case EAXSOURCE_EXCLUSIONLFRATIO:
983 if(cbPropData >= sizeof(float))
985 union { const void *v; const float *fl; } data = { pPropData };
986 TRACE("Exclusion LF Ratio: %f\n", *data.fl);
988 buf->deferred.eax.flExclusionLFRatio = *data.fl;
989 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
991 buf->dirty.bit.send_filters = 1;
992 return DS_OK;
994 return DSERR_INVALIDPARAM;
996 case EAXSOURCE_OUTSIDEVOLUMEHF:
997 if(cbPropData >= sizeof(long))
999 union { const void *v; const long *l; } data = { pPropData };
1000 TRACE("Outisde Volume HF: %ld\n", *data.l);
1002 buf->deferred.eax.lOutsideVolumeHF = *data.l;
1004 buf->dirty.bit.cone_outsidevolumehf = 1;
1005 return DS_OK;
1007 return DSERR_INVALIDPARAM;
1009 case EAXSOURCE_DOPPLERFACTOR:
1010 if(cbPropData >= sizeof(float))
1012 union { const void *v; const float *fl; } data = { pPropData };
1013 TRACE("Doppler Factor: %f\n", *data.fl);
1015 buf->deferred.eax.flDopplerFactor = *data.fl;
1017 buf->dirty.bit.doppler = 1;
1018 return DS_OK;
1020 return DSERR_INVALIDPARAM;
1022 case EAXSOURCE_ROLLOFFFACTOR:
1023 if(cbPropData >= sizeof(float))
1025 union { const void *v; const float *fl; } data = { pPropData };
1026 TRACE("Rolloff Factor: %f\n", *data.fl);
1028 buf->deferred.eax.flRolloffFactor = *data.fl;
1030 buf->dirty.bit.rolloff = 1;
1031 return DS_OK;
1033 return DSERR_INVALIDPARAM;
1035 case EAXSOURCE_ROOMROLLOFFFACTOR:
1036 if(cbPropData >= sizeof(float))
1038 union { const void *v; const float *fl; } data = { pPropData };
1039 TRACE("Room Rolloff Factor: %f\n", *data.fl);
1041 buf->deferred.eax.flRoomRolloffFactor = *data.fl;
1043 buf->dirty.bit.room_rolloff = 1;
1044 return DS_OK;
1046 return DSERR_INVALIDPARAM;
1048 case EAXSOURCE_AIRABSORPTIONFACTOR:
1049 if(cbPropData >= sizeof(float))
1051 union { const void *v; const float *fl; } data = { pPropData };
1052 TRACE("Air Absorb Factor: %f\n", *data.fl);
1054 buf->deferred.eax.flAirAbsorptionFactor = *data.fl;
1056 buf->dirty.bit.air_absorb = 1;
1057 return DS_OK;
1059 return DSERR_INVALIDPARAM;
1061 case EAXSOURCE_FLAGS:
1062 if(cbPropData >= sizeof(DWORD))
1064 union { const void *v; const DWORD *dw; } data = { pPropData };
1065 TRACE("Flags: 0x%lx\n", *data.dw);
1067 buf->deferred.eax.dwFlags = *data.dw;
1069 buf->dirty.bit.flags = 1;
1070 return DS_OK;
1072 return DSERR_INVALIDPARAM;
1074 case EAXSOURCE_SENDPARAMETERS:
1075 if(cbPropData >= sizeof(EAXSOURCESENDPROPERTIES))
1077 union { const void *v; const EAXSOURCESENDPROPERTIES *send; } data = { pPropData };
1078 struct Send *srcsend[EAX_MAX_FXSLOTS];
1079 LONG count = cbPropData / sizeof(EAXSOURCESENDPROPERTIES);
1080 LONG wetmask=0, i;
1082 if(count > buf->share->num_slots)
1084 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_slots);
1085 return DSERR_INVALIDPARAM;
1088 for(i = 0;i < count;++i)
1090 TRACE("Send parameters:\n\tReceiving: %s\n\tSend: %ld\n\tSend HF: %ld\n",
1091 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1092 data.send[i].lSend, data.send[i].lSendHF
1094 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1095 if(!srcsend[i])
1097 ERR("Failed to find active FXSlot target: %s\n",
1098 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1099 return DSERR_INVALIDPARAM;
1101 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1104 for(i = 0;i < count;++i)
1106 srcsend[i]->lSend = data.send[i].lSend;
1107 srcsend[i]->lSendHF = data.send[i].lSendHF;
1109 ApplyFilterParams(buf, &buf->deferred.eax, wetmask);
1111 buf->dirty.bit.send_filters = 1;
1112 return DS_OK;
1114 return DSERR_INVALIDPARAM;
1115 case EAXSOURCE_ALLSENDPARAMETERS:
1116 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1118 union { const void *v; const EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1119 struct Send *srcsend[EAX_MAX_FXSLOTS];
1120 LONG count = cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES);
1121 LONG wetmask=0, i;
1123 if(count > buf->share->num_slots)
1125 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_slots);
1126 return DSERR_INVALIDPARAM;
1129 for(i = 0;i < count;++i)
1131 TRACE("All send parameters:\n\tReceiving: %s\n\tSend: %ld\n\tSend HF: %ld\n\t"
1132 "Occlusion: %ld\n\tOcclusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
1133 "Occlusion Direct Ratio: %f\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n",
1134 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1135 data.send[i].lSend, data.send[i].lSendHF, data.send[i].lOcclusion,
1136 data.send[i].flOcclusionLFRatio, data.send[i].flOcclusionRoomRatio,
1137 data.send[i].flOcclusionDirectRatio, data.send[i].lExclusion,
1138 data.send[i].flExclusionLFRatio
1140 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1141 if(!srcsend[i])
1143 ERR("Failed to find active FXSlot target: %s\n",
1144 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1145 return DSERR_INVALIDPARAM;
1147 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1150 for(i = 0;i < count;++i)
1152 srcsend[i]->lSend = data.send[i].lSend;
1153 srcsend[i]->lSendHF = data.send[i].lSendHF;
1154 srcsend[i]->lOcclusion = data.send[i].lOcclusion;
1155 srcsend[i]->flOcclusionLFRatio = data.send[i].flOcclusionLFRatio;
1156 srcsend[i]->flOcclusionRoomRatio = data.send[i].flOcclusionRoomRatio;
1157 srcsend[i]->flOcclusionDirectRatio = data.send[i].flOcclusionDirectRatio;
1158 srcsend[i]->lExclusion = data.send[i].lExclusion;
1159 srcsend[i]->flExclusionLFRatio = data.send[i].flExclusionLFRatio;
1161 ApplyFilterParams(buf, &buf->deferred.eax, wetmask|APPLY_DRY_PARAMS);
1163 buf->dirty.bit.dry_filter = 1;
1164 buf->dirty.bit.send_filters = 1;
1165 return DS_OK;
1167 return DSERR_INVALIDPARAM;
1168 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1169 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1171 union { const void *v; const EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1172 struct Send *srcsend[EAX_MAX_FXSLOTS];
1173 LONG count = cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES);
1174 LONG wetmask=0, i;
1176 if(count > buf->share->num_slots)
1178 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_slots);
1179 return DSERR_INVALIDPARAM;
1182 for(i = 0;i < count;++i)
1184 TRACE("Occlusion send parameters:\n\tReceiving: %s\n\tOcclusion: %ld\n\t"
1185 "Occlusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
1186 "Occlusion Direct Ratio: %f\n",
1187 debug_fxslot(&data.send[i].guidReceivingFXSlotID), data.send[i].lOcclusion,
1188 data.send[i].flOcclusionLFRatio, data.send[i].flOcclusionRoomRatio,
1189 data.send[i].flOcclusionDirectRatio
1191 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1192 if(!srcsend[i])
1194 ERR("Failed to find active FXSlot target: %s\n",
1195 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1196 return DSERR_INVALIDPARAM;
1198 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1201 for(i = 0;i < count;++i)
1203 srcsend[i]->lOcclusion = data.send[i].lOcclusion;
1204 srcsend[i]->flOcclusionLFRatio = data.send[i].flOcclusionLFRatio;
1205 srcsend[i]->flOcclusionRoomRatio = data.send[i].flOcclusionRoomRatio;
1206 srcsend[i]->flOcclusionDirectRatio = data.send[i].flOcclusionDirectRatio;
1208 ApplyFilterParams(buf, &buf->deferred.eax, wetmask|APPLY_DRY_PARAMS);
1210 buf->dirty.bit.dry_filter = 1;
1211 buf->dirty.bit.send_filters = 1;
1212 return DS_OK;
1214 return DSERR_INVALIDPARAM;
1215 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1216 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1218 union { const void *v; const EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1219 struct Send *srcsend[EAX_MAX_FXSLOTS];
1220 LONG count = cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES);
1221 LONG wetmask=0, i;
1223 if(count > buf->share->num_slots)
1225 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_slots);
1226 return DSERR_INVALIDPARAM;
1229 for(i = 0;i < count;++i)
1231 TRACE("Exclusion send parameters:\n\tReceiving: %s\n\tExclusion: %ld\n\t"
1232 "Exclusion LF Ratio: %f\n",
1233 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1234 data.send[i].lExclusion, data.send[i].flExclusionLFRatio
1236 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1237 if(!srcsend[i])
1239 ERR("Failed to find active FXSlot target: %s\n",
1240 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1241 return DSERR_INVALIDPARAM;
1243 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1246 for(i = 0;i < count;++i)
1248 srcsend[i]->lExclusion = data.send[i].lExclusion;
1249 srcsend[i]->flExclusionLFRatio = data.send[i].flExclusionLFRatio;
1251 ApplyFilterParams(buf, &buf->deferred.eax, wetmask);
1253 buf->dirty.bit.send_filters = 1;
1254 return DS_OK;
1256 return DSERR_INVALIDPARAM;
1258 case EAXSOURCE_ACTIVEFXSLOTID:
1259 if(cbPropData && (cbPropData%sizeof(GUID)) == 0)
1261 union { const void *v; const GUID *guid; } data = { pPropData };
1262 DWORD targets[EAX_MAX_ACTIVE_FXSLOTS];
1263 LONG count = cbPropData / sizeof(GUID);
1264 LONG i;
1266 if(count > buf->share->num_sends)
1268 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1269 return DSERR_INVALIDPARAM;
1272 for(i = 0;i < count;i++)
1274 TRACE("Active FXSlot %ld: %s\n", i, debug_fxslot(&data.guid[i]));
1276 targets[i] = FXSLOT_TARGET_NULL;
1277 if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot0))
1278 targets[i] = FXSLOT_TARGET_0;
1279 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot1))
1280 targets[i] = FXSLOT_TARGET_1;
1281 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot2))
1282 targets[i] = FXSLOT_TARGET_2;
1283 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot3))
1284 targets[i] = FXSLOT_TARGET_3;
1285 else if(IsEqualGUID(&data.guid[i], &EAX_PrimaryFXSlotID))
1286 targets[i] = FXSLOT_TARGET_PRIMARY;
1287 if(targets[i] == FXSLOT_TARGET_NULL && !IsEqualGUID(&data.guid[i], &EAX_NULL_GUID))
1289 ERR("Invalid FXSlot: %s\n", debug_fxslot(&data.guid[i]));
1290 return DSERR_INVALIDPARAM;
1294 for(i = 0;i < count;++i)
1295 buf->deferred.fxslot_targets[i] = targets[i];
1296 buf->dirty.bit.send_filters = 1;
1297 return DS_OK;
1299 return DSERR_INVALIDPARAM;
1301 FIXME("Unhandled propid: 0x%08lx\n", propid);
1302 return E_PROP_ID_UNSUPPORTED;
1305 HRESULT EAX4Source_Get(DSBuffer *buf, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
1307 if(!HAS_EXTENSION(buf->share, EXT_EFX))
1308 return E_PROP_ID_UNSUPPORTED;
1310 switch(propid)
1312 case EAXSOURCE_NONE:
1313 *pcbReturned = 0;
1314 return DS_OK;
1316 case EAXSOURCE_ALLPARAMETERS:
1317 GET_PROP(buf->current.eax, EAXSOURCEPROPERTIES);
1319 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
1320 GET_PROP(EAXSourceObstruction(&buf->current.eax), EAXOBSTRUCTIONPROPERTIES);
1321 case EAXSOURCE_OCCLUSIONPARAMETERS:
1322 GET_PROP(EAXSourceOcclusion(&buf->current.eax), EAXOCCLUSIONPROPERTIES);
1323 case EAXSOURCE_EXCLUSIONPARAMETERS:
1324 GET_PROP(EAXSourceExclusion(&buf->current.eax), EAXEXCLUSIONPROPERTIES);
1326 case EAXSOURCE_DIRECT:
1327 GET_PROP(buf->current.eax.lDirect, long);
1328 case EAXSOURCE_DIRECTHF:
1329 GET_PROP(buf->current.eax.lDirectHF, long);
1331 case EAXSOURCE_ROOM:
1332 GET_PROP(buf->current.eax.lRoom, long);
1333 case EAXSOURCE_ROOMHF:
1334 GET_PROP(buf->current.eax.lRoomHF, long);
1336 case EAXSOURCE_OBSTRUCTION:
1337 GET_PROP(buf->current.eax.lObstruction, long);
1338 case EAXSOURCE_OBSTRUCTIONLFRATIO:
1339 GET_PROP(buf->current.eax.flObstructionLFRatio, float);
1341 case EAXSOURCE_OCCLUSION:
1342 GET_PROP(buf->current.eax.lOcclusion, long);
1343 case EAXSOURCE_OCCLUSIONLFRATIO:
1344 GET_PROP(buf->current.eax.flOcclusionLFRatio, float);
1345 case EAXSOURCE_OCCLUSIONROOMRATIO:
1346 GET_PROP(buf->current.eax.flOcclusionRoomRatio, float);
1347 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
1348 GET_PROP(buf->current.eax.flOcclusionDirectRatio, float);
1350 case EAXSOURCE_EXCLUSION:
1351 GET_PROP(buf->current.eax.lExclusion, long);
1352 case EAXSOURCE_EXCLUSIONLFRATIO:
1353 GET_PROP(buf->current.eax.flExclusionLFRatio, float);
1355 case EAXSOURCE_OUTSIDEVOLUMEHF:
1356 GET_PROP(buf->current.eax.lOutsideVolumeHF, long);
1358 case EAXSOURCE_DOPPLERFACTOR:
1359 GET_PROP(buf->current.eax.flDopplerFactor, float);
1361 case EAXSOURCE_ROLLOFFFACTOR:
1362 GET_PROP(buf->current.eax.flRolloffFactor, float);
1363 case EAXSOURCE_ROOMROLLOFFFACTOR:
1364 GET_PROP(buf->current.eax.flRoomRolloffFactor, float);
1366 case EAXSOURCE_AIRABSORPTIONFACTOR:
1367 GET_PROP(buf->current.eax.flAirAbsorptionFactor, float);
1369 case EAXSOURCE_FLAGS:
1370 GET_PROP(buf->current.eax.dwFlags, DWORD);
1372 case EAXSOURCE_SENDPARAMETERS:
1373 if(cbPropData >= sizeof(EAXSOURCESENDPROPERTIES))
1375 union { void *v; EAXSOURCESENDPROPERTIES *send; } data = { pPropData };
1376 const struct Send *srcsend[EAX_MAX_FXSLOTS];
1377 LONG count = minI(cbPropData / sizeof(EAXSOURCESENDPROPERTIES), EAX_MAX_FXSLOTS);
1378 LONG i;
1380 for(i = 0;i < count;++i)
1382 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1383 if(!srcsend[i])
1385 ERR("Failed to find active FXSlot target: %s\n",
1386 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1387 return DSERR_INVALIDPARAM;
1391 for(i = 0;i < count;++i)
1393 data.send[i].lSend = srcsend[i]->lSend;
1394 data.send[i].lSendHF = srcsend[i]->lSendHF;
1396 *pcbReturned = sizeof(EAXSOURCESENDPROPERTIES)*count;
1397 return DS_OK;
1399 return DSERR_INVALIDPARAM;
1401 case EAXSOURCE_ALLSENDPARAMETERS:
1402 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1404 union { void *v; EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1405 const struct Send *srcsend[EAX_MAX_FXSLOTS];
1406 LONG count = minI(cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES), EAX_MAX_FXSLOTS);
1407 LONG i;
1409 for(i = 0;i < count;++i)
1411 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1412 if(!srcsend[i])
1414 ERR("Failed to find active FXSlot target: %s\n",
1415 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1416 return DSERR_INVALIDPARAM;
1420 for(i = 0;i < count;++i)
1422 data.send[i].lSend = srcsend[i]->lSend;
1423 data.send[i].lSendHF = srcsend[i]->lSendHF;
1424 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1425 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1426 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1427 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1428 data.send[i].lExclusion = srcsend[i]->lExclusion;
1429 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1431 *pcbReturned = sizeof(EAXSOURCEALLSENDPROPERTIES)*count;
1432 return DS_OK;
1434 return DSERR_INVALIDPARAM;
1435 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1436 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1438 union { void *v; EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1439 const struct Send *srcsend[EAX_MAX_FXSLOTS];
1440 LONG count = minI(cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES),
1441 EAX_MAX_FXSLOTS);
1442 LONG i;
1444 for(i = 0;i < count;++i)
1446 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1447 if(!srcsend[i])
1449 ERR("Failed to find active FXSlot target: %s\n",
1450 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1451 return DSERR_INVALIDPARAM;
1455 for(i = 0;i < count;++i)
1457 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1458 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1459 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1460 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1462 *pcbReturned = sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES)*count;
1463 return DS_OK;
1465 return DSERR_INVALIDPARAM;
1466 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1467 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1469 union { void *v; EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1470 const struct Send *srcsend[EAX_MAX_FXSLOTS];
1471 LONG count = minI(cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES),
1472 EAX_MAX_FXSLOTS);
1473 LONG i;
1475 for(i = 0;i < count;++i)
1477 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1478 if(!srcsend[i])
1480 ERR("Failed to find active FXSlot target: %s\n",
1481 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1482 return DSERR_INVALIDPARAM;
1486 for(i = 0;i < count;++i)
1488 data.send[i].lExclusion = srcsend[i]->lExclusion;
1489 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1491 *pcbReturned = sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES)*count;
1492 return DS_OK;
1494 return DSERR_INVALIDPARAM;
1496 case EAXSOURCE_ACTIVEFXSLOTID:
1497 if(cbPropData >= sizeof(GUID))
1499 union { void *v; GUID *guid; } data = { pPropData };
1500 LONG count = minI(cbPropData / sizeof(GUID), EAX_MAX_ACTIVE_FXSLOTS);
1501 LONG i;
1503 for(i = 0;i < count;++i)
1505 if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_0)
1506 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot0;
1507 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_1)
1508 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot1;
1509 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_2)
1510 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot2;
1511 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_3)
1512 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot3;
1513 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_PRIMARY)
1514 data.guid[i] = EAX_PrimaryFXSlotID;
1515 else /*if(buf->current.fxslot_targets[i] >= FXSLOT_TARGET_NULL)*/
1516 data.guid[i] = EAX_NULL_GUID;
1519 *pcbReturned = sizeof(GUID)*count;
1520 return DS_OK;
1522 return DSERR_INVALIDPARAM;
1524 FIXME("Unhandled propid: 0x%08lx\n", propid);
1525 return E_PROP_ID_UNSUPPORTED;