Trace some playback notification information
[dsound-openal.git] / primary.c
bloba6ab2b9f6f61386c04c9786e9c705daf7b45c77e
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)
111 TRACE("Triggering notification %"LONGFMT"u (%"LONGFMT"u) from buffer %p\n", i, ofs, buf);
112 SetEvent(event);
114 continue;
117 /* Normal case */
118 if(ofs >= lastpos && ofs < curpos)
120 TRACE("Triggering notification %"LONGFMT"u (%"LONGFMT"u) from buffer %p\n", i, ofs, buf);
121 SetEvent(event);
126 static void trigger_stop_notifies(DS8Buffer *buf)
128 DWORD i;
129 for(i = 0; i < buf->nnotify; ++i)
131 DSBPOSITIONNOTIFY *not = &buf->notify[i];
132 if(not->dwOffset == (DWORD)DSBPN_OFFSETSTOP)
134 TRACE("Triggering notification %"LONGFMT"u from buffer %p\n", i, buf);
135 SetEvent(not->hEventNotify);
140 static DWORD CALLBACK DS8Primary_thread(void *dwUser)
142 DS8Primary *prim = (DS8Primary*)dwUser;
143 DWORD i, active_notifies;
144 MSG msg;
146 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
148 TRACE("Primary buffer (%p) message loop start\n", prim);
149 while(GetMessageA(&msg, NULL, 0, 0))
151 if(msg.message != WM_USER)
152 continue;
154 EnterCriticalSection(prim->crst);
155 setALContext(prim->ctx);
157 for(i = 0;i < prim->nnotifies;)
159 DS8Buffer *buf = prim->notifies[i];
160 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
161 DWORD status=0, curpos=buf->lastpos;
163 IDirectSoundBuffer8_GetStatus(dsb, &status);
164 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
165 if(buf->lastpos != curpos)
167 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
168 buf->lastpos = curpos;
170 if(!(status&DSBSTATUS_PLAYING))
172 /* Remove this buffer from list and put another at the
173 * current position; don't increment i
175 trigger_stop_notifies(buf);
176 prim->notifies[i] = prim->notifies[--prim->nnotifies];
177 continue;
179 i++;
181 active_notifies = i;
183 /* OpenAL doesn't support our lovely buffer extensions
184 * so just make sure enough buffers are queued
186 if(!prim->SupportedExt[SOFT_BUFFER_SAMPLES] &&
187 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
188 !prim->SupportedExt[EXT_STATIC_BUFFER])
190 for(i = 0;i < prim->nbuffers;++i)
192 DS8Buffer *buf = prim->buffers[i];
193 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
194 ALuint which, ofs;
196 if(buf->buffer->numsegs == 1 || !buf->isplaying)
197 continue;
199 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
200 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
201 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
203 queued -= done;
204 while(done--)
205 alSourceUnqueueBuffers(buf->source, 1, &which);
206 while(queued < QBUFFERS)
208 which = buf->buffer->buffers[buf->curidx];
209 ofs = buf->curidx*buf->buffer->segsize;
210 if(buf->curidx < buf->buffer->numsegs-1)
211 alBufferData(which, buf->buffer->buf_format,
212 buf->buffer->data + ofs, buf->buffer->segsize,
213 buf->buffer->format.Format.nSamplesPerSec);
214 else
215 alBufferData(which, buf->buffer->buf_format,
216 buf->buffer->data + ofs, buf->buffer->lastsegsize,
217 buf->buffer->format.Format.nSamplesPerSec);
219 alSourceQueueBuffers(buf->source, 1, &which);
220 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
221 queued++;
223 if(!buf->curidx && !buf->islooping)
225 buf->isplaying = FALSE;
226 break;
229 if(state != AL_PLAYING)
231 if(!queued)
233 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
234 continue;
236 alSourcePlay(buf->source);
239 checkALError();
241 else if(active_notifies == 0 && prim->timer_id)
243 TRACE("No more notifies, killing timer\n");
244 timeKillEvent(prim->timer_id);
245 prim->timer_id = 0;
246 timeEndPeriod(prim->timer_res);
249 popALContext();
250 LeaveCriticalSection(prim->crst);
252 TRACE("Primary buffer (%p) message loop quit\n", prim);
254 if(prim->timer_id)
256 timeKillEvent(prim->timer_id);
257 prim->timer_id = 0;
258 timeEndPeriod(prim->timer_res);
259 TRACE("Killed timer\n");
262 return 0;
265 static void CALLBACK DS8Primary_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
266 DWORD_PTR dw1, DWORD_PTR dw2)
268 (void)timerID;
269 (void)msg;
270 (void)dw1;
271 (void)dw2;
272 PostThreadMessageA(dwUser, WM_USER, 0, 0);
275 void DS8Primary_starttimer(DS8Primary *prim)
277 DWORD triggertime, res = DS_TIME_RES;
278 ALint refresh = FAKE_REFRESH_COUNT;
279 TIMECAPS time;
281 if(prim->timer_id)
282 return;
284 timeGetDevCaps(&time, sizeof(TIMECAPS));
286 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
287 checkALCError(prim->parent->device);
289 triggertime = 1000 / refresh / 2;
290 if(triggertime < time.wPeriodMin)
291 triggertime = time.wPeriodMin;
292 TRACE("Calling timer every %"LONGFMT"u ms for %i refreshes per second\n", triggertime, refresh);
294 if (res < time.wPeriodMin)
295 res = time.wPeriodMin;
296 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
297 WARN("Could not set minimum resolution, don't expect sound\n");
299 prim->timer_res = res;
300 prim->timer_id = timeSetEvent(triggertime, res, DS8Primary_timer, prim->thread_id, TIME_PERIODIC|TIME_KILL_SYNCHRONOUS);
305 HRESULT DS8Primary_PreInit(DS8Primary *This, DS8Impl *parent)
307 DS3DLISTENER *listener;
308 WAVEFORMATEX *wfx;
309 HRESULT hr;
311 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
312 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
313 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
315 This->parent = parent;
316 This->crst = &parent->share->crst;
317 This->ctx = parent->share->ctx;
318 This->SupportedExt = parent->share->SupportedExt;
319 This->ExtAL = &parent->share->ExtAL;
320 This->sources = parent->share->sources;
321 This->auxslot = parent->share->auxslot;
323 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
324 wfx = &This->format.Format;
326 wfx->wFormatTag = WAVE_FORMAT_PCM;
327 wfx->nChannels = 2;
328 wfx->wBitsPerSample = 8;
329 wfx->nSamplesPerSec = 22050;
330 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
331 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
332 wfx->cbSize = 0;
334 This->stopped = TRUE;
336 /* Apparently primary buffer size is always 32k,
337 * tested on windows with 192k 24 bits sound @ 6 channels
338 * where it will run out in 60 ms and it isn't pointer aligned
340 This->buf_size = 32768;
342 if(This->SupportedExt[SOFT_DEFERRED_UPDATES])
344 This->DeferUpdates = This->ExtAL->DeferUpdatesSOFT;
345 This->ProcessUpdates = This->ExtAL->ProcessUpdatesSOFT;
347 else
349 This->DeferUpdates = wrap_DeferUpdates;
350 This->ProcessUpdates = wrap_ProcessUpdates;
353 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
354 if(This->SupportedExt[EXT_EFX] && This->auxslot != 0)
356 ALint revid = alGetEnumValue("AL_EFFECT_REVERB");
357 if(revid != 0 && revid != -1)
359 This->ExtAL->GenEffects(1, &This->effect);
360 This->ExtAL->Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
361 checkALError();
365 /* Make sure DS3DListener defaults are applied to OpenAL */
366 listener = &This->params;
367 listener->dwSize = sizeof(This->params);
368 listener->vPosition.x = 0.0;
369 listener->vPosition.y = 0.0;
370 listener->vPosition.z = 0.0;
371 listener->vVelocity.x = 0.0;
372 listener->vVelocity.y = 0.0;
373 listener->vVelocity.z = 0.0;
374 listener->vOrientFront.x = 0.0;
375 listener->vOrientFront.y = 0.0;
376 listener->vOrientFront.z = 1.0;
377 listener->vOrientTop.x = 0.0;
378 listener->vOrientTop.y = 1.0;
379 listener->vOrientTop.z = 0.0;
380 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
381 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
382 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
383 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
384 if(FAILED(hr))
385 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
387 This->sizenotifies = This->sizebuffers = parent->share->max_sources;
389 hr = DSERR_OUTOFMEMORY;
390 This->buffers = HeapAlloc(GetProcessHeap(), 0, This->sizebuffers*sizeof(*This->buffers));
391 This->notifies = HeapAlloc(GetProcessHeap(), 0, This->sizenotifies*sizeof(*This->notifies));
392 if(!This->buffers || !This->notifies)
393 goto fail;
395 This->thread_hdl = CreateThread(NULL, 0, DS8Primary_thread, This, 0, &This->thread_id);
396 if(This->thread_hdl == NULL)
397 goto fail;
399 return S_OK;
401 fail:
402 DS8Primary_Clear(This);
403 return hr;
406 void DS8Primary_Clear(DS8Primary *This)
408 TRACE("Clearing primary %p\n", This);
410 if(!This->parent)
411 return;
413 if(This->thread_hdl)
415 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
416 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
418 /* HACK: Apparently, if the device is initialized (thus the primary
419 * buffer has PreInit called) then immediately deleted (the primary
420 * buffer has Clear called), the WM_QUIT message gets sent before
421 * the thread has a chance to run which apparently prevents it from
422 * receiving the message.
423 * If the wait attempt fails, try sending the message again. */
424 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
425 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
426 ERR("Thread wait timed out\n");
428 CloseHandle(This->thread_hdl);
431 setALContext(This->ctx);
432 if(This->effect)
433 This->ExtAL->DeleteEffects(1, &This->effect);
434 popALContext();
435 while(This->nbuffers--)
436 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
438 HeapFree(GetProcessHeap(), 0, This->notifies);
439 HeapFree(GetProcessHeap(), 0, This->buffers);
440 memset(This, 0, sizeof(*This));
443 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
445 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
447 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
449 *ppv = NULL;
450 if(IsEqualIID(riid, &IID_IUnknown) ||
451 IsEqualIID(riid, &IID_IDirectSoundBuffer))
452 *ppv = &This->IDirectSoundBuffer_iface;
453 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
455 if((This->flags&DSBCAPS_CTRL3D))
456 *ppv = &This->IDirectSound3DListener_iface;
458 else
459 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
461 if(*ppv)
463 IUnknown_AddRef((IUnknown*)*ppv);
464 return S_OK;
467 return E_NOINTERFACE;
470 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
472 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
473 LONG ret;
475 ret = InterlockedIncrement(&This->ref);
476 if(ret == 1) This->flags = 0;
478 return ret;
481 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
483 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
484 LONG ret;
486 ret = InterlockedDecrement(&This->ref);
488 return ret;
491 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
493 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
495 TRACE("(%p)->(%p)\n", iface, caps);
497 if(!caps || caps->dwSize < sizeof(*caps))
499 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
500 return DSERR_INVALIDPARAM;
503 caps->dwFlags = This->flags;
504 caps->dwBufferBytes = This->buf_size;
505 caps->dwUnlockTransferRate = 0;
506 caps->dwPlayCpuOverhead = 0;
508 return DS_OK;
511 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
513 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
514 HRESULT hr = DSERR_PRIOLEVELNEEDED;
516 EnterCriticalSection(This->crst);
517 if(This->write_emu)
518 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
519 LeaveCriticalSection(This->crst);
521 return hr;
524 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
526 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
527 HRESULT hr = S_OK;
528 UINT size;
530 if(!wfx && !written)
532 WARN("Cannot report format or format size\n");
533 return DSERR_INVALIDPARAM;
536 EnterCriticalSection(This->crst);
537 size = sizeof(This->format.Format) + This->format.Format.cbSize;
538 if(written)
539 *written = size;
540 if(wfx)
542 if(allocated < size)
543 hr = DSERR_INVALIDPARAM;
544 else
545 memcpy(wfx, &This->format.Format, size);
547 LeaveCriticalSection(This->crst);
549 return hr;
552 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
554 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
555 ALfloat gain;
557 TRACE("(%p)->(%p)\n", iface, volume);
559 if(!volume)
560 return DSERR_INVALIDPARAM;
561 *volume = 0;
563 if(!(This->flags&DSBCAPS_CTRLVOLUME))
564 return DSERR_CONTROLUNAVAIL;
566 setALContext(This->ctx);
567 alGetListenerf(AL_GAIN, &gain);
568 checkALError();
569 popALContext();
571 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
572 return DS_OK;
575 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
577 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
578 HRESULT hr = DS_OK;
580 WARN("(%p)->(%p): semi-stub\n", iface, pan);
582 if(!pan)
583 return DSERR_INVALIDPARAM;
585 EnterCriticalSection(This->crst);
586 if(This->write_emu)
587 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
588 else if(!(This->flags & DSBCAPS_CTRLPAN))
589 hr = DSERR_CONTROLUNAVAIL;
590 else
591 *pan = 0;
592 LeaveCriticalSection(This->crst);
594 return hr;
597 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
599 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
600 HRESULT hr = DS_OK;
602 WARN("(%p)->(%p): semi-stub\n", iface, freq);
604 if(!freq)
605 return DSERR_INVALIDPARAM;
607 if(!(This->flags&DSBCAPS_CTRLFREQUENCY))
608 return DSERR_CONTROLUNAVAIL;
610 EnterCriticalSection(This->crst);
611 *freq = This->format.Format.nSamplesPerSec;
612 LeaveCriticalSection(This->crst);
614 return hr;
617 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
619 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
621 TRACE("(%p)->(%p)\n", iface, status);
623 if(!status)
624 return DSERR_INVALIDPARAM;
626 EnterCriticalSection(This->crst);
627 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
628 if((This->flags&DSBCAPS_LOCDEFER))
629 *status |= DSBSTATUS_LOCHARDWARE;
631 if(This->stopped)
633 DWORD i, state;
634 HRESULT hr;
636 for(i = 0;i < This->nbuffers;++i)
638 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
639 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
640 break;
642 if(i == This->nbuffers)
644 /* Primary stopped and no buffers playing.. */
645 *status = 0;
648 LeaveCriticalSection(This->crst);
650 return DS_OK;
653 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
655 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
656 HRESULT hr;
658 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
660 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
662 WARN("Bad DSBDESC for primary buffer\n");
663 return DSERR_INVALIDPARAM;
665 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
666 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
667 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
669 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
670 return DSERR_INVALIDPARAM;
673 /* Should be 0 if not initialized */
674 if(This->flags)
675 return DSERR_ALREADYINITIALIZED;
677 hr = DS_OK;
678 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
680 DSBUFFERDESC emudesc;
681 DS8Buffer *emu;
683 if(This->write_emu)
685 ERR("There shouldn't be a write_emu!\n");
686 IDirectSoundBuffer8_Release(This->write_emu);
687 This->write_emu = NULL;
690 memset(&emudesc, 0, sizeof(emudesc));
691 emudesc.dwSize = sizeof(emudesc);
692 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
693 /* Dont play last incomplete sample */
694 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
695 emudesc.lpwfxFormat = &This->format.Format;
697 hr = DS8Buffer_Create(&emu, This, NULL);
698 if(SUCCEEDED(hr))
700 This->write_emu = &emu->IDirectSoundBuffer8_iface;
701 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
702 if(FAILED(hr))
704 IDirectSoundBuffer8_Release(This->write_emu);
705 This->write_emu = NULL;
710 if(SUCCEEDED(hr))
711 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
712 return hr;
715 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
717 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
718 HRESULT hr = DSERR_PRIOLEVELNEEDED;
720 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
722 EnterCriticalSection(This->crst);
723 if(This->write_emu)
724 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
725 LeaveCriticalSection(This->crst);
727 return hr;
730 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
732 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
733 HRESULT hr;
735 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
737 if(!(flags & DSBPLAY_LOOPING))
739 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
740 return DSERR_INVALIDPARAM;
743 EnterCriticalSection(This->crst);
744 hr = S_OK;
745 if(This->write_emu)
746 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
747 if(SUCCEEDED(hr))
748 This->stopped = FALSE;
749 LeaveCriticalSection(This->crst);
751 return hr;
754 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
756 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
757 return DSERR_INVALIDCALL;
760 /* Just assume the format is crap, and clean up the damage */
761 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
763 if(from->wFormatTag == WAVE_FORMAT_PCM)
765 wfx->cbSize = 0;
766 if(from->wBitsPerSample == 8 ||
767 from->wBitsPerSample == 16 ||
768 from->wBitsPerSample == 24 ||
769 from->wBitsPerSample == 32)
770 wfx->wBitsPerSample = from->wBitsPerSample;
772 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
774 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
775 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
776 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
778 /* Fail silently.. */
779 if(from->cbSize < size)
780 return;
781 if(!fromx->Samples.wValidBitsPerSample &&
782 !fromx->Format.wBitsPerSample)
783 return;
785 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
786 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
788 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
789 return;
792 wfe->Format.wBitsPerSample = from->wBitsPerSample;
793 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
794 if(!wfe->Samples.wValidBitsPerSample)
795 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
796 wfe->Format.cbSize = size;
797 wfe->dwChannelMask = fromx->dwChannelMask;
798 wfe->SubFormat = fromx->SubFormat;
800 else
802 ERR("Unhandled format tag %04x\n", from->wFormatTag);
803 return;
806 if(from->nChannels)
807 wfx->nChannels = from->nChannels;
808 wfx->wFormatTag = from->wFormatTag;
809 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
810 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
811 wfx->nSamplesPerSec = from->nSamplesPerSec;
812 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
813 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
816 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
818 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
819 HRESULT hr = S_OK;
820 ALCint freq;
822 TRACE("(%p)->(%p)\n", iface, wfx);
824 if(!wfx)
826 WARN("Missing format\n");
827 return DSERR_INVALIDPARAM;
830 EnterCriticalSection(This->crst);
832 if(This->parent->prio_level < DSSCL_PRIORITY)
834 hr = DSERR_PRIOLEVELNEEDED;
835 goto out;
838 TRACE("Requested primary format:\n"
839 " FormatTag = %04x\n"
840 " Channels = %u\n"
841 " SamplesPerSec = %"LONGFMT"u\n"
842 " AvgBytesPerSec = %"LONGFMT"u\n"
843 " BlockAlign = %u\n"
844 " BitsPerSample = %u\n",
845 wfx->wFormatTag, wfx->nChannels,
846 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
847 wfx->nBlockAlign, wfx->wBitsPerSample);
849 copy_waveformat(&This->format.Format, wfx);
851 freq = This->format.Format.nSamplesPerSec;
852 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
853 checkALCError(This->parent->device);
855 This->format.Format.nSamplesPerSec = freq;
856 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
857 This->format.Format.nSamplesPerSec;
859 if(This->write_emu)
861 DS8Buffer *buf;
862 DSBUFFERDESC desc;
864 memset(&desc, 0, sizeof(desc));
865 desc.dwSize = sizeof(desc);
866 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
867 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
868 desc.lpwfxFormat = &This->format.Format;
870 hr = DS8Buffer_Create(&buf, This, NULL);
871 if(FAILED(hr))
872 goto out;
874 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
875 if(FAILED(hr))
876 DS8Buffer_Destroy(buf);
877 else
879 IDirectSoundBuffer8_Release(This->write_emu);
880 This->write_emu = &buf->IDirectSoundBuffer8_iface;
884 out:
885 LeaveCriticalSection(This->crst);
886 return hr;
889 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
891 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
893 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
895 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
897 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
898 return DSERR_INVALIDPARAM;
901 if(!(This->flags&DSBCAPS_CTRLVOLUME))
902 return DSERR_CONTROLUNAVAIL;
904 setALContext(This->ctx);
905 alListenerf(AL_GAIN, mB_to_gain(vol));
906 popALContext();
908 return DS_OK;
911 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
913 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
914 HRESULT hr;
916 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
918 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
920 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
921 return DSERR_INVALIDPARAM;
924 EnterCriticalSection(This->crst);
925 if(!(This->flags&DSBCAPS_CTRLPAN))
927 WARN("control unavailable\n");
928 hr = DSERR_CONTROLUNAVAIL;
930 else if(This->write_emu)
931 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
932 else
934 FIXME("Not supported\n");
935 hr = E_NOTIMPL;
937 LeaveCriticalSection(This->crst);
939 return hr;
942 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
944 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
945 return DSERR_CONTROLUNAVAIL;
948 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
950 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
951 HRESULT hr = S_OK;
953 TRACE("(%p)->()\n", iface);
955 EnterCriticalSection(This->crst);
956 if(This->write_emu)
957 hr = IDirectSoundBuffer8_Stop(This->write_emu);
958 if(SUCCEEDED(hr))
959 This->stopped = TRUE;
960 LeaveCriticalSection(This->crst);
962 return hr;
965 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
967 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
968 HRESULT hr = DSERR_INVALIDCALL;
970 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
972 EnterCriticalSection(This->crst);
973 if(This->write_emu)
974 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
975 LeaveCriticalSection(This->crst);
977 return hr;
980 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
982 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
983 HRESULT hr = S_OK;
985 TRACE("(%p)->()\n", iface);
987 EnterCriticalSection(This->crst);
988 if(This->write_emu)
989 hr = IDirectSoundBuffer8_Restore(This->write_emu);
990 LeaveCriticalSection(This->crst);
992 return hr;
995 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
997 DS8Primary_QueryInterface,
998 DS8Primary_AddRef,
999 DS8Primary_Release,
1000 DS8Primary_GetCaps,
1001 DS8Primary_GetCurrentPosition,
1002 DS8Primary_GetFormat,
1003 DS8Primary_GetVolume,
1004 DS8Primary_GetPan,
1005 DS8Primary_GetFrequency,
1006 DS8Primary_GetStatus,
1007 DS8Primary_Initialize,
1008 DS8Primary_Lock,
1009 DS8Primary_Play,
1010 DS8Primary_SetCurrentPosition,
1011 DS8Primary_SetFormat,
1012 DS8Primary_SetVolume,
1013 DS8Primary_SetPan,
1014 DS8Primary_SetFrequency,
1015 DS8Primary_Stop,
1016 DS8Primary_Unlock,
1017 DS8Primary_Restore
1021 static void DS8Primary_SetParams(DS8Primary *This, const DS3DLISTENER *params, LONG flags)
1023 union PrimaryParamFlags dirty = { flags };
1024 DWORD i;
1026 if(dirty.bit.pos)
1027 alListener3f(AL_POSITION, params->vPosition.x, params->vPosition.y,
1028 -params->vPosition.z);
1029 if(dirty.bit.vel)
1030 alListener3f(AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1031 -params->vVelocity.z);
1032 if(dirty.bit.orientation)
1034 ALfloat orient[6] = {
1035 params->vOrientFront.x, params->vOrientFront.y, -params->vOrientFront.z,
1036 params->vOrientTop.x, params->vOrientTop.y, -params->vOrientTop.z
1038 alListenerfv(AL_ORIENTATION, orient);
1040 if(dirty.bit.distancefactor)
1042 alSpeedOfSound(343.3f/params->flDistanceFactor);
1043 if(This->SupportedExt[EXT_EFX])
1044 alListenerf(AL_METERS_PER_UNIT, params->flDistanceFactor);
1046 if(dirty.bit.rollofffactor)
1048 ALfloat rolloff = params->flRolloffFactor;
1049 This->rollofffactor = rolloff;
1050 for(i = 0;i < This->nbuffers;++i)
1052 const DS8Buffer *buf = This->buffers[i];
1053 if(buf->ds3dmode != DS3DMODE_DISABLE)
1054 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1057 if(dirty.bit.dopplerfactor)
1058 alDopplerFactor(params->flDopplerFactor);
1059 if(dirty.bit.effect)
1060 This->ExtAL->AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1063 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1065 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1066 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1069 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1071 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1072 LONG ret;
1074 ret = InterlockedIncrement(&This->ds3d_ref);
1075 TRACE("new refcount %"LONGFMT"d\n", ret);
1077 return ret;
1080 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1082 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1083 LONG ret;
1085 ret = InterlockedDecrement(&This->ds3d_ref);
1086 TRACE("new refcount %"LONGFMT"d\n", ret);
1088 return ret;
1092 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1094 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1096 TRACE("(%p)->(%p)\n", iface, listener);
1098 if(!listener || listener->dwSize < sizeof(*listener))
1100 WARN("Invalid DS3DLISTENER %p %"LONGFMT"u\n", listener, listener ? listener->dwSize : 0);
1101 return DSERR_INVALIDPARAM;
1104 EnterCriticalSection(This->crst);
1105 setALContext(This->ctx);
1106 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1107 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1108 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1109 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1110 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1111 IDirectSound3DListener_GetDopplerFactor(iface, &listener->flDopplerFactor);
1112 popALContext();
1113 LeaveCriticalSection(This->crst);
1115 return DS_OK;
1118 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1120 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1122 TRACE("(%p)->(%p)\n", iface, distancefactor);
1124 if(!distancefactor)
1126 WARN("Invalid parameter %p\n", distancefactor);
1127 return DSERR_INVALIDPARAM;
1130 setALContext(This->ctx);
1131 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1132 checkALError();
1133 popALContext();
1135 return S_OK;
1138 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1140 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1142 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1144 if(!dopplerfactor)
1146 WARN("Invalid parameter %p\n", dopplerfactor);
1147 return DSERR_INVALIDPARAM;
1150 setALContext(This->ctx);
1151 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1152 checkALError();
1153 popALContext();
1155 return S_OK;
1158 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1160 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1161 ALfloat orient[6];
1163 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1165 if(!front || !top)
1167 WARN("Invalid parameter %p %p\n", front, top);
1168 return DSERR_INVALIDPARAM;
1171 setALContext(This->ctx);
1172 alGetListenerfv(AL_ORIENTATION, orient);
1173 checkALError();
1174 popALContext();
1176 front->x = orient[0];
1177 front->y = orient[1];
1178 front->z = -orient[2];
1179 top->x = orient[3];
1180 top->y = orient[4];
1181 top->z = -orient[5];
1182 return S_OK;
1185 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1187 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1188 ALfloat alpos[3];
1190 TRACE("(%p)->(%p)\n", iface, pos);
1192 if(!pos)
1194 WARN("Invalid parameter %p\n", pos);
1195 return DSERR_INVALIDPARAM;
1198 setALContext(This->ctx);
1199 alGetListenerfv(AL_POSITION, alpos);
1200 checkALError();
1201 popALContext();
1203 pos->x = alpos[0];
1204 pos->y = alpos[1];
1205 pos->z = -alpos[2];
1206 return S_OK;
1209 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1211 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1213 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1215 if(!rollofffactor)
1217 WARN("Invalid parameter %p\n", rollofffactor);
1218 return DSERR_INVALIDPARAM;
1221 EnterCriticalSection(This->crst);
1222 *rollofffactor = This->rollofffactor;
1223 LeaveCriticalSection(This->crst);
1225 return S_OK;
1228 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1230 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1231 ALfloat vel[3];
1233 TRACE("(%p)->(%p)\n", iface, velocity);
1235 if(!velocity)
1237 WARN("Invalid parameter %p\n", velocity);
1238 return DSERR_INVALIDPARAM;
1241 setALContext(This->ctx);
1242 alGetListenerfv(AL_VELOCITY, vel);
1243 checkALError();
1244 popALContext();
1246 velocity->x = vel[0];
1247 velocity->y = vel[1];
1248 velocity->z = -vel[2];
1249 return S_OK;
1252 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1254 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1256 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, listen, apply);
1258 if(!listen || listen->dwSize < sizeof(*listen))
1260 WARN("Invalid parameter %p %"LONGFMT"u\n", listen, listen ? listen->dwSize : 0);
1261 return DSERR_INVALIDPARAM;
1264 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1265 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1267 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1268 return DSERR_INVALIDPARAM;
1271 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1272 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1274 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1275 return DSERR_INVALIDPARAM;
1278 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1279 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1281 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1282 return DSERR_INVALIDPARAM;
1285 if(apply == DS3D_DEFERRED)
1287 EnterCriticalSection(This->crst);
1288 This->params = *listen;
1289 This->params.dwSize = sizeof(This->params);
1290 This->dirty.bit.pos = 1;
1291 This->dirty.bit.vel = 1;
1292 This->dirty.bit.orientation = 1;
1293 This->dirty.bit.distancefactor = 1;
1294 This->dirty.bit.rollofffactor = 1;
1295 This->dirty.bit.dopplerfactor = 1;
1296 LeaveCriticalSection(This->crst);
1298 else
1300 union PrimaryParamFlags dirty = { 0l };
1301 dirty.bit.pos = 1;
1302 dirty.bit.vel = 1;
1303 dirty.bit.orientation = 1;
1304 dirty.bit.distancefactor = 1;
1305 dirty.bit.rollofffactor = 1;
1306 dirty.bit.dopplerfactor = 1;
1308 EnterCriticalSection(This->crst);
1309 setALContext(This->ctx);
1310 DS8Primary_SetParams(This, listen, dirty.flags);
1311 checkALError();
1312 popALContext();
1313 LeaveCriticalSection(This->crst);
1316 return S_OK;
1319 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1321 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1323 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1325 if(factor < DS3D_MINDISTANCEFACTOR ||
1326 factor > DS3D_MAXDISTANCEFACTOR)
1328 WARN("Invalid parameter %f\n", factor);
1329 return DSERR_INVALIDPARAM;
1332 if(apply == DS3D_DEFERRED)
1334 EnterCriticalSection(This->crst);
1335 This->params.flDistanceFactor = factor;
1336 This->dirty.bit.distancefactor = 1;
1337 LeaveCriticalSection(This->crst);
1339 else
1341 setALContext(This->ctx);
1342 alSpeedOfSound(343.3f/factor);
1343 if(This->SupportedExt[EXT_EFX])
1344 alListenerf(AL_METERS_PER_UNIT, factor);
1345 checkALError();
1346 popALContext();
1349 return S_OK;
1352 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1354 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1356 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1358 if(factor < DS3D_MINDOPPLERFACTOR ||
1359 factor > DS3D_MAXDOPPLERFACTOR)
1361 WARN("Invalid parameter %f\n", factor);
1362 return DSERR_INVALIDPARAM;
1365 if(apply == DS3D_DEFERRED)
1367 EnterCriticalSection(This->crst);
1368 This->params.flDopplerFactor = factor;
1369 This->dirty.bit.dopplerfactor = 1;
1370 LeaveCriticalSection(This->crst);
1372 else
1374 setALContext(This->ctx);
1375 alDopplerFactor(factor);
1376 checkALError();
1377 popALContext();
1380 return S_OK;
1383 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1385 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1387 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT"u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1389 if(apply == DS3D_DEFERRED)
1391 EnterCriticalSection(This->crst);
1392 This->params.vOrientFront.x = xFront;
1393 This->params.vOrientFront.y = yFront;
1394 This->params.vOrientFront.z = zFront;
1395 This->params.vOrientTop.x = xTop;
1396 This->params.vOrientTop.y = yTop;
1397 This->params.vOrientTop.z = zTop;
1398 This->dirty.bit.orientation = 1;
1399 LeaveCriticalSection(This->crst);
1401 else
1403 ALfloat orient[6] = {
1404 xFront, yFront, -zFront,
1405 xTop, yTop, -zTop
1407 setALContext(This->ctx);
1408 alListenerfv(AL_ORIENTATION, orient);
1409 checkALError();
1410 popALContext();
1413 return S_OK;
1416 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1418 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1420 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1422 if(apply == DS3D_DEFERRED)
1424 EnterCriticalSection(This->crst);
1425 This->params.vPosition.x = x;
1426 This->params.vPosition.y = y;
1427 This->params.vPosition.z = z;
1428 This->dirty.bit.pos = 1;
1429 LeaveCriticalSection(This->crst);
1431 else
1433 setALContext(This->ctx);
1434 alListener3f(AL_POSITION, x, y, -z);
1435 checkALError();
1436 popALContext();
1439 return S_OK;
1442 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1444 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1446 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1448 if(factor < DS3D_MINROLLOFFFACTOR ||
1449 factor > DS3D_MAXROLLOFFFACTOR)
1451 WARN("Invalid parameter %f\n", factor);
1452 return DSERR_INVALIDPARAM;
1455 EnterCriticalSection(This->crst);
1456 if(apply == DS3D_DEFERRED)
1458 This->params.flRolloffFactor = factor;
1459 This->dirty.bit.rollofffactor = 1;
1461 else
1463 DWORD i;
1465 setALContext(This->ctx);
1466 for(i = 0;i < This->nbuffers;++i)
1468 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1469 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1471 checkALError();
1472 popALContext();
1474 This->rollofffactor = factor;
1476 LeaveCriticalSection(This->crst);
1478 return S_OK;
1481 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1483 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1485 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1487 if(apply == DS3D_DEFERRED)
1489 EnterCriticalSection(This->crst);
1490 This->params.vVelocity.x = x;
1491 This->params.vVelocity.y = y;
1492 This->params.vVelocity.z = z;
1493 This->dirty.bit.vel = 1;
1494 LeaveCriticalSection(This->crst);
1496 else
1498 setALContext(This->ctx);
1499 alListener3f(AL_VELOCITY, x, y, -z);
1500 checkALError();
1501 popALContext();
1504 return S_OK;
1507 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1509 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1510 LONG flags;
1511 DWORD i;
1513 EnterCriticalSection(This->crst);
1514 setALContext(This->ctx);
1515 This->DeferUpdates();
1517 if((flags=InterlockedExchange(&This->dirty.flags, 0)) != 0)
1519 DS8Primary_SetParams(This, &This->params, flags);
1520 /* checkALError is here for debugging */
1521 checkALError();
1523 TRACE("Dirty flags was: 0x%02x\n", flags);
1525 for(i = 0;i < This->nbuffers;++i)
1527 DS8Buffer *buf = This->buffers[i];
1529 if((flags=InterlockedExchange(&buf->dirty.flags, 0)) != 0)
1530 DS8Buffer_SetParams(buf, &buf->params, flags);
1532 checkALError();
1534 This->ProcessUpdates();
1535 popALContext();
1536 LeaveCriticalSection(This->crst);
1538 return DS_OK;
1541 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1543 DS8Primary3D_QueryInterface,
1544 DS8Primary3D_AddRef,
1545 DS8Primary3D_Release,
1546 DS8Primary3D_GetAllParameters,
1547 DS8Primary3D_GetDistanceFactor,
1548 DS8Primary3D_GetDopplerFactor,
1549 DS8Primary3D_GetOrientation,
1550 DS8Primary3D_GetPosition,
1551 DS8Primary3D_GetRolloffFactor,
1552 DS8Primary3D_GetVelocity,
1553 DS8Primary3D_SetAllParameters,
1554 DS8Primary3D_SetDistanceFactor,
1555 DS8Primary3D_SetDopplerFactor,
1556 DS8Primary3D_SetOrientation,
1557 DS8Primary3D_SetPosition,
1558 DS8Primary3D_SetRolloffFactor,
1559 DS8Primary3D_SetVelocity,
1560 DS8Primary3D_CommitDeferredSettings
1563 /* NOTE: Although the app handles listener properties through secondary buffers,
1564 * we pass the requests to the primary buffer though a propertyset interface.
1565 * These methods are not exposed to the app. */
1566 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1568 DS8Primary *This = impl_from_IKsPropertySet(iface);
1569 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1572 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1574 DS8Primary *This = impl_from_IKsPropertySet(iface);
1575 LONG ret;
1577 ret = InterlockedIncrement(&This->prop_ref);
1578 TRACE("new refcount %"LONGFMT"d\n", ret);
1580 return ret;
1583 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1585 DS8Primary *This = impl_from_IKsPropertySet(iface);
1586 LONG ret;
1588 ret = InterlockedDecrement(&This->prop_ref);
1589 TRACE("new refcount %"LONGFMT"d\n", ret);
1591 return ret;
1594 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1595 REFGUID guidPropSet, ULONG dwPropID,
1596 LPVOID pInstanceData, ULONG cbInstanceData,
1597 LPVOID pPropData, ULONG cbPropData,
1598 PULONG pcbReturned)
1600 DS8Primary *This = impl_from_IKsPropertySet(iface);
1601 HRESULT res = E_PROP_ID_UNSUPPORTED;
1602 (void)pInstanceData;
1603 (void)cbInstanceData;
1605 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1607 EnterCriticalSection(This->crst);
1609 if(This->effect == 0)
1610 res = E_PROP_ID_UNSUPPORTED;
1611 else switch(dwPropID)
1613 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1614 res = DSERR_INVALIDPARAM;
1615 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1617 union {
1618 void *v;
1619 EAXLISTENERPROPERTIES *props;
1620 } data = { pPropData };
1622 *data.props = This->eax_prop;
1623 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1624 res = DS_OK;
1626 break;
1628 case DSPROPERTY_EAXLISTENER_ROOM:
1629 res = DSERR_INVALIDPARAM;
1630 if(cbPropData >= sizeof(LONG))
1632 union {
1633 void *v;
1634 LONG *l;
1635 } data = { pPropData };
1637 *data.l = This->eax_prop.lRoom;
1638 *pcbReturned = sizeof(LONG);
1639 res = DS_OK;
1641 break;
1642 case DSPROPERTY_EAXLISTENER_ROOMHF:
1643 res = DSERR_INVALIDPARAM;
1644 if(cbPropData >= sizeof(LONG))
1646 union {
1647 void *v;
1648 LONG *l;
1649 } data = { pPropData };
1651 *data.l = This->eax_prop.lRoomHF;
1652 *pcbReturned = sizeof(LONG);
1653 res = DS_OK;
1655 break;
1657 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1658 res = DSERR_INVALIDPARAM;
1659 if(cbPropData >= sizeof(FLOAT))
1661 union {
1662 void *v;
1663 FLOAT *fl;
1664 } data = { pPropData };
1666 *data.fl = This->eax_prop.flRoomRolloffFactor;
1667 *pcbReturned = sizeof(FLOAT);
1668 res = DS_OK;
1670 break;
1672 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1673 res = DSERR_INVALIDPARAM;
1674 if(cbPropData >= sizeof(DWORD))
1676 union {
1677 void *v;
1678 DWORD *dw;
1679 } data = { pPropData };
1681 *data.dw = This->eax_prop.dwEnvironment;
1682 *pcbReturned = sizeof(DWORD);
1683 res = DS_OK;
1685 break;
1687 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1688 res = DSERR_INVALIDPARAM;
1689 if(cbPropData >= sizeof(FLOAT))
1691 union {
1692 void *v;
1693 FLOAT *fl;
1694 } data = { pPropData };
1696 *data.fl = This->eax_prop.flEnvironmentSize;
1697 *pcbReturned = sizeof(FLOAT);
1698 res = DS_OK;
1700 break;
1701 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
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.flEnvironmentDiffusion;
1711 *pcbReturned = sizeof(FLOAT);
1712 res = DS_OK;
1714 break;
1716 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1717 res = DSERR_INVALIDPARAM;
1718 if(cbPropData >= sizeof(FLOAT))
1720 union {
1721 void *v;
1722 FLOAT *fl;
1723 } data = { pPropData };
1725 *data.fl = This->eax_prop.flAirAbsorptionHF;
1726 *pcbReturned = sizeof(FLOAT);
1727 res = DS_OK;
1729 break;
1731 case DSPROPERTY_EAXLISTENER_FLAGS:
1732 res = DSERR_INVALIDPARAM;
1733 if(cbPropData >= sizeof(DWORD))
1735 union {
1736 void *v;
1737 DWORD *dw;
1738 } data = { pPropData };
1740 *data.dw = This->eax_prop.dwFlags;
1741 *pcbReturned = sizeof(DWORD);
1742 res = DS_OK;
1744 break;
1746 default:
1747 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1748 break;
1751 LeaveCriticalSection(This->crst);
1753 else
1754 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1756 return res;
1759 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1760 REFGUID guidPropSet, ULONG dwPropID,
1761 LPVOID pInstanceData, ULONG cbInstanceData,
1762 LPVOID pPropData, ULONG cbPropData)
1764 DS8Primary *This = impl_from_IKsPropertySet(iface);
1765 HRESULT res = E_PROP_ID_UNSUPPORTED;
1766 (void)pInstanceData;
1767 (void)cbInstanceData;
1769 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1771 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1772 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1774 EnterCriticalSection(This->crst);
1775 setALContext(This->ctx);
1777 if(This->effect == 0)
1778 res = E_PROP_ID_UNSUPPORTED;
1779 else switch(propid)
1781 case DSPROPERTY_EAXLISTENER_NONE: /* not setting any property, just applying */
1782 res = DS_OK;
1783 break;
1785 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1786 do_allparams:
1787 res = DSERR_INVALIDPARAM;
1788 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1790 union {
1791 const void *v;
1792 const EAXLISTENERPROPERTIES *props;
1793 } data = { pPropData };
1795 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1796 This->eax_prop = *data.props;
1797 This->ExtAL->Effectf(This->effect, AL_REVERB_DENSITY,
1798 (data.props->flEnvironmentSize < 2.0f) ?
1799 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1800 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1801 data.props->flEnvironmentDiffusion);
1803 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1804 mB_to_gain(data.props->lRoom));
1805 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1806 mB_to_gain(data.props->lRoomHF));
1808 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1809 data.props->flRoomRolloffFactor);
1811 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_TIME,
1812 data.props->flDecayTime);
1813 This->ExtAL->Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1814 data.props->flDecayHFRatio);
1816 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1817 mB_to_gain(data.props->lReflections));
1818 This->ExtAL->Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1819 data.props->flReflectionsDelay);
1821 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1822 mB_to_gain(data.props->lReverb));
1823 This->ExtAL->Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1824 data.props->flReverbDelay);
1826 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1827 mB_to_gain(data.props->flAirAbsorptionHF));
1829 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1830 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1831 AL_TRUE : AL_FALSE);
1833 checkALError();
1835 This->dirty.bit.effect = 1;
1836 res = DS_OK;
1838 break;
1840 case DSPROPERTY_EAXLISTENER_ROOM:
1841 res = DSERR_INVALIDPARAM;
1842 if(cbPropData >= sizeof(LONG))
1844 union {
1845 const void *v;
1846 const LONG *l;
1847 } data = { pPropData };
1849 This->eax_prop.lRoom = *data.l;
1850 This->ExtAL->Effectf(This->effect, AL_REVERB_GAIN,
1851 mB_to_gain(This->eax_prop.lRoom));
1852 checkALError();
1854 This->dirty.bit.effect = 1;
1855 res = DS_OK;
1857 break;
1858 case DSPROPERTY_EAXLISTENER_ROOMHF:
1859 res = DSERR_INVALIDPARAM;
1860 if(cbPropData >= sizeof(LONG))
1862 union {
1863 const void *v;
1864 const LONG *l;
1865 } data = { pPropData };
1867 This->eax_prop.lRoomHF = *data.l;
1868 This->ExtAL->Effectf(This->effect, AL_REVERB_GAINHF,
1869 mB_to_gain(This->eax_prop.lRoomHF));
1870 checkALError();
1872 This->dirty.bit.effect = 1;
1873 res = DS_OK;
1875 break;
1877 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1878 res = DSERR_INVALIDPARAM;
1879 if(cbPropData >= sizeof(FLOAT))
1881 union {
1882 const void *v;
1883 const FLOAT *fl;
1884 } data = { pPropData };
1886 This->eax_prop.flRoomRolloffFactor = *data.fl;
1887 This->ExtAL->Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1888 This->eax_prop.flRoomRolloffFactor);
1889 checkALError();
1891 This->dirty.bit.effect = 1;
1892 res = DS_OK;
1894 break;
1896 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1897 res = DSERR_INVALIDPARAM;
1898 if(cbPropData >= sizeof(DWORD))
1900 union {
1901 const void *v;
1902 const DWORD *dw;
1903 } data = { pPropData };
1905 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1907 /* Get the environment index's default and pass it down to
1908 * ALLPARAMETERS */
1909 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1910 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1911 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1912 goto do_allparams;
1915 break;
1917 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1918 res = DSERR_INVALIDPARAM;
1919 if(cbPropData >= sizeof(FLOAT))
1921 union {
1922 const void *v;
1923 const FLOAT *fl;
1924 } data = { pPropData };
1926 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
1928 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
1930 This->eax_prop.flEnvironmentSize = *data.fl;
1932 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
1934 This->eax_prop.flDecayTime *= scale;
1935 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
1937 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
1939 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
1940 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
1942 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
1944 This->eax_prop.flReflectionsDelay *= scale;
1945 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
1947 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
1949 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
1950 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
1952 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
1954 This->eax_prop.flReverbDelay *= scale;
1955 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
1958 /* Pass the updated environment properties down to ALLPARAMETERS */
1959 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1960 pPropData = (void*)&This->eax_prop;
1961 cbPropData = sizeof(This->eax_prop);
1962 goto do_allparams;
1965 break;
1966 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1967 res = DSERR_INVALIDPARAM;
1968 if(cbPropData >= sizeof(FLOAT))
1970 union {
1971 const void *v;
1972 const FLOAT *fl;
1973 } data = { pPropData };
1975 This->eax_prop.flEnvironmentDiffusion = *data.fl;
1976 This->ExtAL->Effectf(This->effect, AL_REVERB_DIFFUSION,
1977 This->eax_prop.flEnvironmentDiffusion);
1978 checkALError();
1980 This->dirty.bit.effect = 1;
1981 res = DS_OK;
1983 break;
1985 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1986 res = DSERR_INVALIDPARAM;
1987 if(cbPropData >= sizeof(FLOAT))
1989 union {
1990 const void *v;
1991 const FLOAT *fl;
1992 } data = { pPropData };
1994 This->eax_prop.flAirAbsorptionHF = *data.fl;
1995 This->ExtAL->Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1996 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
1997 checkALError();
1999 This->dirty.bit.effect = 1;
2000 res = DS_OK;
2002 break;
2004 case DSPROPERTY_EAXLISTENER_FLAGS:
2005 res = DSERR_INVALIDPARAM;
2006 if(cbPropData >= sizeof(DWORD))
2008 union {
2009 const void *v;
2010 const DWORD *dw;
2011 } data = { pPropData };
2013 This->eax_prop.dwFlags = *data.dw;
2014 This->ExtAL->Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2015 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2016 AL_TRUE : AL_FALSE);
2017 checkALError();
2019 This->dirty.bit.effect = 1;
2020 res = DS_OK;
2022 break;
2024 default:
2025 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
2026 break;
2029 if(res == DS_OK && immediate)
2030 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2032 popALContext();
2033 LeaveCriticalSection(This->crst);
2035 else
2036 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2038 return res;
2041 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2042 REFGUID guidPropSet, ULONG dwPropID,
2043 PULONG pTypeSupport)
2045 DS8Primary *This = impl_from_IKsPropertySet(iface);
2046 HRESULT res = E_PROP_ID_UNSUPPORTED;
2048 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2050 EnterCriticalSection(This->crst);
2052 if(This->effect == 0)
2053 res = E_PROP_ID_UNSUPPORTED;
2054 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2055 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2056 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2057 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2058 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2059 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2060 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2061 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2062 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2064 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2065 res = DS_OK;
2067 else
2068 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2070 LeaveCriticalSection(This->crst);
2072 else
2073 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2075 return res;
2078 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2080 DS8PrimaryProp_QueryInterface,
2081 DS8PrimaryProp_AddRef,
2082 DS8PrimaryProp_Release,
2083 DS8PrimaryProp_Get,
2084 DS8PrimaryProp_Set,
2085 DS8PrimaryProp_QuerySupport