Make the primary buffer a non-pointer member of the device
[dsound-openal.git] / primary.c
blobffc9b345b707f22f7fbb5e6964dde97f49cb7590
1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "mmreg.h"
45 #include "ks.h"
46 #include "ksmedia.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
50 #else
52 #define WINVER 0x0600
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 #ifndef E_PROP_ID_UNSUPPORTED
62 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
63 #endif
65 #endif
67 static const IDirectSoundBufferVtbl DS8Primary_Vtbl;
68 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl;
69 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl;
71 static void AL_APIENTRY wrap_DeferUpdates(void)
72 { alcSuspendContext(alcGetCurrentContext()); }
73 static void AL_APIENTRY wrap_ProcessUpdates(void)
74 { alcProcessContext(alcGetCurrentContext()); }
77 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
79 DWORD i;
80 for(i = 0; i < buf->nnotify; ++i)
82 DSBPOSITIONNOTIFY *not = &buf->notify[i];
83 HANDLE event = not->hEventNotify;
84 DWORD ofs = not->dwOffset;
86 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
87 continue;
89 /* Wraparound case */
90 if(curpos < lastpos)
92 if(ofs < curpos || ofs >= lastpos)
93 SetEvent(event);
94 continue;
97 /* Normal case */
98 if(ofs >= lastpos && ofs < curpos)
99 SetEvent(event);
103 static void trigger_stop_notifies(DS8Buffer *buf)
105 DWORD i;
106 for(i = 0; i < buf->nnotify; ++i)
108 DSBPOSITIONNOTIFY *not = &buf->notify[i];
109 if(not->dwOffset == (DWORD)DSBPN_OFFSETSTOP)
110 SetEvent(not->hEventNotify);
114 static DWORD CALLBACK ThreadProc(void *dwUser)
116 DS8Primary *prim = (DS8Primary*)dwUser;
117 DWORD i;
118 MSG msg;
120 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
122 while(GetMessageA(&msg, NULL, 0, 0))
124 if(msg.message != WM_USER)
125 continue;
127 EnterCriticalSection(prim->crst);
128 setALContext(prim->ctx);
130 /* OpenAL doesn't support our lovely buffer extensions
131 * so just make sure enough buffers are queued
133 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES] &&
134 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
135 !prim->SupportedExt[EXT_STATIC_BUFFER])
137 for(i = 0;i < prim->nbuffers;++i)
139 DS8Buffer *buf = prim->buffers[i];
140 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
141 ALuint which, ofs;
143 if(buf->buffer->numsegs == 1 || !buf->isplaying)
144 continue;
146 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
147 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
148 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
150 queued -= done;
151 while(done--)
152 alSourceUnqueueBuffers(buf->source, 1, &which);
153 while(queued < QBUFFERS)
155 which = buf->buffer->buffers[buf->curidx];
156 ofs = buf->curidx*buf->buffer->segsize;
157 if(buf->curidx < buf->buffer->numsegs-1)
158 alBufferData(which, buf->buffer->buf_format,
159 buf->buffer->data + ofs, buf->buffer->segsize,
160 buf->buffer->format.Format.nSamplesPerSec);
161 else
162 alBufferData(which, buf->buffer->buf_format,
163 buf->buffer->data + ofs, buf->buffer->lastsegsize,
164 buf->buffer->format.Format.nSamplesPerSec);
166 alSourceQueueBuffers(buf->source, 1, &which);
167 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
168 queued++;
170 if(!buf->curidx && !buf->islooping)
172 buf->isplaying = FALSE;
173 break;
176 if(state != AL_PLAYING)
178 if(!queued)
180 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
181 continue;
183 alSourcePlay(buf->source);
186 checkALError();
189 for(i = 0;i < prim->nnotifies;)
191 DS8Buffer *buf = prim->notifies[i];
192 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
193 DWORD status=0, curpos=buf->lastpos;
195 IDirectSoundBuffer8_GetStatus(dsb, &status);
196 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
197 if(buf->lastpos != curpos)
199 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
200 buf->lastpos = curpos;
202 if(!(status&DSBSTATUS_PLAYING))
204 /* Remove this buffer from list and put another at the
205 * current position; don't increment i
207 trigger_stop_notifies(buf);
208 prim->notifies[i] = prim->notifies[--prim->nnotifies];
209 continue;
211 i++;
213 popALContext();
214 LeaveCriticalSection(prim->crst);
216 return 0;
220 HRESULT DS8Primary_Create(DS8Primary *This, DS8Impl *parent)
222 DS3DLISTENER *listener;
223 WAVEFORMATEX *wfx;
224 HRESULT hr;
226 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
227 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
228 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
230 This->parent = parent;
231 This->crst = &parent->share->crst;
232 This->ctx = parent->share->ctx;
233 This->SupportedExt = parent->share->SupportedExt;
234 This->ExtAL = &parent->share->ExtAL;
235 This->sources = parent->share->sources;
236 This->effect = parent->share->effect;
237 This->auxslot = parent->share->auxslot;
239 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
240 wfx = &This->format.Format;
242 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
244 wfx->wFormatTag = WAVE_FORMAT_PCM;
245 wfx->nChannels = 2;
246 wfx->wBitsPerSample = 8;
247 wfx->nSamplesPerSec = 22050;
248 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
249 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
250 wfx->cbSize = 0;
252 This->stopped = TRUE;
254 /* Apparently primary buffer size is always 32k,
255 * tested on windows with 192k 24 bits sound @ 6 channels
256 * where it will run out in 60 ms and it isn't pointer aligned
258 This->buf_size = 32768;
260 if(This->SupportedExt[SOFT_DEFERRED_UPDATES])
262 This->DeferUpdates = This->ExtAL->DeferUpdatesSOFT;
263 This->ProcessUpdates = This->ExtAL->ProcessUpdatesSOFT;
265 else
267 This->DeferUpdates = wrap_DeferUpdates;
268 This->ProcessUpdates = wrap_ProcessUpdates;
271 /* Make sure DS3DListener defaults are applied to OpenAL */
272 listener = &This->listen;
273 listener->dwSize = sizeof(*listener);
274 listener->vPosition.x = 0.0;
275 listener->vPosition.y = 0.0;
276 listener->vPosition.z = 0.0;
277 listener->vVelocity.x = 0.0;
278 listener->vVelocity.y = 0.0;
279 listener->vVelocity.z = 0.0;
280 listener->vOrientFront.x = 0.0;
281 listener->vOrientFront.y = 0.0;
282 listener->vOrientFront.z = 1.0;
283 listener->vOrientTop.x = 0.0;
284 listener->vOrientTop.y = 1.0;
285 listener->vOrientTop.z = 0.0;
286 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
287 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
288 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
289 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
290 if(FAILED(hr))
291 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
293 This->sizenotifies = This->sizebuffers = parent->share->max_sources;
295 hr = DSERR_OUTOFMEMORY;
296 This->buffers = HeapAlloc(GetProcessHeap(), 0, This->sizebuffers*sizeof(*This->buffers));
297 This->notifies = HeapAlloc(GetProcessHeap(), 0, This->sizenotifies*sizeof(*This->notifies));
298 if(!This->buffers || !This->notifies)
299 goto fail;
301 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
302 if(This->thread_hdl == NULL)
303 goto fail;
305 return S_OK;
307 fail:
308 DS8Primary_Destroy(This);
309 return hr;
312 void DS8Primary_Destroy(DS8Primary *This)
314 TRACE("Destroying primary %p\n", This);
316 if(!This->parent)
317 return;
319 if(This->timer_id)
321 timeKillEvent(This->timer_id);
322 timeEndPeriod(This->timer_res);
323 TRACE("Killed timer\n");
325 if(This->thread_hdl)
327 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
328 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
329 ERR("Thread wait timed out");
330 CloseHandle(This->thread_hdl);
333 EnterCriticalSection(This->crst);
334 while(This->nbuffers--)
335 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
336 LeaveCriticalSection(This->crst);
338 HeapFree(GetProcessHeap(), 0, This->notifies);
339 HeapFree(GetProcessHeap(), 0, This->buffers);
340 memset(This, 0, sizeof(*This));
343 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
345 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
348 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
350 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
352 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
354 *ppv = NULL;
355 if(IsEqualIID(riid, &IID_IUnknown) ||
356 IsEqualIID(riid, &IID_IDirectSoundBuffer))
357 *ppv = &This->IDirectSoundBuffer_iface;
358 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
360 if((This->flags&DSBCAPS_CTRL3D))
361 *ppv = &This->IDirectSound3DListener_iface;
363 else
364 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
366 if(*ppv)
368 IUnknown_AddRef((IUnknown*)*ppv);
369 return S_OK;
372 return E_NOINTERFACE;
375 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
377 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
378 LONG ret;
380 ret = InterlockedIncrement(&This->ref);
381 if(ret == 1) This->flags = 0;
383 return ret;
386 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
388 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
389 LONG ret;
391 ret = InterlockedDecrement(&This->ref);
393 return ret;
396 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
398 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
400 TRACE("(%p)->(%p)\n", iface, caps);
402 if(!caps || caps->dwSize < sizeof(*caps))
404 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
405 return DSERR_INVALIDPARAM;
408 EnterCriticalSection(This->crst);
409 caps->dwFlags = This->flags;
410 caps->dwBufferBytes = This->buf_size;
411 caps->dwUnlockTransferRate = 0;
412 caps->dwPlayCpuOverhead = 0;
413 LeaveCriticalSection(This->crst);
415 return DS_OK;
418 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
420 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
421 HRESULT hr = DSERR_PRIOLEVELNEEDED;
423 EnterCriticalSection(This->crst);
424 if(This->write_emu)
425 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
426 LeaveCriticalSection(This->crst);
428 return hr;
431 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
433 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
434 HRESULT hr = S_OK;
435 UINT size;
437 if(!wfx && !written)
439 WARN("Cannot report format or format size\n");
440 return DSERR_INVALIDPARAM;
443 EnterCriticalSection(This->crst);
444 size = sizeof(This->format.Format) + This->format.Format.cbSize;
445 if(written)
446 *written = size;
447 if(wfx)
449 if(allocated < size)
450 hr = DSERR_INVALIDPARAM;
451 else
452 memcpy(wfx, &This->format.Format, size);
454 LeaveCriticalSection(This->crst);
456 return hr;
459 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
461 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
462 HRESULT hr = S_OK;
464 TRACE("(%p)->(%p)\n", iface, volume);
466 if(!volume)
467 return DSERR_INVALIDPARAM;
469 EnterCriticalSection(This->crst);
470 if(!(This->flags & DSBCAPS_CTRLVOLUME))
471 hr = DSERR_CONTROLUNAVAIL;
472 else
474 ALfloat gain;
476 setALContext(This->ctx);
477 alGetListenerf(AL_GAIN, &gain);
478 checkALError();
479 popALContext();
481 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
483 LeaveCriticalSection(This->crst);
485 return hr;
488 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
490 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
491 HRESULT hr = S_OK;
493 WARN("(%p)->(%p): semi-stub\n", iface, pan);
495 if(!pan)
496 return DSERR_INVALIDPARAM;
498 EnterCriticalSection(This->crst);
499 if(This->write_emu)
500 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
501 else if(!(This->flags & DSBCAPS_CTRLPAN))
502 hr = DSERR_CONTROLUNAVAIL;
503 else
504 *pan = 0;
505 LeaveCriticalSection(This->crst);
507 return hr;
510 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
512 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
513 HRESULT hr = S_OK;
515 WARN("(%p)->(%p): semi-stub\n", iface, freq);
517 if(!freq)
518 return DSERR_INVALIDPARAM;
520 EnterCriticalSection(This->crst);
521 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
522 hr = DSERR_CONTROLUNAVAIL;
523 else
524 *freq = This->format.Format.nSamplesPerSec;
525 LeaveCriticalSection(This->crst);
527 return hr;
530 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
532 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
534 TRACE("(%p)->(%p)\n", iface, status);
536 if(!status)
537 return DSERR_INVALIDPARAM;
539 EnterCriticalSection(This->crst);
541 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
542 if((This->flags&DSBCAPS_LOCDEFER))
543 *status |= DSBSTATUS_LOCHARDWARE;
545 if(This->stopped)
547 DWORD i, state;
548 HRESULT hr;
550 for(i = 0;i < This->nbuffers;++i)
552 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
553 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
554 break;
556 if(i == This->nbuffers)
558 /* Primary stopped and no buffers playing.. */
559 *status = 0;
563 LeaveCriticalSection(This->crst);
565 return S_OK;
568 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
570 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
571 HRESULT hr = S_OK;
573 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
575 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
577 WARN("Bad DSBDESC for primary buffer\n");
578 return DSERR_INVALIDPARAM;
580 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
581 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
582 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
584 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
585 return DSERR_INVALIDPARAM;
588 EnterCriticalSection(This->crst);
589 /* Should be 0 if not initialized */
590 if(This->flags)
592 hr = DSERR_ALREADYINITIALIZED;
593 goto out;
596 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
598 DSBUFFERDESC emudesc;
599 DS8Buffer *emu;
601 if(This->write_emu)
603 ERR("There shouldn't be a write_emu!\n");
604 IDirectSoundBuffer8_Release(This->write_emu);
605 This->write_emu = NULL;
608 memset(&emudesc, 0, sizeof(emudesc));
609 emudesc.dwSize = sizeof(emudesc);
610 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
611 /* Dont play last incomplete sample */
612 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
613 emudesc.lpwfxFormat = &This->format.Format;
615 hr = DS8Buffer_Create(&emu, This, NULL);
616 if(SUCCEEDED(hr))
618 This->write_emu = &emu->IDirectSoundBuffer8_iface;
619 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
620 if(FAILED(hr))
622 IDirectSoundBuffer8_Release(This->write_emu);
623 This->write_emu = NULL;
628 if(SUCCEEDED(hr))
629 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
630 out:
631 LeaveCriticalSection(This->crst);
632 return hr;
635 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
637 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
638 HRESULT hr = DSERR_PRIOLEVELNEEDED;
640 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
642 EnterCriticalSection(This->crst);
643 if(This->write_emu)
644 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
645 LeaveCriticalSection(This->crst);
647 return hr;
650 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
652 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
653 HRESULT hr;
655 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
657 if(!(flags & DSBPLAY_LOOPING))
659 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
660 return DSERR_INVALIDPARAM;
663 EnterCriticalSection(This->crst);
664 hr = S_OK;
665 if(This->write_emu)
666 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
667 if(SUCCEEDED(hr))
668 This->stopped = FALSE;
669 LeaveCriticalSection(This->crst);
671 return hr;
674 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
676 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
677 return DSERR_INVALIDCALL;
680 /* Just assume the format is crap, and clean up the damage */
681 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
683 if(from->wFormatTag == WAVE_FORMAT_PCM)
685 wfx->cbSize = 0;
686 if(from->wBitsPerSample == 8 ||
687 from->wBitsPerSample == 16 ||
688 from->wBitsPerSample == 24 ||
689 from->wBitsPerSample == 32)
690 wfx->wBitsPerSample = from->wBitsPerSample;
692 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
694 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
695 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
696 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
698 /* Fail silently.. */
699 if(from->cbSize < size)
700 return;
701 if(!fromx->Samples.wValidBitsPerSample &&
702 !fromx->Format.wBitsPerSample)
703 return;
705 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
706 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
708 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
709 return;
712 wfe->Format.wBitsPerSample = from->wBitsPerSample;
713 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
714 if(!wfe->Samples.wValidBitsPerSample)
715 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
716 wfe->Format.cbSize = size;
717 wfe->dwChannelMask = fromx->dwChannelMask;
718 wfe->SubFormat = fromx->SubFormat;
720 else
722 ERR("Unhandled format tag %04x\n", from->wFormatTag);
723 return;
726 if(from->nChannels)
727 wfx->nChannels = from->nChannels;
728 wfx->wFormatTag = from->wFormatTag;
729 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
730 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
731 wfx->nSamplesPerSec = from->nSamplesPerSec;
732 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
733 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
736 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
738 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
739 HRESULT hr = S_OK;
740 ALCint freq;
742 TRACE("(%p)->(%p)\n", iface, wfx);
744 if(!wfx)
746 WARN("Missing format\n");
747 return DSERR_INVALIDPARAM;
750 EnterCriticalSection(This->crst);
752 if(This->parent->prio_level < DSSCL_PRIORITY)
754 hr = DSERR_PRIOLEVELNEEDED;
755 goto out;
758 TRACE("Requested primary format:\n"
759 " FormatTag = %04x\n"
760 " Channels = %u\n"
761 " SamplesPerSec = %"LONGFMT"u\n"
762 " AvgBytesPerSec = %"LONGFMT"u\n"
763 " BlockAlign = %u\n"
764 " BitsPerSample = %u\n",
765 wfx->wFormatTag, wfx->nChannels,
766 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
767 wfx->nBlockAlign, wfx->wBitsPerSample);
769 copy_waveformat(&This->format.Format, wfx);
771 freq = This->format.Format.nSamplesPerSec;
772 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
773 checkALCError(This->parent->device);
775 This->format.Format.nSamplesPerSec = freq;
776 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
777 This->format.Format.nSamplesPerSec;
779 if(This->write_emu)
781 DS8Buffer *buf;
782 DSBUFFERDESC desc;
784 memset(&desc, 0, sizeof(desc));
785 desc.dwSize = sizeof(desc);
786 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
787 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
788 desc.lpwfxFormat = &This->format.Format;
790 hr = DS8Buffer_Create(&buf, This, NULL);
791 if(FAILED(hr))
792 goto out;
794 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
795 if(FAILED(hr))
796 DS8Buffer_Destroy(buf);
797 else
799 IDirectSoundBuffer8_Release(This->write_emu);
800 This->write_emu = &buf->IDirectSoundBuffer8_iface;
804 out:
805 LeaveCriticalSection(This->crst);
806 return hr;
809 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
811 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
812 HRESULT hr = S_OK;
814 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
816 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
818 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
819 return DSERR_INVALIDPARAM;
822 EnterCriticalSection(This->crst);
823 if(!(This->flags&DSBCAPS_CTRLVOLUME))
824 hr = DSERR_CONTROLUNAVAIL;
825 if(SUCCEEDED(hr))
827 setALContext(This->ctx);
828 alListenerf(AL_GAIN, mB_to_gain(vol));
829 popALContext();
831 LeaveCriticalSection(This->crst);
833 return hr;
836 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
838 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
839 HRESULT hr;
841 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
843 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
845 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
846 return DSERR_INVALIDPARAM;
849 EnterCriticalSection(This->crst);
850 if(!(This->flags&DSBCAPS_CTRLPAN))
852 WARN("control unavailable\n");
853 hr = DSERR_CONTROLUNAVAIL;
855 else if(This->write_emu)
856 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
857 else
859 FIXME("Not supported\n");
860 hr = E_NOTIMPL;
862 LeaveCriticalSection(This->crst);
864 return hr;
867 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
869 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
870 return DSERR_CONTROLUNAVAIL;
873 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
875 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
876 HRESULT hr = S_OK;
878 TRACE("(%p)->()\n", iface);
880 EnterCriticalSection(This->crst);
881 if(This->write_emu)
882 hr = IDirectSoundBuffer8_Stop(This->write_emu);
883 if(SUCCEEDED(hr))
884 This->stopped = TRUE;
885 LeaveCriticalSection(This->crst);
887 return hr;
890 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
892 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
893 HRESULT hr = DSERR_INVALIDCALL;
895 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
897 EnterCriticalSection(This->crst);
898 if(This->write_emu)
899 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
900 LeaveCriticalSection(This->crst);
902 return hr;
905 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
907 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
908 HRESULT hr = S_OK;
910 TRACE("(%p)->()\n", iface);
912 EnterCriticalSection(This->crst);
913 if(This->write_emu)
914 hr = IDirectSoundBuffer8_Restore(This->write_emu);
915 LeaveCriticalSection(This->crst);
917 return hr;
920 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
922 DS8Primary_QueryInterface,
923 DS8Primary_AddRef,
924 DS8Primary_Release,
925 DS8Primary_GetCaps,
926 DS8Primary_GetCurrentPosition,
927 DS8Primary_GetFormat,
928 DS8Primary_GetVolume,
929 DS8Primary_GetPan,
930 DS8Primary_GetFrequency,
931 DS8Primary_GetStatus,
932 DS8Primary_Initialize,
933 DS8Primary_Lock,
934 DS8Primary_Play,
935 DS8Primary_SetCurrentPosition,
936 DS8Primary_SetFormat,
937 DS8Primary_SetVolume,
938 DS8Primary_SetPan,
939 DS8Primary_SetFrequency,
940 DS8Primary_Stop,
941 DS8Primary_Unlock,
942 DS8Primary_Restore
945 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
947 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
950 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
952 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
953 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
956 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
958 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
959 LONG ret;
961 ret = InterlockedIncrement(&This->ds3d_ref);
962 TRACE("new refcount %"LONGFMT"d\n", ret);
964 return ret;
968 /* Considering the primary buffer doesn't get destroyed
969 * it doesn't make sense to destroy ds3d here
971 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
973 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
974 LONG ret;
976 ret = InterlockedDecrement(&This->ds3d_ref);
977 TRACE("new refcount %"LONGFMT"d\n", ret);
979 return ret;
983 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
985 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
987 TRACE("(%p)->(%p)\n", iface, listener);
989 if(!listener || listener->dwSize < sizeof(*listener))
991 WARN("Invalid DS3DLISTENER %p %"LONGFMT"u\n", listener, listener ? listener->dwSize : 0);
992 return DSERR_INVALIDPARAM;
995 EnterCriticalSection(This->crst);
996 setALContext(This->ctx);
997 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
998 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
999 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1000 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1001 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1002 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
1003 popALContext();
1004 LeaveCriticalSection(This->crst);
1006 return DS_OK;
1009 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1011 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1013 TRACE("(%p)->(%p)\n", iface, distancefactor);
1015 if(!distancefactor)
1017 WARN("Invalid parameter %p\n", distancefactor);
1018 return DSERR_INVALIDPARAM;
1021 EnterCriticalSection(This->crst);
1022 setALContext(This->ctx);
1024 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1025 checkALError();
1027 popALContext();
1028 LeaveCriticalSection(This->crst);
1030 return S_OK;
1033 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1035 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1037 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1039 if(!dopplerfactor)
1041 WARN("Invalid parameter %p\n", dopplerfactor);
1042 return DSERR_INVALIDPARAM;
1045 EnterCriticalSection(This->crst);
1046 setALContext(This->ctx);
1048 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1049 checkALError();
1051 popALContext();
1052 LeaveCriticalSection(This->crst);
1054 return S_OK;
1057 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1059 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1060 ALfloat orient[6];
1062 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1064 if(!front || !top)
1066 WARN("Invalid parameter %p %p\n", front, top);
1067 return DSERR_INVALIDPARAM;
1070 EnterCriticalSection(This->crst);
1071 setALContext(This->ctx);
1073 alGetListenerfv(AL_ORIENTATION, orient);
1074 checkALError();
1076 front->x = orient[0];
1077 front->y = orient[1];
1078 front->z = -orient[2];
1079 top->x = orient[3];
1080 top->y = orient[4];
1081 top->z = -orient[5];
1083 popALContext();
1084 LeaveCriticalSection(This->crst);
1086 return S_OK;
1089 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1091 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1092 ALfloat alpos[3];
1094 TRACE("(%p)->(%p)\n", iface, pos);
1096 if(!pos)
1098 WARN("Invalid parameter %p\n", pos);
1099 return DSERR_INVALIDPARAM;
1102 EnterCriticalSection(This->crst);
1103 setALContext(This->ctx);
1105 alGetListenerfv(AL_POSITION, alpos);
1106 checkALError();
1108 pos->x = alpos[0];
1109 pos->y = alpos[1];
1110 pos->z = -alpos[2];
1112 popALContext();
1113 LeaveCriticalSection(This->crst);
1115 return S_OK;
1118 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1120 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1122 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1124 if(!rollofffactor)
1126 WARN("Invalid parameter %p\n", rollofffactor);
1127 return DSERR_INVALIDPARAM;
1130 EnterCriticalSection(This->crst);
1131 *rollofffactor = This->rollofffactor;
1132 LeaveCriticalSection(This->crst);
1134 return S_OK;
1137 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1139 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1140 ALfloat vel[3];
1142 TRACE("(%p)->(%p)\n", iface, velocity);
1144 if(!velocity)
1146 WARN("Invalid parameter %p\n", velocity);
1147 return DSERR_INVALIDPARAM;
1150 EnterCriticalSection(This->crst);
1151 setALContext(This->ctx);
1153 alGetListenerfv(AL_VELOCITY, vel);
1154 checkALError();
1156 velocity->x = vel[0];
1157 velocity->y = vel[1];
1158 velocity->z = -vel[2];
1160 popALContext();
1161 LeaveCriticalSection(This->crst);
1163 return S_OK;
1166 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1168 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1170 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, listen, apply);
1172 if(!listen || listen->dwSize < sizeof(*listen))
1174 WARN("Invalid parameter %p %"LONGFMT"u\n", listen, listen ? listen->dwSize : 0);
1175 return DSERR_INVALIDPARAM;
1178 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1179 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1181 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1182 return DSERR_INVALIDPARAM;
1185 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1186 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1188 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1189 return DSERR_INVALIDPARAM;
1192 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1193 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1195 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1196 return DSERR_INVALIDPARAM;
1199 EnterCriticalSection(This->crst);
1200 setALContext(This->ctx);
1201 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1202 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1203 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1204 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1205 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1206 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1207 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1208 popALContext();
1209 LeaveCriticalSection(This->crst);
1211 return S_OK;
1214 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1216 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1218 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1220 if(factor < DS3D_MINDISTANCEFACTOR ||
1221 factor > DS3D_MAXDISTANCEFACTOR)
1223 WARN("Invalid parameter %f\n", factor);
1224 return DSERR_INVALIDPARAM;
1227 EnterCriticalSection(This->crst);
1228 if(apply == DS3D_DEFERRED)
1230 This->listen.flDistanceFactor = factor;
1231 This->dirty.bit.distancefactor = 1;
1233 else
1235 setALContext(This->ctx);
1236 alSpeedOfSound(343.3f/factor);
1237 if(This->SupportedExt[EXT_EFX])
1238 alListenerf(AL_METERS_PER_UNIT, factor);
1239 checkALError();
1240 popALContext();
1242 LeaveCriticalSection(This->crst);
1244 return S_OK;
1247 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1249 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1251 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1253 if(factor < DS3D_MINDOPPLERFACTOR ||
1254 factor > DS3D_MAXDOPPLERFACTOR)
1256 WARN("Invalid parameter %f\n", factor);
1257 return DSERR_INVALIDPARAM;
1260 EnterCriticalSection(This->crst);
1261 if(apply == DS3D_DEFERRED)
1263 This->listen.flDopplerFactor = factor;
1264 This->dirty.bit.dopplerfactor = 1;
1266 else
1268 setALContext(This->ctx);
1269 alDopplerFactor(factor);
1270 checkALError();
1271 popALContext();
1273 LeaveCriticalSection(This->crst);
1275 return S_OK;
1278 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1280 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1282 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT"u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1284 EnterCriticalSection(This->crst);
1285 if(apply == DS3D_DEFERRED)
1287 This->listen.vOrientFront.x = xFront;
1288 This->listen.vOrientFront.y = yFront;
1289 This->listen.vOrientFront.z = zFront;
1290 This->listen.vOrientTop.x = xTop;
1291 This->listen.vOrientTop.y = yTop;
1292 This->listen.vOrientTop.z = zTop;
1293 This->dirty.bit.orientation = 1;
1295 else
1297 ALfloat orient[6] = {
1298 xFront, yFront, -zFront,
1299 xTop, yTop, -zTop
1301 setALContext(This->ctx);
1302 alListenerfv(AL_ORIENTATION, orient);
1303 checkALError();
1304 popALContext();
1306 LeaveCriticalSection(This->crst);
1308 return S_OK;
1311 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1313 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1315 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1317 EnterCriticalSection(This->crst);
1318 if(apply == DS3D_DEFERRED)
1320 This->listen.vPosition.x = x;
1321 This->listen.vPosition.y = y;
1322 This->listen.vPosition.z = z;
1323 This->dirty.bit.pos = 1;
1325 else
1327 setALContext(This->ctx);
1328 alListener3f(AL_POSITION, x, y, -z);
1329 checkALError();
1330 popALContext();
1332 LeaveCriticalSection(This->crst);
1334 return S_OK;
1337 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1339 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1341 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1343 if(factor < DS3D_MINROLLOFFFACTOR ||
1344 factor > DS3D_MAXROLLOFFFACTOR)
1346 WARN("Invalid parameter %f\n", factor);
1347 return DSERR_INVALIDPARAM;
1350 EnterCriticalSection(This->crst);
1351 if(apply == DS3D_DEFERRED)
1353 This->listen.flRolloffFactor = factor;
1354 This->dirty.bit.rollofffactor = 1;
1356 else
1358 DWORD i;
1360 setALContext(This->ctx);
1361 for(i = 0;i < This->nbuffers;++i)
1363 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1364 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1366 checkALError();
1367 popALContext();
1369 This->rollofffactor = factor;
1371 LeaveCriticalSection(This->crst);
1373 return S_OK;
1376 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1378 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1380 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1382 EnterCriticalSection(This->crst);
1383 if(apply == DS3D_DEFERRED)
1385 This->listen.vVelocity.x = x;
1386 This->listen.vVelocity.y = y;
1387 This->listen.vVelocity.z = z;
1388 This->dirty.bit.vel = 1;
1390 else
1392 setALContext(This->ctx);
1393 alListener3f(AL_VELOCITY, x, y, -z);
1394 checkALError();
1395 popALContext();
1397 LeaveCriticalSection(This->crst);
1399 return S_OK;
1402 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1404 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1405 const DS3DLISTENER *listen = &This->listen;
1406 DWORD i;
1408 EnterCriticalSection(This->crst);
1409 setALContext(This->ctx);
1410 This->DeferUpdates();
1412 if(This->dirty.bit.pos)
1413 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1414 if(This->dirty.bit.vel)
1415 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1416 if(This->dirty.bit.orientation)
1418 ALfloat orient[6] = {
1419 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1420 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1422 alListenerfv(AL_ORIENTATION, orient);
1424 if(This->dirty.bit.distancefactor)
1426 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1427 if(This->SupportedExt[EXT_EFX])
1428 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1431 if(This->dirty.bit.rollofffactor)
1433 ALfloat rolloff = This->rollofffactor;
1434 for(i = 0;i < This->nbuffers;++i)
1436 DS8Buffer *buf = This->buffers[i];
1437 if(buf->ds3dmode != DS3DMODE_DISABLE)
1438 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1442 if(This->dirty.bit.dopplerfactor)
1443 alDopplerFactor(listen->flDopplerFactor);
1445 if(This->dirty.bit.effect)
1446 This->ExtAL->AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1448 /* checkALError is here for debugging */
1449 checkALError();
1451 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1452 This->dirty.flags = 0;
1454 for(i = 0;i < This->nbuffers;++i)
1456 DS8Buffer *buf = This->buffers[i];
1458 if(!buf->dirty.flags)
1459 continue;
1461 if(buf->dirty.bit.pos)
1462 alSource3f(buf->source, AL_POSITION,
1463 buf->ds3dbuffer.vPosition.x,
1464 buf->ds3dbuffer.vPosition.y,
1465 -buf->ds3dbuffer.vPosition.z);
1466 if(buf->dirty.bit.vel)
1467 alSource3f(buf->source, AL_VELOCITY,
1468 buf->ds3dbuffer.vVelocity.x,
1469 buf->ds3dbuffer.vVelocity.y,
1470 -buf->ds3dbuffer.vVelocity.z);
1471 if(buf->dirty.bit.cone_angles)
1473 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1474 buf->ds3dbuffer.dwInsideConeAngle);
1475 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1476 buf->ds3dbuffer.dwOutsideConeAngle);
1478 if(buf->dirty.bit.cone_orient)
1479 alSource3f(buf->source, AL_DIRECTION,
1480 buf->ds3dbuffer.vConeOrientation.x,
1481 buf->ds3dbuffer.vConeOrientation.y,
1482 -buf->ds3dbuffer.vConeOrientation.z);
1483 if(buf->dirty.bit.cone_outsidevolume)
1484 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1485 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1486 if(buf->dirty.bit.min_distance)
1487 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1488 if(buf->dirty.bit.max_distance)
1489 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1490 if(buf->dirty.bit.mode)
1492 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1493 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1494 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1495 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1496 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1498 buf->dirty.flags = 0;
1500 checkALError();
1502 This->ProcessUpdates();
1503 popALContext();
1504 LeaveCriticalSection(This->crst);
1506 return S_OK;
1509 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1511 DS8Primary3D_QueryInterface,
1512 DS8Primary3D_AddRef,
1513 DS8Primary3D_Release,
1514 DS8Primary3D_GetAllParameters,
1515 DS8Primary3D_GetDistanceFactor,
1516 DS8Primary3D_GetDopplerFactor,
1517 DS8Primary3D_GetOrientation,
1518 DS8Primary3D_GetPosition,
1519 DS8Primary3D_GetRolloffFactor,
1520 DS8Primary3D_GetVelocity,
1521 DS8Primary3D_SetAllParameters,
1522 DS8Primary3D_SetDistanceFactor,
1523 DS8Primary3D_SetDopplerFactor,
1524 DS8Primary3D_SetOrientation,
1525 DS8Primary3D_SetPosition,
1526 DS8Primary3D_SetRolloffFactor,
1527 DS8Primary3D_SetVelocity,
1528 DS8Primary3D_CommitDeferredSettings
1531 /* NOTE: Although the app handles listener properties through secondary buffers,
1532 * we pass the requests to the primary buffer though a propertyset interface.
1533 * These methods are not exposed to the app. */
1534 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1536 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1539 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1541 DS8Primary *This = impl_from_IKsPropertySet(iface);
1542 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1545 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1547 DS8Primary *This = impl_from_IKsPropertySet(iface);
1548 LONG ret;
1550 ret = InterlockedIncrement(&This->prop_ref);
1551 TRACE("new refcount %"LONGFMT"d\n", ret);
1553 return ret;
1556 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1558 DS8Primary *This = impl_from_IKsPropertySet(iface);
1559 LONG ret;
1561 ret = InterlockedDecrement(&This->prop_ref);
1562 TRACE("new refcount %"LONGFMT"d\n", ret);
1564 return ret;
1567 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1568 REFGUID guidPropSet, ULONG dwPropID,
1569 LPVOID pInstanceData, ULONG cbInstanceData,
1570 LPVOID pPropData, ULONG cbPropData,
1571 PULONG pcbReturned)
1573 DS8Primary *This = impl_from_IKsPropertySet(iface);
1574 HRESULT res = E_PROP_ID_UNSUPPORTED;
1575 (void)pInstanceData;
1576 (void)cbInstanceData;
1578 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1580 EnterCriticalSection(This->crst);
1582 if(This->effect == 0)
1583 res = E_PROP_ID_UNSUPPORTED;
1584 else switch(dwPropID)
1586 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1587 res = DSERR_INVALIDPARAM;
1588 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1590 union {
1591 void *v;
1592 EAXLISTENERPROPERTIES *props;
1593 } data = { pPropData };
1595 *data.props = This->eax_prop;
1596 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1597 res = DS_OK;
1599 break;
1601 case DSPROPERTY_EAXLISTENER_ROOM:
1602 res = DSERR_INVALIDPARAM;
1603 if(cbPropData >= sizeof(LONG))
1605 union {
1606 void *v;
1607 LONG *l;
1608 } data = { pPropData };
1610 *data.l = This->eax_prop.lRoom;
1611 *pcbReturned = sizeof(LONG);
1612 res = DS_OK;
1614 break;
1615 case DSPROPERTY_EAXLISTENER_ROOMHF:
1616 res = DSERR_INVALIDPARAM;
1617 if(cbPropData >= sizeof(LONG))
1619 union {
1620 void *v;
1621 LONG *l;
1622 } data = { pPropData };
1624 *data.l = This->eax_prop.lRoomHF;
1625 *pcbReturned = sizeof(LONG);
1626 res = DS_OK;
1628 break;
1630 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1631 res = DSERR_INVALIDPARAM;
1632 if(cbPropData >= sizeof(FLOAT))
1634 union {
1635 void *v;
1636 FLOAT *fl;
1637 } data = { pPropData };
1639 *data.fl = This->eax_prop.flRoomRolloffFactor;
1640 *pcbReturned = sizeof(FLOAT);
1641 res = DS_OK;
1643 break;
1645 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1646 res = DSERR_INVALIDPARAM;
1647 if(cbPropData >= sizeof(DWORD))
1649 union {
1650 void *v;
1651 DWORD *dw;
1652 } data = { pPropData };
1654 *data.dw = This->eax_prop.dwEnvironment;
1655 *pcbReturned = sizeof(DWORD);
1656 res = DS_OK;
1658 break;
1660 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1661 res = DSERR_INVALIDPARAM;
1662 if(cbPropData >= sizeof(FLOAT))
1664 union {
1665 void *v;
1666 FLOAT *fl;
1667 } data = { pPropData };
1669 *data.fl = This->eax_prop.flEnvironmentSize;
1670 *pcbReturned = sizeof(FLOAT);
1671 res = DS_OK;
1673 break;
1674 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1675 res = DSERR_INVALIDPARAM;
1676 if(cbPropData >= sizeof(FLOAT))
1678 union {
1679 void *v;
1680 FLOAT *fl;
1681 } data = { pPropData };
1683 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1684 *pcbReturned = sizeof(FLOAT);
1685 res = DS_OK;
1687 break;
1689 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1690 res = DSERR_INVALIDPARAM;
1691 if(cbPropData >= sizeof(FLOAT))
1693 union {
1694 void *v;
1695 FLOAT *fl;
1696 } data = { pPropData };
1698 *data.fl = This->eax_prop.flAirAbsorptionHF;
1699 *pcbReturned = sizeof(FLOAT);
1700 res = DS_OK;
1702 break;
1704 case DSPROPERTY_EAXLISTENER_FLAGS:
1705 res = DSERR_INVALIDPARAM;
1706 if(cbPropData >= sizeof(DWORD))
1708 union {
1709 void *v;
1710 DWORD *dw;
1711 } data = { pPropData };
1713 *data.dw = This->eax_prop.dwFlags;
1714 *pcbReturned = sizeof(DWORD);
1715 res = DS_OK;
1717 break;
1719 default:
1720 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1721 break;
1724 LeaveCriticalSection(This->crst);
1726 else
1727 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1729 return res;
1732 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1733 REFGUID guidPropSet, ULONG dwPropID,
1734 LPVOID pInstanceData, ULONG cbInstanceData,
1735 LPVOID pPropData, ULONG cbPropData)
1737 DS8Primary *This = impl_from_IKsPropertySet(iface);
1738 HRESULT res = E_PROP_ID_UNSUPPORTED;
1739 (void)pInstanceData;
1740 (void)cbInstanceData;
1742 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1744 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1745 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1747 EnterCriticalSection(This->crst);
1748 setALContext(This->ctx);
1750 if(This->effect == 0)
1751 res = E_PROP_ID_UNSUPPORTED;
1752 else switch(propid)
1754 case 0: /* 0 = not setting any property, just apply */
1755 res = DS_OK;
1756 break;
1758 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1759 do_allparams:
1760 res = DSERR_INVALIDPARAM;
1761 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1763 union {
1764 const void *v;
1765 const EAXLISTENERPROPERTIES *props;
1766 } data = { pPropData };
1768 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1769 This->eax_prop = *data.props;
1770 This->ExtAL->Effectf(This->effect, AL_REVERB_DENSITY,
1771 (data.props->flEnvironmentSize < 2.0f) ?
1772 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1773 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1774 data.props->flEnvironmentDiffusion);
1776 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1777 mB_to_gain(data.props->lRoom));
1778 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1779 mB_to_gain(data.props->lRoomHF));
1781 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1782 data.props->flRoomRolloffFactor);
1784 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_TIME,
1785 data.props->flDecayTime);
1786 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1787 data.props->flDecayHFRatio);
1789 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1790 mB_to_gain(data.props->lReflections));
1791 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1792 data.props->flReflectionsDelay);
1794 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1795 mB_to_gain(data.props->lReverb));
1796 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1797 data.props->flReverbDelay);
1799 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1800 mB_to_gain(data.props->flAirAbsorptionHF));
1802 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1803 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1804 AL_TRUE : AL_FALSE);
1806 checkALError();
1808 This->dirty.bit.effect = 1;
1809 res = DS_OK;
1811 break;
1813 case DSPROPERTY_EAXLISTENER_ROOM:
1814 res = DSERR_INVALIDPARAM;
1815 if(cbPropData >= sizeof(LONG))
1817 union {
1818 const void *v;
1819 const LONG *l;
1820 } data = { pPropData };
1822 This->eax_prop.lRoom = *data.l;
1823 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1824 mB_to_gain(This->eax_prop.lRoom));
1825 checkALError();
1827 This->dirty.bit.effect = 1;
1828 res = DS_OK;
1830 break;
1831 case DSPROPERTY_EAXLISTENER_ROOMHF:
1832 res = DSERR_INVALIDPARAM;
1833 if(cbPropData >= sizeof(LONG))
1835 union {
1836 const void *v;
1837 const LONG *l;
1838 } data = { pPropData };
1840 This->eax_prop.lRoomHF = *data.l;
1841 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1842 mB_to_gain(This->eax_prop.lRoomHF));
1843 checkALError();
1845 This->dirty.bit.effect = 1;
1846 res = DS_OK;
1848 break;
1850 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1851 res = DSERR_INVALIDPARAM;
1852 if(cbPropData >= sizeof(FLOAT))
1854 union {
1855 const void *v;
1856 const FLOAT *fl;
1857 } data = { pPropData };
1859 This->eax_prop.flRoomRolloffFactor = *data.fl;
1860 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1861 This->eax_prop.flRoomRolloffFactor);
1862 checkALError();
1864 This->dirty.bit.effect = 1;
1865 res = DS_OK;
1867 break;
1869 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1870 res = DSERR_INVALIDPARAM;
1871 if(cbPropData >= sizeof(DWORD))
1873 union {
1874 const void *v;
1875 const DWORD *dw;
1876 } data = { pPropData };
1878 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1880 /* Get the environment index's default and pass it down to
1881 * ALLPARAMETERS */
1882 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1883 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1884 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1885 goto do_allparams;
1888 break;
1890 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1891 res = DSERR_INVALIDPARAM;
1892 if(cbPropData >= sizeof(FLOAT))
1894 union {
1895 const void *v;
1896 const FLOAT *fl;
1897 } data = { pPropData };
1899 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1901 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1903 This->eax_prop.flEnvironmentSize = *data.fl;
1905 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1907 This->eax_prop.flDecayTime *= scale;
1908 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1910 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1912 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1913 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1915 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1917 This->eax_prop.flReflectionsDelay *= scale;
1918 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1920 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1922 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1923 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1925 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1927 This->eax_prop.flReverbDelay *= scale;
1928 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1931 /* Pass the updated environment properties down to ALLPARAMETERS */
1932 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1933 pPropData = (void*)&This->eax_prop;
1934 cbPropData = sizeof(This->eax_prop);
1935 goto do_allparams;
1938 break;
1939 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1940 res = DSERR_INVALIDPARAM;
1941 if(cbPropData >= sizeof(FLOAT))
1943 union {
1944 const void *v;
1945 const FLOAT *fl;
1946 } data = { pPropData };
1948 This->eax_prop.flEnvironmentDiffusion = *data.fl;
1949 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1950 This->eax_prop.flEnvironmentDiffusion);
1951 checkALError();
1953 This->dirty.bit.effect = 1;
1954 res = DS_OK;
1956 break;
1958 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1959 res = DSERR_INVALIDPARAM;
1960 if(cbPropData >= sizeof(FLOAT))
1962 union {
1963 const void *v;
1964 const FLOAT *fl;
1965 } data = { pPropData };
1967 This->eax_prop.flAirAbsorptionHF = *data.fl;
1968 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1969 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
1970 checkALError();
1972 This->dirty.bit.effect = 1;
1973 res = DS_OK;
1975 break;
1977 case DSPROPERTY_EAXLISTENER_FLAGS:
1978 res = DSERR_INVALIDPARAM;
1979 if(cbPropData >= sizeof(DWORD))
1981 union {
1982 const void *v;
1983 const DWORD *dw;
1984 } data = { pPropData };
1986 This->eax_prop.dwFlags = *data.dw;
1987 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1988 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1989 AL_TRUE : AL_FALSE);
1990 checkALError();
1992 This->dirty.bit.effect = 1;
1993 res = DS_OK;
1995 default:
1996 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
1997 break;
2000 if(res == DS_OK && immediate)
2001 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2003 popALContext();
2004 LeaveCriticalSection(This->crst);
2006 else
2007 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2009 return res;
2012 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2013 REFGUID guidPropSet, ULONG dwPropID,
2014 PULONG pTypeSupport)
2016 DS8Primary *This = impl_from_IKsPropertySet(iface);
2017 HRESULT res = E_PROP_ID_UNSUPPORTED;
2019 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2021 EnterCriticalSection(This->crst);
2023 if(This->effect == 0)
2024 res = E_PROP_ID_UNSUPPORTED;
2025 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2026 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2027 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2028 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2029 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2030 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2031 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2032 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2033 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2035 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2036 res = DS_OK;
2038 else
2039 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2041 LeaveCriticalSection(This->crst);
2043 else
2044 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2046 return res;
2049 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2051 DS8PrimaryProp_QueryInterface,
2052 DS8PrimaryProp_AddRef,
2053 DS8PrimaryProp_Release,
2054 DS8PrimaryProp_Get,
2055 DS8PrimaryProp_Set,
2056 DS8PrimaryProp_QuerySupport