Reorganize some code
[wine/multimedia.git] / primary.c
blob632c10d51031e8c249b50fdb227299a8f3d2c621
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 inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
74 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
77 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
79 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
82 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
84 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
88 static void AL_APIENTRY wrap_DeferUpdates(void)
89 { alcSuspendContext(alcGetCurrentContext()); }
90 static void AL_APIENTRY wrap_ProcessUpdates(void)
91 { alcProcessContext(alcGetCurrentContext()); }
94 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
96 DWORD i;
97 for(i = 0; i < buf->nnotify; ++i)
99 DSBPOSITIONNOTIFY *not = &buf->notify[i];
100 HANDLE event = not->hEventNotify;
101 DWORD ofs = not->dwOffset;
103 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
104 continue;
106 /* Wraparound case */
107 if(curpos < lastpos)
109 if(ofs < curpos || ofs >= lastpos)
110 SetEvent(event);
111 continue;
114 /* Normal case */
115 if(ofs >= lastpos && ofs < curpos)
116 SetEvent(event);
120 static void trigger_stop_notifies(DS8Buffer *buf)
122 DWORD i;
123 for(i = 0; i < buf->nnotify; ++i)
125 DSBPOSITIONNOTIFY *not = &buf->notify[i];
126 if(not->dwOffset == (DWORD)DSBPN_OFFSETSTOP)
127 SetEvent(not->hEventNotify);
131 static DWORD CALLBACK ThreadProc(void *dwUser)
133 DS8Primary *prim = (DS8Primary*)dwUser;
134 DWORD i;
135 MSG msg;
137 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
139 while(GetMessageA(&msg, NULL, 0, 0))
141 if(msg.message != WM_USER)
142 continue;
144 EnterCriticalSection(prim->crst);
145 setALContext(prim->ctx);
147 /* OpenAL doesn't support our lovely buffer extensions
148 * so just make sure enough buffers are queued
150 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES] &&
151 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
152 !prim->SupportedExt[EXT_STATIC_BUFFER])
154 for(i = 0;i < prim->nbuffers;++i)
156 DS8Buffer *buf = prim->buffers[i];
157 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
158 ALuint which, ofs;
160 if(buf->buffer->numsegs == 1 || !buf->isplaying)
161 continue;
163 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
164 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
165 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
167 queued -= done;
168 while(done--)
169 alSourceUnqueueBuffers(buf->source, 1, &which);
170 while(queued < QBUFFERS)
172 which = buf->buffer->buffers[buf->curidx];
173 ofs = buf->curidx*buf->buffer->segsize;
174 if(buf->curidx < buf->buffer->numsegs-1)
175 alBufferData(which, buf->buffer->buf_format,
176 buf->buffer->data + ofs, buf->buffer->segsize,
177 buf->buffer->format.Format.nSamplesPerSec);
178 else
179 alBufferData(which, buf->buffer->buf_format,
180 buf->buffer->data + ofs, buf->buffer->lastsegsize,
181 buf->buffer->format.Format.nSamplesPerSec);
183 alSourceQueueBuffers(buf->source, 1, &which);
184 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
185 queued++;
187 if(!buf->curidx && !buf->islooping)
189 buf->isplaying = FALSE;
190 break;
193 if(state != AL_PLAYING)
195 if(!queued)
197 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
198 continue;
200 alSourcePlay(buf->source);
203 checkALError();
206 for(i = 0;i < prim->nnotifies;)
208 DS8Buffer *buf = prim->notifies[i];
209 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
210 DWORD status=0, curpos=buf->lastpos;
212 IDirectSoundBuffer8_GetStatus(dsb, &status);
213 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
214 if(buf->lastpos != curpos)
216 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
217 buf->lastpos = curpos;
219 if(!(status&DSBSTATUS_PLAYING))
221 /* Remove this buffer from list and put another at the
222 * current position; don't increment i
224 trigger_stop_notifies(buf);
225 prim->notifies[i] = prim->notifies[--prim->nnotifies];
226 continue;
228 i++;
230 popALContext();
231 LeaveCriticalSection(prim->crst);
233 return 0;
237 HRESULT DS8Primary_PreInit(DS8Primary *This, DS8Impl *parent)
239 DS3DLISTENER *listener;
240 WAVEFORMATEX *wfx;
241 HRESULT hr;
243 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
244 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
245 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
247 This->parent = parent;
248 This->crst = &parent->share->crst;
249 This->ctx = parent->share->ctx;
250 This->SupportedExt = parent->share->SupportedExt;
251 This->ExtAL = &parent->share->ExtAL;
252 This->sources = parent->share->sources;
253 This->auxslot = parent->share->auxslot;
255 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
256 wfx = &This->format.Format;
258 wfx->wFormatTag = WAVE_FORMAT_PCM;
259 wfx->nChannels = 2;
260 wfx->wBitsPerSample = 8;
261 wfx->nSamplesPerSec = 22050;
262 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
263 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
264 wfx->cbSize = 0;
266 This->stopped = TRUE;
268 /* Apparently primary buffer size is always 32k,
269 * tested on windows with 192k 24 bits sound @ 6 channels
270 * where it will run out in 60 ms and it isn't pointer aligned
272 This->buf_size = 32768;
274 if(This->SupportedExt[SOFT_DEFERRED_UPDATES])
276 This->DeferUpdates = This->ExtAL->DeferUpdatesSOFT;
277 This->ProcessUpdates = This->ExtAL->ProcessUpdatesSOFT;
279 else
281 This->DeferUpdates = wrap_DeferUpdates;
282 This->ProcessUpdates = wrap_ProcessUpdates;
285 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
286 if(This->SupportedExt[EXT_EFX] && This->auxslot != 0)
288 ALint revid = alGetEnumValue("AL_EFFECT_REVERB");
289 if(revid != 0 && revid != -1)
291 This->ExtAL->GenEffects(1, &This->effect);
292 This->ExtAL->Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
293 checkALError();
297 /* Make sure DS3DListener defaults are applied to OpenAL */
298 listener = &This->listen;
299 listener->dwSize = sizeof(*listener);
300 listener->vPosition.x = 0.0;
301 listener->vPosition.y = 0.0;
302 listener->vPosition.z = 0.0;
303 listener->vVelocity.x = 0.0;
304 listener->vVelocity.y = 0.0;
305 listener->vVelocity.z = 0.0;
306 listener->vOrientFront.x = 0.0;
307 listener->vOrientFront.y = 0.0;
308 listener->vOrientFront.z = 1.0;
309 listener->vOrientTop.x = 0.0;
310 listener->vOrientTop.y = 1.0;
311 listener->vOrientTop.z = 0.0;
312 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
313 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
314 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
315 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
316 if(FAILED(hr))
317 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
319 This->sizenotifies = This->sizebuffers = parent->share->max_sources;
321 hr = DSERR_OUTOFMEMORY;
322 This->buffers = HeapAlloc(GetProcessHeap(), 0, This->sizebuffers*sizeof(*This->buffers));
323 This->notifies = HeapAlloc(GetProcessHeap(), 0, This->sizenotifies*sizeof(*This->notifies));
324 if(!This->buffers || !This->notifies)
325 goto fail;
327 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
328 if(This->thread_hdl == NULL)
329 goto fail;
331 return S_OK;
333 fail:
334 DS8Primary_Clear(This);
335 return hr;
338 void DS8Primary_Clear(DS8Primary *This)
340 TRACE("Clearing primary %p\n", This);
342 if(!This->parent)
343 return;
345 if(This->timer_id)
347 timeKillEvent(This->timer_id);
348 timeEndPeriod(This->timer_res);
349 TRACE("Killed timer\n");
351 if(This->thread_hdl)
353 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
354 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
355 ERR("Thread wait timed out");
356 CloseHandle(This->thread_hdl);
359 setALContext(This->ctx);
360 if(This->effect)
361 This->ExtAL->DeleteEffects(1, &This->effect);
362 popALContext();
363 while(This->nbuffers--)
364 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
366 HeapFree(GetProcessHeap(), 0, This->notifies);
367 HeapFree(GetProcessHeap(), 0, This->buffers);
368 memset(This, 0, sizeof(*This));
371 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
373 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
375 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
377 *ppv = NULL;
378 if(IsEqualIID(riid, &IID_IUnknown) ||
379 IsEqualIID(riid, &IID_IDirectSoundBuffer))
380 *ppv = &This->IDirectSoundBuffer_iface;
381 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
383 if((This->flags&DSBCAPS_CTRL3D))
384 *ppv = &This->IDirectSound3DListener_iface;
386 else
387 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
389 if(*ppv)
391 IUnknown_AddRef((IUnknown*)*ppv);
392 return S_OK;
395 return E_NOINTERFACE;
398 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
400 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
401 LONG ret;
403 ret = InterlockedIncrement(&This->ref);
404 if(ret == 1) This->flags = 0;
406 return ret;
409 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
411 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
412 LONG ret;
414 ret = InterlockedDecrement(&This->ref);
416 return ret;
419 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
421 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
423 TRACE("(%p)->(%p)\n", iface, caps);
425 if(!caps || caps->dwSize < sizeof(*caps))
427 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
428 return DSERR_INVALIDPARAM;
431 EnterCriticalSection(This->crst);
432 caps->dwFlags = This->flags;
433 caps->dwBufferBytes = This->buf_size;
434 caps->dwUnlockTransferRate = 0;
435 caps->dwPlayCpuOverhead = 0;
436 LeaveCriticalSection(This->crst);
438 return DS_OK;
441 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
443 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
444 HRESULT hr = DSERR_PRIOLEVELNEEDED;
446 EnterCriticalSection(This->crst);
447 if(This->write_emu)
448 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
449 LeaveCriticalSection(This->crst);
451 return hr;
454 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
456 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
457 HRESULT hr = S_OK;
458 UINT size;
460 if(!wfx && !written)
462 WARN("Cannot report format or format size\n");
463 return DSERR_INVALIDPARAM;
466 EnterCriticalSection(This->crst);
467 size = sizeof(This->format.Format) + This->format.Format.cbSize;
468 if(written)
469 *written = size;
470 if(wfx)
472 if(allocated < size)
473 hr = DSERR_INVALIDPARAM;
474 else
475 memcpy(wfx, &This->format.Format, size);
477 LeaveCriticalSection(This->crst);
479 return hr;
482 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
484 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
485 HRESULT hr = S_OK;
487 TRACE("(%p)->(%p)\n", iface, volume);
489 if(!volume)
490 return DSERR_INVALIDPARAM;
492 EnterCriticalSection(This->crst);
493 if(!(This->flags & DSBCAPS_CTRLVOLUME))
494 hr = DSERR_CONTROLUNAVAIL;
495 else
497 ALfloat gain;
499 setALContext(This->ctx);
500 alGetListenerf(AL_GAIN, &gain);
501 checkALError();
502 popALContext();
504 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
506 LeaveCriticalSection(This->crst);
508 return hr;
511 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
513 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
514 HRESULT hr = S_OK;
516 WARN("(%p)->(%p): semi-stub\n", iface, pan);
518 if(!pan)
519 return DSERR_INVALIDPARAM;
521 EnterCriticalSection(This->crst);
522 if(This->write_emu)
523 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
524 else if(!(This->flags & DSBCAPS_CTRLPAN))
525 hr = DSERR_CONTROLUNAVAIL;
526 else
527 *pan = 0;
528 LeaveCriticalSection(This->crst);
530 return hr;
533 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
535 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
536 HRESULT hr = S_OK;
538 WARN("(%p)->(%p): semi-stub\n", iface, freq);
540 if(!freq)
541 return DSERR_INVALIDPARAM;
543 EnterCriticalSection(This->crst);
544 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
545 hr = DSERR_CONTROLUNAVAIL;
546 else
547 *freq = This->format.Format.nSamplesPerSec;
548 LeaveCriticalSection(This->crst);
550 return hr;
553 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
555 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
557 TRACE("(%p)->(%p)\n", iface, status);
559 if(!status)
560 return DSERR_INVALIDPARAM;
562 EnterCriticalSection(This->crst);
564 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
565 if((This->flags&DSBCAPS_LOCDEFER))
566 *status |= DSBSTATUS_LOCHARDWARE;
568 if(This->stopped)
570 DWORD i, state;
571 HRESULT hr;
573 for(i = 0;i < This->nbuffers;++i)
575 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
576 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
577 break;
579 if(i == This->nbuffers)
581 /* Primary stopped and no buffers playing.. */
582 *status = 0;
586 LeaveCriticalSection(This->crst);
588 return S_OK;
591 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
593 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
594 HRESULT hr = S_OK;
596 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
598 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
600 WARN("Bad DSBDESC for primary buffer\n");
601 return DSERR_INVALIDPARAM;
603 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
604 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
605 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
607 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
608 return DSERR_INVALIDPARAM;
611 EnterCriticalSection(This->crst);
612 /* Should be 0 if not initialized */
613 if(This->flags)
615 hr = DSERR_ALREADYINITIALIZED;
616 goto out;
619 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
621 DSBUFFERDESC emudesc;
622 DS8Buffer *emu;
624 if(This->write_emu)
626 ERR("There shouldn't be a write_emu!\n");
627 IDirectSoundBuffer8_Release(This->write_emu);
628 This->write_emu = NULL;
631 memset(&emudesc, 0, sizeof(emudesc));
632 emudesc.dwSize = sizeof(emudesc);
633 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
634 /* Dont play last incomplete sample */
635 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
636 emudesc.lpwfxFormat = &This->format.Format;
638 hr = DS8Buffer_Create(&emu, This, NULL);
639 if(SUCCEEDED(hr))
641 This->write_emu = &emu->IDirectSoundBuffer8_iface;
642 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
643 if(FAILED(hr))
645 IDirectSoundBuffer8_Release(This->write_emu);
646 This->write_emu = NULL;
651 if(SUCCEEDED(hr))
652 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
653 out:
654 LeaveCriticalSection(This->crst);
655 return hr;
658 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
660 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
661 HRESULT hr = DSERR_PRIOLEVELNEEDED;
663 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
665 EnterCriticalSection(This->crst);
666 if(This->write_emu)
667 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
668 LeaveCriticalSection(This->crst);
670 return hr;
673 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
675 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
676 HRESULT hr;
678 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
680 if(!(flags & DSBPLAY_LOOPING))
682 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
683 return DSERR_INVALIDPARAM;
686 EnterCriticalSection(This->crst);
687 hr = S_OK;
688 if(This->write_emu)
689 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
690 if(SUCCEEDED(hr))
691 This->stopped = FALSE;
692 LeaveCriticalSection(This->crst);
694 return hr;
697 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
699 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
700 return DSERR_INVALIDCALL;
703 /* Just assume the format is crap, and clean up the damage */
704 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
706 if(from->wFormatTag == WAVE_FORMAT_PCM)
708 wfx->cbSize = 0;
709 if(from->wBitsPerSample == 8 ||
710 from->wBitsPerSample == 16 ||
711 from->wBitsPerSample == 24 ||
712 from->wBitsPerSample == 32)
713 wfx->wBitsPerSample = from->wBitsPerSample;
715 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
717 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
718 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
719 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
721 /* Fail silently.. */
722 if(from->cbSize < size)
723 return;
724 if(!fromx->Samples.wValidBitsPerSample &&
725 !fromx->Format.wBitsPerSample)
726 return;
728 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
729 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
731 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
732 return;
735 wfe->Format.wBitsPerSample = from->wBitsPerSample;
736 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
737 if(!wfe->Samples.wValidBitsPerSample)
738 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
739 wfe->Format.cbSize = size;
740 wfe->dwChannelMask = fromx->dwChannelMask;
741 wfe->SubFormat = fromx->SubFormat;
743 else
745 ERR("Unhandled format tag %04x\n", from->wFormatTag);
746 return;
749 if(from->nChannels)
750 wfx->nChannels = from->nChannels;
751 wfx->wFormatTag = from->wFormatTag;
752 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
753 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
754 wfx->nSamplesPerSec = from->nSamplesPerSec;
755 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
756 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
759 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
761 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
762 HRESULT hr = S_OK;
763 ALCint freq;
765 TRACE("(%p)->(%p)\n", iface, wfx);
767 if(!wfx)
769 WARN("Missing format\n");
770 return DSERR_INVALIDPARAM;
773 EnterCriticalSection(This->crst);
775 if(This->parent->prio_level < DSSCL_PRIORITY)
777 hr = DSERR_PRIOLEVELNEEDED;
778 goto out;
781 TRACE("Requested primary format:\n"
782 " FormatTag = %04x\n"
783 " Channels = %u\n"
784 " SamplesPerSec = %"LONGFMT"u\n"
785 " AvgBytesPerSec = %"LONGFMT"u\n"
786 " BlockAlign = %u\n"
787 " BitsPerSample = %u\n",
788 wfx->wFormatTag, wfx->nChannels,
789 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
790 wfx->nBlockAlign, wfx->wBitsPerSample);
792 copy_waveformat(&This->format.Format, wfx);
794 freq = This->format.Format.nSamplesPerSec;
795 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
796 checkALCError(This->parent->device);
798 This->format.Format.nSamplesPerSec = freq;
799 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
800 This->format.Format.nSamplesPerSec;
802 if(This->write_emu)
804 DS8Buffer *buf;
805 DSBUFFERDESC desc;
807 memset(&desc, 0, sizeof(desc));
808 desc.dwSize = sizeof(desc);
809 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
810 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
811 desc.lpwfxFormat = &This->format.Format;
813 hr = DS8Buffer_Create(&buf, This, NULL);
814 if(FAILED(hr))
815 goto out;
817 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
818 if(FAILED(hr))
819 DS8Buffer_Destroy(buf);
820 else
822 IDirectSoundBuffer8_Release(This->write_emu);
823 This->write_emu = &buf->IDirectSoundBuffer8_iface;
827 out:
828 LeaveCriticalSection(This->crst);
829 return hr;
832 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
834 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
835 HRESULT hr = S_OK;
837 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
839 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
841 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
842 return DSERR_INVALIDPARAM;
845 EnterCriticalSection(This->crst);
846 if(!(This->flags&DSBCAPS_CTRLVOLUME))
847 hr = DSERR_CONTROLUNAVAIL;
848 if(SUCCEEDED(hr))
850 setALContext(This->ctx);
851 alListenerf(AL_GAIN, mB_to_gain(vol));
852 popALContext();
854 LeaveCriticalSection(This->crst);
856 return hr;
859 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
861 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
862 HRESULT hr;
864 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
866 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
868 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
869 return DSERR_INVALIDPARAM;
872 EnterCriticalSection(This->crst);
873 if(!(This->flags&DSBCAPS_CTRLPAN))
875 WARN("control unavailable\n");
876 hr = DSERR_CONTROLUNAVAIL;
878 else if(This->write_emu)
879 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
880 else
882 FIXME("Not supported\n");
883 hr = E_NOTIMPL;
885 LeaveCriticalSection(This->crst);
887 return hr;
890 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
892 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
893 return DSERR_CONTROLUNAVAIL;
896 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
898 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
899 HRESULT hr = S_OK;
901 TRACE("(%p)->()\n", iface);
903 EnterCriticalSection(This->crst);
904 if(This->write_emu)
905 hr = IDirectSoundBuffer8_Stop(This->write_emu);
906 if(SUCCEEDED(hr))
907 This->stopped = TRUE;
908 LeaveCriticalSection(This->crst);
910 return hr;
913 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
915 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
916 HRESULT hr = DSERR_INVALIDCALL;
918 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
920 EnterCriticalSection(This->crst);
921 if(This->write_emu)
922 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
923 LeaveCriticalSection(This->crst);
925 return hr;
928 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
930 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
931 HRESULT hr = S_OK;
933 TRACE("(%p)->()\n", iface);
935 EnterCriticalSection(This->crst);
936 if(This->write_emu)
937 hr = IDirectSoundBuffer8_Restore(This->write_emu);
938 LeaveCriticalSection(This->crst);
940 return hr;
943 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
945 DS8Primary_QueryInterface,
946 DS8Primary_AddRef,
947 DS8Primary_Release,
948 DS8Primary_GetCaps,
949 DS8Primary_GetCurrentPosition,
950 DS8Primary_GetFormat,
951 DS8Primary_GetVolume,
952 DS8Primary_GetPan,
953 DS8Primary_GetFrequency,
954 DS8Primary_GetStatus,
955 DS8Primary_Initialize,
956 DS8Primary_Lock,
957 DS8Primary_Play,
958 DS8Primary_SetCurrentPosition,
959 DS8Primary_SetFormat,
960 DS8Primary_SetVolume,
961 DS8Primary_SetPan,
962 DS8Primary_SetFrequency,
963 DS8Primary_Stop,
964 DS8Primary_Unlock,
965 DS8Primary_Restore
969 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
971 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
972 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
975 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
977 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
978 LONG ret;
980 ret = InterlockedIncrement(&This->ds3d_ref);
981 TRACE("new refcount %"LONGFMT"d\n", ret);
983 return ret;
986 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
988 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
989 LONG ret;
991 ret = InterlockedDecrement(&This->ds3d_ref);
992 TRACE("new refcount %"LONGFMT"d\n", ret);
994 return ret;
998 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1000 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1002 TRACE("(%p)->(%p)\n", iface, listener);
1004 if(!listener || listener->dwSize < sizeof(*listener))
1006 WARN("Invalid DS3DLISTENER %p %"LONGFMT"u\n", listener, listener ? listener->dwSize : 0);
1007 return DSERR_INVALIDPARAM;
1010 EnterCriticalSection(This->crst);
1011 setALContext(This->ctx);
1012 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1013 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1014 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1015 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1016 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1017 IDirectSound3DListener_GetDopplerFactor(iface, &listener->flDopplerFactor);
1018 popALContext();
1019 LeaveCriticalSection(This->crst);
1021 return DS_OK;
1024 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1026 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1028 TRACE("(%p)->(%p)\n", iface, distancefactor);
1030 if(!distancefactor)
1032 WARN("Invalid parameter %p\n", distancefactor);
1033 return DSERR_INVALIDPARAM;
1036 setALContext(This->ctx);
1037 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1038 checkALError();
1039 popALContext();
1041 return S_OK;
1044 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1046 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1048 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1050 if(!dopplerfactor)
1052 WARN("Invalid parameter %p\n", dopplerfactor);
1053 return DSERR_INVALIDPARAM;
1056 setALContext(This->ctx);
1057 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1058 checkALError();
1059 popALContext();
1061 return S_OK;
1064 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1066 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1067 ALfloat orient[6];
1069 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1071 if(!front || !top)
1073 WARN("Invalid parameter %p %p\n", front, top);
1074 return DSERR_INVALIDPARAM;
1077 setALContext(This->ctx);
1078 alGetListenerfv(AL_ORIENTATION, orient);
1079 checkALError();
1080 popALContext();
1082 front->x = orient[0];
1083 front->y = orient[1];
1084 front->z = -orient[2];
1085 top->x = orient[3];
1086 top->y = orient[4];
1087 top->z = -orient[5];
1088 return S_OK;
1091 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1093 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1094 ALfloat alpos[3];
1096 TRACE("(%p)->(%p)\n", iface, pos);
1098 if(!pos)
1100 WARN("Invalid parameter %p\n", pos);
1101 return DSERR_INVALIDPARAM;
1104 setALContext(This->ctx);
1105 alGetListenerfv(AL_POSITION, alpos);
1106 checkALError();
1107 popALContext();
1109 pos->x = alpos[0];
1110 pos->y = alpos[1];
1111 pos->z = -alpos[2];
1112 return S_OK;
1115 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1117 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1119 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1121 if(!rollofffactor)
1123 WARN("Invalid parameter %p\n", rollofffactor);
1124 return DSERR_INVALIDPARAM;
1127 EnterCriticalSection(This->crst);
1128 *rollofffactor = This->rollofffactor;
1129 LeaveCriticalSection(This->crst);
1131 return S_OK;
1134 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1136 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1137 ALfloat vel[3];
1139 TRACE("(%p)->(%p)\n", iface, velocity);
1141 if(!velocity)
1143 WARN("Invalid parameter %p\n", velocity);
1144 return DSERR_INVALIDPARAM;
1147 setALContext(This->ctx);
1148 alGetListenerfv(AL_VELOCITY, vel);
1149 checkALError();
1150 popALContext();
1152 velocity->x = vel[0];
1153 velocity->y = vel[1];
1154 velocity->z = -vel[2];
1155 return S_OK;
1158 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1160 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1162 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, listen, apply);
1164 if(!listen || listen->dwSize < sizeof(*listen))
1166 WARN("Invalid parameter %p %"LONGFMT"u\n", listen, listen ? listen->dwSize : 0);
1167 return DSERR_INVALIDPARAM;
1170 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1171 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1173 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1174 return DSERR_INVALIDPARAM;
1177 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1178 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1180 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1181 return DSERR_INVALIDPARAM;
1184 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1185 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1187 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1188 return DSERR_INVALIDPARAM;
1191 EnterCriticalSection(This->crst);
1192 setALContext(This->ctx);
1193 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1194 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1195 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1196 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1197 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1198 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1199 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1200 popALContext();
1201 LeaveCriticalSection(This->crst);
1203 return S_OK;
1206 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1208 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1210 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1212 if(factor < DS3D_MINDISTANCEFACTOR ||
1213 factor > DS3D_MAXDISTANCEFACTOR)
1215 WARN("Invalid parameter %f\n", factor);
1216 return DSERR_INVALIDPARAM;
1219 if(apply == DS3D_DEFERRED)
1221 EnterCriticalSection(This->crst);
1222 This->listen.flDistanceFactor = factor;
1223 This->dirty.bit.distancefactor = 1;
1224 LeaveCriticalSection(This->crst);
1226 else
1228 setALContext(This->ctx);
1229 alSpeedOfSound(343.3f/factor);
1230 if(This->SupportedExt[EXT_EFX])
1231 alListenerf(AL_METERS_PER_UNIT, factor);
1232 checkALError();
1233 popALContext();
1236 return S_OK;
1239 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1241 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1243 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1245 if(factor < DS3D_MINDOPPLERFACTOR ||
1246 factor > DS3D_MAXDOPPLERFACTOR)
1248 WARN("Invalid parameter %f\n", factor);
1249 return DSERR_INVALIDPARAM;
1252 if(apply == DS3D_DEFERRED)
1254 EnterCriticalSection(This->crst);
1255 This->listen.flDopplerFactor = factor;
1256 This->dirty.bit.dopplerfactor = 1;
1257 LeaveCriticalSection(This->crst);
1259 else
1261 setALContext(This->ctx);
1262 alDopplerFactor(factor);
1263 checkALError();
1264 popALContext();
1267 return S_OK;
1270 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1272 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1274 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT"u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1276 if(apply == DS3D_DEFERRED)
1278 EnterCriticalSection(This->crst);
1279 This->listen.vOrientFront.x = xFront;
1280 This->listen.vOrientFront.y = yFront;
1281 This->listen.vOrientFront.z = zFront;
1282 This->listen.vOrientTop.x = xTop;
1283 This->listen.vOrientTop.y = yTop;
1284 This->listen.vOrientTop.z = zTop;
1285 This->dirty.bit.orientation = 1;
1286 LeaveCriticalSection(This->crst);
1288 else
1290 ALfloat orient[6] = {
1291 xFront, yFront, -zFront,
1292 xTop, yTop, -zTop
1294 setALContext(This->ctx);
1295 alListenerfv(AL_ORIENTATION, orient);
1296 checkALError();
1297 popALContext();
1300 return S_OK;
1303 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1305 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1307 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1309 if(apply == DS3D_DEFERRED)
1311 EnterCriticalSection(This->crst);
1312 This->listen.vPosition.x = x;
1313 This->listen.vPosition.y = y;
1314 This->listen.vPosition.z = z;
1315 This->dirty.bit.pos = 1;
1316 LeaveCriticalSection(This->crst);
1318 else
1320 setALContext(This->ctx);
1321 alListener3f(AL_POSITION, x, y, -z);
1322 checkALError();
1323 popALContext();
1326 return S_OK;
1329 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1331 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1333 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1335 if(factor < DS3D_MINROLLOFFFACTOR ||
1336 factor > DS3D_MAXROLLOFFFACTOR)
1338 WARN("Invalid parameter %f\n", factor);
1339 return DSERR_INVALIDPARAM;
1342 EnterCriticalSection(This->crst);
1343 if(apply == DS3D_DEFERRED)
1345 This->listen.flRolloffFactor = factor;
1346 This->dirty.bit.rollofffactor = 1;
1348 else
1350 DWORD i;
1352 setALContext(This->ctx);
1353 for(i = 0;i < This->nbuffers;++i)
1355 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1356 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1358 checkALError();
1359 popALContext();
1361 This->rollofffactor = factor;
1363 LeaveCriticalSection(This->crst);
1365 return S_OK;
1368 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1370 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1372 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1374 if(apply == DS3D_DEFERRED)
1376 EnterCriticalSection(This->crst);
1377 This->listen.vVelocity.x = x;
1378 This->listen.vVelocity.y = y;
1379 This->listen.vVelocity.z = z;
1380 This->dirty.bit.vel = 1;
1381 LeaveCriticalSection(This->crst);
1383 else
1385 setALContext(This->ctx);
1386 alListener3f(AL_VELOCITY, x, y, -z);
1387 checkALError();
1388 popALContext();
1391 return S_OK;
1394 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1396 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1397 const DS3DLISTENER *listen = &This->listen;
1398 DWORD i;
1400 EnterCriticalSection(This->crst);
1401 setALContext(This->ctx);
1402 This->DeferUpdates();
1404 if(This->dirty.bit.pos)
1405 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1406 if(This->dirty.bit.vel)
1407 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1408 if(This->dirty.bit.orientation)
1410 ALfloat orient[6] = {
1411 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1412 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1414 alListenerfv(AL_ORIENTATION, orient);
1416 if(This->dirty.bit.distancefactor)
1418 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1419 if(This->SupportedExt[EXT_EFX])
1420 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1423 if(This->dirty.bit.rollofffactor)
1425 ALfloat rolloff = This->rollofffactor;
1426 for(i = 0;i < This->nbuffers;++i)
1428 DS8Buffer *buf = This->buffers[i];
1429 if(buf->ds3dmode != DS3DMODE_DISABLE)
1430 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1434 if(This->dirty.bit.dopplerfactor)
1435 alDopplerFactor(listen->flDopplerFactor);
1437 if(This->dirty.bit.effect)
1438 This->ExtAL->AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1440 /* checkALError is here for debugging */
1441 checkALError();
1443 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1444 This->dirty.flags = 0;
1446 for(i = 0;i < This->nbuffers;++i)
1448 DS8Buffer *buf = This->buffers[i];
1450 if(!buf->dirty.flags)
1451 continue;
1453 if(buf->dirty.bit.pos)
1454 alSource3f(buf->source, AL_POSITION,
1455 buf->ds3dbuffer.vPosition.x,
1456 buf->ds3dbuffer.vPosition.y,
1457 -buf->ds3dbuffer.vPosition.z);
1458 if(buf->dirty.bit.vel)
1459 alSource3f(buf->source, AL_VELOCITY,
1460 buf->ds3dbuffer.vVelocity.x,
1461 buf->ds3dbuffer.vVelocity.y,
1462 -buf->ds3dbuffer.vVelocity.z);
1463 if(buf->dirty.bit.cone_angles)
1465 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1466 buf->ds3dbuffer.dwInsideConeAngle);
1467 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1468 buf->ds3dbuffer.dwOutsideConeAngle);
1470 if(buf->dirty.bit.cone_orient)
1471 alSource3f(buf->source, AL_DIRECTION,
1472 buf->ds3dbuffer.vConeOrientation.x,
1473 buf->ds3dbuffer.vConeOrientation.y,
1474 -buf->ds3dbuffer.vConeOrientation.z);
1475 if(buf->dirty.bit.cone_outsidevolume)
1476 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1477 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1478 if(buf->dirty.bit.min_distance)
1479 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1480 if(buf->dirty.bit.max_distance)
1481 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1482 if(buf->dirty.bit.mode)
1484 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1485 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1486 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1487 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1488 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1490 buf->dirty.flags = 0;
1492 checkALError();
1494 This->ProcessUpdates();
1495 popALContext();
1496 LeaveCriticalSection(This->crst);
1498 return S_OK;
1501 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1503 DS8Primary3D_QueryInterface,
1504 DS8Primary3D_AddRef,
1505 DS8Primary3D_Release,
1506 DS8Primary3D_GetAllParameters,
1507 DS8Primary3D_GetDistanceFactor,
1508 DS8Primary3D_GetDopplerFactor,
1509 DS8Primary3D_GetOrientation,
1510 DS8Primary3D_GetPosition,
1511 DS8Primary3D_GetRolloffFactor,
1512 DS8Primary3D_GetVelocity,
1513 DS8Primary3D_SetAllParameters,
1514 DS8Primary3D_SetDistanceFactor,
1515 DS8Primary3D_SetDopplerFactor,
1516 DS8Primary3D_SetOrientation,
1517 DS8Primary3D_SetPosition,
1518 DS8Primary3D_SetRolloffFactor,
1519 DS8Primary3D_SetVelocity,
1520 DS8Primary3D_CommitDeferredSettings
1523 /* NOTE: Although the app handles listener properties through secondary buffers,
1524 * we pass the requests to the primary buffer though a propertyset interface.
1525 * These methods are not exposed to the app. */
1526 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1528 DS8Primary *This = impl_from_IKsPropertySet(iface);
1529 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1532 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1534 DS8Primary *This = impl_from_IKsPropertySet(iface);
1535 LONG ret;
1537 ret = InterlockedIncrement(&This->prop_ref);
1538 TRACE("new refcount %"LONGFMT"d\n", ret);
1540 return ret;
1543 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1545 DS8Primary *This = impl_from_IKsPropertySet(iface);
1546 LONG ret;
1548 ret = InterlockedDecrement(&This->prop_ref);
1549 TRACE("new refcount %"LONGFMT"d\n", ret);
1551 return ret;
1554 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1555 REFGUID guidPropSet, ULONG dwPropID,
1556 LPVOID pInstanceData, ULONG cbInstanceData,
1557 LPVOID pPropData, ULONG cbPropData,
1558 PULONG pcbReturned)
1560 DS8Primary *This = impl_from_IKsPropertySet(iface);
1561 HRESULT res = E_PROP_ID_UNSUPPORTED;
1562 (void)pInstanceData;
1563 (void)cbInstanceData;
1565 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1567 EnterCriticalSection(This->crst);
1569 if(This->effect == 0)
1570 res = E_PROP_ID_UNSUPPORTED;
1571 else switch(dwPropID)
1573 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1574 res = DSERR_INVALIDPARAM;
1575 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1577 union {
1578 void *v;
1579 EAXLISTENERPROPERTIES *props;
1580 } data = { pPropData };
1582 *data.props = This->eax_prop;
1583 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1584 res = DS_OK;
1586 break;
1588 case DSPROPERTY_EAXLISTENER_ROOM:
1589 res = DSERR_INVALIDPARAM;
1590 if(cbPropData >= sizeof(LONG))
1592 union {
1593 void *v;
1594 LONG *l;
1595 } data = { pPropData };
1597 *data.l = This->eax_prop.lRoom;
1598 *pcbReturned = sizeof(LONG);
1599 res = DS_OK;
1601 break;
1602 case DSPROPERTY_EAXLISTENER_ROOMHF:
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.lRoomHF;
1612 *pcbReturned = sizeof(LONG);
1613 res = DS_OK;
1615 break;
1617 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1618 res = DSERR_INVALIDPARAM;
1619 if(cbPropData >= sizeof(FLOAT))
1621 union {
1622 void *v;
1623 FLOAT *fl;
1624 } data = { pPropData };
1626 *data.fl = This->eax_prop.flRoomRolloffFactor;
1627 *pcbReturned = sizeof(FLOAT);
1628 res = DS_OK;
1630 break;
1632 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1633 res = DSERR_INVALIDPARAM;
1634 if(cbPropData >= sizeof(DWORD))
1636 union {
1637 void *v;
1638 DWORD *dw;
1639 } data = { pPropData };
1641 *data.dw = This->eax_prop.dwEnvironment;
1642 *pcbReturned = sizeof(DWORD);
1643 res = DS_OK;
1645 break;
1647 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1648 res = DSERR_INVALIDPARAM;
1649 if(cbPropData >= sizeof(FLOAT))
1651 union {
1652 void *v;
1653 FLOAT *fl;
1654 } data = { pPropData };
1656 *data.fl = This->eax_prop.flEnvironmentSize;
1657 *pcbReturned = sizeof(FLOAT);
1658 res = DS_OK;
1660 break;
1661 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
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.flEnvironmentDiffusion;
1671 *pcbReturned = sizeof(FLOAT);
1672 res = DS_OK;
1674 break;
1676 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1677 res = DSERR_INVALIDPARAM;
1678 if(cbPropData >= sizeof(FLOAT))
1680 union {
1681 void *v;
1682 FLOAT *fl;
1683 } data = { pPropData };
1685 *data.fl = This->eax_prop.flAirAbsorptionHF;
1686 *pcbReturned = sizeof(FLOAT);
1687 res = DS_OK;
1689 break;
1691 case DSPROPERTY_EAXLISTENER_FLAGS:
1692 res = DSERR_INVALIDPARAM;
1693 if(cbPropData >= sizeof(DWORD))
1695 union {
1696 void *v;
1697 DWORD *dw;
1698 } data = { pPropData };
1700 *data.dw = This->eax_prop.dwFlags;
1701 *pcbReturned = sizeof(DWORD);
1702 res = DS_OK;
1704 break;
1706 default:
1707 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1708 break;
1711 LeaveCriticalSection(This->crst);
1713 else
1714 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1716 return res;
1719 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1720 REFGUID guidPropSet, ULONG dwPropID,
1721 LPVOID pInstanceData, ULONG cbInstanceData,
1722 LPVOID pPropData, ULONG cbPropData)
1724 DS8Primary *This = impl_from_IKsPropertySet(iface);
1725 HRESULT res = E_PROP_ID_UNSUPPORTED;
1726 (void)pInstanceData;
1727 (void)cbInstanceData;
1729 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1731 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1732 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1734 EnterCriticalSection(This->crst);
1735 setALContext(This->ctx);
1737 if(This->effect == 0)
1738 res = E_PROP_ID_UNSUPPORTED;
1739 else switch(propid)
1741 case 0: /* 0 = not setting any property, just apply */
1742 res = DS_OK;
1743 break;
1745 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1746 do_allparams:
1747 res = DSERR_INVALIDPARAM;
1748 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1750 union {
1751 const void *v;
1752 const EAXLISTENERPROPERTIES *props;
1753 } data = { pPropData };
1755 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1756 This->eax_prop = *data.props;
1757 This->ExtAL->Effectf(This->effect, AL_REVERB_DENSITY,
1758 (data.props->flEnvironmentSize < 2.0f) ?
1759 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1760 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1761 data.props->flEnvironmentDiffusion);
1763 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1764 mB_to_gain(data.props->lRoom));
1765 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1766 mB_to_gain(data.props->lRoomHF));
1768 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1769 data.props->flRoomRolloffFactor);
1771 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_TIME,
1772 data.props->flDecayTime);
1773 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1774 data.props->flDecayHFRatio);
1776 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1777 mB_to_gain(data.props->lReflections));
1778 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1779 data.props->flReflectionsDelay);
1781 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1782 mB_to_gain(data.props->lReverb));
1783 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1784 data.props->flReverbDelay);
1786 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1787 mB_to_gain(data.props->flAirAbsorptionHF));
1789 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1790 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1791 AL_TRUE : AL_FALSE);
1793 checkALError();
1795 This->dirty.bit.effect = 1;
1796 res = DS_OK;
1798 break;
1800 case DSPROPERTY_EAXLISTENER_ROOM:
1801 res = DSERR_INVALIDPARAM;
1802 if(cbPropData >= sizeof(LONG))
1804 union {
1805 const void *v;
1806 const LONG *l;
1807 } data = { pPropData };
1809 This->eax_prop.lRoom = *data.l;
1810 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1811 mB_to_gain(This->eax_prop.lRoom));
1812 checkALError();
1814 This->dirty.bit.effect = 1;
1815 res = DS_OK;
1817 break;
1818 case DSPROPERTY_EAXLISTENER_ROOMHF:
1819 res = DSERR_INVALIDPARAM;
1820 if(cbPropData >= sizeof(LONG))
1822 union {
1823 const void *v;
1824 const LONG *l;
1825 } data = { pPropData };
1827 This->eax_prop.lRoomHF = *data.l;
1828 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1829 mB_to_gain(This->eax_prop.lRoomHF));
1830 checkALError();
1832 This->dirty.bit.effect = 1;
1833 res = DS_OK;
1835 break;
1837 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1838 res = DSERR_INVALIDPARAM;
1839 if(cbPropData >= sizeof(FLOAT))
1841 union {
1842 const void *v;
1843 const FLOAT *fl;
1844 } data = { pPropData };
1846 This->eax_prop.flRoomRolloffFactor = *data.fl;
1847 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1848 This->eax_prop.flRoomRolloffFactor);
1849 checkALError();
1851 This->dirty.bit.effect = 1;
1852 res = DS_OK;
1854 break;
1856 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1857 res = DSERR_INVALIDPARAM;
1858 if(cbPropData >= sizeof(DWORD))
1860 union {
1861 const void *v;
1862 const DWORD *dw;
1863 } data = { pPropData };
1865 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1867 /* Get the environment index's default and pass it down to
1868 * ALLPARAMETERS */
1869 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1870 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1871 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1872 goto do_allparams;
1875 break;
1877 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1878 res = DSERR_INVALIDPARAM;
1879 if(cbPropData >= sizeof(FLOAT))
1881 union {
1882 const void *v;
1883 const FLOAT *fl;
1884 } data = { pPropData };
1886 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1888 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1890 This->eax_prop.flEnvironmentSize = *data.fl;
1892 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1894 This->eax_prop.flDecayTime *= scale;
1895 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1897 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1899 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1900 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1902 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1904 This->eax_prop.flReflectionsDelay *= scale;
1905 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1907 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1909 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1910 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1912 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1914 This->eax_prop.flReverbDelay *= scale;
1915 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1918 /* Pass the updated environment properties down to ALLPARAMETERS */
1919 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1920 pPropData = (void*)&This->eax_prop;
1921 cbPropData = sizeof(This->eax_prop);
1922 goto do_allparams;
1925 break;
1926 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1927 res = DSERR_INVALIDPARAM;
1928 if(cbPropData >= sizeof(FLOAT))
1930 union {
1931 const void *v;
1932 const FLOAT *fl;
1933 } data = { pPropData };
1935 This->eax_prop.flEnvironmentDiffusion = *data.fl;
1936 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1937 This->eax_prop.flEnvironmentDiffusion);
1938 checkALError();
1940 This->dirty.bit.effect = 1;
1941 res = DS_OK;
1943 break;
1945 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1946 res = DSERR_INVALIDPARAM;
1947 if(cbPropData >= sizeof(FLOAT))
1949 union {
1950 const void *v;
1951 const FLOAT *fl;
1952 } data = { pPropData };
1954 This->eax_prop.flAirAbsorptionHF = *data.fl;
1955 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1956 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
1957 checkALError();
1959 This->dirty.bit.effect = 1;
1960 res = DS_OK;
1962 break;
1964 case DSPROPERTY_EAXLISTENER_FLAGS:
1965 res = DSERR_INVALIDPARAM;
1966 if(cbPropData >= sizeof(DWORD))
1968 union {
1969 const void *v;
1970 const DWORD *dw;
1971 } data = { pPropData };
1973 This->eax_prop.dwFlags = *data.dw;
1974 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1975 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1976 AL_TRUE : AL_FALSE);
1977 checkALError();
1979 This->dirty.bit.effect = 1;
1980 res = DS_OK;
1982 break;
1984 default:
1985 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
1986 break;
1989 if(res == DS_OK && immediate)
1990 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
1992 popALContext();
1993 LeaveCriticalSection(This->crst);
1995 else
1996 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1998 return res;
2001 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2002 REFGUID guidPropSet, ULONG dwPropID,
2003 PULONG pTypeSupport)
2005 DS8Primary *This = impl_from_IKsPropertySet(iface);
2006 HRESULT res = E_PROP_ID_UNSUPPORTED;
2008 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2010 EnterCriticalSection(This->crst);
2012 if(This->effect == 0)
2013 res = E_PROP_ID_UNSUPPORTED;
2014 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2015 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2016 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2017 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2018 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2019 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2020 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2021 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2022 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2024 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2025 res = DS_OK;
2027 else
2028 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2030 LeaveCriticalSection(This->crst);
2032 else
2033 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2035 return res;
2038 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2040 DS8PrimaryProp_QueryInterface,
2041 DS8PrimaryProp_AddRef,
2042 DS8PrimaryProp_Release,
2043 DS8PrimaryProp_Get,
2044 DS8PrimaryProp_Set,
2045 DS8PrimaryProp_QuerySupport