Only set buffer flags that should be updated
[dsound-openal.git] / primary.c
blobb81a482e5cf97d1584e2e524708b60179b9150fb
1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "mmreg.h"
45 #include "ks.h"
46 #include "ksmedia.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
50 #else
52 #define WINVER 0x0600
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 #ifndef E_PROP_ID_UNSUPPORTED
62 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
63 #endif
65 #endif
67 static const IDirectSoundBufferVtbl DS8Primary_Vtbl;
68 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl;
69 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl;
72 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
74 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
77 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
79 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
82 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
84 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
88 static void AL_APIENTRY wrap_DeferUpdates(void)
89 { alcSuspendContext(alcGetCurrentContext()); }
90 static void AL_APIENTRY wrap_ProcessUpdates(void)
91 { alcProcessContext(alcGetCurrentContext()); }
94 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
96 DWORD i;
97 for(i = 0; i < buf->nnotify; ++i)
99 DSBPOSITIONNOTIFY *not = &buf->notify[i];
100 HANDLE event = not->hEventNotify;
101 DWORD ofs = not->dwOffset;
103 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
104 continue;
106 /* Wraparound case */
107 if(curpos < lastpos)
109 if(ofs < curpos || ofs >= lastpos)
110 SetEvent(event);
111 continue;
114 /* Normal case */
115 if(ofs >= lastpos && ofs < curpos)
116 SetEvent(event);
120 static void trigger_stop_notifies(DS8Buffer *buf)
122 DWORD i;
123 for(i = 0; i < buf->nnotify; ++i)
125 DSBPOSITIONNOTIFY *not = &buf->notify[i];
126 if(not->dwOffset == (DWORD)DSBPN_OFFSETSTOP)
127 SetEvent(not->hEventNotify);
131 static DWORD CALLBACK DS8Primary_thread(void *dwUser)
133 DS8Primary *prim = (DS8Primary*)dwUser;
134 DWORD i, active_notifies;
135 MSG msg;
137 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
139 TRACE("Primary buffer (%p) message loop start\n", prim);
140 while(GetMessageA(&msg, NULL, 0, 0))
142 if(msg.message != WM_USER)
143 continue;
145 EnterCriticalSection(prim->crst);
146 setALContext(prim->ctx);
148 for(i = 0;i < prim->nnotifies;)
150 DS8Buffer *buf = prim->notifies[i];
151 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
152 DWORD status=0, curpos=buf->lastpos;
154 IDirectSoundBuffer8_GetStatus(dsb, &status);
155 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
156 if(buf->lastpos != curpos)
158 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
159 buf->lastpos = curpos;
161 if(!(status&DSBSTATUS_PLAYING))
163 /* Remove this buffer from list and put another at the
164 * current position; don't increment i
166 trigger_stop_notifies(buf);
167 prim->notifies[i] = prim->notifies[--prim->nnotifies];
168 continue;
170 i++;
172 active_notifies = i;
174 /* OpenAL doesn't support our lovely buffer extensions
175 * so just make sure enough buffers are queued
177 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES] &&
178 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
179 !prim->SupportedExt[EXT_STATIC_BUFFER])
181 for(i = 0;i < prim->nbuffers;++i)
183 DS8Buffer *buf = prim->buffers[i];
184 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
185 ALuint which, ofs;
187 if(buf->buffer->numsegs == 1 || !buf->isplaying)
188 continue;
190 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
191 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
192 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
194 queued -= done;
195 while(done--)
196 alSourceUnqueueBuffers(buf->source, 1, &which);
197 while(queued < QBUFFERS)
199 which = buf->buffer->buffers[buf->curidx];
200 ofs = buf->curidx*buf->buffer->segsize;
201 if(buf->curidx < buf->buffer->numsegs-1)
202 alBufferData(which, buf->buffer->buf_format,
203 buf->buffer->data + ofs, buf->buffer->segsize,
204 buf->buffer->format.Format.nSamplesPerSec);
205 else
206 alBufferData(which, buf->buffer->buf_format,
207 buf->buffer->data + ofs, buf->buffer->lastsegsize,
208 buf->buffer->format.Format.nSamplesPerSec);
210 alSourceQueueBuffers(buf->source, 1, &which);
211 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
212 queued++;
214 if(!buf->curidx && !buf->islooping)
216 buf->isplaying = FALSE;
217 break;
220 if(state != AL_PLAYING)
222 if(!queued)
224 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
225 continue;
227 alSourcePlay(buf->source);
230 checkALError();
232 else if(active_notifies == 0 && prim->timer_id)
234 TRACE("No more notifies, killing timer\n");
235 timeKillEvent(prim->timer_id);
236 prim->timer_id = 0;
237 timeEndPeriod(prim->timer_res);
240 popALContext();
241 LeaveCriticalSection(prim->crst);
243 TRACE("Primary buffer (%p) message loop quit\n", prim);
245 if(prim->timer_id)
247 timeKillEvent(prim->timer_id);
248 prim->timer_id = 0;
249 timeEndPeriod(prim->timer_res);
250 TRACE("Killed timer\n");
253 return 0;
256 static void CALLBACK DS8Primary_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
257 DWORD_PTR dw1, DWORD_PTR dw2)
259 (void)timerID;
260 (void)msg;
261 (void)dw1;
262 (void)dw2;
263 PostThreadMessageA(dwUser, WM_USER, 0, 0);
266 void DS8Primary_starttimer(DS8Primary *prim)
268 DWORD triggertime, res = DS_TIME_RES;
269 ALint refresh = FAKE_REFRESH_COUNT;
270 TIMECAPS time;
272 if(prim->timer_id)
273 return;
275 timeGetDevCaps(&time, sizeof(TIMECAPS));
277 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
278 checkALCError(prim->parent->device);
280 triggertime = 1000 / refresh / 2;
281 if(triggertime < time.wPeriodMin)
282 triggertime = time.wPeriodMin;
283 TRACE("Calling timer every %"LONGFMT"u ms for %i refreshes per second\n", triggertime, refresh);
285 if (res < time.wPeriodMin)
286 res = time.wPeriodMin;
287 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
288 WARN("Could not set minimum resolution, don't expect sound\n");
290 prim->timer_res = res;
291 prim->timer_id = timeSetEvent(triggertime, res, DS8Primary_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
296 HRESULT DS8Primary_PreInit(DS8Primary *This, DS8Impl *parent)
298 DS3DLISTENER *listener;
299 WAVEFORMATEX *wfx;
300 HRESULT hr;
302 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
303 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
304 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
306 This->parent = parent;
307 This->crst = &parent->share->crst;
308 This->ctx = parent->share->ctx;
309 This->SupportedExt = parent->share->SupportedExt;
310 This->ExtAL = &parent->share->ExtAL;
311 This->sources = parent->share->sources;
312 This->auxslot = parent->share->auxslot;
314 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
315 wfx = &This->format.Format;
317 wfx->wFormatTag = WAVE_FORMAT_PCM;
318 wfx->nChannels = 2;
319 wfx->wBitsPerSample = 8;
320 wfx->nSamplesPerSec = 22050;
321 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
322 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
323 wfx->cbSize = 0;
325 This->stopped = TRUE;
327 /* Apparently primary buffer size is always 32k,
328 * tested on windows with 192k 24 bits sound @ 6 channels
329 * where it will run out in 60 ms and it isn't pointer aligned
331 This->buf_size = 32768;
333 if(This->SupportedExt[SOFT_DEFERRED_UPDATES])
335 This->DeferUpdates = This->ExtAL->DeferUpdatesSOFT;
336 This->ProcessUpdates = This->ExtAL->ProcessUpdatesSOFT;
338 else
340 This->DeferUpdates = wrap_DeferUpdates;
341 This->ProcessUpdates = wrap_ProcessUpdates;
344 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
345 if(This->SupportedExt[EXT_EFX] && This->auxslot != 0)
347 ALint revid = alGetEnumValue("AL_EFFECT_REVERB");
348 if(revid != 0 && revid != -1)
350 This->ExtAL->GenEffects(1, &This->effect);
351 This->ExtAL->Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
352 checkALError();
356 /* Make sure DS3DListener defaults are applied to OpenAL */
357 listener = &This->listen;
358 listener->dwSize = sizeof(*listener);
359 listener->vPosition.x = 0.0;
360 listener->vPosition.y = 0.0;
361 listener->vPosition.z = 0.0;
362 listener->vVelocity.x = 0.0;
363 listener->vVelocity.y = 0.0;
364 listener->vVelocity.z = 0.0;
365 listener->vOrientFront.x = 0.0;
366 listener->vOrientFront.y = 0.0;
367 listener->vOrientFront.z = 1.0;
368 listener->vOrientTop.x = 0.0;
369 listener->vOrientTop.y = 1.0;
370 listener->vOrientTop.z = 0.0;
371 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
372 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
373 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
374 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
375 if(FAILED(hr))
376 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
378 This->sizenotifies = This->sizebuffers = parent->share->max_sources;
380 hr = DSERR_OUTOFMEMORY;
381 This->buffers = HeapAlloc(GetProcessHeap(), 0, This->sizebuffers*sizeof(*This->buffers));
382 This->notifies = HeapAlloc(GetProcessHeap(), 0, This->sizenotifies*sizeof(*This->notifies));
383 if(!This->buffers || !This->notifies)
384 goto fail;
386 This->thread_hdl = CreateThread(NULL, 0, DS8Primary_thread, This, 0, &This->thread_id);
387 if(This->thread_hdl == NULL)
388 goto fail;
390 return S_OK;
392 fail:
393 DS8Primary_Clear(This);
394 return hr;
397 void DS8Primary_Clear(DS8Primary *This)
399 TRACE("Clearing primary %p\n", This);
401 if(!This->parent)
402 return;
404 if(This->thread_hdl)
406 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
407 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
409 /* HACK: Apparently, if the device is initialized (thus the primary
410 * buffer has PreInit called) then immediately deleted (the primary
411 * buffer has Clear called), the WM_QUIT message gets sent before
412 * the thread has a chance to run which apparently prevents it from
413 * receiving the message.
414 * If the wait attempt fails, try sending the message again. */
415 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
416 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
417 ERR("Thread wait timed out\n");
419 CloseHandle(This->thread_hdl);
422 setALContext(This->ctx);
423 if(This->effect)
424 This->ExtAL->DeleteEffects(1, &This->effect);
425 popALContext();
426 while(This->nbuffers--)
427 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
429 HeapFree(GetProcessHeap(), 0, This->notifies);
430 HeapFree(GetProcessHeap(), 0, This->buffers);
431 memset(This, 0, sizeof(*This));
434 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
436 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
438 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
440 *ppv = NULL;
441 if(IsEqualIID(riid, &IID_IUnknown) ||
442 IsEqualIID(riid, &IID_IDirectSoundBuffer))
443 *ppv = &This->IDirectSoundBuffer_iface;
444 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
446 if((This->flags&DSBCAPS_CTRL3D))
447 *ppv = &This->IDirectSound3DListener_iface;
449 else
450 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
452 if(*ppv)
454 IUnknown_AddRef((IUnknown*)*ppv);
455 return S_OK;
458 return E_NOINTERFACE;
461 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
463 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
464 LONG ret;
466 ret = InterlockedIncrement(&This->ref);
467 if(ret == 1) This->flags = 0;
469 return ret;
472 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
474 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
475 LONG ret;
477 ret = InterlockedDecrement(&This->ref);
479 return ret;
482 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
484 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
486 TRACE("(%p)->(%p)\n", iface, caps);
488 if(!caps || caps->dwSize < sizeof(*caps))
490 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
491 return DSERR_INVALIDPARAM;
494 EnterCriticalSection(This->crst);
495 caps->dwFlags = This->flags;
496 caps->dwBufferBytes = This->buf_size;
497 caps->dwUnlockTransferRate = 0;
498 caps->dwPlayCpuOverhead = 0;
499 LeaveCriticalSection(This->crst);
501 return DS_OK;
504 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
506 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
507 HRESULT hr = DSERR_PRIOLEVELNEEDED;
509 EnterCriticalSection(This->crst);
510 if(This->write_emu)
511 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
512 LeaveCriticalSection(This->crst);
514 return hr;
517 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
519 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
520 HRESULT hr = S_OK;
521 UINT size;
523 if(!wfx && !written)
525 WARN("Cannot report format or format size\n");
526 return DSERR_INVALIDPARAM;
529 EnterCriticalSection(This->crst);
530 size = sizeof(This->format.Format) + This->format.Format.cbSize;
531 if(written)
532 *written = size;
533 if(wfx)
535 if(allocated < size)
536 hr = DSERR_INVALIDPARAM;
537 else
538 memcpy(wfx, &This->format.Format, size);
540 LeaveCriticalSection(This->crst);
542 return hr;
545 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
547 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
548 ALfloat gain;
550 TRACE("(%p)->(%p)\n", iface, volume);
552 if(!volume)
553 return DSERR_INVALIDPARAM;
554 *volume = 0;
556 if(!(This->flags&DSBCAPS_CTRLVOLUME))
557 return DSERR_CONTROLUNAVAIL;
559 setALContext(This->ctx);
560 alGetListenerf(AL_GAIN, &gain);
561 checkALError();
562 popALContext();
564 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
565 return DS_OK;
568 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
570 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
571 HRESULT hr = DS_OK;
573 WARN("(%p)->(%p): semi-stub\n", iface, pan);
575 if(!pan)
576 return DSERR_INVALIDPARAM;
578 EnterCriticalSection(This->crst);
579 if(This->write_emu)
580 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
581 else if(!(This->flags & DSBCAPS_CTRLPAN))
582 hr = DSERR_CONTROLUNAVAIL;
583 else
584 *pan = 0;
585 LeaveCriticalSection(This->crst);
587 return hr;
590 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
592 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
593 HRESULT hr = DS_OK;
595 WARN("(%p)->(%p): semi-stub\n", iface, freq);
597 if(!freq)
598 return DSERR_INVALIDPARAM;
600 if(!(This->flags&DSBCAPS_CTRLFREQUENCY))
601 return DSERR_CONTROLUNAVAIL;
603 EnterCriticalSection(This->crst);
604 *freq = This->format.Format.nSamplesPerSec;
605 LeaveCriticalSection(This->crst);
607 return hr;
610 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
612 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
614 TRACE("(%p)->(%p)\n", iface, status);
616 if(!status)
617 return DSERR_INVALIDPARAM;
619 EnterCriticalSection(This->crst);
620 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
621 if((This->flags&DSBCAPS_LOCDEFER))
622 *status |= DSBSTATUS_LOCHARDWARE;
624 if(This->stopped)
626 DWORD i, state;
627 HRESULT hr;
629 for(i = 0;i < This->nbuffers;++i)
631 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
632 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
633 break;
635 if(i == This->nbuffers)
637 /* Primary stopped and no buffers playing.. */
638 *status = 0;
641 LeaveCriticalSection(This->crst);
643 return DS_OK;
646 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
648 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
649 HRESULT hr;
651 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
653 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
655 WARN("Bad DSBDESC for primary buffer\n");
656 return DSERR_INVALIDPARAM;
658 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
659 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
660 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
662 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
663 return DSERR_INVALIDPARAM;
666 /* Should be 0 if not initialized */
667 if(This->flags)
668 return DSERR_ALREADYINITIALIZED;
670 hr = DS_OK;
671 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
673 DSBUFFERDESC emudesc;
674 DS8Buffer *emu;
676 if(This->write_emu)
678 ERR("There shouldn't be a write_emu!\n");
679 IDirectSoundBuffer8_Release(This->write_emu);
680 This->write_emu = NULL;
683 memset(&emudesc, 0, sizeof(emudesc));
684 emudesc.dwSize = sizeof(emudesc);
685 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
686 /* Dont play last incomplete sample */
687 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
688 emudesc.lpwfxFormat = &This->format.Format;
690 hr = DS8Buffer_Create(&emu, This, NULL);
691 if(SUCCEEDED(hr))
693 This->write_emu = &emu->IDirectSoundBuffer8_iface;
694 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
695 if(FAILED(hr))
697 IDirectSoundBuffer8_Release(This->write_emu);
698 This->write_emu = NULL;
703 if(SUCCEEDED(hr))
704 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
705 return hr;
708 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
710 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
711 HRESULT hr = DSERR_PRIOLEVELNEEDED;
713 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
715 EnterCriticalSection(This->crst);
716 if(This->write_emu)
717 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
718 LeaveCriticalSection(This->crst);
720 return hr;
723 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
725 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
726 HRESULT hr;
728 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
730 if(!(flags & DSBPLAY_LOOPING))
732 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
733 return DSERR_INVALIDPARAM;
736 EnterCriticalSection(This->crst);
737 hr = S_OK;
738 if(This->write_emu)
739 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
740 if(SUCCEEDED(hr))
741 This->stopped = FALSE;
742 LeaveCriticalSection(This->crst);
744 return hr;
747 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
749 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
750 return DSERR_INVALIDCALL;
753 /* Just assume the format is crap, and clean up the damage */
754 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
756 if(from->wFormatTag == WAVE_FORMAT_PCM)
758 wfx->cbSize = 0;
759 if(from->wBitsPerSample == 8 ||
760 from->wBitsPerSample == 16 ||
761 from->wBitsPerSample == 24 ||
762 from->wBitsPerSample == 32)
763 wfx->wBitsPerSample = from->wBitsPerSample;
765 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
767 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
768 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
769 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
771 /* Fail silently.. */
772 if(from->cbSize < size)
773 return;
774 if(!fromx->Samples.wValidBitsPerSample &&
775 !fromx->Format.wBitsPerSample)
776 return;
778 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
779 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
781 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
782 return;
785 wfe->Format.wBitsPerSample = from->wBitsPerSample;
786 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
787 if(!wfe->Samples.wValidBitsPerSample)
788 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
789 wfe->Format.cbSize = size;
790 wfe->dwChannelMask = fromx->dwChannelMask;
791 wfe->SubFormat = fromx->SubFormat;
793 else
795 ERR("Unhandled format tag %04x\n", from->wFormatTag);
796 return;
799 if(from->nChannels)
800 wfx->nChannels = from->nChannels;
801 wfx->wFormatTag = from->wFormatTag;
802 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
803 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
804 wfx->nSamplesPerSec = from->nSamplesPerSec;
805 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
806 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
809 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
811 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
812 HRESULT hr = S_OK;
813 ALCint freq;
815 TRACE("(%p)->(%p)\n", iface, wfx);
817 if(!wfx)
819 WARN("Missing format\n");
820 return DSERR_INVALIDPARAM;
823 EnterCriticalSection(This->crst);
825 if(This->parent->prio_level < DSSCL_PRIORITY)
827 hr = DSERR_PRIOLEVELNEEDED;
828 goto out;
831 TRACE("Requested primary format:\n"
832 " FormatTag = %04x\n"
833 " Channels = %u\n"
834 " SamplesPerSec = %"LONGFMT"u\n"
835 " AvgBytesPerSec = %"LONGFMT"u\n"
836 " BlockAlign = %u\n"
837 " BitsPerSample = %u\n",
838 wfx->wFormatTag, wfx->nChannels,
839 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
840 wfx->nBlockAlign, wfx->wBitsPerSample);
842 copy_waveformat(&This->format.Format, wfx);
844 freq = This->format.Format.nSamplesPerSec;
845 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
846 checkALCError(This->parent->device);
848 This->format.Format.nSamplesPerSec = freq;
849 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
850 This->format.Format.nSamplesPerSec;
852 if(This->write_emu)
854 DS8Buffer *buf;
855 DSBUFFERDESC desc;
857 memset(&desc, 0, sizeof(desc));
858 desc.dwSize = sizeof(desc);
859 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
860 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
861 desc.lpwfxFormat = &This->format.Format;
863 hr = DS8Buffer_Create(&buf, This, NULL);
864 if(FAILED(hr))
865 goto out;
867 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
868 if(FAILED(hr))
869 DS8Buffer_Destroy(buf);
870 else
872 IDirectSoundBuffer8_Release(This->write_emu);
873 This->write_emu = &buf->IDirectSoundBuffer8_iface;
877 out:
878 LeaveCriticalSection(This->crst);
879 return hr;
882 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
884 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
886 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
888 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
890 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
891 return DSERR_INVALIDPARAM;
894 if(!(This->flags&DSBCAPS_CTRLVOLUME))
895 return DSERR_CONTROLUNAVAIL;
897 setALContext(This->ctx);
898 alListenerf(AL_GAIN, mB_to_gain(vol));
899 popALContext();
901 return DS_OK;
904 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
906 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
907 HRESULT hr;
909 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
911 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
913 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
914 return DSERR_INVALIDPARAM;
917 EnterCriticalSection(This->crst);
918 if(!(This->flags&DSBCAPS_CTRLPAN))
920 WARN("control unavailable\n");
921 hr = DSERR_CONTROLUNAVAIL;
923 else if(This->write_emu)
924 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
925 else
927 FIXME("Not supported\n");
928 hr = E_NOTIMPL;
930 LeaveCriticalSection(This->crst);
932 return hr;
935 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
937 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
938 return DSERR_CONTROLUNAVAIL;
941 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
943 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
944 HRESULT hr = S_OK;
946 TRACE("(%p)->()\n", iface);
948 EnterCriticalSection(This->crst);
949 if(This->write_emu)
950 hr = IDirectSoundBuffer8_Stop(This->write_emu);
951 if(SUCCEEDED(hr))
952 This->stopped = TRUE;
953 LeaveCriticalSection(This->crst);
955 return hr;
958 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
960 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
961 HRESULT hr = DSERR_INVALIDCALL;
963 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
965 EnterCriticalSection(This->crst);
966 if(This->write_emu)
967 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
968 LeaveCriticalSection(This->crst);
970 return hr;
973 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
975 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
976 HRESULT hr = S_OK;
978 TRACE("(%p)->()\n", iface);
980 EnterCriticalSection(This->crst);
981 if(This->write_emu)
982 hr = IDirectSoundBuffer8_Restore(This->write_emu);
983 LeaveCriticalSection(This->crst);
985 return hr;
988 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
990 DS8Primary_QueryInterface,
991 DS8Primary_AddRef,
992 DS8Primary_Release,
993 DS8Primary_GetCaps,
994 DS8Primary_GetCurrentPosition,
995 DS8Primary_GetFormat,
996 DS8Primary_GetVolume,
997 DS8Primary_GetPan,
998 DS8Primary_GetFrequency,
999 DS8Primary_GetStatus,
1000 DS8Primary_Initialize,
1001 DS8Primary_Lock,
1002 DS8Primary_Play,
1003 DS8Primary_SetCurrentPosition,
1004 DS8Primary_SetFormat,
1005 DS8Primary_SetVolume,
1006 DS8Primary_SetPan,
1007 DS8Primary_SetFrequency,
1008 DS8Primary_Stop,
1009 DS8Primary_Unlock,
1010 DS8Primary_Restore
1014 static void DS8Primary_SetParams(DS8Primary *This, const DS3DLISTENER *params, LONG flags)
1016 union PrimaryParamFlags dirty = { flags };
1017 DWORD i;
1019 if(dirty.bit.pos)
1020 alListener3f(AL_POSITION, params->vPosition.x, params->vPosition.y,
1021 -params->vPosition.z);
1022 if(dirty.bit.vel)
1023 alListener3f(AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1024 -params->vVelocity.z);
1025 if(dirty.bit.orientation)
1027 ALfloat orient[6] = {
1028 params->vOrientFront.x, params->vOrientFront.y, -params->vOrientFront.z,
1029 params->vOrientTop.x, params->vOrientTop.y, -params->vOrientTop.z
1031 alListenerfv(AL_ORIENTATION, orient);
1033 if(dirty.bit.distancefactor)
1035 alSpeedOfSound(343.3f/params->flDistanceFactor);
1036 if(This->SupportedExt[EXT_EFX])
1037 alListenerf(AL_METERS_PER_UNIT, params->flDistanceFactor);
1039 if(dirty.bit.rollofffactor)
1041 ALfloat rolloff = params->flRolloffFactor;
1042 This->rollofffactor = rolloff;
1043 for(i = 0;i < This->nbuffers;++i)
1045 const DS8Buffer *buf = This->buffers[i];
1046 if(buf->ds3dmode != DS3DMODE_DISABLE)
1047 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1050 if(dirty.bit.dopplerfactor)
1051 alDopplerFactor(params->flDopplerFactor);
1052 if(dirty.bit.effect)
1053 This->ExtAL->AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1056 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1058 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1059 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1062 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1064 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1065 LONG ret;
1067 ret = InterlockedIncrement(&This->ds3d_ref);
1068 TRACE("new refcount %"LONGFMT"d\n", ret);
1070 return ret;
1073 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1075 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1076 LONG ret;
1078 ret = InterlockedDecrement(&This->ds3d_ref);
1079 TRACE("new refcount %"LONGFMT"d\n", ret);
1081 return ret;
1085 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1087 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1089 TRACE("(%p)->(%p)\n", iface, listener);
1091 if(!listener || listener->dwSize < sizeof(*listener))
1093 WARN("Invalid DS3DLISTENER %p %"LONGFMT"u\n", listener, listener ? listener->dwSize : 0);
1094 return DSERR_INVALIDPARAM;
1097 EnterCriticalSection(This->crst);
1098 setALContext(This->ctx);
1099 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1100 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1101 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1102 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1103 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1104 IDirectSound3DListener_GetDopplerFactor(iface, &listener->flDopplerFactor);
1105 popALContext();
1106 LeaveCriticalSection(This->crst);
1108 return DS_OK;
1111 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1113 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1115 TRACE("(%p)->(%p)\n", iface, distancefactor);
1117 if(!distancefactor)
1119 WARN("Invalid parameter %p\n", distancefactor);
1120 return DSERR_INVALIDPARAM;
1123 setALContext(This->ctx);
1124 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1125 checkALError();
1126 popALContext();
1128 return S_OK;
1131 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1133 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1135 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1137 if(!dopplerfactor)
1139 WARN("Invalid parameter %p\n", dopplerfactor);
1140 return DSERR_INVALIDPARAM;
1143 setALContext(This->ctx);
1144 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1145 checkALError();
1146 popALContext();
1148 return S_OK;
1151 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1153 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1154 ALfloat orient[6];
1156 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1158 if(!front || !top)
1160 WARN("Invalid parameter %p %p\n", front, top);
1161 return DSERR_INVALIDPARAM;
1164 setALContext(This->ctx);
1165 alGetListenerfv(AL_ORIENTATION, orient);
1166 checkALError();
1167 popALContext();
1169 front->x = orient[0];
1170 front->y = orient[1];
1171 front->z = -orient[2];
1172 top->x = orient[3];
1173 top->y = orient[4];
1174 top->z = -orient[5];
1175 return S_OK;
1178 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1180 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1181 ALfloat alpos[3];
1183 TRACE("(%p)->(%p)\n", iface, pos);
1185 if(!pos)
1187 WARN("Invalid parameter %p\n", pos);
1188 return DSERR_INVALIDPARAM;
1191 setALContext(This->ctx);
1192 alGetListenerfv(AL_POSITION, alpos);
1193 checkALError();
1194 popALContext();
1196 pos->x = alpos[0];
1197 pos->y = alpos[1];
1198 pos->z = -alpos[2];
1199 return S_OK;
1202 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1204 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1206 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1208 if(!rollofffactor)
1210 WARN("Invalid parameter %p\n", rollofffactor);
1211 return DSERR_INVALIDPARAM;
1214 EnterCriticalSection(This->crst);
1215 *rollofffactor = This->rollofffactor;
1216 LeaveCriticalSection(This->crst);
1218 return S_OK;
1221 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1223 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1224 ALfloat vel[3];
1226 TRACE("(%p)->(%p)\n", iface, velocity);
1228 if(!velocity)
1230 WARN("Invalid parameter %p\n", velocity);
1231 return DSERR_INVALIDPARAM;
1234 setALContext(This->ctx);
1235 alGetListenerfv(AL_VELOCITY, vel);
1236 checkALError();
1237 popALContext();
1239 velocity->x = vel[0];
1240 velocity->y = vel[1];
1241 velocity->z = -vel[2];
1242 return S_OK;
1245 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1247 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1249 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, listen, apply);
1251 if(!listen || listen->dwSize < sizeof(*listen))
1253 WARN("Invalid parameter %p %"LONGFMT"u\n", listen, listen ? listen->dwSize : 0);
1254 return DSERR_INVALIDPARAM;
1257 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1258 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1260 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1261 return DSERR_INVALIDPARAM;
1264 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1265 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1267 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1268 return DSERR_INVALIDPARAM;
1271 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1272 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1274 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1275 return DSERR_INVALIDPARAM;
1278 if(apply == DS3D_DEFERRED)
1280 EnterCriticalSection(This->crst);
1281 This->listen = *listen;
1282 This->listen.dwSize = sizeof(This->listen);
1283 This->dirty.bit.pos = 1;
1284 This->dirty.bit.vel = 1;
1285 This->dirty.bit.orientation = 1;
1286 This->dirty.bit.distancefactor = 1;
1287 This->dirty.bit.rollofffactor = 1;
1288 This->dirty.bit.dopplerfactor = 1;
1289 LeaveCriticalSection(This->crst);
1291 else
1293 union PrimaryParamFlags dirty = { 0l };
1294 dirty.bit.pos = 1;
1295 dirty.bit.vel = 1;
1296 dirty.bit.orientation = 1;
1297 dirty.bit.distancefactor = 1;
1298 dirty.bit.rollofffactor = 1;
1299 dirty.bit.dopplerfactor = 1;
1301 EnterCriticalSection(This->crst);
1302 setALContext(This->ctx);
1303 DS8Primary_SetParams(This, listen, dirty.flags);
1304 popALContext();
1305 LeaveCriticalSection(This->crst);
1308 return S_OK;
1311 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1313 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1315 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1317 if(factor < DS3D_MINDISTANCEFACTOR ||
1318 factor > DS3D_MAXDISTANCEFACTOR)
1320 WARN("Invalid parameter %f\n", factor);
1321 return DSERR_INVALIDPARAM;
1324 if(apply == DS3D_DEFERRED)
1326 EnterCriticalSection(This->crst);
1327 This->listen.flDistanceFactor = factor;
1328 This->dirty.bit.distancefactor = 1;
1329 LeaveCriticalSection(This->crst);
1331 else
1333 setALContext(This->ctx);
1334 alSpeedOfSound(343.3f/factor);
1335 if(This->SupportedExt[EXT_EFX])
1336 alListenerf(AL_METERS_PER_UNIT, factor);
1337 checkALError();
1338 popALContext();
1341 return S_OK;
1344 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1346 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1348 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1350 if(factor < DS3D_MINDOPPLERFACTOR ||
1351 factor > DS3D_MAXDOPPLERFACTOR)
1353 WARN("Invalid parameter %f\n", factor);
1354 return DSERR_INVALIDPARAM;
1357 if(apply == DS3D_DEFERRED)
1359 EnterCriticalSection(This->crst);
1360 This->listen.flDopplerFactor = factor;
1361 This->dirty.bit.dopplerfactor = 1;
1362 LeaveCriticalSection(This->crst);
1364 else
1366 setALContext(This->ctx);
1367 alDopplerFactor(factor);
1368 checkALError();
1369 popALContext();
1372 return S_OK;
1375 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1377 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1379 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT"u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1381 if(apply == DS3D_DEFERRED)
1383 EnterCriticalSection(This->crst);
1384 This->listen.vOrientFront.x = xFront;
1385 This->listen.vOrientFront.y = yFront;
1386 This->listen.vOrientFront.z = zFront;
1387 This->listen.vOrientTop.x = xTop;
1388 This->listen.vOrientTop.y = yTop;
1389 This->listen.vOrientTop.z = zTop;
1390 This->dirty.bit.orientation = 1;
1391 LeaveCriticalSection(This->crst);
1393 else
1395 ALfloat orient[6] = {
1396 xFront, yFront, -zFront,
1397 xTop, yTop, -zTop
1399 setALContext(This->ctx);
1400 alListenerfv(AL_ORIENTATION, orient);
1401 checkALError();
1402 popALContext();
1405 return S_OK;
1408 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1410 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1412 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1414 if(apply == DS3D_DEFERRED)
1416 EnterCriticalSection(This->crst);
1417 This->listen.vPosition.x = x;
1418 This->listen.vPosition.y = y;
1419 This->listen.vPosition.z = z;
1420 This->dirty.bit.pos = 1;
1421 LeaveCriticalSection(This->crst);
1423 else
1425 setALContext(This->ctx);
1426 alListener3f(AL_POSITION, x, y, -z);
1427 checkALError();
1428 popALContext();
1431 return S_OK;
1434 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1436 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1438 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1440 if(factor < DS3D_MINROLLOFFFACTOR ||
1441 factor > DS3D_MAXROLLOFFFACTOR)
1443 WARN("Invalid parameter %f\n", factor);
1444 return DSERR_INVALIDPARAM;
1447 EnterCriticalSection(This->crst);
1448 if(apply == DS3D_DEFERRED)
1450 This->listen.flRolloffFactor = factor;
1451 This->dirty.bit.rollofffactor = 1;
1453 else
1455 DWORD i;
1457 setALContext(This->ctx);
1458 for(i = 0;i < This->nbuffers;++i)
1460 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1461 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1463 checkALError();
1464 popALContext();
1466 This->rollofffactor = factor;
1468 LeaveCriticalSection(This->crst);
1470 return S_OK;
1473 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1475 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1477 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1479 if(apply == DS3D_DEFERRED)
1481 EnterCriticalSection(This->crst);
1482 This->listen.vVelocity.x = x;
1483 This->listen.vVelocity.y = y;
1484 This->listen.vVelocity.z = z;
1485 This->dirty.bit.vel = 1;
1486 LeaveCriticalSection(This->crst);
1488 else
1490 setALContext(This->ctx);
1491 alListener3f(AL_VELOCITY, x, y, -z);
1492 checkALError();
1493 popALContext();
1496 return S_OK;
1499 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1501 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1502 LONG flags;
1503 DWORD i;
1505 EnterCriticalSection(This->crst);
1506 setALContext(This->ctx);
1507 This->DeferUpdates();
1509 if((flags=InterlockedExchange(&This->dirty.flags, 0)) != 0)
1511 DS8Primary_SetParams(This, &This->listen, flags);
1512 /* checkALError is here for debugging */
1513 checkALError();
1515 TRACE("Dirty flags was: 0x%02x\n", flags);
1517 for(i = 0;i < This->nbuffers;++i)
1519 DS8Buffer *buf = This->buffers[i];
1521 if((flags=InterlockedExchange(&buf->dirty.flags, 0)) != 0)
1522 DS8Buffer_SetParams(buf, &buf->ds3dbuffer, flags);
1524 checkALError();
1526 This->ProcessUpdates();
1527 popALContext();
1528 LeaveCriticalSection(This->crst);
1530 return DS_OK;
1533 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1535 DS8Primary3D_QueryInterface,
1536 DS8Primary3D_AddRef,
1537 DS8Primary3D_Release,
1538 DS8Primary3D_GetAllParameters,
1539 DS8Primary3D_GetDistanceFactor,
1540 DS8Primary3D_GetDopplerFactor,
1541 DS8Primary3D_GetOrientation,
1542 DS8Primary3D_GetPosition,
1543 DS8Primary3D_GetRolloffFactor,
1544 DS8Primary3D_GetVelocity,
1545 DS8Primary3D_SetAllParameters,
1546 DS8Primary3D_SetDistanceFactor,
1547 DS8Primary3D_SetDopplerFactor,
1548 DS8Primary3D_SetOrientation,
1549 DS8Primary3D_SetPosition,
1550 DS8Primary3D_SetRolloffFactor,
1551 DS8Primary3D_SetVelocity,
1552 DS8Primary3D_CommitDeferredSettings
1555 /* NOTE: Although the app handles listener properties through secondary buffers,
1556 * we pass the requests to the primary buffer though a propertyset interface.
1557 * These methods are not exposed to the app. */
1558 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1560 DS8Primary *This = impl_from_IKsPropertySet(iface);
1561 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1564 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1566 DS8Primary *This = impl_from_IKsPropertySet(iface);
1567 LONG ret;
1569 ret = InterlockedIncrement(&This->prop_ref);
1570 TRACE("new refcount %"LONGFMT"d\n", ret);
1572 return ret;
1575 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1577 DS8Primary *This = impl_from_IKsPropertySet(iface);
1578 LONG ret;
1580 ret = InterlockedDecrement(&This->prop_ref);
1581 TRACE("new refcount %"LONGFMT"d\n", ret);
1583 return ret;
1586 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1587 REFGUID guidPropSet, ULONG dwPropID,
1588 LPVOID pInstanceData, ULONG cbInstanceData,
1589 LPVOID pPropData, ULONG cbPropData,
1590 PULONG pcbReturned)
1592 DS8Primary *This = impl_from_IKsPropertySet(iface);
1593 HRESULT res = E_PROP_ID_UNSUPPORTED;
1594 (void)pInstanceData;
1595 (void)cbInstanceData;
1597 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1599 EnterCriticalSection(This->crst);
1601 if(This->effect == 0)
1602 res = E_PROP_ID_UNSUPPORTED;
1603 else switch(dwPropID)
1605 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1606 res = DSERR_INVALIDPARAM;
1607 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1609 union {
1610 void *v;
1611 EAXLISTENERPROPERTIES *props;
1612 } data = { pPropData };
1614 *data.props = This->eax_prop;
1615 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1616 res = DS_OK;
1618 break;
1620 case DSPROPERTY_EAXLISTENER_ROOM:
1621 res = DSERR_INVALIDPARAM;
1622 if(cbPropData >= sizeof(LONG))
1624 union {
1625 void *v;
1626 LONG *l;
1627 } data = { pPropData };
1629 *data.l = This->eax_prop.lRoom;
1630 *pcbReturned = sizeof(LONG);
1631 res = DS_OK;
1633 break;
1634 case DSPROPERTY_EAXLISTENER_ROOMHF:
1635 res = DSERR_INVALIDPARAM;
1636 if(cbPropData >= sizeof(LONG))
1638 union {
1639 void *v;
1640 LONG *l;
1641 } data = { pPropData };
1643 *data.l = This->eax_prop.lRoomHF;
1644 *pcbReturned = sizeof(LONG);
1645 res = DS_OK;
1647 break;
1649 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1650 res = DSERR_INVALIDPARAM;
1651 if(cbPropData >= sizeof(FLOAT))
1653 union {
1654 void *v;
1655 FLOAT *fl;
1656 } data = { pPropData };
1658 *data.fl = This->eax_prop.flRoomRolloffFactor;
1659 *pcbReturned = sizeof(FLOAT);
1660 res = DS_OK;
1662 break;
1664 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1665 res = DSERR_INVALIDPARAM;
1666 if(cbPropData >= sizeof(DWORD))
1668 union {
1669 void *v;
1670 DWORD *dw;
1671 } data = { pPropData };
1673 *data.dw = This->eax_prop.dwEnvironment;
1674 *pcbReturned = sizeof(DWORD);
1675 res = DS_OK;
1677 break;
1679 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1680 res = DSERR_INVALIDPARAM;
1681 if(cbPropData >= sizeof(FLOAT))
1683 union {
1684 void *v;
1685 FLOAT *fl;
1686 } data = { pPropData };
1688 *data.fl = This->eax_prop.flEnvironmentSize;
1689 *pcbReturned = sizeof(FLOAT);
1690 res = DS_OK;
1692 break;
1693 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1694 res = DSERR_INVALIDPARAM;
1695 if(cbPropData >= sizeof(FLOAT))
1697 union {
1698 void *v;
1699 FLOAT *fl;
1700 } data = { pPropData };
1702 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1703 *pcbReturned = sizeof(FLOAT);
1704 res = DS_OK;
1706 break;
1708 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1709 res = DSERR_INVALIDPARAM;
1710 if(cbPropData >= sizeof(FLOAT))
1712 union {
1713 void *v;
1714 FLOAT *fl;
1715 } data = { pPropData };
1717 *data.fl = This->eax_prop.flAirAbsorptionHF;
1718 *pcbReturned = sizeof(FLOAT);
1719 res = DS_OK;
1721 break;
1723 case DSPROPERTY_EAXLISTENER_FLAGS:
1724 res = DSERR_INVALIDPARAM;
1725 if(cbPropData >= sizeof(DWORD))
1727 union {
1728 void *v;
1729 DWORD *dw;
1730 } data = { pPropData };
1732 *data.dw = This->eax_prop.dwFlags;
1733 *pcbReturned = sizeof(DWORD);
1734 res = DS_OK;
1736 break;
1738 default:
1739 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1740 break;
1743 LeaveCriticalSection(This->crst);
1745 else
1746 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1748 return res;
1751 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1752 REFGUID guidPropSet, ULONG dwPropID,
1753 LPVOID pInstanceData, ULONG cbInstanceData,
1754 LPVOID pPropData, ULONG cbPropData)
1756 DS8Primary *This = impl_from_IKsPropertySet(iface);
1757 HRESULT res = E_PROP_ID_UNSUPPORTED;
1758 (void)pInstanceData;
1759 (void)cbInstanceData;
1761 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1763 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1764 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1766 EnterCriticalSection(This->crst);
1767 setALContext(This->ctx);
1769 if(This->effect == 0)
1770 res = E_PROP_ID_UNSUPPORTED;
1771 else switch(propid)
1773 case 0: /* 0 = not setting any property, just apply */
1774 res = DS_OK;
1775 break;
1777 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1778 do_allparams:
1779 res = DSERR_INVALIDPARAM;
1780 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1782 union {
1783 const void *v;
1784 const EAXLISTENERPROPERTIES *props;
1785 } data = { pPropData };
1787 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1788 This->eax_prop = *data.props;
1789 This->ExtAL->Effectf(This->effect, AL_REVERB_DENSITY,
1790 (data.props->flEnvironmentSize < 2.0f) ?
1791 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1792 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1793 data.props->flEnvironmentDiffusion);
1795 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1796 mB_to_gain(data.props->lRoom));
1797 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1798 mB_to_gain(data.props->lRoomHF));
1800 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1801 data.props->flRoomRolloffFactor);
1803 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_TIME,
1804 data.props->flDecayTime);
1805 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1806 data.props->flDecayHFRatio);
1808 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1809 mB_to_gain(data.props->lReflections));
1810 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1811 data.props->flReflectionsDelay);
1813 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1814 mB_to_gain(data.props->lReverb));
1815 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1816 data.props->flReverbDelay);
1818 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1819 mB_to_gain(data.props->flAirAbsorptionHF));
1821 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1822 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1823 AL_TRUE : AL_FALSE);
1825 checkALError();
1827 This->dirty.bit.effect = 1;
1828 res = DS_OK;
1830 break;
1832 case DSPROPERTY_EAXLISTENER_ROOM:
1833 res = DSERR_INVALIDPARAM;
1834 if(cbPropData >= sizeof(LONG))
1836 union {
1837 const void *v;
1838 const LONG *l;
1839 } data = { pPropData };
1841 This->eax_prop.lRoom = *data.l;
1842 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1843 mB_to_gain(This->eax_prop.lRoom));
1844 checkALError();
1846 This->dirty.bit.effect = 1;
1847 res = DS_OK;
1849 break;
1850 case DSPROPERTY_EAXLISTENER_ROOMHF:
1851 res = DSERR_INVALIDPARAM;
1852 if(cbPropData >= sizeof(LONG))
1854 union {
1855 const void *v;
1856 const LONG *l;
1857 } data = { pPropData };
1859 This->eax_prop.lRoomHF = *data.l;
1860 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1861 mB_to_gain(This->eax_prop.lRoomHF));
1862 checkALError();
1864 This->dirty.bit.effect = 1;
1865 res = DS_OK;
1867 break;
1869 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1870 res = DSERR_INVALIDPARAM;
1871 if(cbPropData >= sizeof(FLOAT))
1873 union {
1874 const void *v;
1875 const FLOAT *fl;
1876 } data = { pPropData };
1878 This->eax_prop.flRoomRolloffFactor = *data.fl;
1879 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1880 This->eax_prop.flRoomRolloffFactor);
1881 checkALError();
1883 This->dirty.bit.effect = 1;
1884 res = DS_OK;
1886 break;
1888 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1889 res = DSERR_INVALIDPARAM;
1890 if(cbPropData >= sizeof(DWORD))
1892 union {
1893 const void *v;
1894 const DWORD *dw;
1895 } data = { pPropData };
1897 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1899 /* Get the environment index's default and pass it down to
1900 * ALLPARAMETERS */
1901 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1902 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1903 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1904 goto do_allparams;
1907 break;
1909 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1910 res = DSERR_INVALIDPARAM;
1911 if(cbPropData >= sizeof(FLOAT))
1913 union {
1914 const void *v;
1915 const FLOAT *fl;
1916 } data = { pPropData };
1918 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1920 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1922 This->eax_prop.flEnvironmentSize = *data.fl;
1924 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1926 This->eax_prop.flDecayTime *= scale;
1927 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1929 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1931 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1932 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1934 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1936 This->eax_prop.flReflectionsDelay *= scale;
1937 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1939 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1941 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1942 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1944 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1946 This->eax_prop.flReverbDelay *= scale;
1947 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1950 /* Pass the updated environment properties down to ALLPARAMETERS */
1951 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1952 pPropData = (void*)&This->eax_prop;
1953 cbPropData = sizeof(This->eax_prop);
1954 goto do_allparams;
1957 break;
1958 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
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.flEnvironmentDiffusion = *data.fl;
1968 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1969 This->eax_prop.flEnvironmentDiffusion);
1970 checkALError();
1972 This->dirty.bit.effect = 1;
1973 res = DS_OK;
1975 break;
1977 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1978 res = DSERR_INVALIDPARAM;
1979 if(cbPropData >= sizeof(FLOAT))
1981 union {
1982 const void *v;
1983 const FLOAT *fl;
1984 } data = { pPropData };
1986 This->eax_prop.flAirAbsorptionHF = *data.fl;
1987 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1988 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
1989 checkALError();
1991 This->dirty.bit.effect = 1;
1992 res = DS_OK;
1994 break;
1996 case DSPROPERTY_EAXLISTENER_FLAGS:
1997 res = DSERR_INVALIDPARAM;
1998 if(cbPropData >= sizeof(DWORD))
2000 union {
2001 const void *v;
2002 const DWORD *dw;
2003 } data = { pPropData };
2005 This->eax_prop.dwFlags = *data.dw;
2006 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2007 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2008 AL_TRUE : AL_FALSE);
2009 checkALError();
2011 This->dirty.bit.effect = 1;
2012 res = DS_OK;
2014 break;
2016 default:
2017 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
2018 break;
2021 if(res == DS_OK && immediate)
2022 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2024 popALContext();
2025 LeaveCriticalSection(This->crst);
2027 else
2028 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2030 return res;
2033 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2034 REFGUID guidPropSet, ULONG dwPropID,
2035 PULONG pTypeSupport)
2037 DS8Primary *This = impl_from_IKsPropertySet(iface);
2038 HRESULT res = E_PROP_ID_UNSUPPORTED;
2040 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2042 EnterCriticalSection(This->crst);
2044 if(This->effect == 0)
2045 res = E_PROP_ID_UNSUPPORTED;
2046 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2047 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2048 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2049 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2050 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2051 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2052 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2053 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2054 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2056 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2057 res = DS_OK;
2059 else
2060 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2062 LeaveCriticalSection(This->crst);
2064 else
2065 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2067 return res;
2070 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2072 DS8PrimaryProp_QueryInterface,
2073 DS8PrimaryProp_AddRef,
2074 DS8PrimaryProp_Release,
2075 DS8PrimaryProp_Get,
2076 DS8PrimaryProp_Set,
2077 DS8PrimaryProp_QuerySupport