Build and link the version resource for Windows builds
[wine/multimedia.git] / primary.c
blob418f941db7f21b4e789ffae4ed01b6daec91a24f
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
23 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "mmreg.h"
45 #include "ks.h"
46 #include "ksmedia.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
50 #else
52 #define WINVER 0x0600
53 #include <windows.h>
54 #include <dsound.h>
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)
63 #endif
65 #endif
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()); }
76 HRESULT DS8Primary_Create(DS8Primary **ppv, DS8Impl *parent)
78 HRESULT hr = DSERR_OUTOFMEMORY;
79 DS8Primary *This = NULL;
80 DS3DLISTENER *listener;
81 WAVEFORMATEX *wfx;
82 ALuint srcs[256];
83 DWORD nsources;
85 *ppv = NULL;
86 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
87 if(!This) return hr;
89 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
90 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
91 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
93 InitializeCriticalSection(&This->crst);
94 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DS8Primary.crst");
96 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
97 wfx = &This->format.Format;
99 hr = DSERR_NODRIVER;
100 This->ctx = alcCreateContext(parent->device, NULL);
101 if(!This->ctx)
103 ALCenum err = alcGetError(parent->device);
104 ERR("Could not create context (0x%x)!\n", err);
105 goto fail;
108 setALContext(This->ctx);
109 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
111 TRACE("Found AL_EXT_FLOAT32\n");
112 This->SupportedExt[EXT_FLOAT32] = AL_TRUE;
114 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
116 TRACE("Found AL_EXT_MCFORMATS\n");
117 This->SupportedExt[EXT_MCFORMATS] = AL_TRUE;
119 if(alIsExtensionPresent("AL_EXT_STATIC_BUFFER"))
121 TRACE("Found AL_EXT_STATIC_BUFFER\n");
122 This->ExtAL.BufferDataStatic = alGetProcAddress("alBufferDataStatic");
123 This->SupportedExt[EXT_STATIC_BUFFER] = AL_TRUE;
125 if(alIsExtensionPresent("AL_SOFTX_buffer_samples"))
127 TRACE("Found AL_SOFTX_buffer_samples\n");
128 This->ExtAL.BufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
129 This->ExtAL.BufferSubSamplesSOFT = alGetProcAddress("alBufferSubSamplesSOFT");
130 This->ExtAL.GetBufferSamplesSOFT = alGetProcAddress("alGetBufferSamplesSOFT");
131 This->ExtAL.IsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
132 This->SupportedExt[SOFT_BUFFER_SAMPLES] = AL_TRUE;
134 if(alIsExtensionPresent("AL_SOFT_buffer_sub_data"))
136 TRACE("Found AL_SOFT_buffer_sub_data\n");
137 This->ExtAL.BufferSubData = alGetProcAddress("alBufferSubDataSOFT");
138 This->SupportedExt[SOFT_BUFFER_SUB_DATA] = AL_TRUE;
140 if(alIsExtensionPresent("AL_SOFTX_deferred_updates"))
142 TRACE("Found AL_SOFTX_deferred_updates\n");
143 This->ExtAL.DeferUpdates = alGetProcAddress("alDeferUpdatesSOFT");
144 This->ExtAL.ProcessUpdates = alGetProcAddress("alProcessUpdatesSOFT");
145 This->SupportedExt[SOFT_DEFERRED_UPDATES] = AL_TRUE;
147 else
149 This->ExtAL.DeferUpdates = wrap_DeferUpdates;
150 This->ExtAL.ProcessUpdates = wrap_ProcessUpdates;
153 if(alcIsExtensionPresent(parent->device, "ALC_EXT_EFX"))
155 #define LOAD_FUNC(x) (This->ExtAL.x = alGetProcAddress("al"#x))
156 LOAD_FUNC(GenEffects);
157 LOAD_FUNC(DeleteEffects);
158 LOAD_FUNC(Effecti);
159 LOAD_FUNC(Effectf);
161 LOAD_FUNC(GenAuxiliaryEffectSlots);
162 LOAD_FUNC(DeleteAuxiliaryEffectSlots);
163 LOAD_FUNC(AuxiliaryEffectSloti);
164 #undef LOAD_FUNC
165 This->SupportedExt[EXT_EFX] = AL_TRUE;
167 This->ExtAL.GenEffects(1, &This->effect);
168 This->ExtAL.Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
170 This->ExtAL.GenAuxiliaryEffectSlots(1, &This->auxslot);
172 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
174 wfx->wFormatTag = WAVE_FORMAT_PCM;
175 wfx->nChannels = 2;
176 wfx->wBitsPerSample = 8;
177 wfx->nSamplesPerSec = 22050;
178 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
179 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
180 wfx->cbSize = 0;
182 This->stopped = TRUE;
183 This->parent = parent;
184 /* Apparently primary buffer size is always 32k,
185 * tested on windows with 192k 24 bits sound @ 6 channels
186 * where it will run out in 60 ms and it isn't pointer aligned
188 This->buf_size = 32768;
190 if(!This->ExtAL.BufferSubData && !This->ExtAL.BufferSamplesSOFT &&
191 !This->ExtAL.BufferDataStatic)
193 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
194 alcGetString(parent->device, ALC_DEVICE_SPECIFIER));
195 ERR("Please consider using OpenAL-Soft\n");
198 /* Make sure DS3DListener defaults are applied to OpenAL */
199 listener = &This->listen;
200 listener->dwSize = sizeof(*listener);
201 listener->vPosition.x = 0.0;
202 listener->vPosition.y = 0.0;
203 listener->vPosition.z = 0.0;
204 listener->vVelocity.x = 0.0;
205 listener->vVelocity.y = 0.0;
206 listener->vVelocity.z = 0.0;
207 listener->vOrientFront.x = 0.0;
208 listener->vOrientFront.y = 0.0;
209 listener->vOrientFront.z = 1.0;
210 listener->vOrientTop.x = 0.0;
211 listener->vOrientTop.y = 1.0;
212 listener->vOrientTop.z = 0.0;
213 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
214 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
215 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
216 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
217 if(FAILED(hr))
218 ERR("Could not set 3d parameters: %08x\n", hr);
220 for(nsources = 0;nsources < sizeof(srcs)/sizeof(*srcs);nsources++)
222 alGenSources(1, &srcs[nsources]);
223 if(alGetError() != AL_NO_ERROR)
224 break;
226 alDeleteSources(nsources, srcs);
227 getALError();
229 popALContext();
231 This->max_sources = nsources;
232 This->sizenotifies = This->sizebuffers = This->sizesources = nsources+1;
234 hr = DSERR_OUTOFMEMORY;
235 This->sources = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->sources));
236 This->buffers = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->buffers));
237 This->notifies = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->notifies));
238 if(!This->sources || !This->buffers || !This->notifies)
239 goto fail;
241 *ppv = This;
242 return S_OK;
244 fail:
245 DS8Primary_Destroy(This);
246 return hr;
249 void DS8Primary_Destroy(DS8Primary *This)
251 TRACE("Destroying primary %p\n", This);
253 if(This->timer_id)
255 timeKillEvent(This->timer_id);
256 timeEndPeriod(This->timer_res);
257 TRACE("Killed timer\n");
260 if(This->ctx)
262 /* Calling setALContext is not appropriate here,
263 * since we *have* to unset the context before destroying it
265 ALCcontext *old_ctx;
267 EnterCriticalSection(&openal_crst);
268 old_ctx = get_context();
269 if(old_ctx != This->ctx)
270 set_context(This->ctx);
271 else
272 old_ctx = NULL;
274 while(This->nbuffers--)
275 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
277 if(This->nsources)
278 alDeleteSources(This->nsources, This->sources);
280 if(This->effect)
281 This->ExtAL.DeleteEffects(1, &This->effect);
282 if(This->auxslot)
283 This->ExtAL.DeleteAuxiliaryEffectSlots(1, &This->auxslot);
285 HeapFree(GetProcessHeap(), 0, This->sources);
286 HeapFree(GetProcessHeap(), 0, This->notifies);
287 HeapFree(GetProcessHeap(), 0, This->buffers);
289 set_context(old_ctx);
290 alcDestroyContext(This->ctx);
291 LeaveCriticalSection(&openal_crst);
294 This->crst.DebugInfo->Spare[0] = 0;
295 DeleteCriticalSection(&This->crst);
297 HeapFree(GetProcessHeap(), 0, This);
300 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
302 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
305 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
307 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
309 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
311 *ppv = NULL;
312 if(IsEqualIID(riid, &IID_IUnknown) ||
313 IsEqualIID(riid, &IID_IDirectSoundBuffer))
314 *ppv = &This->IDirectSoundBuffer_iface;
315 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
317 if((This->flags&DSBCAPS_CTRL3D))
318 *ppv = &This->IDirectSound3DListener_iface;
320 else
321 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
323 if(*ppv)
325 IUnknown_AddRef((IUnknown*)*ppv);
326 return S_OK;
329 return E_NOINTERFACE;
332 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
334 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
335 LONG ret;
337 ret = InterlockedIncrement(&This->ref);
338 if(This->ref == 1)
339 This->flags = 0;
341 return ret;
344 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
346 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
347 LONG ret;
349 ret = InterlockedDecrement(&This->ref);
351 return ret;
354 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
356 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
358 TRACE("(%p)->(%p)\n", iface, caps);
360 if(!caps || caps->dwSize < sizeof(*caps))
362 WARN("Invalid DSBCAPS (%p, %u)\n", caps, caps ? caps->dwSize : 0);
363 return DSERR_INVALIDPARAM;
366 EnterCriticalSection(&This->crst);
367 caps->dwFlags = This->flags;
368 caps->dwBufferBytes = This->buf_size;
369 caps->dwUnlockTransferRate = 0;
370 caps->dwPlayCpuOverhead = 0;
371 LeaveCriticalSection(&This->crst);
373 return DS_OK;
376 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
378 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
379 HRESULT hr = DSERR_PRIOLEVELNEEDED;
381 EnterCriticalSection(&This->crst);
382 if(This->write_emu)
383 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
384 LeaveCriticalSection(&This->crst);
386 return hr;
389 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
391 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
392 HRESULT hr = S_OK;
393 UINT size;
395 if(!wfx && !written)
397 WARN("Cannot report format or format size\n");
398 return DSERR_INVALIDPARAM;
401 EnterCriticalSection(&This->crst);
402 size = sizeof(This->format.Format) + This->format.Format.cbSize;
403 if(written)
404 *written = size;
405 if(wfx)
407 if(allocated < size)
408 hr = DSERR_INVALIDPARAM;
409 else
410 memcpy(wfx, &This->format.Format, size);
412 LeaveCriticalSection(&This->crst);
414 return hr;
417 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
419 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
420 HRESULT hr = S_OK;
422 TRACE("(%p)->(%p)\n", iface, volume);
424 if(!volume)
425 return DSERR_INVALIDPARAM;
427 EnterCriticalSection(&This->crst);
428 if(!(This->flags & DSBCAPS_CTRLVOLUME))
429 hr = DSERR_CONTROLUNAVAIL;
430 else
432 ALfloat gain;
433 LONG vol;
435 setALContext(This->ctx);
436 alGetListenerf(AL_GAIN, &gain);
437 getALError();
438 popALContext();
440 vol = gain_to_mB(gain);
441 vol = max(vol, DSBVOLUME_MIN);
442 *volume = min(vol, DSBVOLUME_MAX);
444 LeaveCriticalSection(&This->crst);
446 return hr;
449 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
451 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
452 HRESULT hr = S_OK;
454 WARN("(%p)->(%p): semi-stub\n", iface, pan);
456 if(!pan)
457 return DSERR_INVALIDPARAM;
459 EnterCriticalSection(&This->crst);
460 if(This->write_emu)
461 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
462 else if(!(This->flags & DSBCAPS_CTRLPAN))
463 hr = DSERR_CONTROLUNAVAIL;
464 else
465 *pan = 0;
466 LeaveCriticalSection(&This->crst);
468 return hr;
471 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
473 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
474 HRESULT hr = S_OK;
476 WARN("(%p)->(%p): semi-stub\n", iface, freq);
478 if(!freq)
479 return DSERR_INVALIDPARAM;
481 EnterCriticalSection(&This->crst);
482 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
483 hr = DSERR_CONTROLUNAVAIL;
484 else
485 *freq = This->format.Format.nSamplesPerSec;
486 LeaveCriticalSection(&This->crst);
488 return hr;
491 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
493 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
495 TRACE("(%p)->(%p)\n", iface, status);
497 if(!status)
498 return DSERR_INVALIDPARAM;
500 EnterCriticalSection(&This->crst);
502 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
503 if((This->flags&DSBCAPS_LOCDEFER))
504 *status |= DSBSTATUS_LOCHARDWARE;
506 if(This->stopped)
508 DWORD i, state;
509 HRESULT hr;
511 for(i = 0;i < This->nbuffers;++i)
513 hr = IDirectSoundBuffer_GetStatus((IDirectSoundBuffer*)This->buffers[i], &state);
514 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
515 break;
517 if(i == This->nbuffers)
519 /* Primary stopped and no buffers playing.. */
520 *status = 0;
524 LeaveCriticalSection(&This->crst);
526 return S_OK;
529 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
531 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
532 HRESULT hr = S_OK;
534 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
536 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
538 WARN("Bad DSBDESC for primary buffer\n");
539 return DSERR_INVALIDPARAM;
541 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
542 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
543 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
545 WARN("Bad dwFlags %08x\n", desc->dwFlags);
546 return DSERR_INVALIDPARAM;
549 EnterCriticalSection(&This->crst);
550 /* Should be 0 if not initialized */
551 if(This->flags)
553 hr = DSERR_ALREADYINITIALIZED;
554 goto out;
557 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
559 DSBUFFERDESC emudesc;
560 DS8Buffer *emu;
562 if(This->write_emu)
564 ERR("There shouldn't be a write_emu!\n");
565 IDirectSoundBuffer8_Release(This->write_emu);
566 This->write_emu = NULL;
569 memset(&emudesc, 0, sizeof(emudesc));
570 emudesc.dwSize = sizeof(emudesc);
571 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
572 /* Dont play last incomplete sample */
573 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
574 emudesc.lpwfxFormat = &This->format.Format;
576 hr = DS8Buffer_Create(&emu, This, NULL);
577 if(SUCCEEDED(hr))
579 This->write_emu = &emu->IDirectSoundBuffer8_iface;
580 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
581 if(FAILED(hr))
583 IDirectSoundBuffer8_Release(This->write_emu);
584 This->write_emu = NULL;
589 if(SUCCEEDED(hr))
590 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
591 out:
592 LeaveCriticalSection(&This->crst);
593 return hr;
596 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
598 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
599 HRESULT hr = DSERR_PRIOLEVELNEEDED;
601 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
603 EnterCriticalSection(&This->crst);
604 if(This->write_emu)
605 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
606 LeaveCriticalSection(&This->crst);
608 return hr;
611 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
613 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
614 HRESULT hr;
616 TRACE("(%p)->(%u, %u, %u)\n", iface, res1, res2, flags);
618 if(!(flags & DSBPLAY_LOOPING))
620 WARN("Flags (%08x) not set to DSBPLAY_LOOPING\n", flags);
621 return DSERR_INVALIDPARAM;
624 EnterCriticalSection(&This->crst);
625 hr = S_OK;
626 if(This->write_emu)
627 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
628 if(SUCCEEDED(hr))
629 This->stopped = FALSE;
630 LeaveCriticalSection(&This->crst);
632 return hr;
635 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
637 WARN("(%p)->(%u)\n", iface, pos);
638 return DSERR_INVALIDCALL;
641 /* Just assume the format is crap, and clean up the damage */
642 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
644 if(from->wFormatTag == WAVE_FORMAT_PCM)
646 wfx->cbSize = 0;
647 if(from->wBitsPerSample == 8 ||
648 from->wBitsPerSample == 16 ||
649 from->wBitsPerSample == 24 ||
650 from->wBitsPerSample == 32)
651 wfx->wBitsPerSample = from->wBitsPerSample;
653 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
655 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
656 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
657 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
659 /* Fail silently.. */
660 if(from->cbSize < size)
661 return;
662 if(!fromx->Samples.wValidBitsPerSample &&
663 !fromx->Format.wBitsPerSample)
664 return;
666 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
667 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
669 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
670 return;
673 wfe->Format.wBitsPerSample = from->wBitsPerSample;
674 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
675 if(!wfe->Samples.wValidBitsPerSample)
676 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
677 wfe->Format.cbSize = size;
678 wfe->dwChannelMask = fromx->dwChannelMask;
679 wfe->SubFormat = fromx->SubFormat;
681 else
683 ERR("Unhandled format tag %04x\n", from->wFormatTag);
684 return;
687 if(from->nChannels)
688 wfx->nChannels = from->nChannels;
689 wfx->wFormatTag = from->wFormatTag;
690 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
691 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
692 wfx->nSamplesPerSec = from->nSamplesPerSec;
693 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
694 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
697 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
699 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
700 HRESULT hr = S_OK;
701 ALCint freq;
703 TRACE("(%p)->(%p)\n", iface, wfx);
705 if(!wfx)
707 WARN("Missing format\n");
708 return DSERR_INVALIDPARAM;
711 EnterCriticalSection(&This->crst);
713 if(This->parent->prio_level < DSSCL_PRIORITY)
715 hr = DSERR_PRIOLEVELNEEDED;
716 goto out;
719 TRACE("Requested primary format:\n"
720 " FormatTag = %04x\n"
721 " Channels = %u\n"
722 " SamplesPerSec = %u\n"
723 " AvgBytesPerSec = %u\n"
724 " BlockAlign = %u\n"
725 " BitsPerSample = %u\n",
726 wfx->wFormatTag, wfx->nChannels,
727 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
728 wfx->nBlockAlign, wfx->wBitsPerSample);
730 copy_waveformat(&This->format.Format, wfx);
732 freq = This->format.Format.nSamplesPerSec;
733 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
734 getALCError(This->parent->device);
736 This->format.Format.nSamplesPerSec = freq;
737 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
738 This->format.Format.nSamplesPerSec;
740 if(This->write_emu)
742 DS8Buffer *buf;
743 DSBUFFERDESC desc;
745 memset(&desc, 0, sizeof(desc));
746 desc.dwSize = sizeof(desc);
747 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
748 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
749 desc.lpwfxFormat = &This->format.Format;
751 hr = DS8Buffer_Create(&buf, This, NULL);
752 if(FAILED(hr))
753 goto out;
755 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, (IDirectSound*)&This->parent->IDirectSound8_iface, &desc);
756 if(FAILED(hr))
757 DS8Buffer_Destroy(buf);
758 else
760 IDirectSoundBuffer8_Release(This->write_emu);
761 This->write_emu = &buf->IDirectSoundBuffer8_iface;
765 out:
766 LeaveCriticalSection(&This->crst);
767 return hr;
770 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
772 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
773 HRESULT hr = S_OK;
775 TRACE("(%p)->(%d)\n", iface, vol);
777 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
779 WARN("Invalid volume (%d)\n", vol);
780 return DSERR_INVALIDPARAM;
783 EnterCriticalSection(&This->crst);
784 if(!(This->flags&DSBCAPS_CTRLVOLUME))
785 hr = DSERR_CONTROLUNAVAIL;
786 if(SUCCEEDED(hr))
788 setALContext(This->ctx);
789 alListenerf(AL_GAIN, mB_to_gain(vol));
790 popALContext();
792 LeaveCriticalSection(&This->crst);
794 return hr;
797 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
799 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
800 HRESULT hr;
802 TRACE("(%p)->(%d)\n", iface, pan);
804 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
806 WARN("invalid parameter: pan = %d\n", pan);
807 return DSERR_INVALIDPARAM;
810 EnterCriticalSection(&This->crst);
811 if(!(This->flags&DSBCAPS_CTRLPAN))
813 WARN("control unavailable\n");
814 hr = DSERR_CONTROLUNAVAIL;
816 else if(This->write_emu)
817 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
818 else
820 FIXME("Not supported\n");
821 hr = E_NOTIMPL;
823 LeaveCriticalSection(&This->crst);
825 return hr;
828 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
830 WARN("(%p)->(%u)\n", iface, freq);
831 return DSERR_CONTROLUNAVAIL;
834 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
836 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
837 HRESULT hr = S_OK;
839 TRACE("(%p)->()\n", iface);
841 EnterCriticalSection(&This->crst);
842 if(This->write_emu)
843 hr = IDirectSoundBuffer8_Stop(This->write_emu);
844 if(SUCCEEDED(hr))
845 This->stopped = TRUE;
846 LeaveCriticalSection(&This->crst);
848 return hr;
851 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
853 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
854 HRESULT hr = DSERR_INVALIDCALL;
856 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
858 EnterCriticalSection(&This->crst);
859 if(This->write_emu)
860 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
861 LeaveCriticalSection(&This->crst);
863 return hr;
866 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
868 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
869 HRESULT hr = S_OK;
871 TRACE("(%p)->()\n", iface);
873 EnterCriticalSection(&This->crst);
874 if(This->write_emu)
875 hr = IDirectSoundBuffer8_Restore(This->write_emu);
876 LeaveCriticalSection(&This->crst);
878 return hr;
881 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
883 DS8Primary_QueryInterface,
884 DS8Primary_AddRef,
885 DS8Primary_Release,
886 DS8Primary_GetCaps,
887 DS8Primary_GetCurrentPosition,
888 DS8Primary_GetFormat,
889 DS8Primary_GetVolume,
890 DS8Primary_GetPan,
891 DS8Primary_GetFrequency,
892 DS8Primary_GetStatus,
893 DS8Primary_Initialize,
894 DS8Primary_Lock,
895 DS8Primary_Play,
896 DS8Primary_SetCurrentPosition,
897 DS8Primary_SetFormat,
898 DS8Primary_SetVolume,
899 DS8Primary_SetPan,
900 DS8Primary_SetFrequency,
901 DS8Primary_Stop,
902 DS8Primary_Unlock,
903 DS8Primary_Restore
906 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
908 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
911 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
913 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
914 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
917 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
919 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
920 LONG ret;
922 ret = InterlockedIncrement(&This->ds3d_ref);
923 TRACE("new refcount %d\n", ret);
925 return ret;
929 /* Considering the primary buffer doesn't get destroyed
930 * it doesn't make sense to destroy ds3d here
932 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
934 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
935 LONG ret;
937 ret = InterlockedDecrement(&This->ds3d_ref);
938 TRACE("new refcount %d\n", ret);
940 return ret;
944 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
946 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
947 // HRESULT hr;
949 TRACE("(%p)->(%p)\n", iface, listener);
951 if(!listener || listener->dwSize < sizeof(*listener))
953 WARN("Invalid DS3DLISTENER %p %u\n", listener, listener ? listener->dwSize : 0);
954 return DSERR_INVALIDPARAM;
957 EnterCriticalSection(&This->crst);
958 setALContext(This->ctx);
959 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
960 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
961 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
962 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
963 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
964 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
965 popALContext();
966 LeaveCriticalSection(&This->crst);
968 // return hr;
969 return DS_OK;
972 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
974 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
976 TRACE("(%p)->(%p)\n", iface, distancefactor);
978 if(!distancefactor)
980 WARN("Invalid parameter %p\n", distancefactor);
981 return DSERR_INVALIDPARAM;
984 EnterCriticalSection(&This->crst);
985 setALContext(This->ctx);
987 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
988 getALError();
990 popALContext();
991 LeaveCriticalSection(&This->crst);
993 return S_OK;
996 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
998 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1000 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1002 if(!dopplerfactor)
1004 WARN("Invalid parameter %p\n", dopplerfactor);
1005 return DSERR_INVALIDPARAM;
1008 EnterCriticalSection(&This->crst);
1009 setALContext(This->ctx);
1011 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1012 getALError();
1014 popALContext();
1015 LeaveCriticalSection(&This->crst);
1017 return S_OK;
1020 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1022 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1023 ALfloat orient[6];
1025 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1027 if(!front || !top)
1029 WARN("Invalid parameter %p %p\n", front, top);
1030 return DSERR_INVALIDPARAM;
1033 EnterCriticalSection(&This->crst);
1034 setALContext(This->ctx);
1036 alGetListenerfv(AL_ORIENTATION, orient);
1037 getALError();
1039 front->x = orient[0];
1040 front->y = orient[1];
1041 front->z = -orient[2];
1042 top->x = orient[3];
1043 top->y = orient[4];
1044 top->z = -orient[5];
1046 popALContext();
1047 LeaveCriticalSection(&This->crst);
1049 return S_OK;
1052 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1054 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1055 ALfloat alpos[3];
1057 TRACE("(%p)->(%p)\n", iface, pos);
1059 if(!pos)
1061 WARN("Invalid parameter %p\n", pos);
1062 return DSERR_INVALIDPARAM;
1065 EnterCriticalSection(&This->crst);
1066 setALContext(This->ctx);
1068 alGetListenerfv(AL_POSITION, alpos);
1069 getALError();
1071 pos->x = alpos[0];
1072 pos->y = alpos[1];
1073 pos->z = -alpos[2];
1075 popALContext();
1076 LeaveCriticalSection(&This->crst);
1078 return S_OK;
1081 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1083 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1085 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1087 if(!rollofffactor)
1089 WARN("Invalid parameter %p\n", rollofffactor);
1090 return DSERR_INVALIDPARAM;
1093 EnterCriticalSection(&This->crst);
1094 *rollofffactor = This->rollofffactor;
1095 LeaveCriticalSection(&This->crst);
1097 return S_OK;
1100 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1102 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1103 ALfloat vel[3];
1105 TRACE("(%p)->(%p)\n", iface, velocity);
1107 if(!velocity)
1109 WARN("Invalid parameter %p\n", velocity);
1110 return DSERR_INVALIDPARAM;
1113 EnterCriticalSection(&This->crst);
1114 setALContext(This->ctx);
1116 alGetListenerfv(AL_VELOCITY, vel);
1117 getALError();
1119 velocity->x = vel[0];
1120 velocity->y = vel[1];
1121 velocity->z = -vel[2];
1123 popALContext();
1124 LeaveCriticalSection(&This->crst);
1126 return S_OK;
1129 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1131 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1133 TRACE("(%p)->(%p, %u)\n", iface, listen, apply);
1135 if(!listen || listen->dwSize < sizeof(*listen))
1137 WARN("Invalid parameter %p %u\n", listen, listen ? listen->dwSize : 0);
1138 return DSERR_INVALIDPARAM;
1141 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1142 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1144 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1145 return DSERR_INVALIDPARAM;
1148 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1149 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1151 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1152 return DSERR_INVALIDPARAM;
1155 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1156 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1158 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1159 return DSERR_INVALIDPARAM;
1162 EnterCriticalSection(&This->crst);
1163 setALContext(This->ctx);
1164 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1165 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1166 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1167 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1168 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1169 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1170 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1171 popALContext();
1172 LeaveCriticalSection(&This->crst);
1174 return S_OK;
1177 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1179 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1181 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1183 if(factor < DS3D_MINDISTANCEFACTOR ||
1184 factor > DS3D_MAXDISTANCEFACTOR)
1186 WARN("Invalid parameter %f\n", factor);
1187 return DSERR_INVALIDPARAM;
1190 EnterCriticalSection(&This->crst);
1191 if(apply == DS3D_DEFERRED)
1193 This->listen.flDistanceFactor = factor;
1194 This->dirty.bit.distancefactor = 1;
1196 else
1198 setALContext(This->ctx);
1199 alSpeedOfSound(343.3f/factor);
1200 if(This->SupportedExt[EXT_EFX])
1201 alListenerf(AL_METERS_PER_UNIT, factor);
1202 getALError();
1203 popALContext();
1205 LeaveCriticalSection(&This->crst);
1207 return S_OK;
1210 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1212 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1214 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1216 if(factor < DS3D_MINDOPPLERFACTOR ||
1217 factor > DS3D_MAXDOPPLERFACTOR)
1219 WARN("Invalid parameter %f\n", factor);
1220 return DSERR_INVALIDPARAM;
1223 EnterCriticalSection(&This->crst);
1224 if(apply == DS3D_DEFERRED)
1226 This->listen.flDopplerFactor = factor;
1227 This->dirty.bit.dopplerfactor = 1;
1229 else
1231 setALContext(This->ctx);
1232 alDopplerFactor(factor);
1233 getALError();
1234 popALContext();
1236 LeaveCriticalSection(&This->crst);
1238 return S_OK;
1241 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1243 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1245 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1247 EnterCriticalSection(&This->crst);
1248 if(apply == DS3D_DEFERRED)
1250 This->listen.vOrientFront.x = xFront;
1251 This->listen.vOrientFront.y = yFront;
1252 This->listen.vOrientFront.z = zFront;
1253 This->listen.vOrientTop.x = xTop;
1254 This->listen.vOrientTop.y = yTop;
1255 This->listen.vOrientTop.z = zTop;
1256 This->dirty.bit.orientation = 1;
1258 else
1260 ALfloat orient[6] = {
1261 xFront, yFront, -zFront,
1262 xTop, yTop, -zTop
1264 setALContext(This->ctx);
1265 alListenerfv(AL_ORIENTATION, orient);
1266 getALError();
1267 popALContext();
1269 LeaveCriticalSection(&This->crst);
1271 return S_OK;
1274 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1276 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1278 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1280 EnterCriticalSection(&This->crst);
1281 if(apply == DS3D_DEFERRED)
1283 This->listen.vPosition.x = x;
1284 This->listen.vPosition.y = y;
1285 This->listen.vPosition.z = z;
1286 This->dirty.bit.pos = 1;
1288 else
1290 setALContext(This->ctx);
1291 alListener3f(AL_POSITION, x, y, -z);
1292 getALError();
1293 popALContext();
1295 LeaveCriticalSection(&This->crst);
1297 return S_OK;
1300 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1302 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1304 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1306 if(factor < DS3D_MINROLLOFFFACTOR ||
1307 factor > DS3D_MAXROLLOFFFACTOR)
1309 WARN("Invalid parameter %f\n", factor);
1310 return DSERR_INVALIDPARAM;
1313 EnterCriticalSection(&This->crst);
1314 if(apply == DS3D_DEFERRED)
1316 This->listen.flRolloffFactor = factor;
1317 This->dirty.bit.rollofffactor = 1;
1319 else
1321 DWORD i;
1323 setALContext(This->ctx);
1324 for(i = 0;i < This->nbuffers;++i)
1326 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1327 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1329 getALError();
1330 popALContext();
1332 This->rollofffactor = factor;
1334 LeaveCriticalSection(&This->crst);
1336 return S_OK;
1339 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1341 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1343 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1345 EnterCriticalSection(&This->crst);
1346 if(apply == DS3D_DEFERRED)
1348 This->listen.vVelocity.x = x;
1349 This->listen.vVelocity.y = y;
1350 This->listen.vVelocity.z = z;
1351 This->dirty.bit.vel = 1;
1353 else
1355 setALContext(This->ctx);
1356 alListener3f(AL_VELOCITY, x, y, -z);
1357 getALError();
1358 popALContext();
1360 LeaveCriticalSection(&This->crst);
1362 return S_OK;
1365 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1367 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1368 const DS3DLISTENER *listen = &This->listen;
1369 DWORD i;
1371 EnterCriticalSection(&This->crst);
1372 setALContext(This->ctx);
1373 This->ExtAL.DeferUpdates();
1375 if(This->dirty.bit.pos)
1376 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1377 if(This->dirty.bit.vel)
1378 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1379 if(This->dirty.bit.orientation)
1381 ALfloat orient[6] = {
1382 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1383 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1385 alListenerfv(AL_ORIENTATION, orient);
1387 if(This->dirty.bit.distancefactor)
1389 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1390 if(This->SupportedExt[EXT_EFX])
1391 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1394 if(This->dirty.bit.rollofffactor)
1396 ALfloat rolloff = This->rollofffactor;
1397 for(i = 0;i < This->nbuffers;++i)
1399 DS8Buffer *buf = This->buffers[i];
1400 if(buf->ds3dmode != DS3DMODE_DISABLE)
1401 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1405 if(This->dirty.bit.dopplerfactor)
1406 alDopplerFactor(listen->flDopplerFactor);
1408 if(This->dirty.bit.effect)
1409 This->ExtAL.AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1411 /* getALError is here for debugging */
1412 getALError();
1414 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1415 This->dirty.flags = 0;
1417 for(i = 0;i < This->nbuffers;++i)
1419 DS8Buffer *buf = This->buffers[i];
1421 if(!buf->dirty.flags)
1422 continue;
1424 if(buf->dirty.bit.pos)
1425 alSource3f(buf->source, AL_POSITION,
1426 buf->ds3dbuffer.vPosition.x,
1427 buf->ds3dbuffer.vPosition.y,
1428 -buf->ds3dbuffer.vPosition.z);
1429 if(buf->dirty.bit.vel)
1430 alSource3f(buf->source, AL_VELOCITY,
1431 buf->ds3dbuffer.vVelocity.x,
1432 buf->ds3dbuffer.vVelocity.y,
1433 -buf->ds3dbuffer.vVelocity.z);
1434 if(buf->dirty.bit.cone_angles)
1436 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1437 buf->ds3dbuffer.dwInsideConeAngle);
1438 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1439 buf->ds3dbuffer.dwOutsideConeAngle);
1441 if(buf->dirty.bit.cone_orient)
1442 alSource3f(buf->source, AL_DIRECTION,
1443 buf->ds3dbuffer.vConeOrientation.x,
1444 buf->ds3dbuffer.vConeOrientation.y,
1445 -buf->ds3dbuffer.vConeOrientation.z);
1446 if(buf->dirty.bit.cone_outsidevolume)
1447 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1448 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1449 if(buf->dirty.bit.min_distance)
1450 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1451 if(buf->dirty.bit.max_distance)
1452 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1453 if(buf->dirty.bit.mode)
1455 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1456 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1457 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1458 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1459 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1461 buf->dirty.flags = 0;
1463 getALError();
1465 This->ExtAL.ProcessUpdates();
1466 popALContext();
1467 LeaveCriticalSection(&This->crst);
1469 return S_OK;
1472 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1474 DS8Primary3D_QueryInterface,
1475 DS8Primary3D_AddRef,
1476 DS8Primary3D_Release,
1477 DS8Primary3D_GetAllParameters,
1478 DS8Primary3D_GetDistanceFactor,
1479 DS8Primary3D_GetDopplerFactor,
1480 DS8Primary3D_GetOrientation,
1481 DS8Primary3D_GetPosition,
1482 DS8Primary3D_GetRolloffFactor,
1483 DS8Primary3D_GetVelocity,
1484 DS8Primary3D_SetAllParameters,
1485 DS8Primary3D_SetDistanceFactor,
1486 DS8Primary3D_SetDopplerFactor,
1487 DS8Primary3D_SetOrientation,
1488 DS8Primary3D_SetPosition,
1489 DS8Primary3D_SetRolloffFactor,
1490 DS8Primary3D_SetVelocity,
1491 DS8Primary3D_CommitDeferredSettings
1494 /* NOTE: Although the app handles listener properties through secondary buffers,
1495 * we pass the requests to the primary buffer though a propertyset interface.
1496 * These methods are not exposed to the app. */
1497 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1499 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1502 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1504 DS8Primary *This = impl_from_IKsPropertySet(iface);
1505 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
1508 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1510 DS8Primary *This = impl_from_IKsPropertySet(iface);
1511 LONG ret;
1513 ret = InterlockedIncrement(&This->prop_ref);
1514 TRACE("new refcount %d\n", ret);
1516 return ret;
1519 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1521 DS8Primary *This = impl_from_IKsPropertySet(iface);
1522 LONG ret;
1524 ret = InterlockedDecrement(&This->prop_ref);
1525 TRACE("new refcount %d\n", ret);
1527 return ret;
1530 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1531 REFGUID guidPropSet, ULONG dwPropID,
1532 LPVOID pInstanceData, ULONG cbInstanceData,
1533 LPVOID pPropData, ULONG cbPropData,
1534 PULONG pcbReturned)
1536 DS8Primary *This = impl_from_IKsPropertySet(iface);
1537 HRESULT res = E_PROP_ID_UNSUPPORTED;
1539 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
1540 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
1542 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1544 EnterCriticalSection(&This->crst);
1546 if(This->effect == 0)
1547 res = E_PROP_ID_UNSUPPORTED;
1548 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1550 res = DSERR_INVALIDPARAM;
1551 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1553 union {
1554 void *v;
1555 EAXLISTENERPROPERTIES *props;
1556 } data = { pPropData };
1558 *data.props = This->eax_prop;
1559 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1560 res = DS_OK;
1563 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOM)
1565 res = DSERR_INVALIDPARAM;
1566 if(cbPropData >= sizeof(LONG))
1568 union {
1569 void *v;
1570 LONG *l;
1571 } data = { pPropData };
1573 *data.l = This->eax_prop.lRoom;
1574 *pcbReturned = sizeof(LONG);
1575 res = DS_OK;
1578 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF)
1580 res = DSERR_INVALIDPARAM;
1581 if(cbPropData >= sizeof(LONG))
1583 union {
1584 void *v;
1585 LONG *l;
1586 } data = { pPropData };
1588 *data.l = This->eax_prop.lRoomHF;
1589 *pcbReturned = sizeof(LONG);
1590 res = DS_OK;
1593 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1595 res = DSERR_INVALIDPARAM;
1596 if(cbPropData >= sizeof(FLOAT))
1598 union {
1599 void *v;
1600 FLOAT *fl;
1601 } data = { pPropData };
1603 *data.fl = This->eax_prop.flRoomRolloffFactor;
1604 *pcbReturned = sizeof(FLOAT);
1605 res = DS_OK;
1608 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1610 res = DSERR_INVALIDPARAM;
1611 if(cbPropData >= sizeof(DWORD))
1613 union {
1614 void *v;
1615 DWORD *dw;
1616 } data = { pPropData };
1618 *data.dw = This->eax_prop.dwEnvironment;
1619 *pcbReturned = sizeof(DWORD);
1620 res = DS_OK;
1623 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1625 res = DSERR_INVALIDPARAM;
1626 if(cbPropData >= sizeof(FLOAT))
1628 union {
1629 void *v;
1630 FLOAT *fl;
1631 } data = { pPropData };
1633 *data.fl = This->eax_prop.flEnvironmentSize;
1634 *pcbReturned = sizeof(FLOAT);
1635 res = DS_OK;
1638 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
1640 res = DSERR_INVALIDPARAM;
1641 if(cbPropData >= sizeof(FLOAT))
1643 union {
1644 void *v;
1645 FLOAT *fl;
1646 } data = { pPropData };
1648 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1649 *pcbReturned = sizeof(FLOAT);
1650 res = DS_OK;
1653 else if(dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
1655 res = DSERR_INVALIDPARAM;
1656 if(cbPropData >= sizeof(FLOAT))
1658 union {
1659 void *v;
1660 FLOAT *fl;
1661 } data = { pPropData };
1663 *data.fl = This->eax_prop.flAirAbsorptionHF;
1664 *pcbReturned = sizeof(FLOAT);
1665 res = DS_OK;
1668 else if(dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
1670 res = DSERR_INVALIDPARAM;
1671 if(cbPropData >= sizeof(DWORD))
1673 union {
1674 void *v;
1675 DWORD *dw;
1676 } data = { pPropData };
1678 *data.dw = This->eax_prop.dwFlags;
1679 *pcbReturned = sizeof(DWORD);
1680 res = DS_OK;
1683 else
1684 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
1686 LeaveCriticalSection(&This->crst);
1688 else
1689 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1691 return res;
1694 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1695 REFGUID guidPropSet, ULONG dwPropID,
1696 LPVOID pInstanceData, ULONG cbInstanceData,
1697 LPVOID pPropData, ULONG cbPropData)
1699 DS8Primary *This = impl_from_IKsPropertySet(iface);
1700 HRESULT res = E_PROP_ID_UNSUPPORTED;
1702 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
1703 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
1705 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1707 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1708 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1710 EnterCriticalSection(&This->crst);
1711 setALContext(This->ctx);
1713 if(This->effect == 0)
1714 res = E_PROP_ID_UNSUPPORTED;
1715 else if(propid == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1717 do_allparams:
1718 res = DSERR_INVALIDPARAM;
1719 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1721 union {
1722 const void *v;
1723 const EAXLISTENERPROPERTIES *props;
1724 } data = { pPropData };
1726 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1727 This->eax_prop = *data.props;
1728 This->ExtAL.Effectf(This->effect, AL_REVERB_DENSITY,
1729 (data.props->flEnvironmentSize < 2.0f) ?
1730 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1731 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1732 data.props->flEnvironmentDiffusion);
1734 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1735 mB_to_gain(data.props->lRoom));
1736 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1737 mB_to_gain(data.props->lRoomHF));
1739 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1740 data.props->flRoomRolloffFactor);
1742 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_TIME,
1743 data.props->flDecayTime);
1744 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1745 data.props->flDecayHFRatio);
1747 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1748 mB_to_gain(data.props->lReflections));
1749 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1750 data.props->flReflectionsDelay);
1752 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1753 mB_to_gain(data.props->lReverb));
1754 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1755 data.props->flReverbDelay);
1757 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1758 mB_to_gain(data.props->flAirAbsorptionHF));
1760 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1761 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1762 AL_TRUE : AL_FALSE);
1764 getALError();
1766 This->dirty.bit.effect = 1;
1767 res = DS_OK;
1770 else if(propid == DSPROPERTY_EAXLISTENER_ROOM)
1772 res = DSERR_INVALIDPARAM;
1773 if(cbPropData >= sizeof(LONG))
1775 union {
1776 const void *v;
1777 const LONG *l;
1778 } data = { pPropData };
1780 This->eax_prop.lRoom = *data.l;
1781 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1782 mB_to_gain(This->eax_prop.lRoom));
1783 getALError();
1785 This->dirty.bit.effect = 1;
1786 res = DS_OK;
1789 else if(propid == DSPROPERTY_EAXLISTENER_ROOMHF)
1791 res = DSERR_INVALIDPARAM;
1792 if(cbPropData >= sizeof(LONG))
1794 union {
1795 const void *v;
1796 const LONG *l;
1797 } data = { pPropData };
1799 This->eax_prop.lRoomHF = *data.l;
1800 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1801 mB_to_gain(This->eax_prop.lRoomHF));
1802 getALError();
1804 This->dirty.bit.effect = 1;
1805 res = DS_OK;
1808 else if(propid == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1810 res = DSERR_INVALIDPARAM;
1811 if(cbPropData >= sizeof(FLOAT))
1813 union {
1814 const void *v;
1815 const FLOAT *fl;
1816 } data = { pPropData };
1818 This->eax_prop.flRoomRolloffFactor = *data.fl;
1819 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1820 This->eax_prop.flRoomRolloffFactor);
1821 getALError();
1823 This->dirty.bit.effect = 1;
1824 res = DS_OK;
1827 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1829 res = DSERR_INVALIDPARAM;
1830 if(cbPropData >= sizeof(DWORD))
1832 union {
1833 const void *v;
1834 const DWORD *dw;
1835 } data = { pPropData };
1837 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1839 /* Get the environment index's default and pass it down to
1840 * ALLPARAMETERS */
1841 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1842 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1843 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1844 goto do_allparams;
1848 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1850 res = DSERR_INVALIDPARAM;
1851 if(cbPropData >= sizeof(FLOAT))
1853 union {
1854 const void *v;
1855 const FLOAT *fl;
1856 } data = { pPropData };
1858 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1860 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1862 This->eax_prop.flEnvironmentSize = *data.fl;
1864 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1866 This->eax_prop.flDecayTime *= scale;
1867 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1869 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1871 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1872 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1874 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1876 This->eax_prop.flReflectionsDelay *= scale;
1877 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1879 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1881 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1882 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1884 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1886 This->eax_prop.flReverbDelay *= scale;
1887 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1890 /* Pass the updated environment properties down to ALLPARAMETERS */
1891 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1892 pPropData = (void*)&This->eax_prop;
1893 cbPropData = sizeof(This->eax_prop);
1894 goto do_allparams;
1898 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
1900 res = DSERR_INVALIDPARAM;
1901 if(cbPropData >= sizeof(FLOAT))
1903 union {
1904 const void *v;
1905 const FLOAT *fl;
1906 } data = { pPropData };
1908 This->eax_prop.flEnvironmentDiffusion = *data.fl;
1909 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1910 This->eax_prop.flEnvironmentDiffusion);
1911 getALError();
1913 This->dirty.bit.effect = 1;
1914 res = DS_OK;
1917 else if(propid == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
1919 res = DSERR_INVALIDPARAM;
1920 if(cbPropData >= sizeof(FLOAT))
1922 union {
1923 const void *v;
1924 const FLOAT *fl;
1925 } data = { pPropData };
1927 This->eax_prop.flAirAbsorptionHF = *data.fl;
1928 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1929 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
1930 getALError();
1932 This->dirty.bit.effect = 1;
1933 res = DS_OK;
1936 else if(propid == DSPROPERTY_EAXLISTENER_FLAGS)
1938 res = DSERR_INVALIDPARAM;
1939 if(cbPropData >= sizeof(DWORD))
1941 union {
1942 const void *v;
1943 const DWORD *dw;
1944 } data = { pPropData };
1946 This->eax_prop.dwFlags = *data.dw;
1947 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1948 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1949 AL_TRUE : AL_FALSE);
1950 getALError();
1952 This->dirty.bit.effect = 1;
1953 res = DS_OK;
1956 else if(propid != 0)
1957 FIXME("Unhandled propid: 0x%08x\n", propid);
1959 if(res == DS_OK && immediate)
1960 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
1962 popALContext();
1963 LeaveCriticalSection(&This->crst);
1965 else
1966 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1968 return res;
1971 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
1972 REFGUID guidPropSet, ULONG dwPropID,
1973 PULONG pTypeSupport)
1975 DS8Primary *This = impl_from_IKsPropertySet(iface);
1976 HRESULT res = E_PROP_ID_UNSUPPORTED;
1978 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
1980 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1982 EnterCriticalSection(&This->crst);
1984 if(This->effect == 0)
1985 res = E_PROP_ID_UNSUPPORTED;
1986 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
1987 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
1988 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
1989 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
1990 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
1991 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
1992 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
1993 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
1994 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
1996 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
1997 res = DS_OK;
1999 else
2000 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
2002 LeaveCriticalSection(&This->crst);
2004 else
2005 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2007 return res;
2010 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2012 DS8PrimaryProp_QueryInterface,
2013 DS8PrimaryProp_AddRef,
2014 DS8PrimaryProp_Release,
2015 DS8PrimaryProp_Get,
2016 DS8PrimaryProp_Set,
2017 DS8PrimaryProp_QuerySupport