Constify some pointers that won't change after initialization
[dsound-openal.git] / primary.c
blob00f5adae1f9552e8d86d13aba31378c91fd3d462
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;
72 static void AL_APIENTRY wrap_DeferUpdates(void)
73 { alcSuspendContext(alcGetCurrentContext()); }
74 static void AL_APIENTRY wrap_ProcessUpdates(void)
75 { alcProcessContext(alcGetCurrentContext()); }
78 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
80 DWORD i;
81 for(i = 0; i < buf->nnotify; ++i)
83 DSBPOSITIONNOTIFY *not = &buf->notify[i];
84 HANDLE event = not->hEventNotify;
85 DWORD ofs = not->dwOffset;
87 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
88 continue;
90 /* Wraparound case */
91 if(curpos < lastpos)
93 if(ofs < curpos || ofs >= lastpos)
94 SetEvent(event);
95 continue;
98 /* Normal case */
99 if(ofs >= lastpos && ofs < curpos)
100 SetEvent(event);
104 static void trigger_stop_notifies(DS8Buffer *buf)
106 DWORD i;
107 for(i = 0; i < buf->nnotify; ++i)
109 DSBPOSITIONNOTIFY *not = &buf->notify[i];
110 if(not->dwOffset == (DWORD)DSBPN_OFFSETSTOP)
111 SetEvent(not->hEventNotify);
115 static DWORD CALLBACK ThreadProc(void *dwUser)
117 DS8Primary *prim = (DS8Primary*)dwUser;
118 DWORD i;
119 MSG msg;
121 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
123 while(GetMessageA(&msg, NULL, 0, 0))
125 if(msg.message != WM_USER)
126 continue;
128 EnterCriticalSection(prim->crst);
129 setALContext(prim->ctx);
131 /* OpenAL doesn't support our lovely buffer extensions
132 * so just make sure enough buffers are queued
134 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES] &&
135 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
136 !prim->SupportedExt[EXT_STATIC_BUFFER])
138 for(i = 0;i < prim->nbuffers;++i)
140 DS8Buffer *buf = prim->buffers[i];
141 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
142 ALuint which, ofs;
144 if(buf->buffer->numsegs == 1 || !buf->isplaying)
145 continue;
147 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
148 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
149 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
151 queued -= done;
152 while(done--)
153 alSourceUnqueueBuffers(buf->source, 1, &which);
154 while(queued < QBUFFERS)
156 which = buf->buffer->buffers[buf->curidx];
157 ofs = buf->curidx*buf->buffer->segsize;
158 if(buf->curidx < buf->buffer->numsegs-1)
159 alBufferData(which, buf->buffer->buf_format,
160 buf->buffer->data + ofs, buf->buffer->segsize,
161 buf->buffer->format.Format.nSamplesPerSec);
162 else
163 alBufferData(which, buf->buffer->buf_format,
164 buf->buffer->data + ofs, buf->buffer->lastsegsize,
165 buf->buffer->format.Format.nSamplesPerSec);
167 alSourceQueueBuffers(buf->source, 1, &which);
168 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
169 queued++;
171 if(!buf->curidx && !buf->islooping)
173 buf->isplaying = FALSE;
174 break;
177 if(state != AL_PLAYING)
179 if(!queued)
181 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
182 continue;
184 alSourcePlay(buf->source);
187 checkALError();
190 for(i = 0;i < prim->nnotifies;)
192 DS8Buffer *buf = prim->notifies[i];
193 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
194 DWORD status=0, curpos=buf->lastpos;
196 IDirectSoundBuffer8_GetStatus(dsb, &status);
197 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
198 if(buf->lastpos != curpos)
200 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
201 buf->lastpos = curpos;
203 if(!(status&DSBSTATUS_PLAYING))
205 /* Remove this buffer from list and put another at the
206 * current position; don't increment i
208 trigger_stop_notifies(buf);
209 prim->notifies[i] = prim->notifies[--prim->nnotifies];
210 continue;
212 i++;
214 popALContext();
215 LeaveCriticalSection(prim->crst);
217 return 0;
221 HRESULT DS8Primary_PreInit(DS8Primary *This, DS8Impl *parent)
223 DS3DLISTENER *listener;
224 WAVEFORMATEX *wfx;
225 HRESULT hr;
227 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
228 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
229 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
231 This->parent = parent;
232 This->crst = &parent->share->crst;
233 This->ctx = parent->share->ctx;
234 This->SupportedExt = parent->share->SupportedExt;
235 This->ExtAL = &parent->share->ExtAL;
236 This->sources = parent->share->sources;
237 This->effect = parent->share->effect;
238 This->auxslot = parent->share->auxslot;
240 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
241 wfx = &This->format.Format;
243 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
245 wfx->wFormatTag = WAVE_FORMAT_PCM;
246 wfx->nChannels = 2;
247 wfx->wBitsPerSample = 8;
248 wfx->nSamplesPerSec = 22050;
249 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
250 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
251 wfx->cbSize = 0;
253 This->stopped = TRUE;
255 /* Apparently primary buffer size is always 32k,
256 * tested on windows with 192k 24 bits sound @ 6 channels
257 * where it will run out in 60 ms and it isn't pointer aligned
259 This->buf_size = 32768;
261 if(This->SupportedExt[SOFT_DEFERRED_UPDATES])
263 This->DeferUpdates = This->ExtAL->DeferUpdatesSOFT;
264 This->ProcessUpdates = This->ExtAL->ProcessUpdatesSOFT;
266 else
268 This->DeferUpdates = wrap_DeferUpdates;
269 This->ProcessUpdates = wrap_ProcessUpdates;
272 /* Make sure DS3DListener defaults are applied to OpenAL */
273 listener = &This->listen;
274 listener->dwSize = sizeof(*listener);
275 listener->vPosition.x = 0.0;
276 listener->vPosition.y = 0.0;
277 listener->vPosition.z = 0.0;
278 listener->vVelocity.x = 0.0;
279 listener->vVelocity.y = 0.0;
280 listener->vVelocity.z = 0.0;
281 listener->vOrientFront.x = 0.0;
282 listener->vOrientFront.y = 0.0;
283 listener->vOrientFront.z = 1.0;
284 listener->vOrientTop.x = 0.0;
285 listener->vOrientTop.y = 1.0;
286 listener->vOrientTop.z = 0.0;
287 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
288 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
289 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
290 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
291 if(FAILED(hr))
292 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
294 This->sizenotifies = This->sizebuffers = parent->share->max_sources;
296 hr = DSERR_OUTOFMEMORY;
297 This->buffers = HeapAlloc(GetProcessHeap(), 0, This->sizebuffers*sizeof(*This->buffers));
298 This->notifies = HeapAlloc(GetProcessHeap(), 0, This->sizenotifies*sizeof(*This->notifies));
299 if(!This->buffers || !This->notifies)
300 goto fail;
302 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
303 if(This->thread_hdl == NULL)
304 goto fail;
306 return S_OK;
308 fail:
309 DS8Primary_Clear(This);
310 return hr;
313 void DS8Primary_Clear(DS8Primary *This)
315 TRACE("Clearing primary %p\n", This);
317 if(!This->parent)
318 return;
320 if(This->timer_id)
322 timeKillEvent(This->timer_id);
323 timeEndPeriod(This->timer_res);
324 TRACE("Killed timer\n");
326 if(This->thread_hdl)
328 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
329 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
330 ERR("Thread wait timed out");
331 CloseHandle(This->thread_hdl);
334 EnterCriticalSection(This->crst);
335 while(This->nbuffers--)
336 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
337 LeaveCriticalSection(This->crst);
339 HeapFree(GetProcessHeap(), 0, This->notifies);
340 HeapFree(GetProcessHeap(), 0, This->buffers);
341 memset(This, 0, sizeof(*This));
344 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
346 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
349 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
351 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
353 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
355 *ppv = NULL;
356 if(IsEqualIID(riid, &IID_IUnknown) ||
357 IsEqualIID(riid, &IID_IDirectSoundBuffer))
358 *ppv = &This->IDirectSoundBuffer_iface;
359 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
361 if((This->flags&DSBCAPS_CTRL3D))
362 *ppv = &This->IDirectSound3DListener_iface;
364 else
365 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
367 if(*ppv)
369 IUnknown_AddRef((IUnknown*)*ppv);
370 return S_OK;
373 return E_NOINTERFACE;
376 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
378 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
379 LONG ret;
381 ret = InterlockedIncrement(&This->ref);
382 if(ret == 1) This->flags = 0;
384 return ret;
387 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
389 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
390 LONG ret;
392 ret = InterlockedDecrement(&This->ref);
394 return ret;
397 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
399 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
401 TRACE("(%p)->(%p)\n", iface, caps);
403 if(!caps || caps->dwSize < sizeof(*caps))
405 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
406 return DSERR_INVALIDPARAM;
409 EnterCriticalSection(This->crst);
410 caps->dwFlags = This->flags;
411 caps->dwBufferBytes = This->buf_size;
412 caps->dwUnlockTransferRate = 0;
413 caps->dwPlayCpuOverhead = 0;
414 LeaveCriticalSection(This->crst);
416 return DS_OK;
419 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
421 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
422 HRESULT hr = DSERR_PRIOLEVELNEEDED;
424 EnterCriticalSection(This->crst);
425 if(This->write_emu)
426 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
427 LeaveCriticalSection(This->crst);
429 return hr;
432 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
434 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
435 HRESULT hr = S_OK;
436 UINT size;
438 if(!wfx && !written)
440 WARN("Cannot report format or format size\n");
441 return DSERR_INVALIDPARAM;
444 EnterCriticalSection(This->crst);
445 size = sizeof(This->format.Format) + This->format.Format.cbSize;
446 if(written)
447 *written = size;
448 if(wfx)
450 if(allocated < size)
451 hr = DSERR_INVALIDPARAM;
452 else
453 memcpy(wfx, &This->format.Format, size);
455 LeaveCriticalSection(This->crst);
457 return hr;
460 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
462 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
463 HRESULT hr = S_OK;
465 TRACE("(%p)->(%p)\n", iface, volume);
467 if(!volume)
468 return DSERR_INVALIDPARAM;
470 EnterCriticalSection(This->crst);
471 if(!(This->flags & DSBCAPS_CTRLVOLUME))
472 hr = DSERR_CONTROLUNAVAIL;
473 else
475 ALfloat gain;
477 setALContext(This->ctx);
478 alGetListenerf(AL_GAIN, &gain);
479 checkALError();
480 popALContext();
482 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
484 LeaveCriticalSection(This->crst);
486 return hr;
489 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
491 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
492 HRESULT hr = S_OK;
494 WARN("(%p)->(%p): semi-stub\n", iface, pan);
496 if(!pan)
497 return DSERR_INVALIDPARAM;
499 EnterCriticalSection(This->crst);
500 if(This->write_emu)
501 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
502 else if(!(This->flags & DSBCAPS_CTRLPAN))
503 hr = DSERR_CONTROLUNAVAIL;
504 else
505 *pan = 0;
506 LeaveCriticalSection(This->crst);
508 return hr;
511 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
513 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
514 HRESULT hr = S_OK;
516 WARN("(%p)->(%p): semi-stub\n", iface, freq);
518 if(!freq)
519 return DSERR_INVALIDPARAM;
521 EnterCriticalSection(This->crst);
522 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
523 hr = DSERR_CONTROLUNAVAIL;
524 else
525 *freq = This->format.Format.nSamplesPerSec;
526 LeaveCriticalSection(This->crst);
528 return hr;
531 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
533 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
535 TRACE("(%p)->(%p)\n", iface, status);
537 if(!status)
538 return DSERR_INVALIDPARAM;
540 EnterCriticalSection(This->crst);
542 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
543 if((This->flags&DSBCAPS_LOCDEFER))
544 *status |= DSBSTATUS_LOCHARDWARE;
546 if(This->stopped)
548 DWORD i, state;
549 HRESULT hr;
551 for(i = 0;i < This->nbuffers;++i)
553 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
554 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
555 break;
557 if(i == This->nbuffers)
559 /* Primary stopped and no buffers playing.. */
560 *status = 0;
564 LeaveCriticalSection(This->crst);
566 return S_OK;
569 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
571 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
572 HRESULT hr = S_OK;
574 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
576 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
578 WARN("Bad DSBDESC for primary buffer\n");
579 return DSERR_INVALIDPARAM;
581 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
582 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
583 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
585 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
586 return DSERR_INVALIDPARAM;
589 EnterCriticalSection(This->crst);
590 /* Should be 0 if not initialized */
591 if(This->flags)
593 hr = DSERR_ALREADYINITIALIZED;
594 goto out;
597 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
599 DSBUFFERDESC emudesc;
600 DS8Buffer *emu;
602 if(This->write_emu)
604 ERR("There shouldn't be a write_emu!\n");
605 IDirectSoundBuffer8_Release(This->write_emu);
606 This->write_emu = NULL;
609 memset(&emudesc, 0, sizeof(emudesc));
610 emudesc.dwSize = sizeof(emudesc);
611 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
612 /* Dont play last incomplete sample */
613 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
614 emudesc.lpwfxFormat = &This->format.Format;
616 hr = DS8Buffer_Create(&emu, This, NULL);
617 if(SUCCEEDED(hr))
619 This->write_emu = &emu->IDirectSoundBuffer8_iface;
620 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
621 if(FAILED(hr))
623 IDirectSoundBuffer8_Release(This->write_emu);
624 This->write_emu = NULL;
629 if(SUCCEEDED(hr))
630 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
631 out:
632 LeaveCriticalSection(This->crst);
633 return hr;
636 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
638 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
639 HRESULT hr = DSERR_PRIOLEVELNEEDED;
641 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
643 EnterCriticalSection(This->crst);
644 if(This->write_emu)
645 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
646 LeaveCriticalSection(This->crst);
648 return hr;
651 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
653 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
654 HRESULT hr;
656 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
658 if(!(flags & DSBPLAY_LOOPING))
660 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
661 return DSERR_INVALIDPARAM;
664 EnterCriticalSection(This->crst);
665 hr = S_OK;
666 if(This->write_emu)
667 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
668 if(SUCCEEDED(hr))
669 This->stopped = FALSE;
670 LeaveCriticalSection(This->crst);
672 return hr;
675 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
677 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
678 return DSERR_INVALIDCALL;
681 /* Just assume the format is crap, and clean up the damage */
682 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
684 if(from->wFormatTag == WAVE_FORMAT_PCM)
686 wfx->cbSize = 0;
687 if(from->wBitsPerSample == 8 ||
688 from->wBitsPerSample == 16 ||
689 from->wBitsPerSample == 24 ||
690 from->wBitsPerSample == 32)
691 wfx->wBitsPerSample = from->wBitsPerSample;
693 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
695 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
696 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
697 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
699 /* Fail silently.. */
700 if(from->cbSize < size)
701 return;
702 if(!fromx->Samples.wValidBitsPerSample &&
703 !fromx->Format.wBitsPerSample)
704 return;
706 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
707 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
709 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
710 return;
713 wfe->Format.wBitsPerSample = from->wBitsPerSample;
714 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
715 if(!wfe->Samples.wValidBitsPerSample)
716 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
717 wfe->Format.cbSize = size;
718 wfe->dwChannelMask = fromx->dwChannelMask;
719 wfe->SubFormat = fromx->SubFormat;
721 else
723 ERR("Unhandled format tag %04x\n", from->wFormatTag);
724 return;
727 if(from->nChannels)
728 wfx->nChannels = from->nChannels;
729 wfx->wFormatTag = from->wFormatTag;
730 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
731 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
732 wfx->nSamplesPerSec = from->nSamplesPerSec;
733 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
734 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
737 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
739 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
740 HRESULT hr = S_OK;
741 ALCint freq;
743 TRACE("(%p)->(%p)\n", iface, wfx);
745 if(!wfx)
747 WARN("Missing format\n");
748 return DSERR_INVALIDPARAM;
751 EnterCriticalSection(This->crst);
753 if(This->parent->prio_level < DSSCL_PRIORITY)
755 hr = DSERR_PRIOLEVELNEEDED;
756 goto out;
759 TRACE("Requested primary format:\n"
760 " FormatTag = %04x\n"
761 " Channels = %u\n"
762 " SamplesPerSec = %"LONGFMT"u\n"
763 " AvgBytesPerSec = %"LONGFMT"u\n"
764 " BlockAlign = %u\n"
765 " BitsPerSample = %u\n",
766 wfx->wFormatTag, wfx->nChannels,
767 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
768 wfx->nBlockAlign, wfx->wBitsPerSample);
770 copy_waveformat(&This->format.Format, wfx);
772 freq = This->format.Format.nSamplesPerSec;
773 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
774 checkALCError(This->parent->device);
776 This->format.Format.nSamplesPerSec = freq;
777 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
778 This->format.Format.nSamplesPerSec;
780 if(This->write_emu)
782 DS8Buffer *buf;
783 DSBUFFERDESC desc;
785 memset(&desc, 0, sizeof(desc));
786 desc.dwSize = sizeof(desc);
787 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
788 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
789 desc.lpwfxFormat = &This->format.Format;
791 hr = DS8Buffer_Create(&buf, This, NULL);
792 if(FAILED(hr))
793 goto out;
795 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
796 if(FAILED(hr))
797 DS8Buffer_Destroy(buf);
798 else
800 IDirectSoundBuffer8_Release(This->write_emu);
801 This->write_emu = &buf->IDirectSoundBuffer8_iface;
805 out:
806 LeaveCriticalSection(This->crst);
807 return hr;
810 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
812 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
813 HRESULT hr = S_OK;
815 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
817 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
819 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
820 return DSERR_INVALIDPARAM;
823 EnterCriticalSection(This->crst);
824 if(!(This->flags&DSBCAPS_CTRLVOLUME))
825 hr = DSERR_CONTROLUNAVAIL;
826 if(SUCCEEDED(hr))
828 setALContext(This->ctx);
829 alListenerf(AL_GAIN, mB_to_gain(vol));
830 popALContext();
832 LeaveCriticalSection(This->crst);
834 return hr;
837 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
839 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
840 HRESULT hr;
842 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
844 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
846 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
847 return DSERR_INVALIDPARAM;
850 EnterCriticalSection(This->crst);
851 if(!(This->flags&DSBCAPS_CTRLPAN))
853 WARN("control unavailable\n");
854 hr = DSERR_CONTROLUNAVAIL;
856 else if(This->write_emu)
857 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
858 else
860 FIXME("Not supported\n");
861 hr = E_NOTIMPL;
863 LeaveCriticalSection(This->crst);
865 return hr;
868 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
870 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
871 return DSERR_CONTROLUNAVAIL;
874 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
876 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
877 HRESULT hr = S_OK;
879 TRACE("(%p)->()\n", iface);
881 EnterCriticalSection(This->crst);
882 if(This->write_emu)
883 hr = IDirectSoundBuffer8_Stop(This->write_emu);
884 if(SUCCEEDED(hr))
885 This->stopped = TRUE;
886 LeaveCriticalSection(This->crst);
888 return hr;
891 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
893 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
894 HRESULT hr = DSERR_INVALIDCALL;
896 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
898 EnterCriticalSection(This->crst);
899 if(This->write_emu)
900 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
901 LeaveCriticalSection(This->crst);
903 return hr;
906 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
908 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
909 HRESULT hr = S_OK;
911 TRACE("(%p)->()\n", iface);
913 EnterCriticalSection(This->crst);
914 if(This->write_emu)
915 hr = IDirectSoundBuffer8_Restore(This->write_emu);
916 LeaveCriticalSection(This->crst);
918 return hr;
921 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
923 DS8Primary_QueryInterface,
924 DS8Primary_AddRef,
925 DS8Primary_Release,
926 DS8Primary_GetCaps,
927 DS8Primary_GetCurrentPosition,
928 DS8Primary_GetFormat,
929 DS8Primary_GetVolume,
930 DS8Primary_GetPan,
931 DS8Primary_GetFrequency,
932 DS8Primary_GetStatus,
933 DS8Primary_Initialize,
934 DS8Primary_Lock,
935 DS8Primary_Play,
936 DS8Primary_SetCurrentPosition,
937 DS8Primary_SetFormat,
938 DS8Primary_SetVolume,
939 DS8Primary_SetPan,
940 DS8Primary_SetFrequency,
941 DS8Primary_Stop,
942 DS8Primary_Unlock,
943 DS8Primary_Restore
946 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
948 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
951 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
953 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
954 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
957 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
959 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
960 LONG ret;
962 ret = InterlockedIncrement(&This->ds3d_ref);
963 TRACE("new refcount %"LONGFMT"d\n", ret);
965 return ret;
969 /* Considering the primary buffer doesn't get destroyed
970 * it doesn't make sense to destroy ds3d here
972 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
974 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
975 LONG ret;
977 ret = InterlockedDecrement(&This->ds3d_ref);
978 TRACE("new refcount %"LONGFMT"d\n", ret);
980 return ret;
984 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
986 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
988 TRACE("(%p)->(%p)\n", iface, listener);
990 if(!listener || listener->dwSize < sizeof(*listener))
992 WARN("Invalid DS3DLISTENER %p %"LONGFMT"u\n", listener, listener ? listener->dwSize : 0);
993 return DSERR_INVALIDPARAM;
996 EnterCriticalSection(This->crst);
997 setALContext(This->ctx);
998 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
999 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1000 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1001 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1002 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1003 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
1004 popALContext();
1005 LeaveCriticalSection(This->crst);
1007 return DS_OK;
1010 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1012 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1014 TRACE("(%p)->(%p)\n", iface, distancefactor);
1016 if(!distancefactor)
1018 WARN("Invalid parameter %p\n", distancefactor);
1019 return DSERR_INVALIDPARAM;
1022 EnterCriticalSection(This->crst);
1023 setALContext(This->ctx);
1025 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1026 checkALError();
1028 popALContext();
1029 LeaveCriticalSection(This->crst);
1031 return S_OK;
1034 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1036 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1038 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1040 if(!dopplerfactor)
1042 WARN("Invalid parameter %p\n", dopplerfactor);
1043 return DSERR_INVALIDPARAM;
1046 EnterCriticalSection(This->crst);
1047 setALContext(This->ctx);
1049 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1050 checkALError();
1052 popALContext();
1053 LeaveCriticalSection(This->crst);
1055 return S_OK;
1058 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1060 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1061 ALfloat orient[6];
1063 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1065 if(!front || !top)
1067 WARN("Invalid parameter %p %p\n", front, top);
1068 return DSERR_INVALIDPARAM;
1071 EnterCriticalSection(This->crst);
1072 setALContext(This->ctx);
1074 alGetListenerfv(AL_ORIENTATION, orient);
1075 checkALError();
1077 front->x = orient[0];
1078 front->y = orient[1];
1079 front->z = -orient[2];
1080 top->x = orient[3];
1081 top->y = orient[4];
1082 top->z = -orient[5];
1084 popALContext();
1085 LeaveCriticalSection(This->crst);
1087 return S_OK;
1090 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1092 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1093 ALfloat alpos[3];
1095 TRACE("(%p)->(%p)\n", iface, pos);
1097 if(!pos)
1099 WARN("Invalid parameter %p\n", pos);
1100 return DSERR_INVALIDPARAM;
1103 EnterCriticalSection(This->crst);
1104 setALContext(This->ctx);
1106 alGetListenerfv(AL_POSITION, alpos);
1107 checkALError();
1109 pos->x = alpos[0];
1110 pos->y = alpos[1];
1111 pos->z = -alpos[2];
1113 popALContext();
1114 LeaveCriticalSection(This->crst);
1116 return S_OK;
1119 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1121 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1123 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1125 if(!rollofffactor)
1127 WARN("Invalid parameter %p\n", rollofffactor);
1128 return DSERR_INVALIDPARAM;
1131 EnterCriticalSection(This->crst);
1132 *rollofffactor = This->rollofffactor;
1133 LeaveCriticalSection(This->crst);
1135 return S_OK;
1138 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1140 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1141 ALfloat vel[3];
1143 TRACE("(%p)->(%p)\n", iface, velocity);
1145 if(!velocity)
1147 WARN("Invalid parameter %p\n", velocity);
1148 return DSERR_INVALIDPARAM;
1151 EnterCriticalSection(This->crst);
1152 setALContext(This->ctx);
1154 alGetListenerfv(AL_VELOCITY, vel);
1155 checkALError();
1157 velocity->x = vel[0];
1158 velocity->y = vel[1];
1159 velocity->z = -vel[2];
1161 popALContext();
1162 LeaveCriticalSection(This->crst);
1164 return S_OK;
1167 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1169 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1171 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, listen, apply);
1173 if(!listen || listen->dwSize < sizeof(*listen))
1175 WARN("Invalid parameter %p %"LONGFMT"u\n", listen, listen ? listen->dwSize : 0);
1176 return DSERR_INVALIDPARAM;
1179 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1180 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1182 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1183 return DSERR_INVALIDPARAM;
1186 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1187 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1189 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1190 return DSERR_INVALIDPARAM;
1193 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1194 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1196 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1197 return DSERR_INVALIDPARAM;
1200 EnterCriticalSection(This->crst);
1201 setALContext(This->ctx);
1202 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1203 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1204 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1205 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1206 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1207 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1208 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1209 popALContext();
1210 LeaveCriticalSection(This->crst);
1212 return S_OK;
1215 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1217 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1219 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1221 if(factor < DS3D_MINDISTANCEFACTOR ||
1222 factor > DS3D_MAXDISTANCEFACTOR)
1224 WARN("Invalid parameter %f\n", factor);
1225 return DSERR_INVALIDPARAM;
1228 EnterCriticalSection(This->crst);
1229 if(apply == DS3D_DEFERRED)
1231 This->listen.flDistanceFactor = factor;
1232 This->dirty.bit.distancefactor = 1;
1234 else
1236 setALContext(This->ctx);
1237 alSpeedOfSound(343.3f/factor);
1238 if(This->SupportedExt[EXT_EFX])
1239 alListenerf(AL_METERS_PER_UNIT, factor);
1240 checkALError();
1241 popALContext();
1243 LeaveCriticalSection(This->crst);
1245 return S_OK;
1248 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1250 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1252 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1254 if(factor < DS3D_MINDOPPLERFACTOR ||
1255 factor > DS3D_MAXDOPPLERFACTOR)
1257 WARN("Invalid parameter %f\n", factor);
1258 return DSERR_INVALIDPARAM;
1261 EnterCriticalSection(This->crst);
1262 if(apply == DS3D_DEFERRED)
1264 This->listen.flDopplerFactor = factor;
1265 This->dirty.bit.dopplerfactor = 1;
1267 else
1269 setALContext(This->ctx);
1270 alDopplerFactor(factor);
1271 checkALError();
1272 popALContext();
1274 LeaveCriticalSection(This->crst);
1276 return S_OK;
1279 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1281 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1283 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT"u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1285 EnterCriticalSection(This->crst);
1286 if(apply == DS3D_DEFERRED)
1288 This->listen.vOrientFront.x = xFront;
1289 This->listen.vOrientFront.y = yFront;
1290 This->listen.vOrientFront.z = zFront;
1291 This->listen.vOrientTop.x = xTop;
1292 This->listen.vOrientTop.y = yTop;
1293 This->listen.vOrientTop.z = zTop;
1294 This->dirty.bit.orientation = 1;
1296 else
1298 ALfloat orient[6] = {
1299 xFront, yFront, -zFront,
1300 xTop, yTop, -zTop
1302 setALContext(This->ctx);
1303 alListenerfv(AL_ORIENTATION, orient);
1304 checkALError();
1305 popALContext();
1307 LeaveCriticalSection(This->crst);
1309 return S_OK;
1312 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1314 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1316 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1318 EnterCriticalSection(This->crst);
1319 if(apply == DS3D_DEFERRED)
1321 This->listen.vPosition.x = x;
1322 This->listen.vPosition.y = y;
1323 This->listen.vPosition.z = z;
1324 This->dirty.bit.pos = 1;
1326 else
1328 setALContext(This->ctx);
1329 alListener3f(AL_POSITION, x, y, -z);
1330 checkALError();
1331 popALContext();
1333 LeaveCriticalSection(This->crst);
1335 return S_OK;
1338 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1340 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1342 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1344 if(factor < DS3D_MINROLLOFFFACTOR ||
1345 factor > DS3D_MAXROLLOFFFACTOR)
1347 WARN("Invalid parameter %f\n", factor);
1348 return DSERR_INVALIDPARAM;
1351 EnterCriticalSection(This->crst);
1352 if(apply == DS3D_DEFERRED)
1354 This->listen.flRolloffFactor = factor;
1355 This->dirty.bit.rollofffactor = 1;
1357 else
1359 DWORD i;
1361 setALContext(This->ctx);
1362 for(i = 0;i < This->nbuffers;++i)
1364 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1365 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1367 checkALError();
1368 popALContext();
1370 This->rollofffactor = factor;
1372 LeaveCriticalSection(This->crst);
1374 return S_OK;
1377 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1379 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1381 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1383 EnterCriticalSection(This->crst);
1384 if(apply == DS3D_DEFERRED)
1386 This->listen.vVelocity.x = x;
1387 This->listen.vVelocity.y = y;
1388 This->listen.vVelocity.z = z;
1389 This->dirty.bit.vel = 1;
1391 else
1393 setALContext(This->ctx);
1394 alListener3f(AL_VELOCITY, x, y, -z);
1395 checkALError();
1396 popALContext();
1398 LeaveCriticalSection(This->crst);
1400 return S_OK;
1403 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1405 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1406 const DS3DLISTENER *listen = &This->listen;
1407 DWORD i;
1409 EnterCriticalSection(This->crst);
1410 setALContext(This->ctx);
1411 This->DeferUpdates();
1413 if(This->dirty.bit.pos)
1414 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1415 if(This->dirty.bit.vel)
1416 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1417 if(This->dirty.bit.orientation)
1419 ALfloat orient[6] = {
1420 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1421 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1423 alListenerfv(AL_ORIENTATION, orient);
1425 if(This->dirty.bit.distancefactor)
1427 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1428 if(This->SupportedExt[EXT_EFX])
1429 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1432 if(This->dirty.bit.rollofffactor)
1434 ALfloat rolloff = This->rollofffactor;
1435 for(i = 0;i < This->nbuffers;++i)
1437 DS8Buffer *buf = This->buffers[i];
1438 if(buf->ds3dmode != DS3DMODE_DISABLE)
1439 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1443 if(This->dirty.bit.dopplerfactor)
1444 alDopplerFactor(listen->flDopplerFactor);
1446 if(This->dirty.bit.effect)
1447 This->ExtAL->AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1449 /* checkALError is here for debugging */
1450 checkALError();
1452 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1453 This->dirty.flags = 0;
1455 for(i = 0;i < This->nbuffers;++i)
1457 DS8Buffer *buf = This->buffers[i];
1459 if(!buf->dirty.flags)
1460 continue;
1462 if(buf->dirty.bit.pos)
1463 alSource3f(buf->source, AL_POSITION,
1464 buf->ds3dbuffer.vPosition.x,
1465 buf->ds3dbuffer.vPosition.y,
1466 -buf->ds3dbuffer.vPosition.z);
1467 if(buf->dirty.bit.vel)
1468 alSource3f(buf->source, AL_VELOCITY,
1469 buf->ds3dbuffer.vVelocity.x,
1470 buf->ds3dbuffer.vVelocity.y,
1471 -buf->ds3dbuffer.vVelocity.z);
1472 if(buf->dirty.bit.cone_angles)
1474 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1475 buf->ds3dbuffer.dwInsideConeAngle);
1476 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1477 buf->ds3dbuffer.dwOutsideConeAngle);
1479 if(buf->dirty.bit.cone_orient)
1480 alSource3f(buf->source, AL_DIRECTION,
1481 buf->ds3dbuffer.vConeOrientation.x,
1482 buf->ds3dbuffer.vConeOrientation.y,
1483 -buf->ds3dbuffer.vConeOrientation.z);
1484 if(buf->dirty.bit.cone_outsidevolume)
1485 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1486 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1487 if(buf->dirty.bit.min_distance)
1488 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1489 if(buf->dirty.bit.max_distance)
1490 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1491 if(buf->dirty.bit.mode)
1493 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1494 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1495 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1496 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1497 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1499 buf->dirty.flags = 0;
1501 checkALError();
1503 This->ProcessUpdates();
1504 popALContext();
1505 LeaveCriticalSection(This->crst);
1507 return S_OK;
1510 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1512 DS8Primary3D_QueryInterface,
1513 DS8Primary3D_AddRef,
1514 DS8Primary3D_Release,
1515 DS8Primary3D_GetAllParameters,
1516 DS8Primary3D_GetDistanceFactor,
1517 DS8Primary3D_GetDopplerFactor,
1518 DS8Primary3D_GetOrientation,
1519 DS8Primary3D_GetPosition,
1520 DS8Primary3D_GetRolloffFactor,
1521 DS8Primary3D_GetVelocity,
1522 DS8Primary3D_SetAllParameters,
1523 DS8Primary3D_SetDistanceFactor,
1524 DS8Primary3D_SetDopplerFactor,
1525 DS8Primary3D_SetOrientation,
1526 DS8Primary3D_SetPosition,
1527 DS8Primary3D_SetRolloffFactor,
1528 DS8Primary3D_SetVelocity,
1529 DS8Primary3D_CommitDeferredSettings
1532 /* NOTE: Although the app handles listener properties through secondary buffers,
1533 * we pass the requests to the primary buffer though a propertyset interface.
1534 * These methods are not exposed to the app. */
1535 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1537 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1540 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1542 DS8Primary *This = impl_from_IKsPropertySet(iface);
1543 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1546 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1548 DS8Primary *This = impl_from_IKsPropertySet(iface);
1549 LONG ret;
1551 ret = InterlockedIncrement(&This->prop_ref);
1552 TRACE("new refcount %"LONGFMT"d\n", ret);
1554 return ret;
1557 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1559 DS8Primary *This = impl_from_IKsPropertySet(iface);
1560 LONG ret;
1562 ret = InterlockedDecrement(&This->prop_ref);
1563 TRACE("new refcount %"LONGFMT"d\n", ret);
1565 return ret;
1568 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1569 REFGUID guidPropSet, ULONG dwPropID,
1570 LPVOID pInstanceData, ULONG cbInstanceData,
1571 LPVOID pPropData, ULONG cbPropData,
1572 PULONG pcbReturned)
1574 DS8Primary *This = impl_from_IKsPropertySet(iface);
1575 HRESULT res = E_PROP_ID_UNSUPPORTED;
1576 (void)pInstanceData;
1577 (void)cbInstanceData;
1579 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1581 EnterCriticalSection(This->crst);
1583 if(This->effect == 0)
1584 res = E_PROP_ID_UNSUPPORTED;
1585 else switch(dwPropID)
1587 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1588 res = DSERR_INVALIDPARAM;
1589 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1591 union {
1592 void *v;
1593 EAXLISTENERPROPERTIES *props;
1594 } data = { pPropData };
1596 *data.props = This->eax_prop;
1597 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1598 res = DS_OK;
1600 break;
1602 case DSPROPERTY_EAXLISTENER_ROOM:
1603 res = DSERR_INVALIDPARAM;
1604 if(cbPropData >= sizeof(LONG))
1606 union {
1607 void *v;
1608 LONG *l;
1609 } data = { pPropData };
1611 *data.l = This->eax_prop.lRoom;
1612 *pcbReturned = sizeof(LONG);
1613 res = DS_OK;
1615 break;
1616 case DSPROPERTY_EAXLISTENER_ROOMHF:
1617 res = DSERR_INVALIDPARAM;
1618 if(cbPropData >= sizeof(LONG))
1620 union {
1621 void *v;
1622 LONG *l;
1623 } data = { pPropData };
1625 *data.l = This->eax_prop.lRoomHF;
1626 *pcbReturned = sizeof(LONG);
1627 res = DS_OK;
1629 break;
1631 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1632 res = DSERR_INVALIDPARAM;
1633 if(cbPropData >= sizeof(FLOAT))
1635 union {
1636 void *v;
1637 FLOAT *fl;
1638 } data = { pPropData };
1640 *data.fl = This->eax_prop.flRoomRolloffFactor;
1641 *pcbReturned = sizeof(FLOAT);
1642 res = DS_OK;
1644 break;
1646 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1647 res = DSERR_INVALIDPARAM;
1648 if(cbPropData >= sizeof(DWORD))
1650 union {
1651 void *v;
1652 DWORD *dw;
1653 } data = { pPropData };
1655 *data.dw = This->eax_prop.dwEnvironment;
1656 *pcbReturned = sizeof(DWORD);
1657 res = DS_OK;
1659 break;
1661 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1662 res = DSERR_INVALIDPARAM;
1663 if(cbPropData >= sizeof(FLOAT))
1665 union {
1666 void *v;
1667 FLOAT *fl;
1668 } data = { pPropData };
1670 *data.fl = This->eax_prop.flEnvironmentSize;
1671 *pcbReturned = sizeof(FLOAT);
1672 res = DS_OK;
1674 break;
1675 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1676 res = DSERR_INVALIDPARAM;
1677 if(cbPropData >= sizeof(FLOAT))
1679 union {
1680 void *v;
1681 FLOAT *fl;
1682 } data = { pPropData };
1684 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1685 *pcbReturned = sizeof(FLOAT);
1686 res = DS_OK;
1688 break;
1690 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1691 res = DSERR_INVALIDPARAM;
1692 if(cbPropData >= sizeof(FLOAT))
1694 union {
1695 void *v;
1696 FLOAT *fl;
1697 } data = { pPropData };
1699 *data.fl = This->eax_prop.flAirAbsorptionHF;
1700 *pcbReturned = sizeof(FLOAT);
1701 res = DS_OK;
1703 break;
1705 case DSPROPERTY_EAXLISTENER_FLAGS:
1706 res = DSERR_INVALIDPARAM;
1707 if(cbPropData >= sizeof(DWORD))
1709 union {
1710 void *v;
1711 DWORD *dw;
1712 } data = { pPropData };
1714 *data.dw = This->eax_prop.dwFlags;
1715 *pcbReturned = sizeof(DWORD);
1716 res = DS_OK;
1718 break;
1720 default:
1721 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1722 break;
1725 LeaveCriticalSection(This->crst);
1727 else
1728 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1730 return res;
1733 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1734 REFGUID guidPropSet, ULONG dwPropID,
1735 LPVOID pInstanceData, ULONG cbInstanceData,
1736 LPVOID pPropData, ULONG cbPropData)
1738 DS8Primary *This = impl_from_IKsPropertySet(iface);
1739 HRESULT res = E_PROP_ID_UNSUPPORTED;
1740 (void)pInstanceData;
1741 (void)cbInstanceData;
1743 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1745 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1746 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1748 EnterCriticalSection(This->crst);
1749 setALContext(This->ctx);
1751 if(This->effect == 0)
1752 res = E_PROP_ID_UNSUPPORTED;
1753 else switch(propid)
1755 case 0: /* 0 = not setting any property, just apply */
1756 res = DS_OK;
1757 break;
1759 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1760 do_allparams:
1761 res = DSERR_INVALIDPARAM;
1762 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1764 union {
1765 const void *v;
1766 const EAXLISTENERPROPERTIES *props;
1767 } data = { pPropData };
1769 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1770 This->eax_prop = *data.props;
1771 This->ExtAL->Effectf(This->effect, AL_REVERB_DENSITY,
1772 (data.props->flEnvironmentSize < 2.0f) ?
1773 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1774 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1775 data.props->flEnvironmentDiffusion);
1777 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1778 mB_to_gain(data.props->lRoom));
1779 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1780 mB_to_gain(data.props->lRoomHF));
1782 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1783 data.props->flRoomRolloffFactor);
1785 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_TIME,
1786 data.props->flDecayTime);
1787 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1788 data.props->flDecayHFRatio);
1790 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1791 mB_to_gain(data.props->lReflections));
1792 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1793 data.props->flReflectionsDelay);
1795 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1796 mB_to_gain(data.props->lReverb));
1797 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1798 data.props->flReverbDelay);
1800 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1801 mB_to_gain(data.props->flAirAbsorptionHF));
1803 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1804 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1805 AL_TRUE : AL_FALSE);
1807 checkALError();
1809 This->dirty.bit.effect = 1;
1810 res = DS_OK;
1812 break;
1814 case DSPROPERTY_EAXLISTENER_ROOM:
1815 res = DSERR_INVALIDPARAM;
1816 if(cbPropData >= sizeof(LONG))
1818 union {
1819 const void *v;
1820 const LONG *l;
1821 } data = { pPropData };
1823 This->eax_prop.lRoom = *data.l;
1824 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1825 mB_to_gain(This->eax_prop.lRoom));
1826 checkALError();
1828 This->dirty.bit.effect = 1;
1829 res = DS_OK;
1831 break;
1832 case DSPROPERTY_EAXLISTENER_ROOMHF:
1833 res = DSERR_INVALIDPARAM;
1834 if(cbPropData >= sizeof(LONG))
1836 union {
1837 const void *v;
1838 const LONG *l;
1839 } data = { pPropData };
1841 This->eax_prop.lRoomHF = *data.l;
1842 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1843 mB_to_gain(This->eax_prop.lRoomHF));
1844 checkALError();
1846 This->dirty.bit.effect = 1;
1847 res = DS_OK;
1849 break;
1851 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1852 res = DSERR_INVALIDPARAM;
1853 if(cbPropData >= sizeof(FLOAT))
1855 union {
1856 const void *v;
1857 const FLOAT *fl;
1858 } data = { pPropData };
1860 This->eax_prop.flRoomRolloffFactor = *data.fl;
1861 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1862 This->eax_prop.flRoomRolloffFactor);
1863 checkALError();
1865 This->dirty.bit.effect = 1;
1866 res = DS_OK;
1868 break;
1870 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1871 res = DSERR_INVALIDPARAM;
1872 if(cbPropData >= sizeof(DWORD))
1874 union {
1875 const void *v;
1876 const DWORD *dw;
1877 } data = { pPropData };
1879 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1881 /* Get the environment index's default and pass it down to
1882 * ALLPARAMETERS */
1883 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1884 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1885 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1886 goto do_allparams;
1889 break;
1891 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1892 res = DSERR_INVALIDPARAM;
1893 if(cbPropData >= sizeof(FLOAT))
1895 union {
1896 const void *v;
1897 const FLOAT *fl;
1898 } data = { pPropData };
1900 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1902 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1904 This->eax_prop.flEnvironmentSize = *data.fl;
1906 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1908 This->eax_prop.flDecayTime *= scale;
1909 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1911 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1913 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1914 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1916 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1918 This->eax_prop.flReflectionsDelay *= scale;
1919 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1921 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1923 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1924 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1926 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1928 This->eax_prop.flReverbDelay *= scale;
1929 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1932 /* Pass the updated environment properties down to ALLPARAMETERS */
1933 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1934 pPropData = (void*)&This->eax_prop;
1935 cbPropData = sizeof(This->eax_prop);
1936 goto do_allparams;
1939 break;
1940 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1941 res = DSERR_INVALIDPARAM;
1942 if(cbPropData >= sizeof(FLOAT))
1944 union {
1945 const void *v;
1946 const FLOAT *fl;
1947 } data = { pPropData };
1949 This->eax_prop.flEnvironmentDiffusion = *data.fl;
1950 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1951 This->eax_prop.flEnvironmentDiffusion);
1952 checkALError();
1954 This->dirty.bit.effect = 1;
1955 res = DS_OK;
1957 break;
1959 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1960 res = DSERR_INVALIDPARAM;
1961 if(cbPropData >= sizeof(FLOAT))
1963 union {
1964 const void *v;
1965 const FLOAT *fl;
1966 } data = { pPropData };
1968 This->eax_prop.flAirAbsorptionHF = *data.fl;
1969 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1970 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
1971 checkALError();
1973 This->dirty.bit.effect = 1;
1974 res = DS_OK;
1976 break;
1978 case DSPROPERTY_EAXLISTENER_FLAGS:
1979 res = DSERR_INVALIDPARAM;
1980 if(cbPropData >= sizeof(DWORD))
1982 union {
1983 const void *v;
1984 const DWORD *dw;
1985 } data = { pPropData };
1987 This->eax_prop.dwFlags = *data.dw;
1988 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1989 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1990 AL_TRUE : AL_FALSE);
1991 checkALError();
1993 This->dirty.bit.effect = 1;
1994 res = DS_OK;
1996 default:
1997 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
1998 break;
2001 if(res == DS_OK && immediate)
2002 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2004 popALContext();
2005 LeaveCriticalSection(This->crst);
2007 else
2008 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2010 return res;
2013 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2014 REFGUID guidPropSet, ULONG dwPropID,
2015 PULONG pTypeSupport)
2017 DS8Primary *This = impl_from_IKsPropertySet(iface);
2018 HRESULT res = E_PROP_ID_UNSUPPORTED;
2020 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2022 EnterCriticalSection(This->crst);
2024 if(This->effect == 0)
2025 res = E_PROP_ID_UNSUPPORTED;
2026 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2027 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2028 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2029 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2030 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2031 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2032 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2033 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2034 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2036 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2037 res = DS_OK;
2039 else
2040 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2042 LeaveCriticalSection(This->crst);
2044 else
2045 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2047 return res;
2050 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2052 DS8PrimaryProp_QueryInterface,
2053 DS8PrimaryProp_AddRef,
2054 DS8PrimaryProp_Release,
2055 DS8PrimaryProp_Get,
2056 DS8PrimaryProp_Set,
2057 DS8PrimaryProp_QuerySupport