Fix return value of DS8Buffer_SetFX
[dsound-openal.git] / primary.c
blob4a39ca4ff81be3a4b5d5f79f56b94e3a09c49c7d
1 /* DirectSound COM interface
3 * Copyright 2009 Maarten Lankhorst
5 * Some code taken from the original dsound-openal implementation
6 * Copyright 2007-2009 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "mmreg.h"
45 #include "ks.h"
46 #include "ksmedia.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
50 #else
52 #define WINVER 0x0600
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 #ifndef E_PROP_ID_UNSUPPORTED
62 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
63 #endif
65 #endif
67 static const IDirectSoundBufferVtbl DS8Primary_Vtbl;
68 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl;
69 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl;
71 static void AL_APIENTRY wrap_DeferUpdates(void)
72 { alcSuspendContext(alcGetCurrentContext()); }
73 static void AL_APIENTRY wrap_ProcessUpdates(void)
74 { alcProcessContext(alcGetCurrentContext()); }
77 static void trigger_elapsed_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos)
79 DWORD i;
80 for(i = 0; i < buf->nnotify; ++i)
82 DSBPOSITIONNOTIFY *not = &buf->notify[i];
83 HANDLE event = not->hEventNotify;
84 DWORD ofs = not->dwOffset;
86 if(ofs == (DWORD)DSBPN_OFFSETSTOP)
87 continue;
89 /* Wraparound case */
90 if(curpos < lastpos)
92 if(ofs < curpos || ofs >= lastpos)
93 SetEvent(event);
94 continue;
97 /* Normal case */
98 if(ofs >= lastpos && ofs < curpos)
99 SetEvent(event);
103 static void trigger_stop_notifies(DS8Buffer *buf)
105 DWORD i;
106 for(i = 0; i < buf->nnotify; ++i)
108 DSBPOSITIONNOTIFY *not = &buf->notify[i];
109 if(not->dwOffset == (DWORD)DSBPN_OFFSETSTOP)
110 SetEvent(not->hEventNotify);
114 static DWORD CALLBACK ThreadProc(void *dwUser)
116 DS8Primary *prim = (DS8Primary*)dwUser;
117 DWORD i;
118 MSG msg;
120 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
122 while(GetMessageA(&msg, NULL, 0, 0))
124 if(msg.message != WM_USER)
125 continue;
127 EnterCriticalSection(&prim->crst);
128 setALContext(prim->ctx);
130 /* OpenAL doesn't support our lovely buffer extensions
131 * so just make sure enough buffers are queued
133 if(!prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferSubData &&
134 !prim->ExtAL.BufferDataStatic)
136 for(i = 0;i < prim->nbuffers;++i)
138 DS8Buffer *buf = prim->buffers[i];
139 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
140 ALuint which, ofs;
142 if(buf->buffer->numsegs == 1 || !buf->isplaying)
143 continue;
145 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
146 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
147 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
149 queued -= done;
150 while(done--)
151 alSourceUnqueueBuffers(buf->source, 1, &which);
152 while(queued < QBUFFERS)
154 which = buf->buffer->buffers[buf->curidx];
155 ofs = buf->curidx*buf->buffer->segsize;
156 if(buf->curidx < buf->buffer->numsegs-1)
157 alBufferData(which, buf->buffer->buf_format,
158 buf->buffer->data + ofs, buf->buffer->segsize,
159 buf->buffer->format.Format.nSamplesPerSec);
160 else
161 alBufferData(which, buf->buffer->buf_format,
162 buf->buffer->data + ofs, buf->buffer->lastsegsize,
163 buf->buffer->format.Format.nSamplesPerSec);
165 alSourceQueueBuffers(buf->source, 1, &which);
166 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
167 queued++;
169 if(!buf->curidx && !buf->islooping)
171 buf->isplaying = FALSE;
172 break;
175 if(state != AL_PLAYING)
177 if(!queued)
179 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
180 continue;
182 alSourcePlay(buf->source);
184 getALError();
188 for(i = 0;i < prim->nnotifies;)
190 DS8Buffer *buf = prim->notifies[i];
191 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
192 DWORD status=0, curpos=buf->lastpos;
194 IDirectSoundBuffer8_GetStatus(dsb, &status);
195 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
196 if(buf->lastpos != curpos)
198 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
199 buf->lastpos = curpos;
201 if(!(status&DSBSTATUS_PLAYING))
203 /* Remove this buffer from list and put another at the
204 * current position; don't increment i
206 trigger_stop_notifies(buf);
207 prim->notifies[i] = prim->notifies[--prim->nnotifies];
208 continue;
210 i++;
212 popALContext();
213 LeaveCriticalSection(&prim->crst);
215 return 0;
219 HRESULT DS8Primary_Create(DS8Primary **ppv, DS8Impl *parent)
221 HRESULT hr = DSERR_OUTOFMEMORY;
222 DS8Primary *This = NULL;
223 DS3DLISTENER *listener;
224 WAVEFORMATEX *wfx;
225 ALuint srcs[256];
226 DWORD nsources;
228 *ppv = NULL;
229 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
230 if(!This) return hr;
232 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
233 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
234 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
236 InitializeCriticalSection(&This->crst);
237 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DS8Primary.crst");
239 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
240 wfx = &This->format.Format;
242 hr = DSERR_NODRIVER;
243 This->ctx = alcCreateContext(parent->device, NULL);
244 if(!This->ctx)
246 ALCenum err = alcGetError(parent->device);
247 ERR("Could not create context (0x%x)!\n", err);
248 goto fail;
251 setALContext(This->ctx);
252 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
254 TRACE("Found AL_EXT_FLOAT32\n");
255 This->SupportedExt[EXT_FLOAT32] = AL_TRUE;
257 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
259 TRACE("Found AL_EXT_MCFORMATS\n");
260 This->SupportedExt[EXT_MCFORMATS] = AL_TRUE;
262 if(alIsExtensionPresent("AL_EXT_STATIC_BUFFER"))
264 TRACE("Found AL_EXT_STATIC_BUFFER\n");
265 This->ExtAL.BufferDataStatic = alGetProcAddress("alBufferDataStatic");
266 This->SupportedExt[EXT_STATIC_BUFFER] = AL_TRUE;
268 if(alIsExtensionPresent("AL_SOFTX_buffer_samples"))
270 TRACE("Found AL_SOFTX_buffer_samples\n");
271 This->ExtAL.BufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
272 This->ExtAL.BufferSubSamplesSOFT = alGetProcAddress("alBufferSubSamplesSOFT");
273 This->ExtAL.GetBufferSamplesSOFT = alGetProcAddress("alGetBufferSamplesSOFT");
274 This->ExtAL.IsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
275 This->SupportedExt[SOFT_BUFFER_SAMPLES] = AL_TRUE;
277 if(alIsExtensionPresent("AL_SOFT_buffer_sub_data"))
279 TRACE("Found AL_SOFT_buffer_sub_data\n");
280 This->ExtAL.BufferSubData = alGetProcAddress("alBufferSubDataSOFT");
281 This->SupportedExt[SOFT_BUFFER_SUB_DATA] = AL_TRUE;
283 if(alIsExtensionPresent("AL_SOFTX_deferred_updates"))
285 TRACE("Found AL_SOFTX_deferred_updates\n");
286 This->ExtAL.DeferUpdates = alGetProcAddress("alDeferUpdatesSOFT");
287 This->ExtAL.ProcessUpdates = alGetProcAddress("alProcessUpdatesSOFT");
288 This->SupportedExt[SOFT_DEFERRED_UPDATES] = AL_TRUE;
290 else
292 This->ExtAL.DeferUpdates = wrap_DeferUpdates;
293 This->ExtAL.ProcessUpdates = wrap_ProcessUpdates;
296 if(alcIsExtensionPresent(parent->device, "ALC_EXT_EFX"))
298 #define LOAD_FUNC(x) (This->ExtAL.x = alGetProcAddress("al"#x))
299 LOAD_FUNC(GenEffects);
300 LOAD_FUNC(DeleteEffects);
301 LOAD_FUNC(Effecti);
302 LOAD_FUNC(Effectf);
304 LOAD_FUNC(GenAuxiliaryEffectSlots);
305 LOAD_FUNC(DeleteAuxiliaryEffectSlots);
306 LOAD_FUNC(AuxiliaryEffectSloti);
307 #undef LOAD_FUNC
308 This->SupportedExt[EXT_EFX] = AL_TRUE;
310 This->ExtAL.GenEffects(1, &This->effect);
311 This->ExtAL.Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
313 This->ExtAL.GenAuxiliaryEffectSlots(1, &This->auxslot);
315 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
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;
326 This->parent = parent;
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->ExtAL.BufferSubData && !This->ExtAL.BufferSamplesSOFT &&
334 !This->ExtAL.BufferDataStatic)
336 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
337 alcGetString(parent->device, ALC_DEVICE_SPECIFIER));
338 ERR("Please consider using OpenAL-Soft\n");
341 /* Make sure DS3DListener defaults are applied to OpenAL */
342 listener = &This->listen;
343 listener->dwSize = sizeof(*listener);
344 listener->vPosition.x = 0.0;
345 listener->vPosition.y = 0.0;
346 listener->vPosition.z = 0.0;
347 listener->vVelocity.x = 0.0;
348 listener->vVelocity.y = 0.0;
349 listener->vVelocity.z = 0.0;
350 listener->vOrientFront.x = 0.0;
351 listener->vOrientFront.y = 0.0;
352 listener->vOrientFront.z = 1.0;
353 listener->vOrientTop.x = 0.0;
354 listener->vOrientTop.y = 1.0;
355 listener->vOrientTop.z = 0.0;
356 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
357 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
358 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
359 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
360 if(FAILED(hr))
361 ERR("Could not set 3d parameters: %08x\n", hr);
363 for(nsources = 0;nsources < sizeof(srcs)/sizeof(*srcs);nsources++)
365 alGenSources(1, &srcs[nsources]);
366 if(alGetError() != AL_NO_ERROR)
367 break;
369 alDeleteSources(nsources, srcs);
370 getALError();
372 popALContext();
374 This->max_sources = nsources;
375 This->sizenotifies = This->sizebuffers = This->sizesources = nsources+1;
377 hr = DSERR_OUTOFMEMORY;
378 This->sources = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->sources));
379 This->buffers = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->buffers));
380 This->notifies = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->notifies));
381 if(!This->sources || !This->buffers || !This->notifies)
382 goto fail;
384 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
385 if(This->thread_hdl == NULL)
386 goto fail;
388 *ppv = This;
389 return S_OK;
391 fail:
392 DS8Primary_Destroy(This);
393 return hr;
396 void DS8Primary_Destroy(DS8Primary *This)
398 TRACE("Destroying primary %p\n", This);
400 if(This->timer_id)
402 timeKillEvent(This->timer_id);
403 timeEndPeriod(This->timer_res);
404 TRACE("Killed timer\n");
406 if(This->thread_hdl)
408 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
409 WaitForSingleObject(This->thread_hdl, 1000);
410 CloseHandle(This->thread_hdl);
413 if(This->ctx)
415 /* Calling setALContext is not appropriate here,
416 * since we *have* to unset the context before destroying it
418 ALCcontext *old_ctx;
420 EnterCriticalSection(&openal_crst);
421 old_ctx = get_context();
422 if(old_ctx != This->ctx)
423 set_context(This->ctx);
424 else
425 old_ctx = NULL;
427 while(This->nbuffers--)
428 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
430 if(This->nsources)
431 alDeleteSources(This->nsources, This->sources);
433 if(This->effect)
434 This->ExtAL.DeleteEffects(1, &This->effect);
435 if(This->auxslot)
436 This->ExtAL.DeleteAuxiliaryEffectSlots(1, &This->auxslot);
438 HeapFree(GetProcessHeap(), 0, This->sources);
439 HeapFree(GetProcessHeap(), 0, This->notifies);
440 HeapFree(GetProcessHeap(), 0, This->buffers);
442 set_context(old_ctx);
443 alcDestroyContext(This->ctx);
444 LeaveCriticalSection(&openal_crst);
447 This->crst.DebugInfo->Spare[0] = 0;
448 DeleteCriticalSection(&This->crst);
450 HeapFree(GetProcessHeap(), 0, This);
453 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
455 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
458 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
460 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
462 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
464 *ppv = NULL;
465 if(IsEqualIID(riid, &IID_IUnknown) ||
466 IsEqualIID(riid, &IID_IDirectSoundBuffer))
467 *ppv = &This->IDirectSoundBuffer_iface;
468 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
470 if((This->flags&DSBCAPS_CTRL3D))
471 *ppv = &This->IDirectSound3DListener_iface;
473 else
474 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
476 if(*ppv)
478 IUnknown_AddRef((IUnknown*)*ppv);
479 return S_OK;
482 return E_NOINTERFACE;
485 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
487 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
488 LONG ret;
490 ret = InterlockedIncrement(&This->ref);
491 if(ret == 1) This->flags = 0;
493 return ret;
496 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
498 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
499 LONG ret;
501 ret = InterlockedDecrement(&This->ref);
503 return ret;
506 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
508 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
510 TRACE("(%p)->(%p)\n", iface, caps);
512 if(!caps || caps->dwSize < sizeof(*caps))
514 WARN("Invalid DSBCAPS (%p, %u)\n", caps, caps ? caps->dwSize : 0);
515 return DSERR_INVALIDPARAM;
518 EnterCriticalSection(&This->crst);
519 caps->dwFlags = This->flags;
520 caps->dwBufferBytes = This->buf_size;
521 caps->dwUnlockTransferRate = 0;
522 caps->dwPlayCpuOverhead = 0;
523 LeaveCriticalSection(&This->crst);
525 return DS_OK;
528 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
530 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
531 HRESULT hr = DSERR_PRIOLEVELNEEDED;
533 EnterCriticalSection(&This->crst);
534 if(This->write_emu)
535 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
536 LeaveCriticalSection(&This->crst);
538 return hr;
541 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
543 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
544 HRESULT hr = S_OK;
545 UINT size;
547 if(!wfx && !written)
549 WARN("Cannot report format or format size\n");
550 return DSERR_INVALIDPARAM;
553 EnterCriticalSection(&This->crst);
554 size = sizeof(This->format.Format) + This->format.Format.cbSize;
555 if(written)
556 *written = size;
557 if(wfx)
559 if(allocated < size)
560 hr = DSERR_INVALIDPARAM;
561 else
562 memcpy(wfx, &This->format.Format, size);
564 LeaveCriticalSection(&This->crst);
566 return hr;
569 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
571 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
572 HRESULT hr = S_OK;
574 TRACE("(%p)->(%p)\n", iface, volume);
576 if(!volume)
577 return DSERR_INVALIDPARAM;
579 EnterCriticalSection(&This->crst);
580 if(!(This->flags & DSBCAPS_CTRLVOLUME))
581 hr = DSERR_CONTROLUNAVAIL;
582 else
584 ALfloat gain;
585 LONG vol;
587 setALContext(This->ctx);
588 alGetListenerf(AL_GAIN, &gain);
589 getALError();
590 popALContext();
592 vol = gain_to_mB(gain);
593 vol = max(vol, DSBVOLUME_MIN);
594 *volume = min(vol, DSBVOLUME_MAX);
596 LeaveCriticalSection(&This->crst);
598 return hr;
601 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
603 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
604 HRESULT hr = S_OK;
606 WARN("(%p)->(%p): semi-stub\n", iface, pan);
608 if(!pan)
609 return DSERR_INVALIDPARAM;
611 EnterCriticalSection(&This->crst);
612 if(This->write_emu)
613 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
614 else if(!(This->flags & DSBCAPS_CTRLPAN))
615 hr = DSERR_CONTROLUNAVAIL;
616 else
617 *pan = 0;
618 LeaveCriticalSection(&This->crst);
620 return hr;
623 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
625 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
626 HRESULT hr = S_OK;
628 WARN("(%p)->(%p): semi-stub\n", iface, freq);
630 if(!freq)
631 return DSERR_INVALIDPARAM;
633 EnterCriticalSection(&This->crst);
634 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
635 hr = DSERR_CONTROLUNAVAIL;
636 else
637 *freq = This->format.Format.nSamplesPerSec;
638 LeaveCriticalSection(&This->crst);
640 return hr;
643 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
645 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
647 TRACE("(%p)->(%p)\n", iface, status);
649 if(!status)
650 return DSERR_INVALIDPARAM;
652 EnterCriticalSection(&This->crst);
654 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
655 if((This->flags&DSBCAPS_LOCDEFER))
656 *status |= DSBSTATUS_LOCHARDWARE;
658 if(This->stopped)
660 DWORD i, state;
661 HRESULT hr;
663 for(i = 0;i < This->nbuffers;++i)
665 hr = IDirectSoundBuffer_GetStatus((IDirectSoundBuffer*)This->buffers[i], &state);
666 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
667 break;
669 if(i == This->nbuffers)
671 /* Primary stopped and no buffers playing.. */
672 *status = 0;
676 LeaveCriticalSection(&This->crst);
678 return S_OK;
681 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
683 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
684 HRESULT hr = S_OK;
686 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
688 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
690 WARN("Bad DSBDESC for primary buffer\n");
691 return DSERR_INVALIDPARAM;
693 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
694 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
695 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
697 WARN("Bad dwFlags %08x\n", desc->dwFlags);
698 return DSERR_INVALIDPARAM;
701 EnterCriticalSection(&This->crst);
702 /* Should be 0 if not initialized */
703 if(This->flags)
705 hr = DSERR_ALREADYINITIALIZED;
706 goto out;
709 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
711 DSBUFFERDESC emudesc;
712 DS8Buffer *emu;
714 if(This->write_emu)
716 ERR("There shouldn't be a write_emu!\n");
717 IDirectSoundBuffer8_Release(This->write_emu);
718 This->write_emu = NULL;
721 memset(&emudesc, 0, sizeof(emudesc));
722 emudesc.dwSize = sizeof(emudesc);
723 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
724 /* Dont play last incomplete sample */
725 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
726 emudesc.lpwfxFormat = &This->format.Format;
728 hr = DS8Buffer_Create(&emu, This, NULL);
729 if(SUCCEEDED(hr))
731 This->write_emu = &emu->IDirectSoundBuffer8_iface;
732 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
733 if(FAILED(hr))
735 IDirectSoundBuffer8_Release(This->write_emu);
736 This->write_emu = NULL;
741 if(SUCCEEDED(hr))
742 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
743 out:
744 LeaveCriticalSection(&This->crst);
745 return hr;
748 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
750 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
751 HRESULT hr = DSERR_PRIOLEVELNEEDED;
753 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
755 EnterCriticalSection(&This->crst);
756 if(This->write_emu)
757 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
758 LeaveCriticalSection(&This->crst);
760 return hr;
763 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
765 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
766 HRESULT hr;
768 TRACE("(%p)->(%u, %u, %u)\n", iface, res1, res2, flags);
770 if(!(flags & DSBPLAY_LOOPING))
772 WARN("Flags (%08x) not set to DSBPLAY_LOOPING\n", flags);
773 return DSERR_INVALIDPARAM;
776 EnterCriticalSection(&This->crst);
777 hr = S_OK;
778 if(This->write_emu)
779 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
780 if(SUCCEEDED(hr))
781 This->stopped = FALSE;
782 LeaveCriticalSection(&This->crst);
784 return hr;
787 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
789 WARN("(%p)->(%u)\n", iface, pos);
790 return DSERR_INVALIDCALL;
793 /* Just assume the format is crap, and clean up the damage */
794 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
796 if(from->wFormatTag == WAVE_FORMAT_PCM)
798 wfx->cbSize = 0;
799 if(from->wBitsPerSample == 8 ||
800 from->wBitsPerSample == 16 ||
801 from->wBitsPerSample == 24 ||
802 from->wBitsPerSample == 32)
803 wfx->wBitsPerSample = from->wBitsPerSample;
805 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
807 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
808 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
809 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
811 /* Fail silently.. */
812 if(from->cbSize < size)
813 return;
814 if(!fromx->Samples.wValidBitsPerSample &&
815 !fromx->Format.wBitsPerSample)
816 return;
818 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
819 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
821 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
822 return;
825 wfe->Format.wBitsPerSample = from->wBitsPerSample;
826 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
827 if(!wfe->Samples.wValidBitsPerSample)
828 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
829 wfe->Format.cbSize = size;
830 wfe->dwChannelMask = fromx->dwChannelMask;
831 wfe->SubFormat = fromx->SubFormat;
833 else
835 ERR("Unhandled format tag %04x\n", from->wFormatTag);
836 return;
839 if(from->nChannels)
840 wfx->nChannels = from->nChannels;
841 wfx->wFormatTag = from->wFormatTag;
842 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
843 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
844 wfx->nSamplesPerSec = from->nSamplesPerSec;
845 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
846 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
849 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
851 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
852 HRESULT hr = S_OK;
853 ALCint freq;
855 TRACE("(%p)->(%p)\n", iface, wfx);
857 if(!wfx)
859 WARN("Missing format\n");
860 return DSERR_INVALIDPARAM;
863 EnterCriticalSection(&This->crst);
865 if(This->parent->prio_level < DSSCL_PRIORITY)
867 hr = DSERR_PRIOLEVELNEEDED;
868 goto out;
871 TRACE("Requested primary format:\n"
872 " FormatTag = %04x\n"
873 " Channels = %u\n"
874 " SamplesPerSec = %u\n"
875 " AvgBytesPerSec = %u\n"
876 " BlockAlign = %u\n"
877 " BitsPerSample = %u\n",
878 wfx->wFormatTag, wfx->nChannels,
879 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
880 wfx->nBlockAlign, wfx->wBitsPerSample);
882 copy_waveformat(&This->format.Format, wfx);
884 freq = This->format.Format.nSamplesPerSec;
885 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
886 getALCError(This->parent->device);
888 This->format.Format.nSamplesPerSec = freq;
889 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
890 This->format.Format.nSamplesPerSec;
892 if(This->write_emu)
894 DS8Buffer *buf;
895 DSBUFFERDESC desc;
897 memset(&desc, 0, sizeof(desc));
898 desc.dwSize = sizeof(desc);
899 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
900 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
901 desc.lpwfxFormat = &This->format.Format;
903 hr = DS8Buffer_Create(&buf, This, NULL);
904 if(FAILED(hr))
905 goto out;
907 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, (IDirectSound*)&This->parent->IDirectSound8_iface, &desc);
908 if(FAILED(hr))
909 DS8Buffer_Destroy(buf);
910 else
912 IDirectSoundBuffer8_Release(This->write_emu);
913 This->write_emu = &buf->IDirectSoundBuffer8_iface;
917 out:
918 LeaveCriticalSection(&This->crst);
919 return hr;
922 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
924 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
925 HRESULT hr = S_OK;
927 TRACE("(%p)->(%d)\n", iface, vol);
929 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
931 WARN("Invalid volume (%d)\n", vol);
932 return DSERR_INVALIDPARAM;
935 EnterCriticalSection(&This->crst);
936 if(!(This->flags&DSBCAPS_CTRLVOLUME))
937 hr = DSERR_CONTROLUNAVAIL;
938 if(SUCCEEDED(hr))
940 setALContext(This->ctx);
941 alListenerf(AL_GAIN, mB_to_gain(vol));
942 popALContext();
944 LeaveCriticalSection(&This->crst);
946 return hr;
949 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
951 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
952 HRESULT hr;
954 TRACE("(%p)->(%d)\n", iface, pan);
956 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
958 WARN("invalid parameter: pan = %d\n", pan);
959 return DSERR_INVALIDPARAM;
962 EnterCriticalSection(&This->crst);
963 if(!(This->flags&DSBCAPS_CTRLPAN))
965 WARN("control unavailable\n");
966 hr = DSERR_CONTROLUNAVAIL;
968 else if(This->write_emu)
969 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
970 else
972 FIXME("Not supported\n");
973 hr = E_NOTIMPL;
975 LeaveCriticalSection(&This->crst);
977 return hr;
980 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
982 WARN("(%p)->(%u)\n", iface, freq);
983 return DSERR_CONTROLUNAVAIL;
986 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
988 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
989 HRESULT hr = S_OK;
991 TRACE("(%p)->()\n", iface);
993 EnterCriticalSection(&This->crst);
994 if(This->write_emu)
995 hr = IDirectSoundBuffer8_Stop(This->write_emu);
996 if(SUCCEEDED(hr))
997 This->stopped = TRUE;
998 LeaveCriticalSection(&This->crst);
1000 return hr;
1003 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1005 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1006 HRESULT hr = DSERR_INVALIDCALL;
1008 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1010 EnterCriticalSection(&This->crst);
1011 if(This->write_emu)
1012 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
1013 LeaveCriticalSection(&This->crst);
1015 return hr;
1018 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
1020 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1021 HRESULT hr = S_OK;
1023 TRACE("(%p)->()\n", iface);
1025 EnterCriticalSection(&This->crst);
1026 if(This->write_emu)
1027 hr = IDirectSoundBuffer8_Restore(This->write_emu);
1028 LeaveCriticalSection(&This->crst);
1030 return hr;
1033 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
1035 DS8Primary_QueryInterface,
1036 DS8Primary_AddRef,
1037 DS8Primary_Release,
1038 DS8Primary_GetCaps,
1039 DS8Primary_GetCurrentPosition,
1040 DS8Primary_GetFormat,
1041 DS8Primary_GetVolume,
1042 DS8Primary_GetPan,
1043 DS8Primary_GetFrequency,
1044 DS8Primary_GetStatus,
1045 DS8Primary_Initialize,
1046 DS8Primary_Lock,
1047 DS8Primary_Play,
1048 DS8Primary_SetCurrentPosition,
1049 DS8Primary_SetFormat,
1050 DS8Primary_SetVolume,
1051 DS8Primary_SetPan,
1052 DS8Primary_SetFrequency,
1053 DS8Primary_Stop,
1054 DS8Primary_Unlock,
1055 DS8Primary_Restore
1058 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
1060 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
1063 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1065 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1066 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, 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 %d\n", ret);
1077 return ret;
1081 /* Considering the primary buffer doesn't get destroyed
1082 * it doesn't make sense to destroy ds3d here
1084 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1086 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1087 LONG ret;
1089 ret = InterlockedDecrement(&This->ds3d_ref);
1090 TRACE("new refcount %d\n", ret);
1092 return ret;
1096 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1098 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1099 // HRESULT hr;
1101 TRACE("(%p)->(%p)\n", iface, listener);
1103 if(!listener || listener->dwSize < sizeof(*listener))
1105 WARN("Invalid DS3DLISTENER %p %u\n", listener, listener ? listener->dwSize : 0);
1106 return DSERR_INVALIDPARAM;
1109 EnterCriticalSection(&This->crst);
1110 setALContext(This->ctx);
1111 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1112 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1113 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1114 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1115 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1116 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
1117 popALContext();
1118 LeaveCriticalSection(&This->crst);
1120 // return hr;
1121 return DS_OK;
1124 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1126 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1128 TRACE("(%p)->(%p)\n", iface, distancefactor);
1130 if(!distancefactor)
1132 WARN("Invalid parameter %p\n", distancefactor);
1133 return DSERR_INVALIDPARAM;
1136 EnterCriticalSection(&This->crst);
1137 setALContext(This->ctx);
1139 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1140 getALError();
1142 popALContext();
1143 LeaveCriticalSection(&This->crst);
1145 return S_OK;
1148 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1150 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1152 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1154 if(!dopplerfactor)
1156 WARN("Invalid parameter %p\n", dopplerfactor);
1157 return DSERR_INVALIDPARAM;
1160 EnterCriticalSection(&This->crst);
1161 setALContext(This->ctx);
1163 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1164 getALError();
1166 popALContext();
1167 LeaveCriticalSection(&This->crst);
1169 return S_OK;
1172 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1174 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1175 ALfloat orient[6];
1177 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1179 if(!front || !top)
1181 WARN("Invalid parameter %p %p\n", front, top);
1182 return DSERR_INVALIDPARAM;
1185 EnterCriticalSection(&This->crst);
1186 setALContext(This->ctx);
1188 alGetListenerfv(AL_ORIENTATION, orient);
1189 getALError();
1191 front->x = orient[0];
1192 front->y = orient[1];
1193 front->z = -orient[2];
1194 top->x = orient[3];
1195 top->y = orient[4];
1196 top->z = -orient[5];
1198 popALContext();
1199 LeaveCriticalSection(&This->crst);
1201 return S_OK;
1204 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1206 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1207 ALfloat alpos[3];
1209 TRACE("(%p)->(%p)\n", iface, pos);
1211 if(!pos)
1213 WARN("Invalid parameter %p\n", pos);
1214 return DSERR_INVALIDPARAM;
1217 EnterCriticalSection(&This->crst);
1218 setALContext(This->ctx);
1220 alGetListenerfv(AL_POSITION, alpos);
1221 getALError();
1223 pos->x = alpos[0];
1224 pos->y = alpos[1];
1225 pos->z = -alpos[2];
1227 popALContext();
1228 LeaveCriticalSection(&This->crst);
1230 return S_OK;
1233 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1235 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1237 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1239 if(!rollofffactor)
1241 WARN("Invalid parameter %p\n", rollofffactor);
1242 return DSERR_INVALIDPARAM;
1245 EnterCriticalSection(&This->crst);
1246 *rollofffactor = This->rollofffactor;
1247 LeaveCriticalSection(&This->crst);
1249 return S_OK;
1252 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1254 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1255 ALfloat vel[3];
1257 TRACE("(%p)->(%p)\n", iface, velocity);
1259 if(!velocity)
1261 WARN("Invalid parameter %p\n", velocity);
1262 return DSERR_INVALIDPARAM;
1265 EnterCriticalSection(&This->crst);
1266 setALContext(This->ctx);
1268 alGetListenerfv(AL_VELOCITY, vel);
1269 getALError();
1271 velocity->x = vel[0];
1272 velocity->y = vel[1];
1273 velocity->z = -vel[2];
1275 popALContext();
1276 LeaveCriticalSection(&This->crst);
1278 return S_OK;
1281 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1283 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1285 TRACE("(%p)->(%p, %u)\n", iface, listen, apply);
1287 if(!listen || listen->dwSize < sizeof(*listen))
1289 WARN("Invalid parameter %p %u\n", listen, listen ? listen->dwSize : 0);
1290 return DSERR_INVALIDPARAM;
1293 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1294 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1296 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1297 return DSERR_INVALIDPARAM;
1300 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1301 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1303 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1304 return DSERR_INVALIDPARAM;
1307 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1308 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1310 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1311 return DSERR_INVALIDPARAM;
1314 EnterCriticalSection(&This->crst);
1315 setALContext(This->ctx);
1316 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1317 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1318 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1319 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1320 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1321 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1322 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1323 popALContext();
1324 LeaveCriticalSection(&This->crst);
1326 return S_OK;
1329 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1331 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1333 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1335 if(factor < DS3D_MINDISTANCEFACTOR ||
1336 factor > DS3D_MAXDISTANCEFACTOR)
1338 WARN("Invalid parameter %f\n", factor);
1339 return DSERR_INVALIDPARAM;
1342 EnterCriticalSection(&This->crst);
1343 if(apply == DS3D_DEFERRED)
1345 This->listen.flDistanceFactor = factor;
1346 This->dirty.bit.distancefactor = 1;
1348 else
1350 setALContext(This->ctx);
1351 alSpeedOfSound(343.3f/factor);
1352 if(This->SupportedExt[EXT_EFX])
1353 alListenerf(AL_METERS_PER_UNIT, factor);
1354 getALError();
1355 popALContext();
1357 LeaveCriticalSection(&This->crst);
1359 return S_OK;
1362 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1364 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1366 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1368 if(factor < DS3D_MINDOPPLERFACTOR ||
1369 factor > DS3D_MAXDOPPLERFACTOR)
1371 WARN("Invalid parameter %f\n", factor);
1372 return DSERR_INVALIDPARAM;
1375 EnterCriticalSection(&This->crst);
1376 if(apply == DS3D_DEFERRED)
1378 This->listen.flDopplerFactor = factor;
1379 This->dirty.bit.dopplerfactor = 1;
1381 else
1383 setALContext(This->ctx);
1384 alDopplerFactor(factor);
1385 getALError();
1386 popALContext();
1388 LeaveCriticalSection(&This->crst);
1390 return S_OK;
1393 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1395 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1397 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1399 EnterCriticalSection(&This->crst);
1400 if(apply == DS3D_DEFERRED)
1402 This->listen.vOrientFront.x = xFront;
1403 This->listen.vOrientFront.y = yFront;
1404 This->listen.vOrientFront.z = zFront;
1405 This->listen.vOrientTop.x = xTop;
1406 This->listen.vOrientTop.y = yTop;
1407 This->listen.vOrientTop.z = zTop;
1408 This->dirty.bit.orientation = 1;
1410 else
1412 ALfloat orient[6] = {
1413 xFront, yFront, -zFront,
1414 xTop, yTop, -zTop
1416 setALContext(This->ctx);
1417 alListenerfv(AL_ORIENTATION, orient);
1418 getALError();
1419 popALContext();
1421 LeaveCriticalSection(&This->crst);
1423 return S_OK;
1426 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1428 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1430 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1432 EnterCriticalSection(&This->crst);
1433 if(apply == DS3D_DEFERRED)
1435 This->listen.vPosition.x = x;
1436 This->listen.vPosition.y = y;
1437 This->listen.vPosition.z = z;
1438 This->dirty.bit.pos = 1;
1440 else
1442 setALContext(This->ctx);
1443 alListener3f(AL_POSITION, x, y, -z);
1444 getALError();
1445 popALContext();
1447 LeaveCriticalSection(&This->crst);
1449 return S_OK;
1452 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1454 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1456 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1458 if(factor < DS3D_MINROLLOFFFACTOR ||
1459 factor > DS3D_MAXROLLOFFFACTOR)
1461 WARN("Invalid parameter %f\n", factor);
1462 return DSERR_INVALIDPARAM;
1465 EnterCriticalSection(&This->crst);
1466 if(apply == DS3D_DEFERRED)
1468 This->listen.flRolloffFactor = factor;
1469 This->dirty.bit.rollofffactor = 1;
1471 else
1473 DWORD i;
1475 setALContext(This->ctx);
1476 for(i = 0;i < This->nbuffers;++i)
1478 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1479 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1481 getALError();
1482 popALContext();
1484 This->rollofffactor = factor;
1486 LeaveCriticalSection(&This->crst);
1488 return S_OK;
1491 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1493 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1495 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1497 EnterCriticalSection(&This->crst);
1498 if(apply == DS3D_DEFERRED)
1500 This->listen.vVelocity.x = x;
1501 This->listen.vVelocity.y = y;
1502 This->listen.vVelocity.z = z;
1503 This->dirty.bit.vel = 1;
1505 else
1507 setALContext(This->ctx);
1508 alListener3f(AL_VELOCITY, x, y, -z);
1509 getALError();
1510 popALContext();
1512 LeaveCriticalSection(&This->crst);
1514 return S_OK;
1517 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1519 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1520 const DS3DLISTENER *listen = &This->listen;
1521 DWORD i;
1523 EnterCriticalSection(&This->crst);
1524 setALContext(This->ctx);
1525 This->ExtAL.DeferUpdates();
1527 if(This->dirty.bit.pos)
1528 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1529 if(This->dirty.bit.vel)
1530 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1531 if(This->dirty.bit.orientation)
1533 ALfloat orient[6] = {
1534 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1535 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1537 alListenerfv(AL_ORIENTATION, orient);
1539 if(This->dirty.bit.distancefactor)
1541 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1542 if(This->SupportedExt[EXT_EFX])
1543 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1546 if(This->dirty.bit.rollofffactor)
1548 ALfloat rolloff = This->rollofffactor;
1549 for(i = 0;i < This->nbuffers;++i)
1551 DS8Buffer *buf = This->buffers[i];
1552 if(buf->ds3dmode != DS3DMODE_DISABLE)
1553 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1557 if(This->dirty.bit.dopplerfactor)
1558 alDopplerFactor(listen->flDopplerFactor);
1560 if(This->dirty.bit.effect)
1561 This->ExtAL.AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1563 /* getALError is here for debugging */
1564 getALError();
1566 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1567 This->dirty.flags = 0;
1569 for(i = 0;i < This->nbuffers;++i)
1571 DS8Buffer *buf = This->buffers[i];
1573 if(!buf->dirty.flags)
1574 continue;
1576 if(buf->dirty.bit.pos)
1577 alSource3f(buf->source, AL_POSITION,
1578 buf->ds3dbuffer.vPosition.x,
1579 buf->ds3dbuffer.vPosition.y,
1580 -buf->ds3dbuffer.vPosition.z);
1581 if(buf->dirty.bit.vel)
1582 alSource3f(buf->source, AL_VELOCITY,
1583 buf->ds3dbuffer.vVelocity.x,
1584 buf->ds3dbuffer.vVelocity.y,
1585 -buf->ds3dbuffer.vVelocity.z);
1586 if(buf->dirty.bit.cone_angles)
1588 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1589 buf->ds3dbuffer.dwInsideConeAngle);
1590 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1591 buf->ds3dbuffer.dwOutsideConeAngle);
1593 if(buf->dirty.bit.cone_orient)
1594 alSource3f(buf->source, AL_DIRECTION,
1595 buf->ds3dbuffer.vConeOrientation.x,
1596 buf->ds3dbuffer.vConeOrientation.y,
1597 -buf->ds3dbuffer.vConeOrientation.z);
1598 if(buf->dirty.bit.cone_outsidevolume)
1599 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1600 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1601 if(buf->dirty.bit.min_distance)
1602 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1603 if(buf->dirty.bit.max_distance)
1604 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1605 if(buf->dirty.bit.mode)
1607 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1608 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1609 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1610 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1611 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1613 buf->dirty.flags = 0;
1615 getALError();
1617 This->ExtAL.ProcessUpdates();
1618 popALContext();
1619 LeaveCriticalSection(&This->crst);
1621 return S_OK;
1624 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1626 DS8Primary3D_QueryInterface,
1627 DS8Primary3D_AddRef,
1628 DS8Primary3D_Release,
1629 DS8Primary3D_GetAllParameters,
1630 DS8Primary3D_GetDistanceFactor,
1631 DS8Primary3D_GetDopplerFactor,
1632 DS8Primary3D_GetOrientation,
1633 DS8Primary3D_GetPosition,
1634 DS8Primary3D_GetRolloffFactor,
1635 DS8Primary3D_GetVelocity,
1636 DS8Primary3D_SetAllParameters,
1637 DS8Primary3D_SetDistanceFactor,
1638 DS8Primary3D_SetDopplerFactor,
1639 DS8Primary3D_SetOrientation,
1640 DS8Primary3D_SetPosition,
1641 DS8Primary3D_SetRolloffFactor,
1642 DS8Primary3D_SetVelocity,
1643 DS8Primary3D_CommitDeferredSettings
1646 /* NOTE: Although the app handles listener properties through secondary buffers,
1647 * we pass the requests to the primary buffer though a propertyset interface.
1648 * These methods are not exposed to the app. */
1649 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1651 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1654 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1656 DS8Primary *This = impl_from_IKsPropertySet(iface);
1657 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
1660 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1662 DS8Primary *This = impl_from_IKsPropertySet(iface);
1663 LONG ret;
1665 ret = InterlockedIncrement(&This->prop_ref);
1666 TRACE("new refcount %d\n", ret);
1668 return ret;
1671 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1673 DS8Primary *This = impl_from_IKsPropertySet(iface);
1674 LONG ret;
1676 ret = InterlockedDecrement(&This->prop_ref);
1677 TRACE("new refcount %d\n", ret);
1679 return ret;
1682 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1683 REFGUID guidPropSet, ULONG dwPropID,
1684 LPVOID pInstanceData, ULONG cbInstanceData,
1685 LPVOID pPropData, ULONG cbPropData,
1686 PULONG pcbReturned)
1688 DS8Primary *This = impl_from_IKsPropertySet(iface);
1689 HRESULT res = E_PROP_ID_UNSUPPORTED;
1691 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
1692 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
1694 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1696 EnterCriticalSection(&This->crst);
1698 if(This->effect == 0)
1699 res = E_PROP_ID_UNSUPPORTED;
1700 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1702 res = DSERR_INVALIDPARAM;
1703 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1705 union {
1706 void *v;
1707 EAXLISTENERPROPERTIES *props;
1708 } data = { pPropData };
1710 *data.props = This->eax_prop;
1711 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1712 res = DS_OK;
1715 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOM)
1717 res = DSERR_INVALIDPARAM;
1718 if(cbPropData >= sizeof(LONG))
1720 union {
1721 void *v;
1722 LONG *l;
1723 } data = { pPropData };
1725 *data.l = This->eax_prop.lRoom;
1726 *pcbReturned = sizeof(LONG);
1727 res = DS_OK;
1730 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF)
1732 res = DSERR_INVALIDPARAM;
1733 if(cbPropData >= sizeof(LONG))
1735 union {
1736 void *v;
1737 LONG *l;
1738 } data = { pPropData };
1740 *data.l = This->eax_prop.lRoomHF;
1741 *pcbReturned = sizeof(LONG);
1742 res = DS_OK;
1745 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1747 res = DSERR_INVALIDPARAM;
1748 if(cbPropData >= sizeof(FLOAT))
1750 union {
1751 void *v;
1752 FLOAT *fl;
1753 } data = { pPropData };
1755 *data.fl = This->eax_prop.flRoomRolloffFactor;
1756 *pcbReturned = sizeof(FLOAT);
1757 res = DS_OK;
1760 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1762 res = DSERR_INVALIDPARAM;
1763 if(cbPropData >= sizeof(DWORD))
1765 union {
1766 void *v;
1767 DWORD *dw;
1768 } data = { pPropData };
1770 *data.dw = This->eax_prop.dwEnvironment;
1771 *pcbReturned = sizeof(DWORD);
1772 res = DS_OK;
1775 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1777 res = DSERR_INVALIDPARAM;
1778 if(cbPropData >= sizeof(FLOAT))
1780 union {
1781 void *v;
1782 FLOAT *fl;
1783 } data = { pPropData };
1785 *data.fl = This->eax_prop.flEnvironmentSize;
1786 *pcbReturned = sizeof(FLOAT);
1787 res = DS_OK;
1790 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
1792 res = DSERR_INVALIDPARAM;
1793 if(cbPropData >= sizeof(FLOAT))
1795 union {
1796 void *v;
1797 FLOAT *fl;
1798 } data = { pPropData };
1800 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1801 *pcbReturned = sizeof(FLOAT);
1802 res = DS_OK;
1805 else if(dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
1807 res = DSERR_INVALIDPARAM;
1808 if(cbPropData >= sizeof(FLOAT))
1810 union {
1811 void *v;
1812 FLOAT *fl;
1813 } data = { pPropData };
1815 *data.fl = This->eax_prop.flAirAbsorptionHF;
1816 *pcbReturned = sizeof(FLOAT);
1817 res = DS_OK;
1820 else if(dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
1822 res = DSERR_INVALIDPARAM;
1823 if(cbPropData >= sizeof(DWORD))
1825 union {
1826 void *v;
1827 DWORD *dw;
1828 } data = { pPropData };
1830 *data.dw = This->eax_prop.dwFlags;
1831 *pcbReturned = sizeof(DWORD);
1832 res = DS_OK;
1835 else
1836 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
1838 LeaveCriticalSection(&This->crst);
1840 else
1841 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1843 return res;
1846 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1847 REFGUID guidPropSet, ULONG dwPropID,
1848 LPVOID pInstanceData, ULONG cbInstanceData,
1849 LPVOID pPropData, ULONG cbPropData)
1851 DS8Primary *This = impl_from_IKsPropertySet(iface);
1852 HRESULT res = E_PROP_ID_UNSUPPORTED;
1854 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
1855 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
1857 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1859 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1860 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1862 EnterCriticalSection(&This->crst);
1863 setALContext(This->ctx);
1865 if(This->effect == 0)
1866 res = E_PROP_ID_UNSUPPORTED;
1867 else if(propid == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1869 do_allparams:
1870 res = DSERR_INVALIDPARAM;
1871 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1873 union {
1874 const void *v;
1875 const EAXLISTENERPROPERTIES *props;
1876 } data = { pPropData };
1878 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1879 This->eax_prop = *data.props;
1880 This->ExtAL.Effectf(This->effect, AL_REVERB_DENSITY,
1881 (data.props->flEnvironmentSize < 2.0f) ?
1882 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1883 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1884 data.props->flEnvironmentDiffusion);
1886 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1887 mB_to_gain(data.props->lRoom));
1888 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1889 mB_to_gain(data.props->lRoomHF));
1891 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1892 data.props->flRoomRolloffFactor);
1894 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_TIME,
1895 data.props->flDecayTime);
1896 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1897 data.props->flDecayHFRatio);
1899 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1900 mB_to_gain(data.props->lReflections));
1901 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1902 data.props->flReflectionsDelay);
1904 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1905 mB_to_gain(data.props->lReverb));
1906 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1907 data.props->flReverbDelay);
1909 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1910 mB_to_gain(data.props->flAirAbsorptionHF));
1912 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1913 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1914 AL_TRUE : AL_FALSE);
1916 getALError();
1918 This->dirty.bit.effect = 1;
1919 res = DS_OK;
1922 else if(propid == DSPROPERTY_EAXLISTENER_ROOM)
1924 res = DSERR_INVALIDPARAM;
1925 if(cbPropData >= sizeof(LONG))
1927 union {
1928 const void *v;
1929 const LONG *l;
1930 } data = { pPropData };
1932 This->eax_prop.lRoom = *data.l;
1933 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1934 mB_to_gain(This->eax_prop.lRoom));
1935 getALError();
1937 This->dirty.bit.effect = 1;
1938 res = DS_OK;
1941 else if(propid == DSPROPERTY_EAXLISTENER_ROOMHF)
1943 res = DSERR_INVALIDPARAM;
1944 if(cbPropData >= sizeof(LONG))
1946 union {
1947 const void *v;
1948 const LONG *l;
1949 } data = { pPropData };
1951 This->eax_prop.lRoomHF = *data.l;
1952 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1953 mB_to_gain(This->eax_prop.lRoomHF));
1954 getALError();
1956 This->dirty.bit.effect = 1;
1957 res = DS_OK;
1960 else if(propid == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1962 res = DSERR_INVALIDPARAM;
1963 if(cbPropData >= sizeof(FLOAT))
1965 union {
1966 const void *v;
1967 const FLOAT *fl;
1968 } data = { pPropData };
1970 This->eax_prop.flRoomRolloffFactor = *data.fl;
1971 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1972 This->eax_prop.flRoomRolloffFactor);
1973 getALError();
1975 This->dirty.bit.effect = 1;
1976 res = DS_OK;
1979 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1981 res = DSERR_INVALIDPARAM;
1982 if(cbPropData >= sizeof(DWORD))
1984 union {
1985 const void *v;
1986 const DWORD *dw;
1987 } data = { pPropData };
1989 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1991 /* Get the environment index's default and pass it down to
1992 * ALLPARAMETERS */
1993 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1994 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1995 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1996 goto do_allparams;
2000 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
2002 res = DSERR_INVALIDPARAM;
2003 if(cbPropData >= sizeof(FLOAT))
2005 union {
2006 const void *v;
2007 const FLOAT *fl;
2008 } data = { pPropData };
2010 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
2012 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
2014 This->eax_prop.flEnvironmentSize = *data.fl;
2016 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
2018 This->eax_prop.flDecayTime *= scale;
2019 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
2021 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
2023 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
2024 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
2026 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
2028 This->eax_prop.flReflectionsDelay *= scale;
2029 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
2031 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
2033 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
2034 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
2036 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
2038 This->eax_prop.flReverbDelay *= scale;
2039 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
2042 /* Pass the updated environment properties down to ALLPARAMETERS */
2043 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2044 pPropData = (void*)&This->eax_prop;
2045 cbPropData = sizeof(This->eax_prop);
2046 goto do_allparams;
2050 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
2052 res = DSERR_INVALIDPARAM;
2053 if(cbPropData >= sizeof(FLOAT))
2055 union {
2056 const void *v;
2057 const FLOAT *fl;
2058 } data = { pPropData };
2060 This->eax_prop.flEnvironmentDiffusion = *data.fl;
2061 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
2062 This->eax_prop.flEnvironmentDiffusion);
2063 getALError();
2065 This->dirty.bit.effect = 1;
2066 res = DS_OK;
2069 else if(propid == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
2071 res = DSERR_INVALIDPARAM;
2072 if(cbPropData >= sizeof(FLOAT))
2074 union {
2075 const void *v;
2076 const FLOAT *fl;
2077 } data = { pPropData };
2079 This->eax_prop.flAirAbsorptionHF = *data.fl;
2080 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2081 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
2082 getALError();
2084 This->dirty.bit.effect = 1;
2085 res = DS_OK;
2088 else if(propid == DSPROPERTY_EAXLISTENER_FLAGS)
2090 res = DSERR_INVALIDPARAM;
2091 if(cbPropData >= sizeof(DWORD))
2093 union {
2094 const void *v;
2095 const DWORD *dw;
2096 } data = { pPropData };
2098 This->eax_prop.dwFlags = *data.dw;
2099 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2100 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2101 AL_TRUE : AL_FALSE);
2102 getALError();
2104 This->dirty.bit.effect = 1;
2105 res = DS_OK;
2108 else if(propid != 0)
2109 FIXME("Unhandled propid: 0x%08x\n", propid);
2111 if(res == DS_OK && immediate)
2112 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2114 popALContext();
2115 LeaveCriticalSection(&This->crst);
2117 else
2118 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2120 return res;
2123 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2124 REFGUID guidPropSet, ULONG dwPropID,
2125 PULONG pTypeSupport)
2127 DS8Primary *This = impl_from_IKsPropertySet(iface);
2128 HRESULT res = E_PROP_ID_UNSUPPORTED;
2130 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2132 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2134 EnterCriticalSection(&This->crst);
2136 if(This->effect == 0)
2137 res = E_PROP_ID_UNSUPPORTED;
2138 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2139 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2140 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2141 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2142 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2143 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2144 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2145 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2146 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2148 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2149 res = DS_OK;
2151 else
2152 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
2154 LeaveCriticalSection(&This->crst);
2156 else
2157 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2159 return res;
2162 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2164 DS8PrimaryProp_QueryInterface,
2165 DS8PrimaryProp_AddRef,
2166 DS8PrimaryProp_Release,
2167 DS8PrimaryProp_Get,
2168 DS8PrimaryProp_Set,
2169 DS8PrimaryProp_QuerySupport