Make a macro for the default chorus parameters
[dsound-openal.git] / eax4.c
blobebfb7ea875028a06d7967207565f23dd52d6d1a5
1 /* DirectSound EAX interface
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 #define CONST_VTABLE
19 #include <stdarg.h>
20 #include <string.h>
22 #include "windows.h"
23 #include "dsound.h"
25 #include "dsound_private.h"
26 #include "eax-presets.h"
29 static const char *debug_fxslot(const GUID *guid)
31 #define HANDLE_ID(id) if(IsEqualGUID(guid, &(id))) return #id
32 HANDLE_ID(EAX_NULL_GUID);
33 HANDLE_ID(EAX_PrimaryFXSlotID);
34 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot0);
35 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot1);
36 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot2);
37 HANDLE_ID(EAXPROPERTYID_EAX40_FXSlot3);
38 #undef HANDLE_ID
39 return debugstr_guid(guid);
42 static const char *debug_fxguid(const GUID *guid)
44 #define HANDLE_ID(id) if(IsEqualGUID(guid, &(id))) return #id
45 HANDLE_ID(EAX_NULL_GUID);
46 HANDLE_ID(EAX_REVERB_EFFECT);
47 HANDLE_ID(EAX_AGCCOMPRESSOR_EFFECT);
48 HANDLE_ID(EAX_AUTOWAH_EFFECT);
49 HANDLE_ID(EAX_CHORUS_EFFECT);
50 HANDLE_ID(EAX_DISTORTION_EFFECT);
51 HANDLE_ID(EAX_ECHO_EFFECT);
52 HANDLE_ID(EAX_EQUALIZER_EFFECT);
53 HANDLE_ID(EAX_FLANGER_EFFECT);
54 HANDLE_ID(EAX_FREQUENCYSHIFTER_EFFECT);
55 HANDLE_ID(EAX_VOCALMORPHER_EFFECT);
56 HANDLE_ID(EAX_PITCHSHIFTER_EFFECT);
57 HANDLE_ID(EAX_RINGMODULATOR_EFFECT);
58 #undef HANDLE_ID
59 return debugstr_guid(guid);
63 HRESULT EAX4Context_Query(DSPrimary *prim, DWORD propid, ULONG *pTypeSupport)
65 if(!HAS_EXTENSION(prim->share, EXT_EFX))
66 return E_PROP_ID_UNSUPPORTED;
68 switch((propid&~EAXCONTEXT_PARAMETER_DEFERRED))
70 case EAXCONTEXT_NONE:
71 case EAXCONTEXT_ALLPARAMETERS:
72 case EAXCONTEXT_PRIMARYFXSLOTID:
73 case EAXCONTEXT_DISTANCEFACTOR:
74 case EAXCONTEXT_AIRABSORPTIONHF:
75 case EAXCONTEXT_HFREFERENCE:
76 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
77 return DS_OK;
78 case EAXCONTEXT_LASTERROR:
79 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
80 return DS_OK;
82 FIXME("Unhandled propid: 0x%08lx\n", propid);
83 return E_PROP_ID_UNSUPPORTED;
86 HRESULT EAX4Context_Set(DSPrimary *prim, DWORD propid, void *pPropData, ULONG cbPropData)
88 if(!HAS_EXTENSION(prim->share, EXT_EFX))
89 return E_PROP_ID_UNSUPPORTED;
91 switch(propid)
93 case EAXCONTEXT_NONE: /* not setting any property, just applying */
94 return DS_OK;
96 case EAXCONTEXT_ALLPARAMETERS:
97 if(cbPropData >= sizeof(EAXCONTEXTPROPERTIES))
99 union { void *v; const EAXCONTEXTPROPERTIES *props; } data = { pPropData };
100 ALuint prim_slot;
101 TRACE("Parameters:\n\tPrimary FXSlot: %s\n\tDistance Factor: %f\n\t"
102 "Air Absorption: %f\n\tHF Reference: %f\n",
103 debug_fxslot(&data.props->guidPrimaryFXSlotID), data.props->flDistanceFactor,
104 data.props->flAirAbsorptionHF, data.props->flHFReference
107 prim_slot = 0;
108 if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot0))
109 prim_slot = prim->auxslot[0];
110 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot1))
111 prim_slot = prim->auxslot[1];
112 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot2))
113 prim_slot = prim->auxslot[2];
114 else if(IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAXPROPERTYID_EAX40_FXSlot3))
115 prim_slot = prim->auxslot[3];
116 if(prim_slot == 0 && !IsEqualGUID(&data.props->guidPrimaryFXSlotID, &EAX_NULL_GUID))
118 ERR("Unexpected primary FXSlot: %s\n",
119 debug_fxslot(&data.props->guidPrimaryFXSlotID));
120 return DSERR_INVALIDPARAM;
122 if(!(data.props->flDistanceFactor >= DS3D_MINDISTANCEFACTOR &&
123 data.props->flDistanceFactor <= DS3D_MAXDISTANCEFACTOR))
125 ERR("Unexpected distance factor: %f\n", data.props->flDistanceFactor);
126 return DSERR_INVALIDPARAM;
128 if(!(data.props->flAirAbsorptionHF <= 0.0f && data.props->flAirAbsorptionHF >= -100.0f))
130 ERR("Unexpected air absorption: %f\n", data.props->flAirAbsorptionHF);
131 return DSERR_INVALIDPARAM;
133 if(!(data.props->flHFReference >= 1000.0f && data.props->flHFReference <= 20000.0f))
135 ERR("Unexpected HF reference: %f\n", data.props->flAirAbsorptionHF);
136 return DSERR_INVALIDPARAM;
139 prim->deferred.ctx = *data.props;
140 prim->primary_slot = prim_slot;
142 prim->dirty.bit.prim_slotid = 1;
143 prim->dirty.bit.distancefactor2 = 1;
144 prim->dirty.bit.air_absorbhf = 1;
145 prim->dirty.bit.hfreference = 1;
146 return DS_OK;
148 return DSERR_INVALIDPARAM;
150 case EAXCONTEXT_PRIMARYFXSLOTID:
151 if(cbPropData >= sizeof(GUID))
153 union { void *v; const GUID *guid; } data = { pPropData };
154 ALuint prim_slot;
155 TRACE("Primary FXSlot: %s\n", debug_fxslot(data.guid));
157 prim_slot = 0;
158 if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot0))
159 prim_slot = prim->auxslot[0];
160 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot1))
161 prim_slot = prim->auxslot[1];
162 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot2))
163 prim_slot = prim->auxslot[2];
164 else if(IsEqualGUID(data.guid, &EAXPROPERTYID_EAX40_FXSlot3))
165 prim_slot = prim->auxslot[3];
166 if(prim_slot == 0 && !IsEqualGUID(data.guid, &EAX_NULL_GUID))
168 ERR("Unexpected primary FXSlot: %s\n", debug_fxslot(data.guid));
169 return DSERR_INVALIDPARAM;
172 prim->deferred.ctx.guidPrimaryFXSlotID = *data.guid;
173 prim->primary_slot = prim_slot;
175 prim->dirty.bit.prim_slotid = 1;
176 return DS_OK;
178 return DSERR_INVALIDPARAM;
180 case EAXCONTEXT_DISTANCEFACTOR:
181 if(cbPropData >= sizeof(float))
183 union { void *v; const float *fl; } data = { pPropData };
184 TRACE("Distance Factor: %f\n", *data.fl);
186 if(!(*data.fl >= DS3D_MINDISTANCEFACTOR && *data.fl <= DS3D_MAXDISTANCEFACTOR))
188 ERR("Unexpected distance factor: %f\n", *data.fl);
189 return DSERR_INVALIDPARAM;
192 prim->deferred.ctx.flDistanceFactor = *data.fl;
194 prim->dirty.bit.distancefactor2 = 1;
195 return DS_OK;
197 return DSERR_INVALIDPARAM;
199 case EAXCONTEXT_AIRABSORPTIONHF:
200 if(cbPropData >= sizeof(float))
202 union { void *v; const float *fl; } data = { pPropData };
203 TRACE("Air Absorption: %f\n", *data.fl);
205 if(!(*data.fl <= 0.0f && *data.fl >= -100.0f))
207 ERR("Unexpected air absorption: %f\n", *data.fl);
208 return DSERR_INVALIDPARAM;
211 prim->deferred.ctx.flAirAbsorptionHF = *data.fl;
213 prim->dirty.bit.air_absorbhf = 1;
214 return DS_OK;
216 return DSERR_INVALIDPARAM;
218 case EAXCONTEXT_HFREFERENCE:
219 if(cbPropData >= sizeof(float))
221 union { void *v; const float *fl; } data = { pPropData };
222 TRACE("HF Reference: %f\n", *data.fl);
224 if(!(*data.fl >= 1000.0f && *data.fl <= 20000.0f))
226 ERR("Unexpected HF reference: %f\n", *data.fl);
227 return DSERR_INVALIDPARAM;
230 prim->deferred.ctx.flHFReference = *data.fl;
232 prim->dirty.bit.hfreference = 1;
233 return DS_OK;
235 return DSERR_INVALIDPARAM;
237 FIXME("Unhandled propid: 0x%08lx\n", propid);
238 return E_PROP_ID_UNSUPPORTED;
241 #define GET_PROP(src, T) do { \
242 if(cbPropData >= sizeof(T)) \
244 union { void *v; T *props; } data = { pPropData }; \
245 *data.props = src; \
246 *pcbReturned = sizeof(T); \
247 return DS_OK; \
249 return DSERR_INVALIDPARAM; \
250 } while(0)
252 HRESULT EAX4Context_Get(DSPrimary *prim, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
254 if(!HAS_EXTENSION(prim->share, EXT_EFX))
255 return E_PROP_ID_UNSUPPORTED;
257 switch(propid)
259 case EAXCONTEXT_NONE:
260 *pcbReturned = 0;
261 return DS_OK;
263 case EAXCONTEXT_ALLPARAMETERS:
264 GET_PROP(prim->current.ctx, EAXCONTEXTPROPERTIES);
265 case EAXCONTEXT_PRIMARYFXSLOTID:
266 GET_PROP(prim->current.ctx.guidPrimaryFXSlotID, GUID);
267 case EAXCONTEXT_DISTANCEFACTOR:
268 GET_PROP(prim->current.ctx.flDistanceFactor, float);
269 case EAXCONTEXT_AIRABSORPTIONHF:
270 GET_PROP(prim->current.ctx.flAirAbsorptionHF, float);
271 case EAXCONTEXT_HFREFERENCE:
272 GET_PROP(prim->current.ctx.flHFReference, float);
274 case EAXCONTEXT_LASTERROR:
275 GET_PROP(InterlockedExchange(&prim->eax_error, EAX_OK), long);
277 FIXME("Unhandled propid: 0x%08lx\n", propid);
278 return E_PROP_ID_UNSUPPORTED;
282 HRESULT EAX4Slot_Query(DSPrimary *prim, LONG idx, DWORD propid, ULONG *pTypeSupport)
284 if(prim->auxslot[idx] == 0)
285 return E_PROP_ID_UNSUPPORTED;
287 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) < EAXFXSLOT_NONE)
289 if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
291 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) <= EAXREVERB_FLAGS)
293 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
294 return DS_OK;
296 FIXME("Unhandled reverb propid: 0x%08lx\n", propid);
298 else if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
300 if((propid&~EAXFXSLOT_PARAMETER_DEFERRED) <= EAXCHORUS_DELAY)
302 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
303 return DS_OK;
305 FIXME("Unhandled chorus propid: 0x%08lx\n", propid);
307 else /*if(prim->current.fxslot[idx].effect_type == FXSLOT_EFFECT_NULL)*/
309 FIXME("Unhandled null effect propid: 0x%08lx\n", propid);
311 return DSERR_INVALIDPARAM;
313 switch((propid&~EAXFXSLOT_PARAMETER_DEFERRED))
315 case EAXFXSLOT_NONE:
316 case EAXFXSLOT_ALLPARAMETERS:
317 case EAXFXSLOT_LOADEFFECT:
318 case EAXFXSLOT_VOLUME:
319 case EAXFXSLOT_LOCK:
320 case EAXFXSLOT_FLAGS:
321 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
322 return DS_OK;
324 FIXME("Unhandled propid: 0x%08lx\n", propid);
325 return E_PROP_ID_UNSUPPORTED;
329 HRESULT EAX4Slot_Set(DSPrimary *prim, LONG idx, DWORD propid, void *pPropData, ULONG cbPropData)
331 if(prim->auxslot[idx] == 0)
332 return E_PROP_ID_UNSUPPORTED;
334 if(propid < EAXFXSLOT_NONE)
336 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
337 return EAXReverb_Set(prim, idx, propid, pPropData, cbPropData);
338 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
339 return EAXChorus_Set(prim, idx, propid, pPropData, cbPropData);
341 ERR("Unexpected null effect propid 0x%08lx\n", propid);
342 return E_PROP_ID_UNSUPPORTED;
344 switch(propid)
346 case EAXFXSLOT_NONE: /* not setting any property, just applying */
347 return DS_OK;
349 case EAXFXSLOT_ALLPARAMETERS:
350 if(cbPropData >= sizeof(EAXFXSLOTPROPERTIES))
352 union { const void *v; const EAXFXSLOTPROPERTIES *props; } data = { pPropData };
353 DWORD effect_type;
354 TRACE("Parameters:\n\tLoad Effect: %s\n\tVolume: %ld\n\tLock: %ld\n\tFlags: 0x%lx\n",
355 debug_fxguid(&data.props->guidLoadEffect), data.props->lVolume, data.props->lLock,
356 data.props->dwFlags
359 effect_type = FXSLOT_EFFECT_NULL;
360 if(IsEqualGUID(&data.props->guidLoadEffect, &EAX_REVERB_EFFECT))
361 effect_type = FXSLOT_EFFECT_REVERB;
362 else if(IsEqualGUID(&data.props->guidLoadEffect, &EAX_CHORUS_EFFECT))
363 effect_type = FXSLOT_EFFECT_CHORUS;
364 else if(!IsEqualGUID(&data.props->guidLoadEffect, &EAX_NULL_GUID))
366 ERR("Unhandled effect: %s\n", debug_fxguid(&data.props->guidLoadEffect));
367 return DSERR_INVALIDPARAM;
370 if(data.props->lLock == EAXFXSLOT_LOCKED &&
371 prim->deferred.fxslot[idx].props.lLock == EAXFXSLOT_LOCKED &&
372 prim->deferred.fxslot[idx].effect_type != effect_type)
374 ERR("Attempting to change effect type for locked FXSlot\n");
375 return DSERR_INVALIDCALL;
378 if(prim->deferred.fxslot[idx].effect_type != effect_type)
380 alGetError();
381 alEffecti(prim->effect[idx], AL_EFFECT_TYPE,
382 (effect_type == FXSLOT_EFFECT_REVERB) ? AL_EFFECT_EAXREVERB :
383 (effect_type == FXSLOT_EFFECT_CHORUS) ? AL_EFFECT_CHORUS :
384 AL_EFFECT_NULL
386 if(alGetError() != AL_NO_ERROR)
388 ERR("Failed to set effect type %lu\n", effect_type);
389 return DSERR_INVALIDPARAM;
392 prim->deferred.fxslot[idx].effect_type = effect_type;
393 memset(&prim->deferred.fxslot[idx].fx, 0, sizeof(prim->deferred.fxslot[idx].fx));
394 if(effect_type == FXSLOT_EFFECT_REVERB)
395 prim->deferred.fxslot[idx].fx.reverb = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
396 else if(effect_type == FXSLOT_EFFECT_CHORUS)
398 const EAXCHORUSPROPERTIES chorus_def = CHORUS_PRESET_DEFAULT;
399 prim->deferred.fxslot[idx].fx.chorus = chorus_def;
402 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_EFFECT_BIT);
404 prim->deferred.fxslot[idx].props = *data.props;
406 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_VOL_BIT);
407 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_LOCK_BIT);
408 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_FLAGS_BIT);
409 return DS_OK;
411 return DSERR_INVALIDPARAM;
413 case EAXFXSLOT_LOADEFFECT:
414 if(cbPropData >= sizeof(GUID))
416 union { const void *v; const GUID *guid; } data = { pPropData };
417 DWORD effect_type;
418 TRACE("Load Effect: %s\n", debug_fxguid(data.guid));
420 effect_type = FXSLOT_EFFECT_NULL;
421 if(IsEqualGUID(data.guid, &EAX_REVERB_EFFECT))
422 effect_type = FXSLOT_EFFECT_REVERB;
423 else if(IsEqualGUID(data.guid, &EAX_CHORUS_EFFECT))
424 effect_type = FXSLOT_EFFECT_CHORUS;
425 else if(!IsEqualGUID(data.guid, &EAX_NULL_GUID))
427 ERR("Unhandled effect: %s\n", debug_fxguid(data.guid));
428 return DSERR_INVALIDPARAM;
431 if(prim->deferred.fxslot[idx].props.lLock == EAXFXSLOT_LOCKED)
433 ERR("Attempting to change effect type for locked FXSlot\n");
434 return DSERR_INVALIDCALL;
437 alGetError();
438 alEffecti(prim->effect[idx], AL_EFFECT_TYPE,
439 (effect_type == FXSLOT_EFFECT_REVERB) ? AL_EFFECT_EAXREVERB :
440 (effect_type == FXSLOT_EFFECT_CHORUS) ? AL_EFFECT_CHORUS :
441 AL_EFFECT_NULL
443 if(alGetError() != AL_NO_ERROR)
445 ERR("Failed to set effect type %lu\n", effect_type);
446 return DSERR_INVALIDPARAM;
449 prim->deferred.fxslot[idx].effect_type = effect_type;
450 memset(&prim->deferred.fxslot[idx].fx, 0, sizeof(prim->deferred.fxslot[idx].fx));
451 if(effect_type == FXSLOT_EFFECT_REVERB)
452 prim->deferred.fxslot[idx].fx.reverb = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
453 else if(effect_type == FXSLOT_EFFECT_CHORUS)
455 const EAXCHORUSPROPERTIES chorus_def = CHORUS_PRESET_DEFAULT;
456 prim->deferred.fxslot[idx].fx.chorus = chorus_def;
458 prim->deferred.fxslot[idx].props.guidLoadEffect = *data.guid;
460 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_EFFECT_BIT);
461 return DS_OK;
463 return DSERR_INVALIDPARAM;
465 case EAXFXSLOT_VOLUME:
466 if(cbPropData >= sizeof(long))
468 union { const void *v; const long *l; } data = { pPropData };
469 TRACE("Volume: %ld\n", *data.l);
471 prim->deferred.fxslot[idx].props.lVolume = *data.l;
473 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_VOL_BIT);
474 return DS_OK;
476 return DSERR_INVALIDPARAM;
478 case EAXFXSLOT_LOCK:
479 if(cbPropData >= sizeof(long))
481 union { const void *v; const long *l; } data = { pPropData };
482 TRACE("Lock: %ld\n", *data.l);
484 prim->deferred.fxslot[idx].props.lLock = *data.l;
486 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_LOCK_BIT);
487 return DS_OK;
489 return DSERR_INVALIDPARAM;
491 case EAXFXSLOT_FLAGS:
492 if(cbPropData >= sizeof(DWORD))
494 union { const void *v; const DWORD *dw; } data = { pPropData };
495 TRACE("Flags: 0x%lx\n", *data.dw);
497 prim->deferred.fxslot[idx].props.dwFlags = *data.dw;
499 FXSLOT_SET_DIRTY(prim->dirty.bit, idx, FXSLOT_FLAGS_BIT);
500 return DS_OK;
502 return DSERR_INVALIDPARAM;
504 FIXME("Unhandled propid: 0x%08lx\n", propid);
505 return E_PROP_ID_UNSUPPORTED;
508 HRESULT EAX4Slot_Get(DSPrimary *prim, LONG idx, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
510 if(prim->auxslot[idx] == 0)
511 return E_PROP_ID_UNSUPPORTED;
513 if(propid < EAXFXSLOT_NONE)
515 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_REVERB)
516 return EAXReverb_Get(prim, idx, propid, pPropData, cbPropData, pcbReturned);
517 if(prim->deferred.fxslot[idx].effect_type == FXSLOT_EFFECT_CHORUS)
518 return EAXChorus_Get(prim, idx, propid, pPropData, cbPropData, pcbReturned);
520 ERR("Unexpected null effect propid 0x%08lx\n", propid);
521 return E_PROP_ID_UNSUPPORTED;
523 switch(propid)
525 case EAXFXSLOT_NONE:
526 *pcbReturned = 0;
527 return DS_OK;
529 case EAXFXSLOT_ALLPARAMETERS:
530 GET_PROP(prim->current.fxslot[idx].props, EAXFXSLOTPROPERTIES);
531 case EAXFXSLOT_LOADEFFECT:
532 GET_PROP(prim->current.fxslot[idx].props.guidLoadEffect, GUID);
533 case EAXFXSLOT_VOLUME:
534 GET_PROP(prim->current.fxslot[idx].props.lVolume, long);
535 case EAXFXSLOT_LOCK:
536 GET_PROP(prim->current.fxslot[idx].props.lLock, long);
537 case EAXFXSLOT_FLAGS:
538 GET_PROP(prim->current.fxslot[idx].props.dwFlags, DWORD);
540 FIXME("Unhandled propid: 0x%08lx\n", propid);
541 return E_PROP_ID_UNSUPPORTED;
545 #define APPLY_WET0_PARAMS 1
546 #define APPLY_WET1_PARAMS 2
547 #define APPLY_DRY_PARAMS 4
548 #define APPLY_ALL_PARAMS (APPLY_WET0_PARAMS | APPLY_WET1_PARAMS | APPLY_DRY_PARAMS)
549 #define APPLY_ALLWET_PARAMS (APPLY_WET0_PARAMS | APPLY_WET1_PARAMS)
550 static void ApplyFilterParams(DSBuffer *buf, const EAXSOURCEPROPERTIES *props, int apply)
552 /* The LFRatio properties determine how much the given level applies to low
553 * frequencies as well as high frequencies. Technically, given that the
554 * obstruction/occlusion/exclusion levels are the absolute level applied to
555 * high frequencies (relative to full-scale, according to the EAX 2.0 spec)
556 * while the HF filter gains are relative to the low, the HF gains should
557 * increase as LFRatio increases.
559 * However it seems Creative was either wrong when writing out the spec,
560 * or implemented it incorrectly, as the HF filter still applies in full
561 * regardless of the LFRatio. So to replicate the hardware behavior, we do
562 * the same here.
564 /* The interaction of ratios is pretty wierd. The typical combination of
565 * the two act as a minimal baseline, while the sum minus one is used when
566 * larger. This creates a more linear change with the individual ratios as
567 * DirectRatio goes beyond 1, but eases down as the two ratios go toward 0.
569 float room_mb = props->lRoom + props->lExclusion*props->flExclusionLFRatio +
570 maxF(props->flOcclusionLFRatio+props->flOcclusionRoomRatio-1.0f,
571 props->flOcclusionLFRatio*props->flOcclusionRoomRatio) * props->lOcclusion;
572 float room_mbhf = props->lRoomHF + props->lExclusion +
573 props->lOcclusion*props->flOcclusionRoomRatio;
574 float direct_mb = 0;
575 float direct_mbhf = 0;
576 int i;
578 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
580 const struct Send *send = &buf->deferred.send[i];
581 if((apply&(1<<i)) && buf->filter[1+i])
583 float mb = room_mb + send->lExclusion*send->flExclusionLFRatio +
584 maxF(send->flOcclusionLFRatio+send->flOcclusionRoomRatio-1.0f,
585 send->flOcclusionLFRatio*send->flOcclusionRoomRatio)*send->lOcclusion;
586 float mbhf = room_mbhf + send->lExclusion +
587 send->lOcclusion*send->flOcclusionRoomRatio;
589 alFilterf(buf->filter[1+i], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
590 alFilterf(buf->filter[1+i], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
592 /* FIXME: This should either be added like this, or take the minimum
593 * volume level from the separate occlusion properties.
595 direct_mb += maxF(send->flOcclusionLFRatio+send->flOcclusionDirectRatio-1.0f,
596 send->flOcclusionLFRatio*send->flOcclusionDirectRatio) *
597 send->lOcclusion;
598 direct_mbhf += send->lOcclusion*send->flOcclusionDirectRatio;
600 if((apply&APPLY_DRY_PARAMS) && buf->filter[0])
602 float mb = direct_mb + props->lDirect + props->lObstruction*props->flObstructionLFRatio +
603 maxF(props->flOcclusionLFRatio+props->flOcclusionDirectRatio-1.0f,
604 props->flOcclusionLFRatio*props->flOcclusionDirectRatio)*props->lOcclusion;
605 float mbhf = direct_mbhf + props->lDirectHF + props->lObstruction +
606 props->lOcclusion*props->flOcclusionDirectRatio;
608 alFilterf(buf->filter[0], AL_LOWPASS_GAIN, mB_to_gain(minF(mb, buf->filter_mBLimit)));
609 alFilterf(buf->filter[0], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
611 checkALError();
614 static EAXOBSTRUCTIONPROPERTIES EAXSourceObstruction(const EAXSOURCEPROPERTIES *props)
616 EAXOBSTRUCTIONPROPERTIES ret;
617 ret.lObstruction = props->lObstruction;
618 ret.flObstructionLFRatio = props->flObstructionLFRatio;
619 return ret;
622 static EAXOCCLUSIONPROPERTIES EAXSourceOcclusion(const EAXSOURCEPROPERTIES *props)
624 EAXOCCLUSIONPROPERTIES ret;
625 ret.lOcclusion = props->lOcclusion;
626 ret.flOcclusionLFRatio = props->flOcclusionLFRatio;
627 ret.flOcclusionRoomRatio = props->flOcclusionRoomRatio;
628 ret.flOcclusionDirectRatio = props->flOcclusionDirectRatio;
629 return ret;
632 static EAXEXCLUSIONPROPERTIES EAXSourceExclusion(const EAXSOURCEPROPERTIES *props)
634 EAXEXCLUSIONPROPERTIES ret;
635 ret.lExclusion = props->lExclusion;
636 ret.flExclusionLFRatio = props->flExclusionLFRatio;
637 return ret;
640 static struct Send *FindCurrentSend(DSBuffer *buf, const GUID *guid)
642 int i;
643 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
645 DWORD target = buf->current.fxslot_targets[i];
646 if((target == FXSLOT_TARGET_0 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0)) ||
647 (target == FXSLOT_TARGET_1 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1)) ||
648 (target == FXSLOT_TARGET_2 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2)) ||
649 (target == FXSLOT_TARGET_3 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3)) ||
650 (target == FXSLOT_TARGET_PRIMARY && IsEqualGUID(guid, &EAX_PrimaryFXSlotID)) ||
651 (target == FXSLOT_TARGET_NULL && IsEqualGUID(guid, &EAX_NULL_GUID)))
652 return &buf->current.send[i];
654 return NULL;
657 static struct Send *FindDeferredSend(DSBuffer *buf, const GUID *guid)
659 int i;
660 for(i = 0;i < EAX_MAX_ACTIVE_FXSLOTS;i++)
662 DWORD target = buf->deferred.fxslot_targets[i];
663 if((target == FXSLOT_TARGET_0 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot0)) ||
664 (target == FXSLOT_TARGET_1 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot1)) ||
665 (target == FXSLOT_TARGET_2 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot2)) ||
666 (target == FXSLOT_TARGET_3 && IsEqualGUID(guid, &EAXPROPERTYID_EAX40_FXSlot3)) ||
667 (target == FXSLOT_TARGET_PRIMARY && IsEqualGUID(guid, &EAX_PrimaryFXSlotID)) ||
668 (target == FXSLOT_TARGET_NULL && IsEqualGUID(guid, &EAX_NULL_GUID)))
669 return &buf->deferred.send[i];
671 return NULL;
674 HRESULT EAX4Source_Query(DSBuffer *buf, DWORD propid, ULONG *pTypeSupport)
676 if(!HAS_EXTENSION(buf->share, EXT_EFX))
677 return E_PROP_ID_UNSUPPORTED;
679 switch((propid&~EAXSOURCE_PARAMETER_DEFERRED))
681 case EAXSOURCE_NONE:
682 case EAXSOURCE_ALLPARAMETERS:
683 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
684 case EAXSOURCE_OCCLUSIONPARAMETERS:
685 case EAXSOURCE_EXCLUSIONPARAMETERS:
686 case EAXSOURCE_DIRECT:
687 case EAXSOURCE_DIRECTHF:
688 case EAXSOURCE_ROOM:
689 case EAXSOURCE_ROOMHF:
690 case EAXSOURCE_OBSTRUCTION:
691 case EAXSOURCE_OBSTRUCTIONLFRATIO:
692 case EAXSOURCE_OCCLUSION:
693 case EAXSOURCE_OCCLUSIONLFRATIO:
694 case EAXSOURCE_OCCLUSIONROOMRATIO:
695 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
696 case EAXSOURCE_EXCLUSION:
697 case EAXSOURCE_EXCLUSIONLFRATIO:
698 case EAXSOURCE_OUTSIDEVOLUMEHF:
699 case EAXSOURCE_DOPPLERFACTOR:
700 case EAXSOURCE_ROLLOFFFACTOR:
701 case EAXSOURCE_ROOMROLLOFFFACTOR:
702 case EAXSOURCE_AIRABSORPTIONFACTOR:
703 case EAXSOURCE_FLAGS:
704 case EAXSOURCE_SENDPARAMETERS:
705 case EAXSOURCE_ALLSENDPARAMETERS:
706 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
707 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
708 case EAXSOURCE_ACTIVEFXSLOTID:
709 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
710 return DS_OK;
712 FIXME("Unhandled propid: 0x%08lx\n", propid);
713 return E_PROP_ID_UNSUPPORTED;
716 HRESULT EAX4Source_Set(DSBuffer *buf, DWORD propid, void *pPropData, ULONG cbPropData)
718 if(!HAS_EXTENSION(buf->share, EXT_EFX))
719 return E_PROP_ID_UNSUPPORTED;
721 switch(propid)
723 case EAXSOURCE_NONE:
724 return DS_OK;
726 case EAXSOURCE_ALLPARAMETERS:
727 if(cbPropData >= sizeof(EAXSOURCEPROPERTIES))
729 union {
730 const void *v;
731 const EAXSOURCEPROPERTIES *props;
732 } data = { pPropData };
733 TRACE("Parameters:\n\tDirect: %ld\n\tDirect HF: %ld\n\tRoom: %ld\n\tRoom HF: %ld\n\t"
734 "Obstruction: %ld\n\tObstruction LF Ratio: %f\n\tOcclusion: %ld\n\t"
735 "Occlusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
736 "Occlusion Direct Ratio: %f\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n\t"
737 "Outside Volume HF: %ld\n\tDoppler Factor: %f\n\tRolloff Factor: %f\n\t"
738 "Room Rolloff Factor: %f\n\tAir Absorb Factor: %f\n\tFlags: 0x%02lx\n",
739 data.props->lDirect, data.props->lDirectHF, data.props->lRoom, data.props->lRoomHF,
740 data.props->lObstruction, data.props->flObstructionLFRatio, data.props->lOcclusion,
741 data.props->flOcclusionLFRatio, data.props->flOcclusionRoomRatio,
742 data.props->flOcclusionDirectRatio, data.props->lExclusion,
743 data.props->flExclusionLFRatio, data.props->lOutsideVolumeHF,
744 data.props->flDopplerFactor, data.props->flRolloffFactor,
745 data.props->flRoomRolloffFactor, data.props->flAirAbsorptionFactor,
746 data.props->dwFlags
749 buf->deferred.eax = *data.props;
750 ApplyFilterParams(buf, data.props, APPLY_ALL_PARAMS);
752 buf->dirty.bit.dry_filter = 1;
753 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
754 buf->dirty.bit.doppler = 1;
755 buf->dirty.bit.rolloff = 1;
756 buf->dirty.bit.room_rolloff = 1;
757 buf->dirty.bit.cone_outsidevolumehf = 1;
758 buf->dirty.bit.air_absorb = 1;
759 buf->dirty.bit.flags = 1;
760 return DS_OK;
762 return DSERR_INVALIDPARAM;
763 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
764 if(cbPropData >= sizeof(EAXOBSTRUCTIONPROPERTIES))
766 union {
767 const void *v;
768 const EAXOBSTRUCTIONPROPERTIES *props;
769 } data = { pPropData };
770 TRACE("Parameters:\n\tObstruction: %ld\n\tObstruction LF Ratio: %f\n",
771 data.props->lObstruction, data.props->flObstructionLFRatio);
773 buf->deferred.eax.lObstruction = data.props->lObstruction;
774 buf->deferred.eax.flObstructionLFRatio = data.props->flObstructionLFRatio;
775 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
777 buf->dirty.bit.dry_filter = 1;
778 return DS_OK;
780 return DSERR_INVALIDPARAM;
781 case EAXSOURCE_OCCLUSIONPARAMETERS:
782 if(cbPropData >= sizeof(EAXOCCLUSIONPROPERTIES))
784 union {
785 const void *v;
786 const EAXOCCLUSIONPROPERTIES *props;
787 } data = { pPropData };
788 TRACE("Parameters:\n\tOcclusion: %ld\n\tOcclusion LF Ratio: %f\n\t"
789 "Occlusion Room Ratio: %f\n\tOcclusion Direct Ratio: %f\n",
790 data.props->lOcclusion, data.props->flOcclusionLFRatio,
791 data.props->flOcclusionRoomRatio, data.props->flOcclusionDirectRatio
794 buf->deferred.eax.lOcclusion = data.props->lOcclusion;
795 buf->deferred.eax.flOcclusionLFRatio = data.props->flOcclusionLFRatio;
796 buf->deferred.eax.flOcclusionRoomRatio = data.props->flOcclusionRoomRatio;
797 buf->deferred.eax.flOcclusionDirectRatio = data.props->flOcclusionDirectRatio;
798 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
800 buf->dirty.bit.dry_filter = 1;
801 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
802 return DS_OK;
804 return DSERR_INVALIDPARAM;
805 case EAXSOURCE_EXCLUSIONPARAMETERS:
806 if(cbPropData >= sizeof(EAXEXCLUSIONPROPERTIES))
808 union {
809 const void *v;
810 const EAXEXCLUSIONPROPERTIES *props;
811 } data = { pPropData };
812 TRACE("Parameters:\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n",
813 data.props->lExclusion, data.props->flExclusionLFRatio);
815 buf->deferred.eax.lExclusion = data.props->lExclusion;
816 buf->deferred.eax.flExclusionLFRatio = data.props->flExclusionLFRatio;
817 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
819 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
820 return DS_OK;
822 return DSERR_INVALIDPARAM;
824 case EAXSOURCE_DIRECT:
825 if(cbPropData >= sizeof(long))
827 union { const void *v; const long *l; } data = { pPropData };
828 TRACE("Direct: %ld\n", *data.l);
830 buf->deferred.eax.lDirect = *data.l;
831 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
833 buf->dirty.bit.dry_filter = 1;
834 return DS_OK;
836 return DSERR_INVALIDPARAM;
837 case EAXSOURCE_DIRECTHF:
838 if(cbPropData >= sizeof(long))
840 union { const void *v; const long *l; } data = { pPropData };
841 TRACE("Direct HF: %ld\n", *data.l);
843 buf->deferred.eax.lDirectHF = *data.l;
844 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
846 buf->dirty.bit.dry_filter = 1;
847 return DS_OK;
849 return DSERR_INVALIDPARAM;
851 case EAXSOURCE_ROOM:
852 if(cbPropData >= sizeof(long))
854 union { const void *v; const long *l; } data = { pPropData };
855 TRACE("Room: %ld\n", *data.l);
857 buf->deferred.eax.lRoom = *data.l;
858 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
860 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
861 return DS_OK;
863 return DSERR_INVALIDPARAM;
864 case EAXSOURCE_ROOMHF:
865 if(cbPropData >= sizeof(long))
867 union { const void *v; const long *l; } data = { pPropData };
868 TRACE("Room HF: %ld\n", *data.l);
870 buf->deferred.eax.lRoomHF = *data.l;
871 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
873 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
874 return DS_OK;
876 return DSERR_INVALIDPARAM;
878 case EAXSOURCE_OBSTRUCTION:
879 if(cbPropData >= sizeof(long))
881 union { const void *v; const long *l; } data = { pPropData };
882 TRACE("Obstruction: %ld\n", *data.l);
884 buf->deferred.eax.lObstruction = *data.l;
885 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
887 buf->dirty.bit.dry_filter = 1;
888 return DS_OK;
890 return DSERR_INVALIDPARAM;
891 case EAXSOURCE_OBSTRUCTIONLFRATIO:
892 if(cbPropData >= sizeof(float))
894 union { const void *v; const float *fl; } data = { pPropData };
895 TRACE("Obstruction LF Ratio: %f\n", *data.fl);
897 buf->deferred.eax.flObstructionLFRatio = *data.fl;
898 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
900 buf->dirty.bit.dry_filter = 1;
901 return DS_OK;
903 return DSERR_INVALIDPARAM;
905 case EAXSOURCE_OCCLUSION:
906 if(cbPropData >= sizeof(long))
908 union { const void *v; const long *l; } data = { pPropData };
909 TRACE("Occlusion: %ld\n", *data.l);
911 buf->deferred.eax.lOcclusion = *data.l;
912 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
914 buf->dirty.bit.dry_filter = 1;
915 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
916 return DS_OK;
918 return DSERR_INVALIDPARAM;
919 case EAXSOURCE_OCCLUSIONLFRATIO:
920 if(cbPropData >= sizeof(float))
922 union { const void *v; const float *fl; } data = { pPropData };
923 TRACE("Occlusion LF Ratio: %f\n", *data.fl);
925 buf->deferred.eax.flOcclusionLFRatio = *data.fl;
926 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALL_PARAMS);
928 buf->dirty.bit.dry_filter = 1;
929 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
930 return DS_OK;
932 return DSERR_INVALIDPARAM;
933 case EAXSOURCE_OCCLUSIONROOMRATIO:
934 if(cbPropData >= sizeof(float))
936 union { const void *v; const float *fl; } data = { pPropData };
937 TRACE("Occlusion Room Ratio: %f\n", *data.fl);
939 buf->deferred.eax.flOcclusionRoomRatio = *data.fl;
940 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
942 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
943 return DS_OK;
945 return DSERR_INVALIDPARAM;
946 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
947 if(cbPropData >= sizeof(float))
949 union { const void *v; const float *fl; } data = { pPropData };
950 TRACE("Occlusion Direct Ratio: %f\n", *data.fl);
952 buf->deferred.eax.flOcclusionDirectRatio = *data.fl;
953 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_DRY_PARAMS);
955 buf->dirty.bit.dry_filter = 1;
956 return DS_OK;
958 return DSERR_INVALIDPARAM;
960 case EAXSOURCE_EXCLUSION:
961 if(cbPropData >= sizeof(long))
963 union { const void *v; const long *l; } data = { pPropData };
964 TRACE("Exclusion: %ld\n", *data.l);
966 buf->deferred.eax.lExclusion = *data.l;
967 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
969 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
970 return DS_OK;
972 return DSERR_INVALIDPARAM;
973 case EAXSOURCE_EXCLUSIONLFRATIO:
974 if(cbPropData >= sizeof(float))
976 union { const void *v; const float *fl; } data = { pPropData };
977 TRACE("Exclusion LF Ratio: %f\n", *data.fl);
979 buf->deferred.eax.flExclusionLFRatio = *data.fl;
980 ApplyFilterParams(buf, &buf->deferred.eax, APPLY_ALLWET_PARAMS);
982 buf->dirty.bit.send_filter = (1<<buf->share->num_sends) - 1;
983 return DS_OK;
985 return DSERR_INVALIDPARAM;
987 case EAXSOURCE_OUTSIDEVOLUMEHF:
988 if(cbPropData >= sizeof(long))
990 union { const void *v; const long *l; } data = { pPropData };
991 TRACE("Outisde Volume HF: %ld\n", *data.l);
993 buf->deferred.eax.lOutsideVolumeHF = *data.l;
995 buf->dirty.bit.cone_outsidevolumehf = 1;
996 return DS_OK;
998 return DSERR_INVALIDPARAM;
1000 case EAXSOURCE_DOPPLERFACTOR:
1001 if(cbPropData >= sizeof(float))
1003 union { const void *v; const float *fl; } data = { pPropData };
1004 TRACE("Doppler Factor: %f\n", *data.fl);
1006 buf->deferred.eax.flDopplerFactor = *data.fl;
1008 buf->dirty.bit.doppler = 1;
1009 return DS_OK;
1011 return DSERR_INVALIDPARAM;
1013 case EAXSOURCE_ROLLOFFFACTOR:
1014 if(cbPropData >= sizeof(float))
1016 union { const void *v; const float *fl; } data = { pPropData };
1017 TRACE("Rolloff Factor: %f\n", *data.fl);
1019 buf->deferred.eax.flRolloffFactor = *data.fl;
1021 buf->dirty.bit.rolloff = 1;
1022 return DS_OK;
1024 return DSERR_INVALIDPARAM;
1026 case EAXSOURCE_ROOMROLLOFFFACTOR:
1027 if(cbPropData >= sizeof(float))
1029 union { const void *v; const float *fl; } data = { pPropData };
1030 TRACE("Room Rolloff Factor: %f\n", *data.fl);
1032 buf->deferred.eax.flRoomRolloffFactor = *data.fl;
1034 buf->dirty.bit.room_rolloff = 1;
1035 return DS_OK;
1037 return DSERR_INVALIDPARAM;
1039 case EAXSOURCE_AIRABSORPTIONFACTOR:
1040 if(cbPropData >= sizeof(float))
1042 union { const void *v; const float *fl; } data = { pPropData };
1043 TRACE("Air Absorb Factor: %f\n", *data.fl);
1045 buf->deferred.eax.flAirAbsorptionFactor = *data.fl;
1047 buf->dirty.bit.air_absorb = 1;
1048 return DS_OK;
1050 return DSERR_INVALIDPARAM;
1052 case EAXSOURCE_FLAGS:
1053 if(cbPropData >= sizeof(DWORD))
1055 union { const void *v; const DWORD *dw; } data = { pPropData };
1056 TRACE("Flags: 0x%lx\n", *data.dw);
1058 buf->deferred.eax.dwFlags = *data.dw;
1060 buf->dirty.bit.flags = 1;
1061 return DS_OK;
1063 return DSERR_INVALIDPARAM;
1065 case EAXSOURCE_SENDPARAMETERS:
1066 if(cbPropData >= sizeof(EAXSOURCESENDPROPERTIES))
1068 union { const void *v; const EAXSOURCESENDPROPERTIES *send; } data = { pPropData };
1069 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1070 LONG count = cbPropData / sizeof(EAXSOURCESENDPROPERTIES);
1071 LONG wetmask=0, i;
1073 if(count > buf->share->num_sends)
1075 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1076 return DSERR_INVALIDPARAM;
1079 for(i = 0;i < count;++i)
1081 TRACE("Send parameters:\n\tReceiving: %s\n\tSend: %ld\n\tSend HF: %ld\n",
1082 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1083 data.send[i].lSend, data.send[i].lSendHF
1085 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1086 if(!srcsend[i])
1088 ERR("Failed to find active FXSlot target: %s\n",
1089 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1090 return DSERR_INVALIDPARAM;
1092 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1095 for(i = 0;i < count;++i)
1097 srcsend[i]->lSend = data.send[i].lSend;
1098 srcsend[i]->lSendHF = data.send[i].lSendHF;
1100 ApplyFilterParams(buf, &buf->deferred.eax, wetmask);
1102 buf->dirty.bit.send_filter |= wetmask;
1103 return DS_OK;
1105 return DSERR_INVALIDPARAM;
1106 case EAXSOURCE_ALLSENDPARAMETERS:
1107 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1109 union { const void *v; const EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1110 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1111 LONG count = cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES);
1112 LONG wetmask=0, i;
1114 if(count > buf->share->num_sends)
1116 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1117 return DSERR_INVALIDPARAM;
1120 for(i = 0;i < count;++i)
1122 TRACE("All send parameters:\n\tReceiving: %s\n\tSend: %ld\n\tSend HF: %ld\n\t"
1123 "Occlusion: %ld\n\tOcclusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
1124 "Occlusion Direct Ratio: %f\n\tExclusion: %ld\n\tExclusion LF Ratio: %f\n",
1125 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1126 data.send[i].lSend, data.send[i].lSendHF, data.send[i].lOcclusion,
1127 data.send[i].flOcclusionLFRatio, data.send[i].flOcclusionRoomRatio,
1128 data.send[i].flOcclusionDirectRatio, data.send[i].lExclusion,
1129 data.send[i].flExclusionLFRatio
1131 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1132 if(!srcsend[i])
1134 ERR("Failed to find active FXSlot target: %s\n",
1135 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1136 return DSERR_INVALIDPARAM;
1138 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1141 for(i = 0;i < count;++i)
1143 srcsend[i]->lSend = data.send[i].lSend;
1144 srcsend[i]->lSendHF = data.send[i].lSendHF;
1145 srcsend[i]->lOcclusion = data.send[i].lOcclusion;
1146 srcsend[i]->flOcclusionLFRatio = data.send[i].flOcclusionLFRatio;
1147 srcsend[i]->flOcclusionRoomRatio = data.send[i].flOcclusionRoomRatio;
1148 srcsend[i]->flOcclusionDirectRatio = data.send[i].flOcclusionDirectRatio;
1149 srcsend[i]->lExclusion = data.send[i].lExclusion;
1150 srcsend[i]->flExclusionLFRatio = data.send[i].flExclusionLFRatio;
1152 ApplyFilterParams(buf, &buf->deferred.eax, wetmask|APPLY_DRY_PARAMS);
1154 buf->dirty.bit.dry_filter = 1;
1155 buf->dirty.bit.send_filter |= wetmask;
1156 return DS_OK;
1158 return DSERR_INVALIDPARAM;
1159 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1160 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1162 union { const void *v; const EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1163 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1164 LONG count = cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES);
1165 LONG wetmask=0, i;
1167 if(count > buf->share->num_sends)
1169 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1170 return DSERR_INVALIDPARAM;
1173 for(i = 0;i < count;++i)
1175 TRACE("Occlusion send parameters:\n\tReceiving: %s\n\tOcclusion: %ld\n\t"
1176 "Occlusion LF Ratio: %f\n\tOcclusion Room Ratio: %f\n\t"
1177 "Occlusion Direct Ratio: %f\n",
1178 debug_fxslot(&data.send[i].guidReceivingFXSlotID), data.send[i].lOcclusion,
1179 data.send[i].flOcclusionLFRatio, data.send[i].flOcclusionRoomRatio,
1180 data.send[i].flOcclusionDirectRatio
1182 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1183 if(!srcsend[i])
1185 ERR("Failed to find active FXSlot target: %s\n",
1186 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1187 return DSERR_INVALIDPARAM;
1189 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1192 for(i = 0;i < count;++i)
1194 srcsend[i]->lOcclusion = data.send[i].lOcclusion;
1195 srcsend[i]->flOcclusionLFRatio = data.send[i].flOcclusionLFRatio;
1196 srcsend[i]->flOcclusionRoomRatio = data.send[i].flOcclusionRoomRatio;
1197 srcsend[i]->flOcclusionDirectRatio = data.send[i].flOcclusionDirectRatio;
1199 ApplyFilterParams(buf, &buf->deferred.eax, wetmask|APPLY_DRY_PARAMS);
1201 buf->dirty.bit.dry_filter = 1;
1202 buf->dirty.bit.send_filter |= wetmask;
1203 return DS_OK;
1205 return DSERR_INVALIDPARAM;
1206 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1207 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1209 union { const void *v; const EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1210 struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1211 LONG count = cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES);
1212 LONG wetmask=0, i;
1214 if(count > buf->share->num_sends)
1216 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1217 return DSERR_INVALIDPARAM;
1220 for(i = 0;i < count;++i)
1222 TRACE("Exclusion send parameters:\n\tReceiving: %s\n\tExclusion: %ld\n\t"
1223 "Exclusion LF Ratio: %f\n",
1224 debug_fxslot(&data.send[i].guidReceivingFXSlotID),
1225 data.send[i].lExclusion, data.send[i].flExclusionLFRatio
1227 srcsend[i] = FindDeferredSend(buf, &data.send[i].guidReceivingFXSlotID);
1228 if(!srcsend[i])
1230 ERR("Failed to find active FXSlot target: %s\n",
1231 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1232 return DSERR_INVALIDPARAM;
1234 wetmask |= 1 << (srcsend[i]-buf->deferred.send);
1237 for(i = 0;i < count;++i)
1239 srcsend[i]->lExclusion = data.send[i].lExclusion;
1240 srcsend[i]->flExclusionLFRatio = data.send[i].flExclusionLFRatio;
1242 ApplyFilterParams(buf, &buf->deferred.eax, wetmask);
1244 buf->dirty.bit.send_filter |= wetmask;
1245 return DS_OK;
1247 return DSERR_INVALIDPARAM;
1249 case EAXSOURCE_ACTIVEFXSLOTID:
1250 if(cbPropData && (cbPropData%sizeof(GUID)) == 0)
1252 union { const void *v; const GUID *guid; } data = { pPropData };
1253 DWORD targets[EAX_MAX_ACTIVE_FXSLOTS];
1254 LONG count = cbPropData / sizeof(GUID);
1255 LONG i;
1257 if(count > buf->share->num_sends)
1259 ERR("Setting %ld sends, only %d supported\n", count, buf->share->num_sends);
1260 return DSERR_INVALIDPARAM;
1263 for(i = 0;i < count;i++)
1265 TRACE("Active FXSlot %ld: %s\n", i, debug_fxslot(&data.guid[i]));
1267 targets[i] = FXSLOT_TARGET_NULL;
1268 if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot0))
1269 targets[i] = FXSLOT_TARGET_0;
1270 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot1))
1271 targets[i] = FXSLOT_TARGET_1;
1272 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot2))
1273 targets[i] = FXSLOT_TARGET_2;
1274 else if(IsEqualGUID(&data.guid[i], &EAXPROPERTYID_EAX40_FXSlot3))
1275 targets[i] = FXSLOT_TARGET_3;
1276 else if(IsEqualGUID(&data.guid[i], &EAX_PrimaryFXSlotID))
1277 targets[i] = FXSLOT_TARGET_PRIMARY;
1278 if(targets[i] == FXSLOT_TARGET_NULL && !IsEqualGUID(&data.guid[i], &EAX_NULL_GUID))
1280 ERR("Invalid FXSlot: %s\n", debug_fxslot(&data.guid[i]));
1281 return DSERR_INVALIDPARAM;
1285 for(i = 0;i < count;++i)
1286 buf->deferred.fxslot_targets[i] = targets[i];
1287 buf->dirty.bit.send_filter |= (1<<count) - 1;
1288 return DS_OK;
1290 return DSERR_INVALIDPARAM;
1292 FIXME("Unhandled propid: 0x%08lx\n", propid);
1293 return E_PROP_ID_UNSUPPORTED;
1296 HRESULT EAX4Source_Get(DSBuffer *buf, DWORD propid, void *pPropData, ULONG cbPropData, ULONG *pcbReturned)
1298 if(!HAS_EXTENSION(buf->share, EXT_EFX))
1299 return E_PROP_ID_UNSUPPORTED;
1301 switch(propid)
1303 case EAXSOURCE_NONE:
1304 *pcbReturned = 0;
1305 return DS_OK;
1307 case EAXSOURCE_ALLPARAMETERS:
1308 GET_PROP(buf->current.eax, EAXSOURCEPROPERTIES);
1310 case EAXSOURCE_OBSTRUCTIONPARAMETERS:
1311 GET_PROP(EAXSourceObstruction(&buf->current.eax), EAXOBSTRUCTIONPROPERTIES);
1312 case EAXSOURCE_OCCLUSIONPARAMETERS:
1313 GET_PROP(EAXSourceOcclusion(&buf->current.eax), EAXOCCLUSIONPROPERTIES);
1314 case EAXSOURCE_EXCLUSIONPARAMETERS:
1315 GET_PROP(EAXSourceExclusion(&buf->current.eax), EAXEXCLUSIONPROPERTIES);
1317 case EAXSOURCE_DIRECT:
1318 GET_PROP(buf->current.eax.lDirect, long);
1319 case EAXSOURCE_DIRECTHF:
1320 GET_PROP(buf->current.eax.lDirectHF, long);
1322 case EAXSOURCE_ROOM:
1323 GET_PROP(buf->current.eax.lRoom, long);
1324 case EAXSOURCE_ROOMHF:
1325 GET_PROP(buf->current.eax.lRoomHF, long);
1327 case EAXSOURCE_OBSTRUCTION:
1328 GET_PROP(buf->current.eax.lObstruction, long);
1329 case EAXSOURCE_OBSTRUCTIONLFRATIO:
1330 GET_PROP(buf->current.eax.flObstructionLFRatio, float);
1332 case EAXSOURCE_OCCLUSION:
1333 GET_PROP(buf->current.eax.lOcclusion, long);
1334 case EAXSOURCE_OCCLUSIONLFRATIO:
1335 GET_PROP(buf->current.eax.flOcclusionLFRatio, float);
1336 case EAXSOURCE_OCCLUSIONROOMRATIO:
1337 GET_PROP(buf->current.eax.flOcclusionRoomRatio, float);
1338 case EAXSOURCE_OCCLUSIONDIRECTRATIO:
1339 GET_PROP(buf->current.eax.flOcclusionDirectRatio, float);
1341 case EAXSOURCE_EXCLUSION:
1342 GET_PROP(buf->current.eax.lExclusion, long);
1343 case EAXSOURCE_EXCLUSIONLFRATIO:
1344 GET_PROP(buf->current.eax.flExclusionLFRatio, float);
1346 case EAXSOURCE_OUTSIDEVOLUMEHF:
1347 GET_PROP(buf->current.eax.lOutsideVolumeHF, long);
1349 case EAXSOURCE_DOPPLERFACTOR:
1350 GET_PROP(buf->current.eax.flDopplerFactor, float);
1352 case EAXSOURCE_ROLLOFFFACTOR:
1353 GET_PROP(buf->current.eax.flRolloffFactor, float);
1354 case EAXSOURCE_ROOMROLLOFFFACTOR:
1355 GET_PROP(buf->current.eax.flRoomRolloffFactor, float);
1357 case EAXSOURCE_AIRABSORPTIONFACTOR:
1358 GET_PROP(buf->current.eax.flAirAbsorptionFactor, float);
1360 case EAXSOURCE_FLAGS:
1361 GET_PROP(buf->current.eax.dwFlags, DWORD);
1363 case EAXSOURCE_SENDPARAMETERS:
1364 if(cbPropData >= sizeof(EAXSOURCESENDPROPERTIES))
1366 union { void *v; EAXSOURCESENDPROPERTIES *send; } data = { pPropData };
1367 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1368 LONG count = minI(cbPropData / sizeof(EAXSOURCESENDPROPERTIES),
1369 EAX_MAX_ACTIVE_FXSLOTS);
1370 LONG i;
1372 for(i = 0;i < count;++i)
1374 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1375 if(!srcsend[i])
1377 ERR("Failed to find active FXSlot target: %s\n",
1378 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1379 return DSERR_INVALIDPARAM;
1383 for(i = 0;i < count;++i)
1385 data.send[i].lSend = srcsend[i]->lSend;
1386 data.send[i].lSendHF = srcsend[i]->lSendHF;
1388 *pcbReturned = sizeof(EAXSOURCESENDPROPERTIES)*count;
1389 return DS_OK;
1391 return DSERR_INVALIDPARAM;
1393 case EAXSOURCE_ALLSENDPARAMETERS:
1394 if(cbPropData >= sizeof(EAXSOURCEALLSENDPROPERTIES))
1396 union { void *v; EAXSOURCEALLSENDPROPERTIES *send; } data = { pPropData };
1397 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1398 LONG count = minI(cbPropData / sizeof(EAXSOURCEALLSENDPROPERTIES),
1399 EAX_MAX_ACTIVE_FXSLOTS);
1400 LONG i;
1402 for(i = 0;i < count;++i)
1404 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1405 if(!srcsend[i])
1407 ERR("Failed to find active FXSlot target: %s\n",
1408 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1409 return DSERR_INVALIDPARAM;
1413 for(i = 0;i < count;++i)
1415 data.send[i].lSend = srcsend[i]->lSend;
1416 data.send[i].lSendHF = srcsend[i]->lSendHF;
1417 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1418 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1419 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1420 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1421 data.send[i].lExclusion = srcsend[i]->lExclusion;
1422 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1424 *pcbReturned = sizeof(EAXSOURCEALLSENDPROPERTIES)*count;
1425 return DS_OK;
1427 return DSERR_INVALIDPARAM;
1428 case EAXSOURCE_OCCLUSIONSENDPARAMETERS:
1429 if(cbPropData >= sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES))
1431 union { void *v; EAXSOURCEOCCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1432 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1433 LONG count = minI(cbPropData / sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES),
1434 EAX_MAX_ACTIVE_FXSLOTS);
1435 LONG i;
1437 for(i = 0;i < count;++i)
1439 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1440 if(!srcsend[i])
1442 ERR("Failed to find active FXSlot target: %s\n",
1443 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1444 return DSERR_INVALIDPARAM;
1448 for(i = 0;i < count;++i)
1450 data.send[i].lOcclusion = srcsend[i]->lOcclusion;
1451 data.send[i].flOcclusionLFRatio = srcsend[i]->flOcclusionLFRatio;
1452 data.send[i].flOcclusionRoomRatio = srcsend[i]->flOcclusionRoomRatio;
1453 data.send[i].flOcclusionDirectRatio = srcsend[i]->flOcclusionDirectRatio;
1455 *pcbReturned = sizeof(EAXSOURCEOCCLUSIONSENDPROPERTIES)*count;
1456 return DS_OK;
1458 return DSERR_INVALIDPARAM;
1459 case EAXSOURCE_EXCLUSIONSENDPARAMETERS:
1460 if(cbPropData >= sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES))
1462 union { void *v; EAXSOURCEEXCLUSIONSENDPROPERTIES *send; } data = { pPropData };
1463 const struct Send *srcsend[EAX_MAX_ACTIVE_FXSLOTS];
1464 LONG count = minI(cbPropData / sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES),
1465 EAX_MAX_ACTIVE_FXSLOTS);
1466 LONG i;
1468 for(i = 0;i < count;++i)
1470 srcsend[i] = FindCurrentSend(buf, &data.send[i].guidReceivingFXSlotID);
1471 if(!srcsend[i])
1473 ERR("Failed to find active FXSlot target: %s\n",
1474 debug_fxslot(&data.send[i].guidReceivingFXSlotID));
1475 return DSERR_INVALIDPARAM;
1479 for(i = 0;i < count;++i)
1481 data.send[i].lExclusion = srcsend[i]->lExclusion;
1482 data.send[i].flExclusionLFRatio = srcsend[i]->flExclusionLFRatio;
1484 *pcbReturned = sizeof(EAXSOURCEEXCLUSIONSENDPROPERTIES)*count;
1485 return DS_OK;
1487 return DSERR_INVALIDPARAM;
1489 case EAXSOURCE_ACTIVEFXSLOTID:
1490 if(cbPropData >= sizeof(GUID))
1492 union { void *v; GUID *guid; } data = { pPropData };
1493 LONG count = minI(cbPropData / sizeof(GUID), EAX_MAX_ACTIVE_FXSLOTS);
1494 LONG i;
1496 for(i = 0;i < count;++i)
1498 if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_0)
1499 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot0;
1500 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_1)
1501 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot1;
1502 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_2)
1503 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot2;
1504 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_3)
1505 data.guid[i] = EAXPROPERTYID_EAX40_FXSlot3;
1506 else if(buf->current.fxslot_targets[i] == FXSLOT_TARGET_PRIMARY)
1507 data.guid[i] = EAX_PrimaryFXSlotID;
1508 else /*if(buf->current.fxslot_targets[i] >= FXSLOT_TARGET_NULL)*/
1509 data.guid[i] = EAX_NULL_GUID;
1512 *pcbReturned = sizeof(GUID)*count;
1513 return DS_OK;
1515 return DSERR_INVALIDPARAM;
1517 FIXME("Unhandled propid: 0x%08lx\n", propid);
1518 return E_PROP_ID_UNSUPPORTED;