Initial check-in
[wine/multimedia.git] / primary.c
blob12132d315a3be2951939dfb7aa6630d220f57451
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 0x6100
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 InitializeCriticalSection(&This->crst);
90 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DS8Primary.crst");
92 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
93 wfx = &This->format.Format;
95 hr = DSERR_NODRIVER;
96 This->ctx = alcCreateContext(parent->device, NULL);
97 if(!This->ctx)
99 ALCenum err = alcGetError(parent->device);
100 ERR("Could not create context (0x%x)!\n", err);
101 goto fail;
104 setALContext(This->ctx);
105 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
107 TRACE("Found AL_EXT_FLOAT32\n");
108 This->SupportedExt[EXT_FLOAT32] = AL_TRUE;
110 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
112 TRACE("Found AL_EXT_MCFORMATS\n");
113 This->SupportedExt[EXT_MCFORMATS] = AL_TRUE;
115 if(alIsExtensionPresent("AL_EXT_STATIC_BUFFER"))
117 TRACE("Found AL_EXT_STATIC_BUFFER\n");
118 This->ExtAL.BufferDataStatic = alGetProcAddress("alBufferDataStatic");
119 This->SupportedExt[EXT_STATIC_BUFFER] = AL_TRUE;
121 if(alIsExtensionPresent("AL_SOFTX_buffer_samples"))
123 TRACE("Found AL_SOFTX_buffer_samples\n");
124 This->ExtAL.BufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
125 This->ExtAL.BufferSubSamplesSOFT = alGetProcAddress("alBufferSubSamplesSOFT");
126 This->ExtAL.GetBufferSamplesSOFT = alGetProcAddress("alGetBufferSamplesSOFT");
127 This->ExtAL.IsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
128 This->SupportedExt[SOFT_BUFFER_SAMPLES] = AL_TRUE;
130 if(alIsExtensionPresent("AL_SOFT_buffer_sub_data"))
132 TRACE("Found AL_SOFT_buffer_sub_data\n");
133 This->ExtAL.BufferSubData = alGetProcAddress("alBufferSubDataSOFT");
134 This->SupportedExt[SOFT_BUFFER_SUB_DATA] = AL_TRUE;
136 if(alIsExtensionPresent("AL_SOFTX_deferred_updates"))
138 TRACE("Found AL_SOFTX_deferred_updates\n");
139 This->ExtAL.DeferUpdates = alGetProcAddress("alDeferUpdatesSOFT");
140 This->ExtAL.ProcessUpdates = alGetProcAddress("alProcessUpdatesSOFT");
141 This->SupportedExt[SOFT_DEFERRED_UPDATES] = AL_TRUE;
143 else
145 This->ExtAL.DeferUpdates = wrap_DeferUpdates;
146 This->ExtAL.ProcessUpdates = wrap_ProcessUpdates;
149 if(alcIsExtensionPresent(parent->device, "ALC_EXT_EFX"))
151 #define LOAD_FUNC(x) (This->ExtAL.x = alGetProcAddress("al"#x))
152 LOAD_FUNC(GenEffects);
153 LOAD_FUNC(DeleteEffects);
154 LOAD_FUNC(Effecti);
155 LOAD_FUNC(Effectf);
157 LOAD_FUNC(GenAuxiliaryEffectSlots);
158 LOAD_FUNC(DeleteAuxiliaryEffectSlots);
159 LOAD_FUNC(AuxiliaryEffectSloti);
160 #undef LOAD_FUNC
161 This->SupportedExt[EXT_EFX] = AL_TRUE;
163 This->ExtAL.GenEffects(1, &This->effect);
164 This->ExtAL.Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
166 This->ExtAL.GenAuxiliaryEffectSlots(1, &This->auxslot);
168 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
170 wfx->wFormatTag = WAVE_FORMAT_PCM;
171 wfx->nChannels = 2;
172 wfx->wBitsPerSample = 8;
173 wfx->nSamplesPerSec = 22050;
174 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
175 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
176 wfx->cbSize = 0;
178 This->IDirectSoundBuffer_iface.lpVtbl = &DS8Primary_Vtbl;
179 This->IDirectSound3DListener_iface.lpVtbl = &DS8Primary3D_Vtbl;
180 This->IKsPropertySet_iface.lpVtbl = &DS8PrimaryProp_Vtbl;
181 This->stopped = TRUE;
182 This->parent = parent;
183 /* Apparently primary buffer size is always 32k,
184 * tested on windows with 192k 24 bits sound @ 6 channels
185 * where it will run out in 60 ms and it isn't pointer aligned
187 This->buf_size = 32768;
189 if(!This->ExtAL.BufferSubData && !This->ExtAL.BufferSamplesSOFT &&
190 !This->ExtAL.BufferDataStatic)
192 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
193 alcGetString(parent->device, ALC_DEVICE_SPECIFIER));
194 ERR("Please consider using OpenAL-Soft\n");
197 /* Make sure DS3DListener defaults are applied to OpenAL */
198 listener = &This->listen;
199 listener->dwSize = sizeof(*listener);
200 listener->vPosition.x = 0.0;
201 listener->vPosition.y = 0.0;
202 listener->vPosition.z = 0.0;
203 listener->vVelocity.x = 0.0;
204 listener->vVelocity.y = 0.0;
205 listener->vVelocity.z = 0.0;
206 listener->vOrientFront.x = 0.0;
207 listener->vOrientFront.y = 0.0;
208 listener->vOrientFront.z = 1.0;
209 listener->vOrientTop.x = 0.0;
210 listener->vOrientTop.y = 1.0;
211 listener->vOrientTop.z = 0.0;
212 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
213 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
214 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
215 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
216 if(FAILED(hr))
217 ERR("Could not set 3d parameters: %08x\n", hr);
219 for(nsources = 0;nsources < sizeof(srcs)/sizeof(*srcs);nsources++)
221 alGenSources(1, &srcs[nsources]);
222 if(alGetError() != AL_NO_ERROR)
223 break;
225 alDeleteSources(nsources, srcs);
226 getALError();
228 popALContext();
230 This->max_sources = nsources;
231 This->sizenotifies = This->sizebuffers = This->sizesources = nsources+1;
233 hr = DSERR_OUTOFMEMORY;
234 This->sources = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->sources));
235 This->buffers = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->buffers));
236 This->notifies = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->notifies));
237 if(!This->sources || !This->buffers || !This->notifies)
238 goto fail;
240 *ppv = This;
241 return S_OK;
243 fail:
244 DS8Primary_Destroy(This);
245 return hr;
248 void DS8Primary_Destroy(DS8Primary *This)
250 TRACE("Destroying primary %p\n", This);
252 if(This->timer_id)
254 timeKillEvent(This->timer_id);
255 timeEndPeriod(This->timer_res);
256 TRACE("Killed timer\n");
259 if(This->ctx)
261 /* Calling setALContext is not appropriate here,
262 * since we *have* to unset the context before destroying it
264 ALCcontext *old_ctx;
266 EnterCriticalSection(&openal_crst);
267 old_ctx = get_context();
268 if(old_ctx != This->ctx)
269 set_context(This->ctx);
270 else
271 old_ctx = NULL;
273 while(This->nbuffers--)
274 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
276 if(This->nsources)
277 alDeleteSources(This->nsources, This->sources);
279 if(This->effect)
280 This->ExtAL.DeleteEffects(1, &This->effect);
281 if(This->auxslot)
282 This->ExtAL.DeleteAuxiliaryEffectSlots(1, &This->auxslot);
284 HeapFree(GetProcessHeap(), 0, This->sources);
285 HeapFree(GetProcessHeap(), 0, This->notifies);
286 HeapFree(GetProcessHeap(), 0, This->buffers);
288 set_context(old_ctx);
289 alcDestroyContext(This->ctx);
290 LeaveCriticalSection(&openal_crst);
293 This->crst.DebugInfo->Spare[0] = 0;
294 DeleteCriticalSection(&This->crst);
296 HeapFree(GetProcessHeap(), 0, This);
299 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
301 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
304 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
306 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
308 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
310 *ppv = NULL;
311 if(IsEqualIID(riid, &IID_IUnknown) ||
312 IsEqualIID(riid, &IID_IDirectSoundBuffer))
313 *ppv = &This->IDirectSoundBuffer_iface;
314 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
316 if((This->flags&DSBCAPS_CTRL3D))
317 *ppv = &This->IDirectSound3DListener_iface;
319 else
320 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
322 if(*ppv)
324 IUnknown_AddRef((IUnknown*)*ppv);
325 return S_OK;
328 return E_NOINTERFACE;
331 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
333 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
334 LONG ret;
336 ret = InterlockedIncrement(&This->ref);
337 if(This->ref == 1)
338 This->flags = 0;
340 return ret;
343 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
345 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
346 LONG ret;
348 ret = InterlockedDecrement(&This->ref);
350 return ret;
353 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
355 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
357 TRACE("(%p)->(%p)\n", iface, caps);
359 if(!caps || caps->dwSize < sizeof(*caps))
361 WARN("Invalid DSBCAPS (%p, %u)\n", caps, caps ? caps->dwSize : 0);
362 return DSERR_INVALIDPARAM;
365 EnterCriticalSection(&This->crst);
366 caps->dwFlags = This->flags;
367 caps->dwBufferBytes = This->buf_size;
368 caps->dwUnlockTransferRate = 0;
369 caps->dwPlayCpuOverhead = 0;
370 LeaveCriticalSection(&This->crst);
372 return DS_OK;
375 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
377 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
378 HRESULT hr = DSERR_PRIOLEVELNEEDED;
380 EnterCriticalSection(&This->crst);
381 if(This->write_emu)
382 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
383 LeaveCriticalSection(&This->crst);
385 return hr;
388 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
390 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
391 HRESULT hr = S_OK;
392 UINT size;
394 if(!wfx && !written)
396 WARN("Cannot report format or format size\n");
397 return DSERR_INVALIDPARAM;
400 EnterCriticalSection(&This->crst);
401 size = sizeof(This->format.Format) + This->format.Format.cbSize;
402 if(written)
403 *written = size;
404 if(wfx)
406 if(allocated < size)
407 hr = DSERR_INVALIDPARAM;
408 else
409 memcpy(wfx, &This->format.Format, size);
411 LeaveCriticalSection(&This->crst);
413 return hr;
416 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
418 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
419 HRESULT hr = S_OK;
421 TRACE("(%p)->(%p)\n", iface, volume);
423 if(!volume)
424 return DSERR_INVALIDPARAM;
426 EnterCriticalSection(&This->crst);
427 if(!(This->flags & DSBCAPS_CTRLVOLUME))
428 hr = DSERR_CONTROLUNAVAIL;
429 else
431 ALfloat gain;
432 LONG vol;
434 setALContext(This->ctx);
435 alGetListenerf(AL_GAIN, &gain);
436 getALError();
437 popALContext();
439 vol = gain_to_mB(gain);
440 vol = max(vol, DSBVOLUME_MIN);
441 *volume = min(vol, DSBVOLUME_MAX);
443 LeaveCriticalSection(&This->crst);
445 return hr;
448 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
450 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
451 HRESULT hr = S_OK;
453 WARN("(%p)->(%p): semi-stub\n", iface, pan);
455 if(!pan)
456 return DSERR_INVALIDPARAM;
458 EnterCriticalSection(&This->crst);
459 if(This->write_emu)
460 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
461 else if(!(This->flags & DSBCAPS_CTRLPAN))
462 hr = DSERR_CONTROLUNAVAIL;
463 else
464 *pan = 0;
465 LeaveCriticalSection(&This->crst);
467 return hr;
470 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
472 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
473 HRESULT hr = S_OK;
475 WARN("(%p)->(%p): semi-stub\n", iface, freq);
477 if(!freq)
478 return DSERR_INVALIDPARAM;
480 EnterCriticalSection(&This->crst);
481 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
482 hr = DSERR_CONTROLUNAVAIL;
483 else
484 *freq = This->format.Format.nSamplesPerSec;
485 LeaveCriticalSection(&This->crst);
487 return hr;
490 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
492 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
494 TRACE("(%p)->(%p)\n", iface, status);
496 if(!status)
497 return DSERR_INVALIDPARAM;
499 EnterCriticalSection(&This->crst);
501 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
502 if((This->flags&DSBCAPS_LOCDEFER))
503 *status |= DSBSTATUS_LOCHARDWARE;
505 if(This->stopped)
507 DWORD i, state;
508 HRESULT hr;
510 for(i = 0;i < This->nbuffers;++i)
512 hr = IDirectSoundBuffer_GetStatus((IDirectSoundBuffer*)This->buffers[i], &state);
513 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
514 break;
516 if(i == This->nbuffers)
518 /* Primary stopped and no buffers playing.. */
519 *status = 0;
523 LeaveCriticalSection(&This->crst);
525 return S_OK;
528 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
530 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
531 HRESULT hr = S_OK;
533 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
535 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
537 WARN("Bad DSBDESC for primary buffer\n");
538 return DSERR_INVALIDPARAM;
540 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
541 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
542 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
544 WARN("Bad dwFlags %08x\n", desc->dwFlags);
545 return DSERR_INVALIDPARAM;
548 EnterCriticalSection(&This->crst);
549 /* Should be 0 if not initialized */
550 if(This->flags)
552 hr = DSERR_ALREADYINITIALIZED;
553 goto out;
556 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
558 DSBUFFERDESC emudesc;
559 DS8Buffer *emu;
561 if(This->write_emu)
563 ERR("There shouldn't be a write_emu!\n");
564 IDirectSoundBuffer8_Release(This->write_emu);
565 This->write_emu = NULL;
568 memset(&emudesc, 0, sizeof(emudesc));
569 emudesc.dwSize = sizeof(emudesc);
570 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
571 /* Dont play last incomplete sample */
572 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
573 emudesc.lpwfxFormat = &This->format.Format;
575 hr = DS8Buffer_Create(&emu, This, NULL);
576 if(SUCCEEDED(hr))
578 This->write_emu = &emu->IDirectSoundBuffer8_iface;
579 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
580 if(FAILED(hr))
582 IDirectSoundBuffer8_Release(This->write_emu);
583 This->write_emu = NULL;
588 if(SUCCEEDED(hr))
589 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
590 out:
591 LeaveCriticalSection(&This->crst);
592 return hr;
595 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
597 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
598 HRESULT hr = DSERR_PRIOLEVELNEEDED;
600 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
602 EnterCriticalSection(&This->crst);
603 if(This->write_emu)
604 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
605 LeaveCriticalSection(&This->crst);
607 return hr;
610 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
612 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
613 HRESULT hr;
615 TRACE("(%p)->(%u, %u, %u)\n", iface, res1, res2, flags);
617 if(!(flags & DSBPLAY_LOOPING))
619 WARN("Flags (%08x) not set to DSBPLAY_LOOPING\n", flags);
620 return DSERR_INVALIDPARAM;
623 EnterCriticalSection(&This->crst);
624 hr = S_OK;
625 if(This->write_emu)
626 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
627 if(SUCCEEDED(hr))
628 This->stopped = FALSE;
629 LeaveCriticalSection(&This->crst);
631 return hr;
634 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
636 WARN("(%p)->(%u)\n", iface, pos);
637 return DSERR_INVALIDCALL;
640 /* Just assume the format is crap, and clean up the damage */
641 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
643 if(from->wFormatTag == WAVE_FORMAT_PCM)
645 wfx->cbSize = 0;
646 if(from->wBitsPerSample == 8 ||
647 from->wBitsPerSample == 16 ||
648 from->wBitsPerSample == 24 ||
649 from->wBitsPerSample == 32)
650 wfx->wBitsPerSample = from->wBitsPerSample;
652 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
654 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
655 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
656 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
658 /* Fail silently.. */
659 if(from->cbSize < size)
660 return;
661 if(!fromx->Samples.wValidBitsPerSample &&
662 !fromx->Format.wBitsPerSample)
663 return;
665 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
666 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
668 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
669 return;
672 wfe->Format.wBitsPerSample = from->wBitsPerSample;
673 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
674 if(!wfe->Samples.wValidBitsPerSample)
675 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
676 wfe->Format.cbSize = size;
677 wfe->dwChannelMask = fromx->dwChannelMask;
678 wfe->SubFormat = fromx->SubFormat;
680 else
682 ERR("Unhandled format tag %04x\n", from->wFormatTag);
683 return;
686 if(from->nChannels)
687 wfx->nChannels = from->nChannels;
688 wfx->wFormatTag = from->wFormatTag;
689 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
690 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
691 wfx->nSamplesPerSec = from->nSamplesPerSec;
692 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
693 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
696 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
698 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
699 HRESULT hr = S_OK;
700 ALCint freq;
702 TRACE("(%p)->(%p)\n", iface, wfx);
704 if(!wfx)
706 WARN("Missing format\n");
707 return DSERR_INVALIDPARAM;
710 EnterCriticalSection(&This->crst);
712 if(This->parent->prio_level < DSSCL_PRIORITY)
714 hr = DSERR_PRIOLEVELNEEDED;
715 goto out;
718 TRACE("Requested primary format:\n"
719 " FormatTag = %04x\n"
720 " Channels = %u\n"
721 " SamplesPerSec = %u\n"
722 " AvgBytesPerSec = %u\n"
723 " BlockAlign = %u\n"
724 " BitsPerSample = %u\n",
725 wfx->wFormatTag, wfx->nChannels,
726 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
727 wfx->nBlockAlign, wfx->wBitsPerSample);
729 copy_waveformat(&This->format.Format, wfx);
731 freq = This->format.Format.nSamplesPerSec;
732 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
733 getALCError(This->parent->device);
735 This->format.Format.nSamplesPerSec = freq;
736 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
737 This->format.Format.nSamplesPerSec;
739 if(This->write_emu)
741 DS8Buffer *buf;
742 DSBUFFERDESC desc;
744 memset(&desc, 0, sizeof(desc));
745 desc.dwSize = sizeof(desc);
746 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
747 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
748 desc.lpwfxFormat = &This->format.Format;
750 hr = DS8Buffer_Create(&buf, This, NULL);
751 if(FAILED(hr))
752 goto out;
754 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, (IDirectSound*)&This->parent->IDirectSound8_iface, &desc);
755 if(FAILED(hr))
756 DS8Buffer_Destroy(buf);
757 else
759 IDirectSoundBuffer8_Release(This->write_emu);
760 This->write_emu = &buf->IDirectSoundBuffer8_iface;
764 out:
765 LeaveCriticalSection(&This->crst);
766 return hr;
769 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
771 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
772 HRESULT hr = S_OK;
774 TRACE("(%p)->(%d)\n", iface, vol);
776 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
778 WARN("Invalid volume (%d)\n", vol);
779 return DSERR_INVALIDPARAM;
782 EnterCriticalSection(&This->crst);
783 if(!(This->flags&DSBCAPS_CTRLVOLUME))
784 hr = DSERR_CONTROLUNAVAIL;
785 if(SUCCEEDED(hr))
787 setALContext(This->ctx);
788 alListenerf(AL_GAIN, mB_to_gain(vol));
789 popALContext();
791 LeaveCriticalSection(&This->crst);
793 return hr;
796 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
798 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
799 HRESULT hr;
801 TRACE("(%p)->(%d)\n", iface, pan);
803 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
805 WARN("invalid parameter: pan = %d\n", pan);
806 return DSERR_INVALIDPARAM;
809 EnterCriticalSection(&This->crst);
810 if(!(This->flags&DSBCAPS_CTRLPAN))
812 WARN("control unavailable\n");
813 hr = DSERR_CONTROLUNAVAIL;
815 else if(This->write_emu)
816 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
817 else
819 FIXME("Not supported\n");
820 hr = E_NOTIMPL;
822 LeaveCriticalSection(&This->crst);
824 return hr;
827 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
829 WARN("(%p)->(%u)\n", iface, freq);
830 return DSERR_CONTROLUNAVAIL;
833 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
835 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
836 HRESULT hr = S_OK;
838 TRACE("(%p)->()\n", iface);
840 EnterCriticalSection(&This->crst);
841 if(This->write_emu)
842 hr = IDirectSoundBuffer8_Stop(This->write_emu);
843 if(SUCCEEDED(hr))
844 This->stopped = TRUE;
845 LeaveCriticalSection(&This->crst);
847 return hr;
850 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
852 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
853 HRESULT hr = DSERR_INVALIDCALL;
855 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
857 EnterCriticalSection(&This->crst);
858 if(This->write_emu)
859 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
860 LeaveCriticalSection(&This->crst);
862 return hr;
865 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
867 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
868 HRESULT hr = S_OK;
870 TRACE("(%p)->()\n", iface);
872 EnterCriticalSection(&This->crst);
873 if(This->write_emu)
874 hr = IDirectSoundBuffer8_Restore(This->write_emu);
875 LeaveCriticalSection(&This->crst);
877 return hr;
880 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
882 DS8Primary_QueryInterface,
883 DS8Primary_AddRef,
884 DS8Primary_Release,
885 DS8Primary_GetCaps,
886 DS8Primary_GetCurrentPosition,
887 DS8Primary_GetFormat,
888 DS8Primary_GetVolume,
889 DS8Primary_GetPan,
890 DS8Primary_GetFrequency,
891 DS8Primary_GetStatus,
892 DS8Primary_Initialize,
893 DS8Primary_Lock,
894 DS8Primary_Play,
895 DS8Primary_SetCurrentPosition,
896 DS8Primary_SetFormat,
897 DS8Primary_SetVolume,
898 DS8Primary_SetPan,
899 DS8Primary_SetFrequency,
900 DS8Primary_Stop,
901 DS8Primary_Unlock,
902 DS8Primary_Restore
905 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
907 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
910 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
912 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
913 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
916 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
918 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
919 LONG ret;
921 ret = InterlockedIncrement(&This->ds3d_ref);
922 TRACE("new refcount %d\n", ret);
924 return ret;
928 /* Considering the primary buffer doesn't get destroyed
929 * it doesn't make sense to destroy ds3d here
931 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
933 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
934 LONG ret;
936 ret = InterlockedDecrement(&This->ds3d_ref);
937 TRACE("new refcount %d\n", ret);
939 return ret;
943 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
945 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
946 // HRESULT hr;
948 TRACE("(%p)->(%p)\n", iface, listener);
950 if(!listener || listener->dwSize < sizeof(*listener))
952 WARN("Invalid DS3DLISTENER %p %u\n", listener, listener ? listener->dwSize : 0);
953 return DSERR_INVALIDPARAM;
956 EnterCriticalSection(&This->crst);
957 setALContext(This->ctx);
958 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
959 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
960 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
961 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
962 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
963 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
964 popALContext();
965 LeaveCriticalSection(&This->crst);
967 // return hr;
968 return DS_OK;
971 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
973 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
975 TRACE("(%p)->(%p)\n", iface, distancefactor);
977 if(!distancefactor)
979 WARN("Invalid parameter %p\n", distancefactor);
980 return DSERR_INVALIDPARAM;
983 EnterCriticalSection(&This->crst);
984 setALContext(This->ctx);
986 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
987 getALError();
989 popALContext();
990 LeaveCriticalSection(&This->crst);
992 return S_OK;
995 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
997 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
999 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1001 if(!dopplerfactor)
1003 WARN("Invalid parameter %p\n", dopplerfactor);
1004 return DSERR_INVALIDPARAM;
1007 EnterCriticalSection(&This->crst);
1008 setALContext(This->ctx);
1010 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1011 getALError();
1013 popALContext();
1014 LeaveCriticalSection(&This->crst);
1016 return S_OK;
1019 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1021 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1022 ALfloat orient[6];
1024 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1026 if(!front || !top)
1028 WARN("Invalid parameter %p %p\n", front, top);
1029 return DSERR_INVALIDPARAM;
1032 EnterCriticalSection(&This->crst);
1033 setALContext(This->ctx);
1035 alGetListenerfv(AL_ORIENTATION, orient);
1036 getALError();
1038 front->x = orient[0];
1039 front->y = orient[1];
1040 front->z = -orient[2];
1041 top->x = orient[3];
1042 top->y = orient[4];
1043 top->z = -orient[5];
1045 popALContext();
1046 LeaveCriticalSection(&This->crst);
1048 return S_OK;
1051 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1053 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1054 ALfloat alpos[3];
1056 TRACE("(%p)->(%p)\n", iface, pos);
1058 if(!pos)
1060 WARN("Invalid parameter %p\n", pos);
1061 return DSERR_INVALIDPARAM;
1064 EnterCriticalSection(&This->crst);
1065 setALContext(This->ctx);
1067 alGetListenerfv(AL_POSITION, alpos);
1068 getALError();
1070 pos->x = alpos[0];
1071 pos->y = alpos[1];
1072 pos->z = -alpos[2];
1074 popALContext();
1075 LeaveCriticalSection(&This->crst);
1077 return S_OK;
1080 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1082 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1084 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1086 if(!rollofffactor)
1088 WARN("Invalid parameter %p\n", rollofffactor);
1089 return DSERR_INVALIDPARAM;
1092 EnterCriticalSection(&This->crst);
1093 *rollofffactor = This->rollofffactor;
1094 LeaveCriticalSection(&This->crst);
1096 return S_OK;
1099 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1101 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1102 ALfloat vel[3];
1104 TRACE("(%p)->(%p)\n", iface, velocity);
1106 if(!velocity)
1108 WARN("Invalid parameter %p\n", velocity);
1109 return DSERR_INVALIDPARAM;
1112 EnterCriticalSection(&This->crst);
1113 setALContext(This->ctx);
1115 alGetListenerfv(AL_VELOCITY, vel);
1116 getALError();
1118 velocity->x = vel[0];
1119 velocity->y = vel[1];
1120 velocity->z = -vel[2];
1122 popALContext();
1123 LeaveCriticalSection(&This->crst);
1125 return S_OK;
1128 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1130 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1132 TRACE("(%p)->(%p, %u)\n", iface, listen, apply);
1134 if(!listen || listen->dwSize < sizeof(*listen))
1136 WARN("Invalid parameter %p %u\n", listen, listen ? listen->dwSize : 0);
1137 return DSERR_INVALIDPARAM;
1140 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1141 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1143 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1144 return DSERR_INVALIDPARAM;
1147 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1148 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1150 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1151 return DSERR_INVALIDPARAM;
1154 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1155 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1157 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1158 return DSERR_INVALIDPARAM;
1161 EnterCriticalSection(&This->crst);
1162 setALContext(This->ctx);
1163 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1164 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1165 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1166 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1167 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1168 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1169 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1170 popALContext();
1171 LeaveCriticalSection(&This->crst);
1173 return S_OK;
1176 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1178 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1180 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1182 if(factor < DS3D_MINDISTANCEFACTOR ||
1183 factor > DS3D_MAXDISTANCEFACTOR)
1185 WARN("Invalid parameter %f\n", factor);
1186 return DSERR_INVALIDPARAM;
1189 EnterCriticalSection(&This->crst);
1190 if(apply == DS3D_DEFERRED)
1192 This->listen.flDistanceFactor = factor;
1193 This->dirty.bit.distancefactor = 1;
1195 else
1197 setALContext(This->ctx);
1198 alSpeedOfSound(343.3f/factor);
1199 if(This->SupportedExt[EXT_EFX])
1200 alListenerf(AL_METERS_PER_UNIT, factor);
1201 getALError();
1202 popALContext();
1204 LeaveCriticalSection(&This->crst);
1206 return S_OK;
1209 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1211 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1213 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1215 if(factor < DS3D_MINDOPPLERFACTOR ||
1216 factor > DS3D_MAXDOPPLERFACTOR)
1218 WARN("Invalid parameter %f\n", factor);
1219 return DSERR_INVALIDPARAM;
1222 EnterCriticalSection(&This->crst);
1223 if(apply == DS3D_DEFERRED)
1225 This->listen.flDopplerFactor = factor;
1226 This->dirty.bit.dopplerfactor = 1;
1228 else
1230 setALContext(This->ctx);
1231 alDopplerFactor(factor);
1232 getALError();
1233 popALContext();
1235 LeaveCriticalSection(&This->crst);
1237 return S_OK;
1240 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1242 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1244 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1246 EnterCriticalSection(&This->crst);
1247 if(apply == DS3D_DEFERRED)
1249 This->listen.vOrientFront.x = xFront;
1250 This->listen.vOrientFront.y = yFront;
1251 This->listen.vOrientFront.z = zFront;
1252 This->listen.vOrientTop.x = xTop;
1253 This->listen.vOrientTop.y = yTop;
1254 This->listen.vOrientTop.z = zTop;
1255 This->dirty.bit.orientation = 1;
1257 else
1259 ALfloat orient[6] = {
1260 xFront, yFront, -zFront,
1261 xTop, yTop, -zTop
1263 setALContext(This->ctx);
1264 alListenerfv(AL_ORIENTATION, orient);
1265 getALError();
1266 popALContext();
1268 LeaveCriticalSection(&This->crst);
1270 return S_OK;
1273 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1275 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1277 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1279 EnterCriticalSection(&This->crst);
1280 if(apply == DS3D_DEFERRED)
1282 This->listen.vPosition.x = x;
1283 This->listen.vPosition.y = y;
1284 This->listen.vPosition.z = z;
1285 This->dirty.bit.pos = 1;
1287 else
1289 setALContext(This->ctx);
1290 alListener3f(AL_POSITION, x, y, -z);
1291 getALError();
1292 popALContext();
1294 LeaveCriticalSection(&This->crst);
1296 return S_OK;
1299 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1301 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1303 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1305 if(factor < DS3D_MINROLLOFFFACTOR ||
1306 factor > DS3D_MAXROLLOFFFACTOR)
1308 WARN("Invalid parameter %f\n", factor);
1309 return DSERR_INVALIDPARAM;
1312 EnterCriticalSection(&This->crst);
1313 if(apply == DS3D_DEFERRED)
1315 This->listen.flRolloffFactor = factor;
1316 This->dirty.bit.rollofffactor = 1;
1318 else
1320 DWORD i;
1322 setALContext(This->ctx);
1323 for(i = 0;i < This->nbuffers;++i)
1325 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1326 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1328 getALError();
1329 popALContext();
1331 This->rollofffactor = factor;
1333 LeaveCriticalSection(&This->crst);
1335 return S_OK;
1338 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1340 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1342 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1344 EnterCriticalSection(&This->crst);
1345 if(apply == DS3D_DEFERRED)
1347 This->listen.vVelocity.x = x;
1348 This->listen.vVelocity.y = y;
1349 This->listen.vVelocity.z = z;
1350 This->dirty.bit.vel = 1;
1352 else
1354 setALContext(This->ctx);
1355 alListener3f(AL_VELOCITY, x, y, -z);
1356 getALError();
1357 popALContext();
1359 LeaveCriticalSection(&This->crst);
1361 return S_OK;
1364 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1366 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1367 const DS3DLISTENER *listen = &This->listen;
1368 DWORD i;
1370 EnterCriticalSection(&This->crst);
1371 setALContext(This->ctx);
1372 This->ExtAL.DeferUpdates();
1374 if(This->dirty.bit.pos)
1375 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1376 if(This->dirty.bit.vel)
1377 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1378 if(This->dirty.bit.orientation)
1380 ALfloat orient[6] = {
1381 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1382 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1384 alListenerfv(AL_ORIENTATION, orient);
1386 if(This->dirty.bit.distancefactor)
1388 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1389 if(This->SupportedExt[EXT_EFX])
1390 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1393 if(This->dirty.bit.rollofffactor)
1395 ALfloat rolloff = This->rollofffactor;
1396 for(i = 0;i < This->nbuffers;++i)
1398 DS8Buffer *buf = This->buffers[i];
1399 if(buf->ds3dmode != DS3DMODE_DISABLE)
1400 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1404 if(This->dirty.bit.dopplerfactor)
1405 alDopplerFactor(listen->flDopplerFactor);
1407 if(This->dirty.bit.effect)
1408 This->ExtAL.AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1410 /* getALError is here for debugging */
1411 getALError();
1413 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1414 This->dirty.flags = 0;
1416 for(i = 0;i < This->nbuffers;++i)
1418 DS8Buffer *buf = This->buffers[i];
1420 if(!buf->dirty.flags)
1421 continue;
1423 if(buf->dirty.bit.pos)
1424 alSource3f(buf->source, AL_POSITION,
1425 buf->ds3dbuffer.vPosition.x,
1426 buf->ds3dbuffer.vPosition.y,
1427 -buf->ds3dbuffer.vPosition.z);
1428 if(buf->dirty.bit.vel)
1429 alSource3f(buf->source, AL_VELOCITY,
1430 buf->ds3dbuffer.vVelocity.x,
1431 buf->ds3dbuffer.vVelocity.y,
1432 -buf->ds3dbuffer.vVelocity.z);
1433 if(buf->dirty.bit.cone_angles)
1435 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1436 buf->ds3dbuffer.dwInsideConeAngle);
1437 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1438 buf->ds3dbuffer.dwOutsideConeAngle);
1440 if(buf->dirty.bit.cone_orient)
1441 alSource3f(buf->source, AL_DIRECTION,
1442 buf->ds3dbuffer.vConeOrientation.x,
1443 buf->ds3dbuffer.vConeOrientation.y,
1444 -buf->ds3dbuffer.vConeOrientation.z);
1445 if(buf->dirty.bit.cone_outsidevolume)
1446 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1447 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1448 if(buf->dirty.bit.min_distance)
1449 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1450 if(buf->dirty.bit.max_distance)
1451 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1452 if(buf->dirty.bit.mode)
1454 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1455 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1456 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1457 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1458 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1460 buf->dirty.flags = 0;
1462 getALError();
1464 This->ExtAL.ProcessUpdates();
1465 popALContext();
1466 LeaveCriticalSection(&This->crst);
1468 return S_OK;
1471 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1473 DS8Primary3D_QueryInterface,
1474 DS8Primary3D_AddRef,
1475 DS8Primary3D_Release,
1476 DS8Primary3D_GetAllParameters,
1477 DS8Primary3D_GetDistanceFactor,
1478 DS8Primary3D_GetDopplerFactor,
1479 DS8Primary3D_GetOrientation,
1480 DS8Primary3D_GetPosition,
1481 DS8Primary3D_GetRolloffFactor,
1482 DS8Primary3D_GetVelocity,
1483 DS8Primary3D_SetAllParameters,
1484 DS8Primary3D_SetDistanceFactor,
1485 DS8Primary3D_SetDopplerFactor,
1486 DS8Primary3D_SetOrientation,
1487 DS8Primary3D_SetPosition,
1488 DS8Primary3D_SetRolloffFactor,
1489 DS8Primary3D_SetVelocity,
1490 DS8Primary3D_CommitDeferredSettings
1493 /* NOTE: Although the app handles listener properties through secondary buffers,
1494 * we pass the requests to the primary buffer though a propertyset interface.
1495 * These methods are not exposed to the app. */
1496 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1498 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1501 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1503 DS8Primary *This = impl_from_IKsPropertySet(iface);
1504 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
1507 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1509 DS8Primary *This = impl_from_IKsPropertySet(iface);
1510 LONG ret;
1512 ret = InterlockedIncrement(&This->prop_ref);
1513 TRACE("new refcount %d\n", ret);
1515 return ret;
1518 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1520 DS8Primary *This = impl_from_IKsPropertySet(iface);
1521 LONG ret;
1523 ret = InterlockedDecrement(&This->prop_ref);
1524 TRACE("new refcount %d\n", ret);
1526 return ret;
1529 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1530 REFGUID guidPropSet, ULONG dwPropID,
1531 LPVOID pInstanceData, ULONG cbInstanceData,
1532 LPVOID pPropData, ULONG cbPropData,
1533 PULONG pcbReturned)
1535 DS8Primary *This = impl_from_IKsPropertySet(iface);
1536 HRESULT res = E_PROP_ID_UNSUPPORTED;
1538 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
1539 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
1541 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1543 EnterCriticalSection(&This->crst);
1545 if(This->effect == 0)
1546 res = E_PROP_ID_UNSUPPORTED;
1547 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1549 res = DSERR_INVALIDPARAM;
1550 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1552 union {
1553 void *v;
1554 EAXLISTENERPROPERTIES *props;
1555 } data = { pPropData };
1557 *data.props = This->eax_prop;
1558 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1559 res = DS_OK;
1562 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOM)
1564 res = DSERR_INVALIDPARAM;
1565 if(cbPropData >= sizeof(LONG))
1567 union {
1568 void *v;
1569 LONG *l;
1570 } data = { pPropData };
1572 *data.l = This->eax_prop.lRoom;
1573 *pcbReturned = sizeof(LONG);
1574 res = DS_OK;
1577 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF)
1579 res = DSERR_INVALIDPARAM;
1580 if(cbPropData >= sizeof(LONG))
1582 union {
1583 void *v;
1584 LONG *l;
1585 } data = { pPropData };
1587 *data.l = This->eax_prop.lRoomHF;
1588 *pcbReturned = sizeof(LONG);
1589 res = DS_OK;
1592 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1594 res = DSERR_INVALIDPARAM;
1595 if(cbPropData >= sizeof(FLOAT))
1597 union {
1598 void *v;
1599 FLOAT *fl;
1600 } data = { pPropData };
1602 *data.fl = This->eax_prop.flRoomRolloffFactor;
1603 *pcbReturned = sizeof(FLOAT);
1604 res = DS_OK;
1607 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1609 res = DSERR_INVALIDPARAM;
1610 if(cbPropData >= sizeof(DWORD))
1612 union {
1613 void *v;
1614 DWORD *dw;
1615 } data = { pPropData };
1617 *data.dw = This->eax_prop.dwEnvironment;
1618 *pcbReturned = sizeof(DWORD);
1619 res = DS_OK;
1622 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1624 res = DSERR_INVALIDPARAM;
1625 if(cbPropData >= sizeof(FLOAT))
1627 union {
1628 void *v;
1629 FLOAT *fl;
1630 } data = { pPropData };
1632 *data.fl = This->eax_prop.flEnvironmentSize;
1633 *pcbReturned = sizeof(FLOAT);
1634 res = DS_OK;
1637 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
1639 res = DSERR_INVALIDPARAM;
1640 if(cbPropData >= sizeof(FLOAT))
1642 union {
1643 void *v;
1644 FLOAT *fl;
1645 } data = { pPropData };
1647 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1648 *pcbReturned = sizeof(FLOAT);
1649 res = DS_OK;
1652 else if(dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
1654 res = DSERR_INVALIDPARAM;
1655 if(cbPropData >= sizeof(FLOAT))
1657 union {
1658 void *v;
1659 FLOAT *fl;
1660 } data = { pPropData };
1662 *data.fl = This->eax_prop.flAirAbsorptionHF;
1663 *pcbReturned = sizeof(FLOAT);
1664 res = DS_OK;
1667 else if(dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
1669 res = DSERR_INVALIDPARAM;
1670 if(cbPropData >= sizeof(DWORD))
1672 union {
1673 void *v;
1674 DWORD *dw;
1675 } data = { pPropData };
1677 *data.dw = This->eax_prop.dwFlags;
1678 *pcbReturned = sizeof(DWORD);
1679 res = DS_OK;
1682 else
1683 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
1685 LeaveCriticalSection(&This->crst);
1687 else
1688 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1690 return res;
1693 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1694 REFGUID guidPropSet, ULONG dwPropID,
1695 LPVOID pInstanceData, ULONG cbInstanceData,
1696 LPVOID pPropData, ULONG cbPropData)
1698 DS8Primary *This = impl_from_IKsPropertySet(iface);
1699 HRESULT res = E_PROP_ID_UNSUPPORTED;
1701 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
1702 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
1704 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1706 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1707 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1709 EnterCriticalSection(&This->crst);
1710 setALContext(This->ctx);
1712 if(This->effect == 0)
1713 res = E_PROP_ID_UNSUPPORTED;
1714 else if(propid == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1716 do_allparams:
1717 res = DSERR_INVALIDPARAM;
1718 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1720 union {
1721 const void *v;
1722 const EAXLISTENERPROPERTIES *props;
1723 } data = { pPropData };
1725 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1726 This->eax_prop = *data.props;
1727 This->ExtAL.Effectf(This->effect, AL_REVERB_DENSITY,
1728 (data.props->flEnvironmentSize < 2.0f) ?
1729 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1730 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1731 data.props->flEnvironmentDiffusion);
1733 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1734 mB_to_gain(data.props->lRoom));
1735 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1736 mB_to_gain(data.props->lRoomHF));
1738 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1739 data.props->flRoomRolloffFactor);
1741 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_TIME,
1742 data.props->flDecayTime);
1743 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1744 data.props->flDecayHFRatio);
1746 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1747 mB_to_gain(data.props->lReflections));
1748 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1749 data.props->flReflectionsDelay);
1751 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1752 mB_to_gain(data.props->lReverb));
1753 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1754 data.props->flReverbDelay);
1756 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1757 mB_to_gain(data.props->flAirAbsorptionHF));
1759 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1760 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1761 AL_TRUE : AL_FALSE);
1763 getALError();
1765 This->dirty.bit.effect = 1;
1766 res = DS_OK;
1769 else if(propid == DSPROPERTY_EAXLISTENER_ROOM)
1771 res = DSERR_INVALIDPARAM;
1772 if(cbPropData >= sizeof(LONG))
1774 union {
1775 const void *v;
1776 const LONG *l;
1777 } data = { pPropData };
1779 This->eax_prop.lRoom = *data.l;
1780 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1781 mB_to_gain(This->eax_prop.lRoom));
1782 getALError();
1784 This->dirty.bit.effect = 1;
1785 res = DS_OK;
1788 else if(propid == DSPROPERTY_EAXLISTENER_ROOMHF)
1790 res = DSERR_INVALIDPARAM;
1791 if(cbPropData >= sizeof(LONG))
1793 union {
1794 const void *v;
1795 const LONG *l;
1796 } data = { pPropData };
1798 This->eax_prop.lRoomHF = *data.l;
1799 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1800 mB_to_gain(This->eax_prop.lRoomHF));
1801 getALError();
1803 This->dirty.bit.effect = 1;
1804 res = DS_OK;
1807 else if(propid == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1809 res = DSERR_INVALIDPARAM;
1810 if(cbPropData >= sizeof(FLOAT))
1812 union {
1813 const void *v;
1814 const FLOAT *fl;
1815 } data = { pPropData };
1817 This->eax_prop.flRoomRolloffFactor = *data.fl;
1818 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1819 This->eax_prop.flRoomRolloffFactor);
1820 getALError();
1822 This->dirty.bit.effect = 1;
1823 res = DS_OK;
1826 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1828 res = DSERR_INVALIDPARAM;
1829 if(cbPropData >= sizeof(DWORD))
1831 union {
1832 const void *v;
1833 const DWORD *dw;
1834 } data = { pPropData };
1836 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1838 /* Get the environment index's default and pass it down to
1839 * ALLPARAMETERS */
1840 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1841 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1842 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1843 goto do_allparams;
1847 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1849 res = DSERR_INVALIDPARAM;
1850 if(cbPropData >= sizeof(FLOAT))
1852 union {
1853 const void *v;
1854 const FLOAT *fl;
1855 } data = { pPropData };
1857 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1859 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1861 This->eax_prop.flEnvironmentSize = *data.fl;
1863 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1865 This->eax_prop.flDecayTime *= scale;
1866 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1868 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1870 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1871 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1873 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1875 This->eax_prop.flReflectionsDelay *= scale;
1876 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1878 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1880 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1881 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1883 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1885 This->eax_prop.flReverbDelay *= scale;
1886 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1889 /* Pass the updated environment properties down to ALLPARAMETERS */
1890 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1891 pPropData = (void*)&This->eax_prop;
1892 cbPropData = sizeof(This->eax_prop);
1893 goto do_allparams;
1897 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
1899 res = DSERR_INVALIDPARAM;
1900 if(cbPropData >= sizeof(FLOAT))
1902 union {
1903 const void *v;
1904 const FLOAT *fl;
1905 } data = { pPropData };
1907 This->eax_prop.flEnvironmentDiffusion = *data.fl;
1908 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1909 This->eax_prop.flEnvironmentDiffusion);
1910 getALError();
1912 This->dirty.bit.effect = 1;
1913 res = DS_OK;
1916 else if(propid == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
1918 res = DSERR_INVALIDPARAM;
1919 if(cbPropData >= sizeof(FLOAT))
1921 union {
1922 const void *v;
1923 const FLOAT *fl;
1924 } data = { pPropData };
1926 This->eax_prop.flAirAbsorptionHF = *data.fl;
1927 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1928 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
1929 getALError();
1931 This->dirty.bit.effect = 1;
1932 res = DS_OK;
1935 else if(propid == DSPROPERTY_EAXLISTENER_FLAGS)
1937 res = DSERR_INVALIDPARAM;
1938 if(cbPropData >= sizeof(DWORD))
1940 union {
1941 const void *v;
1942 const DWORD *dw;
1943 } data = { pPropData };
1945 This->eax_prop.dwFlags = *data.dw;
1946 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1947 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1948 AL_TRUE : AL_FALSE);
1949 getALError();
1951 This->dirty.bit.effect = 1;
1952 res = DS_OK;
1955 else if(propid != 0)
1956 FIXME("Unhandled propid: 0x%08x\n", propid);
1958 if(res == DS_OK && immediate)
1959 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
1961 popALContext();
1962 LeaveCriticalSection(&This->crst);
1964 else
1965 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1967 return res;
1970 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
1971 REFGUID guidPropSet, ULONG dwPropID,
1972 PULONG pTypeSupport)
1974 DS8Primary *This = impl_from_IKsPropertySet(iface);
1975 HRESULT res = E_PROP_ID_UNSUPPORTED;
1977 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
1979 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1981 EnterCriticalSection(&This->crst);
1983 if(This->effect == 0)
1984 res = E_PROP_ID_UNSUPPORTED;
1985 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
1986 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
1987 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
1988 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
1989 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
1990 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
1991 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
1992 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
1993 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
1995 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
1996 res = DS_OK;
1998 else
1999 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
2001 LeaveCriticalSection(&This->crst);
2003 else
2004 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2006 return res;
2009 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2011 DS8PrimaryProp_QueryInterface,
2012 DS8PrimaryProp_AddRef,
2013 DS8PrimaryProp_Release,
2014 DS8PrimaryProp_Get,
2015 DS8PrimaryProp_Set,
2016 DS8PrimaryProp_QuerySupport