Reduce the scope of some locks
[dsound-openal.git] / primary.c
blob3eee4f4e8c06816eeb9068928b5e0160e9d9f4a4
1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "mmreg.h"
45 #include "ks.h"
46 #include "ksmedia.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
50 #else
52 #define WINVER 0x0600
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 #ifndef E_PROP_ID_UNSUPPORTED
62 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
63 #endif
65 #endif
67 static const IDirectSoundBufferVtbl DS8Primary_Vtbl;
68 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl;
69 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl;
72 static void AL_APIENTRY wrap_DeferUpdates(void)
73 { alcSuspendContext(alcGetCurrentContext()); }
74 static void AL_APIENTRY wrap_ProcessUpdates(void)
75 { alcProcessContext(alcGetCurrentContext()); }
78 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
80 DWORD i;
81 for(i = 0; i < buf->nnotify; ++i)
83 DSBPOSITIONNOTIFY *not = &buf->notify[i];
84 HANDLE event = not->hEventNotify;
85 DWORD ofs = not->dwOffset;
87 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
88 continue;
90 /* Wraparound case */
91 if(curpos < lastpos)
93 if(ofs < curpos || ofs >= lastpos)
94 SetEvent(event);
95 continue;
98 /* Normal case */
99 if(ofs >= lastpos && ofs < curpos)
100 SetEvent(event);
104 static void trigger_stop_notifies(DS8Buffer *buf)
106 DWORD i;
107 for(i = 0; i < buf->nnotify; ++i)
109 DSBPOSITIONNOTIFY *not = &buf->notify[i];
110 if(not->dwOffset == (DWORD)DSBPN_OFFSETSTOP)
111 SetEvent(not->hEventNotify);
115 static DWORD CALLBACK ThreadProc(void *dwUser)
117 DS8Primary *prim = (DS8Primary*)dwUser;
118 DWORD i;
119 MSG msg;
121 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
123 while(GetMessageA(&msg, NULL, 0, 0))
125 if(msg.message != WM_USER)
126 continue;
128 EnterCriticalSection(prim->crst);
129 setALContext(prim->ctx);
131 /* OpenAL doesn't support our lovely buffer extensions
132 * so just make sure enough buffers are queued
134 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES] &&
135 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
136 !prim->SupportedExt[EXT_STATIC_BUFFER])
138 for(i = 0;i < prim->nbuffers;++i)
140 DS8Buffer *buf = prim->buffers[i];
141 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
142 ALuint which, ofs;
144 if(buf->buffer->numsegs == 1 || !buf->isplaying)
145 continue;
147 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
148 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
149 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
151 queued -= done;
152 while(done--)
153 alSourceUnqueueBuffers(buf->source, 1, &which);
154 while(queued < QBUFFERS)
156 which = buf->buffer->buffers[buf->curidx];
157 ofs = buf->curidx*buf->buffer->segsize;
158 if(buf->curidx < buf->buffer->numsegs-1)
159 alBufferData(which, buf->buffer->buf_format,
160 buf->buffer->data + ofs, buf->buffer->segsize,
161 buf->buffer->format.Format.nSamplesPerSec);
162 else
163 alBufferData(which, buf->buffer->buf_format,
164 buf->buffer->data + ofs, buf->buffer->lastsegsize,
165 buf->buffer->format.Format.nSamplesPerSec);
167 alSourceQueueBuffers(buf->source, 1, &which);
168 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
169 queued++;
171 if(!buf->curidx && !buf->islooping)
173 buf->isplaying = FALSE;
174 break;
177 if(state != AL_PLAYING)
179 if(!queued)
181 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
182 continue;
184 alSourcePlay(buf->source);
187 checkALError();
190 for(i = 0;i < prim->nnotifies;)
192 DS8Buffer *buf = prim->notifies[i];
193 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
194 DWORD status=0, curpos=buf->lastpos;
196 IDirectSoundBuffer8_GetStatus(dsb, &status);
197 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
198 if(buf->lastpos != curpos)
200 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
201 buf->lastpos = curpos;
203 if(!(status&DSBSTATUS_PLAYING))
205 /* Remove this buffer from list and put another at the
206 * current position; don't increment i
208 trigger_stop_notifies(buf);
209 prim->notifies[i] = prim->notifies[--prim->nnotifies];
210 continue;
212 i++;
214 popALContext();
215 LeaveCriticalSection(prim->crst);
217 return 0;
221 HRESULT DS8Primary_PreInit(DS8Primary *This, DS8Impl *parent)
223 DS3DLISTENER *listener;
224 WAVEFORMATEX *wfx;
225 HRESULT hr;
227 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
228 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
229 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
231 This->parent = parent;
232 This->crst = &parent->share->crst;
233 This->ctx = parent->share->ctx;
234 This->SupportedExt = parent->share->SupportedExt;
235 This->ExtAL = &parent->share->ExtAL;
236 This->sources = parent->share->sources;
237 This->auxslot = parent->share->auxslot;
239 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
240 wfx = &This->format.Format;
242 wfx->wFormatTag = WAVE_FORMAT_PCM;
243 wfx->nChannels = 2;
244 wfx->wBitsPerSample = 8;
245 wfx->nSamplesPerSec = 22050;
246 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
247 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
248 wfx->cbSize = 0;
250 This->stopped = TRUE;
252 /* Apparently primary buffer size is always 32k,
253 * tested on windows with 192k 24 bits sound @ 6 channels
254 * where it will run out in 60 ms and it isn't pointer aligned
256 This->buf_size = 32768;
258 if(This->SupportedExt[SOFT_DEFERRED_UPDATES])
260 This->DeferUpdates = This->ExtAL->DeferUpdatesSOFT;
261 This->ProcessUpdates = This->ExtAL->ProcessUpdatesSOFT;
263 else
265 This->DeferUpdates = wrap_DeferUpdates;
266 This->ProcessUpdates = wrap_ProcessUpdates;
269 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
270 if(This->SupportedExt[EXT_EFX] && This->auxslot != 0)
272 ALint revid = alGetEnumValue("AL_EFFECT_REVERB");
273 if(revid != 0 && revid != -1)
275 This->ExtAL->GenEffects(1, &This->effect);
276 This->ExtAL->Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
277 checkALError();
281 /* Make sure DS3DListener defaults are applied to OpenAL */
282 listener = &This->listen;
283 listener->dwSize = sizeof(*listener);
284 listener->vPosition.x = 0.0;
285 listener->vPosition.y = 0.0;
286 listener->vPosition.z = 0.0;
287 listener->vVelocity.x = 0.0;
288 listener->vVelocity.y = 0.0;
289 listener->vVelocity.z = 0.0;
290 listener->vOrientFront.x = 0.0;
291 listener->vOrientFront.y = 0.0;
292 listener->vOrientFront.z = 1.0;
293 listener->vOrientTop.x = 0.0;
294 listener->vOrientTop.y = 1.0;
295 listener->vOrientTop.z = 0.0;
296 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
297 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
298 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
299 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
300 if(FAILED(hr))
301 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
303 This->sizenotifies = This->sizebuffers = parent->share->max_sources;
305 hr = DSERR_OUTOFMEMORY;
306 This->buffers = HeapAlloc(GetProcessHeap(), 0, This->sizebuffers*sizeof(*This->buffers));
307 This->notifies = HeapAlloc(GetProcessHeap(), 0, This->sizenotifies*sizeof(*This->notifies));
308 if(!This->buffers || !This->notifies)
309 goto fail;
311 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
312 if(This->thread_hdl == NULL)
313 goto fail;
315 return S_OK;
317 fail:
318 DS8Primary_Clear(This);
319 return hr;
322 void DS8Primary_Clear(DS8Primary *This)
324 TRACE("Clearing primary %p\n", This);
326 if(!This->parent)
327 return;
329 if(This->timer_id)
331 timeKillEvent(This->timer_id);
332 timeEndPeriod(This->timer_res);
333 TRACE("Killed timer\n");
335 if(This->thread_hdl)
337 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
338 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
339 ERR("Thread wait timed out");
340 CloseHandle(This->thread_hdl);
343 setALContext(This->ctx);
344 if(This->effect)
345 This->ExtAL->DeleteEffects(1, &This->effect);
346 popALContext();
347 while(This->nbuffers--)
348 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
350 HeapFree(GetProcessHeap(), 0, This->notifies);
351 HeapFree(GetProcessHeap(), 0, This->buffers);
352 memset(This, 0, sizeof(*This));
355 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
357 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
360 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
362 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
364 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
366 *ppv = NULL;
367 if(IsEqualIID(riid, &IID_IUnknown) ||
368 IsEqualIID(riid, &IID_IDirectSoundBuffer))
369 *ppv = &This->IDirectSoundBuffer_iface;
370 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
372 if((This->flags&DSBCAPS_CTRL3D))
373 *ppv = &This->IDirectSound3DListener_iface;
375 else
376 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
378 if(*ppv)
380 IUnknown_AddRef((IUnknown*)*ppv);
381 return S_OK;
384 return E_NOINTERFACE;
387 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
389 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
390 LONG ret;
392 ret = InterlockedIncrement(&This->ref);
393 if(ret == 1) This->flags = 0;
395 return ret;
398 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
400 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
401 LONG ret;
403 ret = InterlockedDecrement(&This->ref);
405 return ret;
408 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
410 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
412 TRACE("(%p)->(%p)\n", iface, caps);
414 if(!caps || caps->dwSize < sizeof(*caps))
416 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
417 return DSERR_INVALIDPARAM;
420 EnterCriticalSection(This->crst);
421 caps->dwFlags = This->flags;
422 caps->dwBufferBytes = This->buf_size;
423 caps->dwUnlockTransferRate = 0;
424 caps->dwPlayCpuOverhead = 0;
425 LeaveCriticalSection(This->crst);
427 return DS_OK;
430 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
432 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
433 HRESULT hr = DSERR_PRIOLEVELNEEDED;
435 EnterCriticalSection(This->crst);
436 if(This->write_emu)
437 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
438 LeaveCriticalSection(This->crst);
440 return hr;
443 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
445 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
446 HRESULT hr = S_OK;
447 UINT size;
449 if(!wfx && !written)
451 WARN("Cannot report format or format size\n");
452 return DSERR_INVALIDPARAM;
455 EnterCriticalSection(This->crst);
456 size = sizeof(This->format.Format) + This->format.Format.cbSize;
457 if(written)
458 *written = size;
459 if(wfx)
461 if(allocated < size)
462 hr = DSERR_INVALIDPARAM;
463 else
464 memcpy(wfx, &This->format.Format, size);
466 LeaveCriticalSection(This->crst);
468 return hr;
471 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
473 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
474 HRESULT hr = S_OK;
476 TRACE("(%p)->(%p)\n", iface, volume);
478 if(!volume)
479 return DSERR_INVALIDPARAM;
481 EnterCriticalSection(This->crst);
482 if(!(This->flags & DSBCAPS_CTRLVOLUME))
483 hr = DSERR_CONTROLUNAVAIL;
484 else
486 ALfloat gain;
488 setALContext(This->ctx);
489 alGetListenerf(AL_GAIN, &gain);
490 checkALError();
491 popALContext();
493 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
495 LeaveCriticalSection(This->crst);
497 return hr;
500 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
502 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
503 HRESULT hr = S_OK;
505 WARN("(%p)->(%p): semi-stub\n", iface, pan);
507 if(!pan)
508 return DSERR_INVALIDPARAM;
510 EnterCriticalSection(This->crst);
511 if(This->write_emu)
512 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
513 else if(!(This->flags & DSBCAPS_CTRLPAN))
514 hr = DSERR_CONTROLUNAVAIL;
515 else
516 *pan = 0;
517 LeaveCriticalSection(This->crst);
519 return hr;
522 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
524 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
525 HRESULT hr = S_OK;
527 WARN("(%p)->(%p): semi-stub\n", iface, freq);
529 if(!freq)
530 return DSERR_INVALIDPARAM;
532 EnterCriticalSection(This->crst);
533 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
534 hr = DSERR_CONTROLUNAVAIL;
535 else
536 *freq = This->format.Format.nSamplesPerSec;
537 LeaveCriticalSection(This->crst);
539 return hr;
542 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
544 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
546 TRACE("(%p)->(%p)\n", iface, status);
548 if(!status)
549 return DSERR_INVALIDPARAM;
551 EnterCriticalSection(This->crst);
553 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
554 if((This->flags&DSBCAPS_LOCDEFER))
555 *status |= DSBSTATUS_LOCHARDWARE;
557 if(This->stopped)
559 DWORD i, state;
560 HRESULT hr;
562 for(i = 0;i < This->nbuffers;++i)
564 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
565 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
566 break;
568 if(i == This->nbuffers)
570 /* Primary stopped and no buffers playing.. */
571 *status = 0;
575 LeaveCriticalSection(This->crst);
577 return S_OK;
580 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
582 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
583 HRESULT hr = S_OK;
585 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
587 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
589 WARN("Bad DSBDESC for primary buffer\n");
590 return DSERR_INVALIDPARAM;
592 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
593 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
594 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
596 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
597 return DSERR_INVALIDPARAM;
600 EnterCriticalSection(This->crst);
601 /* Should be 0 if not initialized */
602 if(This->flags)
604 hr = DSERR_ALREADYINITIALIZED;
605 goto out;
608 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
610 DSBUFFERDESC emudesc;
611 DS8Buffer *emu;
613 if(This->write_emu)
615 ERR("There shouldn't be a write_emu!\n");
616 IDirectSoundBuffer8_Release(This->write_emu);
617 This->write_emu = NULL;
620 memset(&emudesc, 0, sizeof(emudesc));
621 emudesc.dwSize = sizeof(emudesc);
622 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
623 /* Dont play last incomplete sample */
624 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
625 emudesc.lpwfxFormat = &This->format.Format;
627 hr = DS8Buffer_Create(&emu, This, NULL);
628 if(SUCCEEDED(hr))
630 This->write_emu = &emu->IDirectSoundBuffer8_iface;
631 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
632 if(FAILED(hr))
634 IDirectSoundBuffer8_Release(This->write_emu);
635 This->write_emu = NULL;
640 if(SUCCEEDED(hr))
641 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
642 out:
643 LeaveCriticalSection(This->crst);
644 return hr;
647 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
649 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
650 HRESULT hr = DSERR_PRIOLEVELNEEDED;
652 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
654 EnterCriticalSection(This->crst);
655 if(This->write_emu)
656 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
657 LeaveCriticalSection(This->crst);
659 return hr;
662 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
664 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
665 HRESULT hr;
667 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
669 if(!(flags & DSBPLAY_LOOPING))
671 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
672 return DSERR_INVALIDPARAM;
675 EnterCriticalSection(This->crst);
676 hr = S_OK;
677 if(This->write_emu)
678 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
679 if(SUCCEEDED(hr))
680 This->stopped = FALSE;
681 LeaveCriticalSection(This->crst);
683 return hr;
686 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
688 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
689 return DSERR_INVALIDCALL;
692 /* Just assume the format is crap, and clean up the damage */
693 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
695 if(from->wFormatTag == WAVE_FORMAT_PCM)
697 wfx->cbSize = 0;
698 if(from->wBitsPerSample == 8 ||
699 from->wBitsPerSample == 16 ||
700 from->wBitsPerSample == 24 ||
701 from->wBitsPerSample == 32)
702 wfx->wBitsPerSample = from->wBitsPerSample;
704 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
706 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
707 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
708 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
710 /* Fail silently.. */
711 if(from->cbSize < size)
712 return;
713 if(!fromx->Samples.wValidBitsPerSample &&
714 !fromx->Format.wBitsPerSample)
715 return;
717 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
718 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
720 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
721 return;
724 wfe->Format.wBitsPerSample = from->wBitsPerSample;
725 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
726 if(!wfe->Samples.wValidBitsPerSample)
727 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
728 wfe->Format.cbSize = size;
729 wfe->dwChannelMask = fromx->dwChannelMask;
730 wfe->SubFormat = fromx->SubFormat;
732 else
734 ERR("Unhandled format tag %04x\n", from->wFormatTag);
735 return;
738 if(from->nChannels)
739 wfx->nChannels = from->nChannels;
740 wfx->wFormatTag = from->wFormatTag;
741 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
742 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
743 wfx->nSamplesPerSec = from->nSamplesPerSec;
744 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
745 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
748 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
750 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
751 HRESULT hr = S_OK;
752 ALCint freq;
754 TRACE("(%p)->(%p)\n", iface, wfx);
756 if(!wfx)
758 WARN("Missing format\n");
759 return DSERR_INVALIDPARAM;
762 EnterCriticalSection(This->crst);
764 if(This->parent->prio_level < DSSCL_PRIORITY)
766 hr = DSERR_PRIOLEVELNEEDED;
767 goto out;
770 TRACE("Requested primary format:\n"
771 " FormatTag = %04x\n"
772 " Channels = %u\n"
773 " SamplesPerSec = %"LONGFMT"u\n"
774 " AvgBytesPerSec = %"LONGFMT"u\n"
775 " BlockAlign = %u\n"
776 " BitsPerSample = %u\n",
777 wfx->wFormatTag, wfx->nChannels,
778 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
779 wfx->nBlockAlign, wfx->wBitsPerSample);
781 copy_waveformat(&This->format.Format, wfx);
783 freq = This->format.Format.nSamplesPerSec;
784 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
785 checkALCError(This->parent->device);
787 This->format.Format.nSamplesPerSec = freq;
788 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
789 This->format.Format.nSamplesPerSec;
791 if(This->write_emu)
793 DS8Buffer *buf;
794 DSBUFFERDESC desc;
796 memset(&desc, 0, sizeof(desc));
797 desc.dwSize = sizeof(desc);
798 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
799 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
800 desc.lpwfxFormat = &This->format.Format;
802 hr = DS8Buffer_Create(&buf, This, NULL);
803 if(FAILED(hr))
804 goto out;
806 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
807 if(FAILED(hr))
808 DS8Buffer_Destroy(buf);
809 else
811 IDirectSoundBuffer8_Release(This->write_emu);
812 This->write_emu = &buf->IDirectSoundBuffer8_iface;
816 out:
817 LeaveCriticalSection(This->crst);
818 return hr;
821 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
823 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
824 HRESULT hr = S_OK;
826 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
828 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
830 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
831 return DSERR_INVALIDPARAM;
834 EnterCriticalSection(This->crst);
835 if(!(This->flags&DSBCAPS_CTRLVOLUME))
836 hr = DSERR_CONTROLUNAVAIL;
837 if(SUCCEEDED(hr))
839 setALContext(This->ctx);
840 alListenerf(AL_GAIN, mB_to_gain(vol));
841 popALContext();
843 LeaveCriticalSection(This->crst);
845 return hr;
848 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
850 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
851 HRESULT hr;
853 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
855 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
857 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
858 return DSERR_INVALIDPARAM;
861 EnterCriticalSection(This->crst);
862 if(!(This->flags&DSBCAPS_CTRLPAN))
864 WARN("control unavailable\n");
865 hr = DSERR_CONTROLUNAVAIL;
867 else if(This->write_emu)
868 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
869 else
871 FIXME("Not supported\n");
872 hr = E_NOTIMPL;
874 LeaveCriticalSection(This->crst);
876 return hr;
879 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
881 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
882 return DSERR_CONTROLUNAVAIL;
885 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
887 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
888 HRESULT hr = S_OK;
890 TRACE("(%p)->()\n", iface);
892 EnterCriticalSection(This->crst);
893 if(This->write_emu)
894 hr = IDirectSoundBuffer8_Stop(This->write_emu);
895 if(SUCCEEDED(hr))
896 This->stopped = TRUE;
897 LeaveCriticalSection(This->crst);
899 return hr;
902 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
904 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
905 HRESULT hr = DSERR_INVALIDCALL;
907 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
909 EnterCriticalSection(This->crst);
910 if(This->write_emu)
911 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
912 LeaveCriticalSection(This->crst);
914 return hr;
917 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
919 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
920 HRESULT hr = S_OK;
922 TRACE("(%p)->()\n", iface);
924 EnterCriticalSection(This->crst);
925 if(This->write_emu)
926 hr = IDirectSoundBuffer8_Restore(This->write_emu);
927 LeaveCriticalSection(This->crst);
929 return hr;
932 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
934 DS8Primary_QueryInterface,
935 DS8Primary_AddRef,
936 DS8Primary_Release,
937 DS8Primary_GetCaps,
938 DS8Primary_GetCurrentPosition,
939 DS8Primary_GetFormat,
940 DS8Primary_GetVolume,
941 DS8Primary_GetPan,
942 DS8Primary_GetFrequency,
943 DS8Primary_GetStatus,
944 DS8Primary_Initialize,
945 DS8Primary_Lock,
946 DS8Primary_Play,
947 DS8Primary_SetCurrentPosition,
948 DS8Primary_SetFormat,
949 DS8Primary_SetVolume,
950 DS8Primary_SetPan,
951 DS8Primary_SetFrequency,
952 DS8Primary_Stop,
953 DS8Primary_Unlock,
954 DS8Primary_Restore
957 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
959 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
962 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
964 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
965 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
968 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
970 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
971 LONG ret;
973 ret = InterlockedIncrement(&This->ds3d_ref);
974 TRACE("new refcount %"LONGFMT"d\n", ret);
976 return ret;
980 /* Considering the primary buffer doesn't get destroyed
981 * it doesn't make sense to destroy ds3d here
983 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
985 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
986 LONG ret;
988 ret = InterlockedDecrement(&This->ds3d_ref);
989 TRACE("new refcount %"LONGFMT"d\n", ret);
991 return ret;
995 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
997 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
999 TRACE("(%p)->(%p)\n", iface, listener);
1001 if(!listener || listener->dwSize < sizeof(*listener))
1003 WARN("Invalid DS3DLISTENER %p %"LONGFMT"u\n", listener, listener ? listener->dwSize : 0);
1004 return DSERR_INVALIDPARAM;
1007 EnterCriticalSection(This->crst);
1008 setALContext(This->ctx);
1009 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1010 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1011 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1012 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1013 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1014 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
1015 popALContext();
1016 LeaveCriticalSection(This->crst);
1018 return DS_OK;
1021 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1023 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1025 TRACE("(%p)->(%p)\n", iface, distancefactor);
1027 if(!distancefactor)
1029 WARN("Invalid parameter %p\n", distancefactor);
1030 return DSERR_INVALIDPARAM;
1033 EnterCriticalSection(This->crst);
1034 setALContext(This->ctx);
1036 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1037 checkALError();
1039 popALContext();
1040 LeaveCriticalSection(This->crst);
1042 return S_OK;
1045 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1047 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1049 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1051 if(!dopplerfactor)
1053 WARN("Invalid parameter %p\n", dopplerfactor);
1054 return DSERR_INVALIDPARAM;
1057 EnterCriticalSection(This->crst);
1058 setALContext(This->ctx);
1060 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1061 checkALError();
1063 popALContext();
1064 LeaveCriticalSection(This->crst);
1066 return S_OK;
1069 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1071 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1072 ALfloat orient[6];
1074 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1076 if(!front || !top)
1078 WARN("Invalid parameter %p %p\n", front, top);
1079 return DSERR_INVALIDPARAM;
1082 EnterCriticalSection(This->crst);
1083 setALContext(This->ctx);
1085 alGetListenerfv(AL_ORIENTATION, orient);
1086 checkALError();
1088 front->x = orient[0];
1089 front->y = orient[1];
1090 front->z = -orient[2];
1091 top->x = orient[3];
1092 top->y = orient[4];
1093 top->z = -orient[5];
1095 popALContext();
1096 LeaveCriticalSection(This->crst);
1098 return S_OK;
1101 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1103 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1104 ALfloat alpos[3];
1106 TRACE("(%p)->(%p)\n", iface, pos);
1108 if(!pos)
1110 WARN("Invalid parameter %p\n", pos);
1111 return DSERR_INVALIDPARAM;
1114 EnterCriticalSection(This->crst);
1115 setALContext(This->ctx);
1117 alGetListenerfv(AL_POSITION, alpos);
1118 checkALError();
1120 pos->x = alpos[0];
1121 pos->y = alpos[1];
1122 pos->z = -alpos[2];
1124 popALContext();
1125 LeaveCriticalSection(This->crst);
1127 return S_OK;
1130 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1132 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1134 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1136 if(!rollofffactor)
1138 WARN("Invalid parameter %p\n", rollofffactor);
1139 return DSERR_INVALIDPARAM;
1142 EnterCriticalSection(This->crst);
1143 *rollofffactor = This->rollofffactor;
1144 LeaveCriticalSection(This->crst);
1146 return S_OK;
1149 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1151 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1152 ALfloat vel[3];
1154 TRACE("(%p)->(%p)\n", iface, velocity);
1156 if(!velocity)
1158 WARN("Invalid parameter %p\n", velocity);
1159 return DSERR_INVALIDPARAM;
1162 EnterCriticalSection(This->crst);
1163 setALContext(This->ctx);
1165 alGetListenerfv(AL_VELOCITY, vel);
1166 checkALError();
1168 velocity->x = vel[0];
1169 velocity->y = vel[1];
1170 velocity->z = -vel[2];
1172 popALContext();
1173 LeaveCriticalSection(This->crst);
1175 return S_OK;
1178 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1180 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1182 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, listen, apply);
1184 if(!listen || listen->dwSize < sizeof(*listen))
1186 WARN("Invalid parameter %p %"LONGFMT"u\n", listen, listen ? listen->dwSize : 0);
1187 return DSERR_INVALIDPARAM;
1190 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1191 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1193 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1194 return DSERR_INVALIDPARAM;
1197 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1198 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1200 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1201 return DSERR_INVALIDPARAM;
1204 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1205 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1207 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1208 return DSERR_INVALIDPARAM;
1211 EnterCriticalSection(This->crst);
1212 setALContext(This->ctx);
1213 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1214 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1215 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1216 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1217 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1218 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1219 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1220 popALContext();
1221 LeaveCriticalSection(This->crst);
1223 return S_OK;
1226 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1228 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1230 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1232 if(factor < DS3D_MINDISTANCEFACTOR ||
1233 factor > DS3D_MAXDISTANCEFACTOR)
1235 WARN("Invalid parameter %f\n", factor);
1236 return DSERR_INVALIDPARAM;
1239 if(apply == DS3D_DEFERRED)
1241 EnterCriticalSection(This->crst);
1242 This->listen.flDistanceFactor = factor;
1243 This->dirty.bit.distancefactor = 1;
1244 LeaveCriticalSection(This->crst);
1246 else
1248 setALContext(This->ctx);
1249 alSpeedOfSound(343.3f/factor);
1250 if(This->SupportedExt[EXT_EFX])
1251 alListenerf(AL_METERS_PER_UNIT, factor);
1252 checkALError();
1253 popALContext();
1256 return S_OK;
1259 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1261 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1263 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1265 if(factor < DS3D_MINDOPPLERFACTOR ||
1266 factor > DS3D_MAXDOPPLERFACTOR)
1268 WARN("Invalid parameter %f\n", factor);
1269 return DSERR_INVALIDPARAM;
1272 if(apply == DS3D_DEFERRED)
1274 EnterCriticalSection(This->crst);
1275 This->listen.flDopplerFactor = factor;
1276 This->dirty.bit.dopplerfactor = 1;
1277 LeaveCriticalSection(This->crst);
1279 else
1281 setALContext(This->ctx);
1282 alDopplerFactor(factor);
1283 checkALError();
1284 popALContext();
1287 return S_OK;
1290 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1292 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1294 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT"u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1296 if(apply == DS3D_DEFERRED)
1298 EnterCriticalSection(This->crst);
1299 This->listen.vOrientFront.x = xFront;
1300 This->listen.vOrientFront.y = yFront;
1301 This->listen.vOrientFront.z = zFront;
1302 This->listen.vOrientTop.x = xTop;
1303 This->listen.vOrientTop.y = yTop;
1304 This->listen.vOrientTop.z = zTop;
1305 This->dirty.bit.orientation = 1;
1306 LeaveCriticalSection(This->crst);
1308 else
1310 ALfloat orient[6] = {
1311 xFront, yFront, -zFront,
1312 xTop, yTop, -zTop
1314 setALContext(This->ctx);
1315 alListenerfv(AL_ORIENTATION, orient);
1316 checkALError();
1317 popALContext();
1320 return S_OK;
1323 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1325 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1327 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1329 if(apply == DS3D_DEFERRED)
1331 EnterCriticalSection(This->crst);
1332 This->listen.vPosition.x = x;
1333 This->listen.vPosition.y = y;
1334 This->listen.vPosition.z = z;
1335 This->dirty.bit.pos = 1;
1336 LeaveCriticalSection(This->crst);
1338 else
1340 setALContext(This->ctx);
1341 alListener3f(AL_POSITION, x, y, -z);
1342 checkALError();
1343 popALContext();
1346 return S_OK;
1349 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1351 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1353 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1355 if(factor < DS3D_MINROLLOFFFACTOR ||
1356 factor > DS3D_MAXROLLOFFFACTOR)
1358 WARN("Invalid parameter %f\n", factor);
1359 return DSERR_INVALIDPARAM;
1362 EnterCriticalSection(This->crst);
1363 if(apply == DS3D_DEFERRED)
1365 This->listen.flRolloffFactor = factor;
1366 This->dirty.bit.rollofffactor = 1;
1368 else
1370 DWORD i;
1372 setALContext(This->ctx);
1373 for(i = 0;i < This->nbuffers;++i)
1375 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1376 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1378 checkALError();
1379 popALContext();
1381 This->rollofffactor = factor;
1383 LeaveCriticalSection(This->crst);
1385 return S_OK;
1388 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1390 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1392 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1394 if(apply == DS3D_DEFERRED)
1396 EnterCriticalSection(This->crst);
1397 This->listen.vVelocity.x = x;
1398 This->listen.vVelocity.y = y;
1399 This->listen.vVelocity.z = z;
1400 This->dirty.bit.vel = 1;
1401 LeaveCriticalSection(This->crst);
1403 else
1405 setALContext(This->ctx);
1406 alListener3f(AL_VELOCITY, x, y, -z);
1407 checkALError();
1408 popALContext();
1411 return S_OK;
1414 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1416 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1417 const DS3DLISTENER *listen = &This->listen;
1418 DWORD i;
1420 EnterCriticalSection(This->crst);
1421 setALContext(This->ctx);
1422 This->DeferUpdates();
1424 if(This->dirty.bit.pos)
1425 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1426 if(This->dirty.bit.vel)
1427 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1428 if(This->dirty.bit.orientation)
1430 ALfloat orient[6] = {
1431 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1432 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1434 alListenerfv(AL_ORIENTATION, orient);
1436 if(This->dirty.bit.distancefactor)
1438 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1439 if(This->SupportedExt[EXT_EFX])
1440 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1443 if(This->dirty.bit.rollofffactor)
1445 ALfloat rolloff = This->rollofffactor;
1446 for(i = 0;i < This->nbuffers;++i)
1448 DS8Buffer *buf = This->buffers[i];
1449 if(buf->ds3dmode != DS3DMODE_DISABLE)
1450 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1454 if(This->dirty.bit.dopplerfactor)
1455 alDopplerFactor(listen->flDopplerFactor);
1457 if(This->dirty.bit.effect)
1458 This->ExtAL->AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1460 /* checkALError is here for debugging */
1461 checkALError();
1463 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1464 This->dirty.flags = 0;
1466 for(i = 0;i < This->nbuffers;++i)
1468 DS8Buffer *buf = This->buffers[i];
1470 if(!buf->dirty.flags)
1471 continue;
1473 if(buf->dirty.bit.pos)
1474 alSource3f(buf->source, AL_POSITION,
1475 buf->ds3dbuffer.vPosition.x,
1476 buf->ds3dbuffer.vPosition.y,
1477 -buf->ds3dbuffer.vPosition.z);
1478 if(buf->dirty.bit.vel)
1479 alSource3f(buf->source, AL_VELOCITY,
1480 buf->ds3dbuffer.vVelocity.x,
1481 buf->ds3dbuffer.vVelocity.y,
1482 -buf->ds3dbuffer.vVelocity.z);
1483 if(buf->dirty.bit.cone_angles)
1485 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1486 buf->ds3dbuffer.dwInsideConeAngle);
1487 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1488 buf->ds3dbuffer.dwOutsideConeAngle);
1490 if(buf->dirty.bit.cone_orient)
1491 alSource3f(buf->source, AL_DIRECTION,
1492 buf->ds3dbuffer.vConeOrientation.x,
1493 buf->ds3dbuffer.vConeOrientation.y,
1494 -buf->ds3dbuffer.vConeOrientation.z);
1495 if(buf->dirty.bit.cone_outsidevolume)
1496 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1497 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1498 if(buf->dirty.bit.min_distance)
1499 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1500 if(buf->dirty.bit.max_distance)
1501 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1502 if(buf->dirty.bit.mode)
1504 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1505 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1506 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1507 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1508 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1510 buf->dirty.flags = 0;
1512 checkALError();
1514 This->ProcessUpdates();
1515 popALContext();
1516 LeaveCriticalSection(This->crst);
1518 return S_OK;
1521 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1523 DS8Primary3D_QueryInterface,
1524 DS8Primary3D_AddRef,
1525 DS8Primary3D_Release,
1526 DS8Primary3D_GetAllParameters,
1527 DS8Primary3D_GetDistanceFactor,
1528 DS8Primary3D_GetDopplerFactor,
1529 DS8Primary3D_GetOrientation,
1530 DS8Primary3D_GetPosition,
1531 DS8Primary3D_GetRolloffFactor,
1532 DS8Primary3D_GetVelocity,
1533 DS8Primary3D_SetAllParameters,
1534 DS8Primary3D_SetDistanceFactor,
1535 DS8Primary3D_SetDopplerFactor,
1536 DS8Primary3D_SetOrientation,
1537 DS8Primary3D_SetPosition,
1538 DS8Primary3D_SetRolloffFactor,
1539 DS8Primary3D_SetVelocity,
1540 DS8Primary3D_CommitDeferredSettings
1543 /* NOTE: Although the app handles listener properties through secondary buffers,
1544 * we pass the requests to the primary buffer though a propertyset interface.
1545 * These methods are not exposed to the app. */
1546 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1548 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1551 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1553 DS8Primary *This = impl_from_IKsPropertySet(iface);
1554 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1557 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1559 DS8Primary *This = impl_from_IKsPropertySet(iface);
1560 LONG ret;
1562 ret = InterlockedIncrement(&This->prop_ref);
1563 TRACE("new refcount %"LONGFMT"d\n", ret);
1565 return ret;
1568 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1570 DS8Primary *This = impl_from_IKsPropertySet(iface);
1571 LONG ret;
1573 ret = InterlockedDecrement(&This->prop_ref);
1574 TRACE("new refcount %"LONGFMT"d\n", ret);
1576 return ret;
1579 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1580 REFGUID guidPropSet, ULONG dwPropID,
1581 LPVOID pInstanceData, ULONG cbInstanceData,
1582 LPVOID pPropData, ULONG cbPropData,
1583 PULONG pcbReturned)
1585 DS8Primary *This = impl_from_IKsPropertySet(iface);
1586 HRESULT res = E_PROP_ID_UNSUPPORTED;
1587 (void)pInstanceData;
1588 (void)cbInstanceData;
1590 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1592 EnterCriticalSection(This->crst);
1594 if(This->effect == 0)
1595 res = E_PROP_ID_UNSUPPORTED;
1596 else switch(dwPropID)
1598 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1599 res = DSERR_INVALIDPARAM;
1600 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1602 union {
1603 void *v;
1604 EAXLISTENERPROPERTIES *props;
1605 } data = { pPropData };
1607 *data.props = This->eax_prop;
1608 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1609 res = DS_OK;
1611 break;
1613 case DSPROPERTY_EAXLISTENER_ROOM:
1614 res = DSERR_INVALIDPARAM;
1615 if(cbPropData >= sizeof(LONG))
1617 union {
1618 void *v;
1619 LONG *l;
1620 } data = { pPropData };
1622 *data.l = This->eax_prop.lRoom;
1623 *pcbReturned = sizeof(LONG);
1624 res = DS_OK;
1626 break;
1627 case DSPROPERTY_EAXLISTENER_ROOMHF:
1628 res = DSERR_INVALIDPARAM;
1629 if(cbPropData >= sizeof(LONG))
1631 union {
1632 void *v;
1633 LONG *l;
1634 } data = { pPropData };
1636 *data.l = This->eax_prop.lRoomHF;
1637 *pcbReturned = sizeof(LONG);
1638 res = DS_OK;
1640 break;
1642 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1643 res = DSERR_INVALIDPARAM;
1644 if(cbPropData >= sizeof(FLOAT))
1646 union {
1647 void *v;
1648 FLOAT *fl;
1649 } data = { pPropData };
1651 *data.fl = This->eax_prop.flRoomRolloffFactor;
1652 *pcbReturned = sizeof(FLOAT);
1653 res = DS_OK;
1655 break;
1657 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1658 res = DSERR_INVALIDPARAM;
1659 if(cbPropData >= sizeof(DWORD))
1661 union {
1662 void *v;
1663 DWORD *dw;
1664 } data = { pPropData };
1666 *data.dw = This->eax_prop.dwEnvironment;
1667 *pcbReturned = sizeof(DWORD);
1668 res = DS_OK;
1670 break;
1672 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1673 res = DSERR_INVALIDPARAM;
1674 if(cbPropData >= sizeof(FLOAT))
1676 union {
1677 void *v;
1678 FLOAT *fl;
1679 } data = { pPropData };
1681 *data.fl = This->eax_prop.flEnvironmentSize;
1682 *pcbReturned = sizeof(FLOAT);
1683 res = DS_OK;
1685 break;
1686 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1687 res = DSERR_INVALIDPARAM;
1688 if(cbPropData >= sizeof(FLOAT))
1690 union {
1691 void *v;
1692 FLOAT *fl;
1693 } data = { pPropData };
1695 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1696 *pcbReturned = sizeof(FLOAT);
1697 res = DS_OK;
1699 break;
1701 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1702 res = DSERR_INVALIDPARAM;
1703 if(cbPropData >= sizeof(FLOAT))
1705 union {
1706 void *v;
1707 FLOAT *fl;
1708 } data = { pPropData };
1710 *data.fl = This->eax_prop.flAirAbsorptionHF;
1711 *pcbReturned = sizeof(FLOAT);
1712 res = DS_OK;
1714 break;
1716 case DSPROPERTY_EAXLISTENER_FLAGS:
1717 res = DSERR_INVALIDPARAM;
1718 if(cbPropData >= sizeof(DWORD))
1720 union {
1721 void *v;
1722 DWORD *dw;
1723 } data = { pPropData };
1725 *data.dw = This->eax_prop.dwFlags;
1726 *pcbReturned = sizeof(DWORD);
1727 res = DS_OK;
1729 break;
1731 default:
1732 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1733 break;
1736 LeaveCriticalSection(This->crst);
1738 else
1739 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1741 return res;
1744 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1745 REFGUID guidPropSet, ULONG dwPropID,
1746 LPVOID pInstanceData, ULONG cbInstanceData,
1747 LPVOID pPropData, ULONG cbPropData)
1749 DS8Primary *This = impl_from_IKsPropertySet(iface);
1750 HRESULT res = E_PROP_ID_UNSUPPORTED;
1751 (void)pInstanceData;
1752 (void)cbInstanceData;
1754 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1756 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1757 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1759 EnterCriticalSection(This->crst);
1760 setALContext(This->ctx);
1762 if(This->effect == 0)
1763 res = E_PROP_ID_UNSUPPORTED;
1764 else switch(propid)
1766 case 0: /* 0 = not setting any property, just apply */
1767 res = DS_OK;
1768 break;
1770 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1771 do_allparams:
1772 res = DSERR_INVALIDPARAM;
1773 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1775 union {
1776 const void *v;
1777 const EAXLISTENERPROPERTIES *props;
1778 } data = { pPropData };
1780 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1781 This->eax_prop = *data.props;
1782 This->ExtAL->Effectf(This->effect, AL_REVERB_DENSITY,
1783 (data.props->flEnvironmentSize < 2.0f) ?
1784 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1785 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1786 data.props->flEnvironmentDiffusion);
1788 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1789 mB_to_gain(data.props->lRoom));
1790 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1791 mB_to_gain(data.props->lRoomHF));
1793 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1794 data.props->flRoomRolloffFactor);
1796 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_TIME,
1797 data.props->flDecayTime);
1798 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1799 data.props->flDecayHFRatio);
1801 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1802 mB_to_gain(data.props->lReflections));
1803 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1804 data.props->flReflectionsDelay);
1806 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1807 mB_to_gain(data.props->lReverb));
1808 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1809 data.props->flReverbDelay);
1811 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1812 mB_to_gain(data.props->flAirAbsorptionHF));
1814 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1815 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1816 AL_TRUE : AL_FALSE);
1818 checkALError();
1820 This->dirty.bit.effect = 1;
1821 res = DS_OK;
1823 break;
1825 case DSPROPERTY_EAXLISTENER_ROOM:
1826 res = DSERR_INVALIDPARAM;
1827 if(cbPropData >= sizeof(LONG))
1829 union {
1830 const void *v;
1831 const LONG *l;
1832 } data = { pPropData };
1834 This->eax_prop.lRoom = *data.l;
1835 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1836 mB_to_gain(This->eax_prop.lRoom));
1837 checkALError();
1839 This->dirty.bit.effect = 1;
1840 res = DS_OK;
1842 break;
1843 case DSPROPERTY_EAXLISTENER_ROOMHF:
1844 res = DSERR_INVALIDPARAM;
1845 if(cbPropData >= sizeof(LONG))
1847 union {
1848 const void *v;
1849 const LONG *l;
1850 } data = { pPropData };
1852 This->eax_prop.lRoomHF = *data.l;
1853 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1854 mB_to_gain(This->eax_prop.lRoomHF));
1855 checkALError();
1857 This->dirty.bit.effect = 1;
1858 res = DS_OK;
1860 break;
1862 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1863 res = DSERR_INVALIDPARAM;
1864 if(cbPropData >= sizeof(FLOAT))
1866 union {
1867 const void *v;
1868 const FLOAT *fl;
1869 } data = { pPropData };
1871 This->eax_prop.flRoomRolloffFactor = *data.fl;
1872 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1873 This->eax_prop.flRoomRolloffFactor);
1874 checkALError();
1876 This->dirty.bit.effect = 1;
1877 res = DS_OK;
1879 break;
1881 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1882 res = DSERR_INVALIDPARAM;
1883 if(cbPropData >= sizeof(DWORD))
1885 union {
1886 const void *v;
1887 const DWORD *dw;
1888 } data = { pPropData };
1890 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1892 /* Get the environment index's default and pass it down to
1893 * ALLPARAMETERS */
1894 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1895 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1896 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1897 goto do_allparams;
1900 break;
1902 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1903 res = DSERR_INVALIDPARAM;
1904 if(cbPropData >= sizeof(FLOAT))
1906 union {
1907 const void *v;
1908 const FLOAT *fl;
1909 } data = { pPropData };
1911 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1913 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1915 This->eax_prop.flEnvironmentSize = *data.fl;
1917 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1919 This->eax_prop.flDecayTime *= scale;
1920 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1922 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1924 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1925 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1927 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1929 This->eax_prop.flReflectionsDelay *= scale;
1930 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1932 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1934 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1935 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1937 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1939 This->eax_prop.flReverbDelay *= scale;
1940 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1943 /* Pass the updated environment properties down to ALLPARAMETERS */
1944 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1945 pPropData = (void*)&This->eax_prop;
1946 cbPropData = sizeof(This->eax_prop);
1947 goto do_allparams;
1950 break;
1951 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1952 res = DSERR_INVALIDPARAM;
1953 if(cbPropData >= sizeof(FLOAT))
1955 union {
1956 const void *v;
1957 const FLOAT *fl;
1958 } data = { pPropData };
1960 This->eax_prop.flEnvironmentDiffusion = *data.fl;
1961 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1962 This->eax_prop.flEnvironmentDiffusion);
1963 checkALError();
1965 This->dirty.bit.effect = 1;
1966 res = DS_OK;
1968 break;
1970 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1971 res = DSERR_INVALIDPARAM;
1972 if(cbPropData >= sizeof(FLOAT))
1974 union {
1975 const void *v;
1976 const FLOAT *fl;
1977 } data = { pPropData };
1979 This->eax_prop.flAirAbsorptionHF = *data.fl;
1980 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1981 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
1982 checkALError();
1984 This->dirty.bit.effect = 1;
1985 res = DS_OK;
1987 break;
1989 case DSPROPERTY_EAXLISTENER_FLAGS:
1990 res = DSERR_INVALIDPARAM;
1991 if(cbPropData >= sizeof(DWORD))
1993 union {
1994 const void *v;
1995 const DWORD *dw;
1996 } data = { pPropData };
1998 This->eax_prop.dwFlags = *data.dw;
1999 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2000 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2001 AL_TRUE : AL_FALSE);
2002 checkALError();
2004 This->dirty.bit.effect = 1;
2005 res = DS_OK;
2007 break;
2009 default:
2010 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
2011 break;
2014 if(res == DS_OK && immediate)
2015 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2017 popALContext();
2018 LeaveCriticalSection(This->crst);
2020 else
2021 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2023 return res;
2026 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2027 REFGUID guidPropSet, ULONG dwPropID,
2028 PULONG pTypeSupport)
2030 DS8Primary *This = impl_from_IKsPropertySet(iface);
2031 HRESULT res = E_PROP_ID_UNSUPPORTED;
2033 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2035 EnterCriticalSection(This->crst);
2037 if(This->effect == 0)
2038 res = E_PROP_ID_UNSUPPORTED;
2039 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2040 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2041 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2042 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2043 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2044 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2045 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2046 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2047 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2049 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2050 res = DS_OK;
2052 else
2053 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2055 LeaveCriticalSection(This->crst);
2057 else
2058 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2060 return res;
2063 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2065 DS8PrimaryProp_QueryInterface,
2066 DS8PrimaryProp_AddRef,
2067 DS8PrimaryProp_Release,
2068 DS8PrimaryProp_Get,
2069 DS8PrimaryProp_Set,
2070 DS8PrimaryProp_QuerySupport