1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
39 #include "wine/debug.h"
42 #include "dsound_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
56 #include "dsound_private.h"
58 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 #ifndef E_PROP_ID_UNSUPPORTED
62 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
67 static const IDirectSoundBufferVtbl DS8Primary_Vtbl
;
68 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl
;
69 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl
;
71 static void AL_APIENTRY
wrap_DeferUpdates(void)
72 { alcSuspendContext(alcGetCurrentContext()); }
73 static void AL_APIENTRY
wrap_ProcessUpdates(void)
74 { alcProcessContext(alcGetCurrentContext()); }
77 static void trigger_elapsed_notifies(DS8Buffer
*buf
, DWORD lastpos
, DWORD curpos
)
80 for(i
= 0; i
< buf
->nnotify
; ++i
)
82 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
83 HANDLE event
= not->hEventNotify
;
84 DWORD ofs
= not->dwOffset
;
86 if(ofs
== (DWORD
)DSBPN_OFFSETSTOP
)
92 if(ofs
< curpos
|| ofs
>= lastpos
)
98 if(ofs
>= lastpos
&& ofs
< curpos
)
103 static void trigger_stop_notifies(DS8Buffer
*buf
)
106 for(i
= 0; i
< buf
->nnotify
; ++i
)
108 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
109 if(not->dwOffset
== (DWORD
)DSBPN_OFFSETSTOP
)
110 SetEvent(not->hEventNotify
);
114 static DWORD CALLBACK
ThreadProc(void *dwUser
)
116 DS8Primary
*prim
= (DS8Primary
*)dwUser
;
120 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
122 while(GetMessageA(&msg
, NULL
, 0, 0))
124 if(msg
.message
!= WM_USER
)
127 EnterCriticalSection(&prim
->crst
);
128 setALContext(prim
->ctx
);
130 /* OpenAL doesn't support our lovely buffer extensions
131 * so just make sure enough buffers are queued
133 if(!prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
] &&
134 !prim
->SupportedExt
[SOFT_BUFFER_SUB_DATA
] &&
135 !prim
->SupportedExt
[EXT_STATIC_BUFFER
])
137 for(i
= 0;i
< prim
->nbuffers
;++i
)
139 DS8Buffer
*buf
= prim
->buffers
[i
];
140 ALint done
= 0, queued
= QBUFFERS
, state
= AL_PLAYING
;
143 if(buf
->buffer
->numsegs
== 1 || !buf
->isplaying
)
146 alGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
147 alGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
148 alGetSourcei(buf
->source
, AL_BUFFERS_PROCESSED
, &done
);
152 alSourceUnqueueBuffers(buf
->source
, 1, &which
);
153 while(queued
< QBUFFERS
)
155 which
= buf
->buffer
->buffers
[buf
->curidx
];
156 ofs
= buf
->curidx
*buf
->buffer
->segsize
;
157 if(buf
->curidx
< buf
->buffer
->numsegs
-1)
158 alBufferData(which
, buf
->buffer
->buf_format
,
159 buf
->buffer
->data
+ ofs
, buf
->buffer
->segsize
,
160 buf
->buffer
->format
.Format
.nSamplesPerSec
);
162 alBufferData(which
, buf
->buffer
->buf_format
,
163 buf
->buffer
->data
+ ofs
, buf
->buffer
->lastsegsize
,
164 buf
->buffer
->format
.Format
.nSamplesPerSec
);
166 alSourceQueueBuffers(buf
->source
, 1, &which
);
167 buf
->curidx
= (buf
->curidx
+1)%buf
->buffer
->numsegs
;
170 if(!buf
->curidx
&& !buf
->islooping
)
172 buf
->isplaying
= FALSE
;
176 if(state
!= AL_PLAYING
)
180 IDirectSoundBuffer8_Stop(&buf
->IDirectSoundBuffer8_iface
);
183 alSourcePlay(buf
->source
);
189 for(i
= 0;i
< prim
->nnotifies
;)
191 DS8Buffer
*buf
= prim
->notifies
[i
];
192 IDirectSoundBuffer8
*dsb
= &buf
->IDirectSoundBuffer8_iface
;
193 DWORD status
=0, curpos
=buf
->lastpos
;
195 IDirectSoundBuffer8_GetStatus(dsb
, &status
);
196 IDirectSoundBuffer8_GetCurrentPosition(dsb
, &curpos
, NULL
);
197 if(buf
->lastpos
!= curpos
)
199 trigger_elapsed_notifies(buf
, buf
->lastpos
, curpos
);
200 buf
->lastpos
= curpos
;
202 if(!(status
&DSBSTATUS_PLAYING
))
204 /* Remove this buffer from list and put another at the
205 * current position; don't increment i
207 trigger_stop_notifies(buf
);
208 prim
->notifies
[i
] = prim
->notifies
[--prim
->nnotifies
];
214 LeaveCriticalSection(&prim
->crst
);
220 HRESULT
DS8Primary_Create(DS8Primary
**ppv
, DS8Impl
*parent
)
222 HRESULT hr
= DSERR_OUTOFMEMORY
;
223 DS8Primary
*This
= NULL
;
224 DS3DLISTENER
*listener
;
230 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
233 This
->IDirectSoundBuffer_iface
.lpVtbl
= (IDirectSoundBufferVtbl
*)&DS8Primary_Vtbl
;
234 This
->IDirectSound3DListener_iface
.lpVtbl
= (IDirectSound3DListenerVtbl
*)&DS8Primary3D_Vtbl
;
235 This
->IKsPropertySet_iface
.lpVtbl
= (IKsPropertySetVtbl
*)&DS8PrimaryProp_Vtbl
;
237 InitializeCriticalSection(&This
->crst
);
238 This
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DS8Primary.crst");
240 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
241 wfx
= &This
->format
.Format
;
244 This
->ctx
= alcCreateContext(parent
->device
, NULL
);
247 ALCenum err
= alcGetError(parent
->device
);
248 ERR("Could not create context (0x%x)!\n", err
);
252 setALContext(This
->ctx
);
253 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
255 TRACE("Found AL_EXT_FLOAT32\n");
256 This
->SupportedExt
[EXT_FLOAT32
] = AL_TRUE
;
258 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
260 TRACE("Found AL_EXT_MCFORMATS\n");
261 This
->SupportedExt
[EXT_MCFORMATS
] = AL_TRUE
;
263 if(alIsExtensionPresent("AL_EXT_STATIC_BUFFER"))
265 TRACE("Found AL_EXT_STATIC_BUFFER\n");
266 This
->ExtAL
.BufferDataStatic
= alGetProcAddress("alBufferDataStatic");
267 This
->SupportedExt
[EXT_STATIC_BUFFER
] = AL_TRUE
;
269 if(alIsExtensionPresent("AL_SOFTX_buffer_samples"))
271 TRACE("Found AL_SOFTX_buffer_samples\n");
272 This
->ExtAL
.BufferSamplesSOFT
= alGetProcAddress("alBufferSamplesSOFT");
273 This
->ExtAL
.BufferSubSamplesSOFT
= alGetProcAddress("alBufferSubSamplesSOFT");
274 This
->ExtAL
.GetBufferSamplesSOFT
= alGetProcAddress("alGetBufferSamplesSOFT");
275 This
->ExtAL
.IsBufferFormatSupportedSOFT
= alGetProcAddress("alIsBufferFormatSupportedSOFT");
276 This
->SupportedExt
[SOFT_BUFFER_SAMPLES
] = AL_TRUE
;
278 if(alIsExtensionPresent("AL_SOFT_buffer_sub_data"))
280 TRACE("Found AL_SOFT_buffer_sub_data\n");
281 This
->ExtAL
.BufferSubData
= alGetProcAddress("alBufferSubDataSOFT");
282 This
->SupportedExt
[SOFT_BUFFER_SUB_DATA
] = AL_TRUE
;
284 if(alIsExtensionPresent("AL_SOFTX_deferred_updates"))
286 TRACE("Found AL_SOFTX_deferred_updates\n");
287 This
->ExtAL
.DeferUpdatesSOFT
= alGetProcAddress("alDeferUpdatesSOFT");
288 This
->ExtAL
.ProcessUpdatesSOFT
= alGetProcAddress("alProcessUpdatesSOFT");
289 This
->SupportedExt
[SOFT_DEFERRED_UPDATES
] = AL_TRUE
;
292 if(alcIsExtensionPresent(parent
->device
, "ALC_EXT_EFX"))
294 #define LOAD_FUNC(x) (This->ExtAL.x = alGetProcAddress("al"#x))
295 LOAD_FUNC(GenEffects
);
296 LOAD_FUNC(DeleteEffects
);
300 LOAD_FUNC(GenAuxiliaryEffectSlots
);
301 LOAD_FUNC(DeleteAuxiliaryEffectSlots
);
302 LOAD_FUNC(AuxiliaryEffectSloti
);
304 This
->SupportedExt
[EXT_EFX
] = AL_TRUE
;
306 This
->ExtAL
.GenEffects(1, &This
->effect
);
307 This
->ExtAL
.Effecti(This
->effect
, AL_EFFECT_TYPE
, AL_EFFECT_REVERB
);
309 This
->ExtAL
.GenAuxiliaryEffectSlots(1, &This
->auxslot
);
311 This
->eax_prop
= EnvironmentDefaults
[EAX_ENVIRONMENT_GENERIC
];
313 wfx
->wFormatTag
= WAVE_FORMAT_PCM
;
315 wfx
->wBitsPerSample
= 8;
316 wfx
->nSamplesPerSec
= 22050;
317 wfx
->nBlockAlign
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
318 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
321 This
->stopped
= TRUE
;
322 This
->parent
= parent
;
323 /* Apparently primary buffer size is always 32k,
324 * tested on windows with 192k 24 bits sound @ 6 channels
325 * where it will run out in 60 ms and it isn't pointer aligned
327 This
->buf_size
= 32768;
329 if(!This
->SupportedExt
[SOFT_BUFFER_SUB_DATA
] &&
330 !This
->SupportedExt
[SOFT_BUFFER_SAMPLES
] &&
331 !This
->SupportedExt
[EXT_STATIC_BUFFER
])
333 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
334 alcGetString(parent
->device
, ALC_DEVICE_SPECIFIER
));
335 ERR("Please consider using OpenAL-Soft\n");
338 if(This
->SupportedExt
[SOFT_DEFERRED_UPDATES
])
340 This
->DeferUpdates
= This
->ExtAL
.DeferUpdatesSOFT
;
341 This
->ProcessUpdates
= This
->ExtAL
.ProcessUpdatesSOFT
;
345 This
->DeferUpdates
= wrap_DeferUpdates
;
346 This
->ProcessUpdates
= wrap_ProcessUpdates
;
349 /* Make sure DS3DListener defaults are applied to OpenAL */
350 listener
= &This
->listen
;
351 listener
->dwSize
= sizeof(*listener
);
352 listener
->vPosition
.x
= 0.0;
353 listener
->vPosition
.y
= 0.0;
354 listener
->vPosition
.z
= 0.0;
355 listener
->vVelocity
.x
= 0.0;
356 listener
->vVelocity
.y
= 0.0;
357 listener
->vVelocity
.z
= 0.0;
358 listener
->vOrientFront
.x
= 0.0;
359 listener
->vOrientFront
.y
= 0.0;
360 listener
->vOrientFront
.z
= 1.0;
361 listener
->vOrientTop
.x
= 0.0;
362 listener
->vOrientTop
.y
= 1.0;
363 listener
->vOrientTop
.z
= 0.0;
364 listener
->flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
365 listener
->flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
366 listener
->flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
367 hr
= IDirectSound3DListener_SetAllParameters(&This
->IDirectSound3DListener_iface
, listener
, DS3D_IMMEDIATE
);
369 ERR("Could not set 3d parameters: %08"LONGFMT
"x\n", hr
);
371 for(nsources
= 0;nsources
< sizeof(srcs
)/sizeof(*srcs
);nsources
++)
373 alGenSources(1, &srcs
[nsources
]);
374 if(alGetError() != AL_NO_ERROR
)
377 alDeleteSources(nsources
, srcs
);
382 This
->max_sources
= nsources
;
383 This
->sizenotifies
= This
->sizebuffers
= This
->sizesources
= nsources
+1;
385 hr
= DSERR_OUTOFMEMORY
;
386 This
->sources
= HeapAlloc(GetProcessHeap(), 0, nsources
*sizeof(*This
->sources
));
387 This
->buffers
= HeapAlloc(GetProcessHeap(), 0, nsources
*sizeof(*This
->buffers
));
388 This
->notifies
= HeapAlloc(GetProcessHeap(), 0, nsources
*sizeof(*This
->notifies
));
389 if(!This
->sources
|| !This
->buffers
|| !This
->notifies
)
392 This
->thread_hdl
= CreateThread(NULL
, 0, ThreadProc
, This
, 0, &This
->thread_id
);
393 if(This
->thread_hdl
== NULL
)
400 DS8Primary_Destroy(This
);
404 void DS8Primary_Destroy(DS8Primary
*This
)
406 TRACE("Destroying primary %p\n", This
);
410 timeKillEvent(This
->timer_id
);
411 timeEndPeriod(This
->timer_res
);
412 TRACE("Killed timer\n");
416 PostThreadMessageA(This
->thread_id
, WM_QUIT
, 0, 0);
417 if(WaitForSingleObject(This
->thread_hdl
, 1000) != WAIT_OBJECT_0
)
418 ERR("Thread wait timed out");
419 CloseHandle(This
->thread_hdl
);
424 /* Calling setALContext is not appropriate here,
425 * since we *have* to unset the context before destroying it
429 EnterCriticalSection(&This
->crst
);
430 EnterCriticalSection(&openal_crst
);
431 old_ctx
= get_context();
432 if(old_ctx
!= This
->ctx
)
433 set_context(This
->ctx
);
437 while(This
->nbuffers
--)
438 DS8Buffer_Destroy(This
->buffers
[This
->nbuffers
]);
441 alDeleteSources(This
->nsources
, This
->sources
);
444 This
->ExtAL
.DeleteEffects(1, &This
->effect
);
446 This
->ExtAL
.DeleteAuxiliaryEffectSlots(1, &This
->auxslot
);
448 HeapFree(GetProcessHeap(), 0, This
->sources
);
449 HeapFree(GetProcessHeap(), 0, This
->notifies
);
450 HeapFree(GetProcessHeap(), 0, This
->buffers
);
452 set_context(old_ctx
);
453 alcDestroyContext(This
->ctx
);
454 LeaveCriticalSection(&openal_crst
);
455 LeaveCriticalSection(&This
->crst
);
458 This
->crst
.DebugInfo
->Spare
[0] = 0;
459 DeleteCriticalSection(&This
->crst
);
461 HeapFree(GetProcessHeap(), 0, This
);
464 static inline DS8Primary
*impl_from_IDirectSoundBuffer(IDirectSoundBuffer
*iface
)
466 return CONTAINING_RECORD(iface
, DS8Primary
, IDirectSoundBuffer_iface
);
469 static HRESULT WINAPI
DS8Primary_QueryInterface(IDirectSoundBuffer
*iface
, REFIID riid
, LPVOID
*ppv
)
471 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
473 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
476 if(IsEqualIID(riid
, &IID_IUnknown
) ||
477 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
478 *ppv
= &This
->IDirectSoundBuffer_iface
;
479 else if(IsEqualIID(riid
, &IID_IDirectSound3DListener
))
481 if((This
->flags
&DSBCAPS_CTRL3D
))
482 *ppv
= &This
->IDirectSound3DListener_iface
;
485 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
489 IUnknown_AddRef((IUnknown
*)*ppv
);
493 return E_NOINTERFACE
;
496 static ULONG WINAPI
DS8Primary_AddRef(IDirectSoundBuffer
*iface
)
498 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
501 ret
= InterlockedIncrement(&This
->ref
);
502 if(ret
== 1) This
->flags
= 0;
507 static ULONG WINAPI
DS8Primary_Release(IDirectSoundBuffer
*iface
)
509 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
512 ret
= InterlockedDecrement(&This
->ref
);
517 static HRESULT WINAPI
DS8Primary_GetCaps(IDirectSoundBuffer
*iface
, DSBCAPS
*caps
)
519 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
521 TRACE("(%p)->(%p)\n", iface
, caps
);
523 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
525 WARN("Invalid DSBCAPS (%p, %"LONGFMT
"u)\n", caps
, caps
? caps
->dwSize
: 0);
526 return DSERR_INVALIDPARAM
;
529 EnterCriticalSection(&This
->crst
);
530 caps
->dwFlags
= This
->flags
;
531 caps
->dwBufferBytes
= This
->buf_size
;
532 caps
->dwUnlockTransferRate
= 0;
533 caps
->dwPlayCpuOverhead
= 0;
534 LeaveCriticalSection(&This
->crst
);
539 static HRESULT WINAPI
DS8Primary_GetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD
*playpos
, DWORD
*curpos
)
541 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
542 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
544 EnterCriticalSection(&This
->crst
);
546 hr
= IDirectSoundBuffer8_GetCurrentPosition(This
->write_emu
, playpos
, curpos
);
547 LeaveCriticalSection(&This
->crst
);
552 static HRESULT WINAPI
DS8Primary_GetFormat(IDirectSoundBuffer
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
554 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
560 WARN("Cannot report format or format size\n");
561 return DSERR_INVALIDPARAM
;
564 EnterCriticalSection(&This
->crst
);
565 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
571 hr
= DSERR_INVALIDPARAM
;
573 memcpy(wfx
, &This
->format
.Format
, size
);
575 LeaveCriticalSection(&This
->crst
);
580 static HRESULT WINAPI
DS8Primary_GetVolume(IDirectSoundBuffer
*iface
, LONG
*volume
)
582 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
585 TRACE("(%p)->(%p)\n", iface
, volume
);
588 return DSERR_INVALIDPARAM
;
590 EnterCriticalSection(&This
->crst
);
591 if(!(This
->flags
& DSBCAPS_CTRLVOLUME
))
592 hr
= DSERR_CONTROLUNAVAIL
;
597 setALContext(This
->ctx
);
598 alGetListenerf(AL_GAIN
, &gain
);
602 *volume
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
604 LeaveCriticalSection(&This
->crst
);
609 static HRESULT WINAPI
DS8Primary_GetPan(IDirectSoundBuffer
*iface
, LONG
*pan
)
611 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
614 WARN("(%p)->(%p): semi-stub\n", iface
, pan
);
617 return DSERR_INVALIDPARAM
;
619 EnterCriticalSection(&This
->crst
);
621 hr
= IDirectSoundBuffer8_GetPan(This
->write_emu
, pan
);
622 else if(!(This
->flags
& DSBCAPS_CTRLPAN
))
623 hr
= DSERR_CONTROLUNAVAIL
;
626 LeaveCriticalSection(&This
->crst
);
631 static HRESULT WINAPI
DS8Primary_GetFrequency(IDirectSoundBuffer
*iface
, DWORD
*freq
)
633 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
636 WARN("(%p)->(%p): semi-stub\n", iface
, freq
);
639 return DSERR_INVALIDPARAM
;
641 EnterCriticalSection(&This
->crst
);
642 if(!(This
->flags
& DSBCAPS_CTRLFREQUENCY
))
643 hr
= DSERR_CONTROLUNAVAIL
;
645 *freq
= This
->format
.Format
.nSamplesPerSec
;
646 LeaveCriticalSection(&This
->crst
);
651 static HRESULT WINAPI
DS8Primary_GetStatus(IDirectSoundBuffer
*iface
, DWORD
*status
)
653 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
655 TRACE("(%p)->(%p)\n", iface
, status
);
658 return DSERR_INVALIDPARAM
;
660 EnterCriticalSection(&This
->crst
);
662 *status
= DSBSTATUS_PLAYING
|DSBSTATUS_LOOPING
;
663 if((This
->flags
&DSBCAPS_LOCDEFER
))
664 *status
|= DSBSTATUS_LOCHARDWARE
;
671 for(i
= 0;i
< This
->nbuffers
;++i
)
673 hr
= IDirectSoundBuffer8_GetStatus(&This
->buffers
[i
]->IDirectSoundBuffer8_iface
, &state
);
674 if(SUCCEEDED(hr
) && (state
&DSBSTATUS_PLAYING
))
677 if(i
== This
->nbuffers
)
679 /* Primary stopped and no buffers playing.. */
684 LeaveCriticalSection(&This
->crst
);
689 static HRESULT WINAPI
DS8Primary_Initialize(IDirectSoundBuffer
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
691 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
694 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
696 if(!desc
|| desc
->lpwfxFormat
|| desc
->dwBufferBytes
)
698 WARN("Bad DSBDESC for primary buffer\n");
699 return DSERR_INVALIDPARAM
;
701 if((desc
->dwFlags
&DSBCAPS_CTRLFX
) ||
702 (desc
->dwFlags
&DSBCAPS_CTRLPOSITIONNOTIFY
) ||
703 (desc
->dwFlags
&DSBCAPS_LOCSOFTWARE
))
705 WARN("Bad dwFlags %08"LONGFMT
"x\n", desc
->dwFlags
);
706 return DSERR_INVALIDPARAM
;
709 EnterCriticalSection(&This
->crst
);
710 /* Should be 0 if not initialized */
713 hr
= DSERR_ALREADYINITIALIZED
;
717 if(This
->parent
->prio_level
== DSSCL_WRITEPRIMARY
)
719 DSBUFFERDESC emudesc
;
724 ERR("There shouldn't be a write_emu!\n");
725 IDirectSoundBuffer8_Release(This
->write_emu
);
726 This
->write_emu
= NULL
;
729 memset(&emudesc
, 0, sizeof(emudesc
));
730 emudesc
.dwSize
= sizeof(emudesc
);
731 emudesc
.dwFlags
= DSBCAPS_LOCHARDWARE
| (desc
->dwFlags
&DSBCAPS_CTRLPAN
);
732 /* Dont play last incomplete sample */
733 emudesc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
%This
->format
.Format
.nBlockAlign
);
734 emudesc
.lpwfxFormat
= &This
->format
.Format
;
736 hr
= DS8Buffer_Create(&emu
, This
, NULL
);
739 This
->write_emu
= &emu
->IDirectSoundBuffer8_iface
;
740 hr
= IDirectSoundBuffer8_Initialize(This
->write_emu
, ds
, &emudesc
);
743 IDirectSoundBuffer8_Release(This
->write_emu
);
744 This
->write_emu
= NULL
;
750 This
->flags
= desc
->dwFlags
| DSBCAPS_LOCHARDWARE
;
752 LeaveCriticalSection(&This
->crst
);
756 static HRESULT WINAPI
DS8Primary_Lock(IDirectSoundBuffer
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
758 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
759 HRESULT hr
= DSERR_PRIOLEVELNEEDED
;
761 TRACE("(%p)->(%"LONGFMT
"u, %"LONGFMT
"u, %p, %p, %p, %p, %"LONGFMT
"u)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
763 EnterCriticalSection(&This
->crst
);
765 hr
= IDirectSoundBuffer8_Lock(This
->write_emu
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
766 LeaveCriticalSection(&This
->crst
);
771 static HRESULT WINAPI
DS8Primary_Play(IDirectSoundBuffer
*iface
, DWORD res1
, DWORD res2
, DWORD flags
)
773 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
776 TRACE("(%p)->(%"LONGFMT
"u, %"LONGFMT
"u, %"LONGFMT
"u)\n", iface
, res1
, res2
, flags
);
778 if(!(flags
& DSBPLAY_LOOPING
))
780 WARN("Flags (%08"LONGFMT
"x) not set to DSBPLAY_LOOPING\n", flags
);
781 return DSERR_INVALIDPARAM
;
784 EnterCriticalSection(&This
->crst
);
787 hr
= IDirectSoundBuffer8_Play(This
->write_emu
, res1
, res2
, flags
);
789 This
->stopped
= FALSE
;
790 LeaveCriticalSection(&This
->crst
);
795 static HRESULT WINAPI
DS8Primary_SetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD pos
)
797 WARN("(%p)->(%"LONGFMT
"u)\n", iface
, pos
);
798 return DSERR_INVALIDCALL
;
801 /* Just assume the format is crap, and clean up the damage */
802 static void copy_waveformat(WAVEFORMATEX
*wfx
, const WAVEFORMATEX
*from
)
804 if(from
->wFormatTag
== WAVE_FORMAT_PCM
)
807 if(from
->wBitsPerSample
== 8 ||
808 from
->wBitsPerSample
== 16 ||
809 from
->wBitsPerSample
== 24 ||
810 from
->wBitsPerSample
== 32)
811 wfx
->wBitsPerSample
= from
->wBitsPerSample
;
813 else if(from
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
815 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)wfx
;
816 const WAVEFORMATEXTENSIBLE
*fromx
= (const WAVEFORMATEXTENSIBLE
*)from
;
817 DWORD size
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
819 /* Fail silently.. */
820 if(from
->cbSize
< size
)
822 if(!fromx
->Samples
.wValidBitsPerSample
&&
823 !fromx
->Format
.wBitsPerSample
)
826 if(!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
827 !IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))
829 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe
->SubFormat
));
833 wfe
->Format
.wBitsPerSample
= from
->wBitsPerSample
;
834 wfe
->Samples
.wValidBitsPerSample
= fromx
->Samples
.wValidBitsPerSample
;
835 if(!wfe
->Samples
.wValidBitsPerSample
)
836 wfe
->Samples
.wValidBitsPerSample
= wfe
->Format
.wBitsPerSample
;
837 wfe
->Format
.cbSize
= size
;
838 wfe
->dwChannelMask
= fromx
->dwChannelMask
;
839 wfe
->SubFormat
= fromx
->SubFormat
;
843 ERR("Unhandled format tag %04x\n", from
->wFormatTag
);
848 wfx
->nChannels
= from
->nChannels
;
849 wfx
->wFormatTag
= from
->wFormatTag
;
850 if(from
->nSamplesPerSec
>= DSBFREQUENCY_MIN
&&
851 from
->nSamplesPerSec
<= DSBFREQUENCY_MAX
)
852 wfx
->nSamplesPerSec
= from
->nSamplesPerSec
;
853 wfx
->nBlockAlign
= wfx
->wBitsPerSample
* wfx
->nChannels
/ 8;
854 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
857 static HRESULT WINAPI
DS8Primary_SetFormat(IDirectSoundBuffer
*iface
, const WAVEFORMATEX
*wfx
)
859 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
863 TRACE("(%p)->(%p)\n", iface
, wfx
);
867 WARN("Missing format\n");
868 return DSERR_INVALIDPARAM
;
871 EnterCriticalSection(&This
->crst
);
873 if(This
->parent
->prio_level
< DSSCL_PRIORITY
)
875 hr
= DSERR_PRIOLEVELNEEDED
;
879 TRACE("Requested primary format:\n"
880 " FormatTag = %04x\n"
882 " SamplesPerSec = %"LONGFMT
"u\n"
883 " AvgBytesPerSec = %"LONGFMT
"u\n"
885 " BitsPerSample = %u\n",
886 wfx
->wFormatTag
, wfx
->nChannels
,
887 wfx
->nSamplesPerSec
, wfx
->nAvgBytesPerSec
,
888 wfx
->nBlockAlign
, wfx
->wBitsPerSample
);
890 copy_waveformat(&This
->format
.Format
, wfx
);
892 freq
= This
->format
.Format
.nSamplesPerSec
;
893 alcGetIntegerv(This
->parent
->device
, ALC_FREQUENCY
, 1, &freq
);
894 checkALCError(This
->parent
->device
);
896 This
->format
.Format
.nSamplesPerSec
= freq
;
897 This
->format
.Format
.nAvgBytesPerSec
= This
->format
.Format
.nBlockAlign
*
898 This
->format
.Format
.nSamplesPerSec
;
905 memset(&desc
, 0, sizeof(desc
));
906 desc
.dwSize
= sizeof(desc
);
907 desc
.dwFlags
= DSBCAPS_LOCHARDWARE
|DSBCAPS_CTRLPAN
;
908 desc
.dwBufferBytes
= This
->buf_size
- (This
->buf_size
% This
->format
.Format
.nBlockAlign
);
909 desc
.lpwfxFormat
= &This
->format
.Format
;
911 hr
= DS8Buffer_Create(&buf
, This
, NULL
);
915 hr
= IDirectSoundBuffer8_Initialize(&buf
->IDirectSoundBuffer8_iface
, &This
->parent
->IDirectSound_iface
, &desc
);
917 DS8Buffer_Destroy(buf
);
920 IDirectSoundBuffer8_Release(This
->write_emu
);
921 This
->write_emu
= &buf
->IDirectSoundBuffer8_iface
;
926 LeaveCriticalSection(&This
->crst
);
930 static HRESULT WINAPI
DS8Primary_SetVolume(IDirectSoundBuffer
*iface
, LONG vol
)
932 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
935 TRACE("(%p)->(%"LONGFMT
"d)\n", iface
, vol
);
937 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
939 WARN("Invalid volume (%"LONGFMT
"d)\n", vol
);
940 return DSERR_INVALIDPARAM
;
943 EnterCriticalSection(&This
->crst
);
944 if(!(This
->flags
&DSBCAPS_CTRLVOLUME
))
945 hr
= DSERR_CONTROLUNAVAIL
;
948 setALContext(This
->ctx
);
949 alListenerf(AL_GAIN
, mB_to_gain(vol
));
952 LeaveCriticalSection(&This
->crst
);
957 static HRESULT WINAPI
DS8Primary_SetPan(IDirectSoundBuffer
*iface
, LONG pan
)
959 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
962 TRACE("(%p)->(%"LONGFMT
"d)\n", iface
, pan
);
964 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
966 WARN("invalid parameter: pan = %"LONGFMT
"d\n", pan
);
967 return DSERR_INVALIDPARAM
;
970 EnterCriticalSection(&This
->crst
);
971 if(!(This
->flags
&DSBCAPS_CTRLPAN
))
973 WARN("control unavailable\n");
974 hr
= DSERR_CONTROLUNAVAIL
;
976 else if(This
->write_emu
)
977 hr
= IDirectSoundBuffer8_SetPan(This
->write_emu
, pan
);
980 FIXME("Not supported\n");
983 LeaveCriticalSection(&This
->crst
);
988 static HRESULT WINAPI
DS8Primary_SetFrequency(IDirectSoundBuffer
*iface
, DWORD freq
)
990 WARN("(%p)->(%"LONGFMT
"u)\n", iface
, freq
);
991 return DSERR_CONTROLUNAVAIL
;
994 static HRESULT WINAPI
DS8Primary_Stop(IDirectSoundBuffer
*iface
)
996 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
999 TRACE("(%p)->()\n", iface
);
1001 EnterCriticalSection(&This
->crst
);
1003 hr
= IDirectSoundBuffer8_Stop(This
->write_emu
);
1005 This
->stopped
= TRUE
;
1006 LeaveCriticalSection(&This
->crst
);
1011 static HRESULT WINAPI
DS8Primary_Unlock(IDirectSoundBuffer
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1013 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
1014 HRESULT hr
= DSERR_INVALIDCALL
;
1016 TRACE("(%p)->(%p, %"LONGFMT
"u, %p, %"LONGFMT
"u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
1018 EnterCriticalSection(&This
->crst
);
1020 hr
= IDirectSoundBuffer8_Unlock(This
->write_emu
, ptr1
, len1
, ptr2
, len2
);
1021 LeaveCriticalSection(&This
->crst
);
1026 static HRESULT WINAPI
DS8Primary_Restore(IDirectSoundBuffer
*iface
)
1028 DS8Primary
*This
= impl_from_IDirectSoundBuffer(iface
);
1031 TRACE("(%p)->()\n", iface
);
1033 EnterCriticalSection(&This
->crst
);
1035 hr
= IDirectSoundBuffer8_Restore(This
->write_emu
);
1036 LeaveCriticalSection(&This
->crst
);
1041 static const IDirectSoundBufferVtbl DS8Primary_Vtbl
=
1043 DS8Primary_QueryInterface
,
1047 DS8Primary_GetCurrentPosition
,
1048 DS8Primary_GetFormat
,
1049 DS8Primary_GetVolume
,
1051 DS8Primary_GetFrequency
,
1052 DS8Primary_GetStatus
,
1053 DS8Primary_Initialize
,
1056 DS8Primary_SetCurrentPosition
,
1057 DS8Primary_SetFormat
,
1058 DS8Primary_SetVolume
,
1060 DS8Primary_SetFrequency
,
1066 static inline DS8Primary
*impl_from_IDirectSound3DListener(IDirectSound3DListener
*iface
)
1068 return CONTAINING_RECORD(iface
, DS8Primary
, IDirectSound3DListener_iface
);
1071 static HRESULT WINAPI
DS8Primary3D_QueryInterface(IDirectSound3DListener
*iface
, REFIID riid
, void **ppv
)
1073 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1074 return DS8Primary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1077 static ULONG WINAPI
DS8Primary3D_AddRef(IDirectSound3DListener
*iface
)
1079 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1082 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1083 TRACE("new refcount %"LONGFMT
"d\n", ret
);
1089 /* Considering the primary buffer doesn't get destroyed
1090 * it doesn't make sense to destroy ds3d here
1092 static ULONG WINAPI
DS8Primary3D_Release(IDirectSound3DListener
*iface
)
1094 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1097 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1098 TRACE("new refcount %"LONGFMT
"d\n", ret
);
1104 static HRESULT WINAPI
DS8Primary3D_GetAllParameters(IDirectSound3DListener
*iface
, DS3DLISTENER
*listener
)
1106 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1108 TRACE("(%p)->(%p)\n", iface
, listener
);
1110 if(!listener
|| listener
->dwSize
< sizeof(*listener
))
1112 WARN("Invalid DS3DLISTENER %p %"LONGFMT
"u\n", listener
, listener
? listener
->dwSize
: 0);
1113 return DSERR_INVALIDPARAM
;
1116 EnterCriticalSection(&This
->crst
);
1117 setALContext(This
->ctx
);
1118 IDirectSound3DListener_GetPosition(iface
, &listener
->vPosition
);
1119 IDirectSound3DListener_GetVelocity(iface
, &listener
->vVelocity
);
1120 IDirectSound3DListener_GetOrientation(iface
, &listener
->vOrientFront
, &listener
->vOrientTop
);
1121 IDirectSound3DListener_GetDistanceFactor(iface
, &listener
->flDistanceFactor
);
1122 IDirectSound3DListener_GetRolloffFactor(iface
, &listener
->flRolloffFactor
);
1123 IDirectSound3DListener_GetRolloffFactor(iface
, &listener
->flDopplerFactor
);
1125 LeaveCriticalSection(&This
->crst
);
1130 static HRESULT WINAPI
DS8Primary3D_GetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE
*distancefactor
)
1132 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1134 TRACE("(%p)->(%p)\n", iface
, distancefactor
);
1138 WARN("Invalid parameter %p\n", distancefactor
);
1139 return DSERR_INVALIDPARAM
;
1142 EnterCriticalSection(&This
->crst
);
1143 setALContext(This
->ctx
);
1145 *distancefactor
= 343.3f
/alGetFloat(AL_SPEED_OF_SOUND
);
1149 LeaveCriticalSection(&This
->crst
);
1154 static HRESULT WINAPI
DS8Primary3D_GetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE
*dopplerfactor
)
1156 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1158 TRACE("(%p)->(%p)\n", iface
, dopplerfactor
);
1162 WARN("Invalid parameter %p\n", dopplerfactor
);
1163 return DSERR_INVALIDPARAM
;
1166 EnterCriticalSection(&This
->crst
);
1167 setALContext(This
->ctx
);
1169 *dopplerfactor
= alGetFloat(AL_DOPPLER_FACTOR
);
1173 LeaveCriticalSection(&This
->crst
);
1178 static HRESULT WINAPI
DS8Primary3D_GetOrientation(IDirectSound3DListener
*iface
, D3DVECTOR
*front
, D3DVECTOR
*top
)
1180 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1183 TRACE("(%p)->(%p, %p)\n", iface
, front
, top
);
1187 WARN("Invalid parameter %p %p\n", front
, top
);
1188 return DSERR_INVALIDPARAM
;
1191 EnterCriticalSection(&This
->crst
);
1192 setALContext(This
->ctx
);
1194 alGetListenerfv(AL_ORIENTATION
, orient
);
1197 front
->x
= orient
[0];
1198 front
->y
= orient
[1];
1199 front
->z
= -orient
[2];
1202 top
->z
= -orient
[5];
1205 LeaveCriticalSection(&This
->crst
);
1210 static HRESULT WINAPI
DS8Primary3D_GetPosition(IDirectSound3DListener
*iface
, D3DVECTOR
*pos
)
1212 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1215 TRACE("(%p)->(%p)\n", iface
, pos
);
1219 WARN("Invalid parameter %p\n", pos
);
1220 return DSERR_INVALIDPARAM
;
1223 EnterCriticalSection(&This
->crst
);
1224 setALContext(This
->ctx
);
1226 alGetListenerfv(AL_POSITION
, alpos
);
1234 LeaveCriticalSection(&This
->crst
);
1239 static HRESULT WINAPI
DS8Primary3D_GetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE
*rollofffactor
)
1241 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1243 TRACE("(%p)->(%p)\n", iface
, rollofffactor
);
1247 WARN("Invalid parameter %p\n", rollofffactor
);
1248 return DSERR_INVALIDPARAM
;
1251 EnterCriticalSection(&This
->crst
);
1252 *rollofffactor
= This
->rollofffactor
;
1253 LeaveCriticalSection(&This
->crst
);
1258 static HRESULT WINAPI
DS8Primary3D_GetVelocity(IDirectSound3DListener
*iface
, D3DVECTOR
*velocity
)
1260 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1263 TRACE("(%p)->(%p)\n", iface
, velocity
);
1267 WARN("Invalid parameter %p\n", velocity
);
1268 return DSERR_INVALIDPARAM
;
1271 EnterCriticalSection(&This
->crst
);
1272 setALContext(This
->ctx
);
1274 alGetListenerfv(AL_VELOCITY
, vel
);
1277 velocity
->x
= vel
[0];
1278 velocity
->y
= vel
[1];
1279 velocity
->z
= -vel
[2];
1282 LeaveCriticalSection(&This
->crst
);
1287 static HRESULT WINAPI
DS8Primary3D_SetAllParameters(IDirectSound3DListener
*iface
, const DS3DLISTENER
*listen
, DWORD apply
)
1289 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1291 TRACE("(%p)->(%p, %"LONGFMT
"u)\n", iface
, listen
, apply
);
1293 if(!listen
|| listen
->dwSize
< sizeof(*listen
))
1295 WARN("Invalid parameter %p %"LONGFMT
"u\n", listen
, listen
? listen
->dwSize
: 0);
1296 return DSERR_INVALIDPARAM
;
1299 if(listen
->flDistanceFactor
> DS3D_MAXDISTANCEFACTOR
||
1300 listen
->flDistanceFactor
< DS3D_MINDISTANCEFACTOR
)
1302 WARN("Invalid distance factor (%f)\n", listen
->flDistanceFactor
);
1303 return DSERR_INVALIDPARAM
;
1306 if(listen
->flDopplerFactor
> DS3D_MAXDOPPLERFACTOR
||
1307 listen
->flDopplerFactor
< DS3D_MINDOPPLERFACTOR
)
1309 WARN("Invalid doppler factor (%f)\n", listen
->flDopplerFactor
);
1310 return DSERR_INVALIDPARAM
;
1313 if(listen
->flRolloffFactor
< DS3D_MINROLLOFFFACTOR
||
1314 listen
->flRolloffFactor
> DS3D_MAXROLLOFFFACTOR
)
1316 WARN("Invalid rolloff factor (%f)\n", listen
->flRolloffFactor
);
1317 return DSERR_INVALIDPARAM
;
1320 EnterCriticalSection(&This
->crst
);
1321 setALContext(This
->ctx
);
1322 IDirectSound3DListener_SetPosition(iface
, listen
->vPosition
.x
, listen
->vPosition
.y
, listen
->vPosition
.z
, apply
);
1323 IDirectSound3DListener_SetVelocity(iface
, listen
->vVelocity
.x
, listen
->vVelocity
.y
, listen
->vVelocity
.z
, apply
);
1324 IDirectSound3DListener_SetOrientation(iface
, listen
->vOrientFront
.x
, listen
->vOrientFront
.y
, listen
->vOrientFront
.z
,
1325 listen
->vOrientTop
.x
, listen
->vOrientTop
.y
, listen
->vOrientTop
.z
, apply
);
1326 IDirectSound3DListener_SetDistanceFactor(iface
, listen
->flDistanceFactor
, apply
);
1327 IDirectSound3DListener_SetRolloffFactor(iface
, listen
->flRolloffFactor
, apply
);
1328 IDirectSound3DListener_SetDopplerFactor(iface
, listen
->flDopplerFactor
, apply
);
1330 LeaveCriticalSection(&This
->crst
);
1335 static HRESULT WINAPI
DS8Primary3D_SetDistanceFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1337 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1339 TRACE("(%p)->(%f, %"LONGFMT
"u)\n", iface
, factor
, apply
);
1341 if(factor
< DS3D_MINDISTANCEFACTOR
||
1342 factor
> DS3D_MAXDISTANCEFACTOR
)
1344 WARN("Invalid parameter %f\n", factor
);
1345 return DSERR_INVALIDPARAM
;
1348 EnterCriticalSection(&This
->crst
);
1349 if(apply
== DS3D_DEFERRED
)
1351 This
->listen
.flDistanceFactor
= factor
;
1352 This
->dirty
.bit
.distancefactor
= 1;
1356 setALContext(This
->ctx
);
1357 alSpeedOfSound(343.3f
/factor
);
1358 if(This
->SupportedExt
[EXT_EFX
])
1359 alListenerf(AL_METERS_PER_UNIT
, factor
);
1363 LeaveCriticalSection(&This
->crst
);
1368 static HRESULT WINAPI
DS8Primary3D_SetDopplerFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1370 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1372 TRACE("(%p)->(%f, %"LONGFMT
"u)\n", iface
, factor
, apply
);
1374 if(factor
< DS3D_MINDOPPLERFACTOR
||
1375 factor
> DS3D_MAXDOPPLERFACTOR
)
1377 WARN("Invalid parameter %f\n", factor
);
1378 return DSERR_INVALIDPARAM
;
1381 EnterCriticalSection(&This
->crst
);
1382 if(apply
== DS3D_DEFERRED
)
1384 This
->listen
.flDopplerFactor
= factor
;
1385 This
->dirty
.bit
.dopplerfactor
= 1;
1389 setALContext(This
->ctx
);
1390 alDopplerFactor(factor
);
1394 LeaveCriticalSection(&This
->crst
);
1399 static HRESULT WINAPI
DS8Primary3D_SetOrientation(IDirectSound3DListener
*iface
, D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
, D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
, DWORD apply
)
1401 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1403 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT
"u)\n", iface
, xFront
, yFront
, zFront
, xTop
, yTop
, zTop
, apply
);
1405 EnterCriticalSection(&This
->crst
);
1406 if(apply
== DS3D_DEFERRED
)
1408 This
->listen
.vOrientFront
.x
= xFront
;
1409 This
->listen
.vOrientFront
.y
= yFront
;
1410 This
->listen
.vOrientFront
.z
= zFront
;
1411 This
->listen
.vOrientTop
.x
= xTop
;
1412 This
->listen
.vOrientTop
.y
= yTop
;
1413 This
->listen
.vOrientTop
.z
= zTop
;
1414 This
->dirty
.bit
.orientation
= 1;
1418 ALfloat orient
[6] = {
1419 xFront
, yFront
, -zFront
,
1422 setALContext(This
->ctx
);
1423 alListenerfv(AL_ORIENTATION
, orient
);
1427 LeaveCriticalSection(&This
->crst
);
1432 static HRESULT WINAPI
DS8Primary3D_SetPosition(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1434 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1436 TRACE("(%p)->(%f, %f, %f, %"LONGFMT
"u)\n", iface
, x
, y
, z
, apply
);
1438 EnterCriticalSection(&This
->crst
);
1439 if(apply
== DS3D_DEFERRED
)
1441 This
->listen
.vPosition
.x
= x
;
1442 This
->listen
.vPosition
.y
= y
;
1443 This
->listen
.vPosition
.z
= z
;
1444 This
->dirty
.bit
.pos
= 1;
1448 setALContext(This
->ctx
);
1449 alListener3f(AL_POSITION
, x
, y
, -z
);
1453 LeaveCriticalSection(&This
->crst
);
1458 static HRESULT WINAPI
DS8Primary3D_SetRolloffFactor(IDirectSound3DListener
*iface
, D3DVALUE factor
, DWORD apply
)
1460 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1462 TRACE("(%p)->(%f, %"LONGFMT
"u)\n", iface
, factor
, apply
);
1464 if(factor
< DS3D_MINROLLOFFFACTOR
||
1465 factor
> DS3D_MAXROLLOFFFACTOR
)
1467 WARN("Invalid parameter %f\n", factor
);
1468 return DSERR_INVALIDPARAM
;
1471 EnterCriticalSection(&This
->crst
);
1472 if(apply
== DS3D_DEFERRED
)
1474 This
->listen
.flRolloffFactor
= factor
;
1475 This
->dirty
.bit
.rollofffactor
= 1;
1481 setALContext(This
->ctx
);
1482 for(i
= 0;i
< This
->nbuffers
;++i
)
1484 if(This
->buffers
[i
]->ds3dmode
!= DS3DMODE_DISABLE
)
1485 alSourcef(This
->buffers
[i
]->source
, AL_ROLLOFF_FACTOR
, factor
);
1490 This
->rollofffactor
= factor
;
1492 LeaveCriticalSection(&This
->crst
);
1497 static HRESULT WINAPI
DS8Primary3D_SetVelocity(IDirectSound3DListener
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1499 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1501 TRACE("(%p)->(%f, %f, %f, %"LONGFMT
"u)\n", iface
, x
, y
, z
, apply
);
1503 EnterCriticalSection(&This
->crst
);
1504 if(apply
== DS3D_DEFERRED
)
1506 This
->listen
.vVelocity
.x
= x
;
1507 This
->listen
.vVelocity
.y
= y
;
1508 This
->listen
.vVelocity
.z
= z
;
1509 This
->dirty
.bit
.vel
= 1;
1513 setALContext(This
->ctx
);
1514 alListener3f(AL_VELOCITY
, x
, y
, -z
);
1518 LeaveCriticalSection(&This
->crst
);
1523 static HRESULT WINAPI
DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener
*iface
)
1525 DS8Primary
*This
= impl_from_IDirectSound3DListener(iface
);
1526 const DS3DLISTENER
*listen
= &This
->listen
;
1529 EnterCriticalSection(&This
->crst
);
1530 setALContext(This
->ctx
);
1531 This
->DeferUpdates();
1533 if(This
->dirty
.bit
.pos
)
1534 alListener3f(AL_POSITION
, listen
->vPosition
.x
, listen
->vPosition
.y
, -listen
->vPosition
.z
);
1535 if(This
->dirty
.bit
.vel
)
1536 alListener3f(AL_VELOCITY
, listen
->vVelocity
.x
, listen
->vVelocity
.y
, -listen
->vVelocity
.z
);
1537 if(This
->dirty
.bit
.orientation
)
1539 ALfloat orient
[6] = {
1540 listen
->vOrientFront
.x
, listen
->vOrientFront
.y
, -listen
->vOrientFront
.z
,
1541 listen
->vOrientTop
.x
, listen
->vOrientTop
.y
, -listen
->vOrientTop
.z
1543 alListenerfv(AL_ORIENTATION
, orient
);
1545 if(This
->dirty
.bit
.distancefactor
)
1547 alSpeedOfSound(343.3f
/listen
->flDistanceFactor
);
1548 if(This
->SupportedExt
[EXT_EFX
])
1549 alListenerf(AL_METERS_PER_UNIT
, listen
->flDistanceFactor
);
1552 if(This
->dirty
.bit
.rollofffactor
)
1554 ALfloat rolloff
= This
->rollofffactor
;
1555 for(i
= 0;i
< This
->nbuffers
;++i
)
1557 DS8Buffer
*buf
= This
->buffers
[i
];
1558 if(buf
->ds3dmode
!= DS3DMODE_DISABLE
)
1559 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
, rolloff
);
1563 if(This
->dirty
.bit
.dopplerfactor
)
1564 alDopplerFactor(listen
->flDopplerFactor
);
1566 if(This
->dirty
.bit
.effect
)
1567 This
->ExtAL
.AuxiliaryEffectSloti(This
->auxslot
, AL_EFFECTSLOT_EFFECT
, This
->effect
);
1569 /* checkALError is here for debugging */
1572 TRACE("Dirty flags was: 0x%02x\n", This
->dirty
.flags
);
1573 This
->dirty
.flags
= 0;
1575 for(i
= 0;i
< This
->nbuffers
;++i
)
1577 DS8Buffer
*buf
= This
->buffers
[i
];
1579 if(!buf
->dirty
.flags
)
1582 if(buf
->dirty
.bit
.pos
)
1583 alSource3f(buf
->source
, AL_POSITION
,
1584 buf
->ds3dbuffer
.vPosition
.x
,
1585 buf
->ds3dbuffer
.vPosition
.y
,
1586 -buf
->ds3dbuffer
.vPosition
.z
);
1587 if(buf
->dirty
.bit
.vel
)
1588 alSource3f(buf
->source
, AL_VELOCITY
,
1589 buf
->ds3dbuffer
.vVelocity
.x
,
1590 buf
->ds3dbuffer
.vVelocity
.y
,
1591 -buf
->ds3dbuffer
.vVelocity
.z
);
1592 if(buf
->dirty
.bit
.cone_angles
)
1594 alSourcei(buf
->source
, AL_CONE_INNER_ANGLE
,
1595 buf
->ds3dbuffer
.dwInsideConeAngle
);
1596 alSourcei(buf
->source
, AL_CONE_OUTER_ANGLE
,
1597 buf
->ds3dbuffer
.dwOutsideConeAngle
);
1599 if(buf
->dirty
.bit
.cone_orient
)
1600 alSource3f(buf
->source
, AL_DIRECTION
,
1601 buf
->ds3dbuffer
.vConeOrientation
.x
,
1602 buf
->ds3dbuffer
.vConeOrientation
.y
,
1603 -buf
->ds3dbuffer
.vConeOrientation
.z
);
1604 if(buf
->dirty
.bit
.cone_outsidevolume
)
1605 alSourcef(buf
->source
, AL_CONE_OUTER_GAIN
,
1606 mB_to_gain(buf
->ds3dbuffer
.lConeOutsideVolume
));
1607 if(buf
->dirty
.bit
.min_distance
)
1608 alSourcef(buf
->source
, AL_REFERENCE_DISTANCE
, buf
->ds3dbuffer
.flMinDistance
);
1609 if(buf
->dirty
.bit
.max_distance
)
1610 alSourcef(buf
->source
, AL_MAX_DISTANCE
, buf
->ds3dbuffer
.flMaxDistance
);
1611 if(buf
->dirty
.bit
.mode
)
1613 buf
->ds3dmode
= buf
->ds3dbuffer
.dwMode
;
1614 alSourcei(buf
->source
, AL_SOURCE_RELATIVE
,
1615 (buf
->ds3dmode
!=DS3DMODE_NORMAL
) ? AL_TRUE
: AL_FALSE
);
1616 alSourcef(buf
->source
, AL_ROLLOFF_FACTOR
,
1617 (buf
->ds3dmode
==DS3DMODE_DISABLE
) ? 0.0f
: This
->rollofffactor
);
1619 buf
->dirty
.flags
= 0;
1623 This
->ProcessUpdates();
1625 LeaveCriticalSection(&This
->crst
);
1630 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl
=
1632 DS8Primary3D_QueryInterface
,
1633 DS8Primary3D_AddRef
,
1634 DS8Primary3D_Release
,
1635 DS8Primary3D_GetAllParameters
,
1636 DS8Primary3D_GetDistanceFactor
,
1637 DS8Primary3D_GetDopplerFactor
,
1638 DS8Primary3D_GetOrientation
,
1639 DS8Primary3D_GetPosition
,
1640 DS8Primary3D_GetRolloffFactor
,
1641 DS8Primary3D_GetVelocity
,
1642 DS8Primary3D_SetAllParameters
,
1643 DS8Primary3D_SetDistanceFactor
,
1644 DS8Primary3D_SetDopplerFactor
,
1645 DS8Primary3D_SetOrientation
,
1646 DS8Primary3D_SetPosition
,
1647 DS8Primary3D_SetRolloffFactor
,
1648 DS8Primary3D_SetVelocity
,
1649 DS8Primary3D_CommitDeferredSettings
1652 /* NOTE: Although the app handles listener properties through secondary buffers,
1653 * we pass the requests to the primary buffer though a propertyset interface.
1654 * These methods are not exposed to the app. */
1655 static inline DS8Primary
*impl_from_IKsPropertySet(IKsPropertySet
*iface
)
1657 return CONTAINING_RECORD(iface
, DS8Primary
, IKsPropertySet_iface
);
1660 static HRESULT WINAPI
DS8PrimaryProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
1662 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1663 return DS8Primary_QueryInterface(&This
->IDirectSoundBuffer_iface
, riid
, ppv
);
1666 static ULONG WINAPI
DS8PrimaryProp_AddRef(IKsPropertySet
*iface
)
1668 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1671 ret
= InterlockedIncrement(&This
->prop_ref
);
1672 TRACE("new refcount %"LONGFMT
"d\n", ret
);
1677 static ULONG WINAPI
DS8PrimaryProp_Release(IKsPropertySet
*iface
)
1679 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1682 ret
= InterlockedDecrement(&This
->prop_ref
);
1683 TRACE("new refcount %"LONGFMT
"d\n", ret
);
1688 static HRESULT WINAPI
DS8PrimaryProp_Get(IKsPropertySet
*iface
,
1689 REFGUID guidPropSet
, ULONG dwPropID
,
1690 LPVOID pInstanceData
, ULONG cbInstanceData
,
1691 LPVOID pPropData
, ULONG cbPropData
,
1694 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1695 HRESULT res
= E_PROP_ID_UNSUPPORTED
;
1696 (void)pInstanceData
;
1697 (void)cbInstanceData
;
1699 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
1701 EnterCriticalSection(&This
->crst
);
1703 if(This
->effect
== 0)
1704 res
= E_PROP_ID_UNSUPPORTED
;
1705 else switch(dwPropID
)
1707 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS
:
1708 res
= DSERR_INVALIDPARAM
;
1709 if(cbPropData
>= sizeof(EAXLISTENERPROPERTIES
))
1713 EAXLISTENERPROPERTIES
*props
;
1714 } data
= { pPropData
};
1716 *data
.props
= This
->eax_prop
;
1717 *pcbReturned
= sizeof(EAXLISTENERPROPERTIES
);
1722 case DSPROPERTY_EAXLISTENER_ROOM
:
1723 res
= DSERR_INVALIDPARAM
;
1724 if(cbPropData
>= sizeof(LONG
))
1729 } data
= { pPropData
};
1731 *data
.l
= This
->eax_prop
.lRoom
;
1732 *pcbReturned
= sizeof(LONG
);
1736 case DSPROPERTY_EAXLISTENER_ROOMHF
:
1737 res
= DSERR_INVALIDPARAM
;
1738 if(cbPropData
>= sizeof(LONG
))
1743 } data
= { pPropData
};
1745 *data
.l
= This
->eax_prop
.lRoomHF
;
1746 *pcbReturned
= sizeof(LONG
);
1751 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR
:
1752 res
= DSERR_INVALIDPARAM
;
1753 if(cbPropData
>= sizeof(FLOAT
))
1758 } data
= { pPropData
};
1760 *data
.fl
= This
->eax_prop
.flRoomRolloffFactor
;
1761 *pcbReturned
= sizeof(FLOAT
);
1766 case DSPROPERTY_EAXLISTENER_ENVIRONMENT
:
1767 res
= DSERR_INVALIDPARAM
;
1768 if(cbPropData
>= sizeof(DWORD
))
1773 } data
= { pPropData
};
1775 *data
.dw
= This
->eax_prop
.dwEnvironment
;
1776 *pcbReturned
= sizeof(DWORD
);
1781 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE
:
1782 res
= DSERR_INVALIDPARAM
;
1783 if(cbPropData
>= sizeof(FLOAT
))
1788 } data
= { pPropData
};
1790 *data
.fl
= This
->eax_prop
.flEnvironmentSize
;
1791 *pcbReturned
= sizeof(FLOAT
);
1795 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION
:
1796 res
= DSERR_INVALIDPARAM
;
1797 if(cbPropData
>= sizeof(FLOAT
))
1802 } data
= { pPropData
};
1804 *data
.fl
= This
->eax_prop
.flEnvironmentDiffusion
;
1805 *pcbReturned
= sizeof(FLOAT
);
1810 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
:
1811 res
= DSERR_INVALIDPARAM
;
1812 if(cbPropData
>= sizeof(FLOAT
))
1817 } data
= { pPropData
};
1819 *data
.fl
= This
->eax_prop
.flAirAbsorptionHF
;
1820 *pcbReturned
= sizeof(FLOAT
);
1825 case DSPROPERTY_EAXLISTENER_FLAGS
:
1826 res
= DSERR_INVALIDPARAM
;
1827 if(cbPropData
>= sizeof(DWORD
))
1832 } data
= { pPropData
};
1834 *data
.dw
= This
->eax_prop
.dwFlags
;
1835 *pcbReturned
= sizeof(DWORD
);
1841 FIXME("Unhandled propid: 0x%08"LONGFMT
"x\n", dwPropID
);
1845 LeaveCriticalSection(&This
->crst
);
1848 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
1853 static HRESULT WINAPI
DS8PrimaryProp_Set(IKsPropertySet
*iface
,
1854 REFGUID guidPropSet
, ULONG dwPropID
,
1855 LPVOID pInstanceData
, ULONG cbInstanceData
,
1856 LPVOID pPropData
, ULONG cbPropData
)
1858 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
1859 HRESULT res
= E_PROP_ID_UNSUPPORTED
;
1860 (void)pInstanceData
;
1861 (void)cbInstanceData
;
1863 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
1865 DWORD propid
= dwPropID
& ~DSPROPERTY_EAXLISTENER_DEFERRED
;
1866 BOOL immediate
= !(dwPropID
&DSPROPERTY_EAXLISTENER_DEFERRED
);
1868 EnterCriticalSection(&This
->crst
);
1869 setALContext(This
->ctx
);
1871 if(This
->effect
== 0)
1872 res
= E_PROP_ID_UNSUPPORTED
;
1875 case 0: /* 0 = not setting any property, just apply */
1879 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS
:
1881 res
= DSERR_INVALIDPARAM
;
1882 if(cbPropData
>= sizeof(EAXLISTENERPROPERTIES
))
1886 const EAXLISTENERPROPERTIES
*props
;
1887 } data
= { pPropData
};
1889 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1890 This
->eax_prop
= *data
.props
;
1891 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_DENSITY
,
1892 (data
.props
->flEnvironmentSize
< 2.0f
) ?
1893 (data
.props
->flEnvironmentSize
- 1.0f
) : 1.0f
);
1894 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_DIFFUSION
,
1895 data
.props
->flEnvironmentDiffusion
);
1897 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_GAIN
,
1898 mB_to_gain(data
.props
->lRoom
));
1899 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_GAINHF
,
1900 mB_to_gain(data
.props
->lRoomHF
));
1902 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_ROOM_ROLLOFF_FACTOR
,
1903 data
.props
->flRoomRolloffFactor
);
1905 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_DECAY_TIME
,
1906 data
.props
->flDecayTime
);
1907 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_DECAY_HFRATIO
,
1908 data
.props
->flDecayHFRatio
);
1910 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_REFLECTIONS_GAIN
,
1911 mB_to_gain(data
.props
->lReflections
));
1912 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_REFLECTIONS_DELAY
,
1913 data
.props
->flReflectionsDelay
);
1915 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_LATE_REVERB_GAIN
,
1916 mB_to_gain(data
.props
->lReverb
));
1917 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_LATE_REVERB_DELAY
,
1918 data
.props
->flReverbDelay
);
1920 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_AIR_ABSORPTION_GAINHF
,
1921 mB_to_gain(data
.props
->flAirAbsorptionHF
));
1923 This
->ExtAL
.Effecti(This
->effect
, AL_REVERB_DECAY_HFLIMIT
,
1924 (data
.props
->dwFlags
&EAXLISTENERFLAGS_DECAYHFLIMIT
) ?
1925 AL_TRUE
: AL_FALSE
);
1929 This
->dirty
.bit
.effect
= 1;
1934 case DSPROPERTY_EAXLISTENER_ROOM
:
1935 res
= DSERR_INVALIDPARAM
;
1936 if(cbPropData
>= sizeof(LONG
))
1941 } data
= { pPropData
};
1943 This
->eax_prop
.lRoom
= *data
.l
;
1944 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_GAIN
,
1945 mB_to_gain(This
->eax_prop
.lRoom
));
1948 This
->dirty
.bit
.effect
= 1;
1952 case DSPROPERTY_EAXLISTENER_ROOMHF
:
1953 res
= DSERR_INVALIDPARAM
;
1954 if(cbPropData
>= sizeof(LONG
))
1959 } data
= { pPropData
};
1961 This
->eax_prop
.lRoomHF
= *data
.l
;
1962 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_GAINHF
,
1963 mB_to_gain(This
->eax_prop
.lRoomHF
));
1966 This
->dirty
.bit
.effect
= 1;
1971 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR
:
1972 res
= DSERR_INVALIDPARAM
;
1973 if(cbPropData
>= sizeof(FLOAT
))
1978 } data
= { pPropData
};
1980 This
->eax_prop
.flRoomRolloffFactor
= *data
.fl
;
1981 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_ROOM_ROLLOFF_FACTOR
,
1982 This
->eax_prop
.flRoomRolloffFactor
);
1985 This
->dirty
.bit
.effect
= 1;
1990 case DSPROPERTY_EAXLISTENER_ENVIRONMENT
:
1991 res
= DSERR_INVALIDPARAM
;
1992 if(cbPropData
>= sizeof(DWORD
))
1997 } data
= { pPropData
};
1999 if(*data
.dw
< EAX_ENVIRONMENT_COUNT
)
2001 /* Get the environment index's default and pass it down to
2003 propid
= DSPROPERTY_EAXLISTENER_ALLPARAMETERS
;
2004 pPropData
= (void*)&EnvironmentDefaults
[*data
.dw
];
2005 cbPropData
= sizeof(EnvironmentDefaults
[*data
.dw
]);
2011 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE
:
2012 res
= DSERR_INVALIDPARAM
;
2013 if(cbPropData
>= sizeof(FLOAT
))
2018 } data
= { pPropData
};
2020 if(*data
.fl
>= 1.0f
&& *data
.fl
<= 100.0f
)
2022 double scale
= (*data
.fl
)/This
->eax_prop
.flEnvironmentSize
;
2024 This
->eax_prop
.flEnvironmentSize
= *data
.fl
;
2026 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_DECAYTIMESCALE
))
2028 This
->eax_prop
.flDecayTime
*= scale
;
2029 This
->eax_prop
.flDecayTime
= clampF(This
->eax_prop
.flDecayTime
, 0.1f
, 20.0f
);
2031 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_REFLECTIONSSCALE
))
2033 This
->eax_prop
.lReflections
+= gain_to_mB(1.0/scale
);
2034 This
->eax_prop
.lReflections
= clampI(This
->eax_prop
.lReflections
, -10000, 1000);
2036 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE
))
2038 This
->eax_prop
.flReflectionsDelay
*= scale
;
2039 This
->eax_prop
.flReflectionsDelay
= clampF(This
->eax_prop
.flReflectionsDelay
, 0.0f
, 0.3f
);
2041 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_REVERBSCALE
))
2043 This
->eax_prop
.lReverb
+= gain_to_mB(1.0/scale
);
2044 This
->eax_prop
.lReverb
= clampI(This
->eax_prop
.lReverb
, -10000, 2000);
2046 if((This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_REVERBDELAYSCALE
))
2048 This
->eax_prop
.flReverbDelay
*= scale
;
2049 This
->eax_prop
.flReverbDelay
= clampF(This
->eax_prop
.flReverbDelay
, 0.0f
, 0.1f
);
2052 /* Pass the updated environment properties down to ALLPARAMETERS */
2053 propid
= DSPROPERTY_EAXLISTENER_ALLPARAMETERS
;
2054 pPropData
= (void*)&This
->eax_prop
;
2055 cbPropData
= sizeof(This
->eax_prop
);
2060 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION
:
2061 res
= DSERR_INVALIDPARAM
;
2062 if(cbPropData
>= sizeof(FLOAT
))
2067 } data
= { pPropData
};
2069 This
->eax_prop
.flEnvironmentDiffusion
= *data
.fl
;
2070 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_DIFFUSION
,
2071 This
->eax_prop
.flEnvironmentDiffusion
);
2074 This
->dirty
.bit
.effect
= 1;
2079 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
:
2080 res
= DSERR_INVALIDPARAM
;
2081 if(cbPropData
>= sizeof(FLOAT
))
2086 } data
= { pPropData
};
2088 This
->eax_prop
.flAirAbsorptionHF
= *data
.fl
;
2089 This
->ExtAL
.Effectf(This
->effect
, AL_REVERB_AIR_ABSORPTION_GAINHF
,
2090 mB_to_gain(This
->eax_prop
.flAirAbsorptionHF
));
2093 This
->dirty
.bit
.effect
= 1;
2098 case DSPROPERTY_EAXLISTENER_FLAGS
:
2099 res
= DSERR_INVALIDPARAM
;
2100 if(cbPropData
>= sizeof(DWORD
))
2105 } data
= { pPropData
};
2107 This
->eax_prop
.dwFlags
= *data
.dw
;
2108 This
->ExtAL
.Effecti(This
->effect
, AL_REVERB_DECAY_HFLIMIT
,
2109 (This
->eax_prop
.dwFlags
&EAXLISTENERFLAGS_DECAYHFLIMIT
) ?
2110 AL_TRUE
: AL_FALSE
);
2113 This
->dirty
.bit
.effect
= 1;
2117 FIXME("Unhandled propid: 0x%08"LONGFMT
"x\n", propid
);
2121 if(res
== DS_OK
&& immediate
)
2122 IDirectSound3DListener_CommitDeferredSettings(&This
->IDirectSound3DListener_iface
);
2125 LeaveCriticalSection(&This
->crst
);
2128 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
2133 static HRESULT WINAPI
DS8PrimaryProp_QuerySupport(IKsPropertySet
*iface
,
2134 REFGUID guidPropSet
, ULONG dwPropID
,
2135 PULONG pTypeSupport
)
2137 DS8Primary
*This
= impl_from_IKsPropertySet(iface
);
2138 HRESULT res
= E_PROP_ID_UNSUPPORTED
;
2140 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
2142 EnterCriticalSection(&This
->crst
);
2144 if(This
->effect
== 0)
2145 res
= E_PROP_ID_UNSUPPORTED
;
2146 else if(dwPropID
== DSPROPERTY_EAXLISTENER_ALLPARAMETERS
||
2147 dwPropID
== DSPROPERTY_EAXLISTENER_ROOM
||
2148 dwPropID
== DSPROPERTY_EAXLISTENER_ROOMHF
||
2149 dwPropID
== DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR
||
2150 dwPropID
== DSPROPERTY_EAXLISTENER_ENVIRONMENT
||
2151 dwPropID
== DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE
||
2152 dwPropID
== DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION
||
2153 dwPropID
== DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
||
2154 dwPropID
== DSPROPERTY_EAXLISTENER_FLAGS
)
2156 *pTypeSupport
= KSPROPERTY_SUPPORT_GET
|KSPROPERTY_SUPPORT_SET
;
2160 FIXME("Unhandled propid: 0x%08"LONGFMT
"x\n", dwPropID
);
2162 LeaveCriticalSection(&This
->crst
);
2165 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
2170 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl
=
2172 DS8PrimaryProp_QueryInterface
,
2173 DS8PrimaryProp_AddRef
,
2174 DS8PrimaryProp_Release
,
2177 DS8PrimaryProp_QuerySupport